static void ush_hsic_port_disable(void)
{
	hsic_enable = 0;
	if ((hsic.modem_dev) && (hsic.autosuspend_enable != 0)) {
		dev_dbg(&pci_dev->dev,
			"Disable auto suspend in port disable\n");
		usb_disable_autosuspend(hsic.modem_dev);
		usb_disable_autosuspend(hsic.rh_dev);
		hsic.autosuspend_enable = 0;
	}

	if (hsic.rh_dev) {
		if (hsic.autosuspend_enable != 0) {
			dev_dbg(&pci_dev->dev,
			"Disable auto suspend in port disable\n");
			usb_disable_autosuspend(hsic.rh_dev);
			hsic.autosuspend_enable = 0;
		}
		clear_port_feature(hsic.rh_dev, HSIC_USH_PORT,
				USB_PORT_FEAT_POWER);
		usb_enable_autosuspend(hsic.rh_dev);
		hsic.autosuspend_enable = 1;
	}
	s3_wake_unlock();
}
static void ush_hsic_port_disable(struct pci_dev *pdev)
{
	printk(KERN_ERR "%s---->\n", __func__);
#if 1
	if (hsic.modem_dev) {
		struct usb_device *hdev;

		dev_dbg(&pci_dev->dev,
			"%s----> disconnect modem\n", __func__);
		hdev = hsic.modem_dev->parent;
		usb_disable_autosuspend(hsic.modem_dev);
		usb_disable_autosuspend(hsic.rh_dev);
		if (hdev->children[HSIC_USH_PORT - 1] == hsic.modem_dev) {
			printk(KERN_ERR "%s----> usb disconnect\n", __func__);
			usb_disconnect(&hsic.modem_dev);
			hdev->children[HSIC_USH_PORT - 1] = NULL;
		}
	}
#endif
	if (hsic.rh_dev) {
		dev_dbg(&pci_dev->dev,
			"%s----> disable port\n", __func__);
		printk(KERN_ERR "%s----> disable PP\n", __func__);
		clear_port_feature(hsic.rh_dev, HSIC_USH_PORT,
				USB_PORT_FEAT_POWER);
	}
	hsic.hsic_stopped = 1;
	hsic_enable = 0;
}
Пример #3
0
// Disable port
static void
usb_hub_disconnect(struct usbhub_s *hub, u32 port)
{
    int ret = clear_port_feature(hub, port, USB_PORT_FEAT_ENABLE);
    if (ret)
        dprintf(1, "Failure on hub port %d disconnect\n", port);
}
Пример #4
0
/* return: -1 on error, 0 on success, 1 on disconnect.  */
static int hub_port_reset(struct usb_device *hub, int port,
                          struct usb_device *dev, unsigned int delay)
{
    int i, status;

    /* Reset the port */
    for (i = 0; i < HUB_RESET_TRIES; i++) {
        set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET);

        /* return on disconnect or reset */
        status = hub_port_wait_reset(hub, port, dev, delay);
        if (status != -1) {
            clear_port_feature(hub,
                               port + 1, USB_PORT_FEAT_C_RESET);
            dev->state = status
                         ? USB_STATE_NOTATTACHED
                         : USB_STATE_DEFAULT;
            return status;
        }

        dev_dbg (hubdev (hub),
                 "port %d not enabled, trying reset again...\n",
                 port + 1);
        delay = HUB_LONG_RESET_TIME;
    }

    dev_err (hubdev (hub),
             "Cannot enable port %i.  Maybe the USB cable is bad?\n",
             port + 1);

    return -1;
}
Пример #5
0
int hub_port_disable(struct usb_device *hub, int port)
{
    int ret;

    ret = clear_port_feature(hub, port + 1, USB_PORT_FEAT_ENABLE);
    if (ret)
        dev_err(hubdev(hub), "cannot disable port %d (err = %d)\n",
                port + 1, ret);

    return ret;
}
/**
 * xhci_ush_pci_shutdown - shutdown host controller
 * @dev: USB Host Controller being shutdown
 */
static void xhci_ush_pci_shutdown(struct pci_dev *dev)
{
	struct usb_hcd		*hcd;

	hcd = pci_get_drvdata(dev);
	if (!hcd)
		return;

	if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) &&
			hcd->driver->shutdown) {
		disable_irq(gpio_to_irq(hsic.aux_gpio));
		disable_irq(gpio_to_irq(hsic.wakeup_gpio));
		hcd->driver->shutdown(hcd);
		if (hsic.rh_dev) {
			dev_dbg(&pci_dev->dev,
				"%s: disable port\n", __func__);
			clear_port_feature(hsic.rh_dev, HSIC_USH_PORT,
					USB_PORT_FEAT_POWER);
		}
		pci_disable_device(dev);
	}
}
Пример #7
0
/* return: -1 on error, 0 on success, 1 on disconnect.  */
static int hub_port_debounce(struct usb_device *hub, int port)
{
    int ret;
    int delay_time, stable_count;
    u16 portchange, portstatus;
    unsigned connection;

    connection = 0;
    stable_count = 0;
    for (delay_time = 0; delay_time < HUB_DEBOUNCE_TIMEOUT; delay_time += HUB_DEBOUNCE_STEP) {
        wait_ms(HUB_DEBOUNCE_STEP);

        ret = hub_port_status(hub, port, &portstatus, &portchange);
        if (ret < 0)
            return -1;

        if ((portstatus & USB_PORT_STAT_CONNECTION) == connection) {
            if (connection) {
                if (++stable_count == HUB_DEBOUNCE_STABLE)
                    break;
            }
        } else {
            stable_count = 0;
        }
        connection = portstatus & USB_PORT_STAT_CONNECTION;

        if ((portchange & USB_PORT_STAT_C_CONNECTION)) {
            clear_port_feature(hub, port+1, USB_PORT_FEAT_C_CONNECTION);
        }
    }

    /* XXX Replace this with dbg() when 2.6 is about to ship. */
    dev_dbg (hubdev (hub),
             "debounce: port %d: delay %dms stable %d status 0x%x\n",
             port + 1, delay_time, stable_count, portstatus);

    return ((portstatus&USB_PORT_STAT_CONNECTION)) ? 0 : 1;
}
Пример #8
0
static void hub_port_connect_change(struct usb_hub *hubstate, int port,
                                    u16 portstatus, u16 portchange)
{
    struct usb_device *hub = interface_to_usbdev(hubstate->intf);
    struct usb_device *dev;
    unsigned int delay = HUB_SHORT_RESET_TIME;
    int i;

    dev_dbg (&hubstate->intf->dev,
             "port %d, status %x, change %x, %s\n",
             port + 1, portstatus, portchange, portspeed (portstatus));

    /* Clear the connection change status */
    clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION);

    /* Disconnect any existing devices under this port */
    if (hub->children[port])
        usb_disconnect(&hub->children[port]);

    /* Return now if nothing is connected */
    if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
        if (portstatus & USB_PORT_STAT_ENABLE)
            hub_port_disable(hub, port);

        return;
    }

    if (hub_port_debounce(hub, port)) {
        dev_err (&hubstate->intf->dev,
                 "connect-debounce failed, port %d disabled\n",
                 port+1);
        hub_port_disable(hub, port);
        return;
    }

    /* Some low speed devices have problems with the quick delay, so */
    /*  be a bit pessimistic with those devices. RHbug #23670 */
    if (portstatus & USB_PORT_STAT_LOW_SPEED)
        delay = HUB_LONG_RESET_TIME;

    down(&usb_address0_sem);

    for (i = 0; i < HUB_PROBE_TRIES; i++) {
        struct usb_device *pdev;
        int	len;

        /* Allocate a new device struct */
        dev = usb_alloc_dev(hub, hub->bus);
        if (!dev) {
            dev_err (&hubstate->intf->dev,
                     "couldn't allocate usb_device\n");
            break;
        }

        hub->children[port] = dev;
        dev->state = USB_STATE_POWERED;

        /* Reset the device, and detect its speed */
        if (hub_port_reset(hub, port, dev, delay)) {
            usb_put_dev(dev);
            break;
        }

        /* Find a new address for it */
        usb_connect(dev);

        /* Set up TT records, if needed  */
        if (hub->tt) {
            dev->tt = hub->tt;
            dev->ttport = hub->ttport;
        } else if (dev->speed != USB_SPEED_HIGH
                   && hub->speed == USB_SPEED_HIGH) {
            dev->tt = &hubstate->tt;
            dev->ttport = port + 1;
        }

        /* Save readable and stable topology id, distinguishing
         * devices by location for diagnostics, tools, etc.  The
         * string is a path along hub ports, from the root.  Each
         * device's id will be stable until USB is re-cabled, and
         * hubs are often labeled with these port numbers.
         *
         * Initial size: ".NN" times five hubs + NUL = 16 bytes max
         * (quite rare, since most hubs have 4-6 ports).
         */
        pdev = dev->parent;
        if (pdev->devpath [0] != '0')	/* parent not root? */
            len = snprintf (dev->devpath, sizeof dev->devpath,
                            "%s.%d", pdev->devpath, port + 1);
        /* root == "0", root port 2 == "2", port 3 that hub "2.3" */
        else
            len = snprintf (dev->devpath, sizeof dev->devpath,
                            "%d", port + 1);
        if (len == sizeof dev->devpath)
            dev_err (&hubstate->intf->dev,
                     "devpath size! usb/%03d/%03d path %s\n",
                     dev->bus->busnum, dev->devnum, dev->devpath);
        dev_info (&hubstate->intf->dev,
                  "new USB device on port %d, assigned address %d\n",
                  port + 1, dev->devnum);

        /* put the device in the global device tree. the hub port
         * is the "bus_id"; hubs show in hierarchy like bridges
         */
        dev->dev.parent = dev->parent->dev.parent->parent;

        /* Run it through the hoops (find a driver, etc) */
        if (!usb_new_device(dev, &hub->dev))
            goto done;

        /* Free the configuration if there was an error */
        usb_put_dev(dev);

        /* Switch to a long reset time */
        delay = HUB_LONG_RESET_TIME;
    }

    hub->children[port] = NULL;
    hub_port_disable(hub, port);
done:
    up(&usb_address0_sem);
}
Пример #9
0
static void hub_events(void)
{
    unsigned long flags;
    struct list_head *tmp;
    struct usb_device *dev;
    struct usb_hub *hub;
    u16 hubstatus;
    u16 hubchange;
    u16 portstatus;
    u16 portchange;
    int i, ret;
    int m=0;
    /*
     *  We restart the list every time 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 (m<5) {
        m++;
        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 = interface_to_usbdev(hub->intf);

        list_del_init(tmp);

        if (unlikely(down_trylock(&hub->khubd_sem)))
            BUG();	/* never blocks, we were on list */

        spin_unlock_irqrestore(&hub_event_lock, flags);

        if (hub->error) {
            dev_dbg (&hub->intf->dev, "resetting for error %d\n",
                     hub->error);

            if (hub_reset(hub)) {
                dev_dbg (&hub->intf->dev,
                         "can't reset; disconnecting\n");
                up(&hub->khubd_sem);
                hub_start_disconnect(dev);
                continue;
            }

            hub->nerrors = 0;
            hub->error = 0;
        }

        for (i = 0; i < hub->descriptor->bNbrPorts; i++) {
            ret = hub_port_status(dev, i, &portstatus, &portchange);
            if (ret < 0) {
                continue;
            }

            if (portchange & USB_PORT_STAT_C_CONNECTION) {
                hub_port_connect_change(hub, i, portstatus, portchange);
            } else if (portchange & USB_PORT_STAT_C_ENABLE) {
                dev_dbg (hubdev (dev),
                         "port %d enable change, status %x\n",
                         i + 1, portstatus);
                clear_port_feature(dev,
                                   i + 1, USB_PORT_FEAT_C_ENABLE);

                /*
                 * EM interference sometimes causes badly
                 * 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])) {
                    dev_err (&hub->intf->dev,
                             "port %i "
                             "disabled by hub (EMI?), "
                             "re-enabling...",
                             i + 1);
                    hub_port_connect_change(hub,
                                            i, portstatus, portchange);
                }
            }

            if (portchange & USB_PORT_STAT_C_SUSPEND) {
                dev_dbg (&hub->intf->dev,
                         "suspend change on port %d\n",
                         i + 1);
                clear_port_feature(dev,
                                   i + 1,  USB_PORT_FEAT_C_SUSPEND);
            }

            if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
                dev_err (&hub->intf->dev,
                         "over-current change on port %d\n",
                         i + 1);
                clear_port_feature(dev,
                                   i + 1, USB_PORT_FEAT_C_OVER_CURRENT);
                hub_power_on(hub);
            }

            if (portchange & USB_PORT_STAT_C_RESET) {
                dev_dbg (&hub->intf->dev,
                         "reset change on port %d\n",
                         i + 1);
                clear_port_feature(dev,
                                   i + 1, USB_PORT_FEAT_C_RESET);
            }
        } /* end for i */

        /* deal with hub status changes */
        if (hub_hub_status(hub, &hubstatus, &hubchange) < 0)
            dev_err (&hub->intf->dev, "get_hub_status failed\n");
        else {
            if (hubchange & HUB_CHANGE_LOCAL_POWER) {
                dev_dbg (&hub->intf->dev, "power change\n");
                clear_hub_feature(dev, C_HUB_LOCAL_POWER);
            }
            if (hubchange & HUB_CHANGE_OVERCURRENT) {
                dev_dbg (&hub->intf->dev, "overcurrent change\n");
                wait_ms(500);	/* Cool down */
                clear_hub_feature(dev, C_HUB_OVER_CURRENT);
                hub_power_on(hub);
            }
        }
        up(&hub->khubd_sem);
    } /* end while (1) */

    spin_unlock_irqrestore(&hub_event_lock, flags);
}