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

📄 waveartist.c

📁 iis s3c2410-uda1341语音系统的 开发
💻 C
📖 第 1 页 / 共 4 页
字号:
	outb(0xFF, 0x201);	*CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_DIV1;	while (volume && (inb(0x201) & 0x01))		volume--;	*CSR_TIMER1_CNTL = 0;	restore_flags(flags);		volume = 0x00ffffff - *CSR_TIMER1_VALUE;#ifndef REVERSE	volume = 150 - (volume >> 5);#else	volume = (volume >> 6) - 25;#endif	if (volume < 0)		volume = 0;	if (volume > 100)		volume = 100;	/*	 * slider quite often reads +-8, so debounce this random noise	 */	if (abs(volume - old_slider_volume) > 7) {		old_slider_volume = volume;		if (debug_flg & DEBUG_MIXER)			printk(KERN_DEBUG "Slider volume: %d.\n", volume);	}	return old_slider_volume;}/* * Decode a recording mask into a mixer selection on the NetWinder * as follows: * *     OSS Source	WA Source	Actual source *  SOUND_MASK_IMIX	Mixer		Mixer output (same as AD1848) *  SOUND_MASK_LINE	Line		Line in *  SOUND_MASK_LINE1	Left Mic	Handset *  SOUND_MASK_PHONEIN	Left Aux	Telephone microphone *  SOUND_MASK_MIC	Right Mic	Builtin microphone */static unsigned intnetwinder_select_input(wavnc_info *devc, unsigned int recmask,		       unsigned char *dev_l, unsigned char *dev_r){	unsigned int recdev_l = ADC_MUX_NONE, recdev_r = ADC_MUX_NONE;	if (recmask & SOUND_MASK_IMIX) {		recmask = SOUND_MASK_IMIX;		recdev_l = ADC_MUX_MIXER;		recdev_r = ADC_MUX_MIXER;	} else if (recmask & SOUND_MASK_LINE) {		recmask = SOUND_MASK_LINE;		recdev_l = ADC_MUX_LINE;		recdev_r = ADC_MUX_LINE;	} else if (recmask & SOUND_MASK_LINE1) {		recmask = SOUND_MASK_LINE1;		waveartist_cmd1(devc, WACMD_SET_MONO); /* left */		recdev_l = ADC_MUX_MIC;		recdev_r = ADC_MUX_NONE;	} else if (recmask & SOUND_MASK_PHONEIN) {		recmask = SOUND_MASK_PHONEIN;		waveartist_cmd1(devc, WACMD_SET_MONO); /* left */		recdev_l = ADC_MUX_AUX1;		recdev_r = ADC_MUX_NONE;	} else if (recmask & SOUND_MASK_MIC) {		recmask = SOUND_MASK_MIC;		waveartist_cmd1(devc, WACMD_SET_MONO | 0x100);	/* right */		recdev_l = ADC_MUX_NONE;		recdev_r = ADC_MUX_MIC;	}	*dev_l = recdev_l;	*dev_r = recdev_r;	return recmask;}static intnetwinder_decode_mixer(wavnc_info *devc, int dev, unsigned char lev_l,		       unsigned char lev_r){	switch (dev) {	case SOUND_MIXER_VOLUME:	case SOUND_MIXER_SYNTH:	case SOUND_MIXER_PCM:	case SOUND_MIXER_LINE:	case SOUND_MIXER_IGAIN:		devc->levels[dev] = lev_l | lev_r << 8;		break;	case SOUND_MIXER_MIC:		/* right mic only */		devc->levels[SOUND_MIXER_MIC] &= 0xff;		devc->levels[SOUND_MIXER_MIC] |= lev_l << 8;		break;	case SOUND_MIXER_LINE1:		/* left mic only  */		devc->levels[SOUND_MIXER_MIC] &= 0xff00;		devc->levels[SOUND_MIXER_MIC] |= lev_l;		dev = SOUND_MIXER_MIC;		break;	case SOUND_MIXER_PHONEIN:	/* left aux only  */		devc->levels[SOUND_MIXER_LINE1] = lev_l;		dev = SOUND_MIXER_LINE1;		break;	case SOUND_MIXER_IMIX:	case SOUND_MIXER_PHONEOUT:		break;	default:		dev = -EINVAL;		break;	}	return dev;}static int netwinder_get_mixer(wavnc_info *devc, int dev){	int levels;	switch (dev) {	case SOUND_MIXER_VOLUME:	case SOUND_MIXER_SYNTH:	case SOUND_MIXER_PCM:	case SOUND_MIXER_LINE:	case SOUND_MIXER_IGAIN:		levels = devc->levels[dev];		break;	case SOUND_MIXER_MIC:		/* builtin mic: right mic only */		levels = devc->levels[SOUND_MIXER_MIC] >> 8;		levels |= levels << 8;		break;	case SOUND_MIXER_LINE1:		/* handset mic: left mic only */		levels = devc->levels[SOUND_MIXER_MIC] & 0xff;		levels |= levels << 8;		break;	case SOUND_MIXER_PHONEIN:	/* phone mic: left aux1 only */		levels = devc->levels[SOUND_MIXER_LINE1] & 0xff;		levels |= levels << 8;		break;	default:		levels = 0;	}	return levels;}/* * Waveartist specific mixer information. */static const struct waveartist_mixer_info netwinder_mixer = {	supported_devs:	SOUND_MASK_VOLUME  | SOUND_MASK_SYNTH   |			SOUND_MASK_PCM     | SOUND_MASK_SPEAKER |			SOUND_MASK_LINE    | SOUND_MASK_MIC     |			SOUND_MASK_IMIX    | SOUND_MASK_LINE1   |			SOUND_MASK_PHONEIN | SOUND_MASK_PHONEOUT|			SOUND_MASK_IGAIN,	recording_devs:	SOUND_MASK_LINE    | SOUND_MASK_MIC     |			SOUND_MASK_IMIX    | SOUND_MASK_LINE1   |			SOUND_MASK_PHONEIN,	stereo_devs:	SOUND_MASK_VOLUME  | SOUND_MASK_SYNTH   |			SOUND_MASK_PCM     | SOUND_MASK_LINE    |			SOUND_MASK_IMIX    | SOUND_MASK_IGAIN,	select_input:	netwinder_select_input,	decode_mixer:	netwinder_decode_mixer,	get_mixer:	netwinder_get_mixer,};static voidvnc_configure_mixer(wavnc_info *devc, unsigned int recmask){	if (!devc->no_autoselect) {		if (devc->handset_detect) {			recmask = SOUND_MASK_LINE1;			devc->spkr_mute_state = devc->line_mute_state = 1;		} else if (devc->telephone_detect) {			recmask = SOUND_MASK_PHONEIN;			devc->spkr_mute_state = devc->line_mute_state = 1;		} else {			/* unless someone has asked for LINE-IN,			 * we default to MIC			 */			if ((devc->recmask & SOUND_MASK_LINE) == 0)				devc->recmask = SOUND_MASK_MIC;			devc->spkr_mute_state = devc->line_mute_state = 0;		}		vnc_mute_spkr(devc);		vnc_mute_lout(devc);		if (recmask != devc->recmask)			waveartist_set_recmask(devc, recmask);	}}static intvnc_slider(wavnc_info *devc){	signed int slider_volume;	unsigned int temp, old_hs, old_td;	/*	 * read the "buttons" state.	 *  Bit 4 = 0 means handset present	 *  Bit 5 = 1 means phone offhook	 */	temp = inb(0x201);	old_hs = devc->handset_detect;	old_td = devc->telephone_detect;	devc->handset_detect = !(temp & 0x10);	devc->telephone_detect = !!(temp & 0x20);	if (!devc->no_autoselect &&	    (old_hs != devc->handset_detect ||	     old_td != devc->telephone_detect))		vnc_configure_mixer(devc, devc->recmask);	slider_volume = vnc_volume_slider(devc);	/*	 * If we're using software controlled volume, and	 * the slider moves by more than 20%, then we	 * switch back to slider controlled volume.	 */	if (abs(devc->slider_vol - slider_volume) > 20)		devc->use_slider = 1;	/*	 * use only left channel	 */	temp = levels[SOUND_MIXER_VOLUME] & 0xFF;	if (slider_volume != temp && devc->use_slider) {		devc->slider_vol = slider_volume;		waveartist_set_mixer(devc, SOUND_MIXER_VOLUME,			slider_volume | slider_volume << 8);		return 1;	}	return 0;}static voidvnc_slider_tick(unsigned long data){	int next_timeout;	if (vnc_slider(adev_info + data))		next_timeout = 5;	// mixer reported change	else		next_timeout = VNC_TIMER_PERIOD;	mod_timer(&vnc_timer, jiffies + next_timeout);}static intvnc_private_ioctl(int dev, unsigned int cmd, caddr_t arg){	wavnc_info *devc = (wavnc_info *)audio_devs[dev]->devc;	int val;	switch (cmd) {	case SOUND_MIXER_PRIVATE1:	{		u_int prev_spkr_mute, prev_line_mute, prev_auto_state;		int val;		if (get_user(val, (int *)arg))			return -EFAULT;		/* check if parameter is logical */		if (val & ~(VNC_MUTE_INTERNAL_SPKR |			    VNC_MUTE_LINE_OUT |			    VNC_DISABLE_AUTOSWITCH))			return -EINVAL;		prev_auto_state = devc->no_autoselect;		prev_spkr_mute  = devc->spkr_mute_state;		prev_line_mute  = devc->line_mute_state;		devc->no_autoselect   = (val & VNC_DISABLE_AUTOSWITCH) ? 1 : 0;		devc->spkr_mute_state = (val & VNC_MUTE_INTERNAL_SPKR) ? 1 : 0;		devc->line_mute_state = (val & VNC_MUTE_LINE_OUT) ? 1 : 0;		if (prev_spkr_mute != devc->spkr_mute_state)			vnc_mute_spkr(devc);		if (prev_line_mute != devc->line_mute_state)			vnc_mute_lout(devc);		if (prev_auto_state != devc->no_autoselect)			vnc_configure_mixer(devc, devc->recmask);		return 0;	}	case SOUND_MIXER_PRIVATE2:		if (get_user(val, (int *)arg))			return -EFAULT;		switch (val) {#define VNC_SOUND_PAUSE         0x53    //to pause the DSP#define VNC_SOUND_RESUME        0x57    //to unpause the DSP		case VNC_SOUND_PAUSE:			waveartist_cmd1(devc, 0x16);			break;		case VNC_SOUND_RESUME:			waveartist_cmd1(devc, 0x18);			break;		default:			return -EINVAL;		}		return 0;	/* private ioctl to allow bulk access to waveartist */	case SOUND_MIXER_PRIVATE3:	{		unsigned long	flags;		int		mixer_reg[15], i, val;		if (get_user(val, (int *)arg))			return -EFAULT;		if (copy_from_user(mixer_reg, (void *)val, sizeof(mixer_reg)))			return -EFAULT;		switch (mixer_reg[14]) {		case MIXER_PRIVATE3_RESET:			waveartist_mixer_reset(devc);			break;		case MIXER_PRIVATE3_WRITE:			waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[0], mixer_reg[4]);			waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[1], mixer_reg[5]);			waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[2], mixer_reg[6]);			waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[3], mixer_reg[7]);			waveartist_cmd3(devc, WACMD_SET_MIXER, mixer_reg[8], mixer_reg[9]);			waveartist_cmd3(devc, WACMD_SET_LEVEL, mixer_reg[10], mixer_reg[11]);			waveartist_cmd3(devc, WACMD_SET_LEVEL, mixer_reg[12], mixer_reg[13]);			break;		case MIXER_PRIVATE3_READ:			spin_lock_irqsave(&waveartist_lock, flags);			for (i = 0x30; i < 14 << 8; i += 1 << 8)				waveartist_cmd(devc, 1, &i, 1, mixer_reg + (i >> 8));			spin_unlock_irqrestore(&waveartist_lock, flags);			if (copy_to_user((void *)val, mixer_reg, sizeof(mixer_reg)))				return -EFAULT;			break;		default:			return -EINVAL;		}		return 0;	}	/* read back the state from PRIVATE1 */	case SOUND_MIXER_PRIVATE4:		val = (devc->spkr_mute_state  ? VNC_MUTE_INTERNAL_SPKR : 0) |		      (devc->line_mute_state  ? VNC_MUTE_LINE_OUT      : 0) |		      (devc->handset_detect   ? VNC_HANDSET_DETECT     : 0) |		      (devc->telephone_detect ? VNC_PHONE_DETECT       : 0) |		      (devc->no_autoselect    ? VNC_DISABLE_AUTOSWITCH : 0);		return put_user(val, (int *)arg) ? -EFAULT : 0;	}	if (_SIOC_DIR(cmd) & _SIOC_WRITE) {		/*		 * special case for master volume: if we		 * received this call - switch from hw		 * volume control to a software volume		 * control, till the hw volume is modified		 * to signal that user wants to be back in		 * hardware...		 */		if ((cmd & 0xff) == SOUND_MIXER_VOLUME)			devc->use_slider = 0;		/* speaker output            */		if ((cmd & 0xff) == SOUND_MIXER_SPEAKER) {			unsigned int val, l, r;			if (get_user(val, (int *)arg))				return -EFAULT;			l = val & 0x7f;			r = (val & 0x7f00) >> 8;			val = (l + r) / 2;			devc->levels[SOUND_MIXER_SPEAKER] = val | (val << 8);			devc->spkr_mute_state = (val <= 50);			vnc_mute_spkr(devc);			return 0;		}	}	return -ENOIOCTLCMD;}#endifstatic struct address_info cfg;static int attached;static int __initdata io = 0;static int __initdata irq = 0;static int __initdata dma = 0;static int __initdata dma2 = 0;static int __init init_waveartist(void){	const struct waveartist_mixer_info *mix;	if (!io && machine_is_netwinder()) {		/*		 * The NetWinder WaveArtist is at a fixed address.		 * If the user does not supply an address, use the		 * well-known parameters.		 */		io   = 0x250;		irq  = 12;		dma  = 3;		dma2 = 7;	}	mix = &waveartist_mixer;#ifdef CONFIG_ARCH_NETWINDER	if (machine_is_netwinder())		mix = &netwinder_mixer;#endif	cfg.io_base = io;	cfg.irq = irq;	cfg.dma = dma;	cfg.dma2 = dma2;	if (!probe_waveartist(&cfg))		return -ENODEV;	attach_waveartist(&cfg, mix);	attached = 1;	return 0;}static void __exit cleanup_waveartist(void){	if (attached)		unload_waveartist(&cfg);}module_init(init_waveartist);module_exit(cleanup_waveartist);#ifndef MODULEstatic int __init setup_waveartist(char *str){	/* io, irq, dma, dma2 */	int ints[5];		str = get_options(str, ARRAY_SIZE(ints), ints);		io	= ints[1];	irq	= ints[2];	dma	= ints[3];	dma2	= ints[4];	return 1;}__setup("waveartist=", setup_waveartist);#endifMODULE_DESCRIPTION("Rockwell WaveArtist RWA-010 sound driver");MODULE_PARM(io, "i");		/* IO base */MODULE_PARM(irq, "i");		/* IRQ */MODULE_PARM(dma, "i");		/* DMA */MODULE_PARM(dma2, "i");		/* DMA2 */MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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