⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 at91_udc.c

📁 linux下面gadget设备驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
	while (!list_empty(&ep->queue)) {		req = list_entry(ep->queue.next, struct at91_request, queue);		done(ep, req, status);	}}/*-------------------------------------------------------------------------*/static int at91_ep_enable(struct usb_ep *_ep,				const struct usb_endpoint_descriptor *desc){	struct at91_ep	*ep = container_of(_ep, struct at91_ep, ep);	struct at91_udc	*dev = ep->udc;	u16		maxpacket;	u32		tmp;	unsigned long	flags;	if (!_ep || !ep			|| !desc || ep->desc			|| _ep->name == ep0name			|| desc->bDescriptorType != USB_DT_ENDPOINT			|| (maxpacket = le16_to_cpu(desc->wMaxPacketSize)) == 0			|| maxpacket > ep->maxpacket) {		DBG("bad ep or descriptor\n");		return -EINVAL;	}	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {		DBG("bogus device state\n");		return -ESHUTDOWN;	}	tmp = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;	switch (tmp) {	case USB_ENDPOINT_XFER_CONTROL:		DBG("only one control endpoint\n");		return -EINVAL;	case USB_ENDPOINT_XFER_INT:		if (maxpacket > 64)			goto bogus_max;		break;	case USB_ENDPOINT_XFER_BULK:		switch (maxpacket) {		case 8:		case 16:		case 32:		case 64:			goto ok;		}bogus_max:		DBG("bogus maxpacket %d\n", maxpacket);		return -EINVAL;	case USB_ENDPOINT_XFER_ISOC:		if (!ep->is_pingpong) {			DBG("iso requires double buffering\n");			return -EINVAL;		}		break;	}ok:	local_irq_save(flags);	/* initialize endpoint to match this descriptor */	ep->is_in = (desc->bEndpointAddress & USB_DIR_IN) != 0;	ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC);	ep->stopped = 0;	if (ep->is_in)		tmp |= 0x04;	tmp <<= 8;	tmp |= AT91_UDP_EPEDS;	__raw_writel(tmp, ep->creg);	ep->desc = desc;	ep->ep.maxpacket = maxpacket;	/*	 * reset/init endpoint fifo.  NOTE:  leaves fifo_bank alone,	 * since endpoint resets don't reset hw pingpong state.	 */	at91_udp_write(dev, AT91_UDP_RST_EP, ep->int_mask);	at91_udp_write(dev, AT91_UDP_RST_EP, 0);	local_irq_restore(flags);	return 0;}static int at91_ep_disable (struct usb_ep * _ep){	struct at91_ep	*ep = container_of(_ep, struct at91_ep, ep);	struct at91_udc	*udc = ep->udc;	unsigned long	flags;	if (ep == &ep->udc->ep[0])		return -EINVAL;	local_irq_save(flags);	nuke(ep, -ESHUTDOWN);	/* restore the endpoint's pristine config */	ep->desc = NULL;	ep->ep.maxpacket = ep->maxpacket;	/* reset fifos and endpoint */	if (ep->udc->clocked) {		at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);		at91_udp_write(udc, AT91_UDP_RST_EP, 0);		__raw_writel(0, ep->creg);	}	local_irq_restore(flags);	return 0;}/* * this is a PIO-only driver, so there's nothing * interesting for request or buffer allocation. */static struct usb_request *at91_ep_alloc_request(struct usb_ep *_ep, unsigned int gfp_flags){	struct at91_request *req;	req = kzalloc(sizeof (struct at91_request), gfp_flags);	if (!req)		return NULL;	INIT_LIST_HEAD(&req->queue);	return &req->req;}static void at91_ep_free_request(struct usb_ep *_ep, struct usb_request *_req){	struct at91_request *req;	req = container_of(_req, struct at91_request, req);	BUG_ON(!list_empty(&req->queue));	kfree(req);}static int at91_ep_queue(struct usb_ep *_ep,			struct usb_request *_req, gfp_t gfp_flags){	struct at91_request	*req;	struct at91_ep		*ep;	struct at91_udc		*dev;	int			status;	unsigned long		flags;	req = container_of(_req, struct at91_request, req);	ep = container_of(_ep, struct at91_ep, ep);	if (!_req || !_req->complete			|| !_req->buf || !list_empty(&req->queue)) {		DBG("invalid request\n");		return -EINVAL;	}	if (!_ep || (!ep->desc && ep->ep.name != ep0name)) {		DBG("invalid ep\n");		return -EINVAL;	}	dev = ep->udc;	if (!dev || !dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {		DBG("invalid device\n");		return -EINVAL;	}	_req->status = -EINPROGRESS;	_req->actual = 0;	local_irq_save(flags);	/* try to kickstart any empty and idle queue */	if (list_empty(&ep->queue) && !ep->stopped) {		int	is_ep0;		/*		 * If this control request has a non-empty DATA stage, this		 * will start that stage.  It works just like a non-control		 * request (until the status stage starts, maybe early).		 *		 * If the data stage is empty, then this starts a successful		 * IN/STATUS stage.  (Unsuccessful ones use set_halt.)		 */		is_ep0 = (ep->ep.name == ep0name);		if (is_ep0) {			u32	tmp;			if (!dev->req_pending) {				status = -EINVAL;				goto done;			}			/*			 * defer changing CONFG until after the gadget driver			 * reconfigures the endpoints.			 */			if (dev->wait_for_config_ack) {				tmp = at91_udp_read(dev, AT91_UDP_GLB_STAT);				tmp ^= AT91_UDP_CONFG;				VDBG("toggle config\n");				at91_udp_write(dev, AT91_UDP_GLB_STAT, tmp);			}			if (req->req.length == 0) {ep0_in_status:				PACKET("ep0 in/status\n");				status = 0;				tmp = __raw_readl(ep->creg);				tmp &= ~SET_FX;				tmp |= CLR_FX | AT91_UDP_TXPKTRDY;				__raw_writel(tmp, ep->creg);				dev->req_pending = 0;				goto done;			}		}		if (ep->is_in)			status = write_fifo(ep, req);		else {			status = read_fifo(ep, req);			/* IN/STATUS stage is otherwise triggered by irq */			if (status && is_ep0)				goto ep0_in_status;		}	} else		status = 0;	if (req && !status) {		list_add_tail (&req->queue, &ep->queue);		at91_udp_write(dev, AT91_UDP_IER, ep->int_mask);	}done:	local_irq_restore(flags);	return (status < 0) ? status : 0;}static int at91_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req){	struct at91_ep	*ep;	struct at91_request	*req;	ep = container_of(_ep, struct at91_ep, ep);	if (!_ep || ep->ep.name == ep0name)		return -EINVAL;	/* make sure it's actually queued on this endpoint */	list_for_each_entry (req, &ep->queue, queue) {		if (&req->req == _req)			break;	}	if (&req->req != _req)		return -EINVAL;	done(ep, req, -ECONNRESET);	return 0;}static int at91_ep_set_halt(struct usb_ep *_ep, int value){	struct at91_ep	*ep = container_of(_ep, struct at91_ep, ep);	struct at91_udc	*udc = ep->udc;	u32 __iomem	*creg;	u32		csr;	unsigned long	flags;	int		status = 0;	if (!_ep || ep->is_iso || !ep->udc->clocked)		return -EINVAL;	creg = ep->creg;	local_irq_save(flags);	csr = __raw_readl(creg);	/*	 * fail with still-busy IN endpoints, ensuring correct sequencing	 * of data tx then stall.  note that the fifo rx bytecount isn't	 * completely accurate as a tx bytecount.	 */	if (ep->is_in && (!list_empty(&ep->queue) || (csr >> 16) != 0))		status = -EAGAIN;	else {		csr |= CLR_FX;		csr &= ~SET_FX;		if (value) {			csr |= AT91_UDP_FORCESTALL;			VDBG("halt %s\n", ep->ep.name);		} else {			at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);			at91_udp_write(udc, AT91_UDP_RST_EP, 0);			csr &= ~AT91_UDP_FORCESTALL;		}		__raw_writel(csr, creg);	}	local_irq_restore(flags);	return status;}static const struct usb_ep_ops at91_ep_ops = {	.enable		= at91_ep_enable,	.disable	= at91_ep_disable,	.alloc_request	= at91_ep_alloc_request,	.free_request	= at91_ep_free_request,	.queue		= at91_ep_queue,	.dequeue	= at91_ep_dequeue,	.set_halt	= at91_ep_set_halt,	// there's only imprecise fifo status reporting};/*-------------------------------------------------------------------------*/static int at91_get_frame(struct usb_gadget *gadget){	struct at91_udc *udc = to_udc(gadget);	if (!to_udc(gadget)->clocked)		return -EINVAL;	return at91_udp_read(udc, AT91_UDP_FRM_NUM) & AT91_UDP_NUM;}static int at91_wakeup(struct usb_gadget *gadget){	struct at91_udc	*udc = to_udc(gadget);	u32		glbstate;	int		status = -EINVAL;	unsigned long	flags;	DBG("%s\n", __FUNCTION__ );	local_irq_save(flags);	if (!udc->clocked || !udc->suspended)		goto done;	/* NOTE:  some "early versions" handle ESR differently ... */	glbstate = at91_udp_read(udc, AT91_UDP_GLB_STAT);	if (!(glbstate & AT91_UDP_ESR))		goto done;	glbstate |= AT91_UDP_ESR;	at91_udp_write(udc, AT91_UDP_GLB_STAT, glbstate);done:	local_irq_restore(flags);	return status;}/* reinit == restore inital software state */static void udc_reinit(struct at91_udc *udc){	u32 i;	INIT_LIST_HEAD(&udc->gadget.ep_list);	INIT_LIST_HEAD(&udc->gadget.ep0->ep_list);	for (i = 0; i < NUM_ENDPOINTS; i++) {		struct at91_ep *ep = &udc->ep[i];		if (i != 0)			list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);		ep->desc = NULL;		ep->stopped = 0;		ep->fifo_bank = 0;		ep->ep.maxpacket = ep->maxpacket;		ep->creg = (void __iomem *) udc->udp_baseaddr + AT91_UDP_CSR(i);		// initialiser une queue par endpoint		INIT_LIST_HEAD(&ep->queue);	}}static void stop_activity(struct at91_udc *udc){	struct usb_gadget_driver *driver = udc->driver;	int i;	if (udc->gadget.speed == USB_SPEED_UNKNOWN)		driver = NULL;	udc->gadget.speed = USB_SPEED_UNKNOWN;	udc->suspended = 0;	for (i = 0; i < NUM_ENDPOINTS; i++) {		struct at91_ep *ep = &udc->ep[i];		ep->stopped = 1;		nuke(ep, -ESHUTDOWN);	}	if (driver)		driver->disconnect(&udc->gadget);	udc_reinit(udc);}static void clk_on(struct at91_udc *udc){	if (udc->clocked)		return;	udc->clocked = 1;	clk_enable(udc->iclk);	clk_enable(udc->fclk);}static void clk_off(struct at91_udc *udc){	if (!udc->clocked)		return;	udc->clocked = 0;	udc->gadget.speed = USB_SPEED_UNKNOWN;	clk_disable(udc->fclk);	clk_disable(udc->iclk);}/* * activate/deactivate link with host; minimize power usage for * inactive links by cutting clocks and transceiver power. */static void pullup(struct at91_udc *udc, int is_on){	if (!udc->enabled || !udc->vbus)		is_on = 0;	DBG("%sactive\n", is_on ? "" : "in");	if (is_on) {		clk_on(udc);		at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM);		at91_udp_write(udc, AT91_UDP_TXVC, 0);		if (cpu_is_at91rm9200())			at91_set_gpio_value(udc->board.pullup_pin, 1);		else if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) {			u32	txvc = at91_udp_read(udc, AT91_UDP_TXVC);			txvc |= AT91_UDP_TXVC_PUON;			at91_udp_write(udc, AT91_UDP_TXVC, txvc);		} else if (cpu_is_at91sam9261()) {			u32	usbpucr;			usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR);			usbpucr |= AT91_MATRIX_USBPUCR_PUON;			at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr);		}	} else {		stop_activity(udc);		at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM);		at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);		if (cpu_is_at91rm9200())			at91_set_gpio_value(udc->board.pullup_pin, 0);		else if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) {			u32	txvc = at91_udp_read(udc, AT91_UDP_TXVC);			txvc &= ~AT91_UDP_TXVC_PUON;			at91_udp_write(udc, AT91_UDP_TXVC, txvc);		} else if (cpu_is_at91sam9261()) {			u32	usbpucr;			usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR);			usbpucr &= ~AT91_MATRIX_USBPUCR_PUON;			at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -