2 * Copyright 2010-2011 Christian Lamparter <chunkeey@googlemail.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation version 2 of the License.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include <sys/types.h>
36 struct carlfw_file fw;
37 struct carlfw_file hdr;
39 struct list_head desc_list;
40 unsigned int desc_list_entries,
44 #define carlfw_walk_descs(iter, fw) \
45 list_for_each_entry(iter, &fw->desc_list, h.list)
47 struct carlfw_list_entry_head {
48 struct list_head list;
51 struct carlfw_list_entry {
52 struct carlfw_list_entry_head h;
54 struct carl9170fw_desc_head head;
60 static inline struct carlfw_list_entry *carlfw_desc_to_entry(struct carl9170fw_desc_head *head)
62 return container_of(head, struct carlfw_list_entry, head);
65 static inline struct carl9170fw_desc_head *carlfw_entry_to_desc(struct carlfw_list_entry *entry)
70 static void carlfw_entry_unlink(struct carlfw *fw,
71 struct carlfw_list_entry *entry)
73 fw->desc_list_entries--;
74 fw->desc_list_len -= le16_to_cpu(entry->head.length);
75 list_del(&entry->h.list);
78 static void carlfw_entry_del(struct carlfw *fw,
79 struct carlfw_list_entry *entry)
81 carlfw_entry_unlink(fw, entry);
85 static struct carlfw_list_entry *carlfw_find_entry(struct carlfw *fw,
86 const uint8_t descid[4],
88 uint8_t compatible_revision)
90 struct carlfw_list_entry *iter;
92 carlfw_walk_descs(iter, fw) {
93 if (carl9170fw_desc_cmp(&iter->head, descid, len,
101 static struct carlfw_list_entry *__carlfw_entry_add_prepare(struct carlfw *fw,
102 const struct carl9170fw_desc_head *desc)
104 struct carlfw_list_entry *tmp;
107 len = le16_to_cpu(desc->length);
109 if (len < sizeof(struct carl9170fw_desc_head))
110 return ERR_PTR(-EINVAL);
112 tmp = malloc(sizeof(*tmp) + len);
114 return ERR_PTR(-ENOMEM);
116 fw->desc_list_entries++;
117 fw->desc_list_len += len;
119 memcpy(tmp->data, desc, len);
123 static void __carlfw_release(struct carlfw_file *f)
135 void carlfw_release(struct carlfw *fw)
137 struct carlfw_list_entry *entry;
139 if (!IS_ERR_OR_NULL(fw)) {
140 while (!list_empty(&fw->desc_list)) {
141 entry = list_entry(fw->desc_list.next,
142 struct carlfw_list_entry, h.list);
143 carlfw_entry_del(fw, entry);
146 __carlfw_release(&fw->fw);
147 __carlfw_release(&fw->hdr);
152 static int __carlfw_load(struct carlfw_file *file, const char *name, const char *mode)
154 struct stat file_stat;
158 fh = fopen(name, mode);
160 return errno ? -errno : -1;
162 err = fstat(fileno(fh), &file_stat);
164 return errno ? -errno : -1;
166 file->len = file_stat.st_size;
167 file->data = malloc(file->len);
168 if (file->data == NULL)
171 err = fread(file->data, file->len, 1, fh);
175 file->name = strdup(name);
184 static void *__carlfw_find_desc(struct carlfw_file *file,
187 uint8_t compatible_revision)
190 struct carl9170fw_desc_head *tmp = NULL;
193 * Note: the last desc also has atleast a full desc_head.
194 * There's no reason for looking beyond that point.
196 scan = (file->len - 1) - (sizeof(*tmp) - CARL9170FW_MAGIC_SIZE);
198 if (file->data[scan] == descid[CARL9170FW_MAGIC_SIZE - found - 1])
203 if (found == CARL9170FW_MAGIC_SIZE)
209 if (found == CARL9170FW_MAGIC_SIZE) {
212 tmp = (void *) &file->data[scan];
213 tmp_desc_len = le16_to_cpu(tmp->length);
215 if (!CHECK_HDR_VERSION(tmp, compatible_revision) &&
216 (scan + tmp_desc_len <= file->len) && (tmp_desc_len >= len))
223 void *carlfw_find_desc(struct carlfw *fw,
224 const uint8_t descid[4],
225 const unsigned int len,
226 const uint8_t compatible_revision)
228 struct carlfw_list_entry *tmp;
230 tmp = carlfw_find_entry(fw, descid, len, compatible_revision);
232 return tmp ? carlfw_entry_to_desc(tmp) : NULL;
235 int carlfw_desc_add_tail(struct carlfw *fw,
236 const struct carl9170fw_desc_head *desc)
238 struct carlfw_list_entry *tmp;
240 tmp = __carlfw_entry_add_prepare(fw, desc);
244 list_add_tail(&tmp->h.list, &fw->desc_list);
248 int carlfw_desc_add(struct carlfw *fw,
249 const struct carl9170fw_desc_head *desc,
250 struct carl9170fw_desc_head *prev,
251 struct carl9170fw_desc_head *next)
253 struct carlfw_list_entry *tmp;
255 tmp = __carlfw_entry_add_prepare(fw, desc);
259 list_add(&tmp->h.list, &((carlfw_desc_to_entry(prev))->h.list),
260 &((carlfw_desc_to_entry(next))->h.list));
264 int carlfw_desc_add_before(struct carlfw *fw,
265 const struct carl9170fw_desc_head *desc,
266 struct carl9170fw_desc_head *pos)
268 struct carl9170fw_desc_head *prev;
269 struct carlfw_list_entry *prev_entry;
271 prev_entry = carlfw_desc_to_entry(pos);
273 prev = carlfw_entry_to_desc((struct carlfw_list_entry *) prev_entry->h.list.prev);
275 return carlfw_desc_add(fw, desc, prev, pos);
278 void carlfw_desc_unlink(struct carlfw *fw,
279 struct carl9170fw_desc_head *desc)
281 carlfw_entry_unlink(fw, carlfw_desc_to_entry(desc));
284 void carlfw_desc_del(struct carlfw *fw,
285 struct carl9170fw_desc_head *desc)
287 carlfw_entry_del(fw, carlfw_desc_to_entry(desc));
290 void *carlfw_desc_mod_len(struct carlfw *fw __unused,
291 struct carl9170fw_desc_head *desc, size_t len)
293 struct carlfw_list_entry *obj, tmp;
294 int new_len = le16_to_cpu(desc->length) + len;
296 if (new_len < (int)sizeof(*desc))
297 return ERR_PTR(-EINVAL);
299 if (new_len > CARL9170FW_DESC_MAX_LENGTH)
300 return ERR_PTR(-E2BIG);
302 obj = carlfw_desc_to_entry(desc);
304 memcpy(&tmp, obj, sizeof(tmp));
305 obj = realloc(obj, new_len + sizeof(struct carlfw_list_entry_head));
307 return ERR_PTR(-ENOMEM);
309 list_replace(&tmp.h.list, &obj->h.list);
311 desc = carlfw_entry_to_desc(obj);
312 desc->length = le16_to_cpu(new_len);
313 fw->desc_list_len += len;
318 void *carlfw_desc_next(struct carlfw *fw,
319 struct carl9170fw_desc_head *pos)
321 struct carlfw_list_entry *entry;
324 entry = (struct carlfw_list_entry *) &fw->desc_list;
326 entry = carlfw_desc_to_entry(pos);
328 if (list_at_tail(entry, &fw->desc_list, h.list))
331 entry = (struct carlfw_list_entry *) entry->h.list.next;
333 return carlfw_entry_to_desc(entry);
336 static int carlfw_parse_descs(struct carlfw *fw,
337 struct carl9170fw_otus_desc *otus_desc)
339 const struct carl9170fw_desc_head *iter = NULL;
342 carl9170fw_for_each_hdr(iter, &otus_desc->head) {
343 err = carlfw_desc_add_tail(fw, iter);
347 /* LAST is added automatically by carlfw_store */
352 #if BYTE_ORDER == LITTLE_ENDIAN
353 #define CRCPOLY_LE 0xedb88320
355 /* copied from the linux kernel */
356 static uint32_t crc32_le(uint32_t crc, unsigned char const *p, size_t len)
361 for (i = 0; i < 8; i++)
362 crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
367 #error "this tool does not work with a big endian host yet!"
370 static int carlfw_check_crc32s(struct carlfw *fw)
372 struct carl9170fw_chk_desc *chk_desc;
373 struct carlfw_list_entry *iter;
377 chk_desc = carlfw_find_desc(fw, (uint8_t *) CHK_MAGIC,
379 CARL9170FW_CHK_DESC_CUR_VER);
383 crc32 = crc32_le(~0, (void *) fw->fw.data, fw->fw.len);
384 if (crc32 != le32_to_cpu(chk_desc->fw_crc32))
387 carlfw_walk_descs(iter, fw) {
388 elen = le16_to_cpu(iter->head.length);
390 if (carl9170fw_desc_cmp(&iter->head, (uint8_t *) CHK_MAGIC,
392 CARL9170FW_CHK_DESC_CUR_VER))
395 crc32 = crc32_le(crc32, (void *) &iter->head, elen);
398 if (crc32 != le32_to_cpu(chk_desc->hdr_crc32))
404 struct carlfw *carlfw_load(const char *basename)
408 struct carl9170fw_otus_desc *otus_desc;
409 struct carl9170fw_last_desc *last_desc;
410 struct carlfw_file *hdr_file;
411 unsigned long fin, diff, off, rem;
414 fw = calloc(1, sizeof(*fw));
416 return ERR_PTR(-ENOMEM);
418 init_list_head(&fw->desc_list);
420 err = __carlfw_load(&fw->fw, basename, "r");
429 otus_desc = __carlfw_find_desc(hdr_file, (uint8_t *) OTUS_MAGIC,
431 CARL9170FW_OTUS_DESC_CUR_VER);
432 last_desc = __carlfw_find_desc(hdr_file, (uint8_t *) LAST_MAGIC,
434 CARL9170FW_LAST_DESC_CUR_VER);
436 if (!otus_desc || !last_desc ||
437 (unsigned long) otus_desc > (unsigned long) last_desc) {
442 err = carlfw_parse_descs(fw, otus_desc);
446 fin = (unsigned long)last_desc + sizeof(*last_desc);
447 diff = fin - (unsigned long)otus_desc;
448 rem = hdr_file->len - (fin - (unsigned long) hdr_file->data);
451 off = (unsigned long)otus_desc - (unsigned long)hdr_file->data;
452 memmove(&hdr_file->data[off],
453 ((uint8_t *)last_desc) + sizeof(*last_desc), rem);
456 hdr_file->len -= diff;
457 hdr_file->data = realloc(hdr_file->data, hdr_file->len);
458 if (!hdr_file->data && hdr_file->len) {
463 err = carlfw_check_crc32s(fw);
464 if (err && err != -ENODATA)
474 static int carlfw_apply_checksums(struct carlfw *fw)
476 struct carlfw_list_entry *iter;
477 struct carl9170fw_chk_desc tmp = {
478 CARL9170FW_FILL_DESC(CHK_MAGIC, sizeof(tmp),
479 CARL9170FW_CHK_DESC_MIN_VER,
480 CARL9170FW_CHK_DESC_CUR_VER) };
481 struct carl9170fw_chk_desc *chk_desc = NULL;
483 unsigned int len = 0, elen, max_len;
486 chk_desc = carlfw_find_desc(fw, (uint8_t *) CHK_MAGIC,
488 CARL9170FW_CHK_DESC_CUR_VER);
490 carlfw_desc_del(fw, &chk_desc->head);
494 max_len = fw->desc_list_len;
496 crc32 = crc32_le(~0, (void *) fw->fw.data, fw->fw.len);
497 tmp.fw_crc32 = cpu_to_le32(crc32);
502 * The descriptor checksum is seeded with the firmware's crc32.
503 * This neat trick ensures that the driver can check whenever
504 * descriptor actually belongs to the firmware, or not.
507 carlfw_walk_descs(iter, fw) {
508 elen = le16_to_cpu(iter->head.length);
510 if (max_len < len + elen)
513 crc32 = crc32_le(crc32, (void *) &iter->head, elen);
517 tmp.hdr_crc32 = cpu_to_le32(crc32);
519 err = carlfw_desc_add_tail(fw, &tmp.head);
524 int carlfw_store(struct carlfw *fw)
526 struct carl9170fw_last_desc last_desc = {
527 CARL9170FW_FILL_DESC(LAST_MAGIC, sizeof(last_desc),
528 CARL9170FW_LAST_DESC_MIN_VER,
529 CARL9170FW_LAST_DESC_CUR_VER) };
531 struct carlfw_list_entry *iter;
535 err = carlfw_apply_checksums(fw);
539 fh = fopen(fw->fw.name, "w");
543 err = fwrite(fw->fw.data, fw->fw.len, 1, fh);
552 fh = fopen(fw->hdr.name, "w");
555 carlfw_walk_descs(iter, fw) {
556 elen = le16_to_cpu(iter->head.length);
558 if (elen > CARL9170FW_DESC_MAX_LENGTH) {
563 err = fwrite(iter->data, elen, 1, fh);
570 err = fwrite(&last_desc, sizeof(last_desc), 1, fh);
583 void *carlfw_mod_tailroom(struct carlfw *fw, ssize_t len)
588 new_len = fw->fw.len + len;
590 if (!carl9170fw_size_check(new_len))
591 return ERR_PTR(-EINVAL);
593 buf = realloc(fw->fw.data, new_len);
595 return ERR_PTR(-ENOMEM);
597 fw->fw.len = new_len;
599 return &fw->fw.data[new_len - len];
602 void *carlfw_mod_headroom(struct carlfw *fw, ssize_t len)
607 new_len = fw->fw.len + len;
608 if (!carl9170fw_size_check(new_len))
609 return ERR_PTR(-EINVAL);
612 memmove(fw->fw.data, &fw->fw.data[len], new_len);
614 ptr = carlfw_mod_tailroom(fw, len);
615 if (IS_ERR_OR_NULL(ptr))
619 memmove(&fw->fw.data[len], &fw->fw.data[0], new_len - len);
624 void *carlfw_get_fw(struct carlfw *fw, size_t *len)
630 unsigned int carlfw_get_descs_num(struct carlfw *fw)
632 return fw->desc_list_entries;
635 unsigned int carlfw_get_descs_size(struct carlfw *fw)
637 return fw->desc_list_len;