ioctl 函数.docx

上传人:b****0 文档编号:10063545 上传时间:2023-05-23 格式:DOCX 页数:10 大小:17.28KB
下载 相关 举报
ioctl 函数.docx_第1页
第1页 / 共10页
ioctl 函数.docx_第2页
第2页 / 共10页
ioctl 函数.docx_第3页
第3页 / 共10页
ioctl 函数.docx_第4页
第4页 / 共10页
ioctl 函数.docx_第5页
第5页 / 共10页
ioctl 函数.docx_第6页
第6页 / 共10页
ioctl 函数.docx_第7页
第7页 / 共10页
ioctl 函数.docx_第8页
第8页 / 共10页
ioctl 函数.docx_第9页
第9页 / 共10页
ioctl 函数.docx_第10页
第10页 / 共10页
亲,该文档总共10页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

ioctl 函数.docx

《ioctl 函数.docx》由会员分享,可在线阅读,更多相关《ioctl 函数.docx(10页珍藏版)》请在冰点文库上搜索。

ioctl 函数.docx

ioctl函数

Linux驱动之ioctl

分类:

ARM+Linux2010-05-0917:

10537人阅读评论(0)收藏举报

在用户空间,使用ioctl系统调用来控制设备,原型如下:

intioctl(intfd,unsignedlongcmd,...);

第三个参数不表示一个变数目的参数,而是一个类型可选的参数。

第三个参数依赖于控制命令。

一些命令不用参数,一些用一个整数值,一些使用指针

 

1、ioctl函数定义命令

 

在编写ioctl代码之前,首先需要定义命令。

为了防止对错误的设备使用正确的命令,命令号应该在系统范围内事唯一的

ioctl命令编码被划分为几个段,include/asm/ioctl.h中定义了这些字段:

类型(幻数),基数,传送方向,参数大小等。

Documentation/ioctl-number.txt文件中罗列了再内核中已经使用了的幻数。

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

 

Type:

幻数(类型):

表明哪个设备的命令,在参考了ioctl-number.txt之后选出,8位宽。

 

Number:

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

内核提供了下列宏来帮助定义命令号,如下

_IO(type,nr):

没有参数的命令

_IOR(type,nr,datatype):

从驱动中读数据

_IOW(type,nr,datatype):

写数据到驱动

_IOWR(type,nr,datatype):

双向传送,type和number作为参数被传递

 

2、ioctl函数的实现

 

分三个技术环节:

 

1、返回值

ioctl函数的实现通常是根据命令执行的一个switch语句。

但是当命令不能匹配任何一个设备所支持的命令时,通常返回-EINVAL(“非法参数”)

 

2、参数使用

如果是一个整数,可以直接使用。

如果是指针,我们必须确保这个用户地址是有效的,因此使用前需进行正确的检查

使用intaccess_ok(inttype,constvoid*addr,unsignedlongsize)来检查一个指针地址是否可以访问

第一个参数是VERIFY_READ或者是VERIFY_WRITE,用来表明读用户内存还是写用户内存。

addr参数时要操作的用户内存地址,size是操作的长度。

如果ioctl需要从用户空间读一个整数,那么size=sizeof(int)。

如果需要同时读和写,则使用VERIFY_WRITE。

access_ok返回一个布尔值:

1是成功(存取没问题)和0是失败(存取有问题),如果该函数返回失败,则ioctl应当返回-EFAULT,如:

 

if(_IOC_DIR(cmd)&_IOC_READ)//为什么_IOC_READ对应VERIFY_WRITE?

   err=!

access_ok(VERIFY_WRITE,(void __user*)arg,_IOC_SIZE(cmd));

elseif(_IOC_DIR(cmd)&_IOC_WRITE)

      err=!

access_ok(VERIFY_READ,(void __user*)arg,_IOC_SIZE(cmd));

if(err)

      return–EFAULT

 

在access_ok检测通过后,驱动可以使用cope_from_user和cope_to_user等函数进行参数传递了

 

3、命令操作

switch(cmd)

{

     caseMEMDEV_IOCPRINT:

        printk("<---CMDMEMDEV_IOCPRINTDone--->/n/n");

         break;

 

     caseMEMDEV_IOCGETDATA:

       ioarg=1101;

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

       break;

 

     caseMEMDEV_IOCSETDATA:

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

       printk("<---InKernelMEMDEV_IOCSETDATAioarg=%d--->/n/n",ioarg);

       break;

 

     default:

 

       return-ENOTTY;

}

 

实例分析,源码如下(最好先看《第一个嵌入式Linux的驱动程序》中的源码)

memdev.h:

#ifndef_MEMDEV_H_

#define_MEMDEV_H_

#include

#ifndefMEMDEV_MAJOR

#defineMEMDEV_MAJOR0  

#endif

#ifndefMEMDEV_NR_DEVS

#defineMEMDEV_NR_DEVS3   

#endif

#ifndefMEMDEV_SIZE

#defineMEMDEV_SIZE4096

#endif

typedefstructMem_Dev{

  char*data;

  structMem_Dev*next;  

  unsignedlongsize;

}Mem_Dev;

#defineMEMDEV_IOC_MAGIC 'k'

#defineMEMDEV_IOCPRINT  _IO(MEMDEV_IOC_MAGIC,1)

#defineMEMDEV_IOCGETDATA_IOR(MEMDEV_IOC_MAGIC,2,int)

#defineMEMDEV_IOCSETDATA_IOW(MEMDEV_IOC_MAGIC,3,int)

#defineMEMDEV_IOC_MAXNR3

#endif

 

memdev.c:

#ifndef__KERNEL__

# define__KERNEL__

#endif

#ifndefMODULE

# defineMODULE

#endif

//#include

#include

#include  

#include    

#include  

#include      

#include   

#include   

#include

#include 

#include  

#include"memdev.h"

 

MODULE_LICENSE("GPL");

Mem_Dev*mem_devices;

intmemdev_major=MEMDEV_MAJOR;

intmemdev_open(structinode*inode,structfile*filp)

{

   Mem_Dev*dev;

   

   intnum=MINOR(inode->i_rdev);

   dev=(Mem_Dev*)filp->private_data;

   if(!

dev)

   {

       if(num>=MEMDEV_NR_DEVS)

           return-ENODEV;

       dev=&mem_devices[num];

       filp->private_data=dev;

   }

   //MOD_INC_USE_COUNT;

   

   return0;         

}

intmemdev_release(structinode*inode,structfile*filp)

{

   //MOD_DEC_USE_COUNT;

   return0;

}

intmemdev_ioctl(structinode*inode,structfile*filp,

                unsignedintcmd,unsignedlongarg)

{

   interr=0;

   intret=0;

   intioarg=0;

   

   if(_IOC_TYPE(cmd)!

=MEMDEV_IOC_MAGIC)

       return-ENOTTY;

   if(_IOC_NR(cmd)>MEMDEV_IOC_MAXNR)

       return-ENOTTY;

   

   if(_IOC_DIR(cmd)&_IOC_READ)

       err=!

access_ok(VERIFY_WRITE,(void*)arg,_IOC_SIZE(cmd));

   elseif(_IOC_DIR(cmd)&_IOC_WRITE)

       err=!

access_ok(VERIFY_READ,(void*)arg,_IOC_SIZE(cmd));

   if(err)

       return-EFAULT;

   

   switch(cmd)

   {    

     caseMEMDEV_IOCPRINT:

      printk("<---CMDMEMDEV_IOCPRINTDone--->/n/n");

       break;

          

     caseMEMDEV_IOCGETDATA:

       ioarg=1101;

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

       break;

     

     caseMEMDEV_IOCSETDATA:

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

       printk("<---InKernelMEMDEV_IOCSETDATAioarg=%d--->/n/n",ioarg);

       break;

     default:

 

       return-ENOTTY;

   }

   returnret;

}

 

structfile_operationsmemdev_fops={

   ioctl:

     memdev_ioctl,

   open:

      memdev_open,

   release:

   memdev_release,

};

voidmemdev_cleanup_module(void)

{

   inti;

   

   unregister_chrdev(memdev_major,"memdev");

   

   if(mem_devices)

   {

       for(i=0;i

        kfree(mem_devices[i].data);

       kfree(mem_devices);

   }

}

intmemdev_init_module(void)

{

   intresult,i;

   

   //SET_MODULE_OWNER(&memdev_fops);

 

   result=register_chrdev(memdev_major,"memdev",&memdev_fops);

   if(result<0)

   {

       printk(KERN_WARNING"mem:

can'tgetmajor%d/n",memdev_major);

       returnresult;

   }

   if(memdev_major==0)

    memdev_major=result;

   

   mem_devices=kmalloc(MEMDEV_NR_DEVS*sizeof(Mem_Dev),GFP_KERNEL);

   if(!

mem_devices)

   {

       result=-ENOMEM;

       gotofail;

   }

   memset(mem_devices,0,MEMDEV_NR_DEVS*sizeof(Mem_Dev));

   

   for(i=0;i

   {

       mem_devices[i].size=MEMDEV_SIZE;

       mem_devices[i].data=kmalloc(MEMDEV_SIZE,GFP_KERNEL);

       memset(mem_devices[i].data,0,MEMDEV_SIZE);

   }

   

   return0;

 fail:

   memdev_cleanup_module();

   returnresult;

}

module_init(memdev_init_module);

module_exit(memdev_cleanup_mo

 

app-ioctl.c:

#include

#include

#include

#include

#include"memdev.h" 

 

intmain()

{

 intfd=0;

 intcmd;

 intarg=0;

 charBuf[4096];

 

 fd=open("/dev/memdev0",O_RDWR);

 if(fd<0)

 {

   printf("OpenDevMem0Error!

/n");

   return-1;

 }

 

 printf("<---CallMEMDEV_IOCPRINT--->/n");

 cmd=MEMDEV_IOCPRINT;

 if(ioctl(fd,cmd,&arg)<0)

 {

     printf("CallcmdMEMDEV_IOCPRINTfail/n");

     return-1;

 }

 

 printf("<---CallMEMDEV_IOCSETDATA--->/n");

 cmd=MEMDEV_IOCSETDATA;

 arg=2007;

 if(ioctl(fd,cmd,&arg)<0)

 {

     printf("CallcmdMEMDEV_IOCSETDATAfail/n");

     return-1;

 }

 

 printf("<---CallMEMDEV_IOCGETDATA--->/n");

 cmd=MEMDEV_IOCGETDATA;

 if(ioctl(fd,cmd,&arg)<0)

 {

     printf("CallcmdMEMDEV_IOCGETDATAfail/n");

     return-1;

 }

 printf("<---InUserSpaceMEMDEV_IOCGETDATAGetDatais%d--->/n/n",arg);

 

 close(fd);

 return0; 

}

Makefile和《第一个嵌入式Linux的驱动程序》中的Makefile一样。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 医药卫生 > 基础医学

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2