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