zoukankan      html  css  js  c++  java
  • 驱动学习2:简单驱动创建

    本文使用三种方法创建设备驱动,同时使用应用程序测试驱动是否安装成功。

    其中,前两种方法都是手工创建设备节点,最后一种方法使用混杂设备的方法不需手工创建设备节点

    在/dev/目录下创建设备文件hello,应用程序helltest.c为:

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <string.h>
    #include <sys/ioctl.h>
    
    
    int main(int argc, char *argv[])
    {
        int fd;
        printf("enter driver test %s %s 
    ", argv[1], argv[2]);
        char *hello = "/dev/hello";
    
        if((fd = open(hello, O_RDWR | O_NOCTTY | O_NDELAY)) < 0)
        {
            printf("open %s failed
    ", hello);
        }
        else
        {
            printf("%s fd is %d 
    ", hello, fd);
            ioctl(fd, atoi(argv[1]), atoi(argv[2]));
        }
        close(fd);
        return 1;
    }

    第一种:手动创建驱动

    加载之前首先通过 cat /proc/devices来查看字符主设备号230是否被占用

     

    然后通过 insmod first_drv.ko来挂载, 通过 cat /proc/devices就能看到hello驱动模块是否已挂载好

    root@plnx_arm:/mnt# cat /proc/devices | grep hello
    230 hello

    通过应用程序测试:

    使用./hellotest来运行,发现如果open()打不开,会返回-1

    是因为我们没有创建dev/xxx这个设备节点,然后我们来创建,使它等于刚刚挂载好的hello模块

    //模块的主设备号为230
    mknod -m 660 /dev/hello c 230 0
    ls /dev/hello -l

    crw-rw---- 1 root root 230, 0 Jun 4 11:05 /dev/hello

    再次测试:

    其中open()函数返回值为3,是因为描述符0,1,2都已经被控制台占用了,所以从3开始


    第二种:自动分配设备号

    除了使用第一种方法手工创建设备号外,也可以让系统自动为我们驱动设备自动分配设备号

     仅仅修改代码如下:

    int major;              //定义一个全局变量,用来保存主设备号
    //register_chrdev作用:在VFS虚拟文件系统中找到字符设备,然后通过主设备号找到内核数组里对应位置,最后将设备名字和fops结构体填进去
    static int hello_init(void)
    {
        
        /*如果设置major为0,表示由内核动态分配主设备号,函数的返回值是主设备号*/
        major =register_chrdev (0, DEVICE_NAME, &hello_fops); //230:主设备号,”hello”:设备名
        printk(KERN_EMERG "hello dev has been init!
    ");
        return 0;
    }
    
    static void hello_exit(void)
    {
        //释放设备号、注销设备
        unregister_chrdev(major,DEVICE_NAME);
        printk(KERN_EMERG "hello dev has been exit!
    "); //卸载驱动, 将major填入即可
    }

     如下图,通过动态分配得出它的主设备号是244,然后重新创建设备文件(主设备号为244),运行测试程序

    附完整代码:

    //参考内核源码:gpio.c
    #include <linux/init.h>
    #include <linux/module.h>
    
    #include <linux/platform_device.h>
    #include <linux/miscdevice.h>
    #include <linux/fs.h>
    
    
    #define DEVICE_NAME "hello"
    
    
    MODULE_LICENSE("Dual BSD/GPL");
    MODULE_AUTHOR("pp");
    
    /////////////////////////dev//////////////////////////////////////
    
    static int hello_open(struct inode *inode, struct file *file){
        printk(KERN_EMERG "hello open
    ");
        return 0;
    }
    
    static int hello_release(struct inode *inode, struct file *file){
        printk(KERN_EMERG "hello release
    ");
        return 0;
    }
    
    /*设备文件的读函数中,参数filp为文件结构体指针,buf为用户空间内存地址,count为要读取的字节数,ppos为写的位置相对于文件开头的偏移*/
    //copy_to_user 完成用户空间缓冲区到内核空间的复制
    static ssize_t hello_read(struct file *filp, char __user *buf, size_t len,loff_t *ppos)
    {
       printk("hello_read
    ");      
       return 0;
    }
    /*设备文件的写函数中,参数filp为文件结构体指针,buf为用户空间内存地址,count为要写入的字节数,ppos为写的位置相对于文件开头的偏移*/
    //copy_from_user 完成内核空间到用户空间缓冲区的复制
    static ssize_t hello_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
    {
       printk("hello_write
    ");      
       return 0;
    }
    //ioctl函数
    static long hello_ioctl(struct file *file, unsigned int cmd, unsigned long arg){
        printk("cmd is %d, arg is %d
    ", cmd, arg);
        return 0;
    }
    
    
    static struct file_operations hello_fops = {
        .owner = THIS_MODULE,
        .open = hello_open,  
        .read = hello_read,   
        .write = hello_write,       
        .release = hello_release,
        .unlocked_ioctl = hello_ioctl,
    };
    
    
    
    int major;              //定义一个全局变量,用来保存主设备号
    //register_chrdev作用:在VFS虚拟文件系统中找到字符设备,然后通过主设备号找到内核数组里对应位置,最后将设备名字和fops结构体填进去
    static int hello_init(void)
    {
        
        /*如果设置major为0,表示由内核动态分配主设备号,函数的返回值是主设备号*/
        major =register_chrdev (0, DEVICE_NAME, &hello_fops); //230:主设备号,”hello”:设备名
        printk(KERN_EMERG "hello dev has been init!
    ");
        return 0;
    }
    
    static void hello_exit(void)
    {
        //释放设备号、注销设备
        unregister_chrdev(major,DEVICE_NAME);
        printk(KERN_EMERG "hello dev has been exit!
    "); //卸载驱动, 将major填入即可
    }
    
    
    module_init(hello_init);
    module_exit(hello_exit);
    View Code

    第三种:自动创建驱动(混杂设备)

    #include <linux/init.h>
    #include <linux/module.h>
    
    #include <linux/platform_device.h>
    #include <linux/miscdevice.h>
    #include <linux/fs.h>
    
    
    #define DEVICE_NAME "hello"
    
    MODULE_LICENSE("Dual BSD/GPL");
    MODULE_AUTHOR("pp");
    
    /////////////////////////dev//////////////////////////////////////
    
    static int hello_open(struct inode *inode, struct file *file){
        printk(KERN_EMERG "hello open
    ");
        return 0;
    }
    
    static int hello_release(struct inode *inode, struct file *file){
        printk(KERN_EMERG "hello release
    ");
        return 0;
    }
    
    static long hello_ioctl(struct file *file, unsigned int cmd, unsigned long arg){
        printk("cmd is %d, arg is %d
    ", cmd, arg);
        return 0;
    }
    
    static struct file_operations hello_fops = {
        .owner = THIS_MODULE,
        .open = hello_open,
        .release = hello_release,
        .unlocked_ioctl = hello_ioctl,
    };
    
    static struct miscdevice hello_dev = {
        .minor = MISC_DYNAMIC_MINOR,
        .name = DEVICE_NAME,
        .fops = &hello_fops,
    };
    
    
    
    static int hello_init(void)
    {
        misc_register(&hello_dev);
        printk(KERN_EMERG "hello dev has been init!
    ");
        return 0;
    }
    
    static void hello_exit(void)
    {
        
        misc_deregister(&hello_dev);
        printk(KERN_EMERG "hello dev has been exit!
    ");
    }
    
    module_init(hello_init);
    module_exit(hello_exit);

    我们通过 ls /dev -l 可以看到混杂设备的主设备号为10,验证了书上所讲:

    root@plnx_arm:/mnt# ls -l /dev | grep hello 
    crw-rw----    1 root     root       10,  58 Jun  4 10:28 hello

    通过应用程序测试:

    root@plnx_arm:/mnt# ./hellotest 2 3
    enter driver test 2 3 
    hello open
    /dev/hello fd is 3 
    hello release
  • 相关阅读:
    android-sdk环境变量配置
    2018/08/04
    python 读取配置文件ini ---ConfigParser
    关于自动化测试框架搭建的前期考虑问题
    Jmeter中用例禁用
    Jmeter创建一个http请求
    基本的sql语法
    sql创建表格时出现乱码
    Jmeter安装
    Java环境搭建
  • 原文地址:https://www.cnblogs.com/shuqingstudy/p/9150881.html
Copyright © 2011-2022 走看看