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

📄 jz4740_udc.c

📁 linux下面gadget设备驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
	    (!_req || !_req->complete || !_req->buf	     || !list_empty(&req->queue))) {		DEBUG("%s, bad params\n", __FUNCTION__);		return -EINVAL;	}	ep = container_of(_ep, struct jz4740_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);			jz4740_ep0_kick(dev, ep);			req = 0;		} else if (use_dma) {			/* DMA */			kick_dma(ep, req);		}		/* PIO */		else if (ep_is_in(ep)) {			/* EP1 & EP2 */			usb_set_index(ep_index(ep));			csr = usb_readb(ep->csr);			pio_irq_enable(ep);			if (!(csr & USB_INCSR_FFNOTEMPT)) {				if (write_fifo(ep, req) == 1)					req = 0;			}		} else {			/* EP1 */			usb_set_index(ep_index(ep));			csr = usb_readb(ep->csr);			pio_irq_enable(ep);			if (csr & USB_OUTCSR_OUTPKTRDY) {				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 jz4740_dequeue(struct usb_ep *_ep, struct usb_request *_req){	struct jz4740_ep *ep;	struct jz4740_request *req;	unsigned long flags;	DEBUG("%s, %p\n", __FUNCTION__, _ep);	ep = container_of(_ep, struct jz4740_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 jz4740_set_halt(struct usb_ep *_ep, int value){	struct jz4740_ep *ep;	unsigned long flags;	ep = container_of(_ep, struct jz4740_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_setb(USB_REG_CSR0, USB_CSR0_SENDSTALL);	} else if (ep_is_in(ep)) {		u32 csr = usb_readb(ep->csr);		if (value && ((csr & USB_INCSR_FFNOTEMPT)			      || !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’t collected.			 */			spin_unlock_irqrestore(&ep->dev->lock, flags);			DEBUG			    ("Attempt to halt IN endpoint failed (returning -EAGAIN) %d %d\n",			     (csr & USB_INCSR_FFNOTEMPT),			     !list_empty(&ep->queue));			return -EAGAIN;		}		flush(ep);		if (value) {			usb_setb(ep->csr, USB_INCSR_SENDSTALL);		}		else {			usb_clearb(ep->csr, USB_INCSR_SENDSTALL);			usb_setb(ep->csr, USB_INCSR_CDT);		}	} else {		flush(ep);		if (value) {			usb_setb(ep->csr, USB_OUTCSR_SENDSTALL);		}		else {			usb_clearb(ep->csr, USB_OUTCSR_SENDSTALL);			usb_setb(ep->csr, USB_OUTCSR_CDT);		}	}	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 jz4740_fifo_status(struct usb_ep *_ep){	u32 csr;	int count = 0;	struct jz4740_ep *ep;	ep = container_of(_ep, struct jz4740_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_readb(ep->csr);	if (ep->dev->gadget.speed != USB_SPEED_UNKNOWN ||	    csr & 0x1) {		count = usb_readw(USB_REG_OUTCOUNT);	}	return count;}/** Flush EP FIFO *  NOTE: Sets INDEX register to EP */static void jz4740_fifo_flush(struct usb_ep *_ep){	struct jz4740_ep *ep;	ep = container_of(_ep, struct jz4740_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 jz4740_ep *ep, struct jz4740_request *req){	u32 max;	unsigned count;	int is_last;	max = ep_maxpacket(ep);	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 jz4740_fifo_read(struct jz4740_ep *ep,				       unsigned char *cp, int max){	int bytes;	int count = usb_readw(USB_REG_OUTCOUNT);	volatile u8 *fifo = (volatile u8 *)ep->fifo;	if (count > max)		count = max;	bytes = count;	while (count--)		*cp++ = *fifo;	return bytes;}static __inline__ void jz4740_fifo_write(struct jz4740_ep *ep,					 unsigned char *cp, int count){	volatile u8 *fifo = (volatile u8 *)ep->fifo;	DEBUG_EP0("fifo_write: %d %d\n", ep_index(ep), count);	while (count--)		*fifo = *cp++;}static int read_fifo_ep0(struct jz4740_ep *ep, struct jz4740_request *req){	u32 csr;	u8 *buf;	unsigned bufferspace, count, is_short;	volatile u8 *fifo = (volatile u8 *)ep->fifo;	DEBUG_EP0("%s\n", __FUNCTION__);	csr = usb_readb(USB_REG_CSR0);	if (!(csr & USB_CSR0_OUTPKTRDY))		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 & USB_CSR0_OUTPKTRDY)) {		count = usb_readw(USB_REG_OUTCOUNT);		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 jz4740_udc *dev, unsigned char address){	DEBUG_EP0("%s: %d\n", __FUNCTION__, address);	dev->usb_address = address;	usb_writeb(USB_REG_FADDR, address);}/* * DATA_STATE_RECV (USB_CSR0_OUTPKTRDY) *      - if error *              set USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND | USB_CSR0_SENDSTALL bits *      - else *              set USB_CSR0_SVDOUTPKTRDY bit 				if last set USB_CSR0_DATAEND bit */static void jz4740_ep0_out(struct jz4740_udc *dev, u32 csr){	struct jz4740_request *req;	struct jz4740_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 jz4740_request, queue);	if (req) {		if (req->req.length == 0) {			DEBUG_EP0("ZERO LENGTH OUT!\n");/*			usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); */			usb_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY));			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_setb(USB_REG_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND));			dev->ep0state = WAIT_FOR_SETUP;		} else {			/* Not done yet.. */			DEBUG_EP0("%s: not finished\n", __FUNCTION__);			usb_setb(USB_REG_CSR0, USB_CSR0_SVDOUTPKTRDY);		}	} else {		DEBUG_EP0("NO REQ??!\n");	}}/* * DATA_STATE_XMIT */static int jz4740_ep0_in(struct jz4740_udc *dev, u32 csr){	struct jz4740_request *req;	struct jz4740_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 jz4740_request, queue);	if (!req) {		DEBUG_EP0("%s: NULL REQ\n", __FUNCTION__);		return 0;	}	if (req->req.length == 0) {		usb_setb(USB_REG_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND));		dev->ep0state = WAIT_FOR_SETUP;		return 1;	}	if (req->req.length - req->req.actual == EP0_MAXPACKETSIZE) {		/* 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_setb(USB_REG_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND));		dev->ep0state = WAIT_FOR_SETUP;	} else {		DEBUG_EP0("%s: not finished\n", __FUNCTION__);		usb_setb(USB_REG_CSR0, USB_CSR0_INPKTRDY);	}	if (need_zlp) {		DEBUG_EP0("%s: Need ZLP!\n", __FUNCTION__);		usb_setb(USB_REG_CSR0, USB_CSR0_INPKTRDY);		dev->ep0state = DATA_STATE_NEED_ZLP;	}	return 1;}#if 0static int jz4740_handle_get_status(struct jz4740_udc *dev,				    struct usb_ctrlrequest *ctrl){	struct jz4740_ep *ep0 = &dev->ep[0];	struct jz4740_ep *qep;	int reqtype = (ctrl->bRequestType & USB_RECIP_MASK);	u16 val = 0;	if (reqtype == USB_RECIP_INTERFACE) {		/* This is not supported.		 * And according to the USB spec, this one does nothing..		 * Just return 0		 */		DEBUG_SETUP("GET_STATUS: USB_RECIP_INTERFACE\n");	} else if (reqtype == USB_RECIP_DEVICE) {		DEBUG_SETUP("GET_STATUS: USB_RECIP_DEVICE\n");		val |= (1 << 0);	/* Self powered */		/*val |= (1<<1); *//* Remote wakeup */	} else if (reqtype == USB_RECIP_ENDPOINT) {		int ep_num = (ctrl->wIndex & ~USB_DIR_IN);		DEBUG_SETUP			("GET_STATUS: USB_RECIP_ENDPOINT (%d), ctrl->wLength = %d\n",			 ep_num, ctrl->wLength);		if (ctrl->wLength > 2 || ep_num > 3)			return -EOPNOTSUPP;		qep = &dev->ep[ep_num];		if (ep_is_in(qep) != ((ctrl->wIndex & USB_DIR_IN) ? 1 : 0)		    && ep_index(qep) != 0) {			return -EOPNOTSUPP;		}		usb_set_index(ep_index(qep));		/* Return status on next IN token */		switch (qep->ep_type) {		case ep_control:			val =			    (usb_readb(qep->csr) & USB_CSR0_SENDSTALL) ==			    USB_CSR0_SENDSTALL;			break;		case ep_bulk_in:		case ep_interrupt:			val =			    (usb_readb(qep->csr) & USB_INCSR_SENDSTALL) ==			    USB_INCSR_SENDSTALL;			break;		case ep_bulk_out:			val =			    (usb_readb(qep->csr) & USB_OUTCSR_SENDSTALL) ==			    USB_OUTCSR_SENDSTALL;			break;		}		/* Back to EP0 index */		usb_set_index(0);		DEBUG_SETUP("GET_STATUS, ep: %d (%x), val = %d\n", ep_num,			    ctrl->wIndex, val);	} else {		DEBUG_SETUP("Unknown REQ TYPE: %d\n", reqtype);		return -EOPNOTSUPP;	}	/* Clear "out packet ready" */	usb_setb(USB_REG_CSR0, USB_CSR0_SVDOUTPKTRDY);	/* Put status to FIFO */	jz4740_fifo_write(ep0, (u8 *) & val, sizeof(val));	/* Issue "In packet ready" */	usb_setb(USB_REG_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND));	return 0;}#endif/* * WAIT_FOR_SETUP (OUTPKTRDY) *      - read data packet from EP0 FIFO *      - decode command *      - if error *              set USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND | USB_CSR0_SENDSTALL bits *      - else *              set USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND bits */static void jz4740_ep0_setup(struct jz4740_udc *dev, u32 csr){	struct jz4740_ep *ep = &dev->ep[0];	struct usb_ctrlrequest ctrl;	int i;	DEBUG_SETUP("%s: %x\n", __FUNCTION__, csr);	/* Nuke all previous transfers */	nuke(ep, -EPROTO);	/* read control req from fifo (8 bytes) */	jz4740_fifo_read(ep, (unsigned char *)&ctrl, 8);

⌨️ 快捷键说明

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