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
28static 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. */
53int 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. */
60int 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. */
85int 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 */
97enum 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) */
105int 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) */
121int 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) */
137int 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) */
153int 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) */
167int 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 */
181const 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 */
189const 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 */
197int 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 */
239int pvr2_ctrl_get_v4lid(struct pvr2_ctrl *cptr)
240{
241	if (!cptr) return 0;
242	return cptr->info->v4l_id;
243}
244
245
246unsigned 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 */
265int 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 */
273int 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 */
283int 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 */
295int 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
305static 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
360static const char *boolNames[] = {
361	"false",
362	"true",
363	"no",
364	"yes",
365};
366
367
368static 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
402static 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
431static 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 */
490int 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 */
547int 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 */
587int 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