Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *
0004  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
0005  */
0006 
0007 #include "pvrusb2-std.h"
0008 #include "pvrusb2-debug.h"
0009 #include <asm/string.h>
0010 #include <linux/slab.h>
0011 
0012 struct std_name {
0013     const char *name;
0014     v4l2_std_id id;
0015 };
0016 
0017 
0018 #define CSTD_PAL \
0019     (V4L2_STD_PAL_B| \
0020      V4L2_STD_PAL_B1| \
0021      V4L2_STD_PAL_G| \
0022      V4L2_STD_PAL_H| \
0023      V4L2_STD_PAL_I| \
0024      V4L2_STD_PAL_D| \
0025      V4L2_STD_PAL_D1| \
0026      V4L2_STD_PAL_K| \
0027      V4L2_STD_PAL_M| \
0028      V4L2_STD_PAL_N| \
0029      V4L2_STD_PAL_Nc| \
0030      V4L2_STD_PAL_60)
0031 
0032 #define CSTD_NTSC \
0033     (V4L2_STD_NTSC_M| \
0034      V4L2_STD_NTSC_M_JP| \
0035      V4L2_STD_NTSC_M_KR| \
0036      V4L2_STD_NTSC_443)
0037 
0038 #define CSTD_ATSC \
0039     (V4L2_STD_ATSC_8_VSB| \
0040      V4L2_STD_ATSC_16_VSB)
0041 
0042 #define CSTD_SECAM \
0043     (V4L2_STD_SECAM_B| \
0044      V4L2_STD_SECAM_D| \
0045      V4L2_STD_SECAM_G| \
0046      V4L2_STD_SECAM_H| \
0047      V4L2_STD_SECAM_K| \
0048      V4L2_STD_SECAM_K1| \
0049      V4L2_STD_SECAM_L| \
0050      V4L2_STD_SECAM_LC)
0051 
0052 #define TSTD_B   (V4L2_STD_PAL_B|V4L2_STD_SECAM_B)
0053 #define TSTD_B1  (V4L2_STD_PAL_B1)
0054 #define TSTD_D   (V4L2_STD_PAL_D|V4L2_STD_SECAM_D)
0055 #define TSTD_D1  (V4L2_STD_PAL_D1)
0056 #define TSTD_G   (V4L2_STD_PAL_G|V4L2_STD_SECAM_G)
0057 #define TSTD_H   (V4L2_STD_PAL_H|V4L2_STD_SECAM_H)
0058 #define TSTD_I   (V4L2_STD_PAL_I)
0059 #define TSTD_K   (V4L2_STD_PAL_K|V4L2_STD_SECAM_K)
0060 #define TSTD_K1  (V4L2_STD_SECAM_K1)
0061 #define TSTD_L   (V4L2_STD_SECAM_L)
0062 #define TSTD_M   (V4L2_STD_PAL_M|V4L2_STD_NTSC_M)
0063 #define TSTD_N   (V4L2_STD_PAL_N)
0064 #define TSTD_Nc  (V4L2_STD_PAL_Nc)
0065 #define TSTD_60  (V4L2_STD_PAL_60)
0066 
0067 #define CSTD_ALL (CSTD_PAL|CSTD_NTSC|CSTD_ATSC|CSTD_SECAM)
0068 
0069 /* Mapping of standard bits to color system */
0070 static const struct std_name std_groups[] = {
0071     {"PAL",CSTD_PAL},
0072     {"NTSC",CSTD_NTSC},
0073     {"SECAM",CSTD_SECAM},
0074     {"ATSC",CSTD_ATSC},
0075 };
0076 
0077 /* Mapping of standard bits to modulation system */
0078 static const struct std_name std_items[] = {
0079     {"B",TSTD_B},
0080     {"B1",TSTD_B1},
0081     {"D",TSTD_D},
0082     {"D1",TSTD_D1},
0083     {"G",TSTD_G},
0084     {"H",TSTD_H},
0085     {"I",TSTD_I},
0086     {"K",TSTD_K},
0087     {"K1",TSTD_K1},
0088     {"L",TSTD_L},
0089     {"LC",V4L2_STD_SECAM_LC},
0090     {"M",TSTD_M},
0091     {"Mj",V4L2_STD_NTSC_M_JP},
0092     {"443",V4L2_STD_NTSC_443},
0093     {"Mk",V4L2_STD_NTSC_M_KR},
0094     {"N",TSTD_N},
0095     {"Nc",TSTD_Nc},
0096     {"60",TSTD_60},
0097     {"8VSB",V4L2_STD_ATSC_8_VSB},
0098     {"16VSB",V4L2_STD_ATSC_16_VSB},
0099 };
0100 
0101 
0102 // Search an array of std_name structures and return a pointer to the
0103 // element with the matching name.
0104 static const struct std_name *find_std_name(const struct std_name *arrPtr,
0105                         unsigned int arrSize,
0106                         const char *bufPtr,
0107                         unsigned int bufSize)
0108 {
0109     unsigned int idx;
0110     const struct std_name *p;
0111     for (idx = 0; idx < arrSize; idx++) {
0112         p = arrPtr + idx;
0113         if (strlen(p->name) != bufSize) continue;
0114         if (!memcmp(bufPtr,p->name,bufSize)) return p;
0115     }
0116     return NULL;
0117 }
0118 
0119 
0120 int pvr2_std_str_to_id(v4l2_std_id *idPtr,const char *bufPtr,
0121                unsigned int bufSize)
0122 {
0123     v4l2_std_id id = 0;
0124     v4l2_std_id cmsk = 0;
0125     v4l2_std_id t;
0126     int mMode = 0;
0127     unsigned int cnt;
0128     char ch;
0129     const struct std_name *sp;
0130 
0131     while (bufSize) {
0132         if (!mMode) {
0133             cnt = 0;
0134             while ((cnt < bufSize) && (bufPtr[cnt] != '-')) cnt++;
0135             if (cnt >= bufSize) return 0; // No more characters
0136             sp = find_std_name(std_groups, ARRAY_SIZE(std_groups),
0137                        bufPtr,cnt);
0138             if (!sp) return 0; // Illegal color system name
0139             cnt++;
0140             bufPtr += cnt;
0141             bufSize -= cnt;
0142             mMode = !0;
0143             cmsk = sp->id;
0144             continue;
0145         }
0146         cnt = 0;
0147         while (cnt < bufSize) {
0148             ch = bufPtr[cnt];
0149             if (ch == ';') {
0150                 mMode = 0;
0151                 break;
0152             }
0153             if (ch == '/') break;
0154             cnt++;
0155         }
0156         sp = find_std_name(std_items, ARRAY_SIZE(std_items),
0157                    bufPtr,cnt);
0158         if (!sp) return 0; // Illegal modulation system ID
0159         t = sp->id & cmsk;
0160         if (!t) return 0; // Specific color + modulation system illegal
0161         id |= t;
0162         if (cnt < bufSize) cnt++;
0163         bufPtr += cnt;
0164         bufSize -= cnt;
0165     }
0166 
0167     if (idPtr) *idPtr = id;
0168     return !0;
0169 }
0170 
0171 
0172 unsigned int pvr2_std_id_to_str(char *bufPtr, unsigned int bufSize,
0173                 v4l2_std_id id)
0174 {
0175     unsigned int idx1,idx2;
0176     const struct std_name *ip,*gp;
0177     int gfl,cfl;
0178     unsigned int c1,c2;
0179     cfl = 0;
0180     c1 = 0;
0181     for (idx1 = 0; idx1 < ARRAY_SIZE(std_groups); idx1++) {
0182         gp = std_groups + idx1;
0183         gfl = 0;
0184         for (idx2 = 0; idx2 < ARRAY_SIZE(std_items); idx2++) {
0185             ip = std_items + idx2;
0186             if (!(gp->id & ip->id & id)) continue;
0187             if (!gfl) {
0188                 if (cfl) {
0189                     c2 = scnprintf(bufPtr,bufSize,";");
0190                     c1 += c2;
0191                     bufSize -= c2;
0192                     bufPtr += c2;
0193                 }
0194                 cfl = !0;
0195                 c2 = scnprintf(bufPtr,bufSize,
0196                            "%s-",gp->name);
0197                 gfl = !0;
0198             } else {
0199                 c2 = scnprintf(bufPtr,bufSize,"/");
0200             }
0201             c1 += c2;
0202             bufSize -= c2;
0203             bufPtr += c2;
0204             c2 = scnprintf(bufPtr,bufSize,
0205                        ip->name);
0206             c1 += c2;
0207             bufSize -= c2;
0208             bufPtr += c2;
0209         }
0210     }
0211     return c1;
0212 }
0213 
0214 
0215 // Template data for possible enumerated video standards.  Here we group
0216 // standards which share common frame rates and resolution.
0217 static struct v4l2_standard generic_standards[] = {
0218     {
0219         .id             = (TSTD_B|TSTD_B1|
0220                    TSTD_D|TSTD_D1|
0221                    TSTD_G|
0222                    TSTD_H|
0223                    TSTD_I|
0224                    TSTD_K|TSTD_K1|
0225                    TSTD_L|
0226                    V4L2_STD_SECAM_LC |
0227                    TSTD_N|TSTD_Nc),
0228         .frameperiod    =
0229         {
0230             .numerator  = 1,
0231             .denominator= 25
0232         },
0233         .framelines     = 625,
0234         .reserved       = {0,0,0,0}
0235     }, {
0236         .id             = (TSTD_M|
0237                    V4L2_STD_NTSC_M_JP|
0238                    V4L2_STD_NTSC_M_KR),
0239         .frameperiod    =
0240         {
0241             .numerator  = 1001,
0242             .denominator= 30000
0243         },
0244         .framelines     = 525,
0245         .reserved       = {0,0,0,0}
0246     }, { // This is a total wild guess
0247         .id             = (TSTD_60),
0248         .frameperiod    =
0249         {
0250             .numerator  = 1001,
0251             .denominator= 30000
0252         },
0253         .framelines     = 525,
0254         .reserved       = {0,0,0,0}
0255     }, { // This is total wild guess
0256         .id             = V4L2_STD_NTSC_443,
0257         .frameperiod    =
0258         {
0259             .numerator  = 1001,
0260             .denominator= 30000
0261         },
0262         .framelines     = 525,
0263         .reserved       = {0,0,0,0}
0264     }
0265 };
0266 
0267 static struct v4l2_standard *match_std(v4l2_std_id id)
0268 {
0269     unsigned int idx;
0270     for (idx = 0; idx < ARRAY_SIZE(generic_standards); idx++) {
0271         if (generic_standards[idx].id & id) {
0272             return generic_standards + idx;
0273         }
0274     }
0275     return NULL;
0276 }
0277 
0278 static int pvr2_std_fill(struct v4l2_standard *std,v4l2_std_id id)
0279 {
0280     struct v4l2_standard *template;
0281     int idx;
0282     unsigned int bcnt;
0283     template = match_std(id);
0284     if (!template) return 0;
0285     idx = std->index;
0286     memcpy(std,template,sizeof(*template));
0287     std->index = idx;
0288     std->id = id;
0289     bcnt = pvr2_std_id_to_str(std->name,sizeof(std->name)-1,id);
0290     std->name[bcnt] = 0;
0291     pvr2_trace(PVR2_TRACE_STD,"Set up standard idx=%u name=%s",
0292            std->index,std->name);
0293     return !0;
0294 }
0295 
0296 /* These are special cases of combined standards that we should enumerate
0297    separately if the component pieces are present. */
0298 static v4l2_std_id std_mixes[] = {
0299     V4L2_STD_PAL_B | V4L2_STD_PAL_G,
0300     V4L2_STD_PAL_D | V4L2_STD_PAL_K,
0301     V4L2_STD_SECAM_B | V4L2_STD_SECAM_G,
0302     V4L2_STD_SECAM_D | V4L2_STD_SECAM_K,
0303 };
0304 
0305 struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
0306                        v4l2_std_id id)
0307 {
0308     unsigned int std_cnt = 0;
0309     unsigned int idx,bcnt,idx2;
0310     v4l2_std_id idmsk,cmsk,fmsk;
0311     struct v4l2_standard *stddefs;
0312 
0313     if (pvrusb2_debug & PVR2_TRACE_STD) {
0314         char buf[100];
0315         bcnt = pvr2_std_id_to_str(buf,sizeof(buf),id);
0316         pvr2_trace(
0317             PVR2_TRACE_STD,"Mapping standards mask=0x%x (%.*s)",
0318             (int)id,bcnt,buf);
0319     }
0320 
0321     *countptr = 0;
0322     std_cnt = 0;
0323     fmsk = 0;
0324     for (idmsk = 1, cmsk = id; cmsk; idmsk <<= 1) {
0325         if (!(idmsk & cmsk)) continue;
0326         cmsk &= ~idmsk;
0327         if (match_std(idmsk)) {
0328             std_cnt++;
0329             continue;
0330         }
0331         fmsk |= idmsk;
0332     }
0333 
0334     for (idx2 = 0; idx2 < ARRAY_SIZE(std_mixes); idx2++) {
0335         if ((id & std_mixes[idx2]) == std_mixes[idx2]) std_cnt++;
0336     }
0337 
0338     /* Don't complain about ATSC standard values */
0339     fmsk &= ~CSTD_ATSC;
0340 
0341     if (fmsk) {
0342         char buf[100];
0343         bcnt = pvr2_std_id_to_str(buf,sizeof(buf),fmsk);
0344         pvr2_trace(
0345             PVR2_TRACE_ERROR_LEGS,
0346             "***WARNING*** Failed to classify the following standard(s): %.*s",
0347             bcnt,buf);
0348     }
0349 
0350     pvr2_trace(PVR2_TRACE_STD,"Setting up %u unique standard(s)",
0351            std_cnt);
0352     if (!std_cnt) return NULL; // paranoia
0353 
0354     stddefs = kcalloc(std_cnt, sizeof(struct v4l2_standard),
0355               GFP_KERNEL);
0356     if (!stddefs)
0357         return NULL;
0358 
0359     for (idx = 0; idx < std_cnt; idx++)
0360         stddefs[idx].index = idx;
0361 
0362     idx = 0;
0363 
0364     /* Enumerate potential special cases */
0365     for (idx2 = 0; (idx2 < ARRAY_SIZE(std_mixes)) && (idx < std_cnt);
0366          idx2++) {
0367         if (!(id & std_mixes[idx2])) continue;
0368         if (pvr2_std_fill(stddefs+idx,std_mixes[idx2])) idx++;
0369     }
0370     /* Now enumerate individual pieces */
0371     for (idmsk = 1, cmsk = id; cmsk && (idx < std_cnt); idmsk <<= 1) {
0372         if (!(idmsk & cmsk)) continue;
0373         cmsk &= ~idmsk;
0374         if (!pvr2_std_fill(stddefs+idx,idmsk)) continue;
0375         idx++;
0376     }
0377 
0378     *countptr = std_cnt;
0379     return stddefs;
0380 }
0381 
0382 v4l2_std_id pvr2_std_get_usable(void)
0383 {
0384     return CSTD_ALL;
0385 }