xref: /linux/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c (revision 26fbb4c8c7c3ee9a4c3b4de555a8587b5a19154e)
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 
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. */
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. */
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. */
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 */
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) */
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) */
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) */
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) */
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) */
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 */
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 */
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 */
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 */
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 
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 */
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 */
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 */
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 */
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 
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 
354 static int parse_token(const char *ptr,unsigned int len,
355 		       int *valptr,
356 		       const char * const *names, unsigned int namecnt)
357 {
358 	char buf[33];
359 	unsigned int slen;
360 	unsigned int idx;
361 	int negfl;
362 	char *p2;
363 	*valptr = 0;
364 	if (!names) namecnt = 0;
365 	for (idx = 0; idx < namecnt; idx++) {
366 		if (!names[idx]) continue;
367 		slen = strlen(names[idx]);
368 		if (slen != len) continue;
369 		if (memcmp(names[idx],ptr,slen)) continue;
370 		*valptr = idx;
371 		return 0;
372 	}
373 	negfl = 0;
374 	if ((*ptr == '-') || (*ptr == '+')) {
375 		negfl = (*ptr == '-');
376 		ptr++; len--;
377 	}
378 	if (len >= sizeof(buf)) return -EINVAL;
379 	memcpy(buf,ptr,len);
380 	buf[len] = 0;
381 	*valptr = simple_strtol(buf,&p2,0);
382 	if (negfl) *valptr = -(*valptr);
383 	if (*p2) return -EINVAL;
384 	return 1;
385 }
386 
387 
388 static int parse_mtoken(const char *ptr,unsigned int len,
389 			int *valptr,
390 			const char **names,int valid_bits)
391 {
392 	char buf[33];
393 	unsigned int slen;
394 	unsigned int idx;
395 	char *p2;
396 	int msk;
397 	*valptr = 0;
398 	for (idx = 0, msk = 1; valid_bits; idx++, msk <<= 1) {
399 		if (!(msk & valid_bits)) continue;
400 		valid_bits &= ~msk;
401 		if (!names[idx]) continue;
402 		slen = strlen(names[idx]);
403 		if (slen != len) continue;
404 		if (memcmp(names[idx],ptr,slen)) continue;
405 		*valptr = msk;
406 		return 0;
407 	}
408 	if (len >= sizeof(buf)) return -EINVAL;
409 	memcpy(buf,ptr,len);
410 	buf[len] = 0;
411 	*valptr = simple_strtol(buf,&p2,0);
412 	if (*p2) return -EINVAL;
413 	return 0;
414 }
415 
416 
417 static int parse_tlist(const char *ptr,unsigned int len,
418 		       int *maskptr,int *valptr,
419 		       const char **names,int valid_bits)
420 {
421 	unsigned int cnt;
422 	int mask,val,kv,mode,ret;
423 	mask = 0;
424 	val = 0;
425 	ret = 0;
426 	while (len) {
427 		cnt = 0;
428 		while ((cnt < len) &&
429 		       ((ptr[cnt] <= 32) ||
430 			(ptr[cnt] >= 127))) cnt++;
431 		ptr += cnt;
432 		len -= cnt;
433 		mode = 0;
434 		if ((*ptr == '-') || (*ptr == '+')) {
435 			mode = (*ptr == '-') ? -1 : 1;
436 			ptr++;
437 			len--;
438 		}
439 		cnt = 0;
440 		while (cnt < len) {
441 			if (ptr[cnt] <= 32) break;
442 			if (ptr[cnt] >= 127) break;
443 			cnt++;
444 		}
445 		if (!cnt) break;
446 		if (parse_mtoken(ptr,cnt,&kv,names,valid_bits)) {
447 			ret = -EINVAL;
448 			break;
449 		}
450 		ptr += cnt;
451 		len -= cnt;
452 		switch (mode) {
453 		case 0:
454 			mask = valid_bits;
455 			val |= kv;
456 			break;
457 		case -1:
458 			mask |= kv;
459 			val &= ~kv;
460 			break;
461 		case 1:
462 			mask |= kv;
463 			val |= kv;
464 			break;
465 		default:
466 			break;
467 		}
468 	}
469 	*maskptr = mask;
470 	*valptr = val;
471 	return ret;
472 }
473 
474 
475 /* Convert a symbolic value to a mask/value pair */
476 int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *cptr,
477 			   const char *ptr,unsigned int len,
478 			   int *maskptr,int *valptr)
479 {
480 	int ret = -EINVAL;
481 	unsigned int cnt;
482 
483 	*maskptr = 0;
484 	*valptr = 0;
485 
486 	cnt = 0;
487 	while ((cnt < len) && ((ptr[cnt] <= 32) || (ptr[cnt] >= 127))) cnt++;
488 	len -= cnt; ptr += cnt;
489 	cnt = 0;
490 	while ((cnt < len) && ((ptr[len-(cnt+1)] <= 32) ||
491 			       (ptr[len-(cnt+1)] >= 127))) cnt++;
492 	len -= cnt;
493 
494 	if (!len) return -EINVAL;
495 
496 	LOCK_TAKE(cptr->hdw->big_lock); do {
497 		if (cptr->info->type == pvr2_ctl_int) {
498 			ret = parse_token(ptr,len,valptr,NULL,0);
499 			if (ret >= 0) {
500 				ret = pvr2_ctrl_range_check(cptr,*valptr);
501 			}
502 			*maskptr = ~0;
503 		} else if (cptr->info->type == pvr2_ctl_bool) {
504 			ret = parse_token(ptr,len,valptr,boolNames,
505 					  ARRAY_SIZE(boolNames));
506 			if (ret == 1) {
507 				*valptr = *valptr ? !0 : 0;
508 			} else if (ret == 0) {
509 				*valptr = (*valptr & 1) ? !0 : 0;
510 			}
511 			*maskptr = 1;
512 		} else if (cptr->info->type == pvr2_ctl_enum) {
513 			ret = parse_token(
514 				ptr,len,valptr,
515 				cptr->info->def.type_enum.value_names,
516 				cptr->info->def.type_enum.count);
517 			if (ret >= 0) {
518 				ret = pvr2_ctrl_range_check(cptr,*valptr);
519 			}
520 			*maskptr = ~0;
521 		} else if (cptr->info->type == pvr2_ctl_bitmask) {
522 			ret = parse_tlist(
523 				ptr,len,maskptr,valptr,
524 				cptr->info->def.type_bitmask.bit_names,
525 				cptr->info->def.type_bitmask.valid_bits);
526 		}
527 	} while(0); LOCK_GIVE(cptr->hdw->big_lock);
528 	return ret;
529 }
530 
531 
532 /* Convert a given mask/val to a symbolic value */
533 int pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *cptr,
534 				    int mask,int val,
535 				    char *buf,unsigned int maxlen,
536 				    unsigned int *len)
537 {
538 	int ret = -EINVAL;
539 
540 	*len = 0;
541 	if (cptr->info->type == pvr2_ctl_int) {
542 		*len = scnprintf(buf,maxlen,"%d",val);
543 		ret = 0;
544 	} else if (cptr->info->type == pvr2_ctl_bool) {
545 		*len = scnprintf(buf,maxlen,"%s",val ? "true" : "false");
546 		ret = 0;
547 	} else if (cptr->info->type == pvr2_ctl_enum) {
548 		const char * const *names;
549 		names = cptr->info->def.type_enum.value_names;
550 		if ((val >= 0) &&
551 		    (val < cptr->info->def.type_enum.count)) {
552 			if (names[val]) {
553 				*len = scnprintf(
554 					buf,maxlen,"%s",
555 					names[val]);
556 			} else {
557 				*len = 0;
558 			}
559 			ret = 0;
560 		}
561 	} else if (cptr->info->type == pvr2_ctl_bitmask) {
562 		*len = gen_bitmask_string(
563 			val & mask & cptr->info->def.type_bitmask.valid_bits,
564 			~0,!0,
565 			cptr->info->def.type_bitmask.bit_names,
566 			buf,maxlen);
567 	}
568 	return ret;
569 }
570 
571 
572 /* Convert a given mask/val to a symbolic value */
573 int pvr2_ctrl_value_to_sym(struct pvr2_ctrl *cptr,
574 			   int mask,int val,
575 			   char *buf,unsigned int maxlen,
576 			   unsigned int *len)
577 {
578 	int ret;
579 	LOCK_TAKE(cptr->hdw->big_lock); do {
580 		ret = pvr2_ctrl_value_to_sym_internal(cptr,mask,val,
581 						      buf,maxlen,len);
582 	} while(0); LOCK_GIVE(cptr->hdw->big_lock);
583 	return ret;
584 }
585