diff options
author | David Woodhouse <dwmw2@infradead.org> | 2008-05-30 13:57:27 +0300 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2008-07-10 14:47:36 +0100 |
commit | bacfe09dd7545467965e8d8f1eab20bc62dce00d (patch) | |
tree | 1f8b50e22439ef6d65089b3c5f875a6943b9c9df | |
parent | 88ecf814c47f577248751ddbe9626d98aeef5783 (diff) |
ihex.h: binary representation of ihex records
Some devices need their firmware as a set of {address, len, data...}
records in some specific order rather than a simple blob.
The normal way of doing this kind of thing is 'ihex', which is a text
format and not entirely suitable for use in the kernel.
This provides a binary representation which is very similar, but much
more compact -- and a helper routine to skip to the next record,
because the alignment constraints mean that everybody will screw it up
for themselves otherwise.
Also a helper function which can verify that a 'struct firmware'
contains a valid set of ihex records, and that following them won't run
off the end of the loaded data.
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
-rw-r--r-- | include/linux/ihex.h | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/include/linux/ihex.h b/include/linux/ihex.h new file mode 100644 index 00000000000..df89edd890a --- /dev/null +++ b/include/linux/ihex.h @@ -0,0 +1,50 @@ +/* + * Compact binary representation of ihex records. Some devices need their + * firmware loaded in strange orders rather than a single big blob, but + * actually parsing ihex-as-text within the kernel seems silly. Thus,... + */ + +#ifndef __LINUX_IHEX_H__ +#define __LINUX_IHEX_H__ + +#include <linux/types.h> +#include <linux/firmware.h> + +/* Intel HEX files actually limit the length to 256 bytes, but we have + drivers which would benefit from using separate records which are + longer than that, so we extend to 16 bits of length */ +struct ihex_binrec { + __be32 addr; + __be16 len; + uint8_t data[0]; +} __attribute__((aligned(4))); + +/* Find the next record, taking into account the 4-byte alignment */ +static inline const struct ihex_binrec * +ihex_next_binrec(const struct ihex_binrec *rec) +{ + int next = ((be16_to_cpu(rec->len) + 5) & ~3) - 2; + rec = (void *)&rec->data[next]; + + return be16_to_cpu(rec->len) ? rec : NULL; +} + +/* Check that ihex_next_binrec() won't take us off the end of the image... */ +static inline int ihex_validate_fw(const struct firmware *fw) +{ + const struct ihex_binrec *rec; + size_t ofs = 0; + + while (ofs <= fw->size - sizeof(*rec)) { + rec = (void *)&fw->data[ofs]; + + /* Zero length marks end of records */ + if (!be16_to_cpu(rec->len)) + return 0; + + /* Point to next record... */ + ofs += (sizeof(*rec) + be16_to_cpu(rec->len) + 3) & ~3; + } + return -EINVAL; +} +#endif /* __LINUX_IHEX_H__ */ |