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); }
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; }