1 /*
2  * Copyright (c) 2013 Broadcom Corporation
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include <linux/kernel.h>
18 #include <linux/slab.h>
19 #include <linux/device.h>
20 #include <linux/firmware.h>
21 #include <linux/module.h>
22 
23 #include "debug.h"
24 #include "firmware.h"
25 
26 char brcmf_firmware_path[BRCMF_FW_PATH_LEN];
27 module_param_string(firmware_path, brcmf_firmware_path,
28 		    BRCMF_FW_PATH_LEN, 0440);
29 
30 enum nvram_parser_state {
31 	IDLE,
32 	KEY,
33 	VALUE,
34 	COMMENT,
35 	END
36 };
37 
38 /**
39  * struct nvram_parser - internal info for parser.
40  *
41  * @state: current parser state.
42  * @fwnv: input buffer being parsed.
43  * @nvram: output buffer with parse result.
44  * @nvram_len: lenght of parse result.
45  * @line: current line.
46  * @column: current column in line.
47  * @pos: byte offset in input buffer.
48  * @entry: start position of key,value entry.
49  */
50 struct nvram_parser {
51 	enum nvram_parser_state state;
52 	const struct firmware *fwnv;
53 	u8 *nvram;
54 	u32 nvram_len;
55 	u32 line;
56 	u32 column;
57 	u32 pos;
58 	u32 entry;
59 };
60 
is_nvram_char(char c)61 static bool is_nvram_char(char c)
62 {
63 	/* comment marker excluded */
64 	if (c == '#')
65 		return false;
66 
67 	/* key and value may have any other readable character */
68 	return (c > 0x20 && c < 0x7f);
69 }
70 
is_whitespace(char c)71 static bool is_whitespace(char c)
72 {
73 	return (c == ' ' || c == '\r' || c == '\n' || c == '\t');
74 }
75 
brcmf_nvram_handle_idle(struct nvram_parser * nvp)76 static enum nvram_parser_state brcmf_nvram_handle_idle(struct nvram_parser *nvp)
77 {
78 	char c;
79 
80 	c = nvp->fwnv->data[nvp->pos];
81 	if (c == '\n')
82 		return COMMENT;
83 	if (is_whitespace(c))
84 		goto proceed;
85 	if (c == '#')
86 		return COMMENT;
87 	if (is_nvram_char(c)) {
88 		nvp->entry = nvp->pos;
89 		return KEY;
90 	}
91 	brcmf_dbg(INFO, "warning: ln=%d:col=%d: ignoring invalid character\n",
92 		  nvp->line, nvp->column);
93 proceed:
94 	nvp->column++;
95 	nvp->pos++;
96 	return IDLE;
97 }
98 
brcmf_nvram_handle_key(struct nvram_parser * nvp)99 static enum nvram_parser_state brcmf_nvram_handle_key(struct nvram_parser *nvp)
100 {
101 	enum nvram_parser_state st = nvp->state;
102 	char c;
103 
104 	c = nvp->fwnv->data[nvp->pos];
105 	if (c == '=') {
106 		/* ignore RAW1 by treating as comment */
107 		if (strncmp(&nvp->fwnv->data[nvp->entry], "RAW1", 4) == 0)
108 			st = COMMENT;
109 		else
110 			st = VALUE;
111 	} else if (!is_nvram_char(c)) {
112 		brcmf_dbg(INFO, "warning: ln=%d:col=%d: '=' expected, skip invalid key entry\n",
113 			  nvp->line, nvp->column);
114 		return COMMENT;
115 	}
116 
117 	nvp->column++;
118 	nvp->pos++;
119 	return st;
120 }
121 
122 static enum nvram_parser_state
brcmf_nvram_handle_value(struct nvram_parser * nvp)123 brcmf_nvram_handle_value(struct nvram_parser *nvp)
124 {
125 	char c;
126 	char *skv;
127 	char *ekv;
128 	u32 cplen;
129 
130 	c = nvp->fwnv->data[nvp->pos];
131 	if (!is_nvram_char(c)) {
132 		/* key,value pair complete */
133 		ekv = (u8 *)&nvp->fwnv->data[nvp->pos];
134 		skv = (u8 *)&nvp->fwnv->data[nvp->entry];
135 		cplen = ekv - skv;
136 		/* copy to output buffer */
137 		memcpy(&nvp->nvram[nvp->nvram_len], skv, cplen);
138 		nvp->nvram_len += cplen;
139 		nvp->nvram[nvp->nvram_len] = '\0';
140 		nvp->nvram_len++;
141 		return IDLE;
142 	}
143 	nvp->pos++;
144 	nvp->column++;
145 	return VALUE;
146 }
147 
148 static enum nvram_parser_state
brcmf_nvram_handle_comment(struct nvram_parser * nvp)149 brcmf_nvram_handle_comment(struct nvram_parser *nvp)
150 {
151 	char *eol, *sol;
152 
153 	sol = (char *)&nvp->fwnv->data[nvp->pos];
154 	eol = strchr(sol, '\n');
155 	if (eol == NULL)
156 		return END;
157 
158 	/* eat all moving to next line */
159 	nvp->line++;
160 	nvp->column = 1;
161 	nvp->pos += (eol - sol) + 1;
162 	return IDLE;
163 }
164 
brcmf_nvram_handle_end(struct nvram_parser * nvp)165 static enum nvram_parser_state brcmf_nvram_handle_end(struct nvram_parser *nvp)
166 {
167 	/* final state */
168 	return END;
169 }
170 
171 static enum nvram_parser_state
172 (*nv_parser_states[])(struct nvram_parser *nvp) = {
173 	brcmf_nvram_handle_idle,
174 	brcmf_nvram_handle_key,
175 	brcmf_nvram_handle_value,
176 	brcmf_nvram_handle_comment,
177 	brcmf_nvram_handle_end
178 };
179 
brcmf_init_nvram_parser(struct nvram_parser * nvp,const struct firmware * nv)180 static int brcmf_init_nvram_parser(struct nvram_parser *nvp,
181 				   const struct firmware *nv)
182 {
183 	memset(nvp, 0, sizeof(*nvp));
184 	nvp->fwnv = nv;
185 	/* Alloc for extra 0 byte + roundup by 4 + length field */
186 	nvp->nvram = kzalloc(nv->size + 1 + 3 + sizeof(u32), GFP_KERNEL);
187 	if (!nvp->nvram)
188 		return -ENOMEM;
189 
190 	nvp->line = 1;
191 	nvp->column = 1;
192 	return 0;
193 }
194 
195 /* brcmf_nvram_strip :Takes a buffer of "<var>=<value>\n" lines read from a fil
196  * and ending in a NUL. Removes carriage returns, empty lines, comment lines,
197  * and converts newlines to NULs. Shortens buffer as needed and pads with NULs.
198  * End of buffer is completed with token identifying length of buffer.
199  */
brcmf_fw_nvram_strip(const struct firmware * nv,u32 * new_length)200 static void *brcmf_fw_nvram_strip(const struct firmware *nv, u32 *new_length)
201 {
202 	struct nvram_parser nvp;
203 	u32 pad;
204 	u32 token;
205 	__le32 token_le;
206 
207 	if (brcmf_init_nvram_parser(&nvp, nv) < 0)
208 		return NULL;
209 
210 	while (nvp.pos < nv->size) {
211 		nvp.state = nv_parser_states[nvp.state](&nvp);
212 		if (nvp.state == END)
213 			break;
214 	}
215 	pad = nvp.nvram_len;
216 	*new_length = roundup(nvp.nvram_len + 1, 4);
217 	while (pad != *new_length) {
218 		nvp.nvram[pad] = 0;
219 		pad++;
220 	}
221 
222 	token = *new_length / 4;
223 	token = (~token << 16) | (token & 0x0000FFFF);
224 	token_le = cpu_to_le32(token);
225 
226 	memcpy(&nvp.nvram[*new_length], &token_le, sizeof(token_le));
227 	*new_length += sizeof(token_le);
228 
229 	return nvp.nvram;
230 }
231 
brcmf_fw_nvram_free(void * nvram)232 void brcmf_fw_nvram_free(void *nvram)
233 {
234 	kfree(nvram);
235 }
236 
237 struct brcmf_fw {
238 	struct device *dev;
239 	u16 flags;
240 	const struct firmware *code;
241 	const char *nvram_name;
242 	void (*done)(struct device *dev, const struct firmware *fw,
243 		     void *nvram_image, u32 nvram_len);
244 };
245 
brcmf_fw_request_nvram_done(const struct firmware * fw,void * ctx)246 static void brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx)
247 {
248 	struct brcmf_fw *fwctx = ctx;
249 	u32 nvram_length = 0;
250 	void *nvram = NULL;
251 
252 	brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev));
253 	if (!fw && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL))
254 		goto fail;
255 
256 	if (fw) {
257 		nvram = brcmf_fw_nvram_strip(fw, &nvram_length);
258 		release_firmware(fw);
259 		if (!nvram && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL))
260 			goto fail;
261 	}
262 
263 	fwctx->done(fwctx->dev, fwctx->code, nvram, nvram_length);
264 	kfree(fwctx);
265 	return;
266 
267 fail:
268 	brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev));
269 	release_firmware(fwctx->code);
270 	device_release_driver(fwctx->dev);
271 	kfree(fwctx);
272 }
273 
brcmf_fw_request_code_done(const struct firmware * fw,void * ctx)274 static void brcmf_fw_request_code_done(const struct firmware *fw, void *ctx)
275 {
276 	struct brcmf_fw *fwctx = ctx;
277 	int ret;
278 
279 	brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev));
280 	if (!fw)
281 		goto fail;
282 
283 	/* only requested code so done here */
284 	if (!(fwctx->flags & BRCMF_FW_REQUEST_NVRAM)) {
285 		fwctx->done(fwctx->dev, fw, NULL, 0);
286 		kfree(fwctx);
287 		return;
288 	}
289 	fwctx->code = fw;
290 	ret = request_firmware_nowait(THIS_MODULE, true, fwctx->nvram_name,
291 				      fwctx->dev, GFP_KERNEL, fwctx,
292 				      brcmf_fw_request_nvram_done);
293 
294 	if (!ret)
295 		return;
296 
297 	/* when nvram is optional call .done() callback here */
298 	if (fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL) {
299 		fwctx->done(fwctx->dev, fw, NULL, 0);
300 		kfree(fwctx);
301 		return;
302 	}
303 
304 	/* failed nvram request */
305 	release_firmware(fw);
306 fail:
307 	brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev));
308 	device_release_driver(fwctx->dev);
309 	kfree(fwctx);
310 }
311 
brcmf_fw_get_firmwares(struct device * dev,u16 flags,const char * code,const char * nvram,void (* fw_cb)(struct device * dev,const struct firmware * fw,void * nvram_image,u32 nvram_len))312 int brcmf_fw_get_firmwares(struct device *dev, u16 flags,
313 			   const char *code, const char *nvram,
314 			   void (*fw_cb)(struct device *dev,
315 					 const struct firmware *fw,
316 					 void *nvram_image, u32 nvram_len))
317 {
318 	struct brcmf_fw *fwctx;
319 
320 	brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(dev));
321 	if (!fw_cb || !code)
322 		return -EINVAL;
323 
324 	if ((flags & BRCMF_FW_REQUEST_NVRAM) && !nvram)
325 		return -EINVAL;
326 
327 	fwctx = kzalloc(sizeof(*fwctx), GFP_KERNEL);
328 	if (!fwctx)
329 		return -ENOMEM;
330 
331 	fwctx->dev = dev;
332 	fwctx->flags = flags;
333 	fwctx->done = fw_cb;
334 	if (flags & BRCMF_FW_REQUEST_NVRAM)
335 		fwctx->nvram_name = nvram;
336 
337 	return request_firmware_nowait(THIS_MODULE, true, code, dev,
338 				       GFP_KERNEL, fwctx,
339 				       brcmf_fw_request_code_done);
340 }
341