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

📄 btaudio.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
				__put_user(cpu_to_le16(avg),dst);			}		} else if (8 == bta->bits) {			/* copy + byte downsampling (audio A/D) */			__u8 *src = bta->buf_cpu + bta->read_offset;			__u8 __user *dst = buffer + ret;			int n = ndst;			if (!access_ok(VERIFY_WRITE, dst, ndst)) {				if (0 == ret)					ret = -EFAULT;				break;			}			for (; n; n--, src += (1 << bta->sampleshift), dst++)				__put_user(*src, dst);		} else {			/* copy + word downsampling (audio A/D) */			__u16 *src = (__u16*)(bta->buf_cpu + bta->read_offset);			__u16 __user *dst = (__u16 __user *)(buffer + ret);			int n = ndst>>1;			if (!access_ok(VERIFY_WRITE,dst,ndst)) {				if (0 == ret)					ret = -EFAULT;				break;			}			for (; n; n--, src += (1 << bta->sampleshift), dst++)				__put_user(*src, 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;	}	mutex_unlock(&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 __user *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;	void __user *argp = (void __user *)arg;	int __user *p = argp;	        switch (cmd) {        case OSS_GETVERSION:                return put_user(SOUND_VERSION, p);        case SNDCTL_DSP_GETCAPS:		return 0;        case SNDCTL_DSP_SPEED:		if (get_user(val, p))			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) {			mutex_lock(&bta->lock);			stop_recording(bta);			start_recording(bta);			mutex_unlock(&bta->lock);		}		/* fall through */        case SOUND_PCM_READ_RATE:		if (bta->analog) {			return put_user(HWBASE_AD*4/bta->decimation>>bta->sampleshift, p);		} else {			return put_user(bta->rate, p);		}        case SNDCTL_DSP_STEREO:		if (!bta->analog) {			if (get_user(val, p))				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, p);        case SNDCTL_DSP_CHANNELS:		if (!bta->analog) {			if (get_user(val, p))				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, p);		        case SNDCTL_DSP_GETFMTS: /* Returns a mask */		if (bta->analog)			return put_user(AFMT_S16_LE|AFMT_S8, p);		else			return put_user(AFMT_S16_LE, p);        case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/		if (get_user(val, p))			return -EFAULT;                if (val != AFMT_QUERY) {			if (bta->analog)				bta->bits = (val == AFMT_S8) ? 8 : 16;			else				bta->bits = 16;			if (bta->recording) {				mutex_lock(&bta->lock);				stop_recording(bta);				start_recording(bta);				mutex_unlock(&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,				p);		break;        case SOUND_PCM_READ_BITS:		return put_user(bta->bits, p);        case SNDCTL_DSP_NONBLOCK:                file->f_flags |= O_NONBLOCK;                return 0;        case SNDCTL_DSP_RESET:		if (bta->recording) {			mutex_lock(&bta->lock);			stop_recording(bta);			mutex_unlock(&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,p);        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(argp, &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 const 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 const 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 irqreturn_t btaudio_irq(int irq, void *dev_id){	int count = 0;	u32 stat,astat;	struct btaudio *bta = dev_id;	int handled = 0;	for (;;) {		count++;		stat  = btread(REG_INT_STAT);		astat = stat & btread(REG_INT_MASK);		if (!astat)			return IRQ_RETVAL(handled);		handled = 1;		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 IRQ_NONE;}/* -------------------------------------------------------------- */static unsigned int dsp1 = -1;static unsigned int dsp2 = -1;static unsigned int mixer = -1;static int latency = -1;static int digital = 1;static int analog = 1;static int rate;#define BTA_OSPREY200 1static struct cardinfo cards[] = {	[0] = {		.name	= "default",		.rate	= 32000,	},	[BTA_OSPREY200] = {		.name	= "Osprey 200",		.rate	= 44100,	},};static int __devinit btaudio_probe(struct pci_dev *pci_dev,				   const struct pci_device_id *pci_id){	struct btaudio *bta;	struct cardinfo *card = &cards[pci_id->driver_data];	unsigned char revision,lat;	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 = kzalloc(sizeof(*bta),GFP_ATOMIC);	if (!bta) {		rc = -ENOMEM;		goto fail0;	}	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;	}	/* sample rate */	bta->rate = card->rate;	if (rate)		bta->rate = rate;		mutex_init(&bta->lock);        init_waitqueue_head(&bta->readq);	if (-1 != latency) {		printk(KERN_INFO "btaudio: setting pci latency timer to %d\n",		       latency);		pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency);	}        pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision);        pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &lat);        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, mmio: 0x%lx\n",	       bta->irq, lat, bta->mem);	printk("btaudio: using card config \"%s\"\n", card->name);	/* init hw */        btwrite(0, REG_GPIO_DMA_CTL);        btwrite(0, REG_INT_MASK);        btwrite(~0U, REG_INT_STAT);	pci_set_master(pci_dev);	if ((rc = request_irq(bta->irq, btaudio_irq, IRQF_SHARED|IRQF_DISABLED,			      "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;		}		printk(KERN_INFO "btaudio: registered device dsp%d [digital]\n",		       bta->dsp_digital >> 4);	}	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;		}		printk(KERN_INFO "btaudio: registered device dsp%d [analog]\n",		       bta->dsp_analog >> 4);		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;		}		printk(KERN_INFO "btaudio: registered device mixer%d\n",		       bta->mixer_dev >> 4);	}	/* 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:	iounmap(bta->mmio);	kfree(bta); fail0:	release_mem_region(pci_resource_start(pci_dev,0),			   pci_resource_len(pci_dev,0));	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(~0U, 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));	iounmap(bta->mmio);	/* 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[] = {        {		.vendor		= PCI_VENDOR_ID_BROOKTREE,		.device		= 0x0878,		.subvendor	= 0x0070,		.subdevice	= 0xff01,		.driver_data	= BTA_OSPREY200,	},{		.vendor		= PCI_VENDOR_ID_BROOKTREE,		.device		= 0x0878,		.subvendor	= PCI_ANY_ID,		.subdevice	= PCI_ANY_ID,	},{		.vendor		= PCI_VENDOR_ID_BROOKTREE,		.device		= 0x0878,		.subvendor	= PCI_ANY_ID,		.subdevice	= PCI_ANY_ID,        },{		/* --- end of list --- */	}};static struct pci_driver btaudio_pci_driver = {        .name		= "btaudio",        .id_table	= btaudio_pci_tbl,        .probe		= btaudio_probe,        .remove		=  __devexit_p(btaudio_remove),};static int btaudio_init_module(void){	printk(KERN_INFO "btaudio: driver version 0.7 loaded [%s%s%s]\n",	       digital ? "digital" : "",	       analog && digital ? "+" : "",	       analog ? "analog" : "");	return pci_register_driver(&btaudio_pci_driver);}static void btaudio_cleanup_module(void){	pci_unregister_driver(&btaudio_pci_driver);	return;}module_init(btaudio_init_module);module_exit(btaudio_cleanup_module);module_param(dsp1, int, S_IRUGO);module_param(dsp2, int, S_IRUGO);module_param(mixer, int, S_IRUGO);module_param(debug, int, S_IRUGO | S_IWUSR);module_param(irq_debug, int, S_IRUGO | S_IWUSR);module_param(digital, int, S_IRUGO);module_param(analog, int, S_IRUGO);module_param(rate, int, S_IRUGO);module_param(latency, int, S_IRUGO);MODULE_PARM_DESC(latency,"pci latency timer");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 + -