1. __init
1. 设备号(主, 次设备号)
1. 设备号是由主,次设备号拼接而成.
2. 主,次设备号的拼接(高12位为主设备号, 低20位为次设备号)
3. register_chrdev_region().
4. 字符设备号存储在哈希表中.
5. 主设备1~255, 次设备0~255.
2. 注册设备
1. 初始化cdev结构体.
1. 给.owner = THIS_MODULE
2. 给.fops = file_operations
3. 给.name = 设备字
4. 给.count = 设备数量
5. 给.dev = 设备号
2. 将cdev加入由系统维护的字符设备双向循环链表中.
2. __exit
1. device_destroy();
2. class_destroy(); udev
3. cdev_del()
4. unregister_chrdev_region()
3. 模块宏-> license, 作者, 描述.
4. file_operations结体
5. open()函数方法 -> 自旋锁()
6. read()函数方法 -> 返回值为0表示EOF. 标记读的偏移量.
7. write()函数方法 -> 标记写的偏移量.
8. ioctl()函数方法 -> _IO: 1.nr(0~7) 2:type(8~15) 3.size(16~29) 4.dir(30~31)
_IOR
_IOW
_IORW
9. release()函数方法 -> 应用close()
10. 自动创建设备节点.
1. class_create(THIS_MODULE, "hello") -> /sys/class/hello
2. device_create("led") -> /dev/led
1. misc_register() -> 注册misc设备到miscedevice结构体中
2. misc_unregister() -> 注销misc设备
3. misc_init() -> misc设备初始化
1. 申请设备号, 主10, 次0, 数量 256
2. 注册misc设备到字符设备双向循环链表中.
3. file_operations -> open()
4. misce_open()
1. 使用次设备号,在miscdevice结构体中, 查找misc设备.
2. 用misc设备中的fops替换file结体中的fops方法.
3. 调用misc设备中实现的file_operations中open方法.
1. 单向链表 (设备号)
2. 双向循环链表
1. container_of()
2. list_for_each()
1. atomic_t v = ATOMIC_INIT(1) 初始化原子操作变量为1
2. atomic_inc(&v) 对变量加1操作
3. atomic_dec_and_test(&v) 先对变量减一操作,再测试变量是否等于0.
如果等于返回真.否则返回假.注: 变量值不会自动加1.
0. spinlock_t lock; 定义自旋锁结构体变量
1. spin_lock_init(&lock); 初始化自旋锁结构体.
2. spin_lock(&lock); 加锁
3. spin_unlock(&lock); 解锁
注意: 自旋锁不能进行休眠操作.
0. semaphore sem 定义信号量变量
1. sema_init(&sem, 1) 初始化信号量
2. down(&sem); 对信号量进行P操作, 减1操作
3. up(&sem); 对信息量进行V操作, 加1操作
注意: 信号量可以进行休眠操作.
0. work_struct queue; 定义等待队列变量
1. init_waitqueue_head(&queue); 初始化等待队列
2. wait_event_interruptible(&queue, 条件); 进行等待队列,等待唤醒. 唤醒后检查条件是否满足.
3. wake_up(&queue); 唤醒等待队列
注意: 可以进行休眠操作.
0. tasklet_struct task; 定义tasklet变量
1. tasklet_init(&task, func, arg);
1. tasklet变量
2. 中断处理函数
3. 中断处理函数参数
2. tasklet_schedule(&task); 将中断加入到中断下半部处理的tasklet处理列表中.
3. void func(unsigned long arg); 中断处理函数
注意: 不能进行休眠操作. 软件中断也不能进行休眠操作.
0. work_struct work; 定义工作队列变量
1. INIT_WORK(&work, (void *)func); 初始化工作队列
1. 工作队列变量
2. 处理函数
2. schedule_work(&work); 将中断加入到中断下半部处理的工作队列处理列表中.
3. void func(struct work_struct work); 工作队列处理函数
注意:可以进行休眠操作.
0. request_irq(irq_no, func, flag, name, NULL);
1. 中断号
2. 中断处理函数
3. 中断标记位.IRQF_DISABLE: 当处理中断时,不能被其它中断打断.
4. 中断名子.
5. NULL.
1. irqreturn_t func(int irq_no, void * devid);
1. 返回值 IRQ_HANDLED 中断成功
2. 返回值 IRQ_NONE 中断失败
3. ?还有一个返回值, 需要自己补充上.
2. free_irq(irq_no, NULL); 释放申请的中断号.
1. platform_device_register
2. platform_drvice_register
3. platform_match_device
通用总线, 是虚构出来的.
1. 这块使用name进行匹配
2. platform_get_ioresourec
1. IORESOUREC_MEM
2. IORESOUREC_IRQ
1. .compatible进行匹配
2. platform_get_ioresourec
1. IORESOUREC_MEM
2. IORESOUREC_IRQ
1. i2c_match_device()
2. i2c_init()
3. i2c_probe()
4. i2c_open()
5. i2c_read()
6. i2c_write()
7. i2c_relsease()
8. i2c_ioctl()
1. .of_match_table -> .compatible
2. algos
1. strcut i2c_msg
1. .addr
2. .flags
3. .len
4. .*buf
2. i2c_transfer(adapter, msg, ARRAY_SIZE(smg))
$ sudo insmod hello.ko
$ cat /dev/hello
$ sudo rmmod hello
$ sudo insmod hello.ko
$ sudo chown linux:linux /dev/hello
$ echo "Welcome to kernel" > /dev/hello
$ sudo rmmod hello
$ cat /proc/kallsyms
查看当前系统设备已使用的设备号, 包括字符设备和块设备.
$ cat /proc/devices
第一列是中断号, 第二列是接收中断数目的计数器. 第三列是中断的中断控制器.第四列是中断相关的设备名子.
$ cat /proc/interrupts
需要保证在同一个目录下.
- 创建管道文件.
$ mkfifo ps
- 用cat读ps
$ cat ps
- 向ps写数据
$ cat > ps