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