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

4.104.114.84.95
Last change on this file since b607d9c8 was b607d9c8, checked in by Joel Sherrill <joel.sherrill@…>, on 04/26/05 at 23:03:51

2005-04-26 Joel Sherrill <joel@…>

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