root hub接口device和接口driver的匹配(七)

本文是基於mini2440開發板Linux版本號是linux-2.6.32.2的學習筆記

前面root hub 接口device和接口driver都是用的總線usb_bus_type。但是這個時候device的類型是usb_if_device_type,不再是usb_device_type,也就是usb接口設備,而不是usb設備。
那麼註冊設備的時候,會自動遍歷總線上的所有驅動,看看哪個驅動能匹配上;
註冊驅動的時候,也會遍歷總線上的所有設備,看看哪個設備能匹配上;

usb_bus_type的定義如下:

struct bus_type usb_bus_type = {
	.name =		"usb",
	.match =	usb_device_match,
	.uevent =	usb_uevent,
};

usb_bus_type的匹配函數是usb_device_match,usb_device_match函數的定義如下:

static int usb_device_match(struct device *dev, struct device_driver *drv)
{
	/* devices and interfaces are handled separately */
	//如果是USB設備
	if (is_usb_device(dev)) {

		/* interface drivers never match devices */
		//是匹配USB設備的驅動,USB接口的驅動不能匹配
		if (!is_usb_device_driver(drv))
			return 0;

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

	} else if (is_usb_interface(dev)) { //如果是USB接口
		struct usb_interface *intf;
		struct usb_driver *usb_drv;
		const struct usb_device_id *id;

		/* device drivers never match interfaces */
		//usb接口在註冊driver時將for_devices設置爲0,for_devices =1,表示設備驅動,for_devices = 0,表示接口驅動
		if (is_usb_device_driver(drv))
			return 0;

		intf = to_usb_interface(dev);
		usb_drv = to_usb_driver(drv);
		//匹配id table
		id = usb_match_id(intf, usb_drv->id_table);
		if (id)
			return 1;
		//匹配動態id table
		id = usb_match_dynamic_id(intf, usb_drv);
		if (id)
			return 1;
	}

	return 0;
}

前面說過,它的匹配規則是:
usb 設備device和usb 設備driver任意匹配;
usb device和usb 接口driver不能匹配;
usb 接口device和usb設備driver不能匹配;
usb接口device和usb接口driver根據driver的id_table進行匹配;
這裏是root hub 接口device和接口driver的匹配,所以要根據dev獲得的usb_interface接口和driver的id_table來進行匹配。調用函數usb_match_id

const struct usb_device_id *usb_match_id(struct usb_interface *interface, const struct usb_device_id *id)
{
	/* proc_connectinfo in devio.c may call us with id == NULL. */
	if (id == NULL)
		return NULL;
        
	for (; id->idVendor || id->idProduct || id->bDeviceClass ||
	       id->bInterfaceClass || id->driver_info; id++) {
		if (usb_match_one_id(interface, id))
			return id;
	}

	return NULL;
}

可以根據廠家ID,DeviceClass,InterfaceClass,driver_info等規則匹配。過程就是把設備描述符的相關項或者接口描述符的相關項和driver的id_table的相關項進行比對。

那麼接口driver的id_table是多少呢?在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,
};
static struct usb_device_id hub_id_table [] = {
    { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,
      .bDeviceClass = USB_CLASS_HUB},
    { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
      .bInterfaceClass = USB_CLASS_HUB},
    { }						/* Terminating entry */
};

因爲我們這裏有定義USB_DEVICE_ID_MATCH_DEV_CLASS和USB_DEVICE_ID_MATCH_INT_CLASS,所以我們要匹配它的bDeviceClass和bInterfaceClass。
USB_CLASS_HUB = 9。

那麼root hub 接口device的bDeviceClass和bInterfaceClass是多少呢?

static const u8 usb11_rh_dev_descriptor [18] = {
	0x12,       /*  __u8  bLength; */
	0x01,       /*  __u8  bDescriptorType; Device */
	0x10, 0x01, /*  __le16 bcdUSB; v1.1 */

	0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */
	0x00,	    /*  __u8  bDeviceSubClass; */
	0x00,       /*  __u8  bDeviceProtocol; [ low/full speeds only ] */
	0x40,       /*  __u8  bMaxPacketSize0; 64 Bytes */

	0x6b, 0x1d, /*  __le16 idVendor; Linux Foundation */
	0x01, 0x00, /*  __le16 idProduct; device 0x0001 */
	KERNEL_VER, KERNEL_REL, /*  __le16 bcdDevice */

	0x03,       /*  __u8  iManufacturer; */
	0x02,       /*  __u8  iProduct; */
	0x01,       /*  __u8  iSerialNumber; */
	0x01        /*  __u8  bNumConfigurations; */
};

static const u8 ss_rh_config_descriptor[] = {
	/* one configuration */
	0x09,       /*  __u8  bLength; */
	0x02,       /*  __u8  bDescriptorType; Configuration */
	0x19, 0x00, /*  __le16 wTotalLength; FIXME */
	0x01,       /*  __u8  bNumInterfaces; (1) */
	0x01,       /*  __u8  bConfigurationValue; */
	0x00,       /*  __u8  iConfiguration; */
	0xc0,       /*  __u8  bmAttributes;
				 Bit 7: must be set,
				     6: Self-powered,
				     5: Remote wakeup,
				     4..0: resvd */
	0x00,       /*  __u8  MaxPower; */

	/* one interface */
	0x09,       /*  __u8  if_bLength; */
	0x04,       /*  __u8  if_bDescriptorType; Interface */
	0x00,       /*  __u8  if_bInterfaceNumber; */
	0x00,       /*  __u8  if_bAlternateSetting; */
	0x01,       /*  __u8  if_bNumEndpoints; */
	0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
	0x00,       /*  __u8  if_bInterfaceSubClass; */
	0x00,       /*  __u8  if_bInterfaceProtocol; */
	0x00,       /*  __u8  if_iInterface; */

	/* one endpoint (status change endpoint) */
	0x07,       /*  __u8  ep_bLength; */
	0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
	0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
	0x03,       /*  __u8  ep_bmAttributes; Interrupt */
		    /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8)
		     * see hub.c:hub_configure() for details. */
	(USB_MAXCHILDREN + 1 + 7) / 8, 0x00,
	0x0c        /*  __u8  ep_bInterval; (256ms -- usb 2.0 spec) */
	/*
	 * All 3.0 hubs should have an endpoint companion descriptor,
	 * but we're ignoring that for now.  FIXME?
	 */
};

可以看到,DeviceClass和InterfaceClass都是9,所以是可以匹配上的。

root hub接口device和接口driver的匹配上後,最終調用的probe函數是hub_probe函數。
現在看一下hub_probe函數。

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);

	if (hdev->level == MAX_TOPO_LEVEL) {
		dev_err(&intf->dev,
			"Unsupported bus topology: hub nested too deep\n");
		return -E2BIG;
	}

#ifdef	CONFIG_USB_OTG_BLACKLIST_HUB
	if (hdev->parent) {
		dev_warn(&intf->dev, "ignoring external hub\n");
		return -ENODEV;
	}
#endif

	/* Some hubs have a subclass of 1, which AFAICT according to the */
	/*  specs is not defined, but it works */
	//hub的子類一般就是0,但是有的廠商設置的是1
	if ((desc->desc.bInterfaceSubClass != 0) &&
	    (desc->desc.bInterfaceSubClass != 1)) {
descriptor_error:
		dev_err (&intf->dev, "bad descriptor, ignoring hub\n");
		return -EIO;
	}

	/* Multiple endpoints? What kind of mutant ninja-hub is this? */
	//hub就只有一個endpoint,中斷endpoint,因爲hub的傳輸是中斷傳輸,不包含那個大家都有的控制端點
	if (desc->desc.bNumEndpoints != 1)
		goto descriptor_error;

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

	/* If it's not an interrupt in endpoint, we'd better punt! */
	//判斷這個端點是不是中斷端點,端點0必須是中斷控制方式的端點
	if (!usb_endpoint_is_int_in(endpoint))
		goto descriptor_error;

	/* We found a hub */
	dev_info (&intf->dev, "USB hub found\n");

	hub = kzalloc(sizeof(*hub), GFP_KERNEL);
	if (!hub) {
		dev_dbg (&intf->dev, "couldn't kmalloc hub struct\n");
		return -ENOMEM;
	}

	kref_init(&hub->kref);
	INIT_LIST_HEAD(&hub->event_list);
	hub->intfdev = &intf->dev;
	hub->hdev = hdev;
	INIT_DELAYED_WORK(&hub->leds, led_work);
	INIT_DELAYED_WORK(&hub->init_work, NULL);
	usb_get_intf(intf);
	//讓intf和hub關聯起
	usb_set_intfdata (intf, hub);
	intf->needs_remote_wakeup = 1;
	//hub是高速設備
	if (hdev->speed == USB_SPEED_HIGH)
		highspeed_hubs++;
		
	//配置hub
	if (hub_configure(hub, endpoint) >= 0)
		return 0;

	//如果hub配置失敗,移除hub
	hub_disconnect (intf);
	return -ENODEV;
}

主要是一些參數檢查,然後最重要的就是調用了hub_configure函數。

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";
	
	//申請一個buffer存放urb傳輸數據
	hub->buffer = usb_buffer_alloc(hdev, sizeof(*hub->buffer), GFP_KERNEL,
			&hub->buffer_dma);
	if (!hub->buffer) {
		ret = -ENOMEM;
		goto fail;
	}

	hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL);
	if (!hub->status) {
		ret = -ENOMEM;
		goto fail;
	}
	mutex_init(&hub->status_mutex);
	//申請hub 描述符的內存,大小爲15個字節
	hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
	if (!hub->descriptor) {
		ret = -ENOMEM;
		goto fail;
	}

	/* Request the entire hub descriptor.
	 * hub->descriptor can handle USB_MAXCHILDREN ports,
	 * but the hub can/will return fewer bytes here.
	 */
	 //獲取hub描述符,描述符的長度至少爲9個字節
	ret = get_hub_descriptor(hdev, hub->descriptor,
			sizeof(*hub->descriptor));
	if (ret < 0) {
		message = "can't read hub descriptor";
		goto fail;
	} else if (hub->descriptor->bNbrPorts > USB_MAXCHILDREN) {
		message = "hub has too many ports!";
		ret = -ENODEV;
		goto fail;
	}
	//保存hub所支持的端口數量
	hdev->maxchild = hub->descriptor->bNbrPorts;
	dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild,
		(hdev->maxchild == 1) ? "" : "s");

	hub->port_owners = kzalloc(hdev->maxchild * sizeof(void *), GFP_KERNEL);
	if (!hub->port_owners) {
		ret = -ENOMEM;
		goto fail;
	}
	//用一個臨時變量wHubCharacteristics來代替描述符裏的那個wHubCharacteristics
	wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
	//判斷是不是複合設備
	if (wHubCharacteristics & HUB_CHAR_COMPOUND) {
		int	i;
		char	portstr [USB_MAXCHILDREN + 1];
		//如果是複合設備,就用一個數組portstr[]來記錄每一個端口的設備是否可以被移除
		for (i = 0; i < hdev->maxchild; i++)
			portstr[i] = hub->descriptor->DeviceRemovable
				    [((i + 1) / 8)] & (1 << ((i + 1) % 8))
				? 'F' : 'R';
		portstr[hdev->maxchild] = 0;
		dev_dbg(hub_dev, "compound device; port removable status: %s\n", portstr);
	} else
		dev_dbg(hub_dev, "standalone hub\n");
	//表徵電源切換的方式
	//ganged power switching指的是所有port一次性上電
	//individual port power switching port單獨上電
	switch (wHubCharacteristics & HUB_CHAR_LPSM) {
		case 0x00:
			dev_dbg(hub_dev, "ganged power switching\n");
			break;
		case 0x01:
			dev_dbg(hub_dev, "individual port power switching\n");
			break;
		case 0x02:
		case 0x03:
			dev_dbg(hub_dev, "no power switching (usb 1.0)\n");
			break;
	}
	//表徵過流保護模式
	switch (wHubCharacteristics & HUB_CHAR_OCPM) {
		case 0x00:
			dev_dbg(hub_dev, "global over-current protection\n");
			break;
		case 0x08:
			dev_dbg(hub_dev, "individual port over-current protection\n");
			break;
		case 0x10:
		case 0x18:
			dev_dbg(hub_dev, "no over-current protection\n");
                        break;
	}
	//tt負責高速和低速/全速的數據轉換
	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) {
		//ull/low speed的hub的bDeviceProtocol是0,這種hub就沒有tt
		case 0:
			break;
		//Single TT:整個hub就是一個TT
		//對於high speed的hub,其bDeviceProtocol爲1表示是single tt的
		case 1:
			dev_dbg(hub_dev, "Single TT\n");
			hub->tt.hub = hdev;
			break;
		//TT per port:每個端口都配了一個TT		
		case 2:
			ret = usb_set_interface(hdev, 0, 1);
			if (ret == 0) {
				dev_dbg(hub_dev, "TT per port\n");
				hub->tt.multi = 1;
			} else
				dev_err(hub_dev, "Using single TT (err %d)\n",
					ret);
			hub->tt.hub = hdev;
			break;
		case 3:
			/* USB 3.0 hubs don't have a TT */
			break;
		default:
			dev_dbg(hub_dev, "Unrecognized hub protocol %d\n",
				hdev->descriptor.bDeviceProtocol);
			break;
	}
	//TT在處理兩個低速/全速的交易之間需要一點點時間來緩衝,這個最大的間隔就叫做TT think time
	/* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */
	switch (wHubCharacteristics & HUB_CHAR_TTTT) {
		//Full Speed,其速度是12Mbps,8 FS bit time就是8bits / 1200 0000 bits per second,即約等於666ns
		case HUB_TTTT_8_BITS:
			if (hdev->descriptor.bDeviceProtocol != 0) {
				hub->tt.think_time = 666;
				dev_dbg(hub_dev, "TT requires at most %d "
						"FS bit times (%d ns)\n",
					8, hub->tt.think_time);
			}
			break;
		case HUB_TTTT_16_BITS:
			hub->tt.think_time = 666 * 2;
			dev_dbg(hub_dev, "TT requires at most %d "
					"FS bit times (%d ns)\n",
				16, hub->tt.think_time);
			break;
		case HUB_TTTT_24_BITS:
			hub->tt.think_time = 666 * 3;
			dev_dbg(hub_dev, "TT requires at most %d "
					"FS bit times (%d ns)\n",
				24, hub->tt.think_time);
			break;
		case HUB_TTTT_32_BITS:
			hub->tt.think_time = 666 * 4;
			dev_dbg(hub_dev, "TT requires at most %d "
					"FS bit times (%d ns)\n",
				32, hub->tt.think_time);
			break;
	}

	/* probe() zeroes hub->indicator[] */
	//端口指示燈
	if (wHubCharacteristics & HUB_CHAR_PORTIND) {
		hub->has_indicators = 1;
		dev_dbg(hub_dev, "Port indicators are supported\n");
	}

	dev_dbg(hub_dev, "power on to power good time: %dms\n",
		hub->descriptor->bPwrOn2PwrGood * 2);

	/* power budgeting mostly matters with bus-powered hubs,
	 * and battery-powered root hubs (may provide just 8 mA).
	 */
	//一個控制傳輸,發送的是一個控制請求,GET_STATUS是USB的標準請求之一,獲得Device的狀態,保存在hubstatus裏面
	ret = usb_get_status(hdev, USB_RECIP_DEVICE, 0, &hubstatus);
	if (ret < 2) {
		message = "can't get hub status";
		goto fail;
	}
	le16_to_cpus(&hubstatus);
	//如果是root hub,給hub->mA_per_port賦值
	//計算機的usb端口可以提供500mA的電流
	if (hdev == hdev->bus->root_hub) {
		if (hdev->bus_mA == 0 || hdev->bus_mA >= 500)
			hub->mA_per_port = 500;
		//這個hub沒法提供達到500mA的電流,limited_power記錄限制了電流的情況
		else {
			hub->mA_per_port = hdev->bus_mA;
			hub->limited_power = 1;
		}
	//表徵這個hub是不是自己供電的,外接的hub也有兩種供電方式,自己供電或者請求總線供電
	//要總線供電的hub,於是limited_power也設置爲1
	} else if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
		dev_dbg(hub_dev, "hub controller current requirement: %dmA\n",
			hub->descriptor->bHubContrCurrent);
		hub->limited_power = 1;
		if (hdev->maxchild > 0) {
			//remaining來記錄剩下多少電流
			int remaining = hdev->bus_mA -
					hub->descriptor->bHubContrCurrent;
			//比如你這個hub有四個口,即maxchild爲4,那麼你最少要剩下400mA電流,
			//因爲如果某個端口電流小於100mA的話,設備是沒法正常工作的
			if (remaining < hdev->maxchild * 100)
				dev_warn(hub_dev,
					"insufficient power available "
					"to use all downstream ports\n");
			hub->mA_per_port = 100;		/* 7.2.1.1 */
		}
	//如果是自己供電的那種hub,直接設置爲500mA
	} else {	/* Self-powered external hub */
		/* FIXME: What about battery-powered external hubs that
		 * provide less current per port? */
		hub->mA_per_port = 500;
	}
	if (hub->mA_per_port < 500)
		dev_dbg(hub_dev, "%umA bus power budget for each child\n",
				hub->mA_per_port);

	/* 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);
		if (ret < 0) {
			message = "can't update HCD hub info";
			goto fail;
		}
	}
	//這個請求是hub自己定義的,最後狀態保存在status和change裏面
	ret = hub_hub_status(hub, &hubstatus, &hubchange);
	if (ret < 0) {
		message = "can't get hub status";
		goto fail;
	}

	/* local power status reports aren't always correct */
	if (hdev->actconfig->desc.bmAttributes & USB_CONFIG_ATT_SELFPOWER)
		dev_dbg(hub_dev, "local power source is %s\n",
			(hubstatus & HUB_STATUS_LOCAL_POWER)
			? "lost (inactive)" : "good");

	if ((wHubCharacteristics & HUB_CHAR_OCPM) == 0)
		dev_dbg(hub_dev, "%sover-current condition exists\n",
			(hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");

	/* set up the interrupt endpoint
	 * We use the EP's maxpacket size instead of (PORTS+1+7)/8
	 * bytes as USB2.0[11.12.3] says because some hubs are known
	 * to send more data (and thus cause overflow). For root hubs,
	 * maxpktsize is defined in hcd.c's fake endpoint descriptors
	 * to be big enough for at least USB_MAXCHILDREN ports. */
	//獲得連接host與這個端點的這條管道
	pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress);
	//獲得一個endpoint描述符裏面的wMaxPacketSize,賦給maxp
	maxp = usb_maxpacket(hdev, pipe, usb_pipeout(pipe));
	//前面爲hub->buffer申請了內存,這裏maxp如果大於這個size,就讓它等於hub->buffer的size
	if (maxp > sizeof(*hub->buffer))
		maxp = sizeof(*hub->buffer);
	//申請一個urb
	hub->urb = usb_alloc_urb(0, GFP_KERNEL);
	if (!hub->urb) {
		ret = -ENOMEM;
		goto fail;
	}
	//填充urb,urb完成了就調用hub_irq函數
	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 */
	//blinkenlights表示燈閃不閃
	if (hub->has_indicators && blinkenlights)
		hub->indicator [0] = INDICATOR_CYCLE;

	hub_activate(hub, HUB_INIT);
	return 0;

fail:
	dev_err (hub_dev, "config failed, %s (err %d)\n",
			message, ret);
	/* hub_disconnect() frees urb and descriptor */
	return ret;
}

什麼叫hub描述符?
對於hub來說,除了通常的usb設備有的那些設備描述符,接口描述符,端點描述符以外,hub spec自己也定義了一個描述符,這就叫hub描述符。

struct usb_hub_descriptor {
	__u8  bDescLength;                        //長度>=9,不定長
	__u8  bDescriptorType;                    //#define USB_DT_HUB			0x29
	__u8  bNbrPorts;                          //hub所支持的端口數量
	__le16 wHubCharacteristics;
	__u8  bPwrOn2PwrGood;
	__u8  bHubContrCurrent;                   //Hub控制器的最大電流需求
		/* add 1 bit for hub status change; round to bytes */
	__u8  DeviceRemovable[(USB_MAXCHILDREN + 1 + 7) / 8];   //用來判斷這個端口連接的設備是否是可以移除的,如果該bit爲0,則說明可以被移除
	__u8  PortPwrCtrlMask[(USB_MAXCHILDREN + 1 + 7) / 8];
} __attribute__ ((packed));
  • 用get_hub_descriptor函數,獲取hub描述符。
static int get_hub_descriptor(struct usb_device *hdev, void *data, int size)
{
	int i, ret;
	//requesttype = USB_DIR_IN | USB_RT_HUB
	//bit7 = USB_DIR_IN,表示Device-to-host
	//bit5~6 = 01,表示class特定的
	//bit0~4 = USB_RECIP_DEVICE,表示接收者是設備
	//wvalue = USB_DT_HUB << 8, GET_DESCRIPTOR這個請求的wValue就該是Descriptor Type和Descriptor Index,
	//wValue作爲一個word,有16位,所以高8位放Descriptor Type,而低8位放Descriptor Index
	//hub descriptor的descriptor index必須爲0
	for (i = 0; i < 3; i++) {
		ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
			USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
			USB_DT_HUB << 8, 0, data, size,
			USB_CTRL_GET_TIMEOUT);
		if (ret >= (USB_DT_HUB_NONVAR_SIZE + 2))
			return ret;
	}
	return -EINVAL;
}

hub spec規定, bmRequestType必須是10100000B,因爲D7爲方向位,這裏是IN,所以D7 = 1;
D[6:5]這兩位表示Request的類型,hub是Class特定的,所以D[6:5] = 01;
D[4:0]表示接受者,可以是設備,可以是接口,可以是端點,這裏是設備,所以D[4:0] = 0
hub spec規定GET_DESCRIPTOR這個請求的wValue就該是Descriptor Type和Descriptor Index,高8位放Descriptor Type,而低8位放Descriptor Index。hub descriptor的descriptor index必須爲0。所以,wvalue = USB_DT_HUB << 8。

  • 保存hub支持的端口數量,最大需求電流,電源切換方式
  • 設置hub的高速切換方式
  • 獲取hub設備狀態,設置端口的供電電流
  • 申請中斷傳輸urb,初始化
  • 調用hub_activate(hub, HUB_INIT),調用hub_power_on,提交urb

文章參考:https://blog.csdn.net/fudan_abc/article/category/325189

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章