GNU Linux-libre 6.9.1-gnu
[releases.git] / drivers / media / usb / pvrusb2 / pvrusb2-ctrl.c
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
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. */
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. */
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. */
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 */
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) */
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) */
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) */
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) */
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) */
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 */
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 */
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 */
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 */
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
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 */
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 */
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 */
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 */
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
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
354 static int parse_token(const char *ptr,unsigned int len,
355                        int *valptr,
356                        const char * const *names, unsigned int namecnt)
357 {
358         unsigned int slen;
359         unsigned int idx;
360         *valptr = 0;
361         if (!names) namecnt = 0;
362         for (idx = 0; idx < namecnt; idx++) {
363                 if (!names[idx]) continue;
364                 slen = strlen(names[idx]);
365                 if (slen != len) continue;
366                 if (memcmp(names[idx],ptr,slen)) continue;
367                 *valptr = idx;
368                 return 0;
369         }
370         return kstrtoint(ptr, 0, valptr) ? -EINVAL : 1;
371 }
372
373
374 static int parse_mtoken(const char *ptr,unsigned int len,
375                         int *valptr,
376                         const char **names,int valid_bits)
377 {
378         unsigned int slen;
379         unsigned int idx;
380         int msk;
381         *valptr = 0;
382         for (idx = 0, msk = 1; valid_bits; idx++, msk <<= 1) {
383                 if (!(msk & valid_bits)) continue;
384                 valid_bits &= ~msk;
385                 if (!names[idx]) continue;
386                 slen = strlen(names[idx]);
387                 if (slen != len) continue;
388                 if (memcmp(names[idx],ptr,slen)) continue;
389                 *valptr = msk;
390                 return 0;
391         }
392         return kstrtoint(ptr, 0, valptr);
393 }
394
395
396 static int parse_tlist(const char *ptr,unsigned int len,
397                        int *maskptr,int *valptr,
398                        const char **names,int valid_bits)
399 {
400         unsigned int cnt;
401         int mask,val,kv,mode,ret;
402         mask = 0;
403         val = 0;
404         ret = 0;
405         while (len) {
406                 cnt = 0;
407                 while ((cnt < len) &&
408                        ((ptr[cnt] <= 32) ||
409                         (ptr[cnt] >= 127))) cnt++;
410                 ptr += cnt;
411                 len -= cnt;
412                 mode = 0;
413                 if ((*ptr == '-') || (*ptr == '+')) {
414                         mode = (*ptr == '-') ? -1 : 1;
415                         ptr++;
416                         len--;
417                 }
418                 cnt = 0;
419                 while (cnt < len) {
420                         if (ptr[cnt] <= 32) break;
421                         if (ptr[cnt] >= 127) break;
422                         cnt++;
423                 }
424                 if (!cnt) break;
425                 if (parse_mtoken(ptr,cnt,&kv,names,valid_bits)) {
426                         ret = -EINVAL;
427                         break;
428                 }
429                 ptr += cnt;
430                 len -= cnt;
431                 switch (mode) {
432                 case 0:
433                         mask = valid_bits;
434                         val |= kv;
435                         break;
436                 case -1:
437                         mask |= kv;
438                         val &= ~kv;
439                         break;
440                 case 1:
441                         mask |= kv;
442                         val |= kv;
443                         break;
444                 default:
445                         break;
446                 }
447         }
448         *maskptr = mask;
449         *valptr = val;
450         return ret;
451 }
452
453
454 /* Convert a symbolic value to a mask/value pair */
455 int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *cptr,
456                            const char *ptr,unsigned int len,
457                            int *maskptr,int *valptr)
458 {
459         int ret = -EINVAL;
460         unsigned int cnt;
461
462         *maskptr = 0;
463         *valptr = 0;
464
465         cnt = 0;
466         while ((cnt < len) && ((ptr[cnt] <= 32) || (ptr[cnt] >= 127))) cnt++;
467         len -= cnt; ptr += cnt;
468         cnt = 0;
469         while ((cnt < len) && ((ptr[len-(cnt+1)] <= 32) ||
470                                (ptr[len-(cnt+1)] >= 127))) cnt++;
471         len -= cnt;
472
473         if (!len) return -EINVAL;
474
475         LOCK_TAKE(cptr->hdw->big_lock); do {
476                 if (cptr->info->type == pvr2_ctl_int) {
477                         ret = parse_token(ptr,len,valptr,NULL,0);
478                         if (ret >= 0) {
479                                 ret = pvr2_ctrl_range_check(cptr,*valptr);
480                         }
481                         *maskptr = ~0;
482                 } else if (cptr->info->type == pvr2_ctl_bool) {
483                         ret = parse_token(ptr,len,valptr,boolNames,
484                                           ARRAY_SIZE(boolNames));
485                         if (ret == 1) {
486                                 *valptr = *valptr ? !0 : 0;
487                         } else if (ret == 0) {
488                                 *valptr = (*valptr & 1) ? !0 : 0;
489                         }
490                         *maskptr = 1;
491                 } else if (cptr->info->type == pvr2_ctl_enum) {
492                         ret = parse_token(
493                                 ptr,len,valptr,
494                                 cptr->info->def.type_enum.value_names,
495                                 cptr->info->def.type_enum.count);
496                         if (ret >= 0) {
497                                 ret = pvr2_ctrl_range_check(cptr,*valptr);
498                         }
499                         *maskptr = ~0;
500                 } else if (cptr->info->type == pvr2_ctl_bitmask) {
501                         ret = parse_tlist(
502                                 ptr,len,maskptr,valptr,
503                                 cptr->info->def.type_bitmask.bit_names,
504                                 cptr->info->def.type_bitmask.valid_bits);
505                 }
506         } while(0); LOCK_GIVE(cptr->hdw->big_lock);
507         return ret;
508 }
509
510
511 /* Convert a given mask/val to a symbolic value */
512 int pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *cptr,
513                                     int mask,int val,
514                                     char *buf,unsigned int maxlen,
515                                     unsigned int *len)
516 {
517         int ret = -EINVAL;
518
519         *len = 0;
520         if (cptr->info->type == pvr2_ctl_int) {
521                 *len = scnprintf(buf,maxlen,"%d",val);
522                 ret = 0;
523         } else if (cptr->info->type == pvr2_ctl_bool) {
524                 *len = scnprintf(buf,maxlen,"%s",val ? "true" : "false");
525                 ret = 0;
526         } else if (cptr->info->type == pvr2_ctl_enum) {
527                 const char * const *names;
528                 names = cptr->info->def.type_enum.value_names;
529                 if ((val >= 0) &&
530                     (val < cptr->info->def.type_enum.count)) {
531                         if (names[val]) {
532                                 *len = scnprintf(
533                                         buf,maxlen,"%s",
534                                         names[val]);
535                         } else {
536                                 *len = 0;
537                         }
538                         ret = 0;
539                 }
540         } else if (cptr->info->type == pvr2_ctl_bitmask) {
541                 *len = gen_bitmask_string(
542                         val & mask & cptr->info->def.type_bitmask.valid_bits,
543                         ~0,!0,
544                         cptr->info->def.type_bitmask.bit_names,
545                         buf,maxlen);
546         }
547         return ret;
548 }
549
550
551 /* Convert a given mask/val to a symbolic value */
552 int pvr2_ctrl_value_to_sym(struct pvr2_ctrl *cptr,
553                            int mask,int val,
554                            char *buf,unsigned int maxlen,
555                            unsigned int *len)
556 {
557         int ret;
558         LOCK_TAKE(cptr->hdw->big_lock); do {
559                 ret = pvr2_ctrl_value_to_sym_internal(cptr,mask,val,
560                                                       buf,maxlen,len);
561         } while(0); LOCK_GIVE(cptr->hdw->big_lock);
562         return ret;
563 }