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

📄 net2280.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	retval = driver->bind (&dev->gadget);	if (retval) {		DEBUG (dev, "bind to driver %s --> %d\n",				driver->driver.name, retval);		dev->driver = 0;		return retval;	}	/* ... then enable host detection and ep0; and we're ready	 * for set_configuration as well as eventual disconnect.	 */	net2280_led_active (dev, 1);	ep0_start (dev);	DEBUG (dev, "%s ready, usbctl %08x stdrsp %08x\n",			driver->driver.name,			readl (&dev->usb->usbctl),			readl (&dev->usb->stdrsp));	/* pci writes may still be posted */	return 0;}EXPORT_SYMBOL (usb_gadget_register_driver);static voidstop_activity (struct net2280 *dev, struct usb_gadget_driver *driver){	int			i;	/* don't disconnect if it's not connected */	if (dev->gadget.speed == USB_SPEED_UNKNOWN)		driver = 0;	/* stop hardware; prevent new request submissions;	 * and kill any outstanding requests.	 */	usb_reset (dev);	for (i = 0; i < 7; i++)		nuke (&dev->ep [i]);	/* report disconnect; the driver is already quiesced */	if (driver) {		spin_unlock (&dev->lock);		driver->disconnect (&dev->gadget);		spin_lock (&dev->lock);	}	usb_reinit (dev);}int usb_gadget_unregister_driver (struct usb_gadget_driver *driver){	struct net2280	*dev = the_controller;	unsigned long	flags;	if (!dev)		return -ENODEV;	if (!driver || driver != dev->driver)		return -EINVAL;	spin_lock_irqsave (&dev->lock, flags);	stop_activity (dev, driver);	spin_unlock_irqrestore (&dev->lock, flags);	driver->unbind (&dev->gadget);	dev->driver = 0;	net2280_led_active (dev, 0);	DEBUG (dev, "unregistered driver '%s'\n", driver->driver.name);	return 0;}EXPORT_SYMBOL (usb_gadget_unregister_driver);/*-------------------------------------------------------------------------*//* handle ep0, ep-e, ep-f with 64 byte packets: packet per irq. * also works for dma-capable endpoints, in pio mode or just * to manually advance the queue after short OUT transfers. */static void handle_ep_small (struct net2280_ep *ep){	struct net2280_request	*req;	u32			t;	/* 0 error, 1 mid-data, 2 done */	int			mode = 1;	if (!list_empty (&ep->queue))		req = list_entry (ep->queue.next,			struct net2280_request, queue);	else		req = 0;	/* ack all, and handle what we care about */	t = readl (&ep->regs->ep_stat);	ep->irqs++;#if 0	VDEBUG (ep->dev, "%s ack ep_stat %08x, req %p\n",			ep->ep.name, t, req ? &req->req : 0);#endif	writel (t & ~(1 << NAK_OUT_PACKETS), &ep->regs->ep_stat);	/* for ep0, monitor token irqs to catch data stage length errors	 * and to synchronize on status.	 *	 * also, to defer reporting of protocol stalls ... here's where	 * data or status first appears, handling stalls here should never	 * cause trouble on the host side..	 *	 * control requests could be slightly faster without token synch for	 * status, but status can jam up that way.	 */	if (unlikely (ep->num == 0)) {		if (ep->is_in) {			/* status; stop NAKing */			if (t & (1 << DATA_OUT_PING_TOKEN_INTERRUPT)) {				if (ep->dev->protocol_stall) {					ep->stopped = 1;					set_halt (ep);				}				if (!req)					allow_status (ep);				mode = 2;			/* reply to extra IN data tokens with a zlp */			} else if (t & (1 << DATA_IN_TOKEN_INTERRUPT)) {				if (ep->dev->protocol_stall) {					ep->stopped = 1;					set_halt (ep);					mode = 2;				} else if (!req && ep->stopped)					write_fifo (ep, 0);			}		} else {			/* status; stop NAKing */			if (t & (1 << DATA_IN_TOKEN_INTERRUPT)) {				if (ep->dev->protocol_stall) {					ep->stopped = 1;					set_halt (ep);				}				mode = 2;			/* an extra OUT token is an error */			} else if (((t & (1 << DATA_OUT_PING_TOKEN_INTERRUPT))					&& req					&& req->req.actual == req->req.length)					|| !req) {				ep->dev->protocol_stall = 1;				set_halt (ep);				ep->stopped = 1;				if (req)					done (ep, req, -EOVERFLOW);				req = 0;			}		}	}	if (unlikely (!req))		return;	/* manual DMA queue advance after short OUT */	if (likely (ep->dma != 0)) {		if (t & (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)) {			u32	count;			int	stopped = ep->stopped;			/* TRANSFERRED works around OUT_DONE erratum 0112.			 * we expect (N <= maxpacket) bytes; host wrote M.			 * iff (M < N) we won't ever see a DMA interrupt.			 */			ep->stopped = 1;			for (count = 0; ; t = readl (&ep->regs->ep_stat)) {				/* any preceding dma transfers must finish.				 * dma handles (M >= N), may empty the queue				 */				scan_dma_completions (ep);				if (unlikely (list_empty (&ep->queue)						|| ep->out_overflow)) {					req = 0;					break;				}				req = list_entry (ep->queue.next,					struct net2280_request, queue);				/* here either (M < N), a "real" short rx;				 * or (M == N) and the queue didn't empty				 */				if (likely (t & (1 << FIFO_EMPTY))) {					count = readl (&ep->dma->dmacount);					count &= DMA_BYTE_COUNT_MASK;					if (readl (&ep->dma->dmadesc)							!= req->td_dma)						req = 0;					break;				}				udelay(1);			}			/* stop DMA, leave ep NAKing */			writel ((1 << DMA_ABORT), &ep->dma->dmastat);			spin_stop_dma (ep->dma);			if (likely (req != 0)) {				req->td->dmacount = 0;				t = readl (&ep->regs->ep_avail);				dma_done (ep, req, count, t);			}			/* also flush to prevent erratum 0106 trouble */			if (unlikely (ep->out_overflow					|| (ep->dev->chiprev == 0x0100						&& ep->dev->gadget.speed							== USB_SPEED_FULL))) {				out_flush (ep);				ep->out_overflow = 0;			}			/* (re)start dma if needed, stop NAKing */			ep->stopped = stopped;			if (!list_empty (&ep->queue))				restart_dma (ep);		} else			DEBUG (ep->dev, "%s dma ep_stat %08x ??\n",					ep->ep.name, t);		return;	/* data packet(s) received (in the fifo, OUT) */	} else if (t & (1 << DATA_PACKET_RECEIVED_INTERRUPT)) {		if (read_fifo (ep, req) && ep->num != 0)			mode = 2;	/* data packet(s) transmitted (IN) */	} else if (t & (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)) {		unsigned	len;		len = req->req.length - req->req.actual;		if (len > ep->ep.maxpacket)			len = ep->ep.maxpacket;		req->req.actual += len;		/* if we wrote it all, we're usually done */		if (req->req.actual == req->req.length) {			if (ep->num == 0) {				/* wait for control status */				if (mode != 2)					req = 0;			} else if (!req->req.zero || len != ep->ep.maxpacket)				mode = 2;		}	/* there was nothing to do ...  */	} else if (mode == 1)		return;	/* done */	if (mode == 2) {		/* stream endpoints often resubmit/unlink in completion */		done (ep, req, 0);		/* maybe advance queue to next request */		if (ep->num == 0) {			/* NOTE:  net2280 could let gadget driver start the			 * status stage later. since not all controllers let			 * them control that, the api doesn't (yet) allow it.			 */			if (!ep->stopped)				allow_status (ep);			req = 0;		} else {			if (!list_empty (&ep->queue) && !ep->stopped)				req = list_entry (ep->queue.next,					struct net2280_request, queue);			else				req = 0;			if (req && !ep->is_in)				stop_out_naking (ep);		}	}	/* is there a buffer for the next packet?	 * for best streaming performance, make sure there is one.	 */	if (req && !ep->stopped) {		/* load IN fifo with next packet (may be zlp) */		if (t & (1 << DATA_PACKET_TRANSMITTED_INTERRUPT))			write_fifo (ep, &req->req);	}}static struct net2280_ep *get_ep_by_addr (struct net2280 *dev, u16 wIndex){	struct net2280_ep	*ep;	if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0)		return &dev->ep [0];	list_for_each_entry (ep, &dev->gadget.ep_list, ep.ep_list) {		u8	bEndpointAddress;		if (!ep->desc)			continue;		bEndpointAddress = ep->desc->bEndpointAddress;		if ((wIndex ^ bEndpointAddress) & USB_DIR_IN)			continue;		if ((wIndex & 0x0f) == (bEndpointAddress & 0x0f))			return ep;	}	return 0;}static void handle_stat0_irqs (struct net2280 *dev, u32 stat){	struct net2280_ep	*ep;	u32			num, scratch;	/* most of these don't need individual acks */	stat &= ~(1 << INTA_ASSERTED);	if (!stat)		return;	// DEBUG (dev, "irqstat0 %04x\n", stat);	/* starting a control request? */	if (unlikely (stat & (1 << SETUP_PACKET_INTERRUPT))) {		union {			u32			raw [2];			struct usb_ctrlrequest	r;		} u;		int				tmp = 0;		struct net2280_request		*req;		if (dev->gadget.speed == USB_SPEED_UNKNOWN) {			if (readl (&dev->usb->usbstat) & (1 << HIGH_SPEED))				dev->gadget.speed = USB_SPEED_HIGH;			else				dev->gadget.speed = USB_SPEED_FULL;			net2280_led_speed (dev, dev->gadget.speed);			DEBUG (dev, "%s speed\n",				(dev->gadget.speed == USB_SPEED_HIGH)					? "high" : "full");		}		ep = &dev->ep [0];		ep->irqs++;		/* make sure any leftover request state is cleared */		stat &= ~(1 << ENDPOINT_0_INTERRUPT);		while (!list_empty (&ep->queue)) {			req = list_entry (ep->queue.next,					struct net2280_request, queue);			done (ep, req, (req->req.actual == req->req.length)						? 0 : -EPROTO);		}		ep->stopped = 0;		dev->protocol_stall = 0;		writel (  (1 << TIMEOUT)			| (1 << USB_STALL_SENT)			| (1 << USB_IN_NAK_SENT)			| (1 << USB_IN_ACK_RCVD)			| (1 << USB_OUT_PING_NAK_SENT)			| (1 << USB_OUT_ACK_SENT)			| (1 << FIFO_OVERFLOW)			| (1 << FIFO_UNDERFLOW)			| (1 << SHORT_PACKET_OUT_DONE_INTERRUPT)			| (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)			| (1 << DATA_PACKET_RECEIVED_INTERRUPT)			| (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)			| (1 << DATA_OUT_PING_TOKEN_INTERRUPT)			| (1 << DATA_IN_TOKEN_INTERRUPT)			, &ep->regs->ep_stat);		u.raw [0] = readl (&dev->usb->setup0123);		u.raw [1] = readl (&dev->usb->setup4567);				cpu_to_le32s (&u.raw [0]);		cpu_to_le32s (&u.raw [1]);		le16_to_cpus (&u.r.wValue);		le16_to_cpus (&u.r.wIndex);		le16_to_cpus (&u.r.wLength);		/* ack the irq */		writel (1 << SETUP_PACKET_INTERRUPT, &dev->regs->irqstat0);		stat ^= (1 << SETUP_PACKET_INTERRUPT);		/* watch control traffic at the token level, and force		 * synchronization before letting the status stage happen.		 * FIXME ignore tokens we'll NAK, until driver responds.		 * that'll mean a lot less irqs for some drivers.		 */		ep->is_in = (u.r.bRequestType & USB_DIR_IN) != 0;		if (ep->is_in) {			scratch = (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)				| (1 << DATA_OUT_PING_TOKEN_INTERRUPT)				| (1 << DATA_IN_TOKEN_INTERRUPT);			stop_out_naking (ep);		} else			scratch = (1 << DATA_PACKET_RECEIVED_INTERRUPT)				| (1 << DATA_OUT_PING_TOKEN_INTERRUPT)				| (1 << DATA_IN_TOKEN_INTERRUPT);		writel (scratch, &dev->epregs [0].ep_irqenb);		/* we made the hardware handle most lowlevel requests;		 * everything else goes uplevel to the gadget code.		 */		switch (u.r.bRequest) {		case USB_REQ_GET_STATUS: {			struct net2280_ep	*e;			u16			status;			/* hw handles device and interface status */			if (u.r.bRequestType != (USB_DIR_IN|USB_RECIP_ENDPOINT))				goto delegate;			if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0					|| u.r.wLength > 2)				goto do_stall;			if (readl (&e->regs->ep_rsp)					& (1 << SET_ENDPOINT_HALT))				status = __constant_cpu_to_le16 (1);			else				status = __constant_cpu_to_le16 (0);			/* don't bother with a request object! */			writel (0, &dev->epregs [0].ep_irqenb);			set_fifo_bytecount (ep, u.r.wLength);			writel (status, &dev->epregs [0].ep_data);			allow_status (ep);			VDEBUG (dev, "%s stat %02x\n", ep->ep.name, status);			goto next_endpoints;			}			break;		case USB_REQ_CLEAR_FEATURE: {			struct net2280_ep	*e;			/* hw handles device features */			if (u.r.bRequestType != USB_RECIP_ENDPOINT)				goto delegate;			if (u.r.wValue != 0 /* HALT feature */					|| u.r.wLength != 0)				goto do_stall;			if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0)				goto do_stall;			clear_halt (e);			allow_status (ep);			VDEBUG (dev, "%s clear halt\n", ep->ep.name);			goto next_endpoints;			}			break;		case USB_REQ_SET_FEATURE: {			struct net2280_ep	*e;			/* hw handles device features */			if (u.r.bRequestType != USB_RECIP_ENDPOINT)				goto delegate;			if (u.r.wValue != 0 /* HALT feature */					|| u.r.wLength != 0)				goto do_stall;			if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0)				goto do_stall;			set_halt (e);			allow_status (ep);			VDEBUG (dev, "%s set halt\n", ep->ep.name);			goto next_endpoints;			}			break;		default:delegate:			VDEBUG (dev, "setup %02x.%02x v%04x i%04x "				"ep_cfg %08x\n",				u.r.bRequestType, u.r.bRequest,				u.r.wValue, u.r.wIndex,				readl (&ep->regs->ep_cfg));			spin_unlock (&dev->lock);			tmp = dev->driver->setup (&dev->gadget, &u.r);			spin_lock (&dev->lock);		}		/* stall ep0 on error */		if (tmp < 0) {do_stall:			VDEBUG (dev, "req %02x.%02x protocol STALL; stat %d\n",					u.r.bRequestType, u.r.bRequest, tmp);			dev->protocol_stall = 1;		}		/* some in/out token irq should follow; maybe stall then.		 * driver must queue a request (even zlp) or halt ep0		 *

⌨️ 快捷键说明

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