Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >19.Linux-USB总线驱动分析

19.Linux-USB总线驱动分析

作者头像
诺谦
发布于 2018-01-03 09:54:51
发布于 2018-01-03 09:54:51
8.8K00
代码可运行
举报
文章被收录于专栏:Linux驱动Linux驱动
运行总次数:0
代码可运行

如下图所示,以windows为例,我们插上一个没有USB设备驱动的USB,就会提示你安装驱动程序

为什么一插上就有会提示信息?

是因为windows自带了USB总线驱动程序,

USB总线驱动程序负责:

识别USB设备,给USB设备找到对应的驱动程序

新接入的USB设备的默认地址(编号)是0,在未分配新编号前,PC主机使用0地址和它通信。

然后USB总线驱动程序都会给它分配一个地址(编号)

PC机想访问USB总线上某个USB设备时,发出的命令都含有对应的地址(编号)

USB是一种主从结构。主机叫做Host,从机叫做Device,所有的USB传输,都是从USB主机这方发起;USB设备没有"主动"通知USB主机的能力。

例子:USB鼠标滑动一下立刻产生数据,但是它没有能力通知PC机来读数据,只能被动地等得PC机来读。

USB可以热插拔的硬件原理

   在USB集线器(hub)的每个下游端口的D+和D-上,分别接了一个15K欧姆的下拉电阻到地。这样,在集线器的端口悬空时,就被这两个下拉电阻拉到了低电平。

而在USB设备端,在D+或者D-上接了1.5K欧姆上拉电阻。对于全速和高速设备,上拉电阻是接在D+上;而低速设备则是上拉电阻接在D-上。这样,当设备插入到集线器时,由1.5K的上拉电阻和15K的下拉电阻分压,结果就将差分数据线中的一条拉高了。集线器检测到这个状态后,它就报告给USB主控制器(或者通过它上一层的集线器报告给USB主控制器),这样就检测到设备的插入了。USB高速设备先是被识别为全速设备,然后通过HOST和DEVICE两者之间的确认,再切换到高速模式的。在高速模式下,是电流传输模式,这时将D+上的上拉电阻断开。

USB的4大传输类型:

控制传输(control)  

是每一个USB设备必须支持的,通常用来获取设备描述符、设置设备的状态等等。一个USB设备从插入到最后的拔出这个过程一定会产生控制传输(即便这个USB设备不能被这个系统支持)。 中断传输(interrupt)

支持中断传输的典型设备有USB鼠标、 USB键盘等等。中断传输不是说我的设备真正发出一个中断,然后主机会来读取数据。它其实是一种轮询的方式来完成数据的通信。USB设备会在设备驱动程序中设置一个参数叫做interval,它是endpoint的一个成员。 interval是间隔时间的意思,表示我这个设备希望主机多长时间来轮询自己,只要这个值确定了之后,我主机就会周期性的来查看有没有数据需要处理

批量传输(bulk)

支持批量传输最典型的设备就是U盘,它进行大数量的数据传输,能够保证数据的准确性,但是时间不是固定的。

实时传输(isochronous)  USB摄像头就是实时传输设备的典型代表,它同样进行大数量的数据传输,数据的准确性无法保证,但是对传输延迟非常敏感,也就是说对实时性要求比较高

USB端点:

USB设备与主机会有若干个通信的”端点”,每个端点都有个端点号,除了端点0外,每一个端点只能工作在一种传输类型(控制传输、中断传输、批量传输、实时传输)下,一个传输方向下

传输方向都是基于USB主机的立场说的,

比如:鼠标的数据是从鼠标传到PC机, 对应的端点称为"中断输入端点"

其中端点0是设备的默认控制端点, 既能输出也能输入,用于USB设备的识别过程

同样linux内核也自带了USB总线驱动程序,框架如下:

要想成为一个USB主机,硬件上就必须要有USB主机控制器才行,USB主机控制器又分为4种接口:

OHCI(Open Host Controller Interface): 微软主导的低速USB1.0(1.5Mbps)和全速USB1.1(12Mbps),OHCI接口的软件简单,硬件复杂  

UHCI(Universal Host Controller Interface): Intel主导的低速USB1.0(1.5Mbps)和全速USB1.1(12Mbps), 而UHCI接口的软件复杂,硬件简单  

EHCI(Enhanced Host Controller Interface):高速USB2.0(480Mbps),

xHCI(eXtensible Host Controller Interface):USB3.0(5.0Gbps),采用了9针脚设计,同时也支持USB2.0、1.1等

接下来进入正题,开始分析USB总线驱动,如何识别USB设备

由于内核自带了USB驱动,所以我们先插入一个USB键盘到开发板上看打印信息

发现以下字段:

如下图,找到第一段话是位于drivers/usb/core/hub.c的第2186行

这个hub其实就是我们的USB主机控制器的集线器,用来管理多个USB接口

1. drivers/usb/core/hub.c的第2186行位于hub_port_init()函数里

它又是被谁调用的,如下图所示,我们搜索到它是通过hub_thread()函数调用的

hub_thread()函数如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static int hub_thread(void *__unused)
{

do {
       hub_events();       //执行一次hub事件函数
       wait_event_interruptible(khubd_wait,!list_empty(&hub_event_list) ||kthread_should_stop());                              //(1).每次执行一次hub事件,都会进入一次等待事件中断函数
       try_to_freeze();            
} while (!kthread_should_stop() || !list_empty(&hub_event_list));

pr_debug("%s: khubd exiting\n", usbcore_name);
return 0;
}

从上面函数中得到, 要想执行hub_events(),都要等待khubd_wait这个中断唤醒才行

2.我们搜索”khubd_wait”,看看是被谁唤醒

 找到该中断在kick_khubd()函数中唤醒,代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static void kick_khubd(struct usb_hub *hub)
{
       unsigned long       flags;
       to_usb_interface(hub->intfdev)->pm_usage_cnt = 1;
 
       spin_lock_irqsave(&hub_event_lock, flags);
       if (list_empty(&hub->event_list)) {
              list_add_tail(&hub->event_list, &hub_event_list);
              wake_up(&khubd_wait);                     //唤醒khubd_wait这个中断
       }

       spin_unlock_irqrestore(&hub_event_lock, flags);
}

3.继续搜索kick_khubd,发现被hub_irq()函数中调用

显然,就是当USB设备插入后,D+或D-就会被拉高,然后USB主机控制器就会产生一个hub_irq中断.

4.接下来我们直接分析hub_port_connect_change()函数,如何连接端口的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static void hub_port_connect_change(struct usb_hub *hub, int port1,u16 portstatus, u16 portchange)
{ 
  ... ...
  udev = usb_alloc_dev(hdev, hdev->bus, port1);     //(1)注册一个usb_device,然后会放在usb总线上

  usb_set_device_state(udev, USB_STATE_POWERED); //设置注册的USB设备的状态标志
  ... ...

  choose_address(udev);                              //(2)给新的设备分配一个地址编号
   status = hub_port_init(hub, udev, port1, i);      //(3)初始化端口,与USB设备建立连接
  ... ...

  status = usb_new_device(udev);                 //(4)创建USB设备,与USB设备驱动连接
  ... ...
}

 (usb_device设备结构体参考:http://www.cnblogs.com/lifexy/p/7634511.html

所以最终流程图如下:

5.我们进入hub_port_connect_change()->usb_alloc_dev(),来看看它是怎么设置usb_device的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 1 usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
 2 
 3 {
 4 
 5        struct usb_device *dev;
 6 
 7  
 8 
 9        dev = kzalloc(sizeof(*dev), GFP_KERNEL);   //分配一个usb_device设备结构体
10 
11        ... ...
12 
13  
14 
15        device_initialize(&dev->dev);           //初始化usb_device
16                                     
17        dev->dev.bus = &usb_bus_type;         //(1)设置usb_device的成员device->bus等于usb_bus总线
18 
19        dev->dev.type = &usb_device_type;    //设置usb_device的成员device->type等于usb_device_type
20                                   
21        ... ...
22 
23        return dev;                                        //返回一个usb_device结构体
24 
25 }

(1)在第17行上,设置device成员,主要是用来后面8.2小节,注册usb总线的device表上.

其中usb_bus_type是一个全局变量, 它和我们之前学的platform平台总线相似,属于USB总线, 是Linux中bus的一种.

如下图所示,每当创建一个USB设备,或者USB设备驱动时,USB总线都会调用match成员来匹配一次,使USB设备和USB设备驱动联系起来.

usb_bus_type结构体如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct bus_type usb_bus_type = {
       .name =         "usb",               //总线名称,存在/sys/bus下
       .match = usb_device_match,       //匹配函数,匹配成功就会调用usb_driver驱动的probe函数成员
       .uevent =       usb_uevent,           //事件函数
       .suspend =     usb_suspend,       //休眠函数
       .resume =      usb_resume,       //唤醒函数
};  

6.我们进入hub_port_connect_change()->choose_address(),来看看它是怎么分配地址编号的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static void choose_address(struct usb_device *udev)
{
int devnum;
struct usb_bus    *bus = udev->bus;

devnum = find_next_zero_bit(bus->devmap.devicemap, 128,bus->devnum_next); 
                     //在bus->devnum_next~128区间中,循环查找下一个非0(没有设备)的编号

       if (devnum >= 128)                 //若编号大于等于128,说明没有找到空余的地址编号,从头开始找
              devnum = find_next_zero_bit(bus->devmap.devicemap, 128, 1);
           bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1);  //设置下次寻址的区间+1

       if (devnum < 128) {                                  
              set_bit(devnum, bus->devmap.devicemap);      //设置位
              udev->devnum = devnum;                 
              }
}

从上面代码中分析到每次的地址编号是连续加的,USB接口最大能接127个设备,我们连续插拔两次USB键盘,也可以看出,如下图所示:

7.我们再来看看hub_port_connect_change()->hub_port_init()函数是如何来实现连接USB设备的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 1 static int hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,int retry_counter)
 2 {
 3    ... ...
 4    for (j = 0; j < SET_ADDRESS_TRIES; ++j) 
 5   {
 6        retval = hub_set_address(udev);     //(1)设置地址,告诉USB设备新的地址编号
 7 
 8        if (retval >= 0)
 9                 break;
10        msleep(200);
11    }
12  retval = usb_get_device_descriptor(udev, 8);   //(2)获得USB设备描述符前8个字节
13  ... ...
14 
15  retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);  //重新获取设备描述符信息
16  ... ...
17 }

(1)上面第6行中,hub_set_address()函数主要是用来告诉USB设备新的地址编号, hub_set_address()函数如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static int hub_set_address(struct usb_device *udev)
{
       int retval;
       ... ...
       retval = usb_control_msg(udev, usb_sndaddr0pipe(),USB_REQ_SET_ADDRESS,0, udev->devnum, 0,NULL, 0, USB_CTRL_SET_TIMEOUT);                                                //(1.1)等待传输完成
    if (retval == 0) {              //设置新的地址,传输完成,返回0
              usb_set_device_state(udev, USB_STATE_ADDRESS);  //设置状态标志
              ep0_reinit(udev);
       }
return retval;
}

  usb_control_msg()函数就是用来让USB主机控制器把一个控制报文发给USB设备,如果传输完成就返回0.其中参数udev表示目标设备;使用的管道为usb_sndaddr0pipe(),也就是默认的地址0加上控制端点号0; USB_REQ_SET_ADDRESS表示命令码,既设置地址; udev->devnum表示要设置目标设备的设备号;允许等待传输完成的时间为5秒,因为USB_CTRL_SET_TIMEOUT定义为5000。

2)上面第12行中,usb_get_device_descriptor()函数主要是获取目标设备描述符前8个字节,为什么先只开始读取8个字节?是因为开始时还不知道对方所支持的信包容量,这8个字节是每个设备都有的,后面再根据设备的数据,通过usb_get_device_descriptor()重读一次目标设备的设备描述结构.

其中USB设备描述符结构体如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct usb_device_descriptor {
 __u8  bLength;                          //本描述符的size
 __u8  bDescriptorType;                //描述符的类型,这里是设备描述符DEVICE
 __u16 bcdUSB;                           //指明usb的版本,比如usb2.0
 __u8  bDeviceClass;                    //类
 __u8  bDeviceSubClass;                 //子类
 __u8  bDeviceProtocol;                  //指定协议
 __u8  bMaxPacketSize0;                 //端点0对应的最大包大小
 __u16 idVendor;                         //厂家ID
 __u16 idProduct;                        //产品ID
 __u16 bcdDevice;                        //设备的发布号
 __u8  iManufacturer;                    //字符串描述符中厂家ID的索引
 __u8  iProduct;                         //字符串描述符中产品ID的索引
 __u8  iSerialNumber;                   //字符串描述符中设备序列号的索引
 __u8  bNumConfigurations;               //可能的配置的数目
} __attribute__ ((packed));

8.我们来看看hub_port_connect_change()->usb_new_device()函数是如何来创建USB设备的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int usb_new_device(struct usb_device *udev)
{
   ... ...
   err = usb_get_configuration(udev);           //(1)获取配置描述块
  ... ...
  err = device_add(&udev->dev);     // (2)把device放入bus的dev链表中,并寻找对应的设备驱动
}

(1)其中usb_get_configuration()函数如下,就是获取各个配置

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int   usb_get_configuration(struct usb_device *dev)
{
  ... ...
  /* USB_MAXCONFIG 定义为8,表示设备描述块下有最多不能超过8个配置描述块 */
  /*ncfg表示 设备描述块下 有多少个配置描述块 */
if (ncfg > USB_MAXCONFIG) {
              dev_warn(ddev, "too many configurations: %d, "
                  "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG);
              dev->descriptor.bNumConfigurations = ncfg = USB_MAXCONFIG;
       }
  ... ...
  for (cfgno = 0; cfgno < ncfg; cfgno++)   //for循环,从USB设备里依次读入所有配置描述块
  {
      result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,buffer, USB_DT_CONFIG_SIZE);
                              //每次先读取USB_DT_CONFIG_SIZE个字节,也就是9个字节,暂放到buffer中
      ... ...

      length = max((int) le16_to_cpu(desc->wTotalLength),USB_DT_CONFIG_SIZE);
                  //通过wTotalLength,知道实际数据大小

      bigbuffer = kmalloc(length, GFP_KERNEL);  //然后再来分配足够大的空间
      ... ...

      result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,bigbuffer, length);
                             //在调用一次usb_get_descriptor,把整个配置描述块读出来,放到bigbuffer中
      ... ...

      dev->rawdescriptors[cfgno] = bigbuffer;   //再将bigbuffer地址放在rawdescriptors所指的指针数组中

      result = usb_parse_configuration(&dev->dev, cfgno,&dev->config[cfgno],

    bigbuffer, length);         //最后在解析每个配置块

}
  ... ...
}

(2)其中device_add ()函数如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int   usb_get_configuration(struct usb_device *dev)
{

 dev = get_device(dev);         //使dev等于usb_device下的device成员
 ... ...

if ((error = bus_add_device(dev))) // 把这个设备添加到dev->bus的device表中
              goto BusError;
 ... ...

bus_attach_device(dev);           //来匹配对应的驱动程序
 ... ...
}

 当bus_attach_device()函数匹配成功,就会调用驱动的probe函数

9.我们再来看看usb_bus_type这个的成员usb_device_match函数,看看是如何匹配的

usb_device_match函数如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static int usb_device_match(struct device *dev, struct device_driver *drv)
{

       if (is_usb_device(dev)) {                       //判断是不是USB设备
              if (!is_usb_device_driver(drv))
                     return 0;
              return 1;
         }
else {                                                //否则就是USB驱动或者USB设备的接口

              struct usb_interface *intf;
              struct usb_driver *usb_drv;
              const struct usb_device_id *id;           

              if (is_usb_device_driver(drv))   //如果是USB驱动,就不需要匹配,直接return
                     return 0; 

              intf = to_usb_interface(dev);               //获取USB设备的接口
              usb_drv = to_usb_driver(drv);                    //获取USB驱动

              id = usb_match_id(intf, usb_drv->id_table);  //匹配USB驱动的成员id_table
              if (id)
                     return 1;

              id = usb_match_dynamic_id(intf, usb_drv);
              if (id)
                     return 1;
       }
       return 0;
}

显然就是匹配USB驱动的id_table

10.那么USB驱动的id_table又该如何定义?

id_table的结构体为usb_device_id,如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct usb_device_id {
        
       __u16             match_flags;   //与usb设备匹配那种类型?比较类型的宏如下:
 //USB_DEVICE_ID_MATCH_INT_INFO : 用于匹配设备的接口描述符的3个成员
 //USB_DEVICE_ID_MATCH_DEV_INFO: 用于匹配设备描述符的3个成员
 //USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION: 用于匹配特定的USB设备的4个成员
 //USB_DEVICE_ID_MATCH_DEVICE:用于匹配特定的USB设备的2个成员(idVendor和idProduct)

 
       /* 以下4个用匹配描述特定的USB设备 */
       __u16             idVendor;              //厂家ID
       __u16             idProduct;             //产品ID
       __u16             bcdDevice_lo;        //设备的低版本号
       __u16             bcdDevice_hi;        //设备的高版本号

       /*以下3个就是用于比较设备描述符的*/
       __u8        bDeviceClass;                    //设备类
       __u8        bDeviceSubClass;                 //设备子类
       __u8        bDeviceProtocol;                 //设备协议

       /* 以下3个就是用于比较设备的接口描述符的 */
       __u8        bInterfaceClass;                   //接口类型
       __u8        bInterfaceSubClass;             //接口子类型
       __u8        bInterfaceProtocol;           //接口所遵循的协议

       /* not matched against */
       kernel_ulong_t       driver_info;
};

 (设备描述符合接口描述符结构体参考:http://www.cnblogs.com/lifexy/p/7634511.html

我们参考/drivers/hid/usbhid/usbmouse.c(内核自带的USB鼠标驱动),是如何使用的,如下图所示:

发现它是通过USB_INTERFACE_INFO()这个宏定义的.该宏如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#define USB_INTERFACE_INFO(cl,sc,pr) \
       .match_flags = USB_DEVICE_ID_MATCH_INT_INFO,  \    //设置id_table的.match_flags成员
      .bInterfaceClass = (cl), .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr)
                                                         //设置id_table的3个成员,用于与匹配USB设备的3个成员

然后将上图里的usb_mouse_id_table []里的3个值代入宏USB_INTERFACE_INFO(cl,sc,pr)中:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.bInterfaceClass =USB_INTERFACE_CLASS_HID;  
   //设置匹配USB的接口类型为HID类, 因为USB_INTERFACE_CLASS_HID=0x03
   //HID类是属于人机交互的设备,比如:USB键盘,USB鼠标,USB触摸板,USB游戏操作杆都要填入0X03

.bInterfaceSubClass =USB_INTERFACE_SUBCLASS_BOOT;  
   //设置匹配USB的接口子类型为启动设备

.bInterfaceProtocol=USB_INTERFACE_PROTOCOL_MOUSE;
  //设置匹配USB的接口协议为USB鼠标的协议,等于2
  //当.bInterfaceProtocol=1也就是USB_INTERFACE_PROTOCOL_KEYBOARD时,表示USB键盘的协议

如下图,我们也可以通过windows上也可以找到鼠标的协议号,也是2:

其中VID:表示厂家(vendor)ID

PID:表示产品(Product) ID

总结:当我们插上USB设备时,系统就会获取USB设备的设备、配置、接口、端点的数据,并创建新设备,所以我们的驱动就需要写id_table来匹配该USB设备

USB总线驱动程序大概流程就此结束,未完待续——分析完后下节开始写USB驱动

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-10-06 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
13.USB驱动
问1. 既然还没有"驱动程序",为何能知道是"android phone" 答1. windows里已经有了USB的总线驱动程序,接入USB设备后,是"总线驱动程序"知道你是"android phone" 提示你安装的是"设备驱动程序" USB总线驱动程序负责:识别USB设备, 给USB设备找到对应的驱动程序
嵌入式与Linux那些事
2021/05/20
2K0
Linux驱动开发: USB驱动开发
USB是连接计算机系统与外部设备的一种串口总线标准,也是一种输入输出接口的技术规范,被广泛地应用于个人电脑和移动设备等信息通讯产品,USB就是简写,中文叫通用串行总线。最早出现在1995年,伴随着奔腾机发展而来。自微软在Windows 98中加入对USB接口的支持后,USB接口才推广开来,USB设备也日渐增多,如数码相机、摄像头、扫描仪、游戏杆、打印机、键盘、鼠标等等,其中应用最广的就是摄像头和U盘了。
DS小龙哥
2022/01/12
70.3K0
Linux驱动开发: USB驱动开发
linux中OTG识别到一个U盘后产生一个sg节点的全过程
  需要关注注册驱动的有hub, usb, usb-storage。hub中用来做检测usb口是否有OTG的东东接入,usb是所有usb接入设备的老大哥,usb-storage只是usb的一个小老弟。
啊源股
2019/11/27
2.1K0
一文搞懂 Linux 网络 Phy 驱动
上图来自 瑞昱半导体 (RealTek) 的 RTL8201F 系列网卡 PHY 芯片手册。按OSI 7层网络模型划分,网卡PHY 芯片(图中的RTL8201F)位于物理层,对应的软件层就是本文讨论的 PHY 驱动层;而 MAC 位于 数据链路层,也是通常软件上所说的网卡驱动层,它不是本文的重点,不做展开。另外,可通过 MDIO 接口对 PHY 芯片进行配置(如PHY芯片寄存器读写),而 PHY 和 MAC 通过 MII/RMII 进行数据传输。
刘盼
2023/11/05
3.4K0
一文搞懂 Linux 网络 Phy 驱动
20.Linux-USB鼠标驱动
本文介绍了如何通过Linux内核模块编程,实现USB设备驱动,特别是针对键盘、鼠标等输入设备的驱动开发。通过分析具体的实现过程,作者让读者了解如何通过Linux内核模块编程,实现USB设备驱动,特别是针对键盘、鼠标等输入设备的驱动开发。
诺谦
2018/01/03
8.4K0
20.Linux-USB鼠标驱动
Linux驱动开发: 编写USB接口光谱仪驱动
开发板: Exynos4412(Cortex-A9) ----友善之臂Tiny4412
DS小龙哥
2022/01/17
3.7K0
linux设备驱动程序注冊过程具体解释
以下以内核提供的演示样例代码pci-skeleton.c,具体说明一个pci设备驱动程序的注冊过程。其它设备的驱动代码注冊过程基本同样,大家可自行查看。使用的内核代码版本号是2.6.38。
全栈程序员站长
2022/07/13
2.4K0
Linux驱动之PCI子系统剖析
PCI是外围设备互连(Peripheral Component Interconnect)的简称,作为一种通用的总线接口标准,它已经普遍使用在了计算机中。PCI总线常见于x86体系,本文默认面向的体系为x86,注意x86架构下IO与内存是独立编址的。
菜菜cc
2022/11/15
3.6K1
Linux驱动之PCI子系统剖析
usb协议开发_基于事件驱动的架构
大家好,我是架构君,一个会写代码吟诗的架构师。今天说一说usb协议开发_基于事件驱动的架构,希望能够帮助大家进步!!!
Java架构师必看
2022/06/15
2K0
usb协议开发_基于事件驱动的架构
Linux设备驱动模型-Driver
linux将所有的驱动抽象为struct device_driver结构。这样设计可以方便驱动程序更好编写,在编写驱动的时候只需要将此结构嵌入到具体的驱动中即可。
DragonKingZhu
2020/03/24
4.4K0
21.Linux-写USB键盘驱动(详解)
诺谦
2018/01/03
7.4K0
21.Linux-写USB键盘驱动(详解)
Linux USB 设备驱动模型
"USB 接口"是逻辑上的 USB 设备,编写的 usb_driver 驱动程序,支持的是"USB 接口":
Jasonangel
2023/08/22
7180
Linux USB 设备驱动模型
I2C总线架构 之 I2C核心
在之前的 「《I2C总线架构 之 设备驱动》」 和 「《I2C总线架构 之 总线驱动》」 中一再提到i2c核心,本篇文章就总结一下i2c核心的主要功能。
开源519
2020/09/03
2.7K0
Linux平台驱动分析
/*platform总线,驱动,设备模型。 这是一种机制。这样会使得驱动编写方便,便于维护*/ /*platform总线是一种虚拟的总线。 其实platform总线也是当作设备*/ /*******************************platform总线******************************************************/ int __init platform_bus_init(void) { int error; early_platform
DragonKingZhu
2022/05/08
1.4K0
Linux设备驱动模型-Device
Linux将所有的设备统一抽象为struct device结构, 同时将所有的驱动统一抽象为struct device_driver结构。这样设计之后就方便驱动开发工程师编写驱动,只需要将具体的设备包含struct device结构,具体的驱动包含struct device_driver结构。最终会调用device_register和driver_register将驱动和设备注册到系统,表现出来就是在sys目录的device和driver目录下。本小节先分析device结构,以及相关API,以及如何注册到系统中,以及提供给上层的sys接口。
DragonKingZhu
2020/03/24
8.1K0
宋宝华:Linux设备与驱动的手动解绑与手动绑定
众所周知,Linux靠设备与驱动之间的match,来完成设备与驱动的bind,从而触发驱动的probe()成员函数被执行。每个bus都有相应的match方法,完成match的总的入口函数是:
Linux阅码场
2020/07/21
5.1K0
platform driver注册过程
platform 总线上的驱动注册一般使用module_platform_driver宏,如goldfish设备的注册 module_platform_driver(goldfish_pipe); 这个宏定义在/goldfish/include/linux/platform_device.h文件
全栈程序员站长
2022/09/14
1.2K0
SDIO接口WiFi驱动浅析[通俗易懂]
SDIO-Wifi模块是基于SDIO接口的符合wifi无线网络标准的嵌入式模块,内置无线网络协议IEEE802.11协议栈以及TCP/IP协议栈,能够实现用户主平台数据通过SDIO口到无线网络之间的转换。SDIO具有传输数据快,兼容SD、MMC接口等特点。
全栈程序员站长
2022/11/09
7.2K0
SDIO接口WiFi驱动浅析[通俗易懂]
带你遨游USB世界
USB的全称是Universal Serial Bus,通用串行总线。它的出现主要是为了简化个人计算机与外围设备的连接,增加易用性。USB支持热插拔,并且是即插即用的,另外,它还具有很强的可扩展性,传输速度也很快,这些特性使支持USB接口的电子设备更易用、更大众化。
233333
2020/07/21
2.7K0
带你遨游USB世界
高通SDX55平台:adb功能异常
在Linux环境上使用SDX55模块时出现无法识别adb端口,但可以识别手机adb端口。
四儿家的小祖宗
2022/11/15
3.8K0
高通SDX55平台:adb功能异常
相关推荐
13.USB驱动
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验