Example #1
0
void usb_hub_port_connect_change(struct usb_device *dev, int port)
{
	struct usb_device *usb;
	ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1);
	unsigned short portstatus;

	/* Check status */
	if (usb_get_port_status(dev, port + 1, portsts) < 0) {
		USB_HUB_PRINTF("get_port_status failed\n");
		return;
	}

	portstatus = le16_to_cpu(portsts->wPortStatus);
	USB_HUB_PRINTF("portstatus %x, change %x, %s\n",
			portstatus,
			le16_to_cpu(portsts->wPortChange),
			portspeed(portstatus));

	/* Clear the connection change status */
	usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_CONNECTION);

	/* Disconnect any existing devices under this port */
	if (((!(portstatus & USB_PORT_STAT_CONNECTION)) &&
	     (!(portstatus & USB_PORT_STAT_ENABLE))) || (dev->children[port])) {
		USB_HUB_PRINTF("usb_disconnect(&hub->children[port]);\n");
		/* Return now if nothing is connected */
		if (!(portstatus & USB_PORT_STAT_CONNECTION))
			return;
	}

	/* Reset the port */
	if (hub_port_reset(dev, port, &portstatus) < 0) {
		printf("cannot reset port %i!?\n", port + 1);
		return;
	}

	/* Allocate a new device struct for it */
	usb = usb_alloc_new_device(dev->controller);

	if (portstatus & USB_PORT_STAT_HIGH_SPEED)
		usb->speed = USB_SPEED_HIGH;
	else if (portstatus & USB_PORT_STAT_LOW_SPEED)
		usb->speed = USB_SPEED_LOW;
	else
		usb->speed = USB_SPEED_FULL;

	dev->children[port] = usb;
	usb->parent = dev;
	usb->portnr = port + 1;
	/* Run it through the hoops (find a driver, etc) */
	if (usb_new_device(usb)) {
		/* Woops, disable the port */
		usb_free_device();
		dev->children[port] = NULL;
		USB_HUB_PRINTF("hub: disabling port %d\n", port + 1);
		usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_ENABLE);
	}
}
Example #2
0
struct usb_device *usb_poll_hub_port( struct rt_urb *p_urb, __u8 hub_port_nr )
{
  struct usb_device *p_new_dev  = NULL;
  portstat_t p_pstat;
  struct rt_urb *p_urb_save     = NULL;
  struct usb_device *p_usbdev_save = NULL;

  if(! p_urb || !p_urb->p_usbdev || !p_urb->p_usbdev->p_hcd){
    if (!p_urb)                           ERR("[ERROR] %s - Invalid URB-Pointer \n", __FUNCTION__);
    if (!p_urb->p_usbdev)                 ERR("[ERROR] %s - Invalid USB-Device-Pointer \n", __FUNCTION__);
    if (!p_urb->p_usbdev->p_hcd)          ERR("[ERROR] %s - Invalid Host-Controller-Pointer \n", __FUNCTION__);
    return NULL;
  }

  if (hub_get_portstat( p_urb, hub_port_nr, &p_pstat)){
    ERR_MSG2(p_urb->p_hcd,p_urb->p_usbdev," %s - Get Portstat for Port[%d] failed \n",__FUNCTION__, hub_port_nr);
    return NULL;
  }

  dump_portstatus( p_urb->p_usbdev, hub_port_nr, &p_pstat);

  if( p_pstat.change.c_port_connection ) {  /* Connection detect */
    if( hub_clear_port_feature( p_urb , hub_port_nr, C_PORT_CONNECTION) ){
      return NULL;
    }
    if( p_pstat.stat.port_connection){

      hub_port_resume( p_urb ,hub_port_nr);
      hub_port_reset( p_urb ,hub_port_nr);
      udelay(10);

      // unregister hub_urb
      p_urb_save    = p_urb;
      p_usbdev_save = p_urb->p_usbdev;
      nrt_usb_unregister_urb(p_urb);

      p_new_dev = nrt_usb_config_dev( p_urb->p_hcd, p_urb->p_usbdev->rh_port, p_pstat.stat.port_lowspeed);

      // re-register hub_urb
      p_urb = p_urb_save;
      p_urb->p_usbdev = p_usbdev_save;
      p_urb->p_hcd = p_usbdev_save->p_hcd;
      nrt_usb_register_urb(p_urb);

      return p_new_dev;

    }

    hub_set_port_feature(   p_urb, hub_port_nr, PORT_SUSPEND );
    hub_clear_port_feature( p_urb, hub_port_nr, PORT_ENABLE  );

  }

  return NULL;
}
Example #3
0
static void usb_hub_port_connect_change(struct usb_device *dev, int port)
{
	struct usb_device *usb;
	struct usb_port_status portsts;
	unsigned short portstatus, portchange;

	/* Check status */
	if (usb_get_port_status(dev, port + 1, &portsts) < 0) {
		dev_dbg(&dev->dev, "get_port_status failed\n");
		return;
	}

	portstatus = le16_to_cpu(portsts.wPortStatus);
	portchange = le16_to_cpu(portsts.wPortChange);
	dev_dbg(&dev->dev, "portstatus %x, change %x, %s\n",
			portstatus, portchange, portspeed(portstatus));

	/* Clear the connection change status */
	usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_CONNECTION);

	/* Disconnect any existing devices under this port */
	if (dev->children[port] && !(portstatus & USB_PORT_STAT_CONNECTION)) {
		dev_dbg(&dev->dev, "disconnect detected on port %d\n", port + 1);
		usb_remove_device(dev->children[port]);

		if (!dev->parent && dev->host->usbphy)
			usb_phy_notify_disconnect(dev->host->usbphy, dev->speed);

		return;
	}

	/* Remove disabled but connected devices */
	if (dev->children[port] && !(portstatus & USB_PORT_STAT_ENABLE))
		usb_remove_device(dev->children[port]);

	mdelay(200);

	/* Reset the port */
	if (hub_port_reset(dev, port, &portstatus) < 0) {
		dev_warn(&dev->dev, "cannot reset port %i!?\n", port + 1);
		return;
	}

	mdelay(200);

	/* Allocate a new device struct for it */
	usb = usb_alloc_new_device();
	usb->dev.parent = &dev->dev;
	usb->host = dev->host;

	if (portstatus & USB_PORT_STAT_HIGH_SPEED)
		usb->speed = USB_SPEED_HIGH;
	else if (portstatus & USB_PORT_STAT_LOW_SPEED)
		usb->speed = USB_SPEED_LOW;
	else
		usb->speed = USB_SPEED_FULL;

	dev->children[port] = usb;
	usb->parent = dev;
	usb->portnr = port + 1;

	/* Run it through the hoops (find a driver, etc) */
	if (usb_new_device(usb)) {
		/* Woops, disable the port */
		dev_dbg(&dev->dev, "hub: disabling port %d\n", port + 1);
		usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_ENABLE);
		usb_free_device(usb);
		return;
	}

	if (!dev->parent && dev->host->usbphy)
		usb_phy_notify_connect(dev->host->usbphy, usb->speed);

	device_detect(&usb->dev);
}
Example #4
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);
}
Example #5
0
/*
 * WARNING - If a driver calls usb_reset_device, you should simulate a
 * disconnect() and probe() for other interfaces you doesn't claim. This
 * is left up to the driver writer right now. This insures other drivers
 * have a chance to re-setup their interface.
 *
 * Take a look at proc_resetdevice in devio.c for some sample code to
 * do this.
 * Use this only from within your probe function, otherwise use
 * usb_reset_device() below, which ensure proper locking
 */
int usb_physical_reset_device(struct usb_device *dev)
{
    struct usb_device *parent = dev->parent;
    struct usb_device_descriptor *descriptor;
    int i, ret, port = -1;

    if (!parent) {
        err("attempting to reset root hub!");
        return -EINVAL;
    }

    for (i = 0; i < parent->maxchild; i++)
        if (parent->children[i] == dev) {
            port = i;
            break;
        }

    if (port < 0)
        return -ENOENT;

    descriptor = kmalloc(sizeof *descriptor, GFP_NOIO);
    if (!descriptor) {
        return -ENOMEM;
    }

    down(&usb_address0_sem);

    /* Send a reset to the device */
    if (hub_port_reset(parent, port, dev, HUB_SHORT_RESET_TIME)) {
        hub_port_disable(parent, port);
        up(&usb_address0_sem);
        kfree(descriptor);
        return(-ENODEV);
    }

    /* Reprogram the Address */
    ret = usb_set_address(dev);
    if (ret < 0) {
        err("USB device not accepting new address (error=%d)", ret);
        hub_port_disable(parent, port);
        up(&usb_address0_sem);
        kfree(descriptor);
        return ret;
    }

    /* Let the SET_ADDRESS settle */
    wait_ms(10);

    up(&usb_address0_sem);

    /*
     * Now we fetch the configuration descriptors for the device and
     * see if anything has changed. If it has, we dump the current
     * parsed descriptors and reparse from scratch. Then we leave
     * the device alone for the caller to finish setting up.
     *
     * If nothing changed, we reprogram the configuration and then
     * the alternate settings.
     */

    ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, descriptor,
                             sizeof(*descriptor));
    if (ret < 0) {
        kfree(descriptor);
        return ret;
    }

    le16_to_cpus(&descriptor->bcdUSB);
    le16_to_cpus(&descriptor->idVendor);
    le16_to_cpus(&descriptor->idProduct);
    le16_to_cpus(&descriptor->bcdDevice);

    if (memcmp(&dev->descriptor, descriptor, sizeof(*descriptor))) {
        kfree(descriptor);
        usb_destroy_configuration(dev);

        ret = usb_get_device_descriptor(dev);
        if (ret < sizeof(dev->descriptor)) {
            if (ret < 0)
                err("unable to get device %s descriptor "
                    "(error=%d)", dev->devpath, ret);
            else
                err("USB device %s descriptor short read "
                    "(expected %Zi, got %i)",
                    dev->devpath,
                    sizeof(dev->descriptor), ret);

            clear_bit(dev->devnum, dev->bus->devmap.devicemap);
            dev->devnum = -1;
            return -EIO;
        }

        ret = usb_get_configuration(dev);
        if (ret < 0) {
            err("unable to get configuration (error=%d)", ret);
            usb_destroy_configuration(dev);
            clear_bit(dev->devnum, dev->bus->devmap.devicemap);
            dev->devnum = -1;
            return 1;
        }

        dev->actconfig = dev->config;
        usb_set_maxpacket(dev);

        return 1;
    }

    kfree(descriptor);

    ret = usb_set_configuration(dev, dev->actconfig->desc.bConfigurationValue);
    if (ret < 0) {
        err("failed to set dev %s active configuration (error=%d)",
            dev->devpath, ret);
        return ret;
    }

    for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
        struct usb_interface *intf = &dev->actconfig->interface[i];
        struct usb_interface_descriptor *as;

        as = &intf->altsetting[intf->act_altsetting].desc;
        ret = usb_set_interface(dev, as->bInterfaceNumber,
                                as->bAlternateSetting);
        if (ret < 0) {
            err("failed to set active alternate setting "
                "for dev %s interface %d (error=%d)",
                dev->devpath, i, ret);
            return ret;
        }
    }

    return 0;
}