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

📄 vwsnd.c

📁 iis s3c2410-uda1341语音系统的 开发
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Sound driver for Silicon Graphics 320 and 540 Visual Workstations' * onboard audio.  See notes in ../../Documentation/sound/vwsnd . * * Copyright 1999 Silicon Graphics, Inc.  All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#undef VWSND_DEBUG			/* define for debugging *//* * XXX to do - * *	External sync. *	Rename swbuf, hwbuf, u&i, hwptr&swptr to something rational. *	Bug - if select() called before read(), pcm_setup() not called. *	Bug - output doesn't stop soon enough if process killed. *//* * Things to test - * *	Will readv/writev work?  Write a test. * *	insmod/rmmod 100 million times. * *	Run I/O until int ptrs wrap around (roughly 6.2 hours @ DAT *	rate). * *	Concurrent threads banging on mixer simultaneously, both UP *	and SMP kernels.  Especially, watch for thread A changing *	OUTSRC while thread B changes gain -- both write to the same *	ad1843 register. * *	What happens if a client opens /dev/audio then forks? *	Do two procs have /dev/audio open?  Test. * *	Pump audio through the CD, MIC and line inputs and verify that *	they mix/mute into the output. * *	Apps: *		amp *		mpg123 *		x11amp *		mxv *		kmedia *		esound *		need more input apps * *	Run tests while bombarding with signals.  setitimer(2) will do it...  *//* * This driver is organized in nine sections. * The nine sections are: * *	debug stuff * 	low level lithium access *	high level lithium access *	AD1843 access *	PCM I/O *	audio driver *	mixer driver *	probe/attach/unload *	initialization and loadable kernel module interface * * That is roughly the order of increasing abstraction, so forward * dependencies are minimal. *//* * Locking Notes * *	INC_USE_COUNT and DEC_USE_COUNT keep track of the number of *	open descriptors to this driver. They store it in vwsnd_use_count. * 	The global device list, vwsnd_dev_list,	is immutable when the IN_USE *	is true. * *	devc->open_lock is a semaphore that is used to enforce the *	single reader/single writer rule for /dev/audio.  The rule is *	that each device may have at most one reader and one writer. *	Open will block until the previous client has closed the *	device, unless O_NONBLOCK is specified. * *	The semaphore devc->io_sema serializes PCM I/O syscalls.  This *	is unnecessary in Linux 2.2, because the kernel lock *	serializes read, write, and ioctl globally, but it's there, *	ready for the brave, new post-kernel-lock world. * *	Locking between interrupt and baselevel is handled by the *	"lock" spinlock in vwsnd_port (one lock each for read and *	write).  Each half holds the lock just long enough to see what *	area it owns and update its pointers.  See pcm_output() and *	pcm_input() for most of the gory stuff. * *	devc->mix_sema serializes all mixer ioctls.  This is also *	redundant because of the kernel lock. * *	The lowest level lock is lith->lithium_lock.  It is a *	spinlock which is held during the two-register tango of *	reading/writing an AD1843 register.  See *	li_{read,write}_ad1843_reg(). *//* * Sample Format Notes * *	Lithium's DMA engine has two formats: 16-bit 2's complement *	and 8-bit unsigned .  16-bit transfers the data unmodified, 2 *	bytes per sample.  8-bit unsigned transfers 1 byte per sample *	and XORs each byte with 0x80.  Lithium can input or output *	either mono or stereo in either format. * *	The AD1843 has four formats: 16-bit 2's complement, 8-bit *	unsigned, 8-bit mu-Law and 8-bit A-Law. * *	This driver supports five formats: AFMT_S8, AFMT_U8, *	AFMT_MU_LAW, AFMT_A_LAW, and AFMT_S16_LE. * *	For AFMT_U8 output, we keep the AD1843 in 16-bit mode, and *	rely on Lithium's XOR to translate between U8 and S8. * *	For AFMT_S8, AFMT_MU_LAW and AFMT_A_LAW output, we have to XOR *	the 0x80 bit in software to compensate for Lithium's XOR. *	This happens in pcm_copy_{in,out}(). * * Changes: * 11-10-2000	Bartlomiej Zolnierkiewicz <bkz@linux-ide.org> *		Added some __init/__exit */#include <linux/module.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/semaphore.h>#include <linux/stddef.h>#include <linux/spinlock.h>#include <linux/smp_lock.h>#include <asm/fixmap.h>#include <asm/cobalt.h>#include <asm/semaphore.h>#include "sound_config.h"/*****************************************************************************//* debug stuff */#ifdef VWSND_DEBUG#include <linux/interrupt.h>		/* for in_interrupt() */static int shut_up = 1;/* * dbgassert - called when an assertion fails. */static void dbgassert(const char *fcn, int line, const char *expr){	if (in_interrupt())		panic("ASSERTION FAILED IN INTERRUPT, %s:%s:%d %s\n",		      __FILE__, fcn, line, expr);	else {		int x;		printk(KERN_ERR "ASSERTION FAILED, %s:%s:%d %s\n",		       __FILE__, fcn, line, expr);		x = * (volatile int *) 0; /* force proc to exit */	}}/* * Bunch of useful debug macros: * *	ASSERT	- print unless e nonzero (panic if in interrupt) *	DBGDO	- include arbitrary code if debugging *	DBGX	- debug print raw (w/o function name) *	DBGP	- debug print w/ function name *	DBGE	- debug print function entry *	DBGC	- debug print function call *	DBGR	- debug print function return *	DBGXV	- debug print raw when verbose *	DBGPV	- debug print when verbose *	DBGEV	- debug print function entry when verbose *	DBGRV	- debug print function return when verbose */#define ASSERT(e)      ((e) ? (void) 0 : dbgassert(__FUNCTION__, __LINE__, #e))#define DBGDO(x)            x#define DBGX(fmt, args...)  (in_interrupt() ? 0 : printk(KERN_ERR fmt, ##args))#define DBGP(fmt, args...)  (DBGX(__FUNCTION__ ": " fmt, ##args))#define DBGE(fmt, args...)  (DBGX(__FUNCTION__ fmt, ##args))#define DBGC(rtn)           (DBGP("calling %s\n", rtn))#define DBGR()              (DBGP("returning\n"))#define DBGXV(fmt, args...) (shut_up ? 0 : DBGX(fmt, ##args))#define DBGPV(fmt, args...) (shut_up ? 0 : DBGP(fmt, ##args))#define DBGEV(fmt, args...) (shut_up ? 0 : DBGE(fmt, ##args))#define DBGCV(rtn)          (shut_up ? 0 : DBGC(rtn))#define DBGRV()             (shut_up ? 0 : DBGR())#else /* !VWSND_DEBUG */#define ASSERT(e)           ((void) 0)#define DBGDO(x)            /* don't */#define DBGX(fmt, args...)  ((void) 0)#define DBGP(fmt, args...)  ((void) 0)#define DBGE(fmt, args...)  ((void) 0)#define DBGC(rtn)           ((void) 0)#define DBGR()              ((void) 0)#define DBGPV(fmt, args...) ((void) 0)#define DBGXV(fmt, args...) ((void) 0)#define DBGEV(fmt, args...) ((void) 0)#define DBGCV(rtn)          ((void) 0)#define DBGRV()             ((void) 0)#endif /* !VWSND_DEBUG *//*****************************************************************************//* low level lithium access *//* * We need to talk to Lithium registers on three pages.  Here are * the pages' offsets from the base address (0xFF001000). */enum {	LI_PAGE0_OFFSET = 0x01000 - 0x1000, /* FF001000 */	LI_PAGE1_OFFSET = 0x0F000 - 0x1000, /* FF00F000 */	LI_PAGE2_OFFSET = 0x10000 - 0x1000, /* FF010000 */};/* low-level lithium data */typedef struct lithium {	caddr_t		page0;		/* virtual addresses */	caddr_t		page1;	caddr_t		page2;	spinlock_t	lock;		/* protects codec and UST/MSC access */} lithium_t;/* * li_create initializes the lithium_t structure and sets up vm mappings * to access the registers. * Returns 0 on success, -errno on failure. */static int li_create(lithium_t *lith, unsigned long baseaddr){	static void li_destroy(lithium_t *);	lith->lock = SPIN_LOCK_UNLOCKED;	lith->page0 = ioremap_nocache(baseaddr + LI_PAGE0_OFFSET, PAGE_SIZE);	lith->page1 = ioremap_nocache(baseaddr + LI_PAGE1_OFFSET, PAGE_SIZE);	lith->page2 = ioremap_nocache(baseaddr + LI_PAGE2_OFFSET, PAGE_SIZE);	if (!lith->page0 || !lith->page1 || !lith->page2) {		li_destroy(lith);		return -ENOMEM;	}	return 0;}/* * li_destroy destroys the lithium_t structure and vm mappings. */static void li_destroy(lithium_t *lith){	if (lith->page0) {		iounmap(lith->page0);		lith->page0 = NULL;	}	if (lith->page1) {		iounmap(lith->page1);		lith->page1 = NULL;	}	if (lith->page2) {		iounmap(lith->page2);		lith->page2 = NULL;	}}/* * basic register accessors - read/write long/byte */static __inline__ unsigned long li_readl(lithium_t *lith, int off){	return * (volatile unsigned long *) (lith->page0 + off);}static __inline__ unsigned char li_readb(lithium_t *lith, int off){	return * (volatile unsigned char *) (lith->page0 + off);}static __inline__ void li_writel(lithium_t *lith, int off, unsigned long val){	* (volatile unsigned long *) (lith->page0 + off) = val;}static __inline__ void li_writeb(lithium_t *lith, int off, unsigned char val){	* (volatile unsigned char *) (lith->page0 + off) = val;}/*****************************************************************************//* High Level Lithium Access *//* * Lithium DMA Notes * * Lithium has two dedicated DMA channels for audio.  They are known * as comm1 and comm2 (communication areas 1 and 2).  Comm1 is for * input, and comm2 is for output.  Each is controlled by three * registers: BASE (base address), CFG (config) and CCTL * (config/control). * * Each DMA channel points to a physically contiguous ring buffer in * main memory of up to 8 Kbytes.  (This driver always uses 8 Kb.) * There are three pointers into the ring buffer: read, write, and * trigger.  The pointers are 8 bits each.  Each pointer points to * 32-byte "chunks" of data.  The DMA engine moves 32 bytes at a time, * so there is no finer-granularity control. * * In comm1, the hardware updates the write ptr, and software updates * the read ptr.  In comm2, it's the opposite: hardware updates the * read ptr, and software updates the write ptr.  I designate the * hardware-updated ptr as the hwptr, and the software-updated ptr as * the swptr. * * The trigger ptr and trigger mask are used to trigger interrupts. * From the Lithium spec, section 5.6.8, revision of 12/15/1998: * *	Trigger Mask Value * *	A three bit wide field that represents a power of two mask *	that is used whenever the trigger pointer is compared to its *	respective read or write pointer.  A value of zero here *	implies a mask of 0xFF and a value of seven implies a mask *	0x01.  This value can be used to sub-divide the ring buffer *	into pie sections so that interrupts monitor the progress of *	hardware from section to section. * * My interpretation of that is, whenever the hw ptr is updated, it is * compared with the trigger ptr, and the result is masked by the * trigger mask.  (Actually, by the complement of the trigger mask.) * If the result is zero, an interrupt is triggered.  I.e., interrupt * if ((hwptr & ~mask) == (trptr & ~mask)).  The mask is formed from * the trigger register value as mask = (1 << (8 - tmreg)) - 1. * * In yet different words, setting tmreg to 0 causes an interrupt after * every 256 DMA chunks (8192 bytes) or once per traversal of the * ring buffer.  Setting it to 7 caues an interrupt every 2 DMA chunks * (64 bytes) or 128 times per traversal of the ring buffer. *//* Lithium register offsets and bit definitions */#define LI_HOST_CONTROLLER	0x000# define LI_HC_RESET		 0x00008000# define LI_HC_LINK_ENABLE	 0x00004000# define LI_HC_LINK_FAILURE	 0x00000004# define LI_HC_LINK_CODEC	 0x00000002# define LI_HC_LINK_READY	 0x00000001#define LI_INTR_STATUS		0x010#define LI_INTR_MASK		0x014# define LI_INTR_LINK_ERR	 0x00008000# define LI_INTR_COMM2_TRIG	 0x00000008# define LI_INTR_COMM2_UNDERFLOW 0x00000004# define LI_INTR_COMM1_TRIG	 0x00000002# define LI_INTR_COMM1_OVERFLOW  0x00000001#define LI_CODEC_COMMAND	0x018# define LI_CC_BUSY		 0x00008000# define LI_CC_DIR		 0x00000080#  define LI_CC_DIR_RD		  LI_CC_DIR#  define LI_CC_DIR_WR		(!LI_CC_DIR)# define LI_CC_ADDR_MASK	 0x0000007F#define LI_CODEC_DATA		0x01C#define LI_COMM1_BASE		0x100#define LI_COMM1_CTL		0x104# define LI_CCTL_RESET		 0x80000000# define LI_CCTL_SIZE		 0x70000000# define LI_CCTL_DMA_ENABLE	 0x08000000# define LI_CCTL_TMASK		 0x07000000 /* trigger mask */# define LI_CCTL_TPTR		 0x00FF0000 /* trigger pointer */# define LI_CCTL_RPTR		 0x0000FF00# define LI_CCTL_WPTR		 0x000000FF#define LI_COMM1_CFG		0x108# define LI_CCFG_LOCK		 0x00008000# define LI_CCFG_SLOT		 0x00000070# define LI_CCFG_DIRECTION	 0x00000008#  define LI_CCFG_DIR_IN	(!LI_CCFG_DIRECTION)#  define LI_CCFG_DIR_OUT	  LI_CCFG_DIRECTION# define LI_CCFG_MODE		 0x00000004#  define LI_CCFG_MODE_MONO	(!LI_CCFG_MODE)#  define LI_CCFG_MODE_STEREO	  LI_CCFG_MODE# define LI_CCFG_FORMAT		 0x00000003#  define LI_CCFG_FMT_8BIT	  0x00000000#  define LI_CCFG_FMT_16BIT	  0x00000001#define LI_COMM2_BASE		0x10C#define LI_COMM2_CTL		0x110 /* bit definitions are the same as LI_COMM1_CTL */#define LI_COMM2_CFG		0x114 /* bit definitions are the same as LI_COMM1_CFG */#define LI_UST_LOW		0x200	/* 64-bit Unadjusted System Time is */#define LI_UST_HIGH		0x204	/* microseconds since boot */#define LI_AUDIO1_UST		0x300	/* UST-MSC pairs */#define LI_AUDIO1_MSC		0x304	/* MSC (Media Stream Counter) */#define LI_AUDIO2_UST		0x308	/* counts samples actually */#define LI_AUDIO2_MSC		0x30C	/* processed as of time UST *//*  * Lithium's DMA engine operates on chunks of 32 bytes.  We call that * a DMACHUNK. */#define DMACHUNK_SHIFT 5#define DMACHUNK_SIZE (1 << DMACHUNK_SHIFT)#define BYTES_TO_CHUNKS(bytes) ((bytes) >> DMACHUNK_SHIFT)#define CHUNKS_TO_BYTES(chunks) ((chunks) << DMACHUNK_SHIFT)/* * Two convenient macros to shift bitfields into/out of position. * * Observe that (mask & -mask) is (1 << low_set_bit_of(mask)). * As long as mask is constant, we trust the compiler will change the * multipy and divide into shifts. */#define SHIFT_FIELD(val, mask) (((val) * ((mask) & -(mask))) & (mask))#define UNSHIFT_FIELD(val, mask) (((val) & (mask)) / ((mask) & -(mask)))/*

⌨️ 快捷键说明

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