summaryrefslogtreecommitdiffstats
path: root/cfe/cfe/usb/usbeth.c
diff options
context:
space:
mode:
Diffstat (limited to 'cfe/cfe/usb/usbeth.c')
-rw-r--r--cfe/cfe/usb/usbeth.c850
1 files changed, 850 insertions, 0 deletions
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
+};
+