AVerMedia Cardbus Plus E501R
Итак, стал я недавно обладателем сего чудного девайса =)
Ноутбук Benq Joybook 2100-r32. Debian unstable. Ядро 2.6.17.
Быстрый старт
Добавить опцию загрузки модуля saa7134:
options saa7134 card=46 tuner=12
В этом случае девайс определиться как AverMedia Cardbus E500.
Если Вы используете alsa, то не забудьте загрузить модуль saa7134-alsa, если oss - saa7134-oss.
Для того, чтобы поиметь звук в таких программах как tvtime нужно использовать SOX-redirect:
sox -c 2 -s -w -r 32000 -t ossdsp /dev/dsp2 -t ossdsp -w -r 32000 /dev/dsp
Без лишних телодвижений можно получить звук в mplayer'е, например вот так (для alsa):
mplayer -vo xv -ao alsa -tv driver=v4l2:device=/dev/video0:width=720:height=576:normid=1:chanlist=russia:\ immediatemode=0:alsa:adevice=hw.1,0:audiorate=32000:channels=<list_of_channels> tv://
Тестировал сей девайс, на версии ядра 2.6.16.34, работает все замечательно:
options saa7134 card=46 tuner=12 alsa=1 options tda9887 secam=d install saa7134 /sbin/modprobe tda9887; /sbin/modprobe --ignore-install saa7134; /sbin/modprobe saa7134-alsa && /usr/sbin/alsactl restore >/dev/null 2>&1 || : remove saa7134-alsa { /usr/sbin/alsactl store >/dev/null 2>&1 || : ; }; /sbin/modprobe -r --ignore-remove saa7134-alsa
все что перечислено ниже можно пропустить.
Делаем все как надо ;)
Редактируем драйвер ядра ;) В saa7134.h добавляем определение новой карточки:
#define SAA7134_BOARD_AVERMEDIA_CARDBUS_PLUS 85
Далее редактируем saa7134-card.c, добавляем определение устройства в структуру saa7134_boards:
[SAA7134_BOARD_AVERMEDIA_CARDBUS_PLUS] = { /* hayova@gmail.com */ .name = "AVerMedia Cardbus Plus", .audio_clock = 0x187de7, .tuner_type = TUNER_ALPS_TSBE5_PAL, .radio_type = TUNER_TEA5767, .tuner_addr = 0x61, .radio_addr = 0x60, .tda9887_conf = TDA9887_PRESENT, .gpiomask = 0x0C400003, .inputs = {{ .name = name_tv, .vmux = 1, .amux = TV, .tv = 1, .gpio = 0x0C400001, },{ .name = name_comp1, .vmux = 3, .amux = LINE1, .gpio = 0x0C400002, },{ .name = name_svideo, .vmux = 6, .amux = LINE1, .gpio = 0x0C400002, }}, .radio = { .name = name_radio, .amux = LINE2, .gpio = 0x04400001, },
В том же файле вносим изменения в структуру saa7134_pci_tbl:
/* AVerMedia CardBus Plus */ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, .subvendor = 0x1461, /* Avermedia Technologies Inc */ .subdevice = 0xb7e9, .driver_data = SAA7134_BOARD_AVERMEDIA_CARDBUS_PLUS, },{
И добавляем инициализацию устройства в функцию saa7134_board_init1:
case SAA7134_BOARD_AVERMEDIA_CARDBUS_PLUS: /* power-up tuner chip */ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x0C440003, 0x0C440003); saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0C400000, 0x0C400000); dev->has_remote = SAA7134_REMOTE_GPIO; msleep(1); break;
В файле saa7134-input.c вносим изменения в функцию saa7134_input_init1:
case SAA7134_BOARD_AVERMEDIA_CARDBUS_PLUS: ir_codes = ir_codes_gotview7135; mask_keycode = 0x0007C8; mask_keydown = 0x000010; polling = 50; // ms break;
Далее к saa7134-tvaudio.c применяем следующий патч (решает проблему со звуком в SECAM):
--- linux-2.6.18-rc1-mm1-build/drivers/media/video/saa7134/saa7134-tvaudio.c.old 2006-05-13 23:29:35.000000000 +0400 +++ linux-2.6.18-rc1-mm1-build/drivers/media/video/saa7134/saa7134-tvaudio.c 2006-07-12 04:22:01.000000000 +0400 @@ -50,6 +50,14 @@ module_param(audio_clock_tweak, int, 0644); MODULE_PARM_DESC(audio_clock_tweak, "Audio clock tick fine tuning for cards with audio crystal that's slightly off (range [-1024 .. 1024])"); +static char pal[] = "--"; +static char secam[] = "--"; +static char ntsc[] = "-"; + +module_param_string(pal, pal, sizeof(pal), 0644); +module_param_string(secam, secam, sizeof(secam), 0644); +module_param_string(ntsc, ntsc, sizeof(ntsc), 0644); + #define dprintk(fmt, arg...) if (audio_debug) \ printk(KERN_DEBUG "%s/audio: " fmt, dev->name , ## arg) #define d2printk(fmt, arg...) if (audio_debug > 1) \ @@ -93,61 +101,61 @@ static struct saa7134_tvaudio tvaudio[] = { { .name = "PAL-B/G FM-stereo", - .std = V4L2_STD_PAL, + .std = V4L2_STD_PAL_BG, .mode = TVAUDIO_FM_BG_STEREO, .carr1 = 5500, .carr2 = 5742, },{ .name = "PAL-D/K1 FM-stereo", - .std = V4L2_STD_PAL, + .std = V4L2_STD_PAL_DK, .carr1 = 6500, .carr2 = 6258, .mode = TVAUDIO_FM_BG_STEREO, },{ .name = "PAL-D/K2 FM-stereo", - .std = V4L2_STD_PAL, + .std = V4L2_STD_PAL_DK, .carr1 = 6500, .carr2 = 6742, .mode = TVAUDIO_FM_BG_STEREO, },{ .name = "PAL-D/K3 FM-stereo", - .std = V4L2_STD_PAL, + .std = V4L2_STD_PAL_DK, .carr1 = 6500, .carr2 = 5742, .mode = TVAUDIO_FM_BG_STEREO, },{ .name = "PAL-B/G NICAM", - .std = V4L2_STD_PAL, + .std = V4L2_STD_PAL_BG, .carr1 = 5500, .carr2 = 5850, .mode = TVAUDIO_NICAM_FM, },{ .name = "PAL-I NICAM", - .std = V4L2_STD_PAL, + .std = V4L2_STD_PAL_I, .carr1 = 6000, .carr2 = 6552, .mode = TVAUDIO_NICAM_FM, },{ .name = "PAL-D/K NICAM", - .std = V4L2_STD_PAL, + .std = V4L2_STD_PAL_DK, .carr1 = 6500, .carr2 = 5850, .mode = TVAUDIO_NICAM_FM, },{ .name = "SECAM-L NICAM", - .std = V4L2_STD_SECAM, + .std = V4L2_STD_SECAM_L, .carr1 = 6500, .carr2 = 5850, .mode = TVAUDIO_NICAM_AM, },{ .name = "SECAM-L MONO", - .std = V4L2_STD_SECAM, + .std = V4L2_STD_SECAM_L, .carr1 = 6500, .carr2 = -1, .mode = TVAUDIO_AM_MONO, },{ .name = "SECAM-D/K", - .std = V4L2_STD_SECAM, + .std = V4L2_STD_SECAM_DK, .carr1 = 6500, .carr2 = -1, .mode = TVAUDIO_FM_MONO, @@ -514,6 +522,119 @@ return 0; } +/* get more precise norm info from insmod option */ +static int saa7134_fixup_std(struct saa7134_dev *dev) +{ + struct saa7134_tvnorm *t = dev->tvnorm; + if ((t->id & V4L2_STD_PAL) == V4L2_STD_PAL) { + switch (pal[0]) { + case 'b': + case 'B': + case 'g': + case 'G': + dprintk ("insmod fixup: PAL => PAL-BG\n"); + t->id = V4L2_STD_PAL_BG; + break; + case 'i': + case 'I': + dprintk ("insmod fixup: PAL => PAL-I\n"); + t->id = V4L2_STD_PAL_I; + break; + case 'd': + case 'D': + case 'k': + case 'K': + dprintk ("insmod fixup: PAL => PAL-DK\n"); + t->id = V4L2_STD_PAL_DK; + break; + case 'M': + case 'm': + dprintk ("insmod fixup: PAL => PAL-M\n"); + t->id = V4L2_STD_PAL_M; + break; + case 'N': + case 'n': + if (pal[1] == 'c' || pal[1] == 'C') { + dprintk("insmod fixup: PAL => PAL-Nc\n"); + t->id = V4L2_STD_PAL_Nc; + } else { + dprintk ("insmod fixup: PAL => PAL-N\n"); + t->id = V4L2_STD_PAL_N; + } + break; + case '-': + /* default parameter, do nothing */ + break; + default: + dprintk ("pal= argument not recognised\n"); + break; + } + } + if ((t->id & V4L2_STD_SECAM) == V4L2_STD_SECAM) { + switch (secam[0]) { + case 'b': + case 'B': + case 'g': + case 'G': + case 'h': + case 'H': + dprintk("insmod fixup: SECAM => SECAM-BGH\n"); + t->id = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H; + break; + case 'd': + case 'D': + case 'k': + case 'K': + dprintk ("insmod fixup: SECAM => SECAM-DK\n"); + t->id = V4L2_STD_SECAM_DK; + break; + case 'l': + case 'L': + if ((secam[1]=='C')||(secam[1]=='c')) { + dprintk ("insmod fixup: SECAM => SECAM-L'\n"); + t->id = V4L2_STD_SECAM_LC; + } else { + dprintk ("insmod fixup: SECAM => SECAM-L\n"); + t->id = V4L2_STD_SECAM_L; + } + break; + case '-': + /* default parameter, do nothing */ + break; + default: + dprintk ("secam= argument not recognised\n"); + break; + } + } + + if ((t->id & V4L2_STD_NTSC) == V4L2_STD_NTSC) { + switch (ntsc[0]) { + case 'm': + case 'M': + dprintk("insmod fixup: NTSC => NTSC-M\n"); + t->id = V4L2_STD_NTSC_M; + break; + case 'j': + case 'J': + dprintk("insmod fixup: NTSC => NTSC_M_JP\n"); + t->id = V4L2_STD_NTSC_M_JP; + break; + case 'k': + case 'K': + dprintk("insmod fixup: NTSC => NTSC_M_KR\n"); + t->id = V4L2_STD_NTSC_M_KR; + break; + case '-': + /* default parameter, do nothing */ + break; + default: + dprintk("ntsc= argument not recognised\n"); + break; + } + } + return 0; +} + static int tvaudio_thread(void *data) { struct saa7134_dev *dev = data; @@ -605,6 +726,7 @@ saa7134_tvaudio_setmute(dev); /* find the exact tv audio norm */ + saa7134_fixup_std(dev); for (audio = UNSET, i = 0; i < TVAUDIO; i++) { if (dev->tvnorm->id != UNSET && !(dev->tvnorm->id & tvaudio[i].std))
Потом в файле tuner-core.c вносим изменения в функцию tuner_attach:
if (!no_autodetect) { switch (addr) { case 0x42: case 0x43: case 0x4a: case 0x4b: /* If chip is not tda8290, don't register. since it can be tda9887*/ if (tda8290_probe(&t->i2c) == 0) { tuner_dbg("chip at addr %x is a tda8290\n", addr); } else { /* Default is being tda9887 */ t->type = TUNER_TDA9887; t->mode_mask = T_ANALOG_TV; t->mode = T_STANDBY; goto register_client; } break; case 0x60: //if (tea5767_autodetection(&t->i2c) != EINVAL) { t->type = TUNER_TEA5767; t->mode_mask = T_RADIO; t->mode = T_STANDBY; t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */ default_mode_mask &= ~T_RADIO; goto register_client; //} break; case 0x61: t->type = TUNER_ALPS_TSBE5_PAL; t->mode_mask = T_ANALOG_TV; t->mode = T_STANDBY; goto register_client; break; } }
Проблемы
1. все также не работает радио и пульт :(
И еще, данные, полученные при установленной опции i2c_scan=1 модуля saa7134:
saa7134[0]: i2c scan: found device @ 0x80 [???] -- возможно IR (???) saa7134[0]: i2c scan: found device @ 0x84 [???] -- некая разновидность TDA9887 (???) saa7134[0]: i2c scan: found device @ 0xa0 [eeprom] saa7134[0]: i2c scan: found device @ 0xc0 [tuner (analog)] -- тюнер TEA5767 saa7134[0]: i2c scan: found device @ 0xc2 [???] -- тюнер ALPS TSEZ1
Кроме того, я отписался на список рассылки v4l, там же можно найти больше логов, если кого-нибудь заинтересует.
Пожалуйста поправляйте/добавляйте.
--Hayova 13:09, 18 June 2006 (CEST)