📄 usbdcore_omap1510.c
字号:
/* * (C) Copyright 2003 * Gerry Hamel, geh@ti.com, Texas Instruments * * Based on * linux/drivers/usb/device/bi/omap.c * TI OMAP1510 USB bus interface driver * * Author: MontaVista Software, Inc. * source@mvista.com * (C) Copyright 2002 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */#include <common.h>#if defined(CONFIG_OMAP1510) && defined(CONFIG_USB_DEVICE)#include <asm/io.h>#ifdef CONFIG_OMAP_SX1#include <i2c.h>#endif#include "usbdcore.h"#include "usbdcore_omap1510.h"#include "usbdcore_ep0.h"#define UDC_INIT_MDELAY 80 /* Device settle delay */#define UDC_MAX_ENDPOINTS 31 /* Number of endpoints on this UDC *//* Some kind of debugging output... */#if 1#define UDCDBG(str)#define UDCDBGA(fmt,args...)#else /* The bugs still exists... */#define UDCDBG(str) serial_printf("[%s] %s:%d: " str "\n", __FILE__,__FUNCTION__,__LINE__)#define UDCDBGA(fmt,args...) serial_printf("[%s] %s:%d: " fmt "\n", __FILE__,__FUNCTION__,__LINE__, ##args)#endif#if 1#define UDCREG(name)#define UDCREGL(name)#else /* The bugs still exists... */#define UDCREG(name) serial_printf("%s():%d: %s[%08x]=%.4x\n",__FUNCTION__,__LINE__, (#name), name, inw(name)) /* For 16-bit regs */#define UDCREGL(name) serial_printf("%s():%d: %s[%08x]=%.8x\n",__FUNCTION__,__LINE__, (#name), name, inl(name)) /* For 32-bit regs */#endifstatic struct urb *ep0_urb = NULL;static struct usb_device_instance *udc_device; /* Used in interrupt handler */static u16 udc_devstat = 0; /* UDC status (DEVSTAT) */static u32 udc_interrupts = 0;static void udc_stall_ep (unsigned int ep_addr);static struct usb_endpoint_instance *omap1510_find_ep (int ep){ int i; for (i = 0; i < udc_device->bus->max_endpoints; i++) { if (udc_device->bus->endpoint_array[i].endpoint_address == ep) return &udc_device->bus->endpoint_array[i]; } return NULL;}/* ************************************************************************** *//* IO *//* * omap1510_prepare_endpoint_for_rx * * This function implements TRM Figure 14-11. * * The endpoint to prepare for transfer is specified as a physical endpoint * number. For OUT (rx) endpoints 1 through 15, the corresponding endpoint * configuration register is checked to see if the endpoint is ISO or not. * If the OUT endpoint is valid and is non-ISO then its FIFO is enabled. * No action is taken for endpoint 0 or for IN (tx) endpoints 16 through 30. */static void omap1510_prepare_endpoint_for_rx (int ep_addr){ int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK; UDCDBGA ("omap1510_prepare_endpoint %x", ep_addr); if (((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)) { if ((inw (UDC_EP_RX (ep_num)) & (UDC_EPn_RX_Valid | UDC_EPn_RX_Iso)) == UDC_EPn_RX_Valid) { /* rx endpoint is valid, non-ISO, so enable its FIFO */ outw (UDC_EP_Sel | ep_num, UDC_EP_NUM); outw (UDC_Set_FIFO_En, UDC_CTRL); outw (0, UDC_EP_NUM); } }}/* omap1510_configure_endpoints * * This function implements TRM Figure 14-10. */static void omap1510_configure_endpoints (struct usb_device_instance *device){ int ep; struct usb_bus_instance *bus; struct usb_endpoint_instance *endpoint; unsigned short ep_ptr; unsigned short ep_size; unsigned short ep_isoc; unsigned short ep_doublebuffer; int ep_addr; int packet_size; int buffer_size; int attributes; bus = device->bus; /* There is a dedicated 2048 byte buffer for USB packets that may be * arbitrarily partitioned among the endpoints on 8-byte boundaries. * The first 8 bytes are reserved for receiving setup packets on * endpoint 0. */ ep_ptr = 8; /* reserve the first 8 bytes for the setup fifo */ for (ep = 0; ep < bus->max_endpoints; ep++) { endpoint = bus->endpoint_array + ep; ep_addr = endpoint->endpoint_address; if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { /* IN endpoint */ packet_size = endpoint->tx_packetSize; attributes = endpoint->tx_attributes; } else { /* OUT endpoint */ packet_size = endpoint->rcv_packetSize; attributes = endpoint->rcv_attributes; } switch (packet_size) { case 0: ep_size = 0; break; case 8: ep_size = 0; break; case 16: ep_size = 1; break; case 32: ep_size = 2; break; case 64: ep_size = 3; break; case 128: ep_size = 4; break; case 256: ep_size = 5; break; case 512: ep_size = 6; break; default: UDCDBGA ("ep 0x%02x has bad packet size %d", ep_addr, packet_size); packet_size = 0; ep_size = 0; break; } switch (attributes & USB_ENDPOINT_XFERTYPE_MASK) { case USB_ENDPOINT_XFER_CONTROL: case USB_ENDPOINT_XFER_BULK: case USB_ENDPOINT_XFER_INT: default: /* A non-isochronous endpoint may optionally be * double-buffered. For now we disable * double-buffering. */ ep_doublebuffer = 0; ep_isoc = 0; if (packet_size > 64) packet_size = 0; if (!ep || !ep_doublebuffer) buffer_size = packet_size; else buffer_size = packet_size * 2; break; case USB_ENDPOINT_XFER_ISOC: /* Isochronous endpoints are always double- * buffered, but the double-buffering bit * in the endpoint configuration register * becomes the msb of the endpoint size so we * set the double-buffering flag to zero. */ ep_doublebuffer = 0; ep_isoc = 1; buffer_size = packet_size * 2; break; } /* check to see if our packet buffer RAM is exhausted */ if ((ep_ptr + buffer_size) > 2048) { UDCDBGA ("out of packet RAM for ep 0x%02x buf size %d", ep_addr, buffer_size); buffer_size = packet_size = 0; } /* force a default configuration for endpoint 0 since it is * always enabled */ if (!ep && ((packet_size < 8) || (packet_size > 64))) { buffer_size = packet_size = 64; ep_size = 3; } if (!ep) { /* configure endpoint 0 */ outw ((ep_size << 12) | (ep_ptr >> 3), UDC_EP0); /*UDCDBGA("ep 0 buffer offset 0x%03x packet size 0x%03x", */ /* ep_ptr, packet_size); */ } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { /* IN endpoint */ if (packet_size) { outw ((1 << 15) | (ep_doublebuffer << 14) | (ep_size << 12) | (ep_isoc << 11) | (ep_ptr >> 3), UDC_EP_TX (ep_addr & USB_ENDPOINT_NUMBER_MASK)); UDCDBGA ("IN ep %d buffer offset 0x%03x" " packet size 0x%03x", ep_addr & USB_ENDPOINT_NUMBER_MASK, ep_ptr, packet_size); } else { outw (0, UDC_EP_TX (ep_addr & USB_ENDPOINT_NUMBER_MASK)); } } else { /* OUT endpoint */ if (packet_size) { outw ((1 << 15) | (ep_doublebuffer << 14) | (ep_size << 12) | (ep_isoc << 11) | (ep_ptr >> 3), UDC_EP_RX (ep_addr & USB_ENDPOINT_NUMBER_MASK)); UDCDBGA ("OUT ep %d buffer offset 0x%03x" " packet size 0x%03x", ep_addr & USB_ENDPOINT_NUMBER_MASK, ep_ptr, packet_size); } else { outw (0, UDC_EP_RX (ep_addr & USB_ENDPOINT_NUMBER_MASK)); } } ep_ptr += buffer_size; }}/* omap1510_deconfigure_device * * This function balances omap1510_configure_device. */static void omap1510_deconfigure_device (void){ int epnum; UDCDBG ("clear Cfg_Lock"); outw (inw (UDC_SYSCON1) & ~UDC_Cfg_Lock, UDC_SYSCON1); UDCREG (UDC_SYSCON1); /* deconfigure all endpoints */ for (epnum = 1; epnum <= 15; epnum++) { outw (0, UDC_EP_RX (epnum)); outw (0, UDC_EP_TX (epnum)); }}/* omap1510_configure_device * * This function implements TRM Figure 14-9. */static void omap1510_configure_device (struct usb_device_instance *device){ omap1510_configure_endpoints (device); /* Figure 14-9 indicates we should enable interrupts here, but we have * other routines (udc_all_interrupts, udc_suspended_interrupts) to * do that. */ UDCDBG ("set Cfg_Lock"); outw (inw (UDC_SYSCON1) | UDC_Cfg_Lock, UDC_SYSCON1); UDCREG (UDC_SYSCON1);}/* omap1510_write_noniso_tx_fifo * * This function implements TRM Figure 14-30. * * If the endpoint has an active tx_urb, then the next packet of data from the * URB is written to the tx FIFO. The total amount of data in the urb is given * by urb->actual_length. The maximum amount of data that can be sent in any * one packet is given by endpoint->tx_packetSize. The number of data bytes * from this URB that have already been transmitted is given by endpoint->sent. * endpoint->last is updated by this routine with the number of data bytes * transmitted in this packet. * * In accordance with Figure 14-30, the EP_NUM register must already have been * written with the value to select the appropriate tx FIFO before this routine * is called. */static void omap1510_write_noniso_tx_fifo (struct usb_endpoint_instance *endpoint){ struct urb *urb = endpoint->tx_urb; if (urb) { unsigned int last, i; UDCDBGA ("urb->buffer %p, buffer_length %d, actual_length %d", urb->buffer, urb->buffer_length, urb->actual_length); if ((last = MIN (urb->actual_length - endpoint->sent, endpoint->tx_packetSize))) { u8 *cp = urb->buffer + endpoint->sent; UDCDBGA ("endpoint->sent %d, tx_packetSize %d, last %d", endpoint->sent, endpoint->tx_packetSize, last); if (((u32) cp & 1) == 0) { /* word aligned? */ outsw (UDC_DATA, cp, last >> 1); } else { /* byte aligned. */ for (i = 0; i < (last >> 1); i++) { u16 w = ((u16) cp[2 * i + 1] << 8) | (u16) cp[2 * i]; outw (w, UDC_DATA); } } if (last & 1) { outb (*(cp + last - 1), UDC_DATA); } } endpoint->last = last; }}/* omap1510_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 int omap1510_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;}/* omap1510_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 void omap1510_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 void udc_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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -