henesyinit from p9fd787fda5 years agoHistory
961 lines · 20.4 KB · C
RawDownload
/*  * Driver for Bt848 TV tuner.    *  */#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"../port/error.h"#include "io.h" enum {	Qdir = 0,	Qdata,	Qctl,	Qregs, 	Brooktree_vid = 0x109e,	Brooktree_848_did = 0x0350,	Intel_vid = 0x8086,	Intel_82437_did = 0x122d, 	K = 1024,	M = K * K, 	Numring = 16, 	ntsc_rawpixels = 910,	ntsc_sqpixels = 780,					// Including blanking & inactive	ntsc_hactive = 640,	ntsc_vactive = 480,	ntsc_clkx1delay = 135,				// Clock ticks.	ntsc_clkx1hactive = 754,	ntsc_vdelay = 26,					// # of scan lines.	ntsc_vscale = 0, 	i2c_timing = 7 << 4,	i2c_bt848w3b = 1 << 2,	i2c_bt848scl = 1 << 1,	i2c_bt848sda = 1 << 0, 	i2c_miroproee = 0x80,				// MIRO PRO EEPROM	i2c_tea6300 = i2c_miroproee,	i2c_tda8425 = 0x82,	i2c_tda9840 = 0x84,	i2c_tda9850 = 0xb6,	i2c_haupee = 0xa0,					// Hauppage EEPROM	i2c_stbee = 0xae,					// STB EEPROM 	Bt848_miropro = 0,	Bt848_miro, 	// Bit fields.	iform_muxsel1 = 3 << 5,				// 004	iform_muxsel0 = 2 << 5,		iform_xtselmask = 3 << 3,	iform_xtauto = 3 << 3,	iform_formatmask = 7 << 0,	iform_ntsc = 1 << 0, 	control_ldec = 1 << 5,				// 02C	contrast_100percent = 0xd8,			// 030 	vscale_interlaced = 1 << 5,			// 04C 	adelay_ntsc = 104,					// 060	bdelay_ntsc = 93,					// 064	adc_crush = 1 << 0,					// 068 	colorfmt_rgb16 = (2 << 4) | (2 << 0),	// 0D4	colorctl_gamma = 1 << 4,			// 0D8	capctl_fullframe = 1 << 4,				// 0DC	capctl_captureodd = 1 << 1,	capctl_captureeven = 1 << 0,	vbipacksize = 0x190,				// 0E0 	intstat_riscstatshift = 28,				// 100	intstat_i2crack = 1 << 25,	intstat_scerr = 1 << 19,	intstat_ocerr = 1 << 18,	intstat_fbus = 1 << 12,	intstat_risci = 1 << 11,	intstat_i2cdone = 1 << 8,		intstat_vpress = 1 << 5,	intstat_hlock = 1 << 4,	intstat_vsync = 1 << 1,	intstat_fmtchg = 1 << 0,	intmask_etbf = 1 << 23,				// 104 	gpiodmactl_pltp23_16 = 2 << 6,		// 10C	gpiodmactl_pltp23_0 = 0 << 6,		gpiodmactl_pltp1_16 = 2 << 4,	gpiodmactl_pltp1_0 = 0 << 4,	gpiodmactl_pktp_32 = 3 << 2,			gpiodmactl_pktp_0 = 0 << 2,			gpiodmactl_riscenable = 1 << 1,	gpiodmactl_fifoenable = 1 << 0,	 	// RISC instructions and parameters.	fifo_vre = 0x4,	fifo_vro = 0xC,	fifo_fm1 = 0x6, 	riscirq = 1 << 24,	riscwrite = 0x1 << 28,		riscwrite_sol = 1 << 27,		riscwrite_eol = 1 << 26,	riscskip = 0x2 << 28,	riscjmp = 0x7 << 28,	riscsync = 0x8 << 28,		riscsync_resync = 1 << 15,		riscsync_vre = fifo_vre << 0,		riscsync_vro = fifo_vro << 0,		riscsync_fm1 = fifo_fm1 << 0,	risclabelshift_set = 16,	risclabelshift_reset = 20,}; typedef struct {	ushort		vid;	ushort		did;	char			*name;} Variant; typedef struct {	ulong	devstat;		// 000	ulong	iform;		// 004	ulong	tdec;			// 008	ulong	ecrop;		// 00C	ulong	evdelaylo;		// 010	ulong	evactivelo;	// 014	ulong	ehdelaylo;		// 018	ulong	ehactivelo;	// 01C	ulong	ehscalehi;		// 020	ulong	ehscalelo;		// 024	ulong	bright;		// 028	ulong	econtrol;		// 02C	ulong	contrastlo;	// 030	ulong	satulo;		// 034	ulong	satvlo;		// 038	ulong	hue;			// 03C	ulong	escloop;		// 040	ulong	pad0;		// 044	ulong	oform;		// 048	ulong	evscalehi;		// 04C	ulong	evscalelo;		// 050	ulong	test;			// 054	ulong	pad1[2];		// 058-05C	ulong	adelay;		// 060	ulong	bdelay;		// 064	ulong	adc;			// 068	ulong	evtc;			// 06C	ulong	pad2[3];		// 070-078	ulong	sreset;		// 07C	ulong	tglb;			// 080	ulong	tgctrl;		// 084	ulong	pad3;		// 088	ulong	ocrop;		// 08C	ulong	ovdelaylo;		// 090	ulong	ovactivelo;	// 094	ulong	ohdelaylo;	// 098	ulong	ohactivelo;	// 09C	ulong	ohscalehi;		// 0A0	ulong	ohscalelo;		// 0A4	ulong	pad4;		// 0A8	ulong	ocontrol;		// 0AC	ulong	pad5[4];		// 0B0-0BC	ulong	oscloop;		// 0C0	ulong	pad6[2];		// 0C4-0C8	ulong	ovscalehi;		// 0CC	ulong	ovscalelo;		// 0D0	ulong	colorfmt;		// 0D4	ulong	colorctl;		// 0D8	ulong	capctl;		// 0DC	ulong	vbipacksize;	// 0E0	ulong	vbipackdel;	// 0E4	ulong	fcap;			// 0E8	ulong	ovtc;			// 0EC	ulong	pllflo;		// 0F0	ulong	pllfhi;		// 0F4	ulong	pllxci;		// 0F8	ulong	dvsif;		// 0FC	ulong	intstat;		// 100	ulong	intmask;		// 104	ulong	pad7;		// 108	ulong	gpiodmactl;	// 10C	ulong	i2c;			// 110	ulong	riscstrtadd;	// 114	ulong	gpioouten;	// 118	ulong	gpioreginp;	// 11C	ulong	risccount;		// 120	ulong	pad8[55];		// 124-1FC		ulong	gpiodata[64];	// 200-2FC} Bt848; typedef struct {	char		*name;  	ushort	freq_vhfh;	// Start frequency	ushort	freq_uhf;  	uchar	VHF_L;	uchar	VHF_H;	uchar	UHF;	uchar	cfg; 	ushort	offs;} Tuner; typedef struct {	ulong	*fstart;	ulong	*fjmp;	uchar	*fbase;} Frame; typedef struct {	Lock;	Bt848	*bt848;	Variant	*variant;	Tuner	*tuner;	Pcidev	*pci;	uchar	i2ctuneraddr;	uchar	i2ccmd;			// I2C command	int		board;			// What board is this? 	Ref		fref;				// Copying images?	int		nframes;			// Number of frames to capture.	Frame	*frames;			// DMA program	int		lframe;			// Last frame DMAed} Tv; enum {	TemicPAL = 0,	PhilipsPAL,	PhilipsNTSC,	PhilipsSECAM,	Notuner,	PhilipsPALI,	TemicNTSC,	TemicPALI,	Temic4036,	AlpsTSBH1,	AlpsTSBE1, 	Freqmultiplier = 16,}; static Tuner tuners[] = {        {"Temic PAL", Freqmultiplier * 140.25, Freqmultiplier * 463.25, 		0x02, 0x04, 0x01, 0x8e, 623 },	{"Philips PAL_I", Freqmultiplier * 140.25, Freqmultiplier * 463.25, 		0xa0, 0x90, 0x30, 0x8e, 623 },	{"Philips NTSC",  Freqmultiplier * 157.25, Freqmultiplier * 451.25, 		0xA0, 0x90, 0x30, 0x8e, 732 },	{"Philips SECAM", Freqmultiplier * 168.25, Freqmultiplier * 447.25, 		0xA7, 0x97, 0x37, 0x8e, 623 },	{"NoTuner", 0, 0, 		0x00, 0x00, 0x00, 0x00, 0 },	{"Philips PAL", Freqmultiplier * 168.25, Freqmultiplier * 447.25, 		0xA0, 0x90, 0x30, 0x8e, 623 },	{"Temic NTSC", Freqmultiplier * 157.25, Freqmultiplier * 463.25, 		0x02, 0x04, 0x01, 0x8e, 732 },	{"TEMIC PAL_I", Freqmultiplier * 170.00, Freqmultiplier * 450.00, 		0x02, 0x04, 0x01, 0x8e, 623 },	{"Temic 4036 FY5 NTSC", Freqmultiplier * 157.25, Freqmultiplier * 463.25, 		0xa0, 0x90, 0x30, 0x8e, 732 },	{"Alps TSBH1", Freqmultiplier * 137.25, Freqmultiplier * 385.25, 		0x01, 0x02, 0x08, 0x8e, 732 },	{"Alps TSBE1", Freqmultiplier * 137.25, Freqmultiplier * 385.25, 		0x01, 0x02, 0x08, 0x8e, 732 },}; enum {	CMvstart,	CMvgastart,	CMvstop,	CMchannel,}; static Cmdtab tvctlmsg[] = {	CMvstart,			"vstart",			2,	CMvgastart,		"vgastart",		3,	CMvstop,			"vstop",			1,	CMchannel,		"channel",			3,}; static Dirtab tvtab[]={	".",		{ Qdir, 0, QTDIR },	0,	DMDIR|0555,	"tv",		{ Qdata, 0 },		0,	0600,	"tvctl",	{ Qctl, 0 },			0,	0600,	"tvregs",	{ Qregs, 0 },		0,	0400,}; static Variant variant[] = {{	Brooktree_vid,	Brooktree_848_did,	"Brooktree 848 TV tuner",	},}; static char *boards[] = {	"MIRO PRO",	"MIRO",}; static Tv *tv; static int i2cread(Tv *, uchar, uchar *);static int i2cwrite(Tv *, uchar, uchar, uchar, int);static void tvinterrupt(Ureg *, Tv *);static void vgastart(Tv *, ulong, int);static void vstart(Tv *, int, int, int, int);static void vstop(Tv *);static void frequency(Tv *, int, int);static int getbpp(Tv *); static voidtvinit(void){	Pcidev *pci;	ulong intmask; 	// Test for a triton memory controller.	intmask = 0;	if (pcimatch(nil, Intel_vid, Intel_82437_did))		intmask = intmask_etbf; 	pci = nil;	while ((pci = pcimatch(pci, 0, 0)) != nil) {		int i, t;		Bt848 *bt848;		ushort hscale, hdelay;		uchar v; 		for (i = 0; i != nelem(variant); i++)			if (pci->vid == variant[i].vid && pci->did == variant[i].did)				break;		if (i == nelem(variant))			continue; 		if (tv) {			print("#V: Currently there is only support for one TV, ignoring %s\n",				variant[i].name);			continue;		} 		tv = (Tv *)malloc(sizeof(Tv));		assert(tv); 		tv->variant = &variant[i];		tv->pci = pci;		tv->bt848 = (Bt848 *)upamalloc(pci->mem[0].bar & ~0x0F, 4 * K, K);		if (tv->bt848 == nil)			panic("#V: Cannot allocate memory for Bt848\n");		bt848 = tv->bt848; 		// i2c stuff.		if (pci->did >= 878)			tv->i2ccmd = 0x83;		else 			tv->i2ccmd = i2c_timing | i2c_bt848scl | i2c_bt848sda; 		{			bt848->gpioouten = 0; 			bt848->gpioouten |= 1 << 5;			bt848->gpiodata[0] |= 1 << 5;			microdelay(2500);			bt848->gpiodata[0] |= 1 << 5;			microdelay(2500);		}				if (i2cread(tv, i2c_haupee, &v)) 			panic("#V: Cannot deal with hauppauge boards\n");		if (i2cread(tv, i2c_stbee, &v))			panic("#V: Cannot deal with STB cards\n");		if (i2cread(tv, i2c_miroproee, &v)) {			tv->board = Bt848_miropro;			t = ((bt848->gpiodata[0] >> 10) - 1) & 7;		}		else {			tv->board = Bt848_miro;			t = ((bt848->gpiodata[0] >> 10) - 1) & 7;		} 		if (t >= nelem(tuners))			t = 4;		tv->tuner = &tuners[t];		tv->i2ctuneraddr = 			i2cread(tv, 0xc1, &v)? 0xc0:			i2cread(tv, 0xc3, &v)? 0xc2:			i2cread(tv, 0xc5, &v)? 0xc4:			i2cread(tv, 0xc7, &v)? 0xc6: -1; 		bt848->capctl = capctl_fullframe;		bt848->adelay = adelay_ntsc;		bt848->bdelay = bdelay_ntsc;		bt848->iform = iform_muxsel0|iform_xtauto|iform_ntsc;		bt848->vbipacksize = vbipacksize & 0xff;		bt848->vbipackdel = (vbipacksize >> 8) & 1; 		// setpll(bt848); 		bt848->colorfmt = colorfmt_rgb16; 		hscale = (ntsc_rawpixels * 4096) / ntsc_sqpixels - 4096;		hdelay = (ntsc_clkx1delay * ntsc_hactive) / ntsc_clkx1hactive; 		bt848->ovtc = bt848->evtc = 0;		bt848->ehscalehi = bt848->ohscalehi = (hscale >> 8) & 0xff;		bt848->ehscalelo = bt848->ohscalelo = hscale & 0xff;		bt848->evscalehi &= ~0x1f;		bt848->ovscalehi &= ~0x1f;		bt848->evscalehi |= vscale_interlaced | ((ntsc_vscale >> 8) & 0x1f);		bt848->ovscalehi |= vscale_interlaced | (ntsc_vscale >> 8) & 0x1f;		bt848->evscalelo = bt848->ovscalelo = ntsc_vscale & 0xff;		bt848->ehactivelo = bt848->ohactivelo = ntsc_hactive & 0xff;		bt848->ehdelaylo = bt848->ohdelaylo = hdelay & 0xff;		bt848->evactivelo = bt848->ovactivelo = ntsc_vactive & 0xff;		bt848->evdelaylo = bt848->ovdelaylo = ntsc_vdelay & 0xff;		bt848->ecrop = bt848->ocrop = 			((ntsc_hactive >> 8) & 0x03) |			((hdelay >> 6) & 0x0C) |	        		((ntsc_vactive >> 4) & 0x30) |			((ntsc_vdelay >> 2) & 0xC0);	 		bt848->colorctl = colorctl_gamma;		bt848->capctl = 0;		bt848->gpiodmactl = gpiodmactl_pltp23_16 |			gpiodmactl_pltp1_16 | gpiodmactl_pktp_32;		bt848->gpioreginp = 0;		bt848->contrastlo = contrast_100percent;		bt848->bright = 16;		bt848->adc = (2 << 6) | adc_crush;		bt848->econtrol = bt848->ocontrol = control_ldec;		bt848->escloop = bt848->oscloop = 0;		bt848->intstat = (ulong)-1;		bt848->intmask = intmask | 			intstat_vsync | intstat_scerr | intstat_risci | intstat_ocerr | 			intstat_vpress | intstat_fmtchg | intstat_hlock; 		bt848->gpioouten &= ~0xF;		bt848->gpioouten |= 0xF;		bt848->gpiodata[0] &= ~0xF;		bt848->gpiodata[0] |= 2;	// Enable audio on the MIRO card. 		print("#V: %s (rev %d) (%s/%s) %.8ulX, intl %d\n", 				tv->variant->name, pci->rid, boards[tv->board],				tv->tuner->name, pci->mem[0].bar & ~0x0F, pci->intl); 		intrenable(pci->intl, (void (*)(Ureg *, void *))tvinterrupt, 				tv, pci->tbdf, "tv");		}} static Chan*tvattach(char *spec){	return devattach('V', spec);} static Walkqid *tvwalk(Chan *c, Chan *nc, char **name, int nname){	return devwalk(c, nc, name, nname, tvtab, nelem(tvtab), devgen);} static inttvstat(Chan *c, uchar *db, int n){	return devstat(c, db, n, tvtab, nelem(tvtab), devgen);} static Chan*tvopen(Chan *c, int omode){	switch ((int)c->qid.path) {	case Qdir:		return devopen(c, omode, tvtab, nelem(tvtab), devgen);	} 	c->mode = openmode(omode);	c->flag |= COPEN;	c->offset = 0;	return c;} static voidtvclose(Chan *){} static longtvread(Chan *c, void *a, long n, vlong offset){	static char regs[10 * K];	static int regslen;	char *e, *p; 	USED(offset); 	switch((int)c->qid.path) {	case Qdir:		return devdirread(c, a, n, tvtab, nelem(tvtab), devgen); 	case Qdata: {

Lines 1–500 of 961.