费加罗的婚礼钢琴谱:linux ioctl函数及其驱动和应用程序注意事项
来源:百度文库 编辑:中财网 时间:2024/05/09 06:52:14
linux ioctl函数及其驱动和应用程序注意事项
分类: 嵌入式 2010-03-05 14:48 427人阅读 评论(1) 收藏 举报关于IOCTL驱动的编写方法LDD这本书确实写的比较明白了,在这呢我就简单的做一个介绍。这里我主要描述自己编写IOCTL驱动时所遇到的问题及其原因。
驱动里的ioctl函数主要实现不用read,write函数的与用户空间的简单数据交互及无参数的命令控制。那么我们如何实现这几种功能的IOCTL函数呢?ioctl驱动中以SWITCH{case A,caseB}结构以实现对不同命令的响应,首先我们要对我们要使用的“A”,“B”命令定义一个整个操作系统内唯一的标识,同时这个标识又能够表明我们的操作类型及传递参数的类型(如果需要的话)。linux系统的每一个命令号被分为多个位字段,这些位字段包括type,number,direction,size,分别表示幻数(与设备相关的一个字母,以避免与内核冲突),序数(命令编号),方向位(以用户空间为参照的读,写和无数据传输),size(传递参数类型)。内核中/include/asm/ioctl.h,/Documentation/ioctl-number.txt两个文件表明了我们应该如何定义ioctl命令编号及自定义的幻数,。
看起来构造IOTCL命令这么复杂,庆幸的是内核已经为我们编写了构造命令编号的宏命令。_IO(type,nr),_IOR(type,nr,datatype),_IOW(type,nr,datatype)。它们在
这里把我所写的部分代码贴出来:
驱动程序部分代码:
- #define MOTOR_MAGIC 'k'
- #define SET_PULSE _IOW(MOTOR_MAGIC, 1,int)
- .
- .
- static int motor_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg)
- { int data=0;
- int retval;
- switch (cmd) {
- case SET_PULSE:
- if (copy_from_user(&data, (int *)arg, sizeof(int)))
- return -EFAULT;
- .
- .
- .
- }
应用程序部分代码:
[c-sharp] view plaincopyprint?
- #define MOTOR_MAGIC 'k'
- #define SET_PULSE _IOW(MOTOR_MAGIC, 1,int)
- int pulse,fileno;
- fileno = open("/tmp/usb",O_RDWR);
- if (fileno == -1) {
- printf("open device key error!/n");
- return 0;
- }
- .
- .
- printf("Please input the pulse:/n"
- scanf("%d",pulse);
- if(ioctl(fileno,SET_PULSE,pulse)<0){
- perror("ioctl error");
- exit(1);
- }
- .
- .
这里我们一定要注意的是data 和pulse的数据类型一定要与SET_PULSE _IOW(MOTOR_MAGIC, 1,int)中定义的int类型严格一致,即使是unsigned int 和int类型之间也是有很大差别的,我就是因为设定了unsignedint类型的data和pulse却使用SET_PULSE _IOW(MOTOR_MAGIC, 1,int)搞了我两三天才搞明白。再有就是ioctl函数的声明一定要与 static int motor_ioctl(struct inode *inode,structfile *filp,unsigned int cmd,unsigned longarg);相一致,我刚开始就是定义错了,也是搞了我好长时间才明白。因为内核非常的相信你,它不会检查你的IOTCL定义有没有问题,它只负责把你的IOCTL函数映射到驱动的ioctl操作上。其中inode和filp对应应用程序传递的文件描述符,这和传递给open方法的参数一样,参数cmd由用户空间不经修改的传递给驱动程序,可选的arg参数无论用户空间传递的是指针还是值,它都以unsigned long的形式传递给驱动程序。
还有就是我在驱动中明明是用的是使用地址的copy_from_usr函数,但用户程序却只能传递值.搞了半天最后才知道,原来我的用户程序中的scanf(x),'x'没有加'&'符号,所以这时从终端把读到的数据写到了'x'所代表的地址处,也就是说现在'x'所代表的地址正是所读入的数据.呵呵,总结出的经验就是----->对库函数的参数类型一定要搞清楚.