• 关于 ioctl 函数


    ioctl函数是用于控制的设备的接口

    1.底层: long (*unlocked_ioctl) (struct file *filp, unsigned int cmd, unsigned long args);

    file_operations结构中的一个函数指针成员,具体的函数接口是自己实现的。

    参数:args是4字节的类型,可以传递整型数据,也可以传递指针,指针的话就可以传递一个结构,在cmd中的size位域传递这个结构的字节大小

    2.应用层:int ioctl(int fd, int request, ...);

      功能:ioctl()  函数操纵特殊文件的底层设备参数。

      参数:fd: 文件描述符

         request :请求cmd  关于cmd命令制作参考下面介绍

         ...:可变参数  char *p;

      返回值: 成功: 0 失败: -1

    3.关于cmd:

    其中对于request(cmd)即命令的操作,要保证值的唯一性。

    cmd就是一个数,是应用层传递给驱动的值,在驱动中对应的这个值是否有操作,自己实现。

    内核使用几个宏来制作cmd:

    _IO   : 不传递参数   #define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)
    _IOW  : 只写方式    #define _IOW(type,nr,size)   _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
    _IOR   :只读方式    #define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))
    _IOWR :读写方式     #define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))

    cmd 中各 bit 对应的功能

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

    |31   30  |29       16  | 15    8 |7       0  |

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

    | dir        | size       | type    |  nr       |

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

    cmd  命令码中相应位对应的功能:

    dir :方向: 读 _IOR  写 _IOW  可读可写_IOWR   _IO(type,nr) //没有第三个参数  ...

    size :13位 ---->传递的数据类型(char short int ...struct )的大小 2^14 = 16384

    type :8位  类型----> 给定一个ASCII码, a-z  =====>幻数magic  借助这个幻数让cmd更加唯一 ==类似共享内存中构建键值的== ftok

    nr  :8位  命令码的序号: 2^8 = 256;对设备的控制状态,对命令码中一般不使用2号,内核貌似已使用

    通过这几个宏制作一个cmd命令,然后通过ioctl传递到底层的demo_ioctl中判断cmd对应的nr位域执行对应的操作。

    简单例子:

    -------demo.c驱动程序

    #include <linux/module.h>
    #include <linux/fs.h>
    #include <linux/device.h>
    #include <linux/cdev.h>
    #include <linux/kdev_t.h>
    #include <linux/uaccess.h>
    #include <linux/err.h>
    #include <linux/kernel.h>
    #include <linux/kfifo.h>
    #include "demo.h"
    
    
    /* 变量定义区域 */ 
    const char * name = "demochdrev"; // 字符驱动名字
    unsigned int major;     // 主设备号
    const char *clsname = "mychr"; // 创建class类的名字(不清楚具体什么用途)
    struct class *mycls;
    struct device *mydev;
    
    
    // read 系统调用
    ssize_t demo_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
    {
        printk(KERN_INFO "kernel read 
    ");    
        return 0; // 返回读取字节数
    }
    
    // write 系统调用
    ssize_t demo_write(struct file *filp, const char __user *buf, size_t count, loff_t *offset)
    {
        printk(KERN_INFO "kernel write 
    ");    
        return 0;
    }
    
    // close 系统调用
    int demo_release(struct inode *iod, struct file *filp)
    {
        printk(KERN_INFO "kernel release 
    ");
        return 0;
    }
    
    // open 系统调用
    int demo_open(struct inode *iod, struct file *filp)
    {
        printk(KERN_INFO "kernel open 
    ");
        return 0;
    }
    long demo_ioctl(struct file *filp, unsigned int cmd, unsigned long args) { printk(KERN_INFO "kernel ioctl "); switch(cmd)   { case DEMO_CTL_INT0: printk(KERN_INFO " OPEN LED "); break; case DEMO_CTL_INT1: printk(KERN_INFO " CLOSE LED "); break; default: break; } return 0; } // 对文件的操作方法集 struct file_operations fops = { .owner = THIS_MODULE, .read = demo_read, // 函数实现要在其上面,不然在此处找不到函数的声明 .write = demo_write, .open = demo_open, .release = demo_release, .unlocked_ioctl = demo_ioctl, }; /* 模块 3 步操作c */ // 模块入口,申请字符设备用到的资源 static int __init demo_init(void) { printk(KERN_INFO "module init "); // 1. 注册一个字符设备 cdev major = register_chrdev(0, name, &fops); // major=0 表示自动分配主设备号,其返回值是主设备号 if(major <= 0){ // 注册字符设备失败 printk(KERN_INFO "register chrdev fail "); } // 2.自动创建设备节点 /sys/class 目录下的文件夹名 // 2.1 创建一个 class 类 mycls = class_create(THIS_MODULE, clsname); // 返回值 struct class* 类型 if (IS_ERR(mycls)){ // 创建 class 失败 printk(KERN_INFO "class create fail "); unregister_chrdev(major, name); // 在每步检测申请失败了,就要释放前面申请的资源 return PTR_ERR(mycls); } // 2.2 创建设备节点的名字 mydev = device_create(mycls, NULL,MKDEV(major, 0) , NULL, "demochr%d", 0); // 最后 2 个参数会制作这个驱动的可见的名字,安装模块时会看见/dev/demochr0 if (IS_ERR(mydev)) { // 创建设备节点失败 printk(KERN_INFO "failed to create device "); unregister_chrdev(major, name); class_destroy(mycls); return PTR_ERR(mydev); } return 0; } // 模块出口,释放申请的资源 static void __exit demo_exit(void) { printk(KERN_INFO "module exit "); device_destroy(mycls, MKDEV(major, 0)); // 上面创建的顺序反向操作,栈操作 class_destroy(mycls); unregister_chrdev(major, name); } module_init(demo_init); module_exit(demo_exit); MODULE_LICENSE("GPL");

    ------demo.h 文件定义的cmd 命令

    #ifndef __DEMO_H
    #define __DEMO_H
    
    #define DEMO_TYPE 's'
    #define DEMO_CTL_INT0 _IO(DEMO_TYPE,0)
    #define DEMO_CTL_INT1 _IO(DEMO_TYPE,1)
    
    #endif // __DEMO_H

    -------test.c测试文件

    #include <sys/ioctl.h>
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include "demo.h"
    
    
    const char *pathname = "/dev/demochr0";
    int main(int argc, const char *argv[])
    {
        int fd = open(pathname, O_RDWR);
        ioctl(fd,DEMO_CTL_INT1);
        ioctl(fd,DEMO_CTL_INT0);
    
        return 0;
    }

    ----Makfile文件

    #KERNELDIR=/lib/modules/3.13.0-32-generic/build  
    KERNELDIR=/home/linux/share/kernel-3.4.39
    
    PWD=$(shell pwd)
    all:
        make -C $(KERNELDIR) M=$(PWD) modules
        arm-linux-gcc test.c -o test
        cp test demo.ko ~/rootfs/home/
    
    clean:
        make -C $(KERNELDIR) M=$(PWD) clean
        rm test
    
    obj-m +=demo.o

     烧写到开发板测试:

  • 相关阅读:
    继承
    类和对象
    Scanner类
    面向对象思想
    final关键字
    The difference between text mode and binary mode with file streams
    Linux下常见权限操作相关命令
    Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext
    手动运行jar包,指定配置文件
    jdk 1.8.0_131 Class JavaLaunchHelper is implemented
  • 原文地址:https://www.cnblogs.com/electronic/p/11144328.html
Copyright © 2020-2023  润新知