/* return: -1 on error, 0 on success, 1 on disconnect. */ static int hub_port_wait_reset(struct usb_device *hub, int port, struct usb_device *dev, unsigned int delay) { int delay_time, ret; u16 portstatus; u16 portchange; for (delay_time = 0; delay_time < HUB_RESET_TIMEOUT; delay_time += delay) { /* wait to give the device a chance to reset */ wait_ms(delay); /* read and decode port status */ ret = hub_port_status(hub, port, &portstatus, &portchange); if (ret < 0) { return -1; } /* Device went away? */ if (!(portstatus & USB_PORT_STAT_CONNECTION)) return 1; /* bomb out completely if something weird happened */ if ((portchange & USB_PORT_STAT_C_CONNECTION)) return -1; /* if we`ve finished resetting, then break out of the loop */ if (!(portstatus & USB_PORT_STAT_RESET) && (portstatus & USB_PORT_STAT_ENABLE)) { if (portstatus & USB_PORT_STAT_HIGH_SPEED) dev->speed = USB_SPEED_HIGH; else if (portstatus & USB_PORT_STAT_LOW_SPEED) dev->speed = USB_SPEED_LOW; else dev->speed = USB_SPEED_FULL; return 0; } /* switch to the long delay after two short delay failures */ if (delay_time >= 2 * HUB_SHORT_RESET_TIME) delay = HUB_LONG_RESET_TIME; dev_dbg (hubdev (hub), "port %d not reset yet, waiting %dms\n", port + 1, delay); } return -1; }
static int list_ports(struct state *st) { struct libusb_device **devs; struct libusb_device *dev; int current; int hub_number; int unknown_hub_number = 0; int ret = 0; if (libusb_get_device_list(st->ctx, &devs) < 0){ perror ("failed to access USB"); return 0; } for (current=0; (dev = devs[current]) != NULL; current++) { struct libusb_device_descriptor device_desc; struct libusb_config_descriptor *config_desc; libusb_device_handle *uh; uint16_t dev_vid, dev_pid; ret = libusb_get_device_descriptor(dev, &device_desc); if (ret) goto err; ret = libusb_get_active_config_descriptor(dev, &config_desc); dev_vid = libusb_le16_to_cpu(device_desc.idVendor); dev_pid = libusb_le16_to_cpu(device_desc.idProduct); if (libusb_open(dev, &uh) != 0 ) continue; if (dev_vid == 0x05e3 && dev_pid == 0x0614) { hub_number = get_hub_number(dev); if (hub_number == 1) printf("Upstream hub - "); else if (hub_number == 2) printf("Downstream hub - "); else printf("Unknown hub %d - ", (++unknown_hub_number)); hub_port_status(uh, hub_number - 1); } libusb_free_config_descriptor(config_desc); libusb_close(uh); } err: libusb_free_device_list(devs, 1); return ret; }
/* 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; }
int main (int argc, const char *argv[]) { int busnum = 0, devnum = 0; int cmd = COMMAND_SET_NONE; int port = 1; int value = 0; int request, feature, index; int result = 0; int listing = 0; int verbose = 0; int hub = -1; libusb_device_handle *uh = NULL; int i; if (argc == 1) listing = 1; for (i = 1; i < argc; i++) if (argv[i][0] == '-') switch (argv[i][1]) { case 'h': if (++i >= argc || busnum > 0 || devnum > 0) exit_with_usage (argv[0]); hub = atoi (argv[i]); break; case 'b': if (++i >= argc || hub >= 0) exit_with_usage (argv[0]); busnum = atoi (argv[i]); break; case 'd': if (++i >= argc || hub >= 0) exit_with_usage (argv[0]); devnum = atoi (argv[i]); break; case 'P': if (++i >= argc) exit_with_usage (argv[0]); port = atoi (argv[i]); break; case 'l': if (cmd != COMMAND_SET_NONE) exit_with_usage (argv[0]); if (++i < argc) value = atoi (argv[i]); else value = HUB_LED_GREEN; cmd = COMMAND_SET_LED; break; case 'p': if (cmd != COMMAND_SET_NONE) exit_with_usage (argv[0]); if (++i < argc) value = atoi (argv[i]); else value= 0; cmd = COMMAND_SET_POWER; break; case 'v': verbose = 1; if (argc == 2) listing = 1; break; default: exit_with_usage (argv[0]); } else exit_with_usage (argv[0]); if ((busnum > 0 && devnum <= 0) || (busnum <= 0 && devnum > 0)) /* BUS is specified, but DEV is'nt, or ... */ exit_with_usage (argv[0]); /* Default is the hub #0 */ if (hub < 0 && busnum == 0) hub = 0; /* Default is POWER */ if (cmd == COMMAND_SET_NONE) cmd = COMMAND_SET_POWER; libusb_init ( &ctx ); libusb_set_debug( ctx, 3 ); if (usb_find_hubs (listing, verbose, busnum, devnum, hub) <= 0) { fprintf (stderr, "No hubs found.\n"); libusb_exit( ctx ); exit (1); } if (listing){ libusb_exit( ctx ); exit (0); } if (hub < 0) hub = get_hub (busnum, devnum); if (hub >= 0 && hub < number_of_hubs_with_feature){ if ( libusb_open (hubs[hub].dev, &uh ) || uh == NULL) { fprintf (stderr, "Device not found.\n"); result = 1; } else { if (cmd == COMMAND_SET_POWER){ if (value){ request = LIBUSB_REQUEST_SET_FEATURE; feature = USB_PORT_FEAT_POWER; index = port; }else{ request = LIBUSB_REQUEST_CLEAR_FEATURE; feature = USB_PORT_FEAT_POWER; index = port; } }else{ request = LIBUSB_REQUEST_SET_FEATURE; feature = USB_PORT_FEAT_INDICATOR; index = (value << 8) | port; } if (verbose) printf ("Send control message (REQUEST=%d, FEATURE=%d, INDEX=%d)\n", request, feature, index); /* if(libusb_detach_kernel_driver( uh, 0 )) perror("libusb_detach_kernel_driver"); if(libusb_claim_interface( uh, 0 )) perror("libusb_claim_interface"); */ if (libusb_control_transfer (uh, USB_RT_PORT, request, feature, index, NULL, 0, CTRL_TIMEOUT) < 0) { perror ("failed to control.\n"); result = 1; } if (verbose) hub_port_status (uh, hubs[hub].nport, hubs[hub].usb3); /* libusb_release_interface( uh,0 ); libusb_attach_kernel_driver( uh, 0); */ libusb_close (uh); } } libusb_exit( ctx ); exit (result); }
static int usb_find_hubs (int listing, int verbose, int busnum, int devnum, int hub) { struct libusb_device **devs; struct libusb_device *dev; int i = 0; int r; number_of_hubs_with_feature = 0; if (libusb_get_device_list( ctx, &devs ) < 0){ perror ("failed to access USB"); return 0; } while ( (dev = devs[i++]) != NULL) { struct libusb_device_descriptor desc; unsigned short dev_vid, dev_pid, dev_bcd; r = libusb_get_device_descriptor(dev, &desc); if (r < 0) { continue; } dev_vid = libusb_le16_to_cpu(desc.idVendor); dev_pid = libusb_le16_to_cpu(desc.idProduct); dev_bcd = libusb_le16_to_cpu(desc.bcdUSB); //wmlog_msg(1, "Bus %03d Device %03d: ID %04x:%04x", libusb_get_bus_number(dev), libusb_get_device_address(dev), dev_vid, dev_pid); libusb_device_handle *uh; int print = 0; int usb3 = (dev_bcd >= 0x0300); //printf("found dev %d\n", dev->descriptor.bDeviceClass); if (desc.bDeviceClass != LIBUSB_CLASS_HUB) continue; if (listing || (verbose )) // && ((atoi (bus->dirname) == busnum && dev->devnum == devnum) // || hub == number_of_hubs_with_feature))) print = 1; if( libusb_open (dev, &uh) != 0 ) continue; /* if(libusb_detach_kernel_driver( uh, 0 )) perror("libusb_detach_kernel_driver"); if(libusb_claim_interface( uh, 0 )) perror("libusb_claim_interface");*/ if ( uh != NULL ) { if (print) printf ("Hub #%d at \tBUS:DEV\t\t%03d:%03d\n\t\tUSB VEND:PROD: \t%04x:%04x\n", number_of_hubs_with_feature, libusb_get_bus_number( dev ), libusb_get_device_address( dev ), dev_vid, dev_pid ); char buf[ sizeof(struct usb_hub_descriptor) + 2*4 ]; int len; int nport; struct usb_hub_descriptor *uhd = (struct usb_hub_descriptor *)buf; if ( (len = libusb_control_transfer ( uh, LIBUSB_ENDPOINT_IN | USB_RT_HUB, LIBUSB_REQUEST_GET_DESCRIPTOR, (usb3 ? LIBUSB_DT_SUPERSPEED_HUB : LIBUSB_DT_HUB)<<8, 0, buf, (int)sizeof ( buf ), CTRL_TIMEOUT ) ) // if( libusb_get_descriptor( uh, LIBUSB_DT_HUB, 0, buf, sizeof(buf) ) >(int)sizeof (struct usb_hub_descriptor) ) { if (!(!(uhd->wHubCharacteristics[0] & HUB_CHAR_PORTIND) && (uhd->wHubCharacteristics[0] & HUB_CHAR_LPSM) >= 2)){ switch ((uhd->wHubCharacteristics[0] & HUB_CHAR_LPSM)) { case 0: if (print) fprintf (stderr, " INFO: ganged switching.\n"); break; case 1: if (print) fprintf (stderr, " INFO: individual power switching.\n"); break; case 2: case 3: if (print) fprintf (stderr, " WARN: No power switching.\n"); break; } if (print && !(uhd->wHubCharacteristics[0] & HUB_CHAR_PORTIND)) fprintf (stderr, " WARN: Port indicators are NOT supported.\n"); } } else { perror ("Can't get hub descriptor."); printf( "%d\n",len ); } if( len > 0 ) { nport = buf[2]; hubs[number_of_hubs_with_feature].busnum = libusb_get_bus_number( dev ); hubs[number_of_hubs_with_feature].devnum = libusb_get_device_address( dev ); hubs[number_of_hubs_with_feature].dev = dev; hubs[number_of_hubs_with_feature].indicator_support = (uhd->wHubCharacteristics[0] & HUB_CHAR_PORTIND)? 1 : 0; hubs[number_of_hubs_with_feature].nport = nport; hubs[number_of_hubs_with_feature].usb3 = usb3; number_of_hubs_with_feature++; if (verbose) hub_port_status (uh, nport, usb3); } /* libusb_release_interface( uh,0 ); libusb_attach_kernel_driver( uh, 0); */ libusb_close (uh); } } libusb_free_device_list( devs, 1 ); return number_of_hubs_with_feature; }
static int usb_find_hubs (int listing, int verbose, int busnum, int devnum, int hub) { struct usb_bus *busses; struct usb_bus *bus; number_of_hubs_with_feature = 0; busses = usb_get_busses(); if (busses == NULL) { perror ("failed to access USB"); return -1; } for (bus = busses; bus; bus = bus->next) { struct usb_device *dev; for (dev = bus->devices; dev; dev = dev->next) { usb_dev_handle *uh; int print = 0; if (dev->descriptor.bDeviceClass != USB_CLASS_HUB) continue; if (listing || (verbose && ((atoi (bus->dirname) == busnum && dev->devnum == devnum) || hub == number_of_hubs_with_feature))) print = 1; uh = usb_open (dev); if (uh != NULL) { char buf[1024]; int len; int nport; struct usb_hub_descriptor *uhd = (struct usb_hub_descriptor *)buf; if ((len = usb_control_msg (uh, USB_DIR_IN | USB_RT_HUB, USB_REQ_GET_DESCRIPTOR, USB_DT_HUB << 8, 0, buf, sizeof (buf), CTRL_TIMEOUT)) > sizeof (struct usb_hub_descriptor)) { if (!(uhd->wHubCharacteristics[0] & HUB_CHAR_PORTIND) && (uhd->wHubCharacteristics[0] & HUB_CHAR_LPSM) >= 2) continue; if (print) printf ("Hub #%d at %s:%03d\n", number_of_hubs_with_feature, bus->dirname, dev->devnum); switch ((uhd->wHubCharacteristics[0] & HUB_CHAR_LPSM)) { case 0: if (print) fprintf (stderr, " INFO: ganged switching.\n"); break; case 1: if (print) fprintf (stderr, " INFO: individual power switching.\n"); break; case 2: case 3: if (print) fprintf (stderr, " WARN: No power switching.\n"); break; } if (print && !(uhd->wHubCharacteristics[0] & HUB_CHAR_PORTIND)) fprintf (stderr, " WARN: Port indicators are NOT supported.\n"); } else { perror ("Can't get hub descriptor"); usb_close (uh); continue; } nport = buf[2]; hubs[number_of_hubs_with_feature].busnum = atoi (bus->dirname); hubs[number_of_hubs_with_feature].devnum = dev->devnum; hubs[number_of_hubs_with_feature].dev = dev; hubs[number_of_hubs_with_feature].indicator_support = (uhd->wHubCharacteristics[0] & HUB_CHAR_PORTIND)? 1 : 0; hubs[number_of_hubs_with_feature].nport = nport; number_of_hubs_with_feature++; if (verbose) hub_port_status (uh, nport); usb_close (uh); } } } return number_of_hubs_with_feature; }
int usb_hub_port1_power_ctr(int value) //main (int argc, const char *argv[]) { int busnum = 0, devnum = 0; int cmd = COMMAND_SET_NONE; int port = 1; //int value = 0; int request, feature, index; int result = 0; int listing = 0; int verbose = 0; int hub = -1; usb_dev_handle *uh = NULL; int i; #if 0 if (argc == 1) listing = 1; for (i = 1; i < argc; i++) if (argv[i][0] == '-') switch (argv[i][1]) { case 'h': if (++i >= argc || busnum > 0 || devnum > 0) exit_with_usage (argv[0]); hub = atoi (argv[i]); break; case 'b': if (++i >= argc || hub >= 0) exit_with_usage (argv[0]); busnum = atoi (argv[i]); break; case 'd': if (++i >= argc || hub >= 0) exit_with_usage (argv[0]); devnum = atoi (argv[i]); break; case 'P': if (++i >= argc) exit_with_usage (argv[0]); port = atoi (argv[i]); break; case 'l': if (cmd != COMMAND_SET_NONE) exit_with_usage (argv[0]); if (++i < argc) value = atoi (argv[i]); else value = HUB_LED_GREEN; cmd = COMMAND_SET_LED; break; case 'p': if (cmd != COMMAND_SET_NONE) exit_with_usage (argv[0]); if (++i < argc) value = atoi (argv[i]); else value= 0; cmd = COMMAND_SET_POWER; break; case 'v': verbose = 1; if (argc == 2) listing = 1; break; default: exit_with_usage (argv[0]); } else exit_with_usage (argv[0]); if ((busnum > 0 && devnum <= 0) || (busnum <= 0 && devnum > 0)) /* BUS is specified, but DEV is'nt, or ... */ exit_with_usage (argv[0]); #else listing = 1; int return_busnum, return_devnum ; int *p_return_busnum = & return_busnum ; int *p_return_devnum = & return_devnum ; #endif /* Default is the hub #0 */ if (hub < 0 && busnum == 0) hub = 0; /* Default is POWER */ if (cmd == COMMAND_SET_NONE) cmd = COMMAND_SET_POWER; usb_init (); usb_find_busses (); usb_find_devices (); if ( usb_find_hubs ( p_return_busnum,p_return_devnum ,listing, verbose, busnum, devnum, hub) //usb_find_hubs (listing, verbose, busnum, devnum, hub) <= 0) { fprintf (stderr, "No hubs found.\n"); exit (1); } else { //printf ("Hub %d:%d\n",return_busnum,return_devnum); busnum=return_busnum; devnum=return_devnum; } #if 0 if (listing) exit (0); #endif if (hub < 0) hub = get_hub (busnum, devnum); if (hub >= 0 && hub < number_of_hubs_with_feature) uh = usb_open (hubs[hub].dev); if (uh == NULL) { fprintf (stderr, "Device not found.\n"); result = 1; } else { if (cmd == COMMAND_SET_POWER) if (value) { request = USB_REQ_SET_FEATURE; feature = USB_PORT_FEAT_POWER; index = port; } else { request = USB_REQ_CLEAR_FEATURE; feature = USB_PORT_FEAT_POWER; index = port; } else { request = USB_REQ_SET_FEATURE; feature = USB_PORT_FEAT_INDICATOR; index = (value << 8) | port; } if (verbose) printf ("Send control message (REQUEST=%d, FEATURE=%d, INDEX=%d)\n", request, feature, index); if (usb_control_msg (uh, USB_RT_PORT, request, feature, index, NULL, 0, CTRL_TIMEOUT) < 0) { perror ("failed to control.\n"); result = 1; } if (verbose) hub_port_status (uh, hubs[hub].nport); usb_close (uh); } //exit (result); return (result); }
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); }
/* After USB port reset, treat device number 0 as an USB hub. Assign it with * a device number hub_addr. Then apply enable and reset on downstream port. */ static int dbgp_hub_enable(struct ehci_dbg_port *ehci_debug, unsigned char hub_addr, unsigned char port) { char status[8]; int ret, loop; /* Assign a devicenumber for the hub. */ ret = dbgp_control_msg(ehci_debug, 0, USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, USB_REQ_SET_ADDRESS, hub_addr, 0, NULL, 0); if (ret < 0) goto err; /* Enter configured state on hub. */ ret = dbgp_control_msg(ehci_debug, hub_addr, USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, USB_REQ_SET_CONFIGURATION, 1, 0, NULL, 0); if (ret < 0) goto err; /* Set PORT_POWER, poll for PORT_CONNECTION. */ ret = dbgp_control_msg(ehci_debug, hub_addr, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER, USB_REQ_SET_FEATURE, USB_HUB_PORT_POWER, port, NULL, 0); if (ret < 0) goto err; loop = 100; do { dbgp_mdelay(10); ret = dbgp_control_msg(ehci_debug, hub_addr, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_OTHER, USB_REQ_GET_STATUS, 0, port, status, 4); if (ret < 0) goto err; if (hub_port_status(status, USB_HUB_PORT_CONNECTION)) break; } while (--loop); if (! loop) goto err; ret = dbgp_control_msg(ehci_debug, hub_addr, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER, USB_REQ_CLEAR_FEATURE, USB_HUB_C_PORT_CONNECTION, port, NULL, 0); if (ret < 0) goto err; /* Set PORT_RESET, poll for C_PORT_RESET. */ ret = dbgp_control_msg(ehci_debug, hub_addr, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER, USB_REQ_SET_FEATURE, USB_HUB_PORT_RESET, port, NULL, 0); if (ret < 0) goto err; loop = 100; do { dbgp_mdelay(10); ret = dbgp_control_msg(ehci_debug, hub_addr, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_OTHER, USB_REQ_GET_STATUS, 0, port, status, 4); if (ret < 0) goto err; if (hub_port_status(status, USB_HUB_C_PORT_RESET)) break; } while (--loop); if (! loop) goto err; ret = dbgp_control_msg(ehci_debug, hub_addr, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER, USB_REQ_CLEAR_FEATURE, USB_HUB_C_PORT_RESET, port, NULL, 0); if (ret < 0) goto err; if (hub_port_status(status, USB_HUB_PORT_ENABLED)) return 0; err: return -1; }