1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 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 14 static 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. */ 39 int 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. */ 46 int 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. */ 71 int 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 */ 83 enum 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) */ 91 int 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) */ 107 int 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) */ 123 int 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) */ 139 int 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) */ 153 int 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 */ 167 const 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 */ 175 const 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 */ 183 int 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 */ 225 int pvr2_ctrl_get_v4lid(struct pvr2_ctrl *cptr) 226 { 227 if (!cptr) return 0; 228 return cptr->info->v4l_id; 229 } 230 231 232 unsigned 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 */ 251 int 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 */ 259 int 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 */ 269 int 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 */ 281 int 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 291 static 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 346 static const char *boolNames[] = { 347 "false", 348 "true", 349 "no", 350 "yes", 351 }; 352 353 354 static int parse_token(const char *ptr,unsigned int len, 355 int *valptr, 356 const char * const *names, unsigned int namecnt) 357 { 358 char buf[33]; 359 unsigned int slen; 360 unsigned int idx; 361 int negfl; 362 char *p2; 363 *valptr = 0; 364 if (!names) namecnt = 0; 365 for (idx = 0; idx < namecnt; idx++) { 366 if (!names[idx]) continue; 367 slen = strlen(names[idx]); 368 if (slen != len) continue; 369 if (memcmp(names[idx],ptr,slen)) continue; 370 *valptr = idx; 371 return 0; 372 } 373 negfl = 0; 374 if ((*ptr == '-') || (*ptr == '+')) { 375 negfl = (*ptr == '-'); 376 ptr++; len--; 377 } 378 if (len >= sizeof(buf)) return -EINVAL; 379 memcpy(buf,ptr,len); 380 buf[len] = 0; 381 *valptr = simple_strtol(buf,&p2,0); 382 if (negfl) *valptr = -(*valptr); 383 if (*p2) return -EINVAL; 384 return 1; 385 } 386 387 388 static int parse_mtoken(const char *ptr,unsigned int len, 389 int *valptr, 390 const char **names,int valid_bits) 391 { 392 char buf[33]; 393 unsigned int slen; 394 unsigned int idx; 395 char *p2; 396 int msk; 397 *valptr = 0; 398 for (idx = 0, msk = 1; valid_bits; idx++, msk <<= 1) { 399 if (!(msk & valid_bits)) continue; 400 valid_bits &= ~msk; 401 if (!names[idx]) continue; 402 slen = strlen(names[idx]); 403 if (slen != len) continue; 404 if (memcmp(names[idx],ptr,slen)) continue; 405 *valptr = msk; 406 return 0; 407 } 408 if (len >= sizeof(buf)) return -EINVAL; 409 memcpy(buf,ptr,len); 410 buf[len] = 0; 411 *valptr = simple_strtol(buf,&p2,0); 412 if (*p2) return -EINVAL; 413 return 0; 414 } 415 416 417 static int parse_tlist(const char *ptr,unsigned int len, 418 int *maskptr,int *valptr, 419 const char **names,int valid_bits) 420 { 421 unsigned int cnt; 422 int mask,val,kv,mode,ret; 423 mask = 0; 424 val = 0; 425 ret = 0; 426 while (len) { 427 cnt = 0; 428 while ((cnt < len) && 429 ((ptr[cnt] <= 32) || 430 (ptr[cnt] >= 127))) cnt++; 431 ptr += cnt; 432 len -= cnt; 433 mode = 0; 434 if ((*ptr == '-') || (*ptr == '+')) { 435 mode = (*ptr == '-') ? -1 : 1; 436 ptr++; 437 len--; 438 } 439 cnt = 0; 440 while (cnt < len) { 441 if (ptr[cnt] <= 32) break; 442 if (ptr[cnt] >= 127) break; 443 cnt++; 444 } 445 if (!cnt) break; 446 if (parse_mtoken(ptr,cnt,&kv,names,valid_bits)) { 447 ret = -EINVAL; 448 break; 449 } 450 ptr += cnt; 451 len -= cnt; 452 switch (mode) { 453 case 0: 454 mask = valid_bits; 455 val |= kv; 456 break; 457 case -1: 458 mask |= kv; 459 val &= ~kv; 460 break; 461 case 1: 462 mask |= kv; 463 val |= kv; 464 break; 465 default: 466 break; 467 } 468 } 469 *maskptr = mask; 470 *valptr = val; 471 return ret; 472 } 473 474 475 /* Convert a symbolic value to a mask/value pair */ 476 int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *cptr, 477 const char *ptr,unsigned int len, 478 int *maskptr,int *valptr) 479 { 480 int ret = -EINVAL; 481 unsigned int cnt; 482 483 *maskptr = 0; 484 *valptr = 0; 485 486 cnt = 0; 487 while ((cnt < len) && ((ptr[cnt] <= 32) || (ptr[cnt] >= 127))) cnt++; 488 len -= cnt; ptr += cnt; 489 cnt = 0; 490 while ((cnt < len) && ((ptr[len-(cnt+1)] <= 32) || 491 (ptr[len-(cnt+1)] >= 127))) cnt++; 492 len -= cnt; 493 494 if (!len) return -EINVAL; 495 496 LOCK_TAKE(cptr->hdw->big_lock); do { 497 if (cptr->info->type == pvr2_ctl_int) { 498 ret = parse_token(ptr,len,valptr,NULL,0); 499 if (ret >= 0) { 500 ret = pvr2_ctrl_range_check(cptr,*valptr); 501 } 502 *maskptr = ~0; 503 } else if (cptr->info->type == pvr2_ctl_bool) { 504 ret = parse_token(ptr,len,valptr,boolNames, 505 ARRAY_SIZE(boolNames)); 506 if (ret == 1) { 507 *valptr = *valptr ? !0 : 0; 508 } else if (ret == 0) { 509 *valptr = (*valptr & 1) ? !0 : 0; 510 } 511 *maskptr = 1; 512 } else if (cptr->info->type == pvr2_ctl_enum) { 513 ret = parse_token( 514 ptr,len,valptr, 515 cptr->info->def.type_enum.value_names, 516 cptr->info->def.type_enum.count); 517 if (ret >= 0) { 518 ret = pvr2_ctrl_range_check(cptr,*valptr); 519 } 520 *maskptr = ~0; 521 } else if (cptr->info->type == pvr2_ctl_bitmask) { 522 ret = parse_tlist( 523 ptr,len,maskptr,valptr, 524 cptr->info->def.type_bitmask.bit_names, 525 cptr->info->def.type_bitmask.valid_bits); 526 } 527 } while(0); LOCK_GIVE(cptr->hdw->big_lock); 528 return ret; 529 } 530 531 532 /* Convert a given mask/val to a symbolic value */ 533 int pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *cptr, 534 int mask,int val, 535 char *buf,unsigned int maxlen, 536 unsigned int *len) 537 { 538 int ret = -EINVAL; 539 540 *len = 0; 541 if (cptr->info->type == pvr2_ctl_int) { 542 *len = scnprintf(buf,maxlen,"%d",val); 543 ret = 0; 544 } else if (cptr->info->type == pvr2_ctl_bool) { 545 *len = scnprintf(buf,maxlen,"%s",val ? "true" : "false"); 546 ret = 0; 547 } else if (cptr->info->type == pvr2_ctl_enum) { 548 const char * const *names; 549 names = cptr->info->def.type_enum.value_names; 550 if ((val >= 0) && 551 (val < cptr->info->def.type_enum.count)) { 552 if (names[val]) { 553 *len = scnprintf( 554 buf,maxlen,"%s", 555 names[val]); 556 } else { 557 *len = 0; 558 } 559 ret = 0; 560 } 561 } else if (cptr->info->type == pvr2_ctl_bitmask) { 562 *len = gen_bitmask_string( 563 val & mask & cptr->info->def.type_bitmask.valid_bits, 564 ~0,!0, 565 cptr->info->def.type_bitmask.bit_names, 566 buf,maxlen); 567 } 568 return ret; 569 } 570 571 572 /* Convert a given mask/val to a symbolic value */ 573 int pvr2_ctrl_value_to_sym(struct pvr2_ctrl *cptr, 574 int mask,int val, 575 char *buf,unsigned int maxlen, 576 unsigned int *len) 577 { 578 int ret; 579 LOCK_TAKE(cptr->hdw->big_lock); do { 580 ret = pvr2_ctrl_value_to_sym_internal(cptr,mask,val, 581 buf,maxlen,len); 582 } while(0); LOCK_GIVE(cptr->hdw->big_lock); 583 return ret; 584 } 585