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