diff options
Diffstat (limited to 'cfe/cfe/usb/usbmain.c')
-rw-r--r-- | cfe/cfe/usb/usbmain.c | 367 |
1 files changed, 367 insertions, 0 deletions
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; +} |