不知道怎么开始写好,看着空白的博客想了好几分钟,最后决定按驱动使用步骤开始一步一步介绍,这里假设读者已经有一点驱动程序的知识了,因为基础知识实在是不好解释清楚。
1、驱动使用前肯定要先创建设备文件,设备文件与驱动的关系差不多就是驱动的读写操作都是针对设备文件。创建设备文件命令很简单:
mknod /dev/P0 c 126 0
/dev/P0 是设备文件名,c 表示驱动类型(字符型),126 表示主设备号,0 表示次设备号
2、创建好设备文件后,就要将设备文件对应的驱动模块插入到内核中,命令如下:
insmod gpio
gpio 是驱动程序名称
这里再看看开发板给的文件“./loadgpio”里面的内容就很好理解了
rm -f /dev/P
mknod /dev/P0 c 126 0
insmod gpio
前面算是完成了驱动程序使用的预备工作,此时应用程序就可以使用驱动程序了。完成上面可能有人就会问,将驱动程序和设备文件关联起来是怎么实现的呢?这就需要深入到驱动程序内部了。
3、关于insmod命令与module_init()函数的介绍:
使用insmod gpio命令系统就会调用驱动程序gpio的module_init()函数,这里介绍module_init中关键的一步,调用register_chrdev()函数,先看看函数的原型
int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);
major 是主设备号,name 是驱动程序名称(记住不是设备文件名,我当时就是有弄混淆了),fops 这个不不好解释了,不说了
4、再下来就是应用成学的open、read、write、ioctl等函数,这里就不介绍这么回事,前面的结构体fops在这里起到关键作用哦,因为已经假设你们理解了,就不多少了。
5、下面就要说明gpio驱动程序用到的关键--ioctl函数了。先看看ioctl函数的原型:
int ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
inode 包含打开设备文件相关信息的结构体地址,filp 包含设备驱动程序处理相关信息的结构体地址,cmd 应用程序传递的地址,arg 处理cmd命令的附加数据
这里cmd是一个32位的数据,包含8位的区别序号用于区别命令顺序序号,8位的魔数(magic number)用于区别其他设备驱动程序的ioctl命令,14位的数据大小用于表示arg变量传送的内存大小,还有1位的区别读写位。
手动书写cmd数据比较麻烦,为此linux为创建cmd常数值提供了一些宏函数:
_IO(魔数,基数):创建没有附加数据的命令的宏
_IOR(魔数,基数,变量型):创建从设备驱动程序读取数据的命令的宏
_IOW(魔数,基数,变量型):创建从设备驱动程序上写入数据的命令的宏
_IOWR(魔数,基数,变量型):创建从设备驱动程序读写数据的命令的宏
还有解释cmd命令的宏函数
_IOC_NR(cmd):读取基数域值的宏
_IOC_TYPE(cmd):读取魔数域值的宏
_IOC_SIZE(cmd):读取数据大小域值的宏
_IOC_DIR(cmd):读取读写属性域值的宏
上面宏产生的cmd直接用在应用程序的函数ioctl(fd,cmd,arg)中。
6、最后介绍gpio驱动程序用到的access_ok()函数,用于检查用户空间指针是否可用,取代verfiy_area()函数,函数原型如下:
int access_ok (type, addr, size);
type 访问类型,其值可为VERIFY_READ或VERIFY_WRITE,addr 用户空间的指针变量,其指向一个要检查的内存块开始处,size 要检查内存块的大小