drivers/usb/cdns3/cdns3-gadget.c

Source file repositories/reference/linux-study-clean/drivers/usb/cdns3/cdns3-gadget.c

File Facts

System
Linux kernel
Corpus path
drivers/usb/cdns3/cdns3-gadget.c
Extension
.c
Size
96066 bytes
Lines
3525
Domain
Driver Families
Bucket
drivers/usb
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (!priv_ep->use_streams) {
			ret = cdns3_ep_run_transfer(priv_ep, request);
		} else {
			priv_ep->stream_sg_idx = 0;
			ret = cdns3_ep_run_stream_transfer(priv_ep, request);
		}
		if (ret)
			return ret;

		list_move_tail(&request->list, &priv_ep->pending_req_list);
		if (request->stream_id != 0 || (priv_ep->flags & EP_TDLCHK_EN))
			break;
	}

	priv_ep->flags &= ~EP_RING_FULL;
	return ret;
}

/*
 * WA2: Set flag for all not ISOC OUT endpoints. If this flag is set
 * driver try to detect whether endpoint need additional internal
 * buffer for unblocking on-chip FIFO buffer. This flag will be cleared
 * if before first DESCMISS interrupt the DMA will be armed.
 */
#define cdns3_wa2_enable_detection(priv_dev, priv_ep, reg) do { \
	if (!priv_ep->dir && priv_ep->type != USB_ENDPOINT_XFER_ISOC) { \
		priv_ep->flags |= EP_QUIRK_EXTRA_BUF_DET; \
		(reg) |= EP_STS_EN_DESCMISEN; \
	} } while (0)

static void __cdns3_descmiss_copy_data(struct usb_request *request,
	struct usb_request *descmiss_req)
{
	int length = request->actual + descmiss_req->actual;
	struct scatterlist *s = request->sg;

	if (!s) {
		if (length <= request->length) {
			memcpy(&((u8 *)request->buf)[request->actual],
			       descmiss_req->buf,
			       descmiss_req->actual);
			request->actual = length;
		} else {
			/* It should never occures */
			request->status = -ENOMEM;
		}
	} else {
		if (length <= sg_dma_len(s)) {
			void *p = phys_to_virt(sg_dma_address(s));

			memcpy(&((u8 *)p)[request->actual],
				descmiss_req->buf,
				descmiss_req->actual);
			request->actual = length;
		} else {
			request->status = -ENOMEM;
		}
	}
}

/**
 * cdns3_wa2_descmiss_copy_data - copy data from internal requests to
 * request queued by class driver.
 * @priv_ep: extended endpoint object
 * @request: request object
 */
static void cdns3_wa2_descmiss_copy_data(struct cdns3_endpoint *priv_ep,
					 struct usb_request *request)
{
	struct usb_request *descmiss_req;
	struct cdns3_request *descmiss_priv_req;

	while (!list_empty(&priv_ep->wa2_descmiss_req_list)) {
		int chunk_end;

		descmiss_priv_req =
			cdns3_next_priv_request(&priv_ep->wa2_descmiss_req_list);
		descmiss_req = &descmiss_priv_req->request;

		/* driver can't touch pending request */
		if (descmiss_priv_req->flags & REQUEST_PENDING)
			break;

		chunk_end = descmiss_priv_req->flags & REQUEST_INTERNAL_CH;
		request->status = descmiss_req->status;
		__cdns3_descmiss_copy_data(request, descmiss_req);
		list_del_init(&descmiss_priv_req->list);
		kfree(descmiss_req->buf);
		cdns3_gadget_ep_free_request(&priv_ep->endpoint, descmiss_req);
		--priv_ep->wa2_counter;

Annotation

Implementation Notes