第6章 设备驱动程序(6)

目录

6.7 总线系统

6.7.2 PCI总线

6.7.3 USB

6.8 小结


本专栏文章将有70篇左右,欢迎+关注,查看后续文章。

6.7 总线系统

6.7.2 PCI总线

PCI由Intel开发,用于替代ISA。

PCI已过时,目前采用PCIe。

PCI特点:

        高带宽传输。

        易配置。

        与平台无关。

1. PCI系统的布局

设备标识

PCI总线上的每个设备,有3个编号:

        1. 总线编号(bus number):

                设备所在总线的编号。

                系统最多255个总线。

        2. 插槽编号(slot number):

                一个总线内部编号。不同总线设备插槽编号可能相同。

                一个总线最多有32个设备插槽。

        3. 功能编号(function number):

                区分一个扩展卡上多个不同设备。

                最大为8。

每个设备有一个16位编号标识:

        8位总线编号 + 5位插槽编号 + 3位功能编号         最大值255/32/8

地址空间

PCI设备有三个地址空间:

        IO空间:32bit,最大4G空间。

        数据空间:32bit或64bit 根据CPU位数决定。

        配置空间:包含vendor,设备类型等信息。

三个地址空间可被映射到系统的虚拟内存中。

配置信息

PCI总线无跳线,支持可通过软件配置。即使用配置空间。

PCI设备的配置空间:

        256字节。

                前64字节是标准化的,但都是非强制,而某些项是可选的。

                剩余空间自由使用。

前64字节如上图,深色部分是强制要求的。

配置空间介绍:

        Vendor ID:厂商ID,由PCI组织分配。

        Device ID:由厂商自己内部分配。

        Rev ID:版本ID,可用于选择驱动版本。

        Class Code:用于将设备分为不同功能组,共24bit。

                前8bit为基类,后16bit是子类。如:

                        基类:存储(PCI_BASE_CLASS_STORAGE)

                                子类:

                                        PCI_CLASS_STORAGE_SCSI

                                        PCI_CLASS_STORAGE_SATA

                                        PCI_CLASS_STORAGE_IDE

                                        PCI_CLASS_STORAGE_SAS

                基类:网络(PCI_BASE_CLASS_NETWORK)

                        子类:

                                PCI_CLASS_NETWORK_ETHERNET

                                PCI_CLASS_NETWORK_TOKEN_RING

                                PCI_CLASS_NETWORK_FDDI

                                PCI_CLASS_NETWORK_ATM

        基类:系统组件(PCI_BASE_CLASS_SYSTEM)

                子类:

                        PCI_CLASS_SYSTEM_DMA

                        PCI_CLASS_SYSTEM_TIMER

                        PCI_CLASS_SYSTEM_RTC

Base Address 0-5: 32bit

        指定了设备内存或I/O端口在PCI总线地址空间中的位置(可映射到内存)。

        64位设备中可两两合并3个base address。

IRQ Line:

        值范围:0-255

        用于指定设备使用的中断。

其余字段由硬件使用。

2. 内核中的实现

数据结构

struct pci_bus:

        一个PCI总线。

struct pci_dev:

        一个PCI设备。

struct pci_driver:

        一个PCI驱动。

struct list_head         pci_root_buses:

        作用:连接系统所有PCI总线,用于遍历。

总线的表示

struct         pci_bus {

        struct list_head         node;         //用于连接到全局总线链表

        struct pci_bus         *parent;       //父总线

        struct list_head        children;     //子总线链表

        struct list_head        devices;         //该总线上的所有设备

        struct pci_dev         *self;

                //对于桥设备,指向该桥设备的struct pci_dev实例。

        struct list_head         slots;

                //连接该总线的所有插槽。

        struct resource         *resource[PCI_BRIDGE_RESOURCE_NUM];

                //该总线的系统资源,如IO端口,IO内存。

        struct pci_ops         *ops;

                //用于访问配置空间的函数,如:

                总线扫描、设备枚举、资源分配与释放、电源管理等。

        void         *sysdata;

        struct proc_dir_entry         *procdir;         //向/proc/bus/pci导出总线信息

        unsigned char                    number;      //总线编号

        unsigned char                    primary;

                //桥设备创建的子总线,指示该总线是否为主桥。

        char                                   name[48];         //如:"PCI Bus #01"

        struct device                      dev;

};

除总线0外,其余总线可只通过一个PCI桥接器寻址。

        桥接器:用于连接PCI总线,也算一个PCI设备。

设备管理

pci_dev:

        描述一个PCI设备。

struct         pci_dev {

        struct list_head         bus_list;         //连接同一PCI总线下的PCI设备。

        struct pci_bus           *bus;             //所属总线。

        struct pci_bus           *subordinate;

                //若为PCI桥,用于连接该PCI桥下总线上的设备。

    

        struct proc_dir_entry         *procent;

                //proc文件系统中表示。

        struct pci_slot                    *slot;

                //该设备所在插槽。

        unsigned short         vendor;

        unsigned short         device;

                //该设备的vendor ID和device ID。

        struct pci_driver   *driver;         //该设备的驱动。

        struct device         dev;             //内核通用设备模型。

        unsigned int         irq;                //该设备的中断号。

        struct resource         resource[DEVICE_COUNT_RESOURCE];

                //IO端口,IO内存等资源。

};

驱动程序

pci_driver:表示一个PCI驱动程序。

struct         pci_driver {

        struct list_head         node;         //连接到全局PCI驱动列表。方便遍历查找PCI驱动

        const char                 *name;

        struct pci_device_id         *id_table;

                //定义该驱动可管理的设备列表,每个条目包含Vendor ID、Device ID等标识符。

    

        int         (*probe)(struct pci_dev *dev, const struct pci_device_id *id);

                //热插入一个新PCI设备,且与id_table中一个设备匹配时,调用此回调函数。

        void         (*remove)(struct pci_dev *dev);

                //热拔出一个一个新PCI设备时,调用该函数。

        int         (*suspend)(struct pci_dev *dev, pm_message_t state);

        int         (*resume)(struct pci_dev *dev);

        void         (*shutdown)(struct pci_dev *dev);

                //电源管理。

        struct device_driver         driver;         //通用驱动模型。

};

注册驱动程序

int    pci_register_driver(struct pci_driver   *drv,    struct module    *owner,     const char   *mod_name)

{

        drv->driver.name     =    drv->name;

        drv->driver.bus    =    &pci_bus_type;

        drv->driver.owner    =    owner;

        drv->driver.mod_name     =     mod_name;

        return    driver_register(&drv->driver);

}

一个驱动程序中需填写一个struct pci_device_id数组,并赋值给struct pci_device_id *id_table; 表示该驱动程序可管理的设备列表。

举例:

int __init         my_pci_driver_init(void)

{

        return pci_register_driver(&my_pci_driver);

}

static struct pci_driver         my_pci_driver = {

        .name    =     "my-pci",

        .id_table    =     my_pci_ids,

        .probe     =     my_pci_probe,

        .remove    =     my_pci_remove,

};

static struct pci_device_id         my_pci_ids[] = {

        { PCI_DEVICE(0x10ec, 0x8168) },

        { 0, }

};

其中

#define PCI_DEVICE(vend,dev) \

        .vendor = (vend), .device = (dev), \

        .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID

PCI_ANY_ID: 可以与任何PCI设备ID匹配。

pci_match_id()函数:

        判断指定设备ID是否包含在id_table表中。

6.7.3 USB

USB:即通用串行总线。一种外部总线。

1. 特性和运作模式

USB拓扑如下:

USB驱动设计的核心:

        热插拔。

        驱动透明安装。

设备不直接连接到宿主机控制器,而是连接到集线器。

USB设备分3个层次:

        1. 设备:

                连接到USB总线的设备。

                一个设备可包含几种功能部件,分别由不同驱动控制。

        2. 配置:

                每个设备由一或多个配置组成。

        3. 接口:

                每个配置由一或多个接口组成

        4. 端点end point:

                每个接口由一或多个端点组成。

drivers/usb/下目录将驱动程序分为:

        image:图形/视频设备,如照相机,扫描仪。

        input:输入输出设备。如键盘,鼠标,触摸屏。

        media:多媒体设备。

        net:网卡。

        storage:存储设备。如硬盘。

        core:适配器。

USB有4种传输模式:

        1. 控制传输:

                作用:传输控制信息,配置设备。

                占用带宽少。

                如标准命令:GET_STATUS,SET_INTERFACE。

        2. 块传输bulk transfer:

                作用:传输数据。

                占用全部带宽。

                如存储设备。

        3. 中断传输:

                即周期重复的块传输。

                如网卡。

        4. 同步传输:

                使用预定义带宽,可容忍偶尔数据丢失

                如网络摄像头。

2. 驱动程序管理

USB总线系统包括:

        1. 宿主机适配器的驱动:自身被连接到另一系统总线。

                适配器类型有OHCI,EHCI,UHCI。

        2. 驱动与USB设备通信。

USB有子系统4个任务:

        1. 注册和管理driver

        2. 为USB设备查找driver,及初始化与配置。

        3. 在内存中表示USB设备树。

        4. 设备通信。

struct         usb_driver {

        const char         *name;         //驱动名称。

        int         (*probe) (struct usb_interface *intf, const struct usb_device_id *id);

                //宿主机检测到新设备(id_table中定义的)时调用。

        void      (*disconnect) (struct usb_interface *intf);

        int         (*unlocked_ioctl) (struct usb_interface *intf, unsigned int code,void *buf);

        int         (*suspend) (struct usb_interface *intf, pm_message_t message);

        int         (*resume) (struct usb_interface *intf);

        int         (*reset_resume)(struct usb_interface *intf);

        struct usb_device_id         *id_table;

        struct usbdrv_wrap         drvwrap;

};

struct    usbdrv_wrap {

        struct device_driver         driver; //通用驱动模型。

        int         for_devices;

                //若为0,则为接口驱动。 若为1,则为设备驱动。

};

probe函数和id_tables:用法和PCI一样。

struct         usb_device_id {

        __u16         match_flags;         //检测设备时,指定检查哪些ID。

        __u16         idVendor;

        __u16         idProduct;

        __u16         bcdDevice_lo;

        __u16         bcdDevice_hi;

        __u8         bDeviceClass;

        __u8         bDeviceSubClass;

        __u8         bDeviceProtocol;

        __u8         bInterfaceClass;

        __u8         bInterfaceSubClass;

        __u8         bInterfaceProtocol;

        __u8 bInterfaceNumber;

}

int usb_register(struct usb_driver *driver)

插入设备时,检测到和id_tables中匹配后,调用usb_driver的probe函数,以初始化。

拔出设备时,调用usb_driver的 disconnect函数,来清除资源并卸载设备。

3. 设备树的表示

struct     usb_device {

        int         devnum;         //USB树中全局编号

        char      devpath[16]; //从USB树根节点到设备的经过的集线器端口号。

        u32        route;

        enum usb_device_state         state;

                //已连接/已配置。

        enum usb_device_speed       speed;

                //值为:

                        USB_SPEED_LOW

                        USB_SPEED_HIGH

                        USB_SPEED_SUPER

        struct usb_device         *parent;

                //指向连接的集线器(USB hub)

        struct usb_bus                         *bus;

        struct usb_host_endpoint         ep0;

        struct device                              dev;

        struct usb_device_descriptor     descriptor;

                //厂商ID 产品ID 设备class。

        struct usb_host_config                *config;         //设备可能的配置。

        struct usb_host_config                *actconfig;     //设备当前的配置。

        char                 *product;                   //产品名称。

        char                 *manufacturer;         //生产商。

        char                 *serial;                     //序列号。

        int                    maxchild;                 //如果是集线器,集线器的端口数目。

};

系统可有多个USB树,一颗树就是一根USB总线,而usb_bus_list可连接所有USB总线。

struct         usb_bus {

        struct device         *controller;         //代表总线的硬件

        struct device         *sysdev;

        int                         busnum;             //总线编号,按顺序分配

        const char             *bus_name;

        struct list_head      bus_list;            //用于连接到系统所有总线

        struct usb_devmap         devmap;        //位图,可跟踪已分配的usb编号

        struct usb_device           *root_hub;     //总线设备树根节点,即根集线器。

        int                         bandwidth_allocated;

};

URB:即USB Request Block,底层通过URB和设备交换数据。

6.8 小结

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

停车场防逃费设备有哪些,捷曜超眸相机怎么样,有哪些功能?

在当今快速发展的城市交通环境中,车场管理面临着诸多挑战,其中防逃费现象尤为突出。频繁的逃费行为不仅给车场运营带来了经济损失,也严重影响了停车场的正常秩序。对于车场防逃费方案中,超眸相机,以其尖端的高清成像技…

C++学习(23)

#学习自用# union 共用体和结构体相似&#xff0c;但是共用体一次只能占用一个成员的内存&#xff0c;所有成员共用同一地址。 #include<iostream> using namespace std; union A {int int_val;float float_val; }a; int main() {a.float_val 2.0f;cout << a.f…

浏览器加了token的header导致部分网页打不开

因为测试加了个token&#xff0c;忘记去掉&#xff0c;导致一些系统进不去&#xff0c;只能用无痕浏览器打开&#xff0c;后来发现是因为token的原因

零散的面试题

★1.java常见的引用类型 强:普通的变量引用 软:内存够时,GC不会主动删除,内存不够时,GC会删除 弱:一旦执行GC就会被删除 虚:用了感觉没用 ★2.JDK1.8新特性 lambda表达式(极大简化了匿名内部类的创建&#xff0c;促进函数式编程的风格)函数式接口(只能有一个抽象方法的接口 )日…

Nexus安卓木马分析报告

概述 2023年3月21日晚上&#xff0c;链安与中睿天下联合研发的监控系统检测到一种新型安卓木马。在经过睿士沙箱系统捕获样本之后&#xff0c;发现该安卓木马极有可能是原安卓网银盗号木马SOVA的变种。与此同时&#xff0c;意大利安全公司Cleafy发布了一篇题为《Nexus&#xf…

一款Wordpress网站导航主题,带昼夜切换功能

Wordpress网站导航主题&#xff0c;带昼夜切换功能。 基于wordpress&#xff0c;部署和使用都比较方便。 界面比较简洁大方。后台管理功能也比较全面&#xff0c;值得一试。 这款主题界面、功能都非常简洁。 作者把这款定位为简约导航主题&#xff0c;所以这款wordpress导航…

飞书API 2-1:如何通过 API 创建文件夹?

本文探讨如何通过飞书的 API 来创建文件夹。通过 API 创建的文件夹&#xff0c;一般是放在共享空间&#xff0c;如果要放在个人空间&#xff0c;建议手动创建。 查看 API 文档 API 路径&#xff0c;可在飞书开放平台的服务端 API&#xff0c;依次查找云文档>云空间>文件…

MavenPlus插件的基础功能完善

本次更新主要是在初版的searchEverywhere的基础上增加了pom.xml文件编辑器&#xff0c;目前的界面布局如下&#xff0c;进行适当说明&#xff1a; 打开pom文件后&#xff0c;你会得到如上图所示的布局页面&#xff0c;数据会同步显示 如果有冲突信息&#xff0c;则会以红色显示…

【Android面试八股文】你刚刚提到了V2签名使用美团的Walle实现多渠道打包,那么你能讲一讲Android 签名的 v1、v2、v3、v4版本的区别吗?

文章目录 前言一、简介二、APK 签名方案 v1 (JAR签名)2.1. 签名过程2.2 验证过程2.3 详细例子2.4 优缺点2.5 美团基于V1版本的多渠道打包方案三、APK 签名方案 v23.1 为什么要设计APK 签名方案 v2 ?3.2 APK 签名方案 v2 : 签名前和签名后的 APK3.2.1 签名前和签名后的 APK3.2…

qmt量化交易策略小白学习笔记第40期【qmt编程之期货数据--如何获取合约基础信息】

qmt编程之获取期货数据 qmt更加详细的教程方法&#xff0c;会持续慢慢梳理。 也可找寻博主的历史文章&#xff0c;搜索关键词查看解决方案 &#xff01; 感谢关注&#xff0c;咨询免费开通量化回测与获取实盘权限&#xff0c;欢迎和博主联系&#xff01; 获取合约基础信息 …

Faiss:选择合适的索引Index

向量相似性搜索彻底改变了搜索领域。它允许我们高效地检索从GIF到文章等各种媒体&#xff0c;即使在处理十亿级别数据集时&#xff0c;也能在亚秒级时间内提供令人印象深刻的准确性。 然而&#xff0c;这种灵活性也带来了一个问题&#xff1a;如何知道哪种索引大小最适合我们的…

React+TS 从零开始教程(1)

源码链接&#xff1a;https://pan.quark.cn/s/c6fbc31dcb02 创建项目 直接通过以下命令&#xff0c;我们来创建一个reactts的项目。 npx create-react-app myapp --template typescript这样就创建好了,然后我们导入vscode. npx是npm里面的一个库&#xff0c;可以让你自动使用…

DAB-DETR

论文地址&#xff1a; https://arxiv.org/pdf/2201.12329 文章通过前人的经验得出&#xff0c;导致 DETR 训练速度慢的原因很大可能是因为 decoder 中 cross attention 这个模块&#xff0c;由上面的对比可以看出其与 self attention 的区别主要就在于query的不同。文章猜想两个…

【Maven】项目的Maven插件报错

1. 找到本地maven库 2. 删除本地插件 3. 在IDEA上更新pom.xml

ctfshow web七夕杯

web签到 执行命令没有回显&#xff0c;我们直接写文件就可以了 有字符长度限制 ls />a nl /*>a访问url/api/a下载文件 easy_calc <?phpif(check($code)){eval($result."$code".";");echo($result); }function check(&$code){$num1…

LVS/NAT负载均衡实操

添加规则,并做持久操作 1 添加规则 [rootlvs ~]# ipvsadm -A -t 10.36.178.183:80 -s wrr [rootlvs ~]# ipvsadm -a -t 10.36.178.183:80 -r 192.168.65.201:80 -m -w 3 [rootlvs ~]# ipvsadm -a -t 10.36.178.183:80 -r 192.168.65.202:80 -m -w 1[rootlvs ~]# ipvsadm -Ln …

百度YY设计稿转代码的探索与实践

作者 | KyrieChen 导读 本文阐述了百度&YY互动团队在设计稿转代码方面的实践与沉淀&#xff0c;自研的YYF2C是Figma & AI相结合生成开发代码的一站式解决方案。文章将从遇到的痛点以及对应的方案成果来阐述&#xff0c;并介绍相对应的YYF2C功能点。 全文7217字&#xf…

我的创作纪念日--码农阿豪

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…

OpenCV读取图片

import cv2 as cv # 读取图像 image cv.imread(F:\\mytupian\\xihuduanqiao.jpg) # 创建窗口 cv.namedWindow(image, cv.WINDOW_NORMAL) #显示图像后&#xff0c;允许用户随意调整窗口大小 # 显示图像 cv.imshow(image, image) cv.waitKey(0)import cv2 as cv srccv.imread(…

KVB交易平台:国内三大交易所(上海、深圳、北京)的概要与分析

概述&#xff1a; 上海证券交易所&#xff08;上交所&#xff09;、深圳证券交易所&#xff08;深交所&#xff09;和北京证券交易所&#xff08;北交所&#xff09;是中国大陆三大主要证券交易所。以下是对这三个交易所的比较分析&#xff1a; 一、基本概况 1. 上海证券交易所…