📄 hub.c
字号:
udev->state != USB_STATE_SUSPENDED ) { if (!hdev->auto_pm) dev_dbg(&intf->dev, "port %d nyet suspended\n", port1); return -EBUSY; } } dev_dbg(&intf->dev, "%s\n", __FUNCTION__); /* stop khubd and related activity */ hub_quiesce(hub); /* "global suspend" of the downstream HC-to-USB interface */ if (!hdev->parent) { status = hcd_bus_suspend(hdev->bus); if (status != 0) { dev_dbg(&hdev->dev, "'global' suspend %d\n", status); hub_activate(hub); } } return status;}static int hub_resume(struct usb_interface *intf){ struct usb_hub *hub = usb_get_intfdata (intf); struct usb_device *hdev = hub->hdev; int status; dev_dbg(&intf->dev, "%s\n", __FUNCTION__); /* "global resume" of the downstream HC-to-USB interface */ if (!hdev->parent) { struct usb_bus *bus = hdev->bus; if (bus) { status = hcd_bus_resume (bus); if (status) { dev_dbg(&intf->dev, "'global' resume %d\n", status); return status; } } else return -EOPNOTSUPP; if (status == 0) { /* TRSMRCY = 10 msec */ msleep(10); } } /* tell khubd to look for changes on this hub */ hub_activate(hub); return 0;}/* 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 DEFINE_MUTEX(usb_address0_mutex); struct usb_device *hdev = hub->hdev; int i, j, retval; unsigned delay = HUB_SHORT_RESET_TIME; enum usb_device_speed oldspeed = udev->speed; char *speed, *type; /* 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; mutex_lock(&usb_address0_mutex); /* 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. * For Wireless USB devices, ep0 max packet is always 512 (tho * reported as 0xff in the device descriptor). WUSB1.0[4.8.1]. */ switch (udev->speed) { case USB_SPEED_VARIABLE: /* fixed at 512 */ udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(512); break; 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; } 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_VARIABLE: speed = "variable"; type = "Wireless "; break; default: speed = "?"; break; } dev_info (&udev->dev, "%s %s speed %sUSB device using %s and address %d\n", (udev->config) ? "reset" : "new", speed, type, 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; } /* Retry on all errors; some devices are flakey. * 255 is for WUSB devices, we actually need to use * 512 (WUSB1.0[4.8.1]). */ 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, USB_CTRL_GET_TIMEOUT); switch (buf->bMaxPacketSize0) { case 8: case 16: case 32: case 64: case 255: 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 == 0xff? 512 : 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); mutex_unlock(&usb_address0_mutex); 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, GFP_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_delayed_work (&hub->leds, 0); } } kfree(qual);}static unsignedhub_power_remaining (struct usb_hub *hub){ struct usb_device *hdev = hub->hdev; int remaining; int port1; if (!hub->limited_power) return 0; remaining = hdev->bus_mA - hub->descriptor->bHubContrCurrent; for (port1 = 1; port1 <= hdev->maxchild; ++port1) { struct usb_device *udev = hdev->children[port1 - 1]; int delta; if (!udev) continue; /* Unconfigured devices may not use more than 100mA, * or 8mA for OTG ports */ if (udev->actconfig) delta = udev->actconfig->desc.bMaxPower * 2; else if (port1 != udev->bus->otg_port || hdev->parent) delta = 100; else delta = 8; if (delta > hub->mA_per_port) dev_warn(&udev->dev, "%dmA is over %umA budget " "for port %d!\n", delta, hub->mA_per_port, port1); remaining -= delta; } if (remaining < 0) { dev_warn(hub->intfdev, "%dmA over power budget!\n", - 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 */sta
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -