]> Git Repo - linux.git/blob - drivers/media/i2c/ccs/ccs-data.c
Linux 6.14-rc3
[linux.git] / drivers / media / i2c / ccs / ccs-data.c
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
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
39 static void bin_reserve(struct bin_container *bin, size_t len)
40 {
41         bin->size += ALIGN(len, 8);
42 }
43
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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  */
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         dev_warn(dev, "failed to parse CCS static data: %d\n", rval);
980
981         return rval;
982 }
This page took 0.089285 seconds and 4 git commands to generate.