linux/drivers/media/usb/pvrusb2/pvrusb2-std.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-std.h"
  18#include "pvrusb2-debug.h"
  19#include <asm/string.h>
  20#include <linux/slab.h>
  21
  22struct std_name {
  23        const char *name;
  24        v4l2_std_id id;
  25};
  26
  27
  28#define CSTD_PAL \
  29        (V4L2_STD_PAL_B| \
  30         V4L2_STD_PAL_B1| \
  31         V4L2_STD_PAL_G| \
  32         V4L2_STD_PAL_H| \
  33         V4L2_STD_PAL_I| \
  34         V4L2_STD_PAL_D| \
  35         V4L2_STD_PAL_D1| \
  36         V4L2_STD_PAL_K| \
  37         V4L2_STD_PAL_M| \
  38         V4L2_STD_PAL_N| \
  39         V4L2_STD_PAL_Nc| \
  40         V4L2_STD_PAL_60)
  41
  42#define CSTD_NTSC \
  43        (V4L2_STD_NTSC_M| \
  44         V4L2_STD_NTSC_M_JP| \
  45         V4L2_STD_NTSC_M_KR| \
  46         V4L2_STD_NTSC_443)
  47
  48#define CSTD_ATSC \
  49        (V4L2_STD_ATSC_8_VSB| \
  50         V4L2_STD_ATSC_16_VSB)
  51
  52#define CSTD_SECAM \
  53        (V4L2_STD_SECAM_B| \
  54         V4L2_STD_SECAM_D| \
  55         V4L2_STD_SECAM_G| \
  56         V4L2_STD_SECAM_H| \
  57         V4L2_STD_SECAM_K| \
  58         V4L2_STD_SECAM_K1| \
  59         V4L2_STD_SECAM_L| \
  60         V4L2_STD_SECAM_LC)
  61
  62#define TSTD_B   (V4L2_STD_PAL_B|V4L2_STD_SECAM_B)
  63#define TSTD_B1  (V4L2_STD_PAL_B1)
  64#define TSTD_D   (V4L2_STD_PAL_D|V4L2_STD_SECAM_D)
  65#define TSTD_D1  (V4L2_STD_PAL_D1)
  66#define TSTD_G   (V4L2_STD_PAL_G|V4L2_STD_SECAM_G)
  67#define TSTD_H   (V4L2_STD_PAL_H|V4L2_STD_SECAM_H)
  68#define TSTD_I   (V4L2_STD_PAL_I)
  69#define TSTD_K   (V4L2_STD_PAL_K|V4L2_STD_SECAM_K)
  70#define TSTD_K1  (V4L2_STD_SECAM_K1)
  71#define TSTD_L   (V4L2_STD_SECAM_L)
  72#define TSTD_M   (V4L2_STD_PAL_M|V4L2_STD_NTSC_M)
  73#define TSTD_N   (V4L2_STD_PAL_N)
  74#define TSTD_Nc  (V4L2_STD_PAL_Nc)
  75#define TSTD_60  (V4L2_STD_PAL_60)
  76
  77#define CSTD_ALL (CSTD_PAL|CSTD_NTSC|CSTD_ATSC|CSTD_SECAM)
  78
  79/* Mapping of standard bits to color system */
  80static const struct std_name std_groups[] = {
  81        {"PAL",CSTD_PAL},
  82        {"NTSC",CSTD_NTSC},
  83        {"SECAM",CSTD_SECAM},
  84        {"ATSC",CSTD_ATSC},
  85};
  86
  87/* Mapping of standard bits to modulation system */
  88static const struct std_name std_items[] = {
  89        {"B",TSTD_B},
  90        {"B1",TSTD_B1},
  91        {"D",TSTD_D},
  92        {"D1",TSTD_D1},
  93        {"G",TSTD_G},
  94        {"H",TSTD_H},
  95        {"I",TSTD_I},
  96        {"K",TSTD_K},
  97        {"K1",TSTD_K1},
  98        {"L",TSTD_L},
  99        {"LC",V4L2_STD_SECAM_LC},
 100        {"M",TSTD_M},
 101        {"Mj",V4L2_STD_NTSC_M_JP},
 102        {"443",V4L2_STD_NTSC_443},
 103        {"Mk",V4L2_STD_NTSC_M_KR},
 104        {"N",TSTD_N},
 105        {"Nc",TSTD_Nc},
 106        {"60",TSTD_60},
 107        {"8VSB",V4L2_STD_ATSC_8_VSB},
 108        {"16VSB",V4L2_STD_ATSC_16_VSB},
 109};
 110
 111
 112// Search an array of std_name structures and return a pointer to the
 113// element with the matching name.
 114static const struct std_name *find_std_name(const struct std_name *arrPtr,
 115                                            unsigned int arrSize,
 116                                            const char *bufPtr,
 117                                            unsigned int bufSize)
 118{
 119        unsigned int idx;
 120        const struct std_name *p;
 121        for (idx = 0; idx < arrSize; idx++) {
 122                p = arrPtr + idx;
 123                if (strlen(p->name) != bufSize) continue;
 124                if (!memcmp(bufPtr,p->name,bufSize)) return p;
 125        }
 126        return NULL;
 127}
 128
 129
 130int pvr2_std_str_to_id(v4l2_std_id *idPtr,const char *bufPtr,
 131                       unsigned int bufSize)
 132{
 133        v4l2_std_id id = 0;
 134        v4l2_std_id cmsk = 0;
 135        v4l2_std_id t;
 136        int mMode = 0;
 137        unsigned int cnt;
 138        char ch;
 139        const struct std_name *sp;
 140
 141        while (bufSize) {
 142                if (!mMode) {
 143                        cnt = 0;
 144                        while ((cnt < bufSize) && (bufPtr[cnt] != '-')) cnt++;
 145                        if (cnt >= bufSize) return 0; // No more characters
 146                        sp = find_std_name(std_groups, ARRAY_SIZE(std_groups),
 147                                           bufPtr,cnt);
 148                        if (!sp) return 0; // Illegal color system name
 149                        cnt++;
 150                        bufPtr += cnt;
 151                        bufSize -= cnt;
 152                        mMode = !0;
 153                        cmsk = sp->id;
 154                        continue;
 155                }
 156                cnt = 0;
 157                while (cnt < bufSize) {
 158                        ch = bufPtr[cnt];
 159                        if (ch == ';') {
 160                                mMode = 0;
 161                                break;
 162                        }
 163                        if (ch == '/') break;
 164                        cnt++;
 165                }
 166                sp = find_std_name(std_items, ARRAY_SIZE(std_items),
 167                                   bufPtr,cnt);
 168                if (!sp) return 0; // Illegal modulation system ID
 169                t = sp->id & cmsk;
 170                if (!t) return 0; // Specific color + modulation system illegal
 171                id |= t;
 172                if (cnt < bufSize) cnt++;
 173                bufPtr += cnt;
 174                bufSize -= cnt;
 175        }
 176
 177        if (idPtr) *idPtr = id;
 178        return !0;
 179}
 180
 181
 182unsigned int pvr2_std_id_to_str(char *bufPtr, unsigned int bufSize,
 183                                v4l2_std_id id)
 184{
 185        unsigned int idx1,idx2;
 186        const struct std_name *ip,*gp;
 187        int gfl,cfl;
 188        unsigned int c1,c2;
 189        cfl = 0;
 190        c1 = 0;
 191        for (idx1 = 0; idx1 < ARRAY_SIZE(std_groups); idx1++) {
 192                gp = std_groups + idx1;
 193                gfl = 0;
 194                for (idx2 = 0; idx2 < ARRAY_SIZE(std_items); idx2++) {
 195                        ip = std_items + idx2;
 196                        if (!(gp->id & ip->id & id)) continue;
 197                        if (!gfl) {
 198                                if (cfl) {
 199                                        c2 = scnprintf(bufPtr,bufSize,";");
 200                                        c1 += c2;
 201                                        bufSize -= c2;
 202                                        bufPtr += c2;
 203                                }
 204                                cfl = !0;
 205                                c2 = scnprintf(bufPtr,bufSize,
 206                                               "%s-",gp->name);
 207                                gfl = !0;
 208                        } else {
 209                                c2 = scnprintf(bufPtr,bufSize,"/");
 210                        }
 211                        c1 += c2;
 212                        bufSize -= c2;
 213                        bufPtr += c2;
 214                        c2 = scnprintf(bufPtr,bufSize,
 215                                       ip->name);
 216                        c1 += c2;
 217                        bufSize -= c2;
 218                        bufPtr += c2;
 219                }
 220        }
 221        return c1;
 222}
 223
 224
 225// Template data for possible enumerated video standards.  Here we group
 226// standards which share common frame rates and resolution.
 227static struct v4l2_standard generic_standards[] = {
 228        {
 229                .id             = (TSTD_B|TSTD_B1|
 230                                   TSTD_D|TSTD_D1|
 231                                   TSTD_G|
 232                                   TSTD_H|
 233                                   TSTD_I|
 234                                   TSTD_K|TSTD_K1|
 235                                   TSTD_L|
 236                                   V4L2_STD_SECAM_LC |
 237                                   TSTD_N|TSTD_Nc),
 238                .frameperiod    =
 239                {
 240                        .numerator  = 1,
 241                        .denominator= 25
 242                },
 243                .framelines     = 625,
 244                .reserved       = {0,0,0,0}
 245        }, {
 246                .id             = (TSTD_M|
 247                                   V4L2_STD_NTSC_M_JP|
 248                                   V4L2_STD_NTSC_M_KR),
 249                .frameperiod    =
 250                {
 251                        .numerator  = 1001,
 252                        .denominator= 30000
 253                },
 254                .framelines     = 525,
 255                .reserved       = {0,0,0,0}
 256        }, { // This is a total wild guess
 257                .id             = (TSTD_60),
 258                .frameperiod    =
 259                {
 260                        .numerator  = 1001,
 261                        .denominator= 30000
 262                },
 263                .framelines     = 525,
 264                .reserved       = {0,0,0,0}
 265        }, { // This is total wild guess
 266                .id             = V4L2_STD_NTSC_443,
 267                .frameperiod    =
 268                {
 269                        .numerator  = 1001,
 270                        .denominator= 30000
 271                },
 272                .framelines     = 525,
 273                .reserved       = {0,0,0,0}
 274        }
 275};
 276
 277static struct v4l2_standard *match_std(v4l2_std_id id)
 278{
 279        unsigned int idx;
 280        for (idx = 0; idx < ARRAY_SIZE(generic_standards); idx++) {
 281                if (generic_standards[idx].id & id) {
 282                        return generic_standards + idx;
 283                }
 284        }
 285        return NULL;
 286}
 287
 288static int pvr2_std_fill(struct v4l2_standard *std,v4l2_std_id id)
 289{
 290        struct v4l2_standard *template;
 291        int idx;
 292        unsigned int bcnt;
 293        template = match_std(id);
 294        if (!template) return 0;
 295        idx = std->index;
 296        memcpy(std,template,sizeof(*template));
 297        std->index = idx;
 298        std->id = id;
 299        bcnt = pvr2_std_id_to_str(std->name,sizeof(std->name)-1,id);
 300        std->name[bcnt] = 0;
 301        pvr2_trace(PVR2_TRACE_STD,"Set up standard idx=%u name=%s",
 302                   std->index,std->name);
 303        return !0;
 304}
 305
 306/* These are special cases of combined standards that we should enumerate
 307   separately if the component pieces are present. */
 308static v4l2_std_id std_mixes[] = {
 309        V4L2_STD_PAL_B | V4L2_STD_PAL_G,
 310        V4L2_STD_PAL_D | V4L2_STD_PAL_K,
 311        V4L2_STD_SECAM_B | V4L2_STD_SECAM_G,
 312        V4L2_STD_SECAM_D | V4L2_STD_SECAM_K,
 313};
 314
 315struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
 316                                           v4l2_std_id id)
 317{
 318        unsigned int std_cnt = 0;
 319        unsigned int idx,bcnt,idx2;
 320        v4l2_std_id idmsk,cmsk,fmsk;
 321        struct v4l2_standard *stddefs;
 322
 323        if (pvrusb2_debug & PVR2_TRACE_STD) {
 324                char buf[100];
 325                bcnt = pvr2_std_id_to_str(buf,sizeof(buf),id);
 326                pvr2_trace(
 327                        PVR2_TRACE_STD,"Mapping standards mask=0x%x (%.*s)",
 328                        (int)id,bcnt,buf);
 329        }
 330
 331        *countptr = 0;
 332        std_cnt = 0;
 333        fmsk = 0;
 334        for (idmsk = 1, cmsk = id; cmsk; idmsk <<= 1) {
 335                if (!(idmsk & cmsk)) continue;
 336                cmsk &= ~idmsk;
 337                if (match_std(idmsk)) {
 338                        std_cnt++;
 339                        continue;
 340                }
 341                fmsk |= idmsk;
 342        }
 343
 344        for (idx2 = 0; idx2 < ARRAY_SIZE(std_mixes); idx2++) {
 345                if ((id & std_mixes[idx2]) == std_mixes[idx2]) std_cnt++;
 346        }
 347
 348        /* Don't complain about ATSC standard values */
 349        fmsk &= ~CSTD_ATSC;
 350
 351        if (fmsk) {
 352                char buf[100];
 353                bcnt = pvr2_std_id_to_str(buf,sizeof(buf),fmsk);
 354                pvr2_trace(
 355                        PVR2_TRACE_ERROR_LEGS,
 356                        "WARNING: Failed to classify the following standard(s): %.*s",
 357                        bcnt,buf);
 358        }
 359
 360        pvr2_trace(PVR2_TRACE_STD,"Setting up %u unique standard(s)",
 361                   std_cnt);
 362        if (!std_cnt) return NULL; // paranoia
 363
 364        stddefs = kcalloc(std_cnt, sizeof(struct v4l2_standard),
 365                          GFP_KERNEL);
 366        if (!stddefs)
 367                return NULL;
 368
 369        for (idx = 0; idx < std_cnt; idx++)
 370                stddefs[idx].index = idx;
 371
 372        idx = 0;
 373
 374        /* Enumerate potential special cases */
 375        for (idx2 = 0; (idx2 < ARRAY_SIZE(std_mixes)) && (idx < std_cnt);
 376             idx2++) {
 377                if (!(id & std_mixes[idx2])) continue;
 378                if (pvr2_std_fill(stddefs+idx,std_mixes[idx2])) idx++;
 379        }
 380        /* Now enumerate individual pieces */
 381        for (idmsk = 1, cmsk = id; cmsk && (idx < std_cnt); idmsk <<= 1) {
 382                if (!(idmsk & cmsk)) continue;
 383                cmsk &= ~idmsk;
 384                if (!pvr2_std_fill(stddefs+idx,idmsk)) continue;
 385                idx++;
 386        }
 387
 388        *countptr = std_cnt;
 389        return stddefs;
 390}
 391
 392v4l2_std_id pvr2_std_get_usable(void)
 393{
 394        return CSTD_ALL;
 395}
 396