Esempio n. 1
0
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;
}
Esempio n. 2
0
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();
}
Esempio n. 3
0
/*--------------------------------------------------------------------------*/
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;
}
Esempio n. 4
0
/*--------------------------------------------------------------------------*/
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;
}
Esempio n. 5
0
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);
}
Esempio n. 6
0
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;
}
Esempio n. 7
0
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;
}
Esempio n. 8
0
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);
}
Esempio n. 9
0
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;
}
Esempio n. 10
0
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;
}
Esempio n. 11
0
/*--------------------------------------------------------------------------*/
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;
}
Esempio n. 12
0
/*--------------------------------------------------------------------------*/
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;
}
Esempio n. 13
0
/*--------------------------------------------------------------------------*/
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;
}
Esempio n. 14
0
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;
}
Esempio n. 15
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;
}
Esempio n. 16
0
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);
}
Esempio n. 17
0
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;
}
Esempio n. 18
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;
}