Blog icon indicating copy to clipboard operation
Blog copied to clipboard

Linux USB总线驱动回顾

Open jason--liu opened this issue 5 years ago • 0 comments

最近调试一个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

jason--liu avatar Jun 28 '19 03:06 jason--liu