Blog
Blog copied to clipboard
Linux USB总线驱动回顾
最近调试一个U盘的问题,一直以为是驱动的问题,也借此机会回顾了下Linux USB驱动的大体框架。
驱动模型
其实Linux 下的驱动大部分都遵守总线(BUS),设备(Device),驱动(Driver)模型。这种模型简单说就是总线上有两个链表,一个是驱动链表,一个是设备链表,总线都有一个match
函数,负责匹配设备和驱动,这个匹配过程一般是匹配名字,或者id;当匹配成功后,总线就会调用驱动的probe
函数,至于probe函数做什么事情,那就是具体驱动做的事了。Linux下的i2c,spi,platform,包括USB都是属于这种模型。
匹配过程
代码在driver/usb/core/driver.c中,
static int usb_device_match(struct device *dev, struct device_driver *drv)
{
//先是一些判断,暂时不关心
...
//匹配驱动里面的id_table
id = usb_match_id(intf, usb_drv->id_table);
...
if(id) return 1;
id = usb_match_dynamic_id(intf, usb_drv);
if(id) return 1;
return 0;
}
usb_match_id里面会调用usb_match_one_d,下面看看具体实现。
int usb_match_one_id(struct usb_interface *interface,
const struct usb_device_id *id)
{
// 又是一些判断,忽略暂时不关心,
// 下面就是各种匹配规则,也就是我们驱动里面的id_table编写的规则,下面可以看下优盘是怎么匹配的
/* The interface class, subclass, and protocol should never be
* checked for a match if the device class is Vendor Specific,
* unless the match record specifies the Vendor ID. */
if (dev->descriptor.bDeviceClass == USB_CLASS_VENDOR_SPEC &&
!(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
(id->match_flags & (USB_DEVICE_ID_MATCH_INT_CLASS |
USB_DEVICE_ID_MATCH_INT_SUBCLASS |
USB_DEVICE_ID_MATCH_INT_PROTOCOL)))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
(id->bInterfaceClass != intf->desc.bInterfaceClass))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) &&
(id->bInterfaceSubClass != intf->desc.bInterfaceSubClass))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) &&
(id->bInterfaceProtocol != intf->desc.bInterfaceProtocol))
return 0;
return 1;
}
U盘驱动在drivers/usb/storage/usb.c 看下它的id_table
struct usb_device_id usb_storage_usb_ids[] = {
# include "unusual_devs.h"
{ }/* Terminating entry */
};
//这里直接包含了一个头文件,举个ATMEL例子
UNUSUAL_DEV( 0x03eb, 0x2002, 0x0100, 0x0100,
"ATMEL",
"SND1 Storage",
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE),
//看下这个宏是怎么实现的
#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
vendor_name, product_name, use_protocol, use_transport, \
init_function, Flags) \
{ \
.vendorName = vendor_name, \
.productName = product_name, \
.useProtocol = use_protocol, \
.useTransport = use_transport, \
.initFunction = init_function, \
}
//其实就是给usb_device_id结构里面的各个成员赋值
参考资料
https://blog.csdn.net/encourage2011/article/details/76407232 https://blog.csdn.net/u014742281/article/details/89328518 https://www.veryarm.com/57647.html