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