static int hub_configure(struct usb_hub *hub,
struct usb_endpoint_descriptor *endpoint)
{
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;
//分配集线器的缓存
hub->buffer = usb_buffer_alloc(hdev, sizeof(*hub->buffer), GFP_KERNEL,&hub->buffer_dma);
//缓存空间分配失败则返回出错
if (!hub->buffer)
{
message = "can't allocate hub irq buffer";
ret = -ENOMEM;
goto fail;
}
//分配状态报告结构的空间
hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL);
//分配失败则返回
if (!hub->status)
{
message = "can't kmalloc hub status buffer";
ret = -ENOMEM;
goto fail;
}
mutex_init(&hub->status_mutex);
//分配集线器描述符空间
hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
//分配失败则返回错误
if (!hub->descriptor)
{
message = "can't kmalloc 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.
*/
//取得集线器描述符
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;
}
hdev->maxchild = hub->descriptor->bNbrPorts;
dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild,(hdev->maxchild == 1) ? "" : "s");
wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
//检测是否为复合设备
if (wHubCharacteristics & HUB_CHAR_COMPOUND)
{
int i;
char portstr [USB_MAXCHILDREN + 1];
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");
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;
}
spin_lock_init (&hub->tt.lock);
INIT_LIST_HEAD (&hub->tt.clear_list);
INIT_WORK (&hub->tt.kevent, hub_tt_kevent);
switch (hdev->descriptor.bDeviceProtocol)
{
case 0:
break;
case 1:
dev_dbg(hub_dev, "Single TT\n");
hub->tt.hub = hdev;
break;
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;
default:
dev_dbg(hub_dev, "Unrecognized hub protocol %d\n",
hdev->descriptor.bDeviceProtocol);
break;
}
/* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */
switch (wHubCharacteristics & HUB_CHAR_TTTT)
{
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).
*/
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);
//检测该集线器是否为根集线器
if (hdev == hdev->bus->root_hub)
{
if (hdev->bus_mA == 0 || hdev->bus_mA >= 500)
hub->mA_per_port = 500;
else
{
hub->mA_per_port = hdev->bus_mA;
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)
{
int remaining = hdev->bus_mA - hub->descriptor->bHubContrCurrent;
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 */
}
}
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);
//取得集线器状态及改变
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. */
//设置管道
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);
//分配失败则返回错误
if (!hub->urb)
{
message = "couldn't allocate interrupt urb";
ret = -ENOMEM;
goto fail;
}
//填充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;
hub_power_on(hub);
hub_activate(hub);
return 0;
fail:
dev_err (hub_dev, "config failed, %s (err %d)\n",
message, ret);
/* hub_disconnect() frees urb and descriptor */
return ret;
}
|