| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982 |
- // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
- /*
- * CCS static data binary parser library
- *
- * Copyright 2019--2020 Intel Corporation
- */
- #include <linux/device.h>
- #include <linux/errno.h>
- #include <linux/limits.h>
- #include <linux/mm.h>
- #include <linux/slab.h>
- #include <linux/string.h>
- #include "ccs-data-defs.h"
- struct bin_container {
- void *base;
- void *now;
- void *end;
- size_t size;
- };
- static void *bin_alloc(struct bin_container *bin, size_t len)
- {
- void *ptr;
- len = ALIGN(len, 8);
- if (bin->end - bin->now < len)
- return NULL;
- ptr = bin->now;
- bin->now += len;
- return ptr;
- }
- static void bin_reserve(struct bin_container *bin, size_t len)
- {
- bin->size += ALIGN(len, 8);
- }
- static int bin_backing_alloc(struct bin_container *bin)
- {
- bin->base = bin->now = kvzalloc(bin->size, GFP_KERNEL);
- if (!bin->base)
- return -ENOMEM;
- bin->end = bin->base + bin->size;
- return 0;
- }
- #define is_contained(var, endp) \
- (sizeof(*var) <= (endp) - (void *)(var))
- #define has_headroom(ptr, headroom, endp) \
- ((headroom) <= (endp) - (void *)(ptr))
- #define is_contained_with_headroom(var, headroom, endp) \
- (sizeof(*var) + (headroom) <= (endp) - (void *)(var))
- static int
- ccs_data_parse_length_specifier(const struct __ccs_data_length_specifier *__len,
- size_t *__hlen, size_t *__plen,
- const void *endp)
- {
- size_t hlen, plen;
- if (!is_contained(__len, endp))
- return -ENODATA;
- switch (__len->length >> CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) {
- case CCS_DATA_LENGTH_SPECIFIER_1:
- hlen = sizeof(*__len);
- plen = __len->length &
- ((1 << CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) - 1);
- break;
- case CCS_DATA_LENGTH_SPECIFIER_2: {
- struct __ccs_data_length_specifier2 *__len2 = (void *)__len;
- if (!is_contained(__len2, endp))
- return -ENODATA;
- hlen = sizeof(*__len2);
- plen = ((size_t)
- (__len2->length[0] &
- ((1 << CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) - 1))
- << 8) + __len2->length[1];
- break;
- }
- case CCS_DATA_LENGTH_SPECIFIER_3: {
- struct __ccs_data_length_specifier3 *__len3 = (void *)__len;
- if (!is_contained(__len3, endp))
- return -ENODATA;
- hlen = sizeof(*__len3);
- plen = ((size_t)
- (__len3->length[0] &
- ((1 << CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) - 1))
- << 16) + (__len3->length[1] << 8) + __len3->length[2];
- break;
- }
- default:
- return -EINVAL;
- }
- if (!has_headroom(__len, hlen + plen, endp))
- return -ENODATA;
- *__hlen = hlen;
- *__plen = plen;
- return 0;
- }
- static u8
- ccs_data_parse_format_version(const struct __ccs_data_block *block)
- {
- return block->id >> CCS_DATA_BLOCK_HEADER_ID_VERSION_SHIFT;
- }
- static u8 ccs_data_parse_block_id(const struct __ccs_data_block *block,
- bool is_first)
- {
- if (!is_first)
- return block->id;
- return block->id & ((1 << CCS_DATA_BLOCK_HEADER_ID_VERSION_SHIFT) - 1);
- }
- static int ccs_data_parse_version(struct bin_container *bin,
- struct ccs_data_container *ccsdata,
- const void *payload, const void *endp)
- {
- const struct __ccs_data_block_version *v = payload;
- struct ccs_data_block_version *vv;
- if (v + 1 != endp)
- return -ENODATA;
- if (!bin->base) {
- bin_reserve(bin, sizeof(*ccsdata->version));
- return 0;
- }
- ccsdata->version = bin_alloc(bin, sizeof(*ccsdata->version));
- if (!ccsdata->version)
- return -ENOMEM;
- vv = ccsdata->version;
- vv->version_major = ((u16)v->static_data_version_major[0] << 8) +
- v->static_data_version_major[1];
- vv->version_minor = ((u16)v->static_data_version_minor[0] << 8) +
- v->static_data_version_minor[1];
- vv->date_year = ((u16)v->year[0] << 8) + v->year[1];
- vv->date_month = v->month;
- vv->date_day = v->day;
- return 0;
- }
- static void print_ccs_data_version(struct device *dev,
- struct ccs_data_block_version *v)
- {
- dev_dbg(dev,
- "static data version %4.4x.%4.4x, date %4.4u-%2.2u-%2.2u\n",
- v->version_major, v->version_minor,
- v->date_year, v->date_month, v->date_day);
- }
- static int ccs_data_block_parse_header(const struct __ccs_data_block *block,
- bool is_first, unsigned int *__block_id,
- const void **payload,
- const struct __ccs_data_block **next_block,
- const void *endp, struct device *dev,
- bool verbose)
- {
- size_t plen, hlen;
- u8 block_id;
- int rval;
- if (!is_contained(block, endp))
- return -ENODATA;
- rval = ccs_data_parse_length_specifier(&block->length, &hlen, &plen,
- endp);
- if (rval < 0)
- return rval;
- block_id = ccs_data_parse_block_id(block, is_first);
- if (verbose)
- dev_dbg(dev,
- "Block ID 0x%2.2x, header length %zu, payload length %zu\n",
- block_id, hlen, plen);
- if (!has_headroom(&block->length, hlen + plen, endp))
- return -ENODATA;
- if (__block_id)
- *__block_id = block_id;
- if (payload)
- *payload = (void *)&block->length + hlen;
- if (next_block)
- *next_block = (void *)&block->length + hlen + plen;
- return 0;
- }
- static int ccs_data_parse_regs(struct bin_container *bin,
- struct ccs_reg **__regs,
- size_t *__num_regs, const void *payload,
- const void *endp, struct device *dev)
- {
- struct ccs_reg *regs_base = NULL, *regs = NULL;
- size_t num_regs = 0;
- u16 addr = 0;
- if (bin->base && __regs) {
- regs = regs_base = bin_alloc(bin, sizeof(*regs) * *__num_regs);
- if (!regs)
- return -ENOMEM;
- }
- while (payload < endp && num_regs < INT_MAX) {
- const struct __ccs_data_block_regs *r = payload;
- size_t len;
- const void *data;
- if (!is_contained(r, endp))
- return -ENODATA;
- switch (r->reg_len >> CCS_DATA_BLOCK_REGS_SEL_SHIFT) {
- case CCS_DATA_BLOCK_REGS_SEL_REGS:
- addr += r->reg_len & CCS_DATA_BLOCK_REGS_ADDR_MASK;
- len = ((r->reg_len & CCS_DATA_BLOCK_REGS_LEN_MASK)
- >> CCS_DATA_BLOCK_REGS_LEN_SHIFT) + 1;
- if (!is_contained_with_headroom(r, len, endp))
- return -ENODATA;
- data = r + 1;
- break;
- case CCS_DATA_BLOCK_REGS_SEL_REGS2: {
- const struct __ccs_data_block_regs2 *r2 = payload;
- if (!is_contained(r2, endp))
- return -ENODATA;
- addr += ((u16)(r2->reg_len &
- CCS_DATA_BLOCK_REGS_2_ADDR_MASK) << 8)
- + r2->addr;
- len = ((r2->reg_len & CCS_DATA_BLOCK_REGS_2_LEN_MASK)
- >> CCS_DATA_BLOCK_REGS_2_LEN_SHIFT) + 1;
- if (!is_contained_with_headroom(r2, len, endp))
- return -ENODATA;
- data = r2 + 1;
- break;
- }
- case CCS_DATA_BLOCK_REGS_SEL_REGS3: {
- const struct __ccs_data_block_regs3 *r3 = payload;
- if (!is_contained(r3, endp))
- return -ENODATA;
- addr = ((u16)r3->addr[0] << 8) + r3->addr[1];
- len = (r3->reg_len & CCS_DATA_BLOCK_REGS_3_LEN_MASK) + 1;
- if (!is_contained_with_headroom(r3, len, endp))
- return -ENODATA;
- data = r3 + 1;
- break;
- }
- default:
- return -EINVAL;
- }
- num_regs++;
- if (!bin->base) {
- bin_reserve(bin, len);
- } else if (__regs) {
- if (!regs)
- return -EIO;
- regs->addr = addr;
- regs->len = len;
- regs->value = bin_alloc(bin, len);
- if (!regs->value)
- return -ENOMEM;
- memcpy(regs->value, data, len);
- regs++;
- }
- addr += len;
- payload = data + len;
- }
- if (!bin->base)
- bin_reserve(bin, sizeof(*regs) * num_regs);
- if (__num_regs)
- *__num_regs = num_regs;
- if (bin->base && __regs) {
- if (!regs_base)
- return -EIO;
- *__regs = regs_base;
- }
- return 0;
- }
- static int ccs_data_parse_reg_rules(struct bin_container *bin,
- struct ccs_reg **__regs,
- size_t *__num_regs,
- const void *payload,
- const void *endp, struct device *dev)
- {
- int rval;
- if (!bin->base)
- return ccs_data_parse_regs(bin, NULL, NULL, payload, endp, dev);
- rval = ccs_data_parse_regs(bin, NULL, __num_regs, payload, endp, dev);
- if (rval)
- return rval;
- return ccs_data_parse_regs(bin, __regs, __num_regs, payload, endp,
- dev);
- }
- static void assign_ffd_entry(struct ccs_frame_format_desc *desc,
- const struct __ccs_data_block_ffd_entry *ent)
- {
- desc->pixelcode = ent->pixelcode;
- desc->value = ((u16)ent->value[0] << 8) + ent->value[1];
- }
- static int ccs_data_parse_ffd(struct bin_container *bin,
- struct ccs_frame_format_descs **ffd,
- const void *payload,
- const void *endp, struct device *dev)
- {
- const struct __ccs_data_block_ffd *__ffd = payload;
- const struct __ccs_data_block_ffd_entry *__entry;
- unsigned int i;
- if (!is_contained(__ffd, endp))
- return -ENODATA;
- if ((void *)__ffd + sizeof(*__ffd) +
- ((u32)__ffd->num_column_descs +
- (u32)__ffd->num_row_descs) *
- sizeof(struct __ccs_data_block_ffd_entry) != endp)
- return -ENODATA;
- if (!bin->base) {
- bin_reserve(bin, sizeof(**ffd));
- bin_reserve(bin, __ffd->num_column_descs *
- sizeof(struct ccs_frame_format_desc));
- bin_reserve(bin, __ffd->num_row_descs *
- sizeof(struct ccs_frame_format_desc));
- return 0;
- }
- *ffd = bin_alloc(bin, sizeof(**ffd));
- if (!*ffd)
- return -ENOMEM;
- (*ffd)->num_column_descs = __ffd->num_column_descs;
- (*ffd)->num_row_descs = __ffd->num_row_descs;
- __entry = (void *)(__ffd + 1);
- (*ffd)->column_descs = bin_alloc(bin, __ffd->num_column_descs *
- sizeof(*(*ffd)->column_descs));
- if (!(*ffd)->column_descs)
- return -ENOMEM;
- for (i = 0; i < __ffd->num_column_descs; i++, __entry++)
- assign_ffd_entry(&(*ffd)->column_descs[i], __entry);
- (*ffd)->row_descs = bin_alloc(bin, __ffd->num_row_descs *
- sizeof(*(*ffd)->row_descs));
- if (!(*ffd)->row_descs)
- return -ENOMEM;
- for (i = 0; i < __ffd->num_row_descs; i++, __entry++)
- assign_ffd_entry(&(*ffd)->row_descs[i], __entry);
- if (__entry != endp)
- return -EPROTO;
- return 0;
- }
- static int ccs_data_parse_pdaf_readout(struct bin_container *bin,
- struct ccs_pdaf_readout **pdaf_readout,
- const void *payload,
- const void *endp, struct device *dev)
- {
- const struct __ccs_data_block_pdaf_readout *__pdaf = payload;
- if (!is_contained(__pdaf, endp))
- return -ENODATA;
- if (!bin->base) {
- bin_reserve(bin, sizeof(**pdaf_readout));
- } else {
- *pdaf_readout = bin_alloc(bin, sizeof(**pdaf_readout));
- if (!*pdaf_readout)
- return -ENOMEM;
- (*pdaf_readout)->pdaf_readout_info_order =
- __pdaf->pdaf_readout_info_order;
- }
- return ccs_data_parse_ffd(bin, !bin->base ? NULL : &(*pdaf_readout)->ffd,
- __pdaf + 1, endp, dev);
- }
- static int ccs_data_parse_rules(struct bin_container *bin,
- struct ccs_rule **__rules,
- size_t *__num_rules, const void *payload,
- const void *endp, struct device *dev)
- {
- struct ccs_rule *rules_base = NULL, *rules = NULL, *next_rule = NULL;
- size_t num_rules = 0;
- const void *__next_rule = payload;
- int rval;
- if (bin->base) {
- rules_base = next_rule =
- bin_alloc(bin, sizeof(*rules) * *__num_rules);
- if (!rules_base)
- return -ENOMEM;
- }
- while (__next_rule < endp) {
- size_t rule_hlen, rule_plen, rule_plen2;
- const u8 *__rule_type;
- const void *rule_payload;
- /* Size of a single rule */
- rval = ccs_data_parse_length_specifier(__next_rule, &rule_hlen,
- &rule_plen, endp);
- if (rval < 0)
- return rval;
- __rule_type = __next_rule + rule_hlen;
- if (!is_contained(__rule_type, endp))
- return -ENODATA;
- rule_payload = __rule_type + 1;
- rule_plen2 = rule_plen - sizeof(*__rule_type);
- if (*__rule_type == CCS_DATA_BLOCK_RULE_ID_IF) {
- const struct __ccs_data_block_rule_if *__if_rules =
- rule_payload;
- const size_t __num_if_rules =
- rule_plen2 / sizeof(*__if_rules);
- struct ccs_if_rule *if_rule;
- if (!has_headroom(__if_rules,
- sizeof(*__if_rules) * __num_if_rules,
- rule_payload + rule_plen2))
- return -ENODATA;
- /* Also check there is no extra data */
- if (__if_rules + __num_if_rules !=
- rule_payload + rule_plen2)
- return -EINVAL;
- if (!bin->base) {
- bin_reserve(bin,
- sizeof(*if_rule) *
- __num_if_rules);
- num_rules++;
- } else {
- unsigned int i;
- if (!next_rule)
- return -EIO;
- rules = next_rule;
- next_rule++;
- if_rule = bin_alloc(bin,
- sizeof(*if_rule) *
- __num_if_rules);
- if (!if_rule)
- return -ENOMEM;
- for (i = 0; i < __num_if_rules; i++) {
- if_rule[i].addr =
- ((u16)__if_rules[i].addr[0]
- << 8) +
- __if_rules[i].addr[1];
- if_rule[i].value = __if_rules[i].value;
- if_rule[i].mask = __if_rules[i].mask;
- }
- rules->if_rules = if_rule;
- rules->num_if_rules = __num_if_rules;
- }
- } else {
- /* Check there was an if rule before any other rules */
- if (bin->base && !rules)
- return -EINVAL;
- switch (*__rule_type) {
- case CCS_DATA_BLOCK_RULE_ID_READ_ONLY_REGS:
- rval = ccs_data_parse_reg_rules(bin,
- rules ?
- &rules->read_only_regs : NULL,
- rules ?
- &rules->num_read_only_regs : NULL,
- rule_payload,
- rule_payload + rule_plen2,
- dev);
- if (rval)
- return rval;
- break;
- case CCS_DATA_BLOCK_RULE_ID_FFD:
- rval = ccs_data_parse_ffd(bin, rules ?
- &rules->frame_format : NULL,
- rule_payload,
- rule_payload + rule_plen2,
- dev);
- if (rval)
- return rval;
- break;
- case CCS_DATA_BLOCK_RULE_ID_MSR:
- rval = ccs_data_parse_reg_rules(bin,
- rules ?
- &rules->manufacturer_regs : NULL,
- rules ?
- &rules->num_manufacturer_regs : NULL,
- rule_payload,
- rule_payload + rule_plen2,
- dev);
- if (rval)
- return rval;
- break;
- case CCS_DATA_BLOCK_RULE_ID_PDAF_READOUT:
- rval = ccs_data_parse_pdaf_readout(bin,
- rules ?
- &rules->pdaf_readout : NULL,
- rule_payload,
- rule_payload + rule_plen2,
- dev);
- if (rval)
- return rval;
- break;
- default:
- dev_dbg(dev,
- "Don't know how to handle rule type %u!\n",
- *__rule_type);
- return -EINVAL;
- }
- }
- __next_rule = __next_rule + rule_hlen + rule_plen;
- }
- if (!bin->base) {
- bin_reserve(bin, sizeof(*rules) * num_rules);
- *__num_rules = num_rules;
- } else {
- if (!rules_base)
- return -EIO;
- *__rules = rules_base;
- }
- return 0;
- }
- static int ccs_data_parse_pdaf(struct bin_container *bin, struct ccs_pdaf_pix_loc **pdaf,
- const void *payload, const void *endp,
- struct device *dev)
- {
- const struct __ccs_data_block_pdaf_pix_loc *__pdaf = payload;
- const struct __ccs_data_block_pdaf_pix_loc_block_desc_group *__bdesc_group;
- const struct __ccs_data_block_pdaf_pix_loc_pixel_desc *__pixel_desc;
- unsigned int i;
- u16 num_block_desc_groups;
- u8 max_block_type_id = 0;
- const u8 *__num_pixel_descs;
- if (!is_contained(__pdaf, endp))
- return -ENODATA;
- if (bin->base) {
- *pdaf = bin_alloc(bin, sizeof(**pdaf));
- if (!*pdaf)
- return -ENOMEM;
- } else {
- bin_reserve(bin, sizeof(**pdaf));
- }
- num_block_desc_groups =
- ((u16)__pdaf->num_block_desc_groups[0] << 8) +
- __pdaf->num_block_desc_groups[1];
- if (bin->base) {
- (*pdaf)->main_offset_x =
- ((u16)__pdaf->main_offset_x[0] << 8) +
- __pdaf->main_offset_x[1];
- (*pdaf)->main_offset_y =
- ((u16)__pdaf->main_offset_y[0] << 8) +
- __pdaf->main_offset_y[1];
- (*pdaf)->global_pdaf_type = __pdaf->global_pdaf_type;
- (*pdaf)->block_width = __pdaf->block_width;
- (*pdaf)->block_height = __pdaf->block_height;
- (*pdaf)->num_block_desc_groups = num_block_desc_groups;
- }
- __bdesc_group = (const void *)(__pdaf + 1);
- if (bin->base) {
- (*pdaf)->block_desc_groups =
- bin_alloc(bin,
- sizeof(struct ccs_pdaf_pix_loc_block_desc_group) *
- num_block_desc_groups);
- if (!(*pdaf)->block_desc_groups)
- return -ENOMEM;
- } else {
- bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_block_desc_group) *
- num_block_desc_groups);
- }
- for (i = 0; i < num_block_desc_groups; i++) {
- const struct __ccs_data_block_pdaf_pix_loc_block_desc *__bdesc;
- u16 num_block_descs;
- unsigned int j;
- if (!is_contained(__bdesc_group, endp))
- return -ENODATA;
- num_block_descs =
- ((u16)__bdesc_group->num_block_descs[0] << 8) +
- __bdesc_group->num_block_descs[1];
- if (bin->base) {
- (*pdaf)->block_desc_groups[i].repeat_y =
- __bdesc_group->repeat_y;
- (*pdaf)->block_desc_groups[i].num_block_descs =
- num_block_descs;
- }
- __bdesc = (const void *)(__bdesc_group + 1);
- if (bin->base) {
- (*pdaf)->block_desc_groups[i].block_descs =
- bin_alloc(bin,
- sizeof(struct ccs_pdaf_pix_loc_block_desc) *
- num_block_descs);
- if (!(*pdaf)->block_desc_groups[i].block_descs)
- return -ENOMEM;
- } else {
- bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_block_desc) *
- num_block_descs);
- }
- for (j = 0; j < num_block_descs; j++, __bdesc++) {
- struct ccs_pdaf_pix_loc_block_desc *bdesc;
- if (!is_contained(__bdesc, endp))
- return -ENODATA;
- if (max_block_type_id <= __bdesc->block_type_id)
- max_block_type_id = __bdesc->block_type_id + 1;
- if (!bin->base)
- continue;
- bdesc = &(*pdaf)->block_desc_groups[i].block_descs[j];
- bdesc->repeat_x = ((u16)__bdesc->repeat_x[0] << 8)
- + __bdesc->repeat_x[1];
- if (__bdesc->block_type_id >= num_block_descs)
- return -EINVAL;
- bdesc->block_type_id = __bdesc->block_type_id;
- }
- __bdesc_group = (const void *)__bdesc;
- }
- __num_pixel_descs = (const void *)__bdesc_group;
- if (bin->base) {
- (*pdaf)->pixel_desc_groups =
- bin_alloc(bin,
- sizeof(struct ccs_pdaf_pix_loc_pixel_desc_group) *
- max_block_type_id);
- if (!(*pdaf)->pixel_desc_groups)
- return -ENOMEM;
- (*pdaf)->num_pixel_desc_grups = max_block_type_id;
- } else {
- bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_pixel_desc_group) *
- max_block_type_id);
- }
- for (i = 0; i < max_block_type_id; i++) {
- struct ccs_pdaf_pix_loc_pixel_desc_group *pdgroup = NULL;
- unsigned int j;
- if (!is_contained(__num_pixel_descs, endp))
- return -ENODATA;
- if (bin->base) {
- pdgroup = &(*pdaf)->pixel_desc_groups[i];
- pdgroup->descs =
- bin_alloc(bin,
- sizeof(struct ccs_pdaf_pix_loc_pixel_desc) *
- *__num_pixel_descs);
- if (!pdgroup->descs)
- return -ENOMEM;
- pdgroup->num_descs = *__num_pixel_descs;
- } else {
- bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_pixel_desc) *
- *__num_pixel_descs);
- }
- __pixel_desc = (const void *)(__num_pixel_descs + 1);
- for (j = 0; j < *__num_pixel_descs; j++, __pixel_desc++) {
- struct ccs_pdaf_pix_loc_pixel_desc *pdesc;
- if (!is_contained(__pixel_desc, endp))
- return -ENODATA;
- if (!bin->base)
- continue;
- if (!pdgroup)
- return -EIO;
- pdesc = &pdgroup->descs[j];
- pdesc->pixel_type = __pixel_desc->pixel_type;
- pdesc->small_offset_x = __pixel_desc->small_offset_x;
- pdesc->small_offset_y = __pixel_desc->small_offset_y;
- }
- __num_pixel_descs = (const void *)(__pixel_desc + 1);
- }
- return 0;
- }
- static int ccs_data_parse_license(struct bin_container *bin,
- char **__license,
- size_t *__license_length,
- const void *payload, const void *endp)
- {
- size_t size = endp - payload;
- char *license;
- if (!bin->base) {
- bin_reserve(bin, size);
- return 0;
- }
- license = bin_alloc(bin, size);
- if (!license)
- return -ENOMEM;
- memcpy(license, payload, size);
- *__license = license;
- *__license_length = size;
- return 0;
- }
- static int ccs_data_parse_end(bool *end, const void *payload, const void *endp,
- struct device *dev)
- {
- const struct __ccs_data_block_end *__end = payload;
- if (__end + 1 != endp) {
- dev_dbg(dev, "Invalid end block length %u\n",
- (unsigned int)(endp - payload));
- return -ENODATA;
- }
- *end = true;
- return 0;
- }
- static int __ccs_data_parse(struct bin_container *bin,
- struct ccs_data_container *ccsdata,
- const void *data, size_t len, struct device *dev,
- bool verbose)
- {
- const struct __ccs_data_block *block = data;
- const struct __ccs_data_block *endp = data + len;
- unsigned int version;
- bool is_first = true;
- int rval;
- version = ccs_data_parse_format_version(block);
- if (version != CCS_STATIC_DATA_VERSION) {
- dev_dbg(dev, "Don't know how to handle version %u\n", version);
- return -EINVAL;
- }
- if (verbose)
- dev_dbg(dev, "Parsing CCS static data version %u\n", version);
- if (!bin->base)
- *ccsdata = (struct ccs_data_container){ 0 };
- while (block < endp) {
- const struct __ccs_data_block *next_block;
- unsigned int block_id;
- const void *payload;
- rval = ccs_data_block_parse_header(block, is_first, &block_id,
- &payload, &next_block, endp,
- dev,
- bin->base ? false : verbose);
- if (rval < 0)
- return rval;
- switch (block_id) {
- case CCS_DATA_BLOCK_ID_DUMMY:
- break;
- case CCS_DATA_BLOCK_ID_DATA_VERSION:
- rval = ccs_data_parse_version(bin, ccsdata, payload,
- next_block);
- if (rval < 0)
- return rval;
- break;
- case CCS_DATA_BLOCK_ID_SENSOR_READ_ONLY_REGS:
- rval = ccs_data_parse_regs(
- bin, &ccsdata->sensor_read_only_regs,
- &ccsdata->num_sensor_read_only_regs, payload,
- next_block, dev);
- if (rval < 0)
- return rval;
- break;
- case CCS_DATA_BLOCK_ID_SENSOR_MANUFACTURER_REGS:
- rval = ccs_data_parse_regs(
- bin, &ccsdata->sensor_manufacturer_regs,
- &ccsdata->num_sensor_manufacturer_regs, payload,
- next_block, dev);
- if (rval < 0)
- return rval;
- break;
- case CCS_DATA_BLOCK_ID_MODULE_READ_ONLY_REGS:
- rval = ccs_data_parse_regs(
- bin, &ccsdata->module_read_only_regs,
- &ccsdata->num_module_read_only_regs, payload,
- next_block, dev);
- if (rval < 0)
- return rval;
- break;
- case CCS_DATA_BLOCK_ID_MODULE_MANUFACTURER_REGS:
- rval = ccs_data_parse_regs(
- bin, &ccsdata->module_manufacturer_regs,
- &ccsdata->num_module_manufacturer_regs, payload,
- next_block, dev);
- if (rval < 0)
- return rval;
- break;
- case CCS_DATA_BLOCK_ID_SENSOR_PDAF_PIXEL_LOCATION:
- rval = ccs_data_parse_pdaf(bin, &ccsdata->sensor_pdaf,
- payload, next_block, dev);
- if (rval < 0)
- return rval;
- break;
- case CCS_DATA_BLOCK_ID_MODULE_PDAF_PIXEL_LOCATION:
- rval = ccs_data_parse_pdaf(bin, &ccsdata->module_pdaf,
- payload, next_block, dev);
- if (rval < 0)
- return rval;
- break;
- case CCS_DATA_BLOCK_ID_SENSOR_RULE_BASED_BLOCK:
- rval = ccs_data_parse_rules(
- bin, &ccsdata->sensor_rules,
- &ccsdata->num_sensor_rules, payload, next_block,
- dev);
- if (rval < 0)
- return rval;
- break;
- case CCS_DATA_BLOCK_ID_MODULE_RULE_BASED_BLOCK:
- rval = ccs_data_parse_rules(
- bin, &ccsdata->module_rules,
- &ccsdata->num_module_rules, payload, next_block,
- dev);
- if (rval < 0)
- return rval;
- break;
- case CCS_DATA_BLOCK_ID_LICENSE:
- rval = ccs_data_parse_license(bin, &ccsdata->license,
- &ccsdata->license_length,
- payload, next_block);
- if (rval < 0)
- return rval;
- break;
- case CCS_DATA_BLOCK_ID_END:
- rval = ccs_data_parse_end(&ccsdata->end, payload,
- next_block, dev);
- if (rval < 0)
- return rval;
- break;
- default:
- dev_dbg(dev, "WARNING: not handling block ID 0x%2.2x\n",
- block_id);
- }
- block = next_block;
- is_first = false;
- }
- return 0;
- }
- /**
- * ccs_data_parse - Parse a CCS static data file into a usable in-memory
- * data structure
- * @ccsdata: CCS static data in-memory data structure
- * @data: CCS static data binary
- * @len: Length of @data
- * @dev: Device the data is related to (used for printing debug messages)
- * @verbose: Whether to be verbose or not
- */
- int ccs_data_parse(struct ccs_data_container *ccsdata, const void *data,
- size_t len, struct device *dev, bool verbose)
- {
- struct bin_container bin = { 0 };
- int rval;
- rval = __ccs_data_parse(&bin, ccsdata, data, len, dev, verbose);
- if (rval)
- goto out_cleanup;
- rval = bin_backing_alloc(&bin);
- if (rval)
- goto out_cleanup;
- rval = __ccs_data_parse(&bin, ccsdata, data, len, dev, false);
- if (rval)
- goto out_cleanup;
- if (verbose && ccsdata->version)
- print_ccs_data_version(dev, ccsdata->version);
- if (bin.now != bin.end) {
- rval = -EPROTO;
- dev_dbg(dev, "parsing mismatch; base %p; now %p; end %p\n",
- bin.base, bin.now, bin.end);
- goto out_cleanup;
- }
- ccsdata->backing = bin.base;
- return 0;
- out_cleanup:
- kvfree(bin.base);
- memset(ccsdata, 0, sizeof(*ccsdata));
- dev_warn(dev, "failed to parse CCS static data: %d\n", rval);
- return rval;
- }
|