OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [lib/] [libbsp/] [i386/] [pc386/] [3c509/] [3c509.c] - Blame information for rev 389

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.