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

📄 ad1848.c

📁 iis s3c2410-uda1341语音系统的 开发
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (muteregoffs != regoffs) {		ad_write(devc, muteregoffs, muteval);		devc->saved_regs[muteregoffs] = muteval;	}}static int ad1848_mixer_set(ad1848_info * devc, int dev, int value){	int left = value & 0x000000ff;	int right = (value & 0x0000ff00) >> 8;	int retvol;	if (dev > 31)		return -EINVAL;	if (!(devc->supported_devices & (1 << dev)))		return -EINVAL;	dev = devc->mixer_reroute[dev];	if (devc->mix_devices[dev][LEFT_CHN].nbits == 0)		return -EINVAL;	if (left > 100)		left = 100;	if (right > 100)		right = 100;	if (devc->mix_devices[dev][RIGHT_CHN].nbits == 0)	/* Mono control */		right = left;	retvol = left | (right << 8);	/* Scale volumes */	left = mix_cvt[left];	right = mix_cvt[right];	devc->levels[dev] = retvol;	/*	 * Set the left channel	 */	ad1848_mixer_set_channel(devc, dev, left, LEFT_CHN);	/*	 * Set the right channel	 */	if (devc->mix_devices[dev][RIGHT_CHN].nbits == 0)		goto out;	ad1848_mixer_set_channel(devc, dev, right, RIGHT_CHN); out:	return retvol;}static void ad1848_mixer_reset(ad1848_info * devc){	int i;	char name[32];	devc->mix_devices = &(ad1848_mix_devices[0]);	sprintf(name, "%s_%d", devc->chip_name, nr_ad1848_devs);	for (i = 0; i < 32; i++)		devc->mixer_reroute[i] = i;	devc->supported_rec_devices = MODE1_REC_DEVICES;	switch (devc->model)	{		case MD_4231:		case MD_4231A:		case MD_1845:		case MD_1845_SSCAPE:			devc->supported_devices = MODE2_MIXER_DEVICES;			break;		case MD_C930:			devc->supported_devices = C930_MIXER_DEVICES;			devc->mix_devices = &(c930_mix_devices[0]);			break;		case MD_IWAVE:			devc->supported_devices = MODE3_MIXER_DEVICES;			devc->mix_devices = &(iwave_mix_devices[0]);			break;		case MD_42xB:		case MD_4239:			devc->mix_devices = &(cs42xb_mix_devices[0]);			devc->supported_devices = MODE3_MIXER_DEVICES;			break;		case MD_4232:		case MD_4236:			devc->supported_devices = MODE3_MIXER_DEVICES;			break;		case MD_1848:			if (soundpro) {				devc->supported_devices = SPRO_MIXER_DEVICES;				devc->supported_rec_devices = SPRO_REC_DEVICES;				devc->mix_devices = &(spro_mix_devices[0]);				break;			}		default:			devc->supported_devices = MODE1_MIXER_DEVICES;	}	devc->orig_devices = devc->supported_devices;	devc->orig_rec_devices = devc->supported_rec_devices;	devc->levels = load_mixer_volumes(name, default_mixer_levels, 1);	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)	{		if (devc->supported_devices & (1 << i))			ad1848_mixer_set(devc, i, devc->levels[i]);	}		ad1848_set_recmask(devc, SOUND_MASK_MIC);		devc->mixer_output_port = devc->levels[31] | AUDIO_HEADPHONE | AUDIO_LINE_OUT;	if (!soundpro) {		if (devc->mixer_output_port & AUDIO_SPEAKER)			ad_write(devc, 26, ad_read(devc, 26) & ~0x40);	/* Unmute mono out */		else			ad_write(devc, 26, ad_read(devc, 26) | 0x40);	/* Mute mono out */	} else {		/*		 * From the "wouldn't it be nice if the mixer API had (better)		 * support for custom stuff" category		 */		/* Enable surround mode and SB16 mixer */		ad_write(devc, 16, 0x60);	}}static int ad1848_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg){	ad1848_info *devc = mixer_devs[dev]->devc;	int val;	if (cmd == SOUND_MIXER_PRIVATE1) 	{		if (get_user(val, (int *)arg))			return -EFAULT;		if (val != 0xffff) 		{			val &= (AUDIO_SPEAKER | AUDIO_HEADPHONE | AUDIO_LINE_OUT);			devc->mixer_output_port = val;			val |= AUDIO_HEADPHONE | AUDIO_LINE_OUT;	/* Always on */			devc->mixer_output_port = val;			if (val & AUDIO_SPEAKER)				ad_write(devc, 26, ad_read(devc, 26) & ~0x40);	/* Unmute mono out */			else				ad_write(devc, 26, ad_read(devc, 26) | 0x40);		/* Mute mono out */		}		val = devc->mixer_output_port;		return put_user(val, (int *)arg);	}	if (cmd == SOUND_MIXER_PRIVATE2)	{		if (get_user(val, (int *)arg))			return -EFAULT;		return(ad1848_control(AD1848_MIXER_REROUTE, val));	}	if (((cmd >> 8) & 0xff) == 'M') 	{		if (_SIOC_DIR(cmd) & _SIOC_WRITE)		{			switch (cmd & 0xff) 			{				case SOUND_MIXER_RECSRC:					if (get_user(val, (int *)arg))						return -EFAULT;					val = ad1848_set_recmask(devc, val);					break;								default:					if (get_user(val, (int *)arg))					return -EFAULT;					val = ad1848_mixer_set(devc, cmd & 0xff, val);					break;			} 			return put_user(val, (int *)arg);		}		else		{			switch (cmd & 0xff) 			{				/*				 * Return parameters				 */			    				case SOUND_MIXER_RECSRC:					val = devc->recmask;					break;								case SOUND_MIXER_DEVMASK:					val = devc->supported_devices;					break;								case SOUND_MIXER_STEREODEVS:					val = devc->supported_devices;					if (devc->model != MD_C930)						val &= ~(SOUND_MASK_SPEAKER | SOUND_MASK_IMIX);					break;								case SOUND_MIXER_RECMASK:					val = devc->supported_rec_devices;					break;				case SOUND_MIXER_CAPS:					val=SOUND_CAP_EXCL_INPUT;					break;				default:					val = ad1848_mixer_get(devc, cmd & 0xff);					break;			}			return put_user(val, (int *)arg);		}	}	else		return -EINVAL;}static int ad1848_set_speed(int dev, int arg){	ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;	ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc;	/*	 * The sampling speed is encoded in the least significant nibble of I8. The	 * LSB selects the clock source (0=24.576 MHz, 1=16.9344 MHz) and other	 * three bits select the divisor (indirectly):	 *	 * The available speeds are in the following table. Keep the speeds in	 * the increasing order.	 */	typedef struct	{		int             speed;		unsigned char   bits;	}	speed_struct;	static speed_struct speed_table[] =	{		{5510, (0 << 1) | 1},		{5510, (0 << 1) | 1},		{6620, (7 << 1) | 1},		{8000, (0 << 1) | 0},		{9600, (7 << 1) | 0},		{11025, (1 << 1) | 1},		{16000, (1 << 1) | 0},		{18900, (2 << 1) | 1},		{22050, (3 << 1) | 1},		{27420, (2 << 1) | 0},		{32000, (3 << 1) | 0},		{33075, (6 << 1) | 1},		{37800, (4 << 1) | 1},		{44100, (5 << 1) | 1},		{48000, (6 << 1) | 0}	};	int i, n, selected = -1;	n = sizeof(speed_table) / sizeof(speed_struct);	if (arg <= 0)		return portc->speed;	if (devc->model == MD_1845 || devc->model == MD_1845_SSCAPE)	/* AD1845 has different timer than others */	{		if (arg < 4000)			arg = 4000;		if (arg > 50000)			arg = 50000;		portc->speed = arg;		portc->speed_bits = speed_table[3].bits;		return portc->speed;	}	if (arg < speed_table[0].speed)		selected = 0;	if (arg > speed_table[n - 1].speed)		selected = n - 1;	for (i = 1 /*really */ ; selected == -1 && i < n; i++)	{		if (speed_table[i].speed == arg)			selected = i;		else if (speed_table[i].speed > arg)		{			int diff1, diff2;			diff1 = arg - speed_table[i - 1].speed;			diff2 = speed_table[i].speed - arg;			if (diff1 < diff2)				selected = i - 1;			else				selected = i;		}	}	if (selected == -1)	{		printk(KERN_WARNING "ad1848: Can't find speed???\n");		selected = 3;	}	portc->speed = speed_table[selected].speed;	portc->speed_bits = speed_table[selected].bits;	return portc->speed;}static short ad1848_set_channels(int dev, short arg){	ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc;	if (arg != 1 && arg != 2)		return portc->channels;	portc->channels = arg;	return arg;}static unsigned int ad1848_set_bits(int dev, unsigned int arg){	ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;	ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc;	static struct format_tbl	{		  int             format;		  unsigned char   bits;	}	format2bits[] =	{		{			0, 0		}		,		{			AFMT_MU_LAW, 1		}		,		{			AFMT_A_LAW, 3		}		,		{			AFMT_IMA_ADPCM, 5		}		,		{			AFMT_U8, 0		}		,		{			AFMT_S16_LE, 2		}		,		{			AFMT_S16_BE, 6		}		,		{			AFMT_S8, 0		}		,		{			AFMT_U16_LE, 0		}		,		{			AFMT_U16_BE, 0		}	};	int i, n = sizeof(format2bits) / sizeof(struct format_tbl);	if (arg == 0)		return portc->audio_format;	if (!(arg & ad_format_mask[devc->model]))		arg = AFMT_U8;	portc->audio_format = arg;	for (i = 0; i < n; i++)		if (format2bits[i].format == arg)		{			if ((portc->format_bits = format2bits[i].bits) == 0)				return portc->audio_format = AFMT_U8;		/* Was not supported */			return arg;		}	/* Still hanging here. Something must be terribly wrong */	portc->format_bits = 0;	return portc->audio_format = AFMT_U8;}static struct audio_driver ad1848_audio_driver ={	owner:		THIS_MODULE,	open:		ad1848_open,	close:		ad1848_close,	output_block:	ad1848_output_block,	start_input:	ad1848_start_input,	prepare_for_input:	ad1848_prepare_for_input,	prepare_for_output:	ad1848_prepare_for_output,	halt_io:	ad1848_halt,	halt_input:	ad1848_halt_input,	halt_output:	ad1848_halt_output,	trigger:	ad1848_trigger,	set_speed:	ad1848_set_speed,	set_bits:	ad1848_set_bits,	set_channels:	ad1848_set_channels};static struct mixer_operations ad1848_mixer_operations ={	owner:	THIS_MODULE,	id:	"SOUNDPORT",	name:	"AD1848/CS4248/CS4231",	ioctl:	ad1848_mixer_ioctl};static int ad1848_open(int dev, int mode){	ad1848_info    *devc = NULL;	ad1848_port_info *portc;	unsigned long   flags;	if (dev < 0 || dev >= num_audiodevs)		return -ENXIO;	devc = (ad1848_info *) audio_devs[dev]->devc;	portc = (ad1848_port_info *) audio_devs[dev]->portc;	save_flags(flags);	cli();	if (portc->open_mode || (devc->open_mode & mode))	{		restore_flags(flags);		return -EBUSY;	}	devc->dual_dma = 0;	if (audio_devs[dev]->flags & DMA_DUPLEX)	{		devc->dual_dma = 1;	}	devc->intr_active = 0;	devc->audio_mode = 0;	devc->open_mode |= mode;	portc->open_mode = mode;	ad1848_trigger(dev, 0);	if (mode & OPEN_READ)		devc->record_dev = dev;	if (mode & OPEN_WRITE)		devc->playback_dev = dev;	restore_flags(flags);/* * Mute output until the playback really starts. This decreases clicking (hope so). */	ad_mute(devc);	return 0;}static void ad1848_close(int dev){	unsigned long   flags;	ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;	ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc;	DEB(printk("ad1848_close(void)\n"));	save_flags(flags);	cli();	devc->intr_active = 0;	ad1848_halt(dev);	devc->audio_mode = 0;	devc->open_mode &= ~portc->open_mode;	portc->open_mode = 0;	ad_unmute(devc);	restore_flags(flags);}static void ad1848_output_block(int dev, unsigned long buf, int count, int intrflag){	unsigned long   flags, cnt;	ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;	ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc;	cnt = count;	if (portc->audio_format == AFMT_IMA_ADPCM)	{		cnt /= 4;	}	else	{		if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE))	/* 16 bit data */			cnt >>= 1;	}	if (portc->channels > 1)		cnt >>= 1;	cnt--;	if ((devc->audio_mode & PCM_ENABLE_OUTPUT) && (audio_devs[dev]->flags & DMA_AUTOMODE) &&	    intrflag &&	    cnt == devc->xfer_count)	{		devc->audio_mode |= PCM_ENABLE_OUTPUT;		devc->intr_active = 1;		return;	/*			 * Auto DMA mode on. No need to react			 */	}	save_flags(flags);	cli();	ad_write(devc, 15, (unsigned char) (cnt & 0xff));	ad_write(devc, 14, (unsigned char) ((cnt >> 8) & 0xff));	devc->xfer_count = cnt;	devc->audio_mode |= PCM_ENABLE_OUTPUT;	devc->intr_active = 1;	restore_flags(flags);}static void ad1848_start_input(int dev, unsigned long buf, int count, int intrflag){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -