blob: 55ea914c7fcd3e0a21a17671ef68294831b4a567 [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;
Mike Isely5b72d712009-04-01 01:49:57 -0300140 if (!cptr) return -EINVAL;
Mike Iselyd8554972006-06-26 20:58:46 -0300141 LOCK_TAKE(cptr->hdw->big_lock); do {
Mike Isely5b72d712009-04-01 01:49:57 -0300142 if (cptr->info->get_def_value) {
143 ret = cptr->info->get_def_value(cptr, valptr);
144 } else {
145 *valptr = cptr->info->default_value;
Mike Iselyd8554972006-06-26 20:58:46 -0300146 }
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{
Mike Iselya0fd1cb2006-06-30 11:35:28 -0300183 if (!cptr) return NULL;
Mike Iselyd8554972006-06-26 20:58:46 -0300184 return cptr->info->name;
185}
186
187
188/* Retrieve the control's desc */
189const char *pvr2_ctrl_get_desc(struct pvr2_ctrl *cptr)
190{
Mike Iselya0fd1cb2006-06-30 11:35:28 -0300191 if (!cptr) return NULL;
Mike Iselyd8554972006-06-26 20:58:46 -0300192 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 **names;
207 names = cptr->info->def.type_enum.value_names;
Mike Iselyfdf256f2008-04-22 14:45:38 -0300208 if (pvr2_ctrl_range_check(cptr,val) == 0) {
Mike Iselyd8554972006-06-26 20:58:46 -0300209 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
Mike Iselya761f432006-06-25 20:04:44 -0300238/* 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
Mike Isely1d9f8462006-06-25 20:04:58 -0300254 if (cptr->info->set_value) {
255 flags &= ~V4L2_CTRL_FLAG_READ_ONLY;
256 } else {
257 flags |= V4L2_CTRL_FLAG_READ_ONLY;
258 }
Mike Iselya761f432006-06-25 20:04:44 -0300259
260 return flags;
261}
262
263
Mike Iselyd8554972006-06-26 20:58:46 -0300264/* Return true if control is writable */
265int pvr2_ctrl_is_writable(struct pvr2_ctrl *cptr)
266{
267 if (!cptr) return 0;
Al Viro5fa12472008-03-29 03:07:38 +0000268 return cptr->info->set_value != NULL;
Mike Iselyd8554972006-06-26 20:58:46 -0300269}
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
Mike Isely33213962006-06-25 20:04:40 -0300360static const char *boolNames[] = {
361 "false",
362 "true",
363 "no",
364 "yes",
365};
366
367
Mike Iselyd8554972006-06-26 20:58:46 -0300368static int parse_token(const char *ptr,unsigned int len,
369 int *valptr,
370 const char **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;
Mike Isely33213962006-06-25 20:04:40 -0300398 return 1;
Mike Iselyd8554972006-06-26 20:58:46 -0300399}
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) {
Roel Kluin4ed53a52007-10-28 22:15:33 -0300413 if (!(msk & valid_bits)) continue;
Mike Iselyd8554972006-06-26 20:58:46 -0300414 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) {
Mike Iselya0fd1cb2006-06-30 11:35:28 -0300512 ret = parse_token(ptr,len,valptr,NULL,0);
Pantelis Koukousoulas6fcb5b32006-12-27 23:06:54 -0300513 if (ret >= 0) {
Mike Isely5549f542006-12-27 23:28:54 -0300514 ret = pvr2_ctrl_range_check(cptr,*valptr);
Mike Iselyd8554972006-06-26 20:58:46 -0300515 }
Dan Carpenterd5337962010-08-19 06:50:04 -0300516 *maskptr = ~0;
Mike Isely33213962006-06-25 20:04:40 -0300517 } else if (cptr->info->type == pvr2_ctl_bool) {
Mike Isely27c7b712007-01-20 00:39:17 -0300518 ret = parse_token(ptr,len,valptr,boolNames,
519 ARRAY_SIZE(boolNames));
Mike Isely33213962006-06-25 20:04:40 -0300520 if (ret == 1) {
521 *valptr = *valptr ? !0 : 0;
522 } else if (ret == 0) {
523 *valptr = (*valptr & 1) ? !0 : 0;
524 }
Dan Carpenterd5337962010-08-19 06:50:04 -0300525 *maskptr = 1;
Mike Iselyd8554972006-06-26 20:58:46 -0300526 } 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);
Mike Iselyfdf256f2008-04-22 14:45:38 -0300531 if (ret >= 0) {
532 ret = pvr2_ctrl_range_check(cptr,*valptr);
Mike Iselyd8554972006-06-26 20:58:46 -0300533 }
Dan Carpenterd5337962010-08-19 06:50:04 -0300534 *maskptr = ~0;
Mike Iselyd8554972006-06-26 20:58:46 -0300535 } 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;
Mike Isely33213962006-06-25 20:04:40 -0300558 } else if (cptr->info->type == pvr2_ctl_bool) {
559 *len = scnprintf(buf,maxlen,"%s",val ? "true" : "false");
560 ret = 0;
Mike Iselyd8554972006-06-26 20:58:46 -0300561 } else if (cptr->info->type == pvr2_ctl_enum) {
562 const char **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
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 */