ccs-data.c (23521B)
1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2/* 3 * CCS static data binary parser library 4 * 5 * Copyright 2019--2020 Intel Corporation 6 */ 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 int 62ccs_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 u8 117ccs_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 switch (*__rule_type) { 468 case CCS_DATA_BLOCK_RULE_ID_IF: { 469 const struct __ccs_data_block_rule_if *__if_rules = 470 rule_payload; 471 const size_t __num_if_rules = 472 rule_plen2 / sizeof(*__if_rules); 473 struct ccs_if_rule *if_rule; 474 475 if (!has_headroom(__if_rules, 476 sizeof(*__if_rules) * __num_if_rules, 477 rule_payload + rule_plen2)) 478 return -ENODATA; 479 480 /* Also check there is no extra data */ 481 if (__if_rules + __num_if_rules != 482 rule_payload + rule_plen2) 483 return -EINVAL; 484 485 if (!bin->base) { 486 bin_reserve(bin, 487 sizeof(*if_rule) * 488 __num_if_rules); 489 num_rules++; 490 } else { 491 unsigned int i; 492 493 if (!next_rule) 494 return -EIO; 495 496 rules = next_rule; 497 next_rule++; 498 499 if_rule = bin_alloc(bin, 500 sizeof(*if_rule) * 501 __num_if_rules); 502 if (!if_rule) 503 return -ENOMEM; 504 505 for (i = 0; i < __num_if_rules; i++) { 506 if_rule[i].addr = 507 ((u16)__if_rules[i].addr[0] 508 << 8) + 509 __if_rules[i].addr[1]; 510 if_rule[i].value = __if_rules[i].value; 511 if_rule[i].mask = __if_rules[i].mask; 512 } 513 514 rules->if_rules = if_rule; 515 rules->num_if_rules = __num_if_rules; 516 } 517 break; 518 } 519 case CCS_DATA_BLOCK_RULE_ID_READ_ONLY_REGS: 520 rval = ccs_data_parse_reg_rules(bin, &rules->read_only_regs, 521 &rules->num_read_only_regs, 522 rule_payload, 523 rule_payload + rule_plen2, 524 dev); 525 if (rval) 526 return rval; 527 break; 528 case CCS_DATA_BLOCK_RULE_ID_FFD: 529 rval = ccs_data_parse_ffd(bin, &rules->frame_format, 530 rule_payload, 531 rule_payload + rule_plen2, 532 dev); 533 if (rval) 534 return rval; 535 break; 536 case CCS_DATA_BLOCK_RULE_ID_MSR: 537 rval = ccs_data_parse_reg_rules(bin, 538 &rules->manufacturer_regs, 539 &rules->num_manufacturer_regs, 540 rule_payload, 541 rule_payload + rule_plen2, 542 dev); 543 if (rval) 544 return rval; 545 break; 546 case CCS_DATA_BLOCK_RULE_ID_PDAF_READOUT: 547 rval = ccs_data_parse_pdaf_readout(bin, 548 &rules->pdaf_readout, 549 rule_payload, 550 rule_payload + rule_plen2, 551 dev); 552 if (rval) 553 return rval; 554 break; 555 default: 556 dev_dbg(dev, 557 "Don't know how to handle rule type %u!\n", 558 *__rule_type); 559 return -EINVAL; 560 } 561 __next_rule = __next_rule + rule_hlen + rule_plen; 562 } 563 564 if (!bin->base) { 565 bin_reserve(bin, sizeof(*rules) * num_rules); 566 *__num_rules = num_rules; 567 } else { 568 if (!rules_base) 569 return -EIO; 570 571 *__rules = rules_base; 572 } 573 574 return 0; 575} 576 577static int ccs_data_parse_pdaf(struct bin_container *bin, struct ccs_pdaf_pix_loc **pdaf, 578 const void *payload, const void *endp, 579 struct device *dev) 580{ 581 const struct __ccs_data_block_pdaf_pix_loc *__pdaf = payload; 582 const struct __ccs_data_block_pdaf_pix_loc_block_desc_group *__bdesc_group; 583 const struct __ccs_data_block_pdaf_pix_loc_pixel_desc *__pixel_desc; 584 unsigned int i; 585 u16 num_block_desc_groups; 586 u8 max_block_type_id = 0; 587 const u8 *__num_pixel_descs; 588 589 if (!is_contained(__pdaf, endp)) 590 return -ENODATA; 591 592 if (bin->base) { 593 *pdaf = bin_alloc(bin, sizeof(**pdaf)); 594 if (!*pdaf) 595 return -ENOMEM; 596 } else { 597 bin_reserve(bin, sizeof(**pdaf)); 598 } 599 600 num_block_desc_groups = 601 ((u16)__pdaf->num_block_desc_groups[0] << 8) + 602 __pdaf->num_block_desc_groups[1]; 603 604 if (bin->base) { 605 (*pdaf)->main_offset_x = 606 ((u16)__pdaf->main_offset_x[0] << 8) + 607 __pdaf->main_offset_x[1]; 608 (*pdaf)->main_offset_y = 609 ((u16)__pdaf->main_offset_y[0] << 8) + 610 __pdaf->main_offset_y[1]; 611 (*pdaf)->global_pdaf_type = __pdaf->global_pdaf_type; 612 (*pdaf)->block_width = __pdaf->block_width; 613 (*pdaf)->block_height = __pdaf->block_height; 614 (*pdaf)->num_block_desc_groups = num_block_desc_groups; 615 } 616 617 __bdesc_group = (const void *)(__pdaf + 1); 618 619 if (bin->base) { 620 (*pdaf)->block_desc_groups = 621 bin_alloc(bin, 622 sizeof(struct ccs_pdaf_pix_loc_block_desc_group) * 623 num_block_desc_groups); 624 if (!(*pdaf)->block_desc_groups) 625 return -ENOMEM; 626 } else { 627 bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_block_desc_group) * 628 num_block_desc_groups); 629 } 630 631 for (i = 0; i < num_block_desc_groups; i++) { 632 const struct __ccs_data_block_pdaf_pix_loc_block_desc *__bdesc; 633 u16 num_block_descs; 634 unsigned int j; 635 636 if (!is_contained(__bdesc_group, endp)) 637 return -ENODATA; 638 639 num_block_descs = 640 ((u16)__bdesc_group->num_block_descs[0] << 8) + 641 __bdesc_group->num_block_descs[1]; 642 643 if (bin->base) { 644 (*pdaf)->block_desc_groups[i].repeat_y = 645 __bdesc_group->repeat_y; 646 (*pdaf)->block_desc_groups[i].num_block_descs = 647 num_block_descs; 648 } 649 650 __bdesc = (const void *)(__bdesc_group + 1); 651 652 if (bin->base) { 653 (*pdaf)->block_desc_groups[i].block_descs = 654 bin_alloc(bin, 655 sizeof(struct ccs_pdaf_pix_loc_block_desc) * 656 num_block_descs); 657 if (!(*pdaf)->block_desc_groups[i].block_descs) 658 return -ENOMEM; 659 } else { 660 bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_block_desc) * 661 num_block_descs); 662 } 663 664 for (j = 0; j < num_block_descs; j++, __bdesc++) { 665 struct ccs_pdaf_pix_loc_block_desc *bdesc; 666 667 if (!is_contained(__bdesc, endp)) 668 return -ENODATA; 669 670 if (max_block_type_id <= __bdesc->block_type_id) 671 max_block_type_id = __bdesc->block_type_id + 1; 672 673 if (!bin->base) 674 continue; 675 676 bdesc = &(*pdaf)->block_desc_groups[i].block_descs[j]; 677 678 bdesc->repeat_x = ((u16)__bdesc->repeat_x[0] << 8) 679 + __bdesc->repeat_x[1]; 680 681 if (__bdesc->block_type_id >= num_block_descs) 682 return -EINVAL; 683 684 bdesc->block_type_id = __bdesc->block_type_id; 685 } 686 687 __bdesc_group = (const void *)__bdesc; 688 } 689 690 __num_pixel_descs = (const void *)__bdesc_group; 691 692 if (bin->base) { 693 (*pdaf)->pixel_desc_groups = 694 bin_alloc(bin, 695 sizeof(struct ccs_pdaf_pix_loc_pixel_desc_group) * 696 max_block_type_id); 697 if (!(*pdaf)->pixel_desc_groups) 698 return -ENOMEM; 699 (*pdaf)->num_pixel_desc_grups = max_block_type_id; 700 } else { 701 bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_pixel_desc_group) * 702 max_block_type_id); 703 } 704 705 for (i = 0; i < max_block_type_id; i++) { 706 struct ccs_pdaf_pix_loc_pixel_desc_group *pdgroup = NULL; 707 unsigned int j; 708 709 if (!is_contained(__num_pixel_descs, endp)) 710 return -ENODATA; 711 712 if (bin->base) { 713 pdgroup = &(*pdaf)->pixel_desc_groups[i]; 714 pdgroup->descs = 715 bin_alloc(bin, 716 sizeof(struct ccs_pdaf_pix_loc_pixel_desc) * 717 *__num_pixel_descs); 718 if (!pdgroup->descs) 719 return -ENOMEM; 720 pdgroup->num_descs = *__num_pixel_descs; 721 } else { 722 bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_pixel_desc) * 723 *__num_pixel_descs); 724 } 725 726 __pixel_desc = (const void *)(__num_pixel_descs + 1); 727 728 for (j = 0; j < *__num_pixel_descs; j++, __pixel_desc++) { 729 struct ccs_pdaf_pix_loc_pixel_desc *pdesc; 730 731 if (!is_contained(__pixel_desc, endp)) 732 return -ENODATA; 733 734 if (!bin->base) 735 continue; 736 737 if (!pdgroup) 738 return -EIO; 739 740 pdesc = &pdgroup->descs[j]; 741 pdesc->pixel_type = __pixel_desc->pixel_type; 742 pdesc->small_offset_x = __pixel_desc->small_offset_x; 743 pdesc->small_offset_y = __pixel_desc->small_offset_y; 744 } 745 746 __num_pixel_descs = (const void *)(__pixel_desc + 1); 747 } 748 749 return 0; 750} 751 752static int ccs_data_parse_license(struct bin_container *bin, 753 char **__license, 754 size_t *__license_length, 755 const void *payload, const void *endp) 756{ 757 size_t size = endp - payload; 758 char *license; 759 760 if (!bin->base) { 761 bin_reserve(bin, size); 762 return 0; 763 } 764 765 license = bin_alloc(bin, size); 766 if (!license) 767 return -ENOMEM; 768 769 memcpy(license, payload, size); 770 771 *__license = license; 772 *__license_length = size; 773 774 return 0; 775} 776 777static int ccs_data_parse_end(bool *end, const void *payload, const void *endp, 778 struct device *dev) 779{ 780 const struct __ccs_data_block_end *__end = payload; 781 782 if (__end + 1 != endp) { 783 dev_dbg(dev, "Invalid end block length %u\n", 784 (unsigned int)(endp - payload)); 785 return -ENODATA; 786 } 787 788 *end = true; 789 790 return 0; 791} 792 793static int __ccs_data_parse(struct bin_container *bin, 794 struct ccs_data_container *ccsdata, 795 const void *data, size_t len, struct device *dev, 796 bool verbose) 797{ 798 const struct __ccs_data_block *block = data; 799 const struct __ccs_data_block *endp = data + len; 800 unsigned int version; 801 bool is_first = true; 802 int rval; 803 804 version = ccs_data_parse_format_version(block); 805 if (version != CCS_STATIC_DATA_VERSION) { 806 dev_dbg(dev, "Don't know how to handle version %u\n", version); 807 return -EINVAL; 808 } 809 810 if (verbose) 811 dev_dbg(dev, "Parsing CCS static data version %u\n", version); 812 813 if (!bin->base) 814 *ccsdata = (struct ccs_data_container){ 0 }; 815 816 while (block < endp) { 817 const struct __ccs_data_block *next_block; 818 unsigned int block_id; 819 const void *payload; 820 821 rval = ccs_data_block_parse_header(block, is_first, &block_id, 822 &payload, &next_block, endp, 823 dev, 824 bin->base ? false : verbose); 825 826 if (rval < 0) 827 return rval; 828 829 switch (block_id) { 830 case CCS_DATA_BLOCK_ID_DUMMY: 831 break; 832 case CCS_DATA_BLOCK_ID_DATA_VERSION: 833 rval = ccs_data_parse_version(bin, ccsdata, payload, 834 next_block); 835 if (rval < 0) 836 return rval; 837 break; 838 case CCS_DATA_BLOCK_ID_SENSOR_READ_ONLY_REGS: 839 rval = ccs_data_parse_regs( 840 bin, &ccsdata->sensor_read_only_regs, 841 &ccsdata->num_sensor_read_only_regs, payload, 842 next_block, dev); 843 if (rval < 0) 844 return rval; 845 break; 846 case CCS_DATA_BLOCK_ID_SENSOR_MANUFACTURER_REGS: 847 rval = ccs_data_parse_regs( 848 bin, &ccsdata->sensor_manufacturer_regs, 849 &ccsdata->num_sensor_manufacturer_regs, payload, 850 next_block, dev); 851 if (rval < 0) 852 return rval; 853 break; 854 case CCS_DATA_BLOCK_ID_MODULE_READ_ONLY_REGS: 855 rval = ccs_data_parse_regs( 856 bin, &ccsdata->module_read_only_regs, 857 &ccsdata->num_module_read_only_regs, payload, 858 next_block, dev); 859 if (rval < 0) 860 return rval; 861 break; 862 case CCS_DATA_BLOCK_ID_MODULE_MANUFACTURER_REGS: 863 rval = ccs_data_parse_regs( 864 bin, &ccsdata->module_manufacturer_regs, 865 &ccsdata->num_module_manufacturer_regs, payload, 866 next_block, dev); 867 if (rval < 0) 868 return rval; 869 break; 870 case CCS_DATA_BLOCK_ID_SENSOR_PDAF_PIXEL_LOCATION: 871 rval = ccs_data_parse_pdaf(bin, &ccsdata->sensor_pdaf, 872 payload, next_block, dev); 873 if (rval < 0) 874 return rval; 875 break; 876 case CCS_DATA_BLOCK_ID_MODULE_PDAF_PIXEL_LOCATION: 877 rval = ccs_data_parse_pdaf(bin, &ccsdata->module_pdaf, 878 payload, next_block, dev); 879 if (rval < 0) 880 return rval; 881 break; 882 case CCS_DATA_BLOCK_ID_SENSOR_RULE_BASED_BLOCK: 883 rval = ccs_data_parse_rules( 884 bin, &ccsdata->sensor_rules, 885 &ccsdata->num_sensor_rules, payload, next_block, 886 dev); 887 if (rval < 0) 888 return rval; 889 break; 890 case CCS_DATA_BLOCK_ID_MODULE_RULE_BASED_BLOCK: 891 rval = ccs_data_parse_rules( 892 bin, &ccsdata->module_rules, 893 &ccsdata->num_module_rules, payload, next_block, 894 dev); 895 if (rval < 0) 896 return rval; 897 break; 898 case CCS_DATA_BLOCK_ID_LICENSE: 899 rval = ccs_data_parse_license(bin, &ccsdata->license, 900 &ccsdata->license_length, 901 payload, next_block); 902 if (rval < 0) 903 return rval; 904 break; 905 case CCS_DATA_BLOCK_ID_END: 906 rval = ccs_data_parse_end(&ccsdata->end, payload, 907 next_block, dev); 908 if (rval < 0) 909 return rval; 910 break; 911 default: 912 dev_dbg(dev, "WARNING: not handling block ID 0x%2.2x\n", 913 block_id); 914 } 915 916 block = next_block; 917 is_first = false; 918 } 919 920 return 0; 921} 922 923/** 924 * ccs_data_parse - Parse a CCS static data file into a usable in-memory 925 * data structure 926 * @ccsdata: CCS static data in-memory data structure 927 * @data: CCS static data binary 928 * @len: Length of @data 929 * @dev: Device the data is related to (used for printing debug messages) 930 * @verbose: Whether to be verbose or not 931 */ 932int ccs_data_parse(struct ccs_data_container *ccsdata, const void *data, 933 size_t len, struct device *dev, bool verbose) 934{ 935 struct bin_container bin = { 0 }; 936 int rval; 937 938 rval = __ccs_data_parse(&bin, ccsdata, data, len, dev, verbose); 939 if (rval) 940 return rval; 941 942 rval = bin_backing_alloc(&bin); 943 if (rval) 944 return rval; 945 946 rval = __ccs_data_parse(&bin, ccsdata, data, len, dev, false); 947 if (rval) 948 goto out_free; 949 950 if (verbose && ccsdata->version) 951 print_ccs_data_version(dev, ccsdata->version); 952 953 if (bin.now != bin.end) { 954 rval = -EPROTO; 955 dev_dbg(dev, "parsing mismatch; base %p; now %p; end %p\n", 956 bin.base, bin.now, bin.end); 957 goto out_free; 958 } 959 960 ccsdata->backing = bin.base; 961 962 return 0; 963 964out_free: 965 kvfree(bin.base); 966 967 return rval; 968}