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