(1)概述
操作系统内核通过驱动来操作具体设备。驱动应该属于操作系统的一部分。在linux操作系统中,应用通过系统调用与操作系统进行交互。
linux中所有的硬件资源,都会被抽象一个文件。被称为设备文件。一般在/dev目录下存储。
驱动设备分为三种,字符设备,和块设备(如flash,硬盘,显卡,内存,e2rom),还有网络设备(如网卡,特点在于可以主动发起动作)。注意,网络设备没有对应的设备文件。
字符设备的属性第一个字符为b,块设备属性的第一个字符为c
主设备号设备相连的驱动(也就是具体一类用相同驱动设备),次编号表示具体的设备。
数据已字节流传送的,被称为字符设备。
模块是操作系统内核的一部分,他可以是静态编译在内核中,也可以动态加载。注意,驱动一定是模块,但是模块不一定是驱动。
对模块的操作有下面三个作用
Insmod 挂载模块
Rmmod 卸载模块
Lsmod 查看已经加载的模块
(2)字符设备
当用户使用insmod时,内核进行字符设备的注册
用户进行 open read write等等, 内核中进行初始化,控制底层硬件,进行数据传输
用户进行 rmmod ,从内核卸载该设备。
注意,上述的后半句操作都需要驱动开发者进行实现
设备注册
用下面函数进行注册
int register_chrdev(主设备号,设备名称,调用入口点结构体)
主设备号如果使用0,系统会自动为此驱动程序分配一个主设备号。
返回值如果成功的话,则会返回主设备号。设备名出现在/proc/devices下
用下面函数进行卸载
int unregister_chrdev(主设备号,设备名称)
成功的返回0,且设备在/proc/devices中消失。
下面具体讲所谓调用入口点结构体:(在linux/include/fs.h文件中定义)
该结构体中包含一系列函数指针。 注意,该结构体中的函数没必要都需要实现。常见的比如read,write,flush,open
驱动开发者要实现open函数如下功能
(1)递增计数器
(2)初始化函数
(3)识别次设备号
驱动开发者要实现read,write函数
传入参数中都含有buff。
驱动开发者ioctl函数,用于向设备发出特定命令
ummap常用显卡的驱动中含有,用于大量传输数据。
实现read和write要调用内核中本身含有的函数
copy_to_user(to,from,count)
copy_from_user(to,from.count)
kmalloc //申请连续(逻辑连续)的内存空间,是malloc的kernal版本。可以选择通过参数控制进程在内存不足时是否挂起,是否保证内存必须物理连续(用于DMA)。
kfree 与上面相对应。
printk,无法打印指定格式,但是可以对内容指定其紧急程度。常用的是ERR和DEBUG。
(3)实例:串口驱动设备(s3c2440)
一般来讲,驱动没有自己从头开始编写的。首先最好找相似的开发设备。
串口有tty终端设备层(tty_io.c),串口驱动核心层(serial_core.c),串口驱动设备抽象层(samsung.h),特定设备层(s3c2440.h)。(逐层更底层)
s3c2440.c重定义了最近本的设备操作,调用其中函数即可。