1. 程式人生 > >USB主機控制器驅動——OHCI分析

USB主機控制器驅動——OHCI分析

    本文以 2440-ohci 驅動為例,簡單分析 USB 主機控制器驅動 根 Hub 的註冊過程,以及 USB裝置的列舉過程,並不涉及USB協議,單純分析驅動框架流程。無論是hub還是普通的usb裝置,它們註冊到 usb_bus_type 都會經歷兩次 Match ,因為第一次註冊進來時,是將整個裝置作為一個 device 註冊,然後在通用的 devices 驅動程式 usb_generic_driver 的 generic_probe 函式中,將該裝置的所有介面進行設定並將這些介面註冊到 usb_bus_type 。如果是Hub裝置的介面,則會呼叫 hub_probe,如果是其他裝置則呼叫 xx_probe 函式。如果是 Hub 的話,usb主機會監測hub埠變化,如果有變化會分配一個usb_devices 註冊到 usb_bus_type 重複前邊的步驟。  

  

    首先,整個驅動框架的開始,是基於 platform 平臺匯流排的。

struct platform_device s3c_device_usb = {
	.name		  = "s3c2410-ohci",
	.id		  = -1,
	.num_resources	  = ARRAY_SIZE(s3c_usb_resource),
	.resource	  = s3c_usb_resource,
	.dev              = {
		.dma_mask = &s3c_device_usb_dmamask,
		.coherent_dma_mask = 0xffffffffUL
	}
};
static struct platform_driver ohci_hcd_s3c2410_driver = {
	.probe		= ohci_hcd_s3c2410_drv_probe,
	.remove		= ohci_hcd_s3c2410_drv_remove,
	.shutdown	= usb_hcd_platform_shutdown,
	/*.suspend	= ohci_hcd_s3c2410_drv_suspend, */
	/*.resume	= ohci_hcd_s3c2410_drv_resume, */
	.driver		= {
		.owner	= THIS_MODULE,
		.name	= "s3c2410-ohci",
	},
};
    platform 平臺匯流排模型,這裡定義了 platform_device 和 platform_driver ,後面將這倆註冊到 platform_bus_type 時,就會根據它們的名字來匹配,顯然,它們的名字都是 “s3c2410-ohci” ,匹配成功後,便會呼叫到 ohci_hcd_s3c2410_drv_probe 函式。在看 probe 函式之前,我們先看看裝置側提供的資訊。
static struct resource s3c_usb_resource[] = {
	[0] = {
		.start = S3C_PA_USBHOST,
		.end   = S3C_PA_USBHOST + 0x100 - 1,
		.flags = IORESOURCE_MEM,
	},
	[1] = {
		.start = IRQ_USBH,
		.end   = IRQ_USBH,
		.flags = IORESOURCE_IRQ,
	}
};
    resource 中指定了 2440 主機控制器的暫存器範圍,以及中斷。
int usb_simtec_init(void)
{
	s3c_device_usb.dev.platform_data = &usb_simtec_info;
}


static struct s3c2410_hcd_info usb_simtec_info = {
	.port[0]	= {
		.flags	= S3C_HCDFLG_USED
	},
	.port[1]	= {
		.flags	= S3C_HCDFLG_USED
	},

	.power_control	= usb_simtec_powercontrol,
	.enable_oc	= usb_simtec_enableoc,
};
    這裡,指定了一些額外的資訊,儲存在 dev.platform_data 中,後邊我們再來看他們是幹什麼用的。下面來看 probe 函式。
static int ohci_hcd_s3c2410_drv_probe(struct platform_device *pdev)
{
	return usb_hcd_s3c2410_probe(&ohci_s3c2410_hc_driver, pdev);
}
static int usb_hcd_s3c2410_probe (const struct hc_driver *driver,
				  struct platform_device *dev)
{
	struct usb_hcd *hcd = NULL;
	int retval;
	
	/* 設定GPG4輸出1 mini2440 jz2440好像均不需要 */
	s3c2410_usb_set_power(dev->dev.platform_data, 1, 1);
	s3c2410_usb_set_power(dev->dev.platform_data, 2, 1);
	
	/* 建立usb_hcd 繫結 usb_driver等 */
	hcd = usb_create_hcd(driver, &dev->dev, "s3c24xx");
	
	/* 主機控制暫存器 起始地址 結束地址 */
	hcd->rsrc_start = dev->resource[0].start;
	hcd->rsrc_len   = dev->resource[0].end - dev->resource[0].start + 1;
	
	/* 申請IO空間 */
	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
		...
	}
	/* 獲得usb-host 時鐘 */
	clk = clk_get(&dev->dev, "usb-host");
	/* 獲得 usb-bus-host 時鐘 */
	usb_clk = clk_get(&dev->dev, "usb-bus-host");
	/* 使能時鐘 使能過流檢查 */
	s3c2410_start_hc(dev, hcd);
	/* Ioremap */
	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);

	ohci_hcd_init(hcd_to_ohci(hcd));

	retval = usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED);

	return 0;

}
    前邊第一個 probe 函式僅僅是一箇中轉,usb_hcd_s3c2410_probe 它才是真正的 probe 函式,主要工作就是分配一個 usb_hcd 結構、設定然後 usb_add_hcd 。
struct usb_hcd {

	/*
	 * housekeeping
	 */
	struct usb_bus		self;		/* hcd is-a bus */
	struct kref		kref;		/* reference counter */

	const char		*product_desc;	/* product/vendor string */
	char			irq_descr[24];	/* driver + bus # */

	struct timer_list	rh_timer;	/* drives root-hub polling */
	struct urb		*status_urb;	/* the current status urb */
#ifdef CONFIG_PM
	struct work_struct	wakeup_work;	/* for remote wakeup */
#endif

	/*
	 * hardware info/state
	 */
	const struct hc_driver	*driver;	/* hw-specific hooks */

	/* Flags that need to be manipulated atomically */
	unsigned long		flags;
#define HCD_FLAG_HW_ACCESSIBLE	0x00000001
#define HCD_FLAG_SAW_IRQ	0x00000002

	unsigned		rh_registered:1;/* is root hub registered? */

	/* The next flag is a stopgap, to be removed when all the HCDs
	 * support the new root-hub polling mechanism. */
	unsigned		uses_new_polling:1;
	unsigned		poll_rh:1;	/* poll for rh status? */
	unsigned		poll_pending:1;	/* status has changed? */
	unsigned		wireless:1;	/* Wireless USB HCD */
	unsigned		authorized_default:1;
	unsigned		has_tt:1;	/* Integrated TT in root hub */

	int			irq;		/* irq allocated */
	void __iomem		*regs;		/* device memory/io */
	u64			rsrc_start;	/* memory/io resource start */
	u64			rsrc_len;	/* memory/io resource length */
	unsigned		power_budget;	/* in mA, 0 = no limit */

#define HCD_BUFFER_POOLS	4
	struct dma_pool		*pool [HCD_BUFFER_POOLS];

	int			state;
#	define	__ACTIVE		0x01
#	define	__SUSPEND		0x04
#	define	__TRANSIENT		0x80

#	define	HC_STATE_HALT		0
#	define	HC_STATE_RUNNING	(__ACTIVE)
#	define	HC_STATE_QUIESCING	(__SUSPEND|__TRANSIENT|__ACTIVE)
#	define	HC_STATE_RESUMING	(__SUSPEND|__TRANSIENT)
#	define	HC_STATE_SUSPENDED	(__SUSPEND)

#define	HC_IS_RUNNING(state) ((state) & __ACTIVE)
#define	HC_IS_SUSPENDED(state) ((state) & __SUSPEND)

	/* more shared queuing code would be good; it should support
	 * smarter scheduling, handle transaction translators, etc;
	 * input size of periodic table to an interrupt scheduler.
	 * (ohci 32, uhci 1024, ehci 256/512/1024).
	 */

	/* The HC driver's private data is stored at the end of
	 * this structure.
	 */
	unsigned long hcd_priv[0]
			__attribute__ ((aligned(sizeof(unsigned long))));
};
    usb_hcd —— USB Host Controller Driver,同時,一個主機控制器驅動對應一條 usb_bus 。
struct usb_bus {
	struct device *controller;	/* host/master side hardware */
	int busnum;			/* Bus number (in order of reg) */
	const char *bus_name;		/* stable id (PCI slot_name etc) */
	u8 uses_dma;			/* Does the host controller use DMA? */
	u8 otg_port;			/* 0, or number of OTG/HNP port */
	unsigned is_b_host:1;		/* true during some HNP roleswitches */
	unsigned b_hnp_enable:1;	/* OTG: did A-Host enable HNP? */

	int devnum_next;		/* Next open device number in
					 * round-robin allocation */

	struct usb_devmap devmap;	/* device address allocation map */
	struct usb_device *root_hub;	/* Root hub */
	struct list_head bus_list;	/* list of busses */

	int bandwidth_allocated;	/* on this bus: how much of the time
					 * reserved for periodic (intr/iso)
					 * requests is used, on average?
					 * Units: microseconds/frame.
					 * Limits: Full/low speed reserve 90%,
					 * while high speed reserves 80%.
					 */
	int bandwidth_int_reqs;		/* number of Interrupt requests */
	int bandwidth_isoc_reqs;	/* number of Isoc. requests */

#ifdef CONFIG_USB_DEVICEFS
	struct dentry *usbfs_dentry;	/* usbfs dentry entry for the bus */
#endif

#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
	struct mon_bus *mon_bus;	/* non-null when associated */
	int monitored;			/* non-zero when monitored */
#endif
};

    hcd的分配過程

struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
		struct device *dev, const char *bus_name)
{
	struct usb_hcd *hcd;
	
	/* 分配一個 usb_hcd + driver->hcd_priv_size 空間 */
	hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL);
	
	/* dev->p->driver_data = hcd; */
	dev_set_drvdata(dev, hcd);
	
	kref_init(&hcd->kref);
	
	/* 初始化 usb_bus ,一個主機控制器對應一個 usb_bus */
	usb_bus_init(&hcd->self);
	
	/* 設定 usb_bus */
	hcd->self.controller = dev;
	hcd->self.bus_name = bus_name;
	hcd->self.uses_dma = (dev->dma_mask != NULL);
	
	/* 初始化 根Hub poll定時器 */
	init_timer(&hcd->rh_timer);
	hcd->rh_timer.function = rh_timer_func;
	hcd->rh_timer.data = (unsigned long) hcd;
#ifdef CONFIG_PM
	INIT_WORK(&hcd->wakeup_work, hcd_resume_work);
#endif
	/* 繫結 hc_driver */
	hcd->driver = driver;
	hcd->product_desc = (driver->product_desc) ? driver->product_desc :
			"USB Host Controller";
	return hcd;
}
static void usb_bus_init (struct usb_bus *bus)
{
	memset (&bus->devmap, 0, sizeof(struct usb_devmap));

	bus->devnum_next = 1;

	bus->root_hub = NULL;
	bus->busnum = -1;
	bus->bandwidth_allocated = 0;
	bus->bandwidth_int_reqs  = 0;
	bus->bandwidth_isoc_reqs = 0;

	INIT_LIST_HEAD (&bus->bus_list);
}

整個Probe函式裡幹了那些事:

    1、建立一個 usb_hcd

    2、usb_bus_init ,初始化 usb_hcd 對應的 usb_bus ,bus->devmap 清零,根 Hub 指向 NULL等

    3、設定 usb_hcd.usb_bus 

      3.1 hcd.usb_bus.controller = s3c_device_usb.dev (最開始建立的平臺device)

      3.2 hcd.usb_bus.name = “s3c24xx”

    4、設定 usb_hcd.rh_timer

    5、設定 usb_hcd.driver = ohci_s3c2410_hc_driver 

    6、根據 resource 資源,設定usb_hcd.rsrc_start、usb_hcd.rsrc_len

    7、使能時鐘

    8、ioremap 、申請 io 空間

    9、usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED)

int usb_add_hcd(struct usb_hcd *hcd,
		unsigned int irqnum, unsigned long irqflags)
{
	int retval;
	struct usb_device *rhdev;
	/* 無線USB? */
	hcd->authorized_default = hcd->wireless? 0 : 1;
	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);

	/* hcd->pool[i] = dma_pool_create(name, hcd->self.controller,size, size, 0); */
	if ((retval = hcd_buffer_create(hcd)) != 0) {
		...
	}
	/*
	 * busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);
	 * bus->busnum = busnum;
	 * list_add (&bus->bus_list, &usb_bus_list);
	 */
	if ((retval = usb_register_bus(&hcd->self)) < 0)
		goto err_register_bus;
	/* 根 Hub */
	if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) {
		...
	}

	rhdev->speed = USB_SPEED_FULL;

	hcd->self.root_hub = rhdev;
	
	/* dev->power.can_wakeup = dev->power.should_wakeup = 1 */
	device_init_wakeup(&rhdev->dev, 1);

	if (hcd->driver->irq) {

		snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d",
				hcd->driver->description, hcd->self.busnum);
				
		if ((retval = request_irq(irqnum, &usb_hcd_irq, irqflags,
				hcd->irq_descr, hcd)) != 0) {
			...
		}
		hcd->irq = irqnum;		
	}
	
	hcd->driver->start(hcd));


	/* starting here, usbcore will pay attention to this root hub */
	rhdev->bus_mA = min(500u, hcd->power_budget);
	if ((retval = register_root_hub(hcd)) != 0)
		goto err_register_root_hub;

	retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group);

	if (hcd->uses_new_polling && hcd->poll_rh)
		usb_hcd_poll_rh_status(hcd);
	return retval;

}

usb_hcd_add 幹了哪些事:

    1、hcd_buffer_create(hcd) 

    2、usb_register_bus(&hcd->self) ,將 usb_hcd.usb_bus 註冊到全域性連結串列 usb_bus_list

    3、為根 hub 分配一個 usb_device 結構(核心中,所有的真實的usb裝置(Hub,滑鼠...)都用usb_device結構來描述)

    4、註冊根 Hub 的 usb_device 結構到 usb_bus_type

    弄了半天,神神祕祕的USB主機控制器也只不過是分配了一個 usb_hcd 結構體,為它的 根hub 分配了一個usb_device 結構體,註冊到 usb_bus_type 罷了,後邊是 根Hub 的註冊和裝置列舉過程了。

struct usb_device *usb_alloc_dev(struct usb_device *parent,
				 struct usb_bus *bus, unsigned port1)
{
	struct usb_device *dev;
	struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self);
	unsigned root_hub = 0;
	/* 分配一個 usb_device  */
	dev = kzalloc(sizeof(*dev), GFP_KERNEL);

	device_initialize(&dev->dev);
	/* usb_bus_type */
	dev->dev.bus = &usb_bus_type;
	/* 屬性檔案 */
	dev->dev.type = &usb_device_type;
	dev->dev.groups = usb_device_groups;
	dev->dev.dma_mask = bus->controller->dma_mask;
	set_dev_node(&dev->dev, dev_to_node(bus->controller));
	dev->state = USB_STATE_ATTACHED;
	atomic_set(&dev->urbnum, 0);

	INIT_LIST_HEAD(&dev->ep0.urb_list);
	dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
	dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
	/* ep0 maxpacket comes later, from device descriptor */
	usb_enable_endpoint(dev, &dev->ep0, false);
	dev->can_submit = 1;

	/* 如果是根Hub */
	if (unlikely(!parent)) {
		...
	} else {
		...
	}

<span style="white-space:pre">	</span>...
	}
	return dev;
}
注意一下幾點:

    1、dev->dev.bus = &usb_bus_type 這裡出現了一條“匯流排模型”中的匯流排,注意和 usb_bus 完全沒關係。相當於hub 、滑鼠等 usb 裝置是註冊到 usb_bus_type 的,前面我們說的控制器的驅動是註冊到 platform_bus_type 的。

    2、dev->dev.type = &usb_device_type ;後邊Match函式中會用到

    3、dev->state = USB_STATE_ATTACHED; 根Hub是和控制器連在一起的,必然已經連線上了

      ATTACHED :表示裝置已經連線到 hub 介面上了。

      Powered      :表示加電狀態

      Default         :表示預設狀態,在powered狀態之後,裝置必須受到一個復位訊號併成功復位後,才能使用預設地址迴應主機發過來的裝置描述符的請求。

      Address        :表示主機分配了一個唯一的地址給裝置。

      Configured   :表示裝置已經被主機配置過了,此時,主機可以使用裝置提供的所有功能。

      Supended    :表示掛起狀態,裝置在指定的時間內沒有傳輸,就要進入掛起狀態。
    4、dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT ,我們說一個 usb 裝置有多個配置,每個配置又有多個介面,每個介面有多個 端點。但是端點 0 比較特殊,它是整個 usb 裝置共享的,因此它的表述符直接在 usb_device中。

    5、dev->bus = bus ,根 Hub 連線到 控制器匯流排。

static int register_root_hub(struct usb_hcd *hcd)
{
	struct device *parent_dev = hcd->self.controller;
	struct usb_device *usb_dev = hcd->self.root_hub;
	const int devnum = 1;
	int retval;
	
	/* 裝置地址 */
	usb_dev->devnum = devnum;
	usb_dev->bus->devnum_next = devnum + 1;
	memset (&usb_dev->bus->devmap.devicemap, 0,
			sizeof usb_dev->bus->devmap.devicemap);
	set_bit (devnum, usb_dev->bus->devmap.devicemap);
	usb_set_device_state(usb_dev, USB_STATE_ADDRESS);

	mutex_lock(&usb_bus_list_lock);

	usb_dev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
	
	/* 獲得裝置描述符 */
	retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);

	/* 進一步設定,然後 add_device */
	retval = usb_new_device (usb_dev);

	return retval;
}
    1、usb_dev->devnum = 1 ;根 Hub 的地址為1 ,usb_dev->bus->devmap.devicemap ,表示哪些裝置地址被佔用了,以及這個 hub 一共支援多少裝置。

    2、usb_set_device_state(usb_dev, USB_STATE_ADDRESS); 變更狀態

    3、usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE); 獲得裝置描述符,儲存在usb_dev.descriptor 中。

    4、usb_new_device 進一步設定(獲得配置、端點描述符等),將 usb_device 註冊到 usb_bus_type 。

int usb_get_device_descriptor(struct usb_device *dev, unsigned int size)
{
	struct usb_device_descriptor *desc;
	int ret;

	if (size > sizeof(*desc))
		return -EINVAL;
	desc = kmalloc(sizeof(*desc), GFP_NOIO);
	if (!desc)
		return -ENOMEM;

	ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, size);
	if (ret >= 0)
		memcpy(&dev->descriptor, desc, size);
	kfree(desc);
	return ret;
}
int usb_get_descriptor(struct usb_device *dev, unsigned char type,
		       unsigned char index, void *buf, int size)
{
	int i;
	int result;

	memset(buf, 0, size);	/* Make sure we parse really received data */

	for (i = 0; i < 3; ++i) {
		/* retry on length 0 or error; some devices are flakey */
		result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
				USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
				(type << 8) + index, 0, buf, size,
				USB_CTRL_GET_TIMEOUT);
		if (result <= 0 && result != -ETIMEDOUT)
			continue;
		if (result > 1 && ((u8 *)buf)[1] != type) {
			result = -ENODATA;
			continue;
		}
		break;
	}
	return result;
}
    注意,這裡是將整個根Hub作為一個 device 註冊到 usb_bus_type ,後邊還會將Hub的介面註冊進去
int usb_new_device(struct usb_device *udev)
{
	int err;

	/* Increment the parent's count of unsuspended children */
	if (udev->parent)
		usb_autoresume_device(udev->parent);

	usb_detect_quirks(udev);		/* Determine quirks */
	err = usb_configure_device(udev);	/* detect & probe dev/intfs */

	/* export the usbdev device-node for libusb */
	udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
			(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));

	/* Tell the world! */
	announce_device(udev);

	/* Register the device.  The device driver is responsible
	 * for configuring the device and invoking the add-device
	 * notifier chain (used by usbfs and possibly others).
	 */
	err = device_add(&udev->dev);

	(void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev);
	return err;

}

static int usb_configure_device(struct usb_device *udev)
{
	usb_get_configuration(udev);
}
int usb_get_configuration(struct usb_device *dev)
{
	struct device *ddev = &dev->dev;
	int ncfg = dev->descriptor.bNumConfigurations;
	int result = 0;
	unsigned int cfgno, length;
	unsigned char *buffer;
	unsigned char *bigbuffer;
	struct usb_config_descriptor *desc;

	cfgno = 0;

	if (ncfg > USB_MAXCONFIG) {
		dev->descriptor.bNumConfigurations = ncfg = USB_MAXCONFIG;
	}

	length = ncfg * sizeof(struct usb_host_config);
	dev->config = kzalloc(length, GFP_KERNEL);

	length = ncfg * sizeof(char *);
	dev->rawdescriptors = kzalloc(length, GFP_KERNEL);

	buffer = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL);

	desc = (struct usb_config_descriptor *)buffer;

	result = 0;
	for (; cfgno < ncfg; cfgno++) {
		/* We grab just the first descriptor so we know how long the whole configuration is */
		result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, USB_DT_CONFIG_SIZE);

		length = max((int) le16_to_cpu(desc->wTotalLength), USB_DT_CONFIG_SIZE);

		/* Now that we know the length, get the whole thing */
		bigbuffer = kmalloc(length, GFP_KERNEL);

		result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, length);
		
		dev->rawdescriptors[cfgno] = bigbuffer;
		/* 解析配置描述符 */
		result = usb_parse_configuration(&dev->dev, cfgno, &dev->config[cfgno], bigbuffer, length);
	}
	result = 0;

	return result;
}

    也就是說,在將 usb_device 註冊到 usb_bus_type 時,它所有的描述符資訊都已經獲取到了。

    整個控制器驅動一路走下來,最後 註冊了一個根 Hub 的 usb_device 到 usb_bus_type 。有必要看一下usb_bus_type ,它的 match 函式,將註冊進來的 device 和 介面分開處理。第一次註冊的我們說是 device ,那麼看看對應的 driver 是啥。
struct bus_type usb_bus_type = {
	.name =		"usb",
	.match =	usb_device_match,
	.uevent =	usb_uevent,
};
static int usb_device_match(struct device *dev, struct device_driver *drv)
{
	/* return dev->type == &usb_device_type; */
	if (is_usb_device(dev)) {

		/* return container_of(drv, struct usbdrv_wrap, driver)->for_devices; */
		if (!is_usb_device_driver(drv))
			return 0;

		/* TODO: Add real matching code */
		return 1;

	} else if (is_usb_interface(dev)) {
		....
	}

	return 0;
}

    如果裝置的 dev->type == &usb_device_type ,且 driver.for_devices == 1 ,直接匹配成功。匹配成功之後便會呼叫driver側的 probe 函數了。

struct usb_device_driver usb_generic_driver = {
	.name =	"usb",
	.probe = generic_probe,
	.disconnect = generic_disconnect,
#ifdef	CONFIG_PM
	.suspend = generic_suspend,
	.resume = generic_resume,
#endif
	.supports_autosuspend = 1,
};
static int generic_probe(struct usb_device *udev)
{
	int err, c;

	c = usb_choose_configuration(udev);

	err = usb_set_configuration(udev, c);

	/* USB device state == configured ... usable */
	usb_notify_add_device(udev);

	return 0;
}
int usb_set_configuration(struct usb_device *dev, int configuration)
{
	int i, ret;
	struct usb_host_config *cp = NULL;
	struct usb_interface **new_interfaces = NULL;
	int n, nintf;

	if (dev->authorized == 0 || configuration == -1)
		configuration = 0;
	else {
		for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
			if (dev->config[i].desc.bConfigurationValue ==
					configuration) {
				cp = &dev->config[i];
				break;
			}
		}
	}

	n = nintf = 0;
	if (cp) {
		/* new_interfaces 是個指標陣列,首先為它分配空間 */
		nintf = cp->desc.bNumInterfaces;
		new_interfaces = kmalloc(nintf * sizeof(*new_interfaces), GFP_KERNEL);
		/* 為它指向的介面分配空間 */
		for (; n < nintf; ++n) {
			new_interfaces[n] = kzalloc(sizeof(struct usb_interface), GFP_KERNEL);
		}

		i = dev->bus_mA - cp->desc.bMaxPower * 2;
	}

	/* Wake up the device so we can send it the Set-Config request */
	ret = usb_autoresume_device(dev);

	if (cp)
		ret = usb_hcd_check_bandwidth(dev, cp, NULL);
	else
		ret = usb_hcd_check_bandwidth(dev, NULL, NULL);

	/* if it's already configured, clear out old state first.
	 * getting rid of old interfaces means unbinding their drivers.
	 */
	if (dev->state != USB_STATE_ADDRESS)
		usb_disable_device(dev, 1);	/* Skip ep0 */

	/* Get rid of pending async Set-Config requests for this device */
	cancel_async_set_config(dev);
	
	/* 設定配置 */
	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
			      USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
			      NULL, 0, USB_CTRL_SET_TIMEOUT);

	dev->actconfig = cp;
	
	/* 變更狀態 */
	usb_set_device_state(dev, USB_STATE_CONFIGURED);
	
	/* 設定這個配置的所有介面 */
	for (i = 0; i < nintf; ++i) {
		struct usb_interface_cache *intfc;
		struct usb_interface *intf;
		struct usb_host_interface *alt;

		cp->interface[i] = intf = new_interfaces[i];
		intfc = cp->intf_cache[i];
		intf->altsetting = intfc->altsetting;
		intf->num_altsetting = intfc->num_altsetting;
		intf->intf_assoc = find_iad(dev, cp, i);
		kref_get(&intfc->ref);

		alt = usb_altnum_to_altsetting(intf, 0);

		if (!alt)
			alt = &intf->altsetting[0];

		intf->cur_altsetting = alt;
		usb_enable_interface(dev, intf, true);
		intf->dev.parent = &dev->dev;
		intf->dev.driver = NULL;
		intf->dev.bus = &usb_bus_type;
		
		/* 注意這個,match時會區分 device 和 介面 */
		intf->dev.type = &usb_if_device_type;
		intf->dev.groups = usb_interface_groups;
		intf->dev.dma_mask = dev->dev.dma_mask;
		INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);
		device_initialize(&intf->dev);
		mark_quiesced(intf);
		dev_set_name(&intf->dev, "%d-%s:%d.%d",
			dev->bus->busnum, dev->devpath,
			configuration, alt->desc.bInterfaceNumber);
	}
	kfree(new_interfaces);

	if (cp->string == NULL &&
			!(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
		cp->string = usb_cache_string(dev, cp->desc.iConfiguration);

	for (i = 0; i < nintf; ++i) {
		struct usb_interface *intf = cp->interface[i];
		
		/* 註冊到 usb_bus_type */
		ret = device_add(&intf->dev);
		create_intf_ep_devs(intf);
	}

	usb_autosuspend_device(dev);
	return 0;
}
static int usb_device_match(struct device *dev, struct device_driver *drv)
{
	/* devices and interfaces are handled separately */
	if (is_usb_device(dev)) {
<span style="white-space:pre">	</span>...
	} else if (is_usb_interface(dev)) {
		struct usb_interface *intf;
		struct usb_driver *usb_drv;
		const struct usb_device_id *id;

		/* device drivers never match interfaces */
		if (is_usb_device_driver(drv))
			return 0;

		intf = to_usb_interface(dev);
		usb_drv = to_usb_driver(drv);

		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;
}
    第一次註冊進來的是 devies,在通用的driver 的 probe 函式,將該裝置的所有介面資訊都讀取出來並設定再註冊到 usb_bus_type 中,也就是說在match函式中,會走下邊這個分支,根據 dirver 的 id_table 來匹配,根 Hub 的介面自然是與 hub_driver 進行匹配。
static struct usb_driver hub_driver = {
	.name =		"hub",
	.probe =	hub_probe,
	.disconnect =	hub_disconnect,
	.suspend =	hub_suspend,
	.resume =	hub_resume,
	.reset_resume =	hub_reset_resume,
	.pre_reset =	hub_pre_reset,
	.post_reset =	hub_post_reset,
	.ioctl =	hub_ioctl,
	.id_table =	hub_id_table,
	.supports_autosuspend =	1,
};
int usb_hub_init(void)
{
	if (usb_register(&hub_driver) < 0) {
		...
	}
	/* 建立核心執行緒,子程序將從 hub_thread 開始,名字叫 khubd  */
	khubd_task = kthread_run(hub_thread, NULL, "khubd");
}
    分析過裝置模型的都知道,匹配成功後呼叫的是usb_driver.driver.probe函式,然而這裡並沒有,而且usb_bus_type中也沒有 probe 函式,那麼有可能是在driver的註冊過程中動了哪些手腳。
static inline int usb_register(struct usb_driver *driver)
{
	return usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);
}
int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
			const char *mod_name)
{
	int retval = 0;

	if (usb_disabled())
		return -ENODEV;

	new_driver->drvwrap.for_devices = 0;
	new_driver->drvwrap.driver.name = (char *) new_driver->name;
	new_driver->drvwrap.driver.bus = &usb_bus_type;
	new_driver->drvwrap.driver.probe = usb_probe_interface;
	new_driver->drvwrap.driver.remove = usb_unbind_interface;
	new_driver->drvwrap.driver.owner = owner;
	new_driver->drvwrap.driver.mod_name = mod_name;
	spin_lock_init(&new_driver->dynids.lock);
	INIT_LIST_HEAD(&new_driver->dynids.list);

	retval = driver_register(&new_driver->drvwrap.driver);

	if (!retval) {
		pr_info("%s: registered new interface driver %s\n",
			usbcore_name, new_driver->name);
		usbfs_update_special();
		usb_create_newid_file(new_driver);
	} else {
		printk(KERN_ERR "%s: error %d registering interface "
			"	driver %s\n",
			usbcore_name, retval, new_driver->name);
	}

	return retval;
}
    這裡註冊到 usb_bus_type 的是 usb_driver.drvwrap.driver ,那麼匹配成功後呼叫的自然是 usb_probe_interface
static int usb_probe_interface(struct device *dev)
{
	struct usb_driver *driver = to_usb_driver(dev->driver);
	struct usb_interface *intf = to_usb_interface(dev);
	struct usb_device *udev = interface_to_usbdev(intf);
	const struct usb_device_id *id;
	int error = -ENODEV;

	dev_dbg(dev, "%s\n", __func__);

	intf->needs_binding = 0;

	id = usb_match_id(intf, driver->id_table);
	if (!id)
		id = usb_match_dynamic_id(intf, driver);
	if (id) {
		dev_dbg(dev, "%s - got id\n", __func__);

		error = usb_autoresume_device(udev);
		mark_active(intf);
		intf->condition = USB_INTERFACE_BINDING;

		atomic_set(&intf->pm_usage_cnt, !driver->supports_autosuspend);

		if (intf->needs_altsetting0) {
			error = usb_set_interface(udev, intf->altsetting[0].
					desc.bInterfaceNumber, 0);

			intf->needs_altsetting0 = 0;
		}
<span style="white-space:pre">		</span>/* 看這裡 */
		error = driver->probe(intf, id);

		intf->condition = USB_INTERFACE_BOUND;
		usb_autosuspend_device(udev);
	}

	return error;
}
    獲取到 usb_device 的介面 usb_interface 以及 usb_device_id ,然後 driver->probe(intf, id) 呼叫到 usb_driver.probe 函式。傳遞進來的引數非常重要~,尤其是第一個 ---介面。再看 probe 函式之前,還有一點需要先看一下。
int usb_hub_init(void)
{
	if (usb_register(&hub_driver) < 0) {
		...
	}
	/* 建立核心執行緒,子程序將從 hub_thread 開始,名字叫 khubd  */
	khubd_task = kthread_run(hub_thread, NULL, "khubd");
}
static int hub_thread(void *__unused)
{
	/* khubd needs to be freezable to avoid intefering with USB-PERSIST
	 * port handover.  Otherwise it might see that a full-speed device
	 * was gone before the EHCI controller had handed its port over to
	 * the companion full-speed controller.
	 */
	set_freezable();

	do {
		hub_events();
		/* wait_event_interruptible(khubd_wait, ... */
		wait_event_freezable(khubd_wait,
				!list_empty(&hub_event_list) ||
				kthread_should_stop());
	} while (!kthread_should_stop() || !list_empty(&hub_event_list));

	pr_debug("%s: khubd exiting\n", usbcore_name);
	return 0;
}
    這個核心執行緒裡幹兩件事,第一,hub_events(),第二休眠,等待喚醒。
static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
	struct usb_host_interface *desc;
	struct usb_endpoint_descriptor *endpoint;
	struct usb_device *hdev;
	struct usb_hub *hub;

	desc = intf->cur_altsetting;
	hdev = interface_to_usbdev(intf);

	/* Hub 的子類就是0,即desc->desc 這個interface 描述符裡邊的bInterfaceSubClass就應該是0 */
	if ((desc->desc.bInterfaceSubClass != 0) &&
	    (desc->desc.bInterfaceSubClass != 1)) {
		...
	}

	/* spec 規定了Hub 只有一個端點(除去端點0)也就是中斷端點 */
	if (desc->desc.bNumEndpoints != 1)
		goto descriptor_error;

	endpoint = &desc->endpoint[0].desc;

	/* 判斷這個端點是否是中斷端點 */
	if (!usb_endpoint_is_int_in(endpoint))
		goto descriptor_error;
	/* 分配一個usb_hub */
	hub = kzalloc(sizeof(*hub), GFP_KERNEL);

	kref_init(&hub->kref);
	INIT_LIST_HEAD(&hub->event_list);
	
	hub->intfdev = &intf->dev;	//hub  device
	hub->hdev = hdev;	//hub usb_device
	
	INIT_DELAYED_WORK(&hub->leds, led_work);
	INIT_DELAYED_WORK(&hub->init_work, NULL);
	usb_get_intf(intf);
	
	/* intf->dev = hub */
	usb_set_intfdata (intf, hub);
	
	intf->needs_remote_wakeup = 1;

	if (hdev->speed == USB_SPEED_HIGH)
		highspeed_hubs++;

	if (hub_configure(hub, endpoint) >= 0)
		return 0;

}
static int hub_configure(struct usb_hub *hub, struct usb_endpoint_descriptor *endpoint)
{
	struct usb_hcd *hcd;
	struct usb_device *hdev = hub->hdev;
	struct device *hub_dev = hub->intfdev;
	u16 hubstatus, hubchange;
	u16 wHubCharacteristics;
	unsigned int pipe;
	int maxp, ret;
	char *message = "out of memory";
	
	/* 記憶體分配 */
	hub->buffer = usb_buffer_alloc(hdev, sizeof(*hub->buffer), GFP_KERNEL,
			&hub->buffer_dma);
	hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL);
	mutex_init(&hub->status_mutex);
	hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);

	/* 獲得 hub 描述符 */
	ret = get_hub_descriptor(hdev, hub->descriptor,
			sizeof(*hub->descriptor));

	}
	/* hub 支援的最大下行埠 */
	hdev->maxchild = hub->descriptor->bNbrPorts;

	hub->port_owners = kzalloc(hdev->maxchild * sizeof(void *), GFP_KERNEL);

	wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);

	if (wHubCharacteristics & HUB_CHAR_COMPOUND) {
		/* 複合裝置 */
	} else
		dev_dbg(hub_dev, "standalone hub\n");

	switch (wHubCharacteristics & HUB_CHAR_LPSM) {
		/* 電源切換方式 */
	}

	switch (wHubCharacteristics & HUB_CHAR_OCPM) {
		/* 過流保護模式 */
	}

	spin_lock_init (&hub->tt.lock);
	INIT_LIST_HEAD (&hub->tt.clear_list);
	INIT_WORK(&hub->tt.clear_work, hub_tt_work);
	
	switch (hdev->descriptor.bDeviceProtocol) {
		/* 低速全速裝置掠過 */
	}

	/* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */
	switch (wHubCharacteristics & HUB_CHAR_TTTT) {
		/* 指定 hub->tt.think_time = 666 * n; n根據裝置速度不同而不同*/
	}

	/* 是否支援 hub 上的指示燈 */
	if (wHubCharacteristics & HUB_CHAR_PORTIND) {
		hub->has_indicators = 1;
		dev_dbg(hub_dev, "Port indicators are supported\n");
	}
	/* 請求裝置狀態 */
	ret = usb_get_status(hdev, USB_RECIP_DEVICE, 0, &hubstatus);

	le16_to_cpus(&hubstatus);
	
	/* hub 的埠電流 */
	if (hdev == hdev->bus->root_hub) {	//根Hub
		...
	}


	/* Update the HCD's internal representation of this hub before khubd
	 * starts getting port status changes for devices under the hub.
	 */
	hcd = bus_to_hcd(hdev->bus);
	if (hcd->driver->update_hub_device) {
		ret = hcd->driver->update_hub_device(hcd, hdev,
				&hub->tt, GFP_KERNEL);

	}

	ret = hub_hub_status(hub, &hubstatus, &hubchange);
	
	/* 獲得主機和 Hub 端點的管道 */
	pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress);
	maxp = usb_maxpacket(hdev, pipe, usb_pipeout(pipe));

	if (maxp > sizeof(*hub->buffer))
		maxp = sizeof(*hub->buffer);
	
	/* 分配一個urb */
	hub->urb = usb_alloc_urb(0, GFP_KERNEL);
	/* 填充Urb */
	usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq,
		hub, endpoint->bInterval);
	hub->urb->transfer_dma = hub->buffer_dma;
	hub->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

	/* maybe cycle the hub leds */
	if (hub->has_indicators && blinkenlights)
		hub->indicator [0] = INDICATOR_CYCLE;
	
	//tatus = usb_submit_urb(hub->urb, GFP_NOIO);
	//kick_khubd(hub) -> wake_up(&khubd_wait);
	hub_activate(hub, HUB_INIT);
	return 0;

}

    填充一個 urb ,檢測 hub 埠狀態,如果有狀態發生改變,則會呼叫 hub_irq 

static void hub_irq(struct urb *urb)
{
	struct usb_hub *hub = urb->context;
	int status = urb->status;
	unsigned i;
	unsigned long bits;

	switch (status) {
	....

	/* let khubd handle things */
	case 0:			/* we got data:  port status changed */
		bits = 0;
		for (i = 0; i < urb->actual_length; ++i)
			bits |= ((unsigned long) ((*hub->buffer)[i]))
					<< (i*8);
		hub->event_bits[0] = bits;
		break;
	}

	hub->nerrors = 0;

	/* Something happened, let khubd figure it out */
	kick_khubd(hub);

resubmit:
	if (hub->quiescing)
		return;

	if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0
			&& status != -ENODEV && status != -EPERM)
		dev_err (hub->intfdev, "resubmit --> %d\n", status);
}

    如果哪一位埠發生了變化,標記在 Hub->event_bits[0]中,然後喚醒執行緒,hub_event 被呼叫。再次提交 urb

static void hub_events(void)
{
	struct list_head *tmp;
	struct usb_device *hdev;
	struct usb_interface *intf;
	struct usb_hub *hub;
	struct device *hub_dev;
	u16 hubstatus;
	u16 hubchange;
	u16 portstatus;
	u16 portchange;
	int i, ret;
	int connect_change;

	while (1) {

		/* Grab the first entry at the beginning of the list */
		spin_lock_irq(&hub_event_lock);

		tmp = hub_event_list.next;
		list_del_init(tmp);

		hub = list_entry(tmp, struct usb_hub, event_list);
		kref_get(&hub->kref);
		spin_unlock_irq(&hub_event_lock);

		hdev = hub->hdev;
		hub_dev = hub->intfdev;
		intf = to_usb_interface(hub_dev);

		/* Lock the device, then check to see if we were
		 * disconnected while waiting for the lock to succeed. */
		usb_lock_device(hdev);

		/* Autoresume */
		ret = usb_autopm_get_interface(intf);

		/* deal with port status changes */
		for (i = 1; i <= hub->descriptor->bNbrPorts; i++) {
			if (test_bit(i, hub->busy_bits))
				continue;
			
			connect_change = test_bit(i, hub->change_bits);
			/* 第i位為0返回0 否則返回1,如果埠發生變化,返回1 */
			if (!test_and_clear_bit(i, hub->event_bits) &&
					!connect_change)
				continue;
			/* 程式執行到這,說明第i個埠發生了變化 */
			ret = hub_port_status(hub, i, &portstatus, &portchange);

			if (portchange & USB_PORT_STAT_C_CONNECTION) {
				clear_port_feature(hdev, i, USB_PORT_FEAT_C_CONNECTION);
				connect_change = 1;
			}

			if (portchange & USB_PORT_STAT_C_ENABLE) {
				...
			}

			if (portchange & USB_PORT_STAT_C_SUSPEND) {
				...
			}
			
			if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
				...
			}

			if (portchange & USB_PORT_STAT_C_RESET) {
				...
			}

			if (connect_change)
				hub_port_connect_change(hub, i, portstatus, portchange);
		} /* end for i */
		...
}
static void hub_port_connect_change(struct usb_hub *hub, int port1,
					u16 portstatus, u16 portchange)
{
	struct usb_device *hdev = hub->hdev;
	struct device *hub_dev = hub->intfdev;
	struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
	unsigned wHubCharacteristics =
			le16_to_cpu(hub->descriptor->wHubCharacteristics);
	struct usb_device *udev;
	int status, i;

	for (i = 0; i < SET_CONFIG_TRIES; i++) {
		
		/* 分配一個 usb_device */
		udev = usb_alloc_dev(hdev, hdev->bus, port1);
		
		/* 設定它的狀態為 加電的 */
		usb_set_device_state(udev, USB_STATE_POWERED);
 		udev->bus_mA = hub->mA_per_port;
		udev->level = hdev->level + 1;
		udev->wusb = hub_is_wusb(hub);
		udev->speed = USB_SPEED_UNKNOWN;
		
		/* 分配一個地址 devnum = find_next_zero_bit(bus->devmap.devicemap, 128, bus->devnum_next); */
		choose_address(udev);
		
		/* 復位 獲取描述符 */
		status = hub_port_init(hub, udev, port1, i);

		status = 0;

		/* Run it through the hoops (find a driver, etc) */
		if (!status) {
			status = usb_new_device(udev);
		}

		status = hub_power_remaining(hub);

		return;
}
static int hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
		int retry_counter)
{
	static DEFINE_MUTEX(usb_address0_mutex);

	struct usb_device	*hdev = hub->hdev;
	struct usb_hcd		*hcd = bus_to_hcd(hdev->bus);
	int			i, j, retval;
	unsigned		delay = HUB_SHORT_RESET_TIME;
	enum usb_device_speed	oldspeed = udev->speed;
	char 			*speed, *type;
	int			devnum = udev->devnum;

	mutex_lock(&usb_address0_mutex);
	
	retval = hub_port_reset(hub, port1, udev, delay);
		
	oldspeed = udev->speed;
	
	/* 根據傳輸速度設定端點0的最大包大小 */
	switch (udev->speed) {
	case USB_SPEED_SUPER:
	case USB_SPEED_VARIABLE:	/* fixed at 512 */
		udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
		break;
	case USB_SPEED_HIGH:		/* fixed at 64 */
		udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
		break;
	case USB_SPEED_FULL:		/* 8, 16, 32, or 64 */
		udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
		break;
	case USB_SPEED_LOW:		/* fixed at 8 */
		udev->ep0.desc.wMaxPacketSize = cpu_to_le16(8);
		break;
	default:
		goto fail;
	}
 
	type = "";
	switch (udev->speed) {
	case USB_SPEED_LOW:	speed = "low";	break;
	case USB_SPEED_FULL:	speed = "full";	break;
	case USB_SPEED_HIGH:	speed = "high";	break;
	case USB_SPEED_SUPER:
				speed = "super";
				break;
	case USB_SPEED_VARIABLE:
				speed = "variable";
				type = "Wireless ";
				break;
	default: 		speed = "?";	break;
	}

	for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {

		if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) {
			...
		}

		if (udev->wusb == 0) {
			for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
				
				/* 將分配的地址告訴裝置 ,並設定裝置狀態為 USB_STATE_ADDRESS */
				retval = hub_set_address(udev, devnum);

				msleep(200);
			}

			if (udev->speed == USB_SPEED_SUPER) {
				devnum = udev->devnum;
			}

			msleep(10);
			if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3))
				break;
  		}
		/* 不知道一次能獲取多少,但至少能獲取8 */
		retval = usb_get_device_descriptor(udev, 8);
		if (retval < 8) {
			...
		} else {
			retval = 0;
			break;
		}
	}

	if (udev->descriptor.bMaxPacketSize0 == 0xff ||
			udev->speed == USB_SPEED_SUPER)
		i = 512;
	else
		i = udev->descriptor.bMaxPacketSize0;
	if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) {

		udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i);
		usb_ep0_reinit(udev);
	}
	/* 重新獲取全部描述符 */
	retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);

	retval = 0;

	mutex_unlock(&usb_address0_mutex);
	return retval;
}
    在 Hub_event 中,會呼叫 對於狀態變化的埠呼叫 hub_port_status 來檢測Hub埠的具體狀態,然後呼叫 hub_port_connect_change 

    hub_port_connect_change
        udev = usb_alloc_dev(hdev, hdev->bus, port1);
            dev->dev.bus = &usb_bus_type;
        choose_address(udev); // 給新裝置分配編號(地址)
        hub_port_init   // usb 1-1: new full speed USB device using s3c2410-ohci and address 3
            hub_set_address  // 把編號(地址)告訴USB裝置
            usb_get_device_descriptor(udev, 8); // 獲取裝置描述符
            retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);
            usb_new_device(udev)   
err = usb_get_configuration(udev); // 把所有的描述符都讀出來,並解析
usb_parse_configuration
                device_add  // 把device放入usb_bus_type的dev連結串列, 
                    // 從usb_bus_type的driver連結串列裡取出usb_driver,
                    // 把usb_interface和usb_driver的id_table比較
                    // 如果能匹配,呼叫usb_driver的probe

    顯然,從 usb_alloc_dev 開始,重複瞭如同根 Hub 作為一個 device 註冊進核心時的流程。如此迴圈下去,就能列舉註冊所有的 usb 裝置。