📄 devtv.c
字号:
/* * 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"#include "hcwAMC.h"#define max(a, b) (((a) > (b))? (a): (b))enum { Qdir = 0, Qsubdir, Qsubbase, Qvdata = Qsubbase, Qadata, Qctl, Qregs, Brooktree_vid = 0x109e, Brooktree_848_did = 0x0350, Brooktree_878_did = 0x036E, Intel_vid = 0x8086, Intel_82437_did = 0x122d, K = 1024, M = K * K, Ntvs = 4, 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_nostop = 1 << 5, i2c_nos1b = 1 << 4, i2c_timing = 7 << 4, i2c_bt848w3b = 1 << 2, i2c_bt848scl = 1 << 1, i2c_bt848sda = 1 << 0, i2c_scl = i2c_bt848scl, i2c_sda = i2c_bt848sda, i2c_miroproee = 0x80, // MIRO PRO EEPROM i2c_tea6300 = 0x80, i2c_tda8425 = 0x82, i2c_tda9840 = 0x84, i2c_tda9850 = 0xb6, i2c_haupee = 0xa0, // Hauppage EEPROM i2c_stbee = 0xae, // STB EEPROM i2c_msp3400 = 0x80, i2c_timeout = 1000, i2c_delay = 10, Bt848_miropro = 0, Bt848_miro, Bt878_hauppauge, // 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 colorfmt_YCbCr422 = (8 << 4) | (8 << 0), colorfmt_YCbCr411 = (9 << 4) | (9 << 0), 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_pabort = 1 << 17, intstat_riperr = 1 << 16, intstat_pperr = 1 << 15, intstat_fdsr = 1 << 14, intstat_ftrgt = 1 << 13, 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_apwrdn = 1 << 26, // 10C gpiodmactl_daes2 = 1 << 13, gpiodmactl_daiomda = 1 << 6, gpiodmactl_pltp23_16 = 2 << 6, gpiodmactl_pltp23_0 = 0 << 6, gpiodmactl_pltp1_16 = 2 << 4, gpiodmactl_pltp1_0 = 0 << 4, gpiodmactl_acapenable = 1 << 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, fifo_fm3 = 0xe, riscirq = 1 << 24, riscwrite = 1 << 28, riscwrite123 = 9 << 28, riscwrite1s23 = 11 << 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, riscsync_fm3 = fifo_fm3 << 0, risclabelshift_set = 16, risclabelshift_reset = 20, AudioTuner = 0, AudioRadio, AudioExtern, AudioIntern, AudioOff, AudioOn, asel_tv = 0, asel_radio, asel_mic, asel_smxc, Hwbase_ad = 448000, msp_dem = 0x10, msp_bbp = 0x12, // Altera definitions. gpio_altera_data = 1 << 0, gpio_altera_clock = 1 << 20, gpio_altera_nconfig = 1 << 23, Ial = 0x140001, Idma = 0x100002, Adsp = 0x7fd8, Adsp_verifysystem = 1, Adsp_querysupportplay, Adsp_setstyle, Adsp_setsrate, Adsp_setchannels, Adsp_setresolution, Adsp_setcrcoptions, Adsp_bufenqfor, Adsp_logbuffer, Adsp_startplay, Adsp_stopplay, Adsp_autostop, Adsp_startrecord, Adsp_stoprecord, Adsp_getlastprocessed, Adsp_pause, Adsp_resume, Adsp_setvolume, Adsp_querysupportrecord, Adsp_generalbufenq, Adsp_setdownmixtype, Adsp_setigain, Adsp_setlineout, Adsp_setlangmixtype, Kfir_gc = 0, Kfir_dsp_riscmc, Kfir_dsp_risccram, Kfir_dsp_unitmc, Kfir_bsm_mc, Kfir_mux_mc, Kfir_devid_gc = 7, Kfir_devid_dsp = 4, Kfir_devid_bsm = 5, Kfir_devid_mux = 8, Kfir_200 = 200, Kfir_dev_inst = Kfir_200, Kfir_201 = 201, Kfir_exec = Kfir_201, Kfir_202 = 202, Kfir_adr_eready = 254, Kfir_d_eready_encoding = 0, Kfir_d_eready_ready, Kfir_d_eready_test, Kfir_d_eready_stopdetect, Kfir_d_eready_seqend, VT_KFIR_OFF = 0, VT_KFIR_ON, VT_KFIR_LAYER_II = 1, VT_KFIR_STEREO = 1, Gpioinit = 0, Gpiooutput, Gpioinput, Srate_5512 = 0, Srate_11025 = 2, Srate_16000 = 3, Srate_22050 = 4, Srate_32000 = 5, Srate_44100 = 6, Srate_48000 = 7,};typedef struct Variant Variant;struct Variant { ushort vid; ushort did; char *name;};typedef struct Bt848 Bt848;struct Bt848 { 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};#define packetlen i2ctypedef struct Tuner Tuner;struct Tuner { char *name; ushort freq_vhfh; // Start frequency ushort freq_uhf; uchar VHF_L; uchar VHF_H; uchar UHF; uchar cfg; ushort offs;};typedef struct Frame Frame;struct Frame { ulong *fstart; ulong *fjmp; uchar *fbase;};typedef struct Tv Tv;struct Tv { Lock; Rendez; Bt848 *bt848; Bt848 *bt878; // Really only audio control registers Variant *variant; Tuner *tuner; Pcidev *pci; uchar i2ctuneraddr; uchar i2ccmd; // I2C command int board; // What board is this? ulong cfmt; // Current color format. int channel; // Current channel Ref fref; // Copying images? int nframes; // Number of frames to capture. Frame *frames; // DMA program int lvframe; // Last video frame DMAed uchar *amux; // Audio multiplexer. int nablocks; // Number of audio blocks allocated int absize; // Audio block size int narblocks; // Number of audio blocks received ulong *arisc; // Audio risc bloc uchar *abuf; // Audio data buffers char ainfo[128]; // WinTV/PVR stuff. int msp; Lock kfirlock; ulong i2cstate; // Last i2c state. int gpiostate; // Current GPIO state ulong alterareg; // Last used altera register ulong alteraclock; // Used to clock the altera int asrate; // Audio sample rate uchar aleft, aright; // Left and right audio volume ulong kfirclock; Ref aref; // Copying audio?};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 },};static int hp_tuners[] = { Notuner, Notuner, Notuner, Notuner, Notuner, PhilipsNTSC, Notuner, Notuner, PhilipsPAL, PhilipsSECAM, PhilipsNTSC, PhilipsPALI, Notuner, Notuner, TemicPAL, TemicPALI, Notuner, PhilipsSECAM, PhilipsNTSC, PhilipsPALI, Notuner, PhilipsPAL, Notuner, PhilipsNTSC,};enum { CMvstart, CMastart, CMastop, CMvgastart, CMvstop, CMchannel, CMcolormode, CMvolume, CMmute,};static Cmdtab tvctlmsg[] = { CMvstart, "vstart", 2, CMastart, "astart", 5, CMastop, "astop", 1, CMvgastart, "vgastart", 3, CMvstop, "vstop", 1, CMchannel, "channel", 3, CMcolormode, "colormode", 2, CMvolume, "volume", 3, CMmute, "mute", 1,};static Variant variant[] = {{ Brooktree_vid, Brooktree_848_did, "Brooktree 848 TV tuner", },{ Brooktree_vid, Brooktree_878_did, "Brooktree 878 TV tuner", },};static char *boards[] = { "MIRO PRO", "MIRO", "Hauppauge Bt878",};static ushort Adspfsample[] = { 0x500, 0x700, 0x400, 0x600, 0x300, 0x200, 0x000, 0x100};static ushort Adspstereorates[] = { 64, 96, 112, 128, 160, 192, 224, 256, 320, 384};static uchar miroamux[] = { 2, 0, 0, 0, 10, 0 };static uchar hauppaugeamux[] = { 0, 1, 2, 3, 4, 0 };static char *nicamstate[] = { "analog", "???", "digital", "bad digital receiption" };static Tv tvs[Ntvs];static int ntvs;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 astart(Tv *, char *, uint, uint, uint);static void vstop(Tv *);static void astop(Tv *);static void colormode(Tv *, char *);static void frequency(Tv *, int, int);static int getbitspp(Tv *);static char *getcolormode(ulong);static int mspreset(Tv *);static void i2cscan(Tv *);static int kfirinitialize(Tv *);static void msptune(Tv *);static void mspvolume(Tv *, int, int, int);static void gpioenable(Tv *, ulong, ulong);static void gpiowrite(Tv *, ulong, ulong);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; Tv *tv; 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 (ntvs >= Ntvs) { print("#V: Too many TV cards found\n"); continue; } tv = &tvs[ntvs++]; tv->variant = &variant[i]; tv->pci = pci; tv->bt848 = (Bt848 *)vmap(pci->mem[0].bar & ~0x0F, 4 * K); if (tv->bt848 == nil) panic("#V: Cannot allocate memory for Bt848"); bt848 = tv->bt848; // i2c stuff. if (pci->did >= 878) tv->i2ccmd = 0x83; else tv->i2ccmd = i2c_timing | i2c_bt848scl | i2c_bt848sda; t = 0; if (i2cread(tv, i2c_haupee, &v)) { uchar ee[256]; Pcidev *pci878; Bt848 *bt878; tv->board = Bt878_hauppauge; if (!i2cwrite(tv, i2c_haupee, 0, 0, 0)) panic("#V: Cannot write to Hauppauge EEPROM"); for (i = 0; i != sizeof ee; i++) if (!i2cread(tv, i2c_haupee + 1, &ee[i])) panic("#V: Cannot read from Hauppauge EEPROM"); if (ee[9] > sizeof hp_tuners / sizeof hp_tuners[0]) panic("#V: Tuner out of range (max %d, this %d)", sizeof hp_tuners / sizeof hp_tuners[0], ee[9]); t = hp_tuners[ee[9]]; // Initialize the audio channel. if ((pci878 = pcimatch(nil, Brooktree_vid, 0x878)) == nil) panic("#V: Unsupported Hauppage board"); tv->bt878 = bt878 = (Bt848 *)vmap(pci878->mem[0].bar & ~0x0F, 4 * K); if (bt878 == nil) panic("#V: Cannot allocate memory for the Bt878"); kfirinitialize(tv); // i2cscan(tv); mspreset(tv); bt878->gpiodmactl = 0; bt878->intstat = (ulong)-1; intrenable(pci878->intl, (void (*)(Ureg *, void *))tvinterrupt, tv, pci878->tbdf, "tv"); tv->amux = hauppaugeamux; } else if (i2cread(tv, i2c_stbee, &v)) { USED(t); panic("#V: Cannot deal with STB cards\n"); } else if (i2cread(tv, i2c_miroproee, &v)) { tv->board = Bt848_miropro; t = ((bt848->gpiodata[0] >> 10) - 1) & 7; tv->amux = miroamux; } else { tv->board = Bt848_miro; tv->amux = miroamux; 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); tv->cfmt = 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; if (tv->amux) { gpioenable(tv, ~0xfff, 0xfff); gpiowrite(tv, ~0xfff, tv->amux[AudioRadio]); } print("#V%ld: %s (rev %d) (%s/%s) intl %d\n", tv - tvs, tv->variant->name, pci->rid, boards[tv->board], tv->tuner->name, pci->intl); intrenable(pci->intl, (void (*)(Ureg *, void *))tvinterrupt, tv, pci->tbdf, "tv"); }}static Chan*tvattach(char *spec){ return devattach('V', spec);}#define TYPE(q) ((int)((q).path & 0xff))#define DEV(q) ((int)(((q).path >> 8) & 0xff))#define QID(d, t) ((((d) & 0xff) << 8) | (t))static inttv1gen(Chan *c, int i, Dir *dp){ Qid qid; switch (i) { case Qvdata: mkqid(&qid, QID(DEV(c->qid), Qvdata), 0, QTFILE); devdir(c, qid, "video", 0, eve, 0444, dp); return 1; case Qadata: mkqid(&qid, QID(DEV(c->qid), Qadata), 0, QTFILE); devdir(c, qid, "audio", 0, eve, 0444, dp); return 1; case Qctl: mkqid(&qid, QID(DEV(c->qid), Qctl), 0, QTFILE); devdir(c, qid, "ctl", 0, eve, 0444, dp); return 1; case Qregs: mkqid(&qid, QID(DEV(c->qid), Qregs), 0, QTFILE); devdir(c, qid, "regs", 0, eve, 0444, dp); return 1; } return -1;}static inttvgen(Chan *c, char *, Dirtab *, int, int i, Dir *dp){ Qid qid; int dev;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -