diff options
60 files changed, 7481 insertions, 1754 deletions
diff --git a/sys/i386/isa/sound/CHANGELOG b/sys/i386/isa/sound/CHANGELOG index b04d7a8..e21dfaa 100644 --- a/sys/i386/isa/sound/CHANGELOG +++ b/sys/i386/isa/sound/CHANGELOG @@ -1,10 +1,22 @@ -Changelog for version 2.90 +Changelog for version 3.0-950506 ------------------------------------ -This is an intermediate release (v3.0 prototype with some experimental -features disabled). See experimental.txt for more info. +Since 3.0-94xxxx +- Too many changes -Since pre-3.0-949712 +Since 3.0-940818 +- Fixes for Linux 1.1.4x. +- Disables Disney Sound System with SG NX Pro 16 (less noise). + +Since 2.90-2 +- Fixes to soundcard.h +- Non blocking mode to /dev/sequencer +- Experimental detection code for Ensoniq Soundscape. + +Since 2.90 +- Minor and major bug fixes + +Since pre-3.0-940712 - GUS MAX support - Partially working MSS/WSS support (could work with some cards). - Hardware u-Law and A-Law support with AD1848/CS4248 and CS4231 codecs diff --git a/sys/i386/isa/sound/Readme.aedsp16 b/sys/i386/isa/sound/Readme.aedsp16 new file mode 100644 index 0000000..b205a9d --- /dev/null +++ b/sys/i386/isa/sound/Readme.aedsp16 @@ -0,0 +1,6 @@ +Informations about Audio Excel DSP 16 can be found in the source +file aedsp16.c +Please, read the head of the source before using it. It contain useful +informations. + + Riccardo diff --git a/sys/i386/isa/sound/Readme.modules b/sys/i386/isa/sound/Readme.modules new file mode 100644 index 0000000..315540f --- /dev/null +++ b/sys/i386/isa/sound/Readme.modules @@ -0,0 +1,87 @@ + Linux sound-driver module + (c) Peter Trattler + License: GPL (Gnu Public License) + + +Idea: + +I've modified the sources for the sound driver to allow simply insert and +remove the sound driver from the kernel by calling (only available for Linux) + + insmod /usr/src/linux/modules/sound.o + +and + + rmmod sound + +This may be useful if you are doing one of the following things: + +1) Debugging the sound driver +2) Creating a new device within the sound-driver +3) You do not the sound driver all the time (as it wastes quite a lot of +memory for its buffers) + + +Compilation: + +Go to /usr/src/linux and make the following steps: + +a) configure the sound driver: To do that call "make config" and enable the +sound-driver -- you will be asked different questions about your +sound-hardware (remember not to use a too big DMA-Buffer size; you +should use 16kB, if you have 16Bit devices, otherwise you can use 32kB) + +b) disable the sound driver in the kernel: call make config again but answer +'N' to "Sound card support" + +c) run "make modules"; the sound-driver sound.o should end up in +/usr/src/linux/modules + + +If memory is tight: + +I've allocated at about 70kB for the sound-drivers internal tables. If this +is too much, 'insmod sound.o' will generate the following warning +... +use 'insmod memsize=xxxx' +... +You can only use this command, if you have (I think) at least +modules-1.1.87 or up. You can also switch debugging on by running the command + +insmod sound.o debugmem=1 + + +Files I changed: + +I've only changed the files soundcard.c(most changes) and some changes within +the Makefile, sound_config.h and the Makefile in /usr/src/linux/drivers + + +Bugs: + +a) As the kmalloc (..., GFP_DMA) caused some unexpected errors (I don't know if +it is my fault), I created some code, which is (by default) enabled by + +#define KMALLOC_DMA_BROKEN 1 (within soundcard.c). + +It trys to allocate a large enough region, so that the complete dma-buffer +can be occupied in this space. If it does not fit within this region it +doubles the size of it. But this can cause problems, if the sound-buffer is +too big (as kmalloc can only handle regions at up to circa 100kB). + +So take care to use for 8Bit devices a sound-DMA-buffer of 32kB (maximum) +and for 16Bit devices a maximum of 16kB. Otherwise the allocation scheme +might fail. + +b) Buffers allocated by the different sound devices via calls to kmalloc are +not freed, if the sound driver is removed again (these buffers tend to be +quite small -- so it does not harm a lot) + +c) If there is not enough (kernel-) memory available, the installation of +the sound-driver fails. (This happens quite often, if you did not install the +driver right after booting -- [PS: I've only got 5MB of Ram, so this might +be the source for this problem]) + + +Author: + Peter Trattler (peter@sbox.tu-graz.ac.at) diff --git a/sys/i386/isa/sound/Readme.v30 b/sys/i386/isa/sound/Readme.v30 index cade461..8884ad8 100644 --- a/sys/i386/isa/sound/Readme.v30 +++ b/sys/i386/isa/sound/Readme.v30 @@ -1,38 +1,26 @@ VoxWare v3.0 ------------ -This is a PROTOTYPE of the VoxWare v3.0 to be released late 94. +This is a late alpha/early beta of the VoxWare v3.0 to be relased May/June 95. -All features of v2.5 should work as earlier. There could be some +All features of v2.90-2 should work as earlier. There could be some omissions but they are unintentional. I started this version thread after v2.3 so all features implemented before it are there. -Even this is a prototype, there should not be any fatal bugs. The -prototype just means that I don't have implemented all features -completely. Mainly in the /dev/sequencer2 driver. -For example recording from /dev/sequencer2 won't work -with other cards than a full features MPU-401 or clones. As well the -way how the MIDI controllers are handled will change. - -IMPORTANT!!!!!!!!!!!!!!!!! - -Don't distribute any binaries compiled with the soundcard.h of this version. -They will not work together with older drivers. - New features ============ There are now two new device interfaces. The /dev/midi## is a raw tty like interface to MIDI ports. There is a device file for each MIDI port on your system. They are named (/dev/midi00 to /dev/midiNN). -The second addition is the /dev/sequencer2 which is higher level interface +The second addition is the /dev/music which is higher level interface than the old /dev/sequencer. It's intended for writing device independent applications like sequencers. /dev/midi## ----------- -This interface should be useful for applications like MIDI sysex librarians. +This interface should be usefull for applications like MIDI sysex librarians. There are (currently) no timing features so making music could be impossible. There are as many /dev/midi## devices as there are MIDI ports in the system. @@ -67,7 +55,7 @@ It's not available for the so called MPU UART ports of some soundcards If this ioctl is called with mode=1, the interface is put to the intelligent (coprocessor) mode. NOTE! The MIDI port will be reset when this ioctl is called. It could have some strange effects if not called immediately after open. This -call returns EINVAL if the midi port doesn't support the MPU-401 intelligent +vall returns EINVAL if the midi port doesn't support the MPU-401 intelligent mode. ioctl(fd, SNDCTL_MIDI_MPUCMD, &cmdstruct) is valid only if the MIDI port @@ -95,15 +83,15 @@ where: data Buffer for the command arguments and returned data. -Be extremely careful with the nr_args and nr_returns fields. They +Be extremely carefull with the nr_args and nr_returns fields. They must match the command. An incorrect value will put the card and the driver out of sync. Refer to the MPU-401/MQX-32M documentation for further -details. +datails. -/dev/sequencer2 (if you find a better name, please let me know). ---------------- +/dev/music (/dev/sequencer2) +---------------------------- This device file works much like the /dev/sequencer which has been present since the beginning. The main differences are the following: @@ -113,7 +101,7 @@ the result is somewhere between the MIDI specification and the synth devices of /dev/sequencer. Both kind of devices are accessed using the SEQ_START_NOTE() like macros. The voice number parameters of the API macros have been redefined to denote MIDI channels. This means that the driver allocates voices for -the channels automatically (this is a responsibility/right of an application +the channels automaticly (this is a responsibility/right of an application with /dev/sequencer). The result is that a SEQ_START_NOTE() macro has similar effects for a synth channel than on a MIDI port. This kind of solution provides better device independence than the /dev/sequencer. The @@ -130,12 +118,12 @@ return sum of internal synthesizers (GUS, OPL3) and MIDI ports in the systems. - The new interface is used much like the ordinary /dev/sequencer. The event format is new so you have to use the API macros defined in the -sys/soundcard.h. The interface will probably change before the final 3.0 +sys/soundcard.h. The interface is will propably change before the final 3.0 release but using the API macros should ensure compatibility in source level. The new event format is not recognized by version 2.X so don't try to distribute binaries compiled with soundcard.h of v3.X. -- The basic API usage is similar to the current one. There are some new +- The basic API useage is similar to the current one. There are some new macros but the older ones should work as earlier. The most important incompatibility is that the /dev/sequencer2 driver allocates voices itself. The other one is that the application must send SEQ_START_TIMER() as it's diff --git a/sys/i386/isa/sound/ad1848.c b/sys/i386/isa/sound/ad1848.c index 560edc5..3aa02ed 100644 --- a/sys/i386/isa/sound/ad1848.c +++ b/sys/i386/isa/sound/ad1848.c @@ -7,7 +7,7 @@ * The CS4231 which is used in the GUS MAX and some other cards is * upwards compatible with AD1848 and this driver is able to drive it. * - * Copyright by Hannu Savolainen 1994 + * Copyright by Hannu Savolainen 1994, 1995 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -29,7 +29,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * ad1848.c,v 1.3 1994/10/01 05:46:01 davidg Exp + * Modified: + * Riccardo Facchetti 24 Mar 1995 + * - Added the Audio Excel DSP 16 initialization routine. */ #define DEB(x) @@ -38,6 +40,8 @@ #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AD1848) +#include "ad1848_mixer.h" + #define IMODE_NONE 0 #define IMODE_OUTPUT 1 #define IMODE_INPUT 2 @@ -45,25 +49,32 @@ #define IMODE_MIDI 4 typedef struct -{ - int base; - int irq; - int dma_capture, dma_playback; - unsigned char MCE_bit; - - int speed; - unsigned char speed_bits; - int channels; - int audio_format; - unsigned char format_bits; - - int xfer_count; - int irq_mode; - int intr_active; - int opened; - char *chip_name; - int mode; -} + { + int base; + int irq; + int dma_capture, dma_playback; + unsigned char MCE_bit; + unsigned char saved_regs[16]; + + int speed; + unsigned char speed_bits; + int channels; + int audio_format; + unsigned char format_bits; + + int xfer_count; + int irq_mode; + int intr_active; + int opened; + char *chip_name; + int mode; + + /* Mixer parameters */ + int recmask; + int supported_devices; + int supported_rec_devices; + unsigned short levels[32]; + } ad1848_info; @@ -72,7 +83,10 @@ static char irq2dev[16] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; -static int ad_format_mask[3 /*devc->mode*/ ] = +static char mixer2codec[MAX_MIXER_DEV] = +{0}; + +static int ad_format_mask[3 /*devc->mode */ ] = { 0, AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW, @@ -100,6 +114,10 @@ ad_read (ad1848_info * devc, int reg) { unsigned long flags; int x; + int timeout = 100; + + while (timeout > 0 && INB (devc->base) == 0x80) /*Are we initializing */ + timeout--; DISABLE_INTR (flags); OUTB ((unsigned char) (reg & 0xff) | devc->MCE_bit, io_Index_Addr (devc)); @@ -114,6 +132,10 @@ static void ad_write (ad1848_info * devc, int reg, int data) { unsigned long flags; + int timeout = 100; + + while (timeout > 0 && INB (devc->base) == 0x80) /*Are we initializing */ + timeout--; DISABLE_INTR (flags); OUTB ((unsigned char) (reg & 0xff) | devc->MCE_bit, io_Index_Addr (devc)); @@ -123,55 +145,340 @@ ad_write (ad1848_info * devc, int reg, int data) } static void -ad_set_MCE (ad1848_info * devc, int state) -{ - unsigned long flags; - - DISABLE_INTR (flags); - if (state) - devc->MCE_bit = 0x40; - else - devc->MCE_bit = 0x00; - OUTB (devc->MCE_bit, io_Index_Addr (devc)); - RESTORE_INTR (flags); -} - -static void wait_for_calibration (ad1848_info * devc) { int timeout = 0; /* - * Wait until the auto calibration process has finished. - * - * 1) Wait until the chip becomes ready (reads don't return 0x80). - * 2) Wait until the ACI bit of I11 gets on and then off. - */ + * Wait until the auto calibration process has finished. + * + * 1) Wait until the chip becomes ready (reads don't return 0x80). + * 2) Wait until the ACI bit of I11 gets on and then off. + */ timeout = 100000; - while (timeout > 0 && INB (devc->base) == 0x80) + while (timeout > 0 && INB (devc->base) & 0x80) timeout--; - if (INB (devc->base) == 0x80) + if (INB (devc->base) & 0x80) printk ("ad1848: Auto calibration timed out(1).\n"); - timeout = 100000; + timeout = 100; while (timeout > 0 && !(ad_read (devc, 11) & 0x20)) timeout--; if (!(ad_read (devc, 11) & 0x20)) - printk ("ad1848: Auto calibration timed out(2).\n"); + return; - timeout = 100000; + timeout = 10000; while (timeout > 0 && ad_read (devc, 11) & 0x20) timeout--; if (ad_read (devc, 11) & 0x20) printk ("ad1848: Auto calibration timed out(3).\n"); } +static void +ad_mute (ad1848_info * devc) +{ + int i; + unsigned char prev; + + /* + * Save old register settings and mute output channels + */ + for (i = 6; i < 8; i++) + { + prev = devc->saved_regs[i] = ad_read (devc, i); + ad_write (devc, i, prev | 0x80); + } +} + +static void +ad_unmute (ad1848_info * devc) +{ + int i; + + /* + * Restore back old volume registers (unmute) + */ + for (i = 6; i < 8; i++) + { + ad_write (devc, i, devc->saved_regs[i] & ~0x80); + } +} + +static void +ad_enter_MCE (ad1848_info * devc) +{ + unsigned long flags; + int timeout = 1000; + unsigned short prev; + + while (timeout > 0 && INB (devc->base) == 0x80) /*Are we initializing */ + timeout--; + + DISABLE_INTR (flags); + + devc->MCE_bit = 0x40; + prev = INB (io_Index_Addr (devc)); + if (prev & 0x40) + { + RESTORE_INTR (flags); + return; + } + + OUTB (devc->MCE_bit, io_Index_Addr (devc)); + RESTORE_INTR (flags); +} + +static void +ad_leave_MCE (ad1848_info * devc) +{ + unsigned long flags; + unsigned char prev; + int timeout = 1000; + + while (timeout > 0 && INB (devc->base) == 0x80) /*Are we initializing */ + timeout--; + + DISABLE_INTR (flags); + + devc->MCE_bit = 0x00; + prev = INB (io_Index_Addr (devc)); + OUTB (0x00, io_Index_Addr (devc)); /* Clear the MCE bit */ + + if (prev & 0x40 == 0) /* Not in MCE mode */ + { + RESTORE_INTR (flags); + return; + } + + OUTB (0x00, io_Index_Addr (devc)); /* Clear the MCE bit */ + wait_for_calibration (devc); + RESTORE_INTR (flags); +} + + +static int +ad1848_set_recmask (ad1848_info * devc, int mask) +{ + unsigned char recdev; + int i, n; + + mask &= devc->supported_rec_devices; + + n = 0; + for (i = 0; i < 32; i++) /* Count selected device bits */ + if (mask & (1 << i)) + n++; + + if (n == 0) + mask = SOUND_MASK_MIC; + else if (n != 1) /* Too many devices selected */ + { + mask &= ~devc->recmask; /* Filter out active settings */ + + n = 0; + for (i = 0; i < 32; i++) /* Count selected device bits */ + if (mask & (1 << i)) + n++; + + if (n != 1) + mask = SOUND_MASK_MIC; + } + + switch (mask) + { + case SOUND_MASK_MIC: + recdev = 2; + break; + + case SOUND_MASK_LINE: + case SOUND_MASK_LINE3: + recdev = 0; + break; + + case SOUND_MASK_CD: + case SOUND_MASK_LINE1: + recdev = 1; + break; + + default: + mask = SOUND_MASK_MIC; + recdev = 2; + } + + recdev <<= 6; + ad_write (devc, 0, (ad_read (devc, 0) & 0x3f) | recdev); + ad_write (devc, 1, (ad_read (devc, 1) & 0x3f) | recdev); + + devc->recmask = mask; + return mask; +} + +static void +change_bits (unsigned char *regval, int dev, int chn, int newval) +{ + unsigned char mask; + int shift; + + if (mix_devices[dev][chn].polarity == 1) /* Reverse */ + newval = 100 - newval; + + mask = (1 << mix_devices[dev][chn].nbits) - 1; + shift = mix_devices[dev][chn].bitpos; + newval = (int) ((newval * mask) + 50) / 100; /* Scale it */ + + *regval &= ~(mask << shift); /* Clear bits */ + *regval |= (newval & mask) << shift; /* Set new value */ +} + +static int +ad1848_mixer_get (ad1848_info * devc, int dev) +{ + if (!((1 << dev) & devc->supported_devices)) + return RET_ERROR (EINVAL); + + return devc->levels[dev]; +} + +static int +ad1848_mixer_set (ad1848_info * devc, int dev, int value) +{ + int left = value & 0x000000ff; + int right = (value & 0x0000ff00) >> 8; + + int regoffs; + unsigned char val; + + if (left > 100) + left = 100; + if (right > 100) + right = 100; + + if (dev > 31) + return RET_ERROR (EINVAL); + + if (!(devc->supported_devices & (1 << dev))) + return RET_ERROR (EINVAL); + + if (mix_devices[dev][LEFT_CHN].nbits == 0) + return RET_ERROR (EINVAL); + + /* + * Set the left channel + */ + + regoffs = mix_devices[dev][LEFT_CHN].regno; + val = ad_read (devc, regoffs); + change_bits (&val, dev, LEFT_CHN, left); + devc->levels[dev] = left | (left << 8); + ad_write (devc, regoffs, val); + devc->saved_regs[regoffs] = val; + + /* + * Set the left right + */ + + if (mix_devices[dev][RIGHT_CHN].nbits == 0) + return left | (left << 8); /* Was just a mono channel */ + + regoffs = mix_devices[dev][RIGHT_CHN].regno; + val = ad_read (devc, regoffs); + change_bits (&val, dev, RIGHT_CHN, right); + ad_write (devc, regoffs, val); + devc->saved_regs[regoffs] = val; + + devc->levels[dev] = left | (right << 8); + return left | (right << 8); +} + +static void +ad1848_mixer_reset (ad1848_info * devc) +{ + int i; + + devc->recmask = 0; + if (devc->mode == 2) + devc->supported_devices = MODE2_MIXER_DEVICES; + else + devc->supported_devices = MODE1_MIXER_DEVICES; + + devc->supported_rec_devices = MODE1_REC_DEVICES; + + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) + ad1848_mixer_set (devc, i, devc->levels[i] = default_mixer_levels[i]); + ad1848_set_recmask (devc, SOUND_MASK_MIC); +} + +static int +ad1848_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg) +{ + ad1848_info *devc; + + int codec_dev = mixer2codec[dev]; + + if (!codec_dev) + return RET_ERROR (ENXIO); + + codec_dev--; + + devc = (ad1848_info *) audio_devs[codec_dev]->devc; + + if (((cmd >> 8) & 0xff) == 'M') + { + if (cmd & IOC_IN) + switch (cmd & 0xff) + { + case SOUND_MIXER_RECSRC: + return IOCTL_OUT (arg, ad1848_set_recmask (devc, IOCTL_IN (arg))); + break; + + default: + return IOCTL_OUT (arg, ad1848_mixer_set (devc, cmd & 0xff, IOCTL_IN (arg))); + } + else + switch (cmd & 0xff) /* + * Return parameters + */ + { + + case SOUND_MIXER_RECSRC: + return IOCTL_OUT (arg, devc->recmask); + break; + + case SOUND_MIXER_DEVMASK: + return IOCTL_OUT (arg, devc->supported_devices); + break; + + case SOUND_MIXER_STEREODEVS: + return IOCTL_OUT (arg, devc->supported_devices & + ~(SOUND_MASK_SPEAKER | SOUND_MASK_IMIX)); + break; + + case SOUND_MIXER_RECMASK: + return IOCTL_OUT (arg, devc->supported_rec_devices); + break; + + case SOUND_MIXER_CAPS: + return IOCTL_OUT (arg, SOUND_CAP_EXCL_INPUT); + break; + + default: + return IOCTL_OUT (arg, ad1848_mixer_get (devc, cmd & 0xff)); + } + } + else + return RET_ERROR (EINVAL); +} + static struct audio_operations ad1848_pcm_operations[MAX_AUDIO_DEV] = { { "Generic AD1848 codec", +#if defined(__FreeBSD__) + NEEDS_RESTART, +#else DMA_AUTOMODE, +#endif AFMT_U8, /* Will be set later */ NULL, ad1848_open, @@ -187,6 +494,12 @@ static struct audio_operations ad1848_pcm_operations[MAX_AUDIO_DEV] = NULL }}; +static struct mixer_operations ad1848_mixer_operations = +{ + "AD1848/CS4248/CS4231", + ad1848_mixer_ioctl +}; + static int ad1848_open (int dev, int mode) { @@ -210,7 +523,8 @@ ad1848_open (int dev, int mode) } if (devc->irq) /* Not managed by another driver */ - if ((err = snd_set_irq_handler (devc->irq, adintr)) < 0) + if ((err = snd_set_irq_handler (devc->irq, ad1848_interrupt, + audio_devs[dev]->name)) < 0) { printk ("ad1848: IRQ in use\n"); RESTORE_INTR (flags); @@ -255,18 +569,18 @@ static int set_speed (ad1848_info * devc, int arg) { /* - * The sampling speed is encoded in the least significant nibble of I8. The - * LSB selects the clock source (0=24.576 MHz, 1=16.9344 Mhz) and other - * three bits select the divisor (indirectly): - * - * The available speeds are in the following table. Keep the speeds in - * the increasing order. - */ + * The sampling speed is encoded in the least significant nible of I8. The + * LSB selects the clock source (0=24.576 MHz, 1=16.9344 Mhz) and other + * three bits select the divisor (indirectly): + * + * The available speeds are in the following table. Keep the speeds in + * the increasing order. + */ typedef struct - { - int speed; - unsigned char bits; - } + { + int speed; + unsigned char bits; + } speed_struct; static speed_struct speed_table[] = @@ -297,7 +611,7 @@ set_speed (ad1848_info * devc, int arg) if (arg > speed_table[n - 1].speed) selected = n - 1; - for (i = 1 /*really*/ ; selected == -1 && i < n; i++) + for (i = 1 /*really */ ; selected == -1 && i < n; i++) if (speed_table[i].speed == arg) selected = i; else if (speed_table[i].speed > arg) @@ -339,11 +653,11 @@ set_format (ad1848_info * devc, int arg) { static struct format_tbl - { - int format; - unsigned char bits; - } - format2bits [] = + { + int format; + unsigned char bits; + } + format2bits[] = { { 0, 0 @@ -488,30 +802,31 @@ ad1848_output_block (int dev, unsigned long buf, int count, int intrflag, int dm if (dma_restart) { - ad1848_halt (dev); + /* ad1848_halt (dev); */ DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); } - ad_set_MCE (devc, 1); + ad_enter_MCE (devc); ad_write (devc, 15, (unsigned char) (cnt & 0xff)); ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff)); - ad_write (devc, 9, 0x0d); /* * Playback enable, single DMA channel mode, * auto calibration on. */ - ad_set_MCE (devc, 0); /* + ad_leave_MCE (devc); /* * Starts the calibration process and * enters playback mode after it. */ - wait_for_calibration (devc); + ad_unmute (devc); devc->xfer_count = cnt; devc->irq_mode = IMODE_OUTPUT; devc->intr_active = 1; + INB (io_Status (devc)); + OUTB (0, io_Status (devc)); /* Clear pending interrupts */ RESTORE_INTR (flags); } @@ -521,7 +836,7 @@ ad1848_start_input (int dev, unsigned long buf, int count, int intrflag, int dma unsigned long flags, cnt; ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - /* int count_reg = (devc->mode == 1) ? 14 : 30; */ + int count_reg = 14; /* (devc->mode == 1) ? 14 : 30; */ cnt = count; if (devc->audio_format == AFMT_IMA_ADPCM) @@ -551,38 +866,31 @@ ad1848_start_input (int dev, unsigned long buf, int count, int intrflag, int dma if (dma_restart) { - ad1848_halt (dev); + /* ad1848_halt (dev); */ DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); } - ad_set_MCE (devc, 1); -#if 0 + ad_enter_MCE (devc); + ad_write (devc, count_reg + 1, (unsigned char) (cnt & 0xff)); ad_write (devc, count_reg, (unsigned char) ((cnt >> 8) & 0xff)); -#else - ad_write (devc, 15, (unsigned char) (cnt & 0xff)); - ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff)); - if (devc->mode == 2) - { - ad_write (devc, 31, (unsigned char) (cnt & 0xff)); - ad_write (devc, 32, (unsigned char) ((cnt >> 8) & 0xff)); - } -#endif ad_write (devc, 9, 0x0e); /* * Capture enable, single DMA channel mode, * auto calibration on. */ - ad_set_MCE (devc, 0); /* + ad_leave_MCE (devc); /* * Starts the calibration process and * enters playback mode after it. */ - wait_for_calibration (devc); + ad_unmute (devc); devc->xfer_count = cnt; devc->irq_mode = IMODE_INPUT; devc->intr_active = 1; + INB (io_Status (devc)); + OUTB (0, io_Status (devc)); /* Clear interrupt status */ RESTORE_INTR (flags); } @@ -595,7 +903,7 @@ ad1848_prepare_for_IO (int dev, int bsize, int bcount) ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; DISABLE_INTR (flags); - ad_set_MCE (devc, 1); /* Enables changes to the format select reg */ + ad_enter_MCE (devc); /* Enables changes to the format select reg */ fs = devc->speed_bits | (devc->format_bits << 5); if (devc->channels > 1) @@ -603,41 +911,33 @@ ad1848_prepare_for_IO (int dev, int bsize, int bcount) ad_write (devc, 8, fs); /* - * Write to I8 starts resynchronization. Wait until it completes. + * Write to I8 starts resyncronization. Wait until it completes. */ timeout = 10000; while (timeout > 0 && INB (devc->base) == 0x80) timeout--; - ad_set_MCE (devc, 0); /* - * Starts the calibration process and - * enters playback mode after it. - */ - wait_for_calibration (devc); - RESTORE_INTR (flags); - /* - * If mode == 2 (CS4231), set I28 also. It's the capture format register. - */ + * If mode == 2 (CS4231), set I28 also. It's the capture format register. + */ if (devc->mode == 2) { - ad_set_MCE (devc, 1); ad_write (devc, 28, fs); /* - * Write to I28 starts resynchronization. Wait until it completes. - */ + * Write to I28 starts resyncronization. Wait until it completes. + */ timeout = 10000; while (timeout > 0 && INB (devc->base) == 0x80) timeout--; - ad_set_MCE (devc, 0); /* + } + + ad_leave_MCE (devc); /* * Starts the calibration process and * enters playback mode after it. */ - wait_for_calibration (devc); - RESTORE_INTR (flags); - } + RESTORE_INTR (flags); devc->xfer_count = 0; return 0; } @@ -653,23 +953,44 @@ ad1848_halt (int dev) { ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - ad_write (devc, 9, 0); /* Clear the PEN and CEN bits (among others) */ + ad_mute (devc); + ad_write (devc, 9, ad_read (devc, 9) & ~0x03); /* Stop DMA */ + OUTB (0, io_Status (devc)); /* Clear interrupt status */ + + ad_enter_MCE (devc); + OUTB (0, io_Status (devc)); /* Clear interrupt status */ + ad_write (devc, 15, 0); /* Clear DMA counter */ + ad_write (devc, 14, 0); /* Clear DMA counter */ + + if (devc->mode == 2) + { + ad_write (devc, 30, 0); /* Clear DMA counter */ + ad_write (devc, 31, 0); /* Clear DMA counter */ + } + + ad_write (devc, 9, ad_read (devc, 9) & ~0x03); /* Stop DMA */ + + OUTB (0, io_Status (devc)); /* Clear interrupt status */ OUTB (0, io_Status (devc)); /* Clear interrupt status */ + ad_leave_MCE (devc); + + DMAbuf_reset_dma (dev); } int ad1848_detect (int io_base) { -#define AUDIO_DDB(x) x - unsigned char tmp; int i; ad1848_info *devc = &dev_info[nr_ad1848_devs]; unsigned char tmp1 = 0xff, tmp2 = 0xff; if (nr_ad1848_devs >= MAX_AUDIO_DEV) - return 0; + { + AUDIO_DDB (printk ("ad1848 detect error - step 0\n")); + return 0; + } devc->base = io_base; devc->MCE_bit = 0x40; @@ -681,33 +1002,33 @@ ad1848_detect (int io_base) devc->mode = 1; /* MODE1 = original AD1848 */ /* - * Check that the I/O address is in use. - * - * The bit 0x80 of the base I/O port is known to be 0 after the - * chip has performed it's power on initialization. Just assume - * this has happened before the OS is starting. - * - * If the I/O address is unused, it typically returns 0xff. - */ + * Check that the I/O address is in use. + * + * The bit 0x80 of the base I/O port is known to be 0 after the + * chip has performed it's power on initialization. Just assume + * this has happened before the OS is starting. + * + * If the I/O address is unused, it typically returns 0xff. + */ if ((INB (devc->base) & 0x80) != 0x00) /* Not a AD1884 */ { - AUDIO_DDB (printk ("ad_detect_A\n")); + AUDIO_DDB (printk ("ad1848 detect error - step A\n")); return 0; } /* - * Test if it's possible to change contents of the indirect registers. - * Registers 0 and 1 are ADC volume registers. The bit 0x10 is read only - * so try to avoid using it. -*/ + * Test if it's possible to change contents of the indirect registers. + * Registers 0 and 1 are ADC volume registers. The bit 0x10 is read only + * so try to avoid using it. + */ ad_write (devc, 0, 0xaa); ad_write (devc, 1, 0x45); /* 0x55 with bit 0x10 clear */ if ((tmp1 = ad_read (devc, 0)) != 0xaa || (tmp2 = ad_read (devc, 1)) != 0x45) { - AUDIO_DDB (printk ("ad_detect_B (%x/%x)\n", tmp1, tmp2)); + AUDIO_DDB (printk ("ad1848 detect error - step B (%x/%x)\n", tmp1, tmp2)); return 0; } @@ -716,63 +1037,63 @@ ad1848_detect (int io_base) if ((tmp1 = ad_read (devc, 0)) != 0x45 || (tmp2 = ad_read (devc, 1)) != 0xaa) { - AUDIO_DDB (printk ("ad_detect_C (%x/%x)\n", tmp1, tmp2)); + AUDIO_DDB (printk ("ad1848 detect error - step C (%x/%x)\n", tmp1, tmp2)); return 0; } /* - * The indirect register I12 has some read only bits. Lets - * try to change them. - */ + * The indirect register I12 has some read only bits. Lets + * try to change them. + */ tmp = ad_read (devc, 12); ad_write (devc, 12, (~tmp) & 0x0f); if ((tmp & 0x0f) != ((tmp1 = ad_read (devc, 12)) & 0x0f)) { - AUDIO_DDB (printk ("ad_detect_D (%x)\n", tmp1)); + AUDIO_DDB (printk ("ad1848 detect error - step D (%x)\n", tmp1)); return 0; } /* - * NOTE! Last 4 bits of the reg I12 tell the chip revision. - * 0x01=RevB and 0x0A=RevC. - */ + * NOTE! Last 4 bits of the reg I12 tell the chip revision. + * 0x01=RevB and 0x0A=RevC. + */ /* - * The original AD1848/CS4248 has just 15 indirect registers. This means - * that I0 and I16 should return the same value (etc.). - * Ensure that the Mode2 enable bit of I12 is 0. Otherwise this test fails - * with CS4231. - */ + * The original AD1848/CS4248 has just 15 indirect registers. This means + * that I0 and I16 should return the same value (etc.). + * Ensure that the Mode2 enable bit of I12 is 0. Otherwise this test fails + * with CS4231. + */ ad_write (devc, 12, 0); /* Mode2=disabled */ for (i = 0; i < 16; i++) if ((tmp1 = ad_read (devc, i)) != (tmp2 = ad_read (devc, i + 16))) { - AUDIO_DDB (printk ("ad_detect_F(%d/%x/%x)\n", i, tmp1, tmp2)); + AUDIO_DDB (printk ("ad1848 detect error - step F(%d/%x/%x)\n", i, tmp1, tmp2)); return 0; } /* - * Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit (0x40). - * The bit 0x80 is always 1 in CS4248 and CS4231. - */ + * Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit (0x40). + * The bit 0x80 is always 1 in CS4248 and CS4231. + */ ad_write (devc, 12, 0x40); /* Set mode2, clear 0x80 */ tmp1 = ad_read (devc, 12); if (tmp1 & 0x80) - devc->chip_name = "CS4248"; + devc->chip_name = "CS4248"; /* Our best knowledge just now */ if ((tmp1 & 0xc0) == (0x80 | 0x40)) { /* - * CS4231 detected - is it? - * - * Verify that setting I0 doesn't change I16. - */ + * CS4231 detected - is it? + * + * Verify that setting I0 doesn't change I16. + */ ad_write (devc, 16, 0); /* Set I16 to known value */ ad_write (devc, 0, 0x45); @@ -782,16 +1103,32 @@ ad1848_detect (int io_base) ad_write (devc, 0, 0xaa); if ((tmp1 = ad_read (devc, 16)) == 0xaa) /* Rotten bits? */ { - AUDIO_DDB (printk ("ad_detect_H(%x)\n", tmp1)); + AUDIO_DDB (printk ("ad1848 detect error - step H(%x)\n", tmp1)); return 0; } /* - * It's a CS4231 - So what! - * (Mode2 will be supported later) - */ - devc->chip_name = "CS4231"; - devc->mode = 2; + * Verify that some bits of I25 are read only. + */ + + tmp1 = ad_read (devc, 25); /* Original bits */ + ad_write (devc, 25, ~tmp1); /* Invert all bits */ + if ((ad_read (devc, 25) & 0xe7) == (tmp1 & 0xe7)) + { + /* + * It's a CS4231 + */ + devc->chip_name = "CS4231"; + + +#ifdef MOZART_PORT + if (devc->base != MOZART_PORT) +#endif + devc->mode = 2; + + + } + ad_write (devc, 25, tmp1); /* Restore bits */ } } @@ -802,18 +1139,22 @@ void ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture) { /* - * NOTE! If irq < 0, there is another driver which has allocated the IRQ - * so that this driver doesn't need to allocate/deallocate it. - * The actually used IRQ is ABS(irq). - */ + * NOTE! If irq < 0, there is another driver which has allocated the IRQ + * so that this driver doesn't need to allocate/deallocate it. + * The actually used IRQ is ABS(irq). + */ /* - * Initial values for the indirect registers of CS4248/AD1848. - */ + * Initial values for the indirect registers of CS4248/AD1848. + */ static int init_values[] = { - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, - 0x00, 0x08, 0x02, 0x00, 0xca, 0x00, 0x00, 0x00 + 0xa8, 0xa8, 0x08, 0x08, 0x08, 0x08, 0x80, 0x80, + 0x00, 0x08, 0x02, 0x00, 0x8a, 0x01, 0x00, 0x00, + + /* Positions 16 to 31 just for CS4231 */ + 0x80, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; int i, my_dev; ad1848_info *devc = &dev_info[nr_ad1848_devs]; @@ -836,15 +1177,29 @@ ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture for (i = 0; i < 16; i++) ad_write (devc, i, init_values[i]); + ad_mute (devc); + + if (devc->mode == 2) + { + ad_write (devc, 12, ad_read (devc, 12) | 0x40); /* Mode2 = enabled */ + for (i = 16; i < 32; i++) + ad_write (devc, i, init_values[i]); + } + OUTB (0, io_Status (devc)); /* Clear pending interrupts */ -#ifndef SCO - sprintf (ad1848_pcm_operations[nr_ad1848_devs].name, - "%s (%s)", name, devc->chip_name); -#endif + if (name[0] != 0) + sprintf (ad1848_pcm_operations[nr_ad1848_devs].name, + "%s (%s)", name, devc->chip_name); + else + sprintf (ad1848_pcm_operations[nr_ad1848_devs].name, + "Generic audio codec (%s)", devc->chip_name); - if (irq > 0) - printk (" <%s>", ad1848_pcm_operations[nr_ad1848_devs].name); +#if defined(__FreeBSD__) + printk ("gus0: <%s>\n", ad1848_pcm_operations[nr_ad1848_devs].name); +#else + printk (" <%s>", ad1848_pcm_operations[nr_ad1848_devs].name); +#endif if (num_audiodevs < MAX_AUDIO_DEV) { @@ -860,13 +1215,28 @@ ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture audio_devs[my_dev]->devc = devc; audio_devs[my_dev]->format_mask = ad_format_mask[devc->mode]; nr_ad1848_devs++; + + /* + * Toggle the MCE bit. It completes the initialization phase. + */ + + ad_enter_MCE (devc); /* In case the bit was off */ + ad_leave_MCE (devc); + + if (num_mixers < MAX_MIXER_DEV) + { + mixer2codec[num_mixers] = my_dev + 1; + audio_devs[my_dev]->mixer_dev = num_mixers; + mixer_devs[num_mixers++] = &ad1848_mixer_operations; + ad1848_mixer_reset (devc); + } } else printk ("AD1848: Too many PCM devices available\n"); } void -adintr (int irq) +ad1848_interrupt (INT_HANDLER_PARMS (irq, dummy)) { unsigned char status; ad1848_info *devc; @@ -881,6 +1251,9 @@ adintr (int irq) devc = (ad1848_info *) audio_devs[dev]->devc; status = INB (io_Status (devc)); + if (status == 0x80) + printk ("ad1848_interrupt: Why?\n"); + if (status & 0x01) { if (devc->opened && devc->irq_mode == IMODE_OUTPUT) @@ -893,25 +1266,167 @@ adintr (int irq) } OUTB (0, io_Status (devc)); /* Clear interrupt status */ + + status = INB (io_Status (devc)); + if (status == 0x80 || status & 0x01) + { + printk ("ad1848: Problems when clearing interrupt, status=%x\n", status); + OUTB (0, io_Status (devc)); /* Try again */ + } +} + +#ifdef MOZART_PORT +/* + * Experimental initialization sequence for Mozart soundcard + * (OAK OTI-601 sound chip). + * by Gregor Hoffleit <flight@mathi.uni-heidelberg.de> + * Some comments by Hannu Savolainen. + */ + +int +mozart_init (int io_base) +{ + int i; + unsigned char byte; + static int mozart_detected_here = 0; + + /* + * Valid ports are 0x530 and 0xf40. The DOS based software doesn't allow + * other ports. The OTI-601 preliminary specification says that + * 0xe80 and 0x604 are also possible but it's safest to ignore them. + */ + + if ((io_base != 0x530) && (io_base != 0xf40)) + { + printk ("Mozart: invalid io_base(%x)\n", io_base); + return 0; + } + + if (mozart_detected_here == io_base) /* Already detected this card */ + return 1; + + if (mozart_detected_here != 0) + return 0; /* Don't allow detecting another Mozart card. */ + + /* + * The Mozart chip (OAK OTI-601) must be enabled before _each_ write + * by writing a secret password (0xE2) to the password register (0xf8f). + * Any I/O cycle after writing the password closes the gate and disbles + * further access. + */ + + if (INB (0xf88) != 0) /* Appears to return 0 while the gate is closed */ + { + AUDIO_DDB (printk ("No Mozart signature detected on port 0xf88\n")); + return 0; + } + + OUTB (0xe2, 0xf8f); /* A secret password which opens the gate */ + OUTB (0x10, 0xf91); /* Enable access to codec registers during SB mode */ + for (i = 0; i < 100; i++) /* Delay */ + tenmicrosec (); + OUTB (0xe2, 0xf8f); /* Sesam */ + byte = INB (0xf8d); /* Read MC1 (Mode control register) */ + + /* Read the same register again but with gate closed at this time. */ + if (INB (0xf8d) == 0xff) /* Bus float. Should be 0 if Mozart present */ + { + AUDIO_DDB (printk ("Seems to be no Mozart chip set\n")); + return 0; + } + AUDIO_DDB (printk ("mozart_init: read 0x%x on 0xf8d\n", byte)); + byte = byte | 0x80; /* Switch to WSS mode (disables SB) */ + byte = byte & 0xcf; /* Clear sound base, disable CD, enable joystick */ + + if (io_base == 0xf40) + byte = byte | 0x20; + for (i = 0; i < 100; i++) + tenmicrosec (); + OUTB (0xe2, 0xf8f); /* Open the gate again */ + OUTB (byte, 0xf8d); /* Write the modified value back to MC1 */ + AUDIO_DDB (printk ("mozart_init: wrote 0x%x on 0xf8d\n", byte)); + OUTB (0xe2, 0xf8f); /* Here we come again */ + OUTB (0x20, 0xf91); /* Protect WSS shadow registers against write */ + + for (i = 0; i < 1000; i++) + tenmicrosec (); + + return 1; } +#endif /* MOZART_PORT */ + +#ifdef OPTI_MAD16_PORT +#include "mad16.h" #endif + /* * Some extra code for the MS Sound System */ -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MSS) int probe_ms_sound (struct address_info *hw_config) { - if ((INB (hw_config->io_base + 3) & 0x04) == 0) - return 0; /* WSS ID test failed */ +#if !defined(EXCLUDE_AEDSP16) && defined(AEDSP16_MSS) + /* + * Initialize Audio Excel DSP 16 to MSS: before any operation + * we must enable MSS I/O ports. + */ + + InitAEDSP16_MSS (hw_config); +#endif + + /* + * Check if the IO port returns valid signature. The original MS Sound + * system returns 0x04 while some cards (AudioTriX Pro for example) + * return 0x00. + */ + +#ifdef MOZART_PORT + if (hw_config->io_base == MOZART_PORT) + mozart_init (hw_config->io_base); +#endif + +#ifdef OPTI_MAD16_PORT + if (hw_config->io_base == OPTI_MAD16_PORT) + mad16init (hw_config->io_base); +#endif + + if ((INB (hw_config->io_base + 3) & 0x3f) != 0x04 && + (INB (hw_config->io_base + 3) & 0x3f) != 0x00) + { + AUDIO_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) - return 0; + { + printk ("MSS: Bad IRQ %d\n", hw_config->irq); + return 0; + } if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) - return 0; + { + printk ("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 ("MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq); + return 0; + } return ad1848_detect (hw_config->io_base + 4); } @@ -919,11 +1434,16 @@ probe_ms_sound (struct address_info *hw_config) long attach_ms_sound (long mem_start, struct address_info *hw_config) { - static unsigned char interrupt_bits[12] = - {-1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20}; + static char interrupt_bits[12] = + { + -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20 + }; char bits; - static unsigned char dma_bits[4] = {1, 2, 0, 3}; + static char dma_bits[4] = + { + 1, 2, 0, 3 + }; int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3; @@ -931,20 +1451,20 @@ attach_ms_sound (long mem_start, struct address_info *hw_config) return mem_start; /* - * Set the IRQ and DMA addresses. - */ + * Set the IRQ and DMA addresses. + */ bits = interrupt_bits[hw_config->irq]; if (bits == -1) return mem_start; - OUTB (bits | 0x40, config_port); /* Verify IRQ (I guess) */ + OUTB (bits | 0x40, config_port); if ((INB (version_port) & 0x40) == 0) - printk ("[IRQ?]"); + printk ("[IRQ Conflict?]"); OUTB (bits | dma_bits[hw_config->dma], config_port); /* Write IRQ+DMA setup */ - ad1848_init ("mss0: <MS Sound System>", hw_config->io_base + 4, + ad1848_init ("MS Sound System", hw_config->io_base + 4, hw_config->irq, hw_config->dma, hw_config->dma); diff --git a/sys/i386/isa/sound/ad1848_mixer.h b/sys/i386/isa/sound/ad1848_mixer.h new file mode 100644 index 0000000..9404047 --- /dev/null +++ b/sys/i386/isa/sound/ad1848_mixer.h @@ -0,0 +1,130 @@ +/* + * sound/ad1848_mixer.h + * + * Definitions for the mixer of AD1848 and compatible codecs. + * + * Copyright by Hannu Savolainen 1994 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * The AD1848 codec has generic input lines called Line, Aux1 and Aux2. + * Soundcard manufacturers have connected actual inputs (CD, synth, line, + * etc) to these inputs in different order. Therefore it's difficult + * to assign mixer channels to to these inputs correctly. The following + * contains two alternative mappings. The first one is for GUS MAX and + * the second is just a generic one (line1, line2 and line3). + * (Actually this is not a mapping but rather some kind of interleaving + * solution). + */ +#ifdef GUSMAX_MIXER +#define MODE1_REC_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | \ + SOUND_MASK_CD) + +#define MODE1_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_MIC | \ + SOUND_MASK_CD | \ + SOUND_MASK_IGAIN | \ + SOUND_MASK_PCM|SOUND_MASK_IMIX) + +#define MODE2_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \ + SOUND_MASK_CD | SOUND_MASK_SPEAKER | \ + SOUND_MASK_IGAIN | \ + SOUND_MASK_PCM | SOUND_MASK_IMIX) +#else /* Generic mapping */ +#define MODE1_REC_DEVICES (SOUND_MASK_LINE3 | SOUND_MASK_MIC | \ + SOUND_MASK_LINE1) + +#define MODE1_MIXER_DEVICES (SOUND_MASK_LINE1 | SOUND_MASK_MIC | \ + SOUND_MASK_LINE2 | \ + SOUND_MASK_IGAIN | \ + SOUND_MASK_PCM | SOUND_MASK_IMIX) + +#define MODE2_MIXER_DEVICES (SOUND_MASK_LINE1 | SOUND_MASK_LINE2 | SOUND_MASK_MIC | \ + SOUND_MASK_LINE3 | SOUND_MASK_SPEAKER | \ + SOUND_MASK_IGAIN | \ + SOUND_MASK_PCM | SOUND_MASK_IMIX) +#endif + +struct mixer_def { + unsigned int regno: 7; + unsigned int polarity:1; /* 0=normal, 1=reversed */ + unsigned int bitpos:4; + unsigned int nbits:4; +}; + + +typedef struct mixer_def mixer_ent; + +/* + * Most of the mixer entries work in backwards. Setting the polarity field + * makes them to work correctly. + * + * The channel numbering used by individual soundcards is not fixed. Some + * cards have assigned different meanings for the AUX1, AUX2 and LINE inputs. + * The current version doesn't try to compensate this. + */ + +#define MIX_ENT(name, reg_l, pola_l, pos_l, len_l, reg_r, pola_r, pos_r, len_r) \ + {{reg_l, pola_l, pos_r, len_l}, {reg_r, pola_r, pos_r, len_r}} + +mixer_ent mix_devices[32][2] = { /* As used in GUS MAX */ +MIX_ENT(SOUND_MIXER_VOLUME, 0, 0, 0, 0, 0, 0, 0, 0), +MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0), +MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0), +MIX_ENT(SOUND_MIXER_SYNTH, 4, 1, 0, 5, 5, 1, 0, 5), +MIX_ENT(SOUND_MIXER_PCM, 6, 1, 0, 6, 7, 1, 0, 6), +MIX_ENT(SOUND_MIXER_SPEAKER, 26, 1, 0, 4, 0, 0, 0, 0), +MIX_ENT(SOUND_MIXER_LINE, 18, 1, 0, 5, 19, 1, 0, 5), +MIX_ENT(SOUND_MIXER_MIC, 0, 1, 5, 1, 1, 1, 5, 1), +MIX_ENT(SOUND_MIXER_CD, 2, 1, 0, 5, 3, 1, 0, 5), +MIX_ENT(SOUND_MIXER_IMIX, 13, 1, 2, 6, 0, 0, 0, 0), +MIX_ENT(SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0), +MIX_ENT(SOUND_MIXER_RECLEV, 0, 0, 0, 0, 0, 0, 0, 0), +MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 4, 1, 0, 0, 4), +MIX_ENT(SOUND_MIXER_OGAIN, 0, 0, 0, 0, 0, 0, 0, 0), +MIX_ENT(SOUND_MIXER_LINE1, 2, 1, 0, 5, 3, 1, 0, 5), +MIX_ENT(SOUND_MIXER_LINE2, 4, 1, 0, 5, 5, 1, 0, 5), +MIX_ENT(SOUND_MIXER_LINE3, 18, 1, 0, 5, 19, 1, 0, 5) +}; + +static unsigned short default_mixer_levels[SOUND_MIXER_NRDEVICES] = +{ + 0x5a5a, /* Master Volume */ + 0x3232, /* Bass */ + 0x3232, /* Treble */ + 0x4b4b, /* FM */ + 0x6464, /* PCM */ + 0x4b4b, /* PC Speaker */ + 0x4b4b, /* Ext Line */ + 0x1010, /* Mic */ + 0x4b4b, /* CD */ + 0x0000, /* Recording monitor */ + 0x4b4b, /* SB PCM */ + 0x4b4b, /* Recording level */ + 0x4b4b, /* Input gain */ + 0x4b4b, /* Output gain */ + 0x4b4b, /* Line1 */ + 0x4b4b, /* Line2 */ + 0x4b4b /* Line3 */ +}; + +#define LEFT_CHN 0 +#define RIGHT_CHN 1 diff --git a/sys/i386/isa/sound/adlib_card.c b/sys/i386/isa/sound/adlib_card.c index ec3810b..6365069 100644 --- a/sys/i386/isa/sound/adlib_card.c +++ b/sys/i386/isa/sound/adlib_card.c @@ -25,7 +25,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * ad1848.c,v 1.3 1994/10/01 05:46:01 davidg Exp */ #include "sound_config.h" diff --git a/sys/i386/isa/sound/aedsp16.c b/sys/i386/isa/sound/aedsp16.c new file mode 100644 index 0000000..b14a246 --- /dev/null +++ b/sys/i386/isa/sound/aedsp16.c @@ -0,0 +1,838 @@ +/* + sound/aedsp16.c + + Audio Excel DSP 16 software configuration routines + + Copyright (C) 1995 Riccardo Facchetti (riccardo@cdc8g5.cdc.polimi.it) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. 2. + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + READ THIS + + This module is intended for Audio Excel DSP 16 Sound Card. + + Audio Excel DSP 16 is an SB pro II, Microsoft Sound System + and MPU-401 compatible card. + It is software-only configurable (no jumpers to hard-set irq/dma/mpu-irq), + so before this module, the only way to configure the DSP under linux was + boot the MS-BAU loading the sound.sys device driver (this driver soft- + configure the sound board hardware by massaging someone of its registers), + and then ctrl-alt-del to boot linux with the DSP configured by the DOG + driver. + + This module works configuring your Audio Excel DSP 16's + irq, dma and mpu-401-irq. The voxware probe routines rely on the + fact that if the hardware is there, they can detect it. The problem + with AEDSP16 is that no hardware can be found by the probe routines + if the sound card is not well configured. Sometimes the kernel probe + routines can find an SBPRO even when the card is not configured (this + is the standard setup of the card), but the SBPRO emulation don't work + well if the card is not properly initialized. For this reason + + InitAEDSP16_...() + + routines are called before the voxware probe routines try to detect the + hardware. + + NOTE (READ THE NOTE TOO, IT CONTAIN USEFUL INFORMATIONS) + + The Audio Excel DSP 16 Sound Card emulates both SBPRO and MSS; + the voxware sound driver can be configured for SBPRO and MSS cards + at the same time, but the aedsp16 can't be two cards!! + When we configure it, we have to choose the SBPRO or the MSS emulation + for AEDSP16. We also can install a *REAL* card of the other type + (see [1], not tested but I can't see any reason for it to fail). + + NOTE: If someone can test the combination AEDSP16+MSS or AEDSP16+SBPRO + please let me know if it works. + + The MPU-401 support can be compiled in together with one of the other + two operating modes. + + The board configuration calls, are in the probe_...() routines because + we have to configure the board before probing it for a particular + hardware. After card configuration, we can probe the hardware. + + NOTE: This is something like plug-and-play: we have only to plug + the AEDSP16 board in the socket, and then configure and compile + a kernel that uses the AEDSP16 software configuration capability. + No jumper setting is needed! + + For example, if you want AEDSP16 to be an SBPro, on irq 10, dma 3 + you have just to make config the voxware package, configuring + the SBPro sound card with that parameters, then when configure + asks if you have an AEDSP16, answer yes. That's it. + Compile the kernel and run it. + + NOTE: This means that you can choose irq and dma, but not the + I/O addresses. To change I/O addresses you have to set them + with jumpers. + + NOTE: InitAEDSP16_...() routines get as parameter the hw_config, + the hardware configuration of the - to be configured - board. + The InitAEDSP16() routine, configure the board following our + wishes, that are in the hw_config structure. + + You can change the irq/dma/mirq settings WITHOUT THE NEED to open + your computer and massage the jumpers (there are no irq/dma/mirq + jumpers to be configured anyway, only I/O port ones have to be + configured with jumpers) + + For some ununderstandable reason, the card default of irq 7, dma 1, + don't work for me. Seems to be an IRQ or DMA conflict. Under heavy + HDD work, the kernel start to erupt out a lot of messages like: + + 'Sound: DMA timed out - IRQ/DRQ config error?' + + For what I can say, I have NOT any conflict at irq 7 (under linux I'm + using the lp polling driver), and dma line 1 is unused as stated by + /proc/dma. I can suppose this is a bug of AEDSP16. I know my hardware so + I'm pretty sure I have not any conflict, but may be I'm wrong. Who knows! + Anyway a setting of irq 10, dma 3 works really fine. + + NOTE: if someone can use AEDSP16 with irq 7, dma 1, please let me know + the emulation mode, all the installed hardware and the hardware + configuration (irq and dma settings of all the hardware). + + This init module should work with SBPRO+MSS, when one of the two is + the AEDSP16 emulation and the other the real card. (see [1]) + For example: + + AEDSP16 (0x220) in SBPRO emu (0x220) + real MSS + other + AEDSP16 (0x220) in MSS emu + real SBPRO (0x240) + other + + MPU401 should work. (see [1]) + + [1] Not tested by me for lack of hardware. + + TODO, WISHES AND TECH + + May be there's lot of redundant delays, but for now I want to leave it + this way. + + Should be interesting eventually write down a new ioctl for the + aedsp16, to let the suser() change the irq/dma/mirq on the fly. + The thing is not trivial. + In the real world, there's no need to have such an ioctl because + when we configure the kernel for compile, we can choose the config + parameters. If we change our mind, we can easily re-config the kernel + and re-compile. + Why let the suser() change the config parameters on the fly ? + If anyone have a reasonable answer to this question, I will write down + the code to do it. + + More integration with voxware, using voxware low level routines to + read-write dsp is not possible because you may want to have MSS + support and in that case we can not rely on the functions included + in sb_dsp.c to control 0x2yy I/O ports. I will continue to use my + own I/O functions. + + - About I/O ports allocation - + + The request_region should be done at device probe in every sound card + module. This module is not the best site for requesting regions. + When the request_region code will be added to the main modules such as + sb, adlib, gus, ad1848, etc, the requesting code in this module should + go away. + + I think the request regions should be done this way: + + if (check_region(...)) + return ERR; // I/O region alredy reserved + device_probe(...); + device_attach(...); + request_region(...); // reserve only when we are sure all is okay + + Request the 2x0h region in any case if we are using this card. + + NOTE: the "(sbpro)" string with which we are requesting the aedsp16 region + (see code) does not mean necessarly that we are emulating sbpro. + It mean that the region is the sbpro I/O ports region. We use this + region to access the control registers of the card, and if emulating + sbpro, I/O sbpro registers too. If we are emulating MSS, the sbpro + registers are not used, in no way, to emulate an sbpro: they are + used only for configuration pourposes. + + Someone pointed out that should be possible use both the SBPRO and MSS + modes because the sound card have all the two chipsets, supposing that + the card is really two cards. I have tried something to have the two + modes work together, but, for some reason unknown to me, without success. + + I think all the soft-config only cards have an init sequence similar to + this. If you have a card that is not an aedsp16, you can try to start + with this module changing it (mainly in the CMD? I think) to fit your + needs. + + Started Fri Mar 17 16:13:18 MET 1995 + + v0.1 (ALPHA, was an user-level program called AudioExcelDSP16.c) + - Initial code. + v0.2 (ALPHA) + - Cleanups. + - Integrated with Linux voxware v 2.90-2 kernel sound driver. + - SoundBlaster Pro mode configuration. + - Microsoft Sound System mode configuration. + - MPU-401 mode configuration. + v0.3 (ALPHA) + - Cleanups. + - Rearranged the code to let InitAEDSP16 be more general. + - Erased the REALLY_SLOW_IO. We don't need it. Erased the linux/io.h + inclusion too. We rely on os.h + - Used the INB and OUTB #defined in os.h instead of inb and outb. + - Corrected the code for GetCardName (DSP Copyright) to get a variable + len string (we are not sure about the len of Copyright string). + This works with any SB and compatible. + - Added the code to request_region at device init (should go in + the main body of voxware). + v0.4 (BETA) + - Better configure.c patch for aedsp16 configuration (better + logic of inclusion of AEDSP16 support) + - Modified the conditional compilation to better support more than + one sound card of the emulated type (read the NOTES above) + - Moved the sb init routine from the attach to the very first + probe in sb_card.c + - Rearrangemens and cleanups + - Wiped out some unnecessary code and variables: this is kernel + code so it is better save some TEXT and DATA + - Fixed the request_region code. We must allocate the aedsp16 (sbpro) + I/O ports in any case because they are used to access the DSP + configuration registers and we can not allow anyone to get them. + v0.5 + - cleanups on comments + - prep for diffs against v3.0-proto-950402 + + */ + +/* + * Include the main voxware header file. It include all the os/voxware/etc + * headers needed by this source. + */ +#include "sound_config.h" +/* + * all but ioport.h :) + */ +#include <linux/ioport.h> + +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AEDSP16) + +#define VERSION "0.5" /* Version of Audio Excel DSP 16 driver */ + +#undef AEDSP16_DEBUG /* Define this to enable debug code */ +/* Actually no debug code is activated */ + +/* + * Hardware related defaults + */ +#define IRQ 7 /* 5 7(default) 9 10 11 */ +#define MIRQ 0 /* 5 7 9 10 0(default), 0 means disable */ +#define DMA 1 /* 0 1(default) 3 */ + +/* + * Commands of AEDSP16's DSP (SBPRO+special). + * For now they are CMDn, in the future they may change. + */ +#define CMD1 0xe3 /* Get DSP Copyright */ +#define CMD2 0xe1 /* Get DSP Version */ +#define CMD3 0x88 /* */ +#define CMD4 0x5c /* */ +#define CMD5 0x50 /* Set M&I&DRQ mask (the real config) */ +#define CMD6 0x8c /* Enable Microsoft Sound System mode */ + +/* + * Offsets of AEDSP16 DSP I/O ports. The offest is added to portbase + * to have the actual I/O port. + * Register permissions are: + * (wo) == Write Only + * (ro) == Read Only + * (w-) == Write + * (r-) == Read + */ +#define DSP_RESET 0x06 /* offset of DSP RESET (wo) */ +#define DSP_READ 0x0a /* offset of DSP READ (ro) */ +#define DSP_WRITE 0x0c /* offset of DSP WRITE (w-) */ +#define DSP_COMMAND 0x0c /* offset of DSP COMMAND (w-) */ +#define DSP_STATUS 0x0c /* offset of DSP STATUS (r-) */ +#define DSP_DATAVAIL 0x0e /* offset of DSP DATA AVAILABLE (ro) */ + + +#define RETRY 10 /* Various retry values on I/O opera- */ +#define STATUSRETRY 1000 /* tions. Sometimes we have to */ +#define HARDRETRY 500000 /* wait for previous cmd to complete */ + +/* + * Size of character arrays that store name and version of sound card + */ +#define CARDNAMELEN 15 /* Size of the card's name in chars */ +#define CARDVERLEN 2 /* Size of the card's version in chars */ + +/* + * Bit mapped flags for calling InitAEDSP16(), and saving the current + * emulation mode. + */ +#define INIT_NONE (0 ) +#define INIT_SBPRO (1<<0) +#define INIT_MSS (1<<1) +#define INIT_MPU401 (1<<2) +#define RESET_DSP16 (1<<3) + +/* Base HW Port for Audio Card */ +static int portbase = AEDSP16_BASE; +static int irq = IRQ; /* irq for DSP I/O */ +static int mirq = MIRQ; /* irq for MPU-401 I/O */ +static int dma = DMA; /* dma for DSP I/O */ + +/* Init status of the card */ +static int ae_init = INIT_NONE; /* (bitmapped variable) */ +static int oredparams = 0; /* Will contain or'ed values of params */ +static int gc = 0; /* generic counter (utility counter) */ +struct orVals + { /* Contain the values to be or'ed */ + int val; /* irq|mirq|dma */ + int or; /* oredparams |= TheStruct.or */ + }; + +/* + * Magic values that the DSP will eat when configuring irq/mirq/dma + */ +/* DSP IRQ conversion array */ +static struct orVals orIRQ[] = +{ + {0x05, 0x28}, + {0x07, 0x08}, + {0x09, 0x10}, + {0x0a, 0x18}, + {0x0b, 0x20}, + {0x00, 0x00} +}; + +/* MPU-401 IRQ conversion array */ +static struct orVals orMIRQ[] = +{ + {0x05, 0x04}, + {0x07, 0x44}, + {0x09, 0x84}, + {0x0a, 0xc4}, + {0x00, 0x00} +}; + +/* DMA Channels conversion array */ +static struct orVals orDMA[] = +{ + {0x00, 0x01}, + {0x01, 0x02}, + {0x03, 0x03}, + {0x00, 0x00} +}; + +/* + * Buffers to store audio card informations + */ +static char AudioExcelName[CARDNAMELEN + 1]; +static char AudioExcelVersion[CARDVERLEN + 1]; + +static void +tenmillisec (void) +{ + + for (gc = 0; gc < 1000; gc++) + tenmicrosec (); +} + +static int +WaitForDataAvail (int port) +{ + int loop = STATUSRETRY; + unsigned char ret = 0; + + do + { + ret = INB (port + DSP_DATAVAIL); + /* + * Wait for data available (bit 7 of ret == 1) + */ + } + while (!(ret & 0x80) && loop--); + + if (ret & 0x80) + return 0; + + return -1; +} + +static int +ReadData (int port) +{ + if (WaitForDataAvail (port)) + return -1; + return INB (port + DSP_READ); +} + +static int +CheckDSPOkay (int port) +{ + return ((ReadData (port) == 0xaa) ? 0 : -1); +} + +static int +ResetBoard (int port) +{ + /* + * Reset DSP + */ + OUTB (1, (port + DSP_RESET)); + tenmicrosec (); + OUTB (0, (port + DSP_RESET)); + tenmicrosec (); + tenmicrosec (); + return CheckDSPOkay (port); +} + +static int +WriteDSPCommand (int port, int cmd) +{ + unsigned char ret; + int loop = HARDRETRY; + + do + { + ret = INB (port + DSP_STATUS); + /* + * DSP ready to receive data if bit 7 of ret == 0 + */ + if (!(ret & 0x80)) + { + OUTB (cmd, port + DSP_COMMAND); + return 0; + } + } + while (loop--); + + printk ("[aedsp16] DSP Command (0x%x) timeout.\n", cmd); + return -1; +} + +int +InitMSS (int port) +{ + + tenmillisec (); + + if (WriteDSPCommand (port, CMD6)) + { + printk ("[aedsp16] CMD 0x%x: failed!\n", CMD6); + return -1; + } + + tenmillisec (); + + return 0; +} + +static int +SetUpBoard (int port) +{ + int loop = RETRY; + + do + { + if (WriteDSPCommand (portbase, CMD3)) + { + printk ("[aedsp16] CMD 0x%x: failed!\n", CMD3); + return -1; + } + + tenmillisec (); + + } + while (WaitForDataAvail (port) && loop--); + +#if defined(THIS_SHOULD_GO_AWAY) + if (CheckDSPOkay (port)) + { + printk ("[aedsp16] CheckDSPOkay: failed\n"); + return -1; + } +#else + if (ReadData (port) == -1) + { + printk ("[aedsp16] ReadData after CMD 0x%x: failed\n", CMD3); + return -1; + } +#endif + + if (WriteDSPCommand (portbase, CMD4)) + { + printk ("[aedsp16] CMD 0x%x: failed!\n", CMD4); + return -1; + } + + if (WriteDSPCommand (portbase, CMD5)) + { + printk ("[aedsp16] CMD 0x%x: failed!\n", CMD5); + return -1; + } + + if (WriteDSPCommand (portbase, oredparams)) + { + printk ("[aedsp16] Initialization of (M)IRQ and DMA: failed!\n"); + return -1; + } + return 0; +} + +static int +GetCardVersion (int port) +{ + int len = 0; + int ret; + int ver[3]; + + do + { + if ((ret = ReadData (port)) == -1) + return -1; + /* + * We alredy know how many int are stored (2), so we know when the + * string is finished. + */ + ver[len++] = ret; + } + while (len < CARDVERLEN); + sprintf (AudioExcelVersion, "%d.%d", ver[0], ver[1]); + return 0; +} + +static int +GetCardName (int port) +{ + int len = 0; + int ret; + + do + { + if ((ret = ReadData (port)) == -1) + /* + * If no more data availabe, return to the caller, no error if len>0. + * We have no other way to know when the string is finished. + */ + return (len ? 0 : -1); + + AudioExcelName[len++] = ret; + + } + while (len < CARDNAMELEN); + return 0; +} + +static void +InitializeHardParams (void) +{ + + memset (AudioExcelName, 0, CARDNAMELEN + 1); + memset (AudioExcelVersion, 0, CARDVERLEN + 1); + + for (gc = 0; orIRQ[gc].or; gc++) + if (orIRQ[gc].val == irq) + oredparams |= orIRQ[gc].or; + + for (gc = 0; orMIRQ[gc].or; gc++) + if (orMIRQ[gc].or == mirq) + oredparams |= orMIRQ[gc].or; + + for (gc = 0; orDMA[gc].or; gc++) + if (orDMA[gc].val == dma) + oredparams |= orDMA[gc].or; +} + +static int +InitAEDSP16 (int which) +{ + static char *InitName = NULL; + + InitializeHardParams (); + + if (ResetBoard (portbase)) + { + printk ("[aedsp16] ResetBoard: failed!\n"); + return -1; + } + +#if defined(THIS_SHOULD_GO_AWAY) + if (CheckDSPOkay (portbase)) + { + printk ("[aedsp16] CheckDSPOkay: failed!\n"); + return -1; + } +#endif + + if (WriteDSPCommand (portbase, CMD1)) + { + printk ("[aedsp16] CMD 0x%x: failed!\n", CMD1); + return -1; + } + + if (GetCardName (portbase)) + { + printk ("[aedsp16] GetCardName: failed!\n"); + return -1; + } + + /* + * My AEDSP16 card return SC-6000 in AudioExcelName, so + * if we have something different, we have to be warned. + */ + if (strcmp ("SC-6000", AudioExcelName)) + printk ("[aedsp16] Warning: non SC-6000 audio card!\n"); + + if (WriteDSPCommand (portbase, CMD2)) + { + printk ("[aedsp16] CMD 0x%x: failed!\n", CMD2); + return -1; + } + + if (GetCardVersion (portbase)) + { + printk ("[aedsp16] GetCardVersion: failed!\n"); + return -1; + } + + if (SetUpBoard (portbase)) + { + printk ("[aedsp16] SetUpBoard: failed!\n"); + return -1; + } + + if (which == INIT_MSS) + { + if (InitMSS (portbase)) + { + printk ("[aedsp16] Can't initialize Microsoft Sound System mode.\n"); + return -1; + } + } + + /* + * If we are resetting, do not print any message because we may be + * in playing and we do not want lost too much time. + */ + if (!(which & RESET_DSP16)) + { + if (which & INIT_MPU401) + InitName = "MPU401"; + else if (which & INIT_SBPRO) + InitName = "SBPro"; + else if (which & INIT_MSS) + InitName = "MSS"; + else + InitName = "None"; + + printk ("Audio Excel DSP 16 init v%s (%s %s) [%s]\n", + VERSION, AudioExcelName, + AudioExcelVersion, InitName); + } + + tenmillisec (); + + return 0; +} + +#if defined(AEDSP16_SBPRO) + +int +InitAEDSP16_SBPRO (struct address_info *hw_config) +{ + /* + * If the card is alredy init'ed MSS, we can not init it to SBPRO too + * because the board can not emulate simultaneously MSS and SBPRO. + */ + if (ae_init & INIT_MSS) + return -1; + if (ae_init & INIT_SBPRO) + return 0; + + /* + * For now we will leave this + * code included only when INCLUDE_AEDSP16 is configured in, but it should + * be better include it every time. + */ + if (!(ae_init & INIT_MPU401)) + { + if (check_region (hw_config->io_base, 0x0f)) + { + printk ("AEDSP16/SBPRO I/O port region is alredy in use.\n"); + return -1; + } + } + + /* + * Set up the internal hardware parameters, to let the driver reach + * the Sound Card. + */ + portbase = hw_config->io_base; + irq = hw_config->irq; + dma = hw_config->dma; + if (InitAEDSP16 (INIT_SBPRO)) + return -1; + + if (!(ae_init & INIT_MPU401)) + request_region (hw_config->io_base, 0x0f, "aedsp16 (sbpro)"); + + ae_init |= INIT_SBPRO; + return 0; +} + +#endif /* AEDSP16_SBPRO */ + +#if defined(AEDSP16_MSS) + +int +InitAEDSP16_MSS (struct address_info *hw_config) +{ + /* + * If the card is alredy init'ed SBPRO, we can not init it to MSS too + * because the board can not emulate simultaneously MSS and SBPRO. + */ + if (ae_init & INIT_SBPRO) + return -1; + if (ae_init & INIT_MSS) + return 0; + + /* + * For now we will leave this + * code included only when INCLUDE_AEDSP16 is configured in, but it should + * be better include it every time. + */ + if (check_region (hw_config->io_base, 0x08)) + { + printk ("MSS I/O port region is alredy in use.\n"); + return -1; + } + + /* + * We must allocate the AEDSP16 region too because these are the I/O ports + * to access card's control registers. + */ + if (!(ae_init & INIT_MPU401)) + { + if (check_region (AEDSP16_BASE, 0x0f)) + { + printk ("AEDSP16 I/O port region is alredy in use.\n"); + return -1; + } + } + + + /* + * If we are configuring the card for MSS, the portbase for card configuration + * is the default one (0x220 unless you have changed the factory default + * with board switches), so no need to modify the portbase variable. + * The default is AEDSP16_BASE, that is the right value. + */ + irq = hw_config->irq; + dma = hw_config->dma; + if (InitAEDSP16 (INIT_MSS)) + return -1; + + request_region (hw_config->io_base, 0x08, "aedsp16 (mss)"); + + if (!(ae_init & INIT_MPU401)) + request_region (AEDSP16_BASE, 0x0f, "aedsp16 (sbpro)"); + + ae_init |= INIT_MSS; + return 0; +} + +#endif /* AEDSP16_MSS */ + +#if defined(AEDSP16_MPU401) + +int +InitAEDSP16_MPU401 (struct address_info *hw_config) +{ + if (ae_init & INIT_MPU401) + return 0; + + /* + * For now we will leave this + * code included only when INCLUDE_AEDSP16 is configured in, but it should + * be better include it every time. + */ + if (check_region (hw_config->io_base, 0x02)) + { + printk ("SB I/O port region is alredy in use.\n"); + return -1; + } + + /* + * We must allocate the AEDSP16 region too because these are the I/O ports + * to access card's control registers. + */ + if (!(ae_init & (INIT_MSS | INIT_SBPRO))) + { + if (check_region (AEDSP16_BASE, 0x0f)) + { + printk ("AEDSP16 I/O port region is alredy in use.\n"); + return -1; + } + } + + /* + * If mpu401, the irq and dma are not important, do not touch it + * because we may use the default if sbpro is not yet configured, + * we may use the sbpro ones if configured, and nothing wrong + * should happen. + * + * The mirq default is 0, but once set it to non-0 value, we should + * not touch it anymore (unless I write an ioctl to do it, of course). + */ + mirq = hw_config->irq; + if (InitAEDSP16 (INIT_MPU401)) + return -1; + + request_region (hw_config->io_base, 0x02, "aedsp16 (mpu401)"); + + if (!(ae_init & (INIT_MSS | INIT_SBPRO))) + request_region (AEDSP16_BASE, 0x0f, "aedsp16 (sbpro)"); + + ae_init |= INIT_MPU401; + return 0; +} + +#endif /* AEDSP16_MPU401 */ + +#if 0 /* Leave it out for now. We are not using this portion of code. */ + +/* + * Entry point for a reset function. + * May be I will write the infamous ioctl :) + */ +int +ResetAEDSP16 (void) +{ +#if defined(AEDSP16_DEBUG) + printk ("[aedsp16] ResetAEDSP16 called.\n"); +#endif + return InitAEDSP16 (RESET_DSP16); +} + +#endif /* 0 */ + +#endif /* !EXCLUDE_AEDSP16 */ diff --git a/sys/i386/isa/sound/audio.c b/sys/i386/isa/sound/audio.c index 07d5a5b..005915b 100644 --- a/sys/i386/isa/sound/audio.c +++ b/sys/i386/isa/sound/audio.c @@ -25,7 +25,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * audio.c,v 1.6 1994/10/01 02:16:29 swallace Exp */ #include "sound_config.h" @@ -34,11 +33,13 @@ #ifndef EXCLUDE_AUDIO #include "ulaw.h" +#include "coproc.h" #define ON 1 #define OFF 0 static int wr_buff_no[MAX_AUDIO_DEV]; /* + * != -1, if there is * a incomplete output * block in the queue. @@ -46,6 +47,7 @@ static int wr_buff_no[MAX_AUDIO_DEV]; /* static int wr_buff_size[MAX_AUDIO_DEV], wr_buff_ptr[MAX_AUDIO_DEV]; static int audio_mode[MAX_AUDIO_DEV]; +static int dev_nblock[MAX_AUDIO_DEV]; /* 1 if in noblocking mode */ #define AM_NONE 0 #define AM_WRITE 1 @@ -99,6 +101,16 @@ audio_open (int dev, struct fileinfo *file) if ((ret = DMAbuf_open (dev, mode)) < 0) return ret; + if (audio_devs[dev]->coproc) + if ((ret = audio_devs[dev]->coproc-> + open (audio_devs[dev]->coproc->devc, COPR_PCM)) < 0) + { + audio_release (dev, file); + printk ("Sound: Can't access coprocessor device\n"); + + return ret; + } + local_conversion[dev] = 0; if (DMAbuf_ioctl (dev, SNDCTL_DSP_SETFMT, bits, 1) != bits) @@ -116,6 +128,8 @@ audio_open (int dev, struct fileinfo *file) wr_buff_no[dev] = -1; audio_mode[dev] = AM_NONE; + wr_buff_size[dev] = wr_buff_ptr[dev] = 0; + dev_nblock[dev] = 0; return ret; } @@ -135,6 +149,8 @@ audio_release (int dev, struct fileinfo *file) wr_buff_no[dev] = -1; } + if (audio_devs[dev]->coproc) + audio_devs[dev]->coproc->close (audio_devs[dev]->coproc->devc, COPR_PCM); DMAbuf_release (dev, mode); } @@ -156,9 +172,9 @@ translate_bytes (const void *table, void *buff, unsigned long n) "1:\tlodsb\n\t" "xlatb\n\t" "stosb\n\t" - "loop 1b\n\t": - :"b" ((long) table), "c" (n), "D" ((long) buff), "S" ((long) buff) - :"bx", "cx", "di", "si", "ax"); +"loop 1b\n\t": +: "b" ((long) table), "c" (n), "D" ((long) buff), "S" ((long) buff) +: "bx", "cx", "di", "si", "ax"); } #endif @@ -204,8 +220,17 @@ audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) * There is no incomplete buffers */ { - if ((wr_buff_no[dev] = DMAbuf_getwrbuffer (dev, &wr_dma_buf[dev], &wr_buff_size[dev])) < 0) + if ((wr_buff_no[dev] = DMAbuf_getwrbuffer (dev, &wr_dma_buf[dev], + &wr_buff_size[dev], + dev_nblock[dev])) < 0) { + /* Handle nonblocking mode */ +#if defined(__FreeBSD__) + if (dev_nblock[dev] && wr_buff_no[dev] == RET_ERROR (EWOULDBLOCK)) +#else + if (dev_nblock[dev] && wr_buff_no[dev] == RET_ERROR (EAGAIN)) +#endif + return p; /* No more space. Return # of accepted bytes */ return wr_buff_no[dev]; } wr_buff_ptr[dev] = 0; @@ -285,8 +310,20 @@ audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) while (c) { - if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l)) < 0) - return buff_no; + if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l, + dev_nblock[dev])) < 0) + { + /* Nonblocking mode handling. Return current # of bytes */ + +#if defined(__FreeBSD__) + if (dev_nblock[dev] && buff_no == RET_ERROR (EWOULDBLOCK)) +#else + if (dev_nblock[dev] && buff_no == RET_ERROR (EAGAIN)) +#endif + return p; + + return buff_no; + } if (l > c) l = c; @@ -325,56 +362,151 @@ audio_ioctl (int dev, struct fileinfo *file, dev = dev >> 4; - switch (cmd) + if (((cmd >> 8) & 0xff) == 'C') { - case SNDCTL_DSP_SYNC: - if (wr_buff_no[dev] >= 0) + if (audio_devs[dev]->coproc) /* Coprocessor ioctl */ + return audio_devs[dev]->coproc->ioctl (audio_devs[dev]->coproc->devc, cmd, arg, 0); + else + printk ("/dev/dsp%d: No coprocessor for this device\n", dev); + + return RET_ERROR (EREMOTEIO); + } + else + switch (cmd) + { + case SNDCTL_DSP_SYNC: + if (wr_buff_no[dev] >= 0) + { + DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]); + + wr_buff_no[dev] = -1; + } + return DMAbuf_ioctl (dev, cmd, arg, 0); + break; + + case SNDCTL_DSP_POST: + if (wr_buff_no[dev] >= 0) + { + DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]); + + wr_buff_no[dev] = -1; + } + return 0; + break; + + case SNDCTL_DSP_RESET: + wr_buff_no[dev] = -1; + return DMAbuf_ioctl (dev, cmd, arg, 0); + break; + + case SNDCTL_DSP_GETFMTS: + return IOCTL_OUT (arg, audio_devs[dev]->format_mask); + break; + + case SNDCTL_DSP_SETFMT: + return IOCTL_OUT (arg, set_format (dev, IOCTL_IN (arg))); + + case SNDCTL_DSP_GETISPACE: + if (audio_mode[dev] == AM_WRITE) + return RET_ERROR (EBUSY); + { - DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]); + audio_buf_info info; - wr_buff_no[dev] = -1; + int err = DMAbuf_ioctl (dev, cmd, (unsigned long) &info, 1); + + if (err < 0) + return err; + + if (wr_buff_no[dev] != -1) + info.bytes += wr_buff_ptr[dev]; + + IOCTL_TO_USER ((char *) arg, 0, (char *) &info, sizeof (info)); + return 0; } - return DMAbuf_ioctl (dev, cmd, arg, 0); - break; - case SNDCTL_DSP_POST: - if (wr_buff_no[dev] >= 0) + case SNDCTL_DSP_GETOSPACE: + if (audio_mode[dev] == AM_READ) + return RET_ERROR (EBUSY); + { - DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]); + audio_buf_info info; - wr_buff_no[dev] = -1; - } - return 0; - break; + int err = DMAbuf_ioctl (dev, cmd, (unsigned long) &info, 1); - case SNDCTL_DSP_RESET: - wr_buff_no[dev] = -1; - return DMAbuf_ioctl (dev, cmd, arg, 0); - break; + if (err < 0) + return err; - case SNDCTL_DSP_GETFMTS: - return IOCTL_OUT (arg, audio_devs[dev]->format_mask); - break; + if (wr_buff_no[dev] != -1) + info.bytes += wr_buff_size[dev] - wr_buff_ptr[dev]; + + IOCTL_TO_USER ((char *) arg, 0, (char *) &info, sizeof (info)); + return 0; + } - case SNDCTL_DSP_SETFMT: - return IOCTL_OUT (arg, set_format (dev, IOCTL_IN (arg))); + case SNDCTL_DSP_NONBLOCK: + dev_nblock[dev] = 1; + return 0; + break; - default: - return DMAbuf_ioctl (dev, cmd, arg, 0); - break; - } + default: + return DMAbuf_ioctl (dev, cmd, arg, 0); + } } long audio_init (long mem_start) { /* - * NOTE! This routine could be called several times during boot. - */ + * NOTE! This routine could be called several times during boot. + */ return mem_start; } -#else +#ifdef ALLOW_SELECT +int +audio_select (int dev, struct fileinfo *file, int sel_type, select_table * wait) +{ + int l; + char *dmabuf; + + dev = dev >> 4; + + switch (sel_type) + { + case SEL_IN: + if (audio_mode[dev] != AM_READ && /* Wrong direction */ + audio_mode[dev] != AM_NONE) + return 0; + + if (DMAbuf_getrdbuffer (dev, &dmabuf, &l, + 1 /* Don't block */ ) >= 0) + return 1; /* We have data */ + + return DMAbuf_select (dev, file, sel_type, wait); + break; + + case SEL_OUT: + if (audio_mode[dev] != AM_WRITE && /* Wrong direction */ + audio_mode[dev] != AM_NONE) + return 0; + + if (wr_buff_no[dev] != -1) + return 1; /* There is space in the current buffer */ + + return DMAbuf_select (dev, file, sel_type, wait); + break; + + case SEL_EX: + return 0; + } + + return 0; +} + +#endif /* ALLOW_SELECT */ + +#else /* EXCLUDE_AUDIO */ /* * Stub versions */ diff --git a/sys/i386/isa/sound/dev_table.c b/sys/i386/isa/sound/dev_table.c index c79b39d..dc80a3d 100644 --- a/sys/i386/isa/sound/dev_table.c +++ b/sys/i386/isa/sound/dev_table.c @@ -25,7 +25,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * dev_table.c,v 1.6 1994/10/01 02:16:31 swallace Exp */ #define _DEV_TABLE_C_ @@ -53,6 +52,8 @@ sndtable_init (long mem_start) int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info); int drv; + printk ("Sound initialization started\n"); + for (i = 0; i < (n - 1); i++) if (snd_installed_cards[i].enabled) if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1) @@ -78,74 +79,75 @@ sndtable_init (long mem_start) snd_installed_cards[i].enabled = 0; /* * Mark as not detected */ + printk ("Sound initialization complete\n"); return mem_start; } int sndtable_probe (int unit, struct address_info *hw_config) - { - int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info); +{ + int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info); - if (!unit) - return TRUE; + if (!unit) + return TRUE; + + for (i = 0; i < (n - 1); i++) + if (snd_installed_cards[i].enabled) + if (snd_installed_cards[i].card_type == unit) + { + int drv; - for (i = 0; i < (n - 1); i++) - if (snd_installed_cards[i].enabled) - if (snd_installed_cards[i].card_type == unit) - { - int drv; - - snd_installed_cards[i].config.io_base = hw_config->io_base; - snd_installed_cards[i].config.irq = hw_config->irq; - snd_installed_cards[i].config.dma = hw_config->dma; - if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1) - snd_installed_cards[i].enabled = 0; /* + snd_installed_cards[i].config.io_base = hw_config->io_base; + snd_installed_cards[i].config.irq = hw_config->irq; + snd_installed_cards[i].config.dma = hw_config->dma; + if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1) + snd_installed_cards[i].enabled = 0; /* * Mark as not * detected */ - else if (sound_drivers[drv].probe (hw_config)) - return 1; - snd_installed_cards[i].enabled = 0; /* + else if (sound_drivers[drv].probe (hw_config)) + return 1; + snd_installed_cards[i].enabled = 0; /* * Mark as not detected */ - return 0; - } + return 0; + } - return FALSE; - } + return FALSE; +} int sndtable_init_card (int unit, struct address_info *hw_config) - { - int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info); +{ + int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info); - if (!unit) - { - if (sndtable_init (0) != 0) - panic ("snd: Invalid memory allocation"); - return TRUE; - } + if (!unit) + { + if (sndtable_init (0) != 0) + panic ("snd: Invalid memory allocation\n"); + return TRUE; + } - for (i = 0; i < (n - 1); i++) - if (snd_installed_cards[i].card_type == unit) - { - int drv; + for (i = 0; i < (n - 1); i++) + if (snd_installed_cards[i].card_type == unit) + { + int drv; - snd_installed_cards[i].config.io_base = hw_config->io_base; - snd_installed_cards[i].config.irq = hw_config->irq; - snd_installed_cards[i].config.dma = hw_config->dma; + snd_installed_cards[i].config.io_base = hw_config->io_base; + snd_installed_cards[i].config.irq = hw_config->irq; + snd_installed_cards[i].config.dma = hw_config->dma; - if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1) - snd_installed_cards[i].enabled = 0; /* + if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1) + snd_installed_cards[i].enabled = 0; /* * Mark as not detected */ - else if (sound_drivers[drv].attach (0, hw_config) != 0) - panic ("snd#: Invalid memory allocation"); - return TRUE; - } + else if (sound_drivers[drv].attach (0, hw_config) != 0) + panic ("snd#: Invalid memory allocation\n"); + return TRUE; + } - return FALSE; - } + return FALSE; +} int sndtable_get_cardcount (void) @@ -160,8 +162,8 @@ sound_setup (char *str, int *ints) int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info); /* - * First disable all drivers - */ + * First disable all drivers + */ for (i = 0; i < n; i++) snd_installed_cards[i].enabled = 0; @@ -169,8 +171,8 @@ sound_setup (char *str, int *ints) if (ints[0] == 0 || ints[1] == 0) return; /* - * Then enable them one by time - */ + * Then enable them one by time + */ for (i = 1; i <= ints[0]; i++) { diff --git a/sys/i386/isa/sound/dev_table.h b/sys/i386/isa/sound/dev_table.h index f278223..7aca8d0 100644 --- a/sys/i386/isa/sound/dev_table.h +++ b/sys/i386/isa/sound/dev_table.h @@ -2,7 +2,7 @@ * dev_table.h * * Global definitions for device call tables - * + * * Copyright by Hannu Savolainen 1993 * * Redistribution and use in source and binary forms, with or without @@ -26,8 +26,8 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: dev_table.h,v 1.13 1995/03/28 07:56:11 bde Exp $ - */ + +*/ #ifndef _DEV_TABLE_H_ #define _DEV_TABLE_H_ @@ -107,6 +107,20 @@ struct dma_buffparms { int underrun_count; }; +/* + * Structure for use with various microcontrollers and DSP processors + * in the recent soundcards. + */ +typedef struct coproc_operations { + char name[32]; + int (*open) (void *devc, int sub_device); + void (*close) (void *devc, int sub_device); + int (*ioctl) (void *devc, unsigned int cmd, unsigned int arg, int local); + void (*reset) (void *devc); + + void *devc; /* Driver specific info */ + } coproc_operations; + struct audio_operations { char name[32]; int flags; @@ -117,9 +131,9 @@ struct audio_operations { void *devc; /* Driver specific info */ int (*open) (int dev, int mode); void (*close) (int dev); - void (*output_block) (int dev, unsigned long buf, + void (*output_block) (int dev, unsigned long buf, int count, int intrflag, int dma_restart); - void (*start_input) (int dev, unsigned long buf, + void (*start_input) (int dev, unsigned long buf, int count, int intrflag, int dma_restart); int (*ioctl) (int dev, unsigned int cmd, unsigned int arg, int local); int (*prepare_for_input) (int dev, int bufsize, int nbufs); @@ -133,9 +147,12 @@ struct audio_operations { long buffsize; int dmachan; struct dma_buffparms *dmap; + struct coproc_operations *coproc; + int mixer_dev; }; struct mixer_operations { + char name[32]; int (*ioctl) (int dev, unsigned int cmd, unsigned int arg); }; @@ -162,14 +179,29 @@ struct synth_operations { int (*pmgr_interface) (int dev, struct patmgr_info *info); void (*bender) (int dev, int chn, int value); int (*alloc_voice) (int dev, int chn, int note, struct voice_alloc_info *alloc); + void (*setup_voice) (int dev, int voice, int chn); struct voice_alloc_info alloc; struct channel_info chn_info[16]; }; +struct midi_input_info { /* MIDI input scanner variables */ +#define MI_MAX 10 + int m_busy; + unsigned char m_buf[MI_MAX]; + unsigned char m_prev_status; /* For running status */ + int m_ptr; +#define MST_INIT 0 +#define MST_DATA 1 +#define MST_SYSEX 2 + int m_state; + int m_left; + }; + struct midi_operations { struct midi_info info; struct synth_operations *converter; + struct midi_input_info in_info; int (*open) (int dev, int mode, void (*inputintr)(int dev, unsigned char data), void (*outputintr)(int dev) @@ -183,6 +215,7 @@ struct midi_operations { int (*command) (int dev, unsigned char *data); int (*buffer_status) (int dev); int (*prefix_cmd) (int dev, unsigned char status); + struct coproc_operations *coproc; }; struct sound_timer_operations { @@ -197,7 +230,7 @@ struct sound_timer_operations { void (*arm_timer)(int dev, long time); }; -#ifdef _DEV_TABLE_C_ +#ifdef _DEV_TABLE_C_ struct audio_operations *audio_devs[MAX_AUDIO_DEV] = {NULL}; int num_audiodevs = 0; struct mixer_operations *mixer_devs[MAX_MIXER_DEV] = {NULL}; int num_mixers = 0; struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV] = {NULL}; int num_synths = 0; @@ -205,12 +238,12 @@ struct sound_timer_operations { #ifndef EXCLUDE_SEQUENCER extern struct sound_timer_operations default_sound_timer; - struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = - {&default_sound_timer, NULL}; + struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = + {&default_sound_timer, NULL}; int num_sound_timers = 1; #else - struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = - {NULL}; + struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = + {NULL}; int num_sound_timers = 0; #endif @@ -221,6 +254,12 @@ struct sound_timer_operations { struct driver_info sound_drivers[] = { #ifndef EXCLUDE_PSS {SNDCARD_PSS, "Echo Personal Sound System PSS (ESC614)", attach_pss, probe_pss}, +# ifdef PSS_MPU_BASE + {SNDCARD_PSS_MPU, "PSS-MPU", attach_pss_mpu, probe_pss_mpu}, +# endif +# ifdef PSS_MSS_BASE + {SNDCARD_PSS_MSS, "PSS-MSS", attach_pss_mss, probe_pss_mss}, +# endif #endif #ifndef EXCLUDE_YM3812 {SNDCARD_ADLIB, "OPL-2/OPL-3 FM", attach_adlib_card, probe_adlib}, @@ -237,11 +276,11 @@ struct sound_timer_operations { #ifndef EXCLUDE_SB {SNDCARD_SB, "SoundBlaster", attach_sb_card, probe_sb}, #endif -#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SBPRO) +#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) #ifndef EXCLUDE_AUDIO {SNDCARD_SB16, "SoundBlaster16", sb16_dsp_init, sb16_dsp_detect}, #endif -#if !defined(EXCLUDE_MIDI) && !defined(EXCLUDE_SB16MIDI) +#ifndef EXCLUDE_MIDI {SNDCARD_SB16MIDI,"SB16 MIDI", attach_sb16midi, probe_sb16midi}, #endif #endif @@ -254,9 +293,19 @@ struct sound_timer_operations { #ifndef EXCLUDE_GUS {SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus}, #endif +#ifndef EXCLUDE_SSCAPE + {SNDCARD_SSCAPE, "Ensoniq Soundscape", attach_sscape, probe_sscape}, + {SNDCARD_SSCAPE_MSS, "MS Sound System (SoundScape)", attach_ss_ms_sound, probe_ss_ms_sound}, +#endif +#ifndef EXCLUDE_TRIX + {SNDCARD_TRXPRO, "MediaTriX AudioTriX Pro", attach_trix_wss, probe_trix_wss}, + {SNDCARD_TRXPRO_SB, "AudioTriX (SB mode)", attach_trix_sb, probe_trix_sb}, + {SNDCARD_TRXPRO_MPU, "AudioTriX MIDI", attach_trix_mpu, probe_trix_mpu}, +#endif {0, "*?*", NULL, NULL} }; +#if defined(linux) || defined(__FreeBSD__) /* * List of devices actually configured in the system. * @@ -266,16 +315,27 @@ struct sound_timer_operations { struct card_info snd_installed_cards[] = { #ifndef EXCLUDE_PSS {SNDCARD_PSS, {PSS_BASE, PSS_IRQ, PSS_DMA}, SND_DEFAULT_ENABLE}, +# ifdef PSS_MPU_BASE + {SNDCARD_PSS_MPU, {PSS_MPU_BASE, PSS_MPU_IRQ, 0}, SND_DEFAULT_ENABLE}, +# endif +# ifdef PSS_MSS_BASE + {SNDCARD_PSS_MSS, {PSS_MSS_BASE, PSS_MSS_IRQ, PSS_MSS_DMA}, SND_DEFAULT_ENABLE}, +# endif #endif -#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI) - {SNDCARD_MPU401, {MPU_BASE, MPU_IRQ, 0}, SND_DEFAULT_ENABLE}, -#ifdef MPU2_BASE - {SNDCARD_MPU401, {MPU2_BASE, MPU2_IRQ, 0}, SND_DEFAULT_ENABLE}, -#endif -#ifdef MPU3_BASE - {SNDCARD_MPU401, {MPU3_BASE, MPU2_IRQ, 0}, SND_DEFAULT_ENABLE}, +#ifndef EXCLUDE_TRIX + {SNDCARD_TRXPRO, {TRIX_BASE, TRIX_IRQ, TRIX_DMA}, SND_DEFAULT_ENABLE}, +# ifdef TRIX_SB_BASE + {SNDCARD_TRXPRO_SB, {TRIX_SB_BASE, TRIX_SB_IRQ, TRIX_SB_DMA}, SND_DEFAULT_ENABLE}, +# endif +# ifdef TRIX_MPU_BASE + {SNDCARD_TRXPRO_MPU, {TRIX_MPU_BASE, TRIX_MPU_IRQ, 0}, SND_DEFAULT_ENABLE}, +# endif #endif +#ifndef EXCLUDE_SSCAPE + {SNDCARD_SSCAPE, {SSCAPE_BASE, SSCAPE_IRQ, SSCAPE_DMA}, SND_DEFAULT_ENABLE}, + {SNDCARD_SSCAPE_MSS, {SSCAPE_MSS_BASE, SSCAPE_MSS_IRQ, SSCAPE_MSS_DMA}, SND_DEFAULT_ENABLE}, #endif + #ifndef EXCLUDE_MSS {SNDCARD_MSS, {MSS_BASE, MSS_IRQ, MSS_DMA}, SND_DEFAULT_ENABLE}, # ifdef MSS2_BASE @@ -283,10 +343,6 @@ struct sound_timer_operations { # endif #endif -#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI) - {SNDCARD_UART6850, {U6850_BASE, U6850_IRQ, 0}, SND_DEFAULT_ENABLE}, -#endif - #ifndef EXCLUDE_PAS {SNDCARD_PAS, {PAS_BASE, PAS_IRQ, PAS_DMA}, SND_DEFAULT_ENABLE}, #endif @@ -295,6 +351,20 @@ struct sound_timer_operations { {SNDCARD_SB, {SBC_BASE, SBC_IRQ, SBC_DMA}, SND_DEFAULT_ENABLE}, #endif +#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI) + {SNDCARD_MPU401, {MPU_BASE, MPU_IRQ, 0}, SND_DEFAULT_ENABLE}, +#ifdef MPU2_BASE + {SNDCARD_MPU401, {MPU2_BASE, MPU2_IRQ, 0}, SND_DEFAULT_ENABLE}, +#endif +#ifdef MPU3_BASE + {SNDCARD_MPU401, {MPU3_BASE, MPU2_IRQ, 0}, SND_DEFAULT_ENABLE}, +#endif +#endif + +#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI) + {SNDCARD_UART6850, {U6850_BASE, U6850_IRQ, 0}, SND_DEFAULT_ENABLE}, +#endif + #if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) #ifndef EXCLUDE_AUDIO {SNDCARD_SB16, {SBC_BASE, SBC_IRQ, SB16_DMA}, SND_DEFAULT_ENABLE}, @@ -306,9 +376,9 @@ struct sound_timer_operations { #ifndef EXCLUDE_GUS #ifndef EXCLUDE_GUS16 - {SNDCARD_GUS16, {GUS16_BASE, GUS16_IRQ, GUS16_DMA}, SND_DEFAULT_ENABLE}, + {SNDCARD_GUS16, {GUS16_BASE, GUS16_IRQ, GUS16_DMA, GUS_DMA_READ}, SND_DEFAULT_ENABLE}, #endif - {SNDCARD_GUS, {GUS_BASE, GUS_IRQ, GUS_DMA}, SND_DEFAULT_ENABLE}, + {SNDCARD_GUS, {GUS_BASE, GUS_IRQ, GUS_DMA, GUS_DMA_READ}, SND_DEFAULT_ENABLE}, #endif #ifndef EXCLUDE_YM3812 @@ -317,11 +387,15 @@ struct sound_timer_operations { {0, {0}, 0} }; - int num_sound_drivers = - sizeof(sound_drivers) / sizeof (struct driver_info); int num_sound_cards = sizeof(snd_installed_cards) / sizeof (struct card_info); +#else + int num_sound_cards = 0; +#endif /* linux */ + + int num_sound_drivers = + sizeof(sound_drivers) / sizeof (struct driver_info); #else extern struct audio_operations * audio_devs[MAX_AUDIO_DEV]; int num_audiodevs; @@ -335,9 +409,9 @@ struct sound_timer_operations { extern struct card_info snd_installed_cards[]; extern int num_sound_cards; -long sndtable_init(long mem_start); int sndtable_probe(int unit, struct address_info *hw_config); int sndtable_init_card(int unit, struct address_info *hw_config); +long sndtable_init(long mem_start); int sndtable_get_cardcount (void); struct address_info *sound_getconf(int card_type); void sound_chconf(int card_type, int ioaddr, int irq, int dma); diff --git a/sys/i386/isa/sound/dmabuf.c b/sys/i386/isa/sound/dmabuf.c index e7d8216..52e29e3 100644 --- a/sys/i386/isa/sound/dmabuf.c +++ b/sys/i386/isa/sound/dmabuf.c @@ -3,7 +3,7 @@ * * The DMA buffer manager for digitized voice applications * - * Copyright by Hannu Savolainen 1993, 1994 + * Copyright by Hannu Savolainen 1993, 1994, 1995 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -25,29 +25,24 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: dmabuf.c,v 1.15 1995/05/07 06:38:47 pst Exp $ */ #include "sound_config.h" #ifdef CONFIGURE_SOUNDCARD -#include "sound_calls.h" -#ifdef __FreeBSD__ -#include <machine/soundcard.h> -extern struct selinfo selinfo[SND_NDEVS>>4]; -#endif - #if !defined(EXCLUDE_AUDIO) || !defined(EXCLUDE_GUS) DEFINE_WAIT_QUEUES (dev_sleeper[MAX_AUDIO_DEV], dev_sleep_flag[MAX_AUDIO_DEV]); static struct dma_buffparms dmaps[MAX_AUDIO_DEV] = -{0}; /* - * Primitive way to allocate - * such a large array. - * Needs dynamic run-time alloction. - */ +{ + {0}}; /* + + * Primitive way to allocate + * such a large array. + * Needs dynamic run-time alloction. + */ static void reorganize_buffers (int dev) @@ -83,10 +78,10 @@ reorganize_buffers (int dev) sz = sr * nc * sz; /* - * Compute a buffer size for time not exeeding 1 second. - * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds - * of sound (using the current speed, sample size and #channels). - */ + * Compute a buffer size for time not exeeding 1 second. + * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds + * of sound (using the current speed, sample size and #channels). + */ bsz = dsp_dev->buffsize; while (bsz > sz) @@ -111,9 +106,9 @@ reorganize_buffers (int dev) else { /* - * The process has specified the buffer sice with SNDCTL_DSP_SETFRAGMENT or - * the buffer sice computation has already been done. - */ + * The process has specified the buffer sice with SNDCTL_DSP_SETFRAGMENT or + * the buffer sice computation has already been done. + */ if (dmap->fragment_size > audio_devs[dev]->buffsize) dmap->fragment_size = audio_devs[dev]->buffsize; bsz = dmap->fragment_size; @@ -162,7 +157,6 @@ dma_init_buffers (int dev) dmap->flags = DMA_BUSY; /* Other flags off */ dmap->qlen = dmap->qhead = dmap->qtail = 0; - dmap->qlen = dmap->qtail = dmap->qhead = 0; dmap->dma_mode = DMODE_NONE; } @@ -255,7 +249,7 @@ dma_sync (int dev) /* * Some devices such as GUS have huge amount of on board RAM for the - * audio data. We have to wait util the device has finished playing. + * audio data. We have to wait until the device has finished playing. */ DISABLE_INTR (flags); @@ -300,9 +294,10 @@ DMAbuf_release (int dev, int mode) } int -DMAbuf_start_input(int dev) +DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock) { unsigned long flags; + int err = EIO; struct dma_buffparms *dmap = audio_devs[dev]->dmap; DISABLE_INTR (flags); @@ -324,7 +319,7 @@ DMAbuf_start_input(int dev) if (!(dmap->flags & DMA_ALLOC_DONE)) reorganize_buffers (dev); - if (dmap->dma_mode) + if (!dmap->dma_mode) { int err; @@ -345,32 +340,24 @@ DMAbuf_start_input(int dev) !(dmap->flags & DMA_STARTED)); dmap->flags |= DMA_ACTIVE | DMA_STARTED; } - } - RESTORE_INTR (flags); - return 0; -} - -int -DMAbuf_getrdbuffer (int dev, char **buf, int *len) -{ - unsigned long flags; - int err = EIO; - struct dma_buffparms *dmap = audio_devs[dev]->dmap; - - DISABLE_INTR (flags); - if (!dmap->qlen) - { - if(err = DMAbuf_start_input(dev)) - return err; + if (dontblock) + { + RESTORE_INTR (flags); +#if defined(__FreeBSD__) + return RET_ERROR (EWOULDBLOCK); +#else + return RET_ERROR (EAGAIN); +#endif + } /* Wait for the next block */ - err = EIO; DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ); if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev])) { printk ("Sound: DMA timed out - IRQ/DRQ config error?\n"); + err = EIO; SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]); } else @@ -436,15 +423,15 @@ DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) case SNDCTL_DSP_SETBLKSIZE: { - int size = IOCTL_IN (arg); - + int size = IOCTL_IN(arg); + if(!(dmap->flags & DMA_ALLOC_DONE) && size) { - dmap->fragment_size = size; - return 0; + dmap->fragment_size = size; + return 0; } else - return RET_ERROR (EINVAL); /* Too late to change */ + return RET_ERROR (EINVAL); /* Too late to change */ } break; @@ -461,7 +448,7 @@ DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) } if (dmap->subdivision != 0 || - dmap->fragment_size)/* Loo late to change */ + dmap->fragment_size) /* Loo late to change */ return RET_ERROR (EINVAL); if (fact > MAX_REALTIME_FACTOR) @@ -484,7 +471,7 @@ DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) return RET_ERROR (EIO); if (dmap->subdivision != 0 || - dmap->fragment_size)/* Loo late to change */ + dmap->fragment_size) /* Loo late to change */ return RET_ERROR (EINVAL); bytes = fact & 0xffff; @@ -514,12 +501,24 @@ DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) } break; + case SNDCTL_DSP_GETISPACE: + case SNDCTL_DSP_GETOSPACE: + if (!local) + return RET_ERROR (EINVAL); + + { + audio_buf_info *info = (audio_buf_info *) arg; + + info->fragments = dmap->qlen; + info->fragsize = dmap->fragment_size; + info->bytes = dmap->qlen * dmap->fragment_size; + } + return 0; + default: return audio_devs[dev]->ioctl (dev, cmd, arg, local); } - /* NOTREACHED */ - return RET_ERROR (EIO); } static int @@ -528,13 +527,13 @@ space_in_queue (int dev) int len, max, tmp; struct dma_buffparms *dmap = audio_devs[dev]->dmap; - if (dmap->qlen == dmap->nbufs)/* No space at all */ + if (dmap->qlen == dmap->nbufs) /* No space at all */ return 0; /* - * Verify that there are no more pending buffers than the limit - * defined by the process. - */ + * Verify that there are no more pending buffers than the limit + * defined by the process. + */ max = dmap->max_fragments; len = dmap->qlen; @@ -544,8 +543,8 @@ space_in_queue (int dev) tmp = audio_devs[dev]->local_qlen (dev); if (tmp & len) tmp--; /* - * This buffer has been counted twice - */ + * This buffer has been counted twice + */ len += tmp; } @@ -555,7 +554,7 @@ space_in_queue (int dev) } int -DMAbuf_getwrbuffer (int dev, char **buf, int *size) +DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock) { unsigned long flags; int abort, err = EIO; @@ -588,6 +587,13 @@ DMAbuf_getwrbuffer (int dev, char **buf, int *size) } + if (dontblock) +#if defined(__FreeBSD__) + return RET_ERROR (EWOULDBLOCK); +#else + return RET_ERROR (EAGAIN); +#endif + DISABLE_INTR (flags); abort = 0; @@ -692,28 +698,41 @@ DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode) set_dma_count (chan, dmap->bytes_in_use); enable_dma (chan); RESTORE_INTR (flags); -#else /* linux */ -#ifdef __FreeBSD__ - isa_dmastart (B_RAW + ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE), +#else + +#if defined(__FreeBSD__) + + isa_dmastart (B_RAW + (dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE, (caddr_t)dmap->raw_buf_phys[0], dmap->bytes_in_use, chan); -#else /* __FreeBSD__ */ +#else /* else __FreeBSD__ */ #if defined(GENERIC_SYSV) #ifndef DMAMODE_AUTO printk ("sound: Invalid DMA mode for device %d\n", dev); -#endif /* DMAMODE_AUTO */ +#endif +#if defined(SVR42) + + /* + ** send full count to snd_dma_prog, it will take care of subtracting + ** one if it is required. + */ + snd_dma_prog (chan, dmap->raw_buf_phys[0], dmap->bytes_in_use, + dma_mode, TRUE); + +#else /* !SVR42 */ dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode) #ifdef DMAMODE_AUTO | DMAMODE_AUTO -#endif /* DMAMODE_AUTO */ +#endif , - dmap->raw_buf_phys[0], dmap->bytes_in_use); + dmap->raw_buf_phys[0], dmap->bytes_in_use - 1); dma_enable (chan); -#else /* GENERIC_SYSV */ +#endif /* ! SVR42 */ +#else #error This routine is not valid for this OS. -#endif /* __FreeBSD__ */ -#endif /* linux */ +#endif +#endif #endif } @@ -728,24 +747,30 @@ DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode) set_dma_count (chan, count); enable_dma (chan); RESTORE_INTR (flags); -#else /* linux */ -#ifdef __FreeBSD__ +#else +#if defined(__FreeBSD__) isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE, (caddr_t)physaddr, count, chan); -#else /* __FreeBSD__ */ +#else /* FreeBSD */ #if defined(GENERIC_SYSV) +#if defined(SVR42) + + snd_dma_prog (chan, physaddr, count, dma_mode, FALSE); + +#else /* ! SVR42 */ dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode), physaddr, count); dma_enable (chan); -#else /* GENERIC_SYSV */ +#endif /* SVR42 */ +#else #error This routine is not valid for this OS. #endif /* GENERIC_SYSV */ -#endif /* __FreeBSD */ +#endif -#endif /* linux */ +#endif } return count; @@ -756,9 +781,13 @@ DMAbuf_init (long mem_start) { int dev; +#if defined(SVR42) + snd_dma_init (); +#endif /* SVR42 */ + /* - * NOTE! This routine could be called several times. - */ + * NOTE! This routine could be called several times. + */ for (dev = 0; dev < num_audiodevs; dev++) audio_devs[dev]->dmap = &dmaps[dev]; @@ -769,18 +798,22 @@ void DMAbuf_outputintr (int dev, int event_type) { /* - * Event types: - * 0 = DMA transfer done. Device still has more data in the local - * buffer. - * 1 = DMA transfer done. Device doesn't have local buffer or it's - * empty now. - * 2 = No DMA transfer but the device has now more space in it's local - * buffer. - */ + * Event types: + * 0 = DMA transfer done. Device still has more data in the local + * buffer. + * 1 = DMA transfer done. Device doesn't have local buffer or it's + * empty now. + * 2 = No DMA transfer but the device has now more space in it's local + * buffer. + */ unsigned long flags; struct dma_buffparms *dmap = audio_devs[dev]->dmap; +#if defined(SVR42) + snd_dma_intr (audio_devs[dev]->dmachan); +#endif /* SVR42 */ + if (event_type != 2) { if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs) @@ -819,7 +852,7 @@ DMAbuf_outputintr (int dev, int event_type) WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]); } RESTORE_INTR (flags); -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) if(selinfo[dev].si_pid) selwakeup(&selinfo[dev]); #endif @@ -831,6 +864,10 @@ DMAbuf_inputintr (int dev) unsigned long flags; struct dma_buffparms *dmap = audio_devs[dev]->dmap; +#if defined(SVR42) + snd_dma_intr (audio_devs[dev]->dmachan); +#endif /* SVR42 */ + if (dmap->qlen == (dmap->nbufs - 1)) { printk ("Sound: Recording overrun\n"); @@ -862,7 +899,7 @@ DMAbuf_inputintr (int dev) WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]); } RESTORE_INTR (flags); -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) if(selinfo[dev].si_pid) selwakeup(&selinfo[dev]); #endif @@ -874,7 +911,7 @@ DMAbuf_open_dma (int dev) unsigned long flags; int chan = audio_devs[dev]->dmachan; - if (ALLOC_DMA_CHN (chan)) + if (ALLOC_DMA_CHN (chan, audio_devs[dev]->name)) { printk ("Unable to grab DMA%d for the audio driver\n", chan); return RET_ERROR (EBUSY); @@ -895,67 +932,80 @@ DMAbuf_close_dma (int dev) { int chan = audio_devs[dev]->dmachan; - DMAbuf_reset_dma (chan); + DMAbuf_reset_dma (dev); RELEASE_DMA_CHN (chan); } void -DMAbuf_reset_dma (int chan) -{ -} - -/* - * Used by unix select system call to see if data is ready. - */ -int -DMAbuf_output_ready(int dev) +DMAbuf_reset_dma (int dev) { - struct dma_buffparms *dmap = audio_devs[dev]->dmap; +#if 0 + int chan = audio_devs[dev]->dmachan; - if (!(dmap->flags & DMA_ALLOC_DONE)) - reorganize_buffers (dev); - return space_in_queue (dev); + disable_dma (chan); +#endif } + +#ifdef ALLOW_SELECT int -DMAbuf_input_ready(int dev) +DMAbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wait) { - int h,i,r; struct dma_buffparms *dmap = audio_devs[dev]->dmap; + unsigned long flags; - r = 0; - if(dmap->qlen) + switch (sel_type) { - if(dmap->fragment_size) - { - for(i=0; i<dmap->qlen; i++) - { - h = (dmap->qhead + i) % dmap->nbufs; - r += dmap->fragment_size - dmap->counts[h]; - if(r >= dmap->fragment_size) - break; - } - if(r < dmap->fragment_size) - r = 0; - else - r = 1; - } - else - r = 1; + case SEL_IN: + if (dmap->dma_mode != DMODE_INPUT) + return 0; + + if (!dmap->qlen) + { + DISABLE_INTR (flags); +#if defined(__FreeBSD__) + selrecord(wait, &selinfo[dev]); +#else + dev_sleep_flag[dev].mode = WK_SLEEP; + select_wait (&dev_sleeper[dev], wait); +#endif + RESTORE_INTR (flags); + return 0; + } + return 1; + break; + + case SEL_OUT: + if (dmap->dma_mode == DMODE_INPUT) + return 0; + + if (dmap->dma_mode == DMODE_NONE) + return 1; + + if (!space_in_queue (dev)) + { + DISABLE_INTR (flags); +#if defined(__FreeBSD__) + selrecord(wait, &selinfo[dev]); +#else + dev_sleep_flag[dev].mode = WK_SLEEP; + select_wait (&dev_sleeper[dev], wait); +#endif + RESTORE_INTR (flags); + return 0; + } + return 1; + break; + + case SEL_EX: + return 0; } - else - DMAbuf_start_input(dev); - return(r); + return 0; } -/* - * The sound_mem_init() is called by mem_init() immediately after mem_map is - * initialized and before free_page_list is created. - * - * This routine allocates DMA buffers at the end of available physical memory ( - * <16M) and marks pages reserved at mem_map. - */ -#else +#endif /* ALLOW_SELECT */ + +#else /* EXCLUDE_AUDIO */ /* * Stub versions if audio services not included */ @@ -973,31 +1023,13 @@ DMAbuf_release (int dev, int mode) } int -DMAbuf_start_input (int dev) -{ - return RET_ERROR (EIO); -} - -int -DMAbuf_input_ready (int dev) -{ - return 0; -} - -int -DMAbuf_output_ready (int dev) -{ - return 0; -} - -int -DMAbuf_getwrbuffer (int dev, char **buf, int *size) +DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock) { return RET_ERROR (EIO); } int -DMAbuf_getrdbuffer (int dev, char **buf, int *len) +DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock) { return RET_ERROR (EIO); } @@ -1033,19 +1065,19 @@ DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode) } int -DMAbuf_open_dma (int chan) +DMAbuf_open_dma (int dev) { return RET_ERROR (ENXIO); } void -DMAbuf_close_dma (int chan) +DMAbuf_close_dma (int dev) { return; } void -DMAbuf_reset_dma (int chan) +DMAbuf_reset_dma (int dev) { return; } diff --git a/sys/i386/isa/sound/finetune.h b/sys/i386/isa/sound/finetune.h index 00085f9..b86a0eb 100644 --- a/sys/i386/isa/sound/finetune.h +++ b/sys/i386/isa/sound/finetune.h @@ -23,26 +23,25 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * finetune.h,v 1.3 1994/08/02 07:39:51 davidg Exp */ unsigned short finetune_table[128] = { -/* 0 */ 9439, 9447, 9456, 9464, 9473, 9481, 9490, 9499, -/* 8 */ 9507, 9516, 9524, 9533, 9542, 9550, 9559, 9567, -/* 16 */ 9576, 9585, 9593, 9602, 9611, 9619, 9628, 9637, -/* 24 */ 9645, 9654, 9663, 9672, 9680, 9689, 9698, 9707, -/* 32 */ 9715, 9724, 9733, 9742, 9750, 9759, 9768, 9777, -/* 40 */ 9786, 9795, 9803, 9812, 9821, 9830, 9839, 9848, -/* 48 */ 9857, 9866, 9874, 9883, 9892, 9901, 9910, 9919, -/* 56 */ 9928, 9937, 9946, 9955, 9964, 9973, 9982, 9991, -/* 64 */ 10000, 10009, 10018, 10027, 10036, 10045, 10054, 10063, -/* 72 */ 10072, 10082, 10091, 10100, 10109, 10118, 10127, 10136, -/* 80 */ 10145, 10155, 10164, 10173, 10182, 10191, 10201, 10210, -/* 88 */ 10219, 10228, 10237, 10247, 10256, 10265, 10274, 10284, -/* 96 */ 10293, 10302, 10312, 10321, 10330, 10340, 10349, 10358, -/* 104 */ 10368, 10377, 10386, 10396, 10405, 10415, 10424, 10433, -/* 112 */ 10443, 10452, 10462, 10471, 10481, 10490, 10499, 10509, +/* 0 */ 9439, 9447, 9456, 9464, 9473, 9481, 9490, 9499, +/* 8 */ 9507, 9516, 9524, 9533, 9542, 9550, 9559, 9567, +/* 16 */ 9576, 9585, 9593, 9602, 9611, 9619, 9628, 9637, +/* 24 */ 9645, 9654, 9663, 9672, 9680, 9689, 9698, 9707, +/* 32 */ 9715, 9724, 9733, 9742, 9750, 9759, 9768, 9777, +/* 40 */ 9786, 9795, 9803, 9812, 9821, 9830, 9839, 9848, +/* 48 */ 9857, 9866, 9874, 9883, 9892, 9901, 9910, 9919, +/* 56 */ 9928, 9937, 9946, 9955, 9964, 9973, 9982, 9991, +/* 64 */ 10000, 10009, 10018, 10027, 10036, 10045, 10054, 10063, +/* 72 */ 10072, 10082, 10091, 10100, 10109, 10118, 10127, 10136, +/* 80 */ 10145, 10155, 10164, 10173, 10182, 10191, 10201, 10210, +/* 88 */ 10219, 10228, 10237, 10247, 10256, 10265, 10274, 10284, +/* 96 */ 10293, 10302, 10312, 10321, 10330, 10340, 10349, 10358, +/* 104 */ 10368, 10377, 10386, 10396, 10405, 10415, 10424, 10433, +/* 112 */ 10443, 10452, 10462, 10471, 10481, 10490, 10499, 10509, /* 120 */ 10518, 10528, 10537, 10547, 10556, 10566, 10576, 10585 }; #else diff --git a/sys/i386/isa/sound/gus_card.c b/sys/i386/isa/sound/gus_card.c index 35311d2..4a07fd3 100644 --- a/sys/i386/isa/sound/gus_card.c +++ b/sys/i386/isa/sound/gus_card.c @@ -25,7 +25,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * gus_card.c,v 1.11 1994/10/14 09:04:19 jkh Exp */ #include "sound_config.h" @@ -44,13 +43,14 @@ attach_gus_card (long mem_start, struct address_info *hw_config) { int io_addr; - snd_set_irq_handler (hw_config->irq, gusintr); + snd_set_irq_handler (hw_config->irq, gusintr, "Gravis Ultrasound"); if (gus_wave_detect (hw_config->io_base)) /* * Try first the default */ { - mem_start = gus_wave_init (mem_start, hw_config->irq, hw_config->dma); + mem_start = gus_wave_init (mem_start, hw_config->irq, hw_config->dma, + hw_config->dma_read); #ifndef EXCLUDE_MIDI mem_start = gus_midi_init (mem_start); #endif @@ -73,7 +73,8 @@ attach_gus_card (long mem_start, struct address_info *hw_config) if (gus_wave_detect (io_addr)) { printk (" WARNING! GUS found at %x, config was %x ", io_addr, hw_config->io_base); - mem_start = gus_wave_init (mem_start, hw_config->irq, hw_config->dma); + mem_start = gus_wave_init (mem_start, hw_config->irq, hw_config->dma, + hw_config->dma_read); #ifndef EXCLUDE_MIDI mem_start = gus_midi_init (mem_start); #endif @@ -117,7 +118,7 @@ probe_gus (struct address_info *hw_config) } void -gusintr (int irq) +gusintr (INT_HANDLER_PARMS (irq, dummy)) { unsigned char src; @@ -127,7 +128,11 @@ gusintr (int irq) #ifndef EXCLUDE_GUSMAX if (have_gus_max) - adintr (irq); +# if defined(__FreeBSD__) + ad1848_interrupt (INT_HANDLER_CALL (gus_irq)); +# else + ad1848_interrupt (INT_HANDLER_CALL (irq)); +# endif #endif while (1) @@ -168,7 +173,7 @@ gusintr (int irq) /* * Some extra code for the 16 bit sampling option */ -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS16) && !defined(EXCLUDE_GUS) +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS16) int probe_gus_db16 (struct address_info *hw_config) @@ -182,7 +187,7 @@ attach_gus_db16 (long mem_start, struct address_info *hw_config) gus_pcm_volume = 100; gus_wave_volume = 90; - ad1848_init ("gusxvi0: <GUS 16 bit sampling>", hw_config->io_base, + ad1848_init ("GUS 16 bit sampling", hw_config->io_base, hw_config->irq, hw_config->dma, hw_config->dma); diff --git a/sys/i386/isa/sound/gus_hw.h b/sys/i386/isa/sound/gus_hw.h index e0932e6..f97a0b8 100644 --- a/sys/i386/isa/sound/gus_hw.h +++ b/sys/i386/isa/sound/gus_hw.h @@ -1,6 +1,4 @@ -/* - * gus_hw.h,v 1.3 1994/08/02 07:39:54 davidg Exp - */ + /* * I/O addresses */ diff --git a/sys/i386/isa/sound/gus_linearvol.h b/sys/i386/isa/sound/gus_linearvol.h index f6c4f31..7ad0c30 100644 --- a/sys/i386/isa/sound/gus_linearvol.h +++ b/sys/i386/isa/sound/gus_linearvol.h @@ -1,6 +1,3 @@ -/* - * gus_linearvol.h,v 1.2 1994/08/02 07:39:57 davidg Exp - */ static unsigned short gus_linearvol[128] = { 0x0000, 0x08ff, 0x09ff, 0x0a80, 0x0aff, 0x0b40, 0x0b80, 0x0bc0, 0x0bff, 0x0c20, 0x0c40, 0x0c60, 0x0c80, 0x0ca0, 0x0cc0, 0x0ce0, diff --git a/sys/i386/isa/sound/gus_midi.c b/sys/i386/isa/sound/gus_midi.c index c10c4ca..66c81df 100644 --- a/sys/i386/isa/sound/gus_midi.c +++ b/sys/i386/isa/sound/gus_midi.c @@ -25,7 +25,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * gus_midi.c,v 1.6 1994/10/01 02:16:39 swallace Exp */ #include "sound_config.h" @@ -232,6 +231,7 @@ static struct midi_operations gus_midi_operations = { {"Gravis UltraSound Midi", 0, 0, SNDCARD_GUS}, &std_midi_synth, + {0}, gus_midi_open, gus_midi_close, gus_midi_ioctl, @@ -297,10 +297,12 @@ gus_midi_interrupt (int dummy) } } +#if 0 if (stat & MIDI_FRAME_ERR) - printk ("Midi framing error\n"); + printk ("GUS: Midi framing error\n"); if (stat & MIDI_OVERRUN && input_opened) printk ("GUS: Midi input overrun\n"); +#endif RESTORE_INTR (flags); } diff --git a/sys/i386/isa/sound/gus_vol.c b/sys/i386/isa/sound/gus_vol.c index e2a09fd..055a117 100644 --- a/sys/i386/isa/sound/gus_vol.c +++ b/sys/i386/isa/sound/gus_vol.c @@ -2,8 +2,6 @@ * gus_vol.c - Compute volume for GUS. * * Greg Lee 1993. - * - * gus_vol.c,v 1.5 1994/10/01 02:16:40 swallace Exp */ #include "sound_config.h" #ifndef EXCLUDE_GUS diff --git a/sys/i386/isa/sound/gus_wave.c b/sys/i386/isa/sound/gus_wave.c index 1008aa4..2def4909 100644 --- a/sys/i386/isa/sound/gus_wave.c +++ b/sys/i386/isa/sound/gus_wave.c @@ -25,19 +25,15 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: gus_wave.c,v 1.14 1995/03/12 23:33:52 swallace Exp $ */ #include "sound_config.h" -#include <machine/ultrasound.h> +#include "ultrasound.h" #include "gus_hw.h" -#undef OUTB -#define OUTB(val, port) outb(port, val) - #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS) -#define MAX_SAMPLE 128 +#define MAX_SAMPLE 150 #define MAX_PATCH 256 struct voice_info @@ -82,12 +78,14 @@ extern int gus_base; extern int gus_irq, gus_dma; static long gus_mem_size = 0; static long free_mem_ptr = 0; -static int gus_busy = 0; + int gus_busy[MAX_AUDIO_DEV], gus_dspnum=0; +static int gus_dma_read=0; static int nr_voices = 0; -static int gus_devnum = 0; + int gus_devnum = 0; static int volume_base, volume_scale, volume_method; static int gus_recmask = SOUND_MASK_MIC; static int recording_active = 0; +static int only_read_access = 0; int gus_wave_volume = 60; int gus_pcm_volume = 80; @@ -478,10 +476,12 @@ gus_voice_init (int voice) DISABLE_INTR (flags); gus_select_voice (voice); gus_voice_volume (0); + gus_voice_off (); gus_write_addr (0x0a, 0, 0); /* Set current position to 0 */ gus_write8 (0x00, 0x03); /* Voice off */ gus_write8 (0x0d, 0x03); /* Ramping off */ voice_alloc->map[voice] = 0; + voice_alloc->alloc_times[voice] = 0; RESTORE_INTR (flags); } @@ -676,7 +676,7 @@ gus_initialize (void) unsigned char dma_image, irq_image, tmp; static unsigned char gus_irq_map[16] = - {0, 0, 1, 3, 0, 2, 0, 4, 0, 0, 0, 5, 6, 0, 0, 7}; + {0, 0, 0, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7}; static unsigned char gus_dma_map[8] = {0, 1, 0, 2, 0, 3, 4, 5}; @@ -744,7 +744,14 @@ gus_initialize (void) irq_image |= tmp; irq_image |= 0x40; /* Combine IRQ1 (GF1) and IRQ2 (Midi) */ - dma_image = 0x40; /* Combine DMA1 (DRAM) and IRQ2 (ADC) */ + dma_image = gus_dma_map[gus_dma_read] << 3; + if(!dma_image) + printk ("Warning! GUS DMA read channel not selected.\n"); + if(gus_dma_read == gus_dma) + { + dma_image = 0x40; /* dual dma inhibited + Combine DMA1 (DRAM) and IRQ2 (ADC) */ + } tmp = gus_dma_map[gus_dma]; if (!tmp) printk ("Warning! GUS DMA not selected\n"); @@ -785,7 +792,7 @@ gus_initialize (void) gus_select_voice (0); /* This disables writes to IRQ/DMA reg */ - gusintr (0); /* Serve pending interrupts */ + gusintr (INT_HANDLER_CALL (0)); /* Serve pending interrupts */ RESTORE_INTR (flags); } @@ -892,7 +899,7 @@ guswave_set_instr (int dev, int voice, int instr_no) if (sample_no < 0) { printk ("GUS: Undefined patch %d for voice %d\n", instr_no, voice); - return RET_ERROR (EINVAL);/* Patch not defined */ + return RET_ERROR (EINVAL); /* Patch not defined */ } if (sample_ptrs[sample_no] == -1) /* Sample not loaded */ @@ -913,7 +920,7 @@ guswave_kill_note (int dev, int voice, int note, int velocity) unsigned long flags; DISABLE_INTR (flags); - voice_alloc->map[voice] = 0xffff; + /* voice_alloc->map[voice] = 0xffff; */ if (voices[voice].volume_irq_mode == VMODE_START_NOTE) { voices[voice].kill_pending = 1; @@ -925,17 +932,17 @@ guswave_kill_note (int dev, int voice, int note, int velocity) gus_voice_fade (voice); } + RESTORE_INTR (flags); return 0; } static void guswave_aftertouch (int dev, int voice, int pressure) { +#if 0 short lo_limit, hi_limit; unsigned long flags; - return; /* Procedure currently disabled */ - if (voice < 0 || voice > 31) return; @@ -968,6 +975,7 @@ guswave_aftertouch (int dev, int voice, int pressure) gus_ramp_rate (3, 8); gus_rampon (0x58); /* Bidirectional, dow, loop */ RESTORE_INTR (flags); +#endif /* 0 */ } static void @@ -1024,8 +1032,8 @@ compute_and_set_volume (int voice, int volume, int ramp_time) DISABLE_INTR (flags); /* - * CAUTION! Interrupts disabled. Enable them before returning - */ + * CAUTION! Interrupts disabled. Enable them before returning + */ gus_select_voice (voice); @@ -1234,8 +1242,8 @@ guswave_start_note2 (int dev, int voice, int note_num, int volume) note_freq <= samples[samplep].high_note) sample = samplep; else - samplep = samples[samplep].key; /* - * Follow link + samplep = samples[samplep].key; /* + * Follow link */ } if (sample == -1) @@ -1340,9 +1348,9 @@ guswave_start_note2 (int dev, int voice, int note_num, int volume) } gus_write_addr (0x02, sample_ptrs[sample] + samples[sample].loop_start, - is16bits);/* Loop start location */ + is16bits); /* Loop start location */ gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end, - is16bits);/* Loop end location */ + is16bits); /* Loop end location */ } else { @@ -1350,9 +1358,9 @@ guswave_start_note2 (int dev, int voice, int note_num, int volume) voices[voice].loop_irq_mode = LMODE_FINISH; /* Ramp down at the end */ voices[voice].loop_irq_parm = 1; gus_write_addr (0x02, sample_ptrs[sample], - is16bits);/* Loop start location */ + is16bits); /* Loop start location */ gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].len - 1, - is16bits);/* Loop end location */ + is16bits); /* Loop end location */ } gus_voice_freq (freq); gus_voice_balance (pan); @@ -1382,8 +1390,7 @@ guswave_start_note (int dev, int voice, int note_num, int volume) voices[voice].volume_pending = volume; else { - RESTORE_INTR (flags); - ret_val = guswave_start_note2 (dev, voice, note_num, volume); + ret_val = guswave_start_note2 (gus_devnum, voice, note_num, volume); } } else @@ -1391,7 +1398,7 @@ guswave_start_note (int dev, int voice, int note_num, int volume) gus_select_voice (voice); mode = gus_read8 (0x00); if (mode & 0x20) - gus_write8 (0x00, mode & 0xdf); /* No interrupt! */ + gus_write8 (0x00, mode & 0xdf); /* No interrupt! */ voices[voice].offset_pending = 0; voices[voice].kill_pending = 0; @@ -1400,31 +1407,32 @@ guswave_start_note (int dev, int voice, int note_num, int volume) if (voices[voice].sample_pending >= 0) { - RESTORE_INTR (flags); + RESTORE_INTR (flags); /* Run temporarily with interrupts enabled */ guswave_set_instr (voices[voice].dev_pending, voice, voices[voice].sample_pending); voices[voice].sample_pending = -1; DISABLE_INTR (flags); + gus_select_voice (voice); /* Reselect the voice (just to be sure) */ } if ((mode & 0x01) || (int) ((gus_read16 (0x09) >> 4) < 2065)) { - ret_val = guswave_start_note2 (dev, voice, note_num, volume); + ret_val = guswave_start_note2 (gus_devnum, voice, note_num, volume); } else { - voices[voice].dev_pending = dev; + voices[voice].dev_pending = gus_devnum; voices[voice].note_pending = note_num; voices[voice].volume_pending = volume; voices[voice].volume_irq_mode = VMODE_START_NOTE; gus_rampoff (); gus_ramp_range (2000, 4065); - gus_ramp_rate (0, 63);/* Fastest possible rate */ + gus_ramp_rate (0, 63); /* Fastest possible rate */ gus_rampon (0x20 | 0x40); /* Ramp down, once, irq */ - RESTORE_INTR (flags); } } + RESTORE_INTR (flags); return ret_val; } @@ -1445,16 +1453,19 @@ guswave_open (int dev, int mode) { int err; - if (gus_busy) + if (mode & OPEN_WRITE && gus_busy[gus_devnum] || + mode & OPEN_READ && gus_busy[gus_dspnum]) return RET_ERROR (EBUSY); - gus_initialize (); + if(gus_busy[gus_devnum] == 0 && gus_busy[gus_dspnum] == 0) + gus_initialize (); + voice_alloc->timestamp = 0; if ((err = DMAbuf_open_dma (gus_devnum)) < 0) return err; RESET_WAIT_QUEUE (dram_sleeper, dram_sleep_flag); - gus_busy = 1; + gus_busy[gus_devnum] = 1; active_device = GUS_DEV_WAVE; gus_reset (); @@ -1465,7 +1476,7 @@ guswave_open (int dev, int mode) static void guswave_close (int dev) { - gus_busy = 0; + gus_busy[gus_devnum] = 0; active_device = 0; gus_reset (); @@ -1482,7 +1493,7 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr, unsigned long blk_size, blk_end, left, src_offs, target; - sizeof_patch = (long) &patch.data[0] - (long) &patch; /* Header size */ + sizeof_patch = (long) &patch.data[0] - (long) &patch; /* Header size */ if (format != GUS_PATCH) { @@ -1654,7 +1665,8 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr, addr, sizeof_patch + src_offs, blk_size); - DISABLE_INTR (flags); /******** INTERRUPTS DISABLED NOW ********/ + DISABLE_INTR (flags); +/******** INTERRUPTS DISABLED NOW ********/ gus_write8 (0x41, 0); /* Disable GF1 DMA */ DMAbuf_start_dma (gus_devnum, audio_devs[gus_devnum]->dmap->raw_buf_phys[0], @@ -1688,7 +1700,7 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr, if (audio_devs[gus_devnum]->dmachan > 3) dma_command |= 0x04; /* 16 bit DMA _channel_ */ - gus_write8 (0x41, dma_command); /* Lets bo luteet (=bugs) */ + gus_write8 (0x41, dma_command); /* Lets bo luteet (=bugs) */ /* * Sleep here until the DRAM DMA done interrupt is served @@ -1716,7 +1728,7 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr, free_mem_ptr += patch.len; if (!pmgr_flag) - pmgr_inform (dev, PM_E_PATCH_LOADED, instr, free_sample, 0, 0); + pmgr_inform (gus_devnum, PM_E_PATCH_LOADED, instr, free_sample, 0, 0); free_sample++; return 0; } @@ -1871,13 +1883,25 @@ guswave_hw_control (int dev, unsigned char *event) static int gus_sampling_set_speed (int speed) { + if (speed <= 0) - return gus_sampling_speed; + speed = gus_sampling_speed; + + if (speed < 4000) + speed = 4000; if (speed > 44100) speed = 44100; gus_sampling_speed = speed; + + if (only_read_access) + { + /* Compute nearest valid recording speed and return it */ + + speed = (9878400 / (gus_sampling_speed + 2)) / 16; + speed = (9878400 / (speed * 16)) - 2; + } return speed; } @@ -1961,8 +1985,6 @@ gus_sampling_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) return IOCTL_OUT (arg, RET_ERROR (EINVAL)); break; - default: - return RET_ERROR (EINVAL); } return RET_ERROR (EINVAL); } @@ -1975,17 +1997,36 @@ gus_sampling_reset (int dev) static int gus_sampling_open (int dev, int mode) { + int dev_flag; #ifdef GUS_NO_DMA printk ("GUS: DMA mode not enabled. Device not supported\n"); return RET_ERROR (ENXIO); #endif + dev_flag = 0; + if(mode & OPEN_WRITE) + { + if (gus_busy[gus_devnum]) + return RET_ERROR(EBUSY); + if(dev != gus_devnum) + return RET_ERROR(ENXIO); + dev_flag = gus_busy[gus_devnum] = 1; + } + if(mode & OPEN_READ) + { + if(gus_busy[gus_dspnum]) { + if (dev_flag) gus_busy[gus_devnum] = 0; + return RET_ERROR(EBUSY); + } + + if(dev != gus_dspnum) { + if (dev_flag) gus_busy[gus_devnum] = 0; + return RET_ERROR(ENXIO); + } + } + + if(gus_busy[gus_devnum] == 0 && gus_busy[gus_dspnum] == 0) + gus_initialize (); - if (gus_busy) - return RET_ERROR (EBUSY); - - gus_initialize (); - - gus_busy = 1; active_device = 0; gus_reset (); @@ -2000,6 +2041,7 @@ gus_sampling_open (int dev, int mode) recording_active = 1; set_input_volumes (); } + only_read_access = !(mode & OPEN_WRITE); return 0; } @@ -2007,10 +2049,12 @@ gus_sampling_open (int dev, int mode) static void gus_sampling_close (int dev) { - gus_reset (); - gus_busy = 0; - pcm_opened = 0; - active_device = 0; + gus_busy[dev] = 0; + if (gus_busy[gus_devnum] == 0 && gus_busy[gus_dspnum]) { + active_device = 0; + gus_reset(); + pcm_opened = 0; + } if (recording_active) set_input_volumes (); @@ -2024,16 +2068,16 @@ gus_sampling_update_volume (void) unsigned long flags; int voice; - DISABLE_INTR (flags); if (pcm_active && pcm_opened) for (voice = 0; voice < gus_sampling_channels; voice++) { + DISABLE_INTR (flags); gus_select_voice (voice); gus_rampoff (); gus_voice_volume (1530 + (25 * gus_pcm_volume)); gus_ramp_range (65, 1530 + (25 * gus_pcm_volume)); + RESTORE_INTR (flags); } - RESTORE_INTR (flags); } static void @@ -2075,7 +2119,7 @@ play_next_pcm_block (void) if (this_one == (pcm_nblk - 1)) /* Last fragment of the DRAM buffer */ { mode[chn] |= 0x08; /* Enable loop */ - ramp_mode[chn] = 0x03;/* Disable rollover bit */ + ramp_mode[chn] = 0x03; /* Disable rollover bit */ } else { @@ -2112,12 +2156,12 @@ play_next_pcm_block (void) gus_write_addr (0x02, chn * pcm_banksize, is16bits); /* Loop start */ if (chn != 0) - gus_write_addr (0x04, pcm_banksize + (pcm_bsize * pcm_nblk), + gus_write_addr (0x04, pcm_banksize + (pcm_bsize * pcm_nblk) - 1, is16bits); /* Loop end location */ } if (chn == 0) - gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], + gus_write_addr (0x04, dram_loc + pcm_datasize[this_one] - 1, is16bits); /* Loop end location */ else mode[chn] |= 0x08; /* Enable looping */ @@ -2130,7 +2174,7 @@ play_next_pcm_block (void) if (chn == 0) { mode[chn] &= ~0x08; /* Disable looping */ - mode[chn] |= 0x20;/* Enable IRQ at the end */ + mode[chn] |= 0x20; /* Enable IRQ at the end */ voices[0].loop_irq_mode = LMODE_PCM_STOP; ramp_mode[chn] = 0x03; /* No rollover bit */ } @@ -2193,12 +2237,12 @@ gus_transfer_output_block (int dev, unsigned long buf, this_one = pcm_current_block; gus_write8 (0x41, 0); /* Disable GF1 DMA */ - DMAbuf_start_dma (dev, buf + (chn * count), count, DMA_MODE_WRITE); + DMAbuf_start_dma (gus_devnum, buf + (chn * count), count, DMA_MODE_WRITE); address = this_one * pcm_bsize; address += chn * pcm_banksize; - if (audio_devs[dev]->dmachan > 3) + if (audio_devs[gus_devnum]->dmachan > 3) { hold_address = address; address = address >> 1; @@ -2215,7 +2259,7 @@ gus_transfer_output_block (int dev, unsigned long buf, else dma_command |= 0x80; /* Invert MSB */ - if (audio_devs[dev]->dmachan > 3) + if (audio_devs[gus_devnum]->dmachan > 3) dma_command |= 0x04; /* 16 bit DMA channel */ gus_write8 (0x41, dma_command); /* Kickstart */ @@ -2235,9 +2279,9 @@ gus_transfer_output_block (int dev, unsigned long buf, else { /* - * Left channel data. The right channel - * is transferred after DMA interrupt - */ + * Left channel data. The right channel + * is transferred after DMA interrupt + */ active_device = GUS_DEV_PCM_CONTINUE; } @@ -2251,8 +2295,8 @@ gus_sampling_output_block (int dev, unsigned long buf, int total_count, pcm_current_buf = buf; pcm_current_count = total_count; pcm_current_intrflag = intrflag; - pcm_current_dev = dev; - gus_transfer_output_block (dev, buf, total_count, intrflag, 0); + pcm_current_dev = gus_devnum; + gus_transfer_output_block (gus_devnum, buf, total_count, intrflag, 0); } static void @@ -2264,11 +2308,11 @@ gus_sampling_start_input (int dev, unsigned long buf, int count, DISABLE_INTR (flags); - DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); + DMAbuf_start_dma (gus_dspnum, buf, count, DMA_MODE_READ); mode = 0xa0; /* DMA IRQ enabled, invert MSB */ - if (audio_devs[dev]->dmachan > 3) + if (audio_devs[gus_dspnum]->dmachan > 3) mode |= 0x04; /* 16 bit DMA channel */ if (gus_sampling_channels > 1) mode |= 0x02; /* Stereo */ @@ -2364,8 +2408,8 @@ gus_copy_from_user (int dev, char *localbuf, int localoffs, } else { - int in_left = useroffs; - int in_right = useroffs + 1; + int in_left = useroffs / 2; + int in_right = useroffs / 2 + 1; short *out_left, *out_right; int i; @@ -2404,6 +2448,42 @@ static struct audio_operations gus_sampling_operations = gus_copy_from_user }; +static struct audio_operations gus_sampling_operations_read = +{ + "Gravis UltraSound - read only", + NEEDS_RESTART, + AFMT_U8 | AFMT_S16_LE, + NULL, + gus_sampling_open, + gus_sampling_close, + gus_sampling_output_block, + gus_sampling_start_input, + gus_sampling_ioctl, + gus_sampling_prepare_for_input, + gus_sampling_prepare_for_output, + gus_sampling_reset, + gus_sampling_reset, + gus_local_qlen, + gus_copy_from_user +}; + +static void +guswave_setup_voice (int dev, int voice, int chn) +{ + struct channel_info *info = + &synth_devs[gus_devnum]->chn_info[chn]; + + guswave_set_instr (gus_devnum, voice, info->pgm_num); + + voices[voice].expression_vol = + info->controllers[CTL_EXPRESSION]; /* Just msb */ + voices[voice].main_vol = + (info->controllers[CTL_MAIN_VOLUME] * 100) / 128; + voices[voice].panning = + (info->controllers[CTL_PAN] * 2) - 128; + voices[voice].bender = info->bender_value; +} + static void guswave_bender (int dev, int voice, int value) { @@ -2528,7 +2608,7 @@ guswave_patchmgr (int dev, struct patmgr_info *rec) if (offs < 0 || offs >= samples[sample].len) return RET_ERROR (EINVAL); /* Invalid offset */ - n = samples[sample].len - offs; /* Num of bytes left */ + n = samples[sample].len - offs; /* Num of bytes left */ if (l > n) l = n; @@ -2542,7 +2622,7 @@ guswave_patchmgr (int dev, struct patmgr_info *rec) */ offs += sample_ptrs[sample]; /* - * Begin offset + offset to DRAM + * Begin offsess + offset to DRAM */ for (n = 0; n < l; n++) @@ -2571,8 +2651,8 @@ guswave_patchmgr (int dev, struct patmgr_info *rec) * Invalid offset */ - n = samples[sample].len - offs; /* - * Nr of bytes left + n = samples[sample].len - offs; /* + * Nr of bytes left */ if (l > n) @@ -2587,7 +2667,7 @@ guswave_patchmgr (int dev, struct patmgr_info *rec) */ offs += sample_ptrs[sample]; /* - * Begin offset + offset to DRAM + * Begin offsess + offset to DRAM */ for (n = 0; n < l; n++) @@ -2607,12 +2687,12 @@ guswave_patchmgr (int dev, struct patmgr_info *rec) static int guswave_alloc (int dev, int chn, int note, struct voice_alloc_info *alloc) { - int i, p; + int i, p, best = -1, best_time = 0x7fffffff; p = alloc->ptr; /* - * First look for a completely stopped voice - */ + * First look for a completely stopped voice + */ for (i = 0; i < alloc->max_voice; i++) { @@ -2621,12 +2701,17 @@ guswave_alloc (int dev, int chn, int note, struct voice_alloc_info *alloc) alloc->ptr = p; return p; } + if (alloc->alloc_times[p] < best_time) + { + best = p; + best_time = alloc->alloc_times[p]; + } p = (p + 1) % alloc->max_voice; } /* - * Then look for a releasing voice - */ + * Then look for a releasing voice + */ for (i = 0; i < alloc->max_voice; i++) { @@ -2637,7 +2722,9 @@ guswave_alloc (int dev, int chn, int note, struct voice_alloc_info *alloc) } p = (p + 1) % alloc->max_voice; } - printk ("GUS: Out of free voices\n"); + + if (best >= 0) + p = best; alloc->ptr = p; return p; @@ -2664,7 +2751,8 @@ static struct synth_operations guswave_operations = guswave_volume_method, guswave_patchmgr, guswave_bender, - guswave_alloc + guswave_alloc, + guswave_setup_voice }; static void @@ -2676,10 +2764,10 @@ set_input_volumes (void) DISABLE_INTR (flags); /* - * Enable channels having vol > 10% - * Note! bit 0x01 means line in DISABLED while 0x04 means - * mic in ENABLED. - */ + * Enable channels having vol > 10% + * Note! bit 0x01 means line in DISABLED while 0x04 means + * mic in ENABLED. + */ if (gus_line_vol > 10) mask &= ~0x01; if (gus_mic_vol > 10) @@ -2688,8 +2776,8 @@ set_input_volumes (void) if (recording_active) { /* - * Disable channel, if not selected for recording - */ + * Disable channel, if not selected for recording + */ if (!(gus_recmask & SOUND_MASK_LINE)) mask |= 0x01; if (!(gus_recmask & SOUND_MASK_MIC)) @@ -2833,6 +2921,7 @@ gus_default_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg) static struct mixer_operations gus_mixer_operations = { + "Gravis Ultrasound", gus_default_mixer_ioctl }; @@ -2849,7 +2938,7 @@ gus_default_mixer_init (long mem_start) } long -gus_wave_init (long mem_start, int irq, int dma) +gus_wave_init (long mem_start, int irq, int dma, int dma_read) { unsigned long flags; unsigned char val; @@ -2857,11 +2946,29 @@ gus_wave_init (long mem_start, int irq, int dma) int gus_type = 0x24; /* 2.4 */ int mixer_type = 0; + if (irq < 0 || irq > 15) + { + printk ("ERROR! Invalid IRQ#%d. GUS Disabled", irq); + return mem_start; + } + + if (dma < 0 || dma > 7) + { + printk ("ERROR! Invalid DMA#%d. GUS Disabled", dma); + return mem_start; + } + + if (dma_read == 0) dma_read = dma; + if (dma_read < 0 || dma_read > 7) + { + printk ("ERROR! Invalid DMA#%d. GUS DMA-read disabled", dma_read); + dma_read = dma; + } /* - * Try to identify the GUS model. - * - * Versions < 3.6 don't have the digital ASIC. Try to probe it first. - */ + * Try to identify the GUS model. + * + * Versions < 3.6 don't have the digital ASIC. Try to probe it first. + */ DISABLE_INTR (flags); OUTB (0x20, gus_base + 0x0f); @@ -2871,9 +2978,9 @@ gus_wave_init (long mem_start, int irq, int dma) if (val != 0xff && (val & 0x06)) /* Should be 0x02?? */ { /* - * It has the digital ASIC so the card is at least v3.4. - * Next try to detect the true model. - */ + * It has the digital ASIC so the card is at least v3.4. + * Next try to detect the true model. + */ val = INB (u_MixSelect); @@ -2883,8 +2990,8 @@ gus_wave_init (long mem_start, int irq, int dma) * 10 and above is GUS MAX which has the CS4231 codec/mixer. * * Sorry. No GUS max support yet but it should be available - * soon after the SDK for GUS MAX is available. - */ + * soon after the SDK for GUS MAX is available. + */ if (val == 255 || val < 5) { @@ -2902,68 +3009,31 @@ gus_wave_init (long mem_start, int irq, int dma) model_num = "MAX"; gus_type = 0x40; mixer_type = CS4231; -#ifndef EXCLUDE_GUSMAX - { - unsigned char max_config = 0x40; /* Codec enable */ - - if (dma > 3) - max_config |= 0x30; /* 16 bit playback and capture DMAs */ - - max_config |= (gus_base >> 4) & 0x0f; /* Extract the X from 2X0 */ - - OUTB (max_config, gus_base + 0x106); /* UltraMax control */ - } - - if (ad1848_detect (gus_base + 0x10c)) - { - gus_mic_vol = gus_line_vol = gus_pcm_volume = 100; - gus_wave_volume = 90; - have_gus_max = 1; - ad1848_init ("gusmax0: <GUS MAX>", gus_base + 0x10c, - -irq, - dma, - dma); - } - else - printk ("[Where's the CS4231?]"); -#endif } } else { /* - * ASIC not detected so the card must be 2.2 or 2.4. - * There could still be the 16-bit/mixer daughter card. - * It has the same codec/mixer than MAX. - * At this time there is no support for it but it will appear soon. - */ + * ASIC not detected so the card must be 2.2 or 2.4. + * There could still be the 16-bit/mixer daughter card. + * It has the same codec/mixer than MAX. + * At this time there is no support for it but it will appear soon. + */ } -#ifdef __FreeBSD__ - printk ("gus0: <Gravis UltraSound %s (%dk)>", model_num, (int) gus_mem_size / 1024); -#else /* __FreeBSD__ */ +#if defined(__FreeBSD__) + printk ("gus0: <Gravis UltraSound %s (%dk)>", model_num, + (int) gus_mem_size / 1024); +#else printk (" <Gravis UltraSound %s (%dk)>", model_num, (int) gus_mem_size / 1024); -#endif /* __FreeBSD__ */ - -#ifndef SCO - sprintf (gus_info.name, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024); #endif - if (irq < 0 || irq > 15) - { - printk ("ERROR! Invalid IRQ#%d. GUS Disabled", irq); - return mem_start; - } - - if (dma < 0 || dma > 7) - { - printk ("ERROR! Invalid DMA#%d. GUS Disabled", dma); - return mem_start; - } + sprintf (gus_info.name, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024); gus_irq = irq; gus_dma = dma; + gus_dma_read = dma_read; if (num_synths >= MAX_SYNTH_DEV) printk ("GUS Error: Too many synthesizers\n"); @@ -2984,21 +3054,36 @@ gus_wave_init (long mem_start, int irq, int dma) { audio_devs[gus_devnum = num_audiodevs++] = &gus_sampling_operations; audio_devs[gus_devnum]->dmachan = dma; -#ifndef NO_AUTODMA audio_devs[gus_devnum]->buffcount = 1; -#else - audio_devs[gus_devnum]->flags &= ~DMA_AUTOMODE; - audio_devs[gus_devnum]->buffcount = DSP_BUFFCOUNT; -#endif audio_devs[gus_devnum]->buffsize = DSP_BUFFSIZE; + gus_dspnum = gus_devnum; + gus_busy[gus_devnum] = 0; + gus_busy[gus_dspnum] = 0; } else printk ("GUS: Too many PCM devices available\n"); - /* - * Mixer dependent initialization. - */ + if (num_audiodevs < MAX_AUDIO_DEV) + { + if(dma_read && dma != dma_read) + { + audio_devs[gus_dspnum = num_audiodevs++]= &gus_sampling_operations_read; + audio_devs[gus_dspnum]->dmachan = gus_dma_read; + audio_devs[gus_dspnum]->buffcount = 1; + audio_devs[gus_dspnum]->buffsize = DSP_BUFFSIZE; + gus_busy[gus_dspnum] = 0; + } + else + { + gus_dspnum = gus_devnum; + } + } + else + printk ("GUS READ: Too many PCM devices available\n"); + /* + * Mixer dependent initialization. + */ switch (mixer_type) { case ICS2101: @@ -3008,11 +3093,37 @@ gus_wave_init (long mem_start, int irq, int dma) case CS4231: /* Initialized elsewhere (ad1848.c) */ +#ifndef EXCLUDE_GUSMAX + { + unsigned char max_config = 0x40; /* Codec enable */ + long mixer_init_return; + + if (dma > 3) + max_config |= 0x30; /* 16 bit playback and capture DMAs */ + + max_config |= (gus_base >> 4) & 0x0f; /* Extract the X from 2X0 */ + + OUTB (max_config, gus_base + 0x106); /* UltraMax control */ + mixer_init_return = gus_default_mixer_init(mem_start); + + if (ad1848_detect (gus_base + 0x10c)) + { + gus_mic_vol = gus_line_vol = gus_pcm_volume = 100; + gus_wave_volume = 90; + have_gus_max = 1; + ad1848_init ("GUS MAX", gus_base + 0x10c, + -irq, + dma_read, /* read write reversed */ + dma); + } + else + printk ("[Where's the CS4231?]"); + return mixer_init_return; + } +#endif default: return gus_default_mixer_init (mem_start); } - - return mem_start; } static void @@ -3031,6 +3142,9 @@ do_loop_irq (int voice) */ gus_write8 (0x00, tmp); + if (tmp & 0x03) /* Voice stopped */ + voice_alloc->map[voice] = 0; + mode = voices[voice].loop_irq_mode; voices[voice].loop_irq_mode = 0; parm = voices[voice].loop_irq_parm; @@ -3042,9 +3156,9 @@ do_loop_irq (int voice) * Final loop finished, shoot volume down */ - if ((int) (gus_read16 (0x09) >> 4) < 100) /* - * Get current volume - */ + if ((int) (gus_read16 (0x09) >> 4) < 100) /* + * Get current volume + */ { gus_voice_off (); gus_rampoff (); @@ -3065,26 +3179,29 @@ do_loop_irq (int voice) pcm_active = 0; /* Signal to the play_next_pcm_block routine */ case LMODE_PCM: { - int orig_qlen = pcm_qlen; int flag; /* 0 or 2 */ pcm_qlen--; pcm_head = (pcm_head + 1) % pcm_nblk; - if (pcm_qlen) + if (pcm_qlen && pcm_active) { play_next_pcm_block (); } else { /* Underrun. Just stop the voice */ + gus_select_voice (0); /* Left channel */ + gus_voice_off (); + gus_rampoff (); + gus_select_voice (1); /* Right channel */ gus_voice_off (); gus_rampoff (); pcm_active = 0; } -/* - * If the queue was full before this interrupt, the DMA transfer was - * suspended. Let it continue now. - */ + /* + * If the queue was full before this interrupt, the DMA transfer was + * suspended. Let it continue now. + */ if (dma_active) { if (pcm_qlen == 0) @@ -3187,9 +3304,9 @@ gus_voice_irq (void) * Wave IRQ pending */ if (!(wave_ignore & voice_bit) && (int) voice < nr_voices) /* - * Not done - * yet - */ + * Not done + * yet + */ { wave_ignore |= voice_bit; do_loop_irq (voice); @@ -3199,9 +3316,9 @@ gus_voice_irq (void) * Volume IRQ pending */ if (!(volume_ignore & voice_bit) && (int) voice < nr_voices) /* - * Not done - * yet - */ + * Not done + * yet + */ { volume_ignore |= voice_bit; do_volume_irq (voice); @@ -3251,7 +3368,10 @@ guswave_dma_irq (void) * Sampling Irq pending */ { - DMAbuf_inputintr (gus_devnum); + if (gus_dma_read && gus_dma_read != gus_dma) + DMAbuf_inputintr (gus_dspnum); + else + DMAbuf_inputintr (gus_devnum); } } diff --git a/sys/i386/isa/sound/hex2hex.h b/sys/i386/isa/sound/hex2hex.h new file mode 100644 index 0000000..ecd7b4c --- /dev/null +++ b/sys/i386/isa/sound/hex2hex.h @@ -0,0 +1,97 @@ +/* + * This file is a part of configure.c + * + * hex2hex reads an input file in Intel HEX format and produces + * an (unsigned char) array which contains the bytes and writes it to the + * output file using C syntax + */ + +#define MAX_SIZE (256*1024) +#define ABANDON(why) { \ + fprintf(stderr, "%s: " why "\n", source); \ + fclose(inf);fclose(outf);return 0; \ + } + +int hex2hex(char *source, char *target, char *varline) +{ + FILE *inf, *outf; + + int i,l, c; + unsigned char buf[MAX_SIZE]; + + if ((inf=fopen(source, "r"))==NULL) + { + perror(source); + return 0; + } + + if ((outf=fopen(target, "w"))==NULL) + { + perror(target); + fclose(inf); + return 0; + } + + l=0; + + while ((c=getc(inf))!=EOF) + { + if (c == ':') /* Sync with beginning of line */ + { + int n, check; + unsigned char sum; + int addr; + int linetype; + + if (fscanf(inf, "%02x", &n) != 1) + ABANDON("File format error"); + sum = n; + + if (fscanf(inf, "%04x", &addr) != 1) + ABANDON("File format error"); + sum += addr/256; + sum += addr%256; + + if (fscanf(inf, "%02x", &linetype) != 1) + ABANDON("File format error"); + sum += linetype; + + if (linetype != 0) + continue; + + for (i=0;i<n;i++) + { + if (fscanf(inf, "%02x", &c) != 1) + ABANDON("File format error"); + if (addr >= MAX_SIZE) + ABANDON("File too large"); + buf[addr++] = c; + if (addr > l) + l = addr; + sum += c; + } + + if (fscanf(inf, "%02x", &check) != 1) + ABANDON("File format error"); + + sum = ~sum + 1; + if (check != sum) + ABANDON("Line checksum error"); + } + } + + fprintf(outf, "/*\n *\t Computer generated file. Do not edit.\n */\n"); + fprintf(outf, "%s[] = {\n", varline); + + for (i=0;i<l;i++) + { + if (i) fprintf(outf, ","); + if (i && !(i % 16)) fprintf(outf, "\n"); + fprintf(outf, "0x%02x", buf[i]); + } + + fprintf(outf, "\n};\n\n"); + fclose(inf); + fclose(outf); + return 1; +} diff --git a/sys/i386/isa/sound/ics2101.c b/sys/i386/isa/sound/ics2101.c index 190c74e..9df383a 100644 --- a/sys/i386/isa/sound/ics2101.c +++ b/sys/i386/isa/sound/ics2101.c @@ -25,13 +25,12 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * ics2101.c,v 1.4 1994/10/01 02:16:43 swallace Exp */ #include "sound_config.h" #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS) -#include <machine/ultrasound.h> +#include "ultrasound.h" #include "gus_hw.h" #define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \ @@ -50,10 +49,10 @@ scale_vol (int vol) { #if 1 /* - * Experimental volume scaling by Risto Kankkunen. - * This should give smoother volume response than just - * a plain multiplication. - */ + * Experimental volume scaling by Risto Kankkunen. + * This should give smoother volume response than just + * a plain multiplication. + */ int e; if (vol < 0) @@ -225,6 +224,7 @@ ics2101_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg) static struct mixer_operations ics2101_mixer_operations = { + "ICS2101 Multimedia Mixer", ics2101_mixer_ioctl }; @@ -238,9 +238,9 @@ ics2101_mixer_init (long mem_start) mixer_devs[num_mixers++] = &ics2101_mixer_operations; /* - * Some GUS v3.7 cards had some channels flipped. Disable - * the flipping feature if the model id is other than 5. - */ + * Some GUS v3.7 cards had some channels flipped. Disable + * the flipping feature if the model id is other than 5. + */ if (INB (u_MixSelect) != 5) { diff --git a/sys/i386/isa/sound/local.h b/sys/i386/isa/sound/local.h index 00d7d97..b45b0ac 100644 --- a/sys/i386/isa/sound/local.h +++ b/sys/i386/isa/sound/local.h @@ -5,7 +5,6 @@ #define DSP_BUFFSIZE 65536 #define SELECTED_SOUND_OPTIONS 0xffffffff -#define SOUND_VERSION_STRING "2.90-2" #define SOUND_CONFIG_DATE "Sun Feb 5 14:38:12 EST 1995" #define SOUND_CONFIG_BY "freebsd-hackers" #define SOUND_CONFIG_HOST "freefall" @@ -17,6 +16,8 @@ #define KERNEL_SOUNDCARD #endif +#define ALLOW_SELECT + /* PSS code does not work */ #ifndef EXCLUDE_PSS #define EXCLUDE_PSS @@ -32,9 +33,28 @@ #define EXCLUDE_GUS16 #endif -#include "gusmax.h" -#if NGUSMAX == 0 && !defined(EXCLUDE_GUSMAX) -#define EXCLUDE_GUSMAX +#include "mss.h" +#if NMSS == 0 && !defined(EXCLUDE_MSS) +#define EXCLUDE_MSS +#endif + +#include "trix.h" +#if NTRIX == 0 && !defined(EXCLUDE_TRIX) +#define EXCLUDE_TRIX +#endif + +#include "sscape.h" +#if NSSCAPE == 0 && !defined(EXCLUDE_SSCAPE) +#define EXCLUDE_SSCAPE +#endif + +#if !defined(GUSMAX) && !defined(EXCLUDE_GUSMAX) +# define EXCLUDE_GUSMAX +# if defined(EXCLUDE_GUS16) && defined(EXCLUDE_MSS) && !defined(EXCLUDE_AD1848) +# define EXCLUDE_AD1848 +# endif +#else +# define GUSMAX_MIXER #endif #include <sb.h> @@ -67,11 +87,6 @@ #define EXCLUDE_YM3812 #endif -#include "mss.h" -#if NMSS == 0 && !defined(EXCLUDE_MSS) -#define EXCLUDE_MSS -#endif - #include "uart.h" #if NUART == 0 && !defined(EXCLUDE_UART6850) #define EXCLUDE_UART6850 diff --git a/sys/i386/isa/sound/mad16.h b/sys/i386/isa/sound/mad16.h new file mode 100644 index 0000000..0370973 --- /dev/null +++ b/sys/i386/isa/sound/mad16.h @@ -0,0 +1,91 @@ + +/* + * Initialization code for OPTI MAD16 interface chip by + * Davor Jadrijevic <davor@emard.pub.hr> + * (Included by ad1848.c when MAD16 support is enabled) + * + * It looks like MAD16 is similar than the Mozart chip (OAK OTI-601). + * It could be even possible that these chips are exactly the same. Can + * anybody confirm this? + */ + +static void wr_a_mad16(int base, int v, int a) +{ + OUTB(a, base + 0xf); + OUTB(v, base + 0x11); +} + +static void wr_b_mad16(int base, int v, int a) +{ + OUTB(a, base + 0xf); + OUTB(v, base + 0xd); +} + +/* +static int rd_a_mad16(int base, int a) +{ + OUTB(a, base + 0xf); + return INB(base + 0x11); +} +*/ + +static int rd_b_mad16(int base, int a) +{ + OUTB(a, base + 0xf); + return INB(base + 0xd); +} + +/* +static int rd_0_mad16(int base, int a) +{ + OUTB(a, base + 0xf); + return INB(base + 0xf); +} + +static void wr_ad(int base, int v, int a) +{ + OUTB(a, base + 4); + OUTB(v, base + 5); +} + +static int rd_ad(int base, int a) +{ + OUTB(a, base + 4); + return INB(base + 5); +} +*/ + +static int mad16init(int adr) +{ + int j; + long i; + + static int ad1848_bases[] = +{ 0x220, -1, -1, 0x240, -1, -1, -1, -1, 0x530, 0xE80, 0xF40, 0x604, 0 }; + + int mad16_base = 0xf80, ad1848_base; + + + for(j = 0; (j < 16) && (ad1848_bases[j] != 0); j++) + if(adr == ad1848_bases[j]) + break; + + if( (ad1848_base = ad1848_bases[j]) < 0x530) + { + printk("Unknown MAD16 setting 0x%3X\n", adr); + return -1; + } + + /* printk("OPTi MAD16 WSS at 0x%3X\n", ad1848_base); */ + + rd_b_mad16(mad16_base, 0xe2); + wr_a_mad16(mad16_base, 0x1a, 0xe2); + wr_b_mad16(mad16_base, j * 16 + 1, 0xe2); + wr_a_mad16(mad16_base, 0x1a, 0xe2); + for( i = 0; i < 10000; i++) + if( (INB(ad1848_base+4) & 0x80) == 0 ) + break; + + return 0; +}; + diff --git a/sys/i386/isa/sound/midi_ctrl.h b/sys/i386/isa/sound/midi_ctrl.h index 3aa0f17..8b68c7d 100644 --- a/sys/i386/isa/sound/midi_ctrl.h +++ b/sys/i386/isa/sound/midi_ctrl.h @@ -1,18 +1,15 @@ -/* - * midi_ctrl.h,v 1.2 1994/10/01 02:16:45 swallace Exp - */ static unsigned char ctrl_def_values[128] = { - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 0 to 7 */ - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 8 to 15 */ - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 16 to 23 */ - 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 24 to 31 */ + 0x40,0x40,0x40,0x40, 0x40,0x40,0x40,0x40, /* 0 to 7 */ + 0x40,0x40,0x40,0x40, 0x40,0x40,0x40,0x40, /* 8 to 15 */ + 0x40,0x40,0x40,0x40, 0x40,0x40,0x40,0x40, /* 16 to 23 */ + 0x40,0x40,0x40,0x40, 0x40,0x40,0x40,0x40, /* 24 to 31 */ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 32 to 39 */ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 40 to 47 */ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 48 to 55 */ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 56 to 63 */ - + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 64 to 71 */ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 72 to 79 */ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 80 to 87 */ diff --git a/sys/i386/isa/sound/midi_synth.c b/sys/i386/isa/sound/midi_synth.c index d63e1ab..e2a1c2c 100644 --- a/sys/i386/isa/sound/midi_synth.c +++ b/sys/i386/isa/sound/midi_synth.c @@ -25,9 +25,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * midi_synth.c,v 1.2 1994/10/01 02:16:46 swallace Exp */ +#define USE_SEQ_MACROS +#define USE_SIMPLE_MACROS + #include "sound_config.h" #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MIDI) @@ -41,6 +43,61 @@ DEFINE_WAIT_QUEUE (sysex_sleeper, sysex_sleep_flag); static int midi2synth[MAX_MIDI_DEV]; static unsigned char prev_out_status[MAX_MIDI_DEV]; +#define STORE(cmd) \ +{ \ + int len; \ + unsigned char obuf[8]; \ + cmd; \ + seq_input_event(obuf, len); \ +} +#define _seqbuf obuf +#define _seqbufptr 0 +#define _SEQ_ADVBUF(x) len=x + +void +do_midi_msg (int synthno, unsigned char *msg, int mlen) +{ + switch (msg[0] & 0xf0) + { + case 0x90: + if (msg[2] != 0) + { + STORE (SEQ_START_NOTE (synthno, msg[0] & 0x0f, msg[1], msg[2])); + break; + } + msg[2] = 64; + + case 0x80: + STORE (SEQ_STOP_NOTE (synthno, msg[0] & 0x0f, msg[1], msg[2])); + break; + + case 0xA0: + STORE (SEQ_KEY_PRESSURE (synthno, msg[0] & 0x0f, msg[1], msg[2])); + break; + + case 0xB0: + STORE (SEQ_CONTROL (synthno, msg[0] & 0x0f, + msg[1], msg[2])); + break; + + case 0xC0: + STORE (SEQ_SET_PATCH (synthno, msg[0] & 0x0f, msg[1])); + break; + + case 0xD0: + STORE (SEQ_CHN_PRESSURE (synthno, msg[0] & 0x0f, msg[1])); + break; + + case 0xE0: + STORE (SEQ_BENDER (synthno, msg[0] & 0x0f, + (msg[1] % 0x7f) | ((msg[2] & 0x7f) << 7))); + break; + + default: + printk ("MPU: Unknown midi channel message %02x\n", msg[0]); + } +} + static void midi_outc (int midi_dev, int data) { @@ -70,7 +127,7 @@ midi_outc (int midi_dev, int data) static int prefix_cmd (int midi_dev, unsigned char status) { - if (midi_devs[midi_dev]->prefix_cmd == NULL) + if ((char *) midi_devs[midi_dev]->prefix_cmd == NULL) return 1; return midi_devs[midi_dev]->prefix_cmd (midi_dev, status); @@ -80,6 +137,20 @@ static void midi_synth_input (int dev, unsigned char data) { int orig_dev; + struct midi_input_info *inc; + + static unsigned char len_tab[] = /* # of data bytes following a status + */ + { + 2, /* 8x */ + 2, /* 9x */ + 2, /* Ax */ + 2, /* Bx */ + 1, /* Cx */ + 1, /* Dx */ + 2, /* Ex */ + 0 /* Fx */ + }; if (dev < 0 || dev > num_synths) return; @@ -88,7 +159,86 @@ midi_synth_input (int dev, unsigned char data) return; orig_dev = midi2synth[dev]; + inc = &midi_devs[orig_dev]->in_info; + switch (inc->m_state) + { + case MST_INIT: + if (data & 0x80) /* MIDI status byte */ + { + if ((data & 0xf0) == 0xf0) /* Common message */ + { + switch (data) + { + case 0xf0: /* Sysex */ + inc->m_state = MST_SYSEX; + break; /* Sysex */ + + case 0xf1: /* MTC quarter frame */ + case 0xf3: /* Song select */ + inc->m_state = MST_DATA; + inc->m_ptr = 1; + inc->m_left = 1; + inc->m_buf[0] = data; + break; + + case 0xf2: /* Song position pointer */ + inc->m_state = MST_DATA; + inc->m_ptr = 1; + inc->m_left = 2; + inc->m_buf[0] = data; + break; + + default: + inc->m_buf[0] = data; + inc->m_ptr = 1; + do_midi_msg (dev, inc->m_buf, inc->m_ptr); + inc->m_ptr = 0; + inc->m_left = 0; + } + } + else + { + inc->m_state = MST_DATA; + inc->m_ptr = 1; + inc->m_left = len_tab[(data >> 4) - 8]; + inc->m_buf[0] = inc->m_prev_status = data; + } + } + else if (inc->m_prev_status & 0x80) /* Ignore if no previous status (yet) */ + { /* Data byte (use running status) */ + inc->m_state = MST_DATA; + inc->m_ptr = 2; + inc->m_left = len_tab[(data >> 4) - 8] - 1; + inc->m_buf[0] = inc->m_prev_status; + inc->m_buf[1] = data; + } + break; /* MST_INIT */ + + case MST_DATA: + inc->m_buf[inc->m_ptr++] = data; + if (--inc->m_left <= 0) + { + inc->m_state = MST_INIT; + do_midi_msg (dev, inc->m_buf, inc->m_ptr); + inc->m_ptr = 0; + } + break; /* MST_DATA */ + + case MST_SYSEX: + if (data == 0xf7) /* Sysex end */ + { + inc->m_state = MST_INIT; + inc->m_left = 0; + inc->m_ptr = 0; + } + break; /* MST_SYSEX */ + + default: + printk ("MIDI%d: Unexpected state %d (%02x)\n", orig_dev, inc->m_state, + (int) data); + inc->m_state = MST_INIT; + } } static void @@ -156,9 +306,9 @@ midi_synth_kill_note (int dev, int channel, int note, int velocity) if (msg == 0x90) /* * Running status = Note on */ - midi_outc (orig_dev, 0);/* - * Note on with velocity 0 == note - * off + midi_outc (orig_dev, 0); /* + * Note on with velocity 0 == note + * off */ else midi_outc (orig_dev, velocity); @@ -262,6 +412,8 @@ midi_synth_open (int dev, int mode) { int orig_dev = synth_devs[dev]->midi_dev; int err; + unsigned long flags; + struct midi_input_info *inc; if (orig_dev < 0 || orig_dev > num_midis) return RET_ERROR (ENXIO); @@ -273,6 +425,16 @@ midi_synth_open (int dev, int mode) midi_synth_input, midi_synth_output)) < 0) return err; + inc = &midi_devs[orig_dev]->in_info; + + DISABLE_INTR (flags); + inc->m_busy = 0; + inc->m_state = MST_INIT; + inc->m_ptr = 0; + inc->m_left = 0; + inc->m_prev_status = 0x00; + RESTORE_INTR (flags); + return 1; } @@ -282,8 +444,8 @@ midi_synth_close (int dev) int orig_dev = synth_devs[dev]->midi_dev; /* - * Shut up the synths by sending just single active sensing message. - */ + * Shut up the synths by sending just single active sensing message. + */ midi_devs[orig_dev]->putc (orig_dev, 0xfe); midi_devs[orig_dev]->close (orig_dev); @@ -304,6 +466,7 @@ midi_synth_load_patch (int dev, int format, snd_rw_buf * addr, int i; unsigned long left, src_offs, eox_seen = 0; int first_byte = 1; + int hdr_size = (unsigned long) &sysex.data[0] - (unsigned long) &sysex; if (!prefix_cmd (orig_dev, 0xf0)) return 0; @@ -314,20 +477,20 @@ midi_synth_load_patch (int dev, int format, snd_rw_buf * addr, return RET_ERROR (EINVAL); } - if (count < sizeof (struct sysex_info)) + if (count < hdr_size) { printk ("MIDI Error: Patch header too short\n"); return RET_ERROR (EINVAL); } - count -= sizeof (struct sysex_info); + count -= hdr_size; /* * Copy the header from user space but ignore the first bytes which have * been transferred already. */ - COPY_FROM_USER (&((char *) &sysex)[offs], addr, offs, sizeof (struct sysex_info) - offs); + COPY_FROM_USER (&((char *) &sysex)[offs], addr, offs, hdr_size - offs); if (count < sysex.len) { @@ -345,21 +508,20 @@ midi_synth_load_patch (int dev, int format, snd_rw_buf * addr, { unsigned char data; - GET_BYTE_FROM_USER (data, addr, sizeof (struct sysex_info) + i); + GET_BYTE_FROM_USER (data, addr, hdr_size + i); - if (first_byte && data != 0xf0) - midi_outc (orig_dev, 0xf0); /* Sysex start */ + eox_seen = (i > 0 && data & 0x80); /* End of sysex */ - eox_seen = (data == 0xf7);/* - * Last byte was end of sysex - */ + if (eox_seen && data != 0xf7) + data = 0xf7; if (i == 0) { - if (data != 0xf0) /* - * Sysex start - */ - return RET_ERROR (EINVAL); + if (data != 0xf0) + { + printk ("Error: Sysex start missing\n"); + return RET_ERROR (EINVAL); + } } while (!midi_devs[orig_dev]->putc (orig_dev, (unsigned char) (data & 0xff)) && @@ -407,6 +569,7 @@ midi_synth_aftertouch (int dev, int channel, int pressure) } else if (!prefix_cmd (orig_dev, pressure)) return; + midi_outc (orig_dev, pressure); } @@ -459,7 +622,8 @@ midi_synth_bender (int dev, int channel, int value) prev_chn = prev_out_status[orig_dev] & 0x0f; if (msg != 0xd0 || prev_chn != channel) /* - * * Test for running status */ + * Test for running status + */ { if (!prefix_cmd (orig_dev, 0xe0 | (channel & 0x0f))) return; @@ -472,4 +636,9 @@ midi_synth_bender (int dev, int channel, int value) midi_outc (orig_dev, (value >> 7) & 0x7f); } +void +midi_synth_setup_voice (int dev, int voice, int channel) +{ +} + #endif diff --git a/sys/i386/isa/sound/midi_synth.h b/sys/i386/isa/sound/midi_synth.h index 373cd01..22f56ac 100644 --- a/sys/i386/isa/sound/midi_synth.h +++ b/sys/i386/isa/sound/midi_synth.h @@ -1,6 +1,3 @@ -/* - * midi_synth.h,v 1.2 1994/10/01 02:16:47 swallace Exp - */ int midi_synth_ioctl (int dev, unsigned int cmd, unsigned int arg); int midi_synth_kill_note (int dev, int channel, int note, int velocity); @@ -17,6 +14,7 @@ void midi_synth_aftertouch (int dev, int channel, int pressure); void midi_synth_controller (int dev, int channel, int ctrl_num, int value); int midi_synth_patchmgr (int dev, struct patmgr_info *rec); void midi_synth_bender (int dev, int chn, int value); +void midi_synth_setup_voice (int dev, int voice, int chn); #ifndef _MIDI_SYNTH_C_ @@ -43,6 +41,8 @@ static struct synth_operations std_midi_synth = midi_synth_panning, NULL, midi_synth_patchmgr, - midi_synth_bender + midi_synth_bender, + NULL, /* alloc_voice */ + midi_synth_setup_voice }; #endif diff --git a/sys/i386/isa/sound/midibuf.c b/sys/i386/isa/sound/midibuf.c index d7f4d3c..accc6a0 100644 --- a/sys/i386/isa/sound/midibuf.c +++ b/sys/i386/isa/sound/midibuf.c @@ -25,7 +25,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * midibuf.c,v 1.6 1994/10/01 02:16:48 swallace Exp */ #include "sound_config.h" @@ -121,7 +120,10 @@ midi_input_intr (int dev, unsigned char data) if (SOMEONE_WAITING (input_sleeper[dev], input_sleep_flag[dev])) WAKE_UP (input_sleeper[dev], input_sleep_flag[dev]); } - +#if defined(__FreeBSD__) + if (selinfo[dev].si_pid) + selwakeup(&selinfo[dev]); +#endif } static void @@ -130,6 +132,10 @@ midi_output_intr (int dev) /* * Currently NOP */ +#if defined(__FreeBSD__) + if (selinfo[dev].si_pid) + selwakeup(&selinfo[dev]); +#endif } static void @@ -185,8 +191,8 @@ MIDIbuf_open (int dev, struct fileinfo *file) } /* - * Interrupts disabled. Be careful - */ + * Interrupts disabled. Be careful + */ DISABLE_INTR (flags); if ((err = midi_devs[dev]->open (dev, mode, @@ -246,14 +252,14 @@ MIDIbuf_release (int dev, struct fileinfo *file) DISABLE_INTR (flags); /* - * Wait until the queue is empty - */ + * Wait until the queue is empty + */ if (mode != OPEN_READ) { - midi_devs[dev]->putc (dev, 0xfe); /* - * Active sensing to shut the - * devices + midi_devs[dev]->putc (dev, 0xfe); /* + * Active sensing to shut the + * devices */ while (!PROCESS_ABORTING (midi_sleeper[dev], midi_sleep_flag[dev]) && @@ -380,22 +386,32 @@ MIDIbuf_ioctl (int dev, struct fileinfo *file, dev = dev >> 4; - switch (cmd) + if (((cmd >> 8) & 0xff) == 'C') { + if (midi_devs[dev]->coproc) /* Coprocessor ioctl */ + return midi_devs[dev]->coproc->ioctl (midi_devs[dev]->coproc->devc, cmd, arg, 0); + else + printk ("/dev/midi%d: No coprocessor for this device\n", dev); - case SNDCTL_MIDI_PRETIME: - val = IOCTL_IN (arg); - if (val < 0) - val = 0; - - val = (HZ * val) / 10; - parms[dev].prech_timeout = val; - return IOCTL_OUT (arg, val); - break; - - default: - return midi_devs[dev]->ioctl (dev, cmd, arg); + return RET_ERROR (EREMOTEIO); } + else + switch (cmd) + { + + case SNDCTL_MIDI_PRETIME: + val = IOCTL_IN (arg); + if (val < 0) + val = 0; + + val = (HZ * val) / 10; + parms[dev].prech_timeout = val; + return IOCTL_OUT (arg, val); + break; + + default: + return midi_devs[dev]->ioctl (dev, cmd, arg); + } } #ifdef ALLOW_SELECT @@ -409,8 +425,12 @@ MIDIbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wai case SEL_IN: if (!DATA_AVAIL (midi_in_buf[dev])) { +#if defined(__FreeBSD__) + selrecord(wait, &selinfo[dev]); +#else input_sleep_flag[dev].mode = WK_SLEEP; select_wait (&input_sleeper[dev], wait); +#endif return 0; } return 1; @@ -419,8 +439,12 @@ MIDIbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wai case SEL_OUT: if (SPACE_AVAIL (midi_out_buf[dev])) { +#if defined(__FreeBSD__) + selrecord(wait, &selinfo[dev]); +#else midi_sleep_flag[dev].mode = WK_SLEEP; select_wait (&midi_sleeper[dev], wait); +#endif return 0; } return 1; diff --git a/sys/i386/isa/sound/mpu401.c b/sys/i386/isa/sound/mpu401.c index 5d07842..7b1616d 100644 --- a/sys/i386/isa/sound/mpu401.c +++ b/sys/i386/isa/sound/mpu401.c @@ -25,7 +25,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * mpu401.c,v 1.9 1994/10/01 02:16:49 swallace Exp + * Modified: + * Riccardo Facchetti 24 Mar 1995 + * - Added the Audio Excel DSP 16 initialization routine. */ #define USE_SEQ_MACROS @@ -35,7 +37,8 @@ #ifdef CONFIGURE_SOUNDCARD -#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI) +#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI) +#include "coproc.h" static int init_sequence[20]; /* NOTE! pos 0 = len, start pos 1. */ static int timer_mode = TMR_INTERNAL, timer_caps = TMR_INTERNAL; @@ -76,7 +79,7 @@ struct mpu_config int m_left; unsigned char last_status; void (*inputintr) (int dev, unsigned char data); - unsigned short controls[32]; + int shared_irq; }; #define DATAPORT(base) (base) @@ -102,7 +105,9 @@ static struct mpu_config dev_conf[MAX_MIDI_DEV] = {0}}; static int n_mpu_devs = 0; -static int irq2dev[16]; +static int irq2dev[16] = +{-1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1}; static int reset_mpu401 (struct mpu_config *devc); static void set_uart_mode (int dev, struct mpu_config *devc, int arg); @@ -129,7 +134,7 @@ static struct synth_info mpu_synth_info[MAX_MIDI_DEV]; #define ST_SONGSEL 103 /* Song select */ #define ST_SONGPOS 104 /* Song position pointer */ -static unsigned char len_tab[] =/* # of data bytes following a status +static unsigned char len_tab[] = /* # of data bytes following a status */ { 2, /* 8x */ @@ -143,7 +148,6 @@ static unsigned char len_tab[] =/* # of data bytes following a status }; #define STORE(cmd) \ -if (devc->opened & OPEN_READ) \ { \ int len; \ unsigned char obuf[8]; \ @@ -154,73 +158,10 @@ if (devc->opened & OPEN_READ) \ #define _seqbufptr 0 #define _SEQ_ADVBUF(x) len=x -static void -do_midi_msg (struct mpu_config *devc, unsigned char *msg, int mlen) -{ - switch (msg[0] & 0xf0) - { - case 0x90: - if (msg[2] != 0) - { - STORE (SEQ_START_NOTE (devc->synthno, msg[0] & 0x0f, msg[1], msg[2])); - break; - } - msg[2] = 64; - - case 0x80: - STORE (SEQ_STOP_NOTE (devc->synthno, msg[0] & 0x0f, msg[1], msg[2])); - break; - - case 0xA0: - STORE (SEQ_KEY_PRESSURE (devc->synthno, msg[0] & 0x0f, msg[1], msg[2])); - break; - - case 0xB0: - /* - * Fix the controller value (combine MSB and LSB) - */ - if (msg[1] < 64) - { - int ctrl = msg[1]; - - if (ctrl < 32) - { - devc->controls[ctrl] = (msg[2] & 0x7f) << 7; - } - else - { - ctrl -= 32; - devc->controls[ctrl] = - (devc->controls[ctrl] & ~0x7f) | (msg[2] & 0x7f); - } - STORE (SEQ_CONTROL (devc->synthno, msg[0] & 0x0f, - msg[1], devc->controls[ctrl])); - } - else - STORE (SEQ_CONTROL (devc->synthno, msg[0] & 0x0f, msg[1], msg[2])); - break; - - case 0xC0: - STORE (SEQ_SET_PATCH (devc->synthno, msg[0] & 0x0f, msg[1])); - break; - - case 0xD0: - STORE (SEQ_CHN_PRESSURE (devc->synthno, msg[0] & 0x0f, msg[1])); - break; - - case 0xE0: - STORE (SEQ_BENDER (devc->synthno, msg[0] & 0x0f, - (msg[1] % 0x7f) | ((msg[2] & 0x7f) << 7))); - break; - - default: - printk ("MPU: Unknown midi channel message %02x\n", msg[0]); - } -} - static int mpu_input_scanner (struct mpu_config *devc, unsigned char midic) { + switch (devc->m_state) { case ST_INIT: @@ -278,6 +219,7 @@ mpu_input_scanner (struct mpu_config *devc, unsigned char midic) int msg = (midic & 0xf0) >> 4; devc->m_state = ST_DATABYTE; + if (msg < 8) /* Data byte */ { /* printk("midi msg (running status) "); */ @@ -292,7 +234,7 @@ mpu_input_scanner (struct mpu_config *devc, unsigned char midic) if (devc->m_left <= 0) { devc->m_state = ST_INIT; - do_midi_msg (devc, devc->m_buf, devc->m_ptr); + do_midi_msg (devc->synthno, devc->m_buf, devc->m_ptr); devc->m_ptr = 0; } } @@ -321,7 +263,7 @@ mpu_input_scanner (struct mpu_config *devc, unsigned char midic) else { devc->last_status = midic; - /* printk("midi msg "); */ + /* printk ("midi msg "); */ msg -= 8; devc->m_left = len_tab[msg]; @@ -331,7 +273,7 @@ mpu_input_scanner (struct mpu_config *devc, unsigned char midic) if (devc->m_left <= 0) { devc->m_state = ST_INIT; - do_midi_msg (devc, devc->m_buf, devc->m_ptr); + do_midi_msg (devc->synthno, devc->m_buf, devc->m_ptr); devc->m_ptr = 0; } } @@ -364,8 +306,8 @@ mpu_input_scanner (struct mpu_config *devc, unsigned char midic) devc->m_state = ST_INIT; /* - * Real time messages - */ + * Real time messages + */ case 0xf8: /* midi clock */ devc->m_state = ST_INIT; @@ -437,7 +379,7 @@ mpu_input_scanner (struct mpu_config *devc, unsigned char midic) if ((--devc->m_left) <= 0) { devc->m_state = ST_INIT; - do_midi_msg (devc, devc->m_buf, devc->m_ptr); + do_midi_msg (devc->synthno, devc->m_buf, devc->m_ptr); devc->m_ptr = 0; } break; @@ -455,16 +397,19 @@ mpu401_input_loop (struct mpu_config *devc) { unsigned long flags; int busy; + int n; DISABLE_INTR (flags); busy = devc->m_busy; devc->m_busy = 1; RESTORE_INTR (flags); - if (busy) + if (busy) /* Already inside the scanner */ return; - while (input_avail (devc->base)) + n = 50; + + while (input_avail (devc->base) && n-- > 0) { unsigned char c = read_data (devc->base); @@ -480,7 +425,7 @@ mpu401_input_loop (struct mpu_config *devc) } void -mpuintr (int irq) +mpuintr (INT_HANDLER_PARMS (irq, dummy)) { struct mpu_config *devc; int dev; @@ -498,15 +443,20 @@ mpuintr (int irq) dev = irq2dev[irq]; if (dev == -1) { - printk ("MPU-401: Interrupt #%d?\n", irq); + /* printk ("MPU-401: Interrupt #%d?\n", irq); */ return; } devc = &dev_conf[dev]; - if (devc->base != 0 && (devc->opened & OPEN_READ || devc->mode == MODE_SYNTH)) - if (input_avail (devc->base)) + if (input_avail (devc->base)) + if (devc->base != 0 && (devc->opened & OPEN_READ || devc->mode == MODE_SYNTH)) mpu401_input_loop (devc); + else + { + /* Dummy read (just to acknowledge the interrupt) */ + read_data (devc->base); + } } @@ -530,9 +480,40 @@ mpu401_open (int dev, int mode, return RET_ERROR (EBUSY); } + /* + * Verify that the device is really running. + * Some devices (such as Ensoniq SoundScape don't + * work before the on board processor (OBP) is initialized + * by downloadin it's microcode. + */ + + if (!devc->initialized) + { + if (mpu401_status (devc->base) == 0xff) /* Bus float */ + { + printk ("MPU-401: Device not initialized properly\n"); + return RET_ERROR (EIO); + } + reset_mpu401 (devc); + } + irq2dev[devc->irq] = dev; - if ((err = snd_set_irq_handler (devc->irq, mpuintr) < 0)) - return err; + if (devc->shared_irq == 0) + if ((err = snd_set_irq_handler (devc->irq, mpuintr, midi_devs[dev]->info.name) < 0)) + { + return err; + } + + if (midi_devs[dev]->coproc) + if ((err = midi_devs[dev]->coproc-> + open (midi_devs[dev]->coproc->devc, COPR_MIDI)) < 0) + { + if (devc->shared_irq == 0) + snd_release_irq (devc->irq); + printk ("MPU-401: Can't access coprocessor device\n"); + + return err; + } set_uart_mode (dev, devc, 1); devc->mode = MODE_MIDI; @@ -559,9 +540,12 @@ mpu401_close (int dev) */ devc->mode = 0; - snd_release_irq (devc->irq); + if (devc->shared_irq == 0) + snd_release_irq (devc->irq); devc->inputintr = NULL; - irq2dev[devc->irq] = -1; + + if (midi_devs[dev]->coproc) + midi_devs[dev]->coproc->close (midi_devs[dev]->coproc->devc, COPR_MIDI); devc->opened = 0; } @@ -581,16 +565,16 @@ mpu401_out (int dev, unsigned char midi_byte) */ if (input_avail (devc->base)) - mpu401_input_loop (devc); + { + mpu401_input_loop (devc); + } #endif /* * Sometimes it takes about 13000 loops before the output becomes ready * (After reset). Normally it takes just about 10 loops. */ - for (timeout = 30000; timeout > 0 && !output_ready (devc->base); timeout--); /* - * Wait - */ + for (timeout = 3000; timeout > 0 && !output_ready (devc->base); timeout--); DISABLE_INTR (flags); if (!output_ready (devc->base)) @@ -634,34 +618,42 @@ mpu401_command (int dev, mpu_command_rec * cmd) * (After reset). Normally it takes just about 10 loops. */ - for (timeout = 500000; timeout > 0 && !output_ready (devc->base); timeout--); + timeout = 30000; +retry: + if (timeout-- <= 0) + { + printk ("MPU-401: Command (0x%x) timeout\n", (int) cmd->cmd); + return RET_ERROR (EIO); + } DISABLE_INTR (flags); + if (!output_ready (devc->base)) { - printk ("MPU-401: Command (0x%x) timeout\n", (int) cmd->cmd); RESTORE_INTR (flags); - return RET_ERROR (EIO); + goto retry; } write_command (devc->base, cmd->cmd); ok = 0; - for (timeout = 500000; timeout > 0 && !ok; timeout--) + for (timeout = 50000; timeout > 0 && !ok; timeout--) if (input_avail (devc->base)) - if (mpu_input_scanner (devc, read_data (devc->base)) == MPU_ACK) - ok = 1; + { + if (mpu_input_scanner (devc, read_data (devc->base)) == MPU_ACK) + ok = 1; + } if (!ok) { RESTORE_INTR (flags); - printk ("MPU: No ACK to command (0x%x)\n", (int) cmd->cmd); + /* printk ("MPU: No ACK to command (0x%x)\n", (int) cmd->cmd); */ return RET_ERROR (EIO); } if (cmd->nr_args) for (i = 0; i < cmd->nr_args; i++) { - for (timeout = 30000; timeout > 0 && !output_ready (devc->base); timeout--); + for (timeout = 3000; timeout > 0 && !output_ready (devc->base); timeout--); if (!mpu401_out (dev, cmd->data[i])) { @@ -688,7 +680,7 @@ mpu401_command (int dev, mpu_command_rec * cmd) if (!ok) { RESTORE_INTR (flags); - printk ("MPU: No response(%d) to command (0x%x)\n", i, (int) cmd->cmd); + /* printk ("MPU: No response(%d) to command (0x%x)\n", i, (int) cmd->cmd); */ return RET_ERROR (EIO); } } @@ -858,31 +850,64 @@ mpu_synth_open (int dev, int mode) midi_dev = synth_devs[dev]->midi_dev; if (midi_dev < 0 || midi_dev > num_midis) - return RET_ERROR (ENXIO); + { + return RET_ERROR (ENXIO); + } devc = &dev_conf[midi_dev]; + /* + * Verify that the device is really running. + * Some devices (such as Ensoniq SoundScape don't + * work before the on board processor (OBP) is initialized + * by downloadin it's microcode. + */ + + if (!devc->initialized) + { + if (mpu401_status (devc->base) == 0xff) /* Bus float */ + { + printk ("MPU-401: Device not initialized properly\n"); + return RET_ERROR (EIO); + } + reset_mpu401 (devc); + } + if (devc->opened) { printk ("MPU-401: Midi busy\n"); return RET_ERROR (EBUSY); } - devc->opened = mode; devc->mode = MODE_SYNTH; devc->synthno = dev; devc->inputintr = NULL; irq2dev[devc->irq] = midi_dev; - if ((err = snd_set_irq_handler (devc->irq, mpuintr) < 0)) - return err; + if (devc->shared_irq == 0) + if ((err = snd_set_irq_handler (devc->irq, mpuintr, midi_devs[midi_dev]->info.name) < 0)) + { + return err; + } + + if (midi_devs[midi_dev]->coproc) + if ((err = midi_devs[midi_dev]->coproc-> + open (midi_devs[midi_dev]->coproc->devc, COPR_MIDI)) < 0) + { + if (devc->shared_irq == 0) + snd_release_irq (devc->irq); + printk ("MPU-401: Can't access coprocessor device\n"); + + return err; + } + devc->opened = mode; reset_mpu401 (devc); if (mode & OPEN_READ) { - exec_cmd (midi_dev, 0x34, 0); /* Return timing bytes in stop mode */ exec_cmd (midi_dev, 0x8B, 0); /* Enable data in stop mode */ + exec_cmd (midi_dev, 0x34, 0); /* Return timing bytes in stop mode */ } return 0; @@ -900,11 +925,14 @@ mpu_synth_close (int dev) exec_cmd (midi_dev, 0x15, 0); /* Stop recording, playback and MIDI */ exec_cmd (midi_dev, 0x8a, 0); /* Disable data in stopped mode */ + if (devc->shared_irq == 0) + snd_release_irq (devc->irq); + devc->inputintr = NULL; + + if (midi_devs[midi_dev]->coproc) + midi_devs[midi_dev]->coproc->close (midi_devs[midi_dev]->coproc->devc, COPR_MIDI); devc->opened = 0; devc->mode = 0; - snd_release_irq (devc->irq); - devc->inputintr = NULL; - irq2dev[devc->irq] = -1; } #define MIDI_SYNTH_NAME "MPU-401 UART Midi" @@ -931,7 +959,9 @@ static struct synth_operations mpu401_synth_proto = midi_synth_panning, NULL, midi_synth_patchmgr, - midi_synth_bender + midi_synth_bender, + NULL, /* alloc */ + midi_synth_setup_voice }; static struct synth_operations mpu401_synth_operations[MAX_MIDI_DEV]; @@ -940,6 +970,7 @@ static struct midi_operations mpu401_midi_proto = { {"MPU-401 Midi", 0, MIDI_CAP_MPU401, SNDCARD_MPU401}, NULL, + {0}, mpu401_open, mpu401_close, mpu401_ioctl, @@ -963,25 +994,28 @@ mpu401_chk_version (struct mpu_config *devc) if ((tmp = exec_cmd (num_midis, 0xAC, 0)) < 0) return; + + if ((tmp & 0xf0) > 0x20) /* Why it's larger than 2.x ??? */ + return; + devc->version = tmp; if ((tmp = exec_cmd (num_midis, 0xAD, 0)) < 0) - return; + { + devc->version = 0; + return; + } devc->revision = tmp; } long attach_mpu401 (long mem_start, struct address_info *hw_config) { - int i; unsigned long flags; char revision_char; struct mpu_config *devc; - for (i = 0; i < 16; i++) - irq2dev[i] = -1; - if (num_midis >= MAX_MIDI_DEV) { printk ("MPU-401: Too many midi devices detected\n"); @@ -1001,18 +1035,20 @@ attach_mpu401 (long mem_start, struct address_info *hw_config) devc->timer_flag = 0; devc->m_busy = 0; devc->m_state = ST_INIT; + devc->shared_irq = hw_config->always_detect; - for (i = 0; i < 32; i++) - devc->controls[i] = 0x2000; - - if (!reset_mpu401 (devc)) - return mem_start; + if (!hw_config->always_detect) + { + /* Verify the hardware again */ + if (!reset_mpu401 (devc)) + return mem_start; - DISABLE_INTR (flags); - mpu401_chk_version (devc); - if (devc->version == 0) - mpu401_chk_version (devc); - RESTORE_INTR (flags); + DISABLE_INTR (flags); + mpu401_chk_version (devc); + if (devc->version == 0) + mpu401_chk_version (devc); + RESTORE_INTR (flags); + } if (devc->version == 0) { @@ -1049,20 +1085,18 @@ attach_mpu401 (long mem_start, struct address_info *hw_config) MPU_CAP_CLS | MPU_CAP_2PORT; revision_char = (devc->revision == 0x7f) ? 'M' : ' '; -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) printk ("mpu0: <MQX-%d%c MIDI Interface>", #else printk (" <MQX-%d%c MIDI Interface>", #endif ports, revision_char); -#ifndef SCO sprintf (mpu_synth_info[num_midis].name, "MQX-%d%c MIDI Interface #%d", ports, revision_char, n_mpu_devs); -#endif } else { @@ -1073,7 +1107,7 @@ attach_mpu401 (long mem_start, struct address_info *hw_config) devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_FSK; -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) printk ("mpu0: <MPU-401 MIDI Interface %d.%d%c>", #else printk (" <MPU-401 MIDI Interface %d.%d%c>", @@ -1081,20 +1115,16 @@ attach_mpu401 (long mem_start, struct address_info *hw_config) (devc->version & 0xf0) >> 4, devc->version & 0x0f, revision_char); -#ifndef SCO sprintf (mpu_synth_info[num_midis].name, "MPU-401 %d.%d%c Midi interface #%d", (devc->version & 0xf0) >> 4, devc->version & 0x0f, revision_char, n_mpu_devs); -#endif } -#ifndef SCO strcpy (mpu401_midi_operations[num_midis].info.name, mpu_synth_info[num_midis].name); -#endif mpu401_synth_operations[num_midis].midi_dev = devc->devno = num_midis; mpu401_synth_operations[devc->devno].info = @@ -1103,6 +1133,7 @@ attach_mpu401 (long mem_start, struct address_info *hw_config) if (devc->capabilities & MPU_CAP_INTLG) /* Has timer */ mpu_timer_init (num_midis); + irq2dev[devc->irq] = num_midis; midi_devs[num_midis++] = &mpu401_midi_operations[devc->devno]; return mem_start; } @@ -1163,10 +1194,14 @@ set_uart_mode (int dev, struct mpu_config *devc, int arg) { if (!arg && devc->version == 0) - return; + { + return; + } if ((devc->uart_mode == 0) == (arg == 0)) - return; /* Already set */ + { + return; /* Already set */ + } reset_mpu401 (devc); /* This exits the uart mode */ @@ -1193,6 +1228,19 @@ probe_mpu401 (struct address_info *hw_config) tmp_devc.irq = hw_config->irq; tmp_devc.initialized = 0; +#if !defined(EXCLUDE_AEDSP16) && defined(AEDSP16_MPU401) + /* + * Initialize Audio Excel DSP 16 to MPU-401, before any operation. + */ + InitAEDSP16_MPU401 (hw_config); +#endif + + if (hw_config->always_detect) + return 1; + + if (INB (hw_config->io_base + 1) == 0xff) + return 0; /* Just bus float? */ + ok = reset_mpu401 (&tmp_devc); return ok; @@ -1216,11 +1264,11 @@ static unsigned long clocks2ticks (unsigned long clocks) { /* - * The MPU-401 supports just a limited set of possible timebase values. - * Since the applications require more choices, the driver has to - * program the HW to do it's best and to convert between the HW and - * actual timebases. - */ + * The MPU-401 supports just a limited set of possible timebase values. + * Since the applications require more choices, the driver has to + * program the HW to do it's best and to convert between the HW and + * actual timebases. + */ return ((clocks * curr_timebase) + (hw_timebase / 2)) / hw_timebase; } @@ -1278,8 +1326,8 @@ set_timer_mode (int midi_dev) { if (timer_mode & (TMR_MODE_MIDI | TMR_MODE_CLS)) { - exec_cmd (midi_dev, 0x82, 0); /* Use MIDI sync */ - exec_cmd (midi_dev, 0x91, 0); /* Enable ext MIDI ctrl */ + exec_cmd (midi_dev, 0x82, 0); /* Use MIDI sync */ + exec_cmd (midi_dev, 0x91, 0); /* Enable ext MIDI ctrl */ } else if (timer_mode & TMR_MODE_FSK) exec_cmd (midi_dev, 0x81, 0); /* Use FSK sync */ @@ -1490,8 +1538,6 @@ mpu_timer_ioctl (int dev, break; case SNDCTL_TMR_START: - if (tmr_running) - return 0; start_timer (midi_dev); return 0; break; diff --git a/sys/i386/isa/sound/opl3.c b/sys/i386/isa/sound/opl3.c index 9e76ff1..87487b6 100644 --- a/sys/i386/isa/sound/opl3.c +++ b/sys/i386/isa/sound/opl3.c @@ -25,11 +25,12 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * opl3.c,v 1.7 1994/10/01 02:16:50 swallace Exp */ /* * Major improvements to the FM handling 30AUG92 by Rob Hooft, + */ +/* * hooft@chem.ruu.nl */ @@ -45,6 +46,7 @@ * * OP4 * * begin here */ static int opl3_enabled = 0; +static int opl4_enabled = 0; static int left_address = 0x388, right_address = 0x388, both_address = 0; static int nr_voices = 9; @@ -188,7 +190,7 @@ opl3_detect (int ioaddr) * Note2! The chip is initialized if detected. */ - unsigned char stat1, stat2; + unsigned char stat1, stat2, signature; int i; if (already_initialized) @@ -201,22 +203,13 @@ opl3_detect (int ioaddr) if (opl3_enabled) ioaddr = left_address; - opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); /* - * Reset - * timers - * 1 - * and - * 2 - */ - opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); /* - * Reset the - * IRQ of FM - * * chicp - */ + /* Reset timers 1 and 2 */ + opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); - stat1 = INB (ioaddr); /* - * Read status register - */ + /* Reset the IRQ of the FM chip */ + opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); + + signature = stat1 = INB (ioaddr); /* Status register */ if ((stat1 & 0xE0) != 0x00) { @@ -225,23 +218,19 @@ opl3_detect (int ioaddr) */ } - opl3_command (ioaddr, TIMER1_REGISTER, 0xff); /* - * Set timer 1 to - * 0xff - */ + opl3_command (ioaddr, TIMER1_REGISTER, 0xff); /* Set timer1 to 0xff */ + opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER2_MASK | TIMER1_START); /* * Unmask and start timer 1 */ /* - * Now we have to delay at least 80 msec + * Now we have to delay at least 80 usec */ for (i = 0; i < 50; i++) - tenmicrosec (); /* - * To be sure - */ + tenmicrosec (); stat2 = INB (ioaddr); /* * Read status after timers have expired @@ -251,18 +240,10 @@ opl3_detect (int ioaddr) * Stop the timers */ - opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); /* - * Reset - * timers - * 1 - * and - * 2 - */ - opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); /* - * Reset the - * IRQ of FM - * * chicp - */ + /* Reset timers 1 and 2 */ + opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); + /* Reset the IRQ of the FM chip */ + opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); if ((stat2 & 0xE0) != 0xc0) { @@ -272,9 +253,41 @@ opl3_detect (int ioaddr) } /* - * There is a FM chicp in this address. Now set some default values. + * There is a FM chicp in this address. Detect the type (OPL2 to OPL4) */ + if (signature == 0x06) /* OPL2 */ + { + opl3_enabled = 0; + } + else if (signature == 0x00) /* OPL3 or OPL4 */ + { + unsigned char tmp; + + if (!opl3_enabled) /* Was not already enabled */ + { + left_address = ioaddr; + right_address = ioaddr + 2; + opl3_enabled = 1; + } + + /* + * Detect availability of OPL4 (_experimental_). Works propably + * only after a cold boot. In addition the OPL4 port + * of the chip may not be connected to the PC bus at all. + */ + + opl3_command (right_address, OPL3_MODE_REGISTER, 0x00); + opl3_command (right_address, OPL3_MODE_REGISTER, OPL3_ENABLE | OPL4_ENABLE); + + if ((tmp = INB (ioaddr)) == 0x02) /* Have a OPL4 */ + { + opl4_enabled = 1; + } + opl3_command (right_address, OPL3_MODE_REGISTER, 0); + + } + for (i = 0; i < 9; i++) opl3_command (ioaddr, KEYON_BLOCK + i, 0); /* * Note off @@ -373,14 +386,14 @@ char fm_volume_table[128] = -11, -11, -10, -10, -10, -9, -9, -8, /* * 24 - 31 */ - -8, -8, -7, -7, -7, -6, -6, -6,/* - * 32 - 39 + -8, -8, -7, -7, -7, -6, -6, -6, /* + * 32 - 39 */ - -5, -5, -5, -5, -4, -4, -4, -4,/* - * 40 - 47 + -5, -5, -5, -5, -4, -4, -4, -4, /* + * 40 - 47 */ - -3, -3, -3, -3, -2, -2, -2, -2,/* - * 48 - 55 + -3, -3, -3, -3, -2, -2, -2, -2, /* + * 48 - 55 */ -2, -1, -1, -1, -1, 0, 0, 0, /* * 56 - 63 @@ -472,13 +485,13 @@ set_voice_volume (int voice, int volume) calc_vol (&vol2, volume); } - opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1); /* - * Modulator - * volume + opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1); /* + * Modulator + * volume */ - opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], vol2); /* - * Carrier - * volume + opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], vol2); /* + * Carrier + * volume */ } else @@ -525,7 +538,7 @@ set_voice_volume (int voice, int volume) default: /* * Why ?? - */ ; + */ ; } opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1); @@ -857,12 +870,23 @@ opl3_reset (int dev) static int opl3_open (int dev, int mode) { + int i; + if (!opl3_ok) return RET_ERROR (ENXIO); if (opl3_busy) return RET_ERROR (EBUSY); opl3_busy = 1; + voice_alloc->max_voice = nr_voices = opl3_enabled ? 18 : 9; + voice_alloc->timestamp = 0; + + for (i = 0; i < 18; i++) + { + voice_alloc->map[i] = 0; + voice_alloc->alloc_times[i] = 0; + } + connection_mask = 0x00; /* * Just 2 OP voices */ @@ -876,6 +900,7 @@ opl3_close (int dev) { opl3_busy = 0; voice_alloc->max_voice = nr_voices = opl3_enabled ? 18 : 9; + fm_info.nr_drums = 0; fm_info.perc_mode = 0; @@ -1075,7 +1100,7 @@ opl3_bender (int dev, int voice, int value) static int opl3_alloc_voice (int dev, int chn, int note, struct voice_alloc_info *alloc) { - int i, p, avail_voices; + int i, p, best, first, avail_voices, best_time = 0x7fffffff; struct sbi_instrument *instr; int is4op; int instr_no; @@ -1096,21 +1121,22 @@ opl3_alloc_voice (int dev, int chn, int note, struct voice_alloc_info *alloc) if (is4op) { - p = 0; + first = p = 0; avail_voices = 6; } else { if (nr_voices == 12) /* 4 OP mode. Use the '2 OP only' voices first */ - p = 6; + first = p = 6; else - p = 0; + first = p = 0; avail_voices = nr_voices; } /* - * Now try to find a free voice - */ + * Now try to find a free voice + */ + best = first; for (i = 0; i < avail_voices; i++) { @@ -1118,15 +1144,36 @@ opl3_alloc_voice (int dev, int chn, int note, struct voice_alloc_info *alloc) { return p; } - p = (p + 1) % nr_voices; + if (alloc->alloc_times[p] < best_time) /* Find oldest playing note */ + { + best_time = alloc->alloc_times[p]; + best = p; + } + p = (p + 1) % avail_voices; } /* - * Insert some kind of priority mechanism here. - */ + * Insert some kind of priority mechanism here. + */ - printk ("OPL3: Out of free voices\n"); - return 0; /* All voices in use. Select the first one. */ + if (best < 0) + best = 0; + if (best > nr_voices) + best -= nr_voices; + + return best; /* All voices in use. Select the first one. */ +} + +static void +opl3_setup_voice (int dev, int voice, int chn) +{ + struct channel_info *info = + &synth_devs[dev]->chn_info[chn]; + + opl3_set_instr (dev, voice, + info->pgm_num); + + voices[voice].bender = info->bender_value; } static struct synth_operations opl3_operations = @@ -1150,7 +1197,8 @@ static struct synth_operations opl3_operations = opl3_volume_method, opl3_patchmgr, opl3_bender, - opl3_alloc_voice + opl3_alloc_voice, + opl3_setup_voice }; long @@ -1174,18 +1222,22 @@ opl3_init (long mem_start) opl3_ok = 1; if (opl3_enabled) { -#ifdef __FreeBSD__ - printk ("opl0: <Yamaha OPL-3 FM>"); + if (opl4_enabled) +#if defined(__FreeBSD__) + printk ("opl0: <Yamaha OPL4/OPL3 FM>"); + else + printk ("opl0: <Yamaha OPL-3 FM>"); #else - printk (" <Yamaha OPL-3 FM>"); + printk (" <Yamaha OPL4/OPL3 FM>"); + else + printk (" <Yamaha OPL-3 FM>"); #endif + fm_model = 2; voice_alloc->max_voice = nr_voices = 18; fm_info.nr_drums = 0; fm_info.capabilities |= SYNTH_CAP_OPL3; -#ifndef SCO strcpy (fm_info.name, "Yamaha OPL-3"); -#endif for (i = 0; i < 18; i++) if (physical_voices[i].ioaddr == USE_LEFT) @@ -1193,15 +1245,23 @@ opl3_init (long mem_start) else physical_voices[i].ioaddr = right_address; - /* Enable OPL-3 mode */ - opl3_command (right_address, OPL3_MODE_REGISTER, OPL3_ENABLE); - /* Select all 2-OP voices */ - opl3_command (right_address, CONNECTION_SELECT_REGISTER, 0x00); + opl3_command (right_address, OPL3_MODE_REGISTER, OPL3_ENABLE); /* + * Enable + * OPL-3 + * mode + */ + opl3_command (right_address, CONNECTION_SELECT_REGISTER, 0x00); /* + * Select + * all + * 2-OP + * * + * voices + */ } else { -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) printk ("opl0: <Yamaha 2-OP FM>"); #else printk (" <Yamaha 2-OP FM>"); diff --git a/sys/i386/isa/sound/opl3.h b/sys/i386/isa/sound/opl3.h index d5101cd..d25116b 100644 --- a/sys/i386/isa/sound/opl3.h +++ b/sys/i386/isa/sound/opl3.h @@ -24,7 +24,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: opl3.c,v 1.7 1994/10/01 02:16:50 swallace Exp */ /* @@ -36,8 +35,8 @@ * * The percussive mode is implemented in the left side only. * - * With the above exceptions the both sides can be operated independently. - * + * With the above exeptions the both sides can be operated independently. + * * A 4 OP voice can be created by setting the corresponding * bit at offset 4 of the right side. * @@ -46,7 +45,7 @@ * voice is made inaccessible. * * If a voice is set to the 2 OP mode, it works like 2 OP modes - * of the original YM3812 (AdLib). In addition the voice can + * of the original YM3812 (AdLib). In addition the voice can * be connected the left, right or both stereo channels. It can * even be left unconnected. This works with 4 OP voices also. * @@ -81,6 +80,7 @@ #define OPL3_MODE_REGISTER 0x05 /* Right side */ #define OPL3_ENABLE 0x01 +#define OPL4_ENABLE 0x02 #define KBD_SPLIT_REGISTER 0x08 /* Left side */ #define COMPOSITE_SINE_WAVE_MODE 0x80 /* Don't use with OPL-3? */ @@ -179,13 +179,13 @@ * 0 0 >+-1-+--2--3--4--> * * - * + * * +---+ * | | * 0 1 >+-1-+--2-+ * |-> * >--3----4-+ - * + * * +---+ * | | * 1 0 >+-1-+-----+ diff --git a/sys/i386/isa/sound/os.h b/sys/i386/isa/sound/os.h index 6076065..5b64f43 100644 --- a/sys/i386/isa/sound/os.h +++ b/sys/i386/isa/sound/os.h @@ -3,29 +3,6 @@ /* * OS specific settings for FreeBSD * - * Copyright by UWM - comments to soft-eng@cs.uwm.edu - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * * This chould be used as an example when porting the driver to a new * operating systems. * @@ -35,9 +12,7 @@ * * If you have to make changes to other than these two files, please contact me * before making the changes. It's possible that I have already made the - * change. - * - * os.h,v 1.13 1994/10/01 02:16:53 swallace Exp + * change. */ /* @@ -59,38 +34,47 @@ #include <i386/isa/isa_device.h> #include <machine/cpufunc.h> +/* These few lines are used by 386BSD (only??). */ + +#if NSND > 0 +#define CONFIGURE_SOUNDCARD +#else +#undef CONFIGURED_SOUNDCARD +#endif + + /* * Rest of the file is compiled only if the driver is really required. */ #ifdef CONFIGURE_SOUNDCARD -/* +/* * select() is currently implemented in Linux specific way. Don't enable. * I don't remember what the SHORT_BANNERS means so forget it. */ -#undef ALLOW_SELECT +/*#undef ALLOW_SELECT*/ #define SHORT_BANNERS /* The soundcard.h could be in a nonstandard place so inclyde it here. */ -#include <machine/soundcard.h> +#include "soundcard.h" /* * Here is the first portability problem. Every OS has it's own way to * pass a pointer to the buffer in read() and write() calls. In Linux it's * just a char*. In BSD it's struct uio. This parameter is passed to - * all functions called from read() or write(). Since nothing can be + * all functions called from read() or write(). Since nothing can be * assumed about this structure, the driver uses set of macros for - * accessing the user buffer. + * accessing the user buffer. * * The driver reads/writes bytes in the user buffer sequentially which * means that calls like uiomove() can be used. * * snd_rw_buf is the type which is passed to the device file specific * read() and write() calls. - * + * * The following macros are used to move date to and from the - * user buffer. These macros should be used only when the + * user buffer. These macros should be used only when the * target or source parameter has snd_rw_buf type. * The offs parameter is a offset relative to the beginning of * the user buffer. In Linux the offset is required but for example @@ -107,15 +91,17 @@ typedef struct uio snd_rw_buf; * user space. The count is number of bytes to be moved. */ #define COPY_FROM_USER(target, source, offs, count) \ - do { if (uiomove(target, count, (struct uio *)source)) { \ + do { if (uiomove((caddr_t ) target, count, (struct uio *)source)) { \ printf ("sb: Bad copyin()!\n"); \ } } while(0) + /* Like COPY_FOM_USER but for writes. */ + #define COPY_TO_USER(target, offs, source, count) \ do { if (uiomove(source, count, (struct uio *)target)) { \ printf ("sb: Bad copyout()!\n"); \ } } while(0) -/* +/* * The following macros are like COPY_*_USER but work just with one byte (8bit), * short (16 bit) or long (32 bit) at a time. * The same restrictions apply than for COPY_*_USER @@ -125,6 +111,9 @@ typedef struct uio snd_rw_buf; #define GET_WORD_FROM_USER(target, addr, offs) {uiomove((char*)&(target), 4, (struct uio *)addr);} #define PUT_WORD_TO_USER(addr, offs, data) {uiomove((char*)&(data), 4, (struct uio *)addr);} + +#define EREMOTEIO -1 + /* * The way how the ioctl arguments are passed is another nonportable thing. * In Linux the argument is just a pointer directly to the user segment. On @@ -161,8 +150,9 @@ typedef struct uio snd_rw_buf; */ struct snd_wait { - int mode; int aborting; - }; + int mode; + int aborting; +}; /* * DEFINE_WAIT_QUEUE is used where a wait queue is required. It must define @@ -185,7 +175,7 @@ struct snd_wait { * is aborts the process. This macro is called from close() to see if the * buffers should be discarded. If this kind info is not available, a constant * 1 or 0 could be returned (1 should be better than 0). - * I'm not sure if the following is correct for FreeBSD. + * I'm not sure if the following is correct for 386BSD. */ #define PROCESS_ABORTING(q, f) (f.aborting | curproc->p_siglist) @@ -194,7 +184,7 @@ struct snd_wait { * the process is resumed if it receives a signal. The following is propably * not the way how it should be done on 386bsd. * The on_what parameter is a wait_queue defined with DEFINE_WAIT_QUEUE(), - * and the second is a workarea parameter. The third is a timeout + * and the second is a workarea parameter. The third is a timeout * in ticks. Zero means no timeout. */ #define DO_SLEEP(q, f, time_limit) \ @@ -202,13 +192,13 @@ struct snd_wait { int flag, chn; \ f.mode = WK_SLEEP; \ q = &chn; \ - flag=tsleep((caddr_t)&(chn), (PRIBIO-5)|PCATCH, "sndint", time_limit); \ + flag=tsleep((caddr_t) &chn, (PRIBIO-5)|PCATCH, "sndint", time_limit); \ if(flag == ERESTART) f.aborting = 1;\ else f.aborting = 0;\ f.mode &= ~WK_SLEEP; \ } /* An the following wakes up a process */ -#define WAKE_UP(q, f) {f.mode = WK_WAKEUP;wakeup((caddr_t)q);} +#define WAKE_UP(q, f) {f.mode = WK_WAKEUP;wakeup((caddr_t) q);} /* * Timing macros. This driver assumes that there is a timer running in the @@ -220,11 +210,12 @@ struct snd_wait { #define HZ hz #endif -/* +/* * GET_TIME() returns current value of the counter incremented at timer * ticks. This can overflow, so the timeout might be real big... - * + * */ + extern unsigned long get_time(void); #define GET_TIME() get_time() /*#define GET_TIME() (lbolt) */ /* Returns current time (1/HZ secs since boot) */ @@ -250,11 +241,19 @@ extern unsigned long get_time(void); */ #define INB inb -/* +#define INW inb + +#if 0 +/* * The outb(0, 0x80) is just for slowdown. It's bit unsafe since * this address could be used for something usefull. */ #define OUTB(addr, data) {outb(data, addr);outb(0, 0x80);} +#define OUTW(addr, data) {outw(data, addr);outb(0, 0x80);} +#else +#define OUTB(addr, data) outb(data, addr) +#define OUTW(addr, data) outw(data, addr) +#endif /* memcpy() was not defined og 386bsd. Lets define it here */ #define memcpy(d, s, c) bcopy(s, d, c) @@ -267,9 +266,9 @@ extern unsigned long get_time(void); #define RET_ERROR(err) -(err) -/* - KERNEL_MALLOC() allocates requested number of memory and - KERNEL_FREE is used to free it. +/* + KERNEL_MALLOC() allocates requested number of memory and + KERNEL_FREE is used to free it. These macros are never called from interrupt, in addition the nbytes will never be more than 4096 bytes. Generally the driver will allocate memory in blocks of 4k. If the kernel has just a @@ -289,8 +288,8 @@ extern unsigned long get_time(void); * memory area. The type is the type of the mem_ptr. */ #define PERMANENT_MALLOC(typecast, mem_ptr, size, linux_ptr) \ - {(mem_ptr) = (typecast)malloc((size), M_DEVBUF, M_NOWAIT); \ - if (!(mem_ptr))panic("SOUND: Cannot allocate memory");} + {mem_ptr = (typecast)malloc(size, M_DEVBUF, M_NOWAIT); \ + if (!mem_ptr)panic("SOUND: Cannot allocate memory\n");} /* * The macro DEFINE_TIMER defines variables for the ACTIVATE_TIMER if @@ -310,11 +309,41 @@ extern unsigned long get_time(void); * The rest of this file is not complete yet. The functions using these * macros will not work */ -#define ALLOC_DMA_CHN(chn) ({ 0; }) +#define ALLOC_DMA_CHN(chn,deviceID) ({0; } ) #define RELEASE_DMA_CHN(chn) ({ 0; }) #define DMA_MODE_READ 0 #define DMA_MODE_WRITE 1 #define RELEASE_IRQ(irq_no) +/* + * The macro DECLARE_FILE() adds an entry to struct fileinfo referencing the + * connected filestructure. + * This entry must be initialized in sound_open() in soundcard.c + * + * ISSET_FILE_FLAG() allows checking of flags like O_NONBLOCK on files + * + */ + +#define DECLARE_FILE() struct file *filp +#ifdef notdef +#define ISSET_FILE_FLAG(fileinfo, flag) (fileinfo->filp->f_flag & (flag) ? \ + 1 : 0) +#else +#define ISSET_FILE_FLAG(fileinfo, flag) 0 +#endif +#define INT_HANDLER_PROTO() void(*hndlr)(int) +#define INT_HANDLER_PARMS(irq, parms) int irq +#define INT_HANDLER_CALL(irq) irq + +/* + * For select call... + */ +#ifdef ALLOW_SELECT +typedef struct proc select_table; +#define SEL_IN FREAD +#define SEL_OUT FWRITE +#define SEL_EX 0 +extern struct selinfo selinfo[]; +#endif #endif #endif diff --git a/sys/i386/isa/sound/pas.h b/sys/i386/isa/sound/pas.h index 78e90bf..54c6432 100644 --- a/sys/i386/isa/sound/pas.h +++ b/sys/i386/isa/sound/pas.h @@ -1,6 +1,3 @@ -/* - * pas.h,v 1.6 1994/10/01 12:42:17 ache Exp - */ /* */ /* Port addresses and bit fields for the Media Vision Pro AudioSpectrum second generation sound cards. */ /* */ @@ -45,9 +42,11 @@ #define WAIT_STATE 0xBF88 /* R W Control Four-bit bus wait-state count (~140ns ea.) */ #define BOARD_REV_ID 0x2789 /* R Control Extended Board Revision ID */ +#define CHIP_REV 0xFF88 /* R 0=PAS, 1=PAS+, 2=CDPC, 3=PAS16C, 4=PAS16D */ + #define SYSTEM_CONFIGURATION_1 0x8388 /* R W Control */ #define S_C_1_PCS_ENABLE 0x01 /* R W PC speaker 1=enable, 0=disable PC speaker emulation */ - #define S_C_1_PCM_CLOCK_SELECT 0x02 /* R W PCM 1=14.31818Mhz/12, 0=28.224Mhz master clock */ + #define S_C_1_PCM_CLOCK_SELECT 0x02 /* R W PCM 1=14.31818Mhz/12, 0=28.224Mhz master clock */ #define S_C_1_FM_EMULATE_CLOCK 0x04 /* R W FM 1=use 28.224Mhz/2, 0=use 14.31818Mhz clock */ #define S_C_1_PCS_STEREO 0x10 /* R W PC speaker 1=enable PC speaker stereo effect, 0=disable */ #define S_C_1_PCS_REALSOUND 0x20 /* R W PC speaker 1=enable RealSound enhancement, 0=disable */ @@ -62,6 +61,7 @@ #define IO_CONFIGURATION_1 0xF388 /* R W Control */ #define I_C_1_BOOT_RESET_ENABLE 0x80 /* R W Control 1=reset board on warm boot, 0=don't */ + #define I_C_1_JOYSTICK_ENABLE 0x40 /* R W Control 1=enable joystick port, 0=don't */ #define IO_CONFIGURATION_2 0xF389 /* R W Control */ #define I_C_2_PCM_DMA_DISABLED 0x00 /* R W PCM PCM DMA disabled */ #define IO_CONFIGURATION_3 0xF38A /* R W Control */ @@ -83,7 +83,7 @@ #define OPERATION_MODE_1 0xEF8B /* R Control */ #define O_M_1_CDROM_TYPE 0x03 /* R CD-ROM 3=SCSI, 2=Sony, 0=no CD-ROM interface */ - #define O_M_1_FM_TYPE 0x04 /* R FM 1=stereo, 0=mono FM chip */ + #define O_M_1_FM_TYPE 0x04 /* R FM 1=sterero, 0=mono FM chip */ #define O_M_1_PCM_TYPE 0x08 /* R PCM 1=16-bit Codec, 0=8-bit DAC */ #define OPERATION_MODE_2 0xFF8B /* R Control */ #define O_M_2_PCS_ENABLED 0x02 /* R PC speaker PC speaker emulation 1=enabled, 0=disabled */ @@ -114,7 +114,7 @@ struct { /* R W Mixer Filter translation */ unsigned int freq:24; unsigned int value:8; - } F_F_FILTER_translate[] = + } F_F_FILTER_translate[] = { { 73500, 0x01 }, /* 73500Hz - divide by 16 */ { 65333, 0x02 }, /* 65333Hz - divide by 18 */ { 49000, 0x09 }, /* 49000Hz - divide by 24 */ @@ -131,7 +131,6 @@ #define F_F_PCM_RATE_COUNTER 0x40 /* R W PCM 1=enable, 0=disable sample rate counter */ #define F_F_PCM_BUFFER_COUNTER 0x80 /* R W PCM 1=enable, 0=disable sample buffer counter */ -#define CHIP_REV 0xFF88 /* R Control 0=PAS, 1=PAS+, 2=CDPC, 3=PAS16C, 4=PAS16D */ #define PAS_NONE 0 #define PAS_PLUS 1 #define PAS_CDPC 2 @@ -142,7 +141,7 @@ unsigned char I_C_2_PCM_DMA_translate[] = /* R W PCM PCM DMA channel value translations */ { 4, 1, 2, 3, 0, 5, 6, 7 }; unsigned char I_C_3_PCM_IRQ_translate[] = /* R W PCM PCM IRQ level value translation */ - { 0, 0, 1, 2, 3, 4, 5, 6, 0, 1, 7, 8, 9, 0, 10, 11 }; + { 0, 0, 1, 2, 3, 4, 5, 6, 0, 1, 7, 8, 9, 0, 10, 11 }; unsigned char E_C_MPU401_IRQ_translate[] = /* R W MIDI MPU401 emulation IRQ value translation */ { 0x00, 0x00, 0x01, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x01, 0x05, 0x06, 0x07 }; unsigned char E_C_SB_IRQ_translate[] = /* R W PCM SB emulation IRQ translate */ @@ -150,7 +149,7 @@ unsigned char E_C_SB_DMA_translate[] = /* R W PCM SB emulation DMA translate */ { 0x00, 0x40, 0x80, 0xC0, 0, 0, 0, 0 }; unsigned char O_M_1_to_card[] = /* R W Control Translate (OM1 & 0x0f) to card type */ - { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 4, 0, 2, 3 }; + { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 4, 0, 2, 3 }; #else extern unsigned char I_C_2_PCM_DMA_translate[]; /* R W PCM PCM DMA channel value translations */ extern unsigned char I_C_3_PCM_IRQ_translate[]; /* R W PCM PCM IRQ level value translation */ @@ -251,4 +250,4 @@ #define MIDI_FIFO_STATUS 0x1B89 /* R W MIDI Midi fifo status */ #define MIDI_DATA 0x178A /* R W MIDI Midi data register */ -#define MIDI_INPUT_AVAILABLE 0x0f /* RW MIDI */ +#define MIDI_INPUT_AVAILABLE 0x0f /* RW MIDI */ diff --git a/sys/i386/isa/sound/pas2_card.c b/sys/i386/isa/sound/pas2_card.c index 13f2efc..1714156 100644 --- a/sys/i386/isa/sound/pas2_card.c +++ b/sys/i386/isa/sound/pas2_card.c @@ -26,7 +26,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * pas2_card.c,v 1.11 1994/10/01 12:42:17 ache Exp */ #include "sound_config.h" @@ -45,11 +44,11 @@ int translat_code; static int pas_intr_mask = 0; static int pas_irq = 0; -static char pas_model; -static unsigned char board_rev_id; +char pas_model; static char *pas_model_names[] = {"", "Pro AudioSpectrum+", "CDPC", "Pro AudioSpectrum 16", "Pro AudioSpectrum 16D"}; +extern void mix_write (unsigned char data, int ioaddr); /* * pas_read() and pas_write() are equivalents of INB() and OUTB() */ @@ -72,23 +71,6 @@ pas_write (unsigned char data, int ioaddr) OUTB (data, ioaddr ^ translat_code); } -/* - * The Revision D cards have a problem with their MVA508 interface. The - * kludge-o-rama fix is to make a 16-bit quantity with identical LSB and - * MSBs out of the output byte and to do a 16-bit out to the mixer port - - * 1. - */ - -void -mix_write (unsigned char data, int ioaddr) -{ - if (pas_model == PAS_16D) { - outw ((ioaddr ^ translat_code) - 1, data | (data << 8)); - outb (0, 0x80); - } else - OUTB (data, ioaddr ^ translat_code); -} - void pas2_msg (char *foo) { @@ -98,13 +80,13 @@ pas2_msg (char *foo) /******************* Begin of the Interrupt Handler ********************/ void -pasintr (int unused) +pasintr (INT_HANDLER_PARMS (irq, dummy)) { int status; status = pas_read (INTERRUPT_STATUS); - pas_write (status, INTERRUPT_STATUS); /* - * Clear interrupt + pas_write (status, INTERRUPT_STATUS); /* + * Clear interrupt */ if (status & I_S_PCM_SAMPLE_BUFFER_IRQ) @@ -136,7 +118,7 @@ pas_set_intr (int mask) if (!pas_intr_mask) { - if ((err = snd_set_irq_handler (pas_irq, pasintr)) < 0) + if ((err = snd_set_irq_handler (pas_irq, pasintr, "PAS16")) < 0) return err; } pas_intr_mask |= mask; @@ -201,9 +183,13 @@ config_pas_hw (struct address_info *hw_config) pas_write (S_M_PCM_RESET | S_M_FM_RESET | S_M_SB_RESET | S_M_MIXER_RESET /* * | * S_M_OPL3_DUAL_MONO - */ , SERIAL_MIXER); + */ , SERIAL_MIXER); - pas_write (I_C_1_BOOT_RESET_ENABLE, IO_CONFIGURATION_1); + pas_write (I_C_1_BOOT_RESET_ENABLE +#ifdef PAS_JOYSTICK_ENABLE + | I_C_1_JOYSTICK_ENABLE +#endif + ,IO_CONFIGURATION_1); if (pas_irq < 0 || pas_irq > 15) { @@ -238,9 +224,9 @@ config_pas_hw (struct address_info *hw_config) } /* - * This fixes the timing problems of the PAS due to the Symphony chipset - * as per Media Vision. Only define this if your PAS doesn't work correctly. - */ + * This fixes the timing problems of the PAS due to the Symphony chipset + * as per Media Vision. Only define this if your PAS doesn't work correctly. + */ #ifdef SYMPHONY_PAS OUTB (0x05, 0xa8); OUTB (0x60, 0xa9); @@ -380,14 +366,13 @@ attach_pas_card (long mem_start, struct address_info *hw_config) if (detect_pas_hw (hw_config)) { - board_rev_id = pas_read (BOARD_REV_ID); - if (pas_model = pas_read (CHIP_REV)) + if (pas_model = pas_read (CHIP_REV)) { #ifdef __FreeBSD__ - printk ("pas0: <%s rev %d>", pas_model_names[(int) pas_model], board_rev_id); -#else /* __FreeBSD__ */ + printk ("pas0: <%s rev %d>", pas_model_names[(int) pas_model], pas_read (BOARD_REV_ID)); +#else printk (" <%s rev %d>", pas_model_names[(int) pas_model], pas_read (BOARD_REV_ID)); -#endif /* __FreeBSD__ */ +#endif } if (config_pas_hw (hw_config)) diff --git a/sys/i386/isa/sound/pas2_midi.c b/sys/i386/isa/sound/pas2_midi.c index 7a2e238..6db884b 100644 --- a/sys/i386/isa/sound/pas2_midi.c +++ b/sys/i386/isa/sound/pas2_midi.c @@ -25,7 +25,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * pas2_midi.c,v 1.6 1994/10/01 02:16:55 swallace Exp */ #include "sound_config.h" @@ -84,8 +83,8 @@ pas_midi_open (int dev, int mode, if (mode == OPEN_READ || mode == OPEN_READWRITE) { - ctrl |= M_C_ENA_INPUT_IRQ;/* - * Enable input + ctrl |= M_C_ENA_INPUT_IRQ; /* + * Enable input */ input_opened = 1; } @@ -135,9 +134,9 @@ dump_to_midi (unsigned char midi_byte) fifo_space = ((x = pas_read (MIDI_FIFO_STATUS)) >> 4) & 0x0f; - if (fifo_space == 15 || (fifo_space < 2 && ofifo_bytes > 13)) /* - * Fifo - * full + if (fifo_space == 15 || (fifo_space < 2 && ofifo_bytes > 13)) /* + * Fifo + * full */ { return 0; /* @@ -240,6 +239,7 @@ static struct midi_operations pas_midi_operations = { {"Pro Audio Spectrum", 0, 0, SNDCARD_PAS}, &std_midi_synth, + {0}, pas_midi_open, pas_midi_close, pas_midi_ioctl, @@ -320,8 +320,10 @@ pas_midi_interrupt (void) RESTORE_INTR (flags); } +#if 0 if (stat & M_S_FRAMING_ERROR) printk ("MIDI framing error\n"); +#endif if (stat & M_S_OUTPUT_OVERRUN) { @@ -329,8 +331,8 @@ pas_midi_interrupt (void) ofifo_bytes = 100; } - pas_write (stat, MIDI_STATUS);/* - * Acknowledge interrupts + pas_write (stat, MIDI_STATUS); /* + * Acknowledge interrupts */ } diff --git a/sys/i386/isa/sound/pas2_mixer.c b/sys/i386/isa/sound/pas2_mixer.c index 18c64e5..0b143b3 100644 --- a/sys/i386/isa/sound/pas2_mixer.c +++ b/sys/i386/isa/sound/pas2_mixer.c @@ -27,7 +27,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: pas2_mixer.c,v 1.7 1994/10/01 02:16:56 swallace Exp $ */ #include "sound_config.h" @@ -36,18 +35,12 @@ #include "pas.h" -#define TRACE(what) /* - * * * (what) */ +#define TRACE(what) /* (what) */ extern int translat_code; +extern char pas_model; -static int rec_devices = (SOUND_MASK_MIC); /* - - - * * * * Default * - * recording * source - * - * * */ +static int rec_devices = (SOUND_MASK_MIC); /* Default recording source */ static int mode_control = 0; #define POSSIBLE_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \ @@ -60,53 +53,48 @@ static int mode_control = 0; static unsigned short levels[SOUND_MIXER_NRDEVICES] = { - 0x3232, /* - * Master Volume - */ - 0x3232, /* - * Bass - */ - 0x3232, /* - * Treble - */ - 0x5050, /* - * FM - */ - 0x4b4b, /* - * PCM - */ - 0x3232, /* - * PC Speaker - */ - 0x4b4b, /* - * Ext Line - */ - 0x4b4b, /* - * Mic - */ - 0x4b4b, /* - * CD - */ - 0x6464, /* - * Recording monitor - */ - 0x4b4b, /* - * SB PCM - */ - 0x6464}; /* - + 0x3232, /* Master Volume */ + 0x3232, /* Bass */ + 0x3232, /* Treble */ + 0x5050, /* FM */ + 0x4b4b, /* PCM */ + 0x3232, /* PC Speaker */ + 0x4b4b, /* Ext Line */ + 0x4b4b, /* Mic */ + 0x4b4b, /* CD */ + 0x6464, /* Recording monitor */ + 0x4b4b, /* SB PCM */ + 0x6464 /* Recording level */ +}; - * * * * Recording level */ +void +mix_write (unsigned char data, int ioaddr) +{ + /* + * The Revision D cards have a problem with their MVA508 interface. The + * kludge-o-rama fix is to make a 16-bit quantity with identical LSB and + * MSBs out of the output byte and to do a 16-bit out to the mixer port - + * 1. We need to do this because it isn't timing problem but chip access + * sequence problem. + */ + + if (pas_model == PAS_16D) + { + OUTW (data | (data << 8), (ioaddr ^ translat_code) - 1); + OUTB (0x80, 0); + } + else + pas_write (data, ioaddr); +} static int mixer_output (int right_vol, int left_vol, int div, int bits, - int mixer /* - * Input or output mixer - */ ) + int mixer) /* Input or output mixer */ { int left = left_vol * div / 100; int right = right_vol * div / 100; + if (bits & P_M_MV508_MIXER) { /* * Select input or output mixer @@ -161,9 +149,7 @@ pas_mixer_set (int whichDev, unsigned int level) switch (whichDev) { - case SOUND_MIXER_VOLUME: /* - * Master volume (0-63) - */ + case SOUND_MIXER_VOLUME: /* Master volume (0-63) */ levels[whichDev] = mixer_output (right, left, 63, P_M_MV508_MASTER_A, 0); break; @@ -171,62 +157,39 @@ pas_mixer_set (int whichDev, unsigned int level) * Note! Bass and Treble are mono devices. Will use just the left * channel. */ - case SOUND_MIXER_BASS: /* - * Bass (0-12) - */ + case SOUND_MIXER_BASS: /* Bass (0-12) */ levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_BASS, 0); break; - case SOUND_MIXER_TREBLE: /* - * Treble (0-12) - */ + case SOUND_MIXER_TREBLE: /* Treble (0-12) */ levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_TREBLE, 0); break; - case SOUND_MIXER_SYNTH: /* - * Internal synthesizer (0-31) - */ + case SOUND_MIXER_SYNTH: /* Internal synthesizer (0-31) */ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_FM, mixer); break; - case SOUND_MIXER_PCM: /* - * PAS PCM (0-31) - */ + case SOUND_MIXER_PCM: /* PAS PCM (0-31) */ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_PCM, mixer); break; - case SOUND_MIXER_ALTPCM: /* - * SB PCM (0-31) - */ + case SOUND_MIXER_ALTPCM: /* SB PCM (0-31) */ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SB, mixer); break; - case SOUND_MIXER_SPEAKER: /* - * PC speaker (0-31) - */ + case SOUND_MIXER_SPEAKER: /* PC speaker (0-31) */ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SPEAKER, mixer); break; - case SOUND_MIXER_LINE: /* - * External line (0-31) - */ + case SOUND_MIXER_LINE: /* External line (0-31) */ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_LINE, mixer); break; - case SOUND_MIXER_CD: /* - * CD (0-31) - */ + case SOUND_MIXER_CD: /* CD (0-31) */ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_CDROM, mixer); break; - case SOUND_MIXER_MIC: /* - * External microphone (0-31) - */ + case SOUND_MIXER_MIC: /* External microphone (0-31) */ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_MIC, mixer); break; - case SOUND_MIXER_IMIX: /* - * Recording monitor (0-31) (Only available * - * on the Output Mixer) - */ + case SOUND_MIXER_IMIX: /* Recording monitor (0-31) (Output mixer only) */ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_IMIXER, P_M_MV508_OUTPUTMIX); break; - case SOUND_MIXER_RECLEV: /* - * Recording level (0-15) - */ + case SOUND_MIXER_RECLEV: /* Recording level (0-15) */ levels[whichDev] = mixer_output (right, left, 15, P_M_MV508_MASTER_B, 0); break; @@ -254,9 +217,7 @@ pas_mixer_set (int whichDev, unsigned int level) if (level) mode_control |= P_M_MV508_LOUDNESS; set_mode (mode_control); - return !!level; /* - * 0 or 1 - */ + return !!level; /* 0 or 1 */ break; case SOUND_MIXER_RECSRC: @@ -306,7 +267,7 @@ pas_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg) return IOCTL_OUT (arg, pas_mixer_set (cmd & 0xff, IOCTL_IN (arg))); else { /* - * Read parameters + * Read parameters */ switch (cmd & 0xff) @@ -329,15 +290,11 @@ pas_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg) break; case SOUND_MIXER_CAPS: - return IOCTL_OUT (arg, 0); /* - * No special capabilities - */ + return IOCTL_OUT (arg, 0); /* No special capabilities */ break; case SOUND_MIXER_MUTE: - return IOCTL_OUT (arg, 0); /* - * No mute yet - */ + return IOCTL_OUT (arg, 0); /* No mute yet */ break; case SOUND_MIXER_ENHANCE: @@ -362,6 +319,7 @@ pas_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg) static struct mixer_operations pas_mixer_operations = { + "Pro Audio Spectrum 16", pas_mixer_ioctl }; diff --git a/sys/i386/isa/sound/pas2_pcm.c b/sys/i386/isa/sound/pas2_pcm.c index d07628f..26fc941 100644 --- a/sys/i386/isa/sound/pas2_pcm.c +++ b/sys/i386/isa/sound/pas2_pcm.c @@ -26,7 +26,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * pas2_pcm.c,v 1.7 1994/10/01 02:16:57 swallace Exp */ #include "sound_config.h" @@ -79,14 +78,14 @@ pcm_set_speed (int arg) tmp = pas_read (FILTER_FREQUENCY); -/* - * Set anti-aliasing filters according to sample rate. You really *NEED* - * to enable this feature for all normal recording unless you want to - * experiment with aliasing effects. - * These filters apply to the selected "recording" source. - * I (pfw) don't know the encoding of these 5 bits. The values shown - * come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/. - */ + /* + * Set anti-aliasing filters according to sample rate. You reall *NEED* + * to enable this feature for all normal recording unless you want to + * experiment with aliasing effects. + * These filters apply to the selected "recording" source. + * I (pfw) don't know the encoding of these 5 bits. The values shown + * come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/. + */ #if !defined NO_AUTO_FILTER_SET tmp &= 0xe0; if (pcm_speed >= 2 * 17897) @@ -129,8 +128,8 @@ pcm_set_channels (int arg) pas_write (pas_read (PCM_CONTROL) ^ P_C_PCM_MONO, PCM_CONTROL); pcm_channels = arg; - pcm_set_speed (pcm_speed);/* - * The speed must be reinitialized + pcm_set_speed (pcm_speed); /* + * The speed must be reinitialized */ } @@ -405,12 +404,7 @@ pas_pcm_init (long mem_start, struct address_info *hw_config) { audio_devs[my_devnum = num_audiodevs++] = &pas_pcm_operations; audio_devs[my_devnum]->dmachan = hw_config->dma; -#ifndef NO_AUTODMA audio_devs[my_devnum]->buffcount = 1; -#else - audio_devs[my_devnum]->flags &= ~DMA_AUTOMODE; - audio_devs[my_devnum]->buffcount = DSP_BUFFCOUNT; -#endif audio_devs[my_devnum]->buffsize = 2 * DSP_BUFFSIZE; } else diff --git a/sys/i386/isa/sound/patmgr.c b/sys/i386/isa/sound/patmgr.c index b4c4dc6..fc201dd 100644 --- a/sys/i386/isa/sound/patmgr.c +++ b/sys/i386/isa/sound/patmgr.c @@ -1,7 +1,7 @@ /* * sound/patmgr.c * - * The patch manager interface for the /dev/sequencer + * The patch maneger interface for the /dev/sequencer * * Copyright by Hannu Savolainen 1993 * @@ -25,7 +25,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * patmgr.c,v 1.7 1994/10/01 02:16:58 swallace Exp */ #define PATMGR_C @@ -132,7 +131,7 @@ pmgr_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) return RET_ERROR (EIO); } - COPY_FROM_USER ((caddr_t)mbox[dev], buf, 0, 4); + COPY_FROM_USER (mbox[dev], buf, 0, 4); if (*(unsigned char *) mbox[dev] == SEQ_FULLSIZE) { @@ -235,8 +234,12 @@ pmgr_inform (int dev, int event, unsigned long p1, unsigned long p2, printk (" PATMGR: Server %d mbox full. Why?\n", dev); else { - mbox[dev] = - (struct patmgr_info *) KERNEL_MALLOC (sizeof (struct patmgr_info)); + if ((mbox[dev] = + (struct patmgr_info *) KERNEL_MALLOC (sizeof (struct patmgr_info))) == NULL) + { + printk ("pmgr: Couldn't allocate memory for a message\n"); + return 0; + } mbox[dev]->key = PM_K_EVENT; mbox[dev]->command = event; diff --git a/sys/i386/isa/sound/sb.h b/sys/i386/isa/sound/sb.h index 0a7dd93..bb8ae12 100644 --- a/sys/i386/isa/sound/sb.h +++ b/sys/i386/isa/sound/sb.h @@ -1,6 +1,3 @@ -/* - * sb.h,v 1.2 1994/08/02 07:40:34 davidg Exp - */ #define DSP_RESET (sbc_base + 0x6) #define DSP_READ (sbc_base + 0xA) #define DSP_WRITE (sbc_base + 0xC) diff --git a/sys/i386/isa/sound/sb16_dsp.c b/sys/i386/isa/sound/sb16_dsp.c index e88dacc..c0b1bdf 100644 --- a/sys/i386/isa/sound/sb16_dsp.c +++ b/sys/i386/isa/sound/sb16_dsp.c @@ -27,7 +27,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * sb16_dsp.c,v 1.8 1994/10/01 02:17:02 swallace Exp */ #define DEB(x) @@ -43,11 +42,11 @@ extern int sbc_base; -static int sb16_dsp_ok = 0;/* +static int sb16_dsp_ok = 0; /* - * * * * Set to 1 after successful * - * * initialization */ + * * * * Set to 1 after successful * + * * initialization */ static int dsp_16bit = 0; static int dsp_stereo = 0; static int dsp_current_speed = 8000; /* @@ -79,6 +78,7 @@ static void sb16_dsp_halt (int dev); static int dsp_set_speed (int); static int dsp_set_stereo (int); static void dsp_cleanup (void); +int sb_reset_dsp (void); static struct audio_operations sb16_dsp_operations = { @@ -228,7 +228,7 @@ sb16_dsp_open (int dev, int mode) sb_reset_dsp (); - if (ALLOC_DMA_CHN (dma8)) + if (ALLOC_DMA_CHN (dma8, "SB16 (8bit)")) { printk ("SB16: Unable to grab DMA%d\n", dma8); sb_free_irq (); @@ -236,7 +236,7 @@ sb16_dsp_open (int dev, int mode) } if (dma16 != dma8) - if (ALLOC_DMA_CHN (dma16)) + if (ALLOC_DMA_CHN (dma16, "SB16 (16bit)")) { printk ("SB16: Unable to grab DMA%d\n", dma16); sb_free_irq (); @@ -436,6 +436,7 @@ sb16_dsp_halt (int dev) sb_dsp_command01 (0xda); sb_dsp_command01 (0xd0); } + DMAbuf_reset_dma (dev); } static void @@ -472,12 +473,10 @@ sb16_dsp_init (long mem_start, struct address_info *hw_config) if (sbc_major < 4) return mem_start; /* Not a SB16 */ -#ifndef SCO sprintf (sb16_dsp_operations.name, "SoundBlaster 16 %d.%d", sbc_major, sbc_minor); -#endif -#ifdef __FreeBSD__ - printk ("sbxvi0: <%s>", sb16_dsp_operations.name); +#if defined(__FreeBSD__) + printk ("sbxvo0: <%s>", sb16_dsp_operations.name); #else printk (" <%s>", sb16_dsp_operations.name); #endif @@ -486,12 +485,7 @@ sb16_dsp_init (long mem_start, struct address_info *hw_config) { audio_devs[my_dev = num_audiodevs++] = &sb16_dsp_operations; audio_devs[my_dev]->dmachan = hw_config->dma; -#ifndef NO_AUTODMA audio_devs[my_dev]->buffcount = 1; -#else - audio_devs[my_dev]->flags &= ~DMA_AUTOMODE; - audio_devs[my_dev]->buffcount = DSP_BUFFCOUNT; -#endif audio_devs[my_dev]->buffsize = DSP_BUFFSIZE; } else @@ -541,8 +535,8 @@ sb16_dsp_detect (struct address_info *hw_config) DEB (printk ("SoundBlaster 16: IRQ %d DMA %d OK\n", sb_config->irq, hw_config->dma)); /* - * dsp_showmessage(0xe3,99); - */ + * dsp_showmessage(0xe3,99); + */ sb16_dsp_ok = 1; return 1; } diff --git a/sys/i386/isa/sound/sb16_midi.c b/sys/i386/isa/sound/sb16_midi.c index f4114d9..3da8c0d 100644 --- a/sys/i386/isa/sound/sb16_midi.c +++ b/sys/i386/isa/sound/sb16_midi.c @@ -25,14 +25,13 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * sb16_midi.c,v 1.4 1994/10/01 02:17:03 swallace Exp */ #include "sound_config.h" #ifdef CONFIGURE_SOUNDCARD -#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16MIDI) && !defined(EXCLUDE_MIDI) +#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_MIDI) #include "sb.h" @@ -181,6 +180,7 @@ static struct midi_operations sb16midi_operations = { {"SoundBlaster 16 Midi", 0, 0, SNDCARD_SB16MIDI}, &std_midi_synth, + {0}, sb16midi_open, sb16midi_close, sb16midi_ioctl, @@ -225,11 +225,7 @@ attach_sb16midi (long mem_start, struct address_info *hw_config) return mem_start; } -#ifdef __FreeBSD__ - printk ("sbmidi: <SoundBlaster MPU-401>"); -#else printk (" <SoundBlaster MPU-401>"); -#endif std_midi_synth.midi_dev = my_dev = num_midis; midi_devs[num_midis++] = &sb16midi_operations; diff --git a/sys/i386/isa/sound/sb_card.c b/sys/i386/isa/sound/sb_card.c index 19a34d7..b8e5af2 100644 --- a/sys/i386/isa/sound/sb_card.c +++ b/sys/i386/isa/sound/sb_card.c @@ -25,7 +25,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * sb_card.c,v 1.5 1994/08/02 07:40:39 davidg Exp + * Modified: + * Riccardo Facchetti 24 Mar 1995 + * - Added the Audio Excel DSP 16 initialization routine. */ #include "sound_config.h" @@ -47,6 +49,12 @@ attach_sb_card (long mem_start, struct address_info *hw_config) int probe_sb (struct address_info *hw_config) { +#if !defined(EXCLUDE_AEDSP16) && defined(AEDSP16_SBPRO) + /* + * Initialize Audio Excel DSP 16 to SBPRO. + */ + InitAEDSP16_SBPRO (hw_config); +#endif return sb_dsp_detect (hw_config); } diff --git a/sys/i386/isa/sound/sb_dsp.c b/sys/i386/isa/sound/sb_dsp.c index 5db3c9b..8bffc59 100644 --- a/sys/i386/isa/sound/sb_dsp.c +++ b/sys/i386/isa/sound/sb_dsp.c @@ -26,10 +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 * - * $Id: sb_dsp.c,v 1.22 1994/12/10 22:55:50 ats Exp $ + * JRA Gibson April 1995 + * Code added for MV ProSonic/Jazz 16 in 16 bit mode */ #include "sound_config.h" @@ -43,6 +44,7 @@ int sbc_base = 0; static int sbc_irq = 0; static int open_mode = 0; /* Read, write or both */ +int Jazz16_detected = 0; /* * The DSP channel can be used either for input or output. Variable @@ -84,6 +86,21 @@ volatile int sb_irq_mode = IMODE_NONE; /* * 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 +121,8 @@ sb_dsp_command (unsigned char val) 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 +148,22 @@ sb_dsp_command (unsigned char val) } void -sbintr (int unit) +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 +172,13 @@ sbintr (int unit) 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 +204,7 @@ sbintr (int unit) case IMODE_MIDI: #ifndef EXCLUDE_MIDI - sb_midi_interrupt (unit); + sb_midi_interrupt (irq); #endif break; @@ -209,7 +221,7 @@ sb_get_irq (void) 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 +294,16 @@ dsp_speed (int speed) 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 +316,14 @@ dsp_speed (int speed) * 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 +364,7 @@ dsp_speed (int speed) 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 +424,14 @@ sb_dsp_output_block (int dev, unsigned long buf, int count, 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 +441,8 @@ sb_dsp_output_block (int dev, unsigned long buf, int count, 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 +478,14 @@ sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, 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 +495,8 @@ sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, 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 +526,23 @@ sb_dsp_prepare_for_input (int dev, int bsize, int bcount) * 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 +562,19 @@ sb_dsp_prepare_for_output (int dev, int bsize, int bcount) * 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 @@ -616,12 +655,28 @@ sb_dsp_open (int dev, int mode) if (retval) return retval; + /* Allocate 8 bit dma + */ 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 (); + RELEASE_DMA_CHN (dma8); + return RET_ERROR (EBUSY); + } + } +#endif sb_irq_mode = IMODE_NONE; @@ -634,6 +689,13 @@ sb_dsp_open (int dev, int mode) static void sb_dsp_close (int dev) { +#ifdef JAZZ16 + /* Release 16 bit dma channel + */ + if (Jazz16_detected) + RELEASE_DMA_CHN (dma16); +#endif + DMAbuf_close_dma (dev); sb_free_irq (); dsp_cleanup (); @@ -643,6 +705,32 @@ sb_dsp_close (int dev) 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 +766,31 @@ sb_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) 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 +820,232 @@ sb_dsp_reset (int dev) #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 +1056,16 @@ sb_dsp_detect (struct address_info *hw_config) 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 @@ -737,7 +1075,7 @@ sb_dsp_detect (struct address_info *hw_config) #ifndef EXCLUDE_AUDIO static struct audio_operations sb_dsp_operations = { - "SoundBlaster ", + "SoundBlaster", NOTHING_SPECIAL, AFMT_U8, /* Just 8 bits. Poor old SB */ NULL, @@ -792,6 +1130,9 @@ sb_dsp_init (long mem_start, struct address_info *hw_config) #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,35 +1142,46 @@ sb_dsp_init (long mem_start, struct address_info *hw_config) 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 } -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) printk ("sb0: <%s>", sb_dsp_operations.name); #else printk (" <%s>", sb_dsp_operations.name); #endif -#ifndef EXCLUDE_AUDIO #if !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SBPRO) if (!sb16) /* * There is a better driver for SB16 @@ -844,6 +1196,8 @@ sb_dsp_init (long mem_start, struct address_info *hw_config) } else printk ("SB: Too many DSP devices available\n"); +#else + printk (" <SoundBlaster (configured without audio support)>"); #endif #ifndef EXCLUDE_MIDI diff --git a/sys/i386/isa/sound/sb_midi.c b/sys/i386/isa/sound/sb_midi.c index 4e48e65..cc303ab 100644 --- a/sys/i386/isa/sound/sb_midi.c +++ b/sys/i386/isa/sound/sb_midi.c @@ -25,7 +25,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: sb_midi.c,v 1.4 1994/10/01 02:17:05 swallace Exp $ */ #include "sound_config.h" @@ -43,7 +42,7 @@ * future version of this driver. */ -extern int sb_dsp_ok; /* Set to 1 after successful initialization */ +extern int sb_dsp_ok; /* Set to 1 atfer successful initialization */ extern int sbc_base; extern int sb_midi_mode; @@ -218,6 +217,7 @@ static struct midi_operations sb_midi_operations = { {"SoundBlaster", 0, 0, SNDCARD_SB}, &std_midi_synth, + {0}, sb_midi_open, sb_midi_close, sb_midi_ioctl, diff --git a/sys/i386/isa/sound/sb_mixer.c b/sys/i386/isa/sound/sb_mixer.c index 40a4b03..8deaad5 100644 --- a/sys/i386/isa/sound/sb_mixer.c +++ b/sys/i386/isa/sound/sb_mixer.c @@ -27,10 +27,9 @@ * SUCH DAMAGE. * * Modified: - * Hunyue Yau Jan 6 1994 - * Added code to support the Sound Galaxy NX Pro mixer. + * Hunyue Yau Jan 6 1994 + * Added code to support the Sound Galaxy NX Pro mixer. * - * sb_mixer.c,v 1.4 1994/10/01 02:17:07 swallace Exp */ #include "sound_config.h" @@ -43,6 +42,7 @@ #undef SB_TEST_IRQ extern int sbc_base; +extern int Jazz16_detected; static int mixer_initialized = 0; @@ -98,9 +98,9 @@ sb_mixer_set_stereo (int mode) /* * Returns: - * 0 No mixer detected. - * 1 Only a plain Sound Blaster Pro style mixer detected. - * 2 The Sound Galaxy NX Pro mixer detected. + * 0 No mixer detected. + * 1 Only a plain Sound Blaster Pro style mixer detected. + * 2 The Sound Galaxy NX Pro mixer detected. */ static int detect_mixer (void) @@ -110,6 +110,7 @@ detect_mixer (void) #endif int retcode = 1; + extern int sbc_major; /* * Detect the mixer by changing parameters of two volume channels. If the @@ -128,8 +129,8 @@ detect_mixer (void) #ifdef __SGNXPRO__ /* Attempt to detect the SG NX Pro by check for valid bass/treble - * registers. - */ + * registers. + */ oldbass = sb_getmixer (BASS_LVL); oldtreble = sb_getmixer (TREBLE_LVL); @@ -148,6 +149,21 @@ detect_mixer (void) */ sb_setmixer (BASS_LVL, oldbass); sb_setmixer (TREBLE_LVL, oldtreble); + + /* + * If the SB version is 3.X (SB Pro), assume we have a SG NX Pro 16. + * In this case it's good idea to disable the Disney Sound Source + * compatibility mode. It's useless and just causes noise every time the + * LPT-port is accessed. + * + * Also place the card into WSS mode. + */ + if (sbc_major == 3) + { + OUTB (0x01, sbc_base + 0x1c); + OUTB (0x00, sbc_base + 0x1a); + } + #endif return retcode; } @@ -182,6 +198,100 @@ sb_mixer_get (int dev) return levels[dev]; } +#ifdef JAZZ16 +static char smw_mix_regs[] = /* Left mixer registers */ +{ + 0x0b, /* SOUND_MIXER_VOLUME */ + 0x0d, /* SOUND_MIXER_BASS */ + 0x0d, /* SOUND_MIXER_TREBLE */ + 0x05, /* SOUND_MIXER_SYNTH */ + 0x09, /* SOUND_MIXER_PCM */ + 0x00, /* SOUND_MIXER_SPEAKER */ + 0x03, /* SOUND_MIXER_LINE */ + 0x01, /* SOUND_MIXER_MIC */ + 0x07, /* SOUND_MIXER_CD */ + 0x00, /* SOUND_MIXER_IMIX */ + 0x00, /* SOUND_MIXER_ALTPCM */ + 0x00, /* SOUND_MIXER_RECLEV */ + 0x00, /* SOUND_MIXER_IGAIN */ + 0x00, /* SOUND_MIXER_OGAIN */ + 0x00, /* SOUND_MIXER_LINE1 */ + 0x00, /* SOUND_MIXER_LINE2 */ + 0x00 /* SOUND_MIXER_LINE3 */ +}; + +static void +smw_mixer_init (void) +{ + int i; + + sb_setmixer (0x00, 0x18); /* Mute unused (Telephone) line */ + sb_setmixer (0x10, 0x38); /* Config register 2 */ + + supported_devices = 0; + for (i = 0; i < sizeof (smw_mix_regs); i++) + if (smw_mix_regs[i] != 0) + supported_devices |= (1 << i); + + supported_rec_devices = supported_devices & + ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_PCM | + SOUND_MASK_VOLUME); +} + +static int +smw_mixer_set (int dev, int value) +{ + int left = value & 0x000000ff; + int right = (value & 0x0000ff00) >> 8; + int reg, val; + + if (left > 100) + left = 100; + if (right > 100) + right = 100; + + if (dev > 31) + return RET_ERROR (EINVAL); + + if (!(supported_devices & (1 << dev))) /* Not supported */ + return RET_ERROR (EINVAL); + + switch (dev) + { + case SOUND_MIXER_VOLUME: + sb_setmixer (0x0b, 96 - (96 * left / 100)); /* 96=mute, 0=max */ + sb_setmixer (0x0c, 96 - (96 * right / 100)); + break; + + case SOUND_MIXER_BASS: + case SOUND_MIXER_TREBLE: + levels[dev] = left | (right << 8); + + /* Set left bass and treble values */ + val = ((levels[SOUND_MIXER_TREBLE] & 0xff) * 16 / 100) << 4; + val |= ((levels[SOUND_MIXER_BASS] & 0xff) * 16 / 100) & 0x0f; + sb_setmixer (0x0d, val); + + /* Set right bass and treble values */ + val = (((levels[SOUND_MIXER_TREBLE] >> 8) & 0xff) * 16 / 100) << 4; + val |= (((levels[SOUND_MIXER_BASS] >> 8) & 0xff) * 16 / 100) & 0x0f; + sb_setmixer (0x0e, val); + break; + + default: + reg = smw_mix_regs[dev]; + if (reg == 0) + return RET_ERROR (EINVAL); + sb_setmixer (reg, (24 - (24 * left / 100)) | 0x20); /* 24=mute, 0=max */ + sb_setmixer (reg + 1, (24 - (24 * right / 100)) | 0x40); + } + + levels[dev] = left | (right << 8); + return left | (right << 8); +} + +#endif + static int sb_mixer_set (int dev, int value) { @@ -191,6 +301,11 @@ sb_mixer_set (int dev, int value) int regoffs; unsigned char val; +#ifdef JAZZ16 + if (Jazz16_detected == 2) + return smw_mixer_set (dev, value); +#endif + if (left > 100) left = 100; if (right > 100) @@ -234,6 +349,7 @@ sb_mixer_set (int dev, int value) } change_bits (&val, dev, RIGHT_CHN, right); + sb_setmixer (regoffs, val); levels[dev] = left | (right << 8); @@ -338,6 +454,7 @@ sb_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg) break; default: + return IOCTL_OUT (arg, sb_mixer_set (cmd & 0xff, IOCTL_IN (arg))); } else @@ -355,8 +472,11 @@ sb_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg) break; case SOUND_MIXER_STEREODEVS: - return IOCTL_OUT (arg, supported_devices & - ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER)); + if (Jazz16_detected) + return IOCTL_OUT (arg, supported_devices); + else + return IOCTL_OUT (arg, supported_devices & + ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER)); break; case SOUND_MIXER_RECMASK: @@ -377,6 +497,7 @@ sb_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg) static struct mixer_operations sb_mixer_operations = { + "SoundBlaster", sb_mixer_ioctl }; @@ -415,6 +536,18 @@ sb_mixer_init (int major_model) { case 3: mixer_caps = SOUND_CAP_EXCL_INPUT; + +#ifdef JAZZ16 + if (Jazz16_detected == 2) /* SM Wave */ + { + supported_devices = 0; + supported_rec_devices = 0; + iomap = &sbpro_mix; + smw_mixer_init (); + mixer_type = 1; + } + else +#endif #ifdef __SGNXPRO__ if (mixer_type == 2) /* A SGNXPRO was detected */ { diff --git a/sys/i386/isa/sound/sb_mixer.h b/sys/i386/isa/sound/sb_mixer.h index e605e79..cd103a7 100644 --- a/sys/i386/isa/sound/sb_mixer.h +++ b/sys/i386/isa/sound/sb_mixer.h @@ -1,10 +1,10 @@ /* * sound/sb_mixer.h - * + * * Definitions for the SB Pro and SB16 mixers - * + * * Copyright by Hannu Savolainen 1993 - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: 1. Redistributions of source code must retain the above copyright @@ -12,7 +12,7 @@ * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -28,8 +28,7 @@ * Modified: * Hunyue Yau Jan 6 1994 * Added defines for the Sound Galaxy NX Pro mixer. - * - * sb_mixer.h,v 1.4 1994/10/01 02:17:08 swallace Exp + * */ #define SBPRO_RECORDING_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD) @@ -52,16 +51,17 @@ SOUND_MASK_CD) #define SB16_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD | SOUND_MASK_RECLEV | \ + SOUND_MASK_CD | \ + SOUND_MASK_IGAIN | SOUND_MASK_OGAIN | \ SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE) /* * Mixer registers - * + * * NOTE! RECORD_SRC == IN_FILTER */ -/* +/* * Mixer registers of SB Pro */ #define VOC_VOL 0x04 @@ -80,7 +80,7 @@ #define OPSW 0x3c /* - * Additional registers on the SG NX Pro + * Additional registers on the SG NX Pro */ #define COVOX_VOL 0x42 #define TREBLE_LVL 0x44 @@ -145,7 +145,9 @@ MIX_ENT(SOUND_MIXER_MIC, 0x0a, 2, 3, 0x00, 0, 0), MIX_ENT(SOUND_MIXER_CD, 0x28, 7, 4, 0x28, 3, 4), MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0) +MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0) }; #endif @@ -161,23 +163,51 @@ MIX_ENT(SOUND_MIXER_MIC, 0x3a, 7, 5, 0x00, 0, 0), MIX_ENT(SOUND_MIXER_CD, 0x36, 7, 5, 0x37, 7, 5), MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_RECLEV, 0x3f, 7, 2, 0x40, 7, 2) +MIX_ENT(SOUND_MIXER_RECLEV, 0x3f, 7, 2, 0x40, 7, 2), /* Obsolete. Use IGAIN */ +MIX_ENT(SOUND_MIXER_IGAIN, 0x3f, 7, 2, 0x40, 7, 2), +MIX_ENT(SOUND_MIXER_OGAIN, 0x41, 7, 2, 0x42, 7, 2) }; +#ifdef SM_GAMES /* Master volume is lower and PCM & FM volumes + higher than with SB Pro. This improves the + sound quality */ + +static unsigned short levels[SOUND_MIXER_NRDEVICES] = +{ + 0x2020, /* Master Volume */ + 0x4b4b, /* Bass */ + 0x4b4b, /* Treble */ + 0x6464, /* FM */ + 0x6464, /* PCM */ + 0x4b4b, /* PC Speaker */ + 0x4b4b, /* Ext Line */ + 0x0000, /* Mic */ + 0x4b4b, /* CD */ + 0x4b4b, /* Recording monitor */ + 0x4b4b, /* SB PCM */ + 0x4b4b, /* Recording level */ + 0x4b4b, /* Input gain */ + 0x4b4b}; /* Output gain */ + +#else /* If the user selected just plain SB Pro */ + static unsigned short levels[SOUND_MIXER_NRDEVICES] = { 0x5a5a, /* Master Volume */ - 0x3232, /* Bass */ - 0x3232, /* Treble */ + 0x4b4b, /* Bass */ + 0x4b4b, /* Treble */ 0x4b4b, /* FM */ 0x4b4b, /* PCM */ 0x4b4b, /* PC Speaker */ 0x4b4b, /* Ext Line */ - 0x0000, /* Mic */ + 0x1010, /* Mic */ 0x4b4b, /* CD */ 0x4b4b, /* Recording monitor */ 0x4b4b, /* SB PCM */ - 0x4b4b}; /* Recording level */ + 0x4b4b, /* Recording level */ + 0x4b4b, /* Input gain */ + 0x4b4b}; /* Output gain */ +#endif /* SM_GAMES */ static unsigned char sb16_recmasks_L[SOUND_MIXER_NRDEVICES] = { @@ -192,7 +222,9 @@ static unsigned char sb16_recmasks_L[SOUND_MIXER_NRDEVICES] = 0x04, /* SOUND_MIXER_CD */ 0x00, /* SOUND_MIXER_IMIX */ 0x00, /* SOUND_MIXER_ALTPCM */ - 0x00 /* SOUND_MIXER_RECLEV */ + 0x00, /* SOUND_MIXER_RECLEV */ + 0x00, /* SOUND_MIXER_IGAIN */ + 0x00 /* SOUND_MIXER_OGAIN */ }; static unsigned char sb16_recmasks_R[SOUND_MIXER_NRDEVICES] = @@ -208,7 +240,9 @@ static unsigned char sb16_recmasks_R[SOUND_MIXER_NRDEVICES] = 0x02, /* SOUND_MIXER_CD */ 0x00, /* SOUND_MIXER_IMIX */ 0x00, /* SOUND_MIXER_ALTPCM */ - 0x00 /* SOUND_MIXER_RECLEV */ + 0x00, /* SOUND_MIXER_RECLEV */ + 0x00, /* SOUND_MIXER_IGAIN */ + 0x00 /* SOUND_MIXER_OGAIN */ }; /* diff --git a/sys/i386/isa/sound/sequencer.c b/sys/i386/isa/sound/sequencer.c index 66194ed..e659696 100644 --- a/sys/i386/isa/sound/sequencer.c +++ b/sys/i386/isa/sound/sequencer.c @@ -25,11 +25,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: sequencer.c,v 1.7 1994/10/01 02:17:09 swallace Exp $ */ #define SEQUENCER_C #include "sound_config.h" +#include "midi_ctrl.h" #ifdef CONFIGURE_SOUNDCARD @@ -50,7 +50,7 @@ static int max_synthdev = 0; /* * The seq_mode gives the operating mode of the sequencer: * 1 = level1 (the default) - * 2 = level2 (extended capabilities) + * 2 = level2 (extended capabilites) */ #define SEQ_1 1 @@ -84,7 +84,7 @@ static int output_treshold; static int pre_event_timeout; static unsigned synth_open_mask; -static int seq_queue (unsigned char *note); +static int seq_queue (unsigned char *note, char nonblock); static void seq_startplay (void); static int seq_sync (void); static void seq_reset (void); @@ -114,6 +114,12 @@ sequencer_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) DISABLE_INTR (flags); if (!iqlen) { + if (ISSET_FILE_FLAG (file, O_NONBLOCK)) + { + RESTORE_INTR (flags); + return RET_ERROR (EAGAIN); + } + DO_SLEEP (midi_sleeper, midi_sleep_flag, pre_event_timeout); if (!iqlen) @@ -152,8 +158,8 @@ seq_copy_to_input (unsigned char *event, int len) unsigned long flags; /* - * Verify that the len is valid for the current mode. - */ + * Verify that the len is valid for the current mode. + */ if (len != 4 && len != 8) return; @@ -173,6 +179,10 @@ seq_copy_to_input (unsigned char *event, int len) WAKE_UP (midi_sleeper, midi_sleep_flag); } RESTORE_INTR (flags); +#if defined(__FreeBSD__) + if (selinfo[0].si_pid) + selwakeup(&selinfo[0]); +#endif } static void @@ -332,12 +342,17 @@ sequencer_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) } - if (!seq_queue (event)) + if (!seq_queue (event, ISSET_FILE_FLAG (file, O_NONBLOCK))) { + int processed = count - c; if (!seq_playing) seq_startplay (); - return count - c; + + if (!processed && ISSET_FILE_FLAG (file, O_NONBLOCK)) + return RET_ERROR (EAGAIN); + else + return processed; } p += ev_size; @@ -347,11 +362,13 @@ sequencer_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) if (!seq_playing) seq_startplay (); - return count; + return count; /* This will "eat" chunks shorter than 4 bytes (if written + * alone) Should we really do that ? + */ } static int -seq_queue (unsigned char *note) +seq_queue (unsigned char *note, char nonblock) { /* @@ -364,7 +381,7 @@ seq_queue (unsigned char *note) * Give chance to drain the queue */ - if (qlen >= SEQ_MAX_QUEUE && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) + if (!nonblock && qlen >= SEQ_MAX_QUEUE && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) { /* * Sleep until there is enough space on the queue @@ -373,10 +390,11 @@ seq_queue (unsigned char *note) } if (qlen >= SEQ_MAX_QUEUE) - return 0; /* + { + return 0; /* * To be sure */ - + } memcpy (&queue[qtail * EV_SZ], note, EV_SZ); qtail = (qtail + 1) % SEQ_MAX_QUEUE; @@ -463,6 +481,8 @@ alloc_voice (int dev, int chn, int note) voice = synth_devs[dev]->alloc_voice (dev, chn, note, &synth_devs[dev]->alloc); synth_devs[dev]->alloc.map[voice] = key; + synth_devs[dev]->alloc.alloc_times[voice] = + synth_devs[dev]->alloc.timestamp++; return voice; } @@ -486,33 +506,47 @@ seq_chn_voice_event (unsigned char *event) if (seq_mode == SEQ_2) { if (synth_devs[dev]->alloc_voice) - voice = find_voice (dev, chn, note); + voice = find_voice (dev, chn, note); if (cmd == MIDI_NOTEON && parm == 0) - { - cmd = MIDI_NOTEOFF; - parm = 64; - } + { + cmd = MIDI_NOTEOFF; + parm = 64; + } } switch (cmd) { case MIDI_NOTEON: - if (note > 127 && note != 255) + if (note > 127 && note != 255) /* Not a seq2 feature */ return; if (voice == -1 && seq_mode == SEQ_2 && synth_devs[dev]->alloc_voice) - { + { /* Internal synthesizer (FM, GUS, etc) */ voice = alloc_voice (dev, chn, note); } if (voice == -1) voice = chn; + if (seq_mode == SEQ_2 && dev < num_synths) + { + /* + * The MIDI channel 10 is a percussive channel. Use the note + * number to select the proper patch (128 to 255) to play. + */ + + if (chn == 9) + { + synth_devs[dev]->set_instr (dev, voice, 128 + note); + note = 60; /* Middle C */ + + } + } + if (seq_mode == SEQ_2) { - synth_devs[dev]->set_instr (dev, voice, - synth_devs[dev]->chn_info[chn].pgm_num); + synth_devs[dev]->setup_voice (dev, voice, chn); } synth_devs[dev]->start_note (dev, voice, note, parm); @@ -525,7 +559,9 @@ seq_chn_voice_event (unsigned char *event) break; case MIDI_KEY_PRESSURE: - /* To be implemented */ + if (voice == -1) + voice = chn; + synth_devs[dev]->aftertouch (dev, voice, parm); break; default:; @@ -556,33 +592,27 @@ seq_chn_common_event (unsigned char *event) if (seq_mode == SEQ_2) { synth_devs[dev]->chn_info[chn].pgm_num = p1; + if (dev >= num_synths) + synth_devs[dev]->set_instr (dev, chn, p1); } else synth_devs[dev]->set_instr (dev, chn, p1); + break; case MIDI_CTL_CHANGE: - if (p1 == CTRL_MAIN_VOLUME) - { - w14 = (unsigned short) (((int) w14 * 16383) / 100); - p1 = CTL_MAIN_VOLUME; - } - if (p1 == CTRL_EXPRESSION) - { - w14 *= 128; - p1 = CTL_EXPRESSION; - } if (seq_mode == SEQ_2) { if (chn > 15 || p1 > 127) break; - synth_devs[dev]->chn_info[chn].controllers[p1] = w14 & 0xff; + synth_devs[dev]->chn_info[chn].controllers[p1] = w14 & 0x7f; if (dev < num_synths) { - int val = w14 & 0xff; + int val = w14 & 0x7f; + int i, key; if (p1 < 64) /* Combine MSB and LSB */ { @@ -592,20 +622,42 @@ seq_chn_common_event (unsigned char *event) chn_info[chn].controllers[p1 | 32] & 0x7f); p1 &= ~32; } - else - val = synth_devs[dev]->chn_info[chn].controllers[p1]; - synth_devs[dev]->controller (dev, chn, p1, val); + /* Handle all playing notes on this channel */ + + key = (chn << 8); + + for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) + if ((synth_devs[dev]->alloc.map[i] & 0xff00) == key) + synth_devs[dev]->controller (dev, i, p1, val); } else synth_devs[dev]->controller (dev, chn, p1, w14); } - else + else /* Mode 1 */ synth_devs[dev]->controller (dev, chn, p1, w14); break; case MIDI_PITCH_BEND: - synth_devs[dev]->bender (dev, chn, w14); + if (seq_mode == SEQ_2) + { + synth_devs[dev]->chn_info[chn].bender_value = w14; + + if (dev < num_synths) + { /* Handle all playing notes on this channel */ + int i, key; + + key = (chn << 8); + + for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) + if ((synth_devs[dev]->alloc.map[i] & 0xff00) == key) + synth_devs[dev]->bender (dev, i, w14); + } + else + synth_devs[dev]->bender (dev, chn, w14); + } + else /* MODE 1 */ + synth_devs[dev]->bender (dev, chn, w14); break; default:; @@ -634,6 +686,9 @@ seq_timing_event (unsigned char *event) WAKE_UP (seq_sleeper, seq_sleep_flag); } RESTORE_INTR (flags); +#if defined(__FreeBSD__) + /* must issue a wakeup for anyone waiting (select) XXX */ +#endif } } return ret; @@ -645,9 +700,9 @@ seq_timing_event (unsigned char *event) parm += prev_event_time; /* - * NOTE! No break here. Execution of TMR_WAIT_REL continues in the - * next case (TMR_WAIT_ABS) - */ + * NOTE! No break here. Execution of TMR_WAIT_REL continues in the + * next case (TMR_WAIT_ABS) + */ case TMR_WAIT_ABS: if (parm > 0) @@ -670,6 +725,9 @@ seq_timing_event (unsigned char *event) WAKE_UP (seq_sleeper, seq_sleep_flag); } RESTORE_INTR (flags); +#if defined(__FreeBSD__) + /* must issue a wakeup for select XXX */ +#endif } return TIMER_ARMED; @@ -715,151 +773,173 @@ seq_local_event (unsigned char *event) printk ("seq_local_event() called. WHY????????\n"); } -static void -seq_startplay (void) +static int +play_event (unsigned char *q) { - int this_one; + /* + * NOTE! This routine returns + * 0 = normal event played. + * 1 = Timer armed. Suspend playback until timer callback. + * 2 = MIDI output buffer full. Restore queue and suspend until timer + */ unsigned long *delay; - unsigned char *q; - while (qlen > 0) + switch (q[0]) { + case SEQ_NOTEOFF: + if (synth_open_mask & (1 << 0)) + if (synth_devs[0]) + synth_devs[0]->kill_note (0, q[1], 255, q[3]); + break; - seq_playing = 1; - - qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE; - qlen--; - - q = &queue[this_one * EV_SZ]; + case SEQ_NOTEON: + if (q[4] < 128 || q[4] == 255) + if (synth_open_mask & (1 << 0)) + if (synth_devs[0]) + synth_devs[0]->start_note (0, q[1], q[2], q[3]); + break; - switch (q[0]) - { - case SEQ_NOTEOFF: - if (synth_open_mask & (1 << 0)) - if (synth_devs[0]) - synth_devs[0]->kill_note (0, q[1], 255, q[3]); - break; - - case SEQ_NOTEON: - if (q[4] < 128 || q[4] == 255) - if (synth_open_mask & (1 << 0)) - if (synth_devs[0]) - synth_devs[0]->start_note (0, q[1], q[2], q[3]); - break; - - case SEQ_WAIT: - delay = (unsigned long *) q; /* + case SEQ_WAIT: + delay = (unsigned long *) q; /* * Bytes 1 to 3 are containing the * * delay in GET_TIME() */ - *delay = (*delay >> 8) & 0xffffff; + *delay = (*delay >> 8) & 0xffffff; - if (*delay > 0) - { - long time; + if (*delay > 0) + { + long time; - seq_playing = 1; - time = *delay; - prev_event_time = time; + seq_playing = 1; + time = *delay; + prev_event_time = time; - request_sound_timer (time); + request_sound_timer (time); + + if ((SEQ_MAX_QUEUE - qlen) >= output_treshold) + { + unsigned long flags; - if ((SEQ_MAX_QUEUE - qlen) >= output_treshold) + DISABLE_INTR (flags); + if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) { - unsigned long flags; - - DISABLE_INTR (flags); - if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) - { - WAKE_UP (seq_sleeper, seq_sleep_flag); - } - RESTORE_INTR (flags); + WAKE_UP (seq_sleeper, seq_sleep_flag); } - /* - * The timer is now active and will reinvoke this function - * after the timer expires. Return to the caller now. - */ - return; + RESTORE_INTR (flags); +#if defined(__FreeBSD__) + /* must issue a wakeup for selects XXX */ +#endif } - break; + /* + * The timer is now active and will reinvoke this function + * after the timer expires. Return to the caller now. + */ + return 1; + } + break; - case SEQ_PGMCHANGE: - if (synth_open_mask & (1 << 0)) - if (synth_devs[0]) - synth_devs[0]->set_instr (0, q[1], q[2]); - break; + case SEQ_PGMCHANGE: + if (synth_open_mask & (1 << 0)) + if (synth_devs[0]) + synth_devs[0]->set_instr (0, q[1], q[2]); + break; - case SEQ_SYNCTIMER: /* - * Reset timer + case SEQ_SYNCTIMER: /* + * Reset timer */ - seq_time = GET_TIME (); - prev_input_time = 0; - prev_event_time = 0; - break; + seq_time = GET_TIME (); + prev_input_time = 0; + prev_event_time = 0; + break; - case SEQ_MIDIPUTC: /* + case SEQ_MIDIPUTC: /* * Put a midi character */ - if (midi_opened[q[2]]) - { - int dev; + if (midi_opened[q[2]]) + { + int dev; - dev = q[2]; + dev = q[2]; - if (!midi_devs[dev]->putc (dev, q[1])) - { - /* - * Output FIFO is full. Wait one timer cycle and try again. - */ + if (!midi_devs[dev]->putc (dev, q[1])) + { + /* + * Output FIFO is full. Wait one timer cycle and try again. + */ - qlen++; - qhead = this_one; /* - * Restore queue - */ - seq_playing = 1; - request_sound_timer (-1); - return; - } - else - midi_written[dev] = 1; + seq_playing = 1; + request_sound_timer (-1); + return 2; } - break; + else + midi_written[dev] = 1; + } + break; - case SEQ_ECHO: - seq_copy_to_input (q, 4); /* - * Echo back to the process - */ - break; + case SEQ_ECHO: + seq_copy_to_input (q, 4); /* + * Echo back to the process + */ + break; - case SEQ_PRIVATE: - if ((int) q[1] < max_synthdev) - synth_devs[q[1]]->hw_control (q[1], q); - break; + case SEQ_PRIVATE: + if ((int) q[1] < max_synthdev) + synth_devs[q[1]]->hw_control (q[1], q); + break; - case SEQ_EXTENDED: - extended_event (q); - break; + case SEQ_EXTENDED: + extended_event (q); + break; - case EV_CHN_VOICE: - seq_chn_voice_event (q); - break; + case EV_CHN_VOICE: + seq_chn_voice_event (q); + break; - case EV_CHN_COMMON: - seq_chn_common_event (q); - break; + case EV_CHN_COMMON: + seq_chn_common_event (q); + break; - case EV_TIMING: - if (seq_timing_event (q) == TIMER_ARMED) - { - return; - } - break; + case EV_TIMING: + if (seq_timing_event (q) == TIMER_ARMED) + { + return 1; + } + break; + + case EV_SEQ_LOCAL: + seq_local_event (q); + break; + + default:; + } + + return 0; +} + +static void +seq_startplay (void) +{ + unsigned long flags; + int this_one, action; - case EV_SEQ_LOCAL: - seq_local_event (q); - break; + while (qlen > 0) + { - default:; + DISABLE_INTR (flags); + qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE; + qlen--; + RESTORE_INTR (flags); + + seq_playing = 1; + + if ((action = play_event (&queue[this_one * EV_SZ]))) + { /* Suspend playback. Next timer routine invokes this routine again */ + if (action == 2) + { + qlen++; + qhead = this_one; + } + return; } } @@ -876,14 +956,15 @@ seq_startplay (void) WAKE_UP (seq_sleeper, seq_sleep_flag); } RESTORE_INTR (flags); +#if defined(__FreeBSD__) + /* must issue a wakeup for selects XXX */ +#endif } - } static void reset_controllers (int dev, unsigned char *controller, int update_dev) { -#include "midi_ctrl.h" int i; @@ -915,6 +996,7 @@ setup_mode2 (void) reset_controllers (dev, synth_devs[dev]->chn_info[chn].controllers, 0); + synth_devs[dev]->chn_info[chn].bender_value = (1 << 7); /* Neutral */ } } @@ -999,7 +1081,6 @@ sequencer_open (int dev, struct fileinfo *file) if (level == 2) { - printk ("Using timer #%d\n", tmr_no); if (tmr == NULL) { printk ("sequencer: No timer for level 2\n"); @@ -1036,7 +1117,7 @@ sequencer_open (int dev, struct fileinfo *file) { printk ("Sequencer: Warning! Cannot open synth device #%d (%d)\n", i, tmp); if (synth_devs[i]->midi_dev) - printk ("(Maps to midi dev #%d\n", synth_devs[i]->midi_dev); + printk ("(Maps to MIDI dev #%d)\n", synth_devs[i]->midi_dev); } else { @@ -1092,7 +1173,7 @@ seq_drain_midi_queues (void) n = 1; - while (!PROCESS_ABORTING (midi_sleeper, midi_sleep_flag) && n) + while (!PROCESS_ABORTING (seq_sleeper, seq_sleep_flag) && n) { n = 0; @@ -1133,10 +1214,10 @@ sequencer_release (int dev, struct fileinfo *file) } /* - * * Wait until the queue is empty + * * Wait until the queue is empty (if we don't have nonblock) */ - if (mode != OPEN_READ) + if (mode != OPEN_READ && !ISSET_FILE_FLAG (file, O_NONBLOCK)) while (!PROCESS_ABORTING (seq_sleeper, seq_sleep_flag) && qlen) { seq_sync (); @@ -1181,16 +1262,17 @@ sequencer_release (int dev, struct fileinfo *file) static int seq_sync (void) { + unsigned long flags; + if (qlen && !seq_playing && !PROCESS_ABORTING (seq_sleeper, seq_sleep_flag)) seq_startplay (); - if (qlen && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) /* - * Queue not - * empty - */ + DISABLE_INTR (flags); + if (qlen && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) { DO_SLEEP (seq_sleeper, seq_sleep_flag, 0); } + RESTORE_INTR (flags); return qlen; } @@ -1203,26 +1285,23 @@ midi_outc (int dev, unsigned char data) */ int n; + unsigned long flags; /* * This routine sends one byte to the Midi channel. - */ - /* * If the output Fifo is full, it waits until there - */ - /* * is space in the queue */ - n = 300; /* - * Timeout in jiffies - */ + n = 3 * HZ; /* Timeout */ + DISABLE_INTR (flags); while (n && !midi_devs[dev]->putc (dev, data)) { DO_SLEEP (seq_sleeper, seq_sleep_flag, 4); n--; } + RESTORE_INTR (flags); } static void @@ -1233,8 +1312,8 @@ seq_reset (void) */ int i; - int chn; + unsigned long flags; sound_stop_timer (); seq_time = GET_TIME (); @@ -1251,13 +1330,20 @@ seq_reset (void) if (seq_mode == SEQ_2) { - for (i = 0; i < max_synthdev; i++) - if (synth_open_mask & (1 << i)) - if (synth_devs[i]) - for (chn = 0; chn < 16; chn++) - synth_devs[i]->controller (i, chn, 0xfe, 0); /* All notes off */ + + for (chn = 0; chn < 16; chn++) + for (i = 0; i < max_synthdev; i++) + if (synth_open_mask & (1 << i)) + if (synth_devs[i]) + { + synth_devs[i]->controller (i, chn, 123, 0); /* All notes off */ + synth_devs[i]->controller (i, chn, 121, 0); /* Reset all ctl */ + synth_devs[i]->bender (i, chn, 1 << 13); /* Bender off */ + } + } else + /* seq_mode == SEQ_1 */ { for (i = 0; i < max_mididev; i++) if (midi_written[i]) /* @@ -1265,25 +1351,18 @@ seq_reset (void) */ { /* - * Sending just a ACTIVE SENSING message should be enough to stop all - * playing notes. Since there are devices not recognizing the - * active sensing, we have to send some all notes off messages also. - */ + * Sending just a ACTIVE SENSING message should be enough to stop all + * playing notes. Since there are devices not recognizing the + * active sensing, we have to send some all notes off messages also. + */ midi_outc (i, 0xfe); for (chn = 0; chn < 16; chn++) { midi_outc (i, - (unsigned char) (0xb0 + (chn & 0xff))); /* - * Channel - * msg - */ - midi_outc (i, 0x7b); /* - * All notes off - */ - midi_outc (i, 0); /* - * Dummy parameter - */ + (unsigned char) (0xb0 + (chn & 0x0f))); /* control change */ + midi_outc (i, 0x7b); /* All notes off */ + midi_outc (i, 0); /* Dummy parameter */ } midi_devs[i]->close (i); @@ -1295,8 +1374,13 @@ seq_reset (void) seq_playing = 0; + DISABLE_INTR (flags); if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) - printk ("Sequencer Warning: Unexpected sleeping process\n"); + { + /* printk ("Sequencer Warning: Unexpected sleeping process - Waking up\n"); */ + WAKE_UP (seq_sleeper, seq_sleep_flag); + } + RESTORE_INTR (flags); } @@ -1304,22 +1388,22 @@ static void seq_panic (void) { /* - * This routine is called by the application in case the user - * wants to reset the system to the default state. - */ + * This routine is called by the application in case the user + * wants to reset the system to the default state. + */ seq_reset (); /* - * Since some of the devices don't recognize the active sensing and - * all notes off messages, we have to shut all notes manually. - * - * TO BE IMPLEMENTED LATER - */ + * Since some of the devices don't recognize the active sensing and + * all notes off messages, we have to shut all notes manually. + * + * TO BE IMPLEMENTED LATER + */ /* - * Also return the controllers to their default states - */ + * Also return the controllers to their default states + */ } int @@ -1524,6 +1608,21 @@ sequencer_ioctl (int dev, struct fileinfo *file, } break; + case SNDCTL_SEQ_OUTOFBAND: + { + struct seq_event_rec event; + unsigned long flags; + + IOCTL_FROM_USER ((char *) &event, (char *) arg, 0, sizeof (event)); + + DISABLE_INTR (flags); + play_event (event.arr); + RESTORE_INTR (flags); + + return 0; + } + break; + case SNDCTL_MIDI_INFO: { struct midi_info inf; @@ -1545,7 +1644,11 @@ sequencer_ioctl (int dev, struct fileinfo *file, struct patmgr_info *inf; int dev, err; - inf = (struct patmgr_info *) KERNEL_MALLOC (sizeof (*inf)); + if ((inf = (struct patmgr_info *) KERNEL_MALLOC (sizeof (*inf))) == NULL) + { + printk ("patmgr: Can't allocate memory for a message\n"); + return RET_ERROR (EIO); + } IOCTL_FROM_USER ((char *) inf, (char *) arg, 0, sizeof (*inf)); dev = inf->device; @@ -1579,7 +1682,11 @@ sequencer_ioctl (int dev, struct fileinfo *file, struct patmgr_info *inf; int dev, err; - inf = (struct patmgr_info *) KERNEL_MALLOC (sizeof (*inf)); + if ((inf = (struct patmgr_info *) KERNEL_MALLOC (sizeof (*inf))) == NULL) + { + printk ("patmgr: Can't allocate memory for a message\n"); + return RET_ERROR (EIO); + } IOCTL_FROM_USER ((char *) inf, (char *) arg, 0, sizeof (*inf)); dev = inf->device; @@ -1670,26 +1777,38 @@ sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * w switch (sel_type) { case SEL_IN: + DISABLE_INTR (flags); if (!iqlen) { - DISABLE_INTR (flags); +#if defined(__FreeBSD__) + selrecord(wait, &selinfo[dev]); +#else midi_sleep_flag.mode = WK_SLEEP; select_wait (&midi_sleeper, wait); +#endif RESTORE_INTR (flags); return 0; } + midi_sleep_flag.mode &= ~WK_SLEEP; + RESTORE_INTR (flags); return 1; break; case SEL_OUT: + DISABLE_INTR (flags); if (qlen >= SEQ_MAX_QUEUE) { - DISABLE_INTR (flags); +#if defined(__FreeBSD__) + selrecord(wait, &selinfo[dev]); +#else seq_sleep_flag.mode = WK_SLEEP; select_wait (&seq_sleeper, wait); +#endif RESTORE_INTR (flags); return 0; } + seq_sleep_flag.mode &= ~WK_SLEEP; + RESTORE_INTR (flags); return 1; break; @@ -1853,9 +1972,9 @@ sequencer_init (long mem_start) return mem_start; } +#ifdef ALLOW_SELECT int -/* sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * wait) -SMP */ -sequencer_select (int dev, struct fileinfo *file, int sel_type, void * wait) +sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * wait) { return RET_ERROR (EIO); } @@ -1863,3 +1982,5 @@ sequencer_select (int dev, struct fileinfo *file, int sel_type, void * wait) #endif #endif + +#endif diff --git a/sys/i386/isa/sound/sound_calls.h b/sys/i386/isa/sound/sound_calls.h index ed00975..a7d3764 100644 --- a/sys/i386/isa/sound/sound_calls.h +++ b/sys/i386/isa/sound/sound_calls.h @@ -1,29 +1,24 @@ /* * DMA buffer calls - * - * $Id: sound_calls.h,v 1.12 1995/05/07 06:38:48 pst Exp $ */ -#ifndef _MACHINE_ISA_SOUND_H_ -#define _MACHINE_ISA_SOUND_H_ - int DMAbuf_open(int dev, int mode); -int DMAbuf_output_ready(int dev); -int DMAbuf_input_ready(int dev); int DMAbuf_release(int dev, int mode); -int DMAbuf_getwrbuffer(int dev, char **buf, int *size); -int DMAbuf_getrdbuffer(int dev, char **buf, int *len); +int DMAbuf_getwrbuffer(int dev, char **buf, int *size, int dontblock); +int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock); int DMAbuf_rmchars(int dev, int buff_no, int c); -int DMAbuf_start_input(int dev); int DMAbuf_start_output(int dev, int buff_no, int l); int DMAbuf_ioctl(int dev, unsigned int cmd, unsigned int arg, int local); long DMAbuf_init(long mem_start); int DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode); -int DMAbuf_open_dma (int chan); -void DMAbuf_close_dma (int chan); -void DMAbuf_reset_dma (int chan); +int DMAbuf_open_dma (int dev); +void DMAbuf_close_dma (int dev); +void DMAbuf_reset_dma (int dev); void DMAbuf_inputintr(int dev); void DMAbuf_outputintr(int dev, int underflow_flag); +#ifdef ALLOW_SELECT +int DMAbuf_select(int dev, struct fileinfo *file, int sel_type, select_table * wait); +#endif /* * System calls for /dev/dsp and /dev/audio @@ -38,6 +33,10 @@ int audio_ioctl (int dev, struct fileinfo *file, int audio_lseek (int dev, struct fileinfo *file, off_t offset, int orig); long audio_init (long mem_start); +#ifdef ALLOW_SELECT +int audio_select(int dev, struct fileinfo *file, int sel_type, select_table * wait); +#endif + /* * System calls for the /dev/sequencer */ @@ -87,28 +86,20 @@ long CMIDI_init (long mem_start); int CMIDI_open (int dev, struct fileinfo *file); int CMIDI_write (int dev, struct fileinfo *file, snd_rw_buf *buf, int count); int CMIDI_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count); -int CMIDI_close (int dev, struct fileinfo *file); +int CMIDI_close (int dev, struct fileinfo *file); /* * * Misc calls from various sources */ -/* From pro_midi.c */ - -long pro_midi_attach(long mem_start); -int pro_midi_open(int dev, int mode); -void pro_midi_close(int dev); -int pro_midi_write(int dev, snd_rw_buf *uio); -int pro_midi_read(int dev, snd_rw_buf *uio); - /* From soundcard.c */ long soundcard_init(long mem_start); void tenmicrosec(void); void request_sound_timer (int count); void sound_stop_timer(void); int snd_ioctl_return(int *addr, int value); -int snd_set_irq_handler (int interrupt_level, void(*hndlr)(int)); +int snd_set_irq_handler (int interrupt_level, INT_HANDLER_PROTO(), char *name); void snd_release_irq(int vect); void sound_dma_malloc(int dev); void sound_dma_free(int dev); @@ -131,7 +122,7 @@ int sb_dsp_command (unsigned char val); int sb_reset_dsp (void); /* From sb16_dsp.c */ -void sb16_dsp_interrupt (int unused); +void sb16_dsp_interrupt (int irq); long sb16_dsp_init(long mem_start, struct address_info *hw_config); int sb16_dsp_detect(struct address_info *hw_config); @@ -163,7 +154,6 @@ long attach_adlib_card(long mem_start, struct address_info *hw_config); int probe_adlib(struct address_info *hw_config); /* From pas_card.c */ -void mix_write(unsigned char data, int ioaddr); long attach_pas_card(long mem_start, struct address_info *hw_config); int probe_pas(struct address_info *hw_config); int pas_set_intr(int mask); @@ -186,13 +176,13 @@ void pas_midi_interrupt(void); long attach_gus_card(long mem_start, struct address_info * hw_config); int probe_gus(struct address_info *hw_config); int gus_set_midi_irq(int num); -void gusintr(int); +void gusintr(INT_HANDLER_PARMS(irq, dummy)); long attach_gus_db16(long mem_start, struct address_info * hw_config); int probe_gus_db16(struct address_info *hw_config); /* From gus_wave.c */ int gus_wave_detect(int baseaddr); -long gus_wave_init(long mem_start, int irq, int dma); +long gus_wave_init(long mem_start, int irq, int dma, int dma_read); void gus_voice_irq(void); unsigned char gus_read8 (int reg); void gus_write8(int reg, unsigned int data); @@ -207,6 +197,7 @@ void gus_midi_interrupt(int dummy); /* From mpu401.c */ long attach_mpu401(long mem_start, struct address_info * hw_config); int probe_mpu401(struct address_info *hw_config); +void mpuintr(INT_HANDLER_PARMS(irq, dummy)); /* From uart6850.c */ long attach_uart6850(long mem_start, struct address_info * hw_config); @@ -234,13 +225,23 @@ void sound_timer_interrupt(void); /* From ad1848.c */ void ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture); int ad1848_detect (int io_base); -void adintr (int dev); +void ad1848_interrupt (INT_HANDLER_PARMS(irq, dummy)); long attach_ms_sound(long mem_start, struct address_info * hw_config); int probe_ms_sound(struct address_info *hw_config); /* From pss.c */ int probe_pss (struct address_info *hw_config); long attach_pss (long mem_start, struct address_info *hw_config); +int probe_pss_mpu (struct address_info *hw_config); +long attach_pss_mpu (long mem_start, struct address_info *hw_config); +int probe_pss_mss (struct address_info *hw_config); +long attach_pss_mss (long mem_start, struct address_info *hw_config); + +/* From sscape.c */ +int probe_sscape (struct address_info *hw_config); +long attach_sscape (long mem_start, struct address_info *hw_config); +int probe_ss_ms_sound (struct address_info *hw_config); +long attach_ss_ms_sound(long mem_start, struct address_info * hw_config); int pss_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count); int pss_write (int dev, struct fileinfo *file, snd_rw_buf *buf, int count); @@ -251,4 +252,18 @@ int pss_ioctl (int dev, struct fileinfo *file, int pss_lseek (int dev, struct fileinfo *file, off_t offset, int orig); long pss_init(long mem_start); -#endif /* _MACHINE_ISA_SOUND_H_ */ +/* From aedsp16.c */ +int InitAEDSP16_SBPRO(struct address_info *hw_config); +int InitAEDSP16_MSS(struct address_info *hw_config); +int InitAEDSP16_MPU401(struct address_info *hw_config); + +/* From midi_synth.c */ +void do_midi_msg (int synthno, unsigned char *msg, int mlen); + +/* From trix.c */ +long attach_trix_wss (long mem_start, struct address_info *hw_config); +int probe_trix_wss (struct address_info *hw_config); +long attach_trix_sb (long mem_start, struct address_info *hw_config); +int probe_trix_sb (struct address_info *hw_config); +long attach_trix_mpu (long mem_start, struct address_info *hw_config); +int probe_trix_mpu (struct address_info *hw_config); diff --git a/sys/i386/isa/sound/sound_config.h b/sys/i386/isa/sound/sound_config.h index c3732d5..55ac84c 100644 --- a/sys/i386/isa/sound/sound_config.h +++ b/sys/i386/isa/sound/sound_config.h @@ -2,7 +2,7 @@ * * A driver for Soundcards, misc configuration parameters. * - * + * * Copyright by Hannu Savolainen 1993 * * Redistribution and use in source and binary forms, with or without @@ -26,10 +26,15 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: sound_config.h,v 1.9 1995/03/12 23:34:07 swallace Exp $ */ #include "local.h" +#include "os.h" +#include "soundvers.h" + +#if !defined(PSS_MPU_BASE) && defined(EXCLUDE_SSCAPE) && defined(EXCLUDE_TRIX) +#define EXCLUDE_MPU_EMU +#endif #if defined(ISC) || defined(SCO) || defined(SVR42) #define GENERIC_SYSV @@ -39,10 +44,14 @@ * Disable the AD1848 driver if there are no other drivers requiring it. */ -#if defined(EXCLUDE_GUS16) && defined(EXCLUDE_MSS) && defined(EXCLUDE_PSS) && defined(EXCLUDE_GUSMAX) +#if defined(EXCLUDE_GUS16) && defined(EXCLUDE_MSS) && defined(EXCLUDE_PSS) && defined(EXCLUDE_GUSMAX) && defined(EXCLUDE_SSCAPE) && defined(EXCLUDE_TRIX) #define EXCLUDE_AD1848 #endif +#ifdef PSS_MSS_BASE +#undef EXCLUDE_AD1848 +#endif + #undef CONFIGURE_SOUNDCARD #undef DYNAMIC_BUFFER @@ -53,9 +62,9 @@ #endif #ifdef EXCLUDE_SEQUENCER -#ifndef EXCLUDE_YM3812 +#define EXCLUDE_MIDI #define EXCLUDE_YM3812 -#endif +#define EXCLUDE_OPL3 #endif #ifndef SND_DEFAULT_ENABLE @@ -117,16 +126,8 @@ If your card has nonstandard I/O address or IRQ number, change defines #define GUS_DMA 6 #endif -#ifndef GUS16_BASE -#define GUS16_BASE 0x530 -#endif - -#ifndef GUS16_IRQ -#define GUS16_IRQ 7 -#endif - -#ifndef GUS16_DMA -#define GUS16_DMA 3 +#ifndef GUS_DMA_READ +#define GUS_DMA_READ 3 #endif #ifndef MPU_BASE @@ -150,32 +151,68 @@ If your card has nonstandard I/O address or IRQ number, change defines #define PSS_DMA 1 #endif -#ifndef MAX_REALTIME_FACTOR -#define MAX_REALTIME_FACTOR 4 +#ifndef MSS_BASE +#define MSS_BASE 0 #endif -#ifndef MSS_BASE -#define MSS_BASE 0x530 +#ifndef MSS_DMA +#define MSS_DMA 0 #endif #ifndef MSS_IRQ -#define MSS_IRQ 10 +#define MSS_IRQ 0 #endif -#ifndef MSS_DMA -#define MSS_DMA 1 +#ifndef GUS16_BASE +#define GUS16_BASE 0 +#endif + +#ifndef GUS16_DMA +#define GUS16_DMA 0 #endif -#ifndef U6850_BASE -#define U6850_BASE 0x330 +#ifndef GUS16_IRQ +#define GUS16_IRQ 0 #endif -#ifndef U6850_IRQ -#define U6850_IRQ 5 +#ifndef SSCAPE_BASE +#define SSCAPE_BASE 0 #endif -#ifndef U6850_DMA -#define U6850_DMA 1 +#ifndef SSCAPE_DMA +#define SSCAPE_DMA 0 +#endif + +#ifndef SSCAPE_IRQ +#define SSCAPE_IRQ 0 +#endif + +#ifndef SSCAPE_MSS_BASE +#define SSCAPE_MSS_BASE 0 +#endif + +#ifndef SSCAPE_MSS_DMA +#define SSCAPE_MSS_DMA 0 +#endif + +#ifndef SSCAPE_MSS_IRQ +#define SSCAPE_MSS_IRQ 0 +#endif + +#ifndef TRIX_BASE +#define TRIX_BASE 0x530 +#endif + +#ifndef TRIX_IRQ +#define TRIX_IRQ 10 +#endif + +#ifndef TRIX_DMA +#define TRIX_DMA 1 +#endif + +#ifndef MAX_REALTIME_FACTOR +#define MAX_REALTIME_FACTOR 4 #endif /************* PCM DMA buffer sizes *******************/ @@ -227,7 +264,7 @@ If your card has nonstandard I/O address or IRQ number, change defines #define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */ #define SND_DEV_STATUS 6 /* /dev/sndstat */ /* #7 not in use now. Was in 2.4. Free for use after v3.0. */ -#define SND_DEV_SEQ2 8 /* /dev/sequencer, level 2 interface */ +#define SND_DEV_SEQ2 8 /* /dev/sequecer, level 2 interface */ #define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */ #define SND_DEV_PSS SND_DEV_SNDPROC @@ -237,19 +274,22 @@ If your card has nonstandard I/O address or IRQ number, change defines #define OFF 0 #define MAX_AUDIO_DEV 5 -#define MAX_MIXER_DEV 2 +#define MAX_MIXER_DEV 5 #define MAX_SYNTH_DEV 3 #define MAX_MIDI_DEV 6 #define MAX_TIMER_DEV 3 struct fileinfo { - int mode; /* Open mode */ + int mode; /* Open mode */ + DECLARE_FILE(); /* Reference to file-flags. OS-dependent. */ }; struct address_info { int io_base; int irq; - int dma; + int dma; /* write dma channel */ + int dma_read; /* read dma channel */ + int always_detect; /* 1=Trust me, it's there */ }; #define SYNTH_MAX_VOICES 32 @@ -259,10 +299,13 @@ struct voice_alloc_info { int used_voices; int ptr; /* For device specific use */ unsigned short map[SYNTH_MAX_VOICES]; /* (ch << 8) | (note+1) */ + int timestamp; + int alloc_times[SYNTH_MAX_VOICES]; }; struct channel_info { int pgm_num; + int bender_value; unsigned char controllers[128]; }; @@ -279,17 +322,18 @@ struct channel_info { #define OPEN_WRITE 2 #define OPEN_READWRITE 3 -#include "os.h" #include "sound_calls.h" #include "dev_table.h" #ifndef DEB #define DEB(x) +#endif + +#ifndef AUDIO_DDB +#define AUDIO_DDB(x) +#endif #define TIMER_ARMED 121234 #define TIMER_NOT_ARMED 1 -#define FUTURE_VERSION -#endif - #endif diff --git a/sys/i386/isa/sound/sound_switch.c b/sys/i386/isa/sound/sound_switch.c index b66cad5..2b9233f 100644 --- a/sys/i386/isa/sound/sound_switch.c +++ b/sys/i386/isa/sound/sound_switch.c @@ -25,7 +25,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * sound_switch.c,v 1.4 1994/10/01 02:17:12 swallace Exp */ #include "sound_config.h" @@ -116,7 +115,7 @@ init_status (void) status_ptr = 0; - put_status ("Sound Driver:" SOUND_VERSION_STRING + put_status ("VoxWare Sound Driver:" SOUND_VERSION_STRING " (" SOUND_CONFIG_DATE " " SOUND_CONFIG_BY "@" SOUND_CONFIG_HOST "." SOUND_CONFIG_DOMAIN ")" "\n"); @@ -185,7 +184,11 @@ init_status (void) return; } - if (!put_status ("\nPCM devices:\n")) +#ifdef EXCLUDE_AUDIO + if (!put_status ("\nAudio devices: NOT ENABLED IN CONFIG\n")) + return; +#else + if (!put_status ("\nAudio devices:\n")) return; for (i = 0; i < num_audiodevs; i++) @@ -199,7 +202,12 @@ init_status (void) if (!put_status ("\n")) return; } +#endif +#ifdef EXCLUDE_SEQUENCER + if (!put_status ("\nSynth devices: NOT ENABLED IN CONFIG\n")) + return; +#else if (!put_status ("\nSynth devices:\n")) return; @@ -214,7 +222,12 @@ init_status (void) if (!put_status ("\n")) return; } +#endif +#ifdef EXCLUDE_MIDI + if (!put_status ("\nMidi devices: NOT ENABLED IN CONFIG\n")) + return; +#else if (!put_status ("\nMidi devices:\n")) return; @@ -229,8 +242,9 @@ init_status (void) if (!put_status ("\n")) return; } +#endif - if (!put_status ("\nMIDI Timers:\n")) + if (!put_status ("\nTimers:\n")) return; for (i = 0; i < num_sound_timers; i++) @@ -245,12 +259,20 @@ init_status (void) return; } - if (!put_status ("\n")) - return; - if (!put_status_int (num_mixers, 10)) - return; - if (!put_status (" mixer(s) installed\n")) + if (!put_status ("\nMixers:\n")) return; + + for (i = 0; i < num_mixers; i++) + { + if (!put_status_int (i, 10)) + return; + if (!put_status (": ")) + return; + if (!put_status (mixer_devs[i]->name)) + return; + if (!put_status ("\n")) + return; + } } static int @@ -292,23 +314,16 @@ sound_read_sw (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) return audio_read (dev, file, buf, count); break; -#ifndef EXCLUDE_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: return sequencer_read (dev, file, buf, count); break; -#endif #ifndef EXCLUDE_MIDI case SND_DEV_MIDIN: return MIDIbuf_read (dev, file, buf, count); #endif -#ifndef EXCLUDE_PSS - case SND_DEV_PSS: - return pss_read (dev, file, buf, count); -#endif - default: printk ("Sound: Undefined minor device %d\n", dev); } @@ -325,12 +340,10 @@ sound_write_sw (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) switch (dev & 0x0f) { -#ifndef EXCLUDE_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: return sequencer_write (dev, file, buf, count); break; -#endif case SND_DEV_DSP: case SND_DEV_DSP16: @@ -343,11 +356,6 @@ sound_write_sw (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) return MIDIbuf_write (dev, file, buf, count); #endif -#ifndef EXCLUDE_PSS - case SND_DEV_PSS: - return pss_write (dev, file, buf, count); -#endif - default: return RET_ERROR (EPERM); } @@ -384,13 +392,11 @@ sound_open_sw (int dev, struct fileinfo *file) return 0; break; -#ifndef EXCLUDE_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: if ((retval = sequencer_open (dev, file)) < 0) return retval; break; -#endif #ifndef EXCLUDE_MIDI case SND_DEV_MIDIN: @@ -399,13 +405,6 @@ sound_open_sw (int dev, struct fileinfo *file) break; #endif -#ifndef EXCLUDE_PSS - case SND_DEV_PSS: - if ((retval = pss_open (dev, file)) < 0) - return retval; - break; -#endif - case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: @@ -442,12 +441,10 @@ sound_release_sw (int dev, struct fileinfo *file) case SND_DEV_CTL: break; -#ifndef EXCLUDE_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: sequencer_release (dev, file); break; -#endif #ifndef EXCLUDE_MIDI case SND_DEV_MIDIN: @@ -455,12 +452,6 @@ sound_release_sw (int dev, struct fileinfo *file) break; #endif -#ifndef EXCLUDE_PSS - case SND_DEV_PSS: - pss_release (dev, file); - break; -#endif - case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: @@ -481,11 +472,27 @@ sound_ioctl_sw (int dev, struct fileinfo *file, { DEB (printk ("sound_ioctl_sw(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg)); - if ((dev & 0x0f) != SND_DEV_CTL && num_mixers > 0) - if ((cmd >> 8) & 0xff == 'M') /* - * Mixer ioctl - */ - return mixer_devs[0]->ioctl (0, cmd, arg); + if ((cmd >> 8) & 0xff == 'M' && num_mixers > 0) /* Mixer ioctl */ + if ((dev & 0x0f) != SND_DEV_CTL) + { + int dtype = dev & 0x0f; + int mixdev; + + switch (dtype) + { + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + mixdev = audio_devs[dev >> 4]->mixer_dev; + if (mixdev < 0 || mixdev >= num_mixers) + return RET_ERROR (ENXIO); + return mixer_devs[mixdev]->ioctl (mixdev, cmd, arg); + break; + + default: + return mixer_devs[0]->ioctl (0, cmd, arg); + } + } switch (dev & 0x0f) { @@ -503,12 +510,10 @@ sound_ioctl_sw (int dev, struct fileinfo *file, return mixer_devs[dev]->ioctl (dev, cmd, arg); break; -#ifndef EXCLUDE_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: return sequencer_ioctl (dev, file, cmd, arg); break; -#endif case SND_DEV_DSP: case SND_DEV_DSP16: @@ -522,12 +527,6 @@ sound_ioctl_sw (int dev, struct fileinfo *file, break; #endif -#ifndef EXCLUDE_PSS - case SND_DEV_PSS: - return pss_ioctl (dev, file, cmd, arg); - break; -#endif - default: return RET_ERROR (EPERM); break; diff --git a/sys/i386/isa/sound/sound_timer.c b/sys/i386/isa/sound/sound_timer.c index 91a9f41..e318779 100644 --- a/sys/i386/isa/sound/sound_timer.c +++ b/sys/i386/isa/sound/sound_timer.c @@ -26,7 +26,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * sound_timer.c,v 1.2 1994/10/01 02:17:13 swallace Exp */ #define SEQUENCER_C @@ -88,8 +87,8 @@ static unsigned long tmr2ticks (int tmr_value) { /* - * Convert timer ticks to MIDI ticks - */ + * Convert timer ticks to MIDI ticks + */ unsigned long tmp; unsigned long scale; @@ -111,8 +110,8 @@ reprogram_timer (void) usecs_per_tick = (60 * 1000000) / (curr_tempo * curr_timebase); /* - * Don't kill the system by setting too high timer rate - */ + * Don't kill the system by setting too high timer rate + */ if (usecs_per_tick < 2000) usecs_per_tick = 2000; diff --git a/sys/i386/isa/sound/soundcard.c b/sys/i386/isa/sound/soundcard.c index a396727..9443c6e 100644 --- a/sys/i386/isa/sound/soundcard.c +++ b/sys/i386/isa/sound/soundcard.c @@ -1,8 +1,8 @@ /* * sound/386bsd/soundcard.c - * + * * Soundcard driver for FreeBSD. - * + * * Copyright by Hannu Savolainen 1993 * * Redistribution and use in source and binary forms, with or without @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: soundcard.c,v 1.25 1995/05/11 19:26:24 rgrimes Exp $ + * $Id: soundcard.c,v 1.24 1995/03/12 23:34:10 swallace Exp $ */ #include "sound_config.h" @@ -78,6 +78,14 @@ struct isa_driver gusmaxdriver = {sndprobe, sndattach, "gusmax"}; struct isa_driver uartdriver = {sndprobe, sndattach, "uart"}; struct isa_driver mssdriver = {sndprobe, sndattach, "mss"}; +void +adintr(INT_HANDLER_PARMS(irq,dummy)) +{ +#ifndef EXCLUDE_AD1848 + ad1848_interrupt(INT_HANDLER_CALL(irq)); +#endif +} + unsigned long get_time(void) @@ -91,7 +99,7 @@ int x; return timecopy.tv_usec/(1000000/HZ) + (unsigned long)timecopy.tv_sec*HZ; } - + int sndread (int dev, struct uio *buf) @@ -162,31 +170,40 @@ sndioctl (dev_t dev, int cmd, caddr_t arg, int mode) int sndselect (int dev, int rw, struct proc *p) { - int r,s; - dev = minor (dev); - DEB (printk ("sound_ioctl(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg)); - - r = 0; - DISABLE_INTR(s); - switch (rw) { - case FREAD: /* record */ - if(DMAbuf_input_ready(dev >> 4)) - r = 1; - else - selrecord(p, &selinfo[dev >> 4]); - break; - case FWRITE: /* play */ - if(DMAbuf_output_ready(dev >> 4)) - r = 1; - else - selrecord(p, &selinfo[dev >> 4]); - break; - } - RESTORE_INTR(s); - - return r; + DEB (printk ("snd_select(dev=%d, rw=%d, pid=%d)\n", dev, rw, p->p_pid)); +#ifdef ALLOW_SELECT + switch (dev & 0x0f) + { +#ifndef EXCLUDE_SEQUENCER + case SND_DEV_SEQ: + case SND_DEV_SEQ2: + return sequencer_select (dev, &files[dev], rw, p); + break; +#endif + +#ifndef EXCLUDE_MIDI + case SND_DEV_MIDIN: + return MIDIbuf_select (dev, &files[dev], rw, p); + break; +#endif + +#ifndef EXCLUDE_AUDIO + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + return audio_select (dev, &files[dev], rw, p); + break; +#endif + + default: + return 0; + } + +#endif + + return 0; } static unsigned short @@ -243,7 +260,8 @@ sndprobe (struct isa_device *dev) hw_config.io_base = dev->id_iobase; hw_config.irq = ipri_to_irq (dev->id_irq); hw_config.dma = dev->id_drq; - + hw_config.dma_read = dev->id_flags; /* misuse the flags field for read dma*/ + if(unit) return sndtable_probe (unit, &hw_config); else @@ -256,7 +274,7 @@ sndattach (struct isa_device *dev) int i, unit; static int midi_initialized = 0; static int seq_initialized = 0; - static int generic_midi_initialized = 0; + static int generic_midi_initialized = 0; unsigned long mem_start = 0xefffffffUL; struct address_info hw_config; @@ -264,6 +282,7 @@ sndattach (struct isa_device *dev) hw_config.io_base = dev->id_iobase; hw_config.irq = ipri_to_irq (dev->id_irq); hw_config.dma = dev->id_drq; + hw_config.dma_read = dev->id_flags; /* misuse the flags field for read dma*/ if(!unit) return FALSE; @@ -400,7 +419,7 @@ sound_mem_init (void) if (tmpbuf == NULL) { - printk ("snd: Unable to allocate %ld bytes of buffer\n", + printk ("snd: Unable to allocate %d bytes of buffer\n", audio_devs[dev]->buffsize); return; } @@ -429,11 +448,12 @@ snd_ioctl_return (int *addr, int value) } int -snd_set_irq_handler (int interrupt_level, void(*hndlr)(int)) +snd_set_irq_handler (int interrupt_level, INT_HANDLER_PROTO(), char *name) { return 1; } + void snd_release_irq(int vect) { diff --git a/sys/i386/isa/sound/soundcard.h b/sys/i386/isa/sound/soundcard.h new file mode 100644 index 0000000..02d0da7 --- /dev/null +++ b/sys/i386/isa/sound/soundcard.h @@ -0,0 +1,1045 @@ +#ifndef SOUNDCARD_H +#define SOUNDCARD_H +/* + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + */ + + /* + * If you make modifications to this file, please contact me before + * distributing the modified version. There is already enough + * divercity in the world. + * + * Regards, + * Hannu Savolainen + * hannu@voxware.pp.fi + */ + +#define SOUND_VERSION 301 +#define VOXWARE + +#include <sys/ioctl.h> + +/* + * Supported card ID numbers (Should be somewhere else?) + */ + +#define SNDCARD_ADLIB 1 +#define SNDCARD_SB 2 +#define SNDCARD_PAS 3 +#define SNDCARD_GUS 4 +#define SNDCARD_MPU401 5 +#define SNDCARD_SB16 6 +#define SNDCARD_SB16MIDI 7 +#define SNDCARD_UART6850 8 +#define SNDCARD_GUS16 9 +#define SNDCARD_MSS 10 +#define SNDCARD_PSS 11 +#define SNDCARD_SSCAPE 12 +#define SNDCARD_PSS_MPU 13 +#define SNDCARD_PSS_MSS 14 +#define SNDCARD_SSCAPE_MSS 15 +#define SNDCARD_TRXPRO 16 +#define SNDCARD_TRXPRO_SB 17 +#define SNDCARD_TRXPRO_MPU 18 + +/*********************************** + * IOCTL Commands for /dev/sequencer + */ + +#ifndef _IOWR +/* @(#)ioctlp.h */ + +/* Ioctl's have the command encoded in the lower word, + * and the size of any in or out parameters in the upper + * word. The high 2 bits of the upper word are used + * to encode the in/out status of the parameter; for now + * we restrict parameters to at most 128 bytes. + */ +/* #define IOCTYPE (0xff<<8) */ +#define IOCPARM_MASK 0x7f /* parameters must be < 128 bytes */ +#define IOC_VOID 0x00000000 /* no parameters */ +#define IOC_OUT 0x20000000 /* copy out parameters */ +#define IOC_IN 0x40000000 /* copy in parameters */ +#define IOC_INOUT (IOC_IN|IOC_OUT) +/* the 0x20000000 is so we can distinguish new ioctl's from old */ +#define _IO(x,y) ((int)(IOC_VOID|(x<<8)|y)) +#define _IOR(x,y,t) ((int)(IOC_OUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y)) +#define _IOW(x,y,t) ((int)(IOC_IN|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y)) +/* this should be _IORW, but stdio got there first */ +#define _IOWR(x,y,t) ((int)(IOC_INOUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y)) +#endif /* !_IOWR */ + +#define SNDCTL_SEQ_RESET _IO ('Q', 0) +#define SNDCTL_SEQ_SYNC _IO ('Q', 1) +#define SNDCTL_SYNTH_INFO _IOWR('Q', 2, struct synth_info) +#define SNDCTL_SEQ_CTRLRATE _IOWR('Q', 3, int) /* Set/get timer resolution (HZ) */ +#define SNDCTL_SEQ_GETOUTCOUNT _IOR ('Q', 4, int) +#define SNDCTL_SEQ_GETINCOUNT _IOR ('Q', 5, int) +#define SNDCTL_SEQ_PERCMODE _IOW ('Q', 6, int) +#define SNDCTL_FM_LOAD_INSTR _IOW ('Q', 7, struct sbi_instrument) /* Valid for FM only */ +#define SNDCTL_SEQ_TESTMIDI _IOW ('Q', 8, int) +#define SNDCTL_SEQ_RESETSAMPLES _IOW ('Q', 9, int) +#define SNDCTL_SEQ_NRSYNTHS _IOR ('Q',10, int) +#define SNDCTL_SEQ_NRMIDIS _IOR ('Q',11, int) +#define SNDCTL_MIDI_INFO _IOWR('Q',12, struct midi_info) +#define SNDCTL_SEQ_TRESHOLD _IOW ('Q',13, int) +#define SNDCTL_SYNTH_MEMAVL _IOWR('Q',14, int) /* in=dev#, out=memsize */ +#define SNDCTL_FM_4OP_ENABLE _IOW ('Q',15, int) /* in=dev# */ +#define SNDCTL_PMGR_ACCESS _IOWR('Q',16, struct patmgr_info) +#define SNDCTL_SEQ_PANIC _IO ('Q',17) +#define SNDCTL_SEQ_OUTOFBAND _IOW ('Q',18, struct seq_event_rec) + + struct seq_event_rec { + unsigned char arr[8]; + }; + +#define SNDCTL_TMR_TIMEBASE _IOWR('T', 1, int) +#define SNDCTL_TMR_START _IO ('T', 2) +#define SNDCTL_TMR_STOP _IO ('T', 3) +#define SNDCTL_TMR_CONTINUE _IO ('T', 4) +#define SNDCTL_TMR_TEMPO _IOWR('T', 5, int) +#define SNDCTL_TMR_SOURCE _IOWR('T', 6, int) +# define TMR_INTERNAL 0x00000001 +# define TMR_EXTERNAL 0x00000002 +# define TMR_MODE_MIDI 0x00000010 +# define TMR_MODE_FSK 0x00000020 +# define TMR_MODE_CLS 0x00000040 +# define TMR_MODE_SMPTE 0x00000080 +#define SNDCTL_TMR_METRONOME _IOW ('T', 7, int) +#define SNDCTL_TMR_SELECT _IOW ('T', 8, int) + +/* + * Sample loading mechanism for internal synthesizers (/dev/sequencer) + * The following patch_info structure has been designed to support + * Gravis UltraSound. It tries to be universal format for uploading + * sample based patches but is propably too limited. + */ + +struct patch_info { + short key; /* Use GUS_PATCH here */ +#define GUS_PATCH 0x04fd +#define OBSOLETE_GUS_PATCH 0x02fd + short device_no; /* Synthesizer number */ + short instr_no; /* Midi pgm# */ + + unsigned long mode; +/* + * The least significant byte has the same format than the GUS .PAT + * files + */ +#define WAVE_16_BITS 0x01 /* bit 0 = 8 or 16 bit wave data. */ +#define WAVE_UNSIGNED 0x02 /* bit 1 = Signed - Unsigned data. */ +#define WAVE_LOOPING 0x04 /* bit 2 = looping enabled-1. */ +#define WAVE_BIDIR_LOOP 0x08 /* bit 3 = Set is bidirectional looping. */ +#define WAVE_LOOP_BACK 0x10 /* bit 4 = Set is looping backward. */ +#define WAVE_SUSTAIN_ON 0x20 /* bit 5 = Turn sustaining on. (Env. pts. 3)*/ +#define WAVE_ENVELOPES 0x40 /* bit 6 = Enable envelopes - 1 */ + /* (use the env_rate/env_offs fields). */ +/* Linux specific bits */ +#define WAVE_VIBRATO 0x00010000 /* The vibrato info is valid */ +#define WAVE_TREMOLO 0x00020000 /* The tremolo info is valid */ +#define WAVE_SCALE 0x00040000 /* The scaling info is valid */ +/* Other bits must be zeroed */ + + long len; /* Size of the wave data in bytes */ + long loop_start, loop_end; /* Byte offsets from the beginning */ + +/* + * The base_freq and base_note fields are used when computing the + * playback speed for a note. The base_note defines the tone frequency + * which is heard if the sample is played using the base_freq as the + * playback speed. + * + * The low_note and high_note fields define the minimum and maximum note + * frequencies for which this sample is valid. It is possible to define + * more than one samples for a instrument number at the same time. The + * low_note and high_note fields are used to select the most suitable one. + * + * The fields base_note, high_note and low_note should contain + * the note frequency multiplied by 1000. For example value for the + * middle A is 440*1000. + */ + + unsigned int base_freq; + unsigned long base_note; + unsigned long high_note; + unsigned long low_note; + int panning; /* -128=left, 127=right */ + int detuning; + +/* New fields introduced in version 1.99.5 */ + + /* Envelope. Enabled by mode bit WAVE_ENVELOPES */ + unsigned char env_rate[ 6 ]; /* GUS HW ramping rate */ + unsigned char env_offset[ 6 ]; /* 255 == 100% */ + + /* + * The tremolo, vibrato and scale info are not supported yet. + * Enable by setting the mode bits WAVE_TREMOLO, WAVE_VIBRATO or + * WAVE_SCALE + */ + + unsigned char tremolo_sweep; + unsigned char tremolo_rate; + unsigned char tremolo_depth; + + unsigned char vibrato_sweep; + unsigned char vibrato_rate; + unsigned char vibrato_depth; + + int scale_frequency; + unsigned int scale_factor; /* from 0 to 2048 or 0 to 2 */ + + int volume; + int spare[4]; + char data[1]; /* The waveform data starts here */ + }; + + +struct sysex_info { + short key; /* Use GUS_PATCH here */ +#define SYSEX_PATCH 0x05fd + short device_no; /* Synthesizer number */ + long len; /* Size of the sysex data in bytes */ + unsigned char data[1]; /* Sysex data starts here */ + }; + +/* + * Patch management interface (/dev/sequencer, /dev/patmgr#) + * Don't use these calls if you want to maintain compatibility with + * the future versions of the driver. + */ + +#define PS_NO_PATCHES 0 /* No patch support on device */ +#define PS_MGR_NOT_OK 1 /* Plain patch support (no mgr) */ +#define PS_MGR_OK 2 /* Patch manager supported */ +#define PS_MANAGED 3 /* Patch manager running */ + +#define SNDCTL_PMGR_IFACE _IOWR('P', 1, struct patmgr_info) + +/* + * The patmgr_info is a fixed size structure which is used for two + * different purposes. The intended use is for communication between + * the application using /dev/sequencer and the patch manager daemon + * associated with a synthesizer device (ioctl(SNDCTL_PMGR_ACCESS)). + * + * This structure is also used with ioctl(SNDCTL_PGMR_IFACE) which allows + * a patch manager daemon to read and write device parameters. This + * ioctl available through /dev/sequencer also. Avoid using it since it's + * extremely hardware dependent. In addition access trough /dev/sequencer + * may confuse the patch manager daemon. + */ + +struct patmgr_info { /* Note! size must be < 4k since kmalloc() is used */ + unsigned long key; /* Don't worry. Reserved for communication + between the patch manager and the driver. */ +#define PM_K_EVENT 1 /* Event from the /dev/sequencer driver */ +#define PM_K_COMMAND 2 /* Request from a application */ +#define PM_K_RESPONSE 3 /* From patmgr to application */ +#define PM_ERROR 4 /* Error returned by the patmgr */ + int device; + int command; + +/* + * Commands 0x000 to 0xfff reserved for patch manager programs + */ +#define PM_GET_DEVTYPE 1 /* Returns type of the patch mgr interface of dev */ +#define PMTYPE_FM2 1 /* 2 OP fm */ +#define PMTYPE_FM4 2 /* Mixed 4 or 2 op FM (OPL-3) */ +#define PMTYPE_WAVE 3 /* Wave table synthesizer (GUS) */ +#define PM_GET_NRPGM 2 /* Returns max # of midi programs in parm1 */ +#define PM_GET_PGMMAP 3 /* Returns map of loaded midi programs in data8 */ +#define PM_GET_PGM_PATCHES 4 /* Return list of patches of a program (parm1) */ +#define PM_GET_PATCH 5 /* Return patch header of patch parm1 */ +#define PM_SET_PATCH 6 /* Set patch header of patch parm1 */ +#define PM_READ_PATCH 7 /* Read patch (wave) data */ +#define PM_WRITE_PATCH 8 /* Write patch (wave) data */ + +/* + * Commands 0x1000 to 0xffff are for communication between the patch manager + * and the client + */ +#define _PM_LOAD_PATCH 0x100 + +/* + * Commands above 0xffff reserved for device specific use + */ + + long parm1; + long parm2; + long parm3; + + union { + unsigned char data8[4000]; + unsigned short data16[2000]; + unsigned long data32[1000]; + struct patch_info patch; + } data; + }; + +/* + * When a patch manager daemon is present, it will be informed by the + * driver when something important happens. For example when the + * /dev/sequencer is opened or closed. A record with key == PM_K_EVENT is + * returned. The command field contains the event type: + */ +#define PM_E_OPENED 1 /* /dev/sequencer opened */ +#define PM_E_CLOSED 2 /* /dev/sequencer closed */ +#define PM_E_PATCH_RESET 3 /* SNDCTL_RESETSAMPLES called */ +#define PM_E_PATCH_LOADED 4 /* A patch has been loaded by appl */ + +/* + * /dev/sequencer input events. + * + * The data written to the /dev/sequencer is a stream of events. Events + * are records of 4 or 8 bytes. The first byte defines the size. + * Any number of events can be written with a write call. There + * is a set of macros for sending these events. Use these macros if you + * want to maximize portability of your program. + * + * Events SEQ_WAIT, SEQ_MIDIPUTC and SEQ_ECHO. Are also input events. + * (All input events are currently 4 bytes long. Be prepared to support + * 8 byte events also. If you receive any event having first byte >= 128, + * it's a 8 byte event. + * + * The events are documented at the end of this file. + * + * Normal events (4 bytes) + * There is also a 8 byte version of most of the 4 byte events. The + * 8 byte one is recommended. + */ +#define SEQ_NOTEOFF 0 +#define SEQ_FMNOTEOFF SEQ_NOTEOFF /* Just old name */ +#define SEQ_NOTEON 1 +#define SEQ_FMNOTEON SEQ_NOTEON +#define SEQ_WAIT TMR_WAIT_ABS +#define SEQ_PGMCHANGE 3 +#define SEQ_FMPGMCHANGE SEQ_PGMCHANGE +#define SEQ_SYNCTIMER TMR_START +#define SEQ_MIDIPUTC 5 +#define SEQ_DRUMON 6 /*** OBSOLETE ***/ +#define SEQ_DRUMOFF 7 /*** OBSOLETE ***/ +#define SEQ_ECHO TMR_ECHO /* For synching programs with output */ +#define SEQ_AFTERTOUCH 9 +#define SEQ_CONTROLLER 10 + +/******************************************* + * Midi controller numbers + ******************************************* + * Controllers 0 to 31 (0x00 to 0x1f) and + * 32 to 63 (0x20 to 0x3f) are continuous + * controllers. + * In the MIDI 1.0 these controllers are sent using + * two messages. Controller numbers 0 to 31 are used + * to send the MSB and the controller numbers 32 to 63 + * are for the LSB. Note that just 7 bits are used in MIDI bytes. + */ + +#define CTL_BANK_SELECT 0x00 +#define CTL_MODWHEEL 0x01 +#define CTL_BREATH 0x02 +/* undefined 0x03 */ +#define CTL_FOOT 0x04 +#define CTL_PORTAMENTO_TIME 0x05 +#define CTL_DATA_ENTRY 0x06 +#define CTL_MAIN_VOLUME 0x07 +#define CTL_BALANCE 0x08 +/* undefined 0x09 */ +#define CTL_PAN 0x0a +#define CTL_EXPRESSION 0x0b +/* undefined 0x0c */ +/* undefined 0x0d */ +/* undefined 0x0e */ +/* undefined 0x0f */ +#define CTL_GENERAL_PURPOSE1 0x10 +#define CTL_GENERAL_PURPOSE2 0x11 +#define CTL_GENERAL_PURPOSE3 0x12 +#define CTL_GENERAL_PURPOSE4 0x13 +/* undefined 0x14 - 0x1f */ + +/* undefined 0x20 */ +/* The controller numbers 0x21 to 0x3f are reserved for the */ +/* least significant bytes of the controllers 0x00 to 0x1f. */ +/* These controllers are not recognised by the driver. */ + +/* Controllers 64 to 69 (0x40 to 0x45) are on/off switches. */ +/* 0=OFF and 127=ON (intermediate values are possible) */ +#define CTL_DAMPER_PEDAL 0x40 +#define CTL_SUSTAIN 0x40 /* Alias */ +#define CTL_HOLD 0x40 /* Alias */ +#define CTL_PORTAMENTO 0x41 +#define CTL_SOSTENUTO 0x42 +#define CTL_SOFT_PEDAL 0x43 +/* undefined 0x44 */ +#define CTL_HOLD2 0x45 +/* undefined 0x46 - 0x4f */ + +#define CTL_GENERAL_PURPOSE5 0x50 +#define CTL_GENERAL_PURPOSE6 0x51 +#define CTL_GENERAL_PURPOSE7 0x52 +#define CTL_GENERAL_PURPOSE8 0x53 +/* undefined 0x54 - 0x5a */ +#define CTL_EXT_EFF_DEPTH 0x5b +#define CTL_TREMOLO_DEPTH 0x5c +#define CTL_CHORUS_DEPTH 0x5d +#define CTL_DETUNE_DEPTH 0x5e +#define CTL_CELESTE_DEPTH 0x5e /* Alias for the above one */ +#define CTL_PHASER_DEPTH 0x5f +#define CTL_DATA_INCREMENT 0x60 +#define CTL_DATA_DECREMENT 0x61 +#define CTL_NONREG_PARM_NUM_LSB 0x62 +#define CTL_NONREG_PARM_NUM_MSB 0x63 +#define CTL_REGIST_PARM_NUM_LSB 0x64 +#define CTL_REGIST_PARM_NUM_MSB 0x65 +/* undefined 0x66 - 0x78 */ +/* reserved 0x79 - 0x7f */ + +/* Pseudo controllers (not midi compatible) */ +#define CTRL_PITCH_BENDER 255 +#define CTRL_PITCH_BENDER_RANGE 254 +#define CTRL_EXPRESSION 253 /* Obsolete */ +#define CTRL_MAIN_VOLUME 252 /* Obsolete */ +#define SEQ_BALANCE 11 +#define SEQ_VOLMODE 12 + +/* + * Volume mode decides how volumes are used + */ + +#define VOL_METHOD_ADAGIO 1 +#define VOL_METHOD_LINEAR 2 + +/* + * Note! SEQ_WAIT, SEQ_MIDIPUTC and SEQ_ECHO are used also as + * input events. + */ + +/* + * Event codes 0xf0 to 0xfc are reserved for future extensions. + */ + +#define SEQ_FULLSIZE 0xfd /* Long events */ +/* + * SEQ_FULLSIZE events are used for loading patches/samples to the + * synthesizer devices. These events are passed directly to the driver + * of the associated synthesizer device. There is no limit to the size + * of the extended events. These events are not queued but executed + * immediately when the write() is called (execution can take several + * seconds of time). + * + * When a SEQ_FULLSIZE message is written to the device, it must + * be written using exactly one write() call. Other events cannot + * be mixed to the same write. + * + * For FM synths (YM3812/OPL3) use struct sbi_instrument and write it to the + * /dev/sequencer. Don't write other data together with the instrument structure + * Set the key field of the structure to FM_PATCH. The device field is used to + * route the patch to the corresponding device. + * + * For Gravis UltraSound use struct patch_info. Initialize the key field + * to GUS_PATCH. + */ +#define SEQ_PRIVATE 0xfe /* Low level HW dependent events (8 bytes) */ +#define SEQ_EXTENDED 0xff /* Extended events (8 bytes) OBSOLETE */ + +/* + * Record for FM patches + */ + +typedef unsigned char sbi_instr_data[32]; + +struct sbi_instrument { + unsigned short key; /* Initialize to FM_PATCH or OPL3_PATCH */ +#define FM_PATCH 0x01fd +#define OPL3_PATCH 0x03fd + short device; /* Synth# (0-4) */ + int channel; /* Program# to be initialized */ + sbi_instr_data operators; /* Register settings for operator cells (.SBI format) */ + }; + +struct synth_info { /* Read only */ + char name[30]; + int device; /* 0-N. INITIALIZE BEFORE CALLING */ + int synth_type; +#define SYNTH_TYPE_FM 0 +#define SYNTH_TYPE_SAMPLE 1 +#define SYNTH_TYPE_MIDI 2 /* Midi interface */ + + int synth_subtype; +#define FM_TYPE_ADLIB 0x00 +#define FM_TYPE_OPL3 0x01 + +#define SAMPLE_TYPE_GUS 0x10 + + int perc_mode; /* No longer supported */ + int nr_voices; + int nr_drums; /* Obsolete field */ + int instr_bank_size; + unsigned long capabilities; +#define SYNTH_CAP_PERCMODE 0x00000001 /* No longer used */ +#define SYNTH_CAP_OPL3 0x00000002 /* Set if OPL3 supported */ +#define SYNTH_CAP_INPUT 0x00000004 /* Input (MIDI) device */ + int dummies[19]; /* Reserve space */ + }; + +struct sound_timer_info { + char name[30]; + int caps; + }; + +#define MIDI_CAP_MPU401 1 /* MPU-401 intelligent mode */ + +struct midi_info { + char name[30]; + int device; /* 0-N. INITIALIZE BEFORE CALLING */ + unsigned long capabilities; /* To be defined later */ + int dev_type; + int dummies[18]; /* Reserve space */ + }; + +/******************************************** + * ioctl commands for the /dev/midi## + */ +typedef struct { + unsigned char cmd; + char nr_args, nr_returns; + unsigned char data[30]; + } mpu_command_rec; + +#define SNDCTL_MIDI_PRETIME _IOWR('m', 0, int) +#define SNDCTL_MIDI_MPUMODE _IOWR('m', 1, int) +#define SNDCTL_MIDI_MPUCMD _IOWR('m', 2, mpu_command_rec) + +/******************************************** + * IOCTL commands for /dev/dsp and /dev/audio + */ + +#define SNDCTL_DSP_RESET _IO ('P', 0) +#define SNDCTL_DSP_SYNC _IO ('P', 1) +#define SNDCTL_DSP_SPEED _IOWR('P', 2, int) +#define SNDCTL_DSP_STEREO _IOWR('P', 3, int) +#define SNDCTL_DSP_GETBLKSIZE _IOR('P', 4, int) +#define SNDCTL_DSP_SETBLKSIZE _IOW('P', 4, int) +#define SNDCTL_DSP_SAMPLESIZE SNDCTL_DSP_SETFMT +#define SOUND_PCM_WRITE_CHANNELS _IOWR('P', 6, int) +#define SOUND_PCM_WRITE_FILTER _IOWR('P', 7, int) +#define SNDCTL_DSP_POST _IO ('P', 8) +#define SNDCTL_DSP_SUBDIVIDE _IOWR('P', 9, int) +#define SNDCTL_DSP_SETFRAGMENT _IOWR('P',10, int) + +/* Audio data formats (Note! U8=8 and S16_LE=16 for compatibility) */ +#define SNDCTL_DSP_GETFMTS _IOR ('P',11, int) /* Returns a mask */ +#define SNDCTL_DSP_SETFMT _IOWR('P',5, int) /* Selects ONE fmt*/ +# define AFMT_QUERY 0x00000000 /* Return current fmt */ +# define AFMT_MU_LAW 0x00000001 +# define AFMT_A_LAW 0x00000002 +# define AFMT_IMA_ADPCM 0x00000004 +# define AFMT_U8 0x00000008 +# define AFMT_S16_LE 0x00000010 /* Little endian signed 16*/ +# define AFMT_S16_BE 0x00000020 /* Big endian signed 16 */ +# define AFMT_S8 0x00000040 +# define AFMT_U16_LE 0x00000080 /* Little endian U16 */ +# define AFMT_U16_BE 0x00000100 /* Big endian U16 */ +# define AFMT_MPEG 0x00000200 /* MPEG (2) audio */ + +/* + * Buffer status queries. + */ +typedef struct audio_buf_info { + int fragments; /* # of available fragments (partially usend ones not counted) */ + int fragsize; /* Size of a fragment in bytes */ + + int bytes; /* Available space in bytes (includes partially used fragments) */ + /* Note! 'bytes' could be more than fragments*fragsize */ + } audio_buf_info; + +#define SNDCTL_DSP_GETOSPACE _IOR ('P',12, audio_buf_info) +#define SNDCTL_DSP_GETISPACE _IOR ('P',13, audio_buf_info) +#define SNDCTL_DSP_NONBLOCK _IO ('P',14) + +#define SOUND_PCM_READ_RATE _IOR ('P', 2, int) +#define SOUND_PCM_READ_CHANNELS _IOR ('P', 6, int) +#define SOUND_PCM_READ_BITS _IOR ('P', 5, int) +#define SOUND_PCM_READ_FILTER _IOR ('P', 7, int) + +/* Some alias names */ +#define SOUND_PCM_WRITE_BITS SNDCTL_DSP_SETFMT +#define SOUND_PCM_WRITE_RATE SNDCTL_DSP_SPEED +#define SOUND_PCM_POST SNDCTL_DSP_POST +#define SOUND_PCM_RESET SNDCTL_DSP_RESET +#define SOUND_PCM_SYNC SNDCTL_DSP_SYNC +#define SOUND_PCM_SUBDIVIDE SNDCTL_DSP_SUBDIVIDE +#define SOUND_PCM_SETFRAGMENT SNDCTL_DSP_SETFRAGMENT +#define SOUND_PCM_GETFMTS SNDCTL_DSP_GETFMTS +#define SOUND_PCM_SETFMT SNDCTL_DSP_SETFMT +#define SOUND_PCM_GETOSPACE SNDCTL_DSP_GETOSPACE +#define SOUND_PCM_GETISPACE SNDCTL_DSP_GETISPACE +#define SOUND_PCM_NONBLOCK SNDCTL_DSP_NONBLOCK + +/* + * ioctl calls to be used in communication with coprocessors and + * DSP chips. + */ + +typedef struct copr_buffer { + int command; /* Set to 0 if not used */ + int flags; +#define CPF_NONE 0x0000 +#define CPF_FIRST 0x0001 /* First block */ +#define CPF_LAST 0x0002 /* Last block */ + int len; + int offs; /* If required by the device (0 if not used) */ + + unsigned char data[4000]; /* NOTE! 4000 is not 4k */ + } copr_buffer; + +typedef struct copr_debug_buf { + int command; /* Used internally. Set to 0 */ + int parm1; + int parm2; + int flags; + int len; /* Length of data in bytes */ + } copr_debug_buf; + +typedef struct copr_msg { + int len; + unsigned char data[4000]; + } copr_msg; + +#define SNDCTL_COPR_RESET _IO ('C', 0) +#define SNDCTL_COPR_LOAD _IOWR('C', 1, copr_buffer) +#define SNDCTL_COPR_RDATA _IOWR('C', 2, copr_debug_buf) +#define SNDCTL_COPR_RCODE _IOWR('C', 3, copr_debug_buf) +#define SNDCTL_COPR_WDATA _IOW ('C', 4, copr_debug_buf) +#define SNDCTL_COPR_WCODE _IOW ('C', 5, copr_debug_buf) +#define SNDCTL_COPR_RUN _IOWR('C', 6, copr_debug_buf) +#define SNDCTL_COPR_HALT _IOWR('C', 7, copr_debug_buf) +#define SNDCTL_COPR_SENDMSG _IOW ('C', 8, copr_msg) +#define SNDCTL_COPR_RCVMSG _IOR ('C', 9, copr_msg) + +/********************************************* + * IOCTL commands for /dev/mixer + */ + +/* + * Mixer devices + * + * There can be up to 20 different analog mixer channels. The + * SOUND_MIXER_NRDEVICES gives the currently supported maximum. + * The SOUND_MIXER_READ_DEVMASK returns a bitmask which tells + * the devices supported by the particular mixer. + */ + +#define SOUND_MIXER_NRDEVICES 17 +#define SOUND_MIXER_VOLUME 0 +#define SOUND_MIXER_BASS 1 +#define SOUND_MIXER_TREBLE 2 +#define SOUND_MIXER_SYNTH 3 +#define SOUND_MIXER_PCM 4 +#define SOUND_MIXER_SPEAKER 5 +#define SOUND_MIXER_LINE 6 +#define SOUND_MIXER_MIC 7 +#define SOUND_MIXER_CD 8 +#define SOUND_MIXER_IMIX 9 /* Recording monitor */ +#define SOUND_MIXER_ALTPCM 10 +#define SOUND_MIXER_RECLEV 11 /* Recording level */ +#define SOUND_MIXER_IGAIN 12 /* Input gain */ +#define SOUND_MIXER_OGAIN 13 /* Output gain */ +/* + * The AD1848 codec and compatibles have three line level inputs + * (line, aux1 and aux2). Since each card manufacturer have assigned + * different meanings to these inputs, it's inpractical to assign + * specific meanings (line, cd, synth etc.) to them. + */ +#define SOUND_MIXER_LINE1 14 /* Input source 1 (aux1) */ +#define SOUND_MIXER_LINE2 15 /* Input source 2 (aux2) */ +#define SOUND_MIXER_LINE3 16 /* Input source 3 (line) */ + +/* Some on/off settings (SOUND_SPECIAL_MIN - SOUND_SPECIAL_MAX) */ +/* Not counted to SOUND_MIXER_NRDEVICES, but use the same number space */ +#define SOUND_ONOFF_MIN 28 +#define SOUND_ONOFF_MAX 30 +#define SOUND_MIXER_MUTE 28 /* 0 or 1 */ +#define SOUND_MIXER_ENHANCE 29 /* Enhanced stereo (0, 40, 60 or 80) */ +#define SOUND_MIXER_LOUD 30 /* 0 or 1 */ + +/* Note! Number 31 cannot be used since the sign bit is reserved */ + +#define SOUND_DEVICE_LABELS {"Vol ", "Bass ", "Trebl", "Synth", "Pcm ", "Spkr ", "Line ", \ + "Mic ", "CD ", "Mix ", "Pcm2 ", "Rec ", "IGain", "OGain", \ + "Line1", "Line2", "Line3"} + +#define SOUND_DEVICE_NAMES {"vol", "bass", "treble", "synth", "pcm", "speaker", "line", \ + "mic", "cd", "mix", "pcm2", "rec", "igain", "ogain", \ + "line1", "line2", "line3"} + +/* Device bitmask identifiers */ + +#define SOUND_MIXER_RECSRC 0xff /* Arg contains a bit for each recording source */ +#define SOUND_MIXER_DEVMASK 0xfe /* Arg contains a bit for each supported device */ +#define SOUND_MIXER_RECMASK 0xfd /* Arg contains a bit for each supported recording source */ +#define SOUND_MIXER_CAPS 0xfc + #define SOUND_CAP_EXCL_INPUT 0x00000001 /* Only one recording source at a time */ +#define SOUND_MIXER_STEREODEVS 0xfb /* Mixer channels supporting stereo */ + +/* Device mask bits */ + +#define SOUND_MASK_VOLUME (1 << SOUND_MIXER_VOLUME) +#define SOUND_MASK_BASS (1 << SOUND_MIXER_BASS) +#define SOUND_MASK_TREBLE (1 << SOUND_MIXER_TREBLE) +#define SOUND_MASK_SYNTH (1 << SOUND_MIXER_SYNTH) +#define SOUND_MASK_PCM (1 << SOUND_MIXER_PCM) +#define SOUND_MASK_SPEAKER (1 << SOUND_MIXER_SPEAKER) +#define SOUND_MASK_LINE (1 << SOUND_MIXER_LINE) +#define SOUND_MASK_MIC (1 << SOUND_MIXER_MIC) +#define SOUND_MASK_CD (1 << SOUND_MIXER_CD) +#define SOUND_MASK_IMIX (1 << SOUND_MIXER_IMIX) +#define SOUND_MASK_ALTPCM (1 << SOUND_MIXER_ALTPCM) +#define SOUND_MASK_RECLEV (1 << SOUND_MIXER_RECLEV) +#define SOUND_MASK_IGAIN (1 << SOUND_MIXER_IGAIN) +#define SOUND_MASK_OGAIN (1 << SOUND_MIXER_OGAIN) +#define SOUND_MASK_LINE1 (1 << SOUND_MIXER_LINE1) +#define SOUND_MASK_LINE2 (1 << SOUND_MIXER_LINE2) +#define SOUND_MASK_LINE3 (1 << SOUND_MIXER_LINE3) + +#define SOUND_MASK_MUTE (1 << SOUND_MIXER_MUTE) +#define SOUND_MASK_ENHANCE (1 << SOUND_MIXER_ENHANCE) +#define SOUND_MASK_LOUD (1 << SOUND_MIXER_LOUD) + +#define MIXER_READ(dev) _IOR('M', dev, int) +#define SOUND_MIXER_READ_VOLUME MIXER_READ(SOUND_MIXER_VOLUME) +#define SOUND_MIXER_READ_BASS MIXER_READ(SOUND_MIXER_BASS) +#define SOUND_MIXER_READ_TREBLE MIXER_READ(SOUND_MIXER_TREBLE) +#define SOUND_MIXER_READ_SYNTH MIXER_READ(SOUND_MIXER_SYNTH) +#define SOUND_MIXER_READ_PCM MIXER_READ(SOUND_MIXER_PCM) +#define SOUND_MIXER_READ_SPEAKER MIXER_READ(SOUND_MIXER_SPEAKER) +#define SOUND_MIXER_READ_LINE MIXER_READ(SOUND_MIXER_LINE) +#define SOUND_MIXER_READ_MIC MIXER_READ(SOUND_MIXER_MIC) +#define SOUND_MIXER_READ_CD MIXER_READ(SOUND_MIXER_CD) +#define SOUND_MIXER_READ_IMIX MIXER_READ(SOUND_MIXER_IMIX) +#define SOUND_MIXER_READ_ALTPCM MIXER_READ(SOUND_MIXER_ALTPCM) +#define SOUND_MIXER_READ_RECLEV MIXER_READ(SOUND_MIXER_RECLEV) +#define SOUND_MIXER_READ_IGAIN MIXER_READ(SOUND_MIXER_IGAIN) +#define SOUND_MIXER_READ_OGAIN MIXER_READ(SOUND_MIXER_OGAIN) +#define SOUND_MIXER_READ_LINE1 MIXER_READ(SOUND_MIXER_LINE1) +#define SOUND_MIXER_READ_LINE2 MIXER_READ(SOUND_MIXER_LINE2) +#define SOUND_MIXER_READ_LINE3 MIXER_READ(SOUND_MIXER_LINE3) +#define SOUND_MIXER_READ_MUTE MIXER_READ(SOUND_MIXER_MUTE) +#define SOUND_MIXER_READ_ENHANCE MIXER_READ(SOUND_MIXER_ENHANCE) +#define SOUND_MIXER_READ_LOUD MIXER_READ(SOUND_MIXER_LOUD) + +#define SOUND_MIXER_READ_RECSRC MIXER_READ(SOUND_MIXER_RECSRC) +#define SOUND_MIXER_READ_DEVMASK MIXER_READ(SOUND_MIXER_DEVMASK) +#define SOUND_MIXER_READ_RECMASK MIXER_READ(SOUND_MIXER_RECMASK) +#define SOUND_MIXER_READ_STEREODEVS MIXER_READ(SOUND_MIXER_STEREODEVS) +#define SOUND_MIXER_READ_CAPS MIXER_READ(SOUND_MIXER_CAPS) + +#define MIXER_WRITE(dev) _IOWR('M', dev, int) +#define SOUND_MIXER_WRITE_VOLUME MIXER_WRITE(SOUND_MIXER_VOLUME) +#define SOUND_MIXER_WRITE_BASS MIXER_WRITE(SOUND_MIXER_BASS) +#define SOUND_MIXER_WRITE_TREBLE MIXER_WRITE(SOUND_MIXER_TREBLE) +#define SOUND_MIXER_WRITE_SYNTH MIXER_WRITE(SOUND_MIXER_SYNTH) +#define SOUND_MIXER_WRITE_PCM MIXER_WRITE(SOUND_MIXER_PCM) +#define SOUND_MIXER_WRITE_SPEAKER MIXER_WRITE(SOUND_MIXER_SPEAKER) +#define SOUND_MIXER_WRITE_LINE MIXER_WRITE(SOUND_MIXER_LINE) +#define SOUND_MIXER_WRITE_MIC MIXER_WRITE(SOUND_MIXER_MIC) +#define SOUND_MIXER_WRITE_CD MIXER_WRITE(SOUND_MIXER_CD) +#define SOUND_MIXER_WRITE_IMIX MIXER_WRITE(SOUND_MIXER_IMIX) +#define SOUND_MIXER_WRITE_ALTPCM MIXER_WRITE(SOUND_MIXER_ALTPCM) +#define SOUND_MIXER_WRITE_RECLEV MIXER_WRITE(SOUND_MIXER_RECLEV) +#define SOUND_MIXER_WRITE_IGAIN MIXER_WRITE(SOUND_MIXER_IGAIN) +#define SOUND_MIXER_WRITE_OGAIN MIXER_WRITE(SOUND_MIXER_OGAIN) +#define SOUND_MIXER_WRITE_LINE1 MIXER_WRITE(SOUND_MIXER_LINE1) +#define SOUND_MIXER_WRITE_LINE2 MIXER_WRITE(SOUND_MIXER_LINE2) +#define SOUND_MIXER_WRITE_LINE3 MIXER_WRITE(SOUND_MIXER_LINE3) +#define SOUND_MIXER_WRITE_MUTE MIXER_WRITE(SOUND_MIXER_MUTE) +#define SOUND_MIXER_WRITE_ENHANCE MIXER_WRITE(SOUND_MIXER_ENHANCE) +#define SOUND_MIXER_WRITE_LOUD MIXER_WRITE(SOUND_MIXER_LOUD) + +#define SOUND_MIXER_WRITE_RECSRC MIXER_WRITE(SOUND_MIXER_RECSRC) + +/* + * Level 2 event types for /dev/sequencer + */ + +/* + * The 4 most significant bits of byte 0 specify the class of + * the event: + * + * 0x8X = system level events, + * 0x9X = device/port specific events, event[1] = device/port, + * The last 4 bits give the subtype: + * 0x02 = Channel event (event[3] = chn). + * 0x01 = note event (event[4] = note). + * (0x01 is not used alone but always with bit 0x02). + * event[2] = MIDI message code (0x80=note off etc.) + * + */ + +#define EV_SEQ_LOCAL 0x80 +#define EV_TIMING 0x81 +#define EV_CHN_COMMON 0x92 +#define EV_CHN_VOICE 0x93 +/* + * Event types 200 to 220 are reserved for application use. + * These numbers will not be used by the driver. + */ + +/* + * Events for event type EV_CHN_VOICE + */ + +#define MIDI_NOTEOFF 0x80 +#define MIDI_NOTEON 0x90 +#define MIDI_KEY_PRESSURE 0xA0 + +/* + * Events for event type EV_CHN_COMMON + */ + +#define MIDI_CTL_CHANGE 0xB0 +#define MIDI_PGM_CHANGE 0xC0 +#define MIDI_CHN_PRESSURE 0xD0 +#define MIDI_PITCH_BEND 0xE0 + +#define MIDI_SYSTEM_PREFIX 0xF0 + +/* + * Timer event types + */ +#define TMR_WAIT_REL 1 /* Time relative to the prev time */ +#define TMR_WAIT_ABS 2 /* Absolute time since TMR_START */ +#define TMR_STOP 3 +#define TMR_START 4 +#define TMR_CONTINUE 5 +#define TMR_TEMPO 6 +#define TMR_ECHO 8 +#define TMR_CLOCK 9 /* MIDI clock */ +#define TMR_SPP 10 /* Song position pointer */ +#define TMR_TIMESIG 11 /* Time signature */ + +#if (!defined(__KERNEL__) && !defined(KERNEL) && !defined(INKERNEL) && !defined(_KERNEL)) || defined(USE_SEQ_MACROS) +/* + * Some convenience macros to simplify programming of the + * /dev/sequencer interface + * + * These macros define the API which should be used when possible. + */ + +#ifndef USE_SIMPLE_MACROS +void seqbuf_dump(void); /* This function must be provided by programs */ + +/* Sample seqbuf_dump() implementation: + * + * SEQ_DEFINEBUF (2048); -- Defines a buffer for 2048 bytes + * + * int seqfd; -- The file descriptor for /dev/sequencer. + * + * void + * seqbuf_dump () + * { + * if (_seqbufptr) + * if (write (seqfd, _seqbuf, _seqbufptr) == -1) + * { + * perror ("write /dev/sequencer"); + * exit (-1); + * } + * _seqbufptr = 0; + * } + */ + +#define SEQ_DEFINEBUF(len) unsigned char _seqbuf[len]; int _seqbuflen = len;int _seqbufptr = 0 +#define SEQ_USE_EXTBUF() extern unsigned char _seqbuf[]; extern int _seqbuflen;extern int _seqbufptr +#define SEQ_DECLAREBUF() SEQ_USE_EXTBUF() +#define SEQ_PM_DEFINES struct patmgr_info _pm_info +#define _SEQ_NEEDBUF(len) if ((_seqbufptr+(len)) > _seqbuflen) seqbuf_dump() +#define _SEQ_ADVBUF(len) _seqbufptr += len +#define SEQ_DUMPBUF seqbuf_dump +#else +/* + * This variation of the sequencer macros is used just to format one event + * using fixed buffer. + * + * The program using the macro library must define the following macros before + * using this library. + * + * #define _seqbuf name of the buffer (unsigned char[]) + * #define _SEQ_ADVBUF(len) If the applic needs to know the exact + * size of the event, this macro can be used. + * Otherwise this must be defined as empty. + * #define _seqbufptr Define the name of index variable or 0 if + * not required. + */ +#define _SEQ_NEEDBUF(len) /* empty */ +#endif + +#define PM_LOAD_PATCH(dev, bank, pgm) (SEQ_DUMPBUF(), _pm_info.command = _PM_LOAD_PATCH, \ + _pm_info.device=dev, _pm_info.data.data8[0]=pgm, \ + _pm_info.parm1 = bank, _pm_info.parm2 = 1, \ + ioctl(seqfd, SNDCTL_PMGR_ACCESS, &_pm_info)) +#define PM_LOAD_PATCHES(dev, bank, pgm) (SEQ_DUMPBUF(), _pm_info.command = _PM_LOAD_PATCH, \ + _pm_info.device=dev, memcpy(_pm_info.data.data8, pgm, 128), \ + _pm_info.parm1 = bank, _pm_info.parm2 = 128, \ + ioctl(seqfd, SNDCTL_PMGR_ACCESS, &_pm_info)) + +#define SEQ_VOLUME_MODE(dev, mode) {_SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr] = SEQ_EXTENDED;\ + _seqbuf[_seqbufptr+1] = SEQ_VOLMODE;\ + _seqbuf[_seqbufptr+2] = (dev);\ + _seqbuf[_seqbufptr+3] = (mode);\ + _seqbuf[_seqbufptr+4] = 0;\ + _seqbuf[_seqbufptr+5] = 0;\ + _seqbuf[_seqbufptr+6] = 0;\ + _seqbuf[_seqbufptr+7] = 0;\ + _SEQ_ADVBUF(8);} + +/* + * Midi voice messages + */ + +#define _CHN_VOICE(dev, event, chn, note, parm) \ + {_SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr] = EV_CHN_VOICE;\ + _seqbuf[_seqbufptr+1] = (dev);\ + _seqbuf[_seqbufptr+2] = (event);\ + _seqbuf[_seqbufptr+3] = (chn);\ + _seqbuf[_seqbufptr+4] = (note);\ + _seqbuf[_seqbufptr+5] = (parm);\ + _seqbuf[_seqbufptr+6] = (0);\ + _seqbuf[_seqbufptr+7] = 0;\ + _SEQ_ADVBUF(8);} + +#define SEQ_START_NOTE(dev, chn, note, vol) \ + _CHN_VOICE(dev, MIDI_NOTEON, chn, note, vol) + +#define SEQ_STOP_NOTE(dev, chn, note, vol) \ + _CHN_VOICE(dev, MIDI_NOTEOFF, chn, note, vol) + +#define SEQ_KEY_PRESSURE(dev, chn, note, pressure) \ + _CHN_VOICE(dev, MIDI_KEY_PRESSURE, chn, note, pressure) + +/* + * Midi channel messages + */ + +#define _CHN_COMMON(dev, event, chn, p1, p2, w14) \ + {_SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr] = EV_CHN_COMMON;\ + _seqbuf[_seqbufptr+1] = (dev);\ + _seqbuf[_seqbufptr+2] = (event);\ + _seqbuf[_seqbufptr+3] = (chn);\ + _seqbuf[_seqbufptr+4] = (p1);\ + _seqbuf[_seqbufptr+5] = (p2);\ + *(short *)&_seqbuf[_seqbufptr+6] = (w14);\ + _SEQ_ADVBUF(8);} + +#define SEQ_CHN_PRESSURE(dev, chn, pressure) \ + _CHN_COMMON(dev, MIDI_CHN_PRESSURE, chn, pressure, 0, 0) + +#define SEQ_SET_PATCH(dev, chn, patch) \ + _CHN_COMMON(dev, MIDI_PGM_CHANGE, chn, patch, 0, 0) + +#define SEQ_CONTROL(dev, chn, controller, value) \ + _CHN_COMMON(dev, MIDI_CTL_CHANGE, chn, controller, 0, value) + +#define SEQ_BENDER(dev, chn, value) \ + _CHN_COMMON(dev, MIDI_PITCH_BEND, chn, 0, 0, value) + + +#define SEQ_V2_X_CONTROL(dev, voice, controller, value) {_SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr] = SEQ_EXTENDED;\ + _seqbuf[_seqbufptr+1] = SEQ_CONTROLLER;\ + _seqbuf[_seqbufptr+2] = (dev);\ + _seqbuf[_seqbufptr+3] = (voice);\ + _seqbuf[_seqbufptr+4] = (controller);\ + *(short *)&_seqbuf[_seqbufptr+5] = (value);\ + _seqbuf[_seqbufptr+7] = 0;\ + _SEQ_ADVBUF(8);} +/* + * The following 5 macros are incorrectly implemented and obsolete. + * Use SEQ_BENDER and SEQ_CONTROL (with proper controller) instead. + */ +#define SEQ_PITCHBEND(dev, voice, value) SEQ_V2_X_CONTROL(dev, voice, CTRL_PITCH_BENDER, value) +#define SEQ_BENDER_RANGE(dev, voice, value) SEQ_V2_X_CONTROL(dev, voice, CTRL_PITCH_BENDER_RANGE, value) +#define SEQ_EXPRESSION(dev, voice, value) SEQ_CONTROL(dev, voice, CTL_EXPRESSION, value*128) +#define SEQ_MAIN_VOLUME(dev, voice, value) SEQ_CONTROL(dev, voice, CTL_MAIN_VOLUME, (value*16383)/100) +#define SEQ_PANNING(dev, voice, pos) SEQ_CONTROL(dev, voice, CTL_PAN, (pos+128) / 2) +#if 0 +#define SEQ_PANNING(dev, voice, pos) {_SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr] = SEQ_EXTENDED;\ + _seqbuf[_seqbufptr+1] = SEQ_BALANCE;\ + _seqbuf[_seqbufptr+2] = (dev);\ + _seqbuf[_seqbufptr+3] = (voice);\ + (char)_seqbuf[_seqbufptr+4] = (pos);\ + _seqbuf[_seqbufptr+5] = 0;\ + _seqbuf[_seqbufptr+6] = 0;\ + _seqbuf[_seqbufptr+7] = 1;\ + _SEQ_ADVBUF(8);} +#endif + +/* + * Timing and syncronization macros + */ + +#define _TIMER_EVENT(ev, parm) {_SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr+0] = EV_TIMING; \ + _seqbuf[_seqbufptr+1] = (ev); \ + _seqbuf[_seqbufptr+2] = 0;\ + _seqbuf[_seqbufptr+3] = 0;\ + *(unsigned int *)&_seqbuf[_seqbufptr+4] = (parm); \ + _SEQ_ADVBUF(8);} + +#define SEQ_START_TIMER() _TIMER_EVENT(TMR_START, 0) +#define SEQ_STOP_TIMER() _TIMER_EVENT(TMR_STOP, 0) +#define SEQ_CONTINUE_TIMER() _TIMER_EVENT(TMR_CONTINUE, 0) +#define SEQ_WAIT_TIME(ticks) _TIMER_EVENT(TMR_WAIT_ABS, ticks) +#define SEQ_DELTA_TIME(ticks) _TIMER_EVENT(TMR_WAIT_REL, ticks) +#define SEQ_ECHO_BACK(key) _TIMER_EVENT(TMR_ECHO, key) +#define SEQ_SET_TEMPO(value) _TIMER_EVENT(TMR_TEMPO, value) +#define SEQ_SONGPOS(pos) _TIMER_EVENT(TMR_SPP, pos) +#define SEQ_TIME_SIGNATURE(sig) _TIMER_EVENT(TMR_TIMESIG, sig) + +/* + * Events for the level 1 interface only + */ + +#define SEQ_MIDIOUT(device, byte) {_SEQ_NEEDBUF(4);\ + _seqbuf[_seqbufptr] = SEQ_MIDIPUTC;\ + _seqbuf[_seqbufptr+1] = (byte);\ + _seqbuf[_seqbufptr+2] = (device);\ + _seqbuf[_seqbufptr+3] = 0;\ + _SEQ_ADVBUF(4);} + +/* + * Patch loading. + */ +#define SEQ_WRPATCH(patchx, len) {if (_seqbufptr) seqbuf_dump();\ + if (write(seqfd, (char*)(patchx), len)==-1) \ + perror("Write patch: /dev/sequencer");} +#define SEQ_WRPATCH2(patchx, len) (seqbuf_dump(), write(seqfd, (char*)(patchx), len)) + +#endif +#endif diff --git a/sys/i386/isa/sound/soundvers.h b/sys/i386/isa/sound/soundvers.h new file mode 100644 index 0000000..ca892e8 --- /dev/null +++ b/sys/i386/isa/sound/soundvers.h @@ -0,0 +1 @@ +#define SOUND_VERSION_STRING "3.0-beta-950506" diff --git a/sys/i386/isa/sound/sscape.c b/sys/i386/isa/sound/sscape.c new file mode 100644 index 0000000..9204b18 --- /dev/null +++ b/sys/i386/isa/sound/sscape.c @@ -0,0 +1,1120 @@ +/* + * sound/sscape.c + * + * Low level driver for Ensoniq Soundscape + * + * Copyright by Hannu Savolainen 1994 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "sound_config.h" + +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SSCAPE) + +#include "coproc.h" + +/* + * I/O ports + */ +#define MIDI_DATA 0 +#define MIDI_CTRL 1 +#define HOST_CTRL 2 +#define TX_READY 0x02 +#define RX_READY 0x01 +#define HOST_DATA 3 +#define ODIE_ADDR 4 +#define ODIE_DATA 5 + +/* + * Indirect registers + */ +#define GA_INTSTAT_REG 0 +#define GA_INTENA_REG 1 +#define GA_DMAA_REG 2 +#define GA_DMAB_REG 3 +#define GA_INTCFG_REG 4 +#define GA_DMACFG_REG 5 +#define GA_CDCFG_REG 6 +#define GA_SMCFGA_REG 7 +#define GA_SMCFGB_REG 8 +#define GA_HMCTL_REG 9 + +/* + * DMA channel identifiers (A and B) + */ +#define SSCAPE_DMA_A 0 +#define SSCAPE_DMA_B 1 + +#define PORT(name) (devc->base+name) + +/* + * Host commands recognized by the OBP microcode + */ +#define CMD_GEN_HOST_ACK 0x80 +#define CMD_GEN_MPU_ACK 0x81 +#define CMD_GET_BOARD_TYPE 0x82 +#define CMD_SET_CONTROL 0x88 +#define CMD_GET_CONTROL 0x89 +#define CMD_SET_MT32 0x96 +#define CMD_GET_MT32 0x97 +#define CMD_SET_EXTMIDI 0x9b +#define CMD_GET_EXTMIDI 0x9c + +#define CMD_ACK 0x80 + +typedef struct sscape_info + { + int base, irq, dma; + int ok; /* Properly detected */ + int dma_allocated; + int my_audiodev; + int opened; + } + +sscape_info; +static struct sscape_info dev_info = +{0}; +static struct sscape_info *devc = &dev_info; + +DEFINE_WAIT_QUEUE (sscape_sleeper, sscape_sleep_flag); + +#ifdef REVEAL_SPEA +/* Spea and Reveal have assigned interrupt bits differently than Ensoniq */ +static char valid_interrupts[] = +{9, 7, 5, 15}; + +#else +static char valid_interrupts[] = +{9, 5, 7, 10}; + +#endif + +static unsigned char +sscape_read (struct sscape_info *devc, int reg) +{ + unsigned long flags; + unsigned char val; + + DISABLE_INTR (flags); + OUTB (reg, PORT (ODIE_ADDR)); + val = INB (PORT (ODIE_DATA)); + RESTORE_INTR (flags); + return val; +} + +static void +sscape_write (struct sscape_info *devc, int reg, int data) +{ + unsigned long flags; + + DISABLE_INTR (flags); + OUTB (reg, PORT (ODIE_ADDR)); + OUTB (data, PORT (ODIE_DATA)); + RESTORE_INTR (flags); +} + +static void +host_open (struct sscape_info *devc) +{ + OUTB (0x00, PORT (HOST_CTRL)); /* Put the board to the host mode */ +} + +static void +host_close (struct sscape_info *devc) +{ + OUTB (0x03, PORT (HOST_CTRL)); /* Put the board to the MIDI mode */ +} + +static int +host_write (struct sscape_info *devc, unsigned char *data, int count) +{ + unsigned long flags; + int i, timeout; + + DISABLE_INTR (flags); + + /* + * Send the command and data bytes + */ + + for (i = 0; i < count; i++) + { + for (timeout = 10000; timeout > 0; timeout--) + if (INB (PORT (HOST_CTRL)) & TX_READY) + break; + + if (timeout <= 0) + { + RESTORE_INTR (flags); + return 0; + } + + OUTB (data[i], PORT (HOST_DATA)); + } + + + RESTORE_INTR (flags); + + return 1; +} + +static int +host_read (struct sscape_info *devc) +{ + unsigned long flags; + int timeout; + unsigned char data; + + DISABLE_INTR (flags); + + /* + * Read a byte + */ + + for (timeout = 10000; timeout > 0; timeout--) + if (INB (PORT (HOST_CTRL)) & RX_READY) + break; + + if (timeout <= 0) + { + RESTORE_INTR (flags); + return -1; + } + + data = INB (PORT (HOST_DATA)); + + RESTORE_INTR (flags); + + return data; +} + +static int +host_command1 (struct sscape_info *devc, int cmd) +{ + unsigned char buf[10]; + + buf[0] = (unsigned char) (cmd & 0xff); + + return host_write (devc, buf, 1); +} + +static int +host_command2 (struct sscape_info *devc, int cmd, int parm1) +{ + unsigned char buf[10]; + + buf[0] = (unsigned char) (cmd & 0xff); + buf[1] = (unsigned char) (parm1 & 0xff); + + return host_write (devc, buf, 2); +} + +static int +host_command3 (struct sscape_info *devc, int cmd, int parm1, int parm2) +{ + unsigned char buf[10]; + + buf[0] = (unsigned char) (cmd & 0xff); + buf[1] = (unsigned char) (parm1 & 0xff); + buf[2] = (unsigned char) (parm2 & 0xff); + + return host_write (devc, buf, 3); +} + +static void +set_mt32 (struct sscape_info *devc, int value) +{ + host_open (devc); + host_command2 (devc, CMD_SET_MT32, + value ? 1 : 0); + if (host_read (devc) != CMD_ACK) + { + printk ("SNDSCAPE: Setting MT32 mode failed\n"); + } + host_close (devc); +} + +static int +get_board_type (struct sscape_info *devc) +{ + int tmp; + + host_open (devc); + if (!host_command1 (devc, CMD_GET_BOARD_TYPE)) + tmp = -1; + else + tmp = host_read (devc); + host_close (devc); + return tmp; +} + +void +sscapeintr (INT_HANDLER_PARMS (irq, dummy)) +{ + unsigned char bits, tmp; + static int debug = 0; + + printk ("sscapeintr(0x%02x)\n", (bits = sscape_read (devc, GA_INTSTAT_REG))); + if (SOMEONE_WAITING (sscape_sleeper, sscape_sleep_flag)) + { + WAKE_UP (sscape_sleeper, sscape_sleep_flag); + } + + if (bits & 0x02) /* Host interface interrupt */ + { + printk ("SSCAPE: Host interrupt, data=%02x\n", host_read (devc)); + } + +#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI) + if (bits & 0x01) + { + mpuintr (INT_HANDLER_CALL (irq)); + if (debug++ > 10) /* Temporary debugging hack */ + { + sscape_write (devc, GA_INTENA_REG, 0x00); /* Disable all interrupts */ + } + } +#endif + + /* + * Acknowledge interrupts (toggle the interrupt bits) + */ + + tmp = sscape_read (devc, GA_INTENA_REG); + sscape_write (devc, GA_INTENA_REG, (~bits & 0x0e) | (tmp & 0xf1)); + +} + +static void +sscape_enable_intr (struct sscape_info *devc, unsigned intr_bits) +{ + unsigned char temp, orig; + + temp = orig = sscape_read (devc, GA_INTENA_REG); + temp |= intr_bits; + temp |= 0x80; /* Master IRQ enable */ + + if (temp == orig) + return; /* No change */ + + sscape_write (devc, GA_INTENA_REG, temp); +} + +static void +sscape_disable_intr (struct sscape_info *devc, unsigned intr_bits) +{ + unsigned char temp, orig; + + temp = orig = sscape_read (devc, GA_INTENA_REG); + temp &= ~intr_bits; + if ((temp & ~0x80) == 0x00) + temp = 0x00; /* Master IRQ disable */ + if (temp == orig) + return; /* No change */ + + sscape_write (devc, GA_INTENA_REG, temp); +} + +static void +do_dma (struct sscape_info *devc, int dma_chan, unsigned long buf, int blk_size, int mode) +{ + unsigned char temp; + + if (dma_chan != SSCAPE_DMA_A) + { + printk ("SSCAPE: Tried to use DMA channel != A. Why?\n"); + return; + } + + DMAbuf_start_dma (devc->my_audiodev, + buf, + blk_size, mode); + + temp = devc->dma << 4; /* Setup DMA channel select bits */ + if (devc->dma <= 3) + temp |= 0x80; /* 8 bit DMA channel */ + + temp |= 1; /* Trigger DMA */ + sscape_write (devc, GA_DMAA_REG, temp); + temp &= 0xfe; /* Clear DMA trigger */ + sscape_write (devc, GA_DMAA_REG, temp); +} + +static int +verify_mpu (struct sscape_info *devc) +{ + /* + * The SoundScape board could be in three modes (MPU, 8250 and host). + * If the card is not in the MPU mode, enabling the MPU driver will + * cause infinite loop (the driver believes that there is always some + * received data in the buffer. + * + * Detect this by looking if there are more than 10 received MIDI bytes + * (0x00) in the buffer. + */ + + int i; + + for (i = 0; i < 10; i++) + { + if (INB (devc->base + HOST_CTRL) & 0x80) + return 1; + + if (INB (devc->base) != 0x00) + return 1; + } + + printk ("SoundScape: The device is not in the MPU-401 mode\n"); + return 0; +} + +static int +sscape_coproc_open (void *dev_info, int sub_device) +{ + if (sub_device == COPR_MIDI) + { + set_mt32 (devc, 0); + if (!verify_mpu (devc)) + return RET_ERROR (EIO); + } + + return 0; +} + +static void +sscape_coproc_close (void *dev_info, int sub_device) +{ + struct sscape_info *devc = dev_info; + unsigned long flags; + + DISABLE_INTR (flags); + if (devc->dma_allocated) + { + sscape_write (devc, GA_DMAA_REG, 0x20); /* DMA channel disabled */ +#ifndef EXCLUDE_NATIVE_PCM + DMAbuf_close_dma (devc->my_audiodev); +#endif + devc->dma_allocated = 0; + } + RESET_WAIT_QUEUE (sscape_sleeper, sscape_sleep_flag); + RESTORE_INTR (flags); + + return; +} + +static void +sscape_coproc_reset (void *dev_info) +{ +} + +static int +sscape_download_boot (struct sscape_info *devc, unsigned char *block, int size, int flag) +{ + unsigned long flags; + unsigned char temp; + int done, timeout; + + if (flag & CPF_FIRST) + { + /* + * First block. Have to allocate DMA and to reset the board + * before continuing. + */ + + DISABLE_INTR (flags); + if (devc->dma_allocated == 0) + { +#ifndef EXCLUDE_NATIVE_PCM + if (DMAbuf_open_dma (devc->my_audiodev) < 0) + { + RESTORE_INTR (flags); + return 0; + } +#endif + + devc->dma_allocated = 1; + } + RESTORE_INTR (flags); + + sscape_write (devc, GA_HMCTL_REG, + (temp = sscape_read (devc, GA_HMCTL_REG)) & 0x3f); /*Reset */ + + for (timeout = 10000; timeout > 0; timeout--) + sscape_read (devc, GA_HMCTL_REG); /* Delay */ + + /* Take board out of reset */ + sscape_write (devc, GA_HMCTL_REG, + (temp = sscape_read (devc, GA_HMCTL_REG)) | 0x80); + } + + /* + * Transfer one code block using DMA + */ + memcpy (audio_devs[devc->my_audiodev]->dmap->raw_buf[0], block, size); + + DISABLE_INTR (flags); +/******** INTERRUPTS DISABLED NOW ********/ + do_dma (devc, SSCAPE_DMA_A, + audio_devs[devc->my_audiodev]->dmap->raw_buf_phys[0], + size, DMA_MODE_WRITE); + + /* + * Wait until transfer completes. + */ + RESET_WAIT_QUEUE (sscape_sleeper, sscape_sleep_flag); + done = 0; + timeout = 100; + while (!done && timeout-- > 0) + { + int resid; + + DO_SLEEP (sscape_sleeper, sscape_sleep_flag, 1); + clear_dma_ff (devc->dma); + if ((resid = get_dma_residue (devc->dma)) == 0) + done = 1; + } + + RESTORE_INTR (flags); + if (!done) + return 0; + + if (flag & CPF_LAST) + { + /* + * Take the board out of reset + */ + OUTB (0x00, PORT (HOST_CTRL)); + OUTB (0x00, PORT (MIDI_CTRL)); + + temp = sscape_read (devc, GA_HMCTL_REG); + temp |= 0x40; + sscape_write (devc, GA_HMCTL_REG, temp); /* Kickstart the board */ + + /* + * Wait until the ODB wakes up + */ + + DISABLE_INTR (flags); + done = 0; + timeout = 5 * HZ; + while (!done && timeout-- > 0) + { + DO_SLEEP (sscape_sleeper, sscape_sleep_flag, 1); + if (INB (PORT (HOST_DATA)) == 0xff) /* OBP startup acknowledge */ + done = 1; + } + RESTORE_INTR (flags); + if (!done) + { + printk ("SoundScape: The OBP didn't respond after code download\n"); + return 0; + } + + DISABLE_INTR (flags); + done = 0; + timeout = 5 * HZ; + while (!done && timeout-- > 0) + { + DO_SLEEP (sscape_sleeper, sscape_sleep_flag, 1); + if (INB (PORT (HOST_DATA)) == 0xfe) /* Host startup acknowledge */ + done = 1; + } + RESTORE_INTR (flags); + if (!done) + { + printk ("SoundScape: OBP Initialization failed.\n"); + return 0; + } + + printk ("SoundScape board of type %d initialized OK\n", + get_board_type (devc)); + +#ifdef SSCAPE_DEBUG3 + /* + * Temporary debugging aid. Print contents of the registers after + * downloading the code. + */ + { + int i; + + for (i = 0; i < 13; i++) + printk ("I%d = %02x (new value)\n", i, sscape_read (devc, i)); + } +#endif + + } + + return 1; +} + +static int +download_boot_block (void *dev_info, copr_buffer * buf) +{ + if (buf->len <= 0 || buf->len > sizeof (buf->data)) + return RET_ERROR (EINVAL); + + if (!sscape_download_boot (devc, buf->data, buf->len, buf->flags)) + { + printk ("SSCAPE: Unable to load microcode block to the OBP.\n"); + return RET_ERROR (EIO); + } + + return 0; +} + +static int +sscape_coproc_ioctl (void *dev_info, unsigned int cmd, unsigned int arg, int local) +{ + + switch (cmd) + { + case SNDCTL_COPR_RESET: + sscape_coproc_reset (dev_info); + return 0; + break; + + case SNDCTL_COPR_LOAD: + { + copr_buffer *buf; + int err; + + buf = (copr_buffer *) KERNEL_MALLOC (sizeof (copr_buffer)); + IOCTL_FROM_USER ((char *) buf, (char *) arg, 0, sizeof (*buf)); + err = download_boot_block (dev_info, buf); + KERNEL_FREE (buf); + return err; + } + break; + + default: + return RET_ERROR (EINVAL); + } + + return RET_ERROR (EINVAL); +} + +static coproc_operations sscape_coproc_operations = +{ + "SoundScape M68K", + sscape_coproc_open, + sscape_coproc_close, + sscape_coproc_ioctl, + sscape_coproc_reset, + &dev_info +}; + +static int +sscape_audio_open (int dev, int mode) +{ + unsigned long flags; + sscape_info *devc = (sscape_info *) audio_devs[dev]->devc; + + DISABLE_INTR (flags); + if (devc->opened) + { + RESTORE_INTR (flags); + return RET_ERROR (EBUSY); + } + + if (devc->dma_allocated == 0) + { + int err; + + if ((err = DMAbuf_open_dma (devc->my_audiodev)) < 0) + { + RESTORE_INTR (flags); + return err; + } + + devc->dma_allocated = 1; + } + + devc->opened = 1; + RESTORE_INTR (flags); +#ifdef SSCAPE_DEBUG4 + /* + * Temporary debugging aid. Print contents of the registers + * when the device is opened. + */ + { + int i; + + for (i = 0; i < 13; i++) + printk ("I%d = %02x\n", i, sscape_read (devc, i)); + } +#endif + + return 0; +} + +static void +sscape_audio_close (int dev) +{ + unsigned long flags; + sscape_info *devc = (sscape_info *) audio_devs[dev]->devc; + + DEB (printk ("sscape_audio_close(void)\n")); + + DISABLE_INTR (flags); + + if (devc->dma_allocated) + { + sscape_write (devc, GA_DMAA_REG, 0x20); /* DMA channel disabled */ + DMAbuf_close_dma (dev); + devc->dma_allocated = 0; + } + devc->opened = 0; + + RESTORE_INTR (flags); +} + +static int +set_speed (sscape_info * devc, int arg) +{ + return 8000; +} + +static int +set_channels (sscape_info * devc, int arg) +{ + return 1; +} + +static int +set_format (sscape_info * devc, int arg) +{ + return AFMT_U8; +} + +static int +sscape_audio_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) +{ + sscape_info *devc = (sscape_info *) audio_devs[dev]->devc; + + switch (cmd) + { + case SOUND_PCM_WRITE_RATE: + if (local) + return set_speed (devc, arg); + return IOCTL_OUT (arg, set_speed (devc, IOCTL_IN (arg))); + + case SOUND_PCM_READ_RATE: + if (local) + return 8000; + return IOCTL_OUT (arg, 8000); + + case SNDCTL_DSP_STEREO: + if (local) + return set_channels (devc, arg + 1) - 1; + return IOCTL_OUT (arg, set_channels (devc, IOCTL_IN (arg) + 1) - 1); + + case SOUND_PCM_WRITE_CHANNELS: + if (local) + return set_channels (devc, arg); + return IOCTL_OUT (arg, set_channels (devc, IOCTL_IN (arg))); + + case SOUND_PCM_READ_CHANNELS: + if (local) + return 1; + return IOCTL_OUT (arg, 1); + + case SNDCTL_DSP_SAMPLESIZE: + if (local) + return set_format (devc, arg); + return IOCTL_OUT (arg, set_format (devc, IOCTL_IN (arg))); + + case SOUND_PCM_READ_BITS: + if (local) + return 8; + return IOCTL_OUT (arg, 8); + + default:; + } + return RET_ERROR (EINVAL); +} + +static void +sscape_audio_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart) +{ +} + +static void +sscape_audio_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart) +{ +} + +static int +sscape_audio_prepare_for_input (int dev, int bsize, int bcount) +{ + return 0; +} + +static int +sscape_audio_prepare_for_output (int dev, int bsize, int bcount) +{ + return 0; +} + +static void +sscape_audio_halt (int dev) +{ +} + +static void +sscape_audio_reset (int dev) +{ + sscape_audio_halt (dev); +} + +static struct audio_operations sscape_audio_operations = +{ + "Ensoniq SoundScape channel A", + 0, + AFMT_U8 | AFMT_S16_LE, + NULL, + sscape_audio_open, + sscape_audio_close, + sscape_audio_output_block, + sscape_audio_start_input, + sscape_audio_ioctl, + sscape_audio_prepare_for_input, + sscape_audio_prepare_for_output, + sscape_audio_reset, + sscape_audio_halt, + NULL, + NULL +}; + +long +attach_sscape (long mem_start, struct address_info *hw_config) +{ + int my_dev; + +#ifndef SSCAPE_REGS + /* + * Config register values for Spea/V7 Media FX and Ensoniq S-2000. + * These values are card + * dependent. If you have another SoundScape based card, you have to + * find the correct values. Do the following: + * - Compile this driver with SSCAPE_DEBUG1 defined. + * - Shut down and power off your machine. + * - Boot with DOS so that the SSINIT.EXE program is run. + * - Warm boot to {Linux|SYSV|BSD} and write down the lines displayed + * when detecting the SoundScape. + * - Modify the following list to use the values printed during boot. + * Undefine the SSCAPE_DEBUG1 + */ +#define SSCAPE_REGS { \ +/* I0 */ 0x00, \ + 0xf0, /* Note! Ignored. Set always to 0xf0 */ \ + 0x20, /* Note! Ignored. Set always to 0x20 */ \ + 0x20, /* Note! Ignored. Set always to 0x20 */ \ + 0xf5, /* Ignored */ \ + 0x10, \ + 0x00, \ + 0x2e, /* I7 MEM config A. Likely to vary between models */ \ + 0x00, /* I8 MEM config A. Likely to vary between models */ \ +/* I9 */ 0x40 /* Ignored */ \ + } +#endif + + unsigned long flags; + static unsigned char regs[10] = SSCAPE_REGS; + + int i, irq_bits = 0xff; + + if (!probe_sscape (hw_config)) + return mem_start; + + printk (" <Ensoniq Soundscape>"); + + for (i = 0; i < sizeof (valid_interrupts); i++) + if (hw_config->irq == valid_interrupts[i]) + { + irq_bits = i; + break; + } + + if (hw_config->irq > 15 || (regs[4] = irq_bits == 0xff)) + { + printk ("Invalid IRQ%d\n", hw_config->irq); + return mem_start; + } + + DISABLE_INTR (flags); + + for (i = 1; i < 10; i++) + switch (i) + { + case 1: /* Host interrupt enable */ + sscape_write (devc, i, 0xf0); /* All interrupts enabled */ + break; + + case 2: /* DMA A status/trigger register */ + case 3: /* DMA B status/trigger register */ + sscape_write (devc, i, 0x20); /* DMA channel disabled */ + break; + + case 4: /* Host interrupt config reg */ + sscape_write (devc, i, 0xf0 | (irq_bits << 2) | irq_bits); + break; + + case 5: /* Don't destroy CD-ROM DMA config bits (0xc0) */ + sscape_write (devc, i, (regs[i] & 0x3f) | + (sscape_read (devc, i) & 0x0c)); + break; + + case 6: /* CD-ROM config. Don't touch. */ + break; + + case 9: /* Master control reg. Don't modify CR-ROM bits. Disable SB emul */ + sscape_write (devc, i, + (sscape_read (devc, i) & 0xf0) | 0x00); + break; + + default: + sscape_write (devc, i, regs[i]); + } + + RESTORE_INTR (flags); + +#ifdef SSCAPE_DEBUG2 + /* + * Temporary debugging aid. Print contents of the registers after + * changing them. + */ + { + int i; + + for (i = 0; i < 13; i++) + printk ("I%d = %02x (new value)\n", i, sscape_read (devc, i)); + } +#endif + +#if !defined(EXCLUDE_MIDI) && !defined(EXCLUDE_MPU_EMU) + hw_config->always_detect = 1; + if (probe_mpu401 (hw_config)) + { + int prev_devs; + + prev_devs = num_midis; + mem_start = attach_mpu401 (mem_start, hw_config); + + if (num_midis == (prev_devs + 1)) /* The MPU driver installed itself */ + midi_devs[prev_devs]->coproc = &sscape_coproc_operations; + } +#endif + +#ifndef EXCLUDE_NATIVE_PCM + /* Not supported yet */ + +#ifndef EXCLUDE_AUDIO + if (num_audiodevs < MAX_AUDIO_DEV) + { + audio_devs[my_dev = num_audiodevs++] = &sscape_audio_operations; + audio_devs[my_dev]->dmachan = hw_config->dma; + audio_devs[my_dev]->buffcount = 1; + audio_devs[my_dev]->buffsize = DSP_BUFFSIZE; + audio_devs[my_dev]->devc = devc; + devc->my_audiodev = my_dev; + devc->opened = 0; + audio_devs[my_dev]->coproc = &sscape_coproc_operations; + if (snd_set_irq_handler (hw_config->irq, sscapeintr, "SoundScape") < 0) + printk ("Error: Can't allocate IRQ for SoundScape\n"); + + sscape_write (devc, GA_INTENA_REG, 0x80); /* Master IRQ enable */ + } + else + printk ("SoundScape: More than enough audio devices detected\n"); +#endif +#endif + devc->ok = 1; + return mem_start; +} + +int +probe_sscape (struct address_info *hw_config) +{ + unsigned char save; + + devc->base = hw_config->io_base; + devc->irq = hw_config->irq; + devc->dma = hw_config->dma; + + /* + * First check that the address register of "ODIE" is + * there and that it has exactly 4 writeable bits. + * First 4 bits + */ + if ((save = INB (PORT (ODIE_ADDR))) & 0xf0) + return 0; + + OUTB (0x00, PORT (ODIE_ADDR)); + if (INB (PORT (ODIE_ADDR)) != 0x00) + return 0; + + OUTB (0xff, PORT (ODIE_ADDR)); + if (INB (PORT (ODIE_ADDR)) != 0x0f) + return 0; + + OUTB (save, PORT (ODIE_ADDR)); + + /* + * Now verify that some indirect registers return zero on some bits. + * This may break the driver with some future revisions of "ODIE" but... + */ + + if (sscape_read (devc, 0) & 0x0c) + return 0; + + if (sscape_read (devc, 1) & 0x0f) + return 0; + + if (sscape_read (devc, 5) & 0x0f) + return 0; + +#ifdef SSCAPE_DEBUG1 + /* + * Temporary debugging aid. Print contents of the registers before + * changing them. + */ + { + int i; + + for (i = 0; i < 13; i++) + printk ("I%d = %02x (old value)\n", i, sscape_read (devc, i)); + } +#endif + + return 1; +} + +int +probe_ss_ms_sound (struct address_info *hw_config) +{ + int i, irq_bits = 0xff; + + if (devc->ok == 0) + { + printk ("SoundScape: Invalid initialization order.\n"); + return 0; + } + + for (i = 0; i < sizeof (valid_interrupts); i++) + if (hw_config->irq == valid_interrupts[i]) + { + irq_bits = i; + break; + } +#ifdef REVEAL_SPEA + { + int tmp, status = 0; + int cc; + + if (!((tmp = sscape_read (devc, GA_HMCTL_REG)) & 0xc0)) + { + sscape_write (devc, GA_HMCTL_REG, tmp | 0x80); + for (cc = 0; cc < 200000; ++cc) + INB (devc->base + ODIE_ADDR); + } + } +#endif + + if (hw_config->irq > 15 || irq_bits == 0xff) + { + printk ("SoundScape: Invalid MSS IRQ%d\n", hw_config->irq); + return 0; + } + + return ad1848_detect (hw_config->io_base); +} + +long +attach_ss_ms_sound (long mem_start, struct address_info *hw_config) +{ + /* + * This routine configures the SoundScape card for use with the + * Win Sound System driver. The AD1848 codec interface uses the CD-ROM + * config registers of the "ODIE". + */ + + int i, irq_bits = 0xff; + +#ifdef EXCLUDE_NATIVE_PCM + int prev_devs = num_audiodevs; + +#endif + + /* + * Setup the DMA polarity. + */ + sscape_write (devc, GA_DMACFG_REG, 0x50); + + /* + * Take the gate-arry off of the DMA channel. + */ + sscape_write (devc, GA_DMAB_REG, 0x20); + + /* + * Init the AD1848 (CD-ROM) config reg. + */ + + for (i = 0; i < sizeof (valid_interrupts); i++) + if (hw_config->irq == valid_interrupts[i]) + { + irq_bits = i; + break; + } + + sscape_write (devc, GA_CDCFG_REG, 0x89 | (hw_config->dma << 4) | + (irq_bits << 1)); + + if (hw_config->irq == devc->irq) + printk ("SoundScape: Warning! The WSS mode can't share IRQ with MIDI\n"); + + ad1848_init ("SoundScape", hw_config->io_base, + hw_config->irq, + hw_config->dma, + hw_config->dma); + +#ifdef EXCLUDE_NATIVE_PCM + if (num_audiodevs == (prev_devs + 1)) /* The AD1848 driver installed itself */ + audio_devs[prev_devs]->coproc = &sscape_coproc_operations; +#endif +#ifdef SSCAPE_DEBUG5 + /* + * Temporary debugging aid. Print contents of the registers + * after the AD1848 device has been initialized. + */ + { + int i; + + for (i = 0; i < 13; i++) + printk ("I%d = %02x\n", i, sscape_read (devc, i)); + } +#endif + + return mem_start; +} + +#endif diff --git a/sys/i386/isa/sound/sys_timer.c b/sys/i386/isa/sound/sys_timer.c index 27a333e..6366c22 100644 --- a/sys/i386/isa/sound/sys_timer.c +++ b/sys/i386/isa/sound/sys_timer.c @@ -26,7 +26,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * sys_timer.c,v 1.2 1994/10/01 02:17:16 swallace Exp */ #define SEQUENCER_C @@ -52,13 +51,13 @@ static unsigned long tmr2ticks (int tmr_value) { /* - * Convert system timer ticks (HZ) to MIDI ticks - */ + * Convert system timer ticks (HZ) to MIDI ticks + */ unsigned long tmp; unsigned long scale; - tmp = (tmr_value * 1000) / HZ;/* Convert to msecs */ + tmp = (tmr_value * 1000) / HZ; /* Convert to msecs */ scale = (60 * 1000) / (curr_tempo * curr_timebase); /* msecs per MIDI tick */ diff --git a/sys/i386/isa/sound/trix.c b/sys/i386/isa/sound/trix.c new file mode 100644 index 0000000..6e3db0f --- /dev/null +++ b/sys/i386/isa/sound/trix.c @@ -0,0 +1,323 @@ +/* + * sound/trix.c + * + * Low level driver for the MediaTriX AudioTriX Pro + * (MT-0002-PC Control Chip) + * + * Copyright by Hannu Savolainen 1995 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "sound_config.h" + +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_TRIX) + +#ifdef INCLUDE_TRIX_BOOT +#include "trix_boot.h" +#endif + +static int kilroy_was_here = 0; /* Don't detect twice */ +static int sb_initialized = 0; +static int mpu_initialized = 0; + +static unsigned char +trix_read (int addr) +{ + OUTB ((unsigned char) addr, 0x390); /* MT-0002-PC ASIC address */ + return INB (0x391); /* MT-0002-PC ASIC data */ +} + +static void +trix_write (int addr, int data) +{ + OUTB ((unsigned char) addr, 0x390); /* MT-0002-PC ASIC address */ + OUTB ((unsigned char) data, 0x391); /* MT-0002-PC ASIC data */ +} + +static void +download_boot (int base) +{ + int i = 0, n = sizeof (trix_boot); + + trix_write (0xf8, 0x00); /* ??????? */ + OUTB (0x01, base + 6); /* Clear the internal data pointer */ + OUTB (0x00, base + 6); /* Restart */ + + /* + * Write the boot code to the RAM upload/download register. + * Each write increments the internal data pointer. + */ + OUTB (0x01, base + 6); /* Clear the internal data pointer */ + OUTB (0x1A, 0x390); /* Select RAM download/upload port */ + + for (i = 0; i < n; i++) + OUTB (trix_boot[i], 0x391); + for (i = n; i < 10016; i++) /* Clear up to first 16 bytes of data RAM */ + OUTB (0x00, 0x391); + OUTB (0x00, base + 6); /* Reset */ + OUTB (0x50, 0x390); /* ?????? */ +} + +static int +trix_set_wss_port (struct address_info *hw_config) +{ + unsigned char addr_bits; + + if (kilroy_was_here) /* Already initialized */ + return 0; + + kilroy_was_here = 1; + + if (trix_read (0x15) != 0x71) /* No asic signature */ + return 0; + + /* + * Disable separate wave playback and recording DMA channels since + * the driver doesn't support duplex mode yet. + */ + + trix_write (0x13, trix_read (0x13) & ~0x80); + trix_write (0x14, trix_read (0x14) & ~0x80); + + /* + * Configure the ASIC to place the codec to the proper I/O location + */ + + switch (hw_config->io_base) + { + case 0x530: + addr_bits = 0; + break; + case 0x604: + addr_bits = 1; + break; + case 0xE80: + addr_bits = 2; + break; + case 0xF40: + addr_bits = 3; + break; + default: + return 0; + } + + trix_write (0x19, (trix_read (0x19) & 0x03) | addr_bits); + return 1; +} + +/* + * Probe and attach routines for the Windows Sound System mode of + * AudioTriX Pro + */ + +int +probe_trix_wss (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 (!trix_set_wss_port (hw_config)) + return 0; + + if ((INB (hw_config->io_base + 3) & 0x3f) != 0x00) + { + DDB (printk ("No MSS signature detected on port 0x%x\n", hw_config->io_base)); + return 0; + } + + if (hw_config->irq > 11) + { + printk ("AudioTriX: Bad WSS IRQ %d\n", hw_config->irq); + return 0; + } + + if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) + { + printk ("AudioTriX: Bad WSS 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 ("AudioTriX: Can't use DMA0 with a 8 bit card\n"); + return 0; + } + + if (hw_config->irq > 7 && hw_config->irq != 9 && INB (hw_config->io_base + 3) & 0x80) + { + printk ("AudioTriX: Can't use IRQ%d with a 8 bit card\n", hw_config->irq); + return 0; + } + + return ad1848_detect (hw_config->io_base + 4); +} + +long +attach_trix_wss (long mem_start, struct address_info *hw_config) +{ + static unsigned char interrupt_bits[12] = + {-1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20}; + char bits; + + static unsigned char dma_bits[4] = + {1, 2, 0, 3}; + + int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3; + + if (!kilroy_was_here) + return mem_start; + + /* + * Set the IRQ and DMA addresses. + */ + + bits = interrupt_bits[hw_config->irq]; + if (bits == -1) + return mem_start; + + OUTB (bits | 0x40, config_port); + if ((INB (version_port) & 0x40) == 0) + printk ("[IRQ Conflict?]"); + + OUTB (bits | dma_bits[hw_config->dma], config_port); /* Write IRQ+DMA setup */ + + ad1848_init ("AudioTriX Pro", hw_config->io_base + 4, + hw_config->irq, + hw_config->dma, + hw_config->dma); + return mem_start; +} + +int +probe_trix_sb (struct address_info *hw_config) +{ + + int tmp; + unsigned char conf; + static char irq_translate[] = + {-1, -1, -1, 0, 1, 2, -1, 3}; + +#ifndef INCLUDE_TRIX_BOOT + return 0; /* No boot code -> no fun */ +#endif + if (!kilroy_was_here) + return 0; /* AudioTriX Pro has not been detected earlier */ + + if (sb_initialized) + return 0; + + if (hw_config->io_base & 0xffffff8f != 0x200) + return 0; + + tmp = hw_config->irq; + if (tmp > 7) + return 0; + if (irq_translate[tmp] == -1) + return 0; + + tmp = hw_config->dma; + if (tmp != 1 && tmp != 3) + return 0; + + conf = 0x84; /* DMA and IRQ enable */ + conf |= hw_config->io_base & 0x70; /* I/O address bits */ + conf |= irq_translate[hw_config->irq]; + if (hw_config->dma == 3) + conf |= 0x08; + trix_write (0x1b, conf); + + download_boot (hw_config->io_base); + sb_initialized = 1; + + return 1; +} + +long +attach_trix_sb (long mem_start, struct address_info *hw_config) +{ + printk (" <AudioTriX>"); + return mem_start; +} + +long +attach_trix_mpu (long mem_start, struct address_info *hw_config) +{ + return attach_mpu401 (mem_start, hw_config); +} + +int +probe_trix_mpu (struct address_info *hw_config) +{ + unsigned char conf; + static char irq_bits[] = + {-1, -1, -1, 1, 2, 3, -1, 4, -1, 5}; + + if (!kilroy_was_here) + return 0; /* AudioTriX Pro has not been detected earlier */ + + if (!sb_initialized) + return 0; + + if (mpu_initialized) + return 0; + + if (hw_config->irq > 9) + return 0; + + if (irq_bits[hw_config->irq] == -1) + return 0; + + switch (hw_config->io_base) + { + case 0x330: + conf = 0x00; + break; + case 0x370: + conf = 0x04; + break; + case 0x3b0: + conf = 0x08; + break; + case 0x3f0: + conf = 0x0c; + break; + default: + return 0; /* Invalid port */ + } + + conf |= irq_bits[hw_config->irq] << 4; + + trix_write (0x19, (trix_read (0x19) & 0x83) | conf); + + mpu_initialized = 1; + + return probe_mpu401 (hw_config); +} + +#endif diff --git a/sys/i386/isa/sound/tuning.h b/sys/i386/isa/sound/tuning.h index 0d1d6bb..858e1fe 100644 --- a/sys/i386/isa/sound/tuning.h +++ b/sys/i386/isa/sound/tuning.h @@ -1,29 +1,26 @@ -/* - * tuning.h,v 1.2 1994/08/02 07:41:00 davidg Exp - */ #ifdef SEQUENCER_C -unsigned short semitone_tuning[24] = +unsigned short semitone_tuning[24] = { -/* 0 */ 10000, 10595, 11225, 11892, 12599, 13348, 14142, 14983, -/* 8 */ 15874, 16818, 17818, 18877, 20000, 21189, 22449, 23784, +/* 0 */ 10000, 10595, 11225, 11892, 12599, 13348, 14142, 14983, +/* 8 */ 15874, 16818, 17818, 18877, 20000, 21189, 22449, 23784, /* 16 */ 25198, 26697, 28284, 29966, 31748, 33636, 35636, 37755 }; unsigned short cent_tuning[100] = { -/* 0 */ 10000, 10006, 10012, 10017, 10023, 10029, 10035, 10041, -/* 8 */ 10046, 10052, 10058, 10064, 10070, 10075, 10081, 10087, -/* 16 */ 10093, 10099, 10105, 10110, 10116, 10122, 10128, 10134, -/* 24 */ 10140, 10145, 10151, 10157, 10163, 10169, 10175, 10181, -/* 32 */ 10187, 10192, 10198, 10204, 10210, 10216, 10222, 10228, -/* 40 */ 10234, 10240, 10246, 10251, 10257, 10263, 10269, 10275, -/* 48 */ 10281, 10287, 10293, 10299, 10305, 10311, 10317, 10323, -/* 56 */ 10329, 10335, 10341, 10347, 10353, 10359, 10365, 10371, -/* 64 */ 10377, 10383, 10389, 10395, 10401, 10407, 10413, 10419, -/* 72 */ 10425, 10431, 10437, 10443, 10449, 10455, 10461, 10467, -/* 80 */ 10473, 10479, 10485, 10491, 10497, 10503, 10509, 10515, -/* 88 */ 10521, 10528, 10534, 10540, 10546, 10552, 10558, 10564, +/* 0 */ 10000, 10006, 10012, 10017, 10023, 10029, 10035, 10041, +/* 8 */ 10046, 10052, 10058, 10064, 10070, 10075, 10081, 10087, +/* 16 */ 10093, 10099, 10105, 10110, 10116, 10122, 10128, 10134, +/* 24 */ 10140, 10145, 10151, 10157, 10163, 10169, 10175, 10181, +/* 32 */ 10187, 10192, 10198, 10204, 10210, 10216, 10222, 10228, +/* 40 */ 10234, 10240, 10246, 10251, 10257, 10263, 10269, 10275, +/* 48 */ 10281, 10287, 10293, 10299, 10305, 10311, 10317, 10323, +/* 56 */ 10329, 10335, 10341, 10347, 10353, 10359, 10365, 10371, +/* 64 */ 10377, 10383, 10389, 10395, 10401, 10407, 10413, 10419, +/* 72 */ 10425, 10431, 10437, 10443, 10449, 10455, 10461, 10467, +/* 80 */ 10473, 10479, 10485, 10491, 10497, 10503, 10509, 10515, +/* 88 */ 10521, 10528, 10534, 10540, 10546, 10552, 10558, 10564, /* 96 */ 10570, 10576, 10582, 10589 }; #else diff --git a/sys/i386/isa/sound/uart6850.c b/sys/i386/isa/sound/uart6850.c index 4d8be84..ff6d6c3 100644 --- a/sys/i386/isa/sound/uart6850.c +++ b/sys/i386/isa/sound/uart6850.c @@ -26,7 +26,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * uart6850.c,v 1.2 1994/10/01 02:17:17 swallace Exp */ #include "sound_config.h" @@ -94,9 +93,8 @@ uart6850_input_loop (void) } void -m6850intr (int unit) +m6850intr (INTR_HANDLER_PARMS (irq, dummy)) { - printk ("M"); if (input_avail ()) uart6850_input_loop (); } @@ -244,6 +242,7 @@ static struct midi_operations uart6850_operations = { {"6850 UART", 0, 0, SNDCARD_UART6850}, &std_midi_synth, + {0}, uart6850_open, uart6850_close, uart6850_ioctl, @@ -285,7 +284,7 @@ attach_uart6850 (long mem_start, struct address_info *hw_config) RESTORE_INTR (flags); -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) printk ("uart0: <6850 Midi Interface>"); #else printk (" <6850 Midi Interface>"); @@ -314,7 +313,7 @@ probe_uart6850 (struct address_info *hw_config) uart6850_base = hw_config->io_base; uart6850_irq = hw_config->irq; - if (snd_set_irq_handler (uart6850_irq, m6850intr) < 0) + if (snd_set_irq_handler (uart6850_irq, m6850intr, "MIDI6850") < 0) return 0; ok = reset_uart6850 (); diff --git a/sys/i386/isa/sound/ulaw.h b/sys/i386/isa/sound/ulaw.h index f60d5b6..be9f92d 100644 --- a/sys/i386/isa/sound/ulaw.h +++ b/sys/i386/isa/sound/ulaw.h @@ -1,69 +1,69 @@ static unsigned char ulaw_dsp[] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 2, - 5, 9, 13, 17, 21, 25, 29, 33, - 37, 41, 45, 49, 53, 57, 61, 65, - 68, 70, 72, 74, 76, 78, 80, 82, - 84, 86, 88, 90, 92, 94, 96, 98, - 100, 101, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 113, 114, 115, - 115, 116, 116, 117, 117, 118, 118, 119, - 119, 120, 120, 121, 121, 122, 122, 123, - 123, 123, 124, 124, 124, 124, 125, 125, - 125, 125, 126, 126, 126, 126, 127, 127, - 127, 127, 127, 127, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, - 252, 248, 244, 240, 236, 232, 228, 224, - 220, 216, 212, 208, 204, 200, 196, 192, - 189, 187, 185, 183, 181, 179, 177, 175, - 173, 171, 169, 167, 165, 163, 161, 159, - 157, 156, 155, 154, 153, 152, 151, 150, - 149, 148, 147, 146, 145, 144, 143, 142, - 142, 141, 141, 140, 140, 139, 139, 138, - 138, 137, 137, 136, 136, 135, 135, 134, - 134, 134, 133, 133, 133, 133, 132, 132, - 132, 132, 131, 131, 131, 131, 130, 130, - 130, 130, 130, 130, 129, 129, 129, 129, - 129, 129, 129, 129, 128, 128, 128, 128, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2, + 5, 9, 13, 17, 21, 25, 29, 33, + 37, 41, 45, 49, 53, 57, 61, 65, + 68, 70, 72, 74, 76, 78, 80, 82, + 84, 86, 88, 90, 92, 94, 96, 98, + 100, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, + 115, 116, 116, 117, 117, 118, 118, 119, + 119, 120, 120, 121, 121, 122, 122, 123, + 123, 123, 124, 124, 124, 124, 125, 125, + 125, 125, 126, 126, 126, 126, 127, 127, + 127, 127, 127, 127, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 252, 248, 244, 240, 236, 232, 228, 224, + 220, 216, 212, 208, 204, 200, 196, 192, + 189, 187, 185, 183, 181, 179, 177, 175, + 173, 171, 169, 167, 165, 163, 161, 159, + 157, 156, 155, 154, 153, 152, 151, 150, + 149, 148, 147, 146, 145, 144, 143, 142, + 142, 141, 141, 140, 140, 139, 139, 138, + 138, 137, 137, 136, 136, 135, 135, 134, + 134, 134, 133, 133, 133, 133, 132, 132, + 132, 132, 131, 131, 131, 131, 130, 130, + 130, 130, 130, 130, 129, 129, 129, 129, + 129, 129, 129, 129, 128, 128, 128, 128, }; static unsigned char dsp_ulaw[] = { - 31, 31, 31, 32, 32, 32, 32, 33, - 33, 33, 33, 34, 34, 34, 34, 35, - 35, 35, 35, 36, 36, 36, 36, 37, - 37, 37, 37, 38, 38, 38, 38, 39, - 39, 39, 39, 40, 40, 40, 40, 41, - 41, 41, 41, 42, 42, 42, 42, 43, - 43, 43, 43, 44, 44, 44, 44, 45, - 45, 45, 45, 46, 46, 46, 46, 47, - 47, 47, 47, 48, 48, 49, 49, 50, - 50, 51, 51, 52, 52, 53, 53, 54, - 54, 55, 55, 56, 56, 57, 57, 58, - 58, 59, 59, 60, 60, 61, 61, 62, - 62, 63, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 73, 74, 75, 76, - 77, 78, 79, 81, 83, 85, 87, 89, - 91, 93, 95, 99, 103, 107, 111, 119, - 255, 247, 239, 235, 231, 227, 223, 221, - 219, 217, 215, 213, 211, 209, 207, 206, - 205, 204, 203, 202, 201, 200, 199, 198, - 197, 196, 195, 194, 193, 192, 191, 191, - 190, 190, 189, 189, 188, 188, 187, 187, - 186, 186, 185, 185, 184, 184, 183, 183, - 182, 182, 181, 181, 180, 180, 179, 179, - 178, 178, 177, 177, 176, 176, 175, 175, - 175, 175, 174, 174, 174, 174, 173, 173, - 173, 173, 172, 172, 172, 172, 171, 171, - 171, 171, 170, 170, 170, 170, 169, 169, - 169, 169, 168, 168, 168, 168, 167, 167, - 167, 167, 166, 166, 166, 166, 165, 165, - 165, 165, 164, 164, 164, 164, 163, 163, - 163, 163, 162, 162, 162, 162, 161, 161, - 161, 161, 160, 160, 160, 160, 159, 159, + 31, 31, 31, 32, 32, 32, 32, 33, + 33, 33, 33, 34, 34, 34, 34, 35, + 35, 35, 35, 36, 36, 36, 36, 37, + 37, 37, 37, 38, 38, 38, 38, 39, + 39, 39, 39, 40, 40, 40, 40, 41, + 41, 41, 41, 42, 42, 42, 42, 43, + 43, 43, 43, 44, 44, 44, 44, 45, + 45, 45, 45, 46, 46, 46, 46, 47, + 47, 47, 47, 48, 48, 49, 49, 50, + 50, 51, 51, 52, 52, 53, 53, 54, + 54, 55, 55, 56, 56, 57, 57, 58, + 58, 59, 59, 60, 60, 61, 61, 62, + 62, 63, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 81, 83, 85, 87, 89, + 91, 93, 95, 99, 103, 107, 111, 119, + 255, 247, 239, 235, 231, 227, 223, 221, + 219, 217, 215, 213, 211, 209, 207, 206, + 205, 204, 203, 202, 201, 200, 199, 198, + 197, 196, 195, 194, 193, 192, 191, 191, + 190, 190, 189, 189, 188, 188, 187, 187, + 186, 186, 185, 185, 184, 184, 183, 183, + 182, 182, 181, 181, 180, 180, 179, 179, + 178, 178, 177, 177, 176, 176, 175, 175, + 175, 175, 174, 174, 174, 174, 173, 173, + 173, 173, 172, 172, 172, 172, 171, 171, + 171, 171, 170, 170, 170, 170, 169, 169, + 169, 169, 168, 168, 168, 168, 167, 167, + 167, 167, 166, 166, 166, 166, 165, 165, + 165, 165, 164, 164, 164, 164, 163, 163, + 163, 163, 162, 162, 162, 162, 161, 161, + 161, 161, 160, 160, 160, 160, 159, 159, }; diff --git a/sys/i386/isa/sound/ultrasound.h b/sys/i386/isa/sound/ultrasound.h new file mode 100644 index 0000000..40e2443 --- /dev/null +++ b/sys/i386/isa/sound/ultrasound.h @@ -0,0 +1,121 @@ +#ifndef _ULTRASOUND_H_ +#define _ULTRASOUND_H_ +/* + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +/* + * ultrasound.h - Macros for programming the Gravis Ultrasound + * These macros are extremely device dependent + * and not portable. + */ + +/* + * Private events for Gravis Ultrasound (GUS) + * + * Format: + * byte 0 - SEQ_PRIVATE (0xfe) + * byte 1 - Synthesizer device number (0-N) + * byte 2 - Command (see below) + * byte 3 - Voice number (0-31) + * bytes 4 and 5 - parameter P1 (unsigned short) + * bytes 6 and 7 - parameter P2 (unsigned short) + * + * Commands: + * Each command affects one voice defined in byte 3. + * Unused parameters (P1 and/or P2 *MUST* be initialized to zero). + * _GUS_NUMVOICES - Sets max. number of concurrent voices (P1=14-31, default 16) + * _GUS_VOICESAMPLE- ************ OBSOLETE ************* + * _GUS_VOICEON - Starts voice (P1=voice mode) + * _GUS_VOICEOFF - Stops voice (no parameters) + * _GUS_VOICEFADE - Stops the voice smoothly. + * _GUS_VOICEMODE - Alters the voice mode, don't start or stop voice (P1=voice mode) + * _GUS_VOICEBALA - Sets voice balence (P1, 0=left, 7=middle and 15=right, default 7) + * _GUS_VOICEFREQ - Sets voice (sample) playback frequency (P1=Hz) + * _GUS_VOICEVOL - Sets voice volume (P1=volume, 0xfff=max, 0xeff=half, 0x000=off) + * _GUS_VOICEVOL2 - Sets voice volume (P1=volume, 0xfff=max, 0xeff=half, 0x000=off) + * (Like GUS_VOICEVOL but doesn't change the hw + * volume. It just updates volume in the voice table). + * + * _GUS_RAMPRANGE - Sets limits for volume ramping (P1=low volume, P2=high volume) + * _GUS_RAMPRATE - Sets the speed for volume ramping (P1=scale, P2=rate) + * _GUS_RAMPMODE - Sets the volume ramping mode (P1=ramping mode) + * _GUS_RAMPON - Starts volume ramping (no parameters) + * _GUS_RAMPOFF - Stops volume ramping (no parameters) + * _GUS_VOLUME_SCALE - Changes the volume calculation constants + * for all voices. + */ + +#define _GUS_NUMVOICES 0x00 +#define _GUS_VOICESAMPLE 0x01 /* OBSOLETE */ +#define _GUS_VOICEON 0x02 +#define _GUS_VOICEOFF 0x03 +#define _GUS_VOICEMODE 0x04 +#define _GUS_VOICEBALA 0x05 +#define _GUS_VOICEFREQ 0x06 +#define _GUS_VOICEVOL 0x07 +#define _GUS_RAMPRANGE 0x08 +#define _GUS_RAMPRATE 0x09 +#define _GUS_RAMPMODE 0x0a +#define _GUS_RAMPON 0x0b +#define _GUS_RAMPOFF 0x0c +#define _GUS_VOICEFADE 0x0d +#define _GUS_VOLUME_SCALE 0x0e +#define _GUS_VOICEVOL2 0x0f +#define _GUS_VOICE_POS 0x10 + +/* + * GUS API macros + */ + +#define _GUS_CMD(chn, voice, cmd, p1, p2) \ + {_SEQ_NEEDBUF(8); _seqbuf[_seqbufptr] = SEQ_PRIVATE;\ + _seqbuf[_seqbufptr+1] = (chn); _seqbuf[_seqbufptr+2] = cmd;\ + _seqbuf[_seqbufptr+3] = voice;\ + *(unsigned short*)&_seqbuf[_seqbufptr+4] = p1;\ + *(unsigned short*)&_seqbuf[_seqbufptr+6] = p2;\ + _SEQ_ADVBUF(8);} + +#define GUS_NUMVOICES(chn, p1) _GUS_CMD(chn, 0, _GUS_NUMVOICES, (p1), 0) +#define GUS_VOICESAMPLE(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICESAMPLE, (p1), 0) /* OBSOLETE */ +#define GUS_VOICEON(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICEON, (p1), 0) +#define GUS_VOICEOFF(chn, voice) _GUS_CMD(chn, voice, _GUS_VOICEOFF, 0, 0) +#define GUS_VOICEFADE(chn, voice) _GUS_CMD(chn, voice, _GUS_VOICEFADE, 0, 0) +#define GUS_VOICEMODE(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICEMODE, (p1), 0) +#define GUS_VOICEBALA(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICEBALA, (p1), 0) +#define GUS_VOICEFREQ(chn, voice, p) _GUS_CMD(chn, voice, _GUS_VOICEFREQ, \ + (p) & 0xffff, ((p) >> 16) & 0xffff) +#define GUS_VOICEVOL(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICEVOL, (p1), 0) +#define GUS_VOICEVOL2(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICEVOL2, (p1), 0) +#define GUS_RAMPRANGE(chn, voice, low, high) _GUS_CMD(chn, voice, _GUS_RAMPRANGE, (low), (high)) +#define GUS_RAMPRATE(chn, voice, p1, p2) _GUS_CMD(chn, voice, _GUS_RAMPRATE, (p1), (p2)) +#define GUS_RAMPMODE(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_RAMPMODE, (p1), 0) +#define GUS_RAMPON(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_RAMPON, (p1), 0) +#define GUS_RAMPOFF(chn, voice) _GUS_CMD(chn, voice, _GUS_RAMPOFF, 0, 0) +#define GUS_VOLUME_SCALE(chn, voice, p1, p2) _GUS_CMD(chn, voice, _GUS_VOLUME_SCALE, (p1), (p2)) +#define GUS_VOICE_POS(chn, voice, p) _GUS_CMD(chn, voice, _GUS_VOICE_POS, \ + (p) & 0xffff, ((p) >> 16) & 0xffff) + +#endif |