Linux设备驱动学习
学习新技术需要抓住要点,然后从全局把握技术的流程,再进而细化技术的细节,最后从本质上掌握技术。看了这么长时间的Linux Device Drivers,也配合看了其他从网上找的资料,终于是找到了门路,现在基本上从全局可以把握技术的流程了,至于细化技术细节,还需要更进一步的学习。
要点
Linux设备驱动主要分为两大类(几乎每个介绍Linux驱动的资料上都会这么介绍):字符设备驱动和块设备驱动。至于这么分类,完全是来源于实际需求。CPU的外设可以说是丰富多彩,五花八门,从最简单的UART,AD,DA,INTERRUPT,IIC,SPI,DMA到复杂一点的FLASH,CAN BUS,USB……但是Linux作为操作系统,需要尽可能的将硬件进行抽象,是用户能够尽量忽略硬件上的差别。所以,Linux就做了一个最简单、也是最高级别的抽象。将五花八门的设备笼统的分为处理的对象是单字符的还是多字符组成的块儿的。这样就出现了上述两种设备的分类,至于后来又出现了网络设备g,这完全是由于网络协议过于复杂,将其归为字符设备和块设备都不能很好反映其特点,所以就让其自成一派。
先从字符设备说起。Linux中有一个特点,将所有的东西都看作文件,这里就包括传统意义上的各种格式的文件,还包括Linux对于各物理设备的逻辑抽象——设备。这样做有一个好处,对于无论是传统意义上的文件还是设备都可以采用统一的操作方法,例如open、close、read、write等等。从这个意义上看,当初提出这个观点的人还是挺“懒”的,但“懒”的确是人类进步的不竭动力。对于普通文件,调用open此类的操作后,操作系统具体执行哪些细枝末节的操作,现在没有研究过,具体还不清楚。但是由于具体设备还是五花八门的,所以具体操作上,肯定有差别,所以需要不同的操作细节来处理用户的请求,并争取做到对于用户请求的响应需要和传统意义上的open得到的响应是类似的。这样,就需要在操作系统open此类方法和硬件之间做一层过渡——驱动程序。
重要的方法和数据结构:
Insmod、rmmod
Device name、device number
Module_init、module_exit
Register_chrdev_region、alloc_chrdev_region
File_operations及其成员open,release,read,write……
整体流程
Insmod会调用模块中的module_init函数,module_init函数会通过register_chrdev_region或者是类似的函数向系统注册设备,个人感觉向系统注册,和中断注册一样,完成的是device name和device number的绑定(至于为什么需要这样的绑定,就需要用Linux内核的原理来说明了,不属于这里的范围,现在也不是很清楚)。最后也是很重要的一步,将设备和file_operations绑定,这样当操作系统open/dev下的设备时,调用的设备驱动的open方法就确定了。这里确定的含义是:1、which使用哪一个方法知道了2、how使用什么样的方法也就知道了。
技术细节
设备号的维护:固定分配与动态申请
并发和竟态:互斥信号量、自旋锁的使用
阻塞非阻塞操作
异步通知
对于技术细节方面的东西,需要结合实际,在开发板上跑跑程序,所以买一块开发板玩玩儿。
融会贯通
Linux中的用户空间和内核空间采用不同的内存访问方式。内核空间可以直接操作硬件地址,而用户空间一般不能直接操作硬件地址。用户空间是采用了虚拟内存技术后的空间,暂且先这么说,用户空间的地址需要经过相应的转化才能够对应到实际的物理地址。这样,对于系统来说,在用户空间的操作更具有安全性。在ubuntu中,是不允许使用root用户登录的,而insmod命令是属于root用户的,所以在ubuntu中用户是以备不被允许通过insmod想内核插入模块的。所以,从这个意义上讲,使用普通用户登录对系统更具有安全性。可以使用sudo。