📄 saa7134-tvaudio.c
字号:
/* find the main carrier */ carr_scan = carr_default; if (dev->tvnorm->id & V4L2_STD_PAL) carr_scan = carr_pal; if (dev->tvnorm->id & V4L2_STD_NTSC) carr_scan = carr_ntsc; if (dev->tvnorm->id & V4L2_STD_SECAM) carr_scan = carr_secam; saa_writeb(SAA7134_MONITOR_SELECT,0x00); tvaudio_setmode(dev,&tvaudio[0],NULL); for (i = 0; i < MAX_SCAN; i++) { if (!carr_scan[i]) continue; carr_vals[i] = tvaudio_checkcarrier(dev,carr_scan[i]); if (dev->thread.scan1 != dev->thread.scan2) goto restart; } for (carrier = 0, max1 = 0, max2 = 0, i = 0; i < MAX_SCAN; i++) { if (!carr_scan[i]) continue; if (max1 < carr_vals[i]) { max2 = max1; max1 = carr_vals[i]; carrier = carr_scan[i]; } else if (max2 < carr_vals[i]) { max2 = carr_vals[i]; } } if (0 != carrier && max1 > 2000 && max1 > max2*3) { /* found good carrier */ dprintk("found %s main sound carrier @ %d.%03d MHz [%d/%d]\n", dev->tvnorm->name, carrier/1000, carrier%1000, max1, max2); dev->last_carrier = carrier; } else if (0 != audio_carrier) { /* no carrier -- try insmod option as fallback */ carrier = audio_carrier; printk(KERN_WARNING "%s/audio: audio carrier scan failed, " "using %d.%03d MHz [insmod option]\n", dev->name, carrier/1000, carrier%1000); } else if (0 != dev->last_carrier) { /* no carrier -- try last detected one as fallback */ carrier = dev->last_carrier; printk(KERN_WARNING "%s/audio: audio carrier scan failed, " "using %d.%03d MHz [last detected]\n", dev->name, carrier/1000, carrier%1000); } else { /* no carrier + no fallback -- try first in list */ carrier = carr_scan[0]; printk(KERN_WARNING "%s/audio: audio carrier scan failed, " "using %d.%03d MHz [default]\n", dev->name, carrier/1000, carrier%1000); } tvaudio_setcarrier(dev,carrier,carrier); dev->automute = 0; saa_andorb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0x30, 0x00); saa7134_tvaudio_setmute(dev); /* find the exact tv audio norm */ for (audio = UNSET, i = 0; i < TVAUDIO; i++) { if (dev->tvnorm->id != UNSET && dev->tvnorm->id != tvaudio[i].std) continue; if (tvaudio[i].carr1 != carrier) continue; if (UNSET == audio) audio = i; tvaudio_setmode(dev,&tvaudio[i],"trying"); if (tvaudio_sleep(dev,HZ*2)) goto restart; if (-1 != tvaudio_getstereo(dev,&tvaudio[i])) { audio = i; break; } } saa_andorb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0x30, 0x30); if (UNSET == audio) continue; tvaudio_setmode(dev,&tvaudio[audio],"using"); tvaudio_setstereo(dev,&tvaudio[audio],V4L2_TUNER_MODE_MONO); dev->tvaudio = &tvaudio[audio]; for (;;) { if (tvaudio_sleep(dev,3*HZ)) goto restart; if (dev->thread.exit || signal_pending(current)) break; if (UNSET == dev->thread.mode) { rx = tvaudio_getstereo(dev,&tvaudio[i]); mode = saa7134_tvaudio_rx2mode(rx); } else { mode = dev->thread.mode; } tvaudio_setstereo(dev,&tvaudio[audio],mode); } } done: dev->thread.task = NULL; if(dev->thread.notify != NULL) up(dev->thread.notify); return 0;}/* ------------------------------------------------------------------ *//* saa7133 / saa7135 code */static char *stdres[0x20] = { [0x00] = "no standard detected", [0x01] = "B/G (in progress)", [0x02] = "D/K (in progress)", [0x03] = "M (in progress)", [0x04] = "B/G A2", [0x05] = "B/G NICAM", [0x06] = "D/K A2 (1)", [0x07] = "D/K A2 (2)", [0x08] = "D/K A2 (3)", [0x09] = "D/K NICAM", [0x0a] = "L NICAM", [0x0b] = "I NICAM", [0x0c] = "M Korea", [0x0d] = "M BTSC ", [0x0e] = "M EIAJ", [0x0f] = "FM radio / IF 10.7 / 50 deemp", [0x10] = "FM radio / IF 10.7 / 75 deemp", [0x11] = "FM radio / IF sel / 50 deemp", [0x12] = "FM radio / IF sel / 75 deemp", [0x13 ... 0x1e ] = "unknown", [0x1f] = "??? [in progress]",};#define DSP_RETRY 30#define DSP_DELAY 10static inline int saa_dsp_wait_bit(struct saa7134_dev *dev, int bit){ int state, count = DSP_RETRY; state = saa_readb(SAA7135_DSP_RWSTATE); if (unlikely(state & SAA7135_DSP_RWSTATE_ERR)) { printk("%s: dsp access error\n",dev->name); /* FIXME: send ack ... */ return -EIO; } while (0 == (state & bit)) { if (unlikely(0 == count)) { printk("%s: dsp access wait timeout [bit=%s]\n", dev->name, (bit & SAA7135_DSP_RWSTATE_WRR) ? "WRR" : (bit & SAA7135_DSP_RWSTATE_RDB) ? "RDB" : (bit & SAA7135_DSP_RWSTATE_IDA) ? "IDA" : "???"); return -EIO; } saa_wait(DSP_DELAY); state = saa_readb(SAA7135_DSP_RWSTATE); count--; } return 0;}#if 0static int saa_dsp_readl(struct saa7134_dev *dev, int reg, u32 *value){ int err; d2printk("dsp read reg 0x%x\n", reg<<2); saa_readl(reg); err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_RDB); if (err < 0) return err; *value = saa_readl(reg); d2printk("dsp read => 0x%06x\n", *value & 0xffffff); err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_IDA); if (err < 0) return err; return 0;}#endifint saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value){ int err; d2printk("dsp write reg 0x%x = 0x%06x\n",reg<<2,value); err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_WRR); if (err < 0) return err; saa_writel(reg,value); err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_WRR); if (err < 0) return err; return 0;}static int getstereo_7133(struct saa7134_dev *dev){ int retval = V4L2_TUNER_SUB_MONO; u32 value; value = saa_readl(0x528 >> 2); if (value & 0x20) retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; if (value & 0x40) retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; return retval;}static int mute_input_7133(struct saa7134_dev *dev){ u32 reg = 0; switch (dev->input->amux) { case TV: reg = 0x02; break; case LINE1: reg = 0x00; break; case LINE2: reg = 0x01; break; } if (dev->ctl_mute) reg = 0x07; saa_writel(0x594 >> 2, reg); return 0;}static int tvaudio_thread_ddep(void *data){ struct saa7134_dev *dev = data; u32 value, norms; lock_kernel();#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,61) daemonize(); sigfillset(¤t->blocked); sprintf(current->comm, "%s", dev->name);#else daemonize("%s", dev->name);#endif dev->thread.task = current; unlock_kernel(); if (dev->thread.notify != NULL) up(dev->thread.notify); /* unmute */ saa_dsp_writel(dev, 0x474 >> 2, 0x00); saa_dsp_writel(dev, 0x450 >> 2, 0x00); for (;;) { if (dev->thread.exit || signal_pending(current)) goto done; interruptible_sleep_on(&dev->thread.wq); if (dev->thread.exit || signal_pending(current)) goto done; restart: dev->thread.scan1 = dev->thread.scan2; dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1); norms = 0; if (dev->tvnorm->id & V4L2_STD_PAL) norms |= 0x2c; /* B/G + D/K + I */ if (dev->tvnorm->id & V4L2_STD_NTSC) norms |= 0x40; /* M */ if (dev->tvnorm->id & V4L2_STD_SECAM) norms |= 0x18; /* L + D/K */ if (0 == norms) norms = 0x0000007c; /* quick & dirty -- to be fixed up later ... */ saa_dsp_writel(dev, 0x454 >> 2, 0); saa_dsp_writel(dev, 0x454 >> 2, norms | 0x80); saa_dsp_writel(dev, 0x464 >> 2, 0x000000); saa_dsp_writel(dev, 0x470 >> 2, 0x101010); if (tvaudio_sleep(dev,3*HZ)) goto restart; value = saa_readl(0x528 >> 2) & 0xffffff; dprintk("tvaudio thread status: 0x%x [%s%s%s]\n", value, stdres[value & 0x1f], (value & 0x000020) ? ",stereo" : "", (value & 0x000040) ? ",dual" : ""); dprintk("detailed status: " "%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s\n", (value & 0x000080) ? " A2/EIAJ pilot tone " : "", (value & 0x000100) ? " A2/EIAJ dual " : "", (value & 0x000200) ? " A2/EIAJ stereo " : "", (value & 0x000400) ? " A2/EIAJ noise mute " : "", (value & 0x000800) ? " BTSC/FM radio pilot " : "", (value & 0x001000) ? " SAP carrier " : "", (value & 0x002000) ? " BTSC stereo noise mute " : "", (value & 0x004000) ? " SAP noise mute " : "", (value & 0x008000) ? " VDSP " : "", (value & 0x010000) ? " NICST " : "", (value & 0x020000) ? " NICDU " : "", (value & 0x040000) ? " NICAM muted " : "", (value & 0x080000) ? " NICAM reserve sound " : "", (value & 0x100000) ? " init done " : ""); } done: dev->thread.task = NULL; if(dev->thread.notify != NULL) up(dev->thread.notify); return 0;}/* ------------------------------------------------------------------ *//* common stuff + external entry points */int saa7134_tvaudio_rx2mode(u32 rx){ u32 mode; mode = V4L2_TUNER_MODE_MONO; if (rx & V4L2_TUNER_SUB_STEREO) mode = V4L2_TUNER_MODE_STEREO; else if (rx & V4L2_TUNER_SUB_LANG1) mode = V4L2_TUNER_MODE_LANG1; else if (rx & V4L2_TUNER_SUB_LANG2) mode = V4L2_TUNER_MODE_LANG2; return mode;} void saa7134_tvaudio_setmute(struct saa7134_dev *dev){ switch (dev->pci->device) { case PCI_DEVICE_ID_PHILIPS_SAA7130: case PCI_DEVICE_ID_PHILIPS_SAA7134: mute_input_7134(dev); break; case PCI_DEVICE_ID_PHILIPS_SAA7133: case PCI_DEVICE_ID_PHILIPS_SAA7135: mute_input_7133(dev); break; }}void saa7134_tvaudio_setinput(struct saa7134_dev *dev, struct saa7134_input *in){ dev->input = in; switch (dev->pci->device) { case PCI_DEVICE_ID_PHILIPS_SAA7130: case PCI_DEVICE_ID_PHILIPS_SAA7134: mute_input_7134(dev); break; case PCI_DEVICE_ID_PHILIPS_SAA7133: case PCI_DEVICE_ID_PHILIPS_SAA7135: mute_input_7133(dev); break; }}void saa7134_tvaudio_setvolume(struct saa7134_dev *dev, int level){ switch (dev->pci->device) { case PCI_DEVICE_ID_PHILIPS_SAA7134: saa_writeb(SAA7134_CHANNEL1_LEVEL, level & 0x1f); saa_writeb(SAA7134_CHANNEL2_LEVEL, level & 0x1f); saa_writeb(SAA7134_NICAM_LEVEL_ADJUST, level & 0x1f); break; }}int saa7134_tvaudio_getstereo(struct saa7134_dev *dev){ int retval = V4L2_TUNER_SUB_MONO; switch (dev->pci->device) { case PCI_DEVICE_ID_PHILIPS_SAA7134: if (dev->tvaudio) retval = tvaudio_getstereo(dev,dev->tvaudio); break; case PCI_DEVICE_ID_PHILIPS_SAA7133: case PCI_DEVICE_ID_PHILIPS_SAA7135: retval = getstereo_7133(dev); break; } return retval;}int saa7134_tvaudio_init2(struct saa7134_dev *dev){ DECLARE_MUTEX_LOCKED(sem); int (*my_thread)(void *data) = NULL; int rc; /* enable I2S audio output */ if (saa7134_boards[dev->board].i2s_rate) { int rate = (32000 == saa7134_boards[dev->board].i2s_rate) ? 0x01 : 0x03; /* set rate */ saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, rate); /* enable I2S output */ saa_writeb(SAA7134_DSP_OUTPUT_SELECT, 0x80); saa_writeb(SAA7134_I2S_OUTPUT_SELECT, 0x80); saa_writeb(SAA7134_I2S_OUTPUT_FORMAT, 0x01); saa_writeb(SAA7134_I2S_OUTPUT_LEVEL, 0x00); saa_writeb(SAA7134_I2S_AUDIO_OUTPUT, 0x01); } switch (dev->pci->device) { case PCI_DEVICE_ID_PHILIPS_SAA7134: my_thread = tvaudio_thread; break; case PCI_DEVICE_ID_PHILIPS_SAA7133: case PCI_DEVICE_ID_PHILIPS_SAA7135: my_thread = tvaudio_thread_ddep; break; } if (my_thread) { /* start tvaudio thread */ init_waitqueue_head(&dev->thread.wq); dev->thread.notify = &sem; rc = kernel_thread(my_thread,dev,0); if (rc < 0) printk(KERN_WARNING "%s: kernel_thread() failed\n", dev->name); else down(&sem); dev->thread.notify = NULL; wake_up_interruptible(&dev->thread.wq); } return 0;}int saa7134_tvaudio_fini(struct saa7134_dev *dev){ DECLARE_MUTEX_LOCKED(sem); /* shutdown tvaudio thread */ if (dev->thread.task) { dev->thread.notify = &sem; dev->thread.exit = 1; wake_up_interruptible(&dev->thread.wq); down(&sem); dev->thread.notify = NULL; } saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x07, 0x00); /* LINE1 */ return 0;}int saa7134_tvaudio_do_scan(struct saa7134_dev *dev){ if (dev->thread.task) { dev->thread.mode = UNSET; dev->thread.scan2++; wake_up_interruptible(&dev->thread.wq); } else { dev->automute = 0; saa7134_tvaudio_setmute(dev); } return 0;}/* ----------------------------------------------------------- *//* * Local variables: * c-basic-offset: 8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -