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

📄 ad1848.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	 * The bit 0x80 is always 1 in CS4248 and CS4231.	 */	DDB(printk("ad1848_detect() - step G\n"));	if (ad_flags && *ad_flags == 400)		*ad_flags = 0;	else		ad_write(devc, 12, 0x40);	/* Set mode2, clear 0x80 */	if (ad_flags)		*ad_flags = 0;	tmp1 = ad_read(devc, 12);	if (tmp1 & 0x80)	{		if (ad_flags)			*ad_flags |= AD_F_CS4248;		devc->chip_name = "CS4248";	/* Our best knowledge just now */	}	if (optiC930 || (tmp1 & 0xc0) == (0x80 | 0x40))	{		/*		 *      CS4231 detected - is it?		 *		 *      Verify that setting I0 doesn't change I16.		 */				DDB(printk("ad1848_detect() - step H\n"));		ad_write(devc, 16, 0);	/* Set I16 to known value */		ad_write(devc, 0, 0x45);		if ((tmp1 = ad_read(devc, 16)) != 0x45)	/* No change -> CS4231? */		{			ad_write(devc, 0, 0xaa);			if ((tmp1 = ad_read(devc, 16)) == 0xaa)	/* Rotten bits? */			{				DDB(printk("ad1848 detect error - step H(%x)\n", tmp1));				return 0;			}						/*			 * Verify that some bits of I25 are read only.			 */			DDB(printk("ad1848_detect() - step I\n"));			tmp1 = ad_read(devc, 25);	/* Original bits */			ad_write(devc, 25, ~tmp1);	/* Invert all bits */			if ((ad_read(devc, 25) & 0xe7) == (tmp1 & 0xe7))			{				int id;				/*				 *      It's at least CS4231				 */				devc->chip_name = "CS4231";				devc->model = MD_4231;								/*				 * It could be an AD1845 or CS4231A as well.				 * CS4231 and AD1845 report the same revision info in I25				 * while the CS4231A reports different.				 */				id = ad_read(devc, 25);				if ((id & 0xe7) == 0x80)	/* Device busy??? */					id = ad_read(devc, 25);				if ((id & 0xe7) == 0x80)	/* Device still busy??? */					id = ad_read(devc, 25);				DDB(printk("ad1848_detect() - step J (%02x/%02x)\n", id, ad_read(devc, 25)));                                if ((id & 0xe7) == 0x80) {					/* 					 * It must be a CS4231 or AD1845. The register I23 of					 * CS4231 is undefined and it appears to be read only.					 * AD1845 uses I23 for setting sample rate. Assume					 * the chip is AD1845 if I23 is changeable.					 */					unsigned char   tmp = ad_read(devc, 23);					ad_write(devc, 23, ~tmp);					if (interwave)					{						devc->model = MD_IWAVE;						devc->chip_name = "IWave";					}					else if (ad_read(devc, 23) != tmp)	/* AD1845 ? */					{						devc->chip_name = "AD1845";						devc->model = MD_1845;					}					else if (cs4248_flag)					{						if (ad_flags)							  *ad_flags |= AD_F_CS4248;						devc->chip_name = "CS4248";						devc->model = MD_1848;						ad_write(devc, 12, ad_read(devc, 12) & ~0x40);	/* Mode2 off */					}					ad_write(devc, 23, tmp);	/* Restore */				}				else				{					switch (id & 0x1f) {					case 3: /* CS4236/CS4235 */						{							int xid;							ad_write(devc, 12, ad_read(devc, 12) | 0x60); /* switch to mode 3 */							ad_write(devc, 23, 0x9c); /* select extended register 25 */							xid = inb(io_Indexed_Data(devc));							ad_write(devc, 12, ad_read(devc, 12) & ~0x60); /* back to mode 0 */							if ((xid & 0x1f) == 0x1d) {								devc->chip_name = "CS4235";								devc->model = MD_4235;							} else {								devc->chip_name = "CS4236";								devc->model = MD_4232;							}						}						break;					case 2: /* CS4232/CS4232A */						devc->chip_name = "CS4232";						devc->model = MD_4232;						break;									case 0:						if ((id & 0xe0) == 0xa0)						{							devc->chip_name = "CS4231A";							devc->model = MD_4231A;						}						else						{							devc->chip_name = "CS4321";							devc->model = MD_4231;						}						break;					default: /* maybe */						DDB(printk("ad1848: I25 = %02x/%02x\n", ad_read(devc, 25), ad_read(devc, 25) & 0xe7));                                                if (optiC930)                                                {                                                        devc->chip_name = "82C930";                                                        devc->model = MD_C930;                                                }						else						{							devc->chip_name = "CS4231";							devc->model = MD_4231;						}					}				}			}			ad_write(devc, 25, tmp1);	/* Restore bits */			DDB(printk("ad1848_detect() - step K\n"));		}	} else if (tmp1 == 0x0a) {		/*		 * Is it perhaps a SoundPro CMI8330?		 * If so, then we should be able to change indirect registers		 * greater than I15 after activating MODE2, even though reading		 * back I12 does not show it.		 */		/*		 * Let's try comparing register values		 */		for (i = 0; i < 16; i++) {			if ((tmp1 = ad_read(devc, i)) != (tmp2 = ad_read(devc, i + 16))) {				DDB(printk("ad1848 detect step H(%d/%x/%x) - SoundPro chip?\n", i, tmp1, tmp2));				soundpro = 1;				devc->chip_name = "SoundPro CMI 8330";				break;			}		}	}	DDB(printk("ad1848_detect() - step L\n"));	if (ad_flags)	{		  if (devc->model != MD_1848)			  *ad_flags |= AD_F_CS4231;	}	DDB(printk("ad1848_detect() - Detected OK\n"));	if (devc->model == MD_1848 && ad1847_flag)		devc->chip_name = "AD1847";	if (sscape_flag == 1)		devc->model = MD_1845_SSCAPE;	return 1;}int ad1848_init (char *name, int io_base, int irq, int dma_playback,		int dma_capture, int share_dma, int *osp, struct module *owner){	/*	 * NOTE! If irq < 0, there is another driver which has allocated the IRQ	 *   so that this driver doesn't need to allocate/deallocate it.	 *   The actually used IRQ is ABS(irq).	 */	int my_dev;	char dev_name[100];	int e;	ad1848_info  *devc = &adev_info[nr_ad1848_devs];	ad1848_port_info *portc = NULL;	devc->irq = (irq > 0) ? irq : 0;	devc->open_mode = 0;	devc->timer_ticks = 0;	devc->dma1 = dma_playback;	devc->dma2 = dma_capture;	devc->subtype = cfg.card_subtype;	devc->audio_flags = DMA_AUTOMODE;	devc->playback_dev = devc->record_dev = 0;	if (name != NULL)		devc->name = name;	if (name != NULL && name[0] != 0)		sprintf(dev_name,			"%s (%s)", name, devc->chip_name);	else		sprintf(dev_name,			"Generic audio codec (%s)", devc->chip_name);	request_region(devc->base, 4, devc->name);	conf_printf2(dev_name, devc->base, devc->irq, dma_playback, dma_capture);	if (devc->model == MD_1848 || devc->model == MD_C930)		devc->audio_flags |= DMA_HARDSTOP;	if (devc->model > MD_1848)	{		if (devc->dma1 == devc->dma2 || devc->dma2 == -1 || devc->dma1 == -1)			devc->audio_flags &= ~DMA_DUPLEX;		else			devc->audio_flags |= DMA_DUPLEX;	}	portc = (ad1848_port_info *) kmalloc(sizeof(ad1848_port_info), GFP_KERNEL);	if(portc==NULL)		return -1;	if (owner)		ad1848_audio_driver.owner = owner;		if ((my_dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION,					     dev_name,					     &ad1848_audio_driver,					     sizeof(struct audio_driver),					     devc->audio_flags,					     ad_format_mask[devc->model],					     devc,					     dma_playback,					     dma_capture)) < 0)	{		kfree(portc);		portc=NULL;		return -1;	}		audio_devs[my_dev]->portc = portc;	audio_devs[my_dev]->mixer_dev = -1;	memset((char *) portc, 0, sizeof(*portc));	nr_ad1848_devs++;	devc->pmdev = pm_register(PM_ISA_DEV, my_dev, ad1848_pm_callback);	if (devc->pmdev)		devc->pmdev->data = devc;	ad1848_init_hw(devc);	if (irq > 0)	{		devc->dev_no = my_dev;		if (request_irq(devc->irq, adintr, 0, devc->name, (void *)my_dev) < 0)		{			printk(KERN_WARNING "ad1848: Unable to allocate IRQ\n");			/* Don't free it either then.. */			devc->irq = 0;		}		if (capabilities[devc->model].flags & CAP_F_TIMER)		{#ifndef CONFIG_SMP			int x;			unsigned char tmp = ad_read(devc, 16);#endif						devc->timer_ticks = 0;			ad_write(devc, 21, 0x00);	/* Timer MSB */			ad_write(devc, 20, 0x10);	/* Timer LSB */#ifndef CONFIG_SMP			ad_write(devc, 16, tmp | 0x40);	/* Enable timer */			for (x = 0; x < 100000 && devc->timer_ticks == 0; x++);			ad_write(devc, 16, tmp & ~0x40);	/* Disable timer */			if (devc->timer_ticks == 0)				printk(KERN_WARNING "ad1848: Interrupt test failed (IRQ%d)\n", irq);			else			{				DDB(printk("Interrupt test OK\n"));				devc->irq_ok = 1;			}#else			devc->irq_ok = 1;#endif					}		else			devc->irq_ok = 1;	/* Couldn't test. assume it's OK */	} else if (irq < 0)		irq2dev[-irq] = devc->dev_no = my_dev;#ifndef EXCLUDE_TIMERS	if ((capabilities[devc->model].flags & CAP_F_TIMER) &&	    devc->irq_ok)		ad1848_tmr_install(my_dev);#endif	if (!share_dma)	{		if (sound_alloc_dma(dma_playback, devc->name))			printk(KERN_WARNING "ad1848.c: Can't allocate DMA%d\n", dma_playback);		if (dma_capture != dma_playback)			if (sound_alloc_dma(dma_capture, devc->name))				printk(KERN_WARNING "ad1848.c: Can't allocate DMA%d\n", dma_capture);	}	if ((e = sound_install_mixer(MIXER_DRIVER_VERSION,				     dev_name,				     &ad1848_mixer_operations,				     sizeof(struct mixer_operations),				     devc)) >= 0)	{		audio_devs[my_dev]->mixer_dev = e;	}	return my_dev;}int ad1848_control(int cmd, int arg){	ad1848_info *devc;	if (nr_ad1848_devs < 1)		return -ENODEV;	devc = &adev_info[nr_ad1848_devs - 1];	switch (cmd)	{		case AD1848_SET_XTAL:	/* Change clock frequency of AD1845 (only ) */			if (devc->model != MD_1845 || devc->model != MD_1845_SSCAPE)				return -EINVAL;			ad_enter_MCE(devc);			ad_write(devc, 29, (ad_read(devc, 29) & 0x1f) | (arg << 5));			ad_leave_MCE(devc);			break;		case AD1848_MIXER_REROUTE:		{			int o = (arg >> 8) & 0xff;			int n = arg & 0xff;			if (o < 0 || o >= SOUND_MIXER_NRDEVICES)				return -EINVAL;			if (!(devc->supported_devices & (1 << o)) &&			    !(devc->supported_rec_devices & (1 << o)))				return -EINVAL;			if (n == SOUND_MIXER_NONE)			{	/* Just hide this control */				ad1848_mixer_set(devc, o, 0);	/* Shut up it */				devc->supported_devices &= ~(1 << o);				devc->supported_rec_devices &= ~(1 << o);				break;			}			/* Make the mixer control identified by o to appear as n */			if (n < 0 || n >= SOUND_MIXER_NRDEVICES)				return -EINVAL;			devc->mixer_reroute[n] = o;	/* Rename the control */			if (devc->supported_devices & (1 << o))				devc->supported_devices |= (1 << n);			if (devc->supported_rec_devices & (1 << o))				devc->supported_rec_devices |= (1 << n);			devc->supported_devices &= ~(1 << o);			devc->supported_rec_devices &= ~(1 << o);		}		break;	}	return 0;}void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int share_dma){	int i, mixer, dev = 0;	ad1848_info *devc = NULL;	for (i = 0; devc == NULL && i < nr_ad1848_devs; i++)	{		if (adev_info[i].base == io_base)		{			devc = &adev_info[i];			dev = devc->dev_no;		}	}			if (devc != NULL)	{		if(audio_devs[dev]->portc!=NULL)			kfree(audio_devs[dev]->portc);		release_region(devc->base, 4);		if (!share_dma)		{			if (devc->irq > 0) /* There is no point in freeing irq, if it wasn't allocated */				free_irq(devc->irq, (void *)devc->dev_no);			sound_free_dma(dma_playback);			if (dma_playback != dma_capture)				sound_free_dma(dma_capture);		}		mixer = audio_devs[devc->dev_no]->mixer_dev;		if(mixer>=0)			sound_unload_mixerdev(mixer);		if (devc->pmdev)			pm_unregister(devc->pmdev);		nr_ad1848_devs--;		for ( ; i < nr_ad1848_devs ; i++)			adev_info[i] = adev_info[i+1];	}	else		printk(KERN_ERR "ad1848: Can't find device to be unloaded. Base=%x\n", io_base);}void adintr(int irq, void *dev_id, struct pt_regs *dummy){	unsigned char status;	ad1848_info *devc;	int dev;	int alt_stat = 0xff;	unsigned char c930_stat = 0;	int cnt = 0;	dev = (int)dev_id;	devc = (ad1848_info *) audio_devs[dev]->devc;interrupt_again:		/* Jump back here if int status doesn't reset */	status = inb(io_Status(devc));	if (status == 0x80)		printk(KERN_DEBUG "adintr: Why?\n");	if (devc->model == MD_1848)		outb((0), io_Status(devc));	/* Clear interrupt status */	if (status & 0x01)	{		if (devc->model == MD_C930)		{		/* 82C930 has interrupt status register in MAD16 register MC11 */			unsigned long   flags;			save_flags(flags);			cli();			/* 0xe0e is C930 address port			 * 0xe0f is C930 data port			 */			outb(11, 0xe0e);			c930_stat = inb(0xe0f);			outb((~c930_stat), 0xe0f);			restore_flags(flags);			alt_stat = (c930_stat << 2) & 0x30;		}		else if (devc->model != MD_1848)		{			alt_stat = ad_read(devc, 24);			ad_write(devc, 24, ad_read(devc, 24) & ~alt_stat);	/* Selective ack */		}		if ((devc->open_mode & OPEN_READ) && (devc->audio_mode & PCM_ENABLE_INPUT) && (alt_stat & 0x20))		{			DMAbuf_inputintr(devc->record_dev);		}		if ((devc->open_mode & OPEN_WRITE) && (devc->audio_mode & PCM_ENABLE_OUTPUT) &&		      (alt_stat & 0x10))		{			DMAbuf_outputintr(devc->playback_dev, 1);		}		if (devc->model != MD_1848 && (alt_stat & 0x40))	/* Timer interrupt */		{			devc->timer_ticks++;#ifndef EXCLUDE_TIMERS			if (timer_installed == dev && devc->timer_running)				sound_timer_interrupt();#endif		}	}/* * Sometimes playback or capture interrupts occur while a timer interrupt * is being handled. The interrupt will not be retriggered if we don't * handle it now. Check if an interrupt is still pending and restart * the handler in this case. */	if (inb(io_Status(devc)) & 0x01 && cnt++ < 4)	{		  goto interrupt_again;	}}/* *	Experimental initialization sequence for the integrated sound system *	of the Compaq Deskpro M. */static int init_deskpro_m(struct address_info *hw_config){	unsigned char   tmp;	if ((tmp = inb(0xc44)) == 0xff)	{		DDB(printk("init_deskpro_m: Dead port 0xc44\n"));		return 0;	}	outb(0x10, 0xc44);	outb(0x40, 0xc45);

⌨️ 快捷键说明

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