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