Merge branch 's3c-move' into devel
[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)
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                         ret = cptr->info->default_value;
144                 }
145         } while(0); LOCK_GIVE(cptr->hdw->big_lock);
146         return ret;
147 }
148
149
150 /* Retrieve control's enumeration count (enum only) */
151 int pvr2_ctrl_get_cnt(struct pvr2_ctrl *cptr)
152 {
153         int ret = 0;
154         if (!cptr) return 0;
155         LOCK_TAKE(cptr->hdw->big_lock); do {
156                 if (cptr->info->type == pvr2_ctl_enum) {
157                         ret = cptr->info->def.type_enum.count;
158                 }
159         } while(0); LOCK_GIVE(cptr->hdw->big_lock);
160         return ret;
161 }
162
163
164 /* Retrieve control's valid mask bits (bit mask only) */
165 int pvr2_ctrl_get_mask(struct pvr2_ctrl *cptr)
166 {
167         int ret = 0;
168         if (!cptr) return 0;
169         LOCK_TAKE(cptr->hdw->big_lock); do {
170                 if (cptr->info->type == pvr2_ctl_bitmask) {
171                         ret = cptr->info->def.type_bitmask.valid_bits;
172                 }
173         } while(0); LOCK_GIVE(cptr->hdw->big_lock);
174         return ret;
175 }
176
177
178 /* Retrieve the control's name */
179 const char *pvr2_ctrl_get_name(struct pvr2_ctrl *cptr)
180 {
181         if (!cptr) return NULL;
182         return cptr->info->name;
183 }
184
185
186 /* Retrieve the control's desc */
187 const char *pvr2_ctrl_get_desc(struct pvr2_ctrl *cptr)
188 {
189         if (!cptr) return NULL;
190         return cptr->info->desc;
191 }
192
193
194 /* Retrieve a control enumeration or bit mask value */
195 int pvr2_ctrl_get_valname(struct pvr2_ctrl *cptr,int val,
196                           char *bptr,unsigned int bmax,
197                           unsigned int *blen)
198 {
199         int ret = -EINVAL;
200         if (!cptr) return 0;
201         *blen = 0;
202         LOCK_TAKE(cptr->hdw->big_lock); do {
203                 if (cptr->info->type == pvr2_ctl_enum) {
204                         const char **names;
205                         names = cptr->info->def.type_enum.value_names;
206                         if (pvr2_ctrl_range_check(cptr,val) == 0) {
207                                 if (names[val]) {
208                                         *blen = scnprintf(
209                                                 bptr,bmax,"%s",
210                                                 names[val]);
211                                 } else {
212                                         *blen = 0;
213                                 }
214                                 ret = 0;
215                         }
216                 } else if (cptr->info->type == pvr2_ctl_bitmask) {
217                         const char **names;
218                         unsigned int idx;
219                         int msk;
220                         names = cptr->info->def.type_bitmask.bit_names;
221                         val &= cptr->info->def.type_bitmask.valid_bits;
222                         for (idx = 0, msk = 1; val; idx++, msk <<= 1) {
223                                 if (val & msk) {
224                                         *blen = scnprintf(bptr,bmax,"%s",
225                                                           names[idx]);
226                                         ret = 0;
227                                         break;
228                                 }
229                         }
230                 }
231         } while(0); LOCK_GIVE(cptr->hdw->big_lock);
232         return ret;
233 }
234
235
236 /* Return V4L ID for this control or zero if none */
237 int pvr2_ctrl_get_v4lid(struct pvr2_ctrl *cptr)
238 {
239         if (!cptr) return 0;
240         return cptr->info->v4l_id;
241 }
242
243
244 unsigned int pvr2_ctrl_get_v4lflags(struct pvr2_ctrl *cptr)
245 {
246         unsigned int flags = 0;
247
248         if (cptr->info->get_v4lflags) {
249                 flags = cptr->info->get_v4lflags(cptr);
250         }
251
252         if (cptr->info->set_value) {
253                 flags &= ~V4L2_CTRL_FLAG_READ_ONLY;
254         } else {
255                 flags |= V4L2_CTRL_FLAG_READ_ONLY;
256         }
257
258         return flags;
259 }
260
261
262 /* Return true if control is writable */
263 int pvr2_ctrl_is_writable(struct pvr2_ctrl *cptr)
264 {
265         if (!cptr) return 0;
266         return cptr->info->set_value != NULL;
267 }
268
269
270 /* Return true if control has custom symbolic representation */
271 int pvr2_ctrl_has_custom_symbols(struct pvr2_ctrl *cptr)
272 {
273         if (!cptr) return 0;
274         if (!cptr->info->val_to_sym) return 0;
275         if (!cptr->info->sym_to_val) return 0;
276         return !0;
277 }
278
279
280 /* Convert a given mask/val to a custom symbolic value */
281 int pvr2_ctrl_custom_value_to_sym(struct pvr2_ctrl *cptr,
282                                   int mask,int val,
283                                   char *buf,unsigned int maxlen,
284                                   unsigned int *len)
285 {
286         if (!cptr) return -EINVAL;
287         if (!cptr->info->val_to_sym) return -EINVAL;
288         return cptr->info->val_to_sym(cptr,mask,val,buf,maxlen,len);
289 }
290
291
292 /* Convert a symbolic value to a mask/value pair */
293 int pvr2_ctrl_custom_sym_to_value(struct pvr2_ctrl *cptr,
294                                   const char *buf,unsigned int len,
295                                   int *maskptr,int *valptr)
296 {
297         if (!cptr) return -EINVAL;
298         if (!cptr->info->sym_to_val) return -EINVAL;
299         return cptr->info->sym_to_val(cptr,buf,len,maskptr,valptr);
300 }
301
302
303 static unsigned int gen_bitmask_string(int msk,int val,int msk_only,
304                                        const char **names,
305                                        char *ptr,unsigned int len)
306 {
307         unsigned int idx;
308         long sm,um;
309         int spcFl;
310         unsigned int uc,cnt;
311         const char *idStr;
312
313         spcFl = 0;
314         uc = 0;
315         um = 0;
316         for (idx = 0, sm = 1; msk; idx++, sm <<= 1) {
317                 if (sm & msk) {
318                         msk &= ~sm;
319                         idStr = names[idx];
320                         if (idStr) {
321                                 cnt = scnprintf(ptr,len,"%s%s%s",
322                                                 (spcFl ? " " : ""),
323                                                 (msk_only ? "" :
324                                                  ((val & sm) ? "+" : "-")),
325                                                 idStr);
326                                 ptr += cnt; len -= cnt; uc += cnt;
327                                 spcFl = !0;
328                         } else {
329                                 um |= sm;
330                         }
331                 }
332         }
333         if (um) {
334                 if (msk_only) {
335                         cnt = scnprintf(ptr,len,"%s0x%lx",
336                                         (spcFl ? " " : ""),
337                                         um);
338                         ptr += cnt; len -= cnt; uc += cnt;
339                         spcFl = !0;
340                 } else if (um & val) {
341                         cnt = scnprintf(ptr,len,"%s+0x%lx",
342                                         (spcFl ? " " : ""),
343                                         um & val);
344                         ptr += cnt; len -= cnt; uc += cnt;
345                         spcFl = !0;
346                 } else if (um & ~val) {
347                         cnt = scnprintf(ptr,len,"%s+0x%lx",
348                                         (spcFl ? " " : ""),
349                                         um & ~val);
350                         ptr += cnt; len -= cnt; uc += cnt;
351                         spcFl = !0;
352                 }
353         }
354         return uc;
355 }
356
357
358 static const char *boolNames[] = {
359         "false",
360         "true",
361         "no",
362         "yes",
363 };
364
365
366 static int parse_token(const char *ptr,unsigned int len,
367                        int *valptr,
368                        const char **names,unsigned int namecnt)
369 {
370         char buf[33];
371         unsigned int slen;
372         unsigned int idx;
373         int negfl;
374         char *p2;
375         *valptr = 0;
376         if (!names) namecnt = 0;
377         for (idx = 0; idx < namecnt; idx++) {
378                 if (!names[idx]) continue;
379                 slen = strlen(names[idx]);
380                 if (slen != len) continue;
381                 if (memcmp(names[idx],ptr,slen)) continue;
382                 *valptr = idx;
383                 return 0;
384         }
385         negfl = 0;
386         if ((*ptr == '-') || (*ptr == '+')) {
387                 negfl = (*ptr == '-');
388                 ptr++; len--;
389         }
390         if (len >= sizeof(buf)) return -EINVAL;
391         memcpy(buf,ptr,len);
392         buf[len] = 0;
393         *valptr = simple_strtol(buf,&p2,0);
394         if (negfl) *valptr = -(*valptr);
395         if (*p2) return -EINVAL;
396         return 1;
397 }
398
399
400 static int parse_mtoken(const char *ptr,unsigned int len,
401                         int *valptr,
402                         const char **names,int valid_bits)
403 {
404         char buf[33];
405         unsigned int slen;
406         unsigned int idx;
407         char *p2;
408         int msk;
409         *valptr = 0;
410         for (idx = 0, msk = 1; valid_bits; idx++, msk <<= 1) {
411                 if (!(msk & valid_bits)) continue;
412                 valid_bits &= ~msk;
413                 if (!names[idx]) continue;
414                 slen = strlen(names[idx]);
415                 if (slen != len) continue;
416                 if (memcmp(names[idx],ptr,slen)) continue;
417                 *valptr = msk;
418                 return 0;
419         }
420         if (len >= sizeof(buf)) return -EINVAL;
421         memcpy(buf,ptr,len);
422         buf[len] = 0;
423         *valptr = simple_strtol(buf,&p2,0);
424         if (*p2) return -EINVAL;
425         return 0;
426 }
427
428
429 static int parse_tlist(const char *ptr,unsigned int len,
430                        int *maskptr,int *valptr,
431                        const char **names,int valid_bits)
432 {
433         unsigned int cnt;
434         int mask,val,kv,mode,ret;
435         mask = 0;
436         val = 0;
437         ret = 0;
438         while (len) {
439                 cnt = 0;
440                 while ((cnt < len) &&
441                        ((ptr[cnt] <= 32) ||
442                         (ptr[cnt] >= 127))) cnt++;
443                 ptr += cnt;
444                 len -= cnt;
445                 mode = 0;
446                 if ((*ptr == '-') || (*ptr == '+')) {
447                         mode = (*ptr == '-') ? -1 : 1;
448                         ptr++;
449                         len--;
450                 }
451                 cnt = 0;
452                 while (cnt < len) {
453                         if (ptr[cnt] <= 32) break;
454                         if (ptr[cnt] >= 127) break;
455                         cnt++;
456                 }
457                 if (!cnt) break;
458                 if (parse_mtoken(ptr,cnt,&kv,names,valid_bits)) {
459                         ret = -EINVAL;
460                         break;
461                 }
462                 ptr += cnt;
463                 len -= cnt;
464                 switch (mode) {
465                 case 0:
466                         mask = valid_bits;
467                         val |= kv;
468                         break;
469                 case -1:
470                         mask |= kv;
471                         val &= ~kv;
472                         break;
473                 case 1:
474                         mask |= kv;
475                         val |= kv;
476                         break;
477                 default:
478                         break;
479                 }
480         }
481         *maskptr = mask;
482         *valptr = val;
483         return ret;
484 }
485
486
487 /* Convert a symbolic value to a mask/value pair */
488 int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *cptr,
489                            const char *ptr,unsigned int len,
490                            int *maskptr,int *valptr)
491 {
492         int ret = -EINVAL;
493         unsigned int cnt;
494
495         *maskptr = 0;
496         *valptr = 0;
497
498         cnt = 0;
499         while ((cnt < len) && ((ptr[cnt] <= 32) || (ptr[cnt] >= 127))) cnt++;
500         len -= cnt; ptr += cnt;
501         cnt = 0;
502         while ((cnt < len) && ((ptr[len-(cnt+1)] <= 32) ||
503                                (ptr[len-(cnt+1)] >= 127))) cnt++;
504         len -= cnt;
505
506         if (!len) return -EINVAL;
507
508         LOCK_TAKE(cptr->hdw->big_lock); do {
509                 if (cptr->info->type == pvr2_ctl_int) {
510                         ret = parse_token(ptr,len,valptr,NULL,0);
511                         if (ret >= 0) {
512                                 ret = pvr2_ctrl_range_check(cptr,*valptr);
513                         }
514                         if (maskptr) *maskptr = ~0;
515                 } else if (cptr->info->type == pvr2_ctl_bool) {
516                         ret = parse_token(ptr,len,valptr,boolNames,
517                                           ARRAY_SIZE(boolNames));
518                         if (ret == 1) {
519                                 *valptr = *valptr ? !0 : 0;
520                         } else if (ret == 0) {
521                                 *valptr = (*valptr & 1) ? !0 : 0;
522                         }
523                         if (maskptr) *maskptr = 1;
524                 } else if (cptr->info->type == pvr2_ctl_enum) {
525                         ret = parse_token(
526                                 ptr,len,valptr,
527                                 cptr->info->def.type_enum.value_names,
528                                 cptr->info->def.type_enum.count);
529                         if (ret >= 0) {
530                                 ret = pvr2_ctrl_range_check(cptr,*valptr);
531                         }
532                         if (maskptr) *maskptr = ~0;
533                 } else if (cptr->info->type == pvr2_ctl_bitmask) {
534                         ret = parse_tlist(
535                                 ptr,len,maskptr,valptr,
536                                 cptr->info->def.type_bitmask.bit_names,
537                                 cptr->info->def.type_bitmask.valid_bits);
538                 }
539         } while(0); LOCK_GIVE(cptr->hdw->big_lock);
540         return ret;
541 }
542
543
544 /* Convert a given mask/val to a symbolic value */
545 int pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *cptr,
546                                     int mask,int val,
547                                     char *buf,unsigned int maxlen,
548                                     unsigned int *len)
549 {
550         int ret = -EINVAL;
551
552         *len = 0;
553         if (cptr->info->type == pvr2_ctl_int) {
554                 *len = scnprintf(buf,maxlen,"%d",val);
555                 ret = 0;
556         } else if (cptr->info->type == pvr2_ctl_bool) {
557                 *len = scnprintf(buf,maxlen,"%s",val ? "true" : "false");
558                 ret = 0;
559         } else if (cptr->info->type == pvr2_ctl_enum) {
560                 const char **names;
561                 names = cptr->info->def.type_enum.value_names;
562                 if ((val >= 0) &&
563                     (val < cptr->info->def.type_enum.count)) {
564                         if (names[val]) {
565                                 *len = scnprintf(
566                                         buf,maxlen,"%s",
567                                         names[val]);
568                         } else {
569                                 *len = 0;
570                         }
571                         ret = 0;
572                 }
573         } else if (cptr->info->type == pvr2_ctl_bitmask) {
574                 *len = gen_bitmask_string(
575                         val & mask & cptr->info->def.type_bitmask.valid_bits,
576                         ~0,!0,
577                         cptr->info->def.type_bitmask.bit_names,
578                         buf,maxlen);
579         }
580         return ret;
581 }
582
583
584 /* Convert a given mask/val to a symbolic value */
585 int pvr2_ctrl_value_to_sym(struct pvr2_ctrl *cptr,
586                            int mask,int val,
587                            char *buf,unsigned int maxlen,
588                            unsigned int *len)
589 {
590         int ret;
591         LOCK_TAKE(cptr->hdw->big_lock); do {
592                 ret = pvr2_ctrl_value_to_sym_internal(cptr,mask,val,
593                                                       buf,maxlen,len);
594         } while(0); LOCK_GIVE(cptr->hdw->big_lock);
595         return ret;
596 }
597
598
599 /*
600   Stuff for Emacs to see, in order to encourage consistent editing style:
601   *** Local Variables: ***
602   *** mode: c ***
603   *** fill-column: 75 ***
604   *** tab-width: 8 ***
605   *** c-basic-offset: 8 ***
606   *** End: ***
607   */