source: rtems/c/src/lib/libbsp/i386/pc386/3c509/3c509.c @ 6daada6

4.104.114.84.95
Last change on this file since 6daada6 was 6daada6, checked in by Jennifer Averett <Jennifer.Averett@…>, on 05/06/05 at 19:53:03

2005-05-06 Jennifer Averett <jennifer.averett@…>

  • 3c509/3c509.c, clock/ckinit.c, console/console.c, console/fb_vga.c, console/inch.c, console/ps2_mouse.c, console/serial_mouse.c, ne2000/ne2000.c, timer/timer.c, wd8003/wd8003.c: Moved irq.h to bsp subdirectory.
  • Property mode set to 100644
File size: 44.6 KB
Line 
1/**********************************************************************************
2 * $Header$
3 *
4 * Ported by Rosimildo da Silva.
5 * ConnectTel,Inc.
6 * e-mail: rdasilva@connecttel.com
7 *
8 * MODULE DESCRIPTION:
9 * RTEMS driver for 3COM 3C509 Ethernet Card.
10 * The driver has been tested on PC with a single network card.
11 *
12 *
13 * This driver was based on the FreeBSD implementation( if_ep.c ) of the 3c5x9
14 * family and on the network framework of the RTEMS network driver.
15 * ( WD80x3 by  Eric Norum ).
16 * See notes below:
17 *
18 ******************************************************************************
19 * Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca>
20 * All rights reserved.
21 *
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
25 * 1. Redistributions of source code must retain the above copyright
26 *    notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 *    notice, this list of conditions and the following disclaimer in the
29 *    documentation and/or other materials provided with the distribution.
30 * 3. All advertising materials mentioning features or use of this software
31 *    must display the following acknowledgement:
32 *      This product includes software developed by Herb Peyerl.
33 * 4. The name of Herb Peyerl may not be used to endorse or promote products
34 *    derived from this software without specific prior written permission.
35 *
36 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
37 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
39 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
40 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
45 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46 *
47 *******************************************************************************
48 *
49 * RTEMS driver for M68360 WD1 Ethernet
50 *
51 * W. Eric Norum
52 * Saskatchewan Accelerator Laboratory
53 * University of Saskatchewan
54 * Saskatoon, Saskatchewan, CANADA
55 * eric@skatter.usask.ca
56 *******************************************************************************
57 *
58 *
59 * MODIFICATION/HISTORY:
60 * $Log$
61 * Revision 1.7  2005/05/03 14:20:07  jennifer
62 * 2005-05-03   Jennifer Averett <jennifer.averett@oarcorp.com>
63 *
64 *      * 3c509/3c509.c, ne2000/ne2000.c: Modified parameters to
65 *      remove warnings.
66 *      * console/console.c, wd8003/wd8003.c: Added support for
67 *      addition of parameter in ISRs.
68 *
69 * Revision 1.6  2005/04/26 23:03:51  joel
70 * 2005-04-26   Joel Sherrill <joel@OARcorp.com>
71 *
72 *      * 3c509/3c509.c, wd8003/wd8003.c: Eliminate warnings.
73 *
74 * Revision 1.5  2004/07/25 14:21:43  joel
75 * 2004-07-25   Joel Sherrill <joel@OARcorp.com>
76 *
77 *      * 3c509/3c509.c: Add <sys/errno.h>.
78 *      * startup/linkcmds: Add .jcr section.
79 *
80 * Revision 1.4  2004/04/21 16:01:33  ralf
81 * Remove duplicate white lines.
82 *
83 * Revision 1.3  2004/04/21 10:42:43  ralf
84 * Remove stray white spaces.
85 *
86 * Revision 1.2  1999/12/13 21:21:31  joel
87 * Warning removal patch from Philip A. Prindeville <philipp@zembu.com>.
88 *
89 * Revision 1.1  1999/05/14 16:23:42  joel
90 * Added 3COM 3C509 driver from Rosimildo DaSilva <rdasilva@connecttel.com>.
91 *
92 *
93 **********************************************************************************/
94
95#include <bsp.h>
96
97#include <stdio.h>
98#include <stdarg.h>
99#include <sys/errno.h>
100#include <rtems/error.h>
101#include <rtems/rtems_bsdnet.h>
102
103#include <sys/param.h>
104#include <sys/mbuf.h>
105#include <sys/socket.h>
106#include <sys/sockio.h>
107#include <sys/libkern.h>
108
109#include <net/if.h>
110#include <netinet/in.h>
111#include <netinet/if_ether.h>
112
113#include <bsp/irq.h>
114
115/* Local includes */
116#include "3c509.h"
117#include "elink.h"
118
119/* #define      ET_MINLEN 60 */         /* minimum message length */
120
121/*
122 * Number of WDs supported by this driver
123 */
124#define NWDDRIVER       1
125
126/*
127 * Default number of buffer descriptors set aside for this driver.
128 * The number of transmit buffer descriptors has to be quite large
129 * since a single frame often uses four or more buffer descriptors.
130 */
131/*
132#define RX_BUF_COUNT     15
133#define TX_BUF_COUNT     4
134#define TX_BD_PER_BUF    4
135*/
136
137/*
138 * RTEMS event used by interrupt handler to signal driver tasks.
139 * This must not be any of the events used by the network task synchronization.
140 */
141#define INTERRUPT_EVENT                 RTEMS_EVENT_1
142
143/*
144 * RTEMS event used to start transmit daemon.
145 * This must not be the same as INTERRUPT_EVENT.
146 */
147#define START_TRANSMIT_EVENT    RTEMS_EVENT_2
148
149/*
150 * Receive buffer size -- Allow for a full ethernet packet including CRC
151 */
152
153/*
154#define RBUF_SIZE       1520
155
156#if (MCLBYTES < RBUF_SIZE)
157# error "Driver must have MCLBYTES > RBUF_SIZE"
158#endif
159*/
160
161/* network driver name */
162#define NET_DRIVER_NAME         "ep"
163
164/*
165 * Per device structure.
166 *
167 * XXX Note:  id_conflicts should either become an array of things we're
168 * specifically allowed to conflict with or be subsumed into some
169 * more powerful mechanism for detecting and dealing with multiple types
170 * of non-fatal conflict.  -jkh XXX
171 */
172struct isa_device
173{
174  int   id_id;          /* device id */
175  int   id_unit;        /* unit number */
176  int   id_iobase;      /* base i/o address */
177  u_int id_irq;         /* interrupt request */
178};
179
180struct ep_board
181{
182  int epb_addr;         /* address of this board */
183  char epb_used;                /* was this entry already used for configuring ? */
184                                        /* data from EEPROM for later use */
185  u_short eth_addr[3];  /* Ethernet address */
186  u_short prod_id;              /* product ID */
187  u_short res_cfg;              /* resource configuration */
188};
189
190/*
191 * Ethernet software status per interface.
192 */
193struct ep_softc
194{
195    struct arpcom arpcom;       /* Ethernet common part          */
196    int ep_io_addr;                     /* i/o bus address                       */
197    struct mbuf *top, *mcur;
198    short cur_len;
199    u_short ep_connectors;      /* Connectors on this card.      */
200    u_char ep_connector;        /* Configured connector.         */
201    int stat;                           /* some flags                            */
202    struct ep_board *epb;
203    int unit;
204
205    rtems_irq_connect_data   irqInfo;
206    rtems_id                     rxDaemonTid;
207    rtems_id                     txDaemonTid;
208
209    int                  acceptBroadcast;
210
211    short tx_underrun;
212    short rx_no_first;
213    short rx_no_mbuf;
214    short rx_bpf_disc;
215    short rx_overrunf;
216    short rx_overrunl;
217};
218
219/*  static unsigned long loopc; */
220static volatile unsigned long overrun;
221static volatile unsigned long resend;
222static struct ep_softc ep_softc[ NWDDRIVER ];
223static struct isa_device isa_dev[ NWDDRIVER ] =
224{
225  { 0,                  /* device id                            */
226    0,                  /* unit number                          */
227    -1,         /* base i/o address   ???       */
228    0                   /* interrupt request  ???       */
229  }
230};
231
232static  u_long  ep_unit;
233static  int         ep_boards;
234struct  ep_board ep_board[ EP_MAX_BOARDS + 1];
235static  int ep_current_tag = EP_LAST_TAG + 1;
236static  char *ep_conn_type[] = {"UTP", "AUI", "???", "BNC"};
237
238#define ep_ftst(f) (sc->stat&(f))
239#define ep_fset(f) (sc->stat|=(f))
240#define ep_frst(f) (sc->stat&=~(f))
241
242/* forward declarations for functions */
243static int ep_attach( struct ep_softc *sc );
244static int ep_isa_probe( struct isa_device *is );
245static void epinit(  struct ep_softc *sc );
246static void epread( register struct ep_softc *sc );
247static void epstart( struct ifnet *ifp );
248static void epread( register struct ep_softc *sc );
249static int ep_isa_attach( struct isa_device *is );
250static int get_eeprom_data( int id_port, int offset );
251static void ep_intr( struct ep_softc *sc );
252
253/* external functions */
254extern void Wait_X_ms( unsigned int timeToWait );  /* timer.c ??? */
255
256/**********************************************************************************
257 *
258 * DESCRIPTION: Writes a buffer of data to the I/O port. The data is sent to the
259 *                              port as 32 bits units( 4 bytes ).
260 *
261 * RETURNS: nothing.
262 *
263 **********************************************************************************/
264static __inline void outsl( unsigned short io_addr, uint8_t *out_data, int len )
265{
266   u_long *pl = ( u_long *)out_data;
267   while( len-- )
268   {
269     outport_long( io_addr, *pl );
270         pl++;
271   }
272}
273
274/**********************************************************************************
275 *
276 * DESCRIPTION: Writes a buffer of data to the I/O port. The data is sent to the
277 *                              port as 16 bits units( 2 bytes ).
278 *
279 * RETURNS:
280 *
281 **********************************************************************************/
282static __inline void outsw( unsigned short io_addr, uint8_t *out_data, int len )
283{
284   u_short *ps = ( u_short *)out_data;
285   while( len-- )
286   {
287     outport_word( io_addr, *ps );
288         ps++;
289   }
290}
291
292/**********************************************************************************
293 *
294 * DESCRIPTION: Writes a buffer of data to the I/O port. The data is sent to the
295 *                              port as 8 bits units( 1 byte ).
296 *
297 * RETURNS: nothing
298 *
299 **********************************************************************************/
300static __inline void outsb( unsigned short io_addr, uint8_t *out_data, int len )
301{
302   while( len-- )
303   {
304     outport_byte( io_addr, *out_data );
305         out_data++;
306   }
307}
308
309/**********************************************************************************
310 *
311 * DESCRIPTION: Read a buffer of data from an I/O port. The data is read as 16 bits
312 *                          units or 2 bytes.
313 *
314 * RETURNS: nothing.
315 *
316 **********************************************************************************/
317static __inline void insw( unsigned short io_addr, uint8_t *in_data, int len )
318{
319   u_short *ps = ( u_short *)in_data;
320   while( len-- )
321   {
322     inport_word( io_addr, *ps );
323         ps++;
324   }
325}
326
327/**********************************************************************************
328 *
329 * DESCRIPTION: Read a buffer of data from an I/O port. The data is read as 32 bits
330 *                          units or 4 bytes.
331 *
332 * RETURNS: nothing.
333 *
334 **********************************************************************************/
335static __inline void insl( unsigned short io_addr, uint8_t *in_data, int len )
336{
337   u_long *pl = ( u_long *)in_data;
338   while( len-- )
339   {
340     inport_long( io_addr, *pl );
341         pl++;
342   }
343}
344
345/**********************************************************************************
346 *
347 * DESCRIPTION: Read a buffer of data from an I/O port. The data is read as 8 bits
348 *                          units or 1 bytes.
349 *
350 * RETURNS: nothing.
351 *
352 **********************************************************************************/
353static __inline void insb( unsigned short io_addr, uint8_t *in_data, int len )
354{
355   while( len-- )
356   {
357     inport_byte( io_addr, *in_data++ );
358   }
359}
360
361/**********************************************************************************
362 *
363 * DESCRIPTION: Writes a word to the I/O port.
364 *
365 * RETURNS: nothing.
366 *
367 **********************************************************************************/
368/*
369 * Routine to output a word as defined in FreeBSD.
370 */
371static __inline void outw( unsigned short io_addr, unsigned short out_data )
372{
373  outport_word( io_addr, out_data );
374}
375
376/**********************************************************************************
377 *
378 * DESCRIPTION:  Routine to read a word as defined in FreeBSD.
379 *
380 * RETURNS: nothing
381 *
382 **********************************************************************************/
383static __inline unsigned short inw( unsigned short io_addr )
384{
385  unsigned short in_data;
386  inport_word( io_addr, in_data );
387  return in_data;
388}
389
390/**********************************************************************************
391 *
392 * DESCRIPTION: Routine to output a word as defined in FreeBSD.
393 *
394 * RETURNS: nothing.
395 *
396 **********************************************************************************/
397void __inline outb( unsigned short io_addr, uint8_t out_data )
398{
399  outport_byte( io_addr, out_data );
400}
401
402/**********************************************************************************
403 *
404 * DESCRIPTION: Routine to read a word as defined in FreeBSD.
405 *
406 * RETURNS: byte read.
407 *
408 **********************************************************************************/
409static __inline uint8_t inb( unsigned short io_addr )
410{
411  uint8_t in_data;
412  inport_byte( io_addr, in_data );
413  return in_data;
414}
415
416/**********************************************************************************
417 *
418 * DESCRIPTION:
419 * We get eeprom data from the id_port given an offset into the eeprom.
420 * Basically; after the ID_sequence is sent to all of the cards; they enter
421 * the ID_CMD state where they will accept command requests. 0x80-0xbf loads
422 * the eeprom data.  We then read the port 16 times and with every read; the
423 * cards check for contention (ie: if one card writes a 0 bit and another
424 * writes a 1 bit then the host sees a 0. At the end of the cycle; each card
425 * compares the data on the bus; if there is a difference then that card goes
426 * into ID_WAIT state again). In the meantime; one bit of data is returned in
427 * the AX register which is conveniently returned to us by inb().  Hence; we
428 * read 16 times getting one bit of data with each read.
429 *
430 * RETURNS: 16 bit word from the EEPROM
431 *
432 **********************************************************************************/
433static int get_eeprom_data( int id_port, int offset )
434{
435    int i, data = 0;
436    outb(id_port, 0x80 + offset);
437    Wait_X_ms( 1 );
438    for (i = 0; i < 16; i++)
439            data = (data << 1) | (inw(id_port) & 1);
440    return( data );
441}
442
443/**********************************************************************************
444 *
445 * DESCRIPTION: Waits until the EEPROM of the card is ready to be accessed.
446 *
447 * RETURNS: 0 - not ready; 1 - ok
448 *
449 **********************************************************************************/
450static int eeprom_rdy( struct ep_softc *sc )
451{
452    int i;
453
454    for (i = 0; is_eeprom_busy(BASE) && i < MAX_EEPROMBUSY; i++)
455            continue;
456    if (i >= MAX_EEPROMBUSY)
457    {
458           printf("ep%d: eeprom failed to come ready.\n", sc->unit);
459           return (0);
460    }
461    return (1);
462}
463
464/**********************************************************************************
465 *
466 * DESCRIPTION:
467 * get_e: gets a 16 bits word from the EEPROM.
468 * We must have set the window before call this routine.
469 *
470 * RETURNS: data from EEPROM
471 *
472 **********************************************************************************/
473u_short get_e(  struct ep_softc *sc, int offset )
474{
475    if( !eeprom_rdy(sc) )
476           return (0xffff);
477    outw(BASE + EP_W0_EEPROM_COMMAND, EEPROM_CMD_RD | offset );
478    if( !eeprom_rdy(sc) )
479           return( 0xffff );
480    return( inw( BASE + EP_W0_EEPROM_DATA ) );
481}
482
483/**********************************************************************************
484 *
485 * DESCRIPTION:
486 * Driver interrupt handler. This routine is called by the RTEMS kernel when this
487 * interrupt is raised.
488 *
489 * RETURNS: nothing.
490 *
491 **********************************************************************************/
492static rtems_isr ap_interrupt_handler( rtems_vector_number v )
493{
494  struct ep_softc *sc = (struct ep_softc *)&ep_softc[ 0 ];
495
496  /* de-activate any pending interrrupt, and sent and event to interrupt task
497   * to process all events required by this interrupt.
498   */
499  outw( BASE + EP_COMMAND, SET_INTR_MASK );     /* disable all Ints */
500  rtems_event_send( sc->rxDaemonTid, INTERRUPT_EVENT );
501}
502
503/**********************************************************************************
504 *
505 * DESCRIPTION:
506 *
507 * RETURNS:
508 *
509 **********************************************************************************/
510static void nopOn(const rtems_irq_connect_data* notUsed)
511{
512  /* does nothing */
513}
514
515/**********************************************************************************
516 *
517 * DESCRIPTION:
518 *
519 * RETURNS:
520 *
521 **********************************************************************************/
522static int _3c509_IsOn(const rtems_irq_connect_data* irq)
523{
524  return BSP_irq_enabled_at_i8259s (irq->name);
525}
526
527/**********************************************************************************
528 *
529 * DESCRIPTION:
530 * Initializes the ethernet hardware.
531 *
532 * RETURNS: nothing.
533 *
534 **********************************************************************************/
535static void _3c509_initialize_hardware (struct ep_softc *sc)
536{
537  rtems_status_code st;
538
539  epinit( sc );
540
541  /*
542   * Set up interrupts
543   */
544  sc->irqInfo.hdl = ( rtems_irq_hdl )ap_interrupt_handler;
545  sc->irqInfo.on  = nopOn;
546  sc->irqInfo.off = nopOn;
547  sc->irqInfo.isOn = _3c509_IsOn;
548
549  printf ("3c509: IRQ with Kernel: %d\n", sc->irqInfo.name );
550  st = BSP_install_rtems_irq_handler( &sc->irqInfo );
551  if( !st )
552  {
553    rtems_panic ("Can't attach WD interrupt handler for irq %d\n", sc->irqInfo.name );
554  }
555}
556
557/**********************************************************************************
558 *
559 * DESCRIPTION: Driver interrupt daemon.
560 *
561 * RETURNS: nothing.
562 *
563 **********************************************************************************/
564static void _3c509_rxDaemon (void *arg)
565{
566  struct ep_softc *dp = (struct ep_softc *)&ep_softc[ 0 ];
567  rtems_event_set events;
568
569  printf ("3C509: RX Daemon is starting.\n");
570  for( ;; )
571  {
572    /* printk( "R-" ); */
573    rtems_bsdnet_event_receive( INTERRUPT_EVENT,
574                                                 RTEMS_WAIT | RTEMS_EVENT_ANY,
575                                                 RTEMS_NO_TIMEOUT,
576                                                 &events );
577    /* printk( "R+" ); */
578    ep_intr( dp );
579    epstart( &dp->arpcom.ac_if );
580  }
581  printf ("3C509: RX Daemon is finishing.\n");
582}
583
584/**********************************************************************************
585 *
586 * DESCRIPTION: Driver transmit daemon
587 *
588 * RETURNS:
589 *
590 **********************************************************************************/
591static void _3c509_txDaemon (void *arg)
592{
593    struct ep_softc *sc = (struct ep_softc *)&ep_softc[0];
594        struct ifnet *ifp = &sc->arpcom.ac_if;
595        rtems_event_set events;
596
597    printf ("3C509: TX Daemon is starting.\n");
598    for( ;; )
599        {
600                /*
601                 * Wait for packet
602                 */
603          /* printk( "T-\n" ); */
604                rtems_bsdnet_event_receive( START_TRANSMIT_EVENT,
605                                                                        RTEMS_EVENT_ANY | RTEMS_WAIT,
606                                                                        RTEMS_NO_TIMEOUT,
607                                                                        &events );
608                /*      printk( "T+\n" ); */
609      epstart( ifp );
610      while( ifp->if_flags & IFF_OACTIVE )
611          epstart( ifp );
612        }
613   printf ("3C509: TX Daemon is finishing.\n");
614}
615
616/**********************************************************************************
617 *
618 * DESCRIPTION: Activates the trabsmitter task...
619 *
620 * RETURNS: nothing.
621 *
622 **********************************************************************************/
623static void _3c509_start (struct ifnet *ifp)
624{
625        struct ep_softc *sc = ifp->if_softc;
626        /*    printk ("S");  */
627        ifp->if_flags |= IFF_OACTIVE;
628        rtems_event_send( sc->txDaemonTid, START_TRANSMIT_EVENT );
629}
630
631/**********************************************************************************
632 *
633 * DESCRIPTION: Initialize and start the device
634 *
635 * RETURNS:
636 *
637 **********************************************************************************/
638static void _3c509_init (void *arg)
639{
640  struct ep_softc *sc = arg;
641  struct ifnet *ifp = &sc->arpcom.ac_if;
642
643  printf ("3C509: Initialization called.\n");
644  if (sc->txDaemonTid == 0) {
645
646    /*
647     * Set up WD hardware
648     */
649    _3c509_initialize_hardware (sc);
650    printf ("3C509: starting network driver tasks..\n");
651    /*
652     * Start driver tasks
653     */
654    sc->txDaemonTid = rtems_bsdnet_newproc ("APtx", 4096, _3c509_txDaemon, sc);
655    sc->rxDaemonTid = rtems_bsdnet_newproc ("APrx", 4096, _3c509_rxDaemon, sc);
656  }
657
658  /*
659   * Tell the world that we're running.
660   */
661   ifp->if_flags |= IFF_RUNNING;
662}
663
664/**********************************************************************************
665 *
666 * DESCRIPTION: Stop the device
667 *
668 * RETURNS:
669 *
670 **********************************************************************************/
671static void _3c509_stop (struct ep_softc *sc)
672{
673  struct ifnet *ifp = &sc->arpcom.ac_if;
674  ifp->if_flags &= ~IFF_RUNNING;
675
676  printf ("3C509: stop() called.\n");
677  /*
678   * Stop the transmitter
679   */
680  outw(BASE + EP_COMMAND, RX_DISABLE);
681  outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
682  while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
683  outw(BASE + EP_COMMAND, TX_DISABLE);
684  outw(BASE + EP_COMMAND, STOP_TRANSCEIVER);
685  outw(BASE + EP_COMMAND, RX_RESET);
686  outw(BASE + EP_COMMAND, TX_RESET);
687  while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
688  outw(BASE + EP_COMMAND, C_INTR_LATCH);
689  outw(BASE + EP_COMMAND, SET_RD_0_MASK);
690  outw(BASE + EP_COMMAND, SET_INTR_MASK);
691  outw(BASE + EP_COMMAND, SET_RX_FILTER);
692}
693
694/**********************************************************************************
695 *
696 * DESCRIPTION:  Show interface statistics
697 *
698 * RETURNS: nothing.
699 *
700 **********************************************************************************/
701static void _3c509_stats (struct ep_softc *sc)
702{
703  struct ifnet *ifp = &sc->arpcom.ac_if;
704  printf ("3C509: stats() called.\n");
705  printf("\tStat: %x\n", sc->stat);
706  printf("\tIpackets=%ld, Opackets=%ld\n", ifp->if_ipackets, ifp->if_opackets);
707  printf("\tNOF=%d, NOMB=%d, BPFD=%d, RXOF=%d, RXOL=%d, TXU=%d\n",
708           sc->rx_no_first, sc->rx_no_mbuf, sc->rx_bpf_disc, sc->rx_overrunf,
709           sc->rx_overrunl, sc->tx_underrun );
710}
711
712/**********************************************************************************
713 *
714 * DESCRIPTION: Driver ioctl handler
715 *
716 * RETURNS:
717 *
718 **********************************************************************************/
719static int _3c509_ioctl (struct ifnet *ifp, u_long command, caddr_t data)
720{
721        struct ep_softc *sc = ifp->if_softc;
722        int error = 0;
723
724    printf ("3C509: ioctl() called.\n");
725        switch (command) {
726        case SIOCGIFADDR:
727        case SIOCSIFADDR:
728                ether_ioctl (ifp, command, data);
729                break;
730
731        case SIOCSIFFLAGS:
732                switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
733                case IFF_RUNNING:
734                        _3c509_stop (sc);
735                        break;
736
737                case IFF_UP:
738                        _3c509_init (sc);
739                        break;
740
741                case IFF_UP | IFF_RUNNING:
742                        _3c509_stop (sc);
743                        _3c509_init (sc);
744                        break;
745
746                default:
747                        break;
748                }
749                break;
750
751        case SIO_RTEMS_SHOW_STATS:
752                _3c509_stats( sc );
753                break;
754
755        /*
756         * FIXME: All sorts of multicast commands need to be added here!
757         */
758        default:
759                error = EINVAL;
760                break;
761        }
762        return error;
763}
764
765/**********************************************************************************
766 *
767 * DESCRIPTION:
768 * Attaches this network driver to the system. This function is called by the network
769 * interface during the initialization of the system.
770 *
771 * RETURNS: - 1 - success; 0 - fail to initialize
772 *
773 **********************************************************************************/
774int rtems_3c509_driver_attach (struct rtems_bsdnet_ifconfig *config )
775{
776        struct ep_softc *sc;
777        struct ifnet *ifp;
778        int mtu;
779        int i;
780
781    printf ("3C509: attach() called.\n");
782
783        /*
784         * init some variables
785         */
786        overrun = 0;
787        resend = 0;
788    ep_unit = 0;
789    ep_boards = 0;
790
791        /*
792         * Find a free driver
793         */
794        for (i = 0 ; i < NWDDRIVER ; i++) {
795                sc = &ep_softc[i];
796                ifp = &sc->arpcom.ac_if;
797                if (ifp->if_softc == NULL)
798                        break;
799        }
800        if (i >= NWDDRIVER)
801        {
802                printf ("Too many 3C509 drivers.\n");
803                return 0;
804        }
805
806        /*
807         * Process options
808         */
809        if( config->hardware_address )
810        {
811          memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
812        }
813        else
814        {
815          /* set it to something ... */
816          memset (sc->arpcom.ac_enaddr, 0x08,ETHER_ADDR_LEN);
817        }
818        if (config->mtu)
819                mtu = config->mtu;
820        else
821                mtu = ETHERMTU;
822
823        if (config->irno)
824                sc->irqInfo.name = config->irno;
825        else
826                sc->irqInfo.name = 10;
827
828        if (config->port)
829                sc->ep_io_addr = config->port;
830        else
831                sc->ep_io_addr = 0x300;
832
833        sc->acceptBroadcast = !config->ignore_broadcast;
834
835    printf ("3C509: isa_probe() looking for a card...\n");
836    if( !ep_isa_probe( &isa_dev[ 0 ] ) )
837        {
838           printf ("3C509: isa_probe() fail to find a board.\n");
839           return 0;
840        }
841
842        /* A board has been found, so proceed with the installation of the driver */
843    ep_isa_attach( &isa_dev[ 0 ] );
844        /*
845         * Set up network interface values
846         */
847
848        ifp->if_softc = sc;
849        ifp->if_unit = i;
850        ifp->if_name = NET_DRIVER_NAME;
851        ifp->if_mtu = mtu;
852        ifp->if_init = _3c509_init;
853        ifp->if_ioctl = _3c509_ioctl;
854        ifp->if_start = _3c509_start;
855        ifp->if_output = ether_output;
856    ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
857        if( ifp->if_snd.ifq_maxlen == 0 )
858        {
859           ifp->if_snd.ifq_maxlen = ifqmaxlen;
860        }
861        /*
862         * Attach the interface
863         */
864        if_attach (ifp);
865        ether_ifattach (ifp);
866    printf ("3C509: attach() is complete.\n");
867        return 1;
868}
869
870/**********************************************************************************
871 *
872 * DESCRIPTION:
873 * This function looks for a 3COM card 3c5x9 in an isa bus. If a board is found, it
874 * returns a structure describing the caracteristics of the card. It returns zero when
875 * card can not be found.
876 *
877 * RETURNS:     0 - fail - could not find a card...
878 *                              <>  description of the card.
879 *
880 **********************************************************************************/
881static struct ep_board *ep_look_for_board_at( struct isa_device *is )
882{
883    int data, i, j, id_port = ELINK_ID_PORT;
884    int count = 0;
885
886    if(ep_current_tag == (EP_LAST_TAG + 1) )
887    {
888        /* Come here just one time */
889                ep_current_tag--;
890
891        /* Look for the ISA boards. Init and leave them actived */
892                outb(id_port, 0);
893                outb(id_port, 0);
894
895                elink_idseq(0xCF);
896                elink_reset();
897      Wait_X_ms( 10 );  /* RPS: assuming delay in miliseconds */
898                for (i = 0; i < EP_MAX_BOARDS; i++)
899        {
900                outb(id_port, 0);
901                    outb(id_port, 0);
902                    elink_idseq(0xCF);
903
904                data = get_eeprom_data(id_port, EEPROM_MFG_ID);
905                    if (data != MFG_ID)
906                                break;
907
908                    /* resolve contention using the Ethernet address */
909                    for (j = 0; j < 3; j++)
910                        get_eeprom_data(id_port, j);
911
912                    /* and save this address for later use */
913
914                    for (j = 0; j < 3; j++)
915                           ep_board[ep_boards].eth_addr[j] = get_eeprom_data(id_port, j);
916
917                    ep_board[ep_boards].res_cfg = get_eeprom_data(id_port, EEPROM_RESOURCE_CFG);
918                    ep_board[ep_boards].prod_id = get_eeprom_data(id_port, EEPROM_PROD_ID);
919                    ep_board[ep_boards].epb_used = 0;
920#ifdef PC98
921                    ep_board[ep_boards].epb_addr =
922                                (get_eeprom_data(id_port, EEPROM_ADDR_CFG) & 0x1f) * 0x100 + 0x40d0;
923#else
924                    ep_board[ep_boards].epb_addr =
925                                (get_eeprom_data(id_port, EEPROM_ADDR_CFG) & 0x1f) * 0x10 + 0x200;
926                    if (ep_board[ep_boards].epb_addr > 0x3E0)
927                                /* Board in EISA configuration mode */
928                                continue;
929#endif /* PC98 */
930
931                    outb(id_port, ep_current_tag);      /* tags board */
932                    outb(id_port, ACTIVATE_ADAPTER_TO_CONFIG);
933                    ep_boards++;
934                count++;
935                    ep_current_tag--;
936                }
937                ep_board[ep_boards].epb_addr = 0;
938                if( count )
939                {
940                printf("%d 3C5x9 board(s) on ISA found at", count);
941                    for (j = 0; ep_board[j].epb_addr; j++)
942                           if( ep_board[j].epb_addr <= 0x3E0 )
943                               printf(" 0x%x", ep_board[j].epb_addr );
944                    printf("\n");
945                }
946    }
947
948    /* we have two cases:
949     *
950     *  1. Device was configured with 'port ?'
951     *      In this case we search for the first unused card in list
952     *
953     *  2. Device was configured with 'port xxx'
954     *      In this case we search for the unused card with that address
955     *
956     */
957
958    if (IS_BASE == -1)
959    { /* port? */
960                for (i = 0; ep_board[i].epb_addr && ep_board[i].epb_used; i++) ;
961                if (ep_board[i].epb_addr == 0)
962                      return 0;
963
964                IS_BASE = ep_board[i].epb_addr;
965                ep_board[i].epb_used = 1;
966                return &ep_board[ i ];
967    }
968    else
969    {
970                for (i = 0; ep_board[i].epb_addr && ep_board[i].epb_addr != IS_BASE;  i++ ) ;
971                if (ep_board[i].epb_used || ep_board[i].epb_addr != IS_BASE)
972                            return 0;
973                if (inw(IS_BASE + EP_W0_EEPROM_COMMAND) & EEPROM_TST_MODE)
974                {
975                printf("ep%d: 3c5x9 at 0x%x in PnP mode. Disable PnP mode!\n",
976                                is->id_unit, IS_BASE );
977                }
978                ep_board[i].epb_used = 1;
979                return &ep_board[i];
980    }
981}
982
983/**********************************************************************************
984 *
985 * DESCRIPTION:
986 * This routine checks if there card installed on the machine.
987 *
988 * RETURNS: 0 - no card founded.
989 *                      16 - size of the IO range for the card.
990 *
991 **********************************************************************************/
992static int ep_isa_probe( struct isa_device *is )
993{
994    struct ep_softc *sc;
995    struct ep_board *epb;
996    u_short k;
997
998    /* try to find a 3COM 3c5x9 .... */
999    if( (epb = ep_look_for_board_at(is)) == 0 )
1000                return (0);
1001
1002    sc = &ep_softc[ 0 ];
1003    sc->ep_io_addr = epb->epb_addr;
1004    sc->epb = epb;
1005
1006    /*
1007     * The iobase was found and MFG_ID was 0x6d50. PROD_ID should be
1008     * 0x9[0-f]50       (IBM-PC)
1009     * 0x9[0-f]5[0-f]   (PC-98)
1010     */
1011    GO_WINDOW(0);
1012    k = sc->epb->prod_id;
1013#ifdef PC98
1014    if ((k & 0xf0f0) != (PROD_ID & 0xf0f0))
1015    {
1016#else
1017    if ((k & 0xf0ff) != (PROD_ID & 0xf0ff))
1018    {
1019#endif
1020            printf("ep_isa_probe: ignoring model %04x\n", k );
1021/*        ep_unit--;  */
1022        return (0);
1023    }
1024    k = sc->epb->res_cfg;
1025    k >>= 12;
1026
1027    /* Now we have two cases again:
1028     *
1029     *  1. Device was configured with 'irq?'
1030     *      In this case we use irq read from the board
1031     *
1032     *  2. Device was configured with 'irq xxx'
1033     *      In this case we set up the board to use specified interrupt
1034     *
1035     */
1036
1037    if (is->id_irq == 0)
1038    {    /* irq? */
1039       is->id_irq = ( k == 2 ) ? 9 : k;
1040    }
1041
1042    sc->stat = 0;       /* 16 bit access */
1043
1044    /* By now, the adapter is already activated */
1045
1046    return (EP_IOSIZE);  /* 16 bytes of I/O space used. */
1047}
1048
1049/**********************************************************************************
1050 *
1051 * DESCRIPTION:
1052 * This routine attaches this network driver and the network interface routines.
1053 *
1054 * RETURNS: 0 - failed to attach
1055 *                      1 - success
1056 *
1057 **********************************************************************************/
1058static int ep_isa_attach( struct isa_device *is )
1059{
1060    struct ep_softc *sc = &ep_softc[ 0 ];
1061    u_short config;
1062    int irq;
1063
1064    sc->ep_connectors = 0;
1065    config = inw( IS_BASE + EP_W0_CONFIG_CTRL );
1066    if (config & IS_AUI)
1067    {
1068           sc->ep_connectors |= AUI;
1069    }
1070    if (config & IS_BNC)
1071    {
1072           sc->ep_connectors |= BNC;
1073    }
1074    if (config & IS_UTP)
1075    {
1076           sc->ep_connectors |= UTP;
1077    }
1078    if( !(sc->ep_connectors & 7) )
1079       printf( "no connectors!" );
1080    sc->ep_connector = inw(BASE + EP_W0_ADDRESS_CFG) >> ACF_CONNECTOR_BITS;
1081
1082    /*
1083     * Write IRQ value to board
1084     */
1085
1086    irq = is->id_irq;
1087        /* update the interrupt line number to registered with kernel */
1088        sc->irqInfo.name = irq;
1089
1090    GO_WINDOW( 0 );
1091    SET_IRQ( BASE, irq );
1092
1093    printf( "3C509: I/O=0x%x, IRQ=%d, CONNECTOR=%s, ",
1094            sc->ep_io_addr, sc->irqInfo.name,ep_conn_type[ sc->ep_connector ] );
1095
1096    ep_attach( sc );
1097    return 1;
1098}
1099
1100/**********************************************************************************
1101 *
1102 * DESCRIPTION: Completes the initialization/attachement of the driver.
1103 *
1104 * RETURNS: 0 - ok.
1105 *
1106 **********************************************************************************/
1107static int ep_attach( struct ep_softc *sc )
1108{
1109    u_short *p;
1110    int i;
1111
1112    /*
1113     * Setup the station address
1114     */
1115    p = (u_short *) &sc->arpcom.ac_enaddr;
1116    GO_WINDOW(2);
1117    printf("ADDRESS=" );
1118    for (i = 0; i < 3; i++)
1119    {
1120            p[i] = htons( sc->epb->eth_addr[i] );
1121        outw( BASE + EP_W2_ADDR_0 + (i * 2), ntohs( p[i] ) );
1122        printf("%04x ", (u_short)ntohs( p[i] ) );
1123    }
1124    printf("\n" );
1125
1126    sc->rx_no_first = sc->rx_no_mbuf =
1127        sc->rx_bpf_disc = sc->rx_overrunf = sc->rx_overrunl =
1128        sc->tx_underrun = 0;
1129
1130    ep_fset( F_RX_FIRST );
1131    sc->top = sc->mcur = 0;
1132    return 0;
1133}
1134
1135/**********************************************************************************
1136 *
1137 * DESCRIPTION:
1138 * Initializes the card.
1139 * The order in here seems important. Otherwise we may not receive interrupts. ?!
1140 *
1141 * RETURNS: nothing.
1142 *
1143 **********************************************************************************/
1144static void epinit( struct ep_softc *sc )
1145{
1146    register struct ifnet *ifp = &sc->arpcom.ac_if;
1147    int i, j;
1148
1149    while( inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS ) ;
1150    GO_WINDOW(0);
1151    outw(BASE + EP_COMMAND, STOP_TRANSCEIVER);
1152    GO_WINDOW(4);
1153    outw(BASE + EP_W4_MEDIA_TYPE, DISABLE_UTP);
1154    GO_WINDOW(0);
1155
1156    /* Disable the card */
1157    outw(BASE + EP_W0_CONFIG_CTRL, 0);
1158
1159    /* Enable the card */
1160    outw(BASE + EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ);
1161
1162    GO_WINDOW(2);
1163
1164    /* Reload the ether_addr. */
1165    for (i = 0; i < 6; i++)
1166       outb(BASE + EP_W2_ADDR_0 + i, sc->arpcom.ac_enaddr[i]);
1167
1168    outw(BASE + EP_COMMAND, RX_RESET);
1169    outw(BASE + EP_COMMAND, TX_RESET);
1170    while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
1171
1172    /* Window 1 is operating window */
1173    GO_WINDOW(1);
1174    for (i = 0; i < 31; i++)
1175       inb(BASE + EP_W1_TX_STATUS);
1176
1177    /* get rid of stray intr's */
1178    outw(BASE + EP_COMMAND, ACK_INTR | 0xff);
1179
1180    outw(BASE + EP_COMMAND, SET_RD_0_MASK | S_5_INTS);
1181
1182    outw(BASE + EP_COMMAND, SET_INTR_MASK | S_5_INTS);
1183
1184    if (ifp->if_flags & IFF_PROMISC)
1185           outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL |
1186                                                            FIL_GROUP | FIL_BRDCST | FIL_ALL);
1187    else
1188           outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL | FIL_GROUP | FIL_BRDCST);
1189
1190     /*
1191      * S.B.
1192      *
1193      * Now behavior was slightly changed:
1194      *
1195      * if any of flags link[0-2] is used and its connector is
1196      * physically present the following connectors are used:
1197      *
1198      *   link0 - AUI * highest precedence
1199      *   link1 - BNC
1200      *   link2 - UTP * lowest precedence
1201      *
1202      * If none of them is specified then
1203      * connector specified in the EEPROM is used
1204      * (if present on card or AUI if not).
1205      *
1206      */
1207
1208    /* Set the xcvr. */
1209    if (ifp->if_flags & IFF_LINK0 && sc->ep_connectors & AUI)
1210    {
1211           i = ACF_CONNECTOR_AUI;
1212    }
1213    else if (ifp->if_flags & IFF_LINK1 && sc->ep_connectors & BNC)
1214    {
1215           i = ACF_CONNECTOR_BNC;
1216    }
1217    else if (ifp->if_flags & IFF_LINK2 && sc->ep_connectors & UTP)
1218    {
1219           i = ACF_CONNECTOR_UTP;
1220    }
1221    else
1222    {
1223           i = sc->ep_connector;
1224    }
1225    GO_WINDOW(0);
1226    j = inw(BASE + EP_W0_ADDRESS_CFG) & 0x3fff;
1227    outw(BASE + EP_W0_ADDRESS_CFG, j | (i << ACF_CONNECTOR_BITS));
1228
1229    switch(i)
1230    {
1231      case ACF_CONNECTOR_UTP:
1232          if (sc->ep_connectors & UTP)
1233          {
1234            GO_WINDOW(4);
1235            outw(BASE + EP_W4_MEDIA_TYPE, ENABLE_UTP);
1236          }
1237          break;
1238
1239      case ACF_CONNECTOR_BNC:
1240           if (sc->ep_connectors & BNC)
1241           {
1242            outw(BASE + EP_COMMAND, START_TRANSCEIVER);
1243            Wait_X_ms( 1 );
1244           }
1245       break;
1246
1247      case ACF_CONNECTOR_AUI:
1248            /* nothing to do */
1249                break;
1250
1251      default:
1252           printf("ep%d: strange connector type in EEPROM: assuming AUI\n", sc->unit);
1253           break;
1254    }
1255
1256    outw(BASE + EP_COMMAND, RX_ENABLE);
1257    outw(BASE + EP_COMMAND, TX_ENABLE);
1258
1259    ifp->if_flags |= IFF_RUNNING;
1260    ifp->if_flags &= ~IFF_OACTIVE;      /* just in case */
1261
1262    sc->rx_no_first = sc->rx_no_mbuf =
1263        sc->rx_bpf_disc = sc->rx_overrunf = sc->rx_overrunl =
1264        sc->tx_underrun = 0;
1265
1266    ep_fset(F_RX_FIRST);
1267    if( sc->top )
1268    {
1269           m_freem( sc->top );
1270           sc->top = sc->mcur = 0;
1271    }
1272    outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH);
1273    outw(BASE + EP_COMMAND, SET_TX_START_THRESH | 16);
1274
1275    /*
1276     * Store up a bunch of mbuf's for use later. (MAX_MBS). First we free up
1277     * any that we had in case we're being called from intr or somewhere
1278     * else.
1279     */
1280
1281    GO_WINDOW(1);
1282}
1283
1284static const char padmap[] = {0, 3, 2, 1};
1285
1286/**********************************************************************************
1287 *
1288 * DESCRIPTION: Routine to transmit frames to the card.
1289 *
1290 * RETURNS: nothing.
1291 *
1292 **********************************************************************************/
1293static void epstart( struct ifnet *ifp )
1294{
1295    register struct ep_softc *sc = ifp->if_softc;
1296    register u_int len;
1297    register struct mbuf *m;
1298    struct mbuf *top;
1299    int pad;
1300
1301    while( inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS )
1302        ;
1303startagain:
1304    /*    printk( "S-" ); */
1305
1306    /* Sneak a peek at the next packet */
1307    m = ifp->if_snd.ifq_head;
1308    if (m == 0)
1309    {
1310       ifp->if_flags &= ~IFF_OACTIVE;
1311       return;
1312    }
1313
1314    for( len = 0, top = m; m; m = m->m_next )
1315         len += m->m_len;
1316
1317    pad = padmap[ len & 3 ];
1318
1319    /*
1320     * The 3c509 automatically pads short packets to minimum ethernet length,
1321     * but we drop packets that are too large. Perhaps we should truncate
1322     * them instead?
1323     */
1324    if( len + pad > ETHER_MAX_LEN )
1325    {
1326           /* packet is obviously too large: toss it */
1327       ++ifp->if_oerrors;
1328       IF_DEQUEUE( &ifp->if_snd, m );
1329       m_freem( m );
1330           goto readcheck;
1331    }
1332    if (inw(BASE + EP_W1_FREE_TX) < len + pad + 4)
1333    {
1334           /* no room in FIFO */
1335           outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | (len + pad + 4));
1336       /* make sure */
1337           if (inw(BASE + EP_W1_FREE_TX) < len + pad + 4)
1338           {
1339               ifp->if_flags |= IFF_OACTIVE;
1340               return;
1341           }
1342    }
1343    IF_DEQUEUE( &ifp->if_snd, m );
1344    outw(BASE + EP_W1_TX_PIO_WR_1, len);
1345    outw(BASE + EP_W1_TX_PIO_WR_1, 0x0);        /* Second dword meaningless */
1346
1347    for (top = m; m != 0; m = m->m_next)
1348        {
1349       if( ep_ftst(F_ACCESS_32_BITS ) )
1350       {
1351              outsl( BASE + EP_W1_TX_PIO_WR_1, mtod(m, uint8_t *), m->m_len / 4 );
1352              if( m->m_len & 3 )
1353             outsb(BASE + EP_W1_TX_PIO_WR_1, mtod(m, uint8_t *) + (m->m_len & (~3)), m->m_len & 3 );
1354       }
1355       else
1356       {
1357              outsw( BASE + EP_W1_TX_PIO_WR_1, mtod(m, uint8_t *), m->m_len / 2 );
1358              if( m->m_len & 1 )
1359                  outb( BASE + EP_W1_TX_PIO_WR_1, *(mtod(m, uint8_t *) + m->m_len - 1) );
1360           }
1361        }
1362    while( pad-- )
1363        {
1364           outb(BASE + EP_W1_TX_PIO_WR_1, 0);   /* Padding */
1365        }
1366    ifp->if_timer = 2;
1367    ifp->if_opackets++;
1368    m_freem(top);
1369
1370/*    goto startagain;   */
1371    /*
1372     * Is another packet coming in? We don't want to overflow the tiny RX
1373     * fifo.
1374     */
1375readcheck:
1376    if( inw(BASE + EP_W1_RX_STATUS) & RX_BYTES_MASK )
1377    {
1378        /*
1379         * we check if we have packets left, in that case we prepare to come
1380         * back later
1381         */
1382           if( ifp->if_snd.ifq_head )
1383           {
1384              outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | 8);
1385       }
1386           return;
1387    }
1388    goto startagain;
1389}
1390
1391/**********************************************************************************
1392 *
1393 * DESCRIPTION: Routine to read frames from the card.
1394 *
1395 * RETURNS: nothing.
1396 *
1397 **********************************************************************************/
1398static void epread( register struct ep_softc *sc )
1399{
1400    struct ether_header *eh;
1401    struct mbuf *top, *mcur, *m;
1402    struct ifnet *ifp;
1403    int lenthisone;
1404
1405    short rx_fifo2, status;
1406    register short rx_fifo;
1407
1408    ifp = &sc->arpcom.ac_if;
1409    status = inw( BASE + EP_W1_RX_STATUS );
1410
1411read_again:
1412
1413    if (status & ERR_RX)
1414    {
1415           ++ifp->if_ierrors;
1416           if( status & ERR_RX_OVERRUN )
1417           {
1418            /*
1419             * we can think the rx latency is actually greather than we
1420             * expect
1421             */
1422            if( ep_ftst(F_RX_FIRST) )
1423                   sc->rx_overrunf++;
1424            else
1425                   sc->rx_overrunl++;
1426
1427           }
1428           goto out;
1429    }
1430    rx_fifo = rx_fifo2 = status & RX_BYTES_MASK;
1431
1432    if( ep_ftst( F_RX_FIRST ) )
1433    {
1434           MGETHDR( m, M_DONTWAIT, MT_DATA );
1435       if( !m )
1436              goto out;
1437           if( rx_fifo >= MINCLSIZE )
1438              MCLGET( m, M_DONTWAIT );
1439           sc->top = sc->mcur = top = m;
1440#define EROUND  ((sizeof(struct ether_header) + 3) & ~3)
1441#define EOFF    (EROUND - sizeof(struct ether_header))
1442           top->m_data += EOFF;
1443
1444           /* Read what should be the header. */
1445           insw(BASE + EP_W1_RX_PIO_RD_1, mtod(top, uint8_t *), sizeof(struct ether_header) / 2);
1446           top->m_len = sizeof(struct ether_header);
1447           rx_fifo -= sizeof(struct ether_header);
1448           sc->cur_len = rx_fifo2;
1449    }
1450    else
1451    {
1452           /* come here if we didn't have a complete packet last time */
1453           top = sc->top;
1454           m = sc->mcur;
1455           sc->cur_len += rx_fifo2;
1456    }
1457
1458    /* Reads what is left in the RX FIFO */
1459    while (rx_fifo > 0)
1460    {
1461           lenthisone = min( rx_fifo, M_TRAILINGSPACE(m) );
1462           if( lenthisone == 0 )
1463           {    /* no room in this one */
1464               mcur = m;
1465               MGET(m, M_WAIT, MT_DATA);
1466               if (!m)
1467                      goto out;
1468               if (rx_fifo >= MINCLSIZE)
1469                       MCLGET(m, M_WAIT);
1470               m->m_len = 0;
1471               mcur->m_next = m;
1472               lenthisone = min(rx_fifo, M_TRAILINGSPACE(m));
1473           }
1474           if( ep_ftst( F_ACCESS_32_BITS ) )
1475           { /* default for EISA configured cards*/
1476              insl( BASE + EP_W1_RX_PIO_RD_1, mtod(m, uint8_t *) + m->m_len, lenthisone / 4);
1477              m->m_len += (lenthisone & ~3);
1478              if (lenthisone & 3)
1479                     insb(BASE + EP_W1_RX_PIO_RD_1, mtod(m, uint8_t *) + m->m_len, lenthisone & 3);
1480              m->m_len += (lenthisone & 3);
1481            }
1482            else
1483            {
1484              insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, uint8_t *) + m->m_len, lenthisone / 2);
1485              m->m_len += lenthisone;
1486              if( lenthisone & 1 )
1487                     *(mtod(m, uint8_t *) + m->m_len - 1) = inb(BASE + EP_W1_RX_PIO_RD_1);
1488           }
1489           rx_fifo -= lenthisone;
1490    }
1491
1492    if( status & ERR_RX_INCOMPLETE)
1493    {   /* we haven't received the complete packet */
1494            sc->mcur = m;
1495        sc->rx_no_first++;      /* to know how often we come here */
1496        ep_frst( F_RX_FIRST );
1497            if( !((status = inw(BASE + EP_W1_RX_STATUS)) & ERR_RX_INCOMPLETE) )
1498            {
1499              /* we see if by now, the packet has completly arrived */
1500              goto read_again;
1501            }
1502            outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_NEXT_EARLY_THRESH);
1503            return;
1504    }
1505    outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
1506    ++ifp->if_ipackets;
1507    ep_fset(F_RX_FIRST);
1508    top->m_pkthdr.rcvif = &sc->arpcom.ac_if;
1509    top->m_pkthdr.len = sc->cur_len;
1510
1511    eh = mtod(top, struct ether_header *);
1512    m_adj(top, sizeof(struct ether_header));
1513    ether_input(ifp, eh, top);
1514    sc->top = 0;
1515    while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
1516          ;
1517    outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH);
1518    return;
1519
1520out:
1521    outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
1522    if (sc->top)
1523    {
1524           m_freem(sc->top);
1525           sc->top = 0;
1526       sc->rx_no_mbuf++;
1527    }
1528    ep_fset(F_RX_FIRST);
1529    while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS) ;
1530    outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH);
1531}
1532
1533/**********************************************************************************
1534 *
1535 * DESCRIPTION:
1536 * This routine handles interrupts. It is called from the "RX" task whenever
1537 * the ISR post an event to the task.
1538 * This is basically the "isr" from the FreeBSD driver.
1539 *
1540 * RETURNS: nothing.
1541 *
1542 **********************************************************************************/
1543static void ep_intr( struct ep_softc *sc )
1544{
1545  register int status;
1546  struct ifnet *ifp;
1547  ifp = &sc->arpcom.ac_if;
1548
1549rescan:
1550
1551  /*  printk( "I-" ); */
1552  while( ( status = inw(BASE + EP_STATUS)) & S_5_INTS )
1553  {
1554        /* first acknowledge all interrupt sources */
1555    outw( BASE + EP_COMMAND, ACK_INTR | ( status & S_MASK ) );
1556
1557        if( status & ( S_RX_COMPLETE | S_RX_EARLY ) )
1558        {
1559            epread( sc );
1560            continue;
1561        }
1562        if (status & S_TX_AVAIL)
1563        {
1564            /* we need ACK */
1565            ifp->if_timer = 0;
1566            ifp->if_flags &= ~IFF_OACTIVE;
1567            GO_WINDOW(1);
1568            inw(BASE + EP_W1_FREE_TX);
1569            epstart(ifp);
1570        }
1571        if (status & S_CARD_FAILURE)
1572        {
1573            ifp->if_timer = 0;
1574            printf("\nep%d:\n\tStatus: %x\n", sc->unit, status);
1575            GO_WINDOW(4);
1576            printf("\tFIFO Diagnostic: %x\n", inw(BASE + EP_W4_FIFO_DIAG));
1577            printf("\tStat: %x\n", sc->stat);
1578            printf("\tIpackets=%ld, Opackets=%ld\n", ifp->if_ipackets, ifp->if_opackets);
1579            printf("\tNOF=%d, NOMB=%d, BPFD=%d, RXOF=%d, RXOL=%d, TXU=%d\n",
1580                   sc->rx_no_first, sc->rx_no_mbuf, sc->rx_bpf_disc, sc->rx_overrunf,
1581                   sc->rx_overrunl, sc->tx_underrun);
1582
1583            printf("ep%d: Status: %x (input buffer overflow)\n", sc->unit, status);
1584            ++ifp->if_ierrors;
1585            epinit(sc);
1586            return;
1587        }
1588        if (status & S_TX_COMPLETE)
1589        {
1590            ifp->if_timer = 0;
1591            /* we  need ACK. we do it at the end */
1592            /*
1593             * We need to read TX_STATUS until we get a 0 status in order to
1594             * turn off the interrupt flag.
1595             */
1596            while ((status = inb(BASE + EP_W1_TX_STATUS)) & TXS_COMPLETE)
1597            {
1598                   if (status & TXS_SUCCES_INTR_REQ)
1599                        ;
1600                   else if( status & (TXS_UNDERRUN | TXS_JABBER | TXS_MAX_COLLISION ) )
1601                   {
1602                      outw(BASE + EP_COMMAND, TX_RESET);
1603                      if (status & TXS_UNDERRUN)
1604                      {
1605                             sc->tx_underrun++;
1606                      }
1607                      else
1608                      {
1609                              if( status & TXS_JABBER )
1610                                   ;
1611                          else  /* TXS_MAX_COLLISION - we shouldn't get here */
1612                                   ++ifp->if_collisions;
1613                      }
1614                      ++ifp->if_oerrors;
1615                      outw(BASE + EP_COMMAND, TX_ENABLE);
1616                     /*
1617                      * To have a tx_avail_int but giving the chance to the
1618                      * Reception
1619                      */
1620                      if( ifp->if_snd.ifq_head )
1621                      {
1622                             outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | 8);
1623                      }
1624                   }
1625                   outb( BASE + EP_W1_TX_STATUS, 0x0 ); /* pops up the next status */
1626            } /* while */
1627            ifp->if_flags &= ~IFF_OACTIVE;
1628            GO_WINDOW(1);
1629            inw(BASE + EP_W1_FREE_TX);
1630            epstart( ifp );
1631        }  /* end TX_COMPLETE */
1632  }
1633  outw(BASE + EP_COMMAND, C_INTR_LATCH);        /* ACK int Latch */
1634  if( (status = inw(BASE + EP_STATUS) ) & S_5_INTS )
1635      goto rescan;
1636
1637  /* re-enable Ints */
1638  outw( BASE + EP_COMMAND, SET_INTR_MASK | S_5_INTS );
1639  /* printk( "I+" ); */
1640}
Note: See TracBrowser for help on using the repository browser.