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

📄 mad16.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) by Hannu Savolainen 1993-1997 * * mad16.c * * Initialization code for OPTi MAD16 compatible audio chips. Including * *      OPTi 82C928     MAD16           (replaced by C929) *      OAK OTI-601D    Mozart *      OAK OTI-605	Mozart		(later version with MPU401 Midi) *      OPTi 82C929     MAD16 Pro *      OPTi 82C930 *      OPTi 82C924 * * These audio interface chips don't produce sound themselves. They just * connect some other components (OPL-[234] and a WSS compatible codec) * to the PC bus and perform I/O, DMA and IRQ address decoding. There is * also a UART for the MPU-401 mode (not 82C928/Mozart). * The Mozart chip appears to be compatible with the 82C928, although later * issues of the card, using the OTI-605 chip, have an MPU-401 compatable Midi * port. This port is configured differently to that of the OPTi audio chips. * *	Changes *	 *	Alan Cox		Clean up, added module selections. * *	A. Wik			Added support for Opti924 PnP. *				Improved debugging support.	16-May-1998 *				Fixed bug.			16-Jun-1998 * *      Torsten Duwe            Made Opti924 PnP support non-destructive *                                                             	23-Dec-1998 * *	Paul Grayson		Added support for Midi on later Mozart cards. *								25-Nov-1999 *	Christoph Hellwig	Adapted to module_init/module_exit. *	Arnaldo C. de Melo	got rid of attach_uart401       21-Sep-2000 * *	Pavel Rabel		Clean up                           Nov-2000 */#include <linux/config.h>#include <linux/init.h>#include <linux/module.h>#include "sound_config.h"#include "ad1848.h"#include "sb.h"#include "mpu401.h"static int      mad16_conf;static int      mad16_cdsel;static int      already_initialized = 0;#define C928	1#define MOZART	2#define C929	3#define C930	4#define C924    5/* *    Registers * *      The MAD16 occupies I/O ports 0xf8d to 0xf93 (fixed locations). *      All ports are inactive by default. They can be activated by *      writing 0xE2 or 0xE3 to the password register. The password is valid *      only until the next I/O read or write. * *      82C930 uses 0xE4 as the password and indirect addressing to access *      the config registers. */#define MC0_PORT	0xf8c	/* Dummy port */#define MC1_PORT	0xf8d	/* SB address, CD-ROM interface type, joystick */#define MC2_PORT	0xf8e	/* CD-ROM address, IRQ, DMA, plus OPL4 bit */#define MC3_PORT	0xf8f#define PASSWD_REG	0xf8f#define MC4_PORT	0xf90#define MC5_PORT	0xf91#define MC6_PORT	0xf92#define MC7_PORT	0xf93#define MC8_PORT	0xf94#define MC9_PORT	0xf95#define MC10_PORT	0xf96#define MC11_PORT	0xf97#define MC12_PORT	0xf98static int      board_type = C928;static int     *mad16_osp;static int	c931_detected;	/* minor differences from C930 */static char	c924pnp = 0;	/* "     "           "    C924 */static int	debug = 0;	/* debugging output */#ifdef DDB#undef DDB#endif#define DDB(x) {if (debug) x;}static unsigned char mad_read(int port){	unsigned long flags;	unsigned char tmp;	save_flags(flags);	cli();	switch (board_type)	/* Output password */	{		case C928:		case MOZART:			outb((0xE2), PASSWD_REG);			break;		case C929:			outb((0xE3), PASSWD_REG);			break;		case C930:			/* outb(( 0xE4),  PASSWD_REG); */			break;		case C924:			/* the c924 has its ports relocated by -128 if			   PnP is enabled  -aw */			if (!c924pnp)				outb((0xE5), PASSWD_REG); else				outb((0xE5), PASSWD_REG - 0x80);			break;	}	if (board_type == C930)	{		outb((port - MC0_PORT), 0xe0e);	/* Write to index reg */		tmp = inb(0xe0f);	/* Read from data reg */	}	else		if (!c924pnp)			tmp = inb(port); else			tmp = inb(port-0x80);	restore_flags(flags);	return tmp;}static void mad_write(int port, int value){	unsigned long   flags;	save_flags(flags);	cli();	switch (board_type)	/* Output password */	{		case C928:		case MOZART:			outb((0xE2), PASSWD_REG);			break;		case C929:			outb((0xE3), PASSWD_REG);			break;		case C930:			/* outb(( 0xE4),  PASSWD_REG); */			break;		case C924:			if (!c924pnp)				outb((0xE5), PASSWD_REG); else				outb((0xE5), PASSWD_REG - 0x80);			break;	}	if (board_type == C930)	{		outb((port - MC0_PORT), 0xe0e);	/* Write to index reg */		outb(((unsigned char) (value & 0xff)), 0xe0f);	}	else		if (!c924pnp)			outb(((unsigned char) (value & 0xff)), port); else			outb(((unsigned char) (value & 0xff)), port-0x80);	restore_flags(flags);}static int __init detect_c930(void){	unsigned char   tmp = mad_read(MC1_PORT);	if ((tmp & 0x06) != 0x06)	{		DDB(printk("Wrong C930 signature (%x)\n", tmp));		/* return 0; */	}	mad_write(MC1_PORT, 0);	if (mad_read(MC1_PORT) != 0x06)	{		DDB(printk("Wrong C930 signature2 (%x)\n", tmp));		/* return 0; */	}	mad_write(MC1_PORT, tmp);	/* Restore bits */	mad_write(MC7_PORT, 0);	if ((tmp = mad_read(MC7_PORT)) != 0)	{		DDB(printk("MC7 not writable (%x)\n", tmp));		return 0;	}	mad_write(MC7_PORT, 0xcb);	if ((tmp = mad_read(MC7_PORT)) != 0xcb)	{		DDB(printk("MC7 not writable2 (%x)\n", tmp));		return 0;	}	tmp = mad_read(MC0_PORT+18);	if (tmp == 0xff || tmp == 0x00)		return 1;	/* We probably have a C931 */	DDB(printk("Detected C931 config=0x%02x\n", tmp));	c931_detected = 1;	/*         * We cannot configure the chip if it is in PnP mode.         * If we have a CSN assigned (bit 8 in MC13) we first try         * a software reset, then a software power off, finally         * Clearing PnP mode. The last option is not	 * Bit 8 in MC13          */	if ((mad_read(MC0_PORT+13) & 0x80) == 0)		return 1;	/* Software reset */	mad_write(MC9_PORT, 0x02);	mad_write(MC9_PORT, 0x00);	if ((mad_read(MC0_PORT+13) & 0x80) == 0)		return 1;		/* Power off, and on again */	mad_write(MC9_PORT, 0xc2);	mad_write(MC9_PORT, 0xc0);	if ((mad_read(MC0_PORT+13) & 0x80) == 0)		return 1;	#if 0		/* Force off PnP mode. This is not recommended because	 * the PnP bios will not recognize the chip on the next	 * warm boot and may assignd different resources to other	 * PnP/PCI cards.	 */	mad_write(MC0_PORT+17, 0x04);#endif	return 1;}static int __init detect_mad16(void){	unsigned char tmp, tmp2, bit;	int i, port;	/*	 * Check that reading a register doesn't return bus float (0xff)	 * when the card is accessed using password. This may fail in case	 * the card is in low power mode. Normally at least the power saving	 * mode bit should be 0.	 */	if ((tmp = mad_read(MC1_PORT)) == 0xff)	{		DDB(printk("MC1_PORT returned 0xff\n"));		return 0;	}	for (i = 0xf8d; i <= 0xf98; i++)		if (!c924pnp)			DDB(printk("Port %0x (init value) = %0x\n", i, mad_read(i))) else			DDB(printk("Port %0x (init value) = %0x\n", i-0x80, mad_read(i)));	if (board_type == C930)		return detect_c930();	/*	 * Now check that the gate is closed on first I/O after writing	 * the password. (This is how a MAD16 compatible card works).	 */	if ((tmp2 = inb(MC1_PORT)) == tmp)	/* It didn't close */	{		DDB(printk("MC1_PORT didn't close after read (0x%02x)\n", tmp2));		return 0;	}	bit  = (c924pnp) ?     0x20 : 0x80;	port = (c924pnp) ? MC2_PORT : MC1_PORT;	tmp = mad_read(port);	mad_write(port, tmp ^ bit);	/* Toggle a bit */	if ((tmp2 = mad_read(port)) != (tmp ^ bit))	/* Compare the bit */	{		mad_write(port, tmp);	/* Restore */		DDB(printk("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2));		return 0;	}	mad_write(port, tmp);	/* Restore */	return 1;		/* Bingo */}static int __init wss_init(struct address_info *hw_config){	int ad_flags = 0;	/*	 *    Verify the WSS parameters	 */	if (check_region(hw_config->io_base, 8))	{		printk(KERN_ERR "MSS: I/O port conflict\n");		return 0;	}	if (!ad1848_detect(hw_config->io_base + 4, &ad_flags, mad16_osp))		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.	 */	if ((inb(hw_config->io_base + 3) & 0x3f) != 0x04 &&	    (inb(hw_config->io_base + 3) & 0x3f) != 0x00)	{		DDB(printk("No MSS signature detected on port 0x%x (0x%x)\n", hw_config->io_base, inb(hw_config->io_base + 3)));		return 0;	}	if (hw_config->irq > 11)	{		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("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 1;}static int __init init_c930(struct address_info *hw_config){	unsigned char cfg = 0;	if(c931_detected)	{		/* Bit 0 has reversd meaning. Bits 1 and 2 sese		   reversed on write.		   Support only IDE cdrom. IDE port programmed		   somewhere else. */		cfg =  (cfg & 0x09) ^ 0x07;	}	switch (hw_config->io_base)	{		case 0x530:			cfg |= 0x00;			break;		case 0xe80:			cfg |= 0x10;			break;		case 0xf40:			cfg |= 0x20;			break;		case 0x604:			cfg |= 0x30;			break;		default:			printk(KERN_ERR "MAD16: Invalid codec port %x\n", hw_config->io_base);			return 0;	}	mad_write(MC1_PORT, cfg);	/* MC2 is CD configuration. Don't touch it. */	mad_write(MC3_PORT, 0);	/* Disable SB mode IRQ and DMA */	/* bit 2 of MC4 reverses it's meaning between the C930	   and the C931. */	cfg = c931_detected ? 0x04 : 0x00;	mad_write(MC4_PORT, 0x52|cfg);	mad_write(MC5_PORT, 0x3C);	/* Init it into mode2 */	mad_write(MC6_PORT, 0x02);	/* Enable WSS, Disable MPU and SB */	mad_write(MC7_PORT, 0xCB);	mad_write(MC10_PORT, 0x11);	return wss_init(hw_config);}static int __init chip_detect(void){	int i;	/*	 *    Then try to detect with the old password	 */	board_type = C924;	DDB(printk("Detect using password = 0xE5\n"));		if (!detect_mad16())	/* No luck. Try different model */	{		board_type = C928;		DDB(printk("Detect using password = 0xE2\n"));		if (!detect_mad16())		{			board_type = C929;			DDB(printk("Detect using password = 0xE3\n"));			if (!detect_mad16())			{				if (inb(PASSWD_REG) != 0xff)					return 0;				/*				 * First relocate MC# registers to 0xe0e/0xe0f, disable password 				 */				outb((0xE4), PASSWD_REG);				outb((0x80), PASSWD_REG);				board_type = C930;				DDB(printk("Detect using password = 0xE4\n"));				for (i = 0xf8d; i <= 0xf93; i++)					DDB(printk("port %03x = %02x\n", i, mad_read(i)));                                if(!detect_mad16()) {				  /* The C931 has the password reg at F8D */				  outb((0xE4), 0xF8D);				  outb((0x80), 0xF8D);				  DDB(printk("Detect using password = 0xE4 for C931\n"));				  if (!detect_mad16()) {				    board_type = C924;				    c924pnp++;				    DDB(printk("Detect using password = 0xE5 (again), port offset -0x80\n"));				    if (!detect_mad16()) {				      c924pnp=0;				      return 0;				    }				  				    DDB(printk("mad16.c: 82C924 PnP detected\n"));				  }				}				else				  DDB(printk("mad16.c: 82C930 detected\n"));			} else				DDB(printk("mad16.c: 82C929 detected\n"));		} else {			unsigned char model;			if (((model = mad_read(MC3_PORT)) & 0x03) == 0x03) {				DDB(printk("mad16.c: Mozart detected\n"));				board_type = MOZART;			} else {				DDB(printk("mad16.c: 82C928 detected???\n"));				board_type = C928;			}		}	}	return 1;}static int __init probe_mad16(struct address_info *hw_config){	int i;	static int valid_ports[] = 	{		0x530, 0xe80, 0xf40, 0x604	};	unsigned char tmp;	unsigned char cs4231_mode = 0;	int ad_flags = 0;	if (already_initialized)		return 0;	mad16_osp = hw_config->osp;	/*	 *    Check that all ports return 0xff (bus float) when no password	 *      is written to the password register.	 */	DDB(printk("--- Detecting MAD16 / Mozart ---\n"));	if (!chip_detect())		return 0;	if (board_type == C930)		return init_c930(hw_config);	for (i = 0xf8d; i <= 0xf93; i++)		if (!c924pnp)			DDB(printk("port %03x = %02x\n", i, mad_read(i))) else			DDB(printk("port %03x = %02x\n", i-0x80, mad_read(i)));/* * Set the WSS address */	tmp = (mad_read(MC1_PORT) & 0x0f) | 0x80;	/* Enable WSS, Disable SB */

⌨️ 快捷键说明

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