设备驱动分类
linux设备驱动一般分为3类,字符设备,块设备,网络设备。前两个在/dev目录下有对应的设备节点,网络设备比较特殊,没有。通过ls -l /dev/xx
可以看出设备类型:
thammer@test:~$ ls -l /dev/nvme0n1
brw-rw---- 1 root disk 259, 0 10月 9 08:59 /dev/nvme0n1
thammer@test:~$ ls -l /dev/tty
crw-rw-rw- 1 root tty 5, 0 10月 10 15:25 /dev/tty
以b
开头的表示块设备(block),以c
开头的表示字符设备(character)。块设备一般是指硬盘(HDD),固态硬盘(SSD),移动存储介质如SD卡,TF卡,U盘等,其他拥有设备节点的驱动基本都属于字符设备。暂时仅关注字符设备驱动。
极简字符设备驱动
#include <linux/module.h>
#include <linux/fs.h>// 主设备号
static int major;
static char devName[] = "mychardev";// 对应应用空间的open系统调用
static int chardev_open(struct inode *inode, struct file *file)
{printk(KERN_INFO "chardev open\n");return 0;
}// 对应应用空间的close系统调用
static int chardev_release(struct inode *inode, struct file *file)
{printk(KERN_INFO "chardev release\n");return 0;
}// 字符设备驱动对应的文件操作结构
static struct file_operations fOpts = {.owner = THIS_MODULE,.open = chardev_open,.release = chardev_release
};//加载内核模块后的入口函数
static int __init chardev_drv_init(void)
{printk(KERN_INFO "chardev driver init\n");//向内核注册字符设备驱动major = register_chrdev(0, devName, &fOpts);if (major < 0){printk(KERN_ERR "chardev driver regist\n");return major;}printk(KERN_INFO "got major:%d\n", major);return 0;
}//卸载内核模块后的清理函数
static void __exit chardev_drv_exit(void)
{//向内核注销字符设备驱动unregister_chrdev(major, devName);printk(KERN_INFO "chardev driver exit\n");
}module_init(chardev_drv_init);
module_exit(chardev_drv_exit);MODULE_LICENSE("GPL");
编译该字符设备驱动的Makfile:
KERN_DIR=/usr/src/linux-headers-$(shell uname -r)all:make -C ${KERN_DIR} M=$(shell pwd) modulesclean:make -C ${KERN_DIR} M=$(shell pwd) modules cleanobj-m += chardev_drv.o
编译后,插入驱动模块
make
sudo insmod chardev_drv.ko
通过dmesg可以看到内核日志输出:
[ 5476.132713] chardev driver init
[ 5476.132717] got major:237
到此应用程序如果要操作这个驱动,还缺乏对应的设备节点。这里需要我们手动创建设备节点:
sudo mknod /dev/testchardev c $(cat /proc/devices | grep mychardev | awk '{print $1}') 0
mknode命令用于手动创建设备节点,其命令创建设备节点的格式为:
mknod [选项]... 节点路径 类型 [主设备号 次设备号]
- 选项:一般可以通过
-m
指定创建的设备节点的文件权限。也可以在创建后通过chmod修改。 - 节点路径:习惯位于/dev下面或者其子目录,但是这仅仅是一个习惯而已,实际如果你想要,可以是任意位置。
- 类型:就是
c
,b
等,还可以是比较少见的p
或者u
,p
表示管道,u
和c
等价。 - 主,次设备号:当类型为
p
时不能指定主,次设备号,其他类型时,必须指定。