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

📄 waveartist.c

📁 iis s3c2410-uda1341语音系统的 开发
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * linux/drivers/sound/waveartist.c * * The low level driver for the RWA010 Rockwell Wave Artist * codec chip used in the Rebel.com NetWinder. * * Cleaned up and integrated into 2.1 by Russell King (rmk@arm.linux.org.uk) * and Pat Beirne (patb@corel.ca) * * * Copyright (C) by Rebel.com 1998-1999 * * RWA010 specs received under NDA from Rockwell * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. * * Changes: * 11-10-2000	Bartlomiej Zolnierkiewicz <bkz@linux-ide.org> *		Added __init to waveartist_init() *//* Debugging */#define DEBUG_CMD	1#define DEBUG_OUT	2#define DEBUG_IN	4#define DEBUG_INTR	8#define DEBUG_MIXER	16#define DEBUG_TRIGGER	32#define debug_flg (0)#include <linux/module.h>#include <linux/init.h>#include <linux/config.h>#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <linux/spinlock.h>#include <linux/bitops.h>#include <asm/system.h>#include "sound_config.h"#include "waveartist.h"#ifdef CONFIG_ARM#include <asm/hardware.h>#include <asm/mach-types.h>#endif#ifndef NO_DMA#define NO_DMA	255#endif#define SUPPORTED_MIXER_DEVICES		(SOUND_MASK_SYNTH      |\					 SOUND_MASK_PCM        |\					 SOUND_MASK_LINE       |\					 SOUND_MASK_MIC        |\					 SOUND_MASK_LINE1      |\					 SOUND_MASK_RECLEV     |\					 SOUND_MASK_VOLUME     |\					 SOUND_MASK_IMIX)static unsigned short levels[SOUND_MIXER_NRDEVICES] = {	0x5555,		/* Master Volume	 */	0x0000,		/* Bass			 */	0x0000,		/* Treble		 */	0x2323,		/* Synth (FM)		 */	0x4b4b,		/* PCM			 */	0x6464,		/* PC Speaker		 */	0x0000,		/* Ext Line		 */	0x0000,		/* Mic			 */	0x0000,		/* CD			 */	0x6464,		/* Recording monitor	 */	0x0000,		/* SB PCM (ALT PCM)	 */	0x0000,		/* Recording level	 */	0x6464,		/* Input gain		 */	0x6464,		/* Output gain		 */	0x0000,		/* Line1 (Aux1)		 */	0x0000,		/* Line2 (Aux2)		 */	0x0000,		/* Line3 (Aux3)		 */	0x0000,		/* Digital1		 */	0x0000,		/* Digital2		 */	0x0000,		/* Digital3		 */	0x0000,		/* Phone In		 */	0x6464,		/* Phone Out		 */	0x0000,		/* Video		 */	0x0000,		/* Radio		 */	0x0000		/* Monitor		 */};typedef struct {	struct address_info  hw;	/* hardware */	char		*chip_name;	int		xfer_count;	int		audio_mode;	int		open_mode;	int		audio_flags;	int		record_dev;	int		playback_dev;	int		dev_no;	/* Mixer parameters */	const struct waveartist_mixer_info *mix;	unsigned short	*levels;	   /* cache of volume settings   */	int		recmask;	   /* currently enabled recording device! */#ifdef CONFIG_ARCH_NETWINDER	signed int	slider_vol;	   /* hardware slider volume     */	unsigned int	handset_detect	:1;	unsigned int	telephone_detect:1;	unsigned int	no_autoselect	:1;/* handset/telephone autoselects a path */	unsigned int	spkr_mute_state	:1;/* set by ioctl or autoselect */	unsigned int	line_mute_state	:1;/* set by ioctl or autoselect */	unsigned int	use_slider	:1;/* use slider setting for o/p vol */#endif} wavnc_info;/* * This is the implementation specific mixer information. */struct waveartist_mixer_info {	unsigned int	supported_devs;	   /* Supported devices */	unsigned int	recording_devs;	   /* Recordable devies */	unsigned int	stereo_devs;	   /* Stereo devices	*/	unsigned int	(*select_input)(wavnc_info *, unsigned int,					unsigned char *, unsigned char *);	int		(*decode_mixer)(wavnc_info *, int,					unsigned char, unsigned char);	int		(*get_mixer)(wavnc_info *, int);};typedef struct wavnc_port_info {	int		open_mode;	int		speed;	int		channels;	int		audio_format;} wavnc_port_info;static int		nr_waveartist_devs;static wavnc_info	adev_info[MAX_AUDIO_DEV];static spinlock_t	waveartist_lock = SPIN_LOCK_UNLOCKED;#ifndef CONFIG_ARCH_NETWINDER#define machine_is_netwinder() 0#elsestatic struct timer_list vnc_timer;static void vnc_configure_mixer(wavnc_info *devc, unsigned int input_mask);static int vnc_private_ioctl(int dev, unsigned int cmd, caddr_t arg);static void vnc_slider_tick(unsigned long data);#endifstatic inline voidwaveartist_set_ctlr(struct address_info *hw, unsigned char clear, unsigned char set){	unsigned int ctlr_port = hw->io_base + CTLR;	clear = ~clear & inb(ctlr_port);	outb(clear | set, ctlr_port);}/* Toggle IRQ acknowledge line */static inline voidwaveartist_iack(wavnc_info *devc){	unsigned int ctlr_port = devc->hw.io_base + CTLR;	int old_ctlr;	old_ctlr = inb(ctlr_port) & ~IRQ_ACK;	outb(old_ctlr | IRQ_ACK, ctlr_port);	outb(old_ctlr, ctlr_port);}static inline intwaveartist_sleep(int timeout_ms){	unsigned int timeout = timeout_ms * 10 * HZ / 100;	do {		set_current_state(TASK_INTERRUPTIBLE);		timeout = schedule_timeout(timeout);	} while (timeout);	return 0;}static intwaveartist_reset(wavnc_info *devc){	struct address_info *hw = &devc->hw;	unsigned int timeout, res = -1;	waveartist_set_ctlr(hw, -1, RESET);	waveartist_sleep(2);	waveartist_set_ctlr(hw, RESET, 0);	timeout = 500;	do {		mdelay(2);		if (inb(hw->io_base + STATR) & CMD_RF) {			res = inw(hw->io_base + CMDR);			if (res == 0x55aa)				break;		}	} while (--timeout);	if (timeout == 0) {		printk(KERN_WARNING "WaveArtist: reset timeout ");		if (res != (unsigned int)-1)			printk("(res=%04X)", res);		printk("\n");		return 1;	}	return 0;}/* Helper function to send and receive words * from WaveArtist.  It handles all the handshaking * and can send or receive multiple words. */static intwaveartist_cmd(wavnc_info *devc,		int nr_cmd, unsigned int *cmd,		int nr_resp, unsigned int *resp){	unsigned int io_base = devc->hw.io_base;	unsigned int timed_out = 0;	unsigned int i;	if (debug_flg & DEBUG_CMD) {		printk("waveartist_cmd: cmd=");		for (i = 0; i < nr_cmd; i++)			printk("%04X ", cmd[i]);		printk("\n");	}	/*	 * flush any stale command data from the port.	 */	while (inb(io_base + STATR) & CMD_RF) {		unsigned int old_data;		old_data = inw(io_base + CMDR);		printk("waveartist: flushing stale command data: 0x%04x pc=%p\n",		       old_data, __builtin_return_address(0));		udelay(10);	}	for (i = 0; !timed_out && i < nr_cmd; i++) {		int count;		for (count = 5000; count; count--)			if (inb(io_base + STATR) & CMD_WE)				break;		if (!count)			timed_out = 1;		else			outw(cmd[i], io_base + CMDR);	}	for (i = 0; !timed_out && i < nr_resp; i++) {		int count;		for (count = 5000; count; count--)			if (inb(io_base + STATR) & CMD_RF)				break;		if (!count)			timed_out = 1;		else			resp[i] = inw(io_base + CMDR);	}	if (debug_flg & DEBUG_CMD && !timed_out) {		printk("waveartist_cmd: resp=");		for (i = 0; i < nr_resp; i++)			printk("%04X ", resp[i]);		printk("\n");	}	if (timed_out) {		printk(KERN_ERR "waveartist_cmd: command timed out:");		for (i = 0; i < nr_cmd; i++)			printk(" %04x", cmd[i]);		printk("\n");	}	return timed_out ? 1 : 0;}/* * Send one command word */static inline intwaveartist_cmd1(wavnc_info *devc, unsigned int cmd){	return waveartist_cmd(devc, 1, &cmd, 0, NULL);}/* * Send one command, receive one word */static inline unsigned intwaveartist_cmd1_r(wavnc_info *devc, unsigned int cmd){	unsigned int ret;	waveartist_cmd(devc, 1, &cmd, 1, &ret);	return ret;}/* * Send a double command, receive one * word (and throw it away) */static inline intwaveartist_cmd2(wavnc_info *devc, unsigned int cmd, unsigned int arg){	unsigned int vals[2];	vals[0] = cmd;	vals[1] = arg;	return waveartist_cmd(devc, 2, vals, 1, vals);}/* * Send a triple command */static inline intwaveartist_cmd3(wavnc_info *devc, unsigned int cmd,		unsigned int arg1, unsigned int arg2){	unsigned int vals[3];	vals[0] = cmd;	vals[1] = arg1;	vals[2] = arg2;	return waveartist_cmd(devc, 3, vals, 0, NULL);}static intwaveartist_getrev(wavnc_info *devc, char *rev){	unsigned int temp[2];	unsigned int cmd = WACMD_GETREV;	waveartist_cmd(devc, 1, &cmd, 2, temp);	rev[0] = temp[0] >> 8;	rev[1] = temp[0] & 255;	rev[2] = '\0';	return temp[0];}static void waveartist_halt_output(int dev);static void waveartist_halt_input(int dev);static void waveartist_halt(int dev);static void waveartist_trigger(int dev, int state);static intwaveartist_open(int dev, int mode){	wavnc_info	*devc;	wavnc_port_info	*portc;	unsigned long	flags;	if (dev < 0 || dev >= num_audiodevs)		return -ENXIO;	devc  = (wavnc_info *) audio_devs[dev]->devc;	portc = (wavnc_port_info *) audio_devs[dev]->portc;	spin_lock_irqsave(&waveartist_lock, flags);	if (portc->open_mode || (devc->open_mode & mode)) {		spin_unlock_irqrestore(&waveartist_lock, flags);		return -EBUSY;	}	devc->audio_mode  = 0;	devc->open_mode  |= mode;	portc->open_mode  = mode;	waveartist_trigger(dev, 0);	if (mode & OPEN_READ)		devc->record_dev = dev;	if (mode & OPEN_WRITE)		devc->playback_dev = dev;	spin_unlock_irqrestore(&waveartist_lock, flags);	return 0;}static voidwaveartist_close(int dev){	wavnc_info	*devc = (wavnc_info *) audio_devs[dev]->devc;	wavnc_port_info	*portc = (wavnc_port_info *) audio_devs[dev]->portc;	unsigned long	flags;	spin_lock_irqsave(&waveartist_lock, flags);	waveartist_halt(dev);	devc->audio_mode = 0;	devc->open_mode &= ~portc->open_mode;	portc->open_mode = 0;	spin_unlock_irqrestore(&waveartist_lock, flags);}static voidwaveartist_output_block(int dev, unsigned long buf, int __count, int intrflag){	wavnc_port_info	*portc = (wavnc_port_info *) audio_devs[dev]->portc;	wavnc_info	*devc = (wavnc_info *) audio_devs[dev]->devc;	unsigned long	flags;	unsigned int	count = __count; 	if (debug_flg & DEBUG_OUT)		printk("waveartist: output block, buf=0x%lx, count=0x%x...\n",			buf, count);	/*	 * 16 bit data	 */	if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE))		count >>= 1;	if (portc->channels > 1)		count >>= 1;	count -= 1;	if (devc->audio_mode & PCM_ENABLE_OUTPUT &&	    audio_devs[dev]->flags & DMA_AUTOMODE &&	    intrflag &&	    count == devc->xfer_count) {		devc->audio_mode |= PCM_ENABLE_OUTPUT;		return;	/*			 * Auto DMA mode on. No need to react			 */	}	spin_lock_irqsave(&waveartist_lock, flags);	/*	 * set sample count	 */	waveartist_cmd2(devc, WACMD_OUTPUTSIZE, count);	devc->xfer_count = count;	devc->audio_mode |= PCM_ENABLE_OUTPUT;	spin_unlock_irqrestore(&waveartist_lock, flags);}static voidwaveartist_start_input(int dev, unsigned long buf, int __count, int intrflag){	wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc;	wavnc_info	*devc = (wavnc_info *) audio_devs[dev]->devc;	unsigned long	flags;	unsigned int	count = __count;	if (debug_flg & DEBUG_IN)		printk("waveartist: start input, buf=0x%lx, count=0x%x...\n",			buf, count);	if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE))	/* 16 bit data */		count >>= 1;	if (portc->channels > 1)		count >>= 1;	count -= 1;	if (devc->audio_mode & PCM_ENABLE_INPUT &&	    audio_devs[dev]->flags & DMA_AUTOMODE &&	    intrflag &&	    count == devc->xfer_count) {		return;	/*			 * Auto DMA mode on. No need to react			 */	}	spin_lock_irqsave(&waveartist_lock, flags);	/*	 * set sample count	 */

⌨️ 快捷键说明

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