diff options
Diffstat (limited to 'target/linux')
-rw-r--r-- | target/linux/ar71xx/files/arch/mips/ath79/routerboot.c | 129 | ||||
-rw-r--r-- | target/linux/ar71xx/files/arch/mips/ath79/routerboot.h | 24 |
2 files changed, 153 insertions, 0 deletions
diff --git a/target/linux/ar71xx/files/arch/mips/ath79/routerboot.c b/target/linux/ar71xx/files/arch/mips/ath79/routerboot.c index 1cb1f9d4eb..dbdec02056 100644 --- a/target/linux/ar71xx/files/arch/mips/ath79/routerboot.c +++ b/target/linux/ar71xx/files/arch/mips/ath79/routerboot.c @@ -8,12 +8,21 @@ * by the Free Software Foundation. */ +#define pr_fmt(fmt) "rb: " fmt + #include <linux/kernel.h> +#include <linux/slab.h> #include <linux/errno.h> #include <linux/routerboot.h> +#include <linux/rle.h> #include "routerboot.h" +#define RB_BLOCK_SIZE 0x1000 +#define RB_ART_SIZE 0x10000 + +static struct rb_info rb_info; + static u32 get_u32(void *buf) { u8 *p = buf; @@ -118,3 +127,123 @@ routerboot_find_tag(u8 *buf, unsigned int buflen, u16 tag_id, return ret; } + +static inline int +rb_find_hard_cfg_tag(u16 tag_id, u8 **tag_data, u16 *tag_len) +{ + if (!rb_info.hard_cfg_data || + !rb_info.hard_cfg_size) + return -ENOENT; + + return routerboot_find_tag(rb_info.hard_cfg_data, + rb_info.hard_cfg_size, + tag_id, tag_data, tag_len); +} + +__init const char * +rb_get_board_name(void) +{ + u16 tag_len; + u8 *tag; + int err; + + err = rb_find_hard_cfg_tag(RB_ID_BOARD_NAME, &tag, &tag_len); + if (err) + return NULL; + + return tag; +} + +__init u32 +rb_get_hw_options(void) +{ + u16 tag_len; + u8 *tag; + int err; + + err = rb_find_hard_cfg_tag(RB_ID_HW_OPTIONS, &tag, &tag_len); + if (err) + return 0; + + return get_u32(tag); +} + +__init void * +rb_get_wlan_data(void) +{ + u16 tag_len; + u8 *tag; + void *buf; + int err; + + err = rb_find_hard_cfg_tag(RB_ID_WLAN_DATA, &tag, &tag_len); + if (err) { + pr_err("no calibration data found\n"); + goto err; + } + + buf = kmalloc(RB_ART_SIZE, GFP_KERNEL); + if (buf == NULL) { + pr_err("no memory for calibration data\n"); + goto err; + } + + err = rle_decode((char *) tag, tag_len, buf, RB_ART_SIZE, + NULL, NULL); + if (err) { + pr_err("unable to decode calibration data\n"); + goto err_free; + } + + return buf; + +err_free: + kfree(buf); +err: + return NULL; +} + +__init const struct rb_info * +rb_init_info(void *data, unsigned int size) +{ + unsigned int offset; + + if (size == 0 || (size % RB_BLOCK_SIZE) != 0) + return NULL; + + for (offset = 0; offset < size; offset += RB_BLOCK_SIZE) { + u32 magic; + + magic = get_u32(data + offset); + switch (magic) { + case RB_MAGIC_HARD: + rb_info.hard_cfg_offs = offset; + break; + + case RB_MAGIC_SOFT: + rb_info.soft_cfg_offs = offset; + break; + } + } + + if (!rb_info.hard_cfg_offs) { + pr_err("could not find a valid RouterBOOT hard config\n"); + return NULL; + } + + if (!rb_info.soft_cfg_offs) { + pr_err("could not find a valid RouterBOOT soft config\n"); + return NULL; + } + + rb_info.hard_cfg_size = RB_BLOCK_SIZE; + rb_info.hard_cfg_data = kmemdup(data + rb_info.hard_cfg_offs, + RB_BLOCK_SIZE, GFP_KERNEL); + if (!rb_info.hard_cfg_data) + return NULL; + + rb_info.board_name = rb_get_board_name(); + rb_info.hw_options = rb_get_hw_options(); + + return &rb_info; +} diff --git a/target/linux/ar71xx/files/arch/mips/ath79/routerboot.h b/target/linux/ar71xx/files/arch/mips/ath79/routerboot.h index 2489e0aee0..6ec296afd4 100644 --- a/target/linux/ar71xx/files/arch/mips/ath79/routerboot.h +++ b/target/linux/ar71xx/files/arch/mips/ath79/routerboot.h @@ -11,11 +11,35 @@ #ifndef _ATH79_ROUTERBOOT_H_ #define _ATH79_ROUTERBOOT_H_ +struct rb_info { + unsigned int hard_cfg_offs; + unsigned int hard_cfg_size; + void *hard_cfg_data; + unsigned int soft_cfg_offs; + + const char *board_name; + u32 hw_options; +}; + #ifdef CONFIG_ATH79_ROUTERBOOT +const struct rb_info *rb_init_info(void *data, unsigned int size); +void *rb_get_wlan_data(void); + int routerboot_find_tag(u8 *buf, unsigned int buflen, u16 tag_id, u8 **tag_data, u16 *tag_len); int routerboot_find_magic(u8 *buf, unsigned int buflen, u32 *offset, bool hard); #else +static inline const struct rb_info * +rb_init_info(void *data, unsigned int size) +{ + return NULL; +} + +static inline void *rb_get_wlan_data(void) +{ + return NULL; +} + static inline int routerboot_find_tag(u8 *buf, unsigned int buflen, u16 tag_id, u8 **tag_data, u16 *tag_len) |