patch-1.3.9 linux/drivers/sound/sb_dsp.c
Next file: linux/drivers/sound/sb_midi.c
Previous file: linux/drivers/sound/sb_card.c
Back to the patch index
Back to the overall index
- Lines: 727
- Date:
Mon Jul 10 01:45:18 1995
- Orig file:
v1.3.8/linux/drivers/sound/sb_dsp.c
- Orig date:
Wed Jan 18 09:38:50 1995
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sb_dsp.c linux/drivers/sound/sb_dsp.c
@@ -26,9 +26,11 @@
* SUCH DAMAGE.
*
* Modified:
- * Hunyue Yau Jan 6 1994
- * Added code to support Sound Galaxy NX Pro
+ * Hunyue Yau Jan 6 1994
+ * Added code to support Sound Galaxy NX Pro
*
+ * JRA Gibson April 1995
+ * Code added for MV ProSonic/Jazz 16 in 16 bit mode
*/
#include "sound_config.h"
@@ -42,6 +44,8 @@
int sbc_base = 0;
static int sbc_irq = 0;
static int open_mode = 0; /* Read, write or both */
+int Jazz16_detected = 0;
+int sb_no_recording = 0;
/*
* The DSP channel can be used either for input or output. Variable
@@ -83,6 +87,21 @@
* IMODE_NONE */
static volatile int irq_ok = 0;
+#ifdef JAZZ16
+/* 16 bit support
+ */
+
+static int dsp_16bit = 0;
+static int dma8 = 1;
+static int dma16 = 5;
+
+static int dsp_set_bits (int arg);
+static int initialize_ProSonic16 (void);
+
+/* end of 16 bit support
+ */
+#endif
+
int sb_duplex_midi = 0;
static int my_dev = 0;
@@ -104,8 +123,8 @@
int i;
unsigned long limit;
- limit = GET_TIME () + HZ / 10;/*
- * The timeout is 0.1 seconds
+ limit = GET_TIME () + HZ / 10; /*
+ * The timeout is 0.1 secods
*/
/*
@@ -131,27 +150,22 @@
}
void
-sbintr (int unit, struct pt_regs *regs)
+sbintr (INT_HANDLER_PARMS (irq, dummy))
{
int status;
#ifndef EXCLUDE_SBPRO
if (sb16)
{
- unsigned char src = sb_getmixer (IRQ_STAT); /*
-
-
- * * * * Interrupt
- * source * *
- * register */
+ unsigned char src = sb_getmixer (IRQ_STAT); /* Interrupt source register */
#ifndef EXCLUDE_SB16
if (src & 3)
- sb16_dsp_interrupt (unit);
+ sb16_dsp_interrupt (irq);
#ifndef EXCLUDE_MIDI
if (src & 4)
- sb16midiintr (unit); /*
+ sb16midiintr (irq); /*
* SB MPU401 interrupt
*/
#endif
@@ -160,13 +174,13 @@
if (!(src & 1))
return; /*
- * Not a DSP interrupt
+ * Not a DSP interupt
*/
}
#endif
- status = INB (DSP_DATA_AVAIL);/*
- * Clear interrupt
+ status = INB (DSP_DATA_AVAIL); /*
+ * Clear interrupt
*/
if (sb_intr_active)
@@ -192,7 +206,7 @@
case IMODE_MIDI:
#ifndef EXCLUDE_MIDI
- sb_midi_interrupt (unit);
+ sb_midi_interrupt (irq);
#endif
break;
@@ -209,7 +223,7 @@
int ok;
if (!sb_irq_usecount)
- if ((ok = snd_set_irq_handler (sbc_irq, sbintr)) < 0)
+ if ((ok = snd_set_irq_handler (sbc_irq, sbintr, "SoundBlaster")) < 0)
return ok;
sb_irq_usecount++;
@@ -282,16 +296,16 @@
speed = 4000;
/*
- * Older SB models don't support higher speeds than 22050.
- */
+ * Older SB models don't support higher speeds than 22050.
+ */
if (sbc_major < 2 ||
(sbc_major == 2 && sbc_minor == 0))
max_speed = 22050;
/*
- * SB models earlier than SB Pro have low limit for the input speed.
- */
+ * SB models earlier than SB Pro have low limit for the input speed.
+ */
if (open_mode != OPEN_WRITE) /* Recording is possible */
if (sbc_major < 3) /* Limited input speed with these cards */
if (sbc_major == 2 && sbc_minor > 0)
@@ -304,11 +318,14 @@
* Invalid speed
*/
- if (dsp_stereo && speed > 22050)
- speed = 22050;
+ /* Logitech SoundMan Games and Jazz16 cards can support 44.1kHz stereo */
+#if !defined (SM_GAMES)
/*
* Max. stereo speed is 22050
*/
+ if (dsp_stereo && speed > 22050 && Jazz16_detected == 0)
+ speed = 22050;
+#endif
if ((speed > 22050) && sb_midi_busy)
{
@@ -349,7 +366,7 @@
tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff;
DISABLE_INTR (flags);
- if (sb_dsp_command (0x40))/*
+ if (sb_dsp_command (0x40)) /*
* Set time constant
*/
sb_dsp_command (tconst);
@@ -409,14 +426,14 @@
if (sb_dsp_highspeed)
{
DISABLE_INTR (flags);
- if (sb_dsp_command (0x48))/*
- * High speed size
+ if (sb_dsp_command (0x48)) /*
+ * High speed size
*/
{
sb_dsp_command ((unsigned char) (count & 0xff));
sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
- sb_dsp_command (0x91);/*
- * High speed 8 bit DAC
+ sb_dsp_command (0x91); /*
+ * High speed 8 bit DAC
*/
}
else
@@ -426,8 +443,8 @@
else
{
DISABLE_INTR (flags);
- if (sb_dsp_command (0x14))/*
- * 8-bit DAC (DMA)
+ if (sb_dsp_command (0x14)) /*
+ * 8-bit DAC (DMA)
*/
{
sb_dsp_command ((unsigned char) (count & 0xff));
@@ -463,14 +480,14 @@
if (sb_dsp_highspeed)
{
DISABLE_INTR (flags);
- if (sb_dsp_command (0x48))/*
- * High speed size
+ if (sb_dsp_command (0x48)) /*
+ * High speed size
*/
{
sb_dsp_command ((unsigned char) (count & 0xff));
sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
- sb_dsp_command (0x99);/*
- * High speed 8 bit ADC
+ sb_dsp_command (0x99); /*
+ * High speed 8 bit ADC
*/
}
else
@@ -480,8 +497,8 @@
else
{
DISABLE_INTR (flags);
- if (sb_dsp_command (0x24))/*
- * 8-bit ADC (DMA)
+ if (sb_dsp_command (0x24)) /*
+ * 8-bit ADC (DMA)
*/
{
sb_dsp_command ((unsigned char) (count & 0xff));
@@ -511,11 +528,23 @@
* SB Pro
*/
{
+#ifdef JAZZ16
+ /* Select correct dma channel
+ * for 16/8 bit acccess
+ */
+ audio_devs[my_dev]->dmachan = dsp_16bit ? dma16 : dma8;
+ if (dsp_stereo)
+ sb_dsp_command (dsp_16bit ? 0xac : 0xa8);
+ else
+ sb_dsp_command (dsp_16bit ? 0xa4 : 0xa0);
+#else
+ /* 8 bit only cards use this
+ */
if (dsp_stereo)
sb_dsp_command (0xa8);
else
sb_dsp_command (0xa0);
-
+#endif
dsp_speed (dsp_current_speed); /*
* Speed must be recalculated if
* #channels * changes
@@ -535,7 +564,19 @@
* SB Pro
*/
{
+#ifdef JAZZ16
+ /* 16 bit specific instructions
+ */
+ audio_devs[my_dev]->dmachan = dsp_16bit ? dma16 : dma8;
+ if (Jazz16_detected != 2) /* SM Wave */
+ sb_mixer_set_stereo (dsp_stereo);
+ if (dsp_stereo)
+ sb_dsp_command (dsp_16bit ? 0xac : 0xa8);
+ else
+ sb_dsp_command (dsp_16bit ? 0xa4 : 0xa0);
+#else
sb_mixer_set_stereo (dsp_stereo);
+#endif
dsp_speed (dsp_current_speed); /*
* Speed must be recalculated if
* #channels * changes
@@ -597,6 +638,12 @@
return RET_ERROR (ENXIO);
}
+ if (sb_no_recording && mode & OPEN_READ)
+ {
+ printk ("SB Error: Recording not supported by this device\n");
+ return RET_ERROR (ENOTTY);
+ }
+
if (sb_intr_active || (sb_midi_busy && sb_midi_mode == UART_MIDI))
{
printk ("SB: PCM not possible during MIDI input\n");
@@ -616,12 +663,32 @@
if (retval)
return retval;
+ /* Allocate 8 bit dma
+ */
+#ifdef JAZZ16
+ audio_devs[my_dev]->dmachan = dma8;
+#endif
+
if (DMAbuf_open_dma (dev) < 0)
{
sb_free_irq ();
printk ("SB: DMA Busy\n");
return RET_ERROR (EBUSY);
}
+#ifdef JAZZ16
+ /* Allocate 16 bit dma
+ */
+ if (Jazz16_detected != 0)
+ if (dma16 != dma8)
+ {
+ if (ALLOC_DMA_CHN (dma16, "Jazz16 16 bit"))
+ {
+ sb_free_irq ();
+ DMAbuf_close_dma (dev);
+ return RET_ERROR (EBUSY);
+ }
+ }
+#endif
sb_irq_mode = IMODE_NONE;
@@ -634,6 +701,19 @@
static void
sb_dsp_close (int dev)
{
+#ifdef JAZZ16
+ /* Release 16 bit dma channel
+ */
+ if (Jazz16_detected)
+ {
+ if (audio_devs[my_dev]->dmachan == dma8)
+ RELEASE_DMA_CHN (dma16);
+ else
+ RELEASE_DMA_CHN (dma8);
+
+ }
+#endif
+
DMAbuf_close_dma (dev);
sb_free_irq ();
dsp_cleanup ();
@@ -643,6 +723,32 @@
open_mode = 0;
}
+#ifdef JAZZ16
+/* Function dsp_set_bits() only required for 16 bit cards
+ */
+static int
+dsp_set_bits (int arg)
+{
+ if (arg)
+ if (Jazz16_detected == 0)
+ dsp_16bit = 0;
+ else
+ switch (arg)
+ {
+ case 8:
+ dsp_16bit = 0;
+ break;
+ case 16:
+ dsp_16bit = 1;
+ break;
+ default:
+ dsp_16bit = 0;
+ }
+ return dsp_16bit ? 16 : 8;
+}
+
+#endif /* ifdef JAZZ16 */
+
static int
sb_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
{
@@ -678,14 +784,31 @@
return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg)));
break;
+#ifdef JAZZ16
+ /* Word size specific cases here.
+ * SNDCTL_DSP_SETFMT=SOUND_PCM_WRITE_BITS
+ */
+ case SNDCTL_DSP_SETFMT:
+ if (local)
+ return dsp_set_bits (arg);
+ return IOCTL_OUT (arg, dsp_set_bits (IOCTL_IN (arg)));
+ break;
+
+ case SOUND_PCM_READ_BITS:
+ if (local)
+ return dsp_16bit ? 16 : 8;
+ return IOCTL_OUT (arg, dsp_16bit ? 16 : 8);
+ break;
+#else
case SOUND_PCM_WRITE_BITS:
case SOUND_PCM_READ_BITS:
if (local)
return 8;
- return IOCTL_OUT (arg, 8);/*
- * Only 8 bits/sample supported
+ return IOCTL_OUT (arg, 8); /*
+ * Only 8 bits/sample supported
*/
break;
+#endif /* ifdef JAZZ16 */
case SOUND_PCM_WRITE_FILTER:
case SOUND_PCM_READ_FILTER:
@@ -715,6 +838,232 @@
#endif
+
+#ifdef JAZZ16
+
+/*
+ * Initialization of a Media Vision ProSonic 16 Soundcard.
+ * The function initializes a ProSonic 16 like PROS.EXE does for DOS. It sets
+ * the base address, the DMA-channels, interrupts and enables the joystickport.
+ *
+ * Also used by Jazz 16 (same card, different name)
+ *
+ * written 1994 by Rainer Vranken
+ * E-Mail: rvranken@polaris.informatik.uni-essen.de
+ */
+
+
+#ifndef MPU_BASE /* take default values if not specified */
+#define MPU_BASE 0x330
+#endif
+#ifndef MPU_IRQ
+#define MPU_IRQ 9
+#endif
+
+unsigned int
+get_sb_byte (void)
+{
+ int i;
+
+ for (i = 1000; i; i--)
+ if (INB (DSP_DATA_AVAIL) & 0x80)
+ {
+ return INB (DSP_READ);
+ }
+
+ return 0xffff;
+}
+
+#ifdef SM_WAVE
+/*
+ * Logitech Soundman Wave detection and initialization by Hannu Savolainen.
+ *
+ * There is a microcontroller (8031) in the SM Wave card for MIDI emulation.
+ * it's located at address MPU_BASE+4. MPU_BASE+7 is a SM Wave specific
+ * control register for MC reset, SCSI, OPL4 and DSP (future expansion)
+ * address decoding. Otherwise the SM Wave is just a ordinary MV Jazz16
+ * based soundcard.
+ */
+
+static void
+smw_putmem (int base, int addr, unsigned char val)
+{
+ unsigned long flags;
+
+ DISABLE_INTR (flags);
+
+ OUTB (addr & 0xff, base + 1); /* Low address bits */
+ OUTB (addr >> 8, base + 2); /* High address bits */
+ OUTB (val, base); /* Data */
+
+ RESTORE_INTR (flags);
+}
+
+static unsigned char
+smw_getmem (int base, int addr)
+{
+ unsigned long flags;
+ unsigned char val;
+
+ DISABLE_INTR (flags);
+
+ OUTB (addr & 0xff, base + 1); /* Low address bits */
+ OUTB (addr >> 8, base + 2); /* High address bits */
+ val = INB (base); /* Data */
+
+ RESTORE_INTR (flags);
+ return val;
+}
+
+static int
+initialize_smw (void)
+{
+#ifdef SMW_MIDI0001_INCLUDED
+#include "smw-midi0001.h"
+#else
+ unsigned char smw_ucode[1];
+ int smw_ucodeLen = 0;
+
+#endif
+
+ 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 */
+
+ for (i = 0; i < 300; i++) /* Wait at least 1ms */
+ tenmicrosec ();
+
+ OUTB (control & 0xfc, MPU_BASE + 7); /* xxxxxx00 enables RAM */
+
+ /*
+ * Detect microcontroller by probing the 8k RAM area
+ */
+ smw_putmem (mp_base, 0, 0x00);
+ smw_putmem (mp_base, 1, 0xff);
+ tenmicrosec ();
+
+ if (smw_getmem (mp_base, 0) != 0x00 || smw_getmem (mp_base, 1) != 0xff)
+ {
+ printk ("\nSM Wave: No microcontroller RAM detected (%02x, %02x)\n",
+ smw_getmem (mp_base, 0), smw_getmem (mp_base, 1));
+ return 0; /* No RAM */
+ }
+
+ /*
+ * There is RAM so assume it's really a SM Wave
+ */
+
+#ifdef SMW_MIDI0001_INCLUDED
+ if (smw_ucodeLen != 8192)
+ {
+ printk ("\nSM Wave: Invalid microcode (MIDI0001.BIN) length\n");
+ return 1;
+ }
+#endif
+
+ /*
+ * Download microcode
+ */
+
+ for (i = 0; i < 8192; i++)
+ smw_putmem (mp_base, i, smw_ucode[i]);
+
+ /*
+ * Verify microcode
+ */
+
+ for (i = 0; i < 8192; i++)
+ if (smw_getmem (mp_base, i) != smw_ucode[i])
+ {
+ printk ("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.
+ *
+ * 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 VoxWare
+ * 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 */
+ return 1;
+}
+
+#endif
+
+static int
+initialize_ProSonic16 (void)
+{
+ int x;
+ static unsigned char int_translat[16] =
+ {0, 0, 2, 3, 0, 1, 0, 4, 0, 2, 5, 0, 0, 0, 0, 6}, dma_translat[8] =
+ {0, 1, 0, 2, 0, 3, 0, 4};
+
+ OUTB (0xAF, 0x201); /* ProSonic/Jazz16 wakeup */
+ for (x = 0; x < 1000; ++x) /* wait 10 milliseconds */
+ tenmicrosec ();
+ OUTB (0x50, 0x201);
+ OUTB ((sbc_base & 0x70) | ((MPU_BASE & 0x30) >> 4), 0x201);
+
+ if (sb_reset_dsp ())
+ { /* OK. We have at least a SB */
+
+ /* Check the version number of ProSonic (I guess) */
+
+ if (!sb_dsp_command (0xFA))
+ return 1;
+ if (get_sb_byte () != 0x12)
+ return 1;
+
+ if (sb_dsp_command (0xFB) && /* set DMA-channels and Interrupts */
+ sb_dsp_command ((dma_translat[JAZZ_DMA16] << 4) | dma_translat[SBC_DMA]) &&
+ sb_dsp_command ((int_translat[MPU_IRQ] << 4) | int_translat[sbc_irq]))
+ {
+ Jazz16_detected = 1;
+#ifdef SM_WAVE
+ if (initialize_smw ())
+ Jazz16_detected = 2;
+#endif
+ sb_dsp_disable_midi ();
+ }
+
+ return 1; /* There was at least a SB */
+ }
+ return 0; /* No SB or ProSonic16 detected */
+}
+
+#endif /* ifdef JAZZ16 */
+
int
sb_dsp_detect (struct address_info *hw_config)
{
@@ -725,9 +1074,16 @@
return 0; /*
* Already initialized
*/
+#ifdef JAZZ16
+ dma8 = hw_config->dma;
+ dma16 = JAZZ_DMA16;
+ if (!initialize_ProSonic16 ())
+ return 0;
+#else
if (!sb_reset_dsp ())
return 0;
+#endif
return 1; /*
* Detected
@@ -792,6 +1148,9 @@
#ifndef EXCLUDE_SBPRO
if (sbc_major >= 3)
mixer_type = sb_mixer_init (sbc_major);
+#else
+ if (sbc_major >= 3)
+ printk ("\n\n\n\nNOTE! SB Pro support is required with your soundcard!\n\n\n");
#endif
#ifndef EXCLUDE_YM3812
@@ -801,31 +1160,42 @@
enable_opl3_mode (OPL3_LEFT, OPL3_RIGHT, OPL3_BOTH);
#endif
+#ifndef EXCLUDE_AUDIO
if (sbc_major >= 3)
{
-#if !defined(SCO) && !defined(EXCLUDE_AUDIO)
-# ifdef __SGNXPRO__
+ if (Jazz16_detected)
+ {
+ if (Jazz16_detected == 2)
+ sprintf (sb_dsp_operations.name, "SoundMan Wave %d.%d", sbc_major, sbc_minor);
+ else
+ sprintf (sb_dsp_operations.name, "MV Jazz16 %d.%d", sbc_major, sbc_minor);
+ sb_dsp_operations.format_mask |= AFMT_S16_LE; /* Hurrah, 16 bits */
+ }
+ else
+#ifdef __SGNXPRO__
if (mixer_type == 2)
{
sprintf (sb_dsp_operations.name, "Sound Galaxy NX Pro %d.%d", sbc_major, sbc_minor);
}
else
-# endif
+#endif
+
+ if (sbc_major == 4)
+ {
+ sprintf (sb_dsp_operations.name, "SoundBlaster 16 %d.%d", sbc_major, sbc_minor);
+ }
+ else
{
sprintf (sb_dsp_operations.name, "SoundBlaster Pro %d.%d", sbc_major, sbc_minor);
}
-#endif
}
else
{
-#ifndef SCO
sprintf (sb_dsp_operations.name, "SoundBlaster %d.%d", sbc_major, sbc_minor);
-#endif
}
printk (" <%s>", sb_dsp_operations.name);
-#ifndef EXCLUDE_AUDIO
#if !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SBPRO)
if (!sb16) /*
* There is a better driver for SB16
@@ -840,6 +1210,8 @@
}
else
printk ("SB: Too many DSP devices available\n");
+#else
+ printk (" <SoundBlaster (configured without audio support)>");
#endif
#ifndef EXCLUDE_MIDI
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this