blob: 2741c7b0b537818b5e7302ee479f5c5ff31db5e1 [file] [log] [blame]
Mike Iselyd8554972006-06-26 20:58:46 -03001/*
2 *
Mike Iselyd8554972006-06-26 20:58:46 -03003 *
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
Mike Isely5549f542006-12-27 23:28:54 -030028static 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;
Mike Iselyfdf256f2008-04-22 14:45:38 -030032 } 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;
Mike Isely5549f542006-12-27 23:28:54 -030035 } 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
Mike Iselyd8554972006-06-26 20:58:46 -030052/* 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 {
Al Viro5fa12472008-03-29 03:07:38 +000065 if (cptr->info->set_value) {
Mike Iselyd8554972006-06-26 20:58:46 -030066 if (cptr->info->type == pvr2_ctl_bitmask) {
67 mask &= cptr->info->def.type_bitmask.valid_bits;
Mike Iselyfdf256f2008-04-22 14:45:38 -030068 } else if ((cptr->info->type == pvr2_ctl_int)||
69 (cptr->info->type == pvr2_ctl_enum)) {
Mike Isely5549f542006-12-27 23:28:54 -030070 ret = pvr2_ctrl_range_check(cptr,val);
71 if (ret < 0) break;
Mike Isely33213962006-06-25 20:04:40 -030072 } else if (cptr->info->type != pvr2_ctl_bool) {
73 break;
Mike Iselyd8554972006-06-26 20:58:46 -030074 }
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 {
Mike Isely89ebd632006-08-08 09:10:07 -0300110 if (cptr->info->get_max_value) {
111 cptr->info->get_max_value(cptr,&ret);
112 } else if (cptr->info->type == pvr2_ctl_int) {
Mike Iselyd8554972006-06-26 20:58:46 -0300113 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 {
Mike Isely89ebd632006-08-08 09:10:07 -0300126 if (cptr->info->get_min_value) {
127 cptr->info->get_min_value(cptr,&ret);
128 } else if (cptr->info->type == pvr2_ctl_int) {
Mike Iselyd8554972006-06-26 20:58:46 -0300129 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) */
Mike Isely26dd1c52008-08-31 20:55:03 -0300137int pvr2_ctrl_get_def(struct pvr2_ctrl *cptr, int *valptr)
Mike Iselyd8554972006-06-26 20:58:46 -0300138{
139 int ret = 0;
140 if (!cptr) return 0;
141 LOCK_TAKE(cptr->hdw->big_lock); do {
142 if (cptr->info->type == pvr2_ctl_int) {
Mike Isely26dd1c52008-08-31 20:55:03 -0300143 if (cptr->info->get_def_value) {
144 /* Comment to keep checkpatch.pl quiet */
145 ret = cptr->info->get_def_value(cptr, valptr);
146 } else {
147 /* Comment to keep checkpatch.pl quiet */
148 *valptr = cptr->info->default_value;
149 }
Mike Iselyd8554972006-06-26 20:58:46 -0300150 }
151 } while(0); LOCK_GIVE(cptr->hdw->big_lock);
152 return ret;
153}
154
155
156/* Retrieve control's enumeration count (enum only) */
157int pvr2_ctrl_get_cnt(struct pvr2_ctrl *cptr)
158{
159 int ret = 0;
160 if (!cptr) return 0;
161 LOCK_TAKE(cptr->hdw->big_lock); do {
162 if (cptr->info->type == pvr2_ctl_enum) {
163 ret = cptr->info->def.type_enum.count;
164 }
165 } while(0); LOCK_GIVE(cptr->hdw->big_lock);
166 return ret;
167}
168
169
170/* Retrieve control's valid mask bits (bit mask only) */
171int pvr2_ctrl_get_mask(struct pvr2_ctrl *cptr)
172{
173 int ret = 0;
174 if (!cptr) return 0;
175 LOCK_TAKE(cptr->hdw->big_lock); do {
176 if (cptr->info->type == pvr2_ctl_bitmask) {
177 ret = cptr->info->def.type_bitmask.valid_bits;
178 }
179 } while(0); LOCK_GIVE(cptr->hdw->big_lock);
180 return ret;
181}
182
183
184/* Retrieve the control's name */
185const char *pvr2_ctrl_get_name(struct pvr2_ctrl *cptr)
186{
Mike Iselya0fd1cb2006-06-30 11:35:28 -0300187 if (!cptr) return NULL;
Mike Iselyd8554972006-06-26 20:58:46 -0300188 return cptr->info->name;
189}
190
191
192/* Retrieve the control's desc */
193const char *pvr2_ctrl_get_desc(struct pvr2_ctrl *cptr)
194{
Mike Iselya0fd1cb2006-06-30 11:35:28 -0300195 if (!cptr) return NULL;
Mike Iselyd8554972006-06-26 20:58:46 -0300196 return cptr->info->desc;
197}
198
199
200/* Retrieve a control enumeration or bit mask value */
201int pvr2_ctrl_get_valname(struct pvr2_ctrl *cptr,int val,
202 char *bptr,unsigned int bmax,
203 unsigned int *blen)
204{
205 int ret = -EINVAL;
206 if (!cptr) return 0;
207 *blen = 0;
208 LOCK_TAKE(cptr->hdw->big_lock); do {
209 if (cptr->info->type == pvr2_ctl_enum) {
210 const char **names;
211 names = cptr->info->def.type_enum.value_names;
Mike Iselyfdf256f2008-04-22 14:45:38 -0300212 if (pvr2_ctrl_range_check(cptr,val) == 0) {
Mike Iselyd8554972006-06-26 20:58:46 -0300213 if (names[val]) {
214 *blen = scnprintf(
215 bptr,bmax,"%s",
216 names[val]);
217 } else {
218 *blen = 0;
219 }
220 ret = 0;
221 }
222 } else if (cptr->info->type == pvr2_ctl_bitmask) {
223 const char **names;
224 unsigned int idx;
225 int msk;
226 names = cptr->info->def.type_bitmask.bit_names;
227 val &= cptr->info->def.type_bitmask.valid_bits;
228 for (idx = 0, msk = 1; val; idx++, msk <<= 1) {
229 if (val & msk) {
230 *blen = scnprintf(bptr,bmax,"%s",
231 names[idx]);
232 ret = 0;
233 break;
234 }
235 }
236 }
237 } while(0); LOCK_GIVE(cptr->hdw->big_lock);
238 return ret;
239}
240
241
Mike Iselya761f432006-06-25 20:04:44 -0300242/* Return V4L ID for this control or zero if none */
243int pvr2_ctrl_get_v4lid(struct pvr2_ctrl *cptr)
244{
245 if (!cptr) return 0;
246 return cptr->info->v4l_id;
247}
248
249
250unsigned int pvr2_ctrl_get_v4lflags(struct pvr2_ctrl *cptr)
251{
252 unsigned int flags = 0;
253
254 if (cptr->info->get_v4lflags) {
255 flags = cptr->info->get_v4lflags(cptr);
256 }
257
Mike Isely1d9f8462006-06-25 20:04:58 -0300258 if (cptr->info->set_value) {
259 flags &= ~V4L2_CTRL_FLAG_READ_ONLY;
260 } else {
261 flags |= V4L2_CTRL_FLAG_READ_ONLY;
262 }
Mike Iselya761f432006-06-25 20:04:44 -0300263
264 return flags;
265}
266
267
Mike Iselyd8554972006-06-26 20:58:46 -0300268/* Return true if control is writable */
269int pvr2_ctrl_is_writable(struct pvr2_ctrl *cptr)
270{
271 if (!cptr) return 0;
Al Viro5fa12472008-03-29 03:07:38 +0000272 return cptr->info->set_value != NULL;
Mike Iselyd8554972006-06-26 20:58:46 -0300273}
274
275
276/* Return true if control has custom symbolic representation */
277int pvr2_ctrl_has_custom_symbols(struct pvr2_ctrl *cptr)
278{
279 if (!cptr) return 0;
280 if (!cptr->info->val_to_sym) return 0;
281 if (!cptr->info->sym_to_val) return 0;
282 return !0;
283}
284
285
286/* Convert a given mask/val to a custom symbolic value */
287int pvr2_ctrl_custom_value_to_sym(struct pvr2_ctrl *cptr,
288 int mask,int val,
289 char *buf,unsigned int maxlen,
290 unsigned int *len)
291{
292 if (!cptr) return -EINVAL;
293 if (!cptr->info->val_to_sym) return -EINVAL;
294 return cptr->info->val_to_sym(cptr,mask,val,buf,maxlen,len);
295}
296
297
298/* Convert a symbolic value to a mask/value pair */
299int pvr2_ctrl_custom_sym_to_value(struct pvr2_ctrl *cptr,
300 const char *buf,unsigned int len,
301 int *maskptr,int *valptr)
302{
303 if (!cptr) return -EINVAL;
304 if (!cptr->info->sym_to_val) return -EINVAL;
305 return cptr->info->sym_to_val(cptr,buf,len,maskptr,valptr);
306}
307
308
309static unsigned int gen_bitmask_string(int msk,int val,int msk_only,
310 const char **names,
311 char *ptr,unsigned int len)
312{
313 unsigned int idx;
314 long sm,um;
315 int spcFl;
316 unsigned int uc,cnt;
317 const char *idStr;
318
319 spcFl = 0;
320 uc = 0;
321 um = 0;
322 for (idx = 0, sm = 1; msk; idx++, sm <<= 1) {
323 if (sm & msk) {
324 msk &= ~sm;
325 idStr = names[idx];
326 if (idStr) {
327 cnt = scnprintf(ptr,len,"%s%s%s",
328 (spcFl ? " " : ""),
329 (msk_only ? "" :
330 ((val & sm) ? "+" : "-")),
331 idStr);
332 ptr += cnt; len -= cnt; uc += cnt;
333 spcFl = !0;
334 } else {
335 um |= sm;
336 }
337 }
338 }
339 if (um) {
340 if (msk_only) {
341 cnt = scnprintf(ptr,len,"%s0x%lx",
342 (spcFl ? " " : ""),
343 um);
344 ptr += cnt; len -= cnt; uc += cnt;
345 spcFl = !0;
346 } else if (um & val) {
347 cnt = scnprintf(ptr,len,"%s+0x%lx",
348 (spcFl ? " " : ""),
349 um & val);
350 ptr += cnt; len -= cnt; uc += cnt;
351 spcFl = !0;
352 } else if (um & ~val) {
353 cnt = scnprintf(ptr,len,"%s+0x%lx",
354 (spcFl ? " " : ""),
355 um & ~val);
356 ptr += cnt; len -= cnt; uc += cnt;
357 spcFl = !0;
358 }
359 }
360 return uc;
361}
362
363
Mike Isely33213962006-06-25 20:04:40 -0300364static const char *boolNames[] = {
365 "false",
366 "true",
367 "no",
368 "yes",
369};
370
371
Mike Iselyd8554972006-06-26 20:58:46 -0300372static int parse_token(const char *ptr,unsigned int len,
373 int *valptr,
374 const char **names,unsigned int namecnt)
375{
376 char buf[33];
377 unsigned int slen;
378 unsigned int idx;
379 int negfl;
380 char *p2;
381 *valptr = 0;
382 if (!names) namecnt = 0;
383 for (idx = 0; idx < namecnt; idx++) {
384 if (!names[idx]) continue;
385 slen = strlen(names[idx]);
386 if (slen != len) continue;
387 if (memcmp(names[idx],ptr,slen)) continue;
388 *valptr = idx;
389 return 0;
390 }
391 negfl = 0;
392 if ((*ptr == '-') || (*ptr == '+')) {
393 negfl = (*ptr == '-');
394 ptr++; len--;
395 }
396 if (len >= sizeof(buf)) return -EINVAL;
397 memcpy(buf,ptr,len);
398 buf[len] = 0;
399 *valptr = simple_strtol(buf,&p2,0);
400 if (negfl) *valptr = -(*valptr);
401 if (*p2) return -EINVAL;
Mike Isely33213962006-06-25 20:04:40 -0300402 return 1;
Mike Iselyd8554972006-06-26 20:58:46 -0300403}
404
405
406static int parse_mtoken(const char *ptr,unsigned int len,
407 int *valptr,
408 const char **names,int valid_bits)
409{
410 char buf[33];
411 unsigned int slen;
412 unsigned int idx;
413 char *p2;
414 int msk;
415 *valptr = 0;
416 for (idx = 0, msk = 1; valid_bits; idx++, msk <<= 1) {
Roel Kluin4ed53a52007-10-28 22:15:33 -0300417 if (!(msk & valid_bits)) continue;
Mike Iselyd8554972006-06-26 20:58:46 -0300418 valid_bits &= ~msk;
419 if (!names[idx]) continue;
420 slen = strlen(names[idx]);
421 if (slen != len) continue;
422 if (memcmp(names[idx],ptr,slen)) continue;
423 *valptr = msk;
424 return 0;
425 }
426 if (len >= sizeof(buf)) return -EINVAL;
427 memcpy(buf,ptr,len);
428 buf[len] = 0;
429 *valptr = simple_strtol(buf,&p2,0);
430 if (*p2) return -EINVAL;
431 return 0;
432}
433
434
435static int parse_tlist(const char *ptr,unsigned int len,
436 int *maskptr,int *valptr,
437 const char **names,int valid_bits)
438{
439 unsigned int cnt;
440 int mask,val,kv,mode,ret;
441 mask = 0;
442 val = 0;
443 ret = 0;
444 while (len) {
445 cnt = 0;
446 while ((cnt < len) &&
447 ((ptr[cnt] <= 32) ||
448 (ptr[cnt] >= 127))) cnt++;
449 ptr += cnt;
450 len -= cnt;
451 mode = 0;
452 if ((*ptr == '-') || (*ptr == '+')) {
453 mode = (*ptr == '-') ? -1 : 1;
454 ptr++;
455 len--;
456 }
457 cnt = 0;
458 while (cnt < len) {
459 if (ptr[cnt] <= 32) break;
460 if (ptr[cnt] >= 127) break;
461 cnt++;
462 }
463 if (!cnt) break;
464 if (parse_mtoken(ptr,cnt,&kv,names,valid_bits)) {
465 ret = -EINVAL;
466 break;
467 }
468 ptr += cnt;
469 len -= cnt;
470 switch (mode) {
471 case 0:
472 mask = valid_bits;
473 val |= kv;
474 break;
475 case -1:
476 mask |= kv;
477 val &= ~kv;
478 break;
479 case 1:
480 mask |= kv;
481 val |= kv;
482 break;
483 default:
484 break;
485 }
486 }
487 *maskptr = mask;
488 *valptr = val;
489 return ret;
490}
491
492
493/* Convert a symbolic value to a mask/value pair */
494int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *cptr,
495 const char *ptr,unsigned int len,
496 int *maskptr,int *valptr)
497{
498 int ret = -EINVAL;
499 unsigned int cnt;
500
501 *maskptr = 0;
502 *valptr = 0;
503
504 cnt = 0;
505 while ((cnt < len) && ((ptr[cnt] <= 32) || (ptr[cnt] >= 127))) cnt++;
506 len -= cnt; ptr += cnt;
507 cnt = 0;
508 while ((cnt < len) && ((ptr[len-(cnt+1)] <= 32) ||
509 (ptr[len-(cnt+1)] >= 127))) cnt++;
510 len -= cnt;
511
512 if (!len) return -EINVAL;
513
514 LOCK_TAKE(cptr->hdw->big_lock); do {
515 if (cptr->info->type == pvr2_ctl_int) {
Mike Iselya0fd1cb2006-06-30 11:35:28 -0300516 ret = parse_token(ptr,len,valptr,NULL,0);
Pantelis Koukousoulas6fcb5b32006-12-27 23:06:54 -0300517 if (ret >= 0) {
Mike Isely5549f542006-12-27 23:28:54 -0300518 ret = pvr2_ctrl_range_check(cptr,*valptr);
Mike Iselyd8554972006-06-26 20:58:46 -0300519 }
520 if (maskptr) *maskptr = ~0;
Mike Isely33213962006-06-25 20:04:40 -0300521 } else if (cptr->info->type == pvr2_ctl_bool) {
Mike Isely27c7b712007-01-20 00:39:17 -0300522 ret = parse_token(ptr,len,valptr,boolNames,
523 ARRAY_SIZE(boolNames));
Mike Isely33213962006-06-25 20:04:40 -0300524 if (ret == 1) {
525 *valptr = *valptr ? !0 : 0;
526 } else if (ret == 0) {
527 *valptr = (*valptr & 1) ? !0 : 0;
528 }
529 if (maskptr) *maskptr = 1;
Mike Iselyd8554972006-06-26 20:58:46 -0300530 } else if (cptr->info->type == pvr2_ctl_enum) {
531 ret = parse_token(
532 ptr,len,valptr,
533 cptr->info->def.type_enum.value_names,
534 cptr->info->def.type_enum.count);
Mike Iselyfdf256f2008-04-22 14:45:38 -0300535 if (ret >= 0) {
536 ret = pvr2_ctrl_range_check(cptr,*valptr);
Mike Iselyd8554972006-06-26 20:58:46 -0300537 }
538 if (maskptr) *maskptr = ~0;
539 } else if (cptr->info->type == pvr2_ctl_bitmask) {
540 ret = parse_tlist(
541 ptr,len,maskptr,valptr,
542 cptr->info->def.type_bitmask.bit_names,
543 cptr->info->def.type_bitmask.valid_bits);
544 }
545 } while(0); LOCK_GIVE(cptr->hdw->big_lock);
546 return ret;
547}
548
549
550/* Convert a given mask/val to a symbolic value */
551int pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *cptr,
552 int mask,int val,
553 char *buf,unsigned int maxlen,
554 unsigned int *len)
555{
556 int ret = -EINVAL;
557
558 *len = 0;
559 if (cptr->info->type == pvr2_ctl_int) {
560 *len = scnprintf(buf,maxlen,"%d",val);
561 ret = 0;
Mike Isely33213962006-06-25 20:04:40 -0300562 } else if (cptr->info->type == pvr2_ctl_bool) {
563 *len = scnprintf(buf,maxlen,"%s",val ? "true" : "false");
564 ret = 0;
Mike Iselyd8554972006-06-26 20:58:46 -0300565 } else if (cptr->info->type == pvr2_ctl_enum) {
566 const char **names;
567 names = cptr->info->def.type_enum.value_names;
568 if ((val >= 0) &&
569 (val < cptr->info->def.type_enum.count)) {
570 if (names[val]) {
571 *len = scnprintf(
572 buf,maxlen,"%s",
573 names[val]);
574 } else {
575 *len = 0;
576 }
577 ret = 0;
578 }
579 } else if (cptr->info->type == pvr2_ctl_bitmask) {
580 *len = gen_bitmask_string(
581 val & mask & cptr->info->def.type_bitmask.valid_bits,
582 ~0,!0,
583 cptr->info->def.type_bitmask.bit_names,
584 buf,maxlen);
585 }
586 return ret;
587}
588
589
590/* Convert a given mask/val to a symbolic value */
591int pvr2_ctrl_value_to_sym(struct pvr2_ctrl *cptr,
592 int mask,int val,
593 char *buf,unsigned int maxlen,
594 unsigned int *len)
595{
596 int ret;
597 LOCK_TAKE(cptr->hdw->big_lock); do {
598 ret = pvr2_ctrl_value_to_sym_internal(cptr,mask,val,
599 buf,maxlen,len);
600 } while(0); LOCK_GIVE(cptr->hdw->big_lock);
601 return ret;
602}
603
604
605/*
606 Stuff for Emacs to see, in order to encourage consistent editing style:
607 *** Local Variables: ***
608 *** mode: c ***
609 *** fill-column: 75 ***
610 *** tab-width: 8 ***
611 *** c-basic-offset: 8 ***
612 *** End: ***
613 */