Chinaunix首页 | 论坛 | 博客
  • 博客访问: 686286
  • 博文数量: 152
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1793
  • 用 户 组: 普通用户
  • 注册时间: 2013-09-12 12:26
个人简介

相信自己,只有不想做的,没有做不到的。

文章分类

全部博文(152)

文章存档

2021年(1)

2015年(2)

2014年(74)

2013年(75)

分类: LINUX

2014-06-10 14:43:35

驱动只实现ioctrl接口并使用ioctl修改和读取内核中的一个整型参数为例,使用两个不同方式读取(值传递和地址传递)。

应用程序测试代码main.c

  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6.   
  7. #define IOCTL_RESET 100 /*重置命令*/  
  8. #define IOCTL_GET1  101 /*读取命令值返回*/  
  9. #define IOCTL_GET2  102 /*读取命令地址返回*/  
  10. #define IOCTL_SET1  103 /*设置命令值传入*/  
  11. #define IOCTL_SET2  104 /*设置命令地址传入*/  
  12.   
  13. int main (int *argc,char**argv)  
  14. {  
  15.   int  fs;int val;  
  16.   fs=open("/dev/moduledev60",O_RDWR);  
  17.   if(fs<0)  
  18.   {  
  19.     printf("open fail\n");  
  20.     return -1;  
  21.   }  
  22.   
  23.   ioctl(fs,IOCTL_SET1,1000);                               //使用值传入设置参数  
  24.   printf("ioctl get1 result:%d\n",ioctl(fs,IOCTL_GET1));   //使用返回值读取参数  
  25.   ioctl(fs,IOCTL_GET2,&val);                               //使用地址读取参数   
  26.   printf("ioctl get2 result:%d\n",val);          
  27.   
  28.   /*当设置参数是负数时 使用返回值读参数会出错 由于ioctl返回负数会被内核认为错误*/  
  29.   ioctl(fs,IOCTL_SET1,-100);                               //使用值传入设置参数  
  30.   printf("ioctl get1 result:%d\n",ioctl(fs,IOCTL_GET1));   //使用返回值读取参数  
  31.   ioctl(fs,IOCTL_GET2,&val);                               //使用地址读取参数   
  32.   printf("ioctl get2 result:%d\n",val);    
  33.   
  34.   /*使用地址传入设置参数*/  
  35.   val=5555;  
  36.   ioctl(fs,IOCTL_SET2,&val);  
  37.   printf("ioctl get1 result:%d\n",ioctl(fs,IOCTL_GET1));  
  38.    
  39.   close(fs);  
  40.   return 0;  
  41. }  


驱动主要部分 fileops.c


  1. #define IOCTL_RESET 100 /*重置命令*/  
  2. #define IOCTL_GET1  101 /*读取命令值返回*/  
  3. #define IOCTL_GET2  102 /*读取命令地址返回*/  
  4. #define IOCTL_SET1  103 /*设置命令值传入*/  
  5. #define IOCTL_SET2  104 /*设置命令地址传入*/  
  6. int drive_param=0;  
  7. int fileops_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)  
  8. {  
  9.   printk(KERN_ALERT "fileops_ioctl  \n");  
  10.   switch(cmd)  
  11.   {  
  12.     case IOCTL_RESET:  
  13.       drive_param=0;  
  14.       break;  
  15.     case IOCTL_GET1:  
  16.       return drive_param;  
  17.       break;  
  18.     case IOCTL_GET2:  
  19. //    __put_user(drive_param,(int __user *)arg);  
  20.       if(copy_to_user((int __user*)arg,&drive_param,4)) return -ENOTTY;  
  21.       break;  
  22.     case IOCTL_SET1:  
  23.       drive_param=arg;  
  24.       break;  
  25.     case IOCTL_SET2:  
  26. //    __get_user(drive_param,(int __user *)arg);  
  27.       if(copy_from_user(&drive_param,(int __user*)arg,4))return -ENOTTY;  
  28.       break;    
  29.   }  
  30.   return 0;  
  31. }  

传送单个值时使用 __put_user __get_user要比copy相对快,  注意 __put_user,__get_user 应当只用在已经使用 access_ok 校验过的地址.copy_from_user和copy_to_user跟踪代码会发现已经加了access_ok的校验。



执行结果

  1. ioctl get1 result:1000  
  2. ioctl get2 result:1000  
  3. ioctl get1 result:-1  
  4. ioctl get2 result:-100  
  5. ioctl get1 result:5555  

会发现使用值返回负数-100时,驱动接口内返回-100应用程序的ioctl返回的是-1,使用地址传递参数则正确读取。



下面是部分ioctl-number.tx的内容


  1. If you are adding new ioctl's to the kernel, you should use the _IO macros defined in <linux/ioctl.h>:  
  2.   
  3.     _IO    an ioctl with no parameters  
  4.     _IOW   an ioctl with write parameters (copy_from_user)  
  5.     _IOR   an ioctl with read parameters  (copy_to_user)  
  6.     _IOWR  an ioctl with both write and read parameters.  
  7.   
  8. 'Write' and 'read' are from the user's point of view, just like the system calls 'write' and 'read'.  For example, a SET_FOO ioctl would be _IOW, although the kernel would actually read data from user space;  
  9. a GET_FOO ioctl would be _IOR, although the kernel would actually write data to user space.  
  10.   
  11. The first argument to _IO, _IOW, _IOR, or _IOWR is an identifying letter or number from the table below.  Because of the large number of drivers,many drivers share a partial letter with other drivers.  
  12.   
  13. If you are writing a driver for a new device and need a letter, pick an unused block with enough room for expansion: 32 to 256 ioctl commands.  
  14. You can register the block by patching this file and submitting the patch to Linus Torvalds.  Or you can e-mail me at <mec@shout.net> and I'll register one for you.  
  15.   
  16. The second argument to _IO, _IOW, _IOR, or _IOWR is a sequence number to distinguish ioctls from each other.  The third argument to _IOW,_IOR, or _IOWR is the type of the data going into the kernel or coming out of the kernel (e.g.  'int' or 'struct foo').  NOTE!  Do NOT use sizeof(arg) as the third argument as this results in your ioctl thinking it passes an argument of type size_t.  
  17. Some devices use their major number as the identifier; this is OK, as long as it is unique.  Some devices are irregular and don't follow any convention at all.  
  18.   
  19. Following this convention is good because:  
  20. (1) Keeping the ioctl's globally unique helps error checking: if a program calls an ioctl on the wrong device, it will get an  error rather than some unexpected behaviour.  
  21. (2) The 'strace' build procedure automatically finds ioctl numbers  defined with _IO, _IOW, _IOR
  22. (3) 'strace' can decode numbers back into useful na
  23. , or _IOWR.  mes when the  numbers are unique.  
  24. (4) People looking for ioctls can grep for them more easily when  this convention is used to define the ioctl numbers.  
  25. (5) When following the convention, the driver code can use generic  code to copy the parameters between user and kernel spac
阅读(795) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~