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

📄 nec_vrc5477.c

📁 iis s3c2410-uda1341语音系统的 开发
💻 C
📖 第 1 页 / 共 4 页
字号:
	int ret=0;    	for (list = devs.next; ; list = list->next) {		if (list == &devs)			return -ENODEV;		s = list_entry(list, struct vrc5477_ac97_state, devs);		if (!((s->dev_audio ^ minor) & ~0xf))			break;	}	file->private_data = s;	/* wait for device to become free */	down(&s->open_sem);	while (s->open_mode & file->f_mode) {		if (file->f_flags & O_NONBLOCK) {			up(&s->open_sem);			return -EBUSY;		}		add_wait_queue(&s->open_wait, &wait);		__set_current_state(TASK_INTERRUPTIBLE);		up(&s->open_sem);		schedule();		remove_wait_queue(&s->open_wait, &wait);		set_current_state(TASK_RUNNING);		if (signal_pending(current))			return -ERESTARTSYS;		down(&s->open_sem);	}	spin_lock_irqsave(&s->lock, flags);	if (file->f_mode & FMODE_READ) {		/* set default settings */		set_adc_rate(s, 48000);		s->adcChannels = 2;		ret = prog_dmabuf_adc(s);		if (ret) goto bailout;	}	if (file->f_mode & FMODE_WRITE) {		/* set default settings */		set_dac_rate(s, 48000);		s->dacChannels = 2;		ret = prog_dmabuf_dac(s);		if (ret) goto bailout;	}	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); bailout:	spin_unlock_irqrestore(&s->lock, flags);	up(&s->open_sem);	return ret;}static int vrc5477_ac97_release(struct inode *inode, struct file *file){	struct vrc5477_ac97_state *s = 		(struct vrc5477_ac97_state *)file->private_data;	lock_kernel();	if (file->f_mode & FMODE_WRITE)		drain_dac(s, file->f_flags & O_NONBLOCK);	down(&s->open_sem);	if (file->f_mode & FMODE_WRITE) {		stop_dac(s);		dealloc_dmabuf(s, &s->dma_dac);	}	if (file->f_mode & FMODE_READ) {		stop_adc(s);		dealloc_dmabuf(s, &s->dma_adc);	}	s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);	up(&s->open_sem);	wake_up(&s->open_wait);	unlock_kernel();	return 0;}static /*const*/ struct file_operations vrc5477_ac97_audio_fops = {	owner:	THIS_MODULE,	llseek:		vrc5477_ac97_llseek,	read:		vrc5477_ac97_read,	write:		vrc5477_ac97_write,	poll:		vrc5477_ac97_poll,	ioctl:		vrc5477_ac97_ioctl,	// mmap:	vrc5477_ac97_mmap,	open:		vrc5477_ac97_open,	release:	vrc5477_ac97_release,};/* --------------------------------------------------------------------- *//* --------------------------------------------------------------------- *//* * for debugging purposes, we'll create a proc device that dumps the * CODEC chipstate */#ifdef CONFIG_LL_DEBUGstruct {       const char *regname;       unsigned regaddr;} vrc5477_ac97_regs[] = {	{"VRC5477_INT_STATUS", VRC5477_INT_STATUS},	{"VRC5477_CODEC_WR", VRC5477_CODEC_WR},	{"VRC5477_CODEC_RD", VRC5477_CODEC_RD},	{"VRC5477_CTRL", VRC5477_CTRL},	{"VRC5477_ACLINK_CTRL", VRC5477_ACLINK_CTRL},	{"VRC5477_INT_MASK", VRC5477_INT_MASK},	{"VRC5477_DAC1_CTRL", VRC5477_DAC1_CTRL},	{"VRC5477_DAC1L", VRC5477_DAC1L},	{"VRC5477_DAC1_BADDR", VRC5477_DAC1_BADDR},	{"VRC5477_DAC2_CTRL", VRC5477_DAC2_CTRL},	{"VRC5477_DAC2L", VRC5477_DAC2L},	{"VRC5477_DAC2_BADDR", VRC5477_DAC2_BADDR},	{"VRC5477_DAC3_CTRL", VRC5477_DAC3_CTRL},	{"VRC5477_DAC3L", VRC5477_DAC3L},	{"VRC5477_DAC3_BADDR", VRC5477_DAC3_BADDR},	{"VRC5477_ADC1_CTRL", VRC5477_ADC1_CTRL},	{"VRC5477_ADC1L", VRC5477_ADC1L},	{"VRC5477_ADC1_BADDR", VRC5477_ADC1_BADDR},	{"VRC5477_ADC2_CTRL", VRC5477_ADC2_CTRL},	{"VRC5477_ADC2L", VRC5477_ADC2L},	{"VRC5477_ADC2_BADDR", VRC5477_ADC2_BADDR},	{"VRC5477_ADC3_CTRL", VRC5477_ADC3_CTRL},	{"VRC5477_ADC3L", VRC5477_ADC3L},	{"VRC5477_ADC3_BADDR", VRC5477_ADC3_BADDR},	{NULL, 0x0}};static int proc_vrc5477_ac97_dump (char *buf, char **start, off_t fpos,				   int length, int *eof, void *data){	struct vrc5477_ac97_state *s;	int cnt, len = 0;	if (list_empty(&devs))		return 0;	s = list_entry(devs.next, struct vrc5477_ac97_state, devs);	/* print out header */	len += sprintf(buf + len, "\n\t\tVrc5477 Audio Debug\n\n");	// print out digital controller state	len += sprintf (buf + len, "NEC Vrc5477 Audio Controller registers\n");	len += sprintf (buf + len, "---------------------------------\n");	for (cnt=0; vrc5477_ac97_regs[cnt].regname != NULL; cnt++) {		len+= sprintf (buf + len, "%-20s = %08x\n",			       vrc5477_ac97_regs[cnt].regname,			       inl(s->io + vrc5477_ac97_regs[cnt].regaddr));	}   	/* print out driver state */	len += sprintf (buf + len, "NEC Vrc5477 Audio driver states\n");	len += sprintf (buf + len, "---------------------------------\n");	len += sprintf (buf + len, "dacChannels  = %d\n", s->dacChannels);	len += sprintf (buf + len, "adcChannels  = %d\n", s->adcChannels);	len += sprintf (buf + len, "dacRate  = %d\n", s->dacRate);	len += sprintf (buf + len, "adcRate  = %d\n", s->adcRate);	len += sprintf (buf + len, "dma_dac is %s ready\n",  	                s->dma_dac.ready? "" : "not");        if (s->dma_dac.ready) {		len += sprintf (buf + len, "dma_dac is %s stopped.\n",  	                        s->dma_dac.stopped? "" : "not");		len += sprintf (buf + len, "dma_dac.fragSize = %x\n",                                 s->dma_dac.fragSize);		len += sprintf (buf + len, "dma_dac.fragShift = %x\n",                                 s->dma_dac.fragShift);		len += sprintf (buf + len, "dma_dac.numFrag = %x\n",                                 s->dma_dac.numFrag);		len += sprintf (buf + len, "dma_dac.fragTotalSize = %x\n",                                 s->dma_dac.fragTotalSize);		len += sprintf (buf + len, "dma_dac.nextIn = %x\n",                                 s->dma_dac.nextIn);		len += sprintf (buf + len, "dma_dac.nextOut = %x\n",                                 s->dma_dac.nextOut);		len += sprintf (buf + len, "dma_dac.count = %x\n",                                 s->dma_dac.count);	}	len += sprintf (buf + len, "dma_adc is %s ready\n",  	                s->dma_adc.ready? "" : "not");        if (s->dma_adc.ready) {		len += sprintf (buf + len, "dma_adc is %s stopped.\n",  	                        s->dma_adc.stopped? "" : "not");		len += sprintf (buf + len, "dma_adc.fragSize = %x\n",                                 s->dma_adc.fragSize);		len += sprintf (buf + len, "dma_adc.fragShift = %x\n",                                 s->dma_adc.fragShift);		len += sprintf (buf + len, "dma_adc.numFrag = %x\n",                                 s->dma_adc.numFrag);		len += sprintf (buf + len, "dma_adc.fragTotalSize = %x\n",                                 s->dma_adc.fragTotalSize);		len += sprintf (buf + len, "dma_adc.nextIn = %x\n",                                 s->dma_adc.nextIn);		len += sprintf (buf + len, "dma_adc.nextOut = %x\n",                                 s->dma_adc.nextOut);		len += sprintf (buf + len, "dma_adc.count = %x\n",                                 s->dma_adc.count);	}	 	/* print out CODEC state */	len += sprintf (buf + len, "\nAC97 CODEC registers\n");	len += sprintf (buf + len, "----------------------\n");	for (cnt=0; cnt <= 0x7e; cnt = cnt +2)		len+= sprintf (buf + len, "reg %02x = %04x\n",			       cnt, rdcodec(&s->codec, cnt));	if (fpos >=len){		*start = buf;		*eof =1;		return 0;	}	*start = buf + fpos;	if ((len -= fpos) > length)		return length;	*eof =1;	return len;}#endif /* CONFIG_LL_DEBUG *//* --------------------------------------------------------------------- *//* maximum number of devices; only used for command line params */#define NR_DEVICE 5static unsigned int devindex = 0;MODULE_AUTHOR("Monta Vista Software, jsun@mvista.com or jsun@junsun.net");MODULE_DESCRIPTION("NEC Vrc5477 audio (AC97) Driver");MODULE_LICENSE("GPL");/* --------------------------------------------------------------------- */extern void jsun_scan_pci_bus(void);extern void vrc5477_show_pci_regs(void);extern void vrc5477_show_pdar_regs(void);/* -------------------------------------------------------- */#define         AC97_BASE               0xbb000000#define         myinl(x)                  *(volatile u32*)(AC97_BASE + (x))#define         myoutl(x,y)               *(volatile u32*)(AC97_BASE + (y)) = (x)u16 myrdcodec(u8 addr){        u32 result;        /* wait until we can access codec registers */        // while (inl(VRC5477_CODEC_WR) & 0x80000000);        /* write the address and "read" command to codec */        addr = addr & 0x7f;        myoutl((addr << 16) | VRC5477_CODEC_WR_RWC, VRC5477_CODEC_WR);        /* get the return result */        udelay(100); /* workaround hardware bug */        // dump_memory(0xbb000000, 48);        while ( ((result=myinl(VRC5477_CODEC_RD)) & 0xc0000000) != 0xc0000000);        MIPS_ASSERT(addr == ((result >> 16) & 0x7f) );        return result & 0xffff;}void mywrcodec(u8 addr, u16 data){        /* wait until we can access codec registers */        while (myinl(VRC5477_CODEC_WR) & 0x80000000);        /* write the address and value to codec */        myoutl((addr << 16) | data, VRC5477_CODEC_WR);}void jsun_ac97_test(struct vrc5477_ac97_state *s){        int i;        /* reset codec */	/*        wrcodec(&s->codec, 0, 0);        while (inl(s->io + VRC5477_CODEC_WR) & 0x80000000);	*/        mywrcodec(0, 0);        while (myinl(VRC5477_CODEC_WR) & 0x80000000);	for (i=0; i< 0x40; i+=4) {		MIPS_ASSERT(inl(s->io+i) == myinl(i));	}        printk("codec registers : ");        for (i=0; i<= 0x3a; i+=2) {                if ( (i%0x10) == 0) {                        printk("\n%02x\t", i);                }                // printk("%04x\t", rdcodec(&s->codec, i));                printk("%04x\t", myrdcodec(i));        }        printk("\n\n");        printk("codec registers : ");        for (i=0; i<= 0x3a; i+=2) {                if ( (i%0x10) == 0) {                        printk("\n%02x\t", i);                }                printk("%04x\t", rdcodec(&s->codec, i));        }        printk("\n\n");}static int __devinit vrc5477_ac97_probe(struct pci_dev *pcidev,					const struct pci_device_id *pciid){	struct vrc5477_ac97_state *s;	char proc_str[80];	MIPS_DEBUG(printk("vrc5477_ac97_probe() invoked\n"));	if (pcidev->irq == 0) 		return -1;	if (!(s = kmalloc(sizeof(struct vrc5477_ac97_state), GFP_KERNEL))) {		printk(KERN_ERR PFX "alloc of device struct failed\n");		return -1;	}	memset(s, 0, sizeof(struct vrc5477_ac97_state));	init_waitqueue_head(&s->dma_adc.wait);	init_waitqueue_head(&s->dma_dac.wait);	init_waitqueue_head(&s->open_wait);	init_MUTEX(&s->open_sem);	spin_lock_init(&s->lock);	s->dev = pcidev;	s->io = pci_resource_start(pcidev, 0);	s->irq = pcidev->irq;	s->codec.private_data = s;	s->codec.id = 0;	s->codec.codec_read = rdcodec;	s->codec.codec_write = wrcodec;	s->codec.codec_wait = waitcodec;	/* setting some other default values such as	 * adcChannels, adcRate is done in open() so that         * no persistent state across file opens.	 */	if (!request_region(s->io, pci_resource_len(pcidev,0),			    VRC5477_AC97_MODULE_NAME)) {		printk(KERN_ERR PFX "io ports %#lx->%#lx in use\n",		       s->io, s->io + pci_resource_len(pcidev,0)-1);		goto err_region;	}	if (request_irq(s->irq, vrc5477_ac97_interrupt, SA_INTERRUPT,			VRC5477_AC97_MODULE_NAME, s)) {		printk(KERN_ERR PFX "irq %u in use\n", s->irq);		goto err_irq;	}	printk(KERN_INFO PFX "IO at %#lx, IRQ %d\n", s->io, s->irq);	/* register devices */	if ((s->dev_audio = register_sound_dsp(&vrc5477_ac97_audio_fops, -1)) < 0)		goto err_dev1;	if ((s->codec.dev_mixer =	     register_sound_mixer(&vrc5477_ac97_mixer_fops, -1)) < 0)		goto err_dev2;#ifdef CONFIG_LL_DEBUG	/* intialize the debug proc device */	s->ps = create_proc_read_entry(VRC5477_AC97_MODULE_NAME, 0, NULL,				       proc_vrc5477_ac97_dump, NULL);#endif /* CONFIG_LL_DEBUG */		/* enable pci io and bus mastering */	if (pci_enable_device(pcidev))		goto err_dev3;	pci_set_master(pcidev);/*jsun_scan_pci_bus();vrc5477_show_pci_regs();vrc5477_show_pdar_regs();*/	/* cold reset the AC97 */	outl(VRC5477_ACLINK_CTRL_RST_ON | VRC5477_ACLINK_CTRL_RST_TIME,	     s->io + VRC5477_ACLINK_CTRL);	while (inl(s->io + VRC5477_ACLINK_CTRL) & VRC5477_ACLINK_CTRL_RST_ON);/*jsun_ac97_test(s);*/	/* codec init */	if (!ac97_probe_codec(&s->codec))		goto err_dev3;#ifdef CONFIG_LL_DEBUG	sprintf(proc_str, "driver/%s/%d/ac97", 		VRC5477_AC97_MODULE_NAME, s->codec.id);	s->ac97_ps = create_proc_read_entry (proc_str, 0, NULL,					     ac97_read_proc, &s->codec);	/* TODO : why this proc file does not show up? */#endif        /* let us get the default volumne louder */        wrcodec(&s->codec, 0x2, 0);        wrcodec(&s->codec, 0x18, 0x0707);	/* mute line in loopback to line out */	wrcodec(&s->codec, 0x10, 0x8000);	/* by default we select line in the input */	wrcodec(&s->codec, 0x1a, 0x0404);	/* pick middle value for record gain */	// wrcodec(&s->codec, 0x1c, 0x0707);	wrcodec(&s->codec, 0x1c, 0x0f0f);	wrcodec(&s->codec, 0x1e, 0x07);	/* enable the master interrupt but disable all others */	outl(VRC5477_INT_MASK_NMASK, s->io + VRC5477_INT_MASK);	/* store it in the driver field */	pci_set_drvdata(pcidev, s);	pcidev->dma_mask = 0xffffffff;	/* put it into driver list */	list_add_tail(&s->devs, &devs);	/* increment devindex */	if (devindex < NR_DEVICE-1)		devindex++;	return 0; err_dev3:	unregister_sound_mixer(s->codec.dev_mixer); err_dev2:	unregister_sound_dsp(s->dev_audio); err_dev1:	printk(KERN_ERR PFX "cannot register misc device\n");	free_irq(s->irq, s); err_irq:	release_region(s->io, pci_resource_len(pcidev,0)); err_region:	kfree(s);	return -1;}static void __devinit vrc5477_ac97_remove(struct pci_dev *dev){	struct vrc5477_ac97_state *s = pci_get_drvdata(dev);	if (!s)		return;	list_del(&s->devs);#ifdef CONFIG_LL_DEBUG	if (s->ps)		remove_proc_entry(VRC5477_AC97_MODULE_NAME, NULL);#endif /* CONFIG_LL_DEBUG */	synchronize_irq();	free_irq(s->irq, s);	release_region(s->io, pci_resource_len(dev,0));	unregister_sound_dsp(s->dev_audio);	unregister_sound_mixer(s->codec.dev_mixer);	kfree(s);	pci_set_drvdata(dev, NULL);}#define		PCI_VENDOR_ID_NEC		0x1033#define		PCI_DEVICE_ID_NEC_VRC5477_AC97	0x00A6static struct pci_device_id id_table[] __devinitdata = {    { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_VRC5477_AC97,       PCI_ANY_ID, PCI_ANY_ID, 0, 0 },    { 0, }};MODULE_DEVICE_TABLE(pci, id_table);static struct pci_driver vrc5477_ac97_driver = {	name: VRC5477_AC97_MODULE_NAME,	id_table: id_table,	probe: vrc5477_ac97_probe,	remove: vrc5477_ac97_remove};static int __init init_vrc5477_ac97(void){	if (!pci_present())   /* No PCI bus in this machine! */		return -ENODEV;	printk("Vrc5477 AC97 driver: version v0.1 time " __TIME__ " " __DATE__ " by Jun Sun\n");	return pci_module_init(&vrc5477_ac97_driver);}static void __exit cleanup_vrc5477_ac97(void){	printk(KERN_INFO PFX "unloading\n");	pci_unregister_driver(&vrc5477_ac97_driver);}module_init(init_vrc5477_ac97);module_exit(cleanup_vrc5477_ac97);

⌨️ 快捷键说明

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