static int usb_hub_reset(struct usb_hub *hub) { struct usb_device *dev = hub->dev; int i; DBG_HOST_HUB("### >>> Enter hub.c file --> usb_hub_reset function \n"); /* Disconnect any attached devices */ for (i = 0; i < hub->descriptor->bNbrPorts; i++) { if (dev->children[i]) usb_disconnect(&dev->children[i]); } /* Attempt to reset the hub */ if (hub->urb) usb_unlink_urb(hub->urb); else return -1; if (usb_reset_device(dev)) return -1; hub->urb->dev = dev; if (usb_submit_urb(hub->urb)) return -1; usb_hub_power_on(hub); return 0; }
static int usb_hub_reset(struct usb_hub *hub) { struct usb_device *dev = hub->dev; int i; /* Disconnect any attached devices */ for (i = 0; i < hub->nports; i++) { if (dev->children[i]) usb_disconnect(&dev->children[i]); } /* Attempt to reset the hub */ if (hub->urb) usb_unlink_urb(hub->urb); else return -1; if (usb_reset_device(dev)) return -1; if (usb_submit_urb(hub->urb)) return -1; usb_hub_power_on(hub); return 0; }
static void usb_hub_events(void) { unsigned long flags; struct list_head *tmp; struct usb_device *dev; struct usb_hub *hub; struct usb_hub_status hubsts; u16 hubstatus; u16 hubchange; u16 portstatus; u16 portchange; int i, ret; /* * We restart the list everytime to avoid a deadlock with * deleting hubs downstream from this one. This should be * safe since we delete the hub from the event list. * Not the most efficient, but avoids deadlocks. */ DBG_HOST_HUB("### >>> Enter hub.c file --> usb_hub_events function \n"); while (1) { spin_lock_irqsave(&hub_event_lock, flags); if (list_empty(&hub_event_list)) break; /* Grab the next entry from the beginning of the list */ tmp = hub_event_list.next; hub = list_entry(tmp, struct usb_hub, event_list); dev = hub->dev; list_del(tmp); INIT_LIST_HEAD(tmp); down(&hub->khubd_sem); /* never blocks, we were on list */ spin_unlock_irqrestore(&hub_event_lock, flags); if (hub->error) { dbg("resetting hub %d for error %d", dev->devnum, hub->error); if (usb_hub_reset(hub)) { err("error resetting hub %d - disconnecting", dev->devnum); up(&hub->khubd_sem); usb_hub_disconnect(dev); continue; } hub->nerrors = 0; hub->error = 0; } for (i = 0; i < hub->descriptor->bNbrPorts; i++) { ret = usb_hub_port_status(dev, i, &portstatus, &portchange); if (ret < 0) { continue; } if (portchange & USB_PORT_STAT_C_CONNECTION) { dbg("port %d connection change", i + 1); usb_hub_port_connect_change(hub, i, portstatus, portchange); } else if (portchange & USB_PORT_STAT_C_ENABLE) { dbg("port %d enable change, status %x", i + 1, portstatus); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_ENABLE); /* * EM interference sometimes causes bad shielded USB devices to * be shutdown by the hub, this hack enables them again. * Works at least with mouse driver. */ if (!(portstatus & USB_PORT_STAT_ENABLE) && (portstatus & USB_PORT_STAT_CONNECTION) && (dev->children[i])) { err("already running port %i disabled by hub (EMI?), re-enabling...", i + 1); usb_hub_port_connect_change(hub, i, portstatus, portchange); } } if (portchange & USB_PORT_STAT_C_SUSPEND) { dbg("port %d suspend change", i + 1); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_SUSPEND); } if (portchange & USB_PORT_STAT_C_OVERCURRENT) { err("port %d over-current change", i + 1); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_OVER_CURRENT); usb_hub_power_on(hub); } if (portchange & USB_PORT_STAT_C_RESET) { dbg("port %d reset change", i + 1); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_RESET); } } /* end for i */ /* deal with hub status changes */ if (usb_get_hub_status(dev, &hubsts) < 0) err("get_hub_status failed"); else { hubstatus = le16_to_cpup(&hubsts.wHubStatus); hubchange = le16_to_cpup(&hubsts.wHubChange); if (hubchange & HUB_CHANGE_LOCAL_POWER) { dbg("hub power change"); usb_clear_hub_feature(dev, C_HUB_LOCAL_POWER); } if (hubchange & HUB_CHANGE_OVERCURRENT) { dbg("hub overcurrent change"); wait_ms(500); /* Cool down */ usb_clear_hub_feature(dev, C_HUB_OVER_CURRENT); usb_hub_power_on(hub); } } up(&hub->khubd_sem); } /* end while (1) */ spin_unlock_irqrestore(&hub_event_lock, flags); }
static int usb_hub_configure(struct usb_hub *hub, struct usb_endpoint_descriptor *endpoint) { struct usb_device *dev = hub->dev; struct usb_hub_status hubstatus; char portstr[USB_MAXCHILDREN + 1]; unsigned int pipe; int i, maxp, ret; DBG_HOST_HUB("### >>> Enter hub.c file --> usb_hub_configure function \n"); hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL); if (!hub->descriptor) { err("Unable to kmalloc %Zd bytes for hub descriptor", sizeof(*hub->descriptor)); return -1; } /* Request the entire hub descriptor. */ ret = usb_get_hub_descriptor(dev, hub->descriptor, sizeof(*hub->descriptor)); /* <hub->descriptor> is large enough for a hub with 127 ports; * the hub can/will return fewer bytes here. */ if (ret < 0) { err("Unable to get hub descriptor (err = %d)", ret); kfree(hub->descriptor); return -1; } dev->maxchild = hub->descriptor->bNbrPorts; info("%d port%s detected", hub->descriptor->bNbrPorts, (hub->descriptor->bNbrPorts == 1) ? "" : "s"); le16_to_cpus(&hub->descriptor->wHubCharacteristics); if (hub->descriptor->wHubCharacteristics & HUB_CHAR_COMPOUND) dbg("part of a compound device"); else dbg("standalone hub"); switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) { case 0x00: dbg("ganged power switching"); break; case 0x01: dbg("individual port power switching"); break; case 0x02: case 0x03: dbg("unknown reserved power switching mode"); break; } switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_OCPM) { case 0x00: dbg("global over-current protection"); break; case 0x08: dbg("individual port over-current protection"); break; case 0x10: case 0x18: dbg("no over-current protection"); break; } switch (dev->descriptor.bDeviceProtocol) { case 0: break; case 1: dbg("Single TT"); hub->tt.hub = dev; break; case 2: dbg("TT per port"); hub->tt.hub = dev; hub->tt.multi = 1; break; default: dbg("Unrecognized hub protocol %d", dev->descriptor.bDeviceProtocol); break; } switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_TTTT) { case 0x00: if (dev->descriptor.bDeviceProtocol != 0) dbg("TT requires at most 8 FS bit times"); break; case 0x20: dbg("TT requires at most 16 FS bit times"); break; case 0x40: dbg("TT requires at most 24 FS bit times"); break; case 0x60: dbg("TT requires at most 32 FS bit times"); break; } dbg("Port indicators are %s supported", (hub->descriptor->wHubCharacteristics & HUB_CHAR_PORTIND) ? "" : "not"); dbg("power on to power good time: %dms", hub->descriptor->bPwrOn2PwrGood * 2); dbg("hub controller current requirement: %dmA", hub->descriptor->bHubContrCurrent); for (i = 0; i < dev->maxchild; i++) portstr[i] = hub->descriptor->DeviceRemovable[((i + 1) / 8)] & (1 << ((i + 1) % 8)) ? 'F' : 'R'; portstr[dev->maxchild] = 0; dbg("port removable status: %s", portstr); ret = usb_get_hub_status(dev, &hubstatus); if (ret < 0) { err("Unable to get hub status (err = %d)", ret); kfree(hub->descriptor); return -1; } le16_to_cpus(&hubstatus.wHubStatus); dbg("local power source is %s", (hubstatus.wHubStatus & HUB_STATUS_LOCAL_POWER) ? "lost (inactive)" : "good"); dbg("%sover-current condition exists", (hubstatus.wHubStatus & HUB_STATUS_OVERCURRENT) ? "" : "no "); /* Start the interrupt endpoint */ pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); if (maxp > sizeof(hub->buffer)) maxp = sizeof(hub->buffer); hub->urb = usb_alloc_urb(0); if (!hub->urb) { err("couldn't allocate interrupt urb"); kfree(hub->descriptor); return -1; } FILL_INT_URB(hub->urb, dev, pipe, hub->buffer, maxp, hub_irq, hub, endpoint->bInterval); ret = usb_submit_urb(hub->urb); if (ret) { err("usb_submit_urb failed (%d)", ret); kfree(hub->descriptor); return -1; } /* Wake up khubd */ wake_up(&khubd_wait); usb_hub_power_on(hub); return 0; }
static int usb_hub_configure(struct usb_device *dev) { int i, length; ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, USB_BUFSIZ); unsigned char *bitmap; short hubCharacteristics; struct usb_hub_descriptor *descriptor; struct usb_hub_device *hub; __maybe_unused struct usb_hub_status *hubsts; /* "allocate" Hub device */ hub = usb_hub_allocate(); if (hub == NULL) return -1; hub->pusb_dev = dev; /* Get the the hub descriptor */ if (usb_get_hub_descriptor(dev, buffer, 4) < 0) { debug("usb_hub_configure: failed to get hub " \ "descriptor, giving up %lX\n", dev->status); return -1; } descriptor = (struct usb_hub_descriptor *)buffer; length = min_t(int, descriptor->bLength, sizeof(struct usb_hub_descriptor)); if (usb_get_hub_descriptor(dev, buffer, length) < 0) { debug("usb_hub_configure: failed to get hub " \ "descriptor 2nd giving up %lX\n", dev->status); return -1; } memcpy((unsigned char *)&hub->desc, buffer, length); /* adjust 16bit values */ put_unaligned(le16_to_cpu(get_unaligned( &descriptor->wHubCharacteristics)), &hub->desc.wHubCharacteristics); /* set the bitmap */ bitmap = (unsigned char *)&hub->desc.DeviceRemovable[0]; /* devices not removable by default */ memset(bitmap, 0xff, (USB_MAXCHILDREN+1+7)/8); bitmap = (unsigned char *)&hub->desc.PortPowerCtrlMask[0]; memset(bitmap, 0xff, (USB_MAXCHILDREN+1+7)/8); /* PowerMask = 1B */ for (i = 0; i < ((hub->desc.bNbrPorts + 1 + 7)/8); i++) hub->desc.DeviceRemovable[i] = descriptor->DeviceRemovable[i]; for (i = 0; i < ((hub->desc.bNbrPorts + 1 + 7)/8); i++) hub->desc.PortPowerCtrlMask[i] = descriptor->PortPowerCtrlMask[i]; dev->maxchild = descriptor->bNbrPorts; debug("%d ports detected\n", dev->maxchild); hubCharacteristics = get_unaligned(&hub->desc.wHubCharacteristics); switch (hubCharacteristics & HUB_CHAR_LPSM) { case 0x00: debug("ganged power switching\n"); break; case 0x01: debug("individual port power switching\n"); break; case 0x02: case 0x03: debug("unknown reserved power switching mode\n"); break; } if (hubCharacteristics & HUB_CHAR_COMPOUND) debug("part of a compound device\n"); else debug("standalone hub\n"); switch (hubCharacteristics & HUB_CHAR_OCPM) { case 0x00: debug("global over-current protection\n"); break; case 0x08: debug("individual port over-current protection\n"); break; case 0x10: case 0x18: debug("no over-current protection\n"); break; } debug("power on to power good time: %dms\n", descriptor->bPwrOn2PwrGood * 2); debug("hub controller current requirement: %dmA\n", descriptor->bHubContrCurrent); for (i = 0; i < dev->maxchild; i++) debug("port %d is%s removable\n", i + 1, hub->desc.DeviceRemovable[(i + 1) / 8] & \ (1 << ((i + 1) % 8)) ? " not" : ""); if (sizeof(struct usb_hub_status) > USB_BUFSIZ) { debug("usb_hub_configure: failed to get Status - " \ "too long: %d\n", descriptor->bLength); return -1; } if (usb_get_hub_status(dev, buffer) < 0) { debug("usb_hub_configure: failed to get Status %lX\n", dev->status); return -1; } #ifdef DEBUG hubsts = (struct usb_hub_status *)buffer; #endif debug("get_hub_status returned status %X, change %X\n", le16_to_cpu(hubsts->wHubStatus), le16_to_cpu(hubsts->wHubChange)); debug("local power source is %s\n", (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_LOCAL_POWER) ? \ "lost (inactive)" : "good"); debug("%sover-current condition exists\n", (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? \ "" : "no "); usb_hub_power_on(hub); /* * Reset any devices that may be in a bad state when applying * the power. This is a __weak function. Resetting of the devices * should occur in the board file of the device. */ for (i = 0; i < dev->maxchild; i++) usb_hub_reset_devices(i + 1); for (i = 0; i < dev->maxchild; i++) { ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1); unsigned short portstatus, portchange; int ret; ulong start = get_timer(0); /* * Wait for (whichever finishes first) * - A maximum of 10 seconds * This is a purely observational value driven by connecting * a few broken pen drives and taking the max * 1.5 approach * - connection_change and connection state to report same * state */ do { ret = usb_get_port_status(dev, i + 1, portsts); if (ret < 0) { debug("get_port_status failed\n"); break; } portstatus = le16_to_cpu(portsts->wPortStatus); portchange = le16_to_cpu(portsts->wPortChange); if ((portchange & USB_PORT_STAT_C_CONNECTION) == (portstatus & USB_PORT_STAT_CONNECTION)) break; } while (get_timer(start) < CONFIG_SYS_HZ * 10); if (ret < 0) continue; debug("Port %d Status %X Change %X\n", i + 1, portstatus, portchange); if (portchange & USB_PORT_STAT_C_CONNECTION) { debug("port %d connection change\n", i + 1); usb_hub_port_connect_change(dev, i); } if (portchange & USB_PORT_STAT_C_ENABLE) { debug("port %d enable change, status %x\n", i + 1, portstatus); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_ENABLE); /* * The following hack causes a ghost device problem * to Faraday EHCI */ #ifndef CONFIG_USB_EHCI_FARADAY /* EM interference sometimes causes bad shielded USB * devices to be shutdown by the hub, this hack enables * them again. Works at least with mouse driver */ if (!(portstatus & USB_PORT_STAT_ENABLE) && (portstatus & USB_PORT_STAT_CONNECTION) && ((dev->children[i]))) { debug("already running port %i " \ "disabled by hub (EMI?), " \ "re-enabling...\n", i + 1); usb_hub_port_connect_change(dev, i); } #endif } if (portstatus & USB_PORT_STAT_SUSPEND) { debug("port %d suspend change\n", i + 1); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_SUSPEND); } if (portchange & USB_PORT_STAT_C_OVERCURRENT) { debug("port %d over-current change\n", i + 1); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_OVER_CURRENT); usb_hub_power_on(hub); } if (portchange & USB_PORT_STAT_C_RESET) { debug("port %d reset change\n", i + 1); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_RESET); } } /* end for i all ports */ return 0; }
static int usb_hub_configure(struct usb_device *dev) { unsigned char buffer[USB_BUFSIZ], *bitmap; struct usb_hub_descriptor *descriptor; struct usb_hub_status *hubsts; int i; struct usb_hub_device *hub; hub = xzalloc(sizeof (*hub)); dev->hub = hub; hub->pusb_dev = dev; /* Get the the hub descriptor */ if (usb_get_hub_descriptor(dev, buffer, 4) < 0) { dev_dbg(&dev->dev, "%s: failed to get hub " \ "descriptor, giving up %lX\n", __func__, dev->status); return -1; } descriptor = (struct usb_hub_descriptor *)buffer; /* silence compiler warning if USB_BUFSIZ is > 256 [= sizeof(char)] */ i = descriptor->bLength; if (i > USB_BUFSIZ) { dev_dbg(&dev->dev, "%s: failed to get hub " \ "descriptor - too long: %d\n", __func__, descriptor->bLength); return -1; } if (usb_get_hub_descriptor(dev, buffer, descriptor->bLength) < 0) { dev_dbg(&dev->dev, "%s: failed to get hub " \ "descriptor 2nd giving up %lX\n", __func__, dev->status); return -1; } memcpy((unsigned char *)&hub->desc, buffer, descriptor->bLength); /* adjust 16bit values */ hub->desc.wHubCharacteristics = le16_to_cpu(descriptor->wHubCharacteristics); /* set the bitmap */ bitmap = (unsigned char *)&hub->desc.u.hs.DeviceRemovable[0]; /* devices not removable by default */ memset(bitmap, 0xff, (USB_MAXCHILDREN+1+7)/8); bitmap = (unsigned char *)&hub->desc.u.hs.PortPwrCtrlMask[0]; memset(bitmap, 0xff, (USB_MAXCHILDREN+1+7)/8); /* PowerMask = 1B */ for (i = 0; i < ((hub->desc.bNbrPorts + 1 + 7)/8); i++) hub->desc.u.hs.DeviceRemovable[i] = descriptor->u.hs.DeviceRemovable[i]; for (i = 0; i < ((hub->desc.bNbrPorts + 1 + 7)/8); i++) hub->desc.u.hs.PortPwrCtrlMask[i] = descriptor->u.hs.PortPwrCtrlMask[i]; dev->maxchild = descriptor->bNbrPorts; dev_dbg(&dev->dev, "%d ports detected\n", dev->maxchild); switch (hub->desc.wHubCharacteristics & HUB_CHAR_LPSM) { case 0x00: dev_dbg(&dev->dev, "ganged power switching\n"); break; case 0x01: dev_dbg(&dev->dev, "individual port power switching\n"); break; case 0x02: case 0x03: dev_dbg(&dev->dev, "unknown reserved power switching mode\n"); break; } if (hub->desc.wHubCharacteristics & HUB_CHAR_COMPOUND) dev_dbg(&dev->dev, "part of a compound device\n"); else dev_dbg(&dev->dev, "standalone hub\n"); switch (hub->desc.wHubCharacteristics & HUB_CHAR_OCPM) { case 0x00: dev_dbg(&dev->dev, "global over-current protection\n"); break; case 0x08: dev_dbg(&dev->dev, "individual port over-current protection\n"); break; case 0x10: case 0x18: dev_dbg(&dev->dev, "no over-current protection\n"); break; } dev_dbg(&dev->dev, "power on to power good time: %dms\n", descriptor->bPwrOn2PwrGood * 2); dev_dbg(&dev->dev, "hub controller current requirement: %dmA\n", descriptor->bHubContrCurrent); for (i = 0; i < dev->maxchild; i++) dev_dbg(&dev->dev, "port %d is%s removable\n", i + 1, hub->desc.u.hs.DeviceRemovable[(i + 1) / 8] & \ (1 << ((i + 1) % 8)) ? " not" : ""); if (sizeof(struct usb_hub_status) > USB_BUFSIZ) { dev_dbg(&dev->dev, "%s: failed to get Status - " \ "too long: %d\n", __func__, descriptor->bLength); return -1; } if (usb_get_hub_status(dev, buffer) < 0) { dev_dbg(&dev->dev, "%s: failed to get Status %lX\n", __func__, dev->status); return -1; } hubsts = (struct usb_hub_status *)buffer; dev_dbg(&dev->dev, "get_hub_status returned status %X, change %X\n", le16_to_cpu(hubsts->wHubStatus), le16_to_cpu(hubsts->wHubChange)); dev_dbg(&dev->dev, "local power source is %s\n", (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_LOCAL_POWER) ? \ "lost (inactive)" : "good"); dev_dbg(&dev->dev, "%sover-current condition exists\n", (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? \ "" : "no "); usb_hub_power_on(hub); return 0; }
static int usb_hub_configure_port(struct usb_device *dev, int port) { struct usb_port_status portsts; unsigned short portstatus, portchange; int connect_change = 0; if (usb_get_port_status(dev, port + 1, &portsts) < 0) { dev_dbg(&dev->dev, "get_port_status failed\n"); return -EIO; } portstatus = le16_to_cpu(portsts.wPortStatus); portchange = le16_to_cpu(portsts.wPortChange); dev_dbg(&dev->dev, "Port %d Status %X Change %X\n", port + 1, portstatus, portchange); if (portchange & USB_PORT_STAT_C_CONNECTION) { dev_dbg(&dev->dev, "port %d connection change\n", port + 1); connect_change = 1; } if (portchange & USB_PORT_STAT_C_ENABLE) { dev_dbg(&dev->dev, "port %d enable change, status %x\n", port + 1, portstatus); usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_ENABLE); /* EM interference sometimes causes bad shielded USB * devices to be shutdown by the hub, this hack enables * them again. Works at least with mouse driver */ if (!(portstatus & USB_PORT_STAT_ENABLE) && (portstatus & USB_PORT_STAT_CONNECTION) && ((dev->children[port]))) { dev_dbg(&dev->dev, "already running port %i " \ "disabled by hub (EMI?), " \ "re-enabling...\n", port + 1); connect_change = 1; } } if (connect_change) usb_hub_port_connect_change(dev, port); if (portstatus & USB_PORT_STAT_SUSPEND) { dev_dbg(&dev->dev, "port %d suspend change\n", port + 1); usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_SUSPEND); } if (portchange & USB_PORT_STAT_C_OVERCURRENT) { dev_dbg(&dev->dev, "port %d over-current change\n", port + 1); usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_OVER_CURRENT); usb_hub_power_on(dev->hub); } if (portchange & USB_PORT_STAT_C_RESET) { dev_dbg(&dev->dev, "port %d reset change\n", port + 1); usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_RESET); } return 0; }
int usb_hub_events(void) { USB_LIST_T *tmp; USB_DEV_T *dev; USB_HUB_T *hub; USB_HUB_STATUS_T hubsts; uint16_t hubchange; uint16_t irq_data; int i, ret; //printf("0x%x 0x%x\n", *(uint32_t *)0x40009054, *(uint32_t *)0x40009058); if(list_empty(&_HubEventList)) return 0; /* * We restart the list everytime to avoid a deadlock with * deleting hubs downstream from this one. This should be * safe since we delete the hub from the event list. * Not the most efficient, but avoids deadlocks. */ while(1) { if(list_empty(&_HubEventList)) break; /* Grab the next entry from the beginning of the list */ tmp = _HubEventList.next; hub = list_entry(tmp, USB_HUB_T, event_list); dev = hub->dev; list_del(tmp); INIT_LIST_HEAD(tmp); if(hub->error) { USB_error("hub error %d!!\n", hub->error); } /* added by YCHuang */ if(hub->urb->transfer_buffer_length == 1) irq_data = *(uint8_t *)hub->urb->transfer_buffer; else { /* BIGBIG */ //irq_data = *(uint16_t *)hub->urb->transfer_buffer; /* FIX DEBUG, not verified */ irq_data = (*((uint8_t *)hub->urb->transfer_buffer + 1) << 8) | *(uint8_t *)hub->urb->transfer_buffer; } for(i = 0; i < hub->descriptor.bNbrPorts; i++) { USB_PORT_STATUS_T portsts; uint16_t portstatus, portchange; if(!((irq_data >> (i + 1)) & 0x01)) continue; USB_info("usb_hub_events - hub:%d, get port status...\n", hub->dev->devnum); ret = usb_get_port_status(dev, i + 1, &portsts); if(ret < 0) { USB_error("Error - get_hub %d port %d status failed (err = %d)\n", hub->dev->devnum, i + 1, ret); continue; } portstatus = portsts.wPortStatus; portchange = portsts.wPortChange; USB_debug("port %d, portstatus = %x, portchange = %x\n", i, portstatus, portchange); if(portchange & USB_PORT_STAT_C_CONNECTION) { USB_info("port %d of hub %d connection change\n", i + 1, hub->dev->devnum); usb_hub_port_connect_change(hub, dev, i, &portsts); } else if(portchange & USB_PORT_STAT_C_ENABLE) { USB_info("port %d of hub %d enable change, status %x\n", i + 1, portstatus, hub->dev->devnum); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_ENABLE); /* * EM interference sometimes causes bad shielded USB * devices to be shutdown by the hub, this hack enables * them again. Works at least with mouse driver. */ if(!(portstatus & USB_PORT_STAT_ENABLE) && (portstatus & USB_PORT_STAT_CONNECTION) && (dev->children[i])) { USB_error("Error - already running port %i disabled by hub (EMI?), re-enabling...\n", i + 1); usb_hub_port_connect_change(hub, dev, i, &portsts); } } if(portchange & USB_PORT_STAT_C_SUSPEND) { USB_info("port %d of hub %d suspend change\n", i + 1, hub->dev->devnum); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_SUSPEND); } if(portchange & USB_PORT_STAT_C_OVERCURRENT) { USB_warning("!! port %d of hub %d over-current change\n", i + 1, hub->dev->devnum); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_OVER_CURRENT); usb_hub_power_on(hub); } if(portchange & USB_PORT_STAT_C_RESET) { USB_info("port %d of hub %d reset change\n", i + 1, hub->dev->devnum); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_RESET); } } /* end for i */ /* deal with hub status changes */ if (usb_get_hub_status(dev, &hubsts) < 0) USB_error("Error - get_hub_status failed\n"); else { //hubstatus = USB_SWAP16(hubsts.wHubStatus); hubchange = USB_SWAP16(hubsts.wHubChange); if(hubchange & HUB_CHANGE_LOCAL_POWER) { USB_debug("hub power change\n"); usb_clear_hub_feature(dev, C_HUB_LOCAL_POWER); } if(hubchange & HUB_CHANGE_OVERCURRENT) { USB_error("!!hub overcurrent change\n"); usbh_mdelay(500); /* Cool down */ usb_clear_hub_feature(dev, C_HUB_OVER_CURRENT); usb_hub_power_on(hub); } } } /* end while (1) */ return 1; }
static int usb_hub_configure(USB_HUB_T *hub, EP_INFO_T *ep_info) { USB_DEV_T *dev = hub->dev; USB_HUB_STATUS_T hubstatus; uint32_t pipe; int maxp, ret; USB_info("[HUB] Enter usb_hub_configure()... hub:%d\n", hub->dev->devnum); /* Request the entire hub descriptor. */ ret = usb_get_hub_descriptor(dev, &hub->descriptor, sizeof(USB_HUB_DESC_T)); /* <hub->descriptor> is large enough for a hub with 127 ports; * the hub can/will return fewer bytes here. */ if(ret < 0) { USB_error("Erro - Unable to get hub descriptor (err = %d)\n", ret); return ret; } dev->maxchild = hub->descriptor.bNbrPorts; #ifdef USB_VERBOSE_DEBUG USB_info("%d port%s detected\n", hub->descriptor.bNbrPorts, (hub->descriptor.bNbrPorts == 1) ? "" : "s"); /* D2: Identifying a Compound Device */ if(hub->descriptor.wHubCharacteristics & HUB_CHAR_COMPOUND) { USB_info("part of a compound device\n"); } else { USB_info("standalone hub\n"); } /* D1..D0: Logical Power Switching Mode */ switch(hub->descriptor.wHubCharacteristics & HUB_CHAR_LPSM) { case 0x00: USB_info("ganged power switching\n"); break; case 0x01: USB_info("individual port power switching\n"); break; case 0x02: case 0x03: USB_info("unknown reserved power switching mode\n"); break; } /* D4..D3: Over-current Protection Mode */ switch(hub->descriptor.wHubCharacteristics & HUB_CHAR_OCPM) { case 0x00: USB_info("global over-current protection\n"); break; case 0x08: USB_info("individual port over-current protection\n"); break; case 0x10: case 0x18: USB_info("no over-current protection\n"); break; } switch(dev->descriptor.bDeviceProtocol) { case 0: break; case 1: USB_debug("Single TT, "); break; case 2: USB_debug("TT per port, "); break; default: USB_debug("Unrecognized hub protocol %d", dev->descriptor.bDeviceProtocol); break; } USB_info("power on to power good time: %dms\n", hub->descriptor.bPwrOn2PwrGood * 2); USB_info("hub controller current requirement: %dmA\n", hub->descriptor.bHubContrCurrent); #endif ret = usb_get_hub_status(dev, &hubstatus); if(ret < 0) { USB_error("Unable to get hub %d status (err = %d)\n", hub->dev->devnum, ret); return ret; } hubstatus.wHubStatus = USB_SWAP16(hubstatus.wHubStatus); #ifdef USB_VERBOSE_DEBUG /* Hub status bit 0, Local Power Source */ if(hubstatus.wHubStatus & HUB_STATUS_LOCAL_POWER) { USB_info("local power source is lost (inactive)\n"); } else { USB_info("local power source is good\n"); } /* Hub status bit 1, Over-current Indicator */ if(hubstatus.wHubStatus & HUB_STATUS_OVERCURRENT) { USB_info("!! over-current\n"); } else { USB_info("No over-current.\n"); } #endif /* Start the interrupt endpoint */ pipe = usb_rcvintpipe(dev, ep_info->bEndpointAddress); maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); if(maxp > sizeof(hub->buffer)) maxp = sizeof(hub->buffer); hub->urb = USBH_AllocUrb(); if(!hub->urb) { USB_error("Error - couldn't allocate interrupt urb"); return USB_ERR_NOMEM; } #if 1 /* YCHuang 2012.06.01 */ if(ep_info->bInterval < 16) ep_info->bInterval = 16; #endif FILL_INT_URB(hub->urb, dev, pipe, hub->buffer, maxp, hub_irq, hub, ep_info->bInterval); ret = USBH_SubmitUrb(hub->urb); if(ret) { USB_error("Error - USBH_SubmitUrb failed (%d)", ret); USBH_FreeUrb(hub->urb); return ret; } if(g_ohci_bus.root_hub != hub->dev) usb_hub_power_on(hub); return 0; }
static int usb_hub_configure(struct usb_device *dev) { int i; ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, USB_BUFSIZ); unsigned char *bitmap; short hubCharacteristics; struct usb_hub_descriptor *descriptor; struct usb_hub_device *hub; #ifdef USB_HUB_DEBUG struct usb_hub_status *hubsts; #endif /* "allocate" Hub device */ hub = usb_hub_allocate(); if (hub == NULL) return -1; hub->pusb_dev = dev; /* Get the the hub descriptor */ if (usb_get_hub_descriptor(dev, buffer, 4) < 0) { USB_HUB_PRINTF("usb_hub_configure: failed to get hub " \ "descriptor, giving up %lX\n", dev->status); return -1; } descriptor = (struct usb_hub_descriptor *)buffer; /* silence compiler warning if USB_BUFSIZ is > 256 [= sizeof(char)] */ i = descriptor->bLength; if (i > USB_BUFSIZ) { USB_HUB_PRINTF("usb_hub_configure: failed to get hub " \ "descriptor - too long: %d\n", descriptor->bLength); return -1; } if (usb_get_hub_descriptor(dev, buffer, descriptor->bLength) < 0) { USB_HUB_PRINTF("usb_hub_configure: failed to get hub " \ "descriptor 2nd giving up %lX\n", dev->status); return -1; } memcpy((unsigned char *)&hub->desc, buffer, descriptor->bLength); /* adjust 16bit values */ put_unaligned(le16_to_cpu(get_unaligned( &descriptor->wHubCharacteristics)), &hub->desc.wHubCharacteristics); /* set the bitmap */ bitmap = (unsigned char *)&hub->desc.DeviceRemovable[0]; /* devices not removable by default */ memset(bitmap, 0xff, (USB_MAXCHILDREN+1+7)/8); bitmap = (unsigned char *)&hub->desc.PortPowerCtrlMask[0]; memset(bitmap, 0xff, (USB_MAXCHILDREN+1+7)/8); /* PowerMask = 1B */ for (i = 0; i < ((hub->desc.bNbrPorts + 1 + 7)/8); i++) hub->desc.DeviceRemovable[i] = descriptor->DeviceRemovable[i]; for (i = 0; i < ((hub->desc.bNbrPorts + 1 + 7)/8); i++) hub->desc.PortPowerCtrlMask[i] = descriptor->PortPowerCtrlMask[i]; dev->maxchild = descriptor->bNbrPorts; USB_HUB_PRINTF("%d ports detected\n", dev->maxchild); hubCharacteristics = get_unaligned(&hub->desc.wHubCharacteristics); switch (hubCharacteristics & HUB_CHAR_LPSM) { case 0x00: USB_HUB_PRINTF("ganged power switching\n"); break; case 0x01: USB_HUB_PRINTF("individual port power switching\n"); break; case 0x02: case 0x03: USB_HUB_PRINTF("unknown reserved power switching mode\n"); break; } if (hubCharacteristics & HUB_CHAR_COMPOUND) USB_HUB_PRINTF("part of a compound device\n"); else USB_HUB_PRINTF("standalone hub\n"); switch (hubCharacteristics & HUB_CHAR_OCPM) { case 0x00: USB_HUB_PRINTF("global over-current protection\n"); break; case 0x08: USB_HUB_PRINTF("individual port over-current protection\n"); break; case 0x10: case 0x18: USB_HUB_PRINTF("no over-current protection\n"); break; } USB_HUB_PRINTF("power on to power good time: %dms\n", descriptor->bPwrOn2PwrGood * 2); USB_HUB_PRINTF("hub controller current requirement: %dmA\n", descriptor->bHubContrCurrent); for (i = 0; i < dev->maxchild; i++) USB_HUB_PRINTF("port %d is%s removable\n", i + 1, hub->desc.DeviceRemovable[(i + 1) / 8] & \ (1 << ((i + 1) % 8)) ? " not" : ""); if (sizeof(struct usb_hub_status) > USB_BUFSIZ) { USB_HUB_PRINTF("usb_hub_configure: failed to get Status - " \ "too long: %d\n", descriptor->bLength); return -1; } if (usb_get_hub_status(dev, buffer) < 0) { USB_HUB_PRINTF("usb_hub_configure: failed to get Status %lX\n", dev->status); return -1; } #ifdef USB_HUB_DEBUG hubsts = (struct usb_hub_status *)buffer; #endif USB_HUB_PRINTF("get_hub_status returned status %X, change %X\n", le16_to_cpu(hubsts->wHubStatus), le16_to_cpu(hubsts->wHubChange)); USB_HUB_PRINTF("local power source is %s\n", (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_LOCAL_POWER) ? \ "lost (inactive)" : "good"); USB_HUB_PRINTF("%sover-current condition exists\n", (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? \ "" : "no "); usb_hub_power_on(hub); for (i = 0; i < dev->maxchild; i++) { ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1); unsigned short portstatus, portchange; int ret; ulong start = get_timer(0); /* * Wait for (whichever finishes first) * - A maximum of 10 seconds * This is a purely observational value driven by connecting * a few broken pen drives and taking the max * 1.5 approach * - connection_change and connection state to report same * state */ do { ret = usb_get_port_status(dev, i + 1, portsts); if (ret < 0) { USB_HUB_PRINTF("get_port_status failed\n"); break; } portstatus = le16_to_cpu(portsts->wPortStatus); portchange = le16_to_cpu(portsts->wPortChange); #ifdef CONFIG_MARVELL /* - USB3.0 issue with Avanta-LP/Armada-375: * If usb device was already connected before detection ('usb start'), * port connect status bit is set (USB_PORT_STAT_CONNECTION), * but port connect status change bit (USB_PORT_STAT_C_CONNECTION) is not set. * - Added WA (aligned with kernel driver): instead of checking port change status, * to be satisfied with checking USB_PORT_STAT_CONNECTION Bit on portstatus only" */ if (((portchange & USB_PORT_STAT_C_CONNECTION) == (portstatus & USB_PORT_STAT_CONNECTION)) || (portstatus & USB_PORT_STAT_CONNECTION)) #else if ((portchange & USB_PORT_STAT_C_CONNECTION) == (portstatus & USB_PORT_STAT_CONNECTION)) #endif break; mdelay(100); } while (get_timer(start) < CONFIG_SYS_HZ * 10); if (ret < 0) continue; USB_HUB_PRINTF("Port %d Status %X Change %X\n", i + 1, portstatus, portchange); #ifdef CONFIG_MARVELL /* - USB3.0 issue with Avanta-LP/Armada-375: * If usb device was already connected before detection ('usb start'), * port connect status bit is set (USB_PORT_STAT_CONNECTION), * but port connect status change bit (USB_PORT_STAT_C_CONNECTION) is not set. * - Added WA (aligned with kernel driver): instead of checking port change status, * to be satisfied with checking USB_PORT_STAT_CONNECTION Bit on portstatus only" */ if ((portchange & USB_PORT_STAT_C_CONNECTION) || (portstatus & USB_PORT_STAT_CONNECTION)) { #else if (portchange & USB_PORT_STAT_C_CONNECTION) { #endif USB_HUB_PRINTF("port %d connection change\n", i + 1); usb_hub_port_connect_change(dev, i); } if (portchange & USB_PORT_STAT_C_ENABLE) { USB_HUB_PRINTF("port %d enable change, status %x\n", i + 1, portstatus); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_ENABLE); /* EM interference sometimes causes bad shielded USB * devices to be shutdown by the hub, this hack enables * them again. Works at least with mouse driver */ if (!(portstatus & USB_PORT_STAT_ENABLE) && (portstatus & USB_PORT_STAT_CONNECTION) && ((dev->children[i]))) { USB_HUB_PRINTF("already running port %i " \ "disabled by hub (EMI?), " \ "re-enabling...\n", i + 1); usb_hub_port_connect_change(dev, i); } } if (portstatus & USB_PORT_STAT_SUSPEND) { USB_HUB_PRINTF("port %d suspend change\n", i + 1); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_SUSPEND); } if (portchange & USB_PORT_STAT_C_OVERCURRENT) { USB_HUB_PRINTF("port %d over-current change\n", i + 1); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_OVER_CURRENT); usb_hub_power_on(hub); } if (portchange & USB_PORT_STAT_C_RESET) { USB_HUB_PRINTF("port %d reset change\n", i + 1); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_RESET); } } /* end for i all ports */ return 0; } int usb_hub_probe(struct usb_device *dev, int ifnum) { struct usb_interface *iface; struct usb_endpoint_descriptor *ep; int ret; iface = &dev->config.if_desc[ifnum]; /* Is it a hub? */ if (iface->desc.bInterfaceClass != USB_CLASS_HUB) return 0; /* Some hubs have a subclass of 1, which AFAICT according to the */ /* specs is not defined, but it works */ if ((iface->desc.bInterfaceSubClass != 0) && (iface->desc.bInterfaceSubClass != 1)) return 0; /* Multiple endpoints? What kind of mutant ninja-hub is this? */ if (iface->desc.bNumEndpoints != 1) return 0; ep = &iface->ep_desc[0]; /* Output endpoint? Curiousier and curiousier.. */ if (!(ep->bEndpointAddress & USB_DIR_IN)) return 0; /* If it's not an interrupt endpoint, we'd better punt! */ if ((ep->bmAttributes & 3) != 3) return 0; /* We found a hub */ USB_HUB_PRINTF("USB hub found\n"); ret = usb_hub_configure(dev); return ret; }
int usb_hub_configure(struct usb_device *dev) { int i; ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, USB_BUFSIZ); unsigned char *bitmap; struct usb_hub_descriptor *descriptor; struct usb_hub_device *hub; #ifdef USB_HUB_DEBUG struct usb_hub_status *hubsts; #endif /* "allocate" Hub device */ hub = usb_hub_allocate(); if (hub == NULL) return -1; hub->pusb_dev = dev; /* Get the the hub descriptor */ if (usb_get_hub_descriptor(dev, buffer, 4) < 0) { USB_HUB_PRINTF("usb_hub_configure: failed to get hub " \ "descriptor, giving up %lX\n", dev->status); return -1; } descriptor = (struct usb_hub_descriptor *)buffer; /* silence compiler warning if USB_BUFSIZ is > 256 [= sizeof(char)] */ i = descriptor->bLength; if (i > USB_BUFSIZ) { USB_HUB_PRINTF("usb_hub_configure: failed to get hub " \ "descriptor - too long: %d\n", descriptor->bLength); return -1; } if (usb_get_hub_descriptor(dev, buffer, descriptor->bLength) < 0) { USB_HUB_PRINTF("usb_hub_configure: failed to get hub " \ "descriptor 2nd giving up %lX\n", dev->status); return -1; } memcpy((unsigned char *)&hub->desc, buffer, descriptor->bLength); /* adjust 16bit values */ hub->desc.wHubCharacteristics = le16_to_cpu(descriptor->wHubCharacteristics); /* set the bitmap */ bitmap = (unsigned char *)&hub->desc.DeviceRemovable[0]; /* devices not removable by default */ memset(bitmap, 0xff, (USB_MAXCHILDREN+1+7)/8); bitmap = (unsigned char *)&hub->desc.PortPowerCtrlMask[0]; memset(bitmap, 0xff, (USB_MAXCHILDREN+1+7)/8); /* PowerMask = 1B */ for (i = 0; i < ((hub->desc.bNbrPorts + 1 + 7)/8); i++) hub->desc.DeviceRemovable[i] = descriptor->DeviceRemovable[i]; for (i = 0; i < ((hub->desc.bNbrPorts + 1 + 7)/8); i++) hub->desc.PortPowerCtrlMask[i] = descriptor->PortPowerCtrlMask[i]; dev->maxchild = descriptor->bNbrPorts; USB_HUB_PRINTF("%d ports detected\n", dev->maxchild); switch (hub->desc.wHubCharacteristics & HUB_CHAR_LPSM) { case 0x00: USB_HUB_PRINTF("ganged power switching\n"); break; case 0x01: USB_HUB_PRINTF("individual port power switching\n"); break; case 0x02: case 0x03: USB_HUB_PRINTF("unknown reserved power switching mode\n"); break; } if (hub->desc.wHubCharacteristics & HUB_CHAR_COMPOUND) USB_HUB_PRINTF("part of a compound device\n"); else USB_HUB_PRINTF("standalone hub\n"); switch (hub->desc.wHubCharacteristics & HUB_CHAR_OCPM) { case 0x00: USB_HUB_PRINTF("global over-current protection\n"); break; case 0x08: USB_HUB_PRINTF("individual port over-current protection\n"); break; case 0x10: case 0x18: USB_HUB_PRINTF("no over-current protection\n"); break; } USB_HUB_PRINTF("power on to power good time: %dms\n", descriptor->bPwrOn2PwrGood * 2); USB_HUB_PRINTF("hub controller current requirement: %dmA\n", descriptor->bHubContrCurrent); for (i = 0; i < dev->maxchild; i++) USB_HUB_PRINTF("port %d is%s removable\n", i + 1, hub->desc.DeviceRemovable[(i + 1) / 8] & \ (1 << ((i + 1) % 8)) ? " not" : ""); if (sizeof(struct usb_hub_status) > USB_BUFSIZ) { USB_HUB_PRINTF("usb_hub_configure: failed to get Status - " \ "too long: %d\n", descriptor->bLength); return -1; } if (usb_get_hub_status(dev, buffer) < 0) { USB_HUB_PRINTF("usb_hub_configure: failed to get Status %lX\n", dev->status); return -1; } #ifdef USB_HUB_DEBUG hubsts = (struct usb_hub_status *)buffer; #endif USB_HUB_PRINTF("get_hub_status returned status %X, change %X\n", le16_to_cpu(hubsts->wHubStatus), le16_to_cpu(hubsts->wHubChange)); USB_HUB_PRINTF("local power source is %s\n", (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_LOCAL_POWER) ? \ "lost (inactive)" : "good"); USB_HUB_PRINTF("%sover-current condition exists\n", (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? \ "" : "no "); usb_hub_power_on(hub); for (i = 0; i < dev->maxchild; i++) { ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1); unsigned short portstatus, portchange; if (usb_get_port_status(dev, i + 1, portsts) < 0) { USB_HUB_PRINTF("get_port_status failed\n"); continue; } portstatus = le16_to_cpu(portsts->wPortStatus); portchange = le16_to_cpu(portsts->wPortChange); USB_HUB_PRINTF("Port %d Status %X Change %X\n", i + 1, portstatus, portchange); if (portchange & USB_PORT_STAT_C_CONNECTION) { USB_HUB_PRINTF("port %d connection change\n", i + 1); usb_hub_port_connect_change(dev, i); } if (portchange & USB_PORT_STAT_C_ENABLE) { USB_HUB_PRINTF("port %d enable change, status %x\n", i + 1, portstatus); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_ENABLE); /* EM interference sometimes causes bad shielded USB * devices to be shutdown by the hub, this hack enables * them again. Works at least with mouse driver */ if (!(portstatus & USB_PORT_STAT_ENABLE) && (portstatus & USB_PORT_STAT_CONNECTION) && ((dev->children[i]))) { USB_HUB_PRINTF("already running port %i " \ "disabled by hub (EMI?), " \ "re-enabling...\n", i + 1); usb_hub_port_connect_change(dev, i); } } if (portstatus & USB_PORT_STAT_SUSPEND) { USB_HUB_PRINTF("port %d suspend change\n", i + 1); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_SUSPEND); } if (portchange & USB_PORT_STAT_C_OVERCURRENT) { USB_HUB_PRINTF("port %d over-current change\n", i + 1); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_OVER_CURRENT); usb_hub_power_on(hub); } if (portchange & USB_PORT_STAT_C_RESET) { USB_HUB_PRINTF("port %d reset change\n", i + 1); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_RESET); } } /* end for i all ports */ return 0; }