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