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