12504ba9fSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
20c0d06caSMauro Carvalho Chehab /*
30c0d06caSMauro Carvalho Chehab  *
40c0d06caSMauro Carvalho Chehab  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
50c0d06caSMauro Carvalho Chehab  */
60c0d06caSMauro Carvalho Chehab 
70c0d06caSMauro Carvalho Chehab #include "pvrusb2-std.h"
80c0d06caSMauro Carvalho Chehab #include "pvrusb2-debug.h"
90c0d06caSMauro Carvalho Chehab #include <asm/string.h>
100c0d06caSMauro Carvalho Chehab #include <linux/slab.h>
110c0d06caSMauro Carvalho Chehab 
120c0d06caSMauro Carvalho Chehab struct std_name {
130c0d06caSMauro Carvalho Chehab 	const char *name;
140c0d06caSMauro Carvalho Chehab 	v4l2_std_id id;
150c0d06caSMauro Carvalho Chehab };
160c0d06caSMauro Carvalho Chehab 
170c0d06caSMauro Carvalho Chehab 
180c0d06caSMauro Carvalho Chehab #define CSTD_PAL \
190c0d06caSMauro Carvalho Chehab 	(V4L2_STD_PAL_B| \
200c0d06caSMauro Carvalho Chehab 	 V4L2_STD_PAL_B1| \
210c0d06caSMauro Carvalho Chehab 	 V4L2_STD_PAL_G| \
220c0d06caSMauro Carvalho Chehab 	 V4L2_STD_PAL_H| \
230c0d06caSMauro Carvalho Chehab 	 V4L2_STD_PAL_I| \
240c0d06caSMauro Carvalho Chehab 	 V4L2_STD_PAL_D| \
250c0d06caSMauro Carvalho Chehab 	 V4L2_STD_PAL_D1| \
260c0d06caSMauro Carvalho Chehab 	 V4L2_STD_PAL_K| \
270c0d06caSMauro Carvalho Chehab 	 V4L2_STD_PAL_M| \
280c0d06caSMauro Carvalho Chehab 	 V4L2_STD_PAL_N| \
290c0d06caSMauro Carvalho Chehab 	 V4L2_STD_PAL_Nc| \
300c0d06caSMauro Carvalho Chehab 	 V4L2_STD_PAL_60)
310c0d06caSMauro Carvalho Chehab 
320c0d06caSMauro Carvalho Chehab #define CSTD_NTSC \
330c0d06caSMauro Carvalho Chehab 	(V4L2_STD_NTSC_M| \
340c0d06caSMauro Carvalho Chehab 	 V4L2_STD_NTSC_M_JP| \
350c0d06caSMauro Carvalho Chehab 	 V4L2_STD_NTSC_M_KR| \
360c0d06caSMauro Carvalho Chehab 	 V4L2_STD_NTSC_443)
370c0d06caSMauro Carvalho Chehab 
380c0d06caSMauro Carvalho Chehab #define CSTD_ATSC \
390c0d06caSMauro Carvalho Chehab 	(V4L2_STD_ATSC_8_VSB| \
400c0d06caSMauro Carvalho Chehab 	 V4L2_STD_ATSC_16_VSB)
410c0d06caSMauro Carvalho Chehab 
420c0d06caSMauro Carvalho Chehab #define CSTD_SECAM \
430c0d06caSMauro Carvalho Chehab 	(V4L2_STD_SECAM_B| \
440c0d06caSMauro Carvalho Chehab 	 V4L2_STD_SECAM_D| \
450c0d06caSMauro Carvalho Chehab 	 V4L2_STD_SECAM_G| \
460c0d06caSMauro Carvalho Chehab 	 V4L2_STD_SECAM_H| \
470c0d06caSMauro Carvalho Chehab 	 V4L2_STD_SECAM_K| \
480c0d06caSMauro Carvalho Chehab 	 V4L2_STD_SECAM_K1| \
490c0d06caSMauro Carvalho Chehab 	 V4L2_STD_SECAM_L| \
500c0d06caSMauro Carvalho Chehab 	 V4L2_STD_SECAM_LC)
510c0d06caSMauro Carvalho Chehab 
520c0d06caSMauro Carvalho Chehab #define TSTD_B   (V4L2_STD_PAL_B|V4L2_STD_SECAM_B)
530c0d06caSMauro Carvalho Chehab #define TSTD_B1  (V4L2_STD_PAL_B1)
540c0d06caSMauro Carvalho Chehab #define TSTD_D   (V4L2_STD_PAL_D|V4L2_STD_SECAM_D)
550c0d06caSMauro Carvalho Chehab #define TSTD_D1  (V4L2_STD_PAL_D1)
560c0d06caSMauro Carvalho Chehab #define TSTD_G   (V4L2_STD_PAL_G|V4L2_STD_SECAM_G)
570c0d06caSMauro Carvalho Chehab #define TSTD_H   (V4L2_STD_PAL_H|V4L2_STD_SECAM_H)
580c0d06caSMauro Carvalho Chehab #define TSTD_I   (V4L2_STD_PAL_I)
590c0d06caSMauro Carvalho Chehab #define TSTD_K   (V4L2_STD_PAL_K|V4L2_STD_SECAM_K)
600c0d06caSMauro Carvalho Chehab #define TSTD_K1  (V4L2_STD_SECAM_K1)
610c0d06caSMauro Carvalho Chehab #define TSTD_L   (V4L2_STD_SECAM_L)
620c0d06caSMauro Carvalho Chehab #define TSTD_M   (V4L2_STD_PAL_M|V4L2_STD_NTSC_M)
630c0d06caSMauro Carvalho Chehab #define TSTD_N   (V4L2_STD_PAL_N)
640c0d06caSMauro Carvalho Chehab #define TSTD_Nc  (V4L2_STD_PAL_Nc)
650c0d06caSMauro Carvalho Chehab #define TSTD_60  (V4L2_STD_PAL_60)
660c0d06caSMauro Carvalho Chehab 
670c0d06caSMauro Carvalho Chehab #define CSTD_ALL (CSTD_PAL|CSTD_NTSC|CSTD_ATSC|CSTD_SECAM)
680c0d06caSMauro Carvalho Chehab 
690c0d06caSMauro Carvalho Chehab /* Mapping of standard bits to color system */
700c0d06caSMauro Carvalho Chehab static const struct std_name std_groups[] = {
710c0d06caSMauro Carvalho Chehab 	{"PAL",CSTD_PAL},
720c0d06caSMauro Carvalho Chehab 	{"NTSC",CSTD_NTSC},
730c0d06caSMauro Carvalho Chehab 	{"SECAM",CSTD_SECAM},
740c0d06caSMauro Carvalho Chehab 	{"ATSC",CSTD_ATSC},
750c0d06caSMauro Carvalho Chehab };
760c0d06caSMauro Carvalho Chehab 
770c0d06caSMauro Carvalho Chehab /* Mapping of standard bits to modulation system */
780c0d06caSMauro Carvalho Chehab static const struct std_name std_items[] = {
790c0d06caSMauro Carvalho Chehab 	{"B",TSTD_B},
800c0d06caSMauro Carvalho Chehab 	{"B1",TSTD_B1},
810c0d06caSMauro Carvalho Chehab 	{"D",TSTD_D},
820c0d06caSMauro Carvalho Chehab 	{"D1",TSTD_D1},
830c0d06caSMauro Carvalho Chehab 	{"G",TSTD_G},
840c0d06caSMauro Carvalho Chehab 	{"H",TSTD_H},
850c0d06caSMauro Carvalho Chehab 	{"I",TSTD_I},
860c0d06caSMauro Carvalho Chehab 	{"K",TSTD_K},
870c0d06caSMauro Carvalho Chehab 	{"K1",TSTD_K1},
880c0d06caSMauro Carvalho Chehab 	{"L",TSTD_L},
890c0d06caSMauro Carvalho Chehab 	{"LC",V4L2_STD_SECAM_LC},
900c0d06caSMauro Carvalho Chehab 	{"M",TSTD_M},
910c0d06caSMauro Carvalho Chehab 	{"Mj",V4L2_STD_NTSC_M_JP},
920c0d06caSMauro Carvalho Chehab 	{"443",V4L2_STD_NTSC_443},
930c0d06caSMauro Carvalho Chehab 	{"Mk",V4L2_STD_NTSC_M_KR},
940c0d06caSMauro Carvalho Chehab 	{"N",TSTD_N},
950c0d06caSMauro Carvalho Chehab 	{"Nc",TSTD_Nc},
960c0d06caSMauro Carvalho Chehab 	{"60",TSTD_60},
970c0d06caSMauro Carvalho Chehab 	{"8VSB",V4L2_STD_ATSC_8_VSB},
980c0d06caSMauro Carvalho Chehab 	{"16VSB",V4L2_STD_ATSC_16_VSB},
990c0d06caSMauro Carvalho Chehab };
1000c0d06caSMauro Carvalho Chehab 
1010c0d06caSMauro Carvalho Chehab 
1020c0d06caSMauro Carvalho Chehab // Search an array of std_name structures and return a pointer to the
1030c0d06caSMauro Carvalho Chehab // element with the matching name.
find_std_name(const struct std_name * arrPtr,unsigned int arrSize,const char * bufPtr,unsigned int bufSize)1040c0d06caSMauro Carvalho Chehab static const struct std_name *find_std_name(const struct std_name *arrPtr,
1050c0d06caSMauro Carvalho Chehab 					    unsigned int arrSize,
1060c0d06caSMauro Carvalho Chehab 					    const char *bufPtr,
1070c0d06caSMauro Carvalho Chehab 					    unsigned int bufSize)
1080c0d06caSMauro Carvalho Chehab {
1090c0d06caSMauro Carvalho Chehab 	unsigned int idx;
1100c0d06caSMauro Carvalho Chehab 	const struct std_name *p;
1110c0d06caSMauro Carvalho Chehab 	for (idx = 0; idx < arrSize; idx++) {
1120c0d06caSMauro Carvalho Chehab 		p = arrPtr + idx;
1130c0d06caSMauro Carvalho Chehab 		if (strlen(p->name) != bufSize) continue;
1140c0d06caSMauro Carvalho Chehab 		if (!memcmp(bufPtr,p->name,bufSize)) return p;
1150c0d06caSMauro Carvalho Chehab 	}
1160c0d06caSMauro Carvalho Chehab 	return NULL;
1170c0d06caSMauro Carvalho Chehab }
1180c0d06caSMauro Carvalho Chehab 
1190c0d06caSMauro Carvalho Chehab 
pvr2_std_str_to_id(v4l2_std_id * idPtr,const char * bufPtr,unsigned int bufSize)1200c0d06caSMauro Carvalho Chehab int pvr2_std_str_to_id(v4l2_std_id *idPtr,const char *bufPtr,
1210c0d06caSMauro Carvalho Chehab 		       unsigned int bufSize)
1220c0d06caSMauro Carvalho Chehab {
1230c0d06caSMauro Carvalho Chehab 	v4l2_std_id id = 0;
1240c0d06caSMauro Carvalho Chehab 	v4l2_std_id cmsk = 0;
1250c0d06caSMauro Carvalho Chehab 	v4l2_std_id t;
1260c0d06caSMauro Carvalho Chehab 	int mMode = 0;
1270c0d06caSMauro Carvalho Chehab 	unsigned int cnt;
1280c0d06caSMauro Carvalho Chehab 	char ch;
1290c0d06caSMauro Carvalho Chehab 	const struct std_name *sp;
1300c0d06caSMauro Carvalho Chehab 
1310c0d06caSMauro Carvalho Chehab 	while (bufSize) {
1320c0d06caSMauro Carvalho Chehab 		if (!mMode) {
1330c0d06caSMauro Carvalho Chehab 			cnt = 0;
1340c0d06caSMauro Carvalho Chehab 			while ((cnt < bufSize) && (bufPtr[cnt] != '-')) cnt++;
1350c0d06caSMauro Carvalho Chehab 			if (cnt >= bufSize) return 0; // No more characters
1360c0d06caSMauro Carvalho Chehab 			sp = find_std_name(std_groups, ARRAY_SIZE(std_groups),
1370c0d06caSMauro Carvalho Chehab 					   bufPtr,cnt);
1380c0d06caSMauro Carvalho Chehab 			if (!sp) return 0; // Illegal color system name
1390c0d06caSMauro Carvalho Chehab 			cnt++;
1400c0d06caSMauro Carvalho Chehab 			bufPtr += cnt;
1410c0d06caSMauro Carvalho Chehab 			bufSize -= cnt;
1420c0d06caSMauro Carvalho Chehab 			mMode = !0;
1430c0d06caSMauro Carvalho Chehab 			cmsk = sp->id;
1440c0d06caSMauro Carvalho Chehab 			continue;
1450c0d06caSMauro Carvalho Chehab 		}
1460c0d06caSMauro Carvalho Chehab 		cnt = 0;
1470c0d06caSMauro Carvalho Chehab 		while (cnt < bufSize) {
1480c0d06caSMauro Carvalho Chehab 			ch = bufPtr[cnt];
1490c0d06caSMauro Carvalho Chehab 			if (ch == ';') {
1500c0d06caSMauro Carvalho Chehab 				mMode = 0;
1510c0d06caSMauro Carvalho Chehab 				break;
1520c0d06caSMauro Carvalho Chehab 			}
1530c0d06caSMauro Carvalho Chehab 			if (ch == '/') break;
1540c0d06caSMauro Carvalho Chehab 			cnt++;
1550c0d06caSMauro Carvalho Chehab 		}
1560c0d06caSMauro Carvalho Chehab 		sp = find_std_name(std_items, ARRAY_SIZE(std_items),
1570c0d06caSMauro Carvalho Chehab 				   bufPtr,cnt);
1580c0d06caSMauro Carvalho Chehab 		if (!sp) return 0; // Illegal modulation system ID
1590c0d06caSMauro Carvalho Chehab 		t = sp->id & cmsk;
1600c0d06caSMauro Carvalho Chehab 		if (!t) return 0; // Specific color + modulation system illegal
1610c0d06caSMauro Carvalho Chehab 		id |= t;
1620c0d06caSMauro Carvalho Chehab 		if (cnt < bufSize) cnt++;
1630c0d06caSMauro Carvalho Chehab 		bufPtr += cnt;
1640c0d06caSMauro Carvalho Chehab 		bufSize -= cnt;
1650c0d06caSMauro Carvalho Chehab 	}
1660c0d06caSMauro Carvalho Chehab 
1670c0d06caSMauro Carvalho Chehab 	if (idPtr) *idPtr = id;
1680c0d06caSMauro Carvalho Chehab 	return !0;
1690c0d06caSMauro Carvalho Chehab }
1700c0d06caSMauro Carvalho Chehab 
1710c0d06caSMauro Carvalho Chehab 
pvr2_std_id_to_str(char * bufPtr,unsigned int bufSize,v4l2_std_id id)1720c0d06caSMauro Carvalho Chehab unsigned int pvr2_std_id_to_str(char *bufPtr, unsigned int bufSize,
1730c0d06caSMauro Carvalho Chehab 				v4l2_std_id id)
1740c0d06caSMauro Carvalho Chehab {
1750c0d06caSMauro Carvalho Chehab 	unsigned int idx1,idx2;
1760c0d06caSMauro Carvalho Chehab 	const struct std_name *ip,*gp;
1770c0d06caSMauro Carvalho Chehab 	int gfl,cfl;
1780c0d06caSMauro Carvalho Chehab 	unsigned int c1,c2;
1790c0d06caSMauro Carvalho Chehab 	cfl = 0;
1800c0d06caSMauro Carvalho Chehab 	c1 = 0;
1810c0d06caSMauro Carvalho Chehab 	for (idx1 = 0; idx1 < ARRAY_SIZE(std_groups); idx1++) {
1820c0d06caSMauro Carvalho Chehab 		gp = std_groups + idx1;
1830c0d06caSMauro Carvalho Chehab 		gfl = 0;
1840c0d06caSMauro Carvalho Chehab 		for (idx2 = 0; idx2 < ARRAY_SIZE(std_items); idx2++) {
1850c0d06caSMauro Carvalho Chehab 			ip = std_items + idx2;
1860c0d06caSMauro Carvalho Chehab 			if (!(gp->id & ip->id & id)) continue;
1870c0d06caSMauro Carvalho Chehab 			if (!gfl) {
1880c0d06caSMauro Carvalho Chehab 				if (cfl) {
1890c0d06caSMauro Carvalho Chehab 					c2 = scnprintf(bufPtr,bufSize,";");
1900c0d06caSMauro Carvalho Chehab 					c1 += c2;
1910c0d06caSMauro Carvalho Chehab 					bufSize -= c2;
1920c0d06caSMauro Carvalho Chehab 					bufPtr += c2;
1930c0d06caSMauro Carvalho Chehab 				}
1940c0d06caSMauro Carvalho Chehab 				cfl = !0;
1950c0d06caSMauro Carvalho Chehab 				c2 = scnprintf(bufPtr,bufSize,
1960c0d06caSMauro Carvalho Chehab 					       "%s-",gp->name);
1970c0d06caSMauro Carvalho Chehab 				gfl = !0;
1980c0d06caSMauro Carvalho Chehab 			} else {
1990c0d06caSMauro Carvalho Chehab 				c2 = scnprintf(bufPtr,bufSize,"/");
2000c0d06caSMauro Carvalho Chehab 			}
2010c0d06caSMauro Carvalho Chehab 			c1 += c2;
2020c0d06caSMauro Carvalho Chehab 			bufSize -= c2;
2030c0d06caSMauro Carvalho Chehab 			bufPtr += c2;
2040c0d06caSMauro Carvalho Chehab 			c2 = scnprintf(bufPtr,bufSize,
2050c0d06caSMauro Carvalho Chehab 				       ip->name);
2060c0d06caSMauro Carvalho Chehab 			c1 += c2;
2070c0d06caSMauro Carvalho Chehab 			bufSize -= c2;
2080c0d06caSMauro Carvalho Chehab 			bufPtr += c2;
2090c0d06caSMauro Carvalho Chehab 		}
2100c0d06caSMauro Carvalho Chehab 	}
2110c0d06caSMauro Carvalho Chehab 	return c1;
2120c0d06caSMauro Carvalho Chehab }
2130c0d06caSMauro Carvalho Chehab 
2140c0d06caSMauro Carvalho Chehab 
2150c0d06caSMauro Carvalho Chehab // Template data for possible enumerated video standards.  Here we group
2160c0d06caSMauro Carvalho Chehab // standards which share common frame rates and resolution.
2170c0d06caSMauro Carvalho Chehab static struct v4l2_standard generic_standards[] = {
2180c0d06caSMauro Carvalho Chehab 	{
2190c0d06caSMauro Carvalho Chehab 		.id             = (TSTD_B|TSTD_B1|
2200c0d06caSMauro Carvalho Chehab 				   TSTD_D|TSTD_D1|
2210c0d06caSMauro Carvalho Chehab 				   TSTD_G|
2220c0d06caSMauro Carvalho Chehab 				   TSTD_H|
2230c0d06caSMauro Carvalho Chehab 				   TSTD_I|
2240c0d06caSMauro Carvalho Chehab 				   TSTD_K|TSTD_K1|
2250c0d06caSMauro Carvalho Chehab 				   TSTD_L|
2260c0d06caSMauro Carvalho Chehab 				   V4L2_STD_SECAM_LC |
2270c0d06caSMauro Carvalho Chehab 				   TSTD_N|TSTD_Nc),
2280c0d06caSMauro Carvalho Chehab 		.frameperiod    =
2290c0d06caSMauro Carvalho Chehab 		{
2300c0d06caSMauro Carvalho Chehab 			.numerator  = 1,
2310c0d06caSMauro Carvalho Chehab 			.denominator= 25
2320c0d06caSMauro Carvalho Chehab 		},
2330c0d06caSMauro Carvalho Chehab 		.framelines     = 625,
2340c0d06caSMauro Carvalho Chehab 		.reserved       = {0,0,0,0}
2350c0d06caSMauro Carvalho Chehab 	}, {
2360c0d06caSMauro Carvalho Chehab 		.id             = (TSTD_M|
2370c0d06caSMauro Carvalho Chehab 				   V4L2_STD_NTSC_M_JP|
2380c0d06caSMauro Carvalho Chehab 				   V4L2_STD_NTSC_M_KR),
2390c0d06caSMauro Carvalho Chehab 		.frameperiod    =
2400c0d06caSMauro Carvalho Chehab 		{
2410c0d06caSMauro Carvalho Chehab 			.numerator  = 1001,
2420c0d06caSMauro Carvalho Chehab 			.denominator= 30000
2430c0d06caSMauro Carvalho Chehab 		},
2440c0d06caSMauro Carvalho Chehab 		.framelines     = 525,
2450c0d06caSMauro Carvalho Chehab 		.reserved       = {0,0,0,0}
2460c0d06caSMauro Carvalho Chehab 	}, { // This is a total wild guess
2470c0d06caSMauro Carvalho Chehab 		.id             = (TSTD_60),
2480c0d06caSMauro Carvalho Chehab 		.frameperiod    =
2490c0d06caSMauro Carvalho Chehab 		{
2500c0d06caSMauro Carvalho Chehab 			.numerator  = 1001,
2510c0d06caSMauro Carvalho Chehab 			.denominator= 30000
2520c0d06caSMauro Carvalho Chehab 		},
2530c0d06caSMauro Carvalho Chehab 		.framelines     = 525,
2540c0d06caSMauro Carvalho Chehab 		.reserved       = {0,0,0,0}
2550c0d06caSMauro Carvalho Chehab 	}, { // This is total wild guess
2560c0d06caSMauro Carvalho Chehab 		.id             = V4L2_STD_NTSC_443,
2570c0d06caSMauro Carvalho Chehab 		.frameperiod    =
2580c0d06caSMauro Carvalho Chehab 		{
2590c0d06caSMauro Carvalho Chehab 			.numerator  = 1001,
2600c0d06caSMauro Carvalho Chehab 			.denominator= 30000
2610c0d06caSMauro Carvalho Chehab 		},
2620c0d06caSMauro Carvalho Chehab 		.framelines     = 525,
2630c0d06caSMauro Carvalho Chehab 		.reserved       = {0,0,0,0}
2640c0d06caSMauro Carvalho Chehab 	}
2650c0d06caSMauro Carvalho Chehab };
2660c0d06caSMauro Carvalho Chehab 
match_std(v4l2_std_id id)2670c0d06caSMauro Carvalho Chehab static struct v4l2_standard *match_std(v4l2_std_id id)
2680c0d06caSMauro Carvalho Chehab {
2690c0d06caSMauro Carvalho Chehab 	unsigned int idx;
2700c0d06caSMauro Carvalho Chehab 	for (idx = 0; idx < ARRAY_SIZE(generic_standards); idx++) {
2710c0d06caSMauro Carvalho Chehab 		if (generic_standards[idx].id & id) {
2720c0d06caSMauro Carvalho Chehab 			return generic_standards + idx;
2730c0d06caSMauro Carvalho Chehab 		}
2740c0d06caSMauro Carvalho Chehab 	}
2750c0d06caSMauro Carvalho Chehab 	return NULL;
2760c0d06caSMauro Carvalho Chehab }
2770c0d06caSMauro Carvalho Chehab 
pvr2_std_fill(struct v4l2_standard * std,v4l2_std_id id)2780c0d06caSMauro Carvalho Chehab static int pvr2_std_fill(struct v4l2_standard *std,v4l2_std_id id)
2790c0d06caSMauro Carvalho Chehab {
2800c0d06caSMauro Carvalho Chehab 	struct v4l2_standard *template;
2810c0d06caSMauro Carvalho Chehab 	int idx;
2820c0d06caSMauro Carvalho Chehab 	unsigned int bcnt;
2830c0d06caSMauro Carvalho Chehab 	template = match_std(id);
2840c0d06caSMauro Carvalho Chehab 	if (!template) return 0;
2850c0d06caSMauro Carvalho Chehab 	idx = std->index;
2860c0d06caSMauro Carvalho Chehab 	memcpy(std,template,sizeof(*template));
2870c0d06caSMauro Carvalho Chehab 	std->index = idx;
2880c0d06caSMauro Carvalho Chehab 	std->id = id;
2890c0d06caSMauro Carvalho Chehab 	bcnt = pvr2_std_id_to_str(std->name,sizeof(std->name)-1,id);
2900c0d06caSMauro Carvalho Chehab 	std->name[bcnt] = 0;
2910c0d06caSMauro Carvalho Chehab 	pvr2_trace(PVR2_TRACE_STD,"Set up standard idx=%u name=%s",
2920c0d06caSMauro Carvalho Chehab 		   std->index,std->name);
2930c0d06caSMauro Carvalho Chehab 	return !0;
2940c0d06caSMauro Carvalho Chehab }
2950c0d06caSMauro Carvalho Chehab 
2960c0d06caSMauro Carvalho Chehab /* These are special cases of combined standards that we should enumerate
2970c0d06caSMauro Carvalho Chehab    separately if the component pieces are present. */
2980c0d06caSMauro Carvalho Chehab static v4l2_std_id std_mixes[] = {
2990c0d06caSMauro Carvalho Chehab 	V4L2_STD_PAL_B | V4L2_STD_PAL_G,
3000c0d06caSMauro Carvalho Chehab 	V4L2_STD_PAL_D | V4L2_STD_PAL_K,
3010c0d06caSMauro Carvalho Chehab 	V4L2_STD_SECAM_B | V4L2_STD_SECAM_G,
3020c0d06caSMauro Carvalho Chehab 	V4L2_STD_SECAM_D | V4L2_STD_SECAM_K,
3030c0d06caSMauro Carvalho Chehab };
3040c0d06caSMauro Carvalho Chehab 
pvr2_std_create_enum(unsigned int * countptr,v4l2_std_id id)3050c0d06caSMauro Carvalho Chehab struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
3060c0d06caSMauro Carvalho Chehab 					   v4l2_std_id id)
3070c0d06caSMauro Carvalho Chehab {
3080c0d06caSMauro Carvalho Chehab 	unsigned int std_cnt = 0;
3090c0d06caSMauro Carvalho Chehab 	unsigned int idx,bcnt,idx2;
3100c0d06caSMauro Carvalho Chehab 	v4l2_std_id idmsk,cmsk,fmsk;
3110c0d06caSMauro Carvalho Chehab 	struct v4l2_standard *stddefs;
3120c0d06caSMauro Carvalho Chehab 
3130c0d06caSMauro Carvalho Chehab 	if (pvrusb2_debug & PVR2_TRACE_STD) {
3140c0d06caSMauro Carvalho Chehab 		char buf[100];
3150c0d06caSMauro Carvalho Chehab 		bcnt = pvr2_std_id_to_str(buf,sizeof(buf),id);
3160c0d06caSMauro Carvalho Chehab 		pvr2_trace(
3170c0d06caSMauro Carvalho Chehab 			PVR2_TRACE_STD,"Mapping standards mask=0x%x (%.*s)",
3180c0d06caSMauro Carvalho Chehab 			(int)id,bcnt,buf);
3190c0d06caSMauro Carvalho Chehab 	}
3200c0d06caSMauro Carvalho Chehab 
3210c0d06caSMauro Carvalho Chehab 	*countptr = 0;
3220c0d06caSMauro Carvalho Chehab 	std_cnt = 0;
3230c0d06caSMauro Carvalho Chehab 	fmsk = 0;
3240c0d06caSMauro Carvalho Chehab 	for (idmsk = 1, cmsk = id; cmsk; idmsk <<= 1) {
3250c0d06caSMauro Carvalho Chehab 		if (!(idmsk & cmsk)) continue;
3260c0d06caSMauro Carvalho Chehab 		cmsk &= ~idmsk;
3270c0d06caSMauro Carvalho Chehab 		if (match_std(idmsk)) {
3280c0d06caSMauro Carvalho Chehab 			std_cnt++;
3290c0d06caSMauro Carvalho Chehab 			continue;
3300c0d06caSMauro Carvalho Chehab 		}
3310c0d06caSMauro Carvalho Chehab 		fmsk |= idmsk;
3320c0d06caSMauro Carvalho Chehab 	}
3330c0d06caSMauro Carvalho Chehab 
3340c0d06caSMauro Carvalho Chehab 	for (idx2 = 0; idx2 < ARRAY_SIZE(std_mixes); idx2++) {
3350c0d06caSMauro Carvalho Chehab 		if ((id & std_mixes[idx2]) == std_mixes[idx2]) std_cnt++;
3360c0d06caSMauro Carvalho Chehab 	}
3370c0d06caSMauro Carvalho Chehab 
3380c0d06caSMauro Carvalho Chehab 	/* Don't complain about ATSC standard values */
3390c0d06caSMauro Carvalho Chehab 	fmsk &= ~CSTD_ATSC;
3400c0d06caSMauro Carvalho Chehab 
3410c0d06caSMauro Carvalho Chehab 	if (fmsk) {
3420c0d06caSMauro Carvalho Chehab 		char buf[100];
3430c0d06caSMauro Carvalho Chehab 		bcnt = pvr2_std_id_to_str(buf,sizeof(buf),fmsk);
3440c0d06caSMauro Carvalho Chehab 		pvr2_trace(
3450c0d06caSMauro Carvalho Chehab 			PVR2_TRACE_ERROR_LEGS,
34696292c89SMauro Carvalho Chehab 			"***WARNING*** Failed to classify the following standard(s): %.*s",
3470c0d06caSMauro Carvalho Chehab 			bcnt,buf);
3480c0d06caSMauro Carvalho Chehab 	}
3490c0d06caSMauro Carvalho Chehab 
3500c0d06caSMauro Carvalho Chehab 	pvr2_trace(PVR2_TRACE_STD,"Setting up %u unique standard(s)",
3510c0d06caSMauro Carvalho Chehab 		   std_cnt);
3520c0d06caSMauro Carvalho Chehab 	if (!std_cnt) return NULL; // paranoia
3530c0d06caSMauro Carvalho Chehab 
3546396bb22SKees Cook 	stddefs = kcalloc(std_cnt, sizeof(struct v4l2_standard),
3550c0d06caSMauro Carvalho Chehab 			  GFP_KERNEL);
3560c0d06caSMauro Carvalho Chehab 	if (!stddefs)
3570c0d06caSMauro Carvalho Chehab 		return NULL;
3580c0d06caSMauro Carvalho Chehab 
3590c0d06caSMauro Carvalho Chehab 	for (idx = 0; idx < std_cnt; idx++)
3600c0d06caSMauro Carvalho Chehab 		stddefs[idx].index = idx;
3610c0d06caSMauro Carvalho Chehab 
3620c0d06caSMauro Carvalho Chehab 	idx = 0;
3630c0d06caSMauro Carvalho Chehab 
3640c0d06caSMauro Carvalho Chehab 	/* Enumerate potential special cases */
3650c0d06caSMauro Carvalho Chehab 	for (idx2 = 0; (idx2 < ARRAY_SIZE(std_mixes)) && (idx < std_cnt);
3660c0d06caSMauro Carvalho Chehab 	     idx2++) {
3670c0d06caSMauro Carvalho Chehab 		if (!(id & std_mixes[idx2])) continue;
3680c0d06caSMauro Carvalho Chehab 		if (pvr2_std_fill(stddefs+idx,std_mixes[idx2])) idx++;
3690c0d06caSMauro Carvalho Chehab 	}
3700c0d06caSMauro Carvalho Chehab 	/* Now enumerate individual pieces */
3710c0d06caSMauro Carvalho Chehab 	for (idmsk = 1, cmsk = id; cmsk && (idx < std_cnt); idmsk <<= 1) {
3720c0d06caSMauro Carvalho Chehab 		if (!(idmsk & cmsk)) continue;
3730c0d06caSMauro Carvalho Chehab 		cmsk &= ~idmsk;
3740c0d06caSMauro Carvalho Chehab 		if (!pvr2_std_fill(stddefs+idx,idmsk)) continue;
3750c0d06caSMauro Carvalho Chehab 		idx++;
3760c0d06caSMauro Carvalho Chehab 	}
3770c0d06caSMauro Carvalho Chehab 
3780c0d06caSMauro Carvalho Chehab 	*countptr = std_cnt;
3790c0d06caSMauro Carvalho Chehab 	return stddefs;
3800c0d06caSMauro Carvalho Chehab }
3810c0d06caSMauro Carvalho Chehab 
pvr2_std_get_usable(void)3820c0d06caSMauro Carvalho Chehab v4l2_std_id pvr2_std_get_usable(void)
3830c0d06caSMauro Carvalho Chehab {
3840c0d06caSMauro Carvalho Chehab 	return CSTD_ALL;
3850c0d06caSMauro Carvalho Chehab }
386