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