打印

字符驱动之三:控制

[复制链接]
197|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
roucun|  楼主 | 2018-8-22 09:48 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
1. 命令的格式:    命令的本质是一个32位的无符号数,其实,命令可以是任意的32位数,但是考虑到不同的设备如果支持相同的命令,如果发错了,也会执行的尴尬, linux提供了统一的命令格式。



      | 设备类型    | 序列号     | 方向   | 数据尺寸  |

      |----------    |--------    |------   | --------   |

      | 8 bit          |  8 bit       | 2 bit   | 8~14 bit |



    设备类型:是哪个设备的命令  

    序列号  :是设备的哪一条命令

    方向    :命令的参数的数据方向(从应用程序的角度说)  

读写(_IOC_READ|_IOC_WRITE)不读不写/无数据传输(_IOC_NONE)只读(_IOC_READ)、只写(_IOC_WRITE)



    数据尺寸:命令的参数的大小





2. 命令的构造:构造命令用到一个宏:

_IO:

库:

    include/asm/ioctl.h

在linux源码中:





/* 构造无参数的命令编号 */

#define _IO(type, nr)             _IOC(_IOC_NONE,(type),(nr),0)

/* 构造从驱动程序中读取数据的命令编号 */

#define _IOR(type, nr, size)     _IOC(_IOC_READ,(type),(nr),sizeof(size))  

/* 用于向驱动程序写入数据命令 */

#define _IOW(type, nr, size)    _IOC(_IOC_WRITE,(type),(nr),sizeof(size))

/* 用于双向传输 */

#define _IOWR(type, nr, size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size)



<img id="aimg_YNwxX"  class="zoom" file="http://img.blog.csdn.net/20160829174711170"  lazyloadthumb="1" border="0" alt="" />





参数:

    type,魔术,范围是 0~255(0xff) 。通常,用英文字符 "A" ~ "Z" 或者 "a" ~ "z" 来表示。设备驱动程序从传递进来的命令获取魔数,然后与自身处理的魔数想比较,如果相同则处理,不同则不处理。魔数是拒绝误使用的初步辅助状态。不同的设备驱动程序最好设置不同的魔数,但并不是要求绝对,也是可以使用其他设备驱动程序已用过的魔数。    nr,基数

            基数用于区别各种命令。通常,从 0开始递增,相同设备驱动程序上可以重复使用该值。例如,读取和写入命令中使用了相同的基数,设备驱动程序也能分辨出来,原因在于设备驱动程序区分命令时使用 switch ,且直接使用命令变量 cmd值。

    size,数据长度



3. 避开linux系统中的预定义命令:

#define FIONCLEX 0x5450

#define FIOCLEX    0x5451

#define FIOQSIZE  0x5460

#define FIONBIO   0x5421





之所以避开 预定义命令是因为,如果某设备驱动中包含了与预定义命令一样的命令码,这些命令将被当作预定义命令而不是被设备驱动处理。



这些预定义命令的含义,这里不介绍。



4. 驱动中的实现:思路:主要是实现 struct file_operations 结构体里边的 unlocked_ioctl 方法

要实现的方法中有3个参数,举例如下:

static long led_ioctl (struct file *filep, unsigned int cmd, unsigned long argv)

{

    switch(cmd)

    {

    case HELLO_ONE:

        printk("HELLO_ONE\n");

        break;

    case HELLO_TWO:

        printk("HELLO_TWO\n");

        break;

    default:

        return -EINVAL;

    }

    return 0;

}

struct file_operations led_fops ={

    .unlocked_ioctl =led_ioctl,

};







对应的用户空间(/测试程序):

ioctl(fd, HELLO_ONE)

    其中的fd是打开的文件的操作符, HELLO_ONE 是命令码



5. 代码:





ioctrl.c

[cpp] view plain copy

print?<img id="aimg_W9JHy"  class="zoom" width="12" height="12" file="https://code.csdn.net/assets/CODE_ico.png" border="0" alt="" /><img id="aimg_B45PE"  class="zoom" width="12" height="12" file="https://code.csdn.net/assets/ico_fork.svg" border="0" alt="" />



#include <linux/kernel.h>  #include <linux/module.h>  #include <linux/fs.h>  #include <linux/cdev.h>  #include "test.h"  #include <linux/device.h>  MODULE_LICENSE("GPL");    #define LED_MA 250  #define LED_MI 0    struct cdev cdev;  struct class *my_class;  dev_t devno = MKDEV(LED_MA,LED_MI);    static  int led_open (struct inode * inodep, struct file *filep)  {      printk("led_open\n");      return 0;  }    static int led_release (struct inode *inodep, struct file *filep)  {      printk("led_release\n");      return 0;  }    static long led_ioctl (struct file *filep, unsigned int cmd, unsigned long argv)  {      switch(cmd)      {      case HELLO_ONE:          printk("HELLO_ONE\n");          break;      case HELLO_TWO:          printk("HELLO_TWO\n");          break;      default:          return -EINVAL;      }      return 0;  }  struct file_operations led_fops ={      .owner=THIS_MODULE,      .open = led_open,      .release =led_release,      .unlocked_ioctl =led_ioctl,  };    static int char_dev_create (void)  {      my_class = class_create(THIS_MODULE,"ioctrl_class");      if(IS_ERR(my_class))       {          printk("Err: failed in creating class.\n");          return -1;       }      device_create(my_class,NULL,devno,NULL,"ioctrl");        return 0;  }    static int led_init(void)  {      unsigned int ret = 0;      printk("led_init start \n");        ret = register_chrdev_region(devno,1,"fs4412_led_device");      if(ret<0)      {          printk("register_chrdev_region error\n");          return ret;      }      char_dev_create();        cdev.owner = THIS_MODULE;      cdev_init(&cdev,&led_fops);        ret = cdev_add(&cdev,devno,1);      if(ret<0)      {          printk("cdev_add error\n");          goto err1;      }        return 0;    err1:      unregister_chrdev_region(devno,1);      device_destroy(my_class, devno);         //delete device node under /dev//必须先删除设备,再删除class类      class_destroy(my_class);                 //delete class created by us        return ret;  }    static void led_exit(void)  {      cdev_del(&cdev);      device_destroy(my_class, devno);         //delete device node under /dev//必须先删除设备,再删除class类      class_destroy(my_class);                 //delete class created by us      unregister_chrdev_region(devno,1);      printk("led_exit end \n");      return ;    }  module_init(led_init);  module_exit(led_exit);  









Makefile

[cpp] view plain copy

print?<img id="aimg_SQL4O"  class="zoom" width="12" height="12" file="https://code.csdn.net/assets/CODE_ico.png" border="0" alt="" /><img id="aimg_m44hq"  class="zoom" width="12" height="12" file="https://code.csdn.net/assets/ico_fork.svg" border="0" alt="" />



ifeq ($(KERNELRELEASE),)    KERNELDIR ?= /lib/modules/$(shell uname -r)/build   #KERNELDIR ?= ~/wor_lip/linux-3.4.112  PWD := $(shell pwd)    modules:      $(MAKE) -C $(KERNELDIR) M=$(PWD) modules    modules_install:      $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install    clean:      rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions modules* Module*    .PHONY: modules modules_install clean    else      obj-m := ioctrl.o  endif  





test.h

[cpp] view plain copy

print?<img id="aimg_FCPMR"  class="zoom" width="12" height="12" file="https://code.csdn.net/assets/CODE_ico.png" border="0" alt="" /><img id="aimg_mpdJ2"  class="zoom" width="12" height="12" file="https://code.csdn.net/assets/ico_fork.svg" border="0" alt="" />



#ifndef  __TEST_H__  #define  __TEST_H__    #define HELLO_MAGIC 'k'    #define HELLO_ONE _IO (HELLO_MAGIC, 1)  #define HELLO_TWO _IO (HELLO_MAGIC, 2)    #endif   





test.c

[cpp] view plain copy

print?<img id="aimg_g6Mch"  class="zoom" width="12" height="12" file="https://code.csdn.net/assets/CODE_ico.png" border="0" alt="" /><img id="aimg_m89ep"  class="zoom" width="12" height="12" file="https://code.csdn.net/assets/ico_fork.svg" border="0" alt="" />



#include <stdio.h>  #include <sys/types.h>  #include <sys/ioctl.h>  #include <unistd.h>  #include <fcntl.h>  #include <stdlib.h>    #include "test.h"    int main (void)   {      int fd;        fd = open ("/dev/ioctrl",O_RDWR);      if (fd < 0) {          perror ("fd open failed");          exit(-1);        }        if (ioctl (fd, HELLO_ONE) < 0)      {          perror("fail to ioctl 1");        }      puts("ioctl HELLO_ONE is done") ;      getchar();        if (ioctl (fd, HELLO_TWO) < 0)      {          perror("fail to ioctl 2");        }      puts("ioctl HELLO_TWO is done") ;      getchar();        close (fd);        return 0;    }  





测试:



> sudo ./a.out

ioctl HELLO_ONE is done



ioctl HELLO_TWO is done



> sudo rmmod ioctrl



> dmesg

[24811.453631] led_init start

[24857.563362] led_open

[24857.563370] HELLO_ONE

[24860.293633] HELLO_TWO

[24862.970848] led_release

[24902.467995] led_exit end

使用特权

评论回复

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

421

主题

446

帖子

0

粉丝