Linux设备驱动之多个同类设备共用一套驱动

1. 应用场景

比如我们的设备上有很多一样的usb接口,这些usb接口都需要有驱动才能工作,那么是每个usb都一套单独的驱动程序么?显然不是的,这些usb接口属于同一类设备,用户对他们的操作方法完全一致,只不过不是同一个设备,所以他们可以复用同一套驱动代码,在代码中去判断用户要操作哪个设备,然后去open/read/write这个设备。

2. 如何区分不同的设备

前面说过,每个设备都有一个唯一的标识符–设备号,那么对于同一类设备,它们的主设备号是一样的,次设备号是不一样的,用来区分它们,当用户想要操作哪个具体的设备,就会打开这个设备对应的设备文件(inode结构体),并自动在内核中创建对应的file结构体,这个file结构体中就保存了用户操作的所有信息,最终会传给我们的内核驱动,驱动再根据这个file结构体和inode结构体来判断用户具体要操作的哪个设备,然后去read/write这个具体的设备。

案例:

hanp@hanp:/dev/usb$ ls -lcrw------- 1 root root 180, 0  3月 11 17:29 hiddev0crw------- 1 root root 180, 1  3月 11 17:29 hiddev1

我的主机下面的两个usb设备,他们共用了一套usb驱动,但是他们的设备号是不一样的(180,0)和(180,1),主设备号都是180表示都属于同一类设备(usb设备),次设备号分别是0和1,表示这是两个不同的设备。

3. 代码实现

#include <linux/kernel.h>#include <linux/module.h>#include <linux/cdev.h>#include <linux/device.h>#include <linux/fs.h>#include <asm/uaccess.h>#define NUM_OF_DEVICES    2int major = 255;/* 两个设备,所以有两套结构体 *//* 设备0对应的设备结构体是hello_dev[0], 设备1对应的设备结构体是hello_dev[1] */struct hello_device {    dev_t devno;    struct cdev cdev;    char data[128];    char name[16];}hello_dev[NUM_OF_DEVICES];struct class * hello_class;const char DEVNAME[] = "hello_device";int hello_open(struct inode * ip, struct file * fp){    printk("%s : %d\n", __func__, __LINE__);        /* 获取用户打开的设备对应的设备结构体 hello_dev[0] 或者 hello_dev[1] */    struct hello_device * dev = container_of(ip->i_cdev, struct hello_device, cdev);        /* open的时候,通过container_of能够获取到用户要打开的那个设备的设备结构体,所有需要把这个结构体通过file指针的     * private_data参数传递给read/write */    fp->private_data = dev;        /* 一般用来做初始化设备的操作 */    /* ... */        return 0;}int hello_close(struct inode * ip, struct file * fp){    printk("%s : %d\n", __func__, __LINE__);        /* 一般用来做和open相反的操作,open申请资源,close释放资源 */    /* ... */        return 0;}ssize_t hello_read(struct file * fp, char __user * buf, size_t count, loff_t * loff){    int ret;        /* 通过file指针,获取到用户要操作的设备对应的设备结构体 */    struct hello_device * dev = fp->private_data;        /* 将用户需要的数据从内核空间copy到用户空间(buf) */    printk("%s : %d\n", __func__, __LINE__);    if (count <=0 || count > 128)        count = 128;    if ((ret = copy_to_user(buf, dev->data, count)))    {        printk("copy_to_user err\n");        return -1;    }        return count;}ssize_t hello_write(struct file * fp, const char __user * buf, size_t count, loff_t * loff){    int ret;    struct hello_device * dev = fp->private_data;        /* 将用户需要的数据从内核空间copy到用户空间(buf) */    printk("%s : %d\n", __func__, __LINE__);    if (count <=0 || count > 128)        count = 128;    if ((ret = copy_from_user(dev->data, buf, count)))    {        printk("copy_from_user err\n");        return -1;    }        return count;}/* 2. 分配file_operations结构体 */struct file_operations hello_fops = {    .owner = THIS_MODULE,    .open  = hello_open,    .release = hello_close,    .read = hello_read,    .write = hello_write};struct cdev cdev;static int hello_init(void){    int i;    printk("%s : %d\n", __func__, __LINE__);        /* 1. 生成并注册两个设备的设备号 */    /* 3. 分配、设置、注册两套cdev结构体 */    for (i = 0; i < NUM_OF_DEVICES; i++)    {        hello_dev[i].devno = MKDEV(major, i);        sprintf(hello_dev[i].name, "%s%d", DEVNAME, i);        register_chrdev_region(hello_dev[i].devno, 1, hello_dev[i].name);                hello_dev[i].cdev.owner = THIS_MODULE;        cdev_add(&hello_dev[i].cdev, hello_dev[i].devno, 1);        cdev_init(&hello_dev[i].cdev, &hello_fops);                /* 初始化两个设备各自的存储空间 */        sprintf(hello_dev[i].data, "Hi, I am hello device %d", i);    }        /* 在/sys/class目录下创建hello类,并在这个类下面创建hello_device0和hello_device1 */    hello_class = class_create(THIS_MODULE, DEVNAME);    for (i = 0; i < NUM_OF_DEVICES; i++)    {        device_create(hello_class, NULL, hello_dev[i].devno, NULL, "%s%d", DEVNAME, i);        printk("success!\n");    }    return 0;}static void hello_exit(void){    int i;    printk("%s : %d\n", __func__, __LINE__);        /* 释放资源 */    for (i = 0; i < NUM_OF_DEVICES; i++)    {        device_destroy(hello_class, hello_dev[i].devno);        cdev_del(&hello_dev[i].cdev);        unregister_chrdev_region(hello_dev[i].devno, 1);    }    class_destroy(hello_class);}MODULE_LICENSE("GPL");module_init(hello_init);module_exit(hello_exit);

解释:

container_of:/** * container_of - cast a member of a structure out to the containing structure * @ptr:        the pointer to the member. * @type:       the type of the container struct this is embedded in. * @member:     the name of the member within the struct. * */#define container_of(ptr, type, member)

功能:根据结构体中某个成员的地址,从而获取到整个结构体的首地址

@ptr: 已知结构体成员的地址

@type: 要获取的结构体的类型

@member: 已知结构体成员的名字

我们用到的实例解析:

struct hello_device * dev = container_of(ip->i_cdev, struct hello_device, cdev);

文章最后的图解和上篇文章中我讲到file结构体和inode结构体的关系,其中inode结构体和文件系统下的文件是一一对应的关系,里面保存了这个字符设备对应的cdev结构体:

struct cdev * i_cdev,而这个cdev结构体又包含在设备结构体hello_device中,其中hello_dev[0]中包含的是设备0的cdev,hello_dev[1]中包含的是设备1的cdev,那么

container_of函数就可以根据这个cdev来判断用户打开的是hello_dev[0]还是hello_dev[1]并获取到地址。

流程图解析

编译安装驱动:

sudo insmod hello.ko

hanp@hanp:/dev$ ls hello_device*hello_device0  hello_device1
hanp@hanp:/dev$ cat /proc/devices | grep hello255 hello_device0255 hello_device1

可以看到在/proc/devices下注册了两个设备hello_device0和hello_device1,这两个设备的主设备一样都是255,但是次设备号不一样(cat /dev/hello_deviceX可以查看次设备号)。

4. 写应用程序进行测试 app.c

#include <stdio.h>#include <string.h>#include <unistd.h>#include <sys/stat.h>#include <sys/types.h>#include <fcntl.h>int main(char argc, char * argv[]){    int fd;    int ret;    char buf[64];        if (argc != 2)    {        printf("Usage: %s <filename>\n", argv[0]);        return -1;    }        fd = open(argv[1], O_RDWR);    if (fd < 0)    {        perror("fail to open file");        return -1;    }        /* read data */    ret = read(fd, buf, sizeof(buf));    if (ret < 0)    {        printf("read err!");        return -1;    }    printf("buf = %s\n", buf);        /* write data */    strcpy(buf, "write data from app!");    ret = write(fd, buf, sizeof(buf));    if (ret < 0)    {        printf("write err!");        return -1;    }    read(fd, buf, sizeof(buf));    printf("buf = %s\n", buf);        close(fd);    return 0;}

测试:

$ gcc app.c$ sudo ./a.out /dev/hello_device0buf = Hi, I am hello device 0buf = write data from app!$ sudo ./a.out /dev/hello_device1buf = Hi, I am hello device 1buf = write data from app!

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/1621760.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

ScheduleJS Crack,新的“信息列”水平滚动功能

ScheduleJS Crack,新的“信息列”水平滚动功能 增加了对Angular 16的支持 新的“信息列”水平滚动功能。 新的“信息列”固定功能。 添加了输入属性以处理组件模板中的偶数和奇数ScheduleRowPlainBackgroundColor以及CSS变量。 改进了“信息列”和角度甘特组件的类型。 Schedul…

Unity3D开发之发布webplayer设置全屏

项目打包出来后会出现一个html文件&#xff0c;使用notepad打开&#xff0c;删除部分代码 并增加一些代码可设置全屏。 <style type"text/css">#unityPlayer {float:left;top: 0px; height: 100%; width: 100%;position: relative;}html,body{overflow-y:hidde…

web player php,unity web player是什么软件

unity web player是一款浏览器运行Unity3D游戏引擎发布的游戏的插件&#xff0c;一般是用户在玩游戏的时候系统自动安装的&#xff1b;通过unity web player插件可以发布web平台的游戏。 本文操作环境&#xff1a;Windows7系统&#xff0c;Dell G3电脑。 推荐&#xff1a;《编程…

软考高级系统架构设计师真题练习(一)计算机组成结构

【原文链接】软考高级系统架构设计师真题练习&#xff08;一&#xff09;计算机组成结构 真题练习 1 答案&#xff1a;B 真题练习 2 答案&#xff1a;C 真题练习 3 答案&#xff1a;A 真题练习 4 答案&#xff1a;A、D 真题练习 5 答案&#xff1a;D 真题练习 …

C语言(第三十天)

1. 什么是bug bug本意是昆虫”或“虫子”&#xff0c;现在一般是指在电脑系统或程序中&#xff0c;隐藏着的一些未被发现的缺陷或问 题&#xff0c;简称程序漏洞。 “Bug” 的创始人格蕾丝赫柏&#xff08;Grace Murray Hopper&#xff09;&#xff0c;她是一位为美国海军工作的…

QQ互联申请及配置

QQ互联申请及配置 今天要说的只是针对QQ互联的操作&#xff0c;其他的互联请参考相关网站。 第一步&#xff1a;需要申请API接口的两码 自行登录QQ互联https://connect.qq.com/index.html&#xff0c;然后按照要求申请就OK啦。 过几天你会收到一封审核通过的邮件&#xff1a; …

C、C++、VC、MFC网页自动注册、登陆、发帖、留言 QQ注册、QQ申请器源码、源代码

查看文章 【转】C、C、VC、MFC网页自动注册、登陆、发帖、留言 QQ注册、QQ申请器源码、源代码 2012-01-11 10:58 转载自 qq316293804 最终编辑 qq316293804 参考资料&#xff1a; 自动登录yahoo邮箱http://blog.csdn.net/suisuibianbian/archive/2005/12/12/550260.aspx VC采集…

激活函数总结(二十一):激活函数补充(APL、Inverse Cubic)

激活函数总结&#xff08;二十一&#xff09;&#xff1a;激活函数补充 1 引言2 激活函数2.1 Adaptive piecewise linear&#xff08;APL&#xff09;激活函数2.2 Inverse Cubic激活函数 3. 总结 1 引言 在前面的文章中已经介绍了介绍了一系列激活函数 (Sigmoid、Tanh、ReLU、…

mozilla美国工程师两秒钟制造百度山寨版

周三下午清华科技园的一个咖啡屋&#xff0c;我和几位国内的blogger–刘兴亮、老杳、詹鹏与mozilla组织的两位美国工程师Aza Raskin 、Dan Mills相聚。两位工程师给我们介绍mozilla全球组织和基金会&#xff0c;还给我们演示了很多超级酷的firefox插件&#xff0c;两个多小时的…

热点故事“百度C2C是“社会化商务”的重大利好”

17号下午&#xff0c;传出了百度C2C的消息&#xff0c;一天之内炸开了锅。 玩聚网象techmeme一样的行动起来&#xff0c;自动语义聚合出来了这个玩聚热点故事- 百度C2C是“社会化商务”的重大利好&#xff0c;一时间麦田的、詹鹏的、wkcow的等一大堆blogger的评论都进来了。百度…

BIOS中的内存测试memtest

参考&#xff1a; https://blog.csdn.net/evenness/article/details/7818857 https://blog.csdn.net/skdkjzz/article/details/17073455 https://blog.csdn.net/sannik/article/details/8930625# 在 U-Boot中&#xff0c;Denx&#xff08;U-Boot的开发商&#xff09;针对常见…

Win系统 - 内存稳定性测试软件(MemTest)

给大家介绍一款免安装的内存稳定性测试软件--MemTest&#xff0c;它不但可以彻底的检测出内存的稳定度&#xff0c;还可同时测试记忆的储存与检索资料的能力&#xff0c;memtest pro汉化版软件体积小巧&#xff0c;绿色免安装&#xff0c;使用简单&#xff0c;有兴趣的小伙伴们…

[Linux] VMware虚拟机开机后直接进入memtest

问题描述 今天碰到一个很难受的问题&#xff0c;昨天写报告的时候虚拟机还是正常的&#xff0c;早上开机的时候忽然报错进不了ubuntu虚拟机直接进入一个memtest的界面&#xff0c;情况大概是这样的&#xff1a; 一开始会报一些“error syntax”“error incorrect command”等错…

内存稳定性测试软件(MemTest)

给大家介绍一款免安装的内存稳定性测试软件--MemTest&#xff0c;它不但可以彻底的检测出内存的稳定度&#xff0c;还可同时测试记忆的储存与检索资料的能力&#xff0c;memtest pro汉化版软件体积小巧&#xff0c;绿色免安装&#xff0c;使用简单&#xff0c;有兴趣的小伙伴们…

MemTest内存软件测试介绍说明-2

有很多测试内存的软件。但是&#xff0c;许多测试只是将一些模式套用到内存上&#xff0c;而没有对内存体系结构或如何最好地检测错误进行深入思考或了解。这对于硬盘故障很有效&#xff0c;但很少发现间歇性错误。基于 BIOS 的内存测试对于查找间歇性内存错误毫无用处。 存储…

002微信小程序云开发API数据库-迁移状态查询/更新索引

文章目录 微信小程序云开发API数据库-迁移状态查询案例代码微信小程序云开发API数据库-更新索引案例代码 微信小程序云开发API数据库-迁移状态查询 在微信小程序中&#xff0c;云开发API数据库是一种方便快捷的数据库解决方案。但是&#xff0c;有时候我们可能需要将云开发数据…

PS 见了都自愧不如,吾爱又出新科技

不知道你们在网上见过这样的段子没有&#xff0c;就是某个网友发一张自己的照片出来&#xff0c;然后请求 P 图大神按要求帮助 P 一下图片。 就比如这种&#xff1a; 每次看到这些脑洞与技术同等存在的恶搞 PS 图片&#xff0c;总是让人笑掉大牙的同时理解了一个道理&#xff…

Photoshop 2023官方正版永久使用(卡BUG,无破解)

长话短说 本教程适用于Photoshop 2023版本&#xff0c;其他版本暂未试过&#xff1a; PS是一款收费软件&#xff0c;初次使用有免费试用期限&#xff0c;免费试用期过了以后按如下方式操作即可卡BUG来继续免费使用&#xff1a; 1、 打开软件 2、 点击在adobe.com…

C#---第二十: partial修饰类的特性及应用

0.知识背景 局部类型适用于以下情况&#xff1a; 类型特别大&#xff0c;不宜放在一个文件中实现。一个类型中的一部分代码为自动化工具生成的代码&#xff0c;不宜与我们自己编写的代码混合在一起。需要多人合作编写一个类 局部类型的限制: 局部类型只适用于类、接口、结构&am…

闲人闲谈PS之十九——PS模块的未来

惯例闲话&#xff1a;约莫5年前&#xff0c;闲人曾经对自己职业专业产生过一丝疑虑&#xff0c;SAP实施人们都说五大模块&#xff08;SD/PP/MM/FI/CO&#xff09;&#xff0c;PS模块的存在感如同天边的浮云&#xff0c;也就国网、中石油、国能等这些国字头企业里才有PS的存在&a…