1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * USB Ethernet File: dev_usb_catc.c 5 * 6 * Driver for USB Ethernet devices using the CATC Netmate 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, CATC_NM, BELKIN_CATC }; 103static const char *VENDOR_NAMES[] = { 104 "?", "CATC-Netmate", "Belkin/CATC", "Yikes!" 105}; 106 107static const int ID_TBL[] = { 108 0x0423, 0x000a, CATC_NM, /* CATC (Netmate I) */ 109 0x0423, 0x000c, BELKIN_CATC, /* Belkin/CATC (Netmate II) */ 110 -1 111}; 112 113typedef struct catc_softc_s { 114 usbdev_t *dev; 115 int bulk_inpipe; 116 int bulk_outpipe; 117 int ven_code; 118 uint8_t mac_addr[6]; 119 usbreq_t *rx_ur; 120 uint8_t rxbuf[1600]; /* arbitrary but enough for ethernet packet */ 121} catc_softc_t; 122 123 124/* ************************************** 125 * CATC I/F Functions 126 ************************************** */ 127 128static int catc_send_eth_frame( void *ctx, hsaddr_t buf, int len ); 129static int catc_get_eth_frame( void *ctx, hsaddr_t buf ); 130static int catc_data_rx( void *ctx ); 131static int catc_get_dev_addr( void *ctx, hsaddr_t mac_addr ); 132 133static usbeth_disp_t usbeth_catc = { 134 catc_get_eth_frame, 135 catc_data_rx, 136 catc_send_eth_frame, 137 catc_get_dev_addr 138}; 139 140#if 0 141static int catc_get_reg( usbdev_t *dev, int16_t reg, uint8_t *val ) 142{ 143 return usb_std_request( dev, (USBREQ_TYPE_VENDOR | USBREQ_DIR_IN), 144 CATC_GET_REG, 0, reg, val, 1 ); 145} 146#endif 147 148static int catc_set_reg( usbdev_t *dev, int16_t reg, int16_t val ) 149{ 150 return usb_std_request( dev, (USBREQ_TYPE_VENDOR | USBREQ_DIR_OUT), 151 CATC_SET_REG, val, reg, NULL, 0 ); 152} 153 154static int catc_set_mem( usbdev_t *dev, int16_t addr, 155 uint8_t *data, int16_t len ) 156{ 157 return usb_std_request( dev, (USBREQ_TYPE_VENDOR | USBREQ_DIR_OUT), 158 CATC_SET_MEM, 0, addr, data, len ); 159} 160 161static int catc_get_mac_addr( usbdev_t *dev, uint8_t *mac_addr ) 162{ 163 return usb_std_request( dev, (USBREQ_TYPE_VENDOR | USBREQ_DIR_IN), 164 CATC_GET_MAC_ADDR, 0, 0, mac_addr, 6 ); 165} 166 167static int catc_init_device( catc_softc_t *softc ) 168{ 169 usb_device_descr_t dev_desc; 170 uint16_t vendor_id, product_id; 171 const int *ptr=ID_TBL; 172 usbdev_t *dev = softc->dev; 173 unsigned char *mcast_tbl; 174 175 176 /* find out which device is connected */ 177 usb_get_device_descriptor( softc->dev, &dev_desc, 0 ); 178 vendor_id = (dev_desc.idVendorHigh << 8) + dev_desc.idVendorLow; 179 product_id = (dev_desc.idProductHigh << 8) + dev_desc.idProductLow; 180 181 while( *ptr != -1 ) { 182 if( (vendor_id == ptr[0]) && (product_id == ptr[1]) ) { 183 softc->ven_code = ptr[2]; 184 break; 185 } 186 ptr += 3; 187 } 188 if( *ptr == -1 ) { 189 xprintf( "Unrecognized CATC USB-Ethernet device\n" ); 190 return -1; 191 } 192 193 usb_std_request( dev, (USBREQ_TYPE_STD | USBREQ_REC_INTERFACE), 194 USB_REQUEST_SET_INTERFACE, 195 1, /* alt setting 1 */ 196 0, NULL, 0 ); 197 198 catc_set_reg(dev, CATC_TX_BUF_CNT_REG, 0x04 ); 199 catc_set_reg(dev, CATC_RX_BUF_CNT_REG, 0x10 ); 200 catc_set_reg(dev, CATC_ADV_OP_MODES_REG, 0x01 ); 201 catc_set_reg(dev, CATC_LED_CTRL_REG, 0x08 ); 202 203 /* Enable broadcast rx via bit in multicast table */ 204 mcast_tbl = KMALLOC(64, CACHE_ALIGN); 205 memset( mcast_tbl, 0, 64 ); 206 mcast_tbl[31] = 0x80; /* broadcast bit */ 207 catc_set_mem( dev, CATC_MCAST_TBL_ADDR, mcast_tbl, 64 ); 208 KFREE(mcast_tbl); 209 210 /* Read the adapter's MAC addr */ 211 catc_get_mac_addr( dev, softc->mac_addr ); 212 213 /* display adapter info */ 214 xprintf( "%s USB-Ethernet Adapter (%a)\n", 215 VENDOR_NAMES[softc->ven_code], softc->mac_addr); 216 217 return 0; 218} 219 220static int catc_get_dev_addr( void *ctx, hsaddr_t mac_addr ) 221{ 222 catc_softc_t *softc = (catc_softc_t *) ctx; 223 hs_memcpy_to_hs( mac_addr, softc->mac_addr, 6 ); 224 return 0; 225} 226 227static void catc_queue_rx( catc_softc_t *softc ) 228{ 229 softc->rx_ur = usb_make_request(softc->dev, softc->bulk_inpipe, 230 softc->rxbuf, sizeof(softc->rxbuf), 231 (UR_FLAG_IN | UR_FLAG_SHORTOK)); 232 usb_queue_request(softc->rx_ur); 233} 234 235static int catc_data_rx( void *ctx ) 236{ 237 catc_softc_t *softc = (catc_softc_t *) ctx; 238 usb_poll(softc->dev->ud_bus); 239 return( !softc->rx_ur->ur_inprogress ); 240} 241 242static int catc_get_eth_frame( void *ctx, hsaddr_t buf ) 243{ 244 catc_softc_t *softc = (catc_softc_t *) ctx; 245 int len = 0; 246 uint8_t *rxbuf; 247 248 if( !softc->rx_ur->ur_inprogress ) { 249 rxbuf = softc->rxbuf; 250 len = softc->rx_ur->ur_xferred; 251 if (len > 0) { 252#if CATC_DEBUG 253 xprintf( "Incoming packet :\n" ); 254 hexdump( rxbuf, len, 16, len / 16 + 1 ); 255#endif 256 hs_memcpy_to_hs( buf, rxbuf, len ); 257 } 258 usb_free_request(softc->rx_ur); 259 catc_queue_rx( softc ); 260 } 261 else 262 xprintf( "Bulk data is not available yet!\n" ); 263 264 return( len ); 265} 266 267static int catc_send_eth_frame( void *ctx, hsaddr_t buf, int len ) 268{ 269 catc_softc_t *softc = (catc_softc_t *) ctx; 270 usbreq_t *ur; 271 int txlen = len; 272 unsigned char *txbuf; 273 274 txbuf = usb_dma_alloc(len+2); 275 txbuf[0] = txlen & 0xff; 276 txbuf[1] = (txlen >> 8) & 0xff; /* 1st two bytes...little endian */ 277 hs_memcpy_from_hs( &txbuf[2], buf, txlen ); 278 txlen += 2; 279#if USBETH_DEBUG 280 xprintf( "Outgoing packet :\n" ); 281 hexdump( txbuf, txlen, 16, txlen / 16 + 1 ); 282#endif 283 ur = usb_make_request(softc->dev, softc->bulk_outpipe, 284 txbuf, txlen, UR_FLAG_OUT); 285 usb_sync_request(ur); 286 usb_free_request(ur); 287 usb_dma_free(txbuf); 288 289 return( len ); 290} 291 292static void catc_open_device( catc_softc_t *softc ) 293{ 294 int i; 295 296 for(i = 0; i < 6; ++i) 297 catc_set_reg( softc->dev, (CATC_ETH_ADDR_0_REG - i), softc->mac_addr[i] ); 298 299 /* Enable adapter to receive packets */ 300 catc_set_reg( softc->dev, CATC_ETH_CTRL_REG, 0x09 ); 301 302 /* kick start the receive */ 303 catc_queue_rx( softc ); 304} 305 306static void catc_close_device( catc_softc_t *softc ) 307{ 308 usbdev_t *dev = softc->dev; 309 310 /* Disable adapter from receiving packets */ 311 catc_set_reg( dev, CATC_ETH_CTRL_REG, 0 ); 312} 313 314 315/* ********************************************************************* 316 * CFE-USB interfaces 317 ********************************************************************* */ 318 319/* ********************************************************************* 320 * catc_attach(dev,drv) 321 * 322 * This routine is called when the bus scan stuff finds a usb-ethernet 323 * device. We finish up the initialization by configuring the 324 * device and allocating our softc here. 325 * 326 * Input parameters: 327 * dev - usb device, in the "addressed" state. 328 * drv - the driver table entry that matched 329 * 330 * Return value: 331 * 0 332 ********************************************************************* */ 333 334const cfe_driver_t usbcatcdrv; /* forward declaration */ 335 336static int catc_attach(usbdev_t *dev, usb_driver_t *drv) 337{ 338 usb_config_descr_t *cfgdscr = dev->ud_cfgdescr; 339 usb_endpoint_descr_t *epdscr; 340 usb_endpoint_descr_t *indscr = NULL; 341 usb_endpoint_descr_t *outdscr = NULL; 342 usb_interface_descr_t *ifdscr; 343 catc_softc_t *softc; 344 int idx; 345 346 dev->ud_drv = drv; 347 348 softc = (catc_softc_t *) KMALLOC( sizeof(catc_softc_t), 0 ); 349 if( softc == NULL ) { 350 xprintf( "Failed to allocate softc memory.\n" ); 351 return -1; 352 } 353 memset( softc, 0, sizeof(catc_softc_t) ); 354 dev->ud_private = softc; 355 softc->dev = dev; 356 357 ifdscr = usb_find_cfg_descr(dev,USB_INTERFACE_DESCRIPTOR_TYPE,0); 358 if (ifdscr == NULL) { 359 xprintf("USBETH: ERROR...no interace descriptor\n"); 360 return -1; 361 } 362 363 for (idx = 0; idx < 2; idx++) { 364 epdscr = usb_find_cfg_descr(dev,USB_ENDPOINT_DESCRIPTOR_TYPE,idx); 365 if (USB_ENDPOINT_DIR_OUT(epdscr->bEndpointAddress)) 366 outdscr = epdscr; 367 else 368 indscr = epdscr; 369 } 370 371 if (!indscr || !outdscr) { 372 /* 373 * Could not get descriptors, something is very wrong. 374 * Leave device addressed but not configured. 375 */ 376 xprintf("USBETH: ERROR...no endpoint descriptors\n"); 377 return -1; 378 } 379 380 /* Choose the standard configuration. */ 381 usb_set_configuration(dev,cfgdscr->bConfigurationValue); 382 383 /* Quit if not able to initialize the device */ 384 if (catc_init_device(softc) < 0) 385 return -1; 386 387 /* Open the pipes. */ 388 softc->bulk_inpipe = usb_open_pipe(dev,indscr); 389 softc->bulk_outpipe = usb_open_pipe(dev,outdscr); 390 391 /* Register the device */ 392 usbeth_register(&usbeth_catc,softc); 393 394 /* Open the device */ 395 catc_open_device( softc ); 396 397 return 0; 398} 399 400/* ********************************************************************* 401 * catc_detach(dev) 402 * 403 * This routine is called when the bus scanner notices that 404 * this device has been removed from the system. We should 405 * do any cleanup that is required. The pending requests 406 * will be cancelled automagically. 407 * 408 * Input parameters: 409 * dev - usb device 410 * 411 * Return value: 412 * 0 413 ********************************************************************* */ 414 415static int catc_detach(usbdev_t *dev) 416{ 417 catc_softc_t *softc = (catc_softc_t *) dev->ud_private; 418 419 if (softc != NULL) { 420 usbeth_unregister( softc ); 421 catc_close_device ( softc ); 422 dev->ud_private = NULL; 423 softc->dev = NULL; 424 KFREE(softc); 425 } 426 427 return 0; 428} 429 430/* CFE USB device interface structure */ 431usb_driver_t usbcatc_driver = 432{ 433 "Ethernet Device", 434 catc_attach, 435 catc_detach 436}; 437 438 439/* ********************************************************************* 440 * CFE-Ethernet device interfaces 441 ********************************************************************* */ 442 443 444static int catc_ether_open(cfe_devctx_t *ctx) 445{ 446 catc_softc_t *softc = (catc_softc_t *) ctx->dev_softc; 447 448 if (softc->dev == NULL) 449 return CFE_ERR_NOTREADY; 450 451 USBETH_TRACE( "%s called.\n", __FUNCTION__ ); 452 catc_open_device( softc ); 453 454 return 0; 455} 456 457static int catc_ether_read( cfe_devctx_t *ctx, iocb_buffer_t *buffer ) 458{ 459 catc_softc_t *softc = (catc_softc_t *) ctx->dev_softc; 460 461 if (softc->dev == NULL) 462 return CFE_ERR_NOTREADY; 463 464 buffer->buf_retlen = catc_get_eth_frame( softc, buffer->buf_ptr ); 465 466 return 0; 467} 468 469 470static int catc_ether_inpstat( cfe_devctx_t *ctx, iocb_inpstat_t *inpstat ) 471{ 472 catc_softc_t *softc = (catc_softc_t *) ctx->dev_softc; 473 474 if (softc->dev == NULL) 475 return CFE_ERR_NOTREADY; 476 477 inpstat->inp_status = catc_data_rx( softc ); 478 return 0; 479} 480 481 482static int catc_ether_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 483{ 484 catc_softc_t *softc = (catc_softc_t *) ctx->dev_softc; 485 486 if (softc->dev == NULL) 487 return CFE_ERR_NOTREADY; 488 489 /* Block until hw notifies you data is sent. */ 490 catc_send_eth_frame( softc, buffer->buf_ptr, buffer->buf_length ); 491 492 return 0; 493} 494 495 496static int catc_ether_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 497{ 498 catc_softc_t *softc = (catc_softc_t *) ctx->dev_softc; 499 int retval = 0; 500 501 if (softc->dev == NULL) 502 return CFE_ERR_NOTREADY; 503 504 switch( (int)buffer->buf_ioctlcmd ) { 505 case IOCTL_ETHER_GETHWADDR: 506 USBETH_TRACE( "IOCTL_ETHER_GETHWADDR called.\n" ); 507 catc_get_dev_addr( softc, buffer->buf_ptr ); 508 break; 509 case IOCTL_ETHER_SETHWADDR: 510 xprintf( "IOCTL_ETHER_SETHWADDR not implemented.\n" ); 511 break; 512#if 0 513 case IOCTL_ETHER_GETSPEED: 514 xprintf( "GETSPEED not implemented.\n" ); 515 retval = -1; 516 break; 517 case IOCTL_ETHER_SETSPEED: 518 xprintf( "SETSPEED not implemented.\n" ); 519 retval = -1; 520 break; 521 case IOCTL_ETHER_GETLINK: 522 xprintf( "GETLINK not implemented.\n" ); 523 retval = -1; 524 break; 525 case IOCTL_ETHER_GETLOOPBACK: 526 xprintf( "GETLOOPBACK not implemented.\n" ); 527 retval = -1; 528 break; 529 case IOCTL_ETHER_SETLOOPBACK: 530 xprintf( "SETLOOPBACK not implemented.\n" ); 531 retval = -1; 532 break; 533#endif 534 default: 535 xprintf( "Invalid IOCTL to catc_ether_ioctl.\n" ); 536 retval = -1; 537 } 538 539 return retval; 540} 541 542 543static int catc_ether_close(cfe_devctx_t *ctx) 544{ 545 catc_softc_t *softc = (catc_softc_t *) ctx->dev_softc; 546 547 if (softc->dev == NULL) 548 return CFE_ERR_NOTREADY; 549 550 USBETH_TRACE( "%s called.\n", __FUNCTION__ ); 551 catc_close_device( softc ); 552 return 0; 553} 554 555 556/* CFE ethernet device interface structures */ 557 558const static cfe_devdisp_t catc_ether_dispatch = 559{ 560 catc_ether_open, 561 catc_ether_read, 562 catc_ether_inpstat, 563 catc_ether_write, 564 catc_ether_ioctl, 565 catc_ether_close, 566 NULL, 567 NULL 568}; 569 570const cfe_driver_t usbcatcdrv = 571{ 572 "USB-Ethernet Device", 573 "eth", 574 CFE_DEV_NETWORK, 575 &catc_ether_dispatch, 576 NULL, /* probe...not needed */ 577}; 578 579