g_ep0.c

来自「omap3 linux 2.6 用nocc去除了冗余代码」· C语言 代码 · 共 982 行 · 第 1/2 页

C
982
字号
/****************************************************************** * Copyright 2005 Mentor Graphics Corporation * Copyright (C) 2005-2006 by Texas Instruments * * This file is part of the Inventra Controller Driver for Linux. * * The Inventra Controller Driver for Linux is free software; you * can redistribute it and/or modify it under the terms of the GNU * General Public License version 2 as published by the Free Software * Foundation. * * The Inventra Controller Driver for Linux is distributed in * the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public * License for more details. * * You should have received a copy of the GNU General Public License * along with The Inventra Controller Driver for Linux ; if not, * write to the Free Software Foundation, Inc., 59 Temple Place, * Suite 330, Boston, MA  02111-1307  USA * * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER. * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR * GRAPHICS SUPPORT CUSTOMER. ******************************************************************/#include <linux/kernel.h>#include <linux/list.h>#include <linux/timer.h>#include <linux/spinlock.h>#include <linux/init.h>#include <linux/device.h>#include <linux/interrupt.h>#include "musbdefs.h"/* ep0 is always musb->aLocalEnd[0].ep_in */#define	next_ep0_request(musb)	next_in_request(&(musb)->aLocalEnd[0])/* * Locking note:  we use only the controller lock, for simpler correctness. * It's always held with IRQs blocked. * * It protects the ep0 request queue as well as ep0_state, not just the * controller and indexed registers.  And that lock stays held unless it * needs to be dropped to allow reentering this driver ... like upcalls to * the gadget driver, or adjusting endpoint halt status. */static char *decode_ep0stage(u8 stage){	switch(stage) {	case MGC_END0_STAGE_SETUP:	return "idle";	case MGC_END0_STAGE_TX:		return "in";	case MGC_END0_STAGE_RX:		return "out";	case MGC_END0_STAGE_ACKWAIT:	return "wait";	case MGC_END0_STAGE_STATUSIN:	return "in/status";	case MGC_END0_STAGE_STATUSOUT:	return "out/status";	default:			return "?";	}}/* handle a standard GET_STATUS request * Context:  caller holds controller lock */static int service_tx_status_request(	struct musb *musb,	const struct usb_ctrlrequest *pControlRequest){	void __iomem	*pBase = musb->pRegs;	int handled = 1;	u8 bResult[2], bEnd = 0;	const u8 bRecip = pControlRequest->bRequestType & USB_RECIP_MASK;	bResult[1] = 0;	switch (bRecip) {	case USB_RECIP_DEVICE:		bResult[0] = musb->is_self_powered << USB_DEVICE_SELF_POWERED;		bResult[0] |= musb->may_wakeup << USB_DEVICE_REMOTE_WAKEUP;		if (musb->g.is_otg) {			bResult[0] |= musb->g.b_hnp_enable				<< USB_DEVICE_B_HNP_ENABLE;			bResult[0] |= musb->g.a_alt_hnp_support				<< USB_DEVICE_A_ALT_HNP_SUPPORT;			bResult[0] |= musb->g.a_hnp_support				<< USB_DEVICE_A_HNP_SUPPORT;		}		break;	case USB_RECIP_INTERFACE:		bResult[0] = 0;		break;	case USB_RECIP_ENDPOINT: {		int		is_in;		struct musb_ep	*ep;		u16		tmp;		void __iomem	*regs;		bEnd = (u8) pControlRequest->wIndex;		if (!bEnd) {			bResult[0] = 0;			break;		}		is_in = bEnd & USB_DIR_IN;		if (is_in) {			bEnd &= 0x0f;			ep = &musb->aLocalEnd[bEnd].ep_in;		} else {			ep = &musb->aLocalEnd[bEnd].ep_out;		}		regs = musb->aLocalEnd[bEnd].regs;		if (bEnd >= MUSB_C_NUM_EPS || !ep->desc) {			handled = -EINVAL;			break;		}		MGC_SelectEnd(pBase, bEnd);		if (is_in)			tmp = musb_readw(regs, MGC_O_HDRC_TXCSR)						& MGC_M_TXCSR_P_SENDSTALL;		else			tmp = musb_readw(regs, MGC_O_HDRC_RXCSR)						& MGC_M_RXCSR_P_SENDSTALL;		MGC_SelectEnd(pBase, 0);		bResult[0] = tmp ? 1 : 0;		} break;	default:		/* class, vendor, etc ... delegate */		handled = 0;		break;	}	/* fill up the fifo; caller updates csr0 */	if (handled > 0) {		u16	len = le16_to_cpu(pControlRequest->wLength);		if (len > 2)			len = 2;		musb_write_fifo(&musb->aLocalEnd[0], len, bResult);	}	return handled;}/* * handle a control-IN request, the end0 buffer contains the current request * that is supposed to be a standard control request. Assumes the fifo to * be at least 2 bytes long. * * @return 0 if the request was NOT HANDLED, * < 0 when error * > 0 when the request is processed * * Context:  caller holds controller lock */static intservice_in_request(struct musb *musb,		const struct usb_ctrlrequest *pControlRequest){	int handled = 0;	/* not handled */	if ((pControlRequest->bRequestType & USB_TYPE_MASK)			== USB_TYPE_STANDARD) {		switch (pControlRequest->bRequest) {		case USB_REQ_GET_STATUS:			handled = service_tx_status_request(musb,					pControlRequest);			break;		/* case USB_REQ_SYNC_FRAME: */		default:			break;		}	}	return handled;}/* * Context:  caller holds controller lock */static void musb_g_ep0_giveback(struct musb *musb, struct usb_request *req){	musb->ep0_state = MGC_END0_STAGE_SETUP;	musb_g_giveback(&musb->aLocalEnd[0].ep_in, req, 0);}/* * Tries to start B-device HNP negotiation if enabled via sysfs */static inline void musb_try_b_hnp_enable(struct musb *musb){	void __iomem	*pBase = musb->pRegs;	u8		devctl;	DBG(1, "HNP: Setting HR\n");	devctl = musb_readb(pBase, MGC_O_HDRC_DEVCTL);	musb_writeb(pBase, MGC_O_HDRC_DEVCTL, devctl | MGC_M_DEVCTL_HR);}/* * Handle all control requests with no DATA stage, including standard * requests such as: * USB_REQ_SET_CONFIGURATION, USB_REQ_SET_INTERFACE, unrecognized *	always delegated to the gadget driver * USB_REQ_SET_ADDRESS, USB_REQ_CLEAR_FEATURE, USB_REQ_SET_FEATURE *	always handled here, except for class/vendor/... features * * Context:  caller holds controller lock */static intservice_zero_data_request(struct musb *musb,		struct usb_ctrlrequest *pControlRequest)__releases(musb->Lock)__acquires(musb->Lock){	int handled = -EINVAL;	void __iomem *pBase = musb->pRegs;	const u8 bRecip = pControlRequest->bRequestType & USB_RECIP_MASK;	/* the gadget driver handles everything except what we MUST handle */	if ((pControlRequest->bRequestType & USB_TYPE_MASK)			== USB_TYPE_STANDARD) {		switch (pControlRequest->bRequest) {		case USB_REQ_SET_ADDRESS:			/* change it after the status stage */			musb->bSetAddress = TRUE;			musb->bAddress = (u8) (pControlRequest->wValue & 0x7f);			handled = 1;			break;		case USB_REQ_CLEAR_FEATURE:			switch (bRecip) {			case USB_RECIP_DEVICE:				if (pControlRequest->wValue						!= USB_DEVICE_REMOTE_WAKEUP)					break;				musb->may_wakeup = 0;				handled = 1;				break;			case USB_RECIP_INTERFACE:				break;			case USB_RECIP_ENDPOINT:{				const u8 bEnd = pControlRequest->wIndex & 0x0f;				struct musb_ep *pEnd;				if (bEnd == 0						|| bEnd >= MUSB_C_NUM_EPS						|| pControlRequest->wValue							!= USB_ENDPOINT_HALT)					break;				if (pControlRequest->wIndex & USB_DIR_IN)					pEnd = &musb->aLocalEnd[bEnd].ep_in;				else					pEnd = &musb->aLocalEnd[bEnd].ep_out;				if (!pEnd->desc)					break;				/* REVISIT do it directly, no locking games */				spin_unlock(&musb->Lock);				musb_gadget_set_halt(&pEnd->end_point, 0);				spin_lock(&musb->Lock);				/* select ep0 again */				MGC_SelectEnd(pBase, 0);				handled = 1;				} break;			default:				/* class, vendor, etc ... delegate */				handled = 0;				break;			}			break;		case USB_REQ_SET_FEATURE:			switch (bRecip) {			case USB_RECIP_DEVICE:				handled = 1;				switch (pControlRequest->wValue) {				case USB_DEVICE_REMOTE_WAKEUP:					musb->may_wakeup = 1;					break;				case USB_DEVICE_TEST_MODE:					if (musb->g.speed != USB_SPEED_HIGH)						goto stall;					if (pControlRequest->wIndex & 0xff)						goto stall;					switch (pControlRequest->wIndex >> 8) {					case 1:						pr_debug("TEST_J\n");						/* TEST_J */						musb->bTestModeValue =							MGC_M_TEST_J;						break;					case 2:						/* TEST_K */						pr_debug("TEST_K\n");						musb->bTestModeValue =							MGC_M_TEST_K;						break;					case 3:						/* TEST_SE0_NAK */						pr_debug("TEST_SE0_NAK\n");						musb->bTestModeValue =							MGC_M_TEST_SE0_NAK;						break;					case 4:						/* TEST_PACKET */						pr_debug("TEST_PACKET\n");						musb->bTestModeValue =							MGC_M_TEST_PACKET;						break;					default:						goto stall;					}					/* enter test mode after irq */					if (handled > 0)						musb->bTestMode = TRUE;					break;				case USB_DEVICE_B_HNP_ENABLE:					if (!musb->g.is_otg)						goto stall;					musb->g.b_hnp_enable = 1;					musb_try_b_hnp_enable(musb);					break;				case USB_DEVICE_A_HNP_SUPPORT:					if (!musb->g.is_otg)						goto stall;					musb->g.a_hnp_support = 1;					break;				case USB_DEVICE_A_ALT_HNP_SUPPORT:					if (!musb->g.is_otg)						goto stall;					musb->g.a_alt_hnp_support = 1;					break;stall:				default:					handled = -EINVAL;					break;				}				break;			case USB_RECIP_INTERFACE:				break;			case USB_RECIP_ENDPOINT:{				const u8		bEnd =					pControlRequest->wIndex & 0x0f;				struct musb_ep		*pEnd;				struct musb_hw_ep	*ep;				void __iomem		*regs;				int			is_in;				u16			csr;				if (bEnd == 0						|| bEnd >= MUSB_C_NUM_EPS						|| pControlRequest->wValue							!= USB_ENDPOINT_HALT)					break;				ep = musb->aLocalEnd + bEnd;				regs = ep->regs;				is_in = pControlRequest->wIndex & USB_DIR_IN;				if (is_in)					pEnd = &ep->ep_in;				else					pEnd = &ep->ep_out;				if (!pEnd->desc)					break;				MGC_SelectEnd(pBase, bEnd);				if (is_in) {					csr = musb_readw(regs,							MGC_O_HDRC_TXCSR);					if (csr & MGC_M_TXCSR_FIFONOTEMPTY)						csr |= MGC_M_TXCSR_FLUSHFIFO;					csr |= MGC_M_TXCSR_P_SENDSTALL						| MGC_M_TXCSR_CLRDATATOG						| MGC_M_TXCSR_P_WZC_BITS;					musb_writew(regs, MGC_O_HDRC_TXCSR,							csr);				} else {					csr = musb_readw(regs,							MGC_O_HDRC_RXCSR);					csr |= MGC_M_RXCSR_P_SENDSTALL						| MGC_M_RXCSR_FLUSHFIFO						| MGC_M_RXCSR_CLRDATATOG						| MGC_M_TXCSR_P_WZC_BITS;					musb_writew(regs, MGC_O_HDRC_RXCSR,							csr);				}				/* select ep0 again */				MGC_SelectEnd(pBase, 0);				handled = 1;				} break;			default:				/* class, vendor, etc ... delegate */				handled = 0;				break;			}			break;		default:			/* delegate SET_CONFIGURATION, etc */			handled = 0;		}	} else		handled = 0;	return handled;}/* we have an ep0out data packet * Context:  caller holds controller lock */static void ep0_rxstate(struct musb *this){	void __iomem		*regs = this->control_ep->regs;	struct usb_request	*req;	u16			tmp;	req = next_ep0_request(this);	/* read packet and ack; or stall because of gadget driver bug:	 * should have provided the rx buffer before setup() returned.	 */	if (req) {		void		*buf = req->buf + req->actual;		unsigned	len = req->length - req->actual;		/* read the buffer */		tmp = musb_readb(regs, MGC_O_HDRC_COUNT0);		if (tmp > len) {			req->status = -EOVERFLOW;			tmp = len;		}		musb_read_fifo(&this->aLocalEnd[0], tmp, buf);		req->actual += tmp;		tmp = MGC_M_CSR0_P_SVDRXPKTRDY;		if (tmp < 64 || req->actual == req->length) {			this->ep0_state = MGC_END0_STAGE_STATUSIN;			tmp |= MGC_M_CSR0_P_DATAEND;		} else			req = NULL;	} else		tmp = MGC_M_CSR0_P_SVDRXPKTRDY | MGC_M_CSR0_P_SENDSTALL;	musb_writew(regs, MGC_O_HDRC_CSR0, tmp);	/* NOTE:  we "should" hold off reporting DATAEND and going to	 * STATUSIN until after the completion handler decides whether	 * to issue a stall instead, since this hardware can do that.	 */	if (req)		musb_g_ep0_giveback(this, req);}/* * transmitting to the host (IN), this code might be called from IRQ * and from kernel thread. * * Context:  caller holds controller lock */static void ep0_txstate(struct musb *musb){	void __iomem		*regs = musb->control_ep->regs;	struct usb_request	*pRequest = next_ep0_request(musb);	u16			wCsrVal = MGC_M_CSR0_TXPKTRDY;	u8			*pFifoSource;	u8			wFifoCount;	if (!pRequest) {		// WARN_ON(1);		DBG(2, "odd; csr0 %04x\n", musb_readw(regs, MGC_O_HDRC_CSR0));		return;

⌨️ 快捷键说明

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