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