summaryrefslogtreecommitdiffstats
path: root/cfe/cfe/usb
diff options
context:
space:
mode:
Diffstat (limited to 'cfe/cfe/usb')
-rw-r--r--cfe/cfe/usb/Makefile8
-rw-r--r--cfe/cfe/usb/README183
-rw-r--r--cfe/cfe/usb/ohci.c2126
-rw-r--r--cfe/cfe/usb/ohci.h490
-rw-r--r--cfe/cfe/usb/usbchap9.h389
-rw-r--r--cfe/cfe/usb/usbd.c1215
-rw-r--r--cfe/cfe/usb/usbd.h308
-rw-r--r--cfe/cfe/usb/usbdebug.c307
-rw-r--r--cfe/cfe/usb/usbdevs.c168
-rw-r--r--cfe/cfe/usb/usbeth.c850
-rw-r--r--cfe/cfe/usb/usbeth.h112
-rw-r--r--cfe/cfe/usb/usbhack.c528
-rw-r--r--cfe/cfe/usb/usbhack.h66
-rw-r--r--cfe/cfe/usb/usbhack.mk23
-rw-r--r--cfe/cfe/usb/usbhid.c664
-rw-r--r--cfe/cfe/usb/usbhub.c912
-rw-r--r--cfe/cfe/usb/usbmain.c367
-rw-r--r--cfe/cfe/usb/usbmass.c1199
-rw-r--r--cfe/cfe/usb/usbserial.c713
19 files changed, 10628 insertions, 0 deletions
diff --git a/cfe/cfe/usb/Makefile b/cfe/cfe/usb/Makefile
new file mode 100644
index 0000000..fa38870
--- /dev/null
+++ b/cfe/cfe/usb/Makefile
@@ -0,0 +1,8 @@
+
+#
+# Makefile for USB stuff
+#
+
+
+ALLOBJS += usbmain.o ohci.o usbd.o usbdevs.o usbhub.o usbdebug.o usbhid.o usbmass.o usbserial.o usbeth.o
+CFLAGS += -DCFG_USB=1
diff --git a/cfe/cfe/usb/README b/cfe/cfe/usb/README
new file mode 100644
index 0000000..28ac9bf
--- /dev/null
+++ b/cfe/cfe/usb/README
@@ -0,0 +1,183 @@
+
+------------------------------------------------------------------------
+This directory contains a basic description of the CFE USB stack,
+its current status and features, and what might be done in the
+future to improve it.
+------------------------------------------------------------------------
+
+Question: A USB stack in CFE? But why?
+
+Answer: Why not? It's not terribly useful on the BCM1250, since we
+ don't expect many of you to use USB in your boards, but there IS
+ a USB host controller on the SWARM (BCM1250 reference design).
+ Besides, CFE is actually being used for other non-SiByte
+ Broadcom chips, and some of those _do_ have USB on them.
+
+------------------------------------------------------------------------
+
+Source Files
+------------
+
+ohci.c OHCI USB Host Controller Driver, tested on a BCM1250
+ with an Opti FireLink PCI USB controller
+
+ohci.h Register definitions for ohci.c
+
+usbchap9.h USB "Chapter 9" definitions (Descriptors, etc.)
+
+usbd.c USB Basic Request and pipe management routines, to
+ manage usb devices, do simple requests on the
+ control pipe, open and manage pipes, etc.
+
+usbd.h Prototypes and data structures for usbd.c
+
+usbdevs.c USB Device Driver list - devices we recognize
+ are listed here - if you add a new USB device,
+ you can add its class or vendor ID entries
+ into the table here.
+
+usbdebug.c Some descriptor dump routines live here.
+
+usbhub.c Class driver for USB hubs. Because hubs are also
+ a major player in device discovery, much of the
+ USB device tree management also lives here.
+
+usbhid.c Class driver for keyboards and mice. Right now
+ not much is done with them except echo characters.
+
+usbmass.c Class driver for USB mass-storage devices. We only
+ support the "bulk-only-no-interrupt" protocol.
+ This driver also includes a top half so that
+ it can be accessed as a CFE mass-storage device.
+
+usbmain.c Top-level interface into CFE. The "usb start"
+ command is instantiated here, as well as a
+ "usb show" command to display attached USB devices.
+
+usbhack.c Main program for the test harness, which lets you
+ develop OHCI code under Linux without hacking on
+ either CFE or the kernel. See the comments in this
+ file for more information.
+
+usbhack.h A dumping ground for CFE definitions not otherwise
+ provided by the standard include files.
+
+usbhack.mk GNU makefile for the test harness
+
+------------------------------------------------------------------------
+
+Overview
+--------
+
+The host controller driver is abstracted through a small set of
+primitives defined in usbd.h - at present only the OHCI driver
+is implemented, but there will eventually be support for the
+ScanLogic SL11H part on the BCM1250CPCI board - this is a simple
+"generic-bus" (non-pci) host controller. I doubt we'll ever
+need EHCI/UHCI, since they are present mostly in Intel chipsets.
+
+All events are polled by this driver. There are two polling functions
+that should be called periodically:
+
+ usb_poll(usbbus_t *bus);
+ usb_daemon(usbbus_t *bus);
+
+The "poll" routine handles interrupts from the devices themselves.
+The "daemon" routine monitors the bus for topology changes and
+instantiates an exploration if something changes. Sometimes "daemon"
+needs to do USB I/O, requiring calls to usb_poll() to get the data
+to go in/out via the controller, hence the two routines. You should
+be careful not to all usb_poll() during polling.
+
+
+Device Drivers
+--------------
+
+USB Device drivers are currently extremely simple: There are
+only two methods that need be exported to the device driver table:
+
+attach() Called when the device is "discovered"
+detach() Called when the device is "removed"
+
+When a device is removed, pending transfer requests will be
+canceled with a "canceled" status.
+
+There is no standard for the top side (user API side) of the
+device driver, that is up to the device class. The bottom half
+should make use of the calls in usbd.c
+
+When a device driver is attached via its attach() method,
+it will be in the "addressed" state according to the USB spec.
+The exploration code takes care of assigning the USB address
+to the device. Devices not otherwise recognized by this code will
+be left in the addressed state without any active configurations.
+
+The descriptors are read by the exploration code and are made
+available to the usb_find_cfg_descr() call - you can use this
+function to obtain the endpoint and interface descriptors for
+your device and then call usb_set_configuration() to activate
+the configuration.
+
+When your detach() method is called, the device should be considered
+already gone, so do not attempt to do any I/O to it. Just clean
+up the mess and return.
+
+
+------------------------------------------------------------------------
+
+What works?
+-----------
+
+* OHCI on a BCM1250 via the Opti Firelink USB controller
+
+* The OHCI root hub emulation
+
+* External hubs, and hubs integrated into other devices like
+ keyboards.
+
+* Interrupt transfers
+
+* Transfers (basic requests) on endpoint 0
+
+* Basic device discovery and removal
+
+* Bulk endpoints and transfers
+
+* Some endpoint stalls are handled.
+
+
+------------------------------------------------------------------------
+
+What doesn't work? What is not implemented?
+--------------------------------------------
+
+* The root hub implementation is really shaky, especially in
+ matters of plug-and-play (device insertion/removal events,
+ etc.) Don't be surprised if removing a device from the
+ root hub causes CFE to freeze.
+
+* There is no error recovery code whatsoever. This kind of goes
+ with the above root hub issue.
+
+* Noncoherent DMA is relatively untested.
+
+* Isochronous endpoints are completely unimplemented (and will probably
+ remain that way)
+
+* Power management (for example, power budget in hubs) is unimplemented.
+ (this should be easy)
+
+* Interrupt endpoints are all on the 10ms endpoint in the interrupt
+ tree (endpoints should be placed at the location to guarantee
+ bandwidth at 'bInterval' ms) - no bandwidth management is being
+ done at the moment, but this is pretty simple.
+
+* The OHCI driver cannot be stopped/unloaded.
+
+
+
+
+
+
+
+
diff --git a/cfe/cfe/usb/ohci.c b/cfe/cfe/usb/ohci.c
new file mode 100644
index 0000000..c002091
--- /dev/null
+++ b/cfe/cfe/usb/ohci.c
@@ -0,0 +1,2126 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * OHCI device driver File: ohci.c
+ *
+ * Open Host Controller Interface low-level routines
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#ifndef _CFE_
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+#include "usbhack.h"
+#define CPUCFG_COHERENT_DMA 1 /* hack runs on a PC, PCs are coherent */
+#else
+#include "lib_types.h"
+#include "lib_printf.h"
+#include "lib_string.h"
+#include "lib_physio.h"
+#include "addrspace.h"
+#include "cpu_config.h" /* for CPUCFG_COHERENT_DMA */
+#endif
+
+#include "lib_malloc.h"
+#include "lib_queue.h"
+#include "usbchap9.h"
+#include "usbd.h"
+#include "ohci.h"
+
+
+/* *********************************************************************
+ * Macros for dealing with hardware
+ *
+ * This is all yucky stuff that needs to be made more
+ * processor-independent. It's mostly here now to help us with
+ * our test harness.
+ ********************************************************************* */
+
+#if defined(_CFE_) && defined(__MIPSEB)
+#define BSWAP32(x) __swap32(x)
+static inline uint32_t __swap32(uint32_t x)
+{
+ uint32_t y;
+
+ y = ((x & 0xFF) << 24) |
+ ((x & 0xFF00) << 8) |
+ ((x & 0xFF0000) >> 8) |
+ ((x & 0xFF000000) >> 24);
+
+ return y;
+}
+#else
+#define BSWAP32(x) (x)
+#endif
+
+
+#ifndef _CFE_
+extern uint32_t vtop(void *ptr);
+extern void *ptov(uint32_t x);
+#define OHCI_VTOP(ptr) vtop(ptr)
+#define OHCI_PTOV(ptr) ptov(ptr)
+#define OHCI_WRITECSR(softc,x,y) \
+ *((volatile uint32_t *) ((softc)->ohci_regs + ((x)/sizeof(uint32_t)))) = (y)
+#define OHCI_READCSR(softc,x) \
+ *((volatile uint32_t *) ((softc)->ohci_regs + ((x)/sizeof(uint32_t))))
+#else
+#define OHCI_VTOP(ptr) ((uint32_t)PHYSADDR((long)(ptr)))
+
+#if CPUCFG_COHERENT_DMA
+#define OHCI_PTOV(ptr) ((void *)(KERNADDR(ptr)))
+#else
+#define OHCI_PTOV(ptr) ((void *)(UNCADDR(ptr)))
+#endif
+
+#define OHCI_WRITECSR(softc,x,y) \
+ phys_write32(((softc)->ohci_regs + (x)),(y))
+#define OHCI_READCSR(softc,x) \
+ phys_read32(((softc)->ohci_regs + (x)))
+#endif
+
+#if CPUCFG_COHERENT_DMA
+#define OHCI_INVAL_RANGE(s,l)
+#define OHCI_FLUSH_RANGE(s,l)
+#else /* not coherent */
+#define CFE_CACHE_INVAL_RANGE 32 /* XXX belongs in include file */
+#define CFE_CACHE_FLUSH_RANGE 64
+extern void _cfe_flushcache(int,uint8_t *,uint8_t *);
+#define OHCI_INVAL_RANGE(s,l) _cfe_flushcache(CFE_CACHE_INVAL_RANGE,((uint8_t *) (s)),((uint8_t *) (s))+(l))
+#define OHCI_FLUSH_RANGE(s,l) _cfe_flushcache(CFE_CACHE_FLUSH_RANGE,((uint8_t *) (s)),((uint8_t *) (s))+(l))
+#endif
+
+
+/* *********************************************************************
+ * Bit-reverse table - this table consists of the numbers
+ * at its index, listed in reverse. So, the reverse of 0000 0010
+ * is 0100 0000.
+ ********************************************************************* */
+
+const static int ohci_revbits[OHCI_INTTABLE_SIZE] = {
+ 0x00, 0x10, 0x08, 0x18, 0x04, 0x14, 0x0c, 0x1c,
+ 0x02, 0x12, 0x0a, 0x1a, 0x06, 0x16, 0x0e, 0x1e,
+ 0x01, 0x11, 0x09, 0x19, 0x05, 0x15, 0x0d, 0x1d,
+ 0x03, 0x13, 0x0b, 0x1b, 0x07, 0x17, 0x0f, 0x1f
+};
+
+
+/* *********************************************************************
+ * Macros to convert from "hardware" endpoint and transfer
+ * descriptors (ohci_ed_t, ohci_td_t) to "software"
+ * data structures (ohci_transfer_t, ohci_endpoint_t).
+ *
+ * Basically, there are two tables, indexed by the same value
+ * By subtracting the base of one pool from a pointer, we get
+ * the index into the other table.
+ *
+ * We *could* have included the ed and td in the software
+ * data structures, but placing all the hardware stuff in one
+ * pool will make it easier for hardware that does not handle
+ * coherent DMA, since we can be less careful about what we flush
+ * and what we invalidate.
+ ********************************************************************* */
+
+#define ohci_td_from_transfer(softc,transfer) \
+ ((softc)->ohci_hwtdpool + ((transfer) - (softc)->ohci_transfer_pool))
+
+#define ohci_transfer_from_td(softc,td) \
+ ((softc)->ohci_transfer_pool + ((td) - (softc)->ohci_hwtdpool))
+
+#define ohci_ed_from_endpoint(softc,endpoint) \
+ ((softc)->ohci_hwedpool + ((endpoint) - (softc)->ohci_endpoint_pool))
+
+#define ohci_endpoint_from_ed(softc,ed) \
+ ((softc)->ohci_endpoint_pool + ((ed) - (softc)->ohci_hwedpool))
+
+/* *********************************************************************
+ * Forward declarations
+ ********************************************************************* */
+
+static int ohci_roothub_xfer(usbbus_t *bus,usb_ept_t *uept,usbreq_t *ur);
+static void ohci_roothub_statchg(ohci_softc_t *softc);
+extern usb_hcdrv_t ohci_driver;
+
+/* *********************************************************************
+ * Globals
+ ********************************************************************* */
+
+int ohcidebug = 0;
+void ohci_dumprhstat(uint32_t reg);
+void ohci_dumpportstat(int idx,uint32_t reg);
+void ohci_dumptd(ohci_td_t *td);
+void ohci_dumptdchain(ohci_td_t *td);
+void ohci_dumped(ohci_ed_t *ed);
+void ohci_dumpedchain(ohci_ed_t *ed);
+
+
+/* *********************************************************************
+ * Some debug routines
+ ********************************************************************* */
+
+#if 1
+void ohci_dumprhstat(uint32_t reg)
+{
+ printf("HubStatus: %08X ",reg);
+
+ if (reg & M_OHCI_RHSTATUS_LPS) printf("LocalPowerStatus ");
+ if (reg & M_OHCI_RHSTATUS_OCI) printf("OverCurrent ");
+ if (reg & M_OHCI_RHSTATUS_DRWE) printf("DeviceRemoteWakeupEnable ");
+ if (reg & M_OHCI_RHSTATUS_LPSC) printf("LocalPowerStatusChange ");
+ if (reg & M_OHCI_RHSTATUS_OCIC) printf("OverCurrentIndicatorChange ");
+ printf("\n");
+
+}
+
+void ohci_dumpportstat(int idx,uint32_t reg)
+{
+ printf("Port %d: %08X ",idx,reg);
+ if (reg & M_OHCI_RHPORTSTAT_CCS) printf("Connected ");
+ if (reg & M_OHCI_RHPORTSTAT_PES) printf("PortEnabled ");
+ if (reg & M_OHCI_RHPORTSTAT_PSS) printf("PortSuspended ");
+ if (reg & M_OHCI_RHPORTSTAT_POCI) printf("PortOverCurrent ");
+ if (reg & M_OHCI_RHPORTSTAT_PRS) printf("PortReset ");
+ if (reg & M_OHCI_RHPORTSTAT_PPS) printf("PortPowered ");
+ if (reg & M_OHCI_RHPORTSTAT_LSDA) printf("LowSpeed ");
+ if (reg & M_OHCI_RHPORTSTAT_CSC) printf("ConnectStatusChange ");
+ if (reg & M_OHCI_RHPORTSTAT_PESC) printf("PortEnableStatusChange ");
+ if (reg & M_OHCI_RHPORTSTAT_PSSC) printf("PortSuspendStatusChange ");
+ if (reg & M_OHCI_RHPORTSTAT_OCIC) printf("OverCurrentIndicatorChange ");
+ if (reg & M_OHCI_RHPORTSTAT_PRSC) printf("PortResetStatusChange ");
+ printf("\n");
+}
+
+void ohci_dumptd(ohci_td_t *td)
+{
+ uint32_t ctl;
+ static char *pids[4] = {"SETUP","OUT","IN","RSVD"};
+
+ ctl = BSWAP32(td->td_control);
+
+ printf("[%08X] ctl=%08X (DP=%s,DI=%d,T=%d,EC=%d,CC=%d%s) cbp=%08X be=%08X next=%08X\n",
+ OHCI_VTOP(td),
+ ctl,
+ pids[G_OHCI_TD_PID(ctl)],
+ G_OHCI_TD_DI(ctl),
+ G_OHCI_TD_DT(ctl),
+ G_OHCI_TD_EC(ctl),
+ G_OHCI_TD_CC(ctl),
+ (ctl & M_OHCI_TD_SHORTOK) ? ",R" : "",
+ BSWAP32(td->td_cbp),
+ BSWAP32(td->td_be),
+ BSWAP32(td->td_next_td));
+}
+
+void ohci_dumptdchain(ohci_td_t *td)
+{
+ int idx = 0;
+ for (;;) {
+ printf("%d:[%08X] ctl=%08X cbp=%08X be=%08X next=%08X\n",
+ idx,
+ OHCI_VTOP(td),
+ BSWAP32(td->td_control),
+ BSWAP32(td->td_cbp),
+ BSWAP32(td->td_be),
+ BSWAP32(td->td_next_td));
+ if (!td->td_next_td) break;
+ td = (ohci_td_t *) OHCI_PTOV(BSWAP32(td->td_next_td));
+ idx++;
+ }
+}
+
+void ohci_dumped(ohci_ed_t *ed)
+{
+ uint32_t ctl;
+ static char *pids[4] = {"FTD","OUT","IN","FTD"};
+
+ ctl = BSWAP32(ed->ed_control),
+
+ printf("[%08X] Ctl=%08X (MPS=%d%s%s%s,EN=%d,FA=%d,D=%s) Tailp=%08X headp=%08X next=%08X %s\n",
+ OHCI_VTOP(ed),
+ ctl,
+ G_OHCI_ED_MPS(ctl),
+ (ctl & M_OHCI_ED_LOWSPEED) ? ",LS" : "",
+ (ctl & M_OHCI_ED_SKIP) ? ",SKIP" : "",
+ (ctl & M_OHCI_ED_ISOCFMT) ? ",ISOC" : "",
+ G_OHCI_ED_EN(ctl),
+ G_OHCI_ED_FA(ctl),
+ pids[G_OHCI_ED_DIR(ctl)],
+ BSWAP32(ed->ed_tailp),
+ BSWAP32(ed->ed_headp),
+ BSWAP32(ed->ed_next_ed),
+ BSWAP32(ed->ed_headp) & M_OHCI_ED_HALT ? "HALT" : "");
+ if ((ed->ed_headp & M_OHCI_ED_PTRMASK) == 0) return;
+ ohci_dumptdchain(OHCI_PTOV(BSWAP32(ed->ed_headp) & M_OHCI_ED_PTRMASK));
+}
+
+void ohci_dumpedchain(ohci_ed_t *ed)
+{
+ int idx = 0;
+ for (;;) {
+ printf("---\nED#%d -> ",idx);
+ ohci_dumped(ed);
+ if (!ed->ed_next_ed) break;
+ if (idx > 50) break;
+ ed = (ohci_ed_t *) OHCI_PTOV(BSWAP32(ed->ed_next_ed));
+ idx++;
+ }
+}
+
+#endif
+
+
+static void eptstats(ohci_softc_t *softc)
+{
+ int cnt;
+ ohci_endpoint_t *e;
+ cnt = 0;
+
+ e = softc->ohci_endpoint_freelist;
+ while (e) { e = e->ep_next; cnt++; }
+ printf("%d left, %d inuse\n",cnt,OHCI_EDPOOL_SIZE-cnt);
+}
+
+/* *********************************************************************
+ * _ohci_allocept(softc)
+ *
+ * Allocate an endpoint data structure from the pool, and
+ * make it ready for use. The endpoint is NOT attached to
+ * the hardware at this time.
+ *
+ * Input parameters:
+ * softc - our OHCI controller
+ *
+ * Return value:
+ * pointer to endpoint or NULL
+ ********************************************************************* */
+
+static ohci_endpoint_t *_ohci_allocept(ohci_softc_t *softc)
+{
+ ohci_endpoint_t *e;
+ ohci_ed_t *ed;
+
+ if (ohcidebug > 2) {
+ printf("AllocEpt: ");eptstats(softc);
+ }
+
+ e = softc->ohci_endpoint_freelist;
+
+ if (!e) {
+ printf("No endpoints left!\n");
+ return NULL;
+ }
+
+ softc->ohci_endpoint_freelist = e->ep_next;
+
+ ed = ohci_ed_from_endpoint(softc,e);
+
+ ed->ed_control = BSWAP32(M_OHCI_ED_SKIP);
+ ed->ed_tailp = BSWAP32(0);
+ ed->ed_headp = BSWAP32(0);
+ ed->ed_next_ed = BSWAP32(0);
+
+ e->ep_phys = OHCI_VTOP(ed);
+ e->ep_next = NULL;
+
+ return e;
+}
+
+/* *********************************************************************
+ * _ohci_allocxfer(softc)
+ *
+ * Allocate a transfer descriptor. It is prepared for use
+ * but not attached to the hardware.
+ *
+ * Input parameters:
+ * softc - our OHCI controller
+ *
+ * Return value:
+ * transfer descriptor, or NULL
+ ********************************************************************* */
+
+static ohci_transfer_t *_ohci_allocxfer(ohci_softc_t *softc)
+{
+ ohci_transfer_t *t;
+ ohci_td_t *td;
+
+ if (ohcidebug > 2) {
+ int cnt;
+ cnt = 0;
+ t = softc->ohci_transfer_freelist;
+ while (t) { t = t->t_next; cnt++; }
+ printf("AllocXfer: %d left, %d inuse\n",cnt,OHCI_TDPOOL_SIZE-cnt);
+ }
+
+ t = softc->ohci_transfer_freelist;
+
+ if (!t) {
+ printf("No more transfer descriptors!\n");
+ return NULL;
+ }
+
+ softc->ohci_transfer_freelist = t->t_next;
+
+ td = ohci_td_from_transfer(softc,t);
+
+ td->td_control = BSWAP32(0);
+ td->td_cbp = BSWAP32(0);
+ td->td_next_td = BSWAP32(0);
+ td->td_be = BSWAP32(0);
+
+ t->t_ref = NULL;
+ t->t_next = NULL;
+
+ return t;
+}
+
+/* *********************************************************************
+ * _ohci_freeept(softc,e)
+ *
+ * Free an endpoint, returning it to the pool.
+ *
+ * Input parameters:
+ * softc - our OHCI controller
+ * e - endpoint descriptor to return
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void _ohci_freeept(ohci_softc_t *softc,ohci_endpoint_t *e)
+{
+ if (ohcidebug > 2) {
+ int cnt;
+ ohci_endpoint_t *ee;
+ cnt = 0;
+ ee = softc->ohci_endpoint_freelist;
+ while (ee) { ee = ee->ep_next; cnt++; }
+ printf("FreeEpt[%p]: %d left, %d inuse\n",e,cnt,OHCI_EDPOOL_SIZE-cnt);
+ }
+
+ e->ep_next = softc->ohci_endpoint_freelist;
+ softc->ohci_endpoint_freelist = e;
+}
+
+/* *********************************************************************
+ * _ohci_freexfer(softc,t)
+ *
+ * Free a transfer descriptor, returning it to the pool.
+ *
+ * Input parameters:
+ * softc - our OHCI controller
+ * t - transfer descriptor to return
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void _ohci_freexfer(ohci_softc_t *softc,ohci_transfer_t *t)
+{
+ t->t_next = softc->ohci_transfer_freelist;
+ softc->ohci_transfer_freelist = t;
+}
+
+/* *********************************************************************
+ * _ohci_initpools(softc)
+ *
+ * Allocate and initialize the various pools of things that
+ * we use in the OHCI driver. We do this by allocating some
+ * big chunks from the heap and carving them up.
+ *
+ * Input parameters:
+ * softc - our OHCI controller
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+static int _ohci_initpools(ohci_softc_t *softc)
+{
+ int idx;
+
+ /*
+ * Do the transfer descriptor pool
+ */
+
+ softc->ohci_transfer_pool = KMALLOC(OHCI_TDPOOL_SIZE*sizeof(ohci_transfer_t),0);
+ softc->ohci_hwtdpool = KMALLOC(OHCI_TDPOOL_SIZE*sizeof(ohci_td_t),OHCI_TD_ALIGN);
+
+ /*
+ * In the case of noncoherent DMA, make these uncached addresses.
+ * This way all our descriptors will be uncached. Makes life easier, as we
+ * do not need to worry about flushing descriptors, etc.
+ */
+
+#if (!CPUCFG_COHERENT_DMA)
+ softc->ohci_hwtdpool = (void *) UNCADDR(PHYSADDR((uint32_t)(softc->ohci_hwtdpool)));
+#endif
+
+ if (!softc->ohci_transfer_pool || !softc->ohci_hwtdpool) {
+ printf("Could not allocate transfer descriptors\n");
+ return -1;
+ }
+
+ softc->ohci_transfer_freelist = NULL;
+
+ for (idx = 0; idx < OHCI_TDPOOL_SIZE; idx++) {
+ _ohci_freexfer(softc,softc->ohci_transfer_pool+idx);
+ }
+
+ /*
+ * Do the endpoint descriptor pool
+ */
+
+ softc->ohci_endpoint_pool = KMALLOC(OHCI_EDPOOL_SIZE*sizeof(ohci_endpoint_t),0);
+
+ softc->ohci_hwedpool = KMALLOC(OHCI_EDPOOL_SIZE*sizeof(ohci_ed_t),OHCI_ED_ALIGN);
+
+#if (!CPUCFG_COHERENT_DMA)
+ softc->ohci_hwedpool = (void *) UNCADDR(PHYSADDR((uint32_t)(softc->ohci_hwedpool)));
+#endif
+
+ if (!softc->ohci_endpoint_pool || !softc->ohci_hwedpool) {
+ printf("Could not allocate transfer descriptors\n");
+ return -1;
+ }
+
+ softc->ohci_endpoint_freelist = NULL;
+
+ for (idx = 0; idx < OHCI_EDPOOL_SIZE; idx++) {
+ _ohci_freeept(softc,softc->ohci_endpoint_pool+idx);
+ }
+
+ /*
+ * Finally the host communications area
+ */
+
+ softc->ohci_hcca = KMALLOC(sizeof(ohci_hcca_t),sizeof(ohci_hcca_t));
+
+#if (!CPUCFG_COHERENT_DMA)
+ softc->ohci_hcca = (void *) UNCADDR(PHYSADDR((uint32_t)(softc->ohci_hcca)));
+#endif
+
+ memset(softc->ohci_hcca,0,sizeof(ohci_hcca_t));
+
+ return 0;
+}
+
+
+/* *********************************************************************
+ * ohci_start(bus)
+ *
+ * Start the OHCI controller. After this routine is called,
+ * the hardware will be operational and ready to accept
+ * descriptors and interrupt calls.
+ *
+ * Input parameters:
+ * bus - bus structure, from ohci_create
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+static int ohci_start(usbbus_t *bus)
+{
+ ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
+ uint32_t frameint;
+ uint32_t reg;
+ int idx;
+
+ /*
+ * Force a reset to the controller, followed by a short delay
+ */
+
+ OHCI_WRITECSR(softc,R_OHCI_CONTROL,V_OHCI_CONTROL_HCFS(K_OHCI_HCFS_RESET));
+ usb_delay_ms(bus,OHCI_RESET_DELAY);
+
+ /* Host controller state is now "RESET" */
+
+ /*
+ * We need the frame interval later, so get a copy of it now.
+ */
+ frameint = G_OHCI_FMINTERVAL_FI(OHCI_READCSR(softc,R_OHCI_FMINTERVAL));
+
+ /*
+ * Reset the host controller. When you set the HCR bit
+ * if self-clears when the reset is complete.
+ */
+
+ OHCI_WRITECSR(softc,R_OHCI_CMDSTATUS,M_OHCI_CMDSTATUS_HCR);
+ for (idx = 0; idx < 10000; idx++) {
+ if (!(OHCI_READCSR(softc,R_OHCI_CMDSTATUS) & M_OHCI_CMDSTATUS_HCR)) break;
+ }
+
+ if (OHCI_READCSR(softc,R_OHCI_CMDSTATUS) & M_OHCI_CMDSTATUS_HCR) {
+ /* controller never came out of reset */
+ return -1;
+ }
+
+ /*
+ * Host controller state is now "SUSPEND". We must exit
+ * from this state within 2ms. (5.1.1.4)
+ *
+ * Set up pointers to data structures.
+ */
+
+ OHCI_WRITECSR(softc,R_OHCI_HCCA,OHCI_VTOP(softc->ohci_hcca));
+ OHCI_WRITECSR(softc,R_OHCI_CONTROLHEADED,softc->ohci_ctl_list->ep_phys);
+ OHCI_WRITECSR(softc,R_OHCI_BULKHEADED,softc->ohci_bulk_list->ep_phys);
+
+ /*
+ * Our driver is polled, turn off interrupts
+ */
+
+ OHCI_WRITECSR(softc,R_OHCI_INTDISABLE,M_OHCI_INT_ALL);
+
+ /*
+ * Set up the control register.
+ */
+
+ reg = OHCI_READCSR(softc,R_OHCI_CONTROL);
+
+ reg = M_OHCI_CONTROL_PLE | M_OHCI_CONTROL_CLE | M_OHCI_CONTROL_BLE |
+ M_OHCI_CONTROL_IE |
+ V_OHCI_CONTROL_CBSR(K_OHCI_CBSR_41) |
+ V_OHCI_CONTROL_HCFS(K_OHCI_HCFS_OPERATIONAL);
+
+ OHCI_WRITECSR(softc,R_OHCI_CONTROL,reg);
+
+
+ /*
+ * controller state is now OPERATIONAL
+ */
+
+ reg = OHCI_READCSR(softc,R_OHCI_FMINTERVAL);
+ reg &= M_OHCI_FMINTERVAL_FIT;
+ reg ^= M_OHCI_FMINTERVAL_FIT;
+ reg |= V_OHCI_FMINTERVAL_FSMPS(OHCI_CALC_FSMPS(frameint)) |
+ V_OHCI_FMINTERVAL_FI(frameint);
+ OHCI_WRITECSR(softc,R_OHCI_FMINTERVAL,reg);
+
+ reg = frameint * 9 / 10; /* calculate 90% */
+ OHCI_WRITECSR(softc,R_OHCI_PERIODICSTART,reg);
+
+ usb_delay_ms(softc->ohci_bus,10);
+
+ /*
+ * Remember how many ports we have
+ */
+
+ reg = OHCI_READCSR(softc,R_OHCI_RHDSCRA);
+ softc->ohci_ndp = G_OHCI_RHDSCRA_NDP(reg);
+
+
+ /*
+ * Enable port power
+ */
+
+ OHCI_WRITECSR(softc,R_OHCI_RHSTATUS,M_OHCI_RHSTATUS_LPSC);
+ usb_delay_ms(softc->ohci_bus,10);
+
+ return 0;
+}
+
+
+/* *********************************************************************
+ * _ohci_setupepts(softc)
+ *
+ * Set up the endpoint tree, as described in the OHCI manual.
+ * Basically the hardware knows how to scan lists of lists,
+ * so we build a tree where each level is pointed to by two
+ * parent nodes. We can choose our scanning rate by attaching
+ * endpoints anywhere within this tree.
+ *
+ * Input parameters:
+ * softc - our OHCI controller
+ *
+ * Return value:
+ * 0 if ok
+ * else error (out of descriptors)
+ ********************************************************************* */
+
+static int _ohci_setupepts(ohci_softc_t *softc)
+{
+ int idx;
+ ohci_endpoint_t *e;
+ ohci_ed_t *ed;
+ ohci_endpoint_t *child;
+
+ /*
+ * Set up the list heads for the isochronous, control,
+ * and bulk transfer lists. They don't get the same "tree"
+ * treatment that the interrupt devices get.
+ *
+ * For the purposes of CFE, it's probably not necessary
+ * to be this fancy. The only device we're planning to
+ * talk to is the keyboard and some hubs, which should
+ * have pretty minimal requirements. It's conceivable
+ * that this firmware may find a new home in other
+ * devices, so we'll meet halfway and do some things
+ * "fancy."
+ */
+
+ softc->ohci_isoc_list = _ohci_allocept(softc);
+ softc->ohci_ctl_list = _ohci_allocept(softc);
+ softc->ohci_bulk_list = _ohci_allocept(softc);
+
+ /*
+ * Set up a tree of empty endpoint descriptors. This is
+ * tree is scanned by the hardware from the leaves up to
+ * the root. Once a millisecond, the hardware picks the
+ * next leaf and starts scanning descriptors looking
+ * for something to do. It traverses all of the endpoints
+ * along the way until it gets to the root.
+ *
+ * The idea here is if you put a transfer descriptor on the
+ * root node, the hardware will see it every millisecond,
+ * since the root will be examined each time. If you
+ * put the TD on the leaf, it will be 1/32 millisecond.
+ * The tree therefore is six levels deep.
+ */
+
+ for (idx = 0; idx < OHCI_INTTREE_SIZE; idx++) {
+ e = _ohci_allocept(softc); /* allocated with sKip bit set */
+ softc->ohci_edtable[idx] = e;
+ child = (idx == 0) ? softc->ohci_isoc_list : softc->ohci_edtable[(idx-1)/2];
+ ed = ohci_ed_from_endpoint(softc,e);
+ ed->ed_next_ed = BSWAP32(child->ep_phys);
+ e->ep_next = child;
+ }
+
+ /*
+ * We maintain both physical and virtual copies of the interrupt
+ * table (leaves of the tree).
+ */
+
+ for (idx = 0; idx < OHCI_INTTABLE_SIZE; idx++) {
+ child = softc->ohci_edtable[OHCI_INTTREE_SIZE-OHCI_INTTABLE_SIZE+idx];
+ softc->ohci_inttable[ohci_revbits[idx]] = child;
+ softc->ohci_hcca->hcca_inttable[ohci_revbits[idx]] = BSWAP32(child->ep_phys);
+ }
+
+ /*
+ * Okay, at this point the tree is built.
+ */
+ return 0;
+}
+
+/* *********************************************************************
+ * ohci_stop(bus)
+ *
+ * Stop the OHCI hardware.
+ *
+ * Input parameters:
+ * bus - our bus structure
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void ohci_stop(usbbus_t *bus)
+{
+ ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
+
+ OHCI_WRITECSR(softc,R_OHCI_CONTROL,V_OHCI_CONTROL_HCFS(K_OHCI_HCFS_RESET));
+}
+
+
+/* *********************************************************************
+ * _ohci_queueept(softc,queue,e)
+ *
+ * Add an endpoint to a list of endpoints. This routine
+ * does things in a particular way according to the OHCI
+ * spec so we can add endpoints while the hardware is running.
+ *
+ * Input parameters:
+ * queue - endpoint descriptor for head of queue
+ * e - endpoint to add to queue
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void _ohci_queueept(ohci_softc_t *softc,ohci_endpoint_t *queue,ohci_endpoint_t *newept)
+{
+ ohci_ed_t *qed;
+ ohci_ed_t *newed;
+
+ qed = ohci_ed_from_endpoint(softc,queue);
+ newed = ohci_ed_from_endpoint(softc,newept);
+
+ newept->ep_next = queue->ep_next;
+ newed->ed_next_ed = qed->ed_next_ed;
+
+ queue->ep_next = newept;
+ qed->ed_next_ed = BSWAP32(newept->ep_phys);
+
+ if (ohcidebug > 1) ohci_dumped(newed);
+
+}
+
+/* *********************************************************************
+ * _ohci_deqept(queue,e)
+ *
+ * Remove and endpoint from the list of endpoints. This
+ * routine does things in a particular way according to
+ * the OHCI specification, since we are operating on
+ * a running list.
+ *
+ * Input parameters:
+ * queue - base of queue to look for endpoint on
+ * e - endpoint to remove
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void _ohci_deqept(ohci_softc_t *softc,ohci_endpoint_t *queue,ohci_endpoint_t *e)
+{
+ ohci_endpoint_t *cur;
+ ohci_ed_t *cured;
+ ohci_ed_t *ed;
+
+ cur = queue;
+
+ while (cur && (cur->ep_next != e)) cur = cur->ep_next;
+
+ if (cur == NULL) {
+ printf("Could not remove EP %08X: not on the list!\n",(uint32_t) (intptr_t)e);
+ return;
+ }
+
+ /*
+ * Remove from our regular list
+ */
+
+ cur->ep_next = e->ep_next;
+
+ /*
+ * now remove from the hardware's list
+ */
+
+ cured = ohci_ed_from_endpoint(softc,cur);
+ ed = ohci_ed_from_endpoint(softc,e);
+
+ cured->ed_next_ed = ed->ed_next_ed;
+}
+
+
+/* *********************************************************************
+ * ohci_intr_procdoneq(softc)
+ *
+ * Process the "done" queue for this ohci controller. As
+ * descriptors are retired, the hardware links them to the
+ * "done" queue so we can examine the results.
+ *
+ * Input parameters:
+ * softc - our OHCI controller
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void ohci_intr_procdoneq(ohci_softc_t *softc)
+{
+ uint32_t doneq;
+ ohci_transfer_t *transfer;
+ ohci_td_t *td;
+ int val;
+ usbreq_t *ur;
+
+ /*
+ * Get the head of the queue
+ */
+
+ doneq = softc->ohci_hcca->hcca_donehead;
+ doneq = BSWAP32(doneq);
+
+ td = (ohci_td_t *) OHCI_PTOV(doneq);
+ transfer = ohci_transfer_from_td(softc,td);
+
+ /*
+ * Process all elements from the queue
+ */
+
+ while (doneq) {
+
+ ohci_ed_t *ed;
+ ohci_endpoint_t *ept;
+ usbreq_t *xur = transfer->t_ref;
+
+ if (ohcidebug > 1) {
+ if (xur) {
+ ept = (ohci_endpoint_t *) xur->ur_pipe->up_hwendpoint;
+ ed = ohci_ed_from_endpoint(softc,ept);
+// printf("ProcDoneQ:ED [%08X] -> ",ept->ep_phys);
+// ohci_dumped(ed);
+ }
+ }
+
+ /*
+ * Get the pointer to next one before freeing this one
+ */
+
+ if (ohcidebug > 1) {
+ ur = transfer->t_ref;
+ printf("Done(%d): ",ur ? ur->ur_tdcount : -1);
+ ohci_dumptd(td);
+ }
+
+ doneq = BSWAP32(td->td_next_td);
+
+ val = G_OHCI_TD_CC(BSWAP32(td->td_control));
+
+ if (val != 0) printf("[Transfer error: %d]\n",val);
+
+ /*
+ * See if it's time to call the callback.
+ */
+ ur = transfer->t_ref;
+ if (ur) {
+ ur->ur_status = val;
+ ur->ur_tdcount--;
+ if (BSWAP32(td->td_cbp) == 0) {
+ ur->ur_xferred += transfer->t_length;
+ }
+ else {
+ ur->ur_xferred += transfer->t_length -
+ (BSWAP32(td->td_be) - BSWAP32(td->td_cbp) + 1);
+ }
+ if (ur->ur_tdcount == 0) {
+ /* Noncoherent DMA: need to invalidate, since data is in phys mem */
+ OHCI_INVAL_RANGE(ur->ur_buffer,ur->ur_xferred);
+ usb_complete_request(ur,val);
+ }
+ }
+
+
+ /*
+ * Free up the request
+ */
+ _ohci_freexfer(softc,transfer);
+
+
+ /*
+ * Advance to the next request.
+ */
+
+ td = (ohci_td_t *) OHCI_PTOV(doneq);
+ transfer = ohci_transfer_from_td(softc,td);
+ }
+
+}
+
+/* *********************************************************************
+ * ohci_intr(bus)
+ *
+ * Process pending interrupts for the OHCI controller.
+ *
+ * Input parameters:
+ * bus - our bus structure
+ *
+ * Return value:
+ * 0 if we did nothing
+ * nonzero if we did something.
+ ********************************************************************* */
+
+static int ohci_intr(usbbus_t *bus)
+{
+ uint32_t reg;
+ ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
+
+ /*
+ * Read the interrupt status register.
+ */
+
+ reg = OHCI_READCSR(softc,R_OHCI_INTSTATUS);
+
+ /*
+ * Don't bother doing anything if nothing happened.
+ */
+ if (reg == 0) {
+ return 0;
+ }
+
+ /* Scheduling Overruns */
+ if (reg & M_OHCI_INT_SO) {
+ printf("SchedOverrun\n");
+ }
+
+ /* Done Queue */
+ if (reg & M_OHCI_INT_WDH) {
+ /* printf("DoneQueue\n"); */
+ ohci_intr_procdoneq(softc);
+ }
+
+ /* Start of Frame */
+ if (reg & M_OHCI_INT_SF) {
+ /* don't be noisy about this */
+ }
+
+ /* Resume Detect */
+ if (reg & M_OHCI_INT_RD) {
+ printf("ResumeDetect\n");
+ }
+
+ /* Unrecoverable errors */
+ if (reg & M_OHCI_INT_UE) {
+ printf("UnrecoverableError\n");
+ }
+
+ /* Frame number overflow */
+ if (reg & M_OHCI_INT_FNO) {
+ /*printf("FrameNumberOverflow\n"); */
+ }
+
+ /* Root Hub Status Change */
+ if ((reg & ~softc->ohci_intdisable) & M_OHCI_INT_RHSC) {
+ uint32_t reg;
+ if (ohcidebug > 0) {
+ printf("RootHubStatusChange: ");
+ reg = OHCI_READCSR(softc,R_OHCI_RHSTATUS);
+ ohci_dumprhstat(reg);
+ reg = OHCI_READCSR(softc,R_OHCI_RHPORTSTATUS(1));
+ ohci_dumpportstat(1,reg);
+ reg = OHCI_READCSR(softc,R_OHCI_RHPORTSTATUS(2));
+ ohci_dumpportstat(2,reg);
+ }
+ ohci_roothub_statchg(softc);
+ }
+
+ /* Ownership Change */
+ if (reg & M_OHCI_INT_OC) {
+ printf("OwnershipChange\n");
+ }
+
+ /*
+ * Write the value back to the interrupt
+ * register to clear the bits that were set.
+ */
+
+ OHCI_WRITECSR(softc,R_OHCI_INTSTATUS,reg);
+
+ return 1;
+}
+
+
+/* *********************************************************************
+ * ohci_delete(bus)
+ *
+ * Remove an OHCI bus structure and all resources allocated to
+ * it (used when shutting down USB)
+ *
+ * Input parameters:
+ * bus - our USB bus structure
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void ohci_delete(usbbus_t *bus)
+{
+ // xxx fill in later.
+}
+
+
+/* *********************************************************************
+ * ohci_create(addr)
+ *
+ * Create a USB bus structure and associate it with our OHCI
+ * controller device.
+ *
+ * Input parameters:
+ * addr - physical address of controller
+ *
+ * Return value:
+ * usbbus structure pointer
+ ********************************************************************* */
+
+static usbbus_t *ohci_create(physaddr_t addr)
+{
+ int res;
+ ohci_softc_t *softc;
+ usbbus_t *bus;
+
+ softc = KMALLOC(sizeof(ohci_softc_t),0);
+ if (!softc) return NULL;
+
+ bus = KMALLOC(sizeof(usbbus_t),0);
+ if (!bus) return NULL;
+
+ memset(softc,0,sizeof(ohci_softc_t));
+ memset(bus,0,sizeof(usbbus_t));
+
+ bus->ub_hwsoftc = (usb_hc_t *) softc;
+ bus->ub_hwdisp = &ohci_driver;
+
+ q_init(&(softc->ohci_rh_intrq));
+
+#ifdef _CFE_
+ softc->ohci_regs = addr;
+#else
+ softc->ohci_regs = (volatile uint32_t *) addr;
+#endif
+
+ softc->ohci_rh_newaddr = -1;
+ softc->ohci_bus = bus;
+
+ if ((res = _ohci_initpools(softc)) != 0) goto error;
+ if ((res = _ohci_setupepts(softc)) != 0) goto error;
+
+ OHCI_WRITECSR(softc,R_OHCI_CONTROL,V_OHCI_CONTROL_HCFS(K_OHCI_HCFS_RESET));
+
+ return bus;
+
+error:
+ KFREE(softc);
+ return NULL;
+}
+
+
+/* *********************************************************************
+ * ohci_ept_create(bus,usbaddr,eptnum,mps,flags)
+ *
+ * Create a hardware endpoint structure and attach it to
+ * the hardware's endpoint list. The hardware manages lists
+ * of queues, and this routine adds a new queue to the appropriate
+ * list of queues for the endpoint in question. It roughly
+ * corresponds to the information in the OHCI specification.
+ *
+ * Input parameters:
+ * bus - the USB bus we're dealing with
+ * usbaddr - USB address (0 means default address)
+ * eptnum - the endpoint number
+ * mps - the packet size for this endpoint
+ * flags - various flags to control endpoint creation
+ *
+ * Return value:
+ * endpoint structure poihter, or NULL
+ ********************************************************************* */
+
+static usb_ept_t *ohci_ept_create(usbbus_t *bus,
+ int usbaddr,
+ int eptnum,
+ int mps,
+ int flags)
+{
+ uint32_t eptflags;
+ ohci_endpoint_t *ept;
+ ohci_ed_t *ed;
+ ohci_transfer_t *tailtransfer;
+ ohci_td_t *tailtd;
+ ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
+
+ ept = _ohci_allocept(softc);
+ ed = ohci_ed_from_endpoint(softc,ept);
+
+ tailtransfer = _ohci_allocxfer(softc);
+ tailtd = ohci_td_from_transfer(softc,tailtransfer);
+
+ /*
+ * Set up functional address, endpoint number, and packet size
+ */
+
+ eptflags = V_OHCI_ED_FA(usbaddr) |
+ V_OHCI_ED_EN(eptnum) |
+ V_OHCI_ED_MPS(mps) |
+ 0;
+
+ /*
+ * Set up the endpoint type based on the flags
+ * passed to us
+ */
+
+ if (flags & UP_TYPE_IN) {
+ eptflags |= V_OHCI_ED_DIR(K_OHCI_ED_DIR_IN);
+ }
+ else if (flags & UP_TYPE_OUT) {
+ eptflags |= V_OHCI_ED_DIR(K_OHCI_ED_DIR_OUT);
+ }
+ else {
+ eptflags |= V_OHCI_ED_DIR(K_OHCI_ED_DIR_FROMTD);
+ }
+
+ /*
+ * Don't forget about lowspeed devices.
+ */
+
+ if (flags & UP_TYPE_LOWSPEED) {
+ eptflags |= M_OHCI_ED_LOWSPEED;
+ }
+
+ if (ohcidebug > 0) {
+ printf("Create endpoint %d addr %d flags %08X mps %d\n",
+ eptnum,usbaddr,eptflags,mps);
+ }
+
+ /*
+ * Transfer this info into the endpoint descriptor.
+ * No need to flush the cache here, it'll get done when
+ * we add to the hardware list.
+ */
+
+ ed->ed_control = BSWAP32(eptflags);
+ ed->ed_tailp = BSWAP32(OHCI_VTOP(tailtd));
+ ed->ed_headp = BSWAP32(OHCI_VTOP(tailtd));
+ ept->ep_flags = flags;
+ ept->ep_mps = mps;
+ ept->ep_num = eptnum;
+
+ /*
+ * Put it on the right queue
+ */
+
+ if (flags & UP_TYPE_CONTROL) {
+ _ohci_queueept(softc,softc->ohci_ctl_list,ept);
+ }
+ else if (flags & UP_TYPE_BULK) {
+ _ohci_queueept(softc,softc->ohci_bulk_list,ept);
+ }
+ else if (flags & UP_TYPE_INTR) {
+ /* XXX Choose place in inttable properly. */
+ _ohci_queueept(softc,softc->ohci_inttable[0],ept);
+ }
+
+ return (usb_ept_t *) ept;
+}
+
+/* *********************************************************************
+ * ohci_ept_setaddr(bus,ept,usbaddr)
+ *
+ * Change the functional address for a USB endpoint. We do this
+ * when we switch the device's state from DEFAULT to ADDRESSED
+ * and we've already got the default pipe open. This
+ * routine mucks with the descriptor and changes its address
+ * bits.
+ *
+ * Input parameters:
+ * bus - usb bus structure
+ * ept - an open endpoint descriptor
+ * usbaddr - new address for this endpoint
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void ohci_ept_setaddr(usbbus_t *bus,usb_ept_t *uept,int usbaddr)
+{
+ uint32_t eptflags;
+ ohci_endpoint_t *ept = (ohci_endpoint_t *) uept;
+ ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
+ ohci_ed_t *ed = ohci_ed_from_endpoint(softc,ept);
+
+ eptflags = BSWAP32(ed->ed_control);
+ eptflags &= ~M_OHCI_ED_FA;
+ eptflags |= V_OHCI_ED_FA(usbaddr);
+ ed->ed_control = BSWAP32(eptflags);
+}
+
+
+/* *********************************************************************
+ * ohci_ept_setmps(bus,ept,mps)
+ *
+ * Set the maximum packet size of this endpoint. This is
+ * normally used during the processing of endpoint 0 (default
+ * pipe) after we find out how big ep0's packets can be.
+ *
+ * Input parameters:
+ * bus - our USB bus structure
+ * ept - endpoint structure
+ * mps - new packet size
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void ohci_ept_setmps(usbbus_t *bus,usb_ept_t *uept,int mps)
+{
+ uint32_t eptflags;
+ ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
+ ohci_endpoint_t *ept = (ohci_endpoint_t *) uept;
+ ohci_ed_t *ed = ohci_ed_from_endpoint(softc,ept);
+
+ eptflags = BSWAP32(ed->ed_control);
+ eptflags &= ~M_OHCI_ED_MPS;
+ eptflags |= V_OHCI_ED_MPS(mps);
+ ed->ed_control = BSWAP32(eptflags);
+ ept->ep_mps = mps;
+
+}
+
+/* *********************************************************************
+ * ohci_ept_cleartoggle(bus,ept,mps)
+ *
+ * Clear the data toggle for the specified endpoint.
+ *
+ * Input parameters:
+ * bus - our USB bus structure
+ * ept - endpoint structure
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void ohci_ept_cleartoggle(usbbus_t *bus,usb_ept_t *uept)
+{
+ uint32_t eptflags;
+ ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
+ ohci_endpoint_t *ept = (ohci_endpoint_t *) uept;
+ ohci_ed_t *ed = ohci_ed_from_endpoint(softc,ept);
+
+ eptflags = BSWAP32(ed->ed_headp);
+ eptflags &= ~(M_OHCI_ED_HALT | M_OHCI_ED_TOGGLECARRY);
+ ed->ed_headp = BSWAP32(eptflags);
+
+ OHCI_WRITECSR(softc,R_OHCI_CMDSTATUS,M_OHCI_CMDSTATUS_CLF);
+}
+
+/* *********************************************************************
+ * ohci_ept_delete(bus,ept)
+ *
+ * Deletes an endpoint from the OHCI controller. This
+ * routine also completes pending transfers for the
+ * endpoint and gets rid of the hardware ept (queue base).
+ *
+ * Input parameters:
+ * bus - ohci bus structure
+ * ept - endpoint to remove
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void ohci_ept_delete(usbbus_t *bus,usb_ept_t *uept)
+{
+ ohci_endpoint_t *queue;
+ ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
+ ohci_endpoint_t *ept = (ohci_endpoint_t *) uept;
+ ohci_ed_t *ed = ohci_ed_from_endpoint(softc,ept);
+ uint32_t framenum;
+ uint32_t tdphys;
+ usbreq_t *ur;
+ ohci_td_t *td;
+ ohci_transfer_t *transfer;
+
+ if (ept->ep_flags & UP_TYPE_CONTROL) {
+ queue = softc->ohci_ctl_list;
+ }
+ else if (ept->ep_flags & UP_TYPE_BULK) {
+ queue = softc->ohci_bulk_list;
+ }
+ else if (ept->ep_flags & UP_TYPE_INTR) {
+ queue = softc->ohci_inttable[0];
+ }
+ else {
+ printf("Invalid endpoint\n");
+ return;
+ }
+
+
+ /*
+ * Set the SKIP bit on the endpoint and
+ * wait for two SOFs to guarantee that we're
+ * not processing this ED anymore.
+ */
+
+ ((volatile uint32_t) ed->ed_control) |= BSWAP32(M_OHCI_ED_SKIP);
+
+ framenum = OHCI_READCSR(softc,R_OHCI_FMNUMBER) & 0xFFFF;
+ while ((OHCI_READCSR(softc,R_OHCI_FMNUMBER) & 0xFFFF) == framenum) ; /* NULL LOOP */
+
+ framenum = OHCI_READCSR(softc,R_OHCI_FMNUMBER) & 0xFFFF;
+ while ((OHCI_READCSR(softc,R_OHCI_FMNUMBER) & 0xFFFF) == framenum) ; /* NULL LOOP */
+
+ /*
+ * Remove endpoint from queue
+ */
+
+ _ohci_deqept(softc,queue,ept);
+
+ /*
+ * Free/complete the TDs on the queue
+ */
+
+ tdphys = BSWAP32(ed->ed_headp) & M_OHCI_ED_PTRMASK;
+
+ while (tdphys != BSWAP32(ed->ed_tailp)) {
+ td = (ohci_td_t *) OHCI_PTOV(tdphys);
+ tdphys = BSWAP32(td->td_next_td);
+ transfer = ohci_transfer_from_td(softc,td);
+
+ ur = transfer->t_ref;
+ if (ur) {
+ ur->ur_status = K_OHCI_CC_CANCELLED;
+ ur->ur_tdcount--;
+ if (ur->ur_tdcount == 0) {
+ if (ohcidebug > 0) printf("Completing request due to closed pipe: %p\n",ur);
+ usb_complete_request(ur,K_OHCI_CC_CANCELLED);
+ /* XXX it is expected that the callee will free the usbreq. */
+ }
+ }
+
+ _ohci_freexfer(softc,transfer);
+ }
+
+ /*
+ * tdphys now points at the tail TD. Just free it.
+ */
+
+ td = (ohci_td_t *) OHCI_PTOV(tdphys);
+ _ohci_freexfer(softc,ohci_transfer_from_td(softc,td));
+
+ /*
+ * Return endpoint to free pool
+ */
+
+ _ohci_freeept(softc,ept);
+}
+
+
+
+/* *********************************************************************
+ * ohci_xfer(bus,ept,ur)
+ *
+ * Queue a transfer for the specified endpoint. Depending on
+ * the transfer type, the transfer may go on one of many queues.
+ * When the transfer completes, a callback will be called.
+ *
+ * Input parameters:
+ * bus - bus structure
+ * ept - endpoint descriptor
+ * ur - request (includes pointer to user buffer)
+ *
+ * Return value:
+ * 0 if ok
+ * else error
+ ********************************************************************* */
+
+static int ohci_xfer(usbbus_t *bus,usb_ept_t *uept,usbreq_t *ur)
+{
+ ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
+ ohci_endpoint_t *ept = (ohci_endpoint_t *) uept;
+ ohci_ed_t *ed = ohci_ed_from_endpoint(softc,ept);
+ ohci_transfer_t *newtailtransfer = 0;
+ ohci_td_t *newtailtd = NULL;
+ ohci_transfer_t *curtransfer;
+ ohci_td_t *curtd;
+ uint8_t *ptr;
+ int len;
+ int amtcopy;
+ int pktlen;
+ uint32_t tdcontrol = 0;
+
+ /*
+ * If the destination USB address matches
+ * the address of the root hub, shunt the request
+ * over to our root hub emulation.
+ */
+
+ if (ur->ur_dev->ud_address == softc->ohci_rh_addr) {
+ return ohci_roothub_xfer(bus,uept,ur);
+ }
+
+ /*
+ * Set up the TD flags based on the
+ * request type.
+ */
+
+// pktlen = ept->ep_mps;
+ pktlen = OHCI_TD_MAX_DATA - 16;
+
+ if (ur->ur_flags & UR_FLAG_SETUP) {
+ tdcontrol = V_OHCI_TD_PID(K_OHCI_TD_SETUP) |
+ V_OHCI_TD_DT(K_OHCI_TD_DT_DATA0) |
+ V_OHCI_TD_CC(K_OHCI_CC_NOTACCESSED) |
+ V_OHCI_TD_DI(1);
+ }
+ else if (ur->ur_flags & UR_FLAG_IN) {
+ tdcontrol = V_OHCI_TD_PID(K_OHCI_TD_IN) |
+ V_OHCI_TD_DT(K_OHCI_TD_DT_TCARRY) |
+ V_OHCI_TD_CC(K_OHCI_CC_NOTACCESSED) |
+ V_OHCI_TD_DI(1);
+ }
+ else if (ur->ur_flags & UR_FLAG_OUT) {
+ tdcontrol = V_OHCI_TD_PID(K_OHCI_TD_OUT) |
+ V_OHCI_TD_DT(K_OHCI_TD_DT_TCARRY) |
+ V_OHCI_TD_CC(K_OHCI_CC_NOTACCESSED) |
+ V_OHCI_TD_DI(1);
+ }
+ else if (ur->ur_flags & UR_FLAG_STATUS_OUT) {
+ tdcontrol = V_OHCI_TD_PID(K_OHCI_TD_OUT) |
+ V_OHCI_TD_DT(K_OHCI_TD_DT_DATA1) |
+ V_OHCI_TD_CC(K_OHCI_CC_NOTACCESSED) |
+ V_OHCI_TD_DI(1);
+ }
+ else if (ur->ur_flags & UR_FLAG_STATUS_IN) {
+ tdcontrol = V_OHCI_TD_PID(K_OHCI_TD_IN) |
+ V_OHCI_TD_DT(K_OHCI_TD_DT_DATA1) |
+ V_OHCI_TD_CC(K_OHCI_CC_NOTACCESSED) |
+ V_OHCI_TD_DI(1);
+ }
+ else {
+ printf("Shouldn't happen!\n");
+ }
+
+ if (ur->ur_flags & UR_FLAG_SHORTOK) {
+ tdcontrol |= M_OHCI_TD_SHORTOK;
+ }
+
+
+ ptr = ur->ur_buffer;
+ len = ur->ur_length;
+ ur->ur_tdcount = 0;
+
+ if (ohcidebug > 1) {
+ printf(">> Queueing xfer addr %d pipe %d ED %08X ptr %016llX length %d\n",
+ ur->ur_dev->ud_address,
+ ur->ur_pipe->up_num,
+ ept->ep_phys,
+ (uint64_t) (uintptr_t) ptr,
+ len);
+// ohci_dumped(ed);
+ }
+
+ curtd = OHCI_PTOV(BSWAP32(ed->ed_tailp));
+ curtransfer = ohci_transfer_from_td(softc,curtd);
+
+ if (len == 0) {
+ newtailtransfer = _ohci_allocxfer(softc);
+ newtailtd = ohci_td_from_transfer(softc,newtailtransfer);
+ curtd->td_cbp = 0;
+ curtd->td_be = 0;
+ curtd->td_next_td = BSWAP32(OHCI_VTOP(newtailtd));
+ curtd->td_control = BSWAP32(tdcontrol);
+ curtransfer->t_next = newtailtransfer;
+ curtransfer->t_ref = ur;
+ curtransfer->t_length = 0;
+ if (ohcidebug > 1) { printf("QueueTD: "); ohci_dumptd(curtd); }
+ ur->ur_tdcount++;
+ }
+ else {
+ /* Noncoherent DMA: need to flush user buffer to real memory first */
+ OHCI_FLUSH_RANGE(ptr,len);
+ while (len > 0) {
+ amtcopy = len;
+ if (amtcopy > pktlen) amtcopy = pktlen;
+ newtailtransfer = _ohci_allocxfer(softc);
+ newtailtd = ohci_td_from_transfer(softc,newtailtransfer);
+ curtd->td_cbp = BSWAP32(OHCI_VTOP(ptr));
+ curtd->td_be = BSWAP32(OHCI_VTOP(ptr+amtcopy)-1);
+ curtd->td_next_td = BSWAP32(OHCI_VTOP(newtailtd));
+ curtd->td_control = BSWAP32(tdcontrol);
+ curtransfer->t_next = newtailtransfer;
+ curtransfer->t_ref = ur;
+ curtransfer->t_length = amtcopy;
+ if (ohcidebug > 1) { printf("QueueTD: "); ohci_dumptd(curtd); }
+ curtd = newtailtd;
+ curtransfer = ohci_transfer_from_td(softc,curtd);
+ ptr += amtcopy;
+ len -= amtcopy;
+ ur->ur_tdcount++;
+ }
+ }
+
+ curtd = OHCI_PTOV(BSWAP32(ed->ed_headp & M_OHCI_ED_PTRMASK));
+ ed->ed_tailp = BSWAP32(OHCI_VTOP(newtailtd));
+
+ /*
+ * Prod the controller depending on what type of list we put
+ * a TD on.
+ */
+
+ if (ept->ep_flags & UP_TYPE_BULK) {
+ OHCI_WRITECSR(softc,R_OHCI_CMDSTATUS,M_OHCI_CMDSTATUS_BLF);
+ }
+ else {
+ /* XXX should probably make sure we're UP_TYPE_CONTROL here */
+ OHCI_WRITECSR(softc,R_OHCI_CMDSTATUS,M_OHCI_CMDSTATUS_CLF);
+ }
+
+ return 0;
+}
+
+/* *********************************************************************
+ * Driver structure
+ ********************************************************************* */
+
+usb_hcdrv_t ohci_driver = {
+ ohci_create,
+ ohci_delete,
+ ohci_start,
+ ohci_stop,
+ ohci_intr,
+ ohci_ept_create,
+ ohci_ept_delete,
+ ohci_ept_setmps,
+ ohci_ept_setaddr,
+ ohci_ept_cleartoggle,
+ ohci_xfer
+};
+
+/* *********************************************************************
+ * Root Hub
+ *
+ * Data structures and functions
+ ********************************************************************* */
+
+/*
+ * Data structures and routines to emulate the root hub.
+ */
+static usb_device_descr_t ohci_root_devdsc = {
+ sizeof(usb_device_descr_t), /* bLength */
+ USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */
+ USBWORD(0x0100), /* bcdUSB */
+ USB_DEVICE_CLASS_HUB, /* bDeviceClass */
+ 0, /* bDeviceSubClass */
+ 0, /* bDeviceProtocol */
+ 64, /* bMaxPacketSize0 */
+ USBWORD(0), /* idVendor */
+ USBWORD(0), /* idProduct */
+ USBWORD(0x0100), /* bcdDevice */
+ 1, /* iManufacturer */
+ 2, /* iProduct */
+ 0, /* iSerialNumber */
+ 1 /* bNumConfigurations */
+};
+
+static usb_config_descr_t ohci_root_cfgdsc = {
+ sizeof(usb_config_descr_t), /* bLength */
+ USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType */
+ USBWORD(
+ sizeof(usb_config_descr_t) +
+ sizeof(usb_interface_descr_t) +
+ sizeof(usb_endpoint_descr_t)), /* wTotalLength */
+ 1, /* bNumInterfaces */
+ 1, /* bConfigurationValue */
+ 0, /* iConfiguration */
+ USB_CONFIG_SELF_POWERED, /* bmAttributes */
+ 0 /* MaxPower */
+};
+
+static usb_interface_descr_t ohci_root_ifdsc = {
+ sizeof(usb_interface_descr_t), /* bLength */
+ USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
+ 0, /* bInterfaceNumber */
+ 0, /* bAlternateSetting */
+ 1, /* bNumEndpoints */
+ USB_INTERFACE_CLASS_HUB, /* bInterfaceClass */
+ 0, /* bInterfaceSubClass */
+ 0, /* bInterfaceProtocol */
+ 0 /* iInterface */
+};
+
+static usb_endpoint_descr_t ohci_root_epdsc = {
+ sizeof(usb_endpoint_descr_t), /* bLength */
+ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */
+ (USB_ENDPOINT_DIRECTION_IN | 1), /* bEndpointAddress */
+ USB_ENDPOINT_TYPE_INTERRUPT, /* bmAttributes */
+ USBWORD(8), /* wMaxPacketSize */
+ 255 /* bInterval */
+};
+
+static usb_hub_descr_t ohci_root_hubdsc = {
+ USB_HUB_DESCR_SIZE, /* bLength */
+ USB_HUB_DESCRIPTOR_TYPE, /* bDescriptorType */
+ 0, /* bNumberOfPorts */
+ USBWORD(0), /* wHubCharacteristics */
+ 0, /* bPowreOnToPowerGood */
+ 0, /* bHubControl Current */
+ {0} /* bRemoveAndPowerMask */
+};
+
+/* *********************************************************************
+ * ohci_roothb_strdscr(ptr,str)
+ *
+ * Construct a string descriptor for root hub requests
+ *
+ * Input parameters:
+ * ptr - pointer to where to put descriptor
+ * str - regular string to put into descriptor
+ *
+ * Return value:
+ * number of bytes written to descriptor
+ ********************************************************************* */
+
+static int ohci_roothub_strdscr(uint8_t *ptr,char *str)
+{
+ uint8_t *p = ptr;
+
+ *p++ = strlen(str)*2 + 2; /* Unicode strings */
+ *p++ = USB_STRING_DESCRIPTOR_TYPE;
+ while (*str) {
+ *p++ = *str++;
+ *p++ = 0;
+ }
+ return (p - ptr);
+}
+
+/* *********************************************************************
+ * ohci_roothub_req(softc,req)
+ *
+ * Handle a descriptor request on the control pipe for the
+ * root hub. We pretend to be a real root hub here and
+ * return all the standard descriptors.
+ *
+ * Input parameters:
+ * softc - our OHCI controller
+ * req - a usb request (completed immediately)
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+static int ohci_roothub_req(ohci_softc_t *softc,usb_device_request_t *req)
+{
+ uint8_t *ptr;
+ uint16_t wLength;
+ uint16_t wValue;
+ uint16_t wIndex;
+ usb_port_status_t ups;
+ usb_hub_descr_t hdsc;
+ uint32_t status;
+ uint32_t statport;
+ uint32_t tmpval;
+ int res = 0;
+
+ ptr = softc->ohci_rh_buf;
+
+ wLength = GETUSBFIELD(req,wLength);
+ wValue = GETUSBFIELD(req,wValue);
+ wIndex = GETUSBFIELD(req,wIndex);
+
+ switch (REQSW(req->bRequest,req->bmRequestType)) {
+
+ case REQCODE(USB_REQUEST_GET_STATUS,USBREQ_DIR_IN,USBREQ_TYPE_STD,USBREQ_REC_DEVICE):
+ *ptr++ = (USB_GETSTATUS_SELF_POWERED & 0xFF);
+ *ptr++ = (USB_GETSTATUS_SELF_POWERED >> 8);
+ break;
+
+ case REQCODE(USB_REQUEST_GET_STATUS,USBREQ_DIR_IN,USBREQ_TYPE_STD,USBREQ_REC_ENDPOINT):
+ case REQCODE(USB_REQUEST_GET_STATUS,USBREQ_DIR_IN,USBREQ_TYPE_STD,USBREQ_REC_INTERFACE):
+ *ptr++ = 0;
+ *ptr++ = 0;
+ break;
+
+ case REQCODE(USB_REQUEST_GET_STATUS,USBREQ_DIR_IN,USBREQ_TYPE_CLASS,USBREQ_REC_OTHER):
+ status = OHCI_READCSR(softc,(R_OHCI_RHPORTSTATUS(wIndex)));
+ if (ohcidebug > 0) { printf("RHGetStatus: "); ohci_dumpportstat(wIndex,status);}
+ PUTUSBFIELD((&ups),wPortStatus,(status & 0xFFFF));
+ PUTUSBFIELD((&ups),wPortChange,(status >> 16));
+ memcpy(ptr,&ups,sizeof(ups));
+ ptr += sizeof(ups);
+ break;
+
+ case REQCODE(USB_REQUEST_GET_STATUS,USBREQ_DIR_IN,USBREQ_TYPE_CLASS,USBREQ_REC_DEVICE):
+ *ptr++ = 0;
+ *ptr++ = 0;
+ *ptr++ = 0;
+ *ptr++ = 0;
+ break;
+
+ case REQCODE(USB_REQUEST_CLEAR_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_DEVICE):
+ case REQCODE(USB_REQUEST_CLEAR_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_INTERFACE):
+ case REQCODE(USB_REQUEST_CLEAR_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_ENDPOINT):
+ /* do nothing, not supported */
+ break;
+
+ case REQCODE(USB_REQUEST_CLEAR_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_CLASS,USBREQ_REC_OTHER):
+ statport = R_OHCI_RHPORTSTATUS(wIndex);
+ if (ohcidebug> 0) {
+ printf("RHClearFeature(%d): ",wValue); ohci_dumpportstat(wIndex,OHCI_READCSR(softc,statport));
+ }
+ switch (wValue) {
+ case USB_PORT_FEATURE_CONNECTION:
+ break;
+ case USB_PORT_FEATURE_ENABLE:
+ OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_CCS);
+ break;
+ case USB_PORT_FEATURE_SUSPEND:
+ OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_POCI);
+ break;
+ case USB_PORT_FEATURE_OVER_CURRENT:
+ break;
+ case USB_PORT_FEATURE_RESET:
+ break;
+ case USB_PORT_FEATURE_POWER:
+ OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_LSDA);
+ break;
+ case USB_PORT_FEATURE_LOW_SPEED:
+ break;
+ case USB_PORT_FEATURE_C_PORT_CONNECTION:
+ OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_CSC);
+ break;
+ case USB_PORT_FEATURE_C_PORT_ENABLE:
+ OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_PESC);
+ break;
+ case USB_PORT_FEATURE_C_PORT_SUSPEND:
+ OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_PSSC);
+ break;
+ case USB_PORT_FEATURE_C_PORT_OVER_CURRENT:
+ OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_OCIC);
+ break;
+ case USB_PORT_FEATURE_C_PORT_RESET:
+ OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_PRSC);
+ break;
+
+ }
+
+ /*
+ * If we've cleared all of the conditions that
+ * want our attention on the port status,
+ * then we can accept port status interrupts again.
+ */
+
+ if ((wValue >= USB_PORT_FEATURE_C_PORT_CONNECTION) &&
+ (wValue <= USB_PORT_FEATURE_C_PORT_RESET)) {
+ status = OHCI_READCSR(softc,statport);
+ if ((status & M_OHCI_RHPORTSTAT_ALLC) == 0) {
+ softc->ohci_intdisable &= ~M_OHCI_INT_RHSC;
+ }
+ }
+ break;
+
+ case REQCODE(USB_REQUEST_SET_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_DEVICE):
+ case REQCODE(USB_REQUEST_SET_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_INTERFACE):
+ case REQCODE(USB_REQUEST_SET_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_ENDPOINT):
+ res = -1;
+ break;
+
+ case REQCODE(USB_REQUEST_SET_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_CLASS,USBREQ_REC_DEVICE):
+ /* nothing */
+ break;
+
+ case REQCODE(USB_REQUEST_SET_FEATURE,USBREQ_DIR_OUT,USBREQ_TYPE_CLASS,USBREQ_REC_OTHER):
+ statport = R_OHCI_RHPORTSTATUS(wIndex);
+ switch (wValue) {
+ case USB_PORT_FEATURE_CONNECTION:
+ break;
+ case USB_PORT_FEATURE_ENABLE:
+ OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_PES);
+ break;
+ case USB_PORT_FEATURE_SUSPEND:
+ OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_PSS);
+ break;
+ case USB_PORT_FEATURE_OVER_CURRENT:
+ break;
+ case USB_PORT_FEATURE_RESET:
+ OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_PRS);
+ for (;;) { /* XXX timer */
+ usb_delay_ms(softc->ohci_bus,100);
+ if (!(OHCI_READCSR(softc,statport) & M_OHCI_RHPORTSTAT_PRS)) break;
+ }
+ break;
+ case USB_PORT_FEATURE_POWER:
+ OHCI_WRITECSR(softc,statport,M_OHCI_RHPORTSTAT_PPS);
+ break;
+ case USB_PORT_FEATURE_LOW_SPEED:
+ break;
+ case USB_PORT_FEATURE_C_PORT_CONNECTION:
+ break;
+ case USB_PORT_FEATURE_C_PORT_ENABLE:
+ break;
+ case USB_PORT_FEATURE_C_PORT_SUSPEND:
+ break;
+ case USB_PORT_FEATURE_C_PORT_OVER_CURRENT:
+ break;
+ case USB_PORT_FEATURE_C_PORT_RESET:
+ break;
+
+ }
+
+ break;
+
+ case REQCODE(USB_REQUEST_SET_ADDRESS,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_DEVICE):
+ softc->ohci_rh_newaddr = wValue;
+ break;
+
+ case REQCODE(USB_REQUEST_GET_DESCRIPTOR,USBREQ_DIR_IN,USBREQ_TYPE_STD,USBREQ_REC_DEVICE):
+ switch (wValue >> 8) {
+ case USB_DEVICE_DESCRIPTOR_TYPE:
+ memcpy(ptr,&ohci_root_devdsc,sizeof(ohci_root_devdsc));
+ ptr += sizeof(ohci_root_devdsc);
+ break;
+ case USB_CONFIGURATION_DESCRIPTOR_TYPE:
+ memcpy(ptr,&ohci_root_cfgdsc,sizeof(ohci_root_cfgdsc));
+ ptr += sizeof(ohci_root_cfgdsc);
+ memcpy(ptr,&ohci_root_ifdsc,sizeof(ohci_root_ifdsc));
+ ptr += sizeof(ohci_root_ifdsc);
+ memcpy(ptr,&ohci_root_epdsc,sizeof(ohci_root_epdsc));
+ ptr += sizeof(ohci_root_epdsc);
+ break;
+ case USB_STRING_DESCRIPTOR_TYPE:
+ switch (wValue & 0xFF) {
+ case 1:
+ ptr += ohci_roothub_strdscr(ptr,"Generic");
+ break;
+ case 2:
+ ptr += ohci_roothub_strdscr(ptr,"Root Hub");
+ break;
+ default:
+ *ptr++ = 0;
+ break;
+ }
+ break;
+ default:
+ res = -1;
+ break;
+ }
+ break;
+
+ case REQCODE(USB_REQUEST_GET_DESCRIPTOR,USBREQ_DIR_IN,USBREQ_TYPE_CLASS,USBREQ_REC_DEVICE):
+ memcpy(&hdsc,&ohci_root_hubdsc,sizeof(hdsc));
+ hdsc.bNumberOfPorts = softc->ohci_ndp;
+ status = OHCI_READCSR(softc,R_OHCI_RHDSCRA);
+ tmpval = 0;
+ if (status & M_OHCI_RHDSCRA_NPS) tmpval |= USB_HUBCHAR_PWR_NONE;
+ if (status & M_OHCI_RHDSCRA_PSM) tmpval |= USB_HUBCHAR_PWR_GANGED;
+ else tmpval |= USB_HUBCHAR_PWR_IND;
+ PUTUSBFIELD((&hdsc),wHubCharacteristics,tmpval);
+ tmpval = G_OHCI_RHDSCRA_POTPGT(status);
+ hdsc.bPowerOnToPowerGood = tmpval;
+ hdsc.bDescriptorLength = USB_HUB_DESCR_SIZE + 1;
+ status = OHCI_READCSR(softc,R_OHCI_RHDSCRB);
+ hdsc.bRemoveAndPowerMask[0] = (uint8_t) status;
+ memcpy(ptr,&hdsc,sizeof(hdsc));
+ ptr += sizeof(hdsc);
+ break;
+
+ case REQCODE(USB_REQUEST_SET_DESCRIPTOR,USBREQ_DIR_OUT,USBREQ_TYPE_CLASS,USBREQ_REC_DEVICE):
+ /* nothing */
+ break;
+
+ case REQCODE(USB_REQUEST_GET_CONFIGURATION,USBREQ_DIR_IN,USBREQ_TYPE_STD,USBREQ_REC_DEVICE):
+ *ptr++ = softc->ohci_rh_conf;
+ break;
+
+ case REQCODE(USB_REQUEST_SET_CONFIGURATION,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_DEVICE):
+ softc->ohci_rh_conf = wValue;
+ break;
+
+ case REQCODE(USB_REQUEST_GET_INTERFACE,USBREQ_DIR_IN,USBREQ_TYPE_STD,USBREQ_REC_INTERFACE):
+ *ptr++ = 0;
+ break;
+
+ case REQCODE(USB_REQUEST_SET_INTERFACE,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_INTERFACE):
+ /* nothing */
+ break;
+
+ case REQCODE(USB_REQUEST_SYNC_FRAME,USBREQ_DIR_OUT,USBREQ_TYPE_STD,USBREQ_REC_ENDPOINT):
+ /* nothing */
+ break;
+ }
+
+ softc->ohci_rh_ptr = softc->ohci_rh_buf;
+ softc->ohci_rh_len = ptr - softc->ohci_rh_buf;
+
+ return res;
+}
+
+/* *********************************************************************
+ * ohci_roothub_statchg(softc)
+ *
+ * This routine is called from the interrupt service routine
+ * (well, polling routine) for the ohci controller. If the
+ * controller notices a root hub status change, it dequeues an
+ * interrupt transfer from the root hub's queue and completes
+ * it here.
+ *
+ * Input parameters:
+ * softc - our OHCI controller
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void ohci_roothub_statchg(ohci_softc_t *softc)
+{
+ usbreq_t *ur;
+ uint32_t status;
+ uint8_t portstat = 0;
+ int idx;
+
+ /* Note: this only works up to 8 ports */
+ for (idx = 1; idx <= softc->ohci_ndp; idx++) {
+ status = OHCI_READCSR(softc,R_OHCI_RHPORTSTATUS(idx));
+ if (status & M_OHCI_RHPORTSTAT_ALLC) {
+ portstat = (1<<idx);
+ }
+ }
+
+ if (portstat != 0) {
+ softc->ohci_intdisable |= M_OHCI_INT_RHSC;
+ }
+
+ ur = (usbreq_t *) q_deqnext(&(softc->ohci_rh_intrq));
+ if (!ur) return; /* no requests pending, ignore it */
+
+ memset(ur->ur_buffer,0,ur->ur_length);
+ ur->ur_buffer[0] = portstat;
+ ur->ur_xferred = ur->ur_length;
+
+ usb_complete_request(ur,0);
+}
+
+/* *********************************************************************
+ * ohci_roothub_xfer(softc,req)
+ *
+ * Handle a root hub xfer - ohci_xfer transfers control here
+ * if we detect the address of the root hub - no actual transfers
+ * go out on the wire, we just handle the requests directly to
+ * make it look like a hub is attached.
+ *
+ * This seems to be common practice in the USB world, so we do
+ * it here too.
+ *
+ * Input parameters:
+ * softc - our OHCI controller structure
+ * req - usb request destined for host controller
+ *
+ * Return value:
+ * 0 if ok
+ * else error
+ ********************************************************************* */
+
+static int ohci_roothub_xfer(usbbus_t *bus,usb_ept_t *uept,usbreq_t *ur)
+{
+ ohci_softc_t *softc = (ohci_softc_t *) bus->ub_hwsoftc;
+ ohci_endpoint_t *ept = (ohci_endpoint_t *) uept;
+ int res;
+
+ switch (ept->ep_num) {
+
+ /*
+ * CONTROL ENDPOINT
+ */
+ case 0:
+
+ /*
+ * Three types of transfers: OUT (SETUP), IN (data), or STATUS.
+ * figure out which is which.
+ */
+
+ if (ur->ur_flags & UR_FLAG_SETUP) {
+ /*
+ * SETUP packet - this is an OUT request to the control
+ * pipe. We emulate the hub request here.
+ */
+ usb_device_request_t *req;
+
+ req = (usb_device_request_t *) ur->ur_buffer;
+
+ res = ohci_roothub_req(softc,req);
+ if (res != 0) printf("Root hub request returned an error\n");
+
+ ur->ur_xferred = ur->ur_length;
+ ur->ur_status = 0;
+ usb_complete_request(ur,0);
+ }
+
+ else if (ur->ur_flags & UR_FLAG_STATUS_IN) {
+ /*
+ * STATUS IN : it's sort of like a dummy IN request
+ * to acknowledge a SETUP packet that otherwise has no
+ * status. Just complete the usbreq.
+ */
+
+ if (softc->ohci_rh_newaddr != -1) {
+ softc->ohci_rh_addr = softc->ohci_rh_newaddr;
+ softc->ohci_rh_newaddr = -1;
+ }
+
+ ur->ur_status = 0;
+ ur->ur_xferred = 0;
+ usb_complete_request(ur,0);
+ }
+
+ else if (ur->ur_flags & UR_FLAG_STATUS_OUT) {
+ /*
+ * STATUS OUT : it's sort of like a dummy OUT request
+ */
+ ur->ur_status = 0;
+ ur->ur_xferred = 0;
+ usb_complete_request(ur,0);
+ }
+
+ else if (ur->ur_flags & UR_FLAG_IN) {
+ /*
+ * IN : return data from the root hub
+ */
+ int amtcopy;
+
+ amtcopy = softc->ohci_rh_len;
+ if (amtcopy > ur->ur_length) amtcopy = ur->ur_length;
+
+ memcpy(ur->ur_buffer,softc->ohci_rh_ptr,amtcopy);
+
+ softc->ohci_rh_ptr += amtcopy;
+ softc->ohci_rh_len -= amtcopy;
+
+ ur->ur_status = 0;
+ ur->ur_xferred = amtcopy;
+ usb_complete_request(ur,0);
+ }
+
+ else {
+ printf("Unknown root hub transfer type\n");
+ return -1;
+ }
+ break;
+
+ /*
+ * INTERRUPT ENDPOINT
+ */
+
+ case 1: /* interrupt pipe */
+ if (ur->ur_flags & UR_FLAG_IN) {
+ q_enqueue(&(softc->ohci_rh_intrq),(queue_t *) ur);
+ }
+ break;
+
+ }
+
+
+ return 0;
+}
diff --git a/cfe/cfe/usb/ohci.h b/cfe/cfe/usb/ohci.h
new file mode 100644
index 0000000..06368e5
--- /dev/null
+++ b/cfe/cfe/usb/ohci.h
@@ -0,0 +1,490 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * OHCI defs File: ohci.h
+ *
+ * Open Host controller interface definitions
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+/* *********************************************************************
+ * Macros to muck with bitfields
+ ********************************************************************* */
+
+#define _OHCI_MAKE32(x) ((uint32_t)(x))
+
+/*
+ * Make a mask for 1 bit at position 'n'
+ */
+
+#define _OHCI_MAKEMASK1(n) (_OHCI_MAKE32(1) << _OHCI_MAKE32(n))
+
+/*
+ * Make a mask for 'v' bits at position 'n'
+ */
+
+#define _OHCI_MAKEMASK(v,n) (_OHCI_MAKE32((_OHCI_MAKE32(1)<<(v))-1) << _OHCI_MAKE32(n))
+
+/*
+ * Make a value at 'v' at bit position 'n'
+ */
+
+#define _OHCI_MAKEVALUE(v,n) (_OHCI_MAKE32(v) << _OHCI_MAKE32(n))
+#define _OHCI_GETVALUE(v,n,m) ((_OHCI_MAKE32(v) & _OHCI_MAKE32(m)) >> _OHCI_MAKE32(n))
+
+
+
+/* *********************************************************************
+ * Endpoint Descriptor (interrupt, bulk)
+ ********************************************************************* */
+
+#define OHCI_ED_ALIGN 32
+
+typedef struct ohci_ed_s {
+ uint32_t ed_control;
+ uint32_t ed_tailp;
+ uint32_t ed_headp;
+ uint32_t ed_next_ed;
+} ohci_ed_t;
+
+#define S_OHCI_ED_FA 0
+#define M_OHCI_ED_FA _OHCI_MAKEMASK(7,S_OHCI_ED_FA)
+#define V_OHCI_ED_FA(x) _OHCI_MAKEVALUE(x,S_OHCI_ED_FA)
+#define G_OHCI_ED_FA(x) _OHCI_GETVALUE(x,S_OHCI_ED_FA,M_OHCI_ED_FA)
+
+#define S_OHCI_ED_EN 7
+#define M_OHCI_ED_EN _OHCI_MAKEMASK(4,S_OHCI_ED_EN)
+#define V_OHCI_ED_EN(x) _OHCI_MAKEVALUE(x,S_OHCI_ED_EN)
+#define G_OHCI_ED_EN(x) _OHCI_GETVALUE(x,S_OHCI_ED_EN,M_OHCI_ED_EN)
+
+#define S_OHCI_ED_DIR 11
+#define M_OHCI_ED_DIR _OHCI_MAKEMASK(2,S_OHCI_ED_DIR)
+#define V_OHCI_ED_DIR(x) _OHCI_MAKEVALUE(x,S_OHCI_ED_DIR)
+#define G_OHCI_ED_DIR(x) _OHCI_GETVALUE(x,S_OHCI_ED_DIR,M_OHCI_ED_DIR)
+
+#define K_OHCI_ED_DIR_FROMTD 0
+#define K_OHCI_ED_DIR_OUT 1
+#define K_OHCI_ED_DIR_IN 2
+
+#define M_OHCI_ED_LOWSPEED _OHCI_MAKEMASK1(13)
+#define M_OHCI_ED_SKIP _OHCI_MAKEMASK1(14)
+#define M_OHCI_ED_ISOCFMT _OHCI_MAKEMASK1(15)
+
+#define S_OHCI_ED_MPS 16
+#define M_OHCI_ED_MPS _OHCI_MAKEMASK(11,S_OHCI_ED_MPS)
+#define V_OHCI_ED_MPS(x) _OHCI_MAKEVALUE(x,S_OHCI_ED_MPS)
+#define G_OHCI_ED_MPS(x) _OHCI_GETVALUE(x,S_OHCI_ED_MPS,M_OHCI_ED_MPS)
+
+#define M_OHCI_ED_PTRMASK 0xFFFFFFF0
+#define M_OHCI_ED_HALT _OHCI_MAKEMASK1(0)
+#define M_OHCI_ED_TOGGLECARRY _OHCI_MAKEMASK1(1)
+
+/* *********************************************************************
+ * Transfer Descriptor
+ ********************************************************************* */
+
+#define OHCI_TD_ALIGN 32
+
+typedef struct ohci_td_s {
+ uint32_t td_control;
+ uint32_t td_cbp;
+ uint32_t td_next_td;
+ uint32_t td_be;
+} ohci_td_t;
+
+#define M_OHCI_TD_SHORTOK _OHCI_MAKEMASK1(18)
+
+#define S_OHCI_TD_PID 19
+#define M_OHCI_TD_PID _OHCI_MAKEMASK(2,S_OHCI_TD_PID)
+#define V_OHCI_TD_PID(x) _OHCI_MAKEVALUE(x,S_OHCI_TD_PID)
+#define G_OHCI_TD_PID(x) _OHCI_GETVALUE(x,S_OHCI_TD_PID,M_OHCI_TD_PID)
+
+#define K_OHCI_TD_SETUP 0
+#define K_OHCI_TD_OUT 1
+#define K_OHCI_TD_IN 2
+#define K_OHCI_TD_RESERVED 3
+
+#define V_OHCI_TD_SETUP V_OHCI_TD_PID(K_OHCI_TD_SETUP)
+#define V_OHCI_TD_OUT V_OHCI_TD_PID(K_OHCI_TD_OUT)
+#define V_OHCI_TD_IN V_OHCI_TD_PID(K_OHCI_TD_IN)
+#define V_OHCI_TD_RESERVED V_OHCI_TD_PID(K_OHCI_TD_RESERVED)
+
+#define S_OHCI_TD_DI 21
+#define M_OHCI_TD_DI _OHCI_MAKEMASK(3,S_OHCI_TD_DI)
+#define V_OHCI_TD_DI(x) _OHCI_MAKEVALUE(x,S_OHCI_TD_DI)
+#define G_OHCI_TD_DI(x) _OHCI_GETVALUE(x,S_OHCI_TD_DI,M_OHCI_TD_DI)
+
+#define K_OHCI_TD_NOINTR 7
+#define V_OHCI_TD_NOINTR V_OHCI_TD_DI(K_OHCI_TD_NOINTR)
+
+#define S_OHCI_TD_DT 24
+#define M_OHCI_TD_DT _OHCI_MAKEMASK(2,S_OHCI_TD_DT)
+#define V_OHCI_TD_DT(x) _OHCI_MAKEVALUE(x,S_OHCI_TD_DT)
+#define G_OHCI_TD_DT(x) _OHCI_GETVALUE(x,S_OHCI_TD_DT,M_OHCI_TD_DT)
+
+#define K_OHCI_TD_DT_DATA0 2
+#define K_OHCI_TD_DT_DATA1 3
+#define K_OHCI_TD_DT_TCARRY 0
+
+#define S_OHCI_TD_EC 26
+#define M_OHCI_TD_EC _OHCI_MAKEMASK(2,S_OHCI_TD_EC)
+#define V_OHCI_TD_EC(x) _OHCI_MAKEVALUE(x,S_OHCI_TD_EC)
+#define G_OHCI_TD_EC(x) _OHCI_GETVALUE(x,S_OHCI_TD_EC,M_OHCI_TD_EC)
+
+#define S_OHCI_TD_CC 28
+#define M_OHCI_TD_CC _OHCI_MAKEMASK(4,S_OHCI_TD_CC)
+#define V_OHCI_TD_CC(x) _OHCI_MAKEVALUE(x,S_OHCI_TD_CC)
+#define G_OHCI_TD_CC(x) _OHCI_GETVALUE(x,S_OHCI_TD_CC,M_OHCI_TD_CC)
+
+#define K_OHCI_CC_NOERROR 0
+#define K_OHCI_CC_CRC 1
+#define K_OHCI_CC_BITSTUFFING 2
+#define K_OHCI_CC_DATATOGGLEMISMATCH 3
+#define K_OHCI_CC_STALL 4
+#define K_OHCI_CC_DEVICENOTRESPONDING 5
+#define K_OHCI_CC_PIDCHECKFAILURE 6
+#define K_OHCI_CC_UNEXPECTEDPID 7
+#define K_OHCI_CC_DATAOVERRUN 8
+#define K_OHCI_CC_DATAUNDERRUN 9
+#define K_OHCI_CC_BUFFEROVERRUN 12
+#define K_OHCI_CC_BUFFERUNDERRUN 13
+#define K_OHCI_CC_NOTACCESSED 15
+
+#define K_OHCI_CC_CANCELLED 0xFF
+
+#define OHCI_TD_MAX_DATA 8192
+
+
+/* *********************************************************************
+ * Endpoint descriptor (isochronous)
+ ********************************************************************* */
+
+/*
+ * TBA
+ */
+
+/* *********************************************************************
+ * Host Controller Communications Area (HCCA)
+ ********************************************************************* */
+
+#define OHCI_INTTABLE_SIZE 32
+
+#define OHCI_HCCA_ALIGN 256 /* Align on 256-byte boundary */
+
+typedef struct ohci_hcca_s {
+ uint32_t hcca_inttable[OHCI_INTTABLE_SIZE];
+ uint32_t hcca_framenum; /* note: actually two 16-bit fields */
+ uint32_t hcca_donehead;
+ uint32_t hcca_reserved[29]; /* round to 256 bytes */
+ uint32_t hcca_pad;
+} ohci_hcca_t;
+
+/* *********************************************************************
+ * Registers
+ ********************************************************************* */
+
+#define _OHCI_REGIDX(x) ((x)*4)
+
+#define R_OHCI_REVISION _OHCI_REGIDX(0)
+#define R_OHCI_CONTROL _OHCI_REGIDX(1)
+#define R_OHCI_CMDSTATUS _OHCI_REGIDX(2)
+#define R_OHCI_INTSTATUS _OHCI_REGIDX(3)
+#define R_OHCI_INTENABLE _OHCI_REGIDX(4)
+#define R_OHCI_INTDISABLE _OHCI_REGIDX(5)
+#define R_OHCI_HCCA _OHCI_REGIDX(6)
+#define R_OHCI_PERIODCURRENTED _OHCI_REGIDX(7)
+#define R_OHCI_CONTROLHEADED _OHCI_REGIDX(8)
+#define R_OHCI_CONTROLCURRENTED _OHCI_REGIDX(9)
+#define R_OHCI_BULKHEADED _OHCI_REGIDX(10)
+#define R_OHCI_BULKCURRENTED _OHCI_REGIDX(11)
+#define R_OHCI_DONEHEAD _OHCI_REGIDX(12)
+#define R_OHCI_FMINTERVAL _OHCI_REGIDX(13)
+#define R_OHCI_FMREMAINING _OHCI_REGIDX(14)
+#define R_OHCI_FMNUMBER _OHCI_REGIDX(15)
+#define R_OHCI_PERIODICSTART _OHCI_REGIDX(16)
+#define R_OHCI_LSTHRESHOLD _OHCI_REGIDX(17)
+#define R_OHCI_RHDSCRA _OHCI_REGIDX(18)
+#define R_OHCI_RHDSCRB _OHCI_REGIDX(19)
+#define R_OHCI_RHSTATUS _OHCI_REGIDX(20)
+#define R_OHCI_RHPORTSTATUS(x) _OHCI_REGIDX(20+(x)) /* note: 1-based! */
+
+
+/*
+ * R_OHCI_REVISION
+ */
+
+#define S_OHCI_REV_REV 0
+#define M_OHCI_REV_REV _OHCI_MAKEMASK(8,S_OHCI_REV_REV)
+#define V_OHCI_REV_REV(x) _OHCI_MAKEVALUE(x,S_OHCI_REV_REV)
+#define G_OHCI_REV_REV(x) _OHCI_GETVALUE(x,S_OHCI_REV_REV,M_OHCI_REV_REV)
+#define K_OHCI_REV_11 0x10
+
+/*
+ * R_OHCI_CONTROL
+ */
+
+#define S_OHCI_CONTROL_CBSR 0
+#define M_OHCI_CONTROL_CBSR _OHCI_MAKEMASK(2,S_OHCI_CONTROL_CBSR)
+#define V_OHCI_CONTROL_CBSR(x) _OHCI_MAKEVALUE(x,S_OHCI_CONTROL_CBSR)
+#define G_OHCI_CONTROL_CBSR(x) _OHCI_GETVALUE(x,S_OHCI_CONTROL_CBSR,M_OHCI_CONTROL_CBSR)
+
+#define K_OHCI_CBSR_11 0
+#define K_OHCI_CBSR_21 1
+#define K_OHCI_CBSR_31 2
+#define K_OHCI_CBSR_41 3
+
+#define M_OHCI_CONTROL_PLE _OHCI_MAKEMASK1(2)
+#define M_OHCI_CONTROL_IE _OHCI_MAKEMASK1(3)
+#define M_OHCI_CONTROL_CLE _OHCI_MAKEMASK1(4)
+#define M_OHCI_CONTROL_BLE _OHCI_MAKEMASK1(5)
+
+#define S_OHCI_CONTROL_HCFS 6
+#define M_OHCI_CONTROL_HCFS _OHCI_MAKEMASK(2,S_OHCI_CONTROL_HCFS)
+#define V_OHCI_CONTROL_HCFS(x) _OHCI_MAKEVALUE(x,S_OHCI_CONTROL_HCFS)
+#define G_OHCI_CONTROL_HCFS(x) _OHCI_GETVALUE(x,S_OHCI_CONTROL_HCFS,M_OHCI_CONTROL_HCFS)
+
+#define K_OHCI_HCFS_RESET 0
+#define K_OHCI_HCFS_RESUME 1
+#define K_OHCI_HCFS_OPERATIONAL 2
+#define K_OHCI_HCFS_SUSPEND 3
+
+#define M_OHCI_CONTROL_IR _OHCI_MAKEMASK1(8)
+#define M_OHCI_CONTROL_RWC _OHCI_MAKEMASK1(9)
+#define M_OHCI_CONTROL_RWE _OHCI_MAKEMASK1(10)
+
+/*
+ * R_OHCI_CMDSTATUS
+ */
+
+#define M_OHCI_CMDSTATUS_HCR _OHCI_MAKEMASK1(0)
+#define M_OHCI_CMDSTATUS_CLF _OHCI_MAKEMASK1(1)
+#define M_OHCI_CMDSTATUS_BLF _OHCI_MAKEMASK1(2)
+#define M_OHCI_CMDSTATUS_OCR _OHCI_MAKEMASK1(3)
+
+#define S_OHCI_CMDSTATUS_SOC 16
+#define M_OHCI_CMDSTATUS_SOC _OHCI_MAKEMASK(2,S_OHCI_CMDSTATUS_SOC)
+#define V_OHCI_CMDSTATUS_SOC(x) _OHCI_MAKEVALUE(x,S_OHCI_CMDSTATUS_SOC)
+#define G_OHCI_CMDSTATUS_SOC(x) _OHCI_GETVALUE(x,S_OHCI_CMDSTATUS_SOC,M_OHCI_CMDSTATUS_SOC)
+
+/*
+ * R_OHCI_INTSTATUS, R_OHCI_INTENABLE, R_OHCI_INTDISABLE
+ */
+
+
+#define M_OHCI_INT_SO _OHCI_MAKEMASK1(0)
+#define M_OHCI_INT_WDH _OHCI_MAKEMASK1(1)
+#define M_OHCI_INT_SF _OHCI_MAKEMASK1(2)
+#define M_OHCI_INT_RD _OHCI_MAKEMASK1(3)
+#define M_OHCI_INT_UE _OHCI_MAKEMASK1(4)
+#define M_OHCI_INT_FNO _OHCI_MAKEMASK1(5)
+#define M_OHCI_INT_RHSC _OHCI_MAKEMASK1(6)
+#define M_OHCI_INT_OC _OHCI_MAKEMASK1(30)
+#define M_OHCI_INT_MIE _OHCI_MAKEMASK1(31)
+
+#define M_OHCI_INT_ALL M_OHCI_INT_SO | M_OHCI_INT_WDH | M_OHCI_INT_SF | \
+ M_OHCI_INT_RD | M_OHCI_INT_UE | M_OHCI_INT_FNO | \
+ M_OHCI_INT_RHSC | M_OHCI_INT_OC | M_OHCI_INT_MIE
+
+/*
+ * R_OHCI_FMINTERVAL
+ */
+
+
+#define S_OHCI_FMINTERVAL_FI 0
+#define M_OHCI_FMINTERVAL_FI _OHCI_MAKEMASK(14,S_OHCI_FMINTERVAL_FI)
+#define V_OHCI_FMINTERVAL_FI(x) _OHCI_MAKEVALUE(x,S_OHCI_FMINTERVAL_FI)
+#define G_OHCI_FMINTERVAL_FI(x) _OHCI_GETVALUE(x,S_OHCI_FMINTERVAL_FI,M_OHCI_FMINTERVAL_FI)
+
+#define S_OHCI_FMINTERVAL_FSMPS 16
+#define M_OHCI_FMINTERVAL_FSMPS _OHCI_MAKEMASK(15,S_OHCI_FMINTERVAL_FSMPS)
+#define V_OHCI_FMINTERVAL_FSMPS(x) _OHCI_MAKEVALUE(x,S_OHCI_FMINTERVAL_FSMPS)
+#define G_OHCI_FMINTERVAL_FSMPS(x) _OHCI_GETVALUE(x,S_OHCI_FMINTERVAL_FSMPS,M_OHCI_FMINTERVAL_FSMPS)
+
+#define OHCI_CALC_FSMPS(x) ((((x)-210)*6/7))
+
+
+#define M_OHCI_FMINTERVAL_FIT _OHCI_MAKEMASK1(31)
+
+/*
+ * R_OHCI_FMREMAINING
+ */
+
+
+#define S_OHCI_FMREMAINING_FR 0
+#define M_OHCI_FMREMAINING_FR _OHCI_MAKEMASK(14,S_OHCI_FMREMAINING_FR)
+#define V_OHCI_FMREMAINING_FR(x) _OHCI_MAKEVALUE(x,S_OHCI_FMREMAINING_FR)
+#define G_OHCI_FMREMAINING_FR(x) _OHCI_GETVALUE(x,S_OHCI_FMREMAINING_FR,M_OHCI_FMREMAINING_FR)
+
+#define M_OHCI_FMREMAINING_FRT _OHCI_MAKEMASK1(31)
+
+/*
+ * R_OHCI_RHDSCRA
+ */
+
+
+#define S_OHCI_RHDSCRA_NDP 0
+#define M_OHCI_RHDSCRA_NDP _OHCI_MAKEMASK(8,S_OHCI_RHDSCRA_NDP)
+#define V_OHCI_RHDSCRA_NDP(x) _OHCI_MAKEVALUE(x,S_OHCI_RHDSCRA_NDP)
+#define G_OHCI_RHDSCRA_NDP(x) _OHCI_GETVALUE(x,S_OHCI_RHDSCRA_NDP,M_OHCI_RHDSCRA_NDP)
+
+#define M_OHCI_RHDSCRA_PSM _OHCI_MAKEMASK1(8)
+#define M_OHCI_RHDSCRA_NPS _OHCI_MAKEMASK1(9)
+#define M_OHCI_RHDSCRA_DT _OHCI_MAKEMASK1(10)
+#define M_OHCI_RHDSCRA_OCPM _OHCI_MAKEMASK1(11)
+#define M_OHCI_RHDSCRA_NOCP _OHCI_MAKEMASK1(12)
+
+#define S_OHCI_RHDSCRA_POTPGT 24
+#define M_OHCI_RHDSCRA_POTPGT _OHCI_MAKEMASK(8,S_OHCI_RHDSCRA_POTPGT)
+#define V_OHCI_RHDSCRA_POTPGT(x) _OHCI_MAKEVALUE(x,S_OHCI_RHDSCRA_POTPGT)
+#define G_OHCI_RHDSCRA_POTPGT(x) _OHCI_GETVALUE(x,S_OHCI_RHDSCRA_POTPGT,M_OHCI_RHDSCRA_POTPGT)
+
+/*
+ * R_OHCI_RHDSCRB
+ */
+
+#define S_OHCI_RHDSCRB_DR 0
+#define M_OHCI_RHDSCRB_DR _OHCI_MAKEMASK(16,S_OHCI_RHDSCRB_DR)
+#define V_OHCI_RHDSCRB_DR(x) _OHCI_MAKEVALUE(x,S_OHCI_RHDSCRB_DR)
+#define G_OHCI_RHDSCRB_DR(x) _OHCI_GETVALUE(x,S_OHCI_RHDSCRB_DR,M_OHCI_RHDSCRB_DR)
+
+#define S_OHCI_RHDSCRB_PPCM 16
+#define M_OHCI_RHDSCRB_PPCM _OHCI_MAKEMASK(16,S_OHCI_RHDSCRB_PPCM)
+#define V_OHCI_RHDSCRB_PPCM(x) _OHCI_MAKEVALUE(x,S_OHCI_RHDSCRB_PPCM)
+#define G_OHCI_RHDSCRB_PPCM(x) _OHCI_GETVALUE(x,S_OHCI_RHDSCRB_PPCM,M_OHCI_RHDSCRB_PPCM)
+
+/*
+ * R_OHCI_RHSTATUS
+ */
+
+#define M_OHCI_RHSTATUS_LPS _OHCI_MAKEMASK1(0)
+#define M_OHCI_RHSTATUS_OCI _OHCI_MAKEMASK1(1)
+#define M_OHCI_RHSTATUS_DRWE _OHCI_MAKEMASK1(15)
+#define M_OHCI_RHSTATUS_LPSC _OHCI_MAKEMASK1(16)
+#define M_OHCI_RHSTATUS_OCIC _OHCI_MAKEMASK1(17)
+#define M_OHCI_RHSTATUS_CRWE _OHCI_MAKEMASK1(31)
+
+/*
+ * R_OHCI_RHPORTSTATUS
+ */
+
+#define M_OHCI_RHPORTSTAT_CCS _OHCI_MAKEMASK1(0)
+#define M_OHCI_RHPORTSTAT_PES _OHCI_MAKEMASK1(1)
+#define M_OHCI_RHPORTSTAT_PSS _OHCI_MAKEMASK1(2)
+#define M_OHCI_RHPORTSTAT_POCI _OHCI_MAKEMASK1(3)
+#define M_OHCI_RHPORTSTAT_PRS _OHCI_MAKEMASK1(4)
+#define M_OHCI_RHPORTSTAT_PPS _OHCI_MAKEMASK1(8)
+#define M_OHCI_RHPORTSTAT_LSDA _OHCI_MAKEMASK1(9)
+#define M_OHCI_RHPORTSTAT_CSC _OHCI_MAKEMASK1(16)
+#define M_OHCI_RHPORTSTAT_PESC _OHCI_MAKEMASK1(17)
+#define M_OHCI_RHPORTSTAT_PSSC _OHCI_MAKEMASK1(18)
+#define M_OHCI_RHPORTSTAT_OCIC _OHCI_MAKEMASK1(19)
+#define M_OHCI_RHPORTSTAT_PRSC _OHCI_MAKEMASK1(20)
+
+#define M_OHCI_RHPORTSTAT_ALLC (M_OHCI_RHPORTSTAT_CSC | \
+ M_OHCI_RHPORTSTAT_PSSC | \
+ M_OHCI_RHPORTSTAT_OCIC | \
+ M_OHCI_RHPORTSTAT_PRSC)
+
+/* *********************************************************************
+ * OHCI Structures
+ ********************************************************************* */
+
+#define beginningof(ptr,type,field) ((type *) (((int) (ptr)) - ((int) ((type *) 0)->field)))
+
+#define OHCI_INTTREE_SIZE 63
+
+#define OHCI_EDPOOL_SIZE 128
+#define OHCI_TDPOOL_SIZE 32
+
+typedef struct ohci_endpoint_s {
+ struct ohci_endpoint_s *ep_next;
+ uint32_t ep_phys;
+ int ep_flags;
+ int ep_mps;
+ int ep_num;
+} ohci_endpoint_t;
+
+typedef struct ohci_transfer_s {
+ void *t_ref;
+ int t_length;
+ struct ohci_transfer_s *t_next;
+} ohci_transfer_t;
+
+typedef struct ohci_softc_s {
+ ohci_endpoint_t *ohci_edtable[OHCI_INTTREE_SIZE];
+ ohci_endpoint_t *ohci_inttable[OHCI_INTTABLE_SIZE];
+ ohci_endpoint_t *ohci_isoc_list;
+ ohci_endpoint_t *ohci_ctl_list;
+ ohci_endpoint_t *ohci_bulk_list;
+ ohci_hcca_t *ohci_hcca;
+ ohci_endpoint_t *ohci_endpoint_pool;
+ ohci_transfer_t *ohci_transfer_pool;
+ ohci_ed_t *ohci_hwedpool;
+ ohci_td_t *ohci_hwtdpool;
+ ohci_endpoint_t *ohci_endpoint_freelist;
+ ohci_transfer_t *ohci_transfer_freelist;
+#ifdef _CFE_
+ physaddr_t ohci_regs;
+#else
+ volatile uint32_t *ohci_regs;
+#endif
+ int ohci_ndp;
+ long ohci_addr;
+ uint32_t ohci_intdisable;
+
+ int ohci_rh_newaddr; /* Address to be set on next status update */
+ int ohci_rh_addr; /* address of root hub */
+ int ohci_rh_conf; /* current configuration # */
+ uint8_t ohci_rh_buf[128]; /* buffer to hold hub responses */
+ uint8_t *ohci_rh_ptr; /* pointer into buffer */
+ int ohci_rh_len; /* remaining bytes to transfer */
+ queue_t ohci_rh_intrq; /* Interrupt request queue */
+ usbbus_t *ohci_bus; /* owning usbbus structure */
+
+} ohci_softc_t;
+
+
+/*
+ * Misc stuff
+ */
+#define OHCI_RESET_DELAY 10
+
+
diff --git a/cfe/cfe/usb/usbchap9.h b/cfe/cfe/usb/usbchap9.h
new file mode 100644
index 0000000..1afd0db
--- /dev/null
+++ b/cfe/cfe/usb/usbchap9.h
@@ -0,0 +1,389 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * Chapter 9 definitions File: usbchap9.h
+ *
+ * This module contains definitions from the USB specification,
+ * chapter 9.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+
+#ifndef _USBCHAP9_H_
+#define _USBCHAP9_H_
+
+#define MAXIMUM_USB_STRING_LENGTH 255
+
+/*
+ * values for the bits returned by the USB GET_STATUS command
+ */
+#define USB_GETSTATUS_SELF_POWERED 0x01
+#define USB_GETSTATUS_REMOTE_WAKEUP_ENABLED 0x02
+
+
+#define USB_DEVICE_DESCRIPTOR_TYPE 0x01
+#define USB_CONFIGURATION_DESCRIPTOR_TYPE 0x02
+#define USB_STRING_DESCRIPTOR_TYPE 0x03
+#define USB_INTERFACE_DESCRIPTOR_TYPE 0x04
+#define USB_ENDPOINT_DESCRIPTOR_TYPE 0x05
+#define USB_POWER_DESCRIPTOR_TYPE 0x06
+#define USB_HID_DESCRIPTOR_TYPE 0x21
+#define USB_HUB_DESCRIPTOR_TYPE 0x29
+
+#define USB_DESCRIPTOR_TYPEINDEX(d, i) ((uint16_t)((uint16_t)(d)<<8 | (i)))
+
+/*
+ * Values for bmAttributes field of an
+ * endpoint descriptor
+ */
+
+#define USB_ENDPOINT_TYPE_MASK 0x03
+
+#define USB_ENDPOINT_TYPE_CONTROL 0x00
+#define USB_ENDPOINT_TYPE_ISOCHRONOUS 0x01
+#define USB_ENDPOINT_TYPE_BULK 0x02
+#define USB_ENDPOINT_TYPE_INTERRUPT 0x03
+
+
+/*
+ * definitions for bits in the bmAttributes field of a
+ * configuration descriptor.
+ */
+#define USB_CONFIG_POWERED_MASK 0xc0
+
+#define USB_CONFIG_BUS_POWERED 0x80
+#define USB_CONFIG_SELF_POWERED 0x40
+#define USB_CONFIG_REMOTE_WAKEUP 0x20
+
+/*
+ * Endpoint direction bit, stored in address
+ */
+
+#define USB_ENDPOINT_DIRECTION_MASK 0x80
+#define USB_ENDPOINT_DIRECTION_IN 0x80 /* bit set means IN */
+
+/*
+ * test direction bit in the bEndpointAddress field of
+ * an endpoint descriptor.
+ */
+#define USB_ENDPOINT_DIR_OUT(addr) (!((addr) & USB_ENDPOINT_DIRECTION_MASK))
+#define USB_ENDPOINT_DIR_IN(addr) ((addr) & USB_ENDPOINT_DIRECTION_MASK)
+
+#define USB_ENDPOINT_ADDRESS(addr) ((addr) & 0x0F)
+
+/*
+ * USB defined request codes
+ * see chapter 9 of the USB 1.0 specifcation for
+ * more information.
+ */
+
+/*
+ * These are the correct values based on the USB 1.0
+ * specification
+ */
+
+#define USB_REQUEST_GET_STATUS 0x00
+#define USB_REQUEST_CLEAR_FEATURE 0x01
+
+#define USB_REQUEST_SET_FEATURE 0x03
+
+#define USB_REQUEST_SET_ADDRESS 0x05
+#define USB_REQUEST_GET_DESCRIPTOR 0x06
+#define USB_REQUEST_SET_DESCRIPTOR 0x07
+#define USB_REQUEST_GET_CONFIGURATION 0x08
+#define USB_REQUEST_SET_CONFIGURATION 0x09
+#define USB_REQUEST_GET_INTERFACE 0x0A
+#define USB_REQUEST_SET_INTERFACE 0x0B
+#define USB_REQUEST_SYNC_FRAME 0x0C
+
+
+/*
+ * defined USB device classes
+ */
+
+
+#define USB_DEVICE_CLASS_RESERVED 0x00
+#define USB_DEVICE_CLASS_AUDIO 0x01
+#define USB_DEVICE_CLASS_COMMUNICATIONS 0x02
+#define USB_DEVICE_CLASS_HUMAN_INTERFACE 0x03
+#define USB_DEVICE_CLASS_MONITOR 0x04
+#define USB_DEVICE_CLASS_PHYSICAL_INTERFACE 0x05
+#define USB_DEVICE_CLASS_POWER 0x06
+#define USB_DEVICE_CLASS_PRINTER 0x07
+#define USB_DEVICE_CLASS_STORAGE 0x08
+#define USB_DEVICE_CLASS_HUB 0x09
+#define USB_DEVICE_CLASS_VENDOR_SPECIFIC 0xFF
+
+/*
+ * USB defined Feature selectors
+ */
+
+#define USB_FEATURE_ENDPOINT_STALL 0x0000
+#define USB_FEATURE_REMOTE_WAKEUP 0x0001
+#define USB_FEATURE_POWER_D0 0x0002
+#define USB_FEATURE_POWER_D1 0x0003
+#define USB_FEATURE_POWER_D2 0x0004
+#define USB_FEATURE_POWER_D3 0x0005
+
+/*
+ * USB Device descriptor.
+ * To reduce problems with compilers trying to optimize
+ * this structure, all the fields are bytes.
+ */
+
+#define USBWORD(x) ((x) & 0xFF),(((x) >> 8) & 0xFF)
+
+#define USB_CONTROL_ENDPOINT_MIN_SIZE 8
+
+typedef struct usb_device_descr_s {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bcdUSBLow,bcdUSBHigh;
+ uint8_t bDeviceClass;
+ uint8_t bDeviceSubClass;
+ uint8_t bDeviceProtocol;
+ uint8_t bMaxPacketSize0;
+ uint8_t idVendorLow,idVendorHigh;
+ uint8_t idProductLow,idProductHigh;
+ uint8_t bcdDeviceLow,bcdDeviceHigh;
+ uint8_t iManufacturer;
+ uint8_t iProduct;
+ uint8_t iSerialNumber;
+ uint8_t bNumConfigurations;
+} usb_device_descr_t;
+
+typedef struct usb_endpoint_descr_s {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bEndpointAddress;
+ uint8_t bmAttributes;
+ uint8_t wMaxPacketSizeLow,wMaxPacketSizeHigh;
+ uint8_t bInterval;
+} usb_endpoint_descr_t;
+
+/*
+ * values for bmAttributes Field in
+ * USB_CONFIGURATION_DESCRIPTOR
+ */
+
+#define CONFIG_BUS_POWERED 0x80
+#define CONFIG_SELF_POWERED 0x40
+#define CONFIG_REMOTE_WAKEUP 0x20
+
+typedef struct usb_config_descr_s {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t wTotalLengthLow,wTotalLengthHigh;
+ uint8_t bNumInterfaces;
+ uint8_t bConfigurationValue;
+ uint8_t iConfiguration;
+ uint8_t bmAttributes;
+ uint8_t MaxPower;
+} usb_config_descr_t;
+
+#define USB_INTERFACE_CLASS_HUB 0x09
+
+typedef struct usb_interface_descr_s {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bInterfaceNumber;
+ uint8_t bAlternateSetting;
+ uint8_t bNumEndpoints;
+ uint8_t bInterfaceClass;
+ uint8_t bInterfaceSubClass;
+ uint8_t bInterfaceProtocol;
+ uint8_t iInterface;
+} usb_interface_descr_t;
+
+typedef struct usb_string_descr_s {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bString[1];
+} usb_string_descr_t;
+
+/*
+ * USB power descriptor added to core specification
+ */
+
+#define USB_SUPPORT_D0_COMMAND 0x01
+#define USB_SUPPORT_D1_COMMAND 0x02
+#define USB_SUPPORT_D2_COMMAND 0x04
+#define USB_SUPPORT_D3_COMMAND 0x08
+
+#define USB_SUPPORT_D1_WAKEUP 0x10
+#define USB_SUPPORT_D2_WAKEUP 0x20
+
+
+typedef struct usb_power_descr_s {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bCapabilitiesFlags;
+ uint16_t EventNotification;
+ uint16_t D1LatencyTime;
+ uint16_t D2LatencyTime;
+ uint16_t D3LatencyTime;
+ uint8_t PowerUnit;
+ uint16_t D0PowerConsumption;
+ uint16_t D1PowerConsumption;
+ uint16_t D2PowerConsumption;
+} usb_power_descr_t;
+
+
+typedef struct usb_common_descr_s {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+} usb_common_descr_t;
+
+typedef struct usb_device_status_s {
+ uint8_t wDeviceStatusLow,wDeviceStatusHigh;
+} usb_device_status_t;
+
+
+/*
+ * Standard USB HUB definitions
+ *
+ * See Chapter 11
+ */
+
+#define USB_HUB_DESCR_SIZE 8
+typedef struct usb_hub_descr_s {
+ uint8_t bDescriptorLength; /* Length of this descriptor */
+ uint8_t bDescriptorType; /* Hub configuration type */
+ uint8_t bNumberOfPorts; /* number of ports on this hub */
+ uint8_t wHubCharacteristicsLow; /* Hub Charateristics */
+ uint8_t wHubCharacteristicsHigh;
+ uint8_t bPowerOnToPowerGood; /* port power on till power good in 2ms */
+ uint8_t bHubControlCurrent; /* max current in mA */
+ /* room for 255 ports power control and removable bitmask */
+ uint8_t bRemoveAndPowerMask[64];
+} usb_hub_descr_t;
+
+#define USB_HUBCHAR_PWR_GANGED 0
+#define USB_HUBCHAR_PWR_IND 1
+#define USB_HUBCHAR_PWR_NONE 2
+
+typedef struct usb_hub_status_s {
+ uint8_t wHubStatusLow,wHubStatusHigh;
+ uint8_t wHubChangeLow,wHubChangeHigh;
+} usb_hub_status_t;
+
+#define USB_PORT_STATUS_CONNECT 0x0001
+#define USB_PORT_STATUS_ENABLED 0x0002
+#define USB_PORT_STATUS_SUSPEND 0x0004
+#define USB_PORT_STATUS_OVERCUR 0x0008
+#define USB_PORT_STATUS_RESET 0x0010
+#define USB_PORT_STATUS_POWER 0x0100
+#define USB_PORT_STATUS_LOWSPD 0x0200
+
+typedef struct usb_port_status_s {
+ uint8_t wPortStatusLow,wPortStatusHigh;
+ uint8_t wPortChangeLow,wPortChangeHigh;
+} usb_port_status_t;
+
+
+#define USB_HUBREQ_GET_STATUS 0
+#define USB_HUBREQ_CLEAR_FEATURE 1
+#define USB_HUBREQ_GET_STATE 2
+#define USB_HUBREQ_SET_FEATURE 3
+#define USB_HUBREQ_GET_DESCRIPTOR 6
+#define USB_HUBREQ_SET_DESCRIPTOR 7
+
+#define USB_HUB_FEATURE_C_LOCAL_POWER 0
+#define USB_HUB_FEATURE_C_OVER_CURRENT 1
+
+#define USB_PORT_FEATURE_CONNECTION 0
+#define USB_PORT_FEATURE_ENABLE 1
+#define USB_PORT_FEATURE_SUSPEND 2
+#define USB_PORT_FEATURE_OVER_CURRENT 3
+#define USB_PORT_FEATURE_RESET 4
+#define USB_PORT_FEATURE_POWER 8
+#define USB_PORT_FEATURE_LOW_SPEED 9
+#define USB_PORT_FEATURE_C_PORT_CONNECTION 16
+#define USB_PORT_FEATURE_C_PORT_ENABLE 17
+#define USB_PORT_FEATURE_C_PORT_SUSPEND 18
+#define USB_PORT_FEATURE_C_PORT_OVER_CURRENT 19
+#define USB_PORT_FEATURE_C_PORT_RESET 20
+
+
+#define GETUSBFIELD(s,f) (((s)->f##Low) | ((s)->f##High << 8))
+#define PUTUSBFIELD(s,f,v) (s)->f##Low = (v & 0xFF); \
+ (s)->f##High = ((v)>>8 & 0xFF)
+
+typedef struct usb_device_request_s {
+ uint8_t bmRequestType;
+ uint8_t bRequest;
+ uint8_t wValueLow,wValueHigh;
+ uint8_t wIndexLow,wIndexHigh;
+ uint8_t wLengthLow,wLengthHigh;
+} usb_device_request_t;
+
+/*
+ * Values for the bmAttributes field of a request
+ */
+#define USBREQ_DIR_IN 0x80
+#define USBREQ_DIR_OUT 0x00
+#define USBREQ_TYPE_STD 0x00
+#define USBREQ_TYPE_CLASS 0x20
+#define USBREQ_TYPE_VENDOR 0x40
+#define USBREQ_TYPE_RSVD 0x60
+#define USBREQ_REC_DEVICE 0x00
+#define USBREQ_REC_INTERFACE 0x01
+#define USBREQ_REC_ENDPOINT 0x02
+#define USBREQ_REC_OTHER 0x03
+
+#define REQCODE(req,dir,type,rec) (((req) << 8) | (dir) | (type) | (rec))
+#define REQSW(req,attr) (((req) << 8) | (attr))
+
+/* *********************************************************************
+ * HID stuff
+ ********************************************************************* */
+
+typedef struct usb_hid_descr_s {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bcdHIDLow,bcdHIDHigh;
+ uint8_t bCountryCode;
+ uint8_t bNumDescriptors;
+ uint8_t bClassDescrType;
+ uint8_t wClassDescrLengthLow,wClassDescrLengthHigh;
+} usb_hid_descr_t;
+
+#endif /* _USBCHAP9_H_ */
diff --git a/cfe/cfe/usb/usbd.c b/cfe/cfe/usb/usbd.c
new file mode 100644
index 0000000..3e77049
--- /dev/null
+++ b/cfe/cfe/usb/usbd.c
@@ -0,0 +1,1215 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * USB device layer File: usbd.c
+ *
+ * This module deals with devices (things connected to USB buses)
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#ifndef _CFE_
+#include <stdio.h>
+#include <time.h>
+#include <memory.h>
+#include <stdint.h>
+#include "usbhack.h"
+#else
+#include "lib_types.h"
+#include "lib_string.h"
+#include "lib_printf.h"
+#include "cfe_timer.h"
+#endif
+
+#include "lib_malloc.h"
+#include "lib_queue.h"
+#include "usbchap9.h"
+#include "usbd.h"
+
+/* *********************************************************************
+ * Globals
+ ********************************************************************* */
+
+int usb_noisy = 0;
+
+
+/* *********************************************************************
+ * usb_create_pipe(dev,epaddr,mps,flags)
+ *
+ * Create a pipe, causing the corresponding endpoint to
+ * be created in the host controller driver. Pipes form the
+ * basic "handle" for unidirectional communications with a
+ * USB device.
+ *
+ * Input parameters:
+ * dev - device we're talking about
+ * epaddr - endpoint address open, usually from the endpoint
+ * descriptor
+ * mps - maximum packet size understood by the device
+ * flags - flags for this pipe (UP_xxx flags)
+ *
+ * Return value:
+ * <0 if error
+ * 0 if ok
+ ********************************************************************* */
+
+int usb_create_pipe(usbdev_t *dev,int epaddr,int mps,int flags)
+{
+ usbpipe_t *pipe;
+ int pipeidx;
+
+ pipeidx = USB_EPADDR_TO_IDX(epaddr);
+
+ if (dev->ud_pipes[pipeidx] != NULL) {
+ printf("Trying to create a pipe that was already created!\n");
+ return 0;
+ }
+
+ pipe = KMALLOC(sizeof(usbpipe_t),0);
+
+ if (!pipe) return -1;
+
+ pipe->up_flags = flags;
+ pipe->up_num = pipeidx;
+ pipe->up_mps = mps;
+ pipe->up_dev = dev;
+ if (dev->ud_flags & UD_FLAG_LOWSPEED) flags |= UP_TYPE_LOWSPEED;
+ pipe->up_hwendpoint = UBEPTCREATE(dev->ud_bus,
+ dev->ud_address,
+ USB_ENDPOINT_ADDRESS(epaddr),
+ mps,
+ flags);
+
+ dev->ud_pipes[pipeidx] = pipe;
+
+ return 0;
+}
+
+/* *********************************************************************
+ * usb_open_pipe(dev,epdesc)
+ *
+ * Open a pipe given an endpoint descriptor - this is the
+ * normal way pipes get open, since you've just selected a
+ * configuration and have the descriptors handy with all
+ * the information you need.
+ *
+ * Input parameters:
+ * dev - device we're talking to
+ * epdesc - endpoint descriptor
+ *
+ * Return value:
+ * <0 if error
+ * else endpoint/pipe number (from descriptor)
+ ********************************************************************* */
+
+int usb_open_pipe(usbdev_t *dev,usb_endpoint_descr_t *epdesc)
+{
+ int res;
+ int flags = 0;
+
+ if (USB_ENDPOINT_DIR_IN(epdesc->bEndpointAddress)) flags |= UP_TYPE_IN;
+ else flags |= UP_TYPE_OUT;
+
+ switch (epdesc->bmAttributes & USB_ENDPOINT_TYPE_MASK) {
+ case USB_ENDPOINT_TYPE_CONTROL:
+ flags |= UP_TYPE_CONTROL;
+ break;
+ case USB_ENDPOINT_TYPE_ISOCHRONOUS:
+ flags |= UP_TYPE_ISOC;
+ break;
+ case USB_ENDPOINT_TYPE_BULK:
+ flags |= UP_TYPE_BULK;
+ break;
+ case USB_ENDPOINT_TYPE_INTERRUPT:
+ flags |= UP_TYPE_INTR;
+ break;
+ }
+
+ res = usb_create_pipe(dev,
+ epdesc->bEndpointAddress,
+ GETUSBFIELD(epdesc,wMaxPacketSize),
+ flags);
+
+ if (res < 0) return res;
+
+ return epdesc->bEndpointAddress;
+}
+
+
+/* *********************************************************************
+ * usb_destroy_pipe(dev,epaddr)
+ *
+ * Close(destroy) an open pipe and remove endpoint descriptor
+ *
+ * Input parameters:
+ * dev - device we're talking to
+ * epaddr - pipe to close
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void usb_destroy_pipe(usbdev_t *dev,int epaddr)
+{
+ usbpipe_t *pipe;
+ int pipeidx;
+
+ pipeidx = USB_EPADDR_TO_IDX(epaddr);
+
+ pipe = dev->ud_pipes[pipeidx];
+ if (!pipe) return;
+
+ if (dev->ud_pipes[pipeidx]) {
+ UBEPTDELETE(dev->ud_bus,
+ dev->ud_pipes[pipeidx]->up_hwendpoint);
+ }
+
+ KFREE(dev->ud_pipes[pipeidx]);
+ dev->ud_pipes[pipeidx] = NULL;
+}
+
+/* *********************************************************************
+ * usb_destroy_device(dev)
+ *
+ * Delete an entire USB device, closing its pipes and freeing
+ * the device data structure
+ *
+ * Input parameters:
+ * dev - device to destroy
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void usb_destroy_device(usbdev_t *dev)
+{
+ int idx;
+
+ for (idx = 0; idx < UD_MAX_PIPES; idx++) {
+ if (dev->ud_pipes[idx]) {
+ UBEPTDELETE(dev->ud_bus,
+ dev->ud_pipes[idx]->up_hwendpoint);
+ KFREE(dev->ud_pipes[idx]);
+ }
+ }
+
+ dev->ud_bus->ub_devices[dev->ud_address] = NULL;
+
+ KFREE(dev);
+}
+
+
+/* *********************************************************************
+ * usb_create_device(bus,lowspeed)
+ *
+ * Create a new USB device. This device will be set to
+ * communicate on address zero (default address) and will be
+ * ready for basic stuff so we can figure out what it is.
+ * The control pipe will be open, so you can start requesting
+ * descriptors right away.
+ *
+ * Input parameters:
+ * bus - bus to create device on
+ * lowspeed - true if it's a lowspeed device (the hubs tell
+ * us these things)
+ *
+ * Return value:
+ * usb device structure, or NULL
+ ********************************************************************* */
+
+usbdev_t *usb_create_device(usbbus_t *bus,int lowspeed)
+{
+ usbdev_t *dev;
+ int pipeflags;
+
+ /*
+ * Create the device structure.
+ */
+
+ dev = KMALLOC(sizeof(usbdev_t),0);
+ memset(dev,0,sizeof(usbdev_t));
+
+ dev->ud_bus = bus;
+ dev->ud_address = 0; /* default address */
+ dev->ud_parent = NULL;
+ dev->ud_flags = 0;
+
+ /*
+ * Adjust things based on the target device speed
+ */
+
+ pipeflags = UP_TYPE_CONTROL;
+ if (lowspeed) {
+ pipeflags |= UP_TYPE_LOWSPEED;
+ dev->ud_flags |= UD_FLAG_LOWSPEED;
+ }
+
+ /*
+ * Create the control pipe.
+ */
+
+ usb_create_pipe(dev,0,
+ USB_CONTROL_ENDPOINT_MIN_SIZE,
+ pipeflags);
+
+ return dev;
+}
+
+/* *********************************************************************
+ * usb_make_request(dev,epaddr,buf,len,flags)
+ *
+ * Create a template request structure with basic fields
+ * ready to go. A shorthand routine.
+ *
+ * Input parameters:
+ * dev- device we're talking to
+ * epaddr - endpoint address, from usb_open_pipe()
+ * buf,length - user buffer and buffer length
+ * flags - transfer direction, etc. (UR_xxx flags)
+ *
+ * Return value:
+ * usbreq_t pointer, or NULL
+ ********************************************************************* */
+
+usbreq_t *usb_make_request(usbdev_t *dev,int epaddr,uint8_t *buf,int length,int flags)
+{
+ usbreq_t *ur;
+ usbpipe_t *pipe;
+ int pipeidx;
+
+ pipeidx = USB_EPADDR_TO_IDX(epaddr);
+
+ pipe = dev->ud_pipes[pipeidx];
+
+ if (pipe == NULL) return NULL;
+
+ ur = KMALLOC(sizeof(usbreq_t),0);
+ memset(ur,0,sizeof(usbreq_t));
+
+ ur->ur_dev = dev;
+ ur->ur_pipe = pipe;
+ ur->ur_buffer = buf;
+ ur->ur_length = length;
+ ur->ur_flags = flags;
+ ur->ur_callback = NULL;
+
+ return ur;
+
+}
+
+/* *********************************************************************
+ * usb_poll(bus)
+ *
+ * Handle device-driver polling - simply vectors to host controller
+ * driver.
+ *
+ * Input parameters:
+ * bus - bus structure
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void usb_poll(usbbus_t *bus)
+{
+ UBINTR(bus);
+}
+
+/* *********************************************************************
+ * usb_daemon(bus)
+ *
+ * Polls for topology changes and initiates a bus scan if
+ * necessary.
+ *
+ * Input parameters:
+ * bus - bus to watch
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void usb_daemon(usbbus_t *bus)
+{
+ /*
+ * Just see if someone flagged a need for a scan here
+ * and start the bus scan if necessary.
+ *
+ * The actual scanning is a hub function, starting at the
+ * root hub, so the code for that is over there.
+ */
+
+ if (bus->ub_flags & UB_FLG_NEEDSCAN) {
+ bus->ub_flags &= ~UB_FLG_NEEDSCAN;
+ usb_scan(bus);
+ }
+}
+
+/* *********************************************************************
+ * usb_cancel_request(ur)
+ *
+ * Cancel a pending usb transfer request.
+ *
+ * Input parameters:
+ * ur - request to cancel
+ *
+ * Return value:
+ * 0 if ok
+ * else error (could not find request)
+ ********************************************************************* */
+
+int usb_cancel_request(usbreq_t *ur)
+{
+ printf("usb_cancel_request is not implemented.\n");
+ return 0;
+}
+
+/* *********************************************************************
+ * usb_free_request(ur)
+ *
+ * Return a transfer request to the free pool.
+ *
+ * Input parameters:
+ * ur - request to return
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void usb_free_request(usbreq_t *ur)
+{
+ if (ur->ur_inprogress) {
+ printf("Yow! Tried to free a request that was in progress!\n");
+ return;
+ }
+ KFREE(ur);
+}
+
+/* *********************************************************************
+ * usb_delay_ms(bus,ms)
+ *
+ * Wait a while, calling the polling routine as we go.
+ *
+ * Input parameters:
+ * bus - bus we're talking to
+ * ms - how long to wait
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+
+void usb_delay_ms(usbbus_t *bus,int ms)
+{
+#ifdef _CFE_
+ cfe_sleep(1+((ms*CFE_HZ)/1000));
+#else
+ mydelay(ms);
+#endif
+}
+
+/* *********************************************************************
+ * usb_queue_request(ur)
+ *
+ * Call the transfer handler in the host controller driver to
+ * set up a transfer descriptor
+ *
+ * Input parameters:
+ * ur - request to queue
+ *
+ * Return value:
+ * 0 if ok
+ * else error
+ ********************************************************************* */
+
+int usb_queue_request(usbreq_t *ur)
+{
+ int res;
+
+ ur->ur_inprogress = 1;
+ ur->ur_xferred = 0;
+ res = UBXFER(ur->ur_dev->ud_bus,
+ ur->ur_pipe->up_hwendpoint,
+ ur);
+ return res;
+}
+
+/* *********************************************************************
+ * usb_wait_request(ur)
+ *
+ * Wait until a request completes, calling the polling routine
+ * as we wait.
+ *
+ * Input parameters:
+ * ur - request to wait for
+ *
+ * Return value:
+ * request status
+ ********************************************************************* */
+
+int usb_wait_request(usbreq_t *ur)
+{
+ while ((volatile int) (ur->ur_inprogress)) {
+ usb_poll(ur->ur_dev->ud_bus);
+ }
+
+ return ur->ur_status;
+}
+
+/* *********************************************************************
+ * usb_sync_request(ur)
+ *
+ * Synchronous request - call usb_queue and then usb_wait
+ *
+ * Input parameters:
+ * ur - request to submit
+ *
+ * Return value:
+ * status of request
+ ********************************************************************* */
+
+int usb_sync_request(usbreq_t *ur)
+{
+ usb_queue_request(ur);
+ return usb_wait_request(ur);
+}
+
+/* *********************************************************************
+ * usb_simple_request(dev,reqtype,bRequest,wValue,wIndex)
+ *
+ * Handle a simple USB control pipe request. These are OUT
+ * requests with no data phase.
+ *
+ * Input parameters:
+ * dev - device we're talking to
+ * reqtype - request type (bmRequestType) for descriptor
+ * wValue - wValue for descriptor
+ * wIndex - wIndex for descriptor
+ *
+ * Return value:
+ * 0 if ok
+ * else error
+ ********************************************************************* */
+
+int usb_simple_request(usbdev_t *dev,uint8_t reqtype,int bRequest,int wValue,int wIndex)
+{
+#if 0
+ uint8_t *requestbuf;
+ usb_device_request_t *req;
+ usbreq_t *ur;
+ int res;
+
+ requestbuf = KMALLOC(32,0);
+
+ req = (usb_device_request_t *) requestbuf;
+
+ req->bmRequestType = reqtype;
+ req->bRequest = bRequest;
+ PUTUSBFIELD(req,wValue,wValue);
+ PUTUSBFIELD(req,wIndex,wIndex);
+ PUTUSBFIELD(req,wLength,0);
+
+ if (usb_noisy > 1) printf("Request: ");
+ ur = usb_make_request(dev,0,requestbuf,sizeof(usb_device_request_t),UR_FLAG_SETUP);
+ res = usb_sync_request(ur);
+ usb_free_request(ur);
+
+ if (res == 4) { /* STALL on control pipe */
+ if (usb_noisy > 1) printf("STALL\n");
+ usb_clear_stall(dev,dev->ud_pipes[0]->up_num);
+ return -1;
+ }
+
+ res = ur->ur_xferred;
+ if (usb_noisy > 1) printf("Result %d\n",res);
+
+ if (usb_noisy > 1) printf("Status: ");
+ ur = usb_make_request(dev,0,requestbuf,0,UR_FLAG_STATUS_IN);
+ res = usb_sync_request(ur);
+ usb_free_request(ur);
+ if (usb_noisy > 1) printf("Result %d\n",res);
+
+ if (res == 4) { /* STALL */
+ if (usb_noisy > 1) printf("STALL\n");
+ usb_clear_stall(dev,dev->ud_pipes[0]->up_num);
+ return -1;
+ }
+
+ KFREE(requestbuf);
+
+ return 0;
+#else
+ return usb_std_request(dev,reqtype,bRequest,wValue,wIndex,NULL,0);
+#endif
+
+}
+
+
+/* *********************************************************************
+ * usb_set_configuration(dev,config)
+ *
+ * Set the current configuration for a USB device.
+ *
+ * Input parameters:
+ * dev - device we're talking to
+ * config - bConfigValue for the device
+ *
+ * Return value:
+ * request status
+ ********************************************************************* */
+
+int usb_set_configuration(usbdev_t *dev,int config)
+{
+ int res;
+
+ res = usb_simple_request(dev,0x00,USB_REQUEST_SET_CONFIGURATION,config,0);
+
+ return res;
+}
+
+
+/* *********************************************************************
+ * usb_new_address(bus)
+ *
+ * Return the next available address for the specified bus
+ *
+ * Input parameters:
+ * bus - bus to assign an address for
+ *
+ * Return value:
+ * new address, <0 if error
+ ********************************************************************* */
+
+int usb_new_address(usbbus_t *bus)
+{
+ int idx;
+
+ for (idx = 1; idx < USB_MAX_DEVICES; idx++) {
+ if (bus->ub_devices[idx] == NULL) return idx;
+ }
+
+ return -1;
+}
+
+/* *********************************************************************
+ * usb_set_address(dev,address)
+ *
+ * Set the address of a device. This also puts the device
+ * in the master device table for the bus and reconfigures the
+ * address of the control pipe.
+ *
+ * Input parameters:
+ * dev - device we're talking to
+ * address - new address (1..127)
+ *
+ * Return value:
+ * request status
+ ********************************************************************* */
+
+int usb_set_address(usbdev_t *dev,int address)
+{
+ int res;
+ int idx;
+ usbpipe_t *pipe;
+
+ res = usb_simple_request(dev,0x00,USB_REQUEST_SET_ADDRESS,address,0);
+
+ if (res == 0) {
+ dev->ud_bus->ub_devices[address] = dev;
+ dev->ud_address = address;
+ for (idx = 0; idx < UD_MAX_PIPES; idx++) {
+ pipe = dev->ud_pipes[idx];
+ if (pipe && pipe->up_hwendpoint) {
+ UBEPTSETADDR(dev->ud_bus,pipe->up_hwendpoint,address);
+ }
+ }
+ }
+
+ return res;
+}
+
+/* *********************************************************************
+ * usb_set_ep0mps(dev,mps)
+ *
+ * Set the maximum packet size of endpoint zero (mucks with the
+ * endpoint in the host controller)
+ *
+ * Input parameters:
+ * dev - device we're talking to
+ * mps - max packet size for endpoint zero
+ *
+ * Return value:
+ * request status
+ ********************************************************************* */
+
+int usb_set_ep0mps(usbdev_t *dev,int mps)
+{
+ usbpipe_t *pipe;
+
+ pipe = dev->ud_pipes[0];
+ if (pipe && pipe->up_hwendpoint) {
+ UBEPTSETMPS(dev->ud_bus,pipe->up_hwendpoint,mps);
+ }
+ if (pipe) {
+ pipe->up_mps = mps;
+ }
+
+ return 0;
+}
+
+/* *********************************************************************
+ * usb_clear_stall(dev,epaddr)
+ *
+ * Clear a stall condition on the specified pipe
+ *
+ * Input parameters:
+ * dev - device we're talking to
+ * epaddr - endpoint address
+ *
+ * Return value:
+ * 0 if ok
+ * else error
+ ********************************************************************* */
+int usb_clear_stall(usbdev_t *dev,int epaddr)
+{
+ uint8_t *requestbuf;
+ usb_device_request_t *req;
+ usbreq_t *ur;
+ int res;
+ int pipeidx;
+
+ /*
+ * Clear the stall in the hardware.
+ */
+
+ pipeidx = USB_EPADDR_TO_IDX(epaddr);
+
+ UBEPTCLEARTOGGLE(dev->ud_bus,dev->ud_pipes[pipeidx]->up_hwendpoint);
+
+ /*
+ * Do the "clear stall" request. Note that we should do this
+ * without calling usb_simple_request, since usb_simple_request
+ * may itself stall.
+ */
+
+ requestbuf = KMALLOC(32,0);
+
+ req = (usb_device_request_t *) requestbuf;
+
+ req->bmRequestType = 0x02;
+ req->bRequest = USB_REQUEST_CLEAR_FEATURE;
+ PUTUSBFIELD(req,wValue,0); /* ENDPOINT_HALT */
+ PUTUSBFIELD(req,wIndex,epaddr);
+ PUTUSBFIELD(req,wLength,0);
+
+ ur = usb_make_request(dev,0,requestbuf,
+ sizeof(usb_device_request_t),
+ UR_FLAG_SETUP);
+ res = usb_sync_request(ur);
+ usb_free_request(ur);
+ ur = usb_make_request(dev,0,requestbuf,0,UR_FLAG_STATUS_IN);
+ res = usb_sync_request(ur);
+ usb_free_request(ur);
+
+ KFREE(requestbuf);
+
+ return 0;
+}
+
+
+
+/* *********************************************************************
+ * usb_std_request(dev,bmRequestType,bRequest,wValue,
+ * wIndex,buffer,length)
+ *
+ * Do a standard control request on the control pipe,
+ * with the appropriate setup, data, and status phases.
+ *
+ * Input parameters:
+ * dev - dev we're talking to
+ * bmRequestType,bRequest,wValue,wIndex - fields for the
+ * USB request structure
+ * buffer - user buffer
+ * length - length of user buffer
+ *
+ * Return value:
+ * number of bytes transferred
+ ********************************************************************* */
+
+int usb_std_request(usbdev_t *dev,uint8_t bmRequestType,
+ uint8_t bRequest,uint16_t wValue,
+ uint16_t wIndex,uint8_t *buffer,int length)
+{
+ usbpipe_t *pipe = dev->ud_pipes[0];
+ usbreq_t *ur;
+ int res;
+ usb_device_request_t *req;
+ uint8_t *databuf = NULL;
+
+ req = KMALLOC(32,0);
+
+ if ((buffer != NULL) && (length !=0)) {
+ databuf = KMALLOC(length,0);
+ if (!(bmRequestType & USBREQ_DIR_IN)) {
+ memcpy(databuf,buffer,length);
+ }
+ else {
+ memset(databuf,0,length);
+ }
+ }
+
+ req->bmRequestType = bmRequestType;
+ req->bRequest = bRequest;
+ PUTUSBFIELD(req,wValue,wValue);
+ PUTUSBFIELD(req,wIndex,wIndex);
+ PUTUSBFIELD(req,wLength,length);
+
+ ur = usb_make_request(dev,0,(uint8_t *)req,sizeof(usb_device_request_t),UR_FLAG_SETUP);
+ res = usb_sync_request(ur);
+ usb_free_request(ur);
+
+ if (length != 0) {
+ if (bmRequestType & USBREQ_DIR_IN) {
+ ur = usb_make_request(dev,0,databuf,length,UR_FLAG_IN);
+ }
+ else {
+ ur = usb_make_request(dev,0,databuf,length,UR_FLAG_OUT);
+ }
+
+ res = usb_sync_request(ur);
+
+ if (res == 4) { /* STALL */
+ usb_clear_stall(dev,pipe->up_num);
+ usb_free_request(ur);
+ if (databuf) KFREE(databuf);
+ KFREE(req);
+ return 0;
+ }
+
+ length = ur->ur_xferred;
+ usb_free_request(ur);
+ }
+
+ if ((length != 0) && (databuf != NULL) && (bmRequestType & USBREQ_DIR_IN)) {
+ memcpy(buffer,databuf,length);
+ }
+
+ if (bmRequestType & USBREQ_DIR_IN) {
+ ur = usb_make_request(dev,0,(uint8_t *)req,0,UR_FLAG_STATUS_OUT);
+ }
+ else {
+ ur = usb_make_request(dev,0,(uint8_t *)req,0,UR_FLAG_STATUS_IN);
+ }
+
+ res = usb_sync_request(ur);
+ usb_free_request(ur);
+
+ if (res == 4) { /* STALL */
+ usb_clear_stall(dev,pipe->up_num);
+ if (databuf) KFREE(databuf);
+ KFREE(req);
+ return 0;
+ }
+
+ if (databuf) KFREE(databuf);
+ KFREE(req);
+
+ return length;
+}
+
+
+
+
+/* *********************************************************************
+ * usb_get_descriptor(dev,reqtype,dsctype,dscidx,respbuf,buflen)
+ *
+ * Request a descriptor from the device.
+ *
+ * Input parameters:
+ * dev - device we're talking to
+ * reqtype - bmRequestType field for descriptor we want
+ * dsctype - descriptor type we want
+ * dscidx - index of descriptor we want (often zero)
+ * respbuf - response buffer
+ * buflen - length of response buffer
+ *
+ * Return value:
+ * number of bytes transferred
+ ********************************************************************* */
+
+int usb_get_descriptor(usbdev_t *dev,uint8_t reqtype,int dsctype,int dscidx,
+ uint8_t *respbuf,int buflen)
+{
+ return usb_std_request(dev,
+ reqtype,USB_REQUEST_GET_DESCRIPTOR,
+ USB_DESCRIPTOR_TYPEINDEX(dsctype,dscidx),
+ 0,
+ respbuf,buflen);
+}
+
+/* *********************************************************************
+ * usb_get_string(dev,id,buf,maxlen)
+ *
+ * Request a string from the device, converting it from
+ * unicode to ascii (brutally).
+ *
+ * Input parameters:
+ * dev - device we're talking to
+ * id - string ID
+ * buf - buffer to receive string (null terminated)
+ * maxlen - length of buffer
+ *
+ * Return value:
+ * number of characters in returned string
+ ********************************************************************* */
+
+int usb_get_string(usbdev_t *dev,int id,char *buf,int maxlen)
+{
+ int amtcopy;
+ uint8_t *respbuf;
+ int idx;
+ usb_string_descr_t *sdscr;
+
+ respbuf = KMALLOC(maxlen*2+2,0);
+ sdscr = (usb_string_descr_t *) respbuf;
+
+ /*
+ * First time just get the header of the descriptor so we can
+ * get the string length
+ */
+
+ amtcopy = usb_get_descriptor(dev,USBREQ_DIR_IN,USB_STRING_DESCRIPTOR_TYPE,id,
+ respbuf,2);
+
+ /*
+ * now do it again to get the whole string.
+ */
+
+ if (maxlen > sdscr->bLength) maxlen = sdscr->bLength;
+
+ amtcopy = usb_get_descriptor(dev,USBREQ_DIR_IN,USB_STRING_DESCRIPTOR_TYPE,id,
+ respbuf,maxlen);
+
+ *buf = '\0';
+ amtcopy = sdscr->bLength - 2;
+ if (amtcopy <= 0) return amtcopy;
+
+ for (idx = 0; idx < amtcopy; idx+=2) {
+ *buf++ = sdscr->bString[idx];
+ }
+
+ *buf = '\0';
+
+ KFREE(respbuf);
+
+ return amtcopy;
+}
+
+
+
+/* *********************************************************************
+ * usb_get_device_descriptor(dev,dscr,smallflg)
+ *
+ * Request the device descriptor for the device. This is often
+ * the first descriptor requested, so it needs to be done in
+ * stages so we can find out how big the control pipe is.
+ *
+ * Input parameters:
+ * dev - device we're talking to
+ * dscr - pointer to buffer to receive descriptor
+ * smallflg - TRUE to request just 8 bytes.
+ *
+ * Return value:
+ * number of bytes copied
+ ********************************************************************* */
+
+int usb_get_device_descriptor(usbdev_t *dev,usb_device_descr_t *dscr,int smallflg)
+{
+ int res;
+ uint8_t *respbuf;
+ int amtcopy;
+
+ /*
+ * Smallflg truncates the request 8 bytes. We need to do this for
+ * the very first transaction to a USB device in order to determine
+ * the size of its control pipe. Bad things will happen if you
+ * try to retrieve more data than the control pipe will hold.
+ *
+ * So, be conservative at first and get the first 8 bytes of the
+ * descriptor. Byte 7 is bMaxPacketSize0, the size of the control
+ * pipe. Then you can go back and submit a bigger request for
+ * everything else.
+ */
+
+ amtcopy = smallflg ? USB_CONTROL_ENDPOINT_MIN_SIZE : sizeof(usb_device_descr_t);
+
+ respbuf = KMALLOC(64,0);
+ res = usb_get_descriptor(dev,USBREQ_DIR_IN,USB_DEVICE_DESCRIPTOR_TYPE,0,respbuf,amtcopy);
+ memcpy(dscr,respbuf,amtcopy);
+ KFREE(respbuf);
+ return res;
+
+}
+
+/* *********************************************************************
+ * usb_get_config_descriptor(dev,dscr,idx,maxlen)
+ *
+ * Request the configuration descriptor from the device.
+ *
+ * Input parameters:
+ * dev - device we're talking to
+ * dscr - descriptor buffer (receives data from device)
+ * idx - index of config we want (usually zero)
+ * maxlen - total size of buffer to receive descriptor
+ *
+ * Return value:
+ * number of bytes copied
+ ********************************************************************* */
+
+int usb_get_config_descriptor(usbdev_t *dev,usb_config_descr_t *dscr,int idx,int maxlen)
+{
+ int res;
+ uint8_t *respbuf;
+
+ respbuf = KMALLOC(maxlen,0);
+ res = usb_get_descriptor(dev,USBREQ_DIR_IN,
+ USB_CONFIGURATION_DESCRIPTOR_TYPE,idx,
+ respbuf,maxlen);
+ memcpy(dscr,respbuf,maxlen);
+ KFREE(respbuf);
+ return res;
+
+}
+
+
+
+/* *********************************************************************
+ * usb_get_device_status(dev,status)
+ *
+ * Request status from the device (status descriptor)
+ *
+ * Input parameters:
+ * dev - device we're talking to
+ * status - receives device_status structure
+ *
+ * Return value:
+ * number of bytes returned
+ ********************************************************************* */
+
+int usb_get_device_status(usbdev_t *dev,usb_device_status_t *status)
+{
+ return usb_std_request(dev,
+ USBREQ_DIR_IN,
+ 0,
+ 0,
+ 0,
+ (uint8_t *) status,
+ sizeof(usb_device_status_t));
+}
+
+
+/* *********************************************************************
+ * usb_complete_request(ur,status)
+ *
+ * Called when a usb request completes - pass status to
+ * caller and call the callback if there is one.
+ *
+ * Input parameters:
+ * ur - usbreq_t to complete
+ * status - completion status
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void usb_complete_request(usbreq_t *ur,int status)
+{
+ ur->ur_status = status;
+ ur->ur_inprogress = 0;
+ if (ur->ur_callback) (*(ur->ur_callback))(ur);
+}
+
+
+/* *********************************************************************
+ * usb_initroot(bus)
+ *
+ * Initialize the root hub for the bus - we need to do this
+ * each time a bus is configured.
+ *
+ * Input parameters:
+ * bus - bus to initialize
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void usb_initroot(usbbus_t *bus)
+{
+ usbdev_t *dev;
+ usb_driver_t *drv;
+ int addr;
+ int res;
+ uint8_t *buf;
+ int len;
+ usb_config_descr_t cfgdescr;
+
+ /*
+ * Create a device for the root hub.
+ */
+
+ dev = usb_create_device(bus,0);
+ bus->ub_roothub = dev;
+
+ /*
+ * Get the device descriptor. Make sure it's a hub.
+ */
+
+ res = usb_get_device_descriptor(dev,&(dev->ud_devdescr),TRUE);
+
+ if (dev->ud_devdescr.bDeviceClass != USB_DEVICE_CLASS_HUB) {
+ printf("Error! Root device is not a hub!\n");
+ return;
+ }
+
+ /*
+ * Set up the max packet size for the control endpoint,
+ * then get the rest of the descriptor.
+ */
+
+ usb_set_ep0mps(dev,dev->ud_devdescr.bMaxPacketSize0);
+ res = usb_get_device_descriptor(dev,&(dev->ud_devdescr),FALSE);
+
+ /*
+ * Obtain a new address and set the address of the
+ * root hub to this address.
+ */
+
+ addr = usb_new_address(dev->ud_bus);
+ res = usb_set_address(dev,addr);
+
+ /*
+ * Get the configuration descriptor and all the
+ * associated interface and endpoint descriptors.
+ */
+
+ res = usb_get_config_descriptor(dev,&cfgdescr,0,
+ sizeof(usb_config_descr_t));
+ if (res != sizeof(usb_config_descr_t)) {
+ printf("[a]usb_get_config_descriptor returns %d\n",res);
+ }
+
+ len = GETUSBFIELD(&cfgdescr,wTotalLength);
+ buf = KMALLOC(len,0);
+
+ res = usb_get_config_descriptor(dev,(usb_config_descr_t *)buf,0,len);
+ if (res != len) {
+ printf("[b]usb_get_config_descriptor returns %d\n",res);
+ }
+
+ dev->ud_cfgdescr = (usb_config_descr_t *) buf;
+
+ /*
+ * Select the configuration. Not really needed for our poor
+ * imitation root hub, but it's the right thing to do.
+ */
+
+ usb_set_configuration(dev,cfgdescr.bConfigurationValue);
+
+ /*
+ * Find the driver for this. It had better be the hub
+ * driver.
+ */
+
+ drv = usb_find_driver(dev);
+
+ /*
+ * Call the attach method.
+ */
+
+ (*(drv->udrv_attach))(dev,drv);
+
+ /*
+ * Hub should now be operational.
+ */
+
+}
+
+
+/* *********************************************************************
+ * usb_find_cfg_descr(dev,dtype,idx)
+ *
+ * Find a configuration descriptor - we retrieved all the config
+ * descriptors during discovery, this lets us dig out the one
+ * we want.
+ *
+ * Input parameters:
+ * dev - device we are talking to
+ * dtype - descriptor type to find
+ * idx - index of descriptor if there's more than one
+ *
+ * Return value:
+ * pointer to descriptor or NULL if not found
+ ********************************************************************* */
+
+void *usb_find_cfg_descr(usbdev_t *dev,int dtype,int idx)
+{
+ uint8_t *endptr;
+ uint8_t *ptr;
+ usb_config_descr_t *cfgdscr;
+
+ if (dev->ud_cfgdescr == NULL) return NULL;
+
+ ptr = (uint8_t *) dev->ud_cfgdescr;
+ endptr = ptr + GETUSBFIELD((dev->ud_cfgdescr),wTotalLength);
+
+ while (ptr < endptr) {
+
+ cfgdscr = (usb_config_descr_t *) ptr;
+
+ if (cfgdscr->bDescriptorType == dtype) {
+ if (idx == 0) return (void *) ptr;
+ else idx--;
+ }
+
+ ptr += cfgdscr->bLength;
+
+ }
+
+ return NULL;
+}
diff --git a/cfe/cfe/usb/usbd.h b/cfe/cfe/usb/usbd.h
new file mode 100644
index 0000000..73fde86
--- /dev/null
+++ b/cfe/cfe/usb/usbd.h
@@ -0,0 +1,308 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * USB Device Layer definitions File: usbd.h
+ *
+ * Definitions for the USB device layer.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+#ifndef _PHYSADDR_T_DEFINED_
+#include "lib_physio.h"
+#endif
+
+#include "usbchap9.h"
+
+
+/* *********************************************************************
+ * Forward declarations and opaque types
+ ********************************************************************* */
+
+typedef struct usb_hc_s usb_hc_t;
+typedef struct usb_ept_s usb_ept_t;
+typedef struct usb_hcdrv_s usb_hcdrv_t;
+typedef struct usbdev_s usbdev_t;
+typedef struct usb_driver_s usb_driver_t;
+
+/* *********************************************************************
+ * USB Bus structure - one of these per host controller
+ ********************************************************************* */
+
+#define USB_MAX_DEVICES 128
+
+typedef struct usbbus_s {
+ struct usbbus_s *ub_next; /* link to other buses */
+ usb_hc_t *ub_hwsoftc; /* bus driver softc */
+ usb_hcdrv_t *ub_hwdisp; /* bus driver dispatch */
+ usbdev_t *ub_roothub; /* root hub device */
+ usbdev_t *ub_devices[USB_MAX_DEVICES]; /* pointers to each device, idx by address */
+ unsigned int ub_flags; /* flag bits */
+ int ub_num; /* bus number */
+} usbbus_t;
+
+#define UB_FLG_NEEDSCAN 1 /* some device on bus needs scanning */
+
+/* *********************************************************************
+ * USB Pipe structure - one of these per unidirectional channel
+ * to an endpoint on a USB device
+ ********************************************************************* */
+
+#define UP_TYPE_CONTROL 1
+#define UP_TYPE_BULK 2
+#define UP_TYPE_INTR 4
+#define UP_TYPE_ISOC 8
+
+#define UP_TYPE_IN 128
+#define UP_TYPE_OUT 256
+
+#define UP_TYPE_LOWSPEED 16
+
+typedef struct usbpipe_s {
+ usb_ept_t *up_hwendpoint; /* OHCI-specific endpoint pointer */
+ usbdev_t *up_dev; /* our device info */
+ int up_num; /* pipe number */
+ int up_mps; /* max packet size */
+ int up_flags;
+} usbpipe_t;
+
+/* *********************************************************************
+ * USB device structure - one per device attached to the USB
+ * This is the basic structure applications will use to
+ * refer to a device.
+ ********************************************************************* */
+
+#define UD_FLAG_HUB 0x0001 /* this is a hub device */
+#define UD_FLAG_ROOTHUB 0x0002 /* this is a root hub device */
+#define UD_FLAG_LOWSPEED 0x0008 /* this is a lowspeed device */
+
+#define UD_MAX_PIPES 32
+#define USB_EPADDR_TO_IDX(addr) ((((addr)&0x80) >> 3) | ((addr) & 0x0F))
+//#define USB_EPADDR_TO_IDX(addr) USB_ENDPOINT_ADDRESS(addr)
+//#define UD_MAX_PIPES 16
+
+struct usbdev_s {
+ usb_driver_t *ud_drv; /* Driver's methods */
+ usbbus_t *ud_bus; /* owning bus */
+ int ud_address; /* USB address */
+ usbpipe_t *ud_pipes[UD_MAX_PIPES]; /* pipes, 0 is the control pipe */
+ struct usbdev_s *ud_parent; /* used for hubs */
+ int ud_flags;
+ void *ud_private; /* private data for device driver */
+ usb_device_descr_t ud_devdescr; /* device descriptor */
+ usb_config_descr_t *ud_cfgdescr; /* config, interface, and ep descrs */
+};
+
+
+/* *********************************************************************
+ * USB Request - basic structure to describe an in-progress
+ * I/O request. It associates buses, pipes, and buffers
+ * together.
+ ********************************************************************* */
+
+
+#define UR_FLAG_SYNC 0x8000
+
+#define UR_FLAG_SETUP 0x0001
+#define UR_FLAG_IN 0x0002
+#define UR_FLAG_OUT 0x0004
+#define UR_FLAG_STATUS_IN 0x0008 /* status phase of a control WRITE */
+#define UR_FLAG_STATUS_OUT 0x0010 /* status phase of a control READ */
+#define UR_FLAG_SHORTOK 0x0020 /* short transfers are ok */
+
+
+typedef struct usbreq_s {
+ queue_t ur_qblock;
+
+ /*
+ * pointers to our device and pipe
+ */
+
+ usbdev_t *ur_dev;
+ usbpipe_t *ur_pipe;
+
+ /*
+ * stuff to keep track of the data we transfer
+ */
+
+ uint8_t *ur_buffer;
+ int ur_length;
+ int ur_xferred;
+ int ur_status;
+ int ur_flags;
+
+ /*
+ * Stuff needed for the callback
+ */
+ void *ur_ref;
+ int ur_inprogress;
+ int (*ur_callback)(struct usbreq_s *req);
+
+ /*
+ * For use inside the ohci driver
+ */
+ void *ur_tdqueue;
+ int ur_tdcount;
+} usbreq_t;
+
+
+/* *********************************************************************
+ * Prototypes
+ ********************************************************************* */
+
+int usb_create_pipe(usbdev_t *dev,int pipenum,int mps,int flags);
+void usb_destroy_pipe(usbdev_t *dev,int pipenum);
+int usb_set_address(usbdev_t *dev,int addr);
+usbdev_t *usb_create_device(usbbus_t *bus,int lowspeed);
+void usb_destroy_device(usbdev_t *dev);
+usbreq_t *usb_make_request(usbdev_t *dev,int pipenum,uint8_t *buf,int length,int flags);
+void usb_poll(usbbus_t *bus);
+void usb_daemon(usbbus_t *bus);
+int usb_cancel_request(usbreq_t *ur);
+void usb_free_request(usbreq_t *ur);
+int usb_queue_request(usbreq_t *ur);
+int usb_wait_request(usbreq_t *ur);
+int usb_sync_request(usbreq_t *ur);
+int usb_get_descriptor(usbdev_t *dev,uint8_t reqtype,int dsctype,int dscidx,uint8_t *buffer,int buflen);
+int usb_get_config_descriptor(usbdev_t *dev,usb_config_descr_t *dscr,int idx,int maxlen);
+int usb_get_device_status(usbdev_t *dev,usb_device_status_t *status);
+int usb_set_configuration(usbdev_t *dev,int config);
+int usb_open_pipe(usbdev_t *dev,usb_endpoint_descr_t *epdesc);
+int usb_simple_request(usbdev_t *dev,uint8_t reqtype,int bRequest,int wValue,int wIndex);
+void usb_complete_request(usbreq_t *ur,int status);
+int usb_get_device_descriptor(usbdev_t *dev,usb_device_descr_t *dscr,int smallflg);
+int usb_set_ep0mps(usbdev_t *dev,int mps);
+int usb_new_address(usbbus_t *bus);
+int usb_get_string(usbdev_t *dev,int id,char *buf,int maxlen);
+int usb_std_request(usbdev_t *dev,uint8_t bmRequestType,
+ uint8_t bRequest,uint16_t wValue,
+ uint16_t wIndex,uint8_t *buffer,int length);
+void *usb_find_cfg_descr(usbdev_t *dev,int dtype,int idx);
+void usb_delay_ms(usbbus_t *bus,int ms);
+int usb_clear_stall(usbdev_t *dev,int pipe);
+
+void usb_scan(usbbus_t *bus);
+void usbhub_map_tree(usbbus_t *bus,int (*func)(usbdev_t *dev,void *arg),void *arg);
+void usbhub_dumpbus(usbbus_t *bus,uint32_t verbose);
+
+void usb_initroot(usbbus_t *bus);
+
+
+/* *********************************************************************
+ * Host Controller Driver
+ * Methods for abstracting the USB host controller from the
+ * rest of the goop.
+ ********************************************************************* */
+
+struct usb_hcdrv_s {
+ usbbus_t * (*hcdrv_create)(physaddr_t regaddr);
+ void (*hcdrv_delete)(usbbus_t *);
+ int (*hcdrv_start)(usbbus_t *);
+ void (*hcdrv_stop)(usbbus_t *);
+ int (*hcdrv_intr)(usbbus_t *);
+ usb_ept_t * (*hcdrv_ept_create)(usbbus_t *,int usbaddr,int eptnum,int mps,int flags);
+ void (*hcdrv_ept_delete)(usbbus_t *,usb_ept_t *);
+ void (*hcdrv_ept_setmps)(usbbus_t *,usb_ept_t *,int mps);
+ void (*hcdrv_ept_setaddr)(usbbus_t *,usb_ept_t *,int addr);
+ void (*hcdrv_ept_cleartoggle)(usbbus_t *,usb_ept_t *);
+ int (*hcdrv_xfer)(usbbus_t *,usb_ept_t *uept,usbreq_t *ur);
+};
+
+#define UBCREATE(driver,addr) (*((driver)->hcdrv_create))(addr)
+#define UBDELETE(bus) (*((bus)->ub_hwdisp->hcdrv_delete))(bus)
+#define UBSTART(bus) (*((bus)->ub_hwdisp->hcdrv_start))(bus)
+#define UBSTOP(bus) (*((bus)->ub_hwdisp->hcdrv_stop))(bus)
+#define UBINTR(bus) (*((bus)->ub_hwdisp->hcdrv_intr))(bus)
+#define UBEPTCREATE(bus,addr,num,mps,flags) (*((bus)->ub_hwdisp->hcdrv_ept_create))(bus,addr,num,mps,flags)
+#define UBEPTDELETE(bus,ept) (*((bus)->ub_hwdisp->hcdrv_ept_delete))(bus,ept)
+#define UBEPTSETMPS(bus,ept,mps) (*((bus)->ub_hwdisp->hcdrv_ept_setmps))(bus,ept,mps)
+#define UBEPTSETADDR(bus,ept,addr) (*((bus)->ub_hwdisp->hcdrv_ept_setaddr))(bus,ept,addr)
+#define UBEPTCLEARTOGGLE(bus,ept) (*((bus)->ub_hwdisp->hcdrv_ept_cleartoggle))(bus,ept)
+#define UBXFER(bus,ept,xfer) (*((bus)->ub_hwdisp->hcdrv_xfer))(bus,ept,xfer)
+
+/* *********************************************************************
+ * Devices - methods for abstracting things that _use_ USB
+ * (devices you can plug into the USB) - the entry points
+ * here are basically just for device discovery, since the top half
+ * of the actual driver will be device-specific.
+ ********************************************************************* */
+
+struct usb_driver_s {
+ char *udrv_name;
+ int (*udrv_attach)(usbdev_t *,usb_driver_t *);
+ int (*udrv_detach)(usbdev_t *);
+};
+
+typedef struct usb_drvlist_s {
+ int udl_class;
+ int udl_vendor;
+ int udl_product;
+ usb_driver_t *udl_disp;
+} usb_drvlist_t;
+
+extern usb_driver_t *usb_find_driver(usbdev_t *dev);
+
+#define CLASS_ANY -1
+#define VENDOR_ANY -1
+#define PRODUCT_ANY -1
+
+void mydelay(int x);
+
+#define IS_HUB(dev) ((dev)->ud_devdescr.bDeviceClass == USB_DEVICE_CLASS_HUB)
+
+/* *********************************************************************
+ * Error codes
+ ********************************************************************* */
+
+#define USBD_ERR_OK 0 /* Request ok */
+#define USBD_ERR_STALLED -1 /* Endpoint is stalled */
+#define USBD_ERR_IOERROR -2 /* I/O error */
+#define USBD_ERR_HWERROR -3 /* Hardware failure */
+#define USBD_ERR_CANCELED -4 /* Request canceled */
+#define USBD_ERR_NOMEM -5 /* Out of memory */
+#define USBD_ERR_TIMEOUT -6 /* Request timeout */
+
+/* *********************************************************************
+ * Debug routines
+ ********************************************************************* */
+
+void usb_dbg_dumpportstatus(int port,usb_port_status_t *portstatus,int level);
+void usb_dbg_dumpdescriptors(usbdev_t *dev,uint8_t *ptr,int len);
+void usb_dbg_dumpcfgdescr(usbdev_t *dev);
+void usb_dbg_dumpeptdescr(usb_endpoint_descr_t * epdscr);
diff --git a/cfe/cfe/usb/usbdebug.c b/cfe/cfe/usb/usbdebug.c
new file mode 100644
index 0000000..14ed866
--- /dev/null
+++ b/cfe/cfe/usb/usbdebug.c
@@ -0,0 +1,307 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * USB debugging code File: usbdebug.c
+ *
+ * This module contains debug code for USB.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#ifndef _CFE_
+#include <stdio.h>
+#include <time.h>
+#include <memory.h>
+#include <stdint.h>
+#include "usbhack.h"
+#else
+#include "lib_types.h"
+#include "lib_string.h"
+#include "lib_printf.h"
+#endif
+
+#include "lib_malloc.h"
+#include "lib_queue.h"
+#include "usbchap9.h"
+#include "usbd.h"
+
+
+void usb_dbg_dumpportstatus(int port,usb_port_status_t *portstatus,int level)
+{
+ int idx;
+ uint16_t x;
+
+ for (idx = 0; idx < level; idx++) printf(" ");
+ printf("PORT %d STATUS\n",port);
+
+ for (idx = 0; idx < level; idx++) printf(" ");
+ x = GETUSBFIELD((portstatus),wPortStatus);
+ printf("wPortStatus = %04X ",x);
+ if (x & 1) printf("DevicePresent ");
+ if (x & 2) printf("Enabled ");
+ if (x & 4) printf("Suspend ");
+ if (x & 8) printf("OverCurrent ");
+ if (x & 16) printf("InReset ");
+ if (x & 256) printf("Powered ");
+ if (x & 512) printf("LowSpeed ");
+ printf("\n");
+ for (idx = 0; idx < level; idx++) printf(" ");
+ x = GETUSBFIELD((portstatus),wPortChange);
+ printf("wPortChange = %04X ",x);
+ if (x & 1) printf("ConnectChange ");
+ if (x & 2) printf("EnableChange ");
+ if (x & 4) printf("SuspendChange ");
+ if (x & 8) printf("OverCurrentChange ");
+ if (x & 16) printf("ResetChange ");
+ printf("\n");
+}
+
+void usb_dbg_dumpeptdescr(usb_endpoint_descr_t * epdscr)
+{
+ printf("---------------------------------------------------\n");
+ printf("ENDPOINT DESCRIPTOR\n");
+
+ printf("bLength = %d\n",epdscr->bLength);
+ printf("bDescriptorType = %d\n",epdscr->bDescriptorType);
+ printf("bEndpointAddr = %02X\n",epdscr->bEndpointAddress);
+ printf("bmAttrbutes = %02X\n",epdscr->bmAttributes);
+ printf("wMaxPacketSize = %d\n",GETUSBFIELD(epdscr,wMaxPacketSize));
+ printf("bInterval = %d\n",epdscr->bInterval);
+}
+
+static char *getstringmaybe(usbdev_t *dev,int string)
+{
+ static char buf[256];
+
+ return "";
+
+ if (string == 0) {
+ strcpy(buf,"none");
+ return buf;
+ }
+
+ memset(buf,0,sizeof(buf));
+
+ usb_get_string(dev,string,buf,sizeof(buf));
+
+ return buf;
+}
+
+void usb_dbg_dumpdescriptors(usbdev_t *dev,uint8_t *ptr,int len)
+{
+ uint8_t *endptr;
+ usb_config_descr_t *cfgdscr;
+ usb_interface_descr_t *ifdscr;
+ usb_device_descr_t *devdscr;
+ usb_endpoint_descr_t *epdscr;
+ usb_hid_descr_t *hiddscr;
+ usb_hub_descr_t *hubdscr;
+ static char *eptattribs[4] = {"Control","Isoc","Bulk","Interrupt"};
+ int idx;
+
+ endptr = ptr + len;
+
+ while (ptr < endptr) {
+
+ cfgdscr = (usb_config_descr_t *) ptr;
+
+ switch (cfgdscr->bDescriptorType) {
+ case USB_DEVICE_DESCRIPTOR_TYPE:
+ devdscr = (usb_device_descr_t *) ptr;
+ printf("---------------------------------------------------\n");
+ printf("DEVICE DESCRIPTOR\n");
+ printf("bLength = %d\n",devdscr->bLength);
+ printf("bDescriptorType = %d\n",devdscr->bDescriptorType);
+ printf("bcdUSB = %04X\n",GETUSBFIELD(devdscr,bcdUSB));
+ printf("bDeviceClass = %d\n",devdscr->bDeviceClass);
+ printf("bDeviceSubClass = %d\n",devdscr->bDeviceSubClass);
+ printf("bDeviceProtocol = %d\n",devdscr->bDeviceProtocol);
+ printf("bMaxPktSize0 = %d\n",devdscr->bMaxPacketSize0);
+ if (endptr-ptr <= 8) break;
+ printf("idVendor = %04X (%d)\n",
+ GETUSBFIELD(devdscr,idVendor),
+ GETUSBFIELD(devdscr,idVendor));
+ printf("idProduct = %04X (%d)\n",
+ GETUSBFIELD(devdscr,idProduct),
+ GETUSBFIELD(devdscr,idProduct));
+ printf("bcdDevice = %04X\n",GETUSBFIELD(devdscr,bcdDevice));
+ printf("iManufacturer = %d (%s)\n",
+ devdscr->iManufacturer,
+ getstringmaybe(dev,devdscr->iManufacturer));
+ printf("iProduct = %d (%s)\n",
+ devdscr->iProduct,
+ getstringmaybe(dev,devdscr->iProduct));
+ printf("iSerialNumber = %d (%s)\n",
+ devdscr->iSerialNumber,
+ getstringmaybe(dev,devdscr->iSerialNumber));
+ printf("bNumConfigs = %d\n",devdscr->bNumConfigurations);
+ break;
+ case USB_CONFIGURATION_DESCRIPTOR_TYPE:
+
+ cfgdscr = (usb_config_descr_t *) ptr;
+ printf("---------------------------------------------------\n");
+ printf("CONFIG DESCRIPTOR\n");
+
+ printf("bLength = %d\n",cfgdscr->bLength);
+ printf("bDescriptorType = %d\n",cfgdscr->bDescriptorType);
+ printf("wTotalLength = %d\n",GETUSBFIELD(cfgdscr,wTotalLength));
+ printf("bNumInterfaces = %d\n",cfgdscr->bNumInterfaces);
+ printf("bConfigValue = %d\n",cfgdscr->bConfigurationValue);
+ printf("iConfiguration = %d (%s)\n",
+ cfgdscr->iConfiguration,
+ getstringmaybe(dev,cfgdscr->iConfiguration));
+ printf("bmAttributes = %02X\n",cfgdscr->bmAttributes);
+ printf("MaxPower = %d (%dma)\n",cfgdscr->MaxPower,cfgdscr->MaxPower*2);
+ break;
+
+ case USB_INTERFACE_DESCRIPTOR_TYPE:
+ printf("---------------------------------------------------\n");
+ printf("INTERFACE DESCRIPTOR\n");
+
+ ifdscr = (usb_interface_descr_t *) ptr;
+
+ printf("bLength = %d\n",ifdscr->bLength);
+ printf("bDescriptorType = %d\n",ifdscr->bDescriptorType);
+ printf("bInterfaceNum = %d\n",ifdscr->bInterfaceNumber);
+ printf("bAlternateSet = %d\n",ifdscr->bAlternateSetting);
+ printf("bNumEndpoints = %d\n",ifdscr->bNumEndpoints);
+ printf("bInterfaceClass = %d\n",ifdscr->bInterfaceClass);
+ printf("bInterSubClass = %d\n",ifdscr->bInterfaceSubClass);
+ printf("bInterfaceProto = %d\n",ifdscr->bInterfaceProtocol);
+ printf("iInterface = %d (%s)\n",
+ ifdscr->iInterface,
+ getstringmaybe(dev,ifdscr->iInterface));
+ break;
+
+ case USB_ENDPOINT_DESCRIPTOR_TYPE:
+ printf("---------------------------------------------------\n");
+ printf("ENDPOINT DESCRIPTOR\n");
+
+ epdscr = (usb_endpoint_descr_t *) ptr;
+
+ printf("bLength = %d\n",epdscr->bLength);
+ printf("bDescriptorType = %d\n",epdscr->bDescriptorType);
+ printf("bEndpointAddr = %02X (%d,%s)\n",
+ epdscr->bEndpointAddress,
+ epdscr->bEndpointAddress & 0x0F,
+ (epdscr->bEndpointAddress & USB_ENDPOINT_DIRECTION_IN) ? "IN" : "OUT"
+ );
+ printf("bmAttrbutes = %02X (%s)\n",
+ epdscr->bmAttributes,
+ eptattribs[epdscr->bmAttributes&3]);
+ printf("wMaxPacketSize = %d\n",GETUSBFIELD(epdscr,wMaxPacketSize));
+ printf("bInterval = %d\n",epdscr->bInterval);
+ break;
+
+ case USB_HID_DESCRIPTOR_TYPE:
+ printf("---------------------------------------------------\n");
+ printf("HID DESCRIPTOR\n");
+
+ hiddscr = (usb_hid_descr_t *) ptr;
+
+ printf("bLength = %d\n",hiddscr->bLength);
+ printf("bDescriptorType = %d\n",hiddscr->bDescriptorType);
+ printf("bcdHID = %04X\n",GETUSBFIELD(hiddscr,bcdHID));
+ printf("bCountryCode = %d\n",hiddscr->bCountryCode);
+ printf("bNumDescriptors = %d\n",hiddscr->bNumDescriptors);
+ printf("bClassDescrType = %d\n",hiddscr->bClassDescrType);
+ printf("wClassDescrLen = %d\n",GETUSBFIELD(hiddscr,wClassDescrLength));
+ break;
+
+ case USB_HUB_DESCRIPTOR_TYPE:
+ printf("---------------------------------------------------\n");
+ printf("HUB DESCRIPTOR\n");
+
+ hubdscr = (usb_hub_descr_t *) ptr;
+
+ printf("bLength = %d\n",hubdscr->bDescriptorLength);
+ printf("bDescriptorType = %d\n",hubdscr->bDescriptorType);
+ printf("bNumberOfPorts = %d\n",hubdscr->bNumberOfPorts);
+ printf("wHubCharacters = %04X\n",GETUSBFIELD(hubdscr,wHubCharacteristics));
+ printf("bPowerOnToPwrGd = %d\n",hubdscr->bPowerOnToPowerGood);
+ printf("bHubControlCurr = %d (ma)\n",hubdscr->bHubControlCurrent);
+ printf("bRemPwerMask[0] = %02X\n",hubdscr->bRemoveAndPowerMask[0]);
+
+ break;
+
+ default:
+ printf("---------------------------------------------------\n");
+ printf("UNKNOWN DESCRIPTOR\n");
+ printf("bLength = %d\n",cfgdscr->bLength);
+ printf("bDescriptorType = %d\n",cfgdscr->bDescriptorType);
+ printf("Data Bytes = ");
+ for (idx = 0; idx < cfgdscr->bLength; idx++) {
+ printf("%02X ",ptr[idx]);
+ }
+ printf("\n");
+
+ }
+
+ ptr += cfgdscr->bLength;
+
+ }
+}
+
+
+void usb_dbg_dumpcfgdescr(usbdev_t *dev)
+{
+ uint8_t buffer[512];
+ int res;
+ int len;
+ usb_config_descr_t *cfgdscr;
+
+ memset(buffer,0,sizeof(buffer));
+
+ cfgdscr = (usb_config_descr_t *) &buffer[0];
+
+ res = usb_get_config_descriptor(dev,cfgdscr,0,sizeof(usb_config_descr_t));
+ if (res != sizeof(usb_config_descr_t)) {
+ printf("[a]usb_get_config_descriptor returns %d\n",res);
+ }
+
+ len = GETUSBFIELD(cfgdscr,wTotalLength);
+
+ res = usb_get_config_descriptor(dev,cfgdscr,0,len);
+ if (res != len) {
+ printf("[b]usb_get_config_descriptor returns %d\n",res);
+ }
+
+ usb_dbg_dumpdescriptors(dev,&buffer[0],res);
+}
diff --git a/cfe/cfe/usb/usbdevs.c b/cfe/cfe/usb/usbdevs.c
new file mode 100644
index 0000000..53a0754
--- /dev/null
+++ b/cfe/cfe/usb/usbdevs.c
@@ -0,0 +1,168 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * USB Driver List File: usbdevs.c
+ *
+ * This module contains a table of supported USB devices and
+ * the routines to look up appropriate drivers given
+ * USB product, device, and class codes.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+#ifndef _CFE_
+#include <stdio.h>
+#include <memory.h>
+#include <stdint.h>
+#include "usbhack.h"
+#else
+#include "lib_types.h"
+#include "lib_string.h"
+#include "lib_printf.h"
+#endif
+
+#include "lib_malloc.h"
+#include "lib_queue.h"
+#include "usbchap9.h"
+#include "usbd.h"
+
+/* *********************************************************************
+ * The list of drivers we support. If you add more drivers,
+ * list them here.
+ ********************************************************************* */
+
+extern usb_driver_t usbhub_driver;
+extern usb_driver_t usbhid_driver;
+extern usb_driver_t usbmass_driver;
+extern usb_driver_t usbserial_driver;
+extern usb_driver_t usbeth_driver;
+
+usb_drvlist_t usb_drivers[] = {
+
+ /*
+ * Hub driver
+ */
+
+ {USB_DEVICE_CLASS_HUB, VENDOR_ANY, PRODUCT_ANY, &usbhub_driver},
+
+ /*
+ * Keyboards and mice
+ */
+
+ {USB_DEVICE_CLASS_HUMAN_INTERFACE, VENDOR_ANY,PRODUCT_ANY, &usbhid_driver},
+
+ /*
+ * Mass storage devices
+ */
+
+ {USB_DEVICE_CLASS_STORAGE, VENDOR_ANY, PRODUCT_ANY, &usbmass_driver},
+
+ /*
+ * Serial ports
+ */
+
+ {USB_DEVICE_CLASS_VENDOR_SPECIFIC,0x557,0x2008,&usbserial_driver},
+
+ /*
+ * Ethernet Adapters
+ */
+
+ {USB_DEVICE_CLASS_VENDOR_SPECIFIC,0x506,0x4601,&usbeth_driver}, /* 3Com */
+ {USB_DEVICE_CLASS_VENDOR_SPECIFIC,0x66b,0x2202,&usbeth_driver}, /* Linksys */
+ {USB_DEVICE_CLASS_VENDOR_SPECIFIC,0x66b,0x2203,&usbeth_driver}, /* Linksys */
+ {USB_DEVICE_CLASS_VENDOR_SPECIFIC,0x66b,0x2204,&usbeth_driver}, /* Linksys */
+ {USB_DEVICE_CLASS_VENDOR_SPECIFIC,0x66b,0x2206,&usbeth_driver}, /* Linksys */
+ {USB_DEVICE_CLASS_VENDOR_SPECIFIC,0x66b,0x400b,&usbeth_driver}, /* Linksys */
+ {USB_DEVICE_CLASS_VENDOR_SPECIFIC,0x66b,0x200c,&usbeth_driver}, /* Linksys */
+ {USB_DEVICE_CLASS_RESERVED,0xbda,0x8150,&usbeth_driver}, /* Realtek */
+ {USB_DEVICE_CLASS_VENDOR_SPECIFIC,0x423,0x000a,&usbeth_driver}, /* CATC */
+ {USB_DEVICE_CLASS_VENDOR_SPECIFIC,0x423,0x000c,&usbeth_driver}, /* Belkin */
+
+ {0,0,0,NULL}
+};
+
+
+/* *********************************************************************
+ * usb_find_driver(class,vendor,product)
+ *
+ * Find a suitable device driver to handle the specified
+ * class, vendor, or product.
+ *
+ * Input parameters:
+ * devdescr - device descriptor
+ *
+ * Return value:
+ * pointer to device driver or NULL
+ ********************************************************************* */
+
+usb_driver_t *usb_find_driver(usbdev_t *dev)
+{
+ usb_device_descr_t *devdescr;
+ usb_interface_descr_t *ifdescr;
+ usb_drvlist_t *list;
+ int dclass,vendor,product;
+
+ devdescr = &(dev->ud_devdescr);
+
+ dclass = devdescr->bDeviceClass;
+ if (dclass == 0) {
+ ifdescr = usb_find_cfg_descr(dev,USB_INTERFACE_DESCRIPTOR_TYPE,0);
+ if (ifdescr) dclass = ifdescr->bInterfaceClass;
+ }
+
+ vendor = (int) GETUSBFIELD(devdescr,idVendor);
+ product = (int) GETUSBFIELD(devdescr,idProduct);
+
+ printf("USB: Locating Class %02X Vendor %04X Product %04X: ",dclass,vendor,product);
+
+ list = usb_drivers;
+ while (list->udl_disp) {
+ if (((list->udl_class == dclass) || (list->udl_class == CLASS_ANY)) &&
+ ((list->udl_vendor == vendor) || (list->udl_vendor == VENDOR_ANY)) &&
+ ((list->udl_product == product) || (list->udl_product == PRODUCT_ANY))) {
+ printf("%s\n",list->udl_disp->udrv_name);
+ return list->udl_disp;
+ }
+ list++;
+ }
+
+ printf("Not found.\n");
+
+ return NULL;
+}
diff --git a/cfe/cfe/usb/usbeth.c b/cfe/cfe/usb/usbeth.c
new file mode 100644
index 0000000..bc5aeb0
--- /dev/null
+++ b/cfe/cfe/usb/usbeth.c
@@ -0,0 +1,850 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * USB Ethernet File: usbeth.c
+ *
+ * Driver for USB Ethernet devices.
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+/* *********************************************************************
+ * USB-Ethernet driver - CFE Network Layer Interfaces
+ * NOTE: Some of the device setup for the Admtek & Realtek devices
+ * was derived from reverse engineering! So these interfaces
+ * assume proper device operation.
+ ********************************************************************* */
+
+#include "lib_types.h"
+#include "lib_malloc.h"
+#include "lib_string.h"
+#include "lib_printf.h"
+
+#include "cfe_iocb.h"
+#include "cfe_ioctl.h"
+#include "cfe_timer.h"
+#include "cfe_device.h"
+#include "cfe_devfuncs.h"
+#include "cfe_error.h"
+
+#include "usbd.h"
+#include "usbeth.h"
+
+#if 0
+#define USBETH_TRACE( x, y ... ) xprintf( x, ##y )
+#else
+#define USBETH_TRACE( x, y ... )
+#endif
+
+#define FAIL -1
+
+static int Dev_cnt = 0;
+
+
+/******************************************************************************
+ Debug functions
+******************************************************************************/
+
+//#define DATA_DUMP
+#ifdef DATA_DUMP
+static void hexdump( unsigned char * src, int srclen, int rowlen, int rows )
+{
+ unsigned char * rowptr;
+ unsigned char * srcstp;
+ unsigned char * byteptr;
+
+ srcstp = src + srclen;
+
+ for( rowptr = src; rowptr < src + rowlen * rows; rowptr += rowlen ) {
+ for( byteptr = rowptr; byteptr < rowptr + rowlen && byteptr < srcstp; byteptr++ ) {
+ xprintf( "%2X ", *byteptr );
+ }
+ xprintf( "\n" );
+ }
+ xprintf( "\n" );
+}
+#endif
+
+
+/* *********************************************************************
+ * Interface functions for USB-Ethernet adapters
+ ********************************************************************* */
+
+enum { PEGASUS, PEGASUS_II, NETMATE, REALTEK };
+enum { VEN_NONE, _3_COM, LINKSYS, LINKSYS_10, LINKSYS_100,
+ CATC_NM, BELKIN_CATC, LINKSYS_100M };
+static char * VENDOR_NAMES[] =
+{
+ "?", "3-COM", "LinkSys", "LinkSys-10TX", "LinkSys-100TX",
+ "CATC-Netmate", "Belkin/CATC", "Linksys-100M", "Yikes!"
+};
+
+typedef struct usbeth_softc_s
+{
+ usbdev_t *dev;
+ int bulk_inpipe;
+ int bulk_outpipe;
+ int dev_id;
+ int ven_code;
+ int embed_tx_len;
+ uint8_t mac_addr[6];
+ usbreq_t *rx_ur;
+ uint8_t rxbuf[1600]; //artbitrary but enough for ethernet packet
+} usbeth_softc_t;
+
+
+/* **************************************
+ * CATC I/F Functions
+ ************************************** */
+
+#if 0
+static int catc_get_reg( usbdev_t *dev, int16_t reg, uint8_t *val )
+{
+ return usb_std_request( dev, (USBREQ_TYPE_VENDOR | USBREQ_DIR_IN),
+ CATC_GET_REG, 0, reg, val, 1 );
+}
+#endif
+
+static int catc_set_reg( usbdev_t *dev, int16_t reg, int16_t val )
+{
+ return usb_std_request( dev, (USBREQ_TYPE_VENDOR | USBREQ_DIR_OUT),
+ CATC_SET_REG, val, reg, NULL, 0 );
+}
+
+static int catc_set_mem( usbdev_t *dev, int16_t addr,
+ uint8_t *data, int16_t len )
+{
+ return usb_std_request( dev, (USBREQ_TYPE_VENDOR | USBREQ_DIR_OUT),
+ CATC_SET_MEM, 0, addr, data, len );
+}
+
+static int catc_get_mac_addr( usbdev_t *dev, uint8_t *mac_addr )
+{
+ int status;
+
+ status = usb_std_request( dev, (USBREQ_TYPE_VENDOR | USBREQ_DIR_IN),
+ CATC_GET_MAC_ADDR, 0, 0, mac_addr, 6 );
+ return( status );
+}
+
+static void catc_init_device( usbeth_softc_t * softc )
+{
+ usbdev_t *dev = softc->dev;
+ unsigned char *mcast_tbl;
+
+ usb_std_request( dev, (USBREQ_TYPE_STD | USBREQ_REC_INTERFACE),
+ USB_REQUEST_SET_INTERFACE,
+ 1, //alt setting 1
+ 0, NULL, 0 );
+
+ catc_set_reg(dev, CATC_TX_BUF_CNT_REG, 0x04 );
+ catc_set_reg(dev, CATC_RX_BUF_CNT_REG, 0x10 );
+ catc_set_reg(dev, CATC_ADV_OP_MODES_REG, 0x01 );
+ catc_set_reg(dev, CATC_LED_CTRL_REG, 0x08 );
+
+ /* Enable broadcast rx via bit in mutlicast table */
+ mcast_tbl = KMALLOC(64, 0);
+ memset( mcast_tbl, 0, 64 );
+ mcast_tbl[31] = 0x80; //i.e. broadcast bit
+ catc_set_mem( dev, CATC_MCAST_TBL_ADDR, mcast_tbl, 64 );
+ KFREE(mcast_tbl);
+
+ //Read the adapter's MAC addr
+ catc_get_mac_addr( dev, softc->mac_addr );
+}
+
+static void catc_close_device( usbdev_t *dev )
+{
+ // Now disable adapter from receiving packets
+ catc_set_reg( dev, CATC_ETH_CTRL_REG, 0 );
+}
+
+static void catc_open_device( usbeth_softc_t * softc )
+{
+ int i;
+
+ for(i = 0; i < 6; ++i)
+ catc_set_reg( softc->dev, (CATC_ETH_ADDR_0_REG - i), softc->mac_addr[i] );
+
+ // Now enable adapter to receive packets
+ catc_set_reg( softc->dev, CATC_ETH_CTRL_REG, 0x09 );
+}
+
+/* **************************************
+ * PEGASUS I/F Functions
+ ************************************** */
+
+static int peg_get_reg( usbdev_t *dev, int16_t reg, uint8_t *val, int16_t len )
+{
+ return usb_std_request( dev, (USBREQ_TYPE_VENDOR | USBREQ_DIR_IN),
+ PEG_GET_REG, 0, reg, val, len );
+}
+
+static int peg_set_reg( usbdev_t *dev, int16_t reg, int16_t val )
+{
+ unsigned char data = (uint8_t) val & 0xff;
+
+ return usb_std_request( dev, (USBREQ_TYPE_VENDOR | USBREQ_DIR_OUT),
+ PEG_SET_REG, val, reg, &data, 1 );
+}
+
+static int peg_set_regs( usbdev_t *dev, int16_t reg, int8_t *vals, int16_t len )
+{
+ return usb_std_request( dev, (USBREQ_TYPE_VENDOR | USBREQ_DIR_OUT),
+ PEG_SET_REG, 0, reg, vals, len );
+}
+
+static int peg_get_eep_word( usbdev_t *dev, int16_t ofs, uint8_t *val )
+{
+ int status=0, tries=20;
+ uint8_t data[2];
+
+ if( peg_set_reg( dev, PEG_EEPROM_CTL_REG, 0 ) == FAIL )
+ return FAIL;
+ if( peg_set_reg( dev, PEG_EEPROM_OFS_REG, ofs ) == FAIL )
+ return FAIL;
+ if( peg_set_reg( dev, PEG_EEPROM_CTL_REG, 0x02 ) == FAIL ) //read
+ return FAIL;
+ while( --tries )
+ {
+ if( peg_get_reg( dev, PEG_EEPROM_CTL_REG, data, 1 ) == FAIL )
+ return FAIL;
+ if( data[0] & 0x04 )
+ break; //eeprom data ready
+ }
+ if( !tries )
+ {
+ xprintf( "Pegasus Eeprom read failed!\n" );
+ return FAIL;
+ }
+ if( peg_get_reg( dev, PEG_EEPROM_DATA_REG, data, 2 ) == FAIL )
+ return FAIL;
+ val[0] = data[0];
+ val[1] = data[1];
+
+ return( status );
+}
+
+static int peg_get_mac_addr( usbdev_t *dev, uint8_t *mac_addr )
+{
+ int i, status;
+
+ for( i = 0; i < 3; ++i )
+ {
+ status = peg_get_eep_word( dev, i, &mac_addr[i*2] );
+ }
+ return( status );
+}
+
+static void peg_init_phy( usbdev_t *dev )
+{ //needed for earlier versions (before Rev B) of the USB-100TX adapters
+ static uint8_t phy_magic_wr[] = { 0, 4, 0, 0x1b };
+ static uint8_t read_status[] = { 0, 0, 0, 1 };
+ uint8_t data[4];
+
+ //reset the MAC ans set up GPIOs
+ peg_set_reg( dev, PEG_ETH_CTL1_REG, 0x08 );
+ peg_get_reg( dev, PEG_ETH_CTL1_REG, data, 1 );
+
+ //do following steps to enable link activitiy LED
+ peg_set_reg( dev, PEG_GPIO1_REG, 0x26 );
+ peg_set_reg( dev, PEG_GPIO0_REG, 0x24 );
+ peg_set_reg( dev, PEG_GPIO0_REG, 0x26 );
+
+ //do following set of steps to enable LINK LED
+ memcpy( data, phy_magic_wr, 4 );
+ peg_set_regs( dev, PEG_PHY_ADDR_REG, data, 4); //set up for magic word
+ peg_set_reg( dev, PEG_PHY_CTRL_REG, (0x1b|PHY_WRITE) );
+ peg_get_reg( dev, PEG_PHY_CTRL_REG, data, 1 ); //read status of write
+ memcpy( data, read_status, 4 );
+ peg_set_regs( dev, PEG_PHY_ADDR_REG, data, 4); //set up for phy status reg
+ peg_set_reg( dev, PEG_PHY_CTRL_REG, (1|PHY_READ) );
+ peg_get_reg( dev, PEG_PHY_CTRL_REG, data, 1 ); //read status of read
+ peg_get_reg( dev, PEG_PHY_DATA_REG, data, 2 ); //read status regs
+}
+
+static void peg_init_device( usbeth_softc_t * softc )
+{
+ usbdev_t *dev = softc->dev;
+
+ if( softc->dev_id == PEGASUS_II )
+ peg_set_reg( dev, PEG_INT_PHY_REG, 0x02 ); //enable internal PHY
+ else
+ peg_init_phy( dev );
+
+ //Read the adapter's MAC addr
+ peg_get_mac_addr( dev, softc->mac_addr );
+}
+
+static void peg_close_device( usbdev_t *dev )
+{
+ //Now disable adapter from receiving or transmitting packets
+ peg_set_reg( dev, PEG_ETH_CTL1_REG, 0 );
+}
+
+static void peg_open_device( usbeth_softc_t * softc )
+{
+ usbdev_t *dev = softc->dev;
+
+ //Now setup adapter's receiver with MAC address
+ peg_set_regs( dev, PEG_MAC_ADDR_0_REG, softc->mac_addr, 6 );
+
+ //Now enable adapter to receive and transmit packets
+ peg_set_reg( dev, PEG_ETH_CTL0_REG, 0xc1 );
+ peg_set_reg( dev, PEG_ETH_CTL1_REG, 0x30 );
+}
+
+/* **************************************
+ * REALTEK I/F Functions
+ ************************************** */
+
+//
+// ********** NOT FULLY WORKING YET!!!!!!!!!! ***************
+//
+
+static int rtek_get_reg( usbdev_t *dev, int16_t reg, uint8_t *val, int16_t len )
+{
+ return usb_std_request( dev, (USBREQ_TYPE_VENDOR | USBREQ_DIR_IN),
+ RTEK_REG_ACCESS, reg, 0, val, len );
+}
+
+static int rtek_set_reg( usbdev_t *dev, int16_t reg, int16_t val )
+{
+ unsigned char data = (uint8_t) val & 0xff;
+
+ return usb_std_request( dev, (USBREQ_TYPE_VENDOR | USBREQ_DIR_OUT),
+ RTEK_REG_ACCESS, reg, 0, &data, 1 );
+}
+
+static int rtek_get_mac_addr( usbdev_t *dev, uint8_t *mac_addr )
+{
+ int status;
+
+ status = rtek_get_reg( dev, RTEK_MAC_REG, mac_addr, 6 );
+
+ return( status );
+}
+
+static void rtek_init_device( usbeth_softc_t * softc )
+{
+ int i;
+ usbdev_t *dev = softc->dev;
+ uint8_t val;
+
+ //Reset the adapter
+ rtek_set_reg( dev, RTEK_CMD_REG, RTEK_RESET );
+ for( i = 0; i < 10; ++i )
+ {
+ rtek_get_reg( dev, RTEK_CMD_REG, &val, 1 );
+ if( !(val & RTEK_RESET) )
+ break;
+ usb_delay_ms( NULL, 1 );
+ }
+
+ //autoload the internal registers
+ rtek_set_reg( dev, RTEK_CMD_REG, RTEK_AUTOLOAD );
+ for( i = 0; i < 50; ++i )
+ {
+ rtek_get_reg( dev, RTEK_CMD_REG, &val, 1 );
+ if( !(val & RTEK_AUTOLOAD) )
+ break;
+ usb_delay_ms( NULL, 1 );
+ }
+
+ //Read the adapter's MAC addr
+ rtek_get_mac_addr( dev, softc->mac_addr );
+}
+
+static void rtek_close_device( usbdev_t *dev )
+{
+ //Now disable adapter from receiving or transmitting packets
+ rtek_set_reg( dev, RTEK_CMD_REG, 0 );
+}
+
+static void rtek_open_device( usbeth_softc_t * softc )
+{
+ //accept broadcast & own packets
+ rtek_set_reg( softc->dev, RTEK_RXCFG_REG, 0x0c );
+
+ //Now enable adapter to receive and transmit packets
+ rtek_set_reg( softc->dev, RTEK_CMD_REG, 0x0c );
+}
+
+//*********************** USB-ETH I/F Functions ****************************
+
+static const int ID_TBL[] =
+{
+ 0x0506, 0x4601, PEGASUS_II, _3_COM, //3-Com
+ 0x066b, 0x2202, PEGASUS_II, LINKSYS_10, //LinkSys
+ 0x066b, 0x2203, PEGASUS, LINKSYS_100,
+ 0x066b, 0x2204, PEGASUS, LINKSYS_100,
+ 0x066b, 0x2206, PEGASUS, LINKSYS,
+ 0x066b, 0x400b, PEGASUS_II, LINKSYS_10,
+ 0x066b, 0x200c, PEGASUS_II, LINKSYS_10,
+ 0x0bda, 0x8150, REALTEK, LINKSYS_100M,
+ 0x0423, 0x000a, NETMATE, CATC_NM, //CATC (Netmate I)
+ 0x0423, 0x000c, NETMATE, BELKIN_CATC, //Belkin & CATC (Netmate II)
+ -1
+};
+
+static int usbeth_init_device( usbeth_softc_t * softc )
+{
+ int i;
+ usb_device_descr_t dev_desc;
+ uint16_t vendor_id, device_id;
+ const int *ptr=ID_TBL;
+
+ //find out which device is connected
+ usb_get_device_descriptor( softc->dev, &dev_desc, 0 );
+ vendor_id = (dev_desc.idVendorHigh << 8) + dev_desc.idVendorLow;
+ device_id = (dev_desc.idProductHigh << 8) + dev_desc.idProductLow;
+ xprintf( "USB device: vendor id %04x, device id %04x\n",
+ vendor_id, device_id );
+
+ while( *ptr != -1 )
+ {
+ if( (vendor_id == ptr[0]) && (device_id == ptr[1]) )
+ {
+ softc->dev_id = ptr[2];
+ softc->ven_code = ptr[3];
+ break;
+ }
+ ptr += 4;
+ }
+ if( *ptr == -1 )
+ {
+ xprintf( "Unrecognized USB-Ethernet device\n" );
+ return -1;
+ }
+
+ //init the adapter
+ if( softc->dev_id == NETMATE )
+ {
+ catc_init_device( softc );
+ softc->embed_tx_len = 1;
+ }
+ else
+ {
+ if( softc->dev_id == REALTEK )
+ {
+ rtek_init_device( softc );
+ softc->embed_tx_len = 0;
+ }
+ else
+ {
+ peg_init_device( softc );
+ softc->embed_tx_len = 1;
+ }
+ }
+
+ //display adapter info
+ xprintf( "%s USB-Ethernet Adapter (", VENDOR_NAMES[softc->ven_code] );
+ for( i = 0; i < 6; ++i )
+ xprintf( "%02x%s", softc->mac_addr[i], (i == 5) ? ")\n" : ":" );
+
+ return 0;
+}
+
+static int usbeth_get_dev_addr( usbeth_softc_t * softc, uint8_t *mac_addr )
+{
+ memcpy( mac_addr, softc->mac_addr, 6 );
+ return 0;
+}
+
+static void usbeth_queue_rx( usbeth_softc_t * softc )
+{
+ softc->rx_ur = usb_make_request(softc->dev, softc->bulk_inpipe,
+ softc->rxbuf, sizeof(softc->rxbuf),
+ (UR_FLAG_IN | UR_FLAG_SHORTOK));
+ usb_queue_request(softc->rx_ur);
+}
+
+static void usbeth_close_device( usbeth_softc_t * softc )
+{
+ if( softc->dev_id == NETMATE )
+ catc_close_device( softc->dev );
+ else if( softc->dev_id == REALTEK )
+ rtek_close_device( softc->dev );
+ else
+ peg_close_device( softc->dev );
+}
+
+static void usbeth_open_device( usbeth_softc_t * softc )
+{
+ if( softc->dev_id == NETMATE )
+ catc_open_device( softc );
+ else if( softc->dev_id == REALTEK )
+ rtek_open_device( softc );
+ else
+ peg_open_device( softc );
+
+ //kick start the receive
+ usbeth_queue_rx( softc );
+}
+
+static int usbeth_data_rx( usbeth_softc_t * softc )
+{
+ usb_poll(softc->dev->ud_bus);
+ return( !softc->rx_ur->ur_inprogress );
+}
+
+static int usbeth_get_eth_frame( usbeth_softc_t * softc, unsigned char * buf )
+{
+ int len = 0;
+
+ if( !softc->rx_ur->ur_inprogress )
+ {
+ len = softc->rx_ur->ur_xferred;
+ memcpy( buf, softc->rxbuf, len );
+ usb_free_request(softc->rx_ur);
+ usbeth_queue_rx( softc );
+ }
+ else
+ xprintf( "Bulk data is not available yet!\n" );
+
+ return( len );
+}
+
+static int usbeth_send_eth_frame( usbeth_softc_t * softc, unsigned char * buf, int len )
+{
+ usbreq_t *ur;
+ int txlen = len;
+ unsigned char * txbuf;
+
+ if(softc->embed_tx_len)
+ {
+ txbuf = KMALLOC((len+2), 0);
+ txbuf[0] = txlen & 0xff;
+ txbuf[1] = (txlen >> 8) & 0xff; //1st two bytes...little endian
+ memcpy( &txbuf[2], buf, txlen );
+ txlen += 2;
+ }
+ else
+ {
+ if( softc->dev_id == REALTEK )
+ {
+ //Now for some Realtek chip workarounds
+ if( txlen < 60 ) //some strange limitation
+ txlen = 60;
+ else if( !(txlen % 64) ) //to handle module 64 packets
+ ++txlen;
+ }
+ txbuf = KMALLOC(txlen, 0);
+ memcpy( txbuf, buf, txlen );
+ }
+ ur = usb_make_request(softc->dev, softc->bulk_outpipe,
+ txbuf, txlen, UR_FLAG_OUT);
+ usb_sync_request(ur);
+ usb_free_request(ur);
+ KFREE(txbuf);
+
+ return( len );
+}
+
+
+/* *********************************************************************
+ * CFE-USB interfaces
+ ********************************************************************* */
+
+/* *********************************************************************
+ * usbeth_attach(dev,drv)
+ *
+ * This routine is called when the bus scan stuff finds a usb-ethernet
+ * device. We finish up the initialization by configuring the
+ * device and allocating our softc here.
+ *
+ * Input parameters:
+ * dev - usb device, in the "addressed" state.
+ * drv - the driver table entry that matched
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+
+const cfe_driver_t usbethdrv; //forward declaration
+
+static int usbeth_attach(usbdev_t *dev,usb_driver_t *drv)
+{
+ usb_config_descr_t *cfgdscr = dev->ud_cfgdescr;
+ usb_endpoint_descr_t *epdscr;
+ usb_endpoint_descr_t *indscr = NULL;
+ usb_endpoint_descr_t *outdscr = NULL;
+ usb_interface_descr_t *ifdscr;
+ usbeth_softc_t *softc;
+ int idx;
+
+ dev->ud_drv = drv;
+
+ softc = (usbeth_softc_t *) KMALLOC( sizeof(usbeth_softc_t), 0 );
+ if( softc == NULL )
+ {
+ xprintf( "Failed to allocate softc memory.\n" );
+ return -1;
+ }
+ memset( softc, 0, sizeof(usbeth_softc_t) );
+ dev->ud_private = softc;
+ softc->dev = dev;
+
+ ifdscr = usb_find_cfg_descr(dev,USB_INTERFACE_DESCRIPTOR_TYPE,0);
+ if (ifdscr == NULL)
+ {
+ xprintf("USBETH: ERROR...no interace descriptor\n");
+ return -1;
+ }
+
+
+ for (idx = 0; idx < 2; idx++)
+ {
+ epdscr = usb_find_cfg_descr(dev,USB_ENDPOINT_DESCRIPTOR_TYPE,idx);
+ if (USB_ENDPOINT_DIR_OUT(epdscr->bEndpointAddress))
+ outdscr = epdscr;
+ else
+ indscr = epdscr;
+ }
+
+ if (!indscr || !outdscr)
+ {
+ /*
+ * Could not get descriptors, something is very wrong.
+ * Leave device addressed but not configured.
+ */
+ xprintf("USBETH: ERROR...no endpoint descriptors\n");
+ return -1;
+ }
+
+ /*
+ * Choose the standard configuration.
+ */
+
+ usb_set_configuration(dev,cfgdscr->bConfigurationValue);
+
+ // Quit if not able to initialize the device
+ if (usbeth_init_device(softc) < 0)
+ return -1;
+
+ /*
+ * Open the pipes.
+ */
+
+ softc->bulk_inpipe = usb_open_pipe(dev,indscr);
+ softc->bulk_outpipe = usb_open_pipe(dev,outdscr);
+
+ //Now attach this device as a CFE Ethernet device
+ cfe_attach( (cfe_driver_t *) &usbethdrv, softc, NULL,
+ usbethdrv.drv_description );
+
+ ++Dev_cnt;
+
+ return 0;
+}
+
+/* *********************************************************************
+ * usbeth_detach(dev)
+ *
+ * This routine is called when the bus scanner notices that
+ * this device has been removed from the system. We should
+ * do any cleanup that is required. The pending requests
+ * will be cancelled automagically.
+ *
+ * Input parameters:
+ * dev - usb device
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+
+static int usbeth_detach(usbdev_t *dev)
+{
+ usbeth_softc_t *softc = (usbeth_softc_t *) dev->ud_private;
+
+ --Dev_cnt;
+ KFREE(softc);
+
+ //*** SHOULD DETACH THE ETHERNET DEVICE TOO...LATER
+
+ return 0;
+}
+
+// CFE USB device interface structure
+usb_driver_t usbeth_driver =
+{
+ "Ethernet Device",
+ usbeth_attach,
+ usbeth_detach
+};
+
+
+
+/* *********************************************************************
+ * CFE-Ethernet device interfaces
+ ********************************************************************* */
+
+
+static int usbeth_ether_open(cfe_devctx_t *ctx)
+{
+ if( !Dev_cnt )
+ return CFE_ERR_NOTREADY;
+
+ USBETH_TRACE( "%s called.\n", __FUNCTION__ );
+ usbeth_open_device( (usbeth_softc_t *) ctx->dev_softc );
+
+ return 0;
+}
+
+static int usbeth_ether_read( cfe_devctx_t * ctx, iocb_buffer_t * buffer )
+{
+ if( !Dev_cnt )
+ return CFE_ERR_NOTREADY;
+
+ buffer->buf_retlen = usbeth_get_eth_frame( (usbeth_softc_t *)ctx->dev_softc,
+ buffer->buf_ptr );
+
+#ifdef DATA_DUMP
+ xprintf( "Incoming packet :\n" );
+ hexdump( buffer->buf_ptr, buffer->buf_retlen, 16,
+ buffer->buf_retlen / 16 + 1 );
+#endif
+
+ return 0;
+}
+
+
+static int usbeth_ether_inpstat( cfe_devctx_t * ctx, iocb_inpstat_t * inpstat )
+{
+ if( !Dev_cnt )
+ return CFE_ERR_NOTREADY;
+
+ inpstat->inp_status = usbeth_data_rx( (usbeth_softc_t *) ctx->dev_softc );
+
+ return 0;
+}
+
+
+static int usbeth_ether_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
+{
+ if( !Dev_cnt )
+ return CFE_ERR_NOTREADY;
+
+ // Block until hw notifies you data is sent.
+ usbeth_send_eth_frame( (usbeth_softc_t *) ctx->dev_softc, buffer->buf_ptr,
+ buffer->buf_length );
+
+ return 0;
+}
+
+
+static int usbeth_ether_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
+{
+ int retval = 0;
+
+ if( !Dev_cnt )
+ return CFE_ERR_NOTREADY;
+
+ switch( (int)buffer->buf_ioctlcmd ) {
+ case IOCTL_ETHER_GETHWADDR:
+ USBETH_TRACE( "IOCTL_ETHER_GETHWADDR called.\n" );
+ usbeth_get_dev_addr( (usbeth_softc_t *) ctx->dev_softc,
+ buffer->buf_ptr );
+ break;
+ case IOCTL_ETHER_SETHWADDR:
+ xprintf( "IOCTL_ETHER_SETHWADDR not implemented.\n" );
+ break;
+#if 0
+ case IOCTL_ETHER_GETSPEED:
+ xprintf( "GETSPEED not implemented.\n" );
+ retval = -1;
+ break;
+ case IOCTL_ETHER_SETSPEED:
+ xprintf( "SETSPEED not implemented.\n" );
+ retval = -1;
+ break;
+ case IOCTL_ETHER_GETLINK:
+ xprintf( "GETLINK not implemented.\n" );
+ retval = -1;
+ break;
+ case IOCTL_ETHER_GETLOOPBACK:
+ xprintf( "GETLOOPBACK not implemented.\n" );
+ retval = -1;
+ break;
+ case IOCTL_ETHER_SETLOOPBACK:
+ xprintf( "SETLOOPBACK not implemented.\n" );
+ retval = -1;
+ break;
+#endif
+ default:
+ xprintf( "Invalid IOCTL to usbeth_ether_ioctl.\n" );
+ retval = -1;
+ }
+
+ return retval;
+}
+
+
+static int usbeth_ether_close(cfe_devctx_t *ctx)
+{
+ if( !Dev_cnt )
+ return CFE_ERR_NOTREADY;
+
+ USBETH_TRACE( "%s called.\n", __FUNCTION__ );
+ usbeth_close_device( (usbeth_softc_t *) ctx->dev_softc );
+
+ return 0;
+}
+
+
+// CFE ethernet device interface structures
+const static cfe_devdisp_t usbeth_ether_dispatch =
+{
+ usbeth_ether_open,
+ usbeth_ether_read,
+ usbeth_ether_inpstat,
+ usbeth_ether_write,
+ usbeth_ether_ioctl,
+ usbeth_ether_close,
+ NULL,
+ NULL
+};
+
+const cfe_driver_t usbethdrv =
+{
+ "USB-Ethernet Device",
+ "eth",
+ CFE_DEV_NETWORK,
+ &usbeth_ether_dispatch,
+ NULL, //probe...not needed
+};
+
diff --git a/cfe/cfe/usb/usbeth.h b/cfe/cfe/usb/usbeth.h
new file mode 100644
index 0000000..54f32ae
--- /dev/null
+++ b/cfe/cfe/usb/usbeth.h
@@ -0,0 +1,112 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * USB Ethernet File: usbeth.h
+ *
+ * Driver for USB Ethernet devices.
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+/* *********************************************************************
+ * USB-Ethernet adapter driver includes
+ ********************************************************************* */
+
+#ifndef __usbeth_h__
+#define __usbeth_h__
+
+/* **************************************
+ * CATC Netmate adapter
+ ************************************** */
+
+#define CATC_MCAST_TBL_ADDR 0xFA80 //in Netmate's SRAM
+#define CATC_GET_MAC_ADDR 0xF2
+#define CATC_SET_REG 0xFA
+#define CATC_GET_REG 0xFB
+#define CATC_SET_MEM 0xFC
+
+#define CATC_TX_BUF_CNT_REG 0x20
+#define CATC_RX_BUF_CNT_REG 0x21
+#define CATC_ADV_OP_MODES_REG 0x22
+#define CATC_RX_FRAME_CNT_REG 0x24
+
+#define CATC_ETH_CTRL_REG 0x60
+#define CATC_ENET_STATUS_REG 0x61
+#define CATC_ETH_ADDR_0_REG 0x67 // Byte #0 (leftmost)
+#define CATC_LED_CTRL_REG 0x81
+
+
+/* **************************************
+ * Admtek (PEGASUS II) adapter
+ ************************************** */
+
+#define PEG_SET_REG 0xF1
+#define PEG_GET_REG 0xF0
+
+#define PEG_MCAST_TBL_REG 0x08
+#define PEG_MAC_ADDR_0_REG 0x10
+#define PEG_EEPROM_OFS_REG 0x20
+#define PEG_EEPROM_DATA_REG 0x21
+#define PEG_EEPROM_CTL_REG 0x23
+#define PEG_PHY_ADDR_REG 0x25
+#define PEG_PHY_DATA_REG 0x26 //& 27 for 2 bytes
+#define PEG_PHY_CTRL_REG 0x28
+#define PEG_ETH_CTL0_REG 0x00
+#define PEG_ETH_CTL1_REG 0x01
+#define PEG_ETH_CTL2_REG 0x02
+#define PEG_GPIO0_REG 0x7e
+#define PEG_GPIO1_REG 0x7f
+#define PEG_INT_PHY_REG 0x7b
+
+#define PHY_WRITE 0x20
+#define PHY_READ 0x40
+
+
+/* **************************************
+ * Realtek adapter
+ ************************************** */
+
+#define RTEK_REG_ACCESS 0x05
+#define RTEK_MAC_REG 0x0120
+#define RTEK_CMD_REG 0x012E
+#define RTEK_RXCFG_REG 0x0130
+#define RTEK_RESET 0x10
+#define RTEK_AUTOLOAD 0x01
+
+
+
+#endif //__usbeth_h_
diff --git a/cfe/cfe/usb/usbhack.c b/cfe/cfe/usb/usbhack.c
new file mode 100644
index 0000000..647f213
--- /dev/null
+++ b/cfe/cfe/usb/usbhack.c
@@ -0,0 +1,528 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * Main Module File: usbhack.c
+ *
+ * A crude test program to let us tinker with a USB controller
+ * installed in an X86 Linux PC. Eventually we'll clean up
+ * this stuff and incorporate it into CFE.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <sys/mman.h>
+#include <sys/fcntl.h>
+#include <signal.h>
+#include <memory.h>
+#include <time.h>
+
+#include "lib_malloc.h"
+#include "lib_queue.h"
+#include "usbchap9.h"
+#include "usbd.h"
+#include "ohci.h"
+
+/* *********************************************************************
+ * Macros
+ ********************************************************************* */
+
+#define OHCI_WRITECSR(softc,x,y) \
+ *((volatile uint32_t *) ((softc)->ohci_regs + ((x)/sizeof(uint32_t)))) = (y)
+#define OHCI_READCSR(softc,x) \
+ *((volatile uint32_t *) ((softc)->ohci_regs + ((x)/sizeof(uint32_t))))
+
+/* *********************************************************************
+ * Externs
+ ********************************************************************* */
+
+extern int usb_noisy;
+extern int ohcidebug;
+
+extern usbdev_t *usbmass_dev;
+extern int usbmass_read_sector(usbdev_t *dev,uint32_t sectornum,uint32_t seccnt,
+ uint8_t *buffer);
+
+
+/* *********************************************************************
+ * Play Area definitions
+ *
+ * We use /dev/mem to map two areas - the "play" area and the
+ * "device" area.
+ *
+ * The "play" area maps to the upper 1MB of physical memory.
+ * You need to calculate this address yourself based on your system
+ * setup. If you have 256MB of memory, in your lilo.conf file put
+ * the following line:
+ *
+ * append="mem=255M"
+ *
+ * where '255' is one less than your system memory size. this
+ * leaves 1MB out of Linux's physical memory map and therefore
+ * leaves it to you to play with. /dev/mem will map this
+ * uncached using the Pentium MTRR registers, but for playing
+ * around this will be fine.
+ *
+ * the second area is the "device area" - this is the address
+ * the PCI USB controller's BARs were mapped to. You can find
+ * this by looking through /proc/pci until you find:
+ *
+ * Bus 0, device 8, function 0:
+ * USB Controller: OPTi Unknown device (rev 16).
+ * Vendor id=1045. Device id=c861.
+ * Medium devsel. Fast back-to-back capable. IRQ 3.
+ * Master Capable. Latency=32.
+ * Non-prefetchable 32 bit memory at 0xd9100000 [0xd9100000].
+ *
+ * The 0xd9100000 will probably be different on your system.
+ *
+ * Of course, to make this work you'll need to rebuild the kernel
+ * without USB support, if you're running a recent kernel.
+ * Fortunately(?), I've been using RH 6.2, no USB support there
+ * in the old 2.2 kernels.
+ *
+ * Finally, you'll need to run this program as root. Even if
+ * you mess with the permissions on /dev/mem, there are additional
+ * checks in the kernel, so you will lose.
+ *
+ * But, the good news is that it works well - I've never crashed
+ * my Linux box, and I can use gdb to debug programs.
+ * You will NOT be able to use GDB to display things in the
+ * play area - I believe GDB doesn't know how to deal with
+ * the uncached nature of the memory there. You can see stuff
+ * in the area by tracing through instructions that read the play
+ * area, and viewing the register contents.
+ ********************************************************************* */
+
+#define PLAY_AREA_ADDR (255*1024*1024) /* EDIT ME */
+#define PLAY_AREA_SIZE (1024*1024)
+int play_fd = -1;
+uint8_t *play_area = MAP_FAILED;
+
+#define DEVICE_AREA_ADDR 0xd9100000 /* EDIT ME */
+#define DEVICE_AREA_SIZE 4096
+int dev_fd = -1;
+uint8_t *device_area = MAP_FAILED;
+
+/* *********************************************************************
+ * Globals
+ ********************************************************************* */
+
+
+usbbus_t *bus = NULL;
+ohci_softc_t *ohci = NULL;
+int running = 1;
+
+/* *********************************************************************
+ * vtop(v)
+ *
+ * Given a virtual address in the play area, return its physical
+ * address.
+ *
+ * Input parameters:
+ * v - virtual address
+ *
+ * Return value:
+ * physical address
+ ********************************************************************* */
+
+
+uint32_t vtop(void *v)
+{
+ uint32_t p = (uint32_t) v;
+
+ if (v == 0) return 0;
+
+ p -= (uint32_t) play_area;
+ p += PLAY_AREA_ADDR;
+
+ return p;
+}
+
+/* *********************************************************************
+ * ptov(v)
+ *
+ * Given a phyiscal address in the play area, return the virtual
+ * address.
+ *
+ * Input parameters:
+ * p - physical address
+ *
+ *
+ * Return value:
+ * virtual address (void pointer)
+ ********************************************************************* */
+
+void *ptov(uint32_t p)
+{
+ if (p == 0) return 0;
+
+ p -= PLAY_AREA_ADDR;
+ p += (uint32_t) play_area;
+
+ return (void *) p;
+}
+
+/* *********************************************************************
+ * mydelay(x)
+ *
+ * delay for 'x' milliseconds.
+ *
+ * Input parameters:
+ * x - milliseconds
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void mydelay(int x)
+{
+ struct timespec ts;
+
+ ts.tv_sec = 0;
+ ts.tv_nsec = x * 1000000; /* milliseconds */
+ nanosleep(&ts,NULL);
+}
+
+/* *********************************************************************
+ * console_log(tmplt,...)
+ *
+ * Display a console log message - this is a CFE function
+ * transplanted here.
+ *
+ * Input parameters:
+ * tmplt - printf string args...
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void console_log(const char *tmplt,...)
+{
+ char buffer[256];
+ va_list marker;
+
+ va_start(marker,tmplt);
+ vsprintf(buffer,tmplt,marker);
+ va_end(marker);
+ printf("%s\n",buffer);
+}
+
+/* *********************************************************************
+ * init_devaccess()
+ *
+ * Open /dev/mem and create the play area
+ *
+ * Input parameters:
+ * nothing
+ *
+ * Return value:
+ * 0 if ok, else error
+ ********************************************************************* */
+
+int init_devaccess(void)
+{
+ int idx;
+
+ play_fd = open("/dev/mem",O_RDWR);
+
+ if (play_fd < 0) {
+ perror("open");
+ return -1;
+ }
+
+ dev_fd = open("/dev/mem",O_RDWR | O_SYNC);
+
+ if (dev_fd < 0) {
+ perror("open");
+ close(play_fd);
+ play_fd = -1;
+ return -1;
+ }
+
+ play_area = mmap(NULL,
+ PLAY_AREA_SIZE,
+ PROT_READ|PROT_WRITE,MAP_SHARED,
+ play_fd,
+ PLAY_AREA_ADDR);
+
+ if (play_area != MAP_FAILED) {
+ printf("Play area mapped ok at address %p to %p\n",play_area,play_area+PLAY_AREA_SIZE-1);
+ for (idx = 0; idx < PLAY_AREA_SIZE; idx++) {
+ play_area[idx] = 0x55;
+ if (play_area[idx] != 0x55) printf("Offset %x doesn't work\n",idx);
+ play_area[idx] = 0xaa;
+ if (play_area[idx] != 0xaa) printf("Offset %x doesn't work\n",idx);
+ play_area[idx] = 0x0;
+ if (play_area[idx] != 0x0) printf("Offset %x doesn't work\n",idx);
+ }
+ }
+ else {
+ perror("mmap");
+ close(play_fd);
+ close(dev_fd);
+ play_fd = -1;
+ dev_fd = -1;
+ return -1;
+ }
+
+ device_area = mmap(NULL,
+ DEVICE_AREA_SIZE,
+ PROT_READ|PROT_WRITE,MAP_SHARED,
+ dev_fd,
+ DEVICE_AREA_ADDR);
+
+ if (device_area != MAP_FAILED) {
+ printf("Device area mapped ok at address %p\n",device_area);
+ }
+ else {
+ perror("mmap");
+ munmap(play_area,PLAY_AREA_SIZE);
+ play_area = MAP_FAILED;
+ close(play_fd);
+ close(dev_fd);
+ play_fd = -1;
+ dev_fd = -1;
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/* *********************************************************************
+ * uninit_devaccess()
+ *
+ * Turn off access to the /dev/mem area. this will also
+ * set the OHCI controller's state to reset if we were playing
+ * with it.
+ *
+ * Input parameters:
+ * nothing
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void uninit_devaccess(void)
+{
+ if (ohci->ohci_regs) {
+ OHCI_WRITECSR(ohci,R_OHCI_CONTROL,V_OHCI_CONTROL_HCFS(K_OHCI_HCFS_RESET));
+ }
+
+ if (play_area != MAP_FAILED) munmap(play_area,PLAY_AREA_SIZE);
+ if (device_area != MAP_FAILED) munmap(device_area,DEVICE_AREA_SIZE);
+
+ if (play_fd > 0) close(play_fd);
+ if (dev_fd > 0) close(dev_fd);
+
+ device_area = MAP_FAILED;
+ play_area = MAP_FAILED;
+
+ dev_fd = -1;
+ play_fd = -1;
+}
+
+/* *********************************************************************
+ * sighandler()
+ *
+ * ^C handler - switch off OHCI controller
+ *
+ * Input parameters:
+ * sig - signal
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void sighandler(int sig)
+{
+ signal(SIGINT,SIG_DFL);
+ printf("Interrupted, controller reset\n");
+ if (ohci->ohci_regs) {
+ OHCI_WRITECSR(ohci,R_OHCI_CONTROL,V_OHCI_CONTROL_HCFS(K_OHCI_HCFS_RESET));
+ }
+ running = 0;
+}
+
+
+extern usb_hcdrv_t ohci_driver;
+
+/* *********************************************************************
+ * xprintf(str)
+ *
+ * Called by lib_malloc, we need to supply it.
+ *
+ * Input parameters:
+ * str - string
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+
+int xprintf(char *str)
+{
+ printf("%s",str);
+ return 0;
+}
+
+/* *********************************************************************
+ * main(argc,argv)
+ *
+ * Main test program
+ *
+ * Input parameters:
+ * argc,argv - guess.
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+
+int main(int argc,char *argv[])
+{
+ int res;
+ memstats_t stats;
+ uint8_t *buffer;
+
+ /*
+ * Parse command line args
+ */
+
+ for (res = 1; res < argc; res++) {
+ if (strcmp(argv[res],"-o") == 0) ohcidebug++;
+ if (strcmp(argv[res],"-u") == 0) usb_noisy++;
+ }
+
+ /*
+ * Open the play area.
+ */
+
+ if (init_devaccess() < 0) {
+ printf("Could not map USB controller\n");
+ }
+
+ /*
+ * Establish signal and exit handlers
+ */
+
+ signal(SIGINT,sighandler);
+ atexit(uninit_devaccess);
+
+ /*
+ * Initialize a buffer pool to point at the play area.
+ * the 'malloc' calls inside our driver will therefore
+ * allocate memory suitable for DMA, just like on real
+ * hardware.
+ */
+
+ KMEMINIT(play_area,PLAY_AREA_SIZE);
+
+ buffer = KMALLOC(512,32);
+
+ printf("-------------------------------------------\n\n");
+
+ /*
+ * Create the OHCI driver instance.
+ */
+
+
+ bus = UBCREATE(&ohci_driver,(void *) device_area);
+
+ /*
+ * Hack: retrieve copy of softc for our exception handler
+ */
+
+ ohci = (ohci_softc_t *) bus->ub_hwsoftc;
+
+ /*
+ * Start the controller.
+ */
+
+ res = UBSTART(bus);
+
+ if (res != 0) {
+ printf("Could not init hardware\n");
+ UBSTOP(bus);
+ exit(1);
+ }
+
+ /*
+ * Init the root hub
+ */
+
+ usb_initroot(bus);
+
+ /*
+ * Main loop - just call interrupt routine to poll
+ */
+
+ while (usbmass_dev== NULL) {
+ usb_poll(bus);
+ usb_daemon(bus);
+ }
+
+ for (res = 0; res < 1000; res++) {
+ usbmass_read_sector(usbmass_dev,0,1,buffer);
+ }
+
+ printf("----- finished reading all sectors ----\n");
+
+ while (running) {
+ usb_poll(bus);
+ usb_daemon(bus);
+ }
+
+ /*
+ * Clean up - get heap statistics to see if we
+ * screwed up.
+ */
+
+ res = KMEMSTATS(&stats);
+ if (res < 0) printf("Warning: heap is not consistent\n");
+ else printf("Heap is ok\n");
+
+ exit(0);
+
+}
diff --git a/cfe/cfe/usb/usbhack.h b/cfe/cfe/usb/usbhack.h
new file mode 100644
index 0000000..9f95840
--- /dev/null
+++ b/cfe/cfe/usb/usbhack.h
@@ -0,0 +1,66 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * usb test harness definitions File: usbhack.h
+ *
+ * Anything special required by the test harness is defined
+ * here.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+/* *********************************************************************
+ * Constants
+ ********************************************************************* */
+
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/* *********************************************************************
+ * Prototypes
+ ********************************************************************* */
+
+void console_log(const char *tmplt,...);
+
diff --git a/cfe/cfe/usb/usbhack.mk b/cfe/cfe/usb/usbhack.mk
new file mode 100644
index 0000000..361973e
--- /dev/null
+++ b/cfe/cfe/usb/usbhack.mk
@@ -0,0 +1,23 @@
+
+OBJS = usbhack.o lib_malloc.o lib_queue.o ohci.o usbd.o \
+ usbdevs.o usbhub.o usbdebug.o usbhid.o usbmass.o usbserial.o
+
+CFLAGS = -I../include -g -Wall
+VPATH = ../lib
+
+%.o : %.c
+ gcc $(CFLAGS) -c -o $@ $<
+
+all : usbhack
+ echo done
+
+usbhack : $(OBJS)
+ gcc -o usbhack $(OBJS)
+
+lib_malloc.o : lib_malloc.c
+
+usbhack.o : usbhack.c
+
+
+clean :
+ rm -f *.o usbhack
diff --git a/cfe/cfe/usb/usbhid.c b/cfe/cfe/usb/usbhid.c
new file mode 100644
index 0000000..df84f4e
--- /dev/null
+++ b/cfe/cfe/usb/usbhid.c
@@ -0,0 +1,664 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * USB Human Interface Driver File: usbhid.c
+ *
+ * This module deals with keyboards, mice, etc. It's very simple,
+ * and only the "boot protocol" is supported.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#ifndef _CFE_
+#include <stdio.h>
+#include <time.h>
+#include <memory.h>
+#include <stdint.h>
+#include "usbhack.h"
+#else
+#include "lib_types.h"
+#include "lib_string.h"
+#include "lib_printf.h"
+#include "cfe_console.h"
+#endif
+
+#include "lib_malloc.h"
+#include "lib_queue.h"
+#include "usbchap9.h"
+#include "usbd.h"
+
+/* *********************************************************************
+ * Constants
+ ********************************************************************* */
+
+#define HID_BOOT_PROTOCOL 0
+#define HID_REPORT_PROTOCOL 1
+
+#define HID_DEVTYPE_UNKNOWN 0
+#define HID_DEVTYPE_KBD 1
+#define HID_DEVTYPE_MOUSE 2
+#define HID_DEVTYPE_MAX 2
+
+#define UBR_KBD_MODS 0
+#define UBR_KBD_RSVD 1
+#define UBR_KBD_KEYS 2
+#define UBR_KBD_NUMKEYS 6
+#define UBR_KBD_MAX 8
+
+#define KBD_MOD_LCTRL 0x01
+#define KBD_MOD_LSHIFT 0x02
+#define KBD_MOD_LALT 0x04
+#define KBD_MOD_LWIN 0x08
+
+#define KBD_MOD_RCTRL 0x10
+#define KBD_MOD_RSHIFT 0x20
+#define KBD_MOD_RALT 0x40
+#define KBD_MOD_RWIN 0x80
+
+/* *********************************************************************
+ * Macros
+ ********************************************************************* */
+
+#define usbhid_set_protocol(dev,protocol,ifc) \
+ usb_simple_request(dev,0x21,0x0B,0,ifc)
+
+
+/* *********************************************************************
+ * Forward Definitions
+ ********************************************************************* */
+
+static int usbhid_attach(usbdev_t *dev,usb_driver_t *drv);
+static int usbhid_detach(usbdev_t *dev);
+
+/* *********************************************************************
+ * Structures
+ ********************************************************************* */
+
+typedef struct usbhid_softc_s {
+ int uhid_ipipe;
+ int uhid_ipipemps;
+ int uhid_devtype;
+ uint8_t uhid_imsg[UBR_KBD_MAX];
+ uint8_t uhid_lastmsg[UBR_KBD_MAX];
+ uint32_t uhid_shiftflags;
+} usbhid_softc_t;
+
+usb_driver_t usbhid_driver = {
+ "Human-Interface Device",
+ usbhid_attach,
+ usbhid_detach
+};
+
+static char *usbhid_devtypes[3] = {
+ "Unknown",
+ "Keyboard",
+ "Mouse"};
+
+#ifdef CFG_VGACONSOLE
+extern int pcconsole_enqueue(uint8_t ch);
+#endif
+
+
+/* *********************************************************************
+ * Constants for keyboard table
+ ********************************************************************* */
+
+#define FLG_NUM 0x0001 /* Toggles: same as bits for LEDs */
+#define FLG_CAPS 0x0002
+#define FLG_SCROLL 0x0004
+#define FLG_SHIFT 0x0008 /* Shifts */
+#define FLG_CTRL 0x0100
+#define FLG_ALT 0x0200
+#define FLG_FKEY 0x0400 /* function keys */
+#define FLG_NKPD 0x0800 /* numeric keypad */
+#define FLG_ASCII 0x1000 /* regular ASCII character */
+#define FLG_NONE 0x2000
+
+
+/* *********************************************************************
+ * Structures for keyboard table
+ ********************************************************************* */
+
+#define KC_RESPLEN 4
+typedef struct keycode_s {
+ int kc_type;
+ char kc_normal[KC_RESPLEN];
+ char kc_shifted[KC_RESPLEN];
+ char kc_ctrl[KC_RESPLEN];
+} keycode_t;
+
+
+/* *********************************************************************
+ * Scan code conversion table
+ ********************************************************************* */
+
+static keycode_t usbhid_scantable[] = {
+ { FLG_NONE, "", "", "" }, /* 0 */
+ { FLG_NONE, "", "", "" }, /* 1 */
+ { FLG_NONE, "", "", "" }, /* 2 */
+ { FLG_NONE, "", "", "" }, /* 3 */
+ { FLG_ASCII, "a", "A", "\001" }, /* 4 a */
+ { FLG_ASCII, "b", "B", "\002" }, /* 5 b */
+ { FLG_ASCII, "c", "C", "\003" }, /* 6 c */
+ { FLG_ASCII, "d", "D", "\004" }, /* 7 d */
+ { FLG_ASCII, "e", "E", "\005" }, /* 8 e */
+ { FLG_ASCII, "f", "F", "\006" }, /* 9 f */
+ { FLG_ASCII, "g", "G", "\007" }, /* 10 g */
+ { FLG_ASCII, "h", "H", "\010" }, /* 11 h */
+ { FLG_ASCII, "i", "I", "\011" }, /* 12 i */
+ { FLG_ASCII, "j", "J", "\n" }, /* 13 j */
+ { FLG_ASCII, "k", "K", "\013" }, /* 14 k */
+ { FLG_ASCII, "l", "L", "\014" }, /* 15 l */
+ { FLG_ASCII, "m", "M", "\r" }, /* 16 m */
+ { FLG_ASCII, "n", "N", "\016" }, /* 17 n */
+ { FLG_ASCII, "o", "O", "\017" }, /* 18 o */
+ { FLG_ASCII, "p", "P", "\020" }, /* 19 p */
+ { FLG_ASCII, "q", "Q", "\021" }, /* 20 q */
+ { FLG_ASCII, "r", "R", "\022" }, /* 21 r */
+ { FLG_ASCII, "s", "S", "\023" }, /* 22 s */
+ { FLG_ASCII, "t", "T", "\024" }, /* 23 t */
+ { FLG_ASCII, "u", "U", "\025" }, /* 24 u */
+ { FLG_ASCII, "v", "V", "\026" }, /* 25 v */
+ { FLG_ASCII, "w", "W", "\027" }, /* 26 w */
+ { FLG_ASCII, "x", "X", "\030" }, /* 27 x */
+ { FLG_ASCII, "y", "Y", "\031" }, /* 28 y */
+ { FLG_ASCII, "z", "Z", "\032" }, /* 29 z */
+
+ { FLG_ASCII, "1", "!", "!" }, /* 30 1 */
+ { FLG_ASCII, "2", "@", "\000" }, /* 31 2 */
+ { FLG_ASCII, "3", "#", "#" }, /* 32 3 */
+ { FLG_ASCII, "4", "$", "$" }, /* 33 4 */
+ { FLG_ASCII, "5", "%", "%" }, /* 34 5 */
+ { FLG_ASCII, "6", "^", "\036" }, /* 35 6 */
+ { FLG_ASCII, "7", "&", "&" }, /* 36 7 */
+ { FLG_ASCII, "8", "*", "\010" }, /* 37 8 */
+ { FLG_ASCII, "9", "(", "(" }, /* 38 9 */
+ { FLG_ASCII, "0", ")", ")" }, /* 39 0 */
+
+ { FLG_ASCII, "\r", "\r", "\n" }, /* 40 ENT */
+ { FLG_ASCII, "\033", "\033", "\033" }, /* 41 ESC */
+ { FLG_ASCII, "\177", "\177", "\010" }, /* 42 <- */
+ { FLG_ASCII, "\t", "\177\t", "\t" }, /* 43 ->| */
+ { FLG_ASCII, " ", " ", "\000" }, /* 44 SPC */
+
+ { FLG_ASCII, "-", "_", "\037" }, /* 45 - */
+ { FLG_ASCII, "=", "+", "+" }, /* 46 = */
+ { FLG_ASCII, "[", "{", "\033" }, /* 47 [ */
+ { FLG_ASCII, "]", "}", "\035" }, /* 48 ] */
+ { FLG_ASCII, "\\", "|", "\034" }, /* 49 \ */
+
+ { FLG_NONE, "", "", "" }, /* 50 pound */
+
+ { FLG_ASCII, ";", ":", ";" }, /* 51 ; */
+ { FLG_ASCII, "'", "\"", "'" }, /* 52 ' */
+ { FLG_ASCII, "`", "~", "`" }, /* 53 ` */
+ { FLG_ASCII, ",", "<", "<" }, /* 54 , */
+ { FLG_ASCII, ".", ">", ">" }, /* 55 . */
+ { FLG_ASCII, "/", "?", "\037" }, /* 56 / */
+ { FLG_CAPS, "", "", "" }, /* 57 CAPS */
+
+ { FLG_FKEY, "\033[M", "\033[Y", "\033[k" }, /* 58 f1 */
+ { FLG_FKEY, "\033[N", "\033[Z", "\033[l" }, /* 59 f2 */
+ { FLG_FKEY, "\033[O", "\033[a", "\033[m" }, /* 60 f3 */
+ { FLG_FKEY, "\033[P", "\033[b", "\033[n" }, /* 61 f4 */
+ { FLG_FKEY, "\033[Q", "\033[c", "\033[o" }, /* 62 f5 */
+ { FLG_FKEY, "\033[R", "\033[d", "\033[p" }, /* 63 f6 */
+ { FLG_FKEY, "\033[S", "\033[e", "\033[q" }, /* 64 f7 */
+ { FLG_FKEY, "\033[T", "\033[f", "\033[r" }, /* 65 f8 */
+ { FLG_FKEY, "\033[U", "\033[g", "\033[s" }, /* 66 f9 */
+ { FLG_FKEY, "\033[V", "\033[h", "\033[t" }, /* 67 f10 */
+ { FLG_FKEY, "\033[W", "\033[i", "\033[u" }, /* 68 f11 */
+ { FLG_FKEY, "\033[X", "\033[j", "\033[v" }, /* 69 f12 */
+
+ { FLG_NONE, "", "", "" }, /* 70 prtsc */
+ { FLG_SCROLL, "", "", "" }, /* 71 SCRLK */
+ { FLG_NONE, "", "", "" }, /* 72 pause */
+ { FLG_NONE, "", "", "" }, /* 73 KPins */
+ { FLG_NONE, "", "", "" }, /* 74 KPhome */
+ { FLG_NONE, "", "", "" }, /* 75 KPpgup */
+ { FLG_NONE, "", "", "" }, /* 76 KPdel */
+ { FLG_NONE, "", "", "" }, /* 77 KPend */
+ { FLG_NONE, "", "", "" }, /* 78 KPpgdn */
+
+ { FLG_FKEY, "\033[C", "", "" }, /* 79 KPright */
+ { FLG_FKEY, "\033[D", "", "" }, /* 80 KPleft */
+ { FLG_FKEY, "\033[B", "", "" }, /* 81 KPdown */
+ { FLG_FKEY, "\033[A", "", "" }, /* 82 KPup */
+
+ { FLG_NUM, "", "", "" }, /* 83 NUMLK */
+ { FLG_NKPD, "/", "/", "/" }, /* 84 KP/ */
+ { FLG_NKPD, "*", "*", "*" }, /* 85 KP* */
+ { FLG_NKPD, "-", "-", "-" }, /* 86 KP- */
+ { FLG_NKPD, "+", "+", "+" }, /* 87 KP+ */
+ { FLG_NKPD, "\r", "\r", "\n" }, /* 88 KPent */
+
+ { FLG_NKPD, "1", "\033[F", "1" }, /* 89 KP1 */
+ { FLG_NKPD, "2", "\033[B", "2" }, /* 90 KP2 */
+ { FLG_NKPD, "3", "\033[G", "3" }, /* 91 KP3 */
+ { FLG_NKPD, "4", "\033[D", "4" }, /* 92 KP4 */
+ { FLG_NKPD, "5", "\033[E", "5" }, /* 93 KP5 */
+ { FLG_NKPD, "6", "\033[C", "6" }, /* 94 KP6 */
+ { FLG_NKPD, "7", "\033[H", "7" }, /* 95 KP7 */
+ { FLG_NKPD, "8", "\033[A", "8" }, /* 96 KP8 */
+ { FLG_NKPD, "9", "\033[I", "9" }, /* 97 KP9 */
+ { FLG_NKPD, "0", "\033[L", "0" }, /* 98 KP0 */
+
+ { FLG_NKPD, ".", "\177", "." }, /* 99 KP. */
+
+ { FLG_NONE, "", "", "" }, /* 100 non\ */
+
+};
+
+#define usbhid_scantablesize (sizeof(usbhid_scantable)/sizeof(keycode_t))
+
+
+/* *********************************************************************
+ * usbhid_kbd_mod1(uhid)
+ *
+ * Process modifier key changes for the current USB event,
+ * which was stored in uhid_imsg. Basically all this does
+ * is update uhid_shiftflags, converting the bits into the ones
+ * we use in our keyboard table.
+ *
+ * Input parameters:
+ * uhid - the hid softc.
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void usbhid_kbd_mod1(usbhid_softc_t *uhid)
+{
+ uint8_t changed;
+ uint8_t mod;
+
+ /*
+ * See if anything changed.
+ */
+
+ changed = (uhid->uhid_imsg[UBR_KBD_MODS] ^ uhid->uhid_lastmsg[UBR_KBD_MODS]);
+ if (changed == 0) return;
+
+ /*
+ * Something changed. Reflect changes in our local copy of the
+ * shift state.
+ */
+
+ mod = uhid->uhid_imsg[UBR_KBD_MODS];
+
+ uhid->uhid_shiftflags &= ~(FLG_SHIFT|FLG_ALT|FLG_CTRL);
+
+ if (mod & (KBD_MOD_LCTRL|KBD_MOD_RCTRL)) uhid->uhid_shiftflags |= FLG_CTRL;
+ if (mod & (KBD_MOD_LSHIFT|KBD_MOD_RSHIFT)) uhid->uhid_shiftflags |= FLG_SHIFT;
+ if (mod & (KBD_MOD_LALT|KBD_MOD_RALT)) uhid->uhid_shiftflags |= FLG_ALT;
+}
+
+/* *********************************************************************
+ * usbhid_kbd_scan1(uhid,scan,breakflg)
+ *
+ * Handle a single keyboard event. Using the scan code, look up
+ * the key in the table and convert it to one or more characters
+ * for the keyboard event queue.
+ *
+ * Input parameters:
+ * uhid - the hid softc
+ * scan - scan code from keyboard report
+ * breakflg - true if key is being released, false if pressed
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void usbhid_kbd_scan1(usbhid_softc_t *uhid,uint8_t scan,int breakflg)
+{
+ keycode_t *code = 0;
+ char *str;
+
+ /*
+ * Check scan code for reality.
+ */
+
+ if (scan >= usbhid_scantablesize) return;
+ code = &usbhid_scantable[scan];
+
+ /*
+ * If the change is a toggle, handle the toggle. These
+ * keys also deal with the LEDs on the keyboard.
+ */
+
+ if (code->kc_type & (FLG_CAPS|FLG_SCROLL|FLG_NUM)) {
+ if (!breakflg) uhid->uhid_shiftflags ^= code->kc_type;
+// if (ks->ks_setleds) {
+// (*(ks->ks_setleds))(ks,ks->ks_shiftflags & (FLG_CAPS|FLG_SCROLL|FLG_NUM));
+// }
+ }
+
+ /*
+ * Regular keys - just look up in table and
+ * queue the characters to the upper layers.
+ */
+
+ if (code->kc_type & (FLG_ASCII | FLG_FKEY | FLG_NKPD)) {
+ if (uhid->uhid_shiftflags & (FLG_SHIFT|FLG_CAPS)) str = code->kc_shifted;
+ else if (uhid->uhid_shiftflags & FLG_CTRL) str = code->kc_ctrl;
+ else str = code->kc_normal;
+ if (!breakflg) {
+#if CFG_VGACONSOLE
+ while (*str) {
+ pcconsole_enqueue(*str++);
+ }
+#else
+ printf("%s",str);
+#endif
+#ifndef _CFE_
+ fflush(stdout);
+#endif
+ }
+ }
+
+}
+
+
+/* *********************************************************************
+ * usbhid_kbd_scan(uhid)
+ *
+ * Main processing routine for keyboard report messages. Once
+ * we've determined that it is a keyboard mesage, we end up
+ * here. The work involves seeing what new keys have arrived
+ * in the list (presses), and which ones are no longer there
+ * (releases). To do this, we us the current and previous
+ * report structure.
+ *
+ * Input parameters:
+ * uhid - the hid softc
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void usbhid_kbd_scan(usbhid_softc_t *uhid)
+{
+ int n,o;
+
+ /*
+ * Modifier keys (shift, alt, control)
+ */
+
+ if (uhid->uhid_imsg[UBR_KBD_MODS] ^ uhid->uhid_lastmsg[UBR_KBD_MODS]) {
+ usbhid_kbd_mod1(uhid);
+ }
+
+ /*
+ * "Make" codes (keys pressed down)
+ * Look for keys in 'uhid_imsg' that are not in 'uhid_lastmsg'
+ */
+
+ for (n = UBR_KBD_KEYS; n < (UBR_KBD_KEYS + UBR_KBD_NUMKEYS); n++) {
+ if (uhid->uhid_imsg[n] == 0) break; /* no more keys */
+ for (o = UBR_KBD_KEYS; o < (UBR_KBD_KEYS + UBR_KBD_NUMKEYS); o++) {
+ if (uhid->uhid_imsg[n] == uhid->uhid_lastmsg[o]) break;
+ }
+ if (o == (UBR_KBD_KEYS + UBR_KBD_NUMKEYS)) { /* key not found, must be pressed */
+ usbhid_kbd_scan1(uhid,uhid->uhid_imsg[n],0);
+ }
+ }
+
+ /*
+ * "Break" codes (keys released)
+ * Look for keys in 'uhid_lastmsg' that are not in 'uhid_imsg'
+ */
+
+
+ for (n = UBR_KBD_KEYS; n < (UBR_KBD_KEYS + UBR_KBD_NUMKEYS); n++) {
+ if (uhid->uhid_lastmsg[n] == 0) break; /* no more keys */
+ for (o = UBR_KBD_KEYS; o < (UBR_KBD_KEYS + UBR_KBD_NUMKEYS); o++) {
+ if (uhid->uhid_lastmsg[n] == uhid->uhid_imsg[o]) break;
+ }
+ if (o == (UBR_KBD_KEYS + UBR_KBD_NUMKEYS)) { /* key not found, must be released */
+ usbhid_kbd_scan1(uhid,uhid->uhid_lastmsg[n],1);
+ }
+ }
+}
+
+
+/* *********************************************************************
+ * usbhid_ireq_callback(ur)
+ *
+ * This routine is called when our interrupt transfer completes
+ * and there is report data to be processed.
+ *
+ * Input parameters:
+ * ur - usb request
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+
+static int usbhid_ireq_callback(usbreq_t *ur)
+{
+ usbhid_softc_t *uhid = (ur->ur_dev->ud_private);
+
+ /*
+ * If the driver is unloaded, the request will be cancelled.
+ */
+
+ if (ur->ur_status == 0xFF) {
+ usb_free_request(ur);
+ return 0;
+ }
+
+ /*
+ * What we do now depends on the type of device.
+ */
+
+ switch (uhid->uhid_devtype) {
+ case HID_DEVTYPE_KBD:
+ /*
+ * Handle keyboard event
+ */
+ usbhid_kbd_scan(uhid);
+
+ /*
+ * Save old event to compare for next time.
+ */
+ memcpy(uhid->uhid_lastmsg,uhid->uhid_imsg,8);
+ break;
+
+ case HID_DEVTYPE_MOUSE:
+#if 0
+ /*
+ * No need to handle mice, but here's the good stuff.
+ */
+ printf("Mouse: [%s %s %s] X:%d Y:%d Wheel:%d\n",
+ (ur->ur_buffer[0] & 1) ? "left" : "",
+ (ur->ur_buffer[0] & 4) ? "middle" : "",
+ (ur->ur_buffer[0] & 2) ? "right" : "",
+ (int)(signed char)ur->ur_buffer[1],
+ (int)(signed char)ur->ur_buffer[2],
+ (int)(signed char)ur->ur_buffer[3]);
+#endif
+ break;
+ }
+
+ /*
+ * Re-queue request to get next keyboard event.
+ */
+
+ usb_queue_request(ur);
+
+ return 0;
+}
+
+
+/* *********************************************************************
+ * usbhid_queue_intreq(dev,softc)
+ *
+ * Queue an interrupt request for this usb device. The
+ * driver will place this request on the queue that corresponds
+ * to the endpoint, and will call the callback routine when
+ * something happens.
+ *
+ * Input parameters:
+ * dev - usb device
+ * softc - the usb hid softc
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void usbhid_queue_intreq(usbdev_t *dev,usbhid_softc_t *softc)
+{
+ usbreq_t *ur;
+
+ ur = usb_make_request(dev,
+ softc->uhid_ipipe,
+ softc->uhid_imsg,softc->uhid_ipipemps,
+ UR_FLAG_IN);
+
+ ur->ur_callback = usbhid_ireq_callback;
+
+ usb_queue_request(ur);
+}
+
+
+/* *********************************************************************
+ * usbhid_attach(dev,drv)
+ *
+ * This routine is called when the bus scan stuff finds a HID
+ * device. We finish up the initialization by configuring the
+ * device and allocating our softc here.
+ *
+ * Input parameters:
+ * dev - usb device, in the "addressed" state.
+ * drv - the driver table entry that matched
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+
+static int usbhid_attach(usbdev_t *dev,usb_driver_t *drv)
+{
+ usb_config_descr_t *cfgdscr = dev->ud_cfgdescr;
+ usb_endpoint_descr_t *epdscr;
+ usb_interface_descr_t *ifdscr;
+ usbhid_softc_t *softc;
+
+ dev->ud_drv = drv;
+
+ softc = KMALLOC(sizeof(usbhid_softc_t),0);
+ memset(softc,0,sizeof(usbhid_softc_t));
+ dev->ud_private = softc;
+
+ epdscr = usb_find_cfg_descr(dev,USB_ENDPOINT_DESCRIPTOR_TYPE,0);
+ ifdscr = usb_find_cfg_descr(dev,USB_INTERFACE_DESCRIPTOR_TYPE,0);
+
+ if (!epdscr || !ifdscr) {
+ /*
+ * Could not get descriptors, something is very wrong.
+ * Leave device addressed but not configured.
+ */
+ return 0;
+ }
+
+ /*
+ * Choose the standard configuration.
+ */
+
+ usb_set_configuration(dev,cfgdscr->bConfigurationValue);
+
+ /*
+ * Set the protocol to the "boot" protocol, so we don't
+ * have to deal with fancy HID stuff.
+ */
+
+ usbhid_set_protocol(dev,HID_BOOT_PROTOCOL,ifdscr->bInterfaceNumber);
+
+ /*
+ * Open the interrupt pipe.
+ */
+
+ softc->uhid_ipipe = usb_open_pipe(dev,epdscr);
+ softc->uhid_ipipemps = GETUSBFIELD(epdscr,wMaxPacketSize);
+
+ /*
+ * Figure out the device type from the protocol. Keyboards,
+ * mice use this field to distinguish themselves.
+ */
+
+ softc->uhid_devtype = ifdscr->bInterfaceProtocol;
+ if (softc->uhid_devtype > HID_DEVTYPE_MAX) {
+ softc->uhid_devtype = HID_DEVTYPE_UNKNOWN;
+ }
+
+ console_log("USBHID: %s Configured.\n",
+ usbhid_devtypes[softc->uhid_devtype]);
+
+ /*
+ * Queue a transfer on the interrupt endpoint to catch
+ * our first characters.
+ */
+
+ usbhid_queue_intreq(dev,softc);
+
+ return 0;
+}
+
+/* *********************************************************************
+ * usbhid_detach(dev)
+ *
+ * This routine is called when the bus scanner notices that
+ * this device has been removed from the system. We should
+ * do any cleanup that is required. The pending requests
+ * will be cancelled automagically.
+ *
+ * Input parameters:
+ * dev - usb device
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+
+static int usbhid_detach(usbdev_t *dev)
+{
+ return 0;
+}
+
+
+
diff --git a/cfe/cfe/usb/usbhub.c b/cfe/cfe/usb/usbhub.c
new file mode 100644
index 0000000..1e571ed
--- /dev/null
+++ b/cfe/cfe/usb/usbhub.c
@@ -0,0 +1,912 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * USB Hub and device discovery code File: usbhub.c
+ *
+ * This module deals with hubs and device discovery.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#ifndef _CFE_
+#include <stdio.h>
+#include <time.h>
+#include <memory.h>
+#include <stdint.h>
+#include "usbhack.h"
+#else
+#include "lib_types.h"
+#include "lib_string.h"
+#include "lib_printf.h"
+#include "cfe_console.h"
+#endif
+
+#include "lib_malloc.h"
+#include "lib_queue.h"
+#include "usbchap9.h"
+#include "usbd.h"
+
+/* *********************************************************************
+ * Macros for common hub requests
+ ********************************************************************* */
+
+#define usbhub_set_port_feature(dev,port,feature) \
+ usb_simple_request(dev,0x23,USB_HUBREQ_SET_FEATURE,feature,port)
+
+#define usbhub_set_hub_feature(dev,feature) \
+ usb_simple_request(dev,0x20,USB_HUBREQ_SET_FEATURE,feature,0)
+
+#define usbhub_clear_port_feature(dev,port,feature) \
+ usb_simple_request(dev,0x23,USB_HUBREQ_CLEAR_FEATURE,feature,port)
+
+#define usbhub_clear_hub_feature(dev,feature) \
+ usb_simple_request(dev,0x20,USB_HUBREQ_CLEAR_FEATURE,feature,0)
+
+
+/* *********************************************************************
+ * Externs
+ ********************************************************************* */
+
+extern int usb_noisy;
+
+/* *********************************************************************
+ * Forward declarations
+ ********************************************************************* */
+
+static int usbhub_attach(usbdev_t *dev,usb_driver_t *drv);
+static int usbhub_detach(usbdev_t *dev);
+
+/* *********************************************************************
+ * Hub-specific data structures
+ ********************************************************************* */
+
+#define UHUB_MAX_DEVICES 8
+
+#define UHUB_FLG_NEEDSCAN 1
+
+typedef struct usbhub_softc_s {
+ usb_hub_descr_t uhub_descr;
+ usb_hub_status_t uhub_status;
+ int uhub_ipipe;
+ int uhub_ipipemps;
+ int uhub_nports;
+ unsigned int uhub_flags;
+ uint8_t uhub_imsg[8];
+ usbdev_t *uhub_devices[UHUB_MAX_DEVICES];
+} usbhub_softc_t;
+
+usb_driver_t usbhub_driver = {
+ "USB Hub",
+ usbhub_attach,
+ usbhub_detach
+};
+
+
+/* *********************************************************************
+ * usbhub_ireq_callback(ur)
+ *
+ * this routine is called when the transfer we queued to the
+ * interrupt endpoint on the hub completes. It means that
+ * *some* port on the hub needs attention. The data indicates
+ * which port, but for our purposes we don't really care - if
+ * we get this callback, we'll set a flag and re-probe the bus.
+ *
+ * Input parameters:
+ * ur - usbreq that completed
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+
+static int usbhub_ireq_callback(usbreq_t *ur)
+{
+ int idx;
+ usbhub_softc_t *uhub = (ur->ur_dev->ud_private);
+
+ /*
+ * Check to see if the request was cancelled by someone
+ * deleting our endpoint.
+ */
+
+ if (ur->ur_status == 0xFF) {
+ usb_free_request(ur);
+ return 0;
+ }
+
+ /*
+ * Check to see if any of our ports need attention
+ */
+
+ for (idx = 1; idx <= uhub->uhub_nports; idx++) {
+ if (ur->ur_buffer[0] & (1<<idx)) {
+
+ /*
+ * Mark the hub as needing a scan, and mark the bus as well
+ * so the top-level polling will notice.
+ */
+
+ uhub->uhub_flags |= UHUB_FLG_NEEDSCAN;
+ ur->ur_dev->ud_bus->ub_flags |= UB_FLG_NEEDSCAN;
+ }
+ }
+
+
+ /*
+ * Do NOT requeue the request here. We will do this
+ * during exploration.
+ */
+
+ usb_free_request(ur);
+
+ return 0;
+}
+
+
+/* *********************************************************************
+ * usbhub_get_hub_descriptor(dev,dscr,idx,maxlen)
+ *
+ * Obtain the hub descriptor (special for hubs) from the
+ * device.
+ *
+ * Input parameters:
+ * dev - usb device
+ * dscr - place to put hub descriptor
+ * idx - which hub descriptor to get (usually zero)
+ * maxlen - max # of bytes to return
+ *
+ * Return value:
+ * # of bytes returned
+ ********************************************************************* */
+
+static int usbhub_get_hub_descriptor(usbdev_t *dev,usb_hub_descr_t *dscr,int idx,int maxlen)
+{
+ return usb_std_request(dev,0xA0,
+ USB_HUBREQ_GET_DESCRIPTOR,
+ 0,0,
+ (uint8_t *) dscr,
+ maxlen);
+}
+
+
+/* *********************************************************************
+ * usbhub_get_hub_status(dev,status)
+ *
+ * Obtain the hub status (special for hubs) from the
+ * device.
+ *
+ * Input parameters:
+ * dev - usb device
+ * status - where to put hub status structure
+ *
+ * Return value:
+ * # of bytes returned
+ ********************************************************************* */
+
+#if 0
+static int usbhub_get_hub_status(usbdev_t *dev,usb_hub_status_t *status)
+{
+ return usb_std_request(dev,
+ 0xA0,
+ 0x00,
+ 0,
+ 0,
+ (uint8_t *) status,
+ sizeof(usbhub_status_t));
+}
+#endif
+
+
+/* *********************************************************************
+ * usbhub_get_port_status(dev,port,status)
+ *
+ * Obtain the port status for a particular port from
+ * device.
+ *
+ * Input parameters:
+ * dev - usb device
+ * port - 1-based port number
+ * status - where to put port status structure
+ *
+ * Return value:
+ * # of bytes returned
+ ********************************************************************* */
+
+static int usbhub_get_port_status(usbdev_t *dev,int port,usb_port_status_t *status)
+{
+ return usb_std_request(dev,
+ 0xA3,
+ 0,
+ 0,
+ port,
+ (uint8_t *) status,
+ sizeof(usb_port_status_t));
+}
+
+
+/* *********************************************************************
+ * usbhub_queue_intreq(dev,softc)
+ *
+ * Queue the transfer to the interrupt pipe that will catch
+ * the hub's port status changes
+ *
+ * Input parameters:
+ * dev - usb device
+ * softc - hub-specific data
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void usbhub_queue_intreq(usbdev_t *dev,usbhub_softc_t *softc)
+{
+ usbreq_t *ur;
+
+ ur = usb_make_request(dev,
+ softc->uhub_ipipe,
+ softc->uhub_imsg,softc->uhub_ipipemps,
+ UR_FLAG_IN | UR_FLAG_SHORTOK);
+
+ ur->ur_callback = usbhub_ireq_callback;
+
+ usb_queue_request(ur);
+}
+
+
+/* *********************************************************************
+ * usbhub_attach(dev,drv)
+ *
+ * This routine is called when the hub attaches to the system.
+ * We complete initialization for the hub and set things up so
+ * that an explore will happen soon.
+ *
+ * Input parameters:
+ * dev - usb device
+ * drv - driver structure
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+
+static int usbhub_attach(usbdev_t *dev,usb_driver_t *drv)
+{
+ usb_device_status_t devstatus;
+ usb_config_descr_t *cfgdscr;
+ usb_interface_descr_t *ifdscr;
+ usb_endpoint_descr_t *epdscr;
+ usbhub_softc_t *softc;
+
+ /*
+ * Remember the driver dispatch.
+ */
+
+ dev->ud_drv = drv;
+
+ softc = KMALLOC(sizeof(usbhub_softc_t),0);
+ memset(softc,0,sizeof(usbhub_softc_t));
+ dev->ud_private = softc;
+
+ /*
+ * Dig out the data from the configuration descriptor
+ * (we got this from the device before attach time)
+ */
+
+ cfgdscr = dev->ud_cfgdescr;
+ epdscr = usb_find_cfg_descr(dev,USB_ENDPOINT_DESCRIPTOR_TYPE,0);
+ ifdscr = usb_find_cfg_descr(dev,USB_INTERFACE_DESCRIPTOR_TYPE,0);
+
+ /*
+ * Get device status (is this really necessary?)
+ */
+
+ usb_get_device_status(dev,&devstatus);
+
+ /*
+ * Set us to configuration index 0
+ */
+
+ usb_set_configuration(dev,cfgdscr->bConfigurationValue);
+
+ /*
+ * Get the hub descriptor. Get the first 8 bytes first, then get the rest
+ * if there is more.
+ */
+
+ if (usbhub_get_hub_descriptor(dev,&(softc->uhub_descr),0,USB_HUB_DESCR_SIZE) > USB_HUB_DESCR_SIZE) {
+ usbhub_get_hub_descriptor(dev,&(softc->uhub_descr),0,softc->uhub_descr.bDescriptorLength);
+ }
+
+ /*
+ * remember stuff from the hub descriptor
+ */
+
+ softc->uhub_nports = softc->uhub_descr.bNumberOfPorts;
+
+ /*
+ * Open the interrupt pipe
+ */
+
+ softc->uhub_ipipe = usb_open_pipe(dev,epdscr);
+ softc->uhub_ipipemps = GETUSBFIELD(epdscr,wMaxPacketSize);
+
+ /*
+ * Mark the bus and the hub as needing service.
+ */
+
+ softc->uhub_flags |= UHUB_FLG_NEEDSCAN;
+ dev->ud_bus->ub_flags |= UB_FLG_NEEDSCAN;
+
+ /*
+ * Okay, that's it. The top-level USB daemon will notice
+ * that the bus needs service and will invoke the exploration code.
+ * This may in turn require additional explores until
+ * everything settles down.
+ */
+
+ return 0;
+}
+
+
+/* *********************************************************************
+ * usbhub_detach(dev)
+ *
+ * Called when a hub is removed from the system - we remove
+ * all subordinate devicees.
+ *
+ * Input parameters:
+ * dev - device (hub) that was removed
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+
+static int usbhub_detach(usbdev_t *dev)
+{
+ usbhub_softc_t *hub;
+ usbdev_t *deldev;
+ int idx;
+
+ if (!IS_HUB(dev)) return 0; /* should not happen */
+
+ hub = dev->ud_private;
+ for (idx = 0; idx < UHUB_MAX_DEVICES; idx++) {
+ deldev = hub->uhub_devices[idx];
+ if (deldev) {
+ console_log("USB: Removing device attached to bus %d hub %d port %d",
+ dev->ud_bus->ub_num,
+ dev->ud_address,idx+1);
+ if (deldev->ud_drv) {
+ (*(deldev->ud_drv->udrv_detach))(deldev);
+ }
+ else {
+ if (usb_noisy > 0) {
+ console_log("USB: Detached device on bus %d hub %d port %d "
+ "has no methods",
+ dev->ud_bus->ub_num,
+ dev->ud_address,idx+1);
+ }
+ }
+ if (deldev->ud_cfgdescr) KFREE(deldev->ud_cfgdescr);
+ usb_destroy_device(deldev);
+ }
+ }
+
+ KFREE(hub); /* remove softc */
+
+ return 0;
+}
+
+
+
+/* *********************************************************************
+ * usbhub_map_tree1(dev,level,func,arg)
+ *
+ * This routine is used in recursive device tree exploration.
+ * We call 'func' for each device at this tree, and descend
+ * when we run into hubs
+ *
+ * Input parameters:
+ * dev - current device pointer
+ * level - current nesting level
+ * func - function to call
+ * arg - argument to pass to function
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void usbhub_map_tree1(usbdev_t *dev,int level,
+ int (*func)(usbdev_t *dev,void *arg),void *arg)
+{
+ usbhub_softc_t *hub;
+ int idx;
+
+ (*func)(dev,arg);
+
+ if (IS_HUB(dev)) {
+ hub = dev->ud_private;
+ for (idx = 0; idx < UHUB_MAX_DEVICES; idx++) {
+ if (hub->uhub_devices[idx]) {
+ usbhub_map_tree1(hub->uhub_devices[idx],level+1,func,arg);
+ }
+ }
+ }
+}
+
+/* *********************************************************************
+ * usbhub_map_tree(bus,func,arg)
+ *
+ * Call a function for each device in the tree
+ *
+ * Input parameters:
+ * bus - bus to scan
+ * func - function to call
+ * arg - argument to pass to function
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void usbhub_map_tree(usbbus_t *bus,int (*func)(usbdev_t *dev,void *arg),void *arg)
+{
+ usbhub_map_tree1(bus->ub_roothub,0,func,arg);
+}
+
+
+/* *********************************************************************
+ * usbhub_dumpbus1(dev,arg)
+ *
+ * map function to dump devices in the device tree
+ *
+ * Input parameters:
+ * dev - device we're working on
+ * arg - argument from map_tree call
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+
+static int usbhub_dumpbus1(usbdev_t *dev,void *arg)
+{
+ uint32_t *verbose = (uint32_t *) arg;
+
+ if ((*verbose & 0x00FF) && (dev->ud_address != (*verbose & 0x00FF))) return 0;
+
+ if (*verbose & 0x100) {
+ printf("============================================================================\n");
+ }
+
+ printf("Bus %d Device %d Class %d Vendor %04X Product %04X ",
+ dev->ud_bus->ub_num,
+ dev->ud_address,
+ dev->ud_devdescr.bDeviceClass,
+ GETUSBFIELD(&(dev->ud_devdescr),idVendor),
+ GETUSBFIELD(&(dev->ud_devdescr),idProduct));
+
+
+ if (IS_HUB(dev)) {
+ printf("[HUB]\n");
+ }
+ else {
+ printf("[DEVICE]\n");
+ }
+
+ if (*verbose & 0x100) {
+ usb_dbg_dumpdescriptors(dev,(uint8_t *) &(dev->ud_devdescr),dev->ud_devdescr.bLength);
+ usb_dbg_dumpcfgdescr(dev);
+ }
+
+ return 0;
+}
+
+
+/* *********************************************************************
+ * usbhub_dumpbus(bus,verbose)
+ *
+ * Dump information about devices on the USB bus.
+ *
+ * Input parameters:
+ * bus - bus to dump
+ * verbose - nonzero to display more info, like descriptors
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void usbhub_dumpbus(usbbus_t *bus,uint32_t verbose)
+{
+ usbhub_map_tree(bus,usbhub_dumpbus1,&verbose);
+}
+
+
+
+/* *********************************************************************
+ * usbhub_reset_devicee(dev,port,status)
+ *
+ * Reset a device on a hub port. This routine does a
+ * USB_PORT_FEATURE_RESET on the specified port, waits for the
+ * bit to clear, and returns. It is used to get a device into the
+ * DEFAULT state according to the spec.
+ *
+ * Input parameters:
+ * dev - hub device
+ * port - port number(1-based)
+ * status - place to return port_status structure after
+ * reset completes
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void usbhub_reset_device(usbdev_t *dev,int port,usb_port_status_t *portstatus)
+{
+ console_log("USB: Resetting device on bus %d port %d",dev->ud_bus->ub_num,port);
+#ifndef _CFE_
+ fflush(stdout);
+#endif
+
+ usbhub_set_port_feature(dev,port,USB_PORT_FEATURE_RESET);
+
+ usbhub_get_port_status(dev,port,portstatus);
+
+ for (;;) {
+ usbhub_get_port_status(dev,port,portstatus);
+ if ((GETUSBFIELD((portstatus),wPortStatus) & USB_PORT_STATUS_RESET) == 0) break;
+ usb_delay_ms(dev->ud_bus,250);
+ }
+ usb_delay_ms(dev->ud_bus,250);
+
+ usbhub_clear_port_feature(dev,port,USB_PORT_FEATURE_C_PORT_RESET);
+}
+
+
+
+/* *********************************************************************
+ * usbhub_scan_ports(dev,arg)
+ *
+ * Scan the ports on this hub for new or removed devices.
+ *
+ * Input parameters:
+ * dev - hub device
+ * arg - passed from bus scan main routines
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void usbhub_scan_ports(usbdev_t *dev,void *arg)
+{
+ uint16_t current;
+ uint16_t changed;
+ usbhub_softc_t *softc;
+ int idx;
+ int res;
+ int len;
+ uint8_t *buf;
+ usbdev_t *newdev;
+ usb_driver_t *newdrv;
+ int addr;
+ usb_port_status_t portstatus;
+ usb_config_descr_t cfgdescr;
+ unsigned int powerondelay;
+
+ if (!IS_HUB(dev)) return; /* should not happen. */
+
+ /*
+ * We know this is a hub. Get the softc back.
+ */
+
+ softc = (usbhub_softc_t *) dev->ud_private;
+
+ powerondelay = ((unsigned int) softc->uhub_descr.bPowerOnToPowerGood)*2 + 20;
+
+ /*
+ * Turn on the power to the ports whose power is not yet on.
+ */
+
+ for (idx = 0; idx < softc->uhub_nports; idx++) {
+
+ usbhub_get_port_status(dev,idx+1,&portstatus);
+
+ current = GETUSBFIELD((&portstatus),wPortStatus);
+ changed = GETUSBFIELD((&portstatus),wPortChange);
+ if (usb_noisy > 1) {
+ printf("BeforePowerup: port %d status %04X changed %04X\n",idx+1,current,changed);
+ }
+
+ if (!(current & USB_PORT_STATUS_POWER)) {
+ if (usb_noisy > 1) console_log("USB: Powering up bus %d port %d",
+ dev->ud_bus->ub_num,idx+1);
+ usbhub_set_port_feature(dev,idx+1,USB_PORT_FEATURE_POWER);
+ usb_delay_ms(dev->ud_bus,powerondelay);
+ }
+ }
+
+ /*
+ * Begin exploration at this level.
+ */
+
+ for (idx = 0; idx < softc->uhub_nports; idx++) {
+
+ usbhub_get_port_status(dev,idx+1,&portstatus);
+
+ current = GETUSBFIELD((&portstatus),wPortStatus);
+ changed = GETUSBFIELD((&portstatus),wPortChange);
+
+ if (usb_noisy > 0) {
+ printf("USB: Explore: Bus %d Hub %d port %d status %04X changed %04X\n",
+ dev->ud_bus->ub_num,
+ dev->ud_address,idx+1,current,changed);
+ usb_dbg_dumpportstatus(idx+1,&portstatus,1);
+ }
+
+
+// if (changed & USB_PORT_STATUS_RESET) {
+// usbhub_clear_port_feature(dev,idx+1,USB_PORT_FEATURE_C_PORT_RESET);
+// }
+
+ if (changed & USB_PORT_STATUS_ENABLED) {
+ usbhub_clear_port_feature(dev,idx+1,USB_PORT_FEATURE_C_PORT_ENABLE);
+ }
+
+ if (changed & USB_PORT_STATUS_CONNECT) {
+ /*
+ * A device was either connected or disconnected.
+ * Clear the status change first.
+ */
+
+ usbhub_clear_port_feature(dev,idx+1,USB_PORT_FEATURE_C_PORT_CONNECTION);
+
+ if (current & USB_PORT_STATUS_CONNECT) {
+
+ /*
+ * The device has been CONNECTED.
+ */
+
+ console_log("USB: New device connected to bus %d hub %d port %d",
+ dev->ud_bus->ub_num,
+ dev->ud_address,idx+1);
+
+ /*
+ * Reset the device. Reuse our old port status structure
+ * so we get the latest status. Some devices do not report
+ * lowspeed until they are reset.
+ */
+
+ usbhub_reset_device(dev,idx+1,&portstatus);
+ current = GETUSBFIELD((&portstatus),wPortStatus);
+ changed = GETUSBFIELD((&portstatus),wPortChange);
+
+ /*
+ * Create a device for this port.
+ */
+
+ newdev = usb_create_device(dev->ud_bus,(current & USB_PORT_STATUS_LOWSPD) ? 1 : 0);
+
+ /*
+ * Get the device descriptor.
+ */
+
+ res = usb_get_device_descriptor(newdev,&(newdev->ud_devdescr),TRUE);
+
+ if (usb_noisy > 0) usb_dbg_dumpdescriptors(newdev,(uint8_t *) &(newdev->ud_devdescr),8);
+
+ /*
+ * Set up the max packet size for the control endpoint,
+ * then get the rest of the descriptor.
+ */
+
+ usb_set_ep0mps(newdev,newdev->ud_devdescr.bMaxPacketSize0);
+ res = usb_get_device_descriptor(newdev,&(newdev->ud_devdescr),FALSE);
+
+ /*
+ * Obtain a new address and set the address of the
+ * root hub to this address.
+ */
+
+ addr = usb_new_address(newdev->ud_bus);
+ res = usb_set_address(newdev,addr);
+
+ /*
+ * Get the configuration descriptor and all the
+ * associated interface and endpoint descriptors.
+ */
+
+ res = usb_get_config_descriptor(newdev,&cfgdescr,0,
+ sizeof(usb_config_descr_t));
+ if (res != sizeof(usb_config_descr_t)) {
+ printf("[a]usb_get_config_descriptor returns %d\n",res);
+ }
+
+ len = GETUSBFIELD(&cfgdescr,wTotalLength);
+ buf = KMALLOC(len,0);
+
+ res = usb_get_config_descriptor(newdev,(usb_config_descr_t *)buf,0,len);
+ if (res != len) {
+ printf("[b]usb_get_config_descriptor returns %d\n",res);
+ }
+
+ newdev->ud_cfgdescr = (usb_config_descr_t *) buf;
+
+ if (usb_noisy > 0) usb_dbg_dumpdescriptors(newdev,buf,len);
+
+ /*
+ * Point the hub at the devices it owns
+ */
+
+ softc->uhub_devices[idx] = newdev;
+
+ /*
+ * Find the driver for this. It had better be the hub
+ * driver.
+ */
+
+ newdrv = usb_find_driver(newdev);
+
+ /*
+ * Call the attach method.
+ */
+
+ if (newdrv) {
+ dev->ud_drv = newdrv; /* remember driver dispatch in device */
+ (*(newdrv->udrv_attach))(newdev,newdrv);
+ }
+ }
+
+ else {
+
+ /*
+ * The device has been DISCONNECTED.
+ */
+
+ console_log("USB: Device disconnected from bus %d hub %d port %d",
+ dev->ud_bus->ub_num,
+ dev->ud_address,idx+1);
+
+ /*
+ * Recover pointer to device below hub and clear
+ * this pointer.
+ */
+
+ newdev = softc->uhub_devices[idx]; /* Get device pointer */
+ softc->uhub_devices[idx] = NULL; /* remove device from hub */
+
+ /*
+ * Deassign the USB device's address and then
+ * call detach method to free resources. Devices that
+ * do not have drivers will not have any methods.
+ */
+
+ if (newdev) {
+ if (newdev->ud_drv) {
+ (*(newdev->ud_drv->udrv_detach))(newdev);
+ }
+ else {
+ if (usb_noisy > 0) {
+ console_log("USB: Detached device on bus %d hub %d port %d "
+ "has no methods",
+ dev->ud_bus->ub_num,
+ dev->ud_address,idx+1);
+ }
+ }
+
+ if (newdev->ud_cfgdescr) KFREE(newdev->ud_cfgdescr);
+
+ usb_destroy_device(newdev);
+ }
+
+ }
+ }
+
+ }
+
+
+ /*
+ * Queue up a request for the interrupt pipe. This will catch further
+ * changes at this port.
+ */
+
+ usbhub_queue_intreq(dev,softc);
+
+}
+
+/* *********************************************************************
+ * usbhub_scan1(dev,arg)
+ *
+ * Scan one device at this level, or descend if we run into a hub
+ * This is part of the device discovery code.
+ *
+ * Input parameters:
+ * dev - current device, maybe a hub
+ * arg - passed from main scan routine
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+
+
+static int usbhub_scan1(usbdev_t *dev,void *arg)
+{
+ usbhub_softc_t *hub;
+
+ /*
+ * If the device is not a hub, we've reached the leaves of the
+ * tree.
+ */
+
+ if (!IS_HUB(dev)) return 0;
+
+ /*
+ * Otherwise, scan the ports on this hub.
+ */
+
+ hub = dev->ud_private;
+
+ if (hub->uhub_flags & UHUB_FLG_NEEDSCAN) {
+ hub->uhub_flags &= ~UHUB_FLG_NEEDSCAN;
+ usbhub_scan_ports(dev,arg);
+ }
+
+ return 0;
+}
+
+/* *********************************************************************
+ * usb_scan(bus)
+ *
+ * Scan the bus looking for new or removed devices
+ *
+ * Input parameters:
+ * bus - bus to scan
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void usb_scan(usbbus_t *bus)
+{
+ /*
+ * Call our tree walker with the scan function.
+ */
+
+ usbhub_map_tree(bus,usbhub_scan1,NULL);
+}
+
+
+
+
diff --git a/cfe/cfe/usb/usbmain.c b/cfe/cfe/usb/usbmain.c
new file mode 100644
index 0000000..c39a7f6
--- /dev/null
+++ b/cfe/cfe/usb/usbmain.c
@@ -0,0 +1,367 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * Main Module File: usbmain.c
+ *
+ * Main module that invokes the top of the USB stack from CFE.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#include "lib_types.h"
+#include "lib_malloc.h"
+#include "lib_string.h"
+#include "lib_printf.h"
+#include "lib_queue.h"
+#include "lib_physio.h"
+
+#include "cfe_timer.h"
+#include "ui_command.h"
+
+#if CFG_PCI
+#include "pcireg.h"
+#include "pcivar.h"
+#endif
+
+#include "usbchap9.h"
+#include "usbd.h"
+
+#include "bsp_config.h"
+
+
+/* *********************************************************************
+ * Externs
+ ********************************************************************* */
+
+extern usb_hcdrv_t ohci_driver; /* OHCI Driver dispatch */
+
+extern int ohcidebug; /* OHCI debug control */
+extern int usb_noisy; /* USBD debug control */
+
+int usb_init(void); /* forward */
+int ui_init_usbcmds(void); /* forward */
+
+/* *********************************************************************
+ * Globals
+ ********************************************************************* */
+
+/*
+ * We keep track of the pointers to USB buses in globals.
+ * One entry in this array per USB bus (the Opti controller
+ * on the SWARM has two functions, so it's two buses)
+ */
+
+#define USB_MAX_BUS 4
+int usb_buscnt = 0;
+usbbus_t *usb_buses[USB_MAX_BUS];
+
+
+/* *********************************************************************
+ * usb_cfe_timer(arg)
+ *
+ * This routine is called periodically by CFE's timer routines
+ * to give the USB subsystem some time. Basically we scan
+ * for work to do to manage configuration updates, and handle
+ * interrupts from the USB controllers.
+ *
+ * Input parameters:
+ * arg - value we passed when the timer was initialized
+ * (not used)
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void usb_cfe_timer(void *arg)
+{
+ int idx;
+ static int in_poll = 0;
+
+ /*
+ * We sometimes call the timer routines in here, which calls
+ * the polling loop. This code is not reentrant, so
+ * prevent us from running the interrupt routine or
+ * bus daemon while we are already in there.
+ */
+
+ if (in_poll) return;
+
+ /*
+ * Do not allow nested "interrupts."
+ */
+
+ in_poll = 1;
+
+ for (idx = 0; idx < usb_buscnt; idx++) {
+ if (usb_buses[idx]) {
+ usb_poll(usb_buses[idx]);
+ usb_daemon(usb_buses[idx]);
+ }
+ }
+
+ /*
+ * Okay to call polling again.
+ */
+
+ in_poll = 0;
+}
+
+
+/* *********************************************************************
+ * usb_init_one_ohci(addr)
+ *
+ * Initialize one USB controller.
+ *
+ * Input parameters:
+ * addr - physical address of OHCI registers
+ *
+ * Return value:
+ * 0 if ok
+ * else error
+ ********************************************************************* */
+static int usb_init_one_ohci(uint32_t addr)
+{
+ usbbus_t *bus;
+ int res;
+
+ bus = UBCREATE(&ohci_driver, addr);
+
+ if (bus == NULL) {
+ printf("USB: Could not create OHCI driver structure for controller at 0x%08X\n",addr);
+ return -1;
+ }
+
+ bus->ub_num = usb_buscnt;
+
+ res = UBSTART(bus);
+
+ if (res != 0) {
+ printf("USB: Could not init OHCI controller at 0x%08X\n",addr);
+ UBSTOP(bus);
+ return -1;
+ }
+ else {
+ usb_buses[usb_buscnt++] = bus;
+ usb_initroot(bus);
+ }
+
+ return 0;
+}
+
+#if CFG_PCI
+/* *********************************************************************
+ * usb_init_pci_ohci()
+ *
+ * Initialize all PCI-based OHCI controllers
+ *
+ * Input parameters:
+ * nothing
+ *
+ * Return value:
+ * 0 if ok
+ * else error
+ ********************************************************************* */
+static int usb_init_pci_ohci(void)
+{
+ int res;
+ pcitag_t tag;
+ uint32_t pciclass;
+ physaddr_t bar;
+ int idx;
+
+ idx = 0;
+
+ while (pci_find_class(PCI_CLASS_SERIALBUS,idx,&tag) == 0) {
+ pciclass = pci_conf_read(tag,PCI_CLASS_REG);
+ if ((PCI_SUBCLASS(pciclass) == PCI_SUBCLASS_SERIALBUS_USB) &&
+ (PCI_INTERFACE(pciclass) == 0x10)) {
+ bar = (physaddr_t) pci_conf_read(tag,PCI_MAPREG_START);
+ pci_tagprintf(tag,"OHCI USB controller found at %08X\n",(uint32_t) bar);
+
+ /* On the BCM1250, this sets the address to "match bits" mode,
+ which eliminates the need for byte swaps of data to/from the registers. */
+ bar |= 0x20000000;
+
+ res = usb_init_one_ohci(bar);
+ if (res < 0) break;
+ }
+ idx++;
+ }
+
+ return 0;
+}
+#endif
+
+
+
+/* *********************************************************************
+ * usb_init()
+ *
+ * Initialize the USB subsystem
+ *
+ * Input parameters:
+ * nothing
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+int usb_init(void)
+{
+ static int initdone = 0;
+
+ if (initdone) {
+ printf("USB has already been initialized.\n");
+ return -1;
+ }
+
+ printf("Initializing USB.\n");
+
+ initdone = 1;
+
+ usb_buscnt = 0;
+
+#if CFG_PCI
+ usb_init_pci_ohci();
+#endif
+
+#if CFG_USB_OHCI_BASE
+ usb_init_one_ohci(CFG_USB_OHCI_BASE);
+#endif
+
+ cfe_bg_add(usb_cfe_timer,NULL);
+
+ return 0;
+}
+
+
+
+static int ui_cmd_usb_start(ui_cmdline_t *cmd,int argc,char *argv[])
+{
+ int res = 0;
+
+ if (cmd_sw_isset(cmd,"-o")) ohcidebug++;
+ if (cmd_sw_isset(cmd,"-oo")) ohcidebug+=2;
+ if (cmd_sw_isset(cmd,"-u")) usb_noisy++;
+ if (cmd_sw_isset(cmd,"-uu")) usb_noisy+=2;
+
+ if (usb_buscnt == 0) {
+ res = usb_init();
+ }
+
+ return res;
+}
+
+
+static int ui_cmd_usb_show(ui_cmdline_t *cmd,int argc,char *argv[])
+{
+ int busnum;
+ int devnum;
+ char *x;
+ int idx;
+ uint32_t arg;
+
+ x = cmd_getarg(cmd,1);
+ if (!x) devnum = 0;
+ else devnum = atoi(x);
+
+ x = cmd_getarg(cmd,0);
+ if (!x) x = "*";
+ busnum = atoi(x);
+
+ if (busnum >= usb_buscnt) {
+ printf("Invalid bus number, %d USB Buses currently configured.\n",usb_buscnt);
+ return -1;
+ }
+
+ arg = cmd_sw_isset(cmd,"-v") ? 0x100 : 0;
+ arg |= (devnum & 0xFF);
+
+ if (x[0] == '*') {
+ for (idx = 0; idx < usb_buscnt; idx++) {
+ usbhub_dumpbus(usb_buses[idx],arg);
+ }
+ }
+ else {
+ usbhub_dumpbus(usb_buses[busnum],arg);
+ }
+
+ return 0;
+
+}
+
+/* *********************************************************************
+ * ui_init_usbcmds(void)
+ *
+ * Initialize the USB commands
+ *
+ * Input parameters:
+ * nothing
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+
+int ui_init_usbcmds(void)
+{
+ cmd_addcmd("usb init",
+ ui_cmd_usb_start,
+ NULL,
+ "Initialize the USB controller.",
+ "usb init",
+ "-o;OHCI debug messages|"
+ "-oo;more OHCI debug messages|"
+ "-u;USBD debug messages|"
+ "-uu;more USBD debug messages");
+
+
+ cmd_addcmd("show usb",
+ ui_cmd_usb_show,
+ NULL,
+ "Display devices connected to USB bus.",
+ "usb show [bus [device]]\n\n"
+ "Displays the configuration descriptors for devices connected to the USB\n"
+ "If you specify a bus, the entire bus is displayed. If you specify the\n"
+ "device number as well, only the specified device is displayed\n",
+ "-v;Display descriptors from the devices");
+
+ return 0;
+}
diff --git a/cfe/cfe/usb/usbmass.c b/cfe/cfe/usb/usbmass.c
new file mode 100644
index 0000000..ae3856d
--- /dev/null
+++ b/cfe/cfe/usb/usbmass.c
@@ -0,0 +1,1199 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * USB Mass-Storage driver File: usbmass.c
+ *
+ * This driver deals with mass-storage devices that support
+ * the SCSI Transparent command set and USB Bulk-Only protocol
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#ifndef _CFE_
+#include <stdio.h>
+#include <time.h>
+#include <memory.h>
+#include <stdint.h>
+#include "usbhack.h"
+#else
+#include "lib_types.h"
+#include "lib_string.h"
+#include "lib_printf.h"
+#include "cfe_timer.h"
+#include "cfe_iocb.h"
+#include "cfe_device.h"
+#include "cfe_ioctl.h"
+#include "cfe_error.h"
+#include "cfe_console.h"
+#endif
+
+#include "lib_malloc.h"
+#include "lib_queue.h"
+#include "usbchap9.h"
+#include "usbd.h"
+
+/* *********************************************************************
+ * USB Mass-Storage class Constants
+ ********************************************************************* */
+
+#define USBMASS_CBI_PROTOCOL 0
+#define USBMASS_CBI_NOCOMPLETE_PROTOCOL 1
+#define USBMASS_BULKONLY_PROTOCOL 0x50
+
+#define USBMASS_SUBCLASS_RBC 0x01
+#define USBMASS_SUBCLASS_SFF8020 0x02
+#define USBMASS_SUBCLASS_QIC157 0x03
+#define USBMASS_SUBCLASS_UFI 0x04
+#define USBMASS_SUBCLASS_SFF8070 0x05
+#define USBMASS_SUBCLASS_SCSI 0x06
+
+#define USBMASS_CSW_PASS 0x00
+#define USBMASS_CSW_FAILED 0x01
+#define USBMASS_CSW_PHASEERR 0x02
+
+#define USBMASS_CBW_SIGNATURE 0x43425355
+#define USBMASS_CSW_SIGNATURE 0x53425355
+
+/* *********************************************************************
+ * USB Mass-Storage class Structures
+ ********************************************************************* */
+
+typedef struct usbmass_cbw_s {
+ uint8_t dCBWSignature0,dCBWSignature1,dCBWSignature2,dCBWSignature3;
+ uint8_t dCBWTag0,dCBWTag1,dCBWTag2,dCBWTag3;
+ uint8_t dCBWDataTransferLength0,dCBWDataTransferLength1,
+ dCBWDataTransferLength2,dCBWDataTransferLength3;
+ uint8_t bmCBWFlags;
+ uint8_t bCBWLUN;
+ uint8_t bCBWCBLength;
+ uint8_t CBWCB[16];
+} usbmass_cbw_t;
+
+typedef struct usbmass_csw_s {
+ uint8_t dCSWSignature0,dCSWSignature1,dCSWSignature2,dCSWSignature3;
+ uint8_t dCSWTag0,dCSWTag1,dCSWTag2,dCSWTag3;
+ uint8_t dCSWDataResidue0,dCSWDataResidue1,dCSWDataResidue2,dCSWDataResidue3;
+ uint8_t bCSWStatus;
+} usbmass_csw_t;
+
+#define GETCBWFIELD(s,f) ((uint32_t)((s)->f##0) | ((uint32_t)((s)->f##1) << 8) | \
+ ((uint32_t)((s)->f##2) << 16) | ((uint32_t)((s)->f##3) << 24))
+#define PUTCBWFIELD(s,f,v) (s)->f##0 = (v & 0xFF); \
+ (s)->f##1 = ((v)>>8 & 0xFF); \
+ (s)->f##2 = ((v)>>16 & 0xFF); \
+ (s)->f##3 = ((v)>>24 & 0xFF);
+
+
+int usbmass_request_sense(usbdev_t *dev);
+
+/* *********************************************************************
+ * Linkage to CFE
+ ********************************************************************* */
+
+#ifdef _CFE_
+
+/*
+ * Softc for the CFE side of the disk driver.
+ */
+#define MAX_SECTORSIZE 2048
+typedef struct usbdisk_s {
+ uint32_t usbdisk_sectorsize;
+ uint32_t usbdisk_ttlsect;
+ uint32_t usbdisk_devtype;
+ int usbdisk_unit;
+} usbdisk_t;
+
+/*
+ * This table points at the currently configured USB disk
+ * devices. This lets us leave the CFE half of the driver lying
+ * around while the USB devices come and go. We use the unit number
+ * from the original CFE attach to index this table, and devices
+ * that are not present are "not ready."
+ */
+
+#define USBDISK_MAXUNITS 4
+static usbdev_t *usbdisk_units[USBDISK_MAXUNITS];
+
+/*
+ * CFE device driver routine forwards
+ */
+
+static void usbdisk_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr);
+
+static int usbdisk_open(cfe_devctx_t *ctx);
+static int usbdisk_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int usbdisk_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
+static int usbdisk_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int usbdisk_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int usbdisk_close(cfe_devctx_t *ctx);
+
+/*
+ * CFE device driver descriptor
+ */
+
+const static cfe_devdisp_t usbdisk_dispatch = {
+ usbdisk_open,
+ usbdisk_read,
+ usbdisk_inpstat,
+ usbdisk_write,
+ usbdisk_ioctl,
+ usbdisk_close,
+ NULL,
+ NULL
+};
+
+const cfe_driver_t usb_disk = {
+ "USB Disk",
+ "usbdisk",
+ CFE_DEV_DISK,
+ &usbdisk_dispatch,
+ usbdisk_probe
+};
+
+
+#endif
+
+
+
+/* *********************************************************************
+ * Forward Definitions
+ ********************************************************************* */
+
+static int usbmass_attach(usbdev_t *dev,usb_driver_t *drv);
+static int usbmass_detach(usbdev_t *dev);
+
+/* *********************************************************************
+ * Structures
+ ********************************************************************* */
+
+typedef struct usbmass_softc_s {
+ int umass_inpipe;
+ int umass_outpipe;
+ int umass_devtype;
+ uint32_t umass_curtag;
+ int umass_unit;
+} usbmass_softc_t;
+
+usb_driver_t usbmass_driver = {
+ "Mass-Storage Device",
+ usbmass_attach,
+ usbmass_detach
+};
+
+usbdev_t *usbmass_dev = NULL; /* XX hack for testing only */
+
+/* *********************************************************************
+ * usbmass_mass_storage_reset(dev,ifc)
+ *
+ * Do a bulk-only mass-storage reset.
+ *
+ * Input parameters:
+ * dev - device to reset
+ * ifc - interface number to reset (bInterfaceNum)
+ *
+ * Return value:
+ * status
+ ********************************************************************* */
+
+#define usbmass_mass_storage_reset(dev,ifc) \
+ usb_simple_request(dev,0x21,0xFF,ifc,0)
+
+#if 0
+/* *********************************************************************
+ * usbmass_get_max_lun(dev,lunp)
+ *
+ * Get maximum LUN from device
+ *
+ * Input parameters:
+ * dev - device to reset
+ * lunp - pointer to int to receive max lun
+ *
+ * Return value:
+ * status
+ ********************************************************************* */
+
+static int usbmass_get_max_lun(usbdev_t *dev,int *lunp)
+{
+ uint8_t buf = 0;
+ int res;
+
+ res = usb_std_request(dev,0xA1,0xFE,0,0,&buf,1);
+
+ if (res < 0) return res;
+
+ if (lunp) *lunp = (int) buf;
+ return 0;
+}
+
+#endif
+
+
+/* *********************************************************************
+ * usbmass_stall_recovery(dev)
+ *
+ * Do whatever it takes to unstick a stalled mass-storage device.
+ *
+ * Input parameters:
+ * dev - usb device
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void usbmass_stall_recovery(usbdev_t *dev)
+{
+ usbmass_softc_t *softc;
+
+ softc = (usbmass_softc_t *) dev->ud_private;
+
+ usb_clear_stall(dev,softc->umass_inpipe);
+
+ usbmass_request_sense(dev);
+}
+
+
+/* *********************************************************************
+ * usbmass_read_capacity(dev,sectornum,buffer)
+ *
+ * Reads a sector from the device.
+ *
+ * Input parameters:
+ * dev - usb device
+ * sectornum - sector number to read
+ * buffer - place to put sector we read
+ *
+ * Return value:
+ * status
+ ********************************************************************* */
+
+int usbmass_request_sense(usbdev_t *dev)
+{
+ uint8_t *cbwcsw;
+ uint8_t *sector;
+ usbmass_cbw_t *cbw;
+ usbmass_csw_t *csw;
+ usbreq_t *ur;
+ usbmass_softc_t *softc;
+ int res;
+
+ softc = (usbmass_softc_t *) dev->ud_private;
+
+ cbwcsw = KMALLOC(64,32);
+ sector = KMALLOC(64,32);
+
+ memset(sector,0,64);
+
+ cbw = (usbmass_cbw_t *) cbwcsw;
+ csw = (usbmass_csw_t *) cbwcsw;
+
+ /*
+ * Fill in the fields of the CBW
+ */
+
+ PUTCBWFIELD(cbw,dCBWSignature,USBMASS_CBW_SIGNATURE);
+ PUTCBWFIELD(cbw,dCBWTag,softc->umass_curtag);
+ PUTCBWFIELD(cbw,dCBWDataTransferLength,18);
+ cbw->bmCBWFlags = 0x80; /* IN */
+ cbw->bCBWLUN = 0;
+ cbw->bCBWCBLength = 12;
+ cbw->CBWCB[0] = 0x3; /* REQUEST SENSE */
+ cbw->CBWCB[1] = 0;
+ cbw->CBWCB[2] = 0;
+ cbw->CBWCB[3] = 0;
+ cbw->CBWCB[4] = 18; /* allocation length */
+ cbw->CBWCB[5] = 0;
+ cbw->CBWCB[6] = 0;
+ cbw->CBWCB[7] = 0;
+ cbw->CBWCB[8] = 0;
+ cbw->CBWCB[9] = 0;
+
+ softc->umass_curtag++;
+
+ /*
+ * Send the CBW
+ */
+
+ ur = usb_make_request(dev,softc->umass_outpipe,(uint8_t *) cbw,
+ sizeof(usbmass_cbw_t),UR_FLAG_OUT);
+ res = usb_sync_request(ur);
+ usb_free_request(ur);
+
+ /*
+ * Get the data
+ */
+
+ memset(sector,0,18);
+ ur = usb_make_request(dev,softc->umass_inpipe,sector,
+ 18,UR_FLAG_IN | UR_FLAG_SHORTOK);
+ res = usb_sync_request(ur);
+ usb_free_request(ur);
+
+ /*
+ * Get the Status
+ */
+
+ memset(csw,0,sizeof(usbmass_csw_t));
+ ur = usb_make_request(dev,softc->umass_inpipe,(uint8_t *) csw,
+ sizeof(usbmass_csw_t),UR_FLAG_IN);
+ res = usb_sync_request(ur);
+ usb_free_request(ur);
+
+ KFREE(cbwcsw);
+
+ KFREE(sector);
+
+ return 0;
+
+}
+
+/* *********************************************************************
+ * usbmass_read_sector(dev,sectornum,seccnt,buffer)
+ *
+ * Reads a sector from the device.
+ *
+ * Input parameters:
+ * dev - usb device
+ * sectornum - sector number to read
+ * seccnt - count of sectors to read
+ * buffer - place to put sector we read
+ *
+ * Return value:
+ * status
+ ********************************************************************* */
+
+int usbmass_read_sector(usbdev_t *dev,uint32_t sectornum,uint32_t seccnt,
+ uint8_t *buffer);
+int usbmass_read_sector(usbdev_t *dev,uint32_t sectornum,uint32_t seccnt,
+ uint8_t *buffer)
+{
+ uint8_t *cbwcsw;
+ uint8_t *sector;
+ usbmass_cbw_t *cbw;
+ usbmass_csw_t *csw;
+ usbreq_t *ur;
+ usbmass_softc_t *softc;
+ int res;
+
+ softc = (usbmass_softc_t *) dev->ud_private;
+
+ cbwcsw = KMALLOC(64,32);
+ sector = buffer;
+
+ cbw = (usbmass_cbw_t *) cbwcsw;
+ csw = (usbmass_csw_t *) cbwcsw;
+
+ /*
+ * Fill in the fields of the CBW
+ */
+
+ PUTCBWFIELD(cbw,dCBWSignature,USBMASS_CBW_SIGNATURE);
+ PUTCBWFIELD(cbw,dCBWTag,softc->umass_curtag);
+ PUTCBWFIELD(cbw,dCBWDataTransferLength,(512*seccnt));
+ cbw->bmCBWFlags = 0x80; /* IN */
+ cbw->bCBWLUN = 0;
+ cbw->bCBWCBLength = 10;
+ cbw->CBWCB[0] = 0x28; /* READ */
+ cbw->CBWCB[1] = 0;
+ cbw->CBWCB[2] = (sectornum >> 24) & 0xFF; /* LUN 0 & MSB's of sector */
+ cbw->CBWCB[3] = (sectornum >> 16) & 0xFF;
+ cbw->CBWCB[4] = (sectornum >> 8) & 0xFF;
+ cbw->CBWCB[5] = (sectornum >> 0) & 0xFF;
+ cbw->CBWCB[6] = 0;
+ cbw->CBWCB[7] = 0;
+ cbw->CBWCB[8] = seccnt;
+ cbw->CBWCB[9] = 0;
+
+ softc->umass_curtag++;
+
+ /*
+ * Send the CBW
+ */
+
+ ur = usb_make_request(dev,softc->umass_outpipe,(uint8_t *) cbw,
+ sizeof(usbmass_cbw_t),UR_FLAG_OUT);
+ res = usb_sync_request(ur);
+ usb_free_request(ur);
+ if (res == 4) {
+ usbmass_stall_recovery(dev);
+ KFREE(cbwcsw);
+ return -1;
+ }
+
+
+ /*
+ * Get the data
+ */
+
+ ur = usb_make_request(dev,softc->umass_inpipe,sector,
+ 512*seccnt,UR_FLAG_IN | UR_FLAG_SHORTOK);
+ res = usb_sync_request(ur);
+ usb_free_request(ur);
+ if (res == 4) {
+ usbmass_stall_recovery(dev);
+ KFREE(cbwcsw);
+ return -1;
+ }
+
+
+ /*
+ * Get the Status
+ */
+
+ memset(csw,0,sizeof(usbmass_csw_t));
+ ur = usb_make_request(dev,softc->umass_inpipe,(uint8_t *) csw,
+ sizeof(usbmass_csw_t),UR_FLAG_IN);
+ res = usb_sync_request(ur);
+ usb_free_request(ur);
+ if (res == 4) {
+ usbmass_stall_recovery(dev);
+ KFREE(cbwcsw);
+ return -1;
+ }
+
+
+#if 0
+ printf("CSW: Signature=%08X Tag=%08X Residue=%08X Status=%02X\n",
+ GETCBWFIELD(csw,dCSWSignature),
+ GETCBWFIELD(csw,dCSWTag),
+ GETCBWFIELD(csw,dCSWDataResidue),
+ csw->bCSWStatus);
+#endif
+
+ res = (csw->bCSWStatus == USBMASS_CSW_PASS) ? 0 : -1;
+
+ KFREE(cbwcsw);
+
+ return res;
+
+}
+
+/* *********************************************************************
+ * usbmass_write_sector(dev,sectornum,seccnt,buffer)
+ *
+ * Writes a sector to the device
+ *
+ * Input parameters:
+ * dev - usb device
+ * sectornum - sector number to write
+ * seccnt - count of sectors to write
+ * buffer - place to get sector to write
+ *
+ * Return value:
+ * status
+ ********************************************************************* */
+
+static int usbmass_write_sector(usbdev_t *dev,uint32_t sectornum,uint32_t seccnt,
+ uint8_t *buffer)
+{
+ uint8_t *cbwcsw;
+ uint8_t *sector;
+ usbmass_cbw_t *cbw;
+ usbmass_csw_t *csw;
+ usbreq_t *ur;
+ usbmass_softc_t *softc;
+ int res;
+
+ softc = (usbmass_softc_t *) dev->ud_private;
+
+ cbwcsw = KMALLOC(64,32);
+ sector = buffer;
+
+ cbw = (usbmass_cbw_t *) cbwcsw;
+ csw = (usbmass_csw_t *) cbwcsw;
+
+ /*
+ * Fill in the fields of the CBW
+ */
+
+ PUTCBWFIELD(cbw,dCBWSignature,USBMASS_CBW_SIGNATURE);
+ PUTCBWFIELD(cbw,dCBWTag,softc->umass_curtag);
+ PUTCBWFIELD(cbw,dCBWDataTransferLength,(512*seccnt));
+ cbw->bmCBWFlags = 0x00; /* OUT */
+ cbw->bCBWLUN = 0;
+ cbw->bCBWCBLength = 10;
+ cbw->CBWCB[0] = 0x2A; /* WRITE */
+ cbw->CBWCB[1] = 0;
+ cbw->CBWCB[2] = (sectornum >> 24) & 0xFF; /* LUN 0 & MSB's of sector */
+ cbw->CBWCB[3] = (sectornum >> 16) & 0xFF;
+ cbw->CBWCB[4] = (sectornum >> 8) & 0xFF;
+ cbw->CBWCB[5] = (sectornum >> 0) & 0xFF;
+ cbw->CBWCB[6] = 0;
+ cbw->CBWCB[7] = 0;
+ cbw->CBWCB[8] = seccnt;
+ cbw->CBWCB[9] = 0;
+
+ softc->umass_curtag++;
+
+ /*
+ * Send the CBW
+ */
+
+ ur = usb_make_request(dev,softc->umass_outpipe,(uint8_t *) cbw,
+ sizeof(usbmass_cbw_t),UR_FLAG_OUT);
+ res = usb_sync_request(ur);
+ usb_free_request(ur);
+
+ /*
+ * Send the data
+ */
+
+ ur = usb_make_request(dev,softc->umass_outpipe,sector,
+ 512*seccnt,UR_FLAG_OUT);
+ res = usb_sync_request(ur);
+ usb_free_request(ur);
+
+ /*
+ * Get the Status
+ */
+
+ memset(csw,0,sizeof(usbmass_csw_t));
+ ur = usb_make_request(dev,softc->umass_inpipe,(uint8_t *) csw,
+ sizeof(usbmass_csw_t),UR_FLAG_IN);
+ res = usb_sync_request(ur);
+ usb_free_request(ur);
+
+#if 0
+ printf("CSW: Signature=%08X Tag=%08X Residue=%08X Status=%02X\n",
+ GETCBWFIELD(csw,dCSWSignature),
+ GETCBWFIELD(csw,dCSWTag),
+ GETCBWFIELD(csw,dCSWDataResidue),
+ csw->bCSWStatus);
+#endif
+
+ res = (csw->bCSWStatus == USBMASS_CSW_PASS) ? 0 : -1;
+
+ KFREE(cbwcsw);
+
+ return res;
+}
+
+/* *********************************************************************
+ * usbmass_read_capacity(dev,sectornum,buffer)
+ *
+ * Reads a sector from the device.
+ *
+ * Input parameters:
+ * dev - usb device
+ * sectornum - sector number to read
+ * buffer - place to put sector we read
+ *
+ * Return value:
+ * status
+ ********************************************************************* */
+
+int usbmass_read_capacity(usbdev_t *dev,uint32_t *size);
+int usbmass_read_capacity(usbdev_t *dev,uint32_t *size)
+{
+ uint8_t *cbwcsw;
+ uint8_t *sector;
+ usbmass_cbw_t *cbw;
+ usbmass_csw_t *csw;
+ usbreq_t *ur;
+ usbmass_softc_t *softc;
+ int res;
+
+ softc = (usbmass_softc_t *) dev->ud_private;
+
+ cbwcsw = KMALLOC(64,32);
+ sector = KMALLOC(64,32);
+
+ memset(sector,0,64);
+
+ cbw = (usbmass_cbw_t *) cbwcsw;
+ csw = (usbmass_csw_t *) cbwcsw;
+
+ *size = 0;
+
+ /*
+ * Fill in the fields of the CBW
+ */
+
+ PUTCBWFIELD(cbw,dCBWSignature,USBMASS_CBW_SIGNATURE);
+ PUTCBWFIELD(cbw,dCBWTag,softc->umass_curtag);
+ PUTCBWFIELD(cbw,dCBWDataTransferLength,8);
+ cbw->bmCBWFlags = 0x80; /* IN */
+ cbw->bCBWLUN = 0;
+ cbw->bCBWCBLength = 10;
+ cbw->CBWCB[0] = 0x25; /* READ CAPACITY */
+ cbw->CBWCB[1] = 0;
+ cbw->CBWCB[2] = 0;
+ cbw->CBWCB[3] = 0;
+ cbw->CBWCB[4] = 0;
+ cbw->CBWCB[5] = 0;
+ cbw->CBWCB[6] = 0;
+ cbw->CBWCB[7] = 0;
+ cbw->CBWCB[8] = 0;
+ cbw->CBWCB[9] = 0;
+
+ softc->umass_curtag++;
+
+ /*
+ * Send the CBW
+ */
+
+ ur = usb_make_request(dev,softc->umass_outpipe,(uint8_t *) cbw,
+ sizeof(usbmass_cbw_t),UR_FLAG_OUT);
+ res = usb_sync_request(ur);
+ usb_free_request(ur);
+
+ if (res == 4) {
+ usbmass_stall_recovery(dev);
+ KFREE(cbwcsw);
+ KFREE(sector);
+ return -1;
+ }
+
+ /*
+ * Get the data
+ */
+
+ ur = usb_make_request(dev,softc->umass_inpipe,sector,
+ 8,UR_FLAG_IN | UR_FLAG_SHORTOK);
+ res = usb_sync_request(ur);
+ usb_free_request(ur);
+
+ if (res == 4) {
+ usbmass_stall_recovery(dev);
+ KFREE(cbwcsw);
+ KFREE(sector);
+ return -1;
+ }
+
+ /*
+ * Get the Status
+ */
+
+ memset(csw,0,sizeof(usbmass_csw_t));
+ ur = usb_make_request(dev,softc->umass_inpipe,(uint8_t *) csw,
+ sizeof(usbmass_csw_t),UR_FLAG_IN);
+ res = usb_sync_request(ur);
+ usb_free_request(ur);
+
+ KFREE(cbwcsw);
+
+ *size = (((uint32_t) sector[0]) << 24) |
+ (((uint32_t) sector[1]) << 16) |
+ (((uint32_t) sector[2]) << 8) |
+ (((uint32_t) sector[3]) << 0);
+
+ KFREE(sector);
+
+ return 0;
+
+}
+
+
+
+/* *********************************************************************
+ * usbmass_attach(dev,drv)
+ *
+ * This routine is called when the bus scan stuff finds a mass-storage
+ * device. We finish up the initialization by configuring the
+ * device and allocating our softc here.
+ *
+ * Input parameters:
+ * dev - usb device, in the "addressed" state.
+ * drv - the driver table entry that matched
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+
+static int usbmass_attach(usbdev_t *dev,usb_driver_t *drv)
+{
+ usb_config_descr_t *cfgdscr = dev->ud_cfgdescr;
+ usb_endpoint_descr_t *epdscr;
+ usb_endpoint_descr_t *indscr = NULL;
+ usb_endpoint_descr_t *outdscr = NULL;
+ usb_interface_descr_t *ifdscr;
+ usbmass_softc_t *softc;
+ int idx;
+
+ dev->ud_drv = drv;
+
+ softc = KMALLOC(sizeof(usbmass_softc_t),0);
+ memset(softc,0,sizeof(usbmass_softc_t));
+ dev->ud_private = softc;
+
+ ifdscr = usb_find_cfg_descr(dev,USB_INTERFACE_DESCRIPTOR_TYPE,0);
+ if (ifdscr == NULL) {
+ return -1;
+ }
+
+ if ((ifdscr->bInterfaceSubClass != USBMASS_SUBCLASS_SCSI) ||
+ (ifdscr->bInterfaceProtocol != USBMASS_BULKONLY_PROTOCOL)) {
+ console_log("USBMASS: Do not understand devices with SubClass 0x%02X, Protocol 0x%02X",
+ ifdscr->bInterfaceSubClass,
+ ifdscr->bInterfaceProtocol);
+ return -1;
+ }
+
+ for (idx = 0; idx < 2; idx++) {
+ epdscr = usb_find_cfg_descr(dev,USB_ENDPOINT_DESCRIPTOR_TYPE,idx);
+
+ if (USB_ENDPOINT_DIR_OUT(epdscr->bEndpointAddress)) {
+ outdscr = epdscr;
+ }
+ else {
+ indscr = epdscr;
+ }
+ }
+
+
+ if (!indscr || !outdscr) {
+ /*
+ * Could not get descriptors, something is very wrong.
+ * Leave device addressed but not configured.
+ */
+ return -1;
+ }
+
+ /*
+ * Choose the standard configuration.
+ */
+
+ usb_set_configuration(dev,cfgdscr->bConfigurationValue);
+
+ /*
+ * Open the pipes.
+ */
+
+ softc->umass_inpipe = usb_open_pipe(dev,indscr);
+ softc->umass_outpipe = usb_open_pipe(dev,outdscr);
+ softc->umass_curtag = 0x12345678;
+
+ /*
+ * Save pointer in global unit table so we can
+ * match CFE devices up with USB ones
+ */
+
+
+#ifdef _CFE_
+ softc->umass_unit = -1;
+ for (idx = 0; idx < USBDISK_MAXUNITS; idx++) {
+ if (usbdisk_units[idx] == NULL) {
+ softc->umass_unit = idx;
+ usbdisk_units[idx] = dev;
+ break;
+ }
+ }
+
+ console_log("USBMASS: Unit %d connected",softc->umass_unit);
+#endif
+
+ usbmass_dev = dev;
+
+ return 0;
+}
+
+/* *********************************************************************
+ * usbmass_detach(dev)
+ *
+ * This routine is called when the bus scanner notices that
+ * this device has been removed from the system. We should
+ * do any cleanup that is required. The pending requests
+ * will be cancelled automagically.
+ *
+ * Input parameters:
+ * dev - usb device
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+
+static int usbmass_detach(usbdev_t *dev)
+{
+ usbmass_softc_t *softc;
+ softc = (usbmass_softc_t *) dev->ud_private;
+
+#ifdef _CFE_
+ console_log("USBMASS: USB unit %d disconnected",softc->umass_unit);
+ if (softc->umass_unit >= 0) usbdisk_units[softc->umass_unit] = NULL;
+#endif
+
+ KFREE(softc);
+ return 0;
+}
+
+
+
+#ifdef _CFE_
+
+
+/* *********************************************************************
+ * usbdisk_sectorshift(size)
+ *
+ * Given a sector size, return log2(size). We cheat; this is
+ * only needed for 2048 and 512-byte sectors.
+ * Explicitly using shifts and masks in sector number calculations
+ * helps on 32-bit-only platforms, since we probably won't need
+ * a helper library.
+ *
+ * Input parameters:
+ * size - sector size
+ *
+ * Return value:
+ * # of bits to shift
+ ********************************************************************* */
+
+#define usbdisk_sectorshift(size) (((size)==2048)?11:9)
+
+
+/* *********************************************************************
+ * usbdisk_probe(drv,probe_a,probe_b,probe_ptr)
+ *
+ * Our probe routine. Attach an empty USB disk device to the firmware.
+ *
+ * Input parameters:
+ * drv - driver structure
+ * probe_a - not used
+ * probe_b - not used
+ * probe_ptr - not used
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void usbdisk_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr)
+{
+ usbdisk_t *softc;
+ char descr[128];
+
+ softc = (usbdisk_t *) KMALLOC(sizeof(usbdisk_t),0);
+
+ memset(softc,0,sizeof(usbdisk_t));
+
+ softc->usbdisk_sectorsize = 512;
+ softc->usbdisk_devtype = BLOCK_DEVTYPE_DISK;
+ softc->usbdisk_ttlsect = 0; /* not calculated yet */
+ softc->usbdisk_unit = (int)probe_a;
+
+ xsprintf(descr,"USB Disk unit %d",(int)probe_a);
+
+ cfe_attach(drv,softc,NULL,descr);
+}
+
+
+/* *********************************************************************
+ * usbdisk_open(ctx)
+ *
+ * Process the CFE OPEN call for this device. For IDE disks,
+ * the device is reset and identified, and the geometry is
+ * determined.
+ *
+ * Input parameters:
+ * ctx - device context
+ *
+ * Return value:
+ * 0 if ok, else error code
+ ********************************************************************* */
+
+
+static int usbdisk_open(cfe_devctx_t *ctx)
+{
+ usbdisk_t *softc = ctx->dev_softc;
+ usbdev_t *dev = usbdisk_units[softc->usbdisk_unit];
+ uint32_t size;
+ int res;
+
+ if (!dev) return CFE_ERR_NOTREADY;
+
+ usbmass_request_sense(dev);
+
+ res = usbmass_read_capacity(dev,&size);
+ if (res < 0) return res;
+
+ softc->usbdisk_ttlsect = size;
+
+ return 0;
+}
+
+/* *********************************************************************
+ * usbdisk_read(ctx,buffer)
+ *
+ * Process a CFE READ command for the IDE device. This is
+ * more complex than it looks, since CFE offsets are byte offsets
+ * and we may need to read partial sectors.
+ *
+ * Input parameters:
+ * ctx - device context
+ * buffer - buffer descriptor
+ *
+ * Return value:
+ * number of bytes read, or <0 if an error occured
+ ********************************************************************* */
+
+static int usbdisk_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
+{
+ usbdisk_t *softc = ctx->dev_softc;
+ usbdev_t *dev = usbdisk_units[softc->usbdisk_unit];
+ unsigned char *bptr;
+ int blen;
+ int numsec;
+ int res = 0;
+ int amtcopy;
+ uint64_t lba;
+ uint64_t offset;
+ unsigned char sector[MAX_SECTORSIZE];
+ int sectorshift;
+
+ if (!dev) return CFE_ERR_NOTREADY;
+
+ sectorshift = usbdisk_sectorshift(softc->usbdisk_sectorsize);
+
+ bptr = buffer->buf_ptr;
+ blen = buffer->buf_length;
+ offset = buffer->buf_offset;
+ numsec = (blen + softc->usbdisk_sectorsize - 1) >> sectorshift;
+
+ if (offset & (softc->usbdisk_sectorsize-1)) {
+ lba = (offset >> sectorshift);
+ res = usbmass_read_sector(dev,lba,1,sector);
+ if (res < 0) goto out;
+ amtcopy = softc->usbdisk_sectorsize - (offset & (softc->usbdisk_sectorsize-1));
+ if (amtcopy > blen) amtcopy = blen;
+ memcpy(bptr,&sector[offset & (softc->usbdisk_sectorsize-1)],amtcopy);
+ bptr += amtcopy;
+ offset += amtcopy;
+ blen -= amtcopy;
+ }
+
+ if (blen >= softc->usbdisk_sectorsize) {
+ int seccnt;
+
+ lba = (offset >> sectorshift);
+ seccnt = (blen >> sectorshift);
+
+ res = usbmass_read_sector(dev,lba,seccnt,bptr);
+ if (res < 0) goto out;
+
+ amtcopy = seccnt << sectorshift;
+ bptr += amtcopy;
+ offset += amtcopy;
+ blen -= amtcopy;
+ }
+
+ if (blen) {
+ lba = (offset >> sectorshift);
+ res = usbmass_read_sector(dev,lba,1,sector);
+ if (res < 0) goto out;
+ amtcopy = blen;
+ memcpy(bptr,sector,amtcopy);
+ bptr += amtcopy;
+ offset += amtcopy;
+ blen -= amtcopy;
+ }
+
+out:
+ buffer->buf_retlen = bptr - buffer->buf_ptr;
+
+ return res;
+}
+
+/* *********************************************************************
+ * usbdisk_inpstat(ctx,inpstat)
+ *
+ * Test input status for the IDE disk. Disks are always ready
+ * to read.
+ *
+ * Input parameters:
+ * ctx - device context
+ * inpstat - input status structure
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+
+static int usbdisk_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat)
+{
+ /* usbdisk_t *softc = ctx->dev_softc; */
+
+ inpstat->inp_status = 1;
+ return 0;
+}
+
+/* *********************************************************************
+ * usbdisk_write(ctx,buffer)
+ *
+ * Process a CFE WRITE command for the IDE device. If the write
+ * involves partial sectors, the affected sectors are read first
+ * and the changes are merged in.
+ *
+ * Input parameters:
+ * ctx - device context
+ * buffer - buffer descriptor
+ *
+ * Return value:
+ * number of bytes write, or <0 if an error occured
+ ********************************************************************* */
+
+static int usbdisk_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
+{
+ usbdisk_t *softc = ctx->dev_softc;
+ usbdev_t *dev = usbdisk_units[softc->usbdisk_unit];
+ unsigned char *bptr;
+ int blen;
+ int numsec;
+ int res = 0;
+ int amtcopy;
+ uint64_t offset;
+ uint64_t lba;
+ unsigned char sector[MAX_SECTORSIZE];
+ int sectorshift;
+
+ if (!dev) return CFE_ERR_NOTREADY;
+
+ sectorshift = usbdisk_sectorshift(softc->usbdisk_sectorsize);
+
+ bptr = buffer->buf_ptr;
+ blen = buffer->buf_length;
+ offset = buffer->buf_offset;
+ numsec = (blen + softc->usbdisk_sectorsize - 1) >> sectorshift;
+
+ if (offset & (softc->usbdisk_sectorsize-1)) {
+ lba = (offset >> sectorshift);
+ res = usbmass_read_sector(dev,lba,1,sector);
+ if (res < 0) goto out;
+ amtcopy = softc->usbdisk_sectorsize - (offset & (softc->usbdisk_sectorsize-1));
+ if (amtcopy > blen) amtcopy = blen;
+ memcpy(&sector[offset & (softc->usbdisk_sectorsize-1)],bptr,amtcopy);
+ res = usbmass_write_sector(dev,lba,1,sector);
+ if (res < 0) goto out;
+ bptr += amtcopy;
+ offset += amtcopy;
+ blen -= amtcopy;
+ }
+
+ while (blen >= softc->usbdisk_sectorsize) {
+ amtcopy = softc->usbdisk_sectorsize;
+ lba = (offset >> sectorshift);
+ res = usbmass_write_sector(dev,lba,1,bptr);
+ if (res < 0) goto out;
+ bptr += amtcopy;
+ offset += amtcopy;
+ blen -= amtcopy;
+ }
+
+ if (blen) {
+ lba = (offset >> sectorshift);
+ res = usbmass_read_sector(dev,lba,1,sector);
+ if (res < 0) goto out;
+ amtcopy = blen;
+ memcpy(sector,bptr,amtcopy);
+ res = usbmass_write_sector(dev,lba,1,sector);
+ if (res < 0) goto out;
+ bptr += amtcopy;
+ offset += amtcopy;
+ blen -= amtcopy;
+ }
+
+out:
+ buffer->buf_retlen = bptr - buffer->buf_ptr;
+
+ return res;
+}
+
+
+/* *********************************************************************
+ * usbdisk_ioctl(ctx,buffer)
+ *
+ * Process device I/O control requests for the IDE device.
+ *
+ * Input parameters:
+ * ctx - device context
+ * buffer - buffer descriptor
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+static int usbdisk_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
+{
+ usbdisk_t *softc = ctx->dev_softc;
+ unsigned int *info = (unsigned int *) buffer->buf_ptr;
+ unsigned long long *linfo = (unsigned long long *) buffer->buf_ptr;
+ blockdev_info_t *devinfo;
+
+ switch ((int)buffer->buf_ioctlcmd) {
+ case IOCTL_BLOCK_GETBLOCKSIZE:
+ *info = softc->usbdisk_sectorsize;
+ break;
+ case IOCTL_BLOCK_GETTOTALBLOCKS:
+ *linfo = softc->usbdisk_ttlsect;
+ break;
+ case IOCTL_BLOCK_GETDEVTYPE:
+ devinfo = (blockdev_info_t *) buffer->buf_ptr;
+ devinfo->blkdev_totalblocks = softc->usbdisk_ttlsect;
+ devinfo->blkdev_blocksize = softc->usbdisk_sectorsize;
+ devinfo->blkdev_devtype = softc->usbdisk_devtype;
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+/* *********************************************************************
+ * usbdisk_close(ctx)
+ *
+ * Close the I/O device.
+ *
+ * Input parameters:
+ * ctx - device context
+ *
+ * Return value:
+ * 0 if ok, else error code
+ ********************************************************************* */
+
+static int usbdisk_close(cfe_devctx_t *ctx)
+{
+ /* usbdisk_t *softc = ctx->dev_softc; */
+
+ return 0;
+}
+
+
+#endif
diff --git a/cfe/cfe/usb/usbserial.c b/cfe/cfe/usb/usbserial.c
new file mode 100644
index 0000000..737d8b4
--- /dev/null
+++ b/cfe/cfe/usb/usbserial.c
@@ -0,0 +1,713 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * USB Serial Port Driver File: usbserial.c
+ *
+ * This device can talk to a few of those usb->serial converters
+ * out there.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#ifndef _CFE_
+#include <stdio.h>
+#include <time.h>
+#include <memory.h>
+#include <stdint.h>
+#include "usbhack.h"
+#else
+#include "lib_types.h"
+#include "lib_string.h"
+#include "lib_printf.h"
+#include "cfe_iocb.h"
+#include "cfe_device.h"
+#include "cfe_ioctl.h"
+#include "cfe_console.h"
+#include "bsp_config.h"
+#endif
+
+#include "lib_malloc.h"
+#include "lib_queue.h"
+#include "usbchap9.h"
+#include "usbd.h"
+
+/* *********************************************************************
+ * Constants
+ ********************************************************************* */
+
+#define USER_FIFOSIZE 256
+
+/* *********************************************************************
+ * Structures
+ ********************************************************************* */
+
+typedef struct usbser_linedata_s {
+ uint8_t dLineDataBaud0,dLineDataBaud1,dLineDataBaud2,dLineDataBaud3;
+ uint8_t bLineDataStopBits; /* 0=1, 1=1.5, 2=2 */
+ uint8_t bLineDataParity; /* 0=none, 1=odd, 2=even, 3=mark, 4=space */
+ uint8_t bLineDataBits; /* 5,6,7,8 */
+} usbser_linedata_t;
+
+
+/* *********************************************************************
+ * Macros
+ ********************************************************************* */
+
+#define GETDWFIELD(s,f) ((uint32_t)((s)->f##0) | ((uint32_t)((s)->f##1) << 8) | \
+ ((uint32_t)((s)->f##2) << 16) | ((uint32_t)((s)->f##3) << 24))
+#define PUTDWFIELD(s,f,v) (s)->f##0 = (v & 0xFF); \
+ (s)->f##1 = ((v)>>8 & 0xFF); \
+ (s)->f##2 = ((v)>>16 & 0xFF); \
+ (s)->f##3 = ((v)>>24 & 0xFF);
+
+
+
+/* *********************************************************************
+ * Forward Definitions
+ ********************************************************************* */
+
+static int usbserial_attach(usbdev_t *dev,usb_driver_t *drv);
+static int usbserial_detach(usbdev_t *dev);
+
+#ifdef _CFE_
+static void usb_uart_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr);
+
+static int usb_uart_open(cfe_devctx_t *ctx);
+static int usb_uart_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int usb_uart_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
+static int usb_uart_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int usb_uart_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int usb_uart_close(cfe_devctx_t *ctx);
+
+const static cfe_devdisp_t usb_uart_dispatch = {
+ usb_uart_open,
+ usb_uart_read,
+ usb_uart_inpstat,
+ usb_uart_write,
+ usb_uart_ioctl,
+ usb_uart_close,
+ NULL,
+ NULL
+};
+
+const cfe_driver_t usb_uart = {
+ "USB UART",
+ "uart",
+ CFE_DEV_SERIAL,
+ &usb_uart_dispatch,
+ usb_uart_probe
+};
+
+typedef struct usb_uart_s {
+ int uart_unit;
+ int uart_speed;
+ int uart_flowcontrol;
+} usb_uart_t;
+
+#define USBUART_MAXUNITS 4
+static usbdev_t *usbuart_units[USBUART_MAXUNITS];
+#endif
+
+
+/* *********************************************************************
+ * Structures
+ ********************************************************************* */
+
+typedef struct usbserial_softc_s {
+ int user_inpipe;
+ int user_outpipe;
+ int user_outmps;
+ int user_intpipe;
+ uint8_t user_inbuf[USER_FIFOSIZE];
+ int user_inbuf_in;
+ int user_inbuf_out;
+ uint8_t *user_devinbuf;
+ int user_devinbufsize;
+ int user_unit;
+ uint8_t *user_intbuf;
+ usbser_linedata_t user_linedata;
+} usbserial_softc_t;
+
+usb_driver_t usbserial_driver = {
+ "USB Serial Port",
+ usbserial_attach,
+ usbserial_detach
+};
+
+usbdev_t *usbserial_dev = NULL;
+
+
+#if 0
+/* *********************************************************************
+ * usbserial_get_linedata(dev,linedata)
+ *
+ * Request line data from the device.
+ *
+ * Input parameters:
+ * dev - USB device
+ * linedata - pointer to structure
+ *
+ * Return value:
+ * # of bytes returned
+ * <0 if error
+ ********************************************************************* */
+
+static int usbserial_get_linedata(usbdev_t *dev,usbser_linedata_t *ldata)
+{
+ uint8_t *respbuf;
+ int res;
+
+ respbuf = KMALLOC(32,0);
+
+ res = usb_std_request(dev,0xA1,0x21,0,0,respbuf,sizeof(usbser_linedata_t));
+
+ KFREE(respbuf);
+
+ if ((res >= 0) && ldata) memcpy(ldata,respbuf,sizeof(usbser_linedata_t));
+
+ return res;
+}
+#endif
+
+/* *********************************************************************
+ * usbserial_set_linedata(dev,linedata)
+ *
+ * Set line data to the device.
+ *
+ * Input parameters:
+ * dev - USB device
+ * linedata - pointer to structure
+ *
+ * Return value:
+ * # of bytes returned
+ * <0 if error
+ ********************************************************************* */
+
+static int usbserial_set_linedata(usbdev_t *dev,usbser_linedata_t *ldata)
+{
+ int res;
+
+ /*
+ * Send request to device.
+ */
+
+ res = usb_std_request(dev,0x21,0x20,0,0,(uint8_t *) ldata,sizeof(usbser_linedata_t));
+
+ return res;
+}
+
+#if 0
+/* *********************************************************************
+ * usbserial_song_and_dance(usbdev_t *dev)
+ *
+ * Magic incantations from using the CATC on this device.
+ *
+ * Input parameters:
+ * dev
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+
+static int usbserial_song_and_dance(usbdev_t *dev)
+{
+ int res;
+ char databuf[1];
+
+ res = usb_std_request(dev,0xc0,0x01,0x8484,0,databuf,1); /* READ */
+
+ res = usb_std_request(dev,0x40,0x01,0x0404,0,NULL,0); /* WRITE */
+
+ res = usb_std_request(dev,0xc0,0x01,0x8484,0,databuf,1); /* READ */
+ res = usb_std_request(dev,0xc0,0x01,0x8383,0,databuf,1); /* READ */
+ res = usb_std_request(dev,0xc0,0x01,0x8484,0,databuf,1); /* READ */
+
+ res = usb_std_request(dev,0x40,0x01,0x0404,1,NULL,0); /* WRITE */
+
+ res = usb_std_request(dev,0xc0,0x01,0x8484,0,databuf,1); /* READ */
+ res = usb_std_request(dev,0xc0,0x01,0x8383,0,databuf,1); /* READ */
+
+ res = usb_std_request(dev,0x40,0x01,0x0,1, NULL,0); /* WRITE */
+ res = usb_std_request(dev,0x40,0x01,0x1,0xC0,NULL,0); /* WRITE */
+ res = usb_std_request(dev,0x40,0x01,0x2,4, NULL,0); /* WRITE */
+
+ return 0;
+}
+#endif
+
+/* *********************************************************************
+ * usbserial_tx_data(dev,buffer,len)
+ *
+ * Synchronously transmit data via the USB.
+ *
+ * Input parameters:
+ * dev - device pointer
+ * buffer,len - data we want to send
+ *
+ * Return value:
+ * number of bytes sent.
+ ********************************************************************* */
+
+static int usbserial_tx_data(usbdev_t *dev,uint8_t *buffer,int len)
+{
+ uint8_t *bptr;
+ usbreq_t *ur;
+ usbserial_softc_t *softc = (dev->ud_private);
+ int res;
+
+ bptr = KMALLOC(len,0);
+
+ memcpy(bptr,buffer,len);
+
+ ur = usb_make_request(dev,softc->user_outpipe,bptr,len,UR_FLAG_OUT);
+ res = usb_sync_request(ur);
+
+// printf("Data sent, status=%d, xferred=%d\n",res,ur->ur_xferred);
+
+ res = ur->ur_xferred;
+
+ usb_free_request(ur);
+
+ KFREE(bptr);
+
+ return res;
+}
+
+/* *********************************************************************
+ * usbserial_int_callback(ur)
+ *
+ * Callback routine for the interrupt request, for devices
+ * that have an interrupt pipe. We ignore this.
+ *
+ * Input parameters:
+ * ur - usb request
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static int usbserial_int_callback(usbreq_t *ur)
+{
+// int idx;
+
+ /*
+ * Check to see if the request was cancelled by someone
+ * deleting our endpoint.
+ */
+
+ if (ur->ur_status == 0xFF) {
+ usb_free_request(ur);
+ return 0;
+ }
+
+// printf("serial int msg: ");
+// for (idx = 0; idx < ur->ur_xferred; idx++) printf("%02X ",ur->ur_buffer[idx]);
+// printf("\n");
+
+ usb_queue_request(ur);
+
+ return 0;
+
+}
+
+
+/* *********************************************************************
+ * usbserial_rx_callback(ur)
+ *
+ * Callback routine for the regular data pipe.
+ *
+ * Input parameters:
+ * ur - usb request
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static int usbserial_rx_callback(usbreq_t *ur)
+{
+ int idx;
+ int iptr;
+ usbserial_softc_t *user = (ur->ur_dev->ud_private);
+
+ /*
+ * Check to see if the request was cancelled by someone
+ * deleting our endpoint.
+ */
+
+ if (ur->ur_status == 0xFF) {
+ usb_free_request(ur);
+ return 0;
+ }
+
+ /*
+ * Add characters to the receive fifo
+ */
+
+ for (idx = 0; idx < ur->ur_xferred; idx++) {
+ iptr = (user->user_inbuf_in + 1) & (USER_FIFOSIZE-1);
+ if (iptr == user->user_inbuf_out) break; /* overflow */
+ user->user_inbuf[user->user_inbuf_in] = ur->ur_buffer[idx];
+ user->user_inbuf_in = iptr;
+ }
+
+ /*
+ * Requeue the request
+ */
+
+ usb_queue_request(ur);
+
+ return 0;
+
+}
+
+
+/* *********************************************************************
+ * usbserial_attach(dev,drv)
+ *
+ * This routine is called when the bus scan stuff finds a mass-storage
+ * device. We finish up the initialization by configuring the
+ * device and allocating our softc here.
+ *
+ * Input parameters:
+ * dev - usb device, in the "addressed" state.
+ * drv - the driver table entry that matched
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+
+static int usbserial_attach(usbdev_t *dev,usb_driver_t *drv)
+{
+ usb_config_descr_t *cfgdscr = dev->ud_cfgdescr;
+ usb_endpoint_descr_t *epdscr;
+ usb_endpoint_descr_t *indscr = NULL;
+ usb_endpoint_descr_t *outdscr = NULL;
+ usb_endpoint_descr_t *intdscr = NULL;
+ usb_interface_descr_t *ifdscr;
+ usbser_linedata_t *ldata;
+ usbserial_softc_t *softc;
+ usbreq_t *ur;
+ int idx;
+
+ dev->ud_drv = drv;
+
+ softc = KMALLOC(sizeof(usbserial_softc_t),0);
+ memset(softc,0,sizeof(usbserial_softc_t));
+ dev->ud_private = softc;
+
+ ifdscr = usb_find_cfg_descr(dev,USB_INTERFACE_DESCRIPTOR_TYPE,0);
+ if (ifdscr == NULL) {
+ printf("Could not get interface descriptor\n");
+ return -1;
+ }
+
+ for (idx = 0; idx < ifdscr->bNumEndpoints; idx++) {
+ epdscr = usb_find_cfg_descr(dev,USB_ENDPOINT_DESCRIPTOR_TYPE,idx);
+
+ if ((epdscr->bmAttributes & USB_ENDPOINT_TYPE_MASK) ==
+ USB_ENDPOINT_TYPE_INTERRUPT) {
+ intdscr = epdscr;
+ }
+ else if (USB_ENDPOINT_DIR_OUT(epdscr->bEndpointAddress)) {
+ outdscr = epdscr;
+ }
+ else {
+ indscr = epdscr;
+ }
+ }
+
+
+ if (!indscr || !outdscr) {
+ printf("IN or OUT endpoint descriptors are missing\n");
+ /*
+ * Could not get descriptors, something is very wrong.
+ * Leave device addressed but not configured.
+ */
+ return 0;
+ }
+
+ /*
+ * Choose the standard configuration.
+ */
+
+ usb_set_configuration(dev,cfgdscr->bConfigurationValue);
+
+ /*
+ * Open the pipes.
+ */
+
+ softc->user_inpipe = usb_open_pipe(dev,indscr);
+ softc->user_devinbufsize = GETUSBFIELD(indscr,wMaxPacketSize);
+ softc->user_devinbuf = KMALLOC(softc->user_devinbufsize,0);
+ softc->user_outpipe = usb_open_pipe(dev,outdscr);
+ softc->user_outmps = GETUSBFIELD(outdscr,wMaxPacketSize);
+ if (intdscr) {
+ softc->user_intpipe = usb_open_pipe(dev,intdscr);
+ }
+ else {
+ softc->user_intpipe = -1;
+ }
+
+ ur = usb_make_request(dev,softc->user_inpipe,softc->user_devinbuf,
+ softc->user_devinbufsize,
+ UR_FLAG_IN | UR_FLAG_SHORTOK);
+ ur->ur_callback = usbserial_rx_callback;
+ usb_queue_request(ur);
+
+
+ if (softc->user_intpipe) {
+ softc->user_intbuf = KMALLOC(32,0);
+ ur = usb_make_request(dev,softc->user_intpipe,softc->user_intbuf,
+ GETUSBFIELD(intdscr,wMaxPacketSize),
+ UR_FLAG_IN | UR_FLAG_SHORTOK);
+ ur->ur_callback = usbserial_int_callback;
+ usb_queue_request(ur);
+ }
+
+#ifdef _CFE_
+ softc->user_unit = -1;
+ for (idx = 0; idx < USBUART_MAXUNITS; idx++) {
+ if (usbuart_units[idx] == NULL) {
+ softc->user_unit = idx;
+ usbuart_units[idx] = dev;
+ break;
+ }
+ }
+
+ console_log("USBSERIAL: Unit %d connected",softc->user_unit);
+#endif
+
+// usbserial_song_and_dance(dev);
+
+ ldata = &(softc->user_linedata);
+ PUTDWFIELD(ldata,dLineDataBaud,115200);
+ ldata->bLineDataStopBits = 0;
+ ldata->bLineDataParity = 2;
+ ldata->bLineDataBits = 8;
+
+ usbserial_set_linedata(dev,ldata);
+// usbserial_get_linedata(dev,NULL);
+
+ usbserial_dev = dev;
+
+ return 0;
+}
+
+/* *********************************************************************
+ * usbserial_detach(dev)
+ *
+ * This routine is called when the bus scanner notices that
+ * this device has been removed from the system. We should
+ * do any cleanup that is required. The pending requests
+ * will be cancelled automagically.
+ *
+ * Input parameters:
+ * dev - usb device
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+
+static int usbserial_detach(usbdev_t *dev)
+{
+ usbserial_softc_t *softc;
+
+ softc = dev->ud_private;
+
+
+#ifdef _CFE_
+ console_log("USBSERIAL: USB unit %d disconnected",softc->user_unit);
+ if (softc->user_unit >= 0) usbuart_units[softc->user_unit] = NULL;
+#endif
+
+ if (softc) {
+ if (softc->user_devinbuf) KFREE(softc->user_devinbuf);
+ if (softc->user_intbuf) KFREE(softc->user_intbuf);
+ KFREE(softc);
+ }
+
+ return 0;
+}
+
+
+
+#ifdef _CFE_
+
+
+
+static void usb_uart_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr)
+{
+ usb_uart_t *softc;
+ char descr[80];
+
+ softc = (usb_uart_t *) KMALLOC(sizeof(usb_uart_t),0);
+
+ memset(softc,0,sizeof(usb_uart_t));
+
+ softc->uart_unit = (int)probe_a;
+
+ xsprintf(descr,"USB UART unit %d",(int)probe_a);
+
+ cfe_attach(drv,softc,NULL,descr);
+}
+
+
+static int usb_uart_open(cfe_devctx_t *ctx)
+{
+// usb_uart_t *softc = ctx->dev_softc;
+// int baudrate = CFG_SERIAL_BAUD_RATE;
+// usbdev_t *dev = usbuart_units[softc->uart_unit];
+
+ /*
+ * XXX call the uart setup here
+ */
+
+ return 0;
+}
+
+static int usb_uart_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ usb_uart_t *softc = ctx->dev_softc;
+ usbdev_t *dev = usbuart_units[softc->uart_unit];
+ usbserial_softc_t *user = dev->ud_private;
+ unsigned char *bptr;
+ int blen;
+
+ if (!dev) return 0;
+
+ bptr = buffer->buf_ptr;
+ blen = buffer->buf_length;
+
+ while ((blen > 0) && (user->user_inbuf_out != user->user_inbuf_in)) {
+ *bptr++ = user->user_inbuf[user->user_inbuf_out];
+ user->user_inbuf_out = (user->user_inbuf_out + 1) & (USER_FIFOSIZE-1);
+ blen--;
+ }
+
+ buffer->buf_retlen = buffer->buf_length - blen;
+ return 0;
+}
+
+static int usb_uart_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat)
+{
+ usb_uart_t *softc = ctx->dev_softc;
+ usbdev_t *dev = usbuart_units[softc->uart_unit];
+ usbserial_softc_t *user = dev->ud_private;
+
+ inpstat->inp_status = 0;
+
+ if (!dev) return 0;
+
+ inpstat->inp_status = (user->user_inbuf_in != user->user_inbuf_out);
+
+ return 0;
+}
+
+static int usb_uart_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ usb_uart_t *softc = ctx->dev_softc;
+ unsigned char *bptr;
+ int blen;
+ usbdev_t *dev = usbuart_units[softc->uart_unit];
+ usbserial_softc_t *user = dev->ud_private;
+
+ bptr = buffer->buf_ptr;
+ blen = buffer->buf_length;
+
+ if (!dev) {
+ buffer->buf_retlen = blen;
+ return 0;
+ }
+
+ if (blen > user->user_outmps) blen = user->user_outmps;
+
+ usbserial_tx_data(dev,bptr,blen);
+
+ buffer->buf_retlen = blen;
+ return 0;
+}
+
+static int usb_uart_ioctl(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ usb_uart_t *softc = ctx->dev_softc;
+ usbdev_t *dev = usbuart_units[softc->uart_unit];
+// usbserial_softc_t *user = dev->ud_private;
+
+ if (!dev) return -1;
+
+ unsigned int *info = (unsigned int *) buffer->buf_ptr;
+
+ switch ((int)buffer->buf_ioctlcmd) {
+ case IOCTL_SERIAL_GETSPEED:
+ *info = softc->uart_speed;
+ break;
+ case IOCTL_SERIAL_SETSPEED:
+ softc->uart_speed = *info;
+ /* NYI */
+ break;
+ case IOCTL_SERIAL_GETFLOW:
+ *info = softc->uart_flowcontrol;
+ break;
+ case IOCTL_SERIAL_SETFLOW:
+ softc->uart_flowcontrol = *info;
+ /* NYI */
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static int usb_uart_close(cfe_devctx_t *ctx)
+{
+// usb_uart_t *softc = ctx->dev_softc;
+
+ return 0;
+}
+
+
+
+#endif
+