China Open source community
站内导航:

 
 
 
当前位置: 首页 >> 程序设计 >> Linux Device Driver 3读书笔记.Chapter1-3
 

Linux Device Driver 3读书笔记.Chapter1-3

作者:      来源:http://layne-sah.longlong.cn/sah/     发表时间:2006-03-16     浏览次数:      字号:    

这是第一章到第三章的笔记,主要是总结一下一些基础的概念性的东西。

声明:加了下划线的斜体表示我不能确定的内容,万一有谁轻信了可别怪我啊!

(一) 写Linux Device Driver的基本思路

  写驱动,其实主要就是三件事:

  1. 实现struct file_operations中的函数。一般至少需要实现六个:
    • int (*open) (struct inode *, struct file *);
    • int (*release) (struct inode *, struct file *);
    • ssize_t (*read) (struct file *, char __user *, size_t, loff_t);
    • ssize_t (*write) (struct file *, const char __user, size_t, loff_t);
    • loff_t (*llseek) (struct file *, loff_t, int);
    • int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
  2. 实现两个模块中必须的函数:
    • static int __init my_init(void);
    • static void __exit my_exit(void);
      模块,无外乎就是多了init和exit这两个函数,可以把驱动程序中实现的函数加载进内核中,和把驱动程序从内核中卸载。
  3. 写一个加载模块的脚本,里面要在用insmod加载了驱动模块之后,用mknode创建/dev中相应的文件。今后用户操作设备时都是通过访问/dev中的设备文件进行的。

(二) 一些重要的数据结构

  还有一些数据结构也比较关键,关系也比较复杂:

  • dev_t
    这个不是structure,是简单变量,只用于保存一组major number和minor number。Linux提供一组Macro对其进行读写:
    • MAJOR(dev_t dev); /* 取设备的major number */
    • MINOR(dev_t dev); /* 取设备的minor number */
    • MKDEV(int major, int minor); /* 从一组指定的major number和minor number创建一个dev_t */
  • struct cdev
    用于表示一个char型的设备。里厢内容不详
  • struct file_operations
    用于定义一组在某类文件上操作的函数,根据文件类型不同,需要实现的接口也不同。
  • struct file
    用于表示某个“打开的”文件,是与进程相关的。每次在有程序对文件执行open系统调用时创建。也就是说,同一个文件/设备,对应在其上操作的不同的进程,会创建多个file结构,而实际上操作的文件(或者说inode)是同一个。struct file里面有当前的指针位置和一些标记位等信息;还有指向一个file_operations结构的指针,对于设备文件,这用于提供到驱动程序的接口。
  • struct inode
    用于表示文件系统树形结构中的一个节点,不论是目录还是文件。它里面保存的是文件的具体信息,每个文件只对应一个inode结构。对于char型设备文件,这里面主要有两个field有用:
    • dev_t i_dev; /* 在表示设备文件的inode中用于存放major number和minor number */
    • struct cdev *i_cdev; /* 在表示char型设备文件的inode中用于存放指向对应的cdev的指针 */

(三) scull工作的大致过程:

  1. Linux启动时运行加载驱动模块的脚本。脚本首先做insmod。insmod时会调用驱动模块的init函数。在init中,进行了一些与设备本身相关的初始化设置以后(比如scull需要分配内存空间),会调用cdev_init()和cdev_add()来进行字符设备的初始化,并把这个设备添加进系统。这个过程会创建/proc/modules、/proc/devices两个文件和/sys/devices/目录中相应的项目。接下来脚本用mknod命令创建/dev/目录下的文件。这里创建的/dev/scull0,对应的就是前面说到的inode结构。
  2. 用户空间的程序通过系统调用open打开设备文件(比如在程序中fopen("/dev/scull0", "w" )),Linux会生成一个file结构,其中会包含f_pos(位置指针)、f_mode(打开方式是否只读等)等状态信息,然后调用驱动模块中定义的open()函数,把刚刚生成的file结构作为参数传给open()。open()通常需要根据情况做一些诸如设置互斥标记位之类的工作。
  3. 用户空间的程序通过系统调用进行读写操作(比如使用fprintf()等函数),会调用驱动程序中的read()、write()、llseek()等函数。这些操作会改变file结构中的信息,比如f_pos。
  4. 这时如果有另一个用户空间的程序打开这个设备文件,会再创建一个file结构,因为两个进程在访问时file结构中的信息是不同的,比如位置指针就不同。所以Linux把创建file结构的工作放在open系统调用时,而不是系统加载驱动模块时。但是需要注意的是,和第一个打开这个设备的文件不同,这次的file结构是从第一个进程中fork出来。这样,这个fork出来的进程不需要调用驱动程序中定义的release函数,在其返回时,file结构就会自动销毁。也就是说,只有一个进程会调用驱动程序中的open和release函数(虽然可能不只一个进程会试图关闭设备文件),也就保证了文件打开和关闭的次数不会有不同。
  5. 每一个程序完成操作,关闭设备文件时(比如使用fclose()函数),会销毁对应的file结构。但是只有最后一个进程关闭文件时才会调用驱动程序的release()函数。
  6. 关机时自然就是调用驱动模块中的exit函数,释放资源了。

编辑 webmaster

 
 
 
评论
 
 
发表
 
姓名: QQ:
性别: MSN:
E-mail: 主页:
评分: 1 2 3 4 5
评论内容:
验证码:
  
  • 请遵守《互联网电子公告服务管理规定》及中华人民共和国其他各项有关法律法规。
  • 严禁发表危害国家安全、损害国家利益、破坏民族团结、破坏国家宗教政策、破坏社会稳定、侮辱、诽谤、教唆、淫秽等内容的评论 。
  • 用户需对自己在使用本站服务过程中的行为承担法律责任(直接或间接导致的)。
  • 本站管理员有权保留或删除评论内容。
  • 评论内容只代表网友个人观点,与本网站立场无关。
  •  
    中国源码网 - WWW.YUANMA.ORG - 中国开放源代码社区