zoukankan      html  css  js  c++  java
  • [国嵌攻略][116][字符设备控制技术]

    设备控制理论

    1.设备控制的作用

    大部分驱动程序除了需要提供读写设备的能力外,还需要具备控制设备的能力。比如改变波特率。

    2.设备控制的函数

    在用户空间使用ioctl系统调用函数来控制设备。

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

    fd:要控制的设备文件描述符

    cmd:发送给设备的命令

    ...:第三个参数是可选的参数,存在与否是依赖于控制命令

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

    1. 2.6.36以前的内核

    long (*ioclt)(struct inode *node, struct file *filp, unsigned int cmd, unsigned long arg)

    2. 2.6.36以后的内核

    long (*unlocked_ioctl)(struct file *filp, unsigned int cmd, unsigned long arg)

    参数cmd:通过应用程序ioctl传递下来的命令

    设备控制的实现

    1.定义命令

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

    type(类型/幻数):表明这是属于哪个设备的命令。

    number(序号):用来区分同一个设备的不同命令。

    direction:参数传递的方向,可以是_IOC_NONE(没有数据传输),_IOC_READ(从设备读取数据),_IOC_WRITE(向设备中写入数据)

    size:参数长度

    Linux系统提供了下面的宏来帮助定义命令:

    _IO(type, number):不带参数的命令

    _IOR(type, number, datatype):从设备中读取参数的命令

    _IOW(type, number, datatype):向设备中写入参数的命令

    示例:

    #define MEM_MAGIC ‘m’

    #define MEM_SET _IOW(MEM_MAGIC, 0, int)

    2.操作实现

    unlocked_ioclt函数的现实通常是根据命令执行的一个switch语句。但是当命令不能匹配任何一个设备所支持的命令是,返回-EINVAL。

    编程模型:

    switch(cmd){

        case A:

            //执行A对应的操作

        case B:

            //执行B对应的操作

        default:

            //return -EINVAL

    }

    memdev.h

    //定义命令
    #define MEM_MAGIC 'M'                     //设备幻数
    #define MEM_RST _IO(MEM_MAGIC, 0)         //重启命令
    #define MEM_SET _IOW(MEM_MAGIC, 1, int)   //设置命令

    memdev.c

    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/cdev.h>
    #include <linux/fs.h>
    #include <asm/uaccess.h>
    
    #include "memdev.h"
    
    //全局变量
    struct cdev memdev;   //字符设备
    dev_t devnum;         //设备编号
    
    int register0[5];   //设备0寄存器
    int register1[5];   //设备1寄存器
    
    //定位设备
    loff_t mem_lseek(struct file *filp, loff_t offset, int whence){
        //设置位置
        loff_t newpos;
        
        switch(whence){
            case SEEK_SET:
                newpos = offset;
                break;
            
            case SEEK_CUR:
                newpos = filp->f_pos + offset;
                break;
            
            case SEEK_END:
                newpos = (5 *  sizeof(int)) + offset;
                break;
                
            default:
                newpos = 0;
                break;
        }
        
        //移动位置
        filp->f_pos = newpos;
        
        return newpos;
    }
    
    //读取设备
    ssize_t mem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos){
        //获取地址
        int *base;
        
        base = filp->private_data + *ppos;
        
        //读取数据
        copy_to_user(buf, base, size);
        
        //移动位置
        filp->f_pos += size;
        
        return size;
    }
    
    //写入设备
    ssize_t mem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos){
        //获取地址
        int *base;
        
        base = filp->private_data + *ppos;
        
        //写入数据
        copy_from_user(base, buf, size);
        
        //移动位置
        filp->f_pos += size;
        
        return size;
    }
    
    //控制设备
    long mem_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){ //处理命令 switch(cmd){ case MEM_RST: //重启命令 printk("reset device "); break; case MEM_SET: //设置命令 printk("set arg is %d ", arg); break; default: //错误命名 return -EINVAL; } return 0; } //打开设备 int mem_open(struct inode *node, struct file *filp){ //获取次设备号 int secnum; secnum = MINOR(node->i_rdev); //设置设备地址 if(secnum == 0){ filp->private_data = register0; } if(secnum == 1){ filp->private_data = register1; } return 0; } //关闭设备 int mem_colse(struct inode *node, struct file *filp){ return 0; } //设备方法 struct file_operations memfops = { .llseek = mem_lseek, .read = mem_read, .write = mem_write, .unlocked_ioctl = mem_ioctl, .open = mem_open, .release = mem_colse }; //驱动注册 static int memdev_init(){ //注册设备结构 cdev_init(&memdev, &memfops); //注册主设备号 alloc_chrdev_region(&devnum, 0, 2, "memdev"); //添加设备结构 cdev_add(&memdev, devnum, 2); return 0; } //驱动注销 static void memdev_exit(){ //注销设备结构 cdev_del(&memdev); //注销主设备号 unregister_chrdev_region(devnum, 2); } //驱动声明 MODULE_LICENSE("GPL"); MODULE_AUTHOR("D"); MODULE_DESCRIPTION("memdev"); MODULE_VERSION("v1.0"); module_init(memdev_init); module_exit(memdev_exit);

    contorl.c

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <sys/ioctl.h>
    
    #include "memdev.h"
    
    int main(int argc, char **argv){
        //打开设备
        int fd;
        
        fd = open("/dev/memdev0", O_RDWR);
        
        //设置设备
        ioctl(fd, MEM_SET, 115200);
        
        //重启设备
        ioctl(fd, MEM_RST);
        
        //关闭设备
        close(fd);
        
        return 0;
    }
  • 相关阅读:
    [函數] Firemonkey Android 取得系统参数设定的字型大小
    [示例] 访问类的私有属性
    [修正] 移动平台曲线不平滑的问题(如:TRectangle, TPath...等)
    [修正] Firemonkey TSelection 控件等比缩放时,左下角拉动问题
    [修正] iOS 10 使用相机及相簿闪退的问题修正
    报表之表头
    报表字段刷新
    tfs解除锁
    sql server中排名的问题
    TFS查询无法在Excel中打开
  • 原文地址:https://www.cnblogs.com/d442130165/p/5251145.html
Copyright © 2011-2022 走看看