GNU Linux-libre 4.14.332-gnu1
[releases.git] / drivers / media / usb / pvrusb2 / pvrusb2-ctrl.c
1 /*
2  *
3  *
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  */
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
24 static 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 /* Set the given control. */
49 int 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 /* Set/clear specific bits of the given control. */
56 int 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 /* Get the current value of the given control. */
81 int 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 /* Retrieve control's type */
93 enum 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 /* Retrieve control's maximum value (int type) */
101 int 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 /* Retrieve control's minimum value (int type) */
117 int 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 /* Retrieve control's default value (any type) */
133 int 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 /* Retrieve control's enumeration count (enum only) */
149 int 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 /* Retrieve control's valid mask bits (bit mask only) */
163 int 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 /* Retrieve the control's name */
177 const char *pvr2_ctrl_get_name(struct pvr2_ctrl *cptr)
178 {
179         if (!cptr) return NULL;
180         return cptr->info->name;
181 }
182
183
184 /* Retrieve the control's desc */
185 const char *pvr2_ctrl_get_desc(struct pvr2_ctrl *cptr)
186 {
187         if (!cptr) return NULL;
188         return cptr->info->desc;
189 }
190
191
192 /* Retrieve a control enumeration or bit mask value */
193 int 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 /* Return V4L ID for this control or zero if none */
235 int pvr2_ctrl_get_v4lid(struct pvr2_ctrl *cptr)
236 {
237         if (!cptr) return 0;
238         return cptr->info->v4l_id;
239 }
240
241
242 unsigned 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 /* Return true if control is writable */
261 int 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 /* Return true if control has custom symbolic representation */
269 int 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 /* Convert a given mask/val to a custom symbolic value */
279 int 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 /* Convert a symbolic value to a mask/value pair */
291 int 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
301 static 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
356 static const char *boolNames[] = {
357         "false",
358         "true",
359         "no",
360         "yes",
361 };
362
363
364 static 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
398 static 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
427 static 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 /* Convert a symbolic value to a mask/value pair */
486 int 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 /* Convert a given mask/val to a symbolic value */
543 int 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 /* Convert a given mask/val to a symbolic value */
583 int 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 }