Fix typo.
[b43-tools.git] / ssb_sprom / ssb_sprom.c
1 /*
2
3   Broadcom Sonics Silicon Backplane bus SPROM data modification tool
4
5   Copyright (c) 2006-2007 Michael Buesch <mb@bu3sch.de>
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; see the file COPYING.  If not, write to
19   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20   Boston, MA 02110-1301, USA.
21
22 */
23
24 #include "ssb_sprom.h"
25 #include "utils.h"
26
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <sys/stat.h>
32
33
34 struct cmdline_args cmdargs;
35 uint8_t sprom_rev;
36 uint16_t sprom_size;
37
38 static int value_length_map[] = { /* value to number of bits */
39         [VALUE_RAW] = 8,
40         [VALUE_SUBP] = 16,
41         [VALUE_SUBV] = 16,
42         [VALUE_PPID] = 16,
43         [VALUE_BFLHI] = 16,
44         [VALUE_BFL] = 16,
45         [VALUE_BGMAC] = -1,
46         [VALUE_ETMAC] = -1,
47         [VALUE_AMAC] = -1,
48         [VALUE_ET0PHY] = 8,
49         [VALUE_ET1PHY] = 8,
50         [VALUE_ET0MDC] = 1,
51         [VALUE_ET1MDC] = 1,
52         [VALUE_BREV] = 8,
53         [VALUE_LOC] = 4,
54         [VALUE_ANTA0] = 1,
55         [VALUE_ANTA1] = 1,
56         [VALUE_ANTBG0] = 1,
57         [VALUE_ANTBG1] = 1,
58         [VALUE_ANTGA] = 8,
59         [VALUE_ANTGBG] = 8,
60         [VALUE_PA0B0] = 16,
61         [VALUE_PA0B1] = 16,
62         [VALUE_PA0B2] = 16,
63         [VALUE_PA1B0] = 16,
64         [VALUE_PA1B1] = 16,
65         [VALUE_PA1B2] = 16,
66         [VALUE_WL0GPIO0] = 8,
67         [VALUE_WL0GPIO1] = 8,
68         [VALUE_WL0GPIO2] = 8,
69         [VALUE_WL0GPIO3] = 8,
70         [VALUE_MAXPA] = 8,
71         [VALUE_MAXPBG] = 8,
72         [VALUE_ITSSIA] = 8,
73         [VALUE_ITSSIBG] = 8,
74         [VALUE_SVER] = 8,
75 };
76
77
78 static int hexdump_sprom(const uint8_t *sprom, char *buffer, size_t bsize)
79 {
80         int i, pos = 0;
81
82         for (i = 0; i < sprom_size; i++) {
83                 pos += snprintf(buffer + pos, bsize - pos - 1,
84                                 "%02X", sprom[i] & 0xFF);
85         }
86
87         return pos + 1;
88 }
89
90 static uint8_t sprom_crc(const uint8_t *sprom)
91 {
92         int i;
93         uint8_t crc = 0xFF;
94
95         for (i = 0; i < sprom_size - 1; i++)
96                 crc = crc8(crc, sprom[i]);
97         crc ^= 0xFF;
98
99         return crc;
100 }
101
102 static int write_output_binary(int fd, const uint8_t *sprom)
103 {
104         ssize_t w;
105
106         w = write(fd, sprom, sprom_size);
107         if (w < 0)
108                 return -1;
109
110         return 0;
111 }
112
113 static int write_output_hex(int fd, const uint8_t *sprom)
114 {
115         ssize_t w;
116         char tmp[SPROM4_SIZE * 2 + 10] = { 0 };
117
118         hexdump_sprom(sprom, tmp, sizeof(tmp));
119         prinfo("Raw output:  %s\n", tmp);
120         w = write(fd, tmp, sprom_size * 2);
121         if (w < 0)
122                 return -1;
123
124         return 0;
125 }
126
127 static int write_output(int fd, const uint8_t *sprom)
128 {
129         int err;
130
131         if (cmdargs.outfile) {
132                 err = ftruncate(fd, 0);
133                 if (err) {
134                         prerror("Could not truncate --outfile %s\n",
135                                 cmdargs.outfile);
136                         return -1;
137                 }
138         }
139
140         if (cmdargs.bin_mode)
141                 err = write_output_binary(fd, sprom);
142         else
143                 err = write_output_hex(fd, sprom);
144         if (err)
145                 prerror("Could not write output data.\n");
146
147         return err;
148 }
149
150 static int modify_value(uint8_t *sprom,
151                         struct cmdline_vparm *vparm)
152 {
153         const uint16_t v = vparm->u.value;
154         uint16_t tmp = 0;
155         uint16_t offset;
156
157         switch (vparm->type) {
158         case VALUE_RAW:
159                 sprom[vparm->u.raw.offset] = vparm->u.raw.value;
160                 break;
161         case VALUE_SUBP:
162                 if (sprom_rev == 4)
163                         offset = SPROM4_SUBP;
164                 else
165                         offset = SPROM_SUBP;
166                 sprom[offset + 0] = (v & 0x00FF);
167                 sprom[offset + 1] = (v & 0xFF00) >> 8;
168                 break;
169         case VALUE_SUBV:
170                 sprom[SPROM_SUBV + 0] = (v & 0x00FF);
171                 sprom[SPROM_SUBV + 1] = (v & 0xFF00) >> 8;
172                 break;
173         case VALUE_PPID:
174                 if (sprom_rev == 4)
175                         offset = SPROM4_PPID;
176                 else
177                         offset = SPROM_PPID;
178                 sprom[offset + 0] = (v & 0x00FF);
179                 sprom[offset + 1] = (v & 0xFF00) >> 8;
180                 break;
181         case VALUE_BFLHI:
182                 sprom[SPROM_BFLHI + 0] = (v & 0x00FF);
183                 sprom[SPROM_BFLHI + 1] = (v & 0xFF00) >> 8;
184                 break;
185         case VALUE_BFL:
186                 sprom[SPROM_BOARDFLAGS + 0] = (v & 0x00FF);
187                 sprom[SPROM_BOARDFLAGS + 1] = (v & 0xFF00) >> 8;
188                 break;
189         case VALUE_BGMAC:
190                 if (sprom_rev == 3)
191                         offset = SPROM3_IL0MACADDR;
192                 else if (sprom_rev == 4)
193                         offset = SPROM4_IL0MACADDR;
194                 else
195                         offset = SPROM_IL0MACADDR;
196                 sprom[offset + 1] = vparm->u.mac[0];
197                 sprom[offset + 0] = vparm->u.mac[1];
198                 sprom[offset + 3] = vparm->u.mac[2];
199                 sprom[offset + 2] = vparm->u.mac[3];
200                 sprom[offset + 5] = vparm->u.mac[4];
201                 sprom[offset + 4] = vparm->u.mac[5];
202                 break;
203         case VALUE_ETMAC:
204                 if (sprom_rev == 3)
205                         offset = SPROM3_ET0MACADDR;
206                 else if (sprom_rev == 4)
207                         offset = SPROM4_ET0MACADDR;
208                 else
209                         offset = SPROM_ET0MACADDR;
210                 sprom[offset + 1] = vparm->u.mac[0];
211                 sprom[offset + 0] = vparm->u.mac[1];
212                 sprom[offset + 3] = vparm->u.mac[2];
213                 sprom[offset + 2] = vparm->u.mac[3];
214                 sprom[offset + 5] = vparm->u.mac[4];
215                 sprom[offset + 4] = vparm->u.mac[5];
216                 break;
217         case VALUE_AMAC:
218                 if (sprom_rev == 3)
219                         offset = SPROM3_ET1MACADDR;
220                 else if (sprom_rev == 4)
221                         offset = SPROM4_ET1MACADDR;
222                 else
223                         offset = SPROM_ET1MACADDR;
224                 sprom[offset + 1] = vparm->u.mac[0];
225                 sprom[offset + 0] = vparm->u.mac[1];
226                 sprom[offset + 3] = vparm->u.mac[2];
227                 sprom[offset + 2] = vparm->u.mac[3];
228                 sprom[offset + 5] = vparm->u.mac[4];
229                 sprom[offset + 4] = vparm->u.mac[5];
230                 break;
231         case VALUE_ET0PHY:
232                 tmp |= sprom[SPROM_ETHPHY + 0];
233                 tmp |= sprom[SPROM_ETHPHY + 1] << 8;
234                 tmp = ((tmp & 0x001F) | (v & 0x1F));
235                 sprom[SPROM_ETHPHY + 0] = (tmp & 0x00FF);
236                 sprom[SPROM_ETHPHY + 1] = (tmp & 0xFF00) >> 8;
237                 break;
238         case VALUE_ET1PHY:
239                 tmp |= sprom[SPROM_ETHPHY + 0];
240                 tmp |= sprom[SPROM_ETHPHY + 1] << 8;
241                 tmp = ((tmp & 0x03E0) | ((v & 0x1F) << 5));
242                 sprom[SPROM_ETHPHY + 0] = (tmp & 0x00FF);
243                 sprom[SPROM_ETHPHY + 1] = (tmp & 0xFF00) >> 8;
244                 break;
245         case VALUE_ET0MDC:
246                 sprom[SPROM_ETHPHY + 1] &= ~(1 << 6);
247                 if (v)
248                         sprom[SPROM_ETHPHY + 1] |= (1 << 6);
249                 break;
250         case VALUE_ET1MDC:
251                 sprom[SPROM_ETHPHY + 1] &= ~(1 << 7);
252                 if (v)
253                         sprom[SPROM_ETHPHY + 1] |= (1 << 7);
254                 break;
255         case VALUE_BREV:
256                 if (sprom_rev == 4)
257                         sprom[SPROM4_BOARDREV + 0] = v;
258                 else
259                         sprom[SPROM_BOARDREV + 0] = v;
260                 break;
261         case VALUE_LOC:
262                 tmp = (sprom[SPROM_BOARDREV + 1] & 0xF0);
263                 tmp |= (v & 0x0F);
264                 sprom[SPROM_BOARDREV + 1] = (tmp & 0xFF);
265                 break;
266         case VALUE_ANTA0:
267                 if (sprom_rev == 4)
268                         sprom[SPROM4_BOARDREV + 1] &= ~(1 << 6);
269                 else
270                         sprom[SPROM_BOARDREV + 1] &= ~(1 << 6);
271                 if (v) {
272                         if (sprom_rev == 4) {
273                                 if (sprom_rev == 4)
274                                         sprom[SPROM4_BOARDREV + 1] |= ~(1 << 6);
275                                 else
276                                         sprom[SPROM_BOARDREV + 1] |= (1 << 6);
277                         }
278                 }
279                 break;
280         case VALUE_ANTA1:
281                 sprom[SPROM_BOARDREV + 1] &= ~(1 << 7);
282                 if (v)
283                         sprom[SPROM_BOARDREV + 1] |= (1 << 7);
284                 break;
285         case VALUE_ANTBG0:
286                 sprom[SPROM_BOARDREV + 1] &= ~(1 << 4);
287                 if (v)
288                         sprom[SPROM_BOARDREV + 1] |= (1 << 4);
289                 break;
290         case VALUE_ANTBG1:
291                 sprom[SPROM_BOARDREV + 1] &= ~(1 << 5);
292                 if (v)
293                         sprom[SPROM_BOARDREV + 1] |= (1 << 5);
294                 break;
295         case VALUE_ANTGA:
296                 if (sprom_rev != 4)
297                         sprom[SPROM_ANTENNA_GAIN + 1] = (v & 0xFF);
298                 else
299                         sprom[SPROM4_ANTENNA_GAIN + 1] = (v & 0xFF);
300                 break;
301         case VALUE_ANTGBG:
302                 if (sprom_rev != 4)
303                         sprom[SPROM_ANTENNA_GAIN] = (v & 0xFF);
304                 else
305                         sprom[SPROM4_ANTENNA_GAIN] = (v & 0xFF);
306                 break;
307         case VALUE_PA0B0:
308                 sprom[SPROM_PA0B0 + 0] = (v & 0x00FF);
309                 sprom[SPROM_PA0B0 + 1] = (v & 0xFF00) >> 8;
310                 break;
311         case VALUE_PA0B1:
312                 sprom[SPROM_PA0B1 + 0] = (v & 0x00FF);
313                 sprom[SPROM_PA0B1 + 1] = (v & 0xFF00) >> 8;
314                 break;
315         case VALUE_PA0B2:
316                 sprom[SPROM_PA0B2 + 0] = (v & 0x00FF);
317                 sprom[SPROM_PA0B2 + 1] = (v & 0xFF00) >> 8;
318                 break;
319         case VALUE_PA1B0:
320                 sprom[SPROM_PA1B0 + 0] = (v & 0x00FF);
321                 sprom[SPROM_PA1B0 + 1] = (v & 0xFF00) >> 8;
322                 break;
323         case VALUE_PA1B1:
324                 sprom[SPROM_PA1B1 + 0] = (v & 0x00FF);
325                 sprom[SPROM_PA1B1 + 1] = (v & 0xFF00) >> 8;
326                 break;
327         case VALUE_PA1B2:
328                 sprom[SPROM_PA1B2 + 0] = (v & 0x00FF);
329                 sprom[SPROM_PA1B2 + 1] = (v & 0xFF00) >> 8;
330                 break;
331         case VALUE_WL0GPIO0:
332                 sprom[SPROM_WL0GPIO0 + 0] = (v & 0xFF);
333                 break;
334         case VALUE_WL0GPIO1:
335                 sprom[SPROM_WL0GPIO0 + 1] = (v & 0xFF);
336                 break;
337         case VALUE_WL0GPIO2:
338                 sprom[SPROM_WL0GPIO2 + 0] = (v & 0xFF);
339                 break;
340         case VALUE_WL0GPIO3:
341                 sprom[SPROM_WL0GPIO2 + 1] = (v & 0xFF);
342                 break;
343         case VALUE_MAXPA:
344                 sprom[SPROM_MAXPWR + 0] = (v & 0xFF);
345                 break;
346         case VALUE_MAXPBG:
347                 sprom[SPROM_MAXPWR + 1] = (v & 0xFF);
348                 break;
349         case VALUE_ITSSIA:
350                 sprom[SPROM_IDL_TSSI_TGT + 0] = (v & 0xFF);
351                 break;
352         case VALUE_ITSSIBG:
353                 sprom[SPROM_IDL_TSSI_TGT + 1] = (v & 0xFF);
354                 break;
355         case VALUE_SVER:
356                 if (sprom_rev != 4)
357                         sprom[SPROM_VERSION + 0] = (v & 0xFF);
358                 else
359                         sprom[SPROM4_VERSION + 0] = (v & 0xFF);
360                 break;
361         default:
362                 prerror("vparm->type internal error (0)\n");
363                 exit(1);
364         }
365
366         return 0;
367 }
368
369 static int modify_sprom(uint8_t *sprom)
370 {
371         struct cmdline_vparm *vparm;
372         int i;
373         int modified = 0;
374         uint8_t crc;
375
376         for (i = 0; i < cmdargs.nr_vparm; i++) {
377                 vparm = &(cmdargs.vparm[i]);
378                 if (!vparm->set)
379                         continue;
380                 modify_value(sprom, vparm);
381                 modified = 1;
382         }
383         if (modified) {
384                 /* Recalculate the CRC. */
385                 crc = sprom_crc(sprom);
386                 sprom[sprom_size - 1] = crc;
387         }
388
389         return modified;
390 }
391
392 static void display_value(const uint8_t *sprom,
393                           struct cmdline_vparm *vparm)
394 {
395         const char *desc;
396         uint16_t offset;
397         uint16_t value;
398         uint16_t tmp;
399
400         switch (vparm->type) {
401         case VALUE_RAW:
402                 desc = "RAW";
403                 offset = vparm->u.raw.offset;
404                 value = sprom[offset];
405                 break;
406         case VALUE_SUBP:
407                 desc = "Subsystem product ID";
408                 if (sprom_rev == 4)
409                         offset = SPROM4_SUBP;
410                 else
411                         offset = SPROM_SUBP;
412                 value = sprom[offset + 0];
413                 value |= sprom[offset + 1] << 8;
414                 break;
415         case VALUE_SUBV:
416                 desc = "Subsystem vendor ID";
417                 offset = SPROM_SUBV;
418                 value = sprom[SPROM_SUBV + 0];
419                 value |= sprom[SPROM_SUBV + 1] << 8;
420                 break;
421         case VALUE_PPID:
422                 desc = "PCI Product ID";
423                 if (sprom_rev == 4)
424                         offset = SPROM4_PPID;
425                 else
426                         offset = SPROM_PPID;
427                 value = sprom[offset + 0];
428                 value |= sprom[offset + 1] << 8;
429                 break;
430         case VALUE_BFLHI:
431                 desc = "High 16 bits of Boardflags";
432                 if (sprom_rev == 4)
433                         offset = SPROM4_BOARDFLAGS + 2;
434                 else
435                         offset = SPROM_BFLHI;
436                 value = sprom[offset + 0];
437                 value |= sprom[offset + 1] << 8;
438                 break;
439         case VALUE_BFL:
440                 desc = "Low 16 bits of Boardflags";
441                 if (sprom_rev == 4)
442                         offset = SPROM4_BOARDFLAGS;
443                 else
444                         offset = SPROM_BOARDFLAGS;
445                 value = sprom[offset + 0];
446                 value |= sprom[offset + 1] << 8;
447                 break;
448         case VALUE_BGMAC:
449                 desc = "MAC address for 802.11b/g";
450                 if (sprom_rev == 3)
451                         offset = SPROM3_IL0MACADDR;
452                 else if (sprom_rev == 4)
453                         offset = SPROM4_IL0MACADDR;
454                 else
455                         offset = SPROM_IL0MACADDR;
456                 value = 0;
457                 break;
458         case VALUE_ETMAC:
459                 desc = "MAC address for ethernet";
460                 if (sprom_rev == 3)
461                         offset = SPROM3_ET0MACADDR;
462                 else if (sprom_rev == 4)
463                         offset = SPROM4_ET0MACADDR;
464                 else
465                         offset = SPROM_ET0MACADDR;
466                 value = 0;
467                 break;
468         case VALUE_AMAC:
469                 desc = "MAC address for 802.11a";
470                 if (sprom_rev == 3)
471                         offset = SPROM3_ET1MACADDR;
472                 else if (sprom_rev == 4)
473                         offset = SPROM4_ET1MACADDR;
474                 else
475                         offset = SPROM_ET1MACADDR;
476                 value = 0;
477                 break;
478         case VALUE_ET0PHY:
479                 desc = "Ethernet phy settings (0)";
480                 offset = SPROM_ETHPHY;
481                 tmp = sprom[SPROM_ETHPHY + 0];
482                 tmp |= sprom[SPROM_ETHPHY + 1] << 8;
483                 value = (tmp & 0x001F);
484                 break;
485         case VALUE_ET1PHY:
486                 desc = "Ethernet phy settings (1)";
487                 offset = SPROM_ETHPHY;
488                 tmp = sprom[SPROM_ETHPHY + 0];
489                 tmp |= sprom[SPROM_ETHPHY + 1] << 8;
490                 value = (tmp & 0x03E0) >> 5;
491                 break;
492         case VALUE_ET0MDC:
493                 desc = "et0mdcport";
494                 offset = SPROM_ETHPHY + 1;
495                 value = 0;
496                 if (sprom[SPROM_ETHPHY + 1] & (1 << 6))
497                         value = 1;
498                 break;
499         case VALUE_ET1MDC:
500                 desc = "et1mdcport";
501                 offset = SPROM_ETHPHY + 1;
502                 value = 0;
503                 if (sprom[SPROM_ETHPHY + 1] & (1 << 7))
504                         value = 1;
505                 break;
506         case VALUE_BREV:
507                 desc = "Board revision";
508                 if (sprom_rev == 4)
509                         offset = SPROM4_BOARDREV;
510                 else
511                         offset = SPROM_BOARDREV;
512                 value = sprom[offset + 0];
513                 break;
514         case VALUE_LOC:
515                 desc = "Locale / Country Code";
516                 if (sprom_rev == 4) {
517                         offset = SPROM4_COUNTRY;
518                         value = sprom[offset] | (sprom[offset + 1] << 8);
519                 } else {
520                         offset = SPROM_BOARDREV;
521                         value = (sprom[offset + 1] & 0x0F);
522                 }
523                 break;
524         case VALUE_ANTA0:
525                 desc = "A PHY antenna 0 available";
526                 value = 0;
527                 if (sprom_rev == 4) {
528                         offset = SPROM4_ANTAVAIL;
529                         if (sprom[offset + 1] & 1)
530                                 value = 1;
531                 } else {
532                         offset = SPROM_BOARDREV;
533                         value = 0;
534                         if (sprom[offset + 2] & (1 << 6))
535                                 value = 1;
536                 }
537                 break;
538         case VALUE_ANTA1:
539                 desc = "A PHY antenna 1 available";
540                 value = 0;
541                 if (sprom_rev == 4) {
542                         offset = SPROM4_ANTAVAIL;
543                         if (sprom[offset + 1] & 2)
544                                 value = 1;
545                 } else {
546                         offset = SPROM_BOARDREV;
547                         value = 0;
548                         if (sprom[offset + 2] & (1 << 7))
549                                 value = 1;
550                 }
551                 break;
552         case VALUE_ANTBG0:
553                 desc = "B/G PHY antenna 0 available";
554                 value = 0;
555                 if (sprom_rev == 4) {
556                         offset = SPROM4_ANTAVAIL;
557                         if (sprom[offset] & 1)
558                                 value = 1;
559                 } else {
560                         offset = SPROM_BOARDREV;
561                         value = 0;
562                         if (sprom[offset + 2] & (1 << 4))
563                                 value = 1;
564                 }
565                 break;
566         case VALUE_ANTBG1:
567                 desc = "B/G PHY antenna 1 available";
568                 value = 0;
569                 if (sprom_rev == 4) {
570                         offset = SPROM4_ANTAVAIL;
571                         if (sprom[offset] & 2)
572                                 value = 1;
573                 } else {
574                         offset = SPROM_BOARDREV;
575                         value = 0;
576                         if (sprom[offset + 2] & (1 << 5))
577                                 value = 1;
578                 }
579                 break;
580         case VALUE_ANTGA:
581                 if (sprom_rev != 4) {
582                         desc = "A PHY antenna gain";
583                         offset = SPROM_ANTENNA_GAIN;
584                 } else {
585                         desc = "Antenna 1 Gain";
586                         offset = SPROM4_ANTENNA_GAIN;
587                 }
588                 value = sprom[offset + 1];
589                 break;
590         case VALUE_ANTGBG:
591                 if (sprom_rev != 4) {
592                         desc = "B/G PHY antenna gain";
593                         offset = SPROM_ANTENNA_GAIN;
594                 } else {
595                         desc = "Antenna 0 Gain";
596                         offset = SPROM4_ANTENNA_GAIN;
597                 }
598                 value = sprom[offset];
599                 break;
600         case VALUE_PA0B0:
601                 desc = "pa0b0";
602                 offset = SPROM_PA0B0;
603                 value = sprom[offset + 0];
604                 value |= sprom[offset + 1] << 8;
605                 break;
606         case VALUE_PA0B1:
607                 desc = "pa0b1";
608                 offset = SPROM_PA0B1;
609                 value = sprom[offset + 0];
610                 value |= sprom[offset + 1] << 8;
611                 break;
612         case VALUE_PA0B2:
613                 desc = "pa0b2";
614                 offset = SPROM_PA0B2;
615                 value = sprom[offset + 0];
616                 value |= sprom[offset + 1] << 8;
617                 break;
618         case VALUE_PA1B0:
619                 desc = "pa1b0";
620                 offset = SPROM_PA1B0;
621                 value = sprom[offset + 0];
622                 value |= sprom[offset + 1] << 8;
623                 break;
624         case VALUE_PA1B1:
625                 desc = "pa1b1";
626                 offset = SPROM_PA1B1;
627                 value = sprom[offset + 0];
628                 value |= sprom[offset + 1] << 8;
629                 break;
630         case VALUE_PA1B2:
631                 desc = "pa1b2";
632                 offset = SPROM_PA1B2;
633                 value = sprom[offset + 0];
634                 value |= sprom[offset + 1] << 8;
635                 break;
636         case VALUE_WL0GPIO0:
637                 desc = "LED 0 behaviour";
638                 if (sprom_rev != 4)
639                         offset = SPROM_WL0GPIO0 + 0;
640                 else
641                         offset = SPROM4_WL0GPIO0 + 0;
642                 value = sprom[offset];
643                 break;
644         case VALUE_WL0GPIO1:
645                 desc = "LED 1 behaviour";
646                 if (sprom_rev != 4)
647                         offset = SPROM_WL0GPIO0 + 1;
648                 else
649                         offset = SPROM4_WL0GPIO0 + 1;
650                 value = sprom[offset];
651                 break;
652         case VALUE_WL0GPIO2:
653                 desc = "LED 2 behaviour";
654                 if (sprom_rev != 4)
655                         offset = SPROM_WL0GPIO2 + 0;
656                 else
657                         offset = SPROM4_WL0GPIO2 + 0;
658                 value = sprom[offset];
659                 break;
660         case VALUE_WL0GPIO3:
661                 desc = "LED 3 behaviour";
662                 if (sprom_rev != 4)
663                         offset = SPROM_WL0GPIO2 + 1;
664                 else
665                         offset = SPROM4_WL0GPIO2 + 1;
666                 value = sprom[offset];
667                 break;
668         case VALUE_MAXPA:
669                 desc = "A PHY max powerout";
670                 if (sprom_rev != 4)
671                         offset = SPROM_MAXPWR + 1;
672                 else
673                         offset = SPROM4_MAXPWR + 1;
674                 value = sprom[offset];
675                 break;
676         case VALUE_MAXPBG:
677                 desc = "B/G PHY max powerout";
678                 if (sprom_rev != 4)
679                         offset = SPROM_MAXPWR + 0;
680                 else
681                         offset = SPROM4_MAXPWR + 0;
682                 value = sprom[offset];
683                 break;
684         case VALUE_ITSSIA:
685                 desc = "A PHY idle TSSI target";
686                 if (sprom_rev != 4)
687                         offset = SPROM_IDL_TSSI_TGT + 1;
688                 else
689                         offset = SPROM4_IDL_TSSI_TGT + 1;
690                 value = sprom[offset];
691                 break;
692         case VALUE_ITSSIBG:
693                 desc = "B/G PHY idle TSSI target";
694                 if (sprom_rev != 4)
695                         offset = SPROM_IDL_TSSI_TGT + 0;
696                 else
697                         offset = SPROM4_IDL_TSSI_TGT + 0;
698                 value = sprom[offset];
699                 break;
700         case VALUE_SVER:
701                 desc = "SPROM version";
702                 if (sprom_rev != 4)
703                         offset = SPROM_VERSION;
704                 else
705                         offset = SPROM4_VERSION;
706                 value = sprom[offset];
707                 break;
708         default:
709                 prerror("vparm->type internal error (1)\n");
710                 exit(1);
711         }
712
713         switch (vparm->bits) {
714         case 1:
715                 prdata("SPROM(0x%02X, %s) = %s\n",
716                        offset, desc, value ? "ON" : "OFF");
717                 break;
718         case 4:
719                 prdata("SPROM(0x%02X, %s) = 0x%01X\n",
720                        offset, desc, (value & 0xF));
721                 break;
722         case 8:
723                 prdata("SPROM(0x%02X, %s) = 0x%02X\n",
724                        offset, desc, (value & 0xFF));
725                 break;
726         case 16:
727                 prdata("SPROM(0x%02X, %s) = 0x%04X\n",
728                        offset, desc, (value & 0xFFFF));
729                 break;
730         case -1: {
731                 /* MAC address. */
732                 const uint8_t *p = &(sprom[offset]);
733
734                 prdata("SPROM(0x%02X, %s) = %02x:%02x:%02x:%02x:%02x:%02x\n",
735                        offset, desc,
736                        p[1], p[0], p[3], p[2], p[5], p[4]);
737                 break;
738         }
739         default:
740                 prerror("vparm->bits internal error (%d)\n",
741                         vparm->bits);
742                 exit(1);
743         }
744 }
745
746 static int display_sprom(const uint8_t *sprom)
747 {
748         struct cmdline_vparm *vparm;
749         int i;
750
751         for (i = 0; i < cmdargs.nr_vparm; i++) {
752                 vparm = &(cmdargs.vparm[i]);
753                 if (vparm->set)
754                         continue;
755                 display_value(sprom, vparm);
756         }
757
758         return 0;
759 }
760
761 static int validate_input(const uint8_t *sprom)
762 {
763         uint8_t crc, expected_crc;
764
765         crc = sprom_crc(sprom);
766         expected_crc = sprom[sprom_size - 1];
767
768         if (crc != expected_crc) {
769                 prerror("Corrupt input data (crc: 0x%02X, expected: 0x%02X)\n",
770                         crc, expected_crc);
771                 if (!cmdargs.force)
772                         return 1;
773         }
774
775         return 0;
776 }
777
778 static int parse_input(uint8_t *sprom, char *buffer, size_t bsize)
779 {
780         char *input;
781         size_t inlen;
782         size_t cnt;
783         unsigned long parsed;
784         char tmp[SPROM4_SIZE * 2 + 10] = { 0 };
785
786         if (cmdargs.bin_mode) {
787                 /* The input buffer already contains
788                  * the binary sprom data.
789                  */
790                 internal_error_on(bsize != SPROM_SIZE && bsize != SPROM4_SIZE);
791                 memcpy(sprom, buffer, bsize);
792                 return 0;
793         }
794
795         inlen = bsize;
796         input = strchr(buffer, ':');
797         if (input) {
798                 input++;
799                 inlen -= input - buffer;
800         } else
801                 input = buffer;
802
803         if (inlen < SPROM_SIZE * 2) {
804                 prerror("Input data too short\n");
805                 return -1;
806         }
807         for (cnt = 0; cnt < inlen / 2; cnt++) {
808                 memcpy(tmp, input + cnt * 2, 2);
809                 parsed = strtoul(tmp, NULL, 16);
810                 sprom[cnt] = parsed & 0xFF;
811         }
812         /* check for "magic" data for V4 SPROM */
813         if (sprom[0x40] == 0x72 && sprom[0x41] == 0x53) {
814                 sprom_rev = sprom[SPROM4_VERSION];
815                 sprom_size = SPROM4_SIZE;
816         } else {
817                 sprom_rev = sprom[SPROM_VERSION];
818                 sprom_size = SPROM_SIZE;
819         }
820
821         if (cmdargs.verbose) {
822                 hexdump_sprom(sprom, tmp, sizeof(tmp));
823                 prinfo("Raw input:  %s\n", tmp);
824         }
825
826         return 0;
827 }
828
829 static int read_infile(int fd, char **buffer, size_t *bsize)
830 {
831         struct stat s;
832         int err;
833         ssize_t r;
834
835         err = fstat(fd, &s);
836         if (err) {
837                 prerror("Could not stat input file.\n");
838                 return err;
839         }
840         if (s.st_size == 0) {
841                 prerror("No input data\n");
842                 return -1;
843         }
844         if (cmdargs.bin_mode) {
845                 if (s.st_size != SPROM_SIZE && s.st_size != SPROM4_SIZE) {
846                         prerror("The input data is no SPROM Binary data. "
847                                 "The size must be exactly %d (V1-3) "
848                                 "or %d (V4) bytes, "
849                                 "but it is %u bytes\n",
850                                 SPROM_SIZE, SPROM4_SIZE,
851                                 (unsigned int)(s.st_size));
852                         return -1;
853                 }
854         } else {
855                 if (s.st_size > 1024 * 1024) {
856                         prerror("The input data does not look "
857                                 "like SPROM HEX data (too long).\n");
858                         return -1;
859                 }
860         }
861
862         *bsize = s.st_size;
863         if (!cmdargs.bin_mode)
864                 (*bsize)++;
865         *buffer = malloce(*bsize);
866         r = read(fd, *buffer, s.st_size);
867         if (r != s.st_size) {
868                 prerror("Could not read input data.\n");
869                 return -1;
870         }
871         if (!cmdargs.bin_mode)
872                 (*buffer)[r] = '\0';
873
874         return 0;
875 }
876
877 static void close_infile(int fd)
878 {
879         if (cmdargs.infile)
880                 close(fd);
881 }
882
883 static void close_outfile(int fd)
884 {
885         if (cmdargs.outfile)
886                 close(fd);
887 }
888
889 static int open_infile(int *fd)
890 {
891         *fd = STDIN_FILENO;
892         if (!cmdargs.infile)
893                 return 0;
894         *fd = open(cmdargs.infile, O_RDONLY);
895         if (*fd < 0) {
896                 prerror("Could not open --infile %s\n",
897                         cmdargs.infile);
898                 return -1;
899         }
900
901         return 0;
902 }
903
904 static int open_outfile(int *fd)
905 {
906         *fd = STDOUT_FILENO;
907         if (!cmdargs.outfile)
908                 return 0;
909         *fd = open(cmdargs.outfile, O_RDWR | O_CREAT, 0644);
910         if (*fd < 0) {
911                 prerror("Could not open --outfile %s\n",
912                         cmdargs.outfile);
913                 return -1;
914         }
915
916         return 0;
917 }
918
919 static void print_banner(int forceprint)
920 {
921         const char *str = "Broadcom-SSB SPROM data modification tool version " VERSION "\n";
922         if (forceprint)
923                 prdata(str);
924         else
925                 prinfo(str);
926 }
927
928 static void print_usage(int argc, char *argv[])
929 {
930         print_banner(1);
931         prdata("\nUsage: %s [OPTION]\n", argv[0]);
932         prdata("  -i|--input FILE       Input file\n");
933         prdata("  -o|--output FILE      Output file\n");
934         prdata("  -b|--binmode          The Input data is plain binary data and Output will be binary\n");
935         prdata("  -V|--verbose          Be verbose\n");
936         prdata("  -f|--force            Override error checks\n");
937         prdata("  -v|--version          Print version\n");
938         prdata("  -h|--help             Print this help\n");
939         prdata("\n");
940         prdata("Value Parameters:\n");
941         prdata("\n");
942         prdata("  -s|--rawset OFF,VAL   Set a VALue at a byte-OFFset\n");
943         prdata("  -g|--rawget OFF       Get a value at a byte-OFFset\n");
944         prdata("\n");
945         prdata("Predefined values (for displaying (GET) or modification):\n");
946         prdata("  --subp [0xFFFF]       Subsystem product ID for PCI\n");
947         prdata("  --subv [0xFFFF]       Subsystem vendor ID for PCI\n");
948         prdata("  --ppid [0xFFFF]       Product ID for PCI\n");
949         prdata("  --bflhi [0xFFFF]      High 16 bits of boardflags (only if spromversion > 1)\n");
950         prdata("  --bfl [0xFFFF]        Low 16 bits of boardflags\n");
951         prdata("  --bgmac [MAC-ADDR]    MAC address for 802.11b/g\n");
952         prdata("  --etmac [MAC-ADDR]    MAC address for ethernet, see b44 driver\n");
953         prdata("  --amac [MAC-ADDR]     Mac address for 802.11a\n");
954         prdata("  --et0phy [0xFF]\n");
955         prdata("  --et1phy [0xFF]\n");
956         prdata("  --et0mdc [BOOL]\n");
957         prdata("  --et1mdc [BOOL]\n");
958         prdata("  --brev [0xFF]         Board revision\n");
959         prdata("  --loc [0xF]           Country code\n");
960         prdata("  --anta0 [BOOL]        Antenna 0 available for A PHY\n");
961         prdata("  --anta1 [BOOL]        Antenna 1 available for A PHY\n");
962         prdata("  --antbg0 [BOOL]       Antenna 0 available for B/G PHY\n");
963         prdata("  --antbg1 [BOOL]       Antenna 1 available for B/G PHY\n");
964         prdata("  --antga [0xFF]        Antenna gain for A PHY\n");
965         prdata("  --antgbg [0xFF]       Antenna gain for B/G PHY\n");
966         prdata("  --pa0b0 [0xFFFF]\n");
967         prdata("  --pa0b1 [0xFFFF]\n");
968         prdata("  --pa0b2 [0xFFFF]\n");
969         prdata("  --pa1b0 [0xFFFF]\n");
970         prdata("  --pa1b1 [0xFFFF]\n");
971         prdata("  --pa1b2 [0xFFFF]\n");
972         prdata("  --wl0gpio0 [0xFF]     LED 0 behaviour\n");
973         prdata("  --wl0gpio1 [0xFF]     LED 1 behaviour\n");
974         prdata("  --wl0gpio2 [0xFF]     LED 2 behaviour\n");
975         prdata("  --wl0gpio3 [0xFF]     LED 3 behaviour\n");
976         prdata("  --maxpa [0xFF]        A PHY max power\n");
977         prdata("  --maxpbg [0xFF]       B/G PHY max power\n");
978         prdata("  --itssia [0xFF]       Idle tssi target for A PHY\n");
979         prdata("  --itssibg [0xFF]      Idle tssi target for B/G PHY\n");
980         prdata("  --sver [0xFF]         SPROM-version\n");
981         prdata("\n");
982         prdata("  -P|--print-all        Display all values\n");
983         prdata("\n");
984         prdata(" BOOL      is a boolean value. Either 0 or 1\n");
985         prdata(" 0xF..     is a hexadecimal value\n");
986         prdata(" MAC-ADDR  is a MAC address in the format 00:00:00:00:00:00\n");
987         prdata(" If the value parameter is \"GET\", the value will be printed;\n");
988         prdata(" otherwise it is modified.\n");
989 }
990
991 #define ARG_MATCH               0
992 #define ARG_NOMATCH             1
993 #define ARG_ERROR               -1
994
995 static int do_cmp_arg(char **argv, int *pos,
996                       const char *template,
997                       int allow_merged,
998                       char **param)
999 {
1000         char *arg;
1001         char *next_arg;
1002         size_t arg_len, template_len;
1003
1004         arg = argv[*pos];
1005         next_arg = argv[*pos + 1];
1006         arg_len = strlen(arg);
1007         template_len = strlen(template);
1008
1009         if (param) {
1010                 /* Maybe we have a merged parameter here.
1011                  * A merged parameter is "-pfoobar" for example.
1012                  */
1013                 if (allow_merged && arg_len > template_len) {
1014                         if (memcmp(arg, template, template_len) == 0) {
1015                                 *param = arg + template_len;
1016                                 return ARG_MATCH;
1017                         }
1018                         return ARG_NOMATCH;
1019                 } else if (arg_len != template_len)
1020                         return ARG_NOMATCH;
1021                 *param = next_arg;
1022         }
1023         if (strcmp(arg, template) == 0) {
1024                 if (param) {
1025                         if (*param == 0) {
1026                                 prerror("%s needs a parameter\n", arg);
1027                                 return ARG_ERROR;
1028                         }
1029                         /* Skip the parameter on the next iteration. */
1030                         (*pos)++;
1031                 }
1032                 return ARG_MATCH;
1033         }
1034
1035         return ARG_NOMATCH;
1036 }
1037
1038 /* Simple and lean command line argument parsing. */
1039 static int cmp_arg(char **argv, int *pos,
1040                    const char *long_template,
1041                    const char *short_template,
1042                    char **param)
1043 {
1044         int err;
1045
1046         if (long_template) {
1047                 err = do_cmp_arg(argv, pos, long_template, 0, param);
1048                 if (err == ARG_MATCH || err == ARG_ERROR)
1049                         return err;
1050         }
1051         err = ARG_NOMATCH;
1052         if (short_template)
1053                 err = do_cmp_arg(argv, pos, short_template, 1, param);
1054         return err;
1055 }
1056
1057 static int parse_err;
1058
1059 static int arg_match(char **argv, int *i,
1060                      const char *long_template,
1061                      const char *short_template,
1062                      char **param)
1063 {
1064         int res;
1065
1066         res = cmp_arg(argv, i, long_template,
1067                       short_template, param);
1068         if (res == ARG_ERROR) {
1069                 parse_err = 1;
1070                 return 0;
1071         }
1072         return (res == ARG_MATCH);
1073 }
1074
1075 static int parse_value(const char *str,
1076                        struct cmdline_vparm *vparm,
1077                        const char *param)
1078 {
1079         unsigned long v;
1080         int i;
1081
1082         vparm->bits = value_length_map[vparm->type];
1083         vparm->set = 1;
1084         if (strcmp(str, "GET") == 0 || strcmp(str, "get") == 0) {
1085                 vparm->set = 0;
1086                 return 0;
1087         }
1088         if (vparm->bits == 1) {
1089                 /* This is a boolean value. */
1090                 if (strcmp(str, "0") == 0)
1091                         vparm->u.value = 0;
1092                 else if (strcmp(str, "1") == 0)
1093                         vparm->u.value = 1;
1094                 else
1095                         goto error_bool;
1096                 return 1;
1097         }
1098
1099         if (strncmp(str, "0x", 2) != 0)
1100                 goto error;
1101         str += 2;
1102         /* The following logic presents a problem because the offsets
1103          * for V4 SPROMs can be greater than 0xFF; however, the arguments
1104          * are parsed before the SPROM revision is known. To fix this
1105          * problem, if an input is expecting 0xFF-type input, then input
1106          * of 0xFFF will be permitted */
1107         for (i = 0; i < vparm->bits / 4; i++) {
1108                 if (str[i] == '\0')
1109                         goto error;
1110         }
1111         if (str[i] != '\0') {
1112                 if (i == 2)
1113                         i++;            /* add an extra character */
1114                 if (str[i] != '\0')
1115                         goto error;
1116         }
1117         errno = 0;
1118         v = strtoul(str, NULL, 16);
1119         if (errno)
1120                 goto error;
1121         vparm->u.value = v;
1122
1123         return 1;
1124 error:
1125         if (param) {
1126                 prerror("%s value parsing error. Format: 0x", param);
1127                 for (i = 0; i < vparm->bits / 4; i++)
1128                         prerror("F");
1129                 prerror("\n");
1130         }
1131         return -1;
1132
1133 error_bool:
1134         if (param)
1135                 prerror("%s value parsing error. Format: 0 or 1 (boolean)\n", param);
1136         return -1;
1137 }
1138
1139 static int parse_mac(const char *str,
1140                      struct cmdline_vparm *vparm,
1141                      const char *param)
1142 {
1143         int i;
1144         char *delim;
1145         const char *in = str;
1146         uint8_t *out = vparm->u.mac;
1147
1148         vparm->bits = -1;
1149         vparm->set = 1;
1150         if (strcmp(str, "GET") == 0 || strcmp(str, "get") == 0) {
1151                 vparm->set = 0;
1152                 return 0;
1153         }
1154
1155         for (i = 0; ; i++) {
1156                 errno = 0;
1157                 out[i] = strtoul(in, NULL, 16);
1158                 if (errno)
1159                         goto error;
1160                 if (i == 5) {
1161                         if (in[1] != '\0' && in[2] != '\0')
1162                                 goto error;
1163                         break;
1164                 }
1165                 delim = strchr(in, ':');
1166                 if (!delim)
1167                         goto error;
1168                 in = delim + 1;
1169         }
1170
1171         return 1;
1172 error:
1173         prerror("%s MAC parsing error. Format: 00:00:00:00:00:00\n", param);
1174         return -1;
1175 }
1176
1177 static int parse_rawset(const char *str,
1178                         struct cmdline_vparm *vparm)
1179 {
1180         char *delim;
1181         uint8_t value;
1182         uint16_t offset;
1183         int err;
1184
1185         vparm->type = VALUE_RAW;
1186
1187         delim = strchr(str, ',');
1188         if (!delim)
1189                 goto error;
1190         *delim = '\0';
1191         err = parse_value(str, vparm, NULL);
1192         if (err != 1)
1193                 goto error;
1194         offset = vparm->u.value;
1195         if (offset >= SPROM4_SIZE) {
1196                 prerror("--rawset offset too big (>= 0x%02X)\n",
1197                         SPROM4_SIZE);
1198                 return -1;
1199         }
1200         err = parse_value(delim + 1, vparm, NULL);
1201         if (err != 1)
1202                 goto error;
1203         value = vparm->u.value;
1204
1205         vparm->u.raw.value = value;
1206         vparm->u.raw.offset = offset;
1207         vparm->set = 1;
1208
1209         return 0;
1210 error:
1211         prerror("--rawset value parsing error. Format: 0xFF,0xFF "
1212                 "(first Offset, second Value)\n");
1213         return -1;
1214 }
1215
1216 static int parse_rawget(const char *str,
1217                         struct cmdline_vparm *vparm)
1218 {
1219         int err;
1220         uint16_t offset;
1221
1222         vparm->type = VALUE_RAW;
1223
1224         err = parse_value(str, vparm, "--rawget");
1225         if (err != 1)
1226                 return -1;
1227         offset = vparm->u.value;
1228         if (offset >= SPROM4_SIZE) {
1229                 prerror("--rawget offset too big (>= 0x%02X)\n",
1230                         SPROM4_SIZE);
1231                 return -1;
1232         }
1233
1234         vparm->u.raw.offset = offset;
1235         vparm->type = VALUE_RAW;
1236         vparm->set = 0;
1237
1238         return 0;
1239 }
1240
1241 static int generate_printall(void)
1242 {
1243         struct cmdline_vparm *vparm;
1244         int count, i;
1245         enum valuetype vt = VALUE_FIRST;
1246
1247         count = VALUE_LAST - VALUE_FIRST + 1;
1248         for (i = 0; i < count; i++, vt++) {
1249                 if (cmdargs.nr_vparm == MAX_VPARM) {
1250                         prerror("Too many value parameters.\n");
1251                         return -1;
1252                 }
1253
1254                 vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1255                 vparm->type = vt;
1256                 vparm->set = 0;
1257                 vparm->bits = value_length_map[vt];
1258         }
1259
1260         return 0;
1261 }
1262
1263 static int parse_args(int argc, char *argv[])
1264 {
1265         struct cmdline_vparm *vparm;
1266         int i, err;
1267         char *param;
1268
1269         parse_err = 0;
1270         for (i = 1; i < argc; i++) {
1271                 if (cmdargs.nr_vparm == MAX_VPARM) {
1272                         prerror("Too many value parameters.\n");
1273                         return -1;
1274                 }
1275
1276                 if (arg_match(argv, &i, "--version", "-v", 0)) {
1277                         print_banner(1);
1278                         return 1;
1279                 } else if (arg_match(argv, &i, "--help", "-h", 0)) {
1280                         goto out_usage;
1281                 } else if (arg_match(argv, &i, "--input", "-i", &param)) {
1282                         cmdargs.infile = param;
1283                 } else if (arg_match(argv, &i, "--output", "-o", &param)) {
1284                         cmdargs.outfile = param;
1285                 } else if (arg_match(argv, &i, "--verbose", "-V", 0)) {
1286                         cmdargs.verbose = 1;
1287                 } else if (arg_match(argv, &i, "--force", "-n", 0)) {
1288                         cmdargs.force = 1;
1289                 } else if (arg_match(argv, &i, "--binmode", "-b", 0)) {
1290                         cmdargs.bin_mode = 1;
1291
1292
1293                 } else if (arg_match(argv, &i, "--rawset", "-s", &param)) {
1294                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1295                         err = parse_rawset(param, vparm);
1296                         if (err < 0)
1297                                 goto error;
1298                 } else if (arg_match(argv, &i, "--rawget", "-g", &param)) {
1299                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1300                         err = parse_rawget(param, vparm);
1301                         if (err < 0)
1302                                 goto error;
1303
1304
1305                 } else if (arg_match(argv, &i, "--subp", 0, &param)) {
1306                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1307                         vparm->type = VALUE_SUBP;
1308                         err = parse_value(param, vparm, "--subp");
1309                         if (err < 0)
1310                                 goto error;
1311                 } else if (arg_match(argv, &i, "--subv", 0, &param)) {
1312                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1313                         vparm->type = VALUE_SUBV;
1314                         err = parse_value(param, vparm, "--subv");
1315                         if (err < 0)
1316                                 goto error;
1317                 } else if (arg_match(argv, &i, "--ppid", 0, &param)) {
1318                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1319                         vparm->type = VALUE_PPID;
1320                         err = parse_value(param, vparm, "--ppid");
1321                         if (err < 0)
1322                                 goto error;
1323                 } else if (arg_match(argv, &i, "--bflhi", 0, &param)) {
1324                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1325                         vparm->type = VALUE_BFLHI;
1326                         err = parse_value(param, vparm, "--bflhi");
1327                         if (err < 0)
1328                                 goto error;
1329                 } else if (arg_match(argv, &i, "--bfl", 0, &param)) {
1330                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1331                         vparm->type = VALUE_BFL;
1332                         err = parse_value(param, vparm, "--bfl");
1333                         if (err < 0)
1334                                 goto error;
1335                 } else if (arg_match(argv, &i, "--bgmac", 0, &param)) {
1336                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1337                         vparm->type = VALUE_BGMAC;
1338                         err = parse_mac(param, vparm, "--bgmac");
1339                         if (err < 0)
1340                                 goto error;
1341                 } else if (arg_match(argv, &i, "--etmac", 0, &param)) {
1342                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1343                         vparm->type = VALUE_ETMAC;
1344                         err = parse_mac(param, vparm, "--etmac");
1345                         if (err < 0)
1346                                 goto error;
1347                 } else if (arg_match(argv, &i, "--amac", 0, &param)) {
1348                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1349                         vparm->type = VALUE_AMAC;
1350                         err = parse_mac(param, vparm, "--amac");
1351                         if (err < 0)
1352                                 goto error;
1353                 } else if (arg_match(argv, &i, "--et0phy", 0, &param)) {
1354                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1355                         vparm->type = VALUE_ET0PHY;
1356                         err = parse_value(param, vparm, "--et0phy");
1357                         if (err < 0)
1358                                 goto error;
1359                 } else if (arg_match(argv, &i, "--et1phy", 0, &param)) {
1360                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1361                         vparm->type = VALUE_ET1PHY;
1362                         err = parse_value(param, vparm, "--et1phy");
1363                         if (err < 0)
1364                                 goto error;
1365                 } else if (arg_match(argv, &i, "--et0mdc", 0, &param)) {
1366                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1367                         vparm->type = VALUE_ET0MDC;
1368                         err = parse_value(param, vparm, "--et0mdc");
1369                         if (err < 0)
1370                                 goto error;
1371                 } else if (arg_match(argv, &i, "--et1mdc", 0, &param)) {
1372                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1373                         vparm->type = VALUE_ET1MDC;
1374                         err = parse_value(param, vparm, "--et1mdc");
1375                         if (err < 0)
1376                                 goto error;
1377                 } else if (arg_match(argv, &i, "--brev", 0, &param)) {
1378                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1379                         vparm->type = VALUE_BREV;
1380                         err = parse_value(param, vparm, "--brev");
1381                         if (err < 0)
1382                                 goto error;
1383                 } else if (arg_match(argv, &i, "--loc", 0, &param)) {
1384                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1385                         vparm->type = VALUE_LOC;
1386                         err = parse_value(param, vparm, "--loc");
1387                         if (err < 0)
1388                                 goto error;
1389                 } else if (arg_match(argv, &i, "--anta0", 0, &param)) {
1390                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1391                         vparm->type = VALUE_ANTA0;
1392                         err = parse_value(param, vparm, "--anta0");
1393                         if (err < 0)
1394                                 goto error;
1395                 } else if (arg_match(argv, &i, "--anta1", 0, &param)) {
1396                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1397                         vparm->type = VALUE_ANTA1;
1398                         err = parse_value(param, vparm, "--anta1");
1399                         if (err < 0)
1400                                 goto error;
1401                 } else if (arg_match(argv, &i, "--antbg0", 0, &param)) {
1402                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1403                         vparm->type = VALUE_ANTBG0;
1404                         err = parse_value(param, vparm, "--antbg0");
1405                         if (err < 0)
1406                                 goto error;
1407                 } else if (arg_match(argv, &i, "--antbg1", 0, &param)) {
1408                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1409                         vparm->type = VALUE_ANTBG1;
1410                         err = parse_value(param, vparm, "--antbg1");
1411                         if (err < 0)
1412                                 goto error;
1413                 } else if (arg_match(argv, &i, "--antga", 0, &param)) {
1414                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1415                         vparm->type = VALUE_ANTGA;
1416                         err = parse_value(param, vparm, "--antga");
1417                         if (err < 0)
1418                                 goto error;
1419                 } else if (arg_match(argv, &i, "--antgbg", 0, &param)) {
1420                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1421                         vparm->type = VALUE_ANTGBG;
1422                         err = parse_value(param, vparm, "--antgbg");
1423                         if (err < 0)
1424                                 goto error;
1425                 } else if (arg_match(argv, &i, "--pa0b0", 0, &param)) {
1426                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1427                         vparm->type = VALUE_PA0B0;
1428                         err = parse_value(param, vparm, "--pa0b0");
1429                         if (err < 0)
1430                                 goto error;
1431                 } else if (arg_match(argv, &i, "--pa0b1", 0, &param)) {
1432                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1433                         vparm->type = VALUE_PA0B1;
1434                         err = parse_value(param, vparm, "--pa0b1");
1435                         if (err < 0)
1436                                 goto error;
1437                 } else if (arg_match(argv, &i, "--pa0b2", 0, &param)) {
1438                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1439                         vparm->type = VALUE_PA0B2;
1440                         err = parse_value(param, vparm, "--pa0b2");
1441                         if (err < 0)
1442                                 goto error;
1443                 } else if (arg_match(argv, &i, "--pa1b0", 0, &param)) {
1444                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1445                         vparm->type = VALUE_PA1B0;
1446                         err = parse_value(param, vparm, "--pa1b0");
1447                         if (err < 0)
1448                                 goto error;
1449                 } else if (arg_match(argv, &i, "--pa1b1", 0, &param)) {
1450                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1451                         vparm->type = VALUE_PA1B1;
1452                         err = parse_value(param, vparm, "--pa1b1");
1453                         if (err < 0)
1454                                 goto error;
1455                 } else if (arg_match(argv, &i, "--pa1b2", 0, &param)) {
1456                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1457                         vparm->type = VALUE_PA1B2;
1458                         err = parse_value(param, vparm, "--pa1b2");
1459                         if (err < 0)
1460                                 goto error;
1461                 } else if (arg_match(argv, &i, "--wl0gpio0", 0, &param)) {
1462                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1463                         vparm->type = VALUE_WL0GPIO0;
1464                         err = parse_value(param, vparm, "--wl0gpio0");
1465                         if (err < 0)
1466                                 goto error;
1467                 } else if (arg_match(argv, &i, "--wl0gpio1", 0, &param)) {
1468                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1469                         vparm->type = VALUE_WL0GPIO1;
1470                         err = parse_value(param, vparm, "--wl0gpio1");
1471                         if (err < 0)
1472                                 goto error;
1473                 } else if (arg_match(argv, &i, "--wl0gpio2", 0, &param)) {
1474                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1475                         vparm->type = VALUE_WL0GPIO2;
1476                         err = parse_value(param, vparm, "--wl0gpio2");
1477                         if (err < 0)
1478                                 goto error;
1479                 } else if (arg_match(argv, &i, "--wl0gpio3", 0, &param)) {
1480                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1481                         vparm->type = VALUE_WL0GPIO3;
1482                         err = parse_value(param, vparm, "--wl0gpio3");
1483                         if (err < 0)
1484                                 goto error;
1485                 } else if (arg_match(argv, &i, "--maxpa", 0, &param)) {
1486                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1487                         vparm->type = VALUE_MAXPA;
1488                         err = parse_value(param, vparm, "--maxpa");
1489                         if (err < 0)
1490                                 goto error;
1491                 } else if (arg_match(argv, &i, "--maxpbg", 0, &param)) {
1492                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1493                         vparm->type = VALUE_MAXPBG;
1494                         err = parse_value(param, vparm, "--maxpbg");
1495                         if (err < 0)
1496                                 goto error;
1497                 } else if (arg_match(argv, &i, "--itssia", 0, &param)) {
1498                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1499                         vparm->type = VALUE_ITSSIA;
1500                         err = parse_value(param, vparm, "--itssia");
1501                         if (err < 0)
1502                                 goto error;
1503                 } else if (arg_match(argv, &i, "--itssibg", 0, &param)) {
1504                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1505                         vparm->type = VALUE_ITSSIBG;
1506                         err = parse_value(param, vparm, "--itssibg");
1507                         if (err < 0)
1508                                 goto error;
1509                 } else if (arg_match(argv, &i, "--sver", 0, &param)) {
1510                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1511                         vparm->type = VALUE_SVER;
1512                         err = parse_value(param, vparm, "--sver");
1513                         if (err < 0)
1514                                 goto error;
1515                 } else if (arg_match(argv, &i, "--print-all", "-P", 0)) {
1516                         err = generate_printall();
1517                         if (err)
1518                                 goto error;
1519                 } else {
1520                         if (!parse_err)
1521                                 prerror("Unrecognized argument: %s\n", argv[i]);
1522                         goto out_usage;
1523                 }
1524                 if (parse_err)
1525                         goto out_usage;
1526         }
1527         if (cmdargs.nr_vparm == 0) {
1528                 prerror("No Value parameter given. See --help.\n");
1529                 return -1;
1530         }
1531         return 0;
1532
1533 out_usage:
1534         print_usage(argc, argv);
1535 error:
1536         return -1;      
1537 }
1538
1539
1540 int main(int argc, char **argv)
1541 {
1542         int err;
1543         int fd;
1544         uint8_t sprom[SPROM4_SIZE + 10];
1545         char *buffer = NULL;
1546         size_t buffer_size = 0;
1547
1548         err = parse_args(argc, argv);
1549         if (err == 1)
1550                 return 0;
1551         else if (err != 0)
1552                 goto out;
1553
1554         print_banner(0);
1555         prinfo("\nReading input from \"%s\"...\n",
1556                cmdargs.infile ? cmdargs.infile : "stdin");
1557
1558         err = open_infile(&fd);
1559         if (err)
1560                 goto out;
1561         err = read_infile(fd, &buffer, &buffer_size);
1562         close_infile(fd);
1563         if (err)
1564                 goto out;
1565         err = parse_input(sprom, buffer, buffer_size);
1566         free(buffer);
1567         if (err)
1568                 goto out;
1569         err = validate_input(sprom);
1570         if (err)
1571                 goto out;
1572
1573         err = display_sprom(sprom);
1574         if (err)
1575                 goto out;
1576         err = modify_sprom(sprom);
1577         if (err < 0)
1578                 goto out;
1579         if (err) {
1580                 err = open_outfile(&fd);
1581                 if (err)
1582                         goto out;
1583                 err = write_output(fd, sprom);
1584                 close_outfile(fd);
1585                 if (err)
1586                         goto out;
1587                 prinfo("SPROM modified.\n");
1588         }
1589 out:
1590         return err;
1591 }