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

📄 btaudio.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 2 页
字号:
/*    btaudio - bt878 audio dma driver for linux 2.4.x    (c) 2000 Gerd Knorr <kraxel@bytesex.org>    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.*/#include <linux/version.h>#include <linux/module.h>#include <linux/errno.h>#include <linux/pci.h>#include <linux/sched.h>#include <linux/signal.h>#include <linux/types.h>#include <linux/wrapper.h>#include <linux/interrupt.h>#include <linux/init.h>#include <linux/poll.h>#include <linux/sound.h>#include <linux/soundcard.h>#include <linux/slab.h>#include <asm/uaccess.h>#include <asm/io.h>/* mmio access */#define btwrite(dat,adr)    writel((dat), (bta->mmio+(adr)))#define btread(adr)         readl(bta->mmio+(adr))#define btand(dat,adr)      btwrite((dat) & btread(adr), adr)#define btor(dat,adr)       btwrite((dat) | btread(adr), adr)#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)/* registers (shifted because bta->mmio is long) */#define REG_INT_STAT      (0x100 >> 2)#define REG_INT_MASK      (0x104 >> 2)#define REG_GPIO_DMA_CTL  (0x10c >> 2)#define REG_PACKET_LEN    (0x110 >> 2)#define REG_RISC_STRT_ADD (0x114 >> 2)#define REG_RISC_COUNT    (0x120 >> 2)/* IRQ bits - REG_INT_(STAT|MASK) */#define IRQ_SCERR         (1 << 19)#define IRQ_OCERR         (1 << 18)#define IRQ_PABORT        (1 << 17)#define IRQ_RIPERR        (1 << 16)#define IRQ_PPERR         (1 << 15)#define IRQ_FDSR          (1 << 14)#define IRQ_FTRGT         (1 << 13)#define IRQ_FBUS          (1 << 12)#define IRQ_RISCI         (1 << 11)#define IRQ_OFLOW         (1 <<  3)#define IRQ_BTAUDIO       (IRQ_SCERR | IRQ_OCERR | IRQ_PABORT | IRQ_RIPERR |\			   IRQ_PPERR | IRQ_FDSR  | IRQ_FTRGT  | IRQ_FBUS   |\			   IRQ_RISCI)/* REG_GPIO_DMA_CTL bits */#define DMA_CTL_A_PWRDN   (1 << 26)#define DMA_CTL_DA_SBR    (1 << 14)#define DMA_CTL_DA_ES2    (1 << 13)#define DMA_CTL_ACAP_EN   (1 <<  4)#define DMA_CTL_RISC_EN   (1 <<  1)#define DMA_CTL_FIFO_EN   (1 <<  0)/* RISC instructions */#define RISC_WRITE        (0x01 << 28)#define RISC_JUMP         (0x07 << 28)#define RISC_SYNC         (0x08 << 28)/* RISC bits */#define RISC_WR_SOL       (1 << 27)#define RISC_WR_EOL       (1 << 26)#define RISC_IRQ          (1 << 24)#define RISC_SYNC_RESYNC  (1 << 15)#define RISC_SYNC_FM1     0x06#define RISC_SYNC_VRO     0x0c#define HWBASE_AD (448000)/* -------------------------------------------------------------- */struct btaudio {	/* linked list */	struct btaudio *next;	/* device info */	int            dsp_digital;	int            dsp_analog;	int            mixer_dev;	struct pci_dev *pci;	unsigned int   irq;	unsigned long  mem;	unsigned long  *mmio;	/* locking */	int            users;	struct semaphore lock;	/* risc instructions */	unsigned int   risc_size;	unsigned long  *risc_cpu;	dma_addr_t     risc_dma;	/* audio data */	unsigned int   buf_size;	unsigned char  *buf_cpu;	dma_addr_t     buf_dma;	/* buffer setup */	int line_bytes;	int line_count;	int block_bytes;	int block_count;	/* read fifo management */	int recording;	int dma_block;	int read_offset;	int read_count;	wait_queue_head_t readq;	/* settings */	int gain[3];	int source;	int bits;	int decimation;	int mixcount;	int sampleshift;	int channels;	int analog;};static struct btaudio *btaudios = NULL;static unsigned int dsp1 = -1;static unsigned int dsp2 = -1;static unsigned int mixer = -1;static unsigned int debug = 0;static unsigned int irq_debug = 0;static int digital = 1;static int analog = 1;static int rate = 32000;/* -------------------------------------------------------------- */#define BUF_DEFAULT 128*1024#define BUF_MIN         8192static int alloc_buffer(struct btaudio *bta){	if (NULL == bta->buf_cpu) {		for (bta->buf_size = BUF_DEFAULT; bta->buf_size >= BUF_MIN;		     bta->buf_size = bta->buf_size >> 1) {			bta->buf_cpu = pci_alloc_consistent				(bta->pci, bta->buf_size, &bta->buf_dma);			if (NULL != bta->buf_cpu)				break;		}		if (NULL == bta->buf_cpu)			return -ENOMEM;		memset(bta->buf_cpu,0,bta->buf_size);	}	if (NULL == bta->risc_cpu) {		bta->risc_size = PAGE_SIZE;		bta->risc_cpu = pci_alloc_consistent			(bta->pci, bta->risc_size, &bta->risc_dma);		if (NULL == bta->risc_cpu)			return -ENOMEM;	}	return 0;}static void free_buffer(struct btaudio *bta){	if (NULL != bta->buf_cpu) {		pci_free_consistent(bta->pci, bta->buf_size,				    bta->buf_cpu, bta->buf_dma);		bta->buf_cpu = NULL;	}	if (NULL != bta->risc_cpu) {		pci_free_consistent(bta->pci, bta->risc_size,				    bta->risc_cpu, bta->risc_dma);		bta->risc_cpu = NULL;	}}static int make_risc(struct btaudio *bta){	int rp, bp, line, block;	unsigned long risc;	bta->block_bytes = bta->buf_size >> 4;	bta->block_count = 1 << 4;	bta->line_bytes  = bta->block_bytes;	bta->line_count  = bta->block_count;	while (bta->line_bytes > 4095) {		bta->line_bytes >>= 1;		bta->line_count <<= 1;	}	if (bta->line_count > 255)		return -EINVAL;	if (debug)		printk(KERN_DEBUG		       "btaudio: bufsize=%d - bs=%d bc=%d - ls=%d, lc=%d\n",		       bta->buf_size,bta->block_bytes,bta->block_count,		       bta->line_bytes,bta->line_count);        rp = 0; bp = 0;	block = 0;	bta->risc_cpu[rp++] = cpu_to_le32(RISC_SYNC|RISC_SYNC_FM1);	bta->risc_cpu[rp++] = cpu_to_le32(0);	for (line = 0; line < bta->line_count; line++) {		risc  = RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL;		risc |= bta->line_bytes;		if (0 == (bp & (bta->block_bytes-1))) {			risc |= RISC_IRQ;			risc |= (block  & 0x0f) << 16;			risc |= (~block & 0x0f) << 20;			block++;		}		bta->risc_cpu[rp++] = cpu_to_le32(risc);		bta->risc_cpu[rp++] = cpu_to_le32(bta->buf_dma + bp);		bp += bta->line_bytes;	}	bta->risc_cpu[rp++] = cpu_to_le32(RISC_SYNC|RISC_SYNC_VRO);	bta->risc_cpu[rp++] = cpu_to_le32(0);	bta->risc_cpu[rp++] = cpu_to_le32(RISC_JUMP); 	bta->risc_cpu[rp++] = cpu_to_le32(bta->risc_dma);	return 0;}static int start_recording(struct btaudio *bta){	int ret;	if (0 != (ret = alloc_buffer(bta)))		return ret;	if (0 != (ret = make_risc(bta)))		return ret;	btwrite(bta->risc_dma, REG_RISC_STRT_ADD);	btwrite((bta->line_count << 16) | bta->line_bytes,		REG_PACKET_LEN);	btwrite(IRQ_BTAUDIO, REG_INT_MASK);	if (bta->analog) {		btwrite(DMA_CTL_ACAP_EN |			DMA_CTL_RISC_EN |			DMA_CTL_FIFO_EN |			DMA_CTL_DA_ES2  |			((bta->bits == 8) ? DMA_CTL_DA_SBR : 0) |			(bta->gain[bta->source] << 28) |			(bta->source            << 24) |			(bta->decimation        <<  8),			REG_GPIO_DMA_CTL);	} else {		btwrite(DMA_CTL_ACAP_EN |			DMA_CTL_RISC_EN |			DMA_CTL_FIFO_EN |			DMA_CTL_DA_ES2  |			DMA_CTL_A_PWRDN |			(1 << 6)   |			((bta->bits == 8) ? DMA_CTL_DA_SBR : 0) |			(bta->gain[bta->source] << 28) |			(bta->source            << 24) |			(bta->decimation        <<  8),			REG_GPIO_DMA_CTL);	}	bta->dma_block = 0;	bta->read_offset = 0;	bta->read_count = 0;	bta->recording = 1;	if (debug)		printk(KERN_DEBUG "btaudio: recording started\n");	return 0;}static void stop_recording(struct btaudio *bta){        btand(~15, REG_GPIO_DMA_CTL);	bta->recording = 0;	if (debug)		printk(KERN_DEBUG "btaudio: recording stopped\n");}/* -------------------------------------------------------------- */static int btaudio_mixer_open(struct inode *inode, struct file *file){	int minor = MINOR(inode->i_rdev);	struct btaudio *bta;	for (bta = btaudios; bta != NULL; bta = bta->next)		if (bta->mixer_dev == minor)			break;	if (NULL == bta)		return -ENODEV;	if (debug)		printk("btaudio: open mixer [%d]\n",minor);	file->private_data = bta;	return 0;}static int btaudio_mixer_release(struct inode *inode, struct file *file){	return 0;}static int btaudio_mixer_ioctl(struct inode *inode, struct file *file,			       unsigned int cmd, unsigned long arg){	struct btaudio *bta = file->private_data;	int ret,val=0,i=0;	if (cmd == SOUND_MIXER_INFO) {		mixer_info info;		memset(&info,0,sizeof(info));                strncpy(info.id,"bt878",sizeof(info.id)-1);                strncpy(info.name,"Brooktree Bt878 audio",sizeof(info.name)-1);                info.modify_counter = bta->mixcount;                if (copy_to_user((void *)arg, &info, sizeof(info)))                        return -EFAULT;		return 0;	}	if (cmd == SOUND_OLD_MIXER_INFO) {		_old_mixer_info info;		memset(&info,0,sizeof(info));                strncpy(info.id,"bt878",sizeof(info.id)-1);                strncpy(info.name,"Brooktree Bt878 audio",sizeof(info.name)-1);                if (copy_to_user((void *)arg, &info, sizeof(info)))                        return -EFAULT;		return 0;	}	if (cmd == OSS_GETVERSION)		return put_user(SOUND_VERSION, (int *)arg);	/* read */	if (_SIOC_DIR(cmd) & _SIOC_WRITE)		if (get_user(val, (int *)arg))			return -EFAULT;	switch (cmd) {	case MIXER_READ(SOUND_MIXER_CAPS):		ret = SOUND_CAP_EXCL_INPUT;		break;	case MIXER_READ(SOUND_MIXER_STEREODEVS):		ret = 0;		break;	case MIXER_READ(SOUND_MIXER_RECMASK):	case MIXER_READ(SOUND_MIXER_DEVMASK):		ret = SOUND_MASK_LINE1|SOUND_MASK_LINE2|SOUND_MASK_LINE3;		break;	case MIXER_WRITE(SOUND_MIXER_RECSRC):		if (val & SOUND_MASK_LINE1 && bta->source != 0)			bta->source = 0;		else if (val & SOUND_MASK_LINE2 && bta->source != 1)			bta->source = 1;		else if (val & SOUND_MASK_LINE3 && bta->source != 2)			bta->source = 2;		btaor((bta->gain[bta->source] << 28) |		      (bta->source            << 24),		      0x0cffffff, REG_GPIO_DMA_CTL);	case MIXER_READ(SOUND_MIXER_RECSRC):		switch (bta->source) {		case 0:  ret = SOUND_MASK_LINE1; break;		case 1:  ret = SOUND_MASK_LINE2; break;		case 2:  ret = SOUND_MASK_LINE3; break;		default: ret = 0;		}		break;	case MIXER_WRITE(SOUND_MIXER_LINE1):	case MIXER_WRITE(SOUND_MIXER_LINE2):	case MIXER_WRITE(SOUND_MIXER_LINE3):		if (MIXER_WRITE(SOUND_MIXER_LINE1) == cmd)			i = 0;		if (MIXER_WRITE(SOUND_MIXER_LINE2) == cmd)			i = 1;		if (MIXER_WRITE(SOUND_MIXER_LINE3) == cmd)			i = 2;		bta->gain[i] = (val & 0xff) * 15 / 100;		if (bta->gain[i] > 15) bta->gain[i] = 15;		if (bta->gain[i] <  0) bta->gain[i] =  0;		if (i == bta->source)			btaor((bta->gain[bta->source]<<28),			      0x0fffffff, REG_GPIO_DMA_CTL);		ret  = bta->gain[i] * 100 / 15;		ret |= ret << 8;		break;	case MIXER_READ(SOUND_MIXER_LINE1):	case MIXER_READ(SOUND_MIXER_LINE2):	case MIXER_READ(SOUND_MIXER_LINE3):		if (MIXER_READ(SOUND_MIXER_LINE1) == cmd)			i = 0;		if (MIXER_READ(SOUND_MIXER_LINE2) == cmd)			i = 1;		if (MIXER_READ(SOUND_MIXER_LINE3) == cmd)			i = 2;		ret  = bta->gain[i] * 100 / 15;		ret |= ret << 8;		break;	default:		return -EINVAL;	}	if (put_user(ret, (int *)arg))		return -EFAULT;	return 0;}static struct file_operations btaudio_mixer_fops = {	owner:   THIS_MODULE,	llseek:  no_llseek,	open:    btaudio_mixer_open,	release: btaudio_mixer_release,	ioctl:   btaudio_mixer_ioctl,};/* -------------------------------------------------------------- */static int btaudio_dsp_open(struct inode *inode, struct file *file,			    struct btaudio *bta, int analog){	down(&bta->lock);	if (bta->users)		goto busy;	bta->users++;	file->private_data = bta;	bta->analog = analog;	bta->dma_block = 0;	bta->read_offset = 0;	bta->read_count = 0;	bta->sampleshift = 0;	up(&bta->lock);	return 0; busy:	up(&bta->lock);	return -EBUSY;}static int btaudio_dsp_open_digital(struct inode *inode, struct file *file){	int minor = MINOR(inode->i_rdev);	struct btaudio *bta;	for (bta = btaudios; bta != NULL; bta = bta->next)		if (bta->dsp_digital == minor)			break;	if (NULL == bta)		return -ENODEV;		if (debug)		printk("btaudio: open digital dsp [%d]\n",minor);	return btaudio_dsp_open(inode,file,bta,0);}static int btaudio_dsp_open_analog(struct inode *inode, struct file *file){	int minor = MINOR(inode->i_rdev);	struct btaudio *bta;	for (bta = btaudios; bta != NULL; bta = bta->next)		if (bta->dsp_analog == minor)			break;	if (NULL == bta)		return -ENODEV;	if (debug)		printk("btaudio: open analog dsp [%d]\n",minor);	return btaudio_dsp_open(inode,file,bta,1);}static int btaudio_dsp_release(struct inode *inode, struct file *file){	struct btaudio *bta = file->private_data;	down(&bta->lock);	if (bta->recording)		stop_recording(bta);	bta->users--;	up(&bta->lock);	return 0;}static ssize_t btaudio_dsp_read(struct file *file, char *buffer,				size_t swcount, loff_t *ppos){	struct btaudio *bta = file->private_data;	int hwcount = swcount << bta->sampleshift;	int nsrc, ndst, err, ret = 0;	DECLARE_WAITQUEUE(wait, current);	add_wait_queue(&bta->readq, &wait);	down(&bta->lock);	while (swcount > 0) {		if (0 == bta->read_count) {			if (!bta->recording) {				if (0 != (err = start_recording(bta))) {					if (0 == ret)						ret = err;					break;				}			}			if (file->f_flags & O_NONBLOCK) {				if (0 == ret)					ret = -EAGAIN;				break;			}			up(&bta->lock);			current->state = TASK_INTERRUPTIBLE;			schedule();			down(&bta->lock);			if(signal_pending(current)) {				if (0 == ret)					ret = -EINTR;				break;			}		}		nsrc = (bta->read_count < hwcount) ? bta->read_count : hwcount;		if (nsrc > bta->buf_size - bta->read_offset)			nsrc = bta->buf_size - bta->read_offset;

⌨️ 快捷键说明

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