diff -u --recursive --new-file v1.1.30/linux/Makefile linux/Makefile --- v1.1.30/linux/Makefile Mon Jul 18 14:48:27 1994 +++ linux/Makefile Mon Jul 18 09:51:22 1994 @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 1 -SUBLEVEL = 30 +SUBLEVEL = 31 all: Version zImage diff -u --recursive --new-file v1.1.30/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v1.1.30/linux/drivers/block/floppy.c Mon Jul 18 14:48:28 1994 +++ linux/drivers/block/floppy.c Mon Jul 18 22:51:13 1994 @@ -97,7 +97,7 @@ #define MAJOR_NR FLOPPY_MAJOR #include "blk.h" -static unsigned int changed_floppies = 0, fake_change = 0; +static unsigned int changed_floppies = 0, fake_change = 0, read_only = 0; static int initial_reset_flag = 0; static int need_configure = 1; /* for 82077 */ @@ -150,7 +150,7 @@ #define ST0 (reply_buffer[0]) #define ST1 (reply_buffer[1]) #define ST2 (reply_buffer[2]) -#define ST3 (reply_buffer[3]) +#define ST3 (reply_buffer[0]) /* result of GETSTATUS */ /* * This struct defines the different floppy types. @@ -1037,8 +1037,20 @@ output_byte(1); } +static void check_readonly(void) +{ + unsigned long mask = 1 << current_drive; + + read_only &= ~mask; + output_byte(FD_GETSTATUS); + output_byte(current_drive); + if ((result() == 1) && (ST3 & ST3_RY) && !(ST3 & ST3_FT) && (ST3 & ST3_WP)) + read_only |= mask; +} + static void floppy_ready(void) { + check_readonly(); if (inb(FD_DIR) & 0x80) { changed_floppies |= 1<i_rdev); + if (!fd_ref[inode->i_rdev & 3]--) { + printk("floppy_release with fd_ref == 0"); + fd_ref[inode->i_rdev & 3] = 0; + } + floppy_release_irq_and_dma(); +} + /* * floppy_open check for aliasing (/dev/fd0 can be the same as * /dev/PS0 etc), and disallows simultaneous access to the same @@ -1390,19 +1412,16 @@ buffer_drive = buffer_track = -1; if (old_dev && old_dev != inode->i_rdev) invalidate_buffers(old_dev); - if (filp && filp->f_mode) + if (filp && filp->f_mode) { check_disk_change(inode->i_rdev); - return 0; -} - -static void floppy_release(struct inode * inode, struct file * filp) -{ - fsync_dev(inode->i_rdev); - if (!fd_ref[inode->i_rdev & 3]--) { - printk("floppy_release with fd_ref == 0"); - fd_ref[inode->i_rdev & 3] = 0; + if (filp->f_mode & 2) { + if (1 & (read_only >> drive)) { + floppy_release(inode, filp); + return -EACCES; + } + } } - floppy_release_irq_and_dma(); + return 0; } static int check_floppy_change(dev_t dev) diff -u --recursive --new-file v1.1.30/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v1.1.30/linux/drivers/scsi/sd.c Mon Jul 18 14:48:29 1994 +++ linux/drivers/scsi/sd.c Mon Jul 18 11:28:10 1994 @@ -38,7 +38,7 @@ * Time out in seconds for disks and Magneto-opticals (which are slower). */ -#define SD_TIMEOUT 300 +#define SD_TIMEOUT 600 #define SD_MOD_TIMEOUT 750 #define CLUSTERABLE_DEVICE(SC) (SC->host->hostt->use_clustering && \ diff -u --recursive --new-file v1.1.30/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- v1.1.30/linux/drivers/scsi/sr.c Mon Jul 18 14:48:30 1994 +++ linux/drivers/scsi/sr.c Mon Jul 18 11:22:03 1994 @@ -636,7 +636,6 @@ static void sr_init_done (Scsi_Cmnd * SCpnt) { struct request * req; - struct task_struct * p; req = &SCpnt->request; req->dev = 0xfffe; /* Busy, but indicate request done */ diff -u --recursive --new-file v1.1.30/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c --- v1.1.30/linux/drivers/scsi/sr_ioctl.c Mon Jul 18 14:48:30 1994 +++ linux/drivers/scsi/sr_ioctl.c Mon Jul 18 11:21:50 1994 @@ -21,13 +21,12 @@ static void sr_ioctl_done(Scsi_Cmnd * SCpnt) { struct request * req; - struct task_struct * p; req = &SCpnt->request; req->dev = 0xfffe; /* Busy, but indicate request done */ if (req->sem != NULL) { - up(&req->sem); + up(req->sem); } } diff -u --recursive --new-file v1.1.30/linux/drivers/sound/.blurb linux/drivers/sound/.blurb --- v1.1.30/linux/drivers/sound/.blurb Sun May 1 12:12:22 1994 +++ linux/drivers/sound/.blurb Fri Apr 15 13:36:01 1994 @@ -1,6 +1,27 @@ -NOTE! This driver version is not compatible with the version 1.0c. - This means you have to use the latest version of the snd-util - package (2.0). The earlier ones (from 1.0) will not work. If you have - other programs using ioctl calls of the driver, they must be - recompiled. Most of them will not work without some source - modifications. +NOTE! + + This is an ALPHA TEST VERSION (pre 3.0). The latest + released version of this driver is now part of + Linux kernel distribution. For other operating systems + use the snd-driv-2.5.tar.gz package. + + This particular version contains lots of new features + BUT THERE ARE NO APPLICATIONS WHICH USE THEM. So there + is no need to install this version as long as you are + not developing the driver or applications which use it. + All new features are in the /dev/sequencer and /dev/midi + parts of the driver. + + + This version is little bit incomplete. Some features have + not been implemented for each soundcards yet. All features + of v2.4 should work OK. + +CAUTION! + This version of driver works with applications written and + compiled for v2.*. The problem is that APPLICATIONS COMPILED + WITH soundcard.h OF THIS VERSION WILL NOT WORK WITH OLDER DRIVER. + Be carefull when distributing applications compiled with this + version (just the apps using /dev/sequencer are incompatible). + +Hannu diff -u --recursive --new-file v1.1.30/linux/drivers/sound/CHANGELOG linux/drivers/sound/CHANGELOG --- v1.1.30/linux/drivers/sound/CHANGELOG Sun May 1 12:12:23 1994 +++ linux/drivers/sound/CHANGELOG Mon Jul 18 09:50:55 1994 @@ -1,8 +1,40 @@ -Changelog for version 2.5a --------------------------- +Changelog for version 2.90 +------------------------------------ -Since 2.5 -- Minor fix to read from /dev/sequencer +This is an intermediate release (v3.0 prototype with some experimental +features disabled). See experimental.txt for more info. + +Since pre-3.0-949712 +- GUS MAX support +- Partially working MSS/WSS support (could work with some cards). +- Hardware u-Law and A-Law support with AD1848/CS4248 and CS4231 codecs + (GUS MAX, GUS16, WSS etc). Hardware ADPCM is possible with GUS16 and + GUS MAX, but it doesn't work yet. +Since pre-3.0-940426 +- AD1848/CS4248/CS4231 codec support (MSS, GUS MAX, Aztec, Orchid etc). +This codec chip is used in various soundcards. This version is developed +for the 16 bit daughtercard of GUS. It should work with other cards also +if the following requirements are met: + - The I/O, IRQ and DMA settings are jumper selectable or + the card is initialized by booting DOS before booting Linux (etc.). + - You add the IO, IRQ and DMA settings manually to the local.h. + (Just define GUS16_BASE, GUS16_IRQ and GUS16_DMA). Note that + the base address bust be the base address of the codec chip not the + card itself. For the GUS16 these are the same but most MSS compatible + cards have the codec located at card_base+4. +- Some minor changes + +Since 2.5 (******* MAJOR REWRITE ***********) + +This version is based on v2.3. I have tried to maintain two versions +together so that this one should have the same features than v2.5. +Something may still be missing. If you notice such things, please let me +know. + +The Readme.v30 contains more details. + +- /dev/midi## devices. +- /dev/sequencer2 Since 2.5-beta2 - Some fine tuning to the GUS v3.7 mixer code. diff -u --recursive --new-file v1.1.30/linux/drivers/sound/Makefile linux/drivers/sound/Makefile --- v1.1.30/linux/drivers/sound/Makefile Sun May 1 12:12:23 1994 +++ linux/drivers/sound/Makefile Mon Jul 18 09:50:55 1994 @@ -5,7 +5,7 @@ # # -VERSION = 2.5a +VERSION = 2.90 TARGET_OS = linux .c.s: @@ -19,7 +19,8 @@ opl3.o sequencer.o midibuf.o sb_card.o pas2_card.o adlib_card.o \ pas2_pcm.o pas2_mixer.o pas2_midi.o gus_card.o gus_wave.o mpu401.o \ gus_midi.o gus_vol.o patmgr.o sb_mixer.o sb16_dsp.o sb_midi.o \ - sb16_midi.o sound_switch.o ics2101.o + sb16_midi.o sound_switch.o midi_synth.o uart6850.o sound_timer.o \ + sys_timer.o ics2101.o ad1848.o pss.o all: local.h sound.a diff -u --recursive --new-file v1.1.30/linux/drivers/sound/Readme linux/drivers/sound/Readme --- v1.1.30/linux/drivers/sound/Readme Sun May 1 12:12:23 1994 +++ linux/drivers/sound/Readme Mon Jul 18 09:50:55 1994 @@ -1,152 +1,45 @@ -Release notes for the Linux Sound Driver 2.5a ---------------------------------------------- -This directory contains just the Linux version. The portable version -(SCO/ISC, FreeBSD/NetBSD and SVR4.2) is available from sunsite.unc.edu: -pub/Linux/kernel/sound. - -This is mainly a bug fix release. There are couple of new things such as -linear volume mode for GUS and MIDI recording for SB 2.0 and SB Pro. -Also this version supports the mixer of GUS v3.7. (Support for GUS MAX and -the 16-bit daughtercard is coming sooner or later). - -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). +VoxWare v2.90 release notes +-------------------------- + + This version includes some hidden features which + are described in the file experimental.txt + Some of these features are not enabled by default. Look at + experimental.txt for more info. + + I just decided to release this version with some + incompletely implemented features disabled since + there are some new features required by a popular + application. In addition there is also support + for the GUS MAX and the 16 bit sampling option of GUS. + Also the Windows Sound System stuff is there but may not + work yet (may work with some WSS compatible cards). + +********* IMPORTANT ***************************************** +Linux 1.0 or later is required to by this driver version. + +Don't distribute binaries which use /dev/sequencer and are +compiled with the soundcard.h of this version. They will +not work with version 2.x of the driver. +************************************************************* + + You will need the snd-util-2.5.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/*. If you are looking for the installation instructions, please -look at $OS/Readme. +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 -Most of the features of the /dev/sequencer device file are -available just for GUS owners. - Compatibility with the earlier versions --------------------------------------- -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. - -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-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 -returned as the functional return. For example setting the speed of -/dev/dsp were done as the following: - - int actual_speed; - actual_speed = ioctl(fd, SOUND_PCM_WRITE_RATE, 44100); - -After version 1.99.0 this must be done as the following: - - int actual_speed = 44100; - ioctl(fd, SOUND_PCM_WRITE_RATE, &actual_speed); - -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-2.0 package for further info. - -Known bugs/limitations ----------------------- - -- 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. -- 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 - but at this time the GUS is not available for access via /dev/sequencer. - This is a limitation of the driver. -- 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. -- 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 (like mine). - Try to avoid - switching between VTs while patches are being loaded to the GUS. - 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). - +This version is backward compatible with the version 2.X. All programs +compiled with sys/soundcard.h of v2.X should work without problems. +PROGRAMS COMPILED WITH THE sys/soundcard.h OF THIS VERSION WILL NOT +WORK WITH v2.X DRIVER. BE CAREFULL WHEN DISTRIBUTING BINARIES COMPILED +FOR THIS VERSION. Contributors ------------ @@ -155,30 +48,32 @@ 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 Initial ISC port - Jim Lowe Initial FreeBSD port + 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 - Megens SA MIDI recording for SB and SB Pro. + Joerg Schubert SB16 DSP support. + Andrew Robinson Improvements to the GUS driver + Megens SA MIDI recording for SB and SB Pro. + Mikael Nordqvist Linear volume support for GUS. Mikael Nordqvist Linear volume support for GUS. Ian Hartas SVR4.2 port Markus Aroharju and Risto Kankkunen Major contributions to the mixer support of GUS v3.7. - Hunyue Yau Sound Galaxy NX Pro mixer support. + Marc Hoffman PSS support. Regards, Hannu Savolainen -hannu@voxware.pp.fi, Hannu.Savolainen@Helsinki.fi +hannu@voxware.pp.fi Snail mail: Hannu Savolainen Pallaksentie 4 A 2 00970 Helsinki Finland +FAX: +358 0 395 1968 (usually not connected) diff -u --recursive --new-file v1.1.30/linux/drivers/sound/Readme.linux linux/drivers/sound/Readme.linux --- v1.1.30/linux/drivers/sound/Readme.linux Sun May 1 12:12:23 1994 +++ linux/drivers/sound/Readme.linux Mon Jul 18 09:50:55 1994 @@ -1,35 +1,25 @@ -Sound Driver version 2.5 for Linux ----------------------------------- - -NOTE! The sound driver is now a part of the Linux kernel distribution. - 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. - Installation ------------ -- Since this driver is a part of the Linux kernel distribution, no - special steps are required to build the driver itself. +- Since you are reading this, you have already installed the files so + let's skip this step. To be serious, the sound driver belongs + to linux/drivers/sound. -- In case you are installing a separately distributed sound driver, - you have to do some additional steps. - - Remove all files from the linux/drivers/sound. Old files could - sometimes cause trouble. - - cd linux/drivers. - - gunzip -c snd-driv-X.Y.tar.gz|tar xvf - - - cd ./sound - - cp soundcard.h ultrasound.h /usr/include/linux +- To build the device files you need to run the enclosed shell scrip + (see below). -- To build the device files for this driver, you need to run the enclosed - shell script (at the end of this file). +- If you are installing a separately distributed version, copy the + soundcard.h to /usr/include/linux. It may contain some new stuff. -- Create /usr/include/sys/soundcard.h whic contains just a line: -#include +- Copy the sound/ultrasound.h to /usr/include/sys + (Remove the old one from /usr/include/sys /usr/include/linux first). -- Create /usr/include/sys/ultrasound.h whic contains just a line: -#include +- Ensure you have the following symlink: + ln -s /usr/include/linux/soundcard.h /usr/include/sys/soundcard.h +- Configure and compile Linux as normally (remember to include the + sound support during "make config"). + Boot time configuration (using lilo) ------------------------------------ @@ -61,6 +51,8 @@ 5=MPU-401 UART midi 6=SB16 (16 bit DMA number) 7=SB16 Midi (MPU-401 emulation) + (There are some new ones also but they are currently + not documented). These are the configuration templates for various soundcards: @@ -174,43 +166,76 @@ It runs without burning your CPU. Hannu Savolainen -Hannu.Savolainen@Helsinki.fi -(hannu@voxware.pp.fi (april 94 ->)) +hannu@voxware.pp.fi ----------------- cut here ------------------------------ #!/bin/sh # # soudinstall # -# by Craig Metz - cmetz@thor.tjhsst.edu # # Create the devices # -# Mixer (14, 0) +# Mixer devices # if [ -e /dev/mixer ]; then rm -f /dev/mixer fi + mknod -m 666 /dev/mixer c 14 0 - if [ -e /dev/mixer1 ]; then rm -f /dev/mixer1 fi mknod -m 666 /dev/mixer1 c 14 16 -# + + # Sequencer (14, 1) # if [ -e /dev/sequencer ]; then rm -f /dev/sequencer fi mknod -m 666 /dev/sequencer c 14 1 -# -# MIDI (14, 2) [ Not implemented ] + +if [ -e /dev/patmgr0 ]; then + rm -f /dev/patmgr0 +fi +mknod -m 666 /dev/patmgr0 c 14 17 +if [ -e /dev/patmgr1 ]; then + rm -f /dev/patmgr1 +fi +mknod -m 666 /dev/patmgr1 c 14 33 + +### # Sequencer2 (14, 8) +### # +### if [ -e /dev/sequencer2 ]; then +### rm -f /dev/sequencer2 +### fi +### mknod -m 666 /dev/sequencer2 c 14 8 + +# Midi devices # if [ -e /dev/midi ]; then - rm -f /dev/midi + rm -f /dev/midi # Old name. Don't use it fi -mknod -m 666 /dev/midi c 14 2 +### if [ -e /dev/midi00 ]; then +### rm -f /dev/midi00 +### fi +### mknod -m 666 /dev/midi00 c 14 2 +### +### if [ -e /dev/midi01 ]; then +### rm -f /dev/midi01 +### fi +### mknod -m 666 /dev/midi01 c 14 18 +### +### if [ -e /dev/midi02 ]; then +### rm -f /dev/midi02 +### fi +### mknod -m 666 /dev/midi02 c 14 34 +### +### if [ -e /dev/midi03 ]; then +### rm -f /dev/midi03 +### fi +### mknod -m 666 /dev/midi03 c 14 50 # # DSP (14, 3) # @@ -219,14 +244,14 @@ fi mknod -m 666 /dev/dsp c 14 3 # -# SPARC audio (14, 4) [ Not fully implemented ] +# SPARC compatible /dev/audio (14, 4) # if [ -e /dev/audio ]; then rm -f /dev/audio fi mknod -m 666 /dev/audio c 14 4 # -# DSP2 (14, 19) /dev/dsp for the second soundcard. +# DSP1 (14, 19) /dev/dsp for the second soundcard. # Also the SB emulation part of the # PAS16 card. # @@ -235,7 +260,7 @@ fi mknod -m 666 /dev/dsp1 c 14 19 # -# SPARC audio1 (14, 20) [ Not fully implemented ] +# SPARC audio1 (14, 20) # /dev/audio for the second soundcard. # Also the SB emulation part of the # PAS16 card. diff -u --recursive --new-file v1.1.30/linux/drivers/sound/Readme.v30 linux/drivers/sound/Readme.v30 --- v1.1.30/linux/drivers/sound/Readme.v30 Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/Readme.v30 Mon Jul 18 09:50:55 1994 @@ -0,0 +1,154 @@ +VoxWare v3.0 +------------ + +This is a PROTOTYPE of the VoxWare v3.0 to be relased late 94. + +All features of v2.5 should work as earlier. There could be some +omissions but they are unintentional. I started this version thread +after v2.3 so all features implemented before it are there. + +Even this is a prototype, there should not be any fatal bugs. The +prototype just means that I don't have implemented all features +completely. Mainly in the /dev/sequener2 driver. +For example recording from /dev/sequencer2 won't work +with other cards than a full features MPU-401 or clones. As well the +way how the MIDI controllers are handled will change. + +IMPORTANT!!!!!!!!!!!!!!!!! + +Don't distribute any binaries compiled with the soundcard.h of this version. +They will not work together with older drivers. + +New features +============ + +There are now two new device interfaces. The /dev/midi## is a raw +tty like interface to MIDI ports. There is a device file for each MIDI +port on your system. They are named (/dev/midi00 to /dev/midiNN). +The second addition is the /dev/sequencer2 which is higher level interface +than the old /dev/sequencer. It's intended for writing device independent +applications like sequencers. + +/dev/midi## +----------- + +This interface should be usefull for applications like MIDI sysex librarians. +There are (currently) no timing features so making music could be impossible. + +There are as many /dev/midi## devices as there are MIDI ports in the system. +The /dev/midi00 is connected to the first one, /dev/midi01 to the second etc. + +These devices work like tty devices in raw mode. Everything written to them is +sent out to the MIDI port. There is currently an extra delay of at most +1/100th of sec but it will be removed later. + +The reading algorithm is little bit more complicated. There are two different +cases: + +1) There is at least one byte in the input buffer. + +The read returns as many bytes as it can without waiting for more bytes. +For example when a process reads 100 bytes and there are 10 bytes in the +buffer, the read returns just 10 bytes. + +2) The input buffer is empty when the process calls read. + +The read waits for the first byte and then continues as in case 1. By +default it waits infinitely but there is an ioctl for setting a timeout +for this. The ioctl(fd, SNDCTL_MIDI_PRETIME, &time) changes the timeout. +The time is given in 1/10th of seconds (10 means one second). + +Other ioctl calls: + +ioctl(fd, SNDCTL_MIDI_MPUMODE, &mode) is available for full MPU-401 +compatible devices such as MPU-IPC-T, MQ PC Midi Card or MQX-32. +It's not available for the so called MPU UART ports of some soundcards +(PAS16, SB16 etc). By default the MIDI port is in UART mode after open. +If this ioctl is called with mode=1, the interface is put to the intelligent +(coprocessor) mode. NOTE! The MIDI port will be reset when this ioctl is called. +It could have some strange effects if not called immediately after open. This +vall returns EINVAL if the midi port doesn't support the MPU-401 intelligent +mode. + +ioctl(fd, SNDCTL_MIDI_MPUCMD, &cmdstruct) is valid only if the MIDI port +is put to the coprocessor mode using ioctl(SNDCTL_MIDI_MPUMODE). It's used to +send commands to a MPU-401 compatible MIDI cards. Please refer to the +MPU-401 Technical Reference Manual (or Music Quest Technical Reference +Manual) for descriptions of the commands. + +The argument of SNDCTL_MIDI_MPUCOMMAND is of type mpu_command_rec. It +has the following fields: + +typedef struct { + unsigned char cmd; + + char nr_args, nr_returns; + unsigned char data[30]; + } mpu_command_rec; + +where: + cmd Contains the command number. + nr_args Number of arguments of the command. + MUST BE INITIALIZED BEFORE CALL + nr_returns Number of bytes returned by the command. + MUST BE INITIALIZED BEFORE CALL + data Buffer for the command arguments and returned + data. + +Be extremely carefull with the nr_args and nr_returns fields. They +must match the command. An incorrect value will put the card and +the driver out of sync. Refer to the MPU-401/MQX-32M documentation for further +datails. + + + +/dev/sequencer2 (if you find a better name, please let me know). +--------------- + +This device file works much like the /dev/sequencer which has been present +since the beginning. The main differences are the following: + +- /dev/sequencer makes the MIDI ports to look like the synth devices. In fact +the result is somewhere between the MIDI specification and the synth devices of +/dev/sequencer. Both kind of devices are accessed using the SEQ_START_NOTE() +like macros. The voice number parameters of the API macros have been redefined +to denote MIDI channels. This means that the driver allocates voices for +the channels automaticly (this is a responsibility/right of an application +with /dev/sequencer). The result is that a SEQ_START_NOTE() macro has +similar effects for a synth channel than on a MIDI port. This kind of +solution provides better device independence than the /dev/sequencer. The +drawback is that the new interface doesn't permit so low level access to the +device as the /dev/sequencer does. An application developer must choose between +these two interfaces. I think the old /dev/sequencer is better for applications +like module players while the new one is better for making generic sequencer +programs. + +- There are no separate MIDI devices with the /dev/sequencer2. The +ioctl(SNDCTL_SEQ_NRMIDIS) returns always zero. Instead the MIDI ports are +shown as synth devices. ioctl(SNDCTL_SEQ_NRSYNTHS) on /dev/sequencer2 will +return sum of internal synthesizers (GUS, OPL3) and MIDI ports in the systems. + +- The new interface is used much like the ordinary /dev/sequencer. The +event format is new so you have to use the API macros defined in the +sys/soundcard.h. The interface is will propably change before the final 3.0 +release but using the API macros should ensure compatibility in source level. +The new event format is not recognized by version 2.X so don't try to +distribute binaries compiled with soundcard.h of v3.X. + +- The basic API useage is similar to the current one. There are some new +macros but the older ones should work as earlier. The most important +incompatibility is that the /dev/sequencer2 driver allocates voices itself. +The other one is that the application must send SEQ_START_TIMER() as it's +first event. Otherwise the timer is not started and the application waits +infinitely. + + +There are several new features but I don't document them here. There are +some info in the soundcard.h (near the end). I have also included some +sample code in the directory v30. Full documentation will +appear in the Hacker's Guide later. + +Don't hesitate to contact me in case you have questions or comments. + +Hannu Savolainen +hannu@voxware.pp.fi diff -u --recursive --new-file v1.1.30/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c --- v1.1.30/linux/drivers/sound/ad1848.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/ad1848.c Mon Jul 18 09:50:55 1994 @@ -0,0 +1,953 @@ +/* + * sound/ad1848.c + * + * The low level driver for the AD1848/CS4248 codec chip which + * is used for example in the MS Sound System. + * + * The CS4231 which is used in the GUS MAX and some other cards is + * upwards compatible with AD1848 and this driver is able to drive it. + * + * Copyright by Hannu Savolainen 1994 + * + * 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) +#include "sound_config.h" + +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AD1848) + +#define IMODE_NONE 0 +#define IMODE_OUTPUT 1 +#define IMODE_INPUT 2 +#define IMODE_INIT 3 +#define IMODE_MIDI 4 + +typedef struct +{ + int base; + int irq; + int dma_capture, dma_playback; + unsigned char MCE_bit; + + int speed; + unsigned char speed_bits; + int channels; + int audio_format; + unsigned char format_bits; + + int xfer_count; + int irq_mode; + int intr_active; + int opened; + char *chip_name; + int mode; +} + +ad1848_info; + +static int nr_ad1848_devs = 0; +static char irq2dev[16] = +{-1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1}; + +static int ad_format_mask[2 /*devc->mode*/ ] = +{ + AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW, + AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM +}; + +static ad1848_info dev_info[MAX_AUDIO_DEV]; + +#define io_Index_Addr(d) ((d)->base) +#define io_Indexed_Data(d) ((d)->base+1) +#define io_Status(d) ((d)->base+2) +#define io_Polled_IO(d) ((d)->base+3) + +static int ad1848_open (int dev, int mode); +static void ad1848_close (int dev); +static int ad1848_ioctl (int dev, unsigned int cmd, unsigned int arg, int local); +static void ad1848_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart); +static void ad1848_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart); +static int ad1848_prepare_for_IO (int dev, int bsize, int bcount); +static void ad1848_reset (int dev); +static void ad1848_halt (int dev); +void ad1848_interrupt (int dev); + +static int +ad_read (ad1848_info * devc, int reg) +{ + unsigned long flags; + int x; + + DISABLE_INTR (flags); + OUTB ((unsigned char) (reg & 0xff) | devc->MCE_bit, io_Index_Addr (devc)); + x = INB (io_Indexed_Data (devc)); + /* printk("(%02x<-%02x) ", reg|devc->MCE_bit, x); */ + RESTORE_INTR (flags); + + return x; +} + +static void +ad_write (ad1848_info * devc, int reg, int data) +{ + unsigned long flags; + + DISABLE_INTR (flags); + OUTB ((unsigned char) (reg & 0xff) | devc->MCE_bit, io_Index_Addr (devc)); + OUTB ((unsigned char) (data & 0xff), io_Indexed_Data (devc)); + /* printk("(%02x->%02x) ", reg|devc->MCE_bit, data); */ + RESTORE_INTR (flags); +} + +static void +ad_set_MCE (ad1848_info * devc, int state) +{ + unsigned long flags; + + DISABLE_INTR (flags); + if (state) + devc->MCE_bit = 0x40; + else + devc->MCE_bit = 0x00; + OUTB (devc->MCE_bit, io_Index_Addr (devc)); + RESTORE_INTR (flags); +} + +static void +wait_for_calibration (ad1848_info * devc) +{ + int timeout = 0; + + /* + * Wait until the auto calibration process has finished. + * + * 1) Wait until the chip becomes ready (reads don't return 0x80). + * 2) Wait until the ACI bit of I11 gets on and then off. + */ + + timeout = 100000; + while (timeout > 0 && INB (devc->base) == 0x80) + timeout--; + if (INB (devc->base) == 0x80) + printk ("ad1848: Auto calibration timed out(1).\n"); + + timeout = 100000; + while (timeout > 0 && !(ad_read (devc, 11) & 0x20)) + timeout--; + if (!(ad_read (devc, 11) & 0x20)) + printk ("ad1848: Auto calibration timed out(2).\n"); + + timeout = 100000; + while (timeout > 0 && ad_read (devc, 11) & 0x20) + timeout--; + if (ad_read (devc, 11) & 0x20) + printk ("ad1848: Auto calibration timed out(3).\n"); +} + +static struct audio_operations ad1848_pcm_operations[MAX_AUDIO_DEV] = +{ + { + "Generic AD1848 codec", + DMA_AUTOMODE, + AFMT_U8, /* Will be set later */ + NULL, + ad1848_open, + ad1848_close, + ad1848_output_block, + ad1848_start_input, + ad1848_ioctl, + ad1848_prepare_for_IO, + ad1848_prepare_for_IO, + ad1848_reset, + ad1848_halt, + NULL, + NULL + }}; + +static int +ad1848_open (int dev, int mode) +{ + int err; + ad1848_info *devc = NULL; + unsigned long flags; + + DEB (printk ("ad1848_open(int mode = %X)\n", mode)); + + if (dev < 0 || dev >= num_audiodevs) + return RET_ERROR (ENXIO); + + devc = (ad1848_info *) audio_devs[dev]->devc; + + DISABLE_INTR (flags); + if (devc->opened) + { + RESTORE_INTR (flags); + printk ("ad1848: Already opened\n"); + return RET_ERROR (EBUSY); + } + + if (devc->irq) /* Not managed by another driver */ + if ((err = snd_set_irq_handler (devc->irq, ad1848_interrupt)) < 0) + { + printk ("ad1848: IRQ in use\n"); + RESTORE_INTR (flags); + return err; + } + + if (DMAbuf_open_dma (dev) < 0) + { + RESTORE_INTR (flags); + printk ("ad1848: DMA in use\n"); + return RET_ERROR (EBUSY); + } + + devc->intr_active = 0; + devc->opened = 1; + RESTORE_INTR (flags); + + return 0; +} + +static void +ad1848_close (int dev) +{ + unsigned long flags; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + + DEB (printk ("ad1848_close(void)\n")); + + DISABLE_INTR (flags); + + devc->intr_active = 0; + if (devc->irq) /* Not managed by another driver */ + snd_release_irq (devc->irq); + ad1848_reset (dev); + DMAbuf_close_dma (dev); + devc->opened = 0; + + RESTORE_INTR (flags); +} + +static int +set_speed (ad1848_info * devc, int arg) +{ + /* + * The sampling speed is encoded in the least significant nible of I8. The + * LSB selects the clock source (0=24.576 MHz, 1=16.9344 Mhz) and other + * three bits select the divisor (indirectly): + * + * The available speeds are in the following table. Keep the speeds in + * the increasing order. + */ + typedef struct + { + int speed; + unsigned char bits; + } + speed_struct; + + static speed_struct speed_table[] = + { + {5510, (0 << 1) | 1}, + {5510, (0 << 1) | 1}, + {6620, (7 << 1) | 1}, + {8000, (0 << 1) | 0}, + {9600, (7 << 1) | 0}, + {11025, (1 << 1) | 1}, + {16000, (1 << 1) | 0}, + {18900, (2 << 1) | 1}, + {22050, (3 << 1) | 1}, + {27420, (2 << 1) | 0}, + {32000, (3 << 1) | 0}, + {33075, (6 << 1) | 1}, + {37800, (4 << 1) | 1}, + {44100, (5 << 1) | 1}, + {48000, (6 << 1) | 0} + }; + + int i, n, selected = -1; + + n = sizeof (speed_table) / sizeof (speed_struct); + + if (arg < speed_table[0].speed) + selected = 0; + if (arg > speed_table[n - 1].speed) + selected = n - 1; + + for (i = 1 /*really*/ ; selected == -1 && i < n; i++) + if (speed_table[i].speed == arg) + selected = i; + else if (speed_table[i].speed > arg) + { + int diff1, diff2; + + diff1 = arg - speed_table[i - 1].speed; + diff2 = speed_table[i].speed - arg; + + if (diff1 < diff2) + selected = i - 1; + else + selected = i; + } + + if (selected == -1) + { + printk ("ad1848: Can't find speed???\n"); + selected = 3; + } + + devc->speed = speed_table[selected].speed; + devc->speed_bits = speed_table[selected].bits; + return devc->speed; +} + +static int +set_channels (ad1848_info * devc, int arg) +{ + if (arg != 1 && arg != 2) + return devc->channels; + + devc->channels = arg; + return arg; +} + +static int +set_format (ad1848_info * devc, int arg) +{ + + static struct format_tbl + { + int format; + unsigned char bits; + } + format2bits [] = + { + { + 0, 0 + } + , + { + AFMT_MU_LAW, 1 + } + , + { + AFMT_A_LAW, 3 + } + , + { + AFMT_IMA_ADPCM, 5 + } + , + { + AFMT_U8, 0 + } + , + { + AFMT_S16_LE, 2 + } + , + { + AFMT_S16_BE, 6 + } + , + { + AFMT_S8, 0 + } + , + { + AFMT_U16_LE, 0 + } + , + { + AFMT_U16_BE, 0 + } + }; + int i, n = sizeof (format2bits) / sizeof (struct format_tbl); + + if (!(arg & ad_format_mask[devc->mode])) + arg = AFMT_U8; + + devc->audio_format = arg; + + for (i = 0; i < n; i++) + if (format2bits[i].format == arg) + { + if ((devc->format_bits = format2bits[i].bits) == 0) + return devc->audio_format = AFMT_U8; /* Was not supported */ + + return arg; + } + + /* Still hanging here. Something must be terribly wrong */ + devc->format_bits = 0; + return devc->audio_format = AFMT_U8; +} + +static int +ad1848_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) +{ + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + + switch (cmd) + { + case SOUND_PCM_WRITE_RATE: + if (local) + return set_speed (devc, arg); + return IOCTL_OUT (arg, set_speed (devc, IOCTL_IN (arg))); + + case SOUND_PCM_READ_RATE: + if (local) + return devc->speed; + return IOCTL_OUT (arg, devc->speed); + + case SNDCTL_DSP_STEREO: + if (local) + return set_channels (devc, arg + 1) - 1; + return IOCTL_OUT (arg, set_channels (devc, IOCTL_IN (arg) + 1) - 1); + + case SOUND_PCM_WRITE_CHANNELS: + if (local) + return set_channels (devc, arg); + return IOCTL_OUT (arg, set_channels (devc, IOCTL_IN (arg))); + + case SOUND_PCM_READ_CHANNELS: + if (local) + return devc->channels; + return IOCTL_OUT (arg, devc->channels); + + case SNDCTL_DSP_SAMPLESIZE: + if (local) + return set_format (devc, arg); + return IOCTL_OUT (arg, set_format (devc, IOCTL_IN (arg))); + + case SOUND_PCM_READ_BITS: + if (local) + return devc->audio_format; + return IOCTL_OUT (arg, devc->audio_format); + + default:; + } + return RET_ERROR (EINVAL); +} + +static void +ad1848_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart) +{ + unsigned long flags, cnt; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + + cnt = count; + + if (devc->audio_format == AFMT_IMA_ADPCM) + { + cnt /= 4; + } + else + { + if (devc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */ + cnt >>= 1; + } + if (devc->channels > 1) + cnt >>= 1; + cnt--; + + if (audio_devs[dev]->flags & DMA_AUTOMODE && + intrflag && + cnt == devc->xfer_count) + { + devc->irq_mode = IMODE_OUTPUT; + devc->intr_active = 1; + return; /* + * Auto DMA mode on. No need to react + */ + } + DISABLE_INTR (flags); + + if (dma_restart) + { + ad1848_halt (dev); + DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); + } + + ad_set_MCE (devc, 1); + + ad_write (devc, 15, (unsigned char) (cnt & 0xff)); + ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff)); + + + ad_write (devc, 9, 0x0d); /* + * Playback enable, single DMA channel mode, + * auto calibration on. + */ + + ad_set_MCE (devc, 0); /* + * Starts the calibration process and + * enters playback mode after it. + */ + wait_for_calibration (devc); + + devc->xfer_count = cnt; + devc->irq_mode = IMODE_OUTPUT; + devc->intr_active = 1; + RESTORE_INTR (flags); +} + +static void +ad1848_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart) +{ + unsigned long flags, cnt; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + + /* int count_reg = (devc->mode == 1) ? 14 : 30; */ + + cnt = count; + if (devc->audio_format == AFMT_IMA_ADPCM) + { + cnt /= 4; + } + else + { + if (devc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */ + cnt >>= 1; + } + if (devc->channels > 1) + cnt >>= 1; + cnt--; + + if (audio_devs[dev]->flags & DMA_AUTOMODE && + intrflag && + cnt == devc->xfer_count) + { + devc->irq_mode = IMODE_INPUT; + devc->intr_active = 1; + return; /* + * Auto DMA mode on. No need to react + */ + } + DISABLE_INTR (flags); + + if (dma_restart) + { + ad1848_halt (dev); + DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); + } + + ad_set_MCE (devc, 1); +#if 0 + ad_write (devc, count_reg + 1, (unsigned char) (cnt & 0xff)); + ad_write (devc, count_reg, (unsigned char) ((cnt >> 8) & 0xff)); +#else + ad_write (devc, 15, (unsigned char) (cnt & 0xff)); + ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff)); + if (devc->mode == 2) + { + ad_write (devc, 31, (unsigned char) (cnt & 0xff)); + ad_write (devc, 32, (unsigned char) ((cnt >> 8) & 0xff)); + } +#endif + + ad_write (devc, 9, 0x0e); /* + * Capture enable, single DMA channel mode, + * auto calibration on. + */ + + ad_set_MCE (devc, 0); /* + * Starts the calibration process and + * enters playback mode after it. + */ + wait_for_calibration (devc); + + devc->xfer_count = cnt; + devc->irq_mode = IMODE_INPUT; + devc->intr_active = 1; + RESTORE_INTR (flags); +} + +static int +ad1848_prepare_for_IO (int dev, int bsize, int bcount) +{ + int timeout; + unsigned char fs; + unsigned long flags; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + + DISABLE_INTR (flags); + ad_set_MCE (devc, 1); /* Enables changes to the format select reg */ + fs = devc->speed_bits | (devc->format_bits << 5); + + if (devc->channels > 1) + fs |= 0x10; + + ad_write (devc, 8, fs); + /* + * Write to I8 starts resyncronization. Wait until it completes. + */ + timeout = 10000; + while (timeout > 0 && INB (devc->base) == 0x80) + timeout--; + + ad_set_MCE (devc, 0); /* + * Starts the calibration process and + * enters playback mode after it. + */ + wait_for_calibration (devc); + RESTORE_INTR (flags); + + /* + * If mode == 2 (CS4231), set I28 also. It's the capture format register. + */ + if (devc->mode == 2) + { + ad_set_MCE (devc, 1); + ad_write (devc, 28, fs); + + /* + * Write to I28 starts resyncronization. Wait until it completes. + */ + timeout = 10000; + while (timeout > 0 && INB (devc->base) == 0x80) + timeout--; + + ad_set_MCE (devc, 0); /* + * Starts the calibration process and + * enters playback mode after it. + */ + wait_for_calibration (devc); + RESTORE_INTR (flags); + } + devc->xfer_count = 0; + return 0; +} + +static void +ad1848_reset (int dev) +{ + ad1848_halt (dev); +} + +static void +ad1848_halt (int dev) +{ + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + + ad_write (devc, 9, 0); /* Clear the PEN and CEN bits (among others) */ + OUTB (0, io_Status (devc)); /* Clear interrupt status */ +} + +int +ad1848_detect (int io_base) +{ + +#define DDB(x) x + + unsigned char tmp; + int i; + ad1848_info *devc = &dev_info[nr_ad1848_devs]; + unsigned char tmp1 = 0xff, tmp2 = 0xff; + + if (nr_ad1848_devs >= MAX_AUDIO_DEV) + return 0; + + devc->base = io_base; + devc->MCE_bit = 0x40; + devc->irq = 0; + devc->dma_capture = 0; + devc->dma_playback = 0; + devc->opened = 0; + devc->chip_name = "AD1848"; + devc->mode = 1; /* MODE1 = original AD1848 */ + + /* + * Check that the I/O address is in use. + * + * The bit 0x80 of the base I/O port is known to be 0 after the + * chip has performed it's power on initialization. Just assume + * this has happened before the OS is starting. + * + * If the I/O address is unused, it typically returns 0xff. + */ + + if ((INB (devc->base) & 0x80) != 0x00) /* Not a AD1884 */ + { + DDB (printk ("ad_detect_A\n")); + return 0; + } + + /* + * Test if it's possible to change contents of the indirect registers. + * Registers 0 and 1 are ADC volume registers. The bit 0x10 is read only + * so try to avoid using it. +*/ + + ad_write (devc, 0, 0xaa); + ad_write (devc, 1, 0x45); /* 0x55 with bit 0x10 clear */ + + if ((tmp1 = ad_read (devc, 0)) != 0xaa || (tmp2 = ad_read (devc, 1)) != 0x45) + { + DDB (printk ("ad_detect_B (%x/%x)\n", tmp1, tmp2)); + return 0; + } + + ad_write (devc, 0, 0x45); + ad_write (devc, 1, 0xaa); + + if ((tmp1 = ad_read (devc, 0)) != 0x45 || (tmp2 = ad_read (devc, 1)) != 0xaa) + { + DDB (printk ("ad_detect_C (%x/%x)\n", tmp1, tmp2)); + return 0; + } + + /* + * The indirect register I12 has some read only bits. Lets + * try to change them. + */ + + tmp = ad_read (devc, 12); + ad_write (devc, 12, (~tmp) & 0x0f); + + if ((tmp & 0x0f) != ((tmp1 = ad_read (devc, 12)) & 0x0f)) + { + DDB (printk ("ad_detect_D (%x)\n", tmp1)); + return 0; + } + + /* + * NOTE! Last 4 bits of the reg I12 tell the chip revision. + * 0x01=RevB and 0x0A=RevC. + */ + + /* + * The original AD1848/CS4248 has just 15 indirect registers. This means + * that I0 and I16 should return the same value (etc.). + * Ensure that the Mode2 enable bit of I12 is 0. Otherwise this test fails + * with CS4231. + */ + + ad_write (devc, 12, 0); /* Mode2=disabled */ + + for (i = 0; i < 16; i++) + if ((tmp1 = ad_read (devc, i)) != (tmp2 = ad_read (devc, i + 16))) + { + DDB (printk ("ad_detect_F(%d/%x/%x)\n", i, tmp1, tmp2)); + return 0; + } + + /* + * Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit (0x40). + * The bit 0x80 is always 1 in CS4248 and CS4231. + */ + + ad_write (devc, 12, 0x40); /* Set mode2, clear 0x80 */ + + tmp1 = ad_read (devc, 12); + if (tmp1 & 0x80) + devc->chip_name = "CS4248"; + + if ((tmp1 & 0xc0) == (0x80 | 0x40)) + { + /* + * CS4231 detected - is it? + * + * Verify that setting I0 doesn't change I16. + */ + ad_write (devc, 16, 0); /* Set I16 to known value */ + + ad_write (devc, 0, 0x45); + if ((tmp1 = ad_read (devc, 16)) != 0x45) /* No change -> CS4231? */ + { + + ad_write (devc, 0, 0xaa); + if ((tmp1 = ad_read (devc, 16)) == 0xaa) /* Rotten bits? */ + { + DDB (printk ("ad_detect_H(%x)\n", tmp1)); + return 0; + } + + /* + * It's a CS4231 - So what! + * (Mode2 will be supported later) + */ + devc->chip_name = "CS4231"; + devc->mode = 2; + } + } + + return 1; +} + +void +ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture) +{ + /* + * NOTE! If irq < 0, there is another driver which has allocated the IRQ + * so that this driver doesn't need to allocate/deallocate it. + * The actually used IRQ is ABS(irq). + */ + + /* + * Initial values for the indirect registers of CS4248/AD1848. + */ + static int init_values[] = + { + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, + 0x00, 0x08, 0x02, 0x00, 0xca, 0x00, 0x00, 0x00 + }; + int i, my_dev; + ad1848_info *devc = &dev_info[nr_ad1848_devs]; + + if (!ad1848_detect (io_base)) + return; + + devc->irq = (irq > 0) ? irq : 0; + devc->dma_capture = dma_playback; + devc->dma_playback = dma_capture; + devc->opened = 0; + + if (nr_ad1848_devs != 0) + { + memcpy ((char *) &ad1848_pcm_operations[nr_ad1848_devs], + (char *) &ad1848_pcm_operations[0], + sizeof (struct audio_operations)); + } + + for (i = 0; i < 16; i++) + ad_write (devc, i, init_values[i]); + + OUTB (0, io_Status (devc)); /* Clear pending interrupts */ + +#ifndef SCO + sprintf (ad1848_pcm_operations[nr_ad1848_devs].name, + "%s (%s)", name, devc->chip_name); +#endif + + if (irq > 0) + printk (" <%s>", ad1848_pcm_operations[nr_ad1848_devs].name); + + if (num_audiodevs < MAX_AUDIO_DEV) + { + audio_devs[my_dev = num_audiodevs++] = &ad1848_pcm_operations[nr_ad1848_devs]; + if (irq > 0) + irq2dev[irq] = my_dev; + else if (irq < 0) + irq2dev[-irq] = my_dev; + + audio_devs[my_dev]->dmachan = dma_playback; + audio_devs[my_dev]->buffcount = 1; + audio_devs[my_dev]->buffsize = DSP_BUFFSIZE * 2; + audio_devs[my_dev]->devc = devc; + audio_devs[my_dev]->format_mask = ad_format_mask[devc->mode]; + nr_ad1848_devs++; + } + else + printk ("AD1848: Too many PCM devices available\n"); +} + +void +ad1848_interrupt (int irq) +{ + unsigned char status; + ad1848_info *devc; + int dev; + + if (irq < 0 || irq > 15) + return; /* Bogus irq */ + dev = irq2dev[irq]; + if (dev < 0 || dev >= num_audiodevs) + return; /* Bogus dev */ + + devc = (ad1848_info *) audio_devs[dev]->devc; + status = INB (io_Status (devc)); + + if (status & 0x01) + { + if (devc->opened && devc->irq_mode == IMODE_OUTPUT) + { + DMAbuf_outputintr (dev, 1); + } + + if (devc->opened && devc->irq_mode == IMODE_INPUT) + DMAbuf_inputintr (dev); + } + + OUTB (0, io_Status (devc)); /* Clear interrupt status */ +} + +#endif +/* + * Some extra code for the MS Sound System + */ +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MSS) + +int +probe_ms_sound (struct address_info *hw_config) +{ + int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3; + + if ((INB (hw_config->io_base + 3) & 0x04) == 0) + return 0; /* WSS ID test failed */ + + if (hw_config->irq > 11) + return; + + if (hw_config->dma > 3 || hw_config->dma == 2) + return; + + return ad1848_detect (hw_config->io_base + 4); +} + +long +attach_ms_sound (long mem_start, struct address_info *hw_config) +{ + static unsigned char interrupt_bits[11] = + {-1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20}; + char bits; + + int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3; + + if (!ad1848_detect (hw_config->io_base + 4)) + return mem_start; + + /* + * Set the IRQ and DMA addresses. + */ + + bits = interrupt_bits[hw_config->irq]; + if (bits == -1) + return mem_start; + + OUTB (bits | 0x40, config_port); /* Verify IRQ (I guess) */ + if ((INB (version_port) & 0x40) == 0) + printk ("[IRQ?]"); + + OUTB (bits | hw_config->dma, config_port); /* Write IRQ+DMA setup */ + + ad1848_init ("MS Sound System", hw_config->io_base + 4, + hw_config->irq, + hw_config->dma, + hw_config->dma); + return mem_start; +} + +#endif diff -u --recursive --new-file v1.1.30/linux/drivers/sound/audio.c linux/drivers/sound/audio.c --- v1.1.30/linux/drivers/sound/audio.c Sun May 1 12:12:24 1994 +++ linux/drivers/sound/audio.c Mon Jul 18 09:50:55 1994 @@ -37,19 +37,49 @@ #define ON 1 #define OFF 0 -static int wr_buff_no[MAX_DSP_DEV]; /* != -1, if there is a +static int wr_buff_no[MAX_AUDIO_DEV]; /* + * != -1, if there is + * a incomplete output + * block in the queue. + */ +static int wr_buff_size[MAX_AUDIO_DEV], wr_buff_ptr[MAX_AUDIO_DEV]; - * incomplete output block */ -static int wr_buff_size[MAX_DSP_DEV], wr_buff_ptr[MAX_DSP_DEV]; +static int audio_mode[MAX_AUDIO_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]; +static char *wr_dma_buf[MAX_AUDIO_DEV]; +static int audio_format[MAX_AUDIO_DEV]; +static int local_conversion[MAX_AUDIO_DEV]; + +static int +set_format (int dev, int fmt) +{ + if (fmt != AFMT_QUERY) + { + + local_conversion[dev] = 0; + + if (!(audio_devs[dev]->format_mask & fmt)) /* Not supported */ + if (fmt == AFMT_MU_LAW) + { + fmt = AFMT_U8; + local_conversion[dev] = AFMT_MU_LAW; + } + else + fmt = AFMT_U8; /* This is always supported */ + audio_format[dev] = DMAbuf_ioctl (dev, SNDCTL_DSP_SETFMT, fmt, 1); + } + + if (local_conversion[dev]) /* This shadows the HW format */ + return local_conversion[dev]; + + return audio_format[dev]; +} + int audio_open (int dev, struct fileinfo *file) { @@ -68,12 +98,21 @@ if ((ret = DMAbuf_open (dev, mode)) < 0) return ret; - if (DMAbuf_ioctl (dev, SNDCTL_DSP_SAMPLESIZE, bits, 1) != bits) + local_conversion[dev] = 0; + + if (DMAbuf_ioctl (dev, SNDCTL_DSP_SETFMT, bits, 1) != bits) { audio_release (dev, file); return RET_ERROR (ENXIO); } + if (dev_type == SND_DEV_AUDIO) + { + set_format (dev, AFMT_MU_LAW); + } + else + set_format (dev, bits); + wr_buff_no[dev] = -1; audio_mode[dev] = AM_NONE; @@ -128,21 +167,24 @@ { 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 */ + if (audio_mode[dev] == AM_READ) /* + * Direction changed + */ { wr_buff_no[dev] = -1; } audio_mode[dev] = AM_WRITE; - if (!count) /* Flush output */ + if (!count) /* + * Flush output + */ { if (wr_buff_no[dev] >= 0) { @@ -154,11 +196,17 @@ } while (c) - { /* Perform output blocking */ - if (wr_buff_no[dev] < 0) /* There is no incomplete buffers */ + { /* + * Perform output blocking + */ + if (wr_buff_no[dev] < 0) /* + * There is no incomplete buffers + */ { if ((wr_buff_no[dev] = DMAbuf_getwrbuffer (dev, &wr_dma_buf[dev], &wr_buff_size[dev])) < 0) - return wr_buff_no[dev]; + { + return wr_buff_no[dev]; + } wr_buff_ptr[dev] = 0; } @@ -166,21 +214,27 @@ if (l > (wr_buff_size[dev] - wr_buff_ptr[dev])) l = (wr_buff_size[dev] - wr_buff_ptr[dev]); - if (!dsp_devs[dev]->copy_from_user) - { /* No device specific copy routine */ + if (!audio_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, + audio_devs[dev]->copy_from_user (dev, wr_dma_buf[dev], wr_buff_ptr[dev], buf, p, l); - /* Insert local processing here */ + /* + * Insert local processing here + */ - if (dev_type == SND_DEV_AUDIO) + if (local_conversion[dev] == AFMT_MU_LAW) { #ifdef linux - /* This just allows interrupts while the conversion is running */ + /* + * This just allows interrupts while the conversion is running + */ __asm__ ("sti"); #endif translate_bytes (ulaw_dsp, (unsigned char *) &wr_dma_buf[dev][wr_buff_ptr[dev]], l); @@ -193,7 +247,9 @@ if (wr_buff_ptr[dev] >= wr_buff_size[dev]) { if ((err = DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev])) < 0) - return err; + { + return err; + } wr_buff_no[dev] = -1; } @@ -209,7 +265,6 @@ int c, p, l; char *dmabuf; int buff_no; - int dev_type = dev & 0x0f; dev = dev >> 4; p = 0; @@ -235,12 +290,16 @@ if (l > c) l = c; - /* Insert any local processing here. */ + /* + * Insert any local processing here. + */ - if (dev_type == SND_DEV_AUDIO) + if (local_conversion[dev] == AFMT_MU_LAW) { #ifdef linux - /* This just allows interrupts while the conversion is running */ + /* + * This just allows interrupts while the conversion is running + */ __asm__ ("sti"); #endif @@ -262,7 +321,6 @@ audio_ioctl (int dev, struct fileinfo *file, unsigned int cmd, unsigned int arg) { - int dev_type = dev & 0x0f; dev = dev >> 4; @@ -293,22 +351,32 @@ return DMAbuf_ioctl (dev, cmd, arg, 0); break; - default: - if (dev_type == SND_DEV_AUDIO) - return RET_ERROR (EIO); + case SNDCTL_DSP_GETFMTS: + return IOCTL_OUT (arg, audio_devs[dev]->format_mask); + break; + case SNDCTL_DSP_SETFMT: + return IOCTL_OUT (arg, set_format (dev, IOCTL_IN (arg))); + + default: return DMAbuf_ioctl (dev, cmd, arg, 0); + break; } } long audio_init (long mem_start) { + /* + * NOTE! This routine could be called several times during boot. + */ return mem_start; } #else -/* Stub versions */ +/* + * Stub versions + */ int audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) diff -u --recursive --new-file v1.1.30/linux/drivers/sound/configure.c linux/drivers/sound/configure.c --- v1.1.30/linux/drivers/sound/configure.c Sun May 1 12:12:25 1994 +++ linux/drivers/sound/configure.c Mon Jul 18 09:50:55 1994 @@ -40,23 +40,31 @@ #define OPT_GUS 3 #define OPT_MPU401 4 +#define OPT_UART6850 5 +#define OPT_PSS 6 +#define OPT_GUS16 7 +#define OPT_GUSMAX 8 +#define OPT_MSS 9 + +#define OPT_HIGHLEVEL 10 /* This must be same than the next one */ +#define OPT_SBPRO 10 +#define OPT_SB16 11 +#define OPT_AUDIO 12 +#define OPT_MIDI_AUTO 13 +#define OPT_MIDI 14 +#define OPT_YM3812_AUTO 15 +#define OPT_YM3812 16 +#define OPT_SEQUENCER 17 +#define OPT_LAST 17 /* Must be the same than the defined OPT */ -#define OPT_HIGHLEVEL 5 -#define OPT_SBPRO 5 -#define OPT_SB16 6 -#define OPT_AUDIO 7 -#define OPT_MIDI_AUTO 8 -#define OPT_MIDI 9 -#define OPT_YM3812_AUTO 10 /* Select this automaticly if user selects - * MIDI or AdLib driver */ -#define OPT_YM3812 11 /* Select this if the previous one was not - * selected */ -#define OPT_SEQUENCER 12 -#define OPT_CHIP_MIDI 13 /* New support added at UW - Milwauklee UW - - * Milwauklee */ -#define OPT_LAST 12 - -#define ANY_DEVS (B(OPT_AUDIO)|B(OPT_MIDI)|B(OPT_SEQUENCER)|B(OPT_GUS)|B(OPT_MPU401)) +#define ANY_DEVS (B(OPT_AUDIO)|B(OPT_MIDI)|B(OPT_SEQUENCER)|B(OPT_GUS)| \ + B(OPT_MPU401)|B(OPT_PSS)|B(OPT_GUS16)|B(OPT_GUSMAX)|B(OPT_MSS)) +/* + * Options that have been disabled for some reason (incompletely implemented + * and/or tested). Don't remove from this list before looking at file + * experimental.txt for further info. + */ +#define DISABLED_OPTIONS (B(OPT_PSS)) typedef struct { @@ -87,24 +95,29 @@ hw_entry hw_table[] = { -/* 0 */ +/* + * 0 + */ {0, 0, "PAS", 1, 0, 0}, {0, 0, "SB", 1, 0, 0}, {0, B (OPT_PAS) | B (OPT_SB), "ADLIB", 1, 0, 0}, -/* 3 */ {0, 0, "GUS", 1, 0, 0}, {0, 0, "MPU401", 1, 0, 0}, + {0, 0, "UART6850", 1, 0, 0}, + {0, 0, "PSS", 1, 0, 0}, + {B (OPT_GUS), 0, "GUS16", 1, 0, 0}, + {B (OPT_GUS), B (OPT_GUS16), "GUSMAX", 1, 0, 0}, + {0, 0, "MSS", 1, 0, 0}, + {B (OPT_SB), B (OPT_PAS), "SBPRO", 1, 0, 1}, {B (OPT_SB) | B (OPT_SBPRO), B (OPT_PAS), "SB16", 1, 0, 1}, - {B (OPT_SB) | B (OPT_PAS) | B (OPT_GUS), 0, "AUDIO", 1, 0, 1}, +{B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_GUS), 0, "AUDIO", 1, 0, 1}, {B (OPT_MPU401), 0, "MIDI_AUTO", 0, OPT_MIDI, 0}, - {B (OPT_SB) | B (OPT_PAS) | B (OPT_MPU401) | B (OPT_GUS), 0, "MIDI", 1, 0, 1}, + {B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_MPU401) | B (OPT_GUS), 0, "MIDI", 1, 0, 1}, {B (OPT_ADLIB), 0, "YM3812_AUTO", 0, OPT_YM3812, 0}, - {B (OPT_SB) | B (OPT_PAS) | B (OPT_ADLIB), B (OPT_YM3812_AUTO), "YM3812", 1, 0, 1}, -/* 10 */ - {B (OPT_MIDI) | B (OPT_YM3812) | B (OPT_YM3812_AUTO) | B (OPT_GUS), 0, "SEQUENCER", 0, 0, 1}, - {0, 0, "CHIP_MIDI", 1, 0, 0} + {B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_ADLIB), B (OPT_YM3812_AUTO), "YM3812", 1, 0, 1}, + {B (OPT_MIDI) | B (OPT_YM3812) | B (OPT_YM3812_AUTO) | B (OPT_GUS), 0, "SEQUENCER", 0, 0, 1} }; char *questions[] = @@ -114,6 +127,11 @@ "AdLib support", "Gravis Ultrasound support", "MPU-401 support (NOT for SB16)", + "6850 UART Midi support", + "PSS (ECHO-ADI2111) support", + "16 bit sampling option of GUS (_NOT_ GUS MAX)", + "GUS MAX support", + "Microsoft Sound System support", "SoundBlaster Pro support", "SoundBlaster 16 support", @@ -123,7 +141,7 @@ "This should not be asked", "FM synthesizer (YM3812/OPL-3) support", "/dev/sequencer support", - "MIDI on CHIP support" + "Should I die" }; unsigned long selected_options = 0; @@ -136,12 +154,12 @@ { case 0: fprintf (stderr, "The SoundBlaster, AdLib and ProAudioSpectrum\n" - "cards cannot be installed at the same time\n"); - fprintf (stderr, "\nSelect at most one of them:\n"); + "CARDS cannot be installed at the same time.\n\n" + "However the PAS16 has a SB emulator so you could select" + "the SoundBlaster DRIVER with it.\n"); fprintf (stderr, " - ProAudioSpectrum 16\n"); fprintf (stderr, " - SoundBlaster / SB Pro\n"); - fprintf (stderr, " (Could be selected with PAS16 also\n" - " since there is a SB emulation on it)\n"); + fprintf (stderr, " (Could be selected with a PAS16 also)\n"); fprintf (stderr, " - AdLib\n"); fprintf (stderr, "\nDon't enable SoundBlaster if you have GUS at 0x220!\n\n"); break; @@ -166,6 +184,9 @@ if (hw_table[nr].exclusive_options & selected_options) return 0; + if (DISABLED_OPTIONS & B (nr)) + return 0; + return 1; } @@ -185,7 +206,9 @@ exit (-1); } - if (len < 2) /* There is an additional LF at the end */ + if (len < 2) /* + * There is an additional LF at the end + */ return def_answ; answ[len - 1] = 0; @@ -214,7 +237,9 @@ exit (-1); } - if (len < 2) /* There is an additional LF at the end */ + if (len < 2) /* + * There is an additional LF at the end + */ return default_answer; answ[len - 1] = 0; @@ -242,8 +267,15 @@ if (think_positively (0)) { - selected_options = 0xffffffff & ~B (OPT_MPU401); - fprintf (stderr, "Note! MPU-401 driver was not enabled\n"); + /* + * Select all but some most dangerous cards. These cards are difficult to + * detect reliably or conflict with some other cards (SCSI, Mitsumi) + */ + selected_options = 0xffffffff & + ~(B (OPT_MPU401) | B (OPT_UART6850) | B (OPT_PSS)) & + ~DISABLED_OPTIONS; + + fprintf (stderr, "Note! MPU-401, PSS and 6850 UART drivers not enabled\n"); full_driver = 1; } else @@ -255,14 +287,18 @@ printf ("#undef KERNEL_SOUNDCARD\n"); exit (0); } - /* Partial driver */ + /* + * Partial driver + */ full_driver = 0; for (i = 0; i <= OPT_LAST; i++) if (can_select_option (i)) { - if (!(selected_options & B (i))) /* Not selected yet */ + if (!(selected_options & B (i))) /* + * Not selected yet + */ if (!hw_table[i].verify) { if (hw_table[i].alias) @@ -289,6 +325,73 @@ if (selected_options & B (OPT_SB16)) selected_options |= B (OPT_SBPRO); + if (selected_options & B (OPT_PSS)) + { + genld_again: + fprintf + (stderr, + "if you wish to emulate the soundblaster and you have a DSPxxx.LD.\n" + "then you must include the LD in the kernel.\n" + "(do you wish to include a LD) ? "); + if (think_positively (1)) + { + char path[512]; + + fprintf (stderr, + "Enter the path to your LD file (pwd is sound): "); + scanf ("%s", path); + fprintf (stderr, "including LD file %s\n", path); + selected_options |= B (OPT_SB) | B (OPT_MPU401) | B (OPT_ADLIB); + + /* Gen LD header */ + { + int fd; + int count; + char c; + int i = 0; + + if ((fd = open (path, 0)) > 0) + { + FILE *sf = fopen ("synth-ld.h", "w"); + + fprintf (sf, "/* automaticaly generated by configure */\n"); + fprintf (sf, "unsigned char pss_synth[] = {\n"); + while (1) + { + count = read (fd, &c, 1); + if (count == 0) + break; + if (i != 0 && (i % 10) == 0) + fprintf (sf, "\n"); + fprintf (sf, "0x%02x,", c & 0xFFL); + i++; + } + fprintf (sf, "};\n" + "#define pss_synthLen %d\n", i); + fclose (sf); + close (fd); + } + else + { + fprintf (stderr, "couldn't open %s as the ld file\n", + path); + fprintf (stderr, "try again with correct path? "); + if (think_positively (1)) + goto genld_again; + } + } + } + else + { + FILE *sf = fopen ("synth-ld.h", "w"); + + fprintf (sf, "/* automaticaly generated by configure */\n"); + fprintf (sf, "unsigned char pss_synth[1];\n" + "#define pss_synthLen 0\n"); + fclose (sf); + } + } + if (!(selected_options & ANY_DEVS)) { printf ("#undef CONFIGURE_SOUNDCARD\n"); @@ -307,21 +410,26 @@ printf ("#define EXCLUDE_%s\n", hw_table[i].macro); - printf ("#define EXCLUDE_PRO_MIDI\n"); - printf ("#define EXCLUDE_CHIP_MIDI\n"); - /* * IRQ and DMA settings */ printf ("\n"); #if defined(linux) - if (selected_options & B (OPT_SB) && selected_options & (B (OPT_AUDIO) | B (OPT_MIDI))) + if ((selected_options & B (OPT_SB)) && selected_options & (B (OPT_AUDIO) | B (OPT_MIDI))) { + fprintf (stderr, "\nI/O base for SB?\n" + "The factory default is 220\n" + "Enter the SB I/O base: "); + + num = ask_value ("%x", 0x220); + fprintf (stderr, "SB I/O base set to %03x\n", num); + printf ("#define SBC_BASE 0x%03x\n", num); + fprintf (stderr, "\nIRQ number for SoundBlaster?\n" "The IRQ address is defined by the jumpers on your card.\n" "The factory default is either 5 or 7 (depending on the model).\n" - "Valid values are 9, 5, 7 and 10.\n" + "Valid values are 9(=2), 5, 7 and 10.\n" "Enter the value: "); num = ask_value ("%d", 7); @@ -332,12 +440,11 @@ num = 7; } fprintf (stderr, "SoundBlaster IRQ set to %d\n", num); - printf ("#define SBC_BASE 0x220\n"); + printf ("#define SBC_IRQ %d\n", num); - if (selected_options & (B (OPT_SBPRO) | B (OPT_PAS))) + if (selected_options & (B (OPT_SBPRO) | B (OPT_PAS) | B (OPT_PSS))) { - fprintf (stderr, "\nDMA channel for SoundBlaster?\n" "For SB 1.0, 1.5 and 2.0 this MUST be 1\n" "SB Pro supports DMA channels 0, 1 and 3 (jumper)\n" @@ -397,7 +504,9 @@ "Enter the value: "); num = ask_value ("%d", 10); - if (num == 6 || num < 3 || num > 15 || num == 2) /* Illegal */ + if (num == 6 || num < 3 || num > 15 || num == 2) /* + * Illegal + */ { fprintf (stderr, "*** Illegal input! ***\n"); @@ -461,7 +570,9 @@ "Enter the value: "); num = ask_value ("%d", 15); - if (num == 6 || num < 3 || num > 15 || num == 2) /* Invalid */ + if (num == 6 || num < 3 || num > 15 || num == 2) /* + * Invalid + */ { fprintf (stderr, "*** Illegal input! ***\n"); @@ -498,11 +609,13 @@ fprintf (stderr, "\nIRQ number for MPU-401?\n" "Valid numbers are: 3, 4, 5, 7 and 9(=2).\n" - "The default value is 5.\n" + "The default value is 9.\n" "Enter the value: "); - num = ask_value ("%d", 5); - if (num == 6 || num < 3 || num > 15) /* Used for floppy */ + num = ask_value ("%d", 9); + if (num == 6 || num < 3 || num > 15) /* + * Used for floppy + */ { fprintf (stderr, "*** Illegal input! ***\n"); @@ -511,6 +624,161 @@ fprintf (stderr, "MPU-401 IRQ set to %d\n", num); printf ("#define MPU_IRQ %d\n", num); } + + if (selected_options & B (OPT_UART6850)) + { + fprintf (stderr, "\nI/O base for 6850 UART Midi?\n" + "Be carefull. No defaults.\n" + "Enter the 6850 UART I/O base: "); + + num = ask_value ("%x", 0); + if (num == 0) + { + /* + * Invalid value entered + */ + printf ("#define EXCLUDE_UART6850\n"); + } + else + { + fprintf (stderr, "6850 UART I/O base set to %03x\n", num); + printf ("#define U6850_BASE 0x%03x\n", num); + + fprintf (stderr, "\nIRQ number for 6850 UART?\n" + "Valid numbers are: 3, 4, 5, 7 and 9(=2).\n" + "The default value is 5.\n" + "Enter the value: "); + + num = ask_value ("%d", 5); + if (num == 6 || num < 3 || num > 15) /* + * Used for floppy + */ + { + + fprintf (stderr, "*** Illegal input! ***\n"); + num = 5; + } + fprintf (stderr, "6850 UART IRQ set to %d\n", num); + printf ("#define U6850_IRQ %d\n", num); + } + } + + if (selected_options & B (OPT_PSS)) + { + fprintf (stderr, "\nI/O base for PSS?\n" + "The factory default is 220\n" + "Enter the PSS I/O base: "); + + num = ask_value ("%x", 0x220); + fprintf (stderr, "PSS I/O base set to %03x\n", num); + printf ("#define PSS_BASE 0x%03x\n", num); + + fprintf (stderr, "\nIRQ number for PSS?\n" + "Valid numbers are: 3, 4, 5, 7, 9(=2) or 10.\n" + "The default value is 10.\n" + "Enter the value: "); + + num = ask_value ("%d", 10); + if (num == 6 || num < 3 || num > 15) /* Used for floppy */ + { + fprintf (stderr, "*** Illegal input! ***\n"); + num = 7; + } + fprintf (stderr, "PSS IRQ set to %d\n", num); + printf ("#define PSS_IRQ %d\n", num); + + fprintf (stderr, "\nDMA number for ECHO-PSS?\n" + "The default value is 3\n" + "Enter the value: "); + + num = ask_value ("%d", 3); + if (num == 4 || num < 0 || num > 7) + { + fprintf (stderr, "*** Illegal input! ***\n"); + num = 3; + } + fprintf (stderr, "\nECHO-PSS DMA set to %d\n", num); + printf ("#define PSS_DMA %d\n", num); + } + + if (selected_options & B (OPT_MSS)) + { + fprintf (stderr, "\nI/O base for MSS (MS Sound System)?\n" + "The factory default is 530\n" + "Other possible values are 604, E80 or F40\n" + "Enter the MSS I/O base: "); + + num = ask_value ("%x", 0x530); + fprintf (stderr, "MSS I/O base set to %03x\n", num); + printf ("#define MSS_BASE 0x%03x\n", num); + + fprintf (stderr, "\nIRQ number for MSS?\n" + "Valid numbers are: 7, 9(=2), 10 and 11.\n" + "The default value is 10.\n" + "Enter the value: "); + + num = ask_value ("%d", 10); + if (num == 6 || num < 3 || num > 15) /* Used for floppy */ + { + fprintf (stderr, "*** Illegal input! ***\n"); + num = 7; + } + fprintf (stderr, "MSS IRQ set to %d\n", num); + printf ("#define MSS_IRQ %d\n", num); + + fprintf (stderr, "\nDMA number for MSS?\n" + "Valid values are 1 and 3 (sometimes 0)" + "The default value is 3\n" + "Enter the value: "); + + num = ask_value ("%d", 3); + if (num == 4 || num < 0 || num > 7) + { + fprintf (stderr, "*** Illegal input! ***\n"); + num = 3; + } + fprintf (stderr, "\nMSS DMA set to %d\n", num); + printf ("#define MSS_DMA %d\n", num); + } + + if (selected_options & B (OPT_GUS16)) + { + fprintf (stderr, "\nI/O base for GUS16 (GUS 16 bit sampling option)?\n" + "The factory default is 530\n" + "Other possible values are 604, E80 or F40\n" + "Enter the GUS16 I/O base: "); + + num = ask_value ("%x", 0x530); + fprintf (stderr, "GUS16 I/O base set to %03x\n", num); + printf ("#define GUS16_BASE 0x%03x\n", num); + + fprintf (stderr, "\nIRQ number for GUS16?\n" + "Valid numbers are: 3, 4, 5, 7, or 9(=2).\n" + "The default value is 7.\n" + "Enter the value: "); + + num = ask_value ("%d", 7); + if (num == 6 || num < 3 || num > 15) /* Used for floppy */ + { + fprintf (stderr, "*** Illegal input! ***\n"); + num = 7; + } + fprintf (stderr, "GUS16 IRQ set to %d\n", num); + printf ("#define GUS16_IRQ %d\n", num); + + fprintf (stderr, "\nDMA number for GUS16?\n" + "The default value is 3\n" + "Enter the value: "); + + num = ask_value ("%d", 3); + if (num < 0 || num > 3) + { + fprintf (stderr, "*** Illegal input! ***\n"); + num = 3; + } + fprintf (stderr, "\nGUS16 DMA set to %d\n", num); + printf ("#define GUS16_DMA %d\n", num); + } #endif if (selected_options & B (OPT_AUDIO)) @@ -521,9 +789,12 @@ def_size = 32768; #ifndef __386BSD__ - if (((selected_options & B (OPT_PAS)) || (selected_options & B (OPT_SB16))) && + if ((selected_options & (B (OPT_PAS) | B (OPT_PAS) | B (OPT_GUS16) | B (OPT_GUSMAX) | + B (OPT_MSS) | B (OPT_PSS))) && !full_driver) - def_size = 65536; /* PAS16 or SB16 */ + def_size = 65536; /* + * PAS16 or SB16 + */ #endif fprintf (stderr, "\nSelect the DMA buffer size (4096, 16384, 32768 or 65536 bytes)\n" diff -u --recursive --new-file v1.1.30/linux/drivers/sound/dev_table.c linux/drivers/sound/dev_table.c --- v1.1.30/linux/drivers/sound/dev_table.c Sun May 1 12:12:25 1994 +++ linux/drivers/sound/dev_table.c Mon Jul 18 09:50:55 1994 @@ -32,101 +32,138 @@ #ifdef CONFIGURE_SOUNDCARD +int +snd_find_driver (int type) +{ + int i, n = sizeof (sound_drivers) / sizeof (struct driver_info); + + for (i = 0; i < (n - 1); i++) + if (sound_drivers[i].card_type == type) + return i; + + return -1; /* + * Not found + */ +} + long sndtable_init (long mem_start) { - int i, n = sizeof (supported_drivers) / sizeof (struct card_info); + int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info); + int drv; for (i = 0; i < (n - 1); i++) - if (supported_drivers[i].enabled) - if (supported_drivers[i].probe (&supported_drivers[i].config)) + if (snd_installed_cards[i].enabled) + if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1) + snd_installed_cards[i].enabled = 0; /* + * Mark as not detected + */ + else if (sound_drivers[drv].probe (&snd_installed_cards[i].config)) { #ifndef SHORT_BANNERS printk ("snd%d", - supported_drivers[i].card_type); + snd_installed_cards[i].card_type); #endif - mem_start = supported_drivers[i].attach (mem_start, &supported_drivers[i].config); + mem_start = sound_drivers[drv].attach (mem_start, &snd_installed_cards[i].config); #ifndef SHORT_BANNERS 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); + snd_installed_cards[i].config.io_base, + snd_installed_cards[i].config.irq, + snd_installed_cards[i].config.dma); #endif } else - supported_drivers[i].enabled = 0; /* Mark as not detected */ + snd_installed_cards[i].enabled = 0; /* + * Mark as not detected + */ return mem_start; } int sndtable_probe (int unit, struct address_info *hw_config) -{ - int i, n = sizeof (supported_drivers) / sizeof (struct card_info); + { + int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info); - if (!unit) - return TRUE; + if (!unit) + return TRUE; - for (i = 0; i < (n - 1); i++) - if (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].probe (hw_config)) - return 1; - supported_drivers[i].enabled = 0; /* Mark as not detected */ - return 0; - } + for (i = 0; i < (n - 1); i++) + if (snd_installed_cards[i].enabled) + if (snd_installed_cards[i].card_type == unit) + { + int drv; + + snd_installed_cards[i].config.io_base = hw_config->io_base; + snd_installed_cards[i].config.irq = hw_config->irq; + snd_installed_cards[i].config.dma = hw_config->dma; + if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1) + snd_installed_cards[i].enabled = 0; /* + * Mark as not + * detected + */ + else if (sound_drivers[drv].probe (hw_config)) + return 1; + snd_installed_cards[i].enabled = 0; /* + * Mark as not detected + */ + return 0; + } - return FALSE; -} + return FALSE; + } int sndtable_init_card (int unit, struct address_info *hw_config) -{ - int i, n = sizeof (supported_drivers) / sizeof (struct card_info); - - if (!unit) - { - if (sndtable_init (0) != 0) - panic ("snd: Invalid memory allocation\n"); - return TRUE; - } + { + int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info); - for (i = 0; i < (n - 1); i++) - if (supported_drivers[i].card_type == unit) + if (!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"); + if (sndtable_init (0) != 0) + panic ("snd: Invalid memory allocation\n"); return TRUE; } - return FALSE; -} + for (i = 0; i < (n - 1); i++) + if (snd_installed_cards[i].card_type == unit) + { + int drv; + + snd_installed_cards[i].config.io_base = hw_config->io_base; + snd_installed_cards[i].config.irq = hw_config->irq; + snd_installed_cards[i].config.dma = hw_config->dma; + + if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1) + snd_installed_cards[i].enabled = 0; /* + * Mark as not detected + */ + else if (sound_drivers[drv].attach (0, hw_config) != 0) + panic ("snd#: Invalid memory allocation\n"); + return TRUE; + } + return FALSE; + } + int sndtable_get_cardcount (void) { - return num_dspdevs + num_mixers + num_synths + num_midis; + return num_audiodevs + 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); + int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info); /* * First disable all drivers */ for (i = 0; i < n; i++) - supported_drivers[i].enabled = 0; + snd_installed_cards[i].enabled = 0; if (ints[0] == 0 || ints[1] == 0) return; @@ -145,7 +182,9 @@ if (card_type > 127) { - /* Add any future extensions here */ + /* + * Add any future extensions here + */ return; } @@ -155,17 +194,20 @@ ptr = -1; for (j = 0; j < n && ptr == -1; j++) - if (supported_drivers[j].card_type == card_type) + if (snd_installed_cards[j].card_type == card_type && + !snd_installed_cards[j].enabled) /* + * Not already found + */ 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; + snd_installed_cards[ptr].enabled = 1; + snd_installed_cards[ptr].config.io_base = ioaddr; + snd_installed_cards[ptr].config.irq = irq; + snd_installed_cards[ptr].config.dma = dma; } } } @@ -174,24 +216,27 @@ void sound_chconf (int card_type, int ioaddr, int irq, int dma) { - int i, n = sizeof (supported_drivers) / sizeof (struct card_info); + int i, n = sizeof (snd_installed_cards) / 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) + if (snd_installed_cards[j].card_type == card_type && + !snd_installed_cards[j].enabled) /* + * Not already found + */ ptr = j; if (ptr != -1) { - supported_drivers[ptr].enabled = 1; + snd_installed_cards[ptr].enabled = 1; if (ioaddr) - supported_drivers[ptr].config.io_base = ioaddr; + snd_installed_cards[ptr].config.io_base = ioaddr; if (irq) - supported_drivers[ptr].config.irq = irq; + snd_installed_cards[ptr].config.irq = irq; if (dma) - supported_drivers[ptr].config.dma = dma; + snd_installed_cards[ptr].config.dma = dma; } } @@ -201,17 +246,24 @@ sound_getconf (int card_type) { int j, ptr; - int n = sizeof (supported_drivers) / sizeof (struct card_info); + int n = sizeof (snd_installed_cards) / sizeof (struct card_info); ptr = -1; for (j = 0; j < n && ptr == -1; j++) - if (supported_drivers[j].card_type == card_type) + if (snd_installed_cards[j].card_type == card_type) ptr = j; if (ptr == -1) return (struct address_info *) NULL; - return &supported_drivers[ptr].config; + return &snd_installed_cards[ptr].config; +} + +#else + +void +sound_setup (char *str, int *ints) +{ } #endif diff -u --recursive --new-file v1.1.30/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h --- v1.1.30/linux/drivers/sound/dev_table.h Sun May 1 12:12:25 1994 +++ linux/drivers/sound/dev_table.h Mon Jul 18 09:50:55 1994 @@ -40,20 +40,71 @@ * NOTE! NOTE! NOTE! NOTE! */ -struct card_info { - int card_type; /* From soundcard.c */ +struct driver_info { + int card_type; /* From soundcard.h */ char *name; long (*attach) (long mem_start, struct address_info *hw_config); int (*probe) (struct address_info *hw_config); +}; + +struct card_info { + int card_type; /* Link (search key) to the driver list */ struct address_info config; int enabled; }; -/** UWM -- new MIDI structure here.. **/ +/* + * Device specific parameters (used only by dmabuf.c) + */ +#define MAX_SUB_BUFFERS (32*MAX_REALTIME_FACTOR) + +#define DMODE_NONE 0 +#define DMODE_OUTPUT 1 +#define DMODE_INPUT 2 + +struct dma_buffparms { + int dma_mode; /* DMODE_INPUT, DMODE_OUTPUT or DMODE_NONE */ + + /* + * Pointers to raw buffers + */ + + char *raw_buf[DSP_BUFFCOUNT]; + unsigned long raw_buf_phys[DSP_BUFFCOUNT]; + int raw_count; + + /* + * Device state tables + */ + + unsigned long flags; +#define DMA_BUSY 0x00000001 +#define DMA_RESTART 0x00000002 +#define DMA_ACTIVE 0x00000004 +#define DMA_STARTED 0x00000008 +#define DMA_ALLOC_DONE 0x00000020 + + int open_mode; + + /* + * Queue parameters. + */ + int qlen; + int qhead; + int qtail; + + int nbufs; + int counts[MAX_SUB_BUFFERS]; + int subdivision; + char *buf[MAX_SUB_BUFFERS]; + unsigned long buf_phys[MAX_SUB_BUFFERS]; + + int fragment_size; + int max_fragments; + + int bytes_in_use; -struct generic_midi_info{ - char *name; /* Name of the MIDI device.. */ - long (*attach) (long mem_start); + int underrun_count; }; struct audio_operations { @@ -61,6 +112,9 @@ int flags; #define NOTHING_SPECIAL 0 #define NEEDS_RESTART 1 +#define DMA_AUTOMODE 2 + int format_mask; /* Bitmask for supported audio formats */ + void *devc; /* Driver specific info */ int (*open) (int dev, int mode); void (*close) (int dev); void (*output_block) (int dev, unsigned long buf, @@ -72,9 +126,13 @@ int (*prepare_for_output) (int dev, int bufsize, int nbufs); void (*reset) (int dev); void (*halt_xfer) (int dev); - int (*has_output_drained)(int dev); + int (*local_qlen)(int dev); void (*copy_from_user)(int dev, char *localbuf, int localoffs, snd_rw_buf *userbuf, int useroffs, int len); + int buffcount; + long buffsize; + int dmachan; + struct dma_buffparms *dmap; }; struct mixer_operations { @@ -83,13 +141,14 @@ struct synth_operations { struct synth_info *info; + int midi_dev; int synth_type; int synth_subtype; int (*open) (int dev, int mode); void (*close) (int dev); int (*ioctl) (int dev, unsigned int cmd, unsigned int arg); - int (*kill_note) (int dev, int voice, int velocity); + int (*kill_note) (int dev, int voice, int note, int velocity); int (*start_note) (int dev, int voice, int note, int velocity); int (*set_instr) (int dev, int voice, int instr); void (*reset) (int dev); @@ -101,10 +160,16 @@ void (*panning) (int dev, int voice, int value); void (*volume_method) (int dev, int mode); int (*pmgr_interface) (int dev, struct patmgr_info *info); + void (*bender) (int dev, int chn, int value); + int (*alloc_voice) (int dev, int chn, int note, struct voice_alloc_info *alloc); + + struct voice_alloc_info alloc; + struct channel_info chn_info[16]; }; struct midi_operations { struct midi_info info; + struct synth_operations *converter; int (*open) (int dev, int mode, void (*inputintr)(int dev, unsigned char data), void (*outputintr)(int dev) @@ -115,159 +180,163 @@ int (*start_read) (int dev); int (*end_read) (int dev); void (*kick)(int dev); - int (*command) (int dev, unsigned char data); + int (*command) (int dev, unsigned char *data); int (*buffer_status) (int dev); + int (*prefix_cmd) (int dev, unsigned char status); }; -/** UWM -- new structure for MIDI **/ - -struct generic_midi_operations { - struct midi_info info; - int (*open) (int dev, int mode); - void (*close) (int dev); - int (*write) (int dev, snd_rw_buf *data); - int (*read) (int dev, snd_rw_buf *data); -}; - -#ifndef ALL_EXTERNAL_TO_ME - -#ifdef _MIDI_TABLE_C_ - -/** UWM **/ - struct generic_midi_operations * generic_midi_devs[MAX_MIDI_DEV] = {NULL}; - int num_generic_midis = 0, pro_midi_dev = 0; - - struct generic_midi_info midi_supported[] = { +struct sound_timer_operations { + struct sound_timer_info info; + int priority; + int devlink; + int (*open)(int dev, int mode); + void (*close)(int dev); + int (*event)(int dev, unsigned char *ev); + unsigned long (*get_time)(int dev); + int (*ioctl) (int dev, unsigned int cmd, unsigned int arg); + void (*arm_timer)(int dev, long time); +}; -#ifndef EXCLUDE_PRO_MIDI - {"ProAudioSpectrum MV101",pro_midi_attach} +#ifdef _DEV_TABLE_C_ + struct audio_operations *audio_devs[MAX_AUDIO_DEV] = {NULL}; int num_audiodevs = 0; + struct mixer_operations *mixer_devs[MAX_MIXER_DEV] = {NULL}; int num_mixers = 0; + struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV] = {NULL}; int num_synths = 0; + struct midi_operations *midi_devs[MAX_MIDI_DEV] = {NULL}; int num_midis = 0; + +#ifndef EXCLUDE_SEQUENCER + extern struct sound_timer_operations default_sound_timer; + struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = + {&default_sound_timer, NULL}; + int num_sound_timers = 1; +#else + struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = + {NULL}; + int num_sound_timers = 0; #endif - }; - int num_midi_drivers = - sizeof (midi_supported) / sizeof(struct generic_midi_info); +/* + * List of low level drivers compiled into the kernel. + */ + struct driver_info sound_drivers[] = { +#ifndef EXCLUDE_PSS + {SNDCARD_PSS, "Echo Personal Sound System PSS (ESC614)", attach_pss, probe_pss}, #endif - - -#ifdef _DEV_TABLE_C_ - struct audio_operations * dsp_devs[MAX_DSP_DEV] = {NULL}; int num_dspdevs = 0; - struct mixer_operations * mixer_devs[MAX_MIXER_DEV] = {NULL}; int num_mixers = 0; - struct synth_operations * synth_devs[MAX_SYNTH_DEV] = {NULL}; int num_synths = 0; - struct midi_operations * midi_devs[MAX_MIDI_DEV] = {NULL}; int num_midis = 0; - - -# ifndef EXCLUDE_MPU401 - int mpu401_dev = 0; -# endif +#ifndef EXCLUDE_YM3812 + {SNDCARD_ADLIB, "OPL-2/OPL-3 FM", attach_adlib_card, probe_adlib}, +#endif +#ifndef EXCLUDE_PAS + {SNDCARD_PAS, "ProAudioSpectrum", attach_pas_card, probe_pas}, +#endif +#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI) + {SNDCARD_MPU401,"Roland MPU-401", attach_mpu401, probe_mpu401}, +#endif +#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI) + {SNDCARD_UART6850,"6860 UART Midi", attach_uart6850, probe_uart6850}, +#endif +#ifndef EXCLUDE_SB + {SNDCARD_SB, "SoundBlaster", attach_sb_card, probe_sb}, +#endif +#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) +#ifndef EXCLUDE_AUDIO + {SNDCARD_SB16, "SoundBlaster16", sb16_dsp_init, sb16_dsp_detect}, +#endif +#ifndef EXCLUDE_MIDI + {SNDCARD_SB16MIDI,"SB16 MIDI", attach_sb16midi, probe_sb16midi}, +#endif +#endif +#ifndef EXCLUDE_GUS16 + {SNDCARD_GUS16, "Ultrasound 16-bit opt.", attach_gus_db16, probe_gus_db16}, +#endif +#ifndef EXCLUDE_MSS + {SNDCARD_MSS, "MS Sound System", attach_ms_sound, probe_ms_sound}, +#endif +#ifndef EXCLUDE_GUS + {SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus}, +#endif + {0, "*?*", NULL, NULL} + }; /* + * List of devices actually configured in the system. + * * Note! The detection order is significant. Don't change it. */ - struct card_info supported_drivers[] = { + struct card_info snd_installed_cards[] = { +#ifndef EXCLUDE_PSS + {SNDCARD_PSS, {PSS_BASE, PSS_IRQ, PSS_DMA}, SND_DEFAULT_ENABLE}, +#endif #if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI) - {SNDCARD_MPU401,"Roland MPU-401", attach_mpu401, probe_mpu401, - {MPU_BASE, MPU_IRQ, 0}, SND_DEFAULT_ENABLE}, + {SNDCARD_MPU401, {MPU_BASE, MPU_IRQ, 0}, SND_DEFAULT_ENABLE}, +#ifdef MPU2_BASE + {SNDCARD_MPU401, {MPU2_BASE, MPU2_IRQ, 0}, SND_DEFAULT_ENABLE}, +#endif +#ifdef MPU3_BASE + {SNDCARD_MPU401, {MPU3_BASE, MPU2_IRQ, 0}, SND_DEFAULT_ENABLE}, +#endif #endif +#ifndef EXCLUDE_MSS + {SNDCARD_MSS, {MSS_BASE, MSS_IRQ, MSS_DMA}, SND_DEFAULT_ENABLE}, +#endif + +#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI) + {SNDCARD_UART6850, {U6850_BASE, U6850_IRQ, 0}, SND_DEFAULT_ENABLE}, +#endif #ifndef EXCLUDE_PAS - {SNDCARD_PAS, "ProAudioSpectrum", attach_pas_card, probe_pas, - {PAS_BASE, PAS_IRQ, PAS_DMA}, SND_DEFAULT_ENABLE}, + {SNDCARD_PAS, {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}, SND_DEFAULT_ENABLE}, + {SNDCARD_SB, {SBC_BASE, SBC_IRQ, SBC_DMA}, SND_DEFAULT_ENABLE}, #endif -#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SBPRO) +#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) #ifndef EXCLUDE_AUDIO - {SNDCARD_SB16, "SoundBlaster16", sb16_dsp_init, sb16_dsp_detect, - {SBC_BASE, SBC_IRQ, SB16_DMA}, SND_DEFAULT_ENABLE}, + {SNDCARD_SB16, {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}, + {SNDCARD_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}, +#ifndef EXCLUDE_GUS16 + {SNDCARD_GUS16, {GUS16_BASE, GUS16_IRQ, GUS16_DMA}, SND_DEFAULT_ENABLE}, +#endif + {SNDCARD_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}, SND_DEFAULT_ENABLE}, + {SNDCARD_ADLIB, {FM_MONO, 0, 0}, SND_DEFAULT_ENABLE}, #endif - {0, "*?*", NULL, 0} + {0, {0}, 0} }; int num_sound_drivers = - sizeof(supported_drivers) / sizeof (struct card_info); + sizeof(sound_drivers) / sizeof (struct driver_info); + int num_sound_cards = + sizeof(snd_installed_cards) / sizeof (struct card_info); -# ifndef EXCLUDE_AUDIO - int sound_buffcounts[MAX_DSP_DEV] = {0}; - long sound_buffsizes[MAX_DSP_DEV] = {0}; - int sound_dsp_dmachan[MAX_DSP_DEV] = {0}; - int sound_dma_automode[MAX_DSP_DEV] = {0}; -# endif #else - extern struct audio_operations * dsp_devs[MAX_DSP_DEV]; int num_dspdevs; + extern struct audio_operations * audio_devs[MAX_AUDIO_DEV]; int num_audiodevs; extern struct mixer_operations * mixer_devs[MAX_MIXER_DEV]; extern int num_mixers; - extern struct synth_operations * synth_devs[MAX_SYNTH_DEV]; extern int num_synths; + extern struct synth_operations * synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV]; extern int num_synths; extern struct midi_operations * midi_devs[MAX_MIDI_DEV]; extern int num_midis; -# ifndef EXCLUDE_MPU401 - extern int mpu401_dev; -# endif + extern struct sound_timer_operations * sound_timer_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV]; extern int num_sound_timers; - extern struct card_info supported_drivers[]; + extern struct driver_info sound_drivers[]; extern int num_sound_drivers; + extern struct card_info snd_installed_cards[]; + extern int num_sound_cards; -# ifndef EXCLUDE_AUDIO - extern int sound_buffcounts[MAX_DSP_DEV]; - extern long sound_buffsizes[MAX_DSP_DEV]; - extern int sound_dsp_dmachan[MAX_DSP_DEV]; - extern int sound_dma_automode[MAX_DSP_DEV]; -# endif - -#endif - 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 +int snd_find_driver(int type); -#endif - -/* If external to me.... :) */ - -#ifdef ALL_EXTERNAL_TO_ME - - extern struct audio_operations * dsp_devs[MAX_DSP_DEV]; int num_dspdevs; - extern struct mixer_operations * mixer_devs[MAX_MIXER_DEV]; extern int num_mixers; - extern struct synth_operations * synth_devs[MAX_SYNTH_DEV]; extern int num_synths; - extern struct midi_operations * midi_devs[MAX_MIDI_DEV]; extern int num_midis; - extern struct generic_midi_operations *generic_midi_devs[]; - extern int num_generic_midis, pro_midi_dev; - -#ifndef EXCLUDE_MPU401 - extern int mpu401_dev; -#endif - - extern struct generic_midi_info midi_supported[]; - extern struct card_info supported_drivers[]; - extern int num_sound_drivers; - extern int num_midi_drivers; -#ifndef EXCLUDE_AUDIO - extern int sound_buffcounts[MAX_DSP_DEV]; - extern long sound_buffsizes[MAX_DSP_DEV]; - extern int sound_dsp_dmachan[MAX_DSP_DEV]; - extern int sound_dma_automode[MAX_DSP_DEV]; -#endif - -#endif +#endif /* _DEV_TABLE_C_ */ +#endif /* _DEV_TABLE_H_ */ diff -u --recursive --new-file v1.1.30/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c --- v1.1.30/linux/drivers/sound/dmabuf.c Sun May 1 12:12:26 1994 +++ linux/drivers/sound/dmabuf.c Mon Jul 18 09:50:55 1994 @@ -3,7 +3,7 @@ * * The DMA buffer manager for digitized voice applications * - * Copyright by Hannu Savolainen 1993 + * Copyright by Hannu Savolainen 1993, 1994 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -35,68 +35,14 @@ #if !defined(EXCLUDE_AUDIO) || !defined(EXCLUDE_GUS) -#define MAX_SUB_BUFFERS (32*MAX_REALTIME_FACTOR) +DEFINE_WAIT_QUEUES (dev_sleeper[MAX_AUDIO_DEV], dev_sleep_flag[MAX_AUDIO_DEV]); -/* - * The DSP channel can be used either for input or output. Variable - * 'dma_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 DMODE_NONE 0 -#define DMODE_OUTPUT 1 -#define DMODE_INPUT 2 - -DEFINE_WAIT_QUEUES (dev_sleeper[MAX_DSP_DEV], dev_sleep_flag[MAX_DSP_DEV]); - -static int dma_mode[MAX_DSP_DEV] = -{0}; /* DMODE_INPUT, DMODE_OUTPUT or DMODE_NONE */ - -static volatile int dmabuf_interrupted[MAX_DSP_DEV] = -{0}; - -/* - * Pointers to raw buffers - */ - -char *snd_raw_buf[MAX_DSP_DEV][DSP_BUFFCOUNT] = -{ - {NULL}}; -unsigned long snd_raw_buf_phys[MAX_DSP_DEV][DSP_BUFFCOUNT]; -int snd_raw_count[MAX_DSP_DEV]; - -/* - * Device state tables - */ - -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]; -static int dev_underrun[MAX_DSP_DEV]; -static int bufferalloc_done[MAX_DSP_DEV] = -{0}; - -/* - * Logical buffers for each devices - */ - -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] = -{ - {NULL}}; -static int dev_buffsize[MAX_DSP_DEV]; +static struct dma_buffparms dmaps[MAX_AUDIO_DEV] = +{0}; /* + * Primitive way to allocate + * such a large array. + * Needs dynamic run-time alloction. + */ static void reorganize_buffers (int dev) @@ -105,130 +51,159 @@ * This routine breaks the physical device buffers to logical ones. */ + struct dma_buffparms *dmap = audio_devs[dev]->dmap; + struct audio_operations *dsp_dev = audio_devs[dev]; + 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); - sz = dsp_devs[dev]->ioctl (dev, SOUND_PCM_READ_BITS, 0, 1); + if (dmap->fragment_size == 0) + { /* Compute the fragment size using the default algorithm */ - if (sr < 1 || nc < 1 || sz < 1) - { - printk ("SOUND: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n", dev, sr, nc, sz); - sr = DSP_DEFAULT_SPEED; - nc = 1; - sz = 8; - } + sr = dsp_dev->ioctl (dev, SOUND_PCM_READ_RATE, 0, 1); + nc = dsp_dev->ioctl (dev, SOUND_PCM_READ_CHANNELS, 0, 1); + sz = dsp_dev->ioctl (dev, SOUND_PCM_READ_BITS, 0, 1); + + if (sr < 1 || nc < 1 || sz < 1) + { + printk ("Warning: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n", + dev, sr, nc, sz); + sr = DSP_DEFAULT_SPEED; + nc = 1; + sz = 8; + } - sz /= 8; /* Convert # of bits -> # of bytes */ + sz /= 8; /* #bits -> #bytes */ - sz = sr * nc * sz; + sz = sr * nc * sz; - /* - * Compute a buffer size not exeeding 1 second. + /* + * Compute a buffer size for time not exeeding 1 second. + * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds + * of sound (using the current speed, sample size and #channels). */ - bsz = sound_buffsizes[dev]; + bsz = dsp_dev->buffsize; + while (bsz > sz) + bsz /= 2; - while (bsz > sz) - bsz >>= 1; /* Divide by 2 */ + if (dsp_dev->buffcount == 1 && bsz == dsp_dev->buffsize) + bsz /= 2; /* Needs at least 2 buffers */ - if (sound_buffcounts[dev] == 1 && bsz == sound_buffsizes[dev]) - bsz >>= 1; /* Need at least 2 buffers */ + if (dmap->subdivision == 0) /* Not already set */ + dmap->subdivision = 1; /* Init to default value */ - if (dev_subdivision[dev] == 0) - dev_subdivision[dev] = 1; /* Default value */ + bsz /= dmap->subdivision; - bsz /= dev_subdivision[dev]; /* Use smaller buffers */ + if (bsz < 64) + bsz = 4096; /* Just a sanity check */ - if (bsz == 0) - bsz = 4096; /* Just a sanity check */ + while ((dsp_dev->buffsize * dsp_dev->buffcount) / bsz > MAX_SUB_BUFFERS) + bsz *= 2; - while ((sound_buffsizes[dev] * sound_buffcounts[dev]) / bsz > MAX_SUB_BUFFERS) - bsz <<= 1; /* Too much buffers */ - - dev_buffsize[dev] = bsz; - n = 0; + dmap->fragment_size = bsz; + } + else + { + /* + * The process has specified the buffer sice with SNDCTL_DSP_SETFRAGMENT or + * the buffer sice computation has already been done. + */ + if (dmap->fragment_size > audio_devs[dev]->buffsize) + dmap->fragment_size = audio_devs[dev]->buffsize; + bsz = dmap->fragment_size; + } /* * Now computing addresses for the logical buffers */ - for (i = 0; i < snd_raw_count[dev]; i++) + n = 0; + for (i = 0; i < dmap->raw_count && + n < dmap->max_fragments && + n < MAX_SUB_BUFFERS; i++) { p = 0; - while ((p + bsz) <= sound_buffsizes[dev]) + while ((p + bsz) <= dsp_dev->buffsize && + n < dmap->max_fragments && + n < MAX_SUB_BUFFERS) { - dev_buf[dev][n] = snd_raw_buf[dev][i] + p; - dev_buf_phys[dev][n] = snd_raw_buf_phys[dev][i] + p; + dmap->buf[n] = dmap->raw_buf[i] + p; + dmap->buf_phys[n] = dmap->raw_buf_phys[i] + p; p += bsz; n++; } } - dev_nbufs[dev] = n; + dmap->nbufs = n; + dmap->bytes_in_use = n * bsz; - for (i = 0; i < dev_nbufs[dev]; i++) + for (i = 0; i < dmap->nbufs; i++) { - dev_counts[dev][i] = 0; + dmap->counts[i] = 0; } - bufferalloc_done[dev] = 1; + dmap->flags |= DMA_ALLOC_DONE; } static void dma_init_buffers (int dev) { - RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]); - dev_underrun[dev] = 0; + struct dma_buffparms *dmap = audio_devs[dev]->dmap = &dmaps[dev]; - dev_busy[dev] = 1; + RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]); - bufferalloc_done[dev] = 0; + dmap->flags = DMA_BUSY; /* Other flags off */ + dmap->qlen = dmap->qhead = dmap->qtail = 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; + dmap->qlen = dmap->qtail = dmap->qhead = 0; + dmap->dma_mode = DMODE_NONE; } int DMAbuf_open (int dev, int mode) { int retval; + struct dma_buffparms *dmap = NULL; - if (dev >= num_dspdevs) + if (dev >= num_audiodevs) { printk ("PCM device %d not installed.\n", dev); return RET_ERROR (ENXIO); } - if (dev_busy[dev]) - return RET_ERROR (EBUSY); - - if (!dsp_devs[dev]) + if (!audio_devs[dev]) { - printk ("DSP device %d not initialized\n", dev); + printk ("PCM device %d not initialized\n", dev); return RET_ERROR (ENXIO); } + dmap = audio_devs[dev]->dmap = &dmaps[dev]; + + if (dmap->flags & DMA_BUSY) + return RET_ERROR (EBUSY); + #ifdef USE_RUNTIME_DMAMEM + dmap->raw_buf[0] = NULL; sound_dma_malloc (dev); #endif - if (snd_raw_buf[dev][0] == NULL) + if (dmap->raw_buf[0] == NULL) return RET_ERROR (ENOSPC); /* Memory allocation failed during boot */ - if ((retval = dsp_devs[dev]->open (dev, mode)) < 0) + if ((retval = audio_devs[dev]->open (dev, mode)) < 0) return retval; - dev_modes[dev] = mode; - dev_subdivision[dev] = 0; + dmap->open_mode = mode; + dmap->subdivision = dmap->underrun_count = 0; + dmap->fragment_size = 0; + dmap->max_fragments = 65536; /* Just a large value */ 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); + audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_BITS, 8, 1); + audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_CHANNELS, 1, 1); + audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_RATE, DSP_DEFAULT_SPEED, 1); return 0; } @@ -240,10 +215,11 @@ unsigned long flags; DISABLE_INTR (flags); - dsp_devs[dev]->reset (dev); - dsp_devs[dev]->close (dev); + + audio_devs[dev]->reset (dev); + audio_devs[dev]->close (dev); - if ((retval = dsp_devs[dev]->open (dev, dev_modes[dev])) < 0) + if ((retval = audio_devs[dev]->open (dev, audio_devs[dev]->dmap->open_mode)) < 0) printk ("Sound: Reset failed - Can't reopen device\n"); RESTORE_INTR (flags); @@ -256,17 +232,19 @@ { unsigned long flags; - if (dma_mode[dev] == DMODE_OUTPUT) + if (audio_devs[dev]->dmap->dma_mode == DMODE_OUTPUT) { DISABLE_INTR (flags); - while ((!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) || - dmabuf_interrupted[dev])) - && dev_qlen[dev]) + while (!PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) + && audio_devs[dev]->dmap->qlen) { DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 10 * HZ); if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev])) - return dev_qlen[dev]; + { + RESTORE_INTR (flags); + return audio_devs[dev]->dmap->qlen; + } } RESTORE_INTR (flags); @@ -276,27 +254,26 @@ */ DISABLE_INTR (flags); - if (dsp_devs[dev]->has_output_drained) /* Device has hidden buffers */ + if (audio_devs[dev]->local_qlen) /* Device has hidden buffers */ { - while (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) || - dmabuf_interrupted[dev]) - && !dsp_devs[dev]->has_output_drained (dev)) + while (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev])) + && audio_devs[dev]->local_qlen (dev)) { - DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], HZ / 4); + DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], HZ); } } RESTORE_INTR (flags); } - return dev_qlen[dev]; + return audio_devs[dev]->dmap->qlen; } int DMAbuf_release (int dev, int mode) { + unsigned long flags; - if (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) || - dmabuf_interrupted[dev]) - && (dma_mode[dev] == DMODE_OUTPUT)) + if (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev])) + && (audio_devs[dev]->dmap->dma_mode == DMODE_OUTPUT)) { dma_sync (dev); } @@ -305,12 +282,14 @@ sound_dma_free (dev); #endif - dsp_devs[dev]->reset (dev); + DISABLE_INTR (flags); + audio_devs[dev]->reset (dev); - dsp_devs[dev]->close (dev); + audio_devs[dev]->close (dev); - dma_mode[dev] = DMODE_NONE; - dev_busy[dev] = 0; + audio_devs[dev]->dmap->dma_mode = DMODE_NONE; + audio_devs[dev]->dmap->flags &= ~DMA_BUSY; + RESTORE_INTR (flags); return 0; } @@ -320,50 +299,51 @@ { unsigned long flags; int err = EIO; + struct dma_buffparms *dmap = audio_devs[dev]->dmap; DISABLE_INTR (flags); - if (!dev_qlen[dev]) + if (!dmap->qlen) { - if (dev_needs_restart[dev]) + if (dmap->flags & DMA_RESTART) { dma_reset (dev); - dev_needs_restart[dev] = 0; + dmap->flags &= ~DMA_RESTART; } - if (dma_mode[dev] == DMODE_OUTPUT) /* Was output -> direction change */ + if (dmap->dma_mode == DMODE_OUTPUT) /* Direction change */ { dma_sync (dev); dma_reset (dev); - dma_mode[dev] = DMODE_NONE; + dmap->dma_mode = DMODE_NONE; } - if (!bufferalloc_done[dev]) + if (!(dmap->flags & DMA_ALLOC_DONE)) reorganize_buffers (dev); - if (!dma_mode[dev]) + if (dmap->dma_mode) { int err; - if ((err = dsp_devs[dev]->prepare_for_input (dev, - dev_buffsize[dev], dev_nbufs[dev])) < 0) + if ((err = audio_devs[dev]->prepare_for_input (dev, + dmap->fragment_size, dmap->nbufs)) < 0) { RESTORE_INTR (flags); return err; } - dma_mode[dev] = DMODE_INPUT; + dmap->dma_mode = DMODE_INPUT; } - if (!dev_active[dev]) + if (!(dmap->flags & DMA_ACTIVE)) { - 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; + audio_devs[dev]->start_input (dev, dmap->buf_phys[dmap->qtail], + dmap->fragment_size, 0, + !(audio_devs[dev]->flags & DMA_AUTOMODE) || + !(dmap->flags & DMA_STARTED)); + dmap->flags |= DMA_ACTIVE | DMA_STARTED; } /* Wait for the next block */ + DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ); if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev])) { @@ -376,60 +356,42 @@ } RESTORE_INTR (flags); - if (!dev_qlen[dev]) + if (!dmap->qlen) 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]]; + *buf = &dmap->buf[dmap->qhead][dmap->counts[dmap->qhead]]; + *len = dmap->fragment_size - dmap->counts[dmap->qhead]; - return dev_qhead[dev]; + return dmap->qhead; } int DMAbuf_rmchars (int dev, int buff_no, int c) { - int p = dev_counts[dev][dev_qhead[dev]] + c; + struct dma_buffparms *dmap = audio_devs[dev]->dmap; + + int p = dmap->counts[dmap->qhead] + c; - if (p >= dev_buffsize[dev]) - { /* This buffer is now empty */ - dev_counts[dev][dev_qhead[dev]] = 0; - dev_qlen[dev]--; - dev_qhead[dev] = (dev_qhead[dev] + 1) % dev_nbufs[dev]; + if (p >= dmap->fragment_size) + { /* This buffer is completely empty */ + dmap->counts[dmap->qhead] = 0; + if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs) + printk ("\nSound: Audio queue1 corrupted for dev%d (%d/%d)\n", + dev, dmap->qlen, dmap->nbufs); + dmap->qlen--; + dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; } else - dev_counts[dev][dev_qhead[dev]] = p; + dmap->counts[dmap->qhead] = p; return 0; } int -DMAbuf_read (int dev, snd_rw_buf * user_buf, int count) -{ - char *dmabuf; - int buff_no, c, err; - - /* - * This routine returns at most 'count' bytes from the dsp input buffers. - * Returns negative value if there is an error. - */ - - if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &c)) < 0) - return buff_no; - - if (c > count) - c = count; - - COPY_TO_USER (user_buf, 0, dmabuf, c); - - if ((err = DMAbuf_rmchars (dev, buff_no, c)) < 0) - return err; - return c; - -} - -int DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) { + struct dma_buffparms *dmap = audio_devs[dev]->dmap; + switch (cmd) { case SNDCTL_DSP_RESET: @@ -444,10 +406,10 @@ break; case SNDCTL_DSP_GETBLKSIZE: - if (!bufferalloc_done[dev]) + if (!(dmap->flags & DMA_ALLOC_DONE)) reorganize_buffers (dev); - return IOCTL_OUT (arg, dev_buffsize[dev]); + return IOCTL_OUT (arg, dmap->fragment_size); break; case SNDCTL_DSP_SUBDIVIDE: @@ -456,13 +418,14 @@ if (fact == 0) { - fact = dev_subdivision[dev]; + fact = dmap->subdivision; if (fact == 0) fact = 1; return IOCTL_OUT (arg, fact); } - if (dev_subdivision[dev] != 0) /* Too late to change */ + if (dmap->subdivision != 0 || + dmap->fragment_size)/* Loo late to change */ return RET_ERROR (EINVAL); if (fact > MAX_REALTIME_FACTOR) @@ -471,110 +434,192 @@ if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16) return RET_ERROR (EINVAL); - dev_subdivision[dev] = fact; + dmap->subdivision = fact; return IOCTL_OUT (arg, fact); } break; + case SNDCTL_DSP_SETFRAGMENT: + { + int fact = IOCTL_IN (arg); + int bytes, count; + + if (fact == 0) + return RET_ERROR (EIO); + + if (dmap->subdivision != 0 || + dmap->fragment_size)/* Loo late to change */ + return RET_ERROR (EINVAL); + + bytes = fact & 0xffff; + count = (fact >> 16) & 0xffff; + + if (count == 0) + count = MAX_SUB_BUFFERS; + + if (bytes < 7 || bytes > 17) /* <64 || > 128k */ + return RET_ERROR (EINVAL); + + if (count < 2) + return RET_ERROR (EINVAL); + + dmap->fragment_size = (1 << bytes); + dmap->max_fragments = count; + + if (dmap->fragment_size > audio_devs[dev]->buffsize) + dmap->fragment_size = audio_devs[dev]->buffsize; + + if (dmap->fragment_size == audio_devs[dev]->buffsize && + audio_devs[dev]->flags & DMA_AUTOMODE) + dmap->fragment_size /= 2; /* Needs at least 2 buffers */ + + dmap->subdivision = 1; /* Disable SNDCTL_DSP_SUBDIVIDE */ + return IOCTL_OUT (arg, bytes | (count << 16)); + } + break; + default: - return dsp_devs[dev]->ioctl (dev, cmd, arg, local); + return audio_devs[dev]->ioctl (dev, cmd, arg, local); } - /* NOTREACHED */ return RET_ERROR (EIO); } +static int +space_in_queue (int dev) +{ + int len, max, tmp; + struct dma_buffparms *dmap = audio_devs[dev]->dmap; + + if (dmap->qlen == dmap->nbufs)/* No space at all */ + return 0; + + /* + * Verify that there are no more pending buffers than the limit + * defined by the process. + */ + + max = dmap->max_fragments; + len = dmap->qlen; + + if (audio_devs[dev]->local_qlen) + { + tmp = audio_devs[dev]->local_qlen (dev); + if (tmp & len) + tmp--; /* + * This buffer has been counted twice + */ + len += tmp; + } + + if (len >= max) + return 0; + return 1; +} + int DMAbuf_getwrbuffer (int dev, char **buf, int *size) { unsigned long flags; - int err = EIO; + int abort, err = EIO; + struct dma_buffparms *dmap = audio_devs[dev]->dmap; - if (dma_mode[dev] == DMODE_INPUT) /* Was input -> Direction change */ + if (dmap->dma_mode == DMODE_INPUT) /* Direction change */ { dma_reset (dev); - dma_mode[dev] = DMODE_NONE; + dmap->dma_mode = DMODE_NONE; } - else if (dev_needs_restart[dev]) /* Restart buffering */ + else if (dmap->flags & DMA_RESTART) /* Restart buffering */ { dma_sync (dev); dma_reset (dev); } - dev_needs_restart[dev] = 0; + dmap->flags &= ~DMA_RESTART; - if (!bufferalloc_done[dev]) + if (!(dmap->flags & DMA_ALLOC_DONE)) reorganize_buffers (dev); - if (!dma_mode[dev]) + if (!dmap->dma_mode) { int err; - dma_mode[dev] = DMODE_OUTPUT; - if ((err = dsp_devs[dev]->prepare_for_output (dev, - dev_buffsize[dev], dev_nbufs[dev])) < 0) + dmap->dma_mode = DMODE_OUTPUT; + if ((err = audio_devs[dev]->prepare_for_output (dev, + dmap->fragment_size, dmap->nbufs)) < 0) return err; } DISABLE_INTR (flags); - RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]); - - if (dev_qlen[dev] == dev_nbufs[dev]) + abort = 0; + while (!space_in_queue (dev) && + !abort) { - if (!dev_active[dev]) - { - printk ("Soundcard warning: DMA not activated %d/%d\n", - dev_qlen[dev], dev_nbufs[dev]); - return RET_ERROR (EIO); - } - - /* Wait for free space */ + /* + * Wait for free space + */ 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; + abort = 1; SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]); } else if (PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev])) - err = EINTR; + { + err = EINTR; + abort = 1; + } } RESTORE_INTR (flags); - if (dev_qlen[dev] == dev_nbufs[dev]) - return RET_ERROR (err); /* We have got signal (?) */ + if (!space_in_queue (dev)) + { + return RET_ERROR (err); /* Caught a signal ? */ + } - *buf = dev_buf[dev][dev_qtail[dev]]; - *size = dev_buffsize[dev]; - dev_counts[dev][dev_qtail[dev]] = 0; + *buf = dmap->buf[dmap->qtail]; + *size = dmap->fragment_size; + dmap->counts[dmap->qtail] = 0; - return dev_qtail[dev]; + return dmap->qtail; } int DMAbuf_start_output (int dev, int buff_no, int l) { - if (buff_no != dev_qtail[dev]) - printk ("Soundcard warning: DMA buffers out of sync %d != %d\n", buff_no, dev_qtail[dev]); + struct dma_buffparms *dmap = audio_devs[dev]->dmap; - dev_qlen[dev]++; + if (buff_no != dmap->qtail) + printk ("Sound warning: DMA buffers out of sync %d != %d\n", buff_no, dmap->qtail); - dev_counts[dev][dev_qtail[dev]] = l; - - dev_needs_restart[dev] = (l != dev_buffsize[dev]) && - (sound_dma_automode[dev] || dsp_devs[dev]->flags & NEEDS_RESTART); + dmap->qlen++; + if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs) + printk ("\nSound: Audio queue2 corrupted for dev%d (%d/%d)\n", + dev, dmap->qlen, dmap->nbufs); + + dmap->counts[dmap->qtail] = l; + + if ((l != dmap->fragment_size) && + ((audio_devs[dev]->flags & DMA_AUTOMODE) && + audio_devs[dev]->flags & NEEDS_RESTART)) + dmap->flags |= DMA_RESTART; + else + dmap->flags &= ~DMA_RESTART; - dev_qtail[dev] = (dev_qtail[dev] + 1) % dev_nbufs[dev]; + dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - if (!dev_active[dev]) + if (!(dmap->flags & DMA_ACTIVE)) { - dev_active[dev] = 1; - 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; + dmap->flags |= DMA_ACTIVE; + audio_devs[dev]->output_block (dev, dmap->buf_phys[dmap->qhead], + dmap->counts[dmap->qhead], 0, + !(audio_devs[dev]->flags & DMA_AUTOMODE) || + !(dmap->flags & DMA_STARTED)); + dmap->flags |= DMA_STARTED; } return 0; @@ -583,7 +628,8 @@ int DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode) { - int chan = sound_dsp_dmachan[dev]; + int chan = audio_devs[dev]->dmachan; + struct dma_buffparms *dmap = audio_devs[dev]->dmap; unsigned long flags; /* @@ -595,45 +641,47 @@ * set_dma_addr() */ - if (sound_dma_automode[dev]) - { /* Auto restart mode. Transfer the whole - * buffer */ + if (audio_devs[dev]->flags & DMA_AUTOMODE) + { /* + * Auto restart mode. Transfer the whole * + * buffer + */ #ifdef linux DISABLE_INTR (flags); 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]); + set_dma_addr (chan, dmap->raw_buf_phys[0]); + set_dma_count (chan, dmap->bytes_in_use); enable_dma (chan); RESTORE_INTR (flags); -#else /* linux */ +#else #ifdef __386BSD__ printk ("sound: Invalid DMA mode for device %d\n", dev); isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE, - snd_raw_buf_phys[dev][0], - sound_buffsizes[dev], + dmap->raw_buf_phys[0], + dmap->bytes_in_use, chan); -#else /* __386BSD__ */ -#if defined(ISC) || defined(SCO) || defined(SVR42) +#else +#if defined(GENERIC_SYSV) #ifndef DMAMODE_AUTO printk ("sound: Invalid DMA mode for device %d\n", dev); -#endif /* DMAMODE_AUTO */ +#endif dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode) #ifdef DMAMODE_AUTO | DMAMODE_AUTO -#endif /* DMAMODE_AUTO */ +#endif , - snd_raw_buf_phys[dev][0], count); + dmap->raw_buf_phys[0], dmap->bytes_in_use); dma_enable (chan); -#else /* SYSV */ +#else #error This routine is not valid for this OS. -#endif /* SYSV */ -#endif /* __386BSD__ */ +#endif +#endif -#endif /* linux */ +#endif } else { @@ -646,24 +694,24 @@ set_dma_count (chan, count); enable_dma (chan); RESTORE_INTR (flags); -#else /* linux */ +#else #ifdef __386BSD__ isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE, physaddr, count, chan); -#else /* __386BSD__ */ +#else -#if defined(ISC) || defined(SCO) || defined(SVR42) +#if defined(GENERIC_SYSV) dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode), physaddr, count); dma_enable (chan); -#else /* SYSV */ +#else #error This routine is not valid for this OS. -#endif /* SYSV */ -#endif /* __386BSD__ */ +#endif /* GENERIC_SYSV */ +#endif -#endif /* linux */ +#endif } return count; @@ -672,50 +720,65 @@ long DMAbuf_init (long mem_start) { - int i; + int dev; /* - * In this version the DMA buffer allocation is done by sound_mem_init() - * which is called by init/main.c - */ - - for (i = 0; i < MAX_DSP_DEV; i++) - { - dev_qlen[i] = 0; - dev_qhead[i] = 0; - dev_qtail[i] = 0; - dev_active[i] = 0; - dev_busy[i] = 0; - bufferalloc_done[i] = 0; - } + * NOTE! This routine could be called several times. + */ + for (dev = 0; dev < num_audiodevs; dev++) + audio_devs[dev]->dmap = &dmaps[dev]; return mem_start; } void -DMAbuf_outputintr (int dev, int underrun_flag) +DMAbuf_outputintr (int dev, int event_type) { + /* + * Event types: + * 0 = DMA transfer done. Device still has more data in the local + * buffer. + * 1 = DMA transfer done. Device doesn't have local buffer or it's + * empty now. + * 2 = No DMA transfer but the device has now more space in it's local + * buffer. + */ + unsigned long flags; + struct dma_buffparms *dmap = audio_devs[dev]->dmap; - 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, - !sound_dma_automode[dev]); - dev_active[dev] = 1; - } - else if (underrun_flag) - { - dev_underrun[dev]++; - dsp_devs[dev]->halt_xfer (dev); - dev_needs_restart[dev] = (sound_dma_automode[dev] || - dsp_devs[dev]->flags & NEEDS_RESTART); - } + if (event_type != 2) + { + if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs) + { + printk ("\nSound: Audio queue3 corrupted for dev%d (%d/%d)\n", + dev, dmap->qlen, dmap->nbufs); + return; + } + dmap->qlen--; + dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; + dmap->flags &= ~DMA_ACTIVE; + + if (dmap->qlen) + { + audio_devs[dev]->output_block (dev, dmap->buf_phys[dmap->qhead], + dmap->counts[dmap->qhead], 1, + !(audio_devs[dev]->flags & DMA_AUTOMODE)); + dmap->flags |= DMA_ACTIVE; + } + else if (event_type == 1) + { + dmap->underrun_count++; + audio_devs[dev]->halt_xfer (dev); + if ((audio_devs[dev]->flags & DMA_AUTOMODE) && + audio_devs[dev]->flags & NEEDS_RESTART) + dmap->flags |= DMA_RESTART; + else + dmap->flags &= ~DMA_RESTART; + } + } /* event_type != 2 */ + DISABLE_INTR (flags); if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev])) { @@ -728,28 +791,31 @@ DMAbuf_inputintr (int dev) { unsigned long flags; + struct dma_buffparms *dmap = audio_devs[dev]->dmap; - if (!dev_busy[dev]) - { - dsp_devs[dev]->close (dev); - } - else if (dev_qlen[dev] == (dev_nbufs[dev] - 1)) + if (dmap->qlen == (dmap->nbufs - 1)) { printk ("Sound: Recording overrun\n"); - dev_underrun[dev]++; - dsp_devs[dev]->halt_xfer (dev); - dev_active[dev] = 0; - dev_needs_restart[dev] = sound_dma_automode[dev]; + dmap->underrun_count++; + audio_devs[dev]->halt_xfer (dev); + dmap->flags &= ~DMA_ACTIVE; + if (audio_devs[dev]->flags & DMA_AUTOMODE) + dmap->flags |= DMA_RESTART; + else + dmap->flags &= ~DMA_RESTART; } 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, - !sound_dma_automode[dev]); - dev_active[dev] = 1; + dmap->qlen++; + if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs) + printk ("\nSound: Audio queue4 corrupted for dev%d (%d/%d)\n", + dev, dmap->qlen, dmap->nbufs); + dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; + + audio_devs[dev]->start_input (dev, dmap->buf_phys[dmap->qtail], + dmap->fragment_size, 1, + !(audio_devs[dev]->flags & DMA_AUTOMODE)); + dmap->flags |= DMA_ACTIVE; } DISABLE_INTR (flags); @@ -764,12 +830,12 @@ DMAbuf_open_dma (int dev) { unsigned long flags; - int chan = sound_dsp_dmachan[dev]; + int chan = audio_devs[dev]->dmachan; if (ALLOC_DMA_CHN (chan)) { printk ("Unable to grab DMA%d for the audio driver\n", chan); - return 0; + return RET_ERROR (EBUSY); } DISABLE_INTR (flags); @@ -779,13 +845,13 @@ #endif RESTORE_INTR (flags); - return 1; + return 0; } void DMAbuf_close_dma (int dev) { - int chan = sound_dsp_dmachan[dev]; + int chan = audio_devs[dev]->dmachan; DMAbuf_reset_dma (chan); RELEASE_DMA_CHN (chan); @@ -805,7 +871,9 @@ */ #else -/* Stub versions if audio services not included */ +/* + * Stub versions if audio services not included + */ int DMAbuf_open (int dev, int mode) @@ -817,12 +885,6 @@ DMAbuf_release (int dev, int mode) { return 0; -} - -int -DMAbuf_read (int dev, snd_rw_buf * user_buf, int count) -{ - return RET_ERROR (EIO); } int diff -u --recursive --new-file v1.1.30/linux/drivers/sound/experimental.txt linux/drivers/sound/experimental.txt --- v1.1.30/linux/drivers/sound/experimental.txt Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/experimental.txt Mon Jul 18 09:50:55 1994 @@ -0,0 +1,160 @@ +This version contains some features which is are NOT enabled by default. +I'm trying to release an official/reliable version soon so that the +Linux version of Doom (and other games) becomes possible. For that reason +I have disabled some features which are not reliable enough to be +released for wide public. If you are interested to try them, please +read this file carefully. + +There are currently following goodies which I have disabled: + +1) ECHO PSS (Personal Sound System support) + +This version contains support for soundcards based on the AD20msp614 +chipset made by Analog Devices. This chipset consist of the +AD1848 codec, ADSP-21xx DSP chip and a ESC614 ASIC and is used in some +soundcards made by Orchid, Cardinal, Echo Speech Corporation, Western +Digital and Wearnes Technology. The PSS support is by Marc M. Hoffman +(marc.hoffman@analog.com). I received this stuff about a week ago and +have not been able to test it yet. +If you are interested, remove the B(OPT_PSS) from the DISABLED_OPTIONS +(see above). +You have also to enable the MSS support since I have not integrated +the AD1848 driver with the PSS one yet. + +2) WSS/MSS (Microsoft Sound System) support + +The MSS standard is based on the AD1848 codec by Analog Devices. +Since I don't know how the software configuration of the MSS works +so it's not supported yet. This driver should work if your card +has jumpers for the I/O base, IRQ and DMA or there is a way to configure +them using DOS. You could try this if you have a soundcard with +AD1848 codec. I have tried to use this with Aztech SG NX Pro 16 without +success. +If you are interested, remove the B(OPT_MSS) from the DISABLED_OPTIONS +(see above). + +3) /dev/sequencer2 + +This version has a new device file called /dev/sequence2. I have not +implemented all parts of it but it's there. It's only interesting if +you are writing a sequencer program yourself. Enable by creating +the device file /dev/sequencer (minor 8). + +4) /dev/midi## + +These are tty like raw devices for MIDI ports. Since there is a minor +incompatibility between different versions of Linux, I have disabled +this feature by default. You just need to create the device files yourself. +IMPORTANT! If you get warning at line 64 of midibuf.c, + don't try to use /dev/midi## files. Otherwise your + system halts. You may also try to fix the + DEFINE_TIMER() macro in os.h (just remove the 2nd NULL). + This could happen with some earlier versions of Linux + (before 1.1.0???). + +5) Support for hardware based u-Law/A-Law and ADPCM formats. + +The AD1848 (and compatibles) are able to do compression and +decompression by hardware. This version has experimental support +for some of them. Currently they are implemented just in the +AD1848 driver. The GUS MAX (and the 16 bit daughtercard) support +also 16->4 bit ADPCM (the IMA one) but it don't work yet. +The argument ioctl(SNDCTL_DSP_SAMPLESIZE) can have some new values +in addition to the 8 and 16 supported earlier. Look at soundcard.h +for more info. +(In case somebody dares to ask: The ASP chip of SB16 is not supported +so the hardware compression/decompression doesn't work with it. Also +the ADPCM format is different than the standard (IMA) one (I guess). +This feature is enabled by default. + +5) Real time fix to /dev/dsp and /dev/audio drivers + +The following feature should help game writers. This stuff is enabled +by default. +---------------- cut here --------------------- +There is a new ioctl called SNDCTL_DSP_SETFRAGMENT. It accepts a +int parameter which has format 0x00nn00ss where the nn is max number of +buffer fragments (between 0x02 and 0xff) and the ss gives indirectly the +size of a buffer fragment (fragment_size = (1 << ss)). Valid sizes are +between (ss=0x07 -> 128 bytes and ss=0x11 (17 dec) -> 128k). + +This ioctl must be used ONCE between open() and first call to +read()/write() or ioctl(SNDCTL_DSP_GETBLKSIZE). + +You need just to force the fragment size to a value which is sufficiently +short (gives the 1/20th of sec with the speed/#channels/#bits you are using). + +Using a small number of fragments offers (I guess) a significant advantage. +For example with 2 fragments the driver works as the following (at least +I hope so). Assuming that the process writes exactly 'fragment_size' of +bytes each time (this is really important). + + 1) When the process writes the first fragment, it will be copied to + the DMA buffer area and the playback begins. The write() returns + immediately and the process is free to continue. + + + 2a) If the fragment gets played before the application writes a new + one, the device will be stoppen and restarted which causes a click. + When the process calls write next time, it will be processes as + in step 1. + + 2b) If the process calls write before the buffer underflows, the + data will be queued and the process is free to continue. (There + is now one full and one partially played fragment in the kernel + buffers. This gives average delay of 1.5*fragment_time (for + example 1/20th sec) before the last byte in the buffer gets played. + + + 3a) If the device gets both fragments played before the next write + (underflow), there will be a click. The write will be processed as + in step 1. + + 3b) If the 1st fragment gets played before next write (the process + calls write during playback of the second fragment), it will be + processed as step 2b. + + 3c) If the process writes 3rd fragment when there is already 2 + fragments in the queue (1 playing and 1 waiting), the process + will block until the 1st fragment gets played. It will then be + woken up and it continues as in step 2b. This means that + the process blocks for at most the time required to play a + buffer fragment. + +This method syncronizes the process and the audio device together +automaticly. The process will block at most the 'fragment_time'. Usually +less, depending on how much it needs time to do other things. The maximum +delay between writing a byte and the time when it finally plays is +at most 3 times the 'fragment_time'. + +The delay depends on how much time the program needs to do it's +computations for the next sample (updating screen etc). If it's about +80% of the 'fragment_time' the game will run almost without delays. If it +uses more time, there is a risk that the audio buffer gets empty. + +The application code should be something like the following: + +int frag = 0x00020008; /* 2 fragments of 2^8=256 bytes */ +int frag_size; + +int fd=open("/dev/dsp"); +ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag); +ioctl(NDCTL_DSP_SPEED); /* And #channels & #bits if required */ + +/* + * Query the actual fragment sice since the driver may refuse + * the requested one (unlikely but possible?) + */ + +ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size); + +while(True) +{ + do_computations(); + write(fd, buf, frag_size); /* Always the same size!!!!!!! */ +} + +I have tested this with a modified version of str.c. The algorithm works +as long as the playing program gets enough time to run. Hitting ENTER on +another virtual console causes a pause/click (with 2 frags of 64 bytes). +------------------- cut here --------------------- diff -u --recursive --new-file v1.1.30/linux/drivers/sound/gus_card.c linux/drivers/sound/gus_card.c --- v1.1.30/linux/drivers/sound/gus_card.c Sun May 1 12:12:27 1994 +++ linux/drivers/sound/gus_card.c Mon Jul 18 09:50:55 1994 @@ -36,6 +36,9 @@ void gusintr (int); int gus_base, gus_irq, gus_dma; +extern int gus_wave_volume; +extern int gus_pcm_volume; +extern int have_gus_max; long attach_gus_card (long mem_start, struct address_info *hw_config) @@ -44,12 +47,17 @@ snd_set_irq_handler (hw_config->irq, gusintr); - if (gus_wave_detect (hw_config->io_base)) /* Try first the default */ + if (gus_wave_detect (hw_config->io_base)) /* + * Try first the default + */ { mem_start = gus_wave_init (mem_start, hw_config->irq, hw_config->dma); #ifndef EXCLUDE_MIDI mem_start = gus_midi_init (mem_start); #endif +#ifndef EXCLUDE_SEQUENCER + sound_timer_init (hw_config->io_base + 8); +#endif return mem_start; } @@ -60,7 +68,9 @@ */ for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10) - if (io_addr != hw_config->io_base) /* Already tested */ + if (io_addr != hw_config->io_base) /* + * Already tested + */ if (gus_wave_detect (io_addr)) { printk (" WARNING! GUS found at %x, config was %x ", io_addr, hw_config->io_base); @@ -68,12 +78,17 @@ #ifndef EXCLUDE_MIDI mem_start = gus_midi_init (mem_start); #endif +#ifndef EXCLUDE_SEQUENCER + sound_timer_init (io_addr + 8); +#endif return mem_start; } #endif - return mem_start; /* Not detected */ + return mem_start; /* + * Not detected + */ } int @@ -91,7 +106,9 @@ */ for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10) - if (io_addr != hw_config->io_base) /* Already tested */ + if (io_addr != hw_config->io_base) /* + * Already tested + */ if (gus_wave_detect (io_addr)) return 1; @@ -101,7 +118,7 @@ } void -gusintr (int unit) +gusintr (int irq) { unsigned char src; @@ -109,6 +126,11 @@ sti (); #endif +#ifndef EXCLUDE_GUSMAX + if (have_gus_max) + ad1848_interrupt (irq); +#endif + while (1) { if (!(src = INB (u_IrqStatus))) @@ -128,8 +150,11 @@ if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ)) { - printk ("T"); - gus_write8 (0x45, 0); /* Timer control */ +#ifndef EXCLUDE_SEQUENCER + sound_timer_interrupt (); +#else + gus_write8 (0x45, 0); /* Stop timers */ +#endif } if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ)) @@ -137,6 +162,32 @@ gus_voice_irq (); } } +} + +#endif + +/* + * Some extra code for the 16 bit sampling option + */ +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS16) + +int +probe_gus_db16 (struct address_info *hw_config) +{ + return ad1848_detect (hw_config->io_base); +} + +long +attach_gus_db16 (long mem_start, struct address_info *hw_config) +{ + gus_pcm_volume = 100; + gus_wave_volume = 90; + + ad1848_init ("GUS 16 bit sampling", hw_config->io_base, + hw_config->irq, + hw_config->dma, + hw_config->dma); + return mem_start; } #endif diff -u --recursive --new-file v1.1.30/linux/drivers/sound/gus_midi.c linux/drivers/sound/gus_midi.c --- v1.1.30/linux/drivers/sound/gus_midi.c Sun May 1 12:12:27 1994 +++ linux/drivers/sound/gus_midi.c Mon Jul 18 09:50:55 1994 @@ -79,7 +79,9 @@ gus_midi_control |= MIDI_ENABLE_XMIT; } - OUTB (gus_midi_control, u_MidiControl); /* Enable */ + OUTB (gus_midi_control, u_MidiControl); /* + * Enable + */ midi_busy = 1; qlen = qhead = qtail = output_used = 0; @@ -105,7 +107,9 @@ } else { - /* Enable Midi xmit interrupts (again) */ + /* + * Enable Midi xmit interrupts (again) + */ gus_midi_control |= MIDI_ENABLE_XMIT; OUTB (gus_midi_control, u_MidiControl); } @@ -117,7 +121,9 @@ static void gus_midi_close (int dev) { - /* Reset FIFO pointers, disable intrs */ + /* + * Reset FIFO pointers, disable intrs + */ OUTB (MIDI_RESET, u_MidiControl); midi_busy = 0; @@ -149,14 +155,18 @@ if (!qlen) if (dump_to_midi (midi_byte)) - return 1; /* OK */ + return 1; /* + * OK + */ /* * Put to the local queue */ if (qlen >= 256) - return 0; /* Local queue full */ + return 0; /* + * Local queue full + */ DISABLE_INTR (flags); @@ -213,9 +223,14 @@ return (qlen > 0) | !(GUS_MIDI_STATUS () & MIDI_XMIT_EMPTY); } +#define MIDI_SYNTH_NAME "Gravis Ultrasound Midi" +#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT +#include "midi_synth.h" + static struct midi_operations gus_midi_operations = { - {"Gravis UltraSound", 0, 0, SNDCARD_GUS}, + {"Gravis UltraSound Midi", 0, 0, SNDCARD_GUS}, + &std_midi_synth, gus_midi_open, gus_midi_close, gus_midi_ioctl, @@ -223,16 +238,25 @@ gus_midi_start_read, gus_midi_end_read, gus_midi_kick, - NULL, /* command */ - gus_midi_buffer_status + NULL, /* + * command + */ + gus_midi_buffer_status, + NULL }; long gus_midi_init (long mem_start) { + if (num_midis >= MAX_MIDI_DEV) + { + printk ("Sound: Too many midi devices detected\n"); + return mem_start; + } + OUTB (MIDI_RESET, u_MidiControl); - my_dev = num_midis; + std_midi_synth.midi_dev = my_dev = num_midis; midi_devs[num_midis++] = &gus_midi_operations; return mem_start; } @@ -264,7 +288,9 @@ if (!qlen) { - /* Disable Midi output interrupts, since no data in the buffer */ + /* + * Disable Midi output interrupts, since no data in the buffer + */ gus_midi_control &= ~MIDI_ENABLE_XMIT; OUTB (gus_midi_control, u_MidiControl); } diff -u --recursive --new-file v1.1.30/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c --- v1.1.30/linux/drivers/sound/gus_wave.c Sun May 1 12:12:33 1994 +++ linux/drivers/sound/gus_wave.c Mon Jul 18 09:50:55 1994 @@ -3,7 +3,7 @@ * * Driver for the Gravis UltraSound wave table synth. * - * Copyright by Hannu Savolainen 1993 + * Copyright by Hannu Savolainen 1993, 1994 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -72,23 +72,23 @@ }; +static struct voice_alloc_info *voice_alloc; + extern int gus_base; extern int gus_irq, gus_dma; -extern char *snd_raw_buf[MAX_DSP_DEV][DSP_BUFFCOUNT]; -extern unsigned long snd_raw_buf_phys[MAX_DSP_DEV][DSP_BUFFCOUNT]; -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; 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; int gus_wave_volume = 60; int gus_pcm_volume = 80; +int have_gus_max = 0; +static int gus_line_vol = 100, gus_mic_vol = 0; static unsigned char mix_image = 0x00; /* @@ -97,13 +97,9 @@ */ 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 done ch. 1/2 */ static int gus_sampling_speed; static int gus_sampling_channels; @@ -114,33 +110,13 @@ /* * Variables and buffers for PCM output */ -#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]; /* +#define MAX_PCM_BUFFERS (32*MAX_REALTIME_FACTOR) /* Don't change */ - - * * * * Actual # of bytes - * in blk * */ -static volatile int pcm_head, pcm_tail, pcm_qlen; /* - - - * * * * DRAM queue - * */ +static int pcm_bsize, pcm_nblk, pcm_banksize; +static int pcm_datasize[MAX_PCM_BUFFERS]; +static volatile int pcm_head, pcm_tail, pcm_qlen; static volatile int pcm_active; +static volatile int dma_active; static int pcm_opened = 0; static int pcm_current_dev; static int pcm_current_block; @@ -152,63 +128,25 @@ 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; @@ -231,10 +169,8 @@ 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 /* Instant change. No ramping */ +#define FAST_RAMP 0 /* Fastest possible ramp */ static void reset_sample_memory (void) @@ -248,12 +184,10 @@ for (i = 0; i < 32; i++) patch_map[i] = -1; - gus_poke (0, 0); /* - * Put silence here - */ + gus_poke (0, 0); /* Put a silent sample to the beginning */ gus_poke (1, 0); - free_mem_ptr = 2; + free_sample = 0; for (i = 0; i < MAX_PATCH; i++) @@ -271,7 +205,7 @@ static void gus_poke (long addr, unsigned char data) -{ +{ /* Writes a byte to the DRAM */ unsigned long flags; DISABLE_INTR (flags); @@ -287,7 +221,7 @@ static unsigned char gus_peek (long addr) -{ +{ /* Reads a byte from the DRAM */ unsigned long flags; unsigned char tmp; @@ -306,7 +240,7 @@ void gus_write8 (int reg, unsigned int data) -{ +{ /* Writes to an indirect register (8 bit) */ unsigned long flags; DISABLE_INTR (flags); @@ -319,7 +253,7 @@ unsigned char gus_read8 (int reg) -{ +{ /* Reads from an indirect register (8 bit). Offset 0x80. */ unsigned long flags; unsigned char val; @@ -333,7 +267,7 @@ unsigned char gus_look8 (int reg) -{ +{ /* Reads from an indirect register (8 bit). No additional offset. */ unsigned long flags; unsigned char val; @@ -347,7 +281,7 @@ void gus_write16 (int reg, unsigned int data) -{ +{ /* Writes to an indirect register (16 bit) */ unsigned long flags; DISABLE_INTR (flags); @@ -362,7 +296,7 @@ unsigned short gus_read16 (int reg) -{ +{ /* Reads from an indirect register (16 bit). Offset 0x80. */ unsigned long flags; unsigned char hi, lo; @@ -380,9 +314,11 @@ void gus_write_addr (int reg, unsigned long address, int is16bit) -{ +{ /* Writes an 24 bit memory address */ unsigned long hold_address; + unsigned long flags; + DISABLE_INTR (flags); if (is16bit) { /* @@ -401,6 +337,7 @@ gus_delay (); gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff)); gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff)); + RESTORE_INTR (flags); } static void @@ -420,7 +357,7 @@ if (nvoices > 32) nvoices = 32; - nr_voices = nvoices; + voice_alloc->max_voice = nr_voices = nvoices; gus_write8 (0x0e, (nvoices - 1) | 0xc0); } @@ -444,14 +381,8 @@ { unsigned char mode = (unsigned char) (m & 0xff); - gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc)); /* - * Don't - * start - * or - * stop - * * - * voice - */ + gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | + (mode & 0xfc)); /* Don't touch last two bits */ gus_delay (); gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc)); } @@ -471,9 +402,7 @@ static void gus_voice_volume (unsigned int vol) { - gus_write8 (0x0d, 0x03); /* - * Stop ramp before setting volume - */ + gus_write8 (0x0d, 0x03); /* Stop ramp before setting volume */ gus_write16 (0x09, (unsigned short) (vol << 4)); } @@ -511,14 +440,8 @@ { unsigned char mode = (unsigned char) (m & 0xff); - gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc)); /* - * Don't - * start - * or - * stop - * * - * ramping - */ + gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | + (mode & 0xfc)); /* Leave the last 2 bits alone */ gus_delay (); gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc)); } @@ -551,15 +474,10 @@ 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 */ + voice_alloc->map[voice] = 0; RESTORE_INTR (flags); } @@ -599,17 +517,14 @@ gus_select_voice (voice); gus_rampoff (); RESTORE_INTR (flags); - return; /* - * Sustain - */ - } - - if (voices[voice].env_phase >= 5) - { + return; /* - * Shoot the voice off + * Sustain phase begins. Continue envelope after receiving note off. */ + } + if (voices[voice].env_phase >= 5) + { /* Envelope finished. Shoot the voice down */ gus_voice_init (voice); return; } @@ -626,20 +541,14 @@ gus_voice_volume (prev_vol); - 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 */ { RESTORE_INTR (flags); - step_envelope (voice); /* - * Continue with the next phase - */ + step_envelope (voice); /* Continue the envelope on the next step */ return; } @@ -648,18 +557,14 @@ if (vol >= (4096 - 64)) vol = 4096 - 65; gus_ramp_range (0, vol); - gus_rampon (0x20); /* - * Increasing, irq - */ + gus_rampon (0x20); /* Increasing volume, with IRQ */ } else { if (vol <= 64) vol = 65; gus_ramp_range (vol, 4030); - gus_rampon (0x60); /* - * Decreasing, irq - */ + gus_rampon (0x60); /* Decreasing volume, with IRQ */ } voices[voice].current_volume = vol; RESTORE_INTR (flags); @@ -678,19 +583,13 @@ start_release (int voice, long int flags) { 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 (); @@ -709,18 +608,13 @@ if (instr_no < 0 || instr_no > MAX_SAMPLE) { - gus_write8 (0x00, 0x03); /* - * Hard stop - */ + gus_write8 (0x00, 0x03); /* Hard stop */ + voice_alloc->map[voice] = 0; RESTORE_INTR (flags); 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 bits */ if (voices[voice].mode & WAVE_ENVELOPES) { @@ -731,9 +625,7 @@ /* * Ramp the volume down but not too quickly. */ - if ((gus_read16 (0x09) >> 4) < 100) /* - * Get current volume - */ + if ((int) (gus_read16 (0x09) >> 4) < 100) /* Get current volume */ { gus_voice_off (); gus_rampoff (); @@ -743,9 +635,7 @@ gus_ramp_range (65, 4030); gus_ramp_rate (2, 4); - gus_rampon (0x40 | 0x20); /* - * Down, once, irq - */ + gus_rampon (0x40 | 0x20); /* Down, once, with IRQ */ voices[voice].volume_irq_mode = VMODE_HALT; RESTORE_INTR (flags); } @@ -762,33 +652,24 @@ 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 */ + } static void gus_initialize (void) { unsigned long flags; - register unsigned char dma_image, irq_image, tmp; + unsigned char dma_image, irq_image, tmp; static unsigned char gus_irq_map[16] = {0, 0, 1, 3, 0, 2, 0, 4, 0, 0, 0, 5, 6, 0, 0, 7}; @@ -797,16 +678,11 @@ {0, 1, 0, 2, 0, 3, 4, 5}; 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 (); @@ -814,49 +690,25 @@ * 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 @@ -864,9 +716,7 @@ 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); @@ -888,13 +738,9 @@ if (!tmp) printk ("Warning! GUS IRQ not selected\n"); irq_image |= tmp; - irq_image |= 0x40; /* - * Combine IRQ1 (GF1) and IRQ2 (Midi) - */ + 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"); @@ -908,60 +754,34 @@ * Doing it first time */ - OUTB (mix_image, u_Mixer); /* - * Select DMA control - */ - OUTB (dma_image | 0x80, 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 */ - 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 - */ + 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); } @@ -1068,16 +888,13 @@ 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); + printk ("GUS: Sample #%d not loaded for patch %d (voice %d)\n", + sample_no, instr_no, voice); return RET_ERROR (EINVAL); } @@ -1087,15 +904,12 @@ } 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); + voice_alloc->map[voice] = 0xffff; if (voices[voice].volume_irq_mode == VMODE_START_NOTE) { voices[voice].kill_pending = 1; @@ -1116,26 +930,20 @@ short lo_limit, hi_limit; unsigned long flags; - return; /* - * Currently disabled - */ + return; /* Procedure 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; } @@ -1154,9 +962,7 @@ } gus_ramp_range (lo_limit, hi_limit); gus_ramp_rate (3, 8); - gus_rampon (0x58); /* - * Bidirectional, Down, Loop - */ + gus_rampon (0x58); /* Bidirectional, dow, loop */ RESTORE_INTR (flags); } @@ -1236,9 +1042,7 @@ rate = 16; gus_ramp_rate (0, rate); - if ((target - current) / 64 == 0) /* - * Too close - */ + if ((target - current) / 64 == 0) /* Close enough to target. */ { gus_rampoff (); gus_voice_volume (target); @@ -1251,9 +1055,7 @@ 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 { @@ -1261,9 +1063,7 @@ 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); } @@ -1276,15 +1076,11 @@ DISABLE_INTR (flags); gus_select_voice (voice); - status = gus_read8 (0x00); /* - * Voice status - */ + status = gus_read8 (0x00); /* Get voice status */ RESTORE_INTR (flags); if (status & 0x03) - return; /* - * Voice not started - */ + return; /* Voice was not running */ if (!(voices[voice].mode & WAVE_ENVELOPES)) { @@ -1298,14 +1094,10 @@ 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; @@ -1316,16 +1108,6 @@ compute_volume (voice, voices[voice].midi_volume); -#if 0 /* - * * * Is this really required */ - voices[voice].current_volume = - gus_read16 (0x09) >> 4; /* - * Get current volume - */ - - voices[voice].env_phase--; - step_envelope (voice); -#endif } static void @@ -1344,7 +1126,8 @@ if (voices[voice].volume_irq_mode != VMODE_START_NOTE) { - freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range); + freq = compute_finetune (voices[voice].orig_freq, value, + voices[voice].bender_range); voices[voice].current_freq = freq; DISABLE_INTR (flags); @@ -1357,10 +1140,8 @@ case CTRL_PITCH_BENDER_RANGE: voices[voice].bender_range = value; break; -#ifdef FUTURE_VERSION case CTL_EXPRESSION: value /= 128; -#endif case CTRL_EXPRESSION: if (volume_method == VOL_METHOD_ADAGIO) { @@ -1370,14 +1151,12 @@ } 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: voices[voice].main_vol = value; @@ -1385,9 +1164,7 @@ dynamic_volume_change (voice); break; - default: /* - * Ignore - */ + default: break; } } @@ -1449,7 +1226,8 @@ best_sample = samplep; best_delta = delta_freq; } - if (samples[samplep].low_note <= note_freq && note_freq <= samples[samplep].high_note) + if (samples[samplep].low_note <= note_freq && + note_freq <= samples[samplep].high_note) sample = samplep; else samplep = samples[samplep].key; /* @@ -1462,16 +1240,10 @@ 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; voices[voice].mode = samples[sample].mode; voices[voice].patch_vol = samples[sample].volume; @@ -1488,9 +1260,7 @@ sample_map[voice] = sample; - base_note = samples[sample].base_note / 100; /* - * To avoid overflows - */ + base_note = samples[sample].base_note / 100; /* Try to avoid overflows */ note_freq /= 100; freq = samples[sample].base_freq * note_freq / base_note; @@ -1502,7 +1272,8 @@ * have to calculate the bending now. */ - freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender, voices[voice].bender_range); + freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender, + voices[voice].bender_range); voices[voice].current_freq = freq; pan = (samples[sample].panning + voices[voice].panning) / 32; @@ -1514,9 +1285,7 @@ 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"); @@ -1528,9 +1297,7 @@ DISABLE_INTR (flags); gus_select_voice (voice); - gus_voice_off (); /* - * It may still be running - */ + gus_voice_off (); gus_rampoff (); RESTORE_INTR (flags); @@ -1548,22 +1315,17 @@ if (samples[sample].mode & WAVE_LOOP_BACK) gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].len - - voices[voice].offset_pending, is16bits); /* Sample - * start=end */ + voices[voice].offset_pending, is16bits); /* start=end */ else 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; if (samples[sample].mode & WAVE_BIDIR_LOOP) - mode |= 0x10; /* - * Bidirectional looping on - */ + mode |= 0x10; if (samples[sample].mode & WAVE_LOOP_BACK) { @@ -1573,36 +1335,20 @@ 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 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 - 1, 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); @@ -1613,9 +1359,10 @@ } /* - * * 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. */ + * 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) @@ -1656,7 +1403,7 @@ DISABLE_INTR (flags); } - if ((mode & 0x01) || ((gus_read16 (0x09) >> 4) < 2065)) + if ((mode & 0x01) || (int) ((gus_read16 (0x09) >> 4) < 2065)) { ret_val = guswave_start_note2 (dev, voice, note_num, volume); } @@ -1699,7 +1446,7 @@ gus_initialize (); - if ((err = DMAbuf_open_dma (gus_devnum))) + if ((err = DMAbuf_open_dma (gus_devnum)) < 0) return err; RESET_WAIT_QUEUE (dram_sleeper, dram_sleep_flag); @@ -1731,11 +1478,7 @@ unsigned long blk_size, blk_end, left, src_offs, target; - sizeof_patch = (long) &patch.data[0] - (long) &patch; /* - * Size of - * the header - * * info - */ + sizeof_patch = (long) &patch.data[0] - (long) &patch; /* Header size */ if (format != GUS_PATCH) { @@ -1800,9 +1543,7 @@ } } - free_mem_ptr = (free_mem_ptr + 31) & ~31; /* - * Alignment 32 bytes - */ + free_mem_ptr = (free_mem_ptr + 31) & ~31; /* 32 byte alignment */ #define GUS_BANK_SIZE (256*1024) @@ -1820,17 +1561,13 @@ 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 = /* Aling to 256K */ ((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 */ } } @@ -1863,11 +1600,9 @@ src_offs = 0; target = free_mem_ptr; - while (left) /* - * Not all moved - */ + while (left) /* Not completely transferred yet */ { - blk_size = sound_buffsizes[gus_devnum]; + blk_size = audio_devs[gus_devnum]->buffsize; if (blk_size > left) blk_size = left; @@ -1877,9 +1612,7 @@ blk_end = target + blk_size; if ((target >> 18) != (blk_end >> 18)) - { /* - * Have to split the block - */ + { /* Split the block */ blk_end &= ~(256 * 1024 - 1); blk_size = blk_end - target; @@ -1899,14 +1632,11 @@ if (patch.mode & WAVE_UNSIGNED) if (!(patch.mode & WAVE_16_BITS) || (i & 0x01)) - data ^= 0x80; /* - * Convert to signed - */ + 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; @@ -1916,15 +1646,14 @@ * OK, move now. First in and then out. */ - COPY_FROM_USER (snd_raw_buf[gus_devnum][0], + COPY_FROM_USER (audio_devs[gus_devnum]->dmap->raw_buf[0], addr, sizeof_patch + src_offs, blk_size); 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], + gus_write8 (0x41, 0); /* Disable GF1 DMA */ + DMAbuf_start_dma (gus_devnum, + audio_devs[gus_devnum]->dmap->raw_buf_phys[0], blk_size, DMA_MODE_WRITE); /* @@ -1933,7 +1662,7 @@ address = target; - if (sound_dsp_dmachan[gus_devnum] > 3) + if (audio_devs[gus_devnum]->dmachan > 3) { hold_address = address; address = address >> 1; @@ -1941,33 +1670,21 @@ 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_ - */ - if (sound_dsp_dmachan[gus_devnum] > 3) - dma_command |= 0x04; /* - * 16 bit DMA channel - */ + dma_command |= 0x40; /* 16 bit _DATA_ */ + if (audio_devs[gus_devnum]->dmachan > 3) + dma_command |= 0x04; /* 16 bit DMA _channel_ */ - gus_write8 (0x41, dma_command); /* - * Let's go luteet (=bugs) - */ + gus_write8 (0x41, dma_command); /* Lets bo luteet (=bugs) */ /* * Sleep here until the DRAM DMA done interrupt is served @@ -1979,8 +1696,7 @@ printk ("GUS: DMA Transfer timed out\n"); RESTORE_INTR (flags); } -#endif /* - * * * GUS_NO_DMA */ +#endif /* GUS_NO_DMA */ /* * Now the next part @@ -1990,9 +1706,7 @@ src_offs += blk_size; target += blk_size; - gus_write8 (0x41, 0); /* - * Stop DMA - */ + gus_write8 (0x41, 0); /* Stop DMA */ } free_mem_ptr += patch.len; @@ -2037,9 +1751,7 @@ case _GUS_VOICEON: DISABLE_INTR (flags); gus_select_voice (voice); - p1 &= ~0x20; /* - * Disable intr - */ + p1 &= ~0x20; /* Don't allow interrupts */ gus_voice_on (p1); RESTORE_INTR (flags); break; @@ -2058,9 +1770,7 @@ case _GUS_VOICEMODE: DISABLE_INTR (flags); gus_select_voice (voice); - p1 &= ~0x20; /* - * Disable intr - */ + p1 &= ~0x20; /* Don't allow interrupts */ gus_voice_mode (p1); RESTORE_INTR (flags); break; @@ -2086,18 +1796,14 @@ RESTORE_INTR (flags); break; - case _GUS_VOICEVOL2: /* - * Just update the voice value - */ + case _GUS_VOICEVOL2: /* Just update the software voice level */ 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); @@ -2106,9 +1812,7 @@ case _GUS_RAMPRATE: if (voices[voice].mode & WAVE_ENVELOPES) - break; /* - * NO-NO - */ + break; /* NJET-NJET */ DISABLE_INTR (flags); gus_select_voice (voice); gus_ramp_rate (p1, p2); @@ -2117,37 +1821,27 @@ 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; /* Don't allow interrupts */ gus_ramp_mode (p1); RESTORE_INTR (flags); break; case _GUS_RAMPON: if (voices[voice].mode & WAVE_ENVELOPES) - break; /* - * NO-NO - */ + break; /* EI-EI */ DISABLE_INTR (flags); gus_select_voice (voice); - p1 &= ~0x20; /* - * Disable intr - */ + p1 &= ~0x20; /* Don't allow interrupts */ gus_rampon (p1); RESTORE_INTR (flags); break; case _GUS_RAMPOFF: if (voices[voice].mode & WAVE_ENVELOPES) - break; /* - * NO-NO - */ + break; /* NEJ-NEJ */ DISABLE_INTR (flags); gus_select_voice (voice); gus_rampoff (); @@ -2244,7 +1938,7 @@ return IOCTL_OUT (arg, gus_sampling_channels); break; - case SNDCTL_DSP_SAMPLESIZE: + case SNDCTL_DSP_SETFMT: if (local) return gus_sampling_set_bits (arg); return IOCTL_OUT (arg, gus_sampling_set_bits (IOCTL_IN (arg))); @@ -2255,9 +1949,7 @@ 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 POSSIBLE */ return IOCTL_OUT (arg, RET_ERROR (EINVAL)); break; @@ -2297,6 +1989,7 @@ gus_select_max_voices (14); pcm_active = 0; + dma_active = 0; pcm_opened = 1; if (mode & OPEN_READ) { @@ -2356,24 +2049,18 @@ 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; @@ -2381,23 +2068,15 @@ 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 fragment of the DRAM buffer */ { - mode[chn] |= 0x08; /* - * Enable loop - */ - ramp_mode[chn] = 0x03;/* - * Disable rollover - */ + mode[chn] |= 0x08; /* Enable loop */ + ramp_mode[chn] = 0x03;/* Disable rollover bit */ } else { if (chn == 0) - ramp_mode[chn] = 0x04; /* - * Enable rollover bit - */ + ramp_mode[chn] = 0x04; /* Enable rollover bit */ } DISABLE_INTR (flags); @@ -2405,21 +2084,13 @@ 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) /* Playback not already active */ { /* * The playback was not started yet (or there has been a pause). @@ -2428,67 +2099,42 @@ * the normal loop with irq. */ - gus_voice_off (); /* - * It could already be running - */ + gus_voice_off (); gus_rampoff (); 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 */ 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 looping */ if (pcm_datasize[this_one] != pcm_bsize) { /* - * Incomplete block. Possibly the last one. + * Incompletely filled block. Possibly the last one. */ if (chn == 0) { - mode[chn] &= ~0x08; /* - * Disable loop - */ - mode[chn] |= 0x20;/* - * Enable loop IRQ - */ + mode[chn] &= ~0x08; /* Disable looping */ + mode[chn] |= 0x20;/* Enable IRQ at the end */ 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 looping */ } } @@ -2542,15 +2188,13 @@ 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; address += chn * pcm_banksize; - if (sound_dsp_dmachan[dev] > 3) + if (audio_devs[dev]->dmachan > 3) { hold_address = address; address = address >> 1; @@ -2558,49 +2202,40 @@ 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 - */ + if (audio_devs[dev]->dmachan > 3) + dma_command |= 0x04; /* 16 bit DMA channel */ - gus_write8 (0x41, dma_command); /* - * Kick on - */ + gus_write8 (0x41, dma_command); /* Kickstart */ - if (chn == (gus_sampling_channels - 1)) /* - * Last channel - */ + if (chn == (gus_sampling_channels - 1)) /* Last channel */ { /* * Last (right or mono) channel data */ + dma_active = 1; /* DMA started. There is a unacknowledged buffer */ active_device = GUS_DEV_PCM_DONE; - if (!pcm_active && (pcm_qlen > 2 || count < pcm_bsize)) + if (!pcm_active && (pcm_qlen > 0 || count < pcm_bsize)) { play_next_pcm_block (); } } - else /* - * * * Left channel data. The right channel - * is * * * transferred after DMA interrupt */ - active_device = GUS_DEV_PCM_CONTINUE; + else + { + /* + * Left channel data. The right channel + * is transferred after DMA interrupt + */ + active_device = GUS_DEV_PCM_CONTINUE; + } RESTORE_INTR (flags); } @@ -2627,21 +2262,13 @@ DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); - mode = 0xa0; /* - * DMA IRQ enable, invert MSB - */ + mode = 0xa0; /* DMA IRQ enabled, invert MSB */ - if (sound_dsp_dmachan[dev] > 3) - mode |= 0x04; /* - * 16 bit DMA channel - */ + if (audio_devs[dev]->dmachan > 3) + 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); @@ -2655,9 +2282,7 @@ rate = (9878400 / (gus_sampling_speed + 2)) / 16; - gus_write8 (0x48, rate & 0xff); /* - * Set sampling frequency - */ + gus_write8 (0x48, rate & 0xff); /* Set sampling rate */ if (gus_sampling_bits != 8) { @@ -2700,9 +2325,9 @@ } static int -gus_has_output_drained (int dev) +gus_local_qlen (int dev) { - return !pcm_qlen; + return pcm_qlen; } static void @@ -2760,6 +2385,8 @@ { "Gravis UltraSound", NEEDS_RESTART, + AFMT_U8 | AFMT_S16_LE, + NULL, gus_sampling_open, gus_sampling_close, gus_sampling_output_block, @@ -2769,11 +2396,10 @@ gus_sampling_prepare_for_output, gus_sampling_reset, gus_sampling_reset, - gus_has_output_drained, + gus_local_qlen, gus_copy_from_user }; -#ifdef FUTURE_VERSION static void guswave_bender (int dev, int voice, int value) { @@ -2781,7 +2407,8 @@ unsigned long flags; voices[voice].bender = value - 8192; - freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range); + freq = compute_finetune (voices[voice].orig_freq, value, + voices[voice].bender_range); voices[voice].current_freq = freq; DISABLE_INTR (flags); @@ -2790,8 +2417,6 @@ RESTORE_INTR (flags); } -#endif - static int guswave_patchmgr (int dev, struct patmgr_info *rec) { @@ -2821,9 +2446,7 @@ while (ptr >= 0 && ptr < free_sample) { rec->data.data8[i]++; - ptr = samples[ptr].key; /* - * Follow link - */ + ptr = samples[ptr].key; /* Follow link */ } } return 0; @@ -2838,9 +2461,7 @@ 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; @@ -2860,12 +2481,8 @@ 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 location */ rec->parm2 = sizeof (struct patch_info); } return 0; @@ -2881,14 +2498,10 @@ 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)); @@ -2898,9 +2511,7 @@ 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; @@ -2911,13 +2522,9 @@ 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; /* Num of bytes left */ if (l > n) l = n; @@ -2993,12 +2600,49 @@ } } +static int +guswave_alloc (int dev, int chn, int note, struct voice_alloc_info *alloc) +{ + int i, p; + + p = alloc->ptr; + /* + * First look for a completely stopped voice + */ + + for (i = 0; i < alloc->max_voice; i++) + { + if (alloc->map[p] == 0) + { + alloc->ptr = p; + return p; + } + p = (p + 1) % alloc->max_voice; + } + + /* + * Then look for a releasing voice + */ + + for (i = 0; i < alloc->max_voice; i++) + { + if (alloc->map[p] == 0xffff) + { + alloc->ptr = p; + return p; + } + p = (p + 1) % alloc->max_voice; + } + printk ("GUS: Out of free voices\n"); + + alloc->ptr = p; + return p; +} + static struct synth_operations guswave_operations = { &gus_info, -#ifdef FUTURE_VERSION 0, -#endif SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS, guswave_open, @@ -3015,9 +2659,8 @@ guswave_panning, guswave_volume_method, guswave_patchmgr, -#ifdef FUTURE_VERSION - guswave_bender -#endif + guswave_bender, + guswave_alloc }; static void @@ -3125,10 +2768,7 @@ if (active_device == GUS_DEV_WAVE) for (voice = 0; voice < nr_voices; voice++) - dynamic_volume_change (voice); /* - * Apply the new - * volume - */ + dynamic_volume_change (voice); /* Apply the new vol */ return IOCTL_OUT (arg, gus_wave_volume | (gus_wave_volume << 8)); } @@ -3224,7 +2864,7 @@ val = INB (gus_base + 0x0f); RESTORE_INTR (flags); - if (val != 0xff && (val & 0x06)) /* Should be 0x02? */ + if (val != 0xff && (val & 0x06)) /* Should be 0x02?? */ { /* * It has the digital ASIC so the card is at least v3.4. @@ -3258,6 +2898,31 @@ model_num = "MAX"; gus_type = 0x40; mixer_type = CS4231; +#ifndef EXCLUDE_GUSMAX + { + unsigned char max_config = 0x40; /* Codec enable */ + + if (dma > 3) + max_config |= 0x30; /* 16 bit playback and capture DMAs */ + + max_config |= (gus_base >> 4) & 0x0f; /* Extract the X from 2X0 */ + + OUTB (max_config, gus_base + 0x106); /* UltraMax control */ + } + + if (ad1848_detect (gus_base + 0x10c)) + { + gus_mic_vol = gus_line_vol = gus_pcm_volume = 100; + gus_wave_volume = 90; + have_gus_max = 1; + ad1848_init ("GUS MAX", gus_base + 0x10c, + -irq, + dma, + dma); + } + else + printk ("[Where's the CS4231?]"); +#endif } } else @@ -3295,7 +2960,10 @@ if (num_synths >= MAX_SYNTH_DEV) printk ("GUS Error: Too many synthesizers\n"); else - synth_devs[num_synths++] = &guswave_operations; + { + voice_alloc = &guswave_operations.alloc; + synth_devs[num_synths++] = &guswave_operations; + } PERMANENT_MALLOC (struct patch_info *, samples, (MAX_SAMPLE + 1) * sizeof (*samples), mem_start); @@ -3304,13 +2972,12 @@ gus_initialize (); - if (num_dspdevs < MAX_DSP_DEV) + if (num_audiodevs < MAX_AUDIO_DEV) { - dsp_devs[gus_devnum = num_dspdevs++] = &gus_sampling_operations; - sound_dsp_dmachan[gus_devnum] = dma; - sound_buffcounts[gus_devnum] = 1; - sound_buffsizes[gus_devnum] = DSP_BUFFSIZE; - sound_dma_automode[gus_devnum] = 0; + audio_devs[gus_devnum = num_audiodevs++] = &gus_sampling_operations; + audio_devs[gus_devnum]->dmachan = dma; + audio_devs[gus_devnum]->buffcount = 1; + audio_devs[gus_devnum]->buffsize = DSP_BUFFSIZE; } else printk ("GUS: Too many PCM devices available\n"); @@ -3322,11 +2989,12 @@ switch (mixer_type) { case ICS2101: - gus_line_vol=gus_mic_vol=gus_wave_volume = gus_pcm_volume = 100; + gus_mic_vol = gus_line_vol = gus_pcm_volume = 100; + gus_wave_volume = 90; return ics2101_mixer_init (mem_start); case CS4231: - /* Available soon */ + /* Initialized elsewhere (ad1848.c) */ default: return gus_default_mixer_init (mem_start); } @@ -3361,7 +3029,7 @@ * Final loop finished, shoot volume down */ - if ((gus_read16 (0x09) >> 4) < 100) /* + if ((int) (gus_read16 (0x09) >> 4) < 100) /* * Get current volume */ { @@ -3381,12 +3049,11 @@ break; case LMODE_PCM_STOP: - pcm_active = 0; /* - * Requires extensive processing - */ + pcm_active = 0; /* Signal to the play_next_pcm_block routine */ case LMODE_PCM: { int orig_qlen = pcm_qlen; + int flag; /* 0 or 2 */ pcm_qlen--; pcm_head = (pcm_head + 1) % pcm_nblk; @@ -3395,18 +3062,27 @@ play_next_pcm_block (); } else - { /* - * Out of data. Just stop the voice - */ + { /* Underrun. Just stop the voice */ gus_voice_off (); gus_rampoff (); pcm_active = 0; } - if (orig_qlen == pcm_nblk) + /* + * If the queue was full before this interrupt, the DMA transfer was + * suspended. Let it continue now. + */ + if (dma_active) { - DMAbuf_outputintr (gus_devnum, 0); + if (pcm_qlen == 0) + flag = 1; /* Underflow */ + else + flag = 0; + dma_active = 0; } + else + flag = 2; /* Just notify the dmabuf.c */ + DMAbuf_outputintr (gus_devnum, flag); } break; @@ -3456,7 +3132,9 @@ 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); + guswave_kill_note (voices[voice].dev_pending, voice, + voices[voice].note_pending, 0); + if (voices[voice].sample_pending >= 0) { guswave_set_instr (voices[voice].dev_pending, voice, @@ -3495,7 +3173,7 @@ if (!(src & 0x80)) /* * Wave IRQ pending */ - if (!(wave_ignore & voice_bit) && voice < nr_voices) /* + if (!(wave_ignore & voice_bit) && (int) voice < nr_voices) /* * Not done * yet */ @@ -3507,7 +3185,7 @@ if (!(src & 0x40)) /* * Volume IRQ pending */ - if (!(volume_ignore & voice_bit) && voice < nr_voices) /* + if (!(volume_ignore & voice_bit) && (int) voice < nr_voices) /* * Not done * yet */ @@ -3523,12 +3201,8 @@ { 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 interrupt pending */ switch (active_device) { case GUS_DEV_WAVE: @@ -3536,16 +3210,21 @@ WAKE_UP (dram_sleeper, dram_sleep_flag); break; - case GUS_DEV_PCM_CONTINUE: + case GUS_DEV_PCM_CONTINUE: /* Left channel data transferred */ gus_transfer_output_block (pcm_current_dev, pcm_current_buf, pcm_current_count, pcm_current_intrflag, 1); break; - case GUS_DEV_PCM_DONE: + case GUS_DEV_PCM_DONE: /* Right or mono channel data transferred */ if (pcm_qlen < pcm_nblk) { - DMAbuf_outputintr (gus_devnum, pcm_qlen == 0); + int flag = (1 - dma_active) * 2; /* 0 or 2 */ + + if (pcm_qlen == 0) + flag = 1; /* Underrun */ + dma_active = 0; + DMAbuf_outputintr (gus_devnum, flag); } break; diff -u --recursive --new-file v1.1.30/linux/drivers/sound/ics2101.c linux/drivers/sound/ics2101.c --- v1.1.30/linux/drivers/sound/ics2101.c Sun May 1 12:12:33 1994 +++ linux/drivers/sound/ics2101.c Mon Jul 18 09:50:55 1994 @@ -44,34 +44,36 @@ static int right_fix[ICS_MIXDEVS] = {2, 2, 2, 1, 2, 1}; -static int -scale_vol(int vol) +static int +scale_vol (int vol) { #if 1 -/* + /* * Experimental volume scaling by Risto Kankkunen. * This should give smoother volume response than just * a plain multiplication. */ - int e; + int e; - if (vol < 0) - vol = 0; - if (vol > 100) - vol = 100; - vol = (31 * vol + 50) / 100; - e = 0; - if (vol) { - while (vol < 16) { - vol <<= 1; - e--; - } - vol -= 16; - e += 7; - } - return ((e << 4) + vol); + if (vol < 0) + vol = 0; + if (vol > 100) + vol = 100; + vol = (31 * vol + 50) / 100; + e = 0; + if (vol) + { + while (vol < 16) + { + vol <<= 1; + e--; + } + vol -= 16; + e += 7; + } + return ((e << 4) + vol); #else - return ((vol*127)+50)/100; + return ((vol * 127) + 50) / 100; #endif } @@ -83,7 +85,7 @@ int ctrl_addr = dev << 3; int attn_addr = dev << 3; - vol=scale_vol(vol); + vol = scale_vol (vol); if (chn == CHN_LEFT) { @@ -180,7 +182,7 @@ case SOUND_MIXER_STEREODEVS: return IOCTL_OUT (arg, SOUND_MASK_LINE | SOUND_MASK_CD | - SOUND_MASK_SYNTH | SOUND_MASK_VOLUME| + SOUND_MASK_SYNTH | SOUND_MASK_VOLUME | SOUND_MASK_MIC); break; diff -u --recursive --new-file v1.1.30/linux/drivers/sound/midi_ctrl.h linux/drivers/sound/midi_ctrl.h --- v1.1.30/linux/drivers/sound/midi_ctrl.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/midi_ctrl.h Mon Jul 18 09:50:55 1994 @@ -0,0 +1,22 @@ +static unsigned char ctrl_def_values[128] = +{ + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 0 to 7 */ + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 8 to 15 */ + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 16 to 23 */ + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 24 to 31 */ + + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 32 to 39 */ + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 40 to 47 */ + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 48 to 55 */ + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 56 to 63 */ + + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 64 to 71 */ + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 72 to 79 */ + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 80 to 87 */ + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 88 to 95 */ + + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 96 to 103 */ + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 104 to 111 */ + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 112 to 119 */ + 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, /* 120 to 127 */ +}; diff -u --recursive --new-file v1.1.30/linux/drivers/sound/midi_synth.c linux/drivers/sound/midi_synth.c --- v1.1.30/linux/drivers/sound/midi_synth.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/midi_synth.c Mon Jul 18 09:50:55 1994 @@ -0,0 +1,474 @@ +/* + * sound/midi_synth.c + * + * High level midi sequencer manager for dumb MIDI interfaces. + * + * 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_MIDI) + +#define _MIDI_SYNTH_C_ + +DEFINE_WAIT_QUEUE (sysex_sleeper, sysex_sleep_flag); + +#include "midi_synth.h" + +static int midi2synth[MAX_MIDI_DEV]; +static unsigned char prev_out_status[MAX_MIDI_DEV]; + +static void +midi_outc (int midi_dev, int data) +{ + int timeout; + + for (timeout = 0; timeout < 32000; timeout++) + if (midi_devs[midi_dev]->putc (midi_dev, (unsigned char) (data & 0xff))) + { + if (data & 0x80) /* + * Status byte + */ + prev_out_status[midi_dev] = + (unsigned char) (data & 0xff); /* + * Store for running status + */ + return; /* + * Mission complete + */ + } + + /* + * Sorry! No space on buffers. + */ + printk ("Midi send timed out\n"); +} + +static int +prefix_cmd (int midi_dev, unsigned char status) +{ + if (midi_devs[midi_dev]->prefix_cmd == NULL) + return 1; + + return midi_devs[midi_dev]->prefix_cmd (midi_dev, status); +} + +static void +midi_synth_input (int dev, unsigned char data) +{ + int orig_dev; + + if (dev < 0 || dev > num_synths) + return; + + if (data == 0xfe) /* Ignore active sensing */ + return; + + orig_dev = midi2synth[dev]; + +} + +static void +midi_synth_output (int dev) +{ + /* + * Currently NOP + */ +} + +int +midi_synth_ioctl (int dev, + unsigned int cmd, unsigned int arg) +{ + /* + * int orig_dev = synth_devs[dev]->midi_dev; + */ + + switch (cmd) + { + + case SNDCTL_SYNTH_INFO: + IOCTL_TO_USER ((char *) arg, 0, synth_devs[dev]->info, + sizeof (struct synth_info)); + + return 0; + break; + + case SNDCTL_SYNTH_MEMAVL: + return 0x7fffffff; + break; + + default: + return RET_ERROR (EINVAL); + } +} + +int +midi_synth_kill_note (int dev, int channel, int note, int velocity) +{ + int orig_dev = synth_devs[dev]->midi_dev; + int msg, chn; + + if (note < 0 || note > 127) + return 0; + if (channel < 0 || channel > 15) + return 0; + if (velocity < 0) + velocity = 0; + if (velocity > 127) + velocity = 127; + + msg = prev_out_status[orig_dev] & 0xf0; + chn = prev_out_status[orig_dev] & 0x0f; + + if (chn == channel && ((msg == 0x90 && velocity == 64) || msg == 0x80)) + { /* + * Use running status + */ + if (!prefix_cmd (orig_dev, note)) + return 0; + + midi_outc (orig_dev, note); + + if (msg == 0x90) /* + * Running status = Note on + */ + midi_outc (orig_dev, 0);/* + * Note on with velocity 0 == note + * off + */ + else + midi_outc (orig_dev, velocity); + } + else + { + if (velocity == 64) + { + if (!prefix_cmd (orig_dev, 0x90 | (channel & 0x0f))) + return 0; + midi_outc (orig_dev, 0x90 | (channel & 0x0f)); /* + * Note on + */ + midi_outc (orig_dev, note); + midi_outc (orig_dev, 0); /* + * Zero G + */ + } + else + { + if (!prefix_cmd (orig_dev, 0x80 | (channel & 0x0f))) + return 0; + midi_outc (orig_dev, 0x80 | (channel & 0x0f)); /* + * Note off + */ + midi_outc (orig_dev, note); + midi_outc (orig_dev, velocity); + } + } + + return 0; +} + +int +midi_synth_set_instr (int dev, int channel, int instr_no) +{ + int orig_dev = synth_devs[dev]->midi_dev; + + if (instr_no < 0 || instr_no > 127) + return 0; + if (channel < 0 || channel > 15) + return 0; + + if (!prefix_cmd (orig_dev, 0xc0 | (channel & 0x0f))) + return 0; + midi_outc (orig_dev, 0xc0 | (channel & 0x0f)); /* + * Program change + */ + midi_outc (orig_dev, instr_no); + + return 0; +} + +int +midi_synth_start_note (int dev, int channel, int note, int velocity) +{ + int orig_dev = synth_devs[dev]->midi_dev; + int msg, chn; + + if (note < 0 || note > 127) + return 0; + if (channel < 0 || channel > 15) + return 0; + if (velocity < 0) + velocity = 0; + if (velocity > 127) + velocity = 127; + + msg = prev_out_status[orig_dev] & 0xf0; + chn = prev_out_status[orig_dev] & 0x0f; + + if (chn == channel && msg == 0x90) + { /* + * Use running status + */ + if (!prefix_cmd (orig_dev, note)) + return 0; + midi_outc (orig_dev, note); + midi_outc (orig_dev, velocity); + } + else + { + if (!prefix_cmd (orig_dev, 0x90 | (channel & 0x0f))) + return 0; + midi_outc (orig_dev, 0x90 | (channel & 0x0f)); /* + * Note on + */ + midi_outc (orig_dev, note); + midi_outc (orig_dev, velocity); + } + return 0; +} + +void +midi_synth_reset (int dev) +{ +} + +int +midi_synth_open (int dev, int mode) +{ + int orig_dev = synth_devs[dev]->midi_dev; + int err; + + if (orig_dev < 0 || orig_dev > num_midis) + return RET_ERROR (ENXIO); + + midi2synth[orig_dev] = dev; + prev_out_status[orig_dev] = 0; + + if ((err = midi_devs[orig_dev]->open (orig_dev, mode, + midi_synth_input, midi_synth_output)) < 0) + return err; + + return 1; +} + +void +midi_synth_close (int dev) +{ + int orig_dev = synth_devs[dev]->midi_dev; + + /* + * Shut up the synths by sending just single active sensing message. + */ + midi_devs[orig_dev]->putc (orig_dev, 0xfe); + + midi_devs[orig_dev]->close (orig_dev); +} + +void +midi_synth_hw_control (int dev, unsigned char *event) +{ +} + +int +midi_synth_load_patch (int dev, int format, snd_rw_buf * addr, + int offs, int count, int pmgr_flag) +{ + int orig_dev = synth_devs[dev]->midi_dev; + + struct sysex_info sysex; + int i; + unsigned long left, src_offs, eox_seen = 0; + int first_byte = 1; + + if (!prefix_cmd (orig_dev, 0xf0)) + return 0; + + if (format != SYSEX_PATCH) + { + printk ("MIDI Error: Invalid patch format (key) 0x%x\n", format); + return RET_ERROR (EINVAL); + } + + if (count < sizeof (struct sysex_info)) + { + printk ("MIDI Error: Patch header too short\n"); + return RET_ERROR (EINVAL); + } + + count -= sizeof (struct sysex_info); + + /* + * Copy the header from user space but ignore the first bytes which have + * been transferred already. + */ + + COPY_FROM_USER (&((char *) &sysex)[offs], addr, offs, sizeof (struct sysex_info) - offs); + + if (count < sysex.len) + { + printk ("MIDI Warning: Sysex record too short (%d<%d)\n", + count, (int) sysex.len); + sysex.len = count; + } + + left = sysex.len; + src_offs = 0; + + RESET_WAIT_QUEUE (sysex_sleeper, sysex_sleep_flag); + + for (i = 0; i < left && !PROCESS_ABORTING (sysex_sleeper, sysex_sleep_flag); i++) + { + unsigned char data; + + GET_BYTE_FROM_USER (data, addr, sizeof (struct sysex_info) + i); + + if (first_byte && data != 0xf0) + midi_outc (orig_dev, 0xf0); /* Sysex start */ + + eox_seen = (data == 0xf7);/* + * Last byte was end of sysex + */ + + if (i == 0) + { + if (data != 0xf0) /* + * Sysex start + */ + return RET_ERROR (EINVAL); + } + + while (!midi_devs[orig_dev]->putc (orig_dev, (unsigned char) (data & 0xff)) && + !PROCESS_ABORTING (sysex_sleeper, sysex_sleep_flag)) + DO_SLEEP (sysex_sleeper, sysex_sleep_flag, 1); /* Wait for timeout */ + + if (!first_byte && data & 0x80) + return 0; + first_byte = 0; + } + + if (!eox_seen) + midi_outc (orig_dev, 0xf7); + return 0; +} + +void +midi_synth_panning (int dev, int channel, int pressure) +{ +} + +void +midi_synth_aftertouch (int dev, int channel, int pressure) +{ + int orig_dev = synth_devs[dev]->midi_dev; + int msg, chn; + + if (pressure < 0 || pressure > 127) + return; + if (channel < 0 || channel > 15) + return; + + msg = prev_out_status[orig_dev] & 0xf0; + chn = prev_out_status[orig_dev] & 0x0f; + + if (msg != 0xd0 || chn != channel) /* + * Test for running status + */ + { + if (!prefix_cmd (orig_dev, 0xd0 | (channel & 0x0f))) + return; + midi_outc (orig_dev, 0xd0 | (channel & 0x0f)); /* + * Channel pressure + */ + } + else if (!prefix_cmd (orig_dev, pressure)) + return; + midi_outc (orig_dev, pressure); +} + +void +midi_synth_controller (int dev, int channel, int ctrl_num, int value) +{ + int orig_dev = synth_devs[dev]->midi_dev; + int chn, msg; + + if (ctrl_num < 1 || ctrl_num > 127) + return; /* NOTE! Controller # 0 ignored */ + if (channel < 0 || channel > 15) + return; + + msg = prev_out_status[orig_dev] & 0xf0; + chn = prev_out_status[orig_dev] & 0x0f; + + if (msg != 0xb0 || chn != channel) + { + if (!prefix_cmd (orig_dev, 0xb0 | (channel & 0x0f))) + return; + midi_outc (orig_dev, 0xb0 | (channel & 0x0f)); + } + else if (!prefix_cmd (orig_dev, ctrl_num)) + return; + + midi_outc (orig_dev, ctrl_num); + midi_outc (orig_dev, value & 0x7f); +} + +int +midi_synth_patchmgr (int dev, struct patmgr_info *rec) +{ + return RET_ERROR (EINVAL); +} + +void +midi_synth_bender (int dev, int channel, int value) +{ + int orig_dev = synth_devs[dev]->midi_dev; + int msg, prev_chn; + + if (channel < 0 || channel > 15) + return; + + if (value < 0 || value > 16383) + return; + + msg = prev_out_status[orig_dev] & 0xf0; + prev_chn = prev_out_status[orig_dev] & 0x0f; + + if (msg != 0xd0 || prev_chn != channel) /* + * * Test for running status */ + { + if (!prefix_cmd (orig_dev, 0xe0 | (channel & 0x0f))) + return; + midi_outc (orig_dev, 0xe0 | (channel & 0x0f)); + } + else if (!prefix_cmd (orig_dev, value & 0x7f)) + return; + + midi_outc (orig_dev, value & 0x7f); + midi_outc (orig_dev, (value >> 7) & 0x7f); +} + +#endif diff -u --recursive --new-file v1.1.30/linux/drivers/sound/midi_synth.h linux/drivers/sound/midi_synth.h --- v1.1.30/linux/drivers/sound/midi_synth.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/midi_synth.h Mon Jul 18 09:50:55 1994 @@ -0,0 +1,45 @@ +int midi_synth_ioctl (int dev, + unsigned int cmd, unsigned int arg); +int midi_synth_kill_note (int dev, int channel, int note, int velocity); +int midi_synth_set_instr (int dev, int channel, int instr_no); +int midi_synth_start_note (int dev, int channel, int note, int volume); +void midi_synth_reset (int dev); +int midi_synth_open (int dev, int mode); +void midi_synth_close (int dev); +void midi_synth_hw_control (int dev, unsigned char *event); +int midi_synth_load_patch (int dev, int format, snd_rw_buf * addr, + int offs, int count, int pmgr_flag); +void midi_synth_panning (int dev, int channel, int pressure); +void midi_synth_aftertouch (int dev, int channel, int pressure); +void midi_synth_controller (int dev, int channel, int ctrl_num, int value); +int midi_synth_patchmgr (int dev, struct patmgr_info *rec); +void midi_synth_bender (int dev, int chn, int value); + + +#ifndef _MIDI_SYNTH_C_ +static struct synth_info std_synth_info = +{MIDI_SYNTH_NAME, 0, SYNTH_TYPE_MIDI, 0, 0, 128, 0, 128, MIDI_SYNTH_CAPS}; + +static struct synth_operations std_midi_synth = +{ + &std_synth_info, + 0, + SYNTH_TYPE_MIDI, + 0, + midi_synth_open, + midi_synth_close, + midi_synth_ioctl, + midi_synth_kill_note, + midi_synth_start_note, + midi_synth_set_instr, + midi_synth_reset, + midi_synth_hw_control, + midi_synth_load_patch, + midi_synth_aftertouch, + midi_synth_controller, + midi_synth_panning, + NULL, + midi_synth_patchmgr, + midi_synth_bender +}; +#endif diff -u --recursive --new-file v1.1.30/linux/drivers/sound/midibuf.c linux/drivers/sound/midibuf.c --- v1.1.30/linux/drivers/sound/midibuf.c Sun May 1 12:12:34 1994 +++ linux/drivers/sound/midibuf.c Mon Jul 18 09:50:55 1994 @@ -1,10 +1,8 @@ /* * sound/midibuf.c * - * Device file manager for /dev/midi + * Device file manager for /dev/midi# * - * NOTE! This part of the driver is currently just a stub. - * * Copyright by Hannu Savolainen 1993 * * Redistribution and use in source and binary forms, with or without @@ -31,88 +29,410 @@ #include "sound_config.h" -#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MPU401) +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MIDI) + +/* + * Don't make MAX_QUEUE_SIZE larger than 4000 + */ + +#define MAX_QUEUE_SIZE 4000 + +DEFINE_WAIT_QUEUES (midi_sleeper[MAX_MIDI_DEV], midi_sleep_flag[MAX_MIDI_DEV]); +DEFINE_WAIT_QUEUES (input_sleeper[MAX_MIDI_DEV], input_sleep_flag[MAX_MIDI_DEV]); + +struct midi_buf + { + int len, head, tail; + unsigned char queue[MAX_QUEUE_SIZE]; + }; + +struct midi_parms + { + int prech_timeout; /* + * Timeout before the first ch + */ + }; + +static struct midi_buf *midi_out_buf[MAX_MIDI_DEV] = +{NULL}; +static struct midi_buf *midi_in_buf[MAX_MIDI_DEV] = +{NULL}; +static struct midi_parms parms[MAX_MIDI_DEV]; + +static void midi_poll (unsigned long dummy); + +DEFINE_TIMER (poll_timer, midi_poll); +static volatile int open_devs = 0; + +#define DATA_AVAIL(q) (q->len) +#define SPACE_AVAIL(q) (MAX_QUEUE_SIZE - q->len) + +#define QUEUE_BYTE(q, data) \ + if (SPACE_AVAIL(q)) \ + { \ + unsigned long flags; \ + DISABLE_INTR(flags); \ + q->queue[q->tail] = (data); \ + q->len++; q->tail = (q->tail+1) % MAX_QUEUE_SIZE; \ + RESTORE_INTR(flags); \ + } + +#define REMOVE_BYTE(q, data) \ + if (DATA_AVAIL(q)) \ + { \ + unsigned long flags; \ + DISABLE_INTR(flags); \ + data = q->queue[q->head]; \ + q->len--; q->head = (q->head+1) % MAX_QUEUE_SIZE; \ + RESTORE_INTR(flags); \ + } + +void +drain_midi_queue (int dev) +{ + + /* + * Give the Midi driver time to drain its output queues + */ + + if (midi_devs[dev]->buffer_status != NULL) + while (!PROCESS_ABORTING (midi_sleeper[dev], midi_sleep_flag[dev]) && + midi_devs[dev]->buffer_status (dev)) + DO_SLEEP (midi_sleeper[dev], midi_sleep_flag[dev], HZ / 10); +} + +static void +midi_input_intr (int dev, unsigned char data) +{ + if (midi_in_buf[dev] == NULL) + return; + + if (data == 0xfe) /* + * Active sensing + */ + return; /* + * Ignore + */ + + if (SPACE_AVAIL (midi_in_buf[dev])) + { + QUEUE_BYTE (midi_in_buf[dev], data); + if (SOMEONE_WAITING (input_sleeper[dev], input_sleep_flag[dev])) + WAKE_UP (input_sleeper[dev], input_sleep_flag[dev]); + } + +} + +static void +midi_output_intr (int dev) +{ + /* + * Currently NOP + */ +} -#if 0 -#include "midiioctl.h" -#include "midivar.h" -#endif +static void +midi_poll (unsigned long dummy) +{ + unsigned long flags; + int dev; -static int midibuf_busy = 0; + DISABLE_INTR (flags); + if (open_devs) + { + for (dev = 0; dev < num_midis; dev++) + if (midi_out_buf[dev] != NULL) + { + while (DATA_AVAIL (midi_out_buf[dev]) && + midi_devs[dev]->putc (dev, + midi_out_buf[dev]->queue[midi_out_buf[dev]->head])) + { + midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE; + midi_out_buf[dev]->len--; + } + + if (DATA_AVAIL (midi_out_buf[dev]) < 100 && + SOMEONE_WAITING (midi_sleeper[dev], midi_sleep_flag[dev])) + WAKE_UP (midi_sleeper[dev], midi_sleep_flag[dev]); + } + ACTIVATE_TIMER (poll_timer, midi_poll, 1); /* + * Come back later + */ + } + RESTORE_INTR (flags); +} int MIDIbuf_open (int dev, struct fileinfo *file) { int mode, err; + unsigned long flags; dev = dev >> 4; mode = file->mode & O_ACCMODE; - if (midibuf_busy) - return RET_ERROR (EBUSY); + if (num_midis > MAX_MIDI_DEV) + { + printk ("Sound: FATAL ERROR: Too many midi interfaces\n"); + num_midis = MAX_MIDI_DEV; + } - if (!mpu401_dev) + if (dev < 0 || dev >= num_midis) { - printk ("Midi: MPU-401 compatible Midi interface not present\n"); + printk ("Sound: Nonexistent MIDI interface %d\n", dev); return RET_ERROR (ENXIO); } - if ((err = midi_devs[mpu401_dev]->open (mpu401_dev, mode, NULL, NULL)) < 0) - return err; + /* + * Interrupts disabled. Be careful + */ + + DISABLE_INTR (flags); + if ((err = midi_devs[dev]->open (dev, mode, + midi_input_intr, midi_output_intr)) < 0) + { + RESTORE_INTR (flags); + return err; + } + + parms[dev].prech_timeout = 0; + + RESET_WAIT_QUEUE (midi_sleeper[dev], midi_sleep_flag[dev]); + RESET_WAIT_QUEUE (input_sleeper[dev], input_sleep_flag[dev]); + + midi_in_buf[dev] = (struct midi_buf *) KERNEL_MALLOC (sizeof (struct midi_buf)); + + if (midi_in_buf[dev] == NULL) + { + printk ("midi: Can't allocate buffer\n"); + midi_devs[dev]->close (dev); + RESTORE_INTR (flags); + return RET_ERROR (EIO); + } + midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0; + + midi_out_buf[dev] = (struct midi_buf *) KERNEL_MALLOC (sizeof (struct midi_buf)); - midibuf_busy = 1; + if (midi_out_buf[dev] == NULL) + { + printk ("midi: Can't allocate buffer\n"); + midi_devs[dev]->close (dev); + KERNEL_FREE (midi_in_buf[dev]); + midi_in_buf[dev] = NULL; + RESTORE_INTR (flags); + return RET_ERROR (EIO); + } + midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0; + if (!open_devs) + ACTIVATE_TIMER (poll_timer, midi_poll, 1); /* + * Come back later + */ + open_devs++; + RESTORE_INTR (flags); - return RET_ERROR (ENXIO); + return err; } void MIDIbuf_release (int dev, struct fileinfo *file) { int mode; + unsigned long flags; dev = dev >> 4; mode = file->mode & O_ACCMODE; - midi_devs[mpu401_dev]->close (mpu401_dev); - midibuf_busy = 0; + DISABLE_INTR (flags); + + /* + * Wait until the queue is empty + */ + + if (mode != OPEN_READ) + { + midi_devs[dev]->putc (dev, 0xfe); /* + * Active sensing to shut the + * devices + */ + + while (!PROCESS_ABORTING (midi_sleeper[dev], midi_sleep_flag[dev]) && + DATA_AVAIL (midi_out_buf[dev])) + DO_SLEEP (midi_sleeper[dev], midi_sleep_flag[dev], 0); /* + * Sync + */ + + drain_midi_queue (dev); /* + * Ensure the output queues are empty + */ + } + + midi_devs[dev]->close (dev); + KERNEL_FREE (midi_in_buf[dev]); + KERNEL_FREE (midi_out_buf[dev]); + midi_in_buf[dev] = NULL; + midi_out_buf[dev] = NULL; + open_devs--; + RESTORE_INTR (flags); } int MIDIbuf_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) { + unsigned long flags; + int c, n, i; + unsigned char tmp_data; dev = dev >> 4; - return count; + if (!count) + return 0; + + DISABLE_INTR (flags); + + c = 0; + + while (c < count) + { + n = SPACE_AVAIL (midi_out_buf[dev]); + + if (n == 0) /* + * No space just now. We have to sleep + */ + { + DO_SLEEP (midi_sleeper[dev], midi_sleep_flag[dev], 0); + if (PROCESS_ABORTING (midi_sleeper[dev], midi_sleep_flag[dev])) + { + RESTORE_INTR (flags); + return RET_ERROR (EINTR); + } + + n = SPACE_AVAIL (midi_out_buf[dev]); + } + + if (n > (count - c)) + n = count - c; + + for (i = 0; i < n; i++) + { + COPY_FROM_USER (&tmp_data, buf, c, 1); + QUEUE_BYTE (midi_out_buf[dev], tmp_data); + c++; + } + } + + RESTORE_INTR (flags); + + return c; } int MIDIbuf_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) { + int n, c = 0; + unsigned long flags; + unsigned char tmp_data; + dev = dev >> 4; - return RET_ERROR (EIO); + DISABLE_INTR (flags); + + if (!DATA_AVAIL (midi_in_buf[dev])) /* + * No data yet, wait + */ + { + DO_SLEEP (input_sleeper[dev], input_sleep_flag[dev], + parms[dev].prech_timeout); + if (PROCESS_ABORTING (input_sleeper[dev], input_sleep_flag[dev])) + c = RET_ERROR (EINTR); /* + * The user is getting restless + */ + } + + if (c == 0 && DATA_AVAIL (midi_in_buf[dev])) /* + * Got some bytes + */ + { + n = DATA_AVAIL (midi_in_buf[dev]); + if (n > count) + n = count; + c = 0; + + while (c < n) + { + REMOVE_BYTE (midi_in_buf[dev], tmp_data); + COPY_TO_USER (buf, c, &tmp_data, 1); + c++; + } + } + + RESTORE_INTR (flags); + + return c; } int MIDIbuf_ioctl (int dev, struct fileinfo *file, unsigned int cmd, unsigned int arg) { + int val; + dev = dev >> 4; switch (cmd) { + case SNDCTL_MIDI_PRETIME: + val = IOCTL_IN (arg); + if (val < 0) + val = 0; + + val = (HZ * val) / 10; + parms[dev].prech_timeout = val; + return IOCTL_OUT (arg, val); + break; + default: - return midi_devs[0]->ioctl (dev, cmd, arg); + return midi_devs[dev]->ioctl (dev, cmd, arg); } } -void -MIDIbuf_bytes_received (int dev, unsigned char *buf, int count) +#ifdef ALLOW_SELECT +int +MIDIbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wait) { + dev = dev >> 4; + + switch (sel_type) + { + case SEL_IN: + if (!DATA_AVAIL (midi_in_buf[dev])) + { + input_sleep_flag[dev].mode = WK_SLEEP; + select_wait (&input_sleeper[dev], wait); + return 0; + } + return 1; + break; + + case SEL_OUT: + if (SPACE_AVAIL (midi_out_buf[dev])) + { + midi_sleep_flag[dev].mode = WK_SLEEP; + select_wait (&midi_sleeper[dev], wait); + return 0; + } + return 1; + break; + + case SEL_EX: + return 0; + } + + return 0; } + +#endif /* ALLOW_SELECT */ long MIDIbuf_init (long mem_start) diff -u --recursive --new-file v1.1.30/linux/drivers/sound/mpu401.c linux/drivers/sound/mpu401.c --- v1.1.30/linux/drivers/sound/mpu401.c Sun May 1 12:12:34 1994 +++ linux/drivers/sound/mpu401.c Mon Jul 18 09:50:55 1994 @@ -3,8 +3,6 @@ * * The low level driver for Roland MPU-401 compatible Midi cards. * - * This version supports just the DUMB UART mode. - * * Copyright by Hannu Savolainen 1993 * * Redistribution and use in source and binary forms, with or without @@ -29,48 +27,486 @@ * */ +#define USE_SEQ_MACROS +#define USE_SIMPLE_MACROS + #include "sound_config.h" #ifdef CONFIGURE_SOUNDCARD #if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI) -#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 */ - -#define mpu401_status() INB(STATPORT) -#define input_avail() (!(mpu401_status()&INPUT_AVAIL)) -#define output_ready() (!(mpu401_status()&OUTPUT_READY)) -#define mpu401_cmd(cmd) OUTB(cmd, COMDPORT) -#define mpu401_read() INB(DATAPORT) -#define mpu401_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 mpu401_opened = 0; -static int mpu401_base = 0x330; -static int mpu401_irq; -static int mpu401_detected = 0; -static int my_dev; +static int init_sequence[20]; /* NOTE! pos 0 = len, start pos 1. */ +static int timer_mode = TMR_INTERNAL, timer_caps = TMR_INTERNAL; + +struct mpu_config + { + int base; /* + * I/O base + */ + int irq; + int opened; /* + * Open mode + */ + int devno; + int synthno; + int uart_mode; + int initialized; + int mode; +#define MODE_MIDI 1 +#define MODE_SYNTH 2 + unsigned char version, revision; + unsigned int capabilities; +#define MPU_CAP_INTLG 0x10000000 +#define MPU_CAP_SYNC 0x00000010 +#define MPU_CAP_FSK 0x00000020 +#define MPU_CAP_CLS 0x00000040 +#define MPU_CAP_SMPTE 0x00000080 +#define MPU_CAP_2PORT 0x00000001 + int timer_flag; + +#define MBUF_MAX 10 +#define BUFTEST(dc) if (dc->m_ptr >= MBUF_MAX || dc->m_ptr < 0) \ + {printk("MPU: Invalid buffer pointer %d/%d, s=%d\n", dc->m_ptr, dc->m_left, dc->m_state);dc->m_ptr--;} + int m_busy; + unsigned char m_buf[MBUF_MAX]; + int m_ptr; + int m_state; + int m_left; + unsigned char last_status; + void (*inputintr) (int dev, unsigned char data); + unsigned short controls[32]; + }; + +#define DATAPORT(base) (base) +#define COMDPORT(base) (base+1) +#define STATPORT(base) (base+1) + +#define mpu401_status(base) INB(STATPORT(base)) +#define input_avail(base) (!(mpu401_status(base)&INPUT_AVAIL)) +#define output_ready(base) (!(mpu401_status(base)&OUTPUT_READY)) +#define write_command(base, cmd) OUTB(cmd, COMDPORT(base)) +#define read_data(base) INB(DATAPORT(base)) + +#define write_data(base, byte) OUTB(byte, DATAPORT(base)) + +#define OUTPUT_READY 0x40 +#define INPUT_AVAIL 0x80 +#define MPU_ACK 0xF7 +#define MPU_RESET 0xFF +#define UART_MODE_ON 0x3F + +static struct mpu_config dev_conf[MAX_MIDI_DEV] = +{ + {0}}; + +static int n_mpu_devs = 0; +static int irq2dev[16]; + +static int reset_mpu401 (struct mpu_config *devc); +static void set_uart_mode (int dev, struct mpu_config *devc, int arg); +static void mpu_timer_init (int midi_dev); +static void mpu_timer_interrupt (void); +static void timer_ext_event (struct mpu_config *devc, int event, int parm); + +static struct synth_info mpu_synth_info_proto = +{"MPU-401 MIDI interface", 0, SYNTH_TYPE_MIDI, 0, 0, 128, 0, 128, SYNTH_CAP_INPUT}; + +static struct synth_info mpu_synth_info[MAX_MIDI_DEV]; + +/* + * States for the input scanner + */ + +#define ST_INIT 0 /* Ready for timing byte or msg */ +#define ST_TIMED 1 /* Leading timing byte rcvd */ +#define ST_DATABYTE 2 /* Waiting for (nr_left) data bytes */ + +#define ST_SYSMSG 100 /* System message (sysx etc). */ +#define ST_SYSEX 101 /* System exclusive msg */ +#define ST_MTC 102 /* Midi Time Code (MTC) qframe msg */ +#define ST_SONGSEL 103 /* Song select */ +#define ST_SONGPOS 104 /* Song position pointer */ + +static unsigned char len_tab[] =/* # of data bytes following a status + */ +{ + 2, /* 8x */ + 2, /* 9x */ + 2, /* Ax */ + 2, /* Bx */ + 1, /* Cx */ + 1, /* Dx */ + 2, /* Ex */ + 0 /* Fx */ +}; + +#define STORE(cmd) \ +if (devc->opened & OPEN_READ) \ +{ \ + int len; \ + unsigned char obuf[8]; \ + cmd; \ + seq_input_event(obuf, len); \ +} +#define _seqbuf obuf +#define _seqbufptr 0 +#define _SEQ_ADVBUF(x) len=x + +static void +do_midi_msg (struct mpu_config *devc, unsigned char *msg, int mlen) +{ + switch (msg[0] & 0xf0) + { + case 0x90: + if (msg[2] != 0) + { + STORE (SEQ_START_NOTE (devc->synthno, msg[0] & 0x0f, msg[1], msg[2])); + break; + } + msg[2] = 64; + + case 0x80: + STORE (SEQ_STOP_NOTE (devc->synthno, msg[0] & 0x0f, msg[1], msg[2])); + break; + + case 0xA0: + STORE (SEQ_KEY_PRESSURE (devc->synthno, msg[0] & 0x0f, msg[1], msg[2])); + break; + + case 0xB0: + /* + * Fix the controller value (combine MSB and LSB) + */ + if (msg[1] < 64) + { + int ctrl = msg[1]; + + if (ctrl < 32) + { + devc->controls[ctrl] = (msg[2] & 0x7f) << 7; + } + else + { + ctrl -= 32; + devc->controls[ctrl] = + (devc->controls[ctrl] & ~0x7f) | (msg[2] & 0x7f); + } + STORE (SEQ_CONTROL (devc->synthno, msg[0] & 0x0f, + msg[1], devc->controls[ctrl])); + } + else + STORE (SEQ_CONTROL (devc->synthno, msg[0] & 0x0f, msg[1], msg[2])); + break; + + case 0xC0: + STORE (SEQ_SET_PATCH (devc->synthno, msg[0] & 0x0f, msg[1])); + break; + + case 0xD0: + STORE (SEQ_CHN_PRESSURE (devc->synthno, msg[0] & 0x0f, msg[1])); + break; + + case 0xE0: + STORE (SEQ_BENDER (devc->synthno, msg[0] & 0x0f, + (msg[1] % 0x7f) | ((msg[2] & 0x7f) << 7))); + break; + + default: + printk ("MPU: Unknown midi channel message %02x\n", msg[0]); + } +} + +static int +mpu_input_scanner (struct mpu_config *devc, unsigned char midic) +{ + switch (devc->m_state) + { + case ST_INIT: + switch (midic) + { + case 0xf8: + /* Timer overflow */ + break; + + case 0xfc: + printk (""); + break; + + case 0xfd: + if (devc->timer_flag) + mpu_timer_interrupt (); + break; + + case 0xfe: + return MPU_ACK; + break; + + case 0xf0: + case 0xf1: + case 0xf2: + case 0xf3: + case 0xf4: + case 0xf5: + case 0xf6: + case 0xf7: + printk ("", midic & 0x0f); + break; + + case 0xf9: + printk (""); + break; + + case 0xff: + devc->m_state = ST_SYSMSG; + break; + + default: + if (midic <= 0xef) + { + /* printk("mpu time: %d ", midic); */ + devc->m_state = ST_TIMED; + } + else + printk (" ", midic); + } + break; + + case ST_TIMED: + { + int msg = (midic & 0xf0) >> 4; + + devc->m_state = ST_DATABYTE; + if (msg < 8) /* Data byte */ + { + /* printk("midi msg (running status) "); */ + msg = (devc->last_status & 0xf0) >> 4; + msg -= 8; + devc->m_left = len_tab[msg] - 1; + + devc->m_ptr = 2; + devc->m_buf[0] = devc->last_status; + devc->m_buf[1] = midic; + + if (devc->m_left <= 0) + { + devc->m_state = ST_INIT; + do_midi_msg (devc, devc->m_buf, devc->m_ptr); + devc->m_ptr = 0; + } + } + else if (msg == 0xf) /* MPU MARK */ + { + devc->m_state = ST_INIT; + + switch (midic) + { + case 0xf8: + /* printk("NOP "); */ + break; + + case 0xf9: + /* printk("meas end "); */ + break; + + case 0xfc: + /* printk("data end "); */ + break; + + default: + printk ("Unknown MPU mark %02x\n", midic); + } + } + else + { + devc->last_status = midic; + /* printk("midi msg "); */ + msg -= 8; + devc->m_left = len_tab[msg]; + + devc->m_ptr = 1; + devc->m_buf[0] = midic; + + if (devc->m_left <= 0) + { + devc->m_state = ST_INIT; + do_midi_msg (devc, devc->m_buf, devc->m_ptr); + devc->m_ptr = 0; + } + } + } + break; + + case ST_SYSMSG: + switch (midic) + { + case 0xf0: + printk (""); + devc->m_state = ST_SYSEX; + break; + + case 0xf1: + devc->m_state = ST_MTC; + break; + + case 0xf2: + devc->m_state = ST_SONGPOS; + devc->m_ptr = 0; + break; + + case 0xf3: + devc->m_state = ST_SONGSEL; + break; + + case 0xf6: + /* printk("tune_request\n"); */ + devc->m_state = ST_INIT; + + /* + * Real time messages + */ + case 0xf8: + /* midi clock */ + devc->m_state = ST_INIT; + timer_ext_event (devc, TMR_CLOCK, 0); + break; + + case 0xfA: + devc->m_state = ST_INIT; + timer_ext_event (devc, TMR_START, 0); + break; + + case 0xFB: + devc->m_state = ST_INIT; + timer_ext_event (devc, TMR_CONTINUE, 0); + break; + + case 0xFC: + devc->m_state = ST_INIT; + timer_ext_event (devc, TMR_STOP, 0); + break; + + case 0xFE: + /* active sensing */ + devc->m_state = ST_INIT; + break; + + case 0xff: + /* printk("midi hard reset"); */ + devc->m_state = ST_INIT; + break; + + default: + printk ("unknown MIDI sysmsg %0x\n", midic); + devc->m_state = ST_INIT; + } + break; + + case ST_MTC: + devc->m_state = ST_INIT; + printk ("MTC frame %x02\n", midic); + break; + + case ST_SYSEX: + if (midic == 0xf7) + { + printk (""); + devc->m_state = ST_INIT; + } + else + printk ("%02x ", midic); + break; + + case ST_SONGPOS: + BUFTEST (devc); + devc->m_buf[devc->m_ptr++] = midic; + if (devc->m_ptr == 2) + { + devc->m_state = ST_INIT; + devc->m_ptr = 0; + timer_ext_event (devc, TMR_SPP, + ((devc->m_buf[1] & 0x7f) << 7) | + (devc->m_buf[0] & 0x7f)); + } + break; + + case ST_DATABYTE: + BUFTEST (devc); + devc->m_buf[devc->m_ptr++] = midic; + if ((--devc->m_left) <= 0) + { + devc->m_state = ST_INIT; + do_midi_msg (devc, devc->m_buf, devc->m_ptr); + devc->m_ptr = 0; + } + break; + + default: + printk ("Bad state %d ", devc->m_state); + devc->m_state = ST_INIT; + } + + return 1; +} + +static void +mpu401_input_loop (struct mpu_config *devc) +{ + unsigned long flags; + int busy; + + DISABLE_INTR (flags); + busy = devc->m_busy; + devc->m_busy = 1; + RESTORE_INTR (flags); + + if (busy) + return; + + while (input_avail (devc->base)) + { + unsigned char c = read_data (devc->base); + + if (devc->mode == MODE_SYNTH) + { + mpu_input_scanner (devc, c); + } + else if (devc->opened & OPEN_READ && devc->inputintr != NULL) + devc->inputintr (devc->devno, c); + } -static int reset_mpu401 (void); -static void (*midi_input_intr) (int dev, unsigned char data); + devc->m_busy = 0; +} void -mpuintr (int unit) +mpuintr (int irq) { - while (input_avail ()) + struct mpu_config *devc; + int dev; + +#ifdef linux + sti (); +#endif + + if (irq < 1 || irq > 15) { - unsigned char c = mpu401_read (); + printk ("MPU-401: Interrupt #%d?\n", irq); + return; + } - if (mpu401_opened & OPEN_READ) - midi_input_intr (my_dev, c); + dev = irq2dev[irq]; + if (dev == -1) + { + printk ("MPU-401: Interrupt #%d?\n", irq); + return; } + + devc = &dev_conf[dev]; + + if (devc->base != 0 && (devc->opened & OPEN_READ || devc->mode == MODE_SYNTH)) + if (input_avail (devc->base)) + mpu401_input_loop (devc); + } static int @@ -79,16 +515,32 @@ void (*output) (int dev) ) { - if (mpu401_opened) + int err; + struct mpu_config *devc; + + if (dev < 0 || dev >= num_midis) + return RET_ERROR (ENXIO); + + devc = &dev_conf[dev]; + + if (devc->opened) { printk ("MPU-401: Midi busy\n"); return RET_ERROR (EBUSY); } - mpuintr (0); + irq2dev[devc->irq] = dev; + if ((err = snd_set_irq_handler (devc->irq, mpuintr) < 0)) + return err; + + set_uart_mode (dev, devc, 1); + devc->mode = MODE_MIDI; + devc->synthno = 0; + + mpu401_input_loop (devc); - midi_input_intr = input; - mpu401_opened = mode; + devc->inputintr = input; + devc->opened = mode; return 0; } @@ -96,7 +548,20 @@ static void mpu401_close (int dev) { - mpu401_opened = 0; + struct mpu_config *devc; + + devc = &dev_conf[dev]; + + if (devc->uart_mode) + reset_mpu401 (devc); /* + * This disables the UART mode + */ + devc->mode = 0; + + snd_release_irq (devc->irq); + devc->inputintr = NULL; + irq2dev[devc->irq] = -1; + devc->opened = 0; } static int @@ -105,38 +570,180 @@ int timeout; unsigned long flags; + struct mpu_config *devc; + + devc = &dev_conf[dev]; + +#if 0 /* * Test for input since pending input seems to block the output. */ - DISABLE_INTR (flags); + if (input_avail (devc->base)) + mpu401_input_loop (devc); +#endif + /* + * Sometimes it takes about 13000 loops before the output becomes ready + * (After reset). Normally it takes just about 10 loops. + */ - if (input_avail ()) - mpuintr (0); + for (timeout = 30000; timeout > 0 && !output_ready (devc->base); timeout--); /* + * Wait + */ + DISABLE_INTR (flags); + if (!output_ready (devc->base)) + { + printk ("MPU-401: Send data timeout\n"); + RESTORE_INTR (flags); + return 0; + } + + write_data (devc->base, midi_byte); RESTORE_INTR (flags); + return 1; +} + +static int +mpu401_command (int dev, mpu_command_rec * cmd) +{ + int i, timeout, ok; + int ret = 0; + unsigned long flags; + struct mpu_config *devc; + + devc = &dev_conf[dev]; + if (devc->uart_mode) /* + * Not possible in UART mode + */ + { + printk ("MPU-401 commands not possible in the UART mode\n"); + return RET_ERROR (EINVAL); + } + /* - * Sometimes it takes about 13000 loops before the output becomes ready + * Test for input since pending input seems to block the output. + */ + if (input_avail (devc->base)) + mpu401_input_loop (devc); + + /* + * Sometimes it takes about 30000 loops before the output becomes ready * (After reset). Normally it takes just about 10 loops. */ - for (timeout = 30000; timeout > 0 && !output_ready (); timeout--); /* Wait */ + for (timeout = 500000; timeout > 0 && !output_ready (devc->base); timeout--); - if (!output_ready ()) + DISABLE_INTR (flags); + if (!output_ready (devc->base)) { - printk ("MPU-401: Timeout\n"); - return 0; + printk ("MPU-401: Command (0x%x) timeout\n", (int) cmd->cmd); + RESTORE_INTR (flags); + return RET_ERROR (EIO); } - mpu401_write (midi_byte); - return 1; + write_command (devc->base, cmd->cmd); + ok = 0; + for (timeout = 500000; timeout > 0 && !ok; timeout--) + if (input_avail (devc->base)) + if (mpu_input_scanner (devc, read_data (devc->base)) == MPU_ACK) + ok = 1; + + if (!ok) + { + RESTORE_INTR (flags); + printk ("MPU: No ACK to command (0x%x)\n", (int) cmd->cmd); + return RET_ERROR (EIO); + } + + if (cmd->nr_args) + for (i = 0; i < cmd->nr_args; i++) + { + for (timeout = 30000; timeout > 0 && !output_ready (devc->base); timeout--); + + if (!mpu401_out (dev, cmd->data[i])) + { + RESTORE_INTR (flags); + printk ("MPU: Command (0x%x), parm send failed.\n", (int) cmd->cmd); + return RET_ERROR (EIO); + } + } + + ret = 0; + cmd->data[0] = 0; + + if (cmd->nr_returns) + for (i = 0; i < cmd->nr_returns; i++) + { + ok = 0; + for (timeout = 5000; timeout > 0 && !ok; timeout--) + if (input_avail (devc->base)) + { + cmd->data[i] = read_data (devc->base); + ok = 1; + } + + if (!ok) + { + RESTORE_INTR (flags); + printk ("MPU: No response(%d) to command (0x%x)\n", i, (int) cmd->cmd); + return RET_ERROR (EIO); + } + } + + RESTORE_INTR (flags); + + return ret; } static int -mpu401_command (int dev, unsigned char midi_byte) +exec_cmd (int dev, int cmd, int data) { - return 1; + int ret; + + static mpu_command_rec rec; + + rec.cmd = cmd & 0xff; + rec.nr_args = ((cmd & 0xf0) == 0xE0); + rec.nr_returns = ((cmd & 0xf0) == 0xA0); + rec.data[0] = data & 0xff; + + if ((ret = mpu401_command (dev, &rec)) < 0) + return ret; + return (unsigned char) rec.data[0]; +} + +static int +mpu401_prefix_cmd (int dev, unsigned char status) +{ + struct mpu_config *devc = &dev_conf[dev]; + + if (devc->uart_mode) + return 1; + + if (status < 0xf0) + { + if (exec_cmd (dev, 0xD0, 0) < 0) + return 0; + + return 1; + } + + switch (status) + { + case 0xF0: + if (exec_cmd (dev, 0xDF, 0) < 0) + return 0; + + return 1; + break; + + default: + return 0; + } + + return 0; } static int @@ -154,7 +761,45 @@ static int mpu401_ioctl (int dev, unsigned cmd, unsigned arg) { - return RET_ERROR (EINVAL); + struct mpu_config *devc; + + devc = &dev_conf[dev]; + + switch (cmd) + { + case 1: + IOCTL_FROM_USER ((char *) &init_sequence, (char *) arg, 0, sizeof (init_sequence)); + return 0; + break; + + case SNDCTL_MIDI_MPUMODE: + if (devc->version == 0) + { + printk ("MPU-401: Intelligent mode not supported by the HW\n"); + return RET_ERROR (EINVAL); + } + set_uart_mode (dev, devc, !IOCTL_IN (arg)); + return 0; + break; + + case SNDCTL_MIDI_MPUCMD: + { + int ret; + mpu_command_rec rec; + + IOCTL_FROM_USER ((char *) &rec, (char *) arg, 0, sizeof (rec)); + + if ((ret = mpu401_command (dev, &rec)) < 0) + return ret; + + IOCTL_TO_USER ((char *) arg, 0, (char *) &rec, sizeof (rec)); + return 0; + } + break; + + default: + return RET_ERROR (EINVAL); + } } static void @@ -165,12 +810,135 @@ static int mpu401_buffer_status (int dev) { - return 0; /* No data in buffers */ + return 0; /* + * No data in buffers + */ +} + +static int +mpu_synth_ioctl (int dev, + unsigned int cmd, unsigned int arg) +{ + int midi_dev; + struct mpu_config *devc; + + midi_dev = synth_devs[dev]->midi_dev; + + if (midi_dev < 0 || midi_dev > num_midis) + return RET_ERROR (ENXIO); + + devc = &dev_conf[midi_dev]; + + switch (cmd) + { + + case SNDCTL_SYNTH_INFO: + IOCTL_TO_USER ((char *) arg, 0, &mpu_synth_info[midi_dev], + sizeof (struct synth_info)); + + return 0; + break; + + case SNDCTL_SYNTH_MEMAVL: + return 0x7fffffff; + break; + + default: + return RET_ERROR (EINVAL); + } +} + +static int +mpu_synth_open (int dev, int mode) +{ + int midi_dev, err; + struct mpu_config *devc; + + midi_dev = synth_devs[dev]->midi_dev; + + if (midi_dev < 0 || midi_dev > num_midis) + return RET_ERROR (ENXIO); + + devc = &dev_conf[midi_dev]; + + if (devc->opened) + { + printk ("MPU-401: Midi busy\n"); + return RET_ERROR (EBUSY); + } + + devc->opened = mode; + devc->mode = MODE_SYNTH; + devc->synthno = dev; + + devc->inputintr = NULL; + irq2dev[devc->irq] = midi_dev; + if ((err = snd_set_irq_handler (devc->irq, mpuintr) < 0)) + return err; + + reset_mpu401 (devc); + + if (mode & OPEN_READ) + { + exec_cmd (midi_dev, 0x34, 0); /* Return timing bytes in stop mode */ + exec_cmd (midi_dev, 0x8B, 0); /* Enable data in stop mode */ + } + + return 0; +} + +static void +mpu_synth_close (int dev) +{ + int midi_dev; + struct mpu_config *devc; + + midi_dev = synth_devs[dev]->midi_dev; + + devc = &dev_conf[midi_dev]; + exec_cmd (midi_dev, 0x15, 0); /* Stop recording, playback and MIDI */ + exec_cmd (midi_dev, 0x8a, 0); /* Disable data in stopped mode */ + + devc->opened = 0; + devc->mode = 0; + snd_release_irq (devc->irq); + devc->inputintr = NULL; + irq2dev[devc->irq] = -1; } -static struct midi_operations mpu401_operations = +#define MIDI_SYNTH_NAME "MPU-401 UART Midi" +#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT +#include "midi_synth.h" + +static struct synth_operations mpu401_synth_proto = +{ + NULL, + 0, + SYNTH_TYPE_MIDI, + 0, + mpu_synth_open, + mpu_synth_close, + mpu_synth_ioctl, + midi_synth_kill_note, + midi_synth_start_note, + midi_synth_set_instr, + midi_synth_reset, + midi_synth_hw_control, + midi_synth_load_patch, + midi_synth_aftertouch, + midi_synth_controller, + midi_synth_panning, + NULL, + midi_synth_patchmgr, + midi_synth_bender +}; + +static struct synth_operations mpu401_synth_operations[MAX_MIDI_DEV]; + +static struct midi_operations mpu401_midi_proto = { - {"MPU-401", 0, 0, SNDCARD_MPU401}, + {"MPU-401 Midi", 0, MIDI_CAP_MPU401, SNDCARD_MPU401}, + NULL, mpu401_open, mpu401_close, mpu401_ioctl, @@ -178,100 +946,776 @@ mpu401_start_read, mpu401_end_read, mpu401_kick, - mpu401_command, - mpu401_buffer_status + NULL, + mpu401_buffer_status, + mpu401_prefix_cmd }; +static struct midi_operations mpu401_midi_operations[MAX_MIDI_DEV]; + +static void +mpu401_chk_version (struct mpu_config *devc) +{ + int tmp; + + devc->version = devc->revision = 0; + + if ((tmp = exec_cmd (num_midis, 0xAC, 0)) < 0) + return; + devc->version = tmp; + + if ((tmp = exec_cmd (num_midis, 0xAD, 0)) < 0) + return; + devc->revision = tmp; +} long attach_mpu401 (long mem_start, struct address_info *hw_config) { - int ok, timeout; + int i; unsigned long flags; + char revision_char; - mpu401_base = hw_config->io_base; - mpu401_irq = hw_config->irq; + struct mpu_config *devc; - if (!mpu401_detected) - return RET_ERROR (EIO); + for (i = 0; i < 16; i++) + irq2dev[i] = -1; - DISABLE_INTR (flags); - for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /* Wait */ - mpu401_cmd (UART_MODE_ON); + if (num_midis >= MAX_MIDI_DEV) + { + printk ("MPU-401: Too many midi devices detected\n"); + return mem_start; + } - ok = 0; - for (timeout = 50000; timeout > 0 && !ok; timeout--) - if (input_avail ()) - if (mpu401_read () == MPU_ACK) - ok = 1; + devc = &dev_conf[num_midis]; + devc->base = hw_config->io_base; + devc->irq = hw_config->irq; + devc->opened = 0; + devc->uart_mode = 0; + devc->initialized = 0; + devc->version = 0; + devc->revision = 0; + devc->capabilities = 0; + devc->timer_flag = 0; + devc->m_busy = 0; + devc->m_state = ST_INIT; + + for (i = 0; i < 32; i++) + devc->controls[i] = 0x2000; + + if (!reset_mpu401 (devc)) + return mem_start; + + DISABLE_INTR (flags); + mpu401_chk_version (devc); + if (devc->version == 0) + mpu401_chk_version (devc); RESTORE_INTR (flags); - printk (" "); + if (devc->version == 0) + { + memcpy ((char *) &mpu401_synth_operations[num_midis], + (char *) &std_midi_synth, + sizeof (struct synth_operations)); + } + else + { + devc->capabilities |= MPU_CAP_INTLG; /* Supports intelligent mode */ + memcpy ((char *) &mpu401_synth_operations[num_midis], + (char *) &mpu401_synth_proto, + sizeof (struct synth_operations)); + } + + memcpy ((char *) &mpu401_midi_operations[num_midis], + (char *) &mpu401_midi_proto, + sizeof (struct midi_operations)); + + mpu401_midi_operations[num_midis].converter = + &mpu401_synth_operations[num_midis]; + + memcpy ((char *) &mpu_synth_info[num_midis], + (char *) &mpu_synth_info_proto, + sizeof (struct synth_info)); + + n_mpu_devs++; + + if (devc->version == 0x20 && devc->revision >= 0x07) /* MusicQuest interface */ + { + int ports = (devc->revision & 0x08) ? 32 : 16; + + devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_SMPTE | + MPU_CAP_CLS | MPU_CAP_2PORT; + + revision_char = (devc->revision == 0x7f) ? 'M' : ' '; + printk (" ", + ports, + revision_char); +#ifndef SCO + sprintf (mpu_synth_info[num_midis].name, + "MQX-%d%c MIDI Interface #%d", + ports, + revision_char, + n_mpu_devs); +#endif + } + else + { + + revision_char = devc->revision ? devc->revision + '@' : ' '; + if (devc->revision > ('Z' - '@')) + revision_char = '+'; + + devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_FSK; + + printk (" ", + (devc->version & 0xf0) >> 4, + devc->version & 0x0f, + revision_char); +#ifndef SCO + sprintf (mpu_synth_info[num_midis].name, + "MPU-401 %d.%d%c Midi interface #%d", + (devc->version & 0xf0) >> 4, + devc->version & 0x0f, + revision_char, + n_mpu_devs); +#endif + } + +#ifndef SCO + strcpy (mpu401_midi_operations[num_midis].info.name, + mpu_synth_info[num_midis].name); +#endif + + mpu401_synth_operations[num_midis].midi_dev = devc->devno = num_midis; + mpu401_synth_operations[devc->devno].info = + &mpu_synth_info[devc->devno]; - my_dev = num_midis; - mpu401_dev = num_midis; - midi_devs[num_midis++] = &mpu401_operations; + if (devc->capabilities & MPU_CAP_INTLG) /* Has timer */ + mpu_timer_init (num_midis); + + midi_devs[num_midis++] = &mpu401_midi_operations[devc->devno]; return mem_start; } static int -reset_mpu401 (void) +reset_mpu401 (struct mpu_config *devc) { unsigned long flags; int ok, timeout, n; + int timeout_limit; /* * Send the RESET command. Try again if no success at the first time. + * (If the device is in the UART mode, it will not ack the reset cmd). */ ok = 0; - DISABLE_INTR (flags); + timeout_limit = devc->initialized ? 30000 : 100000; + devc->initialized = 1; for (n = 0; n < 2 && !ok; n++) { - for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /* Wait */ - mpu401_cmd (MPU_RESET); /* Send MPU-401 RESET Command */ + for (timeout = timeout_limit; timeout > 0 && !ok; timeout--) + ok = output_ready (devc->base); + + write_command (devc->base, 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 (mpu401_read () == MPU_ACK) - ok = 1; + for (timeout = timeout_limit * 2; timeout > 0 && !ok; timeout--) + { + DISABLE_INTR (flags); + if (input_avail (devc->base)) + if (read_data (devc->base) == MPU_ACK) + ok = 1; + RESTORE_INTR (flags); + } } - mpu401_opened = 0; - if (ok) - mpuintr (0); /* Flush input before enabling interrupts */ + devc->m_state = ST_INIT; + devc->m_ptr = 0; + devc->m_left = 0; + devc->last_status = 0; + devc->uart_mode = 0; - RESTORE_INTR (flags); - return ok; } +static void +set_uart_mode (int dev, struct mpu_config *devc, int arg) +{ + + if (!arg && devc->version == 0) + return; + + if ((devc->uart_mode == 0) == (arg == 0)) + return; /* Already set */ + reset_mpu401 (devc); /* This exits the uart mode */ + + if (arg) + { + if (exec_cmd (dev, UART_MODE_ON, 0) < 0) + { + printk ("MPU%d: Can't enter UART mode\n", devc->devno); + devc->uart_mode = 0; + return; + } + } + devc->uart_mode = arg; + +} + int probe_mpu401 (struct address_info *hw_config) { int ok = 0; + struct mpu_config tmp_devc; + + tmp_devc.base = hw_config->io_base; + tmp_devc.irq = hw_config->irq; + tmp_devc.initialized = 0; + + ok = reset_mpu401 (&tmp_devc); + + return ok; +} + +/***************************************************** + * Timer stuff + ****************************************************/ + +#if !defined(EXCLUDE_SEQUENCER) + +static volatile int timer_initialized = 0, timer_open = 0, tmr_running = 0; +static volatile int curr_tempo, curr_timebase, hw_timebase; +static int max_timebase = 8; /* 8*24=192 ppqn */ +static volatile unsigned long next_event_time; +static volatile unsigned long curr_ticks, curr_clocks; +static unsigned long prev_event_time; +static int metronome_mode; + +static unsigned long +clocks2ticks (unsigned long clocks) +{ + /* + * The MPU-401 supports just a limited set of possible timebase values. + * Since the applications require more choices, the driver has to + * program the HW to do it's best and to convert between the HW and + * actual timebases. + */ + + return ((clocks * curr_timebase) + (hw_timebase / 2)) / hw_timebase; +} + +static void +set_timebase (int midi_dev, int val) +{ + int hw_val; + + if (val < 48) + val = 48; + if (val > 1000) + val = 1000; + + hw_val = val; + hw_val = (hw_val + 23) / 24; + if (hw_val > max_timebase) + hw_val = max_timebase; + + if (exec_cmd (midi_dev, 0xC0 | (hw_val & 0x0f), 0) < 0) + { + printk ("MPU: Can't set HW timebase to %d\n", hw_val * 24); + return; + } + hw_timebase = hw_val * 24; + curr_timebase = val; + +} + +static void +tmr_reset (void) +{ + unsigned long flags; + + DISABLE_INTR (flags); + next_event_time = 0xffffffff; + prev_event_time = 0; + curr_ticks = curr_clocks = 0; + RESTORE_INTR (flags); +} + +static void +set_timer_mode (int midi_dev) +{ + if (timer_mode & TMR_MODE_CLS) + exec_cmd (midi_dev, 0x3c, 0); /* Use CLS sync */ + else if (timer_mode & TMR_MODE_SMPTE) + exec_cmd (midi_dev, 0x3d, 0); /* Use SMPTE sync */ + + if (timer_mode & TMR_INTERNAL) + { + exec_cmd (midi_dev, 0x80, 0); /* Use MIDI sync */ + } + else + { + if (timer_mode & (TMR_MODE_MIDI | TMR_MODE_CLS)) + { + exec_cmd (midi_dev, 0x82, 0); /* Use MIDI sync */ + exec_cmd (midi_dev, 0x91, 0); /* Enable ext MIDI ctrl */ + } + else if (timer_mode & TMR_MODE_FSK) + exec_cmd (midi_dev, 0x81, 0); /* Use FSK sync */ + } +} + +static void +stop_metronome (int midi_dev) +{ + exec_cmd (midi_dev, 0x84, 0); /* Disable metronome */ +} + +static void +setup_metronome (int midi_dev) +{ + int numerator, denominator; + int clks_per_click, num_32nds_per_beat; + int beats_per_measure; + + numerator = ((unsigned) metronome_mode >> 24) & 0xff; + denominator = ((unsigned) metronome_mode >> 16) & 0xff; + clks_per_click = ((unsigned) metronome_mode >> 8) & 0xff; + num_32nds_per_beat = (unsigned) metronome_mode & 0xff; + beats_per_measure = (numerator * 4) >> denominator; + + if (!metronome_mode) + exec_cmd (midi_dev, 0x84, 0); /* Disable metronome */ + else + { + exec_cmd (midi_dev, 0xE4, clks_per_click); + exec_cmd (midi_dev, 0xE6, beats_per_measure); + exec_cmd (midi_dev, 0x83, 0); /* Enable metronome without accents */ + } +} + +static int +start_timer (int midi_dev) +{ + tmr_reset (); + set_timer_mode (midi_dev); - mpu401_base = hw_config->io_base; - mpu401_irq = hw_config->irq; + if (tmr_running) + return TIMER_NOT_ARMED; /* Already running */ - if (snd_set_irq_handler (mpu401_irq, mpuintr) < 0) + if (timer_mode & TMR_INTERNAL) + { + exec_cmd (midi_dev, 0x02, 0); /* Send MIDI start */ + tmr_running = 1; + return TIMER_NOT_ARMED; + } + else + { + exec_cmd (midi_dev, 0x35, 0); /* Enable mode messages to PC */ + exec_cmd (midi_dev, 0x38, 0); /* Enable sys common messages to PC */ + exec_cmd (midi_dev, 0x39, 0); /* Enable real time messages to PC */ + exec_cmd (midi_dev, 0x97, 0); /* Enable system exclusive messages to PC */ + } + + return TIMER_ARMED; +} + +static int +mpu_timer_open (int dev, int mode) +{ + int midi_dev = sound_timer_devs[dev]->devlink; + + if (timer_open) + return RET_ERROR (EBUSY); + + tmr_reset (); + curr_tempo = 50; + exec_cmd (midi_dev, 0xE0, 50); + curr_timebase = hw_timebase = 120; + set_timebase (midi_dev, 120); + timer_open = 1; + metronome_mode = 0; + set_timer_mode (midi_dev); + + exec_cmd (midi_dev, 0xe7, 0x04); /* Send all clocks to host */ + exec_cmd (midi_dev, 0x95, 0); /* Enable clock to host */ + + return 0; +} + +static void +mpu_timer_close (int dev) +{ + int midi_dev = sound_timer_devs[dev]->devlink; + + timer_open = tmr_running = 0; + exec_cmd (midi_dev, 0x15, 0); /* Stop all */ + exec_cmd (midi_dev, 0x94, 0); /* Disable clock to host */ + exec_cmd (midi_dev, 0x8c, 0); /* Disable measure end messages to host */ + stop_metronome (midi_dev); +} + +static int +mpu_timer_event (int dev, unsigned char *event) +{ + unsigned char command = event[1]; + unsigned long parm = *(unsigned int *) &event[4]; + int midi_dev = sound_timer_devs[dev]->devlink; + + switch (command) + { + case TMR_WAIT_REL: + parm += prev_event_time; + case TMR_WAIT_ABS: + if (parm > 0) + { + long time; + + if (parm <= curr_ticks) /* It's the time */ + return TIMER_NOT_ARMED; + + time = parm; + next_event_time = prev_event_time = time; + + return TIMER_ARMED; + } + break; + + case TMR_START: + if (tmr_running) + break; + return start_timer (midi_dev); + break; + + case TMR_STOP: + exec_cmd (midi_dev, 0x01, 0); /* Send MIDI stop */ + stop_metronome (midi_dev); + tmr_running = 0; + break; + + case TMR_CONTINUE: + if (tmr_running) + break; + exec_cmd (midi_dev, 0x03, 0); /* Send MIDI continue */ + setup_metronome (midi_dev); + tmr_running = 1; + break; + + case TMR_TEMPO: + if (parm) + { + if (parm < 8) + parm = 8; + if (parm > 250) + parm = 250; + + if (exec_cmd (midi_dev, 0xE0, parm) < 0) + printk ("MPU: Can't set tempo to %d\n", (int) parm); + curr_tempo = parm; + } + break; + + case TMR_ECHO: + seq_copy_to_input (event, 8); + break; + + case TMR_TIMESIG: + if (metronome_mode) /* Metronome enabled */ + { + metronome_mode = parm; + setup_metronome (midi_dev); + } + break; + + default:; + } + + return TIMER_NOT_ARMED; +} + +static unsigned long +mpu_timer_get_time (int dev) +{ + if (!timer_open) return 0; - ok = reset_mpu401 (); + return curr_ticks; +} - mpu401_detected = ok; - return ok; +static int +mpu_timer_ioctl (int dev, + unsigned int command, unsigned int arg) +{ + int midi_dev = sound_timer_devs[dev]->devlink; + + switch (command) + { + case SNDCTL_TMR_SOURCE: + { + int parm = IOCTL_IN (arg) & timer_caps; + + if (parm != 0) + { + timer_mode = parm; + + if (timer_mode & TMR_MODE_CLS) + exec_cmd (midi_dev, 0x3c, 0); /* Use CLS sync */ + else if (timer_mode & TMR_MODE_SMPTE) + exec_cmd (midi_dev, 0x3d, 0); /* Use SMPTE sync */ + } + + return IOCTL_OUT (arg, timer_mode); + } + break; + + case SNDCTL_TMR_START: + if (tmr_running) + return 0; + start_timer (midi_dev); + return 0; + break; + + case SNDCTL_TMR_STOP: + tmr_running = 0; + exec_cmd (midi_dev, 0x01, 0); /* Send MIDI stop */ + stop_metronome (midi_dev); + return 0; + break; + + case SNDCTL_TMR_CONTINUE: + if (tmr_running) + return 0; + tmr_running = 1; + exec_cmd (midi_dev, 0x03, 0); /* Send MIDI continue */ + return 0; + break; + + case SNDCTL_TMR_TIMEBASE: + { + int val = IOCTL_IN (arg); + + if (val) + set_timebase (midi_dev, val); + + return IOCTL_OUT (arg, curr_timebase); + } + break; + + case SNDCTL_TMR_TEMPO: + { + int val = IOCTL_IN (arg); + int ret; + + if (val) + { + if (val < 8) + val = 8; + if (val > 250) + val = 250; + if ((ret = exec_cmd (midi_dev, 0xE0, val)) < 0) + { + printk ("MPU: Can't set tempo to %d\n", (int) val); + return ret; + } + + curr_tempo = val; + } + + return IOCTL_OUT (arg, curr_tempo); + } + break; + + case SNDCTL_SEQ_CTRLRATE: + if (IOCTL_IN (arg) != 0) /* Can't change */ + return RET_ERROR (EINVAL); + + return IOCTL_OUT (arg, ((curr_tempo * curr_timebase) + 30) / 60); + break; + + case SNDCTL_TMR_METRONOME: + metronome_mode = IOCTL_IN (arg); + setup_metronome (midi_dev); + return 0; + break; + + default: + } + + return RET_ERROR (EINVAL); +} + +static void +mpu_timer_arm (int dev, long time) +{ + if (time < 0) + time = curr_ticks + 1; + else if (time <= curr_ticks) /* It's the time */ + return; + + next_event_time = prev_event_time = time; + + return; +} + +static struct sound_timer_operations mpu_timer = +{ + {"MPU-401 Timer", 0}, + 10, /* Priority */ + 0, /* Local device link */ + mpu_timer_open, + mpu_timer_close, + mpu_timer_event, + mpu_timer_get_time, + mpu_timer_ioctl, + mpu_timer_arm +}; + +static void +mpu_timer_interrupt (void) +{ + + if (!timer_open) + return; + + if (!tmr_running) + return; + + curr_clocks++; + curr_ticks = clocks2ticks (curr_clocks); + + if (curr_ticks >= next_event_time) + { + next_event_time = 0xffffffff; + sequencer_timer (); + } +} + +static void +timer_ext_event (struct mpu_config *devc, int event, int parm) +{ + int midi_dev = devc->devno; + + if (!devc->timer_flag) + return; + + switch (event) + { + case TMR_CLOCK: + printk (""); + break; + + case TMR_START: + printk ("Ext MIDI start\n"); + if (!tmr_running) + if (timer_mode & TMR_EXTERNAL) + { + tmr_running = 1; + setup_metronome (midi_dev); + next_event_time = 0; + STORE (SEQ_START_TIMER ()); + } + break; + + case TMR_STOP: + printk ("Ext MIDI stop\n"); + if (timer_mode & TMR_EXTERNAL) + { + tmr_running = 0; + stop_metronome (midi_dev); + STORE (SEQ_STOP_TIMER ()); + } + break; + + case TMR_CONTINUE: + printk ("Ext MIDI continue\n"); + if (timer_mode & TMR_EXTERNAL) + { + tmr_running = 1; + setup_metronome (midi_dev); + STORE (SEQ_CONTINUE_TIMER ()); + } + break; + + case TMR_SPP: + printk ("Songpos: %d\n", parm); + if (timer_mode & TMR_EXTERNAL) + { + STORE (SEQ_SONGPOS (parm)); + } + break; + } +} + +static void +mpu_timer_init (int midi_dev) +{ + struct mpu_config *devc; + int n; + + devc = &dev_conf[midi_dev]; + + if (timer_initialized) + return; /* There is already a similar timer */ + + timer_initialized = 1; + + mpu_timer.devlink = midi_dev; + dev_conf[midi_dev].timer_flag = 1; + +#if 1 + if (num_sound_timers >= MAX_TIMER_DEV) + n = 0; /* Overwrite the system timer */ + else + n = num_sound_timers++; +#else + n = 0; +#endif + sound_timer_devs[n] = &mpu_timer; + + if (devc->version < 0x20) /* Original MPU-401 */ + timer_caps = TMR_INTERNAL | TMR_EXTERNAL | TMR_MODE_FSK | TMR_MODE_MIDI; + else + { + /* + * The version number 2.0 is used (at least) by the + * MusicQuest cards and the Roland Super-MPU. + * + * MusicQuest has given a special meaning to the bits of the + * revision number. The Super-MPU returns 0. + */ + + if (devc->revision) + timer_caps |= TMR_EXTERNAL | TMR_MODE_MIDI; + + if (devc->revision & 0x02) + timer_caps |= TMR_MODE_CLS; + +#if 0 + if (devc->revision & 0x04) + timer_caps |= TMR_MODE_SMPTE; +#endif + + if (devc->revision & 0x40) + max_timebase = 10; /* Has the 216 and 240 ppqn modes */ + } + + timer_mode = (TMR_INTERNAL | TMR_MODE_MIDI) & timer_caps; + } + +#endif #endif diff -u --recursive --new-file v1.1.30/linux/drivers/sound/opl3.c linux/drivers/sound/opl3.c --- v1.1.30/linux/drivers/sound/opl3.c Sun May 1 12:12:35 1994 +++ linux/drivers/sound/opl3.c Mon Jul 18 09:50:55 1994 @@ -27,8 +27,12 @@ * */ -/* Major improvements to the FM handling 30AUG92 by Rob Hooft, */ -/* hooft@chem.ruu.nl */ +/* + * Major improvements to the FM handling 30AUG92 by Rob Hooft, + */ +/* + * hooft@chem.ruu.nl + */ #include "sound_config.h" @@ -37,8 +41,9 @@ #include "opl3.h" #define MAX_VOICE 18 -#define OFFS_4OP 11 /* Definitions for the operators OP3 and OP4 - * begin here */ +#define OFFS_4OP 11 /* + * * * Definitions for the operators OP3 and + * * OP4 * * begin here */ static int opl3_enabled = 0; static int left_address = 0x388, right_address = 0x388, both_address = 0; @@ -58,24 +63,30 @@ }; static struct voice_info voices[MAX_VOICE]; +static struct voice_alloc_info *voice_alloc; +static struct channel_info *chn_info; static struct sbi_instrument *instrmap; static struct sbi_instrument *active_instrument[MAX_VOICE] = {NULL}; static struct synth_info fm_info = -{"AdLib", 0, SYNTH_TYPE_FM, FM_TYPE_ADLIB, 0, 9, 0, SBFM_MAXINSTR, 0}; +{"OPL-2", 0, SYNTH_TYPE_FM, FM_TYPE_ADLIB, 0, 9, 0, SBFM_MAXINSTR, 0}; 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, unsigned int addr, unsigned int val); -static int opl3_kill_note (int dev, int voice, int velocity); +static int opl3_kill_note (int dev, int voice, int note, int velocity); static unsigned char connection_mask = 0x00; void @@ -99,9 +110,9 @@ static int voices_4op[MAX_VOICE] = {0, 1, 2, 9, 10, 11, 6, 7, 8, 15, 16, 17}; - connection_mask = 0x3f; - opl3_command (right_address, CONNECTION_SELECT_REGISTER, 0x3f); /* Select all 4-OP - * voices */ + connection_mask = 0x3f; /* Connect all possible 4 OP voices */ + opl3_command (right_address, CONNECTION_SELECT_REGISTER, 0x3f); + for (i = 0; i < 3; i++) physical_voices[i].voice_mode = 4; for (i = 3; i < 6; i++) @@ -114,7 +125,7 @@ for (i = 0; i < 12; i++) logical_voices[i] = voices_4op[i]; - nr_voices = 12; + voice_alloc->max_voice = nr_voices = 12; } static int @@ -183,66 +194,111 @@ if (already_initialized) { - return 0; /* Do avoid duplicate initializations */ + 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 */ + 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 + */ + + stat1 = INB (ioaddr); /* + * Read status register + */ - stat1 = INB (ioaddr); /* Read status register */ - 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 */ + TIMER2_MASK | TIMER1_START); /* + * Unmask and start timer 1 + */ /* * Now we have to delay at least 80 msec */ for (i = 0; i < 50; i++) - tenmicrosec (); /* To be sure */ - - stat2 = INB (ioaddr); /* Read status after timers have expired */ + tenmicrosec (); /* + * To be sure + */ + + stat2 = INB (ioaddr); /* + * Read status after timers have expired + */ - /* Stop the timers */ + /* + * Stop the timers + */ - opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); /* Reset timers 1 and 2 */ - opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); /* Reset the IRQ of FM - * chicp */ + 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 + */ if ((stat2 & 0xE0) != 0xc0) { - return 0; /* There is no YM3812 */ + return 0; /* + * There is no YM3812 + */ } - /* There is a FM chicp in this address. Now set some default values. */ + /* + * There is a FM chicp in this address. Now set some default values. + */ for (i = 0; i < 9; i++) - opl3_command (ioaddr, KEYON_BLOCK + i, 0); /* Note off */ + opl3_command (ioaddr, KEYON_BLOCK + i, 0); /* + * Note off + */ opl3_command (ioaddr, TEST_REGISTER, ENABLE_WAVE_SELECT); - opl3_command (ioaddr, PERCUSSION_REGISTER, 0x00); /* Melodic mode. */ + opl3_command (ioaddr, PERCUSSION_REGISTER, 0x00); /* + * Melodic mode. + */ return 1; } static int -opl3_kill_note (int dev, int voice, int velocity) +opl3_kill_note (int dev, int voice, int note, int velocity) { struct physical_voice_info *map; if (voice < 0 || voice >= nr_voices) return 0; + voice_alloc->map[voice] = 0; + map = &physical_voices[logical_voices[voice]]; DEB (printk ("Kill note %d\n", voice)); @@ -254,7 +310,9 @@ voices[voice].keyon_byte = 0; voices[voice].bender = 0; - voices[voice].bender_range = 200; /* 200 cents = 2 semitones */ + voices[voice].bender_range = 200; /* + * 200 cents = 2 semitones + */ voices[voice].orig_freq = 0; voices[voice].current_freq = 0; voices[voice].mode = 0; @@ -304,23 +362,56 @@ * it saves a lot of log() calculations. (RH) */ char fm_volume_table[128] = -{-64, -48, -40, -35, -32, -29, -27, -26, /* 0 - 7 */ - -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 */ - -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 */ - 3, 3, 3, 3, 3, 3, 3, 4, /* 80 - 87 */ - 4, 4, 4, 4, 4, 4, 4, 5, /* 88 - 95 */ - 5, 5, 5, 5, 5, 5, 5, 5, /* 96 - 103 */ - 6, 6, 6, 6, 6, 6, 6, 6, /* 104 - 111 */ - 6, 7, 7, 7, 7, 7, 7, 7, /* 112 - 119 */ - 7, 7, 7, 8, 8, 8, 8, 8}; /* 120 - 127 */ +{-64, -48, -40, -35, -32, -29, -27, -26, /* + * 0 - 7 + */ + -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 + */ + -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 + */ + 3, 3, 3, 3, 3, 3, 3, 4, /* + * 80 - 87 + */ + 4, 4, 4, 4, 4, 4, 4, 5, /* + * 88 - 95 + */ + 5, 5, 5, 5, 5, 5, 5, 5, /* + * 96 - 103 + */ + 6, 6, 6, 6, 6, 6, 6, 6, /* + * 104 - 111 + */ + 6, 7, 7, 7, 7, 7, 7, 7, /* + * 112 - 119 + */ + 7, 7, 7, 8, 8, 8, 8, 8}; /* + + * * * * 120 - 127 */ + static void calc_vol (unsigned char *regbyte, int volume) { @@ -361,26 +452,40 @@ return; if (voices[voice].mode == 2) - { /* 2 OP voice */ + { /* + * 2 OP voice + */ vol1 = instr->operators[2]; vol2 = instr->operators[3]; if ((instr->operators[10] & 0x01)) - { /* Additive synthesis */ + { /* + * Additive synthesis + */ calc_vol (&vol1, volume); calc_vol (&vol2, volume); } else - { /* FM synthesis */ + { /* + * FM synthesis + */ 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 */ + { /* + * 4 OP voice + */ int connection; vol1 = instr->operators[2]; @@ -398,7 +503,9 @@ switch (connection) { case 0: - calc_vol (&vol4, volume); /* Just the OP 4 is carrier */ + calc_vol (&vol4, volume); /* + * Just the OP 4 is carrier + */ break; case 1: @@ -417,7 +524,9 @@ calc_vol (&vol4, volume); break; - default:/* Why ?? */ ; + default: /* + * Why ?? + */ ; } opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1); @@ -443,15 +552,26 @@ if (map->voice_mode == 0) return 0; - if (note == 255) /* Just change the volume */ + if (note == 255) /* + * Just change the volume + */ { set_voice_volume (voice, volume); return 0; } - /* Kill previous note before playing */ - opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], 0xff); /* Carrier volume to min */ - opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], 0xff); /* Modulator volume to */ + /* + * Kill previous note before playing + */ + opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], 0xff); /* + * Carrier + * volume to + * min + */ + opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], 0xff); /* + * Modulator + * volume to + */ if (map->voice_mode == 4) { @@ -459,7 +579,10 @@ opl3_command (map->ioaddr, KSL_LEVEL + map->op[3], 0xff); } - opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, 0x00); /* Note off */ + opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, 0x00); /* + * Note + * off + */ instr = active_instrument[voice]; @@ -475,7 +598,9 @@ } if (map->voice_mode == 2 && instr->key == OPL3_PATCH) - return 0; /* Cannot play */ + return 0; /* + * Cannot play + */ voice_mode = map->voice_mode; @@ -486,7 +611,9 @@ voice_shift = (map->ioaddr == left_address) ? 0 : 3; voice_shift += map->voice_num; - if (instr->key != OPL3_PATCH) /* Just 2 OP patch */ + if (instr->key != OPL3_PATCH) /* + * Just 2 OP patch + */ { voice_mode = 2; connection_mask &= ~(1 << voice_shift); @@ -499,26 +626,38 @@ opl3_command (right_address, CONNECTION_SELECT_REGISTER, connection_mask); } - /* Set Sound Characteristics */ + /* + * Set Sound Characteristics + */ opl3_command (map->ioaddr, AM_VIB + map->op[0], instr->operators[0]); opl3_command (map->ioaddr, AM_VIB + map->op[1], instr->operators[1]); - /* Set Attack/Decay */ + /* + * Set Attack/Decay + */ opl3_command (map->ioaddr, ATTACK_DECAY + map->op[0], instr->operators[4]); opl3_command (map->ioaddr, ATTACK_DECAY + map->op[1], instr->operators[5]); - /* Set Sustain/Release */ + /* + * Set Sustain/Release + */ opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[0], instr->operators[6]); opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[1], instr->operators[7]); - /* Set Wave Select */ + /* + * Set Wave Select + */ opl3_command (map->ioaddr, WAVE_SELECT + map->op[0], instr->operators[8]); opl3_command (map->ioaddr, WAVE_SELECT + map->op[1], instr->operators[9]); - /* Set Feedback/Connection */ + /* + * Set Feedback/Connection + */ fpc = instr->operators[10]; if (!(fpc & 0x30)) - fpc |= 0x30; /* Ensure that at least one chn is enabled */ + fpc |= 0x30; /* + * Ensure that at least one chn is enabled + */ opl3_command (map->ioaddr, FEEDBACK_CONNECTION + map->voice_num, fpc); @@ -529,26 +668,38 @@ if (voice_mode == 4) { - /* Set Sound Characteristics */ + /* + * Set Sound Characteristics + */ opl3_command (map->ioaddr, AM_VIB + map->op[2], instr->operators[OFFS_4OP + 0]); opl3_command (map->ioaddr, AM_VIB + map->op[3], instr->operators[OFFS_4OP + 1]); - /* Set Attack/Decay */ + /* + * Set Attack/Decay + */ opl3_command (map->ioaddr, ATTACK_DECAY + map->op[2], instr->operators[OFFS_4OP + 4]); opl3_command (map->ioaddr, ATTACK_DECAY + map->op[3], instr->operators[OFFS_4OP + 5]); - /* Set Sustain/Release */ + /* + * Set Sustain/Release + */ opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[2], instr->operators[OFFS_4OP + 6]); opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[3], instr->operators[OFFS_4OP + 7]); - /* Set Wave Select */ + /* + * Set Wave Select + */ opl3_command (map->ioaddr, WAVE_SELECT + map->op[2], instr->operators[OFFS_4OP + 8]); opl3_command (map->ioaddr, WAVE_SELECT + map->op[3], instr->operators[OFFS_4OP + 9]); - /* Set Feedback/Connection */ + /* + * Set Feedback/Connection + */ fpc = instr->operators[OFFS_4OP + 10]; if (!(fpc & 0x30)) - fpc |= 0x30; /* Ensure that at least one chn is enabled */ + fpc |= 0x30; /* + * Ensure that at least one chn is enabled + */ opl3_command (map->ioaddr, FEEDBACK_CONNECTION + map->voice_num + 3, fpc); } @@ -568,9 +719,13 @@ freq_to_fnum (freq, &block, &fnum); - /* Play note */ + /* + * Play note + */ - data = fnum & 0xff; /* Least significant bits of fnumber */ + 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); @@ -587,8 +742,12 @@ { int f, octave; - /* Converts the note frequency to block and fnum values for the FM chip */ - /* First try to compute the block -value (octave) where the note belongs */ + /* + * Converts the note frequency to block and fnum values for the FM chip + */ + /* + * First try to compute the block -value (octave) where the note belongs + */ f = freq; @@ -630,7 +789,10 @@ * register. The OPL-3 survives with just two INBs */ - OUTB ((unsigned char) (addr & 0xff), io_addr); /* Select register */ + OUTB ((unsigned char) (addr & 0xff), io_addr); /* + * Select register + * + */ if (!opl3_enabled) tenmicrosec (); @@ -638,7 +800,10 @@ for (i = 0; i < 2; i++) INB (io_addr); - OUTB ((unsigned char) (val & 0xff), io_addr + 1); /* Write to register */ + OUTB ((unsigned char) (val & 0xff), io_addr + 1); /* + * Write to register + * + */ if (!opl3_enabled) { @@ -659,26 +824,26 @@ for (i = 0; i < nr_voices; i++) { opl3_command (physical_voices[logical_voices[i]].ioaddr, - KSL_LEVEL + physical_voices[logical_voices[i]].op[0], 0xff); /* OP1 volume to min */ + KSL_LEVEL + physical_voices[logical_voices[i]].op[0], 0xff); opl3_command (physical_voices[logical_voices[i]].ioaddr, - KSL_LEVEL + physical_voices[logical_voices[i]].op[1], 0xff); /* OP2 volume to min */ + KSL_LEVEL + physical_voices[logical_voices[i]].op[1], 0xff); - if (physical_voices[logical_voices[i]].voice_mode == 4) /* 4 OP voice */ + if (physical_voices[logical_voices[i]].voice_mode == 4) { opl3_command (physical_voices[logical_voices[i]].ioaddr, - KSL_LEVEL + physical_voices[logical_voices[i]].op[2], 0xff); /* OP3 volume to min */ + KSL_LEVEL + physical_voices[logical_voices[i]].op[2], 0xff); opl3_command (physical_voices[logical_voices[i]].ioaddr, - KSL_LEVEL + physical_voices[logical_voices[i]].op[3], 0xff); /* OP4 volume to min */ + KSL_LEVEL + physical_voices[logical_voices[i]].op[3], 0xff); } - opl3_kill_note (dev, i, 64); + opl3_kill_note (dev, i, 0, 64); } if (opl3_enabled) { - nr_voices = 18; + voice_alloc->max_voice = nr_voices = 18; for (i = 0; i < 18; i++) logical_voices[i] = i; @@ -699,7 +864,9 @@ return RET_ERROR (EBUSY); opl3_busy = 1; - connection_mask = 0x00; /* Just 2 OP voices */ + connection_mask = 0x00; /* + * Just 2 OP voices + */ if (opl3_enabled) opl3_command (right_address, CONNECTION_SELECT_REGISTER, connection_mask); return 0; @@ -709,7 +876,7 @@ opl3_close (int dev) { opl3_busy = 0; - nr_voices = opl3_enabled ? 18 : 9; + voice_alloc->max_voice = nr_voices = opl3_enabled ? 18 : 9; fm_info.nr_drums = 0; fm_info.perc_mode = 0; @@ -814,13 +981,17 @@ break; } - /* Not implemented yet */ + /* + * Not implemented yet + */ } else { SET_VIBRATO (1); - if ((instr->operators[10] & 0x01)) /* Additive synthesis */ + if ((instr->operators[10] & 0x01)) /* + * Additive synthesis + */ SET_VIBRATO (2); } } @@ -828,41 +999,57 @@ #undef SET_VIBRATO static void -opl3_controller (int dev, int voice, int ctrl_num, int value) +bend_pitch (int dev, int voice, int value) { unsigned char data; int block, fnum, freq; struct physical_voice_info *map; - if (voice < 0 || voice >= nr_voices) - return; - map = &physical_voices[logical_voices[voice]]; if (map->voice_mode == 0) return; + voices[voice].bender = value; + if (!value) + return; + if (!(voices[voice].keyon_byte & 0x20)) + return; /* + * Not keyed on + */ + + freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender, voices[voice].bender_range); + voices[voice].current_freq = freq; + + freq_to_fnum (freq, &block, &fnum); + + 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 + * + */ + voices[voice].keyon_byte = data; + opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, data); +} + +static void +opl3_controller (int dev, int voice, int ctrl_num, int value) +{ + if (voice < 0 || voice >= nr_voices) + return; + switch (ctrl_num) { case CTRL_PITCH_BENDER: - voices[voice].bender = value; - if (!value) - return; - if (!(voices[voice].keyon_byte & 0x20)) - return; /* Not keyed on */ - - freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender, voices[voice].bender_range); - voices[voice].current_freq = freq; - - freq_to_fnum (freq, &block, &fnum); - - 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 */ - voices[voice].keyon_byte = data; - opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, data); + bend_pitch (dev, voice, value); break; case CTRL_PITCH_BENDER_RANGE: @@ -877,9 +1064,76 @@ return RET_ERROR (EINVAL); } +static void +opl3_bender (int dev, int voice, int value) +{ + if (voice < 0 || voice >= nr_voices) + return; + + bend_pitch (dev, voice, value); +} + +static int +opl3_alloc_voice (int dev, int chn, int note, struct voice_alloc_info *alloc) +{ + int i, p, avail_voices; + struct sbi_instrument *instr; + int is4op; + int instr_no; + + if (chn < 0 || chn > 15) + instr_no = 0; + else + instr_no = chn_info[chn].pgm_num; + + instr = &instrmap[instr_no]; + if (instr->channel < 0 || /* Instrument not loaded */ + nr_voices != 12) /* Not in 4 OP mode */ + is4op = 0; + else if (nr_voices == 12) /* 4 OP mode */ + is4op = (instr->key == OPL3_PATCH); + else + is4op = 0; + + if (is4op) + { + p = 0; + avail_voices = 6; + } + else + { + if (nr_voices == 12) /* 4 OP mode. Use the '2 OP only' voices first */ + p = 6; + else + p = 0; + avail_voices = nr_voices; + } + + /* + * Now try to find a free voice + */ + + for (i = 0; i < avail_voices; i++) + { + if (alloc->map[p] == 0) + { + return p; + } + p = (p + 1) % nr_voices; + } + + /* + * Insert some kind of priority mechanism here. + */ + + printk ("OPL3: Out of free voices\n"); + return 0; /* All voices in use. Select the first one. */ +} + static struct synth_operations opl3_operations = { &fm_info, + 0, SYNTH_TYPE_FM, FM_TYPE_ADLIB, opl3_open, @@ -895,7 +1149,9 @@ opl3_controller, opl3_panning, opl3_volume_method, - opl3_patchmgr + opl3_patchmgr, + opl3_bender, + opl3_alloc_voice }; long @@ -906,14 +1162,22 @@ PERMANENT_MALLOC (struct sbi_instrument *, instrmap, SBFM_MAXINSTR * sizeof (*instrmap), mem_start); - synth_devs[num_synths++] = &opl3_operations; + if (num_synths >= MAX_SYNTH_DEV) + printk ("OPL3 Error: Too many synthesizers\n"); + else + { + synth_devs[num_synths++] = &opl3_operations; + voice_alloc = &opl3_operations.alloc; + chn_info = &opl3_operations.chn_info[0]; + } + fm_model = 0; opl3_ok = 1; if (opl3_enabled) { printk (" "); fm_model = 2; - nr_voices = 18; + voice_alloc->max_voice = nr_voices = 18; fm_info.nr_drums = 0; fm_info.capabilities |= SYNTH_CAP_OPL3; #ifndef SCO @@ -927,15 +1191,24 @@ physical_voices[i].ioaddr = right_address; - opl3_command (right_address, OPL3_MODE_REGISTER, OPL3_ENABLE); /* Enable OPL-3 mode */ - opl3_command (right_address, CONNECTION_SELECT_REGISTER, 0x00); /* Select all 2-OP - * voices */ + opl3_command (right_address, OPL3_MODE_REGISTER, OPL3_ENABLE); /* + * Enable + * OPL-3 + * mode + */ + opl3_command (right_address, CONNECTION_SELECT_REGISTER, 0x00); /* + * Select + * all + * 2-OP + * * + * voices + */ } else { printk (" "); fm_model = 1; - nr_voices = 9; + voice_alloc->max_voice = nr_voices = 9; fm_info.nr_drums = 0; for (i = 0; i < 18; i++) diff -u --recursive --new-file v1.1.30/linux/drivers/sound/os.h linux/drivers/sound/os.h --- v1.1.30/linux/drivers/sound/os.h Sun May 1 12:12:35 1994 +++ linux/drivers/sound/os.h Mon Jul 18 09:50:55 1994 @@ -44,8 +44,8 @@ #include #include #include -#include #include +#include typedef char snd_rw_buf; @@ -73,7 +73,7 @@ #define DEFINE_WAIT_QUEUES(name, flag) static struct wait_queue *name = {NULL}; \ static volatile struct snd_wait flag = {{0}} #define RESET_WAIT_QUEUE(q, f) {f.aborting = 0;f.mode = WK_NONE;} -#define PROCESS_ABORTING(q, f) (f.aborting | (current->signal & ~current->blocked)) +#define PROCESS_ABORTING(q, f) (/*f.aborting | */(current->signal & ~current->blocked)) #define SET_ABORT_FLAG(q, f) f.aborting = 1 #define TIMED_OUT(q, f) (f.mode & WK_TIMEOUT) #define DO_SLEEP(q, f, time_limit) \ @@ -141,7 +141,7 @@ #define DEFINE_TIMER(name, proc) \ static struct timer_list name = \ - {NULL, 0, 0, 0, proc} + {NULL, NULL, 0, 0, proc} /* * The ACTIVATE_TIMER requests system to call 'proc' after 'time' ticks. @@ -153,3 +153,9 @@ #define INB inb #define OUTB outb + +/* + * SND_SA_INTERRUPT is required. Otherwise the IRQ number is not passed + * the handler. + */ +#define SND_SA_INTERRUPT diff -u --recursive --new-file v1.1.30/linux/drivers/sound/pas.h linux/drivers/sound/pas.h --- v1.1.30/linux/drivers/sound/pas.h Sun May 1 12:12:36 1994 +++ linux/drivers/sound/pas.h Mon Jul 18 09:50:55 1994 @@ -135,25 +135,25 @@ #define PAS_16D 4 #ifdef DEFINE_TRANSLATIONS - char I_C_2_PCM_DMA_translate[] = /* R W PCM PCM DMA channel value translations */ + unsigned char I_C_2_PCM_DMA_translate[] = /* R W PCM PCM DMA channel value translations */ { 4, 1, 2, 3, 0, 5, 6, 7 }; - char I_C_3_PCM_IRQ_translate[] = /* R W PCM PCM IRQ level value translation */ + unsigned char I_C_3_PCM_IRQ_translate[] = /* R W PCM PCM IRQ level value translation */ { 0, 0, 1, 2, 3, 4, 5, 6, 0, 1, 7, 8, 9, 0, 10, 11 }; - char E_C_MPU401_IRQ_translate[] = /* R W MIDI MPU401 emulation IRQ value translation */ + unsigned char E_C_MPU401_IRQ_translate[] = /* R W MIDI MPU401 emulation IRQ value translation */ { 0x00, 0x00, 0x01, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x01, 0x05, 0x06, 0x07 }; - char E_C_SB_IRQ_translate[] = /* R W PCM SB emulation IRQ translate */ + unsigned char E_C_SB_IRQ_translate[] = /* R W PCM SB emulation IRQ translate */ { 0x00, 0x00, 0x08, 0x10, 0x00, 0x18, 0x00, 0x20, 0x00, 0x08, 0x28, 0x30, 0x38, 0, 0 }; - char E_C_SB_DMA_translate[] = /* R W PCM SB emulation DMA translate */ + unsigned char E_C_SB_DMA_translate[] = /* R W PCM SB emulation DMA translate */ { 0x00, 0x40, 0x80, 0xC0, 0, 0, 0, 0 }; - char O_M_1_to_card[] = /* R W Control Translate (OM1 & 0x0f) to card type */ + unsigned char O_M_1_to_card[] = /* R W Control Translate (OM1 & 0x0f) to card type */ { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 4, 0, 2, 3 }; #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 */ - extern char E_C_MPU401_IRQ_translate[]; /* R W MIDI MPU401 emulation IRQ value translation */ - extern char E_C_SB_IRQ_translate[]; /* R W PCM SB emulation IRQ translate */ - extern char E_C_SB_DMA_translate[]; /* R W PCM SB emulation DMA translate */ - extern char O_M_1_to_card[]; /* R W Control Translate (OM1 & 0x0f) to card type */ + extern unsigned char I_C_2_PCM_DMA_translate[]; /* R W PCM PCM DMA channel value translations */ + extern unsigned char I_C_3_PCM_IRQ_translate[]; /* R W PCM PCM IRQ level value translation */ + extern unsigned char E_C_MPU401_IRQ_translate[]; /* R W MIDI MPU401 emulation IRQ value translation */ + extern unsigned char E_C_SB_IRQ_translate[]; /* R W PCM SB emulation IRQ translate */ + extern unsigned char E_C_SB_DMA_translate[]; /* R W PCM SB emulation DMA translate */ + extern unsigned char O_M_1_to_card[]; /* R W Control Translate (OM1 & 0x0f) to card type */ #endif #define PARALLEL_MIXER 0x078B /* W Mixer Documented for MVD101 as FM Mono Right decode?? */ diff -u --recursive --new-file v1.1.30/linux/drivers/sound/pas2_card.c linux/drivers/sound/pas2_card.c --- v1.1.30/linux/drivers/sound/pas2_card.c Sun May 1 12:12:36 1994 +++ linux/drivers/sound/pas2_card.c Mon Jul 18 09:50:55 1994 @@ -1,5 +1,4 @@ #define _PAS2_CARD_C_ -#define SND_SA_INTERRUPT /* * sound/pas2_card.c * @@ -49,9 +48,15 @@ static char *pas_model_names[] = {"", "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 */ -/* to support other than the default base address */ +/* + * pas_read() and pas_write() are equivalents of INB() and OUTB() + */ +/* + * These routines perform the I/O address translation required + */ +/* + * to support other than the default base address + */ unsigned char pas_read (int ioaddr) @@ -79,7 +84,9 @@ 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) { @@ -143,27 +150,39 @@ config_pas_hw (struct address_info *hw_config) { char ok = 1; + unsigned int_ptrs; /* scsi/sound interrupt pointers */ pas_irq = hw_config->irq; pas_write (0x00, INTERRUPT_MASK); - pas_write (0x36, SAMPLE_COUNTER_CONTROL); /* Local timer control - * register */ - - pas_write (0x36, SAMPLE_RATE_TIMER); /* Sample rate timer (16 bit) */ + pas_write (0x36, SAMPLE_COUNTER_CONTROL); /* + * Local timer control * + * register + */ + + pas_write (0x36, SAMPLE_RATE_TIMER); /* + * Sample rate timer (16 bit) + */ pas_write (0, SAMPLE_RATE_TIMER); - pas_write (0x74, SAMPLE_COUNTER_CONTROL); /* Local timer control - * register */ - - pas_write (0x74, SAMPLE_BUFFER_COUNTER); /* Sample count register (16 - * bit) */ + pas_write (0x74, SAMPLE_COUNTER_CONTROL); /* + * Local timer control * + * register + */ + + pas_write (0x74, SAMPLE_BUFFER_COUNTER); /* + * Sample count register (16 + * * bit) + */ pas_write (0, SAMPLE_BUFFER_COUNTER); pas_write (F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER | F_F_MIXER_UNMUTE | 1, FILTER_FREQUENCY); pas_write (P_C_PCM_DMA_ENABLE | P_C_PCM_MONO | P_C_PCM_DAC_MODE | P_C_MIXER_CROSS_L_TO_L | P_C_MIXER_CROSS_R_TO_R, PCM_CONTROL); - pas_write (S_M_PCM_RESET | S_M_FM_RESET | S_M_SB_RESET | S_M_MIXER_RESET /* | S_M_OPL3_DUAL_MONO */ , SERIAL_MIXER); + pas_write (S_M_PCM_RESET | S_M_FM_RESET | S_M_SB_RESET | S_M_MIXER_RESET /* + * | + * S_M_OPL3_DUAL_MONO + */ , SERIAL_MIXER); pas_write (I_C_1_BOOT_RESET_ENABLE, IO_CONFIGURATION_1); @@ -174,7 +193,9 @@ } else { - pas_write (I_C_3_PCM_IRQ_translate[pas_irq], IO_CONFIGURATION_3); + int_ptrs = pas_read (IO_CONFIGURATION_3); + int_ptrs |= I_C_3_PCM_IRQ_translate[pas_irq] & 0xf; + pas_write (int_ptrs, IO_CONFIGURATION_3); if (!I_C_3_PCM_IRQ_translate[pas_irq]) { printk ("PAS2: Invalid IRQ %d", pas_irq); @@ -209,14 +230,23 @@ #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, 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 (0x18, SYSTEM_CONFIGURATION_3); /* ??? */ - - pas_write (F_F_MIXER_UNMUTE | 0x01, FILTER_FREQUENCY); /* Sets mute off and - * selects filter rate - * of 17.897 kHz */ + 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 || pas_model == PAS_16D) pas_write (8, PRESCALE_DIVIDER); @@ -235,12 +265,20 @@ { unsigned char irq_dma; - /* Turn on Sound Blaster compatibility */ - /* bit 1 = SB emulation */ - /* bit 0 = MPU401 emulation (CDPC only :-( ) */ + /* + * Turn on Sound Blaster compatibility + */ + /* + * bit 1 = SB emulation + */ + /* + * bit 0 = MPU401 emulation (CDPC only :-( ) + */ pas_write (0x02, COMPATIBILITY_ENABLE); - /* "Emulation address" */ + /* + * "Emulation address" + */ pas_write ((sb_config->io_base >> 4) & 0x0f, EMULATION_ADDRESS); if (!E_C_SB_DMA_translate[sb_config->dma]) @@ -277,10 +315,16 @@ * you have something on base port 0x388. SO be forewarned. */ - OUTB (0xBC, MASTER_DECODE); /* Talk to first board */ - OUTB (hw_config->io_base >> 2, MASTER_DECODE); /* Set base address */ + OUTB (0xBC, MASTER_DECODE); /* + * Talk to first board + */ + OUTB (hw_config->io_base >> 2, MASTER_DECODE); /* + * Set base address + */ translat_code = PAS_DEFAULT_BASE ^ hw_config->io_base; - pas_write (1, WAIT_STATE); /* One wait-state */ + pas_write (1, WAIT_STATE); /* + * One wait-state + */ board_id = pas_read (INTERRUPT_MASK); @@ -299,7 +343,9 @@ foo = INB (INTERRUPT_MASK); pas_write (board_id, INTERRUPT_MASK); - if (board_id != foo) /* Not a PAS2 */ + if (board_id != foo) /* + * Not a PAS2 + */ return 0; pas_model = O_M_1_to_card[pas_read (OPERATION_MODE_1) & 0x0f]; @@ -329,8 +375,10 @@ #if !defined(EXCLUDE_SB_EMULATION) && !defined(EXCLUDE_SB) - sb_dsp_disable_midi (); /* The SB emulation don't support - * midi */ + sb_dsp_disable_midi (); /* + * The SB emulation don't support * + * midi + */ #endif #ifndef EXCLUDE_YM3812 diff -u --recursive --new-file v1.1.30/linux/drivers/sound/pas2_midi.c linux/drivers/sound/pas2_midi.c --- v1.1.30/linux/drivers/sound/pas2_midi.c Sun May 1 12:12:36 1994 +++ linux/drivers/sound/pas2_midi.c Mon Jul 18 09:50:55 1994 @@ -62,7 +62,9 @@ return RET_ERROR (EBUSY); } - /* Reset input and output FIFO pointers */ + /* + * Reset input and output FIFO pointers + */ pas_write (M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO, MIDI_CONTROL); @@ -71,7 +73,9 @@ if ((err = pas_set_intr (I_M_MIDI_IRQ_ENABLE)) < 0) return err; - /* Enable input available and output FIFO empty interrupts */ + /* + * Enable input available and output FIFO empty interrupts + */ ctrl = 0; input_opened = 0; @@ -79,20 +83,26 @@ 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; } if (mode == OPEN_WRITE || mode == OPEN_READWRITE) { - ctrl |= M_C_ENA_OUTPUT_IRQ | /* Enable output */ + ctrl |= M_C_ENA_OUTPUT_IRQ | /* + * Enable output + */ M_C_ENA_OUTPUT_HALF_IRQ; } pas_write (ctrl, MIDI_CONTROL); - /* Acknowledge any pending interrupts */ + /* + * Acknowledge any pending interrupts + */ pas_write (0xff, MIDI_STATUS); ofifo_bytes = 0; @@ -108,7 +118,9 @@ pas_midi_close (int dev) { - /* Reset FIFO pointers, disable intrs */ + /* + * Reset FIFO pointers, disable intrs + */ pas_write (M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO, MIDI_CONTROL); pas_remove_intr (I_M_MIDI_IRQ_ENABLE); @@ -122,9 +134,14 @@ 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 */ + return 0; /* + * Upper layer will call again + */ } ofifo_bytes++; @@ -160,14 +177,18 @@ if (!qlen) if (dump_to_midi (midi_byte)) - return 1; /* OK */ + return 1; /* + * OK + */ /* * Put to the local queue */ if (qlen >= 256) - return 0; /* Local queue full */ + return 0; /* + * Local queue full + */ DISABLE_INTR (flags); @@ -210,9 +231,14 @@ return !qlen; } +#define MIDI_SYNTH_NAME "Pro Audio Spectrum Midi" +#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT +#include "midi_synth.h" + static struct midi_operations pas_midi_operations = { {"Pro Audio Spectrum", 0, 0, SNDCARD_PAS}, + &std_midi_synth, pas_midi_open, pas_midi_close, pas_midi_ioctl, @@ -220,14 +246,23 @@ pas_midi_start_read, pas_midi_end_read, pas_midi_kick, - NULL, /* command */ - pas_buffer_status + NULL, /* + * command + */ + pas_buffer_status, + NULL }; long pas_midi_init (long mem_start) { - my_dev = num_midis; + if (num_midis >= MAX_MIDI_DEV) + { + printk ("Sound: Too many midi devices detected\n"); + return mem_start; + } + + std_midi_synth.midi_dev = my_dev = num_midis; midi_devs[num_midis++] = &pas_midi_operations; return mem_start; } @@ -241,9 +276,13 @@ stat = pas_read (MIDI_STATUS); - if (stat & M_S_INPUT_AVAIL) /* Input byte available */ + if (stat & M_S_INPUT_AVAIL) /* + * Input byte available + */ { - incount = pas_read (MIDI_FIFO_STATUS) & 0x0f; /* Input FIFO count */ + incount = pas_read (MIDI_FIFO_STATUS) & 0x0f; /* + * Input FIFO count + */ if (!incount) incount = 16; @@ -253,7 +292,9 @@ midi_input_intr (my_dev, pas_read (MIDI_DATA)); } else - pas_read (MIDI_DATA); /* Flush */ + pas_read (MIDI_DATA); /* + * Flush + */ } if (stat & (M_S_OUTPUT_EMPTY | M_S_OUTPUT_HALF_EMPTY)) @@ -287,7 +328,9 @@ ofifo_bytes = 100; } - pas_write (stat, MIDI_STATUS);/* Acknowledge interrupts */ + pas_write (stat, MIDI_STATUS);/* + * Acknowledge interrupts + */ } #endif diff -u --recursive --new-file v1.1.30/linux/drivers/sound/pas2_mixer.c linux/drivers/sound/pas2_mixer.c --- v1.1.30/linux/drivers/sound/pas2_mixer.c Sun May 1 12:12:37 1994 +++ linux/drivers/sound/pas2_mixer.c Mon Jul 18 09:50:55 1994 @@ -35,11 +35,18 @@ #include "pas.h" -#define TRACE(what) /* (what) */ +#define TRACE(what) /* + * * * (what) */ 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 | \ @@ -52,22 +59,49 @@ static unsigned short levels[SOUND_MIXER_NRDEVICES] = { - 0x3232, /* Master Volume */ - 0x3232, /* Bass */ - 0x3232, /* Treble */ - 0x5050, /* FM */ - 0x4b4b, /* PCM */ - 0x3232, /* PC Speaker */ - 0x4b4b, /* Ext Line */ - 0x4b4b, /* Mic */ - 0x4b4b, /* CD */ - 0x6464, /* Recording monitor */ - 0x4b4b, /* SB PCM */ - 0x6464}; /* Recording level */ + 0x3232, /* + * Master Volume + */ + 0x3232, /* + * Bass + */ + 0x3232, /* + * Treble + */ + 0x5050, /* + * FM + */ + 0x4b4b, /* + * PCM + */ + 0x3232, /* + * PC Speaker + */ + 0x4b4b, /* + * Ext Line + */ + 0x4b4b, /* + * Mic + */ + 0x4b4b, /* + * CD + */ + 0x6464, /* + * Recording monitor + */ + 0x4b4b, /* + * SB PCM + */ + 0x6464}; /* + + * * * * Recording level */ + static int mixer_output (int right_vol, int left_vol, int div, int bits, - int mixer /* Input or output mixer */ ) + int mixer /* + * Input or output mixer + */ ) { int left = left_vol * div / 100; int right = right_vol * div / 100; @@ -81,13 +115,17 @@ */ if (bits & P_M_MV508_MIXER) - { /* Select input or output mixer */ + { /* + * Select input or output mixer + */ left |= mixer; right |= mixer; } 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; @@ -130,7 +168,9 @@ switch (whichDev) { - case SOUND_MIXER_VOLUME: /* Master volume (0-63) */ + case SOUND_MIXER_VOLUME: /* + * Master volume (0-63) + */ levels[whichDev] = mixer_output (right, left, 63, P_M_MV508_MASTER_A, 0); break; @@ -138,40 +178,62 @@ * Note! Bass and Treble are mono devices. Will use just the left * channel. */ - case SOUND_MIXER_BASS: /* Bass (0-12) */ + case SOUND_MIXER_BASS: /* + * Bass (0-12) + */ levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_BASS, 0); break; - case SOUND_MIXER_TREBLE: /* Treble (0-12) */ + case SOUND_MIXER_TREBLE: /* + * Treble (0-12) + */ levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_TREBLE, 0); break; - case SOUND_MIXER_SYNTH: /* Internal synthesizer (0-31) */ + case SOUND_MIXER_SYNTH: /* + * Internal synthesizer (0-31) + */ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_FM, mixer); break; - case SOUND_MIXER_PCM: /* PAS PCM (0-31) */ + case SOUND_MIXER_PCM: /* + * PAS PCM (0-31) + */ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_PCM, mixer); break; - case SOUND_MIXER_ALTPCM: /* SB PCM (0-31) */ + case SOUND_MIXER_ALTPCM: /* + * SB PCM (0-31) + */ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SB, mixer); break; - case SOUND_MIXER_SPEAKER: /* PC speaker (0-31) */ + case SOUND_MIXER_SPEAKER: /* + * PC speaker (0-31) + */ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SPEAKER, mixer); break; - case SOUND_MIXER_LINE: /* External line (0-31) */ + case SOUND_MIXER_LINE: /* + * External line (0-31) + */ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_LINE, mixer); break; - case SOUND_MIXER_CD: /* CD (0-31) */ + case SOUND_MIXER_CD: /* + * CD (0-31) + */ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_CDROM, mixer); break; - case SOUND_MIXER_MIC: /* External microphone (0-31) */ + case SOUND_MIXER_MIC: /* + * External microphone (0-31) + */ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_MIC, mixer); break; - case SOUND_MIXER_IMIX: /* Recording monitor (0-31) (Only available - * on the Output Mixer) */ + case SOUND_MIXER_IMIX: /* + * Recording monitor (0-31) (Only available * + * on the Output Mixer) + */ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_IMIXER, P_M_MV508_OUTPUTMIX); break; - case SOUND_MIXER_RECLEV: /* Recording level (0-15) */ + case SOUND_MIXER_RECLEV: /* + * Recording level (0-15) + */ levels[whichDev] = mixer_output (right, left, 15, P_M_MV508_MASTER_B, 0); break; @@ -199,7 +261,9 @@ if (level) mode_control |= P_M_MV508_LOUDNESS; set_mode (mode_control); - return !!level; /* 0 or 1 */ + return !!level; /* + * 0 or 1 + */ break; case SOUND_MIXER_RECSRC: @@ -226,91 +290,6 @@ /*****/ static int -mixer_set_levels (struct sb_mixer_levels *user_l) -{ -#define cmix(v) ((((v.r*100+7)/15)<<8)| ((v.l*100+7)/15)) - - 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)); - - pas_mixer_set (SOUND_MIXER_VOLUME, cmix (l.master)); - pas_mixer_set (SOUND_MIXER_LINE, cmix (l.line)); - pas_mixer_set (SOUND_MIXER_PCM, cmix (l.voc)); - pas_mixer_set (SOUND_MIXER_ALTPCM, cmix (l.voc)); - pas_mixer_set (SOUND_MIXER_SYNTH, cmix (l.fm)); - pas_mixer_set (SOUND_MIXER_CD, cmix (l.cd)); - pas_mixer_set (SOUND_MIXER_MIC, ((l.mic * 100 + 3) / 7) | (((l.mic * 100 + 3) / 7) << 8)); - 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; - S_BYTE val; - int src; - unsigned long flags; - - 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 (RET_ERROR (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. - */ - - DISABLE_INTR (flags); - - val = (pas_read (PCM_CONTROL) & ~P_C_MIXER_CROSS_FIELD) | P_C_MIXER_CROSS_R_TO_R | P_C_MIXER_CROSS_L_TO_L; - if (!p.dsp_stereo) - val |= (P_C_MIXER_CROSS_R_TO_L | P_C_MIXER_CROSS_L_TO_R); /* Mono */ - pas_write (val, PCM_CONTROL); - - RESTORE_INTR (flags); - - switch (p.record_source) - { - case SRC_CD: - src = SOUND_MASK_CD; - break; - - case SRC_LINE: - src = SOUND_MASK_LINE; - break; - - default: - src = SOUND_MASK_MIC; - break; - } - - pas_mixer_set (SOUND_MIXER_RECSRC, src); - - /* - * setmixer (OUT_FILTER, ((dsp_stereo ? STEREO_DAC : MONO_DAC) | - * (p.filter_output ? FILT_ON : FILT_OFF))); - */ - return (0); -} - -static int getmixer (int dev, int chn) { if (chn == P_M_MV508_RIGHT) @@ -323,73 +302,6 @@ } } -/* Read the current mixer level settings into the user's struct. */ -static int -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.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; - - l.voc.r = ((getmixer (SOUND_MIXER_PCM, P_M_MV508_RIGHT) * 15) + 50) / 100; /* DAC */ - l.voc.l = ((getmixer (SOUND_MIXER_PCM, P_M_MV508_LEFT) * 15) + 50) / 100; - - l.fm.r = ((getmixer (SOUND_MIXER_SYNTH, P_M_MV508_RIGHT) * 15) + 50) / 100; /* FM */ - l.fm.l = ((getmixer (SOUND_MIXER_SYNTH, P_M_MV508_LEFT) * 15) + 50) / 100; - - l.cd.r = ((getmixer (SOUND_MIXER_CD, P_M_MV508_RIGHT) * 15) + 50) / 100; /* CD */ - l.cd.l = ((getmixer (SOUND_MIXER_CD, P_M_MV508_LEFT) * 15) + 50) / 100; - - l.mic = ((getmixer (SOUND_MIXER_MIC, P_M_MV508_LEFT) * 7) + 50) / 100; /* Microphone */ - - 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; - - switch (rec_devices) - { - case SOUND_MASK_CD: - params.record_source = SRC_CD; - break; - - case SOUND_MASK_LINE: - params.record_source = SRC_LINE; - break; - - case SOUND_MASK_MIC: - params.record_source = SRC_MIC; - break; - - default: - params.record_source = SRC_MIC; - pas_mixer_set (SOUND_MIXER_RECSRC, SOUND_MASK_MIC); /* Adjust */ - } - - params.hifreq_filter = OFF; - params.filter_input = OFF; - params.filter_output = OFF; - - val = INB (PCM_CONTROL); - params.dsp_stereo = ((val & P_C_MIXER_CROSS_FIELD) == (P_C_MIXER_CROSS_L_TO_L | P_C_MIXER_CROSS_R_TO_R)); - - IOCTL_TO_USER ((char *) user_params, 0, (char *) ¶ms, sizeof (params)); - return (0); -} - -/*****/ - static void pas_mixer_reset (void) { @@ -413,7 +325,9 @@ if (cmd & IOC_IN) return IOCTL_OUT (arg, pas_mixer_set (cmd & 0xff, IOCTL_IN (arg))); else - { /* Read parameters */ + { /* + * Read parameters + */ switch (cmd & 0xff) { @@ -435,11 +349,15 @@ break; case SOUND_MIXER_CAPS: - return IOCTL_OUT (arg, 0); /* No special capabilities */ + return IOCTL_OUT (arg, 0); /* + * No special capabilities + */ break; case SOUND_MIXER_MUTE: - return IOCTL_OUT (arg, 0); /* No mute yet */ + return IOCTL_OUT (arg, 0); /* + * No mute yet + */ break; case SOUND_MIXER_ENHANCE: @@ -459,27 +377,6 @@ } } } - else - { - switch (cmd) - { - case MIXER_IOCTL_SET_LEVELS: - mixer_set_levels ((struct sb_mixer_levels *) arg); - return mixer_get_levels ((struct sb_mixer_levels *) arg); - case MIXER_IOCTL_SET_PARAMS: - mixer_set_params ((struct sb_mixer_params *) arg); - return mixer_get_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: - pas_mixer_reset (); - return (0); - default: - return RET_ERROR (EINVAL); - } - } return RET_ERROR (EINVAL); } @@ -493,7 +390,8 @@ { pas_mixer_reset (); - mixer_devs[num_mixers++] = &pas_mixer_operations; + if (num_mixers < MAX_MIXER_DEV) + mixer_devs[num_mixers++] = &pas_mixer_operations; return 1; } diff -u --recursive --new-file v1.1.30/linux/drivers/sound/pas2_pcm.c linux/drivers/sound/pas2_pcm.c --- v1.1.30/linux/drivers/sound/pas2_pcm.c Sun May 1 12:12:37 1994 +++ linux/drivers/sound/pas2_pcm.c Mon Jul 18 09:50:55 1994 @@ -36,17 +36,20 @@ #if !defined(EXCLUDE_PAS) && !defined(EXCLUDE_AUDIO) -#define TRACE(WHAT) /* (WHAT) */ +#define TRACE(WHAT) /* + * * * (WHAT) */ #define PAS_PCM_INTRBITS (0x08) -/* Sample buffer timer interrupt enable */ +/* + * Sample buffer timer interrupt enable + */ #define PCM_NON 0 #define PCM_DAC 1 #define PCM_ADC 2 static unsigned long pcm_speed = 0; /* sampling rate */ -static unsigned char pcm_channels = 1; /* channels/sample (1 or 2) */ +static unsigned char pcm_channels = 1; /* channels (1 or 2) */ static unsigned char pcm_bits = 8; /* bits/sample (8 or 16) */ static unsigned char pcm_filter = 0; /* filter FLAG */ static unsigned char pcm_mode = PCM_NON; @@ -65,7 +68,7 @@ if (arg < 5000) arg = 5000; - foo = 1193180 / arg; + foo = (1193180 + (arg / 2)) / arg; arg = 1193180 / foo; if (pcm_channels & 2) @@ -75,6 +78,31 @@ tmp = pas_read (FILTER_FREQUENCY); + /* + * Set anti-aliasing filters according to sample rate. You reall *NEED* + * to enable this feature for all normal recording unless you want to + * experiment with aliasing effects. + * These filters apply to the selected "recording" source. + * I (pfw) don't know the encoding of these 5 bits. The values shown + * come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/. +*/ +#if !defined NO_AUTO_FILTER_SET + tmp &= 0xe0; + if (pcm_speed >= 2 * 17897) + tmp |= 0x21; + else if (pcm_speed >= 2 * 15909) + tmp |= 0x22; + else if (pcm_speed >= 2 * 11931) + tmp |= 0x29; + else if (pcm_speed >= 2 * 8948) + tmp |= 0x31; + else if (pcm_speed >= 2 * 5965) + tmp |= 0x39; + else if (pcm_speed >= 2 * 2982) + tmp |= 0x24; + pcm_filter = tmp; +#endif + DISABLE_INTR (flags); pas_write (tmp & ~(F_F_PCM_RATE_COUNTER | F_F_PCM_BUFFER_COUNTER), FILTER_FREQUENCY); @@ -100,7 +128,9 @@ 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; @@ -159,7 +189,7 @@ return IOCTL_OUT (arg, pcm_channels); break; - case SNDCTL_DSP_SAMPLESIZE: + case SNDCTL_DSP_SETFMT: if (local) return pcm_set_bits (arg); return IOCTL_OUT (arg, pcm_set_bits (IOCTL_IN (arg))); @@ -170,7 +200,9 @@ return pcm_bits; return IOCTL_OUT (arg, pcm_bits); - case SOUND_PCM_WRITE_FILTER: /* NOT YET IMPLEMENTED */ + case SOUND_PCM_WRITE_FILTER: /* + * NOT YET IMPLEMENTED + */ if (IOCTL_IN (arg) > 1) return IOCTL_OUT (arg, RET_ERROR (EINVAL)); break; @@ -205,7 +237,7 @@ if ((err = pas_set_intr (PAS_PCM_INTRBITS)) < 0) return err; - if (!DMAbuf_open_dma (dev)) + if (DMAbuf_open_dma (dev) < 0) { pas_remove_intr (PAS_PCM_INTRBITS); return RET_ERROR (EBUSY); @@ -242,13 +274,15 @@ TRACE (printk ("pas2_pcm.c: static void pas_pcm_output_block(char *buf = %P, int count = %X)\n", buf, count)); cnt = count; - if (sound_dsp_dmachan[dev] > 3) + if (audio_devs[dev]->dmachan > 3) cnt >>= 1; - if (sound_dma_automode[dev] && + if (audio_devs[dev]->flags & DMA_AUTOMODE && intrflag && cnt == pcm_count) - return; /* Auto mode on. No need to react */ + return; /* + * Auto mode on. No need to react + */ DISABLE_INTR (flags); @@ -258,7 +292,7 @@ if (restart_dma) DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); - if (sound_dsp_dmachan[dev] > 3) + if (audio_devs[dev]->dmachan > 3) count >>= 1; if (count != pcm_count) @@ -289,20 +323,22 @@ TRACE (printk ("pas2_pcm.c: static void pas_pcm_start_input(char *buf = %P, int count = %X)\n", buf, count)); cnt = count; - if (sound_dsp_dmachan[dev] > 3) + if (audio_devs[dev]->dmachan > 3) cnt >>= 1; - if (sound_dma_automode[my_devnum] && + if (audio_devs[my_devnum]->flags & DMA_AUTOMODE && intrflag && cnt == pcm_count) - return; /* Auto mode on. No need to react */ + return; /* + * Auto mode on. No need to react + */ DISABLE_INTR (flags); if (restart_dma) DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); - if (sound_dsp_dmachan[dev] > 3) + if (audio_devs[dev]->dmachan > 3) count >>= 1; if (count != pcm_count) @@ -337,7 +373,9 @@ static struct audio_operations pas_pcm_operations = { "Pro Audio Spectrum", - NOTHING_SPECIAL, + DMA_AUTOMODE, + AFMT_U8 | AFMT_S16_LE, + NULL, pas_pcm_open, pas_pcm_close, pas_pcm_output_block, @@ -346,9 +384,9 @@ pas_pcm_prepare_for_input, pas_pcm_prepare_for_output, pas_pcm_reset, - pas_pcm_reset, /* halt_xfer */ - NULL, /* has_output_drained */ - NULL /* copy_from_user */ + pas_pcm_reset, + NULL, + NULL }; long @@ -362,28 +400,12 @@ pcm_set_speed (DSP_DEFAULT_SPEED); - if (num_dspdevs < MAX_DSP_DEV) + if (num_audiodevs < MAX_AUDIO_DEV) { - 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; - sound_buffsizes[my_devnum] = 2 * 65536; - sound_dma_automode[my_devnum] = 1; - } - else - { - sound_buffcounts[my_devnum] = 1; - 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 + audio_devs[my_devnum = num_audiodevs++] = &pas_pcm_operations; + audio_devs[my_devnum]->dmachan = hw_config->dma; + audio_devs[my_devnum]->buffcount = 1; + audio_devs[my_devnum]->buffsize = 2 * DSP_BUFFSIZE; } else printk ("PAS2: Too many PCM devices available\n"); @@ -394,14 +416,16 @@ void pas_pcm_interrupt (unsigned char status, int cause) { - if (cause == 1) /* PCM buffer done */ + if (cause == 1) /* + * PCM buffer done + */ { /* * Halt the PCM first. Otherwise we don't have time to start a new * block before the PCM chip proceeds to the next sample */ - if (!sound_dma_automode[my_devnum]) + if (!(audio_devs[my_devnum]->flags & DMA_AUTOMODE)) { pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE, PCM_CONTROL); diff -u --recursive --new-file v1.1.30/linux/drivers/sound/patmgr.c linux/drivers/sound/patmgr.c --- v1.1.30/linux/drivers/sound/patmgr.c Sun May 1 12:12:38 1994 +++ linux/drivers/sound/patmgr.c Mon Jul 18 09:50:55 1994 @@ -67,7 +67,9 @@ pmgr_release (int dev) { - if (mbox[dev]) /* Killed in action. Inform the client */ + if (mbox[dev]) /* + * Killed in action. Inform the client + */ { mbox[dev]->key = PM_ERROR; diff -u --recursive --new-file v1.1.30/linux/drivers/sound/pss.c linux/drivers/sound/pss.c --- v1.1.30/linux/drivers/sound/pss.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/pss.c Mon Jul 18 09:50:55 1994 @@ -0,0 +1,924 @@ +/* Marc.Hoffman@analog.com + + This is a pss driver. + + it is based on Greg.Yukna@analog.com @file{host} for DOG + + Unfortunately I can't distribute the ld file needed to + make the pss card to emulate the SB stuff. + + I have provided a simple interface to the PSS unlike the + DOG version. to download a new algorithim just cat it to + /dev/pss 14,9. + + You really need to rebuild this with the synth.ld file + + get the .ld from your dos directory maybe + voyetra\dsp001.ld + + ld2inc < synth.ld > synth-ld.h + (make config does the same). + + rebuild + + Okay if you blow things away no problem just + + main(){ioctl(open("/dev/pss"),SNDCTL_PSS_RESET)}; + + and everything will be okay. + + At first I was going to wory about applications that were using + the sound stuff and disallow the use of /dev/pss. But for + now I figured it doesn't matter. + + And if you change algos all the other applications running die off + due to DMA problems. Yeah just pull the plug and watch em die. + + If the registers get hosed + main(){ioctl(open("/dev/pss"),SNDCTL_PSS_SETUP_REGISTERS)}; + + Probably everything else can be done via mmap + + Oh if you want to develope code for the ADSP-21xx or Program the + 1848 just send me mail and I will hook you up. + + marc.hoffman@analog.com + + */ +#include "sound_config.h" + +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_PSS) + +#ifndef PSS_MSS_BASE +#define PSS_MSS_BASE 0 +#endif + +#ifndef PSS_MPU_BASE +#define PSS_MPU_BASE 0 +#endif + +#ifndef PSS_MPU_IRQ +#define PSS_MPU_IRQ 0 +#endif + +#undef DEB +#define DEB(x) x + +#include "pss.h" + +static int pss_ok = 0; +static int sb_ok = 0; + +static int pss_base; +static int pss_irq; +static int pss_dma; + +static int gamePort = 0; + +static int sbInt; +static int cdPol; +static int cdAddr = 0; /* 0x340; */ +static int cdInt = 10; + +/* Define these by hand in local.h */ +static int wssAddr = PSS_MSS_BASE; +static int midiAddr = PSS_MPU_BASE; +static int midiInt = PSS_MPU_IRQ; + +static int SoundPortAddress; +static int SoundPortData; +static int speaker = 1; + + +static struct pss_speaker default_speaker = +{0, 0, 0, PSS_STEREO}; + +DEFINE_WAIT_QUEUE (pss_sleeper, pss_sleep_flag); + +#include "synth-ld.h" + +static int pss_download_boot (unsigned char *block, int size); +static int pss_reset_dsp (void); + +static inline void +pss_outpw (unsigned short port, unsigned short value) +{ + __asm__ __volatile__ ("outw %w0, %w1" + : /* no outputs */ + :"a" (value), "d" (port)); +} + +static inline unsigned int +pss_inpw (unsigned short port) +{ + unsigned int _v; + __asm__ __volatile__ ("inw %w1,%w0" + :"=a" (_v):"d" (port), "0" (0)); + + return _v; +} + +static void +PSS_write (int data) +{ + 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 + * 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++) + { + if (pss_inpw (pss_base + PSS_STATUS) & PSS_WRITE_EMPTY) + { + pss_outpw (pss_base + PSS_DATA, data); + return; + } + } + printk ("PSS: DSP Command (%04x) Timeout.\n", data); + printk ("IRQ conflict???\n"); +} + + +static void +pss_setaddr (int addr, int configAddr) +{ + int val; + + val = pss_inpw (configAddr); + val &= ADDR_MASK; + val |= (addr << 4); + pss_outpw (configAddr, val); +} + +/*_____ pss_checkint + This function tests an interrupt number to see if + it is availible. It takes the interrupt button + as it's argument and returns TRUE if the interrupt + is ok. +*/ +static int +pss_checkint (int intNum) +{ + int val; + int ret; + int i; + + /*_____ Set the interrupt bits */ + switch (intNum) + { + case 3: + val = pss_inpw (pss_base + PSS_CONFIG); + val &= INT_MASK; + val |= INT_3_BITS; + pss_outpw (pss_base + PSS_CONFIG, val); + break; + case 5: + val = pss_inpw (pss_base + PSS_CONFIG); + val &= INT_MASK; + val |= INT_5_BITS; + pss_outpw (pss_base + PSS_CONFIG, val); + break; + case 7: + val = pss_inpw (pss_base + PSS_CONFIG); + val &= INT_MASK; + val |= INT_7_BITS; + pss_outpw (pss_base + PSS_CONFIG, val); + break; + case 9: + val = pss_inpw (pss_base + PSS_CONFIG); + val &= INT_MASK; + val |= INT_9_BITS; + pss_outpw (pss_base + PSS_CONFIG, val); + break; + case 10: + val = pss_inpw (pss_base + PSS_CONFIG); + val &= INT_MASK; + val |= INT_10_BITS; + pss_outpw (pss_base + PSS_CONFIG, val); + break; + case 11: + val = pss_inpw (pss_base + PSS_CONFIG); + val &= INT_MASK; + val |= INT_11_BITS; + pss_outpw (pss_base + PSS_CONFIG, val); + break; + case 12: + val = pss_inpw (pss_base + PSS_CONFIG); + val &= INT_MASK; + val |= INT_12_BITS; + pss_outpw (pss_base + PSS_CONFIG, val); + break; + default: + printk ("unknown interupt selected. %d\n", intNum); + return 0; + } + + /*_____ Set the interrupt test bit */ + val = pss_inpw (pss_base + PSS_CONFIG); + val |= INT_TEST_BIT; + pss_outpw (pss_base + PSS_CONFIG, val); + + /*_____ Check if the interrupt is in use */ + /*_____ Do it a few times in case there is a delay */ + ret = 0; + for (i = 0; i < 5; i++) + { + val = pss_inpw (pss_base + PSS_CONFIG); + if (val & INT_TEST_PASS) + { + ret = 1; + break; + } + } + /*_____ Clear the Test bit and the interrupt bits */ + val = pss_inpw (pss_base + PSS_CONFIG); + val &= INT_TEST_BIT_MASK; + val &= INT_MASK; + pss_outpw (pss_base + PSS_CONFIG, val); + return (ret); +} + +/*____ pss_setint + This function sets the correct bits in the + configuration register to + enable the chosen interrupt. +*/ +static void +pss_setint (int intNum, int configAddress) +{ + int val; + + switch (intNum) + { + case 0: + val = pss_inpw (configAddress); + val &= INT_MASK; + pss_outpw (configAddress, val); + break; + case 3: + val = pss_inpw (configAddress); + val &= INT_MASK; + val |= INT_3_BITS; + pss_outpw (configAddress, val); + break; + case 5: + val = pss_inpw (configAddress); + val &= INT_MASK; + val |= INT_5_BITS; + pss_outpw (configAddress, val); + break; + case 7: + val = pss_inpw (configAddress); + val &= INT_MASK; + val |= INT_7_BITS; + pss_outpw (configAddress, val); + break; + case 9: + val = pss_inpw (configAddress); + val &= INT_MASK; + val |= INT_9_BITS; + pss_outpw (configAddress, val); + break; + case 10: + val = pss_inpw (configAddress); + val &= INT_MASK; + val |= INT_10_BITS; + pss_outpw (configAddress, val); + break; + case 11: + val = pss_inpw (configAddress); + val &= INT_MASK; + val |= INT_11_BITS; + pss_outpw (configAddress, val); + break; + case 12: + val = pss_inpw (configAddress); + val &= INT_MASK; + val |= INT_12_BITS; + pss_outpw (configAddress, val); + break; + default: + printk ("pss_setint unkown int\n"); + } +} + + +/*____ pss_setsbint + This function sets the correct bits in the + SoundBlaster configuration PSS register to + enable the chosen interrupt. + It takes a interrupt button as its argument. +*/ +static void +pss_setsbint (int intNum) +{ + int val; + int sbConfigAddress; + + sbConfigAddress = pss_base + SB_CONFIG; + switch (intNum) + { + case 3: + val = pss_inpw (sbConfigAddress); + val &= INT_MASK; + val |= INT_3_BITS; + pss_outpw (sbConfigAddress, val); + break; + case 5: + val = pss_inpw (sbConfigAddress); + val &= INT_MASK; + val |= INT_5_BITS; + pss_outpw (sbConfigAddress, val); + break; + case 7: + val = pss_inpw (sbConfigAddress); + val &= INT_MASK; + val |= INT_7_BITS; + pss_outpw (sbConfigAddress, val); + break; + default: + printk ("pss_setsbint: unknown_int\n"); + } +} + +/*____ pss_setsbdma + This function sets the correct bits in the + SoundBlaster configuration PSS register to + enable the chosen DMA channel. + It takes a DMA button as its argument. +*/ +static void +pss_setsbdma (int dmaNum) +{ + int val; + int sbConfigAddress; + + sbConfigAddress = pss_base + SB_CONFIG; + + switch (dmaNum) + { + case 1: + val = pss_inpw (sbConfigAddress); + val &= DMA_MASK; + val |= DMA_1_BITS; + pss_outpw (sbConfigAddress, val); + break; + default: + printk ("Personal Sound System ERROR! pss_setsbdma: unknown_dma\n"); + } +} + +/*____ pss_setwssdma + This function sets the correct bits in the + WSS configuration PSS register to + enable the chosen DMA channel. + It takes a DMA button as its argument. +*/ +static void +pss_setwssdma (int dmaNum) +{ + int val; + int wssConfigAddress; + + wssConfigAddress = pss_base + PSS_WSS_CONFIG; + + switch (dmaNum) + { + case 0: + val = pss_inpw (wssConfigAddress); + val &= DMA_MASK; + val |= DMA_0_BITS; + pss_outpw (wssConfigAddress, val); + break; + case 1: + val = pss_inpw (wssConfigAddress); + val &= DMA_MASK; + val |= DMA_1_BITS; + pss_outpw (wssConfigAddress, val); + break; + case 3: + val = pss_inpw (wssConfigAddress); + val &= DMA_MASK; + val |= DMA_3_BITS; + pss_outpw (wssConfigAddress, val); + break; + default: + printk ("Personal Sound System ERROR! pss_setwssdma: unknown_dma\n"); + } +} + + +/*_____ SetSpeakerOut + This function sets the Volume, Bass, Treble and Mode of + the speaker out channel. + */ +void +pss_setspeaker (struct pss_speaker *spk) +{ + PSS_write (SET_MASTER_COMMAND); + if (spk->volume > PHILLIPS_VOL_MAX) + spk->volume = PHILLIPS_VOL_MAX; + if (spk->volume < PHILLIPS_VOL_MIN) + spk->volume = PHILLIPS_VOL_MIN; + + PSS_write (MASTER_VOLUME_LEFT + | (PHILLIPS_VOL_CONSTANT + spk->volume / PHILLIPS_VOL_STEP)); + PSS_write (SET_MASTER_COMMAND); + PSS_write (MASTER_VOLUME_RIGHT + | (PHILLIPS_VOL_CONSTANT + spk->volume / PHILLIPS_VOL_STEP)); + + if (spk->bass > PHILLIPS_BASS_MAX) + spk->bass = PHILLIPS_BASS_MAX; + if (spk->bass < PHILLIPS_BASS_MIN) + spk->bass = PHILLIPS_BASS_MIN; + PSS_write (SET_MASTER_COMMAND); + PSS_write (MASTER_BASS + | (PHILLIPS_BASS_CONSTANT + spk->bass / PHILLIPS_BASS_STEP)); + + if (spk->treb > PHILLIPS_TREBLE_MAX) + spk->treb = PHILLIPS_TREBLE_MAX; + if (spk->treb < PHILLIPS_TREBLE_MIN) + spk->treb = PHILLIPS_TREBLE_MIN; + PSS_write (SET_MASTER_COMMAND); + PSS_write (MASTER_TREBLE + | (PHILLIPS_TREBLE_CONSTANT + spk->treb / PHILLIPS_TREBLE_STEP)); + + PSS_write (SET_MASTER_COMMAND); + PSS_write (MASTER_SWITCH | spk->mode); +} + +static void +pss_init1848 (void) +{ + /*_____ Wait for 1848 to init */ + while (INB (SoundPortAddress) & SP_IN_INIT); + + /*_____ Wait for 1848 to autocal */ + OUTB (SoundPortAddress, SP_TEST_AND_INIT); + while (INB (SoundPortData) & AUTO_CAL_IN_PROG); +} + +static int +pss_configure_registers_to_look_like_sb (void) +{ + pss_setaddr (wssAddr, pss_base + PSS_WSS_CONFIG); + + SoundPortAddress = wssAddr + 4; + SoundPortData = wssAddr + 5; + + DEB (printk ("Turning Game Port %s.\n", + gamePort ? "On" : "Off")); + + /*_____ Turn on the Game port */ + if (gamePort) + pss_outpw (pss_base + PSS_STATUS, + pss_inpw (pss_base + PSS_STATUS) | GAME_BIT); + else + pss_outpw (pss_base + PSS_STATUS, + pss_inpw (pss_base + PSS_STATUS) & GAME_BIT_MASK); + + + DEB (printk ("PSS attaching base %x irq %d dma %d\n", + pss_base, pss_irq, pss_dma)); + + /* Check if sb is enabled if it is check the interrupt */ + pss_outpw (pss_base + SB_CONFIG, 0); + + if (pss_irq != 0) + { + DEB (printk ("PSS Emulating Sound Blaster ADDR %04x\n", pss_base)); + DEB (printk ("PSS SBC: attaching base %x irq %d dma %d\n", + SBC_BASE, SBC_IRQ, SBC_DMA)); + + if (pss_checkint (SBC_IRQ) == 0) + { + printk ("PSS! attach: int_error\n"); + return 0; + } + + pss_setsbint (SBC_IRQ); + pss_setsbdma (SBC_DMA); + sb_ok = 1; + } + else + { + sb_ok = 0; + printk ("PSS: sound blaster error init\n"); + } + + /* Check if cd is enabled if it is check the interrupt */ + pss_outpw (pss_base + CD_CONFIG, 0); + + if (cdAddr != 0) + { + DEB (printk ("PSS:CD drive %x irq: %d", cdAddr, cdInt)); + if (cdInt != 0) + { + if (pss_checkint (cdInt) == 0) + { + printk ("Can't allocate cdInt %d\n", cdInt); + } + else + { + int val; + + printk ("CD poll "); + pss_setaddr (cdAddr, pss_base + CD_CONFIG); + pss_setint (cdInt, pss_base + CD_CONFIG); + + /* set the correct bit in the + configuration register to + set the irq polarity for the CD-Rom. + NOTE: This bit is in the address config + field, It must be configured after setting + the CD-ROM ADDRESS!!! */ + val = pss_inpw (pss_base + CD_CONFIG); + pss_outpw (pss_base + CD_CONFIG, 0); + val &= CD_POL_MASK; + if (cdPol) + val |= CD_POL_BIT; + pss_outpw (pss_base + CD_CONFIG, val); + } + } + } + + /* Check if midi is enabled if it is check the interrupt */ + pss_outpw (pss_base + MIDI_CONFIG, 0); + if (midiAddr != 0) + { + printk ("midi init %x %d\n", midiAddr, midiInt); + if (pss_checkint (midiInt) == 0) + { + printk ("midi init int error %x %d\n", midiAddr, midiInt); + } + else + { + pss_setaddr (midiAddr, pss_base + MIDI_CONFIG); + pss_setint (midiInt, pss_base + MIDI_CONFIG); + } + } + return 1; +} + +long +attach_pss (long mem_start, struct address_info *hw_config) +{ + if (pss_ok) + { + if (hw_config) + { + printk (" "); + } + + return mem_start; + } + + pss_ok = 1; + + if (pss_configure_registers_to_look_like_sb () == 0) + return mem_start; + + if (sb_ok) + if (pss_synthLen + && pss_download_boot (pss_synth, pss_synthLen)) + { + if (speaker) + pss_setspeaker (&default_speaker); + pss_ok = 1; + } + else + pss_reset_dsp (); + + return mem_start; +} + +int +probe_pss (struct address_info *hw_config) +{ + pss_base = hw_config->io_base; + pss_irq = hw_config->irq; + pss_dma = hw_config->dma; + + if ((pss_inpw (pss_base + 4) & 0xff00) == 0x4500) + { + attach_pss (0, hw_config); + return 1; + } + printk (" fail base %x irq %d dma %d\n", pss_base, pss_irq, pss_dma); + return 0; +} + + +static int +pss_reattach (void) +{ + pss_ok = 0; + attach_pss (0, 0); + return 1; +} + +static int +pss_reset_dsp () +{ + unsigned long i, limit = GET_TIME () + 10; + + pss_outpw (pss_base + PSS_CONTROL, 0x2000); + + for (i = 0; i < 32768 && GET_TIME () < limit; i++) + pss_inpw (pss_base + PSS_CONTROL); + + pss_outpw (pss_base + PSS_CONTROL, 0x0000); + + return 1; +} + + +static int +pss_download_boot (unsigned char *block, int size) +{ + int i, limit, val, count; + + printk ("PSS: downloading boot code synth.ld... "); + + /*_____ Warn DSP software that a boot is coming */ + pss_outpw (pss_base + PSS_DATA, 0x00fe); + + limit = GET_TIME () + 10; + + for (i = 0; i < 32768 && GET_TIME () < limit; i++) + if (pss_inpw (pss_base + PSS_DATA) == 0x5500) + break; + + pss_outpw (pss_base + PSS_DATA, *block++); + + pss_reset_dsp (); + printk ("start "); + + count = 1; + while (1) + { + int j; + + for (j = 0; j < 327670; j++) + { + /*_____ Wait for BG to appear */ + if (pss_inpw (pss_base + PSS_STATUS) & PSS_FLAG3) + break; + } + + if (j == 327670) + { + /* It's ok we timed out when the file was empty */ + if (count >= size) + break; + else + { + printk ("\nPSS: DownLoad timeout problems, byte %d=%d\n", + count, size); + return 0; + } + } + /*_____ Send the next byte */ + pss_outpw (pss_base + PSS_DATA, *block++); + count++; + } + + /*_____ Why */ + pss_outpw (pss_base + PSS_DATA, 0); + + limit = GET_TIME () + 10; + for (i = 0; i < 32768 && GET_TIME () < limit; i++) + val = pss_inpw (pss_base + PSS_STATUS); + + printk ("downloaded\n"); + + limit = GET_TIME () + 10; + for (i = 0; i < 32768 && GET_TIME () < limit; i++) + { + val = pss_inpw (pss_base + PSS_STATUS); + if (val & 0x4000) + break; + } + + /* now read the version */ + for (i = 0; i < 32000; i++) + { + val = pss_inpw (pss_base + PSS_STATUS_REG); + if (val & PSS_READ_FULL) + break; + } + if (i == 32000) + return 0; + + val = pss_inpw (pss_base + PSS_DATA_REG); + + return 1; +} + + +/* The following is a simple device driver for the pss. + All I really care about is comunication to and from the pss. + + The ability to reinitialize the This will be + default when release is choosen. + + SNDCTL_PSS_DOWNLOAD: + + Okay we need to creat new minor numbers for the + DOWNLOAD functionality. + + 14,0x19 -- /dev/pssld where a read operation would output the + current ld to user space + where a write operation would effectively + download a new ld. + + 14,0x09 -- /dev/psecho would open up a comunication path to the + esc614 asic. Given the ability to send + messages to the asic and recive messages too. + + All messages would get read and written in the + same manner. It would be up to the application + and the ld to maintain a relationship + of what the messages mean. + + for this device we need to implement select. */ +#define CODE_BUFFER_LEN (64*1024) +static char *code_buffer; +static int code_length; + +static int lock_pss = 0; + +int +pss_open (int dev, struct fileinfo *file) +{ + int mode; + + DEB (printk ("pss_open\n")); + + if (pss_ok == 0) + return RET_ERROR (EIO); + + if (lock_pss) + return 0; + + lock_pss = 1; + + dev = dev >> 4; + mode = file->mode & O_ACCMODE; + if (mode == O_WRONLY) + { + printk ("pss-open for WRONLY\n"); + code_length = 0; + } + + RESET_WAIT_QUEUE (pss_sleeper, pss_sleep_flag); + return 1; +} + +void +pss_release (int dev, struct fileinfo *file) +{ + int mode; + + DEB (printk ("pss_release\n")); + if (pss_ok == 0) + return RET_ERROR (EIO); + + dev = dev >> 4; + mode = file->mode & O_ACCMODE; + if (mode == O_WRONLY && code_length > 0) + { +#ifdef linux + /* This just allows interrupts while the conversion is running */ + __asm__ ("sti"); +#endif + if (!pss_download_boot (code_buffer, code_length)) + { + pss_reattach (); + } + } + lock_pss = 0; +} + +int +pss_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) +{ + int c, p; + + DEB (printk ("pss_read\n")); + if (pss_ok == 0) + return RET_ERROR (EIO); + + dev = dev >> 4; + p = 0; + c = count; + + return count - c; +} + +int +pss_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) +{ + DEB (printk ("pss_write\n")); + if (pss_ok == 0) + return RET_ERROR (EIO); + dev = dev >> 4; + + if (count) /* Flush output */ + { + COPY_FROM_USER (&code_buffer[code_length], buf, 0, count); + code_length += count; + } + return count; +} + + +int +pss_ioctl (int dev, struct fileinfo *file, + unsigned int cmd, unsigned int arg) +{ + DEB (printk ("pss_ioctl dev=%d cmd=%x\n", dev, cmd)); + if (pss_ok == 0) + return RET_ERROR (EIO); + + dev = dev >> 4; + + switch (cmd) + { + case SNDCTL_PSS_RESET: + pss_reattach (); + return 1; + + case SNDCTL_PSS_SETUP_REGISTERS: + pss_configure_registers_to_look_like_sb (); + return 1; + + case SNDCTL_PSS_SPEAKER: + { + struct pss_speaker params; + COPY_FROM_USER (¶ms, (char *) arg, 0, sizeof (struct pss_speaker)); + + pss_setspeaker (¶ms); + return 0; + } + default: + return RET_ERROR (EIO); + } +} + +/* This is going to be used to implement + waiting on messages sent from the DSP and to the + DSP when comunication is used via the pss directly. + + We need to find out if the pss can generate a diffrent + interupt other than the one it has been setup for. + + This way we can carry on a conversation with the pss + on a seprate chanel. This would be usefull for debugging. */ + +pss_select (int dev, struct fileinfo * file, int sel_type, select_table * wait) +{ + return 0; + if (pss_ok == 0) + return RET_ERROR (EIO); + + dev = dev >> 4; + + switch (sel_type) + { + case SEL_IN: + select_wait (&pss_sleeper, wait); + return 0; + break; + + case SEL_OUT: + select_wait (&pss_sleeper, wait); + return 0; + break; + + case SEL_EX: + return 0; + } + + return 0; +} + +long +pss_init (long mem_start) +{ + DEB (printk ("pss_init\n")); + if (pss_ok) + { + code_buffer = mem_start; + mem_start += CODE_BUFFER_LEN; + } + return mem_start; +} + +#endif diff -u --recursive --new-file v1.1.30/linux/drivers/sound/pss.h linux/drivers/sound/pss.h --- v1.1.30/linux/drivers/sound/pss.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/pss.h Mon Jul 18 09:50:55 1994 @@ -0,0 +1,371 @@ +/****************************************************************************** + + def.h + + Version 1.3 11/2/93 + + Copyright (c) 1993 Analog Devices Inc. All rights reserved + +******************************************************************************/ +/* Port offsets from base port for Sound Blaster DSP */ +#define DSP_PORT_CMSD0 0x00 /* C/MS music voice 1-6 data port, write only */ +#define DSP_PORT_CMSR0 0x01 /* C/MS music voice 1-6 register port, write only */ +#define DSP_PORT_CMSD1 0x02 /* C/MS music voice 7-12 data port, write only */ +#define DSP_PORT_CMSR1 0x03 /* C/MS music voice 7-12 register port, write only */ + +#define DSP_PORT_STATUS 0x04 /* DSP Status bits, read only */ +#define DSP_PORT_CONTROL 0x04 /* DSP Control bits, write only */ +#define DSP_PORT_DATA_LSB 0x05 /* Read or write LSB of 16 bit data */ + + +#define DSP_PORT_RESET 0x06 /* DSP Reset, write only */ +#define DSP_PORT_07h 0x07 /* reserved port */ + +#define DSP_PORT_FMD0 0x08 /* FM music data/status port, read/write */ +#define DSP_PORT_FMR0 0x09 /* FM music data/status port, write only */ + +#define DSP_PORT_RDDATA 0x0A /* DSP Read data, read only reading signals DSP */ +#define DSP_PORT_0Bh 0x0B /* reserved port */ +#define DSP_PORT_WRDATA 0x0C /* DSP Write data or command, write */ +#define DSP_PORT_WRBUSY 0x0C /* DSP Write buffer status (bit 7), read */ +#define DSP_PORT_0Dh 0x0D /* reserved port */ +#define DSP_PORT_DATAAVAIL 0x0E /* DSP Data available status (bit 7), read only */ +#define DSP_PORT_INTERFACE 0x0E /* Sets DMA Channel and Interrupt, write only */ +#define DSP_PORT_0Fh 0x0F /* reserved port (used on Pro cards) */ + +#define ADDR_MASK 0x003f + +#define INT_MASK 0xffc7 +#define INT_3_BITS 0x0008 +#define INT_5_BITS 0x0010 +#define INT_7_BITS 0x0018 +#define INT_9_BITS 0x0020 +#define INT_10_BITS 0x0028 +#define INT_11_BITS 0x0030 +#define INT_12_BITS 0x0038 + +#define GAME_BIT 0x0400 +#define GAME_BIT_MASK 0xfbff + +#define INT_TEST_BIT 0x0200 +#define INT_TEST_PASS 0x0100 +#define INT_TEST_BIT_MASK 0xFDFF + +#define DMA_MASK 0xfff8 +#define DMA_0_BITS 0x0001 +#define DMA_1_BITS 0x0002 +#define DMA_3_BITS 0x0003 +#define DMA_5_BITS 0x0004 +#define DMA_6_BITS 0x0005 +#define DMA_7_BITS 0x0006 + +#define DMA_TEST_BIT 0x0080 +#define DMA_TEST_PASS 0x0040 +#define DMA_TEST_BIT_MASK 0xFF7F + + +/* Echo DSP Flags */ + +#define DSP_FLAG3 0x10 +#define DSP_FLAG2 0x08 +#define DSP_FLAG1 0x80 +#define DSP_FLAG0 0x40 + +#define PSS_CONFIG 0x10 +#define PSS_WSS_CONFIG 0x12 +#define SB_CONFIG 0x14 +#define MIDI_CONFIG 0x18 +#define CD_CONFIG 0x16 +#define UART_CONFIG 0x1a + +#define PSS_DATA 0x00 +#define PSS_STATUS 0x02 +#define PSS_CONTROL 0x02 +#define PSS_ID_VERS 0x04 + +#define PSS_FLAG3 0x0800 +#define PSS_FLAG2 0x0400 +#define PSS_FLAG1 0x1000 +#define PSS_FLAG0 0x0800 + +/*_____ WSS defines */ +#define WSS_BASE_ADDRESS 0x530 +#define WSS_CONFIG 0x0 +#define WSS_VERSION 0x03 +#define WSS_SP0 0x04 +#define WSS_SP1 0x05 +#define WSS_SP2 0x06 +#define WSS_SP3 0x07 + +/*_____ SoundPort register addresses */ + +#define SP_LIN_SOURCE_CTRL 0x00 +#define SP_RIN_SOURCE_CTRL 0x01 +#define SP_LIN_GAIN_CTRL 0x10 +#define SP_RIN_GAIN_CTRL 0x11 +#define SP_LAUX1_CTRL 0x02 +#define SP_RAUX1_CTRL 0x03 +#define SP_LAUX2_CTRL 0x04 +#define SP_RAUX2_CTRL 0x05 +#define SP_LOUT_CTRL 0x06 +#define SP_ROUT_CTRL 0x07 +#define SP_CLK_FORMAT 0x48 +#define SP_INT_CONF 0x09 +#define SP_INT_CONF_MCE 0x49 +#define SP_PIN_CTRL 0x0a +#define SP_TEST_INIT 0x0b +#define SP_MISC_CTRL 0x0c +#define SP_MIX_CTRL 0x0d +#define SP_DMA_UCNT 0x0e +#define SP_DMA_LCNT 0x0f + +/*_____ Gain constants */ + +#define GAIN_0 0x00 +#define GAIN_1_5 0x01 +#define GAIN_3 0x02 +#define GAIN_4_5 0x03 +#define GAIN_6 0x04 +#define GAIN_7_5 0x05 +#define GAIN_9 0x06 +#define GAIN_10_5 0x07 +#define GAIN_12 0x08 +#define GAIN_13_5 0x09 +#define GAIN_15 0x0a +#define GAIN_16_5 0x0b +#define GAIN_18 0x0c +#define GAIN_19_5 0x0d +#define GAIN_21 0x0e +#define GAIN_22_5 0x0f +#define MUTE 0XFFFF + +/*_____ Attenuation constants */ + +#define ATTEN_0 0x00 +#define ATTEN_1_5 0x01 +#define ATTEN_3 0x02 +#define ATTEN_4_5 0x03 +#define ATTEN_6 0x04 +#define ATTEN_7_5 0x05 +#define ATTEN_9 0x06 +#define ATTEN_10_5 0x07 +#define ATTEN_12 0x08 +#define ATTEN_13_5 0x09 +#define ATTEN_15 0x0a +#define ATTEN_16_5 0x0b +#define ATTEN_18 0x0c +#define ATTEN_19_5 0x0d +#define ATTEN_21 0x0e +#define ATTEN_22_5 0x0f + + +#define PSS_WRITE_EMPTY 0x8000 + +#define CD_POL_MASK 0xFFBF +#define CD_POL_BIT 0x0040 + + + +/****************************************************************************** + + host.h + + Version 1.2 9/27/93 + + Copyright (c) 1993 Analog Devices Inc. All rights reserved + +******************************************************************************/ +#define SB_WRITE_FULL 0x80 +#define SB_READ_FULL 0x80 +#define SB_WRITE_STATUS 0x0C +#define SB_READ_STATUS 0x0E +#define SB_READ_DATA 0x0A +#define SB_WRITE_DATA 0x0C + +#define PSS_DATA_REG 0x00 +#define PSS_STATUS_REG 0x02 +#define PSS_WRITE_EMPTY 0x8000 +#define PSS_READ_FULL 0x4000 + +/*_____ 1848 Sound Port bit defines */ + +#define SP_IN_INIT 0x80 +#define MODE_CHANGE_ENABLE 0x40 +#define MODE_CHANGE_MASK 0xbf +#define TRANSFER_DISABLE 0x20 +#define TRANSFER_DISABLE_MASK 0xdf +#define ADDRESS_MASK 0xf0 + +/*_____ Status bits */ +#define INTERRUPT_STATUS 0x01 +#define PLAYBACK_READY 0x02 +#define PLAYBACK_LEFT 0x04 +/*_____ pbright is not left */ +#define PLAYBACK_UPPER 0x08 +/*_____ bplower is not upper */ + +#define SAMPLE_OVERRUN 0x10 +#define SAMPLE_UNDERRUN 0x10 +#define CAPTURE_READY 0x20 +#define CAPTURE_LEFT 0x40 +/*_____ cpright is not left */ +#define CAPTURE_UPPER 0x08 +/*_____ cplower is not upper */ + +/*_____ Input & Output regs bits */ +#define LINE_INPUT 0x80 +#define AUX_INPUT 0x40 +#define MIC_INPUT 0x80 +#define MIXED_DAC_INPUT 0xC0 +#define INPUT_GAIN_MASK 0xf0 +#define INPUT_MIC_GAIN_ENABLE 0x20 +#define INPUT_MIC_GAIN_MASK 0xdf +#define INPUT_SOURCE_MASK 0x3f +#define AUX_INPUT_ATTEN_MASK 0xf0 +#define AUX_INPUT_MUTE 0x80 +#define AUX_INPUT_MUTE_MASK 0x7f +#define OUTPUT_MUTE 0x80 +#define OUTPUT_MUTE_MASK 0x7f +#define OUTPUT_ATTEN_MASK 0xc0 + +/*_____ Clock and Data format reg bits */ +#define CLOCK_SELECT_MASK 0xfe +#define CLOCK_XTAL2 0x01 +#define CLOCK_XTAL1 0x00 +#define CLOCK_FREQ_MASK 0xf1 +#define STEREO_MONO_MASK 0xef +#define STEREO 0x10 +#define AUDIO_MONO 0x00 +#define LINEAR_COMP_MASK 0xdf +#define LINEAR 0x00 +#define COMPANDED 0x20 +#define FORMAT_MASK 0xbf +#define PCM 0x00 +#define ULAW 0x00 +#define TWOS_COMP 0x40 +#define ALAW 0x40 + +/*_____ Interface Configuration reg bits */ +#define PLAYBACK_ENABLE 0x01 +#define PLAYBACK_ENABLE_MASK 0xfe +#define CAPTURE_ENABLE 0x02 +#define CAPTURE_ENABLE_MASK 0xfd +#define SINGLE_DMA 0x04 +#define SINGLE_DMA_MASK 0xfb +#define DUAL_DMA 0x00 +#define AUTO_CAL_ENABLE 0x08 +#define AUTO_CAL_DISABLE_MASK 0xf7 +#define PLAYBACK_PIO_ENABLE 0x40 +#define PLAYBACK_DMA_MASK 0xbf +#define CAPTURE_PIO_ENABLE 0x80 +#define CAPTURE_DMA_MASK 0x7f + +/*_____ Pin control bits */ +#define INTERRUPT_ENABLE 0x02 +#define INTERRUPT_MASK 0xfd + +/*_____ Test and init reg bits */ +#define OVERRANGE_LEFT_MASK 0xfc +#define OVERRANGE_RIGHT_MASK 0xf3 +#define DATA_REQUEST_STATUS 0x10 +#define AUTO_CAL_IN_PROG 0x20 +#define PLAYBACK_UNDERRUN 0x40 +#define CAPTURE_UNDERRUN 0x80 + +/*_____ Miscellaneous Control reg bits */ +#define ID_MASK 0xf0 + +/*_____ Digital Mix Control reg bits */ +#define DIGITAL_MIX1_MUTE_MASK 0xfe +#define MIX_ATTEN_MASK 0x03 + +/*_____ 1848 Sound Port reg defines */ + +#define SP_LEFT_INPUT_CONTROL 0x0 +#define SP_RIGHT_INPUT_CONTROL 0x1 +#define SP_LEFT_AUX1_CONTROL 0x2 +#define SP_RIGHT_AUX1_CONTROL 0x3 +#define SP_LEFT_AUX2_CONTROL 0x4 +#define SP_RIGHT_AUX2_CONTROL 0x5 +#define SP_LEFT_OUTPUT_CONTROL 0x6 +#define SP_RIGHT_OUTPUT_CONTROL 0x7 +#define SP_CLOCK_DATA_FORMAT 0x8 +#define SP_INTERFACE_CONFIG 0x9 +#define SP_PIN_CONTROL 0xA +#define SP_TEST_AND_INIT 0xB +#define SP_MISC_INFO 0xC +#define SP_DIGITAL_MIX 0xD +#define SP_UPPER_BASE_COUNT 0xE +#define SP_LOWER_BASE_COUNT 0xF + +#define HOST_SP_ADDR (0x534) +#define HOST_SP_DATA (0x535) + + +/****************************************************************************** + + phillips.h + + Version 1.2 9/27/93 + + Copyright (c) 1993 Analog Devices Inc. All rights reserved + +******************************************************************************/ +/*_____ Phillips control SW defines */ + +/*_____ Settings and ranges */ +#define VOLUME_MAX 6 +#define VOLUME_MIN (-64) +#define VOLUME_RANGE 70 +#define VOLUME_STEP 2 +#define BASS_MAX 15 +#define BASS_MIN (-12) +#define BASS_STEP 2 +#define BASS_RANGE 27 +#define TREBLE_MAX 12 +#define TREBLE_MIN (-12) +#define TREBLE_STEP 2 +#define TREBLE_RANGE 24 + +#define VOLUME_CONSTANT 252 +#define BASS_CONSTANT 246 +#define TREBLE_CONSTANT 246 + +/*_____ Software commands */ +#define SET_MASTER_COMMAND 0x0010 +#define MASTER_VOLUME_LEFT 0x0000 +#define MASTER_VOLUME_RIGHT 0x0100 +#define MASTER_BASS 0x0200 +#define MASTER_TREBLE 0x0300 +#define MASTER_SWITCH 0x0800 + +#define STEREO_MODE 0x00ce +#define PSEUDO_MODE 0x00d6 +#define SPATIAL_MODE 0x00de +#define MONO_MODE 0x00c6 + + +#define PSS_STEREO 0x00ce +#define PSS_PSEUDO 0x00d6 +#define PSS_SPATIAL 0x00de +#define PSS_MONO 0x00c6 + +#define PHILLIPS_VOL_MIN -64 +#define PHILLIPS_VOL_MAX 6 +#define PHILLIPS_VOL_DELTA 70 +#define PHILLIPS_VOL_INITIAL -20 +#define PHILLIPS_VOL_CONSTANT 252 +#define PHILLIPS_VOL_STEP 2 +#define PHILLIPS_BASS_MIN -12 +#define PHILLIPS_BASS_MAX 15 +#define PHILLIPS_BASS_DELTA 27 +#define PHILLIPS_BASS_INITIAL 0 +#define PHILLIPS_BASS_CONSTANT 246 +#define PHILLIPS_BASS_STEP 2 +#define PHILLIPS_TREBLE_MIN -12 +#define PHILLIPS_TREBLE_MAX 12 +#define PHILLIPS_TREBLE_DELTA 24 +#define PHILLIPS_TREBLE_INITIAL 0 +#define PHILLIPS_TREBLE_CONSTANT 246 +#define PHILLIPS_TREBLE_STEP 2 + diff -u --recursive --new-file v1.1.30/linux/drivers/sound/sb16_dsp.c linux/drivers/sound/sb16_dsp.c --- v1.1.30/linux/drivers/sound/sb16_dsp.c Sun May 1 12:12:39 1994 +++ linux/drivers/sound/sb16_dsp.c Mon Jul 18 09:50:55 1994 @@ -32,7 +32,7 @@ #define DEB(x) #define DEB1(x) /* - #define DEB_DMARES + * #define DEB_DMARES */ #include "sound_config.h" #include "sb.h" @@ -40,19 +40,28 @@ #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_AUDIO) && !defined(EXCLUDE_SBPRO) -extern int sbc_base, sbc_minor, sbc_major; +extern int sbc_base; -static int sb16_dsp_ok = 0;/* Set to 1 after successful initialization */ +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_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 +static int irq_mode = IMODE_NONE; /* + - IMODE_NONE */ + * * * * IMODE_INPUT, IMODE_OUTPUT + * or * * IMODE_NONE */ static int my_dev = 0; static volatile int intr_active = 0; @@ -74,7 +83,9 @@ static struct audio_operations sb16_dsp_operations = { "SoundBlaster 16", - NOTHING_SPECIAL, + DMA_AUTOMODE, + AFMT_U8 | AFMT_S16_LE, + NULL, sb16_dsp_open, sb16_dsp_close, sb16_dsp_output_block, @@ -100,79 +111,6 @@ } static int -wait_data_avail (unsigned long 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 ((unsigned long) 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 1) return IOCTL_OUT (arg, RET_ERROR (EINVAL)); default: @@ -286,6 +226,8 @@ if (retval < 0) return retval; + sb_reset_dsp (); + if (ALLOC_DMA_CHN (dma8)) { printk ("SB16: Unable to grab DMA%d\n", dma8); @@ -302,8 +244,6 @@ return RET_ERROR (EBUSY); } - dsp_ini2 (); - irq_mode = IMODE_NONE; dsp_busy = 1; @@ -344,7 +284,7 @@ printk ("output_block: %x %d %d\n", buf, count, intrflag); if (intrflag) { - int pos, chan = sound_dsp_dmachan[dev]; + int pos, chan = audio_devs[dev]->dmachan; DISABLE_INTR (flags); clear_dma_ff (chan); @@ -355,13 +295,15 @@ printk ("dmapos=%d %x\n", pos, pos); } #endif - if (sound_dma_automode[dev] && + if (audio_devs[dev]->flags & DMA_AUTOMODE && intrflag && cnt == dsp_count) { irq_mode = IMODE_OUTPUT; intr_active = 1; - return; /* Auto mode on. No need to react */ + return; /* + * Auto mode on. No need to react + */ } DISABLE_INTR (flags); @@ -378,13 +320,11 @@ (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; + RESTORE_INTR (flags); } static void @@ -401,7 +341,7 @@ printk ("start_input: %x %d %d\n", buf, count, intrflag); if (intrflag) { - int pos, chan = sound_dsp_dmachan[dev]; + int pos, chan = audio_devs[dev]->dmachan; DISABLE_INTR (flags); clear_dma_ff (chan); @@ -412,19 +352,21 @@ printk ("dmapos=%d %x\n", pos, pos); } #endif - if (sound_dma_automode[dev] && + if (audio_devs[dev]->flags & DMA_AUTOMODE && intrflag && cnt == dsp_count) { irq_mode = IMODE_INPUT; intr_active = 1; - return; /* Auto mode on. No need to react */ + return; /* + * Auto mode on. No need to react + */ } DISABLE_INTR (flags); if (dma_restart) { - sb16_dsp_halt (dev); + sb_reset_dsp (); DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); } @@ -437,18 +379,16 @@ 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; + RESTORE_INTR (flags); } static int sb16_dsp_prepare_for_input (int dev, int bsize, int bcount) { - sound_dsp_dmachan[my_dev] = dsp_16bit ? dma16 : dma8; + audio_devs[my_dev]->dmachan = dsp_16bit ? dma16 : dma8; dsp_count = 0; dsp_cleanup (); return 0; @@ -457,7 +397,7 @@ static int sb16_dsp_prepare_for_output (int dev, int bsize, int bcount) { - sound_dsp_dmachan[my_dev] = dsp_16bit ? dma16 : dma8; + audio_devs[my_dev]->dmachan = dsp_16bit ? dma16 : dma8; dsp_count = 0; dsp_cleanup (); return 0; @@ -511,6 +451,9 @@ case 7: ival = 4; break; + case 9: + ival = 1; + break; case 10: ival = 8; break; @@ -524,8 +467,10 @@ long sb16_dsp_init (long mem_start, struct address_info *hw_config) { + extern int sbc_major, sbc_minor; + if (sbc_major < 4) - return mem_start; + return mem_start; /* Not a SB16 */ #ifndef SCO sprintf (sb16_dsp_operations.name, "SoundBlaster 16 %d.%d", sbc_major, sbc_minor); @@ -533,13 +478,12 @@ printk (" <%s>", sb16_dsp_operations.name); - if (num_dspdevs < MAX_DSP_DEV) + if (num_audiodevs < MAX_AUDIO_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; + audio_devs[my_dev = num_audiodevs++] = &sb16_dsp_operations; + audio_devs[my_dev]->dmachan = hw_config->dma; + audio_devs[my_dev]->buffcount = 1; + audio_devs[my_dev]->buffsize = DSP_BUFFSIZE; } else printk ("SB: Too many DSP devices available\n"); @@ -551,9 +495,10 @@ sb16_dsp_detect (struct address_info *hw_config) { struct address_info *sb_config; + extern int sbc_major; if (sb16_dsp_ok) - return 1; /* Already initialized */ + return 1; /* Can't drive two cards */ if (!(sb_config = sound_getconf (SNDCARD_SB))) { @@ -561,13 +506,16 @@ return 0; } - /* sb_setmixer(OPSW,0xf); - if(sb_getmixer(OPSW)!=0xf) - return 0; */ + /* + * sb_setmixer(OPSW,0xf); if(sb_getmixer(OPSW)!=0xf) return 0; + */ if (!sb_reset_dsp ()) return 0; + if (sbc_major < 4) /* Set by the plain SB driver */ + return 0; /* Not a SB16 */ + if (hw_config->dma < 4) if (hw_config->dma != sb_config->dma) { @@ -584,7 +532,7 @@ DEB (printk ("SoundBlaster 16: IRQ %d DMA %d OK\n", sb_config->irq, hw_config->dma)); /* - dsp_showmessage(0xe3,99); + * dsp_showmessage(0xe3,99); */ sb16_dsp_ok = 1; return 1; @@ -595,7 +543,9 @@ { int data; - data = INB (DSP_DATA_AVL16); /* Interrupt acknowledge */ + data = INB (DSP_DATA_AVL16); /* + * Interrupt acknowledge + */ if (intr_active) switch (irq_mode) diff -u --recursive --new-file v1.1.30/linux/drivers/sound/sb16_midi.c linux/drivers/sound/sb16_midi.c --- v1.1.30/linux/drivers/sound/sb16_midi.c Sun May 1 12:12:39 1994 +++ linux/drivers/sound/sb16_midi.c Mon Jul 18 09:50:55 1994 @@ -33,10 +33,12 @@ #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 */ +#include "sb.h" +#define DATAPORT (sb16midi_base) +#define COMDPORT (sb16midi_base+1) +#define STATPORT (sb16midi_base+1) + #define sb16midi_status() INB(STATPORT) #define input_avail() (!(sb16midi_status()&INPUT_AVAIL)) #define output_ready() (!(sb16midi_status()&OUTPUT_READY)) @@ -44,26 +46,24 @@ #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" */ +#define OUTPUT_READY 0x40 +#define INPUT_AVAIL 0x80 +#define MPU_ACK 0xFE +#define MPU_RESET 0xFF +#define UART_MODE_ON 0x3F static int sb16midi_opened = 0; static int sb16midi_base = 0x330; static int sb16midi_detected = 0; static int my_dev; +extern int sbc_base; static int reset_sb16midi (void); static void (*midi_input_intr) (int dev, unsigned char data); -extern int sbc_major; - static void sb16midi_input_loop (void) { - while (input_avail ()) { unsigned char c = sb16midi_read (); @@ -127,7 +127,9 @@ * (After reset). Normally it takes just about 10 loops. */ - for (timeout = 30000; timeout > 0 && !output_ready (); timeout--); /* Wait */ + for (timeout = 30000; timeout > 0 && !output_ready (); timeout--); /* + * Wait + */ if (!output_ready ()) { @@ -140,12 +142,6 @@ } static int -sb16midi_command (int dev, unsigned char midi_byte) -{ - return 1; -} - -static int sb16midi_start_read (int dev) { return 0; @@ -171,12 +167,19 @@ static int sb16midi_buffer_status (int dev) { - return 0; /* No data in buffers */ + return 0; /* + * No data in buffers + */ } +#define MIDI_SYNTH_NAME "SoundBlaster 16 Midi" +#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT +#include "midi_synth.h" + static struct midi_operations sb16midi_operations = { - {"SoundBlaster MPU-401", 0, 0, SNDCARD_SB16MIDI}, + {"SoundBlaster 16 Midi", 0, 0, SNDCARD_SB16MIDI}, + &std_midi_synth, sb16midi_open, sb16midi_close, sb16midi_ioctl, @@ -184,8 +187,9 @@ sb16midi_start_read, sb16midi_end_read, sb16midi_kick, - sb16midi_command, - sb16midi_buffer_status + NULL, + sb16midi_buffer_status, + NULL }; @@ -201,7 +205,9 @@ return RET_ERROR (EIO); DISABLE_INTR (flags); - for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /* Wait */ + for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /* + * Wait + */ sb16midi_cmd (UART_MODE_ON); ok = 0; @@ -212,9 +218,15 @@ RESTORE_INTR (flags); + if (num_midis >= MAX_MIDI_DEV) + { + printk ("Sound: Too many midi devices detected\n"); + return mem_start; + } + printk (" "); - my_dev = num_midis; + std_midi_synth.midi_dev = my_dev = num_midis; midi_devs[num_midis++] = &sb16midi_operations; return mem_start; } @@ -235,8 +247,12 @@ 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 */ + 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 @@ -252,7 +268,9 @@ sb16midi_opened = 0; if (ok) - sb16midi_input_loop (); /* Flush input before enabling interrupts */ + sb16midi_input_loop (); /* + * Flush input before enabling interrupts + */ RESTORE_INTR (flags); @@ -264,10 +282,13 @@ probe_sb16midi (struct address_info *hw_config) { int ok = 0; + int i; + extern int sbc_major; - sb16midi_base = hw_config->io_base; if (sbc_major < 4) - return 0; /* SB16 not detected */ + return 0; /* Not a SB16 */ + + sb16midi_base = hw_config->io_base; if (sb_get_irq () < 0) return 0; diff -u --recursive --new-file v1.1.30/linux/drivers/sound/sb_dsp.c linux/drivers/sound/sb_dsp.c --- v1.1.30/linux/drivers/sound/sb_dsp.c Sat May 7 14:54:03 1994 +++ linux/drivers/sound/sb_dsp.c Mon Jul 18 09:50:55 1994 @@ -25,10 +25,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * Modified: - * Hunyue Yau Jan 6 1994 - * Added code to support Sound Galaxy NX Pro - * */ #include "sound_config.h" @@ -41,7 +37,7 @@ int sbc_base = 0; static int sbc_irq = 0; -static int open_mode=0; +static int open_mode = 0; /* Read, write or both */ /* * The DSP channel can be used either for input or output. Variable @@ -51,23 +47,36 @@ * future version of this driver. */ -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; int sb_dsp_highspeed = 0; -int sbc_major = 1; -int sbc_minor = 0; /* DSP version */ +int sbc_major = 1, sbc_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; int sb_midi_mode = NORMAL_MIDI; -int sb_midi_busy = 0; /* 1 if the process has output to MIDI */ +int sb_midi_busy = 0; /* + + + * * * * 1 if the process has output + * to * * MIDI */ int sb_dsp_busy = 0; -volatile int sb_irq_mode = IMODE_NONE; /* IMODE_INPUT, IMODE_OUTPUT +volatile int sb_irq_mode = IMODE_NONE; /* - * or IMODE_NONE */ + + * * * * IMODE_INPUT, * + * IMODE_OUTPUT * * or * + * IMODE_NONE */ static volatile int irq_ok = 0; int sb_duplex_midi = 0; @@ -81,7 +90,9 @@ #if !defined(EXCLUDE_MIDI) || !defined(EXCLUDE_AUDIO) -/* Common code for the midi and pcm functions */ +/* + * Common code for the midi and pcm functions + */ int sb_dsp_command (unsigned char val) @@ -89,7 +100,9 @@ int i; unsigned long limit; - limit = GET_TIME () + HZ / 10;/* The timeout is 0.1 secods */ + limit = GET_TIME () + HZ / 10;/* + * The timeout is 0.1 secods + */ /* * Note! the i<500000 is an emergency exit. The sb_dsp_command() is sometimes @@ -121,25 +134,36 @@ #ifndef EXCLUDE_SBPRO if (sb16) { - unsigned char src = sb_getmixer (IRQ_STAT); /* Interrupt source register */ + unsigned char src = sb_getmixer (IRQ_STAT); /* + + * * * * Interrupt + * source * * + * register */ + #ifndef EXCLUDE_SB16 if (src & 3) sb16_dsp_interrupt (unit); #ifndef EXCLUDE_MIDI if (src & 4) - sb16midiintr (unit); /* MPU401 interrupt */ + sb16midiintr (unit); /* + * SB MPU401 interrupt + */ #endif #endif if (!(src & 1)) - return; /* Not a DSP interupt */ + return; /* + * Not a DSP interupt + */ } #endif - status = INB (DSP_DATA_AVAIL);/* Clear interrupt */ + status = INB (DSP_DATA_AVAIL);/* + * Clear interrupt + */ if (sb_intr_active) switch (sb_irq_mode) @@ -152,7 +176,9 @@ case IMODE_INPUT: sb_intr_active = 0; DMAbuf_inputintr (my_dev); - /* A complete buffer has been input. Let's start new one */ + /* + * A complete buffer has been input. Let's start new one + */ break; case IMODE_INIT: @@ -160,13 +186,11 @@ irq_ok = 1; break; -#ifndef EXCLUDE_MIDI - case IMODE_MIDI: +#ifndef EXCLUDE_MIDI sb_midi_interrupt (unit); - break; - #endif + break; default: printk ("SoundBlaster: Unexpected interrupt\n"); @@ -213,11 +237,19 @@ tenmicrosec (); tenmicrosec (); - for (loopc = 0; loopc < 1000 && !(INB (DSP_DATA_AVAIL) & 0x80); loopc++); /* Wait for data - * available status */ + for (loopc = 0; loopc < 1000 && !(INB (DSP_DATA_AVAIL) & 0x80); loopc++); /* + * Wait + * for + * data + * * + * available + * status + */ if (INB (DSP_READ) != 0xAA) - return 0; /* Sorry */ + return 0; /* + * Sorry + */ return 1; } @@ -264,11 +296,15 @@ max_speed = 13000; if (speed > max_speed) - speed = max_speed; /* Invalid speed */ + speed = max_speed; /* + * Invalid speed + */ if (dsp_stereo && speed > 22050) speed = 22050; - /* Max. stereo speed is 22050 */ + /* + * Max. stereo speed is 22050 + */ if ((speed > 22050) && sb_midi_busy) { @@ -279,10 +315,14 @@ if (dsp_stereo) speed *= 2; - /* Now the speed should be valid */ + /* + * Now the speed should be valid + */ if (speed > 22050) - { /* High speed mode */ + { /* + * High speed mode + */ int tmp; tconst = (unsigned char) ((65536 - @@ -305,7 +345,9 @@ tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff; DISABLE_INTR (flags); - if (sb_dsp_command (0x40))/* Set time constant */ + if (sb_dsp_command (0x40))/* + * Set time constant + */ sb_dsp_command (tconst); RESTORE_INTR (flags); @@ -329,7 +371,9 @@ return 0; #else if (sbc_major < 3 || sb16) - return 0; /* Sorry no stereo */ + return 0; /* + * Sorry no stereo + */ if (mode && sb_midi_busy) { @@ -354,18 +398,22 @@ sb_irq_mode = IMODE_OUTPUT; DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); - if (sound_dsp_dmachan[dev] > 3) + if (audio_devs[dev]->dmachan > 3) count >>= 1; count--; if (sb_dsp_highspeed) { DISABLE_INTR (flags); - if (sb_dsp_command (0x48))/* High speed size */ + if (sb_dsp_command (0x48))/* + * High speed size + */ { sb_dsp_command ((unsigned char) (count & 0xff)); sb_dsp_command ((unsigned char) ((count >> 8) & 0xff)); - sb_dsp_command (0x91);/* High speed 8 bit DAC */ + sb_dsp_command (0x91);/* + * High speed 8 bit DAC + */ } else printk ("SB Error: Unable to start (high speed) DAC\n"); @@ -374,7 +422,9 @@ else { DISABLE_INTR (flags); - if (sb_dsp_command (0x14))/* 8-bit DAC (DMA) */ + if (sb_dsp_command (0x14))/* + * 8-bit DAC (DMA) + */ { sb_dsp_command ((unsigned char) (count & 0xff)); sb_dsp_command ((unsigned char) ((count >> 8) & 0xff)); @@ -390,7 +440,9 @@ 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 */ + /* + * Start a DMA input to the buffer pointed by dmaqtail + */ unsigned long flags; @@ -400,18 +452,22 @@ sb_irq_mode = IMODE_INPUT; DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); - if (sound_dsp_dmachan[dev] > 3) + if (audio_devs[dev]->dmachan > 3) count >>= 1; count--; if (sb_dsp_highspeed) { DISABLE_INTR (flags); - if (sb_dsp_command (0x48))/* High speed size */ + if (sb_dsp_command (0x48))/* + * High speed size + */ { sb_dsp_command ((unsigned char) (count & 0xff)); sb_dsp_command ((unsigned char) ((count >> 8) & 0xff)); - sb_dsp_command (0x99);/* High speed 8 bit ADC */ + sb_dsp_command (0x99);/* + * High speed 8 bit ADC + */ } else printk ("SB Error: Unable to start (high speed) ADC\n"); @@ -420,7 +476,9 @@ else { DISABLE_INTR (flags); - if (sb_dsp_command (0x24))/* 8-bit ADC (DMA) */ + if (sb_dsp_command (0x24))/* + * 8-bit ADC (DMA) + */ { sb_dsp_command ((unsigned char) (count & 0xff)); sb_dsp_command ((unsigned char) ((count >> 8) & 0xff)); @@ -445,15 +503,19 @@ dsp_cleanup (); dsp_speaker (OFF); - if (sbc_major == 3) /* SB Pro */ + if (sbc_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 */ + dsp_speed (dsp_current_speed); /* + * Speed must be recalculated if + * #channels * changes + */ } return 0; } @@ -465,11 +527,15 @@ dsp_speaker (ON); #ifndef EXCLUDE_SBPRO - if (sbc_major == 3) /* SB Pro */ + if (sbc_major == 3) /* + * SB Pro + */ { sb_mixer_set_stereo (dsp_stereo); - dsp_speed (dsp_current_speed); /* Speed must be recalculated if #channels - * changes */ + dsp_speed (dsp_current_speed); /* + * Speed must be recalculated if + * #channels * changes + */ } #endif return 0; @@ -497,7 +563,9 @@ sb_irq_mode = IMODE_INIT; - sb_dsp_command (0xf2); /* This should cause immediate interrupt */ + sb_dsp_command (0xf2); /* + * This should cause immediate interrupt + */ DO_SLEEP (testq, testf, HZ / 5); @@ -544,7 +612,7 @@ if (retval) return retval; - if (!DMAbuf_open_dma (dev)) + if (DMAbuf_open_dma (dev) < 0) { sb_free_irq (); printk ("SB: DMA Busy\n"); @@ -610,7 +678,9 @@ 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: @@ -648,12 +718,16 @@ sbc_irq = hw_config->irq; if (sb_dsp_ok) - return 0; /* Already initialized */ + return 0; /* + * Already initialized + */ if (!sb_reset_dsp ()) return 0; - return 1; /* Detected */ + return 1; /* + * Detected + */ } #ifndef EXCLUDE_AUDIO @@ -661,6 +735,8 @@ { "SoundBlaster", NOTHING_SPECIAL, + AFMT_U8, /* Just 8 bits. Poor old SB */ + NULL, sb_dsp_open, sb_dsp_close, sb_dsp_output_block, @@ -670,7 +746,7 @@ sb_dsp_prepare_for_output, sb_dsp_reset, sb_dsp_halt_xfer, - NULL, /* has_output_drained */ + NULL, /* local_qlen */ NULL /* copy_from_user */ }; @@ -680,15 +756,18 @@ sb_dsp_init (long mem_start, struct address_info *hw_config) { int i; - int prostat = 0; sbc_major = sbc_minor = 0; - sb_dsp_command (0xe1); /* Get version */ + sb_dsp_command (0xe1); /* + * Get version + */ for (i = 1000; i; i--) { if (INB (DSP_DATA_AVAIL) & 0x80) - { /* wait for Data Ready */ + { /* + * wait for Data Ready + */ if (sbc_major == 0) sbc_major = INB (DSP_READ); else @@ -699,35 +778,28 @@ } } - if (sbc_major == 2 || sbc_major == 3) /* SB 2.0 or SB Pro */ + if (sbc_major == 2 || sbc_major == 3) sb_duplex_midi = 1; if (sbc_major == 4) sb16 = 1; #ifndef EXCLUDE_SBPRO - if (sbc_major >= 3 || - (sbc_major == 2 && sbc_minor == 1)) /* Sound Galaxy ??? */ - prostat = sb_mixer_init (sbc_major); + if (sbc_major >= 3) + sb_mixer_init (sbc_major); #endif -#ifndef EXCLUDE_YM3812 +#ifndef EXCLUDE_YM8312 + if (sbc_major > 3 || - (sbc_major == 3 && INB (0x388) == 0x00)) /* Non OPL-3 should return 0x06 */ + (sbc_major == 3 && INB (0x388) == 0x00)) /* Should be 0x06 if not OPL-3 */ enable_opl3_mode (OPL3_LEFT, OPL3_RIGHT, OPL3_BOTH); #endif if (sbc_major >= 3) { #ifndef SCO - if (prostat) - { - sprintf (sb_dsp_operations.name, "Sound Galaxy NX Pro %d.%d", sbc_major, sbc_minor); - } - else - { - sprintf (sb_dsp_operations.name, "SoundBlaster Pro %d.%d", sbc_major, sbc_minor); - } + sprintf (sb_dsp_operations.name, "SoundBlaster Pro %d.%d", sbc_major, sbc_minor); #endif } else @@ -741,23 +813,26 @@ #ifndef EXCLUDE_AUDIO #if !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SBPRO) - if (!sb16) /* There is a better driver for SB16 */ + if (!sb16) /* + * There is a better driver for SB16 + */ #endif - if (num_dspdevs < MAX_DSP_DEV) + if (num_audiodevs < MAX_AUDIO_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; + audio_devs[my_dev = num_audiodevs++] = &sb_dsp_operations; + audio_devs[my_dev]->buffcount = DSP_BUFFCOUNT; + audio_devs[my_dev]->buffsize = DSP_BUFFSIZE; + audio_devs[my_dev]->dmachan = hw_config->dma; } else printk ("SB: Too many DSP devices available\n"); #endif #ifndef EXCLUDE_MIDI - if (!midi_disabled && !sb16) /* Midi don't work in the SB emulation mode - * of PAS, SB16 has better midi interface */ + if (!midi_disabled && !sb16) /* + * Midi don't work in the SB emulation mode * + * of PAS, SB16 has better midi interface + */ sb_midi_init (sbc_major); #endif diff -u --recursive --new-file v1.1.30/linux/drivers/sound/sb_midi.c linux/drivers/sound/sb_midi.c --- v1.1.30/linux/drivers/sound/sb_midi.c Sun May 1 12:12:41 1994 +++ linux/drivers/sound/sb_midi.c Mon Jul 18 09:50:55 1994 @@ -42,23 +42,26 @@ * future version of this driver. */ -extern int sb_dsp_ok; /* Set to 1 after successful initialization */ +extern int sb_dsp_ok; /* Set to 1 atfer successful initialization */ +extern int sbc_base; extern int sb_midi_mode; -extern int sb_midi_busy; /* 1 if the process has output to MIDI */ +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 volatile int sb_irq_mode; extern int sb_duplex_midi; extern int sb_intr_active; -extern int sbc_base; +int input_opened = 0; +static int my_dev; -static int input_opened = 0; -static void (*midi_input_intr) (int dev, unsigned char data); -static int my_dev = 0; +void (*midi_input_intr) (int dev, unsigned char data); static int sb_midi_open (int dev, int mode, @@ -74,10 +77,13 @@ return RET_ERROR (ENXIO); } + if (sb_midi_busy) + return RET_ERROR (EBUSY); + if (mode != OPEN_WRITE && !sb_duplex_midi) { if (num_midis == 1) - printk ("SoundBlaster: MIDI input not supported with plain SB\n"); + printk ("SoundBlaster: Midi input not currently supported\n"); return RET_ERROR (EPERM); } @@ -101,20 +107,20 @@ sb_reset_dsp (); - if (!sb_dsp_command (0xf2)) /* This is undodumented, isn't it */ - return RET_ERROR (EIO); /* be nice to DSP */ - if (!sb_dsp_command (0x35)) - return RET_ERROR (EIO); /* Enter the UART mode */ + 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 */ + return 0; /* + * IRQ not free + */ } input_opened = 1; - my_dev = dev; midi_input_intr = input; } @@ -128,7 +134,9 @@ { if (sb_midi_mode == UART_MIDI) { - sb_reset_dsp (); /* The only way to kill the UART mode */ + sb_reset_dsp (); /* + * The only way to kill the UART mode + */ sb_free_irq (); } sb_intr_active = 0; @@ -141,8 +149,6 @@ { unsigned long flags; - sb_midi_busy = 1; /* Kill all notes after close */ - if (sb_midi_mode == NORMAL_MIDI) { DISABLE_INTR (flags); @@ -153,7 +159,9 @@ RESTORE_INTR (flags); } else - sb_dsp_command (midi_byte); /* UART write */ + sb_dsp_command (midi_byte); /* + * UART write + */ return 1; } @@ -201,23 +209,43 @@ RESTORE_INTR (flags); } +#define MIDI_SYNTH_NAME "SoundBlaster Midi" +#define MIDI_SYNTH_CAPS 0 +#include "midi_synth.h" + static struct midi_operations sb_midi_operations = { {"SoundBlaster", 0, 0, SNDCARD_SB}, + &std_midi_synth, 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 */ + NULL, /* + * Kick + */ + NULL, /* + * command + */ + NULL, /* + * buffer_status + */ + NULL }; void sb_midi_init (int model) { + if (num_midis >= MAX_MIDI_DEV) + { + printk ("Sound: Too many midi devices detected\n"); + return; + } + + std_midi_synth.midi_dev = num_midis; + my_dev = num_midis; midi_devs[num_midis++] = &sb_midi_operations; } diff -u --recursive --new-file v1.1.30/linux/drivers/sound/sb_mixer.c linux/drivers/sound/sb_mixer.c --- v1.1.30/linux/drivers/sound/sb_mixer.c Sun May 1 12:12:42 1994 +++ linux/drivers/sound/sb_mixer.c Mon Jul 18 09:50:55 1994 @@ -26,10 +26,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * Modified: - * Hunyue Yau Jan 6 1994 - * Added code to support the Sound Galaxy NX Pro mixer. - * */ #include "sound_config.h" @@ -58,7 +54,9 @@ unsigned long flags; DISABLE_INTR (flags); - OUTB ((unsigned char) (port & 0xff), MIXER_ADDR); /* Select register */ + OUTB ((unsigned char) (port & 0xff), MIXER_ADDR); /* + * Select register + */ tenmicrosec (); OUTB ((unsigned char) (value & 0xff), MIXER_DATA); tenmicrosec (); @@ -72,7 +70,9 @@ unsigned long flags; DISABLE_INTR (flags); - OUTB ((unsigned char) (port & 0xff), MIXER_ADDR); /* Select register */ + OUTB ((unsigned char) (port & 0xff), MIXER_ADDR); /* + * Select register + */ tenmicrosec (); val = INB (MIXER_DATA); tenmicrosec (); @@ -91,21 +91,9 @@ | (mode ? STEREO_DAC : MONO_DAC))); } -/* - * Returns: - * 0 No mixer detected. - * 1 Only a plain Sound Blaster Pro style mixer detected. - * 2 The Sound Galaxy NX Pro mixer detected. - */ static int detect_mixer (void) { -#ifdef __SGNXPRO__ - int oldbass, oldtreble; - -#endif - int retcode = 1; - /* * 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 @@ -115,34 +103,13 @@ sb_setmixer (VOC_VOL, 0x33); if (sb_getmixer (FM_VOL) != 0xff) - return 0; /* No match */ + return 0; /* + * No match + */ if (sb_getmixer (VOC_VOL) != 0x33) return 0; -#ifdef __SGNXPRO__ - /* Attempt to detect the SG NX Pro by check for valid bass/treble - * registers. - */ - oldbass = sb_getmixer (BASS_LVL); - oldtreble = sb_getmixer (TREBLE_LVL); - - sb_setmixer (BASS_LVL, 0xaa); - sb_setmixer (TREBLE_LVL, 0x55); - - if ((sb_getmixer (BASS_LVL) != 0xaa) || - (sb_getmixer (TREBLE_LVL) != 0x55)) - { - retcode = 1; /* 1 == Only SB Pro detected */ - } - else - retcode = 2; /* 2 == SG NX Pro detected */ - /* Restore register in either case since SG NX Pro has EEPROM with - * 'preferred' values stored. - */ - sb_setmixer (BASS_LVL, oldbass); - sb_setmixer (TREBLE_LVL, oldtreble); -#endif - return retcode; + return 1; } static void @@ -152,12 +119,18 @@ int shift; mask = (1 << (*iomap)[dev][chn].nbits) - 1; - newval = ((newval * mask) + 50) / 100; /* Scale it */ + newval = (int) ((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 */ + *regval &= ~(mask << shift); /* + * Filter out the previous value + */ + *regval |= (newval & mask) << shift; /* + * Set the new value + */ } static int @@ -186,7 +159,9 @@ if (dev > 31) return RET_ERROR (EINVAL); - if (!(supported_devices & (1 << dev))) /* Not supported */ + if (!(supported_devices & (1 << dev))) /* + * Not supported + */ return RET_ERROR (EINVAL); regoffs = (*iomap)[dev][LEFT_CHN].regno; @@ -199,15 +174,23 @@ levels[dev] = left | (left << 8); - if ((*iomap)[dev][RIGHT_CHN].regno != regoffs) /* Change register */ + if ((*iomap)[dev][RIGHT_CHN].regno != regoffs) /* + * Change register + */ { - sb_setmixer (regoffs, val); /* Save the old one */ + 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 */ + return left | (left << 8); /* + * Just left channel present + */ + + val = sb_getmixer (regoffs); /* + * Read the new one + */ } change_bits (&val, dev, RIGHT_CHN, right); @@ -238,21 +221,27 @@ if (devmask != SOUND_MASK_MIC && devmask != SOUND_MASK_LINE && devmask != SOUND_MASK_CD) - { /* More than one devices selected. Drop the - * previous selection */ + { /* + * 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 */ + { /* + * More than one devices selected. Default to + * * mic + */ devmask = SOUND_MASK_MIC; } - if (devmask ^ recmask) /* Input source changed */ + if (devmask ^ recmask) /* + * Input source changed + */ { switch (devmask) { @@ -312,7 +301,9 @@ return IOCTL_OUT (arg, sb_mixer_set (cmd & 0xff, IOCTL_IN (arg))); } else - switch (cmd & 0xff) /* Return parameters */ + switch (cmd & 0xff) /* + * Return parameters + */ { case SOUND_MIXER_RECSRC: @@ -359,25 +350,18 @@ set_recmask (SOUND_MASK_MIC); } -/* - * Returns a code depending on whether a SG NX Pro was detected. - * 0 == Plain SB 16 or SB Pro - * 1 == SG NX Pro detected. - * - * Used to update message. - */ -int +void sb_mixer_init (int major_model) { - int mixerstat; - - sb_setmixer (0x00, 0); /* Reset mixer */ - - mixerstat = detect_mixer (); + sb_setmixer (0x00, 0); /* + * Reset mixer + */ + + if (!detect_mixer ()) + return; /* + * No mixer. Why? + */ - if (!mixerstat) - return 0; /* No mixer. Why? */ - mixer_initialized = 1; mixer_model = major_model; @@ -385,21 +369,9 @@ { case 3: mixer_caps = SOUND_CAP_EXCL_INPUT; -#ifdef __SGNXPRO__ - if (mixerstat == 2) - { /* A SGNXPRO was detected */ - supported_devices = SGNXPRO_MIXER_DEVICES; - supported_rec_devices = SGNXPRO_RECORDING_DEVICES; - iomap = &sgnxpro_mix; - } - else -#endif - { /* Otherwise plain SB Pro */ - supported_devices = SBPRO_MIXER_DEVICES; - supported_rec_devices = SBPRO_RECORDING_DEVICES; - iomap = &sbpro_mix; - } - + supported_devices = SBPRO_MIXER_DEVICES; + supported_rec_devices = SBPRO_RECORDING_DEVICES; + iomap = &sbpro_mix; break; case 4: @@ -411,12 +383,12 @@ default: printk ("SB Warning: Unsupported mixer type\n"); - return 0; + return; } - mixer_devs[num_mixers++] = &sb_mixer_operations; + if (num_mixers < MAX_MIXER_DEV) + mixer_devs[num_mixers++] = &sb_mixer_operations; sb_mixer_reset (); - return (mixerstat == 2); } #endif diff -u --recursive --new-file v1.1.30/linux/drivers/sound/sb_mixer.h linux/drivers/sound/sb_mixer.h --- v1.1.30/linux/drivers/sound/sb_mixer.h Sun May 1 12:12:42 1994 +++ linux/drivers/sound/sb_mixer.h Mon Jul 18 09:50:55 1994 @@ -24,29 +24,13 @@ * 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. - * - * Modified: - * Hunyue Yau Jan 6 1994 - * Added defines for the Sound Galaxy NX Pro mixer. * */ - #define SBPRO_RECORDING_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD) -/* Same as SB Pro, unless I find otherwise */ -#define SGNXPRO_RECORDING_DEVICES SBPRO_RECORDING_DEVICES - #define SBPRO_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_MIC | \ SOUND_MASK_CD | SOUND_MASK_VOLUME) -/* SG NX Pro has treble and bass settings on the mixer. The 'speaker' - * channel is the COVOX/DisneySoundSource emulation volume control - * on the mixer. It does NOT control speaker volume. Should have own - * mask eventually? - */ -#define SGNXPRO_MIXER_DEVICES (SBPRO_MIXER_DEVICES|SOUND_MASK_BASS| \ - SOUND_MASK_TREBLE|SOUND_MASK_SPEAKER ) - #define SB16_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \ SOUND_MASK_CD) @@ -78,13 +62,6 @@ #define IRQ_STAT 0x82 #define OPSW 0x3c -/* - * Additional registers on the SG NX Pro - */ -#define COVOX_VOL 0x42 -#define TREBLE_LVL 0x44 -#define BASS_LVL 0x46 - #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 */ @@ -131,23 +108,6 @@ MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0) }; -#ifdef __SGNXPRO__ -mixer_tab sgnxpro_mix = { -MIX_ENT(SOUND_MIXER_VOLUME, 0x22, 7, 4, 0x22, 3, 4), -MIX_ENT(SOUND_MIXER_BASS, 0x46, 2, 3, 0x00, 0, 0), -MIX_ENT(SOUND_MIXER_TREBLE, 0x44, 2, 3, 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, 0x42, 2, 3, 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) -}; -#endif - 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), @@ -209,4 +169,13 @@ 0x00, /* SOUND_MIXER_ALTPCM */ 0x00 /* SOUND_MIXER_RECLEV */ }; + +/* + * Recording sources (SB Pro) + */ + +#define SRC_MIC 1 /* Select Microphone recording source */ +#define SRC_CD 3 /* Select CD recording source */ +#define SRC_LINE 7 /* Use Line-in for recording source */ + #endif diff -u --recursive --new-file v1.1.30/linux/drivers/sound/sequencer.c linux/drivers/sound/sequencer.c --- v1.1.30/linux/drivers/sound/sequencer.c Sun May 1 12:12:43 1994 +++ linux/drivers/sound/sequencer.c Mon Jul 18 09:50:55 1994 @@ -35,31 +35,52 @@ #ifndef EXCLUDE_SEQUENCER static int sequencer_ok = 0; +static struct sound_timer_operations *tmr; +static int tmr_no = -1; /* Currently selected timer */ +static int pending_timer = -1; /* For timer change operation */ + +/* + * Local counts for number of synth and MIDI devices. These are initialized + * by the sequencer_open. + */ +static int max_mididev = 0; +static int max_synthdev = 0; + +/* + * The seq_mode gives the operating mode of the sequencer: + * 1 = level1 (the default) + * 2 = level2 (extended capabilites) + */ + +#define SEQ_1 1 +#define SEQ_2 2 +static int seq_mode = SEQ_1; DEFINE_WAIT_QUEUE (seq_sleeper, seq_sleep_flag); -/* DEFINE_WAIT_QUEUE (midi_sleeper, midi_sleep_flag); */ -#define midi_sleeper seq_sleeper -#define midi_sleep_flag seq_sleep_flag +DEFINE_WAIT_QUEUE (midi_sleeper, midi_sleep_flag); static int midi_opened[MAX_MIDI_DEV] = -{0}; /* 1 if the process has opened MIDI */ +{0}; static int midi_written[MAX_MIDI_DEV] = {0}; -unsigned long seq_time = 0; /* Reference point for the timer */ +unsigned long prev_input_time = 0; +int prev_event_time; +unsigned long seq_time = 0; #include "tuning.h" #define EV_SZ 8 -#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 */ +#define IEV_SZ 8 +static unsigned char *queue = NULL; +static unsigned char *iqueue = NULL; static volatile int qhead = 0, qtail = 0, qlen = 0; static volatile int iqhead = 0, iqtail = 0, iqlen = 0; static volatile int seq_playing = 0; static int sequencer_busy = 0; static int output_treshold; +static int pre_event_timeout; static unsigned synth_open_mask; static int seq_queue (unsigned char *note); @@ -70,48 +91,48 @@ {0}; #if MAX_SYNTH_DEV > 15 -#error Too many synthesizer devices +#error Too many synthesizer devices enabled. #endif int sequencer_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) { int c = count, p = 0; + int ev_len; unsigned long flags; dev = dev >> 4; - if (dev) /* Patch manager device */ + ev_len = seq_mode == SEQ_1 ? 4 : 8; + + if (dev) /* + * Patch manager device + */ return pmgr_read (dev - 1, file, buf, count); - while (c > 3) + DISABLE_INTR (flags); + if (!iqlen) { - DISABLE_INTR (flags); + DO_SLEEP (midi_sleeper, midi_sleep_flag, pre_event_timeout); + if (!iqlen) { - if (c != count) /* Some data has been received */ - { - RESTORE_INTR (flags); - return count - c; /* Return what we have */ - } - - DO_SLEEP (midi_sleeper, midi_sleep_flag, 0); - - if (!iqlen) - { - RESTORE_INTR (flags); - return count - c; - } + RESTORE_INTR (flags); + return 0; } + } + + while (iqlen && c >= ev_len) + { - COPY_TO_USER (buf, p, &iqueue[iqhead * IEV_SZ], IEV_SZ); - p += 4; - c -= 4; + COPY_TO_USER (buf, p, &iqueue[iqhead * IEV_SZ], ev_len); + p += ev_len; + c -= ev_len; iqhead = (iqhead + 1) % SEQ_MAX_QUEUE; iqlen--; - RESTORE_INTR (flags); } + RESTORE_INTR (flags); return count - c; } @@ -119,19 +140,30 @@ static void sequencer_midi_output (int dev) { - /* Currently NOP */ + /* + * Currently NOP + */ } -static void -copy_to_input (unsigned char *event) +void +seq_copy_to_input (unsigned char *event, int len) { unsigned long flags; + /* + * Verify that the len is valid for the current mode. + */ + + if (len != 4 && len != 8) + return; + if ((seq_mode == SEQ_1) != (len == 4)) + return; + if (iqlen >= (SEQ_MAX_QUEUE - 1)) return; /* Overflow */ DISABLE_INTR (flags); - memcpy (&iqueue[iqtail * IEV_SZ], event, IEV_SZ); + memcpy (&iqueue[iqtail * IEV_SZ], event, len); iqlen++; iqtail = (iqtail + 1) % SEQ_MAX_QUEUE; @@ -145,23 +177,54 @@ static void sequencer_midi_input (int dev, unsigned char data) { - int tstamp; + unsigned int tstamp; unsigned char event[4]; - if (data == 0xfe) /* Active sensing */ - return; /* Ignore */ + if (data == 0xfe) /* Ignore active sensing */ + return; - tstamp = GET_TIME () - seq_time; /* Time since open() */ - tstamp = (tstamp << 8) | SEQ_WAIT; + tstamp = GET_TIME () - seq_time; + if (tstamp != prev_input_time) + { + tstamp = (tstamp << 8) | SEQ_WAIT; - copy_to_input ((unsigned char *) &tstamp); + seq_copy_to_input ((unsigned char *) &tstamp, 4); + prev_input_time = tstamp; + } event[0] = SEQ_MIDIPUTC; event[1] = data; event[2] = dev; event[3] = 0; - copy_to_input (event); + seq_copy_to_input (event, 4); +} + +void +seq_input_event (unsigned char *event, int len) +{ + unsigned long this_time; + + if (seq_mode == SEQ_2) + this_time = tmr->get_time (tmr_no); + else + this_time = GET_TIME () - seq_time; + + if (this_time != prev_input_time) + { + unsigned char tmp_event[8]; + + tmp_event[0] = EV_TIMING; + tmp_event[1] = TMR_WAIT_ABS; + tmp_event[2] = 0; + tmp_event[3] = 0; + *(unsigned long *) &tmp_event[4] = this_time; + + seq_copy_to_input (tmp_event, 8); + prev_input_time = this_time; + } + + seq_copy_to_input (event, len); } int @@ -179,7 +242,9 @@ if (mode == OPEN_READ) return RET_ERROR (EIO); - if (dev) /* Patch manager device */ + if (dev) /* + * Patch manager device + */ return pmgr_write (dev - 1, file, buf, count); c = count; @@ -194,7 +259,7 @@ int err; dev = *(unsigned short *) &event[2]; - if (dev < 0 || dev >= num_synths) + if (dev < 0 || dev >= max_synthdev) return RET_ERROR (ENXIO); if (!(synth_open_mask & (1 << dev))) @@ -207,8 +272,13 @@ return err; } - if (ev_code == SEQ_EXTENDED || ev_code == SEQ_PRIVATE) + if (ev_code >= 128) { + if (seq_mode == SEQ_2 && ev_code == SEQ_EXTENDED) + { + printk ("Sequencer: Invalid level 2 event %x\n", ev_code); + return RET_ERROR (EINVAL); + } ev_size = 8; @@ -223,7 +293,14 @@ } else - ev_size = 4; + { + if (seq_mode == SEQ_2) + { + printk ("Sequencer: 4 byte event in level 2 mode\n"); + return RET_ERROR (EINVAL); + } + ev_size = 4; + } if (event[0] == SEQ_MIDIPUTC) { @@ -233,7 +310,7 @@ int mode; int dev = event[2]; - if (dev >= num_midis) + if (dev >= max_mididev) { printk ("Sequencer Error: Nonexistent MIDI device %d\n", dev); return RET_ERROR (ENXIO); @@ -276,20 +353,28 @@ seq_queue (unsigned char *note) { - /* Test if there is space in the queue */ + /* + * Test if there is space in the queue + */ if (qlen >= SEQ_MAX_QUEUE) if (!seq_playing) - seq_startplay (); /* Give chance to drain the queue */ + seq_startplay (); /* + * Give chance to drain the queue + */ if (qlen >= SEQ_MAX_QUEUE && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) { - /* Sleep until there is enough space on the queue */ + /* + * Sleep until there is enough space on the queue + */ DO_SLEEP (seq_sleeper, seq_sleep_flag, 0); } if (qlen >= SEQ_MAX_QUEUE) - return 0; /* To be sure */ + return 0; /* + * To be sure + */ memcpy (&queue[qtail * EV_SZ], note, EV_SZ); @@ -304,7 +389,7 @@ { int dev = q[2]; - if (dev < 0 || dev >= num_synths) + if (dev < 0 || dev >= max_synthdev) return RET_ERROR (ENXIO); if (!(synth_open_mask & (1 << dev))) @@ -313,7 +398,7 @@ switch (q[1]) { case SEQ_NOTEOFF: - synth_devs[dev]->kill_note (dev, q[3], q[5]); + synth_devs[dev]->kill_note (dev, q[3], q[4], q[5]); break; case SEQ_NOTEON: @@ -340,7 +425,8 @@ break; case SEQ_VOLMODE: - synth_devs[dev]->volume_method (dev, q[3]); + if (synth_devs[dev]->volume_method != NULL) + synth_devs[dev]->volume_method (dev, q[3]); break; default: @@ -350,6 +436,282 @@ return 0; } +static int +find_voice (int dev, int chn, int note) +{ + unsigned short key; + int i; + + key = (chn << 8) | (note + 1); + + for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++) + if (synth_devs[dev]->alloc.map[i] == key) + return i; + + return -1; +} + +static int +alloc_voice (int dev, int chn, int note) +{ + unsigned short key; + int voice; + + key = (chn << 8) | (note + 1); + + voice = synth_devs[dev]->alloc_voice (dev, chn, note, + &synth_devs[dev]->alloc); + synth_devs[dev]->alloc.map[voice] = key; + return voice; +} + +static void +seq_chn_voice_event (unsigned char *event) +{ + unsigned char dev = event[1]; + unsigned char cmd = event[2]; + unsigned char chn = event[3]; + unsigned char note = event[4]; + unsigned char parm = event[5]; + int voice = -1; + + if ((int) dev > max_synthdev) + return; + if (!(synth_open_mask & (1 << dev))) + return; + if (!synth_devs[dev]) + return; + + if (seq_mode == SEQ_2) + if (synth_devs[dev]->alloc_voice) + voice = find_voice (dev, chn, note); + + if (cmd == MIDI_NOTEON && parm == 0) + { + cmd = MIDI_NOTEOFF; + parm = 64; + } + + switch (cmd) + { + case MIDI_NOTEON: + if (note > 127) + return; + + if (voice == -1 && seq_mode == SEQ_2 && synth_devs[dev]->alloc_voice) + { + voice = alloc_voice (dev, chn, note); + } + + if (voice == -1) + voice = chn; + + if (seq_mode == SEQ_2) + { + synth_devs[dev]->set_instr (dev, voice, + synth_devs[dev]->chn_info[chn].pgm_num); + } + + synth_devs[dev]->start_note (dev, voice, note, parm); + break; + + case MIDI_NOTEOFF: + if (voice == -1) + voice = chn; + synth_devs[dev]->kill_note (dev, voice, note, parm); + break; + + case MIDI_KEY_PRESSURE: + /* To be implemented */ + break; + + default:; + } +} + +static void +seq_chn_common_event (unsigned char *event) +{ + unsigned char dev = event[1]; + unsigned char cmd = event[2]; + unsigned char chn = event[3]; + unsigned char p1 = event[4]; + + /* unsigned char p2 = event[5]; */ + unsigned short w14 = *(short *) &event[6]; + + if ((int) dev > max_synthdev) + return; + if (!(synth_open_mask & (1 << dev))) + return; + if (!synth_devs[dev]) + return; + + switch (cmd) + { + case MIDI_PGM_CHANGE: + if (seq_mode == SEQ_2) + { + synth_devs[dev]->chn_info[chn].pgm_num = p1; + } + else + synth_devs[dev]->set_instr (dev, chn, p1); + break; + + case MIDI_CTL_CHANGE: + if (p1 == CTRL_MAIN_VOLUME) + { + w14 = (unsigned short) (((int) w14 * 16383) / 100); + p1 = CTL_MAIN_VOLUME; + } + if (p1 == CTRL_EXPRESSION) + { + w14 *= 128; + p1 = CTL_EXPRESSION; + } + + if (seq_mode == SEQ_2) + { + if (chn > 15 || p1 > 127) + break; + + synth_devs[dev]->chn_info[chn].controllers[p1] = w14 & 0xff; + + if (dev < num_synths) + { + int val = w14 & 0xff; + + if (p1 < 64) /* Combine MSB and LSB */ + { + val = ((synth_devs[dev]-> + chn_info[chn].controllers[p1 & ~32] & 0x7f) << 7) + | (synth_devs[dev]-> + chn_info[chn].controllers[p1 | 32] & 0x7f); + p1 &= ~32; + } + else + val = synth_devs[dev]->chn_info[chn].controllers[p1]; + + synth_devs[dev]->controller (dev, chn, p1, val); + } + else + synth_devs[dev]->controller (dev, chn, p1, w14); + } + else + synth_devs[dev]->controller (dev, chn, p1, w14); + break; + + case MIDI_PITCH_BEND: + synth_devs[dev]->bender (dev, chn, w14); + break; + + default:; + } +} + +static int +seq_timing_event (unsigned char *event) +{ + unsigned char cmd = event[1]; + unsigned int parm = *(int *) &event[4]; + + if (seq_mode == SEQ_2) + { + int ret; + + if ((ret = tmr->event (tmr_no, event)) == TIMER_ARMED) + { + if ((SEQ_MAX_QUEUE - qlen) >= output_treshold) + { + unsigned long flags; + + DISABLE_INTR (flags); + if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) + { + WAKE_UP (seq_sleeper, seq_sleep_flag); + } + RESTORE_INTR (flags); + } + } + return ret; + } + + switch (cmd) + { + case TMR_WAIT_REL: + parm += prev_event_time; + + /* + * NOTE! No break here. Execution of TMR_WAIT_REL continues in the + * next case (TMR_WAIT_ABS) + */ + + case TMR_WAIT_ABS: + if (parm > 0) + { + long time; + + seq_playing = 1; + time = parm; + prev_event_time = time; + + request_sound_timer (time); + + if ((SEQ_MAX_QUEUE - qlen) >= output_treshold) + { + unsigned long flags; + + DISABLE_INTR (flags); + if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) + { + WAKE_UP (seq_sleeper, seq_sleep_flag); + } + RESTORE_INTR (flags); + } + + return TIMER_ARMED; + } + break; + + case TMR_START: + seq_time = GET_TIME (); + prev_input_time = 0; + prev_event_time = 0; + break; + + case TMR_STOP: + break; + + case TMR_CONTINUE: + break; + + case TMR_TEMPO: + break; + + case TMR_ECHO: + if (seq_mode == SEQ_2) + seq_copy_to_input (event, 8); + else + { + parm = (parm << 8 | SEQ_ECHO); + seq_copy_to_input ((unsigned char *) &parm, 4); + } + break; + + default:; + } + + return TIMER_NOT_ARMED; +} + +static void +seq_local_event (unsigned char *event) +{ + /* unsigned char cmd = event[1]; */ + + printk ("seq_local_event() called. WHY????????\n"); +} + static void seq_startplay (void) { @@ -359,6 +721,9 @@ while (qlen > 0) { + + seq_playing = 1; + qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE; qlen--; @@ -369,7 +734,7 @@ case SEQ_NOTEOFF: if (synth_open_mask & (1 << 0)) if (synth_devs[0]) - synth_devs[0]->kill_note (0, q[1], q[3]); + synth_devs[0]->kill_note (0, q[1], 255, q[3]); break; case SEQ_NOTEON: @@ -380,8 +745,10 @@ break; case SEQ_WAIT: - delay = (unsigned long *) q; /* Bytes 1 to 3 are containing the - * delay in GET_TIME() */ + delay = (unsigned long *) q; /* + * Bytes 1 to 3 are containing the * + * delay in GET_TIME() + */ *delay = (*delay >> 8) & 0xffffff; if (*delay > 0) @@ -390,6 +757,7 @@ seq_playing = 1; time = *delay; + prev_event_time = time; request_sound_timer (time); @@ -404,8 +772,11 @@ } RESTORE_INTR (flags); } - return; /* Stop here. Timer routine will continue - * playing after the delay */ + /* + * The timer is now active and will reinvoke this function + * after the timer expires. Return to the caller now. + */ + return; } break; @@ -415,11 +786,17 @@ synth_devs[0]->set_instr (0, q[1], q[2]); break; - case SEQ_SYNCTIMER: /* Reset timer */ + case SEQ_SYNCTIMER: /* + * Reset timer + */ seq_time = GET_TIME (); + prev_input_time = 0; + prev_event_time = 0; break; - case SEQ_MIDIPUTC: /* Put a midi character */ + case SEQ_MIDIPUTC: /* + * Put a midi character + */ if (midi_opened[q[2]]) { int dev; @@ -433,7 +810,9 @@ */ qlen++; - qhead = this_one; /* Restore queue */ + qhead = this_one; /* + * Restore queue + */ seq_playing = 1; request_sound_timer (-1); return; @@ -444,11 +823,13 @@ break; case SEQ_ECHO: - copy_to_input (q); /* Echo back to the process */ + seq_copy_to_input (q, 4); /* + * Echo back to the process + */ break; case SEQ_PRIVATE: - if (q[1] < num_synths) + if ((int) q[1] < max_synthdev) synth_devs[q[1]]->hw_control (q[1], q); break; @@ -456,6 +837,25 @@ extended_event (q); break; + case EV_CHN_VOICE: + seq_chn_voice_event (q); + break; + + case EV_CHN_COMMON: + seq_chn_common_event (q); + break; + + case EV_TIMING: + if (seq_timing_event (q) == TIMER_ARMED) + { + return; + } + break; + + case EV_SEQ_LOCAL: + seq_local_event (q); + break; + default:; } @@ -477,10 +877,55 @@ } +static void +reset_controllers (int dev, unsigned char *controller, int update_dev) +{ +#include "midi_ctrl.h" + + int i; + + for (i = 0; i < 128; i++) + controller[i] = ctrl_def_values[i]; +} + +static void +setup_mode2 (void) +{ + int dev; + + max_synthdev = num_synths; + + for (dev = 0; dev < num_midis; dev++) + if (midi_devs[dev]->converter != NULL) + { + synth_devs[max_synthdev++] = + midi_devs[dev]->converter; + } + + for (dev = 0; dev < max_synthdev; dev++) + { + int chn; + + for (chn = 0; chn < 16; chn++) + { + synth_devs[dev]->chn_info[chn].pgm_num = 0; + reset_controllers (dev, + synth_devs[dev]->chn_info[chn].controllers, + 0); + } + } + + max_mididev = 0; + seq_mode = SEQ_2; +} + int sequencer_open (int dev, struct fileinfo *file) { int retval, mode, i; + int level, tmp; + + level = ((dev & 0x0f) == SND_DEV_SEQ2) ? 2 : 1; dev = dev >> 4; mode = file->mode & O_ACCMODE; @@ -493,15 +938,22 @@ return RET_ERROR (ENXIO); } - if (dev) /* Patch manager device */ + if (dev) /* + * Patch manager device + */ { int err; dev--; + + if (dev >= MAX_SYNTH_DEV) + return RET_ERROR (ENXIO); if (pmgr_present[dev]) return RET_ERROR (EBUSY); if ((err = pmgr_open (dev)) < 0) - return err; /* Failed */ + return err; /* + * Failed + */ pmgr_present[dev] = 1; return err; @@ -513,40 +965,105 @@ return RET_ERROR (EBUSY); } - if (!(num_synths + num_midis)) - return RET_ERROR (ENXIO); + max_mididev = num_midis; + max_synthdev = num_synths; + pre_event_timeout = 0; + seq_mode = SEQ_1; - synth_open_mask = 0; + if (pending_timer != -1) + { + tmr_no = pending_timer; + pending_timer = -1; + } - 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); + if (tmr_no == -1) /* Not selected yet */ + { + int i, best; - seq_time = GET_TIME (); + best = -1; + for (i = 0; i < num_sound_timers; i++) + if (sound_timer_devs[i]->priority > best) + { + tmr_no = i; + best = sound_timer_devs[i]->priority; + } - for (i = 0; i < num_midis; i++) - { - midi_opened[i] = 0; - midi_written[i] = 0; + if (tmr_no == -1) /* Should not be */ + tmr_no = 0; } - if (mode == OPEN_READ || mode == OPEN_READWRITE) - { /* Initialize midi input devices */ - if (!num_midis) + tmr = sound_timer_devs[tmr_no]; + + if (level == 2) + { + printk ("Using timer #%d\n", tmr_no); + if (tmr == NULL) { - printk ("Sequencer: No Midi devices. Input not possible\n"); + printk ("sequencer: No timer for level 2\n"); return RET_ERROR (ENXIO); } + setup_mode2 (); + } - for (i = 0; i < num_midis; i++) - { - if ((retval = midi_devs[i]->open (i, mode, + if (seq_mode == SEQ_1 && (mode == OPEN_READ || mode == OPEN_READWRITE)) + if (!max_mididev) + { + printk ("Sequencer: No Midi devices. Input not possible\n"); + return RET_ERROR (ENXIO); + } + + if (!max_synthdev && !max_mididev) + return RET_ERROR (ENXIO); + + synth_open_mask = 0; + + for (i = 0; i < max_mididev; i++) + { + midi_opened[i] = 0; + midi_written[i] = 0; + } + + /* + * if (mode == OPEN_WRITE || mode == OPEN_READWRITE) + */ + for (i = 0; i < max_synthdev; i++) /* + * Open synth devices + */ + if ((tmp = synth_devs[i]->open (i, mode)) < 0) + { + printk ("Sequencer: Warning! Cannot open synth device #%d (%d)\n", i, tmp); + if (synth_devs[i]->midi_dev) + printk ("(Maps to midi dev #%d\n", synth_devs[i]->midi_dev); + } + else + { + synth_open_mask |= (1 << i); + if (synth_devs[i]->midi_dev) /* + * Is a midi interface + */ + midi_opened[synth_devs[i]->midi_dev] = 1; + } + + seq_time = GET_TIME (); + prev_input_time = 0; + prev_event_time = 0; + + if (seq_mode == SEQ_1 && (mode == OPEN_READ || mode == OPEN_READWRITE)) + { /* + * Initialize midi input devices + */ + for (i = 0; i < max_mididev; i++) + if (!midi_opened[i]) + { + if ((retval = midi_devs[i]->open (i, mode, sequencer_midi_input, sequencer_midi_output)) >= 0) - midi_opened[i] = 1; - } + midi_opened[i] = 1; + } + } + + if (seq_mode == SEQ_2) + { + tmr->open (tmr_no, seq_mode); } sequencer_busy = 1; @@ -576,7 +1093,7 @@ { n = 0; - for (i = 0; i < num_midis; i++) + for (i = 0; i < max_mididev; i++) if (midi_opened[i] && midi_written[i]) if (midi_devs[i]->buffer_status != NULL) if (midi_devs[i]->buffer_status (i)) @@ -602,7 +1119,9 @@ DEB (printk ("sequencer_release(dev=%d)\n", dev)); - if (dev) /* Patch manager device */ + if (dev) /* + * Patch manager device + */ { dev--; pmgr_release (dev); @@ -611,34 +1130,48 @@ } /* - * Wait until the queue is empty + * * Wait until the queue is empty */ - while (!PROCESS_ABORTING (seq_sleeper, seq_sleep_flag) && qlen) - { - seq_sync (); - } + if (mode != OPEN_READ) + while (!PROCESS_ABORTING (seq_sleeper, seq_sleep_flag) && qlen) + { + seq_sync (); + } if (mode != OPEN_READ) - seq_drain_midi_queues (); /* Ensure the output queues are empty */ + 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 */ - - 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 (synth_open_mask & (1 << i)) /* Actually opened */ - if (synth_devs[i]) + seq_drain_midi_queues (); /* + * Flush the all notes off messages + */ + + for (i = 0; i < max_synthdev; i++) + if (synth_open_mask & (1 << i)) /* + * Actually opened + */ + if (synth_devs[i]) + { synth_devs[i]->close (i); + if (synth_devs[i]->midi_dev) + midi_opened[synth_devs[i]->midi_dev] = 0; + } + for (i = 0; i < num_synths; i++) if (pmgr_present[i]) pmgr_inform (i, PM_E_CLOSED, 0, 0, 0, 0); + for (i = 0; i < max_mididev; i++) + if (midi_opened[i]) + midi_devs[i]->close (i); + + if (seq_mode == SEQ_2) + tmr->close (tmr_no); + sequencer_busy = 0; } @@ -648,7 +1181,10 @@ if (qlen && !seq_playing && !PROCESS_ABORTING (seq_sleeper, seq_sleep_flag)) seq_startplay (); - if (qlen && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) /* Queue not empty */ + if (qlen && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) /* + * Queue not + * empty + */ { DO_SLEEP (seq_sleeper, seq_sleep_flag, 0); } @@ -665,11 +1201,19 @@ int n; - /* This routine sends one byte to the Midi channel. */ - /* If the output Fifo is full, it waits until there */ - /* is space in the queue */ + /* + * This routine sends one byte to the Midi channel. + */ + /* + * If the output Fifo is full, it waits until there + */ + /* + * is space in the queue + */ - n = 300; /* Timeout in jiffies */ + n = 300; /* + * Timeout in jiffies + */ while (n && !midi_devs[dev]->putc (dev, data)) { @@ -685,34 +1229,66 @@ * NOTE! Calls sleep(). Don't call this from interrupt. */ - int i, chn; + int i; + + int chn; sound_stop_timer (); + seq_time = GET_TIME (); + prev_input_time = 0; + prev_event_time = 0; qlen = qhead = qtail = 0; iqlen = iqhead = iqtail = 0; - for (i = 0; i < num_synths; i++) + for (i = 0; i < max_synthdev; i++) if (synth_open_mask & (1 << i)) if (synth_devs[i]) synth_devs[i]->reset (i); - for (i = 0; i < num_midis; i++) - if (midi_written[i]) /* Midi used. Some notes may still be playing */ - { - for (chn = 0; chn < 16; chn++) + if (seq_mode == SEQ_2) + { + for (i = 0; i < max_synthdev; i++) + if (synth_open_mask & (1 << i)) + if (synth_devs[i]) + for (chn = 0; chn < 16; chn++) + synth_devs[i]->controller (i, chn, 0xfe, 0); /* All notes off */ + } + else + { + for (i = 0; i < max_mididev; i++) + if (midi_written[i]) /* + * Midi used. Some notes may still be playing + */ { - midi_outc (i, - (unsigned char) (0xb0 + (chn & 0xff))); /* Channel msg */ - midi_outc (i, 0x7b);/* All notes off */ - midi_outc (i, 0); /* Dummy parameter */ - } + /* + * Sending just a ACTIVE SENSING message should be enough to stop all + * playing notes. Since there are devices not recognizing the + * active sensing, we have to send some all notes off messages also. + */ + midi_outc (i, 0xfe); + + for (chn = 0; chn < 16; chn++) + { + midi_outc (i, + (unsigned char) (0xb0 + (chn & 0xff))); /* + * Channel + * msg + */ + midi_outc (i, 0x7b); /* + * All notes off + */ + midi_outc (i, 0); /* + * Dummy parameter + */ + } - midi_devs[i]->close (i); + midi_devs[i]->close (i); - midi_written[i] = 0; - midi_opened[i] = 0; - } + midi_written[i] = 0; + midi_opened[i] = 0; + } + } seq_playing = 0; @@ -721,6 +1297,28 @@ } +static void +seq_panic (void) +{ + /* + * This routine is called by the application in case the user + * wants to reset the system to the default state. + */ + + seq_reset (); + + /* + * Since some of the devices don't recognize the active sensing and + * all notes off messages, we have to shut all notes manually. + * + * TO BE IMPLEMENTED LATER + */ + + /* + * Also return the controllers to their default states + */ +} + int sequencer_ioctl (int dev, struct fileinfo *file, unsigned int cmd, unsigned int arg) @@ -732,20 +1330,62 @@ switch (cmd) { + case SNDCTL_TMR_TIMEBASE: + case SNDCTL_TMR_TEMPO: + case SNDCTL_TMR_START: + case SNDCTL_TMR_STOP: + case SNDCTL_TMR_CONTINUE: + case SNDCTL_TMR_METRONOME: + case SNDCTL_TMR_SOURCE: + if (dev) /* Patch manager */ + return RET_ERROR (EIO); - case SNDCTL_SEQ_SYNC: + if (seq_mode != SEQ_2) + return RET_ERROR (EINVAL); + return tmr->ioctl (tmr_no, cmd, arg); + break; + + case SNDCTL_TMR_SELECT: if (dev) /* Patch manager */ return RET_ERROR (EIO); + if (seq_mode != SEQ_2) + return RET_ERROR (EINVAL); + pending_timer = IOCTL_IN (arg); + + if (pending_timer < 0 || pending_timer >= num_sound_timers) + { + pending_timer = -1; + return RET_ERROR (EINVAL); + } + + return IOCTL_OUT (arg, pending_timer); + break; + + case SNDCTL_SEQ_PANIC: + seq_panic (); + break; + + case SNDCTL_SEQ_SYNC: + if (dev) /* + * Patch manager + */ + return RET_ERROR (EIO); + if (mode == OPEN_READ) return 0; while (qlen && !PROCESS_ABORTING (seq_sleeper, seq_sleep_flag)) seq_sync (); - return 0; + if (qlen) + return RET_ERROR (EINTR); + else + return 0; break; case SNDCTL_SEQ_RESET: - if (dev) /* Patch manager */ + if (dev) /* + * Patch manager + */ return RET_ERROR (EIO); seq_reset (); @@ -753,11 +1393,13 @@ break; case SNDCTL_SEQ_TESTMIDI: - if (dev) /* Patch manager */ + if (dev) /* + * Patch manager + */ return RET_ERROR (EIO); midi_dev = IOCTL_IN (arg); - if (midi_dev >= num_midis) + if (midi_dev >= max_mididev) return RET_ERROR (ENXIO); if (!midi_opened[midi_dev]) @@ -777,7 +1419,9 @@ break; case SNDCTL_SEQ_GETINCOUNT: - if (dev) /* Patch manager */ + if (dev) /* + * Patch manager + */ return RET_ERROR (EIO); if (mode == OPEN_WRITE) @@ -796,7 +1440,15 @@ if (dev) /* Patch manager */ return RET_ERROR (EIO); - /* If *arg == 0, just return the current rate */ + /* + * If *arg == 0, just return the current rate + */ + if (seq_mode == SEQ_2) + return tmr->ioctl (tmr_no, cmd, arg); + + if (IOCTL_IN (arg) != 0) + return RET_ERROR (EINVAL); + return IOCTL_OUT (arg, HZ); break; @@ -815,11 +1467,11 @@ break; case SNDCTL_SEQ_NRSYNTHS: - return IOCTL_OUT (arg, num_synths); + return IOCTL_OUT (arg, max_synthdev); break; case SNDCTL_SEQ_NRMIDIS: - return IOCTL_OUT (arg, num_midis); + return IOCTL_OUT (arg, max_mididev); break; case SNDCTL_SYNTH_MEMAVL: @@ -859,7 +1511,7 @@ IOCTL_FROM_USER ((char *) &inf, (char *) arg, 0, sizeof (inf)); dev = inf.device; - if (dev < 0 || dev >= num_synths) + if (dev < 0 || dev >= max_synthdev) return RET_ERROR (ENXIO); if (!(synth_open_mask & (1 << dev)) && !orig_dev) @@ -877,7 +1529,7 @@ IOCTL_FROM_USER ((char *) &inf, (char *) arg, 0, sizeof (inf)); dev = inf.device; - if (dev < 0 || dev >= num_midis) + if (dev < 0 || dev >= max_mididev) return RET_ERROR (ENXIO); IOCTL_TO_USER ((char *) arg, 0, (char *) &(midi_devs[dev]->info), sizeof (inf)); @@ -957,7 +1609,9 @@ { int tmp = IOCTL_IN (arg); - if (dev) /* Patch manager */ + if (dev) /* + * Patch manager + */ return RET_ERROR (EIO); if (tmp < 1) @@ -969,8 +1623,23 @@ } break; + case SNDCTL_MIDI_PRETIME: + { + int val = IOCTL_IN (arg); + + if (val < 0) + val = 0; + + val = (HZ * val) / 10; + pre_event_timeout = val; + return IOCTL_OUT (arg, val); + } + break; + default: - if (dev) /* Patch manager */ + if (dev) /* + * Patch manager + */ return RET_ERROR (EIO); if (mode == OPEN_READ) @@ -991,6 +1660,8 @@ int sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * wait) { + unsigned long flags; + dev = dev >> 4; switch (sel_type) @@ -998,17 +1669,22 @@ case SEL_IN: if (!iqlen) { + DISABLE_INTR (flags); + midi_sleep_flag.mode = WK_SLEEP; select_wait (&midi_sleeper, wait); + RESTORE_INTR (flags); return 0; } return 1; - break; case SEL_OUT: if (qlen >= SEQ_MAX_QUEUE) { + DISABLE_INTR (flags); + seq_sleep_flag.mode = WK_SLEEP; select_wait (&seq_sleeper, wait); + RESTORE_INTR (flags); return 0; } return 1; @@ -1042,7 +1718,7 @@ { 261632, 277189, 293671, 311132, 329632, 349232, 369998, 391998, 415306, 440000, 466162, 493880 - }; /* Note freq*1000 for octave 5 */ + }; #define BASE_OCTAVE 5 @@ -1056,7 +1732,9 @@ else if (octave > BASE_OCTAVE) note_freq <<= (octave - BASE_OCTAVE); - /* note_freq >>= 1; */ + /* + * note_freq >>= 1; + */ return note_freq; } @@ -1102,12 +1780,17 @@ semitones = bend / 100; cents = bend % 100; - amount = semitone_tuning[semitones] * multiplier * cent_tuning[cents] / 10000; + amount = (int) (semitone_tuning[semitones] * multiplier * cent_tuning[cents]) + / 10000; if (negative) - return (base_freq * 10000) / amount; /* Bend down */ + return (base_freq * 10000) / amount; /* + * Bend down + */ else - return (base_freq * amount) / 10000; /* Bend up */ + return (base_freq * amount) / 10000; /* + * Bend up + */ } @@ -1123,7 +1806,9 @@ } #else -/* Stub version */ +/* + * Stub version + */ int sequencer_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) { diff -u --recursive --new-file v1.1.30/linux/drivers/sound/sound_calls.h linux/drivers/sound/sound_calls.h --- v1.1.30/linux/drivers/sound/sound_calls.h Sun May 1 12:12:43 1994 +++ linux/drivers/sound/sound_calls.h Mon Jul 18 09:50:55 1994 @@ -4,7 +4,6 @@ int DMAbuf_open(int dev, int mode); int DMAbuf_release(int dev, int mode); -int DMAbuf_read (int dev, snd_rw_buf *user_buf, int count); int DMAbuf_getwrbuffer(int dev, char **buf, int *size); int DMAbuf_getrdbuffer(int dev, char **buf, int *len); int DMAbuf_rmchars(int dev, int buff_no, int c); @@ -46,6 +45,8 @@ void sequencer_timer(void); int note_to_freq(int note_num); unsigned long compute_finetune(unsigned long base_freq, int bend, int range); +void seq_input_event(unsigned char *event, int len); +void seq_copy_to_input (unsigned char *event, int len); #ifdef ALLOW_SELECT int sequencer_select(int dev, struct fileinfo *file, int sel_type, select_table * wait); @@ -65,6 +66,10 @@ void MIDIbuf_bytes_received(int dev, unsigned char *buf, int count); long MIDIbuf_init(long mem_start); +#ifdef ALLOW_SELECT +int MIDIbuf_select(int dev, struct fileinfo *file, int sel_type, select_table * wait); +#endif + /* * System calls for the generic midi interface. * @@ -126,16 +131,16 @@ void sb16midiintr (int unit); long attach_sb16midi(long mem_start, struct address_info * hw_config); int probe_sb16midi(struct address_info *hw_config); +void sb_midi_interrupt(int dummy); /* From sb_midi.c */ void sb_midi_init(int model); -void sb_midi_interrupt(int dummy); /* 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); -int sb_mixer_init(int major_model); +void sb_mixer_init(int major_model); /* From opl3.c */ int opl3_detect (int ioaddr); @@ -173,6 +178,8 @@ int probe_gus(struct address_info *hw_config); int gus_set_midi_irq(int num); void gusintr(int); +long attach_gus_db16(long mem_start, struct address_info * hw_config); +int probe_gus_db16(struct address_info *hw_config); /* From gus_wave.c */ int gus_wave_detect(int baseaddr); @@ -192,6 +199,10 @@ long attach_mpu401(long mem_start, struct address_info * hw_config); int probe_mpu401(struct address_info *hw_config); +/* From uart6850.c */ +long attach_uart6850(long mem_start, struct address_info * hw_config); +int probe_uart6850(struct address_info *hw_config); + /* From opl3.c */ void enable_opl3_mode(int left, int right, int both); @@ -206,3 +217,27 @@ /* From ics2101.c */ long ics2101_mixer_init(long mem_start); + +/* From sound_timer.c */ +void sound_timer_init(int io_base); +void sound_timer_interrupt(void); + +/* From ad1848.c */ +void ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture); +int ad1848_detect (int io_base); +void ad1848_interrupt (int dev); +long attach_ms_sound(long mem_start, struct address_info * hw_config); +int probe_ms_sound(struct address_info *hw_config); + +/* From pss.c */ +int probe_pss (struct address_info *hw_config); +long attach_pss (long mem_start, struct address_info *hw_config); + +int pss_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count); +int pss_write (int dev, struct fileinfo *file, snd_rw_buf *buf, int count); +int pss_open (int dev, struct fileinfo *file); +void pss_release (int dev, struct fileinfo *file); +int pss_ioctl (int dev, struct fileinfo *file, + unsigned int cmd, unsigned int arg); +int pss_lseek (int dev, struct fileinfo *file, off_t offset, int orig); +long pss_init(long mem_start); diff -u --recursive --new-file v1.1.30/linux/drivers/sound/sound_config.h linux/drivers/sound/sound_config.h --- v1.1.30/linux/drivers/sound/sound_config.h Fri Jan 21 15:59:51 1994 +++ linux/drivers/sound/sound_config.h Mon Jul 18 09:50:55 1994 @@ -30,7 +30,18 @@ #include "local.h" +#if defined(ISC) || defined(SCO) || defined(SVR42) +#define GENERIC_SYSV +#endif + +/* + * Disable the AD1848 driver if there are no other drivers requiring it. + */ +#if defined(EXCLUDE_GUS16) && defined(EXCLUDE_MSS) && defined(EXCLUDE_PSS) && defined(EXCLUDE_GUSMAX) +#define EXCLUDE_AD1848 +#endif + #undef CONFIGURE_SOUNDCARD #undef DYNAMIC_BUFFER @@ -50,18 +61,6 @@ #define SND_DEFAULT_ENABLE 1 #endif -/** UWM - new MIDI stuff **/ - -#ifdef EXCLUDE_CHIP_MIDI -#define EXCLUDE_PRO_MIDI -#endif - -/** UWM - stuff **/ - -#if defined(EXCLUDE_SEQUENCER) && defined(EXCLUDE_AUDIO) -#undef CONFIGURE_SOUNDCARD -#endif - #ifdef CONFIGURE_SOUNDCARD /* ****** IO-address, DMA and IRQ settings **** @@ -125,6 +124,19 @@ #define MPU_IRQ 6 #endif +/* Echo Personal Sound System */ +#ifndef PSS_BASE +#define PSS_BASE 0x220 /* 0x240 or */ +#endif + +#ifndef PSS_IRQ +#define PSS_IRQ 7 +#endif + +#ifndef PSS_DMA +#define PSS_DMA 1 +#endif + #ifndef MAX_REALTIME_FACTOR #define MAX_REALTIME_FACTOR 4 #endif @@ -156,48 +168,42 @@ driver. (There is no need to alter this) */ #define SEQ_MAX_QUEUE 1024 -#define SBFM_MAXINSTR (256) /* Size of the FM Instrument - bank */ +#define SBFM_MAXINSTR (256) /* Size of the FM Instrument bank */ /* 128 instruments for general MIDI setup and 16 unassigned */ -#define SND_NDEVS 50 /* Number of supported devices */ +/* + * Minor numbers for the sound driver. + * + * Unfortunately Creative called the codec chip of SB as a DSP. For this + * reason the /dev/dsp is reserved for digitized audio use. There is a + * device for true DSP processors but it will be called something else. + * In v3.0 it's /dev/sndproc but this could be a temporary solution. + */ + +#define SND_NDEVS 64 /* Number of supported devices */ #define SND_DEV_CTL 0 /* Control port /dev/mixer */ #define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM synthesizer and MIDI output) */ -#define SND_DEV_MIDIN 2 /* MIDI input /dev/midin (not implemented - yet) */ +#define SND_DEV_MIDIN 2 /* Raw midi access */ #define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */ #define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */ #define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */ -#define SND_DEV_STATUS 6 /* /dev/sndstatus */ - -/* UWM ... note add new MIDI devices here.. - * Also do not forget to add table midi_supported[] - * Minor numbers for on-chip midi devices start from 15.. and - * should be contiguous.. viz. 15,16,17.... - * ERROR!!!!!!!!! NO NO. Minor numbers above 15 are reserved!!!!!! Hannu - * Also note the max # of midi devices as MAX_MIDI_DEV - */ - -#define CMIDI_DEV_PRO 15 /* Chip midi device == /dev/pro_midi */ +#define SND_DEV_STATUS 6 /* /dev/sndstat */ +/* #7 not in use now. Was in 2.4. Free for use after v3.0. */ +#define SND_DEV_SEQ2 8 /* /dev/sequecer, level 2 interface */ +#define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */ +#define SND_DEV_PSS SND_DEV_SNDPROC -/* - * Add other midis here... - . - . - . - . - */ - #define DSP_DEFAULT_SPEED 8000 #define ON 1 #define OFF 0 -#define MAX_DSP_DEV 4 +#define MAX_AUDIO_DEV 4 #define MAX_MIXER_DEV 2 #define MAX_SYNTH_DEV 3 -#define MAX_MIDI_DEV 4 +#define MAX_MIDI_DEV 6 +#define MAX_TIMER_DEV 3 struct fileinfo { int mode; /* Open mode */ @@ -209,6 +215,20 @@ int dma; }; +#define SYNTH_MAX_VOICES 32 + +struct voice_alloc_info { + int max_voice; + int used_voices; + int ptr; /* For device specific use */ + unsigned short map[SYNTH_MAX_VOICES]; /* (ch << 8) | (note+1) */ + }; + +struct channel_info { + int pgm_num; + unsigned char controllers[128]; + }; + /* * Process wakeup reasons */ @@ -228,6 +248,11 @@ #ifndef DEB #define DEB(x) + +#define TIMER_ARMED 121234 +#define TIMER_NOT_ARMED 1 + +#define FUTURE_VERSION #endif #endif diff -u --recursive --new-file v1.1.30/linux/drivers/sound/sound_switch.c linux/drivers/sound/sound_switch.c --- v1.1.30/linux/drivers/sound/sound_switch.c Sun May 1 12:12:44 1994 +++ linux/drivers/sound/sound_switch.c Mon Jul 18 09:50:55 1994 @@ -40,10 +40,12 @@ { {0}}; -static int in_use = 0; /* Total # of open device files (excluding +static int in_use = 0; /* - * minor 0) */ + * * * * Total # of open device files + * (excluding * * * minor 0) */ + /* * /dev/sndstatus -device */ @@ -56,7 +58,9 @@ { int l; - for (l = 0; l < 256, s[l]; l++); /* l=strlen(s); */ + for (l = 0; l < 256, s[l]; l++); /* + * l=strlen(s); + */ if (status_len + l >= 4000) return 0; @@ -121,37 +125,58 @@ if (!put_status_int (SELECTED_SOUND_OPTIONS, 16)) return; - if (!put_status ("\n\nHW config: \n")) + if (!put_status ("\n\nInstalled drivers: \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)) + if (!put_status_int (sound_drivers[i].card_type, 10)) return; if (!put_status (": ")) return; - if (!put_status (supported_drivers[i].name)) + if (!put_status (sound_drivers[i].name)) + return; + + if (!put_status ("\n")) return; + } + + if (!put_status ("\n\nCard config: \n")) + return; + + for (i = 0; i < (num_sound_cards - 1); i++) + { + int drv; + + if (!snd_installed_cards[i].enabled) + if (!put_status ("(")) + return; + + /* + * if (!put_status_int(snd_installed_cards[i].card_type, 10)) return; + * if (!put_status (": ")) return; + */ + + if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) != -1) + if (!put_status (sound_drivers[drv].name)) + return; + if (!put_status (" at 0x")) return; - if (!put_status_int (supported_drivers[i].config.io_base, 16)) + if (!put_status_int (snd_installed_cards[i].config.io_base, 16)) return; if (!put_status (" irq ")) return; - if (!put_status_int (supported_drivers[i].config.irq, 10)) + if (!put_status_int (snd_installed_cards[i].config.irq, 10)) return; if (!put_status (" drq ")) return; - if (!put_status_int (supported_drivers[i].config.dma, 10)) + if (!put_status_int (snd_installed_cards[i].config.dma, 10)) return; - if (!supported_drivers[i].enabled) + if (!snd_installed_cards[i].enabled) if (!put_status (")")) return; @@ -162,13 +187,13 @@ if (!put_status ("\nPCM devices:\n")) return; - for (i = 0; i < num_dspdevs; i++) + for (i = 0; i < num_audiodevs; i++) { if (!put_status_int (i, 10)) return; if (!put_status (": ")) return; - if (!put_status (dsp_devs[i]->name)) + if (!put_status (audio_devs[i]->name)) return; if (!put_status ("\n")) return; @@ -204,16 +229,27 @@ return; } - if (num_mixers) + if (!put_status ("\nMIDI Timers:\n")) + return; + + for (i = 0; i < num_sound_timers; i++) { - if (!put_status ("\nMixer(s) installed\n")) + if (!put_status_int (i, 10)) return; - } - else - { - if (!put_status ("\nNo mixers installed\n")) + if (!put_status (": ")) + return; + if (!put_status (sound_timer_devs[i]->info.name)) return; + if (!put_status ("\n")) + return; } + + if (!put_status ("\n")) + return; + if (!put_status_int (num_mixers, 10)) + return; + if (!put_status (" mixer(s) installed\n")) + return; } static int @@ -256,14 +292,20 @@ break; case SND_DEV_SEQ: + case SND_DEV_SEQ2: return sequencer_read (dev, file, buf, count); break; -#ifndef EXCLUDE_MPU401 +#ifndef EXCLUDE_MIDI case SND_DEV_MIDIN: return MIDIbuf_read (dev, file, buf, count); #endif +#ifndef EXCLUDE_PSS + case SND_DEV_PSS: + return pss_read (dev, file, buf, count); +#endif + default: printk ("Sound: Undefined minor device %d\n", dev); } @@ -281,6 +323,7 @@ { case SND_DEV_SEQ: + case SND_DEV_SEQ2: return sequencer_write (dev, file, buf, count); break; @@ -290,6 +333,16 @@ return audio_write (dev, file, buf, count); break; +#ifndef EXCLUDE_MIDI + case SND_DEV_MIDIN: + return MIDIbuf_write (dev, file, buf, count); +#endif + +#ifndef EXCLUDE_PSS + case SND_DEV_PSS: + return pss_write (dev, file, buf, count); +#endif + default: return RET_ERROR (EPERM); } @@ -327,17 +380,25 @@ break; case SND_DEV_SEQ: + case SND_DEV_SEQ2: if ((retval = sequencer_open (dev, file)) < 0) return retval; break; -#ifndef EXCLUDE_MPU401 +#ifndef EXCLUDE_MIDI case SND_DEV_MIDIN: if ((retval = MIDIbuf_open (dev, file)) < 0) return retval; break; #endif +#ifndef EXCLUDE_PSS + case SND_DEV_PSS: + if ((retval = pss_open (dev, file)) < 0) + return retval; + break; +#endif + case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: @@ -375,15 +436,22 @@ break; case SND_DEV_SEQ: + case SND_DEV_SEQ2: sequencer_release (dev, file); break; -#ifndef EXCLUDE_MPU401 +#ifndef EXCLUDE_MIDI case SND_DEV_MIDIN: MIDIbuf_release (dev, file); break; #endif +#ifndef EXCLUDE_PSS + case SND_DEV_PSS: + pss_release (dev, file); + break; +#endif + case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: @@ -404,6 +472,12 @@ { DEB (printk ("sound_ioctl_sw(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg)); + if ((dev & 0x0f) != SND_DEV_CTL && num_mixers > 0) + if ((cmd >> 8) & 0xff == 'M') /* + * Mixer ioctl + */ + return mixer_devs[0]->ioctl (0, cmd, arg); + switch (dev & 0x0f) { @@ -412,13 +486,16 @@ if (!num_mixers) return RET_ERROR (ENXIO); - if ((dev >> 4) >= num_mixers) + dev = dev >> 4; + + if (dev >= num_mixers) return RET_ERROR (ENXIO); - return mixer_devs[dev >> 4]->ioctl (dev >> 4, cmd, arg); + return mixer_devs[dev]->ioctl (dev, cmd, arg); break; case SND_DEV_SEQ: + case SND_DEV_SEQ2: return sequencer_ioctl (dev, file, cmd, arg); break; @@ -428,9 +505,15 @@ return audio_ioctl (dev, file, cmd, arg); break; -#ifndef EXCLUDE_MPU401 +#ifndef EXCLUDE_MIDI case SND_DEV_MIDIN: return MIDIbuf_ioctl (dev, file, cmd, arg); + break; +#endif + +#ifndef EXCLUDE_PSS + case SND_DEV_PSS: + return pss_ioctl (dev, file, cmd, arg); break; #endif diff -u --recursive --new-file v1.1.30/linux/drivers/sound/sound_timer.c linux/drivers/sound/sound_timer.c --- v1.1.30/linux/drivers/sound/sound_timer.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/sound_timer.c Mon Jul 18 09:50:55 1994 @@ -0,0 +1,406 @@ +/* + * sound/sound_timer.c + * + * Timer for the level 2 interface of the /dev/sequencer. Uses the + * 80 and 320 usec timers of OPL-3 (PAS16 only) and GUS. + * + * 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 SEQUENCER_C +#include "sound_config.h" + +#ifdef CONFIGURE_SOUNDCARD + +#if !defined(EXCLUDE_SEQUENCER) && (!defined(EXCLUDE_GUS) || (!defined(EXCLUDE_PAS) && !defined(EXCLUDE_YM3812))) + +static volatile int initialized = 0, opened = 0, tmr_running = 0; +static volatile time_t tmr_offs, tmr_ctr; +static volatile unsigned long ticks_offs; +static volatile int curr_tempo, curr_timebase; +static volatile unsigned long curr_ticks; +static volatile unsigned long next_event_time; +static unsigned long prev_event_time; +static volatile int select_addr, data_addr; +static volatile int curr_timer = 0; +static volatile unsigned long usecs_per_tmr; /* Length of the current interval */ + + +static void +timer_command (unsigned int addr, unsigned int val) +{ + int i; + + OUTB ((unsigned char) (addr & 0xff), select_addr); + + for (i = 0; i < 2; i++) + INB (select_addr); + + OUTB ((unsigned char) (val & 0xff), data_addr); + + for (i = 0; i < 2; i++) + INB (select_addr); +} + +static void +arm_timer (int timer, unsigned int interval) +{ + + curr_timer = timer; + + if (timer == 1) + { + gus_write8 (0x46, 256 - interval); /* Set counter for timer 1 */ + gus_write8 (0x45, 0x04); /* Enable timer 1 IRQ */ + timer_command (0x04, 0x01); /* Start timer 1 */ + } + else + { + gus_write8 (0x47, 256 - interval); /* Set counter for timer 2 */ + gus_write8 (0x45, 0x08); /* Enable timer 2 IRQ */ + timer_command (0x04, 0x02); /* Start timer 2 */ + } +} + +static unsigned long +tmr2ticks (int tmr_value) +{ + /* + * Convert timer ticks to MIDI ticks + */ + + unsigned long tmp; + unsigned long scale; + + tmp = tmr_value * usecs_per_tmr; /* Convert to usecs */ + + scale = (60 * 1000000) / (curr_tempo * curr_timebase); /* usecs per MIDI tick */ + + return (tmp + (scale / 2)) / scale; +} + +static void +reprogram_timer (void) +{ + unsigned long usecs_per_tick; + int timer_no, resolution; + int divisor; + + usecs_per_tick = (60 * 1000000) / (curr_tempo * curr_timebase); + + /* + * Don't kill the system by setting too high timer rate + */ + if (usecs_per_tick < 2000) + usecs_per_tick = 2000; + + if (usecs_per_tick > (256 * 80)) + { + timer_no = 2; + resolution = 320; /* usec */ + } + else + { + timer_no = 1; + resolution = 80; /* usec */ + } + + divisor = (usecs_per_tick + (resolution / 2)) / resolution; + usecs_per_tmr = divisor * resolution; + + arm_timer (timer_no, divisor); +} + +static void +tmr_reset (void) +{ + unsigned long flags; + + DISABLE_INTR (flags); + tmr_offs = 0; + ticks_offs = 0; + tmr_ctr = 0; + next_event_time = 0xffffffff; + prev_event_time = 0; + curr_ticks = 0; + RESTORE_INTR (flags); +} + +static int +timer_open (int dev, int mode) +{ + if (opened) + return RET_ERROR (EBUSY); + + tmr_reset (); + curr_tempo = 60; + curr_timebase = HZ; + opened = 1; + reprogram_timer (); + + return 0; +} + +static void +timer_close (int dev) +{ + opened = tmr_running = 0; + gus_write8 (0x45, 0); /* Disable both timers */ +} + +static int +timer_event (int dev, unsigned char *event) +{ + unsigned char cmd = event[1]; + unsigned long parm = *(int *) &event[4]; + + switch (cmd) + { + case TMR_WAIT_REL: + parm += prev_event_time; + case TMR_WAIT_ABS: + if (parm > 0) + { + long time; + + if (parm <= curr_ticks) /* It's the time */ + return TIMER_NOT_ARMED; + + time = parm; + next_event_time = prev_event_time = time; + + return TIMER_ARMED; + } + break; + + case TMR_START: + tmr_reset (); + tmr_running = 1; + reprogram_timer (); + break; + + case TMR_STOP: + tmr_running = 0; + break; + + case TMR_CONTINUE: + tmr_running = 1; + reprogram_timer (); + break; + + case TMR_TEMPO: + if (parm) + { + if (parm < 8) + parm = 8; + if (parm > 250) + parm = 250; + tmr_offs = tmr_ctr; + ticks_offs += tmr2ticks (tmr_ctr); + tmr_ctr = 0; + curr_tempo = parm; + reprogram_timer (); + } + break; + + case TMR_ECHO: + seq_copy_to_input (event, 8); + break; + + default:; + } + + return TIMER_NOT_ARMED; +} + +static unsigned long +timer_get_time (int dev) +{ + if (!opened) + return 0; + + return curr_ticks; +} + +static int +timer_ioctl (int dev, + unsigned int cmd, unsigned int arg) +{ + switch (cmd) + { + case SNDCTL_TMR_SOURCE: + return IOCTL_OUT (arg, TMR_INTERNAL); + break; + + case SNDCTL_TMR_START: + tmr_reset (); + tmr_running = 1; + return 0; + break; + + case SNDCTL_TMR_STOP: + tmr_running = 0; + return 0; + break; + + case SNDCTL_TMR_CONTINUE: + tmr_running = 1; + return 0; + break; + + case SNDCTL_TMR_TIMEBASE: + { + int val = IOCTL_IN (arg); + + if (val) + { + if (val < 1) + val = 1; + if (val > 1000) + val = 1000; + curr_timebase = val; + } + + return IOCTL_OUT (arg, curr_timebase); + } + break; + + case SNDCTL_TMR_TEMPO: + { + int val = IOCTL_IN (arg); + + if (val) + { + if (val < 8) + val = 8; + if (val > 250) + val = 250; + tmr_offs = tmr_ctr; + ticks_offs += tmr2ticks (tmr_ctr); + tmr_ctr = 0; + curr_tempo = val; + reprogram_timer (); + } + + return IOCTL_OUT (arg, curr_tempo); + } + break; + + case SNDCTL_SEQ_CTRLRATE: + if (IOCTL_IN (arg) != 0) /* Can't change */ + return RET_ERROR (EINVAL); + + return IOCTL_OUT (arg, ((curr_tempo * curr_timebase) + 30) / 60); + break; + + case SNDCTL_TMR_METRONOME: + /* NOP */ + break; + + default: + } + + return RET_ERROR (EINVAL); +} + +static void +timer_arm (int dev, long time) +{ + if (time < 0) + time = curr_ticks + 1; + else if (time <= curr_ticks) /* It's the time */ + return; + + next_event_time = prev_event_time = time; + + return; +} + +static struct sound_timer_operations sound_timer = +{ + {"OPL-3/GUS Timer", 0}, + 1, /* Priority */ + 0, /* Local device link */ + timer_open, + timer_close, + timer_event, + timer_get_time, + timer_ioctl, + timer_arm +}; + +void +sound_timer_interrupt (void) +{ + gus_write8 (0x45, 0); /* Ack IRQ */ + timer_command (4, 0x80); /* Reset IRQ flags */ + + if (!opened) + return; + + if (curr_timer == 1) + gus_write8 (0x45, 0x04); /* Start timer 1 again */ + else + gus_write8 (0x45, 0x08); /* Start timer 2 again */ + + if (!tmr_running) + return; + + tmr_ctr++; + curr_ticks = ticks_offs + tmr2ticks (tmr_ctr); + + if (curr_ticks >= next_event_time) + { + next_event_time = 0xffffffff; + sequencer_timer (); + } +} + +void +sound_timer_init (int io_base) +{ + int n; + + if (initialized) + return; /* There is already a similar timer */ + + select_addr = io_base; + data_addr = io_base + 1; + + initialized = 1; + +#if 1 + if (num_sound_timers >= MAX_TIMER_DEV) + n = 0; /* Overwrite the system timer */ + else + n = num_sound_timers++; +#else + n = 0; +#endif + + sound_timer_devs[n] = &sound_timer; +} + +#endif +#endif diff -u --recursive --new-file v1.1.30/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c --- v1.1.30/linux/drivers/sound/soundcard.c Sun May 1 12:12:45 1994 +++ linux/drivers/sound/soundcard.c Mon Jul 18 09:50:55 1994 @@ -1,4 +1,3 @@ - /* * linux/kernel/chr_drv/sound/soundcard.c * @@ -34,8 +33,6 @@ #include -extern long seq_time; - static int soundcards_installed = 0; /* Number of installed * soundcards */ @@ -43,10 +40,6 @@ static struct fileinfo files[SND_NDEVS]; -extern char *snd_raw_buf[MAX_DSP_DEV][DSP_BUFFCOUNT]; -extern unsigned long snd_raw_buf_phys[MAX_DSP_DEV][DSP_BUFFCOUNT]; -extern int snd_raw_count[MAX_DSP_DEV]; - int snd_ioctl_return (int *addr, int value) { @@ -146,9 +139,17 @@ switch (dev & 0x0f) { +#ifndef EXCLUDE_SEQUENCER case SND_DEV_SEQ: return sequencer_select (dev, &files[dev], sel_type, wait); break; +#endif + +#ifndef EXCLUDE_MIDI + case SND_DEV_MIDIN: + return MIDIbuf_select (dev, &files[dev], sel_type, wait); + break; +#endif default: return 0; @@ -183,19 +184,23 @@ if (!(soundcards_installed = sndtable_get_cardcount ())) return mem_start; /* No cards detected */ - if (num_dspdevs) /* Audio devices present */ +#ifndef EXCLUDE_AUDIO + if (num_audiodevs) /* Audio devices present */ { mem_start = DMAbuf_init (mem_start); mem_start = audio_init (mem_start); } +#endif -#ifndef EXCLUDE_MPU401 +#ifndef EXCLUDE_MIDI if (num_midis) mem_start = MIDIbuf_init (mem_start); #endif +#ifndef EXCLUDE_SEQUENCER if (num_midis + num_synths) mem_start = sequencer_init (mem_start); +#endif return mem_start; } @@ -243,10 +248,13 @@ free_irq (vect); } +#ifndef EXCLUDE_SEQUENCER void request_sound_timer (int count) { -#ifndef EXCLUDE_SEQUENCER + extern unsigned long seq_time; + +#if 1 if (count < 0) count = jiffies + (-count); else @@ -257,10 +265,12 @@ #endif } +#endif + void sound_stop_timer (void) { -#ifndef EXCLUDE_SEQUENCER +#if 1 timer_table[SOUND_TIMER].expires = 0; timer_active &= ~(1 << SOUND_TIMER); #endif @@ -281,6 +291,7 @@ { int i, dev; unsigned long start_addr, end_addr, mem_ptr, dma_pagesize; + struct dma_buffparms *dmap; mem_ptr = high_memory; @@ -289,38 +300,40 @@ if (mem_ptr > (16 * 1024 * 1024)) mem_ptr = 16 * 1024 * 1024; /* Limit to 16M */ - for (dev = 0; dev < num_dspdevs; dev++) /* Enumerate devices */ - if (sound_buffcounts[dev] > 0 && sound_dsp_dmachan[dev] > 0) + for (dev = 0; dev < num_audiodevs; dev++) /* Enumerate devices */ + if (audio_devs[dev]->buffcount > 0 && audio_devs[dev]->dmachan >= 0) { - if (sound_dma_automode[dev]) - sound_buffcounts[dev] = 1; + dmap = audio_devs[dev]->dmap; + + if (audio_devs[dev]->flags & DMA_AUTOMODE) + audio_devs[dev]->buffcount = 1; - if (sound_dsp_dmachan[dev] > 3 && sound_buffsizes[dev] > 65536) + if (audio_devs[dev]->dmachan > 3 && audio_devs[dev]->buffsize > 65536) dma_pagesize = 131072;/* 128k */ else dma_pagesize = 65536; /* More sanity checks */ - if (sound_buffsizes[dev] > dma_pagesize) - sound_buffsizes[dev] = dma_pagesize; - sound_buffsizes[dev] &= 0xfffff000; /* Truncate to n*4k */ - if (sound_buffsizes[dev] < 4096) - sound_buffsizes[dev] = 4096; + if (audio_devs[dev]->buffsize > dma_pagesize) + audio_devs[dev]->buffsize = dma_pagesize; + audio_devs[dev]->buffsize &= 0xfffff000; /* Truncate to n*4k */ + if (audio_devs[dev]->buffsize < 4096) + audio_devs[dev]->buffsize = 4096; /* Now allocate the buffers */ - for (snd_raw_count[dev] = 0; snd_raw_count[dev] < sound_buffcounts[dev]; snd_raw_count[dev]++) + for (dmap->raw_count = 0; dmap->raw_count < audio_devs[dev]->buffcount; dmap->raw_count++) { - start_addr = mem_ptr - sound_buffsizes[dev]; - if (!valid_dma_page (start_addr, sound_buffsizes[dev], dma_pagesize)) + start_addr = mem_ptr - audio_devs[dev]->buffsize; + if (!valid_dma_page (start_addr, audio_devs[dev]->buffsize, dma_pagesize)) start_addr &= ~(dma_pagesize - 1); /* Align address to * dma_pagesize */ - end_addr = start_addr + sound_buffsizes[dev] - 1; + end_addr = start_addr + audio_devs[dev]->buffsize - 1; - snd_raw_buf[dev][snd_raw_count[dev]] = (char *) start_addr; - snd_raw_buf_phys[dev][snd_raw_count[dev]] = start_addr; + dmap->raw_buf[dmap->raw_count] = (char *) start_addr; + dmap->raw_buf_phys[dmap->raw_count] = start_addr; mem_ptr = start_addr; for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++) diff -u --recursive --new-file v1.1.30/linux/drivers/sound/sys_timer.c linux/drivers/sound/sys_timer.c --- v1.1.30/linux/drivers/sound/sys_timer.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/sys_timer.c Mon Jul 18 09:50:55 1994 @@ -0,0 +1,304 @@ +/* + * sound/sys_timer.c + * + * The default timer for the Level 2 sequencer interface + * Uses the (100HZ) timer of kernel. + * + * 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 SEQUENCER_C +#include "sound_config.h" + +#ifdef CONFIGURE_SOUNDCARD + +#ifndef EXCLUDE_SEQUENCER + +static volatile int opened = 0, tmr_running = 0; +static volatile time_t tmr_offs, tmr_ctr; +static volatile unsigned long ticks_offs; +static volatile int curr_tempo, curr_timebase; +static volatile unsigned long curr_ticks; +static volatile unsigned long next_event_time; +static unsigned long prev_event_time; + +static void poll_def_tmr (unsigned long dummy); + +DEFINE_TIMER (def_tmr, poll_def_tmr); + +static unsigned long +tmr2ticks (int tmr_value) +{ + /* + * Convert system timer ticks (HZ) to MIDI ticks + */ + + unsigned long tmp; + unsigned long scale; + + tmp = (tmr_value * 1000) / HZ;/* Convert to msecs */ + + scale = (60 * 1000) / (curr_tempo * curr_timebase); /* msecs per MIDI tick */ + + return (tmp + (scale / 2)) / scale; +} + +static void +poll_def_tmr (unsigned long dummy) +{ + + if (opened) + { + ACTIVATE_TIMER (def_tmr, poll_def_tmr, 1); + + if (tmr_running) + { + tmr_ctr++; + curr_ticks = ticks_offs + tmr2ticks (tmr_ctr); + + if (curr_ticks >= next_event_time) + { + next_event_time = 0xffffffff; + sequencer_timer (); + } + } + } +} + +static void +tmr_reset (void) +{ + unsigned long flags; + + DISABLE_INTR (flags); + tmr_offs = 0; + ticks_offs = 0; + tmr_ctr = 0; + next_event_time = 0xffffffff; + prev_event_time = 0; + curr_ticks = 0; + RESTORE_INTR (flags); +} + +static int +def_tmr_open (int dev, int mode) +{ + if (opened) + return RET_ERROR (EBUSY); + + tmr_reset (); + curr_tempo = 60; + curr_timebase = HZ; + opened = 1; + + ACTIVATE_TIMER (def_tmr, poll_def_tmr, 1); + + return 0; +} + +static void +def_tmr_close (int dev) +{ + opened = tmr_running = 0; +} + +static int +def_tmr_event (int dev, unsigned char *event) +{ + unsigned char cmd = event[1]; + unsigned long parm = *(int *) &event[4]; + + switch (cmd) + { + case TMR_WAIT_REL: + parm += prev_event_time; + case TMR_WAIT_ABS: + if (parm > 0) + { + long time; + + if (parm <= curr_ticks) /* It's the time */ + return TIMER_NOT_ARMED; + + time = parm; + next_event_time = prev_event_time = time; + + return TIMER_ARMED; + } + break; + + case TMR_START: + tmr_reset (); + tmr_running = 1; + break; + + case TMR_STOP: + tmr_running = 0; + break; + + case TMR_CONTINUE: + tmr_running = 1; + break; + + case TMR_TEMPO: + if (parm) + { + if (parm < 8) + parm = 8; + if (parm > 250) + parm = 250; + tmr_offs = tmr_ctr; + ticks_offs += tmr2ticks (tmr_ctr); + tmr_ctr = 0; + curr_tempo = parm; + } + break; + + case TMR_ECHO: + seq_copy_to_input (event, 8); + break; + + default:; + } + + return TIMER_NOT_ARMED; +} + +static unsigned long +def_tmr_get_time (int dev) +{ + if (!opened) + return 0; + + return curr_ticks; +} + +static int +def_tmr_ioctl (int dev, + unsigned int cmd, unsigned int arg) +{ + switch (cmd) + { + case SNDCTL_TMR_SOURCE: + return IOCTL_OUT (arg, TMR_INTERNAL); + break; + + case SNDCTL_TMR_START: + tmr_reset (); + tmr_running = 1; + return 0; + break; + + case SNDCTL_TMR_STOP: + tmr_running = 0; + return 0; + break; + + case SNDCTL_TMR_CONTINUE: + tmr_running = 1; + return 0; + break; + + case SNDCTL_TMR_TIMEBASE: + { + int val = IOCTL_IN (arg); + + if (val) + { + if (val < 1) + val = 1; + if (val > 1000) + val = 1000; + curr_timebase = val; + } + + return IOCTL_OUT (arg, curr_timebase); + } + break; + + case SNDCTL_TMR_TEMPO: + { + int val = IOCTL_IN (arg); + + if (val) + { + if (val < 8) + val = 8; + if (val > 250) + val = 250; + tmr_offs = tmr_ctr; + ticks_offs += tmr2ticks (tmr_ctr); + tmr_ctr = 0; + curr_tempo = val; + } + + return IOCTL_OUT (arg, curr_tempo); + } + break; + + case SNDCTL_SEQ_CTRLRATE: + if (IOCTL_IN (arg) != 0) /* Can't change */ + return RET_ERROR (EINVAL); + + return IOCTL_OUT (arg, ((curr_tempo * curr_timebase) + 30) / 60); + break; + + case SNDCTL_TMR_METRONOME: + /* NOP */ + break; + + default:; + } + + return RET_ERROR (EINVAL); +} + +static void +def_tmr_arm (int dev, long time) +{ + if (time < 0) + time = curr_ticks + 1; + else if (time <= curr_ticks) /* It's the time */ + return; + + next_event_time = prev_event_time = time; + + return; +} + +struct sound_timer_operations default_sound_timer = +{ + {"System Timer", 0}, + 0, /* Priority */ + 0, /* Local device link */ + def_tmr_open, + def_tmr_close, + def_tmr_event, + def_tmr_get_time, + def_tmr_ioctl, + def_tmr_arm +}; + +#endif +#endif diff -u --recursive --new-file v1.1.30/linux/drivers/sound/uart6850.c linux/drivers/sound/uart6850.c --- v1.1.30/linux/drivers/sound/uart6850.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/sound/uart6850.c Mon Jul 18 09:50:55 1994 @@ -0,0 +1,323 @@ +/* + * sound/uart6850.c + * + * Copyright by Hannu Savolainen 1993 + * + * Mon Nov 22 22:38:35 MET 1993 marco@driq.home.usn.nl: + * added 6850 support, used with COVOX SoundMaster II and custom cards. + * + * 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_UART6850) && !defined(EXCLUDE_MIDI) + +#define DATAPORT (uart6850_base) /* + * * * Midi6850 Data I/O Port on IBM + * */ +#define COMDPORT (uart6850_base+1) /* + * * * Midi6850 Command Port on IBM */ +#define STATPORT (uart6850_base+1) /* + * * * Midi6850 Status Port on IBM */ + +#define uart6850_status() INB(STATPORT) +#define input_avail() ((uart6850_status()&INPUT_AVAIL)) +#define output_ready() ((uart6850_status()&OUTPUT_READY)) +#define uart6850_cmd(cmd) OUTB(cmd, COMDPORT) +#define uart6850_read() INB(DATAPORT) +#define uart6850_write(byte) OUTB(byte, DATAPORT) + +#define OUTPUT_READY 0x02 /* + * * * Mask for Data Read Ready Bit */ +#define INPUT_AVAIL 0x01 /* + * * * Mask for Data Send Ready Bit */ + +#define UART_RESET 0x95 /* + * * * 6850 Total Reset Command */ +#define UART_MODE_ON 0x03 /* + * * * 6850 Send/Receive UART Mode */ + +static int uart6850_opened = 0; +static int uart6850_base = 0x330; +static int uart6850_irq; +static int uart6850_detected = 0; +static int my_dev; + +static int reset_uart6850 (void); +static void (*midi_input_intr) (int dev, unsigned char data); + +static void +uart6850_input_loop (void) +{ + int count; + + count = 10; + + while (count) /* + * Not timed out + */ + if (input_avail ()) + { + unsigned char c = uart6850_read (); + + count = 100; + + if (uart6850_opened & OPEN_READ) + midi_input_intr (my_dev, c); + } + else + while (!input_avail () && count) + count--; +} + +void +m6850intr (int unit) +{ + printk ("M"); + if (input_avail ()) + uart6850_input_loop (); +} + +/* + * It looks like there is no input interrupts in the UART mode. Let's try + * polling. + */ + +static void +poll_uart6850 (unsigned long dummy) +{ + unsigned long flags; + + DEFINE_TIMER (uart6850_timer, poll_uart6850); + + if (!(uart6850_opened & OPEN_READ)) + return; /* + * No longer required + */ + + DISABLE_INTR (flags); + + if (input_avail ()) + uart6850_input_loop (); + + ACTIVATE_TIMER (uart6850_timer, poll_uart6850, 1); /* + * Come back later + */ + + RESTORE_INTR (flags); +} + +static int +uart6850_open (int dev, int mode, + void (*input) (int dev, unsigned char data), + void (*output) (int dev) +) +{ + if (uart6850_opened) + { + printk ("Midi6850: Midi busy\n"); + return RET_ERROR (EBUSY); + } + + uart6850_cmd (UART_RESET); + + uart6850_input_loop (); + + midi_input_intr = input; + uart6850_opened = mode; + poll_uart6850 (0); /* + * Enable input polling + */ + + return 0; +} + +static void +uart6850_close (int dev) +{ + uart6850_cmd (UART_MODE_ON); + + uart6850_opened = 0; +} + +static int +uart6850_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 ()) + uart6850_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 ("Midi6850: Timeout\n"); + return 0; + } + + uart6850_write (midi_byte); + return 1; +} + +static int +uart6850_command (int dev, unsigned char *midi_byte) +{ + return 1; +} + +static int +uart6850_start_read (int dev) +{ + return 0; +} + +static int +uart6850_end_read (int dev) +{ + return 0; +} + +static int +uart6850_ioctl (int dev, unsigned cmd, unsigned arg) +{ + return RET_ERROR (EINVAL); +} + +static void +uart6850_kick (int dev) +{ +} + +static int +uart6850_buffer_status (int dev) +{ + return 0; /* + * No data in buffers + */ +} + +#define MIDI_SYNTH_NAME "6850 UART Midi" +#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT +#include "midi_synth.h" + +static struct midi_operations uart6850_operations = +{ + {"6850 UART", 0, 0, SNDCARD_UART6850}, + &std_midi_synth, + uart6850_open, + uart6850_close, + uart6850_ioctl, + uart6850_out, + uart6850_start_read, + uart6850_end_read, + uart6850_kick, + uart6850_command, + uart6850_buffer_status +}; + + +long +attach_uart6850 (long mem_start, struct address_info *hw_config) +{ + int ok, timeout; + unsigned long flags; + + if (num_midis >= MAX_MIDI_DEV) + { + printk ("Sound: Too many midi devices detected\n"); + return mem_start; + } + + uart6850_base = hw_config->io_base; + uart6850_irq = hw_config->irq; + + if (!uart6850_detected) + return RET_ERROR (EIO); + + DISABLE_INTR (flags); + + for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /* + * Wait + */ + uart6850_cmd (UART_MODE_ON); + + ok = 1; + + RESTORE_INTR (flags); + + printk (" <6850 Midi Interface>"); + + std_midi_synth.midi_dev = my_dev = num_midis; + midi_devs[num_midis++] = &uart6850_operations; + return mem_start; +} + +static int +reset_uart6850 (void) +{ + uart6850_read (); + return 1; /* + * OK + */ +} + + +int +probe_uart6850 (struct address_info *hw_config) +{ + int ok = 0; + + uart6850_base = hw_config->io_base; + uart6850_irq = hw_config->irq; + + if (snd_set_irq_handler (uart6850_irq, m6850intr) < 0) + return 0; + + ok = reset_uart6850 (); + + uart6850_detected = ok; + return ok; +} + +#endif + +#endif diff -u --recursive --new-file v1.1.30/linux/fs/buffer.c linux/fs/buffer.c --- v1.1.30/linux/fs/buffer.c Fri Jul 8 13:26:40 1994 +++ linux/fs/buffer.c Mon Jul 18 13:08:22 1994 @@ -1113,13 +1113,13 @@ * etc. This also allows us to optimize memory usage by sharing code pages * and filesystem buffers.. */ -unsigned long bread_page(unsigned long address, dev_t dev, int b[], int size, int prot) +unsigned long bread_page(unsigned long address, dev_t dev, int b[], int size, int share) { struct buffer_head * bh[8]; unsigned long where; int i, j; - if (!(prot & PAGE_RW)) { + if (share) { where = try_to_share_buffers(address,dev,b,size); if (where) return where; diff -u --recursive --new-file v1.1.30/linux/fs/ext/namei.c linux/fs/ext/namei.c --- v1.1.30/linux/fs/ext/namei.c Fri May 27 10:49:12 1994 +++ linux/fs/ext/namei.c Mon Jul 18 11:29:02 1994 @@ -55,7 +55,7 @@ */ static int ext_match(int len,const char * name,struct ext_dir_entry * de) { - register int same __asm__("ax"); + register int same; if (!de || !de->inode || len > EXT_NAME_LEN) return 0; @@ -64,7 +64,8 @@ return 1; if (len < EXT_NAME_LEN && len != de->name_len) return 0; - __asm__("cld\n\t" + __asm__ __volatile__( + "cld\n\t" "repe ; cmpsb\n\t" "setz %%al" :"=a" (same) diff -u --recursive --new-file v1.1.30/linux/fs/ext2/namei.c linux/fs/ext2/namei.c --- v1.1.30/linux/fs/ext2/namei.c Fri May 27 10:49:13 1994 +++ linux/fs/ext2/namei.c Mon Jul 18 09:15:15 1994 @@ -390,6 +390,7 @@ return err; } de->inode = inode->i_ino; + dir->i_version++; #ifndef DONT_USE_DCACHE ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len, de->inode); @@ -456,6 +457,7 @@ return err; } de->inode = inode->i_ino; + dir->i_version++; #ifndef DONT_USE_DCACHE ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len, de->inode); @@ -532,6 +534,7 @@ return err; } de->inode = inode->i_ino; + dir->i_version++; #ifndef DONT_USE_DCACHE ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len, de->inode); @@ -657,6 +660,7 @@ inode->i_size = 0; } retval = ext2_delete_entry (de, bh); + dir->i_version++; } up(&inode->i_sem); if (retval) @@ -729,6 +733,7 @@ retval = ext2_delete_entry (de, bh); if (retval) goto end_unlink; + dir->i_version++; mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { ll_rw_block (WRITE, 1, &bh); @@ -817,6 +822,7 @@ return err; } de->inode = inode->i_ino; + dir->i_version++; #ifndef DONT_USE_DCACHE ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len, de->inode); @@ -863,6 +869,7 @@ return err; } de->inode = oldinode->i_ino; + dir->i_version++; #ifndef DONT_USE_DCACHE ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len, de->inode); @@ -1036,6 +1043,8 @@ goto try_again; if (retval) goto end_rename; + new_dir->i_version++; + old_dir->i_version++; if (new_inode) { new_inode->i_nlink--; new_inode->i_ctime = CURRENT_TIME; @@ -1043,16 +1052,6 @@ } old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; old_dir->i_dirt = 1; - mark_buffer_dirty(old_bh, 1); - if (IS_SYNC(old_dir)) { - ll_rw_block (WRITE, 1, &old_bh); - wait_on_buffer (old_bh); - } - mark_buffer_dirty(new_bh, 1); - if (IS_SYNC(new_dir)) { - ll_rw_block (WRITE, 1, &new_bh); - wait_on_buffer (new_bh); - } if (dir_bh) { PARENT_INO(dir_bh->b_data) = new_dir->i_ino; mark_buffer_dirty(dir_bh, 1); @@ -1065,6 +1064,16 @@ new_dir->i_nlink++; new_dir->i_dirt = 1; } + } + mark_buffer_dirty(old_bh, 1); + if (IS_SYNC(old_dir)) { + ll_rw_block (WRITE, 1, &old_bh); + wait_on_buffer (old_bh); + } + mark_buffer_dirty(new_bh, 1); + if (IS_SYNC(new_dir)) { + ll_rw_block (WRITE, 1, &new_bh); + wait_on_buffer (new_bh); } retval = 0; end_rename: diff -u --recursive --new-file v1.1.30/linux/fs/isofs/namei.c linux/fs/isofs/namei.c --- v1.1.30/linux/fs/isofs/namei.c Sun Dec 12 12:26:43 1993 +++ linux/fs/isofs/namei.c Mon Jul 18 11:24:50 1994 @@ -26,7 +26,7 @@ */ static int isofs_match(int len,const char * name, char * compare, int dlen) { - register int same __asm__("ax"); + register int same; if (!compare) return 0; /* "" means "." ---> so paths like "/usr/lib//libc.a" work */ @@ -45,7 +45,8 @@ if (dlen != len) return 0; - __asm__("cld\n\t" + __asm__ __volatile__( + "cld\n\t" "repe ; cmpsb\n\t" "setz %%al" :"=a" (same) diff -u --recursive --new-file v1.1.30/linux/fs/nfs/mmap.c linux/fs/nfs/mmap.c --- v1.1.30/linux/fs/nfs/mmap.c Tue Jun 21 14:16:23 1994 +++ linux/fs/nfs/mmap.c Mon Jul 18 13:00:26 1994 @@ -23,16 +23,9 @@ #include #include -extern int share_page(struct vm_area_struct * area, struct task_struct * tsk, - struct inode * inode, unsigned long address, unsigned long error_code, - unsigned long newpage); +static unsigned long nfs_file_mmap_nopage(struct vm_area_struct * area, + unsigned long address, unsigned long page, int error_code); -extern unsigned long put_page(struct task_struct * tsk,unsigned long page, - unsigned long address,int prot); - -static void nfs_file_mmap_nopage(int error_code, struct vm_area_struct * area, - unsigned long address); - extern void file_mmap_free(struct vm_area_struct * area); extern int file_mmap_share(struct vm_area_struct * from, struct vm_area_struct * to, unsigned long address); @@ -85,12 +78,11 @@ } -static void nfs_file_mmap_nopage(int error_code, struct vm_area_struct * area, - unsigned long address) +static unsigned long nfs_file_mmap_nopage(struct vm_area_struct * area, unsigned long address, + unsigned long page, int error_code) { struct inode * inode = area->vm_inode; unsigned int clear; - unsigned long page; unsigned long tmp; int n; int i; @@ -100,19 +92,6 @@ address &= PAGE_MASK; pos = address - area->vm_start + area->vm_offset; - page = get_free_page(GFP_KERNEL); - if (share_page(area, area->vm_task, inode, address, error_code, page)) { - ++area->vm_task->mm->min_flt; - return; - } - - ++area->vm_task->mm->maj_flt; - if (!page) { - oom(current); - put_page(area->vm_task, BAD_PAGE, address, PAGE_PRIVATE); - return; - } - clear = 0; if (address + PAGE_SIZE > area->vm_end) { clear = address + PAGE_SIZE - area->vm_end; @@ -141,17 +120,9 @@ nfs_refresh_inode(inode, &fattr); #endif - if (!(error_code & PAGE_RW)) { - if (share_page(area, area->vm_task, inode, address, error_code, page)) - return; - } - tmp = page + PAGE_SIZE; while (clear--) { *(char *)--tmp = 0; } - if (put_page(area->vm_task,page,address,area->vm_page_prot)) - return; - free_page(page); - oom(current); + return page; } diff -u --recursive --new-file v1.1.30/linux/fs/super.c linux/fs/super.c --- v1.1.30/linux/fs/super.c Tue May 31 12:48:18 1994 +++ linux/fs/super.c Mon Jul 18 22:51:13 1994 @@ -610,7 +610,11 @@ } fops = get_blkfops(MAJOR(dev)); if (fops && fops->open) { - retval = fops->open(inode,NULL); + struct file dummy; /* allows read-write or read-only flag */ + memset(&dummy, 0, sizeof(dummy)); + dummy.f_inode = inode; + dummy.f_mode = (new_flags & MS_RDONLY) ? 1 : 3; + retval = fops->open(inode, &dummy); if (retval) { iput(inode); return retval; @@ -628,7 +632,7 @@ retval = do_mount(dev,dir_name,t,flags,(void *) page); free_page(page); if (retval && fops && fops->release) - fops->release(inode,NULL); + fops->release(inode, NULL); iput(inode); return retval; } diff -u --recursive --new-file v1.1.30/linux/include/linux/fdreg.h linux/include/linux/fdreg.h --- v1.1.30/linux/include/linux/fdreg.h Tue Mar 1 08:27:32 1994 +++ linux/include/linux/fdreg.h Mon Jul 18 22:51:14 1994 @@ -47,8 +47,11 @@ /* Bits of FD_ST3 */ #define ST3_HA 0x04 /* Head (Address) */ +#define ST3_DS 0x08 /* drive is double-sided */ #define ST3_TZ 0x10 /* Track Zero signal (1=track 0) */ +#define ST3_RY 0x20 /* drive is ready */ #define ST3_WP 0x40 /* Write Protect */ +#define ST3_FT 0x80 /* Drive Fault */ /* Values for FD_COMMAND */ #define FD_RECALIBRATE 0x07 /* move to track 0 */ @@ -61,6 +64,7 @@ #define FD_VERSION 0x10 /* get version code */ #define FD_CONFIGURE 0x13 /* configure FIFO operation */ #define FD_PERPENDICULAR 0x12 /* perpendicular r/w mode */ +#define FD_GETSTATUS 0x04 /* read ST3 */ /* DMA commands */ #define DMA_READ 0x46 diff -u --recursive --new-file v1.1.30/linux/include/linux/fs.h linux/include/linux/fs.h --- v1.1.30/linux/include/linux/fs.h Mon Jul 18 14:48:30 1994 +++ linux/include/linux/fs.h Mon Jul 18 13:08:40 1994 @@ -444,7 +444,7 @@ extern void brelse(struct buffer_head * buf); extern void set_blocksize(dev_t dev, int size); extern struct buffer_head * bread(dev_t dev, int block, int size); -extern unsigned long bread_page(unsigned long addr,dev_t dev,int b[],int size,int prot); +extern unsigned long bread_page(unsigned long addr,dev_t dev,int b[],int size,int share); extern struct buffer_head * breada(dev_t dev,int block, int size, unsigned int pos, unsigned int filesize); extern void put_super(dev_t dev); diff -u --recursive --new-file v1.1.30/linux/include/linux/mm.h linux/include/linux/mm.h --- v1.1.30/linux/include/linux/mm.h Sat Jul 9 16:30:47 1994 +++ linux/include/linux/mm.h Mon Jul 18 12:33:53 1994 @@ -55,9 +55,10 @@ struct vm_operations_struct { void (*open)(struct vm_area_struct * area); void (*close)(struct vm_area_struct * area); - void (*nopage)(int error_code, - struct vm_area_struct * area, unsigned long address); - void (*wppage)(struct vm_area_struct * area, unsigned long address); + unsigned long (*nopage)(struct vm_area_struct * area, unsigned long address, + unsigned long page, int error_code); + unsigned long (*wppage)(struct vm_area_struct * area, unsigned long address, + unsigned long page); int (*share)(struct vm_area_struct * from, struct vm_area_struct * to, unsigned long address); int (*unmap)(struct vm_area_struct *area, unsigned long, size_t); }; @@ -135,6 +136,7 @@ extern void show_free_areas(void); extern unsigned long put_dirty_page(struct task_struct * tsk,unsigned long page, unsigned long address); + extern void free_page_tables(struct task_struct * tsk); extern void clear_page_tables(struct task_struct * tsk); extern int copy_page_tables(struct task_struct * to); @@ -144,9 +146,9 @@ extern int zeromap_page_range(unsigned long from, unsigned long size, int mask); extern void do_wp_page(unsigned long error_code, unsigned long address, - struct task_struct *tsk, unsigned long user_esp); + struct task_struct *tsk); extern void do_no_page(unsigned long error_code, unsigned long address, - struct task_struct *tsk, unsigned long user_esp); + struct task_struct *tsk); extern unsigned long paging_init(unsigned long start_mem, unsigned long end_mem); extern void mem_init(unsigned long low_start_mem, diff -u --recursive --new-file v1.1.30/linux/include/linux/soundcard.h linux/include/linux/soundcard.h --- v1.1.30/linux/include/linux/soundcard.h Sun May 1 12:12:47 1994 +++ linux/include/linux/soundcard.h Mon Jul 18 09:38:23 1994 @@ -34,7 +34,7 @@ * * Regards, * Hannu Savolainen - * hannu@voxware.pp.fi, Hannu.Savolainen@helsinki.fi + * hannu@voxware.pp.fi */ #define SOUND_VERSION 203 @@ -46,13 +46,17 @@ * Supported card ID numbers (Should be somewhere else?) */ -#define SNDCARD_ADLIB 1 -#define SNDCARD_SB 2 -#define SNDCARD_PAS 3 -#define SNDCARD_GUS 4 -#define SNDCARD_MPU401 5 -#define SNDCARD_SB16 6 -#define SNDCARD_SB16MIDI 7 +#define SNDCARD_ADLIB 1 +#define SNDCARD_SB 2 +#define SNDCARD_PAS 3 +#define SNDCARD_GUS 4 +#define SNDCARD_MPU401 5 +#define SNDCARD_SB16 6 +#define SNDCARD_SB16MIDI 7 +#define SNDCARD_UART6850 8 +#define SNDCARD_GUS16 9 +#define SNDCARD_MSS 10 +#define SNDCARD_PSS 11 /*********************************** * IOCTL Commands for /dev/sequencer @@ -98,7 +102,23 @@ #define SNDCTL_SYNTH_MEMAVL _IOWR('Q',14, int) /* in=dev#, out=memsize */ #define SNDCTL_FM_4OP_ENABLE _IOW ('Q',15, int) /* in=dev# */ #define SNDCTL_PMGR_ACCESS _IOWR('Q',16, struct patmgr_info) +#define SNDCTL_SEQ_PANIC _IO ('Q',17) +#define SNDCTL_TMR_TIMEBASE _IOWR('T', 1, int) +#define SNDCTL_TMR_START _IO ('T', 2) +#define SNDCTL_TMR_STOP _IO ('T', 3) +#define SNDCTL_TMR_CONTINUE _IO ('T', 4) +#define SNDCTL_TMR_TEMPO _IOWR('T', 5, int) +#define SNDCTL_TMR_SOURCE _IOWR('T', 6, int) +# define TMR_INTERNAL 0x00000001 +# define TMR_EXTERNAL 0x00000002 +# define TMR_MODE_MIDI 0x00000010 +# define TMR_MODE_FSK 0x00000020 +# define TMR_MODE_CLS 0x00000040 +# define TMR_MODE_SMPTE 0x00000080 +#define SNDCTL_TMR_METRONOME _IOW ('T', 7, int) +#define SNDCTL_TMR_SELECT _IOW ('T', 8, int) + /* * Sample loading mechanism for internal synthesizers (/dev/sequencer) * The following patch_info structure has been designed to support @@ -187,6 +207,14 @@ }; +struct sysex_info { + short key; /* Use GUS_PATCH here */ +#define SYSEX_PATCH 0x05fd + short device_no; /* Synthesizer number */ + long len; /* Size of the sysex data in bytes */ + unsigned char data[1]; /* Sysex data starts here */ + }; + /* * Patch management interface (/dev/sequencer, /dev/patmgr#) * Don't use these calls if you want to maintain compatibility with @@ -282,7 +310,7 @@ * * Events SEQ_WAIT, SEQ_MIDIPUTC and SEQ_ECHO. Are also input events. * (All input events are currently 4 bytes long. Be prepared to support - * 8 byte events also. If you receive any event having first byte >= 0xf0, + * 8 byte events also. If you receive any event having first byte >= 128, * it's a 8 byte event. * * The events are documented at the end of this file. @@ -295,20 +323,99 @@ #define SEQ_FMNOTEOFF SEQ_NOTEOFF /* Just old name */ #define SEQ_NOTEON 1 #define SEQ_FMNOTEON SEQ_NOTEON -#define SEQ_WAIT 2 +#define SEQ_WAIT TMR_WAIT_ABS #define SEQ_PGMCHANGE 3 #define SEQ_FMPGMCHANGE SEQ_PGMCHANGE -#define SEQ_SYNCTIMER 4 +#define SEQ_SYNCTIMER TMR_START #define SEQ_MIDIPUTC 5 #define SEQ_DRUMON 6 /*** OBSOLETE ***/ #define SEQ_DRUMOFF 7 /*** OBSOLETE ***/ -#define SEQ_ECHO 8 /* For synching programs with output */ +#define SEQ_ECHO TMR_ECHO /* For synching programs with output */ #define SEQ_AFTERTOUCH 9 #define SEQ_CONTROLLER 10 + +/******************************************* + * Midi controller numbers + ******************************************* + * Controllers 0 to 31 (0x00 to 0x1f) and + * 32 to 63 (0x20 to 0x3f) are continuous + * controllers. + * In the MIDI 1.0 these controllers are sent using + * two messages. Controller numbers 0 to 31 are used + * to send the LSB and the controller numbers 32 to 63 + * are for the LSB. + * + * This driver uses just the numbers 0 to 31 to store both + * the LSB and MSB. The controller value is a unsigned short + * and it's valid range is between 0 and 16383 (0x0000 to 0x3fff). + * The driver sends the controller value using two messages when + * necessary. + */ + +#define CTL_BANK_SELECT 0x00 +#define CTL_MODWHEEL 0x01 +#define CTL_BREATH 0x02 +/* undefined 0x03 */ +#define CTL_FOOT 0x04 +#define CTL_PORTAMENTO_TIME 0x05 +#define CTL_DATA_ENTRY 0x06 +#define CTL_MAIN_VOLUME 0x07 +#define CTL_BALANCE 0x08 +/* undefined 0x09 */ +#define CTL_PAN 0x0a +#define CTL_EXPRESSION 0x0b +/* undefined 0x0c */ +/* undefined 0x0d */ +/* undefined 0x0e */ +/* undefined 0x0f */ +#define CTL_GENERAL_PURPOSE1 0x10 +#define CTL_GENERAL_PURPOSE2 0x11 +#define CTL_GENERAL_PURPOSE3 0x12 +#define CTL_GENERAL_PURPOSE4 0x13 +/* undefined 0x14 - 0x1f */ + +/* undefined 0x20 */ +/* The controller numbers 0x21 to 0x3f are reserved for the */ +/* least significant bytes of the controllers 0x00 to 0x1f. */ +/* These controllers are not recognised by the driver. */ + +/* Controllers 64 to 69 (0x40 to 0x45) are on/off switches. */ +/* 0=OFF and 127=ON (intermediate values are possible) */ +#define CTL_DAMPER_PEDAL 0x40 +#define CTL_SUSTAIN 0x40 /* Alias */ +#define CTL_HOLD 0x40 /* Alias */ +#define CTL_PORTAMENTO 0x41 +#define CTL_SOSTENUTO 0x42 +#define CTL_SOFT_PEDAL 0x43 +/* undefined 0x44 */ +#define CTL_HOLD2 0x45 +/* undefined 0x46 - 0x4f */ + +#define CTL_GENERAL_PURPOSE5 0x50 +#define CTL_GENERAL_PURPOSE6 0x51 +#define CTL_GENERAL_PURPOSE7 0x52 +#define CTL_GENERAL_PURPOSE8 0x53 +/* undefined 0x54 - 0x5a */ +#define CTL_EXT_EFF_DEPTH 0x5b +#define CTL_TREMOLO_DEPTH 0x5c +#define CTL_CHORUS_DEPTH 0x5d +#define CTL_DETUNE_DEPTH 0x5e +#define CTL_CELESTE_DEPTH 0x5e /* Alias for the above one */ +#define CTL_PHASER_DEPTH 0x5f +#define CTL_DATA_INCREMENT 0x60 +#define CTL_DATA_DECREMENT 0x61 +#define CTL_NONREG_PARM_NUM_LSB 0x62 +#define CTL_NONREG_PARM_NUM_MSB 0x63 +#define CTL_REGIST_PARM_NUM_LSB 0x64 +#define CTL_REGIST_PARM_NUM_MSB 0x65 +/* undefined 0x66 - 0x78 */ +/* reserved 0x79 - 0x7f */ + +/* Pseudo controllers (not midi compatible) */ #define CTRL_PITCH_BENDER 255 #define CTRL_PITCH_BENDER_RANGE 254 -#define CTRL_EXPRESSION 253 -#define CTRL_MAIN_VOLUME 252 +#define CTRL_EXPRESSION 253 /* Obsolete */ +#define CTRL_MAIN_VOLUME 252 /* Obsolete */ #define SEQ_BALANCE 11 #define SEQ_VOLMODE 12 @@ -350,26 +457,7 @@ * to GUS_PATCH. */ #define SEQ_PRIVATE 0xfe /* Low level HW dependent events (8 bytes) */ -#define SEQ_EXTENDED 0xff /* Extended events (8 bytes) */ - -/* - * Extended events for synthesizers (8 bytes) - * - * Format: - * - * b0 = SEQ_EXTENDED - * b1 = command - * b2 = device - * b3-b7 = parameters - * - * Command b3 b4 b5 b6 b7 - * ---------------------------------------------------------------------------- - * SEQ_NOTEON voice note volume 0 0 - * SEQ_NOTEOFF voice note volume 0 0 - * SEQ_PGMCHANGE voice pgm 0 0 0 - * SEQ_DRUMON (voice) drum# volume 0 0 - * SEQ_DRUMOFF (voice) drum# volume 0 0 - */ +#define SEQ_EXTENDED 0xff /* Extended events (8 bytes) OBSOLETE */ /* * Record for FM patches @@ -392,6 +480,7 @@ int synth_type; #define SYNTH_TYPE_FM 0 #define SYNTH_TYPE_SAMPLE 1 +#define SYNTH_TYPE_MIDI 2 /* Midi interface */ int synth_subtype; #define FM_TYPE_ADLIB 0x00 @@ -406,9 +495,17 @@ unsigned long capabilities; #define SYNTH_CAP_PERCMODE 0x00000001 /* No longer used */ #define SYNTH_CAP_OPL3 0x00000002 /* Set if OPL3 supported */ +#define SYNTH_CAP_INPUT 0x00000004 /* Input (MIDI) device */ int dummies[19]; /* Reserve space */ }; +struct sound_timer_info { + char name[30]; + int caps; + }; + +#define MIDI_CAP_MPU401 1 /* MPU-401 intelligent mode */ + struct midi_info { char name[30]; int device; /* 0-N. INITIALIZE BEFORE CALLING */ @@ -418,6 +515,19 @@ }; /******************************************** + * ioctl commands for the /dev/midi## + */ +typedef struct { + unsigned char cmd; + char nr_args, nr_returns; + unsigned char data[30]; + } mpu_command_rec; + +#define SNDCTL_MIDI_PRETIME _IOWR('m', 0, int) +#define SNDCTL_MIDI_MPUMODE _IOWR('m', 1, int) +#define SNDCTL_MIDI_MPUCMD _IOWR('m', 2, mpu_command_rec) + +/******************************************** * IOCTL commands for /dev/dsp and /dev/audio */ @@ -426,24 +536,57 @@ #define SNDCTL_DSP_SPEED _IOWR('P', 2, int) #define SNDCTL_DSP_STEREO _IOWR('P', 3, int) #define SNDCTL_DSP_GETBLKSIZE _IOWR('P', 4, int) -#define SNDCTL_DSP_SAMPLESIZE _IOWR('P', 5, int) /* 8, 12 or 16 */ +#define SNDCTL_DSP_SAMPLESIZE SNDCTL_DSP_SETFMT #define SOUND_PCM_WRITE_CHANNELS _IOWR('P', 6, int) #define SOUND_PCM_WRITE_FILTER _IOWR('P', 7, int) #define SNDCTL_DSP_POST _IO ('P', 8) #define SNDCTL_DSP_SUBDIVIDE _IOWR('P', 9, int) +#define SNDCTL_DSP_SETFRAGMENT _IOWR('P',10, int) +/* Audio data formats (Note! U8=8 and S16_LE=16 for compatibility) */ +#define SNDCTL_DSP_GETFMTS _IOR ('P',11, int) /* Returns a mask */ +#define SNDCTL_DSP_SETFMT _IOWR('P',5, int) /* Selects ONE fmt*/ +# define AFMT_QUERY 0x00000000 /* Return current fmt */ +# define AFMT_MU_LAW 0x00000001 +# define AFMT_A_LAW 0x00000002 +# define AFMT_IMA_ADPCM 0x00000004 +# define AFMT_U8 0x00000008 +# define AFMT_S16_LE 0x00000010 /* Little endian signed 16*/ +# define AFMT_S16_BE 0x00000020 /* Big endian signed 16 */ +# define AFMT_S8 0x00000040 +# define AFMT_U16_LE 0x00000080 /* Little endian U16 */ +# define AFMT_U16_BE 0x00000100 /* Big endian U16 */ + #define SOUND_PCM_READ_RATE _IOR ('P', 2, int) #define SOUND_PCM_READ_CHANNELS _IOR ('P', 6, int) #define SOUND_PCM_READ_BITS _IOR ('P', 5, int) #define SOUND_PCM_READ_FILTER _IOR ('P', 7, int) /* Some alias names */ -#define SOUND_PCM_WRITE_BITS SNDCTL_DSP_SAMPLESIZE +#define SOUND_PCM_WRITE_BITS SNDCTL_DSP_SETFMT #define SOUND_PCM_WRITE_RATE SNDCTL_DSP_SPEED #define SOUND_PCM_POST SNDCTL_DSP_POST #define SOUND_PCM_RESET SNDCTL_DSP_RESET #define SOUND_PCM_SYNC SNDCTL_DSP_SYNC #define SOUND_PCM_SUBDIVIDE SNDCTL_DSP_SUBDIVIDE +#define SOUND_PCM_SETFRAGMENT SNDCTL_DSP_SETFRAGMENT +#define SOUND_PCM_GETFMTS SNDCTL_DSP_GETFMTS +#define SOUND_PCM_SETFMT SNDCTL_DSP_SETFMT + +/********************************************* + * IOCTL /dev/pss (experimental PSS API by marc.hoffman@analog.com. + * likely to change in near future. + */ +#define SNDCTL_PSS_RESET _IO ('C', 0) +#define SNDCTL_PSS_SETUP_REGISTERS _IO ('C', 1) +#define SNDCTL_PSS_SPEAKER _IOW ('C', 2, struct pss_speaker) + +struct pss_speaker { + int volume; + int bass; + int treb; + int mode; +}; /********************************************* * IOCTL commands for /dev/mixer @@ -559,57 +702,66 @@ #define SOUND_MIXER_WRITE_RECSRC MIXER_WRITE(SOUND_MIXER_RECSRC) /* - * The following mixer ioctl calls are compatible with the BSD driver by - * Steve Haehnichen + * Level 2 event types for /dev/sequencer + */ + +/* + * The 4 most significant bits of byte 0 specify the class of + * the event: * - * Since this interface is entirely SB specific, it will be dropped in the - * near future. + * 0x8X = system level events, + * 0x9X = device/port specific events, event[1] = device/port, + * The last 4 bits give the subtype: + * 0x02 = Channel event (event[3] = chn). + * 0x01 = note event (event[4] = note). + * (0x01 is not used alone but always with bit 0x02). + * event[2] = MIDI message code (0x80=note off etc.) + * */ -typedef unsigned char S_BYTE; -typedef unsigned char S_FLAG; -struct stereo_vol -{ - S_BYTE l; /* Left volume */ - S_BYTE r; /* Right volume */ -}; +#define EV_SEQ_LOCAL 0x80 +#define EV_TIMING 0x81 +#define EV_CHN_COMMON 0x92 +#define EV_CHN_VOICE 0x93 +/* + * Event types 200 to 220 are reserved for application use. + * These numbers will not be used by the driver. + */ -#define MIXER_IOCTL_SET_LEVELS _IOW ('s', 20, struct sb_mixer_levels) -#define MIXER_IOCTL_SET_PARAMS _IOW ('s', 21, struct sb_mixer_params) -#define MIXER_IOCTL_READ_LEVELS _IOR ('s', 22, struct sb_mixer_levels) -#define MIXER_IOCTL_READ_PARAMS _IOR ('s', 23, struct sb_mixer_params) -#define MIXER_IOCTL_RESET _IO ('s', 24) - -/* - * Mixer volume levels for MIXER_IOCTL_SET_VOL & MIXER_IOCTL_READ_VOL - */ -struct sb_mixer_levels -{ - struct stereo_vol master; /* Master volume */ - struct stereo_vol voc; /* DSP Voice volume */ - struct stereo_vol fm; /* FM volume */ - struct stereo_vol line; /* Line-in volume */ - struct stereo_vol cd; /* CD audio */ - S_BYTE mic; /* Microphone level */ -}; +/* + * Events for event type EV_CHN_VOICE + */ + +#define MIDI_NOTEOFF 0x80 +#define MIDI_NOTEON 0x90 +#define MIDI_KEY_PRESSURE 0xA0 /* - * Mixer parameters for MIXER_IOCTL_SET_PARAMS & MIXER_IOCTL_READ_PARAMS + * Events for event type EV_CHN_COMMON */ -struct sb_mixer_params -{ - S_BYTE record_source; /* Recording source (See SRC_xxx below) */ - S_FLAG hifreq_filter; /* Filter frequency (hi/low) */ - S_FLAG filter_input; /* ANFI input filter */ - S_FLAG filter_output; /* DNFI output filter */ - S_FLAG dsp_stereo; /* 1 if DSP is in Stereo mode */ -}; + +#define MIDI_CTL_CHANGE 0xB0 +#define MIDI_PGM_CHANGE 0xC0 +#define MIDI_CHN_PRESSURE 0xD0 +#define MIDI_PITCH_BEND 0xE0 + +#define MIDI_SYSTEM_PREFIX 0xF0 -#define SRC_MIC 1 /* Select Microphone recording source */ -#define SRC_CD 3 /* Select CD recording source */ -#define SRC_LINE 7 /* Use Line-in for recording source */ +/* + * Timer event types + */ +#define TMR_WAIT_REL 1 /* Time relative to the prev time */ +#define TMR_WAIT_ABS 2 /* Absolute time since TMR_START */ +#define TMR_STOP 3 +#define TMR_START 4 +#define TMR_CONTINUE 5 +#define TMR_TEMPO 6 +#define TMR_ECHO 8 +#define TMR_CLOCK 9 /* MIDI clock */ +#define TMR_SPP 10 /* Song position pointer */ +#define TMR_TIMESIG 11 /* Time signature */ -#if !defined(KERNEL) && !defined(INKERNEL) +#if (!defined(__KERNEL__) && !defined(KERNEL) && !defined(INKERNEL) && !defined(_KERNEL)) || defined(USE_SEQ_MACROS) /* * Some convenience macros to simplify programming of the * /dev/sequencer interface @@ -617,6 +769,7 @@ * These macros define the API which should be used when possible. */ +#ifndef USE_SIMPLE_MACROS void seqbuf_dump(void); /* This function must be provided by programs */ /* Sample seqbuf_dump() implementation: @@ -638,12 +791,31 @@ * } */ -#define SEQ_DEFINEBUF(len) unsigned char _seqbuf[len]; int _seqbuflen = len; int _seqbufptr = 0 -#define SEQ_DECLAREBUF() extern unsigned char _seqbuf[]; extern int _seqbuflen;extern int _seqbufptr +#define SEQ_DEFINEBUF(len) unsigned char _seqbuf[len]; int _seqbuflen = len;int _seqbufptr = 0 +#define SEQ_USE_EXTBUF() extern unsigned char _seqbuf[]; extern int _seqbuflen;extern int _seqbufptr +#define SEQ_DECLAREBUF() SEQ_USE_EXTBUF() #define SEQ_PM_DEFINES struct patmgr_info _pm_info #define _SEQ_NEEDBUF(len) if ((_seqbufptr+(len)) > _seqbuflen) seqbuf_dump() #define _SEQ_ADVBUF(len) _seqbufptr += len #define SEQ_DUMPBUF seqbuf_dump +#else +/* + * This variation of the sequencer macros is used just to format one event + * using fixed buffer. + * + * The program using the macro library must define the following macros before + * using this library. + * + * #define _seqbuf name of the buffer (unsigned char[]) + * #define _SEQ_ADVBUF(len) If the applic needs to know the exact + * size of the event, this macro can be used. + * Otherwise this must be defined as empty. + * #define _seqbufptr Define the name of index variable or 0 if + * not required. + */ +#define _SEQ_NEEDBUF(len) /* empty */ +#endif + #define PM_LOAD_PATCH(dev, bank, pgm) (SEQ_DUMPBUF(), _pm_info.command = _PM_LOAD_PATCH, \ _pm_info.device=dev, _pm_info.data.data8[0]=pgm, \ _pm_info.parm1 = bank, _pm_info.parm2 = 1, \ @@ -664,39 +836,68 @@ _seqbuf[_seqbufptr+7] = 0;\ _SEQ_ADVBUF(8);} -#define SEQ_START_NOTE(dev, voice, note, vol) {_SEQ_NEEDBUF(8);\ - _seqbuf[_seqbufptr] = SEQ_EXTENDED;\ - _seqbuf[_seqbufptr+1] = SEQ_NOTEON;\ - _seqbuf[_seqbufptr+2] = (dev);\ - _seqbuf[_seqbufptr+3] = (voice);\ - _seqbuf[_seqbufptr+4] = (note);\ - _seqbuf[_seqbufptr+5] = (vol);\ - _seqbuf[_seqbufptr+6] = 0;\ - _seqbuf[_seqbufptr+7] = 0;\ - _SEQ_ADVBUF(8);} +/* + * Midi voice messages + */ -#define SEQ_STOP_NOTE(dev, voice, note, vol) {_SEQ_NEEDBUF(8);\ - _seqbuf[_seqbufptr] = SEQ_EXTENDED;\ - _seqbuf[_seqbufptr+1] = SEQ_NOTEOFF;\ - _seqbuf[_seqbufptr+2] = (dev);\ - _seqbuf[_seqbufptr+3] = (voice);\ +#define _CHN_VOICE(dev, event, chn, note, parm) \ + {_SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr] = EV_CHN_VOICE;\ + _seqbuf[_seqbufptr+1] = (dev);\ + _seqbuf[_seqbufptr+2] = (event);\ + _seqbuf[_seqbufptr+3] = (chn);\ _seqbuf[_seqbufptr+4] = (note);\ - _seqbuf[_seqbufptr+5] = (vol);\ - _seqbuf[_seqbufptr+6] = 0;\ + _seqbuf[_seqbufptr+5] = (parm);\ + _seqbuf[_seqbufptr+6] = (0);\ _seqbuf[_seqbufptr+7] = 0;\ _SEQ_ADVBUF(8);} -#define SEQ_CHN_PRESSURE(dev, voice, pressure) {_SEQ_NEEDBUF(8);\ - _seqbuf[_seqbufptr] = SEQ_EXTENDED;\ - _seqbuf[_seqbufptr+1] = SEQ_AFTERTOUCH;\ - _seqbuf[_seqbufptr+2] = (dev);\ - _seqbuf[_seqbufptr+3] = (voice);\ - _seqbuf[_seqbufptr+4] = (pressure);\ - _seqbuf[_seqbufptr+5] = 0;\ - _seqbuf[_seqbufptr+6] = 0;\ - _seqbuf[_seqbufptr+7] = 0;\ +#define SEQ_START_NOTE(dev, chn, note, vol) \ + _CHN_VOICE(dev, MIDI_NOTEON, chn, note, vol) + +#define SEQ_STOP_NOTE(dev, chn, note, vol) \ + _CHN_VOICE(dev, MIDI_NOTEOFF, chn, note, vol) + +#define SEQ_KEY_PRESSURE(dev, chn, note, pressure) \ + _CHN_VOICE(dev, MIDI_KEY_PRESSURE, chn, note, pressure) + +/* + * Midi channel messages + */ + +#define _CHN_COMMON(dev, event, chn, p1, p2, w14) \ + {_SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr] = EV_CHN_COMMON;\ + _seqbuf[_seqbufptr+1] = (dev);\ + _seqbuf[_seqbufptr+2] = (event);\ + _seqbuf[_seqbufptr+3] = (chn);\ + _seqbuf[_seqbufptr+4] = (p1);\ + _seqbuf[_seqbufptr+5] = (p2);\ + *(short *)&_seqbuf[_seqbufptr+6] = (w14);\ _SEQ_ADVBUF(8);} +#define SEQ_CHN_PRESSURE(dev, chn, pressure) \ + _CHN_COMMON(dev, MIDI_CHN_PRESSURE, chn, pressure, 0, 0) + +#define SEQ_SET_PATCH(dev, chn, patch) \ + _CHN_COMMON(dev, MIDI_PGM_CHANGE, chn, patch, 0, 0) + +#define SEQ_CONTROL(dev, chn, controller, value) \ + _CHN_COMMON(dev, MIDI_CTL_CHANGE, chn, controller, 0, value) + +#define SEQ_BENDER(dev, chn, value) \ + _CHN_COMMON(dev, MIDI_PITCH_BEND, chn, 0, 0, value) + +/* + * The following 5 macros are incorrectly implemented and obsolete. + * Use SEQ_BENDER and SEQ_CONTROL (with proper controller) instead. + */ +#define SEQ_PITCHBEND(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_PITCH_BENDER, value) +#define SEQ_BENDER_RANGE(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_PITCH_BENDER_RANGE, value) +#define SEQ_EXPRESSION(dev, voice, value) SEQ_CONTROL(dev, voice, CTL_EXPRESSION, value*128) +#define SEQ_MAIN_VOLUME(dev, voice, value) SEQ_CONTROL(dev, voice, CTL_MAIN_VOLUME, (value*16383)/100) +#define SEQ_PANNING(dev, voice, pos) SEQ_CONTROL(dev, voice, CTL_PAN, (pos+128) / 2) +#if 0 #define SEQ_PANNING(dev, voice, pos) {_SEQ_NEEDBUF(8);\ _seqbuf[_seqbufptr] = SEQ_EXTENDED;\ _seqbuf[_seqbufptr+1] = SEQ_BALANCE;\ @@ -705,58 +906,50 @@ (char)_seqbuf[_seqbufptr+4] = (pos);\ _seqbuf[_seqbufptr+5] = 0;\ _seqbuf[_seqbufptr+6] = 0;\ - _seqbuf[_seqbufptr+7] = 0;\ - _SEQ_ADVBUF(8);} - -#define SEQ_CONTROL(dev, voice, controller, value) {_SEQ_NEEDBUF(8);\ - _seqbuf[_seqbufptr] = SEQ_EXTENDED;\ - _seqbuf[_seqbufptr+1] = SEQ_CONTROLLER;\ - _seqbuf[_seqbufptr+2] = (dev);\ - _seqbuf[_seqbufptr+3] = (voice);\ - _seqbuf[_seqbufptr+4] = (controller);\ - *(short *)&_seqbuf[_seqbufptr+5] = (value);\ - _seqbuf[_seqbufptr+7] = 0;\ + _seqbuf[_seqbufptr+7] = 1;\ _SEQ_ADVBUF(8);} +#endif -#define SEQ_PITCHBEND(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_PITCH_BENDER, value) -#define SEQ_BENDER_RANGE(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_PITCH_BENDER_RANGE, value) -#define SEQ_EXPRESSION(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_EXPRESSION, value) -#define SEQ_MAIN_VOLUME(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_MAIN_VOLUME, value) +/* + * Timing and syncronization macros + */ -#define SEQ_START_TIMER() {_SEQ_NEEDBUF(4);\ - _seqbuf[_seqbufptr] = SEQ_SYNCTIMER;\ - _seqbuf[_seqbufptr+1] = 0;\ +#define _TIMER_EVENT(ev, parm) {_SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr+0] = EV_TIMING; \ + _seqbuf[_seqbufptr+1] = (ev); \ _seqbuf[_seqbufptr+2] = 0;\ _seqbuf[_seqbufptr+3] = 0;\ - _SEQ_ADVBUF(4);} -#define SEQ_SET_PATCH(dev, voice, patch) {_SEQ_NEEDBUF(8);\ - _seqbuf[_seqbufptr] = SEQ_EXTENDED;\ - _seqbuf[_seqbufptr+1] = SEQ_PGMCHANGE;\ - _seqbuf[_seqbufptr+2] = (dev);\ - _seqbuf[_seqbufptr+3] = (voice);\ - _seqbuf[_seqbufptr+4] = (patch);\ - _seqbuf[_seqbufptr+5] = 0;\ - _seqbuf[_seqbufptr+6] = 0;\ - _seqbuf[_seqbufptr+7] = 0;\ + *(unsigned int *)&_seqbuf[_seqbufptr+4] = (parm); \ _SEQ_ADVBUF(8);} -#define SEQ_WAIT_TIME(ticks) {_SEQ_NEEDBUF(4);\ - *(unsigned long *)&_seqbuf[_seqbufptr] = SEQ_WAIT | ((ticks) << 8);\ - _SEQ_ADVBUF(4);} - -#define SEQ_ECHO_BACK(key) {_SEQ_NEEDBUF(4);\ - *(unsigned long *)&_seqbuf[_seqbufptr] = SEQ_ECHO | ((key) << 8);\ - _SEQ_ADVBUF(4);} +#define SEQ_START_TIMER() _TIMER_EVENT(TMR_START, 0) +#define SEQ_STOP_TIMER() _TIMER_EVENT(TMR_STOP, 0) +#define SEQ_CONTINUE_TIMER() _TIMER_EVENT(TMR_CONTINUE, 0) +#define SEQ_WAIT_TIME(ticks) _TIMER_EVENT(TMR_WAIT_ABS, ticks) +#define SEQ_DELTA_TIME(ticks) _TIMER_EVENT(TMR_WAIT_REL, ticks) +#define SEQ_ECHO_BACK(key) _TIMER_EVENT(TMR_ECHO, key) +#define SEQ_SET_TEMPO(value) _TIMER_EVENT(TMR_TEMPO, value) +#define SEQ_SONGPOS(pos) _TIMER_EVENT(TMR_SPP, pos) +#define SEQ_TIME_SIGNATURE(sig) _TIMER_EVENT(TMR_TIMESIG, sig) +/* + * Events for the level 1 interface only + */ + #define SEQ_MIDIOUT(device, byte) {_SEQ_NEEDBUF(4);\ _seqbuf[_seqbufptr] = SEQ_MIDIPUTC;\ _seqbuf[_seqbufptr+1] = (byte);\ _seqbuf[_seqbufptr+2] = (device);\ _seqbuf[_seqbufptr+3] = 0;\ _SEQ_ADVBUF(4);} -#define SEQ_WRPATCH(patchx, len) {if (_seqbufptr) seqbuf_dump();\ + +/* + * Patch loading. + */ +#define SEQ_WRPATCH(patchx, len) {if (_seqbufptr) seqbuf_dump();\ if (write(seqfd, (char*)(patchx), len)==-1) \ perror("Write patch: /dev/sequencer");} +#define SEQ_WRPATCH2(patchx, len) (seqbuf_dump(), write(seqfd, (char*)(patchx), len)) #endif long soundcard_init(long mem_start); diff -u --recursive --new-file v1.1.30/linux/kernel/ptrace.c linux/kernel/ptrace.c --- v1.1.30/linux/kernel/ptrace.c Mon Dec 27 08:54:52 1993 +++ linux/kernel/ptrace.c Mon Jul 18 12:45:50 1994 @@ -98,7 +98,7 @@ page = *((unsigned long *) page); } if (!(page & PAGE_PRESENT)) { - do_no_page(0,addr,tsk,0); + do_no_page(0,addr,tsk); goto repeat; } /* this is a hack for non-kernel-mapped video buffers and similar */ @@ -133,13 +133,13 @@ page = *((unsigned long *) page); } if (!(page & PAGE_PRESENT)) { - do_no_page(0 /* PAGE_RW */ ,addr,tsk,0); + do_no_page(0 /* PAGE_RW */ ,addr,tsk); goto repeat; } if (!(page & PAGE_RW)) { if(!(page & PAGE_COW)) readonly = 1; - do_wp_page(PAGE_RW | PAGE_PRESENT,addr,tsk,0); + do_wp_page(PAGE_RW | PAGE_PRESENT,addr,tsk); goto repeat; } /* this is a hack for non-kernel-mapped video buffers and similar */ diff -u --recursive --new-file v1.1.30/linux/mm/memory.c linux/mm/memory.c --- v1.1.30/linux/mm/memory.c Mon Jun 27 16:47:02 1994 +++ linux/mm/memory.c Mon Jul 18 15:53:55 1994 @@ -561,7 +561,7 @@ * in better assembly code.. The "default" path will see no jumps at all. */ static void __do_wp_page(unsigned long error_code, unsigned long address, - struct task_struct * tsk, unsigned long user_esp) + struct task_struct * tsk) { unsigned long *pde, pte, old_page, prot; unsigned long new_page; @@ -626,7 +626,7 @@ * the low-level function only in that case.. */ void do_wp_page(unsigned long error_code, unsigned long address, - struct task_struct * tsk, unsigned long user_esp) + struct task_struct * tsk) { unsigned long page; unsigned long * pg_table; @@ -643,7 +643,7 @@ if (page & PAGE_RW) return; if (!(page & PAGE_COW)) { - if (user_esp && tsk == current) { + if ((error_code & PAGE_USER) && tsk == current) { current->tss.cr2 = address; current->tss.error_code = error_code; current->tss.trap_no = 14; @@ -656,7 +656,7 @@ invalidate(); return; } - __do_wp_page(error_code, address, tsk, user_esp); + __do_wp_page(error_code, address, tsk); return; } printk("bad page directory entry %08lx\n",page); @@ -670,7 +670,7 @@ size >>= PAGE_SHIFT; start &= PAGE_MASK; do { - do_wp_page(1,start,current,0); + do_wp_page(1,start,current); start += PAGE_SIZE; } while (size--); return 0; @@ -733,30 +733,25 @@ * task. * * NOTE! This assumes we have checked that p != current, and that they - * share the same executable or library. - * - * We may want to fix this to allow page sharing for PIC pages at different - * addresses so that ELF will really perform properly. As long as the vast - * majority of sharable libraries load at fixed addresses this is not a - * big concern. Any sharing of pages between the buffer cache and the - * code space reduces the need for this as well. - ERY + * share the same inode and can generally otherwise be shared. */ -static int try_to_share(unsigned long address, struct task_struct * tsk, - struct task_struct * p, unsigned long error_code, unsigned long newpage) +static int try_to_share(unsigned long to_address, struct vm_area_struct * to_area, + unsigned long from_address, struct vm_area_struct * from_area, + unsigned long newpage) { unsigned long from; unsigned long to; unsigned long from_page; unsigned long to_page; - from_page = (unsigned long)PAGE_DIR_OFFSET(p->tss.cr3,address); - to_page = (unsigned long)PAGE_DIR_OFFSET(tsk->tss.cr3,address); + from_page = (unsigned long)PAGE_DIR_OFFSET(from_area->vm_task->tss.cr3,from_address); + to_page = (unsigned long)PAGE_DIR_OFFSET(to_area->vm_task->tss.cr3,to_address); /* is there a page-directory at from? */ from = *(unsigned long *) from_page; if (!(from & PAGE_PRESENT)) return 0; from &= PAGE_MASK; - from_page = from + PAGE_PTR(address); + from_page = from + PAGE_PTR(from_address); from = *(unsigned long *) from_page; /* is the page clean and present? */ if ((from & (PAGE_PRESENT | PAGE_DIRTY)) != PAGE_PRESENT) @@ -770,68 +765,88 @@ if (!(to & PAGE_PRESENT)) return 0; to &= PAGE_MASK; - to_page = to + PAGE_PTR(address); + to_page = to + PAGE_PTR(to_address); if (*(unsigned long *) to_page) return 0; -/* share them if read - do COW immediately otherwise */ - if (error_code & PAGE_RW) { - if(!newpage) /* did the page exist? SRB. */ - return 0; - copy_page((from & PAGE_MASK),newpage); - to = newpage | PAGE_PRIVATE; - } else { - mem_map[MAP_NR(from)]++; - from &= ~PAGE_RW; - to = from; - if(newpage) /* only if it existed. SRB. */ - free_page(newpage); - } - *(unsigned long *) from_page = from; +/* do we copy? */ + if (newpage) { + copy_page((from & PAGE_MASK), newpage); + *(unsigned long *) to_page = newpage | to_area->vm_page_prot; + return 1; + } +/* just share them.. */ + mem_map[MAP_NR(from)]++; +/* fill in the 'to' field, checking for COW-stuff */ + to = (from & PAGE_MASK) | to_area->vm_page_prot; + if (to & PAGE_COW) + to &= ~PAGE_RW; *(unsigned long *) to_page = to; +/* Check if we need to do anything at all to the 'from' field */ + if (!(from & PAGE_RW)) + return 1; + if (!(from_area->vm_page_prot & PAGE_COW)) + return 1; +/* ok, need to mark it read-only, so invalidate aany possible old TB entry */ + from &= ~PAGE_RW; + *(unsigned long *) from_page = from; invalidate(); return 1; } /* * share_page() tries to find a process that could share a page with - * the current one. Address is the address of the wanted page relative - * to the current data space. + * the current one. * - * We first check if it is at all feasible by checking executable->i_count. + * We first check if it is at all feasible by checking inode->i_count. * It should be >1 if there are other tasks sharing this inode. */ -int share_page(struct vm_area_struct * area, struct task_struct * tsk, - struct inode * inode, - unsigned long address, unsigned long error_code, unsigned long newpage) +static int share_page(struct vm_area_struct * area, unsigned long address, + unsigned long error_code, unsigned long newpage) { + struct inode * inode; struct task_struct ** p; - - if (!inode || inode->i_count < 2 || !area->vm_ops) - return 0; + unsigned long offset; + unsigned long from_address; + unsigned long give_page; + + if (!area || !(inode = area->vm_inode) || inode->i_count < 2) + return 0; + /* do we need to copy or can we just share? */ + give_page = 0; + if ((area->vm_page_prot & PAGE_COW) && (error_code & PAGE_RW)) { + if (!newpage) + return 0; + give_page = newpage; + } + offset = address - area->vm_start + area->vm_offset; for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) { + struct vm_area_struct * mpnt; if (!*p) continue; - if (tsk == *p) + if (area->vm_task == *p) continue; - if (inode != (*p)->executable) { - if(!area) continue; - /* Now see if there is something in the VMM that - we can share pages with */ - if(area){ - struct vm_area_struct * mpnt; - for (mpnt = (*p)->mm->mmap; mpnt; mpnt = mpnt->vm_next) { - if (mpnt->vm_ops == area->vm_ops && - mpnt->vm_inode->i_ino == area->vm_inode->i_ino&& - mpnt->vm_inode->i_dev == area->vm_inode->i_dev){ - if (mpnt->vm_ops->share(mpnt, area, address)) - break; - }; - }; - if (!mpnt) continue; /* Nope. Nuthin here */ - }; - } - if (try_to_share(address,tsk,*p,error_code,newpage)) + /* Now see if there is something in the VMM that + we can share pages with */ + for (mpnt = (*p)->mm->mmap; mpnt; mpnt = mpnt->vm_next) { + /* must be same inode */ + if (mpnt->vm_inode != inode) + continue; + /* offsets must be mutually page-aligned */ + if ((mpnt->vm_offset ^ area->vm_offset) & ~PAGE_MASK) + continue; + /* the other area must actually cover the wanted page.. */ + from_address = offset + mpnt->vm_start - mpnt->vm_offset; + if (from_address < mpnt->vm_start || from_address >= mpnt->vm_end) + continue; + /* .. NOW we can actually try to use the same physical page */ + if (!try_to_share(address, area, from_address, mpnt, give_page)) + continue; + /* free newpage if we never used it.. */ + if (give_page || !newpage) + return 1; + free_page(newpage); return 1; + } } return 0; } @@ -870,13 +885,42 @@ return 0; } -void do_no_page(unsigned long error_code, unsigned long address, - struct task_struct *tsk, unsigned long user_esp) +static void handle_no_page(struct vm_area_struct * vma, + unsigned long address, unsigned long error_code) { - unsigned long tmp; unsigned long page; - struct vm_area_struct * mpnt; + int prot; + + page = get_free_page(GFP_KERNEL); + if (share_page(vma, address, error_code, page)) { + ++vma->vm_task->mm->min_flt; + return; + } + if (!page) { + oom(current); + put_page(vma->vm_task, BAD_PAGE, address, PAGE_PRIVATE); + return; + } + ++vma->vm_task->mm->maj_flt; + ++vma->vm_task->mm->rss; + page = vma->vm_ops->nopage(vma, address, page, error_code); + if (share_page(vma, address, error_code, 0)) + return; + prot = vma->vm_page_prot; + if ((prot & PAGE_COW) && mem_map[MAP_NR(page)] > 1) + prot &= ~PAGE_RW; + if (put_page(vma->vm_task, page, address, prot)) + return; + free_page(page); + oom(current); +} +void do_no_page(unsigned long error_code, unsigned long address, + struct task_struct *tsk) +{ + unsigned long page, tmp; + struct vm_area_struct * vma; + page = get_empty_pgtable(tsk,address); if (!page) return; @@ -891,42 +935,43 @@ swap_in((unsigned long *) page); return; } - address &= 0xfffff000; - tmp = 0; - for (mpnt = tsk->mm->mmap; mpnt != NULL; mpnt = mpnt->vm_next) { - if (address < mpnt->vm_start) + address &= PAGE_MASK; + for (vma = tsk->mm->mmap ; ; vma = vma->vm_next) { + if (!vma) + goto bad_area; + if (vma->vm_end > address) break; - if (address >= mpnt->vm_end) { - tmp = mpnt->vm_end; - continue; - } - if (!mpnt->vm_ops || !mpnt->vm_ops->nopage) { - ++tsk->mm->rss; - ++tsk->mm->min_flt; - get_empty_page(tsk,address); - return; - } + } + if (vma->vm_start <= address) + goto good_area; + if (!(vma->vm_flags & VM_GROWSDOWN)) + goto bad_area; + if (vma->vm_end - address > tsk->rlim[RLIMIT_STACK].rlim_cur) + goto bad_area; + vma->vm_offset -= vma->vm_start - address; + vma->vm_start = address; + +good_area: + if (!vma->vm_ops || !vma->vm_ops->nopage) { ++tsk->mm->rss; - mpnt->vm_ops->nopage(error_code, mpnt, address); + ++tsk->mm->min_flt; + get_empty_page(tsk,address); return; } + handle_no_page(vma, address, error_code); + return; + +bad_area: if (tsk != current) - goto ok_no_page; - if (address >= tsk->mm->end_data && address < tsk->mm->brk) - goto ok_no_page; - if (mpnt && (mpnt->vm_flags & VM_GROWSDOWN) && - address - tmp > mpnt->vm_start - address && - tsk->rlim[RLIMIT_STACK].rlim_cur > mpnt->vm_end - address) { - mpnt->vm_start = address; - goto ok_no_page; - } + goto kernel_needs_bad_page; tsk->tss.cr2 = address; - current->tss.error_code = error_code; - current->tss.trap_no = 14; + tsk->tss.error_code = error_code; + tsk->tss.trap_no = 14; send_sig(SIGSEGV,tsk,1); if (error_code & 4) /* user level access? */ return; -ok_no_page: + +kernel_needs_bad_page: ++tsk->mm->rss; ++tsk->mm->min_flt; get_empty_page(tsk,address); @@ -940,28 +985,25 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) { unsigned long address; - unsigned long user_esp = 0; + unsigned long page; unsigned int bit; /* get the address */ __asm__("movl %%cr2,%0":"=r" (address)); if (address < TASK_SIZE) { - if (error_code & 4) { /* user mode access? */ - if (regs->eflags & VM_MASK) { - bit = (address - 0xA0000) >> PAGE_SHIFT; - if (bit < 32) - current->screen_bitmap |= 1 << bit; - } else - user_esp = regs->esp; + if (regs->eflags & VM_MASK) { + bit = (address - 0xA0000) >> PAGE_SHIFT; + if (bit < 32) + current->screen_bitmap |= 1 << bit; } if (error_code & PAGE_PRESENT) { #ifdef CONFIG_TEST_VERIFY_AREA if (regs->cs == KERNEL_CS) printk("WP fault at %08x\n", regs->eip); #endif - do_wp_page(error_code, address, current, user_esp); + do_wp_page(error_code, address, current); } else { - do_no_page(error_code, address, current, user_esp); + do_no_page(error_code, address, current); } return; } @@ -979,16 +1021,16 @@ printk(KERN_ALERT "Unable to handle kernel paging request"); printk(" at kernel address %08lx\n",address); address += TASK_SIZE; - __asm__("movl %%cr3,%0" : "=r" (user_esp)); + __asm__("movl %%cr3,%0" : "=r" (page)); printk(KERN_ALERT "current->tss.cr3 = %08lx, %%cr3 = %08lx\n", - current->tss.cr3, user_esp); - user_esp = ((unsigned long *) user_esp)[address >> 22]; - printk(KERN_ALERT "*pde = %08lx\n", user_esp); - if (user_esp & PAGE_PRESENT) { - user_esp &= PAGE_MASK; + current->tss.cr3, page); + page = ((unsigned long *) page)[address >> 22]; + printk(KERN_ALERT "*pde = %08lx\n", page); + if (page & PAGE_PRESENT) { + page &= PAGE_MASK; address &= 0x003ff000; - user_esp = ((unsigned long *) user_esp)[address >> PAGE_SHIFT]; - printk(KERN_ALERT "*pte = %08lx\n", user_esp); + page = ((unsigned long *) page)[address >> PAGE_SHIFT]; + printk(KERN_ALERT "*pte = %08lx\n", page); } die_if_kernel("Oops", regs, error_code); do_exit(SIGKILL); @@ -1214,11 +1256,11 @@ /* This handles a generic mmap of a disk file */ -void file_mmap_nopage(int error_code, struct vm_area_struct * area, unsigned long address) +unsigned long file_mmap_nopage(struct vm_area_struct * area, unsigned long address, + unsigned long page, int error_code) { struct inode * inode = area->vm_inode; unsigned int block; - unsigned long page; int nr[8]; int i, j; int prot = area->vm_page_prot; @@ -1227,32 +1269,11 @@ block = address - area->vm_start + area->vm_offset; block >>= inode->i_sb->s_blocksize_bits; - page = get_free_page(GFP_KERNEL); - if (share_page(area, area->vm_task, inode, address, error_code, page)) { - ++area->vm_task->mm->min_flt; - return; - } - - ++area->vm_task->mm->maj_flt; - if (!page) { - oom(current); - put_page(area->vm_task, BAD_PAGE, address, PAGE_PRIVATE); - return; - } for (i=0, j=0; i< PAGE_SIZE ; j++, block++, i += inode->i_sb->s_blocksize) nr[j] = bmap(inode,block); if (error_code & PAGE_RW) prot |= PAGE_RW | PAGE_DIRTY; - page = bread_page(page, inode->i_dev, nr, inode->i_sb->s_blocksize, prot); - - if (!(prot & PAGE_RW)) { - if (share_page(area, area->vm_task, inode, address, error_code, page)) - return; - } - if (put_page(area->vm_task,page,address,prot)) - return; - free_page(page); - oom(current); + return bread_page(page, inode->i_dev, nr, inode->i_sb->s_blocksize, !(error_code & PAGE_RW)); } void file_mmap_free(struct vm_area_struct * area) @@ -1274,16 +1295,6 @@ struct vm_area_struct * area2, unsigned long address) { - if (area1->vm_inode != area2->vm_inode) - return 0; - if (area1->vm_start != area2->vm_start) - return 0; - if (area1->vm_end != area2->vm_end) - return 0; - if (area1->vm_offset != area2->vm_offset) - return 0; - if (area1->vm_page_prot != area2->vm_page_prot) - return 0; return 1; } diff -u --recursive --new-file v1.1.30/linux/mm/swap.c linux/mm/swap.c --- v1.1.30/linux/mm/swap.c Sat May 7 14:54:17 1994 +++ linux/mm/swap.c Mon Jul 18 11:37:07 1994 @@ -869,7 +869,7 @@ val->freeswap = val->totalswap = 0; for (i = 0; i < nr_swapfiles; i++) { - if (!(swap_info[i].flags & SWP_USED)) + if ((swap_info[i].flags & SWP_WRITEOK) != SWP_WRITEOK) continue; for (j = 0; j < swap_info[i].max; ++j) switch (swap_info[i].swap_map[j]) {