1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * USB Ethernet File: dev_usb_asix.c 5 * 6 * Driver for USB Ethernet devices using the ASIX AX8817 chip. 7 * 8 ********************************************************************* 9 * 10 * Copyright 2000,2001,2005 11 * Broadcom Corporation. All rights reserved. 12 * 13 * This software is furnished under license and may be used and 14 * copied only in accordance with the following terms and 15 * conditions. Subject to these conditions, you may download, 16 * copy, install, use, modify and distribute modified or unmodified 17 * copies of this software in source and/or binary form. No title 18 * or ownership is transferred hereby. 19 * 20 * 1) Any source code used, modified or distributed must reproduce 21 * and retain this copyright notice and list of conditions as 22 * they appear in the source file. 23 * 24 * 2) No right is granted to use any trade name, trademark, or 25 * logo of Broadcom Corporation. Neither the "Broadcom 26 * Corporation" name nor any trademark or logo of Broadcom 27 * Corporation may be used to endorse or promote products 28 * derived from this software without the prior written 29 * permission of Broadcom Corporation. 30 * 31 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR 32 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED 33 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 34 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT 35 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN 36 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, 37 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 38 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 39 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 40 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 41 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 42 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF 43 * THE POSSIBILITY OF SUCH DAMAGE. 44 ********************************************************************* */ 45 46/* ********************************************************************* 47 * USB-Ethernet driver - CFE Network Layer Interfaces 48 ********************************************************************* */ 49 50#include "cfe.h" 51 52#include "usbd.h" 53#include "usbeth.h" 54 55/* XXX Move to usbeth.h */ 56/* ************************************** 57 * ASIX AX8817 adapter 58 ************************************** */ 59 60#define ASIX_MII_SWOP_CMD 0x06 61#define ASIX_MII_READ_CMD 0x07 62#define ASIX_MII_WRITE_CMD 0x08 63#define ASIX_MII_HWOP_CMD 0x0a 64#define ASIX_RXCTL_CMD 0x10 65#define ASIX_IPG1_CMD 0x12 66#define ASIX_IPG2_CMD 0x13 67#define ASIX_IPG3_CMD 0x14 68#define ASIX_MAC_ADDR_CMD 0x17 69#define ASIX_PHYID_CMD 0x19 70#define ASIX_MED_WRITE_CMD 0x1b 71#define ASIX_GPIO_WRITE_CMD 0x1f 72 73 74#if 0 75#define USBETH_TRACE( x, y ... ) xprintf( x, ##y ) 76#else 77#define USBETH_TRACE( x, y ... ) 78#endif 79 80#define FAIL -1 81 82#define USB_MALLOC_VALUE 32 83 84 85/****************************************************************************** 86 Debug functions 87******************************************************************************/ 88 89#ifndef USBETH_DEBUG 90#define USBETH_DEBUG 0 91#endif 92 93 94#if USBETH_DEBUG 95static void hexdump( unsigned char *src, int srclen, int rowlen, int rows ) 96{ 97 unsigned char *rowptr; 98 unsigned char *srcstp; 99 unsigned char *byteptr; 100 101 srcstp = src + srclen; 102 103 for( rowptr = src; rowptr < src + rowlen * rows; rowptr += rowlen ) { 104 for( byteptr = rowptr; byteptr < rowptr + rowlen && byteptr < srcstp; byteptr++ ) { 105 xprintf( "%2X ", *byteptr ); 106 } 107 xprintf( "\n" ); 108 } 109 xprintf( "\n" ); 110} 111#else 112#define hexdump(src,srclen,rowlen,rows) ((void)0) 113#endif 114 115 116/* ********************************************************************* 117 * Interface functions for USB-Ethernet adapters 118 ********************************************************************* */ 119 120enum { VEN_NONE, HAWKING, NETGEAR }; 121static char *VENDOR_NAMES[] = { 122 "?", "Hawking", "Netgear", "Yikes!" 123}; 124 125static const int ID_TBL[] = { 126 0x0846, 0x1040, NETGEAR, /* Netgear FA120 */ 127 0x07b8, 0x420a, HAWKING, /* Hawking UF200 */ 128 -1 129}; 130 131typedef struct asix_softc_s 132{ 133 usbdev_t *dev; 134 int bulk_inpipe; 135 int bulk_outpipe; 136 int dev_id; 137 int ven_code; 138 uint8_t mac_addr[6]; 139 usbreq_t *rx_ur; 140 uint8_t rxbuf[1600]; /* artbitrary but enough for ethernet packet */ 141} asix_softc_t; 142 143 144/* ************************************** 145 * ASIX AX8817x I/F Functions 146 ************************************** */ 147 148static int asix_send_eth_frame( void *ctx, hsaddr_t buf, int len ); 149static int asix_get_eth_frame( void *ctx, hsaddr_t buf ); 150static int asix_data_rx( void *ctx ); 151static int asix_get_dev_addr( void *ctx, hsaddr_t mac_addr ); 152 153static usbeth_disp_t usbeth_asix = { 154 asix_get_eth_frame, 155 asix_data_rx, 156 asix_send_eth_frame, 157 asix_get_dev_addr 158}; 159 160 161static int asix_get_reg( usbdev_t *dev, uint8_t cmd, int16_t val, int16_t index, uint8_t *buf, int16_t len ) 162{ 163 return usb_std_request( dev, (USBREQ_TYPE_VENDOR | USBREQ_DIR_IN), 164 cmd, val, index, buf, len ); 165} 166 167static int asix_set_reg( usbdev_t *dev, uint8_t cmd, int16_t val, int16_t index, uint8_t *buf, int16_t len ) 168{ 169 return usb_std_request( dev, (USBREQ_TYPE_VENDOR | USBREQ_DIR_OUT), 170 cmd, val, index, buf, len ); 171} 172 173static int asix_get_mac_addr( usbdev_t *dev, uint8_t *mac_addr ) 174{ 175 return asix_get_reg( dev, ASIX_MAC_ADDR_CMD, 0, 0, mac_addr, 6 ); 176} 177 178static int asix_init_device( asix_softc_t *softc ) 179{ 180 usb_device_descr_t dev_desc; 181 uint16_t vendor_id, device_id; 182 const int *ptr=ID_TBL; 183 184 /* find out which device is connected */ 185 usb_get_device_descriptor( softc->dev, &dev_desc, 0 ); 186 vendor_id = (dev_desc.idVendorHigh << 8) + dev_desc.idVendorLow; 187 device_id = (dev_desc.idProductHigh << 8) + dev_desc.idProductLow; 188 xprintf( "USB device: vendor id %04x, device id %04x\n", 189 vendor_id, device_id ); 190 191 while( *ptr != -1 ) { 192 if( (vendor_id == ptr[0]) && (device_id == ptr[1]) ) { 193 softc->dev_id = ptr[2]; 194 softc->ven_code = ptr[3]; 195 break; 196 } 197 ptr += 4; 198 } 199 if( *ptr == -1 ) { 200 xprintf( "Unrecognized USB-Ethernet device\n" ); 201 return -1; 202 } 203 204 /* Read the adapter's MAC addr */ 205 asix_get_mac_addr( softc->dev, softc->mac_addr ); 206 207 /* display adapter info */ 208 xprintf( "%s USB-Ethernet Adapter (%a)\n", 209 VENDOR_NAMES[softc->ven_code], softc->mac_addr); 210 211 return 0; 212} 213 214static int asix_get_dev_addr( void *ctx, hsaddr_t mac_addr ) 215{ 216 asix_softc_t *softc = (asix_softc_t *) ctx; 217 218 hs_memcpy_to_hs( mac_addr, softc->mac_addr, 6 ); 219 return 0; 220} 221 222static void asix_queue_rx( asix_softc_t *softc ) 223{ 224 softc->rx_ur = usb_make_request(softc->dev, softc->bulk_inpipe, 225 softc->rxbuf, sizeof(softc->rxbuf), 226 (UR_FLAG_IN | UR_FLAG_SHORTOK)); 227 usb_queue_request(softc->rx_ur); 228} 229 230static int asix_data_rx( void *ctx ) 231{ 232 asix_softc_t *softc = (asix_softc_t *) ctx; 233 234 usb_poll(softc->dev->ud_bus); 235 return( !softc->rx_ur->ur_inprogress ); 236} 237 238static int asix_get_eth_frame( void *ctx, hsaddr_t buf ) 239{ 240 asix_softc_t *softc = (asix_softc_t *) ctx; 241 int len = 0; 242 243 if( !softc->rx_ur->ur_inprogress ) { 244 len = softc->rx_ur->ur_xferred; 245 hs_memcpy_to_hs( buf, softc->rxbuf, len ); 246 usb_free_request(softc->rx_ur); 247 asix_queue_rx( softc ); 248 } 249 else 250 xprintf( "Bulk data is not available yet!\n" ); 251 252 return( len ); 253} 254 255static int asix_send_eth_frame( void *ctx, hsaddr_t buf, int len ) 256{ 257 asix_softc_t *softc = (asix_softc_t *) ctx; 258 usbreq_t *ur; 259 int txlen = len; 260 unsigned char *txbuf; 261 262 txbuf = KMALLOC(txlen, USB_MALLOC_VALUE); 263 hs_memcpy_from_hs( txbuf, buf, txlen ); 264 ur = usb_make_request(softc->dev, softc->bulk_outpipe, 265 txbuf, txlen, UR_FLAG_OUT); 266 usb_sync_request(ur); 267 usb_free_request(ur); 268 KFREE(txbuf); 269 270 return( len ); 271} 272 273static void asix_open_device( asix_softc_t *softc ) 274{ 275 usbdev_t *dev = softc->dev; 276 uint8_t data[2]; 277 int16_t phyid; 278 279 asix_set_reg( dev, ASIX_MII_SWOP_CMD, 0, 0, NULL, 0 ); 280 asix_get_reg( dev, ASIX_PHYID_CMD, 0, 0, data, 2 ); 281 282 /* UF200 seems to need a GPIO settings */ 283 asix_set_reg( dev, ASIX_GPIO_WRITE_CMD, 0x11, 0, NULL, 0 ); 284 asix_set_reg( dev, ASIX_GPIO_WRITE_CMD, 0x13, 0, NULL, 0 ); 285 asix_set_reg( dev, ASIX_GPIO_WRITE_CMD, 0x0c, 0, NULL, 0 ); 286 287 phyid = data[1]; 288 data[0] = 0; data[1] = 0; 289 asix_set_reg( dev, ASIX_MII_WRITE_CMD, phyid, 0, data, 2 ); 290 data[1] = 0x80; 291 asix_set_reg( dev, ASIX_MII_WRITE_CMD, phyid, 0, data, 2 ); 292 asix_set_reg( dev, ASIX_MED_WRITE_CMD, 6, 0, NULL, 0 ); 293 asix_set_reg( dev, ASIX_IPG1_CMD, 0x15, 0, NULL, 0 ); 294 asix_set_reg( dev, ASIX_IPG2_CMD, 0x0c, 0, NULL, 0 ); 295 asix_set_reg( dev, ASIX_IPG3_CMD, 0x12, 0, NULL, 0 ); 296 data[0] = 0x01; data[1] = 0x05; 297 asix_set_reg( dev, ASIX_MII_WRITE_CMD, phyid, 4, data, 2 ); 298 data[0] = 0; data[1] = 0x12; 299 asix_set_reg( dev, ASIX_MII_WRITE_CMD, phyid, 0, data, 2 ); 300 asix_set_reg( dev, ASIX_MII_HWOP_CMD, 0, 0, NULL, 0 ); 301 asix_set_reg( dev, ASIX_RXCTL_CMD, 0x81, 0, NULL, 0 ); 302 303 /* kick start the receive */ 304 asix_queue_rx( softc ); 305} 306 307static void asix_close_device( asix_softc_t *softc ) 308{ 309 /* disable adapter from receiving packets */ 310 asix_set_reg( softc->dev, ASIX_RXCTL_CMD, 0, 0, NULL, 0 ); 311} 312 313 314/* ********************************************************************* 315 * CFE-USB interfaces 316 ********************************************************************* */ 317 318/* ********************************************************************* 319 * asix_attach(dev,drv) 320 * 321 * This routine is called when the bus scan stuff finds a usb-ethernet 322 * device. We finish up the initialization by configuring the 323 * device and allocating our softc here. 324 * 325 * Input parameters: 326 * dev - usb device, in the "addressed" state. 327 * drv - the driver table entry that matched 328 * 329 * Return value: 330 * 0 331 ********************************************************************* */ 332 333const cfe_driver_t usbasix_driver; /* forward declaration */ 334 335static int asix_attach(usbdev_t *dev,usb_driver_t *drv) 336{ 337 usb_config_descr_t *cfgdscr = dev->ud_cfgdescr; 338 usb_endpoint_descr_t *epdscr; 339 usb_endpoint_descr_t *indscr = NULL; 340 usb_endpoint_descr_t *outdscr = NULL; 341 usb_interface_descr_t *ifdscr; 342 asix_softc_t *softc; 343 int idx; 344 345 dev->ud_drv = drv; 346 347 softc = (asix_softc_t *) KMALLOC( sizeof(asix_softc_t), USB_MALLOC_VALUE ); 348 if( softc == NULL ) { 349 xprintf( "Failed to allocate softc memory.\n" ); 350 return -1; 351 } 352 memset( softc, 0, sizeof(asix_softc_t) ); 353 dev->ud_private = softc; 354 softc->dev = dev; 355 356 ifdscr = usb_find_cfg_descr(dev,USB_INTERFACE_DESCRIPTOR_TYPE,0); 357 if (ifdscr == NULL) { 358 xprintf("USBETH: ERROR...no interace descriptor\n"); 359 return -1; 360 } 361 362 for (idx = 0; idx < 3; idx++) { 363 epdscr = usb_find_cfg_descr(dev,USB_ENDPOINT_DESCRIPTOR_TYPE,idx); 364 if((epdscr->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK) { 365 if (USB_ENDPOINT_DIR_OUT(epdscr->bEndpointAddress)) 366 outdscr = epdscr; 367 else 368 indscr = epdscr; 369 } 370 } 371 372 if (!indscr || !outdscr) { 373 /* 374 * Could not get descriptors, something is very wrong. 375 * Leave device addressed but not configured. 376 */ 377 xprintf("USBETH: ERROR...bulk endpoint descriptor(s) missing\n"); 378 return -1; 379 } 380 381 /* Choose the standard configuration. */ 382 usb_set_configuration(dev,cfgdscr->bConfigurationValue); 383 384 /* Quit if not able to initialize the device */ 385 if (asix_init_device(softc) < 0) 386 return -1; 387 388 /* Open the pipes. */ 389 softc->bulk_inpipe = usb_open_pipe(dev,indscr); 390 softc->bulk_outpipe = usb_open_pipe(dev,outdscr); 391 392 /* Register the device */ 393 usbeth_register(&usbeth_asix, softc); 394 395 /* Open the device */ 396 asix_open_device( softc ); 397 398 return 0; 399} 400 401/* ********************************************************************* 402 * asix_detach(dev) 403 * 404 * This routine is called when the bus scanner notices that 405 * this device has been removed from the system. We should 406 * do any cleanup that is required. The pending requests 407 * will be cancelled automagically. 408 * 409 * Input parameters: 410 * dev - usb device 411 * 412 * Return value: 413 * 0 414 ********************************************************************* */ 415 416static int asix_detach(usbdev_t *dev) 417{ 418 asix_softc_t *softc = (asix_softc_t *) dev->ud_private; 419 420 if (softc != NULL) { 421 usbeth_unregister( softc ); 422 asix_close_device( softc ); 423 dev->ud_private = NULL; 424 softc->dev = NULL; 425 KFREE(softc); 426 } 427 428 return 0; 429} 430 431/* CFE USB device interface structure */ 432usb_driver_t usbeth_driver = 433{ 434 "Ethernet Device", 435 asix_attach, 436 asix_detach 437}; 438