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