首页 技术 正文
技术 2022年11月16日
0 收藏 551 点赞 3,282 浏览 14851 个字

转自:http://my.oschina.net/u/274829/blog/285014

1,ioctl介绍

ioctl控制设备读写数据以及关闭等。

用户空间函数原型:int ioctl(int fd,unsinged long cmd,…)

  • fd-文件描述符

  • cmd-对设备的发出的控制命令

  • …表示这是一个可选的参数,存在与否依赖于cmd,如cmd为修改波特率,那么….就表示波特率的值。如果cmd表示关闭,则不需要参数

内核函数原型

file_operations结构体里面long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);

ioctl命令段分为:类型,序号,传递方向,参数大小

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

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

  • Direction 传送方向:可能的值是

_IOC_NONE(没数据传输)

_IOC_READ(从设备读)

_IOC_WRITE

  • Size 用户参数大小:(13/14位宽,视处理器而定)

内核提供了一些宏来帮助定义命令:

  • _IO(type, nr )    type为命令类型  如int, nr为序号

    没有参数的命令

  • _IOR(type, nr, datatype)

从驱动中读数据,datatype 读的数据参数的类型

  • _IOW(type, nr, datatype)

写数据到驱动

  • _IOWR(type,nr, datatype)

读写数据

定义命令例子  #define MEM_IOC_MAGIC ‘m’   //定义幻数,因为命令类型type是8位的所以找个字符代替

#define MEM_IOCSET

_IOW(MEM_IOC_MAGIC,0,int)   //命令 去写 一个 int型的数据

#define MEM_IOCGQSET

_IOR(MEM_IOC_MAGIC, 1, int)

2,ioctl命令使用时注意事项

用户使用int ioctl(int fd,unsinged long cmd,…)时,…就是要传递的参数

再通过long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long arg);中的arg传递,如果arg是一个整形,可以直接使用,如果是指针,我们必须确保这个用户地址是有效的,因此,使用之前需要进行正解的检查。

内部有检查的,不需要检测的:

Copy_from_user

Copy_to_user

Get_user

Put_user

需要检测的:

__get_user

__put_user

使用int access_ok(int type, const void *addr, unsigned long size)检测

Type 是VERIFY_READ 或者VERIFY_WRITE用来表明是读用户内存还是写用户内存。

Addr参数是要操作的用户内存地址,size是操作的长度。如果ioctl需要从用户空间读一个整数,那么size参数就等于sizeof(int)

linux 高级字符设备驱动 ioctl操作介绍 例程分析实现【转】

内核读,写入用户空间,所以用户空间使用VERIFY_WRITE写验证用户内存是否可用。

Access_ok返回一个布尔值:1,是成功(存取没问题),失败,ioctr返回-EFAULT

3,ioctl实现例程

?

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 #include <linux/module.h>#include <linux/types.h>#include <linux/fs.h>#include <linux/errno.h>#include <linux/mm.h>#include <linux/sched.h>#include <linux/init.h>#include <linux/cdev.h>#include <asm/io.h>#include <asm/system.h>#include <asm/uaccess.h> #include "memdev.h" static int mem_major = MEMDEV_MAJOR; module_param(mem_major, int, S_IRUGO); struct mem_dev *mem_devp; /*设备结构体指针*/ struct cdev cdev;  /*文件打开函数*/int mem_open(struct inode *inode, struct file *filp){    struct mem_dev *dev;         /*获取次设备号*/    int num = MINOR(inode->i_rdev);     if (num >= MEMDEV_NR_DEVS)             return -ENODEV;    dev = &mem_devp[num];         /*将设备描述结构指针赋值给文件私有数据指针*/    filp->private_data = dev;         return 0; } /*文件释放函数*/int mem_release(struct inode *inode, struct file *filp){  return 0;} /*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; } /*文件操作结构体*/static const struct file_operations mem_fops ={  .owner = THIS_MODULE,  .open = mem_open,  .release = mem_release,  .ioctl = memdev_ioctl,}; /*设备驱动模块加载函数*/static int memdev_init(void){  int result;  int i;   dev_t devno = MKDEV(mem_major, 0);   /* 静态申请设备号*/  if (mem_major)    result = register_chrdev_region(devno, 2, "memdev");  else  /* 动态分配设备号 */  {    result = alloc_chrdev_region(&devno, 0, 2, "memdev");    mem_major = MAJOR(devno);  }       if (result < 0)    return result;   /*初始化cdev结构*/  cdev_init(&cdev, &mem_fops);  cdev.owner = THIS_MODULE;  cdev.ops = &mem_fops;     /* 注册字符设备 */  cdev_add(&cdev, MKDEV(mem_major, 0), MEMDEV_NR_DEVS);      /* 为设备描述结构分配内存*/  mem_devp = kmalloc(MEMDEV_NR_DEVS * sizeof(struct mem_dev), GFP_KERNEL);  if (!mem_devp)    /*申请失败*/  {    result =  - ENOMEM;    goto fail_malloc;  }  memset(mem_devp, 0, sizeof(struct mem_dev));     /*为设备分配内存*/  for (i=0; i < MEMDEV_NR_DEVS; i++)   {        mem_devp[i].size = MEMDEV_SIZE;        mem_devp[i].data = kmalloc(MEMDEV_SIZE, GFP_KERNEL);        memset(mem_devp[i].data, 0, MEMDEV_SIZE);  }       return 0;   fail_malloc:   unregister_chrdev_region(devno, 1);     return result;} /*模块卸载函数*/static void memdev_exit(void){  cdev_del(&cdev);   /*注销设备*/  kfree(mem_devp);     /*释放设备结构体内存*/  unregister_chrdev_region(MKDEV(mem_major, 0), 2); /*释放设备号*/} MODULE_AUTHOR("David Xie");MODULE_LICENSE("GPL"); module_init(memdev_init);module_exit(memdev_exit);

.h

?

1234567891011121314151617181920212223242526272829303132333435 #ifndef _MEMDEV_H_#define _MEMDEV_H_ #include <linux/ioctl.h> #ifndef MEMDEV_MAJOR#define MEMDEV_MAJOR 190   /*预设的mem的主设备号*/#endif #ifndef MEMDEV_NR_DEVS#define MEMDEV_NR_DEVS 2    /*设备数*/#endif #ifndef MEMDEV_SIZE#define MEMDEV_SIZE 4096#endif /*mem设备描述结构体*/struct mem_dev                                     {                                                          char *data;                        unsigned long size;       }; /* 定义幻数 */#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) #define MEMDEV_IOC_MAXNR 3 #endif /* _MEMDEV_H_ */

Makefile

?

12345678910111213 ifneq ($(KERNELRELEASE),) obj-m := memdev.o else     KDIR := /forlinux/linux-3.0.1all:    make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-clean:    rm -f *.ko *.o *.mod.o *.mod.c *.symvers  modul* endif

测试程序

?

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657 #include <stdio.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h> #include "memdev.h"  /* 包含命令定义 */ int main(){    int fd = 0;    int cmd;    int arg = 0;    char Buf[4096];              /*打开设备文件*/    fd = open("/dev/memdev0",O_RDWR);    if (fd < 0)    {        printf("Open Dev Mem0 Error!\n");        return -1;    }         /* 调用命令MEMDEV_IOCPRINT */    printf("<--- Call MEMDEV_IOCPRINT --->\n");    cmd = MEMDEV_IOCPRINT;    if (ioctl(fd, cmd, &arg) < 0)        {            printf("Call cmd MEMDEV_IOCPRINT fail\n");            return -1;    }              /* 调用命令MEMDEV_IOCSETDATA */    printf("<--- Call MEMDEV_IOCSETDATA --->\n");    cmd = MEMDEV_IOCSETDATA;    arg = 2007;    if (ioctl(fd, cmd, &arg) < 0)        {            printf("Call cmd MEMDEV_IOCSETDATA fail\n");            return -1;    }          /* 调用命令MEMDEV_IOCGETDATA */    printf("<--- Call MEMDEV_IOCGETDATA --->\n");    cmd = MEMDEV_IOCGETDATA;    if (ioctl(fd, cmd, &arg) < 0)        {            printf("Call cmd MEMDEV_IOCGETDATA fail\n");            return -1;    }    printf("<--- In User Space MEMDEV_IOCGETDATA Get Data is %d --->\n\n",arg);           close(fd);    return 0;  }

1,ioctl介绍

ioctl控制设备读写数据以及关闭等。

用户空间函数原型:int ioctl(int fd,unsinged long cmd,…)

  • fd-文件描述符

  • cmd-对设备的发出的控制命令

  • …表示这是一个可选的参数,存在与否依赖于cmd,如cmd为修改波特率,那么….就表示波特率的值。如果cmd表示关闭,则不需要参数

内核函数原型

file_operations结构体里面long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);

ioctl命令段分为:类型,序号,传递方向,参数大小

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

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

  • Direction 传送方向:可能的值是

_IOC_NONE(没数据传输)

_IOC_READ(从设备读)

_IOC_WRITE

  • Size 用户参数大小:(13/14位宽,视处理器而定)

内核提供了一些宏来帮助定义命令:

  • _IO(type, nr )    type为命令类型  如int, nr为序号

    没有参数的命令

  • _IOR(type, nr, datatype)

从驱动中读数据,datatype 读的数据参数的类型

  • _IOW(type, nr, datatype)

写数据到驱动

  • _IOWR(type,nr, datatype)

读写数据

定义命令例子  #define MEM_IOC_MAGIC ‘m’   //定义幻数,因为命令类型type是8位的所以找个字符代替

#define MEM_IOCSET

_IOW(MEM_IOC_MAGIC,0,int)   //命令 去写 一个 int型的数据

#define MEM_IOCGQSET

_IOR(MEM_IOC_MAGIC, 1, int)

2,ioctl命令使用时注意事项

用户使用int ioctl(int fd,unsinged long cmd,…)时,…就是要传递的参数

再通过long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long arg);中的arg传递,如果arg是一个整形,可以直接使用,如果是指针,我们必须确保这个用户地址是有效的,因此,使用之前需要进行正解的检查。

内部有检查的,不需要检测的:

Copy_from_user

Copy_to_user

Get_user

Put_user

需要检测的:

__get_user

__put_user

使用int access_ok(int type, const void *addr, unsigned long size)检测

Type 是VERIFY_READ 或者VERIFY_WRITE用来表明是读用户内存还是写用户内存。

Addr参数是要操作的用户内存地址,size是操作的长度。如果ioctl需要从用户空间读一个整数,那么size参数就等于sizeof(int)

linux 高级字符设备驱动 ioctl操作介绍 例程分析实现【转】

内核读,写入用户空间,所以用户空间使用VERIFY_WRITE写验证用户内存是否可用。

Access_ok返回一个布尔值:1,是成功(存取没问题),失败,ioctr返回-EFAULT

3,ioctl实现例程

?

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 #include <linux/module.h>#include <linux/types.h>#include <linux/fs.h>#include <linux/errno.h>#include <linux/mm.h>#include <linux/sched.h>#include <linux/init.h>#include <linux/cdev.h>#include <asm/io.h>#include <asm/system.h>#include <asm/uaccess.h> #include "memdev.h" static int mem_major = MEMDEV_MAJOR; module_param(mem_major, int, S_IRUGO); struct mem_dev *mem_devp; /*设备结构体指针*/ struct cdev cdev;  /*文件打开函数*/int mem_open(struct inode *inode, struct file *filp){    struct mem_dev *dev;         /*获取次设备号*/    int num = MINOR(inode->i_rdev);     if (num >= MEMDEV_NR_DEVS)             return -ENODEV;    dev = &mem_devp[num];         /*将设备描述结构指针赋值给文件私有数据指针*/    filp->private_data = dev;         return 0; } /*文件释放函数*/int mem_release(struct inode *inode, struct file *filp){  return 0;} /*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; } /*文件操作结构体*/static const struct file_operations mem_fops ={  .owner = THIS_MODULE,  .open = mem_open,  .release = mem_release,  .ioctl = memdev_ioctl,}; /*设备驱动模块加载函数*/static int memdev_init(void){  int result;  int i;   dev_t devno = MKDEV(mem_major, 0);   /* 静态申请设备号*/  if (mem_major)    result = register_chrdev_region(devno, 2, "memdev");  else  /* 动态分配设备号 */  {    result = alloc_chrdev_region(&devno, 0, 2, "memdev");    mem_major = MAJOR(devno);  }       if (result < 0)    return result;   /*初始化cdev结构*/  cdev_init(&cdev, &mem_fops);  cdev.owner = THIS_MODULE;  cdev.ops = &mem_fops;     /* 注册字符设备 */  cdev_add(&cdev, MKDEV(mem_major, 0), MEMDEV_NR_DEVS);      /* 为设备描述结构分配内存*/  mem_devp = kmalloc(MEMDEV_NR_DEVS * sizeof(struct mem_dev), GFP_KERNEL);  if (!mem_devp)    /*申请失败*/  {    result =  - ENOMEM;    goto fail_malloc;  }  memset(mem_devp, 0, sizeof(struct mem_dev));     /*为设备分配内存*/  for (i=0; i < MEMDEV_NR_DEVS; i++)   {        mem_devp[i].size = MEMDEV_SIZE;        mem_devp[i].data = kmalloc(MEMDEV_SIZE, GFP_KERNEL);        memset(mem_devp[i].data, 0, MEMDEV_SIZE);  }       return 0;   fail_malloc:   unregister_chrdev_region(devno, 1);     return result;} /*模块卸载函数*/static void memdev_exit(void){  cdev_del(&cdev);   /*注销设备*/  kfree(mem_devp);     /*释放设备结构体内存*/  unregister_chrdev_region(MKDEV(mem_major, 0), 2); /*释放设备号*/} MODULE_AUTHOR("David Xie");MODULE_LICENSE("GPL"); module_init(memdev_init);module_exit(memdev_exit);

.h

?

1234567891011121314151617181920212223242526272829303132333435 #ifndef _MEMDEV_H_#define _MEMDEV_H_ #include <linux/ioctl.h> #ifndef MEMDEV_MAJOR#define MEMDEV_MAJOR 190   /*预设的mem的主设备号*/#endif #ifndef MEMDEV_NR_DEVS#define MEMDEV_NR_DEVS 2    /*设备数*/#endif #ifndef MEMDEV_SIZE#define MEMDEV_SIZE 4096#endif /*mem设备描述结构体*/struct mem_dev                                     {                                                          char *data;                        unsigned long size;       }; /* 定义幻数 */#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) #define MEMDEV_IOC_MAXNR 3 #endif /* _MEMDEV_H_ */

Makefile

?

12345678910111213 ifneq ($(KERNELRELEASE),) obj-m := memdev.o else     KDIR := /forlinux/linux-3.0.1all:    make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-clean:    rm -f *.ko *.o *.mod.o *.mod.c *.symvers  modul* endif

测试程序

?

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657 #include <stdio.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h> #include "memdev.h"  /* 包含命令定义 */ int main(){    int fd = 0;    int cmd;    int arg = 0;    char Buf[4096];              /*打开设备文件*/    fd = open("/dev/memdev0",O_RDWR);    if (fd < 0)    {        printf("Open Dev Mem0 Error!\n");        return -1;    }         /* 调用命令MEMDEV_IOCPRINT */    printf("<--- Call MEMDEV_IOCPRINT --->\n");    cmd = MEMDEV_IOCPRINT;    if (ioctl(fd, cmd, &arg) < 0)        {            printf("Call cmd MEMDEV_IOCPRINT fail\n");            return -1;    }              /* 调用命令MEMDEV_IOCSETDATA */    printf("<--- Call MEMDEV_IOCSETDATA --->\n");    cmd = MEMDEV_IOCSETDATA;    arg = 2007;    if (ioctl(fd, cmd, &arg) < 0)        {            printf("Call cmd MEMDEV_IOCSETDATA fail\n");            return -1;    }          /* 调用命令MEMDEV_IOCGETDATA */    printf("<--- Call MEMDEV_IOCGETDATA --->\n");    cmd = MEMDEV_IOCGETDATA;    if (ioctl(fd, cmd, &arg) < 0)        {            printf("Call cmd MEMDEV_IOCGETDATA fail\n");            return -1;    }    printf("<--- In User Space MEMDEV_IOCGETDATA Get Data is %d --->\n\n",arg);           close(fd);    return 0;  }
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,492
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,907
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,740
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,495
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:8,132
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:5,297