1a6b396f4SSakari Ailus // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2a6b396f4SSakari Ailus /* 3a6b396f4SSakari Ailus * CCS static data binary parser library 4a6b396f4SSakari Ailus * 5a6b396f4SSakari Ailus * Copyright 2019--2020 Intel Corporation 6a6b396f4SSakari Ailus */ 7a6b396f4SSakari Ailus 8a6b396f4SSakari Ailus #include <linux/device.h> 9a6b396f4SSakari Ailus #include <linux/errno.h> 10a6b396f4SSakari Ailus #include <linux/limits.h> 11a6b396f4SSakari Ailus #include <linux/mm.h> 12a6b396f4SSakari Ailus #include <linux/slab.h> 13a6b396f4SSakari Ailus #include <linux/types.h> 14a6b396f4SSakari Ailus 15a6b396f4SSakari Ailus #include "ccs-data-defs.h" 16a6b396f4SSakari Ailus 17a6b396f4SSakari Ailus struct bin_container { 18a6b396f4SSakari Ailus void *base; 19a6b396f4SSakari Ailus void *now; 20a6b396f4SSakari Ailus void *end; 21a6b396f4SSakari Ailus size_t size; 22a6b396f4SSakari Ailus }; 23a6b396f4SSakari Ailus 24a6b396f4SSakari Ailus static void *bin_alloc(struct bin_container *bin, size_t len) 25a6b396f4SSakari Ailus { 26a6b396f4SSakari Ailus void *ptr; 27a6b396f4SSakari Ailus 28a6b396f4SSakari Ailus len = ALIGN(len, 8); 29a6b396f4SSakari Ailus 30a6b396f4SSakari Ailus if (bin->end - bin->now < len) 31a6b396f4SSakari Ailus return NULL; 32a6b396f4SSakari Ailus 33a6b396f4SSakari Ailus ptr = bin->now; 34a6b396f4SSakari Ailus bin->now += len; 35a6b396f4SSakari Ailus 36a6b396f4SSakari Ailus return ptr; 37a6b396f4SSakari Ailus } 38a6b396f4SSakari Ailus 39a6b396f4SSakari Ailus static void bin_reserve(struct bin_container *bin, size_t len) 40a6b396f4SSakari Ailus { 41a6b396f4SSakari Ailus bin->size += ALIGN(len, 8); 42a6b396f4SSakari Ailus } 43a6b396f4SSakari Ailus 44a6b396f4SSakari Ailus static int bin_backing_alloc(struct bin_container *bin) 45a6b396f4SSakari Ailus { 46a6b396f4SSakari Ailus bin->base = bin->now = kvzalloc(bin->size, GFP_KERNEL); 47a6b396f4SSakari Ailus if (!bin->base) 48a6b396f4SSakari Ailus return -ENOMEM; 49a6b396f4SSakari Ailus 50a6b396f4SSakari Ailus bin->end = bin->base + bin->size; 51a6b396f4SSakari Ailus 52a6b396f4SSakari Ailus return 0; 53a6b396f4SSakari Ailus } 54a6b396f4SSakari Ailus 55a6b396f4SSakari Ailus #define is_contained(var, endp) \ 56a6b396f4SSakari Ailus (sizeof(*var) <= (endp) - (void *)(var)) 57a6b396f4SSakari Ailus #define has_headroom(ptr, headroom, endp) \ 58a6b396f4SSakari Ailus ((headroom) <= (endp) - (void *)(ptr)) 59a6b396f4SSakari Ailus #define is_contained_with_headroom(var, headroom, endp) \ 60a6b396f4SSakari Ailus (sizeof(*var) + (headroom) <= (endp) - (void *)(var)) 61a6b396f4SSakari Ailus 62a6b396f4SSakari Ailus static int 63a6b396f4SSakari Ailus ccs_data_parse_length_specifier(const struct __ccs_data_length_specifier *__len, 64a6b396f4SSakari Ailus size_t *__hlen, size_t *__plen, 65a6b396f4SSakari Ailus const void *endp) 66a6b396f4SSakari Ailus { 67a6b396f4SSakari Ailus size_t hlen, plen; 68a6b396f4SSakari Ailus 69a6b396f4SSakari Ailus if (!is_contained(__len, endp)) 70a6b396f4SSakari Ailus return -ENODATA; 71a6b396f4SSakari Ailus 72a6b396f4SSakari Ailus switch (__len->length >> CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) { 73a6b396f4SSakari Ailus case CCS_DATA_LENGTH_SPECIFIER_1: 74a6b396f4SSakari Ailus hlen = sizeof(*__len); 75a6b396f4SSakari Ailus plen = __len->length & 76a6b396f4SSakari Ailus ((1 << CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) - 1); 77a6b396f4SSakari Ailus break; 78a6b396f4SSakari Ailus case CCS_DATA_LENGTH_SPECIFIER_2: { 79a6b396f4SSakari Ailus struct __ccs_data_length_specifier2 *__len2 = (void *)__len; 80a6b396f4SSakari Ailus 81a6b396f4SSakari Ailus if (!is_contained(__len2, endp)) 82a6b396f4SSakari Ailus return -ENODATA; 83a6b396f4SSakari Ailus 84a6b396f4SSakari Ailus hlen = sizeof(*__len2); 85a6b396f4SSakari Ailus plen = ((size_t) 86a6b396f4SSakari Ailus (__len2->length[0] & 87a6b396f4SSakari Ailus ((1 << CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) - 1)) 88a6b396f4SSakari Ailus << 8) + __len2->length[1]; 89a6b396f4SSakari Ailus break; 90a6b396f4SSakari Ailus } 91a6b396f4SSakari Ailus case CCS_DATA_LENGTH_SPECIFIER_3: { 92a6b396f4SSakari Ailus struct __ccs_data_length_specifier3 *__len3 = (void *)__len; 93a6b396f4SSakari Ailus 94a6b396f4SSakari Ailus if (!is_contained(__len3, endp)) 95a6b396f4SSakari Ailus return -ENODATA; 96a6b396f4SSakari Ailus 97a6b396f4SSakari Ailus hlen = sizeof(*__len3); 98a6b396f4SSakari Ailus plen = ((size_t) 99a6b396f4SSakari Ailus (__len3->length[0] & 100a6b396f4SSakari Ailus ((1 << CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) - 1)) 101a6b396f4SSakari Ailus << 16) + (__len3->length[0] << 8) + __len3->length[1]; 102a6b396f4SSakari Ailus break; 103a6b396f4SSakari Ailus } 104a6b396f4SSakari Ailus default: 105a6b396f4SSakari Ailus return -EINVAL; 106a6b396f4SSakari Ailus } 107a6b396f4SSakari Ailus 108a6b396f4SSakari Ailus if (!has_headroom(__len, hlen + plen, endp)) 109a6b396f4SSakari Ailus return -ENODATA; 110a6b396f4SSakari Ailus 111a6b396f4SSakari Ailus *__hlen = hlen; 112a6b396f4SSakari Ailus *__plen = plen; 113a6b396f4SSakari Ailus 114a6b396f4SSakari Ailus return 0; 115a6b396f4SSakari Ailus } 116a6b396f4SSakari Ailus 117a6b396f4SSakari Ailus static u8 118a6b396f4SSakari Ailus ccs_data_parse_format_version(const struct __ccs_data_block *block) 119a6b396f4SSakari Ailus { 120a6b396f4SSakari Ailus return block->id >> CCS_DATA_BLOCK_HEADER_ID_VERSION_SHIFT; 121a6b396f4SSakari Ailus } 122a6b396f4SSakari Ailus 123a6b396f4SSakari Ailus static u8 ccs_data_parse_block_id(const struct __ccs_data_block *block, 124a6b396f4SSakari Ailus bool is_first) 125a6b396f4SSakari Ailus { 126a6b396f4SSakari Ailus if (!is_first) 127a6b396f4SSakari Ailus return block->id; 128a6b396f4SSakari Ailus 129a6b396f4SSakari Ailus return block->id & ((1 << CCS_DATA_BLOCK_HEADER_ID_VERSION_SHIFT) - 1); 130a6b396f4SSakari Ailus } 131a6b396f4SSakari Ailus 132a6b396f4SSakari Ailus static int ccs_data_parse_version(struct bin_container *bin, 133a6b396f4SSakari Ailus struct ccs_data_container *ccsdata, 134a6b396f4SSakari Ailus const void *payload, const void *endp) 135a6b396f4SSakari Ailus { 136a6b396f4SSakari Ailus const struct __ccs_data_block_version *v = payload; 137a6b396f4SSakari Ailus struct ccs_data_block_version *vv; 138a6b396f4SSakari Ailus 139a6b396f4SSakari Ailus if (v + 1 != endp) 140a6b396f4SSakari Ailus return -ENODATA; 141a6b396f4SSakari Ailus 142a6b396f4SSakari Ailus if (!bin->base) { 143a6b396f4SSakari Ailus bin_reserve(bin, sizeof(*ccsdata->version)); 144a6b396f4SSakari Ailus return 0; 145a6b396f4SSakari Ailus } 146a6b396f4SSakari Ailus 147a6b396f4SSakari Ailus ccsdata->version = bin_alloc(bin, sizeof(*ccsdata->version)); 148a6b396f4SSakari Ailus if (!ccsdata->version) 149a6b396f4SSakari Ailus return -ENOMEM; 150a6b396f4SSakari Ailus 151a6b396f4SSakari Ailus vv = ccsdata->version; 152a6b396f4SSakari Ailus vv->version_major = ((u16)v->static_data_version_major[0] << 8) + 153a6b396f4SSakari Ailus v->static_data_version_major[1]; 154a6b396f4SSakari Ailus vv->version_minor = ((u16)v->static_data_version_minor[0] << 8) + 155*1bc0b1baSSakari Ailus v->static_data_version_minor[1]; 156a6b396f4SSakari Ailus vv->date_year = ((u16)v->year[0] << 8) + v->year[1]; 157a6b396f4SSakari Ailus vv->date_month = v->month; 158a6b396f4SSakari Ailus vv->date_day = v->day; 159a6b396f4SSakari Ailus 160a6b396f4SSakari Ailus return 0; 161a6b396f4SSakari Ailus } 162a6b396f4SSakari Ailus 163a6b396f4SSakari Ailus static void print_ccs_data_version(struct device *dev, 164a6b396f4SSakari Ailus struct ccs_data_block_version *v) 165a6b396f4SSakari Ailus { 166a6b396f4SSakari Ailus dev_dbg(dev, 167a6b396f4SSakari Ailus "static data version %4.4x.%4.4x, date %4.4u-%2.2u-%2.2u\n", 168a6b396f4SSakari Ailus v->version_major, v->version_minor, 169a6b396f4SSakari Ailus v->date_year, v->date_month, v->date_day); 170a6b396f4SSakari Ailus } 171a6b396f4SSakari Ailus 172a6b396f4SSakari Ailus static int ccs_data_block_parse_header(const struct __ccs_data_block *block, 173a6b396f4SSakari Ailus bool is_first, unsigned int *__block_id, 174a6b396f4SSakari Ailus const void **payload, 175a6b396f4SSakari Ailus const struct __ccs_data_block **next_block, 176a6b396f4SSakari Ailus const void *endp, struct device *dev, 177a6b396f4SSakari Ailus bool verbose) 178a6b396f4SSakari Ailus { 179a6b396f4SSakari Ailus size_t plen, hlen; 180a6b396f4SSakari Ailus u8 block_id; 181a6b396f4SSakari Ailus int rval; 182a6b396f4SSakari Ailus 183a6b396f4SSakari Ailus if (!is_contained(block, endp)) 184a6b396f4SSakari Ailus return -ENODATA; 185a6b396f4SSakari Ailus 186a6b396f4SSakari Ailus rval = ccs_data_parse_length_specifier(&block->length, &hlen, &plen, 187a6b396f4SSakari Ailus endp); 188a6b396f4SSakari Ailus if (rval < 0) 189a6b396f4SSakari Ailus return rval; 190a6b396f4SSakari Ailus 191a6b396f4SSakari Ailus block_id = ccs_data_parse_block_id(block, is_first); 192a6b396f4SSakari Ailus 193a6b396f4SSakari Ailus if (verbose) 194a6b396f4SSakari Ailus dev_dbg(dev, 195a6b396f4SSakari Ailus "Block ID 0x%2.2x, header length %zu, payload length %zu\n", 196a6b396f4SSakari Ailus block_id, hlen, plen); 197a6b396f4SSakari Ailus 198a6b396f4SSakari Ailus if (!has_headroom(&block->length, hlen + plen, endp)) 199a6b396f4SSakari Ailus return -ENODATA; 200a6b396f4SSakari Ailus 201a6b396f4SSakari Ailus if (__block_id) 202a6b396f4SSakari Ailus *__block_id = block_id; 203a6b396f4SSakari Ailus 204a6b396f4SSakari Ailus if (payload) 205a6b396f4SSakari Ailus *payload = (void *)&block->length + hlen; 206a6b396f4SSakari Ailus 207a6b396f4SSakari Ailus if (next_block) 208a6b396f4SSakari Ailus *next_block = (void *)&block->length + hlen + plen; 209a6b396f4SSakari Ailus 210a6b396f4SSakari Ailus return 0; 211a6b396f4SSakari Ailus } 212a6b396f4SSakari Ailus 213a6b396f4SSakari Ailus static int ccs_data_parse_regs(struct bin_container *bin, 214a6b396f4SSakari Ailus struct ccs_reg **__regs, 215a6b396f4SSakari Ailus size_t *__num_regs, const void *payload, 216a6b396f4SSakari Ailus const void *endp, struct device *dev) 217a6b396f4SSakari Ailus { 218a6b396f4SSakari Ailus struct ccs_reg *regs_base, *regs; 219a6b396f4SSakari Ailus size_t num_regs = 0; 220a6b396f4SSakari Ailus u16 addr = 0; 221a6b396f4SSakari Ailus 222a6b396f4SSakari Ailus if (bin->base && __regs) { 223a6b396f4SSakari Ailus regs = regs_base = bin_alloc(bin, sizeof(*regs) * *__num_regs); 224a6b396f4SSakari Ailus if (!regs) 225a6b396f4SSakari Ailus return -ENOMEM; 226a6b396f4SSakari Ailus } 227a6b396f4SSakari Ailus 228a6b396f4SSakari Ailus while (payload < endp && num_regs < INT_MAX) { 229a6b396f4SSakari Ailus const struct __ccs_data_block_regs *r = payload; 230a6b396f4SSakari Ailus size_t len; 231a6b396f4SSakari Ailus const void *data; 232a6b396f4SSakari Ailus 233a6b396f4SSakari Ailus if (!is_contained(r, endp)) 234a6b396f4SSakari Ailus return -ENODATA; 235a6b396f4SSakari Ailus 236a6b396f4SSakari Ailus switch (r->reg_len >> CCS_DATA_BLOCK_REGS_SEL_SHIFT) { 237a6b396f4SSakari Ailus case CCS_DATA_BLOCK_REGS_SEL_REGS: 238a6b396f4SSakari Ailus addr += r->reg_len & CCS_DATA_BLOCK_REGS_ADDR_MASK; 239a6b396f4SSakari Ailus len = ((r->reg_len & CCS_DATA_BLOCK_REGS_LEN_MASK) 240a6b396f4SSakari Ailus >> CCS_DATA_BLOCK_REGS_LEN_SHIFT) + 1; 241a6b396f4SSakari Ailus 242a6b396f4SSakari Ailus if (!is_contained_with_headroom(r, len, endp)) 243a6b396f4SSakari Ailus return -ENODATA; 244a6b396f4SSakari Ailus 245a6b396f4SSakari Ailus data = r + 1; 246a6b396f4SSakari Ailus break; 247a6b396f4SSakari Ailus case CCS_DATA_BLOCK_REGS_SEL_REGS2: { 248a6b396f4SSakari Ailus const struct __ccs_data_block_regs2 *r2 = payload; 249a6b396f4SSakari Ailus 250a6b396f4SSakari Ailus if (!is_contained(r2, endp)) 251a6b396f4SSakari Ailus return -ENODATA; 252a6b396f4SSakari Ailus 253a6b396f4SSakari Ailus addr += ((u16)(r2->reg_len & 254a6b396f4SSakari Ailus CCS_DATA_BLOCK_REGS_2_ADDR_MASK) << 8) 255a6b396f4SSakari Ailus + r2->addr; 256a6b396f4SSakari Ailus len = ((r2->reg_len & CCS_DATA_BLOCK_REGS_2_LEN_MASK) 257a6b396f4SSakari Ailus >> CCS_DATA_BLOCK_REGS_2_LEN_SHIFT) + 1; 258a6b396f4SSakari Ailus 259a6b396f4SSakari Ailus if (!is_contained_with_headroom(r2, len, endp)) 260a6b396f4SSakari Ailus return -ENODATA; 261a6b396f4SSakari Ailus 262a6b396f4SSakari Ailus data = r2 + 1; 263a6b396f4SSakari Ailus break; 264a6b396f4SSakari Ailus } 265a6b396f4SSakari Ailus case CCS_DATA_BLOCK_REGS_SEL_REGS3: { 266a6b396f4SSakari Ailus const struct __ccs_data_block_regs3 *r3 = payload; 267a6b396f4SSakari Ailus 268a6b396f4SSakari Ailus if (!is_contained(r3, endp)) 269a6b396f4SSakari Ailus return -ENODATA; 270a6b396f4SSakari Ailus 271a6b396f4SSakari Ailus addr = ((u16)r3->addr[0] << 8) + r3->addr[1]; 272a6b396f4SSakari Ailus len = (r3->reg_len & CCS_DATA_BLOCK_REGS_3_LEN_MASK) + 1; 273a6b396f4SSakari Ailus 274a6b396f4SSakari Ailus if (!is_contained_with_headroom(r3, len, endp)) 275a6b396f4SSakari Ailus return -ENODATA; 276a6b396f4SSakari Ailus 277a6b396f4SSakari Ailus data = r3 + 1; 278a6b396f4SSakari Ailus break; 279a6b396f4SSakari Ailus } 280a6b396f4SSakari Ailus default: 281a6b396f4SSakari Ailus return -EINVAL; 282a6b396f4SSakari Ailus } 283a6b396f4SSakari Ailus 284a6b396f4SSakari Ailus num_regs++; 285a6b396f4SSakari Ailus 286a6b396f4SSakari Ailus if (!bin->base) { 287a6b396f4SSakari Ailus bin_reserve(bin, len); 288a6b396f4SSakari Ailus } else if (__regs) { 289a6b396f4SSakari Ailus regs->addr = addr; 290a6b396f4SSakari Ailus regs->len = len; 291a6b396f4SSakari Ailus regs->value = bin_alloc(bin, len); 292a6b396f4SSakari Ailus if (!regs->value) 293a6b396f4SSakari Ailus return -ENOMEM; 294a6b396f4SSakari Ailus 295a6b396f4SSakari Ailus memcpy(regs->value, data, len); 296a6b396f4SSakari Ailus regs++; 297a6b396f4SSakari Ailus } 298a6b396f4SSakari Ailus 299a6b396f4SSakari Ailus addr += len; 300a6b396f4SSakari Ailus payload = data + len; 301a6b396f4SSakari Ailus } 302a6b396f4SSakari Ailus 303a6b396f4SSakari Ailus if (!bin->base) 304a6b396f4SSakari Ailus bin_reserve(bin, sizeof(*regs) * num_regs); 305a6b396f4SSakari Ailus 306a6b396f4SSakari Ailus if (__num_regs) 307a6b396f4SSakari Ailus *__num_regs = num_regs; 308a6b396f4SSakari Ailus 309a6b396f4SSakari Ailus if (bin->base && __regs) 310a6b396f4SSakari Ailus *__regs = regs_base; 311a6b396f4SSakari Ailus 312a6b396f4SSakari Ailus return 0; 313a6b396f4SSakari Ailus } 314a6b396f4SSakari Ailus 315a6b396f4SSakari Ailus static int ccs_data_parse_reg_rules(struct bin_container *bin, 316a6b396f4SSakari Ailus struct ccs_reg **__regs, 317a6b396f4SSakari Ailus size_t *__num_regs, 318a6b396f4SSakari Ailus const void *payload, 319a6b396f4SSakari Ailus const void *endp, struct device *dev) 320a6b396f4SSakari Ailus { 321a6b396f4SSakari Ailus int rval; 322a6b396f4SSakari Ailus 323a6b396f4SSakari Ailus if (!bin->base) 324a6b396f4SSakari Ailus return ccs_data_parse_regs(bin, NULL, NULL, payload, endp, dev); 325a6b396f4SSakari Ailus 326a6b396f4SSakari Ailus rval = ccs_data_parse_regs(bin, NULL, __num_regs, payload, endp, dev); 327a6b396f4SSakari Ailus if (rval) 328a6b396f4SSakari Ailus return rval; 329a6b396f4SSakari Ailus 330a6b396f4SSakari Ailus return ccs_data_parse_regs(bin, __regs, __num_regs, payload, endp, 331a6b396f4SSakari Ailus dev); 332a6b396f4SSakari Ailus } 333a6b396f4SSakari Ailus 334a6b396f4SSakari Ailus static void assign_ffd_entry(struct ccs_frame_format_desc *desc, 335a6b396f4SSakari Ailus const struct __ccs_data_block_ffd_entry *ent) 336a6b396f4SSakari Ailus { 337a6b396f4SSakari Ailus desc->pixelcode = ent->pixelcode; 338a6b396f4SSakari Ailus desc->value = ((u16)ent->value[0] << 8) + ent->value[1]; 339a6b396f4SSakari Ailus } 340a6b396f4SSakari Ailus 341a6b396f4SSakari Ailus static int ccs_data_parse_ffd(struct bin_container *bin, 342a6b396f4SSakari Ailus struct ccs_frame_format_descs **ffd, 343a6b396f4SSakari Ailus const void *payload, 344a6b396f4SSakari Ailus const void *endp, struct device *dev) 345a6b396f4SSakari Ailus { 346a6b396f4SSakari Ailus const struct __ccs_data_block_ffd *__ffd = payload; 347a6b396f4SSakari Ailus const struct __ccs_data_block_ffd_entry *__entry; 348a6b396f4SSakari Ailus unsigned int i; 349a6b396f4SSakari Ailus 350a6b396f4SSakari Ailus if (!is_contained(__ffd, endp)) 351a6b396f4SSakari Ailus return -ENODATA; 352a6b396f4SSakari Ailus 353a6b396f4SSakari Ailus if ((void *)__ffd + sizeof(*__ffd) + 354a6b396f4SSakari Ailus ((u32)__ffd->num_column_descs + 355a6b396f4SSakari Ailus (u32)__ffd->num_row_descs) * 356a6b396f4SSakari Ailus sizeof(struct __ccs_data_block_ffd_entry) != endp) 357a6b396f4SSakari Ailus return -ENODATA; 358a6b396f4SSakari Ailus 359a6b396f4SSakari Ailus if (!bin->base) { 360a6b396f4SSakari Ailus bin_reserve(bin, sizeof(**ffd)); 361a6b396f4SSakari Ailus bin_reserve(bin, __ffd->num_column_descs * 362a6b396f4SSakari Ailus sizeof(struct ccs_frame_format_desc)); 363a6b396f4SSakari Ailus bin_reserve(bin, __ffd->num_row_descs * 364a6b396f4SSakari Ailus sizeof(struct ccs_frame_format_desc)); 365a6b396f4SSakari Ailus 366a6b396f4SSakari Ailus return 0; 367a6b396f4SSakari Ailus } 368a6b396f4SSakari Ailus 369a6b396f4SSakari Ailus *ffd = bin_alloc(bin, sizeof(**ffd)); 370a6b396f4SSakari Ailus if (!*ffd) 371a6b396f4SSakari Ailus return -ENOMEM; 372a6b396f4SSakari Ailus 373a6b396f4SSakari Ailus (*ffd)->num_column_descs = __ffd->num_column_descs; 374a6b396f4SSakari Ailus (*ffd)->num_row_descs = __ffd->num_row_descs; 375a6b396f4SSakari Ailus __entry = (void *)(__ffd + 1); 376a6b396f4SSakari Ailus 377a6b396f4SSakari Ailus (*ffd)->column_descs = bin_alloc(bin, __ffd->num_column_descs * 378a6b396f4SSakari Ailus sizeof(*(*ffd)->column_descs)); 379a6b396f4SSakari Ailus if (!(*ffd)->column_descs) 380a6b396f4SSakari Ailus return -ENOMEM; 381a6b396f4SSakari Ailus 382a6b396f4SSakari Ailus for (i = 0; i < __ffd->num_column_descs; i++, __entry++) 383a6b396f4SSakari Ailus assign_ffd_entry(&(*ffd)->column_descs[i], __entry); 384a6b396f4SSakari Ailus 385a6b396f4SSakari Ailus (*ffd)->row_descs = bin_alloc(bin, __ffd->num_row_descs * 386a6b396f4SSakari Ailus sizeof(*(*ffd)->row_descs)); 387a6b396f4SSakari Ailus if (!(*ffd)->row_descs) 388a6b396f4SSakari Ailus return -ENOMEM; 389a6b396f4SSakari Ailus 390a6b396f4SSakari Ailus for (i = 0; i < __ffd->num_row_descs; i++, __entry++) 391a6b396f4SSakari Ailus assign_ffd_entry(&(*ffd)->row_descs[i], __entry); 392a6b396f4SSakari Ailus 393a6b396f4SSakari Ailus if (__entry != endp) 394a6b396f4SSakari Ailus return -EPROTO; 395a6b396f4SSakari Ailus 396a6b396f4SSakari Ailus return 0; 397a6b396f4SSakari Ailus } 398a6b396f4SSakari Ailus 399a6b396f4SSakari Ailus static int ccs_data_parse_pdaf_readout(struct bin_container *bin, 400a6b396f4SSakari Ailus struct ccs_pdaf_readout **pdaf_readout, 401a6b396f4SSakari Ailus const void *payload, 402a6b396f4SSakari Ailus const void *endp, struct device *dev) 403a6b396f4SSakari Ailus { 404a6b396f4SSakari Ailus const struct __ccs_data_block_pdaf_readout *__pdaf = payload; 405a6b396f4SSakari Ailus 406a6b396f4SSakari Ailus if (!is_contained(__pdaf, endp)) 407a6b396f4SSakari Ailus return -ENODATA; 408a6b396f4SSakari Ailus 409a6b396f4SSakari Ailus if (!bin->base) { 410a6b396f4SSakari Ailus bin_reserve(bin, sizeof(**pdaf_readout)); 411a6b396f4SSakari Ailus } else { 412a6b396f4SSakari Ailus *pdaf_readout = bin_alloc(bin, sizeof(**pdaf_readout)); 413a6b396f4SSakari Ailus if (!*pdaf_readout) 414a6b396f4SSakari Ailus return -ENOMEM; 415a6b396f4SSakari Ailus 416a6b396f4SSakari Ailus (*pdaf_readout)->pdaf_readout_info_order = 417a6b396f4SSakari Ailus __pdaf->pdaf_readout_info_order; 418a6b396f4SSakari Ailus } 419a6b396f4SSakari Ailus 420a6b396f4SSakari Ailus return ccs_data_parse_ffd(bin, !bin->base ? NULL : &(*pdaf_readout)->ffd, 421a6b396f4SSakari Ailus __pdaf + 1, endp, dev); 422a6b396f4SSakari Ailus } 423a6b396f4SSakari Ailus 424a6b396f4SSakari Ailus static int ccs_data_parse_rules(struct bin_container *bin, 425a6b396f4SSakari Ailus struct ccs_rule **__rules, 426a6b396f4SSakari Ailus size_t *__num_rules, const void *payload, 427a6b396f4SSakari Ailus const void *endp, struct device *dev) 428a6b396f4SSakari Ailus { 429a6b396f4SSakari Ailus struct ccs_rule *rules_base, *rules = NULL, *next_rule; 430a6b396f4SSakari Ailus size_t num_rules = 0; 431a6b396f4SSakari Ailus const void *__next_rule = payload; 432a6b396f4SSakari Ailus int rval; 433a6b396f4SSakari Ailus 434a6b396f4SSakari Ailus if (bin->base) { 435a6b396f4SSakari Ailus rules_base = next_rule = 436a6b396f4SSakari Ailus bin_alloc(bin, sizeof(*rules) * *__num_rules); 437a6b396f4SSakari Ailus if (!rules_base) 438a6b396f4SSakari Ailus return -ENOMEM; 439a6b396f4SSakari Ailus } 440a6b396f4SSakari Ailus 441a6b396f4SSakari Ailus while (__next_rule < endp) { 442a6b396f4SSakari Ailus size_t rule_hlen, rule_plen, rule_plen2; 443a6b396f4SSakari Ailus const u8 *__rule_type; 444a6b396f4SSakari Ailus const void *rule_payload; 445a6b396f4SSakari Ailus 446a6b396f4SSakari Ailus /* Size of a single rule */ 447a6b396f4SSakari Ailus rval = ccs_data_parse_length_specifier(__next_rule, &rule_hlen, 448a6b396f4SSakari Ailus &rule_plen, endp); 449a6b396f4SSakari Ailus 450a6b396f4SSakari Ailus if (rval < 0) 451a6b396f4SSakari Ailus return rval; 452a6b396f4SSakari Ailus 453a6b396f4SSakari Ailus __rule_type = __next_rule + rule_hlen; 454a6b396f4SSakari Ailus 455a6b396f4SSakari Ailus if (!is_contained(__rule_type, endp)) 456a6b396f4SSakari Ailus return -ENODATA; 457a6b396f4SSakari Ailus 458a6b396f4SSakari Ailus rule_payload = __rule_type + 1; 459a6b396f4SSakari Ailus rule_plen2 = rule_plen - sizeof(*__rule_type); 460a6b396f4SSakari Ailus 461a6b396f4SSakari Ailus switch (*__rule_type) { 462a6b396f4SSakari Ailus case CCS_DATA_BLOCK_RULE_ID_IF: { 463a6b396f4SSakari Ailus const struct __ccs_data_block_rule_if *__if_rules = 464a6b396f4SSakari Ailus rule_payload; 465a6b396f4SSakari Ailus const size_t __num_if_rules = 466a6b396f4SSakari Ailus rule_plen2 / sizeof(*__if_rules); 467a6b396f4SSakari Ailus struct ccs_if_rule *if_rule; 468a6b396f4SSakari Ailus 469a6b396f4SSakari Ailus if (!has_headroom(__if_rules, 470a6b396f4SSakari Ailus sizeof(*__if_rules) * __num_if_rules, 471a6b396f4SSakari Ailus rule_payload + rule_plen2)) 472a6b396f4SSakari Ailus return -ENODATA; 473a6b396f4SSakari Ailus 474a6b396f4SSakari Ailus /* Also check there is no extra data */ 475a6b396f4SSakari Ailus if (__if_rules + __num_if_rules != 476a6b396f4SSakari Ailus rule_payload + rule_plen2) 477a6b396f4SSakari Ailus return -EINVAL; 478a6b396f4SSakari Ailus 479a6b396f4SSakari Ailus if (!bin->base) { 480a6b396f4SSakari Ailus bin_reserve(bin, 481a6b396f4SSakari Ailus sizeof(*if_rule) * 482a6b396f4SSakari Ailus __num_if_rules); 483a6b396f4SSakari Ailus num_rules++; 484a6b396f4SSakari Ailus } else { 485a6b396f4SSakari Ailus unsigned int i; 486a6b396f4SSakari Ailus 487a6b396f4SSakari Ailus rules = next_rule; 488a6b396f4SSakari Ailus next_rule++; 489a6b396f4SSakari Ailus 490a6b396f4SSakari Ailus if_rule = bin_alloc(bin, 491a6b396f4SSakari Ailus sizeof(*if_rule) * 492a6b396f4SSakari Ailus __num_if_rules); 493a6b396f4SSakari Ailus if (!if_rule) 494a6b396f4SSakari Ailus return -ENOMEM; 495a6b396f4SSakari Ailus 496a6b396f4SSakari Ailus for (i = 0; i < __num_if_rules; i++) { 497a6b396f4SSakari Ailus if_rule[i].addr = 498a6b396f4SSakari Ailus ((u16)__if_rules[i].addr[0] 499a6b396f4SSakari Ailus << 8) + 500a6b396f4SSakari Ailus __if_rules[i].addr[1]; 501a6b396f4SSakari Ailus if_rule[i].value = __if_rules[i].value; 502a6b396f4SSakari Ailus if_rule[i].mask = __if_rules[i].mask; 503a6b396f4SSakari Ailus } 504a6b396f4SSakari Ailus 505a6b396f4SSakari Ailus rules->if_rules = if_rule; 506a6b396f4SSakari Ailus rules->num_if_rules = __num_if_rules; 507a6b396f4SSakari Ailus } 508a6b396f4SSakari Ailus break; 509a6b396f4SSakari Ailus } 510a6b396f4SSakari Ailus case CCS_DATA_BLOCK_RULE_ID_READ_ONLY_REGS: 511a6b396f4SSakari Ailus rval = ccs_data_parse_reg_rules(bin, &rules->read_only_regs, 512a6b396f4SSakari Ailus &rules->num_read_only_regs, 513a6b396f4SSakari Ailus rule_payload, 514a6b396f4SSakari Ailus rule_payload + rule_plen2, 515a6b396f4SSakari Ailus dev); 516a6b396f4SSakari Ailus if (rval) 517a6b396f4SSakari Ailus return rval; 518a6b396f4SSakari Ailus break; 519a6b396f4SSakari Ailus case CCS_DATA_BLOCK_RULE_ID_FFD: 520a6b396f4SSakari Ailus rval = ccs_data_parse_ffd(bin, &rules->frame_format, 521a6b396f4SSakari Ailus rule_payload, 522a6b396f4SSakari Ailus rule_payload + rule_plen2, 523a6b396f4SSakari Ailus dev); 524a6b396f4SSakari Ailus if (rval) 525a6b396f4SSakari Ailus return rval; 526a6b396f4SSakari Ailus break; 527a6b396f4SSakari Ailus case CCS_DATA_BLOCK_RULE_ID_MSR: 528a6b396f4SSakari Ailus rval = ccs_data_parse_reg_rules(bin, 529a6b396f4SSakari Ailus &rules->manufacturer_regs, 530a6b396f4SSakari Ailus &rules->num_manufacturer_regs, 531a6b396f4SSakari Ailus rule_payload, 532a6b396f4SSakari Ailus rule_payload + rule_plen2, 533a6b396f4SSakari Ailus dev); 534a6b396f4SSakari Ailus if (rval) 535a6b396f4SSakari Ailus return rval; 536a6b396f4SSakari Ailus break; 537a6b396f4SSakari Ailus case CCS_DATA_BLOCK_RULE_ID_PDAF_READOUT: 538a6b396f4SSakari Ailus rval = ccs_data_parse_pdaf_readout(bin, 539a6b396f4SSakari Ailus &rules->pdaf_readout, 540a6b396f4SSakari Ailus rule_payload, 541a6b396f4SSakari Ailus rule_payload + rule_plen2, 542a6b396f4SSakari Ailus dev); 543a6b396f4SSakari Ailus if (rval) 544a6b396f4SSakari Ailus return rval; 545a6b396f4SSakari Ailus break; 546a6b396f4SSakari Ailus default: 547a6b396f4SSakari Ailus dev_dbg(dev, 548a6b396f4SSakari Ailus "Don't know how to handle rule type %u!\n", 549a6b396f4SSakari Ailus *__rule_type); 550a6b396f4SSakari Ailus return -EINVAL; 551a6b396f4SSakari Ailus } 552a6b396f4SSakari Ailus __next_rule = __next_rule + rule_hlen + rule_plen; 553a6b396f4SSakari Ailus } 554a6b396f4SSakari Ailus 555a6b396f4SSakari Ailus if (!bin->base) { 556a6b396f4SSakari Ailus bin_reserve(bin, sizeof(*rules) * num_rules); 557a6b396f4SSakari Ailus *__num_rules = num_rules; 558a6b396f4SSakari Ailus } else { 559a6b396f4SSakari Ailus *__rules = rules_base; 560a6b396f4SSakari Ailus } 561a6b396f4SSakari Ailus 562a6b396f4SSakari Ailus return 0; 563a6b396f4SSakari Ailus } 564a6b396f4SSakari Ailus 565a6b396f4SSakari Ailus static int ccs_data_parse_pdaf(struct bin_container *bin, struct ccs_pdaf_pix_loc **pdaf, 566a6b396f4SSakari Ailus const void *payload, const void *endp, 567a6b396f4SSakari Ailus struct device *dev) 568a6b396f4SSakari Ailus { 569a6b396f4SSakari Ailus const struct __ccs_data_block_pdaf_pix_loc *__pdaf = payload; 570a6b396f4SSakari Ailus const struct __ccs_data_block_pdaf_pix_loc_block_desc_group *__bdesc_group; 571a6b396f4SSakari Ailus const struct __ccs_data_block_pdaf_pix_loc_pixel_desc *__pixel_desc; 572a6b396f4SSakari Ailus unsigned int i; 573a6b396f4SSakari Ailus u16 num_block_desc_groups; 574a6b396f4SSakari Ailus u8 max_block_type_id = 0; 575a6b396f4SSakari Ailus const u8 *__num_pixel_descs; 576a6b396f4SSakari Ailus 577a6b396f4SSakari Ailus if (!is_contained(__pdaf, endp)) 578a6b396f4SSakari Ailus return -ENODATA; 579a6b396f4SSakari Ailus 580a6b396f4SSakari Ailus if (bin->base) { 581a6b396f4SSakari Ailus *pdaf = bin_alloc(bin, sizeof(**pdaf)); 582a6b396f4SSakari Ailus if (!*pdaf) 583a6b396f4SSakari Ailus return -ENOMEM; 584a6b396f4SSakari Ailus } else { 585a6b396f4SSakari Ailus bin_reserve(bin, sizeof(**pdaf)); 586a6b396f4SSakari Ailus } 587a6b396f4SSakari Ailus 588a6b396f4SSakari Ailus num_block_desc_groups = 589a6b396f4SSakari Ailus ((u16)__pdaf->num_block_desc_groups[0] << 8) + 590a6b396f4SSakari Ailus __pdaf->num_block_desc_groups[1]; 591a6b396f4SSakari Ailus 592a6b396f4SSakari Ailus if (bin->base) { 593a6b396f4SSakari Ailus (*pdaf)->main_offset_x = 594a6b396f4SSakari Ailus ((u16)__pdaf->main_offset_x[0] << 8) + 595a6b396f4SSakari Ailus __pdaf->main_offset_x[1]; 596a6b396f4SSakari Ailus (*pdaf)->main_offset_y = 597a6b396f4SSakari Ailus ((u16)__pdaf->main_offset_y[0] << 8) + 598a6b396f4SSakari Ailus __pdaf->main_offset_y[1]; 599a6b396f4SSakari Ailus (*pdaf)->global_pdaf_type = __pdaf->global_pdaf_type; 600a6b396f4SSakari Ailus (*pdaf)->block_width = __pdaf->block_width; 601a6b396f4SSakari Ailus (*pdaf)->block_height = __pdaf->block_height; 602a6b396f4SSakari Ailus (*pdaf)->num_block_desc_groups = num_block_desc_groups; 603a6b396f4SSakari Ailus } 604a6b396f4SSakari Ailus 605a6b396f4SSakari Ailus __bdesc_group = (const void *)(__pdaf + 1); 606a6b396f4SSakari Ailus 607a6b396f4SSakari Ailus if (bin->base) { 608a6b396f4SSakari Ailus (*pdaf)->block_desc_groups = 609a6b396f4SSakari Ailus bin_alloc(bin, 610a6b396f4SSakari Ailus sizeof(struct ccs_pdaf_pix_loc_block_desc_group) * 611a6b396f4SSakari Ailus num_block_desc_groups); 612a6b396f4SSakari Ailus if (!(*pdaf)->block_desc_groups) 613a6b396f4SSakari Ailus return -ENOMEM; 614a6b396f4SSakari Ailus } else { 615a6b396f4SSakari Ailus bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_block_desc_group) * 616a6b396f4SSakari Ailus num_block_desc_groups); 617a6b396f4SSakari Ailus } 618a6b396f4SSakari Ailus 619a6b396f4SSakari Ailus for (i = 0; i < num_block_desc_groups; i++) { 620a6b396f4SSakari Ailus const struct __ccs_data_block_pdaf_pix_loc_block_desc *__bdesc; 621a6b396f4SSakari Ailus u16 num_block_descs; 622a6b396f4SSakari Ailus unsigned int j; 623a6b396f4SSakari Ailus 624a6b396f4SSakari Ailus if (!is_contained(__bdesc_group, endp)) 625a6b396f4SSakari Ailus return -ENODATA; 626a6b396f4SSakari Ailus 627a6b396f4SSakari Ailus num_block_descs = 628a6b396f4SSakari Ailus ((u16)__bdesc_group->num_block_descs[0] << 8) + 629a6b396f4SSakari Ailus __bdesc_group->num_block_descs[1]; 630a6b396f4SSakari Ailus 631a6b396f4SSakari Ailus if (bin->base) { 632a6b396f4SSakari Ailus (*pdaf)->block_desc_groups[i].repeat_y = 633a6b396f4SSakari Ailus __bdesc_group->repeat_y; 634a6b396f4SSakari Ailus (*pdaf)->block_desc_groups[i].num_block_descs = 635a6b396f4SSakari Ailus num_block_descs; 636a6b396f4SSakari Ailus } 637a6b396f4SSakari Ailus 638a6b396f4SSakari Ailus __bdesc = (const void *)(__bdesc_group + 1); 639a6b396f4SSakari Ailus 640a6b396f4SSakari Ailus if (bin->base) { 641a6b396f4SSakari Ailus (*pdaf)->block_desc_groups[i].block_descs = 642a6b396f4SSakari Ailus bin_alloc(bin, 643a6b396f4SSakari Ailus sizeof(struct ccs_pdaf_pix_loc_block_desc) * 644a6b396f4SSakari Ailus num_block_descs); 645a6b396f4SSakari Ailus if (!(*pdaf)->block_desc_groups[i].block_descs) 646a6b396f4SSakari Ailus return -ENOMEM; 647a6b396f4SSakari Ailus } else { 648a6b396f4SSakari Ailus bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_block_desc) * 649a6b396f4SSakari Ailus num_block_descs); 650a6b396f4SSakari Ailus } 651a6b396f4SSakari Ailus 652a6b396f4SSakari Ailus for (j = 0; j < num_block_descs; j++, __bdesc++) { 653a6b396f4SSakari Ailus struct ccs_pdaf_pix_loc_block_desc *bdesc; 654a6b396f4SSakari Ailus 655a6b396f4SSakari Ailus if (!is_contained(__bdesc, endp)) 656a6b396f4SSakari Ailus return -ENODATA; 657a6b396f4SSakari Ailus 658a6b396f4SSakari Ailus if (max_block_type_id <= __bdesc->block_type_id) 659a6b396f4SSakari Ailus max_block_type_id = __bdesc->block_type_id + 1; 660a6b396f4SSakari Ailus 661a6b396f4SSakari Ailus if (!bin->base) 662a6b396f4SSakari Ailus continue; 663a6b396f4SSakari Ailus 664a6b396f4SSakari Ailus bdesc = &(*pdaf)->block_desc_groups[i].block_descs[j]; 665a6b396f4SSakari Ailus 666a6b396f4SSakari Ailus bdesc->repeat_x = ((u16)__bdesc->repeat_x[0] << 8) 667a6b396f4SSakari Ailus + __bdesc->repeat_x[1]; 668a6b396f4SSakari Ailus 669a6b396f4SSakari Ailus if (__bdesc->block_type_id >= num_block_descs) 670a6b396f4SSakari Ailus return -EINVAL; 671a6b396f4SSakari Ailus 672a6b396f4SSakari Ailus bdesc->block_type_id = __bdesc->block_type_id; 673a6b396f4SSakari Ailus } 674a6b396f4SSakari Ailus 675a6b396f4SSakari Ailus __bdesc_group = (const void *)__bdesc; 676a6b396f4SSakari Ailus } 677a6b396f4SSakari Ailus 678a6b396f4SSakari Ailus __num_pixel_descs = (const void *)__bdesc_group; 679a6b396f4SSakari Ailus 680a6b396f4SSakari Ailus if (bin->base) { 681a6b396f4SSakari Ailus (*pdaf)->pixel_desc_groups = 682a6b396f4SSakari Ailus bin_alloc(bin, 683a6b396f4SSakari Ailus sizeof(struct ccs_pdaf_pix_loc_pixel_desc_group) * 684a6b396f4SSakari Ailus max_block_type_id); 685a6b396f4SSakari Ailus if (!(*pdaf)->pixel_desc_groups) 686a6b396f4SSakari Ailus return -ENOMEM; 687a6b396f4SSakari Ailus (*pdaf)->num_pixel_desc_grups = max_block_type_id; 688a6b396f4SSakari Ailus } else { 689a6b396f4SSakari Ailus bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_pixel_desc_group) * 690a6b396f4SSakari Ailus max_block_type_id); 691a6b396f4SSakari Ailus } 692a6b396f4SSakari Ailus 693a6b396f4SSakari Ailus for (i = 0; i < max_block_type_id; i++) { 694a6b396f4SSakari Ailus struct ccs_pdaf_pix_loc_pixel_desc_group *pdgroup; 695a6b396f4SSakari Ailus unsigned int j; 696a6b396f4SSakari Ailus 697a6b396f4SSakari Ailus if (!is_contained(__num_pixel_descs, endp)) 698a6b396f4SSakari Ailus return -ENODATA; 699a6b396f4SSakari Ailus 700a6b396f4SSakari Ailus if (bin->base) { 701a6b396f4SSakari Ailus pdgroup = &(*pdaf)->pixel_desc_groups[i]; 702a6b396f4SSakari Ailus pdgroup->descs = 703a6b396f4SSakari Ailus bin_alloc(bin, 704a6b396f4SSakari Ailus sizeof(struct ccs_pdaf_pix_loc_pixel_desc) * 705a6b396f4SSakari Ailus *__num_pixel_descs); 706a6b396f4SSakari Ailus if (!pdgroup->descs) 707a6b396f4SSakari Ailus return -ENOMEM; 708a6b396f4SSakari Ailus pdgroup->num_descs = *__num_pixel_descs; 709a6b396f4SSakari Ailus } else { 710a6b396f4SSakari Ailus bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_pixel_desc) * 711a6b396f4SSakari Ailus *__num_pixel_descs); 712a6b396f4SSakari Ailus } 713a6b396f4SSakari Ailus 714a6b396f4SSakari Ailus __pixel_desc = (const void *)(__num_pixel_descs + 1); 715a6b396f4SSakari Ailus 716a6b396f4SSakari Ailus for (j = 0; j < *__num_pixel_descs; j++, __pixel_desc++) { 717a6b396f4SSakari Ailus struct ccs_pdaf_pix_loc_pixel_desc *pdesc; 718a6b396f4SSakari Ailus 719a6b396f4SSakari Ailus if (!is_contained(__pixel_desc, endp)) 720a6b396f4SSakari Ailus return -ENODATA; 721a6b396f4SSakari Ailus 722a6b396f4SSakari Ailus if (!bin->base) 723a6b396f4SSakari Ailus continue; 724a6b396f4SSakari Ailus 725a6b396f4SSakari Ailus pdesc = &pdgroup->descs[j]; 726a6b396f4SSakari Ailus pdesc->pixel_type = __pixel_desc->pixel_type; 727a6b396f4SSakari Ailus pdesc->small_offset_x = __pixel_desc->small_offset_x; 728a6b396f4SSakari Ailus pdesc->small_offset_y = __pixel_desc->small_offset_y; 729a6b396f4SSakari Ailus } 730a6b396f4SSakari Ailus 731a6b396f4SSakari Ailus __num_pixel_descs = (const void *)(__pixel_desc + 1); 732a6b396f4SSakari Ailus } 733a6b396f4SSakari Ailus 734a6b396f4SSakari Ailus return 0; 735a6b396f4SSakari Ailus } 736a6b396f4SSakari Ailus 737a6b396f4SSakari Ailus static int ccs_data_parse_license(struct bin_container *bin, 738a6b396f4SSakari Ailus char **__license, 739a6b396f4SSakari Ailus size_t *__license_length, 740a6b396f4SSakari Ailus const void *payload, const void *endp) 741a6b396f4SSakari Ailus { 742a6b396f4SSakari Ailus size_t size = endp - payload; 743a6b396f4SSakari Ailus char *license; 744a6b396f4SSakari Ailus 745a6b396f4SSakari Ailus if (!bin->base) { 746a6b396f4SSakari Ailus bin_reserve(bin, size); 747a6b396f4SSakari Ailus return 0; 748a6b396f4SSakari Ailus } 749a6b396f4SSakari Ailus 750a6b396f4SSakari Ailus license = bin_alloc(bin, size); 751a6b396f4SSakari Ailus if (!license) 752a6b396f4SSakari Ailus return -ENOMEM; 753a6b396f4SSakari Ailus 754a6b396f4SSakari Ailus memcpy(license, payload, size); 755a6b396f4SSakari Ailus 756a6b396f4SSakari Ailus *__license = license; 757a6b396f4SSakari Ailus *__license_length = size; 758a6b396f4SSakari Ailus 759a6b396f4SSakari Ailus return 0; 760a6b396f4SSakari Ailus } 761a6b396f4SSakari Ailus 762a6b396f4SSakari Ailus static int ccs_data_parse_end(bool *end, const void *payload, const void *endp, 763a6b396f4SSakari Ailus struct device *dev) 764a6b396f4SSakari Ailus { 765a6b396f4SSakari Ailus const struct __ccs_data_block_end *__end = payload; 766a6b396f4SSakari Ailus 767a6b396f4SSakari Ailus if (__end + 1 != endp) { 768a6b396f4SSakari Ailus dev_dbg(dev, "Invalid end block length %u\n", 769a6b396f4SSakari Ailus (unsigned int)(endp - payload)); 770a6b396f4SSakari Ailus return -ENODATA; 771a6b396f4SSakari Ailus } 772a6b396f4SSakari Ailus 773a6b396f4SSakari Ailus *end = true; 774a6b396f4SSakari Ailus 775a6b396f4SSakari Ailus return 0; 776a6b396f4SSakari Ailus } 777a6b396f4SSakari Ailus 778a6b396f4SSakari Ailus static int __ccs_data_parse(struct bin_container *bin, 779a6b396f4SSakari Ailus struct ccs_data_container *ccsdata, 780a6b396f4SSakari Ailus const void *data, size_t len, struct device *dev, 781a6b396f4SSakari Ailus bool verbose) 782a6b396f4SSakari Ailus { 783a6b396f4SSakari Ailus const struct __ccs_data_block *block = data; 784a6b396f4SSakari Ailus const struct __ccs_data_block *endp = data + len; 785a6b396f4SSakari Ailus unsigned int version; 786a6b396f4SSakari Ailus bool is_first = true; 787a6b396f4SSakari Ailus int rval; 788a6b396f4SSakari Ailus 789a6b396f4SSakari Ailus version = ccs_data_parse_format_version(block); 790a6b396f4SSakari Ailus if (version != CCS_STATIC_DATA_VERSION) { 791a6b396f4SSakari Ailus dev_dbg(dev, "Don't know how to handle version %u\n", version); 792a6b396f4SSakari Ailus return -EINVAL; 793a6b396f4SSakari Ailus } 794a6b396f4SSakari Ailus 795a6b396f4SSakari Ailus if (verbose) 796a6b396f4SSakari Ailus dev_dbg(dev, "Parsing CCS static data version %u\n", version); 797a6b396f4SSakari Ailus 798a6b396f4SSakari Ailus if (!bin->base) 799a6b396f4SSakari Ailus *ccsdata = (struct ccs_data_container){ 0 }; 800a6b396f4SSakari Ailus 801a6b396f4SSakari Ailus while (block < endp) { 802a6b396f4SSakari Ailus const struct __ccs_data_block *next_block; 803a6b396f4SSakari Ailus unsigned int block_id; 804a6b396f4SSakari Ailus const void *payload; 805a6b396f4SSakari Ailus 806a6b396f4SSakari Ailus rval = ccs_data_block_parse_header(block, is_first, &block_id, 807a6b396f4SSakari Ailus &payload, &next_block, endp, 808a6b396f4SSakari Ailus dev, 809a6b396f4SSakari Ailus bin->base ? false : verbose); 810a6b396f4SSakari Ailus 811a6b396f4SSakari Ailus if (rval < 0) 812a6b396f4SSakari Ailus return rval; 813a6b396f4SSakari Ailus 814a6b396f4SSakari Ailus switch (block_id) { 815a6b396f4SSakari Ailus case CCS_DATA_BLOCK_ID_DUMMY: 816a6b396f4SSakari Ailus break; 817a6b396f4SSakari Ailus case CCS_DATA_BLOCK_ID_DATA_VERSION: 818a6b396f4SSakari Ailus rval = ccs_data_parse_version(bin, ccsdata, payload, 819a6b396f4SSakari Ailus next_block); 820a6b396f4SSakari Ailus if (rval < 0) 821a6b396f4SSakari Ailus return rval; 822a6b396f4SSakari Ailus break; 823a6b396f4SSakari Ailus case CCS_DATA_BLOCK_ID_SENSOR_READ_ONLY_REGS: 824a6b396f4SSakari Ailus rval = ccs_data_parse_regs( 825a6b396f4SSakari Ailus bin, &ccsdata->sensor_read_only_regs, 826a6b396f4SSakari Ailus &ccsdata->num_sensor_read_only_regs, payload, 827a6b396f4SSakari Ailus next_block, dev); 828a6b396f4SSakari Ailus if (rval < 0) 829a6b396f4SSakari Ailus return rval; 830a6b396f4SSakari Ailus break; 831a6b396f4SSakari Ailus case CCS_DATA_BLOCK_ID_SENSOR_MANUFACTURER_REGS: 832a6b396f4SSakari Ailus rval = ccs_data_parse_regs( 833a6b396f4SSakari Ailus bin, &ccsdata->sensor_manufacturer_regs, 834a6b396f4SSakari Ailus &ccsdata->num_sensor_manufacturer_regs, payload, 835a6b396f4SSakari Ailus next_block, dev); 836a6b396f4SSakari Ailus if (rval < 0) 837a6b396f4SSakari Ailus return rval; 838a6b396f4SSakari Ailus break; 839a6b396f4SSakari Ailus case CCS_DATA_BLOCK_ID_MODULE_READ_ONLY_REGS: 840a6b396f4SSakari Ailus rval = ccs_data_parse_regs( 841a6b396f4SSakari Ailus bin, &ccsdata->module_read_only_regs, 842a6b396f4SSakari Ailus &ccsdata->num_module_read_only_regs, payload, 843a6b396f4SSakari Ailus next_block, dev); 844a6b396f4SSakari Ailus if (rval < 0) 845a6b396f4SSakari Ailus return rval; 846a6b396f4SSakari Ailus break; 847a6b396f4SSakari Ailus case CCS_DATA_BLOCK_ID_MODULE_MANUFACTURER_REGS: 848a6b396f4SSakari Ailus rval = ccs_data_parse_regs( 849a6b396f4SSakari Ailus bin, &ccsdata->module_manufacturer_regs, 850a6b396f4SSakari Ailus &ccsdata->num_module_manufacturer_regs, payload, 851a6b396f4SSakari Ailus next_block, dev); 852a6b396f4SSakari Ailus if (rval < 0) 853a6b396f4SSakari Ailus return rval; 854a6b396f4SSakari Ailus break; 855a6b396f4SSakari Ailus case CCS_DATA_BLOCK_ID_SENSOR_PDAF_PIXEL_LOCATION: 856a6b396f4SSakari Ailus rval = ccs_data_parse_pdaf(bin, &ccsdata->sensor_pdaf, 857a6b396f4SSakari Ailus payload, next_block, dev); 858a6b396f4SSakari Ailus if (rval < 0) 859a6b396f4SSakari Ailus return rval; 860a6b396f4SSakari Ailus break; 861a6b396f4SSakari Ailus case CCS_DATA_BLOCK_ID_MODULE_PDAF_PIXEL_LOCATION: 862a6b396f4SSakari Ailus rval = ccs_data_parse_pdaf(bin, &ccsdata->module_pdaf, 863a6b396f4SSakari Ailus payload, next_block, dev); 864a6b396f4SSakari Ailus if (rval < 0) 865a6b396f4SSakari Ailus return rval; 866a6b396f4SSakari Ailus break; 867a6b396f4SSakari Ailus case CCS_DATA_BLOCK_ID_SENSOR_RULE_BASED_BLOCK: 868a6b396f4SSakari Ailus rval = ccs_data_parse_rules( 869a6b396f4SSakari Ailus bin, &ccsdata->sensor_rules, 870a6b396f4SSakari Ailus &ccsdata->num_sensor_rules, payload, next_block, 871a6b396f4SSakari Ailus dev); 872a6b396f4SSakari Ailus if (rval < 0) 873a6b396f4SSakari Ailus return rval; 874a6b396f4SSakari Ailus break; 875a6b396f4SSakari Ailus case CCS_DATA_BLOCK_ID_MODULE_RULE_BASED_BLOCK: 876a6b396f4SSakari Ailus rval = ccs_data_parse_rules( 877a6b396f4SSakari Ailus bin, &ccsdata->module_rules, 878a6b396f4SSakari Ailus &ccsdata->num_module_rules, payload, next_block, 879a6b396f4SSakari Ailus dev); 880a6b396f4SSakari Ailus if (rval < 0) 881a6b396f4SSakari Ailus return rval; 882a6b396f4SSakari Ailus break; 883a6b396f4SSakari Ailus case CCS_DATA_BLOCK_ID_LICENSE: 884a6b396f4SSakari Ailus rval = ccs_data_parse_license(bin, &ccsdata->license, 885a6b396f4SSakari Ailus &ccsdata->license_length, 886a6b396f4SSakari Ailus payload, next_block); 887a6b396f4SSakari Ailus if (rval < 0) 888a6b396f4SSakari Ailus return rval; 889a6b396f4SSakari Ailus break; 890a6b396f4SSakari Ailus case CCS_DATA_BLOCK_ID_END: 891a6b396f4SSakari Ailus rval = ccs_data_parse_end(&ccsdata->end, payload, 892a6b396f4SSakari Ailus next_block, dev); 893a6b396f4SSakari Ailus if (rval < 0) 894a6b396f4SSakari Ailus return rval; 895a6b396f4SSakari Ailus break; 896a6b396f4SSakari Ailus default: 897a6b396f4SSakari Ailus dev_dbg(dev, "WARNING: not handling block ID 0x%2.2x\n", 898a6b396f4SSakari Ailus block_id); 899a6b396f4SSakari Ailus } 900a6b396f4SSakari Ailus 901a6b396f4SSakari Ailus block = next_block; 902a6b396f4SSakari Ailus is_first = false; 903a6b396f4SSakari Ailus } 904a6b396f4SSakari Ailus 905a6b396f4SSakari Ailus return 0; 906a6b396f4SSakari Ailus } 907a6b396f4SSakari Ailus 908a6b396f4SSakari Ailus /** 909a6b396f4SSakari Ailus * ccs_data_parse - Parse a CCS static data file into a usable in-memory 910a6b396f4SSakari Ailus * data structure 911a6b396f4SSakari Ailus * @ccsdata: CCS static data in-memory data structure 912a6b396f4SSakari Ailus * @data: CCS static data binary 913a6b396f4SSakari Ailus * @len: Length of @data 914a6b396f4SSakari Ailus * @dev: Device the data is related to (used for printing debug messages) 915a6b396f4SSakari Ailus * @verbose: Whether to be verbose or not 916a6b396f4SSakari Ailus */ 917a6b396f4SSakari Ailus int ccs_data_parse(struct ccs_data_container *ccsdata, const void *data, 918a6b396f4SSakari Ailus size_t len, struct device *dev, bool verbose) 919a6b396f4SSakari Ailus { 920a6b396f4SSakari Ailus struct bin_container bin = { 0 }; 921a6b396f4SSakari Ailus int rval; 922a6b396f4SSakari Ailus 923a6b396f4SSakari Ailus rval = __ccs_data_parse(&bin, ccsdata, data, len, dev, verbose); 924a6b396f4SSakari Ailus if (rval) 925a6b396f4SSakari Ailus return rval; 926a6b396f4SSakari Ailus 927a6b396f4SSakari Ailus rval = bin_backing_alloc(&bin); 928a6b396f4SSakari Ailus if (rval) 929a6b396f4SSakari Ailus return rval; 930a6b396f4SSakari Ailus 931a6b396f4SSakari Ailus rval = __ccs_data_parse(&bin, ccsdata, data, len, dev, false); 932a6b396f4SSakari Ailus if (rval) 933a6b396f4SSakari Ailus goto out_free; 934a6b396f4SSakari Ailus 935a6b396f4SSakari Ailus if (verbose && ccsdata->version) 936a6b396f4SSakari Ailus print_ccs_data_version(dev, ccsdata->version); 937a6b396f4SSakari Ailus 938a6b396f4SSakari Ailus if (bin.now != bin.end) { 939a6b396f4SSakari Ailus rval = -EPROTO; 940a6b396f4SSakari Ailus dev_dbg(dev, "parsing mismatch; base %p; now %p; end %p\n", 941a6b396f4SSakari Ailus bin.base, bin.now, bin.end); 942a6b396f4SSakari Ailus goto out_free; 943a6b396f4SSakari Ailus } 944a6b396f4SSakari Ailus 945a6b396f4SSakari Ailus ccsdata->backing = bin.base; 946a6b396f4SSakari Ailus 947a6b396f4SSakari Ailus return 0; 948a6b396f4SSakari Ailus 949a6b396f4SSakari Ailus out_free: 950a6b396f4SSakari Ailus kvfree(bin.base); 951a6b396f4SSakari Ailus 952a6b396f4SSakari Ailus return rval; 953a6b396f4SSakari Ailus } 954