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