xref: /linux/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c (revision a6b63ca4)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
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 
pvr2_ctrl_range_check(struct pvr2_ctrl * cptr,int val)14 static 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. */
pvr2_ctrl_set_value(struct pvr2_ctrl * cptr,int val)39 int 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. */
pvr2_ctrl_set_mask_value(struct pvr2_ctrl * cptr,int mask,int val)46 int 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. */
pvr2_ctrl_get_value(struct pvr2_ctrl * cptr,int * valptr)71 int 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 */
pvr2_ctrl_get_type(struct pvr2_ctrl * cptr)83 enum 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) */
pvr2_ctrl_get_max(struct pvr2_ctrl * cptr)91 int 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) */
pvr2_ctrl_get_min(struct pvr2_ctrl * cptr)107 int 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) */
pvr2_ctrl_get_def(struct pvr2_ctrl * cptr,int * valptr)123 int 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) */
pvr2_ctrl_get_cnt(struct pvr2_ctrl * cptr)139 int 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) */
pvr2_ctrl_get_mask(struct pvr2_ctrl * cptr)153 int 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 */
pvr2_ctrl_get_name(struct pvr2_ctrl * cptr)167 const 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 */
pvr2_ctrl_get_desc(struct pvr2_ctrl * cptr)175 const 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 */
pvr2_ctrl_get_valname(struct pvr2_ctrl * cptr,int val,char * bptr,unsigned int bmax,unsigned int * blen)183 int 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 */
pvr2_ctrl_get_v4lid(struct pvr2_ctrl * cptr)225 int pvr2_ctrl_get_v4lid(struct pvr2_ctrl *cptr)
226 {
227 	if (!cptr) return 0;
228 	return cptr->info->v4l_id;
229 }
230 
231 
pvr2_ctrl_get_v4lflags(struct pvr2_ctrl * cptr)232 unsigned 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 */
pvr2_ctrl_is_writable(struct pvr2_ctrl * cptr)251 int 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 */
pvr2_ctrl_has_custom_symbols(struct pvr2_ctrl * cptr)259 int 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 */
pvr2_ctrl_custom_value_to_sym(struct pvr2_ctrl * cptr,int mask,int val,char * buf,unsigned int maxlen,unsigned int * len)269 int 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 */
pvr2_ctrl_custom_sym_to_value(struct pvr2_ctrl * cptr,const char * buf,unsigned int len,int * maskptr,int * valptr)281 int 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 
gen_bitmask_string(int msk,int val,int msk_only,const char ** names,char * ptr,unsigned int len)291 static 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 
346 static const char *boolNames[] = {
347 	"false",
348 	"true",
349 	"no",
350 	"yes",
351 };
352 
353 
parse_token(const char * ptr,unsigned int len,int * valptr,const char * const * names,unsigned int namecnt)354 static 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 
parse_mtoken(const char * ptr,unsigned int len,int * valptr,const char ** names,int valid_bits)374 static 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 
parse_tlist(const char * ptr,unsigned int len,int * maskptr,int * valptr,const char ** names,int valid_bits)396 static 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 */
pvr2_ctrl_sym_to_value(struct pvr2_ctrl * cptr,const char * ptr,unsigned int len,int * maskptr,int * valptr)455 int 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 */
pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl * cptr,int mask,int val,char * buf,unsigned int maxlen,unsigned int * len)512 int 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 */
pvr2_ctrl_value_to_sym(struct pvr2_ctrl * cptr,int mask,int val,char * buf,unsigned int maxlen,unsigned int * len)552 int 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