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); } }
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; }
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); }
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); }
/* * 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; }