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

📄 jz4740_udc.c

📁 linux下面gadget设备驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
	u32 physaddr = virt_to_phys((void *)req->req.buf);	max = le16_to_cpu(ep->desc->wMaxPacketSize);	if (use_dma) {		u32 dma_count;		/* DMA interrupt generated due to the last packet loaded into the FIFO */		dma_count = usb_readl(ep->reg_addr) - physaddr;		req->req.actual += dma_count;		if (dma_count % max) {			/* If the last packet is less than MAXP, set INPKTRDY manually */			usb_setb(ep->csr, USB_INCSR_INPKTRDY);		}		done(ep, req, 0);		if (list_empty(&ep->queue)) {			pio_irq_disable(ep);			return 1;		}		else {			/* advance the request queue */			req = list_entry(ep->queue.next, struct jz4740_request, queue);			kick_dma(ep, req);			return 0;		}	}	/*	 * PIO mode handling starts here ...	 */	csr = usb_readb(ep->csr);	if (!(csr & USB_INCSR_FFNOTEMPT)) {		unsigned count;		int is_last, is_short;		count = write_packet(ep, req, max);		usb_setb(ep->csr, USB_INCSR_INPKTRDY);		/* last packet is usually short (or a zlp) */		if (unlikely(count != max))			is_last = is_short = 1;		else {			if (likely(req->req.length != req->req.actual)			    || req->req.zero)				is_last = 0;			else				is_last = 1;			/* interrupt/iso maxpacket may not fill the fifo */			is_short = unlikely(max < ep_maxpacket(ep));		}		DEBUG("%s: wrote %s %d bytes%s%s %d left %p\n", __FUNCTION__,		      ep->ep.name, count,		      is_last ? "/L" : "", is_short ? "/S" : "",		      req->req.length - req->req.actual, req);		/* requests complete when all IN data is in the FIFO */		if (is_last) {			done(ep, req, 0);			if (list_empty(&ep->queue)) {				pio_irq_disable(ep);			}			return 1;		}	} else {		DEBUG("Hmm.. %d ep FIFO is not empty!\n", ep_index(ep));	}	return 0;}/** Read to request from FIFO (max read == bytes in fifo) *  Return:  0 = still running, 1 = completed, negative = errno *  NOTE: INDEX register must be set for EP */static int read_fifo(struct jz4740_ep *ep, struct jz4740_request *req){	u32 csr;	unsigned count, is_short;	u32 physaddr = virt_to_phys((void *)req->req.buf);	if (use_dma) {		u32 dma_count;		/* DMA interrupt generated due to a packet less than MAXP loaded into the FIFO */		dma_count = usb_readl(ep->reg_addr) - physaddr;		req->req.actual += dma_count;		/* Disable interrupt and DMA */		pio_irq_disable(ep);		usb_writel(USB_REG_CNTL2, 0);		/* Read all bytes from this packet */		count = usb_readw(USB_REG_OUTCOUNT);		count = read_packet(ep, req, count);		if (count) {			/* If the last packet is greater than zero, clear OUTPKTRDY manually */			usb_clearb(ep->csr, USB_OUTCSR_OUTPKTRDY);		}		done(ep, req, 0);		if (!list_empty(&ep->queue)) {			/* advance the request queue */			req = list_entry(ep->queue.next, struct jz4740_request, queue);			kick_dma(ep, req);		}		return 1;	}	/*	 * PIO mode handling starts here ...	 */	/* make sure there's a packet in the FIFO. */	csr = usb_readb(ep->csr);	if (!(csr & USB_OUTCSR_OUTPKTRDY)) {		DEBUG("%s: Packet NOT ready!\n", __FUNCTION__);		return -EINVAL;	}	/* read all bytes from this packet */	count = usb_readw(USB_REG_OUTCOUNT);	is_short = (count < ep->ep.maxpacket);	count = read_packet(ep, req, count);	DEBUG("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);	/* Clear OutPktRdy */	usb_clearb(ep->csr, USB_OUTCSR_OUTPKTRDY);	/* completion */	if (is_short || req->req.actual == req->req.length) {		done(ep, req, 0);		if (list_empty(&ep->queue))			pio_irq_disable(ep);		return 1;	}	/* finished that packet.  the next one may be waiting... */	return 0;}/* *	done - retire a request; caller blocked irqs *  INDEX register is preserved to keep same */static void done(struct jz4740_ep *ep, struct jz4740_request *req, int status){	unsigned int stopped = ep->stopped;	u32 index;	DEBUG("%s, %p\n", __FUNCTION__, ep);	list_del_init(&req->queue);	if (likely(req->req.status == -EINPROGRESS))		req->req.status = status;	else		status = req->req.status;	if (status && status != -ESHUTDOWN)		DEBUG("complete %s req %p stat %d len %u/%u\n",		      ep->ep.name, &req->req, status,		      req->req.actual, req->req.length);	/* don't modify queue heads during completion callback */	ep->stopped = 1;	/* Read current index (completion may modify it) */	index = usb_readb(USB_REG_INDEX);	spin_unlock(&ep->dev->lock);	req->req.complete(&ep->ep, &req->req);	spin_lock(&ep->dev->lock);	/* Restore index */	usb_set_index(index);	ep->stopped = stopped;}/** Enable EP interrupt */static void pio_irq_enable(struct jz4740_ep *ep){	DEBUG("%s: EP%d %s\n", __FUNCTION__, ep_index(ep), ep_is_in(ep) ? "IN": "OUT");	if (ep_is_in(ep)) {		switch (ep_index(ep)) {		case 1:			usb_setw(USB_REG_INTRINE, USB_INTR_INEP1);			break;		case 2:			usb_setw(USB_REG_INTRINE, USB_INTR_INEP2);			break;		default:			DEBUG("Unknown endpoint: %d\n", ep_index(ep));			break;		}	}	else {		switch (ep_index(ep)) {		case 1:			usb_setw(USB_REG_INTROUTE, USB_INTR_OUTEP1);			break;		default:			DEBUG("Unknown endpoint: %d\n", ep_index(ep));			break;		}	}}/** Disable EP interrupt */static void pio_irq_disable(struct jz4740_ep *ep){	DEBUG("%s: EP%d %s\n", __FUNCTION__, ep_index(ep), ep_is_in(ep) ? "IN": "OUT");	if (ep_is_in(ep)) {		switch (ep_index(ep)) {		case 1:			usb_clearw(USB_REG_INTRINE, USB_INTR_INEP1);			break;		case 2:			usb_clearw(USB_REG_INTRINE, USB_INTR_INEP2);			break;		default:			DEBUG("Unknown endpoint: %d\n", ep_index(ep));			break;		}	}	else {		switch (ep_index(ep)) {		case 1:			usb_clearw(USB_REG_INTROUTE, USB_INTR_OUTEP1);			break;		default:			DEBUG("Unknown endpoint: %d\n", ep_index(ep));			break;		}	}}/* * 	nuke - dequeue ALL requests */static void nuke(struct jz4740_ep *ep, int status){	struct jz4740_request *req;	DEBUG("%s, %p\n", __FUNCTION__, ep);	/* Flush FIFO */	flush(ep);	/* called with irqs blocked */	while (!list_empty(&ep->queue)) {		req = list_entry(ep->queue.next, struct jz4740_request, queue);		done(ep, req, status);	}	/* Disable IRQ if EP is enabled (has descriptor) */	if (ep->desc)		pio_irq_disable(ep);}/** Flush EP FIFO * NOTE: INDEX register must be set before this call */static void flush(struct jz4740_ep *ep){	DEBUG("%s, %p\n", __FUNCTION__, ep);	switch (ep->ep_type) {	case ep_control:		break;	case ep_bulk_in:	case ep_interrupt:		usb_setb(ep->csr, USB_INCSR_FF);		break;	case ep_bulk_out:		usb_setb(ep->csr, USB_OUTCSR_FF);		break;	}}/** * jz4740_in_epn - handle IN interrupt */static void jz4740_in_epn(struct jz4740_udc *dev, u32 ep_idx, u32 intr){	u32 csr;	struct jz4740_ep *ep = &dev->ep[ep_idx + 1];	struct jz4740_request *req;	usb_set_index(ep_index(ep));	csr = usb_readb(ep->csr);	DEBUG("%s: %d, csr %x\n", __FUNCTION__, ep_idx, csr);	if (csr & USB_INCSR_SENTSTALL) {		DEBUG("USB_INCSR_SENTSTALL\n");		usb_clearb(ep->csr, USB_INCSR_SENTSTALL);		return;	}	if (!ep->desc) {		DEBUG("%s: NO EP DESC\n", __FUNCTION__);		return;	}	if (list_empty(&ep->queue))		req = 0;	else		req = list_entry(ep->queue.next, struct jz4740_request, queue);	DEBUG("req: %p\n", req);	if (!req)		return;	write_fifo(ep, req);}/* * Bulk OUT (recv) */static void jz4740_out_epn(struct jz4740_udc *dev, u32 ep_idx, u32 intr){	struct jz4740_ep *ep = &dev->ep[ep_idx];	struct jz4740_request *req;	DEBUG("%s: %d\n", __FUNCTION__, ep_idx);	usb_set_index(ep_index(ep));	if (ep->desc) {		u32 csr;		if (use_dma) {			/* DMA starts here ... */			if (list_empty(&ep->queue))				req = 0;			else				req = list_entry(ep->queue.next, struct jz4740_request, queue);			if (req)				read_fifo(ep, req);			return;		}		/*		 * PIO mode starts here ...		 */		while ((csr = usb_readb(ep->csr)) & 		       (USB_OUTCSR_OUTPKTRDY | USB_OUTCSR_SENTSTALL)) {			DEBUG("%s: %x\n", __FUNCTION__, csr);			if (csr & USB_OUTCSR_SENTSTALL) {				DEBUG("%s: stall sent, flush fifo\n",				      __FUNCTION__);				/* usb_set(USB_OUT_CSR1_FIFO_FLUSH, ep->csr1); */				flush(ep);			} else if (csr & USB_OUTCSR_OUTPKTRDY) {				if (list_empty(&ep->queue))					req = 0;				else					req =						list_entry(ep->queue.next,							   struct jz4740_request,							   queue);				if (!req) {					DEBUG("%s: NULL REQ %d\n",					      __FUNCTION__, ep_idx);					break;				} else {					read_fifo(ep, req);				}			}		}	} else {		/* Throw packet away.. */		printk("%s: ep %p ep_indx %d No descriptor?!?\n", __FUNCTION__, ep, ep_idx);		flush(ep);	}}static int jz4740_ep_enable(struct usb_ep *_ep,			    const struct usb_endpoint_descriptor *desc){	struct jz4740_ep *ep;	struct jz4740_udc *dev;	unsigned long flags;	u32 max, csrh = 0;	ep = container_of(_ep, struct jz4740_ep, ep);	if (!_ep || !desc || ep->desc || _ep->name == ep0name	    || desc->bDescriptorType != USB_DT_ENDPOINT	    || ep->bEndpointAddress != desc->bEndpointAddress) {		DEBUG("%s, bad ep or descriptor\n", __FUNCTION__);		return -EINVAL;	}	/* xfer types must match, except that interrupt ~= bulk */	if (ep->bmAttributes != desc->bmAttributes	    && ep->bmAttributes != USB_ENDPOINT_XFER_BULK	    && desc->bmAttributes != USB_ENDPOINT_XFER_INT) {		DEBUG("%s, %s type mismatch\n", __FUNCTION__, _ep->name);		return -EINVAL;	}	dev = ep->dev;	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {		DEBUG("%s, bogus device state\n", __FUNCTION__);		return -ESHUTDOWN;	}	max = le16_to_cpu(desc->wMaxPacketSize);	/* Configure the endpoint */	usb_set_index(desc->bEndpointAddress & 0x0F);	if (ep_is_in(ep)) {		usb_writew(USB_REG_INMAXP, max);		switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {		case USB_ENDPOINT_XFER_BULK:		case USB_ENDPOINT_XFER_INT:			csrh &= ~USB_INCSRH_ISO;			break;		case USB_ENDPOINT_XFER_ISOC:			csrh |= USB_INCSRH_ISO;			break;		}		usb_writeb(USB_REG_INCSRH, csrh);	}	else {		usb_writew(USB_REG_OUTMAXP, max);		switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {		case USB_ENDPOINT_XFER_BULK:			 csrh &= ~USB_OUTCSRH_ISO;			break;		case USB_ENDPOINT_XFER_INT:			csrh &= ~USB_OUTCSRH_ISO;			csrh |= USB_OUTCSRH_DNYT;			break;		case USB_ENDPOINT_XFER_ISOC:			csrh |= USB_OUTCSRH_ISO;			break;		}		usb_writeb(USB_REG_OUTCSRH, csrh);	}	spin_lock_irqsave(&ep->dev->lock, flags);	ep->stopped = 0;	ep->desc = desc;	ep->pio_irqs = 0;	ep->ep.maxpacket = max;	spin_unlock_irqrestore(&ep->dev->lock, flags);	/* Reset halt state (does flush) */	jz4740_set_halt(_ep, 0);	DEBUG("%s: enabled %s\n", __FUNCTION__, _ep->name);	return 0;}/** Disable EP *  NOTE: Sets INDEX register */static int jz4740_ep_disable(struct usb_ep *_ep){	struct jz4740_ep *ep;	unsigned long flags;	DEBUG("%s, %p\n", __FUNCTION__, _ep);	ep = container_of(_ep, struct jz4740_ep, ep);	if (!_ep || !ep->desc) {		DEBUG("%s, %s not enabled\n", __FUNCTION__,		      _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);	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 *jz4740_alloc_request(struct usb_ep *ep, gfp_t gfp_flags){	struct jz4740_request *req;	DEBUG("%s, %p\n", __FUNCTION__, ep);	req = kzalloc(sizeof(*req), gfp_flags);	if (!req)		return 0;	INIT_LIST_HEAD(&req->queue);	return &req->req;}static void jz4740_free_request(struct usb_ep *ep, struct usb_request *_req){	struct jz4740_request *req;	DEBUG("%s, %p\n", __FUNCTION__, ep);	req = container_of(_req, struct jz4740_request, req);	WARN_ON(!list_empty(&req->queue));	kfree(req);}/*--------------------------------------------------------------------*//** Queue one request *  Kickstart transfer if needed *  NOTE: Sets INDEX register */static int jz4740_queue(struct usb_ep *_ep, struct usb_request *_req,			gfp_t gfp_flags){	struct jz4740_request *req;	struct jz4740_ep *ep;	struct jz4740_udc *dev;	unsigned long flags;	DEBUG("%s, %p\n", __FUNCTION__, _ep);	req = container_of(_req, struct jz4740_request, req);	if (unlikely

⌨️ 快捷键说明

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