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 22 struct 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 */ 80 static 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 */ 88 static 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. 114 static 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 130 int 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 182 unsigned 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. 227 static 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 277 static 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 288 static 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. */ 308 static 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 315 struct 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 392 v4l2_std_id pvr2_std_get_usable(void) 393 { 394 return CSTD_ALL; 395 } 396