WIP FPC-III support
[linux/fpc-iii.git] / drivers / media / i2c / ccs / ccs-data.c
blob9a6097b088bdfb69d69f9f1d26da62149e0a6a7a
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /*
3 * CCS static data binary parser library
5 * Copyright 2019--2020 Intel Corporation
6 */
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 #include <linux/types.h>
15 #include "ccs-data-defs.h"
17 struct bin_container {
18 void *base;
19 void *now;
20 void *end;
21 size_t size;
24 static void *bin_alloc(struct bin_container *bin, size_t len)
26 void *ptr;
28 len = ALIGN(len, 8);
30 if (bin->end - bin->now < len)
31 return NULL;
33 ptr = bin->now;
34 bin->now += len;
36 return ptr;
39 static void bin_reserve(struct bin_container *bin, size_t len)
41 bin->size += ALIGN(len, 8);
44 static int bin_backing_alloc(struct bin_container *bin)
46 bin->base = bin->now = kvzalloc(bin->size, GFP_KERNEL);
47 if (!bin->base)
48 return -ENOMEM;
50 bin->end = bin->base + bin->size;
52 return 0;
55 #define is_contained(var, endp) \
56 (sizeof(*var) <= (endp) - (void *)(var))
57 #define has_headroom(ptr, headroom, endp) \
58 ((headroom) <= (endp) - (void *)(ptr))
59 #define is_contained_with_headroom(var, headroom, endp) \
60 (sizeof(*var) + (headroom) <= (endp) - (void *)(var))
62 static int
63 ccs_data_parse_length_specifier(const struct __ccs_data_length_specifier *__len,
64 size_t *__hlen, size_t *__plen,
65 const void *endp)
67 size_t hlen, plen;
69 if (!is_contained(__len, endp))
70 return -ENODATA;
72 switch (__len->length >> CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) {
73 case CCS_DATA_LENGTH_SPECIFIER_1:
74 hlen = sizeof(*__len);
75 plen = __len->length &
76 ((1 << CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) - 1);
77 break;
78 case CCS_DATA_LENGTH_SPECIFIER_2: {
79 struct __ccs_data_length_specifier2 *__len2 = (void *)__len;
81 if (!is_contained(__len2, endp))
82 return -ENODATA;
84 hlen = sizeof(*__len2);
85 plen = ((size_t)
86 (__len2->length[0] &
87 ((1 << CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) - 1))
88 << 8) + __len2->length[1];
89 break;
91 case CCS_DATA_LENGTH_SPECIFIER_3: {
92 struct __ccs_data_length_specifier3 *__len3 = (void *)__len;
94 if (!is_contained(__len3, endp))
95 return -ENODATA;
97 hlen = sizeof(*__len3);
98 plen = ((size_t)
99 (__len3->length[0] &
100 ((1 << CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) - 1))
101 << 16) + (__len3->length[0] << 8) + __len3->length[1];
102 break;
104 default:
105 return -EINVAL;
108 if (!has_headroom(__len, hlen + plen, endp))
109 return -ENODATA;
111 *__hlen = hlen;
112 *__plen = plen;
114 return 0;
117 static u8
118 ccs_data_parse_format_version(const struct __ccs_data_block *block)
120 return block->id >> CCS_DATA_BLOCK_HEADER_ID_VERSION_SHIFT;
123 static u8 ccs_data_parse_block_id(const struct __ccs_data_block *block,
124 bool is_first)
126 if (!is_first)
127 return block->id;
129 return block->id & ((1 << CCS_DATA_BLOCK_HEADER_ID_VERSION_SHIFT) - 1);
132 static int ccs_data_parse_version(struct bin_container *bin,
133 struct ccs_data_container *ccsdata,
134 const void *payload, const void *endp)
136 const struct __ccs_data_block_version *v = payload;
137 struct ccs_data_block_version *vv;
139 if (v + 1 != endp)
140 return -ENODATA;
142 if (!bin->base) {
143 bin_reserve(bin, sizeof(*ccsdata->version));
144 return 0;
147 ccsdata->version = bin_alloc(bin, sizeof(*ccsdata->version));
148 if (!ccsdata->version)
149 return -ENOMEM;
151 vv = ccsdata->version;
152 vv->version_major = ((u16)v->static_data_version_major[0] << 8) +
153 v->static_data_version_major[1];
154 vv->version_minor = ((u16)v->static_data_version_minor[0] << 8) +
155 v->static_data_version_major[1];
156 vv->date_year = ((u16)v->year[0] << 8) + v->year[1];
157 vv->date_month = v->month;
158 vv->date_day = v->day;
160 return 0;
163 static void print_ccs_data_version(struct device *dev,
164 struct ccs_data_block_version *v)
166 dev_dbg(dev,
167 "static data version %4.4x.%4.4x, date %4.4u-%2.2u-%2.2u\n",
168 v->version_major, v->version_minor,
169 v->date_year, v->date_month, v->date_day);
172 static int ccs_data_block_parse_header(const struct __ccs_data_block *block,
173 bool is_first, unsigned int *__block_id,
174 const void **payload,
175 const struct __ccs_data_block **next_block,
176 const void *endp, struct device *dev,
177 bool verbose)
179 size_t plen, hlen;
180 u8 block_id;
181 int rval;
183 if (!is_contained(block, endp))
184 return -ENODATA;
186 rval = ccs_data_parse_length_specifier(&block->length, &hlen, &plen,
187 endp);
188 if (rval < 0)
189 return rval;
191 block_id = ccs_data_parse_block_id(block, is_first);
193 if (verbose)
194 dev_dbg(dev,
195 "Block ID 0x%2.2x, header length %zu, payload length %zu\n",
196 block_id, hlen, plen);
198 if (!has_headroom(&block->length, hlen + plen, endp))
199 return -ENODATA;
201 if (__block_id)
202 *__block_id = block_id;
204 if (payload)
205 *payload = (void *)&block->length + hlen;
207 if (next_block)
208 *next_block = (void *)&block->length + hlen + plen;
210 return 0;
213 static int ccs_data_parse_regs(struct bin_container *bin,
214 struct ccs_reg **__regs,
215 size_t *__num_regs, const void *payload,
216 const void *endp, struct device *dev)
218 struct ccs_reg *regs_base, *regs;
219 size_t num_regs = 0;
220 u16 addr = 0;
222 if (bin->base && __regs) {
223 regs = regs_base = bin_alloc(bin, sizeof(*regs) * *__num_regs);
224 if (!regs)
225 return -ENOMEM;
228 while (payload < endp && num_regs < INT_MAX) {
229 const struct __ccs_data_block_regs *r = payload;
230 size_t len;
231 const void *data;
233 if (!is_contained(r, endp))
234 return -ENODATA;
236 switch (r->reg_len >> CCS_DATA_BLOCK_REGS_SEL_SHIFT) {
237 case CCS_DATA_BLOCK_REGS_SEL_REGS:
238 addr += r->reg_len & CCS_DATA_BLOCK_REGS_ADDR_MASK;
239 len = ((r->reg_len & CCS_DATA_BLOCK_REGS_LEN_MASK)
240 >> CCS_DATA_BLOCK_REGS_LEN_SHIFT) + 1;
242 if (!is_contained_with_headroom(r, len, endp))
243 return -ENODATA;
245 data = r + 1;
246 break;
247 case CCS_DATA_BLOCK_REGS_SEL_REGS2: {
248 const struct __ccs_data_block_regs2 *r2 = payload;
250 if (!is_contained(r2, endp))
251 return -ENODATA;
253 addr += ((u16)(r2->reg_len &
254 CCS_DATA_BLOCK_REGS_2_ADDR_MASK) << 8)
255 + r2->addr;
256 len = ((r2->reg_len & CCS_DATA_BLOCK_REGS_2_LEN_MASK)
257 >> CCS_DATA_BLOCK_REGS_2_LEN_SHIFT) + 1;
259 if (!is_contained_with_headroom(r2, len, endp))
260 return -ENODATA;
262 data = r2 + 1;
263 break;
265 case CCS_DATA_BLOCK_REGS_SEL_REGS3: {
266 const struct __ccs_data_block_regs3 *r3 = payload;
268 if (!is_contained(r3, endp))
269 return -ENODATA;
271 addr = ((u16)r3->addr[0] << 8) + r3->addr[1];
272 len = (r3->reg_len & CCS_DATA_BLOCK_REGS_3_LEN_MASK) + 1;
274 if (!is_contained_with_headroom(r3, len, endp))
275 return -ENODATA;
277 data = r3 + 1;
278 break;
280 default:
281 return -EINVAL;
284 num_regs++;
286 if (!bin->base) {
287 bin_reserve(bin, len);
288 } else if (__regs) {
289 regs->addr = addr;
290 regs->len = len;
291 regs->value = bin_alloc(bin, len);
292 if (!regs->value)
293 return -ENOMEM;
295 memcpy(regs->value, data, len);
296 regs++;
299 addr += len;
300 payload = data + len;
303 if (!bin->base)
304 bin_reserve(bin, sizeof(*regs) * num_regs);
306 if (__num_regs)
307 *__num_regs = num_regs;
309 if (bin->base && __regs)
310 *__regs = regs_base;
312 return 0;
315 static int ccs_data_parse_reg_rules(struct bin_container *bin,
316 struct ccs_reg **__regs,
317 size_t *__num_regs,
318 const void *payload,
319 const void *endp, struct device *dev)
321 int rval;
323 if (!bin->base)
324 return ccs_data_parse_regs(bin, NULL, NULL, payload, endp, dev);
326 rval = ccs_data_parse_regs(bin, NULL, __num_regs, payload, endp, dev);
327 if (rval)
328 return rval;
330 return ccs_data_parse_regs(bin, __regs, __num_regs, payload, endp,
331 dev);
334 static void assign_ffd_entry(struct ccs_frame_format_desc *desc,
335 const struct __ccs_data_block_ffd_entry *ent)
337 desc->pixelcode = ent->pixelcode;
338 desc->value = ((u16)ent->value[0] << 8) + ent->value[1];
341 static int ccs_data_parse_ffd(struct bin_container *bin,
342 struct ccs_frame_format_descs **ffd,
343 const void *payload,
344 const void *endp, struct device *dev)
346 const struct __ccs_data_block_ffd *__ffd = payload;
347 const struct __ccs_data_block_ffd_entry *__entry;
348 unsigned int i;
350 if (!is_contained(__ffd, endp))
351 return -ENODATA;
353 if ((void *)__ffd + sizeof(*__ffd) +
354 ((u32)__ffd->num_column_descs +
355 (u32)__ffd->num_row_descs) *
356 sizeof(struct __ccs_data_block_ffd_entry) != endp)
357 return -ENODATA;
359 if (!bin->base) {
360 bin_reserve(bin, sizeof(**ffd));
361 bin_reserve(bin, __ffd->num_column_descs *
362 sizeof(struct ccs_frame_format_desc));
363 bin_reserve(bin, __ffd->num_row_descs *
364 sizeof(struct ccs_frame_format_desc));
366 return 0;
369 *ffd = bin_alloc(bin, sizeof(**ffd));
370 if (!*ffd)
371 return -ENOMEM;
373 (*ffd)->num_column_descs = __ffd->num_column_descs;
374 (*ffd)->num_row_descs = __ffd->num_row_descs;
375 __entry = (void *)(__ffd + 1);
377 (*ffd)->column_descs = bin_alloc(bin, __ffd->num_column_descs *
378 sizeof(*(*ffd)->column_descs));
379 if (!(*ffd)->column_descs)
380 return -ENOMEM;
382 for (i = 0; i < __ffd->num_column_descs; i++, __entry++)
383 assign_ffd_entry(&(*ffd)->column_descs[i], __entry);
385 (*ffd)->row_descs = bin_alloc(bin, __ffd->num_row_descs *
386 sizeof(*(*ffd)->row_descs));
387 if (!(*ffd)->row_descs)
388 return -ENOMEM;
390 for (i = 0; i < __ffd->num_row_descs; i++, __entry++)
391 assign_ffd_entry(&(*ffd)->row_descs[i], __entry);
393 if (__entry != endp)
394 return -EPROTO;
396 return 0;
399 static int ccs_data_parse_pdaf_readout(struct bin_container *bin,
400 struct ccs_pdaf_readout **pdaf_readout,
401 const void *payload,
402 const void *endp, struct device *dev)
404 const struct __ccs_data_block_pdaf_readout *__pdaf = payload;
406 if (!is_contained(__pdaf, endp))
407 return -ENODATA;
409 if (!bin->base) {
410 bin_reserve(bin, sizeof(**pdaf_readout));
411 } else {
412 *pdaf_readout = bin_alloc(bin, sizeof(**pdaf_readout));
413 if (!*pdaf_readout)
414 return -ENOMEM;
416 (*pdaf_readout)->pdaf_readout_info_order =
417 __pdaf->pdaf_readout_info_order;
420 return ccs_data_parse_ffd(bin, !bin->base ? NULL : &(*pdaf_readout)->ffd,
421 __pdaf + 1, endp, dev);
424 static int ccs_data_parse_rules(struct bin_container *bin,
425 struct ccs_rule **__rules,
426 size_t *__num_rules, const void *payload,
427 const void *endp, struct device *dev)
429 struct ccs_rule *rules_base, *rules = NULL, *next_rule;
430 size_t num_rules = 0;
431 const void *__next_rule = payload;
432 int rval;
434 if (bin->base) {
435 rules_base = next_rule =
436 bin_alloc(bin, sizeof(*rules) * *__num_rules);
437 if (!rules_base)
438 return -ENOMEM;
441 while (__next_rule < endp) {
442 size_t rule_hlen, rule_plen, rule_plen2;
443 const u8 *__rule_type;
444 const void *rule_payload;
446 /* Size of a single rule */
447 rval = ccs_data_parse_length_specifier(__next_rule, &rule_hlen,
448 &rule_plen, endp);
450 if (rval < 0)
451 return rval;
453 __rule_type = __next_rule + rule_hlen;
455 if (!is_contained(__rule_type, endp))
456 return -ENODATA;
458 rule_payload = __rule_type + 1;
459 rule_plen2 = rule_plen - sizeof(*__rule_type);
461 switch (*__rule_type) {
462 case CCS_DATA_BLOCK_RULE_ID_IF: {
463 const struct __ccs_data_block_rule_if *__if_rules =
464 rule_payload;
465 const size_t __num_if_rules =
466 rule_plen2 / sizeof(*__if_rules);
467 struct ccs_if_rule *if_rule;
469 if (!has_headroom(__if_rules,
470 sizeof(*__if_rules) * __num_if_rules,
471 rule_payload + rule_plen2))
472 return -ENODATA;
474 /* Also check there is no extra data */
475 if (__if_rules + __num_if_rules !=
476 rule_payload + rule_plen2)
477 return -EINVAL;
479 if (!bin->base) {
480 bin_reserve(bin,
481 sizeof(*if_rule) *
482 __num_if_rules);
483 num_rules++;
484 } else {
485 unsigned int i;
487 rules = next_rule;
488 next_rule++;
490 if_rule = bin_alloc(bin,
491 sizeof(*if_rule) *
492 __num_if_rules);
493 if (!if_rule)
494 return -ENOMEM;
496 for (i = 0; i < __num_if_rules; i++) {
497 if_rule[i].addr =
498 ((u16)__if_rules[i].addr[0]
499 << 8) +
500 __if_rules[i].addr[1];
501 if_rule[i].value = __if_rules[i].value;
502 if_rule[i].mask = __if_rules[i].mask;
505 rules->if_rules = if_rule;
506 rules->num_if_rules = __num_if_rules;
508 break;
510 case CCS_DATA_BLOCK_RULE_ID_READ_ONLY_REGS:
511 rval = ccs_data_parse_reg_rules(bin, &rules->read_only_regs,
512 &rules->num_read_only_regs,
513 rule_payload,
514 rule_payload + rule_plen2,
515 dev);
516 if (rval)
517 return rval;
518 break;
519 case CCS_DATA_BLOCK_RULE_ID_FFD:
520 rval = ccs_data_parse_ffd(bin, &rules->frame_format,
521 rule_payload,
522 rule_payload + rule_plen2,
523 dev);
524 if (rval)
525 return rval;
526 break;
527 case CCS_DATA_BLOCK_RULE_ID_MSR:
528 rval = ccs_data_parse_reg_rules(bin,
529 &rules->manufacturer_regs,
530 &rules->num_manufacturer_regs,
531 rule_payload,
532 rule_payload + rule_plen2,
533 dev);
534 if (rval)
535 return rval;
536 break;
537 case CCS_DATA_BLOCK_RULE_ID_PDAF_READOUT:
538 rval = ccs_data_parse_pdaf_readout(bin,
539 &rules->pdaf_readout,
540 rule_payload,
541 rule_payload + rule_plen2,
542 dev);
543 if (rval)
544 return rval;
545 break;
546 default:
547 dev_dbg(dev,
548 "Don't know how to handle rule type %u!\n",
549 *__rule_type);
550 return -EINVAL;
552 __next_rule = __next_rule + rule_hlen + rule_plen;
555 if (!bin->base) {
556 bin_reserve(bin, sizeof(*rules) * num_rules);
557 *__num_rules = num_rules;
558 } else {
559 *__rules = rules_base;
562 return 0;
565 static int ccs_data_parse_pdaf(struct bin_container *bin, struct ccs_pdaf_pix_loc **pdaf,
566 const void *payload, const void *endp,
567 struct device *dev)
569 const struct __ccs_data_block_pdaf_pix_loc *__pdaf = payload;
570 const struct __ccs_data_block_pdaf_pix_loc_block_desc_group *__bdesc_group;
571 const struct __ccs_data_block_pdaf_pix_loc_pixel_desc *__pixel_desc;
572 unsigned int i;
573 u16 num_block_desc_groups;
574 u8 max_block_type_id = 0;
575 const u8 *__num_pixel_descs;
577 if (!is_contained(__pdaf, endp))
578 return -ENODATA;
580 if (bin->base) {
581 *pdaf = bin_alloc(bin, sizeof(**pdaf));
582 if (!*pdaf)
583 return -ENOMEM;
584 } else {
585 bin_reserve(bin, sizeof(**pdaf));
588 num_block_desc_groups =
589 ((u16)__pdaf->num_block_desc_groups[0] << 8) +
590 __pdaf->num_block_desc_groups[1];
592 if (bin->base) {
593 (*pdaf)->main_offset_x =
594 ((u16)__pdaf->main_offset_x[0] << 8) +
595 __pdaf->main_offset_x[1];
596 (*pdaf)->main_offset_y =
597 ((u16)__pdaf->main_offset_y[0] << 8) +
598 __pdaf->main_offset_y[1];
599 (*pdaf)->global_pdaf_type = __pdaf->global_pdaf_type;
600 (*pdaf)->block_width = __pdaf->block_width;
601 (*pdaf)->block_height = __pdaf->block_height;
602 (*pdaf)->num_block_desc_groups = num_block_desc_groups;
605 __bdesc_group = (const void *)(__pdaf + 1);
607 if (bin->base) {
608 (*pdaf)->block_desc_groups =
609 bin_alloc(bin,
610 sizeof(struct ccs_pdaf_pix_loc_block_desc_group) *
611 num_block_desc_groups);
612 if (!(*pdaf)->block_desc_groups)
613 return -ENOMEM;
614 } else {
615 bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_block_desc_group) *
616 num_block_desc_groups);
619 for (i = 0; i < num_block_desc_groups; i++) {
620 const struct __ccs_data_block_pdaf_pix_loc_block_desc *__bdesc;
621 u16 num_block_descs;
622 unsigned int j;
624 if (!is_contained(__bdesc_group, endp))
625 return -ENODATA;
627 num_block_descs =
628 ((u16)__bdesc_group->num_block_descs[0] << 8) +
629 __bdesc_group->num_block_descs[1];
631 if (bin->base) {
632 (*pdaf)->block_desc_groups[i].repeat_y =
633 __bdesc_group->repeat_y;
634 (*pdaf)->block_desc_groups[i].num_block_descs =
635 num_block_descs;
638 __bdesc = (const void *)(__bdesc_group + 1);
640 if (bin->base) {
641 (*pdaf)->block_desc_groups[i].block_descs =
642 bin_alloc(bin,
643 sizeof(struct ccs_pdaf_pix_loc_block_desc) *
644 num_block_descs);
645 if (!(*pdaf)->block_desc_groups[i].block_descs)
646 return -ENOMEM;
647 } else {
648 bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_block_desc) *
649 num_block_descs);
652 for (j = 0; j < num_block_descs; j++, __bdesc++) {
653 struct ccs_pdaf_pix_loc_block_desc *bdesc;
655 if (!is_contained(__bdesc, endp))
656 return -ENODATA;
658 if (max_block_type_id <= __bdesc->block_type_id)
659 max_block_type_id = __bdesc->block_type_id + 1;
661 if (!bin->base)
662 continue;
664 bdesc = &(*pdaf)->block_desc_groups[i].block_descs[j];
666 bdesc->repeat_x = ((u16)__bdesc->repeat_x[0] << 8)
667 + __bdesc->repeat_x[1];
669 if (__bdesc->block_type_id >= num_block_descs)
670 return -EINVAL;
672 bdesc->block_type_id = __bdesc->block_type_id;
675 __bdesc_group = (const void *)__bdesc;
678 __num_pixel_descs = (const void *)__bdesc_group;
680 if (bin->base) {
681 (*pdaf)->pixel_desc_groups =
682 bin_alloc(bin,
683 sizeof(struct ccs_pdaf_pix_loc_pixel_desc_group) *
684 max_block_type_id);
685 if (!(*pdaf)->pixel_desc_groups)
686 return -ENOMEM;
687 (*pdaf)->num_pixel_desc_grups = max_block_type_id;
688 } else {
689 bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_pixel_desc_group) *
690 max_block_type_id);
693 for (i = 0; i < max_block_type_id; i++) {
694 struct ccs_pdaf_pix_loc_pixel_desc_group *pdgroup;
695 unsigned int j;
697 if (!is_contained(__num_pixel_descs, endp))
698 return -ENODATA;
700 if (bin->base) {
701 pdgroup = &(*pdaf)->pixel_desc_groups[i];
702 pdgroup->descs =
703 bin_alloc(bin,
704 sizeof(struct ccs_pdaf_pix_loc_pixel_desc) *
705 *__num_pixel_descs);
706 if (!pdgroup->descs)
707 return -ENOMEM;
708 pdgroup->num_descs = *__num_pixel_descs;
709 } else {
710 bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_pixel_desc) *
711 *__num_pixel_descs);
714 __pixel_desc = (const void *)(__num_pixel_descs + 1);
716 for (j = 0; j < *__num_pixel_descs; j++, __pixel_desc++) {
717 struct ccs_pdaf_pix_loc_pixel_desc *pdesc;
719 if (!is_contained(__pixel_desc, endp))
720 return -ENODATA;
722 if (!bin->base)
723 continue;
725 pdesc = &pdgroup->descs[j];
726 pdesc->pixel_type = __pixel_desc->pixel_type;
727 pdesc->small_offset_x = __pixel_desc->small_offset_x;
728 pdesc->small_offset_y = __pixel_desc->small_offset_y;
731 __num_pixel_descs = (const void *)(__pixel_desc + 1);
734 return 0;
737 static int ccs_data_parse_license(struct bin_container *bin,
738 char **__license,
739 size_t *__license_length,
740 const void *payload, const void *endp)
742 size_t size = endp - payload;
743 char *license;
745 if (!bin->base) {
746 bin_reserve(bin, size);
747 return 0;
750 license = bin_alloc(bin, size);
751 if (!license)
752 return -ENOMEM;
754 memcpy(license, payload, size);
756 *__license = license;
757 *__license_length = size;
759 return 0;
762 static int ccs_data_parse_end(bool *end, const void *payload, const void *endp,
763 struct device *dev)
765 const struct __ccs_data_block_end *__end = payload;
767 if (__end + 1 != endp) {
768 dev_dbg(dev, "Invalid end block length %u\n",
769 (unsigned int)(endp - payload));
770 return -ENODATA;
773 *end = true;
775 return 0;
778 static int __ccs_data_parse(struct bin_container *bin,
779 struct ccs_data_container *ccsdata,
780 const void *data, size_t len, struct device *dev,
781 bool verbose)
783 const struct __ccs_data_block *block = data;
784 const struct __ccs_data_block *endp = data + len;
785 unsigned int version;
786 bool is_first = true;
787 int rval;
789 version = ccs_data_parse_format_version(block);
790 if (version != CCS_STATIC_DATA_VERSION) {
791 dev_dbg(dev, "Don't know how to handle version %u\n", version);
792 return -EINVAL;
795 if (verbose)
796 dev_dbg(dev, "Parsing CCS static data version %u\n", version);
798 if (!bin->base)
799 *ccsdata = (struct ccs_data_container){ 0 };
801 while (block < endp) {
802 const struct __ccs_data_block *next_block;
803 unsigned int block_id;
804 const void *payload;
806 rval = ccs_data_block_parse_header(block, is_first, &block_id,
807 &payload, &next_block, endp,
808 dev,
809 bin->base ? false : verbose);
811 if (rval < 0)
812 return rval;
814 switch (block_id) {
815 case CCS_DATA_BLOCK_ID_DUMMY:
816 break;
817 case CCS_DATA_BLOCK_ID_DATA_VERSION:
818 rval = ccs_data_parse_version(bin, ccsdata, payload,
819 next_block);
820 if (rval < 0)
821 return rval;
822 break;
823 case CCS_DATA_BLOCK_ID_SENSOR_READ_ONLY_REGS:
824 rval = ccs_data_parse_regs(
825 bin, &ccsdata->sensor_read_only_regs,
826 &ccsdata->num_sensor_read_only_regs, payload,
827 next_block, dev);
828 if (rval < 0)
829 return rval;
830 break;
831 case CCS_DATA_BLOCK_ID_SENSOR_MANUFACTURER_REGS:
832 rval = ccs_data_parse_regs(
833 bin, &ccsdata->sensor_manufacturer_regs,
834 &ccsdata->num_sensor_manufacturer_regs, payload,
835 next_block, dev);
836 if (rval < 0)
837 return rval;
838 break;
839 case CCS_DATA_BLOCK_ID_MODULE_READ_ONLY_REGS:
840 rval = ccs_data_parse_regs(
841 bin, &ccsdata->module_read_only_regs,
842 &ccsdata->num_module_read_only_regs, payload,
843 next_block, dev);
844 if (rval < 0)
845 return rval;
846 break;
847 case CCS_DATA_BLOCK_ID_MODULE_MANUFACTURER_REGS:
848 rval = ccs_data_parse_regs(
849 bin, &ccsdata->module_manufacturer_regs,
850 &ccsdata->num_module_manufacturer_regs, payload,
851 next_block, dev);
852 if (rval < 0)
853 return rval;
854 break;
855 case CCS_DATA_BLOCK_ID_SENSOR_PDAF_PIXEL_LOCATION:
856 rval = ccs_data_parse_pdaf(bin, &ccsdata->sensor_pdaf,
857 payload, next_block, dev);
858 if (rval < 0)
859 return rval;
860 break;
861 case CCS_DATA_BLOCK_ID_MODULE_PDAF_PIXEL_LOCATION:
862 rval = ccs_data_parse_pdaf(bin, &ccsdata->module_pdaf,
863 payload, next_block, dev);
864 if (rval < 0)
865 return rval;
866 break;
867 case CCS_DATA_BLOCK_ID_SENSOR_RULE_BASED_BLOCK:
868 rval = ccs_data_parse_rules(
869 bin, &ccsdata->sensor_rules,
870 &ccsdata->num_sensor_rules, payload, next_block,
871 dev);
872 if (rval < 0)
873 return rval;
874 break;
875 case CCS_DATA_BLOCK_ID_MODULE_RULE_BASED_BLOCK:
876 rval = ccs_data_parse_rules(
877 bin, &ccsdata->module_rules,
878 &ccsdata->num_module_rules, payload, next_block,
879 dev);
880 if (rval < 0)
881 return rval;
882 break;
883 case CCS_DATA_BLOCK_ID_LICENSE:
884 rval = ccs_data_parse_license(bin, &ccsdata->license,
885 &ccsdata->license_length,
886 payload, next_block);
887 if (rval < 0)
888 return rval;
889 break;
890 case CCS_DATA_BLOCK_ID_END:
891 rval = ccs_data_parse_end(&ccsdata->end, payload,
892 next_block, dev);
893 if (rval < 0)
894 return rval;
895 break;
896 default:
897 dev_dbg(dev, "WARNING: not handling block ID 0x%2.2x\n",
898 block_id);
901 block = next_block;
902 is_first = false;
905 return 0;
909 * ccs_data_parse - Parse a CCS static data file into a usable in-memory
910 * data structure
911 * @ccsdata: CCS static data in-memory data structure
912 * @data: CCS static data binary
913 * @len: Length of @data
914 * @dev: Device the data is related to (used for printing debug messages)
915 * @verbose: Whether to be verbose or not
917 int ccs_data_parse(struct ccs_data_container *ccsdata, const void *data,
918 size_t len, struct device *dev, bool verbose)
920 struct bin_container bin = { 0 };
921 int rval;
923 rval = __ccs_data_parse(&bin, ccsdata, data, len, dev, verbose);
924 if (rval)
925 return rval;
927 rval = bin_backing_alloc(&bin);
928 if (rval)
929 return rval;
931 rval = __ccs_data_parse(&bin, ccsdata, data, len, dev, false);
932 if (rval)
933 goto out_free;
935 if (verbose && ccsdata->version)
936 print_ccs_data_version(dev, ccsdata->version);
938 if (bin.now != bin.end) {
939 rval = -EPROTO;
940 dev_dbg(dev, "parsing mismatch; base %p; now %p; end %p\n",
941 bin.base, bin.now, bin.end);
942 goto out_free;
945 ccsdata->backing = bin.base;
947 return 0;
949 out_free:
950 kvfree(bin.base);
952 return rval;