/* * Called from process context when the hub is gone. * Detach all devices on active ports. */ int uhub_detach(struct device *self, int flags) { struct uhub_softc *sc = (struct uhub_softc *)self; struct usbd_hub *hub = sc->sc_hub->hub; struct usbd_port *rup; int port; if (hub == NULL) /* Must be partially working */ return (0); usbd_abort_pipe(sc->sc_ipipe); usbd_close_pipe(sc->sc_ipipe); for (port = 0; port < hub->nports; port++) { rup = &hub->ports[port]; if (rup->device != NULL) { usbd_detach(rup->device, self); rup->device = NULL; } } if (hub->ports[0].tt) free(hub->ports[0].tt, M_USBDEV, 0); if (sc->sc_statusbuf) free(sc->sc_statusbuf, M_USBDEV, 0); if (hub->ports) free(hub->ports, M_USBDEV, 0); free(hub, M_USBDEV, 0); sc->sc_hub->hub = NULL; return (0); }
/* Comment : Must be called before any other devi_hid... function */ void devi_unregister_usb_client(void * h) { int rc; pModule_data_t pModule = (pModule_data_t)h; struct timespec t; assert(pModule); if(pModule -> ep_int) { usbd_reset_pipe(pModule -> ep_int); usbd_abort_pipe(pModule -> ep_int); } if(pModule -> ep_cntl) usbd_abort_pipe(pModule -> ep_cntl); if(pModule -> urb) usbd_free_urb(pModule -> urb); if(pModule -> ep_int_buf) usbd_free(pModule -> ep_int_buf); if(pModule -> ep_cnt_buf) usbd_free(pModule -> ep_cnt_buf); sleep(1); if(EOK != (rc = usbd_detach(pModule -> pDevice))) { if(verbosity) fprintf(stderr, "Detach device: error %i\n", rc); } clock_gettime(CLOCK_REALTIME, &t); t.tv_sec += MAX_TIME_WAIT; if(EOK != pthread_mutex_timedlock(&mod_mutex, &t)) return ; LIST_REMOVE(pModule, lst_conn); pthread_mutex_unlock(&mod_mutex); free(pModule); }
/* Return : None */ void removal( struct usbd_connection * pConnection, usbd_device_instance_t * pInstance ) { struct usbd_device * pDevice; pModule_data_t pModule; int rc; if(NULL != ( pDevice = usbd_device_lookup( pConnection, pInstance ))) { pModule = usbd_device_extra( pDevice ); if( pModule -> ep_int ) { // Stop the Interrupt In endpoint usbd_abort_pipe( pModule -> ep_int ); // Abort pipe usbd_free_urb( pModule -> urb ); // Free request block usbd_free( pModule -> ep_int_buf ); if( rc = usbd_detach( pModule -> pDevice ) ) fprintf( stderr, "usbd_detach %i\n", rc ); } } }
int uhub_port_connect(struct uhub_softc *sc, int port, int status, int change) { struct usbd_port *up = &sc->sc_hub->hub->ports[port-1]; int speed; /* We have a connect status change, handle it. */ usbd_clear_port_feature(sc->sc_hub, port, UHF_C_PORT_CONNECTION); /* * If there is already a device on the port the change status * must mean that is has disconnected. Looking at the * current connect status is not enough to figure this out * since a new unit may have been connected before we handle * the disconnect. */ if (up->device != NULL) { /* Disconnected */ usbd_detach(up->device, &sc->sc_dev); up->device = NULL; } /* Nothing connected, just ignore it. */ if ((status & UPS_CURRENT_CONNECT_STATUS) == 0) return (0); /* Connected */ if ((status & (UPS_PORT_POWER|UPS_PORT_POWER_SS)) == 0) { printf("%s: connected port %d has no power\n", DEVNAME(sc), port); return (-1); } /* Wait for maximum device power up time. */ usbd_delay_ms(sc->sc_hub, USB_PORT_POWERUP_DELAY); /* Reset port, which implies enabling it. */ if (usbd_reset_port(sc->sc_hub, port)) { printf("%s: port %d reset failed\n", DEVNAME(sc), port); return (-1); } /* Get port status again, it might have changed during reset */ if (usbd_get_port_status(sc->sc_hub, port, &up->status)) return (-1); status = UGETW(up->status.wPortStatus); change = UGETW(up->status.wPortChange); DPRINTF("%s: port %d status=0x%04x change=0x%04x\n", DEVNAME(sc), port, status, change); /* Nothing connected, just ignore it. */ if ((status & UPS_CURRENT_CONNECT_STATUS) == 0) { DPRINTF("%s: port %d, device disappeared after reset\n", DEVNAME(sc), port); return (-1); } /* * Figure out device speed. This is a bit tricky because * UPS_PORT_POWER_SS and UPS_LOW_SPEED share the same bit. */ if ((status & UPS_PORT_POWER) == 0) status &= ~UPS_PORT_POWER_SS; if (status & UPS_HIGH_SPEED) speed = USB_SPEED_HIGH; else if (status & UPS_LOW_SPEED) speed = USB_SPEED_LOW; else { /* * If there is no power bit set, it is certainly * a Super Speed device, so use the speed of its * parent hub. */ if (status & UPS_PORT_POWER) speed = USB_SPEED_FULL; else speed = sc->sc_hub->speed; } /* * Reduce the speed, otherwise we won't setup the proper * transfer methods. */ if (speed > sc->sc_hub->speed) speed = sc->sc_hub->speed; /* Get device info and set its address. */ if (usbd_new_device(&sc->sc_dev, sc->sc_hub->bus, sc->sc_hub->depth + 1, speed, port, up)) { /* * The unit refused to accept a new address, or had * some other serious problem. Since we cannot leave * at 0 we have to disable the port instead. */ printf("%s: device problem, disabling port %d\n", DEVNAME(sc), port); usbd_clear_port_feature(sc->sc_hub, port, UHF_PORT_ENABLE); return (-1); } return (0); }
/* Return : None */ void insertion( struct usbd_connection *pConnection, usbd_device_instance_t *pInstance ) { int rc; struct usbd_device * pDevice; pModule_data_t pModule, * ppModule; if(verbosity) printf("Try to inser device\n"); if( EOK != (rc = usbd_attach( pConnection, pInstance, sizeof(module_data_t **), &pDevice ) )) { char * pMsgTxt = "Error: cannot attach USB device #%i (error code is %i)\n"; fprintf(stderr, pMsgTxt, (int)(pInstance -> devno), rc); slogf(_SLOG_SETCODE(_SLOGC_INPUT, 0), _SLOG_ERROR, pMsgTxt, (int)(pInstance -> devno), rc); return; } ppModule = (pModule_data_t *)usbd_device_extra(pDevice); // Try to find if somebody cares about keyboard reports for(pModule = LIST_FIRST_ITEM(&modList); NULL != pModule; pModule = LIST_NEXT_ITEM(pModule, lst_conn)) { // Check device number if specified if( (USBD_CONNECT_WILDCARD != pModule -> nDev) && (pModule -> nDev != pInstance -> devno)) continue; if( (USBD_CONNECT_WILDCARD != pModule -> nVendor) && (pModule -> nVendor != pInstance -> ident.vendor)) continue; // Wrong vendor - ignore if((USBD_CONNECT_WILDCARD != pModule -> nClass) && (pModule -> nClass != pInstance -> ident.dclass)) continue; if((USBD_CONNECT_WILDCARD != pModule -> nSubClass) && (pModule -> nSubClass != pInstance -> ident.subclass)) continue; pModule -> pInstance = pInstance; pModule -> pDevice = pDevice; if( EOK == parse_descriptors( pModule) ) { if( pModule -> ep_int_buf = usbd_alloc( pModule -> ep_int_size ) ) { if( pModule -> urb = usbd_alloc_urb( NULL ) ) { // Initialize request block usbd_setup_interrupt( pModule -> urb, URB_DIR_IN, pModule -> ep_int_buf, pModule->ep_int_size ); // Initialize Interrupt callback function if( EOK == usbd_io( pModule -> urb, pModule -> ep_int, usb_dev_int, pModule, USBD_TIME_INFINITY ) ) { pModule -> flags |= USB_DEVICE_ON | USB_DEVICE_PRESENT; *ppModule = pModule; if(verbosity) printf("Attach device\n"); return; } else { if(verbosity) printf("Cannot attach device\n"); } } usbd_free( pModule -> ep_int_buf ); } usbd_detach( pDevice ); } } }