drivers/usb/chipidea/udc.c

Source file repositories/reference/linux-study-clean/drivers/usb/chipidea/udc.c

File Facts

System
Linux kernel
Corpus path
drivers/usb/chipidea/udc.c
Extension
.c
Size
59675 bytes
Lines
2447
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 (sg_dma_address(s) % PAGE_SIZE) {
			dev_err(hwep->ci->dev, "not page aligned sg buffer\n");
			return -EINVAL;
		}

		if (node && (node->td_remaining_size >= sg_dma_len(s))) {
			ci_add_buffer_entry(node, s);
			node->td_remaining_size -= sg_dma_len(s);
		} else {
			ret = prepare_td_per_sg(hwep, hwreq, s);
			if (ret)
				return ret;

			node = list_entry(hwreq->tds.prev,
				struct td_node, td);
		}

		s = sg_next(s);
	}

	return ret;
}

/*
 * Verify if the scatterlist is valid by iterating each sg entry.
 * Return invalid sg entry index which is less than num_sgs.
 */
static int sglist_get_invalid_entry(struct device *dma_dev, u8 dir,
			struct usb_request *req)
{
	int i;
	struct scatterlist *s = req->sg;

	if (req->num_sgs == 1)
		return 1;

	dir = dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE;

	for (i = 0; i < req->num_sgs; i++, s = sg_next(s)) {
		/* Only small sg (generally last sg) may be bounced. If
		 * that happens. we can't ensure the addr is page-aligned
		 * after dma map.
		 */
		if (dma_kmalloc_needs_bounce(dma_dev, s->length, dir))
			break;

		/* Make sure each sg start address (except first sg) is
		 * page-aligned and end address (except last sg) is also
		 * page-aligned.
		 */
		if (i == 0) {
			if (!IS_ALIGNED(s->offset + s->length,
						CI_HDRC_PAGE_SIZE))
				break;
		} else {
			if (s->offset)
				break;
			if (!sg_is_last(s) && !IS_ALIGNED(s->length,
						CI_HDRC_PAGE_SIZE))
				break;
		}
	}

	return i;
}

static int sglist_do_bounce(struct ci_hw_req *hwreq, int index,
			bool copy, unsigned int *bounced)
{
	void *buf;
	int i, ret, nents, num_sgs;
	unsigned int rest, rounded;
	struct scatterlist *sg, *src, *dst;

	nents = index + 1;
	ret = sg_alloc_table(&hwreq->sgt, nents, GFP_KERNEL);
	if (ret)
		return ret;

	sg = src = hwreq->req.sg;
	num_sgs = hwreq->req.num_sgs;
	rest = hwreq->req.length;
	dst = hwreq->sgt.sgl;

	for (i = 0; i < index; i++) {
		memcpy(dst, src, sizeof(*src));
		rest -= src->length;
		src = sg_next(src);
		dst = sg_next(dst);
	}

Annotation

Implementation Notes