static int usbhub_dumpbus1(usbdev_t *dev,void *arg) { uint32_t *verbose = (uint32_t *) arg; if ((*verbose & 0x00FF) && (dev->ud_address != (*verbose & 0x00FF))) return 0; if (*verbose & 0x100) { printf("============================================================================\n"); } printf("Bus %d Device %d Class %d Vendor %04X Product %04X ", dev->ud_bus->ub_num, dev->ud_address, dev->ud_devdescr.bDeviceClass, GETUSBFIELD(&(dev->ud_devdescr),idVendor), GETUSBFIELD(&(dev->ud_devdescr),idProduct)); if (IS_HUB(dev)) { printf("[HUB]\n"); } else { printf("[DEVICE]\n"); } if (*verbose & 0x100) { usb_dbg_dumpdescriptors(dev,(uint8_t *) &(dev->ud_devdescr),dev->ud_devdescr.bLength); usb_dbg_dumpcfgdescr(dev); } return 0; }
static int usbhub_detach(usbdev_t *dev) { usbhub_softc_t *hub; usbdev_t *deldev; int idx; if (!IS_HUB(dev)) return 0; /* should not happen */ hub = dev->ud_private; for (idx = 0; idx < UHUB_MAX_DEVICES; idx++) { deldev = hub->uhub_devices[idx]; if (deldev) { console_log("USB: Removing device attached to bus %d hub %d port %d", dev->ud_bus->ub_num, dev->ud_address,idx+1); if (deldev->ud_drv) { (*(deldev->ud_drv->udrv_detach))(deldev); } else { if (usb_noisy > 0) { console_log("USB: Detached device on bus %d hub %d port %d " "has no methods", dev->ud_bus->ub_num, dev->ud_address,idx+1); } } if (deldev->ud_cfgdescr) KFREE(deldev->ud_cfgdescr); usb_destroy_device(deldev); } } KFREE(hub); /* remove softc */ return 0; }
static int usbhub_detach(usbdev_t *dev) { usbhub_softc_t *hub; usbdev_t *deldev; int idx; if (!IS_HUB(dev)) return 0; /* should not happen */ hub = dev->ud_private; for (idx = 0; idx < UHUB_MAX_DEVICES; idx++) { deldev = hub->uhub_devices[idx]; if (deldev) { if (usb_noisy > 0) console_log("USB: Removing device attached to bus %d hub %d port %d", dev->ud_bus->ub_num, dev->ud_address,idx+1); if (deldev->ud_drv) { /* close open pipes, cancel reqs */ usb_destroy_all_pipes(deldev); /* * Try to process the done queue. This will complete any * requests that made it out of the pipes while we were * doing the stuff above. */ usb_poll(deldev->ud_bus); /* Call detach method, clean up device softc */ (*(deldev->ud_drv->udrv_detach))(deldev); } else { if (usb_noisy > 0) { console_log("USB: Detached device on bus %d hub %d port %d " "has no methods", dev->ud_bus->ub_num, dev->ud_address,idx+1); } } if (deldev->ud_cfgdescr) usb_dma_free(deldev->ud_cfgdescr); usb_destroy_device(deldev); } } if (hub->uhub_imsg != NULL) { usb_dma_free(hub->uhub_imsg); } KFREE(hub); /* remove softc */ return 0; }
static void usbhub_map_tree1(usbdev_t *dev,int level, int (*func)(usbdev_t *dev,void *arg),void *arg) { usbhub_softc_t *hub; int idx; (*func)(dev,arg); if (IS_HUB(dev)) { hub = dev->ud_private; for (idx = 0; idx < UHUB_MAX_DEVICES; idx++) { if (hub->uhub_devices[idx]) { usbhub_map_tree1(hub->uhub_devices[idx],level+1,func,arg); } } } }
static int usbhub_scan1(usbdev_t *dev,void *arg) { usbhub_softc_t *hub; /* * If the device is not a hub, we've reached the leaves of the * tree. */ if (!IS_HUB(dev)) return 0; /* * Otherwise, scan the ports on this hub. */ hub = dev->ud_private; if (hub->uhub_flags & UHUB_FLG_NEEDSCAN) { hub->uhub_flags &= ~UHUB_FLG_NEEDSCAN; usbhub_scan_ports(dev,arg); } return 0; }
static void usbhub_scan_ports(usbdev_t *dev,void *arg) { uint16_t current; uint16_t changed; usbhub_softc_t *softc; int idx; int res; int len; uint8_t *buf; usbdev_t *newdev; usb_driver_t *newdrv; int addr; usb_port_status_t *portstatus; usb_config_descr_t cfgdescr; unsigned int powerondelay; if (!IS_HUB(dev)) return; /* should not happen. */ portstatus = usb_dma_alloc(sizeof(usb_port_status_t)); if (portstatus == NULL) return; /* * We know this is a hub. Get the softc back. */ softc = (usbhub_softc_t *) dev->ud_private; powerondelay = ((unsigned int) softc->uhub_descr.bPowerOnToPowerGood)*2 + 20; /* * Turn on the power to the ports whose power is not yet on. */ for (idx = 0; idx < softc->uhub_nports; idx++) { usbhub_get_port_status(dev,idx+1,portstatus); current = GETUSBFIELD(portstatus,wPortStatus); changed = GETUSBFIELD(portstatus,wPortChange); if (usb_noisy > 1) { printf("BeforePowerup: port %d status %04X changed %04X\n",idx+1,current,changed); } if (!(current & USB_PORT_STATUS_POWER)) { if (usb_noisy > 1) console_log("USB: Powering up bus %d port %d", dev->ud_bus->ub_num,idx+1); usbhub_set_port_feature(dev,idx+1,USB_PORT_FEATURE_POWER); usb_delay_ms(dev->ud_bus,powerondelay); } } /* * Begin exploration at this level. */ for (idx = 0; idx < softc->uhub_nports; idx++) { usbhub_get_port_status(dev,idx+1,portstatus); current = GETUSBFIELD(portstatus,wPortStatus); changed = GETUSBFIELD(portstatus,wPortChange); if (usb_noisy > 0) { printf("USB: Explore: Bus %d Hub %d port %d status %04X changed %04X\n", dev->ud_bus->ub_num, dev->ud_address,idx+1,current,changed); usb_dbg_dumpportstatus(idx+1,portstatus,1); } // if (changed & USB_PORT_STATUS_RESET) { // usbhub_clear_port_feature(dev,idx+1,USB_PORT_FEATURE_C_PORT_RESET); // } if (changed & USB_PORT_STATUS_ENABLED) { usbhub_clear_port_feature(dev,idx+1,USB_PORT_FEATURE_C_PORT_ENABLE); } if (changed & USB_PORT_STATUS_CONNECT) { /* * A device was either connected or disconnected. * Clear the status change first. */ usbhub_clear_port_feature(dev,idx+1,USB_PORT_FEATURE_C_PORT_CONNECTION); if (current & USB_PORT_STATUS_CONNECT) { /* * The device has been CONNECTED. */ console_log("USB: New device connected to bus %d hub %d port %d", dev->ud_bus->ub_num, dev->ud_address,idx+1); /* * Reset the device. Reuse our old port status structure * so we get the latest status. Some devices do not report * lowspeed until they are reset. */ usbhub_reset_device(dev,idx+1,portstatus); current = GETUSBFIELD(portstatus,wPortStatus); changed = GETUSBFIELD(portstatus,wPortChange); /* * Create a device for this port. */ newdev = usb_create_device(dev->ud_bus,(current & USB_PORT_STATUS_LOWSPD) ? 1 : 0); /* * Get the device descriptor. */ res = usb_get_device_descriptor(newdev,&newdev->ud_devdescr,TRUE); if (usb_noisy > 1) usb_dbg_dumpdescriptors(newdev,(uint8_t *) &(newdev->ud_devdescr),8); /* * Set up the max packet size for the control endpoint, * then get the rest of the descriptor. */ usb_set_ep0mps(newdev,newdev->ud_devdescr.bMaxPacketSize0); res = usb_get_device_descriptor(newdev,&newdev->ud_devdescr,FALSE); /* * Obtain a new address and set the address of the * root hub to this address. */ addr = usb_new_address(newdev->ud_bus); res = usb_set_address(newdev,addr); /* * Get the configuration descriptor and all the * associated interface and endpoint descriptors. */ res = usb_get_config_descriptor(newdev,&cfgdescr,0, sizeof(usb_config_descr_t)); if (res != sizeof(usb_config_descr_t)) { printf("[a] usb_get_config_descriptor returns %d\n",res); } len = GETUSBFIELD(&cfgdescr,wTotalLength); buf = usb_dma_alloc(len); res = usb_get_config_descriptor(newdev,(usb_config_descr_t *)buf,0,len); if (res != len) { printf("[b] usb_get_config_descriptor returns %d\n",res); } newdev->ud_cfgdescr = (usb_config_descr_t *) buf; if (usb_noisy > 1) usb_dbg_dumpdescriptors(newdev,buf,len); /* * Point the hub at the devices it owns */ softc->uhub_devices[idx] = newdev; /* * Find the driver for this. It had better be the hub * driver. */ newdrv = usb_find_driver(newdev); /* * Call the attach method. */ if (newdrv) { newdev->ud_drv = newdrv; /* remember driver dispatch in device */ (*(newdrv->udrv_attach))(newdev,newdrv); } } else { /* * The device has been DISCONNECTED. */ console_log("USB: Device disconnected from bus %d hub %d port %d", dev->ud_bus->ub_num, dev->ud_address,idx+1); /* * Recover pointer to device below hub and clear * this pointer. */ newdev = softc->uhub_devices[idx]; /* Get device pointer */ usbhub_markdetached(newdev); /* mark device and all subordinate devices as "removing" */ softc->uhub_devices[idx] = NULL; /* remove device from hub */ /* * Deassign the USB device's address and then * call detach method to free resources. Devices that * do not have drivers will not have any methods. */ if (newdev) { if (newdev->ud_drv) { /* close open pipes, cancel reqs */ usb_destroy_all_pipes(newdev); /* * Try to process the done queue. This will complete any * requests that made it out of the pipes while we were * doing the stuff above. */ usb_poll(newdev->ud_bus); /* Call detach method, clean up device softc */ (*(newdev->ud_drv->udrv_detach))(newdev); } else { if (usb_noisy > 0) { console_log("USB: Detached device on bus %d hub %d port %d " "has no methods", dev->ud_bus->ub_num, dev->ud_address,idx+1); } } if (newdev->ud_cfgdescr) usb_dma_free(newdev->ud_cfgdescr); usb_destroy_device(newdev); } } } } usb_dma_free(portstatus); /* * Queue up a request for the interrupt pipe. This will catch further * changes at this port. */ usbhub_queue_intreq(dev,softc); }