nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | |||
3 | Broadcom Sonics Silicon Backplane bus SPROM data modification tool |
||
4 | |||
5 | Copyright (c) 2006-2008 Michael Buesch <m@bues.ch> |
||
6 | Copyright (c) 2008 Larry Finger <Larry.Finger@lwfinger.net> |
||
7 | |||
8 | This program is free software; you can redistribute it and/or modify |
||
9 | it under the terms of the GNU General Public License as published by |
||
10 | the Free Software Foundation; either version 2 of the License, or |
||
11 | (at your option) any later version. |
||
12 | |||
13 | This program is distributed in the hope that it will be useful, |
||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
16 | GNU General Public License for more details. |
||
17 | |||
18 | You should have received a copy of the GNU General Public License |
||
19 | along with this program; see the file COPYING. If not, write to |
||
20 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
||
21 | Boston, MA 02110-1301, USA. |
||
22 | |||
23 | */ |
||
24 | |||
25 | #include "ssb_sprom.h" |
||
26 | #include "utils.h" |
||
27 | |||
28 | #include <unistd.h> |
||
29 | #include <fcntl.h> |
||
30 | #include <string.h> |
||
31 | #include <errno.h> |
||
32 | #include <sys/stat.h> |
||
33 | |||
34 | |||
35 | struct cmdline_args cmdargs; |
||
36 | static uint8_t sprom_rev; |
||
37 | static uint16_t sprom_size; |
||
38 | |||
39 | /* SPROM layouts are described by the following table. The entries are as follows: |
||
40 | * |
||
41 | * uint16_t rev_mask A bit mask of the sprom revisions that contain this data |
||
42 | * enum valuetype type The type of datum represented by this table entry |
||
43 | * uint16_t length The length of this datum in bits. A value of 34 means a MAC address. |
||
44 | * A value of 33 means a 2 character country code. |
||
45 | * uint16_t offset The offset (in bytes) from the start of the sprom. |
||
46 | * uint16_t mask The mask needed to extract this datum from the 16-bit word. |
||
47 | * uint16_t shift The shift needed to right align this datum. |
||
48 | * char *desc The short character string used to describe this datum. |
||
49 | * char *label The long character string that tells the function of this datum. |
||
50 | * |
||
51 | * The table is ended with a rev_mask of zero. |
||
52 | */ |
||
53 | |||
54 | static const struct var_entry sprom_table[] = { |
||
55 | { MASK_1_8, VAL_SUBP, 16, 0x04, 0xFFFF, 0x00, "subp", "Subsystem Product ID" }, |
||
56 | { MASK_1_8, VAL_SUBV, 16, 0x06, 0xFFFF, 0x00, "subv", "Subsystem Vendor ID " }, |
||
57 | { MASK_1_8, VAL_PPID, 16, 0x08, 0xFFFF, 0x00, "ppid", "PCI Product ID " }, |
||
58 | { MASK_2_3, VAL_BFLHI, 16, 0x38, 0xFFFF, 0x00, "bflhi", "High 16 bits of boardflags" }, |
||
59 | { MASK_4, VAL_BFLHI, 16, 0x46, 0xFFFF, 0x00, "bflhi", "High 16 bits of boardflags" }, |
||
60 | { MASK_5, VAL_BFLHI, 16, 0x4C, 0xFFFF, 0x00, "bflhi", "High 16 bits of boardflags" }, |
||
61 | { MASK_8, VAL_BFLHI, 16, 0x86, 0xFFFF, 0x00, "bflhi", "High 16 bits of boardflags" }, |
||
62 | { MASK_1_3, VAL_BFL, 16, 0x72, 0xFFFF, 0x00, "bfl", "Low 16 bits of boardflags " }, |
||
63 | { MASK_4, VAL_BFL, 16, 0x44, 0xFFFF, 0x00, "bfl", "Low 16 bits of boardflags " }, |
||
64 | { MASK_5, VAL_BFL, 16, 0x4A, 0xFFFF, 0x00, "bfl", "Low 16 bits of boardflags " }, |
||
65 | { MASK_8, VAL_BFL, 16, 0x84, 0xFFFF, 0x00, "bfl", "Low 16 bits of boardflags " }, |
||
66 | { MASK_1_2, VAL_BGMAC, 34, 0x48, 0xFFFF, 0x00, "bgmac", "MAC Address for 802.11b/g" }, |
||
67 | { MASK_3, VAL_BGMAC, 34, 0x4A, 0xFFFF, 0x00, "bgmac", "MAC Address for 802.11b/g" }, |
||
68 | { MASK_4, VAL_BGMAC, 34, 0x4C, 0xFFFF, 0x00, "macadr", "MAC Address" }, |
||
69 | { MASK_5, VAL_BGMAC, 34, 0x52, 0xFFFF, 0x00, "macadr", "MAC Address" }, |
||
70 | { MASK_8, VAL_BGMAC, 34, 0x8C, 0xFFFF, 0x00, "macadr", "MAC Address" }, |
||
71 | { MASK_1_2, VAL_ETMAC, 34, 0x4E, 0xFFFF, 0x00, "etmac", "MAC Address for ethernet " }, |
||
72 | { MASK_1_2, VAL_AMAC, 34, 0x54, 0xFFFF, 0x00, "amac", "MAC Address for 802.11a " }, |
||
73 | { MASK_1_3, VAL_ET0PHY, 5, 0x5A, 0x001F, 0x00, "et0phy", "Ethernet phy settings(0)" }, |
||
74 | { MASK_1_3, VAL_ET1PHY, 5, 0x5A, 0x03E0, 0x05, "et1phy", "Ethernet phy settings(1)" }, |
||
75 | { MASK_1_3, VAL_ET0MDC, 1, 0x5A, 0x4000, 0x0E, "et0mdc", "MDIO for ethernet 0" }, |
||
76 | { MASK_1_3, VAL_ET1MDC, 1, 0x5A, 0x8000, 0x0F, "et1mdc", "MDIO for ethernet 1" }, |
||
77 | { MASK_1_3, VAL_BREV, 8, 0x5C, 0x00FF, 0x00, "brev", "Board revision" }, |
||
78 | { MASK_4_5, VAL_BREV, 8, 0x42, 0x00FF, 0x00, "brev", "Board revision" }, |
||
79 | { MASK_8, VAL_BREV, 8, 0x82, 0x00FF, 0x00, "brev", "Board revision" }, |
||
80 | { MASK_1_3, VAL_LOC, 4, 0x5C, 0x0300, 0x08, "loc", "Locale / Country Code" }, |
||
81 | { MASK_4, VAL_LOC, 33, 0x52, 0xFFFF, 0x00, "ccode", "Country Code" }, |
||
82 | { MASK_5, VAL_LOC, 33, 0x44, 0xFFFF, 0x00, "ccode", "Country Code" }, |
||
83 | { MASK_8, VAL_LOC, 33, 0x92, 0xFFFF, 0x00, "ccode", "Country Code" }, |
||
84 | { MASK_4_5, VAL_REGREV, 16, 0x54, 0xFFFF, 0x00, "regrev", "Regulatory revision" }, |
||
85 | { MASK_8, VAL_REGREV, 16, 0x94, 0xFFFF, 0x00, "regrev", "Regulatory revision" }, |
||
86 | { MASK_1_3, VAL_ANTBG0, 1, 0x5C, 0x1000, 0x0C, "antbg0", "Antenna 0 available for B/G PHY" }, |
||
87 | { MASK_1_3, VAL_ANTBG1, 1, 0x5C, 0x2000, 0x0D, "antbg1", "Antenna 1 available for B/G PHY" }, |
||
88 | { MASK_1_3, VAL_ANTA0, 1, 0x5C, 0x4000, 0x0E, "anta0", "Antenna 0 available for A PHY" }, |
||
89 | { MASK_1_3, VAL_ANTA1, 1, 0x5C, 0x8000, 0x0F, "anta1", "Antenna 1 available for A PHY" }, |
||
90 | { MASK_4_5, VAL_ANTBG0, 8, 0x5C, 0x00FF, 0x00, "antbg0", "Available antenna bitmask for 2 GHz" }, |
||
91 | { MASK_8, VAL_ANTBG0, 8, 0x9C, 0x00FF, 0x00, "antbg0", "Available antenna bitmask for 2 GHz" }, |
||
92 | { MASK_4_5, VAL_ANTA0, 8, 0x5C, 0xFF00, 0x08, "anta0", "Available antenna bitmask for 5 GHz" }, |
||
93 | { MASK_8, VAL_ANTA0, 8, 0x9C, 0xFF00, 0x08, "anta0", "Available antenna bitmask for 5 GHz" }, |
||
94 | { MASK_1_3, VAL_ANTGA, 8, 0x74, 0xFF00, 0x08, "antga" , "Antenna gain (5 GHz)" }, |
||
95 | { MASK_1_3, VAL_ANTGBG, 8, 0x74, 0x00FF, 0x00, "antgbg", "Antenna gain (2 GHz)" }, |
||
96 | { MASK_4_5, VAL_ANTG0, 8, 0x5E, 0x00FF, 0x00, "antg0", "Antenna 0 gain" }, |
||
97 | { MASK_4_5, VAL_ANTG1, 8, 0x5E, 0xFF00, 0x08, "antg1", "Antenna 1 gain" }, |
||
98 | { MASK_4_5, VAL_ANTG2, 8, 0x60, 0x00FF, 0x00, "antg2", "Antenna 2 gain" }, |
||
99 | { MASK_4_5, VAL_ANTG3, 8, 0x60, 0xFF00, 0x08, "antg3", "Antenna 3 gain" }, |
||
100 | { MASK_8, VAL_ANTG0, 8, 0x9E, 0x00FF, 0x00, "antg0", "Antenna 0 gain" }, |
||
101 | { MASK_8, VAL_ANTG1, 8, 0x9E, 0xFF00, 0x08, "antg1", "Antenna 1 gain" }, |
||
102 | { MASK_8, VAL_ANTG2, 8, 0xA0, 0x00FF, 0x00, "antg2", "Antenna 2 gain" }, |
||
103 | { MASK_8, VAL_ANTG3, 8, 0xA0, 0xFF00, 0x08, "antg3", "Antenna 3 gain" }, |
||
104 | { MASK_1_3, VAL_PA0B0, 16, 0x5E, 0xFFFF, 0x00, "pa0b0", "Power Amplifier W0 PAB0" }, |
||
105 | { MASK_1_3, VAL_PA0B1, 16, 0x60, 0xFFFF, 0x00, "pa0b1", "Power Amplifier W0 PAB1" }, |
||
106 | { MASK_1_3, VAL_PA0B2, 16, 0x62, 0xFFFF, 0x00, "pa0b2", "Power Amplifier W0 PAB2" }, |
||
107 | { MASK_1_3, VAL_PA1B0, 16, 0x6A, 0xFFFF, 0x00, "pa1b0", "Power Amplifier W1 PAB0" }, |
||
108 | { MASK_1_3, VAL_PA1B1, 16, 0x6C, 0xFFFF, 0x00, "pa1b1", "Power Amplifier W1 PAB1" }, |
||
109 | { MASK_1_3, VAL_PA1B2, 16, 0x6E, 0xFFFF, 0x00, "pa1b2", "Power Amplifier W1 PAB2" }, |
||
110 | { MASK_1_3, VAL_LED0, 8, 0x64, 0x00FF, 0x00, "led0", "LED 0 behavior" }, |
||
111 | { MASK_1_3, VAL_LED1, 8, 0x64, 0xFF00, 0x08, "led1", "LED 1 behavior" }, |
||
112 | { MASK_1_3, VAL_LED2, 8, 0x66, 0x00FF, 0x00, "led2", "LED 2 behavior" }, |
||
113 | { MASK_1_3, VAL_LED3, 8, 0x66, 0xFF00, 0x08, "led3", "LED 3 behavior" }, |
||
114 | { MASK_4, VAL_LED0, 8, 0x56, 0x00FF, 0x00, "led0", "LED 0 behavior" }, |
||
115 | { MASK_4, VAL_LED1, 8, 0x56, 0xFF00, 0x08, "led1", "LED 1 behavior" }, |
||
116 | { MASK_4, VAL_LED2, 8, 0x58, 0x00FF, 0x00, "led2", "LED 2 behavior" }, |
||
117 | { MASK_4, VAL_LED3, 8, 0x58, 0xFF00, 0x08, "led3", "LED 3 behavior" }, |
||
118 | { MASK_5, VAL_LED0, 8, 0x76, 0x00FF, 0x00, "led0", "LED 0 behavior" }, |
||
119 | { MASK_5, VAL_LED1, 8, 0x76, 0xFF00, 0x08, "led1", "LED 1 behavior" }, |
||
120 | { MASK_5, VAL_LED2, 8, 0x78, 0x00FF, 0x00, "led2", "LED 2 behavior" }, |
||
121 | { MASK_5, VAL_LED3, 8, 0x78, 0xFF00, 0x08, "led3", "LED 3 behavior" }, |
||
122 | { MASK_1_3, VAL_MAXPBG, 8, 0x68, 0x00FF, 0x00, "maxpbg", "B/G PHY max power out" }, |
||
123 | { MASK_4_5, VAL_MAXPBG, 8, 0x80, 0x00FF, 0x00, "maxpbg", "Max power 2GHz - Path 1" }, |
||
124 | { MASK_8, VAL_MAXPBG, 8, 0xC0, 0x00FF, 0x00, "maxpbg", "Max power 2GHz - Path 1" }, |
||
125 | { MASK_1_3, VAL_MAXPA, 8, 0x68, 0xFF00, 0x08, "maxpa", "A PHY max power out " }, |
||
126 | { MASK_4_5, VAL_MAXPA, 8, 0x8A, 0x00FF, 0x00, "maxpa", "Max power 5GHz - Path 1" }, |
||
127 | { MASK_8, VAL_MAXPA, 8, 0xCA, 0xFF00, 0x08, "maxpa", "Max power 5GHz - Path 1" }, |
||
128 | { MASK_1_3, VAL_ITSSIBG, 8, 0x70, 0x00FF, 0x00, "itssibg", "Idle TSSI target 2 GHz" }, |
||
129 | { MASK_1_3, VAL_ITSSIA, 8, 0x70, 0xFF00, 0x08, "itssia", "Idle TSSI target 5 GHz" }, |
||
130 | { MASK_4_5, VAL_ITSSIBG, 8, 0x80, 0xFF00, 0x08, "itssibg", "Idle TSSI target 2 GHz - Path 1" }, |
||
131 | { MASK_4_5, VAL_ITSSIA, 8, 0x8A, 0xFF00, 0x08, "itssia", "Idle TSSI target 5 GHz - Path 1" }, |
||
132 | { MASK_8, VAL_ITSSIBG, 8, 0xC0, 0xFF00, 0x08, "itssibg", "Idle TSSI target 2 GHz - Path 1" }, |
||
133 | { MASK_8, VAL_ITSSIA, 8, 0xCA, 0xFF00, 0x08, "itssia", "Idle TSSI target 5 GHz - Path 1" }, |
||
134 | { MASK_8, VAL_TPI2G0, 16, 0x62, 0xFFFF, 0x00, "tpi2g0", "TX Power Index 2GHz" }, |
||
135 | { MASK_8, VAL_TPI2G1, 16, 0x64, 0xFFFF, 0x00, "tpi2g1", "TX Power Index 2GHz" }, |
||
136 | { MASK_8, VAL_TPI5GM0,16, 0x66, 0xFFFF, 0x00, "tpi5gm0", "TX Power Index 5GHz middle subband" }, |
||
137 | { MASK_8, VAL_TPI5GM1,16, 0x68, 0xFFFF, 0x00, "tpi5gm1", "TX Power Index 5GHz middle subband" }, |
||
138 | { MASK_8, VAL_TPI5GL0,16, 0x6A, 0xFFFF, 0x00, "tpi5gl0", "TX Power Index 5GHz low subband " }, |
||
139 | { MASK_8, VAL_TPI5GL1,16, 0x6C, 0xFFFF, 0x00, "tpi5gl1", "TX Power Index 5GHz low subband " }, |
||
140 | { MASK_8, VAL_TPI5GH0,16, 0x6E, 0xFFFF, 0x00, "tpi5gh0", "TX Power Index 5GHz high subband " }, |
||
141 | { MASK_8, VAL_TPI5GH1,16, 0x70, 0xFFFF, 0x00, "tpi5gh1", "TX Power Index 5GHz high subband " }, |
||
142 | { MASK_8, VAL_2CCKPO, 16, 0x140,0xFFFF, 0x00, "cckpo2g", "2 GHz CCK power offset " }, |
||
143 | { MASK_8, VAL_2OFDMPO,32, 0x142,0xFFFF, 0x00, "ofdm2g", "2 GHz OFDM power offset" }, |
||
144 | { MASK_8, VAL_5MPO, 32, 0x146,0xFFFF, 0x00, "ofdm5gm", "5 GHz OFDM middle subband power offset" }, |
||
145 | { MASK_8, VAL_5LPO, 32, 0x14A,0xFFFF, 0x00, "ofdm5gl", "5 GHz OFDM low subband power offset " }, |
||
146 | { MASK_8, VAL_5HPO, 32, 0x14E,0xFFFF, 0x00, "ofdm5gh", "5 GHz OFDM high subband power offset " }, |
||
147 | { MASK_8, VAL_2MCSPO, 16, 0x152,0xFFFF, 0x00, "mcspo2", "2 GHz MCS power offset" }, |
||
148 | { MASK_8, VAL_5MMCSPO,16, 0x162,0xFFFF, 0x00, "mcspo5m", "5 GHz middle subband MCS power offset" }, |
||
149 | { MASK_8, VAL_5LMCSPO,16, 0x172,0xFFFF, 0x00, "mcspo5l", "5 GHz low subband MCS power offset " }, |
||
150 | { MASK_8, VAL_5HMCSPO,16, 0x182,0xFFFF, 0x00, "mcspo5h", "5 GHz high subband MCS power offset " }, |
||
151 | { MASK_8, VAL_CCDPO, 16, 0x192,0xFFFF, 0x00, "ccdpo", "CCD power offset " }, |
||
152 | { MASK_8, VAL_STBCPO, 16, 0x194,0xFFFF, 0x00, "stbcpo", "STBC power offset " }, |
||
153 | { MASK_8, VAL_BW40PO, 16, 0x196,0xFFFF, 0x00, "bw40po", "BW40 power offset " }, |
||
154 | { MASK_8, VAL_BWDUPPO,16, 0x198,0xFFFF, 0x00, "bwduppo", "BWDUP power offset" }, |
||
155 | { MASK_4_5, VAL_TPI2G0, 16, 0x62, 0xFFFF, 0x00, "tpi2g0", "TX Power Index 2GHz" }, |
||
156 | { MASK_4_5, VAL_TPI2G1, 16, 0x64, 0xFFFF, 0x00, "tpi2g1", "TX Power Index 2GHz" }, |
||
157 | { MASK_4_5, VAL_TPI5GM0,16, 0x66, 0xFFFF, 0x00, "tpi5gm0", "TX Power Index 5GHz middle subband" }, |
||
158 | { MASK_4_5, VAL_TPI5GM1,16, 0x68, 0xFFFF, 0x00, "tpi5gm1", "TX Power Index 5GHz middle subband" }, |
||
159 | { MASK_4_5, VAL_TPI5GL0,16, 0x6A, 0xFFFF, 0x00, "tpi5gl0", "TX Power Index 5GHz low subband " }, |
||
160 | { MASK_4_5, VAL_TPI5GL1,16, 0x6C, 0xFFFF, 0x00, "tpi5gl1", "TX Power Index 5GHz low subband " }, |
||
161 | { MASK_4_5, VAL_TPI5GH0,16, 0x6E, 0xFFFF, 0x00, "tpi5gh0", "TX Power Index 5GHz high subband " }, |
||
162 | { MASK_4_5, VAL_TPI5GH1,16, 0x70, 0xFFFF, 0x00, "tpi5gh1", "TX Power Index 5GHz high subband " }, |
||
163 | { MASK_4_5, VAL_2CCKPO, 16, 0x138,0xFFFF, 0x00, "cckpo2g", "2 GHz CCK power offset " }, |
||
164 | { MASK_4_5, VAL_2OFDMPO,32, 0x13A,0xFFFF, 0x00, "ofdm2g", "2 GHz OFDM power offset" }, |
||
165 | { MASK_4_5, VAL_5MPO, 32, 0x13E,0xFFFF, 0x00, "ofdm5gm", "5 GHz OFDM middle subband power offset" }, |
||
166 | { MASK_4_5, VAL_5LPO, 32, 0x142,0xFFFF, 0x00, "ofdm5gl", "5 GHz OFDM low subband power offset " }, |
||
167 | { MASK_4_5, VAL_5HPO, 32, 0x146,0xFFFF, 0x00, "ofdm5gh", "5 GHz OFDM high subband power offset " }, |
||
168 | { MASK_4_5, VAL_2MCSPO, 16, 0x14A,0xFFFF, 0x00, "mcspo2", "2 GHz MCS power offset" }, |
||
169 | { MASK_4_5, VAL_5MMCSPO,16, 0x15A,0xFFFF, 0x00, "mcspo5m", "5 GHz middle subband MCS power offset" }, |
||
170 | { MASK_4_5, VAL_5LMCSPO,16, 0x16A,0xFFFF, 0x00, "mcspo5l", "5 GHz low subband MCS power offset " }, |
||
171 | { MASK_4_5, VAL_5HMCSPO,16, 0x17A,0xFFFF, 0x00, "mcspo5h", "5 GHz high subband MCS power offset " }, |
||
172 | { MASK_4_5, VAL_CCDPO, 16, 0x18A,0xFFFF, 0x00, "ccdpo", "CCD power offset " }, |
||
173 | { MASK_4_5, VAL_STBCPO, 16, 0x18C,0xFFFF, 0x00, "stbcpo", "STBC power offset " }, |
||
174 | { MASK_4_5, VAL_BW40PO, 16, 0x18E,0xFFFF, 0x00, "bw40po", "BW40 power offset " }, |
||
175 | { MASK_4_5, VAL_BWDUPPO,16, 0x190,0xFFFF, 0x00, "bwduppo", "BWDUP power offset" }, |
||
176 | /* per path variables are below here - only path 1 decoded for now */ |
||
177 | { MASK_4_5, VAL_PA0B0, 16, 0xC2, 0xFFFF, 0x00, "pa0b0", "Path 1: Power Amplifier W0 PAB0" }, |
||
178 | { MASK_4_5, VAL_PA0B1, 16, 0xC4, 0xFFFF, 0x00, "pa0b1", "Path 1: Power Amplifier W0 PAB1" }, |
||
179 | { MASK_4_5, VAL_PA0B2, 16, 0xC6, 0xFFFF, 0x00, "pa0b2", "Path 1: Power Amplifier W0 PAB2" }, |
||
180 | { MASK_4_5, VAL_PA0B3, 16, 0xC8, 0xFFFF, 0x00, "pa0b3", "Path 1: Power Amplifier W0 PAB3" }, |
||
181 | { MASK_4_5, VAL_PA1B0, 8, 0xCC, 0x00FF, 0x00, "pam5h", "Path 1: 5 GHz high subband PAM " }, |
||
182 | { MASK_4_5, VAL_PA1B0, 8, 0xCC, 0xFF00, 0x08, "pam5l", "Path 1: 5 GHz low subband PAM " }, |
||
183 | { MASK_4_5, VAL_5MPA0, 16, 0xCE, 0xFFFF, 0x00, "pa5m0", "Path 1: 5 GHz Power Amplifier middle 0" }, |
||
184 | { MASK_4_5, VAL_5MPA1, 16, 0xD0, 0xFFFF, 0x00, "pa5m1", "Path 1: 5 GHz Power Amplifier middle 1" }, |
||
185 | { MASK_4_5, VAL_5MPA2, 16, 0xD2, 0xFFFF, 0x00, "pa5m2", "Path 1: 5 GHz Power Amplifier middle 2" }, |
||
186 | { MASK_4_5, VAL_5MPA3, 16, 0xD4, 0xFFFF, 0x00, "pa5m3", "Path 1: 5 GHz Power Amplifier middle 3" }, |
||
187 | { MASK_4_5, VAL_5LPA0, 16, 0xD6, 0xFFFF, 0x00, "pa5l0", "Path 1: 5 GHz Power Amplifier low 0 " }, |
||
188 | { MASK_4_5, VAL_5LPA1, 16, 0xD8, 0xFFFF, 0x00, "pa5l1", "Path 1: 5 GHz Power Amplifier low 1 " }, |
||
189 | { MASK_4_5, VAL_5LPA2, 16, 0xDA, 0xFFFF, 0x00, "pa5l2", "Path 1: 5 GHz Power Amplifier low 2 " }, |
||
190 | { MASK_4_5, VAL_5LPA3, 16, 0xDC, 0xFFFF, 0x00, "pa5l3", "Path 1: 5 GHz Power Amplifier low 3 " }, |
||
191 | { MASK_4_5, VAL_5HPA0, 16, 0xDE, 0xFFFF, 0x00, "pa5h0", "Path 1: 5 GHz Power Amplifier high 0 " }, |
||
192 | { MASK_4_5, VAL_5HPA1, 16, 0xE0, 0xFFFF, 0x00, "pa5h1", "Path 1: 5 GHz Power Amplifier high 1 " }, |
||
193 | { MASK_4_5, VAL_5HPA2, 16, 0xE2, 0xFFFF, 0x00, "pa5h2", "Path 1: 5 GHz Power Amplifier high 2 " }, |
||
194 | { MASK_4_5, VAL_5HPA3, 16, 0xE4, 0xFFFF, 0x00, "pa5h3", "Path 1: 5 GHz Power Amplifier high 3 " }, |
||
195 | { MASK_8, VAL_PA0B0, 16, 0xC2, 0xFFFF, 0x00, "pa0b0", "SISO (Path 1) Power Amplifier W0 PAB0" }, |
||
196 | { MASK_8, VAL_PA0B1, 16, 0xC4, 0xFFFF, 0x00, "pa0b1", "SISO (Path 1) Power Amplifier W0 PAB1" }, |
||
197 | { MASK_8, VAL_PA0B2, 16, 0xC6, 0xFFFF, 0x00, "pa0b2", "SISO (Path 1) Power Amplifier W0 PAB2" }, |
||
198 | { MASK_8, VAL_PA1B0, 16, 0xCC, 0xFFFF, 0x00, "pa5m0", "SISO (Path 1) 5 GHz Power Amplifier middle 0" }, |
||
199 | { MASK_8, VAL_PA1B1, 16, 0xCE, 0xFFFF, 0x00, "pa5m1", "SISO (Path 1) 5 GHz Power Amplifier middle 1" }, |
||
200 | { MASK_8, VAL_PA1B2, 16, 0xD0, 0xFFFF, 0x00, "pa5m2", "SISO (Path 1) 5 GHz Power Amplifier middle 2" }, |
||
201 | { MASK_8, VAL_5MPA0, 16, 0xD2, 0xFFFF, 0x00, "pa5l0", "SISO (Path 1) 5 GHz Power Amplifier low 0 " }, |
||
202 | { MASK_8, VAL_5MPA1, 16, 0xD4, 0xFFFF, 0x00, "pa5l1", "SISO (Path 1) 5 GHz Power Amplifier low 1 " }, |
||
203 | { MASK_8, VAL_5MPA2, 16, 0xD6, 0xFFFF, 0x00, "pa5l2", "SISO (Path 1) 5 GHz Power Amplifier low 2 " }, |
||
204 | { MASK_8, VAL_5LPA0, 16, 0xD8, 0xFFFF, 0x00, "pa5h0", "SISO (Path 1) 5 GHz Power Amplifier high 0 " }, |
||
205 | { MASK_8, VAL_5LPA1, 16, 0xDA, 0xFFFF, 0x00, "pa5h1", "SISO (Path 1) 5 GHz Power Amplifier high 1 " }, |
||
206 | { MASK_8, VAL_5LPA2, 16, 0xDC, 0xFFFF, 0x00, "pa5h2", "SISO (Path 1) 5 GHz Power Amplifier high 2 " }, |
||
207 | |||
208 | { 0, }, |
||
209 | }; |
||
210 | |||
211 | /* find an item in the table by sprom revision and short description |
||
212 | * returns length and type. The function value is -1 if the item is not |
||
213 | * found, otherwise 0. |
||
214 | */ |
||
215 | |||
216 | static int locate_item_by_desc(int rev, enum valuetype *type, uint16_t *length, char *desc) |
||
217 | { |
||
218 | int i; |
||
219 | |||
220 | for (i = 0; ; i++) { |
||
221 | if (sprom_table[i].rev_mask == 0) |
||
222 | return -1; /* end of table */ |
||
223 | if ((sprom_table[i].rev_mask & rev) && |
||
224 | (!strcmp(sprom_table[i].desc, desc))) { |
||
225 | /* this is the record we want */ |
||
226 | *length = sprom_table[i].length; |
||
227 | *type = sprom_table[i].type; |
||
228 | return 0; |
||
229 | } |
||
230 | } |
||
231 | return -1; /* flow cannot reach here, but this statement makes gcc happy */ |
||
232 | } |
||
233 | |||
234 | /* find an item in the table by sprom revision and type |
||
235 | * return length, offset, mask, shift, desc, and label |
||
236 | * The function returns -1 if no item matches the request. |
||
237 | */ |
||
238 | |||
239 | static int locate_item_rev(int rev, enum valuetype type, uint16_t *length, uint16_t *offset, |
||
240 | uint16_t *mask, uint16_t *shift, char *desc, char *label) |
||
241 | { |
||
242 | int i; |
||
243 | |||
244 | for (i = 0; ; i++) { |
||
245 | if (sprom_table[i].rev_mask == 0) |
||
246 | return -1; /* end of table */ |
||
247 | if ((sprom_table[i].rev_mask & rev) && |
||
248 | (sprom_table[i].type == type)) { |
||
249 | /* this is the record we want */ |
||
250 | *length = sprom_table[i].length; |
||
251 | *offset = sprom_table[i].offset; |
||
252 | *mask = sprom_table[i].mask; |
||
253 | *shift = sprom_table[i].shift; |
||
254 | strcpy(desc, sprom_table[i].desc); |
||
255 | strcpy(label, sprom_table[i].label); |
||
256 | return 0; |
||
257 | } |
||
258 | } |
||
259 | return -1; /* flow cannot reach here, but this statement makes gcc happy */ |
||
260 | } |
||
261 | |||
262 | static int check_rev(uint16_t rev) |
||
263 | { |
||
264 | if ((rev < 0) || (rev > 8) || (rev == 6) || (rev == 7)) { |
||
265 | prerror("\nIllegal value for sprom_rev\n"); |
||
266 | return -1; |
||
267 | } |
||
268 | return 0; |
||
269 | } |
||
270 | |||
271 | static int hexdump_sprom(const uint8_t *sprom, char *buffer, size_t bsize) |
||
272 | { |
||
273 | int i, pos = 0; |
||
274 | |||
275 | for (i = 0; i < sprom_size; i++) { |
||
276 | pos += snprintf(buffer + pos, bsize - pos - 1, |
||
277 | "%02X", sprom[i] & 0xFF); |
||
278 | } |
||
279 | |||
280 | return pos + 1; |
||
281 | } |
||
282 | |||
283 | static uint8_t sprom_crc(const uint8_t *sprom) |
||
284 | { |
||
285 | int i; |
||
286 | uint8_t crc = 0xFF; |
||
287 | |||
288 | for (i = 0; i < sprom_size - 1; i++) |
||
289 | crc = crc8(crc, sprom[i]); |
||
290 | crc ^= 0xFF; |
||
291 | |||
292 | return crc; |
||
293 | } |
||
294 | |||
295 | static int write_output_binary(int fd, const uint8_t *sprom) |
||
296 | { |
||
297 | ssize_t w; |
||
298 | |||
299 | w = write(fd, sprom, sprom_size); |
||
300 | if (w < 0) |
||
301 | return -1; |
||
302 | |||
303 | return 0; |
||
304 | } |
||
305 | |||
306 | static int write_output_hex(int fd, const uint8_t *sprom) |
||
307 | { |
||
308 | ssize_t w; |
||
309 | char tmp[SPROM4_SIZE * 2 + 10] = { 0 }; |
||
310 | |||
311 | hexdump_sprom(sprom, tmp, sizeof(tmp)); |
||
312 | prinfo("Raw output: %s\n", tmp); |
||
313 | w = write(fd, tmp, sprom_size * 2); |
||
314 | if (w < 0) |
||
315 | return -1; |
||
316 | |||
317 | return 0; |
||
318 | } |
||
319 | |||
320 | static int write_output(int fd, const uint8_t *sprom) |
||
321 | { |
||
322 | int err; |
||
323 | |||
324 | if (cmdargs.outfile) { |
||
325 | err = ftruncate(fd, 0); |
||
326 | if (err) { |
||
327 | prerror("Could not truncate --outfile %s\n", |
||
328 | cmdargs.outfile); |
||
329 | return -1; |
||
330 | } |
||
331 | } |
||
332 | |||
333 | if (cmdargs.bin_mode) |
||
334 | err = write_output_binary(fd, sprom); |
||
335 | else |
||
336 | err = write_output_hex(fd, sprom); |
||
337 | if (err) |
||
338 | prerror("Could not write output data.\n"); |
||
339 | |||
340 | return err; |
||
341 | } |
||
342 | |||
343 | static int modify_value(uint8_t *sprom, |
||
344 | struct cmdline_vparm *vparm) |
||
345 | { |
||
346 | const uint32_t v = vparm->u.value; |
||
347 | uint16_t tmp = 0; |
||
348 | uint16_t offset; |
||
349 | char desc[100]; |
||
350 | char label[200]; |
||
351 | uint16_t length; |
||
352 | uint16_t mask; |
||
353 | uint16_t shift; |
||
354 | uint16_t old_value; |
||
355 | uint32_t value = 0; |
||
356 | |||
357 | int rev_bit = BIT(sprom_rev); |
||
358 | |||
359 | |||
360 | if (vparm->type == VAL_RAW) { |
||
361 | sprom[vparm->u.raw.offset] = vparm->u.raw.value; |
||
362 | return 0; |
||
363 | } |
||
364 | if (locate_item_rev(rev_bit, vparm->type, &length, &offset, &mask, |
||
365 | &shift, desc, label)) |
||
366 | return -1; |
||
367 | |||
368 | if (length < 32) { |
||
369 | old_value = sprom[offset + 0]; |
||
370 | old_value |= sprom[offset + 1] << 8; |
||
371 | if (length < 16) { |
||
372 | tmp = v << shift; |
||
373 | value = (old_value & ~mask) | tmp; |
||
374 | } else |
||
375 | value = v; |
||
376 | sprom[offset + 0] = (value & 0x00FF); |
||
377 | sprom[offset + 1] = (value & 0xFF00) >> 8; |
||
378 | } else if (length == 32) { |
||
379 | value = v; |
||
380 | sprom[offset + 0] = (value & 0x00FF); |
||
381 | sprom[offset + 1] = (value >> 8) & 0xFF; |
||
382 | sprom[offset + 2] = (value >> 16) & 0xFF; |
||
383 | sprom[offset + 3] = (value >> 24) & 0xFF; |
||
384 | } else if (length == 34) { /* MAC address */ |
||
385 | sprom[offset + 1] = vparm->u.mac[0]; |
||
386 | sprom[offset + 0] = vparm->u.mac[1]; |
||
387 | sprom[offset + 3] = vparm->u.mac[2]; |
||
388 | sprom[offset + 2] = vparm->u.mac[3]; |
||
389 | sprom[offset + 5] = vparm->u.mac[4]; |
||
390 | sprom[offset + 4] = vparm->u.mac[5]; |
||
391 | } else if (length == 33) { /* country code */ |
||
392 | sprom[offset + 1] = vparm->u.ccode[0]; |
||
393 | sprom[offset + 0] = vparm->u.ccode[1]; |
||
394 | } else { |
||
395 | prerror("Incorrect value for length (%d)\n", length); |
||
396 | exit(1); |
||
397 | } |
||
398 | |||
399 | return 0; |
||
400 | } |
||
401 | |||
402 | static int modify_sprom(uint8_t *sprom) |
||
403 | { |
||
404 | struct cmdline_vparm *vparm; |
||
405 | int i; |
||
406 | int modified = 0; |
||
407 | uint8_t crc; |
||
408 | |||
409 | for (i = 0; i < cmdargs.nr_vparm; i++) { |
||
410 | vparm = &(cmdargs.vparm[i]); |
||
411 | if (!vparm->set) |
||
412 | continue; |
||
413 | modify_value(sprom, vparm); |
||
414 | modified = 1; |
||
415 | } |
||
416 | if (modified) { |
||
417 | /* Recalculate the CRC. */ |
||
418 | crc = sprom_crc(sprom); |
||
419 | sprom[sprom_size - 1] = crc; |
||
420 | } |
||
421 | |||
422 | return modified; |
||
423 | } |
||
424 | |||
425 | static void display_value(const uint8_t *sprom, |
||
426 | struct cmdline_vparm *vparm) |
||
427 | { |
||
428 | char desc[100]; |
||
429 | char label[200]; |
||
430 | char buffer[50]; |
||
431 | char tbuf[2]; |
||
432 | uint16_t offset; |
||
433 | uint16_t length; |
||
434 | uint16_t mask; |
||
435 | uint16_t shift; |
||
436 | uint32_t value = 0; |
||
437 | int rev_bit = BIT(sprom_rev); |
||
438 | const uint8_t *p; |
||
439 | int i; |
||
440 | |||
441 | if (locate_item_rev(rev_bit, vparm->type, &length, &offset, &mask, |
||
442 | &shift, desc, label)) |
||
443 | return; |
||
444 | if (length < 32) { |
||
445 | value = sprom[offset + 0]; |
||
446 | value |= sprom[offset + 1] << 8; |
||
447 | value = (value & mask) >> shift; |
||
448 | } else if (length == 32) { |
||
449 | value = sprom[offset + 0]; |
||
450 | value |= sprom[offset + 1] << 8; |
||
451 | value |= sprom[offset + 2] << 16; |
||
452 | value |= sprom[offset + 3] << 24; |
||
453 | } |
||
454 | sprintf(buffer, "SPROM(0x%03X), %s, ", offset, desc); |
||
455 | buffer[25] = '\0'; |
||
456 | p = &(sprom[offset]); |
||
457 | |||
458 | switch (length) { |
||
459 | case 1: |
||
460 | prdata("%s%s = %s\n", buffer, label, value ? "ON" : "OFF"); |
||
461 | break; |
||
462 | case 4: |
||
463 | prdata("%s%s = 0x%01X\n", buffer, label, (value & 0xF)); |
||
464 | break; |
||
465 | case 5: |
||
466 | prdata("%s%s = 0x%02X\n", buffer, label, (value & 0x1F)); |
||
467 | break; |
||
468 | case 8: |
||
469 | prdata("%s%s = 0x%02X\n", buffer, label, (value & 0xFF)); |
||
470 | break; |
||
471 | case 16: |
||
472 | prdata("%s%s = 0x%04X\n", buffer, label, value); |
||
473 | break; |
||
474 | case 32: |
||
475 | prdata("%s%s = 0x%08X\n", buffer, label, value); |
||
476 | break; |
||
477 | case 33: /* alphabetic country code */ |
||
478 | for (i = 0; i < 2; i++) { |
||
479 | tbuf[i] = p[i]; |
||
480 | if (!tbuf[i]) /* if not encoded, the value is zero */ |
||
481 | tbuf[i] = ' '; |
||
482 | } |
||
483 | prdata("%s%s = \"%c%c\"\n", buffer, label, tbuf[1], tbuf[0]); |
||
484 | break; |
||
485 | case 34: |
||
486 | /* MAC address. */ |
||
487 | prdata("%s%s = %02x:%02x:%02x:%02x:%02x:%02x\n", |
||
488 | buffer, label, p[1], p[0], p[3], p[2], p[5], p[4]); |
||
489 | break; |
||
490 | default: |
||
491 | prerror("vparm->bits internal error (%d)\n", |
||
492 | vparm->bits); |
||
493 | exit(1); |
||
494 | } |
||
495 | } |
||
496 | |||
497 | static int display_sprom(const uint8_t *sprom) |
||
498 | { |
||
499 | struct cmdline_vparm *vparm; |
||
500 | int i; |
||
501 | |||
502 | for (i = 0; i < cmdargs.nr_vparm; i++) { |
||
503 | vparm = &(cmdargs.vparm[i]); |
||
504 | if (vparm->set) |
||
505 | continue; |
||
506 | display_value(sprom, vparm); |
||
507 | } |
||
508 | |||
509 | return 0; |
||
510 | } |
||
511 | |||
512 | static int validate_input(const uint8_t *sprom) |
||
513 | { |
||
514 | uint8_t crc, expected_crc; |
||
515 | |||
516 | crc = sprom_crc(sprom); |
||
517 | expected_crc = sprom[sprom_size - 1]; |
||
518 | |||
519 | if (crc != expected_crc) { |
||
520 | prerror("Corrupt input data (crc: 0x%02X, expected: 0x%02X)\n", |
||
521 | crc, expected_crc); |
||
522 | if (!cmdargs.force) |
||
523 | return 1; |
||
524 | } |
||
525 | |||
526 | return 0; |
||
527 | } |
||
528 | |||
529 | static int parse_input(uint8_t *sprom, char *buffer, size_t bsize) |
||
530 | { |
||
531 | char *input; |
||
532 | size_t inlen; |
||
533 | size_t cnt; |
||
534 | unsigned long parsed; |
||
535 | char tmp[SPROM4_SIZE * 2 + 10] = { 0 }; |
||
536 | |||
537 | if (cmdargs.bin_mode) { |
||
538 | /* The input buffer already contains |
||
539 | * the binary sprom data. |
||
540 | */ |
||
541 | internal_error_on(bsize != SPROM_SIZE && bsize != SPROM4_SIZE); |
||
542 | memcpy(sprom, buffer, bsize); |
||
543 | return 0; |
||
544 | } |
||
545 | |||
546 | inlen = bsize; |
||
547 | input = strchr(buffer, ':'); |
||
548 | if (input) { |
||
549 | input++; |
||
550 | inlen -= input - buffer; |
||
551 | } else |
||
552 | input = buffer; |
||
553 | |||
554 | if (inlen < SPROM_SIZE * 2) { |
||
555 | prerror("Input data too short\n"); |
||
556 | return -1; |
||
557 | } |
||
558 | for (cnt = 0; cnt < inlen / 2; cnt++) { |
||
559 | memcpy(tmp, input + cnt * 2, 2); |
||
560 | parsed = strtoul(tmp, NULL, 16); |
||
561 | sprom[cnt] = parsed & 0xFF; |
||
562 | } |
||
563 | /* check for 440 byte versions (V4 and higher) */ |
||
564 | if (inlen > 300) { |
||
565 | sprom_rev = sprom[SPROM4_SIZE - 2]; |
||
566 | sprom_size = SPROM4_SIZE; |
||
567 | } else { |
||
568 | sprom_rev = sprom[SPROM_SIZE - 2]; |
||
569 | sprom_size = SPROM_SIZE; |
||
570 | } |
||
571 | if (check_rev(sprom_rev)) |
||
572 | exit(1); |
||
573 | if (cmdargs.verbose) { |
||
574 | hexdump_sprom(sprom, tmp, sizeof(tmp)); |
||
575 | prinfo("Raw input: %s\n", tmp); |
||
576 | } |
||
577 | |||
578 | return 0; |
||
579 | } |
||
580 | |||
581 | static int read_infile(int fd, char **buffer, size_t *bsize) |
||
582 | { |
||
583 | struct stat s; |
||
584 | int err; |
||
585 | ssize_t r; |
||
586 | |||
587 | err = fstat(fd, &s); |
||
588 | if (err) { |
||
589 | prerror("Could not stat input file.\n"); |
||
590 | return err; |
||
591 | } |
||
592 | if (s.st_size == 0) { |
||
593 | prerror("No input data\n"); |
||
594 | return -1; |
||
595 | } |
||
596 | if (cmdargs.bin_mode) { |
||
597 | if (s.st_size != SPROM_SIZE && s.st_size != SPROM4_SIZE) { |
||
598 | prerror("The input data is not SPROM Binary data. " |
||
599 | "The size must be exactly %d (V1-3) " |
||
600 | "or %d (V4-8) bytes, " |
||
601 | "but it is %u bytes\n", |
||
602 | SPROM_SIZE, SPROM4_SIZE, |
||
603 | (unsigned int)(s.st_size)); |
||
604 | return -1; |
||
605 | } |
||
606 | } else { |
||
607 | if (s.st_size > 1024 * 1024) { |
||
608 | prerror("The input data does not look " |
||
609 | "like SPROM HEX data (too long).\n"); |
||
610 | return -1; |
||
611 | } |
||
612 | } |
||
613 | |||
614 | *bsize = s.st_size; |
||
615 | if (!cmdargs.bin_mode) |
||
616 | (*bsize)++; |
||
617 | *buffer = malloce(*bsize); |
||
618 | r = read(fd, *buffer, s.st_size); |
||
619 | if (r != s.st_size) { |
||
620 | prerror("Could not read input data.\n"); |
||
621 | return -1; |
||
622 | } |
||
623 | if (!cmdargs.bin_mode) |
||
624 | (*buffer)[r] = '\0'; |
||
625 | |||
626 | return 0; |
||
627 | } |
||
628 | |||
629 | static void close_infile(int fd) |
||
630 | { |
||
631 | if (cmdargs.infile) |
||
632 | close(fd); |
||
633 | } |
||
634 | |||
635 | static void close_outfile(int fd) |
||
636 | { |
||
637 | if (cmdargs.outfile) |
||
638 | close(fd); |
||
639 | } |
||
640 | |||
641 | static int open_infile(int *fd) |
||
642 | { |
||
643 | *fd = STDIN_FILENO; |
||
644 | if (!cmdargs.infile) |
||
645 | return 0; |
||
646 | *fd = open(cmdargs.infile, O_RDONLY); |
||
647 | if (*fd < 0) { |
||
648 | prerror("Could not open --infile %s\n", |
||
649 | cmdargs.infile); |
||
650 | return -1; |
||
651 | } |
||
652 | |||
653 | return 0; |
||
654 | } |
||
655 | |||
656 | static int open_outfile(int *fd) |
||
657 | { |
||
658 | *fd = STDOUT_FILENO; |
||
659 | if (!cmdargs.outfile) |
||
660 | return 0; |
||
661 | *fd = open(cmdargs.outfile, O_RDWR | O_CREAT, 0644); |
||
662 | if (*fd < 0) { |
||
663 | prerror("Could not open --outfile %s\n", |
||
664 | cmdargs.outfile); |
||
665 | return -1; |
||
666 | } |
||
667 | |||
668 | return 0; |
||
669 | } |
||
670 | |||
671 | static void print_banner(int forceprint) |
||
672 | { |
||
673 | const char *str = "Broadcom-SSB SPROM data modification tool.\n" |
||
674 | "\n" |
||
675 | "Copyright (C) Michael Buesch\n" |
||
676 | "Licensed under the GNU/GPL version 2 or later\n" |
||
677 | "\n" |
||
678 | "Be exceedingly careful with this tool. Improper" |
||
679 | " usage WILL BRICK YOUR DEVICE.\n"; |
||
680 | if (forceprint) |
||
681 | prdata(str); |
||
682 | else |
||
683 | prinfo(str); |
||
684 | } |
||
685 | |||
686 | static void print_usage(int argc, char *argv[]) |
||
687 | { |
||
688 | enum valuetype loop; |
||
689 | char desc[100]; |
||
690 | char label[200]; |
||
691 | char buffer[200]; |
||
692 | uint16_t offset; |
||
693 | uint16_t length; |
||
694 | uint16_t mask; |
||
695 | uint16_t shift; |
||
696 | int rev_bit; |
||
697 | |||
698 | print_banner(1); |
||
699 | prdata("\nUsage: %s [OPTION]\n", argv[0]); |
||
700 | prdata(" -i|--input FILE Input file\n"); |
||
701 | prdata(" -o|--output FILE Output file\n"); |
||
702 | prdata(" -b|--binmode The Input data is plain binary data and Output will be binary\n"); |
||
703 | prdata(" -V|--verbose Be verbose\n"); |
||
704 | prdata(" -f|--force Override error checks\n"); |
||
705 | prdata(" -v|--version Print version\n"); |
||
706 | prdata(" -h|--help Print this help\n"); |
||
707 | prdata("\nValue Parameters:\n"); |
||
708 | prdata("\n"); |
||
709 | prdata(" -s|--rawset OFF,VAL Set a VALue at a byte-OFFset\n"); |
||
710 | prdata(" -g|--rawget OFF Get a value at a byte-OFFset\n"); |
||
711 | prdata("\n"); |
||
712 | |||
713 | for (sprom_rev = 1; sprom_rev < 9; sprom_rev++) { |
||
714 | if (sprom_rev == 6 || sprom_rev == 7) |
||
715 | sprom_rev = 8; |
||
716 | |||
717 | rev_bit = BIT(sprom_rev); |
||
718 | prdata("\n================================================================\n" |
||
719 | "Rev. %d: Predefined values (for displaying (GET) or modification)\n" |
||
720 | "================================================================\n", sprom_rev); |
||
721 | |||
722 | for (loop = 0; loop <= VAL_LAST; loop++) { |
||
723 | if (locate_item_rev(rev_bit, loop, &length, &offset, &mask, |
||
724 | &shift, desc, label)) |
||
725 | continue; |
||
726 | |||
727 | switch (length) { |
||
728 | case 34: |
||
729 | sprintf(buffer, " --%s [MAC-ADDR]%30s", desc, " "); |
||
730 | break; |
||
731 | case 33: |
||
732 | sprintf(buffer, " --%s [2 Char String]%30s", desc, " "); |
||
733 | break; |
||
734 | case 32: |
||
735 | sprintf(buffer, " --%s [0xFFFFFFFF]%30s", desc, " "); |
||
736 | break; |
||
737 | case 16: |
||
738 | sprintf(buffer, " --%s [0xFFFF]%30s", desc, " "); |
||
739 | break; |
||
740 | case 8: |
||
741 | sprintf(buffer, " --%s [0xFF]%30s", desc, " "); |
||
742 | break; |
||
743 | case 5: |
||
744 | sprintf(buffer, " --%s [0x1F]%30s", desc, " "); |
||
745 | break; |
||
746 | case 4: |
||
747 | sprintf(buffer, " --%s [0xF]%30s", desc, " "); |
||
748 | break; |
||
749 | case 1: |
||
750 | sprintf(buffer, " --%s [BOOL]%30s", desc, " "); |
||
751 | break; |
||
752 | default: |
||
753 | prerror("Program error: Incorrect value of item length (%d)\n", length); |
||
754 | exit(1); |
||
755 | } |
||
756 | buffer[28] = '\0'; |
||
757 | prdata("%s%s\n", buffer, label); |
||
758 | } |
||
759 | } |
||
760 | |||
761 | prdata("\n"); |
||
762 | prdata(" -P|--print-all Display all values\n"); |
||
763 | prdata("\n"); |
||
764 | prdata(" BOOL is a boolean value. Either 0 or 1\n"); |
||
765 | prdata(" 0xF.. is a hexadecimal value\n"); |
||
766 | prdata(" MAC-ADDR is a MAC address in the format 00:00:00:00:00:00\n"); |
||
767 | prdata(" If the value parameter is \"GET\", the value will be printed;\n"); |
||
768 | prdata(" otherwise it is modified.\n"); |
||
769 | prdata("\nBe exceedingly careful with this tool. Improper" |
||
770 | " usage WILL BRICK YOUR DEVICE.\n"); |
||
771 | } |
||
772 | |||
773 | #define ARG_MATCH 0 |
||
774 | #define ARG_NOMATCH 1 |
||
775 | #define ARG_ERROR -1 |
||
776 | |||
777 | static int do_cmp_arg(char **argv, int *pos, |
||
778 | const char *template, |
||
779 | int allow_merged, |
||
780 | char **param) |
||
781 | { |
||
782 | char *arg; |
||
783 | char *next_arg; |
||
784 | size_t arg_len, template_len; |
||
785 | |||
786 | arg = argv[*pos]; |
||
787 | next_arg = argv[*pos + 1]; |
||
788 | arg_len = strlen(arg); |
||
789 | template_len = strlen(template); |
||
790 | |||
791 | if (param) { |
||
792 | /* Maybe we have a merged parameter here. |
||
793 | * A merged parameter is "-pfoobar" for example. |
||
794 | */ |
||
795 | if (allow_merged && arg_len > template_len) { |
||
796 | if (memcmp(arg, template, template_len) == 0) { |
||
797 | *param = arg + template_len; |
||
798 | return ARG_MATCH; |
||
799 | } |
||
800 | return ARG_NOMATCH; |
||
801 | } else if (arg_len != template_len) |
||
802 | return ARG_NOMATCH; |
||
803 | *param = next_arg; |
||
804 | } |
||
805 | if (strcmp(arg, template) == 0) { |
||
806 | if (param) { |
||
807 | if (*param == NULL) { |
||
808 | prerror("%s needs a parameter\n", arg); |
||
809 | return ARG_ERROR; |
||
810 | } |
||
811 | /* Skip the parameter on the next iteration. */ |
||
812 | (*pos)++; |
||
813 | } |
||
814 | return ARG_MATCH; |
||
815 | } |
||
816 | |||
817 | return ARG_NOMATCH; |
||
818 | } |
||
819 | |||
820 | /* Simple and lean command line argument parsing. */ |
||
821 | static int cmp_arg(char **argv, int *pos, |
||
822 | const char *long_template, |
||
823 | const char *short_template, |
||
824 | char **param) |
||
825 | { |
||
826 | int err; |
||
827 | |||
828 | if (long_template) { |
||
829 | err = do_cmp_arg(argv, pos, long_template, 0, param); |
||
830 | if (err == ARG_MATCH || err == ARG_ERROR) |
||
831 | return err; |
||
832 | } |
||
833 | err = ARG_NOMATCH; |
||
834 | if (short_template) |
||
835 | err = do_cmp_arg(argv, pos, short_template, 1, param); |
||
836 | return err; |
||
837 | } |
||
838 | |||
839 | static int parse_err; |
||
840 | |||
841 | static int arg_match(char **argv, int *i, |
||
842 | const char *long_template, |
||
843 | const char *short_template, |
||
844 | char **param) |
||
845 | { |
||
846 | int res; |
||
847 | |||
848 | res = cmp_arg(argv, i, long_template, |
||
849 | short_template, param); |
||
850 | if (res == ARG_ERROR) { |
||
851 | parse_err = 1; |
||
852 | return 0; |
||
853 | } |
||
854 | return (res == ARG_MATCH); |
||
855 | } |
||
856 | |||
857 | static int parse_value(const char *str, |
||
858 | struct cmdline_vparm *vparm, |
||
859 | const char *param) |
||
860 | { |
||
861 | unsigned long v; |
||
862 | int i; |
||
863 | |||
864 | vparm->set = 1; |
||
865 | if (strcmp(str, "GET") == 0 || strcmp(str, "get") == 0) { |
||
866 | vparm->set = 0; |
||
867 | return 0; |
||
868 | } |
||
869 | if (vparm->bits > 32) |
||
870 | return 0; |
||
871 | if (vparm->bits == 1) { |
||
872 | /* This is a boolean value. */ |
||
873 | if (strcmp(str, "0") == 0) |
||
874 | vparm->u.value = 0; |
||
875 | else if (strcmp(str, "1") == 0) |
||
876 | vparm->u.value = 1; |
||
877 | else |
||
878 | goto error_bool; |
||
879 | return 1; |
||
880 | } |
||
881 | |||
882 | if (strncmp(str, "0x", 2) != 0) |
||
883 | goto error; |
||
884 | str += 2; |
||
885 | /* The following logic presents a problem because the offsets |
||
886 | * for V4 SPROMs can be greater than 0xFF; however, the arguments |
||
887 | * are parsed before the SPROM revision is known. To fix this |
||
888 | * problem, if an input is expecting 0xFF-type input, then input |
||
889 | * of 0xFFF will be permitted */ |
||
890 | for (i = 0; i < vparm->bits / 4; i++) { |
||
891 | if (str[i] == '\0') |
||
892 | goto error; |
||
893 | } |
||
894 | if (str[i] != '\0') { |
||
895 | if (i == 2) |
||
896 | i++; /* add an extra character */ |
||
897 | if (str[i] != '\0') |
||
898 | goto error; |
||
899 | } |
||
900 | errno = 0; |
||
901 | v = strtoul(str, NULL, 16); |
||
902 | if (errno) |
||
903 | goto error; |
||
904 | vparm->u.value = v; |
||
905 | |||
906 | return 1; |
||
907 | error: |
||
908 | if (param) { |
||
909 | prerror("%s value parsing error. Format: 0x", param); |
||
910 | for (i = 0; i < vparm->bits / 4; i++) |
||
911 | prerror("F"); |
||
912 | prerror("\n"); |
||
913 | } |
||
914 | return -1; |
||
915 | |||
916 | error_bool: |
||
917 | if (param) |
||
918 | prerror("%s value parsing error. Format: 0 or 1 (boolean)\n", param); |
||
919 | return -1; |
||
920 | } |
||
921 | |||
922 | static int parse_ccode(const char *str, |
||
923 | struct cmdline_vparm *vparm, |
||
924 | const char *param) |
||
925 | { |
||
926 | const char *in = str; |
||
927 | char *out = vparm->u.ccode; |
||
928 | |||
929 | vparm->bits = 33; |
||
930 | vparm->set = 1; |
||
931 | if (strcmp(str, "GET") == 0 || strcmp(str, "get") == 0) { |
||
932 | vparm->set = 0; |
||
933 | return 0; |
||
934 | } |
||
935 | |||
936 | memcpy(out, in, 2); |
||
937 | return 1; |
||
938 | } |
||
939 | |||
940 | static int parse_mac(const char *str, |
||
941 | struct cmdline_vparm *vparm, |
||
942 | const char *param) |
||
943 | { |
||
944 | int i; |
||
945 | char *delim; |
||
946 | const char *in = str; |
||
947 | uint8_t *out = vparm->u.mac; |
||
948 | |||
949 | vparm->bits = 34; |
||
950 | vparm->set = 1; |
||
951 | if (strcmp(str, "GET") == 0 || strcmp(str, "get") == 0) { |
||
952 | vparm->set = 0; |
||
953 | return 0; |
||
954 | } |
||
955 | |||
956 | for (i = 0; ; i++) { |
||
957 | errno = 0; |
||
958 | out[i] = strtoul(in, NULL, 16); |
||
959 | if (errno) |
||
960 | goto error; |
||
961 | if (i == 5) { |
||
962 | if (in[1] != '\0' && in[2] != '\0') |
||
963 | goto error; |
||
964 | break; |
||
965 | } |
||
966 | delim = strchr(in, ':'); |
||
967 | if (!delim) |
||
968 | goto error; |
||
969 | in = delim + 1; |
||
970 | } |
||
971 | |||
972 | return 1; |
||
973 | error: |
||
974 | prerror("%s MAC parsing error. Format: 00:00:00:00:00:00\n", param); |
||
975 | return -1; |
||
976 | } |
||
977 | |||
978 | static int parse_rawset(const char *str, |
||
979 | struct cmdline_vparm *vparm) |
||
980 | { |
||
981 | char *delim; |
||
982 | uint8_t value; |
||
983 | uint16_t offset; |
||
984 | int err; |
||
985 | |||
986 | vparm->type = VAL_RAW; |
||
987 | |||
988 | delim = strchr(str, ','); |
||
989 | if (!delim) |
||
990 | goto error; |
||
991 | *delim = '\0'; |
||
992 | err = parse_value(str, vparm, NULL); |
||
993 | if (err != 1) |
||
994 | goto error; |
||
995 | offset = vparm->u.value; |
||
996 | if (offset >= SPROM4_SIZE) { |
||
997 | prerror("--rawset offset too big (>= 0x%02X)\n", |
||
998 | SPROM4_SIZE); |
||
999 | return -1; |
||
1000 | } |
||
1001 | err = parse_value(delim + 1, vparm, NULL); |
||
1002 | if (err != 1) |
||
1003 | goto error; |
||
1004 | value = vparm->u.value; |
||
1005 | |||
1006 | vparm->u.raw.value = value; |
||
1007 | vparm->u.raw.offset = offset; |
||
1008 | vparm->set = 1; |
||
1009 | |||
1010 | return 0; |
||
1011 | error: |
||
1012 | prerror("--rawset value parsing error. Format: 0xFF,0xFF " |
||
1013 | "(first Offset, second Value)\n"); |
||
1014 | return -1; |
||
1015 | } |
||
1016 | |||
1017 | static int parse_rawget(const char *str, |
||
1018 | struct cmdline_vparm *vparm) |
||
1019 | { |
||
1020 | int err; |
||
1021 | uint16_t offset; |
||
1022 | |||
1023 | vparm->type = VAL_RAW; |
||
1024 | |||
1025 | err = parse_value(str, vparm, "--rawget"); |
||
1026 | if (err != 1) |
||
1027 | return -1; |
||
1028 | offset = vparm->u.value; |
||
1029 | if (offset >= SPROM4_SIZE) { |
||
1030 | prerror("--rawget offset too big (>= 0x%02X)\n", |
||
1031 | SPROM4_SIZE); |
||
1032 | return -1; |
||
1033 | } |
||
1034 | |||
1035 | vparm->u.raw.offset = offset; |
||
1036 | vparm->type = VAL_RAW; |
||
1037 | vparm->set = 0; |
||
1038 | |||
1039 | return 0; |
||
1040 | } |
||
1041 | |||
1042 | static int generate_printall(void) |
||
1043 | { |
||
1044 | enum valuetype vt = 0; |
||
1045 | int j; |
||
1046 | |||
1047 | for (vt = 0; vt <= VAL_LAST; vt++) { |
||
1048 | if (cmdargs.nr_vparm == MAX_VPARM) { |
||
1049 | prerror("Too many value parameters.\n"); |
||
1050 | return -1; |
||
1051 | } |
||
1052 | for (j = 0; ; j++) { |
||
1053 | enum valuetype type = sprom_table[j].type; |
||
1054 | short mask = sprom_table[j].rev_mask; |
||
1055 | |||
1056 | if (mask == 0) |
||
1057 | break; |
||
1058 | if ((mask & BIT(sprom_rev)) && (type == vt)) { |
||
1059 | cmdargs.vparm[cmdargs.nr_vparm].type = vt; |
||
1060 | cmdargs.vparm[cmdargs.nr_vparm].set = 0; |
||
1061 | cmdargs.vparm[cmdargs.nr_vparm++].bits = sprom_table[j].length; |
||
1062 | } |
||
1063 | } |
||
1064 | } |
||
1065 | return 0; |
||
1066 | } |
||
1067 | |||
1068 | static int parse_args(int argc, char *argv[], int pass) |
||
1069 | { |
||
1070 | struct cmdline_vparm *vparm; |
||
1071 | int i, err; |
||
1072 | char *param; |
||
1073 | char *arg; |
||
1074 | uint16_t length; |
||
1075 | enum valuetype type; |
||
1076 | |||
1077 | parse_err = 0; |
||
1078 | for (i = 1; i < argc; i++) { |
||
1079 | if (cmdargs.nr_vparm == MAX_VPARM) { |
||
1080 | prerror("Too many value parameters.\n"); |
||
1081 | return -1; |
||
1082 | } |
||
1083 | |||
1084 | if (arg_match(argv, &i, "--version", "-v", NULL)) { |
||
1085 | print_banner(1); |
||
1086 | return 1; |
||
1087 | } else if (arg_match(argv, &i, "--help", "-h", NULL)) { |
||
1088 | goto out_usage; |
||
1089 | } else if (arg_match(argv, &i, "--input", "-i", ¶m)) { |
||
1090 | cmdargs.infile = param; |
||
1091 | } else if (arg_match(argv, &i, "--output", "-o", ¶m)) { |
||
1092 | cmdargs.outfile = param; |
||
1093 | } else if (arg_match(argv, &i, "--verbose", "-V", NULL)) { |
||
1094 | cmdargs.verbose = 1; |
||
1095 | } else if (arg_match(argv, &i, "--force", "-n", NULL)) { |
||
1096 | cmdargs.force = 1; |
||
1097 | } else if (arg_match(argv, &i, "--binmode", "-b", NULL)) { |
||
1098 | cmdargs.bin_mode = 1; |
||
1099 | } else if (pass == 2 && arg_match(argv, &i, "--rawset", "-s", ¶m)) { |
||
1100 | vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]); |
||
1101 | err = parse_rawset(param, vparm); |
||
1102 | if (err < 0) |
||
1103 | goto error; |
||
1104 | } else if (pass == 2 && arg_match(argv, &i, "--rawget", "-g", ¶m)) { |
||
1105 | vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]); |
||
1106 | err = parse_rawget(param, vparm); |
||
1107 | if (err < 0) |
||
1108 | goto error; |
||
1109 | |||
1110 | } else if (pass == 2 && arg_match(argv, &i, "--print-all", "-P", NULL)) { |
||
1111 | err = generate_printall(); |
||
1112 | if (err) |
||
1113 | goto error; |
||
1114 | |||
1115 | } else if (pass == 2) { |
||
1116 | arg = argv[i]; |
||
1117 | if (arg[0] != '-' || arg[1] != '-') |
||
1118 | goto out_usage; /* all must start with "--" */ |
||
1119 | if (locate_item_by_desc(BIT(sprom_rev), &type, &length, arg + 2)) |
||
1120 | goto out_usage; |
||
1121 | arg_match(argv, &i, arg, NULL, ¶m); |
||
1122 | vparm = &(cmdargs.vparm[cmdargs.nr_vparm++]); |
||
1123 | vparm->type = type; |
||
1124 | vparm->bits = length; |
||
1125 | err = parse_value(param, vparm, arg); |
||
1126 | if (err < 0) |
||
1127 | goto error; |
||
1128 | if (length == 34) { |
||
1129 | err = parse_mac(param, vparm, arg); |
||
1130 | if (err < 0) |
||
1131 | goto error; |
||
1132 | } |
||
1133 | if (length == 33) { |
||
1134 | err = parse_ccode(param, vparm, arg); |
||
1135 | if (err < 0) |
||
1136 | goto error; |
||
1137 | } |
||
1138 | } |
||
1139 | if (parse_err) |
||
1140 | goto out_usage; |
||
1141 | } |
||
1142 | if (pass == 2 && cmdargs.nr_vparm == 0) { |
||
1143 | prerror("No Value parameter given. See --help.\n"); |
||
1144 | return -1; |
||
1145 | } |
||
1146 | return 0; |
||
1147 | |||
1148 | out_usage: |
||
1149 | print_usage(argc, argv); |
||
1150 | error: |
||
1151 | return -1; |
||
1152 | } |
||
1153 | |||
1154 | |||
1155 | int main(int argc, char **argv) |
||
1156 | { |
||
1157 | int err; |
||
1158 | int fd; |
||
1159 | uint8_t sprom[SPROM4_SIZE + 10]; |
||
1160 | char *buffer = NULL; |
||
1161 | size_t buffer_size = 0; |
||
1162 | |||
1163 | /* Some arguments require that the revision of the sprom be known, |
||
1164 | * but that is not known until the sprom data are read. This difficulty |
||
1165 | * is handled by making two passes through the argument list. The first |
||
1166 | * only process those arguments that do not depend on sprom revision. |
||
1167 | * |
||
1168 | * Do the first pass through arguments |
||
1169 | */ |
||
1170 | err = parse_args(argc, argv, 1); |
||
1171 | if (err == 1) |
||
1172 | return 0; |
||
1173 | else if (err != 0) |
||
1174 | goto out; |
||
1175 | |||
1176 | print_banner(0); |
||
1177 | prinfo("\nReading input from \"%s\"...\n", |
||
1178 | cmdargs.infile ? cmdargs.infile : "stdin"); |
||
1179 | |||
1180 | err = open_infile(&fd); |
||
1181 | if (err) |
||
1182 | goto out; |
||
1183 | err = read_infile(fd, &buffer, &buffer_size); |
||
1184 | close_infile(fd); |
||
1185 | if (err) |
||
1186 | goto out; |
||
1187 | err = parse_input(sprom, buffer, buffer_size); |
||
1188 | free(buffer); |
||
1189 | if (err) |
||
1190 | goto out; |
||
1191 | err = validate_input(sprom); |
||
1192 | if (err) |
||
1193 | goto out; |
||
1194 | |||
1195 | /* do second pass through argument list */ |
||
1196 | err = parse_args(argc, argv, 2); |
||
1197 | if (err == 1) |
||
1198 | return 0; |
||
1199 | else if (err != 0) |
||
1200 | goto out; |
||
1201 | |||
1202 | err = display_sprom(sprom); |
||
1203 | if (err) |
||
1204 | goto out; |
||
1205 | err = modify_sprom(sprom); |
||
1206 | if (err < 0) |
||
1207 | goto out; |
||
1208 | if (err) { |
||
1209 | err = open_outfile(&fd); |
||
1210 | if (err) |
||
1211 | goto out; |
||
1212 | err = write_output(fd, sprom); |
||
1213 | close_outfile(fd); |
||
1214 | if (err) |
||
1215 | goto out; |
||
1216 | prinfo("SPROM modified.\n"); |
||
1217 | } |
||
1218 | prdata("The input file is data from a revision %d SPROM.\n", sprom_rev); |
||
1219 | out: |
||
1220 | return err; |
||
1221 | } |