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

📄 btaudio.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 2 页
字号:
		ndst = nsrc >> bta->sampleshift;				if ((bta->analog  && 0 == bta->sampleshift) ||		    (!bta->analog && 2 == bta->channels)) {			/* just copy */			if (copy_to_user(buffer + ret, bta->buf_cpu + bta->read_offset, nsrc)) {				if (0 == ret)					ret = -EFAULT;				break;			}		} else if (!bta->analog) {			/* stereo => mono (digital audio) */			__s16 *src = (__s16*)(bta->buf_cpu + bta->read_offset);			__s16 *dst = (__s16*)(buffer + ret);			__s16 avg;			int n = ndst>>1;			if (0 != verify_area(VERIFY_WRITE,dst,ndst)) {				if (0 == ret)					ret = -EFAULT;				break;			}			for (; n; n--, dst++) {				avg  = (__s16)le16_to_cpu(*src) / 2; src++;				avg += (__s16)le16_to_cpu(*src) / 2; src++;				__put_user(cpu_to_le16(avg),(__u16*)(dst));			}		} else if (8 == bta->bits) {			/* copy + byte downsampling (audio A/D) */			__u8 *src = bta->buf_cpu + bta->read_offset;			__u8 *dst = buffer + ret;			int n = ndst;			if (0 != verify_area(VERIFY_WRITE,dst,ndst)) {				if (0 == ret)					ret = -EFAULT;				break;			}			for (; n; n--, src += (1 << bta->sampleshift), dst++)				__put_user(*src,(__u8*)(dst));		} else {			/* copy + word downsampling (audio A/D) */			__u16 *src = (__u16*)(bta->buf_cpu + bta->read_offset);			__u16 *dst = (__u16*)(buffer + ret);			int n = ndst>>1;			if (0 != verify_area(VERIFY_WRITE,dst,ndst)) {				if (0 == ret)					ret = -EFAULT;				break;			}			for (; n; n--, src += (1 << bta->sampleshift), dst++)				__put_user(*src,(__u16*)(dst));		}		ret     += ndst;		swcount -= ndst;		hwcount -= nsrc;		bta->read_count  -= nsrc;		bta->read_offset += nsrc;		if (bta->read_offset == bta->buf_size)			bta->read_offset = 0;	}	up(&bta->lock);	remove_wait_queue(&bta->readq, &wait);	current->state = TASK_RUNNING;	return ret;}static ssize_t btaudio_dsp_write(struct file *file, const char *buffer,				 size_t count, loff_t *ppos){	return -EINVAL;}static int btaudio_dsp_ioctl(struct inode *inode, struct file *file,			     unsigned int cmd, unsigned long arg){	struct btaudio *bta = file->private_data;	int s, i, ret, val = 0;	        switch (cmd) {        case OSS_GETVERSION:                return put_user(SOUND_VERSION, (int *)arg);        case SNDCTL_DSP_GETCAPS:		return 0;        case SNDCTL_DSP_SPEED:		if (get_user(val, (int*)arg))			return -EFAULT;		if (bta->analog) {			for (s = 0; s < 16; s++)				if (val << s >= HWBASE_AD*4/15)					break;			for (i = 15; i >= 5; i--)				if (val << s <= HWBASE_AD*4/i)					break;			bta->sampleshift = s;			bta->decimation  = i;			if (debug)				printk(KERN_DEBUG "btaudio: rate: req=%d  "				       "dec=%d shift=%d hwrate=%d swrate=%d\n",				       val,i,s,(HWBASE_AD*4/i),(HWBASE_AD*4/i)>>s);		} else {			bta->sampleshift = (bta->channels == 2) ? 0 : 1;			bta->decimation  = 0;		}		if (bta->recording) {			down(&bta->lock);			stop_recording(bta);			start_recording(bta);			up(&bta->lock);		}		/* fall through */        case SOUND_PCM_READ_RATE:		if (bta->analog) {			return put_user(HWBASE_AD*4/bta->decimation>>bta->sampleshift, (int*)arg);		} else {			return put_user(rate, (int*)arg);		}        case SNDCTL_DSP_STEREO:		if (!bta->analog) {			if (get_user(val, (int*)arg))				return -EFAULT;			bta->channels    = (val > 0) ? 2 : 1;			bta->sampleshift = (bta->channels == 2) ? 0 : 1;			if (debug)				printk(KERN_INFO				       "btaudio: stereo=%d channels=%d\n",				       val,bta->channels);		} else {			if (val == 1)				return -EFAULT;			else {				bta->channels = 1;				if (debug)					printk(KERN_INFO					       "btaudio: stereo=0 channels=1\n");			}		}		return put_user((bta->channels)-1, (int *)arg);        case SNDCTL_DSP_CHANNELS:		if (!analog) {			if (get_user(val, (int*)arg))				return -EFAULT;			bta->channels    = (val > 1) ? 2 : 1;			bta->sampleshift = (bta->channels == 2) ? 0 : 1;			if (debug)				printk(KERN_DEBUG				       "btaudio: val=%d channels=%d\n",				       val,bta->channels);		}		/* fall through */        case SOUND_PCM_READ_CHANNELS:		return put_user(bta->channels, (int *)arg);		        case SNDCTL_DSP_GETFMTS: /* Returns a mask */		if (analog)			return put_user(AFMT_S16_LE|AFMT_S8, (int*)arg);		else			return put_user(AFMT_S16_LE, (int*)arg);        case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/		if (get_user(val, (int*)arg))			return -EFAULT;                if (val != AFMT_QUERY) {			if (analog)				bta->bits = (val == AFMT_S8) ? 8 : 16;			else				bta->bits = 16;			if (bta->recording) {				down(&bta->lock);				stop_recording(bta);				start_recording(bta);				up(&bta->lock);			}		}		if (debug)			printk(KERN_DEBUG "btaudio: fmt: bits=%d\n",bta->bits);                return put_user((bta->bits==16) ? AFMT_S16_LE : AFMT_S8,				(int*)arg);		break;        case SOUND_PCM_READ_BITS:		return put_user(bta->bits, (int*)arg);        case SNDCTL_DSP_NONBLOCK:                file->f_flags |= O_NONBLOCK;                return 0;        case SNDCTL_DSP_RESET:		if (bta->recording) {			down(&bta->lock);			stop_recording(bta);			up(&bta->lock);		}		return 0;        case SNDCTL_DSP_GETBLKSIZE:		if (!bta->recording) {			if (0 != (ret = alloc_buffer(bta)))				return ret;			if (0 != (ret = make_risc(bta)))				return ret;		}		return put_user(bta->block_bytes>>bta->sampleshift,(int*)arg);        case SNDCTL_DSP_SYNC:		/* NOP */		return 0;	case SNDCTL_DSP_GETISPACE:	{		audio_buf_info info;		if (!bta->recording)			return -EINVAL;		info.fragsize = bta->block_bytes>>bta->sampleshift;		info.fragstotal = bta->block_count;		info.bytes = bta->read_count;		info.fragments = info.bytes / info.fragsize;		if (debug)			printk(KERN_DEBUG "btaudio: SNDCTL_DSP_GETISPACE "			       "returns %d/%d/%d/%d\n",			       info.fragsize, info.fragstotal,			       info.bytes, info.fragments);		if (copy_to_user((void *)arg, &info, sizeof(info)))			return -EFAULT;		return 0;	}#if 0 /* TODO */        case SNDCTL_DSP_GETTRIGGER:        case SNDCTL_DSP_SETTRIGGER:        case SNDCTL_DSP_SETFRAGMENT:#endif	default:		return -EINVAL;	}}static unsigned int btaudio_dsp_poll(struct file *file, struct poll_table_struct *wait){	struct btaudio *bta = file->private_data;	unsigned int mask = 0;	poll_wait(file, &bta->readq, wait);	if (0 == bta->read_count)		mask |= (POLLIN | POLLRDNORM);	return mask;}static struct file_operations btaudio_digital_dsp_fops = {	owner:   THIS_MODULE,	llseek:  no_llseek,	open:    btaudio_dsp_open_digital,	release: btaudio_dsp_release,	read:    btaudio_dsp_read,	write:   btaudio_dsp_write,	ioctl:   btaudio_dsp_ioctl,	poll:    btaudio_dsp_poll,};static struct file_operations btaudio_analog_dsp_fops = {	owner:   THIS_MODULE,	llseek:  no_llseek,	open:    btaudio_dsp_open_analog,	release: btaudio_dsp_release,	read:    btaudio_dsp_read,	write:   btaudio_dsp_write,	ioctl:   btaudio_dsp_ioctl,	poll:    btaudio_dsp_poll,};/* -------------------------------------------------------------- */static char *irq_name[] = { "", "", "", "OFLOW", "", "", "", "", "", "", "",			    "RISCI", "FBUS", "FTRGT", "FDSR", "PPERR",			    "RIPERR", "PABORT", "OCERR", "SCERR" };static void btaudio_irq(int irq, void *dev_id, struct pt_regs * regs){	int count = 0;	u32 stat,astat;	struct btaudio *bta = dev_id;	for (;;) {		count++;		stat  = btread(REG_INT_STAT);		astat = stat & btread(REG_INT_MASK);		if (!astat)			return;		btwrite(astat,REG_INT_STAT);		if (irq_debug) {			int i;			printk(KERN_DEBUG "btaudio: irq loop=%d risc=%x, bits:",			       count, stat>>28);			for (i = 0; i < (sizeof(irq_name)/sizeof(char*)); i++) {				if (stat & (1 << i))					printk(" %s",irq_name[i]);				if (astat & (1 << i))					printk("*");			}			printk("\n");		}		if (stat & IRQ_RISCI) {			int blocks;			blocks = (stat >> 28) - bta->dma_block;			if (blocks < 0)				blocks += bta->block_count;			bta->dma_block = stat >> 28;			if (bta->read_count + 2*bta->block_bytes > bta->buf_size) {				stop_recording(bta);				printk(KERN_INFO "btaudio: buffer overrun\n");			}			if (blocks > 0) {				bta->read_count += blocks * bta->block_bytes;				wake_up_interruptible(&bta->readq);			}		}		if (count > 10) {			printk(KERN_WARNING			       "btaudio: Oops - irq mask cleared\n");			btwrite(0, REG_INT_MASK);		}	}	return;}/* -------------------------------------------------------------- */static int __devinit btaudio_probe(struct pci_dev *pci_dev,				   const struct pci_device_id *pci_id){	struct btaudio *bta;	unsigned char revision,latency;	int rc = -EBUSY;	if (pci_enable_device(pci_dev))		return -EIO;	if (!request_mem_region(pci_resource_start(pci_dev,0),				pci_resource_len(pci_dev,0),				"btaudio")) {		return -EBUSY;	}	bta = kmalloc(sizeof(*bta),GFP_ATOMIC);	if (!bta) {		printk(KERN_WARNING 		       "btaudio: not enough memory\n");		rc = -ENOMEM;		goto fail1;	}	memset(bta,0,sizeof(*bta));	bta->pci  = pci_dev;	bta->irq  = pci_dev->irq;	bta->mem  = pci_resource_start(pci_dev,0);	bta->mmio = ioremap(pci_resource_start(pci_dev,0),			    pci_resource_len(pci_dev,0));	bta->source     = 1;	bta->bits       = 8;	bta->channels   = 1;	if (bta->analog) {		bta->decimation  = 15;	} else {		bta->decimation  = 0;		bta->sampleshift = 1;	}	init_MUTEX(&bta->lock);        init_waitqueue_head(&bta->readq);        pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision);        pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &latency);        printk(KERN_INFO "btaudio: Bt%x (rev %d) at %02x:%02x.%x, ",	       pci_dev->device,revision,pci_dev->bus->number,	       PCI_SLOT(pci_dev->devfn),PCI_FUNC(pci_dev->devfn));        printk("irq: %d, latency: %d, memory: 0x%lx\n",	       bta->irq, latency, bta->mem);	/* init hw */        btwrite(0, REG_GPIO_DMA_CTL);        btwrite(0, REG_INT_MASK);        btwrite(~0x0UL, REG_INT_STAT);	pci_set_master(pci_dev);	if ((rc = request_irq(bta->irq, btaudio_irq, SA_SHIRQ|SA_INTERRUPT,			       "btaudio",(void *)bta)) < 0) {		printk(KERN_WARNING		       "btaudio: can't request irq (rc=%d)\n",rc);		goto fail1;	}	/* register devices */	if (digital) {		rc = bta->dsp_digital =			register_sound_dsp(&btaudio_digital_dsp_fops,dsp1);		if (rc < 0) {			printk(KERN_WARNING			       "btaudio: can't register digital dsp (rc=%d)\n",rc);			goto fail2;		}	}	if (analog) {		rc = bta->dsp_analog =			register_sound_dsp(&btaudio_analog_dsp_fops,dsp2);		if (rc < 0) {			printk(KERN_WARNING			       "btaudio: can't register analog dsp (rc=%d)\n",rc);			goto fail3;		}		rc = bta->mixer_dev = register_sound_mixer(&btaudio_mixer_fops,mixer);		if (rc < 0) {			printk(KERN_WARNING			       "btaudio: can't register mixer (rc=%d)\n",rc);			goto fail4;		}	}	if (debug)		printk(KERN_DEBUG "btaudio: minors: digital=%d, analog=%d, mixer=%d\n",		       bta->dsp_digital, bta->dsp_analog, bta->mixer_dev);	/* hook into linked list */	bta->next = btaudios;	btaudios = bta;	pci_set_drvdata(pci_dev,bta);        return 0; fail4:	unregister_sound_dsp(bta->dsp_analog); fail3:	if (digital)		unregister_sound_dsp(bta->dsp_digital); fail2:        free_irq(bta->irq,bta);	 fail1:	release_mem_region(pci_resource_start(pci_dev,0),			   pci_resource_len(pci_dev,0));	kfree(bta);	return rc;}static void __devexit btaudio_remove(struct pci_dev *pci_dev){	struct btaudio *bta = pci_get_drvdata(pci_dev);	struct btaudio *walk;	/* turn off all DMA / IRQs */        btand(~15, REG_GPIO_DMA_CTL);        btwrite(0, REG_INT_MASK);        btwrite(~0x0UL, REG_INT_STAT);	/* unregister devices */	if (digital) {		unregister_sound_dsp(bta->dsp_digital);	}	if (analog) {		unregister_sound_dsp(bta->dsp_analog);		unregister_sound_mixer(bta->mixer_dev);	}	/* free resources */	free_buffer(bta);        free_irq(bta->irq,bta);	release_mem_region(pci_resource_start(pci_dev,0),			   pci_resource_len(pci_dev,0));	/* remove from linked list */	if (bta == btaudios) {		btaudios = NULL;	} else {		for (walk = btaudios; walk->next != bta; walk = walk->next)			; /* if (NULL == walk->next) BUG(); */		walk->next = bta->next;	}	pci_set_drvdata(pci_dev, NULL);	kfree(bta);	return;}/* -------------------------------------------------------------- */static struct pci_device_id btaudio_pci_tbl[] __devinitdata = {        { PCI_VENDOR_ID_BROOKTREE, 0x0878,          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},        { PCI_VENDOR_ID_BROOKTREE, 0x0879,          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},        {0,}};static struct pci_driver btaudio_pci_driver = {        name:     "btaudio",        id_table: btaudio_pci_tbl,        probe:    btaudio_probe,        remove:   __devexit_p(btaudio_remove),};int btaudio_init_module(void){	printk(KERN_INFO "btaudio: driver version 0.6 loaded [%s%s%s]\n",	       analog ? "analog" : "",	       analog && digital ? "+" : "",	       digital ? "digital" : "");	return pci_module_init(&btaudio_pci_driver);}void btaudio_cleanup_module(void){	pci_unregister_driver(&btaudio_pci_driver);	return;}module_init(btaudio_init_module);module_exit(btaudio_cleanup_module);MODULE_PARM(dsp1,"i");MODULE_PARM(dsp2,"i");MODULE_PARM(mixer,"i");MODULE_PARM(debug,"i");MODULE_PARM(irq_debug,"i");MODULE_PARM(digital,"i");MODULE_PARM(analog,"i");MODULE_PARM(rate,"i");MODULE_DEVICE_TABLE(pci, btaudio_pci_tbl);MODULE_DESCRIPTION("bt878 audio dma driver");MODULE_AUTHOR("Gerd Knorr");MODULE_LICENSE("GPL");/* * Local variables: * c-basic-offset: 8 * End: */

⌨️ 快捷键说明

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