+static int brcmsmac_name_to_idx(const char *name)
+{
+ if (strcmp("lcn0bsinitvals24", name) == 0) {
+ return D11LCN0BSINITVALS24;
+ } else if (strcmp("lcn0initvals24", name) == 0) {
+ return D11LCN0INITVALS24;
+ } else if (strcmp("lcn1bsinitvals24", name) == 0) {
+ return D11LCN1BSINITVALS24;
+ } else if (strcmp("lcn1initvals24", name) == 0) {
+ return D11LCN1INITVALS24;
+ } else if (strcmp("lcn2bsinitvals24", name) == 0) {
+ return D11LCN2BSINITVALS24;
+ } else if (strcmp("lcn2initvals24", name) == 0) {
+ return D11LCN2INITVALS24;
+ } else if (strcmp("n0absinitvals16", name) == 0) {
+ return D11N0ABSINITVALS16;
+ } else if (strcmp("n0bsinitvals16", name) == 0) {
+ return D11N0BSINITVALS16;
+ } else if (strcmp("n0initvals16", name) == 0) {
+ return D11N0INITVALS16;
+ } else if (strcmp("ucode16_mimo", name) == 0) {
+ return D11UCODE_OVERSIGHT16_MIMO;
+ } else if (strcmp("ucode24_lcn", name) == 0) {
+ return D11UCODE_OVERSIGHT24_LCN;
+ }
+ return 0;
+}
+
+static int brcmsmac_name_to_size_idx(const char *name)
+{
+ if (strcmp("ucode16_mimo", name) == 0) {
+ return D11UCODE_OVERSIGHT16_MIMOSZ;
+ } else if (strcmp("ucode24_lcn", name) == 0) {
+ return D11UCODE_OVERSIGHT24_LCNSZ;
+ }
+ return 0;
+}
+
+static void brcmsmac_clear_file(void)
+{
+ FILE *f;
+ char nbuf[4096];
+ int r;
+
+ r = snprintf(nbuf, sizeof(nbuf),
+ "%s/brcm", cmdargs.target_dir);
+ if (r >= sizeof(nbuf)) {
+ fprintf(stderr, "name too long");
+ exit(2);
+ }
+
+ r = mkdir(nbuf, 0770);
+ if (r && errno != EEXIST) {
+ perror("failed to create output directory");
+ exit(2);
+ }
+
+ r = snprintf(nbuf, sizeof(nbuf),
+ "%s/brcm/bcm43xx-0.fw", cmdargs.target_dir);
+ if (r >= sizeof(nbuf)) {
+ fprintf(stderr, "name too long");
+ exit(2);
+ }
+ f = fopen(nbuf, "w");
+ if (!f) {
+ perror("failed to open data file");
+ exit(2);
+ }
+ fclose(f);
+
+ r = snprintf(nbuf, sizeof(nbuf),
+ "%s/brcm/bcm43xx_hdr-0.fw", cmdargs.target_dir);
+ if (r >= sizeof(nbuf)) {
+ fprintf(stderr, "name too long");
+ exit(2);
+ }
+ f = fopen(nbuf, "w");
+ fclose(f);
+}
+
+static void brcmsmac_write_file(int idx, uint8_t *buf, uint32_t len)
+{
+ FILE *f;
+ FILE *h;
+ char nbuf[4096];
+ int r;
+ int offset;
+ struct firmware_hdr fw_hdr;
+
+ r = snprintf(nbuf, sizeof(nbuf),
+ "%s/brcm/bcm43xx-0.fw", cmdargs.target_dir);
+ if (r >= sizeof(nbuf)) {
+ fprintf(stderr, "name too long");
+ exit(2);
+ }
+ f = fopen(nbuf, "a");
+ if (!f) {
+ perror("failed to open data file");
+ exit(2);
+ }
+ fseek(f, 0L, SEEK_END);
+
+ r = snprintf(nbuf, sizeof(nbuf),
+ "%s/brcm/bcm43xx_hdr-0.fw", cmdargs.target_dir);
+ if (r >= sizeof(nbuf)) {
+ fprintf(stderr, "name too long");
+ exit(2);
+ }
+ h = fopen(nbuf, "a");
+ if (!h) {
+ perror("failed to open header file");
+ exit(2);
+ }
+ fseek(h, 0L, SEEK_END);
+
+ offset = ftell(f);
+
+ fw_hdr.offset = to_le32(offset);
+ fw_hdr.len = to_le32(len);
+ fw_hdr.idx = to_le32(idx);
+
+ if (fwrite(&fw_hdr, sizeof(fw_hdr), 1, h) != 1) {
+ perror("failed to write file");
+ exit(2);
+ }
+ fclose(h);
+ if (fwrite(buf, 1, len, f) != len) {
+ perror("failed to write file");
+ exit(2);
+ }
+ fclose(f);
+}
+
+static void brcmsmac_add_dummy_entries(void)
+{
+ uint8_t buf[4] = {0};
+
+ brcmsmac_write_file(D11N0ABSINITVALS16, buf, 4);
+ brcmsmac_write_file(D11UCODE_OVERSIGHT_BOMMAJOR, buf, 4);
+ brcmsmac_write_file(D11UCODE_OVERSIGHT_BOMMINOR, buf, 4);
+}
+
+static void brcmsmac_extract(FILE *f, const struct extract *extract,
+ uint32_t flags)
+{
+ uint8_t *buf;
+ size_t data_length;
+ int ucode_rev = 0;
+ int brcmsmac_idx = 0;
+ be32_t size;
+
+
+ brcmsmac_idx = brcmsmac_name_to_idx(extract->name);
+ if (!brcmsmac_idx)
+ return;
+ printf("%s %s\n",
+ cmdargs.mode == FWCM_IDENTIFY ? "Contains" : "Extracting",
+ extract->name);
+
+ buf = read_object(f, extract);
+
+ switch (extract->type) {
+ case EXT_UCODE_3:
+ ucode_rev += 1;
+ case EXT_UCODE_2:
+ ucode_rev += 1;
+ case EXT_UCODE_1:
+ ucode_rev += 1;
+ data_length = extract->length;
+ if (flags & FW_FLAG_LE)
+ swap_endianness_ucode(buf, data_length);
+ analyse_ucode(ucode_rev, buf, data_length);
+ swap_endianness_ucode(buf, data_length);
+ size = to_le32(data_length);
+ break;
+ case EXT_PCM:
+ data_length = extract->length;
+ if (!(flags & FW_FLAG_LE))
+ swap_endianness_pcm(buf, data_length);
+ size = to_le32(data_length);
+ break;
+ case EXT_IV: {
+ data_length = extract->length;
+ if (!(flags & FW_FLAG_LE)) {
+ struct iv *in = (struct iv *)buf;
+ int i;
+
+ for (i = 0; i < data_length / sizeof(struct iv); i++, in++)
+ swap_endianness_iv(in);
+ }
+ size = to_le32(data_length);
+ break;
+ }
+ default:
+ exit(255);
+ }
+
+ brcmsmac_write_file(brcmsmac_idx, buf, data_length);
+ int size_idx = brcmsmac_name_to_size_idx(extract->name);
+ if (size_idx)
+ brcmsmac_write_file(size_idx, (uint8_t *)&size, 4);
+
+ free(buf);
+}
+