brintos

brintos / linux-shallow public Read only

0
0
Text · 23.3 KiB · 08400ed Raw
980 lines · c
1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause2/*3 * CCS static data binary parser library4 *5 * Copyright 2019--2020 Intel Corporation6 */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 16struct bin_container {17	void *base;18	void *now;19	void *end;20	size_t size;21};22 23static 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 38static void bin_reserve(struct bin_container *bin, size_t len)39{40	bin->size += ALIGN(len, 8);41}42 43static 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 61static int62ccs_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 116static u8117ccs_data_parse_format_version(const struct __ccs_data_block *block)118{119	return block->id >> CCS_DATA_BLOCK_HEADER_ID_VERSION_SHIFT;120}121 122static 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 131static 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 162static 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 171static 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 212static 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 321static 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 340static 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 347static 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 405static 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 430static 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 588static 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 763static 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 788static 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 804static 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-memory936 *		    data structure937 * @ccsdata:	CCS static data in-memory data structure938 * @data:	CCS static data binary939 * @len:	Length of @data940 * @dev:	Device the data is related to (used for printing debug messages)941 * @verbose:	Whether to be verbose or not942 */943int 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 975out_free:976	kvfree(bin.base);977 978	return rval;979}980