123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598 |
- /*
- *
- *
- * Copyright (C) 2005 Mike Isely <isely@pobox.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
- #include "pvrusb2-ctrl.h"
- #include "pvrusb2-hdw-internal.h"
- #include <linux/errno.h>
- #include <linux/string.h>
- #include <linux/mutex.h>
- static int pvr2_ctrl_range_check(struct pvr2_ctrl *cptr,int val)
- {
- if (cptr->info->check_value) {
- if (!cptr->info->check_value(cptr,val)) return -ERANGE;
- } else if (cptr->info->type == pvr2_ctl_enum) {
- if (val < 0) return -ERANGE;
- if (val >= cptr->info->def.type_enum.count) return -ERANGE;
- } else {
- int lim;
- lim = cptr->info->def.type_int.min_value;
- if (cptr->info->get_min_value) {
- cptr->info->get_min_value(cptr,&lim);
- }
- if (val < lim) return -ERANGE;
- lim = cptr->info->def.type_int.max_value;
- if (cptr->info->get_max_value) {
- cptr->info->get_max_value(cptr,&lim);
- }
- if (val > lim) return -ERANGE;
- }
- return 0;
- }
- /* Set the given control. */
- int pvr2_ctrl_set_value(struct pvr2_ctrl *cptr,int val)
- {
- return pvr2_ctrl_set_mask_value(cptr,~0,val);
- }
- /* Set/clear specific bits of the given control. */
- int pvr2_ctrl_set_mask_value(struct pvr2_ctrl *cptr,int mask,int val)
- {
- int ret = 0;
- if (!cptr) return -EINVAL;
- LOCK_TAKE(cptr->hdw->big_lock); do {
- if (cptr->info->set_value) {
- if (cptr->info->type == pvr2_ctl_bitmask) {
- mask &= cptr->info->def.type_bitmask.valid_bits;
- } else if ((cptr->info->type == pvr2_ctl_int)||
- (cptr->info->type == pvr2_ctl_enum)) {
- ret = pvr2_ctrl_range_check(cptr,val);
- if (ret < 0) break;
- } else if (cptr->info->type != pvr2_ctl_bool) {
- break;
- }
- ret = cptr->info->set_value(cptr,mask,val);
- } else {
- ret = -EPERM;
- }
- } while(0); LOCK_GIVE(cptr->hdw->big_lock);
- return ret;
- }
- /* Get the current value of the given control. */
- int pvr2_ctrl_get_value(struct pvr2_ctrl *cptr,int *valptr)
- {
- int ret = 0;
- if (!cptr) return -EINVAL;
- LOCK_TAKE(cptr->hdw->big_lock); do {
- ret = cptr->info->get_value(cptr,valptr);
- } while(0); LOCK_GIVE(cptr->hdw->big_lock);
- return ret;
- }
- /* Retrieve control's type */
- enum pvr2_ctl_type pvr2_ctrl_get_type(struct pvr2_ctrl *cptr)
- {
- if (!cptr) return pvr2_ctl_int;
- return cptr->info->type;
- }
- /* Retrieve control's maximum value (int type) */
- int pvr2_ctrl_get_max(struct pvr2_ctrl *cptr)
- {
- int ret = 0;
- if (!cptr) return 0;
- LOCK_TAKE(cptr->hdw->big_lock); do {
- if (cptr->info->get_max_value) {
- cptr->info->get_max_value(cptr,&ret);
- } else if (cptr->info->type == pvr2_ctl_int) {
- ret = cptr->info->def.type_int.max_value;
- }
- } while(0); LOCK_GIVE(cptr->hdw->big_lock);
- return ret;
- }
- /* Retrieve control's minimum value (int type) */
- int pvr2_ctrl_get_min(struct pvr2_ctrl *cptr)
- {
- int ret = 0;
- if (!cptr) return 0;
- LOCK_TAKE(cptr->hdw->big_lock); do {
- if (cptr->info->get_min_value) {
- cptr->info->get_min_value(cptr,&ret);
- } else if (cptr->info->type == pvr2_ctl_int) {
- ret = cptr->info->def.type_int.min_value;
- }
- } while(0); LOCK_GIVE(cptr->hdw->big_lock);
- return ret;
- }
- /* Retrieve control's default value (any type) */
- int pvr2_ctrl_get_def(struct pvr2_ctrl *cptr, int *valptr)
- {
- int ret = 0;
- if (!cptr) return -EINVAL;
- LOCK_TAKE(cptr->hdw->big_lock); do {
- if (cptr->info->get_def_value) {
- ret = cptr->info->get_def_value(cptr, valptr);
- } else {
- *valptr = cptr->info->default_value;
- }
- } while(0); LOCK_GIVE(cptr->hdw->big_lock);
- return ret;
- }
- /* Retrieve control's enumeration count (enum only) */
- int pvr2_ctrl_get_cnt(struct pvr2_ctrl *cptr)
- {
- int ret = 0;
- if (!cptr) return 0;
- LOCK_TAKE(cptr->hdw->big_lock); do {
- if (cptr->info->type == pvr2_ctl_enum) {
- ret = cptr->info->def.type_enum.count;
- }
- } while(0); LOCK_GIVE(cptr->hdw->big_lock);
- return ret;
- }
- /* Retrieve control's valid mask bits (bit mask only) */
- int pvr2_ctrl_get_mask(struct pvr2_ctrl *cptr)
- {
- int ret = 0;
- if (!cptr) return 0;
- LOCK_TAKE(cptr->hdw->big_lock); do {
- if (cptr->info->type == pvr2_ctl_bitmask) {
- ret = cptr->info->def.type_bitmask.valid_bits;
- }
- } while(0); LOCK_GIVE(cptr->hdw->big_lock);
- return ret;
- }
- /* Retrieve the control's name */
- const char *pvr2_ctrl_get_name(struct pvr2_ctrl *cptr)
- {
- if (!cptr) return NULL;
- return cptr->info->name;
- }
- /* Retrieve the control's desc */
- const char *pvr2_ctrl_get_desc(struct pvr2_ctrl *cptr)
- {
- if (!cptr) return NULL;
- return cptr->info->desc;
- }
- /* Retrieve a control enumeration or bit mask value */
- int pvr2_ctrl_get_valname(struct pvr2_ctrl *cptr,int val,
- char *bptr,unsigned int bmax,
- unsigned int *blen)
- {
- int ret = -EINVAL;
- if (!cptr) return 0;
- *blen = 0;
- LOCK_TAKE(cptr->hdw->big_lock); do {
- if (cptr->info->type == pvr2_ctl_enum) {
- const char * const *names;
- names = cptr->info->def.type_enum.value_names;
- if (pvr2_ctrl_range_check(cptr,val) == 0) {
- if (names[val]) {
- *blen = scnprintf(
- bptr,bmax,"%s",
- names[val]);
- } else {
- *blen = 0;
- }
- ret = 0;
- }
- } else if (cptr->info->type == pvr2_ctl_bitmask) {
- const char **names;
- unsigned int idx;
- int msk;
- names = cptr->info->def.type_bitmask.bit_names;
- val &= cptr->info->def.type_bitmask.valid_bits;
- for (idx = 0, msk = 1; val; idx++, msk <<= 1) {
- if (val & msk) {
- *blen = scnprintf(bptr,bmax,"%s",
- names[idx]);
- ret = 0;
- break;
- }
- }
- }
- } while(0); LOCK_GIVE(cptr->hdw->big_lock);
- return ret;
- }
- /* Return V4L ID for this control or zero if none */
- int pvr2_ctrl_get_v4lid(struct pvr2_ctrl *cptr)
- {
- if (!cptr) return 0;
- return cptr->info->v4l_id;
- }
- unsigned int pvr2_ctrl_get_v4lflags(struct pvr2_ctrl *cptr)
- {
- unsigned int flags = 0;
- if (cptr->info->get_v4lflags) {
- flags = cptr->info->get_v4lflags(cptr);
- }
- if (cptr->info->set_value) {
- flags &= ~V4L2_CTRL_FLAG_READ_ONLY;
- } else {
- flags |= V4L2_CTRL_FLAG_READ_ONLY;
- }
- return flags;
- }
- /* Return true if control is writable */
- int pvr2_ctrl_is_writable(struct pvr2_ctrl *cptr)
- {
- if (!cptr) return 0;
- return cptr->info->set_value != NULL;
- }
- /* Return true if control has custom symbolic representation */
- int pvr2_ctrl_has_custom_symbols(struct pvr2_ctrl *cptr)
- {
- if (!cptr) return 0;
- if (!cptr->info->val_to_sym) return 0;
- if (!cptr->info->sym_to_val) return 0;
- return !0;
- }
- /* Convert a given mask/val to a custom symbolic value */
- int pvr2_ctrl_custom_value_to_sym(struct pvr2_ctrl *cptr,
- int mask,int val,
- char *buf,unsigned int maxlen,
- unsigned int *len)
- {
- if (!cptr) return -EINVAL;
- if (!cptr->info->val_to_sym) return -EINVAL;
- return cptr->info->val_to_sym(cptr,mask,val,buf,maxlen,len);
- }
- /* Convert a symbolic value to a mask/value pair */
- int pvr2_ctrl_custom_sym_to_value(struct pvr2_ctrl *cptr,
- const char *buf,unsigned int len,
- int *maskptr,int *valptr)
- {
- if (!cptr) return -EINVAL;
- if (!cptr->info->sym_to_val) return -EINVAL;
- return cptr->info->sym_to_val(cptr,buf,len,maskptr,valptr);
- }
- static unsigned int gen_bitmask_string(int msk,int val,int msk_only,
- const char **names,
- char *ptr,unsigned int len)
- {
- unsigned int idx;
- long sm,um;
- int spcFl;
- unsigned int uc,cnt;
- const char *idStr;
- spcFl = 0;
- uc = 0;
- um = 0;
- for (idx = 0, sm = 1; msk; idx++, sm <<= 1) {
- if (sm & msk) {
- msk &= ~sm;
- idStr = names[idx];
- if (idStr) {
- cnt = scnprintf(ptr,len,"%s%s%s",
- (spcFl ? " " : ""),
- (msk_only ? "" :
- ((val & sm) ? "+" : "-")),
- idStr);
- ptr += cnt; len -= cnt; uc += cnt;
- spcFl = !0;
- } else {
- um |= sm;
- }
- }
- }
- if (um) {
- if (msk_only) {
- cnt = scnprintf(ptr,len,"%s0x%lx",
- (spcFl ? " " : ""),
- um);
- ptr += cnt; len -= cnt; uc += cnt;
- spcFl = !0;
- } else if (um & val) {
- cnt = scnprintf(ptr,len,"%s+0x%lx",
- (spcFl ? " " : ""),
- um & val);
- ptr += cnt; len -= cnt; uc += cnt;
- spcFl = !0;
- } else if (um & ~val) {
- cnt = scnprintf(ptr,len,"%s+0x%lx",
- (spcFl ? " " : ""),
- um & ~val);
- ptr += cnt; len -= cnt; uc += cnt;
- spcFl = !0;
- }
- }
- return uc;
- }
- static const char *boolNames[] = {
- "false",
- "true",
- "no",
- "yes",
- };
- static int parse_token(const char *ptr,unsigned int len,
- int *valptr,
- const char * const *names, unsigned int namecnt)
- {
- char buf[33];
- unsigned int slen;
- unsigned int idx;
- int negfl;
- char *p2;
- *valptr = 0;
- if (!names) namecnt = 0;
- for (idx = 0; idx < namecnt; idx++) {
- if (!names[idx]) continue;
- slen = strlen(names[idx]);
- if (slen != len) continue;
- if (memcmp(names[idx],ptr,slen)) continue;
- *valptr = idx;
- return 0;
- }
- negfl = 0;
- if ((*ptr == '-') || (*ptr == '+')) {
- negfl = (*ptr == '-');
- ptr++; len--;
- }
- if (len >= sizeof(buf)) return -EINVAL;
- memcpy(buf,ptr,len);
- buf[len] = 0;
- *valptr = simple_strtol(buf,&p2,0);
- if (negfl) *valptr = -(*valptr);
- if (*p2) return -EINVAL;
- return 1;
- }
- static int parse_mtoken(const char *ptr,unsigned int len,
- int *valptr,
- const char **names,int valid_bits)
- {
- char buf[33];
- unsigned int slen;
- unsigned int idx;
- char *p2;
- int msk;
- *valptr = 0;
- for (idx = 0, msk = 1; valid_bits; idx++, msk <<= 1) {
- if (!(msk & valid_bits)) continue;
- valid_bits &= ~msk;
- if (!names[idx]) continue;
- slen = strlen(names[idx]);
- if (slen != len) continue;
- if (memcmp(names[idx],ptr,slen)) continue;
- *valptr = msk;
- return 0;
- }
- if (len >= sizeof(buf)) return -EINVAL;
- memcpy(buf,ptr,len);
- buf[len] = 0;
- *valptr = simple_strtol(buf,&p2,0);
- if (*p2) return -EINVAL;
- return 0;
- }
- static int parse_tlist(const char *ptr,unsigned int len,
- int *maskptr,int *valptr,
- const char **names,int valid_bits)
- {
- unsigned int cnt;
- int mask,val,kv,mode,ret;
- mask = 0;
- val = 0;
- ret = 0;
- while (len) {
- cnt = 0;
- while ((cnt < len) &&
- ((ptr[cnt] <= 32) ||
- (ptr[cnt] >= 127))) cnt++;
- ptr += cnt;
- len -= cnt;
- mode = 0;
- if ((*ptr == '-') || (*ptr == '+')) {
- mode = (*ptr == '-') ? -1 : 1;
- ptr++;
- len--;
- }
- cnt = 0;
- while (cnt < len) {
- if (ptr[cnt] <= 32) break;
- if (ptr[cnt] >= 127) break;
- cnt++;
- }
- if (!cnt) break;
- if (parse_mtoken(ptr,cnt,&kv,names,valid_bits)) {
- ret = -EINVAL;
- break;
- }
- ptr += cnt;
- len -= cnt;
- switch (mode) {
- case 0:
- mask = valid_bits;
- val |= kv;
- break;
- case -1:
- mask |= kv;
- val &= ~kv;
- break;
- case 1:
- mask |= kv;
- val |= kv;
- break;
- default:
- break;
- }
- }
- *maskptr = mask;
- *valptr = val;
- return ret;
- }
- /* Convert a symbolic value to a mask/value pair */
- int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *cptr,
- const char *ptr,unsigned int len,
- int *maskptr,int *valptr)
- {
- int ret = -EINVAL;
- unsigned int cnt;
- *maskptr = 0;
- *valptr = 0;
- cnt = 0;
- while ((cnt < len) && ((ptr[cnt] <= 32) || (ptr[cnt] >= 127))) cnt++;
- len -= cnt; ptr += cnt;
- cnt = 0;
- while ((cnt < len) && ((ptr[len-(cnt+1)] <= 32) ||
- (ptr[len-(cnt+1)] >= 127))) cnt++;
- len -= cnt;
- if (!len) return -EINVAL;
- LOCK_TAKE(cptr->hdw->big_lock); do {
- if (cptr->info->type == pvr2_ctl_int) {
- ret = parse_token(ptr,len,valptr,NULL,0);
- if (ret >= 0) {
- ret = pvr2_ctrl_range_check(cptr,*valptr);
- }
- *maskptr = ~0;
- } else if (cptr->info->type == pvr2_ctl_bool) {
- ret = parse_token(ptr,len,valptr,boolNames,
- ARRAY_SIZE(boolNames));
- if (ret == 1) {
- *valptr = *valptr ? !0 : 0;
- } else if (ret == 0) {
- *valptr = (*valptr & 1) ? !0 : 0;
- }
- *maskptr = 1;
- } else if (cptr->info->type == pvr2_ctl_enum) {
- ret = parse_token(
- ptr,len,valptr,
- cptr->info->def.type_enum.value_names,
- cptr->info->def.type_enum.count);
- if (ret >= 0) {
- ret = pvr2_ctrl_range_check(cptr,*valptr);
- }
- *maskptr = ~0;
- } else if (cptr->info->type == pvr2_ctl_bitmask) {
- ret = parse_tlist(
- ptr,len,maskptr,valptr,
- cptr->info->def.type_bitmask.bit_names,
- cptr->info->def.type_bitmask.valid_bits);
- }
- } while(0); LOCK_GIVE(cptr->hdw->big_lock);
- return ret;
- }
- /* Convert a given mask/val to a symbolic value */
- int pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *cptr,
- int mask,int val,
- char *buf,unsigned int maxlen,
- unsigned int *len)
- {
- int ret = -EINVAL;
- *len = 0;
- if (cptr->info->type == pvr2_ctl_int) {
- *len = scnprintf(buf,maxlen,"%d",val);
- ret = 0;
- } else if (cptr->info->type == pvr2_ctl_bool) {
- *len = scnprintf(buf,maxlen,"%s",val ? "true" : "false");
- ret = 0;
- } else if (cptr->info->type == pvr2_ctl_enum) {
- const char * const *names;
- names = cptr->info->def.type_enum.value_names;
- if ((val >= 0) &&
- (val < cptr->info->def.type_enum.count)) {
- if (names[val]) {
- *len = scnprintf(
- buf,maxlen,"%s",
- names[val]);
- } else {
- *len = 0;
- }
- ret = 0;
- }
- } else if (cptr->info->type == pvr2_ctl_bitmask) {
- *len = gen_bitmask_string(
- val & mask & cptr->info->def.type_bitmask.valid_bits,
- ~0,!0,
- cptr->info->def.type_bitmask.bit_names,
- buf,maxlen);
- }
- return ret;
- }
- /* Convert a given mask/val to a symbolic value */
- int pvr2_ctrl_value_to_sym(struct pvr2_ctrl *cptr,
- int mask,int val,
- char *buf,unsigned int maxlen,
- unsigned int *len)
- {
- int ret;
- LOCK_TAKE(cptr->hdw->big_lock); do {
- ret = pvr2_ctrl_value_to_sym_internal(cptr,mask,val,
- buf,maxlen,len);
- } while(0); LOCK_GIVE(cptr->hdw->big_lock);
- return ret;
- }
|