File Index
Files and directories
Sign in
FILE

ccs-data.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/i2c/ccs/ccs-data.c 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
 17struct bin_container {
 18	void *base;
 19	void *now;
 20	void *end;
 21	size_t size;
 22};
 23
 24static 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
 39static void bin_reserve(struct bin_container *bin, size_t len)
 40{
 41	bin->size += ALIGN(len, 8);
 42}
 43
 44static 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
 62static int
 63ccs_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
117static u8
118ccs_data_parse_format_version(const struct __ccs_data_block *block)
119{
120	return block->id >> CCS_DATA_BLOCK_HEADER_ID_VERSION_SHIFT;
121}
122
123static 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
132static 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
163static 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
172static 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
213static 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
322static 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
341static 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
348static 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
406static 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
431static 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
589static 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
764static 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
789static 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
805static 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 */
944int 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
976out_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}
~/ Read-only file preview.