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