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

📄 omap.c

📁 Linux2.4.20针对三星公司的s3c2440内核基础上的一些设备驱动代码
💻 C
📖 第 1 页 / 共 4 页
字号:
}/* omap_read_noniso_rx_fifo * * This function implements TRM Figure 14-28. * * If the endpoint has an active rcv_urb, then the next packet of data is read  * from the rcv FIFO and written to rcv_urb->buffer at offset  * rcv_urb->actual_length to append the packet data to the data from any  * previous packets for this transfer.  We assume that there is sufficient room * left in the buffer to hold an entire packet of data. * * The return value is the number of bytes read from the FIFO for this packet. * * In accordance with Figure 14-28, the EP_NUM register must already have been * written with the value to select the appropriate rcv FIFO before this routine * is called. */static intomap_read_noniso_rx_fifo(struct usb_endpoint_instance *endpoint){	struct urb *urb = endpoint->rcv_urb;	int len = 0;	if (urb) {		len = inw(UDC_RXFSTAT);		if (len) {			unsigned char *cp = urb->buffer + urb->actual_length;			insw(UDC_DATA, cp, len >> 1);			if (len & 1)				*(cp + len - 1) = inb(UDC_DATA);		}	}	return len;}/* omap_prepare_for_control_write_status * * This function implements TRM Figure 14-17. * * We have to deal here with non-autodecoded control writes that haven't already * been dealt with by ep0_recv_setup.  The non-autodecoded standard control  * write requests are:  set/clear endpoint feature, set configuration, set * interface, and set descriptor.  ep0_recv_setup handles set/clear requests for  * ENDPOINT_HALT by halting the endpoint for a set request and resetting the  * endpoint for a clear request.  ep0_recv_setup returns an error for  * SET_DESCRIPTOR requests which causes them to be terminated with a stall by * the setup handler.  A SET_INTERFACE request is handled by ep0_recv_setup by  * generating a DEVICE_SET_INTERFACE event.  This leaves only the  * SET_CONFIGURATION event for us to deal with here. * */static voidomap_prepare_for_control_write_status(struct urb *urb){	struct usb_device_request *request = &urb->device_request;;	/* check for a SET_CONFIGURATION request */	if (request->bRequest == USB_REQ_SET_CONFIGURATION) {		int configuration = le16_to_cpu(request->wValue) & 0xff;		unsigned short devstat = inw(UDC_DEVSTAT);		if ((devstat & (UDC_ADD | UDC_CFG)) == UDC_ADD) {			/* device is currently in ADDRESSED state */			if (configuration) {				/* Assume the specified non-zero configuration				 * value is valid and switch to the CONFIGURED 				 * state.				 */				outw(UDC_Dev_Cfg, UDC_SYSCON2);			}		} else if ((devstat & UDC_CFG) == UDC_CFG) {			/* device is currently in CONFIGURED state */			if (!configuration) {				/* Switch to ADDRESSED state. */				outw(UDC_Clr_Cfg, UDC_SYSCON2);			}		}	}	/* select EP0 tx FIFO */	outw(UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM);	/* clear endpoint (no data bytes in status stage) */	outw(UDC_Clr_EP, UDC_CTRL);	/* enable the EP0 tx FIFO */	outw(UDC_Set_FIFO_En, UDC_CTRL);	/* deselect the endpoint */	outw(UDC_EP_Dir, UDC_EP_NUM);}/* udc_state_transition_up * udc_state_transition_down * * Helper functions to implement device state changes.  The device states and * the events that transition between them are: * *				STATE_ATTACHED *				||	/\ *				\/	|| *	DEVICE_HUB_CONFIGURED			DEVICE_HUB_RESET *				||	/\ *				\/	|| *				STATE_POWERED *				||	/\ *				\/	|| *	DEVICE_RESET				DEVICE_POWER_INTERRUPTION *				||	/\ *				\/	|| *				STATE_DEFAULT *				||	/\ *				\/	|| *	DEVICE_ADDRESS_ASSIGNED			DEVICE_RESET *				||	/\ *				\/	|| *				STATE_ADDRESSED *				||	/\ *				\/	|| *	DEVICE_CONFIGURED			DEVICE_DE_CONFIGURED *				||	/\ *				\/	|| *				STATE_CONFIGURED * * udc_state_transition_up transitions up (in the direction from STATE_ATTACHED * to STATE_CONFIGURED) from the specified initial state to the specified final * state, passing through each intermediate state on the way.  If the initial * state is at or above (i.e. nearer to STATE_CONFIGURED) the final state, then * no state transitions will take place. * * udc_state_transition_down transitions down (in the direction from  * STATE_CONFIGURED to STATE_ATTACHED) from the specified initial state to the  * specified final state, passing through each intermediate state on the way.   * If the initial state is at or below (i.e. nearer to STATE_ATTACHED) the final  * state, then no state transitions will take place. * * These functions must only be called with interrupts disabled. */static voidudc_state_transition_up(usb_device_state_t initial, usb_device_state_t final){	if (initial < final) {		switch (initial) {		case STATE_ATTACHED:			usbd_device_event_irq(udc_device,					      DEVICE_HUB_CONFIGURED, 0);			if (final == STATE_POWERED)				break;		case STATE_POWERED:			usbd_device_event_irq(udc_device, DEVICE_RESET, 0);			if (final == STATE_DEFAULT)				break;		case STATE_DEFAULT:			usbd_device_event_irq(udc_device,					      DEVICE_ADDRESS_ASSIGNED, 0);			if (final == STATE_ADDRESSED)				break;		case STATE_ADDRESSED:			usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0);		case STATE_CONFIGURED:			break;		default:			break;		}	}}static voidudc_state_transition_down(usb_device_state_t initial, usb_device_state_t final){	if (initial > final) {		switch (initial) {		case STATE_CONFIGURED:			usbd_device_event_irq(udc_device,					      DEVICE_DE_CONFIGURED, 0);			if (final == STATE_ADDRESSED)				break;		case STATE_ADDRESSED:			usbd_device_event_irq(udc_device, DEVICE_RESET, 0);			if (final == STATE_DEFAULT)				break;		case STATE_DEFAULT:			usbd_device_event_irq(udc_device,					      DEVICE_POWER_INTERRUPTION, 0);			if (final == STATE_POWERED)				break;		case STATE_POWERED:			usbd_device_event_irq(udc_device, DEVICE_HUB_RESET, 0);		case STATE_ATTACHED:			break;		default:			break;		}	}}/* Handle all device state changes. * This function implements TRM Figure 14-21. */static voidomap_udc_state_changed(void){	u16 bits;	u16 devstat = inw(UDC_DEVSTAT);	UDCDBG("state changed, devstat %x, old %x", devstat, udc_devstat);	bits = devstat ^ udc_devstat;	if (bits) {		if (bits & UDC_ATT) {			if (devstat & UDC_ATT) {				UDCDBG("device attached and powered");				udc_state_transition_up(udc_device->							device_state,							STATE_POWERED);			} else {				UDCDBG("device detached or unpowered");				udc_state_transition_down(udc_device->							  device_state,							  STATE_ATTACHED);			}		}		if (bits & UDC_USB_Reset) {			if (devstat & UDC_USB_Reset) {				UDCDBG("device reset in progess");				udc_state_transition_down(udc_device->							  device_state,							  STATE_POWERED);			} else {				UDCDBG("device reset completed");			}		}		if (bits & UDC_DEF) {			if (devstat & UDC_DEF) {				UDCDBG("device entering default state");				udc_state_transition_up(udc_device->							device_state,							STATE_DEFAULT);			} else {				UDCDBG("device leaving default state");				udc_state_transition_down(udc_device->							  device_state,							  STATE_POWERED);			}		}		if (bits & UDC_SUS) {			if (devstat & UDC_SUS) {				UDCDBG("entering suspended state");				usbd_device_event_irq(udc_device,						      DEVICE_BUS_INACTIVE, 0);			} else {				UDCDBG("leaving suspended state");				usbd_device_event_irq(udc_device,						      DEVICE_BUS_ACTIVITY, 0);			}		}		if (bits & UDC_R_WK_OK) {			UDCDBG("remote wakeup %s", (devstat & UDC_R_WK_OK)			       ? "enabled" : "disabled");		}		if (bits & UDC_ADD) {			if (devstat & UDC_ADD) {				UDCDBG("default -> addressed");				udc_state_transition_up(udc_device->							device_state,							STATE_ADDRESSED);			} else {				UDCDBG("addressed -> default");				udc_state_transition_down(udc_device->							  device_state,							  STATE_DEFAULT);			}		}		if (bits & UDC_CFG) {			if (devstat & UDC_CFG) {				UDCDBG("device configured");				/* The ep0_recv_setup function generates the				 * DEVICE_CONFIGURED event when a				 * USB_REQ_SET_CONFIGURATION setup packet is				 * received, so we should already be in the				 * state STATE_CONFIGURED.				 */				udc_state_transition_up(udc_device->							device_state,							STATE_CONFIGURED);			} else {				UDCDBG("device deconfigured");				udc_state_transition_down(udc_device->							  device_state,							  STATE_ADDRESSED);			}		}	}	/* Clear interrupt source */	outw(UDC_DS_Chg, UDC_IRQ_SRC);	/* Save current DEVSTAT */	udc_devstat = devstat;}/* Handle SETUP USB interrupt. * This function implements TRM Figure 14-14. */static voidomap_udc_setup(struct usb_endpoint_instance *endpoint){	UDCDBG("-> Entering device setup");	do {		const int setup_pktsize = 8;		unsigned char *datap =		    (unsigned char *) &ep0_urb->device_request;		/* Gain access to EP 0 setup FIFO */		outw(UDC_Setup_Sel, UDC_EP_NUM);		/* Read control request data */		insb(UDC_DATA, datap, setup_pktsize);		UDCDBG("EP0 setup read [%x %x %x %x %x %x %x %x]",		       *(datap + 0), *(datap + 1), *(datap + 2), *(datap + 3),		       *(datap + 4), *(datap + 5), *(datap + 6), *(datap + 7));		/* Reset EP0 setup FIFO */		outw(0, UDC_EP_NUM);	} while (inw(UDC_IRQ_SRC) & UDC_Setup);	/* Try to process setup packet */	if (usbd_recv_setup(ep0_urb)) {		/* Not a setup packet, stall next EP0 transaction */		udc_stall_ep(0);		UDCDBG("can't parse setup packet, still waiting for setup");		return;	}	/* Check direction */	if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK)	    == USB_REQ_HOST2DEVICE) {		UDCDBG("control write on EP0");		if (le16_to_cpu(ep0_urb->device_request.wLength)) {			/* We don't support control write data stages.			 * The only standard control write request with a data			 * stage is SET_DESCRIPTOR, and ep0_recv_setup doesn't			 * support that so we just stall those requests.  A 			 * function driver might support a non-standard 			 * write request with a data stage, but it isn't 			 * obvious what we would do with the data if we read it 			 * so we'll just stall it.  It seems like the API isn't 			 * quite right here.			 */#if 0			/* Here is what we would do if we did support control 			 * write data stages.			 */			ep0_urb->actual_length = 0;			outw(0, UDC_EP_NUM);			/* enable the EP0 rx FIFO */			outw(UDC_Set_FIFO_En, UDC_CTRL);#else			/* Stall this request */			UDCDBG("Stalling unsupported EP0 control write data "			       "stage.");			udc_stall_ep(0);#endif		} else {			omap_prepare_for_control_write_status(ep0_urb);		}	} else {		UDCDBG("control read on EP0");		/* The ep0_recv_setup function has already placed our response		 * packet data in ep0_urb->buffer and the packet length in 		 * ep0_urb->actual_length.		 */		endpoint->tx_urb = ep0_urb;		endpoint->sent = 0;		/* select the EP0 tx FIFO */		outw(UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM);		/* Write packet data to the FIFO.  omap_write_noniso_tx_fifo		 * will update endpoint->last with the number of bytes written 		 * to the FIFO.		 */		omap_write_noniso_tx_fifo(endpoint);		/* enable the FIFO to start the packet transmission */		outw(UDC_Set_FIFO_En, UDC_CTRL);		/* deselect the EP0 tx FIFO */		outw(UDC_EP_Dir, UDC_EP_NUM);	}	UDCDBG("<- Leaving device setup");}/* Handle endpoint 0 RX interrupt * This routine implements TRM Figure 14-16. */static voidomap_udc_ep0_rx(struct usb_endpoint_instance *endpoint){	unsigned short status;	UDCDBG("RX on EP0");	/* select EP0 rx FIFO */	outw(UDC_EP_Sel, UDC_EP_NUM);	status = inw(UDC_STAT_FLG);	if (status & UDC_ACK) {		/* Check direction */		if ((ep0_urb->device_request.bmRequestType		     & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) {			/* This rx interrupt must be for a control write data			 * stage packet.			 *			 * We don't support control write data stages.			 * We should never end up here.			 */			/* clear the EP0 rx FIFO */			outw(UDC_Clr_EP, UDC_CTRL);			/* deselect the EP0 rx FIFO */			outw(0, UDC_EP_NUM);			UDCDBG("Stalling unexpected EP0 control write "			       "data stage packet");			udc_stall_ep(0);		} else {			/* This rx interrupt must be for a control read status 			 * stage packet.			 */			UDCDBG("ACK on EP0 control read status stage packet");			/* deselect EP0 rx FIFO */			outw(0, UDC_EP_NUM);		}	} else if (status & UDC_STALL) {		UDCDBG("EP0 stall during RX");		/* deselect EP0 rx FIFO */		outw(0, UDC_EP_NUM);	} else {		/* deselect EP0 rx FIFO */		outw(0, UDC_EP_NUM);	}}/* Handle endpoint 0 TX interrupt * This routine implements TRM Figure 14-18. */static voidomap_udc_ep0_tx(struct usb_endpoint_instance *endpoint){	unsigned short status;	struct usb_device_request *request = &ep0_urb->device_request;	UDCDBG("TX on EP0");	/* select EP0 TX FIFO */	outw(UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM);	status = inw(UDC_STAT_FLG);	if (status & UDC_ACK) {		/* Check direction */		if ((request->bmRequestType & USB_REQ_DIRECTION_MASK)		    == USB_REQ_HOST2DEVICE) {			/* This tx interrupt must be for a control write status 			 * stage packet.			 */			UDCDBG("ACK on EP0 control write status stage packet");			/* deselect EP0 TX FIFO */			outw(UDC_EP_Dir, UDC_EP_NUM);		} else {			/* This tx interrupt must be for a control read data 			 * stage packet.			 */			int wLength = le16_to_cpu(request->wLength);			/* Update our count of bytes sent so far in this			 * transfer.			 */			endpoint->sent += endpoint->last;			/* We are finished with this transfer if we have sent 			 * all of the bytes in our tx urb (urb->actual_length)			 * unless we need a zero-length terminating packet.  We 			 * need a zero-length terminating packet if we returned 			 * fewer bytes than were requested (wLength) by the host,			 * and the number of bytes we returned is an exact			 * multiple of the packet size endpoint->tx_packetSize.			 */			if ((endpoint->sent == ep0_urb->actual_length)			    && ((ep0_urb->actual_length == wLength)				|| (endpoint->last != endpoint->tx_packetSize))) {				/* Done with control read data stage. */				UDCDBG("control read data stage complete");				/* deselect EP0 TX FIFO */				outw(UDC_EP_Dir, UDC_EP_NUM);				/* select EP0 RX FIFO to prepare for control				 * read status stage.				 */				outw(UDC_EP_Sel, UDC_EP_NUM);				/* clear the EP0 RX FIFO */				outw(UDC_Clr_EP, UDC_CTRL);				/* enable the EP0 RX FIFO */				outw(UDC_Set_FIFO_En, UDC_CTRL);				/* deselect the EP0 RX FIFO */				outw(0, UDC_EP_NUM);			} else {				/* We still have another packet of data to send 				 * in this control read data stage or else we 				 * need a zero-length terminating packet.				 */				UDCDBG("ACK control read data stage packet");				omap_write_noniso_tx_fifo(endpoint);				/* enable the EP0 tx FIFO to start transmission */				outw(UDC_Set_FIFO_En, UDC_CTRL);				/* deselect EP0 TX FIFO */				outw(UDC_EP_Dir, UDC_EP_NUM);			}		}	} else if (status & UDC_STALL) {		UDCDBG("EP0 stall during TX");		/* deselect EP0 TX FIFO */		outw(UDC_EP_Dir, UDC_EP_NUM);	} else {		/* deselect EP0 TX FIFO */		outw(UDC_EP_Dir, UDC_EP_NUM);	}}/* Handle RX transaction on non-ISO endpoint. * This function implements TRM Figure 14-27. * The ep argument is a physical endpoint number for a non-ISO OUT endpoint * in the range 1 to 15.

⌨️ 快捷键说明

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