/*
* 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 compatible 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 <linux/gameport.h>
#include <linux/spinlock.h>
#include "sound_config.h"
#include "ad1848.h"
#include "sb.h"
#include "mpu401.h"
#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
#define SUPPORT_JOYSTICK 1
#endif
static int mad16_conf;
static int mad16_cdsel;
static DEFINE_SPINLOCK(lock);
#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 0xf98
static int board_type = C928;
static int *mad16_osp;
static int c931_detected; /* minor differences from C930 */
static char c924pnp; /* " " " C924 */
static int debug; /* debugging output */
#ifdef DDB
#undef DDB
#endif
#define DDB(x) do {if (debug) x;} while (0)
static unsigned char mad_read(int port)
{
unsigned long flags;
unsigned char tmp;
spin_lock_irqsave(&lock,flags);
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);
spin_unlock_irqrestore(&lock,flags);
return tmp;
}
static void mad_write(int port, int value)
{
unsigned long flags;
spin_lock_irqsave(&lock,flags);
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);
spin_unlock_irqrestore(&lock,flags);
}
static<