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

📄 ad1848.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	outb(0x00, 0xc46);	outb(0xe8, 0xc47);	outb(0x14, 0xc44);	outb(0x40, 0xc45);	outb(0x00, 0xc46);	outb(0xe8, 0xc47);	outb(0x10, 0xc44);	return 1;}/* *	Experimental initialization sequence for the integrated sound system *	of Compaq Deskpro XL. */static int init_deskpro(struct address_info *hw_config){	unsigned char   tmp;	if ((tmp = inb(0xc44)) == 0xff)	{		DDB(printk("init_deskpro: Dead port 0xc44\n"));		return 0;	}	outb((tmp | 0x04), 0xc44);	/* Select bank 1 */	if (inb(0xc44) != 0x04)	{		DDB(printk("init_deskpro: Invalid bank1 signature in port 0xc44\n"));		return 0;	}	/*	 * OK. It looks like a Deskpro so let's proceed.	 */	/*	 * I/O port 0xc44 Audio configuration register.	 *	 * bits 0xc0:   Audio revision bits	 *              0x00 = Compaq Business Audio	 *              0x40 = MS Sound System Compatible (reset default)	 *              0x80 = Reserved	 *              0xc0 = Reserved	 * bit 0x20:    No Wait State Enable	 *              0x00 = Disabled (reset default, DMA mode)	 *              0x20 = Enabled (programmed I/O mode)	 * bit 0x10:    MS Sound System Decode Enable	 *              0x00 = Decoding disabled (reset default)	 *              0x10 = Decoding enabled	 * bit 0x08:    FM Synthesis Decode Enable	 *              0x00 = Decoding Disabled (reset default)	 *              0x08 = Decoding enabled	 * bit 0x04     Bank select	 *              0x00 = Bank 0	 *              0x04 = Bank 1	 * bits 0x03    MSS Base address	 *              0x00 = 0x530 (reset default)	 *              0x01 = 0x604	 *              0x02 = 0xf40	 *              0x03 = 0xe80	 */#ifdef DEBUGXL	/* Debug printing */	printk("Port 0xc44 (before): ");	outb((tmp & ~0x04), 0xc44);	printk("%02x ", inb(0xc44));	outb((tmp | 0x04), 0xc44);	printk("%02x\n", inb(0xc44));#endif	/* Set bank 1 of the register */	tmp = 0x58;		/* MSS Mode, MSS&FM decode enabled */	switch (hw_config->io_base)	{		case 0x530:			tmp |= 0x00;			break;		case 0x604:			tmp |= 0x01;			break;		case 0xf40:			tmp |= 0x02;			break;		case 0xe80:			tmp |= 0x03;			break;		default:			DDB(printk("init_deskpro: Invalid MSS port %x\n", hw_config->io_base));			return 0;	}	outb((tmp & ~0x04), 0xc44);	/* Write to bank=0 */#ifdef DEBUGXL	/* Debug printing */	printk("Port 0xc44 (after): ");	outb((tmp & ~0x04), 0xc44);	/* Select bank=0 */	printk("%02x ", inb(0xc44));	outb((tmp | 0x04), 0xc44);	/* Select bank=1 */	printk("%02x\n", inb(0xc44));#endif	/*	 * I/O port 0xc45 FM Address Decode/MSS ID Register.	 *	 * bank=0, bits 0xfe:   FM synthesis Decode Compare bits 7:1 (default=0x88)	 * bank=0, bit 0x01:    SBIC Power Control Bit	 *                      0x00 = Powered up	 *                      0x01 = Powered down	 * bank=1, bits 0xfc:   MSS ID (default=0x40)	 */#ifdef DEBUGXL	/* Debug printing */	printk("Port 0xc45 (before): ");	outb((tmp & ~0x04), 0xc44);	/* Select bank=0 */	printk("%02x ", inb(0xc45));	outb((tmp | 0x04), 0xc44);	/* Select bank=1 */	printk("%02x\n", inb(0xc45));#endif	outb((tmp & ~0x04), 0xc44);	/* Select bank=0 */	outb((0x88), 0xc45);	/* FM base 7:0 = 0x88 */	outb((tmp | 0x04), 0xc44);	/* Select bank=1 */	outb((0x10), 0xc45);	/* MSS ID = 0x10 (MSS port returns 0x04) */#ifdef DEBUGXL	/* Debug printing */	printk("Port 0xc45 (after): ");	outb((tmp & ~0x04), 0xc44);	/* Select bank=0 */	printk("%02x ", inb(0xc45));	outb((tmp | 0x04), 0xc44);	/* Select bank=1 */	printk("%02x\n", inb(0xc45));#endif	/*	 * I/O port 0xc46 FM Address Decode/Address ASIC Revision Register.	 *	 * bank=0, bits 0xff:   FM synthesis Decode Compare bits 15:8 (default=0x03)	 * bank=1, bits 0xff:   Audio addressing ASIC id	 */#ifdef DEBUGXL	/* Debug printing */	printk("Port 0xc46 (before): ");	outb((tmp & ~0x04), 0xc44);	/* Select bank=0 */	printk("%02x ", inb(0xc46));	outb((tmp | 0x04), 0xc44);	/* Select bank=1 */	printk("%02x\n", inb(0xc46));#endif	outb((tmp & ~0x04), 0xc44);	/* Select bank=0 */	outb((0x03), 0xc46);	/* FM base 15:8 = 0x03 */	outb((tmp | 0x04), 0xc44);	/* Select bank=1 */	outb((0x11), 0xc46);	/* ASIC ID = 0x11 */#ifdef DEBUGXL	/* Debug printing */	printk("Port 0xc46 (after): ");	outb((tmp & ~0x04), 0xc44);	/* Select bank=0 */	printk("%02x ", inb(0xc46));	outb((tmp | 0x04), 0xc44);	/* Select bank=1 */	printk("%02x\n", inb(0xc46));#endif	/*	 * I/O port 0xc47 FM Address Decode Register.	 *	 * bank=0, bits 0xff:   Decode enable selection for various FM address bits	 * bank=1, bits 0xff:   Reserved	 */#ifdef DEBUGXL	/* Debug printing */	printk("Port 0xc47 (before): ");	outb((tmp & ~0x04), 0xc44);	/* Select bank=0 */	printk("%02x ", inb(0xc47));	outb((tmp | 0x04), 0xc44);	/* Select bank=1 */	printk("%02x\n", inb(0xc47));#endif	outb((tmp & ~0x04), 0xc44);	/* Select bank=0 */	outb((0x7c), 0xc47);	/* FM decode enable bits = 0x7c */	outb((tmp | 0x04), 0xc44);	/* Select bank=1 */	outb((0x00), 0xc47);	/* Reserved bank1 = 0x00 */#ifdef DEBUGXL	/* Debug printing */	printk("Port 0xc47 (after): ");	outb((tmp & ~0x04), 0xc44);	/* Select bank=0 */	printk("%02x ", inb(0xc47));	outb((tmp | 0x04), 0xc44);	/* Select bank=1 */	printk("%02x\n", inb(0xc47));#endif	/*	 * I/O port 0xc6f = Audio Disable Function Register	 */#ifdef DEBUGXL	printk("Port 0xc6f (before) = %02x\n", inb(0xc6f));#endif	outb((0x80), 0xc6f);#ifdef DEBUGXL	printk("Port 0xc6f (after) = %02x\n", inb(0xc6f));#endif	return 1;}int probe_ms_sound(struct address_info *hw_config){	unsigned char   tmp;	DDB(printk("Entered probe_ms_sound(%x, %d)\n", hw_config->io_base, hw_config->card_subtype));	if (check_region(hw_config->io_base, 8))	{		printk(KERN_ERR "MSS: I/O port conflict\n");		return 0;	}	if (hw_config->card_subtype == 1)	/* Has no IRQ/DMA registers */	{		/* check_opl3(0x388, hw_config); */		return ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp);	}	if (deskpro_xl && hw_config->card_subtype == 2)	/* Compaq Deskpro XL */	{		if (!init_deskpro(hw_config))			return 0;	}	if (deskpro_m)	/* Compaq Deskpro M */	{		if (!init_deskpro_m(hw_config))			return 0;	}	/*	   * Check if the IO port returns valid signature. The original MS Sound	   * system returns 0x04 while some cards (AudioTrix Pro for example)	   * return 0x00 or 0x0f.	 */	if ((tmp = inb(hw_config->io_base + 3)) == 0xff)	/* Bus float */	{		  int             ret;		  DDB(printk("I/O address is inactive (%x)\n", tmp));		  if (!(ret = ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp)))			  return 0;		  return 1;	}	DDB(printk("MSS signature = %x\n", tmp & 0x3f));	if ((tmp & 0x3f) != 0x04 &&	    (tmp & 0x3f) != 0x0f &&	    (tmp & 0x3f) != 0x00)	{		int ret;		MDB(printk(KERN_ERR "No MSS signature detected on port 0x%x (0x%x)\n", hw_config->io_base, (int) inb(hw_config->io_base + 3)));		DDB(printk("Trying to detect codec anyway but IRQ/DMA may not work\n"));		if (!(ret = ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp)))			return 0;		hw_config->card_subtype = 1;		return 1;	}	if ((hw_config->irq != 5)  &&	    (hw_config->irq != 7)  &&	    (hw_config->irq != 9)  &&	    (hw_config->irq != 10) &&	    (hw_config->irq != 11) &&	    (hw_config->irq != 12))	{		printk(KERN_ERR "MSS: Bad IRQ %d\n", hw_config->irq);		return 0;	}	if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3)	{		  printk(KERN_ERR "MSS: Bad DMA %d\n", hw_config->dma);		  return 0;	}	/*	 * Check that DMA0 is not in use with a 8 bit board.	 */	if (hw_config->dma == 0 && inb(hw_config->io_base + 3) & 0x80)	{		printk(KERN_ERR "MSS: Can't use DMA0 with a 8 bit card/slot\n");		return 0;	}	if (hw_config->irq > 7 && hw_config->irq != 9 && inb(hw_config->io_base + 3) & 0x80)	{		printk(KERN_ERR "MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq);		return 0;	}	return ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp);}void attach_ms_sound(struct address_info *hw_config, struct module *owner){	static signed char interrupt_bits[12] =	{		-1, -1, -1, -1, -1, 0x00, -1, 0x08, -1, 0x10, 0x18, 0x20	};	signed char     bits;	char            dma2_bit = 0;	static char     dma_bits[4] =	{		1, 2, 0, 3	};	int config_port = hw_config->io_base + 0;	int version_port = hw_config->io_base + 3;	int dma = hw_config->dma;	int dma2 = hw_config->dma2;	if (hw_config->card_subtype == 1)	/* Has no IRQ/DMA registers */	{		hw_config->slots[0] = ad1848_init("MS Sound System", hw_config->io_base + 4,						    hw_config->irq,						    hw_config->dma,						    hw_config->dma2, 0, 						    hw_config->osp,						    owner);		request_region(hw_config->io_base, 4, "WSS config");		return;	}	/*	 * Set the IRQ and DMA addresses.	 */	bits = interrupt_bits[hw_config->irq];	if (bits == -1)	{		printk(KERN_ERR "MSS: Bad IRQ %d\n", hw_config->irq);		return;	}	outb((bits | 0x40), config_port);	if ((inb(version_port) & 0x40) == 0)		printk(KERN_ERR "[MSS: IRQ Conflict?]\n");/* * Handle the capture DMA channel */	if (dma2 != -1 && dma2 != dma)	{		if (!((dma == 0 && dma2 == 1) ||			(dma == 1 && dma2 == 0) ||			(dma == 3 && dma2 == 0)))		{	/* Unsupported combination. Try to swap channels */			int tmp = dma;			dma = dma2;			dma2 = tmp;		}		if ((dma == 0 && dma2 == 1) ||			(dma == 1 && dma2 == 0) ||			(dma == 3 && dma2 == 0))		{			dma2_bit = 0x04;	/* Enable capture DMA */		}		else		{			printk(KERN_WARNING "MSS: Invalid capture DMA\n");			dma2 = dma;		}	}	else	{		dma2 = dma;	}	hw_config->dma = dma;	hw_config->dma2 = dma2;	outb((bits | dma_bits[dma] | dma2_bit), config_port);	/* Write IRQ+DMA setup */	hw_config->slots[0] = ad1848_init("MS Sound System", hw_config->io_base + 4,					  hw_config->irq,					  dma, dma2, 0,					  hw_config->osp,					  THIS_MODULE);	request_region(hw_config->io_base, 4, "WSS config");}void unload_ms_sound(struct address_info *hw_config){	ad1848_unload(hw_config->io_base + 4,		      hw_config->irq,		      hw_config->dma,		      hw_config->dma2, 0);	sound_unload_audiodev(hw_config->slots[0]);	release_region(hw_config->io_base, 4);}#ifndef EXCLUDE_TIMERS/* * Timer stuff (for /dev/music). */static unsigned int current_interval = 0;static unsigned int ad1848_tmr_start(int dev, unsigned int usecs){	unsigned long   flags;	ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;	unsigned long   xtal_nsecs;	/* nanoseconds per xtal oscillator tick */	unsigned long   divider;	save_flags(flags);	cli();	/*	 * Length of the timer interval (in nanoseconds) depends on the	 * selected crystal oscillator. Check this from bit 0x01 of I8.	 *	 * AD1845 has just one oscillator which has cycle time of 10.050 us	 * (when a 24.576 MHz xtal oscillator is used).	 *	 * Convert requested interval to nanoseconds before computing	 * the timer divider.	 */	if (devc->model == MD_1845 || devc->model == MD_1845_SSCAPE)		xtal_nsecs = 10050;	else if (ad_read(devc, 8) & 0x01)		xtal_nsecs = 9920;	else		xtal_nsecs = 9969;	divider = (usecs * 1000 + xtal_nsecs / 2) / xtal_nsecs;	if (divider < 100)	/* Don't allow shorter intervals than about 1ms */		divider = 100;	if (divider > 65535)	/* Overflow check */		divider = 65535;	ad_write(devc, 21, (divider >> 8) & 0xff);	/* Set upper bits */	ad_write(devc, 20, divider & 0xff);	/* Set lower bits */	ad_write(devc, 16, ad_read(devc, 16) | 0x40);	/* Start the timer */	devc->timer_running = 1;	restore_flags(flags);	return current_interval = (divider * xtal_nsecs + 500) / 1000;}static void ad1848_tmr_reprogram(int dev){	/*	 *    Audio driver has changed sampling rate so that a different xtal	 *      oscillator was selected. We have to reprogram the timer rate.	 */	ad1848_tmr_start(dev, current_interval);	sound_timer_syncinterval(current_interval);}static void ad1848_tmr_disable(int dev){	unsigned long   flags;	ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;	save_flags(flags);	cli();	ad_write(devc, 16, ad_read(devc, 16) & ~0x40);	devc->timer_running = 0;	restore_flags(flags);}static void ad1848_tmr_restart(int dev){	unsigned long   flags;	ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;	if (current_interval == 0)		return;	save_flags(flags);	cli();	ad_write(devc, 16, ad_read(devc, 16) | 0x40);	devc->timer_running = 1;	restore_flags(flags);}static struct sound_lowlev_timer ad1848_tmr ={	0,	2,	ad1848_tmr_start,	ad1848_tmr_disable,	ad1848_tmr_restart};static int ad1848_tmr_install(int dev){	if (timer_installed != -1)		return 0;	/* Don't install another timer */	timer_installed = ad1848_tmr.dev = dev;	sound_timer_init(&ad1848_tmr, audio_devs[dev]->name);	return 1;}#endif /* EXCLUDE_TIMERS */static int ad1848_suspend(ad1848_info *devc){	unsigned long flags;	save_flags(flags);	cli();	ad_mute(devc);		restore_flags(flags);	return 0;}static int ad1848_resume(ad1848_info *devc){	unsigned long flags;	int mixer_levels[32], i;	save_flags(flags);	cli();	/* store old mixer levels */	memcpy(mixer_levels, devc->levels, sizeof (mixer_levels));  	ad1848_init_hw(devc);	/* restore mixer levels */	for (i = 0; i < 32; i++)		ad1848_mixer_set(devc, devc->dev_no, mixer_levels[i]);	if (!devc->subtype) {		static signed char interrupt_bits[12

⌨️ 快捷键说明

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