• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/bitops.h>
83 
84 #include <linux/netdevice.h>
85 #include <linux/ethtool.h>
86 #include <linux/etherdevice.h>
87 // #include <linux/skbuff.h>
88 // #include <linux/if_arp.h>
89 // #include <linux/ioport.h>
90 
91 #include <debug.h>
92 
93 #include <hcf.h>
94 #include <dhf.h>
95 // #include <hcfdef.h>
96 
97 #include <wl_if.h>
98 #include <wl_internal.h>
99 #include <wl_util.h>
100 #include <wl_priv.h>
101 #include <wl_main.h>
102 #include <wl_netdev.h>
103 #include <wl_wext.h>
104 
105 #ifdef USE_PROFILE
106 #include <wl_profile.h>
107 #endif  /* USE_PROFILE */
108 
109 #ifdef BUS_PCMCIA
110 #include <wl_cs.h>
111 #endif  /* BUS_PCMCIA */
112 
113 #ifdef BUS_PCI
114 #include <wl_pci.h>
115 #endif  /* BUS_PCI */
116 
117 
118 /*******************************************************************************
119  * global variables
120  ******************************************************************************/
121 #if DBG
122 extern dbg_info_t *DbgInfo;
123 #endif  /* DBG */
124 
125 
126 #if HCF_ENCAP
127 #define MTU_MAX (HCF_MAX_MSG - ETH_HLEN - 8)
128 #else
129 #define MTU_MAX (HCF_MAX_MSG - ETH_HLEN)
130 #endif
131 
132 //static int mtu = MTU_MAX;
133 //MODULE_PARM(mtu, "i");
134 //MODULE_PARM_DESC(mtu, "MTU");
135 
136 /*******************************************************************************
137  * macros
138  ******************************************************************************/
139 #define BLOCK_INPUT(buf, len) \
140     desc->buf_addr = buf; \
141     desc->BUF_SIZE = len; \
142     status = hcf_rcv_msg(&(lp->hcfCtx), desc, 0)
143 
144 #define BLOCK_INPUT_DMA(buf, len) memcpy( buf, desc_next->buf_addr, pktlen )
145 
146 /*******************************************************************************
147  * function prototypes
148  ******************************************************************************/
149 
150 /*******************************************************************************
151  *	wl_init()
152  *******************************************************************************
153  *
154  *  DESCRIPTION:
155  *
156  *      We never need to do anything when a "Wireless" device is "initialized"
157  *  by the net software, because we only register already-found cards.
158  *
159  *  PARAMETERS:
160  *
161  *      dev - a pointer to the device's net_device structure
162  *
163  *  RETURNS:
164  *
165  *      0 on success
166  *      errno value otherwise
167  *
168  ******************************************************************************/
wl_init(struct net_device * dev)169 int wl_init( struct net_device *dev )
170 {
171 //    unsigned long       flags;
172 //    struct wl_private   *lp = wl_priv(dev);
173     /*------------------------------------------------------------------------*/
174 
175     DBG_FUNC( "wl_init" );
176     DBG_ENTER( DbgInfo );
177 
178     DBG_PARAM( DbgInfo, "dev", "%s (0x%p)", dev->name, dev );
179 
180     /* Nothing to do, but grab the spinlock anyway just in case we ever need
181        this routine */
182 //  wl_lock( lp, &flags );
183 //  wl_unlock( lp, &flags );
184 
185     DBG_LEAVE( DbgInfo );
186     return 0;
187 } // wl_init
188 /*============================================================================*/
189 
190 /*******************************************************************************
191  *	wl_config()
192  *******************************************************************************
193  *
194  *  DESCRIPTION:
195  *
196  *      Implement the SIOCSIFMAP interface.
197  *
198  *  PARAMETERS:
199  *
200  *      dev - a pointer to the device's net_device structure
201  *      map - a pointer to the device's ifmap structure
202  *
203  *  RETURNS:
204  *
205  *      0 on success
206  *      errno otherwise
207  *
208  ******************************************************************************/
wl_config(struct net_device * dev,struct ifmap * map)209 int wl_config( struct net_device *dev, struct ifmap *map )
210 {
211     DBG_FUNC( "wl_config" );
212     DBG_ENTER( DbgInfo );
213 
214     DBG_PARAM( DbgInfo, "dev", "%s (0x%p)", dev->name, dev );
215     DBG_PARAM( DbgInfo, "map", "0x%p", map );
216 
217     /* The only thing we care about here is a port change. Since this not needed,
218        ignore the request. */
219     DBG_TRACE(DbgInfo, "%s: %s called.\n", dev->name, __func__);
220 
221     DBG_LEAVE( DbgInfo );
222     return 0;
223 } // wl_config
224 /*============================================================================*/
225 
226 /*******************************************************************************
227  *	wl_stats()
228  *******************************************************************************
229  *
230  *  DESCRIPTION:
231  *
232  *      Return the current device statistics.
233  *
234  *  PARAMETERS:
235  *
236  *      dev - a pointer to the device's net_device structure
237  *
238  *  RETURNS:
239  *
240  *      a pointer to a net_device_stats structure containing the network
241  *      statistics.
242  *
243  ******************************************************************************/
wl_stats(struct net_device * dev)244 struct net_device_stats *wl_stats( struct net_device *dev )
245 {
246 #ifdef USE_WDS
247     int                         count;
248 #endif  /* USE_WDS */
249     unsigned long               flags;
250     struct net_device_stats     *pStats;
251     struct wl_private           *lp = wl_priv(dev);
252     /*------------------------------------------------------------------------*/
253 
254     //DBG_FUNC( "wl_stats" );
255     //DBG_ENTER( DbgInfo );
256     //DBG_PARAM( DbgInfo, "dev", "%s (0x%p)", dev->name, dev );
257 
258     pStats = NULL;
259 
260     wl_lock( lp, &flags );
261 
262 #ifdef USE_RTS
263     if( lp->useRTS == 1 ) {
264 	wl_unlock( lp, &flags );
265 
266 	//DBG_LEAVE( DbgInfo );
267 	return NULL;
268     }
269 #endif  /* USE_RTS */
270 
271     /* Return the statistics for the appropriate device */
272 #ifdef USE_WDS
273 
274     for( count = 0; count < NUM_WDS_PORTS; count++ ) {
275 	if( dev == lp->wds_port[count].dev ) {
276 	    pStats = &( lp->wds_port[count].stats );
277 	}
278     }
279 
280 #endif  /* USE_WDS */
281 
282     /* If pStats is still NULL, then the device is not a WDS port */
283     if( pStats == NULL ) {
284         pStats = &( lp->stats );
285     }
286 
287     wl_unlock( lp, &flags );
288 
289     //DBG_LEAVE( DbgInfo );
290 
291     return pStats;
292 } // wl_stats
293 /*============================================================================*/
294 
295 /*******************************************************************************
296  *	wl_open()
297  *******************************************************************************
298  *
299  *  DESCRIPTION:
300  *
301  *      Open the device.
302  *
303  *  PARAMETERS:
304  *
305  *      dev - a pointer to the device's net_device structure
306  *
307  *  RETURNS:
308  *
309  *      0 on success
310  *      errno otherwise
311  *
312  ******************************************************************************/
wl_open(struct net_device * dev)313 int wl_open(struct net_device *dev)
314 {
315     int                 status = HCF_SUCCESS;
316     struct wl_private   *lp = wl_priv(dev);
317     unsigned long       flags;
318     /*------------------------------------------------------------------------*/
319 
320     DBG_FUNC( "wl_open" );
321     DBG_ENTER( DbgInfo );
322 
323     wl_lock( lp, &flags );
324 
325 #ifdef USE_RTS
326     if( lp->useRTS == 1 ) {
327 	DBG_TRACE( DbgInfo, "Skipping device open, in RTS mode\n" );
328 	wl_unlock( lp, &flags );
329 	DBG_LEAVE( DbgInfo );
330 	return -EIO;
331     }
332 #endif  /* USE_RTS */
333 
334 #ifdef USE_PROFILE
335     parse_config( dev );
336 #endif
337 
338     if( lp->portState == WVLAN_PORT_STATE_DISABLED ) {
339 	DBG_TRACE( DbgInfo, "Enabling Port 0\n" );
340 	status = wl_enable( lp );
341 
342         if( status != HCF_SUCCESS ) {
343             DBG_TRACE( DbgInfo, "Enable port 0 failed: 0x%x\n", status );
344         }
345     }
346 
347     // Holding the lock too long, make a gap to allow other processes
348     wl_unlock(lp, &flags);
349     wl_lock( lp, &flags );
350 
351     if ( strlen( lp->fw_image_filename ) ) {
352 	DBG_TRACE( DbgInfo, ";???? Kludgy way to force a download\n" );
353 	status = wl_go( lp );
354     } else {
355 	status = wl_apply( lp );
356     }
357 
358     // Holding the lock too long, make a gap to allow other processes
359     wl_unlock(lp, &flags);
360     wl_lock( lp, &flags );
361 
362     if( status != HCF_SUCCESS ) {
363 	// Unsuccessful, try reset of the card to recover
364 	status = wl_reset( dev );
365     }
366 
367     // Holding the lock too long, make a gap to allow other processes
368     wl_unlock(lp, &flags);
369     wl_lock( lp, &flags );
370 
371     if( status == HCF_SUCCESS ) {
372 	netif_carrier_on( dev );
373 	WL_WDS_NETIF_CARRIER_ON( lp );
374 
375 	lp->is_handling_int = WL_HANDLING_INT; // Start handling interrupts
376         wl_act_int_on( lp );
377 
378 	netif_start_queue( dev );
379 	WL_WDS_NETIF_START_QUEUE( lp );
380     } else {
381         wl_hcf_error( dev, status );		/* Report the error */
382         netif_device_detach( dev );		/* Stop the device and queue */
383     }
384 
385     wl_unlock( lp, &flags );
386 
387     DBG_LEAVE( DbgInfo );
388     return status;
389 } // wl_open
390 /*============================================================================*/
391 
392 /*******************************************************************************
393  *	wl_close()
394  *******************************************************************************
395  *
396  *  DESCRIPTION:
397  *
398  *      Close the device.
399  *
400  *  PARAMETERS:
401  *
402  *      dev - a pointer to the device's net_device structure
403  *
404  *  RETURNS:
405  *
406  *      0 on success
407  *      errno otherwise
408  *
409  ******************************************************************************/
wl_close(struct net_device * dev)410 int wl_close( struct net_device *dev )
411 {
412     struct wl_private   *lp = wl_priv(dev);
413     unsigned long   flags;
414     /*------------------------------------------------------------------------*/
415 
416     DBG_FUNC("wl_close");
417     DBG_ENTER(DbgInfo);
418     DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev);
419 
420     /* Mark the adapter as busy */
421     netif_stop_queue( dev );
422     WL_WDS_NETIF_STOP_QUEUE( lp );
423 
424     netif_carrier_off( dev );
425     WL_WDS_NETIF_CARRIER_OFF( lp );
426 
427     /* Shutdown the adapter:
428             Disable adapter interrupts
429             Stop Tx/Rx
430             Update statistics
431             Set low power mode
432     */
433 
434     wl_lock( lp, &flags );
435 
436     wl_act_int_off( lp );
437     lp->is_handling_int = WL_NOT_HANDLING_INT; // Stop handling interrupts
438 
439 #ifdef USE_RTS
440     if( lp->useRTS == 1 ) {
441 	DBG_TRACE( DbgInfo, "Skipping device close, in RTS mode\n" );
442 	wl_unlock( lp, &flags );
443 	DBG_LEAVE( DbgInfo );
444 	return -EIO;
445     }
446 #endif  /* USE_RTS */
447 
448     /* Disable the ports */
449     wl_disable( lp );
450 
451     wl_unlock( lp, &flags );
452 
453     DBG_LEAVE( DbgInfo );
454     return 0;
455 } // wl_close
456 /*============================================================================*/
457 
wl_get_drvinfo(struct net_device * dev,struct ethtool_drvinfo * info)458 static void wl_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
459 {
460     strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1);
461     strncpy(info->version, DRV_VERSION_STR, sizeof(info->version) - 1);
462 //	strncpy(info.fw_version, priv->fw_name,
463 //	sizeof(info.fw_version) - 1);
464 
465     if (dev->dev.parent) {
466     	dev_set_name(dev->dev.parent, "%s", info->bus_info);
467 	//strncpy(info->bus_info, dev->dev.parent->bus_id,
468 	//	sizeof(info->bus_info) - 1);
469     } else {
470 	snprintf(info->bus_info, sizeof(info->bus_info) - 1,
471 		"PCMCIA FIXME");
472 //		    "PCMCIA 0x%lx", priv->hw.iobase);
473     }
474 } // wl_get_drvinfo
475 
476 static struct ethtool_ops wl_ethtool_ops = {
477     .get_drvinfo = wl_get_drvinfo,
478     .get_link = ethtool_op_get_link,
479 };
480 
481 
482 /*******************************************************************************
483  *	wl_ioctl()
484  *******************************************************************************
485  *
486  *  DESCRIPTION:
487  *
488  *      The IOCTL handler for the device.
489  *
490  *  PARAMETERS:
491  *
492  *      dev - a pointer to the device's net_device struct.
493  *      rq  - a pointer to the IOCTL request buffer.
494  *      cmd - the IOCTL command code.
495  *
496  *  RETURNS:
497  *
498  *      0 on success
499  *      errno value otherwise
500  *
501  ******************************************************************************/
wl_ioctl(struct net_device * dev,struct ifreq * rq,int cmd)502 int wl_ioctl( struct net_device *dev, struct ifreq *rq, int cmd )
503 {
504     struct wl_private  *lp = wl_priv(dev);
505     unsigned long           flags;
506     int                     ret = 0;
507     /*------------------------------------------------------------------------*/
508 
509     DBG_FUNC( "wl_ioctl" );
510     DBG_ENTER(DbgInfo);
511     DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev);
512     DBG_PARAM(DbgInfo, "rq", "0x%p", rq);
513     DBG_PARAM(DbgInfo, "cmd", "0x%04x", cmd);
514 
515     wl_lock( lp, &flags );
516 
517     wl_act_int_off( lp );
518 
519 #ifdef USE_RTS
520     if( lp->useRTS == 1 ) {
521 	/* Handle any RTS IOCTL here */
522 	if( cmd == WL_IOCTL_RTS ) {
523 	    DBG_TRACE( DbgInfo, "IOCTL: WL_IOCTL_RTS\n" );
524 	    ret = wvlan_rts( (struct rtsreq *)rq, dev->base_addr );
525 	} else {
526 	    DBG_TRACE( DbgInfo, "IOCTL not supported in RTS mode: 0x%X\n", cmd );
527 	    ret = -EOPNOTSUPP;
528 	}
529 
530 	goto out_act_int_on_unlock;
531     }
532 #endif  /* USE_RTS */
533 
534     /* Only handle UIL IOCTL requests when the UIL has the system blocked. */
535     if( !(( lp->flags & WVLAN2_UIL_BUSY ) && ( cmd != WVLAN2_IOCTL_UIL ))) {
536 #ifdef USE_UIL
537 	struct uilreq  *urq = (struct uilreq *)rq;
538 #endif /* USE_UIL */
539 
540 	switch( cmd ) {
541 		// ================== Private IOCTLs (up to 16) ==================
542 #ifdef USE_UIL
543 	case WVLAN2_IOCTL_UIL:
544 	     DBG_TRACE( DbgInfo, "IOCTL: WVLAN2_IOCTL_UIL\n" );
545 	     ret = wvlan_uil( urq, lp );
546 	     break;
547 #endif  /* USE_UIL */
548 
549 	default:
550 	     DBG_TRACE(DbgInfo, "IOCTL CODE NOT SUPPORTED: 0x%X\n", cmd );
551 	     ret = -EOPNOTSUPP;
552 	     break;
553 	}
554     } else {
555 	DBG_WARNING( DbgInfo, "DEVICE IS BUSY, CANNOT PROCESS REQUEST\n" );
556 	ret = -EBUSY;
557     }
558 
559 #ifdef USE_RTS
560 out_act_int_on_unlock:
561 #endif  /* USE_RTS */
562     wl_act_int_on( lp );
563 
564     wl_unlock( lp, &flags );
565 
566     DBG_LEAVE( DbgInfo );
567     return ret;
568 } // wl_ioctl
569 /*============================================================================*/
570 
571 #ifdef CONFIG_NET_POLL_CONTROLLER
wl_poll(struct net_device * dev)572 void wl_poll(struct net_device *dev)
573 {
574     struct wl_private *lp = wl_priv(dev);
575     unsigned long flags;
576     struct pt_regs regs;
577 
578     wl_lock( lp, &flags );
579     wl_isr(dev->irq, dev, &regs);
580     wl_unlock( lp, &flags );
581 }
582 #endif
583 
584 /*******************************************************************************
585  *	wl_tx_timeout()
586  *******************************************************************************
587  *
588  *  DESCRIPTION:
589  *
590  *      The handler called when, for some reason, a Tx request is not completed.
591  *
592  *  PARAMETERS:
593  *
594  *      dev - a pointer to the device's net_device struct.
595  *
596  *  RETURNS:
597  *
598  *      N/A
599  *
600  ******************************************************************************/
wl_tx_timeout(struct net_device * dev)601 void wl_tx_timeout( struct net_device *dev )
602 {
603 #ifdef USE_WDS
604     int                     count;
605 #endif  /* USE_WDS */
606     unsigned long           flags;
607     struct wl_private       *lp = wl_priv(dev);
608     struct net_device_stats *pStats = NULL;
609     /*------------------------------------------------------------------------*/
610 
611     DBG_FUNC( "wl_tx_timeout" );
612     DBG_ENTER( DbgInfo );
613 
614     DBG_WARNING( DbgInfo, "%s: Transmit timeout.\n", dev->name );
615 
616     wl_lock( lp, &flags );
617 
618 #ifdef USE_RTS
619     if( lp->useRTS == 1 ) {
620 	DBG_TRACE( DbgInfo, "Skipping tx_timeout handler, in RTS mode\n" );
621 	wl_unlock( lp, &flags );
622 
623 	DBG_LEAVE( DbgInfo );
624 	return;
625     }
626 #endif  /* USE_RTS */
627 
628     /* Figure out which device (the "root" device or WDS port) this timeout
629        is for */
630 #ifdef USE_WDS
631 
632     for( count = 0; count < NUM_WDS_PORTS; count++ ) {
633 	if( dev == lp->wds_port[count].dev ) {
634 	    pStats = &( lp->wds_port[count].stats );
635 
636 	    /* Break the loop so that we can use the counter to access WDS
637 	       information in the private structure */
638 	    break;
639 	}
640     }
641 
642 #endif  /* USE_WDS */
643 
644     /* If pStats is still NULL, then the device is not a WDS port */
645     if( pStats == NULL ) {
646 	pStats = &( lp->stats );
647     }
648 
649     /* Accumulate the timeout error */
650     pStats->tx_errors++;
651 
652     wl_unlock( lp, &flags );
653 
654     DBG_LEAVE( DbgInfo );
655     return;
656 } // wl_tx_timeout
657 /*============================================================================*/
658 
659 /*******************************************************************************
660  *	wl_send()
661  *******************************************************************************
662  *
663  *  DESCRIPTION:
664  *
665  *      The routine which performs data transmits.
666  *
667  *  PARAMETERS:
668  *
669  *      lp  - a pointer to the device's wl_private struct.
670  *
671  *  RETURNS:
672  *
673  *      0 on success
674  *      1 on error
675  *
676  ******************************************************************************/
wl_send(struct wl_private * lp)677 int wl_send( struct wl_private *lp )
678 {
679 
680     int                 status;
681     DESC_STRCT          *desc;
682     WVLAN_LFRAME        *txF = NULL;
683     struct list_head    *element;
684     int                 len;
685     /*------------------------------------------------------------------------*/
686 
687     DBG_FUNC( "wl_send" );
688 
689     if( lp == NULL ) {
690         DBG_ERROR( DbgInfo, "Private adapter struct is NULL\n" );
691         return FALSE;
692     }
693     if( lp->dev == NULL ) {
694         DBG_ERROR( DbgInfo, "net_device struct in wl_private is NULL\n" );
695         return FALSE;
696     }
697 
698     /* Check for the availability of FIDs; if none are available, don't take any
699        frames off the txQ */
700     if( lp->hcfCtx.IFB_RscInd == 0 ) {
701         return FALSE;
702     }
703 
704     /* Reclaim the TxQ Elements and place them back on the free queue */
705     if( !list_empty( &( lp->txQ[0] ))) {
706         element = lp->txQ[0].next;
707 
708         txF = (WVLAN_LFRAME * )list_entry( element, WVLAN_LFRAME, node );
709         if( txF != NULL ) {
710             lp->txF.skb  = txF->frame.skb;
711             lp->txF.port = txF->frame.port;
712 
713             txF->frame.skb  = NULL;
714             txF->frame.port = 0;
715 
716             list_del( &( txF->node ));
717             list_add( element, &( lp->txFree ));
718 
719             lp->txQ_count--;
720 
721             if( lp->txQ_count < TX_Q_LOW_WATER_MARK ) {
722                 if( lp->netif_queue_on == FALSE ) {
723                     DBG_TX( DbgInfo, "Kickstarting Q: %d\n", lp->txQ_count );
724                     netif_wake_queue( lp->dev );
725                     WL_WDS_NETIF_WAKE_QUEUE( lp );
726                     lp->netif_queue_on = TRUE;
727                 }
728             }
729         }
730     }
731 
732     if( lp->txF.skb == NULL ) {
733         return FALSE;
734     }
735 
736     /* If the device has resources (FIDs) available, then Tx the packet */
737     /* Format the TxRequest and send it to the adapter */
738     len = lp->txF.skb->len < ETH_ZLEN ? ETH_ZLEN : lp->txF.skb->len;
739 
740     desc                    = &( lp->desc_tx );
741     desc->buf_addr          = lp->txF.skb->data;
742     desc->BUF_CNT           = len;
743     desc->next_desc_addr    = NULL;
744 
745     status = hcf_send_msg( &( lp->hcfCtx ), desc, lp->txF.port );
746 
747     if( status == HCF_SUCCESS ) {
748         lp->dev->trans_start = jiffies;
749 
750         DBG_TX( DbgInfo, "Transmit...\n" );
751 
752         if( lp->txF.port == HCF_PORT_0 ) {
753             lp->stats.tx_packets++;
754             lp->stats.tx_bytes += lp->txF.skb->len;
755         }
756 
757 #ifdef USE_WDS
758         else
759         {
760             lp->wds_port[(( lp->txF.port >> 8 ) - 1)].stats.tx_packets++;
761             lp->wds_port[(( lp->txF.port >> 8 ) - 1)].stats.tx_bytes += lp->txF.skb->len;
762         }
763 
764 #endif  /* USE_WDS */
765 
766         /* Free the skb and perform queue cleanup, as the buffer was
767             transmitted successfully */
768         dev_kfree_skb( lp->txF.skb );
769 
770         lp->txF.skb = NULL;
771         lp->txF.port = 0;
772     }
773 
774     return TRUE;
775 } // wl_send
776 /*============================================================================*/
777 
778 /*******************************************************************************
779  *	wl_tx()
780  *******************************************************************************
781  *
782  *  DESCRIPTION:
783  *
784  *      The Tx handler function for the network layer.
785  *
786  *  PARAMETERS:
787  *
788  *      skb - a pointer to the sk_buff structure containing the data to transfer.
789  *      dev - a pointer to the device's net_device structure.
790  *
791  *  RETURNS:
792  *
793  *      0 on success
794  *      1 on error
795  *
796  ******************************************************************************/
wl_tx(struct sk_buff * skb,struct net_device * dev,int port)797 int wl_tx( struct sk_buff *skb, struct net_device *dev, int port )
798 {
799     unsigned long           flags;
800     struct wl_private       *lp = wl_priv(dev);
801     WVLAN_LFRAME            *txF = NULL;
802     struct list_head        *element;
803     /*------------------------------------------------------------------------*/
804 
805     DBG_FUNC( "wl_tx" );
806 
807     /* Grab the spinlock */
808     wl_lock( lp, &flags );
809 
810     if( lp->flags & WVLAN2_UIL_BUSY ) {
811         DBG_WARNING( DbgInfo, "UIL has device blocked\n" );
812         /* Start dropping packets here??? */
813 	wl_unlock( lp, &flags );
814         return 1;
815     }
816 
817 #ifdef USE_RTS
818     if( lp->useRTS == 1 ) {
819         DBG_PRINT( "RTS: we're getting a Tx...\n" );
820 	wl_unlock( lp, &flags );
821         return 1;
822     }
823 #endif  /* USE_RTS */
824 
825     if( !lp->use_dma ) {
826         /* Get an element from the queue */
827         element = lp->txFree.next;
828         txF = (WVLAN_LFRAME *)list_entry( element, WVLAN_LFRAME, node );
829         if( txF == NULL ) {
830             DBG_ERROR( DbgInfo, "Problem with list_entry\n" );
831 	    wl_unlock( lp, &flags );
832             return 1;
833         }
834         /* Fill out the frame */
835         txF->frame.skb = skb;
836         txF->frame.port = port;
837         /* Move the frame to the txQ */
838         /* NOTE: Here's where we would do priority queueing */
839         list_del( &( txF->node ));
840         list_add( &( txF->node ), &( lp->txQ[0] ));
841 
842         lp->txQ_count++;
843         if( lp->txQ_count >= DEFAULT_NUM_TX_FRAMES ) {
844             DBG_TX( DbgInfo, "Q Full: %d\n", lp->txQ_count );
845             if( lp->netif_queue_on == TRUE ) {
846                 netif_stop_queue( lp->dev );
847                 WL_WDS_NETIF_STOP_QUEUE( lp );
848                 lp->netif_queue_on = FALSE;
849             }
850         }
851     }
852     wl_act_int_off( lp ); /* Disable Interrupts */
853 
854     /* Send the data to the hardware using the appropriate method */
855 #ifdef ENABLE_DMA
856     if( lp->use_dma ) {
857         wl_send_dma( lp, skb, port );
858     }
859     else
860 #endif
861     {
862         wl_send( lp );
863     }
864     /* Re-enable Interrupts, release the spinlock and return */
865     wl_act_int_on( lp );
866     wl_unlock( lp, &flags );
867     return 0;
868 } // wl_tx
869 /*============================================================================*/
870 
871 /*******************************************************************************
872  *	wl_rx()
873  *******************************************************************************
874  *
875  *  DESCRIPTION:
876  *
877  *      The routine which performs data reception.
878  *
879  *  PARAMETERS:
880  *
881  *      dev - a pointer to the device's net_device structure.
882  *
883  *  RETURNS:
884  *
885  *      0 on success
886  *      1 on error
887  *
888  ******************************************************************************/
wl_rx(struct net_device * dev)889 int wl_rx(struct net_device *dev)
890 {
891     int                     port;
892     struct sk_buff          *skb;
893     struct wl_private       *lp = wl_priv(dev);
894     int                     status;
895     hcf_16                  pktlen;
896     hcf_16                  hfs_stat;
897     DESC_STRCT              *desc;
898     /*------------------------------------------------------------------------*/
899 
900     DBG_FUNC("wl_rx")
901     DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev);
902 
903     if(!( lp->flags & WVLAN2_UIL_BUSY )) {
904 
905 #ifdef USE_RTS
906         if( lp->useRTS == 1 ) {
907             DBG_PRINT( "RTS: We're getting an Rx...\n" );
908             return -EIO;
909         }
910 #endif  /* USE_RTS */
911 
912         /* Read the HFS_STAT register from the lookahead buffer */
913         hfs_stat = (hcf_16)(( lp->lookAheadBuf[HFS_STAT] ) |
914                             ( lp->lookAheadBuf[HFS_STAT + 1] << 8 ));
915 
916         /* Make sure the frame isn't bad */
917         if(( hfs_stat & HFS_STAT_ERR ) != HCF_SUCCESS ) {
918             DBG_WARNING( DbgInfo, "HFS_STAT_ERROR (0x%x) in Rx Packet\n",
919                          lp->lookAheadBuf[HFS_STAT] );
920             return -EIO;
921         }
922 
923         /* Determine what port this packet is for */
924         port = ( hfs_stat >> 8 ) & 0x0007;
925         DBG_RX( DbgInfo, "Rx frame for port %d\n", port );
926 
927         pktlen = lp->hcfCtx.IFB_RxLen;
928         if (pktlen != 0) {
929             skb = ALLOC_SKB(pktlen);
930             if (skb != NULL) {
931                 /* Set the netdev based on the port */
932                 switch( port ) {
933 #ifdef USE_WDS
934                 case 1:
935                 case 2:
936                 case 3:
937                 case 4:
938                 case 5:
939                 case 6:
940                     skb->dev = lp->wds_port[port-1].dev;
941                     break;
942 #endif  /* USE_WDS */
943 
944                 case 0:
945                 default:
946                     skb->dev = dev;
947                     break;
948                 }
949 
950                 desc = &( lp->desc_rx );
951 
952                 desc->next_desc_addr = NULL;
953 
954 /*
955 #define BLOCK_INPUT(buf, len) \
956     desc->buf_addr = buf; \
957     desc->BUF_SIZE = len; \
958     status = hcf_rcv_msg(&(lp->hcfCtx), desc, 0)
959 */
960 
961                 GET_PACKET( skb->dev, skb, pktlen );
962 
963                 if( status == HCF_SUCCESS ) {
964                     netif_rx( skb );
965 
966                     if( port == 0 ) {
967                         lp->stats.rx_packets++;
968                         lp->stats.rx_bytes += pktlen;
969                     }
970 #ifdef USE_WDS
971                     else
972                     {
973                         lp->wds_port[port-1].stats.rx_packets++;
974                         lp->wds_port[port-1].stats.rx_bytes += pktlen;
975                     }
976 #endif  /* USE_WDS */
977 
978                     dev->last_rx = jiffies;
979 
980 #ifdef WIRELESS_EXT
981 #ifdef WIRELESS_SPY
982                     if( lp->spydata.spy_number > 0 ) {
983                         char *srcaddr = skb->mac.raw + MAC_ADDR_SIZE;
984 
985                         wl_spy_gather( dev, srcaddr );
986                     }
987 #endif /* WIRELESS_SPY */
988 #endif /* WIRELESS_EXT */
989                 } else {
990                     DBG_ERROR( DbgInfo, "Rx request to card FAILED\n" );
991 
992                     if( port == 0 ) {
993                         lp->stats.rx_dropped++;
994                     }
995 #ifdef USE_WDS
996                     else
997                     {
998                         lp->wds_port[port-1].stats.rx_dropped++;
999                     }
1000 #endif  /* USE_WDS */
1001 
1002                     dev_kfree_skb( skb );
1003                 }
1004             } else {
1005                 DBG_ERROR( DbgInfo, "Could not alloc skb\n" );
1006 
1007                 if( port == 0 ) {
1008                     lp->stats.rx_dropped++;
1009                 }
1010 #ifdef USE_WDS
1011                 else
1012                 {
1013                     lp->wds_port[port-1].stats.rx_dropped++;
1014                 }
1015 #endif  /* USE_WDS */
1016             }
1017         }
1018     }
1019 
1020     return 0;
1021 } // wl_rx
1022 /*============================================================================*/
1023 
1024 /*******************************************************************************
1025  *	wl_multicast()
1026  *******************************************************************************
1027  *
1028  *  DESCRIPTION:
1029  *
1030  *      Function to handle multicast packets
1031  *
1032  *  PARAMETERS:
1033  *
1034  *      dev - a pointer to the device's net_device structure.
1035  *
1036  *  RETURNS:
1037  *
1038  *      N/A
1039  *
1040  ******************************************************************************/
1041 #ifdef NEW_MULTICAST
1042 
wl_multicast(struct net_device * dev)1043 void wl_multicast( struct net_device *dev )
1044 {
1045 #if 1 //;? (HCF_TYPE) & HCF_TYPE_STA //;?should we return an error status in AP mode
1046 //;?seems reasonable that even an AP-only driver could afford this small additional footprint
1047 
1048     int                 x;
1049     struct netdev_hw_addr *ha;
1050     struct wl_private   *lp = wl_priv(dev);
1051     unsigned long       flags;
1052     /*------------------------------------------------------------------------*/
1053 
1054     DBG_FUNC( "wl_multicast" );
1055     DBG_ENTER( DbgInfo );
1056     DBG_PARAM( DbgInfo, "dev", "%s (0x%p)", dev->name, dev );
1057 
1058     if( !wl_adapter_is_open( dev )) {
1059         DBG_LEAVE( DbgInfo );
1060         return;
1061     }
1062 
1063 #if DBG
1064     if( DBG_FLAGS( DbgInfo ) & DBG_PARAM_ON ) {
1065         DBG_PRINT("  flags: %s%s%s\n",
1066             ( dev->flags & IFF_PROMISC ) ? "Promiscous " : "",
1067             ( dev->flags & IFF_MULTICAST ) ? "Multicast " : "",
1068             ( dev->flags & IFF_ALLMULTI ) ? "All-Multicast" : "" );
1069 
1070         DBG_PRINT( "  mc_count: %d\n", netdev_mc_count(dev));
1071 
1072 	netdev_for_each_mc_addr(ha, dev)
1073 	DBG_PRINT("    %pM (%d)\n", ha->addr, dev->addr_len);
1074     }
1075 #endif /* DBG */
1076 
1077     if(!( lp->flags & WVLAN2_UIL_BUSY )) {
1078 
1079 #ifdef USE_RTS
1080         if( lp->useRTS == 1 ) {
1081             DBG_TRACE( DbgInfo, "Skipping multicast, in RTS mode\n" );
1082 
1083             DBG_LEAVE( DbgInfo );
1084             return;
1085         }
1086 #endif  /* USE_RTS */
1087 
1088         wl_lock( lp, &flags );
1089         wl_act_int_off( lp );
1090 
1091 		if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_STA  ) {
1092             if( dev->flags & IFF_PROMISC ) {
1093                 /* Enable promiscuous mode */
1094                 lp->ltvRecord.len       = 2;
1095                 lp->ltvRecord.typ       = CFG_PROMISCUOUS_MODE;
1096                 lp->ltvRecord.u.u16[0]  = CNV_INT_TO_LITTLE( 1 );
1097                 DBG_PRINT( "Enabling Promiscuous mode (IFF_PROMISC)\n" );
1098                 hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
1099             }
1100             else if ((netdev_mc_count(dev) > HCF_MAX_MULTICAST) ||
1101                     ( dev->flags & IFF_ALLMULTI )) {
1102                 /* Shutting off this filter will enable all multicast frames to
1103                    be sent up from the device; however, this is a static RID, so
1104                    a call to wl_apply() is needed */
1105                 lp->ltvRecord.len       = 2;
1106                 lp->ltvRecord.typ       = CFG_CNF_RX_ALL_GROUP_ADDR;
1107                 lp->ltvRecord.u.u16[0]  = CNV_INT_TO_LITTLE( 0 );
1108                 DBG_PRINT( "Enabling all multicast mode (IFF_ALLMULTI)\n" );
1109                 hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
1110                 wl_apply( lp );
1111             }
1112             else if (!netdev_mc_empty(dev)) {
1113                 /* Set the multicast addresses */
1114                 lp->ltvRecord.len = ( netdev_mc_count(dev) * 3 ) + 1;
1115                 lp->ltvRecord.typ = CFG_GROUP_ADDR;
1116 
1117 		x = 0;
1118 		netdev_for_each_mc_addr(ha, dev)
1119                     memcpy(&(lp->ltvRecord.u.u8[x++ * ETH_ALEN]),
1120 			   ha->addr, ETH_ALEN);
1121                 DBG_PRINT( "Setting multicast list\n" );
1122                 hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
1123             } else {
1124                 /* Disable promiscuous mode */
1125                 lp->ltvRecord.len       = 2;
1126                 lp->ltvRecord.typ       = CFG_PROMISCUOUS_MODE;
1127                 lp->ltvRecord.u.u16[0]  = CNV_INT_TO_LITTLE( 0 );
1128                 DBG_PRINT( "Disabling Promiscuous mode\n" );
1129                 hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
1130 
1131                 /* Disable multicast mode */
1132                 lp->ltvRecord.len = 2;
1133                 lp->ltvRecord.typ = CFG_GROUP_ADDR;
1134                 DBG_PRINT( "Disabling Multicast mode\n" );
1135                 hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
1136 
1137                 /* Turning on this filter will prevent all multicast frames from
1138                    being sent up from the device; however, this is a static RID,
1139                    so a call to wl_apply() is needed */
1140                 lp->ltvRecord.len       = 2;
1141                 lp->ltvRecord.typ       = CFG_CNF_RX_ALL_GROUP_ADDR;
1142                 lp->ltvRecord.u.u16[0]  = CNV_INT_TO_LITTLE( 1 );
1143                 DBG_PRINT( "Disabling all multicast mode (IFF_ALLMULTI)\n" );
1144                 hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
1145                 wl_apply( lp );
1146             }
1147         }
1148         wl_act_int_on( lp );
1149 	wl_unlock( lp, &flags );
1150     }
1151     DBG_LEAVE( DbgInfo );
1152 #endif /* HCF_STA */
1153 } // wl_multicast
1154 /*============================================================================*/
1155 
1156 #else /* NEW_MULTICAST */
1157 
wl_multicast(struct net_device * dev,int num_addrs,void * addrs)1158 void wl_multicast( struct net_device *dev, int num_addrs, void *addrs )
1159 {
1160     DBG_FUNC( "wl_multicast");
1161     DBG_ENTER(DbgInfo);
1162 
1163     DBG_PARAM( DbgInfo, "dev", "%s (0x%p)", dev->name, dev );
1164     DBG_PARAM( DbgInfo, "num_addrs", "%d", num_addrs );
1165     DBG_PARAM( DbgInfo, "addrs", "0x%p", addrs );
1166 
1167 #error Obsolete set multicast interface!
1168 
1169     DBG_LEAVE( DbgInfo );
1170 } // wl_multicast
1171 /*============================================================================*/
1172 
1173 #endif /* NEW_MULTICAST */
1174 
1175 static const struct net_device_ops wl_netdev_ops =
1176 {
1177     .ndo_start_xmit         = &wl_tx_port0,
1178 
1179     .ndo_set_config         = &wl_config,
1180     .ndo_get_stats          = &wl_stats,
1181     .ndo_set_rx_mode        = &wl_multicast,
1182 
1183     .ndo_init               = &wl_insert,
1184     .ndo_open               = &wl_adapter_open,
1185     .ndo_stop               = &wl_adapter_close,
1186     .ndo_do_ioctl           = &wl_ioctl,
1187 
1188     .ndo_tx_timeout         = &wl_tx_timeout,
1189 
1190 #ifdef CONFIG_NET_POLL_CONTROLLER
1191     .ndo_poll_controller    = wl_poll,
1192 #endif
1193 };
1194 
1195 /*******************************************************************************
1196  *	wl_device_alloc()
1197  *******************************************************************************
1198  *
1199  *  DESCRIPTION:
1200  *
1201  *      Create instances of net_device and wl_private for the new adapter
1202  *  and register the device's entry points in the net_device structure.
1203  *
1204  *  PARAMETERS:
1205  *
1206  *      N/A
1207  *
1208  *  RETURNS:
1209  *
1210  *      a pointer to an allocated and initialized net_device struct for this
1211  *      device.
1212  *
1213  ******************************************************************************/
wl_device_alloc(void)1214 struct net_device * wl_device_alloc( void )
1215 {
1216     struct net_device   *dev = NULL;
1217     struct wl_private   *lp = NULL;
1218     /*------------------------------------------------------------------------*/
1219 
1220     DBG_FUNC( "wl_device_alloc" );
1221     DBG_ENTER( DbgInfo );
1222 
1223     /* Alloc a net_device struct */
1224     dev = alloc_etherdev(sizeof(struct wl_private));
1225     if (!dev)
1226         return NULL;
1227 
1228     /* Initialize the 'next' pointer in the struct. Currently only used for PCI,
1229        but do it here just in case it's used for other buses in the future */
1230     lp = wl_priv(dev);
1231 
1232 
1233     /* Check MTU */
1234     if( dev->mtu > MTU_MAX )
1235     {
1236 	    DBG_WARNING( DbgInfo, "%s: MTU set too high, limiting to %d.\n",
1237                         dev->name, MTU_MAX );
1238     	dev->mtu = MTU_MAX;
1239     }
1240 
1241     /* Setup the function table in the device structure. */
1242 
1243     dev->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def;
1244     lp->wireless_data.spy_data = &lp->spy_data;
1245     dev->wireless_data = &lp->wireless_data;
1246 
1247     dev->netdev_ops = &wl_netdev_ops;
1248 
1249     dev->watchdog_timeo     = TX_TIMEOUT;
1250 
1251     dev->ethtool_ops	    = &wl_ethtool_ops;
1252 
1253     netif_stop_queue( dev );
1254 
1255     /* Allocate virutal devices for WDS support if needed */
1256     WL_WDS_DEVICE_ALLOC( lp );
1257 
1258     DBG_LEAVE( DbgInfo );
1259     return dev;
1260 } // wl_device_alloc
1261 /*============================================================================*/
1262 
1263 /*******************************************************************************
1264  *	wl_device_dealloc()
1265  *******************************************************************************
1266  *
1267  *  DESCRIPTION:
1268  *
1269  *      Free instances of net_device and wl_private strcutres for an adapter
1270  *  and perform basic cleanup.
1271  *
1272  *  PARAMETERS:
1273  *
1274  *      dev - a pointer to the device's net_device structure.
1275  *
1276  *  RETURNS:
1277  *
1278  *      N/A
1279  *
1280  ******************************************************************************/
wl_device_dealloc(struct net_device * dev)1281 void wl_device_dealloc( struct net_device *dev )
1282 {
1283 //    struct wl_private   *lp = wl_priv(dev);
1284     /*------------------------------------------------------------------------*/
1285 
1286     DBG_FUNC( "wl_device_dealloc" );
1287     DBG_ENTER( DbgInfo );
1288 
1289     /* Dealloc the WDS ports */
1290     WL_WDS_DEVICE_DEALLOC( lp );
1291 
1292     free_netdev( dev );
1293 
1294     DBG_LEAVE( DbgInfo );
1295     return;
1296 } // wl_device_dealloc
1297 /*============================================================================*/
1298 
1299 /*******************************************************************************
1300  *	wl_tx_port0()
1301  *******************************************************************************
1302  *
1303  *  DESCRIPTION:
1304  *
1305  *      The handler routine for Tx over HCF_PORT_0.
1306  *
1307  *  PARAMETERS:
1308  *
1309  *      skb - a pointer to the sk_buff to transmit.
1310  *      dev - a pointer to a net_device structure representing HCF_PORT_0.
1311  *
1312  *  RETURNS:
1313  *
1314  *      N/A
1315  *
1316  ******************************************************************************/
wl_tx_port0(struct sk_buff * skb,struct net_device * dev)1317 int wl_tx_port0( struct sk_buff *skb, struct net_device *dev )
1318 {
1319     DBG_TX( DbgInfo, "Tx on Port 0\n" );
1320 
1321     return wl_tx( skb, dev, HCF_PORT_0 );
1322 #ifdef ENABLE_DMA
1323     return wl_tx_dma( skb, dev, HCF_PORT_0 );
1324 #endif
1325 } // wl_tx_port0
1326 /*============================================================================*/
1327 
1328 #ifdef USE_WDS
1329 
1330 /*******************************************************************************
1331  *	wl_tx_port1()
1332  *******************************************************************************
1333  *
1334  *  DESCRIPTION:
1335  *
1336  *      The handler routine for Tx over HCF_PORT_1.
1337  *
1338  *  PARAMETERS:
1339  *
1340  *      skb - a pointer to the sk_buff to transmit.
1341  *      dev - a pointer to a net_device structure representing HCF_PORT_1.
1342  *
1343  *  RETURNS:
1344  *
1345  *      N/A
1346  *
1347  ******************************************************************************/
wl_tx_port1(struct sk_buff * skb,struct net_device * dev)1348 int wl_tx_port1( struct sk_buff *skb, struct net_device *dev )
1349 {
1350     DBG_TX( DbgInfo, "Tx on Port 1\n" );
1351     return wl_tx( skb, dev, HCF_PORT_1 );
1352 } // wl_tx_port1
1353 /*============================================================================*/
1354 
1355 /*******************************************************************************
1356  *	wl_tx_port2()
1357  *******************************************************************************
1358  *
1359  *  DESCRIPTION:
1360  *
1361  *      The handler routine for Tx over HCF_PORT_2.
1362  *
1363  *  PARAMETERS:
1364  *
1365  *      skb - a pointer to the sk_buff to transmit.
1366  *      dev - a pointer to a net_device structure representing HCF_PORT_2.
1367  *
1368  *  RETURNS:
1369  *
1370  *      N/A
1371  *
1372  ******************************************************************************/
wl_tx_port2(struct sk_buff * skb,struct net_device * dev)1373 int wl_tx_port2( struct sk_buff *skb, struct net_device *dev )
1374 {
1375     DBG_TX( DbgInfo, "Tx on Port 2\n" );
1376     return wl_tx( skb, dev, HCF_PORT_2 );
1377 } // wl_tx_port2
1378 /*============================================================================*/
1379 
1380 /*******************************************************************************
1381  *	wl_tx_port3()
1382  *******************************************************************************
1383  *
1384  *  DESCRIPTION:
1385  *
1386  *      The handler routine for Tx over HCF_PORT_3.
1387  *
1388  *  PARAMETERS:
1389  *
1390  *      skb - a pointer to the sk_buff to transmit.
1391  *      dev - a pointer to a net_device structure representing HCF_PORT_3.
1392  *
1393  *  RETURNS:
1394  *
1395  *      N/A
1396  *
1397  ******************************************************************************/
wl_tx_port3(struct sk_buff * skb,struct net_device * dev)1398 int wl_tx_port3( struct sk_buff *skb, struct net_device *dev )
1399 {
1400     DBG_TX( DbgInfo, "Tx on Port 3\n" );
1401     return wl_tx( skb, dev, HCF_PORT_3 );
1402 } // wl_tx_port3
1403 /*============================================================================*/
1404 
1405 /*******************************************************************************
1406  *	wl_tx_port4()
1407  *******************************************************************************
1408  *
1409  *  DESCRIPTION:
1410  *
1411  *      The handler routine for Tx over HCF_PORT_4.
1412  *
1413  *  PARAMETERS:
1414  *
1415  *      skb - a pointer to the sk_buff to transmit.
1416  *      dev - a pointer to a net_device structure representing HCF_PORT_4.
1417  *
1418  *  RETURNS:
1419  *
1420  *      N/A
1421  *
1422  ******************************************************************************/
wl_tx_port4(struct sk_buff * skb,struct net_device * dev)1423 int wl_tx_port4( struct sk_buff *skb, struct net_device *dev )
1424 {
1425     DBG_TX( DbgInfo, "Tx on Port 4\n" );
1426     return wl_tx( skb, dev, HCF_PORT_4 );
1427 } // wl_tx_port4
1428 /*============================================================================*/
1429 
1430 /*******************************************************************************
1431  *	wl_tx_port5()
1432  *******************************************************************************
1433  *
1434  *  DESCRIPTION:
1435  *
1436  *      The handler routine for Tx over HCF_PORT_5.
1437  *
1438  *  PARAMETERS:
1439  *
1440  *      skb - a pointer to the sk_buff to transmit.
1441  *      dev - a pointer to a net_device structure representing HCF_PORT_5.
1442  *
1443  *  RETURNS:
1444  *
1445  *      N/A
1446  *
1447  ******************************************************************************/
wl_tx_port5(struct sk_buff * skb,struct net_device * dev)1448 int wl_tx_port5( struct sk_buff *skb, struct net_device *dev )
1449 {
1450     DBG_TX( DbgInfo, "Tx on Port 5\n" );
1451     return wl_tx( skb, dev, HCF_PORT_5 );
1452 } // wl_tx_port5
1453 /*============================================================================*/
1454 
1455 /*******************************************************************************
1456  *	wl_tx_port6()
1457  *******************************************************************************
1458  *
1459  *  DESCRIPTION:
1460  *
1461  *      The handler routine for Tx over HCF_PORT_6.
1462  *
1463  *  PARAMETERS:
1464  *
1465  *      skb - a pointer to the sk_buff to transmit.
1466  *      dev - a pointer to a net_device structure representing HCF_PORT_6.
1467  *
1468  *  RETURNS:
1469  *
1470  *      N/A
1471  *
1472  ******************************************************************************/
wl_tx_port6(struct sk_buff * skb,struct net_device * dev)1473 int wl_tx_port6( struct sk_buff *skb, struct net_device *dev )
1474 {
1475     DBG_TX( DbgInfo, "Tx on Port 6\n" );
1476     return wl_tx( skb, dev, HCF_PORT_6 );
1477 } // wl_tx_port6
1478 /*============================================================================*/
1479 
1480 /*******************************************************************************
1481  *	wl_wds_device_alloc()
1482  *******************************************************************************
1483  *
1484  *  DESCRIPTION:
1485  *
1486  *      Create instances of net_device to represent the WDS ports, and register
1487  *  the device's entry points in the net_device structure.
1488  *
1489  *  PARAMETERS:
1490  *
1491  *      lp  - a pointer to the device's private adapter structure
1492  *
1493  *  RETURNS:
1494  *
1495  *      N/A, but will place pointers to the allocated and initialized net_device
1496  *      structs in the private adapter structure.
1497  *
1498  ******************************************************************************/
wl_wds_device_alloc(struct wl_private * lp)1499 void wl_wds_device_alloc( struct wl_private *lp )
1500 {
1501     int count;
1502     /*------------------------------------------------------------------------*/
1503 
1504     DBG_FUNC( "wl_wds_device_alloc" );
1505     DBG_ENTER( DbgInfo );
1506 
1507     /* WDS support requires additional net_device structs to be allocated,
1508        so that user space apps can use these virtual devices to specify the
1509        port on which to Tx/Rx */
1510     for( count = 0; count < NUM_WDS_PORTS; count++ ) {
1511         struct net_device *dev_wds = NULL;
1512 
1513         dev_wds = kmalloc( sizeof( struct net_device ), GFP_KERNEL );
1514         memset( dev_wds, 0, sizeof( struct net_device ));
1515 
1516         ether_setup( dev_wds );
1517 
1518         lp->wds_port[count].dev = dev_wds;
1519 
1520         /* Re-use wl_init for all the devices, as it currently does nothing, but
1521            is required. Re-use the stats/tx_timeout handler for all as well; the
1522            WDS port which is requesting these operations can be determined by
1523            the net_device pointer. Set the private member of all devices to point
1524            to the same net_device struct; that way, all information gets
1525            funnelled through the one "real" net_device. Name the WDS ports
1526            "wds<n>" */
1527         lp->wds_port[count].dev->init           = &wl_init;
1528         lp->wds_port[count].dev->get_stats      = &wl_stats;
1529         lp->wds_port[count].dev->tx_timeout     = &wl_tx_timeout;
1530         lp->wds_port[count].dev->watchdog_timeo = TX_TIMEOUT;
1531         lp->wds_port[count].dev->priv           = lp;
1532 
1533         sprintf( lp->wds_port[count].dev->name, "wds%d", count );
1534     }
1535 
1536     /* Register the Tx handlers */
1537     lp->wds_port[0].dev->hard_start_xmit = &wl_tx_port1;
1538     lp->wds_port[1].dev->hard_start_xmit = &wl_tx_port2;
1539     lp->wds_port[2].dev->hard_start_xmit = &wl_tx_port3;
1540     lp->wds_port[3].dev->hard_start_xmit = &wl_tx_port4;
1541     lp->wds_port[4].dev->hard_start_xmit = &wl_tx_port5;
1542     lp->wds_port[5].dev->hard_start_xmit = &wl_tx_port6;
1543 
1544     WL_WDS_NETIF_STOP_QUEUE( lp );
1545 
1546     DBG_LEAVE( DbgInfo );
1547     return;
1548 } // wl_wds_device_alloc
1549 /*============================================================================*/
1550 
1551 /*******************************************************************************
1552  *	wl_wds_device_dealloc()
1553  *******************************************************************************
1554  *
1555  *  DESCRIPTION:
1556  *
1557  *      Free instances of net_device structures used to support WDS.
1558  *
1559  *  PARAMETERS:
1560  *
1561  *      lp  - a pointer to the device's private adapter structure
1562  *
1563  *  RETURNS:
1564  *
1565  *      N/A
1566  *
1567  ******************************************************************************/
wl_wds_device_dealloc(struct wl_private * lp)1568 void wl_wds_device_dealloc( struct wl_private *lp )
1569 {
1570     int count;
1571     /*------------------------------------------------------------------------*/
1572 
1573     DBG_FUNC( "wl_wds_device_dealloc" );
1574     DBG_ENTER( DbgInfo );
1575 
1576     for( count = 0; count < NUM_WDS_PORTS; count++ ) {
1577         struct net_device *dev_wds = NULL;
1578 
1579         dev_wds = lp->wds_port[count].dev;
1580 
1581         if( dev_wds != NULL ) {
1582             if( dev_wds->flags & IFF_UP ) {
1583                 dev_close( dev_wds );
1584                 dev_wds->flags &= ~( IFF_UP | IFF_RUNNING );
1585             }
1586 
1587             free_netdev(dev_wds);
1588             lp->wds_port[count].dev = NULL;
1589         }
1590     }
1591 
1592     DBG_LEAVE( DbgInfo );
1593     return;
1594 } // wl_wds_device_dealloc
1595 /*============================================================================*/
1596 
1597 /*******************************************************************************
1598  *	wl_wds_netif_start_queue()
1599  *******************************************************************************
1600  *
1601  *  DESCRIPTION:
1602  *
1603  *      Used to start the netif queues of all the "virtual" network devices
1604  *      which repesent the WDS ports.
1605  *
1606  *  PARAMETERS:
1607  *
1608  *      lp  - a pointer to the device's private adapter structure
1609  *
1610  *  RETURNS:
1611  *
1612  *      N/A
1613  *
1614  ******************************************************************************/
wl_wds_netif_start_queue(struct wl_private * lp)1615 void wl_wds_netif_start_queue( struct wl_private *lp )
1616 {
1617     int count;
1618     /*------------------------------------------------------------------------*/
1619 
1620     if( lp != NULL ) {
1621         for( count = 0; count < NUM_WDS_PORTS; count++ ) {
1622             if( lp->wds_port[count].is_registered &&
1623                 lp->wds_port[count].netif_queue_on == FALSE ) {
1624                 netif_start_queue( lp->wds_port[count].dev );
1625                 lp->wds_port[count].netif_queue_on = TRUE;
1626             }
1627         }
1628     }
1629 
1630     return;
1631 } // wl_wds_netif_start_queue
1632 /*============================================================================*/
1633 
1634 /*******************************************************************************
1635  *	wl_wds_netif_stop_queue()
1636  *******************************************************************************
1637  *
1638  *  DESCRIPTION:
1639  *
1640  *      Used to stop the netif queues of all the "virtual" network devices
1641  *      which repesent the WDS ports.
1642  *
1643  *  PARAMETERS:
1644  *
1645  *      lp  - a pointer to the device's private adapter structure
1646  *
1647  *  RETURNS:
1648  *
1649  *      N/A
1650  *
1651  ******************************************************************************/
wl_wds_netif_stop_queue(struct wl_private * lp)1652 void wl_wds_netif_stop_queue( struct wl_private *lp )
1653 {
1654     int count;
1655     /*------------------------------------------------------------------------*/
1656 
1657     if( lp != NULL ) {
1658         for( count = 0; count < NUM_WDS_PORTS; count++ ) {
1659             if( lp->wds_port[count].is_registered &&
1660                 lp->wds_port[count].netif_queue_on == TRUE ) {
1661                 netif_stop_queue( lp->wds_port[count].dev );
1662                 lp->wds_port[count].netif_queue_on = FALSE;
1663             }
1664         }
1665     }
1666 
1667     return;
1668 } // wl_wds_netif_stop_queue
1669 /*============================================================================*/
1670 
1671 /*******************************************************************************
1672  *	wl_wds_netif_wake_queue()
1673  *******************************************************************************
1674  *
1675  *  DESCRIPTION:
1676  *
1677  *      Used to wake the netif queues of all the "virtual" network devices
1678  *      which repesent the WDS ports.
1679  *
1680  *  PARAMETERS:
1681  *
1682  *      lp  - a pointer to the device's private adapter structure
1683  *
1684  *  RETURNS:
1685  *
1686  *      N/A
1687  *
1688  ******************************************************************************/
wl_wds_netif_wake_queue(struct wl_private * lp)1689 void wl_wds_netif_wake_queue( struct wl_private *lp )
1690 {
1691     int count;
1692     /*------------------------------------------------------------------------*/
1693 
1694     if( lp != NULL ) {
1695         for( count = 0; count < NUM_WDS_PORTS; count++ ) {
1696             if( lp->wds_port[count].is_registered &&
1697                 lp->wds_port[count].netif_queue_on == FALSE ) {
1698                 netif_wake_queue( lp->wds_port[count].dev );
1699                 lp->wds_port[count].netif_queue_on = TRUE;
1700             }
1701         }
1702     }
1703 
1704     return;
1705 } // wl_wds_netif_wake_queue
1706 /*============================================================================*/
1707 
1708 /*******************************************************************************
1709  *	wl_wds_netif_carrier_on()
1710  *******************************************************************************
1711  *
1712  *  DESCRIPTION:
1713  *
1714  *      Used to signal the network layer that carrier is present on all of the
1715  *      "virtual" network devices which repesent the WDS ports.
1716  *
1717  *  PARAMETERS:
1718  *
1719  *      lp  - a pointer to the device's private adapter structure
1720  *
1721  *  RETURNS:
1722  *
1723  *      N/A
1724  *
1725  ******************************************************************************/
wl_wds_netif_carrier_on(struct wl_private * lp)1726 void wl_wds_netif_carrier_on( struct wl_private *lp )
1727 {
1728     int count;
1729     /*------------------------------------------------------------------------*/
1730 
1731     if( lp != NULL ) {
1732         for( count = 0; count < NUM_WDS_PORTS; count++ ) {
1733             if( lp->wds_port[count].is_registered ) {
1734                 netif_carrier_on( lp->wds_port[count].dev );
1735             }
1736         }
1737     }
1738 
1739     return;
1740 } // wl_wds_netif_carrier_on
1741 /*============================================================================*/
1742 
1743 /*******************************************************************************
1744  *	wl_wds_netif_carrier_off()
1745  *******************************************************************************
1746  *
1747  *  DESCRIPTION:
1748  *
1749  *      Used to signal the network layer that carrier is NOT present on all of
1750  *      the "virtual" network devices which repesent the WDS ports.
1751  *
1752  *  PARAMETERS:
1753  *
1754  *      lp  - a pointer to the device's private adapter structure
1755  *
1756  *  RETURNS:
1757  *
1758  *      N/A
1759  *
1760  ******************************************************************************/
wl_wds_netif_carrier_off(struct wl_private * lp)1761 void wl_wds_netif_carrier_off( struct wl_private *lp )
1762 {
1763     int count;
1764     /*------------------------------------------------------------------------*/
1765 
1766     if( lp != NULL ) {
1767         for( count = 0; count < NUM_WDS_PORTS; count++ ) {
1768             if( lp->wds_port[count].is_registered ) {
1769                 netif_carrier_off( lp->wds_port[count].dev );
1770             }
1771         }
1772     }
1773 
1774     return;
1775 } // wl_wds_netif_carrier_off
1776 /*============================================================================*/
1777 
1778 #endif  /* USE_WDS */
1779 
1780 #ifdef ENABLE_DMA
1781 /*******************************************************************************
1782  *	wl_send_dma()
1783  *******************************************************************************
1784  *
1785  *  DESCRIPTION:
1786  *
1787  *      The routine which performs data transmits when using busmaster DMA.
1788  *
1789  *  PARAMETERS:
1790  *
1791  *      lp   - a pointer to the device's wl_private struct.
1792  *      skb  - a pointer to the network layer's data buffer.
1793  *      port - the Hermes port on which to transmit.
1794  *
1795  *  RETURNS:
1796  *
1797  *      0 on success
1798  *      1 on error
1799  *
1800  ******************************************************************************/
wl_send_dma(struct wl_private * lp,struct sk_buff * skb,int port)1801 int wl_send_dma( struct wl_private *lp, struct sk_buff *skb, int port )
1802 {
1803     int         len;
1804     DESC_STRCT *desc = NULL;
1805     DESC_STRCT *desc_next = NULL;
1806     /*------------------------------------------------------------------------*/
1807 
1808     DBG_FUNC( "wl_send_dma" );
1809 
1810     if( lp == NULL )
1811     {
1812         DBG_ERROR( DbgInfo, "Private adapter struct is NULL\n" );
1813         return FALSE;
1814     }
1815 
1816     if( lp->dev == NULL )
1817     {
1818         DBG_ERROR( DbgInfo, "net_device struct in wl_private is NULL\n" );
1819         return FALSE;
1820     }
1821 
1822     /* AGAIN, ALL THE QUEUEING DONE HERE IN I/O MODE IS NOT PERFORMED */
1823 
1824     if( skb == NULL )
1825     {
1826         DBG_WARNING (DbgInfo, "Nothing to send.\n");
1827         return FALSE;
1828     }
1829 
1830     len = skb->len;
1831 
1832     /* Get a free descriptor */
1833     desc = wl_pci_dma_get_tx_packet( lp );
1834 
1835     if( desc == NULL )
1836     {
1837         if( lp->netif_queue_on == TRUE ) {
1838             netif_stop_queue( lp->dev );
1839             WL_WDS_NETIF_STOP_QUEUE( lp );
1840             lp->netif_queue_on = FALSE;
1841 
1842             dev_kfree_skb( skb );
1843             return 0;
1844         }
1845     }
1846 
1847     SET_BUF_CNT( desc, /*HCF_DMA_FD_CNT*/HFS_ADDR_DEST );
1848     SET_BUF_SIZE( desc, HCF_DMA_TX_BUF1_SIZE );
1849 
1850     desc_next = desc->next_desc_addr;
1851 
1852     if( desc_next->buf_addr == NULL )
1853     {
1854         DBG_ERROR( DbgInfo, "DMA descriptor buf_addr is NULL\n" );
1855         return FALSE;
1856     }
1857 
1858     /* Copy the payload into the DMA packet */
1859     memcpy( desc_next->buf_addr, skb->data, len );
1860 
1861     SET_BUF_CNT( desc_next, len );
1862     SET_BUF_SIZE( desc_next, HCF_MAX_PACKET_SIZE );
1863 
1864     hcf_dma_tx_put( &( lp->hcfCtx ), desc, 0 );
1865 
1866     /* Free the skb and perform queue cleanup, as the buffer was
1867             transmitted successfully */
1868     dev_kfree_skb( skb );
1869 
1870     return TRUE;
1871 } // wl_send_dma
1872 /*============================================================================*/
1873 
1874 /*******************************************************************************
1875  *	wl_rx_dma()
1876  *******************************************************************************
1877  *
1878  *  DESCRIPTION:
1879  *
1880  *      The routine which performs data reception when using busmaster DMA.
1881  *
1882  *  PARAMETERS:
1883  *
1884  *      dev - a pointer to the device's net_device structure.
1885  *
1886  *  RETURNS:
1887  *
1888  *      0 on success
1889  *      1 on error
1890  *
1891  ******************************************************************************/
wl_rx_dma(struct net_device * dev)1892 int wl_rx_dma( struct net_device *dev )
1893 {
1894     int                      port;
1895     hcf_16                   pktlen;
1896     hcf_16                   hfs_stat;
1897     struct sk_buff          *skb;
1898     struct wl_private       *lp = NULL;
1899     DESC_STRCT              *desc, *desc_next;
1900     //CFG_MB_INFO_RANGE2_STRCT x;
1901     /*------------------------------------------------------------------------*/
1902 
1903     DBG_FUNC("wl_rx")
1904     DBG_PARAM(DbgInfo, "dev", "%s (0x%p)", dev->name, dev);
1905 
1906     if((( lp = dev->priv ) != NULL ) &&
1907 	!( lp->flags & WVLAN2_UIL_BUSY )) {
1908 
1909 #ifdef USE_RTS
1910         if( lp->useRTS == 1 ) {
1911             DBG_PRINT( "RTS: We're getting an Rx...\n" );
1912             return -EIO;
1913         }
1914 #endif  /* USE_RTS */
1915 
1916         //if( lp->dma.status == 0 )
1917         //{
1918             desc = hcf_dma_rx_get( &( lp->hcfCtx ));
1919 
1920             if( desc != NULL )
1921             {
1922                 /* Check and see if we rcvd. a WMP frame */
1923                 /*
1924                 if((( *(hcf_8 *)&desc->buf_addr[HFS_STAT] ) &
1925                     ( HFS_STAT_MSG_TYPE | HFS_STAT_ERR )) == HFS_STAT_WMP_MSG )
1926                 {
1927                     DBG_TRACE( DbgInfo, "Got a WMP frame\n" );
1928 
1929                     x.len = sizeof( CFG_MB_INFO_RANGE2_STRCT ) / sizeof( hcf_16 );
1930 				    x.typ = CFG_MB_INFO;
1931 				    x.base_typ = CFG_WMP;
1932 				    x.frag_cnt = 2;
1933 				    x.frag_buf[0].frag_len  = GET_BUF_CNT( descp ) / sizeof( hcf_16 );
1934 				    x.frag_buf[0].frag_addr = (hcf_8 *) descp->buf_addr ;
1935 				    x.frag_buf[1].frag_len  = ( GET_BUF_CNT( descp->next_desc_addr ) + 1 ) / sizeof( hcf_16 );
1936 				    x.frag_buf[1].frag_addr = (hcf_8 *) descp->next_desc_addr->buf_addr ;
1937 
1938                     hcf_put_info( &( lp->hcfCtx ), (LTVP)&x );
1939                 }
1940                 */
1941 
1942                 desc_next = desc->next_desc_addr;
1943 
1944                 /* Make sure the buffer isn't empty */
1945                 if( GET_BUF_CNT( desc ) == 0 ) {
1946                     DBG_WARNING( DbgInfo, "Buffer is empty!\n" );
1947 
1948                     /* Give the descriptor back to the HCF */
1949                     hcf_dma_rx_put( &( lp->hcfCtx ), desc );
1950                     return -EIO;
1951                 }
1952 
1953                 /* Read the HFS_STAT register from the lookahead buffer */
1954                 hfs_stat = (hcf_16)( desc->buf_addr[HFS_STAT/2] );
1955 
1956                 /* Make sure the frame isn't bad */
1957                 if(( hfs_stat & HFS_STAT_ERR ) != HCF_SUCCESS )
1958                 {
1959                     DBG_WARNING( DbgInfo, "HFS_STAT_ERROR (0x%x) in Rx Packet\n",
1960                                 desc->buf_addr[HFS_STAT/2] );
1961 
1962                     /* Give the descriptor back to the HCF */
1963                     hcf_dma_rx_put( &( lp->hcfCtx ), desc );
1964                     return -EIO;
1965                 }
1966 
1967                 /* Determine what port this packet is for */
1968                 port = ( hfs_stat >> 8 ) & 0x0007;
1969                 DBG_RX( DbgInfo, "Rx frame for port %d\n", port );
1970 
1971                 pktlen = GET_BUF_CNT(desc_next);
1972                 if (pktlen != 0) {
1973                     skb = ALLOC_SKB(pktlen);
1974                     if (skb != NULL) {
1975                         switch( port ) {
1976 #ifdef USE_WDS
1977                         case 1:
1978                         case 2:
1979                         case 3:
1980                         case 4:
1981                         case 5:
1982                         case 6:
1983                             skb->dev = lp->wds_port[port-1].dev;
1984                             break;
1985 #endif  /* USE_WDS */
1986 
1987                         case 0:
1988                         default:
1989                             skb->dev = dev;
1990                             break;
1991                         }
1992 
1993                         GET_PACKET_DMA( skb->dev, skb, pktlen );
1994 
1995                         /* Give the descriptor back to the HCF */
1996                         hcf_dma_rx_put( &( lp->hcfCtx ), desc );
1997 
1998                         netif_rx( skb );
1999 
2000                         if( port == 0 ) {
2001                             lp->stats.rx_packets++;
2002                             lp->stats.rx_bytes += pktlen;
2003                         }
2004 #ifdef USE_WDS
2005                         else
2006                         {
2007                             lp->wds_port[port-1].stats.rx_packets++;
2008                             lp->wds_port[port-1].stats.rx_bytes += pktlen;
2009                         }
2010 #endif  /* USE_WDS */
2011 
2012                         dev->last_rx = jiffies;
2013 
2014                     } else {
2015                         DBG_ERROR( DbgInfo, "Could not alloc skb\n" );
2016 
2017                         if( port == 0 )
2018 	                    {
2019 	                        lp->stats.rx_dropped++;
2020 	                    }
2021 #ifdef USE_WDS
2022                         else
2023                         {
2024                             lp->wds_port[port-1].stats.rx_dropped++;
2025                         }
2026 #endif  /* USE_WDS */
2027                     }
2028                 }
2029             }
2030         //}
2031     }
2032 
2033     return 0;
2034 } // wl_rx_dma
2035 /*============================================================================*/
2036 #endif  // ENABLE_DMA
2037