drivers/usb/gadget/udc/snps_udc_core.c

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

File Facts

System
Linux kernel
Corpus path
drivers/usb/gadget/udc/snps_udc_core.c
Extension
.c
Size
81709 bytes
Lines
3193
Domain
Driver Families
Bucket
drivers/usb
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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 (dev->ep[i].regs) {
			/* read fifo size */
			tmp = readl(&dev->ep[i].regs->bufin_framenum);
			tmp = AMD_GETBITS(tmp, UDC_EPIN_BUFF_SIZE);
			ep->txfifo += tmp;
		}
	}
	return 0;
}

/* CNAK pending field: bit0 = ep0in, bit16 = ep0out */
static u32 cnak_pending;

static void UDC_QUEUE_CNAK(struct udc_ep *ep, unsigned num)
{
	if (readl(&ep->regs->ctl) & AMD_BIT(UDC_EPCTL_NAK)) {
		DBG(ep->dev, "NAK could not be cleared for ep%d\n", num);
		cnak_pending |= 1 << (num);
		ep->naking = 1;
	} else
		cnak_pending = cnak_pending & (~(1 << (num)));
}


/* Enables endpoint, is called by gadget driver */
static int
udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc)
{
	struct udc_ep		*ep;
	struct udc		*dev;
	u32			tmp;
	unsigned long		iflags;
	u8 udc_csr_epix;
	unsigned		maxpacket;

	if (!usbep
			|| usbep->name == ep0_string
			|| !desc
			|| desc->bDescriptorType != USB_DT_ENDPOINT)
		return -EINVAL;

	ep = container_of(usbep, struct udc_ep, ep);
	dev = ep->dev;

	DBG(dev, "udc_ep_enable() ep %d\n", ep->num);

	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
		return -ESHUTDOWN;

	spin_lock_irqsave(&dev->lock, iflags);
	ep->ep.desc = desc;

	ep->halted = 0;

	/* set traffic type */
	tmp = readl(&dev->ep[ep->num].regs->ctl);
	tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_EPCTL_ET);
	writel(tmp, &dev->ep[ep->num].regs->ctl);

	/* set max packet size */
	maxpacket = usb_endpoint_maxp(desc);
	tmp = readl(&dev->ep[ep->num].regs->bufout_maxpkt);
	tmp = AMD_ADDBITS(tmp, maxpacket, UDC_EP_MAX_PKT_SIZE);
	ep->ep.maxpacket = maxpacket;
	writel(tmp, &dev->ep[ep->num].regs->bufout_maxpkt);

	/* IN ep */
	if (ep->in) {

		/* ep ix in UDC CSR register space */
		udc_csr_epix = ep->num;

		/* set buffer size (tx fifo entries) */
		tmp = readl(&dev->ep[ep->num].regs->bufin_framenum);
		/* double buffering: fifo size = 2 x max packet size */
		tmp = AMD_ADDBITS(
				tmp,
				maxpacket * UDC_EPIN_BUFF_SIZE_MULT
					  / UDC_DWORD_BYTES,
				UDC_EPIN_BUFF_SIZE);
		writel(tmp, &dev->ep[ep->num].regs->bufin_framenum);

		/* calc. tx fifo base addr */
		udc_set_txfifo_addr(ep);

		/* flush fifo */
		tmp = readl(&ep->regs->ctl);
		tmp |= AMD_BIT(UDC_EPCTL_F);
		writel(tmp, &ep->regs->ctl);

Annotation

Implementation Notes