Chinaunix首页 | 论坛 | 博客
  • 博客访问: 133776
  • 博文数量: 85
  • 博客积分: 3980
  • 博客等级: 中校
  • 技术积分: 1000
  • 用 户 组: 普通用户
  • 注册时间: 2009-06-08 06:42
文章分类

全部博文(85)

文章存档

2010年(1)

2009年(84)

我的朋友

分类: LINUX

2009-06-16 06:41:26

原型:int ioctl(struct inode *inode, struct file *filp,
                 unsigned int cmd, unsigned long arg);
当第一次看到驱动程序中的ioctl时,被它那大量的case所迷惑了。不是它的量大,而是应该怎样设定其中的分支为应用程序提供统一的入口参数,也就是说和其他驱动中ioctl的规则保持一致。
ioctl中第一个参数和第二个参数很明白。
要很好的编写驱动ioctl,就需要理解第三个参数cmd。
找到内核内核代码 include/asm/ioctl.h 中的相关定义和描述,就会明白应该按照什么规则来设定。
目前cmd是一个32位无符号整数,被分为4个字段。从高到底分别为
| dir | size | type | nr |
dir: 2bit,命令指示,表示命令类型
size: 14bit,数据大小,通常和第四个参数有关
type: 8bit,类型,又称之为幻数,表示设备的类型
nr: 8bit,命令序号。
各个字段的顺序和位宽可能在不同版本、不同平台的内核中是不同的,写内核模块时应使用内核提供的宏来作处理,而不直接设定。
当然这个cmd的规定对驱动程序来说并不是严格的,也可另起炉灶,但是这不好。
相对于驱动程序中的ioctl就是应用程序中的ioctl,其原型是:
ioctl (int __fd, unsigned long int __request, ...)
其中int __fd 是已经打开的文件描述符。
int __request 是请求命令字,这是与设备相关的,也就是对应驱动程序ioctl中的cmd
第三个参数依赖于第二个参数,通常是一个指针,或有或无。
同样对应用程序的request的设定也应使用相应的宏来处理,参看 /asm-generic/ioctl.h
下面以ldd3中提供的scull设备为对象,在应用程序中调用ioctl对其进行控制。
int main(void)
{
 int fd = open("/dev/scull",O_RDONLY);
 int qset_size = 2000;
 if(fd<0){
  printf("error\n");
  return 0;
 }
 ioctl(fd, _IO('k',0) ); // 其中k是scull设备的类型
 // 这条命令是复位scull设备中量子和量子集的大小。
 printf("%d\n", ioctl(fd,_IO('k',8) ) ); // 获取默认量子集大小
 ioctl(fd, _IOW('k',2,int), &qset_size ); // 更改量子集大小
 printf("%d\n", ioctl(fd,_IO('k',8) ) );
 close(fd);
 return 0;
}
实际上,这里调用宏函数来设定request,只是为了更清晰的了解如何设定request( 也就是设定驱动程序中的cmd),
而在应用程序中通常是直接给出其值。比如ioctl(sock, SIOCGIFNAME, &ifr)来获取接口名.

例:
userspase:
    struct my_entry {
       char back[9];
    };
    struct my_entry  mine;
    int fd = open(MY_FILE, O_RDWR);   
    err=ioctl(fd, GET_MINE, &mine);

Kernel:
int example_ioctl(struct inode *inode,
                        struct file *file,
                        unsigned int cmd,
                        /* The number of the ioctl */
                        unsigned long arg)
                        /* The parameter to it */
{

    struct my_entry entest;
    switch(cmd){
        case GET_MINE:
          copy_from_user(&entest, (struct my_entry*)arg, sizeof(struct my_entry));
          strncpy(entest.back,"I`m come",9);
          printk("%s \n", entest.back);
          copy_to_user((struct my_entry*)arg, &entest, sizeof(struct my_entry));
          return 0;
    }
    return -1;
}
阅读(862) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~