通过内核源码树编译得到的xxx.ko驱动下载到sd卡中,启动内核进入系统用insmod xxx.ko安装驱动,该命令会调用
module_init(chrdev_init)中指定的chrdev_init函数,在该函数里我们调用register_chrdev来进行注册,注册会申请以下三个结构体
char_device_struct,驱动程序描述符cdev,probe结构体来对应一个驱动程序
1 char_device_struct:
一个驱动程序有一个设备号范围,在该设备号范围的设备文件都会使用该驱动程序,将对应该驱动程序的char_device_struct
根据主设备号的hash值插入chrdevs数组,这是纵向插入,在其横向链表的插入过程中我们根据其设备号范围的大小将其小
在前大在后进行插入,结构体中cdev指向驱动程序描述符cdev
2 驱动程序描述符cdev
cdev中ops指向我们传入的file_operations结构体,
3 probe结构体 (用来根据设备号查找cdev)
内核中有段内存被cdev_map指向又来存储probe结构体的指针,与char_device_struct的存储方式相同,
probe中data指向cdev
通过 /proc/devices目录以及lsmod命令可以查看注册情况。
注册完成后创建设备文件:
mknod /dev/testchar c 250 0 只要改设备号在该驱动对应的设备号范围就会调用该驱动
下面分析mknod /dev/testchar c 250 0
系统调用会调用vfs_mknod(nd.path.dentry->d_inode,dentry,mode,new_decode_dev(dev));第一个参数为目录dev的inode
第二个参数为新建的testchar的目录项,该函数又会调用dev目录的inode的mknod方法找到该方法为ramfs_mknod
得到设备文件的inode且inode->i_fop = &def_chr_fops; inode->i_rdev = rdev;这样我们就完成了设备文件的创建
下面open("/dev/testchar", O_RDWR)分析打开设备文件的过程:
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode)
————do_sys_open(AT_FDCWD, filename, flags, mode);
————struct file *f = do_filp_open(dfd, tmp, flags, mode, 0);
————do_last
————finish_open
————nameidata_to_filp
————__dentry_open
————fd_install
在__dentry_open中我们将设备文件的节点的 i_fop赋给file结构体的 f_op 并执行其 open方法,我们创建设备文件时知道
设备文件的 inode->i_fop = &def_chr_fops,执行open即chrdev_open,该函数中我们根据inode->i_rdev即设备号在cdev_map
中查找对应的设备驱动程序描述符cdev并赋值给inode->i_cdev,将cdev中的ops赋给filp->f_op并执行其open方法
fd_install将文件描述符与file结构体绑定,此后IO文件操作将会调用驱动程序
使用新接口 register_chrdev_region/alloc_chrdev_region 注册分析:
操作 register_chrdev_region cdev_init cdev_add
新接口和老接口注册方式差不多
register_chrdev_region 注册 char_device_struct
cdev_init 初始化驱动程序描述符 cdev
cdev_add 向 cdev_map 注册 probe结构体