linux/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c
<<
>>
Prefs
   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
  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        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
 388static 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
 417static 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 */
 476int 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 */
 533int 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 */
 573int 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