kern/73669: /sys/dev/bktr could support Pinnacle PCTV Rave cards,
if certain patches are applied
Arne Wörner
arne_woerner at yahoo.com
Mon Nov 8 04:10:33 PST 2004
>Number: 73669
>Category: kern
>Synopsis: /sys/dev/bktr could support Pinnacle PCTV Rave cards, if certain patches are applied
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: change-request
>Submitter-Id: current-users
>Arrival-Date: Mon Nov 08 12:10:33 GMT 2004
>Closed-Date:
>Last-Modified:
>Originator: Arne Wörner
>Release: R5.3
>Organization:
>Environment:
FreeBSD neo.riddick.homeunix.org. 5.3-RELEASE FreeBSD 5.3-RELEASE #3: Sun Nov 7 02:50:30 UTC 2004 aw at neo.riddick.homeunix.org.:/usr/src/sys/i386/compile/RIDDICK i386
>Description:
Since 2003 there are patches, that make Pinnacle PCTV Raves cards supported (they have a different tuner (MT2032 not Brooktree)).
I would be glad, if somebody could apply them to 5.3-STABLE and 6.0-CURRENT and maybe even to 4-STABLE, before they get too outdated.
I feel, that the patched bktr driver works very well.
I looked through the source code, and I have found nothing suspicious.
And I am sorry, that I molested a committer (Watson (core); core sounded somehow like kernel committer to me)... I just forgot this change request mechanism...
>How-To-Repeat:
>Fix:
Applying
Branko Lankester <branko at euro.net>'s
patches (at least in R5.3 for bktr_card.h there is a problem, that has to be fixed manually)
diff -c .org/bktr_card.c ./bktr_card.c
*** .org/bktr_card.c Sat Feb 8 03:04:57 2003
--- ./bktr_card.c Fri Nov 7 00:30:20 2003
***************
*** 355,360 ****
--- 355,372 ----
{ 0x10000, 0, 0x10000, 0, 1 }, /* audio MUX values */
0x10f00 }, /* GPIO mask */
+ { CARD_PINNACLE_PCTV_RAVE, /* the card id */
+ "Pinnacle PCTV Rave", /* the 'name' */
+ NULL, /* the tuner */
+ 0, /* the tuner i2c address */
+ 0, /* dbx unknown */
+ 0,
+ 0,
+ 0, /* EEProm unknown */
+ 0, /* size unknown */
+ { 0x02, 0x01, 0x00, 0x0a, 1 }, /* audio MUX values */
+ 0x03000F }, /* GPIO mask */
+
};
struct bt848_card_sig bt848_card_signature[1]= {
***************
*** 554,559 ****
--- 566,572 ----
#define PCI_VENDOR_FLYVIDEO_2 0x1852
#define PCI_VENDOR_PINNACLE_ALT 0xBD11
#define PCI_VENDOR_IODATA 0x10fc
+ #define PCI_VENDOR_PINNACLE_NEW 0x11BD
#define MODEL_IODATA_GV_BCTV3_PCI 0x4020
***************
*** 696,701 ****
--- 709,729 ----
bktr->card.eepromSize = (u_char)(256 / EEPROMBLOCKSIZE);
goto checkTuner;
}
+
+ if (subsystem_vendor_id == PCI_VENDOR_PINNACLE_NEW) {
+ bktr->card = cards[ (card = CARD_PINNACLE_PCTV_RAVE) ];
+ bktr->card.eepromAddr = eeprom_i2c_address;
+ bktr->card.eepromSize = (u_char)(256 / EEPROMBLOCKSIZE);
+
+ TDA9887_init(bktr, 0);
+
+ /* look for a tuner */
+ tuner_i2c_address = locate_tuner_address( bktr );
+ printf( "%s: tuner @ %#x\n", bktr_name(bktr), tuner_i2c_address );
+ select_tuner( bktr, TUNER_MT2032 );
+
+ goto checkDBX;
+ }
/* Vendor is unknown. We will use the standard probe code */
/* which may not give best results */
diff -c .org/bktr_card.h ./bktr_card.h
*** .org/bktr_card.h Sat Feb 8 03:04:57 2003
--- ./bktr_card.h Thu Aug 28 23:36:45 2003
***************
*** 77,83 ****
#define CARD_LEADTEK 15
#define CARD_TERRATVPLUS 16
#define CARD_IO_BCTV3 17
! #define Bt848_MAX_CARD 18
#define CARD_IO_GV CARD_IO_BCTV2
--- 77,84 ----
#define CARD_LEADTEK 15
#define CARD_TERRATVPLUS 16
#define CARD_IO_BCTV3 17
! #define CARD_PINNACLE_PCTV_RAVE 18
! #define Bt848_MAX_CARD 19
#define CARD_IO_GV CARD_IO_BCTV2
diff -c .org/bktr_tuner.c ./bktr_tuner.c
*** .org/bktr_tuner.c Thu Oct 26 18:38:46 2000
--- ./bktr_tuner.c Fri Aug 29 00:16:29 2003
***************
*** 137,142 ****
--- 137,146 ----
#define TSBH1_FCONTROL 0xce
+ static void mt2032_set_tv_freq(bktr_ptr_t bktr, unsigned int freq);
+ static int mt2032_init(bktr_ptr_t bktr);
+
+
static const struct TUNER tuners[] = {
/* XXX FIXME: fill in the band-switch crosspoints */
/* NO_TUNER */
***************
*** 277,283 ****
TSBH1_FCONTROL,
0x00 },
{ 0x00, 0x00 }, /* band-switch crosspoints */
! { 0x01, 0x02, 0x08, 0x00 } } /* the band-switch values */
};
--- 281,297 ----
TSBH1_FCONTROL,
0x00 },
{ 0x00, 0x00 }, /* band-switch crosspoints */
! { 0x01, 0x02, 0x08, 0x00 } }, /* the band-switch values */
!
! /* MT2032 Microtune */
! { "MT2032", /* the 'name' */
! TTYPE_PAL, /* input type */
! { TSA552x_SCONTROL, /* control byte for Tuner PLL */
! TSA552x_SCONTROL,
! TSA552x_SCONTROL,
! 0x00 },
! { 0x00, 0x00 }, /* band-switch crosspoints */
! { 0xa0, 0x90, 0x30, 0x00 } }, /* the band-switch values */
};
***************
*** 711,716 ****
--- 725,733 ----
} else {
bktr->card.tuner = NULL;
}
+ if (tuner_type == TUNER_MT2032) {
+ mt2032_init(bktr);
+ }
}
/*
***************
*** 788,793 ****
--- 805,814 ----
if ( tuner == NULL )
return( -1 );
+ if (tuner == &tuners[TUNER_MT2032]) {
+ mt2032_set_tv_freq(bktr, frequency);
+ return 0;
+ }
if (type == TV_FREQUENCY) {
/*
* select the band based on frequency
***************
*** 975,980 ****
--- 996,1003 ----
* Get the Tuner status and signal strength
*/
int get_tuner_status( bktr_ptr_t bktr ) {
+ if (bktr->card.tuner == &tuners[TUNER_MT2032])
+ return 0;
return i2cRead( bktr, bktr->card.tuner_pllAddr + 1 );
}
***************
*** 1013,1016 ****
--- 1036,1409 ----
chnlset->max_channel=freqTable[chnlset->index].ptr[0];
return( 0 );
+ }
+
+
+
+
+ #define TDA9887_ADDR 0x86
+
+ int
+ TDA9887_init(bktr_ptr_t bktr, int output2_enable)
+ {
+ u_char addr = TDA9887_ADDR;
+ #if 0
+ char buf[8];
+
+ /* NOTE: these are PAL values */
+ buf[0] = 0; /* sub address */
+ buf[1] = 0x50; /* output port1 inactive */
+ buf[2] = 0x6e; /* tuner takeover point / de-emphasis */
+ buf[3] = 0x09; /* fVIF = 38.9 MHz, fFM = 5.5 MHz */
+
+ if (!output2_enable)
+ buf[1] |= 0x80;
+
+ if (i2cWriteBuf(bktr, addr, 4, buf) == -1) {
+ printf("%s: TDA9887 write failed\n", bktr_name(bktr));
+ return -1;
+ }
+ #else
+ i2cWrite(bktr, addr, 0, output2_enable ? 0x50 : 0xd0);
+ i2cWrite(bktr, addr, 1, 0x6e);
+ i2cWrite(bktr, addr, 2, 0x09);
+ #endif
+ return 0;
+ }
+
+
+
+ #define MT2032_OPTIMIZE_VCO 1
+
+ /* holds the value of XOGC register after init */
+ static int MT2032_XOGC = 4;
+
+ /* card.tuner_pllAddr not set during init */
+ #define MT2032_ADDR 0xc0
+
+ #ifndef MT2032_ADDR
+ #define MT2032_ADDR (bktr->card.tuner_pllAddr)
+ #endif
+
+ static u_char
+ _MT2032_GetRegister(bktr_ptr_t bktr, u_char regNum)
+ {
+ int ch;
+
+ if (i2cWrite(bktr, MT2032_ADDR, regNum, -1) == -1) {
+ printf("%s: MT2032 write failed (i2c addr %#x)\n",
+ bktr_name(bktr), MT2032_ADDR);
+ }
+ if ((ch = i2cRead(bktr, MT2032_ADDR + 1)) == -1) {
+ printf("%s: MT2032 get register %d failed\n",
+ bktr_name(bktr), regNum);
+ return 0;
+ }
+ return ch;
+ }
+
+ static void
+ _MT2032_SetRegister(bktr_ptr_t bktr, u_char regNum, u_char data)
+ {
+ i2cWrite(bktr, MT2032_ADDR, regNum, data);
+ }
+
+ #define MT2032_GetRegister(r) _MT2032_GetRegister(bktr,r)
+ #define MT2032_SetRegister(r,d) _MT2032_SetRegister(bktr,r,d)
+
+
+ static int
+ mt2032_init(bktr_ptr_t bktr)
+ {
+ u_char rdbuf[22];
+ int xogc, xok = 0;
+ int i;
+
+ TDA9887_init(bktr, 0);
+
+ for (i = 0; i < 21; i++)
+ rdbuf[i] = MT2032_GetRegister(i);
+
+ printf("%s: MT2032: Companycode=%02x%02x Part=%02x Revision=%02x\n",
+ bktr_name(bktr),
+ rdbuf[0x11], rdbuf[0x12], rdbuf[0x13], rdbuf[0x14]);
+
+ /* Initialize Registers per spec. */
+ MT2032_SetRegister(2, 0xff);
+ MT2032_SetRegister(3, 0x0f);
+ MT2032_SetRegister(4, 0x1f);
+ MT2032_SetRegister(6, 0xe4);
+ MT2032_SetRegister(7, 0x8f);
+ MT2032_SetRegister(8, 0xc3);
+ MT2032_SetRegister(9, 0x4e);
+ MT2032_SetRegister(10, 0xec);
+ MT2032_SetRegister(13, 0x32);
+
+ /* Adjust XOGC (register 7), wait for XOK */
+ xogc = 7;
+ do {
+ DELAY(10000);
+ xok = MT2032_GetRegister(0x0e) & 0x01;
+ if (xok == 1) {
+ break;
+ }
+ xogc--;
+ if (xogc == 3) {
+ xogc = 4; /* min. 4 per spec */
+ break;
+ }
+ MT2032_SetRegister(7, 0x88 + xogc);
+ } while (xok != 1);
+
+ TDA9887_init(bktr, 1);
+
+ MT2032_XOGC = xogc;
+
+ return 0;
+ }
+
+ static int
+ MT2032_SpurCheck(int f1, int f2, int spectrum_from, int spectrum_to)
+ {
+ int n1 = 1, n2, f;
+
+ f1 = f1 / 1000; /* scale to kHz to avoid 32bit overflows */
+ f2 = f2 / 1000;
+ spectrum_from /= 1000;
+ spectrum_to /= 1000;
+
+ do {
+ n2 = -n1;
+ f = n1 * (f1 - f2);
+ do {
+ n2--;
+ f = f - f2;
+ if ((f > spectrum_from) && (f < spectrum_to)) {
+ return 1;
+ }
+ } while ((f > (f2 - spectrum_to)) || (n2 > -5));
+ n1++;
+ } while (n1 < 5);
+
+ return 0;
+ }
+
+ static int
+ MT2032_ComputeFreq(
+ int rfin,
+ int if1,
+ int if2,
+ int spectrum_from,
+ int spectrum_to,
+ unsigned char *buf,
+ int *ret_sel,
+ int xogc
+ )
+ { /* all in Hz */
+ int fref, lo1, lo1n, lo1a, s, sel;
+ int lo1freq, desired_lo1, desired_lo2, lo2, lo2n, lo2a,
+ lo2num, lo2freq;
+ int nLO1adjust;
+
+ fref = 5250 * 1000; /* 5.25MHz */
+
+ /* per spec 2.3.1 */
+ desired_lo1 = rfin + if1;
+ lo1 = (2 * (desired_lo1 / 1000) + (fref / 1000)) / (2 * fref / 1000);
+ lo1freq = lo1 * fref;
+ desired_lo2 = lo1freq - rfin - if2;
+
+ /* per spec 2.3.2 */
+ for (nLO1adjust = 1; nLO1adjust < 3; nLO1adjust++) {
+ if (!MT2032_SpurCheck(lo1freq, desired_lo2, spectrum_from, spectrum_to)) {
+ break;
+ }
+ if (lo1freq < desired_lo1) {
+ lo1 += nLO1adjust;
+ } else {
+ lo1 -= nLO1adjust;
+ }
+
+ lo1freq = lo1 * fref;
+ desired_lo2 = lo1freq - rfin - if2;
+ }
+
+ /* per spec 2.3.3 */
+ s = lo1freq / 1000 / 1000;
+
+ if (MT2032_OPTIMIZE_VCO) {
+ if (s > 1890) {
+ sel = 0;
+ } else if (s > 1720) {
+ sel = 1;
+ } else if (s > 1530) {
+ sel = 2;
+ } else if (s > 1370) {
+ sel = 3;
+ } else {
+ sel = 4;/* >1090 */
+ }
+ } else {
+ if (s > 1790) {
+ sel = 0;/* <1958 */
+ } else if (s > 1617) {
+ sel = 1;
+ } else if (s > 1449) {
+ sel = 2;
+ } else if (s > 1291) {
+ sel = 3;
+ } else {
+ sel = 4;/* >1090 */
+ }
+ }
+
+ *ret_sel = sel;
+
+ /* per spec 2.3.4 */
+ lo1n = lo1 / 8;
+ lo1a = lo1 - (lo1n * 8);
+ lo2 = desired_lo2 / fref;
+ lo2n = lo2 / 8;
+ lo2a = lo2 - (lo2n * 8);
+ /* scale to fit in 32bit arith */
+ lo2num = ((desired_lo2 / 1000) % (fref / 1000)) * 3780 / (fref / 1000);
+ lo2freq = (lo2a + 8 * lo2n) * fref + lo2num * (fref / 1000) / 3780 * 1000;
+
+ if (lo1a < 0 || lo1a > 7 || lo1n < 17 || lo1n > 48 || lo2a < 0 ||
+ lo2a > 7 || lo2n < 17 || lo2n > 30) {
+ printf("MT2032: parameter out of range\n");
+ return -1;
+ }
+ /* set up MT2032 register map for transfer over i2c */
+ buf[0] = lo1n - 1;
+ buf[1] = lo1a | (sel << 4);
+ buf[2] = 0x86; /* LOGC */
+ buf[3] = 0x0f; /* reserved */
+ buf[4] = 0x1f;
+ buf[5] = (lo2n - 1) | (lo2a << 5);
+ if (rfin < 400 * 1000 * 1000) {
+ buf[6] = 0xe4;
+ } else {
+ buf[6] = 0xf4; /* set PKEN per rev 1.2 */
+ }
+
+ buf[7] = 8 + xogc;
+ buf[8] = 0xc3; /* reserved */
+ buf[9] = 0x4e; /* reserved */
+ buf[10] = 0xec; /* reserved */
+ buf[11] = (lo2num & 0xff);
+ buf[12] = (lo2num >> 8) | 0x80; /* Lo2RST */
+
+ return 0;
+ }
+
+ static int
+ MT2032_CheckLOLock(bktr_ptr_t bktr)
+ {
+ int t, lock = 0;
+ for (t = 0; t < 10; t++) {
+ lock = MT2032_GetRegister(0x0e) & 0x06;
+ if (lock == 6) {
+ break;
+ }
+ DELAY(1000);
+ }
+ return lock;
+ }
+
+ static int
+ MT2032_OptimizeVCO(bktr_ptr_t bktr, int sel, int lock)
+ {
+ int tad1, lo1a;
+
+ tad1 = MT2032_GetRegister(0x0f) & 0x07;
+
+ if (tad1 == 0) {
+ return lock;
+ }
+ if (tad1 == 1) {
+ return lock;
+ }
+ if (tad1 == 2) {
+ if (sel == 0) {
+ return lock;
+ } else {
+ sel--;
+ }
+ } else {
+ if (sel < 4) {
+ sel++;
+ } else {
+ return lock;
+ }
+ }
+ lo1a = MT2032_GetRegister(0x01) & 0x07;
+ MT2032_SetRegister(0x01, lo1a | (sel << 4));
+ lock = MT2032_CheckLOLock(bktr);
+ return lock;
+ }
+
+ static int
+ MT2032_SetIFFreq(bktr_ptr_t bktr, int rfin, int if1, int if2, int from, int to)
+ {
+ u_char buf[21];
+ int lint_try, sel, lock = 0;
+
+ if (MT2032_ComputeFreq(rfin, if1, if2, from, to, &buf[0], &sel, MT2032_XOGC) == -1)
+ return -1;
+
+ TDA9887_init(bktr, 0);
+
+ printf("%s: MT2032-SetIFFreq: 0x%02X%02X%02X%02X...\n",
+ bktr_name(bktr),
+ buf[0x00], buf[0x01], buf[0x02], buf[0x03]);
+
+ /* send only the relevant registers per Rev. 1.2 */
+ MT2032_SetRegister(0, buf[0x00]);
+ MT2032_SetRegister(1, buf[0x01]);
+ MT2032_SetRegister(2, buf[0x02]);
+
+ MT2032_SetRegister(5, buf[0x05]);
+ MT2032_SetRegister(6, buf[0x06]);
+ MT2032_SetRegister(7, buf[0x07]);
+
+ MT2032_SetRegister(11, buf[0x0B]);
+ MT2032_SetRegister(12, buf[0x0C]);
+
+ /* wait for PLLs to lock (per manual), retry LINT if not. */
+ for (lint_try = 0; lint_try < 2; lint_try++) {
+ lock = MT2032_CheckLOLock(bktr);
+
+ if (MT2032_OPTIMIZE_VCO) {
+ lock = MT2032_OptimizeVCO(bktr, sel, lock);
+ }
+ if (lock == 6) {
+ break;
+ }
+ /* set LINT to re-init PLLs */
+ MT2032_SetRegister(7, 0x80 + 8 + MT2032_XOGC);
+ DELAY(10000);
+ MT2032_SetRegister(7, 8 + MT2032_XOGC);
+ }
+ if (lock != 6)
+ printf("%s: PLL didn't lock\n", bktr_name(bktr));
+
+ MT2032_SetRegister(2, 0x20);
+
+ TDA9887_init(bktr, 1);
+ return 0;
+ }
+
+ static void
+ mt2032_set_tv_freq(bktr_ptr_t bktr, unsigned int freq)
+ {
+ int if2,from,to;
+
+ from=32900*1000;
+ to=39900*1000;
+ if2=38900*1000;
+
+ printf("%s: setting frequency to %d\n", bktr_name(bktr), freq*62500);
+ MT2032_SetIFFreq(bktr, freq*62500 /* freq*1000*1000/16 */,
+ 1090*1000*1000, if2, from, to);
}
diff -c .org/bktr_tuner.h ./bktr_tuner.h
*** .org/bktr_tuner.h Mon Sep 27 00:06:20 1999
--- ./bktr_tuner.h Thu Aug 28 23:34:20 2003
***************
*** 59,65 ****
#define PHILIPS_FR1236_SECAM 11 /* These have FM radio support */
#define ALPS_TSCH5 12
#define ALPS_TSBH1 13
! #define Bt848_MAX_TUNER 14
/* experimental code for Automatic Frequency Control */
#define TUNER_AFC
--- 59,66 ----
#define PHILIPS_FR1236_SECAM 11 /* These have FM radio support */
#define ALPS_TSCH5 12
#define ALPS_TSBH1 13
! #define TUNER_MT2032 14
! #define Bt848_MAX_TUNER 15
/* experimental code for Automatic Frequency Control */
#define TUNER_AFC
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list