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

📄 ad1889.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 2 页
字号:
		buffer += cnt;		ret += cnt;		/* we have something to play - go play it! */		ad1889_trigger_playback(dev);	}err2:	remove_wait_queue(&state->dmabuf.wait, &wait);err1:	up(&state->sem);	return ret;}static unsigned int ad1889_poll(struct file *file, struct poll_table_struct *wait){	unsigned int mask = 0;#if 0	ad1889_dev_t *dev = (ad1889_dev_t *)file->private_data;	ad1889_state_t *state = NULL;	struct dmabuf *dmabuf;	unsigned long flags;		if (!(file->f_mode & (FMODE_READ | FMODE_WRITE)))		return -EINVAL;	if (file->f_mode & FMODE_WRITE) {		state = &dev->state[AD_WAV_STATE];		if (!state) return 0;		dmabuf = &state->dmabuf;		poll_wait(file, &dmabuf->wait, wait);	}	if (file->f_mode & FMODE_READ) {		state = &dev->state[AD_ADC_STATE];		if (!state) return 0;		dmabuf = &state->dmabuf;		poll_wait(file, &dmabuf->wait, wait);	}	spin_lock_irqsave(&dev->lock, flags);	ad1889_update_ptr(dev, 0);	if (file->f_mode & FMODE_WRITE) {		state = &dev->state[WAV_STATE];		dmabuf = &state->dmabuf;		if (dmabuf->mapped) {			if (dmabuf->count >= (int)dmabuf->fragsize)				mask |= POLLOUT | POLLWRNORM;		} else {			if ((int)dmabuf->dmasize >= dmabuf->count + 				(int)dmabuf->fragsize)				mask |= POLLOUT | POLLWRNORM;		}	}	if (file ->f_mode & FMODE_READ) {		state = &dev->state[AD_ADC_STATE];		dmabuf = &state->dmabuf;		if (dmabuf->count >= (int)dmabuf->fragsize)			mask |= POLLIN | POLLRDNORM;	}	spin_unlock_irqrestore(&dev->lock, flags);#endif	return mask;}static int ad1889_mmap(struct file *file, struct vm_area_struct *vma){	return 0;}static int ad1889_ioctl(struct inode *inode, struct file *file, unsigned int cmd,	unsigned long arg){	int val = 0;	ad1889_dev_t *dev = (ad1889_dev_t *)file->private_data;	struct dmabuf *dmabuf;	audio_buf_info abinfo;	int __user *p = (int __user *)arg;	DBG("ad1889_ioctl cmd 0x%x arg %lu\n", cmd, arg);	switch (cmd)	{	case OSS_GETVERSION:		return put_user(SOUND_VERSION, p);	case SNDCTL_DSP_RESET:		break;	case SNDCTL_DSP_SYNC:		break;	case SNDCTL_DSP_SPEED:		/* set sampling rate */		if (get_user(val, p))			return -EFAULT;		if (val > 5400 && val < 48000)		{			if (file->f_mode & FMODE_WRITE)				AD1889_WRITEW(ad1889_dev, AD_DSWAS, val);			if (file->f_mode & FMODE_READ)				AD1889_WRITEW(ad1889_dev, AD_DSRES, val);		}		return 0;	case SNDCTL_DSP_STEREO: /* undocumented? */		if (get_user(val, p))			return -EFAULT;		if (file->f_mode & FMODE_READ) {			val = AD1889_READW(ad1889_dev, AD_DSWSMC);			if (val) {				val |= 0x0200;  /* set WAST */			} else {				val &= ~0x0200; /* clear WAST */			}			AD1889_WRITEW(ad1889_dev, AD_DSWSMC, val);		}		if (file->f_mode & FMODE_WRITE) {			val = AD1889_READW(ad1889_dev, AD_DSRAMC);			if (val) {				val |= 0x0002;  /* set ADST */			} else {				val &= ~0x0002; /* clear ADST */			}			AD1889_WRITEW(ad1889_dev, AD_DSRAMC, val);		}		return 0;	case SNDCTL_DSP_GETBLKSIZE:		return put_user(DMA_SIZE, p);	case SNDCTL_DSP_GETFMTS:		return put_user(AFMT_S16_LE|AFMT_U8, p);	case SNDCTL_DSP_SETFMT:		if (get_user(val, p))			return -EFAULT;		if (val == 0) {			if (file->f_mode & FMODE_READ) 				ad1889_set_adc_fmt(dev, val);			if (file->f_mode & FMODE_WRITE) 				ad1889_set_wav_fmt(dev, val);		} else {			val = AFMT_S16_LE | AFMT_U8;		}		return put_user(val, p);	case SNDCTL_DSP_CHANNELS:		break;	case SNDCTL_DSP_POST:		/* send all data to device */		break;	case SNDCTL_DSP_SUBDIVIDE:		break;	case SNDCTL_DSP_SETFRAGMENT:		/* not supported; uses fixed fragment sizes */		return put_user(DMA_SIZE, p);	case SNDCTL_DSP_GETOSPACE:	case SNDCTL_DSP_GETISPACE:		/* space left in dma buffers */		if (cmd == SNDCTL_DSP_GETOSPACE)			dmabuf = &dev->state[AD_WAV_STATE].dmabuf;		else			dmabuf = &dev->state[AD_ADC_STATE].dmabuf;		abinfo.fragments = 1;		abinfo.fragstotal = 1;		abinfo.fragsize = DMA_SIZE;		abinfo.bytes = DMA_SIZE;		return copy_to_user(p, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;	case SNDCTL_DSP_NONBLOCK:		file->f_flags |= O_NONBLOCK;		return 0;	case SNDCTL_DSP_GETCAPS:		return put_user(0, p);	case SNDCTL_DSP_GETTRIGGER:	case SNDCTL_DSP_SETTRIGGER:		break;	case SNDCTL_DSP_GETIPTR:	case SNDCTL_DSP_GETOPTR:		break;	case SNDCTL_DSP_SETDUPLEX:		break;		case SNDCTL_DSP_GETODELAY:		break;	case SOUND_PCM_READ_RATE:		return put_user(AD1889_READW(ad1889_dev, AD_DSWAS), p);	case SOUND_PCM_READ_CHANNELS:	case SOUND_PCM_READ_BITS:		break;	case SNDCTL_DSP_MAPINBUF:	case SNDCTL_DSP_MAPOUTBUF:	case SNDCTL_DSP_SETSYNCRO:	case SOUND_PCM_WRITE_FILTER:	case SOUND_PCM_READ_FILTER:		break;	default:		break;	}	return -ENOTTY;}static int ad1889_open(struct inode *inode, struct file *file){	/* check minor; only support /dev/dsp atm */	if (iminor(inode) != 3)		return -ENXIO;		file->private_data = ad1889_dev;	ad1889_set_wav_rate(ad1889_dev, 48000);	ad1889_set_wav_fmt(ad1889_dev, AFMT_S16_LE);	AD1889_WRITEW(ad1889_dev, AD_DSWADA, 0x0404); /* attenuation */	return nonseekable_open(inode, file);}static int ad1889_release(struct inode *inode, struct file *file){	/* if we have state free it here */	return 0;}static struct file_operations ad1889_fops = {	.owner		= THIS_MODULE,	.llseek		= no_llseek,	.read		= ad1889_read,	.write		= ad1889_write,	.poll		= ad1889_poll,	.ioctl		= ad1889_ioctl,	.mmap		= ad1889_mmap,	.open		= ad1889_open,	.release	= ad1889_release,};/************************* /dev/mixer interfaces ************************ */static int ad1889_mixer_open(struct inode *inode, struct file *file){	if (ad1889_dev->ac97_codec->dev_mixer != iminor(inode))		return -ENODEV;	file->private_data = ad1889_dev->ac97_codec;	return 0;}static int ad1889_mixer_release(struct inode *inode, struct file *file){	return 0;}static int ad1889_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 ad1889_mixer_fops = {	.owner		= THIS_MODULE,	.llseek		= no_llseek,	.ioctl		= ad1889_mixer_ioctl,	.open		= ad1889_mixer_open,	.release	= ad1889_mixer_release,};/************************* AC97 interfaces ****************************** */static void ad1889_codec_write(struct ac97_codec *ac97, u8 reg, u16 val){	ad1889_dev_t *dev = ac97->private_data;	//DBG("Writing 0x%x to 0x%lx\n", val, dev->regbase + 0x100 + reg);	AD1889_WRITEW(dev, 0x100 + reg, val);}static u16 ad1889_codec_read(struct ac97_codec *ac97, u8 reg){	ad1889_dev_t *dev = ac97->private_data;	//DBG("Reading from 0x%lx\n", dev->regbase + 0x100 + reg);	return AD1889_READW(dev, 0x100 + reg);}	static int ad1889_ac97_init(ad1889_dev_t *dev, int id){	struct ac97_codec *ac97;	u16 eid;	if ((ac97 = ac97_alloc_codec()) == NULL) 		return -ENOMEM;	ac97->private_data = dev;	ac97->id = id;	ac97->codec_read = ad1889_codec_read;	ac97->codec_write = ad1889_codec_write;	if (ac97_probe_codec(ac97) == 0) {		printk(DEVNAME ": ac97_probe_codec failed\n");		goto out_free;	}	eid = ad1889_codec_read(ac97, AC97_EXTENDED_ID);	if (eid == 0xffff) {		printk(KERN_WARNING DEVNAME ": no codec attached?\n");		goto out_free;	}	dev->ac97_features = eid;	if ((ac97->dev_mixer = register_sound_mixer(&ad1889_mixer_fops, -1)) < 0) {		printk(KERN_ERR DEVNAME ": cannot register mixer\n");		goto out_free;	}	dev->ac97_codec = ac97;	return 0;out_free:	ac97_release_codec(ac97);	return -ENODEV;}static int ad1889_aclink_reset(struct pci_dev * pcidev){	u16 stat;	int retry = 200;	ad1889_dev_t *dev = pci_get_drvdata(pcidev);	AD1889_WRITEW(dev, AD_DSCCS, 0x8000); /* turn on clock */	AD1889_READW(dev, AD_DSCCS); 	WAIT_10MS();	stat = AD1889_READW(dev, AD_ACIC);	stat |= 0x0002;				/* Reset Disable */	AD1889_WRITEW(dev, AD_ACIC, stat);	(void) AD1889_READW(dev, AD_ACIC);	/* flush posted write */	udelay(10);	stat = AD1889_READW(dev, AD_ACIC);	stat |= 0x0001;				/* Interface Enable */	AD1889_WRITEW(dev, AD_ACIC, stat);	do {		if (AD1889_READW(dev, AD_ACIC) & 0x8000)	/* Ready */			break;		WAIT_10MS();		retry--;	} while (retry > 0);	if (!retry) {		printk(KERN_ERR "ad1889_aclink_reset: codec is not ready [0x%x]\n",			    AD1889_READW(dev, AD_ACIC));		return -EBUSY;	}	/* TODO reset AC97 codec */	/* TODO set wave/adc pci ctrl status */	stat = AD1889_READW(dev, AD_ACIC);	stat |= 0x0004;				/* Audio Stream Output Enable */	AD1889_WRITEW(dev, AD_ACIC, stat);	return 0;}/************************* PCI interfaces ****************************** *//* PCI device table */static struct pci_device_id ad1889_id_tbl[] = {	{ PCI_VENDOR_ID_ANALOG_DEVICES, PCI_DEVICE_ID_AD1889JS, PCI_ANY_ID, 	  PCI_ANY_ID, 0, 0, (unsigned long)DEVNAME },	{ },};MODULE_DEVICE_TABLE(pci, ad1889_id_tbl);static irqreturn_t ad1889_interrupt(int irq, void *dev_id, struct pt_regs *regs){	u32 stat;	ad1889_dev_t *dev = (ad1889_dev_t *)dev_id;	stat = AD1889_READL(dev, AD_DMADISR);	/* clear ISR */	AD1889_WRITEL(dev, AD_DMADISR, stat);	if (stat & 0x8) {		/* WAVI */		DBG("WAV interrupt\n");		dev->stats.wav_intrs++;		if (dev->state[AD_WAV_STATE].dmabuf.ready) {			ad1889_stop_wav(&dev->state[AD_WAV_STATE]);	/* clean up */			ad1889_start_wav(&dev->state[AD_WAV_STATE]);	/* start new */		}	}	if ((stat & 0x2) && dev->state[AD_ADC_STATE].dmabuf.ready) { /* ADCI */		DBG("ADC interrupt\n");		dev->stats.adc_intrs++;	}	if(stat)		return IRQ_HANDLED;	return IRQ_NONE;}static void ad1889_initcfg(ad1889_dev_t *dev){	u16 tmp16;	u32 tmp32;	/* make sure the interrupt bits are setup the way we want */	tmp32 = AD1889_READL(dev, AD_DMAWAVCTRL);	tmp32 &= ~0xff; /* flat dma, no sg, mask out the intr bits */	tmp32 |= 0x6;  /* intr on count, loop */	AD1889_WRITEL(dev, AD_DMAWAVCTRL, tmp32);	/* unmute... */	tmp16 = AD1889_READW(dev, AD_DSWADA);	tmp16 &= ~0x8080;	AD1889_WRITEW(dev, AD_DSWADA, tmp16);}static int __devinit ad1889_probe(struct pci_dev *pcidev, const struct pci_device_id *ent){	int err;	ad1889_dev_t *dev;	unsigned long bar;	struct proc_dir_entry *proc_root = NULL;	if ((err = pci_enable_device(pcidev)) != 0) {		printk(KERN_ERR DEVNAME ": pci_enable_device failed\n");		return err;	}	pci_set_master(pcidev);	if ((dev = ad1889_alloc_dev(pcidev)) == NULL) {		printk(KERN_ERR DEVNAME ": cannot allocate memory for device\n");		return -ENOMEM;	}	pci_set_drvdata(pcidev, dev);	bar = pci_resource_start(pcidev, 0);	        if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_MEM)) {		printk(KERN_ERR DEVNAME ": memory region not assigned\n");		goto err_free_mem;	}	if (request_irq(pcidev->irq, ad1889_interrupt, SA_SHIRQ, DEVNAME, dev) != 0) {		printk(KERN_ERR DEVNAME ": unable to request interrupt\n");		goto err_free_mem;	}	request_mem_region(bar, AD_DSIOMEMSIZE, DEVNAME);	dev->regbase = (unsigned long)ioremap_nocache(bar, AD_DSIOMEMSIZE);	printk(KERN_INFO DEVNAME ": %s at 0x%lx IRQ %d\n",		(char *)ent->driver_data, dev->regbase, pcidev->irq);	if (ad1889_aclink_reset(pcidev) != 0)		goto err_free_mem;	/* register /dev/dsp */	if ((dev->dev_audio = register_sound_dsp(&ad1889_fops, -1)) < 0) {		printk(KERN_ERR DEVNAME ": cannot register /dev/dsp\n");		goto err_free_irq;	}	if ((err = ad1889_ac97_init(dev, 0)) != 0)		goto err_free_dsp;	if (((proc_root = proc_mkdir("driver/ad1889", NULL)) == NULL) ||	    create_proc_read_entry("ac97", S_IFREG|S_IRUGO, proc_root, ac97_read_proc, dev->ac97_codec) == NULL ||	    create_proc_read_entry("info", S_IFREG|S_IRUGO, proc_root, ad1889_read_proc, dev) == NULL) 		goto err_free_dsp;		ad1889_initcfg(dev);	//DBG(DEVNAME ": Driver initialization done!\n");	ad1889_dev = dev;	return 0;err_free_dsp:	unregister_sound_dsp(dev->dev_audio);err_free_irq:	free_irq(pcidev->irq, dev);err_free_mem:	ad1889_free_dev(dev);	pci_set_drvdata(pcidev, NULL);	return -ENODEV;}static void __devexit ad1889_remove(struct pci_dev *pcidev){	ad1889_dev_t *dev = pci_get_drvdata(pcidev);	if (dev == NULL) return;		unregister_sound_mixer(dev->ac97_codec->dev_mixer);	unregister_sound_dsp(dev->dev_audio);	free_irq(pcidev->irq, dev);	release_mem_region(dev->regbase, AD_DSIOMEMSIZE);	/* any hw programming needed? */	ad1889_free_dev(dev);}MODULE_AUTHOR("Randolph Chung");MODULE_DESCRIPTION("Analog Devices AD1889 PCI Audio");MODULE_LICENSE("GPL");static struct pci_driver ad1889_driver = {	.name		= DEVNAME,	.id_table	= ad1889_id_tbl,	.probe		= ad1889_probe,	.remove		= __devexit_p(ad1889_remove),};static int __init ad1889_init_module(void){	return pci_module_init(&ad1889_driver);}static void ad1889_exit_module(void){	pci_unregister_driver(&ad1889_driver);	return;}module_init(ad1889_init_module);module_exit(ad1889_exit_module);

⌨️ 快捷键说明

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