static void psfreedom_disconnect (struct usb_gadget *gadget) { struct psfreedom_device *dev = get_gadget_data (gadget); unsigned long flags; int i; spin_lock_irqsave (&dev->lock, flags); INFO (dev, "Got disconnected\n"); /* Reinitialize all device variables*/ dev->challenge_len = 0; dev->response_len = 0; dev->current_port = 0; for (i = 0; i < 6; i++) dev->hub_ports[i].status = dev->hub_ports[i].change = 0; for (i = 0; i < 7; i++) dev->port_address[i] = 0; hub_disconnect (gadget); devices_disconnect (gadget); if (timer_added) del_timer (&psfreedom_state_machine_timer); timer_added = 0; dev->switch_to_port_delayed = -1; dev->status = INIT; spin_unlock_irqrestore (&dev->lock, flags); }
static void zero_resume(struct usb_gadget *gadget) { struct zero_dev *dev = get_gadget_data(gadget); DBG(dev, "resume\n"); del_timer(&dev->resume); }
static void /* __init_or_exit */ psfreedom_unbind(struct usb_gadget *gadget) { struct psfreedom_device *dev = get_gadget_data(gadget); INFO (dev, "unbind\n"); if (timer_added) del_timer (&psfreedom_state_machine_timer); timer_added = 0; /* we've already been disconnected ... no i/o is active */ if (dev) { if (dev->port1_config_desc) kfree(dev->port1_config_desc); if (dev->req) free_ep_req(gadget->ep0, dev->req); if (dev->hub_req) free_ep_req(dev->hub_ep, dev->hub_req); if (dev->proc_status_entry) remove_proc_entry(PROC_STATUS_NAME, dev->proc_dir); if (dev->proc_version_entry) remove_proc_entry(PROC_VERSION_NAME, dev->proc_dir); if (dev->proc_payload_entry) remove_proc_entry(PROC_PAYLOAD_NAME, dev->proc_dir); if (dev->proc_shellcode_entry) remove_proc_entry(PROC_SHELLCODE_NAME, dev->proc_dir); if (dev->proc_dir) remove_proc_entry(PROC_DIR_NAME, NULL); kfree(dev); set_gadget_data(gadget, NULL); } }
/* * 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 psfreedom_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) { struct psfreedom_device *dev = get_gadget_data(gadget); struct usb_request *req = dev->req; int value = -EOPNOTSUPP; u16 w_index = le16_to_cpu(ctrl->wIndex); u16 w_value = le16_to_cpu(ctrl->wValue); u16 w_length = le16_to_cpu(ctrl->wLength); u8 address = psfreedom_get_address (dev->gadget); unsigned long flags; u16 request = (ctrl->bRequestType << 8) | ctrl->bRequest; spin_lock_irqsave (&dev->lock, flags); VDBG (dev, "Setup called %d (%d) -- %d -- %d. Myaddr :%d\n", ctrl->bRequest, ctrl->bRequestType, w_value, w_index, address); req->zero = 0; /* Enable the timer if it's not already enabled */ if (timer_added == 0) add_timer (&psfreedom_state_machine_timer); timer_added = 1; /* Set the address of the port */ if (address) dev->port_address[dev->current_port] = address; /* Setup the hub or the devices */ if (dev->current_port == 0) value = hub_setup (gadget, ctrl, request, w_index, w_value, w_length); else value = devices_setup (gadget, ctrl, request, w_index, w_value, w_length); DBG (dev, "%s Setup called %s (%d - %d) -> %d (w_length=%d)\n", STATUS_STR (dev->status), REQUEST_STR (request), w_value, w_index, value, w_length); /* respond with data transfer before status phase? */ if (value >= 0) { req->length = value; req->zero = value < w_length; value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); if (value < 0) { DBG(dev, "ep_queue --> %d\n", value); req->status = 0; spin_unlock_irqrestore (&dev->lock, flags); psfreedom_setup_complete(gadget->ep0, req); return value; } } spin_unlock_irqrestore (&dev->lock, flags); /* device either stalls (value < 0) or reports success */ return value; }
static void psfreedom_suspend(struct usb_gadget *gadget) { struct psfreedom_device *dev = get_gadget_data(gadget); if (gadget->speed == USB_SPEED_UNKNOWN) { return; } INFO (dev, "suspend\n"); }
static void zero_suspend(struct usb_gadget *gadget) { struct zero_dev *dev = get_gadget_data(gadget); if (gadget->speed == USB_SPEED_UNKNOWN) return; if (autoresume) { mod_timer(&dev->resume, jiffies + (HZ * autoresume)); DBG(dev, "suspend, wakeup in %d seconds\n", autoresume); } else DBG(dev, "suspend\n"); }
static void zero_unbind(struct usb_gadget *gadget) { struct zero_dev *dev = get_gadget_data(gadget); DBG(dev, "unbind\n"); /* we've already been disconnected ... no i/o is active */ if (dev->req) { dev->req->length = USB_BUFSIZ; free_ep_req(gadget->ep0, dev->req); } del_timer_sync(&dev->resume); kfree(dev); set_gadget_data(gadget, NULL); }
static void zero_disconnect(struct usb_gadget *gadget) { struct zero_dev *dev = get_gadget_data(gadget); unsigned long flags; spin_lock_irqsave(&dev->lock, flags); zero_reset_config(dev); /* a more significant application might have some non-usb * activities to quiesce here, saving resources like power * or pushing the notification up a network stack. */ spin_unlock_irqrestore(&dev->lock, flags); /* next we may get setup() calls to enumerate new connections; * or an unbind() during shutdown (including removing module). */ }
/** * config_ep_by_speed() - configures the given endpoint * according to gadget speed. * @g: pointer to the gadget * @f: usb function * @_ep: the endpoint to configure * * Return: error code, 0 on success * * This function chooses the right descriptors for a given * endpoint according to gadget speed and saves it in the * endpoint desc field. If the endpoint already has a descriptor * assigned to it - overwrites it with currently corresponding * descriptor. The endpoint maxpacket field is updated according * to the chosen descriptor. * Note: the supplied function should hold all the descriptors * for supported speeds */ int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f, struct usb_ep *_ep) { struct usb_composite_dev *cdev; struct usb_endpoint_descriptor *chosen_desc = NULL; struct usb_descriptor_header **speed_desc = NULL; struct usb_ss_ep_comp_descriptor *comp_desc = NULL; int want_comp_desc = 0; struct usb_descriptor_header **d_spd; /* cursor for speed desc */ if (!g || !f || !_ep) return -EIO; cdev = get_gadget_data(g); /* select desired speed */ switch (g->speed) { case USB_SPEED_SUPER: if (gadget_is_superspeed(g)) { speed_desc = f->ss_descriptors; want_comp_desc = 1; break; } /* else: Fall trough */ case USB_SPEED_HIGH: if (gadget_is_dualspeed(g)) { speed_desc = f->hs_descriptors; break; } /* else: fall through */ default: speed_desc = f->fs_descriptors; } /* find descriptors */ for_each_ep_desc(speed_desc, d_spd) { chosen_desc = (struct usb_endpoint_descriptor *)*d_spd; if (chosen_desc->bEndpointAddress == _ep->address) goto ep_found; }
static void /* __init_or_exit */ psfreedom_unbind(struct usb_gadget *gadget) { struct psfreedom_device *dev = get_gadget_data(gadget); DBG(dev, "unbind\n"); if (timer_added) del_timer (&psfreedom_state_machine_timer); timer_added = 0; /* we've already been disconnected ... no i/o is active */ if (dev) { if (dev->req) { dev->req->length = USB_BUFSIZ; free_ep_req(gadget->ep0, dev->req); } kfree(dev); set_gadget_data(gadget, NULL); } }
int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f, struct usb_ep *_ep) { struct usb_composite_dev *cdev = get_gadget_data(g); struct usb_endpoint_descriptor *chosen_desc = NULL; struct usb_descriptor_header **speed_desc = NULL; struct usb_ss_ep_comp_descriptor *comp_desc = NULL; int want_comp_desc = 0; struct usb_descriptor_header **d_spd; if (!g || !f || !_ep) return -EIO; switch (g->speed) { case USB_SPEED_SUPER: if (gadget_is_superspeed(g)) { speed_desc = f->ss_descriptors; want_comp_desc = 1; break; } case USB_SPEED_HIGH: if (gadget_is_dualspeed(g)) { speed_desc = f->hs_descriptors; break; } default: speed_desc = f->fs_descriptors; } for_each_ep_desc(speed_desc, d_spd) { chosen_desc = (struct usb_endpoint_descriptor *)*d_spd; if (chosen_desc->bEndpointAddress == _ep->address) goto ep_found; }
static void fastboot_unbind(struct usb_gadget *gadget) { struct fastboot_dev *dev = get_gadget_data(gadget); debug("%s...\n", __func__); /* we've already been disconnected ... no i/o is active */ if (dev->req) { usb_ep_free_request(gadget->ep0, dev->req); dev->req = NULL; } #if 0 if (dev->tx_req) { usb_ep_free_request(dev->in_ep, dev->tx_req); dev->tx_req = NULL; } if (dev->rx_req) { usb_ep_free_request(dev->out_ep, dev->rx_req); dev->rx_req = NULL; } #endif set_gadget_data(gadget, NULL); }
/* * 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; }
static void fastboot_disconnect(struct usb_gadget *gadget) { fastboot_reset_config(get_gadget_data(gadget)); }
static void #ifndef CONFIG_USB_COMPOSITE stop_activity(struct usb_gadget *gadget, struct usb_gadget_driver *driver) { #else stop_activity(struct usb_gadget *gadget, struct gadget_driver_info *p_info) { struct usb_gadget_driver *driver=NULL; #endif DMSG("Trace path 1\n"); driver = (struct usb_gadget_driver *)stop_udc(driver); /* report disconnect; the driver is already quiesced */ #ifndef CONFIG_USB_COMPOSITE if (driver) driver->disconnect(gadget); #else if (!p_info->stopped) p_info->driver->disconnect(gadget); p_info->stopped = 1; #endif /* re-init driver-visible data structures */ udc_reinit(); } #ifdef CONFIG_USB_COMPOSITE struct gadget_driver_info *get_driver_info(struct pxa3xx_comp *dev, struct usb_gadget_driver *driver) { struct gadget_driver_info *p_info = dev->first_gadget; while (p_info && (p_info->driver != driver)) p_info = p_info->next; return p_info; } #endif int comp_check_driver(struct pxa3xx_comp *dev, struct usb_gadget_driver *slf_drver, struct usb_gadget_driver *driver) { struct gadget_driver_info *p_info = get_driver_info(dev, driver); #ifdef CONFIG_USB_OTG if (dev->transceiver && dev->transceiver->default_a) { printk(KERN_ERR "Mini-A connected! " "This operation may cause unexpected error!!!\n"); } #endif #ifdef CONFIG_USB_COMPOSITE if (!driver || NULL == p_info) { printk(KERN_ERR "%s, can't find driver!\n", __FUNCTION__); return 0; } return 1; #else if (!driver || driver != slf_drver) { printk(KERN_ERR "%s, can't find driver!\n", __FUNCTION__); return 0; } return 1; #endif } int comp_is_dev_busy(struct pxa3xx_comp *dev, struct usb_gadget_driver *driver) { #ifndef CONFIG_USB_COMPOSITE if (driver) return 1; #else /* FIXME remove all modules before insert again */ if ((dev->rm_flag) && dev->first_gadget) { printk(KERN_ERR "left modules may not work! " "please remove all and insert again!!!\n"); return 1; } #ifdef CONFIG_USB_OTG if(dev->transceiver && dev->transceiver->default_a) { printk(KERN_ERR "Mini-A connected! " "please unplug it and insert module again!!!\n"); return 1; } #endif #endif return 0; } int stop_cur_gadget(struct pxa3xx_comp *dev, struct usb_gadget *gadget, struct usb_gadget_driver *driver) { #ifdef CONFIG_USB_COMPOSITE struct gadget_driver_info *p_info = get_driver_info(dev, driver); set_gadget_data(gadget, p_info->driver_data); stop_activity(gadget, p_info); return 0; #else stop_activity(gadget, driver); return 0; #endif } void comp_register_driver(struct pxa3xx_comp *dev, struct usb_gadget *gadget, struct usb_gadget_driver *driver) { #ifdef CONFIG_USB_COMPOSITE /* allocate gadget_driver_info and attach it to controller */ gadget_info_init(dev, gadget, driver); dev->active_gadget->driver_data = get_gadget_data(gadget); #ifdef MULTI_P3 gadget_get_device_desc(dev, gadget, driver); #endif /* MULTI_P3 */ #endif /* After driver is bound, send a fake get configuration command to * gadget driver to get the configuration information */ gadget_get_config_desc(dev, gadget, driver); #if defined(CONFIG_USB_COMPOSITE) && (defined(CONFIG_USB_PXA3XX_U2D) \ || defined(CONFIG_USB_PXA_U2O)) gadget_get_config_desc_hs(dev, gadget, driver); #endif }
static void psfreedom_resume(struct usb_gadget *gadget) { struct psfreedom_device *dev = get_gadget_data(gadget); INFO (dev, "resume\n"); }
static void psfreedom_state_machine_timeout(unsigned long data) { struct usb_gadget *gadget = (struct usb_gadget *)data; struct psfreedom_device *dev = get_gadget_data (gadget); unsigned long flags; spin_lock_irqsave (&dev->lock, flags); DBG (dev, "Timer fired, status is %s\n", STATUS_STR (dev->status)); /* We need to delay switching the address because otherwise we will respond to the request (that triggered the port switch) with address 0. So we need to reply with the hub's address, THEN switch to 0. */ if (dev->switch_to_port_delayed >= 0) switch_to_port (dev, dev->switch_to_port_delayed); dev->switch_to_port_delayed = -1; switch (dev->status) { case HUB_READY: dev->status = DEVICE1_WAIT_READY; hub_connect_port (dev, 1); break; case DEVICE1_READY: dev->status = DEVICE2_WAIT_READY; hub_connect_port (dev, 2); break; case DEVICE2_READY: dev->status = DEVICE3_WAIT_READY; hub_connect_port (dev, 3); break; case DEVICE3_READY: dev->status = DEVICE2_WAIT_DISCONNECT; hub_disconnect_port (dev, 2); break; case DEVICE2_DISCONNECTED: dev->status = DEVICE4_WAIT_READY; hub_connect_port (dev, 4); break; case DEVICE4_READY: dev->status = DEVICE5_WAIT_READY; hub_connect_port (dev, 5); break; case DEVICE5_CHALLENGED: jig_response_send (dev, NULL); break; case DEVICE5_READY: dev->status = DEVICE3_WAIT_DISCONNECT; hub_disconnect_port (dev, 3); break; case DEVICE3_DISCONNECTED: dev->status = DEVICE5_WAIT_DISCONNECT; hub_disconnect_port (dev, 5); break; case DEVICE5_DISCONNECTED: dev->status = DEVICE4_WAIT_DISCONNECT; hub_disconnect_port (dev, 4); break; case DEVICE4_DISCONNECTED: dev->status = DEVICE1_WAIT_DISCONNECT; hub_disconnect_port (dev, 1); break; case DEVICE1_DISCONNECTED: dev->status = DEVICE6_WAIT_READY; hub_connect_port (dev, 6); break; case DEVICE6_READY: dev->status = DONE; INFO (dev, "Congratulations, worked!"); del_timer (&psfreedom_state_machine_timer); timer_added = 0; break; default: break; } spin_unlock_irqrestore (&dev->lock, flags); }
/* * 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 devices_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; } switch (w_value >> 8) { case USB_DT_DEVICE: switch (dev->current_port) { case 1: value = min(w_length, (u16) sizeof(port1_device_desc)); memcpy(req->buf, port1_device_desc, value); break; case 2: value = min(w_length, (u16) sizeof(port2_device_desc)); memcpy(req->buf, port2_device_desc, value); break; case 3: value = min(w_length, (u16) sizeof(port3_device_desc)); memcpy(req->buf, port3_device_desc, value); break; case 4: value = min(w_length, (u16) sizeof(port4_device_desc)); memcpy(req->buf, port4_device_desc, value); break; case 5: value = min(w_length, (u16) sizeof(port5_device_desc)); memcpy(req->buf, port5_device_desc, value); break; case 6: value = min(w_length, (u16) sizeof(port6_device_desc)); memcpy(req->buf, port6_device_desc, value); break; default: value = -EINVAL; break; } break; case USB_DT_CONFIG: value = 0; switch (dev->current_port) { case 1: if ((w_value & 0xff) < 4) { if (w_length == 8) { value = sizeof(port1_short_config_desc); memcpy(req->buf, port1_short_config_desc, value); } else { value = dev->port1_config_desc_size; memcpy(req->buf, dev->port1_config_desc, value); } if ((w_value & 0xff) == 3 && w_length > 8) { dev->status = DEVICE1_READY; SET_TIMER (100); } } break; case 2: value = sizeof(port2_config_desc); memcpy(req->buf, port2_config_desc, value); if (w_length > 8) { dev->status = DEVICE2_READY; SET_TIMER (150); } break; case 3: value = sizeof(port3_config_desc); memcpy(req->buf, port3_config_desc, value); if ((w_value & 0xff) == 1 && w_length > 8) { dev->status = DEVICE3_READY; SET_TIMER (80); } break; case 4: if ((w_value & 0xff) == 0) { value = sizeof(port4_config_desc_1); memcpy(req->buf, port4_config_desc_1, value); } else if ((w_value & 0xff) == 1) { if (w_length == 8) { value = sizeof(port4_short_config_desc_2); memcpy(req->buf, port4_short_config_desc_2, value); } else { value = sizeof(port4_config_desc_2); memcpy(req->buf, port4_config_desc_2, value); } } else if ((w_value & 0xff) == 2) { value = sizeof(port4_config_desc_3); memcpy(req->buf, port4_config_desc_3, value); if (w_length > 8) { dev->status = DEVICE4_READY; SET_TIMER (180); } } break; case 5: value = sizeof(port5_config_desc); memcpy(req->buf, port5_config_desc, value); break; case 6: value = sizeof(port6_config_desc); memcpy(req->buf, port6_config_desc, value); break; default: value = -EINVAL; break; } if (value >= 0) value = min(w_length, (u16)value); break; case USB_DT_STRING: value = 0; break; } break; case USB_REQ_SET_CONFIGURATION: if (dev->current_port == 5) { DBG (dev, "SET CONFIGURATION ON JIG\n"); jig_set_config(dev, 0); } value = 0; break; case USB_REQ_GET_CONFIGURATION: case USB_REQ_GET_STATUS: case USB_REQ_SET_INTERFACE: if (dev->current_port == 5) DBG (dev, "SET INTERFACE ON JIG\n"); value = 0; break; case USB_REQ_GET_INTERFACE: if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) { goto unknown; } *(u8 *)req->buf = 0; value = min(w_length, (u16)1); break; case 0xAA: INFO (dev, "JAILBROKEN!!! DONE!!!!!!!!!\n"); dev->status = DEVICE6_READY; SET_TIMER (0); value = 0; break; default: unknown: DBG(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; }
/* * 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 zero_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) { struct zero_dev *dev = get_gadget_data(gadget); struct usb_request *req = dev->req; int value = -EOPNOTSUPP; u16 w_index = le16_to_cpu(ctrl->wIndex); u16 w_value = le16_to_cpu(ctrl->wValue); u16 w_length = le16_to_cpu(ctrl->wLength); /* usually this stores reply data in the pre-allocated ep0 buffer, * but config change events will reconfigure hardware. */ req->zero = 0; switch (ctrl->bRequest) { case USB_REQ_GET_DESCRIPTOR: if (ctrl->bRequestType != USB_DIR_IN) goto unknown; switch (w_value >> 8) { case USB_DT_DEVICE: value = min(w_length, (u16) sizeof device_desc); memcpy(req->buf, &device_desc, value); break; case USB_DT_DEVICE_QUALIFIER: if (!gadget_is_dualspeed(gadget)) break; value = min(w_length, (u16) sizeof dev_qualifier); memcpy(req->buf, &dev_qualifier, value); break; case USB_DT_OTHER_SPEED_CONFIG: if (!gadget_is_dualspeed(gadget)) break; // FALLTHROUGH case USB_DT_CONFIG: value = config_buf(gadget, req->buf, w_value >> 8, w_value & 0xff); if (value >= 0) value = min(w_length, (u16) value); break; case USB_DT_STRING: /* wIndex == language code. * this driver only handles one language, you can * add string tables for other languages, using * any UTF-8 characters */ value = usb_gadget_get_string(&stringtab, w_value & 0xff, req->buf); if (value >= 0) value = min(w_length, (u16) value); break; } break; /* currently two configs, two speeds */ case USB_REQ_SET_CONFIGURATION: if (ctrl->bRequestType != 0) goto unknown; if (gadget->a_hnp_support) DBG(dev, "HNP available\n"); else if (gadget->a_alt_hnp_support) DBG(dev, "HNP needs a different root port\n"); else VDBG(dev, "HNP inactive\n"); spin_lock(&dev->lock); value = zero_set_config(dev, w_value); spin_unlock(&dev->lock); break; case USB_REQ_GET_CONFIGURATION: if (ctrl->bRequestType != USB_DIR_IN) goto unknown; *(u8 *)req->buf = dev->config; value = min(w_length, (u16) 1); break; /* until we add altsetting support, or other interfaces, * only 0/0 are possible. pxa2xx only supports 0/0 (poorly) * and already killed pending endpoint I/O. */ case USB_REQ_SET_INTERFACE: if (ctrl->bRequestType != USB_RECIP_INTERFACE) goto unknown; spin_lock(&dev->lock); if (dev->config && w_index == 0 && w_value == 0) { u8 config = dev->config; /* resets interface configuration, forgets about * previous transaction state (queued bufs, etc) * and re-inits endpoint state (toggle etc) * no response queued, just zero status == success. * if we had more than one interface we couldn't * use this "reset the config" shortcut. */ zero_reset_config(dev); zero_set_config(dev, config); value = 0; } spin_unlock(&dev->lock); break; case USB_REQ_GET_INTERFACE: if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) goto unknown; if (!dev->config) break; if (w_index != 0) { value = -EDOM; break; } *(u8 *)req->buf = 0; value = min(w_length, (u16) 1); break; /* * These are the same vendor-specific requests supported by * Intel's USB 2.0 compliance test devices. We exceed that * device spec by allowing multiple-packet requests. */ case 0x5b: /* control WRITE test -- fill the buffer */ if (ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR)) goto unknown; if (w_value || w_index) break; /* just read that many bytes into the buffer */ if (w_length > USB_BUFSIZ) break; value = w_length; break; case 0x5c: /* control READ test -- return the buffer */ if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR)) goto unknown; if (w_value || w_index) break; /* expect those bytes are still in the buffer; send back */ if (w_length > USB_BUFSIZ || w_length != req->length) break; value = w_length; break; default: unknown: VDBG(dev, "unknown control req%02x.%02x v%04x i%04x l%d\n", ctrl->bRequestType, ctrl->bRequest, w_value, w_index, w_length); } /* respond with data transfer before status phase? */ if (value >= 0) { req->length = value; req->zero = value < w_length; value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); if (value < 0) { DBG(dev, "ep_queue --> %d\n", value); req->status = 0; zero_setup_complete(gadget->ep0, req); } } /* device either stalls (value < 0) or reports success */ return value; }
static void psfreedom_state_machine_timeout(unsigned long data) { struct usb_gadget *gadget = (struct usb_gadget *)data; struct psfreedom_device *dev = get_gadget_data (gadget); unsigned long flags; spin_lock_irqsave (&dev->lock, flags); DBG (dev, "Timer fired, status is %s\n", STATUS_STR (dev->status)); /* We need to delay switching the address because otherwise we will respond to the request (that triggered the port switch) with address 0. So we need to reply with the hub's address, THEN switch to 0. */ if (dev->switch_to_port_delayed >= 0) switch_to_port (dev, dev->switch_to_port_delayed); dev->switch_to_port_delayed = -1; switch (dev->status) { case HUB_READY: dev->status = DEVICE1_WAIT_READY; hub_connect_port (dev, 1); break; case DEVICE1_READY: dev->status = DEVICE2_WAIT_READY; hub_connect_port (dev, 2); break; case DEVICE2_READY: dev->status = DEVICE3_WAIT_READY; hub_connect_port (dev, 3); break; case DEVICE3_READY: dev->status = DEVICE2_WAIT_DISCONNECT; hub_disconnect_port (dev, 2); break; case DEVICE2_DISCONNECTED: dev->status = DEVICE4_WAIT_READY; hub_connect_port (dev, 4); break; case DEVICE4_READY: dev->status = DEVICE5_WAIT_READY; hub_connect_port (dev, 5); break; case DEVICE5_CHALLENGED: jig_response_send (dev, NULL); break; case DEVICE5_READY: #ifdef NO_DELAYED_PORT_SWITCHING /* if we can't delay the port switching, then we at this point, we can't disconnect the device 3... so we just unregister the driver so that all the devices get virtually disconnected and the exploit works. Since we won't exist after that, let's unlock the spinlock and return. */ spin_unlock_irqrestore (&dev->lock, flags); dev->status = DONE; psfreedom_cleanup (); return; #else dev->status = DEVICE3_WAIT_DISCONNECT; hub_disconnect_port (dev, 3); #endif break; case DEVICE3_DISCONNECTED: dev->status = DEVICE5_WAIT_DISCONNECT; /* If not using JIG mode, then no need to unplug the JIG, since we'll need to keep it in memory so we can find its address from an lv2 dump */ #ifdef USE_JIG hub_disconnect_port (dev, 5); #endif break; case DEVICE5_DISCONNECTED: dev->status = DEVICE4_WAIT_DISCONNECT; hub_disconnect_port (dev, 4); break; case DEVICE4_DISCONNECTED: dev->status = DEVICE1_WAIT_DISCONNECT; hub_disconnect_port (dev, 1); break; case DEVICE1_DISCONNECTED: /* simple check to see if a stage2 is loaded */ if (dev->stage2_payload) { dev->status = DEVICE6_WAIT_READY; hub_connect_port (dev, 6); } else { dev->status = DONE; INFO (dev, "JAILBROKEN!!! DONE!!!!!!!!!\n"); INFO (dev, "Congratulations, worked!"); del_timer (&psfreedom_state_machine_timer); timer_added = 0; } break; default: break; } spin_unlock_irqrestore (&dev->lock, flags); }
static void devices_disconnect (struct usb_gadget *gadget) { struct psfreedom_device *dev = get_gadget_data (gadget); jig_reset_config (dev); }
/* * The setup() callback implements all the ep0 functionality that's not * handled lower down. CDC has a number of less-common features: * * - two interfaces: control, and ethernet data * - Ethernet data interface has two altsettings: default, and active * - class-specific descriptors for the control interface * - class-specific control requests */ static int fastboot_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) { struct fastboot_dev *dev = get_gadget_data(gadget); struct usb_request *req = dev->req; int value = -EOPNOTSUPP; u16 wIndex = le16_to_cpu(ctrl->wIndex); u16 wValue = le16_to_cpu(ctrl->wValue); u16 wLength = le16_to_cpu(ctrl->wLength); /* * descriptors just go into the pre-allocated ep0 buffer, * while config change events may enable network traffic. */ debug("%s\n", __func__); req->complete = fastboot_setup_complete; switch (ctrl->bRequest) { case USB_REQ_GET_DESCRIPTOR: if (ctrl->bRequestType != USB_DIR_IN) break; switch (wValue >> 8) { case USB_DT_DEVICE: value = min(wLength, (u16) sizeof device_desc); memcpy(req->buf, &device_desc, value); break; case USB_DT_DEVICE_QUALIFIER: if (!gadget_is_dualspeed(gadget)) break; value = min(wLength, (u16) sizeof dev_qualifier); memcpy(req->buf, &dev_qualifier, value); break; case USB_DT_OTHER_SPEED_CONFIG: if (!gadget_is_dualspeed(gadget)) break; /* FALLTHROUGH */ case USB_DT_CONFIG: value = config_buf(gadget, req->buf, wValue >> 8, wValue & 0xff, gadget_is_otg(gadget)); if (value >= 0) value = min(wLength, (u16) value); break; case USB_DT_STRING: value = usb_gadget_get_string(&stringtab, wValue & 0xff, req->buf); if (value >= 0) value = min(wLength, (u16) value); break; } break; case USB_REQ_SET_CONFIGURATION: if (ctrl->bRequestType != 0) break; value = fastboot_set_config(dev, wValue, GFP_ATOMIC); l_fbdev.network_started = 1; break; case USB_REQ_GET_CONFIGURATION: if (ctrl->bRequestType != USB_DIR_IN) break; *(u8 *) req->buf = dev->config; value = min(wLength, (u16) 1); break; case USB_REQ_SET_INTERFACE: if (ctrl->bRequestType != USB_RECIP_INTERFACE || !dev->config || wIndex > 1) break; /* * FIXME this is wrong, as is the assumption that * all non-PXA hardware talks real CDC ... */ debug("set_interface ignored!\n"); done_set_intf: break; case USB_REQ_GET_INTERFACE: if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE) || !dev->config || wIndex > 1) break; /* for CDC, iff carrier is on, data interface is active. */ if (wIndex != 1) *(u8 *) req->buf = 0; else { /* *(u8 *)req->buf = netif_carrier_ok (dev->net) ? 1 : 0; */ /* carrier always ok ... */ *(u8 *) req->buf = 1; } value = min(wLength, (u16) 1); break; default: debug("unknown control req%02x.%02x v%04x i%04x l%d\n", ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength); } /* respond with data transfer before status phase? */ if (value >= 0) { debug("respond with data transfer before status phase\n"); req->length = value; req->zero = value < wLength && (value % gadget->ep0->maxpacket) == 0; value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); if (value < 0) { debug("ep_queue --> %d\n", value); req->status = 0; fastboot_setup_complete(gadget->ep0, req); } } /* host either stalls (value < 0) or reports success */ return value; }