992689605d25f3983e642c08acd20815f524de02
[openwrt/staging/dedeckeh.git] / target / linux / generic / files / drivers / platform / mikrotik / rb_hardconfig.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Driver for MikroTik RouterBoot hard config.
4 *
5 * Copyright (C) 2020 Thibaut VARĂˆNE <hacks+kernel@slashdirt.org>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published
9 * by the Free Software Foundation.
10 *
11 * This driver exposes the data encoded in the "hard_config" flash segment of
12 * MikroTik RouterBOARDs devices. It presents the data in a sysfs folder
13 * named "hard_config". The WLAN calibration data is available on demand via
14 * the 'wlan_data' sysfs file in that folder.
15 *
16 * This driver permanently allocates a chunk of RAM as large as the hard_config
17 * MTD partition, although it is technically possible to operate entirely from
18 * the MTD device without using a local buffer (except when requesting WLAN
19 * calibration data), at the cost of a performance penalty.
20 *
21 * Note: PAGE_SIZE is assumed to be >= 4K, hence the device attribute show
22 * routines need not check for output overflow.
23 *
24 * Some constant defines extracted from routerboot.{c,h} by Gabor Juhos
25 * <juhosg@openwrt.org>
26 */
27
28 #include <linux/types.h>
29 #include <linux/init.h>
30 #include <linux/kernel.h>
31 #include <linux/slab.h>
32 #include <linux/errno.h>
33 #include <linux/kobject.h>
34 #include <linux/bitops.h>
35 #include <linux/string.h>
36 #include <linux/mtd/mtd.h>
37 #include <linux/sysfs.h>
38 #include <linux/lzo.h>
39
40 #include "routerboot.h"
41
42 #define RB_HARDCONFIG_VER "0.04"
43 #define RB_HC_PR_PFX "[rb_hardconfig] "
44
45 /* ID values for hardware settings */
46 #define RB_ID_FLASH_INFO 0x03
47 #define RB_ID_MAC_ADDRESS_PACK 0x04
48 #define RB_ID_BOARD_PRODUCT_CODE 0x05
49 #define RB_ID_BIOS_VERSION 0x06
50 #define RB_ID_SDRAM_TIMINGS 0x08
51 #define RB_ID_DEVICE_TIMINGS 0x09
52 #define RB_ID_SOFTWARE_ID 0x0A
53 #define RB_ID_SERIAL_NUMBER 0x0B
54 #define RB_ID_MEMORY_SIZE 0x0D
55 #define RB_ID_MAC_ADDRESS_COUNT 0x0E
56 #define RB_ID_HW_OPTIONS 0x15
57 #define RB_ID_WLAN_DATA 0x16
58 #define RB_ID_BOARD_IDENTIFIER 0x17
59 #define RB_ID_PRODUCT_NAME 0x21
60 #define RB_ID_DEFCONF 0x26
61
62 /* Bit definitions for hardware options */
63 #define RB_HW_OPT_NO_UART BIT(0)
64 #define RB_HW_OPT_HAS_VOLTAGE BIT(1)
65 #define RB_HW_OPT_HAS_USB BIT(2)
66 #define RB_HW_OPT_HAS_ATTINY BIT(3)
67 #define RB_HW_OPT_PULSE_DUTY_CYCLE BIT(9)
68 #define RB_HW_OPT_NO_NAND BIT(14)
69 #define RB_HW_OPT_HAS_LCD BIT(15)
70 #define RB_HW_OPT_HAS_POE_OUT BIT(16)
71 #define RB_HW_OPT_HAS_uSD BIT(17)
72 #define RB_HW_OPT_HAS_SIM BIT(18)
73 #define RB_HW_OPT_HAS_SFP BIT(20)
74 #define RB_HW_OPT_HAS_WIFI BIT(21)
75 #define RB_HW_OPT_HAS_TS_FOR_ADC BIT(22)
76 #define RB_HW_OPT_HAS_PLC BIT(29)
77
78 static struct kobject *hc_kobj;
79 static u8 *hc_buf; // ro buffer after init(): no locking required
80 static size_t hc_buflen;
81
82 /*
83 * For LZOR style WLAN data unpacking.
84 * This binary blob is prepended to the data encoded on some devices as
85 * RB_ID_WLAN_DATA, the result is then first decompressed with LZO, and then
86 * finally RLE-decoded.
87 * This binary blob has been extracted from RouterOS by
88 * https://forum.openwrt.org/u/ius
89 */
90 static const u8 hc_lzor_prefix[] = {
91 0x00, 0x05, 0x4c, 0x4c, 0x44, 0x00, 0x34, 0xfe,
92 0xfe, 0x34, 0x11, 0x3c, 0x1e, 0x3c, 0x2e, 0x3c,
93 0x4c, 0x34, 0x00, 0x52, 0x62, 0x92, 0xa2, 0xb2,
94 0xc3, 0x2a, 0x14, 0x00, 0x00, 0x05, 0xfe, 0x6a,
95 0x3c, 0x16, 0x32, 0x16, 0x11, 0x1e, 0x12, 0x46,
96 0x32, 0x46, 0x11, 0x4e, 0x12, 0x36, 0x32, 0x36,
97 0x11, 0x3e, 0x12, 0x5a, 0x9a, 0x64, 0x00, 0x04,
98 0xfe, 0x10, 0x3c, 0x00, 0x01, 0x00, 0x00, 0x28,
99 0x0c, 0x00, 0x0f, 0xfe, 0x14, 0x00, 0x24, 0x24,
100 0x23, 0x24, 0x24, 0x23, 0x25, 0x22, 0x21, 0x21,
101 0x23, 0x22, 0x21, 0x22, 0x21, 0x2d, 0x38, 0x00,
102 0x0c, 0x25, 0x25, 0x24, 0x25, 0x25, 0x24, 0x23,
103 0x22, 0x21, 0x20, 0x23, 0x21, 0x21, 0x22, 0x21,
104 0x2d, 0x38, 0x00, 0x28, 0xb0, 0x00, 0x00, 0x22,
105 0x00, 0x00, 0xc0, 0xfe, 0x03, 0x00, 0xc0, 0x00,
106 0x62, 0xff, 0x62, 0xff, 0xfe, 0x06, 0x00, 0xbb,
107 0xff, 0xba, 0xff, 0xfe, 0x08, 0x00, 0x9e, 0xff,
108 0xfe, 0x0a, 0x00, 0x53, 0xff, 0xfe, 0x02, 0x00,
109 0x20, 0xff, 0xb1, 0xfe, 0xfe, 0xb2, 0xfe, 0xfe,
110 0xed, 0xfe, 0xfe, 0xfe, 0x04, 0x00, 0x3a, 0xff,
111 0x3a, 0xff, 0xde, 0xfd, 0x5f, 0x04, 0x33, 0xff,
112 0x4c, 0x74, 0x03, 0x05, 0x05, 0xff, 0x6d, 0xfe,
113 0xfe, 0x6d, 0xfe, 0xfe, 0xaf, 0x08, 0x63, 0xff,
114 0x64, 0x6f, 0x08, 0xac, 0xff, 0xbf, 0x6d, 0x08,
115 0x7a, 0x6d, 0x08, 0x96, 0x74, 0x04, 0x00, 0x08,
116 0x79, 0xff, 0xda, 0xfe, 0xfe, 0xdb, 0xfe, 0xfe,
117 0x56, 0xff, 0xfe, 0x04, 0x00, 0x5e, 0xff, 0x5e,
118 0xff, 0x6c, 0xfe, 0xfe, 0xfe, 0x06, 0x00, 0x41,
119 0xff, 0x7f, 0x74, 0x03, 0x00, 0x11, 0x44, 0xff,
120 0xa9, 0xfe, 0xfe, 0xa9, 0xfe, 0xfe, 0xa5, 0x8f,
121 0x01, 0x00, 0x08, 0x01, 0x01, 0x02, 0x04, 0x08,
122 0x02, 0x04, 0x08, 0x08, 0x01, 0x01, 0xfe, 0x22,
123 0x00, 0x4c, 0x60, 0x64, 0x8c, 0x90, 0xd0, 0xd4,
124 0xd8, 0x5c, 0x10, 0x09, 0xd8, 0xff, 0xb0, 0xff,
125 0x00, 0x00, 0xba, 0xff, 0x14, 0x00, 0xba, 0xff,
126 0x64, 0x00, 0x00, 0x08, 0xfe, 0x06, 0x00, 0x74,
127 0xff, 0x42, 0xff, 0xce, 0xff, 0x60, 0xff, 0x0a,
128 0x00, 0xb4, 0x00, 0xa0, 0x00, 0xa0, 0xfe, 0x07,
129 0x00, 0x0a, 0x00, 0xb0, 0xff, 0x96, 0x4d, 0x00,
130 0x56, 0x57, 0x18, 0xa6, 0xff, 0x92, 0x70, 0x11,
131 0x00, 0x12, 0x90, 0x90, 0x76, 0x5a, 0x54, 0x54,
132 0x4c, 0x46, 0x38, 0x00, 0x10, 0x10, 0x08, 0xfe,
133 0x05, 0x00, 0x38, 0x29, 0x25, 0x23, 0x22, 0x22,
134 0x1f, 0x00, 0x00, 0x00, 0xf6, 0xe1, 0xdd, 0xf8,
135 0xfe, 0x00, 0xfe, 0x15, 0x00, 0x00, 0xd0, 0x02,
136 0x74, 0x02, 0x08, 0xf8, 0xe5, 0xde, 0x02, 0x04,
137 0x04, 0xfd, 0x00, 0x00, 0x00, 0x07, 0x50, 0x2d,
138 0x01, 0x90, 0x90, 0x76, 0x60, 0xb0, 0x07, 0x07,
139 0x0c, 0x0c, 0x04, 0xfe, 0x05, 0x00, 0x66, 0x66,
140 0x5a, 0x56, 0xbc, 0x01, 0x06, 0xfc, 0xfc, 0xf1,
141 0xfe, 0x07, 0x00, 0x24, 0x95, 0x70, 0x64, 0x18,
142 0x06, 0x2c, 0xff, 0xb5, 0xfe, 0xfe, 0xb5, 0xfe,
143 0xfe, 0xe2, 0x8c, 0x24, 0x02, 0x2f, 0xff, 0x2f,
144 0xff, 0xb4, 0x78, 0x02, 0x05, 0x73, 0xff, 0xed,
145 0xfe, 0xfe, 0x4f, 0xff, 0x36, 0x74, 0x1e, 0x09,
146 0x4f, 0xff, 0x50, 0xff, 0xfe, 0x16, 0x00, 0x70,
147 0xac, 0x70, 0x8e, 0xac, 0x40, 0x0e, 0x01, 0x70,
148 0x7f, 0x8e, 0xac, 0x6c, 0x00, 0x0b, 0xfe, 0x02,
149 0x00, 0xfe, 0x0a, 0x2c, 0x2a, 0x2a, 0x28, 0x26,
150 0x1e, 0x1e, 0xfe, 0x02, 0x20, 0x65, 0x20, 0x00,
151 0x00, 0x05, 0x12, 0x00, 0x11, 0x1e, 0x11, 0x11,
152 0x41, 0x1e, 0x41, 0x11, 0x31, 0x1e, 0x31, 0x11,
153 0x70, 0x75, 0x7a, 0x7f, 0x84, 0x89, 0x8e, 0x93,
154 0x98, 0x30, 0x20, 0x00, 0x02, 0x00, 0xfe, 0x06,
155 0x3c, 0xbc, 0x32, 0x0c, 0x00, 0x00, 0x2a, 0x12,
156 0x1e, 0x12, 0x2e, 0x12, 0xcc, 0x12, 0x11, 0x1a,
157 0x1e, 0x1a, 0x2e, 0x1a, 0x4c, 0x10, 0x1e, 0x10,
158 0x11, 0x18, 0x1e, 0x42, 0x1e, 0x42, 0x2e, 0x42,
159 0xcc, 0x42, 0x11, 0x4a, 0x1e, 0x4a, 0x2e, 0x4a,
160 0x4c, 0x40, 0x1e, 0x40, 0x11, 0x48, 0x1e, 0x32,
161 0x1e, 0x32, 0x2e, 0x32, 0xcc, 0x32, 0x11, 0x3a,
162 0x1e, 0x3a, 0x2e, 0x3a, 0x4c, 0x30, 0x1e, 0x30,
163 0x11, 0x38, 0x1e, 0x27, 0x9a, 0x01, 0x9d, 0xa2,
164 0x2f, 0x28, 0x00, 0x00, 0x46, 0xde, 0xc4, 0xbf,
165 0xa6, 0x9d, 0x81, 0x7b, 0x5c, 0x61, 0x40, 0xc7,
166 0xc0, 0xae, 0xa9, 0x8c, 0x83, 0x6a, 0x62, 0x50,
167 0x3e, 0xce, 0xc2, 0xae, 0xa3, 0x8c, 0x7b, 0x6a,
168 0x5a, 0x50, 0x35, 0xd7, 0xc2, 0xb7, 0xa4, 0x95,
169 0x7e, 0x72, 0x5a, 0x59, 0x37, 0xfe, 0x02, 0xf8,
170 0x8c, 0x95, 0x90, 0x8f, 0x00, 0xd7, 0xc0, 0xb7,
171 0xa2, 0x95, 0x7b, 0x72, 0x56, 0x59, 0x32, 0xc7,
172 0xc3, 0xae, 0xad, 0x8c, 0x85, 0x6a, 0x63, 0x50,
173 0x3e, 0xce, 0xc3, 0xae, 0xa4, 0x8c, 0x7c, 0x6a,
174 0x59, 0x50, 0x34, 0xd7, 0xc2, 0xb7, 0xa5, 0x95,
175 0x7e, 0x72, 0x59, 0x59, 0x36, 0xfc, 0x05, 0x00,
176 0x02, 0xce, 0xc5, 0xae, 0xa5, 0x95, 0x83, 0x72,
177 0x5c, 0x59, 0x36, 0xbf, 0xc6, 0xa5, 0xab, 0x8c,
178 0x8c, 0x6a, 0x67, 0x50, 0x41, 0x64, 0x07, 0x00,
179 0x02, 0x95, 0x8c, 0x72, 0x65, 0x59, 0x3f, 0xce,
180 0xc7, 0xae, 0xa8, 0x95, 0x86, 0x72, 0x5f, 0x59,
181 0x39, 0xfe, 0x02, 0xf8, 0x8b, 0x7c, 0x0b, 0x09,
182 0xb7, 0xc2, 0x9d, 0xa4, 0x83, 0x85, 0x6a, 0x6b,
183 0x50, 0x44, 0xb7, 0xc1, 0x64, 0x01, 0x00, 0x06,
184 0x61, 0x5d, 0x48, 0x3d, 0xae, 0xc4, 0x9d, 0xad,
185 0x7b, 0x85, 0x61, 0x66, 0x48, 0x46, 0xae, 0xc3,
186 0x95, 0xa3, 0x72, 0x7c, 0x59, 0x56, 0x38, 0x31,
187 0x7c, 0x0b, 0x00, 0x0c, 0x96, 0x91, 0x8f, 0x00,
188 0xb7, 0xc0, 0xa5, 0xab, 0x8c, 0x8a, 0x6a, 0x64,
189 0x50, 0x3c, 0xb7, 0xc0, 0x9d, 0xa0, 0x83, 0x80,
190 0x6a, 0x64, 0x50, 0x3d, 0xb7, 0xc5, 0x9d, 0xa5,
191 0x83, 0x87, 0x6c, 0x08, 0x07, 0xae, 0xc0, 0x9d,
192 0xa8, 0x83, 0x88, 0x6a, 0x6d, 0x50, 0x46, 0xfc,
193 0x05, 0x00, 0x16, 0xbf, 0xc0, 0xa5, 0xa2, 0x8c,
194 0x7f, 0x6a, 0x57, 0x50, 0x2f, 0xb7, 0xc7, 0xa5,
195 0xb1, 0x8c, 0x8e, 0x72, 0x6d, 0x59, 0x45, 0xbf,
196 0xc6, 0xa5, 0xa8, 0x8c, 0x87, 0x6a, 0x5f, 0x50,
197 0x37, 0xbf, 0xc2, 0xa5, 0xa4, 0x8c, 0x83, 0x6a,
198 0x5c, 0x50, 0x34, 0xbc, 0x05, 0x00, 0x0e, 0x90,
199 0x00, 0xc7, 0xc2, 0xae, 0xaa, 0x95, 0x82, 0x7b,
200 0x60, 0x61, 0x3f, 0xb7, 0xc6, 0xa5, 0xb1, 0x8c,
201 0x8d, 0x72, 0x6b, 0x61, 0x51, 0xbf, 0xc4, 0xa5,
202 0xa5, 0x8c, 0x82, 0x72, 0x61, 0x59, 0x39, 0x6c,
203 0x26, 0x03, 0x95, 0x82, 0x7b, 0x61, 0x61, 0x40,
204 0xfc, 0x05, 0x00, 0x00, 0x7e, 0xd7, 0xc3, 0xb7,
205 0xa8, 0x9d, 0x80, 0x83, 0x5d, 0x6a, 0x3f, 0xbf,
206 0xc7, 0xa5, 0xa8, 0x8c, 0x84, 0x72, 0x60, 0x61,
207 0x46, 0xbf, 0xc2, 0xae, 0xb0, 0x9d, 0x92, 0x83,
208 0x6f, 0x6a, 0x50, 0xd7, 0xc3, 0xb7, 0xa7, 0x9d,
209 0x80, 0x83, 0x5e, 0x6a, 0x40, 0xfe, 0x02, 0xf8,
210 0x8d, 0x96, 0x90, 0x90, 0xfe, 0x05, 0x00, 0x8a,
211 0xc4, 0x63, 0xb8, 0x3c, 0xa6, 0x29, 0x97, 0x16,
212 0x81, 0x84, 0xb7, 0x5b, 0xa9, 0x33, 0x94, 0x1e,
213 0x83, 0x11, 0x70, 0xb8, 0xc2, 0x70, 0xb1, 0x4d,
214 0xa3, 0x2a, 0x8d, 0x1b, 0x7b, 0xa8, 0xbc, 0x68,
215 0xab, 0x47, 0x9d, 0x27, 0x87, 0x18, 0x75, 0xae,
216 0xc6, 0x7d, 0xbb, 0x4d, 0xaa, 0x1c, 0x84, 0x11,
217 0x72, 0xa3, 0xbb, 0x6e, 0xad, 0x3c, 0x97, 0x24,
218 0x85, 0x16, 0x71, 0x80, 0xb2, 0x57, 0xa4, 0x30,
219 0x8e, 0x1c, 0x7c, 0x10, 0x68, 0xbb, 0xbd, 0x75,
220 0xac, 0x4f, 0x9e, 0x2b, 0x87, 0x1a, 0x76, 0x96,
221 0xc5, 0x5e, 0xb5, 0x3e, 0xa5, 0x1f, 0x8c, 0x12,
222 0x7a, 0xc1, 0xc6, 0x42, 0x9f, 0x27, 0x8c, 0x16,
223 0x77, 0x0f, 0x67, 0x9d, 0xbc, 0x68, 0xad, 0x36,
224 0x95, 0x20, 0x83, 0x11, 0x6d, 0x9b, 0xb8, 0x67,
225 0xa8, 0x34, 0x90, 0x1f, 0x7c, 0x10, 0x67, 0x9e,
226 0xc9, 0x6a, 0xbb, 0x37, 0xa4, 0x20, 0x90, 0x11,
227 0x7b, 0xc6, 0xc8, 0x47, 0xa4, 0x2a, 0x90, 0x18,
228 0x7b, 0x10, 0x6c, 0xae, 0xc4, 0x5d, 0xad, 0x37,
229 0x9a, 0x1f, 0x85, 0x13, 0x75, 0x70, 0xad, 0x42,
230 0x99, 0x25, 0x84, 0x17, 0x74, 0x0b, 0x56, 0x87,
231 0xc8, 0x57, 0xb8, 0x2b, 0x9e, 0x19, 0x8a, 0x0d,
232 0x74, 0xa7, 0xc8, 0x6e, 0xb9, 0x36, 0xa0, 0x1f,
233 0x8b, 0x11, 0x75, 0x94, 0xbe, 0x4b, 0xa5, 0x2a,
234 0x92, 0x18, 0x7c, 0x0f, 0x6b, 0xaf, 0xc0, 0x58,
235 0xa8, 0x34, 0x94, 0x1d, 0x7d, 0x12, 0x6d, 0x82,
236 0xc0, 0x52, 0xb0, 0x25, 0x94, 0x14, 0x7f, 0x0c,
237 0x68, 0x84, 0xbf, 0x3e, 0xa4, 0x22, 0x8e, 0x10,
238 0x76, 0x0b, 0x65, 0x88, 0xb6, 0x42, 0x9b, 0x26,
239 0x87, 0x14, 0x70, 0x0c, 0x5f, 0xc5, 0xc2, 0x3e,
240 0x97, 0x23, 0x83, 0x13, 0x6c, 0x0c, 0x5c, 0xb1,
241 0xc9, 0x76, 0xbc, 0x4a, 0xaa, 0x20, 0x8d, 0x12,
242 0x78, 0x93, 0xbf, 0x46, 0xa3, 0x26, 0x8d, 0x14,
243 0x74, 0x0c, 0x62, 0xc8, 0xc4, 0x3b, 0x97, 0x21,
244 0x82, 0x11, 0x6a, 0x0a, 0x59, 0xa3, 0xb9, 0x68,
245 0xa9, 0x30, 0x8d, 0x1a, 0x78, 0x0f, 0x61, 0xa0,
246 0xc9, 0x73, 0xbe, 0x50, 0xb1, 0x30, 0x9f, 0x14,
247 0x80, 0x83, 0xb7, 0x3c, 0x9a, 0x20, 0x84, 0x0e,
248 0x6a, 0x0a, 0x57, 0xac, 0xc2, 0x68, 0xb0, 0x2e,
249 0x92, 0x19, 0x7c, 0x0d, 0x63, 0x93, 0xbe, 0x62,
250 0xb0, 0x3c, 0x9e, 0x1a, 0x80, 0x0e, 0x6b, 0xbb,
251 0x02, 0xa0, 0x02, 0xa0, 0x02, 0x6f, 0x00, 0x75,
252 0x00, 0x75, 0x00, 0x00, 0x00, 0xad, 0x02, 0xb3,
253 0x02, 0x6f, 0x00, 0x87, 0x00, 0x85, 0xfe, 0x03,
254 0x00, 0xc2, 0x02, 0x82, 0x4d, 0x92, 0x6e, 0x4d,
255 0xb1, 0xa8, 0x84, 0x01, 0x00, 0x07, 0x7e, 0x00,
256 0xa8, 0x02, 0xa4, 0x02, 0xa4, 0x02, 0xa2, 0x00,
257 0xa6, 0x00, 0xa6, 0x00, 0x00, 0x00, 0xb4, 0x02,
258 0xb4, 0x02, 0x92, 0x00, 0x96, 0x00, 0x96, 0x46,
259 0x04, 0xb0, 0x02, 0x64, 0x02, 0x0a, 0x8c, 0x00,
260 0x90, 0x02, 0x98, 0x02, 0x98, 0x02, 0x0e, 0x01,
261 0x11, 0x01, 0x11, 0x50, 0xc3, 0x08, 0x88, 0x02,
262 0x88, 0x02, 0x19, 0x01, 0x02, 0x01, 0x02, 0x01,
263 0xf3, 0x2d, 0x00, 0x00
264 };
265
266 /* Array of known hw_options bits with human-friendly parsing */
267 static struct hc_hwopt {
268 const u32 bit;
269 const char *str;
270 } const hc_hwopts[] = {
271 {
272 .bit = RB_HW_OPT_NO_UART,
273 .str = "no UART\t\t",
274 }, {
275 .bit = RB_HW_OPT_HAS_VOLTAGE,
276 .str = "has Vreg\t",
277 }, {
278 .bit = RB_HW_OPT_HAS_USB,
279 .str = "has usb\t\t",
280 }, {
281 .bit = RB_HW_OPT_HAS_ATTINY,
282 .str = "has ATtiny\t",
283 }, {
284 .bit = RB_HW_OPT_NO_NAND,
285 .str = "no NAND\t\t",
286 }, {
287 .bit = RB_HW_OPT_HAS_LCD,
288 .str = "has LCD\t\t",
289 }, {
290 .bit = RB_HW_OPT_HAS_POE_OUT,
291 .str = "has POE out\t",
292 }, {
293 .bit = RB_HW_OPT_HAS_uSD,
294 .str = "has MicroSD\t",
295 }, {
296 .bit = RB_HW_OPT_HAS_SIM,
297 .str = "has SIM\t\t",
298 }, {
299 .bit = RB_HW_OPT_HAS_SFP,
300 .str = "has SFP\t\t",
301 }, {
302 .bit = RB_HW_OPT_HAS_WIFI,
303 .str = "has WiFi\t",
304 }, {
305 .bit = RB_HW_OPT_HAS_TS_FOR_ADC,
306 .str = "has TS ADC\t",
307 }, {
308 .bit = RB_HW_OPT_HAS_PLC,
309 .str = "has PLC\t\t",
310 },
311 };
312
313 /*
314 * The MAC is stored network-endian on all devices, in 2 32-bit segments:
315 * <XX:XX:XX:XX> <XX:XX:00:00>. Kernel print has us covered.
316 */
317 static ssize_t hc_tag_show_mac(const u8 *pld, u16 pld_len, char *buf)
318 {
319 if (8 != pld_len)
320 return -EINVAL;
321
322 return sprintf(buf, "%pM\n", pld);
323 }
324
325 /*
326 * Print HW options in a human readable way:
327 * The raw number and in decoded form
328 */
329 static ssize_t hc_tag_show_hwoptions(const u8 *pld, u16 pld_len, char *buf)
330 {
331 char *out = buf;
332 u32 data; // cpu-endian
333 int i;
334
335 if (sizeof(data) != pld_len)
336 return -EINVAL;
337
338 data = *(u32 *)pld;
339 out += sprintf(out, "raw\t\t: 0x%08x\n\n", data);
340
341 for (i = 0; i < ARRAY_SIZE(hc_hwopts); i++)
342 out += sprintf(out, "%s: %s\n", hc_hwopts[i].str,
343 (data & hc_hwopts[i].bit) ? "true" : "false");
344
345 return out - buf;
346 }
347
348 static ssize_t hc_wlan_data_bin_read(struct file *filp, struct kobject *kobj,
349 struct bin_attribute *attr, char *buf,
350 loff_t off, size_t count);
351
352 static struct hc_wlan_attr {
353 struct bin_attribute battr;
354 u16 pld_ofs;
355 u16 pld_len;
356 } hc_wlandata_battr = {
357 .battr = __BIN_ATTR(wlan_data, S_IRUSR, hc_wlan_data_bin_read, NULL, 0),
358 };
359
360 static ssize_t hc_attr_show(struct kobject *kobj, struct kobj_attribute *attr,
361 char *buf);
362
363 /* Array of known tags to publish in sysfs */
364 static struct hc_attr {
365 const u16 tag_id;
366 ssize_t (* const tshow)(const u8 *pld, u16 pld_len, char *buf);
367 struct kobj_attribute kattr;
368 u16 pld_ofs;
369 u16 pld_len;
370 } hc_attrs[] = {
371 {
372 .tag_id = RB_ID_FLASH_INFO,
373 .tshow = routerboot_tag_show_u32s,
374 .kattr = __ATTR(flash_info, S_IRUSR, hc_attr_show, NULL),
375 }, {
376 .tag_id = RB_ID_MAC_ADDRESS_PACK,
377 .tshow = hc_tag_show_mac,
378 .kattr = __ATTR(mac_base, S_IRUSR, hc_attr_show, NULL),
379 }, {
380 .tag_id = RB_ID_BOARD_PRODUCT_CODE,
381 .tshow = routerboot_tag_show_string,
382 .kattr = __ATTR(board_product_code, S_IRUSR, hc_attr_show, NULL),
383 }, {
384 .tag_id = RB_ID_BIOS_VERSION,
385 .tshow = routerboot_tag_show_string,
386 .kattr = __ATTR(booter_version, S_IRUSR, hc_attr_show, NULL),
387 }, {
388 .tag_id = RB_ID_SERIAL_NUMBER,
389 .tshow = routerboot_tag_show_string,
390 .kattr = __ATTR(board_serial, S_IRUSR, hc_attr_show, NULL),
391 }, {
392 .tag_id = RB_ID_MEMORY_SIZE,
393 .tshow = routerboot_tag_show_u32s,
394 .kattr = __ATTR(mem_size, S_IRUSR, hc_attr_show, NULL),
395 }, {
396 .tag_id = RB_ID_MAC_ADDRESS_COUNT,
397 .tshow = routerboot_tag_show_u32s,
398 .kattr = __ATTR(mac_count, S_IRUSR, hc_attr_show, NULL),
399 }, {
400 .tag_id = RB_ID_HW_OPTIONS,
401 .tshow = hc_tag_show_hwoptions,
402 .kattr = __ATTR(hw_options, S_IRUSR, hc_attr_show, NULL),
403 }, {
404 .tag_id = RB_ID_WLAN_DATA,
405 .tshow = NULL,
406 }, {
407 .tag_id = RB_ID_BOARD_IDENTIFIER,
408 .tshow = routerboot_tag_show_string,
409 .kattr = __ATTR(board_identifier, S_IRUSR, hc_attr_show, NULL),
410 }, {
411 .tag_id = RB_ID_PRODUCT_NAME,
412 .tshow = routerboot_tag_show_string,
413 .kattr = __ATTR(product_name, S_IRUSR, hc_attr_show, NULL),
414 }, {
415 .tag_id = RB_ID_DEFCONF,
416 .tshow = routerboot_tag_show_string,
417 .kattr = __ATTR(defconf, S_IRUSR, hc_attr_show, NULL),
418 }
419 };
420
421 /*
422 * If the RB_ID_WLAN_DATA payload starts with RB_MAGIC_ERD, then past
423 * that magic number the payload itself contains a routerboot tag node
424 * locating the LZO-compressed calibration data at id 0x1.
425 */
426 static int hc_wlan_data_unpack_erd(const u8 *inbuf, size_t inlen,
427 void *outbuf, size_t *outlen)
428 {
429 u16 lzo_ofs, lzo_len;
430 int ret;
431
432 /* Find embedded tag */
433 ret = routerboot_tag_find(inbuf, inlen, 0x1, // always id 1
434 &lzo_ofs, &lzo_len);
435 if (ret) {
436 pr_debug(RB_HC_PR_PFX "ERD data not found\n");
437 goto fail;
438 }
439
440 if (lzo_len > inlen) {
441 pr_debug(RB_HC_PR_PFX "Invalid ERD data length\n");
442 ret = -EINVAL;
443 goto fail;
444 }
445
446 ret = lzo1x_decompress_safe(inbuf+lzo_ofs, lzo_len, outbuf, outlen);
447 if (ret)
448 pr_debug(RB_HC_PR_PFX "LZO decompression error (%d)\n", ret);
449
450 fail:
451 return ret;
452 }
453
454 /*
455 * If the RB_ID_WLAN_DATA payload starts with RB_MAGIC_LZOR, then past
456 * that magic number is a payload that must be appended to the hc_lzor_prefix,
457 * the resulting blob is LZO-compressed. In the LZO decompression result,
458 * the RB_MAGIC_ERD magic number (aligned) must be located. Following that
459 * magic, there is a routerboot tag node (id 0x1) locating the RLE-encoded
460 * calibration data payload.
461 */
462 static int hc_wlan_data_unpack_lzor(const u8 *inbuf, size_t inlen,
463 void *outbuf, size_t *outlen)
464 {
465 u16 rle_ofs, rle_len;
466 const u32 *needle;
467 u8 *tempbuf;
468 size_t templen, lzo_len;
469 int ret;
470
471 lzo_len = inlen + sizeof(hc_lzor_prefix);
472 if (lzo_len > *outlen)
473 return -EFBIG;
474
475 /* Temporary buffer same size as the outbuf */
476 templen = *outlen;
477 tempbuf = kmalloc(templen, GFP_KERNEL);
478 if (!outbuf)
479 return -ENOMEM;
480
481 /* Concatenate into the outbuf */
482 memcpy(outbuf, hc_lzor_prefix, sizeof(hc_lzor_prefix));
483 memcpy(outbuf + sizeof(hc_lzor_prefix), inbuf, inlen);
484
485 /* LZO-decompress lzo_len bytes of outbuf into the tempbuf */
486 ret = lzo1x_decompress_safe(outbuf, lzo_len, tempbuf, &templen);
487 if (ret) {
488 if (LZO_E_INPUT_NOT_CONSUMED == ret) {
489 /*
490 * The tag length appears to always be aligned (probably
491 * because it is the "root" RB_ID_WLAN_DATA tag), thus
492 * the LZO payload may be padded, which can trigger a
493 * spurious error which we ignore here.
494 */
495 pr_debug(RB_HC_PR_PFX "LZOR: LZO EOF before buffer end - this may be harmless\n");
496 } else {
497 pr_debug(RB_HC_PR_PFX "LZOR: LZO decompression error (%d)\n", ret);
498 goto fail;
499 }
500 }
501
502 /*
503 * Post decompression we have a blob (possibly byproduct of the lzo
504 * dictionary). We need to find RB_MAGIC_ERD. The magic number seems to
505 * be 32bit-aligned in the decompression output.
506 */
507 needle = (const u32 *)tempbuf;
508 while (RB_MAGIC_ERD != *needle++) {
509 if ((u8 *)needle >= tempbuf+templen) {
510 pr_debug(RB_HC_PR_PFX "LZOR: ERD magic not found\n");
511 ret = -ENODATA;
512 goto fail;
513 }
514 };
515 templen -= (u8 *)needle - tempbuf;
516
517 /* Past magic. Look for tag node */
518 ret = routerboot_tag_find((u8 *)needle, templen, 0x1, &rle_ofs, &rle_len);
519 if (ret) {
520 pr_debug(RB_HC_PR_PFX "LZOR: RLE data not found\n");
521 goto fail;
522 }
523
524 if (rle_len > templen) {
525 pr_debug(RB_HC_PR_PFX "LZOR: Invalid RLE data length\n");
526 ret = -EINVAL;
527 goto fail;
528 }
529
530 /* RLE-decode tempbuf from needle back into the outbuf */
531 ret = routerboot_rle_decode((u8 *)needle+rle_ofs, rle_len, outbuf, outlen);
532 if (ret)
533 pr_debug(RB_HC_PR_PFX "LZOR: RLE decoding error (%d)\n", ret);
534
535 fail:
536 kfree(tempbuf);
537 return ret;
538 }
539
540 static int hc_wlan_data_unpack(const size_t tofs, size_t tlen,
541 void *outbuf, size_t *outlen)
542 {
543 const u8 *lbuf;
544 u32 magic;
545 int ret;
546
547 /* Caller ensure tlen > 0. tofs is aligned */
548 if ((tofs + tlen) > hc_buflen)
549 return -EIO;
550
551 lbuf = hc_buf + tofs;
552 magic = *(u32 *)lbuf;
553
554 ret = -ENODATA;
555 switch (magic) {
556 case RB_MAGIC_LZOR:
557 /* Skip magic */
558 lbuf += sizeof(magic);
559 tlen -= sizeof(magic);
560 ret = hc_wlan_data_unpack_lzor(lbuf, tlen, outbuf, outlen);
561 break;
562 case RB_MAGIC_ERD:
563 /* Skip magic */
564 lbuf += sizeof(magic);
565 tlen -= sizeof(magic);
566 ret = hc_wlan_data_unpack_erd(lbuf, tlen, outbuf, outlen);
567 break;
568 default:
569 /*
570 * If the RB_ID_WLAN_DATA payload doesn't start with a
571 * magic number, the payload itself is the raw RLE-encoded
572 * calibration data.
573 */
574 ret = routerboot_rle_decode(lbuf, tlen, outbuf, outlen);
575 if (ret)
576 pr_debug(RB_HC_PR_PFX "RLE decoding error (%d)\n", ret);
577 break;
578 }
579
580 return ret;
581 }
582
583 static ssize_t hc_attr_show(struct kobject *kobj, struct kobj_attribute *attr,
584 char *buf)
585 {
586 const struct hc_attr *hc_attr;
587 const u8 *pld;
588 u16 pld_len;
589
590 hc_attr = container_of(attr, typeof(*hc_attr), kattr);
591
592 if (!hc_attr->pld_len)
593 return -ENOENT;
594
595 pld = hc_buf + hc_attr->pld_ofs;
596 pld_len = hc_attr->pld_len;
597
598 return hc_attr->tshow(pld, pld_len, buf);
599 }
600
601 /*
602 * This function will allocate and free memory every time it is called. This
603 * is not the fastest way to do this, but since the data is rarely read (mainly
604 * at boot time to load wlan caldata), this makes it possible to save memory for
605 * the system.
606 */
607 static ssize_t hc_wlan_data_bin_read(struct file *filp, struct kobject *kobj,
608 struct bin_attribute *attr, char *buf,
609 loff_t off, size_t count)
610 {
611 struct hc_wlan_attr *hc_wattr;
612 size_t outlen;
613 void *outbuf;
614 int ret;
615
616 hc_wattr = container_of(attr, typeof(*hc_wattr), battr);
617
618 if (!hc_wattr->pld_len)
619 return -ENOENT;
620
621 outlen = RB_ART_SIZE;
622
623 /* Don't bother unpacking if the source is already too large */
624 if (hc_wattr->pld_len > outlen)
625 return -EFBIG;
626
627 outbuf = kmalloc(outlen, GFP_KERNEL);
628 if (!outbuf)
629 return -ENOMEM;
630
631 ret = hc_wlan_data_unpack(hc_wattr->pld_ofs, hc_wattr->pld_len, outbuf, &outlen);
632 if (ret) {
633 kfree(outbuf);
634 return ret;
635 }
636
637 if (off >= outlen) {
638 kfree(outbuf);
639 return 0;
640 }
641
642 if (off + count > outlen)
643 count = outlen - off;
644
645 memcpy(buf, outbuf + off, count);
646
647 kfree(outbuf);
648 return count;
649 }
650
651 int __init rb_hardconfig_init(struct kobject *rb_kobj)
652 {
653 struct mtd_info *mtd;
654 size_t bytes_read, buflen;
655 const u8 *buf;
656 int i, ret;
657 u32 magic;
658
659 hc_buf = NULL;
660 hc_kobj = NULL;
661
662 // TODO allow override
663 mtd = get_mtd_device_nm(RB_MTD_HARD_CONFIG);
664 if (IS_ERR(mtd))
665 return -ENODEV;
666
667 hc_buflen = mtd->size;
668 hc_buf = kmalloc(hc_buflen, GFP_KERNEL);
669 if (!hc_buf)
670 return -ENOMEM;
671
672 ret = mtd_read(mtd, 0, hc_buflen, &bytes_read, hc_buf);
673
674 if (ret)
675 goto fail;
676
677 if (bytes_read != hc_buflen) {
678 ret = -EIO;
679 goto fail;
680 }
681
682 /* Check we have what we expect */
683 magic = *(const u32 *)hc_buf;
684 if (RB_MAGIC_HARD != magic) {
685 ret = -EINVAL;
686 goto fail;
687 }
688
689 /* Skip magic */
690 buf = hc_buf + sizeof(magic);
691 buflen = hc_buflen - sizeof(magic);
692
693 /* Populate sysfs */
694 ret = -ENOMEM;
695 hc_kobj = kobject_create_and_add(RB_MTD_HARD_CONFIG, rb_kobj);
696 if (!hc_kobj)
697 goto fail;
698
699 /* Locate and publish all known tags */
700 for (i = 0; i < ARRAY_SIZE(hc_attrs); i++) {
701 ret = routerboot_tag_find(buf, buflen, hc_attrs[i].tag_id,
702 &hc_attrs[i].pld_ofs, &hc_attrs[i].pld_len);
703 if (ret) {
704 hc_attrs[i].pld_ofs = hc_attrs[i].pld_len = 0;
705 continue;
706 }
707
708 /* Account for skipped magic */
709 hc_attrs[i].pld_ofs += sizeof(magic);
710
711 /* Special case RB_ID_WLAN_DATA to prep and create the binary attribute */
712 if ((RB_ID_WLAN_DATA == hc_attrs[i].tag_id) && hc_attrs[i].pld_len) {
713 hc_wlandata_battr.pld_ofs = hc_attrs[i].pld_ofs;
714 hc_wlandata_battr.pld_len = hc_attrs[i].pld_len;
715
716 ret = sysfs_create_bin_file(hc_kobj, &hc_wlandata_battr.battr);
717 if (ret)
718 pr_warn(RB_HC_PR_PFX "Could not create %s sysfs entry (%d)\n",
719 hc_wlandata_battr.battr.attr.name, ret);
720 }
721 /* All other tags are published via standard attributes */
722 else {
723 ret = sysfs_create_file(hc_kobj, &hc_attrs[i].kattr.attr);
724 if (ret)
725 pr_warn(RB_HC_PR_PFX "Could not create %s sysfs entry (%d)\n",
726 hc_attrs[i].kattr.attr.name, ret);
727 }
728 }
729
730 pr_info("MikroTik RouterBOARD hardware configuration sysfs driver v" RB_HARDCONFIG_VER "\n");
731
732 return 0;
733
734 fail:
735 kfree(hc_buf);
736 hc_buf = NULL;
737 return ret;
738 }
739
740 void __exit rb_hardconfig_exit(void)
741 {
742 kobject_put(hc_kobj);
743 kfree(hc_buf);
744 }