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

📄 forte.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * forte.c - ForteMedia FM801 OSS Driver * * Written by Martin K. Petersen <mkp@mkp.net> * Copyright (C) 2002 Hewlett-Packard Company * Portions Copyright (C) 2003 Martin K. Petersen * * Latest version: http://mkp.net/forte/ * * Based upon the ALSA FM801 driver by Jaroslav Kysela and OSS drivers * by Thomas Sailer, Alan Cox, Zach Brown, and Jeff Garzik.  Thanks * guys! * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 as published by the Free Software Foundation. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * */ #include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/spinlock.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/poll.h>#include <linux/sound.h>#include <linux/ac97_codec.h>#include <linux/interrupt.h>#include <linux/proc_fs.h>#include <asm/uaccess.h>#include <asm/io.h>#define DRIVER_NAME	"forte"#define DRIVER_VERSION 	"$Id: forte.c,v 1.63 2003/03/01 05:32:42 mkp Exp $"#define PFX 		DRIVER_NAME ": "#undef M_DEBUG#ifdef M_DEBUG#define DPRINTK(args...) printk(KERN_WARNING args)#else#define DPRINTK(args...)#endif/* Card capabilities */#define FORTE_CAPS              (DSP_CAP_MMAP | DSP_CAP_TRIGGER)/* Supported audio formats */#define FORTE_FMTS		(AFMT_U8 | AFMT_S16_LE)/* Buffers */#define FORTE_MIN_FRAG_SIZE     256#define FORTE_MAX_FRAG_SIZE     PAGE_SIZE#define FORTE_DEF_FRAG_SIZE     256#define FORTE_MIN_FRAGMENTS     2#define FORTE_MAX_FRAGMENTS     256#define FORTE_DEF_FRAGMENTS     2#define FORTE_MIN_BUF_MSECS     500#define FORTE_MAX_BUF_MSECS     1000/* PCI BARs */#define FORTE_PCM_VOL           0x00    /* PCM Output Volume */#define FORTE_FM_VOL            0x02    /* FM Output Volume */#define FORTE_I2S_VOL           0x04    /* I2S Volume */#define FORTE_REC_SRC           0x06    /* Record Source */#define FORTE_PLY_CTRL          0x08    /* Playback Control */#define FORTE_PLY_COUNT         0x0a    /* Playback Count */#define FORTE_PLY_BUF1          0x0c    /* Playback Buffer I */#define FORTE_PLY_BUF2          0x10    /* Playback Buffer II */#define FORTE_CAP_CTRL          0x14    /* Capture Control */#define FORTE_CAP_COUNT         0x16    /* Capture Count */#define FORTE_CAP_BUF1          0x18    /* Capture Buffer I */#define FORTE_CAP_BUF2          0x1c    /* Capture Buffer II */#define FORTE_CODEC_CTRL        0x22    /* Codec Control */#define FORTE_I2S_MODE          0x24    /* I2S Mode Control */#define FORTE_VOLUME            0x26    /* Volume Up/Down/Mute Status */#define FORTE_I2C_CTRL          0x29    /* I2C Control */#define FORTE_AC97_CMD          0x2a    /* AC'97 Command */#define FORTE_AC97_DATA         0x2c    /* AC'97 Data */#define FORTE_MPU401_DATA       0x30    /* MPU401 Data */#define FORTE_MPU401_CMD        0x31    /* MPU401 Command */#define FORTE_GPIO_CTRL         0x52    /* General Purpose I/O Control */#define FORTE_GEN_CTRL          0x54    /* General Control */#define FORTE_IRQ_MASK          0x56    /* Interrupt Mask */#define FORTE_IRQ_STATUS        0x5a    /* Interrupt Status */#define FORTE_OPL3_BANK0        0x68    /* OPL3 Status Read / Bank 0 Write */#define FORTE_OPL3_DATA0        0x69    /* OPL3 Data 0 Write */#define FORTE_OPL3_BANK1        0x6a    /* OPL3 Bank 1 Write */#define FORTE_OPL3_DATA1        0x6b    /* OPL3 Bank 1 Write */#define FORTE_POWERDOWN         0x70    /* Blocks Power Down Control */#define FORTE_CAP_OFFSET        FORTE_CAP_CTRL - FORTE_PLY_CTRL#define FORTE_AC97_ADDR_SHIFT   10/* Playback and record control register bits */#define FORTE_BUF1_LAST         (1<<1)#define FORTE_BUF2_LAST         (1<<2)#define FORTE_START             (1<<5)#define FORTE_PAUSE             (1<<6)#define FORTE_IMMED_STOP        (1<<7)#define FORTE_RATE_SHIFT        8#define FORTE_RATE_MASK         (15 << FORTE_RATE_SHIFT)#define FORTE_CHANNELS_4        (1<<12) /* Playback only */#define FORTE_CHANNELS_6        (2<<12) /* Playback only */#define FORTE_CHANNELS_6MS      (3<<12) /* Playback only */#define FORTE_CHANNELS_MASK     (3<<12)#define FORTE_16BIT             (1<<14)#define FORTE_STEREO            (1<<15)/* IRQ status bits */#define FORTE_IRQ_PLAYBACK      (1<<8)#define FORTE_IRQ_CAPTURE       (1<<9)#define FORTE_IRQ_VOLUME        (1<<14)#define FORTE_IRQ_MPU           (1<<15)/* CODEC control */#define FORTE_CC_CODEC_RESET    (1<<5)#define FORTE_CC_AC97_RESET     (1<<6)/* AC97 cmd */#define FORTE_AC97_WRITE        (0<<7)#define FORTE_AC97_READ         (1<<7)#define FORTE_AC97_DP_INVALID   (0<<8)#define FORTE_AC97_DP_VALID     (1<<8)#define FORTE_AC97_PORT_RDY     (0<<9)#define FORTE_AC97_PORT_BSY     (1<<9)struct forte_channel {        const char 		*name;	unsigned short		ctrl; 		/* Ctrl BAR contents */	unsigned long 		iobase;		/* Ctrl BAR address */	wait_queue_head_t	wait;	void 			*buf; 		/* Buffer */	dma_addr_t		buf_handle; 	/* Buffer handle */        unsigned int 		record;	unsigned int		format;        unsigned int		rate;	unsigned int		stereo;	unsigned int		frag_sz; 	/* Current fragment size */	unsigned int		frag_num; 	/* Current # of fragments */	unsigned int		frag_msecs;     /* Milliseconds per frag */	unsigned int		buf_sz;		/* Current buffer size */	unsigned int		hwptr;		/* Tail */	unsigned int		swptr; 		/* Head */	unsigned int		filled_frags; 	/* Fragments currently full */	unsigned int		next_buf;	/* Index of next buffer */	unsigned int		active;		/* Channel currently in use */	unsigned int		mapped;		/* mmap */	unsigned int		buf_pages;	/* Real size of buffer */	unsigned int		nr_irqs;	/* Number of interrupts */	unsigned int		bytes;		/* Total bytes */	unsigned int		residue;	/* Partial fragment */};struct forte_chip {	struct pci_dev		*pci_dev;	unsigned long		iobase;	int			irq;	struct semaphore	open_sem; 	/* Device access */	spinlock_t		lock;		/* State */	spinlock_t		ac97_lock;	struct ac97_codec	*ac97;	int			multichannel;	int			dsp; 		/* OSS handle */	int                     trigger;	/* mmap I/O trigger */	struct forte_channel	play;	struct forte_channel	rec;};static int channels[] = { 2, 4, 6, };static int rates[]    = { 5500, 8000, 9600, 11025, 16000, 19200, 			  22050, 32000, 38400, 44100, 48000, };static struct forte_chip *forte;static int found;/* AC97 Codec -------------------------------------------------------------- *//**  * forte_ac97_wait: * @chip:	fm801 instance whose AC97 codec to wait on * * FIXME: *		Stop busy-waiting */static inline intforte_ac97_wait (struct forte_chip *chip){	int i = 10000;	while ( (inw (chip->iobase + FORTE_AC97_CMD) & FORTE_AC97_PORT_BSY) 		&& i-- )		cpu_relax();	return i == 0;}/** * forte_ac97_read: * @codec:	AC97 codec to read from * @reg:	register to read */u16forte_ac97_read (struct ac97_codec *codec, u8 reg){	u16 ret = 0;	struct forte_chip *chip = codec->private_data;	spin_lock (&chip->ac97_lock);	/* Knock, knock */	if (forte_ac97_wait (chip)) {		printk (KERN_ERR PFX "ac97_read: Serial bus busy\n");		goto out;	}	/* Send read command */	outw (reg | (1<<7), chip->iobase + FORTE_AC97_CMD);	if (forte_ac97_wait (chip)) {		printk (KERN_ERR PFX "ac97_read: Bus busy reading reg 0x%x\n",			reg);		goto out;	}		/* Sanity checking */	if (inw (chip->iobase + FORTE_AC97_CMD) & FORTE_AC97_DP_INVALID) {		printk (KERN_ERR PFX "ac97_read: Invalid data port");		goto out;	}	/* Fetch result */	ret = inw (chip->iobase + FORTE_AC97_DATA); out:	spin_unlock (&chip->ac97_lock);	return ret;}/** * forte_ac97_write: * @codec:	AC97 codec to send command to * @reg:	register to write * @val:	value to write */voidforte_ac97_write (struct ac97_codec *codec, u8 reg, u16 val){	struct forte_chip *chip = codec->private_data;	spin_lock (&chip->ac97_lock);	/* Knock, knock */	if (forte_ac97_wait (chip)) {		printk (KERN_ERR PFX "ac97_write: Serial bus busy\n");		goto out;	}	outw (val, chip->iobase + FORTE_AC97_DATA);	outb (reg | FORTE_AC97_WRITE, chip->iobase + FORTE_AC97_CMD);	/* Wait for completion */	if (forte_ac97_wait (chip)) {		printk (KERN_ERR PFX "ac97_write: Bus busy after write\n");		goto out;	} out:	spin_unlock (&chip->ac97_lock);}/* Mixer ------------------------------------------------------------------- *//** * forte_mixer_open: * @inode:		 * @file:		 */static intforte_mixer_open (struct inode *inode, struct file *file){	struct forte_chip *chip = forte;	file->private_data = chip->ac97;	return 0;}/** * forte_mixer_release: * @inode:		 * @file:		 */static intforte_mixer_release (struct inode *inode, struct file *file){	/* We will welease Wodewick */	return 0;}/** * forte_mixer_ioctl: * @inode:		 * @file:		 */static intforte_mixer_ioctl (struct inode *inode, struct file *file, 		   unsigned int cmd, unsigned long arg){	struct ac97_codec *codec = (struct ac97_codec *) file->private_data;	return codec->mixer_ioctl (codec, cmd, arg);}static struct file_operations forte_mixer_fops = {	.owner			= THIS_MODULE,	.llseek         	= no_llseek,	.ioctl          	= forte_mixer_ioctl,	.open           	= forte_mixer_open,	.release        	= forte_mixer_release,};/* Channel ----------------------------------------------------------------- *//**  * forte_channel_reset: * @channel:	Channel to reset *  * Locking:	Must be called with lock held. */static voidforte_channel_reset (struct forte_channel *channel){	if (!channel || !channel->iobase)		return;	DPRINTK ("%s: channel = %s\n", __FUNCTION__, channel->name);	channel->ctrl &= ~FORTE_START;	outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL);		/* We always play at least two fragments, hence these defaults */ 	channel->hwptr = channel->frag_sz;	channel->next_buf = 1;	channel->swptr = 0;	channel->filled_frags = 0;	channel->active = 0;	channel->bytes = 0;	channel->nr_irqs = 0;	channel->mapped = 0;	channel->residue = 0;}/**  * forte_channel_start: * @channel: 	Channel to start (record/playback) * * Locking:	Must be called with lock held. */static void inlineforte_channel_start (struct forte_channel *channel){	if (!channel || !channel->iobase || channel->active) 		return;	channel->ctrl &= ~(FORTE_PAUSE | FORTE_BUF1_LAST | FORTE_BUF2_LAST			   | FORTE_IMMED_STOP);	channel->ctrl |= FORTE_START;	channel->active = 1;	outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL);}/**  * forte_channel_stop: * @channel: 	Channel to stop * * Locking:	Must be called with lock held. */static void inlineforte_channel_stop (struct forte_channel *channel){	if (!channel || !channel->iobase) 		return;	channel->ctrl &= ~(FORTE_START | FORTE_PAUSE);		channel->ctrl |= FORTE_IMMED_STOP;	channel->active = 0;	outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL);}/**  * forte_channel_pause: * @channel: 	Channel to pause * * Locking:	Must be called with lock held. */static void inlineforte_channel_pause (struct forte_channel *channel){	if (!channel || !channel->iobase) 		return;	channel->ctrl |= FORTE_PAUSE;	channel->active = 0;	outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL);}/**  * forte_channel_rate: * @channel: 	Channel whose rate to set.  Playback and record are *           	independent. * @rate:    	Channel rate in Hz * * Locking:	Must be called with lock held. */static intforte_channel_rate (struct forte_channel *channel, unsigned int rate){	int new_rate;	if (!channel || !channel->iobase) 		return -EINVAL;	/* The FM801 only supports a handful of fixed frequencies.	 * We find the value closest to what userland requested.	 */	if      (rate <= 6250)  { rate = 5500;  new_rate =  0; }	else if (rate <= 8800)  { rate = 8000;  new_rate =  1; }	else if (rate <= 10312) { rate = 9600;  new_rate =  2; }	else if (rate <= 13512) { rate = 11025; new_rate =  3; }	else if (rate <= 17600) { rate = 16000; new_rate =  4; }	else if (rate <= 20625) { rate = 19200; new_rate =  5; }	else if (rate <= 27025) { rate = 22050; new_rate =  6; }	else if (rate <= 35200) { rate = 32000; new_rate =  7; }	else if (rate <= 41250) { rate = 38400; new_rate =  8; }	else if (rate <= 46050) { rate = 44100; new_rate =  9; }	else                    { rate = 48000; new_rate = 10; }	channel->ctrl &= ~FORTE_RATE_MASK;	channel->ctrl |= new_rate << FORTE_RATE_SHIFT;	channel->rate = rate;	DPRINTK ("%s: %s rate = %d\n", __FUNCTION__, channel->name, rate);	return rate;}/**  * forte_channel_format: * @channel: 	Channel whose audio format to set * @format:  	OSS format ID * * Locking:	Must be called with lock held. */static intforte_channel_format (struct forte_channel *channel, int format){	if (!channel || !channel->iobase) 		return -EINVAL;	switch (format) {	case AFMT_QUERY:		break;		case AFMT_U8:		channel->ctrl &= ~FORTE_16BIT;		channel->format = AFMT_U8;		break;	case AFMT_S16_LE:	default:		channel->ctrl |= FORTE_16BIT;		channel->format = AFMT_S16_LE;		break;	}

⌨️ 快捷键说明

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