]> git.pld-linux.org Git - packages/3c5x9setup.git/blob - 3c5x9setup.donald.becker.0.05b.redhog.1.c
- tabs in preamle
[packages/3c5x9setup.git] / 3c5x9setup.donald.becker.0.05b.redhog.1.c
1 /* 3c5x9setup.c: Setup program for 3Com EtherLink III ethercards.
2
3    Copyright 1994-1999 by Donald Becker <becker@cesdis.gsfc.nasa.gov>
4    Modified 2000 by RedHog (Egil Möller) <redhog@lysator.liu.se>
5    This version released under the Gnu Public License, incorporated herein
6    by reference.  Contact the author for use under other terms.
7
8    This is a EEPROM setup and diagnostic program for the 3Com 3c5x9 series
9    ethercards.  Most products with "EtherLink III" in the name are supported,
10    including
11         3c509, 3c529, 3c579  (ISA, MCA, EISA, but not PCI)
12         3c556 3c562, 3c563, 3c574 and other PCMCIA (but not CardBus) cards
13    The 'B' and 'C' suffix versions are supported, as are the various
14    transceiver options (e.g. "-TPO")
15
16    Instructions are at
17      http://cesdis.gsfc.nasa.gov/linux/diag/index.html
18      http://3c5x9.redhog.org
19
20    This program must be compiled with "-O"!  See the bottom of this file
21    for the suggested compile-command.
22
23    The author may be reached as becker@cesdis.gsfc.nasa.gov.
24    C/O USRA-CESDIS, Code 930.5 Bldg. 28, Nimbus Rd., Greenbelt MD 20771
25
26    References
27    The 3Com EtherLink III manual, available from 3Com
28    http://cesdis.gsfc.nasa.gov/linux/diag/index.html
29 */
30
31 static char *version_msg =
32 "3c5x9setup.c:donald.becker.0.05b.redhog.1 2/5/00 RedHog (Egil Möller) <redhog@lysator.liu.se>\n";
33 static char *usage_msg =
34 "Usage: 3c5x9setup [-aEfFsvVw] [-p <IOport>] [-F 10baseT|10base2|AUI>] [-Q <IRQ>] [-d <filename>] [-r <filename>] [-u <UMID>] [-m <MAC address>]\n";
35
36 #ifndef __OPTIMIZE__
37 #warning  You must compile this program with the correct options!
38 #warning  See the last lines of the source file.
39 #error You must compile this driver with "-O".
40 #endif
41 #include <unistd.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <getopt.h>
45 #include <strings.h>
46 #include <errno.h>
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <fcntl.h>
50
51 #if defined(__linux__)  &&  __GNU_LIBRARY__ == 1
52 #include <asm/io.h>                     /* Newer libraries use <sys/io.h> instead. */
53 #else
54 #include <sys/io.h>
55 /* Use   extern iopl(int level);  if your glibc does not define it. */
56 #endif
57
58 /* We should use __u8 .. __u32, but they are not always defined. */
59 typedef unsigned int u32;
60 typedef unsigned short u16;
61 typedef unsigned char u8;
62
63 struct option longopts[] = {
64  /* { name  has_arg  *flag  val } */
65         {"base-address", 1, 0, 'p'},
66         {"new-base-address", 1, 0, 'P'},
67         {"show-all-registers",  0, 0, 'a'},     /* Print all registers. */
68         {"debug",                       0, 0, 'D'},
69         {"show-eeprom",         0, 0, 'e'}, /* Dump EEPROM contents (-ee valid). */
70         {"help",                        0, 0, 'h'},     /* Give help */
71         {"emergency-rewrite",  0, 0, 'E'}, /* Re-write a corrupted EEPROM.  */
72         {"force-detection",  0, 0, 'f'},
73         {"new-interface",  1, 0, 'F'},  /* New interface (built-in, AUI, etc.) */
74         {"new-IOaddress",       1, 0, 'P'},     /* New base I/O address. */
75         {"new-irq",     1, 0, 'Q'},             /* New interrupt number */
76         {"verbose",     0, 0, 'v'},             /* Verbose mode */
77         {"version", 0, 0, 'V'},         /* Display version number */
78         {"write-EEPROM", 1, 0, 'w'},/* Actually write the EEPROM with new vals */
79         {"dump", 1, 0, 'd'},        /* Dump EEPROM content to file */
80         {"restore", 1, 0, 'r'},     /* Restore EEPROM content from fale */
81     {"new-hw", 1, 0, 'm'},      /* Sets the MAC adress of the card */
82     {"new-muid", 1, 0, 'u'},    /* Sets the Unique identifier of the card */
83         { 0, 0, 0, 0 }
84 };
85
86 /* Offsets from base I/O address. */
87 #define EL3_CMD 0x0e
88 #define EL3_STATUS 0x0e
89
90 enum Window0 {
91         Wn0EepromCmd = 10,              /* Window 0: EEPROM command register. */
92         Wn0EepromData = 12,             /* Window 0: EEPROM results register. */
93         IntrStatus=0x0E,                        /* Valid in all windows. */
94 };
95
96 #define  EEPROM_READ 0x80
97 #define  EEPROM_WRITE 0x40
98 #define  EEPROM_ERASE 0xC0
99 #define  EEPROM_EWENB 0x30              /* Enable erasing/writing for 10 msec. */
100 #define  EEPROM_EWDIS 0x00              /* Enable erasing/writing for 10 msec. */
101 enum Win0_EEPROM_bits {
102         EEPROM_Read = 0x80, EEPROM_Busy = 0x8000,
103 };
104
105 #define EL3WINDOW(win_num) outw(0x0800+(win_num), ioaddr + EL3_CMD)
106
107 /* Register window 1 offsets, the window used in normal operation. */
108 enum Window1 {
109         TX_FIFO = 0x0,  RX_FIFO = 0x0,  Wn1RxErrors = 0x4,
110         Wn1RxStatus = 0x8,  Wn1Timer=0xA, Wn1TxStatus = 0xB,
111         Wn1TxFree = 0xC, /* Remaining free bytes in Tx buffer. */
112 };
113
114 const char *intr_names[13] ={
115         "Interrupt latch", "Adapter Failure", "Tx Complete", "Tx Available",
116         "Rx Complete", "Rx Early Notice", "Driver Intr Request",
117         "Statistics Full", "DMA Done", "Download Complete", "Upload Complete",
118         "DMA in Progress", "Command in Progress",
119 };
120
121 /* EEPROM operation locations. */
122 enum eeprom_offset {
123         PhysAddr01=0, PhysAddr23=1, PhysAddr45=2, ModelID=3,
124         EtherLink3ID=7, IFXcvrIO=8, IRQLine=9,
125         AltPhysAddr01=10, AltPhysAddr23=11, AltPhysAddr45=12,
126         DriverTune=13, Checksum=15};
127
128 /* Last-hope recovery major boo-boos: rewrite the EEPROM with the values
129    from my card (and hope I don't met you on the net...).
130    This image is valid only for an pre-B 3c509.
131 */
132 unsigned short djb_eeprom[16] = {
133         0x0020, 0xaf0e, 0x3bc2, 0x9058, 0xbc4e, 0x0036, 0x4441, 0x6d50,
134         0x0090, 0xaf00, 0x0020, 0xaf0e, 0x3bc2, 0x1310, 0x0000, 0x343c, }; 
135 /* Values read from the EEPROM, and the new image. */
136 #define EEPROM_SPACE 64
137 unsigned short eeprom_contents[EEPROM_SPACE];
138 unsigned short new_ee_contents[EEPROM_SPACE];
139
140 int verbose = 1, opt_f = 0, debug = 0;
141 int show_regs = 0, show_eeprom = 0;
142 int do_write_eeprom = 0;
143 int ioaddr;
144
145 const char *intrs_pending_msg = 
146 " This network adapter has unhandled interrupts!\n"
147 " This should never occur with properly configured adapter.  You may have\n"
148 "   a hardware interrupt conflict.\n"
149 " Check /proc/interrupts to verify that the interrupt is properly\n"
150 "   registered, and that the count is increasing.\n"
151 " This problem is frequently solved by moving the adapter to different IRQ.\n"
152 " For ISA cards, verify that the BIOS setup has assigned the IRQ line to\n"
153 "  ISA bus.\n"
154 " For PCMCIA cards, change the configuration file, typically named\n"
155 "  /etc/pcmcia/config.opts, to use a different IRQ.\n";
156
157 static void print_eeprom(unsigned short *eeprom_contents);
158 static void write_eeprom(short ioaddr, int index, int value);
159 static unsigned int calculate_checksum(unsigned short *values);
160 static int do_update(unsigned short *ee_values,
161                                          int index, char *field_name, int new_value);
162 \f
163 int
164 main(int argc, char **argv)
165 {
166         int port_base = 0x300;
167         int new_interface = -1, new_irq = -1, new_ioaddr = -1;
168         int errflag = 0, show_version = 0;
169         int emergency_rewrite = 0;
170         int show_regs = 0, opt_a = 0;
171         char *dumpcard = NULL;
172         char *restorecard = NULL;
173     char *new_hw = NULL;
174     char *new_umid = NULL;
175         int c, longind, i, j, saved_window;
176         extern char *optarg;
177
178         while ((c = getopt_long(argc, argv, "aDeEfF:hi:p:P:Q:svVwX:d:r:o:m:",
179                                                         longopts, &longind))
180                    != -1)
181                 switch (c) {
182                 case 'a': show_regs++; opt_a++;         break;
183                 case 'D': debug++; break;
184                 case 'e': show_eeprom++;                break;
185                 case 'E': emergency_rewrite++;  break;
186                 case 'f': opt_f++; break;
187                 case 'F': case 'X':
188                         if (strncmp(optarg, "10base", 6) == 0) {
189                                 switch (optarg[6]) {
190                                 case 'T':  new_interface = 0; break;
191                                 case '2':  new_interface = 3; break;
192                                 case '5':  new_interface = 1; break;
193                                 default: errflag++;
194                                 }
195                         } else if (strcmp(optarg, "AUI") == 0)
196                                 new_interface = 1;
197                         else if (optarg[0] >= '0' &&  optarg[0] <= '3'
198                                            &&  optarg[1] == 0)
199                                 new_interface = optarg[0] - '0';
200                         else {
201                                 fprintf(stderr, "Invalid interface specified: it must be"
202                                                 " 0..3, '10base{T,2,5}' or 'AUI'.\n");
203                                 errflag++;
204                         }
205                         break;
206                 case 'Q':
207                         new_irq = atoi(optarg);
208                         if (new_irq < 3 || new_irq > 15 || new_irq == 6 || new_irq == 8) {
209                                 fprintf(stderr, "Invalid new IRQ %#x.  Valid values: "
210                                                 "3-5,7,9-15.\n", new_irq);
211                                 errflag++;
212                         }
213                         break;
214                 case 'p':
215                         port_base = strtol(optarg, NULL, 16);
216                         break;
217                 case 'P':
218                         new_ioaddr = strtol(optarg, NULL, 16);
219                         if (new_ioaddr < 0x200 || new_ioaddr > 0x3f0) {
220                                 fprintf(stderr, "Invalid new I/O address %#x.  Valid range "
221                                                 "0x200-0x3f0.\n", new_ioaddr);
222                                 errflag++;
223                         }
224                         break;
225                 case 'v': verbose++;             break;
226                 case 'V': show_version++;                break;
227                 case 'w': do_write_eeprom++;     break;
228                 case '?': case 'h':
229                         errflag++;
230         case 'd':
231                         dumpcard = optarg;
232                         break;
233                 case 'r':
234                         restorecard = optarg;
235                         break;
236                 case 'm':
237                         new_hw = optarg;
238                         break;
239                 case 'u':
240                         new_umid = optarg;
241                         break;
242                 }
243         if (errflag) {
244                 fprintf(stderr, usage_msg);
245                 return 3;
246         }
247
248         if (ioperm(port_base, 16, 1) < 0) {
249                 perror("3c5x9setup: ioperm()");
250                 fprintf(stderr, "This program must be run as root.\n");
251                 return 2;
252         }
253
254         if (verbose)
255                 printf(version_msg);
256
257         ioaddr = port_base;
258
259         saved_window = inw(ioaddr + EL3_STATUS);
260         if (saved_window == 0xffff) {
261                 printf("No EtherLink III device exists at address 0x%X.\n", ioaddr);
262                 if ( ! opt_f) {
263                         printf("Use the '-f' option proceed anyway.\n");
264                         return 2;
265                 }
266         }
267
268         /* We can check for a stuck interrupt even while the chip is active. */
269         if (verbose || opt_a) {
270                 unsigned intr_status = inw(ioaddr + IntrStatus);
271                 printf(" %snterrupt sources are pending.\n",
272                            (intr_status & 0x03ff) ? "I": "No i");
273                 if (intr_status & 0x3ff) {
274                         for (i = 0; i < 13; i++)
275                                 if (intr_status & (1<<i))
276                                         printf("   %s indication.\n", intr_names[i]);
277                 }
278         }
279         if (!opt_f  && (saved_window & 0xe000) == 0x2000) {
280                 int last_intr = inb(ioaddr + Wn1Timer);
281                 printf("A potential 3c5*9 has been found, but it appears to still be "
282                            "active.\nOnly limited information is available without "
283                            "disturbing network operation.\n"
284                            " Either shutdown the network, or use the '-f' flag to see all "
285                            "registers.\n");
286                 printf("  Available Tx room %d bytes, Tx/Rx Status %4.4x / %4.4x.\n",
287                            inw(ioaddr + Wn1TxFree), inb(ioaddr + Wn1TxStatus),
288                            inb(ioaddr + Wn1RxStatus));
289                 if (last_intr != 255)
290                         printf("  An interrupt occured only %d ticks ago!\n", last_intr);
291                 if (saved_window & 0x00ff)
292                         printf(intrs_pending_msg);
293                 return 1;
294         }
295
296         EL3WINDOW(0);
297         if (inw(port_base) == 0x6d50) {
298                 printf("3c5x9 found at %#3.3x.\n", port_base);
299         } else {
300                 printf("3c5*9 not found at %#3.3x, status %4.4x.\n"
301                            "If there is a 3c5*9 card in the machine, explicitly set the"
302                            " I/O port address\n  using '-p <ioaddr>\n",
303                            port_base, inw(port_base));
304                 if (opt_f < 2)
305                         return 1;
306         }
307
308         EL3WINDOW(5);
309         printf(" Indication enable is %4.4x, interrupt enable is %4.4x.\n",
310                    inw(ioaddr + 12), inw(ioaddr + 10));
311
312         if (show_regs) {
313                 const char *statname[12] = {
314                         "Carrier Lost", "Heartbeat", "Tx Multiple collisions",
315                         "Tx Single collisions", "Tx Late collisions", "Rx FIFO overruns",
316                         "Tx packets", "Rx packets", "Tx deferrals",
317                         "(256 Rx/Tx counts)", "Rx bytes", "Tx bytes"};
318                 int stats[12];
319                 /* First read the statistics registers, which are clear-on-read. */
320                 EL3WINDOW(6);
321                 for (i = 0; i < 10; i++)
322                         stats[i] = inb(ioaddr + i);
323                 stats[10] = inw(ioaddr + 10);
324                 stats[11] = inw(ioaddr + 12);
325                 for (i = 0; i < 12; i++)
326                         if (stats[i])
327                                 printf("  Event counts: %s is %d.\n", statname[i], stats[i]);
328         }
329                                                 
330         if (show_regs) {
331                 for (j = 0; j < 8; j++) {
332                         int i;
333                         printf("  Window %d:", j);
334                         outw(0x0800 + j, ioaddr + 0x0e);
335                         for (i = 0; i < 16; i+=2)
336                                 printf(" %4.4x", inw(ioaddr + i));
337                         printf(".\n");
338                 }
339         }
340
341         EL3WINDOW(0);
342
343         /* Read the EEPROM. */
344         for (i = 0; i < EEPROM_SPACE; i++) {
345                 int boguscheck;
346                 outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd);
347                 /* Pause for up to 162 us. for the read to take place.
348                    Typical max. 175 ticks. */
349                 for (boguscheck = 0; boguscheck < 1620; boguscheck++)
350                         if ((inw(ioaddr + Wn0EepromCmd) & EEPROM_Busy) == 0)
351                                 break;
352                 eeprom_contents[i] = inw(ioaddr + Wn0EepromData);
353                 if (show_eeprom > 2)
354                         printf("EEPROM read of index %d %s after %d ticks -> %4.4x.\n",
355                                    i, boguscheck < 1620 ? "completed" : "failed", boguscheck,
356                                    eeprom_contents[i]);
357         }
358
359         if (emergency_rewrite) {
360                 if (emergency_rewrite < 3  ||  !do_write_eeprom)
361                         printf(" Caution!  Last-chance EEPROM write requested.  The\n"
362                                    " new EEPROM values will not be written without"
363                                    " '-E -E -E -w' flags.\n");
364                 else {
365                         for (i = 0; i < 16; i++) {
366                                 eeprom_contents[i] = djb_eeprom[i];
367                                 write_eeprom(ioaddr, i, eeprom_contents[i]);
368                         }
369                 }
370         }
371
372     if (restorecard)
373          {
374       int fd;
375       int ret;
376
377           if ((fd = open(restorecard, O_RDONLY)))
378            {
379                 for (i = 0; i < 16; i++)
380                  {
381                   while ((ret = read(fd, (char *) (eeprom_contents + i), 1)) == 0);
382                   if (ret < 0)
383                    break;
384                   while ((ret = read(fd, ((char *) (eeprom_contents + i)) + 1, 1)) == 0);
385                   if (ret < 0)
386                    break;
387                  }
388                 if (ret < 0)
389                  {
390                   perror("Unable to read EEPROM image from file.");
391                   exit(1);
392                  }
393                 else
394                  fprintf(stderr, "EEPROM image read from file '%s'.\n", restorecard);
395                 close(fd);
396        }
397           else
398            {
399                 perror("Unable to read EEPROM image from file.");
400                 exit(1);
401            }
402           if (do_write_eeprom)
403            {
404         for (i = 0; i < 16; i++)
405          write_eeprom(ioaddr, i, eeprom_contents[i]);
406                 fprintf(stderr, "EEPROM image written to card.\n");
407            }
408           else
409            fprintf(stderr, "Specify -w to write image to card.\n");
410          }
411
412         {
413                 unsigned short new_ifxcvrio = eeprom_contents[IFXcvrIO];
414                 unsigned short new_irqline = eeprom_contents[IRQLine];
415                 int something_changed = 0;
416
417                 if (new_interface >= 0)
418                         new_ifxcvrio = (new_interface << 14) | (new_ifxcvrio & 0x3fff);
419                 if (new_ioaddr > 0)
420                         new_ifxcvrio = ((new_ioaddr>>4) & 0x1f) | (new_ifxcvrio & 0xffe0);
421                 if (new_irq > 0)
422                         new_irqline = (new_irq << 12) | 0x0f00;
423
424                 if (do_update(eeprom_contents, IRQLine, "IRQ", new_irqline))
425                         something_changed++;
426
427                 if (do_update(eeprom_contents, IFXcvrIO, "transceiver/IO",
428                                           new_ifxcvrio))
429                         something_changed++;
430
431                 if (new_hw)
432                  {
433           unsigned short mac_address_tmp[6];
434           unsigned char  mac_address[6];
435
436           sscanf(new_hw, "%X:%X:%X:%X:%X:%X",
437                                  (unsigned int* ) (mac_address_tmp + 0), (unsigned int* ) (mac_address_tmp + 1),
438                                  (unsigned int* ) (mac_address_tmp + 2), (unsigned int* ) (mac_address_tmp + 3),
439                                  (unsigned int* ) (mac_address_tmp + 4), (unsigned int* ) (mac_address_tmp + 5));
440
441           for (i = 0; i < 6; i++)
442            mac_address[i] = (unsigned char) mac_address_tmp[i^1];
443
444           do_update(eeprom_contents, PhysAddr01, "MACAddress", ((unsigned short*) mac_address)[0]);
445                   do_update(eeprom_contents, PhysAddr23, "MACAddress", ((unsigned short*) mac_address)[1]);
446                   do_update(eeprom_contents, PhysAddr45, "MACAddress", ((unsigned short*) mac_address)[2]);
447                  }
448
449                 if (new_umid)
450                  {
451           unsigned short mac_address_tmp[6];
452           unsigned char  mac_address[6];
453
454           sscanf(new_umid, "%X:%X:%X:%X:%X:%X",
455                                  (unsigned int* ) (mac_address_tmp + 0), (unsigned int* ) (mac_address_tmp + 1),
456                                  (unsigned int* ) (mac_address_tmp + 2), (unsigned int* ) (mac_address_tmp + 3),
457                                  (unsigned int* ) (mac_address_tmp + 4), (unsigned int* ) (mac_address_tmp + 5));
458
459           for (i = 0; i < 6; i++)
460            mac_address[i] = (unsigned char) mac_address_tmp[i^1];
461
462           do_update(eeprom_contents, AltPhysAddr01, "UMID", ((unsigned short*) mac_address)[0]);
463                   do_update(eeprom_contents, AltPhysAddr23, "UMID", ((unsigned short*) mac_address)[1]);
464                   do_update(eeprom_contents, AltPhysAddr45, "UMID", ((unsigned short*) mac_address)[2]);
465                  }
466
467                 /* To change another EEPROM value write it here. */
468
469                 if (do_update(eeprom_contents, Checksum, "checksum",
470                                           calculate_checksum(eeprom_contents)))
471                         something_changed++;
472
473                 if (something_changed  &&  !do_write_eeprom)
474                         printf(" (The new EEPROM values will not be written without"
475                                         " the '-w' flag.)\n");
476         }
477
478         if (verbose > 1 || show_eeprom) {
479                 print_eeprom(eeprom_contents);
480         }
481
482     if (dumpcard)
483          {
484       int fd;
485       int ret;
486
487           if ((fd = open(dumpcard, O_WRONLY | O_CREAT | O_TRUNC)))
488            {
489                 for (i = 0; i < 16; i++)
490                  {
491                   while ((ret = write(fd, (char *) (eeprom_contents + i), 1)) == 0);
492                   if (ret < 0)
493                    break;
494                   while ((ret = write(fd, ((char *) (eeprom_contents + i)) + 1, 1)) == 0);
495                   if (ret < 0)
496                    break;
497                  }
498                 if (ret < 0)
499                  perror("Unable to write EEPROM image to file.");
500                 else
501                  fprintf(stderr, "EEPROM image written to file '%s'.\n", dumpcard);
502            }
503           else
504        perror("Unable to write EEPROM image to file.");
505       close(fd);
506          }
507
508         EL3WINDOW(saved_window>>13);
509
510         return 0;
511 }
512
513 static void print_eeprom(unsigned short *eeprom_contents)
514 {
515         char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"};
516         u16 *ee = eeprom_contents;
517         int i;
518
519         printf(" EEPROM contents:");
520         if (show_eeprom)
521                 for(i = 0; i < EEPROM_SPACE; i++)
522                         printf("%s %4.4x", i % 8 ? "" : "\n   ", eeprom_contents[i]);
523         printf("\n  Model number 3c%2.2x%1.1x version %1.1x, base I/O %#x, IRQ %d, "
524                    "%s port.\n",
525                    eeprom_contents[ModelID] & 0x00ff,
526                    eeprom_contents[ModelID] >> 12,
527                    (eeprom_contents[ModelID] >> 8) & 0x000f,
528                    0x200 + ((eeprom_contents[IFXcvrIO] & 0x1f) << 4),
529                    eeprom_contents[IRQLine] >> 12,
530                    if_names[eeprom_contents[IFXcvrIO] >> 14]);
531
532         printf("  3Com Node Address (UMID) ");
533         for (i =  0; i < 6; i++)
534                 printf("%2.2X%s", ((unsigned char *)(eeprom_contents + AltPhysAddr01))[i^1], i < 5 ? ":" : " (used as a unique ID only).\n");
535         printf("  OEM Station address (MAC) ");
536         for (i =  0; i < 6; i++)
537                 printf("%2.2X%s", ((unsigned char *)(eeprom_contents + PhysAddr01))[i^1], i < 5 ? ":" : " (used as the ethernet address).\n");
538
539         /* Y2K safe.  This two-digit date is for information purposes only.
540            It is never used for computations. */
541         printf("  Manufacture date (MM/DD/YY) %d/%d/%d, division %c,"
542                    " product %c%c.\n", (ee[4] >> 5) & 15,
543                    ee[4] & 31, ee[4] >> 9, ((unsigned char *)(eeprom_contents + PhysAddr01))[10], ((unsigned char *)(eeprom_contents + PhysAddr01))[12], ((unsigned char *)(eeprom_contents + PhysAddr01))[13]);
544         printf("  Options: %s duplex, %sable linkbeat.\n",
545                    ee[13] & 0x8000 ? "force full" : "half",
546                    ee[13] & 0x4000 ? "dis" : "en");
547
548         if (calculate_checksum(eeprom_contents) != eeprom_contents[Checksum])
549                 printf("****CHECKSUM ERROR****: Calcuated checksum: %4.4x, "
550                            "stored checksum %4.4x.\n",
551                            calculate_checksum(eeprom_contents),
552                            eeprom_contents[Checksum]);
553         else
554                 printf("  The computed checksum matches the stored checksum of %4.4x.\n",
555                            eeprom_contents[Checksum]);
556 }
557
558
559 static void write_eeprom(short ioaddr, int index, int value)
560 {
561         int timer;
562         /* Verify that the EEPROM is idle. */
563         for (timer = 1620; inw(ioaddr + Wn0EepromCmd) & 0x8000;)
564                 if (--timer < 0)
565                         goto error_return;
566         outw(EEPROM_EWENB, ioaddr + Wn0EepromCmd);
567         usleep(60);
568         outw(EEPROM_ERASE + index, ioaddr + Wn0EepromCmd);
569         usleep(60);
570         outw(EEPROM_EWENB, ioaddr + Wn0EepromCmd);
571         usleep(60);
572         outw(value, ioaddr + Wn0EepromData);
573         outw(EEPROM_WRITE + index, ioaddr + Wn0EepromCmd);
574         for (timer = 16000; inw(ioaddr + Wn0EepromCmd) & 0x8000;)
575                 if (--timer < 0)
576                         goto error_return;
577         if (debug)
578                 fprintf(stderr, "EEPROM wrote index %d with 0x%4.4x after %d ticks!\n",
579                                 index, value, 16000-timer);
580         return;
581 error_return:
582         fprintf(stderr, "Failed to write EEPROM location %d with 0x%4.4x!\n",
583                         index, value);
584 }
585
586 /* Calculate the EEPROM checksum.
587    The checksum for the fixed values is returned in the high byte.
588    The checksum for the programmable variables is in the low the byte.
589    */
590
591 static unsigned int
592 calculate_checksum(unsigned short *values)
593 {
594         int fixed_checksum = 0, var_checksum = 0;
595         int i;
596
597         for (i = 0; i <= 14; i++) {                             /* Note: 14 (loc. 15 is the sum) */
598                 if (i == IFXcvrIO || i == IRQLine || i == DriverTune)
599                         var_checksum ^= values[i];
600                 else
601                         fixed_checksum ^= values[i];
602         }
603         return ((fixed_checksum ^ (fixed_checksum << 8)) & 0xff00) |
604                 ((var_checksum ^ (var_checksum >> 8)) & 0xff);
605 }
606
607 static int do_update(unsigned short *ee_values,
608                                          int index, char *field_name, int new_value)
609 {
610         if (ee_values[index] != new_value) {
611                 if (do_write_eeprom) {
612                         printf("Writing new %s entry 0x%4.4x.\n",
613                                    field_name, new_value);
614                         write_eeprom(ioaddr, index, new_value);
615                 } else
616                         printf(" Would write new %s entry 0x%4.4x (old value 0x%4.4x).\n",
617                                    field_name, new_value, ee_values[index]);
618                 ee_values[index] = new_value;
619                 return 1;
620         }
621         return 0;
622 }
623
624 \f
625 /*
626  * Local variables:
627  *  compile-command: "cc -O -Wall -o 3c5x9setup 3c5x9setup.c"
628  *  c-indent-level: 4
629  *  c-basic-offset: 4
630  *  tab-width: 4
631  * End:
632  */
This page took 0.128071 seconds and 3 git commands to generate.