Example #1
0
/**
 * This function is used to submit an I/O Request to an EP.
 *
 *	- When the request completes the request's completion callback
 *	  is called to return the request to the driver.
 *	- An EP, except control EPs, may have multiple requests
 *	  pending.
 *	- Once submitted the request cannot be examined or modified.
 *	- Each request is turned into one or more packets.
 *	- A BULK EP can queue any amount of data; the transfer is
 *	  packetized.
 *	- Zero length Packets are specified with the request 'zero'
 *	  flag.
 */
static int ep_queue(struct usb_ep *usb_ep, struct usb_request *usb_req,
		    gfp_t gfp_flags)
{
	dwc_otg_pcd_t *pcd;
	int retval = 0;

	//trace_printk("(%p,%p,%d)\n",
	//	    usb_ep, usb_req, gfp_flags);

	if (!usb_req || !usb_req->complete ||
		(!gadget_wrapper->gadget.sg_supported &&
			!usb_req->buf)) {
		DWC_WARN("bad params\n");
		return -EINVAL;
	}

	if (!usb_ep) {
		DWC_WARN("bad ep\n");
		return -EINVAL;
	}

	pcd = gadget_wrapper->pcd;
	if (!gadget_wrapper->driver ||
	    gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
		DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
			    gadget_wrapper->gadget.speed);
		DWC_WARN("bogus device state\n");
		return -ESHUTDOWN;
	}

	//trace_printk( "%s queue req %p, len %d buf %p\n",
	//	    usb_ep->name, usb_req, usb_req->length, usb_req->buf);

	usb_req->status = -EINPROGRESS;
	usb_req->actual = 0;

	retval = dwc_otg_pcd_ep_queue(pcd, usb_ep, usb_req->buf, usb_req->dma/*dma_addr*/,
				      usb_req->length, usb_req->zero, usb_req->num_sgs,
				      usb_req->sg, usb_req, gfp_flags == GFP_ATOMIC ? 1 : 0);
	if (retval) {
		pr_err("%s, cannot enqueue a renquest, err :%d\n", __func__,
			retval);
		pr_info( "%s queue req %p, len %d buf %p\n",
			    usb_ep->name, usb_req, usb_req->length, usb_req->buf);
		return -EINVAL;
	}

	return 0;
}
/**
 * This function is used to submit an I/O Request to an EP.
 *
 *	- When the request completes the request's completion callback
 *	  is called to return the request to the driver.
 *	- An EP, except control EPs, may have multiple requests
 *	  pending.
 *	- Once submitted the request cannot be examined or modified.
 *	- Each request is turned into one or more packets.
 *	- A BULK EP can queue any amount of data; the transfer is
 *	  packetized.
 *	- Zero length Packets are specified with the request 'zero'
 *	  flag.
 */
static int ep_queue(struct usb_ep *usb_ep, struct usb_request *usb_req,
		    gfp_t gfp_flags)
{
	dwc_otg_pcd_t *pcd;
	int retval;

	DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p,%d)\n",
		    __func__, usb_ep, usb_req, gfp_flags);

	if (!usb_req || !usb_req->complete || !usb_req->buf) {
		DWC_WARN("bad params\n");
		return -EINVAL;
	}

	if (!usb_ep) {
		DWC_WARN("bad ep\n");
		return -EINVAL;
	}

	pcd = gadget_wrapper->pcd;
	if (!gadget_wrapper->driver ||
	    gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
		DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
			    gadget_wrapper->gadget.speed);
		DWC_WARN("bogus device state\n");
		return -ESHUTDOWN;
	}

	DWC_DEBUGPL(DBG_PCD, "%s queue req %p, len %d buf %p\n",
		    usb_ep->name, usb_req, usb_req->length, usb_req->buf);

	usb_req->status = -EINPROGRESS;
	usb_req->actual = 0;

	retval = dwc_otg_pcd_ep_queue(pcd, usb_ep, usb_req->buf, usb_req->dma,
				      usb_req->length, usb_req->zero, usb_req,
				      gfp_flags == GFP_ATOMIC ? 1 : 0);
	if (retval) {
		return -EINVAL;
	}

	return 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;
}
int usb_ep_write(int ep_address, uint8_t *buf, int len, void *priv)
{
	return dwc_otg_pcd_ep_queue(dwc_otg_device->pcd, ep_address, buf, buf,
				    len, 0, priv, 0);
}