linux_dsm_epyc7002/sound/oss/sb_common.c

1292 lines
29 KiB
C
Raw Normal View History

/*
* sound/oss/sb_common.c
*
* Common routines for Sound Blaster compatible cards.
*
*
* Copyright (C) by Hannu Savolainen 1993-1997
*
* OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*
*
* Daniel J. Rodriksson: Modified sbintr to handle 8 and 16 bit interrupts
* for full duplex support ( only sb16 by now )
* Rolf Fokkens: Added (BETA?) support for ES1887 chips.
* (fokkensr@vertis.nl) Which means: You can adjust the recording levels.
*
* 2000/01/18 - separated sb_card and sb_common -
* Jeff Garzik <jgarzik@pobox.com>
*
* 2000/09/18 - got rid of attach_uart401
* Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
* 2001/01/26 - replaced CLI/STI with spinlocks
* Chris Rankin <rankinc@zipworld.com.au>
*/
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h percpu.h is included by sched.h and module.h and thus ends up being included when building most .c files. percpu.h includes slab.h which in turn includes gfp.h making everything defined by the two files universally available and complicating inclusion dependencies. percpu.h -> slab.h dependency is about to be removed. Prepare for this change by updating users of gfp and slab facilities include those headers directly instead of assuming availability. As this conversion needs to touch large number of source files, the following script is used as the basis of conversion. http://userweb.kernel.org/~tj/misc/slabh-sweep.py The script does the followings. * Scan files for gfp and slab usages and update includes such that only the necessary includes are there. ie. if only gfp is used, gfp.h, if slab is used, slab.h. * When the script inserts a new include, it looks at the include blocks and try to put the new include such that its order conforms to its surrounding. It's put in the include block which contains core kernel includes, in the same order that the rest are ordered - alphabetical, Christmas tree, rev-Xmas-tree or at the end if there doesn't seem to be any matching order. * If the script can't find a place to put a new include (mostly because the file doesn't have fitting include block), it prints out an error message indicating which .h file needs to be added to the file. The conversion was done in the following steps. 1. The initial automatic conversion of all .c files updated slightly over 4000 files, deleting around 700 includes and adding ~480 gfp.h and ~3000 slab.h inclusions. The script emitted errors for ~400 files. 2. Each error was manually checked. Some didn't need the inclusion, some needed manual addition while adding it to implementation .h or embedding .c file was more appropriate for others. This step added inclusions to around 150 files. 3. The script was run again and the output was compared to the edits from #2 to make sure no file was left behind. 4. Several build tests were done and a couple of problems were fixed. e.g. lib/decompress_*.c used malloc/free() wrappers around slab APIs requiring slab.h to be added manually. 5. The script was run on all .h files but without automatically editing them as sprinkling gfp.h and slab.h inclusions around .h files could easily lead to inclusion dependency hell. Most gfp.h inclusion directives were ignored as stuff from gfp.h was usually wildly available and often used in preprocessor macros. Each slab.h inclusion directive was examined and added manually as necessary. 6. percpu.h was updated not to include slab.h. 7. Build test were done on the following configurations and failures were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my distributed build env didn't work with gcov compiles) and a few more options had to be turned off depending on archs to make things build (like ipr on powerpc/64 which failed due to missing writeq). * x86 and x86_64 UP and SMP allmodconfig and a custom test config. * powerpc and powerpc64 SMP allmodconfig * sparc and sparc64 SMP allmodconfig * ia64 SMP allmodconfig * s390 SMP allmodconfig * alpha SMP allmodconfig * um on x86_64 SMP allmodconfig 8. percpu.h modifications were reverted so that it could be applied as a separate patch and serve as bisection point. Given the fact that I had only a couple of failures from tests on step 6, I'm fairly confident about the coverage of this conversion patch. If there is a breakage, it's likely to be something in one of the arch headers which should be easily discoverable easily on most builds of the specific arch. Signed-off-by: Tejun Heo <tj@kernel.org> Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org> Cc: Ingo Molnar <mingo@redhat.com> Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 15:04:11 +07:00
#include <linux/slab.h>
#include "sound_config.h"
#include "sound_firmware.h"
#include "mpu401.h"
#include "sb_mixer.h"
#include "sb.h"
#include "sb_ess.h"
/*
* global module flag
*/
int sb_be_quiet;
static sb_devc *detected_devc; /* For communication from probe to init */
static sb_devc *last_devc; /* For MPU401 initialization */
static unsigned char jazz_irq_bits[] = {
0, 0, 2, 3, 0, 1, 0, 4, 0, 2, 5, 0, 0, 0, 0, 6
};
static unsigned char jazz_dma_bits[] = {
0, 1, 0, 2, 0, 3, 0, 4
};
void *smw_free;
/*
* Jazz16 chipset specific control variables
*/
static int jazz16_base; /* Not detected */
static unsigned char jazz16_bits; /* I/O relocation bits */
static DEFINE_SPINLOCK(jazz16_lock);
/*
* Logitech Soundman Wave specific initialization code
*/
#ifdef SMW_MIDI0001_INCLUDED
#include "smw-midi0001.h"
#else
static unsigned char *smw_ucode;
static int smw_ucodeLen;
#endif
static sb_devc *last_sb; /* Last sb loaded */
int sb_dsp_command(sb_devc * devc, unsigned char val)
{
int i;
unsigned long limit;
limit = jiffies + HZ / 10; /* Timeout */
/*
* Note! the i<500000 is an emergency exit. The sb_dsp_command() is sometimes
* called while interrupts are disabled. This means that the timer is
* disabled also. However the timeout situation is a abnormal condition.
* Normally the DSP should be ready to accept commands after just couple of
* loops.
*/
for (i = 0; i < 500000 && (limit-jiffies)>0; i++)
{
if ((inb(DSP_STATUS) & 0x80) == 0)
{
outb((val), DSP_COMMAND);
return 1;
}
}
printk(KERN_WARNING "Sound Blaster: DSP command(%x) timeout.\n", val);
return 0;
}
int sb_dsp_get_byte(sb_devc * devc)
{
int i;
for (i = 1000; i; i--)
{
if (inb(DSP_DATA_AVAIL) & 0x80)
return inb(DSP_READ);
}
return 0xffff;
}
static void sb_intr (sb_devc *devc)
{
int status;
unsigned char src = 0xff;
if (devc->model == MDL_SB16)
{
src = sb_getmixer(devc, IRQ_STAT); /* Interrupt source register */
if (src & 4) /* MPU401 interrupt */
if(devc->midi_irq_cookie)
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers Maintain a per-CPU global "struct pt_regs *" variable which can be used instead of passing regs around manually through all ~1800 interrupt handlers in the Linux kernel. The regs pointer is used in few places, but it potentially costs both stack space and code to pass it around. On the FRV arch, removing the regs parameter from all the genirq function results in a 20% speed up of the IRQ exit path (ie: from leaving timer_interrupt() to leaving do_IRQ()). Where appropriate, an arch may override the generic storage facility and do something different with the variable. On FRV, for instance, the address is maintained in GR28 at all times inside the kernel as part of general exception handling. Having looked over the code, it appears that the parameter may be handed down through up to twenty or so layers of functions. Consider a USB character device attached to a USB hub, attached to a USB controller that posts its interrupts through a cascaded auxiliary interrupt controller. A character device driver may want to pass regs to the sysrq handler through the input layer which adds another few layers of parameter passing. I've build this code with allyesconfig for x86_64 and i386. I've runtested the main part of the code on FRV and i386, though I can't test most of the drivers. I've also done partial conversion for powerpc and MIPS - these at least compile with minimal configurations. This will affect all archs. Mostly the changes should be relatively easy. Take do_IRQ(), store the regs pointer at the beginning, saving the old one: struct pt_regs *old_regs = set_irq_regs(regs); And put the old one back at the end: set_irq_regs(old_regs); Don't pass regs through to generic_handle_irq() or __do_IRQ(). In timer_interrupt(), this sort of change will be necessary: - update_process_times(user_mode(regs)); - profile_tick(CPU_PROFILING, regs); + update_process_times(user_mode(get_irq_regs())); + profile_tick(CPU_PROFILING); I'd like to move update_process_times()'s use of get_irq_regs() into itself, except that i386, alone of the archs, uses something other than user_mode(). Some notes on the interrupt handling in the drivers: (*) input_dev() is now gone entirely. The regs pointer is no longer stored in the input_dev struct. (*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does something different depending on whether it's been supplied with a regs pointer or not. (*) Various IRQ handler function pointers have been moved to type irq_handler_t. Signed-Off-By: David Howells <dhowells@redhat.com> (cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
2006-10-05 20:55:46 +07:00
uart401intr(devc->irq, devc->midi_irq_cookie);
if (!(src & 3))
return; /* Not a DSP interrupt */
}
if (devc->intr_active && (!devc->fullduplex || (src & 0x01)))
{
switch (devc->irq_mode)
{
case IMODE_OUTPUT:
DMAbuf_outputintr(devc->dev, 1);
break;
case IMODE_INPUT:
DMAbuf_inputintr(devc->dev);
break;
case IMODE_INIT:
break;
case IMODE_MIDI:
sb_midi_interrupt(devc);
break;
default:
/* printk(KERN_WARNING "Sound Blaster: Unexpected interrupt\n"); */
;
}
}
else if (devc->intr_active_16 && (src & 0x02))
{
switch (devc->irq_mode_16)
{
case IMODE_OUTPUT:
DMAbuf_outputintr(devc->dev, 1);
break;
case IMODE_INPUT:
DMAbuf_inputintr(devc->dev);
break;
case IMODE_INIT:
break;
default:
/* printk(KERN_WARNING "Sound Blaster: Unexpected interrupt\n"); */
;
}
}
/*
* Acknowledge interrupts
*/
if (src & 0x01)
status = inb(DSP_DATA_AVAIL);
if (devc->model == MDL_SB16 && src & 0x02)
status = inb(DSP_DATA_AVL16);
}
static void pci_intr(sb_devc *devc)
{
int src = inb(devc->pcibase+0x1A);
src&=3;
if(src)
sb_intr(devc);
}
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers Maintain a per-CPU global "struct pt_regs *" variable which can be used instead of passing regs around manually through all ~1800 interrupt handlers in the Linux kernel. The regs pointer is used in few places, but it potentially costs both stack space and code to pass it around. On the FRV arch, removing the regs parameter from all the genirq function results in a 20% speed up of the IRQ exit path (ie: from leaving timer_interrupt() to leaving do_IRQ()). Where appropriate, an arch may override the generic storage facility and do something different with the variable. On FRV, for instance, the address is maintained in GR28 at all times inside the kernel as part of general exception handling. Having looked over the code, it appears that the parameter may be handed down through up to twenty or so layers of functions. Consider a USB character device attached to a USB hub, attached to a USB controller that posts its interrupts through a cascaded auxiliary interrupt controller. A character device driver may want to pass regs to the sysrq handler through the input layer which adds another few layers of parameter passing. I've build this code with allyesconfig for x86_64 and i386. I've runtested the main part of the code on FRV and i386, though I can't test most of the drivers. I've also done partial conversion for powerpc and MIPS - these at least compile with minimal configurations. This will affect all archs. Mostly the changes should be relatively easy. Take do_IRQ(), store the regs pointer at the beginning, saving the old one: struct pt_regs *old_regs = set_irq_regs(regs); And put the old one back at the end: set_irq_regs(old_regs); Don't pass regs through to generic_handle_irq() or __do_IRQ(). In timer_interrupt(), this sort of change will be necessary: - update_process_times(user_mode(regs)); - profile_tick(CPU_PROFILING, regs); + update_process_times(user_mode(get_irq_regs())); + profile_tick(CPU_PROFILING); I'd like to move update_process_times()'s use of get_irq_regs() into itself, except that i386, alone of the archs, uses something other than user_mode(). Some notes on the interrupt handling in the drivers: (*) input_dev() is now gone entirely. The regs pointer is no longer stored in the input_dev struct. (*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does something different depending on whether it's been supplied with a regs pointer or not. (*) Various IRQ handler function pointers have been moved to type irq_handler_t. Signed-Off-By: David Howells <dhowells@redhat.com> (cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
2006-10-05 20:55:46 +07:00
static irqreturn_t sbintr(int irq, void *dev_id)
{
sb_devc *devc = dev_id;
devc->irq_ok = 1;
switch (devc->model) {
case MDL_ESSPCI:
pci_intr (devc);
break;
case MDL_ESS:
ess_intr (devc);
break;
default:
sb_intr (devc);
break;
}
return IRQ_HANDLED;
}
int sb_dsp_reset(sb_devc * devc)
{
int loopc;
DEB(printk("Entered sb_dsp_reset()\n"));
if (devc->model == MDL_ESS) return ess_dsp_reset (devc);
/* This is only for non-ESS chips */
outb(1, DSP_RESET);
udelay(10);
outb(0, DSP_RESET);
udelay(30);
for (loopc = 0; loopc < 1000 && !(inb(DSP_DATA_AVAIL) & 0x80); loopc++);
if (inb(DSP_READ) != 0xAA)
{
DDB(printk("sb: No response to RESET\n"));
return 0; /* Sorry */
}
DEB(printk("sb_dsp_reset() OK\n"));
return 1;
}
static void dsp_get_vers(sb_devc * devc)
{
int i;
unsigned long flags;
DDB(printk("Entered dsp_get_vers()\n"));
spin_lock_irqsave(&devc->lock, flags);
devc->major = devc->minor = 0;
sb_dsp_command(devc, 0xe1); /* Get version */
for (i = 100000; i; i--)
{
if (inb(DSP_DATA_AVAIL) & 0x80)
{
if (devc->major == 0)
devc->major = inb(DSP_READ);
else
{
devc->minor = inb(DSP_READ);
break;
}
}
}
spin_unlock_irqrestore(&devc->lock, flags);
DDB(printk("DSP version %d.%02d\n", devc->major, devc->minor));
}
static int sb16_set_dma_hw(sb_devc * devc)
{
int bits;
if (devc->dma8 != 0 && devc->dma8 != 1 && devc->dma8 != 3)
{
printk(KERN_ERR "SB16: Invalid 8 bit DMA (%d)\n", devc->dma8);
return 0;
}
bits = (1 << devc->dma8);
if (devc->dma16 >= 5 && devc->dma16 <= 7)
bits |= (1 << devc->dma16);
sb_setmixer(devc, DMA_NR, bits);
return 1;
}
static void sb16_set_mpu_port(sb_devc * devc, struct address_info *hw_config)
{
/*
* This routine initializes new MIDI port setup register of SB Vibra (CT2502).
*/
unsigned char bits = sb_getmixer(devc, 0x84) & ~0x06;
switch (hw_config->io_base)
{
case 0x300:
sb_setmixer(devc, 0x84, bits | 0x04);
break;
case 0x330:
sb_setmixer(devc, 0x84, bits | 0x00);
break;
default:
sb_setmixer(devc, 0x84, bits | 0x02); /* Disable MPU */
printk(KERN_ERR "SB16: Invalid MIDI I/O port %x\n", hw_config->io_base);
}
}
static int sb16_set_irq_hw(sb_devc * devc, int level)
{
int ival;
switch (level)
{
case 5:
ival = 2;
break;
case 7:
ival = 4;
break;
case 9:
ival = 1;
break;
case 10:
ival = 8;
break;
default:
printk(KERN_ERR "SB16: Invalid IRQ%d\n", level);
return 0;
}
sb_setmixer(devc, IRQ_NR, ival);
return 1;
}
static void relocate_Jazz16(sb_devc * devc, struct address_info *hw_config)
{
unsigned char bits = 0;
unsigned long flags;
if (jazz16_base != 0 && jazz16_base != hw_config->io_base)
return;
switch (hw_config->io_base)
{
case 0x220:
bits = 1;
break;
case 0x240:
bits = 2;
break;
case 0x260:
bits = 3;
break;
default:
return;
}
bits = jazz16_bits = bits << 5;
jazz16_base = hw_config->io_base;
/*
* Magic wake up sequence by writing to 0x201 (aka Joystick port)
*/
spin_lock_irqsave(&jazz16_lock, flags);
outb((0xAF), 0x201);
outb((0x50), 0x201);
outb((bits), 0x201);
spin_unlock_irqrestore(&jazz16_lock, flags);
}
static int init_Jazz16(sb_devc * devc, struct address_info *hw_config)
{
char name[100];
/*
* First try to check that the card has Jazz16 chip. It identifies itself
* by returning 0x12 as response to DSP command 0xfa.
*/
if (!sb_dsp_command(devc, 0xfa))
return 0;
if (sb_dsp_get_byte(devc) != 0x12)
return 0;
/*
* OK so far. Now configure the IRQ and DMA channel used by the card.
*/
if (hw_config->irq < 1 || hw_config->irq > 15 || jazz_irq_bits[hw_config->irq] == 0)
{
printk(KERN_ERR "Jazz16: Invalid interrupt (IRQ%d)\n", hw_config->irq);
return 0;
}
if (hw_config->dma < 0 || hw_config->dma > 3 || jazz_dma_bits[hw_config->dma] == 0)
{
printk(KERN_ERR "Jazz16: Invalid 8 bit DMA (DMA%d)\n", hw_config->dma);
return 0;
}
if (hw_config->dma2 < 0)
{
printk(KERN_ERR "Jazz16: No 16 bit DMA channel defined\n");
return 0;
}
if (hw_config->dma2 < 5 || hw_config->dma2 > 7 || jazz_dma_bits[hw_config->dma2] == 0)
{
printk(KERN_ERR "Jazz16: Invalid 16 bit DMA (DMA%d)\n", hw_config->dma2);
return 0;
}
devc->dma16 = hw_config->dma2;
if (!sb_dsp_command(devc, 0xfb))
return 0;
if (!sb_dsp_command(devc, jazz_dma_bits[hw_config->dma] |
(jazz_dma_bits[hw_config->dma2] << 4)))
return 0;
if (!sb_dsp_command(devc, jazz_irq_bits[hw_config->irq]))
return 0;
/*
* Now we have configured a standard Jazz16 device.
*/
devc->model = MDL_JAZZ;
strcpy(name, "Jazz16");
hw_config->name = "Jazz16";
devc->caps |= SB_NO_MIDI;
return 1;
}
static void relocate_ess1688(sb_devc * devc)
{
unsigned char bits;
switch (devc->base)
{
case 0x220:
bits = 0x04;
break;
case 0x230:
bits = 0x05;
break;
case 0x240:
bits = 0x06;
break;
case 0x250:
bits = 0x07;
break;
default:
return; /* Wrong port */
}
DDB(printk("Doing ESS1688 address selection\n"));
/*
* ES1688 supports two alternative ways for software address config.
* First try the so called Read-Sequence-Key method.
*/
/* Reset the sequence logic */
inb(0x229);
inb(0x229);
inb(0x229);
/* Perform the read sequence */
inb(0x22b);
inb(0x229);
inb(0x22b);
inb(0x229);
inb(0x229);
inb(0x22b);
inb(0x229);
/* Select the base address by reading from it. Then probe using the port. */
inb(devc->base);
if (sb_dsp_reset(devc)) /* Bingo */
return;
#if 0 /* This causes system lockups (Nokia 386/25 at least) */
/*
* The last resort is the system control register method.
*/
outb((0x00), 0xfb); /* 0xFB is the unlock register */
outb((0x00), 0xe0); /* Select index 0 */
outb((bits), 0xe1); /* Write the config bits */
outb((0x00), 0xf9); /* 0xFB is the lock register */
#endif
}
int sb_dsp_detect(struct address_info *hw_config, int pci, int pciio, struct sb_module_options *sbmo)
{
sb_devc sb_info;
sb_devc *devc = &sb_info;
memset((char *) &sb_info, 0, sizeof(sb_info)); /* Zero everything */
/* Copy module options in place */
if(sbmo) memcpy(&devc->sbmo, sbmo, sizeof(struct sb_module_options));
sb_info.my_mididev = -1;
sb_info.my_mixerdev = -1;
sb_info.dev = -1;
/*
* Initialize variables
*/
DDB(printk("sb_dsp_detect(%x) entered\n", hw_config->io_base));
spin_lock_init(&devc->lock);
devc->type = hw_config->card_subtype;
devc->base = hw_config->io_base;
devc->irq = hw_config->irq;
devc->dma8 = hw_config->dma;
devc->dma16 = -1;
devc->pcibase = pciio;
if(pci == SB_PCI_ESSMAESTRO)
{
devc->model = MDL_ESSPCI;
devc->caps |= SB_PCI_IRQ;
hw_config->driver_use_1 |= SB_PCI_IRQ;
hw_config->card_subtype = MDL_ESSPCI;
}
if(pci == SB_PCI_YAMAHA)
{
devc->model = MDL_YMPCI;
devc->caps |= SB_PCI_IRQ;
hw_config->driver_use_1 |= SB_PCI_IRQ;
hw_config->card_subtype = MDL_YMPCI;
printk("Yamaha PCI mode.\n");
}
if (devc->sbmo.acer)
{
unsigned long flags;
spin_lock_irqsave(&devc->lock, flags);
inb(devc->base + 0x09);
inb(devc->base + 0x09);
inb(devc->base + 0x09);
inb(devc->base + 0x0b);
inb(devc->base + 0x09);
inb(devc->base + 0x0b);
inb(devc->base + 0x09);
inb(devc->base + 0x09);
inb(devc->base + 0x0b);
inb(devc->base + 0x09);
inb(devc->base + 0x00);
spin_unlock_irqrestore(&devc->lock, flags);
}
/*
* Detect the device
*/
if (sb_dsp_reset(devc))
dsp_get_vers(devc);
else
devc->major = 0;
if (devc->type == 0 || devc->type == MDL_JAZZ || devc->type == MDL_SMW)
if (devc->major == 0 || (devc->major == 3 && devc->minor == 1))
relocate_Jazz16(devc, hw_config);
if (devc->major == 0 && (devc->type == MDL_ESS || devc->type == 0))
relocate_ess1688(devc);
if (!sb_dsp_reset(devc))
{
DDB(printk("SB reset failed\n"));
#ifdef MODULE
printk(KERN_INFO "sb: dsp reset failed.\n");
#endif
return 0;
}
if (devc->major == 0)
dsp_get_vers(devc);
if (devc->major == 3 && devc->minor == 1)
{
if (devc->type == MDL_AZTECH) /* SG Washington? */
{
if (sb_dsp_command(devc, 0x09))
if (sb_dsp_command(devc, 0x00)) /* Enter WSS mode */
{
int i;
/* Have some delay */
for (i = 0; i < 10000; i++)
inb(DSP_DATA_AVAIL);
devc->caps = SB_NO_AUDIO | SB_NO_MIDI; /* Mixer only */
devc->model = MDL_AZTECH;
}
}
}
if(devc->type == MDL_ESSPCI)
devc->model = MDL_ESSPCI;
if(devc->type == MDL_YMPCI)
{
printk("YMPCI selected\n");
devc->model = MDL_YMPCI;
}
/*
* Save device information for sb_dsp_init()
*/
detected_devc = kmemdup(devc, sizeof(sb_devc), GFP_KERNEL);
if (detected_devc == NULL)
{
printk(KERN_ERR "sb: Can't allocate memory for device information\n");
return 0;
}
MDB(printk(KERN_INFO "SB %d.%02d detected OK (%x)\n", devc->major, devc->minor, hw_config->io_base));
return 1;
}
int sb_dsp_init(struct address_info *hw_config, struct module *owner)
{
sb_devc *devc;
char name[100];
extern int sb_be_quiet;
int mixer22, mixer30;
/*
* Check if we had detected a SB device earlier
*/
DDB(printk("sb_dsp_init(%x) entered\n", hw_config->io_base));
name[0] = 0;
if (detected_devc == NULL)
{
MDB(printk("No detected device\n"));
return 0;
}
devc = detected_devc;
detected_devc = NULL;
if (devc->base != hw_config->io_base)
{
DDB(printk("I/O port mismatch\n"));
release_region(devc->base, 16);
return 0;
}
/*
* Now continue initialization of the device
*/
devc->caps = hw_config->driver_use_1;
if (!((devc->caps & SB_NO_AUDIO) && (devc->caps & SB_NO_MIDI)) && hw_config->irq > 0)
{ /* IRQ setup */
/*
* ESS PCI cards do shared PCI IRQ stuff. Since they
* will get shared PCI irq lines we must cope.
*/
int i=(devc->caps&SB_PCI_IRQ)?IRQF_SHARED:0;
if (request_irq(hw_config->irq, sbintr, i, "soundblaster", devc) < 0)
{
printk(KERN_ERR "SB: Can't allocate IRQ%d\n", hw_config->irq);
release_region(devc->base, 16);
return 0;
}
devc->irq_ok = 0;
if (devc->major == 4)
if (!sb16_set_irq_hw(devc, devc->irq)) /* Unsupported IRQ */
{
free_irq(devc->irq, devc);
release_region(devc->base, 16);
return 0;
}
if ((devc->type == 0 || devc->type == MDL_ESS) &&
devc->major == 3 && devc->minor == 1)
{ /* Handle various chipsets which claim they are SB Pro compatible */
if ((devc->type != 0 && devc->type != MDL_ESS) ||
!ess_init(devc, hw_config))
{
if ((devc->type != 0 && devc->type != MDL_JAZZ &&
devc->type != MDL_SMW) || !init_Jazz16(devc, hw_config))
{
DDB(printk("This is a genuine SB Pro\n"));
}
}
}
if (devc->major == 4 && devc->minor <= 11 ) /* Won't work */
devc->irq_ok = 1;
else
{
int n;
for (n = 0; n < 3 && devc->irq_ok == 0; n++)
{
if (sb_dsp_command(devc, 0xf2)) /* Cause interrupt immediately */
{
int i;
for (i = 0; !devc->irq_ok && i < 10000; i++);
}
}
if (!devc->irq_ok)
printk(KERN_WARNING "sb: Interrupt test on IRQ%d failed - Probable IRQ conflict\n", devc->irq);
else
{
DDB(printk("IRQ test OK (IRQ%d)\n", devc->irq));
}
}
} /* IRQ setup */
last_sb = devc;
switch (devc->major)
{
case 1: /* SB 1.0 or 1.5 */
devc->model = hw_config->card_subtype = MDL_SB1;
break;
case 2: /* SB 2.x */
if (devc->minor == 0)
devc->model = hw_config->card_subtype = MDL_SB2;
else
devc->model = hw_config->card_subtype = MDL_SB201;
break;
case 3: /* SB Pro and most clones */
switch (devc->model) {
case 0:
devc->model = hw_config->card_subtype = MDL_SBPRO;
if (hw_config->name == NULL)
hw_config->name = "Sound Blaster Pro (8 BIT ONLY)";
break;
case MDL_ESS:
ess_dsp_init(devc, hw_config);
break;
}
break;
case 4:
devc->model = hw_config->card_subtype = MDL_SB16;
/*
* ALS007 and ALS100 return DSP version 4.2 and have 2 post-reset !=0
* registers at 0x3c and 0x4c (output ctrl registers on ALS007) whereas
* a "standard" SB16 doesn't have a register at 0x4c. ALS100 actively
* updates register 0x22 whenever 0x30 changes, as per the SB16 spec.
* Since ALS007 doesn't, this can be used to differentiate the 2 cards.
*/
if ((devc->minor == 2) && sb_getmixer(devc,0x3c) && sb_getmixer(devc,0x4c))
{
mixer30 = sb_getmixer(devc,0x30);
sb_setmixer(devc,0x22,(mixer22=sb_getmixer(devc,0x22)) & 0x0f);
sb_setmixer(devc,0x30,0xff);
/* ALS100 will force 0x30 to 0xf8 like SB16; ALS007 will allow 0xff. */
/* Register 0x22 & 0xf0 on ALS100 == 0xf0; on ALS007 it == 0x10. */
if ((sb_getmixer(devc,0x30) != 0xff) || ((sb_getmixer(devc,0x22) & 0xf0) != 0x10))
{
devc->submodel = SUBMDL_ALS100;
if (hw_config->name == NULL)
hw_config->name = "Sound Blaster 16 (ALS-100)";
}
else
{
sb_setmixer(devc,0x3c,0x1f); /* Enable all inputs */
sb_setmixer(devc,0x4c,0x1f);
sb_setmixer(devc,0x22,mixer22); /* Restore 0x22 to original value */
devc->submodel = SUBMDL_ALS007;
if (hw_config->name == NULL)
hw_config->name = "Sound Blaster 16 (ALS-007)";
}
sb_setmixer(devc,0x30,mixer30);
}
else if (hw_config->name == NULL)
hw_config->name = "Sound Blaster 16";
if (hw_config->dma2 == -1)
devc->dma16 = devc->dma8;
else if (hw_config->dma2 < 5 || hw_config->dma2 > 7)
{
printk(KERN_WARNING "SB16: Bad or missing 16 bit DMA channel\n");
devc->dma16 = devc->dma8;
}
else
devc->dma16 = hw_config->dma2;
if(!sb16_set_dma_hw(devc)) {
free_irq(devc->irq, devc);
release_region(hw_config->io_base, 16);
return 0;
}
devc->caps |= SB_NO_MIDI;
}
if (!(devc->caps & SB_NO_MIXER))
if (devc->major == 3 || devc->major == 4)
sb_mixer_init(devc, owner);
if (!(devc->caps & SB_NO_MIDI))
sb_dsp_midi_init(devc, owner);
if (hw_config->name == NULL)
hw_config->name = "Sound Blaster (8 BIT/MONO ONLY)";
sprintf(name, "%s (%d.%02d)", hw_config->name, devc->major, devc->minor);
conf_printf(name, hw_config);
/*
* Assuming that a sound card is Sound Blaster (compatible) is the most common
* configuration error and the mother of all problems. Usually sound cards
* emulate SB Pro but in addition they have a 16 bit native mode which should be
* used in Unix. See Readme.cards for more information about configuring OSS/Free
* properly.
*/
if (devc->model <= MDL_SBPRO)
{
if (devc->major == 3 && devc->minor != 1) /* "True" SB Pro should have v3.1 (rare ones may have 3.2). */
{
printk(KERN_INFO "This sound card may not be fully Sound Blaster Pro compatible.\n");
printk(KERN_INFO "In many cases there is another way to configure OSS so that\n");
printk(KERN_INFO "it works properly with OSS (for example in 16 bit mode).\n");
printk(KERN_INFO "Please ignore this message if you _really_ have a SB Pro.\n");
}
else if (!sb_be_quiet && devc->model == MDL_SBPRO)
{
printk(KERN_INFO "SB DSP version is just %d.%02d which means that your card is\n", devc->major, devc->minor);
printk(KERN_INFO "several years old (8 bit only device) or alternatively the sound driver\n");
printk(KERN_INFO "is incorrectly configured.\n");
}
}
hw_config->card_subtype = devc->model;
hw_config->slots[0]=devc->dev;
last_devc = devc; /* For SB MPU detection */
if (!(devc->caps & SB_NO_AUDIO) && devc->dma8 >= 0)
{
if (sound_alloc_dma(devc->dma8, "SoundBlaster8"))
{
printk(KERN_WARNING "Sound Blaster: Can't allocate 8 bit DMA channel %d\n", devc->dma8);
}
if (devc->dma16 >= 0 && devc->dma16 != devc->dma8)
{
if (sound_alloc_dma(devc->dma16, "SoundBlaster16"))
printk(KERN_WARNING "Sound Blaster: can't allocate 16 bit DMA channel %d.\n", devc->dma16);
}
sb_audio_init(devc, name, owner);
hw_config->slots[0]=devc->dev;
}
else
{
MDB(printk("Sound Blaster: no audio devices found.\n"));
}
return 1;
}
/* if (sbmpu) below we allow mpu401 to manage the midi devs
otherwise we have to unload them. (Andrzej Krzysztofowicz) */
void sb_dsp_unload(struct address_info *hw_config, int sbmpu)
{
sb_devc *devc;
devc = audio_devs[hw_config->slots[0]]->devc;
if (devc && devc->base == hw_config->io_base)
{
if ((devc->model & MDL_ESS) && devc->pcibase)
release_region(devc->pcibase, 8);
release_region(devc->base, 16);
if (!(devc->caps & SB_NO_AUDIO))
{
sound_free_dma(devc->dma8);
if (devc->dma16 >= 0)
sound_free_dma(devc->dma16);
}
if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI))
{
if (devc->irq > 0)
free_irq(devc->irq, devc);
sb_mixer_unload(devc);
/* We don't have to do this bit any more the UART401 is its own
master -- Krzysztof Halasa */
/* But we have to do it, if UART401 is not detected */
if (!sbmpu)
sound_unload_mididev(devc->my_mididev);
sound_unload_audiodev(devc->dev);
}
kfree(devc);
}
else
release_region(hw_config->io_base, 16);
kfree(detected_devc);
}
/*
* Mixer access routines
*
* ES1887 modifications: some mixer registers reside in the
* range above 0xa0. These must be accessed in another way.
*/
void sb_setmixer(sb_devc * devc, unsigned int port, unsigned int value)
{
unsigned long flags;
if (devc->model == MDL_ESS) {
ess_setmixer (devc, port, value);
return;
}
spin_lock_irqsave(&devc->lock, flags);
outb(((unsigned char) (port & 0xff)), MIXER_ADDR);
udelay(20);
outb(((unsigned char) (value & 0xff)), MIXER_DATA);
udelay(20);
spin_unlock_irqrestore(&devc->lock, flags);
}
unsigned int sb_getmixer(sb_devc * devc, unsigned int port)
{
unsigned int val;
unsigned long flags;
if (devc->model == MDL_ESS) return ess_getmixer (devc, port);
spin_lock_irqsave(&devc->lock, flags);
outb(((unsigned char) (port & 0xff)), MIXER_ADDR);
udelay(20);
val = inb(MIXER_DATA);
udelay(20);
spin_unlock_irqrestore(&devc->lock, flags);
return val;
}
void sb_chgmixer
(sb_devc * devc, unsigned int reg, unsigned int mask, unsigned int val)
{
int value;
value = sb_getmixer(devc, reg);
value = (value & ~mask) | (val & mask);
sb_setmixer(devc, reg, value);
}
/*
* MPU401 MIDI initialization.
*/
static void smw_putmem(sb_devc * devc, int base, int addr, unsigned char val)
{
unsigned long flags;
spin_lock_irqsave(&jazz16_lock, flags); /* NOT the SB card? */
outb((addr & 0xff), base + 1); /* Low address bits */
outb((addr >> 8), base + 2); /* High address bits */
outb((val), base); /* Data */
spin_unlock_irqrestore(&jazz16_lock, flags);
}
static unsigned char smw_getmem(sb_devc * devc, int base, int addr)
{
unsigned long flags;
unsigned char val;
spin_lock_irqsave(&jazz16_lock, flags); /* NOT the SB card? */
outb((addr & 0xff), base + 1); /* Low address bits */
outb((addr >> 8), base + 2); /* High address bits */
val = inb(base); /* Data */
spin_unlock_irqrestore(&jazz16_lock, flags);
return val;
}
static int smw_midi_init(sb_devc * devc, struct address_info *hw_config)
{
int mpu_base = hw_config->io_base;
int mp_base = mpu_base + 4; /* Microcontroller base */
int i;
unsigned char control;
/*
* Reset the microcontroller so that the RAM can be accessed
*/
control = inb(mpu_base + 7);
outb((control | 3), mpu_base + 7); /* Set last two bits to 1 (?) */
outb(((control & 0xfe) | 2), mpu_base + 7); /* xxxxxxx0 resets the mc */
mdelay(3); /* Wait at least 1ms */
outb((control & 0xfc), mpu_base + 7); /* xxxxxx00 enables RAM */
/*
* Detect microcontroller by probing the 8k RAM area
*/
smw_putmem(devc, mp_base, 0, 0x00);
smw_putmem(devc, mp_base, 1, 0xff);
udelay(10);
if (smw_getmem(devc, mp_base, 0) != 0x00 || smw_getmem(devc, mp_base, 1) != 0xff)
{
DDB(printk("SM Wave: No microcontroller RAM detected (%02x, %02x)\n", smw_getmem(devc, mp_base, 0), smw_getmem(devc, mp_base, 1)));
return 0; /* No RAM */
}
/*
* There is RAM so assume it's really a SM Wave
*/
devc->model = MDL_SMW;
smw_mixer_init(devc);
#ifdef MODULE
if (!smw_ucode)
{
smw_ucodeLen = mod_firmware_load("/etc/sound/midi0001.bin", (void *) &smw_ucode);
smw_free = smw_ucode;
}
#endif
if (smw_ucodeLen > 0)
{
if (smw_ucodeLen != 8192)
{
printk(KERN_ERR "SM Wave: Invalid microcode (MIDI0001.BIN) length\n");
return 1;
}
/*
* Download microcode
*/
for (i = 0; i < 8192; i++)
smw_putmem(devc, mp_base, i, smw_ucode[i]);
/*
* Verify microcode
*/
for (i = 0; i < 8192; i++)
if (smw_getmem(devc, mp_base, i) != smw_ucode[i])
{
printk(KERN_ERR "SM Wave: Microcode verification failed\n");
return 0;
}
}
control = 0;
#ifdef SMW_SCSI_IRQ
/*
* Set the SCSI interrupt (IRQ2/9, IRQ3 or IRQ10). The SCSI interrupt
* is disabled by default.
*
* FIXME - make this a module option
*
* BTW the Zilog 5380 SCSI controller is located at MPU base + 0x10.
*/
{
static unsigned char scsi_irq_bits[] = {
0, 0, 3, 1, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0
};
control |= scsi_irq_bits[SMW_SCSI_IRQ] << 6;
}
#endif
#ifdef SMW_OPL4_ENABLE
/*
* Make the OPL4 chip visible on the PC bus at 0x380.
*
* There is no need to enable this feature since this driver
* doesn't support OPL4 yet. Also there is no RAM in SM Wave so
* enabling OPL4 is pretty useless.
*/
control |= 0x10; /* Uses IRQ12 if bit 0x20 == 0 */
/* control |= 0x20; Uncomment this if you want to use IRQ7 */
#endif
outb((control | 0x03), mpu_base + 7); /* xxxxxx11 restarts */
hw_config->name = "SoundMan Wave";
return 1;
}
static int init_Jazz16_midi(sb_devc * devc, struct address_info *hw_config)
{
int mpu_base = hw_config->io_base;
int sb_base = devc->base;
int irq = hw_config->irq;
unsigned char bits = 0;
unsigned long flags;
if (irq < 0)
irq *= -1;
if (irq < 1 || irq > 15 ||
jazz_irq_bits[irq] == 0)
{
printk(KERN_ERR "Jazz16: Invalid MIDI interrupt (IRQ%d)\n", irq);
return 0;
}
switch (sb_base)
{
case 0x220:
bits = 1;
break;
case 0x240:
bits = 2;
break;
case 0x260:
bits = 3;
break;
default:
return 0;
}
bits = jazz16_bits = bits << 5;
switch (mpu_base)
{
case 0x310:
bits |= 1;
break;
case 0x320:
bits |= 2;
break;
case 0x330:
bits |= 3;
break;
default:
printk(KERN_ERR "Jazz16: Invalid MIDI I/O port %x\n", mpu_base);
return 0;
}
/*
* Magic wake up sequence by writing to 0x201 (aka Joystick port)
*/
spin_lock_irqsave(&jazz16_lock, flags);
outb(0xAF, 0x201);
outb(0x50, 0x201);
outb(bits, 0x201);
spin_unlock_irqrestore(&jazz16_lock, flags);
hw_config->name = "Jazz16";
smw_midi_init(devc, hw_config);
if (!sb_dsp_command(devc, 0xfb))
return 0;
if (!sb_dsp_command(devc, jazz_dma_bits[devc->dma8] |
(jazz_dma_bits[devc->dma16] << 4)))
return 0;
if (!sb_dsp_command(devc, jazz_irq_bits[devc->irq] |
(jazz_irq_bits[irq] << 4)))
return 0;
return 1;
}
int probe_sbmpu(struct address_info *hw_config, struct module *owner)
{
sb_devc *devc = last_devc;
int ret;
if (last_devc == NULL)
return 0;
last_devc = NULL;
if (hw_config->io_base <= 0)
{
/* The real vibra16 is fine about this, but we have to go
wipe up after Cyrix again */
if(devc->model == MDL_SB16 && devc->minor >= 12)
{
unsigned char bits = sb_getmixer(devc, 0x84) & ~0x06;
sb_setmixer(devc, 0x84, bits | 0x02); /* Disable MPU */
}
return 0;
}
#if defined(CONFIG_SOUND_MPU401)
if (devc->model == MDL_ESS)
{
struct resource *ports;
ports = request_region(hw_config->io_base, 2, "mpu401");
if (!ports) {
printk(KERN_ERR "sbmpu: I/O port conflict (%x)\n", hw_config->io_base);
return 0;
}
if (!ess_midi_init(devc, hw_config)) {
release_region(hw_config->io_base, 2);
return 0;
}
hw_config->name = "ESS1xxx MPU";
devc->midi_irq_cookie = NULL;
if (!probe_mpu401(hw_config, ports)) {
release_region(hw_config->io_base, 2);
return 0;
}
attach_mpu401(hw_config, owner);
if (last_sb->irq == -hw_config->irq)
last_sb->midi_irq_cookie =
(void *)(long) hw_config->slots[1];
return 1;
}
#endif
switch (devc->model)
{
case MDL_SB16:
if (hw_config->io_base != 0x300 && hw_config->io_base != 0x330)
{
printk(KERN_ERR "SB16: Invalid MIDI port %x\n", hw_config->io_base);
return 0;
}
hw_config->name = "Sound Blaster 16";
if (hw_config->irq < 3 || hw_config->irq == devc->irq)
hw_config->irq = -devc->irq;
if (devc->minor > 12) /* What is Vibra's version??? */
sb16_set_mpu_port(devc, hw_config);
break;
case MDL_JAZZ:
if (hw_config->irq < 3 || hw_config->irq == devc->irq)
hw_config->irq = -devc->irq;
if (!init_Jazz16_midi(devc, hw_config))
return 0;
break;
case MDL_YMPCI:
hw_config->name = "Yamaha PCI Legacy";
printk("Yamaha PCI legacy UART401 check.\n");
break;
default:
return 0;
}
ret = probe_uart401(hw_config, owner);
if (ret)
last_sb->midi_irq_cookie=midi_devs[hw_config->slots[4]]->devc;
return ret;
}
void unload_sbmpu(struct address_info *hw_config)
{
#if defined(CONFIG_SOUND_MPU401)
if (!strcmp (hw_config->name, "ESS1xxx MPU")) {
unload_mpu401(hw_config);
return;
}
#endif
unload_uart401(hw_config);
}
EXPORT_SYMBOL(sb_dsp_init);
EXPORT_SYMBOL(sb_dsp_detect);
EXPORT_SYMBOL(sb_dsp_unload);
EXPORT_SYMBOL(sb_be_quiet);
EXPORT_SYMBOL(probe_sbmpu);
EXPORT_SYMBOL(unload_sbmpu);
EXPORT_SYMBOL(smw_free);
MODULE_LICENSE("GPL");