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