1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * USB Ethernet File: dev_usb_rtek.c 5 * 6 * Driver for USB Ethernet devices using Realtek RTL8150 chip. 7 * 8 ********************************************************************* 9 * 10 * Copyright 2000,2001,2002,2003,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 22 * as 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. The "Broadcom Corporation" 26 * name may not be used to endorse or promote products derived 27 * from this software without the prior written permission of 28 * Broadcom Corporation. 29 * 30 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR 31 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED 32 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 33 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT 34 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN 35 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, 36 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 37 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 38 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 39 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 40 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 41 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF 42 * THE POSSIBILITY OF SUCH DAMAGE. 43 ********************************************************************* */ 44 45/* ********************************************************************* 46 * USB-Ethernet driver - CFE Network Layer Interfaces 47 ********************************************************************* */ 48 49#include "cfe.h" 50 51#include "usbd.h" 52#include "usbeth.h" 53 54#if 0 55#define USBETH_TRACE( x, y ... ) xprintf( x, ##y ) 56#else 57#define USBETH_TRACE( x, y ... ) ((void)0) 58#endif 59 60#define FAIL -1 61 62#define CACHE_ALIGN 32 /* XXX place holder, big enough to now. */ 63#define ALIGN(n,align) (((n)+((align)-1)) & ~((align)-1)) 64 65#define usb_dma_alloc(n) (KMALLOC(ALIGN((n),CACHE_ALIGN),CACHE_ALIGN)) 66#define usb_dma_free(p) (KFREE(p)) 67 68/****************************************************************************** 69 Debug functions 70******************************************************************************/ 71 72#ifndef USBETH_DEBUG 73#define USBETH_DEBUG 0 74#endif 75 76#if USBETH_DEBUG 77static void hexdump( unsigned char *src, int srclen, int rowlen, int rows ) 78{ 79 unsigned char *rowptr; 80 unsigned char *srcstp; 81 unsigned char *byteptr; 82 83 srcstp = src + srclen; 84 85 for( rowptr = src; rowptr < src + rowlen * rows; rowptr += rowlen ) { 86 for( byteptr = rowptr; byteptr < rowptr + rowlen && byteptr < srcstp; byteptr++ ) { 87 xprintf( "%2X ", *byteptr ); 88 } 89 xprintf( "\n" ); 90 } 91 xprintf( "\n" ); 92} 93#else 94#define hexdump(src,srclen,rowlen,rows) ((void)0) 95#endif 96 97 98/* ********************************************************************* 99 * Interface functions for USB-Ethernet adapters 100 ********************************************************************* */ 101 102enum { VEN_NONE, LINKSYS_100M }; 103static const char *VENDOR_NAMES[] = { 104 "?", "Linksys-100M", "Yikes!" 105}; 106 107static const int ID_TBL[] = { 108 0x0BDA, 0x8150, LINKSYS_100M, 109 -1 110}; 111 112typedef struct rtek_softc_s { 113 usbdev_t *dev; 114 int bulk_inpipe; 115 int bulk_outpipe; 116 int ven_code; 117 uint8_t mac_addr[6]; 118 usbreq_t *rx_ur; 119 uint8_t rxbuf[1600]; /* arbitrary but enough for ethernet packet */ 120} rtek_softc_t; 121 122 123/* ************************************** 124 * REALTEK RTL8150 I/F Functions. 125 ************************************** */ 126 127static int rtek_send_eth_frame( void *ctx, hsaddr_t buf, int len ); 128static int rtek_get_eth_frame( void *ctx, hsaddr_t buf ); 129static int rtek_data_rx( void *ctx ); 130static int rtek_get_dev_addr( void *ctx, hsaddr_t mac_addr ); 131 132static usbeth_disp_t usbeth_rtek = { 133 rtek_get_eth_frame, 134 rtek_data_rx, 135 rtek_send_eth_frame, 136 rtek_get_dev_addr 137}; 138 139 140static int rtek_get_reg( usbdev_t *dev, int16_t reg, uint8_t *val, int16_t len ) 141{ 142 return usb_std_request( dev, (USBREQ_TYPE_VENDOR | USBREQ_DIR_IN), 143 RTEK_REG_ACCESS, reg, 0, val, len ); 144} 145 146static int rtek_set_reg( usbdev_t *dev, int16_t reg, int8_t val ) 147{ 148 uint8_t data[1]; 149 150 data[0] = val; 151 return usb_std_request( dev, (USBREQ_TYPE_VENDOR | USBREQ_DIR_OUT), 152 RTEK_REG_ACCESS, reg, 0, data, 1 ); 153} 154 155static int rtek_get_mac_addr( usbdev_t *dev, uint8_t *mac_addr ) 156{ 157 return rtek_get_reg( dev, R_RTEK_MAC, mac_addr, 6 ); 158} 159 160static int rtek_init_device( rtek_softc_t *softc ) 161{ 162 usb_device_descr_t dev_desc; 163 uint16_t vendor_id, product_id; 164 const int *ptr=ID_TBL; 165 int i; 166 usbdev_t *dev = softc->dev; 167 uint8_t val; 168 169 /* find out which device is connected */ 170 usb_get_device_descriptor( softc->dev, &dev_desc, 0 ); 171 vendor_id = (dev_desc.idVendorHigh << 8) + dev_desc.idVendorLow; 172 product_id = (dev_desc.idProductHigh << 8) + dev_desc.idProductLow; 173 174 while( *ptr != -1 ) { 175 if( (vendor_id == ptr[0]) && (product_id == ptr[1]) ) { 176 softc->ven_code = ptr[2]; 177 break; 178 } 179 ptr += 3; 180 } 181 if( *ptr == -1 ) { 182 xprintf( "Unrecognized Realtek USB-Ethernet device\n" ); 183 return -1; 184 } 185 186 /* Reset the adapter */ 187 rtek_set_reg( dev, R_RTEK_CMD, RTEK_RESET ); 188 for( i = 0; i < 10; ++i ) { 189 rtek_get_reg( dev, R_RTEK_CMD, &val, 1 ); 190 if( !(val & RTEK_RESET) ) 191 break; 192 usb_delay_ms( NULL, 1 ); 193 } 194 195 /* Autoload the internal registers */ 196 rtek_set_reg( dev, R_RTEK_CMD, RTEK_AUTOLOAD ); 197 for( i = 0; i < 50; ++i ) { 198 rtek_get_reg( dev, R_RTEK_CMD, &val, 1 ); 199 if( !(val & RTEK_AUTOLOAD) ) 200 break; 201 usb_delay_ms( NULL, 1 ); 202 } 203 204 /* Read the adapter's MAC addr */ 205 rtek_get_mac_addr( 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 rtek_get_dev_addr( void *ctx, hsaddr_t mac_addr ) 215{ 216 rtek_softc_t *softc = (rtek_softc_t *) ctx; 217 hs_memcpy_to_hs( mac_addr, softc->mac_addr, 6 ); 218 return 0; 219} 220 221static void rtek_queue_rx( rtek_softc_t *softc ) 222{ 223 softc->rx_ur = usb_make_request(softc->dev, softc->bulk_inpipe, 224 softc->rxbuf, sizeof(softc->rxbuf), 225 (UR_FLAG_IN | UR_FLAG_SHORTOK)); 226 usb_queue_request(softc->rx_ur); 227} 228 229static int rtek_data_rx( void *ctx ) 230{ 231 rtek_softc_t *softc = (rtek_softc_t *) ctx; 232 usb_poll(softc->dev->ud_bus); 233 return( !softc->rx_ur->ur_inprogress ); 234} 235 236static int rtek_get_eth_frame( void *ctx, hsaddr_t buf ) 237{ 238 int len = 0; 239 rtek_softc_t *softc = (rtek_softc_t *) ctx; 240 uint8_t *rxbuf; 241 242 if( !softc->rx_ur->ur_inprogress ) { 243 rxbuf = softc->rxbuf; 244 len = softc->rx_ur->ur_xferred; 245 if (len > 0) { 246#if USBETH_DEBUG 247 xprintf( "Incoming packet :\n" ); 248 hexdump( rxbuf, len, 16, len / 16 + 1 ); 249#endif 250 hs_memcpy_to_hs( buf, rxbuf, len ); 251 } 252 usb_free_request(softc->rx_ur); 253 rtek_queue_rx( softc ); 254 } 255 else 256 xprintf( "Bulk data is not available yet!\n" ); 257 258 return( len ); 259} 260 261static int rtek_send_eth_frame( void *ctx, hsaddr_t buf, int len ) 262{ 263 rtek_softc_t *softc = (rtek_softc_t *) ctx; 264 usbreq_t *ur; 265 int txlen = len; 266 unsigned char *txbuf; 267 268 /* First some Realtek chip workarounds */ 269 if( txlen < 60 ) /* some strange limitation */ 270 txlen = 60; 271 else if( !(txlen % 64) ) /* to handle module 64 packets */ 272 ++txlen; 273 274 txbuf = usb_dma_alloc(txlen); 275 hs_memcpy_from_hs( txbuf, buf, txlen ); 276 277#if USBETH_DEBUG 278 xprintf( "Outgoing packet :\n" ); 279 hexdump( txbuf, txlen, 16, txlen / 16 + 1 ); 280#endif 281 ur = usb_make_request(softc->dev, softc->bulk_outpipe, 282 txbuf, txlen, UR_FLAG_OUT); 283 usb_sync_request(ur); 284 usb_free_request(ur); 285 usb_dma_free(txbuf); 286 287 return( len ); 288} 289 290static void rtek_open_device( rtek_softc_t *softc ) 291{ 292 /* Accept broadcast & own packets */ 293 rtek_set_reg( softc->dev, R_RTEK_RXCFG, RTEK_MACADDR | RTEK_BCASTADDR ); 294 295 /* Enable adapter to receive and transmit packets */ 296 rtek_set_reg( softc->dev, R_RTEK_CMD, RTEK_RXENABLE | RTEK_TXENABLE ); 297 298 /* kick start the receive */ 299 rtek_queue_rx( softc ); 300} 301 302 303static void rtek_close_device( rtek_softc_t *softc ) 304{ 305 usbdev_t *dev = softc->dev; 306 307 /* Disable adapter from receiving or transmitting packets */ 308 rtek_set_reg( dev, R_RTEK_CMD, 0 ); 309} 310 311 312/* ********************************************************************* 313 * CFE-USB interfaces 314 ********************************************************************* */ 315 316/* ********************************************************************* 317 * rtek_attach(dev,drv) 318 * 319 * This routine is called when the bus scan stuff finds a usb-ethernet 320 * device. We finish up the initialization by configuring the 321 * device and allocating our softc here. 322 * 323 * Input parameters: 324 * dev - usb device, in the "addressed" state. 325 * drv - the driver table entry that matched 326 * 327 * Return value: 328 * 0 329 ********************************************************************* */ 330 331const cfe_driver_t usbrtekdrv; /* forward declaration */ 332 333static int rtek_attach(usbdev_t *dev, usb_driver_t *drv) 334{ 335 usb_config_descr_t *cfgdscr = dev->ud_cfgdescr; 336 usb_endpoint_descr_t *epdscr; 337 usb_endpoint_descr_t *indscr = NULL; 338 usb_endpoint_descr_t *outdscr = NULL; 339 usb_interface_descr_t *ifdscr; 340 rtek_softc_t *softc; 341 int idx; 342 343 dev->ud_drv = drv; 344 345 softc = (rtek_softc_t *) KMALLOC( sizeof(rtek_softc_t), 0 ); 346 if( softc == NULL ) { 347 xprintf( "Failed to allocate softc memory.\n" ); 348 return -1; 349 } 350 memset( softc, 0, sizeof(rtek_softc_t) ); 351 dev->ud_private = softc; 352 softc->dev = dev; 353 354 ifdscr = usb_find_cfg_descr(dev,USB_INTERFACE_DESCRIPTOR_TYPE,0); 355 if (ifdscr == NULL) { 356 xprintf("USBETH: ERROR...no interace descriptor\n"); 357 return -1; 358 } 359 360 for (idx = 0; idx < 2; idx++) { 361 epdscr = usb_find_cfg_descr(dev,USB_ENDPOINT_DESCRIPTOR_TYPE,idx); 362 if (USB_ENDPOINT_DIR_OUT(epdscr->bEndpointAddress)) 363 outdscr = epdscr; 364 else 365 indscr = epdscr; 366 } 367 368 if (!indscr || !outdscr) { 369 /* 370 * Could not get descriptors, something is very wrong. 371 * Leave device addressed but not configured. 372 */ 373 xprintf("USBETH: ERROR...no endpoint descriptors\n"); 374 return -1; 375 } 376 377 /* Choose the standard configuration. */ 378 usb_set_configuration(dev,cfgdscr->bConfigurationValue); 379 380 /* Quit if not able to initialize the device */ 381 if (rtek_init_device(softc) < 0) 382 return -1; 383 384 /* Open the pipes. */ 385 softc->bulk_inpipe = usb_open_pipe(dev,indscr); 386 softc->bulk_outpipe = usb_open_pipe(dev,outdscr); 387 388 /* Register the device */ 389 usbeth_register(&usbeth_rtek,softc); 390 391 /* Open the device */ 392 rtek_open_device( softc ); 393 394 return 0; 395} 396 397/* ********************************************************************* 398 * rtek_detach(dev) 399 * 400 * This routine is called when the bus scanner notices that 401 * this device has been removed from the system. We should 402 * do any cleanup that is required. The pending requests 403 * will be cancelled automagically. 404 * 405 * Input parameters: 406 * dev - usb device 407 * 408 * Return value: 409 * 0 410 ********************************************************************* */ 411 412static int rtek_detach(usbdev_t *dev) 413{ 414 rtek_softc_t *softc = (rtek_softc_t *) dev->ud_private; 415 416 if (softc != NULL) { 417 usbeth_unregister( softc ); 418 rtek_close_device( softc ); 419 dev->ud_private = NULL; 420 softc->dev = NULL; 421 KFREE(softc); 422 } 423 424 return 0; 425} 426 427/* CFE USB device interface structure */ 428usb_driver_t usbrtek_driver = 429{ 430 "Ethernet Device", 431 rtek_attach, 432 rtek_detach 433}; 434 435 436 437 438