示例#1
0
void free_ohci_ED(ED_T *ed)
{
    int      i;

    for (i = 0; i < MEM_POOL_UNIT_NUM; i++)
    {
        if ((uint32_t)_mem_pool[i] == (uint32_t)ed)
        {
            mem_debug("[FREE]  [ED] - 0x%x\n", (int)ed);
            _unit_used[i] = 0;
            _mem_pool_used--;
            return;
        }
    }
    USB_debug("free_ohci_ED - not found! (ignored in case of multiple UTR)\n");
}
示例#2
0
void free_ehci_QH(QH_T *qh)
{
    int      i;

    for (i = 0; i < MEM_POOL_UNIT_NUM; i++)
    {
        if ((uint32_t)_mem_pool[i] == (uint32_t)qh)
        {
            mem_debug("[FREE]  [QH] - 0x%x\n", (int)qh);
            _unit_used[i] = 0;
            _mem_pool_used--;
            return;
        }
    }
    USB_debug("free_ehci_QH - not found! (ignored in case of multiple UTR)\n");
}
示例#3
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;
}
示例#4
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);
}
示例#5
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;
}
示例#6
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;
}
示例#7
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;
}