分类: LINUX
2012-09-20 16:50:35
字符设备
字符设备是个能够象字节流(比如文件)一样访问的设备,由字符设备驱动程序来实现这种特性。通过/dev下的字符设备文件来访问。字符设备驱动程序通常至少需要实现 open、close、read 和 write 系统调用。
大多数字符设备是个只能顺序访问的数据通道,不能前后移动访问指针,这点和文件不同。比如串口驱动,只能顺序的读写设备。然而,也存在和数据区或者文件特性类似的字符设备,访问它们时可前后移动访问指针。
主设备号和次设备号
主设备号是内核识别一个设备的标识。是一个整数,范围从0到(4096-1),但是一般使用1到255。
次设备号是驱动程序自己用来区别多个设备。是一个整数,范围从0到(1048576-1),但是一般使用0到255。
预定义的主设备号:详见Documentation/devices.txt
/dev目录下查看主次设备号
设备号
系统用一个dev_t 结构定义变量表示设备号,实际它是主设备号和次设备号的综合。
怎样通过设备号获得主或者次设备号?
MAJOR(dev_t dev);
MINOR(dev_t dev);
怎样通过主次设备号获得设备号?
MKDEV(int major, int minor);
申请设备号
register_chrdev_region
主设备号已经确认的情况下使用。
参数分别是设备号,次设备号数量,设备名称
alloc_chrdev_region
自动分配主设备号
参数分别是获取的设备号(输出参数),第一个次设备号,次设备号数量,设备名称
字符设备注册
cdev_init
字符设备初始化。
参数分别是字符设备结构指针,文件操作结构指针。
cdev_add
字符设备添加。
参数分别是字符设备结构指针,设备号,次设备号数量。
释放函数接口
cdev_del
参数是字符设备结构指针。
unregister_chrdev_region
参数分别是设备号,次设备号数量。
文件操作
字符驱动和内核的接口:file_operations结构体。结构体多是一些函数指针,我们要实现其中的主要函数。在(include/linux/fs.h)定义。
字符驱动只要实现一个file_operations结构体,并注册到内核中,内核就有了操作此设备的能力。
file_operations的主要域:
struct module *owner:指向模块自身。
open:打开设备。
release:关闭设备。
read:从设备上读数据。
write::向设备上写数据。
ioctl:操作设备函数。
打开文件操作
open(struct inode *inode, struct file *filp)
模块使用计数加1。
识别次设备号,如有必要更新f_op 指针。分配并填写置于filp->private_data 里的数据结构。
硬件操作:
检查设备相关错误(诸如设备未就绪或类似的硬件问题)。
如果设备是首次打开,则对其初始化。
如果有中断操作,申请中断处理程序。
关闭文件操作
release(struct inode *inode, struct file *filp)
模块使用计数减1
释放放由open 分配的,保存在filp->private_data中的所有内容
硬件操作
如果申请了中断,则释放中断处理程序。
在最后一次关闭操作时关闭设备
读写文件操作
ssize_t read(struct file *filp, char *buff, size_t count, loff_t *offp);
ssize_t write(struct file *filp, const char *buff, size_t count, loff_t *offp);
参数说明:
参数filp 是文件指针,
参数buff 是指向用户空间的缓冲区,这个缓冲区或者保存将写入的数据,或者是一个存放新读入数据的空缓冲区。
参数count 是请求传输的数据长度。
最后的offp 是一个指向“long offset type(长偏移量类型)”对象的指针,这个对象指明用户在文件中存取操作的位置。
Io控制文件操作
ioctl函数,为设备驱动程序执行“命令”提供了一个特有的入口点,用来设置或者读取设备的属性信息。
int (*ioctl) (struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg);
在用户空间对应的ioctl 系统调用为:
int ioctl(int d, int cmd, ...);
在用户空间对字符设备调用ioctl系统调用,会最终调用字符设备的ioctl函数。