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

📄 superh_udc.c

📁 LINUX2.4.18内核下的usb GADGET驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
	}	ep->desc = desc;	ep->dma = -1;	ep->stopped = 0;	/* flush fifo (mostly for OUT buffers), enable irq */	superh_ep_fifo_flush (_ep);	/* ... reset halt state too, if we could ... */#ifdef	USE_DMA#endif	DBG(DBG_VERBOSE, "enabled %s\n", _ep->name);	return 0;}static int superh_ep_disable (struct usb_ep *_ep){	struct superh_ep	*ep;	DBG(DBG_NOISY, "superh_ep_disable\n");	ep = container_of (_ep, struct superh_ep, ep);	if (!_ep || !ep->desc) {		DMSG("%s, %s not enabled\n", __FUNCTION__,			_ep ? ep->ep.name : NULL);		return -EINVAL;	}	nuke (ep, -ESHUTDOWN);#ifdef	USE_DMA	/* TODO */	if (ep->dma >= 0) {		*ep->reg_drcmr = 0;		pxa_free_dma (ep->dma);		ep->dma = -1;	}#endif	/* flush fifo (mostly for IN buffers) */	superh_ep_fifo_flush (_ep);	ep->desc = 0;	ep->stopped = 1;	DBG(DBG_VERBOSE, "%s disabled\n", _ep->name);	return 0;}/* for the superh, these can just wrap kmalloc/kfree.  gadget drivers * must still pass correctly initialized endpoints, since other controller * drivers may care about how it's currently set up (dma issues etc). *//* * 	superh_ep_alloc_request - allocate a request data structure */static struct usb_request *superh_ep_alloc_request (struct usb_ep *_ep, int gfp_flags){	struct superh_request *req;	/* FIXME for bulk out-dma endpoints, preallocate a frame's worth of	 * (aligned) dma descriptors at the end of the request	 */	req = kmalloc (sizeof *req, gfp_flags);	if (!req)		return 0;	memset (req, 0, sizeof *req);	INIT_LIST_HEAD (&req->queue);	DBG(DBG_VERY_NOISY, "superh_ep_alloc_request: %p %d\n", req, list_empty(&req->queue));	return &req->req;}/* * 	superh_ep_free_request - deallocate a request data structure */static voidsuperh_ep_free_request (struct usb_ep *_ep, struct usb_request *_req){	struct superh_request	*req;	req = container_of (_req, struct superh_request, req);	WARN_ON (!list_empty (&req->queue));	kfree(req);}/* SH cache needs flushing with DMA I/O (it's dma-incoherent), but there's * no device-affinity and the heap works perfectly well for i/o buffers. * TODO: check this */static void *superh_ep_alloc_buffer(struct usb_ep *_ep, unsigned bytes,		       dma_addr_t *dma, int gfp_flags){	char			*retval;	retval = kmalloc (bytes, gfp_flags);	if (retval)		*dma = virt_to_bus (retval);	return retval;}static voidsuperh_ep_free_buffer(struct usb_ep *_ep, void *buf, dma_addr_t dma,		unsigned bytes){	kfree (buf);}static struct superh_request*process_ep_req(struct superh_ep *ep, struct superh_request *req){	struct superh_udc *dev = ep->dev;	if (ep->desc == 0 /* ep0 */) {		switch (dev->ep0state) {		case EP0_IN_DATA_PHASE:			DBG(DBG_VERY_NOISY, "superh_ep_queue: EP0_IN_DATA_PHASE\n");			dev->stats.write.ops++;			if (write_ep0_fifo(ep, req))				req = 0;			break;					case EP0_OUT_DATA_PHASE:			DBG(DBG_VERY_NOISY, "superh_ep_queue: EP0_OUT_DATA_PHASE\n");			dev->stats.read.ops++;			if (read_ep0_fifo(ep, req))				req = 0;			break;					default:			DMSG("ep0 i/o, odd state %d\n", dev->ep0state);			return 0;		}#ifdef	USE_DMA		/* either start dma or prime pio pump */	}	else if (ep->dma >= 0) {		kick_dma(ep, req);#endif		/* can the FIFO can satisfy the request immediately? */	}	else if ((ep->bEndpointAddress & USB_DIR_IN) != 0) {		if ((ep->desc->bEndpointAddress & 0x0f) == 2		    && (ctrl_inb(USBIFR0) & EP2_TR) != 0		    && write_fifo(ep, req)) {			req = 0;		}		else if ((ep->desc->bEndpointAddress & 0x0f) == 3		    && (ctrl_inb(USBIFR1) & EP3_TR) != 0		    && write_fifo(ep, req)) {			req = 0;		}	}	if (likely (((req && ep->desc) && ep->dma < 0) || ep->desc == 0))		pio_irq_enable(ep);	return req;} static intsuperh_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags){	struct superh_request	*req;	struct superh_ep	*ep;	struct superh_udc	*dev;	unsigned long		flags;	req = container_of(_req, struct superh_request, req);	ep = container_of(_ep, struct superh_ep, ep);	DBG(DBG_VERY_NOISY, "superh_ep_queue\n");	/* If we have just sent a fake configuration request then	 * this is the reply.  We don't want to send it to the host	 * so just ignore it.	 */	if (ep->desc == 0 /* ep0 */ && ep->dev->fake_config) {		DBG(DBG_NOISY, "Ignoring bogus SET_CONFIGURATION response\n");		done(ep, req, 0);		ep->dev->fake_config = 0;		return 1;	}	if (unlikely (!_req || !_req->complete || !_req->buf		      || !list_empty(&req->queue))) {		DMSG("%s, bad params %s, %p, %p, %p, %d\n", __FUNCTION__,		     ep->ep.name, _req, _req->complete, _req->buf,		     list_empty(&req->queue));		return -EINVAL;	}	if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) {		DMSG("%s, bad ep\n", __FUNCTION__);		return -EINVAL;	}	dev = ep->dev;	if (unlikely (!dev->driver			|| dev->gadget.speed == USB_SPEED_UNKNOWN)) {		DMSG("%s, bogus device state\n", __FUNCTION__);		return -ESHUTDOWN;	}#ifdef	USE_DMA	/* TODO */	if (ep->dma >= 0) {		unsigned long	start = (unsigned long) _req->buf;		clean_dcache_range(start, start + _req->length);		/* or for USB_DIR_OUT, invalidate_dcache_range (...) */	}#endif	DBG(DBG_NOISY, "%s queue req %p, len %d buf %p\n",	     _ep->name, _req, _req->length, _req->buf);	local_irq_save(flags);	_req->status = -EINPROGRESS;	_req->actual = 0;	/* kickstart this i/o queue? */	if (list_empty(&ep->queue) && !ep->stopped && !ep->halted) {		req = process_ep_req(ep, req);	}		/* pio or dma irq handler advances the queue. */	if (likely (req != 0))		list_add_tail(&req->queue, &ep->queue);	local_irq_restore(flags);	return 0;}static intsuperh_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req){	struct superh_ep	*ep;	struct superh_request	*req;	unsigned long		flags;	DBG(DBG_NOISY, "superh_ep_dequeue %s\n", _ep->name);	ep = container_of(_ep, struct superh_ep, ep);	req = container_of(_req, struct superh_request, req);	if (!_ep || !_req || ep->ep.name == ep0name)		return -EINVAL;	local_irq_save(flags);#ifdef	USE_DMA	if (ep->dma >= 0 && ep->queue.next == &req->queue && !ep->stopped) {		cancel_dma(ep);		done(ep, req, -ECONNRESET);		/* restart i/o */		if (!list_empty(&ep->queue)) {			req = list_entry(ep->queue.next,					struct superh_request, queue);			kick_dma(ep, req);		}	} else#endif	if (!list_empty(&req->queue))		done(ep, req, -ECONNRESET);	else		req = 0;	local_irq_restore(flags);	return req ? 0 : -EOPNOTSUPP;}/* stall/unstall an endpoint, 0 clears the stall, 1 sets it */static intsuperh_ep_set_halt(struct usb_ep *_ep, int value){	struct superh_ep	*ep;	unsigned long		flags;	ep = container_of(_ep, struct superh_ep, ep);	if (unlikely (!_ep			|| (!ep->desc && ep->ep.name != ep0name))			|| ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) {		DMSG("%s, bad ep\n", __FUNCTION__);		return -EINVAL;	}	if (ep->halted == value)		return 0;	local_irq_save(flags);	if (value == 1 && (ep->bEndpointAddress & USB_DIR_IN) != 0	    && ((ctrl_inb(USBDASTS) & ep->data_present_mask) != 0		|| !list_empty(&ep->queue))) {		local_irq_restore(flags);		DBG(DBG_VERBOSE, "Can't %s on %s\n", value ? " halt" : "clear halt", _ep->name);		return -EAGAIN;	}	if (value) {		or_b(ep->stall_mask, USBEPSTL);		if (!ep->desc) {			ep->dev->ep0state = EP0_STALL;		}		/* disable ep interrupts and set a timer to clear the stall */		pio_irq_disable(ep);		mod_timer(&ep->dev->timer, jiffies + STALL_TIME);	}	else {		and_b(~ep->stall_mask, USBEPSTL);	}	ep->halted = value;	local_irq_restore(flags);	DBG(DBG_VERBOSE, "%s %s\n", _ep->name, value ? " halt" : "clear halt");	return 0;}static int superh_ep_fifo_status(struct usb_ep *_ep){	struct superh_ep        *ep;	DBG(DBG_NOISY, "superh_ep_fifo_status\n");	ep = container_of(_ep, struct superh_ep, ep);	if (!_ep) {		DMSG("%s, bad ep\n", __FUNCTION__);		return -ENODEV;	}	if ((ep->bEndpointAddress & USB_DIR_IN) != 0)		return -EOPNOTSUPP;	if (ep->dev->gadget.speed == USB_SPEED_UNKNOWN)		return 0;	else {		switch (ep->desc->bEndpointAddress & 0x0f) {		case 0:			return ctrl_inb(USBEPSZ0O);		case 1:			return ctrl_inb(USBEPSZ1);		}	}		return 0;}static void superh_ep_fifo_flush(struct usb_ep *_ep){	struct superh_ep        *ep;	DBG(DBG_NOISY, "superh_ep_fifo_flush\n");	ep = container_of(_ep, struct superh_ep, ep);	if (!_ep || ep->ep.name == ep0name || !list_empty(&ep->queue)) {		DMSG("%s, bad ep\n", __FUNCTION__);		return;	}	or_b(ep->clear_mask, USBFCLR);}static struct usb_ep_ops superh_ep_ops = {	.enable		= superh_ep_enable,	.disable	= superh_ep_disable,	.alloc_request	= superh_ep_alloc_request,	.free_request	= superh_ep_free_request,	.alloc_buffer	= superh_ep_alloc_buffer,	.free_buffer	= superh_ep_free_buffer,	.queue		= superh_ep_queue,	.dequeue	= superh_ep_dequeue,	.set_halt	= superh_ep_set_halt,	.fifo_status	= superh_ep_fifo_status,	.fifo_flush	= superh_ep_fifo_flush,};/* --------------------------------------------------------------------------- * 	device-scoped parts of the api to the usb controller hardware * --------------------------------------------------------------------------- */static int superh_udc_get_frame(struct usb_gadget *_gadget){	DBG(DBG_VERY_NOISY, "superh_udc_get_frame\n");	return -EOPNOTSUPP;}static const struct usb_gadget_ops superh_udc_ops = {	.get_frame	 = superh_udc_get_frame,	// no remote wakeup	// always selfpowered};/* if we're trying to save space, don't bother with this proc file */#if defined(CONFIG_PROC_FS) && !defined(CONFIG_EMBEDDED)#  define	UDC_PROC_FILE#endif#ifdef UDC_PROC_FILEstatic const char proc_node_name [] = "driver/udc";static intudc_proc_read(char *page, char **start, off_t off, int count,		int *eof, void *_dev){	char			*buf = page;	struct superh_udc	*dev = _dev;	char			*next = buf;	unsigned		size = count;	unsigned long		flags;	int			t;	int			i;	local_irq_save(flags);	/* basic device status */	t = snprintf(next, size,		"%s\n%s version: %s\nGadget driver: %s\nHost %s\n\n",		driver_desc,		driver_name, DRIVER_VERSION,		dev->driver ? dev->driver->driver.name : "(none)",		is_usb_connected ? "full speed" : "disconnected");	size -= t;	next += t;	/* device registers */	t = snprintf(next, size,		     "ifr0 %02X, ifr1 %02X, isr0 %02X, isr1 %02X, ier0 %02X, ier1 %02X\n",		     ctrl_inb(USBIFR0), ctrl_inb(USBIFR1),		     ctrl_inb(USBISR0), ctrl_inb(USBISR1),		     ctrl_inb(USBIER0), ctrl_inb(USBIER1));	size -= t;	next += t;	t = snprintf(next, size,		     "epsz0o %02X, epsz1 %02X, dasts %02X, dmar %02X\n",

⌨️ 快捷键说明

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