费加罗的婚礼钢琴谱: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)。它们在包含的中有定义,所以在我们的驱动中应包含这个头文件。其中_IO()用做无参数的命令编号,_IOR()用做从驱动中读取数据的命令编号,_IOW()用做写入数据命令。 LDD中用:defineSCULL_IOC_MAGIC 'k' ,define SCULL_IOCSQUANTUM_IOW(SCULL_IOC_MAGIC,1,int)表示SCULL_IOCSQUANTUM命令编号为向驱动中写数据,命令编号为1,传送参数类型为int。

这里把我所写的部分代码贴出来:
 驱动程序部分代码:

[c-sharp] view plaincopyprint?
  1.  #define MOTOR_MAGIC  'k'  
  2.  #define SET_PULSE _IOW(MOTOR_MAGIC,  1,int)  
  3.   .  
  4.   .  
  5.   static int motor_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg)  
  6. {      int data=0;   
  7.       int retval;  
  8.       switch (cmd) {  
  9.       case SET_PULSE:  
  10.               if (copy_from_user(&data, (int *)arg, sizeof(int)))  
  11.                return -EFAULT;  
  12.              .  
  13.              .  
  14.              .  
  15. }  
 
   
应用程序部分代码:  
[c-sharp] view plaincopyprint?
  1. #define MOTOR_MAGIC  'k'  
  2. #define SET_PULSE _IOW(MOTOR_MAGIC,  1,int)  
  3. int pulse,fileno;  
  4. fileno = open("/tmp/usb",O_RDWR);   
  5. if (fileno == -1) {   
  6.     printf("open device key error!/n");   
  7.     return 0;   
  8. }  
  9.    .  
  10.    .  
  11.    printf("Please input the pulse:/n"  
  12.    scanf("%d",pulse);    
  13.    if(ioctl(fileno,SET_PULSE,pulse)<0){  
  14.       perror("ioctl error");  
  15.       exit(1);  
  16.    }         
  17.     .  
  18.     .   
 
 这里我们一定要注意的是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'所代表的地址正是所读入的数据.呵呵,总结出的经验就是----->对库函数的参数类型一定要搞清楚.