设备与模块
设备类型主要设备类型在Linux系统中,设备被抽象为文件,通过文件系统进行管理。根据设备的功能和特性,主要分为以下三种类型:
1. 字符设备(Character Device)
定义:以字符流(字节流)的形式传输数据,数据的读取和写入是顺序的、无缓冲的,不支持随机访问。
特点:
数据传输实时性强,常用于单次少量数据交互的场景。
不支持通过文件系统的lseek命令随机定位读写位置。
常见设备:
键盘、鼠标、串口(如/dev/ttyS0)、终端(如/dev/tty1)、打印机等。
部分传感器设备(如温度传感器、串口通信设备)。
设备文件标识:
在/dev目录下,设备文件的类型标识为c(通过ls -l命令查看)。
示例:crw-rw-r-- 1 root root 1, 3 May 23 08:00 /dev/null(c表示字符设备)。
2. 块设备(Block Device)
定义:以数据块(Block,如4KB为一个块)为单位传输数据,支持随机访问(可通过块地址直接定位数据),通常有数据缓冲机制。
特点:
适合大批量数据的快速读写,如磁盘存储。
支持文件系统的创建(如EX ...
块IO层
块块设备和字符设备在 Linux 系统中,块设备(Block Device)和字符设备(Character Device)是两种基本的设备分类,用于区分不同类型的硬件设备及其数据交互方式。它们的核心区别在于数据读写的方式、缓冲机制和应用场景。
一、块设备(Block Device)定义块设备是一种以“数据块(Block)”为单位进行随机读写的设备。数据块的大小通常为固定值(如 512字节、4KB 等),设备驱动程序会对数据进行缓冲和缓存,支持按块随机访问(即可以直接读取任意块的数据,无需按顺序)。
特点
数据交互方式
以块(Block)为最小单位读写,块大小由设备硬件决定(如硬盘的扇区通常是 512B 或 4KB)。
支持随机访问:可以直接定位到任意块进行读写,无需按顺序操作(类似数组索引)。
缓冲机制
内核会为块设备提供缓冲区(Buffer)或缓存(Cache),用于暂存数据以提高读写效率。例如,硬盘的读写操作会先经过文件系统的块缓冲区。
典型设备
存储设备:硬盘(HDD/SSD)、U盘、光盘(CD/DVD)、SD卡等。
虚拟存储 ...
内存管理
页概念在现代计算机系统中,处理器的寻址通常通过 虚拟地址(Virtual Address) 进行,而虚拟地址到物理地址的转换过程涉及“页”(Page)的概念。对于支持内存管理单元(MMU)的处理器(如ARMv7),寻址过程会按照页来划分和管理内存,但具体机制需要结合硬件架构和操作系统来理解。以下是详细说明:
一、处理器寻址的基本概念
虚拟地址与物理地址
虚拟地址:应用程序看到的内存地址(由操作系统分配),范围由处理器位数决定(如32位处理器虚拟地址空间为0~4GB)。
物理地址:实际内存(RAM)的硬件地址,由处理器地址总线宽度决定(如32位处理器物理地址空间通常也是4GB)。
MMU的作用:负责将虚拟地址转换为物理地址,这个过程称为 地址转换(Address Translation)。
分页(Paging)机制
操作系统将虚拟地址空间和物理地址空间划分为固定大小的块,称为 页(Page)。
虚拟地址对应的页称为 虚拟页(Virtual Page),物理地址对应的页称为 物理页(Physical Page)。
页的大小由处理器架构决定(如ARMv7支持4 ...
input子系统
input子系统定义input子系统是linux内核针对某一类型的设备而创建的,比如键盘、鼠标、触摸屏、手柄等。input子系统分为以下几部分:input驱动层,input核心层,input事件层。
上图中,最左边的就是具体的设备,这个不用管。中间部分就是我们要关注的input驱动层,input核心层,input事件层。驱动层:输入设备的具体驱动程序,比如按键驱动程序,向内核层报告输入内容。核心层:承上启下,为驱动层提供输入设备注册和操作接口。通知事件层对输入事件进行处理。事件层:主要和用户空间进行交互。
drivers/input/input.c
123register_chrdev_region(MKDEV(INPUT_MAJOR, 0), INPUT_MAX_CHAR_DEVICES, "input");
这个文件中注册了一个类,设备号是13
输入设备注册在使用 input 子系统的时候我们只需要注册一个 input 设备即可,input_dev 结构体表示 input设备,此结构体定义在 include/lin ...
并发与竞争
1、应用层的锁和内核中的锁区别1-1、特性1-1-1、 内核锁(Kernel Locks)
作用:内核锁用于保护内核数据结构,防止多个内核线程或进程同时访问和修改这些数据结构,从而避免数据不一致或竞争条件。
类型:
自旋锁(Spinlock):当一个线程试图获取已经被占用的自旋锁时,它会不断循环(自旋)直到锁可用。适用于持有时间短的场景。
互斥锁(Mutex):当一个线程试图获取已经被占用的互斥锁时,它会被阻塞,直到锁可用。适用于持有时间较长的场景。
读写锁(Read-Write Lock):允许多个读操作同时进行,但写操作是独占的。适用于读多写少的场景。
使用场景:内核锁主要用于内核空间,保护内核数据结构,确保内核的稳定性和一致性。
1-1-2、 应用层锁(Application-Level Locks)
作用:应用层锁用于保护应用程序中的共享数据,防止多个线程或进程同时访问和修改这些数据,从而避免数据不一致或竞争条件。
类型:
互斥锁(Mutex):类似于内核中的互斥锁,用于保护共享资源,确保同一时间只有一个线程可以访问。
读写锁(Read-Write Lock):允许多个读 ...
linux中断
linux中断1、硬件中断1-1、Linux内核中断API以下是Linux内核中断处理相关的API
1-1-1、中断处理函数注册和注销12int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev);void free_irq(unsigned int irq, void *dev);
request_irq
参数:
unsigned int irq: 中断号。
irq_handler_t handler: 中断处理函数指针。
unsigned long flags: 中断标志(如IRQF_SHARED表示共享中断线)。
const char *name: 中断处理程序的名称,用于调试。
void *dev: 设备标识符,通常为设备结构体。
返回值:
0: 成功注册。
非零值: 注册失败。
free_irq
参数:
unsigned int irq: 中断号。
void *dev: 设备标识符,必须与注册时一致。
...
无题
设备树中,半导体厂商一般已经将芯片的型号、频率、IO、中断、时钟、DMA、内存等参数进行了封装,用户只需要在设备树中引用即可。举例:配置gpio,gpio一般在设备树中以节点方式描述,节点名以gpio开头,节点名后面接gpio的编号,如gpio0、gpio1、gpio2等。如imx6ull的gpio1节点:
123456789101112gpio1: gpio@0209c000 { compatible = "fsl,imx6ul-gpio", "fsl,imx35-gpio"; reg = <0x0209c000 0x4000>; interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>; gpio-controller; #gpio-cells = <2>; interrupt-controller; #interrupt-cells cc ...
linux内核定时器
定时器1、内核config配置配置内核定时器步骤
12->kernel Features ->timer frequency (<choice> [=y])
在里面可以选择系统的节拍数,默认是1000Hz,也就是1ms节拍,如果选择2000Hz,就是0.5ms节拍,如果选择10000Hz,就是0.1ms节拍。配置完成后,在源码中的.config文件中,会自动生成如下配置:
1CONFIG_HZ=1000
这个就是节拍率。
这个配置生效在:include/asm-generic/param.h中
1234567891011#ifndef __ASM_GENERIC_PARAM_H#define __ASM_GENERIC_PARAM_H#include <uapi/asm-generic/param.h># undef HZ# define HZ CONFIG_HZ /* Internal kernel timer frequency */# define USER_HZ 100 /* some user inte ...
内核4.8后与4.8之前的gpio差异
在 Linux 内核中,有专门用于控制 GPIO(General - Purpose Input/Output,通用输入输出)输出的函数。
4.8 之前的内核在较旧的 Linux 内核版本中,使用的是传统的 GPIO 接口。相关函数主要定义在 <linux/gpio.h> 头文件中。
1、请求GPIO在使用 GPIO 之前,需要先请求该 GPIO 资源,以确保不会与其他驱动冲突。
123#include <linux/gpio.h>int gpio_request(unsigned gpio, const char *label);
2、设置GPIO方向输出1int gpio_direction_output(unsigned gpio, int value);
gpio:要设置的 GPIO 编号。
value:初始输出电平,0 表示低电平,1 表示高电平。返回值:成功时返回 0,失败时返回负数错误码。
3、设置 GPIO 输出电平1void gpio_set_value(unsigned gpio, int value);
gpio: ...