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