PageRenderTime 50ms CodeModel.GetById 6ms app.highlight 33ms RepoModel.GetById 0ms app.codeStats 1ms

/drivers/staging/wlags49_h2/wl_netdev.c

https://bitbucket.org/slukk/jb-tsm-kernel-4.2
C | 2037 lines | 953 code | 282 blank | 802 comment | 162 complexity | fc6867309f307f87b2d59e0b09bee68e MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0

Large files files are truncated, but you can click here to view the full file

   1/*******************************************************************************
   2 * Agere Systems Inc.
   3 * Wireless device driver for Linux (wlags49).
   4 *
   5 * Copyright (c) 1998-2003 Agere Systems Inc.
   6 * All rights reserved.
   7 *   http://www.agere.com
   8 *
   9 * Initially developed by TriplePoint, Inc.
  10 *   http://www.triplepoint.com
  11 *
  12 *------------------------------------------------------------------------------
  13 *
  14 *   This file contains handler functions registered with the net_device
  15 *   structure.
  16 *
  17 *------------------------------------------------------------------------------
  18 *
  19 * SOFTWARE LICENSE
  20 *
  21 * This software is provided subject to the following terms and conditions,
  22 * which you should read carefully before using the software.  Using this
  23 * software indicates your acceptance of these terms and conditions.  If you do
  24 * not agree with these terms and conditions, do not use the software.
  25 *
  26 * Copyright � 2003 Agere Systems Inc.
  27 * All rights reserved.
  28 *
  29 * Redistribution and use in source or binary forms, with or without
  30 * modifications, are permitted provided that the following conditions are met:
  31 *
  32 * . Redistributions of source code must retain the above copyright notice, this
  33 *    list of conditions and the following Disclaimer as comments in the code as
  34 *    well as in the documentation and/or other materials provided with the
  35 *    distribution.
  36 *
  37 * . Redistributions in binary form must reproduce the above copyright notice,
  38 *    this list of conditions and the following Disclaimer in the documentation
  39 *    and/or other materials provided with the distribution.
  40 *
  41 * . Neither the name of Agere Systems Inc. nor the names of the contributors
  42 *    may be used to endorse or promote products derived from this software
  43 *    without specific prior written permission.
  44 *
  45 * Disclaimer
  46 *
  47 * THIS SOFTWARE IS PROVIDED �AS IS� AND ANY EXPRESS OR IMPLIED WARRANTIES,
  48 * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
  49 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  ANY
  50 * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
  51 * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
  52 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  53 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  54 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  55 * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
  56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  57 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  58 * DAMAGE.
  59 *
  60 ******************************************************************************/
  61
  62/*******************************************************************************
  63 * include files
  64 ******************************************************************************/
  65#include <wl_version.h>
  66
  67#include <linux/module.h>
  68#include <linux/slab.h>
  69#include <linux/types.h>
  70#include <linux/kernel.h>
  71// #include <linux/sched.h>
  72// #include <linux/ptrace.h>
  73// #include <linux/slab.h>
  74// #include <linux/ctype.h>
  75// #include <linux/string.h>
  76//#include <linux/timer.h>
  77// #include <linux/interrupt.h>
  78// #include <linux/in.h>
  79// #include <linux/delay.h>
  80// #include <linux/skbuff.h>
  81// #include <asm/io.h>
  82// #include <asm/system.h>
  83// #include <asm/bitops.h>
  84
  85#include <linux/netdevice.h>
  86#include <linux/ethtool.h>
  87#include <linux/etherdevice.h>
  88// #include <linux/skbuff.h>
  89// #include <linux/if_arp.h>
  90// #include <linux/ioport.h>
  91
  92#include <debug.h>
  93
  94#include <hcf.h>
  95#include <dhf.h>
  96// #include <hcfdef.h>
  97
  98#include <wl_if.h>
  99#include <wl_internal.h>
 100#include <wl_util.h>
 101#include <wl_priv.h>
 102#include <wl_main.h>
 103#include <wl_netdev.h>
 104#include <wl_wext.h>
 105
 106#ifdef USE_PROFILE
 107#include <wl_profile.h>
 108#endif  /* USE_PROFILE */
 109
 110#ifdef BUS_PCMCIA
 111#include <wl_cs.h>
 112#endif  /* BUS_PCMCIA */
 113
 114#ifdef BUS_PCI
 115#include <wl_pci.h>
 116#endif  /* BUS_PCI */
 117
 118
 119/*******************************************************************************
 120 * global variables
 121 ******************************************************************************/
 122#if DBG
 123extern dbg_info_t *DbgInfo;
 124#endif  /* DBG */
 125
 126
 127#if HCF_ENCAP
 128#define MTU_MAX (HCF_MAX_MSG - ETH_HLEN - 8)
 129#else
 130#define MTU_MAX (HCF_MAX_MSG - ETH_HLEN)
 131#endif
 132
 133//static int mtu = MTU_MAX;
 134//MODULE_PARM(mtu, "i");
 135//MODULE_PARM_DESC(mtu, "MTU");
 136
 137/*******************************************************************************
 138 * macros
 139 ******************************************************************************/
 140#define BLOCK_INPUT(buf, len) \
 141    desc->buf_addr = buf; \
 142    desc->BUF_SIZE = len; \
 143    status = hcf_rcv_msg(&(lp->hcfCtx), desc, 0)
 144
 145#define BLOCK_INPUT_DMA(buf, len) memcpy( buf, desc_next->buf_addr, pktlen )
 146
 147/*******************************************************************************
 148 * function prototypes
 149 ******************************************************************************/
 150
 151/*******************************************************************************
 152 *	wl_init()
 153 *******************************************************************************
 154 *
 155 *  DESCRIPTION:
 156 *
 157 *      We never need to do anything when a "Wireless" device is "initialized"
 158 *  by the net software, because we only register already-found cards.
 159 *
 160 *  PARAMETERS:
 161 *
 162 *      dev - a pointer to the device's net_device structure
 163 *
 164 *  RETURNS:
 165 *
 166 *      0 on success
 167 *      errno value otherwise
 168 *
 169 ******************************************************************************/
 170int wl_init( struct net_device *dev )
 171{
 172//    unsigned long       flags;
 173//    struct wl_private   *lp = wl_priv(dev);
 174    /*------------------------------------------------------------------------*/
 175
 176    DBG_FUNC( "wl_init" );
 177    DBG_ENTER( DbgInfo );
 178
 179    DBG_PARAM( DbgInfo, "dev", "%s (0x%p)", dev->name, dev );
 180
 181    /* Nothing to do, but grab the spinlock anyway just in case we ever need
 182       this routine */
 183//  wl_lock( lp, &flags );
 184//  wl_unlock( lp, &flags );
 185
 186    DBG_LEAVE( DbgInfo );
 187    return 0;
 188} // wl_init
 189/*============================================================================*/
 190
 191/*******************************************************************************
 192 *	wl_config()
 193 *******************************************************************************
 194 *
 195 *  DESCRIPTION:
 196 *
 197 *      Implement the SIOCSIFMAP interface.
 198 *
 199 *  PARAMETERS:
 200 *
 201 *      dev - a pointer to the device's net_device structure
 202 *      map - a pointer to the device's ifmap structure
 203 *
 204 *  RETURNS:
 205 *
 206 *      0 on success
 207 *      errno otherwise
 208 *
 209 ******************************************************************************/
 210int wl_config( struct net_device *dev, struct ifmap *map )
 211{
 212    DBG_FUNC( "wl_config" );
 213    DBG_ENTER( DbgInfo );
 214
 215    DBG_PARAM( DbgInfo, "dev", "%s (0x%p)", dev->name, dev );
 216    DBG_PARAM( DbgInfo, "map", "0x%p", map );
 217
 218    /* The only thing we care about here is a port change. Since this not needed,
 219       ignore the request. */
 220    DBG_TRACE( DbgInfo, "%s: %s called.\n", dev->name, __FUNC__ );
 221
 222    DBG_LEAVE( DbgInfo );
 223    return 0;
 224} // wl_config
 225/*============================================================================*/
 226
 227/*******************************************************************************
 228 *	wl_stats()
 229 *******************************************************************************
 230 *
 231 *  DESCRIPTION:
 232 *
 233 *      Return the current device statistics.
 234 *
 235 *  PARAMETERS:
 236 *
 237 *      dev - a pointer to the device's net_device structure
 238 *
 239 *  RETURNS:
 240 *
 241 *      a pointer to a net_device_stats structure containing the network
 242 *      statistics.
 243 *
 244 ******************************************************************************/
 245struct net_device_stats *wl_stats( struct net_device *dev )
 246{
 247#ifdef USE_WDS
 248    int                         count;
 249#endif  /* USE_WDS */
 250    unsigned long               flags;
 251    struct net_device_stats     *pStats;
 252    struct wl_private           *lp = wl_priv(dev);
 253    /*------------------------------------------------------------------------*/
 254
 255    //DBG_FUNC( "wl_stats" );
 256    //DBG_ENTER( DbgInfo );
 257    //DBG_PARAM( DbgInfo, "dev", "%s (0x%p)", dev->name, dev );
 258
 259    pStats = NULL;
 260
 261    wl_lock( lp, &flags );
 262
 263#ifdef USE_RTS
 264    if( lp->useRTS == 1 ) {
 265	wl_unlock( lp, &flags );
 266
 267	//DBG_LEAVE( DbgInfo );
 268	return NULL;
 269    }
 270#endif  /* USE_RTS */
 271
 272    /* Return the statistics for the appropriate device */
 273#ifdef USE_WDS
 274
 275    for( count = 0; count < NUM_WDS_PORTS; count++ ) {
 276	if( dev == lp->wds_port[count].dev ) {
 277	    pStats = &( lp->wds_port[count].stats );
 278	}
 279    }
 280
 281#endif  /* USE_WDS */
 282
 283    /* If pStats is still NULL, then the device is not a WDS port */
 284    if( pStats == NULL ) {
 285        pStats = &( lp->stats );
 286    }
 287
 288    wl_unlock( lp, &flags );
 289
 290    //DBG_LEAVE( DbgInfo );
 291
 292    return pStats;
 293} // wl_stats
 294/*============================================================================*/
 295
 296/*******************************************************************************
 297 *	wl_open()
 298 *******************************************************************************
 299 *
 300 *  DESCRIPTION:
 301 *
 302 *      Open the device.
 303 *
 304 *  PARAMETERS:
 305 *
 306 *      dev - a pointer to the device's net_device structure
 307 *
 308 *  RETURNS:
 309 *
 310 *      0 on success
 311 *      errno otherwise
 312 *
 313 ******************************************************************************/
 314int wl_open(struct net_device *dev)
 315{
 316    int                 status = HCF_SUCCESS;
 317    struct wl_private   *lp = wl_priv(dev);
 318    unsigned long       flags;
 319    /*------------------------------------------------------------------------*/
 320
 321    DBG_FUNC( "wl_open" );
 322    DBG_ENTER( DbgInfo );
 323
 324    wl_lock( lp, &flags );
 325
 326#ifdef USE_RTS
 327    if( lp->useRTS == 1 ) {
 328	DBG_TRACE( DbgInfo, "Skipping device open, in RTS mode\n" );
 329	wl_unlock( lp, &flags );
 330	DBG_LEAVE( DbgInfo );
 331	return -EIO;
 332    }
 333#endif  /* USE_RTS */
 334
 335#ifdef USE_PROFILE
 336    parse_config( dev );
 337#endif
 338
 339    if( lp->portState == WVLAN_PORT_STATE_DISABLED ) {
 340	DBG_TRACE( DbgInfo, "Enabling Port 0\n" );
 341	status = wl_enable( lp );
 342
 343        if( status != HCF_SUCCESS ) {
 344            DBG_TRACE( DbgInfo, "Enable port 0 failed: 0x%x\n", status );
 345        }
 346    }
 347
 348    // Holding the lock too long, make a gap to allow other processes
 349    wl_unlock(lp, &flags);
 350    wl_lock( lp, &flags );
 351
 352    if ( strlen( lp->fw_image_filename ) ) {
 353	DBG_TRACE( DbgInfo, ";???? Kludgy way to force a download\n" );
 354	status = wl_go( lp );
 355    } else {
 356	status = wl_apply( lp );
 357    }
 358
 359    // Holding the lock too long, make a gap to allow other processes
 360    wl_unlock(lp, &flags);
 361    wl_lock( lp, &flags );
 362
 363    if( status != HCF_SUCCESS ) {
 364	// Unsuccessful, try reset of the card to recover
 365	status = wl_reset( dev );
 366    }
 367
 368    // Holding the lock too long, make a gap to allow other processes
 369    wl_unlock(lp, &flags);
 370    wl_lock( lp, &flags );
 371
 372    if( status == HCF_SUCCESS ) {
 373	netif_carrier_on( dev );
 374	WL_WDS_NETIF_CARRIER_ON( lp );
 375
 376	lp->is_handling_int = WL_HANDLING_INT; // Start handling interrupts
 377        wl_act_int_on( lp );
 378
 379	netif_start_queue( dev );
 380	WL_WDS_NETIF_START_QUEUE( lp );
 381    } else {
 382        wl_hcf_error( dev, status );		/* Report the error */
 383        netif_device_detach( dev );		/* Stop the device and queue */
 384    }
 385
 386    wl_unlock( lp, &flags );
 387
 388    DBG_LEAVE( DbgInfo );
 389    return status;
 390} // wl_open
 391/*============================================================================*/
 392
 393/*******************************************************************************
 394 *	wl_close()
 395 *******************************************************************************
 396 *
 397 *  DESCRIPTION:
 398 *
 399 *      Close the device.
 400 *
 401 *  PARAMETERS:
 402 *
 403 *      dev - a pointer to the device's net_device structure
 404 *
 405 *  RETURNS:
 406 *
 407 *      0 on success
 408 *      errno otherwise
 409 *
 410 ******************************************************************************/
 411int wl_close( struct net_device *dev )
 412{
 413    struct wl_private   *lp = wl_priv(dev);
 414    unsigned long   flags;
 415    /*------------------------------------------------------------------------*/
 416
 417    DBG_FUNC("wl_close");
 418    DBG_ENTER(DbgInfo);
 419    DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev);
 420
 421    /* Mark the adapter as busy */
 422    netif_stop_queue( dev );
 423    WL_WDS_NETIF_STOP_QUEUE( lp );
 424
 425    netif_carrier_off( dev );
 426    WL_WDS_NETIF_CARRIER_OFF( lp );
 427
 428    /* Shutdown the adapter:
 429            Disable adapter interrupts
 430            Stop Tx/Rx
 431            Update statistics
 432            Set low power mode
 433    */
 434
 435    wl_lock( lp, &flags );
 436
 437    wl_act_int_off( lp );
 438    lp->is_handling_int = WL_NOT_HANDLING_INT; // Stop handling interrupts
 439
 440#ifdef USE_RTS
 441    if( lp->useRTS == 1 ) {
 442	DBG_TRACE( DbgInfo, "Skipping device close, in RTS mode\n" );
 443	wl_unlock( lp, &flags );
 444	DBG_LEAVE( DbgInfo );
 445	return -EIO;
 446    }
 447#endif  /* USE_RTS */
 448
 449    /* Disable the ports */
 450    wl_disable( lp );
 451
 452    wl_unlock( lp, &flags );
 453
 454    DBG_LEAVE( DbgInfo );
 455    return 0;
 456} // wl_close
 457/*============================================================================*/
 458
 459static void wl_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 460{
 461    strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1);
 462    strncpy(info->version, DRV_VERSION_STR, sizeof(info->version) - 1);
 463//	strncpy(info.fw_version, priv->fw_name,
 464//	sizeof(info.fw_version) - 1);
 465
 466    if (dev->dev.parent) {
 467    	dev_set_name(dev->dev.parent, "%s", info->bus_info);
 468	//strncpy(info->bus_info, dev->dev.parent->bus_id,
 469	//	sizeof(info->bus_info) - 1);
 470    } else {
 471	snprintf(info->bus_info, sizeof(info->bus_info) - 1,
 472		"PCMCIA FIXME");
 473//		    "PCMCIA 0x%lx", priv->hw.iobase);
 474    }
 475} // wl_get_drvinfo
 476
 477static struct ethtool_ops wl_ethtool_ops = {
 478    .get_drvinfo = wl_get_drvinfo,
 479    .get_link = ethtool_op_get_link,
 480};
 481
 482
 483/*******************************************************************************
 484 *	wl_ioctl()
 485 *******************************************************************************
 486 *
 487 *  DESCRIPTION:
 488 *
 489 *      The IOCTL handler for the device.
 490 *
 491 *  PARAMETERS:
 492 *
 493 *      dev - a pointer to the device's net_device struct.
 494 *      rq  - a pointer to the IOCTL request buffer.
 495 *      cmd - the IOCTL command code.
 496 *
 497 *  RETURNS:
 498 *
 499 *      0 on success
 500 *      errno value otherwise
 501 *
 502 ******************************************************************************/
 503int wl_ioctl( struct net_device *dev, struct ifreq *rq, int cmd )
 504{
 505    struct wl_private  *lp = wl_priv(dev);
 506    unsigned long           flags;
 507    int                     ret = 0;
 508    /*------------------------------------------------------------------------*/
 509
 510    DBG_FUNC( "wl_ioctl" );
 511    DBG_ENTER(DbgInfo);
 512    DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev);
 513    DBG_PARAM(DbgInfo, "rq", "0x%p", rq);
 514    DBG_PARAM(DbgInfo, "cmd", "0x%04x", cmd);
 515
 516    wl_lock( lp, &flags );
 517
 518    wl_act_int_off( lp );
 519
 520#ifdef USE_RTS
 521    if( lp->useRTS == 1 ) {
 522	/* Handle any RTS IOCTL here */
 523	if( cmd == WL_IOCTL_RTS ) {
 524	    DBG_TRACE( DbgInfo, "IOCTL: WL_IOCTL_RTS\n" );
 525	    ret = wvlan_rts( (struct rtsreq *)rq, dev->base_addr );
 526	} else {
 527	    DBG_TRACE( DbgInfo, "IOCTL not supported in RTS mode: 0x%X\n", cmd );
 528	    ret = -EOPNOTSUPP;
 529	}
 530
 531	goto out_act_int_on_unlock;
 532    }
 533#endif  /* USE_RTS */
 534
 535    /* Only handle UIL IOCTL requests when the UIL has the system blocked. */
 536    if( !(( lp->flags & WVLAN2_UIL_BUSY ) && ( cmd != WVLAN2_IOCTL_UIL ))) {
 537#ifdef USE_UIL
 538	struct uilreq  *urq = (struct uilreq *)rq;
 539#endif /* USE_UIL */
 540
 541	switch( cmd ) {
 542		// ================== Private IOCTLs (up to 16) ==================
 543#ifdef USE_UIL
 544	case WVLAN2_IOCTL_UIL:
 545	     DBG_TRACE( DbgInfo, "IOCTL: WVLAN2_IOCTL_UIL\n" );
 546	     ret = wvlan_uil( urq, lp );
 547	     break;
 548#endif  /* USE_UIL */
 549
 550	default:
 551	     DBG_TRACE(DbgInfo, "IOCTL CODE NOT SUPPORTED: 0x%X\n", cmd );
 552	     ret = -EOPNOTSUPP;
 553	     break;
 554	}
 555    } else {
 556	DBG_WARNING( DbgInfo, "DEVICE IS BUSY, CANNOT PROCESS REQUEST\n" );
 557	ret = -EBUSY;
 558    }
 559
 560#ifdef USE_RTS
 561out_act_int_on_unlock:
 562#endif  /* USE_RTS */
 563    wl_act_int_on( lp );
 564
 565    wl_unlock( lp, &flags );
 566
 567    DBG_LEAVE( DbgInfo );
 568    return ret;
 569} // wl_ioctl
 570/*============================================================================*/
 571
 572#ifdef CONFIG_NET_POLL_CONTROLLER
 573void wl_poll(struct net_device *dev)
 574{
 575    struct wl_private *lp = wl_priv(dev);
 576    unsigned long flags;
 577    struct pt_regs regs;
 578
 579    wl_lock( lp, &flags );
 580    wl_isr(dev->irq, dev, &regs);
 581    wl_unlock( lp, &flags );
 582}
 583#endif
 584
 585/*******************************************************************************
 586 *	wl_tx_timeout()
 587 *******************************************************************************
 588 *
 589 *  DESCRIPTION:
 590 *
 591 *      The handler called when, for some reason, a Tx request is not completed.
 592 *
 593 *  PARAMETERS:
 594 *
 595 *      dev - a pointer to the device's net_device struct.
 596 *
 597 *  RETURNS:
 598 *
 599 *      N/A
 600 *
 601 ******************************************************************************/
 602void wl_tx_timeout( struct net_device *dev )
 603{
 604#ifdef USE_WDS
 605    int                     count;
 606#endif  /* USE_WDS */
 607    unsigned long           flags;
 608    struct wl_private       *lp = wl_priv(dev);
 609    struct net_device_stats *pStats = NULL;
 610    /*------------------------------------------------------------------------*/
 611
 612    DBG_FUNC( "wl_tx_timeout" );
 613    DBG_ENTER( DbgInfo );
 614
 615    DBG_WARNING( DbgInfo, "%s: Transmit timeout.\n", dev->name );
 616
 617    wl_lock( lp, &flags );
 618
 619#ifdef USE_RTS
 620    if( lp->useRTS == 1 ) {
 621	DBG_TRACE( DbgInfo, "Skipping tx_timeout handler, in RTS mode\n" );
 622	wl_unlock( lp, &flags );
 623
 624	DBG_LEAVE( DbgInfo );
 625	return;
 626    }
 627#endif  /* USE_RTS */
 628
 629    /* Figure out which device (the "root" device or WDS port) this timeout
 630       is for */
 631#ifdef USE_WDS
 632
 633    for( count = 0; count < NUM_WDS_PORTS; count++ ) {
 634	if( dev == lp->wds_port[count].dev ) {
 635	    pStats = &( lp->wds_port[count].stats );
 636
 637	    /* Break the loop so that we can use the counter to access WDS
 638	       information in the private structure */
 639	    break;
 640	}
 641    }
 642
 643#endif  /* USE_WDS */
 644
 645    /* If pStats is still NULL, then the device is not a WDS port */
 646    if( pStats == NULL ) {
 647	pStats = &( lp->stats );
 648    }
 649
 650    /* Accumulate the timeout error */
 651    pStats->tx_errors++;
 652
 653    wl_unlock( lp, &flags );
 654
 655    DBG_LEAVE( DbgInfo );
 656    return;
 657} // wl_tx_timeout
 658/*============================================================================*/
 659
 660/*******************************************************************************
 661 *	wl_send()
 662 *******************************************************************************
 663 *
 664 *  DESCRIPTION:
 665 *
 666 *      The routine which performs data transmits.
 667 *
 668 *  PARAMETERS:
 669 *
 670 *      lp  - a pointer to the device's wl_private struct.
 671 *
 672 *  RETURNS:
 673 *
 674 *      0 on success
 675 *      1 on error
 676 *
 677 ******************************************************************************/
 678int wl_send( struct wl_private *lp )
 679{
 680
 681    int                 status;
 682    DESC_STRCT          *desc;
 683    WVLAN_LFRAME        *txF = NULL;
 684    struct list_head    *element;
 685    int                 len;
 686    /*------------------------------------------------------------------------*/
 687
 688    DBG_FUNC( "wl_send" );
 689
 690    if( lp == NULL ) {
 691        DBG_ERROR( DbgInfo, "Private adapter struct is NULL\n" );
 692        return FALSE;
 693    }
 694    if( lp->dev == NULL ) {
 695        DBG_ERROR( DbgInfo, "net_device struct in wl_private is NULL\n" );
 696        return FALSE;
 697    }
 698
 699    /* Check for the availability of FIDs; if none are available, don't take any
 700       frames off the txQ */
 701    if( lp->hcfCtx.IFB_RscInd == 0 ) {
 702        return FALSE;
 703    }
 704
 705    /* Reclaim the TxQ Elements and place them back on the free queue */
 706    if( !list_empty( &( lp->txQ[0] ))) {
 707        element = lp->txQ[0].next;
 708
 709        txF = (WVLAN_LFRAME * )list_entry( element, WVLAN_LFRAME, node );
 710        if( txF != NULL ) {
 711            lp->txF.skb  = txF->frame.skb;
 712            lp->txF.port = txF->frame.port;
 713
 714            txF->frame.skb  = NULL;
 715            txF->frame.port = 0;
 716
 717            list_del( &( txF->node ));
 718            list_add( element, &( lp->txFree ));
 719
 720            lp->txQ_count--;
 721
 722            if( lp->txQ_count < TX_Q_LOW_WATER_MARK ) {
 723                if( lp->netif_queue_on == FALSE ) {
 724                    DBG_TX( DbgInfo, "Kickstarting Q: %d\n", lp->txQ_count );
 725                    netif_wake_queue( lp->dev );
 726                    WL_WDS_NETIF_WAKE_QUEUE( lp );
 727                    lp->netif_queue_on = TRUE;
 728                }
 729            }
 730        }
 731    }
 732
 733    if( lp->txF.skb == NULL ) {
 734        return FALSE;
 735    }
 736
 737    /* If the device has resources (FIDs) available, then Tx the packet */
 738    /* Format the TxRequest and send it to the adapter */
 739    len = lp->txF.skb->len < ETH_ZLEN ? ETH_ZLEN : lp->txF.skb->len;
 740
 741    desc                    = &( lp->desc_tx );
 742    desc->buf_addr          = lp->txF.skb->data;
 743    desc->BUF_CNT           = len;
 744    desc->next_desc_addr    = NULL;
 745
 746    status = hcf_send_msg( &( lp->hcfCtx ), desc, lp->txF.port );
 747
 748    if( status == HCF_SUCCESS ) {
 749        lp->dev->trans_start = jiffies;
 750
 751        DBG_TX( DbgInfo, "Transmit...\n" );
 752
 753        if( lp->txF.port == HCF_PORT_0 ) {
 754            lp->stats.tx_packets++;
 755            lp->stats.tx_bytes += lp->txF.skb->len;
 756        }
 757
 758#ifdef USE_WDS
 759        else
 760        {
 761            lp->wds_port[(( lp->txF.port >> 8 ) - 1)].stats.tx_packets++;
 762            lp->wds_port[(( lp->txF.port >> 8 ) - 1)].stats.tx_bytes += lp->txF.skb->len;
 763        }
 764
 765#endif  /* USE_WDS */
 766
 767        /* Free the skb and perform queue cleanup, as the buffer was
 768            transmitted successfully */
 769        dev_kfree_skb( lp->txF.skb );
 770
 771        lp->txF.skb = NULL;
 772        lp->txF.port = 0;
 773    }
 774
 775    return TRUE;
 776} // wl_send
 777/*============================================================================*/
 778
 779/*******************************************************************************
 780 *	wl_tx()
 781 *******************************************************************************
 782 *
 783 *  DESCRIPTION:
 784 *
 785 *      The Tx handler function for the network layer.
 786 *
 787 *  PARAMETERS:
 788 *
 789 *      skb - a pointer to the sk_buff structure containing the data to transfer.
 790 *      dev - a pointer to the device's net_device structure.
 791 *
 792 *  RETURNS:
 793 *
 794 *      0 on success
 795 *      1 on error
 796 *
 797 ******************************************************************************/
 798int wl_tx( struct sk_buff *skb, struct net_device *dev, int port )
 799{
 800    unsigned long           flags;
 801    struct wl_private       *lp = wl_priv(dev);
 802    WVLAN_LFRAME            *txF = NULL;
 803    struct list_head        *element;
 804    /*------------------------------------------------------------------------*/
 805
 806    DBG_FUNC( "wl_tx" );
 807
 808    /* Grab the spinlock */
 809    wl_lock( lp, &flags );
 810
 811    if( lp->flags & WVLAN2_UIL_BUSY ) {
 812        DBG_WARNING( DbgInfo, "UIL has device blocked\n" );
 813        /* Start dropping packets here??? */
 814	wl_unlock( lp, &flags );
 815        return 1;
 816    }
 817
 818#ifdef USE_RTS
 819    if( lp->useRTS == 1 ) {
 820        DBG_PRINT( "RTS: we're getting a Tx...\n" );
 821	wl_unlock( lp, &flags );
 822        return 1;
 823    }
 824#endif  /* USE_RTS */
 825
 826    if( !lp->use_dma ) {
 827        /* Get an element from the queue */
 828        element = lp->txFree.next;
 829        txF = (WVLAN_LFRAME *)list_entry( element, WVLAN_LFRAME, node );
 830        if( txF == NULL ) {
 831            DBG_ERROR( DbgInfo, "Problem with list_entry\n" );
 832	    wl_unlock( lp, &flags );
 833            return 1;
 834        }
 835        /* Fill out the frame */
 836        txF->frame.skb = skb;
 837        txF->frame.port = port;
 838        /* Move the frame to the txQ */
 839        /* NOTE: Here's where we would do priority queueing */
 840        list_del( &( txF->node ));
 841        list_add( &( txF->node ), &( lp->txQ[0] ));
 842
 843        lp->txQ_count++;
 844        if( lp->txQ_count >= DEFAULT_NUM_TX_FRAMES ) {
 845            DBG_TX( DbgInfo, "Q Full: %d\n", lp->txQ_count );
 846            if( lp->netif_queue_on == TRUE ) {
 847                netif_stop_queue( lp->dev );
 848                WL_WDS_NETIF_STOP_QUEUE( lp );
 849                lp->netif_queue_on = FALSE;
 850            }
 851        }
 852    }
 853    wl_act_int_off( lp ); /* Disable Interrupts */
 854
 855    /* Send the data to the hardware using the appropriate method */
 856#ifdef ENABLE_DMA
 857    if( lp->use_dma ) {
 858        wl_send_dma( lp, skb, port );
 859    }
 860    else
 861#endif
 862    {
 863        wl_send( lp );
 864    }
 865    /* Re-enable Interrupts, release the spinlock and return */
 866    wl_act_int_on( lp );
 867    wl_unlock( lp, &flags );
 868    return 0;
 869} // wl_tx
 870/*============================================================================*/
 871
 872/*******************************************************************************
 873 *	wl_rx()
 874 *******************************************************************************
 875 *
 876 *  DESCRIPTION:
 877 *
 878 *      The routine which performs data reception.
 879 *
 880 *  PARAMETERS:
 881 *
 882 *      dev - a pointer to the device's net_device structure.
 883 *
 884 *  RETURNS:
 885 *
 886 *      0 on success
 887 *      1 on error
 888 *
 889 ******************************************************************************/
 890int wl_rx(struct net_device *dev)
 891{
 892    int                     port;
 893    struct sk_buff          *skb;
 894    struct wl_private       *lp = wl_priv(dev);
 895    int                     status;
 896    hcf_16                  pktlen;
 897    hcf_16                  hfs_stat;
 898    DESC_STRCT              *desc;
 899    /*------------------------------------------------------------------------*/
 900
 901    DBG_FUNC("wl_rx")
 902    DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev);
 903
 904    if(!( lp->flags & WVLAN2_UIL_BUSY )) {
 905
 906#ifdef USE_RTS
 907        if( lp->useRTS == 1 ) {
 908            DBG_PRINT( "RTS: We're getting an Rx...\n" );
 909            return -EIO;
 910        }
 911#endif  /* USE_RTS */
 912
 913        /* Read the HFS_STAT register from the lookahead buffer */
 914        hfs_stat = (hcf_16)(( lp->lookAheadBuf[HFS_STAT] ) |
 915                            ( lp->lookAheadBuf[HFS_STAT + 1] << 8 ));
 916
 917        /* Make sure the frame isn't bad */
 918        if(( hfs_stat & HFS_STAT_ERR ) != HCF_SUCCESS ) {
 919            DBG_WARNING( DbgInfo, "HFS_STAT_ERROR (0x%x) in Rx Packet\n",
 920                         lp->lookAheadBuf[HFS_STAT] );
 921            return -EIO;
 922        }
 923
 924        /* Determine what port this packet is for */
 925        port = ( hfs_stat >> 8 ) & 0x0007;
 926        DBG_RX( DbgInfo, "Rx frame for port %d\n", port );
 927
 928        pktlen = lp->hcfCtx.IFB_RxLen;
 929        if (pktlen != 0) {
 930            skb = ALLOC_SKB(pktlen);
 931            if (skb != NULL) {
 932                /* Set the netdev based on the port */
 933                switch( port ) {
 934#ifdef USE_WDS
 935                case 1:
 936                case 2:
 937                case 3:
 938                case 4:
 939                case 5:
 940                case 6:
 941                    skb->dev = lp->wds_port[port-1].dev;
 942                    break;
 943#endif  /* USE_WDS */
 944
 945                case 0:
 946                default:
 947                    skb->dev = dev;
 948                    break;
 949                }
 950
 951                desc = &( lp->desc_rx );
 952
 953                desc->next_desc_addr = NULL;
 954
 955/*
 956#define BLOCK_INPUT(buf, len) \
 957    desc->buf_addr = buf; \
 958    desc->BUF_SIZE = len; \
 959    status = hcf_rcv_msg(&(lp->hcfCtx), desc, 0)
 960*/
 961
 962                GET_PACKET( skb->dev, skb, pktlen );
 963
 964                if( status == HCF_SUCCESS ) {
 965                    netif_rx( skb );
 966
 967                    if( port == 0 ) {
 968                        lp->stats.rx_packets++;
 969                        lp->stats.rx_bytes += pktlen;
 970                    }
 971#ifdef USE_WDS
 972                    else
 973                    {
 974                        lp->wds_port[port-1].stats.rx_packets++;
 975                        lp->wds_port[port-1].stats.rx_bytes += pktlen;
 976                    }
 977#endif  /* USE_WDS */
 978
 979                    dev->last_rx = jiffies;
 980
 981#ifdef WIRELESS_EXT
 982#ifdef WIRELESS_SPY
 983                    if( lp->spydata.spy_number > 0 ) {
 984                        char *srcaddr = skb->mac.raw + MAC_ADDR_SIZE;
 985
 986                        wl_spy_gather( dev, srcaddr );
 987                    }
 988#endif /* WIRELESS_SPY */
 989#endif /* WIRELESS_EXT */
 990                } else {
 991                    DBG_ERROR( DbgInfo, "Rx request to card FAILED\n" );
 992
 993                    if( port == 0 ) {
 994                        lp->stats.rx_dropped++;
 995                    }
 996#ifdef USE_WDS
 997                    else
 998                    {
 999                        lp->wds_port[port-1].stats.rx_dropped++;
1000                    }
1001#endif  /* USE_WDS */
1002
1003                    dev_kfree_skb( skb );
1004                }
1005            } else {
1006                DBG_ERROR( DbgInfo, "Could not alloc skb\n" );
1007
1008                if( port == 0 ) {
1009                    lp->stats.rx_dropped++;
1010                }
1011#ifdef USE_WDS
1012                else
1013                {
1014                    lp->wds_port[port-1].stats.rx_dropped++;
1015                }
1016#endif  /* USE_WDS */
1017            }
1018        }
1019    }
1020
1021    return 0;
1022} // wl_rx
1023/*============================================================================*/
1024
1025/*******************************************************************************
1026 *	wl_multicast()
1027 *******************************************************************************
1028 *
1029 *  DESCRIPTION:
1030 *
1031 *      Function to handle multicast packets
1032 *
1033 *  PARAMETERS:
1034 *
1035 *      dev - a pointer to the device's net_device structure.
1036 *
1037 *  RETURNS:
1038 *
1039 *      N/A
1040 *
1041 ******************************************************************************/
1042#ifdef NEW_MULTICAST
1043
1044void wl_multicast( struct net_device *dev )
1045{
1046#if 1 //;? (HCF_TYPE) & HCF_TYPE_STA //;?should we return an error status in AP mode
1047//;?seems reasonable that even an AP-only driver could afford this small additional footprint
1048
1049    int                 x;
1050    struct netdev_hw_addr *ha;
1051    struct wl_private   *lp = wl_priv(dev);
1052    unsigned long       flags;
1053    /*------------------------------------------------------------------------*/
1054
1055    DBG_FUNC( "wl_multicast" );
1056    DBG_ENTER( DbgInfo );
1057    DBG_PARAM( DbgInfo, "dev", "%s (0x%p)", dev->name, dev );
1058
1059    if( !wl_adapter_is_open( dev )) {
1060        DBG_LEAVE( DbgInfo );
1061        return;
1062    }
1063
1064#if DBG
1065    if( DBG_FLAGS( DbgInfo ) & DBG_PARAM_ON ) {
1066        DBG_PRINT("  flags: %s%s%s\n",
1067            ( dev->flags & IFF_PROMISC ) ? "Promiscous " : "",
1068            ( dev->flags & IFF_MULTICAST ) ? "Multicast " : "",
1069            ( dev->flags & IFF_ALLMULTI ) ? "All-Multicast" : "" );
1070
1071        DBG_PRINT( "  mc_count: %d\n", netdev_mc_count(dev));
1072
1073	netdev_for_each_mc_addr(ha, dev)
1074	DBG_PRINT("    %pM (%d)\n", ha->addr, dev->addr_len);
1075    }
1076#endif /* DBG */
1077
1078    if(!( lp->flags & WVLAN2_UIL_BUSY )) {
1079
1080#ifdef USE_RTS
1081        if( lp->useRTS == 1 ) {
1082            DBG_TRACE( DbgInfo, "Skipping multicast, in RTS mode\n" );
1083
1084            DBG_LEAVE( DbgInfo );
1085            return;
1086        }
1087#endif  /* USE_RTS */
1088
1089        wl_lock( lp, &flags );
1090        wl_act_int_off( lp );
1091
1092		if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_STA  ) {
1093            if( dev->flags & IFF_PROMISC ) {
1094                /* Enable promiscuous mode */
1095                lp->ltvRecord.len       = 2;
1096                lp->ltvRecord.typ       = CFG_PROMISCUOUS_MODE;
1097                lp->ltvRecord.u.u16[0]  = CNV_INT_TO_LITTLE( 1 );
1098                DBG_PRINT( "Enabling Promiscuous mode (IFF_PROMISC)\n" );
1099                hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
1100            }
1101            else if ((netdev_mc_count(dev) > HCF_MAX_MULTICAST) ||
1102                    ( dev->flags & IFF_ALLMULTI )) {
1103                /* Shutting off this filter will enable all multicast frames to
1104                   be sent up from the device; however, this is a static RID, so
1105                   a call to wl_apply() is needed */
1106                lp->ltvRecord.len       = 2;
1107                lp->ltvRecord.typ       = CFG_CNF_RX_ALL_GROUP_ADDR;
1108                lp->ltvRecord.u.u16[0]  = CNV_INT_TO_LITTLE( 0 );
1109                DBG_PRINT( "Enabling all multicast mode (IFF_ALLMULTI)\n" );
1110                hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
1111                wl_apply( lp );
1112            }
1113            else if (!netdev_mc_empty(dev)) {
1114                /* Set the multicast addresses */
1115                lp->ltvRecord.len = ( netdev_mc_count(dev) * 3 ) + 1;
1116                lp->ltvRecord.typ = CFG_GROUP_ADDR;
1117
1118		x = 0;
1119		netdev_for_each_mc_addr(ha, dev)
1120                    memcpy(&(lp->ltvRecord.u.u8[x++ * ETH_ALEN]),
1121			   ha->addr, ETH_ALEN);
1122                DBG_PRINT( "Setting multicast list\n" );
1123                hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
1124            } else {
1125                /* Disable promiscuous mode */
1126                lp->ltvRecord.len       = 2;
1127                lp->ltvRecord.typ       = CFG_PROMISCUOUS_MODE;
1128                lp->ltvRecord.u.u16[0]  = CNV_INT_TO_LITTLE( 0 );
1129                DBG_PRINT( "Disabling Promiscuous mode\n" );
1130                hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
1131
1132                /* Disable multicast mode */
1133                lp->ltvRecord.len = 2;
1134                lp->ltvRecord.typ = CFG_GROUP_ADDR;
1135                DBG_PRINT( "Disabling Multicast mode\n" );
1136                hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
1137
1138                /* Turning on this filter will prevent all multicast frames from
1139                   being sent up from the device; however, this is a static RID,
1140                   so a call to wl_apply() is needed */
1141                lp->ltvRecord.len       = 2;
1142                lp->ltvRecord.typ       = CFG_CNF_RX_ALL_GROUP_ADDR;
1143                lp->ltvRecord.u.u16[0]  = CNV_INT_TO_LITTLE( 1 );
1144                DBG_PRINT( "Disabling all multicast mode (IFF_ALLMULTI)\n" );
1145                hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
1146                wl_apply( lp );
1147            }
1148        }
1149        wl_act_int_on( lp );
1150	wl_unlock( lp, &flags );
1151    }
1152    DBG_LEAVE( DbgInfo );
1153#endif /* HCF_STA */
1154} // wl_multicast
1155/*============================================================================*/
1156
1157#else /* NEW_MULTICAST */
1158
1159void wl_multicast( struct net_device *dev, int num_addrs, void *addrs )
1160{
1161    DBG_FUNC( "wl_multicast");
1162    DBG_ENTER(DbgInfo);
1163
1164    DBG_PARAM( DbgInfo, "dev", "%s (0x%p)", dev->name, dev );
1165    DBG_PARAM( DbgInfo, "num_addrs", "%d", num_addrs );
1166    DBG_PARAM( DbgInfo, "addrs", "0x%p", addrs );
1167
1168#error Obsolete set multicast interface!
1169
1170    DBG_LEAVE( DbgInfo );
1171} // wl_multicast
1172/*============================================================================*/
1173
1174#endif /* NEW_MULTICAST */
1175
1176static const struct net_device_ops wl_netdev_ops =
1177{
1178    .ndo_start_xmit         = &wl_tx_port0,
1179
1180    .ndo_set_config         = &wl_config,
1181    .ndo_get_stats          = &wl_stats,
1182    .ndo_set_multicast_list = &wl_multicast,
1183
1184    .ndo_init               = &wl_insert,
1185    .ndo_open               = &wl_adapter_open,
1186    .ndo_stop               = &wl_adapter_close,
1187    .ndo_do_ioctl           = &wl_ioctl,
1188
1189    .ndo_tx_timeout         = &wl_tx_timeout,
1190
1191#ifdef CONFIG_NET_POLL_CONTROLLER
1192    .ndo_poll_controller    = wl_poll,
1193#endif
1194};
1195
1196/*******************************************************************************
1197 *	wl_device_alloc()
1198 *******************************************************************************
1199 *
1200 *  DESCRIPTION:
1201 *
1202 *      Create instances of net_device and wl_private for the new adapter
1203 *  and register the device's entry points in the net_device structure.
1204 *
1205 *  PARAMETERS:
1206 *
1207 *      N/A
1208 *
1209 *  RETURNS:
1210 *
1211 *      a pointer to an allocated and initialized net_device struct for this
1212 *      device.
1213 *
1214 ******************************************************************************/
1215struct net_device * wl_device_alloc( void )
1216{
1217    struct net_device   *dev = NULL;
1218    struct wl_private   *lp = NULL;
1219    /*------------------------------------------------------------------------*/
1220
1221    DBG_FUNC( "wl_device_alloc" );
1222    DBG_ENTER( DbgInfo );
1223
1224    /* Alloc a net_device struct */
1225    dev = alloc_etherdev(sizeof(struct wl_private));
1226    if (!dev)
1227        return NULL;
1228
1229    /* Initialize the 'next' pointer in the struct. Currently only used for PCI,
1230       but do it here just in case it's used for other buses in the future */
1231    lp = wl_priv(dev);
1232
1233
1234    /* Check MTU */
1235    if( dev->mtu > MTU_MAX )
1236    {
1237	    DBG_WARNING( DbgInfo, "%s: MTU set too high, limiting to %d.\n",
1238                        dev->name, MTU_MAX );
1239    	dev->mtu = MTU_MAX;
1240    }
1241
1242    /* Setup the function table in the device structure. */
1243
1244    dev->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def;
1245    lp->wireless_data.spy_data = &lp->spy_data;
1246    dev->wireless_data = &lp->wireless_data;
1247
1248    dev->netdev_ops = &wl_netdev_ops;
1249
1250    dev->watchdog_timeo     = TX_TIMEOUT;
1251
1252    dev->ethtool_ops	    = &wl_ethtool_ops;
1253
1254    netif_stop_queue( dev );
1255
1256    /* Allocate virutal devices for WDS support if needed */
1257    WL_WDS_DEVICE_ALLOC( lp );
1258
1259    DBG_LEAVE( DbgInfo );
1260    return dev;
1261} // wl_device_alloc
1262/*============================================================================*/
1263
1264/*******************************************************************************
1265 *	wl_device_dealloc()
1266 *******************************************************************************
1267 *
1268 *  DESCRIPTION:
1269 *
1270 *      Free instances of net_device and wl_private strcutres for an adapter
1271 *  and perform basic cleanup.
1272 *
1273 *  PARAMETERS:
1274 *
1275 *      dev - a pointer to the device's net_device structure.
1276 *
1277 *  RETURNS:
1278 *
1279 *      N/A
1280 *
1281 ******************************************************************************/
1282void wl_device_dealloc( struct net_device *dev )
1283{
1284//    struct wl_private   *lp = wl_priv(dev);
1285    /*------------------------------------------------------------------------*/
1286
1287    DBG_FUNC( "wl_device_dealloc" );
1288    DBG_ENTER( DbgInfo );
1289
1290    /* Dealloc the WDS ports */
1291    WL_WDS_DEVICE_DEALLOC( lp );
1292
1293    free_netdev( dev );
1294
1295    DBG_LEAVE( DbgInfo );
1296    return;
1297} // wl_device_dealloc
1298/*============================================================================*/
1299
1300/*******************************************************************************
1301 *	wl_tx_port0()
1302 *******************************************************************************
1303 *
1304 *  DESCRIPTION:
1305 *
1306 *      The handler routine for Tx over HCF_PORT_0.
1307 *
1308 *  PARAMETERS:
1309 *
1310 *      skb - a pointer to the sk_buff to transmit.
1311 *      dev - a pointer to a net_device structure representing HCF_PORT_0.
1312 *
1313 *  RETURNS:
1314 *
1315 *      N/A
1316 *
1317 ******************************************************************************/
1318int wl_tx_port0( struct sk_buff *skb, struct net_device *dev )
1319{
1320    DBG_TX( DbgInfo, "Tx on Port 0\n" );
1321
1322    return wl_tx( skb, dev, HCF_PORT_0 );
1323#ifdef ENABLE_DMA
1324    return wl_tx_dma( skb, dev, HCF_PORT_0 );
1325#endif
1326} // wl_tx_port0
1327/*============================================================================*/
1328
1329#ifdef USE_WDS
1330
1331/*******************************************************************************
1332 *	wl_tx_port1()
1333 *******************************************************************************
1334 *
1335 *  DESCRIPTION:
1336 *
1337 *      The handler routine for Tx over HCF_PORT_1.
1338 *
1339 *  PARAMETERS:
1340 *
1341 *      skb - a pointer to the sk_buff to transmit.
1342 *      dev - a pointer to a net_device structure representing HCF_PORT_1.
1343 *
1344 *  RETURNS:
1345 *
1346 *      N/A
1347 *
1348 ******************************************************************************/
1349int wl_tx_port1( struct sk_buff *skb, struct net_device *dev )
1350{
1351    DBG_TX( DbgInfo, "Tx on Port 1\n" );
1352    return wl_tx( skb, dev, HCF_PORT_1 );
1353} // wl_tx_port1
1354/*============================================================================*/
1355
1356/*******************************************************************************
1357 *	wl_tx_port2()
1358 *******************************************************************************
1359 *
1360 *  DESCRIPTION:
1361 *
1362 *      The handler routine for Tx over HCF_PORT_2.
1363 *
1364 *  PARAMETERS:
1365 *
1366 *      skb - a pointer to the sk_buff to transmit.
1367 *      dev - a pointer to a net_device structure representing HCF_PORT_2.
1368 *
1369 *  RETURNS:
1370 *
1371 *      N/A
1372 *
1373 ******************************************************************************/
1374int wl_tx_port2( struct sk_buff *skb, struct net_device *dev )
1375{
1376    DBG_TX( DbgInfo, "Tx on Port 2\n" );
1377    return wl_tx( skb, dev, HCF_PORT_2 );
1378} // wl_tx_port2
1379/*============================================================================*/
1380
1381/*******************************************************************************
1382 *	wl_tx_port3()
1383 *******************************************************************************
1384 *
1385 *  DESCRIPTION:
1386 *
1387 *      The handler routine for Tx over HCF_PORT_3.
1388 *
1389 *  PARAMETERS:
1390 *
1391 *      skb - a pointer to the sk_buff to transmit.
1392 *      dev - a pointer to a net_device structure representing HCF_PORT_3.
1393 *
1394 *  RETURNS:
1395 *
1396 *      N/A
1397 *
1398 ******************************************************************************/
1399int wl_tx_port3( struct sk_buff *skb, struct net_device *dev )
1400{
1401    DBG_TX( DbgInfo, "Tx on Port 3\n" );
1402    return wl_tx( skb, dev, HCF_PORT_3 );
1403} // wl_tx_port3
1404/*============================================================================*/
1405
1406/*******************************************************************************
1407 *	wl_tx_port4()
1408 *******************************************************************************
1409 *
1410 *  DESCRIPTION:
1411 *
1412 *      The handler routine for Tx over HCF_PORT_4.
1413 *
1414 *  PARAMETERS:
1415 *
1416 *      skb - a pointer to the sk_buff to transmit.
1417 *      dev - a pointer to a net_device structure representing HCF_PORT_4.
1418 *
1419 *  RETURNS:
1420 *
1421 *      N/A
1422 *
1423 ******************************************************************************/
1424int wl_tx_port4( struct sk_buff *skb, struct net_device *dev )
1425{
1426    DBG_TX( DbgInfo, "Tx on Port 4\n" );
1427    return wl_tx( skb, dev, HCF_PORT_4 );
1428} // wl_tx_port4
1429/*============================================================================*/
1430
1431/*******************************************************************************
1432 *	wl_tx_port5()
1433 *******************************************************************************
1434 *
1435 *  DESCRIPTION:
1436 *
1437 *      The handler routine for Tx over HCF_PORT_5.
1438 *
1439 *  PARAMETERS:
1440 *
1441 *      skb - a pointer to the sk_buff to transmit.
1442 *      dev - a pointer to a net_device structure representing HCF_PORT_5.
1443 *
1444 *  RETURNS:
1445 *
1446 *      N/A
1447 *
1448 ******************************************************************************/
1449int wl_tx_port5( struct sk_buff *skb, struct net_device *dev )
1450{
1451    DBG_TX( DbgInfo, "Tx on Port 5\n" );
1452    return wl_tx( skb, dev, HCF_PORT_5 );
1453} // wl_tx_port5
1454/*============================================================================*/
1455
1456/*******************************************************************************
1457 *	wl_tx_port6()
1458 *******************************************************************************
1459 *
1460 *  DESCRIPTION:
1461 *
1462 *      The handler routine for Tx over HCF_PORT_6.
1463 *
1464 *  PARAMETERS:
1465 *
1466 *      skb - a pointer to the sk_buff to transmit.
1467 *      dev - a pointer to a net_device structure representing HCF_PORT_6.
1468 *
1469 *  RETURNS:
1470 *
1471 *      N/A
1472 *
1473 ******************************************************************************/
1474int wl_tx_port6( struct sk_buff *skb, struct net_device *dev )
1475{
1476    DBG_TX( DbgInfo, "Tx on Port 6\n" );
1477    return wl_tx( skb, dev, HCF_PORT_6 );
1478} // wl_tx_port6
1479/*============================================================================*/
1480
1481/*******************************************************************************
1482 *	wl_wds_device_alloc()
1483 *******************************************************************************
1484 *
1485 *  DESCRIPTION:
1486 *
1487 *      Create instances of net_device to represent the WDS ports, and register
1488 *  the device's entry points in the net_device structure.
1489 *
1490 *  PARAMETERS:
1491 *
1492 *      lp  - a pointer to the device's private adapter structure
1493 *
1494 *  RETURNS:
1495 *
1496 *      N/A, but will place pointers to the allocated and initialized net_device
1497 *      structs in the private adapter structure.
1498 *
1499 ******************************************************************************/
1500void wl_wds_device_alloc( struct wl_private *lp )
1501{
1502    int count;
1503    /*------------------------------------------------------------------------*/
1504
1505    DBG_FUNC( "wl_wds_device_alloc" );
1506    DBG_ENTER( DbgInfo );
1507
1508    /* WDS support requires additional net_device structs to be allocated,
1509       so that user space apps can use these virtual devices to specify the
1510       port on which to Tx/Rx */
1511    for( count = 0; count < NUM_WDS_PORTS; count++ ) {
1512        struct net_device *dev_wds = NULL;
1513
1514        dev_wds = kmalloc( sizeof( struct net_device ), GFP_KERNEL );
1515        memset( dev_wds, 0, sizeof( struct net_device ));
1516
1517        ether_setup( dev_wds );
1518
1519        lp->wds_port[count].dev = dev_wds;
1520
1521        /* Re-use wl_init for all the devices, as it currently does nothing, but
1522           is required. Re-use the stats/tx_timeout handler for all as well; the
1523           WDS port which is requesting these operations can be determined by
1524           the net_device pointer. Set the private member of all devices to point
1525           to the same net_device struct; that way, all information gets
1526           funnelled through the one "real" net_device. Name the WDS ports
1527           "wds<n>" */
1528        lp->wds_port[count].dev->init           = &wl_init;
1529        lp->wds_port[count].dev->get_stats      = &wl_stats;
1530        lp->wds_port[count].dev->tx_timeout     = &wl_tx_timeout;
1531        lp->wds_port[count].dev->watchdog_timeo = TX_TIMEOUT;
1532        lp->wds_port[count].dev->priv           = lp;
1533
1534        sprintf( lp->wds_port[count].dev->name, "wds%d", count );
1535    }
1536
1537    /* Register the Tx handlers */
1538    lp->wds_port[0].dev->hard_start_xmit = &wl_tx_port1;
1539    lp->wds_port[1].dev->hard_start_xmit = &wl_tx_port2;
1540    lp->wds_port[2].dev->hard_start_xmit = &wl_tx_port3;
1541    lp->wds_port[3].dev->hard_start_xmit = &wl_tx_port4;
1542    lp->wds_port[4].dev->hard_start_xmit = &wl_tx_port5;
1543    lp->wds_port[5].dev->hard_start_xmit = &wl_tx_port6;
1544
1545    WL_WDS_NETIF_STOP_QUEUE( lp );
1546
1547    DBG_LEAVE( DbgInfo );
1548    return;
1549} // wl_wds_device_alloc
1550/*============================================================================*/
1551
1552/*******************************************************************************
1553 *	wl_wds_device_dealloc()
1554 *******************************************************************************
1555 *
1556 *  DESCRIPTION:
1557 *
1558 *      Free instances of net_device structures used to support WDS.
1559 *
1560 *  PARAMETERS:
1561 *
1562 *      lp  - a pointer to the device's private adapter structure
1563 *
1564 *  RETURNS:
1565 *
1566 *      N/A
1567 *
1568 ******************************************************************************/
1569void wl_wds_device_dealloc( struct wl_private *lp )
1570{
1571    int count;
1572    /*------------------------------------------------------------------------*/
1573
1574    DBG_FUNC( "wl_wds_device_dealloc" );
1575    DBG_ENTER( DbgInfo );
1576
1577    for( count = 0; count < NUM_WDS_PORTS; count++ ) {
1578        struct net_device *dev_wds = NULL;
1579
1580        dev_wds = lp->wds_port[count].dev;
1581
1582        if( dev_wds != NULL ) {
1583            if( dev_wds->flags & IFF_UP ) {
1584                dev_close( dev_wds );
1585                dev_wds->flags &= ~( IFF_UP | IFF_RUNNING );
1586            }
1587
1588            free_netdev(dev_wds);
1589            lp->wds_port[count].dev = NULL;
1590        }
1591    }
1592
1593    DBG_LEAVE( DbgInfo );
1594    return;
1595} // wl_wds_device_dealloc
1596/*============================================================================*/
1597
1598/*******************************************************************************
1599 *	wl_wds_netif_start_queue()
1600 *******************************************************************************
1601 *
1602 *  DESCRIPTION:
1603 *
1604 *      Used to start the netif queues of all the "virtual" network devices
1605 *      which repesent the WDS ports.
1606 *
1607 *  PARAMETERS:
1608 *
1609 *      lp  - a pointer to the device's private adapter structure
1610 *
1611 *  RETURNS:
1612 *
1613 *      N/A
1614 *
1615 ******************************************************************************/
1616void wl_wds_netif_start_queue( struct wl_private *lp )
1617{
1618    int count;
1619    /*------------------------------------------------------------------------*/
1620
1621    if( lp != NULL ) {
1622        for( count = 0; count < NUM_WDS_PORTS; count++ ) {
1623            if( lp->wds_port[count].is_registered &&
1624                lp->wds_port[count].netif_queue_on == FALSE ) {
1625                netif_start_queue( lp->wds_port[count].dev );
1626                lp->wds_port[count].netif_queue_on = TRUE;
1627            }
1628        }
1629    }
1630
1631    return;
1632} // wl_wds_netif_start_queue
1633/*============================================================================*/
1634
1635/*******************************************************************************
1636 *	wl_wds_netif_stop_queue()
1637 *******************************************************************************
1638 *
1639 *  DESCRIPTION:
1640 *
1641 *      Used to stop the netif queues of all the "virtual" network devices
1642 *      which repesent the WDS ports.
1643 *
1644 *  PARAMETERS:
1645 *
1646 *      lp  - a pointer to the device's private adapter structure
1647 *
1648 *  RETURNS:
1649 *
1650 *      N/A
1651 *
1652 ******************************************************************************/
1653void wl_wds_netif_stop_queue( struct wl_private *lp )
1654{
1655    int count;
1656    /*------------------------------------------------------------------------*/
1657
1658    if( lp != NULL ) {
1659        for( count = 0; count < NUM_WDS_PORTS; count++ ) {
1660            if( lp->wds_port[count].is_registered &&
1661                lp->wds_port[count].netif_queue_on == TRUE ) {
1662                netif_stop_queue( lp->wds_port[count].

Large files files are truncated, but you can click here to view the full file