blob: d644afec5a5c6262cae411adacfc9376c5d97bf8 [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
217/* Return true if control is writable */
218int pvr2_ctrl_is_writable(struct pvr2_ctrl *cptr)
219{
220 if (!cptr) return 0;
221 return cptr->info->set_value != 0;
222}
223
224
225/* Return true if control has custom symbolic representation */
226int pvr2_ctrl_has_custom_symbols(struct pvr2_ctrl *cptr)
227{
228 if (!cptr) return 0;
229 if (!cptr->info->val_to_sym) return 0;
230 if (!cptr->info->sym_to_val) return 0;
231 return !0;
232}
233
234
235/* Convert a given mask/val to a custom symbolic value */
236int pvr2_ctrl_custom_value_to_sym(struct pvr2_ctrl *cptr,
237 int mask,int val,
238 char *buf,unsigned int maxlen,
239 unsigned int *len)
240{
241 if (!cptr) return -EINVAL;
242 if (!cptr->info->val_to_sym) return -EINVAL;
243 return cptr->info->val_to_sym(cptr,mask,val,buf,maxlen,len);
244}
245
246
247/* Convert a symbolic value to a mask/value pair */
248int pvr2_ctrl_custom_sym_to_value(struct pvr2_ctrl *cptr,
249 const char *buf,unsigned int len,
250 int *maskptr,int *valptr)
251{
252 if (!cptr) return -EINVAL;
253 if (!cptr->info->sym_to_val) return -EINVAL;
254 return cptr->info->sym_to_val(cptr,buf,len,maskptr,valptr);
255}
256
257
258static unsigned int gen_bitmask_string(int msk,int val,int msk_only,
259 const char **names,
260 char *ptr,unsigned int len)
261{
262 unsigned int idx;
263 long sm,um;
264 int spcFl;
265 unsigned int uc,cnt;
266 const char *idStr;
267
268 spcFl = 0;
269 uc = 0;
270 um = 0;
271 for (idx = 0, sm = 1; msk; idx++, sm <<= 1) {
272 if (sm & msk) {
273 msk &= ~sm;
274 idStr = names[idx];
275 if (idStr) {
276 cnt = scnprintf(ptr,len,"%s%s%s",
277 (spcFl ? " " : ""),
278 (msk_only ? "" :
279 ((val & sm) ? "+" : "-")),
280 idStr);
281 ptr += cnt; len -= cnt; uc += cnt;
282 spcFl = !0;
283 } else {
284 um |= sm;
285 }
286 }
287 }
288 if (um) {
289 if (msk_only) {
290 cnt = scnprintf(ptr,len,"%s0x%lx",
291 (spcFl ? " " : ""),
292 um);
293 ptr += cnt; len -= cnt; uc += cnt;
294 spcFl = !0;
295 } else if (um & val) {
296 cnt = scnprintf(ptr,len,"%s+0x%lx",
297 (spcFl ? " " : ""),
298 um & val);
299 ptr += cnt; len -= cnt; uc += cnt;
300 spcFl = !0;
301 } else if (um & ~val) {
302 cnt = scnprintf(ptr,len,"%s+0x%lx",
303 (spcFl ? " " : ""),
304 um & ~val);
305 ptr += cnt; len -= cnt; uc += cnt;
306 spcFl = !0;
307 }
308 }
309 return uc;
310}
311
312
Mike Isely33213962006-06-25 20:04:40 -0300313static const char *boolNames[] = {
314 "false",
315 "true",
316 "no",
317 "yes",
318};
319
320
Mike Iselyd8554972006-06-26 20:58:46 -0300321static int parse_token(const char *ptr,unsigned int len,
322 int *valptr,
323 const char **names,unsigned int namecnt)
324{
325 char buf[33];
326 unsigned int slen;
327 unsigned int idx;
328 int negfl;
329 char *p2;
330 *valptr = 0;
331 if (!names) namecnt = 0;
332 for (idx = 0; idx < namecnt; idx++) {
333 if (!names[idx]) continue;
334 slen = strlen(names[idx]);
335 if (slen != len) continue;
336 if (memcmp(names[idx],ptr,slen)) continue;
337 *valptr = idx;
338 return 0;
339 }
340 negfl = 0;
341 if ((*ptr == '-') || (*ptr == '+')) {
342 negfl = (*ptr == '-');
343 ptr++; len--;
344 }
345 if (len >= sizeof(buf)) return -EINVAL;
346 memcpy(buf,ptr,len);
347 buf[len] = 0;
348 *valptr = simple_strtol(buf,&p2,0);
349 if (negfl) *valptr = -(*valptr);
350 if (*p2) return -EINVAL;
Mike Isely33213962006-06-25 20:04:40 -0300351 return 1;
Mike Iselyd8554972006-06-26 20:58:46 -0300352}
353
354
355static int parse_mtoken(const char *ptr,unsigned int len,
356 int *valptr,
357 const char **names,int valid_bits)
358{
359 char buf[33];
360 unsigned int slen;
361 unsigned int idx;
362 char *p2;
363 int msk;
364 *valptr = 0;
365 for (idx = 0, msk = 1; valid_bits; idx++, msk <<= 1) {
366 if (!msk & valid_bits) continue;
367 valid_bits &= ~msk;
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 = msk;
373 return 0;
374 }
375 if (len >= sizeof(buf)) return -EINVAL;
376 memcpy(buf,ptr,len);
377 buf[len] = 0;
378 *valptr = simple_strtol(buf,&p2,0);
379 if (*p2) return -EINVAL;
380 return 0;
381}
382
383
384static int parse_tlist(const char *ptr,unsigned int len,
385 int *maskptr,int *valptr,
386 const char **names,int valid_bits)
387{
388 unsigned int cnt;
389 int mask,val,kv,mode,ret;
390 mask = 0;
391 val = 0;
392 ret = 0;
393 while (len) {
394 cnt = 0;
395 while ((cnt < len) &&
396 ((ptr[cnt] <= 32) ||
397 (ptr[cnt] >= 127))) cnt++;
398 ptr += cnt;
399 len -= cnt;
400 mode = 0;
401 if ((*ptr == '-') || (*ptr == '+')) {
402 mode = (*ptr == '-') ? -1 : 1;
403 ptr++;
404 len--;
405 }
406 cnt = 0;
407 while (cnt < len) {
408 if (ptr[cnt] <= 32) break;
409 if (ptr[cnt] >= 127) break;
410 cnt++;
411 }
412 if (!cnt) break;
413 if (parse_mtoken(ptr,cnt,&kv,names,valid_bits)) {
414 ret = -EINVAL;
415 break;
416 }
417 ptr += cnt;
418 len -= cnt;
419 switch (mode) {
420 case 0:
421 mask = valid_bits;
422 val |= kv;
423 break;
424 case -1:
425 mask |= kv;
426 val &= ~kv;
427 break;
428 case 1:
429 mask |= kv;
430 val |= kv;
431 break;
432 default:
433 break;
434 }
435 }
436 *maskptr = mask;
437 *valptr = val;
438 return ret;
439}
440
441
442/* Convert a symbolic value to a mask/value pair */
443int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *cptr,
444 const char *ptr,unsigned int len,
445 int *maskptr,int *valptr)
446{
447 int ret = -EINVAL;
448 unsigned int cnt;
449
450 *maskptr = 0;
451 *valptr = 0;
452
453 cnt = 0;
454 while ((cnt < len) && ((ptr[cnt] <= 32) || (ptr[cnt] >= 127))) cnt++;
455 len -= cnt; ptr += cnt;
456 cnt = 0;
457 while ((cnt < len) && ((ptr[len-(cnt+1)] <= 32) ||
458 (ptr[len-(cnt+1)] >= 127))) cnt++;
459 len -= cnt;
460
461 if (!len) return -EINVAL;
462
463 LOCK_TAKE(cptr->hdw->big_lock); do {
464 if (cptr->info->type == pvr2_ctl_int) {
465 ret = parse_token(ptr,len,valptr,0,0);
Mike Isely33213962006-06-25 20:04:40 -0300466 if ((ret >= 0) &&
Mike Iselyd8554972006-06-26 20:58:46 -0300467 ((*valptr < cptr->info->def.type_int.min_value) ||
468 (*valptr > cptr->info->def.type_int.max_value))) {
Mike Isely33213962006-06-25 20:04:40 -0300469 ret = -ERANGE;
Mike Iselyd8554972006-06-26 20:58:46 -0300470 }
471 if (maskptr) *maskptr = ~0;
Mike Isely33213962006-06-25 20:04:40 -0300472 } else if (cptr->info->type == pvr2_ctl_bool) {
473 ret = parse_token(
474 ptr,len,valptr,boolNames,
475 sizeof(boolNames)/sizeof(boolNames[0]));
476 if (ret == 1) {
477 *valptr = *valptr ? !0 : 0;
478 } else if (ret == 0) {
479 *valptr = (*valptr & 1) ? !0 : 0;
480 }
481 if (maskptr) *maskptr = 1;
Mike Iselyd8554972006-06-26 20:58:46 -0300482 } else if (cptr->info->type == pvr2_ctl_enum) {
483 ret = parse_token(
484 ptr,len,valptr,
485 cptr->info->def.type_enum.value_names,
486 cptr->info->def.type_enum.count);
Mike Isely33213962006-06-25 20:04:40 -0300487 if ((ret >= 0) &&
Mike Iselyd8554972006-06-26 20:58:46 -0300488 ((*valptr < 0) ||
489 (*valptr >= cptr->info->def.type_enum.count))) {
Mike Isely33213962006-06-25 20:04:40 -0300490 ret = -ERANGE;
Mike Iselyd8554972006-06-26 20:58:46 -0300491 }
492 if (maskptr) *maskptr = ~0;
493 } else if (cptr->info->type == pvr2_ctl_bitmask) {
494 ret = parse_tlist(
495 ptr,len,maskptr,valptr,
496 cptr->info->def.type_bitmask.bit_names,
497 cptr->info->def.type_bitmask.valid_bits);
498 }
499 } while(0); LOCK_GIVE(cptr->hdw->big_lock);
500 return ret;
501}
502
503
504/* Convert a given mask/val to a symbolic value */
505int pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *cptr,
506 int mask,int val,
507 char *buf,unsigned int maxlen,
508 unsigned int *len)
509{
510 int ret = -EINVAL;
511
512 *len = 0;
513 if (cptr->info->type == pvr2_ctl_int) {
514 *len = scnprintf(buf,maxlen,"%d",val);
515 ret = 0;
Mike Isely33213962006-06-25 20:04:40 -0300516 } else if (cptr->info->type == pvr2_ctl_bool) {
517 *len = scnprintf(buf,maxlen,"%s",val ? "true" : "false");
518 ret = 0;
Mike Iselyd8554972006-06-26 20:58:46 -0300519 } else if (cptr->info->type == pvr2_ctl_enum) {
520 const char **names;
521 names = cptr->info->def.type_enum.value_names;
522 if ((val >= 0) &&
523 (val < cptr->info->def.type_enum.count)) {
524 if (names[val]) {
525 *len = scnprintf(
526 buf,maxlen,"%s",
527 names[val]);
528 } else {
529 *len = 0;
530 }
531 ret = 0;
532 }
533 } else if (cptr->info->type == pvr2_ctl_bitmask) {
534 *len = gen_bitmask_string(
535 val & mask & cptr->info->def.type_bitmask.valid_bits,
536 ~0,!0,
537 cptr->info->def.type_bitmask.bit_names,
538 buf,maxlen);
539 }
540 return ret;
541}
542
543
544/* Convert a given mask/val to a symbolic value */
545int pvr2_ctrl_value_to_sym(struct pvr2_ctrl *cptr,
546 int mask,int val,
547 char *buf,unsigned int maxlen,
548 unsigned int *len)
549{
550 int ret;
551 LOCK_TAKE(cptr->hdw->big_lock); do {
552 ret = pvr2_ctrl_value_to_sym_internal(cptr,mask,val,
553 buf,maxlen,len);
554 } while(0); LOCK_GIVE(cptr->hdw->big_lock);
555 return ret;
556}
557
558
559/*
560 Stuff for Emacs to see, in order to encourage consistent editing style:
561 *** Local Variables: ***
562 *** mode: c ***
563 *** fill-column: 75 ***
564 *** tab-width: 8 ***
565 *** c-basic-offset: 8 ***
566 *** End: ***
567 */