static int usb_hub_port_reset(USB_DEV_T *hub, int port, USB_DEV_T *dev, uint32_t delay) { int i; USB_info("usb_hub_port_reset: hub:%d, port:%d dev:%x\n", hub->devnum, port + 1, (int)dev); /* Reset the port */ for(i = 0; i < HUB_RESET_TRIES; i++) /* retry loop */ { usb_set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET); /* return success if the port reset OK */ if(!usb_hub_port_wait_reset(hub, port, dev, delay)) { usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_RESET); return 0; } USB_error("port %d of hub %d not enabled, %dth trying reset again...\n", port + 1, hub->devnum, i); delay = HUB_LONG_RESET_TIME; } USB_error("Cannot enable port %i of hub %d, disabling port.\n", port + 1, hub->devnum); USB_error("Error - Maybe the USB cable is bad?\n"); return -1; }
void usbh_memory_init(void) { int i; if (sizeof(TD_T) > MEM_POOL_UNIT_SIZE) { USB_error("TD_T - MEM_POOL_UNIT_SIZE too small!\n"); while (1); } if (sizeof(ED_T) > MEM_POOL_UNIT_SIZE) { USB_error("ED_T - MEM_POOL_UNIT_SIZE too small!\n"); while (1); } for (i = 0; i < MEM_POOL_UNIT_NUM; i++) { _unit_used[i] = 0; _mem_pool[i] = (uint8_t *)((uint32_t)&_mem_pool_buff[i] | NON_CACHE_MASK); } _usbh_mem_used = 0L; _usbh_max_mem_used = 0L; _mem_pool_used = 0; _sidx = 0; g_udev_list = NULL; memset(_dev_addr_pool, 0, sizeof(_dev_addr_pool)); _device_addr = 1; USB_InitializeMemoryPool(); }
/*--------------------------------------------------------------------------*/ QH_T * alloc_ehci_QH(void) { int i; QH_T *qh = NULL; for (i = (_sidx+1) % MEM_POOL_UNIT_NUM; i != _sidx; i = (i+1) % MEM_POOL_UNIT_NUM) { if (_unit_used[i] == 0) { _unit_used[i] = 1; _sidx = i; _mem_pool_used++; qh = (QH_T *)_mem_pool[i]; memset(qh, 0, sizeof(*qh)); mem_debug("[ALLOC] [QH] - 0x%x\n", (int)qh); break; } } if (qh == NULL) { USB_error("alloc_ehci_QH failed!\n"); return NULL; } qh->Curr_qTD = QTD_LIST_END; qh->OL_Next_qTD = QTD_LIST_END; qh->OL_Alt_Next_qTD = QTD_LIST_END; qh->OL_Token = QTD_STS_HALT; return qh; }
/*--------------------------------------------------------------------------*/ qTD_T * alloc_ehci_qTD(UTR_T *utr) { int i; qTD_T *qtd; for (i = (_sidx+1) % MEM_POOL_UNIT_NUM; i != _sidx; i = (i+1) % MEM_POOL_UNIT_NUM) { if (_unit_used[i] == 0) { _unit_used[i] = 1; _sidx = i; _mem_pool_used++; qtd = (qTD_T *)_mem_pool[i]; memset(qtd, 0, sizeof(*qtd)); qtd->Next_qTD = QTD_LIST_END; qtd->Alt_Next_qTD = QTD_LIST_END; qtd->Token = 0x1197B7F; // QTD_STS_HALT; visit_qtd() will not remove a qTD with this mark. It means the qTD still not ready for transfer. qtd->utr = utr; mem_debug("[ALLOC] [qTD] - 0x%x\n", (int)qtd); return qtd; } } USB_error("alloc_ehci_qTD failed!\n"); return NULL; }
void usb_hub_port_disable(USB_DEV_T *hub, int port) { int ret; ret = usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_ENABLE); if(ret) USB_error("cannot disable port %d of hub %d (err = %d)\n", port + 1, hub->devnum, ret); }
void * usbh_alloc_mem(int size) { void *p; p = USB_malloc(size, 16); if (p == NULL) { USB_error("usbh_alloc_mem failed! %d\n", size); return NULL; } memset(p, 0, size); memory_counter(size); return p; }
UTR_T * alloc_utr(UDEV_T *udev) { UTR_T *utr; utr = (UTR_T *)USB_malloc(sizeof(*utr), 16); if (utr == NULL) { USB_error("alloc_utr failed!\n"); return NULL; } memory_counter(sizeof(*utr)); memset(utr, 0, sizeof(*utr)); utr->udev = udev; mem_debug("[ALLOC] [UTR] - 0x%x\n", (int)utr); return utr; }
void free_ehci_siTD(siTD_T *sitd) { int i; for (i = 0; i < MEM_POOL_UNIT_NUM; i++) { if ((uint32_t)_mem_pool[i] == (uint32_t)sitd) { mem_debug("[FREE] [siTD] - 0x%x\n", (int)sitd); _unit_used[i] = 0; _mem_pool_used--; return; } } USB_error("free_ehci_siTD 0x%x - not found!\n", (int)sitd); }
UDEV_T * alloc_device(void) { UDEV_T *udev; udev = (UDEV_T *)USB_malloc(sizeof(*udev), 16); if (udev == NULL) { USB_error("alloc_device failed!\n"); return NULL; } memset(udev, 0, sizeof(*udev)); memory_counter(sizeof(*udev)); udev->cur_conf = -1; /* must! used to identify the first SET CONFIGURATION */ udev->next = g_udev_list; /* chain to global device list */ g_udev_list = udev; return udev; }
ED_T * alloc_ohci_ED(void) { int i; ED_T *ed; for (i = 0; i < MEM_POOL_UNIT_NUM; i++) { if (_unit_used[i] == 0) { _unit_used[i] = 1; _mem_pool_used++; ed = (ED_T *)_mem_pool[i]; memset(ed, 0, sizeof(*ed)); mem_debug("[ALLOC] [ED] - 0x%x\n", (int)ed); return ed; } } USB_error("alloc_ohci_ED failed!\n"); return NULL; }
/*--------------------------------------------------------------------------*/ siTD_T * alloc_ehci_siTD(void) { int i; siTD_T *sitd; for (i = (_sidx+1) % MEM_POOL_UNIT_NUM; i != _sidx; i = (i+1) % MEM_POOL_UNIT_NUM) { if (_unit_used[i] == 0) { _unit_used[i] = 1; _sidx = i; _mem_pool_used ++; sitd = (siTD_T *)_mem_pool[i]; memset(sitd, 0, sizeof(*sitd)); mem_debug("[ALLOC] [siTD] - 0x%x\n", (int)sitd); return sitd; } } USB_error("alloc_ehci_siTD failed!\n"); return NULL; }
/*--------------------------------------------------------------------------*/ TD_T * alloc_ohci_TD(UTR_T *utr) { int i; TD_T *td; for (i = 0; i < MEM_POOL_UNIT_NUM; i++) { if (_unit_used[i] == 0) { _unit_used[i] = 1; _mem_pool_used++; td = (TD_T *)_mem_pool[i]; memset(td, 0, sizeof(*td)); td->utr = utr; mem_debug("[ALLOC] [TD] - 0x%x\n", (int)td); return td; } } USB_error("alloc_ohci_TD failed!\n"); return NULL; }
/*--------------------------------------------------------------------------*/ iTD_T * alloc_ehci_iTD(void) { int i; iTD_T *itd; for (i = (_sidx+1) % MEM_POOL_UNIT_NUM; i != _sidx; i = (i+1) % MEM_POOL_UNIT_NUM) { if (i+2 >= MEM_POOL_UNIT_NUM) continue; if ((_unit_used[i] == 0) && (_unit_used[i+1] == 0)) { _unit_used[i] = _unit_used[i+1] = 1; _sidx = i+1; _mem_pool_used += 2; itd = (iTD_T *)_mem_pool[i]; memset(itd, 0, sizeof(*itd)); mem_debug("[ALLOC] [iTD] - 0x%x\n", (int)itd); return itd; } } USB_error("alloc_ehci_iTD failed!\n"); return NULL; }
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_port_wait_reset(USB_DEV_T *hub, int port, USB_DEV_T *dev, uint32_t delay) { int delay_time, ret; uint16_t portchange, portstatus; USB_PORT_STATUS_T portsts; for (delay_time = 0; delay_time < HUB_RESET_TIMEOUT; delay_time += delay) { /* wait to give the device a chance to reset */ usbh_mdelay(delay); /* read and decode port status */ ret = usb_get_port_status(hub, port + 1, &portsts); if(ret < 0) { USB_error("Error - get_port_status(%d) failed (err = %d)\n", port + 1, ret); return -1; } portstatus = portsts.wPortStatus; portchange = portsts.wPortChange; USB_info("port %d of hub %d, portstatus %x, change %x, %s\n", port + 1, hub->devnum, portstatus, portchange, portstatus & (1 << USB_PORT_FEAT_LOWSPEED) ? "1.5 Mb/s" : "12 Mb/s"); if((portchange & USB_PORT_STAT_C_CONNECTION) || !(portstatus & USB_PORT_STAT_CONNECTION)) return -1; /* if we have finished resetting, then break out of the loop */ if(!(portstatus & USB_PORT_STAT_RESET) && (portstatus & USB_PORT_STAT_ENABLE)) { if(portstatus & USB_PORT_STAT_HIGH_SPEED) { USB_debug("Device is high speed!\n"); dev->speed = USB_SPEED_HIGH; } else if(portstatus & USB_PORT_STAT_LOW_SPEED) { USB_debug("Device is low speed!\n"); dev->speed = USB_SPEED_LOW; } else { USB_debug("Device is full speed!\n"); dev->speed = USB_SPEED_FULL; } dev->slow = (portstatus & USB_PORT_STAT_LOW_SPEED) ? 1 : 0; return 0; } /* switch to the long delay after two short delay failures */ if(delay_time >= 2 * HUB_SHORT_RESET_TIME) delay = HUB_LONG_RESET_TIME; USB_info("port %d of hub %d not reset yet, waiting %dms\n", port + 1, hub->devnum, delay); } return -1; }
static void usb_hub_port_connect_change(USB_HUB_T *hubstate, USB_DEV_T *hub, int port, USB_PORT_STATUS_T *portsts) { USB_DEV_T *dev; uint16_t portstatus; // portchange; uint32_t delay = HUB_SHORT_RESET_TIME; int i; portstatus = portsts->wPortStatus; //portchange = portsts->wPortChange; //USB_info("usb_hub_port_connect_change - port %d, portstatus %x, change %x, %s\n", port + 1, portstatus, // portchange, portstatus & (1 << USB_PORT_FEAT_LOWSPEED) ? "1.5 Mb/s" : "12 Mb/s"); /* Clear the connection change status */ usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION); /* Disconnect any existing devices under this port */ if(hub->children[port]) usbh_disconnect_device(&hub->children[port]); /* Return now if nothing is connected */ if(!(portstatus & USB_PORT_STAT_CONNECTION)) { if(portstatus & USB_PORT_STAT_ENABLE) usb_hub_port_disable(hub, port); return; } if(portstatus & USB_PORT_STAT_LOW_SPEED) { usbh_mdelay(400); delay = HUB_LONG_RESET_TIME; } for(i = 0; i < HUB_PROBE_TRIES; i++) { /* Allocate a new device struct */ dev = usbh_alloc_device(hub, hub->bus); if(!dev) { USB_error("Error - couldn't allocate usb_device\n"); break; } dev->hub_port = port; hub->children[port] = dev; if(usb_hub_port_reset(hub, port, dev, delay)) { usbh_free_device(dev); break; } /* Find a new device ID for it */ usbh_connect_device(dev); USB_debug("USB new device connect, assigned device number %d\n", dev->devnum); /* Run it through the hoops (find a driver, etc) */ if(usbh_settle_new_device(dev) == 0) return; // OK. /* Free the configuration if there was an error */ usbh_free_device(dev); /* Switch to a long reset time */ delay = HUB_LONG_RESET_TIME; } hub->children[port] = NULL; usb_hub_port_disable(hub, port); }
static int hub_probe(USB_DEV_T *dev, USB_IF_DESC_T *ifd, const USB_DEV_ID_T *id) { EP_INFO_T *ep_info; USB_HUB_T *hub; int ifnum; int i; USB_debug("hub_probe - dev=0x%x\n", (int)dev); ifnum = ifd->bInterfaceNumber; if(dev->descriptor.bDeviceClass != 0x09) return USB_ERR_NODEV; ep_info = NULL; for(i = 0; i < dev->ep_list_cnt; i++) { if((dev->ep_list[i].ifnum == ifnum) && ((dev->ep_list[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) { ep_info = &dev->ep_list[i]; break; } } if(ep_info == NULL) { USB_error("hub int ep not found!\n"); return USB_ERR_NODEV; } /* Output endpoint? Curiousier and curiousier.. */ if(!(ep_info->bEndpointAddress & USB_DIR_IN)) { USB_error("Error - Device #%d is hub class, but has output endpoint?\n", dev->devnum); return USB_ERR_NODEV; } /* If it's not an interrupt endpoint, we'd better punt! */ if((ep_info->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) { USB_error("Error - Device #%d is hub class, but has endpoint other than interrupt?\n", dev->devnum); return USB_ERR_NODEV; } /* We found a hub */ USB_debug("USB hub found\n"); hub = usbh_alloc_hubdev(); if(!hub) return USB_ERR_NOMEM; INIT_LIST_HEAD(&hub->event_list); hub->dev = dev; if(usb_hub_configure(hub, ep_info) == 0) return 0; USB_error("Error - hub configuration failed for device #%d\n", dev->devnum); /* Delete it and then reset it */ list_del(&hub->event_list); INIT_LIST_HEAD(&hub->event_list); usbh_free_hubdev(hub); return USB_ERR_NODEV; }
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; }