Chinaunix首页 | 论坛 | 博客
  • 博客访问: 241031
  • 博文数量: 27
  • 博客积分: 358
  • 博客等级: 一等列兵
  • 技术积分: 291
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-25 17:35
文章分类

全部博文(27)

文章存档

2015年(1)

2014年(4)

2013年(6)

2012年(4)

2011年(12)

分类: LINUX

2013-07-31 15:09:28

原文地址:字符设备驱动中的ioctl 作者:tmaclub

ioctl是设备驱动中的一个奇葩,所有不适合write,read等情况下,都可用它实现,有点像北方的杂烩菜。

言归正传,简单介绍下。

 

用户系统调用:int ioctl( int fd,unsigned long cmd, …)

驱动中对应的函数:

ioctl int*ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg),前两个参数和其他驱动函数一致,后面两个分别对应系统调用中的后两个。

道理就是这样简单,但是linux内核提供了一套标准方法来构造命令,后面再讲,首先测试下我们的ioctl

 

下面是一个最简单的ioctl调用,麻雀虽小,五脏俱全。

 

点击(此处)折叠或打开

 

  1. #include <linux/init.h>
  2. #include <linux/module.h>
  3. #include <linux/cdev.h>
  4. #include <linux/fs.h>
  5. #include <linux/types.h>
  6. #include <linux/slab.h>
  7. #include <linux/uaccess.h>
  8. #include <linux/moduleparam.h>
  9. //#include <linux/>


  10. MODULE_LICENSE("Dual BSD/GPL");

  11. int major=0;
  12. module_param(major,int,0);
  13. int minor=0;
  14. module_param(minor,int,0);
  15. struct test_dev{
  16.         char test[256];
  17.         struct cdev cdev;
  18. };
  19. struct test_dev* my_dev;

  20. int test_open(struct inode *inode,struct file *filp)
  21. {
  22.         printk(KERN_ALERT "open, tamclub");
  23.         return 0;
  24. }

  25. static int test_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg)
  26. {
  27.         switch(cmd){
  28.                 case 1:printk(KERN_ALERT "i o y");break;
  29.                 case 2:printk(KERN_ALERT "y o m");break;
  30.                 default:break;

  31.         }
  32. }
  33. int test_release(struct inode *inode,struct file *filp)
  34. {
  35.         printk(KERN_ALERT "close, tamclub");
  36.         return 0;
  37. }

  38. static struct file_operations test_fops={
  39.         .owner=THIS_MODULE,
  40.        .open=test_open,
  41.         .ioctl=test_ioctl,
  42.         .release=test_release,
  43. };
  44. static int hello_init(void)
  45. {
  46.         int ret;
  47.         dev_t dev;
  48.         my_dev=kmalloc(sizeof(struct test_dev),GFP_KERNEL);
  49.         if(!my_dev){
  50.                 printk("bad kmalloc");
  51.                 return -ENOMEM;
  52.         }
  53.         if(major){
  54.                 dev=MKDEV(major,minor);
  55.                 ret=register_chrdev_region(dev,0,"test");
  56.         }else{
  57.                 ret=alloc_chrdev_region(&dev,minor,1,"test");
  58.                 major=MAJOR(dev);
  59.                 printk(KERN_ALERT "%d",major);
  60.         }
  61.         if(ret<0){
  62.                 printk(KERN_ALERT "can't get major %d\n",major);
  63.         }
  64.         cdev_init(&my_dev->cdev,&test_fops);
  65.         my_dev->cdev.owner=THIS_MODULE;
  66.         my_dev->cdev.ops=&test_fops;

  67.         
  68.         ret=cdev_add(&my_dev->cdev,dev,1);
  69.         if(ret){
  70.                 printk(KERN_ALERT "error %d",ret);
  71.         }

  72.         printk(KERN_ALERT "Hello, tmaclub\n");
  73.         return 0;
  74. }

  75. static void hello_exit(void)
  76. {
  77.         unregister_chrdev_region(MKDEV(major,minor),1);
  78.         cdev_del(&my_dev->cdev);
  79.         kfree(my_dev);
  80.         printk(KERN_ALERT "Goodbye, tmaclub\n");
  81. }

  82. module_init(hello_init);
  83. module_exit(hello_exit);
下面是最简单的应用程序:

点击(此处)折叠或打开

  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <fcntl.h>
  4. #include <stdio.h>

  5. int main(void)
  6. {
  7.         int fd;
  8.         fd=open("/dev/my_dev",O_RDWR|O_NONBLOCK);
  9.         if(fd != -1){
  10.         printf("success");
  11.         ioctl(fd,1);
  12.         close(fd);
  13.         }
  14. }

调试结果如下:
open, tamclub<1>i o y<1>close, tamclub
调试过程中出现了了点小问题,就是打不开/dev/my_dev(设备节点,mknod创建),原来是权限不够。

执行如下命令解决:chmod 777 /dev/my_dev,然后再执行应用程序。

 

   上述虽然简单的实现了一个ioctl,但是如果内核中这样写,linux就成不了linux了。内核中提供了一套构建cmd和解析cmd的命令,用起来很方便,也避免了使用过程中的一些错误。

在Linux核心中是这样定义一个命令码的:
  ____________________________________
  | 设备类型 | 序列号 | 方向 |数据尺寸|
  |----------|--------|------|--------|
  | 8 bit  | 8 bit |2 bit |8~14 bit|
  |----------|--------|------|--------|

上述所说的宏就是用来构造和解析这些命令码的,有兴趣的可以试下,其实完全一样。

阅读(2014) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~