/*
 * 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");
}
Ejemplo n.º 2
0
/*
 * 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;
}
Ejemplo n.º 3
0
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;
}