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