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

📄 waveartist.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 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/smp.h>#include <linux/spinlock.h>#include <asm/hardware.h>#include <asm/mach-types.h>#include <asm/system.h>#include "sound_config.h"#include "waveartist.h"#ifndef _ISA_DMA#define _ISA_DMA(x) (x)#endif#ifndef _ISA_IRQ#define _ISA_IRQ(x) (x)#endif#define POSSIBLE_RECORDING_DEVICES	(SOUND_MASK_LINE       |\					 SOUND_MASK_MIC	       |\					 SOUND_MASK_LINE1)#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			 */	0x0000,		/* PC Speaker		 */	0x0000,		/* Ext Line		 */	0x0000,		/* Mic			 */	0x0000,		/* CD			 */	0x0000,		/* Recording monitor	 */	0x0000,		/* SB PCM (ALT PCM)	 */	0x0000,		/* Recording level	 */	0x0000,		/* Input gain		 */	0x0000,		/* Output gain		 */	0x0000,		/* Line1 (Aux1)		 */	0x0000,		/* Line2 (Aux2)		 */	0x0000,		/* Line3 (Aux3)		 */	0x0000,		/* Digital1		 */	0x0000,		/* Digital2		 */	0x0000,		/* Digital3		 */	0x0000,		/* Phone In		 */	0x0000,		/* 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 */	unsigned short	*levels;	   /* cache of volume settings   */	int		recmask;	   /* currently enabled recording device! */	int             supported_devices; /* SUPPORTED_MIXER_DEVICES    */	int             rec_devices;	   /* POSSIBLE_RECORDING_DEVICES */#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;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 machine_is_netwinder#define machine_is_netwinder() 0#endifstatic struct timer_list vnc_timer;static void vnc_configure_mixer(wavnc_info *devc);static int vnc_private_ioctl(int dev, unsigned int cmd, caddr_t arg);static void vnc_slider_tick(unsigned long data);static 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 {		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");	}	if (inb(io_base + STATR) & CMD_RF) {		int old_data;		/* flush the port		 */		old_data = inw(io_base + CMDR);		if (debug_flg & DEBUG_CMD)			printk("flushed %04X...", old_data);		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) {		if (!timed_out) {			printk("waveartist_cmd: resp=");			for (i = 0; i < nr_resp; i++)				printk("%04X ", resp[i]);			printk("\n");		} else			printk("waveartist_cmd: timed out\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) {		devc->audio_mode |= PCM_ENABLE_INPUT;		return;	/*			 * Auto DMA mode on. No need to react			 */	}	spin_lock_irqsave(&waveartist_lock, flags);	/*	 * set sample count	 */	waveartist_cmd2(devc, WACMD_INPUTSIZE, count);	devc->xfer_count = count;	devc->audio_mode |= PCM_ENABLE_INPUT;	spin_unlock_irqrestore(&waveartist_lock, flags);}static intwaveartist_ioctl(int dev, unsigned int cmd, caddr_t arg){	return -EINVAL;}static unsigned intwaveartist_get_speed(wavnc_port_info *portc){	unsigned int speed;	/*	 * program the speed, channels, bits	 */	if (portc->speed == 8000)		speed = 0x2E71;	else if (portc->speed == 11025)		speed = 0x4000;	else if (portc->speed == 22050)		speed = 0x8000;	else if (portc->speed == 44100)		speed = 0x0;	else {		/*		 * non-standard - just calculate		 */		speed = portc->speed << 16;		speed = (speed / 44100) & 65535;	}	return speed;}static unsigned intwaveartist_get_bits(wavnc_port_info *portc){	unsigned int bits;	if (portc->audio_format == AFMT_S16_LE)		bits = 1;	else if (portc->audio_format == AFMT_S8)		bits = 0;	else		bits = 2;	//default AFMT_U8	return bits;}static intwaveartist_prepare_for_input(int dev, int bsize, int bcount){	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;	if (devc->audio_mode)		return 0;	speed = waveartist_get_speed(portc);	bits  = waveartist_get_bits(portc);	spin_lock_irqsave(&waveartist_lock, flags);	if (waveartist_cmd2(devc, WACMD_INPUTFORMAT, bits))		printk(KERN_WARNING "waveartist: error setting the "		       "record format to %d\n", portc->audio_format);	if (waveartist_cmd2(devc, WACMD_INPUTCHANNELS, portc->channels))		printk(KERN_WARNING "waveartist: error setting record "		       "to %d channels\n", portc->channels);	/*	 * write cmd SetSampleSpeedTimeConstant	 */	if (waveartist_cmd2(devc, WACMD_INPUTSPEED, speed))		printk(KERN_WARNING "waveartist: error setting the record "		       "speed to %dHz.\n", portc->speed);	if (waveartist_cmd2(devc, WACMD_INPUTDMA, 1))		printk(KERN_WARNING "waveartist: error setting the record "		       "data path to 0x%X\n", 1);	if (waveartist_cmd2(devc, WACMD_INPUTFORMAT, bits))		printk(KERN_WARNING "waveartist: error setting the record "		       "format to %d\n", portc->audio_format);	devc->xfer_count = 0;	spin_unlock_irqrestore(&waveartist_lock, flags);	waveartist_halt_input(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 intwaveartist_prepare_for_output(int dev, int bsize, int bcount)

⌨️ 快捷键说明

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