summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorWolfgang Denk <wd@pollux.denx.de>2006-06-14 15:45:53 (GMT)
committerWolfgang Denk <wd@pollux.denx.de>2006-06-14 15:45:53 (GMT)
commit16c8d5e76ae0f78f39a60608574adfe0feb9cc70 (patch)
tree3b5d071b5fd9f34044ff154437f92149edf6105f /drivers
parent81d72d7e2e7996c6c4e60985dbcc84afe5ed816c (diff)
downloadu-boot-16c8d5e76ae0f78f39a60608574adfe0feb9cc70.tar.xz
Various USB related patches
- Add support for mpc8xx USB device. - Add support for Common Device Class - Abstract Control Model USB console. - Add support for flow control in USB slave devices. - Add support for switching between gserial and cdc_acm using environment. - Minor changes to usbdcore_omap1510.c usbdcore_omap1510.h - Update usbcore slightly to ease host enumeration. - Fix non-portable endian problems in usbdcore and usbdcore_ep0. - Add AdderUSB_config as a defconfig to enable usage of the USB console by default with the Adder87x U-Boot port. Patches by Bryan O'Donoghue <bodonoghue@codehermit.ie>, 29 May 2006
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/usbdcore_ep0.c163
-rw-r--r--drivers/usbdcore_mpc8xx.c1412
-rw-r--r--drivers/usbdcore_omap1510.c29
-rw-r--r--drivers/usbtty.c707
-rw-r--r--drivers/usbtty.h60
6 files changed, 2043 insertions, 330 deletions
diff --git a/drivers/Makefile b/drivers/Makefile
index d5b6811..8732e16 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -48,7 +48,7 @@ OBJS = 3c589.o 5701rls.o ali512x.o \
ti_pci1410a.o tigon3.o tsec.o \
usb_ohci.o usbdcore.o usbdcore_ep0.o usbdcore_omap1510.o usbtty.o \
videomodes.o w83c553f.o \
- ks8695eth.o
+ ks8695eth.o usbdcore_mpc8xx.o
all: $(LIB)
diff --git a/drivers/usbdcore_ep0.c b/drivers/usbdcore_ep0.c
index 260befe..5e7443b 100644
--- a/drivers/usbdcore_ep0.c
+++ b/drivers/usbdcore_ep0.c
@@ -2,6 +2,9 @@
* (C) Copyright 2003
* Gerry Hamel, geh@ti.com, Texas Instruments
*
+ * (C) Copyright 2006
+ * Bryan O'Donoghue, deckard@CodeHermit.ie
+ *
* Based on
* linux/drivers/usbd/ep0.c
*
@@ -39,11 +42,17 @@
* function driver. This may need to change.
*
* XXX
+ *
+ * As alluded to above, a simple callback cdc_recv_setup has been implemented
+ * in the usb_device data structure to facilicate passing
+ * Common Device Class packets to a function driver.
+ *
+ * XXX
*/
#include <common.h>
-#if defined(CONFIG_OMAP1510) && defined(CONFIG_USB_DEVICE)
+#if defined(CONFIG_USB_DEVICE)
#include "usbdcore.h"
#if 0
@@ -69,7 +78,7 @@ static int ep0_get_status (struct usb_device_instance *device,
char *cp;
urb->actual_length = 2;
- cp = urb->buffer;
+ cp = (char*)urb->buffer;
cp[0] = cp[1] = 0;
switch (requesttype) {
@@ -115,7 +124,7 @@ static int ep0_get_one (struct usb_device_instance *device, struct urb *urb,
*
* Copy configuration data to urb transfer buffer if there is room for it.
*/
-static void copy_config (struct urb *urb, void *data, int max_length,
+void copy_config (struct urb *urb, void *data, int max_length,
int max_buf)
{
int available;
@@ -128,10 +137,7 @@ static void copy_config (struct urb *urb, void *data, int max_length,
dbg_ep0 (1, "data is NULL");
return;
}
- if (!(length = *(unsigned char *) data)) {
- dbg_ep0 (1, "length is zero");
- return;
- }
+ length = max_length;
if (length > max_length) {
dbg_ep0 (1, "length: %d >= max_length: %d", length,
@@ -192,7 +198,7 @@ static int ep0_get_descriptor (struct usb_device_instance *device,
/* setup tx urb */
urb->actual_length = 0;
- cp = urb->buffer;
+ cp = (char*)urb->buffer;
dbg_ep0 (2, "%s", USBD_DEVICE_DESCRIPTORS (descriptor_type));
@@ -200,7 +206,6 @@ static int ep0_get_descriptor (struct usb_device_instance *device,
case USB_DESCRIPTOR_TYPE_DEVICE:
{
struct usb_device_descriptor *device_descriptor;
-
if (!
(device_descriptor =
usbd_device_device_descriptor (device, port))) {
@@ -214,20 +219,16 @@ static int ep0_get_descriptor (struct usb_device_instance *device,
/* correct the correct control endpoint 0 max packet size into the descriptor */
device_descriptor =
(struct usb_device_descriptor *) urb->buffer;
- device_descriptor->bMaxPacketSize0 =
- urb->device->bus->maxpacketsize;
}
- /*dbg_ep0(3, "copied device configuration, actual_length: %x", urb->actual_length); */
+ dbg_ep0(3, "copied device configuration, actual_length: 0x%x", urb->actual_length);
break;
case USB_DESCRIPTOR_TYPE_CONFIGURATION:
{
- int bNumInterface;
struct usb_configuration_descriptor
*configuration_descriptor;
struct usb_device_descriptor *device_descriptor;
-
if (!
(device_descriptor =
usbd_device_device_descriptor (device, port))) {
@@ -251,130 +252,35 @@ static int ep0_get_descriptor (struct usb_device_instance *device,
index);
return -1;
}
+ dbg_ep0(0, "attempt to copy %d bytes to urb\n",cpu_to_le16(configuration_descriptor->wTotalLength));
copy_config (urb, configuration_descriptor,
- sizeof (struct
- usb_configuration_descriptor),
- max);
-
-
- /* iterate across interfaces for specified configuration */
- dbg_ep0 (0, "bNumInterfaces: %d",
- configuration_descriptor->bNumInterfaces);
- for (bNumInterface = 0;
- bNumInterface <
- configuration_descriptor->bNumInterfaces;
- bNumInterface++) {
- int bAlternateSetting;
- struct usb_interface_instance
- *interface_instance;
-
- dbg_ep0 (3, "[%d] bNumInterfaces: %d",
- bNumInterface,
- configuration_descriptor->bNumInterfaces);
-
- if (! (interface_instance = usbd_device_interface_instance (device,
- port, index, bNumInterface)))
- {
- dbg_ep0 (3, "[%d] interface_instance NULL",
- bNumInterface);
- return -1;
- }
- /* iterate across interface alternates */
- for (bAlternateSetting = 0;
- bAlternateSetting < interface_instance->alternates;
- bAlternateSetting++) {
- /*int class; */
- int bNumEndpoint;
- struct usb_interface_descriptor *interface_descriptor;
-
- struct usb_alternate_instance *alternate_instance;
-
- dbg_ep0 (3, "[%d:%d] alternates: %d",
- bNumInterface,
- bAlternateSetting,
- interface_instance->alternates);
-
- if (! (alternate_instance = usbd_device_alternate_instance (device, port, index, bNumInterface, bAlternateSetting))) {
- dbg_ep0 (3, "[%d] alternate_instance NULL",
- bNumInterface);
- return -1;
- }
- /* copy descriptor for this interface */
- copy_config (urb, alternate_instance->interface_descriptor,
- sizeof (struct usb_interface_descriptor),
- max);
-
- /*dbg_ep0(3, "[%d:%d] classes: %d endpoints: %d", bNumInterface, bAlternateSetting, */
- /* alternate_instance->classes, alternate_instance->endpoints); */
-
- /* iterate across classes for this alternate interface */
-#if 0
- for (class = 0;
- class < alternate_instance->classes;
- class++) {
- struct usb_class_descriptor *class_descriptor;
- /*dbg_ep0(3, "[%d:%d:%d] classes: %d", bNumInterface, bAlternateSetting, */
- /* class, alternate_instance->classes); */
- if (!(class_descriptor = usbd_device_class_descriptor_index (device, port, index, bNumInterface, bAlternateSetting, class))) {
- dbg_ep0 (3, "[%d] class NULL",
- class);
- return -1;
- }
- /* copy descriptor for this class */
- copy_config (urb, class_descriptor,
- sizeof (struct usb_class_descriptor),
- max);
- }
-#endif
-
- /* iterate across endpoints for this alternate interface */
- interface_descriptor = alternate_instance->interface_descriptor;
- for (bNumEndpoint = 0;
- bNumEndpoint < alternate_instance->endpoints;
- bNumEndpoint++) {
- struct usb_endpoint_descriptor *endpoint_descriptor;
- dbg_ep0 (3, "[%d:%d:%d] endpoint: %d",
- bNumInterface,
- bAlternateSetting,
- bNumEndpoint,
- interface_descriptor->
- bNumEndpoints);
- if (!(endpoint_descriptor = usbd_device_endpoint_descriptor_index (device, port, index, bNumInterface, bAlternateSetting, bNumEndpoint))) {
- dbg_ep0 (3, "[%d] endpoint NULL",
- bNumEndpoint);
- return -1;
- }
- /* copy descriptor for this endpoint */
- copy_config (urb, endpoint_descriptor,
- sizeof (struct usb_endpoint_descriptor),
- max);
- }
- }
- }
- dbg_ep0 (3, "lengths: %d %d",
- le16_to_cpu (configuration_descriptor->wTotalLength),
- urb->actual_length);
+ cpu_to_le16(configuration_descriptor->wTotalLength),
+ max);
}
+
break;
case USB_DESCRIPTOR_TYPE_STRING:
{
struct usb_string_descriptor *string_descriptor;
-
if (!(string_descriptor = usbd_get_string (index))) {
+ serial_printf("Invalid string index %d\n", index);
return -1;
}
- /*dbg_ep0(3, "string_descriptor: %p", string_descriptor); */
+ dbg_ep0(3, "string_descriptor: %p length %d", string_descriptor, string_descriptor->bLength);
copy_config (urb, string_descriptor, string_descriptor->bLength, max);
}
break;
case USB_DESCRIPTOR_TYPE_INTERFACE:
+ serial_printf("USB_DESCRIPTOR_TYPE_INTERFACE - error not implemented\n");
return -1;
case USB_DESCRIPTOR_TYPE_ENDPOINT:
+ serial_printf("USB_DESCRIPTOR_TYPE_ENDPOINT - error not implemented\n");
return -1;
case USB_DESCRIPTOR_TYPE_HID:
{
+ serial_printf("USB_DESCRIPTOR_TYPE_HID - error not implemented\n");
return -1; /* unsupported at this time */
#if 0
int bNumInterface =
@@ -403,6 +309,7 @@ static int ep0_get_descriptor (struct usb_device_instance *device,
break;
case USB_DESCRIPTOR_TYPE_REPORT:
{
+ serial_printf("USB_DESCRIPTOR_TYPE_REPORT - error not implemented\n");
return -1; /* unsupported at this time */
#if 0
int bNumInterface =
@@ -434,12 +341,19 @@ static int ep0_get_descriptor (struct usb_device_instance *device,
#endif
}
break;
+ case USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER:
+ {
+ /* If a USB device supports both a full speed and low speed operation
+ * we must send a Device_Qualifier descriptor here
+ */
+ return -1;
+ }
default:
return -1;
}
- dbg_ep0 (1, "urb: buffer: %p buffer_length: %2d actual_length: %2d packet size: %2d",
+ dbg_ep0 (1, "urb: buffer: %p buffer_length: %2d actual_length: %2d tx_packetSize: %2d",
urb->buffer, urb->buffer_length, urb->actual_length,
device->bus->endpoint_array[0].tx_packetSize);
/*
@@ -495,6 +409,12 @@ int ep0_recv_setup (struct urb *urb)
/* handle USB Standard Request (c.f. USB Spec table 9-2) */
if ((request->bmRequestType & USB_REQ_TYPE_MASK) != 0) {
+ if(device->device_state <= STATE_CONFIGURED){
+ /* Attempt to handle a CDC specific request if we are
+ * in the configured state.
+ */
+ return device->cdc_recv_setup(request,urb);
+ }
dbg_ep0 (1, "non standard request: %x",
request->bmRequestType & USB_REQ_TYPE_MASK);
return -1; /* Stall here */
@@ -567,6 +487,7 @@ int ep0_recv_setup (struct urb *urb)
le16_to_cpu (request->wValue) & 0xff);
case USB_REQ_GET_CONFIGURATION:
+ serial_printf("get config %d\n", device->configuration);
return ep0_get_one (device, urb,
device->configuration);
@@ -642,7 +563,6 @@ int ep0_recv_setup (struct urb *urb)
/*dbg_ep0(2, "address: %d %d %d", */
/* request->wValue, le16_to_cpu(request->wValue), device->address); */
- serial_printf ("DEVICE_ADDRESS_ASSIGNED.. event?\n");
return 0;
case USB_REQ_SET_DESCRIPTOR: /* XXX should we support this? */
@@ -653,9 +573,10 @@ int ep0_recv_setup (struct urb *urb)
/* c.f. 9.4.7 - the top half of wValue is reserved */
/* */
if ((device->configuration =
- le16_to_cpu (request->wValue) & 0x7f) != 0) {
+ le16_to_cpu (request->wValue) & 0xFF80) != 0) {
/* c.f. 9.4.7 - zero is the default or addressed state, in our case this */
/* is the same is configuration zero */
+ serial_printf("error setting dev->config to zero!\n");
device->configuration = 0; /* TBR - ?????? */
}
/* reset interface and alternate settings */
diff --git a/drivers/usbdcore_mpc8xx.c b/drivers/usbdcore_mpc8xx.c
new file mode 100644
index 0000000..9bd2c23
--- /dev/null
+++ b/drivers/usbdcore_mpc8xx.c
@@ -0,0 +1,1412 @@
+/*
+ * Copyright (C) 2006 by Bryan O'Donoghue, CodeHermit
+ * bodonoghue@CodeHermit.ie
+ *
+ * References
+ * DasUBoot/drivers/usbdcore_omap1510.c, for design and implementation ideas.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Notes :
+ * 1. #define __SIMULATE_ERROR__ to inject a CRC error into every 2nd TX
+ * packet to force the USB re-transmit protocol.
+ *
+ * 2. #define __DEBUG_UDC__ to switch on debug tracing to serial console
+ * be careful that tracing doesn't create Hiesen-bugs with respect to
+ * response timeouts to control requests.
+ *
+ * 3. This driver should be able to support any higher level driver that
+ * that wants to do either of the two standard UDC implementations
+ * Control-Bulk-Interrupt or Bulk-IN/Bulk-Out standards. Hence
+ * gserial and cdc_acm should work with this code.
+ *
+ * 4. NAK events never actually get raised at all, the documentation
+ * is just wrong !
+ *
+ * 5. For some reason, cbd_datlen is *always* +2 the value it should be.
+ * this means that having an RX cbd of 16 bytes is not possible, since
+ * the same size is reported for 14 bytes received as 16 bytes received
+ * until we can find out why this happens, RX cbds must be limited to 8
+ * bytes. TODO: check errata for this behaviour.
+ *
+ * 6. Right now this code doesn't support properly powering up with the USB
+ * cable attached to the USB host my development board the Adder87x doesn't
+ * have a pull-up fitted to allow this, so it is necessary to power the
+ * board and *then* attached the USB cable to the host. However somebody
+ * with a different design in their board may be able to keep the cable
+ * constantly connected and simply enable/disable a pull-up re
+ * figure 31.1 in MPC885RM.pdf instead of having to power up the board and
+ * then attach the cable !
+ *
+ */
+#include <common.h>
+#include <config.h>
+
+#if defined(CONFIG_MPC885_FAMILY) && defined(CONFIG_USB_DEVICE)
+#include <commproc.h>
+#include "usbdcore.h"
+#include "usbdcore_mpc8xx.h"
+#include "usbdcore_ep0.h"
+
+#define ERR(fmt, args...)\
+ serial_printf("ERROR : [%s] %s:%d: "fmt,\
+ __FILE__,__FUNCTION__,__LINE__, ##args)
+#ifdef __DEBUG_UDC__
+ #define DBG(fmt,args...)\
+ serial_printf("[%s] %s:%d: "fmt,\
+ __FILE__,__FUNCTION__,__LINE__, ##args)
+#else
+ #define DBG(fmt,args...)
+#endif
+
+/* Static Data */
+#ifdef __SIMULATE_ERROR__
+ static char err_poison_test = 0;
+#endif
+static struct mpc8xx_ep ep_ref[MAX_ENDPOINTS];
+static u32 address_base = STATE_NOT_READY;
+static mpc8xx_udc_state_t udc_state = 0;
+static struct usb_device_instance *udc_device = 0;
+static volatile usb_epb_t *endpoints[MAX_ENDPOINTS];
+static volatile cbd_t * tx_cbd[TX_RING_SIZE];
+static volatile cbd_t * rx_cbd[RX_RING_SIZE];
+static volatile immap_t *immr = 0;
+static volatile cpm8xx_t *cp = 0;
+static volatile usb_pram_t *usb_paramp = 0;
+static volatile usb_t *usbp = 0;
+static int rx_ct = 0;
+static int tx_ct = 0;
+
+/* Static Function Declarations */
+static void mpc8xx_udc_state_transition_up (usb_device_state_t initial,
+ usb_device_state_t final);
+static void mpc8xx_udc_state_transition_down (usb_device_state_t initial,
+ usb_device_state_t final);
+static void mpc8xx_udc_stall (unsigned int ep);
+static void mpc8xx_udc_flush_tx_fifo(int epid);
+static void mpc8xx_udc_flush_rx_fifo(void);
+static void mpc8xx_udc_clear_rxbd (volatile cbd_t * rx_cbdp);
+static void mpc8xx_udc_init_tx(struct usb_endpoint_instance *epi,
+ struct urb * tx_urb);
+static void mpc8xx_udc_dump_request(struct usb_device_request *request);
+static void mpc8xx_udc_clock_init (volatile immap_t * immr,
+ volatile cpm8xx_t * cp);
+static int mpc8xx_udc_ep_tx (struct usb_endpoint_instance *epi);
+static int mpc8xx_udc_epn_rx (unsigned int epid, volatile cbd_t * rx_cbdp);
+static void mpc8xx_udc_ep0_rx(volatile cbd_t * rx_cbdp);
+static void mpc8xx_udc_cbd_init (void);
+static void mpc8xx_udc_endpoint_init (void);
+static void mpc8xx_udc_cbd_attach (int ep, uchar tx_size, uchar rx_size);
+static u32 mpc8xx_udc_alloc (u32 data_size, u32 alignment);
+static int mpc8xx_udc_ep0_rx_setup (volatile cbd_t * rx_cbdp);
+static void mpc8xx_udc_set_nak (unsigned int ep);
+static short mpc8xx_udc_handle_txerr(void);
+static void mpc8xx_udc_advance_rx(volatile cbd_t ** rx_cbdp, int epid);
+
+/******************************************************************************
+ Global Linkage
+ *****************************************************************************/
+
+/* udc_init
+ *
+ * Do initial bus gluing
+ */
+int udc_init(void)
+{
+ /* Init various pointers */
+ immr = (immap_t *) CFG_IMMR;
+ cp = (cpm8xx_t *)&(immr->im_cpm);
+ usb_paramp = (usb_pram_t*)&(cp->cp_dparam[PROFF_USB]);
+ usbp = (usb_t *) &(cp->cp_scc[0]);
+
+ memset(ep_ref, 0x00, (sizeof(struct mpc8xx_ep) * MAX_ENDPOINTS));
+
+ udc_device = 0;
+ udc_state = STATE_NOT_READY;
+
+ usbp->usmod= 0x00;
+ usbp->uscom= 0;
+
+ /* Set USB Frame #0, Respond at Address & Get a clock source */
+ usbp->usaddr = 0x00;
+ mpc8xx_udc_clock_init (immr, cp);
+
+ /* PA15, PA14 as perhiperal USBRXD and USBOE */
+ immr->im_ioport.iop_padir&= ~0x0003;
+ immr->im_ioport.iop_papar|= 0x0003;
+
+ /* PC11/PC10 as peripheral USBRXP USBRXN */
+ immr->im_ioport.iop_pcso|= 0x0030;
+
+ /* PC7/PC6 as perhiperal USBTXP and USBTXN */
+ immr->im_ioport.iop_pcdir|= 0x0300;
+ immr->im_ioport.iop_pcpar|= 0x0300;
+
+ /* Set the base address */
+ address_base = (u32)(cp->cp_dpmem + CPM_USB_BASE);
+
+ /* Initialise endpoints and circular buffers */
+ mpc8xx_udc_endpoint_init();
+ mpc8xx_udc_cbd_init();
+
+ /* Assign allocated Dual Port Endpoint descriptors */
+ usb_paramp->ep0ptr = (u32)endpoints[0];
+ usb_paramp->ep1ptr = (u32)endpoints[1];
+ usb_paramp->ep2ptr = (u32)endpoints[2];
+ usb_paramp->ep3ptr = (u32)endpoints[3];
+ usb_paramp->frame_n = 0;
+
+ DBG("ep0ptr=0x%08x ep1ptr=0x%08x ep2ptr=0x%08x ep3ptr=0x%08x\n",
+ usb_paramp->ep0ptr, usb_paramp->ep1ptr, usb_paramp->ep2ptr,
+ usb_paramp->ep3ptr);
+
+ return 0;
+}
+
+/* udc_irq
+ *
+ * Poll for whatever events may have occured
+ */
+void udc_irq(void)
+{
+ int epid = 0;
+ volatile cbd_t * rx_cbdp = 0;
+ volatile cbd_t * rx_cbdp_base = 0;
+
+ if(udc_state!=STATE_READY){
+ return;
+ }
+
+ if(usbp->usber&USB_E_BSY){
+ /* This shouldn't happen. If it does then it's a bug ! */
+ usbp->usber|=USB_E_BSY;
+ mpc8xx_udc_flush_rx_fifo();
+ }
+
+
+ /* Scan all RX/Bidirectional Endpoints for RX data. */
+ for(epid = 0; epid<MAX_ENDPOINTS; epid++){
+
+ if(!ep_ref[epid].prx){
+ continue;
+ }
+
+ rx_cbdp = rx_cbdp_base = ep_ref[epid].prx;
+ do{
+ if(!(rx_cbdp->cbd_sc&RX_BD_E)){
+
+ if(rx_cbdp->cbd_sc&0x1F){
+ /* Corrupt data discard it.
+ * Controller has NAK'd this packet.
+ */
+ mpc8xx_udc_clear_rxbd(rx_cbdp);
+
+ }else{
+ if(!epid){
+ mpc8xx_udc_ep0_rx(rx_cbdp);
+
+ }else{
+ /* Process data */
+ mpc8xx_udc_set_nak(epid);
+ mpc8xx_udc_epn_rx(epid,rx_cbdp);
+ mpc8xx_udc_clear_rxbd(rx_cbdp);
+ }
+ }
+
+ /* Advance RX CBD pointer */
+ mpc8xx_udc_advance_rx(&rx_cbdp, epid);
+ ep_ref[epid].prx = rx_cbdp;
+ }else{
+ /* Advance RX CBD pointer */
+ mpc8xx_udc_advance_rx(&rx_cbdp, epid);
+ }
+
+ }while(rx_cbdp != rx_cbdp_base);
+ }
+
+ /* Handle TX events as appropiate, the correct place to do this is
+ * in a tx routine. Perhaps TX on epn was pre-empted by ep0
+ */
+
+ if(usbp->usber&USB_E_TXB){
+ usbp->usber|=USB_E_TXB;
+ }
+
+ if(usbp->usber&(USB_TX_ERRMASK)){
+ mpc8xx_udc_handle_txerr();
+ }
+
+ /* Switch to the default state, respond at the default address */
+ if(usbp->usber&USB_E_RESET){
+ usbp->usber|=USB_E_RESET;
+ usbp->usaddr = 0x00;
+ udc_device->device_state = STATE_DEFAULT;
+ }
+
+ /*if(usbp->usber&USB_E_IDLE){
+ We could suspend here !
+ usbp->usber|=USB_E_IDLE;
+ DBG("idle state change\n");
+ }
+ if(usbp->usbs){
+ We could resume here when IDLE is deasserted !
+ Not worth doing, so long as we are self powered though.
+ }*/
+
+ return;
+}
+
+
+
+/* udc_endpoint_write
+ *
+ * Write some data to an endpoint
+ */
+int udc_endpoint_write(struct usb_endpoint_instance *epi)
+{
+ int ep = 0;
+ short epid = 1, unnak = 0, ret = 0;
+
+ if(udc_state != STATE_READY){
+ ERR("invalid udc_state != STATE_READY!\n");
+ return -1;
+ }
+
+ if(!udc_device || !epi){
+ return -1;
+ }
+
+ if(udc_device->device_state!=STATE_CONFIGURED){
+ return -1;
+ }
+
+ ep = epi->endpoint_address & 0x03;
+ if(ep >= MAX_ENDPOINTS){
+ return -1;
+ }
+
+ /* Set NAK for all RX endpoints during TX */
+ for(epid = 1; epid<MAX_ENDPOINTS; epid++){
+
+ /* Don't set NAK on DATA IN/CONTROL endpoints */
+ if(ep_ref[epid].sc & USB_DIR_IN){
+ continue;
+ }
+
+ if(!(usbp->usep[epid]&( USEP_THS_NAK | USEP_RHS_NAK ))){
+ unnak |= 1<<epid;
+ }
+
+ mpc8xx_udc_set_nak(epid);
+ }
+
+ mpc8xx_udc_init_tx(&udc_device->bus->endpoint_array[ep],epi->tx_urb);
+ ret = mpc8xx_udc_ep_tx(&udc_device->bus->endpoint_array[ep]);
+
+ /* Remove temporary NAK */
+ for(epid = 1; epid<MAX_ENDPOINTS; epid++){
+ if(unnak&(1<<epid)){
+ udc_unset_nak(epid);
+ }
+ }
+
+ return ret;
+}
+
+/* mpc8xx_udc_assign_urb
+ *
+ * Associate a given urb to an endpoint TX or RX transmit/receive buffers
+ */
+static int mpc8xx_udc_assign_urb(int ep, char direction)
+{
+ struct usb_endpoint_instance *epi = 0;
+
+ if(ep >= MAX_ENDPOINTS){
+ goto err;
+ }
+ epi = &udc_device->bus->endpoint_array[ep];
+ if(!epi){
+ goto err;
+ }
+
+ if(!ep_ref[ep].urb){
+ ep_ref[ep].urb = usbd_alloc_urb(udc_device,
+ udc_device->bus->endpoint_array);
+ if(!ep_ref[ep].urb){
+ goto err;
+ }
+ }else{
+ ep_ref[ep].urb->actual_length = 0;
+ }
+
+ switch(direction){
+ case USB_DIR_IN:
+ epi->tx_urb = ep_ref[ep].urb;
+ break;
+ case USB_DIR_OUT:
+ epi->rcv_urb = ep_ref[ep].urb;
+ break;
+ default:
+ goto err;
+ }
+ return 0;
+
+err:
+ udc_state = STATE_ERROR;
+ return -1;
+}
+
+/* udc_setup_ep
+ *
+ * Associate U-Boot software endpoints to mpc8xx endpoint parameter ram
+ * Isochronous endpoints aren't yet supported!
+ */
+void udc_setup_ep(struct usb_device_instance *device, unsigned int ep,
+ struct usb_endpoint_instance *epi)
+{
+ uchar direction = 0;
+ int ep_attrib = 0;
+
+ if(epi && (ep < MAX_ENDPOINTS)){
+
+ if(ep == 0){
+ if (epi->rcv_attributes!=USB_ENDPOINT_XFER_CONTROL
+ ||epi->tx_attributes!=
+ USB_ENDPOINT_XFER_CONTROL){
+
+ /* ep0 must be a control endpoint*/
+ udc_state = STATE_ERROR;
+ return;
+
+ }
+ if(!(ep_ref[ep].sc & EP_ATTACHED)){
+ mpc8xx_udc_cbd_attach (ep, epi->tx_packetSize,
+ epi->rcv_packetSize);
+ }
+ usbp->usep[ep] = 0x0000;
+ return;
+ }
+
+ if ((epi->endpoint_address & USB_ENDPOINT_DIR_MASK)
+ == USB_DIR_IN) {
+
+ direction = 1;
+ ep_attrib = epi->tx_attributes;
+ epi->rcv_packetSize = 0;
+ ep_ref[ep].sc |= USB_DIR_IN;
+ } else {
+
+ direction = 0;
+ ep_attrib = epi->rcv_attributes;
+ epi->tx_packetSize = 0;
+ ep_ref[ep].sc &= ~USB_DIR_IN;
+ }
+
+ if(mpc8xx_udc_assign_urb(ep, epi->endpoint_address
+ &USB_ENDPOINT_DIR_MASK)){
+ return;
+ }
+
+ switch(ep_attrib){
+ case USB_ENDPOINT_XFER_CONTROL:
+ if(!(ep_ref[ep].sc & EP_ATTACHED)){
+ mpc8xx_udc_cbd_attach (ep,
+ epi->tx_packetSize,
+ epi->rcv_packetSize);
+ }
+ usbp->usep[ep] = ep<<12;
+ epi->rcv_urb = epi->tx_urb = ep_ref[ep].urb;
+
+ break;
+ case USB_ENDPOINT_XFER_BULK :
+ case USB_ENDPOINT_XFER_INT:
+ if(!(ep_ref[ep].sc & EP_ATTACHED)){
+ if(direction){
+ mpc8xx_udc_cbd_attach (ep,
+ epi->tx_packetSize, 0);
+ }else{
+ mpc8xx_udc_cbd_attach (ep,
+ 0, epi->rcv_packetSize);
+ }
+ }
+ usbp->usep[ep]= (ep<<12)|((ep_attrib)<<8);
+
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ default:
+ serial_printf("Error endpoint attrib %d>3\n",
+ ep_attrib);
+ udc_state = STATE_ERROR;
+ break;
+ }
+ }
+
+}
+
+/* udc_connect
+ *
+ * Move state, switch on the USB
+ */
+void udc_connect(void)
+{
+ /* Enable pull-up resistor on D+
+ * TODO: fit a pull-up resistor to drive SE0 for > 2.5us
+ */
+
+ if(udc_state!=STATE_ERROR){
+ udc_state = STATE_READY;
+ usbp->usmod|= USMOD_EN;
+ }
+}
+
+/* udc_disconnect
+ *
+ * Disconnect is not used but, is included for completeness
+ */
+void udc_disconnect(void)
+{
+ /* Disable pull-up resistor on D-
+ * TODO: fix a pullup resistor to control this
+ */
+
+ if(udc_state!=STATE_ERROR){
+ udc_state = STATE_NOT_READY;
+ }
+ usbp->usmod&=~USMOD_EN;
+}
+
+/* udc_enable
+ *
+ * Grab an EP0 URB, register interest in a subset of USB events
+ */
+void udc_enable(struct usb_device_instance *device)
+{
+ if(udc_state == STATE_ERROR){
+ return;
+ }
+
+ udc_device = device;
+
+ if(!ep_ref[0].urb){
+ ep_ref[0].urb = usbd_alloc_urb(device,
+ device->bus->endpoint_array);
+ }
+
+ /* Register interest in all events except SOF, enable transceiver */
+ usbp->usber= 0x03FF;
+ usbp->usbmr= 0x02F7;
+
+ return;
+}
+
+/* udc_disable
+ *
+ * disable the currently hooked device
+ */
+void udc_disable(void)
+{
+ int i = 0;
+
+ if(udc_state == STATE_ERROR){
+ DBG("Won't disable UDC. udc_state==STATE_ERROR !\n");
+ return;
+ }
+
+ udc_device = 0;
+
+ for(;i<MAX_ENDPOINTS; i++){
+ if(ep_ref[i].urb){
+ usbd_dealloc_urb(ep_ref[i].urb);
+ ep_ref[i].urb = 0;
+ }
+ }
+
+ usbp->usbmr= 0x00;
+ usbp->usmod= ~USMOD_EN;
+ udc_state = STATE_NOT_READY;
+}
+
+/* udc_startup_events
+ *
+ * Enable the specified device
+ */
+void udc_startup_events(struct usb_device_instance *device)
+{
+ udc_enable(device);
+ if(udc_state == STATE_READY){
+ usbd_device_event_irq (device, DEVICE_CREATE, 0);
+ }
+}
+
+/* udc_set_nak
+ *
+ * Allow upper layers to signal lower layers should not accept more RX data
+ *
+ */
+void udc_set_nak(int epid)
+{
+ if(epid){
+ mpc8xx_udc_set_nak(epid);
+ }
+}
+
+/* udc_unset_nak
+ *
+ * Suspend sending of NAK tokens for DATA OUT tokens on a given endpoint.
+ * Switch off NAKing on this endpoint to accept more data output from host.
+ *
+ */
+void udc_unset_nak (int epid)
+{
+ if(epid > MAX_ENDPOINTS){
+ return;
+ }
+
+ if(usbp->usep[epid]&(USEP_THS_NAK | USEP_RHS_NAK)){
+ usbp->usep[epid]&= ~(USEP_THS_NAK | USEP_RHS_NAK);
+ __asm__ ("eieio");
+ }
+}
+
+/******************************************************************************
+ Static Linkage
+******************************************************************************/
+
+/* 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.
+ *
+ */
+
+static void mpc8xx_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,
+ 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 void mpc8xx_udc_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;
+ }
+ }
+}
+
+/* mpc8xx_udc_stall
+ *
+ * Force returning of STALL tokens on the given endpoint. Protocol or function
+ * STALL conditions are permissable here
+ */
+static void mpc8xx_udc_stall (unsigned int ep)
+{
+ usbp->usep[ep] |= STALL_BITMASK;
+}
+
+/* mpc8xx_udc_set_nak
+ *
+ * Force returning of NAK responses for the given endpoint as a kind of very
+ * simple flow control
+ */
+static void mpc8xx_udc_set_nak (unsigned int ep)
+{
+ usbp->usep[ep] |= NAK_BITMASK;
+ __asm__ ("eieio");
+}
+
+/* mpc8xx_udc_handle_txerr
+ *
+ * Handle errors relevant to TX. Return a status code to allow calling
+ * indicative of what if anything happened
+ */
+static short mpc8xx_udc_handle_txerr()
+{
+ short ep = 0, ret = 0;
+
+ for(; ep<TX_RING_SIZE; ep++){
+ if(usbp->usber&(0x10<<ep)){
+
+ /* Timeout or underrun */
+ if(tx_cbd[ep]->cbd_sc&0x06){
+ ret = 1;
+ mpc8xx_udc_flush_tx_fifo(ep);
+
+ }else{
+ if(usbp->usep[ep]&STALL_BITMASK){
+ if(!ep){
+ usbp->usep[ep]&=
+ ~STALL_BITMASK;
+ }
+ }/* else NAK */
+ }
+ usbp->usber|=(0x10<<ep);
+ }
+ }
+ return ret;
+}
+
+/* mpc8xx_udc_advance_rx
+ *
+ * Advance cbd rx
+ */
+static void mpc8xx_udc_advance_rx(volatile cbd_t ** rx_cbdp, int epid)
+{
+ if((*rx_cbdp)->cbd_sc & RX_BD_W){
+ *rx_cbdp = (volatile cbd_t*)
+ (endpoints[epid]->rbase + CFG_IMMR);
+
+ }else{
+ (*rx_cbdp)++;
+ }
+}
+
+
+/* mpc8xx_udc_flush_tx_fifo
+ *
+ * Flush a given TX fifo. Assumes one tx cbd per endpoint
+ */
+static void mpc8xx_udc_flush_tx_fifo(int epid)
+{
+ volatile cbd_t * tx_cbdp = 0;
+
+ if(epid > MAX_ENDPOINTS){
+ return;
+ }
+
+ /* TX stop */
+ immr->im_cpm.cp_cpcr = ((epid<<2) | 0x1D01);
+ __asm__ ("eieio");
+ while(immr->im_cpm.cp_cpcr & 0x01);
+
+ usbp->uscom = 0x40 | 0;
+
+ /* reset ring */
+ tx_cbdp = (cbd_t*)(endpoints[epid]->tbptr + CFG_IMMR);
+ tx_cbdp->cbd_sc = (TX_BD_I | TX_BD_W);
+
+
+ endpoints[epid]->tptr = endpoints[epid]->tbase;
+ endpoints[epid]->tstate = 0x00;
+ endpoints[epid]->tbcnt = 0x00;
+
+ /* TX start */
+ immr->im_cpm.cp_cpcr = ((epid<<2) | 0x2D01);
+ __asm__ ("eieio");
+ while(immr->im_cpm.cp_cpcr & 0x01);
+
+ return;
+}
+
+/* mpc8xx_udc_flush_rx_fifo
+ *
+ * For the sake of completeness of the namespace, it seems like
+ * a good-design-decision (tm) to include mpc8xx_udc_flush_rx_fifo();
+ * If RX_BD_E is true => a driver bug either here or in an upper layer
+ * not polling frequently enough. If RX_BD_E is true we have told the host
+ * we have accepted data but, the CPM found it had no-where to put that data
+ * which needless to say would be a bad thing.
+ */
+static void mpc8xx_udc_flush_rx_fifo()
+{
+ int i = 0;
+ for(i = 0;i<RX_RING_SIZE; i++){
+ if(!(rx_cbd[i]->cbd_sc&RX_BD_E)){
+ ERR("buf %p used rx data len = 0x%x sc=0x%x!\n",
+ rx_cbd[i], rx_cbd[i]->cbd_datlen,
+ rx_cbd[i]->cbd_sc);
+
+ }
+ }
+ ERR("BUG : Input over-run\n");
+}
+
+/* mpc8xx_udc_clear_rxbd
+ *
+ * Release control of RX CBD to CP.
+ */
+static void mpc8xx_udc_clear_rxbd(volatile cbd_t * rx_cbdp)
+{
+ rx_cbdp->cbd_datlen = 0x0000;
+ rx_cbdp->cbd_sc= ((rx_cbdp->cbd_sc & RX_BD_W)|(RX_BD_E | RX_BD_I));
+ __asm__ ("eieio");
+}
+
+/* mpc8xx_udc_tx_irq
+ *
+ * Parse for tx timeout, control RX or USB reset/busy conditions
+ * Return -1 on timeout, -2 on fatal error, else return zero
+ */
+static int mpc8xx_udc_tx_irq(int ep)
+{
+ int i = 0;
+
+ if(usbp->usber&(USB_TX_ERRMASK)){
+ if(mpc8xx_udc_handle_txerr()){
+ /* Timeout, controlling function must retry send */
+ return -1;
+ }
+ }
+
+ if(usbp->usber & (USB_E_RESET|USB_E_BSY)){
+ /* Fatal, abandon TX transaction */
+ return -2;
+ }
+
+ if(usbp->usber & USB_E_RXB){
+ for(i = 0;i<RX_RING_SIZE; i++){
+ if(!(rx_cbd[i]->cbd_sc&RX_BD_E)){
+ if((rx_cbd[i] == ep_ref[0].prx) || ep){
+ return -2;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* mpc8xx_udc_ep_tx
+ *
+ * Transmit in a re-entrant fashion outbound USB packets.
+ * Implement retry/timeout mechanism described in USB specification
+ * Toggle DATA0/DATA1 pids as necessary
+ * Introduces non-standard tx_retry. The USB standard has no scope for slave
+ * devices to give up TX, however tx_retry stops us getting stuck in an endless
+ * TX loop.
+ */
+static int mpc8xx_udc_ep_tx (struct usb_endpoint_instance *epi)
+{
+ struct urb *urb = epi->tx_urb;
+ volatile cbd_t * tx_cbdp = 0;
+ unsigned int ep = 0, pkt_len = 0, x = 0, tx_retry = 0;
+ int ret = 0;
+
+ if(!epi || (epi->endpoint_address&0x03)>=MAX_ENDPOINTS || !urb){
+ return -1;
+ }
+
+ ep = epi->endpoint_address & 0x03;
+ tx_cbdp = (cbd_t*)(endpoints[ep]->tbptr + CFG_IMMR);
+
+ if(tx_cbdp->cbd_sc&TX_BD_R || usbp->usber&USB_E_TXB){
+ mpc8xx_udc_flush_tx_fifo(ep);
+ usbp->usber |= USB_E_TXB;
+ };
+
+ while(tx_retry++ < 100){
+ ret = mpc8xx_udc_tx_irq(ep);
+ if(ret == -1){
+ /* ignore timeout here */
+ }else if(ret == -2){
+ /* Abandon TX */
+ mpc8xx_udc_flush_tx_fifo(ep);
+ return -1;
+ }
+
+ tx_cbdp = (cbd_t*)(endpoints[ep]->tbptr + CFG_IMMR);
+ while(tx_cbdp->cbd_sc&TX_BD_R){};
+ tx_cbdp->cbd_sc = (tx_cbdp->cbd_sc&TX_BD_W);
+
+ pkt_len = urb->actual_length - epi->sent;
+
+ if(pkt_len> epi->tx_packetSize || pkt_len > EP_MAX_PKT){
+ pkt_len = MIN(epi->tx_packetSize, EP_MAX_PKT);
+ }
+
+ for(x=0; x<pkt_len; x++){
+ *((unsigned char*)(tx_cbdp->cbd_bufaddr+x)) =
+ urb->buffer[epi->sent + x];
+ }
+ tx_cbdp->cbd_datlen = pkt_len;
+ tx_cbdp->cbd_sc|=(CBD_TX_BITMASK | ep_ref[ep].pid);
+ __asm__ ("eieio");
+
+ #ifdef __SIMULATE_ERROR__
+ if(++err_poison_test == 2){
+ err_poison_test = 0;
+ tx_cbdp->cbd_sc&=~TX_BD_TC;
+ }
+ #endif
+
+ usbp->uscom = (USCOM_STR | ep);
+
+ while(!(usbp->usber&USB_E_TXB)){
+ ret = mpc8xx_udc_tx_irq(ep);
+ if(ret == -1){
+ /* TX timeout */
+ break;
+ }else if(ret == -2){
+ if(usbp->usber & USB_E_TXB){
+ usbp->usber|=USB_E_TXB;
+ }
+ mpc8xx_udc_flush_tx_fifo(ep);
+ return -1;
+ }
+ };
+
+ if(usbp->usber & USB_E_TXB){
+ usbp->usber|=USB_E_TXB;
+ }
+
+ /* ACK must be present <= 18bit times from TX */
+ if(ret == -1){
+ continue;
+ }
+
+ /* TX ACK : USB 2.0 8.7.2, Toggle PID, Advance TX */
+ epi->sent += pkt_len;
+ epi->last = MIN (urb->actual_length - epi->sent,
+ epi->tx_packetSize);
+ TOGGLE_TX_PID(ep_ref[ep].pid);
+
+ if(epi->sent >= epi->tx_urb->actual_length){
+
+ epi->tx_urb->actual_length = 0;
+ epi->sent = 0;
+
+ if(ep_ref[ep].sc & EP_SEND_ZLP){
+ ep_ref[ep].sc &= ~EP_SEND_ZLP;
+ }else{
+ return 0;
+ }
+ }
+ }
+
+ ERR("TX fail, endpoint 0x%x tx bytes 0x%x/0x%x\n",ep, epi->sent,
+ epi->tx_urb->actual_length);
+
+ return -1;
+}
+
+/* mpc8xx_udc_dump_request
+ *
+ * Dump a control request to console
+ */
+static void mpc8xx_udc_dump_request(struct usb_device_request *request)
+{
+ DBG(
+ "bmRequestType:%02x bRequest:%02x wValue:%04x "
+ "wIndex:%04x wLength:%04x ?\n",
+ request->bmRequestType,
+ request->bRequest,
+ request->wValue,
+ request->wIndex,
+ request->wLength);
+
+ return;
+}
+
+/* mpc8xx_udc_ep0_rx_setup
+ *
+ * Decode received ep0 SETUP packet. return non-zero on error
+ */
+static int mpc8xx_udc_ep0_rx_setup (volatile cbd_t * rx_cbdp)
+{
+ unsigned int x = 0;
+ struct urb * purb = ep_ref[0].urb;
+ struct usb_endpoint_instance *epi =
+ &udc_device->bus->endpoint_array[0];
+
+ for(; x<rx_cbdp->cbd_datlen; x++){
+ *(((unsigned char*)&ep_ref[0].urb->device_request)+x) =
+ *((unsigned char*)(rx_cbdp->cbd_bufaddr+x));
+ }
+
+ mpc8xx_udc_clear_rxbd(rx_cbdp);
+
+ if (ep0_recv_setup(purb)) {
+ mpc8xx_udc_dump_request(&purb->device_request);
+ return -1;
+ }
+
+ if ((purb->device_request.bmRequestType&USB_REQ_DIRECTION_MASK)
+ == USB_REQ_HOST2DEVICE) {
+
+ switch (purb->device_request.bRequest){
+ case USB_REQ_SET_ADDRESS:
+ /* Send the Status OUT ZLP */
+ ep_ref[0].pid = TX_BD_PID_DATA1;
+ purb->actual_length = 0;
+ mpc8xx_udc_init_tx(epi,purb);
+ mpc8xx_udc_ep_tx(epi);
+
+ /* Move to the addressed state */
+ usbp->usaddr = udc_device->address;
+ mpc8xx_udc_state_transition_up(udc_device->device_state,
+ STATE_ADDRESSED);
+ return 0;
+
+ case USB_REQ_SET_CONFIGURATION:
+ if(!purb->device_request.wValue){
+
+ /* Respond at default address */
+ usbp->usaddr = 0x00;
+ mpc8xx_udc_state_transition_down(udc_device->device_state,
+ STATE_ADDRESSED);
+
+ } else {
+
+ /* TODO: Support multiple configurations */
+ mpc8xx_udc_state_transition_up(udc_device->device_state,STATE_CONFIGURED);
+ for(x=1; x<MAX_ENDPOINTS; x++){
+ if((udc_device->bus->endpoint_array[x].endpoint_address&USB_ENDPOINT_DIR_MASK)
+ == USB_DIR_IN){
+ ep_ref[x].pid = TX_BD_PID_DATA0;
+ }else{
+ ep_ref[x].pid = RX_BD_PID_DATA0;
+ }
+ /* Set configuration must unstall endpoints */
+ usbp->usep[x]&=~STALL_BITMASK;
+ }
+
+ }
+ break;
+ default:
+ /* CDC/Vendor specific */
+ break;
+ }
+
+ /* Send ZLP as ACK in Status OUT phase */
+ ep_ref[0].pid = TX_BD_PID_DATA1;
+ purb->actual_length = 0;
+ mpc8xx_udc_init_tx(epi,purb);
+ mpc8xx_udc_ep_tx(epi);
+
+ }else{
+ if(purb->actual_length){
+ ep_ref[0].pid = TX_BD_PID_DATA1;
+ mpc8xx_udc_init_tx(epi,purb);
+
+ if(!(purb->actual_length%EP0_MAX_PACKET_SIZE)){
+ ep_ref[0].sc |= EP_SEND_ZLP;
+ }
+
+ if(purb->device_request.wValue==
+ USB_DESCRIPTOR_TYPE_DEVICE){
+ if(le16_to_cpu(purb->device_request.wLength)>
+ purb->actual_length){
+ /* Send EP0_MAX_PACKET_SIZE bytes
+ * unless correct size requested.
+ */
+ if(purb->actual_length >
+ epi->tx_packetSize){
+
+ purb->actual_length =
+ epi->tx_packetSize;
+ }
+
+ }
+ }
+ mpc8xx_udc_ep_tx(epi);
+
+ }else{
+ /* Corrupt SETUP packet? */
+ ERR("Zero length data or SETUP with DATA-IN phase ?\n");
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* mpc8xx_udc_init_tx
+ *
+ * Setup some basic parameters for a TX transaction
+ */
+static void mpc8xx_udc_init_tx(struct usb_endpoint_instance *epi,
+ struct urb * tx_urb)
+{
+ epi->sent = 0;
+ epi->last = 0;
+ epi->tx_urb = tx_urb;
+}
+
+/* mpc8xx_udc_ep0_rx
+ *
+ * Receive ep0/control USB data. Parse and possibly send a response.
+ */
+static void mpc8xx_udc_ep0_rx(volatile cbd_t * rx_cbdp)
+{
+ if(rx_cbdp->cbd_sc&RX_BD_PID_SETUP){
+
+ /* Unconditionally accept SETUP packets */
+ if(mpc8xx_udc_ep0_rx_setup(rx_cbdp)){
+ mpc8xx_udc_stall (0);
+ }
+
+ } else {
+
+ mpc8xx_udc_clear_rxbd(rx_cbdp);
+
+ if((rx_cbdp->cbd_datlen-2)){
+ /* SETUP with a DATA phase
+ * outside of SETUP packet.
+ * Reply with STALL.
+ */
+ mpc8xx_udc_stall (0);
+ }
+ }
+}
+
+/* mpc8xx_udc_epn_rx
+ *
+ * Receive some data from cbd into USB system urb data abstraction
+ * Upper layers should NAK if there is insufficient RX data space
+ */
+static int mpc8xx_udc_epn_rx (unsigned int epid, volatile cbd_t * rx_cbdp)
+{
+ struct usb_endpoint_instance *epi = 0;
+ struct urb *urb = 0;
+ unsigned int x = 0;
+
+ if(epid >= MAX_ENDPOINTS || !rx_cbdp->cbd_datlen){
+ return 0;
+ }
+
+ /* USB 2.0 PDF section 8.6.4
+ * Discard data with invalid PID it is a resend.
+ */
+ if(ep_ref[epid].pid!=(rx_cbdp->cbd_sc&0xC0)){
+ return 1;
+ }
+ TOGGLE_RX_PID(ep_ref[epid].pid);
+
+ epi = &udc_device->bus->endpoint_array[epid];
+ urb = epi->rcv_urb;
+
+ for(; x<(rx_cbdp->cbd_datlen-2); x++){
+ *((unsigned char*)(urb->buffer + urb->actual_length +x)) =
+ *((unsigned char*)(rx_cbdp->cbd_bufaddr+x));
+ }
+
+ if(x){
+ usbd_rcv_complete (epi, x, 0);
+ if(ep_ref[epid].urb->status == RECV_ERROR){
+ DBG("RX error unset NAK\n");
+ udc_unset_nak(epid);
+ }
+ }
+ return x;
+}
+
+/* mpc8xx_udc_clock_init
+ *
+ * Obtain a clock reference for Full Speed Signaling
+ */
+static void mpc8xx_udc_clock_init (volatile immap_t * immr,
+ volatile cpm8xx_t * cp)
+{
+
+#if defined(CFG_USB_EXTC_CLK)
+
+ /* This has been tested with a 48MHz crystal on CLK6 */
+ switch(CFG_USB_EXTC_CLK){
+ case 1:
+ immr->im_ioport.iop_papar|= 0x0100;
+ immr->im_ioport.iop_padir&= ~0x0100;
+ cp->cp_sicr|= 0x24;
+ break;
+ case 2:
+ immr->im_ioport.iop_papar|= 0x0200;
+ immr->im_ioport.iop_padir&= ~0x0200;
+ cp->cp_sicr|= 0x2D;
+ break;
+ case 3:
+ immr->im_ioport.iop_papar|= 0x0400;
+ immr->im_ioport.iop_padir&= ~0x0400;
+ cp->cp_sicr|= 0x36;
+ break;
+ case 4:
+ immr->im_ioport.iop_papar|= 0x0800;
+ immr->im_ioport.iop_padir&= ~0x0800;
+ cp->cp_sicr|= 0x3F;
+ break;
+ default:
+ udc_state = STATE_ERROR;
+ break;
+ }
+
+#elif defined(CFG_USB_BRGCLK)
+
+ /* This has been tested with brgclk == 50MHz */
+ DECLARE_GLOBAL_DATA_PTR;
+ int divisor = 0;
+
+ if(gd->cpu_clk<48000000L){
+ ERR("brgclk is too slow for full-speed USB!\n");
+ udc_state = STATE_ERROR;
+ return;
+ }
+
+ /* Assume the brgclk is 'good enough', we want !(gd->cpu_clk%48Mhz)
+ * but, can /probably/ live with close-ish alternative rates.
+ */
+ divisor = (gd->cpu_clk/48000000L)-1;
+ cp->cp_sicr &= ~0x0000003F;
+
+ switch(CFG_USB_BRGCLK){
+ case 1:
+ cp->cp_brgc1 |= (divisor|CPM_BRG_EN);
+ cp->cp_sicr &= ~0x2F;
+ break;
+ case 2:
+ cp->cp_brgc2 |= (divisor|CPM_BRG_EN);
+ cp->cp_sicr |= 0x00000009;
+ break;
+ case 3:
+ cp->cp_brgc3 |= (divisor|CPM_BRG_EN);
+ cp->cp_sicr |= 0x00000012;
+ break;
+ case 4:
+ cp->cp_brgc4 = (divisor|CPM_BRG_EN);
+ cp->cp_sicr |= 0x0000001B;
+ break;
+ default:
+ udc_state = STATE_ERROR;
+ break;
+ }
+
+#else
+ #error "CFG_USB_EXTC_CLK or CFG_USB_BRGCLK must be defined"
+#endif
+
+}
+
+/* mpc8xx_udc_cbd_attach
+ *
+ * attach a cbd to and endpoint
+ */
+static void mpc8xx_udc_cbd_attach (int ep, uchar tx_size, uchar rx_size)
+{
+
+ if (!tx_cbd[ep] || !rx_cbd[ep] || ep >= MAX_ENDPOINTS){
+ udc_state = STATE_ERROR;
+ return;
+ }
+
+ if (tx_size>USB_MAX_PKT || rx_size>USB_MAX_PKT ||
+ (!tx_size && !rx_size)){
+ udc_state = STATE_ERROR;
+ return;
+ }
+
+ /* Attach CBD to appropiate Parameter RAM Endpoint data structure */
+ if(rx_size){
+ endpoints[ep]->rbase = (u32)rx_cbd[rx_ct];
+ endpoints[ep]->rbptr = (u32)rx_cbd[rx_ct];
+ rx_ct++;
+
+ if(!ep){
+
+ endpoints[ep]->rbptr = (u32)rx_cbd[rx_ct];
+ rx_cbd[rx_ct]->cbd_sc |= RX_BD_W;
+ rx_ct++;
+
+ }else{
+ rx_ct += 2;
+ endpoints[ep]->rbptr = (u32)rx_cbd[rx_ct];
+ rx_cbd[rx_ct]->cbd_sc |= RX_BD_W;
+ rx_ct++;
+ }
+
+ /* Where we expect to RX data on this endpoint */
+ ep_ref[ep].prx = rx_cbd[rx_ct-1];
+ }else{
+
+ ep_ref[ep].prx = 0;
+ endpoints[ep]->rbase = 0;
+ endpoints[ep]->rbptr = 0;
+ }
+
+ if(tx_size){
+ endpoints[ep]->tbase = (u32)tx_cbd[tx_ct];
+ endpoints[ep]->tbptr = (u32)tx_cbd[tx_ct];
+ tx_ct++;
+ }else{
+ endpoints[ep]->tbase = 0;
+ endpoints[ep]->tbptr = 0;
+ }
+
+ endpoints[ep]->tstate = 0;
+ endpoints[ep]->tbcnt = 0;
+ endpoints[ep]->mrblr = EP_MAX_PKT;
+ endpoints[ep]->rfcr = 0x18;
+ endpoints[ep]->tfcr = 0x18;
+ ep_ref[ep].sc |= EP_ATTACHED;
+
+ DBG("ep %d rbase 0x%08x rbptr 0x%08x tbase 0x%08x tbptr 0x%08x prx = %p\n",
+ ep, endpoints[ep]->rbase, endpoints[ep]->rbptr, endpoints[ep]->tbase,
+ endpoints[ep]->tbptr, ep_ref[ep].prx);
+
+ return;
+}
+
+/* mpc8xx_udc_cbd_init
+ *
+ * Allocate space for a cbd and allocate TX/RX data space
+ */
+static void mpc8xx_udc_cbd_init (void)
+{
+ int i = 0;
+
+ for(; i<TX_RING_SIZE; i++){
+ tx_cbd[i]= (cbd_t*)
+ mpc8xx_udc_alloc(sizeof(cbd_t), sizeof(int));
+ }
+
+ for(i=0; i<RX_RING_SIZE; i++){
+ rx_cbd[i]= (cbd_t*)
+ mpc8xx_udc_alloc(sizeof(cbd_t),sizeof(int));
+ }
+
+ for(i=0; i< TX_RING_SIZE; i++){
+ tx_cbd[i]->cbd_bufaddr =
+ mpc8xx_udc_alloc(EP_MAX_PKT, sizeof(int));
+
+ tx_cbd[i]->cbd_sc = (TX_BD_I | TX_BD_W);
+ tx_cbd[i]->cbd_datlen = 0x0000;
+ }
+
+
+ for(i=0; i< RX_RING_SIZE; i++){
+ rx_cbd[i]->cbd_bufaddr =
+ mpc8xx_udc_alloc(EP_MAX_PKT, sizeof(int));
+ rx_cbd[i]->cbd_sc = (RX_BD_I | RX_BD_E);
+ rx_cbd[i]->cbd_datlen = 0x0000;
+
+ }
+
+ return;
+}
+
+/* mpc8xx_udc_endpoint_init
+ *
+ * Attach an endpoint to some dpram
+ */
+static void mpc8xx_udc_endpoint_init (void)
+{
+ int i = 0;
+
+ for(; i<MAX_ENDPOINTS; i++){
+ endpoints[i]= (usb_epb_t*)
+ mpc8xx_udc_alloc(sizeof(usb_epb_t) , 32);
+ }
+}
+
+/* mpc8xx_udc_alloc
+ *
+ * Grab the address of some dpram
+ */
+static u32 mpc8xx_udc_alloc (u32 data_size, u32 alignment)
+{
+ u32 retaddr = address_base;
+
+ while(retaddr%alignment){
+ retaddr++;
+ }
+ address_base+= data_size;
+
+ return retaddr;
+}
+
+#endif /* CONFIG_MPC885_FAMILY && CONFIG_USB_DEVICE) */
diff --git a/drivers/usbdcore_omap1510.c b/drivers/usbdcore_omap1510.c
index 1d54a63..83d898f 100644
--- a/drivers/usbdcore_omap1510.c
+++ b/drivers/usbdcore_omap1510.c
@@ -645,7 +645,7 @@ static void omap1510_udc_state_changed (void)
static void omap1510_udc_setup (struct usb_endpoint_instance *endpoint)
{
UDCDBG ("-> Entering device setup");
-
+
do {
const int setup_pktsize = 8;
unsigned char *datap =
@@ -1517,4 +1517,31 @@ void udc_startup_events (struct usb_device_instance *device)
udc_enable (device);
}
+/**
+ * udc_irq - do pseudo interrupts
+ */
+void udc_irq(void)
+{
+ /* Loop while we have interrupts.
+ * If we don't do this, the input chain
+ * polling delay is likely to miss
+ * host requests.
+ */
+ while (inw (UDC_IRQ_SRC) & ~UDC_SOF_Flg) {
+ /* Handle any new IRQs */
+ omap1510_udc_irq ();
+ omap1510_udc_noniso_irq ();
+ }
+}
+
+/* Flow control */
+void udc_set_nak(int epid)
+{
+ /* TODO: implement this functionality in omap1510 */
+}
+
+void udc_unset_nak (int epid)
+{
+ /* TODO: implement this functionality in omap1510 */
+}
#endif
diff --git a/drivers/usbtty.c b/drivers/usbtty.c
index ce4a12e..ed96999 100644
--- a/drivers/usbtty.c
+++ b/drivers/usbtty.c
@@ -1,6 +1,9 @@
/*
* (C) Copyright 2003
* Gerry Hamel, geh@ti.com, Texas Instruments
+ *
+ * (C) Copyright 2006
+ * Bryan O'Donoghue, bodonoghue@codehermit.ie
*
* 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
@@ -25,20 +28,42 @@
#include <circbuf.h>
#include <devices.h>
#include "usbtty.h"
+#include "usb_cdc_acm.h"
+#include "usbdescriptors.h"
+#include <config.h> /* If defined, override Linux identifiers with
+ * vendor specific ones */
#if 0
-#define TTYDBG(fmt,args...) serial_printf("[%s] %s %d: "fmt, __FILE__,__FUNCTION__,__LINE__,##args)
+#define TTYDBG(fmt,args...)\
+ serial_printf("[%s] %s %d: "fmt, __FILE__,__FUNCTION__,__LINE__,##args)
#else
#define TTYDBG(fmt,args...) do{}while(0)
#endif
-#if 0
-#define TTYERR(fmt,args...) serial_printf("ERROR![%s] %s %d: "fmt, __FILE__,__FUNCTION__,__LINE__,##args)
+#if 1
+#define TTYERR(fmt,args...)\
+ serial_printf("ERROR![%s] %s %d: "fmt, __FILE__,__FUNCTION__,\
+ __LINE__,##args)
#else
#define TTYERR(fmt,args...) do{}while(0)
#endif
/*
+ * Defines
+ */
+#define NUM_CONFIGS 1
+#define MAX_INTERFACES 2
+#define NUM_ENDPOINTS 3
+#define ACM_TX_ENDPOINT 3
+#define ACM_RX_ENDPOINT 2
+#define GSERIAL_TX_ENDPOINT 2
+#define GSERIAL_RX_ENDPOINT 1
+#define NUM_ACM_INTERFACES 2
+#define NUM_GSERIAL_INTERFACES 1
+#define CONFIG_USBD_DATA_INTERFACE_STR "Bulk Data Interface"
+#define CONFIG_USBD_CTRL_INTERFACE_STR "Control Interface"
+
+/*
* Buffers to hold input and output data
*/
#define USBTTY_BUFFER_SIZE 256
@@ -50,157 +75,336 @@ static circbuf_t usbtty_output;
* Instance variables
*/
static device_t usbttydev;
-static struct usb_device_instance device_instance[1];
-static struct usb_bus_instance bus_instance[1];
+static struct usb_device_instance device_instance[1];
+static struct usb_bus_instance bus_instance[1];
static struct usb_configuration_instance config_instance[NUM_CONFIGS];
-static struct usb_interface_instance interface_instance[NUM_INTERFACES];
-static struct usb_alternate_instance alternate_instance[NUM_INTERFACES];
-static struct usb_endpoint_instance endpoint_instance[NUM_ENDPOINTS+1]; /* one extra for control endpoint */
-
-/*
- * Static allocation of urbs
- */
-#define RECV_ENDPOINT 1
-#define TX_ENDPOINT 2
+static struct usb_interface_instance interface_instance[MAX_INTERFACES];
+static struct usb_alternate_instance alternate_instance[MAX_INTERFACES];
+/* one extra for control endpoint */
+static struct usb_endpoint_instance endpoint_instance[NUM_ENDPOINTS+1];
/*
* Global flag
*/
int usbtty_configured_flag = 0;
-
/*
* Serial number
*/
static char serial_number[16];
+
/*
- * Descriptors
+ * Descriptors, Strings, Local variables.
*/
+
+/* defined and used by usbdcore_ep0.c */
+extern struct usb_string_descriptor **usb_strings;
+
+/* Indicies, References */
+static unsigned short rx_endpoint = 0;
+static unsigned short tx_endpoint = 0;
+static unsigned short interface_count = 0;
+static struct usb_string_descriptor *usbtty_string_table[STR_COUNT];
+
+/* USB Descriptor Strings */
static u8 wstrLang[4] = {4,USB_DT_STRING,0x9,0x4};
static u8 wstrManufacturer[2 + 2*(sizeof(CONFIG_USBD_MANUFACTURER)-1)];
static u8 wstrProduct[2 + 2*(sizeof(CONFIG_USBD_PRODUCT_NAME)-1)];
static u8 wstrSerial[2 + 2*(sizeof(serial_number) - 1)];
static u8 wstrConfiguration[2 + 2*(sizeof(CONFIG_USBD_CONFIGURATION_STR)-1)];
-static u8 wstrInterface[2 + 2*(sizeof(CONFIG_USBD_INTERFACE_STR)-1)];
-
-static struct usb_string_descriptor *usbtty_string_table[] = {
- (struct usb_string_descriptor*)wstrLang,
- (struct usb_string_descriptor*)wstrManufacturer,
- (struct usb_string_descriptor*)wstrProduct,
- (struct usb_string_descriptor*)wstrSerial,
- (struct usb_string_descriptor*)wstrConfiguration,
- (struct usb_string_descriptor*)wstrInterface
-};
-extern struct usb_string_descriptor **usb_strings; /* defined and used by omap1510_ep0.c */
+static u8 wstrDataInterface[2 + 2*(sizeof(CONFIG_USBD_DATA_INTERFACE_STR)-1)];
+static u8 wstrCtrlInterface[2 + 2*(sizeof(CONFIG_USBD_DATA_INTERFACE_STR)-1)];
+/* Standard USB Data Structures */
+static struct usb_interface_descriptor interface_descriptors[MAX_INTERFACES];
+static struct usb_endpoint_descriptor *ep_descriptor_ptrs[NUM_ENDPOINTS];
+static struct usb_configuration_descriptor *configuration_descriptor = 0;
static struct usb_device_descriptor device_descriptor = {
- bLength: sizeof(struct usb_device_descriptor),
- bDescriptorType: USB_DT_DEVICE,
- bcdUSB: USB_BCD_VERSION,
- bDeviceClass: USBTTY_DEVICE_CLASS,
- bDeviceSubClass: USBTTY_DEVICE_SUBCLASS,
- bDeviceProtocol: USBTTY_DEVICE_PROTOCOL,
- bMaxPacketSize0: EP0_MAX_PACKET_SIZE,
- idVendor: CONFIG_USBD_VENDORID,
- idProduct: CONFIG_USBD_PRODUCTID,
- bcdDevice: USBTTY_BCD_DEVICE,
- iManufacturer: STR_MANUFACTURER,
- iProduct: STR_PRODUCT,
- iSerialNumber: STR_SERIAL,
- bNumConfigurations: NUM_CONFIGS
- };
-static struct usb_configuration_descriptor config_descriptors[NUM_CONFIGS] = {
- {
- bLength: sizeof(struct usb_configuration_descriptor),
- bDescriptorType: USB_DT_CONFIG,
- wTotalLength: (sizeof(struct usb_configuration_descriptor)*NUM_CONFIGS) +
- (sizeof(struct usb_interface_descriptor)*NUM_INTERFACES) +
- (sizeof(struct usb_endpoint_descriptor)*NUM_ENDPOINTS),
- bNumInterfaces: NUM_INTERFACES,
- bConfigurationValue: 1,
- iConfiguration: STR_CONFIG,
- bmAttributes: BMATTRIBUTE_SELF_POWERED | BMATTRIBUTE_RESERVED,
- bMaxPower: USBTTY_MAXPOWER
- },
-};
-static struct usb_interface_descriptor interface_descriptors[NUM_INTERFACES] = {
- {
- bLength: sizeof(struct usb_interface_descriptor),
- bDescriptorType: USB_DT_INTERFACE,
- bInterfaceNumber: 0,
- bAlternateSetting: 0,
- bNumEndpoints: NUM_ENDPOINTS,
- bInterfaceClass: USBTTY_INTERFACE_CLASS,
- bInterfaceSubClass: USBTTY_INTERFACE_SUBCLASS,
- bInterfaceProtocol: USBTTY_INTERFACE_PROTOCOL,
- iInterface: STR_INTERFACE
- },
+ .bLength = sizeof(struct usb_device_descriptor),
+ .bDescriptorType = USB_DT_DEVICE,
+ .bcdUSB = cpu_to_le16(USB_BCD_VERSION),
+ .bDeviceSubClass = 0x00,
+ .bDeviceProtocol = 0x00,
+ .bMaxPacketSize0 = EP0_MAX_PACKET_SIZE,
+ .idVendor = cpu_to_le16(CONFIG_USBD_VENDORID),
+ .bcdDevice = cpu_to_le16(USBTTY_BCD_DEVICE),
+ .iManufacturer = STR_MANUFACTURER,
+ .iProduct = STR_PRODUCT,
+ .iSerialNumber = STR_SERIAL,
+ .bNumConfigurations = NUM_CONFIGS
};
-static struct usb_endpoint_descriptor ep_descriptors[NUM_ENDPOINTS] = {
- {
- bLength: sizeof(struct usb_endpoint_descriptor),
- bDescriptorType: USB_DT_ENDPOINT,
- bEndpointAddress: CONFIG_USBD_SERIAL_OUT_ENDPOINT | USB_DIR_OUT,
- bmAttributes: USB_ENDPOINT_XFER_BULK,
- wMaxPacketSize: CONFIG_USBD_SERIAL_OUT_PKTSIZE,
- bInterval: 0
- },
- {
- bLength: sizeof(struct usb_endpoint_descriptor),
- bDescriptorType: USB_DT_ENDPOINT,
- bEndpointAddress: CONFIG_USBD_SERIAL_IN_ENDPOINT | USB_DIR_IN,
- bmAttributes: USB_ENDPOINT_XFER_BULK,
- wMaxPacketSize: CONFIG_USBD_SERIAL_IN_PKTSIZE,
- bInterval: 0
- },
- {
- bLength: sizeof(struct usb_endpoint_descriptor),
- bDescriptorType: USB_DT_ENDPOINT,
- bEndpointAddress: CONFIG_USBD_SERIAL_INT_ENDPOINT | USB_DIR_IN,
- bmAttributes: USB_ENDPOINT_XFER_INT,
- wMaxPacketSize: CONFIG_USBD_SERIAL_INT_PKTSIZE,
- bInterval: 0
- },
-};
-static struct usb_endpoint_descriptor *ep_descriptor_ptrs[NUM_ENDPOINTS] = {
- &(ep_descriptors[0]),
- &(ep_descriptors[1]),
- &(ep_descriptors[2]),
+
+
+/*
+ * Static CDC ACM specific descriptors
+ */
+
+struct acm_config_desc {
+ struct usb_configuration_descriptor configuration_desc;
+
+ /* Master Interface */
+ struct usb_interface_descriptor interface_desc;
+
+ struct usb_class_header_function_descriptor usb_class_header;
+ struct usb_class_call_management_descriptor usb_class_call_mgt;
+ struct usb_class_abstract_control_descriptor usb_class_acm;
+ struct usb_class_union_function_descriptor usb_class_union;
+ struct usb_endpoint_descriptor notification_endpoint;
+
+ /* Slave Interface */
+ struct usb_interface_descriptor data_class_interface;
+ struct usb_endpoint_descriptor
+ data_endpoints[NUM_ENDPOINTS-1] __attribute__((packed));
+} __attribute__((packed));
+
+static struct acm_config_desc acm_configuration_descriptors[NUM_CONFIGS] = {
+ {
+ .configuration_desc ={
+ .bLength =
+ sizeof(struct usb_configuration_descriptor),
+ .bDescriptorType = USB_DT_CONFIG,
+ .wTotalLength =
+ cpu_to_le16(sizeof(struct acm_config_desc)),
+ .bNumInterfaces = NUM_ACM_INTERFACES,
+ .bConfigurationValue = 1,
+ .iConfiguration = STR_CONFIG,
+ .bmAttributes =
+ BMATTRIBUTE_SELF_POWERED|BMATTRIBUTE_RESERVED,
+ .bMaxPower = USBTTY_MAXPOWER
+ },
+ /* Interface 1 */
+ .interface_desc = {
+ .bLength = sizeof(struct usb_interface_descriptor),
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 0x01,
+ .bInterfaceClass =
+ COMMUNICATIONS_INTERFACE_CLASS_CONTROL,
+ .bInterfaceSubClass = COMMUNICATIONS_ACM_SUBCLASS,
+ .bInterfaceProtocol = COMMUNICATIONS_V25TER_PROTOCOL,
+ .iInterface = STR_CTRL_INTERFACE,
+ },
+ .usb_class_header = {
+ .bFunctionLength =
+ sizeof(struct usb_class_header_function_descriptor),
+ .bDescriptorType = CS_INTERFACE,
+ .bDescriptorSubtype = USB_ST_HEADER,
+ .bcdCDC = cpu_to_le16(110),
+ },
+ .usb_class_call_mgt = {
+ .bFunctionLength =
+ sizeof(struct usb_class_call_management_descriptor),
+ .bDescriptorType = CS_INTERFACE,
+ .bDescriptorSubtype = USB_ST_CMF,
+ .bmCapabilities = 0x00,
+ .bDataInterface = 0x01,
+ },
+ .usb_class_acm = {
+ .bFunctionLength =
+ sizeof(struct usb_class_abstract_control_descriptor),
+ .bDescriptorType = CS_INTERFACE,
+ .bDescriptorSubtype = USB_ST_ACMF,
+ .bmCapabilities = 0x00,
+ },
+ .usb_class_union = {
+ .bFunctionLength =
+ sizeof(struct usb_class_union_function_descriptor),
+ .bDescriptorType = CS_INTERFACE,
+ .bDescriptorSubtype = USB_ST_UF,
+ .bMasterInterface = 0x00,
+ .bSlaveInterface0 = 0x01,
+ },
+ .notification_endpoint = {
+ .bLength =
+ sizeof(struct usb_endpoint_descriptor),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0x01 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize
+ = cpu_to_le16(CONFIG_USBD_SERIAL_INT_PKTSIZE),
+ .bInterval = 0xFF,
+ },
+
+ /* Interface 2 */
+ .data_class_interface = {
+ .bLength =
+ sizeof(struct usb_interface_descriptor),
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0x01,
+ .bAlternateSetting = 0x00,
+ .bNumEndpoints = 0x02,
+ .bInterfaceClass =
+ COMMUNICATIONS_INTERFACE_CLASS_DATA,
+ .bInterfaceSubClass = DATA_INTERFACE_SUBCLASS_NONE,
+ .bInterfaceProtocol = DATA_INTERFACE_PROTOCOL_NONE,
+ .iInterface = STR_DATA_INTERFACE,
+ },
+ .data_endpoints = {
+ {
+ .bLength =
+ sizeof(struct usb_endpoint_descriptor),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0x02 | USB_DIR_OUT,
+ .bmAttributes =
+ USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize =
+ cpu_to_le16(CONFIG_USBD_SERIAL_BULK_PKTSIZE),
+ .bInterval = 0xFF,
+ },
+ {
+ .bLength =
+ sizeof(struct usb_endpoint_descriptor),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0x03 | USB_DIR_IN,
+ .bmAttributes =
+ USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize =
+ cpu_to_le16(CONFIG_USBD_SERIAL_BULK_PKTSIZE),
+ .bInterval = 0xFF,
+ },
+ },
+ },
+};
+
+static struct rs232_emu rs232_desc={
+ .dter = 115200,
+ .stop_bits = 0x00,
+ .parity = 0x00,
+ .data_bits = 0x08
};
-/* utility function for converting char* to wide string used by USB */
-static void str2wide (char *str, u16 * wide)
-{
- int i;
- for (i = 0; i < strlen (str) && str[i]; i++)
- wide[i] = (u16) str[i];
-}
+/*
+ * Static Generic Serial specific data
+ */
+
+
+struct gserial_config_desc {
+
+ struct usb_configuration_descriptor configuration_desc;
+ struct usb_interface_descriptor
+ interface_desc[NUM_GSERIAL_INTERFACES] __attribute__((packed));
+ struct usb_endpoint_descriptor
+ data_endpoints[NUM_ENDPOINTS] __attribute__((packed));
+
+} __attribute__((packed));
+
+static struct gserial_config_desc
+gserial_configuration_descriptors[NUM_CONFIGS] ={
+ {
+ .configuration_desc ={
+ .bLength = sizeof(struct usb_configuration_descriptor),
+ .bDescriptorType = USB_DT_CONFIG,
+ .wTotalLength =
+ cpu_to_le16(sizeof(struct gserial_config_desc)),
+ .bNumInterfaces = NUM_GSERIAL_INTERFACES,
+ .bConfigurationValue = 1,
+ .iConfiguration = STR_CONFIG,
+ .bmAttributes =
+ BMATTRIBUTE_SELF_POWERED|BMATTRIBUTE_RESERVED,
+ .bMaxPower = USBTTY_MAXPOWER
+ },
+ .interface_desc = {
+ {
+ .bLength =
+ sizeof(struct usb_interface_descriptor),
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = NUM_ENDPOINTS,
+ .bInterfaceClass =
+ COMMUNICATIONS_INTERFACE_CLASS_VENDOR,
+ .bInterfaceSubClass =
+ COMMUNICATIONS_NO_SUBCLASS,
+ .bInterfaceProtocol =
+ COMMUNICATIONS_NO_PROTOCOL,
+ .iInterface = STR_DATA_INTERFACE
+ },
+ },
+ .data_endpoints = {
+ {
+ .bLength =
+ sizeof(struct usb_endpoint_descriptor),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0x01 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize =
+ cpu_to_le16(CONFIG_USBD_SERIAL_OUT_PKTSIZE),
+ .bInterval= 0xFF,
+ },
+ {
+ .bLength =
+ sizeof(struct usb_endpoint_descriptor),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0x02 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize =
+ cpu_to_le16(CONFIG_USBD_SERIAL_IN_PKTSIZE),
+ .bInterval = 0xFF,
+ },
+ {
+ .bLength =
+ sizeof(struct usb_endpoint_descriptor),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0x03 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize =
+ cpu_to_le16(CONFIG_USBD_SERIAL_INT_PKTSIZE),
+ .bInterval = 0xFF,
+ },
+ },
+ },
+};
/*
- * Prototypes
+ * Static Function Prototypes
*/
+
static void usbtty_init_strings (void);
static void usbtty_init_instances (void);
static void usbtty_init_endpoints (void);
-
+static void usbtty_init_terminal_type(short type);
static void usbtty_event_handler (struct usb_device_instance *device,
- usb_device_event_t event, int data);
+ usb_device_event_t event, int data);
+static int usbtty_cdc_setup(struct usb_device_request *request,
+ struct urb *urb);
static int usbtty_configured (void);
-
static int write_buffer (circbuf_t * buf);
static int fill_buffer (circbuf_t * buf);
void usbtty_poll (void);
-static void pretend_interrupts (void);
+/* utility function for converting char* to wide string used by USB */
+static void str2wide (char *str, u16 * wide)
+{
+ int i;
+ for (i = 0; i < strlen (str) && str[i]; i++){
+ #if defined(__LITTLE_ENDIAN__)
+ wide[i] = (u16) str[i];
+ #elif defined(__BIG_ENDIAN__)
+ wide[i] = ((u16)(str[i])<<8);
+ #else
+ #error "__LITTLE_ENDIAN__ or __BIG_ENDIAN__ undefined"
+ #endif
+ }
+}
/*
* Test whether a character is in the RX buffer
*/
+
int usbtty_tstc (void)
{
+ struct usb_endpoint_instance *endpoint =
+ &endpoint_instance[rx_endpoint];
+
+ /* If no input data exists, allow more RX to be accepted */
+ if(usbtty_input.size <= 0){
+ udc_unset_nak(endpoint->endpoint_address&0x03);
+ }
+
usbtty_poll ();
return (usbtty_input.size > 0);
}
@@ -210,15 +414,21 @@ int usbtty_tstc (void)
* otherwise. When the function is succesfull, the character read is
* written into its argument c.
*/
+
int usbtty_getc (void)
{
char c;
+ struct usb_endpoint_instance *endpoint =
+ &endpoint_instance[rx_endpoint];
while (usbtty_input.size <= 0) {
+ udc_unset_nak(endpoint->endpoint_address&0x03);
usbtty_poll ();
}
buf_pop (&usbtty_input, &c, 1);
+ udc_set_nak(endpoint->endpoint_address&0x03);
+
return c;
}
@@ -238,7 +448,6 @@ void usbtty_putc (const char c)
}
}
-
/* usbtty_puts() helper function for finding the next '\n' in a string */
static int next_nl_pos (const char *s)
{
@@ -252,8 +461,9 @@ static int next_nl_pos (const char *s)
}
/*
- * Output a string to the usb client port.
+ * Output a string to the usb client port - implementing flow control
*/
+
static void __usbtty_puts (const char *str, int len)
{
int maxlen = usbtty_output.totalsize;
@@ -261,22 +471,19 @@ static void __usbtty_puts (const char *str, int len)
/* break str into chunks < buffer size, if needed */
while (len > 0) {
- space = maxlen - usbtty_output.size;
+ usbtty_poll ();
+ space = maxlen - usbtty_output.size;
/* Empty buffer here, if needed, to ensure space... */
- if (space <= 0) {
+ if (space) {
write_buffer (&usbtty_output);
- space = maxlen - usbtty_output.size;
- if (space <= 0) {
- space = len; /* allow old data to be overwritten. */
- }
- }
-
- n = MIN (space, MIN (len, maxlen));
- buf_push (&usbtty_output, str, n);
+
+ n = MIN (space, MIN (len, maxlen));
+ buf_push (&usbtty_output, str, n);
- str += n;
- len -= n;
+ str += n;
+ len -= n;
+ }
}
}
@@ -313,8 +520,10 @@ int drv_usbtty_init (void)
{
int rc;
char * sn;
+ char * tt;
int snlen;
+ /* Ger seiral number */
if (!(sn = getenv("serial#"))) {
sn = "000000000000";
}
@@ -327,6 +536,14 @@ int drv_usbtty_init (void)
memcpy (serial_number, sn, snlen);
serial_number[snlen] = '\0';
+ /* Decide on which type of UDC device to be.
+ */
+
+ if(!(tt = getenv("usbtty"))) {
+ tt = "generic";
+ }
+ usbtty_init_terminal_type(strcmp(tt,"cdc_acm"));
+
/* prepare buffers... */
buf_init (&usbtty_input, USBTTY_BUFFER_SIZE);
buf_init (&usbtty_output, USBTTY_BUFFER_SIZE);
@@ -337,7 +554,7 @@ int drv_usbtty_init (void)
usbtty_init_strings ();
usbtty_init_instances ();
- udc_startup_events (device_instance); /* Enable our device, initialize udc pointers */
+ udc_startup_events (device_instance);/* Enable dev, init udc pointers */
udc_connect (); /* Enable pullup for host detection */
usbtty_init_endpoints ();
@@ -362,34 +579,52 @@ static void usbtty_init_strings (void)
{
struct usb_string_descriptor *string;
+ usbtty_string_table[STR_LANG] =
+ (struct usb_string_descriptor*)wstrLang;
+
string = (struct usb_string_descriptor *) wstrManufacturer;
- string->bLength = sizeof (wstrManufacturer);
+ string->bLength = sizeof(wstrManufacturer);
string->bDescriptorType = USB_DT_STRING;
str2wide (CONFIG_USBD_MANUFACTURER, string->wData);
+ usbtty_string_table[STR_MANUFACTURER]=string;
+
string = (struct usb_string_descriptor *) wstrProduct;
- string->bLength = sizeof (wstrProduct);
+ string->bLength = sizeof(wstrProduct);
string->bDescriptorType = USB_DT_STRING;
str2wide (CONFIG_USBD_PRODUCT_NAME, string->wData);
+ usbtty_string_table[STR_PRODUCT]=string;
+
string = (struct usb_string_descriptor *) wstrSerial;
- string->bLength = 2 + 2*strlen(serial_number);
+ string->bLength = sizeof(serial_number);
string->bDescriptorType = USB_DT_STRING;
str2wide (serial_number, string->wData);
+ usbtty_string_table[STR_SERIAL]=string;
+
string = (struct usb_string_descriptor *) wstrConfiguration;
- string->bLength = sizeof (wstrConfiguration);
+ string->bLength = sizeof(wstrConfiguration);
string->bDescriptorType = USB_DT_STRING;
str2wide (CONFIG_USBD_CONFIGURATION_STR, string->wData);
+ usbtty_string_table[STR_CONFIG]=string;
+
+
+ string = (struct usb_string_descriptor *) wstrDataInterface;
+ string->bLength = sizeof(wstrDataInterface);
+ string->bDescriptorType = USB_DT_STRING;
+ str2wide (CONFIG_USBD_DATA_INTERFACE_STR, string->wData);
+ usbtty_string_table[STR_DATA_INTERFACE]=string;
- string = (struct usb_string_descriptor *) wstrInterface;
- string->bLength = sizeof (wstrInterface);
+ string = (struct usb_string_descriptor *) wstrCtrlInterface;
+ string->bLength = sizeof(wstrCtrlInterface);
string->bDescriptorType = USB_DT_STRING;
- str2wide (CONFIG_USBD_INTERFACE_STR, string->wData);
+ str2wide (CONFIG_USBD_CTRL_INTERFACE_STR, string->wData);
+ usbtty_string_table[STR_CTRL_INTERFACE]=string;
/* Now, initialize the string table for ep0 handling */
usb_strings = usbtty_string_table;
-}
+}
static void usbtty_init_instances (void)
{
@@ -400,6 +635,7 @@ static void usbtty_init_instances (void)
device_instance->device_state = STATE_INIT;
device_instance->device_descriptor = &device_descriptor;
device_instance->event = usbtty_event_handler;
+ device_instance->cdc_recv_setup = usbtty_cdc_setup;
device_instance->bus = bus_instance;
device_instance->configurations = NUM_CONFIGS;
device_instance->configuration_instance_array = config_instance;
@@ -415,8 +651,8 @@ static void usbtty_init_instances (void)
/* configuration instance */
memset (config_instance, 0,
sizeof (struct usb_configuration_instance));
- config_instance->interfaces = NUM_INTERFACES;
- config_instance->configuration_descriptor = config_descriptors;
+ config_instance->interfaces = interface_count;
+ config_instance->configuration_descriptor = configuration_descriptor;
config_instance->interface_instance_array = interface_instance;
/* interface instance */
@@ -447,17 +683,22 @@ static void usbtty_init_instances (void)
sizeof (struct usb_endpoint_instance));
endpoint_instance[i].endpoint_address =
- ep_descriptors[i - 1].bEndpointAddress;
+ ep_descriptor_ptrs[i - 1]->bEndpointAddress;
- endpoint_instance[i].rcv_packetSize =
- ep_descriptors[i - 1].wMaxPacketSize;
endpoint_instance[i].rcv_attributes =
- ep_descriptors[i - 1].bmAttributes;
+ ep_descriptor_ptrs[i - 1]->bmAttributes;
+
+ endpoint_instance[i].rcv_packetSize =
+ le16_to_cpu(ep_descriptor_ptrs[i - 1]->wMaxPacketSize);
+
+ endpoint_instance[i].tx_attributes =
+ ep_descriptor_ptrs[i - 1]->bmAttributes;
endpoint_instance[i].tx_packetSize =
- ep_descriptors[i - 1].wMaxPacketSize;
+ le16_to_cpu(ep_descriptor_ptrs[i - 1]->wMaxPacketSize);
+
endpoint_instance[i].tx_attributes =
- ep_descriptors[i - 1].bmAttributes;
+ ep_descriptor_ptrs[i - 1]->bmAttributes;
urb_link_init (&endpoint_instance[i].rcv);
urb_link_init (&endpoint_instance[i].rdy);
@@ -480,13 +721,79 @@ static void usbtty_init_endpoints (void)
int i;
bus_instance->max_endpoints = NUM_ENDPOINTS + 1;
- for (i = 0; i <= NUM_ENDPOINTS; i++) {
+ for (i = 1; i <= NUM_ENDPOINTS; i++) {
udc_setup_ep (device_instance, i, &endpoint_instance[i]);
}
}
+/* usbtty_init_terminal_type
+ *
+ * Do some late binding for our device type.
+ */
+static void usbtty_init_terminal_type(short type)
+{
+ switch(type){
+ /* CDC ACM */
+ case 0:
+ /* Assign endpoint descriptors */
+ ep_descriptor_ptrs[0] =
+ &acm_configuration_descriptors[0].notification_endpoint;
+ ep_descriptor_ptrs[1] =
+ &acm_configuration_descriptors[0].data_endpoints[0];
+ ep_descriptor_ptrs[2] =
+ &acm_configuration_descriptors[0].data_endpoints[1];
+
+ /* Enumerate Device Descriptor */
+ device_descriptor.bDeviceClass =
+ COMMUNICATIONS_DEVICE_CLASS;
+ device_descriptor.idProduct =
+ cpu_to_le16(CONFIG_USBD_PRODUCTID_CDCACM);
+
+ /* Assign endpoint indices */
+ tx_endpoint = ACM_TX_ENDPOINT;
+ rx_endpoint = ACM_RX_ENDPOINT;
+
+ /* Configuration Descriptor */
+ configuration_descriptor =
+ (struct usb_configuration_descriptor*)
+ &acm_configuration_descriptors;
+
+ /* Interface count */
+ interface_count = NUM_ACM_INTERFACES;
+ break;
-/*********************************************************************************/
+ /* BULK IN/OUT & Default */
+ case 1:
+ default:
+ /* Assign endpoint descriptors */
+ ep_descriptor_ptrs[0] =
+ &gserial_configuration_descriptors[0].data_endpoints[0];
+ ep_descriptor_ptrs[1] =
+ &gserial_configuration_descriptors[0].data_endpoints[1];
+ ep_descriptor_ptrs[2] =
+ &gserial_configuration_descriptors[0].data_endpoints[2];
+
+ /* Enumerate Device Descriptor */
+ device_descriptor.bDeviceClass = 0xFF;
+ device_descriptor.idProduct =
+ cpu_to_le16(CONFIG_USBD_PRODUCTID_GSERIAL);
+
+ /* Assign endpoint indices */
+ tx_endpoint = GSERIAL_TX_ENDPOINT;
+ rx_endpoint = GSERIAL_RX_ENDPOINT;
+
+ /* Configuration Descriptor */
+ configuration_descriptor =
+ (struct usb_configuration_descriptor*)
+ &gserial_configuration_descriptors;
+
+ /* Interface count */
+ interface_count = NUM_GSERIAL_INTERFACES;
+ break;
+ }
+}
+
+/******************************************************************************/
static struct urb *next_urb (struct usb_device_instance *device,
struct usb_endpoint_instance *endpoint)
@@ -525,28 +832,40 @@ static int write_buffer (circbuf_t * buf)
if (!usbtty_configured ()) {
return 0;
}
+
+ struct usb_endpoint_instance *endpoint =
+ &endpoint_instance[tx_endpoint];
+ struct urb *current_urb = NULL;
- if (buf->size) {
+ current_urb = next_urb (device_instance, endpoint);
+ /* TX data still exists - send it now
+ */
+ if(endpoint->sent < current_urb->actual_length){
+ if(udc_endpoint_write (endpoint)){
+ /* Write pre-empted by RX */
+ return -1;
+ }
+ }
- struct usb_endpoint_instance *endpoint =
- &endpoint_instance[TX_ENDPOINT];
- struct urb *current_urb = NULL;
+ if (buf->size) {
char *dest;
int space_avail;
int popnum, popped;
int total = 0;
- /* Break buffer into urb sized pieces, and link each to the endpoint */
+ /* Break buffer into urb sized pieces,
+ * and link each to the endpoint
+ */
while (buf->size > 0) {
- current_urb = next_urb (device_instance, endpoint);
+
if (!current_urb) {
TTYERR ("current_urb is NULL, buf->size %d\n",
buf->size);
return total;
}
- dest = current_urb->buffer +
+ dest = (char*)current_urb->buffer +
current_urb->actual_length;
space_avail =
@@ -562,14 +881,19 @@ static int write_buffer (circbuf_t * buf)
current_urb->actual_length += popped;
total += popped;
- /* If endpoint->last == 0, then transfers have not started on this endpoint */
+ /* If endpoint->last == 0, then transfers have
+ * not started on this endpoint
+ */
if (endpoint->last == 0) {
- udc_endpoint_write (endpoint);
+ if(udc_endpoint_write (endpoint)){
+ /* Write pre-empted by RX */
+ return -1;
+ }
}
- } /* end while */
+ }/* end while */
return total;
- } /* end if tx_urb */
+ }
return 0;
}
@@ -577,18 +901,22 @@ static int write_buffer (circbuf_t * buf)
static int fill_buffer (circbuf_t * buf)
{
struct usb_endpoint_instance *endpoint =
- &endpoint_instance[RECV_ENDPOINT];
+ &endpoint_instance[rx_endpoint];
if (endpoint->rcv_urb && endpoint->rcv_urb->actual_length) {
- unsigned int nb = endpoint->rcv_urb->actual_length;
+ unsigned int nb = 0;
char *src = (char *) endpoint->rcv_urb->buffer;
+ unsigned int rx_avail = buf->totalsize - buf->size;
- buf_push (buf, src, nb);
- endpoint->rcv_urb->actual_length = 0;
+ if(rx_avail >= endpoint->rcv_urb->actual_length){
+ nb = endpoint->rcv_urb->actual_length;
+ buf_push (buf, src, nb);
+ endpoint->rcv_urb->actual_length = 0;
+
+ }
return nb;
}
-
return 0;
}
@@ -597,7 +925,7 @@ static int usbtty_configured (void)
return usbtty_configured_flag;
}
-/*********************************************************************************/
+/******************************************************************************/
static void usbtty_event_handler (struct usb_device_instance *device,
usb_device_event_t event, int data)
@@ -619,8 +947,34 @@ static void usbtty_event_handler (struct usb_device_instance *device,
}
}
-/*********************************************************************************/
+/******************************************************************************/
+
+int usbtty_cdc_setup(struct usb_device_request *request, struct urb *urb)
+{
+ switch (request->bRequest){
+ case ACM_SET_CONTROL_LINE_STATE: /* Implies DTE ready */
+ break;
+ case ACM_SEND_ENCAPSULATED_COMMAND : /* Required */
+ break;
+ case ACM_SET_LINE_ENCODING : /* DTE stop/parity bits
+ * per character */
+ break;
+ case ACM_GET_ENCAPSULATED_RESPONSE : /* request response */
+ break;
+ case ACM_GET_LINE_ENCODING : /* request DTE rate,
+ * stop/parity bits */
+ memcpy (urb->buffer , &rs232_desc, sizeof(rs232_desc));
+ urb->actual_length = sizeof(rs232_desc);
+
+ break;
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+/******************************************************************************/
/*
* Since interrupt handling has not yet been implemented, we use this function
@@ -630,36 +984,29 @@ static void usbtty_event_handler (struct usb_device_instance *device,
void usbtty_poll (void)
{
/* New interrupts? */
- pretend_interrupts ();
+ udc_irq();
- /* Write any output data to host buffer (do this before checking interrupts to avoid missing one) */
+ /* Write any output data to host buffer
+ * (do this before checking interrupts to avoid missing one)
+ */
if (usbtty_configured ()) {
write_buffer (&usbtty_output);
}
/* New interrupts? */
- pretend_interrupts ();
-
- /* Check for new data from host.. (do this after checking interrupts to get latest data) */
+ udc_irq();
+
+ /* Check for new data from host..
+ * (do this after checking interrupts to get latest data)
+ */
if (usbtty_configured ()) {
fill_buffer (&usbtty_input);
}
/* New interrupts? */
- pretend_interrupts ();
-}
+ udc_irq();
-static void pretend_interrupts (void)
-{
- /* Loop while we have interrupts.
- * If we don't do this, the input chain
- * polling delay is likely to miss
- * host requests.
- */
- while (inw (UDC_IRQ_SRC) & ~UDC_SOF_Flg) {
- /* Handle any new IRQs */
- omap1510_udc_irq ();
- omap1510_udc_noniso_irq ();
- }
}
+
+
#endif
diff --git a/drivers/usbtty.h b/drivers/usbtty.h
index 79c2fe5..731b763 100644
--- a/drivers/usbtty.h
+++ b/drivers/usbtty.h
@@ -2,6 +2,9 @@
* (C) Copyright 2003
* Gerry Hamel, geh@ti.com, Texas Instruments
*
+ * (C) Copyright 2006
+ * Bryan O'Donoghue, bodonoghue@codehermit.ie, CodeHermit
+ *
* 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
@@ -21,44 +24,47 @@
#ifndef __USB_TTY_H__
#define __USB_TTY_H__
-
#include "usbdcore.h"
+#if defined(CONFIG_PPC)
+#include "usbdcore_mpc8xx.h"
+#elif defined(CONFIG_ARM)
#include "usbdcore_omap1510.h"
+#endif
+#include <version_autogenerated.h>
-#define NUM_CONFIGS 1
-#define NUM_INTERFACES 1
-#define NUM_ENDPOINTS 3
+/* If no VendorID/ProductID is defined in config.h, pretend to be Linux
+ * DO NOT Reuse this Vendor/Product setup with protocol incompatible devices */
-#define EP0_MAX_PACKET_SIZE 64
+#define CONFIG_USBD_VENDORID 0x0525 /* Linux/NetChip */
+#define CONFIG_USBD_PRODUCTID_GSERIAL 0xa4a6 /* gserial */
+#define CONFIG_USBD_PRODUCTID_CDCACM 0xa4a7 /* CDC ACM */
+#define CONFIG_USBD_MANUFACTURER "Das U-Boot"
+#define CONFIG_USBD_PRODUCT_NAME U_BOOT_VERSION
-#define CONFIG_USBD_CONFIGURATION_STR "TTY via USB"
-#define CONFIG_USBD_INTERFACE_STR "Simple Serial Data Interface - Bulk Mode"
+#define CONFIG_USBD_CONFIGURATION_STR "TTY via USB"
-#define CONFIG_USBD_SERIAL_OUT_ENDPOINT 2
-#define CONFIG_USBD_SERIAL_OUT_PKTSIZE 64
-#define CONFIG_USBD_SERIAL_IN_ENDPOINT 1
-#define CONFIG_USBD_SERIAL_IN_PKTSIZE 64
-#define CONFIG_USBD_SERIAL_INT_ENDPOINT 5
-#define CONFIG_USBD_SERIAL_INT_PKTSIZE 16
-
+#define CONFIG_USBD_SERIAL_OUT_ENDPOINT UDC_OUT_ENDPOINT
+#define CONFIG_USBD_SERIAL_OUT_PKTSIZE UDC_OUT_PACKET_SIZE
+#define CONFIG_USBD_SERIAL_IN_ENDPOINT UDC_IN_ENDPOINT
+#define CONFIG_USBD_SERIAL_IN_PKTSIZE UDC_IN_PACKET_SIZE
+#define CONFIG_USBD_SERIAL_INT_ENDPOINT UDC_INT_ENDPOINT
+#define CONFIG_USBD_SERIAL_INT_PKTSIZE UDC_INT_PACKET_SIZE
+#define CONFIG_USBD_SERIAL_BULK_PKTSIZE UDC_BULK_PACKET_SIZE
#define USBTTY_DEVICE_CLASS COMMUNICATIONS_DEVICE_CLASS
-#define USBTTY_DEVICE_SUBCLASS COMMUNICATIONS_NO_SUBCLASS
-#define USBTTY_DEVICE_PROTOCOL COMMUNICATIONS_NO_PROTOCOL
-
-#define USBTTY_INTERFACE_CLASS 0xFF /* Vendor Specific */
-#define USBTTY_INTERFACE_SUBCLASS 0x02
-#define USBTTY_INTERFACE_PROTOCOL 0x01
-#define USBTTY_BCD_DEVICE 0x0
-#define USBTTY_MAXPOWER 0x0
+#define USBTTY_BCD_DEVICE 0x00
+#define USBTTY_MAXPOWER 0x00
-#define STR_MANUFACTURER 1
-#define STR_PRODUCT 2
-#define STR_SERIAL 3
-#define STR_CONFIG 4
-#define STR_INTERFACE 5
+#define STR_LANG 0x00
+#define STR_MANUFACTURER 0x01
+#define STR_PRODUCT 0x02
+#define STR_SERIAL 0x03
+#define STR_CONFIG 0x04
+#define STR_DATA_INTERFACE 0x05
+#define STR_CTRL_INTERFACE 0x06
+#define STR_COUNT 0x07
#endif