10952775eec72e68028ebed4acd0c9e92efda88f
[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-2008 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.\n"
922                           "\n"
923                           "Copyright (C) Michael Buesch\n"
924                           "Licensed under the GNU/GPL version 2 or later\n"
925                           "\n"
926                           "DO NOT USE THIS TOOL. YOU WILL BRICK YOUR DEVICE.\n";
927         if (forceprint)
928                 prdata(str);
929         else
930                 prinfo(str);
931 }
932
933 static void print_usage(int argc, char *argv[])
934 {
935         print_banner(1);
936         prdata("\nUsage: %s [OPTION]\n", argv[0]);
937         prdata("  -i|--input FILE       Input file\n");
938         prdata("  -o|--output FILE      Output file\n");
939         prdata("  -b|--binmode          The Input data is plain binary data and Output will be binary\n");
940         prdata("  -V|--verbose          Be verbose\n");
941         prdata("  -f|--force            Override error checks\n");
942         prdata("  -v|--version          Print version\n");
943         prdata("  -h|--help             Print this help\n");
944         prdata("\n");
945         prdata("Value Parameters:\n");
946         prdata("\n");
947         prdata("  -s|--rawset OFF,VAL   Set a VALue at a byte-OFFset\n");
948         prdata("  -g|--rawget OFF       Get a value at a byte-OFFset\n");
949         prdata("\n");
950         prdata("Predefined values (for displaying (GET) or modification):\n");
951         prdata("  --subp [0xFFFF]       Subsystem product ID for PCI\n");
952         prdata("  --subv [0xFFFF]       Subsystem vendor ID for PCI\n");
953         prdata("  --ppid [0xFFFF]       Product ID for PCI\n");
954         prdata("  --bflhi [0xFFFF]      High 16 bits of boardflags (only if spromversion > 1)\n");
955         prdata("  --bfl [0xFFFF]        Low 16 bits of boardflags\n");
956         prdata("  --bgmac [MAC-ADDR]    MAC address for 802.11b/g\n");
957         prdata("  --etmac [MAC-ADDR]    MAC address for ethernet, see b44 driver\n");
958         prdata("  --amac [MAC-ADDR]     Mac address for 802.11a\n");
959         prdata("  --et0phy [0xFF]\n");
960         prdata("  --et1phy [0xFF]\n");
961         prdata("  --et0mdc [BOOL]\n");
962         prdata("  --et1mdc [BOOL]\n");
963         prdata("  --brev [0xFF]         Board revision\n");
964         prdata("  --loc [0xF]           Country code\n");
965         prdata("  --anta0 [BOOL]        Antenna 0 available for A PHY\n");
966         prdata("  --anta1 [BOOL]        Antenna 1 available for A PHY\n");
967         prdata("  --antbg0 [BOOL]       Antenna 0 available for B/G PHY\n");
968         prdata("  --antbg1 [BOOL]       Antenna 1 available for B/G PHY\n");
969         prdata("  --antga [0xFF]        Antenna gain for A PHY\n");
970         prdata("  --antgbg [0xFF]       Antenna gain for B/G PHY\n");
971         prdata("  --pa0b0 [0xFFFF]\n");
972         prdata("  --pa0b1 [0xFFFF]\n");
973         prdata("  --pa0b2 [0xFFFF]\n");
974         prdata("  --pa1b0 [0xFFFF]\n");
975         prdata("  --pa1b1 [0xFFFF]\n");
976         prdata("  --pa1b2 [0xFFFF]\n");
977         prdata("  --wl0gpio0 [0xFF]     LED 0 behaviour\n");
978         prdata("  --wl0gpio1 [0xFF]     LED 1 behaviour\n");
979         prdata("  --wl0gpio2 [0xFF]     LED 2 behaviour\n");
980         prdata("  --wl0gpio3 [0xFF]     LED 3 behaviour\n");
981         prdata("  --maxpa [0xFF]        A PHY max power\n");
982         prdata("  --maxpbg [0xFF]       B/G PHY max power\n");
983         prdata("  --itssia [0xFF]       Idle tssi target for A PHY\n");
984         prdata("  --itssibg [0xFF]      Idle tssi target for B/G PHY\n");
985         prdata("  --sver [0xFF]         SPROM-version\n");
986         prdata("\n");
987         prdata("  -P|--print-all        Display all values\n");
988         prdata("\n");
989         prdata(" BOOL      is a boolean value. Either 0 or 1\n");
990         prdata(" 0xF..     is a hexadecimal value\n");
991         prdata(" MAC-ADDR  is a MAC address in the format 00:00:00:00:00:00\n");
992         prdata(" If the value parameter is \"GET\", the value will be printed;\n");
993         prdata(" otherwise it is modified.\n");
994 }
995
996 #define ARG_MATCH               0
997 #define ARG_NOMATCH             1
998 #define ARG_ERROR               -1
999
1000 static int do_cmp_arg(char **argv, int *pos,
1001                       const char *template,
1002                       int allow_merged,
1003                       char **param)
1004 {
1005         char *arg;
1006         char *next_arg;
1007         size_t arg_len, template_len;
1008
1009         arg = argv[*pos];
1010         next_arg = argv[*pos + 1];
1011         arg_len = strlen(arg);
1012         template_len = strlen(template);
1013
1014         if (param) {
1015                 /* Maybe we have a merged parameter here.
1016                  * A merged parameter is "-pfoobar" for example.
1017                  */
1018                 if (allow_merged && arg_len > template_len) {
1019                         if (memcmp(arg, template, template_len) == 0) {
1020                                 *param = arg + template_len;
1021                                 return ARG_MATCH;
1022                         }
1023                         return ARG_NOMATCH;
1024                 } else if (arg_len != template_len)
1025                         return ARG_NOMATCH;
1026                 *param = next_arg;
1027         }
1028         if (strcmp(arg, template) == 0) {
1029                 if (param) {
1030                         if (*param == 0) {
1031                                 prerror("%s needs a parameter\n", arg);
1032                                 return ARG_ERROR;
1033                         }
1034                         /* Skip the parameter on the next iteration. */
1035                         (*pos)++;
1036                 }
1037                 return ARG_MATCH;
1038         }
1039
1040         return ARG_NOMATCH;
1041 }
1042
1043 /* Simple and lean command line argument parsing. */
1044 static int cmp_arg(char **argv, int *pos,
1045                    const char *long_template,
1046                    const char *short_template,
1047                    char **param)
1048 {
1049         int err;
1050
1051         if (long_template) {
1052                 err = do_cmp_arg(argv, pos, long_template, 0, param);
1053                 if (err == ARG_MATCH || err == ARG_ERROR)
1054                         return err;
1055         }
1056         err = ARG_NOMATCH;
1057         if (short_template)
1058                 err = do_cmp_arg(argv, pos, short_template, 1, param);
1059         return err;
1060 }
1061
1062 static int parse_err;
1063
1064 static int arg_match(char **argv, int *i,
1065                      const char *long_template,
1066                      const char *short_template,
1067                      char **param)
1068 {
1069         int res;
1070
1071         res = cmp_arg(argv, i, long_template,
1072                       short_template, param);
1073         if (res == ARG_ERROR) {
1074                 parse_err = 1;
1075                 return 0;
1076         }
1077         return (res == ARG_MATCH);
1078 }
1079
1080 static int parse_value(const char *str,
1081                        struct cmdline_vparm *vparm,
1082                        const char *param)
1083 {
1084         unsigned long v;
1085         int i;
1086
1087         vparm->bits = value_length_map[vparm->type];
1088         vparm->set = 1;
1089         if (strcmp(str, "GET") == 0 || strcmp(str, "get") == 0) {
1090                 vparm->set = 0;
1091                 return 0;
1092         }
1093         if (vparm->bits == 1) {
1094                 /* This is a boolean value. */
1095                 if (strcmp(str, "0") == 0)
1096                         vparm->u.value = 0;
1097                 else if (strcmp(str, "1") == 0)
1098                         vparm->u.value = 1;
1099                 else
1100                         goto error_bool;
1101                 return 1;
1102         }
1103
1104         if (strncmp(str, "0x", 2) != 0)
1105                 goto error;
1106         str += 2;
1107         /* The following logic presents a problem because the offsets
1108          * for V4 SPROMs can be greater than 0xFF; however, the arguments
1109          * are parsed before the SPROM revision is known. To fix this
1110          * problem, if an input is expecting 0xFF-type input, then input
1111          * of 0xFFF will be permitted */
1112         for (i = 0; i < vparm->bits / 4; i++) {
1113                 if (str[i] == '\0')
1114                         goto error;
1115         }
1116         if (str[i] != '\0') {
1117                 if (i == 2)
1118                         i++;            /* add an extra character */
1119                 if (str[i] != '\0')
1120                         goto error;
1121         }
1122         errno = 0;
1123         v = strtoul(str, NULL, 16);
1124         if (errno)
1125                 goto error;
1126         vparm->u.value = v;
1127
1128         return 1;
1129 error:
1130         if (param) {
1131                 prerror("%s value parsing error. Format: 0x", param);
1132                 for (i = 0; i < vparm->bits / 4; i++)
1133                         prerror("F");
1134                 prerror("\n");
1135         }
1136         return -1;
1137
1138 error_bool:
1139         if (param)
1140                 prerror("%s value parsing error. Format: 0 or 1 (boolean)\n", param);
1141         return -1;
1142 }
1143
1144 static int parse_mac(const char *str,
1145                      struct cmdline_vparm *vparm,
1146                      const char *param)
1147 {
1148         int i;
1149         char *delim;
1150         const char *in = str;
1151         uint8_t *out = vparm->u.mac;
1152
1153         vparm->bits = -1;
1154         vparm->set = 1;
1155         if (strcmp(str, "GET") == 0 || strcmp(str, "get") == 0) {
1156                 vparm->set = 0;
1157                 return 0;
1158         }
1159
1160         for (i = 0; ; i++) {
1161                 errno = 0;
1162                 out[i] = strtoul(in, NULL, 16);
1163                 if (errno)
1164                         goto error;
1165                 if (i == 5) {
1166                         if (in[1] != '\0' && in[2] != '\0')
1167                                 goto error;
1168                         break;
1169                 }
1170                 delim = strchr(in, ':');
1171                 if (!delim)
1172                         goto error;
1173                 in = delim + 1;
1174         }
1175
1176         return 1;
1177 error:
1178         prerror("%s MAC parsing error. Format: 00:00:00:00:00:00\n", param);
1179         return -1;
1180 }
1181
1182 static int parse_rawset(const char *str,
1183                         struct cmdline_vparm *vparm)
1184 {
1185         char *delim;
1186         uint8_t value;
1187         uint16_t offset;
1188         int err;
1189
1190         vparm->type = VALUE_RAW;
1191
1192         delim = strchr(str, ',');
1193         if (!delim)
1194                 goto error;
1195         *delim = '\0';
1196         err = parse_value(str, vparm, NULL);
1197         if (err != 1)
1198                 goto error;
1199         offset = vparm->u.value;
1200         if (offset >= SPROM4_SIZE) {
1201                 prerror("--rawset offset too big (>= 0x%02X)\n",
1202                         SPROM4_SIZE);
1203                 return -1;
1204         }
1205         err = parse_value(delim + 1, vparm, NULL);
1206         if (err != 1)
1207                 goto error;
1208         value = vparm->u.value;
1209
1210         vparm->u.raw.value = value;
1211         vparm->u.raw.offset = offset;
1212         vparm->set = 1;
1213
1214         return 0;
1215 error:
1216         prerror("--rawset value parsing error. Format: 0xFF,0xFF "
1217                 "(first Offset, second Value)\n");
1218         return -1;
1219 }
1220
1221 static int parse_rawget(const char *str,
1222                         struct cmdline_vparm *vparm)
1223 {
1224         int err;
1225         uint16_t offset;
1226
1227         vparm->type = VALUE_RAW;
1228
1229         err = parse_value(str, vparm, "--rawget");
1230         if (err != 1)
1231                 return -1;
1232         offset = vparm->u.value;
1233         if (offset >= SPROM4_SIZE) {
1234                 prerror("--rawget offset too big (>= 0x%02X)\n",
1235                         SPROM4_SIZE);
1236                 return -1;
1237         }
1238
1239         vparm->u.raw.offset = offset;
1240         vparm->type = VALUE_RAW;
1241         vparm->set = 0;
1242
1243         return 0;
1244 }
1245
1246 static int generate_printall(void)
1247 {
1248         struct cmdline_vparm *vparm;
1249         int count, i;
1250         enum valuetype vt = VALUE_FIRST;
1251
1252         count = VALUE_LAST - VALUE_FIRST + 1;
1253         for (i = 0; i < count; i++, vt++) {
1254                 if (cmdargs.nr_vparm == MAX_VPARM) {
1255                         prerror("Too many value parameters.\n");
1256                         return -1;
1257                 }
1258
1259                 vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1260                 vparm->type = vt;
1261                 vparm->set = 0;
1262                 vparm->bits = value_length_map[vt];
1263         }
1264
1265         return 0;
1266 }
1267
1268 static int parse_args(int argc, char *argv[])
1269 {
1270         struct cmdline_vparm *vparm;
1271         int i, err;
1272         char *param;
1273
1274         parse_err = 0;
1275         for (i = 1; i < argc; i++) {
1276                 if (cmdargs.nr_vparm == MAX_VPARM) {
1277                         prerror("Too many value parameters.\n");
1278                         return -1;
1279                 }
1280
1281                 if (arg_match(argv, &i, "--version", "-v", 0)) {
1282                         print_banner(1);
1283                         return 1;
1284                 } else if (arg_match(argv, &i, "--help", "-h", 0)) {
1285                         goto out_usage;
1286                 } else if (arg_match(argv, &i, "--input", "-i", &param)) {
1287                         cmdargs.infile = param;
1288                 } else if (arg_match(argv, &i, "--output", "-o", &param)) {
1289                         cmdargs.outfile = param;
1290                 } else if (arg_match(argv, &i, "--verbose", "-V", 0)) {
1291                         cmdargs.verbose = 1;
1292                 } else if (arg_match(argv, &i, "--force", "-n", 0)) {
1293                         cmdargs.force = 1;
1294                 } else if (arg_match(argv, &i, "--binmode", "-b", 0)) {
1295                         cmdargs.bin_mode = 1;
1296
1297
1298                 } else if (arg_match(argv, &i, "--rawset", "-s", &param)) {
1299                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1300                         err = parse_rawset(param, vparm);
1301                         if (err < 0)
1302                                 goto error;
1303                 } else if (arg_match(argv, &i, "--rawget", "-g", &param)) {
1304                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1305                         err = parse_rawget(param, vparm);
1306                         if (err < 0)
1307                                 goto error;
1308
1309
1310                 } else if (arg_match(argv, &i, "--subp", 0, &param)) {
1311                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1312                         vparm->type = VALUE_SUBP;
1313                         err = parse_value(param, vparm, "--subp");
1314                         if (err < 0)
1315                                 goto error;
1316                 } else if (arg_match(argv, &i, "--subv", 0, &param)) {
1317                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1318                         vparm->type = VALUE_SUBV;
1319                         err = parse_value(param, vparm, "--subv");
1320                         if (err < 0)
1321                                 goto error;
1322                 } else if (arg_match(argv, &i, "--ppid", 0, &param)) {
1323                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1324                         vparm->type = VALUE_PPID;
1325                         err = parse_value(param, vparm, "--ppid");
1326                         if (err < 0)
1327                                 goto error;
1328                 } else if (arg_match(argv, &i, "--bflhi", 0, &param)) {
1329                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1330                         vparm->type = VALUE_BFLHI;
1331                         err = parse_value(param, vparm, "--bflhi");
1332                         if (err < 0)
1333                                 goto error;
1334                 } else if (arg_match(argv, &i, "--bfl", 0, &param)) {
1335                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1336                         vparm->type = VALUE_BFL;
1337                         err = parse_value(param, vparm, "--bfl");
1338                         if (err < 0)
1339                                 goto error;
1340                 } else if (arg_match(argv, &i, "--bgmac", 0, &param)) {
1341                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1342                         vparm->type = VALUE_BGMAC;
1343                         err = parse_mac(param, vparm, "--bgmac");
1344                         if (err < 0)
1345                                 goto error;
1346                 } else if (arg_match(argv, &i, "--etmac", 0, &param)) {
1347                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1348                         vparm->type = VALUE_ETMAC;
1349                         err = parse_mac(param, vparm, "--etmac");
1350                         if (err < 0)
1351                                 goto error;
1352                 } else if (arg_match(argv, &i, "--amac", 0, &param)) {
1353                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1354                         vparm->type = VALUE_AMAC;
1355                         err = parse_mac(param, vparm, "--amac");
1356                         if (err < 0)
1357                                 goto error;
1358                 } else if (arg_match(argv, &i, "--et0phy", 0, &param)) {
1359                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1360                         vparm->type = VALUE_ET0PHY;
1361                         err = parse_value(param, vparm, "--et0phy");
1362                         if (err < 0)
1363                                 goto error;
1364                 } else if (arg_match(argv, &i, "--et1phy", 0, &param)) {
1365                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1366                         vparm->type = VALUE_ET1PHY;
1367                         err = parse_value(param, vparm, "--et1phy");
1368                         if (err < 0)
1369                                 goto error;
1370                 } else if (arg_match(argv, &i, "--et0mdc", 0, &param)) {
1371                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1372                         vparm->type = VALUE_ET0MDC;
1373                         err = parse_value(param, vparm, "--et0mdc");
1374                         if (err < 0)
1375                                 goto error;
1376                 } else if (arg_match(argv, &i, "--et1mdc", 0, &param)) {
1377                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1378                         vparm->type = VALUE_ET1MDC;
1379                         err = parse_value(param, vparm, "--et1mdc");
1380                         if (err < 0)
1381                                 goto error;
1382                 } else if (arg_match(argv, &i, "--brev", 0, &param)) {
1383                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1384                         vparm->type = VALUE_BREV;
1385                         err = parse_value(param, vparm, "--brev");
1386                         if (err < 0)
1387                                 goto error;
1388                 } else if (arg_match(argv, &i, "--loc", 0, &param)) {
1389                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1390                         vparm->type = VALUE_LOC;
1391                         err = parse_value(param, vparm, "--loc");
1392                         if (err < 0)
1393                                 goto error;
1394                 } else if (arg_match(argv, &i, "--anta0", 0, &param)) {
1395                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1396                         vparm->type = VALUE_ANTA0;
1397                         err = parse_value(param, vparm, "--anta0");
1398                         if (err < 0)
1399                                 goto error;
1400                 } else if (arg_match(argv, &i, "--anta1", 0, &param)) {
1401                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1402                         vparm->type = VALUE_ANTA1;
1403                         err = parse_value(param, vparm, "--anta1");
1404                         if (err < 0)
1405                                 goto error;
1406                 } else if (arg_match(argv, &i, "--antbg0", 0, &param)) {
1407                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1408                         vparm->type = VALUE_ANTBG0;
1409                         err = parse_value(param, vparm, "--antbg0");
1410                         if (err < 0)
1411                                 goto error;
1412                 } else if (arg_match(argv, &i, "--antbg1", 0, &param)) {
1413                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1414                         vparm->type = VALUE_ANTBG1;
1415                         err = parse_value(param, vparm, "--antbg1");
1416                         if (err < 0)
1417                                 goto error;
1418                 } else if (arg_match(argv, &i, "--antga", 0, &param)) {
1419                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1420                         vparm->type = VALUE_ANTGA;
1421                         err = parse_value(param, vparm, "--antga");
1422                         if (err < 0)
1423                                 goto error;
1424                 } else if (arg_match(argv, &i, "--antgbg", 0, &param)) {
1425                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1426                         vparm->type = VALUE_ANTGBG;
1427                         err = parse_value(param, vparm, "--antgbg");
1428                         if (err < 0)
1429                                 goto error;
1430                 } else if (arg_match(argv, &i, "--pa0b0", 0, &param)) {
1431                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1432                         vparm->type = VALUE_PA0B0;
1433                         err = parse_value(param, vparm, "--pa0b0");
1434                         if (err < 0)
1435                                 goto error;
1436                 } else if (arg_match(argv, &i, "--pa0b1", 0, &param)) {
1437                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1438                         vparm->type = VALUE_PA0B1;
1439                         err = parse_value(param, vparm, "--pa0b1");
1440                         if (err < 0)
1441                                 goto error;
1442                 } else if (arg_match(argv, &i, "--pa0b2", 0, &param)) {
1443                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1444                         vparm->type = VALUE_PA0B2;
1445                         err = parse_value(param, vparm, "--pa0b2");
1446                         if (err < 0)
1447                                 goto error;
1448                 } else if (arg_match(argv, &i, "--pa1b0", 0, &param)) {
1449                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1450                         vparm->type = VALUE_PA1B0;
1451                         err = parse_value(param, vparm, "--pa1b0");
1452                         if (err < 0)
1453                                 goto error;
1454                 } else if (arg_match(argv, &i, "--pa1b1", 0, &param)) {
1455                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1456                         vparm->type = VALUE_PA1B1;
1457                         err = parse_value(param, vparm, "--pa1b1");
1458                         if (err < 0)
1459                                 goto error;
1460                 } else if (arg_match(argv, &i, "--pa1b2", 0, &param)) {
1461                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1462                         vparm->type = VALUE_PA1B2;
1463                         err = parse_value(param, vparm, "--pa1b2");
1464                         if (err < 0)
1465                                 goto error;
1466                 } else if (arg_match(argv, &i, "--wl0gpio0", 0, &param)) {
1467                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1468                         vparm->type = VALUE_WL0GPIO0;
1469                         err = parse_value(param, vparm, "--wl0gpio0");
1470                         if (err < 0)
1471                                 goto error;
1472                 } else if (arg_match(argv, &i, "--wl0gpio1", 0, &param)) {
1473                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1474                         vparm->type = VALUE_WL0GPIO1;
1475                         err = parse_value(param, vparm, "--wl0gpio1");
1476                         if (err < 0)
1477                                 goto error;
1478                 } else if (arg_match(argv, &i, "--wl0gpio2", 0, &param)) {
1479                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1480                         vparm->type = VALUE_WL0GPIO2;
1481                         err = parse_value(param, vparm, "--wl0gpio2");
1482                         if (err < 0)
1483                                 goto error;
1484                 } else if (arg_match(argv, &i, "--wl0gpio3", 0, &param)) {
1485                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1486                         vparm->type = VALUE_WL0GPIO3;
1487                         err = parse_value(param, vparm, "--wl0gpio3");
1488                         if (err < 0)
1489                                 goto error;
1490                 } else if (arg_match(argv, &i, "--maxpa", 0, &param)) {
1491                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1492                         vparm->type = VALUE_MAXPA;
1493                         err = parse_value(param, vparm, "--maxpa");
1494                         if (err < 0)
1495                                 goto error;
1496                 } else if (arg_match(argv, &i, "--maxpbg", 0, &param)) {
1497                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1498                         vparm->type = VALUE_MAXPBG;
1499                         err = parse_value(param, vparm, "--maxpbg");
1500                         if (err < 0)
1501                                 goto error;
1502                 } else if (arg_match(argv, &i, "--itssia", 0, &param)) {
1503                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1504                         vparm->type = VALUE_ITSSIA;
1505                         err = parse_value(param, vparm, "--itssia");
1506                         if (err < 0)
1507                                 goto error;
1508                 } else if (arg_match(argv, &i, "--itssibg", 0, &param)) {
1509                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1510                         vparm->type = VALUE_ITSSIBG;
1511                         err = parse_value(param, vparm, "--itssibg");
1512                         if (err < 0)
1513                                 goto error;
1514                 } else if (arg_match(argv, &i, "--sver", 0, &param)) {
1515                         vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]);
1516                         vparm->type = VALUE_SVER;
1517                         err = parse_value(param, vparm, "--sver");
1518                         if (err < 0)
1519                                 goto error;
1520                 } else if (arg_match(argv, &i, "--print-all", "-P", 0)) {
1521                         err = generate_printall();
1522                         if (err)
1523                                 goto error;
1524                 } else {
1525                         if (!parse_err)
1526                                 prerror("Unrecognized argument: %s\n", argv[i]);
1527                         goto out_usage;
1528                 }
1529                 if (parse_err)
1530                         goto out_usage;
1531         }
1532         if (cmdargs.nr_vparm == 0) {
1533                 prerror("No Value parameter given. See --help.\n");
1534                 return -1;
1535         }
1536         return 0;
1537
1538 out_usage:
1539         print_usage(argc, argv);
1540 error:
1541         return -1;      
1542 }
1543
1544
1545 int main(int argc, char **argv)
1546 {
1547         int err;
1548         int fd;
1549         uint8_t sprom[SPROM4_SIZE + 10];
1550         char *buffer = NULL;
1551         size_t buffer_size = 0;
1552
1553         err = parse_args(argc, argv);
1554         if (err == 1)
1555                 return 0;
1556         else if (err != 0)
1557                 goto out;
1558
1559         print_banner(0);
1560         prinfo("\nReading input from \"%s\"...\n",
1561                cmdargs.infile ? cmdargs.infile : "stdin");
1562
1563         err = open_infile(&fd);
1564         if (err)
1565                 goto out;
1566         err = read_infile(fd, &buffer, &buffer_size);
1567         close_infile(fd);
1568         if (err)
1569                 goto out;
1570         err = parse_input(sprom, buffer, buffer_size);
1571         free(buffer);
1572         if (err)
1573                 goto out;
1574         err = validate_input(sprom);
1575         if (err)
1576                 goto out;
1577
1578         err = display_sprom(sprom);
1579         if (err)
1580                 goto out;
1581         err = modify_sprom(sprom);
1582         if (err < 0)
1583                 goto out;
1584         if (err) {
1585                 err = open_outfile(&fd);
1586                 if (err)
1587                         goto out;
1588                 err = write_output(fd, sprom);
1589                 close_outfile(fd);
1590                 if (err)
1591                         goto out;
1592                 prinfo("SPROM modified.\n");
1593         }
1594 out:
1595         return err;
1596 }