示例#1
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);
}
示例#2
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;
}