⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 saa7134-tvaudio.c

📁 电脑主机的PCI电视卡的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		/* 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(&current->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 + -