2 * Copyright (c) 2013 Broadcom Corporation
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.
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.
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>
26 char brcmf_firmware_path
[BRCMF_FW_PATH_LEN
];
27 module_param_string(firmware_path
, brcmf_firmware_path
,
28 BRCMF_FW_PATH_LEN
, 0440);
30 enum nvram_parser_state
{
39 * struct nvram_parser - internal info for parser.
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.
51 enum nvram_parser_state state
;
52 const struct firmware
*fwnv
;
61 static bool is_nvram_char(char c
)
63 /* comment marker excluded */
67 /* key and value may have any other readable character */
68 return (c
> 0x20 && c
< 0x7f);
71 static bool is_whitespace(char c
)
73 return (c
== ' ' || c
== '\r' || c
== '\n' || c
== '\t');
76 static enum nvram_parser_state
brcmf_nvram_handle_idle(struct nvram_parser
*nvp
)
80 c
= nvp
->fwnv
->data
[nvp
->pos
];
87 if (is_nvram_char(c
)) {
88 nvp
->entry
= nvp
->pos
;
91 brcmf_dbg(INFO
, "warning: ln=%d:col=%d: ignoring invalid character\n",
92 nvp
->line
, nvp
->column
);
99 static enum nvram_parser_state
brcmf_nvram_handle_key(struct nvram_parser
*nvp
)
101 enum nvram_parser_state st
= nvp
->state
;
104 c
= nvp
->fwnv
->data
[nvp
->pos
];
106 /* ignore RAW1 by treating as comment */
107 if (strncmp(&nvp
->fwnv
->data
[nvp
->entry
], "RAW1", 4) == 0)
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
);
122 static enum nvram_parser_state
123 brcmf_nvram_handle_value(struct nvram_parser
*nvp
)
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
];
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';
148 static enum nvram_parser_state
149 brcmf_nvram_handle_comment(struct nvram_parser
*nvp
)
153 sol
= (char *)&nvp
->fwnv
->data
[nvp
->pos
];
154 eol
= strchr(sol
, '\n');
158 /* eat all moving to next line */
161 nvp
->pos
+= (eol
- sol
) + 1;
165 static enum nvram_parser_state
brcmf_nvram_handle_end(struct nvram_parser
*nvp
)
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
180 static int brcmf_init_nvram_parser(struct nvram_parser
*nvp
,
181 const struct firmware
*nv
)
183 memset(nvp
, 0, sizeof(*nvp
));
185 /* Alloc for extra 0 byte + roundup by 4 + length field */
186 nvp
->nvram
= kzalloc(nv
->size
+ 1 + 3 + sizeof(u32
), GFP_KERNEL
);
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.
200 static void *brcmf_fw_nvram_strip(const struct firmware
*nv
, u32
*new_length
)
202 struct nvram_parser nvp
;
207 if (brcmf_init_nvram_parser(&nvp
, nv
) < 0)
210 while (nvp
.pos
< nv
->size
) {
211 nvp
.state
= nv_parser_states
[nvp
.state
](&nvp
);
212 if (nvp
.state
== END
)
216 *new_length
= roundup(nvp
.nvram_len
+ 1, 4);
217 while (pad
!= *new_length
) {
222 token
= *new_length
/ 4;
223 token
= (~token
<< 16) | (token
& 0x0000FFFF);
224 token_le
= cpu_to_le32(token
);
226 memcpy(&nvp
.nvram
[*new_length
], &token_le
, sizeof(token_le
));
227 *new_length
+= sizeof(token_le
);
232 void brcmf_fw_nvram_free(void *nvram
)
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
);
246 static void brcmf_fw_request_nvram_done(const struct firmware
*fw
, void *ctx
)
248 struct brcmf_fw
*fwctx
= ctx
;
249 u32 nvram_length
= 0;
252 brcmf_dbg(TRACE
, "enter: dev=%s\n", dev_name(fwctx
->dev
));
253 if (!fw
&& !(fwctx
->flags
& BRCMF_FW_REQ_NV_OPTIONAL
))
257 nvram
= brcmf_fw_nvram_strip(fw
, &nvram_length
);
258 release_firmware(fw
);
259 if (!nvram
&& !(fwctx
->flags
& BRCMF_FW_REQ_NV_OPTIONAL
))
263 fwctx
->done(fwctx
->dev
, fwctx
->code
, nvram
, nvram_length
);
268 brcmf_dbg(TRACE
, "failed: dev=%s\n", dev_name(fwctx
->dev
));
269 release_firmware(fwctx
->code
);
270 device_release_driver(fwctx
->dev
);
274 static void brcmf_fw_request_code_done(const struct firmware
*fw
, void *ctx
)
276 struct brcmf_fw
*fwctx
= ctx
;
279 brcmf_dbg(TRACE
, "enter: dev=%s\n", dev_name(fwctx
->dev
));
283 /* only requested code so done here */
284 if (!(fwctx
->flags
& BRCMF_FW_REQUEST_NVRAM
)) {
285 fwctx
->done(fwctx
->dev
, fw
, NULL
, 0);
290 ret
= request_firmware_nowait(THIS_MODULE
, true, fwctx
->nvram_name
,
291 fwctx
->dev
, GFP_KERNEL
, fwctx
,
292 brcmf_fw_request_nvram_done
);
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);
304 /* failed nvram request */
305 release_firmware(fw
);
307 brcmf_dbg(TRACE
, "failed: dev=%s\n", dev_name(fwctx
->dev
));
308 device_release_driver(fwctx
->dev
);
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
))
318 struct brcmf_fw
*fwctx
;
320 brcmf_dbg(TRACE
, "enter: dev=%s\n", dev_name(dev
));
324 if ((flags
& BRCMF_FW_REQUEST_NVRAM
) && !nvram
)
327 fwctx
= kzalloc(sizeof(*fwctx
), GFP_KERNEL
);
332 fwctx
->flags
= flags
;
334 if (flags
& BRCMF_FW_REQUEST_NVRAM
)
335 fwctx
->nvram_name
= nvram
;
337 return request_firmware_nowait(THIS_MODULE
, true, code
, dev
,
339 brcmf_fw_request_code_done
);