static void hub_connect_port (struct psfreedom_device *dev, unsigned int port) { if (port == 0 || port > 6) return; switch_to_port (dev, 0); /* Here, we must enable the port directly, otherwise we might loose time with the host asking for the status a few more times, and waiting for it to be enabled, etc.. and we might miss the 5seconds window in which we need to connect the JIG */ dev->hub_ports[port-1].status |= PORT_STAT_CONNECTION; dev->hub_ports[port-1].status |= PORT_STAT_ENABLE; /* If the speed flag set is not the same as what the device suports, it will not work */ if (psfreedom_is_high_speed ()) dev->hub_ports[port-1].status |= PORT_STAT_HIGH_SPEED; else if (psfreedom_is_low_speed ()) dev->hub_ports[port-1].status |= PORT_STAT_HIGH_SPEED; dev->hub_ports[port-1].change |= PORT_STAT_C_CONNECTION; hub_port_changed (dev); }
static void hub_disconnect_port (struct psfreedom_device *dev, unsigned int port) { if (port == 0 || port > 6) return; switch_to_port (dev, 0); dev->hub_ports[port-1].status &= ~PORT_STAT_CONNECTION; dev->hub_ports[port-1].status &= ~PORT_STAT_ENABLE; dev->hub_ports[port-1].status &= ~PORT_STAT_HIGH_SPEED; dev->hub_ports[port-1].status &= ~PORT_STAT_LOW_SPEED; dev->hub_ports[port-1].change |= PORT_STAT_C_CONNECTION; hub_port_changed (dev); }
static void hub_disconnect_port (unsigned int port) { if (port == 0 || port > 6) { return; } switch_to_port (0); // After jig send response ep2 needs behave as hub if (machine_state==DEVICE3_WAIT_DISCONNECT) { ep2_reset(); } port_status[port-1] &= ~PORT_STAT_CONNECTION; port_status[port-1] &= ~PORT_STAT_ENABLE; port_change[port-1] |= PORT_STAT_C_CONNECTION; hub_port_changed (); }
static void hub_connect_port (unsigned int port) { if (port == 0 || port > 6) { return; } expected_port_reset = port; //PRINTKD( "[%lu]Hub: Connect port %d\n", (jiffies-start_time)*10, port ); switch_to_port (0); /* Here, we must enable the port directly, otherwise we might loose time with the host asking for the status a few more times, and waiting for it to be enabled, etc.. and we might miss the 5seconds window in which we need to connect the JIG */ port_status[port-1] |= PORT_STAT_CONNECTION; port_status[port-1] |= PORT_STAT_ENABLE; port_change[port-1] |= PORT_STAT_C_CONNECTION; hub_port_changed (); }
/* * The setup() callback implements all the ep0 functionality that's * not handled lower down, in hardware or the hardware driver (like * device and endpoint feature flags, and their status). It's all * housekeeping for the gadget function we're implementing. Most of * the work is in config-specific setup. */ static int hub_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl, u16 request, u16 w_index, u16 w_value, u16 w_length) { struct psfreedom_device *dev = get_gadget_data(gadget); struct usb_request *req = dev->req; int value = -EOPNOTSUPP; /* usually this stores reply data in the pre-allocated ep0 buffer, * but config change events will reconfigure hardware. */ switch (ctrl->bRequest) { case USB_REQ_GET_DESCRIPTOR: if ((ctrl->bRequestType & USB_DIR_IN) == 0) { goto unknown; } if ((ctrl->bRequestType & USB_TYPE_CLASS) == USB_TYPE_CLASS) { /* GET_HUB_DESCRIPTOR Class specific request */ value = min(w_length, (u16) sizeof(hub_header_desc)); memcpy(req->buf, &hub_header_desc, value); if (value >= 0) value = min(w_length, (u16)value); } else { switch (w_value >> 8) { case USB_DT_DEVICE: value = min(w_length, (u16) sizeof(hub_device_desc)); memcpy(req->buf, &hub_device_desc, value); break; case USB_DT_CONFIG: memcpy(req->buf, &hub_config_desc, sizeof(hub_config_desc)); value = sizeof(hub_config_desc); memcpy (req->buf + value, &hub_interface_desc, sizeof(hub_interface_desc)); value += sizeof(hub_interface_desc); memcpy (req->buf + value, &hub_endpoint_desc, sizeof(hub_endpoint_desc)); value += sizeof(hub_endpoint_desc); if (value >= 0) value = min(w_length, (u16)value); break; case USB_DT_STRING: value = 0; break; } } break; case USB_REQ_SET_CONFIGURATION: if (ctrl->bRequestType != 0) { goto unknown; } value = hub_set_config(dev, w_value); break; case USB_REQ_GET_CONFIGURATION: if (ctrl->bRequestType != USB_DIR_IN) { goto unknown; } *(u8 *)req->buf = 0; value = min(w_length, (u16)1); break; case USB_REQ_SET_INTERFACE: if (ctrl->bRequestType != USB_RECIP_INTERFACE) { goto unknown; } value = 0; break; case USB_REQ_GET_INTERFACE: if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) { goto unknown; } if (w_index >= 1) { value = -EDOM; break; } *(u8 *)req->buf = 0; value = min(w_length, (u16)1); break; case USB_REQ_SET_FEATURE: if ((ctrl->bRequestType & USB_TYPE_CLASS) == USB_TYPE_CLASS) { switch (ctrl->bRequestType & USB_RECIP_MASK) { /* SET_HUB_FEATURE */ case USB_RECIP_DEVICE: switch (w_value) { case 0: /* C_HUB_LOCAL_POWER */ case 1: /* C_HUB_OVER_CURRENT */ VDBG (dev, "SetHubFeature called\n"); value = 0; break; default: value = -EINVAL; break; } break; case USB_RECIP_OTHER: /* SET_PORT_FEATURE */ if (w_index == 0 || w_index > 6) { DBG (dev, "SetPortFeature: invalid port index %d\n", w_index); value = -EINVAL; break; } switch (w_value) { case 4: /* PORT_RESET */ DBG (dev, "SetPortFeature PORT_RESET called\n"); dev->hub_ports[w_index-1].change |= PORT_STAT_C_RESET; hub_port_changed (dev); value = 0; break; case 8: /* PORT_POWER */ DBG (dev, "SetPortFeature PORT_POWER called\n"); dev->hub_ports[w_index-1].status |= PORT_STAT_POWER; if (dev->status == INIT && w_index == 6) { dev->status = HUB_READY; SET_TIMER (150); } value = 0; break; case 0: /* PORT_CONNECTION */ case 1: /* PORT_ENABLE */ case 2: /* PORT_SUSPEND */ case 3: /* PORT_OVER_CURRENT */ case 9: /* PORT_LOW_SPEED */ case 16: /* C_PORT_CONNECTION */ case 17: /* C_PORT_ENABLE */ case 18: /* C_PORT_SUSPEND */ case 19: /* C_PORT_OVER_CURRENT */ case 20: /* C_PORT_RESET */ case 21: /* PORT_TEST */ case 22: /* PORT_INDICATOR */ DBG (dev, "SetPortFeature called\n"); value = 0; break; default: value = -EINVAL; break; } break; } } break; case USB_REQ_CLEAR_FEATURE: if ((ctrl->bRequestType & USB_TYPE_CLASS) == USB_TYPE_CLASS) { switch (ctrl->bRequestType & USB_RECIP_MASK) { /* CLEAR_HUB_FEATURE */ case USB_RECIP_DEVICE: switch (w_value) { case 0: /* C_HUB_LOCAL_POWER */ case 1: /* C_HUB_OVER_CURRENT */ VDBG (dev, "ClearHubFeature called\n"); value = 0; break; default: value = -EINVAL; break; } break; case USB_RECIP_OTHER: /* CLEAR_PORT_FEATURE */ if (w_index == 0 || w_index > 6) { DBG (dev, "ClearPortFeature: invalid port index %d\n", w_index); value = -EINVAL; break; } switch (w_value) { case 0: /* PORT_CONNECTION */ case 1: /* PORT_ENABLE */ case 2: /* PORT_SUSPEND */ case 3: /* PORT_OVER_CURRENT */ case 4: /* PORT_RESET */ case 8: /* PORT_POWER */ case 9: /* PORT_LOW_SPEED */ value = 0; break; case 16: /* C_PORT_CONNECTION */ DBG (dev, "ClearPortFeature C_PORT_CONNECTION called\n"); dev->hub_ports[w_index-1].change &= ~PORT_STAT_C_CONNECTION; switch (dev->status) { case DEVICE1_WAIT_DISCONNECT: dev->status = DEVICE1_DISCONNECTED; SET_TIMER (200); break; case DEVICE2_WAIT_DISCONNECT: dev->status = DEVICE2_DISCONNECTED; SET_TIMER (170); break; case DEVICE3_WAIT_DISCONNECT: dev->status = DEVICE3_DISCONNECTED; SET_TIMER (450); break; case DEVICE4_WAIT_DISCONNECT: dev->status = DEVICE4_DISCONNECTED; SET_TIMER (200); break; case DEVICE5_WAIT_DISCONNECT: dev->status = DEVICE5_DISCONNECTED; SET_TIMER (200); break; default: break; } value = 0; break; case 20: /* C_PORT_RESET */ DBG (dev, "ClearPortFeature C_PORT_RESET called\n"); dev->hub_ports[w_index-1].change &= ~PORT_STAT_C_RESET; switch (dev->status) { case DEVICE1_WAIT_READY: if (w_index == 1) dev->switch_to_port_delayed = w_index; break; case DEVICE2_WAIT_READY: if (w_index == 2) dev->switch_to_port_delayed = w_index; break; case DEVICE3_WAIT_READY: if (w_index == 3) dev->switch_to_port_delayed = w_index; break; case DEVICE4_WAIT_READY: if (w_index == 4) dev->switch_to_port_delayed = w_index; break; case DEVICE5_WAIT_READY: if (w_index == 5) dev->switch_to_port_delayed = w_index; break; case DEVICE6_WAIT_READY: if (w_index == 6) dev->switch_to_port_delayed = w_index; break; default: break; } /* Delay switching the port because we first need to response to this request with the proper address */ if (dev->switch_to_port_delayed >= 0) SET_TIMER (0); value = 0; break; case 17: /* C_PORT_ENABLE */ case 18: /* C_PORT_SUSPEND */ case 19: /* C_PORT_OVER_CURRENT */ case 21: /* PORT_TEST */ case 22: /* PORT_INDICATOR */ DBG (dev, "ClearPortFeature called\n"); value = 0; break; default: value = -EINVAL; break; } break; } } break; case USB_REQ_GET_STATUS: if ((ctrl->bRequestType & USB_TYPE_CLASS) == USB_TYPE_CLASS) { u16 status = 0; u16 change = 0; value = 2 * sizeof (u16); switch (ctrl->bRequestType & USB_RECIP_MASK) { case USB_RECIP_DEVICE: /* GET_HUB_STATUS */ status = 0; change = 0; break; case USB_RECIP_OTHER: /* GET_PORT_STATUS */ if (w_index == 0 || w_index > 6) { DBG (dev, "GetPortstatus : invalid port index %d\n", w_index); value = -EINVAL; break; } status = dev->hub_ports[w_index -1].status; change = dev->hub_ports[w_index -1].change; break; default: goto unknown; } if (value > 0) { DBG (dev, "GetHub/PortStatus: transmtiting status %d change %d\n", status, change); status = cpu_to_le16 (status); change = cpu_to_le16 (change); memcpy(req->buf, &status, sizeof(u16)); memcpy(req->buf + sizeof(u16), &change, sizeof(u16)); } } break; default: unknown: ERROR (dev, "unknown control req%02x.%02x v%04x i%04x l%d\n", ctrl->bRequestType, ctrl->bRequest, w_value, w_index, w_length); } /* device either stalls (value < 0) or reports success */ return value; }