From a75ba8fa22bbc804034c31bdc19ddfe5318ab7cf Mon Sep 17 00:00:00 2001 From: Steven Wallace Date: Fri, 11 Mar 1994 10:27:25 +0000 Subject: [PATCH] Integrated Hannu Savolainen's new VoxWare sound drivers, version 2.4. These drivers now have full SoundBlaster 16 support. --- sys/i386/isa/sound/CHANGELOG | 55 + sys/i386/isa/sound/RELNOTES.Linux | 235 ++-- sys/i386/isa/sound/adlib_card.c | 3 +- sys/i386/isa/sound/audio.c | 102 +- sys/i386/isa/sound/dev_table.c | 135 ++- sys/i386/isa/sound/dev_table.h | 42 +- sys/i386/isa/sound/dmabuf.c | 324 ++++-- sys/i386/isa/sound/gus_card.c | 77 +- sys/i386/isa/sound/gus_midi.c | 4 +- sys/i386/isa/sound/gus_vol.c | 43 +- sys/i386/isa/sound/gus_wave.c | 1677 ++++++++++++++++++++++------- sys/i386/isa/sound/local.h | 10 +- sys/i386/isa/sound/midi.c | 216 ++-- sys/i386/isa/sound/midibuf.c | 2 +- sys/i386/isa/sound/mpu401.c | 60 +- sys/i386/isa/sound/opl3.c | 54 +- sys/i386/isa/sound/os.h | 94 +- sys/i386/isa/sound/pas.h | 7 +- sys/i386/isa/sound/pas2_card.c | 96 +- sys/i386/isa/sound/pas2_midi.c | 12 +- sys/i386/isa/sound/pas2_mixer.c | 10 +- sys/i386/isa/sound/pas2_pcm.c | 41 +- sys/i386/isa/sound/patmgr.c | 31 +- sys/i386/isa/sound/pro_midi.c | 140 +-- sys/i386/isa/sound/sb.h | 28 + sys/i386/isa/sound/sb16_dsp.c | 641 +++++++++++ sys/i386/isa/sound/sb16_midi.c | 314 ++++++ sys/i386/isa/sound/sb_card.c | 3 +- sys/i386/isa/sound/sb_dsp.c | 1089 +++++-------------- sys/i386/isa/sound/sb_midi.c | 198 ++++ sys/i386/isa/sound/sb_mixer.c | 359 ++++++ sys/i386/isa/sound/sb_mixer.h | 172 +++ sys/i386/isa/sound/sequencer.c | 284 ++--- sys/i386/isa/sound/sound_calls.h | 54 +- sys/i386/isa/sound/sound_config.h | 43 +- sys/i386/isa/sound/sound_switch.c | 444 ++++++++ sys/i386/isa/sound/soundcard.c | 256 +---- 37 files changed, 5023 insertions(+), 2332 deletions(-) create mode 100644 sys/i386/isa/sound/CHANGELOG create mode 100644 sys/i386/isa/sound/sb.h create mode 100644 sys/i386/isa/sound/sb16_dsp.c create mode 100644 sys/i386/isa/sound/sb16_midi.c create mode 100644 sys/i386/isa/sound/sb_midi.c create mode 100644 sys/i386/isa/sound/sb_mixer.c create mode 100644 sys/i386/isa/sound/sb_mixer.h create mode 100644 sys/i386/isa/sound/sound_switch.c diff --git a/sys/i386/isa/sound/CHANGELOG b/sys/i386/isa/sound/CHANGELOG new file mode 100644 index 000000000000..78168dd5d672 --- /dev/null +++ b/sys/i386/isa/sound/CHANGELOG @@ -0,0 +1,55 @@ +Changelog for version 2.4 +------------------------- + +Since 2.3b +- Fixed bug which made it impossible to make long recordings to disk. + Recording was not restarted after a buffer overflow situation. +- Limited mixer support for GUS. +- Numerous improvements to the GUS driver by Andrew Robinson. Including + some click removal etc. + +Since 2.3 +- Fixed some minor bugs in the SB16 driver. + +Since 2.2b +- Full SB16 DSP support. 8/16 bit, mono/stereo +- The SCO and FreeBSD versions should be in sync now. There are some + problems with SB16 and GUS in the freebsd versions. + The DMA buffer allocation of the SCO version has been polished but + there could still be some problems. At least it hogs memory. + The DMA channel + configuration method used in the sco/System is a hack. +- Support for the MPU emulation of the SB16. +- Some big arrays are now allocated boot time. This makes the bss segment + smaller which makes it possible to use the full driver with + NetBSD. These arrays are not allocated if no suitable soundcard is available. +- Fixed a bug in the compute_and_set_volume in gus_wave.c +- Fixed the too fast mono playback problem of SB Pro and PAS16. + +Since 2.2 +- Stereo recording for SB Pro. Somehow it was missing and nobody + had noticed it earlier. +- Minor polishing. +- Interpreting of boot time arguments (sound=) for Linux. +- Breakup of sb_dsp.c. Parts of the code has been moved to + sb_mixer.c and sb_midi.c + +Since 2.1 +- Preliminary support for SB16. + - The SB16 mixer is supported in it's native mode. + - Digitized voice capability up to 44.1 kHz/8 bit/mono + (16 bit and stereo support coming in the next release). +- Fixed some bugs in the digitized voice driver for PAS16. +- Proper initialization of the SB emulation of latest PAS16 models. + +- Significantly improved /dev/dsp and /dev/audio support. + - Now supports half duplex mode. It's now possible to record and + playback without closing and reopening the device. + - It's possible to use smaller buffers than earlier. There is a new + ioctl(fd, SNDCTL_DSP_SUBDIVIDE, &n) where n should be 1, 2 or 4. + This call instructs the driver to use smaller buffers. The default + buffer size (0.5 to 1.0 seconds) is divided by n. Should be called + immediately after opening the device. + +Since 2.0 +Just cosmetic changes. diff --git a/sys/i386/isa/sound/RELNOTES.Linux b/sys/i386/isa/sound/RELNOTES.Linux index 4082f4e255b0..bd47edef7c36 100644 --- a/sys/i386/isa/sound/RELNOTES.Linux +++ b/sys/i386/isa/sound/RELNOTES.Linux @@ -1,67 +1,68 @@ -Release notes for the Linux Sound Driver 1.99.9 ------------------------------------------------ +Release notes for the Linux Sound Driver 2.4 +-------------------------------------------- -******** THIS IS A BETA TEST RELEASE ******** -which means that there can be some untested things. In theory -there is a risk that this driver causes some trouble to your system. -You should not use this driver before backing up your disks. +NOTE! The sound driver is a part of the Linux kernel distribution also. + Check that your kernel doesn't have more recent version than this + when installing a separately distributed sound driver. The + version number of this driver is defined in the makefile. +This version contains a driver for the SB16 also. +The SB16 driver requires separate DMA channels for the 8 and 16 bit +modes. There should be a way to share the 8 bit DMA channels between +these modes but this feature is not supported yet. +The SB16 DSP support is by Joerg Schubert (jsb@sth.ruhr-uni-bochum.de). +The SB16 driver has also the Midi input capability even at the same +time with the /dev/dsp. Also the WaveBlaster daughter board is supported. +No support for the ASP chip yet (the ASP chip can be installed but it's +not used by the driver). +You will need the snd-util-2.4.tar.gz and snd-data-0.1.tar.Z +packages to use this driver. They should be in the same +ftp site or BBS from where you got this driver. For +example at nic.funet.fi:pub/OS/Linux/*. -Welcome to use the Gravis UltraSound driver for Linux. This -driver still supports the same cards than version 1.0c -(SoundBlaster, SB Pro, Pro Audio Spectrum 16 and AdLib). -In addition there is rather limited support for MPU-401 +There is a new version of the tracker program available (tracker-3_19.lzh) but +I don't know where it is available. The tracker 3.10 has bugs and it don't work +without some fixes. Look at the README of the snd-util-2.3. + +If you are looking for the installation instructions, please +look at linux/Readme. + +This version supports the following soundcards: +GUS, SoundBlaster, SB Pro, SB16, Pro Audio Spectrum 16 and AdLib. +In addition there is rather limited support for MPU-401. (and compatible) midi cards. Also the OPL-3 synthesizer -of the SB Pro and PAS16 cards is now supported in the 4 OP -modes. Most of the features of the /dev/sequencer device file are available just for GUS owners. -The SoundBlaster 16 and SB 16 ASP cards are not supported. -They could work in mono mode with speeds < 22 kHz. -The OPL-3 chicp of the SB 16 should work (without problems?). -Is there anybody willing to implement the SB 16 support -(have the SB 16 and the SDK for it)? - - -This is the first version of the driver which has almost -all of the features which I have planned to include into -version 2.0. Some features are still missing and some ones -doesn't work. - NOTE! There are separate driver for CD-ROMS supported by some soundcards. The driver for CDU31A (Fusion 16) is called cdu31a-0.6.diff.z. It will be contained in the Linux version 0.99.12. The driver for the CD-ROM of SB Pro is sbpcd0.4.tar.gz (these were the latest versions when I wrote this). These files should be at least at sunsite.unc.edu. - As far as I know, there is no driver for the SCSI interface of PAS16 - (yet). + Also the SCSI interface of the PAS16 should be supported by + Linux 0.99.13k and later. There is also a driver for joystick. Look for file joystick-0.5.tar.gz (sunsite). - Since this driver is a sound driver, it will not contain support - for SCSI/CD-ROM/Joystick -devices. Compatibility with the earlier versions --------------------------------------- -This is just like the version 1.99.7/1.99.8. There is just some minor -enhancements. Most of them are portability fixes. If you are porting -this driver to any OS, please look at the 386bsd/os.h. There is some -new macros and some macros have more parameters. In addition this file -contains some usefull comments. +In this version the ultrasound.h no longer includes the sys/soundcard.h +You have to change the gmod.c of the snd-util-2.0 package and to add an +include for it. -**** There is some ISC and 386bsd stuff in this driver. Please stay away **** -This stuff is here just because I want to be in sync with the porters. These -ports don't work yet. +IMPORTANT!!!!!!!!!!!!!!!!!!!!!! + +This version is not binary or source compatible with the version 1.0c. The ioctl() interface has changed completely since version 1.0c. All programs using this driver must be at least recompiled. -The snd-util-1.99.6 package contains some utilities for this version. +The snd-util-2.0 package contains some utilities for this version. The version 1.0c and earlier used a 'nonportable' ioctl calling scheme where the input argument was passed by value and the output value was @@ -78,59 +79,46 @@ After version 1.99.0 this must be done as the following: If you have an application written for the version 1.0, you should search for the strings SNDCTL_ and SOUND_ and to check the parameters. +The following ioctl calls have changed: + + SNDCTL_SEQ_GETOUTCOUNT + SNDCTL_SEQ_GETINCOUNT + SNDCTL_SEQ_TESTMIDI + SNDCTL_DSP_SPEED + SNDCTL_DSP_STEREO + SNDCTL_DSP_GETBLKSIZE + SNDCTL_DSP_SAMPLESIZE + SOUND_PCM_WRITE_CHANNELS + SOUND_PCM_WRITE_FILTER + SOUND_PCM_READ_RATE + SOUND_PCM_READ_CHANNELS + SOUND_PCM_READ_BITS + SOUND_PCM_READ_FILTER + SOUND_PCM_WRITE_BITS + SOUND_PCM_WRITE_RATE + SOUND_MIXER_READ_* (several ones) + SOUND_MIXER_WRITE_* (several ones) Since the this version will support more than one synthesizer devices at the same time, the ioctl(SNDCTL_FM_LOAD_INSTR) is obsolete. In addition there is some new fields which must be initialized. Look at the sbiset.c in -the snd-util-1.99.6 package for further info. +the snd-util-2.0 package for further info. -The GUS patch format has changed since the version 1.99.3. You have to -use latest versions of the programs in the sound/gustest directory. In -addition the version 0.4g of the Adagio package supports this format. +This version is almost 100% compatible with the alpha test version (1.99.9). The +difference is in the installation procedure. -New features +Using this driver with other operating systems than Linux +--------------------------------------------------------- + +This package contains just the Linux version. The version 2.3 +for SCO is available at nic.funet.fi:pub/OS/Linux/ALPHA/sound. +The version 2.3 doesn't work well with xxxxxBSD. Use the version +2.3 for them. + +/dev/sndstat ------------ -There is also some changes which make this version more usable than -the version 1.0c. - -- /dev/dsp and /dev/audio - -The DMA buffering is now little bit more intelligent than earlier. The -buffer size is selected run-time so that a buffer holds data for 0.5 to -1.0 seconds of recording or playback. This makes recording more comfortable -than with version 1.0. With the previous version there was sometimes more -than 10 seconds of delay before the driver returned the first input byte. - -There is also support for more than one digitized voice devices. The device -files /dev/dsp1 and /dev/audio1 (minor 19 and 20) are available with PAS16. -The /dev/dsp (/dev/audio) is connected to the PCM circuit of the PAS16 itself -and the /dev/dsp1 (/dev/audio1) to the SB emulation of PAS16 card. Two -dsp/audio devices are available also if you have combination of SB and GUS. -With GUS and PAS16 you will have even three dsp/audio devices. These devices -can be used independently and can be active at the same time (3 channels -at the same time propably don't work). - -The dsp/audio support of PAS16 should be much cleaner now since the -constant clicking sound between the DMA blocks (about once per second) has -been eliminated. - -The stereo playback of GUS doesn't work perfectly. There is lot of -clicking in the output. - -- /dev/mixer - -No changes. - -There is no mixer for the GUS yet. - -- /dev/sequencer - -This part has the most changes. Mostly to support the rich -features of the Gravis UltraSound. There is also the support -for the OPL-3 synthesizer chip. - -- /dev/sndstat +The /dev/sndstat is now available in the SCO and BSD versions also. This is a new devicefile for debugging purposes. A better place for it is in the /proc -directory but I was just too lazy to implement it @@ -139,11 +127,13 @@ info about the current configuration (see the example below). If you send me a error/problem report, please include a printout from this device to your message (cat /dev/sndstat). +Note! This device file is currently present only in the Linux version + of this driver. + ------ cut here --- cat /dev/sndstat example -------- Sound Driver:1.99.7 (Fri Jul 9 17:01:47 GMT 1993 root@lucifer.savolai.fi) Config options: 0x00000d4b -Major number: 14 HW config: Type 4: Gravis Ultrasound at 0x210 irq 15 drq 6 Type 3: ProAudioSpectrum at 0x388 irq 10 drq 3 @@ -166,12 +156,15 @@ Midi devices: Mixer(s) installed ------ cut here ---- End of Example ----------- +Known bugs/limitations +---------------------- -Known bugs ----------- - -- There was clicking during stereo playback to /dev/dsp with GUS. - * Fixed in 1.99.9 * +- High speed recording of long audio samples (>20 second) to disk + is not possible. Everything works until next sync() which delays the + recording process too much. A delay longer than 0.1 to 0.3 seconds is + too much. +- The SB16 driver sometimes swaps the left and right channels together. +- Midi input doesn't work with SB and SB Pro (SB16 works). - It's not possible to open /dev/dsp (or /dev/audio) while the /dev/sequencer is open for output and GUS is the only soundcard installed. It's possible if /dev/dsp is opened before /dev/sequencer @@ -180,12 +173,70 @@ Known bugs - MPU-401 driver hangs the computer on boot if there is no MPU-401 installed. It uses by default the I/O port 0x330 whic is used by Adaptec 1542 SCSI adapter. +- There are some problems in midi input with MPU-401 and the SB16 midi + (MPU-401 emulation). This makes it impossible to read long sysex dumps + using these devices. - The /dev/sequencer playback to GUS sounds sometimes rather weird. Hitting ^C and playing again should solve this problem. This is propably caused by - incompatibilities between GUS and certain VLB motherboards. Try to avoid + incompatibilities between GUS and certain VLB motherboards (like mine). + Try to avoid switching between VTs while patches are being loaded to the GUS. -- There was some problems with GUS and Mitsumi CD in version 1.99.8. Fixed - in 1.99.9. -- /dev/audio sounded like stereo with GUS. Fixed in 1.99.9. + This problem disappears completely if you define GUS_PATCH_NO_DMA in the + local.h (after make config in linux). The drawback is that patch loading + without DMA takes several times longer than with DMA. - There is a skeleton of the patch manager support. It don't work in this version. + + +Future development +------------------ + +- Since this driver is no longer just the Linux Sound Driver, it's time + to give it a new name. I have planned to use name VoxWare. +- I'm writing a Hacker's guide to the VoxWare sound driver. Should + be ready within this(/next) year (alpha version). +- Completion of the ISC, SCO and BSD ports. Port to SVR4.2. +- I'm interested to implement/include support for new soundcards and + operating systems. + + Hint for the soundcard and OS manufacturers: + I'm collecting soundcards (high end ones) and SDKs for them. In + addition I'm collecting PC operating systems. I will be happy if + somebody sends me such items. In addition such kind of donation + makes it easier to change the VoxWare driver to support your + soundcard or operating system. However, please contact me before + sending anything. + +I will propably release some fix versions within this and next year. At +least when the non-Linux versions get ready. The next major release (3.0) +will be quite complete rewrite and released after about a year (end of 94 or +beginning of 95). + + +Contributors +------------ + +This driver contains code by several contributors. In addition several other +persons have given usefull suggestions. The following is a list of major +contributors. (I could have forgotten some names.) + + Craig Metz 1/2 of the PAS16 Mixer and PCM support + Rob Hooft Volume computation algorithm for the FM synth. + Mika Liljeberg uLaw encoding and decoding routines + Greg Lee Volume computation algorithm for the GUS and + lot's of valuable suggestions. + Andy Warner ISC port + Jim Lowe FreeBSD port + Anders Baekgaard Bughunting and valuable suggestions. + Joerg Schubert SB16 DSP support. + Andrew Robinson Improvements to the GUS driver + +Regards, + +Hannu Savolainen +hsavolai@cs.helsinki.fi + +Snail mail: Hannu Savolainen + Pallaksentie 4 A 2 + 00970 Helsinki + Finland diff --git a/sys/i386/isa/sound/adlib_card.c b/sys/i386/isa/sound/adlib_card.c index 29e521e914d9..3b7df5ebd925 100644 --- a/sys/i386/isa/sound/adlib_card.c +++ b/sys/i386/isa/sound/adlib_card.c @@ -1,6 +1,5 @@ - /* - * linux/kernel/chr_drv/sound/adlib_card.c + * sound/adlib_card.c * * Detection routine for the AdLib card. * diff --git a/sys/i386/isa/sound/audio.c b/sys/i386/isa/sound/audio.c index 775e6abeb021..84c1f6c7b744 100644 --- a/sys/i386/isa/sound/audio.c +++ b/sys/i386/isa/sound/audio.c @@ -1,5 +1,5 @@ /* - * linux/kernel/chr_drv/sound/audio.c + * sound/audio.c * * Device file manager for /dev/audio * @@ -38,23 +38,45 @@ #define OFF 0 static int wr_buff_no[MAX_DSP_DEV]; /* != -1, if there is a + * incomplete output block */ static int wr_buff_size[MAX_DSP_DEV], wr_buff_ptr[MAX_DSP_DEV]; + +static int audio_mode[MAX_DSP_DEV]; + +#define AM_NONE 0 +#define AM_WRITE 1 +#define AM_READ 2 + static char *wr_dma_buf[MAX_DSP_DEV]; int audio_open (int dev, struct fileinfo *file) { - int mode; int ret; + int bits; + int dev_type = dev & 0x0f; + int mode = file->mode & O_ACCMODE; dev = dev >> 4; - mode = file->mode & O_ACCMODE; + + if (dev_type == SND_DEV_DSP16) + bits = 16; + else + bits = 8; if ((ret = DMAbuf_open (dev, mode)) < 0) return ret; + if (DMAbuf_ioctl (dev, SNDCTL_DSP_SAMPLESIZE, bits, 1) != bits) + { + audio_release (dev, file); + return RET_ERROR (ENXIO); + } + wr_buff_no[dev] = -1; + audio_mode[dev] = AM_NONE; + return ret; } @@ -94,9 +116,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 @@ -106,12 +128,20 @@ audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) { int c, p, l; int err; + int dev_type = dev & 0x0f; dev = dev >> 4; p = 0; c = count; + if (audio_mode[dev] == AM_READ) /* Direction changed */ + { + wr_buff_no[dev] = -1; + } + + audio_mode[dev] = AM_WRITE; + if (!count) /* Flush output */ { if (wr_buff_no[dev] >= 0) @@ -136,15 +166,25 @@ audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) if (l > (wr_buff_size[dev] - wr_buff_ptr[dev])) l = (wr_buff_size[dev] - wr_buff_ptr[dev]); - COPY_FROM_USER (&wr_dma_buf[dev][wr_buff_ptr[dev]], buf, p, l); + if (!dsp_devs[dev]->copy_from_user) + { /* No device specific copy routine */ + COPY_FROM_USER (&wr_dma_buf[dev][wr_buff_ptr[dev]], buf, p, l); + } + else + dsp_devs[dev]->copy_from_user (dev, + wr_dma_buf[dev], wr_buff_ptr[dev], buf, p, l); + /* Insert local processing here */ + if (dev_type == SND_DEV_AUDIO) + { #ifdef linux - /* This just allows interrupts while the conversion is running */ - __asm__ ("sti"); + /* This just allows interrupts while the conversion is running */ + __asm__ ("sti"); #endif - translate_bytes (ulaw_dsp, &wr_dma_buf[dev][wr_buff_ptr[dev]], l); + translate_bytes (ulaw_dsp, &wr_dma_buf[dev][wr_buff_ptr[dev]], l); + } c -= l; p += l; @@ -169,11 +209,24 @@ audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) int c, p, l; char *dmabuf; int buff_no; + int dev_type = dev & 0x0f; dev = dev >> 4; p = 0; c = count; + if (audio_mode[dev] == AM_WRITE) + { + if (wr_buff_no[dev] >= 0) + { + DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]); + + wr_buff_no[dev] = -1; + } + } + + audio_mode[dev] = AM_READ; + while (c) { if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l)) < 0) @@ -183,12 +236,16 @@ audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) l = c; /* Insert any local processing here. */ + + if (dev_type == SND_DEV_AUDIO) + { #ifdef linux - /* This just allows interrupts while the conversion is running */ - __asm__ ("sti"); + /* This just allows interrupts while the conversion is running */ + __asm__ ("sti"); #endif - translate_bytes (dsp_ulaw, dmabuf, l); + translate_bytes (dsp_ulaw, dmabuf, l); + } COPY_TO_USER (buf, p, dmabuf, l); @@ -205,6 +262,8 @@ int audio_ioctl (int dev, struct fileinfo *file, unsigned int cmd, unsigned int arg) { + int dev_type = dev & 0x0f; + dev = dev >> 4; switch (cmd) @@ -235,11 +294,10 @@ audio_ioctl (int dev, struct fileinfo *file, break; default: -#if 1 - return RET_ERROR (EIO); -#else + if (dev_type == SND_DEV_AUDIO) + return RET_ERROR (EIO); + return DMAbuf_ioctl (dev, cmd, arg, 0); -#endif } } @@ -266,14 +324,14 @@ audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) int audio_open (int dev, struct fileinfo *file) - { - return RET_ERROR (ENXIO); - } +{ + return RET_ERROR (ENXIO); +} void audio_release (int dev, struct fileinfo *file) - { - }; +{ +}; int audio_ioctl (int dev, struct fileinfo *file, unsigned int cmd, unsigned int arg) diff --git a/sys/i386/isa/sound/dev_table.c b/sys/i386/isa/sound/dev_table.c index 7eabad4ab8a0..5f6fc7bf340c 100644 --- a/sys/i386/isa/sound/dev_table.c +++ b/sys/i386/isa/sound/dev_table.c @@ -1,5 +1,5 @@ /* - * linux/kernel/chr_drv/sound/dev_table.c + * sound/dev_table.c * * Device call tables. * @@ -38,21 +38,24 @@ sndtable_init (long mem_start) int i, n = sizeof (supported_drivers) / sizeof (struct card_info); for (i = 0; i < (n - 1); i++) - if (supported_drivers[i].probe (&supported_drivers[i].config)) - { + if (supported_drivers[i].enabled) + if (supported_drivers[i].probe (&supported_drivers[i].config)) + { #ifndef SHORT_BANNERS - printk ("snd%d", - supported_drivers[i].card_type); + printk ("snd%d", + supported_drivers[i].card_type); #endif - mem_start = supported_drivers[i].attach (mem_start, &supported_drivers[i].config); + mem_start = supported_drivers[i].attach (mem_start, &supported_drivers[i].config); #ifndef SHORT_BANNERS - printk (" at 0x%03x irq %d drq %d\n", - supported_drivers[i].config.io_base, - supported_drivers[i].config.irq, - supported_drivers[i].config.dma); + printk (" at 0x%x irq %d drq %d\n", + supported_drivers[i].config.io_base, + supported_drivers[i].config.irq, + supported_drivers[i].config.dma); #endif - } + } + else + supported_drivers[i].enabled = 0; /* Mark as not detected */ return mem_start; } @@ -66,7 +69,15 @@ sndtable_probe (int unit, struct address_info *hw_config) for (i = 0; i < (n - 1); i++) if (supported_drivers[i].card_type == unit) - return supported_drivers[i].probe (hw_config); + { + supported_drivers[i].config.io_base = hw_config->io_base; + supported_drivers[i].config.irq = hw_config->irq; + supported_drivers[i].config.dma = hw_config->dma; + if (supported_drivers[i].probe (hw_config)) + return 1; + supported_drivers[i].enabled = 0; /* Mark as not detected */ + return 0; + } return FALSE; } @@ -86,6 +97,10 @@ sndtable_init_card (int unit, struct address_info *hw_config) for (i = 0; i < (n - 1); i++) if (supported_drivers[i].card_type == unit) { + supported_drivers[i].config.io_base = hw_config->io_base; + supported_drivers[i].config.irq = hw_config->irq; + supported_drivers[i].config.dma = hw_config->dma; + if (supported_drivers[i].attach (0, hw_config) != 0) panic ("snd#: Invalid memory allocation\n"); return TRUE; @@ -100,4 +115,100 @@ sndtable_get_cardcount (void) return num_dspdevs + num_mixers + num_synths + num_midis; } +#ifdef linux +void +sound_setup (char *str, int *ints) +{ + int i, n = sizeof (supported_drivers) / sizeof (struct card_info); + +/* + * First disable all drivers + */ + + for (i = 0; i < n; i++) + supported_drivers[i].enabled = 0; + + if (ints[0] == 0 || ints[1] == 0) + return; +/* + * Then enable them one by time + */ + + for (i = 1; i <= ints[0]; i++) + { + int card_type, ioaddr, irq, dma, ptr, j; + unsigned int val; + + val = (unsigned int) ints[i]; + + card_type = (val & 0x0ff00000) >> 20; + + if (card_type > 127) + { + /* Add any future extensions here */ + return; + } + + ioaddr = (val & 0x000fff00) >> 8; + irq = (val & 0x000000f0) >> 4; + dma = (val & 0x0000000f); + + ptr = -1; + for (j = 0; j < n && ptr == -1; j++) + if (supported_drivers[j].card_type == card_type) + ptr = j; + + if (ptr == -1) + printk ("Sound: Invalid setup parameter 0x%08x\n", val); + else + { + supported_drivers[ptr].enabled = 1; + supported_drivers[ptr].config.io_base = ioaddr; + supported_drivers[ptr].config.irq = irq; + supported_drivers[ptr].config.dma = dma; + } + } +} +#else +void +sound_chconf (int card_type, int ioaddr, int irq, int dma) +{ + int i, n = sizeof (supported_drivers) / sizeof (struct card_info); + + int ptr, j; + + ptr = -1; + for (j = 0; j < n && ptr == -1; j++) + if (supported_drivers[j].card_type == card_type) + ptr = j; + + if (ptr != -1) + { + supported_drivers[ptr].enabled = 1; + if (ioaddr) + supported_drivers[ptr].config.io_base = ioaddr; + if (irq) + supported_drivers[ptr].config.irq = irq; + if (dma) + supported_drivers[ptr].config.dma = dma; + } +} +#endif + +struct address_info * +sound_getconf (int card_type) +{ + int j, ptr; + int n = sizeof (supported_drivers) / sizeof (struct card_info); + + ptr = -1; + for (j = 0; j < n && ptr == -1; j++) + if (supported_drivers[j].card_type == card_type) + ptr = j; + + if (ptr == -1) + return (struct address_info *) NULL; + + return &supported_drivers[ptr].config; +} #endif diff --git a/sys/i386/isa/sound/dev_table.h b/sys/i386/isa/sound/dev_table.h index 9bfd7847ecd2..d917a4650997 100644 --- a/sys/i386/isa/sound/dev_table.h +++ b/sys/i386/isa/sound/dev_table.h @@ -46,6 +46,7 @@ struct card_info { long (*attach) (long mem_start, struct address_info *hw_config); int (*probe) (struct address_info *hw_config); struct address_info config; + int enabled; }; /** UWM -- new MIDI structure here.. **/ @@ -59,8 +60,10 @@ struct audio_operations { char name[32]; int (*open) (int dev, int mode); void (*close) (int dev); - void (*output_block) (int dev, unsigned long buf, int count, int intrflag); - void (*start_input) (int dev, unsigned long buf, int count, int intrflag); + void (*output_block) (int dev, unsigned long buf, + int count, int intrflag, int dma_restart); + 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); int (*prepare_for_output) (int dev, int bufsize, int nbufs); @@ -159,31 +162,42 @@ struct generic_midi_operations { */ struct card_info supported_drivers[] = { -#ifndef EXCLUDE_MPU401 +#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI) {SNDCARD_MPU401,"Roland MPU-401", attach_mpu401, probe_mpu401, - {MPU_BASE, MPU_IRQ, 0}}, -#endif - -#ifndef EXCLUDE_GUS - {SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus, - {GUS_BASE, GUS_IRQ, GUS_DMA}}, + {MPU_BASE, MPU_IRQ, 0}, SND_DEFAULT_ENABLE}, #endif #ifndef EXCLUDE_PAS {SNDCARD_PAS, "ProAudioSpectrum", attach_pas_card, probe_pas, - {PAS_BASE, PAS_IRQ, PAS_DMA}}, + {PAS_BASE, PAS_IRQ, PAS_DMA}, SND_DEFAULT_ENABLE}, #endif #ifndef EXCLUDE_SB {SNDCARD_SB, "SoundBlaster", attach_sb_card, probe_sb, - {SBC_BASE, SBC_IRQ, SBC_DMA}}, + {SBC_BASE, SBC_IRQ, SBC_DMA}, SND_DEFAULT_ENABLE}, +#endif + +#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) +#ifndef EXCLUDE_AUDIO + {SNDCARD_SB16, "SoundBlaster16", sb16_dsp_init, sb16_dsp_detect, + {SBC_BASE, SBC_IRQ, SB16_DMA}, SND_DEFAULT_ENABLE}, +#endif +#ifndef EXCLUDE_MIDI + {SNDCARD_SB16MIDI,"SB16 MPU-401", attach_sb16midi, probe_sb16midi, + {SB16MIDI_BASE, SBC_IRQ, 0}, SND_DEFAULT_ENABLE}, +#endif +#endif + +#ifndef EXCLUDE_GUS + {SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus, + {GUS_BASE, GUS_IRQ, GUS_DMA}, SND_DEFAULT_ENABLE}, #endif #ifndef EXCLUDE_YM3812 {SNDCARD_ADLIB, "AdLib", attach_adlib_card, probe_adlib, - {FM_MONO, 0, 0}}, + {FM_MONO, 0, 0}, SND_DEFAULT_ENABLE}, #endif - {0, "*?*", NULL} + {0, "*?*", NULL, 0} }; int num_sound_drivers = @@ -220,6 +234,8 @@ struct generic_midi_operations { long sndtable_init(long mem_start); int sndtable_get_cardcount (void); long CMIDI_init(long mem_start); /* */ +struct address_info *sound_getconf(int card_type); +void sound_chconf(int card_type, int ioaddr, int irq, int dma); #endif #endif diff --git a/sys/i386/isa/sound/dmabuf.c b/sys/i386/isa/sound/dmabuf.c index ace02d149a41..35a3e019a05a 100644 --- a/sys/i386/isa/sound/dmabuf.c +++ b/sys/i386/isa/sound/dmabuf.c @@ -1,5 +1,5 @@ /* - * linux/kernel/chr_drv/sound/dmabuf.c + * sound/dmabuf.c * * The DMA buffer manager for digitized voice applications * @@ -35,7 +35,7 @@ #if !defined(EXCLUDE_AUDIO) || !defined(EXCLUDE_GUS) -#define MAX_SUB_BUFFERS 16 +#define MAX_SUB_BUFFERS (32*MAX_REALTIME_FACTOR) /* * The DSP channel can be used either for input or output. Variable @@ -48,7 +48,6 @@ #define DMODE_NONE 0 #define DMODE_OUTPUT 1 #define DMODE_INPUT 2 -#define DMODE_INIT 3 DEFINE_WAIT_QUEUES (dev_sleeper[MAX_DSP_DEV], dev_sleep_flag[MAX_DSP_DEV]); @@ -58,22 +57,6 @@ static int dma_mode[MAX_DSP_DEV] = static volatile int dmabuf_interrupted[MAX_DSP_DEV] = {0}; -#ifdef ISC -/* I don't like this. */ -#undef INTERRUPTIBLE_SLEEP_ON -#define INTERRUPTIBLE_SLEEP_ON(A,F) { \ - A = F = 1; \ - if (sleep(&(A), (PZERO + 5) | PCATCH)) { \ - A = F = 0; \ - dmabuf_interrupted[dev] = 1; \ - dev_busy[dev] = 0; \ - dma_reset(dev); \ - dmabuf_interrupted[dev] = 0; \ - /* longjmp(u.u_qsav, 1); Where it goes??? */ \ - } \ - } -#endif - /* * Pointers to raw buffers */ @@ -89,7 +72,10 @@ int snd_raw_count[MAX_DSP_DEV]; */ static int dev_busy[MAX_DSP_DEV]; +static int dev_needs_restart[MAX_DSP_DEV]; +static int dev_modes[MAX_DSP_DEV]; static int dev_active[MAX_DSP_DEV]; +static int dev_started[MAX_DSP_DEV]; static int dev_qlen[MAX_DSP_DEV]; static int dev_qhead[MAX_DSP_DEV]; static int dev_qtail[MAX_DSP_DEV]; @@ -101,9 +87,11 @@ static int bufferalloc_done[MAX_DSP_DEV] = * Logical buffers for each devices */ -static int dev_nbufs[MAX_DSP_DEV]; /* # of logical buffers ( >= - * sound_buffcounts[dev] */ +static int dev_nbufs[MAX_DSP_DEV]; /* # of logical buffers ( >= + + * sound_buffcounts[dev] */ static int dev_counts[MAX_DSP_DEV][MAX_SUB_BUFFERS]; +static int dev_subdivision[MAX_DSP_DEV]; static unsigned long dev_buf_phys[MAX_DSP_DEV][MAX_SUB_BUFFERS]; static char *dev_buf[MAX_DSP_DEV][MAX_SUB_BUFFERS] = { @@ -117,8 +105,8 @@ reorganize_buffers (int dev) * This routine breaks the physical device buffers to logical ones. */ - unsigned long i, p, n; - unsigned long sr, nc, sz, bsz; + unsigned i, p, n; + unsigned sr, nc, sz, bsz; sr = dsp_devs[dev]->ioctl (dev, SOUND_PCM_READ_RATE, 0, 1); nc = dsp_devs[dev]->ioctl (dev, SOUND_PCM_READ_CHANNELS, 0, 1); @@ -148,6 +136,17 @@ reorganize_buffers (int dev) if (sound_buffcounts[dev] == 1 && bsz == sound_buffsizes[dev]) bsz >>= 1; /* Need at least 2 buffers */ + if (dev_subdivision[dev] == 0) + dev_subdivision[dev] = 1; /* Default value */ + + bsz /= dev_subdivision[dev]; /* Use smaller buffers */ + + if (bsz == 0) + bsz = 4096; /* Just a sanity check */ + + while ((sound_buffsizes[dev] * sound_buffcounts[dev]) / bsz > MAX_SUB_BUFFERS) + bsz <<= 1; /* Too much buffers */ + dev_buffsize[dev] = bsz; n = 0; @@ -178,6 +177,21 @@ reorganize_buffers (int dev) bufferalloc_done[dev] = 1; } +static void +dma_init_buffers (int dev) +{ + RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]); + dev_underrun[dev] = 0; + + dev_busy[dev] = 1; + + bufferalloc_done[dev] = 0; + + dev_active[dev] = dev_qlen[dev] = dev_qtail[dev] = dev_qhead[dev] = 0; + dev_needs_restart[dev] = dev_started[dev] = 0; + dma_mode[dev] = DMODE_NONE; +} + int DMAbuf_open (int dev, int mode) { @@ -198,20 +212,23 @@ DMAbuf_open (int dev, int mode) return RET_ERROR (ENXIO); } +#ifdef USE_RUNTIME_DMAMEM + sound_dma_malloc (dev); +#endif + if (snd_raw_buf[dev][0] == NULL) return RET_ERROR (ENOSPC); /* Memory allocation failed during boot */ if ((retval = dsp_devs[dev]->open (dev, mode)) < 0) return retval; - dev_underrun[dev] = 0; + dev_modes[dev] = mode; + dev_subdivision[dev] = 0; - dev_busy[dev] = 1; - - reorganize_buffers (dev); - bufferalloc_done[dev] = 0; - - dev_qlen[dev] = dev_qtail[dev] = dev_qhead[dev] = 0; + dma_init_buffers (dev); + dsp_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_BITS, 8, 1); + dsp_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_CHANNELS, 1, 1); + dsp_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_RATE, DSP_DEFAULT_SPEED, 1); return 0; } @@ -219,12 +236,19 @@ DMAbuf_open (int dev, int mode) static void dma_reset (int dev) { - dsp_devs[dev]->reset (dev); + int retval; + unsigned long flags; - dev_qlen[dev] = 0; - dev_qhead[dev] = 0; - dev_qtail[dev] = 0; - dev_active[dev] = 0; + DISABLE_INTR (flags); + dsp_devs[dev]->reset (dev); + dsp_devs[dev]->close (dev); + + if ((retval = dsp_devs[dev]->open (dev, dev_modes[dev])) < 0) + printk ("Sound: Reset failed - Can't reopen device\n"); + RESTORE_INTR (flags); + + dma_init_buffers (dev); + reorganize_buffers (dev); } static int @@ -241,11 +265,11 @@ dma_sync (int dev) timed_out = 0; time = GET_TIME (); - while ((!(PROCESS_ABORTING || dmabuf_interrupted[dev]) && !timed_out) + while ((!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) || + dmabuf_interrupted[dev]) && !timed_out) && dev_qlen[dev]) { - REQUEST_TIMEOUT (10 * HZ, dev_sleeper[dev]); - INTERRUPTIBLE_SLEEP_ON (dev_sleeper[dev], dev_sleep_flag[dev]); + DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 10 * HZ); if ((GET_TIME () - time) > (10 * HZ)) timed_out = 1; } @@ -259,11 +283,11 @@ dma_sync (int dev) DISABLE_INTR (flags); if (dsp_devs[dev]->has_output_drained) /* Device has hidden buffers */ { - while (!(PROCESS_ABORTING || dmabuf_interrupted[dev]) + while (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) || + dmabuf_interrupted[dev]) && !dsp_devs[dev]->has_output_drained (dev)) { - REQUEST_TIMEOUT (HZ / 4, dev_sleeper[dev]); - INTERRUPTIBLE_SLEEP_ON (dev_sleeper[dev], dev_sleep_flag[dev]); + DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], HZ / 4); } } RESTORE_INTR (flags); @@ -275,16 +299,20 @@ int DMAbuf_release (int dev, int mode) { - if (!(PROCESS_ABORTING || dmabuf_interrupted[dev]) + if (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) || + dmabuf_interrupted[dev]) && (dma_mode[dev] == DMODE_OUTPUT)) { dma_sync (dev); } - dma_reset (dev); +#ifdef USE_RUNTIME_DMAMEM + sound_dma_free (dev); +#endif - if (!dev_active[dev]) - dsp_devs[dev]->close (dev); + dsp_devs[dev]->reset (dev); + + dsp_devs[dev]->close (dev); dma_mode[dev] = DMODE_NONE; dev_busy[dev] = 0; @@ -296,40 +324,65 @@ int DMAbuf_getrdbuffer (int dev, char **buf, int *len) { unsigned long flags; - - if (!bufferalloc_done[dev]) - reorganize_buffers (dev); - - if (!dma_mode[dev]) - { - int err; - - if ((err = dsp_devs[dev]->prepare_for_input (dev, - dev_buffsize[dev], dev_nbufs[dev])) < 0) - return err; - dma_mode[dev] = DMODE_INPUT; - } - - if (dma_mode[dev] != DMODE_INPUT) - return RET_ERROR (EBUSY); /* Can't change mode on fly */ + int err = EIO; DISABLE_INTR (flags); if (!dev_qlen[dev]) { + if (dev_needs_restart[dev]) + { + dma_reset (dev); + dev_needs_restart[dev] = 0; + } + + if (dma_mode[dev] == DMODE_OUTPUT) /* Was output -> direction change */ + { + dma_sync (dev); + dma_reset (dev); + dma_mode[dev] = DMODE_NONE; + } + + if (!bufferalloc_done[dev]) + reorganize_buffers (dev); + + if (!dma_mode[dev]) + { + int err; + + if ((err = dsp_devs[dev]->prepare_for_input (dev, + dev_buffsize[dev], dev_nbufs[dev])) < 0) + { + RESTORE_INTR (flags); + return err; + } + dma_mode[dev] = DMODE_INPUT; + } + if (!dev_active[dev]) { - dsp_devs[dev]->start_input (dev, dev_buf_phys[dev][dev_qtail[dev]], dev_buffsize[dev], 0); + dsp_devs[dev]->start_input (dev, dev_buf_phys[dev][dev_qtail[dev]], + dev_buffsize[dev], 0, + !sound_dma_automode[dev] || + !dev_started[dev]); dev_active[dev] = 1; + dev_started[dev] = 1; } /* Wait for the next block */ - REQUEST_TIMEOUT (10 * HZ, dev_sleeper[dev]); - INTERRUPTIBLE_SLEEP_ON (dev_sleeper[dev], dev_sleep_flag[dev]); + 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 + err = EINTR; } RESTORE_INTR (flags); if (!dev_qlen[dev]) - return RET_ERROR (EINTR); + return RET_ERROR (err); *buf = &dev_buf[dev][dev_qhead[dev]][dev_counts[dev][dev_qhead[dev]]]; *len = dev_buffsize[dev] - dev_counts[dev][dev_qhead[dev]]; @@ -391,6 +444,7 @@ DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) case SNDCTL_DSP_SYNC: dma_sync (dev); + dma_reset (dev); return 0; break; @@ -401,6 +455,32 @@ DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) return IOCTL_OUT (arg, dev_buffsize[dev]); break; + case SNDCTL_DSP_SUBDIVIDE: + { + int fact = IOCTL_IN (arg); + + if (fact == 0) + { + fact = dev_subdivision[dev]; + if (fact == 0) + fact = 1; + return IOCTL_OUT (arg, fact); + } + + if (dev_subdivision[dev] != 0) /* Too late to change */ + return RET_ERROR (EINVAL); + + if (fact > MAX_REALTIME_FACTOR) + return RET_ERROR (EINVAL); + + if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16) + return RET_ERROR (EINVAL); + + dev_subdivision[dev] = fact; + return IOCTL_OUT (arg, fact); + } + break; + default: return dsp_devs[dev]->ioctl (dev, cmd, arg, local); } @@ -412,6 +492,20 @@ int DMAbuf_getwrbuffer (int dev, char **buf, int *size) { unsigned long flags; + int err = EIO; + + if (dma_mode[dev] == DMODE_INPUT) /* Was input -> Direction change */ + { + dma_reset (dev); + dma_mode[dev] = DMODE_NONE; + } + else if (dev_needs_restart[dev]) /* Restart buffering */ + { + dma_sync (dev); + dma_reset (dev); + } + + dev_needs_restart[dev] = 0; if (!bufferalloc_done[dev]) reorganize_buffers (dev); @@ -426,10 +520,11 @@ DMAbuf_getwrbuffer (int dev, char **buf, int *size) return err; } - if (dma_mode[dev] != DMODE_OUTPUT) - return RET_ERROR (EBUSY); /* Can't change mode on fly */ DISABLE_INTR (flags); + + RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]); + if (dev_qlen[dev] == dev_nbufs[dev]) { if (!dev_active[dev]) @@ -440,14 +535,20 @@ DMAbuf_getwrbuffer (int dev, char **buf, int *size) } /* Wait for free space */ - REQUEST_TIMEOUT (60 * HZ, dev_sleeper[dev]); /* GUS requires up to 60 - * sec */ - INTERRUPTIBLE_SLEEP_ON (dev_sleeper[dev], dev_sleep_flag[dev]); + 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 if (PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev])) + err = EINTR; } RESTORE_INTR (flags); if (dev_qlen[dev] == dev_nbufs[dev]) - return RET_ERROR (EIO); /* We have got signal (?) */ + return RET_ERROR (err); /* We have got signal (?) */ *buf = dev_buf[dev][dev_qtail[dev]]; *size = dev_buffsize[dev]; @@ -466,12 +567,17 @@ DMAbuf_start_output (int dev, int buff_no, int l) dev_counts[dev][dev_qtail[dev]] = l; + dev_needs_restart[dev] = (l != dev_buffsize[dev]); + dev_qtail[dev] = (dev_qtail[dev] + 1) % dev_nbufs[dev]; if (!dev_active[dev]) { dev_active[dev] = 1; - dsp_devs[dev]->output_block (dev, dev_buf_phys[dev][dev_qhead[dev]], dev_counts[dev][dev_qhead[dev]], 0); + dsp_devs[dev]->output_block (dev, dev_buf_phys[dev][dev_qhead[dev]], + dev_counts[dev][dev_qhead[dev]], 0, + !sound_dma_automode[dev] || !dev_started[dev]); + dev_started[dev] = 1; } return 0; @@ -500,9 +606,9 @@ DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode) disable_dma (chan); clear_dma_ff (chan); set_dma_mode (chan, dma_mode | DMA_AUTOINIT); - set_dma_addr (chan, snd_raw_buf_phys[dev][0]); - set_dma_count (chan, sound_buffsizes[dev]); - enable_dma (chan); + set_dma_addr (chan, (caddr_t)snd_raw_buf_phys[dev][0]); + set_dma_count (chan, (unsigned)sound_buffsizes[dev]); + enable_dma ((unsigned)chan); RESTORE_INTR (flags); #else @@ -511,16 +617,22 @@ DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode) isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE, (caddr_t)snd_raw_buf_phys[dev][0], - (unsigned)sound_buffsizes[dev], - (unsigned)chan); + sound_buffsizes[dev], + chan); #else -#ifdef ISC +#if defined(ISC) || defined(SCO) +#ifndef DMAMODE_AUTO printk ("sound: Invalid DMA mode for device %d\n", dev); - dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode) | DMAMODE_AUTO, - snd_raw_buf_phys[dev][0], count - 1); +#endif + dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode) +#ifdef DMAMODE_AUTO + | DMAMODE_AUTO +#endif + , + snd_raw_buf_phys[dev][0], count); dma_enable (chan); #else -# error This routine is not valid for this OS. +#error This routine is not valid for this OS. #endif #endif @@ -545,12 +657,12 @@ DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode) chan); #else -#ifdef ISC +#if defined(ISC) || defined(SCO) dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode), - physaddr, count - 1); + physaddr, count); dma_enable (chan); #else -# error This routine is not valid for this OS. +#error This routine is not valid for this OS. #endif /* !ISC */ #endif @@ -584,37 +696,32 @@ DMAbuf_init (long mem_start) } void -DMAbuf_outputintr (int dev) +DMAbuf_outputintr (int dev, int underrun_flag) { unsigned long flags; - dev_active[dev] = 0; dev_qlen[dev]--; dev_qhead[dev] = (dev_qhead[dev] + 1) % dev_nbufs[dev]; + dev_active[dev] = 0; if (dev_qlen[dev]) { - dsp_devs[dev]->output_block (dev, dev_buf_phys[dev][dev_qhead[dev]], dev_counts[dev][dev_qhead[dev]], 1); + dsp_devs[dev]->output_block (dev, dev_buf_phys[dev][dev_qhead[dev]], + dev_counts[dev][dev_qhead[dev]], 1, + !sound_dma_automode[dev]); dev_active[dev] = 1; } - else + else if (underrun_flag) { - if (dev_busy[dev]) - { - dev_underrun[dev]++; - dsp_devs[dev]->halt_xfer (dev); - } - else - { /* Device has been closed */ - dsp_devs[dev]->close (dev); - } + dev_underrun[dev]++; + dsp_devs[dev]->halt_xfer (dev); + dev_needs_restart[dev] = 1; } DISABLE_INTR (flags); - if (dev_sleep_flag[dev]) + if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev])) { - dev_sleep_flag[dev] = 0; - WAKE_UP (dev_sleeper[dev]); + WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]); } RESTORE_INTR (flags); } @@ -624,30 +731,33 @@ DMAbuf_inputintr (int dev) { unsigned long flags; - dev_active[dev] = 0; if (!dev_busy[dev]) { dsp_devs[dev]->close (dev); } else if (dev_qlen[dev] == (dev_nbufs[dev] - 1)) { + printk ("Sound: Recording overrun\n"); dev_underrun[dev]++; dsp_devs[dev]->halt_xfer (dev); + dev_active[dev] = 0; + dev_needs_restart[dev] = 1; } else { dev_qlen[dev]++; dev_qtail[dev] = (dev_qtail[dev] + 1) % dev_nbufs[dev]; - dsp_devs[dev]->start_input (dev, dev_buf_phys[dev][dev_qtail[dev]], dev_buffsize[dev], 1); + dsp_devs[dev]->start_input (dev, dev_buf_phys[dev][dev_qtail[dev]], + dev_buffsize[dev], 1, + !sound_dma_automode[dev]); dev_active[dev] = 1; } DISABLE_INTR (flags); - if (dev_sleep_flag[dev]) + if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev])) { - dev_sleep_flag[dev] = 0; - WAKE_UP (dev_sleeper[dev]); + WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]); } RESTORE_INTR (flags); } @@ -697,7 +807,7 @@ DMAbuf_reset_dma (int chan) */ #else -/* Stub versions if audio services not included */ +/* Stub versions if audio services not included */ int DMAbuf_open (int dev, int mode) @@ -784,7 +894,7 @@ DMAbuf_inputintr (int dev) } void -DMAbuf_outputintr (int dev) +DMAbuf_outputintr (int dev, int underrun_flag) { return; } diff --git a/sys/i386/isa/sound/gus_card.c b/sys/i386/isa/sound/gus_card.c index 414034deef6f..29cc3d59243d 100644 --- a/sys/i386/isa/sound/gus_card.c +++ b/sys/i386/isa/sound/gus_card.c @@ -1,5 +1,5 @@ /* - * linux/kernel/chr_drv/sound/gus_card.c + * sound/gus_card.c * * Detection routine for the Gravis Ultrasound. * @@ -37,76 +37,12 @@ void gusintr (int); int gus_base, gus_irq, gus_dma; -static int -set_gus_irq (int interrupt_level) -{ - int retcode = EINVAL; - -#ifdef linux - struct sigaction sa; - - sa.sa_handler = gusintr; - -#ifdef SND_SA_INTERRUPT - sa.sa_flags = SA_INTERRUPT; -#else - sa.sa_flags = 0; -#endif - - sa.sa_mask = 0; - sa.sa_restorer = NULL; - - retcode = irqaction (interrupt_level, &sa); - - if (retcode < 0) - { - printk ("GUS: IRQ%d already in use\n", interrupt_level); - } - -#else - /* # error Unimplemented for this OS */ -#endif - return retcode; -} - -int -gus_set_midi_irq (int interrupt_level) -{ - int retcode = EINVAL; - -#ifdef linux - struct sigaction sa; - - sa.sa_handler = gus_midi_interrupt; - -#ifdef SND_SA_INTERRUPT - sa.sa_flags = SA_INTERRUPT; -#else - sa.sa_flags = 0; -#endif - - sa.sa_mask = 0; - sa.sa_restorer = NULL; - - retcode = irqaction (interrupt_level, &sa); - - if (retcode < 0) - { - printk ("GUS: IRQ%d already in use\n", interrupt_level); - } - -#else - /* # error Unimplemented for this OS */ -#endif - return retcode; -} - long attach_gus_card (long mem_start, struct address_info *hw_config) { int io_addr; - set_gus_irq (hw_config->irq); + snd_set_irq_handler (hw_config->irq, gusintr); if (gus_wave_detect (hw_config->io_base)) /* Try first the default */ { @@ -127,7 +63,7 @@ attach_gus_card (long mem_start, struct address_info *hw_config) if (io_addr != hw_config->io_base) /* Already tested */ if (gus_wave_detect (io_addr)) { - printk (" WARNING! GUS found at %03x, config was %03x ", io_addr, hw_config->io_base); + 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); #ifndef EXCLUDE_MIDI mem_start = gus_midi_init (mem_start); @@ -168,7 +104,10 @@ void gusintr (int unit) { unsigned char src; - unsigned long flags; + +#ifdef linux + sti (); +#endif while (1) { @@ -195,9 +134,7 @@ gusintr (int unit) if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ)) { - DISABLE_INTR (flags); gus_voice_irq (); - RESTORE_INTR (flags); } } } diff --git a/sys/i386/isa/sound/gus_midi.c b/sys/i386/isa/sound/gus_midi.c index b5cd6844cd1d..5e06f7f239ee 100644 --- a/sys/i386/isa/sound/gus_midi.c +++ b/sys/i386/isa/sound/gus_midi.c @@ -1,5 +1,5 @@ /* - * linux/kernel/chr_drv/sound/gus2_midi.c + * sound/gus2_midi.c * * The low level driver for the GUS Midi Interface. * @@ -215,7 +215,7 @@ gus_midi_buffer_status (int dev) static struct midi_operations gus_midi_operations = { - {"Gravis UltraSound", 0}, + {"Gravis UltraSound", 0, 0, SNDCARD_GUS}, gus_midi_open, gus_midi_close, gus_midi_ioctl, diff --git a/sys/i386/isa/sound/gus_vol.c b/sys/i386/isa/sound/gus_vol.c index b3f1e84060ad..6e56d546cea5 100644 --- a/sys/i386/isa/sound/gus_vol.c +++ b/sys/i386/isa/sound/gus_vol.c @@ -1,4 +1,4 @@ -/* +/* * gus_vol.c - Compute volume for GUS. * * Greg Lee 1993. @@ -11,7 +11,7 @@ extern int gus_wave_volume; -/* +/* * Calculate gus volume from note velocity, main volume, expression, and * intrinsic patch volume given in patch library. Expression is multiplied * in, so it emphasizes differences in note velocity, while main volume is @@ -31,35 +31,48 @@ gus_adagio_vol (int vel, int mainv, int xpn, int voicev) int i, m, n, x; - /* + /* * A voice volume of 64 is considered neutral, so adjust the main volume if * something other than this neutral value was assigned in the patch * library. */ x = 256 + 6 * (voicev - 64); - /* Boost expression by voice volume above neutral. */ + /* + * Boost expression by voice volume above neutral. + */ if (voicev > 65) xpn += voicev - 64; xpn += (voicev - 64) / 2; - /* Combine multiplicative and level components. */ + /* + * Combine multiplicative and level components. + */ x = vel * xpn * 6 + (voicev / 4) * x; #ifdef GUS_VOLUME - /* + /* * Further adjustment by installation-specific master volume control - * (default 50). + * (default 60). */ x = (x * GUS_VOLUME * GUS_VOLUME) / 10000; #endif - if (x < (1 << 11)) - return (11 << 8); +#ifdef GUS_USE_CHN_MAIN_VOLUME + /* + * Experimental support for the channel main volume + */ + + mainv = (mainv / 2) + 64; /* Scale to 64 to 127 */ + x = (x * mainv * mainv) / 16384; +#endif + + if (x < 2) + return (0); else if (x >= 65535) return ((15 << 8) | 255); - /* + /* * Convert to gus's logarithmic form with 4 bit exponent i and 8 bit * mantissa m. */ @@ -76,13 +89,15 @@ gus_adagio_vol (int vel, int mainv, int xpn, int voicev) n >>= 1; i++; } - /* + /* * Mantissa is part of linear volume not expressed in exponent. (This is * not quite like real logs -- I wonder if it's right.) */ m = x - (1 << i); - /* Adjust mantissa to 8 bits. */ + /* + * Adjust mantissa to 8 bits. + */ if (m > 0) { if (i > 8) @@ -91,10 +106,6 @@ gus_adagio_vol (int vel, int mainv, int xpn, int voicev) m <<= 8 - i; } - /* low volumes give occasional sour notes */ - if (i < 11) - return (11 << 8); - return ((i << 8) + m); } diff --git a/sys/i386/isa/sound/gus_wave.c b/sys/i386/isa/sound/gus_wave.c index deb3a1525991..7c625e279d40 100644 --- a/sys/i386/isa/sound/gus_wave.c +++ b/sys/i386/isa/sound/gus_wave.c @@ -1,6 +1,6 @@ -/* - * linux/kernel/chr_drv/sound/gus_wave.c +/* + * sound/gus_wave.c * * Driver for the Gravis UltraSound wave table synth. * @@ -28,15 +28,19 @@ * */ -/* #define GUS_LINEAR_VOLUME */ - #include "sound_config.h" +#ifdef linux +#include +#elif __FreeBSD__ #include +#else +#include "ultrasound.h" +#endif #include "gus_hw.h" #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS) -#define MAX_SAMPLE 256 +#define MAX_SAMPLE 128 #define MAX_PATCH 256 struct voice_info @@ -57,16 +61,22 @@ struct voice_info int volume_irq_mode, volume_irq_parm; #define VMODE_HALT 1 #define VMODE_ENVELOPE 2 +#define VMODE_START_NOTE 3 int env_phase; unsigned char env_rate[6]; unsigned char env_offset[6]; - /* + /* * Volume computation parameters for gus_adagio_vol() */ int main_vol, expression_vol, patch_vol; + /* Variables for "Ultraclick" removal */ + int dev_pending, note_pending, volume_pending, sample_pending; + char kill_pending; + long offset_pending; + }; extern int gus_base; @@ -77,24 +87,31 @@ extern int snd_raw_count[MAX_DSP_DEV]; static long gus_mem_size = 0; static long free_mem_ptr = 0; static int gus_busy = 0; -static int nr_voices = 0; /* Number of currently allowed voices */ +static int nr_voices = 0; static int gus_devnum = 0; static int volume_base, volume_scale, volume_method; +static int gus_line_vol = 100, gus_mic_vol = 0; +static int gus_recmask = SOUND_MASK_MIC; +static int recording_active = 0; #define VOL_METHOD_ADAGIO 1 -int gus_wave_volume = 60; /* Master wolume for wave (0 to 100) */ +int gus_wave_volume = 60; +int gus_pcm_volume = 80; static unsigned char mix_image = 0x00; -/* - * Current version of this_one driver doesn't allow synth and PCM functions +/* + * Current version of this driver doesn't allow synth and PCM functions * at the same time. The active_device specifies the active driver */ static int active_device = 0; -#define GUS_DEV_WAVE 1 /* Wave table synth */ -#define GUS_DEV_PCM_DONE 2 /* PCM device, transfer done */ -#define GUS_DEV_PCM_CONTINUE 3 /* PCM device, transfer the second - * chn */ +#define GUS_DEV_WAVE 1 /* + * * * Wave table synth */ +#define GUS_DEV_PCM_DONE 2 /* + * * * PCM device, transfer done */ +#define GUS_DEV_PCM_CONTINUE 3 /* + * * * PCM device, transfer the + * second * * * chn */ static int gus_sampling_speed; static int gus_sampling_channels; @@ -102,16 +119,37 @@ static int gus_sampling_bits; DEFINE_WAIT_QUEUE (dram_sleeper, dram_sleep_flag); -/* +/* * Variables and buffers for PCM output */ -#define MAX_PCM_BUFFERS 32 /* Don't change */ -static int pcm_bsize, /* Current blocksize */ - pcm_nblk, /* Current # of blocks */ - pcm_banksize; /* # bytes allocated for channels */ -static int pcm_datasize[MAX_PCM_BUFFERS]; /* Actual # of bytes in blk */ -static volatile int pcm_head, pcm_tail, pcm_qlen; /* DRAM queue */ +#define MAX_PCM_BUFFERS (32*MAX_REALTIME_FACTOR) /* + * * * Don't + * * * change + * + */ + +static int pcm_bsize, /* + * Current blocksize + */ + pcm_nblk, /* + * Current # of blocks + */ + pcm_banksize; /* + + + * * * * # bytes allocated for channels */ +static int pcm_datasize[MAX_PCM_BUFFERS]; /* + + + * * * * Actual # of bytes + * in blk * */ +static volatile int pcm_head, pcm_tail, pcm_qlen; /* + + + * * * * DRAM queue + * */ static volatile int pcm_active; +static int pcm_opened = 0; static int pcm_current_dev; static int pcm_current_block; static unsigned long pcm_current_buf; @@ -122,28 +160,66 @@ struct voice_info voices[32]; static int freq_div_table[] = { - 44100, /* 14 */ - 41160, /* 15 */ - 38587, /* 16 */ - 36317, /* 17 */ - 34300, /* 18 */ - 32494, /* 19 */ - 30870, /* 20 */ - 29400, /* 21 */ - 28063, /* 22 */ - 26843, /* 23 */ - 25725, /* 24 */ - 24696, /* 25 */ - 23746, /* 26 */ - 22866, /* 27 */ - 22050, /* 28 */ - 21289, /* 29 */ - 20580, /* 30 */ - 19916, /* 31 */ - 19293 /* 32 */ + 44100, /* + * 14 + */ + 41160, /* + * 15 + */ + 38587, /* + * 16 + */ + 36317, /* + * 17 + */ + 34300, /* + * 18 + */ + 32494, /* + * 19 + */ + 30870, /* + * 20 + */ + 29400, /* + * 21 + */ + 28063, /* + * 22 + */ + 26843, /* + * 23 + */ + 25725, /* + * 24 + */ + 24696, /* + * 25 + */ + 23746, /* + * 26 + */ + 22866, /* + * 27 + */ + 22050, /* + * 28 + */ + 21289, /* + * 29 + */ + 20580, /* + * 30 + */ + 19916, /* + * 31 + */ + 19293 /* + * 32 + */ }; -static struct patch_info samples[MAX_SAMPLE + 1]; +static struct patch_info *samples; static long sample_ptrs[MAX_SAMPLE + 1]; static int sample_map[32]; static int free_sample; @@ -159,9 +235,13 @@ static void gus_poke (long addr, unsigned char data); static void compute_and_set_volume (int voice, int volume, int ramp_time); extern unsigned short gus_adagio_vol (int vel, int mainv, int xpn, int voicev); static void compute_volume (int voice, int volume); +static void do_volume_irq (int voice); +static void set_input_volumes (void); -#define INSTANT_RAMP -1 /* Dont use ramping */ -#define FAST_RAMP 0 /* Fastest possible ramp */ +#define INSTANT_RAMP -1 /* + * * * Dont use ramping */ +#define FAST_RAMP 0 /* + * * * Fastest possible ramp */ static void reset_sample_memory (void) @@ -175,7 +255,9 @@ reset_sample_memory (void) for (i = 0; i < 32; i++) patch_map[i] = -1; - gus_poke (0, 0); /* Put silence here */ + gus_poke (0, 0); /* + * Put silence here + */ gus_poke (1, 0); free_mem_ptr = 2; @@ -230,14 +312,14 @@ gus_peek (long addr) } void -gus_write8 (int reg, unsigned char data) +gus_write8 (int reg, unsigned int data) { unsigned long flags; DISABLE_INTR (flags); OUTB (reg, u_Command); - OUTB (data, u_DataHi); + OUTB ((unsigned char) (data & 0xff), u_DataHi); RESTORE_INTR (flags); } @@ -271,7 +353,7 @@ gus_look8 (int reg) } void -gus_write16 (int reg, unsigned short data) +gus_write16 (int reg, unsigned int data) { unsigned long flags; @@ -279,8 +361,8 @@ gus_write16 (int reg, unsigned short data) OUTB (reg, u_Command); - OUTB (data & 0xff, u_DataLo); - OUTB ((data >> 8) & 0xff, u_DataHi); + OUTB ((unsigned char) (data & 0xff), u_DataLo); + OUTB ((unsigned char) ((data >> 8) & 0xff), u_DataHi); RESTORE_INTR (flags); } @@ -310,7 +392,7 @@ gus_write_addr (int reg, unsigned long address, int is16bit) if (is16bit) { - /* + /* * Special processing required for 16 bit patches */ @@ -347,11 +429,11 @@ gus_select_max_voices (int nvoices) } static void -gus_voice_on (unsigned char mode) +gus_voice_on (unsigned int mode) { - gus_write8 (0x00, mode & 0xfc); + gus_write8 (0x00, (unsigned char) (mode & 0xfc)); gus_delay (); - gus_write8 (0x00, mode & 0xfc); + gus_write8 (0x00, (unsigned char) (mode & 0xfc)); } static void @@ -361,10 +443,18 @@ gus_voice_off (void) } static void -gus_voice_mode (unsigned char mode) +gus_voice_mode (unsigned int m) { - gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc)); /* Don't start or stop - * voice */ + unsigned char mode = (unsigned char) (m & 0xff); + + gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc)); /* + * Don't + * start + * or + * stop + * * + * voice + */ gus_delay (); gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc)); } @@ -382,44 +472,56 @@ gus_voice_freq (unsigned long freq) } static void -gus_voice_volume (unsigned short vol) +gus_voice_volume (unsigned int vol) { - gus_write8 (0x0d, 0x03); /* Stop ramp before setting volume */ - gus_write16 (0x09, vol << 4); + gus_write8 (0x0d, 0x03); /* + * Stop ramp before setting volume + */ + gus_write16 (0x09, (unsigned short) (vol << 4)); } static void -gus_voice_balance (unsigned char balance) +gus_voice_balance (unsigned int balance) { - gus_write8 (0x0c, balance); + gus_write8 (0x0c, (unsigned char) (balance & 0xff)); } static void -gus_ramp_range (unsigned short low, unsigned short high) +gus_ramp_range (unsigned int low, unsigned int high) { - gus_write8 (0x07, (low >> 4) & 0xff); - gus_write8 (0x08, (high >> 4) & 0xff); + gus_write8 (0x07, (unsigned char) ((low >> 4) & 0xff)); + gus_write8 (0x08, (unsigned char) ((high >> 4) & 0xff)); } static void -gus_ramp_rate (unsigned char scale, unsigned char rate) +gus_ramp_rate (unsigned int scale, unsigned int rate) { - gus_write8 (0x06, ((scale & 0x03) << 6) | (rate & 0x3f)); + gus_write8 (0x06, (unsigned char) (((scale & 0x03) << 6) | (rate & 0x3f))); } static void -gus_rampon (unsigned char mode) +gus_rampon (unsigned int m) { + unsigned char mode = (unsigned char) (m & 0xff); + gus_write8 (0x0d, mode & 0xfc); gus_delay (); gus_write8 (0x0d, mode & 0xfc); } static void -gus_ramp_mode (unsigned char mode) +gus_ramp_mode (unsigned int m) { - gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc)); /* Don't start or stop - * ramping */ + unsigned char mode = (unsigned char) (m & 0xff); + + gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc)); /* + * Don't + * start + * or + * stop + * * + * ramping + */ gus_delay (); gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc)); } @@ -430,6 +532,20 @@ gus_rampoff (void) gus_write8 (0x0d, 0x03); } +static void +gus_set_voice_pos (int voice, long position) +{ + int sample_no; + + if ((sample_no = sample_map[voice]) != -1) + if (position < samples[sample_no].len) + if (voices[voice].volume_irq_mode == VMODE_START_NOTE) + voices[voice].offset_pending = position; + else + gus_write_addr (0x0a, sample_ptrs[sample_no] + position, + samples[sample_no].mode & WAVE_16_BITS); +} + static void gus_voice_init (int voice) { @@ -438,11 +554,22 @@ gus_voice_init (int voice) DISABLE_INTR (flags); gus_select_voice (voice); gus_voice_volume (0); - gus_write_addr (0x0a, 0, 0); /* Set current position to 0 */ - gus_write8 (0x00, 0x03); /* Voice off */ - gus_write8 (0x0d, 0x03); /* Ramping off */ + gus_write_addr (0x0a, 0, 0); /* + * Set current position to 0 + */ + gus_write8 (0x00, 0x03); /* + * Voice off + */ + gus_write8 (0x0d, 0x03); /* + * Ramping off + */ RESTORE_INTR (flags); +} + +static void +gus_voice_init2 (int voice) +{ voices[voice].panning = 0; voices[voice].mode = 0; voices[voice].orig_freq = 20000; @@ -459,6 +586,7 @@ gus_voice_init (int voice) voices[voice].main_vol = 127; voices[voice].patch_vol = 127; voices[voice].expression_vol = 127; + voices[voice].sample_pending = -1; } static void @@ -470,12 +598,14 @@ step_envelope (int voice) if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2) { gus_rampoff (); - return; /* Sustain */ + return; /* + * Sustain + */ } if (voices[voice].env_phase >= 5) { - /* + /* * Shoot the voice off */ @@ -491,13 +621,19 @@ step_envelope (int voice) vol = voices[voice].initial_volume * voices[voice].env_offset[phase] / 255; rate = voices[voice].env_rate[phase]; - gus_write8 (0x06, rate); /* Ramping rate */ + gus_write8 (0x06, rate); /* + * Ramping rate + */ voices[voice].volume_irq_mode = VMODE_ENVELOPE; - if (((vol - prev_vol) / 64) == 0) /* No significant volume change */ + if (((vol - prev_vol) / 64) == 0) /* + * No significant volume change + */ { - step_envelope (voice); /* Continue with the next phase */ + step_envelope (voice); /* + * Continue with the next phase + */ return; } @@ -506,14 +642,18 @@ step_envelope (int voice) if (vol >= (4096 - 64)) vol = 4096 - 65; gus_ramp_range (0, vol); - gus_rampon (0x20); /* Increasing, irq */ + gus_rampon (0x20); /* + * Increasing, irq + */ } else { if (vol <= 64) vol = 65; - gus_ramp_range (vol, 4095); - gus_rampon (0x60); /* Decreasing, irq */ + gus_ramp_range (vol, 4030); + gus_rampon (0x60); /* + * Decreasing, irq + */ } voices[voice].current_volume = vol; } @@ -531,13 +671,19 @@ static void start_release (int voice) { if (gus_read8 (0x00) & 0x03) - return; /* Voice already stopped */ + return; /* + * Voice already stopped + */ - voices[voice].env_phase = 2; /* Will be incremented by step_envelope */ + voices[voice].env_phase = 2; /* + * Will be incremented by step_envelope + */ voices[voice].current_volume = voices[voice].initial_volume = - gus_read16 (0x09) >> 4; /* Get current volume */ + gus_read16 (0x09) >> 4; /* + * Get current volume + */ voices[voice].mode &= ~WAVE_SUSTAIN_ON; gus_rampoff (); @@ -551,11 +697,17 @@ gus_voice_fade (int voice) if (instr_no < 0 || instr_no > MAX_SAMPLE) { - gus_write8 (0x00, 0x03); /* Hard stop */ + gus_write8 (0x00, 0x03); /* + * Hard stop + */ return; } - is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /* 8 or 16 bit samples */ + is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /* + * 8 or 16 + * bit + * samples + */ if (voices[voice].mode & WAVE_ENVELOPES) { @@ -563,10 +715,12 @@ gus_voice_fade (int voice) return; } - /* + /* * Ramp the volume down but not too quickly. */ - if ((gus_read16 (0x09) >> 4) < 100) /* Get current volume */ + if ((gus_read16 (0x09) >> 4) < 100) /* + * Get current volume + */ { gus_voice_off (); gus_rampoff (); @@ -574,9 +728,11 @@ gus_voice_fade (int voice) return; } - gus_ramp_range (65, 4095); + gus_ramp_range (65, 4030); gus_ramp_rate (2, 4); - gus_rampon (0x40 | 0x20); /* Down, once, irq */ + gus_rampon (0x40 | 0x20); /* + * Down, once, irq + */ voices[voice].volume_irq_mode = VMODE_HALT; } @@ -592,14 +748,25 @@ gus_reset (void) for (i = 0; i < 32; i++) { - gus_voice_init (i); /* Turn voice off */ + gus_voice_init (i); /* + * Turn voice off + */ + gus_voice_init2 (i); } - INB (u_Status); /* Touch the status register */ + INB (u_Status); /* + * Touch the status register + */ - gus_look8 (0x41); /* Clear any pending DMA IRQs */ - gus_look8 (0x49); /* Clear any pending sample IRQs */ - gus_read8 (0x0f); /* Clear pending IRQs */ + gus_look8 (0x41); /* + * Clear any pending DMA IRQs + */ + gus_look8 (0x49); /* + * Clear any pending sample IRQs + */ + gus_read8 (0x0f); /* + * Clear pending IRQs + */ } @@ -617,59 +784,86 @@ gus_initialize (void) DISABLE_INTR (flags); - gus_write8 (0x4c, 0); /* Reset GF1 */ + gus_write8 (0x4c, 0); /* + * Reset GF1 + */ gus_delay (); gus_delay (); - gus_write8 (0x4c, 1); /* Release Reset */ + gus_write8 (0x4c, 1); /* + * Release Reset + */ gus_delay (); gus_delay (); - /* + /* * Clear all interrupts */ - gus_write8 (0x41, 0); /* DMA control */ - gus_write8 (0x45, 0); /* Timer control */ - gus_write8 (0x49, 0); /* Sample control */ + gus_write8 (0x41, 0); /* + * DMA control + */ + gus_write8 (0x45, 0); /* + * Timer control + */ + gus_write8 (0x49, 0); /* + * Sample control + */ gus_select_max_voices (24); - INB (u_Status); /* Touch the status register */ + INB (u_Status); /* + * Touch the status register + */ - gus_look8 (0x41); /* Clear any pending DMA IRQs */ - gus_look8 (0x49); /* Clear any pending sample IRQs */ - gus_read8 (0x0f); /* Clear pending IRQs */ + gus_look8 (0x41); /* + * Clear any pending DMA IRQs + */ + gus_look8 (0x49); /* + * Clear any pending sample IRQs + */ + gus_read8 (0x0f); /* + * Clear pending IRQs + */ - gus_reset (); /* Resets all voices */ + gus_reset (); /* + * Resets all voices + */ - gus_look8 (0x41); /* Clear any pending DMA IRQs */ - gus_look8 (0x49); /* Clear any pending sample IRQs */ - gus_read8 (0x0f); /* Clear pending IRQs */ + gus_look8 (0x41); /* + * Clear any pending DMA IRQs + */ + gus_look8 (0x49); /* + * Clear any pending sample IRQs + */ + gus_read8 (0x0f); /* + * Clear pending IRQs + */ - gus_write8 (0x4c, 7); /* Master reset | DAC enable | IRQ enable */ + gus_write8 (0x4c, 7); /* + * Master reset | DAC enable | IRQ enable + */ - /* + /* * Set up for Digital ASIC */ OUTB (0x05, gus_base + 0x0f); - mix_image |= 0x02; /* Disable line out */ + mix_image |= 0x02; /* + * Disable line out + */ OUTB (mix_image, u_Mixer); OUTB (0x00, u_IRQDMAControl); OUTB (0x00, gus_base + 0x0f); - /* + /* * Now set up the DMA and IRQ interface * * The GUS supports two IRQs and two DMAs. * - * If GUS_MIDI_IRQ is defined and if it's != GUS_IRQ, separate Midi IRQ is set - * up. Otherwise the same IRQ is shared by the both devices. - * * Just one DMA channel is used. This prevents simultaneous ADC and DAC. * Adding this support requires significant changes to the dmabuf.c, dsp.c * and audio.c also. @@ -680,63 +874,89 @@ gus_initialize (void) if (!tmp) printk ("Warning! GUS IRQ not selected\n"); irq_image |= tmp; + irq_image |= 0x40; /* + * Combine IRQ1 (GF1) and IRQ2 (Midi) + */ - if (GUS_MIDI_IRQ != gus_irq) - { /* The midi irq was defined and != wave irq */ - tmp = gus_irq_map[GUS_MIDI_IRQ]; - tmp <<= 3; - - if (!tmp) - printk ("Warning! GUS Midi IRQ not selected\n"); - else - gus_set_midi_irq (GUS_MIDI_IRQ); - - irq_image |= tmp; - } - else - irq_image |= 0x40; /* Combine IRQ1 (GF1) and IRQ2 (Midi) */ - - dma_image = 0x40; /* Combine DMA1 (DRAM) and IRQ2 (ADC) */ + dma_image = 0x40; /* + * Combine DMA1 (DRAM) and IRQ2 (ADC) + */ tmp = gus_dma_map[gus_dma]; if (!tmp) printk ("Warning! GUS DMA not selected\n"); dma_image |= tmp; - /* + /* * For some reason the IRQ and DMA addresses must be written twice */ - /* Doing it first time */ + /* + * Doing it first time + */ - OUTB (mix_image, u_Mixer); /* Select DMA control */ - OUTB (dma_image, u_IRQDMAControl); /* Set DMA address */ + OUTB (mix_image, u_Mixer); /* + * Select DMA control + */ + OUTB (dma_image | 0x80, u_IRQDMAControl); /* + * Set DMA address + */ - OUTB (mix_image | 0x40, u_Mixer); /* Select IRQ control */ - OUTB (irq_image, u_IRQDMAControl); /* Set IRQ address */ + OUTB (mix_image | 0x40, u_Mixer); /* + * Select IRQ control + */ + OUTB (irq_image, u_IRQDMAControl); /* + * Set IRQ address + */ - /* Doing it second time */ + /* + * Doing it second time + */ - OUTB (mix_image, u_Mixer); /* Select DMA control */ - OUTB (dma_image, u_IRQDMAControl); /* Set DMA address */ + OUTB (mix_image, u_Mixer); /* + * Select DMA control + */ + OUTB (dma_image, u_IRQDMAControl); /* + * Set DMA address + */ - OUTB (mix_image | 0x40, u_Mixer); /* Select IRQ control */ - OUTB (irq_image, u_IRQDMAControl); /* Set IRQ address */ + OUTB (mix_image | 0x40, u_Mixer); /* + * Select IRQ control + */ + OUTB (irq_image, u_IRQDMAControl); /* + * Set IRQ address + */ - gus_select_voice (0); /* This disables writes to IRQ/DMA reg */ + gus_select_voice (0); /* + * This disables writes to IRQ/DMA reg + */ - mix_image &= ~0x02; /* Enable line out */ - mix_image |= 0x08; /* Enable IRQ */ - OUTB (mix_image, u_Mixer); /* Turn mixer channels on */ + mix_image &= ~0x02; /* + * Enable line out + */ + mix_image |= 0x08; /* + * Enable IRQ + */ + OUTB (mix_image, u_Mixer); /* + * Turn mixer channels on + * Note! Mic in is left off. + */ - gus_select_voice (0); /* This disables writes to IRQ/DMA reg */ + gus_select_voice (0); /* + * This disables writes to IRQ/DMA reg + */ - gusintr (0); /* Serve pending interrupts */ + gusintr (0); /* + * Serve pending interrupts + */ RESTORE_INTR (flags); } int gus_wave_detect (int baseaddr) { + unsigned long i; + unsigned long loc; + gus_base = baseaddr; gus_write8 (0x4c, 0); /* Reset GF1 */ @@ -747,31 +967,37 @@ gus_wave_detect (int baseaddr) gus_delay (); gus_delay (); - gus_poke (0x000, 0xaa); - gus_poke (0x100, 0x55); + /* See if there is first block there.... */ + gus_poke (0L, 0xaa); + if (gus_peek (0L) != 0xaa) + return (0); - if (gus_peek (0x000) != 0xaa) - return 0; - if (gus_peek (0x100) != 0x55) - return 0; + /* Now zero it out so that I can check for mirroring .. */ + gus_poke (0L, 0x00); + for (i = 1L; i < 1024L; i++) + { + int n, failed; - gus_mem_size = 0x40000; /* 256k */ - gus_poke (0x40000, 0xaa); - if (gus_peek (0x40000) != 0xaa) - return 1; + /* check for mirroring ... */ + if (gus_peek (0L) != 0) + break; + loc = i << 10; - gus_mem_size = 0x80000; /* 512k */ - gus_poke (0x80000, 0xaa); - if (gus_peek (0x80000) != 0xaa) - return 1; + for (n = loc - 1, failed = 0; n <= loc; n++) + { + gus_poke (loc, 0xaa); + if (gus_peek (loc) != 0xaa) + failed = 1; - gus_mem_size = 0xc0000; /* 768k */ - gus_poke (0xc0000, 0xaa); - if (gus_peek (0xc0000) != 0xaa) - return 1; - - gus_mem_size = 0x100000; /* 1M */ + gus_poke (loc, 0x55); + if (gus_peek (loc) != 0x55) + failed = 1; + } + if (failed) + break; + } + gus_mem_size = i << 10; return 1; } @@ -816,16 +1042,26 @@ guswave_set_instr (int dev, int voice, int instr_no) if (voice < 0 || voice > 31) return RET_ERROR (EINVAL); + if (voices[voice].volume_irq_mode == VMODE_START_NOTE) + { + voices[voice].sample_pending = instr_no; + return 0; + } + sample_no = patch_table[instr_no]; patch_map[voice] = -1; 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 */ + if (sample_ptrs[sample_no] == -1) /* + * Sample not loaded + */ { printk ("GUS: Sample #%d not loaded for patch %d (voice %d)\n", sample_no, instr_no, voice); return RET_ERROR (EINVAL); @@ -837,13 +1073,22 @@ guswave_set_instr (int dev, int voice, int instr_no) } static int +#ifdef FUTURE_VERSION +guswave_kill_note (int dev, int voice, int note, int velocity) +#else guswave_kill_note (int dev, int voice, int velocity) +#endif { unsigned long flags; DISABLE_INTR (flags); - gus_select_voice (voice); - gus_voice_fade (voice); + if (voices[voice].volume_irq_mode == VMODE_START_NOTE) + voices[voice].kill_pending = 1; + else + { + gus_select_voice (voice); + gus_voice_fade (voice); + } RESTORE_INTR (flags); return 0; @@ -855,20 +1100,26 @@ guswave_aftertouch (int dev, int voice, int pressure) short lo_limit, hi_limit; unsigned long flags; - return; /* Currently disabled */ + return; /* + * Currently disabled + */ if (voice < 0 || voice > 31) return; if (voices[voice].mode & WAVE_ENVELOPES && voices[voice].env_phase != 2) - return; /* Don't mix with envelopes */ + return; /* + * Don't mix with envelopes + */ if (pressure < 32) { DISABLE_INTR (flags); gus_select_voice (voice); gus_rampoff (); - compute_and_set_volume (voice, 255, 0); /* Back to original volume */ + compute_and_set_volume (voice, 255, 0); /* + * Back to original volume + */ RESTORE_INTR (flags); return; } @@ -887,7 +1138,9 @@ guswave_aftertouch (int dev, int voice, int pressure) } gus_ramp_range (lo_limit, hi_limit); gus_ramp_rate (3, 8); - gus_rampon (0x58); /* Bidirectional, Down, Loop */ + gus_rampon (0x58); /* + * Bidirectional, Down, Loop + */ RESTORE_INTR (flags); } @@ -902,31 +1155,38 @@ static void compute_volume (int voice, int volume) { if (volume < 128) + voices[voice].midi_volume = volume; + + switch (volume_method) { - voices[voice].midi_volume = volume; + case VOL_METHOD_ADAGIO: + voices[voice].initial_volume = + gus_adagio_vol (voices[voice].midi_volume, voices[voice].main_vol, + voices[voice].expression_vol, + voices[voice].patch_vol); + break; - switch (volume_method) - { - case VOL_METHOD_ADAGIO: - voices[voice].initial_volume = - gus_adagio_vol (volume, voices[voice].main_vol, - voices[voice].expression_vol, - voices[voice].patch_vol); - break; - - default: - voices[voice].initial_volume = volume_base + (volume * volume_scale); - } + default: + voices[voice].initial_volume = volume_base + + (voices[voice].midi_volume * volume_scale); } - if (voices[voice].initial_volume > 4095) - voices[voice].initial_volume = 4095; + if (voices[voice].initial_volume > 4030) + voices[voice].initial_volume = 4030; } static void compute_and_set_volume (int voice, int volume, int ramp_time) { int current, target, rate; + unsigned long flags; + + DISABLE_INTR (flags); +/* + * CAUTION! Interrupts disabled. Enable them before returning + */ + + gus_select_voice (voice); compute_volume (voice, volume); voices[voice].current_volume = voices[voice].initial_volume; @@ -938,6 +1198,7 @@ compute_and_set_volume (int voice, int volume, int ramp_time) { gus_rampoff (); gus_voice_volume (target); + RESTORE_INTR (flags); return; } @@ -947,10 +1208,13 @@ compute_and_set_volume (int voice, int volume, int ramp_time) rate = 16; gus_ramp_rate (0, rate); - if ((target - current) / 64 == 0) /* Too close */ + if ((target - current) / 64 == 0) /* + * Too close + */ { gus_rampoff (); gus_voice_volume (target); + RESTORE_INTR (flags); return; } @@ -959,7 +1223,9 @@ compute_and_set_volume (int voice, int volume, int ramp_time) if (target > (4095 - 65)) target = 4095 - 65; gus_ramp_range (current, target); - gus_rampon (0x00); /* Ramp up, once, no irq */ + gus_rampon (0x00); /* + * Ramp up, once, no irq + */ } else { @@ -967,8 +1233,11 @@ compute_and_set_volume (int voice, int volume, int ramp_time) target = 65; gus_ramp_range (target, current); - gus_rampon (0x40); /* Ramp down, once, no irq */ + gus_rampon (0x40); /* + * Ramp down, once, no irq + */ } + RESTORE_INTR (flags); } static void @@ -979,11 +1248,15 @@ dynamic_volume_change (int voice) DISABLE_INTR (flags); gus_select_voice (voice); - status = gus_read8 (0x00); /* Voice status */ + status = gus_read8 (0x00); /* + * Voice status + */ RESTORE_INTR (flags); if (status & 0x03) - return; /* Voice not started */ + return; /* + * Voice not started + */ if (!(voices[voice].mode & WAVE_ENVELOPES)) { @@ -991,16 +1264,20 @@ dynamic_volume_change (int voice) return; } - /* + /* * Voice is running and has envelopes. */ DISABLE_INTR (flags); gus_select_voice (voice); - status = gus_read8 (0x0d); /* Ramping status */ + status = gus_read8 (0x0d); /* + * Ramping status + */ RESTORE_INTR (flags); - if (status & 0x03) /* Sustain phase? */ + if (status & 0x03) /* + * Sustain phase? + */ { compute_and_set_volume (voice, voices[voice].midi_volume, 1); return; @@ -1011,9 +1288,12 @@ dynamic_volume_change (int voice) compute_volume (voice, voices[voice].midi_volume); -#if 0 /* Is this really required */ +#if 0 /* + * * * Is this really required */ voices[voice].current_volume = - gus_read16 (0x09) >> 4; /* Get current volume */ + gus_read16 (0x09) >> 4; /* + * Get current volume + */ voices[voice].env_phase--; step_envelope (voice); @@ -1033,38 +1313,58 @@ guswave_controller (int dev, int voice, int ctrl_num, int value) { case CTRL_PITCH_BENDER: voices[voice].bender = value; - freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range); - voices[voice].current_freq = freq; - DISABLE_INTR (flags); - gus_select_voice (voice); - gus_voice_freq (freq); - RESTORE_INTR (flags); + if (voices[voice].volume_irq_mode != VMODE_START_NOTE) + { + freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range); + voices[voice].current_freq = freq; + + DISABLE_INTR (flags); + gus_select_voice (voice); + gus_voice_freq (freq); + RESTORE_INTR (flags); + } break; case CTRL_PITCH_BENDER_RANGE: voices[voice].bender_range = value; break; - +#ifdef FUTURE_VERSION + case CTL_EXPRESSION: + value /= 128; +#endif case CTRL_EXPRESSION: volume_method = VOL_METHOD_ADAGIO; voices[voice].expression_vol = value; - dynamic_volume_change (voice); + if (voices[voice].volume_irq_mode != VMODE_START_NOTE) + dynamic_volume_change (voice); break; +#ifdef FUTURE_VERSION + case CTL_PAN: + voices[voice].panning = (value * 2) - 128; + break; + + case CTL_MAIN_VOLUME: + value = (value * 100) / 16383; +#endif + case CTRL_MAIN_VOLUME: volume_method = VOL_METHOD_ADAGIO; voices[voice].main_vol = value; - dynamic_volume_change (voice); + if (voices[voice].volume_irq_mode != VMODE_START_NOTE) + dynamic_volume_change (voice); break; - default: /* Ignore */ + default: /* + * Ignore + */ break; } } static int -guswave_start_note (int dev, int voice, int note_num, int volume) +guswave_start_note2 (int dev, int voice, int note_num, int volume) { int sample, best_sample, best_delta, delta_freq; int is16bits, samplep, patch, pan; @@ -1102,7 +1402,7 @@ guswave_start_note (int dev, int voice, int note_num, int volume) note_freq = note_to_freq (note_num); - /* + /* * Find a sample within a patch so that the note_freq is between low_note * and high_note. */ @@ -1123,7 +1423,9 @@ guswave_start_note (int dev, int voice, int note_num, int volume) if (samples[samplep].low_note <= note_freq && note_freq <= samples[samplep].high_note) sample = samplep; else - samplep = samples[samplep].key; /* Follow link */ + samplep = samples[samplep].key; /* + * Follow link + */ } if (sample == -1) sample = best_sample; @@ -1131,10 +1433,16 @@ guswave_start_note (int dev, int voice, int note_num, int volume) if (sample == -1) { printk ("GUS: Patch %d not defined for note %d\n", patch, note_num); - return 0; /* Should play default patch ??? */ + return 0; /* + * Should play default patch ??? + */ } - is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0; /* 8 or 16 bit samples */ + is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0; /* + * 8 or 16 + * bit + * samples + */ voices[voice].mode = samples[sample].mode; voices[voice].patch_vol = samples[sample].volume; @@ -1151,14 +1459,16 @@ guswave_start_note (int dev, int voice, int note_num, int volume) sample_map[voice] = sample; - base_note = samples[sample].base_note / 100; /* To avoid overflows */ + base_note = samples[sample].base_note / 100; /* + * To avoid overflows + */ note_freq /= 100; freq = samples[sample].base_freq * note_freq / base_note; voices[voice].orig_freq = freq; - /* + /* * Since the pitch bender may have been set before playing the note, we * have to calculate the bending now. */ @@ -1175,19 +1485,23 @@ guswave_start_note (int dev, int voice, int note_num, int volume) if (samples[sample].mode & WAVE_16_BITS) { - mode |= 0x04; /* 16 bits */ + mode |= 0x04; /* + * 16 bits + */ if ((sample_ptrs[sample] >> 18) != ((sample_ptrs[sample] + samples[sample].len) >> 18)) printk ("GUS: Sample address error\n"); } /************************************************************************* - * CAUTION! Interrupts disabled. Don't return before enabling - *************************************************************************/ + * CAUTION! Interrupts disabled. Don't return before enabling + *************************************************************************/ DISABLE_INTR (flags); gus_select_voice (voice); - gus_voice_off (); /* It may still be running */ + gus_voice_off (); /* + * It may still be running + */ gus_rampoff (); if (voices[voice].mode & WAVE_ENVELOPES) { @@ -1198,35 +1512,62 @@ guswave_start_note (int dev, int voice, int note_num, int volume) compute_and_set_volume (voice, volume, 0); if (samples[sample].mode & WAVE_LOOP_BACK) - gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].len, is16bits); /* Sample start=end */ + gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].len - + voices[voice].offset_pending, is16bits); /* Sample + * start=end */ else - gus_write_addr (0x0a, sample_ptrs[sample], is16bits); /* Sample start=begin */ + gus_write_addr (0x0a, sample_ptrs[sample] + voices[voice].offset_pending, + is16bits); /* Sample start=begin */ if (samples[sample].mode & WAVE_LOOPING) { - mode |= 0x08; /* Looping on */ + mode |= 0x08; /* + * Looping on + */ if (samples[sample].mode & WAVE_BIDIR_LOOP) - mode |= 0x10; /* Bidirectional looping on */ + mode |= 0x10; /* + * Bidirectional looping on + */ if (samples[sample].mode & WAVE_LOOP_BACK) { - gus_write_addr (0x0a, /* Put the current location = loop_end */ - sample_ptrs[sample] + samples[sample].loop_end, is16bits); - mode |= 0x40; /* Loop backwards */ + gus_write_addr (0x0a, + sample_ptrs[sample] + samples[sample].loop_end - + voices[voice].offset_pending, is16bits); + mode |= 0x40; } - gus_write_addr (0x02, sample_ptrs[sample] + samples[sample].loop_start, is16bits); /* Loop start location */ - gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end, is16bits); /* Loop end location */ + gus_write_addr (0x02, sample_ptrs[sample] + samples[sample].loop_start, is16bits); /* + * Loop + * start + * location + */ + gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end, is16bits); /* + * Loop + * end + * location + */ } else { - mode |= 0x20; /* Loop irq at the end */ - voices[voice].loop_irq_mode = LMODE_FINISH; /* Ramp it down at the - * end */ + mode |= 0x20; /* + * Loop irq at the end + */ + voices[voice].loop_irq_mode = LMODE_FINISH; /* + * Ramp it down at + * the * end + */ voices[voice].loop_irq_parm = 1; - gus_write_addr (0x02, sample_ptrs[sample], is16bits); /* Loop start location */ - gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].len, is16bits); /* Loop end location */ + gus_write_addr (0x02, sample_ptrs[sample], is16bits); /* + * Loop start + * location + */ + gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].len - 1, is16bits); /* + * Loop + * end + * location + */ } gus_voice_freq (freq); gus_voice_balance (pan); @@ -1236,13 +1577,76 @@ guswave_start_note (int dev, int voice, int note_num, int volume) return 0; } +/* + * * New guswave_start_note by Andrew J. Robinson attempts to minimize + * clicking * when the note playing on the voice is changed. It uses volume + * ramping. */ + +static int +guswave_start_note (int dev, int voice, int note_num, int volume) +{ + long int flags; + int mode; + int ret_val = 0; + + DISABLE_INTR (flags); + if (note_num == 255) + { + if (voices[voice].volume_irq_mode == VMODE_START_NOTE) + voices[voice].volume_pending = volume; + else + ret_val = guswave_start_note2 (dev, voice, note_num, volume); + } + else + { + gus_select_voice (voice); + mode = gus_read8 (0x00); + if (mode & 0x20) + gus_write8 (0x00, mode & 0xdf); /* No interrupt! */ + + voices[voice].offset_pending = 0; + voices[voice].kill_pending = 0; + voices[voice].volume_irq_mode = 0; + voices[voice].loop_irq_mode = 0; + + if (voices[voice].sample_pending >= 0) + { + guswave_set_instr (voices[voice].dev_pending, voice, + voices[voice].sample_pending); + voices[voice].sample_pending = -1; + } + + if ((mode & 0x01) || ((gus_read16 (0x09) >> 4) < 2065)) + { + ret_val = guswave_start_note2 (dev, voice, note_num, volume); + } + else + { + voices[voice].dev_pending = dev; + 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_rampon (0x20 | 0x40); /* Ramp down, once, irq */ + } + } + RESTORE_INTR (flags); + return ret_val; +} + static void guswave_reset (int dev) { int i; for (i = 0; i < 32; i++) - gus_voice_init (i); + { + gus_voice_init (i); + gus_voice_init2 (i); + } } static int @@ -1253,9 +1657,12 @@ guswave_open (int dev, int mode) if (gus_busy) return RET_ERROR (EBUSY); + gus_initialize (); + if ((err = DMAbuf_open_dma (gus_devnum))) return err; + RESET_WAIT_QUEUE (dram_sleeper, dram_sleep_flag); gus_busy = 1; active_device = GUS_DEV_WAVE; @@ -1280,22 +1687,29 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr, { struct patch_info patch; int instr; + long sizeof_patch; unsigned long blk_size, blk_end, left, src_offs, target; + sizeof_patch = (long) &patch.data[0] - (long) &patch; /* + * Size of + * the header + * * info + */ + if (format != GUS_PATCH) { - printk ("GUS Error: Invalid patch format (key) 0x%04x\n", format); + printk ("GUS Error: Invalid patch format (key) 0x%x\n", format); return RET_ERROR (EINVAL); } - if (count < sizeof (patch)) + if (count < sizeof_patch) { printk ("GUS Error: Patch header too short\n"); return RET_ERROR (EINVAL); } - count -= sizeof (patch); + count -= sizeof_patch; if (free_sample >= MAX_SAMPLE) { @@ -1303,12 +1717,12 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr, return RET_ERROR (ENOSPC); } - /* + /* * Copy the header from user space but ignore the first bytes which have * been transferred already. */ - COPY_FROM_USER (&((char *) &patch)[offs], addr, offs, sizeof (patch) - offs); + COPY_FROM_USER (&((char *) &patch)[offs], addr, offs, sizeof_patch - offs); instr = patch.instr_no; @@ -1321,13 +1735,13 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr, if (count < patch.len) { printk ("GUS Warning: Patch record too short (%d<%d)\n", - count, patch.len); + count, (int) patch.len); patch.len = count; } if (patch.len <= 0 || patch.len > gus_mem_size) { - printk ("GUS: Invalid sample length %d\n", patch.len); + printk ("GUS: Invalid sample length %d\n", (int) patch.len); return RET_ERROR (EINVAL); } @@ -1346,31 +1760,37 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr, } } - free_mem_ptr = (free_mem_ptr + 31) & ~31; /* Alignment 32 bytes */ + free_mem_ptr = (free_mem_ptr + 31) & ~31; /* + * Alignment 32 bytes + */ #define GUS_BANK_SIZE (256*1024) if (patch.mode & WAVE_16_BITS) { - /* + /* * 16 bit samples must fit one 256k bank. */ if (patch.len >= GUS_BANK_SIZE) { - printk ("GUS: Sample (16 bit) too long %d\n", patch.len); + printk ("GUS: Sample (16 bit) too long %d\n", (int) patch.len); return RET_ERROR (ENOSPC); } if ((free_mem_ptr / GUS_BANK_SIZE) != ((free_mem_ptr + patch.len) / GUS_BANK_SIZE)) { - unsigned long tmp_mem = /* Align to 256K*N */ + unsigned long tmp_mem = /* + * Align to 256K*N + */ ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE; if ((tmp_mem + patch.len) > gus_mem_size) return RET_ERROR (ENOSPC); - free_mem_ptr = tmp_mem; /* This leaves unusable memory */ + free_mem_ptr = tmp_mem; /* + * This leaves unusable memory + */ } } @@ -1379,21 +1799,23 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr, sample_ptrs[free_sample] = free_mem_ptr; - /* Tremolo is not possible with envelopes */ + /* + * Tremolo is not possible with envelopes + */ if (patch.mode & WAVE_ENVELOPES) patch.mode &= ~WAVE_TREMOLO; - memcpy ((char *) &samples[free_sample], &patch, sizeof (patch)); + memcpy ((char *) &samples[free_sample], &patch, sizeof_patch); - /* + /* * Link this_one sample to the list of samples for patch 'instr'. */ samples[free_sample].key = patch_table[instr]; patch_table[instr] = free_sample; - /* + /* * Use DMA to transfer the wave data to the DRAM */ @@ -1401,26 +1823,30 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr, src_offs = 0; target = free_mem_ptr; - while (left) /* Not all moved */ + while (left) /* + * Not all moved + */ { blk_size = sound_buffsizes[gus_devnum]; if (blk_size > left) blk_size = left; - /* + /* * DMA cannot cross 256k bank boundaries. Check for that. */ blk_end = target + blk_size; if ((target >> 18) != (blk_end >> 18)) - { /* Have to split the block */ + { /* + * Have to split the block + */ blk_end &= ~(256 * 1024 - 1); blk_size = blk_end - target; } -#ifdef GUS_NO_DMA - /* +#if defined(GUS_NO_DMA) || defined(GUS_PATCH_NO_DMA) + /* * For some reason the DMA is not possible. We have to use PIO. */ { @@ -1429,28 +1855,39 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr, for (i = 0; i < blk_size; i++) { - GET_BYTE_FROM_USER (data, addr, sizeof (patch) + i); + GET_BYTE_FROM_USER (data, addr, sizeof_patch + i); + if (patch.mode & WAVE_UNSIGNED) + + if (!(patch.mode & WAVE_16_BITS) || (i & 0x01)) + data ^= 0x80; /* + * Convert to signed + */ gus_poke (target + i, data); } } -#else /* GUS_NO_DMA */ +#else /* + * * * GUS_NO_DMA */ { unsigned long address, hold_address; unsigned char dma_command; + unsigned long flags; - /* + /* * OK, move now. First in and then out. */ COPY_FROM_USER (snd_raw_buf[gus_devnum][0], - addr, sizeof (patch) + src_offs, + addr, sizeof_patch + src_offs, blk_size); - gus_write8 (0x41, 0); /* Disable GF1 DMA */ + DISABLE_INTR (flags); /******** INTERRUPTS DISABLED NOW ********/ + gus_write8 (0x41, 0); /* + * Disable GF1 DMA + */ DMAbuf_start_dma (gus_devnum, snd_raw_buf_phys[gus_devnum][0], blk_size, DMA_MODE_WRITE); - /* + /* * Set the DRAM address for the wave data */ @@ -1464,32 +1901,48 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr, address |= (hold_address & 0x000c0000L); } - gus_write16 (0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ + gus_write16 (0x42, (address >> 4) & 0xffff); /* + * DRAM DMA address + */ - /* + /* * Start the DMA transfer */ - dma_command = 0x21; /* IRQ enable, DMA start */ + dma_command = 0x21; /* + * IRQ enable, DMA start + */ if (patch.mode & WAVE_UNSIGNED) - dma_command |= 0x80; /* Invert MSB */ + dma_command |= 0x80; /* + * Invert MSB + */ if (patch.mode & WAVE_16_BITS) - dma_command |= 0x40; /* 16 bit _DATA_ */ + dma_command |= 0x40; /* + * 16 bit _DATA_ + */ if (sound_dsp_dmachan[gus_devnum] > 3) - dma_command |= 0x04; /* 16 bit DMA channel */ + dma_command |= 0x04; /* + * 16 bit DMA channel + */ - gus_write8 (0x41, dma_command); /* Let's go luteet (=bugs) */ + gus_write8 (0x41, dma_command); /* + * Let's go luteet (=bugs) + */ - /* + /* * Sleep here until the DRAM DMA done interrupt is served */ active_device = GUS_DEV_WAVE; - INTERRUPTIBLE_SLEEP_ON (dram_sleeper, dram_sleep_flag); + DO_SLEEP (dram_sleeper, dram_sleep_flag, HZ); + if (TIMED_OUT (dram_sleeper, dram_sleep_flag)) + printk ("GUS: DMA Transfer timed out\n"); + RESTORE_INTR (flags); } -#endif /* GUS_NO_DMA */ +#endif /* + * * * GUS_NO_DMA */ - /* + /* * Now the next part */ @@ -1497,7 +1950,9 @@ guswave_load_patch (int dev, int format, snd_rw_buf * addr, src_offs += blk_size; target += blk_size; - gus_write8 (0x41, 0); /* Stop DMA */ + gus_write8 (0x41, 0); /* + * Stop DMA + */ } free_mem_ptr += patch.len; @@ -1521,6 +1976,10 @@ guswave_hw_control (int dev, unsigned char *event) p2 = *(unsigned short *) &event[6]; plong = *(unsigned long *) &event[4]; + if ((voices[voice].volume_irq_mode == VMODE_START_NOTE) && + (cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS)) + do_volume_irq (voice); + switch (cmd) { @@ -1538,7 +1997,9 @@ guswave_hw_control (int dev, unsigned char *event) case _GUS_VOICEON: DISABLE_INTR (flags); gus_select_voice (voice); - p1 &= ~0x20; /* Disable intr */ + p1 &= ~0x20; /* + * Disable intr + */ gus_voice_on (p1); RESTORE_INTR (flags); break; @@ -1560,7 +2021,9 @@ guswave_hw_control (int dev, unsigned char *event) case _GUS_VOICEMODE: DISABLE_INTR (flags); gus_select_voice (voice); - p1 &= ~0x20; /* Disable intr */ + p1 &= ~0x20; /* + * Disable intr + */ gus_voice_mode (p1); RESTORE_INTR (flags); break; @@ -1586,14 +2049,18 @@ guswave_hw_control (int dev, unsigned char *event) RESTORE_INTR (flags); break; - case _GUS_VOICEVOL2: /* Just update the voice value */ + case _GUS_VOICEVOL2: /* + * Just update the voice value + */ voices[voice].initial_volume = voices[voice].current_volume = p1; break; case _GUS_RAMPRANGE: if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NO-NO */ + break; /* + * NO-NO + */ DISABLE_INTR (flags); gus_select_voice (voice); gus_ramp_range (p1, p2); @@ -1602,7 +2069,9 @@ guswave_hw_control (int dev, unsigned char *event) case _GUS_RAMPRATE: if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NO-NO */ + break; /* + * NO-NO + */ DISABLE_INTR (flags); gus_select_voice (voice); gus_ramp_rate (p1, p2); @@ -1611,27 +2080,37 @@ guswave_hw_control (int dev, unsigned char *event) case _GUS_RAMPMODE: if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NO-NO */ + break; /* + * NO-NO + */ DISABLE_INTR (flags); gus_select_voice (voice); - p1 &= ~0x20; /* Disable intr */ + p1 &= ~0x20; /* + * Disable intr + */ gus_ramp_mode (p1); RESTORE_INTR (flags); break; case _GUS_RAMPON: if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NO-NO */ + break; /* + * NO-NO + */ DISABLE_INTR (flags); gus_select_voice (voice); - p1 &= ~0x20; /* Disable intr */ + p1 &= ~0x20; /* + * Disable intr + */ gus_rampon (p1); RESTORE_INTR (flags); break; case _GUS_RAMPOFF: if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NO-NO */ + break; /* + * NO-NO + */ DISABLE_INTR (flags); gus_select_voice (voice); gus_rampoff (); @@ -1643,6 +2122,13 @@ guswave_hw_control (int dev, unsigned char *event) volume_scale = p2; break; + case _GUS_VOICE_POS: + DISABLE_INTR (flags); + gus_select_voice (voice); + gus_set_voice_pos (voice, plong); + RESTORE_INTR (flags); + break; + default:; } } @@ -1710,6 +2196,8 @@ gus_sampling_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) break; case SOUND_PCM_WRITE_CHANNELS: + if (local) + return gus_sampling_set_channels (arg); return IOCTL_OUT (arg, gus_sampling_set_channels (IOCTL_IN (arg))); break; @@ -1730,7 +2218,9 @@ gus_sampling_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) return gus_sampling_bits; return IOCTL_OUT (arg, gus_sampling_bits); - case SOUND_PCM_WRITE_FILTER: /* NOT YET IMPLEMENTED */ + case SOUND_PCM_WRITE_FILTER: /* + * NOT YET IMPLEMENTED + */ return IOCTL_OUT (arg, RET_ERROR (EINVAL)); break; @@ -1760,6 +2250,8 @@ gus_sampling_open (int dev, int mode) if (gus_busy) return RET_ERROR (EBUSY); + gus_initialize (); + gus_busy = 1; active_device = 0; @@ -1767,10 +2259,13 @@ gus_sampling_open (int dev, int mode) reset_sample_memory (); gus_select_max_voices (14); - gus_sampling_set_bits (8); - gus_sampling_set_channels (1); - gus_sampling_set_speed (DSP_DEFAULT_SPEED); pcm_active = 0; + pcm_opened = 1; + if (mode & OPEN_READ) + { + recording_active = 1; + set_input_volumes (); + } return 0; } @@ -1780,7 +2275,31 @@ gus_sampling_close (int dev) { gus_reset (); gus_busy = 0; + pcm_opened = 0; active_device = 0; + + if (recording_active) + set_input_volumes (); + + recording_active = 0; +} + +static void +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++) + { + 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); } static void @@ -1800,18 +2319,24 @@ play_next_pcm_block (void) for (chn = 0; chn < gus_sampling_channels; chn++) { mode[chn] = 0x00; - ramp_mode[chn] = 0x03; /* Ramping and rollover off */ + ramp_mode[chn] = 0x03; /* + * Ramping and rollover off + */ if (chn == 0) { - mode[chn] |= 0x20; /* Loop irq */ + mode[chn] |= 0x20; /* + * Loop irq + */ voices[chn].loop_irq_mode = LMODE_PCM; } if (gus_sampling_bits != 8) { is16bits = 1; - mode[chn] |= 0x04; /* 16 bit data */ + mode[chn] |= 0x04; /* + * 16 bit data + */ } else is16bits = 0; @@ -1819,15 +2344,23 @@ play_next_pcm_block (void) dram_loc = this_one * pcm_bsize; dram_loc += chn * pcm_banksize; - if (this_one == (pcm_nblk - 1)) /* Last of the DRAM buffers */ + if (this_one == (pcm_nblk - 1)) /* + * Last of the DRAM buffers + */ { - mode[chn] |= 0x08; /* Enable loop */ - ramp_mode[chn] = 0x03;/* Disable rollover */ + mode[chn] |= 0x08; /* + * Enable loop + */ + ramp_mode[chn] = 0x03; /* + * Disable rollover + */ } else { if (chn == 0) - ramp_mode[chn] = 0x04; /* Enable rollover bit */ + ramp_mode[chn] = 0x04; /* + * Enable rollover bit + */ } DISABLE_INTR (flags); @@ -1835,53 +2368,90 @@ play_next_pcm_block (void) gus_voice_freq (speed); if (gus_sampling_channels == 1) - gus_voice_balance (7); /* mono */ + gus_voice_balance (7); /* + * mono + */ else if (chn == 0) - gus_voice_balance (0); /* left */ + gus_voice_balance (0); /* + * left + */ else - gus_voice_balance (15); /* right */ + gus_voice_balance (15); /* + * right + */ - if (!pcm_active) /* Voice not started yet */ + if (!pcm_active) /* + * Voice not started yet + */ { - /* + /* * The playback was not started yet (or there has been a pause). * Start the voice (again) and ask for a rollover irq at the end of * this_one block. If this_one one is last of the buffers, use just * the normal loop with irq. */ - gus_voice_off (); /* It could already be running */ + gus_voice_off (); /* + * It could already be running + */ gus_rampoff (); - gus_voice_volume (4000); - gus_ramp_range (65, 4030); + gus_voice_volume (1530 + (25 * gus_pcm_volume)); + gus_ramp_range (65, 1530 + (25 * gus_pcm_volume)); - gus_write_addr (0x0a, dram_loc, is16bits); /* Starting position */ - gus_write_addr (0x02, chn * pcm_banksize, is16bits); /* Loop start location */ + gus_write_addr (0x0a, dram_loc, is16bits); /* + * Starting position + */ + gus_write_addr (0x02, chn * pcm_banksize, is16bits); /* + * Loop start + * location + */ if (chn != 0) gus_write_addr (0x04, pcm_banksize + (pcm_bsize * pcm_nblk), - is16bits); /* Loop end location */ + is16bits); /* + * Loop end location + */ } if (chn == 0) - gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits); /* Loop end location */ + gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits); /* + * Loop + * end + * location + */ else - mode[chn] |= 0x08; /* Enable loop */ + mode[chn] |= 0x08; /* + * Enable loop + */ if (pcm_datasize[this_one] != pcm_bsize) { - /* Incomplete block. Possibly the last one. */ + /* + * Incomplete block. Possibly the last one. + */ if (chn == 0) { - mode[chn] &= ~0x08; /* Disable loop */ - mode[chn] |= 0x20;/* Enable loop IRQ */ + mode[chn] &= ~0x08; /* + * Disable loop + */ + mode[chn] |= 0x20; /* + * Enable loop IRQ + */ voices[0].loop_irq_mode = LMODE_PCM_STOP; - ramp_mode[chn] = 0x03; /* No rollover bit */ + ramp_mode[chn] = 0x03; /* + * No rollover bit + */ } else { - gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits); /* Loop end location */ - mode[chn] &= ~0x08; /* Disable loop */ + gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits); /* + * Loop + * end + * location + */ + mode[chn] &= ~0x08; /* + * Disable loop + */ } } @@ -1904,7 +2474,7 @@ static void gus_transfer_output_block (int dev, unsigned long buf, int total_count, int intrflag, int chn) { - /* + /* * This routine transfers one block of audio data to the DRAM. In mono mode * it's called just once. When in stereo mode, this_one routine is called * once for both channels. @@ -1935,7 +2505,9 @@ gus_transfer_output_block (int dev, unsigned long buf, else this_one = pcm_current_block; - gus_write8 (0x41, 0); /* Disable GF1 DMA */ + gus_write8 (0x41, 0); /* + * Disable GF1 DMA + */ DMAbuf_start_dma (dev, buf + (chn * count), count, DMA_MODE_WRITE); address = this_one * pcm_bsize; @@ -1949,38 +2521,56 @@ gus_transfer_output_block (int dev, unsigned long buf, address |= (hold_address & 0x000c0000L); } - gus_write16 (0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ + gus_write16 (0x42, (address >> 4) & 0xffff); /* + * DRAM DMA address + */ - dma_command = 0x21; /* IRQ enable, DMA start */ + dma_command = 0x21; /* + * IRQ enable, DMA start + */ if (gus_sampling_bits != 8) - dma_command |= 0x40; /* 16 bit _DATA_ */ + dma_command |= 0x40; /* + * 16 bit _DATA_ + */ else - dma_command |= 0x80; /* Invert MSB */ + dma_command |= 0x80; /* + * Invert MSB + */ if (sound_dsp_dmachan[dev] > 3) - dma_command |= 0x04; /* 16 bit DMA channel */ + dma_command |= 0x04; /* + * 16 bit DMA channel + */ - gus_write8 (0x41, dma_command); /* Kick on */ + gus_write8 (0x41, dma_command); /* + * Kick on + */ - if (chn == (gus_sampling_channels - 1)) /* Last channel */ + if (chn == (gus_sampling_channels - 1)) /* + * Last channel + */ { - /* Last (right or mono) channel data */ + /* + * Last (right or mono) channel data + */ active_device = GUS_DEV_PCM_DONE; if (!pcm_active && (pcm_qlen > 2 || count < pcm_bsize)) { play_next_pcm_block (); } } - else /* Left channel data. The right channel is - * transferred after DMA interrupt */ + else /* + * * * Left channel data. The right channel + * is * * * transferred after DMA interrupt */ active_device = GUS_DEV_PCM_CONTINUE; RESTORE_INTR (flags); } static void -gus_sampling_output_block (int dev, unsigned long buf, int total_count, int intrflag) +gus_sampling_output_block (int dev, unsigned long buf, int total_count, + int intrflag, int restart_dma) { pcm_current_buf = buf; pcm_current_count = total_count; @@ -1990,7 +2580,8 @@ gus_sampling_output_block (int dev, unsigned long buf, int total_count, int intr } static void -gus_sampling_start_input (int dev, unsigned long buf, int count, int intrflag) +gus_sampling_start_input (int dev, unsigned long buf, int count, + int intrflag, int restart_dma) { unsigned long flags; unsigned char mode; @@ -1999,13 +2590,21 @@ gus_sampling_start_input (int dev, unsigned long buf, int count, int intrflag) DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); - mode = 0xa0; /* DMA IRQ enable, invert MSB */ + mode = 0xa0; /* + * DMA IRQ enable, invert MSB + */ if (sound_dsp_dmachan[dev] > 3) - mode |= 0x04; /* 16 bit DMA channel */ + mode |= 0x04; /* + * 16 bit DMA channel + */ if (gus_sampling_channels > 1) - mode |= 0x02; /* Stereo */ - mode |= 0x01; /* DMA enable */ + mode |= 0x02; /* + * Stereo + */ + mode |= 0x01; /* + * DMA enable + */ gus_write8 (0x49, mode); @@ -2019,7 +2618,9 @@ gus_sampling_prepare_for_input (int dev, int bsize, int bcount) rate = (9878400 / (gus_sampling_speed + 2)) / 16; - gus_write8 (0x48, rate & 0xff); /* Set sampling frequency */ + gus_write8 (0x48, rate & 0xff); /* + * Set sampling frequency + */ if (gus_sampling_bits != 8) { @@ -2072,7 +2673,9 @@ gus_copy_from_user (int dev, char *localbuf, int localoffs, snd_rw_buf * userbuf, int useroffs, int len) { if (gus_sampling_channels == 1) - COPY_FROM_USER (&localbuf[localoffs], userbuf, useroffs, len); + { + COPY_FROM_USER (&localbuf[localoffs], userbuf, useroffs, len); + } else if (gus_sampling_bits == 8) { int in_left = useroffs; @@ -2119,19 +2722,37 @@ gus_copy_from_user (int dev, char *localbuf, int localoffs, static struct audio_operations gus_sampling_operations = { "Gravis UltraSound", - 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, /* halt_xfer */ + 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_has_output_drained, gus_copy_from_user }; +#ifdef FUTURE_VERSION +static void +guswave_bender (int dev, int voice, int value) +{ + int freq; + unsigned long flags; + + voices[voice].bender = value - 8192; + freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range); + voices[voice].current_freq = freq; + + DISABLE_INTR (flags); + gus_select_voice (voice); + gus_voice_freq (freq); + RESTORE_INTR (flags); +} +#endif + static int guswave_patchmgr (int dev, struct patmgr_info *rec) { @@ -2161,7 +2782,9 @@ guswave_patchmgr (int dev, struct patmgr_info *rec) while (ptr >= 0 && ptr < free_sample) { rec->data.data8[i]++; - ptr = samples[ptr].key; /* Follow link */ + ptr = samples[ptr].key; /* + * Follow link + */ } } return 0; @@ -2176,7 +2799,9 @@ guswave_patchmgr (int dev, struct patmgr_info *rec) while (ptr >= 0 && ptr < free_sample) { rec->data.data32[n++] = ptr; - ptr = samples[ptr].key; /* Follow link */ + ptr = samples[ptr].key; /* + * Follow link + */ } } rec->parm1 = n; @@ -2196,8 +2821,12 @@ guswave_patchmgr (int dev, struct patmgr_info *rec) pat = (struct patch_info *) rec->data.data8; - pat->key = GUS_PATCH; /* Restore patch type */ - rec->parm1 = sample_ptrs[ptr]; /* DRAM address */ + pat->key = GUS_PATCH; /* + * Restore patch type + */ + rec->parm1 = sample_ptrs[ptr]; /* + * DRAM address + */ rec->parm2 = sizeof (struct patch_info); } return 0; @@ -2213,10 +2842,14 @@ guswave_patchmgr (int dev, struct patmgr_info *rec) pat = (struct patch_info *) rec->data.data8; - if (pat->len > samples[ptr].len) /* Cannot expand sample */ + if (pat->len > samples[ptr].len) /* + * Cannot expand sample + */ return RET_ERROR (EINVAL); - pat->key = samples[ptr].key; /* Ensure the link is correct */ + pat->key = samples[ptr].key; /* + * Ensure the link is correct + */ memcpy ((char *) &samples[ptr], rec->data.data8, sizeof (struct patch_info)); @@ -2226,7 +2859,9 @@ guswave_patchmgr (int dev, struct patmgr_info *rec) return 0; break; - case PM_READ_PATCH: /* Returns a block of wave data from the DRAM */ + case PM_READ_PATCH: /* + * Returns a block of wave data from the DRAM + */ { int sample = rec->parm1; int n; @@ -2237,9 +2872,13 @@ guswave_patchmgr (int dev, struct patmgr_info *rec) return RET_ERROR (EINVAL); if (offs < 0 || offs >= samples[sample].len) - return RET_ERROR (EINVAL); /* Invalid offset */ + return RET_ERROR (EINVAL); /* + * Invalid offset + */ - n = samples[sample].len - offs; /* Nr of bytes left */ + n = samples[sample].len - offs; /* + * Nr of bytes left + */ if (l > n) l = n; @@ -2248,18 +2887,26 @@ guswave_patchmgr (int dev, struct patmgr_info *rec) l = sizeof (rec->data.data8); if (l <= 0) - return RET_ERROR (EINVAL); /* Was there a bug? */ + return RET_ERROR (EINVAL); /* + * Was there a bug? + */ - offs += sample_ptrs[sample]; /* Begin offsess + offset to DRAM */ + offs += sample_ptrs[sample]; /* + * Begin offsess + offset to DRAM + */ for (n = 0; n < l; n++) rec->data.data8[n] = gus_peek (offs++); - rec->parm1 = n; /* Nr of bytes copied */ + rec->parm1 = n; /* + * Nr of bytes copied + */ } return 0; break; - case PM_WRITE_PATCH: /* Writes a block of wave data to the DRAM */ + case PM_WRITE_PATCH: /* + * Writes a block of wave data to the DRAM + */ { int sample = rec->parm1; int n; @@ -2270,9 +2917,13 @@ guswave_patchmgr (int dev, struct patmgr_info *rec) return RET_ERROR (EINVAL); if (offs < 0 || offs >= samples[sample].len) - return RET_ERROR (EINVAL); /* Invalid offset */ + return RET_ERROR (EINVAL); /* + * Invalid offset + */ - n = samples[sample].len - offs; /* Nr of bytes left */ + n = samples[sample].len - offs; /* + * Nr of bytes left + */ if (l > n) l = n; @@ -2281,13 +2932,19 @@ guswave_patchmgr (int dev, struct patmgr_info *rec) l = sizeof (rec->data.data8); if (l <= 0) - return RET_ERROR (EINVAL); /* Was there a bug? */ + return RET_ERROR (EINVAL); /* + * Was there a bug? + */ - offs += sample_ptrs[sample]; /* Begin offsess + offset to DRAM */ + offs += sample_ptrs[sample]; /* + * Begin offsess + offset to DRAM + */ for (n = 0; n < l; n++) gus_poke (offs++, rec->data.data8[n]); - rec->parm1 = n; /* Nr of bytes copied */ + rec->parm1 = n; /* + * Nr of bytes copied + */ } return 0; break; @@ -2300,6 +2957,9 @@ guswave_patchmgr (int dev, struct patmgr_info *rec) static struct synth_operations guswave_operations = { &gus_info, +#ifdef FUTURE_VERSION + 0, +#endif SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS, guswave_open, @@ -2314,13 +2974,188 @@ static struct synth_operations guswave_operations = guswave_aftertouch, guswave_controller, guswave_panning, - guswave_patchmgr + guswave_patchmgr, +#ifdef FUTURE_VERSION + guswave_bender +#endif +}; + +static void +set_input_volumes (void) +{ + unsigned long flags; + unsigned char mask = 0xff & ~0x06; /* Just line out enabled */ + + DISABLE_INTR (flags); + +/* + * 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) + mask |= 0x04; + + if (recording_active) + { +/* + * Disable channel, if not selected for recording + */ + if (!(gus_recmask & SOUND_MASK_LINE)) + mask |= 0x01; + if (!(gus_recmask & SOUND_MASK_MIC)) + mask &= ~0x04; + } + + mix_image &= ~0x07; + mix_image |= mask & 0x07; + OUTB (mix_image, u_Mixer); + + RESTORE_INTR (flags); +} + +static int +gus_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg) +{ +#define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \ + SOUND_MASK_SYNTH|SOUND_MASK_PCM) + if (((cmd >> 8) & 0xff) == 'M') + { + if (cmd & IOC_IN) + switch (cmd & 0xff) + { + case SOUND_MIXER_RECSRC: + gus_recmask = IOCTL_IN (arg) & MIX_DEVS; + if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE))) + gus_recmask = SOUND_MASK_MIC; + /* Note! Input volumes are updated during next open for recording */ + return IOCTL_OUT (arg, gus_recmask); + break; + + case SOUND_MIXER_MIC: + { + int vol = IOCTL_IN (arg) & 0xff; + + if (vol < 0) + vol = 0; + if (vol > 100) + vol = 100; + gus_mic_vol = vol; + set_input_volumes (); + return IOCTL_OUT (arg, vol | (vol << 8)); + } + break; + + case SOUND_MIXER_LINE: + { + int vol = IOCTL_IN (arg) & 0xff; + + if (vol < 0) + vol = 0; + if (vol > 100) + vol = 100; + gus_line_vol = vol; + set_input_volumes (); + return IOCTL_OUT (arg, vol | (vol << 8)); + } + break; + + case SOUND_MIXER_PCM: + gus_pcm_volume = IOCTL_IN (arg) & 0xff; + if (gus_pcm_volume < 0) + gus_pcm_volume = 0; + if (gus_pcm_volume > 100) + gus_pcm_volume = 100; + gus_sampling_update_volume (); + return IOCTL_OUT (arg, gus_pcm_volume | (gus_pcm_volume << 8)); + break; + + case SOUND_MIXER_SYNTH: + { + int voice; + + gus_wave_volume = IOCTL_IN (arg) & 0xff; + + if (gus_wave_volume < 0) + gus_wave_volume = 0; + if (gus_wave_volume > 100) + gus_wave_volume = 100; + + if (active_device == GUS_DEV_WAVE) + for (voice = 0; voice < nr_voices; voice++) + dynamic_volume_change (voice); /* + * Apply the new + * volume + */ + + return IOCTL_OUT (arg, gus_wave_volume | (gus_wave_volume << 8)); + } + break; + + default: + return RET_ERROR (EINVAL); + } + else + switch (cmd & 0xff) /* + * Return parameters + */ + { + + case SOUND_MIXER_RECSRC: + return IOCTL_OUT (arg, gus_recmask); + break; + + case SOUND_MIXER_DEVMASK: + return IOCTL_OUT (arg, MIX_DEVS); + break; + + case SOUND_MIXER_STEREODEVS: + return IOCTL_OUT (arg, 0); + break; + + case SOUND_MIXER_RECMASK: + return IOCTL_OUT (arg, SOUND_MASK_MIC | SOUND_MASK_LINE); + break; + + case SOUND_MIXER_CAPS: + return IOCTL_OUT (arg, 0); + break; + + case SOUND_MIXER_MIC: + return IOCTL_OUT (arg, gus_mic_vol | (gus_mic_vol << 8)); + break; + + case SOUND_MIXER_LINE: + return IOCTL_OUT (arg, gus_line_vol | (gus_line_vol << 8)); + break; + + case SOUND_MIXER_PCM: + return IOCTL_OUT (arg, gus_pcm_volume | (gus_pcm_volume << 8)); + break; + + case SOUND_MIXER_SYNTH: + return IOCTL_OUT (arg, gus_wave_volume | (gus_wave_volume << 8)); + break; + + default: + return RET_ERROR (EINVAL); + } + } + else + return RET_ERROR (EINVAL); +} + +static struct mixer_operations gus_mixer_operations = +{ + gus_mixer_ioctl }; long gus_wave_init (long mem_start, int irq, int dma) { - printk ("snd4: ", gus_mem_size / 1024); + printk ("snd4: ", (int) gus_mem_size / 1024); if (irq < 0 || irq > 15) { @@ -2342,6 +3177,9 @@ gus_wave_init (long mem_start, int irq, int dma) else synth_devs[num_synths++] = &guswave_operations; + PERMANENT_MALLOC (struct patch_info *, samples, + (MAX_SAMPLE + 1) * sizeof (*samples), mem_start); + reset_sample_memory (); gus_initialize (); @@ -2357,6 +3195,12 @@ gus_wave_init (long mem_start, int irq, int dma) else printk ("GUS: Too many PCM devices available\n"); + if (num_mixers < MAX_MIXER_DEV) /* + * Don't install if there is another + * mixer + */ + mixer_devs[num_mixers++] = &gus_mixer_operations; + return mem_start; } @@ -2371,7 +3215,9 @@ do_loop_irq (int voice) gus_select_voice (voice); tmp = gus_read8 (0x00); - tmp &= ~0x20; /* Disable wave IRQ for this_one voice */ + tmp &= ~0x20; /* + * Disable wave IRQ for this_one voice + */ gus_write8 (0x00, tmp); mode = voices[voice].loop_irq_mode; @@ -2381,23 +3227,33 @@ do_loop_irq (int voice) switch (mode) { - case LMODE_FINISH: /* Final loop finished, shoot volume down */ + case LMODE_FINISH: /* + * Final loop finished, shoot volume down + */ - if ((gus_read16 (0x09) >> 4) < 100) /* Get current volume */ + if ((gus_read16 (0x09) >> 4) < 100) /* + * Get current volume + */ { gus_voice_off (); gus_rampoff (); gus_voice_init (voice); - return; + break; } gus_ramp_range (65, 4065); - gus_ramp_rate (0, 63); /* Fastest possible rate */ - gus_rampon (0x20 | 0x40); /* Ramp down, once, irq */ + gus_ramp_rate (0, 63); /* + * Fastest possible rate + */ + gus_rampon (0x20 | 0x40); /* + * Ramp down, once, irq + */ voices[voice].volume_irq_mode = VMODE_HALT; break; case LMODE_PCM_STOP: - pcm_active = 0; /* Requires extensive processing */ + pcm_active = 0; /* + * Requires extensive processing + */ case LMODE_PCM: { int orig_qlen = pcm_qlen; @@ -2409,7 +3265,9 @@ do_loop_irq (int voice) play_next_pcm_block (); } else - { /* Out of data. Just stop the voice */ + { /* + * Out of data. Just stop the voice + */ gus_voice_off (); gus_rampoff (); pcm_active = 0; @@ -2417,7 +3275,7 @@ do_loop_irq (int voice) if (orig_qlen == pcm_nblk) { - DMAbuf_outputintr (gus_devnum); + DMAbuf_outputintr (gus_devnum, 0); } } break; @@ -2439,7 +3297,9 @@ do_volume_irq (int voice) gus_select_voice (voice); tmp = gus_read8 (0x0d); - tmp &= ~0x20; /* Disable volume ramp IRQ */ + tmp &= ~0x20; /* + * Disable volume ramp IRQ + */ gus_write8 (0x0d, tmp); mode = voices[voice].volume_irq_mode; @@ -2448,7 +3308,9 @@ do_volume_irq (int voice) switch (mode) { - case VMODE_HALT: /* Decay phase finished */ + case VMODE_HALT: /* + * Decay phase finished + */ gus_voice_init (voice); break; @@ -2457,6 +3319,19 @@ do_volume_irq (int voice) step_envelope (voice); break; + case VMODE_START_NOTE: + guswave_start_note2 (voices[voice].dev_pending, voice, + voices[voice].note_pending, voices[voice].volume_pending); + if (voices[voice].kill_pending) + guswave_kill_note (voices[voice].dev_pending, voice, 0); + if (voices[voice].sample_pending >= 0) + { + guswave_set_instr (voices[voice].dev_pending, voice, + voices[voice].sample_pending); + voices[voice].sample_pending = -1; + } + break; + default:; } @@ -2473,24 +3348,38 @@ gus_voice_irq (void) while (1) { - src = gus_read8 (0x0f); /* Get source info */ + src = gus_read8 (0x0f); /* + * Get source info + */ voice = src & 0x1f; src &= 0xc0; if (src == (0x80 | 0x40)) - return; /* No interrupt */ + return; /* + * No interrupt + */ voice_bit = 1 << voice; - if (!(src & 0x80)) /* Wave IRQ pending */ - if (!(wave_ignore & voice_bit) && voice < nr_voices) /* Not done yet */ + if (!(src & 0x80)) /* + * Wave IRQ pending + */ + if (!(wave_ignore & voice_bit) && voice < nr_voices) /* + * Not done + * yet + */ { wave_ignore |= voice_bit; do_loop_irq (voice); } - if (!(src & 0x40)) /* Volume IRQ pending */ - if (!(volume_ignore & voice_bit) && voice < nr_voices) /* Not done yet */ + if (!(src & 0x40)) /* + * Volume IRQ pending + */ + if (!(volume_ignore & voice_bit) && voice < nr_voices) /* + * Not done + * yet + */ { volume_ignore |= voice_bit; do_volume_irq (voice); @@ -2503,13 +3392,17 @@ guswave_dma_irq (void) { unsigned char status; - status = gus_look8 (0x41); /* Get DMA IRQ Status */ - if (status & 0x40) /* DMA Irq pending */ + status = gus_look8 (0x41); /* + * Get DMA IRQ Status + */ + if (status & 0x40) /* + * DMA Irq pending + */ switch (active_device) { case GUS_DEV_WAVE: - if (dram_sleep_flag) - WAKE_UP (dram_sleeper); + if (SOMEONE_WAITING (dram_sleeper, dram_sleep_flag)) + WAKE_UP (dram_sleeper, dram_sleep_flag); break; case GUS_DEV_PCM_CONTINUE: @@ -2521,15 +3414,19 @@ guswave_dma_irq (void) case GUS_DEV_PCM_DONE: if (pcm_qlen < pcm_nblk) { - DMAbuf_outputintr (gus_devnum); + DMAbuf_outputintr (gus_devnum, pcm_qlen == 0); } break; default:; } - status = gus_look8 (0x49); /* Get Sampling IRQ Status */ - if (status & 0x40) /* Sampling Irq pending */ + status = gus_look8 (0x49); /* + * Get Sampling IRQ Status + */ + if (status & 0x40) /* + * Sampling Irq pending + */ { DMAbuf_inputintr (gus_devnum); } diff --git a/sys/i386/isa/sound/local.h b/sys/i386/isa/sound/local.h index f81bd7821673..26d294b22960 100644 --- a/sys/i386/isa/sound/local.h +++ b/sys/i386/isa/sound/local.h @@ -1,10 +1,14 @@ -/* These few lines are used by FreeBSD (only??). */ - +/* for FreeBSD */ #include "snd.h" #if NSND > 0 -#define CONFIGURE_SOUNDCARD +#define KERNEL_SOUNDCARD #endif #define DSP_BUFFSIZE 32768 #define SELECTED_SOUND_OPTIONS 0xffffffff +#define SOUND_VERSION_STRING "2.4" +#define SOUND_CONFIG_DATE "Mon Mar 7 23:54:09 PST 1994" +#define SOUND_CONFIG_BY "swallace" +#define SOUND_CONFIG_HOST "freefall.cdrom.com" +#define SOUND_CONFIG_DOMAIN "" diff --git a/sys/i386/isa/sound/midi.c b/sys/i386/isa/sound/midi.c index 8d604a80abc2..6ea51b061b9c 100644 --- a/sys/i386/isa/sound/midi.c +++ b/sys/i386/isa/sound/midi.c @@ -31,24 +31,27 @@ #ifndef EXCLUDE_CHIP_MIDI -static int generic_midi_busy[MAX_MIDI_DEV]; +static int generic_midi_busy[MAX_MIDI_DEV]; -long CMIDI_init (long mem_start) +long +CMIDI_init (long mem_start) { - - int i; - int n = num_midi_drivers; - /* int n = sizeof (midi_supported) / sizeof( struct generic_midi_info ); - */ - for (i = 0; i < n; i++) - { - if ( midi_supported[i].attach (mem_start) ) - { - printk("MIDI: Successfully attached %s\n",midi_supported[i].name); - } - } - return (mem_start); + int i; + int n = num_midi_drivers; + + /* + * int n = sizeof (midi_supported) / sizeof( struct generic_midi_info ); + */ + for (i = 0; i < n; i++) + { + if (midi_supported[i].attach (mem_start)) + { + printk ("MIDI: Successfully attached %s\n", midi_supported[i].name); + } + + } + return (mem_start); } @@ -56,142 +59,143 @@ int CMIDI_open (int dev, struct fileinfo *file) { - int mode, err, retval; + int mode, err, retval; - dev = dev >> 4; + dev = dev >> 4; - mode = file->mode & O_ACCMODE; + mode = file->mode & O_ACCMODE; - if (generic_midi_busy[dev]) - return (RET_ERROR(EBUSY)); + if (generic_midi_busy[dev]) + return (RET_ERROR (EBUSY)); - - if (dev >= num_generic_midis) - { - printk(" MIDI device %d not installed.\n", dev); - return (ENXIO); - } - if (!generic_midi_devs[dev]) - { - printk(" MIDI device %d not initialized\n",dev); + if (dev >= num_generic_midis) + { + printk (" MIDI device %d not installed.\n", dev); return (ENXIO); - } + } - /* If all good and healthy, go ahead and issue call! */ + if (!generic_midi_devs[dev]) + { + printk (" MIDI device %d not initialized\n", dev); + return (ENXIO); + } - - retval = generic_midi_devs[dev]->open (dev, mode) ; + /* If all good and healthy, go ahead and issue call! */ - /* If everything ok, set device as busy */ - if ( retval >= 0 ) - generic_midi_busy[dev] = 1; - - return ( retval ); + retval = generic_midi_devs[dev]->open (dev, mode); + + /* If everything ok, set device as busy */ + + if (retval >= 0) + generic_midi_busy[dev] = 1; + + return (retval); } -int -CMIDI_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) +int +CMIDI_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) { - int retval; - - dev = dev >> 4; + int retval; - if (dev >= num_generic_midis) - { - printk(" MIDI device %d not installed.\n", dev); - return (ENXIO); - } + dev = dev >> 4; - /* Make double sure of healthiness -- doubt - * Need we check this again?? - * - */ - - if (!generic_midi_devs[dev]) - { - printk(" MIDI device %d not initialized\n",dev); + if (dev >= num_generic_midis) + { + printk (" MIDI device %d not installed.\n", dev); return (ENXIO); - } + } - /* If all good and healthy, go ahead and issue call! */ + /* + * Make double sure of healthiness -- doubt Need we check this again?? + * + */ - - retval = generic_midi_devs[dev]->write (dev, buf); + if (!generic_midi_devs[dev]) + { + printk (" MIDI device %d not initialized\n", dev); + return (ENXIO); + } - return ( retval ); + /* If all good and healthy, go ahead and issue call! */ -} + + retval = generic_midi_devs[dev]->write (dev, buf); + + return (retval); + +} int -CMIDI_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count) +CMIDI_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) { - int retval; - - dev = dev >> 4; + int retval; - if (dev >= num_generic_midis) - { - printk(" MIDI device %d not installed.\n", dev); - return (ENXIO); - } + dev = dev >> 4; - /* Make double sure of healthiness -- doubt - * Need we check this again?? - * - */ - - if (!generic_midi_devs[dev]) - { - printk(" MIDI device %d not initialized\n",dev); + if (dev >= num_generic_midis) + { + printk (" MIDI device %d not installed.\n", dev); return (ENXIO); - } + } - /* If all good and healthy, go ahead and issue call! */ + /* + * Make double sure of healthiness -- doubt Need we check this again?? + * + */ - - retval = generic_midi_devs[dev]->read(dev,buf); + if (!generic_midi_devs[dev]) + { + printk (" MIDI device %d not initialized\n", dev); + return (ENXIO); + } - return (retval); + /* If all good and healthy, go ahead and issue call! */ + + + retval = generic_midi_devs[dev]->read (dev, buf); + + return (retval); + +} -} - int CMIDI_close (int dev, struct fileinfo *file) { - int retval; - dev = dev >> 4; + int retval; - if (dev >= num_generic_midis) - { - printk(" MIDI device %d not installed.\n", dev); - return (ENXIO); - } + dev = dev >> 4; - /* Make double sure of healthiness -- doubt - * Need we check this again?? - * - */ - - if (!generic_midi_devs[dev]) - { - printk(" MIDI device %d not initialized\n",dev); + if (dev >= num_generic_midis) + { + printk (" MIDI device %d not installed.\n", dev); return (ENXIO); - } + } - /* If all good and healthy, go ahead and issue call! */ + /* + * Make double sure of healthiness -- doubt Need we check this again?? + * + */ + + if (!generic_midi_devs[dev]) + { + printk (" MIDI device %d not initialized\n", dev); + return (ENXIO); + } + + /* If all good and healthy, go ahead and issue call! */ - generic_midi_devs[dev]->close(dev); + generic_midi_devs[dev]->close (dev); - generic_midi_busy[dev] = 0; /* Free the device */ + generic_midi_busy[dev] = 0; /* Free the device */ - return (0) ; + return (0); } diff --git a/sys/i386/isa/sound/midibuf.c b/sys/i386/isa/sound/midibuf.c index 0196f84876bf..54b7266ad6ca 100644 --- a/sys/i386/isa/sound/midibuf.c +++ b/sys/i386/isa/sound/midibuf.c @@ -1,5 +1,5 @@ /* - * linux/kernel/chr_drv/sound/midibuf.c + * sound/midibuf.c * * Device file manager for /dev/midi * diff --git a/sys/i386/isa/sound/mpu401.c b/sys/i386/isa/sound/mpu401.c index e8c011bc7940..449b6befae08 100644 --- a/sys/i386/isa/sound/mpu401.c +++ b/sys/i386/isa/sound/mpu401.c @@ -1,5 +1,5 @@ /* - * linux/kernel/chr_drv/sound/mpu401.c + * sound/mpu401.c * * The low level driver for Roland MPU-401 compatible Midi cards. * @@ -35,7 +35,7 @@ #if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI) -#define DATAPORT (mpu401_base)/* MPU-401 Data I/O Port on IBM */ +#define DATAPORT (mpu401_base) /* MPU-401 Data I/O Port on IBM */ #define COMDPORT (mpu401_base+1) /* MPU-401 Command Port on IBM */ #define STATPORT (mpu401_base+1) /* MPU-401 Status Port on IBM */ @@ -95,21 +95,12 @@ mpuintr (int unit) * polling. */ -/* XXX WARNING: FreeBSD doesn't seem to have timer_lists like this, - * so until I figure out how to do the analogous thing in FreeBSD, I'm - * not all that sure WHAT this driver will do! It might work, depending - * on the condition taken, but then again it might not! -jkh - * XXX WARNING - */ static void poll_mpu401 (unsigned long dummy) { unsigned long flags; -#ifdef linux - static struct timer_list mpu401_timer = - {NULL, 0, 0, poll_mpu401}; -#endif + DEFINE_TIMER (mpu401_timer, poll_mpu401); if (!(mpu401_opened & OPEN_READ)) return; /* No longer required */ @@ -119,46 +110,11 @@ poll_mpu401 (unsigned long dummy) if (input_avail ()) mpu401_input_loop (); -#ifdef linux - mpu401_timer.expires = 1; - add_timer (&mpu401_timer); /* Come back later */ -#endif + ACTIVATE_TIMER (mpu401_timer, poll_mpu401, 1); /* Come back later */ RESTORE_INTR (flags); } -static int -set_mpu401_irq (int interrupt_level) -{ - int retcode = EINVAL; - -#ifdef linux - struct sigaction sa; - - sa.sa_handler = mpuintr; - -#ifdef SND_SA_INTERRUPT - sa.sa_flags = SA_INTERRUPT; -#else - sa.sa_flags = 0; -#endif - - sa.sa_mask = 0; - sa.sa_restorer = NULL; - - retcode = irqaction (interrupt_level, &sa); - - if (retcode < 0) - { - printk ("MPU-401: IRQ%d already in use\n", interrupt_level); - } - -#else - /* # error Unimplemented for this OS */ -#endif - return retcode; -} - static int mpu401_open (int dev, int mode, void (*input) (int dev, unsigned char data), @@ -257,7 +213,7 @@ mpu401_buffer_status (int dev) static struct midi_operations mpu401_operations = { - {"MPU-401", 0}, + {"MPU-401", 0, 0, SNDCARD_MPU401}, mpu401_open, mpu401_close, mpu401_ioctl, @@ -297,9 +253,7 @@ attach_mpu401 (long mem_start, struct address_info *hw_config) printk ("snd5: "); my_dev = num_midis; -#ifdef linux mpu401_dev = num_midis; -#endif midi_devs[num_midis++] = &mpu401_operations; return mem_start; } @@ -311,7 +265,7 @@ reset_mpu401 (void) int ok, timeout, n; /* - * Send the RESET command. Try twice if no success at the first time. + * Send the RESET command. Try again if no success at the first time. */ ok = 0; @@ -353,7 +307,7 @@ probe_mpu401 (struct address_info *hw_config) mpu401_base = hw_config->io_base; mpu401_irq = hw_config->irq; - if (set_mpu401_irq (mpu401_irq) < 0) + if (snd_set_irq_handler (mpu401_irq, mpuintr) < 0) return 0; ok = reset_mpu401 (); diff --git a/sys/i386/isa/sound/opl3.c b/sys/i386/isa/sound/opl3.c index 2dbed1f96e00..58327a32de25 100644 --- a/sys/i386/isa/sound/opl3.c +++ b/sys/i386/isa/sound/opl3.c @@ -1,5 +1,5 @@ /* - * linux/kernel/chr_drv/sound/opl3.c + * sound/opl3.c * * A low level driver for Yamaha YM3812 and OPL-3 -chips * @@ -38,7 +38,7 @@ #define MAX_VOICE 18 #define OFFS_4OP 11 /* Definitions for the operators OP3 and OP4 - * begin here */ + * begin here */ static int opl3_enabled = 0; static int left_address = 0x388, right_address = 0x388, both_address = 0; @@ -59,8 +59,7 @@ struct voice_info static struct voice_info voices[MAX_VOICE]; -typedef struct sbi_instrument instr_array[SBFM_MAXINSTR]; -static instr_array instrmap; +static struct sbi_instrument *instrmap; static struct sbi_instrument *active_instrument[MAX_VOICE] = {NULL}; @@ -71,11 +70,11 @@ static int already_initialized = 0; static int opl3_ok = 0; static int opl3_busy = 0; -static int fm_model = 0; /* 0=no fm, 1=mono, 2=SB Pro 1, 3=SB Pro 2 */ +static int fm_model = 0; /* 0=no fm, 1=mono, 2=SB Pro 1, 3=SB Pro 2 */ static int store_instr (int instr_no, struct sbi_instrument *instr); static void freq_to_fnum (int freq, int *block, int *fnum); -static void opl3_command (int io_addr, const unsigned char addr, const unsigned char val); +static void opl3_command (int io_addr, unsigned int addr, unsigned int val); static int opl3_kill_note (int dev, int voice, int velocity); static unsigned char connection_mask = 0x00; @@ -112,7 +111,7 @@ enter_4op_mode (void) for (i = 0; i < 12; i++) logical_voices[i] = voices_4op[i]; - nr_voices = 6; + nr_voices = 12; } static int @@ -140,7 +139,7 @@ opl3_ioctl (int dev, break; case SNDCTL_SYNTH_INFO: - fm_info.nr_voices = nr_voices; + fm_info.nr_voices = (nr_voices == 12) ? 6 : nr_voices; IOCTL_TO_USER ((char *) arg, 0, &fm_info, sizeof (fm_info)); return 0; @@ -184,6 +183,9 @@ opl3_detect (int ioaddr) return 0; /* Do avoid duplicate initializations */ } + 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 */ @@ -192,10 +194,10 @@ opl3_detect (int ioaddr) if ((stat1 & 0xE0) != 0x00) { - return 0; /* Should be 0x00 */ + return 0; /* Should be 0x00 */ } - opl3_command (ioaddr, TIMER1_REGISTER, 0xff); /* Set timer 1 to 0xff */ + opl3_command (ioaddr, TIMER1_REGISTER, 0xff); /* Set timer 1 to 0xff */ opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER2_MASK | TIMER1_START); /* Unmask and start timer 1 */ @@ -270,7 +272,7 @@ store_instr (int instr_no, struct sbi_instrument *instr) { if (instr->key != FM_PATCH && (instr->key != OPL3_PATCH || !opl3_enabled)) - printk ("FM warning: Invalid patch format field (key) 0x%04x\n", instr->key); + printk ("FM warning: Invalid patch format field (key) 0x%x\n", instr->key); memcpy ((char *) &(instrmap[instr_no]), (char *) instr, sizeof (*instr)); return 0; @@ -303,9 +305,9 @@ char fm_volume_table[128] = -24, -23, -21, -20, -19, -18, -18, -17, /* 8 - 15 */ -16, -15, -15, -14, -13, -13, -12, -12, /* 16 - 23 */ -11, -11, -10, -10, -10, -9, -9, -8, /* 24 - 31 */ - -8, -8, -7, -7, -7, -6, -6, -6,/* 32 - 39 */ - -5, -5, -5, -5, -4, -4, -4, -4,/* 40 - 47 */ - -3, -3, -3, -3, -2, -2, -2, -2,/* 48 - 55 */ + -8, -8, -7, -7, -7, -6, -6, -6, /* 32 - 39 */ + -5, -5, -5, -5, -4, -4, -4, -4, /* 40 - 47 */ + -3, -3, -3, -3, -2, -2, -2, -2, /* 48 - 55 */ -2, -1, -1, -1, -1, 0, 0, 0, /* 56 - 63 */ 0, 0, 0, 1, 1, 1, 1, 1, /* 64 - 71 */ 1, 2, 2, 2, 2, 2, 2, 2, /* 72 - 79 */ @@ -362,7 +364,7 @@ set_voice_volume (int voice, int volume) vol2 = instr->operators[3]; if ((instr->operators[10] & 0x01)) - { /* Additive synthesis */ + { /* Additive synthesis */ calc_vol (&vol1, volume); calc_vol (&vol2, volume); } @@ -371,8 +373,8 @@ 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[1], vol2); /* Carrier 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 */ } else { /* 4 OP voice */ @@ -412,7 +414,7 @@ set_voice_volume (int voice, int volume) calc_vol (&vol4, volume); break; - default:/* Why ?? */ ; + default: /* Why ?? */ ; } opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1); @@ -616,7 +618,7 @@ freq_to_fnum (int freq, int *block, int *fnum) } static void -opl3_command (int io_addr, const unsigned char addr, const unsigned char val) +opl3_command (int io_addr, unsigned int addr, unsigned int val) { int i; @@ -625,7 +627,7 @@ opl3_command (int io_addr, const unsigned char addr, const unsigned char val) * register. The OPL-3 survives with just two INBs */ - OUTB (addr, io_addr); /* Select register */ + OUTB ((unsigned char) (addr & 0xff), io_addr); /* Select register */ if (!opl3_enabled) tenmicrosec (); @@ -633,7 +635,7 @@ opl3_command (int io_addr, const unsigned char addr, const unsigned char val) for (i = 0; i < 2; i++) INB (io_addr); - OUTB (val, io_addr + 1); /* Write to register */ + OUTB ((unsigned char) (val & 0xff), io_addr + 1); /* Write to register */ if (!opl3_enabled) { @@ -849,8 +851,9 @@ opl3_controller (int dev, int voice, int ctrl_num, int value) data = fnum & 0xff; /* Least significant bits of fnumber */ opl3_command (map->ioaddr, FNUM_LOW + map->voice_num, data); - data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3); /* KEYON|OCTAVE|MS bits - * of f-num */ + data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3); + /* KEYON|OCTAVE|MS bits * of f-num */ + voices[voice].keyon_byte = data; opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, data); break; @@ -892,6 +895,9 @@ opl3_init (long mem_start) { int i; + PERMANENT_MALLOC(struct sbi_instrument *, instrmap, + SBFM_MAXINSTR * sizeof (*instrmap), mem_start); + synth_devs[num_synths++] = &opl3_operations; fm_model = 0; opl3_ok = 1; @@ -902,7 +908,9 @@ opl3_init (long mem_start) 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) diff --git a/sys/i386/isa/sound/os.h b/sys/i386/isa/sound/os.h index fba20980c3f0..9d18b6a25adf 100644 --- a/sys/i386/isa/sound/os.h +++ b/sys/i386/isa/sound/os.h @@ -3,7 +3,7 @@ /* * OS specific settings for FreeBSD * - * Copyright by Hannu Savolainen 1993 + * 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 @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * This should be used as an example when porting the driver to a new + * This chould be used as an example when porting the driver to a new * operating systems. * * What you should do is to rewrite the soundcard.c and os.h (this file). @@ -44,7 +44,6 @@ #include "param.h" #include "systm.h" -#include "kernel.h" #include "ioctl.h" #include "tty.h" #include "proc.h" @@ -52,6 +51,7 @@ #include "conf.h" #include "file.h" #include "uio.h" +#include "kernel.h" #include "syslog.h" #include "errno.h" #include "malloc.h" @@ -63,10 +63,6 @@ */ #ifdef CONFIGURE_SOUNDCARD -/* lbolt is required by the FreeBSD version (only???) */ -extern int __timeout_val; -extern int __process_aborting; - /* * select() is currently implemented in Linux specific way. Don't enable. * I don't remember what the SHORT_BANNERS means so forget it. @@ -163,14 +159,25 @@ typedef struct uio snd_rw_buf; * The following macros define an interface to the process management. */ +struct snd_wait { + int mode; int aborting; + }; + /* * DEFINE_WAIT_QUEUE is used where a wait queue is required. It must define * a structure which can be passed as a parameter to a sleep(). The second * parameter is name of a flag variable (must be defined as int). */ -#define DEFINE_WAIT_QUEUE(qname, flag) static int *qname = NULL; static int flag = 0 +#define DEFINE_WAIT_QUEUE(qname, flag) static int *qname = NULL; \ + static volatile struct snd_wait flag = {0} /* Like the above but defines an array of wait queues and flags */ -#define DEFINE_WAIT_QUEUES(qname, flag) static int *qname = {NULL}; static int flag = {0} +#define DEFINE_WAIT_QUEUES(qname, flag) static int *qname = {NULL}; \ + static volatile struct snd_wait flag = {{0}} + +#define RESET_WAIT_QUEUE(q, f) {f.aborting = 0;f.mode = WK_NONE;} +#define SET_ABORT_FLAG(q, f) f.aborting = 1 +#define TIMED_OUT(q, f) (f.mode & WK_TIMEOUT) +#define SOMEONE_WAITING(q, f) (f.mode & WK_SLEEP) /* * This driver handles interrupts little bit nonstandard way. The following * macro is used to test if the current process has received a signal which @@ -179,34 +186,28 @@ typedef struct uio snd_rw_buf; * 1 or 0 could be returned (1 should be better than 0). * I'm not sure if the following is correct for FreeBSD. */ -#define PROCESS_ABORTING (__process_aborting | curproc->p_sig) -/* - * REQUEST_TIMEOUT is called before sleep. It shoud ensure that the - * process is woken up after given number of ticks (1/HZ secs.). - * The wqueue gives the wait queue. - */ -#define REQUEST_TIMEOUT(nticks, wqueue) __timeout_val = nticks; +#define PROCESS_ABORTING(q, f) (f.aborting | curproc->p_sig) /* * The following macro calls sleep. It should be implemented such that * 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() - * The second parameter is a flag. It must be initialized to 1 before sleep - * and to zero after proces continues. + * 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 + * in ticks. Zero means no timeout. */ -#define INTERRUPTIBLE_SLEEP_ON(on_what, flag) \ +#define DO_SLEEP(q, f, time_limit) \ { \ - flag = 1; \ - flag=tsleep((caddr_t)&(on_what), (PRIBIO-5)|PCATCH, "sndint", __timeout_val); \ - if(flag == ERESTART) __process_aborting = 1;\ - else __process_aborting = 0;\ - __timeout_val = 0; \ - flag = 0; \ + int flag, chn; \ + f.mode = WK_SLEEP; \ + q = &chn; \ + 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(who) wakeup((caddr_t)&(who)) +#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 @@ -215,6 +216,7 @@ typedef struct uio snd_rw_buf; */ #ifndef HZ +extern int hz; #define HZ hz #endif @@ -223,9 +225,9 @@ typedef struct uio snd_rw_buf; * ticks. This can overflow, so the timeout might be real big... * */ -#define GET_TIME() get_time() extern long get_time(void); -/*#define GET_TIME() (lbolt)*/ /* Returns current time (1/HZ secs since boot) */ +#define GET_TIME() get_time() +/*#define GET_TIME() (lbolt) */ /* Returns current time (1/HZ secs since boot) */ /* * The following three macros are called before and after atomic @@ -248,7 +250,11 @@ extern long get_time(void); */ #define INB inb -#define OUTB(addr, data) outb(data, addr) +/* + * 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);} /* memcpy() was not defined og 386bsd. Lets define it here */ #define memcpy(d, s, c) bcopy(s, d, c) @@ -273,6 +279,32 @@ extern long get_time(void); #define KERNEL_MALLOC(nbytes) malloc(nbytes, M_TEMP, M_WAITOK) #define KERNEL_FREE(addr) free(addr, M_TEMP) +/* + * The macro PERMANENT_MALLOC(typecast, mem_ptr, size, linux_ptr) + * returns size bytes of + * (kernel virtual) memory which will never get freed by the driver. + * This macro is called only during boot. The linux_ptr is a linux specific + * parameter which should be ignored in other operating systems. + * The mem_ptr is a pointer variable where the macro assigns pointer to the + * 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_TEMP, M_WAITOK) + +/* + * The macro DEFINE_TIMER defines variables for the ACTIVATE_TIMER if + * required. The name is the variable/name to be used and the proc is + * the procedure to be called when the timer expires. + */ + +#define DEFINE_TIMER(name, proc) + +/* + * The ACTIVATE_TIMER requests system to call 'proc' after 'time' ticks. + */ + +#define ACTIVATE_TIMER(name, proc, time) \ + timeout((timeout_func_t)proc, 0, time); /* * The rest of this file is not complete yet. The functions using these * macros will not work diff --git a/sys/i386/isa/sound/pas.h b/sys/i386/isa/sound/pas.h index 4dadea3713b8..797c8fdbcd24 100644 --- a/sys/i386/isa/sound/pas.h +++ b/sys/i386/isa/sound/pas.h @@ -132,6 +132,7 @@ #define PAS_PLUS 1 #define PAS_CDPC 2 #define PAS_16 3 +#define PAS_16D 4 #ifdef DEFINE_TRANSLATIONS char I_C_2_PCM_DMA_translate[] = /* R W PCM PCM DMA channel value translations */ @@ -141,11 +142,11 @@ char E_C_MPU401_IRQ_translate[] = /* R W MIDI MPU401 emulation IRQ value translation */ { 0x00, 0x00, 0x01, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x05, 0x06, 0x07 }; char E_C_SB_IRQ_translate[] = /* R W PCM SB emulation IRQ translate */ - { 0x00, 0x00, 0x08, 0x10, 0x00, 0x18, 0x00, 0x20, 0x00, 0x00, 0x28, 0x30, 0x38 }; + { 0x00, 0x00, 0x08, 0x10, 0x00, 0x18, 0x00, 0x20, 0x00, 0x00, 0x28, 0x30, 0x38, 0, 0 }; char E_C_SB_DMA_translate[] = /* R W PCM SB emulation DMA translate */ - { 0x00, 0x40, 0x80, 0xC0 }; + { 0x00, 0x40, 0x80, 0xC0, 0, 0, 0, 0 }; 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, 3, 0, 2, 3 }; + { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 4, 0, 2, 3 }; #else extern char I_C_2_PCM_DMA_translate[]; /* R W PCM PCM DMA channel value translations */ extern char I_C_3_PCM_IRQ_translate[]; /* R W PCM PCM IRQ level value translation */ diff --git a/sys/i386/isa/sound/pas2_card.c b/sys/i386/isa/sound/pas2_card.c index 96fe651fbaac..c89dd33f832e 100644 --- a/sys/i386/isa/sound/pas2_card.c +++ b/sys/i386/isa/sound/pas2_card.c @@ -1,7 +1,7 @@ #define _PAS2_CARD_C_ #define SND_SA_INTERRUPT /* - * linux/kernel/chr_drv/sound/pas2_card.c + * sound/pas2_card.c * * Detection routine for the Pro Audio Spectrum cards. * @@ -47,7 +47,7 @@ static int pas_irq = 0; static char pas_model; static char *pas_model_names[] = -{"", "Pro AudioSpectrum+", "CDPC", "Pro AudioSpectrum 16"}; +{"", "Pro AudioSpectrum+", "CDPC", "Pro AudioSpectrum 16", "Pro AudioSpectrum 16D"}; /* pas_read() and pas_write() are equivalents of INB() and OUTB() */ /* These routines perform the I/O address translation required */ @@ -79,7 +79,7 @@ pasintr (int unused) 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) { @@ -100,39 +100,6 @@ pasintr (int unused) } -static int -set_pas_irq (int interrupt_level) -{ -#ifdef linux - int retcode; - struct sigaction sa; - - pas_write (0xff, INTERRUPT_STATUS); /* Reset pending interrupts */ - - sa.sa_handler = pasintr; - -#ifdef SND_SA_INTERRUPT - sa.sa_flags = SA_INTERRUPT; -#else - sa.sa_flags = 0; -#endif - - sa.sa_mask = 0; - sa.sa_restorer = NULL; - - retcode = irqaction (interrupt_level, &sa); - - if (retcode < 0) - { - printk ("ProAudioSpectrum: IRQ%d already in use\n", interrupt_level); - } - return retcode; -#else - /* # error This routine does not work with this OS */ - return EINVAL; -#endif -} - int pas_set_intr (int mask) { @@ -143,7 +110,7 @@ pas_set_intr (int mask) if (!pas_intr_mask) { - if ((err = set_pas_irq (pas_irq)) < 0) + if ((err = snd_set_irq_handler (pas_irq, pasintr)) < 0) return err; } pas_intr_mask |= mask; @@ -163,7 +130,7 @@ pas_remove_intr (int mask) if (!pas_intr_mask) { - RELEASE_IRQ (pas_irq); + snd_release_irq (pas_irq); } return 0; } @@ -230,20 +197,28 @@ 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. + */ +#ifdef SYMPHONY_PAS + OUTB (0x05, 0xa8); + OUTB (0x60, 0xa9); +#endif + #ifdef BROKEN_BUS_CLOCK pas_write (S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND | S_C_1_FM_EMULATE_CLOCK, SYSTEM_CONFIGURATION_1); #else /* pas_write(S_C_1_PCS_ENABLE, SYSTEM_CONFIGURATION_1); */ pas_write (S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND, SYSTEM_CONFIGURATION_1); #endif - /* pas_write(S_C_2_PCM_16_BIT, SYSTEM_CONFIGURATION_2); Don't do this */ pas_write (0x18, SYSTEM_CONFIGURATION_3); /* ??? */ pas_write (F_F_MIXER_UNMUTE | 0x01, FILTER_FREQUENCY); /* Sets mute off and * selects filter rate * of 17.897 kHz */ - if (pas_model == PAS_16) + if (pas_model == PAS_16 || pas_model == PAS_16D) pas_write (8, PRESCALE_DIVIDER); else pas_write (0, PRESCALE_DIVIDER); @@ -253,13 +228,35 @@ config_pas_hw (struct address_info *hw_config) #if !defined(EXCLUDE_SB_EMULATION) || !defined(EXCLUDE_SB) - /* Turn on Sound Blaster compatibility */ - /* bit 1 = SB emulation */ - /* bit 0 = MPU401 emulation (CDPC only :-( ) */ - pas_write (0x02, COMPATIBILITY_ENABLE); + { + struct address_info *sb_config; - /* "Emulation address" */ - pas_write ((SBC_BASE >> 4) & 0x0f, EMULATION_ADDRESS); + if ((sb_config = sound_getconf (SNDCARD_SB))) + { + unsigned char irq_dma; + + /* Turn on Sound Blaster compatibility */ + /* bit 1 = SB emulation */ + /* bit 0 = MPU401 emulation (CDPC only :-( ) */ + pas_write (0x02, COMPATIBILITY_ENABLE); + + /* "Emulation address" */ + pas_write ((sb_config->io_base >> 4) & 0x0f, EMULATION_ADDRESS); + + if (!E_C_SB_DMA_translate[sb_config->dma]) + printk ("\n\nPAS16 Warning: Invalid SB DMA %d\n\n", + sb_config->dma); + + if (!E_C_SB_IRQ_translate[sb_config->irq]) + printk ("\n\nPAS16 Warning: Invalid SB IRQ %d\n\n", + sb_config->irq); + + irq_dma = E_C_SB_DMA_translate[sb_config->dma] | + E_C_SB_IRQ_translate[sb_config->irq]; + + pas_write (irq_dma, EMULATION_CONFIGURATION); + } + } #endif if (!ok) @@ -305,7 +302,7 @@ detect_pas_hw (struct address_info *hw_config) if (board_id != foo) /* Not a PAS2 */ return 0; - if ((pas_model = O_M_1_to_card[pas_read (OPERATION_MODE_1) & 0x0f])); + pas_model = O_M_1_to_card[pas_read (OPERATION_MODE_1) & 0x0f]; return pas_model; } @@ -330,11 +327,11 @@ attach_pas_card (long mem_start, struct address_info *hw_config) mem_start = pas_pcm_init (mem_start, hw_config); #endif -# if !defined(EXCLUDE_SB_EMULATION) && !defined(EXCLUDE_SB) +#if !defined(EXCLUDE_SB_EMULATION) && !defined(EXCLUDE_SB) sb_dsp_disable_midi (); /* The SB emulation don't support * midi */ -# endif +#endif #ifndef EXCLUDE_YM3812 enable_opl3_mode (0x388, 0x38a, 0); @@ -350,7 +347,6 @@ attach_pas_card (long mem_start, struct address_info *hw_config) } } - printk ("\n"); return mem_start; } diff --git a/sys/i386/isa/sound/pas2_midi.c b/sys/i386/isa/sound/pas2_midi.c index 1a605905420f..5620d7294dd9 100644 --- a/sys/i386/isa/sound/pas2_midi.c +++ b/sys/i386/isa/sound/pas2_midi.c @@ -1,5 +1,5 @@ /* - * linux/kernel/chr_drv/sound/pas2_midi.c + * sound/pas2_midi.c * * The low level driver for the PAS Midi Interface. * @@ -79,7 +79,7 @@ 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; } @@ -122,7 +122,7 @@ 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; /* Upper layer will call again */ } @@ -212,7 +212,7 @@ pas_buffer_status (int dev) static struct midi_operations pas_midi_operations = { - {"Pro Audio Spectrum", 0}, + {"Pro Audio Spectrum", 0, 0, SNDCARD_PAS}, pas_midi_open, pas_midi_close, pas_midi_ioctl, @@ -283,11 +283,11 @@ pas_midi_interrupt (void) if (stat & M_S_OUTPUT_OVERRUN) { - printk ("MIDI output overrun %02x,%02x,%d \n", pas_read (MIDI_FIFO_STATUS), stat, ofifo_bytes); + printk ("MIDI output overrun %x,%x,%d \n", pas_read (MIDI_FIFO_STATUS), stat, ofifo_bytes); ofifo_bytes = 100; } - pas_write (stat, MIDI_STATUS);/* Acknowledge interrupts */ + pas_write (stat, MIDI_STATUS); /* Acknowledge interrupts */ } #endif diff --git a/sys/i386/isa/sound/pas2_mixer.c b/sys/i386/isa/sound/pas2_mixer.c index 33135d24e859..0ec67533c348 100644 --- a/sys/i386/isa/sound/pas2_mixer.c +++ b/sys/i386/isa/sound/pas2_mixer.c @@ -1,7 +1,7 @@ #define _PAS2_MIXER_C_ /* - * linux/kernel/chr_drv/sound/pas2_mixer.c + * sound/pas2_mixer.c * * Mixer routines for the Pro Audio Spectrum cards. * @@ -39,14 +39,14 @@ extern int translat_code; -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 | \ SOUND_MASK_CD | SOUND_MASK_ALTPCM) #define SUPPORTED_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD /*|SOUND_MASK_ALTPCM*/ | SOUND_MASK_IMIX | \ + SOUND_MASK_CD | SOUND_MASK_ALTPCM | SOUND_MASK_IMIX | \ SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_RECLEV | \ SOUND_MASK_MUTE | SOUND_MASK_ENHANCE | SOUND_MASK_LOUD) @@ -87,7 +87,7 @@ mixer_output (int right_vol, int left_vol, int div, int bits, } if (bits == P_M_MV508_BASS || bits == P_M_MV508_TREBLE) - { /* Bass and trebble are mono devices */ + { /* Bass and trebble are mono devices */ pas_write (P_M_MV508_ADDRESS | bits, PARALLEL_MIXER); pas_write (left, PARALLEL_MIXER); right_vol = left_vol; @@ -331,7 +331,7 @@ mixer_get_levels (struct sb_mixer_levels *user_l) struct sb_mixer_levels l; l.master.r = ((((levels[SOUND_MIXER_VOLUME] >> 8) & 0x7f) * 15) + 50) / 100; /* Master */ - l.master.l = (((levels[SOUND_MIXER_VOLUME] & 0x7f) * 15) + 50) / 100; /* Master */ + l.master.l = (((levels[SOUND_MIXER_VOLUME] & 0x7f) * 15) + 50) / 100; /* Master */ l.line.r = ((getmixer (SOUND_MIXER_LINE, P_M_MV508_RIGHT) * 15) + 50) / 100; /* Line */ l.line.l = ((getmixer (SOUND_MIXER_LINE, P_M_MV508_LEFT) * 15) + 50) / 100; diff --git a/sys/i386/isa/sound/pas2_pcm.c b/sys/i386/isa/sound/pas2_pcm.c index 878de5aaca94..f8b2238369ce 100644 --- a/sys/i386/isa/sound/pas2_pcm.c +++ b/sys/i386/isa/sound/pas2_pcm.c @@ -1,6 +1,6 @@ #define _PAS2_PCM_C_ /* - * linux/kernel/chr_drv/sound/pas2_pcm.c + * sound/pas2_pcm.c * * The low level driver for the Pro Audio Spectrum ADC/DAC. * @@ -100,7 +100,7 @@ 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 */ } return pcm_channels; @@ -148,6 +148,8 @@ pas_pcm_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) break; case SOUND_PCM_WRITE_CHANNELS: + if (local) + return pcm_set_channels (arg); return IOCTL_OUT (arg, pcm_set_channels (IOCTL_IN (arg))); break; @@ -200,12 +202,6 @@ pas_pcm_open (int dev, int mode) TRACE (printk ("pas2_pcm.c: static int pas_pcm_open(int mode = %X)\n", mode)); - if (mode != OPEN_READ && mode != OPEN_WRITE) - { - printk ("PAS2: Attempt to open PCM device for simultaneous read and write"); - return RET_ERROR (EINVAL); - } - if ((err = pas_set_intr (PAS_PCM_INTRBITS)) < 0) return err; @@ -217,10 +213,6 @@ pas_pcm_open (int dev, int mode) pcm_count = 0; - pcm_set_bits (8); - pcm_set_channels (1); - pcm_set_speed (DSP_DEFAULT_SPEED); - return 0; } @@ -242,7 +234,8 @@ pas_pcm_close (int dev) } static void -pas_pcm_output_block (int dev, unsigned long buf, int count, int intrflag) +pas_pcm_output_block (int dev, unsigned long buf, int count, + int intrflag, int restart_dma) { unsigned long flags, cnt; @@ -251,7 +244,6 @@ pas_pcm_output_block (int dev, unsigned long buf, int count, int intrflag) cnt = count; if (sound_dsp_dmachan[dev] > 3) cnt >>= 1; - cnt--; if (sound_dma_automode[dev] && intrflag && @@ -263,11 +255,11 @@ pas_pcm_output_block (int dev, unsigned long buf, int count, int intrflag) pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE, PCM_CONTROL); - DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); + if (restart_dma) + DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); if (sound_dsp_dmachan[dev] > 3) count >>= 1; - count--; if (count != pcm_count) { @@ -288,7 +280,8 @@ pas_pcm_output_block (int dev, unsigned long buf, int count, int intrflag) } static void -pas_pcm_start_input (int dev, unsigned long buf, int count, int intrflag) +pas_pcm_start_input (int dev, unsigned long buf, int count, + int intrflag, int restart_dma) { unsigned long flags; int cnt; @@ -298,7 +291,6 @@ pas_pcm_start_input (int dev, unsigned long buf, int count, int intrflag) cnt = count; if (sound_dsp_dmachan[dev] > 3) cnt >>= 1; - cnt--; if (sound_dma_automode[my_devnum] && intrflag && @@ -307,13 +299,12 @@ pas_pcm_start_input (int dev, unsigned long buf, int count, int intrflag) DISABLE_INTR (flags); - DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); + if (restart_dma) + DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); if (sound_dsp_dmachan[dev] > 3) count >>= 1; - count--; - if (count != pcm_count) { pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY); @@ -374,6 +365,7 @@ pas_pcm_init (long mem_start, struct address_info *hw_config) { dsp_devs[my_devnum = num_dspdevs++] = &pas_pcm_operations; sound_dsp_dmachan[my_devnum] = hw_config->dma; +#ifndef PAS_NO_AUTODMA if (hw_config->dma > 3) { sound_buffcounts[my_devnum] = 1; @@ -386,6 +378,11 @@ pas_pcm_init (long mem_start, struct address_info *hw_config) sound_buffsizes[my_devnum] = DSP_BUFFSIZE; sound_dma_automode[my_devnum] = 1; } +#else + sound_buffcounts[my_devnum] = 2; + sound_buffsizes[my_devnum] = DSP_BUFFSIZE; + sound_dma_automode[my_devnum] = 0; +#endif } else printk ("PAS2: Too many PCM devices available\n"); @@ -413,7 +410,7 @@ pas_pcm_interrupt (unsigned char status, int cause) { case PCM_DAC: - DMAbuf_outputintr (my_devnum); + DMAbuf_outputintr (my_devnum, 1); break; case PCM_ADC: diff --git a/sys/i386/isa/sound/patmgr.c b/sys/i386/isa/sound/patmgr.c index 140a42845e5b..f5697ae265a5 100644 --- a/sys/i386/isa/sound/patmgr.c +++ b/sys/i386/isa/sound/patmgr.c @@ -1,5 +1,5 @@ /* - * linux/kernel/chr_drv/sound/patmgr.c + * sound/patmgr.c * * The patch maneger interface for the /dev/sequencer * @@ -58,6 +58,8 @@ pmgr_open (int dev) return RET_ERROR (EBUSY); pmgr_opened[dev] = 1; + RESET_WAIT_QUEUE (server_procs[dev], server_wait_flag[dev]); + return 0; } @@ -71,8 +73,8 @@ pmgr_release (int dev) mbox[dev]->key = PM_ERROR; mbox[dev]->parm1 = RET_ERROR (EIO); - if (appl_wait_flag) - WAKE_UP (appl_proc); + if (SOMEONE_WAITING (appl_proc, appl_wait_flag)) + WAKE_UP (appl_proc, appl_wait_flag); } pmgr_opened[dev] = 0; @@ -90,13 +92,14 @@ pmgr_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) return RET_ERROR (EIO); } - while (!ok && !PROCESS_ABORTING) + while (!ok && !PROCESS_ABORTING (server_procs[dev], server_wait_flag[dev])) { DISABLE_INTR (flags); - while (!(mbox[dev] && msg_direction[dev] == A_TO_S) && !PROCESS_ABORTING) + while (!(mbox[dev] && msg_direction[dev] == A_TO_S) && + !PROCESS_ABORTING (server_procs[dev], server_wait_flag[dev])) { - INTERRUPTIBLE_SLEEP_ON (server_procs[dev], server_wait_flag[dev]); + DO_SLEEP (server_procs[dev], server_wait_flag[dev], 0); } if (mbox[dev] && msg_direction[dev] == A_TO_S) @@ -158,9 +161,9 @@ pmgr_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) COPY_FROM_USER (&((char *) mbox[dev])[4], buf, 4, count - 4); msg_direction[dev] = S_TO_A; - if (appl_wait_flag) + if (SOMEONE_WAITING (appl_proc, appl_wait_flag)) { - WAKE_UP (appl_proc); + WAKE_UP (appl_proc, appl_wait_flag); } } @@ -185,12 +188,12 @@ pmgr_access (int dev, struct patmgr_info *rec) mbox[dev] = rec; msg_direction[dev] = A_TO_S; - if (server_wait_flag[dev]) + if (SOMEONE_WAITING (server_procs[dev], server_wait_flag[dev])) { - WAKE_UP (server_procs[dev]); + WAKE_UP (server_procs[dev], server_wait_flag[dev]); } - INTERRUPTIBLE_SLEEP_ON (appl_proc, appl_wait_flag); + DO_SLEEP (appl_proc, appl_wait_flag, 0); if (msg_direction[dev] != S_TO_A) { @@ -239,12 +242,12 @@ pmgr_inform (int dev, int event, unsigned long p1, unsigned long p2, mbox[dev]->parm3 = p3; msg_direction[dev] = A_TO_S; - if (server_wait_flag[dev]) + if (SOMEONE_WAITING (server_procs[dev], server_wait_flag[dev])) { - WAKE_UP (server_procs[dev]); + WAKE_UP (server_procs[dev], server_wait_flag[dev]); } - INTERRUPTIBLE_SLEEP_ON (appl_proc, appl_wait_flag); + DO_SLEEP (appl_proc, appl_wait_flag, 0); if (mbox[dev]) KERNEL_FREE (mbox[dev]); mbox[dev] = NULL; diff --git a/sys/i386/isa/sound/pro_midi.c b/sys/i386/isa/sound/pro_midi.c index 606657d403da..b9ffa26a9ab2 100644 --- a/sys/i386/isa/sound/pro_midi.c +++ b/sys/i386/isa/sound/pro_midi.c @@ -1,5 +1,5 @@ /* - * Copyright by UWM -- comments to soft-eng@cs.uwm.edu + * 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 @@ -37,140 +37,148 @@ /** Structure for handling operations **/ -static struct generic_midi_operations pro_midi_operations = { +static struct generic_midi_operations pro_midi_operations = +{ - {"Pro_Audio_Spectrum 16 MV101", 0}, - pro_midi_open, - pro_midi_close, - pro_midi_write, - pro_midi_read + {"Pro_Audio_Spectrum 16 MV101", 0}, + pro_midi_open, + pro_midi_close, + pro_midi_write, + pro_midi_read }; /* - * Note! Note! Note! - * Follow the same model for any other attach function you + * Note! Note! Note! Follow the same model for any other attach function you * may write */ -long pro_midi_attach( long mem_start) +long +pro_midi_attach (long mem_start) { pro_midi_dev = num_generic_midis; generic_midi_devs[num_generic_midis++] = &pro_midi_operations; return mem_start; -} +} -int pro_midi_open(int dev, int mode) +int +pro_midi_open (int dev, int mode) { - int intr_mask, s; + int intr_mask, s; - s = splhigh(); + s = splhigh (); - /* Reset the input and output FIFO pointers */ + /* Reset the input and output FIFO pointers */ - outb(MIDI_CONTROL,M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO); + outb (MIDI_CONTROL, M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO); - /* Get the interrupt status */ + /* Get the interrupt status */ - intr_mask = inb(INTERRUPT_MASK); + intr_mask = inb (INTERRUPT_MASK); - /* Enable MIDI IRQ */ + /* Enable MIDI IRQ */ - intr_mask |= I_M_MIDI_IRQ_ENABLE; - outb(INTERRUPT_MASK, intr_mask); + intr_mask |= I_M_MIDI_IRQ_ENABLE; + outb (INTERRUPT_MASK, intr_mask); /* Enable READ/WRITE on MIDI port. This part is quite unsure though */ - outb(MIDI_CONTROL,M_C_ENA_OUTPUT_IRQ | M_C_ENA_INPUT_IRQ); + outb (MIDI_CONTROL, M_C_ENA_OUTPUT_IRQ | M_C_ENA_INPUT_IRQ); /* Acknowledge pending interrupts */ - outb(MIDI_STATUS,0xff); + outb (MIDI_STATUS, 0xff); - splx(s); + splx (s); - return(ESUCCESS); + return (ESUCCESS); } -void pro_midi_close(int dev) +void +pro_midi_close (int dev) { - int intr_mask; + int intr_mask; - /* Clean up */ + /* Clean up */ - outb(MIDI_CONTROL,M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO); - intr_mask = inb(INTERRUPT_MASK); - intr_mask &= ~I_M_MIDI_IRQ_ENABLE; - outb(INTERRUPT_MASK,intr_mask); + outb (MIDI_CONTROL, M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO); + intr_mask = inb (INTERRUPT_MASK); + intr_mask &= ~I_M_MIDI_IRQ_ENABLE; + outb (INTERRUPT_MASK, intr_mask); - return; + return; } -int pro_midi_write(int dev, struct uio *uio) +int +pro_midi_write (int dev, struct uio *uio) { - int s; - unsigned char data; + int s; + unsigned char data; - /* printf("midi: Going to do write routine..\n"); */ - while(uio->uio_resid) { + /* printf("midi: Going to do write routine..\n"); */ + while (uio->uio_resid) + { - if ( uiomove(&data,1,uio) ) return(ENOTTY); + if (uiomove (&data, 1, uio)) + return (ENOTTY); - s = splhigh(); + s = splhigh (); - DELAY(30); - outb(MIDI_DATA,data); - DELAY(70); /* Ze best pause.. find a better one if - * you can :) - */ - splx(s); - } + DELAY (30); + outb (MIDI_DATA, data); + DELAY (70); /* Ze best pause.. find a better one if you + * can :) */ + splx (s); + } - return(ESUCCESS); + return (ESUCCESS); } -int pro_midi_read(int dev, struct uio *uio) +int +pro_midi_read (int dev, struct uio *uio) { - int s; - unsigned char data; + int s; + unsigned char data; - s = splhigh(); + s = splhigh (); - /* For each uio_iov[] entry .... */ + /* For each uio_iov[] entry .... */ - while (uio->uio_resid) { + while (uio->uio_resid) + { - if((( inb(MIDI_STATUS) & M_S_INPUT_AVAIL) == 0 ) && - ((inb(MIDI_FIFO_STATUS) & MIDI_INPUT_AVAILABLE) == 0 ) ) + if (((inb (MIDI_STATUS) & M_S_INPUT_AVAIL) == 0) && + ((inb (MIDI_FIFO_STATUS) & MIDI_INPUT_AVAILABLE) == 0)) - data = 0xfe; - else - data = inb(MIDI_DATA); + data = 0xfe; + else + data = inb (MIDI_DATA); - if ( uiomove(&data, 1 , uio)) { + if (uiomove (&data, 1, uio)) + { - printf("midi: Bad copyout()!\n"); - return(ENOTTY); + printf ("midi: Bad copyout()!\n"); + return (ENOTTY); - } + } - } - splx(s); - return(ESUCCESS); + } + splx (s); + return (ESUCCESS); } diff --git a/sys/i386/isa/sound/sb.h b/sys/i386/isa/sound/sb.h new file mode 100644 index 000000000000..bb8ae12d7e60 --- /dev/null +++ b/sys/i386/isa/sound/sb.h @@ -0,0 +1,28 @@ +#define DSP_RESET (sbc_base + 0x6) +#define DSP_READ (sbc_base + 0xA) +#define DSP_WRITE (sbc_base + 0xC) +#define DSP_COMMAND (sbc_base + 0xC) +#define DSP_STATUS (sbc_base + 0xC) +#define DSP_DATA_AVAIL (sbc_base + 0xE) +#define DSP_DATA_AVL16 (sbc_base + 0xF) +#define MIXER_ADDR (sbc_base + 0x4) +#define MIXER_DATA (sbc_base + 0x5) +#define OPL3_LEFT (sbc_base + 0x0) +#define OPL3_RIGHT (sbc_base + 0x2) +#define OPL3_BOTH (sbc_base + 0x8) +/* DSP Commands */ + +#define DSP_CMD_SPKON 0xD1 +#define DSP_CMD_SPKOFF 0xD3 +#define DSP_CMD_DMAON 0xD0 +#define DSP_CMD_DMAOFF 0xD4 + +#define IMODE_NONE 0 +#define IMODE_OUTPUT 1 +#define IMODE_INPUT 2 +#define IMODE_INIT 3 +#define IMODE_MIDI 4 + +#define NORMAL_MIDI 0 +#define UART_MIDI 1 + diff --git a/sys/i386/isa/sound/sb16_dsp.c b/sys/i386/isa/sound/sb16_dsp.c new file mode 100644 index 000000000000..8787b2727bcb --- /dev/null +++ b/sys/i386/isa/sound/sb16_dsp.c @@ -0,0 +1,641 @@ +/* + * sound/sb16_dsp.c + * + * The low level driver for the SoundBlaster DSP chip. + * + * (C) 1993 J. Schubert (jsb@sth.ruhr-uni-bochum.de) + * + * based on SB-driver by (C) Hannu Savolainen + * + * 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. + * + */ + +#define DEB(x) +#define DEB1(x) +/* + #define DEB_DMARES + */ +#include "sound_config.h" +#include "sb.h" +#include "sb_mixer.h" + +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_AUDIO) && !defined(EXCLUDE_SBPRO) + +extern int sbc_base; + +static int sb16_dsp_ok = 0; /* Set to 1 after successful initialization */ +static int dsp_16bit = 0; +static int dsp_stereo = 0; +static int dsp_current_speed = 8000; /*DSP_DEFAULT_SPEED; */ +static int dsp_busy = 0; +static int dma16, dma8; +static unsigned long dsp_count = 0; + +static int irq_mode = IMODE_NONE; /* IMODE_INPUT, IMODE_OUTPUT or + + IMODE_NONE */ +static int my_dev = 0; + +static volatile int intr_active = 0; + +static int sb16_dsp_open (int dev, int mode); +static void sb16_dsp_close (int dev); +static void sb16_dsp_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart); +static void sb16_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart); +static int sb16_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local); +static int sb16_dsp_prepare_for_input (int dev, int bsize, int bcount); +static int sb16_dsp_prepare_for_output (int dev, int bsize, int bcount); +static void sb16_dsp_reset (int dev); +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 = +{ + "SoundBlaster 16", + sb16_dsp_open, + sb16_dsp_close, + sb16_dsp_output_block, + sb16_dsp_start_input, + sb16_dsp_ioctl, + sb16_dsp_prepare_for_input, + sb16_dsp_prepare_for_output, + sb16_dsp_reset, + sb16_dsp_halt, + NULL, + NULL +}; + +static int +sb_dsp_command01 (unsigned char val) +{ + int i = 1 << 16; + + while (--i & (!INB (DSP_STATUS) & 0x80)); + if (!i) + printk ("SB16 sb_dsp_command01 Timeout\n"); + return sb_dsp_command (val); +} + +static int +wait_data_avail (int t) +{ + int loopc = 5000000; + + t += GET_TIME (); + do + { + if (INB (DSP_DATA_AVAIL) & 0x80) + return 1; + } + while (--loopc && GET_TIME () < t); + printk ("!data_avail l=%d\n", loopc); + return 0; +} + +static int +read_dsp (int t) +{ + if (!wait_data_avail (t)) + return -1; + else + return INB (DSP_READ); +} + +static int +dsp_ini2 (void) +{ +#if 0 + /* sb_setmixer(0x83, sb_getmixer(0x83) | 0x03); */ + sb_dsp_command (0xe2); + sb_dsp_command (0x76); /* E0 ??? */ + sb_dsp_command (0xe2); + sb_dsp_command (0x30); /* A0 ??? */ + sb_dsp_command (0xe4); + sb_dsp_command (0xaa); + sb_dsp_command (0xe8); + if (read_dsp (100) != 0xaa) + printk ("Error dsp_ini2\n"); +#endif + return 0; +} +/* + static char *dsp_getmessage(unsigned char command,int maxn) + { + static char buff[100]; + int n=0; + + sb_dsp_command(command); + while(n 44100) + mode = 44100; + dsp_current_speed = mode; + } + return mode; +} + +static int +dsp_set_stereo (int mode) +{ + DEB (printk ("dsp_set_stereo(%d)\n", mode)); + + dsp_stereo = mode; + + return mode; +} + +static int +dsp_set_bits (int arg) +{ + DEB (printk ("dsp_set_bits(%d)\n", arg)); + + if (arg) + switch (arg) + { + case 8: + dsp_16bit = 0; + break; + case 16: + dsp_16bit = 1; + break; + default: + return RET_ERROR (EINVAL); + } + return dsp_16bit ? 16 : 8; +} + +static int +sb16_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) +{ + switch (cmd) + { + case SOUND_PCM_WRITE_RATE: + if (local) + return dsp_set_speed (arg); + return IOCTL_OUT (arg, dsp_set_speed (IOCTL_IN (arg))); + + case SOUND_PCM_READ_RATE: + if (local) + return dsp_current_speed; + return IOCTL_OUT (arg, dsp_current_speed); + + case SNDCTL_DSP_STEREO: + if (local) + return dsp_set_stereo (arg); + return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg))); + + case SOUND_PCM_WRITE_CHANNELS: + if (local) + return dsp_set_stereo (arg - 1) + 1; + return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg) - 1) + 1); + + case SOUND_PCM_READ_CHANNELS: + if (local) + return dsp_stereo + 1; + return IOCTL_OUT (arg, dsp_stereo + 1); + + case SNDCTL_DSP_SAMPLESIZE: + if (local) + return dsp_set_bits (arg); + return IOCTL_OUT (arg, dsp_set_bits (IOCTL_IN (arg))); + + case SOUND_PCM_READ_BITS: + if (local) + return dsp_16bit ? 16 : 8; + return IOCTL_OUT (arg, dsp_16bit ? 16 : 8); + + case SOUND_PCM_WRITE_FILTER: /* NOT YET IMPLEMENTED */ + if (IOCTL_IN (arg) > 1) + return IOCTL_OUT (arg, RET_ERROR (EINVAL)); + default: + return RET_ERROR (EINVAL); + } + + return RET_ERROR (EINVAL); +} + +static int +sb16_dsp_open (int dev, int mode) +{ + int retval; + + DEB (printk ("sb16_dsp_open()\n")); + if (!sb16_dsp_ok) + { + printk ("SB16 Error: SoundBlaster board not installed\n"); + return RET_ERROR (ENXIO); + } + + if (intr_active) + return RET_ERROR (EBUSY); + + retval = sb_get_irq (); + if (retval < 0) + return retval; + + if (ALLOC_DMA_CHN (dma8)) + { + printk ("SB16: Unable to grab DMA%d\n", dma8); + sb_free_irq (); + return RET_ERROR (EBUSY); + } + + if (dma16 != dma8) + if (ALLOC_DMA_CHN (dma16)) + { + printk ("SB16: Unable to grab DMA%d\n", dma16); + sb_free_irq (); + RELEASE_DMA_CHN (dma8); + return RET_ERROR (EBUSY); + } + + dsp_ini2 (); + + irq_mode = IMODE_NONE; + dsp_busy = 1; + + return 0; +} + +static void +sb16_dsp_close (int dev) +{ + unsigned long flags; + + DEB (printk ("sb16_dsp_close()\n")); + sb_dsp_command01 (0xd9); + sb_dsp_command01 (0xd5); + + DISABLE_INTR (flags); + RELEASE_DMA_CHN (dma8); + + if (dma16 != dma8) + RELEASE_DMA_CHN (dma16); + sb_free_irq (); + dsp_cleanup (); + dsp_busy = 0; + RESTORE_INTR (flags); +} + +static void +sb16_dsp_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart) +{ + unsigned long flags, cnt; + + cnt = count; + if (dsp_16bit) + cnt >>= 1; + cnt--; + +#ifdef DEB_DMARES + printk ("output_block: %x %d %d\n", buf, count, intrflag); + if (intrflag) + { + int pos, chan = sound_dsp_dmachan[dev]; + + DISABLE_INTR (flags); + clear_dma_ff (chan); + disable_dma (chan); + pos = get_dma_residue (chan); + enable_dma (chan); + RESTORE_INTR (flags); + printk ("dmapos=%d %x\n", pos, pos); + } +#endif + if (sound_dma_automode[dev] && + intrflag && + cnt == dsp_count) + { + irq_mode = IMODE_OUTPUT; + intr_active = 1; + return; /* Auto mode on. No need to react */ + } + DISABLE_INTR (flags); + + if (dma_restart) + { + sb16_dsp_halt (dev); + DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); + } + sb_dsp_command (0x41); + sb_dsp_command ((unsigned char) ((dsp_current_speed >> 8) & 0xff)); + sb_dsp_command ((unsigned char) (dsp_current_speed & 0xff)); + sb_dsp_command ((unsigned char) (dsp_16bit ? 0xb6 : 0xc6)); + sb_dsp_command ((unsigned char) ((dsp_stereo ? 0x20 : 0) + + (dsp_16bit ? 0x10 : 0))); + sb_dsp_command01 ((unsigned char) (cnt & 0xff)); + sb_dsp_command ((unsigned char) (cnt >> 8)); + /* sb_dsp_command (0); + sb_dsp_command (0); */ + + RESTORE_INTR (flags); + dsp_count = cnt; + irq_mode = IMODE_OUTPUT; + intr_active = 1; +} + +static void +sb16_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart) +{ + unsigned long flags, cnt; + + cnt = count; + if (dsp_16bit) + cnt >>= 1; + cnt--; + +#ifdef DEB_DMARES + printk ("start_input: %x %d %d\n", buf, count, intrflag); + if (intrflag) + { + int pos, chan = sound_dsp_dmachan[dev]; + + DISABLE_INTR (flags); + clear_dma_ff (chan); + disable_dma (chan); + pos = get_dma_residue (chan); + enable_dma (chan); + RESTORE_INTR (flags); + printk ("dmapos=%d %x\n", pos, pos); + } +#endif + if (sound_dma_automode[dev] && + intrflag && + cnt == dsp_count) + { + irq_mode = IMODE_INPUT; + intr_active = 1; + return; /* Auto mode on. No need to react */ + } + DISABLE_INTR (flags); + + if (dma_restart) + { + sb16_dsp_halt (dev); + DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); + } + + sb_dsp_command (0x42); + sb_dsp_command ((unsigned char) ((dsp_current_speed >> 8) & 0xff)); + sb_dsp_command ((unsigned char) (dsp_current_speed & 0xff)); + sb_dsp_command ((unsigned char) (dsp_16bit ? 0xbe : 0xce)); + sb_dsp_command ((unsigned char) ((dsp_stereo ? 0x20 : 0) + + (dsp_16bit ? 0x10 : 0))); + sb_dsp_command01 ((unsigned char) (cnt & 0xff)); + sb_dsp_command ((unsigned char) (cnt >> 8)); + + /* sb_dsp_command (0); + sb_dsp_command (0); */ + RESTORE_INTR (flags); + dsp_count = cnt; + irq_mode = IMODE_INPUT; + intr_active = 1; +} + +static int +sb16_dsp_prepare_for_input (int dev, int bsize, int bcount) +{ + sound_dsp_dmachan[my_dev] = dsp_16bit ? dma16 : dma8; + dsp_count = 0; + dsp_cleanup (); + return 0; +} + +static int +sb16_dsp_prepare_for_output (int dev, int bsize, int bcount) +{ + sound_dsp_dmachan[my_dev] = dsp_16bit ? dma16 : dma8; + dsp_count = 0; + dsp_cleanup (); + return 0; +} + +static void +dsp_cleanup (void) +{ + irq_mode = IMODE_NONE; + intr_active = 0; +} + +static void +sb16_dsp_reset (int dev) +{ + unsigned long flags; + + DISABLE_INTR (flags); + + sb_reset_dsp (); + dsp_cleanup (); + + RESTORE_INTR (flags); +} + +static void +sb16_dsp_halt (int dev) +{ + if (dsp_16bit) + { + sb_dsp_command01 (0xd9); + sb_dsp_command01 (0xd5); + } + else + { + sb_dsp_command01 (0xda); + sb_dsp_command01 (0xd0); + } +} + +static void +set_irq_hw (int level) +{ + int ival; + + switch (level) + { + case 5: + ival = 2; + break; + case 7: + ival = 4; + break; + case 10: + ival = 8; + break; + default: + printk ("SB16_IRQ_LEVEL %d does not exist\n", level); + return; + } + sb_setmixer (IRQ_NR, ival); +} + +long +sb16_dsp_init (long mem_start, struct address_info *hw_config) +{ + int i, major, minor; + + major = minor = 0; + sb_dsp_command (0xe1); /* Get version */ + + for (i = 1000; i; i--) + { + if (INB (DSP_DATA_AVAIL) & 0x80) + { /* wait for Data Ready */ + if (major == 0) + major = INB (DSP_READ); + else + { + minor = INB (DSP_READ); + break; + } + } + } + +#ifndef SCO + sprintf (sb16_dsp_operations.name, "SoundBlaster 16 %d.%d", major, minor); +#endif + + printk ("snd6: <%s>", sb16_dsp_operations.name); + + if (num_dspdevs < MAX_DSP_DEV) + { + dsp_devs[my_dev = num_dspdevs++] = &sb16_dsp_operations; + sound_dsp_dmachan[my_dev] = hw_config->dma; + sound_buffcounts[my_dev] = 1; + sound_buffsizes[my_dev] = DSP_BUFFSIZE; + sound_dma_automode[my_dev] = 1; + } + else + printk ("SB: Too many DSP devices available\n"); + sb16_dsp_ok = 1; + return mem_start; +} + +int +sb16_dsp_detect (struct address_info *hw_config) +{ + struct address_info *sb_config; + + if (sb16_dsp_ok) + return 1; /* Already initialized */ + + if (!(sb_config = sound_getconf (SNDCARD_SB))) + { + printk ("SB16 Error: Plain SB not configured\n"); + return 0; + } + + if (sbc_base != hw_config->io_base) + printk ("Warning! SB16 I/O != SB I/O\n"); + + /* sb_setmixer(OPSW,0xf); + if(sb_getmixer(OPSW)!=0xf) + return 0; */ + + if (!sb_reset_dsp ()) + return 0; + + if (hw_config->irq != sb_config->irq) + { + printk ("SB16 Error: Invalid IRQ number %d/%d\n", + sb_config->irq, hw_config->irq); + return 0; + } + + if (hw_config->dma < 4) + if (hw_config->dma != sb_config->dma) + { + printk ("SB16 Error: Invalid DMA channel %d/%d\n", + sb_config->dma, hw_config->dma); + return 0; + } + + dma16 = hw_config->dma; + dma8 = sb_config->dma; + set_irq_hw (hw_config->irq); + sb_setmixer (DMA_NR, (1 << hw_config->dma) | (1 << sb_config->dma)); + + DEB (printk ("SoundBlaster 16: IRQ %d DMA %d OK\n", hw_config->irq, hw_config->dma)); + +/* + dsp_showmessage(0xe3,99); + */ + sb16_dsp_ok = 1; + return 1; +} + +void +sb16_dsp_interrupt (int unused) +{ + int data; + + data = INB (DSP_DATA_AVL16); /* Interrupt acknowledge */ + + if (intr_active) + switch (irq_mode) + { + case IMODE_OUTPUT: + intr_active = 0; + DMAbuf_outputintr (my_dev, 1); + break; + + case IMODE_INPUT: + intr_active = 0; + DMAbuf_inputintr (my_dev); + break; + + default: + printk ("SoundBlaster: Unexpected interrupt\n"); + } +} +#endif diff --git a/sys/i386/isa/sound/sb16_midi.c b/sys/i386/isa/sound/sb16_midi.c new file mode 100644 index 000000000000..f7a61a65bd2c --- /dev/null +++ b/sys/i386/isa/sound/sb16_midi.c @@ -0,0 +1,314 @@ +/* + * sound/sb16_midi.c + * + * The low level driver for the MPU-401 UART emulation of the SB16. + * + * 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. + * + */ + +#include "sound_config.h" + +#ifdef CONFIGURE_SOUNDCARD + +#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_MIDI) + +#define DATAPORT (sb16midi_base) /* MPU-401 Data I/O Port on IBM */ +#define COMDPORT (sb16midi_base+1) /* MPU-401 Command Port on IBM */ +#define STATPORT (sb16midi_base+1) /* MPU-401 Status Port on IBM */ + +#define sb16midi_status() INB(STATPORT) +#define input_avail() (!(sb16midi_status()&INPUT_AVAIL)) +#define output_ready() (!(sb16midi_status()&OUTPUT_READY)) +#define sb16midi_cmd(cmd) OUTB(cmd, COMDPORT) +#define sb16midi_read() INB(DATAPORT) +#define sb16midi_write(byte) OUTB(byte, DATAPORT) + +#define OUTPUT_READY 0x40 /* Mask for Data Read Redy Bit */ +#define INPUT_AVAIL 0x80 /* Mask for Data Send Ready Bit */ +#define MPU_ACK 0xFE /* MPU-401 Acknowledge Response */ +#define MPU_RESET 0xFF /* MPU-401 Total Reset Command */ +#define UART_MODE_ON 0x3F /* MPU-401 "Dumb UART Mode" */ + +static int sb16midi_opened = 0; +static int sb16midi_base = 0x330; +static int sb16midi_detected = 0; +static int my_dev; + +static int reset_sb16midi (void); +static void (*midi_input_intr) (int dev, unsigned char data); + +static void +sb16midi_input_loop (void) +{ + int count; + + count = 10; + + while (count) /* Not timed out */ + if (input_avail ()) + { + unsigned char c = sb16midi_read (); + + count = 100; + + if (sb16midi_opened & OPEN_READ) + midi_input_intr (my_dev, c); + } + else + while (!input_avail () && count) + count--; +} + +void +sb16midiintr (int unit) +{ + if (input_avail ()) + sb16midi_input_loop (); +} + +/* + * It looks like there is no input interrupts in the UART mode. Let's try + * polling. + */ + +static void +poll_sb16midi (unsigned long dummy) +{ + unsigned long flags; + + DEFINE_TIMER (sb16midi_timer, poll_sb16midi); + + if (!(sb16midi_opened & OPEN_READ)) + return; /* No longer required */ + + DISABLE_INTR (flags); + + if (input_avail ()) + sb16midi_input_loop (); + + ACTIVATE_TIMER (sb16midi_timer, poll_sb16midi, 1); /* Come back later */ + + RESTORE_INTR (flags); +} + +static int +sb16midi_open (int dev, int mode, + void (*input) (int dev, unsigned char data), + void (*output) (int dev) +) +{ + if (sb16midi_opened) + { + return RET_ERROR (EBUSY); + } + + sb16midi_input_loop (); + + midi_input_intr = input; + sb16midi_opened = mode; + poll_sb16midi (0); /* Enable input polling */ + + return 0; +} + +static void +sb16midi_close (int dev) +{ + sb16midi_opened = 0; +} + +static int +sb16midi_out (int dev, unsigned char midi_byte) +{ + int timeout; + unsigned long flags; + + /* + * Test for input since pending input seems to block the output. + */ + + DISABLE_INTR (flags); + + if (input_avail ()) + sb16midi_input_loop (); + + RESTORE_INTR (flags); + + /* + * 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 (); timeout--); /* Wait */ + + if (!output_ready ()) + { + printk ("MPU-401: Timeout\n"); + return 0; + } + + sb16midi_write (midi_byte); + return 1; +} + +static int +sb16midi_command (int dev, unsigned char midi_byte) +{ + return 1; +} + +static int +sb16midi_start_read (int dev) +{ + return 0; +} + +static int +sb16midi_end_read (int dev) +{ + return 0; +} + +static int +sb16midi_ioctl (int dev, unsigned cmd, unsigned arg) +{ + return RET_ERROR (EINVAL); +} + +static void +sb16midi_kick (int dev) +{ +} + +static int +sb16midi_buffer_status (int dev) +{ + return 0; /* No data in buffers */ +} + +static struct midi_operations sb16midi_operations = +{ + {"SoundBlaster MPU-401", 0, 0, SNDCARD_SB16MIDI}, + sb16midi_open, + sb16midi_close, + sb16midi_ioctl, + sb16midi_out, + sb16midi_start_read, + sb16midi_end_read, + sb16midi_kick, + sb16midi_command, + sb16midi_buffer_status +}; + + +long +attach_sb16midi (long mem_start, struct address_info *hw_config) +{ + int ok, timeout; + unsigned long flags; + + sb16midi_base = hw_config->io_base; + + if (!sb16midi_detected) + return RET_ERROR (EIO); + + DISABLE_INTR (flags); + for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /* Wait */ + sb16midi_cmd (UART_MODE_ON); + + ok = 0; + for (timeout = 50000; timeout > 0 && !ok; timeout--) + if (input_avail ()) + if (sb16midi_read () == MPU_ACK) + ok = 1; + + RESTORE_INTR (flags); + + printk ("snd7: "); + + my_dev = num_midis; + midi_devs[num_midis++] = &sb16midi_operations; + return mem_start; +} + +static int +reset_sb16midi (void) +{ + unsigned long flags; + int ok, timeout, n; + + /* + * Send the RESET command. Try again if no success at the first time. + */ + + ok = 0; + + DISABLE_INTR (flags); + + for (n = 0; n < 2 && !ok; n++) + { + for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /* Wait */ + sb16midi_cmd (MPU_RESET); /* Send MPU-401 RESET Command */ + + /* + * Wait at least 25 msec. This method is not accurate so let's make the + * loop bit longer. Cannot sleep since this is called during boot. + */ + + for (timeout = 50000; timeout > 0 && !ok; timeout--) + if (input_avail ()) + if (sb16midi_read () == MPU_ACK) + ok = 1; + + } + + sb16midi_opened = 0; + if (ok) + sb16midi_input_loop (); /* Flush input before enabling interrupts */ + + RESTORE_INTR (flags); + + return ok; +} + + +int +probe_sb16midi (struct address_info *hw_config) +{ + int ok = 0; + + sb16midi_base = hw_config->io_base; + + if (sb_get_irq () < 0) + return 0; + + ok = reset_sb16midi (); + + sb16midi_detected = ok; + return ok; +} + +#endif + +#endif diff --git a/sys/i386/isa/sound/sb_card.c b/sys/i386/isa/sound/sb_card.c index e2527c51a35e..ef90b4bef312 100644 --- a/sys/i386/isa/sound/sb_card.c +++ b/sys/i386/isa/sound/sb_card.c @@ -1,6 +1,5 @@ - /* - * linux/kernel/chr_drv/sound/sb_card.c + * sound/sb_card.c * * Detection routine for the SoundBlaster cards. * diff --git a/sys/i386/isa/sound/sb_dsp.c b/sys/i386/isa/sound/sb_dsp.c index 4c273646bdd3..2ed058f34823 100644 --- a/sys/i386/isa/sound/sb_dsp.c +++ b/sys/i386/isa/sound/sb_dsp.c @@ -1,7 +1,7 @@ /* - * linux/kernel/chr_drv/sound/sb_dsp.c + * sound/sb_dsp.c * - * The low level driver for the SoundBlaster DS chips. + * The low level driver for the SoundBlaster DSP chip. * * Copyright by Hannu Savolainen 1993 * @@ -25,152 +25,75 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * The mixer support is based on the SB-BSD 1.5 driver by (C) Steve Haehnichen - * */ #include "sound_config.h" #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB) +#include "sb.h" +#include "sb_mixer.h" #undef SB_TEST_IRQ -#define DSP_RESET (sbc_base + 0x6) -#define DSP_READ (sbc_base + 0xA) -#define DSP_WRITE (sbc_base + 0xC) -#define DSP_COMMAND (sbc_base + 0xC) -#define DSP_STATUS (sbc_base + 0xC) -#define DSP_DATA_AVAIL (sbc_base + 0xE) -#define MIXER_ADDR (sbc_base + 0x4) -#define MIXER_DATA (sbc_base + 0x5) -#define OPL3_LEFT (sbc_base + 0x0) -#define OPL3_RIGHT (sbc_base + 0x2) -#define OPL3_BOTH (sbc_base + 0x8) - -static int sbc_base = 0; +int sbc_base = 0; static int sbc_irq = 0; -#define POSSIBLE_RECORDING_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD) - -#define SUPPORTED_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_MIC | \ - SOUND_MASK_CD | SOUND_MASK_VOLUME) - -/* - * Mixer registers - * - * NOTE! RECORD_SRC == IN_FILTER - */ - -#define VOC_VOL 0x04 -#define MIC_VOL 0x0A -#define MIC_MIX 0x0A -#define RECORD_SRC 0x0C -#define IN_FILTER 0x0C -#define OUT_FILTER 0x0E -#define MASTER_VOL 0x22 -#define FM_VOL 0x26 -#define CD_VOL 0x28 -#define LINE_VOL 0x2E - -#define FREQ_HI (1 << 3)/* Use High-frequency ANFI filters */ -#define FREQ_LOW 0 /* Use Low-frequency ANFI filters */ -#define FILT_ON 0 /* Yes, 0 to turn it on, 1 for off */ -#define FILT_OFF (1 << 5) - -/* Convenient byte masks */ -#define B1(x) ((x) & 0x01) -#define B2(x) ((x) & 0x03) -#define B3(x) ((x) & 0x07) -#define B4(x) ((x) & 0x0f) -#define B5(x) ((x) & 0x1f) -#define B6(x) ((x) & 0x3f) -#define B7(x) ((x) & 0x7f) -#define B8(x) ((x) & 0xff) -#define F(x) (!!(x)) /* 0 or 1 only */ - -#define MONO_DAC 0x00 -#define STEREO_DAC 0x02 - -/* DSP Commands */ - -#define DSP_CMD_SPKON 0xD1 -#define DSP_CMD_SPKOFF 0xD3 - /* * The DSP channel can be used either for input or output. Variable - * 'irq_mode' will be set when the program calls read or write first time + * 'sb_irq_mode' will be set when the program calls read or write first time * after open. Current version doesn't support mode changes without closing * and reopening the device. Support for this feature may be implemented in a * future version of this driver. */ -#define IMODE_NONE 0 -#define IMODE_OUTPUT 1 -#define IMODE_INPUT 2 -#define IMODE_INIT 3 -#define IMODE_MIDI 4 - -#define NORMAL_MIDI 0 -#define UART_MIDI 1 - -static int sb_dsp_ok = 0; /* Set to 1 after successful initialization */ +int sb_dsp_ok = 0; /* Set to 1 after successful initialization */ static int midi_disabled = 0; -static int dsp_highspeed = 0, dsp_stereo = 0; +int sb_dsp_highspeed = 0; +static int major = 1, minor = 0; /* DSP version */ +static int dsp_stereo = 0; static int dsp_current_speed = DSP_DEFAULT_SPEED; +static int sb16 = 0; +static int irq_verified = 0; -#ifndef EXCLUDE_SBPRO -static int rec_devices = SOUND_MASK_MIC; -static int hi_filter = 0, filter_in = 0, filter_out = 0; +int sb_midi_mode = NORMAL_MIDI; +int sb_midi_busy = 0; /* 1 if the process has output to MIDI */ +int sb_dsp_busy = 0; -#endif +volatile int sb_irq_mode = IMODE_NONE; /* IMODE_INPUT, IMODE_OUTPUT -static int midi_mode = NORMAL_MIDI; -static int midi_busy = 0; /* 1 if the process has output to MIDI */ -static int dsp_busy = 0; - -static volatile int irq_mode = IMODE_NONE; /* IMODE_INPUT, IMODE_OUTPUT * or IMODE_NONE */ static volatile int irq_ok = 0; -static int dsp_model = 1; /* DSP version */ -static int dsp_mono = 1; /* 1 SB, 0 SB Pro */ -static int duplex_midi = 0; +int sb_dsp_model = 1; /* 1=SB, 2=SB Pro */ +int sb_duplex_midi = 0; static int my_dev = 0; -static volatile int intr_active = 0; +volatile int sb_intr_active = 0; static int dsp_speed (int); static int dsp_set_stereo (int mode); -static int dsp_command (unsigned char val); - -#ifndef EXCLUDE_SBPRO -static void setmixer (unsigned char port, unsigned char value); -static int getmixer (unsigned char port); -static void init_mixer (void); -static int detect_mixer (void); - -#endif +int sb_dsp_command (unsigned char val); #if !defined(EXCLUDE_MIDI) || !defined(EXCLUDE_AUDIO) /* Common code for the midi and pcm functions */ -static int -dsp_command (unsigned char val) +int +sb_dsp_command (unsigned char val) { int i, limit; limit = GET_TIME () + 10; /* The timeout is 0.1 secods */ /* - * Note! the i<5000000 is an emergency exit. The dsp_command() is sometimes + * Note! the i<500000 is an emergency exit. The sb_dsp_command() is sometimes * called while interrupts are disabled. This means that the timer is * disabled also. However the timeout situation is a abnormal condition. * Normally the DSP should be ready to accept commands after just couple of * loops. */ - for (i = 0; i < 5000000 && GET_TIME () < limit; i++) + for (i = 0; i < 500000 && GET_TIME () < limit; i++) { if ((INB (DSP_STATUS) & 0x80) == 0) { @@ -179,41 +102,62 @@ dsp_command (unsigned char val) } } - printk ("SoundBlaster: DSP Command(%02x) Timeout.\n", val); + printk ("SoundBlaster: DSP Command(%x) Timeout.\n", val); printk ("IRQ conflict???\n"); return 0; } void -sbintr (int unused) +sbintr (int unit) { int status, data; - status = INB (DSP_DATA_AVAIL);/* Clear interrupt */ +#ifndef EXCLUDE_SBPRO + if (sb16) + { + unsigned char src = sb_getmixer (IRQ_STAT); /* Interrupt source register */ - if (intr_active) - switch (irq_mode) +#ifndef EXCLUDE_SB16 + if (src & 3) + sb16_dsp_interrupt (unit); + +#ifndef EXCLUDE_MIDI + if (src & 4) + sb16midiintr (unit); /* MPU401 interrupt */ +#endif + +#endif + + if (!(src & 1)) + return; /* Not a DSP interupt */ + } +#endif + + status = INB (DSP_DATA_AVAIL); /* Clear interrupt */ + + if (sb_intr_active) + switch (sb_irq_mode) { case IMODE_OUTPUT: - intr_active = 0; - DMAbuf_outputintr (my_dev); + sb_intr_active = 0; + DMAbuf_outputintr (my_dev, 1); break; case IMODE_INPUT: - intr_active = 0; + sb_intr_active = 0; DMAbuf_inputintr (my_dev); /* A complete buffer has been input. Let's start new one */ break; case IMODE_INIT: - intr_active = 0; + sb_intr_active = 0; irq_ok = 1; break; case IMODE_MIDI: printk ("+"); data = INB (DSP_READ); - printk ("%02x", data); + printk ("%x", data); break; @@ -222,40 +166,36 @@ sbintr (int unused) } } -static int -set_dsp_irq (int interrupt_level) +static int sb_irq_usecount = 0; + +int +sb_get_irq (void) { - int retcode = EINVAL; + int ok; -#ifdef linux - struct sigaction sa; + if (!sb_irq_usecount) + if ((ok = snd_set_irq_handler (sbc_irq, sbintr)) < 0) + return ok; - sa.sa_handler = sbintr; + sb_irq_usecount++; -#ifdef SND_SA_INTERRUPT - sa.sa_flags = SA_INTERRUPT; -#else - sa.sa_flags = 0; -#endif - - sa.sa_mask = 0; - sa.sa_restorer = NULL; - - retcode = irqaction (interrupt_level, &sa); - - if (retcode < 0) - { - printk ("SoundBlaster: IRQ%d already in use\n", interrupt_level); - } - -#else - /* # error Unimplemented for this OS */ -#endif - return retcode; + return 0; } -static int -reset_dsp (void) +void +sb_free_irq (void) +{ + if (!sb_irq_usecount) + return; + + sb_irq_usecount--; + + if (!sb_irq_usecount) + snd_release_irq (sbc_irq); +} + +int +sb_reset_dsp (void) { int loopc; @@ -283,9 +223,9 @@ static void dsp_speaker (char state) { if (state) - dsp_command (DSP_CMD_SPKON); + sb_dsp_command (DSP_CMD_SPKON); else - dsp_command (DSP_CMD_SPKOFF); + sb_dsp_command (DSP_CMD_SPKOFF); } static int @@ -294,14 +234,13 @@ dsp_speed (int speed) unsigned char tconst; unsigned long flags; - if (speed < 4000) speed = 4000; if (speed > 44100) speed = 44100; /* Invalid speed */ - if (dsp_model == 1 && speed > 22050) + if (sb_dsp_model == 1 && speed > 22050) speed = 22050; /* SB Classic doesn't support higher speed */ @@ -310,44 +249,51 @@ dsp_speed (int speed) speed = 22050; /* Max. stereo speed is 22050 */ - if ((speed > 22050) && midi_busy) + if ((speed > 22050) && sb_midi_busy) { printk ("SB Warning: High speed DSP not possible simultaneously with MIDI output\n"); speed = 22050; } if (dsp_stereo) - speed <<= 1; + speed *= 2; /* Now the speed should be valid */ if (speed > 22050) { /* High speed mode */ - tconst = (unsigned char) ((65536 - (256000000 / speed)) >> 8); - dsp_highspeed = 1; + int tmp; + + tconst = (unsigned char) ((65536 - + ((256000000 + speed / 2) / speed)) >> 8); + sb_dsp_highspeed = 1; DISABLE_INTR (flags); - if (dsp_command (0x40)) - dsp_command (tconst); + if (sb_dsp_command (0x40)) + sb_dsp_command (tconst); RESTORE_INTR (flags); - speed = (256000000 / (65536 - (tconst << 8))); + tmp = 65536 - (tconst << 8); + speed = (256000000 + tmp / 2) / tmp; } else { - dsp_highspeed = 0; - tconst = (256 - (1000000 / speed)) & 0xff; + int tmp; + + sb_dsp_highspeed = 0; + tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff; DISABLE_INTR (flags); - if (dsp_command (0x40)) /* Set time constant */ - dsp_command (tconst); + if (sb_dsp_command (0x40)) /* Set time constant */ + sb_dsp_command (tconst); RESTORE_INTR (flags); - speed = 1000000 / (256 - tconst); + tmp = 256 - tconst; + speed = (1000000 + tmp / 2) / tmp; } if (dsp_stereo) - speed >>= 1; + speed /= 2; dsp_current_speed = speed; return speed; @@ -358,49 +304,47 @@ dsp_set_stereo (int mode) { dsp_stereo = 0; - if (dsp_mono == 1) +#ifdef EXCLUDE_SBPRO + return 0; +#else + if (sb_dsp_model == 1 || sb16) return 0; /* Sorry no stereo */ - if (mode && midi_busy) + if (mode && sb_midi_busy) { printk ("SB Warning: Stereo DSP not possible simultaneously with MIDI output\n"); return 0; } dsp_stereo = !!mode; - -#ifndef EXCLUDE_SBPRO - setmixer (OUT_FILTER, ((getmixer (OUT_FILTER) & ~STEREO_DAC) - | (mode ? STEREO_DAC : MONO_DAC))); + return dsp_stereo; #endif - dsp_speed (dsp_current_speed);/* Speed must be recalculated if #channels - * changes */ - return mode; } static void -sb_dsp_output_block (int dev, unsigned long buf, int count, int intrflag) +sb_dsp_output_block (int dev, unsigned long buf, int count, + int intrflag, int restart_dma) { unsigned long flags; - if (!irq_mode) + if (!sb_irq_mode) dsp_speaker (ON); - irq_mode = IMODE_OUTPUT; + sb_irq_mode = IMODE_OUTPUT; DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); if (sound_dsp_dmachan[dev] > 3) count >>= 1; count--; - if (dsp_highspeed) + if (sb_dsp_highspeed) { DISABLE_INTR (flags); - if (dsp_command (0x48)) /* High speed size */ + if (sb_dsp_command (0x48)) /* High speed size */ { - dsp_command (count & 0xff); - dsp_command ((count >> 8) & 0xff); - dsp_command (0x91); /* High speed 8 bit DAC */ + sb_dsp_command ((unsigned char) (count & 0xff)); + sb_dsp_command ((unsigned char) ((count >> 8) & 0xff)); + sb_dsp_command (0x91); /* High speed 8 bit DAC */ } else printk ("SB Error: Unable to start (high speed) DAC\n"); @@ -409,43 +353,44 @@ sb_dsp_output_block (int dev, unsigned long buf, int count, int intrflag) else { DISABLE_INTR (flags); - if (dsp_command (0x14)) /* 8-bit DAC (DMA) */ + if (sb_dsp_command (0x14)) /* 8-bit DAC (DMA) */ { - dsp_command (count & 0xff); - dsp_command ((count >> 8) & 0xff); + sb_dsp_command ((unsigned char) (count & 0xff)); + sb_dsp_command ((unsigned char) ((count >> 8) & 0xff)); } else printk ("SB Error: Unable to start DAC\n"); RESTORE_INTR (flags); } - intr_active = 1; + sb_intr_active = 1; } static void -sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag) +sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, + int restart_dma) { /* Start a DMA input to the buffer pointed by dmaqtail */ unsigned long flags; - if (!irq_mode) + if (!sb_irq_mode) dsp_speaker (OFF); - irq_mode = IMODE_INPUT; + sb_irq_mode = IMODE_INPUT; DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); if (sound_dsp_dmachan[dev] > 3) count >>= 1; count--; - if (dsp_highspeed) + if (sb_dsp_highspeed) { DISABLE_INTR (flags); - if (dsp_command (0x48)) /* High speed size */ + if (sb_dsp_command (0x48)) /* High speed size */ { - dsp_command (count & 0xff); - dsp_command ((count >> 8) & 0xff); - dsp_command (0x99); /* High speed 8 bit ADC */ + sb_dsp_command ((unsigned char) (count & 0xff)); + sb_dsp_command ((unsigned char) ((count >> 8) & 0xff)); + sb_dsp_command (0x99); /* High speed 8 bit ADC */ } else printk ("SB Error: Unable to start (high speed) ADC\n"); @@ -454,23 +399,23 @@ sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag) else { DISABLE_INTR (flags); - if (dsp_command (0x24)) /* 8-bit ADC (DMA) */ + if (sb_dsp_command (0x24)) /* 8-bit ADC (DMA) */ { - dsp_command (count & 0xff); - dsp_command ((count >> 8) & 0xff); + sb_dsp_command ((unsigned char) (count & 0xff)); + sb_dsp_command ((unsigned char) ((count >> 8) & 0xff)); } else printk ("SB Error: Unable to start ADC\n"); RESTORE_INTR (flags); } - intr_active = 1; + sb_intr_active = 1; } static void dsp_cleanup (void) { - intr_active = 0; + sb_intr_active = 0; } static int @@ -478,6 +423,17 @@ sb_dsp_prepare_for_input (int dev, int bsize, int bcount) { dsp_cleanup (); dsp_speaker (OFF); + + if (major == 3) /* SB Pro */ + { + if (dsp_stereo) + sb_dsp_command (0xa8); + else + sb_dsp_command (0xa0); + + dsp_speed (dsp_current_speed); /* Speed must be recalculated if #channels + * changes */ + } return 0; } @@ -486,6 +442,15 @@ sb_dsp_prepare_for_output (int dev, int bsize, int bcount) { dsp_cleanup (); dsp_speaker (ON); + +#ifndef EXCLUDE_SBPRO + if (major == 3) /* SB Pro */ + { + sb_mixer_set_stereo (dsp_stereo); + dsp_speed (dsp_current_speed); /* Speed must be recalculated if #channels + * changes */ + } +#endif return 0; } @@ -494,6 +459,40 @@ sb_dsp_halt_xfer (int dev) { } +static int +verify_irq (void) +{ +#if 0 + DEFINE_WAIT_QUEUE (testq, testf); + + irq_ok = 0; + + if (sb_get_irq () == -1) + { + printk ("*** SB Error: Irq %d already in use\n", sbc_irq); + return 0; + } + + + sb_irq_mode = IMODE_INIT; + + sb_dsp_command (0xf2); /* This should cause immediate interrupt */ + + DO_SLEEP (testq, testf, HZ / 5); + + sb_free_irq (); + + if (!irq_ok) + { + printk ("SB Warning: IRQ%d test not passed!", sbc_irq); + irq_ok = 1; + } +#else + irq_ok = 1; +#endif + return irq_ok; +} + static int sb_dsp_open (int dev, int mode) { @@ -505,40 +504,35 @@ sb_dsp_open (int dev, int mode) return RET_ERROR (ENXIO); } - if (!irq_ok) - { - printk ("SB Error: Incorrect IRQ setting (%d)\n", sbc_irq); - return RET_ERROR (ENXIO); - } - - if (intr_active || (midi_busy && midi_mode == UART_MIDI)) + if (sb_intr_active || (sb_midi_busy && sb_midi_mode == UART_MIDI)) { printk ("SB: PCM not possible during MIDI input\n"); return RET_ERROR (EBUSY); } - if (mode != OPEN_READ && mode != OPEN_WRITE) + if (!irq_verified) { - printk ("SoundBlaster error: DAC and ACD not possible simultaneously\n"); - return RET_ERROR (EINVAL); + verify_irq (); + irq_verified = 1; } + else if (!irq_ok) + printk ("SB Warning: Incorrect IRQ setting %d\n", + sbc_irq); - retval = set_dsp_irq (sbc_irq); + retval = sb_get_irq (); if (retval) return retval; if (!DMAbuf_open_dma (dev)) { - RELEASE_IRQ (sbc_irq); + sb_free_irq (); printk ("SB: DMA Busy\n"); return RET_ERROR (EBUSY); } - dsp_set_stereo (OFF); - dsp_speed (DSP_DEFAULT_SPEED); - irq_mode = IMODE_NONE; + sb_irq_mode = IMODE_NONE; - dsp_busy = 1; + sb_dsp_busy = 1; return 0; } @@ -547,12 +541,11 @@ static void sb_dsp_close (int dev) { DMAbuf_close_dma (dev); - RELEASE_IRQ (sbc_irq); + sb_free_irq (); dsp_cleanup (); - dsp_speed (DSP_DEFAULT_SPEED); - dsp_set_stereo (OFF); dsp_speaker (OFF); - dsp_busy = 0; + sb_dsp_busy = 0; + sb_dsp_highspeed = 0; } static int @@ -573,6 +566,8 @@ sb_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) break; case SOUND_PCM_WRITE_CHANNELS: + if (local) + return dsp_set_stereo (arg - 1) + 1; return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg) - 1) + 1); break; @@ -592,7 +587,7 @@ sb_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) 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; case SOUND_PCM_WRITE_FILTER: @@ -614,7 +609,7 @@ sb_dsp_reset (int dev) DISABLE_INTR (flags); - reset_dsp (); + sb_reset_dsp (); dsp_cleanup (); RESTORE_INTR (flags); @@ -631,538 +626,12 @@ sb_dsp_detect (struct address_info *hw_config) if (sb_dsp_ok) return 0; /* Already initialized */ - if (!reset_dsp ()) + if (!sb_reset_dsp ()) return 0; return 1; /* Detected */ } -#ifndef EXCLUDE_SBPRO - -static void -setmixer (unsigned char port, unsigned char value) -{ - OUTB (port, MIXER_ADDR); /* Select register */ - tenmicrosec (); - OUTB (value, MIXER_DATA); - tenmicrosec (); -} - -static int -getmixer (unsigned char port) -{ - int val; - - OUTB (port, MIXER_ADDR); /* Select register */ - tenmicrosec (); - val = INB (MIXER_DATA); - tenmicrosec (); - - return val; -} - -static int -detect_mixer (void) -{ - /* - * Detect the mixer by changing parameters of two volume channels. If the - * values read back match with the values written, the mixer is there (is - * it?) - */ - setmixer (FM_VOL, 0xff); - setmixer (VOC_VOL, 0x33); - - if (getmixer (FM_VOL) != 0xff) - return 0; /* No match */ - if (getmixer (VOC_VOL) != 0x33) - return 0; - - return 1; -} - -static void -init_mixer (void) -{ - setmixer (MASTER_VOL, 0xbb); - setmixer (VOC_VOL, 0x99); - setmixer (LINE_VOL, 0xbb); - setmixer (FM_VOL, 0x99); - setmixer (CD_VOL, 0x11); - setmixer (MIC_MIX, 0x11); - setmixer (RECORD_SRC, 0x31); - setmixer (OUT_FILTER, 0x31); -} - -static void -set_filter (int record_source, int hifreq_filter, int filter_input, int filter_output) -{ - setmixer (RECORD_SRC, (record_source - | (hifreq_filter ? FREQ_HI : FREQ_LOW) - | (filter_input ? FILT_ON : FILT_OFF))); - - setmixer (OUT_FILTER, ((dsp_stereo ? STEREO_DAC : MONO_DAC) - | (filter_output ? FILT_ON : FILT_OFF))); - - hi_filter = hifreq_filter; - filter_in = filter_input; - filter_out = filter_output; -} - -static int -mixer_output (int right_vol, int left_vol, int div, int device) -{ - int left = ((left_vol * div) + 50) / 100; - int right = ((right_vol * div) + 50) / 100; - - setmixer (device, ((left & 0xf) << 4) | (right & 0xf)); - - return (left_vol | (right_vol << 8)); -} - -static int -sbp_mixer_set (int whichDev, unsigned int level) -{ - int left, right, devmask; - - left = level & 0x7f; - right = (level & 0x7f00) >> 8; - - switch (whichDev) - { - case SOUND_MIXER_VOLUME: /* Master volume (0-15) */ - return mixer_output (right, left, 15, MASTER_VOL); - break; - case SOUND_MIXER_SYNTH: /* Internal synthesizer (0-15) */ - return mixer_output (right, left, 15, FM_VOL); - break; - case SOUND_MIXER_PCM: /* PAS PCM (0-15) */ - return mixer_output (right, left, 15, VOC_VOL); - break; - case SOUND_MIXER_LINE: /* External line (0-15) */ - return mixer_output (right, left, 15, LINE_VOL); - break; - case SOUND_MIXER_CD: /* CD (0-15) */ - return mixer_output (right, left, 15, CD_VOL); - break; - case SOUND_MIXER_MIC: /* External microphone (0-7) */ - return mixer_output (right, left, 7, MIC_VOL); - break; - - case SOUND_MIXER_RECSRC: - devmask = level & POSSIBLE_RECORDING_DEVICES; - - if (devmask != SOUND_MASK_MIC && - devmask != SOUND_MASK_LINE && - devmask != SOUND_MASK_CD) - { /* More than one devices selected. Drop the - * previous selection */ - devmask &= ~rec_devices; - } - - if (devmask != SOUND_MASK_MIC && - devmask != SOUND_MASK_LINE && - devmask != SOUND_MASK_CD) - { /* More than one devices selected. Default to - * mic */ - devmask = SOUND_MASK_MIC; - } - - if (devmask ^ rec_devices)/* Input source changed */ - { - switch (devmask) - { - - case SOUND_MASK_MIC: - set_filter (SRC_MIC, hi_filter, filter_in, filter_out); - break; - - case SOUND_MASK_LINE: - set_filter (SRC_LINE, hi_filter, filter_in, filter_out); - break; - - case SOUND_MASK_CD: - set_filter (SRC_CD, hi_filter, filter_in, filter_out); - break; - - default: - set_filter (SRC_MIC, hi_filter, filter_in, filter_out); - } - } - - rec_devices = devmask; - - return rec_devices; - break; - - default: - return RET_ERROR (EINVAL); - } - -} - -static int -mixer_input (int div, int device) -{ - int level, left, right, half; - - level = getmixer (device); - half = div / 2; - - left = ((((level & 0xf0) >> 4) * 100) + half) / div; - right = (((level & 0x0f) * 100) + half) / div; - - return (right << 8) | left; -} - -static int -sbp_mixer_get (int whichDev) -{ - - switch (whichDev) - { - case SOUND_MIXER_VOLUME: /* Master volume (0-15) */ - return mixer_input (15, MASTER_VOL); - break; - case SOUND_MIXER_SYNTH: /* Internal synthesizer (0-15) */ - return mixer_input (15, FM_VOL); - break; - case SOUND_MIXER_PCM: /* PAS PCM (0-15) */ - return mixer_input (15, VOC_VOL); - break; - case SOUND_MIXER_LINE: /* External line (0-15) */ - return mixer_input (15, LINE_VOL); - break; - case SOUND_MIXER_CD: /* CD (0-15) */ - return mixer_input (15, CD_VOL); - break; - case SOUND_MIXER_MIC: /* External microphone (0-7) */ - return mixer_input (7, MIC_VOL); - break; - - default: - return RET_ERROR (EINVAL); - } - -} - -/* - * Sets mixer volume levels. All levels except mic are 0 to 15, mic is 7. See - * sbinfo.doc for details on granularity and such. Basically, the mixer - * forces the lowest bit high, effectively reducing the possible settings by - * one half. Yes, that's right, volume levels have 8 settings, and - * microphone has four. Sucks. - */ -static int -mixer_set_levels (struct sb_mixer_levels *user_l) -{ - struct sb_mixer_levels l; - - IOCTL_FROM_USER ((char *) &l, ((char *) user_l), 0, sizeof (l)); - - if (l.master.l & ~0xF || l.master.r & ~0xF - || l.line.l & ~0xF || l.line.r & ~0xF - || l.voc.l & ~0xF || l.voc.r & ~0xF - || l.fm.l & ~0xF || l.fm.r & ~0xF - || l.cd.l & ~0xF || l.cd.r & ~0xF - || l.mic & ~0x7) - return (RET_ERROR (EINVAL)); - - setmixer (MASTER_VOL, (l.master.l << 4) | l.master.r); - setmixer (LINE_VOL, (l.line.l << 4) | l.line.r); - setmixer (VOC_VOL, (l.voc.l << 4) | l.voc.r); - setmixer (FM_VOL, (l.fm.l << 4) | l.fm.r); - setmixer (CD_VOL, (l.cd.l << 4) | l.cd.r); - setmixer (MIC_VOL, l.mic); - return (0); -} - -/* - * This sets aspects of the Mixer that are not volume levels. (Recording - * source, filter level, I/O filtering, and stereo.) - */ - -static int -mixer_set_params (struct sb_mixer_params *user_p) -{ - struct sb_mixer_params p; - - IOCTL_FROM_USER ((char *) &p, (char *) user_p, 0, sizeof (p)); - - if (p.record_source != SRC_MIC - && p.record_source != SRC_CD - && p.record_source != SRC_LINE) - return (EINVAL); - - /* - * I'm not sure if this is The Right Thing. Should stereo be entirely - * under control of DSP? I like being able to toggle it while a sound is - * playing, so I do this... because I can. - */ - - dsp_stereo = !!p.dsp_stereo; - - set_filter (p.record_source, p.hifreq_filter, p.filter_input, p.filter_output); - - switch (p.record_source) - { - - case SRC_MIC: - rec_devices = SOUND_MASK_MIC; - break; - - case SRC_LINE: - rec_devices = SOUND_MASK_LINE; - break; - - case SRC_CD: - rec_devices = SOUND_MASK_CD; - } - - return (0); -} - -/* Read the current mixer level settings into the user's struct. */ -static int -mixer_get_levels (struct sb_mixer_levels *user_l) -{ - S_BYTE val; - struct sb_mixer_levels l; - - val = getmixer (MASTER_VOL); /* Master */ - l.master.l = B4 (val >> 4); - l.master.r = B4 (val); - - val = getmixer (LINE_VOL); /* FM */ - l.line.l = B4 (val >> 4); - l.line.r = B4 (val); - - val = getmixer (VOC_VOL); /* DAC */ - l.voc.l = B4 (val >> 4); - l.voc.r = B4 (val); - - val = getmixer (FM_VOL); /* FM */ - l.fm.l = B4 (val >> 4); - l.fm.r = B4 (val); - - val = getmixer (CD_VOL); /* CD */ - l.cd.l = B4 (val >> 4); - l.cd.r = B4 (val); - - val = getmixer (MIC_VOL); /* Microphone */ - l.mic = B3 (val); - - IOCTL_TO_USER ((char *) user_l, 0, (char *) &l, sizeof (l)); - - return (0); -} - -/* Read the current mixer parameters into the user's struct. */ -static int -mixer_get_params (struct sb_mixer_params *user_params) -{ - S_BYTE val; - struct sb_mixer_params params; - - val = getmixer (RECORD_SRC); - params.record_source = val & 0x07; - params.hifreq_filter = !!(val & FREQ_HI); - params.filter_input = (val & FILT_OFF) ? OFF : ON; - params.filter_output = (getmixer (OUT_FILTER) & FILT_OFF) ? OFF : ON; - params.dsp_stereo = dsp_stereo; - - IOCTL_TO_USER ((char *) user_params, 0, (char *) ¶ms, sizeof (params)); - return (0); -} - -static int -sb_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg) -{ - if (((cmd >> 8) & 0xff) == 'M') - { - if (cmd & IOC_IN) - return IOCTL_OUT (arg, sbp_mixer_set (cmd & 0xff, IOCTL_IN (arg))); - else - { /* Read parameters */ - - switch (cmd & 0xff) - { - - case SOUND_MIXER_RECSRC: - return IOCTL_OUT (arg, rec_devices); - break; - - case SOUND_MIXER_DEVMASK: - return IOCTL_OUT (arg, SUPPORTED_MIXER_DEVICES); - break; - - case SOUND_MIXER_STEREODEVS: - return IOCTL_OUT (arg, SUPPORTED_MIXER_DEVICES & ~SOUND_MASK_MIC); - break; - - case SOUND_MIXER_RECMASK: - return IOCTL_OUT (arg, POSSIBLE_RECORDING_DEVICES); - break; - - case SOUND_MIXER_CAPS: - return IOCTL_OUT (arg, SOUND_CAP_EXCL_INPUT); - break; - - default: - return IOCTL_OUT (arg, sbp_mixer_get (cmd & 0xff)); - } - } - } - else - { - switch (cmd) - { - case MIXER_IOCTL_SET_LEVELS: - return (mixer_set_levels ((struct sb_mixer_levels *) arg)); - case MIXER_IOCTL_SET_PARAMS: - return (mixer_set_params ((struct sb_mixer_params *) arg)); - case MIXER_IOCTL_READ_LEVELS: - return (mixer_get_levels ((struct sb_mixer_levels *) arg)); - case MIXER_IOCTL_READ_PARAMS: - return (mixer_get_params ((struct sb_mixer_params *) arg)); - case MIXER_IOCTL_RESET: - init_mixer (); - return (0); - default: - return RET_ERROR (EINVAL); - } - } -} - -/* End of mixer code */ -#endif - -#ifndef EXCLUDE_MIDI - -/* Midi code */ - -static int -sb_midi_open (int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) -) -{ - int ret; - - if (!sb_dsp_ok) - { - printk ("SB Error: MIDI hardware not installed\n"); - return RET_ERROR (ENXIO); - } - - if (mode != OPEN_WRITE && !duplex_midi) - { - if (num_midis == 1) - printk ("SoundBlaster: Midi input not currently supported\n"); - return RET_ERROR (EPERM); - } - - midi_mode = NORMAL_MIDI; - if (mode != OPEN_WRITE) - { - if (dsp_busy || intr_active) - return RET_ERROR (EBUSY); - midi_mode = UART_MIDI; - } - - if (dsp_highspeed || dsp_stereo) - { - printk ("SB Error: Midi output not possible during stereo or high speed audio\n"); - return RET_ERROR (EBUSY); - } - - if (midi_mode == UART_MIDI) - { - irq_mode = IMODE_MIDI; - - reset_dsp (); - dsp_speaker (OFF); - - if (!dsp_command (0x35)) - return RET_ERROR (EIO); /* Enter the UART mode */ - intr_active = 1; - - if ((ret = set_dsp_irq (sbc_irq)) < 0) - { - reset_dsp (); - return 0; /* IRQ not free */ - } - } - - midi_busy = 1; - - return 0; -} - -static void -sb_midi_close (int dev) -{ - if (midi_mode == UART_MIDI) - { - reset_dsp (); /* The only way to kill the UART mode */ - RELEASE_IRQ (sbc_irq); - } - intr_active = 0; - midi_busy = 0; -} - -static int -sb_midi_out (int dev, unsigned char midi_byte) -{ - unsigned long flags; - - midi_busy = 1; /* Kill all notes after close */ - - if (midi_mode == NORMAL_MIDI) - { - DISABLE_INTR (flags); - if (dsp_command (0x38)) - dsp_command (midi_byte); - else - printk ("SB Error: Unable to send a MIDI byte\n"); - RESTORE_INTR (flags); - } - else - dsp_command (midi_byte); /* UART write */ - - return 1; -} - -static int -sb_midi_start_read (int dev) -{ - if (midi_mode != UART_MIDI) - { - printk ("SoundBlaster: MIDI input not implemented.\n"); - return RET_ERROR (EPERM); - } - return 0; -} - -static int -sb_midi_end_read (int dev) -{ - if (midi_mode == UART_MIDI) - { - reset_dsp (); - intr_active = 0; - } - return 0; -} - -static int -sb_midi_ioctl (int dev, unsigned cmd, unsigned arg) -{ - return RET_ERROR (EPERM); -} - -/* End of midi code */ -#endif - #ifndef EXCLUDE_AUDIO static struct audio_operations sb_dsp_operations = { @@ -1182,132 +651,84 @@ static struct audio_operations sb_dsp_operations = #endif -#ifndef EXCLUDE_SBPRO -static struct mixer_operations sb_mixer_operations = -{ - sb_mixer_ioctl -}; - -#endif - -#ifndef EXCLUDE_MIDI -static struct midi_operations sb_midi_operations = -{ - {"SoundBlaster", 0}, - sb_midi_open, - sb_midi_close, - sb_midi_ioctl, - sb_midi_out, - sb_midi_start_read, - sb_midi_end_read, - NULL, /* Kick */ - NULL, /* command */ - NULL /* buffer_status */ -}; - -#endif - -static int -verify_irq (void) -{ -#if 0 - unsigned long loop; - - irq_ok = 0; - - if (set_dsp_irq (sbc_irq) == -1) - { - printk ("*** SB Error: Irq %d already in use\n", sbc_irq); - return 0; - } - - - irq_mode = IMODE_INIT; - - dsp_command (0xf2); /* This should cause immediate interrupt */ - - for (loop = 100000; loop > 0 && !irq_ok; loop--); - - RELEASE_IRQ (sbc_irq); - - if (!irq_ok) - { - printk ("SB Warning: IRQ test not passed!"); - irq_ok = 1; - } -#else - irq_ok = 1; -#endif - return irq_ok; -} - long sb_dsp_init (long mem_start, struct address_info *hw_config) { - int i, major, minor; + int i; major = minor = 0; - dsp_command (0xe1); /* Get version */ + sb_dsp_command (0xe1); /* Get version */ for (i = 1000; i; i--) { - if (inb (DSP_DATA_AVAIL) & 0x80) + if (INB (DSP_DATA_AVAIL) & 0x80) { /* wait for Data Ready */ if (major == 0) - major = inb (DSP_READ); + major = INB (DSP_READ); else { - minor = inb (DSP_READ); + minor = INB (DSP_READ); break; } } } - dsp_model = major; + + if (major == 2 || major == 3) + sb_duplex_midi = 1; + + if (major == 4) + sb16 = 1; + + if (major >= 3) + sb_dsp_model = 2; #ifndef EXCLUDE_SBPRO - if (detect_mixer ()) + if (major >= 3) + sb_mixer_init (major); +#endif + +#ifndef EXCLUDE_YM3812 + if (major > 3 || (major == 3 && minor > 0)) /* SB Pro2 or later */ { - dsp_mono = 0; + enable_opl3_mode (OPL3_LEFT, OPL3_RIGHT, OPL3_BOTH); + } +#endif + + if (major >= 3) + { +#ifndef SCO sprintf (sb_dsp_operations.name, "SoundBlaster Pro %d.%d", major, minor); - init_mixer (); - mixer_devs[num_mixers++] = &sb_mixer_operations; - - if (major >= 2) - duplex_midi = 1; - -#ifndef EXCLUDE_YM8312 - if (major > 3 || (major == 3 && minor > 0)) /* SB Pro2 or later */ - { - enable_opl3_mode (OPL3_LEFT, OPL3_RIGHT, OPL3_BOTH); - } #endif } else + { +#ifndef SCO + sprintf (sb_dsp_operations.name, "SoundBlaster %d.%d", major, minor); #endif - sprintf (sb_dsp_operations.name, "SoundBlaster %d.%d", major, minor); + } printk ("snd2: <%s>", sb_dsp_operations.name); - if (!verify_irq ()) - return mem_start; - #ifndef EXCLUDE_AUDIO - if (num_dspdevs < MAX_DSP_DEV) - { - dsp_devs[my_dev = num_dspdevs++] = &sb_dsp_operations; - sound_buffcounts[my_dev] = DSP_BUFFCOUNT; - sound_buffsizes[my_dev] = DSP_BUFFSIZE; - sound_dsp_dmachan[my_dev] = hw_config->dma; - sound_dma_automode[my_dev] = 0; - } - else - printk ("SB: Too many DSP devices available\n"); +#if !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SBPRO) + if (!sb16) /* There is a better driver for SB16 */ +#endif + if (num_dspdevs < MAX_DSP_DEV) + { + dsp_devs[my_dev = num_dspdevs++] = &sb_dsp_operations; + sound_buffcounts[my_dev] = DSP_BUFFCOUNT; + sound_buffsizes[my_dev] = DSP_BUFFSIZE; + sound_dsp_dmachan[my_dev] = hw_config->dma; + sound_dma_automode[my_dev] = 0; + } + else + printk ("SB: Too many DSP devices available\n"); #endif #ifndef EXCLUDE_MIDI - if (!midi_disabled) /* Midi don't work in the SB emulation mode - * of PAS */ - midi_devs[num_midis++] = &sb_midi_operations; + if (!midi_disabled && !sb16) /* Midi don't work in the SB emulation mode + * of PAS, SB16 has better midi interface */ + sb_midi_init (major); #endif sb_dsp_ok = 1; diff --git a/sys/i386/isa/sound/sb_midi.c b/sys/i386/isa/sound/sb_midi.c new file mode 100644 index 000000000000..2b0ab5219d3a --- /dev/null +++ b/sys/i386/isa/sound/sb_midi.c @@ -0,0 +1,198 @@ +/* + * sound/sb_dsp.c + * + * The low level driver for the SoundBlaster DS chips. + * + * 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. + * + */ + +#include "sound_config.h" + +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_MIDI) + +#include "sb.h" +#undef SB_TEST_IRQ + +/* + * The DSP channel can be used either for input or output. Variable + * 'sb_irq_mode' will be set when the program calls read or write first time + * after open. Current version doesn't support mode changes without closing + * and reopening the device. Support for this feature may be implemented in a + * future version of this driver. + */ + +extern int sb_dsp_ok; /* Set to 1 after successful initialization */ + +extern int sb_midi_mode; +extern int sb_midi_busy; /* 1 if the process has output to MIDI */ +extern int sb_dsp_busy; +extern int sb_dsp_highspeed; + +extern volatile int sb_irq_mode; /* IMODE_INPUT, IMODE_OUTPUT + + * or IMODE_NONE */ +extern int sb_dsp_model; /* 1=SB, 2=SB Pro */ +extern int sb_duplex_midi; +extern int sb_intr_active; + +static int +sb_midi_open (int dev, int mode, + void (*input) (int dev, unsigned char data), + void (*output) (int dev) +) +{ + int ret; + + if (!sb_dsp_ok) + { + printk ("SB Error: MIDI hardware not installed\n"); + return RET_ERROR (ENXIO); + } + + if (mode != OPEN_WRITE && !sb_duplex_midi) + { + if (num_midis == 1) + printk ("SoundBlaster: Midi input not currently supported\n"); + return RET_ERROR (EPERM); + } + + sb_midi_mode = NORMAL_MIDI; + if (mode != OPEN_WRITE) + { + if (sb_dsp_busy || sb_intr_active) + return RET_ERROR (EBUSY); + sb_midi_mode = UART_MIDI; + } + + if (sb_dsp_highspeed) + { + printk ("SB Error: Midi output not possible during stereo or high speed audio\n"); + return RET_ERROR (EBUSY); + } + + if (sb_midi_mode == UART_MIDI) + { + sb_irq_mode = IMODE_MIDI; + + sb_reset_dsp (); + + if (!sb_dsp_command (0x35)) + return RET_ERROR (EIO); /* Enter the UART mode */ + sb_intr_active = 1; + + if ((ret = sb_get_irq ()) < 0) + { + sb_reset_dsp (); + return 0; /* IRQ not free */ + } + } + + sb_midi_busy = 1; + + return 0; +} + +static void +sb_midi_close (int dev) +{ + if (sb_midi_mode == UART_MIDI) + { + sb_reset_dsp (); /* The only way to kill the UART mode */ + sb_free_irq (); + } + sb_intr_active = 0; + sb_midi_busy = 0; +} + +static int +sb_midi_out (int dev, unsigned char midi_byte) +{ + unsigned long flags; + + sb_midi_busy = 1; /* Kill all notes after close */ + + if (sb_midi_mode == NORMAL_MIDI) + { + DISABLE_INTR (flags); + if (sb_dsp_command (0x38)) + sb_dsp_command (midi_byte); + else + printk ("SB Error: Unable to send a MIDI byte\n"); + RESTORE_INTR (flags); + } + else + sb_dsp_command (midi_byte); /* UART write */ + + return 1; +} + +static int +sb_midi_start_read (int dev) +{ + if (sb_midi_mode != UART_MIDI) + { + printk ("SoundBlaster: MIDI input not implemented.\n"); + return RET_ERROR (EPERM); + } + return 0; +} + +static int +sb_midi_end_read (int dev) +{ + if (sb_midi_mode == UART_MIDI) + { + sb_reset_dsp (); + sb_intr_active = 0; + } + return 0; +} + +static int +sb_midi_ioctl (int dev, unsigned cmd, unsigned arg) +{ + return RET_ERROR (EPERM); +} + +static struct midi_operations sb_midi_operations = +{ + {"SoundBlaster", 0, 0, SNDCARD_SB}, + sb_midi_open, + sb_midi_close, + sb_midi_ioctl, + sb_midi_out, + sb_midi_start_read, + sb_midi_end_read, + NULL, /* Kick */ + NULL, /* command */ + NULL /* buffer_status */ +}; + +void +sb_midi_init (int model) +{ + midi_devs[num_midis++] = &sb_midi_operations; +} + +#endif diff --git a/sys/i386/isa/sound/sb_mixer.c b/sys/i386/isa/sound/sb_mixer.c new file mode 100644 index 000000000000..089a2affbd87 --- /dev/null +++ b/sys/i386/isa/sound/sb_mixer.c @@ -0,0 +1,359 @@ + +/* + * sound/sb_mixer.c + * + * The low level mixer driver for the SoundBlaster Pro and SB16 cards. + * + * 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. + * + */ + +#include "sound_config.h" + +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_SBPRO) +#define __SB_MIXER_C__ + +#include "sb.h" +#include "sb_mixer.h" +#undef SB_TEST_IRQ + +extern int sbc_base; + +static int mixer_initialized = 0; + +static int supported_rec_devices; +static int supported_devices; +static int recmask = 0; +static int mixer_model; +static int mixer_caps; +static mixer_tab *iomap; + +void +sb_setmixer (unsigned int port, unsigned int value) +{ + unsigned long flags; + + DISABLE_INTR (flags); + OUTB ((unsigned char) (port & 0xff), MIXER_ADDR); /* Select register */ + tenmicrosec (); + OUTB ((unsigned char) (value & 0xff), MIXER_DATA); + tenmicrosec (); + RESTORE_INTR (flags); +} + +int +sb_getmixer (unsigned int port) +{ + int val; + unsigned long flags; + + DISABLE_INTR (flags); + OUTB ((unsigned char) (port & 0xff), MIXER_ADDR); /* Select register */ + tenmicrosec (); + val = INB (MIXER_DATA); + tenmicrosec (); + RESTORE_INTR (flags); + + return val; +} + +void +sb_mixer_set_stereo (int mode) +{ + if (!mixer_initialized) + return; + + sb_setmixer (OUT_FILTER, ((sb_getmixer (OUT_FILTER) & ~STEREO_DAC) + | (mode ? STEREO_DAC : MONO_DAC))); +} + +static int +detect_mixer (void) +{ + /* + * Detect the mixer by changing parameters of two volume channels. If the + * values read back match with the values written, the mixer is there (is + * it?) + */ + sb_setmixer (FM_VOL, 0xff); + sb_setmixer (VOC_VOL, 0x33); + + if (sb_getmixer (FM_VOL) != 0xff) + return 0; /* No match */ + if (sb_getmixer (VOC_VOL) != 0x33) + return 0; + + return 1; +} + +static void +change_bits (unsigned char *regval, int dev, int chn, int newval) +{ + unsigned char mask; + int shift; + + mask = (1 << (*iomap)[dev][chn].nbits) - 1; + newval = ((newval * mask) + 50) / 100; /* Scale it */ + + shift = (*iomap)[dev][chn].bitoffs - (*iomap)[dev][LEFT_CHN].nbits + 1; + + *regval &= ~(mask << shift); /* Filter out the previous value */ + *regval |= (newval & mask) << shift; /* Set the new value */ +} + +static int +sb_mixer_get (int dev) +{ + if (!((1 << dev) & supported_devices)) + return RET_ERROR (EINVAL); + + return levels[dev]; +} + +static int +sb_mixer_set (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 (!(supported_devices & (1 << dev))) /* Not supported */ + return RET_ERROR (EINVAL); + + regoffs = (*iomap)[dev][LEFT_CHN].regno; + + if (regoffs == 0) + return RET_ERROR (EINVAL); + + val = sb_getmixer (regoffs); + change_bits (&val, dev, LEFT_CHN, left); + + levels[dev] = left | (left << 8); + + if ((*iomap)[dev][RIGHT_CHN].regno != regoffs) /* Change register */ + { + sb_setmixer (regoffs, val); /* Save the old one */ + regoffs = (*iomap)[dev][RIGHT_CHN].regno; + + if (regoffs == 0) + return left | (left << 8); /* Just left channel present */ + + val = sb_getmixer (regoffs); /* Read the new one */ + } + + change_bits (&val, dev, RIGHT_CHN, right); + sb_setmixer (regoffs, val); + + levels[dev] = left | (right << 8); + return left | (right << 8); +} + +static void +set_recsrc (int src) +{ + sb_setmixer (RECORD_SRC, (sb_getmixer (RECORD_SRC) & ~7) | (src & 0x7)); +} + +static int +set_recmask (int mask) +{ + int devmask, i; + unsigned char regimageL, regimageR; + + devmask = mask & supported_rec_devices; + + switch (mixer_model) + { + case 3: + + if (devmask != SOUND_MASK_MIC && + devmask != SOUND_MASK_LINE && + devmask != SOUND_MASK_CD) + { /* More than one devices selected. Drop the + * previous selection */ + devmask &= ~recmask; + } + + if (devmask != SOUND_MASK_MIC && + devmask != SOUND_MASK_LINE && + devmask != SOUND_MASK_CD) + { /* More than one devices selected. Default to + * mic */ + devmask = SOUND_MASK_MIC; + } + + + if (devmask ^ recmask) /* Input source changed */ + { + switch (devmask) + { + + case SOUND_MASK_MIC: + set_recsrc (SRC_MIC); + break; + + case SOUND_MASK_LINE: + set_recsrc (SRC_LINE); + break; + + case SOUND_MASK_CD: + set_recsrc (SRC_CD); + break; + + default: + set_recsrc (SRC_MIC); + } + } + + break; + + case 4: + if (!devmask) + devmask = SOUND_MASK_MIC; + + regimageL = regimageR = 0; + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) + if ((1 << i) & devmask) + { + regimageL |= sb16_recmasks_L[i]; + regimageR |= sb16_recmasks_R[i]; + } + sb_setmixer (SB16_IMASK_L, regimageL); + sb_setmixer (SB16_IMASK_R, regimageR); + break; + } + + recmask = devmask; + return recmask; +} + +static int +sb_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg) +{ + if (((cmd >> 8) & 0xff) == 'M') + { + if (cmd & IOC_IN) + switch (cmd & 0xff) + { + case SOUND_MIXER_RECSRC: + return IOCTL_OUT (arg, set_recmask (IOCTL_IN (arg))); + break; + + default: + return IOCTL_OUT (arg, sb_mixer_set (cmd & 0xff, IOCTL_IN (arg))); + } + else + switch (cmd & 0xff) /* Return parameters */ + { + + case SOUND_MIXER_RECSRC: + return IOCTL_OUT (arg, recmask); + break; + + case SOUND_MIXER_DEVMASK: + return IOCTL_OUT (arg, supported_devices); + break; + + case SOUND_MIXER_STEREODEVS: + return IOCTL_OUT (arg, supported_devices & + ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER)); + break; + + case SOUND_MIXER_RECMASK: + return IOCTL_OUT (arg, supported_rec_devices); + break; + + case SOUND_MIXER_CAPS: + return IOCTL_OUT (arg, mixer_caps); + break; + + default: + return IOCTL_OUT (arg, sb_mixer_get (cmd & 0xff)); + } + } + else + return RET_ERROR (EINVAL); +} + +static struct mixer_operations sb_mixer_operations = +{ + sb_mixer_ioctl +}; + +static void +sb_mixer_reset (void) +{ + int i; + + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) + sb_mixer_set (i, levels[i]); + set_recmask (SOUND_MASK_MIC); +} + +void +sb_mixer_init (int major_model) +{ + sb_setmixer (0x00, 0); /* Reset mixer */ + + if (!detect_mixer ()) + return; /* No mixer. Why? */ + + mixer_initialized = 1; + mixer_model = major_model; + + switch (major_model) + { + case 3: + mixer_caps = SOUND_CAP_EXCL_INPUT; + supported_devices = SBPRO_MIXER_DEVICES; + supported_rec_devices = SBPRO_RECORDING_DEVICES; + iomap = &sbpro_mix; + break; + + case 4: + mixer_caps = 0; + supported_devices = SB16_MIXER_DEVICES; + supported_rec_devices = SB16_RECORDING_DEVICES; + iomap = &sb16_mix; + break; + + default: + printk ("SB Warning: Unsupported mixer type\n"); + return; + } + + mixer_devs[num_mixers++] = &sb_mixer_operations; + sb_mixer_reset (); +} + +#endif diff --git a/sys/i386/isa/sound/sb_mixer.h b/sys/i386/isa/sound/sb_mixer.h new file mode 100644 index 000000000000..304af6423baa --- /dev/null +++ b/sys/i386/isa/sound/sb_mixer.h @@ -0,0 +1,172 @@ +/* + * 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 + * 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. + * + */ +#define SBPRO_RECORDING_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD) + +#define SBPRO_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_MIC | \ + SOUND_MASK_CD | SOUND_MASK_VOLUME) + +#define SB16_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \ + 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_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE) + +/* + * Mixer registers + * + * NOTE! RECORD_SRC == IN_FILTER + */ + +/* + * Mixer registers of SB Pro + */ +#define VOC_VOL 0x04 +#define MIC_VOL 0x0A +#define MIC_MIX 0x0A +#define RECORD_SRC 0x0C +#define IN_FILTER 0x0C +#define OUT_FILTER 0x0E +#define MASTER_VOL 0x22 +#define FM_VOL 0x26 +#define CD_VOL 0x28 +#define LINE_VOL 0x2E +#define IRQ_NR 0x80 +#define DMA_NR 0x81 +#define IRQ_STAT 0x82 +#define OPSW 0x3c + +#define FREQ_HI (1 << 3)/* Use High-frequency ANFI filters */ +#define FREQ_LOW 0 /* Use Low-frequency ANFI filters */ +#define FILT_ON 0 /* Yes, 0 to turn it on, 1 for off */ +#define FILT_OFF (1 << 5) + +#define MONO_DAC 0x00 +#define STEREO_DAC 0x02 + +/* + * Mixer registers of SB16 + */ +#define SB16_IMASK_L 0x3d +#define SB16_IMASK_R 0x3e + +#define LEFT_CHN 0 +#define RIGHT_CHN 1 + +struct mixer_def { + unsigned int regno: 8; + unsigned int bitoffs:4; + unsigned int nbits:4; +}; + + +typedef struct mixer_def mixer_tab[32][2]; +typedef struct mixer_def mixer_ent; + +#define MIX_ENT(name, reg_l, bit_l, len_l, reg_r, bit_r, len_r) \ + {{reg_l, bit_l, len_l}, {reg_r, bit_r, len_r}} + +#ifdef __SB_MIXER_C__ +mixer_tab sbpro_mix = { +MIX_ENT(SOUND_MIXER_VOLUME, 0x22, 7, 4, 0x22, 3, 4), +MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_SYNTH, 0x26, 7, 4, 0x26, 3, 4), +MIX_ENT(SOUND_MIXER_PCM, 0x04, 7, 4, 0x04, 3, 4), +MIX_ENT(SOUND_MIXER_SPEAKER, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_LINE, 0x2e, 7, 4, 0x2e, 3, 4), +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) +}; + +mixer_tab sb16_mix = { +MIX_ENT(SOUND_MIXER_VOLUME, 0x30, 7, 5, 0x31, 7, 5), +MIX_ENT(SOUND_MIXER_BASS, 0x46, 7, 4, 0x47, 7, 4), +MIX_ENT(SOUND_MIXER_TREBLE, 0x44, 7, 4, 0x45, 7, 4), +MIX_ENT(SOUND_MIXER_SYNTH, 0x34, 7, 5, 0x35, 7, 5), +MIX_ENT(SOUND_MIXER_PCM, 0x32, 7, 5, 0x33, 7, 5), +MIX_ENT(SOUND_MIXER_SPEAKER, 0x3b, 7, 2, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_LINE, 0x38, 7, 5, 0x39, 7, 5), +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) +}; + +static unsigned short levels[SOUND_MIXER_NRDEVICES] = +{ + 0x5a5a, /* Master Volume */ + 0x3232, /* Bass */ + 0x3232, /* Treble */ + 0x4b4b, /* FM */ + 0x4b4b, /* PCM */ + 0x4b4b, /* PC Speaker */ + 0x4b4b, /* Ext Line */ + 0x0000, /* Mic */ + 0x4b4b, /* CD */ + 0x4b4b, /* Recording monitor */ + 0x4b4b, /* SB PCM */ + 0x4b4b}; /* Recording level */ + +static unsigned char sb16_recmasks_L[SOUND_MIXER_NRDEVICES] = +{ + 0x00, /* SOUND_MIXER_VOLUME */ + 0x00, /* SOUND_MIXER_BASS */ + 0x00, /* SOUND_MIXER_TREBLE */ + 0x40, /* SOUND_MIXER_SYNTH */ + 0x00, /* SOUND_MIXER_PCM */ + 0x00, /* SOUND_MIXER_SPEAKER */ + 0x10, /* SOUND_MIXER_LINE */ + 0x01, /* SOUND_MIXER_MIC */ + 0x04, /* SOUND_MIXER_CD */ + 0x00, /* SOUND_MIXER_IMIX */ + 0x00, /* SOUND_MIXER_ALTPCM */ + 0x00 /* SOUND_MIXER_RECLEV */ +}; + +static unsigned char sb16_recmasks_R[SOUND_MIXER_NRDEVICES] = +{ + 0x00, /* SOUND_MIXER_VOLUME */ + 0x00, /* SOUND_MIXER_BASS */ + 0x00, /* SOUND_MIXER_TREBLE */ + 0x20, /* SOUND_MIXER_SYNTH */ + 0x00, /* SOUND_MIXER_PCM */ + 0x00, /* SOUND_MIXER_SPEAKER */ + 0x08, /* SOUND_MIXER_LINE */ + 0x01, /* SOUND_MIXER_MIC */ + 0x02, /* SOUND_MIXER_CD */ + 0x00, /* SOUND_MIXER_IMIX */ + 0x00, /* SOUND_MIXER_ALTPCM */ + 0x00 /* SOUND_MIXER_RECLEV */ +}; +#endif diff --git a/sys/i386/isa/sound/sequencer.c b/sys/i386/isa/sound/sequencer.c index 7df08120ebcc..a015925732df 100644 --- a/sys/i386/isa/sound/sequencer.c +++ b/sys/i386/isa/sound/sequencer.c @@ -1,5 +1,5 @@ /* - * linux/kernel/chr_drv/sound/sequencer.c + * sound/sequencer.c * * The sequencer personality manager. * @@ -37,7 +37,9 @@ static int sequencer_ok = 0; DEFINE_WAIT_QUEUE (seq_sleeper, seq_sleep_flag); -DEFINE_WAIT_QUEUE (midi_sleeper, midi_sleep_flag); +/* DEFINE_WAIT_QUEUE (midi_sleeper, midi_sleep_flag); */ +#define midi_sleeper seq_sleeper +#define midi_sleep_flag seq_sleep_flag static int midi_opened[MAX_MIDI_DEV] = {0}; /* 1 if the process has opened MIDI */ @@ -49,8 +51,10 @@ long seq_time = 0; /* Reference point for the timer */ #include "tuning.h" #define EV_SZ 8 -static unsigned char queue[SEQ_MAX_QUEUE][EV_SZ]; -static unsigned char iqueue[SEQ_MAX_QUEUE][4]; +#define IEV_SZ 4 +static unsigned char *queue = NULL; /* SEQ_MAX_QUEUE * EV_SZ bytes */ +static unsigned char *iqueue = NULL; /* SEQ_MAX_QUEUE * IEV_SZ bytes */ + static volatile int qhead = 0, qtail = 0, qlen = 0; static volatile int iqhead = 0, iqtail = 0, iqlen = 0; static volatile int seq_playing = 0; @@ -83,13 +87,13 @@ sequencer_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) { if (!iqlen) { - INTERRUPTIBLE_SLEEP_ON (midi_sleeper, midi_sleep_flag); + DO_SLEEP (midi_sleeper, midi_sleep_flag, 0); if (!iqlen) return count - c; } - COPY_TO_USER (buf, p, &iqueue[iqhead][0], 4); + COPY_TO_USER (buf, p, &iqueue[iqhead * IEV_SZ], IEV_SZ); p += 4; c -= 4; @@ -114,14 +118,14 @@ copy_to_input (unsigned char *event) if (iqlen >= (SEQ_MAX_QUEUE - 1)) return; /* Overflow */ - memcpy (iqueue[iqtail], event, 4); + memcpy (&iqueue[iqtail * IEV_SZ], event, IEV_SZ); iqlen++; iqtail = (iqtail + 1) % SEQ_MAX_QUEUE; DISABLE_INTR (flags); - if (midi_sleep_flag) + if (SOMEONE_WAITING (midi_sleeper, midi_sleep_flag)) { - WAKE_UP (midi_sleeper); + WAKE_UP (midi_sleeper, midi_sleep_flag); } RESTORE_INTR (flags); } @@ -266,16 +270,16 @@ seq_queue (unsigned char *note) if (!seq_playing) seq_startplay (); /* Give chance to drain the queue */ - if (qlen >= SEQ_MAX_QUEUE && !seq_sleep_flag) + if (qlen >= SEQ_MAX_QUEUE && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) { /* Sleep until there is enough space on the queue */ - INTERRUPTIBLE_SLEEP_ON (seq_sleeper, seq_sleep_flag); + DO_SLEEP (seq_sleeper, seq_sleep_flag, 0); } if (qlen >= SEQ_MAX_QUEUE) return 0; /* To be sure */ - memcpy (&queue[qtail][0], note, EV_SZ); + memcpy (&queue[qtail * EV_SZ], note, EV_SZ); qtail = (qtail + 1) % SEQ_MAX_QUEUE; qlen++; @@ -342,7 +346,7 @@ seq_startplay (void) qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE; qlen--; - q = &queue[this_one][0]; + q = &queue[this_one * EV_SZ]; switch (q[0]) { @@ -378,10 +382,9 @@ seq_startplay (void) unsigned long flags; DISABLE_INTR (flags); - if (seq_sleep_flag) + if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) { - seq_sleep_flag = 0; - WAKE_UP (seq_sleeper); + WAKE_UP (seq_sleeper, seq_sleep_flag); } RESTORE_INTR (flags); } @@ -449,10 +452,9 @@ seq_startplay (void) unsigned long flags; DISABLE_INTR (flags); - if (seq_sleep_flag) + if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) { - seq_sleep_flag = 0; - WAKE_UP (seq_sleeper); + WAKE_UP (seq_sleeper, seq_sleep_flag); } RESTORE_INTR (flags); } @@ -461,86 +463,87 @@ seq_startplay (void) int sequencer_open (int dev, struct fileinfo *file) - { - int retval, mode, i; +{ + int retval, mode, i; - dev = dev >> 4; - mode = file->mode & O_ACCMODE; + dev = dev >> 4; + mode = file->mode & O_ACCMODE; - DEB (printk ("sequencer_open(dev=%d)\n", dev)); + DEB (printk ("sequencer_open(dev=%d)\n", dev)); - if (!sequencer_ok) - { - printk ("Soundcard: Sequencer not initialized\n"); - return RET_ERROR (ENXIO); - } - - if (dev) /* Patch manager device */ - { - int err; - - dev--; - if (pmgr_present[dev]) - return RET_ERROR (EBUSY); - if ((err = pmgr_open (dev)) < 0) - return err; /* Failed */ - - pmgr_present[dev] = 1; - return err; - } - - if (sequencer_busy) - { - printk ("Sequencer busy\n"); - return RET_ERROR (EBUSY); - } - - if (!(num_synths + num_midis)) + if (!sequencer_ok) + { + printk ("Soundcard: Sequencer not initialized\n"); return RET_ERROR (ENXIO); + } - synth_open_mask = 0; + if (dev) /* Patch manager device */ + { + int err; - if (mode == OPEN_WRITE || mode == OPEN_READWRITE) - for (i = 0; i < num_synths; i++) /* Open synth devices */ - if (synth_devs[i]->open (i, mode) < 0) - printk ("Sequencer: Warning! Cannot open synth device #%d\n", i); - else - synth_open_mask |= (1 << i); + dev--; + if (pmgr_present[dev]) + return RET_ERROR (EBUSY); + if ((err = pmgr_open (dev)) < 0) + return err; /* Failed */ - seq_time = GET_TIME (); + pmgr_present[dev] = 1; + return err; + } - for (i = 0; i < num_midis; i++) - { - midi_opened[i] = 0; - midi_written[i] = 0; - } + if (sequencer_busy) + { + printk ("Sequencer busy\n"); + return RET_ERROR (EBUSY); + } - if (mode == OPEN_READ || mode == OPEN_READWRITE) - { /* Initialize midi input devices */ - if (!num_midis) - { - printk ("Sequencer: No Midi devices. Input not possible\n"); - return RET_ERROR (ENXIO); - } + if (!(num_synths + num_midis)) + return RET_ERROR (ENXIO); - for (i = 0; i < num_midis; i++) - { - if ((retval = midi_devs[i]->open (i, mode, + synth_open_mask = 0; + + if (mode == OPEN_WRITE || mode == OPEN_READWRITE) + for (i = 0; i < num_synths; i++) /* Open synth devices */ + if (synth_devs[i]->open (i, mode) < 0) + printk ("Sequencer: Warning! Cannot open synth device #%d\n", i); + else + synth_open_mask |= (1 << i); + + seq_time = GET_TIME (); + + for (i = 0; i < num_midis; i++) + { + midi_opened[i] = 0; + midi_written[i] = 0; + } + + if (mode == OPEN_READ || mode == OPEN_READWRITE) + { /* Initialize midi input devices */ + if (!num_midis) + { + printk ("Sequencer: No Midi devices. Input not possible\n"); + return RET_ERROR (ENXIO); + } + + for (i = 0; i < num_midis; i++) + { + if ((retval = midi_devs[i]->open (i, mode, sequencer_midi_input, sequencer_midi_output)) >= 0) - midi_opened[i] = 1; - } - } + midi_opened[i] = 1; + } + } - sequencer_busy = 1; - seq_sleep_flag = midi_sleep_flag = 0; - output_treshold = SEQ_MAX_QUEUE / 2; + sequencer_busy = 1; + RESET_WAIT_QUEUE (seq_sleeper, seq_sleep_flag); + RESET_WAIT_QUEUE (midi_sleeper, midi_sleep_flag); + output_treshold = SEQ_MAX_QUEUE / 2; - for (i = 0; i < num_synths; i++) - if (pmgr_present[i]) - pmgr_inform (i, PM_E_OPENED, 0, 0, 0, 0); + for (i = 0; i < num_synths; i++) + if (pmgr_present[i]) + pmgr_inform (i, PM_E_OPENED, 0, 0, 0, 0); - return 0; - } + return 0; +} void seq_drain_midi_queues (void) @@ -553,7 +556,7 @@ seq_drain_midi_queues (void) n = 1; - while (!PROCESS_ABORTING && n) + while (!PROCESS_ABORTING (midi_sleeper, midi_sleep_flag) && n) { n = 0; @@ -568,70 +571,70 @@ seq_drain_midi_queues (void) */ if (n) { - REQUEST_TIMEOUT (HZ / 10, seq_sleeper); - INTERRUPTIBLE_SLEEP_ON (seq_sleeper, seq_sleep_flag); + DO_SLEEP (seq_sleeper, seq_sleep_flag, HZ / 10); } } } void sequencer_release (int dev, struct fileinfo *file) - { - int i; - int mode = file->mode & O_ACCMODE; +{ + int i; + int mode = file->mode & O_ACCMODE; - dev = dev >> 4; + dev = dev >> 4; - DEB (printk ("sequencer_release(dev=%d)\n", dev)); + DEB (printk ("sequencer_release(dev=%d)\n", dev)); - if (dev) /* Patch manager device */ - { - dev--; - pmgr_release (dev); - pmgr_present[dev] = 0; - return; - } + if (dev) /* Patch manager device */ + { + dev--; + pmgr_release (dev); + pmgr_present[dev] = 0; + return; + } - /* + /* * Wait until the queue is empty - */ - while (!PROCESS_ABORTING && qlen) - { - seq_sync (); - } + */ - if (mode != OPEN_READ) - seq_drain_midi_queues (); /* Ensure the output queues are empty */ - seq_reset (); - if (mode != OPEN_READ) - seq_drain_midi_queues (); /* Flush the all notes off messages */ + while (!PROCESS_ABORTING (seq_sleeper, seq_sleep_flag) && qlen) + { + seq_sync (); + } - for (i = 0; i < num_midis; i++) - if (midi_opened[i]) - midi_devs[i]->close (i); + if (mode != OPEN_READ) + seq_drain_midi_queues (); /* Ensure the output queues are empty */ + seq_reset (); + if (mode != OPEN_READ) + seq_drain_midi_queues (); /* Flush the all notes off messages */ - if (mode == OPEN_WRITE || mode == OPEN_READWRITE) - for (i = 0; i < num_synths; i++) - if (synth_open_mask & (1 << i)) /* Actually opened */ - if (synth_devs[i]) - synth_devs[i]->close (i); + for (i = 0; i < num_midis; i++) + if (midi_opened[i]) + midi_devs[i]->close (i); + if (mode == OPEN_WRITE || mode == OPEN_READWRITE) for (i = 0; i < num_synths; i++) - if (pmgr_present[i]) - pmgr_inform (i, PM_E_CLOSED, 0, 0, 0, 0); + if (synth_open_mask & (1 << i)) /* Actually opened */ + if (synth_devs[i]) + synth_devs[i]->close (i); - sequencer_busy = 0; - } + for (i = 0; i < num_synths; i++) + if (pmgr_present[i]) + pmgr_inform (i, PM_E_CLOSED, 0, 0, 0, 0); + + sequencer_busy = 0; +} static int seq_sync (void) { - if (qlen && !seq_playing && !PROCESS_ABORTING) + if (qlen && !seq_playing && !PROCESS_ABORTING (seq_sleeper, seq_sleep_flag)) seq_startplay (); - if (qlen && !seq_sleep_flag) /* Queue not empty */ + if (qlen && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) /* Queue not empty */ { - INTERRUPTIBLE_SLEEP_ON (seq_sleeper, seq_sleep_flag); + DO_SLEEP (seq_sleeper, seq_sleep_flag, 0); } return qlen; @@ -654,8 +657,7 @@ midi_outc (int dev, unsigned char data) while (n && !midi_devs[dev]->putc (dev, data)) { - REQUEST_TIMEOUT (1, seq_sleeper); - INTERRUPTIBLE_SLEEP_ON (seq_sleeper, seq_sleep_flag); + DO_SLEEP (seq_sleeper, seq_sleep_flag, 4); n--; } } @@ -684,8 +686,9 @@ seq_reset (void) { for (chn = 0; chn < 16; chn++) { - midi_outc (i, 0xb0 + chn); /* Channel message */ - midi_outc (i, 0x7b);/* All notes off */ + midi_outc (i, + (unsigned char) (0xb0 + (chn & 0xff))); /* Channel msg */ + midi_outc (i, 0x7b); /* All notes off */ midi_outc (i, 0); /* Dummy parameter */ } @@ -697,7 +700,7 @@ seq_reset (void) seq_playing = 0; - if (seq_sleep_flag) + if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) printk ("Sequencer Warning: Unexpected sleeping process\n"); } @@ -720,7 +723,7 @@ sequencer_ioctl (int dev, struct fileinfo *file, if (mode == OPEN_READ) return 0; - while (qlen && !PROCESS_ABORTING) + while (qlen && !PROCESS_ABORTING (seq_sleeper, seq_sleep_flag)) seq_sync (); return 0; break; @@ -979,7 +982,6 @@ sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * w case SEL_IN: if (!iqlen) { - midi_sleep_flag = 1; select_wait (&midi_sleeper, wait); return 0; } @@ -990,7 +992,6 @@ sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * w case SEL_OUT: if (qlen >= SEQ_MAX_QUEUE) { - seq_sleep_flag = 1; select_wait (&seq_sleeper, wait); return 0; } @@ -1039,7 +1040,7 @@ note_to_freq (int note_num) else if (octave > BASE_OCTAVE) note_freq <<= (octave - BASE_OCTAVE); - /* note_freq >>= 1; */ + /* note_freq >>= 1; */ return note_freq; } @@ -1092,6 +1093,9 @@ sequencer_init (long mem_start) { sequencer_ok = 1; + PERMANENT_MALLOC (unsigned char *, queue, SEQ_MAX_QUEUE * EV_SZ, mem_start); + PERMANENT_MALLOC (unsigned char *, iqueue, SEQ_MAX_QUEUE * IEV_SZ, mem_start); + return mem_start; } @@ -1111,14 +1115,14 @@ sequencer_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) int sequencer_open (int dev, struct fileinfo *file) - { - return RET_ERROR (ENXIO); - } +{ + return RET_ERROR (ENXIO); +} void sequencer_release (int dev, struct fileinfo *file) - { - } +{ +} int sequencer_ioctl (int dev, struct fileinfo *file, unsigned int cmd, unsigned int arg) diff --git a/sys/i386/isa/sound/sound_calls.h b/sys/i386/isa/sound/sound_calls.h index 89bd79604359..97fb7699666e 100644 --- a/sys/i386/isa/sound/sound_calls.h +++ b/sys/i386/isa/sound/sound_calls.h @@ -16,23 +16,10 @@ int DMAbuf_open_dma (int chan); void DMAbuf_close_dma (int chan); void DMAbuf_reset_dma (int chan); void DMAbuf_inputintr(int dev); -void DMAbuf_outputintr(int dev); +void DMAbuf_outputintr(int dev, int underflow_flag); /* - * System calls for the /dev/dsp - */ - -int dsp_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count); -int dsp_write (int dev, struct fileinfo *file, snd_rw_buf *buf, int count); -int dsp_open (int dev, struct fileinfo *file, int bits); -void dsp_release (int dev, struct fileinfo *file); -int dsp_ioctl (int dev, struct fileinfo *file, - unsigned int cmd, unsigned int arg); -int dsp_lseek (int dev, struct fileinfo *file, off_t offset, int orig); -long dsp_init (long mem_start); - -/* - * System calls for the /dev/audio + * System calls for /dev/dsp and /dev/audio */ int audio_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count); @@ -108,11 +95,46 @@ 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)); +void snd_release_irq(int vect); +void sound_dma_malloc(int dev); +void sound_dma_free(int dev); + +/* From sound_switch.c */ +int sound_read_sw (int dev, struct fileinfo *file, snd_rw_buf *buf, int count); +int sound_write_sw (int dev, struct fileinfo *file, snd_rw_buf *buf, int count); +int sound_open_sw (int dev, struct fileinfo *file); +void sound_release_sw (int dev, struct fileinfo *file); +int sound_ioctl_sw (int dev, struct fileinfo *file, + unsigned int cmd, unsigned long arg); /* From sb_dsp.c */ int sb_dsp_detect (struct address_info *hw_config); long sb_dsp_init (long mem_start, struct address_info *hw_config); void sb_dsp_disable_midi(void); +int sb_get_irq(void); +void sb_free_irq(void); +int sb_dsp_command (unsigned char val); +int sb_reset_dsp (void); + +/* From sb16_dsp.c */ +void sb16_dsp_interrupt (int unused); +long sb16_dsp_init(long mem_start, struct address_info *hw_config); +int sb16_dsp_detect(struct address_info *hw_config); + +/* From sb16_midi.c */ +void sb16midiintr (int unit); +long attach_sb16midi(long mem_start, struct address_info * hw_config); +int probe_sb16midi(struct address_info *hw_config); + +/* From sb_midi.c */ +void sb_midi_init(int model); + +/* From sb_mixer.c */ +void sb_setmixer (unsigned int port, unsigned int value); +int sb_getmixer (unsigned int port); +void sb_mixer_set_stereo(int mode); +void sb_mixer_init(int major_model); /* From opl3.c */ int opl3_detect (int ioaddr); @@ -156,7 +178,7 @@ int gus_wave_detect(int baseaddr); long gus_wave_init(long mem_start, int irq, int dma); void gus_voice_irq(void); unsigned char gus_read8 (int reg); -void gus_write8(int reg, unsigned char data); +void gus_write8(int reg, unsigned int data); void guswave_dma_irq(void); void gus_delay(void); diff --git a/sys/i386/isa/sound/sound_config.h b/sys/i386/isa/sound/sound_config.h index 9cbd8103b8f5..0d30c12aadc4 100644 --- a/sys/i386/isa/sound/sound_config.h +++ b/sys/i386/isa/sound/sound_config.h @@ -30,6 +30,16 @@ #include "local.h" + +#undef CONFIGURE_SOUNDCARD +#undef DYNAMIC_BUFFER + +#ifdef KERNEL_SOUNDCARD +#define CONFIGURE_SOUNDCARD +#define DYNAMIC_BUFFER +#undef LOADABLE_SOUNDCARD +#endif + #ifdef EXCLUDE_SEQUENCER #ifndef EXCLUDE_MIDI #define EXCLUDE_MIDI @@ -42,6 +52,10 @@ #endif #endif +#ifndef SND_DEFAULT_ENABLE +#define SND_DEFAULT_ENABLE 1 +#endif + /** UWM - new MIDI stuff **/ #ifdef EXCLUDE_CHIP_MIDI @@ -75,6 +89,14 @@ If your card has nonstandard I/O address or IRQ number, change defines #define SBC_DMA 1 #endif +#ifndef SB16_DMA +#define SB16_DMA 6 +#endif + +#ifndef SB16MIDI_BASE +#define SB16MIDI_BASE 0x300 +#endif + #ifndef PAS_BASE #define PAS_BASE 0x388 #endif @@ -111,6 +133,10 @@ If your card has nonstandard I/O address or IRQ number, change defines #define MPU_IRQ 6 #endif +#ifndef MAX_REALTIME_FACTOR +#define MAX_REALTIME_FACTOR 4 +#endif + /************* PCM DMA buffer sizes *******************/ /* If you are using high playback or recording speeds, the default buffersize @@ -132,8 +158,6 @@ If your card has nonstandard I/O address or IRQ number, change defines #define DMA_AUTOINIT 0x10 -#define SND_MAJOR 14 - #define FM_MONO 0x388 /* This is the I/O address used by AdLib */ /* SEQ_MAX_QUEUE is the maximum number of sequencer events buffered by the @@ -178,10 +202,10 @@ If your card has nonstandard I/O address or IRQ number, change defines #define ON 1 #define OFF 0 -#define MAX_DSP_DEV 3 -#define MAX_MIXER_DEV 1 +#define MAX_DSP_DEV 4 +#define MAX_MIXER_DEV 2 #define MAX_SYNTH_DEV 3 -#define MAX_MIDI_DEV 3 +#define MAX_MIDI_DEV 4 struct fileinfo { int mode; /* Open mode */ @@ -193,6 +217,15 @@ struct address_info { int dma; }; +/* + * Process wakeup reasons + */ +#define WK_NONE 0x00 +#define WK_WAKEUP 0x01 +#define WK_TIMEOUT 0x02 +#define WK_SIGNAL 0x04 +#define WK_SLEEP 0x08 + #define OPEN_READ 1 #define OPEN_WRITE 2 #define OPEN_READWRITE 3 diff --git a/sys/i386/isa/sound/sound_switch.c b/sys/i386/isa/sound/sound_switch.c new file mode 100644 index 000000000000..52120d53e49d --- /dev/null +++ b/sys/i386/isa/sound/sound_switch.c @@ -0,0 +1,444 @@ +/* + * sound/sound_switch.c + * + * The system call switch + * + * 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. + * + */ + +#include "sound_config.h" + +#ifdef CONFIGURE_SOUNDCARD + +struct sbc_device + { + int usecount; + }; + +static struct sbc_device sbc_devices[SND_NDEVS] = +{ + {0}}; + +static int in_use = 0; /* Total # of open device files (excluding + + * minor 0) */ + +/* + * /dev/sndstatus -device + */ +static char *status_buf = NULL; +static int status_len, status_ptr; +static int status_busy = 0; + +static int +put_status (char *s) +{ + int l; + + for (l = 0; l < 256, s[l]; l++); /* l=strlen(s); */ + + if (status_len + l >= 4000) + return 0; + + memcpy (&status_buf[status_len], s, l); + status_len += l; + + return 1; +} + +static int +put_status_int (unsigned int val, int radix) +{ + int l, v; + + static char hx[] = "0123456789abcdef"; + char buf[11]; + + if (!val) + return put_status ("0"); + + l = 0; + buf[10] = 0; + + while (val) + { + v = val % radix; + val = val / radix; + + buf[9 - l] = hx[v]; + l++; + } + + if (status_len + l >= 4000) + return 0; + + memcpy (&status_buf[status_len], &buf[10 - l], l); + status_len += l; + + return 1; +} + +static void +init_status (void) +{ + /* + * Write the status information to the status_buf and update status_len. + * There is a limit of 4000 bytes for the data. + */ + + int i; + + status_ptr = 0; + + put_status ("Sound Driver:" SOUND_VERSION_STRING + " (" SOUND_CONFIG_DATE " " SOUND_CONFIG_BY "@" + SOUND_CONFIG_HOST "." SOUND_CONFIG_DOMAIN ")" + "\n"); + + if (!put_status ("Config options: ")) + return; + if (!put_status_int (SELECTED_SOUND_OPTIONS, 16)) + return; + + if (!put_status ("\n\nHW config: \n")) + return; + + for (i = 0; i < (num_sound_drivers - 1); i++) + { + if (!supported_drivers[i].enabled) + if (!put_status ("(")) + return; + + if (!put_status ("Type ")) + return; + if (!put_status_int (supported_drivers[i].card_type, 10)) + return; + if (!put_status (": ")) + return; + if (!put_status (supported_drivers[i].name)) + return; + if (!put_status (" at 0x")) + return; + if (!put_status_int (supported_drivers[i].config.io_base, 16)) + return; + if (!put_status (" irq ")) + return; + if (!put_status_int (supported_drivers[i].config.irq, 10)) + return; + if (!put_status (" drq ")) + return; + if (!put_status_int (supported_drivers[i].config.dma, 10)) + return; + + if (!supported_drivers[i].enabled) + if (!put_status (")")) + return; + + if (!put_status ("\n")) + return; + } + + if (!put_status ("\nPCM devices:\n")) + return; + + for (i = 0; i < num_dspdevs; i++) + { + if (!put_status_int (i, 10)) + return; + if (!put_status (": ")) + return; + if (!put_status (dsp_devs[i]->name)) + return; + if (!put_status ("\n")) + return; + } + + if (!put_status ("\nSynth devices:\n")) + return; + + for (i = 0; i < num_synths; i++) + { + if (!put_status_int (i, 10)) + return; + if (!put_status (": ")) + return; + if (!put_status (synth_devs[i]->info->name)) + return; + if (!put_status ("\n")) + return; + } + + if (!put_status ("\nMidi devices:\n")) + return; + + for (i = 0; i < num_midis; i++) + { + if (!put_status_int (i, 10)) + return; + if (!put_status (": ")) + return; + if (!put_status (midi_devs[i]->info.name)) + return; + if (!put_status ("\n")) + return; + } + + if (num_mixers) + { + if (!put_status ("\nMixer(s) installed\n")) + return; + } + else + { + if (!put_status ("\nNo mixers installed\n")) + return; + } +} + +static int +read_status (snd_rw_buf * buf, int count) +{ + /* + * Return at most 'count' bytes from the status_buf. + */ + int l, c; + + l = count; + c = status_len - status_ptr; + + if (l > c) + l = c; + if (l <= 0) + return 0; + + COPY_TO_USER (buf, 0, &status_buf[status_ptr], l); + status_ptr += l; + + return l; +} + +int +sound_read_sw (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) +{ + DEB (printk ("sound_read_sw(dev=%d, count=%d)\n", dev, count)); + + switch (dev & 0x0f) + { + case SND_DEV_STATUS: + return read_status (buf, count); + break; + + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + return audio_read (dev, file, buf, count); + break; + + case SND_DEV_SEQ: + return sequencer_read (dev, file, buf, count); + break; + +#ifndef EXCLUDE_MPU401 + case SND_DEV_MIDIN: + return MIDIbuf_read (dev, file, buf, count); +#endif + + default: + printk ("Sound: Undefined minor device %d\n", dev); + } + + return RET_ERROR (EPERM); +} + +int +sound_write_sw (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) +{ + + DEB (printk ("sound_write_sw(dev=%d, count=%d)\n", dev, count)); + + switch (dev & 0x0f) + { + + case SND_DEV_SEQ: + return sequencer_write (dev, file, buf, count); + break; + + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + return audio_write (dev, file, buf, count); + break; + + default: + return RET_ERROR (EPERM); + } + + return count; +} + +int +sound_open_sw (int dev, struct fileinfo *file) +{ + int retval; + + DEB (printk ("sound_open_sw(dev=%d) : usecount=%d\n", dev, sbc_devices[dev].usecount)); + + if ((dev >= SND_NDEVS) || (dev < 0)) + { + printk ("Invalid minor device %d\n", dev); + return RET_ERROR (ENXIO); + } + + switch (dev & 0x0f) + { + case SND_DEV_STATUS: + if (status_busy) + return RET_ERROR (EBUSY); + status_busy = 1; + if ((status_buf = (char *) KERNEL_MALLOC (4000)) == NULL) + return RET_ERROR (EIO); + status_len = status_ptr = 0; + init_status (); + break; + + case SND_DEV_CTL: + return 0; + break; + + case SND_DEV_SEQ: + if ((retval = sequencer_open (dev, file)) < 0) + return retval; + break; + +#ifndef EXCLUDE_MPU401 + case SND_DEV_MIDIN: + if ((retval = MIDIbuf_open (dev, file)) < 0) + return retval; + break; +#endif + + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + if ((retval = audio_open (dev, file)) < 0) + return retval; + break; + + default: + printk ("Invalid minor device %d\n", dev); + return RET_ERROR (ENXIO); + } + + sbc_devices[dev].usecount++; + in_use++; + + return 0; +} + +void +sound_release_sw (int dev, struct fileinfo *file) +{ + + DEB (printk ("sound_release_sw(dev=%d)\n", dev)); + + switch (dev & 0x0f) + { + case SND_DEV_STATUS: + if (status_buf) + KERNEL_FREE (status_buf); + status_buf = NULL; + status_busy = 0; + break; + + case SND_DEV_CTL: + break; + + case SND_DEV_SEQ: + sequencer_release (dev, file); + break; + +#ifndef EXCLUDE_MPU401 + case SND_DEV_MIDIN: + MIDIbuf_release (dev, file); + break; +#endif + + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + audio_release (dev, file); + break; + + default: + printk ("Sound error: Releasing unknown device 0x%02x\n", dev); + } + + sbc_devices[dev].usecount--; + in_use--; +} + +int +sound_ioctl_sw (int dev, struct fileinfo *file, + unsigned int cmd, unsigned long arg) +{ + DEB (printk ("sound_ioctl_sw(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg)); + + switch (dev & 0x0f) + { + + case SND_DEV_CTL: + + if (!num_mixers) + return RET_ERROR (ENXIO); + + if ((dev >> 4) >= num_mixers) + return RET_ERROR (ENXIO); + + return mixer_devs[dev >> 4]->ioctl (dev >> 4, cmd, arg); + break; + + case SND_DEV_SEQ: + return sequencer_ioctl (dev, file, cmd, arg); + break; + + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + return audio_ioctl (dev, file, cmd, arg); + break; + +#ifndef EXCLUDE_MPU401 + case SND_DEV_MIDIN: + return MIDIbuf_ioctl (dev, file, cmd, arg); + break; +#endif + + default: + return RET_ERROR (EPERM); + break; + } + + return RET_ERROR (EPERM); +} +#endif diff --git a/sys/i386/isa/sound/soundcard.c b/sys/i386/isa/sound/soundcard.c index 79c9b09298d1..3448f32d0cf9 100644 --- a/sys/i386/isa/sound/soundcard.c +++ b/sys/i386/isa/sound/soundcard.c @@ -34,28 +34,20 @@ #include "dev_table.h" -int __timeout_val = 0; -int __process_aborting = 0; - u_int snd1mask; u_int snd2mask; u_int snd3mask; u_int snd4mask; u_int snd5mask; - -struct sbc_device -{ - int usecount; -}; +u_int snd6mask; +u_int snd7mask; +u_int snd8mask; +u_int snd9mask; #define FIX_RETURN(ret) {if ((ret)<0) return -(ret); else return 0;} -static struct sbc_device sbc_devices[SND_NDEVS]; static int timer_running = 0; -static int in_use = 0; /* Total # of open device files (excluding - * minor 0) */ - static int soundcards_installed = 0; /* Number of installed * soundcards */ static int soundcard_configured = 0; @@ -91,41 +83,7 @@ sndread (int dev, struct uio *buf) dev = minor (dev); - DEB (printk ("sound_read(dev=%d, count=%d)\n", dev, count)); - - switch (dev & 0x0f) /* It really has to be 0x0f */ - { - case SND_DEV_AUDIO: - FIX_RETURN (audio_read (dev, &files[dev], buf, count)); - break; - - case SND_DEV_DSP: - case SND_DEV_DSP16: - FIX_RETURN (dsp_read (dev, &files[dev], buf, count)); - break; - - case SND_DEV_SEQ: - FIX_RETURN (sequencer_read (dev, &files[dev], buf, count)); - break; - -#ifndef EXCLUDE_CHIP_MIDI - case CMIDI_DEV_PRO: - FIX_RETURN (CMIDI_read (dev, &files[dev], buf, count)); - - break; -#endif - - -#ifndef EXCLUDE_MPU401 - case SND_DEV_MIDIN: - FIX_RETURN (MIDIbuf_read (dev, &files[dev], buf, count)); -#endif - - default: - ; - } - - FIX_RETURN (-EPERM); + FIX_RETURN (sound_read_sw (dev, &files[dev], buf, count)); } int @@ -133,37 +91,9 @@ sndwrite (int dev, struct uio *buf) { int count = buf->uio_resid; - DEB (printk ("sound_write(dev=%d, count=%d)\n", dev, count)); - dev = minor (dev); - switch (dev & 0x0f) /* It really has to be 0x0f */ - { - - case SND_DEV_SEQ: - FIX_RETURN (sequencer_write (dev, &files[dev], buf, count)); - break; - - case SND_DEV_AUDIO: - FIX_RETURN (audio_write (dev, &files[dev], buf, count)); - break; - - case SND_DEV_DSP: - case SND_DEV_DSP16: - FIX_RETURN (dsp_write (dev, &files[dev], buf, count)); - break; - -#ifndef EXCLUDE_CHIP_MIDI - case CMIDI_DEV_PRO: - FIX_RETURN (CMIDI_write (dev, &files[dev], buf, count)); - break; -#endif - - default: - FIX_RETURN (-EPERM); - } - - FIX_RETURN (count); + FIX_RETURN (sound_write_sw (dev, &files[dev], buf, count)); } int @@ -173,16 +103,6 @@ sndopen (dev_t dev, int flags) dev = minor (dev); - /* printf("SND: Minor number is now : %ld\n",dev); */ - - DEB (printk ("sound_open(dev=%d) : usecount=%d\n", dev, sbc_devices[dev].usecount)); - - if ((dev >= SND_NDEVS) || (dev < 0)) - { - printk ("Invalid minor device %d\n", dev); - FIX_RETURN (-ENODEV); - } - if (!soundcard_configured && dev) { printk ("SoundCard Error: The soundcard system has not been configured\n"); @@ -198,62 +118,7 @@ sndopen (dev_t dev, int flags) else if (flags & FWRITE) files[dev].mode = OPEN_WRITE; - switch (dev & 0x0f) /* It has to be 0x0f. Trust me */ - { - case SND_DEV_CTL: - if (!soundcards_installed) - if (soundcard_configured) - { - printk ("Soundcard not installed\n"); - FIX_RETURN (-ENODEV); - } - break; - - case SND_DEV_SEQ: - if ((retval = sequencer_open (dev, &files[dev])) < 0) - FIX_RETURN (retval); - break; - -/** UWM stuff **/ - -#ifndef EXCLUDE_CHIP_MIDI - case CMIDI_DEV_PRO: - FIX_RETURN ( CMIDI_open (dev, &files[dev]) ); - break; -#endif - - -#ifndef EXCLUDE_MPU401 - case SND_DEV_MIDIN: - if ((retval = MIDIbuf_open (dev, &files[dev])) < 0) - FIX_RETURN (retval); - break; -#endif - - case SND_DEV_AUDIO: - if ((retval = audio_open (dev, &files[dev])) < 0) - FIX_RETURN (retval); - break; - - case SND_DEV_DSP: - if ((retval = dsp_open (dev, &files[dev], 8)) < 0) - FIX_RETURN (retval); - break; - - case SND_DEV_DSP16: - if ((retval = dsp_open (dev, &files[dev], 16)) < 0) - FIX_RETURN (retval); - break; - - default: - printk ("Invalid minor device %d\n", dev); - FIX_RETURN (-ENODEV); - } - - sbc_devices[dev].usecount++; - in_use++; - - FIX_RETURN (0); + FIX_RETURN(sound_open_sw (dev, &files[dev])); } int @@ -262,41 +127,7 @@ sndclose (dev_t dev, int flags) dev = minor (dev); - DEB (printk ("sound_release(dev=%d)\n", dev)); - - switch (dev & 0x0f) /* Has to be 0x0f */ - { - case SND_DEV_SEQ: - sequencer_release (dev, &files[dev]); - break; - -#ifndef EXCLUDE_CHIP_MIDI - case CMIDI_DEV_PRO: - CMIDI_close (dev, &files[dev]); - break; -#endif - -#ifndef EXCLUDE_MPU401 - case SND_DEV_MIDIN: - MIDIbuf_release (dev, &files[dev]); - break; -#endif - - case SND_DEV_AUDIO: - audio_release (dev, &files[dev]); - break; - - case SND_DEV_DSP: - case SND_DEV_DSP16: - dsp_release (dev, &files[dev]); - break; - - default:; - } - - sbc_devices[dev].usecount--; - in_use--; /* If not control port */ - + sound_release_sw(dev, &files[dev]); FIX_RETURN (0); } @@ -305,46 +136,7 @@ sndioctl (dev_t dev, int cmd, caddr_t arg, int mode) { dev = minor (dev); - DEB (printk ("sound_ioctl(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg)); - - switch (dev & 0x0f) - { - - case SND_DEV_CTL: - if (!num_mixers) - FIX_RETURN (-ENODEV); - - if (dev >= num_mixers) - FIX_RETURN (-ENODEV); - - FIX_RETURN (mixer_devs[dev]->ioctl (dev, cmd, (unsigned int) arg)); - break; - - case SND_DEV_SEQ: - FIX_RETURN (sequencer_ioctl (dev, &files[dev], cmd, (unsigned int) arg)); - break; - - case SND_DEV_AUDIO: - FIX_RETURN (audio_ioctl (dev, &files[dev], cmd, (unsigned int) arg)); - break; - - case SND_DEV_DSP: - case SND_DEV_DSP16: - FIX_RETURN (dsp_ioctl (dev, &files[dev], cmd, (unsigned int) arg)); - break; - -#ifndef EXCLUDE_MPU401 - case SND_DEV_MIDIN: - FIX_RETURN (MIDIbuf_ioctl (dev, &files[dev], cmd, (unsigned int) arg)); - break; -#endif - - default: - FIX_RETURN (-EPERM); - break; - } - - FIX_RETURN (-EPERM); + FIX_RETURN (sound_ioctl_sw (dev, &files[dev], cmd, (unsigned int) arg)); } int @@ -380,7 +172,6 @@ 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; - return sndtable_probe (dev->id_unit, &hw_config); } @@ -430,7 +221,6 @@ sndattach (struct isa_device *dev) dsp_initialized = 1; mem_start = DMAbuf_init (mem_start); mem_start = audio_init (mem_start); - mem_start = dsp_init (mem_start); } /** UWM stuff **/ @@ -459,11 +249,6 @@ sndattach (struct isa_device *dev) mem_start = sequencer_init (mem_start); } - for (i = 0; i < SND_NDEVS; i++) - { - sbc_devices[i].usecount = 0; - } - return TRUE; } @@ -514,7 +299,7 @@ void sound_stop_timer (void) { if (timer_running) - untimeout ((timeout_func_t)sequencer_timer, 0); /* XXX should fix */ + untimeout ((timeout_func_t)sequencer_timer, 0); timer_running = 0; } @@ -532,6 +317,7 @@ sound_mem_init (void) { dsp_init_mask |= (1 << dev); +#if 1 /* 0 */ if (sound_dma_automode[dev]) { sound_dma_automode[dev] = 0; /* Not possible with FreeBSD */ @@ -551,8 +337,10 @@ sound_mem_init (void) dma_pagesize = 131072; /* 128k */ else dma_pagesize = 65536; -#endif +#else dma_pagesize = 4096; /* use bounce buffer */ +#endif + /* More sanity checks */ @@ -561,6 +349,11 @@ sound_mem_init (void) sound_buffsizes[dev] &= ~0xfff; /* Truncate to n*4k */ if (sound_buffsizes[dev] < 4096) sound_buffsizes[dev] = 4096; +#else + dma_pagesize = 4096; + sound_buffsizes[dev] = 4096; + sound_buffcounts[dev] = 16; /* -> 64k */ +#endif /* Now allocate the buffers */ @@ -616,4 +409,15 @@ snd_ioctl_return (int *addr, int value) return 0; } +int +snd_set_irq_handler (int interrupt_level, void(*hndlr)(int)) +{ + return 1; +} + +void +snd_release_irq(int vect) +{ +} + #endif