2005-04-17 02:20:36 +04:00
/*
* Copyright ( C ) by Hannu Savolainen 1993 - 1997
*
* mad16 . c
*
* Initialization code for OPTi MAD16 compatible audio chips . Including
*
* OPTi 82 C928 MAD16 ( replaced by C929 )
* OAK OTI - 601 D Mozart
* OAK OTI - 605 Mozart ( later version with MPU401 Midi )
* OPTi 82 C929 MAD16 Pro
* OPTi 82 C930
* OPTi 82 C924
*
* 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 82 C928 / Mozart ) .
* The Mozart chip appears to be compatible with the 82 C928 , 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"
2005-06-01 11:38:46 +04:00
# if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
# define SUPPORT_JOYSTICK 1
# endif
2005-04-17 02:20:36 +04:00
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 .
*
* 82 C930 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 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 )
{
/*
* 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 ;
}
/*
* 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 > 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 void __init init_c930 ( struct address_info * hw_config , int base )
{
unsigned char cfg = 0 ;
cfg | = ( 0x0f & mad16_conf ) ;
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 ;
}
cfg | = base < < 4 ;
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 ;
if ( mad16_cdsel & 0x20 )
mad_write ( MC4_PORT , 0x62 | cfg ) ; /* opl4 */
else
mad_write ( MC4_PORT , 0x52 | cfg ) ; /* opl3 */
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 ) ;
}
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 ( ) ) {
return 1 ;
}
board_type = C928 ;
DDB ( printk ( " Detect using password = 0xE2 \n " ) ) ;
if ( detect_mad16 ( ) )
{
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 ;
}
board_type = C929 ;
DDB ( printk ( " Detect using password = 0xE3 \n " ) ) ;
if ( detect_mad16 ( ) )
{
DDB ( printk ( " mad16.c: 82C929 detected \n " ) ) ;
return 1 ;
}
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 ( ) ) {
DDB ( printk ( " mad16.c: 82C930 detected \n " ) ) ;
return 1 ;
}
/* 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 ( ) ) {
return 1 ;
}
board_type = C924 ;
c924pnp + + ;
DDB ( printk ( " Detect using password = 0xE5 (again), port offset -0x80 \n " ) ) ;
if ( detect_mad16 ( ) ) {
DDB ( printk ( " mad16.c: 82C924 PnP detected \n " ) ) ;
return 1 ;
}
c924pnp = 0 ;
return 0 ;
}
static int __init probe_mad16 ( struct address_info * hw_config )
{
int i ;
unsigned char tmp ;
unsigned char cs4231_mode = 0 ;
int ad_flags = 0 ;
signed char bits ;
static char dma_bits [ 4 ] = {
1 , 2 , 0 , 3
} ;
int config_port = hw_config - > io_base + 0 , version_port = hw_config - > io_base + 3 ;
int dma = hw_config - > dma , dma2 = hw_config - > dma2 ;
unsigned char dma2_bit = 0 ;
int base ;
struct resource * ports ;
mad16_osp = hw_config - > osp ;
switch ( hw_config - > io_base ) {
case 0x530 :
base = 0 ;
break ;
case 0xe80 :
base = 1 ;
break ;
case 0xf40 :
base = 2 ;
break ;
case 0x604 :
base = 3 ;
break ;
default :
printk ( KERN_ERR " MAD16/Mozart: Bad WSS base address 0x%x \n " , hw_config - > io_base ) ;
return 0 ;
}
if ( dma ! = 0 & & dma ! = 1 & & dma ! = 3 ) {
printk ( KERN_ERR " MSS: Bad DMA %d \n " , dma ) ;
return 0 ;
}
/*
* 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 ;
switch ( hw_config - > irq ) {
case 7 :
bits = 8 ;
break ;
case 9 :
bits = 0x10 ;
break ;
case 10 :
bits = 0x18 ;
break ;
case 12 :
bits = 0x20 ;
break ;
case 5 : /* Also IRQ5 is possible on C930 */
if ( board_type = = C930 | | c924pnp ) {
bits = 0x28 ;
break ;
}
default :
printk ( KERN_ERR " MAD16/Mozart: Bad IRQ %d \n " , hw_config - > irq ) ;
return 0 ;
}
ports = request_region ( hw_config - > io_base + 4 , 4 , " ad1848 " ) ;
if ( ! ports ) {
printk ( KERN_ERR " MSS: I/O port conflict \n " ) ;
return 0 ;
}
if ( ! request_region ( hw_config - > io_base , 4 , " mad16 WSS config " ) ) {
release_region ( hw_config - > io_base + 4 , 4 ) ;
printk ( KERN_ERR " MSS: I/O port conflict \n " ) ;
return 0 ;
}
if ( board_type = = C930 ) {
init_c930 ( hw_config , base ) ;
goto got_it ;
}
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 */
tmp | = base < < 4 ; /* WSS port select bits */
/*
* Set optional CD - ROM and joystick settings .
*/
tmp & = ~ 0x0f ;
tmp | = ( mad16_conf & 0x0f ) ; /* CD-ROM and joystick bits */
mad_write ( MC1_PORT , tmp ) ;
tmp = mad16_cdsel ;
mad_write ( MC2_PORT , tmp ) ;
mad_write ( MC3_PORT , 0xf0 ) ; /* Disable SB */
if ( board_type = = C924 ) /* Specific C924 init values */
{
mad_write ( MC4_PORT , 0xA0 ) ;
mad_write ( MC5_PORT , 0x05 ) ;
mad_write ( MC6_PORT , 0x03 ) ;
}
if ( ! ad1848_detect ( ports , & ad_flags , mad16_osp ) )
goto fail ;
if ( ad_flags & ( AD_F_CS4231 | AD_F_CS4248 ) )
cs4231_mode = 0x02 ; /* CS4248/CS4231 sync delay switch */
if ( board_type = = C929 )
{
mad_write ( MC4_PORT , 0xa2 ) ;
mad_write ( MC5_PORT , 0xA5 | cs4231_mode ) ;
mad_write ( MC6_PORT , 0x03 ) ; /* Disable MPU401 */
}
else
{
mad_write ( MC4_PORT , 0x02 ) ;
mad_write ( MC5_PORT , 0x30 | cs4231_mode ) ;
}
for ( i = 0xf8d ; i < = 0xf93 ; i + + ) {
if ( ! c924pnp )
DDB ( printk ( " port %03x after init = %02x \n " , i , mad_read ( i ) ) ) ;
else
DDB ( printk ( " port %03x after init = %02x \n " , i - 0x80 , mad_read ( i ) ) ) ;
}
got_it :
ad_flags = 0 ;
if ( ! ad1848_detect ( ports , & ad_flags , mad16_osp ) )
goto fail ;
if ( ! wss_init ( hw_config ) )
goto fail ;
/*
* Set the IRQ and DMA addresses .
*/
outb ( ( bits | 0x40 ) , config_port ) ;
if ( ( inb ( version_port ) & 0x40 ) = = 0 )
printk ( KERN_ERR " [IRQ Conflict?] \n " ) ;
/*
* Handle the capture DMA channel
*/
if ( ad_flags & AD_F_CS4231 & & 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 ( " MAD16: Invalid capture DMA \n " ) ;
dma2 = dma ;
}
}
else dma2 = dma ;
outb ( ( bits | dma_bits [ dma ] | dma2_bit ) , config_port ) ; /* Write IRQ+DMA setup */
hw_config - > slots [ 0 ] = ad1848_init ( " mad16 WSS " , ports ,
hw_config - > irq ,
dma ,
dma2 , 0 ,
hw_config - > osp ,
THIS_MODULE ) ;
return 1 ;
fail :
release_region ( hw_config - > io_base + 4 , 4 ) ;
release_region ( hw_config - > io_base , 4 ) ;
return 0 ;
}
static int __init probe_mad16_mpu ( struct address_info * hw_config )
{
unsigned char tmp ;
if ( board_type < C929 ) /* Early chip. No MPU support. Just SB MIDI */
{
# ifdef CONFIG_MAD16_OLDCARD
tmp = mad_read ( MC3_PORT ) ;
/*
* MAD16 SB base is defined by the WSS base . It cannot be changed
* alone .
* Ignore configured I / O base . Use the active setting .
*/
if ( mad_read ( MC1_PORT ) & 0x20 )
hw_config - > io_base = 0x240 ;
else
hw_config - > io_base = 0x220 ;
switch ( hw_config - > irq )
{
case 5 :
tmp = ( tmp & 0x3f ) | 0x80 ;
break ;
case 7 :
tmp = ( tmp & 0x3f ) ;
break ;
case 11 :
tmp = ( tmp & 0x3f ) | 0x40 ;
break ;
default :
printk ( KERN_ERR " mad16/Mozart: Invalid MIDI IRQ \n " ) ;
return 0 ;
}
mad_write ( MC3_PORT , tmp | 0x04 ) ;
hw_config - > driver_use_1 = SB_MIDI_ONLY ;
if ( ! request_region ( hw_config - > io_base , 16 , " soundblaster " ) )
return 0 ;
if ( ! sb_dsp_detect ( hw_config , 0 , 0 , NULL ) ) {
release_region ( hw_config - > io_base , 16 ) ;
return 0 ;
}
if ( mad_read ( MC1_PORT ) & 0x20 )
hw_config - > io_base = 0x240 ;
else
hw_config - > io_base = 0x220 ;
hw_config - > name = " Mad16/Mozart " ;
sb_dsp_init ( hw_config , THIS_MODULE ) ;
return 1 ;
# else
/* assuming all later Mozart cards are identified as
* either 82 C928 or Mozart . If so , following code attempts
* to set MPU register . TODO - add probing
*/
tmp = mad_read ( MC8_PORT ) ;
switch ( hw_config - > irq )
{
case 5 :
tmp | = 0x08 ;
break ;
case 7 :
tmp | = 0x10 ;
break ;
case 9 :
tmp | = 0x18 ;
break ;
case 10 :
tmp | = 0x20 ;
break ;
case 11 :
tmp | = 0x28 ;
break ;
default :
printk ( KERN_ERR " mad16/MOZART: invalid mpu_irq \n " ) ;
return 0 ;
}
switch ( hw_config - > io_base )
{
case 0x300 :
tmp | = 0x01 ;
break ;
case 0x310 :
tmp | = 0x03 ;
break ;
case 0x320 :
tmp | = 0x05 ;
break ;
case 0x330 :
tmp | = 0x07 ;
break ;
default :
printk ( KERN_ERR " mad16/MOZART: invalid mpu_io \n " ) ;
return 0 ;
}
mad_write ( MC8_PORT , tmp ) ; /* write MPU port parameters */
goto probe_401 ;
# endif
}
tmp = mad_read ( MC6_PORT ) & 0x83 ;
tmp | = 0x80 ; /* MPU-401 enable */
/* Set the MPU base bits */
switch ( hw_config - > io_base )
{
case 0x300 :
tmp | = 0x60 ;
break ;
case 0x310 :
tmp | = 0x40 ;
break ;
case 0x320 :
tmp | = 0x20 ;
break ;
case 0x330 :
tmp | = 0x00 ;
break ;
default :
printk ( KERN_ERR " MAD16: Invalid MIDI port 0x%x \n " , hw_config - > io_base ) ;
return 0 ;
}
/* Set the MPU IRQ bits */
switch ( hw_config - > irq )
{
case 5 :
tmp | = 0x10 ;
break ;
case 7 :
tmp | = 0x18 ;
break ;
case 9 :
tmp | = 0x00 ;
break ;
case 10 :
tmp | = 0x08 ;
break ;
default :
printk ( KERN_ERR " MAD16: Invalid MIDI IRQ %d \n " , hw_config - > irq ) ;
break ;
}
mad_write ( MC6_PORT , tmp ) ; /* Write MPU401 config */
# ifndef CONFIG_MAD16_OLDCARD
probe_401 :
# endif
hw_config - > driver_use_1 = SB_MIDI_ONLY ;
hw_config - > name = " Mad16/Mozart " ;
return probe_uart401 ( hw_config , THIS_MODULE ) ;
}
static void __exit unload_mad16 ( struct address_info * hw_config )
{
ad1848_unload ( hw_config - > io_base + 4 ,
hw_config - > irq ,
hw_config - > dma ,
hw_config - > dma2 , 0 ) ;
release_region ( hw_config - > io_base , 4 ) ;
sound_unload_audiodev ( hw_config - > slots [ 0 ] ) ;
}
static void __exit unload_mad16_mpu ( struct address_info * hw_config )
{
# ifdef CONFIG_MAD16_OLDCARD
if ( board_type < C929 ) /* Early chip. No MPU support. Just SB MIDI */
{
sb_dsp_unload ( hw_config , 0 ) ;
return ;
}
# endif
unload_uart401 ( hw_config ) ;
}
static struct address_info cfg ;
static struct address_info cfg_mpu ;
static int found_mpu ;
static int __initdata mpu_io = 0 ;
static int __initdata mpu_irq = 0 ;
static int __initdata io = - 1 ;
static int __initdata dma = - 1 ;
static int __initdata dma16 = - 1 ; /* Set this for modules that need it */
static int __initdata irq = - 1 ;
static int __initdata cdtype = 0 ;
static int __initdata cdirq = 0 ;
static int __initdata cdport = 0x340 ;
static int __initdata cddma = - 1 ;
static int __initdata opl4 = 0 ;
static int __initdata joystick = 0 ;
module_param ( mpu_io , int , 0 ) ;
module_param ( mpu_irq , int , 0 ) ;
module_param ( io , int , 0 ) ;
module_param ( dma , int , 0 ) ;
module_param ( dma16 , int , 0 ) ;
module_param ( irq , int , 0 ) ;
module_param ( cdtype , int , 0 ) ;
module_param ( cdirq , int , 0 ) ;
module_param ( cdport , int , 0 ) ;
module_param ( cddma , int , 0 ) ;
module_param ( opl4 , int , 0 ) ;
module_param ( joystick , bool , 0 ) ;
module_param ( debug , bool , 0644 ) ;
static int __initdata dma_map [ 2 ] [ 8 ] =
{
{ 0x03 , - 1 , - 1 , - 1 , - 1 , 0x00 , 0x01 , 0x02 } ,
{ 0x03 , - 1 , 0x01 , 0x00 , - 1 , - 1 , - 1 , - 1 }
} ;
static int __initdata irq_map [ 16 ] =
{
0x00 , - 1 , - 1 , 0x0A ,
- 1 , 0x04 , - 1 , 0x08 ,
- 1 , 0x10 , 0x14 , 0x18 ,
- 1 , - 1 , - 1 , - 1
} ;
2005-06-01 11:38:46 +04:00
# ifdef SUPPORT_JOYSTICK
static struct gameport * gameport ;
2005-04-17 02:20:36 +04:00
static int __devinit mad16_register_gameport ( int io_port )
{
if ( ! request_region ( io_port , 1 , " mad16 gameport " ) ) {
printk ( KERN_ERR " mad16: gameport address 0x%#x already in use \n " , io_port ) ;
return - EBUSY ;
}
gameport = gameport_allocate_port ( ) ;
if ( ! gameport ) {
printk ( KERN_ERR " mad16: can not allocate memory for gameport \n " ) ;
release_region ( io_port , 1 ) ;
return - ENOMEM ;
}
gameport_set_name ( gameport , " MAD16 Gameport " ) ;
gameport_set_phys ( gameport , " isa%04x/gameport0 " , io_port ) ;
gameport - > io = io_port ;
gameport_register_port ( gameport ) ;
return 0 ;
}
2005-06-01 11:38:46 +04:00
static inline void mad16_unregister_gameport ( void )
{
if ( gameport ) {
/* the gameport was initialized so we must free it up */
gameport_unregister_port ( gameport ) ;
gameport = NULL ;
release_region ( 0x201 , 1 ) ;
}
}
# else
static inline int mad16_register_gameport ( int io_port ) { return - ENOSYS ; }
static inline void mad16_unregister_gameport ( void ) { }
# endif
2005-04-17 02:20:36 +04:00
static int __devinit init_mad16 ( void )
{
int dmatype = 0 ;
printk ( KERN_INFO " MAD16 audio driver Copyright (C) by Hannu Savolainen 1993-1996 \n " ) ;
printk ( KERN_INFO " CDROM " ) ;
switch ( cdtype )
{
case 0x00 :
printk ( " Disabled " ) ;
cdirq = 0 ;
break ;
case 0x02 :
printk ( " Sony CDU31A " ) ;
dmatype = 1 ;
if ( cddma = = - 1 ) cddma = 3 ;
break ;
case 0x04 :
printk ( " Mitsumi " ) ;
dmatype = 0 ;
if ( cddma = = - 1 ) cddma = 5 ;
break ;
case 0x06 :
printk ( " Panasonic Lasermate " ) ;
dmatype = 1 ;
if ( cddma = = - 1 ) cddma = 3 ;
break ;
case 0x08 :
printk ( " Secondary IDE " ) ;
dmatype = 0 ;
if ( cddma = = - 1 ) cddma = 5 ;
break ;
case 0x0A :
printk ( " Primary IDE " ) ;
dmatype = 0 ;
if ( cddma = = - 1 ) cddma = 5 ;
break ;
default :
printk ( " \n " ) ;
printk ( KERN_ERR " Invalid CDROM type \n " ) ;
return - EINVAL ;
}
/*
* Build the config words
*/
mad16_conf = ( joystick ^ 1 ) | cdtype ;
mad16_cdsel = 0 ;
if ( opl4 )
mad16_cdsel | = 0x20 ;
if ( cdtype ) {
if ( cddma > 7 | | cddma < 0 | | dma_map [ dmatype ] [ cddma ] = = - 1 )
{
printk ( " \n " ) ;
printk ( KERN_ERR " Invalid CDROM DMA \n " ) ;
return - EINVAL ;
}
if ( cddma )
printk ( " , DMA %d " , cddma ) ;
else
printk ( " , no DMA " ) ;
if ( ! cdirq )
printk ( " , no IRQ " ) ;
else if ( cdirq < 0 | | cdirq > 15 | | irq_map [ cdirq ] = = - 1 )
{
printk ( " , invalid IRQ (disabling) " ) ;
cdirq = 0 ;
}
else printk ( " , IRQ %d " , cdirq ) ;
mad16_cdsel | = dma_map [ dmatype ] [ cddma ] ;
if ( cdtype < 0x08 )
{
switch ( cdport )
{
case 0x340 :
mad16_cdsel | = 0x00 ;
break ;
case 0x330 :
mad16_cdsel | = 0x40 ;
break ;
case 0x360 :
mad16_cdsel | = 0x80 ;
break ;
case 0x320 :
mad16_cdsel | = 0xC0 ;
break ;
default :
printk ( KERN_ERR " Unknown CDROM I/O base %d \n " , cdport ) ;
return - EINVAL ;
}
}
mad16_cdsel | = irq_map [ cdirq ] ;
}
printk ( " . \n " ) ;
cfg . io_base = io ;
cfg . irq = irq ;
cfg . dma = dma ;
cfg . dma2 = dma16 ;
if ( cfg . io_base = = - 1 | | cfg . dma = = - 1 | | cfg . irq = = - 1 ) {
printk ( KERN_ERR " I/O, DMA and irq are mandatory \n " ) ;
return - EINVAL ;
}
if ( ! request_region ( MC0_PORT , 12 , " mad16 " ) )
return - EBUSY ;
if ( ! probe_mad16 ( & cfg ) ) {
release_region ( MC0_PORT , 12 ) ;
return - ENODEV ;
}
cfg_mpu . io_base = mpu_io ;
cfg_mpu . irq = mpu_irq ;
found_mpu = probe_mad16_mpu ( & cfg_mpu ) ;
if ( joystick )
mad16_register_gameport ( 0x201 ) ;
return 0 ;
}
static void __exit cleanup_mad16 ( void )
{
if ( found_mpu )
unload_mad16_mpu ( & cfg_mpu ) ;
2005-06-01 11:38:46 +04:00
mad16_unregister_gameport ( ) ;
2005-04-17 02:20:36 +04:00
unload_mad16 ( & cfg ) ;
release_region ( MC0_PORT , 12 ) ;
}
module_init ( init_mad16 ) ;
module_exit ( cleanup_mad16 ) ;
# ifndef MODULE
static int __init setup_mad16 ( char * str )
{
/* io, irq */
int ints [ 8 ] ;
str = get_options ( str , ARRAY_SIZE ( ints ) , ints ) ;
io = ints [ 1 ] ;
irq = ints [ 2 ] ;
dma = ints [ 3 ] ;
dma16 = ints [ 4 ] ;
mpu_io = ints [ 5 ] ;
mpu_irq = ints [ 6 ] ;
joystick = ints [ 7 ] ;
return 1 ;
}
__setup ( " mad16= " , setup_mad16 ) ;
# endif
MODULE_LICENSE ( " GPL " ) ;