~smartboyhw/wubi/bug-1080090-new

« back to all changes in this revision

Viewing changes to src/grub4dos/netboot/.svn/text-base/3c595.c.svn-base

  • Committer: Howard Chan
  • Date: 2012-11-20 10:16:05 UTC
  • Revision ID: smartboyhw@gmail.com-20121120101605-qfmjfsdynpzg9an9
Added images

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
* 3c595.c -- 3COM 3C595 Fast Etherlink III PCI driver for etherboot
3
 
*
4
 
* Copyright (C) 2000 Shusuke Nisiyama <shu@athena.qe.eng.hokudai.ac.jp>
5
 
* All rights reserved.
6
 
* Mar. 14, 2000
7
 
*
8
 
*  This software may be used, modified, copied, distributed, and sold, in
9
 
*  both source and binary form provided that the above copyright and these
10
 
*  terms are retained. Under no circumstances are the authors responsible for
11
 
*  the proper functioning of this software, nor do the authors assume any
12
 
*  responsibility for damages incurred with its use.
13
 
*
14
 
* This code is based on Martin Renters' etherboot-4.4.3 3c509.c and 
15
 
* Herb Peyerl's FreeBSD 3.4-RELEASE if_vx.c driver.
16
 
*
17
 
*  Copyright (C) 1993-1994, David Greenman, Martin Renters.
18
 
*  Copyright (C) 1993-1995, Andres Vega Garcia.
19
 
*  Copyright (C) 1995, Serge Babkin.
20
 
*
21
 
*  Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca>
22
 
*
23
 
*/
24
 
 
25
 
/* #define EDEBUG */
26
 
 
27
 
#include "etherboot.h"
28
 
#include "nic.h"
29
 
#include "pci.h"
30
 
#include "3c595.h"
31
 
#include "timer.h"
32
 
 
33
 
static unsigned short   eth_nic_base, eth_asic_base;
34
 
static unsigned short   vx_connector, vx_connectors;
35
 
 
36
 
static struct connector_entry {
37
 
  int bit;
38
 
  char *name;
39
 
} conn_tab[VX_CONNECTORS] = {
40
 
#define CONNECTOR_UTP   0
41
 
  { 0x08, "utp"},
42
 
#define CONNECTOR_AUI   1
43
 
  { 0x20, "aui"},
44
 
/* dummy */
45
 
  { 0, "???"},
46
 
#define CONNECTOR_BNC   3
47
 
  { 0x10, "bnc"},
48
 
#define CONNECTOR_TX    4
49
 
  { 0x02, "tx"},
50
 
#define CONNECTOR_FX    5
51
 
  { 0x04, "fx"},
52
 
#define CONNECTOR_MII   6
53
 
  { 0x40, "mii"},
54
 
  { 0, "???"}
55
 
};
56
 
 
57
 
static void vxgetlink(void);
58
 
static void vxsetlink(void);
59
 
 
60
 
#define udelay(n)       waiton_timer2(((n)*TICKS_PER_MS)/1000)
61
 
 
62
 
/**************************************************************************
63
 
ETH_RESET - Reset adapter
64
 
***************************************************************************/
65
 
static void t595_reset(struct nic *nic)
66
 
{
67
 
        int i, j;
68
 
 
69
 
        /***********************************************************
70
 
                        Reset 3Com 595 card
71
 
        *************************************************************/
72
 
 
73
 
        /* stop card */
74
 
        outw(RX_DISABLE, BASE + VX_COMMAND);
75
 
        outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND);
76
 
        VX_BUSY_WAIT;
77
 
        outw(TX_DISABLE, BASE + VX_COMMAND);
78
 
        outw(STOP_TRANSCEIVER, BASE + VX_COMMAND);
79
 
        udelay(8000);
80
 
        outw(RX_RESET, BASE + VX_COMMAND);
81
 
        VX_BUSY_WAIT;
82
 
        outw(TX_RESET, BASE + VX_COMMAND);
83
 
        VX_BUSY_WAIT;
84
 
        outw(C_INTR_LATCH, BASE + VX_COMMAND);
85
 
        outw(SET_RD_0_MASK, BASE + VX_COMMAND);
86
 
        outw(SET_INTR_MASK, BASE + VX_COMMAND);
87
 
        outw(SET_RX_FILTER, BASE + VX_COMMAND);
88
 
 
89
 
        /*
90
 
        * initialize card
91
 
        */
92
 
        VX_BUSY_WAIT;
93
 
 
94
 
        GO_WINDOW(0);
95
 
 
96
 
        /* Disable the card */
97
 
/*      outw(0, BASE + VX_W0_CONFIG_CTRL); */
98
 
 
99
 
        /* Configure IRQ to none */
100
 
/*      outw(SET_IRQ(0), BASE + VX_W0_RESOURCE_CFG); */
101
 
 
102
 
        /* Enable the card */
103
 
/*      outw(ENABLE_DRQ_IRQ, BASE + VX_W0_CONFIG_CTRL); */
104
 
 
105
 
        GO_WINDOW(2);
106
 
 
107
 
        /* Reload the ether_addr. */
108
 
        for (i = 0; i < ETH_ALEN; i++)
109
 
                outb(nic->node_addr[i], BASE + VX_W2_ADDR_0 + i);
110
 
 
111
 
        outw(RX_RESET, BASE + VX_COMMAND);
112
 
        VX_BUSY_WAIT;
113
 
        outw(TX_RESET, BASE + VX_COMMAND);
114
 
        VX_BUSY_WAIT;
115
 
 
116
 
        /* Window 1 is operating window */
117
 
        GO_WINDOW(1);
118
 
        for (i = 0; i < 31; i++)
119
 
                inb(BASE + VX_W1_TX_STATUS);
120
 
 
121
 
        outw(SET_RD_0_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
122
 
                S_TX_COMPLETE | S_TX_AVAIL, BASE + VX_COMMAND);
123
 
        outw(SET_INTR_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
124
 
                S_TX_COMPLETE | S_TX_AVAIL, BASE + VX_COMMAND);
125
 
 
126
 
/*
127
 
 * Attempt to get rid of any stray interrupts that occured during
128
 
 * configuration.  On the i386 this isn't possible because one may
129
 
 * already be queued.  However, a single stray interrupt is
130
 
 * unimportant.
131
 
 */
132
 
 
133
 
        outw(ACK_INTR | 0xff, BASE + VX_COMMAND);
134
 
 
135
 
        outw(SET_RX_FILTER | FIL_INDIVIDUAL |
136
 
            FIL_BRDCST, BASE + VX_COMMAND);
137
 
 
138
 
        vxsetlink();
139
 
/*{
140
 
        int i,j;
141
 
        i = CONNECTOR_TX;
142
 
        GO_WINDOW(3);
143
 
        j = inl(BASE + VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK;
144
 
        outl(BASE + VX_W3_INTERNAL_CFG, j | (i <<INTERNAL_CONNECTOR_BITS));
145
 
        GO_WINDOW(4);
146
 
        outw(LINKBEAT_ENABLE, BASE + VX_W4_MEDIA_TYPE);
147
 
        GO_WINDOW(1);
148
 
}*/
149
 
 
150
 
        /* start tranciever and receiver */
151
 
        outw(RX_ENABLE, BASE + VX_COMMAND);
152
 
        outw(TX_ENABLE, BASE + VX_COMMAND);
153
 
 
154
 
}
155
 
 
156
 
/**************************************************************************
157
 
ETH_TRANSMIT - Transmit a frame
158
 
***************************************************************************/
159
 
static char padmap[] = {
160
 
        0, 3, 2, 1};
161
 
 
162
 
static void t595_transmit(
163
 
struct nic *nic,
164
 
const char *d,                  /* Destination */
165
 
unsigned int t,                 /* Type */
166
 
unsigned int s,                 /* size */
167
 
const char *p)                  /* Packet */
168
 
{
169
 
        register int len;
170
 
        int pad;
171
 
        int status;
172
 
 
173
 
#ifdef EDEBUG
174
 
        printf("{l=%d,t=%hX}",s+ETH_HLEN,t);
175
 
#endif
176
 
 
177
 
        /* swap bytes of type */
178
 
        t= htons(t);
179
 
 
180
 
        len=s+ETH_HLEN; /* actual length of packet */
181
 
        pad = padmap[len & 3];
182
 
 
183
 
        /*
184
 
        * The 3c595 automatically pads short packets to minimum ethernet length,
185
 
        * but we drop packets that are too large. Perhaps we should truncate
186
 
        * them instead?
187
 
        */
188
 
        if (len + pad > ETH_FRAME_LEN) {
189
 
                return;
190
 
        }
191
 
 
192
 
        /* drop acknowledgements */
193
 
        while(( status=inb(BASE + VX_W1_TX_STATUS) )& TXS_COMPLETE ) {
194
 
                if(status & (TXS_UNDERRUN|TXS_MAX_COLLISION|TXS_STATUS_OVERFLOW)) {
195
 
                        outw(TX_RESET, BASE + VX_COMMAND);
196
 
                        outw(TX_ENABLE, BASE + VX_COMMAND);
197
 
                }
198
 
 
199
 
                outb(0x0, BASE + VX_W1_TX_STATUS);
200
 
        }
201
 
 
202
 
        while (inw(BASE + VX_W1_FREE_TX) < len + pad + 4) {
203
 
                /* no room in FIFO */
204
 
        }
205
 
 
206
 
        outw(len, BASE + VX_W1_TX_PIO_WR_1);
207
 
        outw(0x0, BASE + VX_W1_TX_PIO_WR_1);    /* Second dword meaningless */
208
 
 
209
 
        /* write packet */
210
 
        outsw(BASE + VX_W1_TX_PIO_WR_1, d, ETH_ALEN/2);
211
 
        outsw(BASE + VX_W1_TX_PIO_WR_1, nic->node_addr, ETH_ALEN/2);
212
 
        outw(t, BASE + VX_W1_TX_PIO_WR_1);
213
 
        outsw(BASE + VX_W1_TX_PIO_WR_1, p, s / 2);
214
 
        if (s & 1)
215
 
                outb(*(p+s - 1), BASE + VX_W1_TX_PIO_WR_1);
216
 
 
217
 
        while (pad--)
218
 
                outb(0, BASE + VX_W1_TX_PIO_WR_1);      /* Padding */
219
 
 
220
 
        /* wait for Tx complete */
221
 
        while((inw(BASE + VX_STATUS) & S_COMMAND_IN_PROGRESS) != 0)
222
 
                ;
223
 
}
224
 
 
225
 
/**************************************************************************
226
 
ETH_POLL - Wait for a frame
227
 
***************************************************************************/
228
 
static int t595_poll(struct nic *nic)
229
 
{
230
 
        /* common variables */
231
 
        unsigned short type = 0;        /* used by EDEBUG */
232
 
        /* variables for 3C595 */
233
 
        short status, cst;
234
 
        register short rx_fifo;
235
 
 
236
 
        cst=inw(BASE + VX_STATUS);
237
 
 
238
 
#ifdef EDEBUG
239
 
        if(cst & 0x1FFF)
240
 
                printf("-%hX-",cst);
241
 
#endif
242
 
 
243
 
        if( (cst & S_RX_COMPLETE)==0 ) {
244
 
                /* acknowledge  everything */
245
 
                outw(ACK_INTR | cst, BASE + VX_COMMAND);
246
 
                outw(C_INTR_LATCH, BASE + VX_COMMAND);
247
 
 
248
 
                return 0;
249
 
        }
250
 
 
251
 
        status = inw(BASE + VX_W1_RX_STATUS);
252
 
#ifdef EDEBUG
253
 
        printf("*%hX*",status);
254
 
#endif
255
 
 
256
 
        if (status & ERR_RX) {
257
 
                outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND);
258
 
                return 0;
259
 
        }
260
 
 
261
 
        rx_fifo = status & RX_BYTES_MASK;
262
 
        if (rx_fifo==0)
263
 
                return 0;
264
 
 
265
 
                /* read packet */
266
 
#ifdef EDEBUG
267
 
        printf("[l=%d",rx_fifo);
268
 
#endif
269
 
        insw(BASE + VX_W1_RX_PIO_RD_1, nic->packet, rx_fifo / 2);
270
 
        if(rx_fifo & 1)
271
 
                nic->packet[rx_fifo-1]=inb(BASE + VX_W1_RX_PIO_RD_1);
272
 
        nic->packetlen=rx_fifo;
273
 
 
274
 
        while(1) {
275
 
                status = inw(BASE + VX_W1_RX_STATUS);
276
 
#ifdef EDEBUG
277
 
                printf("*%hX*",status);
278
 
#endif
279
 
                rx_fifo = status & RX_BYTES_MASK;
280
 
 
281
 
                if(rx_fifo>0) {
282
 
                        insw(BASE + VX_W1_RX_PIO_RD_1, nic->packet+nic->packetlen, rx_fifo / 2);
283
 
                        if(rx_fifo & 1)
284
 
                                nic->packet[nic->packetlen+rx_fifo-1]=inb(BASE + VX_W1_RX_PIO_RD_1);
285
 
                        nic->packetlen+=rx_fifo;
286
 
#ifdef EDEBUG
287
 
                        printf("+%d",rx_fifo);
288
 
#endif
289
 
                }
290
 
                if(( status & RX_INCOMPLETE )==0) {
291
 
#ifdef EDEBUG
292
 
                        printf("=%d",nic->packetlen);
293
 
#endif
294
 
                        break;
295
 
                }
296
 
                udelay(1000);
297
 
        }
298
 
 
299
 
        /* acknowledge reception of packet */
300
 
        outw(RX_DISCARD_TOP_PACK, BASE + VX_COMMAND);
301
 
        while (inw(BASE + VX_STATUS) & S_COMMAND_IN_PROGRESS);
302
 
#ifdef EDEBUG
303
 
        type = (nic->packet[12]<<8) | nic->packet[13];
304
 
        if(nic->packet[0]+nic->packet[1]+nic->packet[2]+nic->packet[3]+nic->packet[4]+
305
 
            nic->packet[5] == 0xFF*ETH_ALEN)
306
 
                printf(",t=%hX,b]",type);
307
 
        else
308
 
                printf(",t=%hX]",type);
309
 
#endif
310
 
        return 1;
311
 
}
312
 
 
313
 
 
314
 
/*************************************************************************
315
 
        3Com 595 - specific routines
316
 
**************************************************************************/
317
 
 
318
 
static int
319
 
eeprom_rdy()
320
 
{
321
 
        int i;
322
 
 
323
 
        for (i = 0; is_eeprom_busy(BASE) && i < MAX_EEPROMBUSY; i++)
324
 
                udelay(1000);
325
 
        if (i >= MAX_EEPROMBUSY) {
326
 
                /* printf("3c595: eeprom failed to come ready.\n"); */
327
 
                printf("3c595: eeprom is busy.\n"); /* memory in EPROM is tight */
328
 
                return (0);
329
 
        }
330
 
        return (1);
331
 
}
332
 
 
333
 
/*
334
 
 * get_e: gets a 16 bits word from the EEPROM. we must have set the window
335
 
 * before
336
 
 */
337
 
static int
338
 
get_e(offset)
339
 
int offset;
340
 
{
341
 
        if (!eeprom_rdy())
342
 
                return (0xffff);
343
 
        outw(EEPROM_CMD_RD | offset, BASE + VX_W0_EEPROM_COMMAND);
344
 
        if (!eeprom_rdy())
345
 
                return (0xffff);
346
 
        return (inw(BASE + VX_W0_EEPROM_DATA));
347
 
}
348
 
 
349
 
static void            
350
 
vxgetlink(void)
351
 
{
352
 
    int n, k;
353
 
 
354
 
    GO_WINDOW(3);
355
 
    vx_connectors = inw(BASE + VX_W3_RESET_OPT) & 0x7f;
356
 
    for (n = 0, k = 0; k < VX_CONNECTORS; k++) {
357
 
      if (vx_connectors & conn_tab[k].bit) {
358
 
        if (n > 0) {
359
 
          printf("/");
360
 
        }
361
 
        printf(conn_tab[k].name);
362
 
        n++;
363
 
      }
364
 
    }
365
 
    if (vx_connectors == 0) {
366
 
        printf("no connectors!");
367
 
        return;
368
 
    }
369
 
    GO_WINDOW(3);
370
 
    vx_connector = (inl(BASE + VX_W3_INTERNAL_CFG) 
371
 
                        & INTERNAL_CONNECTOR_MASK) 
372
 
                        >> INTERNAL_CONNECTOR_BITS;
373
 
    if (vx_connector & 0x10) {
374
 
        vx_connector &= 0x0f;
375
 
        printf("[*%s*]", conn_tab[vx_connector].name);
376
 
        printf(": disable 'auto select' with DOS util!");
377
 
    } else {
378
 
        printf("[*%s*]", conn_tab[vx_connector].name);
379
 
    }
380
 
}
381
 
 
382
 
static void            
383
 
vxsetlink(void)
384
 
{       
385
 
    int i, j, k;
386
 
    char *reason, *warning;
387
 
    static short prev_flags;
388
 
    static char prev_conn = -1;
389
 
 
390
 
    if (prev_conn == -1) {
391
 
        prev_conn = vx_connector;
392
 
    }
393
 
 
394
 
    i = vx_connector;       /* default in EEPROM */
395
 
    reason = "default";
396
 
    warning = 0;
397
 
 
398
 
    if ((vx_connectors & conn_tab[vx_connector].bit) == 0) {
399
 
        warning = "strange connector type in EEPROM.";
400
 
        reason = "forced";
401
 
        i = CONNECTOR_UTP;
402
 
    }
403
 
 
404
 
        if (warning != 0) {
405
 
            printf("warning: %s\n", warning);
406
 
        }
407
 
        printf("selected %s. (%s)\n", conn_tab[i].name, reason);
408
 
 
409
 
    /* Set the selected connector. */
410
 
    GO_WINDOW(3);
411
 
    j = inl(BASE + VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK;
412
 
    outl(j | (i <<INTERNAL_CONNECTOR_BITS), BASE + VX_W3_INTERNAL_CFG);
413
 
 
414
 
    /* First, disable all. */
415
 
    outw(STOP_TRANSCEIVER, BASE + VX_COMMAND);
416
 
    udelay(8000);
417
 
    GO_WINDOW(4);
418
 
    outw(0, BASE + VX_W4_MEDIA_TYPE);
419
 
 
420
 
    /* Second, enable the selected one. */
421
 
    switch(i) {
422
 
      case CONNECTOR_UTP:
423
 
        GO_WINDOW(4);
424
 
        outw(ENABLE_UTP, BASE + VX_W4_MEDIA_TYPE);
425
 
        break;
426
 
      case CONNECTOR_BNC:
427
 
        outw(START_TRANSCEIVER,BASE + VX_COMMAND);
428
 
        udelay(8000);
429
 
        break;
430
 
      case CONNECTOR_TX:
431
 
      case CONNECTOR_FX:
432
 
        GO_WINDOW(4);
433
 
        outw(LINKBEAT_ENABLE, BASE + VX_W4_MEDIA_TYPE);
434
 
        break;
435
 
      default:  /* AUI and MII fall here */
436
 
        break;
437
 
    }
438
 
    GO_WINDOW(1); 
439
 
}
440
 
 
441
 
static void t595_disable(struct nic *nic)
442
 
{
443
 
    outw(STOP_TRANSCEIVER, BASE + VX_COMMAND);
444
 
    udelay(8000);
445
 
    GO_WINDOW(4);
446
 
    outw(0, BASE + VX_W4_MEDIA_TYPE);
447
 
    GO_WINDOW(1);
448
 
}
449
 
 
450
 
/**************************************************************************
451
 
ETH_PROBE - Look for an adapter
452
 
***************************************************************************/
453
 
struct nic *t595_probe(struct nic *nic, unsigned short *probeaddrs, struct pci_device *pci)
454
 
{
455
 
        int i;
456
 
        unsigned short *p;
457
 
 
458
 
        if (probeaddrs == 0 || probeaddrs[0] == 0)
459
 
                return 0;
460
 
/*      eth_nic_base = probeaddrs[0] & ~3; */
461
 
        eth_nic_base = pci->ioaddr;
462
 
 
463
 
        GO_WINDOW(0);
464
 
        outw(GLOBAL_RESET, BASE + VX_COMMAND);
465
 
        VX_BUSY_WAIT;
466
 
 
467
 
        vxgetlink();
468
 
 
469
 
/*
470
 
        printf("\nEEPROM:");
471
 
        for (i = 0; i < (EEPROMSIZE/2); i++) {
472
 
          printf("%hX:", get_e(i));
473
 
        }
474
 
        printf("\n");
475
 
*/
476
 
        /*
477
 
        * Read the station address from the eeprom
478
 
        */
479
 
        p = (unsigned short *) nic->node_addr;
480
 
        for (i = 0; i < 3; i++) {
481
 
                GO_WINDOW(0);
482
 
                p[i] = htons(get_e(EEPROM_OEM_ADDR_0 + i));
483
 
                GO_WINDOW(2);
484
 
                outw(ntohs(p[i]), BASE + VX_W2_ADDR_0 + (i * 2));
485
 
        }
486
 
 
487
 
        printf("Ethernet address: %!\n", nic->node_addr);
488
 
 
489
 
        t595_reset(nic);
490
 
        nic->reset = t595_reset;
491
 
        nic->poll = t595_poll;
492
 
        nic->transmit = t595_transmit;
493
 
        nic->disable = t595_disable;
494
 
        return nic;
495
 
 
496
 
}
497
 
 
498
 
/*
499
 
 * Local variables:
500
 
 *  c-basic-offset: 8
501
 
 * End:
502
 
 */
503