• 字符设备控制


    1.应用函数

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

    int ioctl(int fd,unsigned long cmd,...)
    

    fd: 要控制的设备文件描述符
    fd: 要控制的设备文件描述符
    cmd: 发送给设备的控制命令
    …: 第3个参数是可选的参数,存在与否是依赖于控制命令(第 2 个参数 )。

    2.驱动函数

    当应用程序使用ioctl系统调用时,驱动程序将由如下函数来响应:

    • 2.6.36 之前的内核
      long (ioctl) (struct inode node ,struct file* filp, unsigned int cmd,unsigned long arg)
    • 2.6.36之后的内核
      long (*unlocked_ioctl) (struct file *filp, unsigned int cmd, unsigned long arg)
      参数cmd: 通过应用函数ioctl传递下来的命令

    3.控制操作

    3.1 定义命令

    命令从其实质而言就是一个整数, 但为了让这个整数具备更好的可读性,我们通常会把这个整数分为几个段:类型(8位),序号,参数传送方向,参数长度。

    • Type(类型/幻数): 表明这是属于哪个设备的命令。
    • Number(序号),用来区分同一设备的不同命令。
    • Direction:参数传送的方向,可能的值是 _IOC_NONE(没有数据传输),_IOC_READ, _IOC_WRITE(向设备写入参数)
    • Size: 参数长度
      此外,Linux系统提供了下面的宏来帮助定义命令:
    • _IO(type,nr):不带参数的命令
    • _IOR(type,nr,datatype):从设备中读参数的命令
    • _IOW(type,nr,datatype):向设备写入参数的命令
      eg.
      #define MEM_MAGIC ‘m’ //定义幻数
      #define MEM_SET _IOW(MEM_MAGIC, 0, int)

    3.2实现操作

    unlocked_ioctl函数的实现通常是根据命令执行的一个switch语句。但是,当命令号不能匹配任何一个设备所支持的命令时,返回-EINVAL.
    编程模型:

    Switch cmd
    Case 命令A:
    	//执行A对应的操作
    Case 命令B:
    	//执行B对应的操作
    Default:
    	// return -EINVAL
    

    4.代码

    mem_ctl.c

     1 #include<sys/types.h>
     2 #include<sys/stat.h>
     3 #include<fcntl.h>
     4 #include<sys/ioctl.h>
     5 #include "memdev.h"
     6 
     7 int main()
     8 {
     9     int fd;
    10     
    11     fd = open("/dev/memdev0", O_RDWR);//可读可写打开文件
    12     
    13     ioctl(fd, MEM_SET, 115200);//第一个参数fd,第二个是我们要发送的命令,第三个是要传入的参数
    14     
    15     ioctl(fd, MEM_RESTART);//重启
    16     
    17     close(fd);
    18 }
    mem_ctl

    memdev.h

     1 #ifndef MEM_DEV_H
     2 #define MEM_DEV_H
     3 
     4 #define MEM_MAGIC 'm' //定义一个幻数,而长度正好和ASC码长度一样为8位,所以这里定义个字符
     5 #define MEM_RESTART _IO(MEM_MAGIC, 0)   //第一个命令是重启的命令,重启的命令不带参数 第一命令这里序号定义成0
     6 #define MEM_SET  _IOW(MEM_MAGIC, 1, int) //设置参数命令,第2个命令,类型为int
     7 
     8 
     9 
    10 #endif
    memdev.h

    memdev.c

      1 #include <linux/module.h>
      2 #include <linux/types.h>
      3 #include <linux/fs.h>
      4 #include <linux/errno.h>
      5 #include <linux/init.h>
      6 #include <linux/cdev.h>
      7 #include <asm/uaccess.h>
      8 #include <linux/slab.h>
      9 #include "memdev.h"
     10 
     11 
     12 int dev1_registers[5];
     13 int dev2_registers[5];
     14 
     15 struct cdev mdev;
     16 dev_t devno;
     17 
     18 static int mem_open(struct inode *inode, struct file *filep)
     19 {
     20     int num = MINOR(inode->i_rdev);//Secondary equipment number
     21     
     22     if (num==0)
     23         filep->private_data = dev1_registers;
     24     else if(num == 1)
     25         filep->private_data = dev2_registers;
     26     else
     27         return -ENODEV; 
     28     
     29     return 0; 
     30 
     31 }
     32 
     33 static int mem_release(struct inode *inode, struct file *filep)
     34 {
     35   return 0;
     36 }
     37 
     38 static loff_t mem_llseek(struct file *filep, loff_t offset, int base_addr )
     39 {
     40     loff_t newpos;
     41 
     42     switch(base_addr) {
     43       case SEEK_SET: 
     44         newpos = offset;
     45         break;
     46 
     47       case SEEK_CUR: 
     48         newpos = filep->f_pos + offset;
     49         break;
     50 
     51       case SEEK_END: 
     52         newpos = 5*sizeof(int)-1 + offset;
     53         break;
     54 
     55       default: 
     56         return -EINVAL;
     57     }
     58     if((newpos<0) || (newpos>5*sizeof(int)))
     59         return -EINVAL;
     60         
     61     filep->f_pos = newpos;
     62     return newpos;
     63 
     64 }
     65 
     66 static ssize_t mem_read(struct file *filep, char __user *buf, size_t size, loff_t *ppos)
     67 {
     68     unsigned long p =  *ppos;
     69     unsigned int count = size;
     70       int ret = 0;
     71     int *register_addr = filep->private_data;     
     72     
     73     if(p >= 5*sizeof(int))
     74         return 0;
     75       if(count > 5*sizeof(int) - p)
     76         count = 5*sizeof(int) - p;
     77     
     78     if (copy_to_user(buf, register_addr+p, count))
     79       {
     80         ret = -EFAULT;
     81       }
     82     else
     83     {
     84         ppos += count;
     85         ret = count;
     86     }
     87     return ret;
     88 }
     89 
     90 static ssize_t mem_write(struct file *filep, const char __user *buf, size_t size, loff_t *ppos)
     91 {
     92     unsigned long p =  *ppos;
     93     unsigned int count = size;
     94       int ret = 0;
     95       int *register_addr = filep->private_data;
     96   
     97       if (p >= 5*sizeof(int))
     98         return 0;
     99       if (count > 5*sizeof(int) - p)
    100         count = 5*sizeof(int) - p;
    101     
    102       if (copy_from_user(register_addr + p, buf, count))
    103         ret = -EFAULT;
    104       else
    105       {
    106         *ppos += count;
    107         ret = count;
    108       }
    109       return ret;
    110 }
    111 
    112 static long mem_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  
    113 {  
    114   
    115     switch(cmd)  
    116     {  
    117         case MEM_RESTART: //传入的是重启的命令  
    118             printk(KERN_WARNING"restart device!
    ");//这里通过虚拟设备来模拟  
    119             return 0;  
    120         case MEM_SET:    //传入的是设置参数命令  
    121             printk(KERN_WARNING"arg is : %d
    ", arg);//打印出传入的参数  
    122             return 0;  
    123         default:  
    124             return -EINVAL;//其他的打印错误  
    125               
    126     }  
    127       
    128     return 0;  
    129 }
    130 
    131 static const struct file_operations mem_fops =
    132 {
    133   .llseek = mem_llseek,
    134   .read = mem_read,
    135   .write = mem_write,
    136   .open = mem_open,
    137   .release = mem_release,
    138   .unlocked_ioctl = mem_ioctl
    139 };
    140 
    141 static int memdev_init(void)
    142 {
    143     cdev_init(&mdev,&mem_fops);
    144     alloc_chrdev_region(&devno, 0, 2, "memdev");
    145     cdev_add(&mdev,devno,2);
    146 
    147     return 0;
    148 }
    149 
    150 static void memdev_exit(void)
    151 {
    152     cdev_del(&mdev);
    153     unregister_chrdev_region(devno, 2);     
    154 }
    155 
    156 module_init(memdev_init);
    157 module_exit(memdev_exit);
    memdev.c
  • 相关阅读:
    Java 开发问题
    include和request
    VC++6.0怎么显示行号
    快速排序
    如何解决虚拟机安装centos无法全屏显示问题!
    详解.NET 4.0新特性Dynamic相关知识
    Action C#
    windbg不常用命令2
    底层枚举 网络连接时的结构
    netbios 和smb
  • 原文地址:https://www.cnblogs.com/boyiliushui/p/6665178.html
Copyright © 2020-2023  润新知