Chinaunix首页 | 论坛 | 博客
  • 博客访问: 7724408
  • 博文数量: 961
  • 博客积分: 15795
  • 博客等级: 上将
  • 技术积分: 16612
  • 用 户 组: 普通用户
  • 注册时间: 2010-08-07 14:23
文章分类

全部博文(961)

文章存档

2016年(1)

2015年(61)

2014年(41)

2013年(51)

2012年(235)

2011年(391)

2010年(181)

分类: 嵌入式

2011-09-22 16:30:28

大部分驱动除了需要具备读写设备的能力外,还需要具备对硬件控制的能力。例如,要求设备报告错误信息,改变波特率,这些操作常常通过ioctl方法来实现。

 

在用户空间,使用ioctl 系统调用来控制设备,原型:int ioctl(int fd,unsigned long cmd,...)

ioctl 驱动方法:int (*ioctl)(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg)

cmd参数从用户空间传下来,可选的参数arg 以一个unsigned long 的形式传递,不管它是一个整数或一个指针。如果cmd命令不涉及数据传输,则第3 个参数arg的值无任何意义。

 

在编写ioctl代码之前,首先需要定义命令。为了防止对错误的设备使用正确的命令,命令号应该在系统范围内是唯一的。ioctl 命令编码被划分为几个位段,include/asm/ioctl.h中定义了这些位字段:类型(幻数),序号,传送方向参数的大小Documentation/ioctl-number.txt文件中罗列了在内核中已经使用了的幻数。

定义ioctl 命令的正确方法是使用4 个位段, 这个列表中介绍的符号定义在:

Type:幻数(类型): 表明哪个设备的命令,在参考了ioctlnumber.txt之后选出,8 位宽。

Number:序号,表明设备命令中的第几个,8 位宽。

Direction数据传送的方向,可能的值是_IOC_NONE(没有数据传输),_IOC_READ, _IOC_WRITE数据传送是从应用程序的观点来看待的,_IOC_READ 意思是从设备读

Size用户数据的大小。(13/14位宽,视处理器而定)

 

内核提供了下列宏来帮助定义命令:

 _IO(typenr)      没有参数的命令

 _IOR(typenrdatatype)  从驱动中读数据

 _IOW(typenrdatatype) 写数据到驱动

 _IOWR(typenrdatatype)      双向传送,type number 成员作为参数被传递。

 

Ioctl函数实现(参数)

       如果是一个整数,可以直接使用。如果是指针,我们必须确保这个用户地址是有效的,因此使用前需进行正确的检查。

不需要检测: copy_from_user   copy_to_user       get_user       put_user

需要检测: __get_user       __put_user

 

Ioctl函数实现(参数检查)

int access_ok(int type, const void *addr, unsigned long size)

第一个参数是VERIFY_READ 或者VERIFY_WRITE,用来表明是读用户内存还是写用户内存addr 参数是要操作的用户内存地址,size 是操作的长度。如果ioctl 需要从用户空间读一个整数,那么size参数等于sizeof(int)access_ok 返回一个布尔值: 1 是成功(存取没问题)0 是失败(存取有问题),如果该函数返回失败, Ioctl应当返回

EFAULT

 

Ioctl驱动实现代码:

/* 定义幻数 */

#define MEMDEV_IOC_MAGIC  'k'

 

/* 定义命令 */

#define MEMDEV_IOCPRINT   _IO(MEMDEV_IOC_MAGIC, 1)

#define MEMDEV_IOCGETDATA _IOR(MEMDEV_IOC_MAGIC, 2, int)

#define MEMDEV_IOCSETDATA _IOW(MEMDEV_IOC_MAGIC, 3, int)

 

/*IO操作*/

int memdev_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)

{

 

    int err = 0;

    int ret = 0;

    int ioarg = 0;

   

    /* 检测命令的有效性 */

    if (_IOC_TYPE(cmd) != MEMDEV_IOC_MAGIC)

        return -EINVAL;

    if (_IOC_NR(cmd) > MEMDEV_IOC_MAXNR)

        return -EINVAL;

 

    /* 根据命令类型,检测参数空间是否可以访问 */

    if (_IOC_DIR(cmd) & _IOC_READ)

        err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));

    else if (_IOC_DIR(cmd) & _IOC_WRITE)

        err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));

    if (err)

        return -EFAULT;

 

    /* 根据命令,执行相应的操作 */

    switch(cmd) {

 

      /* 打印当前设备信息 */

      case MEMDEV_IOCPRINT:

      printk("<--- CMD MEMDEV_IOCPRINT Done--->\n\n");

        break;

     

      /* 获取参数 */

      case MEMDEV_IOCGETDATA:

        ioarg = 1101;

        ret = __put_user(ioarg, (int *)arg);

        break;

     

      /* 设置参数 */

      case MEMDEV_IOCSETDATA:

        ret = __get_user(ioarg, (int *)arg);

        printk("<--- In Kernel MEMDEV_IOCSETDATA ioarg = %d --->\n\n",ioarg);

        break;

 

      default: 

        return -EINVAL;

    }

    return ret;

 

}

 

完整代码:  设备Ioctl控制.rar   

阅读(1583) | 评论(0) | 转发(3) |
0

上一篇:并发控制

下一篇:内核等待队列

给主人留下些什么吧!~~