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

📄 lh7a40x_udc.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
		      _ep ? ep->ep.name : NULL);		return -EINVAL;	}	spin_lock_irqsave(&ep->dev->lock, flags);	usb_set_index(ep_index(ep));	/* Nuke all pending requests (does flush) */	nuke(ep, -ESHUTDOWN);	/* Disable ep IRQ */	pio_irq_disable(ep_index(ep));	ep->desc = 0;	ep->stopped = 1;	spin_unlock_irqrestore(&ep->dev->lock, flags);	DEBUG("%s: disabled %s\n", __FUNCTION__, _ep->name);	return 0;}static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep,						 gfp_t gfp_flags){	struct lh7a40x_request *req;	DEBUG("%s, %p\n", __FUNCTION__, ep);	req = kmalloc(sizeof *req, gfp_flags);	if (!req)		return 0;	memset(req, 0, sizeof *req);	INIT_LIST_HEAD(&req->queue);	return &req->req;}static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *_req){	struct lh7a40x_request *req;	DEBUG("%s, %p\n", __FUNCTION__, ep);	req = container_of(_req, struct lh7a40x_request, req);	WARN_ON(!list_empty(&req->queue));	kfree(req);}static void *lh7a40x_alloc_buffer(struct usb_ep *ep, unsigned bytes,				  dma_addr_t * dma, gfp_t gfp_flags){	char *retval;	DEBUG("%s (%p, %d, %d)\n", __FUNCTION__, ep, bytes, gfp_flags);	retval = kmalloc(bytes, gfp_flags & ~(__GFP_DMA | __GFP_HIGHMEM));	if (retval)		*dma = virt_to_bus(retval);	return retval;}static void lh7a40x_free_buffer(struct usb_ep *ep, void *buf, dma_addr_t dma,				unsigned bytes){	DEBUG("%s, %p\n", __FUNCTION__, ep);	kfree(buf);}/** Queue one request *  Kickstart transfer if needed *  NOTE: Sets INDEX register */static int lh7a40x_queue(struct usb_ep *_ep, struct usb_request *_req,			 gfp_t gfp_flags){	struct lh7a40x_request *req;	struct lh7a40x_ep *ep;	struct lh7a40x_udc *dev;	unsigned long flags;	DEBUG("\n\n\n%s, %p\n", __FUNCTION__, _ep);	req = container_of(_req, struct lh7a40x_request, req);	if (unlikely	    (!_req || !_req->complete || !_req->buf	     || !list_empty(&req->queue))) {		DEBUG("%s, bad params\n", __FUNCTION__);		return -EINVAL;	}	ep = container_of(_ep, struct lh7a40x_ep, ep);	if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) {		DEBUG("%s, bad ep\n", __FUNCTION__);		return -EINVAL;	}	dev = ep->dev;	if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) {		DEBUG("%s, bogus device state %p\n", __FUNCTION__, dev->driver);		return -ESHUTDOWN;	}	DEBUG("%s queue req %p, len %d buf %p\n", _ep->name, _req, _req->length,	      _req->buf);	spin_lock_irqsave(&dev->lock, flags);	_req->status = -EINPROGRESS;	_req->actual = 0;	/* kickstart this i/o queue? */	DEBUG("Add to %d Q %d %d\n", ep_index(ep), list_empty(&ep->queue),	      ep->stopped);	if (list_empty(&ep->queue) && likely(!ep->stopped)) {		u32 csr;		if (unlikely(ep_index(ep) == 0)) {			/* EP0 */			list_add_tail(&req->queue, &ep->queue);			lh7a40x_ep0_kick(dev, ep);			req = 0;		} else if (ep_is_in(ep)) {			/* EP1 & EP3 */			usb_set_index(ep_index(ep));			csr = usb_read(ep->csr1);			pio_irq_enable(ep_index(ep));			if ((csr & USB_IN_CSR1_FIFO_NOT_EMPTY) == 0) {				if (write_fifo(ep, req) == 1)					req = 0;			}		} else {			/* EP2 */			usb_set_index(ep_index(ep));			csr = usb_read(ep->csr1);			pio_irq_enable(ep_index(ep));			if (!(csr & USB_OUT_CSR1_FIFO_FULL)) {				if (read_fifo(ep, req) == 1)					req = 0;			}		}	}	/* pio or dma irq handler advances the queue. */	if (likely(req != 0))		list_add_tail(&req->queue, &ep->queue);	spin_unlock_irqrestore(&dev->lock, flags);	return 0;}/* dequeue JUST ONE request */static int lh7a40x_dequeue(struct usb_ep *_ep, struct usb_request *_req){	struct lh7a40x_ep *ep;	struct lh7a40x_request *req;	unsigned long flags;	DEBUG("%s, %p\n", __FUNCTION__, _ep);	ep = container_of(_ep, struct lh7a40x_ep, ep);	if (!_ep || ep->ep.name == ep0name)		return -EINVAL;	spin_lock_irqsave(&ep->dev->lock, flags);	/* 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) {		spin_unlock_irqrestore(&ep->dev->lock, flags);		return -EINVAL;	}	done(ep, req, -ECONNRESET);	spin_unlock_irqrestore(&ep->dev->lock, flags);	return 0;}/** Halt specific EP *  Return 0 if success *  NOTE: Sets INDEX register to EP ! */static int lh7a40x_set_halt(struct usb_ep *_ep, int value){	struct lh7a40x_ep *ep;	unsigned long flags;	ep = container_of(_ep, struct lh7a40x_ep, ep);	if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) {		DEBUG("%s, bad ep\n", __FUNCTION__);		return -EINVAL;	}	usb_set_index(ep_index(ep));	DEBUG("%s, ep %d, val %d\n", __FUNCTION__, ep_index(ep), value);	spin_lock_irqsave(&ep->dev->lock, flags);	if (ep_index(ep) == 0) {		/* EP0 */		usb_set(EP0_SEND_STALL, ep->csr1);	} else if (ep_is_in(ep)) {		u32 csr = usb_read(ep->csr1);		if (value && ((csr & USB_IN_CSR1_FIFO_NOT_EMPTY)			      || !list_empty(&ep->queue))) {			/*			 * Attempts to halt IN endpoints will fail (returning -EAGAIN)			 * if any transfer requests are still queued, or if the controller			 * FIFO still holds bytes that the host hasn抰 collected.			 */			spin_unlock_irqrestore(&ep->dev->lock, flags);			DEBUG			    ("Attempt to halt IN endpoint failed (returning -EAGAIN) %d %d\n",			     (csr & USB_IN_CSR1_FIFO_NOT_EMPTY),			     !list_empty(&ep->queue));			return -EAGAIN;		}		flush(ep);		if (value)			usb_set(USB_IN_CSR1_SEND_STALL, ep->csr1);		else {			usb_clear(USB_IN_CSR1_SEND_STALL, ep->csr1);			usb_set(USB_IN_CSR1_CLR_DATA_TOGGLE, ep->csr1);		}	} else {		flush(ep);		if (value)			usb_set(USB_OUT_CSR1_SEND_STALL, ep->csr1);		else {			usb_clear(USB_OUT_CSR1_SEND_STALL, ep->csr1);			usb_set(USB_OUT_CSR1_CLR_DATA_REG, ep->csr1);		}	}	if (value) {		ep->stopped = 1;	} else {		ep->stopped = 0;	}	spin_unlock_irqrestore(&ep->dev->lock, flags);	DEBUG("%s %s halted\n", _ep->name, value == 0 ? "NOT" : "IS");	return 0;}/** Return bytes in EP FIFO *  NOTE: Sets INDEX register to EP */static int lh7a40x_fifo_status(struct usb_ep *_ep){	u32 csr;	int count = 0;	struct lh7a40x_ep *ep;	ep = container_of(_ep, struct lh7a40x_ep, ep);	if (!_ep) {		DEBUG("%s, bad ep\n", __FUNCTION__);		return -ENODEV;	}	DEBUG("%s, %d\n", __FUNCTION__, ep_index(ep));	/* LPD can't report unclaimed bytes from IN fifos */	if (ep_is_in(ep))		return -EOPNOTSUPP;	usb_set_index(ep_index(ep));	csr = usb_read(ep->csr1);	if (ep->dev->gadget.speed != USB_SPEED_UNKNOWN ||	    csr & USB_OUT_CSR1_OUT_PKT_RDY) {		count = usb_read(USB_OUT_FIFO_WC1);	}	return count;}/** Flush EP FIFO *  NOTE: Sets INDEX register to EP */static void lh7a40x_fifo_flush(struct usb_ep *_ep){	struct lh7a40x_ep *ep;	ep = container_of(_ep, struct lh7a40x_ep, ep);	if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) {		DEBUG("%s, bad ep\n", __FUNCTION__);		return;	}	usb_set_index(ep_index(ep));	flush(ep);}/****************************************************************//* End Point 0 related functions                                *//****************************************************************//* return:  0 = still running, 1 = completed, negative = errno */static int write_fifo_ep0(struct lh7a40x_ep *ep, struct lh7a40x_request *req){	u32 max;	unsigned count;	int is_last;	max = ep_maxpacket(ep);	DEBUG_EP0("%s\n", __FUNCTION__);	count = write_packet(ep, req, max);	/* last packet is usually short (or a zlp) */	if (unlikely(count != max))		is_last = 1;	else {		if (likely(req->req.length != req->req.actual) || req->req.zero)			is_last = 0;		else			is_last = 1;	}	DEBUG_EP0("%s: wrote %s %d bytes%s %d left %p\n", __FUNCTION__,		  ep->ep.name, count,		  is_last ? "/L" : "", req->req.length - req->req.actual, req);	/* requests complete when all IN data is in the FIFO */	if (is_last) {		done(ep, req, 0);		return 1;	}	return 0;}static __inline__ int lh7a40x_fifo_read(struct lh7a40x_ep *ep,					unsigned char *cp, int max){	int bytes;	int count = usb_read(USB_OUT_FIFO_WC1);	volatile u32 *fifo = (volatile u32 *)ep->fifo;	if (count > max)		count = max;	bytes = count;	while (count--)		*cp++ = *fifo & 0xFF;	return bytes;}static __inline__ void lh7a40x_fifo_write(struct lh7a40x_ep *ep,					  unsigned char *cp, int count){	volatile u32 *fifo = (volatile u32 *)ep->fifo;	DEBUG_EP0("fifo_write: %d %d\n", ep_index(ep), count);	while (count--)		*fifo = *cp++;}static int read_fifo_ep0(struct lh7a40x_ep *ep, struct lh7a40x_request *req){	u32 csr;	u8 *buf;	unsigned bufferspace, count, is_short;	volatile u32 *fifo = (volatile u32 *)ep->fifo;	DEBUG_EP0("%s\n", __FUNCTION__);	csr = usb_read(USB_EP0_CSR);	if (!(csr & USB_OUT_CSR1_OUT_PKT_RDY))		return 0;	buf = req->req.buf + req->req.actual;	prefetchw(buf);	bufferspace = req->req.length - req->req.actual;	/* read all bytes from this packet */	if (likely(csr & EP0_OUT_PKT_RDY)) {		count = usb_read(USB_OUT_FIFO_WC1);		req->req.actual += min(count, bufferspace);	} else			/* zlp */		count = 0;	is_short = (count < ep->ep.maxpacket);	DEBUG_EP0("read %s %02x, %d bytes%s req %p %d/%d\n",		  ep->ep.name, csr, count,		  is_short ? "/S" : "", req, req->req.actual, req->req.length);	while (likely(count-- != 0)) {		u8 byte = (u8) (*fifo & 0xff);		if (unlikely(bufferspace == 0)) {			/* this happens when the driver's buffer			 * is smaller than what the host sent.			 * discard the extra data.			 */			if (req->req.status != -EOVERFLOW)				DEBUG_EP0("%s overflow %d\n", ep->ep.name,					  count);			req->req.status = -EOVERFLOW;		} else {			*buf++ = byte;			bufferspace--;		}	}	/* completion */	if (is_short || req->req.actual == req->req.length) {		done(ep, req, 0);		return 1;	}	/* finished that packet.  the next one may be waiting... */	return 0;}/** * udc_set_address - set the USB address for this device * @address: * * Called from control endpoint function after it decodes a set address setup packet. */static void udc_set_address(struct lh7a40x_udc *dev, unsigned char address){	DEBUG_EP0("%s: %d\n", __FUNCTION__, address);	/* c.f. 15.1.2.2 Table 15-4 address will be used after DATA_END is set */	dev->usb_address = address;	usb_set((address & USB_FA_FUNCTION_ADDR), USB_FA);	usb_set(USB_FA_ADDR_UPDATE | (address & USB_FA_FUNCTION_ADDR), USB_FA);	/* usb_read(USB_FA); */}/* * DATA_STATE_RECV (OUT_PKT_RDY) *      - if error *              set EP0_CLR_OUT | EP0_DATA_END | EP0_SEND_STALL bits *      - else *              set EP0_CLR_OUT bit 				if last set EP0_DATA_END bit */static void lh7a40x_ep0_out(struct lh7a40x_udc *dev, u32 csr){	struct lh7a40x_request *req;	struct lh7a40x_ep *ep = &dev->ep[0];	int ret;	DEBUG_EP0("%s: %x\n", __FUNCTION__, csr);	if (list_empty(&ep->queue))		req = 0;	else		req = list_entry(ep->queue.next, struct lh7a40x_request, queue);	if (req) {		if (req->req.length == 0) {			DEBUG_EP0("ZERO LENGTH OUT!\n");			usb_set((EP0_CLR_OUT | EP0_DATA_END), USB_EP0_CSR);			dev->ep0state = WAIT_FOR_SETUP;			return;		}		ret = read_fifo_ep0(ep, req);		if (ret) {			/* Done! */			DEBUG_EP0("%s: finished, waiting for status\n",				  __FUNCTION__);			usb_set((EP0_CLR_OUT | EP0_DATA_END), USB_EP0_CSR);			dev->ep0state = WAIT_FOR_SETUP;		} else {			/* Not done yet.. */			DEBUG_EP0("%s: not finished\n", __FUNCTION__);			usb_set(EP0_CLR_OUT, USB_EP0_CSR);		}	} else {		DEBUG_EP0("NO REQ??!\n");	}}/* * DATA_STATE_XMIT */static int lh7a40x_ep0_in(struct lh7a40x_udc *dev, u32 csr){	struct lh7a40x_request *req;	struct lh7a40x_ep *ep = &dev->ep[0];	int ret, need_zlp = 0;	DEBUG_EP0("%s: %x\n", __FUNCTION__, csr);	if (list_empty(&ep->queue))		req = 0;	else		req = list_entry(ep->queue.next, struct lh7a40x_request, queue);	if (!req) {		DEBUG_EP0("%s: NULL REQ\n", __FUNCTION__);		return 0;	}	if (req->req.length == 0) {		usb_set((EP0_IN_PKT_RDY | EP0_DATA_END), USB_EP0_CSR);		dev->ep0state = WAIT_FOR_SETUP;		return 1;	}	if (req->req.length - req->req.actual == EP0_PACKETSIZE) {		/* Next write will end with the packet size, */		/* so we need Zero-length-packet */		need_zlp = 1;	}	ret = write_fifo_ep0(ep, req);	if (ret == 1 && !need_zlp) {		/* Last packet */		DEBUG_EP0("%s: finished, waiting for status\n", __FUNCTION__);		usb_set((EP0_IN_PKT_RDY | EP0_DATA_END), USB_EP0_CSR);		dev->ep0state = WAIT_FOR_SETUP;	} else {		DEBUG_EP0("%s: not finished\n", __FUNCTION__);		usb_set(EP0_IN_PKT_RDY, USB_EP0_CSR);	}	if (need_zlp) {		DEBUG_EP0("%s: Need ZLP!\n", __FUNCTION__);		usb_set(EP0_IN_PKT_RDY, USB_EP0_CSR);		dev->ep0state = DATA_STATE_NEED_ZLP;	}

⌨️ 快捷键说明

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