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

📄 lh7a40x_udc.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
	return 1;}static int lh7a40x_handle_get_status(struct lh7a40x_udc *dev,				     struct usb_ctrlrequest *ctrl){	struct lh7a40x_ep *ep0 = &dev->ep[0];	struct lh7a40x_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_read(qep->csr1) & EP0_SEND_STALL) ==			    EP0_SEND_STALL;			break;		case ep_bulk_in:		case ep_interrupt:			val =			    (usb_read(qep->csr1) & USB_IN_CSR1_SEND_STALL) ==			    USB_IN_CSR1_SEND_STALL;			break;		case ep_bulk_out:			val =			    (usb_read(qep->csr1) & USB_OUT_CSR1_SEND_STALL) ==			    USB_OUT_CSR1_SEND_STALL;			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_set((EP0_CLR_OUT), USB_EP0_CSR);	/* Put status to FIFO */	lh7a40x_fifo_write(ep0, (u8 *) & val, sizeof(val));	/* Issue "In packet ready" */	usb_set((EP0_IN_PKT_RDY | EP0_DATA_END), USB_EP0_CSR);	return 0;}/* * WAIT_FOR_SETUP (OUT_PKT_RDY) *      - read data packet from EP0 FIFO *      - decode command *      - if error *              set EP0_CLR_OUT | EP0_DATA_END | EP0_SEND_STALL bits *      - else *              set EP0_CLR_OUT | EP0_DATA_END bits */static void lh7a40x_ep0_setup(struct lh7a40x_udc *dev, u32 csr){	struct lh7a40x_ep *ep = &dev->ep[0];	struct usb_ctrlrequest ctrl;	int i, bytes, is_in;	DEBUG_SETUP("%s: %x\n", __FUNCTION__, csr);	/* Nuke all previous transfers */	nuke(ep, -EPROTO);	/* read control req from fifo (8 bytes) */	bytes = lh7a40x_fifo_read(ep, (unsigned char *)&ctrl, 8);	DEBUG_SETUP("Read CTRL REQ %d bytes\n", bytes);	DEBUG_SETUP("CTRL.bRequestType = %d (is_in %d)\n", ctrl.bRequestType,		    ctrl.bRequestType == USB_DIR_IN);	DEBUG_SETUP("CTRL.bRequest = %d\n", ctrl.bRequest);	DEBUG_SETUP("CTRL.wLength = %d\n", ctrl.wLength);	DEBUG_SETUP("CTRL.wValue = %d (%d)\n", ctrl.wValue, ctrl.wValue >> 8);	DEBUG_SETUP("CTRL.wIndex = %d\n", ctrl.wIndex);	/* Set direction of EP0 */	if (likely(ctrl.bRequestType & USB_DIR_IN)) {		ep->bEndpointAddress |= USB_DIR_IN;		is_in = 1;	} else {		ep->bEndpointAddress &= ~USB_DIR_IN;		is_in = 0;	}	dev->req_pending = 1;	/* Handle some SETUP packets ourselves */	switch (ctrl.bRequest) {	case USB_REQ_SET_ADDRESS:		if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE))			break;		DEBUG_SETUP("USB_REQ_SET_ADDRESS (%d)\n", ctrl.wValue);		udc_set_address(dev, ctrl.wValue);		usb_set((EP0_CLR_OUT | EP0_DATA_END), USB_EP0_CSR);		return;	case USB_REQ_GET_STATUS:{			if (lh7a40x_handle_get_status(dev, &ctrl) == 0)				return;	case USB_REQ_CLEAR_FEATURE:	case USB_REQ_SET_FEATURE:			if (ctrl.bRequestType == USB_RECIP_ENDPOINT) {				struct lh7a40x_ep *qep;				int ep_num = (ctrl.wIndex & 0x0f);				/* Support only HALT feature */				if (ctrl.wValue != 0 || ctrl.wLength != 0				    || ep_num > 3 || ep_num < 1)					break;				qep = &dev->ep[ep_num];				if (ctrl.bRequest == USB_REQ_SET_FEATURE) {					DEBUG_SETUP("SET_FEATURE (%d)\n",						    ep_num);					lh7a40x_set_halt(&qep->ep, 1);				} else {					DEBUG_SETUP("CLR_FEATURE (%d)\n",						    ep_num);					lh7a40x_set_halt(&qep->ep, 0);				}				usb_set_index(0);				/* Reply with a ZLP on next IN token */				usb_set((EP0_CLR_OUT | EP0_DATA_END),					USB_EP0_CSR);				return;			}			break;		}	default:		break;	}	if (likely(dev->driver)) {		/* device-2-host (IN) or no data setup command, process immediately */		spin_unlock(&dev->lock);		i = dev->driver->setup(&dev->gadget, &ctrl);		spin_lock(&dev->lock);		if (i < 0) {			/* setup processing failed, force stall */			DEBUG_SETUP			    ("  --> ERROR: gadget setup FAILED (stalling), setup returned %d\n",			     i);			usb_set_index(0);			usb_set((EP0_CLR_OUT | EP0_DATA_END | EP0_SEND_STALL),				USB_EP0_CSR);			/* ep->stopped = 1; */			dev->ep0state = WAIT_FOR_SETUP;		}	}}/* * DATA_STATE_NEED_ZLP */static void lh7a40x_ep0_in_zlp(struct lh7a40x_udc *dev, u32 csr){	DEBUG_EP0("%s: %x\n", __FUNCTION__, csr);	/* c.f. Table 15-14 */	usb_set((EP0_IN_PKT_RDY | EP0_DATA_END), USB_EP0_CSR);	dev->ep0state = WAIT_FOR_SETUP;}/* * handle ep0 interrupt */static void lh7a40x_handle_ep0(struct lh7a40x_udc *dev, u32 intr){	struct lh7a40x_ep *ep = &dev->ep[0];	u32 csr;	/* Set index 0 */	usb_set_index(0); 	csr = usb_read(USB_EP0_CSR);	DEBUG_EP0("%s: csr = %x\n", __FUNCTION__, csr);	/*	 * For overview of what we should be doing see c.f. Chapter 18.1.2.4	 * We will follow that outline here modified by our own global state	 * indication which provides hints as to what we think should be	 * happening..	 */	/*	 * if SENT_STALL is set	 *      - clear the SENT_STALL bit	 */	if (csr & EP0_SENT_STALL) {		DEBUG_EP0("%s: EP0_SENT_STALL is set: %x\n", __FUNCTION__, csr);		usb_clear((EP0_SENT_STALL | EP0_SEND_STALL), USB_EP0_CSR);		nuke(ep, -ECONNABORTED);		dev->ep0state = WAIT_FOR_SETUP;		return;	}	/*	 * if a transfer is in progress && IN_PKT_RDY and OUT_PKT_RDY are clear	 *      - fill EP0 FIFO	 *      - if last packet	 *      -       set IN_PKT_RDY | DATA_END	 *      - else	 *              set IN_PKT_RDY	 */	if (!(csr & (EP0_IN_PKT_RDY | EP0_OUT_PKT_RDY))) {		DEBUG_EP0("%s: IN_PKT_RDY and OUT_PKT_RDY are clear\n",			  __FUNCTION__);		switch (dev->ep0state) {		case DATA_STATE_XMIT:			DEBUG_EP0("continue with DATA_STATE_XMIT\n");			lh7a40x_ep0_in(dev, csr);			return;		case DATA_STATE_NEED_ZLP:			DEBUG_EP0("continue with DATA_STATE_NEED_ZLP\n");			lh7a40x_ep0_in_zlp(dev, csr);			return;		default:			/* Stall? */			DEBUG_EP0("Odd state!! state = %s\n",				  state_names[dev->ep0state]);			dev->ep0state = WAIT_FOR_SETUP;			/* nuke(ep, 0); */			/* usb_set(EP0_SEND_STALL, ep->csr1); */			break;		}	}	/*	 * if SETUP_END is set	 *      - abort the last transfer	 *      - set SERVICED_SETUP_END_BIT	 */	if (csr & EP0_SETUP_END) {		DEBUG_EP0("%s: EP0_SETUP_END is set: %x\n", __FUNCTION__, csr);		usb_set(EP0_CLR_SETUP_END, USB_EP0_CSR);		nuke(ep, 0);		dev->ep0state = WAIT_FOR_SETUP;	}	/*	 * if EP0_OUT_PKT_RDY is set	 *      - read data packet from EP0 FIFO	 *      - decode command	 *      - if error	 *              set SERVICED_OUT_PKT_RDY | DATA_END bits | SEND_STALL	 *      - else	 *              set SERVICED_OUT_PKT_RDY | DATA_END bits	 */	if (csr & EP0_OUT_PKT_RDY) {		DEBUG_EP0("%s: EP0_OUT_PKT_RDY is set: %x\n", __FUNCTION__,			  csr);		switch (dev->ep0state) {		case WAIT_FOR_SETUP:			DEBUG_EP0("WAIT_FOR_SETUP\n");			lh7a40x_ep0_setup(dev, csr);			break;		case DATA_STATE_RECV:			DEBUG_EP0("DATA_STATE_RECV\n");			lh7a40x_ep0_out(dev, csr);			break;		default:			/* send stall? */			DEBUG_EP0("strange state!! 2. send stall? state = %d\n",				  dev->ep0state);			break;		}	}}static void lh7a40x_ep0_kick(struct lh7a40x_udc *dev, struct lh7a40x_ep *ep){	u32 csr;	usb_set_index(0);	csr = usb_read(USB_EP0_CSR);	DEBUG_EP0("%s: %x\n", __FUNCTION__, csr);	/* Clear "out packet ready" */	usb_set(EP0_CLR_OUT, USB_EP0_CSR);	if (ep_is_in(ep)) {		dev->ep0state = DATA_STATE_XMIT;		lh7a40x_ep0_in(dev, csr);	} else {		dev->ep0state = DATA_STATE_RECV;		lh7a40x_ep0_out(dev, csr);	}}/* --------------------------------------------------------------------------- * 	device-scoped parts of the api to the usb controller hardware * --------------------------------------------------------------------------- */static int lh7a40x_udc_get_frame(struct usb_gadget *_gadget){	u32 frame1 = usb_read(USB_FRM_NUM1);	/* Least significant 8 bits */	u32 frame2 = usb_read(USB_FRM_NUM2);	/* Most significant 3 bits */	DEBUG("%s, %p\n", __FUNCTION__, _gadget);	return ((frame2 & 0x07) << 8) | (frame1 & 0xff);}static int lh7a40x_udc_wakeup(struct usb_gadget *_gadget){	/* host may not have enabled remote wakeup */	/*if ((UDCCS0 & UDCCS0_DRWF) == 0)	   return -EHOSTUNREACH;	   udc_set_mask_UDCCR(UDCCR_RSM); */	return -ENOTSUPP;}static const struct usb_gadget_ops lh7a40x_udc_ops = {	.get_frame = lh7a40x_udc_get_frame,	.wakeup = lh7a40x_udc_wakeup,	/* current versions must always be self-powered */};static void nop_release(struct device *dev){	DEBUG("%s %s\n", __FUNCTION__, dev->bus_id);}static struct lh7a40x_udc memory = {	.usb_address = 0,	.gadget = {		   .ops = &lh7a40x_udc_ops,		   .ep0 = &memory.ep[0].ep,		   .name = driver_name,		   .dev = {			   .bus_id = "gadget",			   .release = nop_release,			   },		   },	/* control endpoint */	.ep[0] = {		  .ep = {			 .name = ep0name,			 .ops = &lh7a40x_ep_ops,			 .maxpacket = EP0_PACKETSIZE,			 },		  .dev = &memory,		  .bEndpointAddress = 0,		  .bmAttributes = 0,		  .ep_type = ep_control,		  .fifo = io_p2v(USB_EP0_FIFO),		  .csr1 = USB_EP0_CSR,		  .csr2 = USB_EP0_CSR,		  },	/* first group of endpoints */	.ep[1] = {		  .ep = {			 .name = "ep1in-bulk",			 .ops = &lh7a40x_ep_ops,			 .maxpacket = 64,			 },		  .dev = &memory,		  .bEndpointAddress = USB_DIR_IN | 1,		  .bmAttributes = USB_ENDPOINT_XFER_BULK,		  .ep_type = ep_bulk_in,		  .fifo = io_p2v(USB_EP1_FIFO),		  .csr1 = USB_IN_CSR1,		  .csr2 = USB_IN_CSR2,		  },	.ep[2] = {		  .ep = {			 .name = "ep2out-bulk",			 .ops = &lh7a40x_ep_ops,			 .maxpacket = 64,			 },		  .dev = &memory,		  .bEndpointAddress = 2,		  .bmAttributes = USB_ENDPOINT_XFER_BULK,		  .ep_type = ep_bulk_out,		  .fifo = io_p2v(USB_EP2_FIFO),		  .csr1 = USB_OUT_CSR1,		  .csr2 = USB_OUT_CSR2,		  },	.ep[3] = {		  .ep = {			 .name = "ep3in-int",			 .ops = &lh7a40x_ep_ops,			 .maxpacket = 64,			 },		  .dev = &memory,		  .bEndpointAddress = USB_DIR_IN | 3,		  .bmAttributes = USB_ENDPOINT_XFER_INT,		  .ep_type = ep_interrupt,		  .fifo = io_p2v(USB_EP3_FIFO),		  .csr1 = USB_IN_CSR1,		  .csr2 = USB_IN_CSR2,		  },};/* * 	probe - binds to the platform device */static int lh7a40x_udc_probe(struct platform_device *pdev){	struct lh7a40x_udc *dev = &memory;	int retval;	DEBUG("%s: %p\n", __FUNCTION__, pdev);	spin_lock_init(&dev->lock);	dev->dev = &pdev->dev;	device_initialize(&dev->gadget.dev);	dev->gadget.dev.parent = &pdev->dev;	the_controller = dev;	platform_set_drvdata(pdev, dev);	udc_disable(dev);	udc_reinit(dev);	/* irq setup after old hardware state is cleaned up */	retval =	    request_irq(IRQ_USBINTR, lh7a40x_udc_irq, SA_INTERRUPT, driver_name,			dev);	if (retval != 0) {		DEBUG(KERN_ERR "%s: can't get irq %i, err %d\n", driver_name,		      IRQ_USBINTR, retval);		return -EBUSY;	}	create_proc_files();	return retval;}static int lh7a40x_udc_remove(struct platform_device *pdev){	struct lh7a40x_udc *dev = platform_get_drvdata(pdev);	DEBUG("%s: %p\n", __FUNCTION__, pdev);	udc_disable(dev);	remove_proc_files();	usb_gadget_unregister_driver(dev->driver);	free_irq(IRQ_USBINTR, dev);	platform_set_drvdata(pdev, 0);	the_controller = 0;	return 0;}/*-------------------------------------------------------------------------*/static struct platform_driver udc_driver = {	.probe = lh7a40x_udc_probe,	.remove = lh7a40x_udc_remove	    /* FIXME power management support */	    /* .suspend = ... disable UDC */	    /* .resume = ... re-enable UDC */	.driver	= {		.name = (char *)driver_name,		.owner = THIS_MODULE,	},};static int __init udc_init(void){	DEBUG("%s: %s version %s\n", __FUNCTION__, driver_name, DRIVER_VERSION);	return platform_driver_register(&udc_driver);}static void __exit udc_exit(void){	platform_driver_unregister(&udc_driver);}module_init(udc_init);module_exit(udc_exit);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_AUTHOR("Mikko Lahteenmaki, Bo Henriksen");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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