📄 devtv.c
字号:
uchar *abuf; int s, d; if (bt878 == nil || tv->amux == nil) error("#V: Card does not support audio"); selector = 0; if (!strcmp(input, "tv")) selector = asel_tv; else if (!strcmp(input, "radio")) selector = asel_radio; else if (!strcmp(input, "mic")) selector = asel_mic; else if (!strcmp(input, "smxc")) selector = asel_smxc; else error("#V: Invalid input"); if (nasz > 0xfff) error("#V: Audio block size too big (max 0xfff)"); abuf = (uchar *)malloc(nab * nasz * sizeof(uchar)); assert(abuf); arisc = riscaudio(PADDR(abuf), nab, nasz); ilock(tv); if (tv->arisc) { iunlock(tv); free(abuf); free(arisc); error(Einuse); } tv->arisc = arisc; tv->abuf = abuf; tv->nablocks = nab; tv->absize = nasz; bt878->riscstrtadd = PADDR(tv->arisc); bt878->packetlen = (nab << 16) | nasz; bt878->intmask = intstat_scerr | intstat_ocerr | intstat_risci | intstat_pabort | intstat_riperr | intstat_pperr | intstat_fdsr | intstat_ftrgt | intstat_fbus; /* Assume analog, 16bpp */ for (s = 0; s < 16; s++) if (rate << s > Hwbase_ad * 4 / 15) break; for (d = 15; d >= 4; d--) if (rate << s < Hwbase_ad * 4 / d) break; print("astart: sampleshift %d, decimation %d\n", s, d); tv->narblocks = 0; bt878->gpiodmactl = gpiodmactl_fifoenable | gpiodmactl_riscenable | gpiodmactl_acapenable | gpiodmactl_daes2 | /* gpiodmactl_apwrdn | */ gpiodmactl_daiomda | (d << 8) | (9 << 28) | (selector << 24); print("dmactl %.8ulX\n", bt878->gpiodmactl); iunlock(tv);}static voidastop(Tv *tv){ Bt848 *bt878 = tv->bt878; ilock(tv); if (tv->aref.ref > 0) { iunlock(tv); error(Einuse); } if (tv->abuf) { bt878->gpiodmactl &= ~gpiodmactl_riscenable; bt878->gpiodmactl &= ~gpiodmactl_fifoenable; free(tv->abuf); tv->abuf = nil; free(tv->arisc); tv->arisc = nil; } iunlock(tv);}static voidvgastart(Tv *tv, ulong pa, int stride){ Frame *frame; frame = (Frame *)malloc(sizeof(Frame)); assert(frame); if (waserror()) { free(frame); nexterror(); } frame->fbase = nil; frame->fstart = riscpacked(pa, 0, ntsc_hactive * getbitspp(tv) / 8, ntsc_vactive, stride * getbitspp(tv) / 8, &frame->fjmp); *frame->fjmp = PADDR(frame->fstart); vactivate(tv, frame, 1);}static voidvstop(Tv *tv){ Bt848 *bt848 = tv->bt848; ilock(tv); if (tv->fref.ref > 0) { iunlock(tv); error(Einuse); } if (tv->frames) { int i; bt848->gpiodmactl &= ~gpiodmactl_riscenable; bt848->gpiodmactl &= ~gpiodmactl_fifoenable; bt848->capctl &= ~(capctl_captureodd|capctl_captureeven); for (i = 0; i != tv->nframes; i++) if (tv->frames[i].fbase) free(tv->frames[i].fbase); free(tv->frames); tv->frames = nil; } iunlock(tv);}static longhrcfreq[] = { /* HRC CATV frequencies */ 0, 7200, 5400, 6000, 6600, 7800, 8400, 17400, 18000, 18600, 19200, 19800, 20400, 21000, 12000, 12600, 13200, 13800, 14400, 15000, 15600, 16200, 16800, 21600, 22200, 22800, 23400, 24000, 24600, 25200, 25800, 26400, 27000, 27600, 28200, 28800, 29400, 30000, 30600, 31200, 31800, 32400, 33000, 33600, 34200, 34800, 35400, 36000, 36600, 37200, 37800, 38400, 39000, 39600, 40200, 40800, 41400, 42000, 42600, 43200, 43800, 44400, 45000, 45600, 46200, 46800, 47400, 48000, 48600, 49200, 49800, 50400, 51000, 51600, 52200, 52800, 53400, 54000, 54600, 55200, 55800, 56400, 57000, 57600, 58200, 58800, 59400, 60000, 60600, 61200, 61800, 62400, 63000, 63600, 64200, 9000, 9600, 10200, 10800, 11400, 64800, 65400, 66000, 66600, 67200, 67800, 68400, 69000, 69600, 70200, 70800, 71400, 72000, 72600, 73200, 73800, 74400, 75000, 75600, 76200, 76800, 77400, 78000, 78600, 79200, 79800,};static voidfrequency(Tv *tv, int channel, int finetune){ Tuner *tuner = tv->tuner; long freq; ushort div; uchar cfg; if (channel < 0 || channel > nelem(hrcfreq)) error(Ebadarg); freq = (hrcfreq[channel] * Freqmultiplier) / 100; if (freq < tuner->freq_vhfh) cfg = tuner->VHF_L; else if (freq < tuner->freq_uhf) cfg = tuner->VHF_H; else cfg = tuner->UHF; div = (freq + tuner->offs + finetune) & 0x7fff; if (!i2cwrite(tv, tv->i2ctuneraddr, (div >> 8) & 0x7f, div, 1)) error(Eio); if (!i2cwrite(tv, tv->i2ctuneraddr, tuner->cfg, cfg, 1)) error(Eio); tv->channel = channel; if (tv->msp) msptune(tv);}static struct { char *cmode; ulong realmode; ulong cbits;} colormodes[] = {{ "RGB16", colorfmt_rgb16, colorfmt_rgb16, },{ "YCbCr422", colorfmt_YCbCr422, colorfmt_YCbCr422, },{ "YCbCr411", colorfmt_YCbCr411, colorfmt_YCbCr422, },};static voidcolormode(Tv *tv, char *colormode){ Bt848 *bt848 = tv->bt848; int i; for (i = 0; i != nelem(colormodes); i++) if (!strcmp(colormodes[i].cmode, colormode)) break; if (i == nelem(colormodes)) error(Ebadarg); tv->cfmt = colormodes[i].realmode; bt848->colorfmt = colormodes[i].cbits;}static intgetbitspp(Tv *tv){ switch (tv->cfmt) { case colorfmt_rgb16: case colorfmt_YCbCr422: return 16; case colorfmt_YCbCr411: return 12; default: error("getbitspp: Unsupport color format\n"); } return -1;}static char *getcolormode(ulong cmode){ switch (cmode) { case colorfmt_rgb16: return "RGB16"; case colorfmt_YCbCr411: return "YCbCr411"; case colorfmt_YCbCr422: return (cmode == colorfmt_YCbCr422)? "YCbCr422": "YCbCr411"; default: error("getcolormode: Unsupport color format\n"); } return nil;}static voidi2c_set(Tv *tv, int scl, int sda){ Bt848 *bt848 = tv->bt848; ulong d; bt848->i2c = (scl << 1) | sda; d = bt848->i2c; USED(d); microdelay(i2c_delay);}static uchari2c_getsda(Tv *tv){ Bt848 *bt848 = tv->bt848; return bt848->i2c & i2c_sda;}static voidi2c_start(Tv *tv){ i2c_set(tv, 0, 1); i2c_set(tv, 1, 1); i2c_set(tv, 1, 0); i2c_set(tv, 0, 0);}static voidi2c_stop(Tv *tv){ i2c_set(tv, 0, 0); i2c_set(tv, 1, 0); i2c_set(tv, 1, 1);}static voidi2c_bit(Tv *tv, int sda){ i2c_set(tv, 0, sda); i2c_set(tv, 1, sda); i2c_set(tv, 0, sda);}static inti2c_getack(Tv *tv){ int ack; i2c_set(tv, 0, 1); i2c_set(tv, 1, 1); ack = i2c_getsda(tv); i2c_set(tv, 0, 1); return ack;}static inti2c_wr8(Tv *tv, uchar d, int wait){ int i, ack; i2c_set(tv, 0, 0); for (i = 0; i != 8; i++) { i2c_bit(tv, (d & 0x80)? 1: 0); d <<= 1; } if (wait) microdelay(wait); ack = i2c_getack(tv); return ack == 0;}static uchari2c_rd8(Tv *tv, int lastbyte){ int i; uchar d; d = 0; i2c_set(tv, 0, 1); for (i = 0; i != 8; i++) { i2c_set(tv, 1, 1); d <<= 1; if (i2c_getsda(tv)) d |= 1; i2c_set(tv, 0, 1); } i2c_bit(tv, lastbyte? 1: 0); return d;}static intmspsend(Tv *tv, uchar *cmd, int ncmd){ int i, j, delay; for (i = 0; i != 3; i++) { delay = 2000; i2c_start(tv); for (j = 0; j != ncmd; j++) { if (!i2c_wr8(tv, cmd[j], delay)) break; delay = 0; } i2c_stop(tv); if (j == ncmd) return 1; microdelay(10000); print("mspsend: retrying\n"); } return 0;}static intmspwrite(Tv *tv, uchar sub, ushort reg, ushort v){ uchar b[6]; b[0] = i2c_msp3400; b[1] = sub; b[2] = reg >> 8; b[3] = reg; b[4] = v >> 8; b[5] = v; return mspsend(tv, b, sizeof b);}static intmspread(Tv *tv, uchar sub, ushort reg, ushort *data){ uchar b[4]; int i; b[0] = i2c_msp3400; b[1] = sub; b[2] = reg >> 8; b[3] = reg; for (i = 0; i != 3; i++) { i2c_start(tv); if (!i2c_wr8(tv, b[0], 2000) || !i2c_wr8(tv, b[1] | 1, 0) || !i2c_wr8(tv, b[2], 0) || !i2c_wr8(tv, b[3], 0)) { i2c_stop(tv); microdelay(10000); print("retrying\n"); continue; } i2c_start(tv); if (!i2c_wr8(tv, b[0] | 1, 2000)) { i2c_stop(tv); continue; } *data = i2c_rd8(tv, 0) << 8; *data |= i2c_rd8(tv, 1); i2c_stop(tv); return 1; } return 0;}static uchar mspt_reset[] = { i2c_msp3400, 0, 0x80, 0 };static uchar mspt_on[] = { i2c_msp3400, 0, 0, 0 };static intmspreset(Tv *tv){ ushort v, p; Bt848 *bt848 = tv->bt848; ulong b; b = 1 << 5; gpioenable(tv, ~b, b); gpiowrite(tv, ~b, 0); microdelay(2500); gpiowrite(tv, ~b, b); bt848->i2c = 0x80; microdelay(2000); mspsend(tv, mspt_reset, sizeof mspt_reset); microdelay(2000); if (!mspsend(tv, mspt_on, sizeof mspt_on)) { print("#V: Cannot find MSP34x5G on the I2C bus (on)\n"); return 0; } microdelay(2000); if (!mspread(tv, msp_bbp, 0x001e, &v)) { print("#V: Cannot read MSP34xG5 chip version\n"); return 0; } if (!mspread(tv, msp_bbp, 0x001f, &p)) { print("#V: Cannot read MSP34xG5 product code\n"); return 0; } print("#V: MSP34%dg ROM %.d, %d.%d\n", (uchar)(p >> 8), (uchar)p, (uchar)(v >> 8), (uchar)v); tv->msp = 1; return 1;}static voidmspvolume(Tv *tv, int mute, int l, int r){ short v, d; ushort b; if (mute) { v = 0; b = 0; } else { tv->aleft = l; tv->aright = r; d = v = max(l, r); if (d == 0) d++; b = ((r - l) * 0x7f) / d; } mspwrite(tv, msp_bbp, 0, v << 8); mspwrite(tv, msp_bbp, 7, v? 0x4000: 0); mspwrite(tv, msp_bbp, 1, b << 8); }static char *mspaformat(int f){ switch (f) { case 0: return "unknown"; case 2: case 0x20: case 0x30: return "M-BTSC"; case 3: return "B/G-FM"; case 4: case 9: case 0xB: return "L-AM/NICAM D/Kn"; case 8: return "B/G-NICAM"; case 0xA: return "I"; case 0x40: return "FM-Radio"; } return "unknown format";} static voidmsptune(Tv *tv){ ushort d, s, nicam; int i; mspvolume(tv, 1, 0, 0); if (!mspwrite(tv, msp_dem, 0x0030, 0x2033)) error("#V: Cannot set MODUS register"); if (!mspwrite(tv, msp_bbp, 0x0008, 0x0320)) error("#V: Cannot set loadspeaker input"); if (!mspwrite(tv, msp_dem, 0x0040, 0x0001)) error("#V: Cannot set I2S clock freq"); if (!mspwrite(tv, msp_bbp, 0x000d, 0x1900)) error("#V: Cannot set SCART prescale"); if (!mspwrite(tv, msp_bbp, 0x000e, 0x2403)) error("#V: Cannot set FM/AM prescale"); if (!mspwrite(tv, msp_bbp, 0x0010, 0x5a00)) error("#V: Cannot set NICAM prescale"); if (!mspwrite(tv, msp_dem, 0x0020, 0x0001)) error("#V: Cannot start auto detect"); for (d = (ushort)-1, i = 0; i != 10; i++) { if (!mspread(tv, msp_dem, 0x007e, &d)) error("#V: Cannot get autodetect info MSP34xG5"); if (d == 0 || d < 0x800) break; delay(50); } if (!mspread(tv, msp_dem, 0x0200, &s)) error("#V: Cannot get status info MSP34xG5"); mspvolume(tv, 0, tv->aleft, tv->aright); nicam = ((s >> 4) & 2) | ((s >> 9) & 1); snprint(tv->ainfo, sizeof tv->ainfo, "%s %s %s", mspaformat(d), (s & (1 << 6))? "stereo": "mono", nicamstate[nicam]);}static voidi2cscan(Tv *tv){ int i, ack; for (i = 0; i < 0x100; i += 2) { i2c_start(tv); ack = i2c_wr8(tv, i, 0); i2c_stop(tv); if (ack) { print("i2c device @%.2uX\n", i); } } for (i = 0xf0; i != 0xff; i++) { i2c_start(tv); ack = i2c_wr8(tv, i, 0); i2c_stop(tv); if (ack) print("i2c device may be at @%.2uX\n", i); }}static voidgpioenable(Tv *tv, ulong mask, ulong data){ Bt848 *bt848 = tv->bt848; bt848->gpioouten = (bt848->gpioouten & mask) | data;}static voidgpiowrite(Tv *tv, ulong mask, ulong data){ Bt848 *bt848 = tv->bt848; bt848->gpiodata[0] = (bt848->gpiodata[0] & mask) | data;}static voidalteraoutput(Tv *tv){ if (tv->gpiostate == Gpiooutput) return; gpioenable(tv, ~0xffffff, 0x56ffff); microdelay(10); tv->gpiostate = Gpiooutput;}static voidalterainput(Tv *tv){ if (tv->gpiostate == Gpioinput) return; gpioenable(tv, ~0xffffff, 0x570000); microdelay(10); tv->gpiostate = Gpioinput;}static voidalterareg(Tv *tv, ulong reg){ if (tv->alterareg == reg) return; gpiowrite(tv, ~0x56ffff, (reg & 0x54ffff) | tv->alteraclock); microdelay(10); tv->alterareg = reg;}static voidalterawrite(Tv *tv, ulong reg, ushort data){ alteraoutput(tv); alterareg(tv, reg); tv->alteraclock ^= 0x20000; gpiowrite(tv, ~0x56ffff, (reg & 0x540000) | data | tv->alteraclock); microdelay(10);}static voidalteraread(Tv *tv, int reg, ushort *data){ Bt848 *bt848 = tv->bt848; if (tv->alterareg != reg) { alteraoutput(tv); alterareg(tv, reg); } else { gpioenable(tv, ~0xffffff, 0x560000); microdelay(10); } alterainput(tv); gpiowrite(tv, ~0x570000, (reg & 0x560000) | tv->alteraclock); microdelay(10); *data = (ushort)bt848->gpiodata[0]; microdelay(10);}static voidkfirloadu(Tv *tv, uchar *u, int ulen){ Bt848 *bt848 = tv->bt848; int i, j; ilock(&tv->kfirlock); bt848->gpioouten &= 0xff000000; bt848->gpioouten |= gpio_altera_data | gpio_altera_clock | gpio_altera_nconfig; bt848->gpiodata[0] &= 0xff000000; microdelay(10); bt848->gpiodata[0] |= gpio_altera_nconfig; microdelay(10); // Download the microcode for (i = 0; i != ulen; i++) for (j = 0; j != 8; j++) { bt848->gpiodata[0] &= ~(gpio_altera_clock|gpio_altera_data); if (u[i] & 1) bt848->gpiodata[0] |= gpio_altera_data; bt848->gpiodata[0] |= gpio_altera_clock; u[i] >>= 1; } bt848->gpiodata[0] &= ~gpio_altera_clock; microdelay(100); // Initialize. for (i = 0; i != 30; i++) { bt848->gpiodata[0] &= ~gpio_altera_clock; bt848->gpiodata[0] |= gpio_altera_clock; } bt848->gpiodata[0] &= ~(gpio_altera_clock|gpio_altera_data); iunlock(&tv->kfirlock); tv->gpiostate = Gpioinit;}static voidkfirreset(Tv *tv){ alterawrite(tv, 0, 0); microdelay(10); alterawrite(tv, 0x40000, 0); microdelay(10); alterawrite(tv, 0x40006, 0x80); microdelay(10); alterawrite(tv, 8, 1); microdelay(10); alterawrite(tv, 0x40004, 2); microdelay(10); alterawrite(tv, 4, 3); microdelay(3);}static intkfirinitialize(Tv *tv){ // Initialize parameters? tv->gpiostate = Gpioinit; tv->alterareg = -1; tv->alteraclock = 0x20000; kfirloadu(tv, hcwAMC, sizeof hcwAMC); kfirreset(tv); return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -