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

📄 waveartist.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
{	unsigned long	flags;	wavnc_info	*devc = (wavnc_info *) audio_devs[dev]->devc;	wavnc_port_info	*portc = (wavnc_port_info *) audio_devs[dev]->portc;	unsigned int	speed, bits;	/*	 * program the speed, channels, bits	 */	speed = waveartist_get_speed(portc);	bits  = waveartist_get_bits(portc);	spin_lock_irqsave(&waveartist_lock, flags);	if (waveartist_cmd2(devc, WACMD_OUTPUTSPEED, speed) &&	    waveartist_cmd2(devc, WACMD_OUTPUTSPEED, speed))		printk(KERN_WARNING "waveartist: error setting the playback "		       "speed to %dHz.\n", portc->speed);	if (waveartist_cmd2(devc, WACMD_OUTPUTCHANNELS, portc->channels))		printk(KERN_WARNING "waveartist: error setting the playback "		       "to %d channels\n", portc->channels);	if (waveartist_cmd2(devc, WACMD_OUTPUTDMA, 0))		printk(KERN_WARNING "waveartist: error setting the playback "		       "data path to 0x%X\n", 0);	if (waveartist_cmd2(devc, WACMD_OUTPUTFORMAT, bits))		printk(KERN_WARNING "waveartist: error setting the playback "		       "format to %d\n", portc->audio_format);	devc->xfer_count = 0;	spin_unlock_irqrestore(&waveartist_lock, flags);	waveartist_halt_output(dev);	if (debug_flg & DEBUG_INTR) {		printk("WA CTLR reg: 0x%02X.\n",inb(devc->hw.io_base + CTLR));		printk("WA STAT reg: 0x%02X.\n",inb(devc->hw.io_base + STATR));		printk("WA IRQS reg: 0x%02X.\n",inb(devc->hw.io_base + IRQSTAT));	}	return 0;}static voidwaveartist_halt(int dev){	wavnc_port_info	*portc = (wavnc_port_info *) audio_devs[dev]->portc;	wavnc_info	*devc;	if (portc->open_mode & OPEN_WRITE)		waveartist_halt_output(dev);	if (portc->open_mode & OPEN_READ)		waveartist_halt_input(dev);	devc = (wavnc_info *) audio_devs[dev]->devc;	devc->audio_mode = 0;}static voidwaveartist_halt_input(int dev){	wavnc_info	*devc = (wavnc_info *) audio_devs[dev]->devc;	unsigned long	flags;	spin_lock_irqsave(&waveartist_lock, flags);	/*	 * Stop capture	 */	waveartist_cmd1(devc, WACMD_INPUTSTOP);	devc->audio_mode &= ~PCM_ENABLE_INPUT;	/*	 * Clear interrupt by toggling	 * the IRQ_ACK bit in CTRL	 */	if (inb(devc->hw.io_base + STATR) & IRQ_REQ)		waveartist_iack(devc);//	devc->audio_mode &= ~PCM_ENABLE_INPUT;	spin_unlock_irqrestore(&waveartist_lock, flags);}static voidwaveartist_halt_output(int dev){	wavnc_info	*devc = (wavnc_info *) audio_devs[dev]->devc;	unsigned long	flags;	spin_lock_irqsave(&waveartist_lock, flags);	waveartist_cmd1(devc, WACMD_OUTPUTSTOP);	devc->audio_mode &= ~PCM_ENABLE_OUTPUT;	/*	 * Clear interrupt by toggling	 * the IRQ_ACK bit in CTRL	 */	if (inb(devc->hw.io_base + STATR) & IRQ_REQ)		waveartist_iack(devc);//	devc->audio_mode &= ~PCM_ENABLE_OUTPUT;	spin_unlock_irqrestore(&waveartist_lock, flags);}static voidwaveartist_trigger(int dev, int state){	wavnc_info	*devc = (wavnc_info *) audio_devs[dev]->devc;	wavnc_port_info	*portc = (wavnc_port_info *) audio_devs[dev]->portc;	unsigned long	flags;	if (debug_flg & DEBUG_TRIGGER) {		printk("wavnc: audio trigger ");		if (state & PCM_ENABLE_INPUT)			printk("in ");		if (state & PCM_ENABLE_OUTPUT)			printk("out");		printk("\n");	}	spin_lock_irqsave(&waveartist_lock, flags);	state &= devc->audio_mode;	if (portc->open_mode & OPEN_READ &&	    state & PCM_ENABLE_INPUT)		/*		 * enable ADC Data Transfer to PC		 */		waveartist_cmd1(devc, WACMD_INPUTSTART);	if (portc->open_mode & OPEN_WRITE &&	    state & PCM_ENABLE_OUTPUT)		/*		 * enable DAC data transfer from PC		 */		waveartist_cmd1(devc, WACMD_OUTPUTSTART);	spin_unlock_irqrestore(&waveartist_lock, flags);}static intwaveartist_set_speed(int dev, int arg){	wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc;	if (arg <= 0)		return portc->speed;	if (arg < 5000)		arg = 5000;	if (arg > 44100)		arg = 44100;	portc->speed = arg;	return portc->speed;}static shortwaveartist_set_channels(int dev, short arg){	wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc;	if (arg != 1 && arg != 2)		return portc->channels;	portc->channels = arg;	return arg;}static unsigned intwaveartist_set_bits(int dev, unsigned int arg){	wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc;	if (arg == 0)		return portc->audio_format;	if ((arg != AFMT_U8) && (arg != AFMT_S16_LE) && (arg != AFMT_S8))		arg = AFMT_U8;	portc->audio_format = arg;	return arg;}static struct audio_driver waveartist_audio_driver = {	owner:		THIS_MODULE,	open:		waveartist_open,	close:		waveartist_close,	output_block:	waveartist_output_block,	start_input:	waveartist_start_input,	ioctl:		waveartist_ioctl,	prepare_for_input:	waveartist_prepare_for_input,	prepare_for_output:	waveartist_prepare_for_output,	halt_io:	waveartist_halt,	halt_input:	waveartist_halt_input,	halt_output:	waveartist_halt_output,	trigger:	waveartist_trigger,	set_speed:	waveartist_set_speed,	set_bits:	waveartist_set_bits,	set_channels:	waveartist_set_channels};static voidwaveartist_intr(int irq, void *dev_id, struct pt_regs *regs){	wavnc_info *devc = (wavnc_info *)dev_id;	int	   irqstatus, status;	irqstatus = inb(devc->hw.io_base + IRQSTAT);	status    = inb(devc->hw.io_base + STATR);	if (debug_flg & DEBUG_INTR)		printk("waveartist_intr: stat=%02x, irqstat=%02x\n",		       status, irqstatus);	if (status & IRQ_REQ)	/* Clear interrupt */		waveartist_iack(devc);	else		printk(KERN_WARNING "waveartist: unexpected interrupt\n");	if (irqstatus & 0x01) {		int temp = 1;		/* PCM buffer done		 */		if ((status & DMA0) && (devc->audio_mode & PCM_ENABLE_OUTPUT)) {			DMAbuf_outputintr(devc->playback_dev, 1);			temp = 0;		}		if ((status & DMA1) && (devc->audio_mode & PCM_ENABLE_INPUT)) {			DMAbuf_inputintr(devc->record_dev);			temp = 0;		}		if (temp)	//default:			printk(KERN_WARNING "waveartist: Unknown interrupt\n");	}	if (irqstatus & 0x2)		// We do not use SB mode natively...		printk(KERN_WARNING "waveartist: Unexpected SB interrupt...\n");}/* ------------------------------------------------------------------------- * Mixer stuff */static voidwaveartist_mixer_update(wavnc_info *devc, int whichDev){	unsigned int mask, reg_l, reg_r;	unsigned int lev_left, lev_right;	unsigned int vals[3];	lev_left  = devc->levels[whichDev] & 0xff;	lev_right = devc->levels[whichDev] >> 8;#define SCALE(lev,max)	((lev) * (max) / 100)	if (machine_is_netwinder() && whichDev == SOUND_MIXER_PHONEOUT)		whichDev = SOUND_MIXER_VOLUME;	switch(whichDev) {	case SOUND_MIXER_VOLUME:		mask  = 0x000e;		reg_l = 0x200;		reg_r = 0x600;		lev_left  = SCALE(lev_left,  7) << 1;		lev_right = SCALE(lev_right, 7) << 1;		break;	case SOUND_MIXER_LINE:		if ((devc->recmask & SOUND_MASK_LINE) == 0)			return;		mask  = 0x07c0;		reg_l = 0x000;		reg_r = 0x400;		lev_left  = SCALE(lev_left,  31) << 6;		lev_right = SCALE(lev_right, 31) << 6;		break;	case SOUND_MIXER_MIC:		if ((devc->recmask & SOUND_MASK_MIC) == 0)			return;		mask  = 0x0030;		reg_l = 0x200;		reg_r = 0x600;		lev_left  = SCALE(lev_left,  3) << 4;		lev_right = SCALE(lev_right, 3) << 4;		break;	case SOUND_MIXER_RECLEV:		mask  = 0x000f;		reg_l = 0x300;		reg_r = 0x700;		lev_left  = SCALE(lev_left,  10);		lev_right = SCALE(lev_right, 10);		break;	case SOUND_MIXER_LINE1:		if ((devc->recmask & SOUND_MASK_LINE1) == 0)			return;		mask  = 0x003e;		reg_l = 0x000;		reg_r = 0x400;		lev_left  = SCALE(lev_left,  31) << 1;		lev_right = SCALE(lev_right, 31) << 1;		break;	case SOUND_MIXER_PCM:		waveartist_cmd3(devc, WACMD_SET_LEVEL,				SCALE(lev_left,  32767),				SCALE(lev_right, 32767));		return;	case SOUND_MIXER_SYNTH:		waveartist_cmd3(devc, 0x0100 | WACMD_SET_LEVEL,				SCALE(lev_left,  32767),				SCALE(lev_right, 32767));		return;	default:		return;	}	/* read left setting */	vals[0] = reg_l + WACMD_GET_LEVEL;	waveartist_cmd(devc, 1, vals, 1, vals + 1);	/* read right setting */	vals[0] = reg_r + 0x30;	waveartist_cmd(devc, 1, vals, 1, vals + 2);	vals[1] = (vals[1] & ~mask) | (lev_left  & mask);	vals[2] = (vals[2] & ~mask) | (lev_right & mask);	/* write left,right back */	vals[0] = WACMD_SET_MIXER;	waveartist_cmd(devc, 3, vals, 0, NULL);}static voidwaveartist_select_input(wavnc_info *devc, unsigned int input){	unsigned int vals[3];	/*	 * Get reg 9	 */	vals[0] = 0x0830;	waveartist_cmd(devc, 1, vals, 1, vals + 1);	/*	 * Get reg 10, only so that we can write it back.	 */	vals[0] = 0x0930;	waveartist_cmd(devc, 1, vals, 1, vals + 2);	if (debug_flg & DEBUG_MIXER)		printk("RECSRC: old left: 0x%04X, old right: 0x%04X.\n",			vals[1] & 0x07, (vals[1] >> 3) & 0x07);	/*	 * kill current left/right mux input select	 */	vals[1] &= ~0x03F;	switch (input) {	case SOUND_MASK_MIC:		/*		 * right=mic, left=mic		 */		vals[1] |= 0x002D;		break;	case SOUND_MASK_LINE1:		/*		 * right=none, left=Aux1;		 */		vals[1] |= 0x0004;		break;	case SOUND_MASK_LINE:		/*		 * right=Line, left=Line;		 */		vals[1] |= 0x0012;		break;	}	if (debug_flg & DEBUG_MIXER)		printk("RECSRC %d: left=0x%04X, right=0x%04X.\n", input,			vals[1] & 0x07, (vals[1] >> 3) & 0x07);	/*	 * and finally - write the reg pair back....	 */	vals[0] = WACMD_SET_MIXER;	waveartist_cmd(devc, 3, vals, 0, NULL);}static intwaveartist_mixer_set(wavnc_info *devc, int whichDev, unsigned int level){	unsigned int lev_left  = level & 0x007f;	unsigned int lev_right = (level & 0x7f00) >> 8;	int left, right, devmask;	left = level & 0x7f;	right = (level & 0x7f00) >> 8;	if (debug_flg & DEBUG_MIXER)		printk("wa_mixer_set(dev=%d, level=%X)\n",			whichDev, level);	switch (whichDev) {	case SOUND_MIXER_VOLUME:	/* master volume (0-7)       */	case SOUND_MIXER_LINE:		/* external line (0-31)      */	case SOUND_MIXER_MIC:		/* mono mic (0-3)            */	case SOUND_MIXER_RECLEV:	/* recording level (0-7)     */	case SOUND_MIXER_LINE1:		/* mono external aux1 (0-31) */	case SOUND_MIXER_PCM:		/* Waveartist PCM (0-32767)  */	case SOUND_MIXER_SYNTH:		/* internal synth (0-31)     */	case SOUND_MIXER_IMIX:		/* recording feedback        */		devc->levels[whichDev] = lev_left | lev_right << 8;		waveartist_mixer_update(devc, whichDev);		break;	/* Select recording input source	 */	case SOUND_MIXER_RECSRC:		devmask = level & devc->rec_devices;#ifdef CONFIG_ARCH_NETWINDER		if (machine_is_netwinder())			vnc_configure_mixer(devc);		else#endif		{			waveartist_select_input(devc, level);			/*			 * if record monitoring is on, make sure the bit is set			 */			if (devc->levels[SOUND_MIXER_IMIX])				waveartist_mixer_update(devc, SOUND_MIXER_IMIX);		}		/*		 * do not save in "levels", return current setting		 */		return devc->recmask;	default:		return -EINVAL;	}	return devc->levels[whichDev];}static voidwaveartist_mixer_reset(wavnc_info *devc){	int i;	if (debug_flg & DEBUG_MIXER)		printk("%s: mixer_reset\n", devc->hw.name);	/*	 * reset mixer cmd	 */	waveartist_cmd1(devc, WACMD_RST_MIXER);	/*	 * set input for ADC to come from 'quiet'	 * turn on default modes	 */	waveartist_cmd3(devc, WACMD_SET_MIXER, 0x9800, 0xa836);	/*	 * set mixer input select to none, RX filter gains 0 db	 */	waveartist_cmd3(devc, WACMD_SET_MIXER, 0x4c00, 0x8c00);	/*	 * set bit 0 reg 2 to 1 - unmute MonoOut	 */	waveartist_cmd3(devc, WACMD_SET_MIXER, 0x2801, 0x6800);	/* set default input device = internal mic	 * current recording device = none	 */	devc->recmask = 0;	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)		waveartist_mixer_update(devc, i);	devc->supported_devices = SUPPORTED_MIXER_DEVICES;	devc->rec_devices = POSSIBLE_RECORDING_DEVICES;	if (machine_is_netwinder()) {		devc->supported_devices |= SOUND_MASK_PHONEIN | SOUND_MASK_PHONEOUT;		devc->rec_devices |= SOUND_MASK_PHONEIN;	}}static intwaveartist_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg){	wavnc_info *devc = (wavnc_info *)audio_devs[dev]->devc;	int ret;#ifdef CONFIG_ARCH_NETWINDER	if (machine_is_netwinder()) {		ret = vnc_private_ioctl(dev, cmd, arg);		if (ret != -ENOIOCTLCMD)			return ret;	}#endif	if (((cmd >> 8) & 0xff) == 'M') {		if (_SIOC_DIR(cmd) & _SIOC_WRITE) {			int val;			if (get_user(val, (int *)arg))				return -EFAULT;			return waveartist_mixer_set(devc, cmd & 0xff, val);		} else {			/*			 * Return parameters			 */			switch (cmd & 0xff) {			case SOUND_MIXER_RECSRC:				ret = devc->recmask;				break;			case SOUND_MIXER_DEVMASK:				ret = devc->supported_devices;				break;			case SOUND_MIXER_STEREODEVS:				ret = devc->supported_devices &					~(SOUND_MASK_SPEAKER|SOUND_MASK_IMIX);				break;			case SOUND_MIXER_RECMASK:				ret = devc->rec_devices;				break;			case SOUND_MIXER_CAPS:				ret = SOUND_CAP_EXCL_INPUT;				break;			default:				if ((cmd & 0xff) < SOUND_MIXER_NRDEVICES)					ret = devc->levels[cmd & 0xff];				else					return -EINVAL;			}			return put_user(ret, (int *)arg) ? -EFAULT : 0;		}	}	return -ENOIOCTLCMD;}static struct mixer_operations waveartist_mixer_operations ={	owner:	THIS_MODULE,	id:	"WaveArtist",	name:	"WaveArtist NetWinder",	ioctl:	waveartist_mixer_ioctl};static int __init waveartist_init(wavnc_info *devc){	wavnc_port_info *portc;	char rev[3], dev_name[64];	int my_dev;	if (waveartist_reset(devc))		return -ENODEV;	sprintf(dev_name, "%s (%s", devc->hw.name, devc->chip_name);	if (waveartist_getrev(devc, rev)) {		strcat(dev_name, " rev. ");		strcat(dev_name, rev);	}	strcat(dev_name, ")");	conf_printf2(dev_name, devc->hw.io_base, devc->hw.irq,		     devc->hw.dma, devc->hw.dma2);	portc = (wavnc_port_info *)kmalloc(sizeof(wavnc_port_info), GFP_KERNEL);	if (portc == NULL)		goto nomem;	memset(portc, 0, sizeof(wavnc_port_info));

⌨️ 快捷键说明

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