int hub_port_resume( struct rt_urb *p_urb, __u16 port_nr) { int tries = 100; int us_delay = 10000; portstat_t pstat; if( hub_get_portstat( p_urb, port_nr, &pstat) ){ return -1; } if( !pstat.stat.port_suspend ){ return 0; } if( hub_clear_port_feature( p_urb, port_nr, PORT_SUSPEND) ){ return -1; } do{ udelay(us_delay); if( hub_get_portstat( p_urb, port_nr, &pstat) ){ return -1; } } while( tries-- && !pstat.change.c_port_suspend ); if(!tries){ return(-1); } hub_clear_port_feature( p_urb, port_nr, C_PORT_SUSPEND); return 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; }
int hub_port_reset( struct rt_urb *p_urb, __u16 port_nr) { int tries = 100; int us_delay = 10000; portstat_t pstat; if( hub_set_port_feature( p_urb, port_nr, PORT_RESET) ){ return -1; } do{ udelay(us_delay); if( hub_get_portstat( p_urb, port_nr, &pstat) ){ return -1; } } while( tries-- && !pstat.change.c_port_reset ); if(!tries){ return(-1); } hub_clear_port_feature( p_urb, port_nr, C_PORT_RESET); return 0; }
static vsf_err_t hub_reset_thread(struct vsfsm_pt_t *pt, vsfsm_evt_t evt) { struct vsfusbh_hub_t *hub = (struct vsfusbh_hub_t *)pt->user_data; struct vsfusbh_urb_t *vsfurb = hub->vsfurb; vsf_err_t err; vsfsm_pt_begin(pt); hub->retry = 0; do { /* send command to reset port */ vsfurb->transfer_buffer = NULL; vsfurb->transfer_length = 0; err = hub_set_port_feature(hub->usbh, vsfurb, hub->counter, USB_PORT_FEAT_RESET); if (err != VSFERR_NONE) return err; vsfsm_pt_wfe(pt, VSFSM_EVT_URB_COMPLETE); if (vsfurb->status != URB_OK) return VSFERR_FAIL; /* delay 100ms after port reset*/ vsfsm_pt_delay(pt, 100); // clear reset vsfurb->transfer_buffer = NULL; vsfurb->transfer_length = 0; err = hub_clear_port_feature(hub->usbh, vsfurb, hub->counter, USB_PORT_FEAT_C_RESET); if (err != VSFERR_NONE) return err; vsfsm_pt_wfe(pt, VSFSM_EVT_URB_COMPLETE); if (vsfurb->status != URB_OK) return VSFERR_FAIL; /* delay 100ms after port reset*/ vsfsm_pt_delay(pt, 50); /* get port status for check */ vsfurb->transfer_buffer = &hub->hub_portsts; vsfurb->transfer_length = sizeof(hub->hub_portsts); err = hub_get_port_status(hub->usbh, vsfurb, hub->counter); if (err != VSFERR_NONE) return err; vsfsm_pt_wfe(pt, VSFSM_EVT_URB_COMPLETE); if (vsfurb->status != URB_OK) return VSFERR_FAIL; /* check port status after reset */ if (hub->hub_portsts.wPortStatus & USB_PORT_STAT_ENABLE) { return VSFERR_NONE; } else { /* delay 200ms for next reset*/ vsfsm_pt_delay(pt, 200); } } while (hub->retry++ <= 3); vsfsm_pt_end(pt); return VSFERR_FAIL; }
static vsf_err_t hub_scan_thread(struct vsfsm_pt_t *pt, vsfsm_evt_t evt) { vsf_err_t err; struct vsfusbh_hub_t *hub = (struct vsfusbh_hub_t *)pt->user_data; struct vsfusbh_urb_t *vsfurb = hub->vsfurb; vsfsm_pt_begin(pt); do { hub->counter = 1; do { // get port status vsfurb->transfer_buffer = &hub->hub_portsts; vsfurb->transfer_length = sizeof(hub->hub_portsts); err = hub_get_port_status(hub->usbh, vsfurb, hub->counter); if (err != VSFERR_NONE) return err; vsfsm_pt_wfe(pt, VSFSM_EVT_URB_COMPLETE); if (vsfurb->status != URB_OK) return VSFERR_FAIL; if (hub->hub_portsts.wPortChange & USB_PORT_STAT_C_CONNECTION) { // try to connect vsfsm_pt_wfpt(pt, &hub->drv_connect_pt); } else if (hub->hub_portsts.wPortChange & USB_PORT_STAT_C_ENABLE) { vsfurb->transfer_buffer = NULL; vsfurb->transfer_length = 0; err = hub_clear_port_feature(hub->usbh, vsfurb, hub->counter, USB_PORT_FEAT_C_ENABLE); if (err != VSFERR_NONE) return err; vsfsm_pt_wfe(pt, VSFSM_EVT_URB_COMPLETE); if (vsfurb->status != URB_OK) return VSFERR_FAIL; hub->hub_portsts.wPortChange &= ~USB_PORT_STAT_C_ENABLE; } if (hub->hub_portsts.wPortChange & USB_PORT_STAT_C_SUSPEND) { vsfurb->transfer_buffer = NULL; vsfurb->transfer_length = 0; err = hub_clear_port_feature(hub->usbh, vsfurb, hub->counter, USB_PORT_FEAT_C_SUSPEND); if (err != VSFERR_NONE) return err; vsfsm_pt_wfe(pt, VSFSM_EVT_URB_COMPLETE); if (vsfurb->status != URB_OK) return VSFERR_FAIL; hub->hub_portsts.wPortChange &= ~USB_PORT_STAT_C_SUSPEND; } if (hub->hub_portsts.wPortChange & USB_PORT_STAT_C_OVERCURRENT) { vsfurb->transfer_buffer = NULL; vsfurb->transfer_length = 0; err = hub_clear_port_feature(hub->usbh, vsfurb, hub->counter, USB_PORT_FEAT_C_OVER_CURRENT); if (err != VSFERR_NONE) return err; vsfsm_pt_wfe(pt, VSFSM_EVT_URB_COMPLETE); if (vsfurb->status != URB_OK) return VSFERR_FAIL; hub->hub_portsts.wPortChange &= ~USB_PORT_FEAT_C_OVER_CURRENT; // TODO : power every port } if (hub->hub_portsts.wPortChange & USB_PORT_STAT_C_RESET) { vsfurb->transfer_buffer = NULL; vsfurb->transfer_length = 0; err = hub_clear_port_feature(hub->usbh, vsfurb, hub->counter, USB_PORT_FEAT_C_RESET); if (err != VSFERR_NONE) return err; vsfsm_pt_wfe(pt, VSFSM_EVT_URB_COMPLETE); if (vsfurb->status != URB_OK) return VSFERR_FAIL; hub->hub_portsts.wPortChange &= ~USB_PORT_FEAT_C_RESET; } } while (hub->counter++ < hub->dev->maxchild); // TODO : poll hub status vsfsm_pt_delay(pt, 500); } while (1); vsfsm_pt_end(pt); return VSFERR_NONE; }
static vsf_err_t hub_connect_thread(struct vsfsm_pt_t *pt, vsfsm_evt_t evt) { vsf_err_t err; struct vsfusbh_hub_t *hub = (struct vsfusbh_hub_t *)pt->user_data; struct vsfusbh_urb_t *vsfurb = hub->vsfurb; struct vsfusbh_device_t *dev; vsfsm_pt_begin(pt); /* clear the cnnection change state */ vsfurb->transfer_buffer = NULL; vsfurb->transfer_length = 0; err = hub_clear_port_feature(hub->usbh, vsfurb, hub->counter, USB_PORT_FEAT_C_CONNECTION); if (err != VSFERR_NONE) return err; vsfsm_pt_wfe(pt, VSFSM_EVT_URB_COMPLETE); if (vsfurb->status != URB_OK) return VSFERR_FAIL; if (hub->dev->children[hub->counter - 1] != NULL) { vsfusbh_disconnect_device(hub->usbh, &hub->dev->children[hub->counter - 1]); } if (!(hub->hub_portsts.wPortStatus & USB_PORT_STAT_CONNECTION)) { if (hub->hub_portsts.wPortStatus & USB_PORT_STAT_ENABLE) { vsfurb->transfer_buffer = NULL; vsfurb->transfer_length = 0; err = hub_clear_port_feature(hub->usbh, vsfurb, hub->counter, USB_PORT_FEAT_ENABLE); if (err != VSFERR_NONE) return err; vsfsm_pt_wfe(pt, VSFSM_EVT_URB_COMPLETE); if (vsfurb->status != URB_OK) return VSFERR_FAIL; } return VSFERR_NONE; } if (hub->hub_portsts.wPortStatus & USB_PORT_STAT_LOW_SPEED) { vsfsm_pt_delay(pt, 200); } vsfsm_pt_wfpt(pt, &hub->drv_reset_pt); vsfsm_pt_delay(pt, 200); // wait for new_dev free while (hub->usbh->new_dev != NULL) { vsfsm_pt_delay(pt, 200); } dev = vsfusbh_alloc_device(hub->usbh); if (NULL == dev) return VSFERR_FAIL; if (hub->hub_portsts.wPortStatus & USB_PORT_STAT_LOW_SPEED) { dev->speed = USB_SPEED_LOW; dev->slow = 1; } else if (hub->hub_portsts.wPortStatus & USB_PORT_STAT_HIGH_SPEED) dev->speed = USB_SPEED_HIGH; else dev->speed = USB_SPEED_FULL; hub->dev->children[hub->counter - 1] = dev; dev->parent = hub->dev; hub->usbh->new_dev = dev; vsfsm_post_evt_pending(&hub->usbh->sm, VSFSM_EVT_NEW_DEVICE); vsfsm_pt_end(pt); return VSFERR_NONE; }