📄 hub.c
字号:
} else return -EOPNOTSUPP; if (status == 0) { /* TRSMRCY = 10 msec */ msleep(10); } } hub_activate(hub); /* REVISIT: this recursion probably shouldn't exist. Remove * this code sometime, after retesting with different root and * external hubs. */#ifdef CONFIG_USB_SUSPEND { unsigned port1; for (port1 = 1; port1 <= hdev->maxchild; port1++) { struct usb_device *udev; u16 portstat, portchange; udev = hdev->children [port1-1]; status = hub_port_status(hub, port1, &portstat, &portchange); if (status == 0) { if (portchange & USB_PORT_STAT_C_SUSPEND) { clear_port_feature(hdev, port1, USB_PORT_FEAT_C_SUSPEND); portchange &= ~USB_PORT_STAT_C_SUSPEND; } /* let khubd handle disconnects etc */ if (portchange) continue; } if (!udev || status < 0) continue; down (&udev->serialize); if (portstat & USB_PORT_STAT_SUSPEND) status = hub_port_resume(hub, port1, udev); else { status = finish_device_resume(udev); if (status < 0) { dev_dbg(&intf->dev, "resume port %d --> %d\n", port1, status); hub_port_logical_disconnect(hub, port1); } } up(&udev->serialize); } }#endif return 0;}void usb_suspend_root_hub(struct usb_device *hdev){ struct usb_hub *hub = hdev_to_hub(hdev); /* This also makes any led blinker stop retriggering. We're called * from irq, so the blinker might still be scheduled. Caller promises * that the root hub status URB will be canceled. */ __hub_quiesce(hub); mark_quiesced(to_usb_interface(hub->intfdev));}void usb_resume_root_hub(struct usb_device *hdev){ struct usb_hub *hub = hdev_to_hub(hdev); hub->resume_root_hub = 1; kick_khubd(hub);}/* USB 2.0 spec, 7.1.7.3 / fig 7-29: * * Between connect detection and reset signaling there must be a delay * of 100ms at least for debounce and power-settling. The corresponding * timer shall restart whenever the downstream port detects a disconnect. * * Apparently there are some bluetooth and irda-dongles and a number of * low-speed devices for which this debounce period may last over a second. * Not covered by the spec - but easy to deal with. * * This implementation uses a 1500ms total debounce timeout; if the * connection isn't stable by then it returns -ETIMEDOUT. It checks * every 25ms for transient disconnects. When the port status has been * unchanged for 100ms it returns the port status. */#define HUB_DEBOUNCE_TIMEOUT 1500#define HUB_DEBOUNCE_STEP 25#define HUB_DEBOUNCE_STABLE 100static int hub_port_debounce(struct usb_hub *hub, int port1){ int ret; int total_time, stable_time = 0; u16 portchange, portstatus; unsigned connection = 0xffff; for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) { ret = hub_port_status(hub, port1, &portstatus, &portchange); if (ret < 0) return ret; if (!(portchange & USB_PORT_STAT_C_CONNECTION) && (portstatus & USB_PORT_STAT_CONNECTION) == connection) { stable_time += HUB_DEBOUNCE_STEP; if (stable_time >= HUB_DEBOUNCE_STABLE) break; } else { stable_time = 0; connection = portstatus & USB_PORT_STAT_CONNECTION; } if (portchange & USB_PORT_STAT_C_CONNECTION) { clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_CONNECTION); } if (total_time >= HUB_DEBOUNCE_TIMEOUT) break; msleep(HUB_DEBOUNCE_STEP); } dev_dbg (hub->intfdev, "debounce: port %d: total %dms stable %dms status 0x%x\n", port1, total_time, stable_time, portstatus); if (stable_time < HUB_DEBOUNCE_STABLE) return -ETIMEDOUT; return portstatus;}static void ep0_reinit(struct usb_device *udev){ usb_disable_endpoint(udev, 0 + USB_DIR_IN); usb_disable_endpoint(udev, 0 + USB_DIR_OUT); udev->ep_in[0] = udev->ep_out[0] = &udev->ep0;}#define usb_sndaddr0pipe() (PIPE_CONTROL << 30)#define usb_rcvaddr0pipe() ((PIPE_CONTROL << 30) | USB_DIR_IN)static int hub_set_address(struct usb_device *udev){ int retval; if (udev->devnum == 0) return -EINVAL; if (udev->state == USB_STATE_ADDRESS) return 0; if (udev->state != USB_STATE_DEFAULT) return -EINVAL; retval = usb_control_msg(udev, usb_sndaddr0pipe(), USB_REQ_SET_ADDRESS, 0, udev->devnum, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); if (retval == 0) { usb_set_device_state(udev, USB_STATE_ADDRESS); ep0_reinit(udev); } return retval;}/* Reset device, (re)assign address, get device descriptor. * Device connection must be stable, no more debouncing needed. * Returns device in USB_STATE_ADDRESS, except on error. * * If this is called for an already-existing device (as part of * usb_reset_device), the caller must own the device lock. For a * newly detected device that is not accessible through any global * pointers, it's not necessary to lock the device. */static inthub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, int retry_counter){ static DECLARE_MUTEX(usb_address0_sem); struct usb_device *hdev = hub->hdev; int i, j, retval; unsigned delay = HUB_SHORT_RESET_TIME; enum usb_device_speed oldspeed = udev->speed; /* root hub ports have a slightly longer reset period * (from USB 2.0 spec, section 7.1.7.5) */ if (!hdev->parent) { delay = HUB_ROOT_RESET_TIME; if (port1 == hdev->bus->otg_port) hdev->bus->b_hnp_enable = 0; } /* Some low speed devices have problems with the quick delay, so */ /* be a bit pessimistic with those devices. RHbug #23670 */ if (oldspeed == USB_SPEED_LOW) delay = HUB_LONG_RESET_TIME; down(&usb_address0_sem); /* Reset the device; full speed may morph to high speed */ retval = hub_port_reset(hub, port1, udev, delay); if (retval < 0) /* error or disconnect */ goto fail; /* success, speed is known */ retval = -ENODEV; if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) { dev_dbg(&udev->dev, "device reset changed speed!\n"); goto fail; } oldspeed = udev->speed; /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ... * it's fixed size except for full speed devices. */ switch (udev->speed) { case USB_SPEED_HIGH: /* fixed at 64 */ udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64); break; case USB_SPEED_FULL: /* 8, 16, 32, or 64 */ /* to determine the ep0 maxpacket size, try to read * the device descriptor to get bMaxPacketSize0 and * then correct our initial guess. */ udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64); break; case USB_SPEED_LOW: /* fixed at 8 */ udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(8); break; default: goto fail; } dev_info (&udev->dev, "%s %s speed USB device using %s and address %d\n", (udev->config) ? "reset" : "new", ({ char *speed; switch (udev->speed) { case USB_SPEED_LOW: speed = "low"; break; case USB_SPEED_FULL: speed = "full"; break; case USB_SPEED_HIGH: speed = "high"; break; default: speed = "?"; break; }; speed;}), udev->bus->controller->driver->name, udev->devnum); /* Set up TT records, if needed */ if (hdev->tt) { udev->tt = hdev->tt; udev->ttport = hdev->ttport; } else if (udev->speed != USB_SPEED_HIGH && hdev->speed == USB_SPEED_HIGH) { udev->tt = &hub->tt; udev->ttport = port1; } /* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way? * Because device hardware and firmware is sometimes buggy in * this area, and this is how Linux has done it for ages. * Change it cautiously. * * NOTE: If USE_NEW_SCHEME() is true we will start by issuing * a 64-byte GET_DESCRIPTOR request. This is what Windows does, * so it may help with some non-standards-compliant devices. * Otherwise we start with SET_ADDRESS and then try to read the * first 8 bytes of the device descriptor to get the ep0 maxpacket * value. */ for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) { if (USE_NEW_SCHEME(retry_counter)) { struct usb_device_descriptor *buf; int r = 0;#define GET_DESCRIPTOR_BUFSIZE 64 buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO); if (!buf) { retval = -ENOMEM; continue; } /* Use a short timeout the first time through, * so that recalcitrant full-speed devices with * 8- or 16-byte ep0-maxpackets won't slow things * down tremendously by NAKing the unexpectedly * early status stage. Also, retry on all errors; * some devices are flakey. */ for (j = 0; j < 3; ++j) { buf->bMaxPacketSize0 = 0; r = usb_control_msg(udev, usb_rcvaddr0pipe(), USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, USB_DT_DEVICE << 8, 0, buf, GET_DESCRIPTOR_BUFSIZE, (i ? USB_CTRL_GET_TIMEOUT : 1000)); switch (buf->bMaxPacketSize0) { case 8: case 16: case 32: case 64: if (buf->bDescriptorType == USB_DT_DEVICE) { r = 0; break; } /* FALL THROUGH */ default: if (r == 0) r = -EPROTO; break; } if (r == 0) break; } udev->descriptor.bMaxPacketSize0 = buf->bMaxPacketSize0; kfree(buf); retval = hub_port_reset(hub, port1, udev, delay); if (retval < 0) /* error or disconnect */ goto fail; if (oldspeed != udev->speed) { dev_dbg(&udev->dev, "device reset changed speed!\n"); retval = -ENODEV; goto fail; } if (r) { dev_err(&udev->dev, "device descriptor " "read/%s, error %d\n", "64", r); retval = -EMSGSIZE; continue; }#undef GET_DESCRIPTOR_BUFSIZE } for (j = 0; j < SET_ADDRESS_TRIES; ++j) { retval = hub_set_address(udev); if (retval >= 0) break; msleep(200); } if (retval < 0) { dev_err(&udev->dev, "device not accepting address %d, error %d\n", udev->devnum, retval); goto fail; } /* cope with hardware quirkiness: * - let SET_ADDRESS settle, some device hardware wants it * - read ep0 maxpacket even for high and low speed, */ msleep(10); if (USE_NEW_SCHEME(retry_counter)) break; retval = usb_get_device_descriptor(udev, 8); if (retval < 8) { dev_err(&udev->dev, "device descriptor " "read/%s, error %d\n", "8", retval); if (retval >= 0) retval = -EMSGSIZE; } else { retval = 0; break; } } if (retval) goto fail; i = udev->descriptor.bMaxPacketSize0; if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) { if (udev->speed != USB_SPEED_FULL || !(i == 8 || i == 16 || i == 32 || i == 64)) { dev_err(&udev->dev, "ep0 maxpacket = %d\n", i); retval = -EMSGSIZE; goto fail; } dev_dbg(&udev->dev, "ep0 maxpacket = %d\n", i); udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i); ep0_reinit(udev); } retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE); if (retval < (signed)sizeof(udev->descriptor)) { dev_err(&udev->dev, "device descriptor read/%s, error %d\n", "all", retval); if (retval >= 0) retval = -ENOMSG; goto fail; } retval = 0;fail: if (retval) hub_port_disable(hub, port1, 0); up(&usb_address0_sem); return retval;}static voidcheck_highspeed (struct usb_hub *hub, struct usb_device *udev, int port1){ struct usb_qualifier_descriptor *qual; int status; qual = kmalloc (sizeof *qual, SLAB_KERNEL); if (qual == NULL) return; status = usb_get_descriptor (udev, USB_DT_DEVICE_QUALIFIER, 0, qual, sizeof *qual); if (status == sizeof *qual) { dev_info(&udev->dev, "not running at top speed; " "connect to a high speed hub\n"); /* hub LEDs are probably harder to miss than syslog */ if (hub->has_indicators) { hub->indicator[port1-1] = INDICATOR_GREEN_BLINK; schedule_work (&hub->leds); } } kfree(qual);}static unsignedhub_power_remaining (struct usb_hub *hub){ struct usb_device *hdev = hub->hdev; int remaining; unsigned i; remaining = hub->power_budget; if (!remaining) /* self-powered */ return 0; for (i = 0; i < hdev->maxchild; i++) { struct usb_device *udev = hdev->children[i]; int delta, ceiling; if (!udev) continue; /* 100mA per-port ceiling, or 8mA for OTG ports */ if (i != (udev->bus->otg_port - 1) || hdev->parent) ceiling = 50; else ceiling = 4; if (udev->actconfig) delta = udev->actconfig->desc.bMaxPower; else delta = ceiling; // dev_dbg(&udev->dev, "budgeted %dmA\n", 2 * delta); if (delta > ceiling) dev_warn(&udev->dev, "%dmA over %dmA budget!\n", 2 * (delta - ceiling), 2 * ceiling); remaining -= delta; } if (remaining < 0) { dev_warn(hub->intfdev, "%dmA over power budget!\n", -2 * remaining); remaining = 0; } return remaining;}/* Handle physical or logical connection change events. * This routine is called when: * a port connection-change occurs; * a port enable-change occurs (often caused by EMI); * usb_reset_device() encounters changed descriptors (as from * a firmware download) * caller already locked the hub */static void hub_port_connect_change(struct
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -