• ioctl命令字解释


    1、命令字字段说明

    每个 ioctl 命令实际上都是一个 32 位整型数,各字段和含义如表 2.1 所示。


    例如, 0x82187201 是带长度为 0x218 的参数读命令,功能号为 1,幻数用 ASCII 表示是“r”,实际上这个命令是<linux/msdos_fs.h>中的 VFAT_IOCTL_READDIR_BOTH 命令:

    #define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct __fat_dirent[2])

    2. 构造 ioctl 命令

    为驱动构造 ioctl 命令,首先要为驱动选择一个可用的幻数作为驱动的特征码,以区分不同驱动的命令。内核已经使用了很多幻数,为了防止冲突,最好不要再使用这些系统已经占用的幻数来作为驱动的特征码。已经被使用的幻数列表详见<Documentation/ioctl/ioctl-number.txt>文件。在不同平台上,幻数所使用情况都不同,为防止冲突,可以选择其它平台使用的幻数来用。

    选定幻数后,可以这样来进行定义:

    #define LED_IOC_MAGIC 'Z'

    ioctl 命令字段的 bit[31:30]表示命令的方向,分别表示使用_IO_IOW_IOR _IOWR这几个宏定义,分别用于构造不同的命令:

    _IO(type, nr)
    _IOW(type, nr, size)
    _IOR(type, nr, size)
    _IOWR(type, nr, size)
    构造无参数的命令编号
    构造往驱动写入数据的命令编号
    构造从驱动中读取数据的命令编号
    构造双向传输的命令编号

     

    这些宏定义中, type 是幻数, nr 是功能号, size 是数据大小。
    例如,为 LED 驱动构造 ioctl 命令,由于控制 LED 无需数据传输,可以这样定义:

    #define SET_LED_ON _IO(LED_IOC_MAGIC, 0)
    #define SET_LED_OFF _IO(LED_IOC_MAGIC, 1)

    如果想在 ioctl 中往驱动写入一个 int 型的数据,可以这样定义:

    #define CHAR_WRITE_DATA _IOW(CHAR_IOC_MAGIC, 2, int)

    类似的,要从驱动中读取 int 型的数据,则定义为:

    #define CHAR_READ_DATA _IOR(CHAR_IOC_MAGIC, 3, int)

     

    注意:同一份驱动的 ioctl 命令定义,无论有无数据传输以及数据传输方向是否相同,各命令的序号都不能相同定义完所需的全部命令后,还需定义一个命令的最大的编号,防止传入参数超过编号范围。

    3. 解析 ioctl 命令驱动程序必须对传入的命令进行解析,包括传输方向、命令类型、命令编号以及参数大
    小,分别可以通过下面的宏定义完成:

    _IOC_DIR(nr)
    _IOC_TYPE(nr)
    _IOC_NR(nr)
    _IOC_SIZE(nr)
    解析命令的传输方向
    解析命令类型
    解析命令序号
    解析参数大小

    如果解析发现命令出错,可以返回-ENOTTY,如:

    if (_IOC_TYPE(cmd) != LED_IOC_MAGIC) {
      return -ENOTTY;
    }
    if (_IOC_NR(cmd) >= LED_IOC_MAXNR) {
      return -ENOTTY;
    }

    3、实例

    led灯驱动

     

     #include <linux/init.h>
     #include <linux/module.h>
     #include <linux/fs.h>
     #include <linux/cdev.h>
     #include <linux/device.h>
     #include <linux/version.h>
     #include <asm/mach/arch.h>
     #include <mach/hardware.h>
     #include <mach/gpio.h>
     #include <asm/gpio.h>
     #include "led_drv.h"
    
     static int major;
     static int minor;
    struct cdev *led; /* cdev 数据结构 */
    static dev_t devno; /* 设备编号 */
    static struct class *led_class;
    
     #define DEVICE_NAME "led"
     #define GPIO_LED_PIN_NUM 55 /* gpio 1_23 */
    
     static int led_open(struct inode *inode, struct file *file )
    {
      try_module_get(THIS_MODULE);
      gpio_direction_output(GPIO_LED_PIN_NUM, 1);
      return 0;
    }
    
     static int led_release(struct inode *inode, struct file *file )
    {
      module_put(THIS_MODULE);
       gpio_direction_output(GPIO_LED_PIN_NUM, 1);
       return 0;
     }
    
     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
     int led_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
     #else
     static int led_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
     #endif
    {
       if (_IOC_TYPE(cmd) != LED_IOC_MAGIC) {
         return -ENOTTY;
     }
    
     if (_IOC_NR(cmd) > LED_IOCTL_MAXNR) {
       return -ENOTTY;
     }
    
     switch(cmd) {
       case LED_ON:
         gpio_set_value(GPIO_LED_PIN_NUM, 0);
       break;
    
       case LED_OFF:
         gpio_set_value(GPIO_LED_PIN_NUM, 1);
       break;
       default:     gpio_set_value(27, 0);   break; }   return 0;
    } struct file_operations led_fops = {   .owner = THIS_MODULE,    .open = led_open,    .release = led_release, #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)   .unlocked_ioctl = led_ioctl #else   .ioctl = led_ioctl #endif }; static int __init led_init(void)
    { int ret;   gpio_free(GPIO_LED_PIN_NUM);   if (gpio_request(GPIO_LED_PIN_NUM, "led_run")) {      printk("request %s gpio faile \n", "led_run");     return -1;   } ret = alloc_chrdev_region(&devno, minor, 1, "led"); /* 从系统获取主设备号 */ major = MAJOR(devno); if (ret < 0) {   printk(KERN_ERR "cannot get major %d \n", major);     return -1; } led = cdev_alloc(); /* 分配 led 结构 */ if (led != NULL)
      {   cdev_init(led, &led_fops); /* 初始化 led 结构 */    led->owner = THIS_MODULE;   if (cdev_add(led, devno, 1) != 0) { /* 增加 led 到系统中 */       printk(KERN_ERR "add cdev error!\n");       goto error;     } }
    else
    {   printk(KERN_ERR "cdev_alloc error!\n");   return -1; }
    led_class = class_create(THIS_MODULE, "led_class"); if (IS_ERR(led_class)) {   printk(KERN_INFO "create class error\n");   return -1; }   device_create(led_class, NULL, devno, NULL, "led");   return 0; error:   unregister_chrdev_region(devno, 1); /* 释放已经获得的设备号 */   return ret; } static void __exit led_exit(void) {   cdev_del(led); /* 移除字符设备 */   unregister_chrdev_region(devno, 1); /* 释放设备号 */   device_destroy(led_class, devno);   class_destroy(led_class); } module_init(led_init); module_exit(led_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Chenxibing, linux@zlgmcu.com");

     main.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/ioctl.h>
    #include <errno.h>
    #include <fcntl.h>
    #include "../led_drv.h"
    
    #define DEV_NAME "/dev/led"
    
    int main(int argc, char *argv[])
    {
    int i;
    int fd = 0;
    fd = open (DEV_NAME, O_RDONLY);
    if (fd < 0) {
         perror("Open "DEV_NAME" Failed!\n");
         exit(1);
    }
     
     for (i=0; i<3; i++) {
          ioctl(fd, LED_ON);
         sleep(1);
         ioctl(fd, LED_OFF);
         sleep(1);
     }
    
       close(fd);
       return 0;
    }
    

      

      

      



      

     

  • 相关阅读:
    Javajdbc
    Web Project添加Struts2框架
    CSS去除免费虚拟主机的广告心得分享
    List<T>采用delegate快速实现排序、查找等操作
    ASP.NET视频采集站核心技术分析(附送对付搜索引擎蜘蛛的贱招)
    Azure完整实例:在线日程表
    [发布]ClouderaCMS: 基于Windows Azure的开源CMS
    获取配置文件节点的值
    asp.net DataGrid排序
    checkbox 获取选中的值
  • 原文地址:https://www.cnblogs.com/yuanqiangfei/p/15735182.html
Copyright © 2020-2023  润新知