From cf784d554fdb94f21671830135dba56b507126cf Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Sat, 21 Jul 2007 21:26:40 -0300 Subject: V4L/DVB (5899): bttv: Fix Viewcast Osprey 440 support Various gpio and mux settings for the Osprey 440 weren't correct. Fix them and provide some documentation about how the gpios work. The osprey eeprom routine wasn't run for the 440, add it. It was also crap, re-written to be better. Add the Osprey 440 to the Bt878 ALSA driver's whitelist. Currently the sample rate is fixed at 32kHz, as the driver doesn't support different rates for digital input mode, though the card can select the rate from 32, 44.1, or 48 kHz via gpio. Setting the audio gain via ALSA isn't supported yet; a userspace tool that programs the X9221 via i2c-dev must be used. The Bt878 digital audio format isn't programmed correctly for the CS5331A ADC used, resulting in extremely garbled sound. That is fixed in a followup patch. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-cards.c | 238 +++++++++++++++++++-------------- 1 file changed, 134 insertions(+), 104 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 387cb2122d4f..f6715007d409 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -33,6 +33,7 @@ #include #include #include +#include #include @@ -45,7 +46,7 @@ static void boot_msp34xx(struct bttv *btv, int pin); static void boot_bt832(struct bttv *btv); static void hauppauge_eeprom(struct bttv *btv); static void avermedia_eeprom(struct bttv *btv); -static void osprey_eeprom(struct bttv *btv); +static void osprey_eeprom(struct bttv *btv, const u8 ee[256]); static void modtec_eeprom(struct bttv *btv); static void init_PXC200(struct bttv *btv); static void init_RTV24(struct bttv *btv); @@ -2843,13 +2844,28 @@ struct tvcard bttv_tvcards[] = { .has_remote = 1, }, /* ---- card 0x8c ---------------------------------- */ + /* Has four Bt878 chips behind a PCI bridge, each chip has: + one external BNC composite input (mux 2) + three internal composite inputs (unknown muxes) + an 18-bit stereo A/D (CS5331A), which has: + one external stereo unblanced (RCA) audio connection + one (or 3?) internal stereo balanced (XLR) audio connection + input is selected via gpio to a 14052B mux + (mask=0x300, unbal=0x000, bal=0x100, ??=0x200,0x300) + gain is controlled via an X9221A chip on the I2C bus @0x28 + sample rate is controlled via gpio to an MK1413S + (mask=0x3, 32kHz=0x0, 44.1kHz=0x1, 48kHz=0x2, ??=0x3) + There is neither a tuner nor an svideo input. */ [BTTV_BOARD_OSPREY440] = { .name = "Osprey 440", - .video_inputs = 1, - .audio_inputs = 1, + .video_inputs = 4, + .audio_inputs = 2, /* this is meaningless */ .tuner = UNSET, - .svhs = 1, - .muxsel = { 2 }, + .svhs = UNSET, + .muxsel = { 2, 3, 0, 1 }, /* 3,0,1 are guesses */ + .gpiomask = 0x303, + .gpiomute = 0x000, /* int + 32kHz */ + .gpiomux = { 0, 0, 0x000, 0x100}, .pll = PLL_28, .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, @@ -3453,11 +3469,12 @@ void __devinit bttv_init_card2(struct bttv *btv) case BTTV_BOARD_OSPREY2xx: case BTTV_BOARD_OSPREY2x0_SVID: case BTTV_BOARD_OSPREY2x0: + case BTTV_BOARD_OSPREY440: case BTTV_BOARD_OSPREY500: case BTTV_BOARD_OSPREY540: case BTTV_BOARD_OSPREY2000: bttv_readee(btv,eeprom_data,0xa0); - osprey_eeprom(btv); + osprey_eeprom(btv, eeprom_data); break; case BTTV_BOARD_IDS_EAGLE: init_ids_eagle(btv); @@ -3748,106 +3765,119 @@ static int __devinit pvr_boot(struct bttv *btv) /* ----------------------------------------------------------------------- */ /* some osprey specific stuff */ -static void __devinit osprey_eeprom(struct bttv *btv) +static void __devinit osprey_eeprom(struct bttv *btv, const u8 ee[256]) { - int i = 0; - unsigned char *ee = eeprom_data; - unsigned long serial = 0; - - if (btv->c.type == 0) { - /* this might be an antique... check for MMAC label in eeprom */ - if ((ee[0]=='M') && (ee[1]=='M') && (ee[2]=='A') && (ee[3]=='C')) { - unsigned char checksum = 0; - for (i = 0; i < 21; i++) - checksum += ee[i]; - if (checksum != ee[21]) - return; - btv->c.type = BTTV_BOARD_OSPREY1x0_848; - for (i = 12; i < 21; i++) - serial *= 10, serial += ee[i] - '0'; - } + int i; + u32 serial = 0; + int cardid = -1; + + /* This code will nevery actually get called in this case.... */ + if (btv->c.type == BTTV_BOARD_UNKNOWN) { + /* this might be an antique... check for MMAC label in eeprom */ + if (!strncmp(ee, "MMAC", 4)) { + u8 checksum = 0; + for (i = 0; i < 21; i++) + checksum += ee[i]; + if (checksum != ee[21]) + return; + cardid = BTTV_BOARD_OSPREY1x0_848; + for (i = 12; i < 21; i++) + serial *= 10, serial += ee[i] - '0'; + } } else { - unsigned short type; - int offset = 4*16; - - for (; offset < 8*16; offset += 16) { - unsigned short checksum = 0; - /* verify the checksum */ - for (i = 0; i < 14; i++) - checksum += ee[i+offset]; - checksum = ~checksum; /* no idea why */ - if ((((checksum>>8)&0x0FF) == ee[offset+14]) && - ((checksum & 0x0FF) == ee[offset+15])) { - break; - } - } - - if (offset >= 8*16) - return; - - /* found a valid descriptor */ - type = (ee[offset+4]<<8) | (ee[offset+5]); - - switch(type) { - /* 848 based */ - case 0x0004: - btv->c.type = BTTV_BOARD_OSPREY1x0_848; - break; - case 0x0005: - btv->c.type = BTTV_BOARD_OSPREY101_848; - break; - - /* 878 based */ - case 0x0012: - case 0x0013: - btv->c.type = BTTV_BOARD_OSPREY1x0; - break; - case 0x0014: - case 0x0015: - btv->c.type = BTTV_BOARD_OSPREY1x1; - break; - case 0x0016: - case 0x0017: - case 0x0020: - btv->c.type = BTTV_BOARD_OSPREY1x1_SVID; - break; - case 0x0018: - case 0x0019: - case 0x001E: - case 0x001F: - btv->c.type = BTTV_BOARD_OSPREY2xx; - break; - case 0x001A: - case 0x001B: - btv->c.type = BTTV_BOARD_OSPREY2x0_SVID; - break; - case 0x0040: - btv->c.type = BTTV_BOARD_OSPREY500; - break; - case 0x0050: - case 0x0056: - btv->c.type = BTTV_BOARD_OSPREY540; - /* bttv_osprey_540_init(btv); */ - break; - case 0x0060: - case 0x0070: - case 0x00A0: - btv->c.type = BTTV_BOARD_OSPREY2x0; - /* enable output on select control lines */ - gpio_inout(0xffffff,0x000303); - break; - default: - /* unknown...leave generic, but get serial # */ - break; - } - serial = (ee[offset+6] << 24) - | (ee[offset+7] << 16) - | (ee[offset+8] << 8) - | (ee[offset+9]); - } - - printk(KERN_INFO "bttv%d: osprey eeprom: card=%d name=%s serial=%ld\n", - btv->c.nr, btv->c.type, bttv_tvcards[btv->c.type].name,serial); + unsigned short type; + + for (i = 4*16; i < 8*16; i += 16) { + u16 checksum = ip_compute_csum(ee + i, 16); + + if ((checksum&0xff) + (checksum>>8) == 0xff) + break; + } + if (i >= 8*16) + return; + ee += i; + + /* found a valid descriptor */ + type = be16_to_cpup((u16*)(ee+4)); + + switch(type) { + /* 848 based */ + case 0x0004: + cardid = BTTV_BOARD_OSPREY1x0_848; + break; + case 0x0005: + cardid = BTTV_BOARD_OSPREY101_848; + break; + + /* 878 based */ + case 0x0012: + case 0x0013: + cardid = BTTV_BOARD_OSPREY1x0; + break; + case 0x0014: + case 0x0015: + cardid = BTTV_BOARD_OSPREY1x1; + break; + case 0x0016: + case 0x0017: + case 0x0020: + cardid = BTTV_BOARD_OSPREY1x1_SVID; + break; + case 0x0018: + case 0x0019: + case 0x001E: + case 0x001F: + cardid = BTTV_BOARD_OSPREY2xx; + break; + case 0x001A: + case 0x001B: + cardid = BTTV_BOARD_OSPREY2x0_SVID; + break; + case 0x0040: + cardid = BTTV_BOARD_OSPREY500; + break; + case 0x0050: + case 0x0056: + cardid = BTTV_BOARD_OSPREY540; + /* bttv_osprey_540_init(btv); */ + break; + case 0x0060: + case 0x0070: + case 0x00A0: + cardid = BTTV_BOARD_OSPREY2x0; + /* enable output on select control lines */ + gpio_inout(0xffffff,0x000303); + break; + case 0x00D8: + cardid = BTTV_BOARD_OSPREY440; + break; + default: + /* unknown...leave generic, but get serial # */ + printk(KERN_INFO "bttv%d: " + "osprey eeprom: unknown card type 0x%04x\n", + btv->c.nr, type); + break; + } + serial = be32_to_cpup((u32*)(ee+6)); + } + + printk(KERN_INFO "bttv%d: osprey eeprom: card=%d '%s' serial=%u\n", + btv->c.nr, cardid, + cardid>0 ? bttv_tvcards[cardid].name : "Unknown", serial); + + if (cardid<0 || btv->c.type == cardid) + return; + + /* card type isn't set correctly */ + if (card[btv->c.nr] < bttv_num_tvcards) { + printk(KERN_WARNING "bttv%d: osprey eeprom: " + "Not overriding user specified card type\n", btv->c.nr); + } else { + printk(KERN_INFO "bttv%d: osprey eeprom: " + "Changing card type from %d to %d\n", btv->c.nr, + btv->c.type, cardid); + btv->c.type = cardid; + } } /* ----------------------------------------------------------------------- */ -- cgit v1.2.3