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 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 374 static 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 396 static 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 */ 455 int 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 */ 512 int 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 */ 552 int 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