brintos

brintos / linux-shallow public Read only

0
0
Text · 12.6 KiB · 8ae3ad8 Raw
564 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *4 *  Copyright (C) 2005 Mike Isely <isely@pobox.com>5 */6 7#include "pvrusb2-ctrl.h"8#include "pvrusb2-hdw-internal.h"9#include <linux/errno.h>10#include <linux/string.h>11#include <linux/mutex.h>12 13 14static int pvr2_ctrl_range_check(struct pvr2_ctrl *cptr,int val)15{16	if (cptr->info->check_value) {17		if (!cptr->info->check_value(cptr,val)) return -ERANGE;18	} else if (cptr->info->type == pvr2_ctl_enum) {19		if (val < 0) return -ERANGE;20		if (val >= cptr->info->def.type_enum.count) return -ERANGE;21	} else {22		int lim;23		lim = cptr->info->def.type_int.min_value;24		if (cptr->info->get_min_value) {25			cptr->info->get_min_value(cptr,&lim);26		}27		if (val < lim) return -ERANGE;28		lim = cptr->info->def.type_int.max_value;29		if (cptr->info->get_max_value) {30			cptr->info->get_max_value(cptr,&lim);31		}32		if (val > lim) return -ERANGE;33	}34	return 0;35}36 37 38/* Set the given control. */39int pvr2_ctrl_set_value(struct pvr2_ctrl *cptr,int val)40{41	return pvr2_ctrl_set_mask_value(cptr,~0,val);42}43 44 45/* Set/clear specific bits of the given control. */46int pvr2_ctrl_set_mask_value(struct pvr2_ctrl *cptr,int mask,int val)47{48	int ret = 0;49	if (!cptr) return -EINVAL;50	LOCK_TAKE(cptr->hdw->big_lock); do {51		if (cptr->info->set_value) {52			if (cptr->info->type == pvr2_ctl_bitmask) {53				mask &= cptr->info->def.type_bitmask.valid_bits;54			} else if ((cptr->info->type == pvr2_ctl_int)||55				   (cptr->info->type == pvr2_ctl_enum)) {56				ret = pvr2_ctrl_range_check(cptr,val);57				if (ret < 0) break;58			} else if (cptr->info->type != pvr2_ctl_bool) {59				break;60			}61			ret = cptr->info->set_value(cptr,mask,val);62		} else {63			ret = -EPERM;64		}65	} while(0); LOCK_GIVE(cptr->hdw->big_lock);66	return ret;67}68 69 70/* Get the current value of the given control. */71int pvr2_ctrl_get_value(struct pvr2_ctrl *cptr,int *valptr)72{73	int ret = 0;74	if (!cptr) return -EINVAL;75	LOCK_TAKE(cptr->hdw->big_lock); do {76		ret = cptr->info->get_value(cptr,valptr);77	} while(0); LOCK_GIVE(cptr->hdw->big_lock);78	return ret;79}80 81 82/* Retrieve control's type */83enum pvr2_ctl_type pvr2_ctrl_get_type(struct pvr2_ctrl *cptr)84{85	if (!cptr) return pvr2_ctl_int;86	return cptr->info->type;87}88 89 90/* Retrieve control's maximum value (int type) */91int pvr2_ctrl_get_max(struct pvr2_ctrl *cptr)92{93	int ret = 0;94	if (!cptr) return 0;95	LOCK_TAKE(cptr->hdw->big_lock); do {96		if (cptr->info->get_max_value) {97			cptr->info->get_max_value(cptr,&ret);98		} else if (cptr->info->type == pvr2_ctl_int) {99			ret = cptr->info->def.type_int.max_value;100		}101	} while(0); LOCK_GIVE(cptr->hdw->big_lock);102	return ret;103}104 105 106/* Retrieve control's minimum value (int type) */107int pvr2_ctrl_get_min(struct pvr2_ctrl *cptr)108{109	int ret = 0;110	if (!cptr) return 0;111	LOCK_TAKE(cptr->hdw->big_lock); do {112		if (cptr->info->get_min_value) {113			cptr->info->get_min_value(cptr,&ret);114		} else if (cptr->info->type == pvr2_ctl_int) {115			ret = cptr->info->def.type_int.min_value;116		}117	} while(0); LOCK_GIVE(cptr->hdw->big_lock);118	return ret;119}120 121 122/* Retrieve control's default value (any type) */123int pvr2_ctrl_get_def(struct pvr2_ctrl *cptr, int *valptr)124{125	int ret = 0;126	if (!cptr) return -EINVAL;127	LOCK_TAKE(cptr->hdw->big_lock); do {128		if (cptr->info->get_def_value) {129			ret = cptr->info->get_def_value(cptr, valptr);130		} else {131			*valptr = cptr->info->default_value;132		}133	} while(0); LOCK_GIVE(cptr->hdw->big_lock);134	return ret;135}136 137 138/* Retrieve control's enumeration count (enum only) */139int pvr2_ctrl_get_cnt(struct pvr2_ctrl *cptr)140{141	int ret = 0;142	if (!cptr) return 0;143	LOCK_TAKE(cptr->hdw->big_lock); do {144		if (cptr->info->type == pvr2_ctl_enum) {145			ret = cptr->info->def.type_enum.count;146		}147	} while(0); LOCK_GIVE(cptr->hdw->big_lock);148	return ret;149}150 151 152/* Retrieve control's valid mask bits (bit mask only) */153int pvr2_ctrl_get_mask(struct pvr2_ctrl *cptr)154{155	int ret = 0;156	if (!cptr) return 0;157	LOCK_TAKE(cptr->hdw->big_lock); do {158		if (cptr->info->type == pvr2_ctl_bitmask) {159			ret = cptr->info->def.type_bitmask.valid_bits;160		}161	} while(0); LOCK_GIVE(cptr->hdw->big_lock);162	return ret;163}164 165 166/* Retrieve the control's name */167const char *pvr2_ctrl_get_name(struct pvr2_ctrl *cptr)168{169	if (!cptr) return NULL;170	return cptr->info->name;171}172 173 174/* Retrieve the control's desc */175const char *pvr2_ctrl_get_desc(struct pvr2_ctrl *cptr)176{177	if (!cptr) return NULL;178	return cptr->info->desc;179}180 181 182/* Retrieve a control enumeration or bit mask value */183int pvr2_ctrl_get_valname(struct pvr2_ctrl *cptr,int val,184			  char *bptr,unsigned int bmax,185			  unsigned int *blen)186{187	int ret = -EINVAL;188	if (!cptr) return 0;189	*blen = 0;190	LOCK_TAKE(cptr->hdw->big_lock); do {191		if (cptr->info->type == pvr2_ctl_enum) {192			const char * const *names;193			names = cptr->info->def.type_enum.value_names;194			if (pvr2_ctrl_range_check(cptr,val) == 0) {195				if (names[val]) {196					*blen = scnprintf(197						bptr,bmax,"%s",198						names[val]);199				} else {200					*blen = 0;201				}202				ret = 0;203			}204		} else if (cptr->info->type == pvr2_ctl_bitmask) {205			const char **names;206			unsigned int idx;207			int msk;208			names = cptr->info->def.type_bitmask.bit_names;209			val &= cptr->info->def.type_bitmask.valid_bits;210			for (idx = 0, msk = 1; val; idx++, msk <<= 1) {211				if (val & msk) {212					*blen = scnprintf(bptr,bmax,"%s",213							  names[idx]);214					ret = 0;215					break;216				}217			}218		}219	} while(0); LOCK_GIVE(cptr->hdw->big_lock);220	return ret;221}222 223 224/* Return V4L ID for this control or zero if none */225int pvr2_ctrl_get_v4lid(struct pvr2_ctrl *cptr)226{227	if (!cptr) return 0;228	return cptr->info->v4l_id;229}230 231 232unsigned int pvr2_ctrl_get_v4lflags(struct pvr2_ctrl *cptr)233{234	unsigned int flags = 0;235 236	if (cptr->info->get_v4lflags) {237		flags = cptr->info->get_v4lflags(cptr);238	}239 240	if (cptr->info->set_value) {241		flags &= ~V4L2_CTRL_FLAG_READ_ONLY;242	} else {243		flags |= V4L2_CTRL_FLAG_READ_ONLY;244	}245 246	return flags;247}248 249 250/* Return true if control is writable */251int pvr2_ctrl_is_writable(struct pvr2_ctrl *cptr)252{253	if (!cptr) return 0;254	return cptr->info->set_value != NULL;255}256 257 258/* Return true if control has custom symbolic representation */259int pvr2_ctrl_has_custom_symbols(struct pvr2_ctrl *cptr)260{261	if (!cptr) return 0;262	if (!cptr->info->val_to_sym) return 0;263	if (!cptr->info->sym_to_val) return 0;264	return !0;265}266 267 268/* Convert a given mask/val to a custom symbolic value */269int pvr2_ctrl_custom_value_to_sym(struct pvr2_ctrl *cptr,270				  int mask,int val,271				  char *buf,unsigned int maxlen,272				  unsigned int *len)273{274	if (!cptr) return -EINVAL;275	if (!cptr->info->val_to_sym) return -EINVAL;276	return cptr->info->val_to_sym(cptr,mask,val,buf,maxlen,len);277}278 279 280/* Convert a symbolic value to a mask/value pair */281int pvr2_ctrl_custom_sym_to_value(struct pvr2_ctrl *cptr,282				  const char *buf,unsigned int len,283				  int *maskptr,int *valptr)284{285	if (!cptr) return -EINVAL;286	if (!cptr->info->sym_to_val) return -EINVAL;287	return cptr->info->sym_to_val(cptr,buf,len,maskptr,valptr);288}289 290 291static unsigned int gen_bitmask_string(int msk,int val,int msk_only,292				       const char **names,293				       char *ptr,unsigned int len)294{295	unsigned int idx;296	long sm,um;297	int spcFl;298	unsigned int uc,cnt;299	const char *idStr;300 301	spcFl = 0;302	uc = 0;303	um = 0;304	for (idx = 0, sm = 1; msk; idx++, sm <<= 1) {305		if (sm & msk) {306			msk &= ~sm;307			idStr = names[idx];308			if (idStr) {309				cnt = scnprintf(ptr,len,"%s%s%s",310						(spcFl ? " " : ""),311						(msk_only ? "" :312						 ((val & sm) ? "+" : "-")),313						idStr);314				ptr += cnt; len -= cnt; uc += cnt;315				spcFl = !0;316			} else {317				um |= sm;318			}319		}320	}321	if (um) {322		if (msk_only) {323			cnt = scnprintf(ptr,len,"%s0x%lx",324					(spcFl ? " " : ""),325					um);326			ptr += cnt; len -= cnt; uc += cnt;327			spcFl = !0;328		} else if (um & val) {329			cnt = scnprintf(ptr,len,"%s+0x%lx",330					(spcFl ? " " : ""),331					um & val);332			ptr += cnt; len -= cnt; uc += cnt;333			spcFl = !0;334		} else if (um & ~val) {335			cnt = scnprintf(ptr,len,"%s+0x%lx",336					(spcFl ? " " : ""),337					um & ~val);338			ptr += cnt; len -= cnt; uc += cnt;339			spcFl = !0;340		}341	}342	return uc;343}344 345 346static const char *boolNames[] = {347	"false",348	"true",349	"no",350	"yes",351};352 353 354static int parse_token(const char *ptr,unsigned int len,355		       int *valptr,356		       const char * const *names, unsigned int namecnt)357{358	unsigned int slen;359	unsigned int idx;360	*valptr = 0;361	if (!names) namecnt = 0;362	for (idx = 0; idx < namecnt; idx++) {363		if (!names[idx]) continue;364		slen = strlen(names[idx]);365		if (slen != len) continue;366		if (memcmp(names[idx],ptr,slen)) continue;367		*valptr = idx;368		return 0;369	}370	return kstrtoint(ptr, 0, valptr) ? -EINVAL : 1;371}372 373 374static int parse_mtoken(const char *ptr,unsigned int len,375			int *valptr,376			const char **names,int valid_bits)377{378	unsigned int slen;379	unsigned int idx;380	int msk;381	*valptr = 0;382	for (idx = 0, msk = 1; valid_bits; idx++, msk <<= 1) {383		if (!(msk & valid_bits)) continue;384		valid_bits &= ~msk;385		if (!names[idx]) continue;386		slen = strlen(names[idx]);387		if (slen != len) continue;388		if (memcmp(names[idx],ptr,slen)) continue;389		*valptr = msk;390		return 0;391	}392	return kstrtoint(ptr, 0, valptr);393}394 395 396static int parse_tlist(const char *ptr,unsigned int len,397		       int *maskptr,int *valptr,398		       const char **names,int valid_bits)399{400	unsigned int cnt;401	int mask,val,kv,mode,ret;402	mask = 0;403	val = 0;404	ret = 0;405	while (len) {406		cnt = 0;407		while ((cnt < len) &&408		       ((ptr[cnt] <= 32) ||409			(ptr[cnt] >= 127))) cnt++;410		ptr += cnt;411		len -= cnt;412		mode = 0;413		if ((*ptr == '-') || (*ptr == '+')) {414			mode = (*ptr == '-') ? -1 : 1;415			ptr++;416			len--;417		}418		cnt = 0;419		while (cnt < len) {420			if (ptr[cnt] <= 32) break;421			if (ptr[cnt] >= 127) break;422			cnt++;423		}424		if (!cnt) break;425		if (parse_mtoken(ptr,cnt,&kv,names,valid_bits)) {426			ret = -EINVAL;427			break;428		}429		ptr += cnt;430		len -= cnt;431		switch (mode) {432		case 0:433			mask = valid_bits;434			val |= kv;435			break;436		case -1:437			mask |= kv;438			val &= ~kv;439			break;440		case 1:441			mask |= kv;442			val |= kv;443			break;444		default:445			break;446		}447	}448	*maskptr = mask;449	*valptr = val;450	return ret;451}452 453 454/* Convert a symbolic value to a mask/value pair */455int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *cptr,456			   const char *ptr,unsigned int len,457			   int *maskptr,int *valptr)458{459	int ret = -EINVAL;460	unsigned int cnt;461 462	*maskptr = 0;463	*valptr = 0;464 465	cnt = 0;466	while ((cnt < len) && ((ptr[cnt] <= 32) || (ptr[cnt] >= 127))) cnt++;467	len -= cnt; ptr += cnt;468	cnt = 0;469	while ((cnt < len) && ((ptr[len-(cnt+1)] <= 32) ||470			       (ptr[len-(cnt+1)] >= 127))) cnt++;471	len -= cnt;472 473	if (!len) return -EINVAL;474 475	LOCK_TAKE(cptr->hdw->big_lock); do {476		if (cptr->info->type == pvr2_ctl_int) {477			ret = parse_token(ptr,len,valptr,NULL,0);478			if (ret >= 0) {479				ret = pvr2_ctrl_range_check(cptr,*valptr);480			}481			*maskptr = ~0;482		} else if (cptr->info->type == pvr2_ctl_bool) {483			ret = parse_token(ptr,len,valptr,boolNames,484					  ARRAY_SIZE(boolNames));485			if (ret == 1) {486				*valptr = *valptr ? !0 : 0;487			} else if (ret == 0) {488				*valptr = (*valptr & 1) ? !0 : 0;489			}490			*maskptr = 1;491		} else if (cptr->info->type == pvr2_ctl_enum) {492			ret = parse_token(493				ptr,len,valptr,494				cptr->info->def.type_enum.value_names,495				cptr->info->def.type_enum.count);496			if (ret >= 0) {497				ret = pvr2_ctrl_range_check(cptr,*valptr);498			}499			*maskptr = ~0;500		} else if (cptr->info->type == pvr2_ctl_bitmask) {501			ret = parse_tlist(502				ptr,len,maskptr,valptr,503				cptr->info->def.type_bitmask.bit_names,504				cptr->info->def.type_bitmask.valid_bits);505		}506	} while(0); LOCK_GIVE(cptr->hdw->big_lock);507	return ret;508}509 510 511/* Convert a given mask/val to a symbolic value */512int pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *cptr,513				    int mask,int val,514				    char *buf,unsigned int maxlen,515				    unsigned int *len)516{517	int ret = -EINVAL;518 519	*len = 0;520	if (cptr->info->type == pvr2_ctl_int) {521		*len = scnprintf(buf,maxlen,"%d",val);522		ret = 0;523	} else if (cptr->info->type == pvr2_ctl_bool) {524		*len = scnprintf(buf,maxlen,"%s",val ? "true" : "false");525		ret = 0;526	} else if (cptr->info->type == pvr2_ctl_enum) {527		const char * const *names;528		names = cptr->info->def.type_enum.value_names;529		if ((val >= 0) &&530		    (val < cptr->info->def.type_enum.count)) {531			if (names[val]) {532				*len = scnprintf(533					buf,maxlen,"%s",534					names[val]);535			} else {536				*len = 0;537			}538			ret = 0;539		}540	} else if (cptr->info->type == pvr2_ctl_bitmask) {541		*len = gen_bitmask_string(542			val & mask & cptr->info->def.type_bitmask.valid_bits,543			~0,!0,544			cptr->info->def.type_bitmask.bit_names,545			buf,maxlen);546	}547	return ret;548}549 550 551/* Convert a given mask/val to a symbolic value */552int pvr2_ctrl_value_to_sym(struct pvr2_ctrl *cptr,553			   int mask,int val,554			   char *buf,unsigned int maxlen,555			   unsigned int *len)556{557	int ret;558	LOCK_TAKE(cptr->hdw->big_lock); do {559		ret = pvr2_ctrl_value_to_sym_internal(cptr,mask,val,560						      buf,maxlen,len);561	} while(0); LOCK_GIVE(cptr->hdw->big_lock);562	return ret;563}564