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