static int hub_check_port(struct usb_dev *dev, int port) { struct usb_hub_ps ps; uint32_t time; if (!hub_get_port_status(dev, port, &ps, sizeof(ps))) return false; dprintf("Port Status %04X Port Change %04X\n", le16_to_cpu(ps.wPortStatus), le16_to_cpu(ps.wPortChange)); if (!(le16_to_cpu(ps.wPortStatus) & HUB_PS_POWER)) { hub_set_port_feature(dev, port, HUB_PF_POWER); SLOF_msleep(100); time = SLOF_GetTimer() + USB_TIMEOUT; while (time > SLOF_GetTimer()) { cpu_relax(); hub_get_port_status(dev, port, &ps, sizeof(ps)); if (le16_to_cpu(ps.wPortStatus) & HUB_PS_CONNECTION) { dprintf("power on Port Status %04X Port Change %04X\n", le16_to_cpu(ps.wPortStatus), le16_to_cpu(ps.wPortChange)); break; } } } if (le16_to_cpu(ps.wPortStatus) & HUB_PS_CONNECTION) { hub_set_port_feature(dev, port, HUB_PF_RESET); SLOF_msleep(100); time = SLOF_GetTimer() + USB_TIMEOUT; while (time > SLOF_GetTimer()) { cpu_relax(); hub_get_port_status(dev, port, &ps, sizeof(ps)); if (!(le16_to_cpu(ps.wPortStatus) & HUB_PS_RESET)) { dprintf("reset Port Status %04X Port Change %04X\n", le16_to_cpu(ps.wPortStatus), le16_to_cpu(ps.wPortChange)); return true; } } } return false; }
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; }