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