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)