/* * This function must be registered as a interrupt handler after calling the * driver_init() function. */ void usb_ISR(void) { /* * FIXME: we shall be able to detect USB reset here with resetdet field * or is it host only */ gintsts_data_t gintsts; __DWC_WARN("USB ISR! - enter\n"); do { dwc_otg_handle_common_intr(dwc_otg_device); dwc_otg_pcd_handle_intr(dwc_otg_device->pcd); gintsts.d32 = dwc_otg_read_core_intr(dwc_otg_device->core_if); __DWC_WARN("USB ISR! - gintsts: %d\n", gintsts.d32); } while (gintsts.d32 != 0); __DWC_WARN("USB ISR! - exit\n"); }
/* * This function is called when an lm_device is bound to a * dwc_otg_driver. It creates the driver components required to * control the device (CIL, HCD, and PCD) and it initializes the * device. The driver components are stored in a dwc_otg_device * structure. A reference to the dwc_otg_device is saved in the * lm_device. This allows the driver to access the dwc_otg_device * structure on subsequent calls to driver methods for this device. * */ int usb_driver_init(uint32_t base_addr) { int retval = 0; __DWC_WARN("dwc_otg_driver_init\n"); dwc_otg_device = &static_data->dwc_otg_device_inst; DWC_MEMSET(dwc_otg_device, 0, sizeof(*dwc_otg_device)); /* * Initialize driver data to point to the global DWC_otg * Device structure. */ __DWC_ERROR("dwc_otg_device addr = 0x%p\n", dwc_otg_device); dwc_otg_device->core_if = dwc_otg_cil_init(base_addr); if (!dwc_otg_device->core_if) { __DWC_ERROR("CIL initialization failed!\n"); retval = -DWC_E_NO_MEMORY; goto fail; } #ifdef USB_DEBUG /* * Attempt to ensure this device is really a DWC_otg Controller. * Read and verify the SNPSID register contents. The value should be * 0x45F42XXX or 0x45F42XXX, which corresponds to either "OT2" or "OTG3", * as in "OTG version 2.XX" or "OTG version 3.XX". */ if (((dwc_otg_get_gsnpsid(dwc_otg_device->core_if) & 0xFFFFF000) != 0x4F542000) && ((dwc_otg_get_gsnpsid(dwc_otg_device->core_if) & 0xFFFFF000) != 0x4F543000)) { __DWC_WARN("Bad value for SNPSID: 0x%x\n", dwc_otg_get_gsnpsid(dwc_otg_device->core_if)); retval = -DWC_E_INVALID; goto fail; } #endif /* USB_DEBUG */ /* * Disable the global interrupt until all the interrupt * handlers are installed. */ __DWC_WARN("USB INIT: Disabling global IRQ\n"); dwc_otg_disable_global_interrupts(dwc_otg_device->core_if); /* * Initialize the DWC_otg core. */ __DWC_WARN("USB INIT: Initializing OTG core\n"); dwc_otg_core_init(dwc_otg_device->core_if); /* * Initialize the PCD */ __DWC_WARN("USB INIT: Initializing PCD\n"); retval = pcd_init(dwc_otg_device); if (retval != 0) { __DWC_ERROR("pcd_init failed\n"); dwc_otg_device->pcd = NULL; goto fail; } __DWC_WARN("USB INIT: Enabling global IRQ\n"); dwc_otg_enable_global_interrupts(dwc_otg_device->core_if); __DWC_WARN("DWC core initialized! \n"); return 0; fail: __DWC_ERROR("ERROR! unable to init USB driver\n"); return retval; }
static int _setup(dwc_otg_pcd_t *pcd, uint8_t *bytes) { DWC_DEBUGPL(DBG_PCD, "%s(): enter \n", __func__); const usb_device_request_t *ctrlReq = (usb_device_request_t *)bytes; int value = 0; int idx; usb_device_request_t ctrlConvertedReq; usb_device_request_t *ctrl = &ctrlConvertedReq; ctrl->bmRequestType = (uByte)(ctrlReq->bmRequestType); ctrl->bRequest = (uByte)(ctrlReq->bRequest); ctrl->wValue[0] = ctrlReq->wValue[0]; ctrl->wValue[1] = ctrlReq->wValue[1]; ctrl->wIndex[0] = ctrlReq->wIndex[0]; ctrl->wIndex[1] = ctrlReq->wIndex[1]; ctrl->wLength[0] = ctrlReq->wLength[0]; ctrl->wLength[1] = ctrlReq->wLength[1]; /* * usually this stores reply data in the pre-allocated ep0 buffer, * but config change events will reconfigure hardware. */ static_data->dl_req.data.zero = 0; if (UT_GET_RECIPIENT(ctrl->bmRequestType) == UT_INTERFACE) { if ((UT_GET_DIR(ctrl->bmRequestType) == UT_WRITE) && (UGETW(ctrl->wLength) > 0)) { static_data->dl_req.data.buf = &static_data->ep0_buffer[0]; DWC_MEMCPY(&static_data->dl_req.out_req, ctrl, sizeof(*ctrl)); static_data->dl_req.data.length = DWC_MIN(UGETW( ctrl->wLength), static_data->ep0_buffer_size); // either shorter than asked, or multiple of the MPS require ZLP. static_data->dl_req.data.zero = ((value < UGETW(ctrl->wLength)) && ((value % pcd->ep0.dwc_ep. maxpacket) == 0)) ? 1 : 0; // Elaborate when getting the time. dwc_otg_pcd_ep_queue( pcd, /*void* ep_hanlde */ NULL, static_data->dl_req.data.buf, (dwc_dma_t)static_data->dl_req. data.buf, static_data->dl_req.data.length, static_data->dl_req.data.zero, /*void* req_handle */ &static_data ->dl_req, 0); } else { static_data->dl_req.data.buf = &static_data->ep0_buffer[0]; if (static_data->usb_class_handler(ctrl, &value, &static_data->dl_req .data.buf) != 0) { value = -DWC_E_NOT_SUPPORTED; } } } else { switch (ctrl->bRequest) { case UR_GET_DESCRIPTOR: __DWC_ERROR("ctrl->Length = %d \n", UGETW(ctrl->wLength)); switch (UGETW(ctrl->wValue) >> 8) { case UDESC_DEVICE: value = DWC_MIN(UGETW(ctrl->wLength), USB_DEVICE_DESCRIPTOR_SIZE); static_data->dl_req.data.buf = (uint8_t *) static_data-> usb_device_descriptor; break; case UDESC_CONFIG: value = DWC_MIN(UGETW(ctrl->wLength), UGETW(static_data-> usb_config_descriptor-> wTotalLength)); static_data->dl_req.data.buf = (uint8_t *) static_data-> usb_config_descriptor; break; case UDESC_OTHER_SPEED_CONFIGURATION: __DWC_ERROR ( "UDESC_OTHER_SPEED_CONFIGURATION NOT IMPLEMENTED! \n"); break; case UDESC_STRING: /* wIndex == language code. * this driver only handles one language, you can * add string tables for other languages, using * any UTF-8 characters */ idx = UGETW(ctrl->wValue) & 0xFF; __DWC_ERROR("UDESC_STRING idx = %d \n", idx); __DWC_ERROR( "UDESC_STRING bLength = %d \n", &static_data->strings_desc[idx]. bLength); if (idx > static_data->usb_strings_count) { if (idx == 0xEE) { // Microsoft MTP extension value = 0; } else { value = -DWC_E_INVALID; } } else { value = DWC_MIN(UGETW( ctrl->wLength), static_data-> strings_desc[idx]. bLength); static_data->dl_req.data.buf = (uint8_t *) & static_data->strings_desc[idx]; } break; } break; case UR_SET_CONFIG: static_data->usb_config = UGETW(ctrl->wValue); value = 0; { int i; for (i = 0; i < static_data->usb_num_endpoints; i++) { int ret = dwc_otg_pcd_ep_enable( pcd, (const uint8_t *)&static_data->usb_endpoints[ i], static_data ->usb_endpoints[i]. bEndpointAddress); __DWC_WARN( "Enabled endpoint: %x ret: %d\n", static_data->usb_endpoints[i ].bEndpointAddress, ret); } struct usb_event evt; evt.event = USB_EVENT_SET_CONFIG; evt.event_data.config = static_data->usb_config; if (static_data->usb_event_cb) { static_data->usb_event_cb(&evt); } } break; case UR_GET_CONFIG: static_data->dl_req.data.buf = &static_data->usb_config; value = DWC_MIN(UGETW(ctrl->wLength), 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 UR_SET_INTERFACE: value = 0; break; case UR_GET_INTERFACE: __DWC_ERROR("UR_GET_INTERFACE NOT IMPLEMENTED! \n"); goto unknown; break; default: unknown: value = -DWC_E_NOT_SUPPORTED; break; } } /* respond with data transfer before status phase? */ __DWC_ERROR("%s(): req.length = %d - max length is 64 \n", __func__, value); if (value >= 0) { static_data->dl_req.data.length = value; // either shorter than asked, or multiple of the MPS require ZLP. static_data->dl_req.data.zero = ((value < UGETW(ctrl->wLength)) && ((value % pcd->ep0.dwc_ep.maxpacket) == 0)) ? 1 : 0; // Elaborate when getting the time. dwc_otg_pcd_ep_queue(pcd, /*void* ep_hanlde */ NULL, static_data->dl_req.data.buf, (dwc_dma_t)static_data->dl_req.data.buf, static_data->dl_req.data.length, static_data->dl_req.data.zero, /*void* req_handle */ NULL, 0); } /* device either stalls (value < 0) or reports success */ return value; }