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

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