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

📄 superh_udc.c

📁 LINUX2.4.18内核下的usb GADGET驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
		unsigned	count;		int		is_last, is_short;		count = write_packet(ep->fifo_reg, req, max);		/* 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->ep.maxpacket);			/* FIXME ep.maxpacket should be the current size,			 * modified (for periodic endpoints) when the			 * ep is enabled.  do that, re-init as needed,			 * and change maxpacket refs accordingly.			 */		}		DBG(DBG_VERY_NOISY, "wrote %s %d bytes%s%s %d left %p\n",			ep->ep.name, count,			is_last ? "/L" : "", is_short ? "/S" : "",			req->req.length - req->req.actual, req);		/* let loose that packet. maybe try writing another one,		 * double buffering might work.		 */		or_b(ep->packet_enable_mask, USBTRG);		/* requests complete when all IN data is in the FIFO */		if (is_last) {			done (ep, req, 0);			if (list_empty(&ep->queue) || unlikely(ep->dma >= 0)) {				pio_irq_disable (ep);			}#ifdef USE_DMA			/* TODO */			if (unlikely(ep->dma >= 0) && !list_empty(&ep->queue)) {				DMSG("%s pio2dma\n", ep->ep.name);				req = list_entry(ep->queue.next,						struct superh_request, queue);				kick_dma(ep,req);				return 0;			}#endif			return 1;		}		/* Only loop if on EP2 as it is double buffered */	} while (ep->bEndpointAddress == (2|USB_DIR_IN)		 && ctrl_inb(USBIFR0) & EP2_EMPTY);	return 0;}/* * read_ep0_fifo - unload packets from ep0 control-out fifo.  caller * should have made sure there's at least one packet ready. * * returns true if the request completed because of short packet or the * request buffer having filled (and maybe overran till end-of-packet). */static intread_ep0_fifo(struct superh_ep *ep, struct superh_request *req){	u8		*buf;	unsigned	bufferspace, count;	DBG(DBG_VERY_NOISY, "read_ep0_fifo\n");	if (!ep) {		DMSG("read_ep0_fifo invalid ep\n");		return -EINVAL;	}	if (!req) {		DMSG("read_ep0_fifo invalid req\n");		return -EINVAL;	}	if (ep->desc != 0) {		DMSG("read_ep0_fifo from invalid EP (%s)\n", ep->ep.name);		return -EINVAL;	}		/* make sure there's a packet in the FIFO.	 */	if (likely ((ctrl_inb(USBIFR0) & EP0o_TS) == 0)) {		buf = req->req.buf + req->req.actual;		bufferspace = req->req.length - req->req.actual;			/* read all bytes from this packet */		count = ctrl_inb(USBEPSZ0O);		req->req.actual += min (count, bufferspace);		DBG(DBG_VERY_NOISY, "read %s %d bytes req %p %d/%d\n",		    ep->ep.name, count,		    req, req->req.actual, req->req.length);		while (likely (count-- != 0)) {			u8	byte = ctrl_inb(USBEPDR0O);						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)					DMSG("%s overflow %d\n",					     ep->ep.name, count);				req->req.status = -EOVERFLOW;			} else {				*buf++ = byte;				bufferspace--;			}		}				/* Send ACK */		or_b(EP0o_RDFN, USBTRG);		/* completion */		if (req->req.actual >= req->req.length) {			done (ep, req, 0);			ep0_idle(ep->dev);			return 1;		}	}	return 0;}/* * read_fifo -  unload packet(s) from the fifo we use for usb OUT * transfers and put them into the request.  caller should have made * sure there's at least one packet ready. * * returns true if the request completed because of short packet or the * request buffer having filled (and maybe overran till end-of-packet). */static intread_fifo (struct superh_ep *ep, struct superh_request *req){	DBG(DBG_VERY_NOISY, "read_fifo\n");	if ((ep->bEndpointAddress & 0x0f) != 1) {		DMSG("read_fifo from invalid EP (%s)\n", ep->ep.name);		return -EINVAL;	}	for (;;) {		u8		*buf;		unsigned	bufferspace, count, is_short;		/* make sure there's a packet in the FIFO.		 */		if (unlikely ((ctrl_inb(USBIFR0) & EP1_FULL) == 0))			break;		buf = req->req.buf + req->req.actual;		bufferspace = req->req.length - req->req.actual;		/* read all bytes from this packet */		count = ctrl_inb(USBEPSZ1);		req->req.actual += min (count, bufferspace);		is_short = (count < ep->desc->wMaxPacketSize);		DBG(DBG_VERY_NOISY, "read %s %d bytes%s req %p %d/%d\n",			ep->ep.name, count,			is_short ? "/S" : "",			req, req->req.actual, req->req.length);		while (likely (count-- != 0)) {			u8	byte = ctrl_inb(USBEPDR1);			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)					DMSG("%s overflow %d\n",						ep->ep.name, count);				req->req.status = -EOVERFLOW;			} else {				*buf++ = byte;				bufferspace--;			}		}		or_b(EP1_RDFN, USBTRG);		/* There could now be another packet because of dual buffer */		/* 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;}/*--------------------------------------------------------------------------*/ /* Interrupt Handler(s) *//* * superh_udc_irq_f0 - high priority interrupt handler * this deals with data to & from the bulk pipes */static void superh_udc_irq_f0(int irq, void *_dev, struct pt_regs *regs){	unsigned char             f0_status;	struct superh_udc         *dev = (struct superh_udc*) _dev;	struct superh_request     *req;	struct superh_ep          *ep;	DBG(DBG_NOISY, "superh_udc_irq_f0 %p\n", dev);	atomic_inc(&dev->in_interrupt);	dev->stats.irqs++;	dev->stats.irq0s++;	f0_status = ctrl_inb(USBIFR0);	/* Acknowledge interrupts */	ctrl_outb(~(f0_status & F0_HIGH), USBIFR0);	if (f0_status & EP1_FULL) {		DBG(DBG_NOISY, "superh_udc_irq_f0 %p: EP1 FULL\n", dev);		ep = &dev->ep[1];				if (likely (!list_empty(&ep->queue)))			req = list_entry(ep->queue.next,					 struct superh_request, queue);		else			req = 0;		if (req)			read_fifo(ep, req);		else			pio_irq_disable(ep);	}		if ( f0_status & (EP2_TR | EP2_EMPTY) ) {		DBG(DBG_NOISY, "superh_udc_irq_f0 %p: EP2 TR | EP2_EMPTY\n", dev);		ep = &dev->ep[2];		if (likely (!list_empty(&ep->queue)))			req = list_entry(ep->queue.next,					struct superh_request, queue);		else			req = 0;		if (req) {			if ((f0_status & EP2_TR) && (f0_status & EP2_EMPTY))				write_fifo(ep, req);			else				and_b(~EP2_EMPTY, USBIER0);						}		else {			pio_irq_disable(ep);		}	}	atomic_dec(&dev->in_interrupt);}/** * superh_udc_irq_f1 - low priority interrupt handler * */static void superh_udc_irq_f1(int irq, void *_dev, struct pt_regs *regs){	unsigned char       f0_status;	unsigned char       f1_status;	struct superh_udc   *dev = (struct superh_udc*) _dev;	atomic_inc(&dev->in_interrupt);;	dev->stats.irqs++;	dev->stats.irq1s++;	f0_status = ctrl_inb(USBIFR0);	f1_status = ctrl_inb(USBIFR1);	/* Acknowledge interrupts */	ctrl_outb(~(f0_status & F0_LOW), USBIFR0);	ctrl_outb(~(f1_status & F1_LOW), USBIFR1);	/* VBUSF indicates the USB being connected/disconnected */	if (f1_status & VBUSF) {		DBG(DBG_VERY_NOISY, "superh_udc_irq_f1[%lx] VBUSF\n", dev->stats.irqs);		if (!is_usb_connected) {			/* report disconnect just once */			if (dev->gadget.speed != USB_SPEED_UNKNOWN) {				DMSG("disconnect %s\n",					dev->driver ? dev->driver->driver.name : 0);				stop_activity(dev, dev->driver);			}		}		else if (dev->gadget.speed == USB_SPEED_UNKNOWN) {			DMSG("connect\n");			dev->setup_countdown = DEFAULT_SETUP_COUNT;		}	}	/* Bus Reset */	if (f0_status & BRST) {		int i;		DBG(DBG_VERBOSE, "superh_udc_irq_f1[%lx]: BRST bus reset\n", dev->stats.irqs);		/* kill any outstanding requests  */		for (i = 0; i < 4; i++) {			struct superh_ep *ep = &dev->ep[i];			nuke(ep, -ESHUTDOWN);			ep->halted = 0;			ep->stopped = 0;		}		/* reset fifo's and stall's */		ctrl_outb( EP3_CLEAR | EP1_CLEAR | EP2_CLEAR | EP0o_CLEAR | EP0i_CLEAR, USBFCLR );		ctrl_outb( 0, USBEPSTL );		DMSG("gadget driver '%s', address zero\n", dev->driver->driver.name);		if (dev->gadget.speed == USB_SPEED_UNKNOWN)			init_udc_timer(dev);		dev->gadget.speed = USB_SPEED_FULL;		memset(&dev->stats, 0, sizeof dev->stats);		if (dev->setup_countdown < 0)			dev->setup_countdown = RESET_SETUP_COUNT;		dev->reset_time = jiffies;		dev->fake_config = 0;		ep0_idle(dev);	}        /* EPOi Transmit Complete - data to host on EP0 ACKed	 * EP0i Transfer Request - no data in FIFO to send on EP0         * either way we send next data if there is any and the FIFO is not busy	 * it will interrupt again if we later if we don't send anything.	 */	if ((f0_status & EP0i_TR || f0_status & EP0i_TS)	    && (ctrl_inb(USBDASTS) & EP0i_DE) == 0) {		struct superh_ep	*ep = &dev->ep[0];		struct superh_request	*req;		DBG(DBG_VERY_NOISY, "superh_udc_irq_f1[%lx]: ep0i TR\n", dev->stats.irqs);		if (!list_empty(&ep->queue)) {			req = list_entry(ep->queue.next, struct superh_request, queue);			write_ep0_fifo(ep, req);		}		or_b(EP0i_PKTE, USBTRG);	}	/* Setup Command Receive Complete */	if (f0_status & SETUP_TS) {		DBG(DBG_NOISY, "superh_udc_irq_f1[%lx]: SETUP TS\n", dev->stats.irqs);		or_b( EP0o_CLEAR | EP0i_CLEAR, USBFCLR);		handle_ep0_setup(dev);	}	/* EPOo Receive Complete - EP0 has received data from host */	if (f0_status & EP0o_TS) {		struct superh_request     *req;		struct superh_ep          *ep;		DBG(DBG_VERY_NOISY, "superh_int_hndlr_f1[%lx]: ep0o TS\n", dev->stats.irqs);		ep = &dev->ep[0];		if (likely (!list_empty(&ep->queue)))			req = list_entry(ep->queue.next,					 struct superh_request, queue);		else			req = 0;		if (req)			read_ep0_fifo(ep, req);	}	/* EP3 Transmit Request & Transmit Complete */	if ( f1_status & (EP3_TR | EP3_TS) ) {		struct superh_request     *req;		struct superh_ep          *ep;		DBG(DBG_VERY_NOISY, "superh_udc_irq_f1[%lx]: EP3 TR | EP3_TS (%x)\n", dev->stats.irqs, f1_status);		ep = &dev->ep[3];		if (likely (!list_empty(&ep->queue)))			req = list_entry(ep->queue.next,					struct superh_request, queue);		else			req = 0;		if (req) {			if ((f1_status & EP3_TR) && (ctrl_inb(USBDASTS) & EP3_DE) == 0)				write_fifo(ep, req);					}		else {			pio_irq_disable(ep);		}	}	atomic_dec(&dev->in_interrupt);;}/*--------------------------------------------------------------------------*/ /* * endpoint enable/disable * * we need to verify the descriptors used to enable endpoints.  since superh * endpoint configurations are fixed, and are pretty much always enabled, * there's not a lot to manage here. * */static int superh_ep_enable (struct usb_ep *_ep,		const struct usb_endpoint_descriptor *desc){	struct superh_ep        *ep;	struct superh_udc       *dev;	DBG(DBG_NOISY, "superh_ep_enable\n");	ep = container_of (_ep, struct superh_ep, ep);	if (!_ep || !desc || ep->desc || _ep->name == ep0name			|| desc->bDescriptorType != USB_DT_ENDPOINT			|| ep->bEndpointAddress != desc->bEndpointAddress			|| ep->ep.maxpacket < desc->wMaxPacketSize) {		DMSG("%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) {		DMSG("%s, %s type mismatch\n", __FUNCTION__, _ep->name);		return -EINVAL;	}#if 0	/* hardware _could_ do smaller, but driver doesn't */	if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK				&& desc->wMaxPacketSize != BULK_FIFO_SIZE)			|| !desc->wMaxPacketSize) {		DMSG("%s, bad %s maxpacket\n", __FUNCTION__, _ep->name);		return -ERANGE;	}#endif	dev = ep->dev;	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) {		DMSG("%s, bogus device state\n", __FUNCTION__);		return -ESHUTDOWN;

⌨️ 快捷键说明

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