summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormarkm <markm@FreeBSD.org>1997-10-31 06:30:22 +0000
committermarkm <markm@FreeBSD.org>1997-10-31 06:30:22 +0000
commitbe4808f6e2badf1629d651d8f1d2f5c7707e47a8 (patch)
tree9a3e498c45ec2bf39c7d1c79c9aa4bab90d109e8
parent17d7551904f5e100c3f914c00c72350a63a49dfa (diff)
downloadFreeBSD-src-be4808f6e2badf1629d651d8f1d2f5c7707e47a8.zip
FreeBSD-src-be4808f6e2badf1629d651d8f1d2f5c7707e47a8.tar.gz
Upgrade the sound sources to Amancio Hasty's latest-and-greatest.
This is based on Voxware 3.5, and corresponds to Amancio's `guspnp21'. Bug reports to Amancio, please!
-rw-r--r--sys/i386/include/soundcard.h601
-rw-r--r--sys/i386/isa/sound/CHANGELOG82
-rw-r--r--sys/i386/isa/sound/README.FREEBSD165
-rw-r--r--sys/i386/isa/sound/Readme248
-rw-r--r--sys/i386/isa/sound/Readme.cards845
-rw-r--r--sys/i386/isa/sound/Readme.modules186
-rw-r--r--sys/i386/isa/sound/Readme.v302
-rw-r--r--sys/i386/isa/sound/ad1848.c2638
-rw-r--r--sys/i386/isa/sound/ad1848_mixer.h38
-rw-r--r--sys/i386/isa/sound/adlib_card.c30
-rw-r--r--sys/i386/isa/sound/aedsp16.c838
-rw-r--r--sys/i386/isa/sound/audio.c713
-rw-r--r--sys/i386/isa/sound/awe_wave.c51
-rw-r--r--sys/i386/isa/sound/cs4232.c206
-rw-r--r--sys/i386/isa/sound/dev_table.c341
-rw-r--r--sys/i386/isa/sound/dev_table.h732
-rw-r--r--sys/i386/isa/sound/dmabuf.c2018
-rw-r--r--sys/i386/isa/sound/gus_card.c225
-rw-r--r--sys/i386/isa/sound/gus_midi.c344
-rw-r--r--sys/i386/isa/sound/gus_vol.c170
-rw-r--r--sys/i386/isa/sound/gus_wave.c6731
-rw-r--r--sys/i386/isa/sound/hex2hex.h2
-rw-r--r--sys/i386/isa/sound/ics2101.c365
-rw-r--r--sys/i386/isa/sound/iwdefs.h712
-rw-r--r--sys/i386/isa/sound/local.h203
-rw-r--r--sys/i386/isa/sound/mad16.c524
-rw-r--r--sys/i386/isa/sound/mad16_sb_midi.c285
-rw-r--r--sys/i386/isa/sound/maui.c225
-rw-r--r--sys/i386/isa/sound/midi_synth.c841
-rw-r--r--sys/i386/isa/sound/midi_synth.h7
-rw-r--r--sys/i386/isa/sound/midibuf.c626
-rw-r--r--sys/i386/isa/sound/mmap_test.c274
-rw-r--r--sys/i386/isa/sound/mpu401.c2284
-rw-r--r--sys/i386/isa/sound/opl3.c1700
-rw-r--r--sys/i386/isa/sound/opl3.h14
-rw-r--r--sys/i386/isa/sound/os.h334
-rw-r--r--sys/i386/isa/sound/pas2_card.c507
-rw-r--r--sys/i386/isa/sound/pas2_midi.c406
-rw-r--r--sys/i386/isa/sound/pas2_mixer.c490
-rw-r--r--sys/i386/isa/sound/pas2_pcm.c612
-rw-r--r--sys/i386/isa/sound/pas_hw.h236
-rw-r--r--sys/i386/isa/sound/patmgr.c321
-rw-r--r--sys/sys/soundcard.h601
43 files changed, 16782 insertions, 11991 deletions
diff --git a/sys/i386/include/soundcard.h b/sys/i386/include/soundcard.h
index b19b190..3b10c5d 100644
--- a/sys/i386/include/soundcard.h
+++ b/sys/i386/include/soundcard.h
@@ -1,3 +1,5 @@
+#ifndef SOUNDCARD_H
+#define SOUNDCARD_H
/*
* Copyright by Hannu Savolainen 1993
*
@@ -33,15 +35,18 @@
* Regards,
* Hannu Savolainen
* hannu@voxware.pp.fi
+ *
+ **********************************************************************
+ * PS. The Hacker's Guide to VoxWare available from
+ * nic.funet.fi:pub/OS/Linux/ALPHA/sound. The file is
+ * snd-sdk-doc-0.1.ps.gz (gzipped postscript). It contains
+ * some useful information about programming with VoxWare.
+ * (NOTE! The pub/OS/Linux/ALPHA/ directories are hidden. You have
+ * to cd inside them before the files are accessible.)
+ **********************************************************************
*/
-#ifndef _MACHINE_SOUNDCARD_H_
-#define _MACHINE_SOUNDCARD_H_
-
#define SOUND_VERSION 301
-#define VOXWARE
-
-#include <sys/ioccom.h>
/*
* Supported card ID numbers (Should be somewhere else?)
@@ -65,43 +70,26 @@
#define SNDCARD_TRXPRO 16
#define SNDCARD_TRXPRO_SB 17
#define SNDCARD_TRXPRO_MPU 18
-#ifdef PC98
-#define SNDCARD_PCM86 19
-#endif
-#define SNDCARD_AWE32 20
+#define SNDCARD_MAD16 19
+#define SNDCARD_MAD16_MPU 20
+#define SNDCARD_CS4232 21
+#define SNDCARD_CS4232_MPU 22
+#define SNDCARD_MAUI 23
+#define SNDCARD_PSEUDO_MSS 24
+#define SNDCARD_AWE32 25
-
-/***********************************
+/*
* IOCTL Commands for /dev/sequencer
*/
#ifndef _IOWR
-/* @(#)ioctlp.h */
-
-/* Ioctl's have the command encoded in the lower word,
- * and the size of any in or out parameters in the upper
- * word. The high 2 bits of the upper word are used
- * to encode the in/out status of the parameter; for now
- * we restrict parameters to at most 128 bytes.
- */
-/* #define IOCTYPE (0xff<<8) */
-#define IOCPARM_MASK 0x7f /* parameters must be < 128 bytes */
-#define IOC_VOID 0x00000000 /* no parameters */
-#define IOC_OUT 0x20000000 /* copy out parameters */
-#define IOC_IN 0x40000000 /* copy in parameters */
-#define IOC_INOUT (IOC_IN|IOC_OUT)
-/* the 0x20000000 is so we can distinguish new ioctl's from old */
-#define _IO(x,y) ((int)(IOC_VOID|(x<<8)|y))
-#define _IOR(x,y,t) ((int)(IOC_OUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y))
-#define _IOW(x,y,t) ((int)(IOC_IN|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y))
-/* this should be _IORW, but stdio got there first */
-#define _IOWR(x,y,t) ((int)(IOC_INOUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y))
+#include <sys/ioccom.h>
#endif /* !_IOWR */
#define SNDCTL_SEQ_RESET _IO ('Q', 0)
#define SNDCTL_SEQ_SYNC _IO ('Q', 1)
#define SNDCTL_SYNTH_INFO _IOWR('Q', 2, struct synth_info)
-#define SNDCTL_SEQ_CTRLRATE _IOWR('Q', 3, int) /* Set/get timer resolution (HZ) */
+#define SNDCTL_SEQ_CTRLRATE _IOWR('Q', 3, int) /* Set/get timer resolution (hz) */
#define SNDCTL_SEQ_GETOUTCOUNT _IOR ('Q', 4, int)
#define SNDCTL_SEQ_GETINCOUNT _IOR ('Q', 5, int)
#define SNDCTL_SEQ_PERCMODE _IOW ('Q', 6, int)
@@ -111,16 +99,17 @@
#define SNDCTL_SEQ_NRSYNTHS _IOR ('Q',10, int)
#define SNDCTL_SEQ_NRMIDIS _IOR ('Q',11, int)
#define SNDCTL_MIDI_INFO _IOWR('Q',12, struct midi_info)
-#define SNDCTL_SEQ_TRESHOLD _IOW ('Q',13, int)
+#define SNDCTL_SEQ_THRESHOLD _IOW ('Q',13, int)
+#define SNDCTL_SEQ_TRESHOLD SNDCTL_SEQ_THRESHOLD /* there was once a typo */
#define SNDCTL_SYNTH_MEMAVL _IOWR('Q',14, int) /* in=dev#, out=memsize */
#define SNDCTL_FM_4OP_ENABLE _IOW ('Q',15, int) /* in=dev# */
#define SNDCTL_PMGR_ACCESS _IOWR('Q',16, struct patmgr_info)
#define SNDCTL_SEQ_PANIC _IO ('Q',17)
#define SNDCTL_SEQ_OUTOFBAND _IOW ('Q',18, struct seq_event_rec)
- struct seq_event_rec {
- unsigned char arr[8];
- };
+struct seq_event_rec {
+ u_char arr[8];
+};
#define SNDCTL_TMR_TIMEBASE _IOWR('T', 1, int)
#define SNDCTL_TMR_START _IO ('T', 2)
@@ -138,20 +127,32 @@
#define SNDCTL_TMR_SELECT _IOW ('T', 8, int)
/*
+ * Endian aware patch key generation algorithm.
+ */
+
+#if defined(_AIX) || defined(AIX)
+# define _PATCHKEY(id) (0xfd00|id)
+#else
+# define _PATCHKEY(id) ((id<<8)|0xfd)
+#endif
+
+/*
* Sample loading mechanism for internal synthesizers (/dev/sequencer)
* The following patch_info structure has been designed to support
* Gravis UltraSound. It tries to be universal format for uploading
- * sample based patches but is probably too limited.
+ * sample based patches but is propably too limited.
*/
struct patch_info {
- short key; /* Use GUS_PATCH here */
-#define GUS_PATCH 0x04fd
-#define OBSOLETE_GUS_PATCH 0x02fd
- short device_no; /* Synthesizer number */
- short instr_no; /* Midi pgm# */
+/* u_short key; Use GUS_PATCH here */
+ short key; /* Use GUS_PATCH here */
+#define GUS_PATCH _PATCHKEY(0x04)
+#define OBSOLETE_GUS_PATCH _PATCHKEY(0x02)
+
+ short device_no; /* Synthesizer number */
+ short instr_no; /* Midi pgm# */
- unsigned long mode;
+ u_long mode;
/*
* The least significant byte has the same format than the GUS .PAT
* files
@@ -170,8 +171,8 @@ struct patch_info {
#define WAVE_SCALE 0x00040000 /* The scaling info is valid */
/* Other bits must be zeroed */
- long len; /* Size of the wave data in bytes */
- long loop_start, loop_end; /* Byte offsets from the beginning */
+ long len; /* Size of the wave data in bytes */
+ long loop_start, loop_end; /* Byte offsets from the beginning */
/*
* The base_freq and base_note fields are used when computing the
@@ -189,18 +190,18 @@ struct patch_info {
* middle A is 440*1000.
*/
- unsigned int base_freq;
- unsigned long base_note;
- unsigned long high_note;
- unsigned long low_note;
- int panning; /* -128=left, 127=right */
- int detuning;
+ u_int base_freq;
+ u_long base_note;
+ u_long high_note;
+ u_long low_note;
+ int panning; /* -128=left, 127=right */
+ int detuning;
/* New fields introduced in version 1.99.5 */
/* Envelope. Enabled by mode bit WAVE_ENVELOPES */
- unsigned char env_rate[ 6 ]; /* GUS HW ramping rate */
- unsigned char env_offset[ 6 ]; /* 255 == 100% */
+ u_char env_rate[ 6 ]; /* GUS HW ramping rate */
+ u_char env_offset[ 6 ]; /* 255 == 100% */
/*
* The tremolo, vibrato and scale info are not supported yet.
@@ -208,30 +209,30 @@ struct patch_info {
* WAVE_SCALE
*/
- unsigned char tremolo_sweep;
- unsigned char tremolo_rate;
- unsigned char tremolo_depth;
-
- unsigned char vibrato_sweep;
- unsigned char vibrato_rate;
- unsigned char vibrato_depth;
+ u_char tremolo_sweep;
+ u_char tremolo_rate;
+ u_char tremolo_depth;
- int scale_frequency;
- unsigned int scale_factor; /* from 0 to 2048 or 0 to 2 */
-
- int volume;
- int spare[4];
- char data[1]; /* The waveform data starts here */
- };
+ u_char vibrato_sweep;
+ u_char vibrato_rate;
+ u_char vibrato_depth;
+ int scale_frequency;
+ u_int scale_factor; /* from 0 to 2048 or 0 to 2 */
+
+ int volume;
+ int spare[4];
+ char data[1]; /* The waveform data starts here */
+};
struct sysex_info {
- short key; /* Use GUS_PATCH here */
-#define SYSEX_PATCH 0x05fd
- short device_no; /* Synthesizer number */
- long len; /* Size of the sysex data in bytes */
- unsigned char data[1]; /* Sysex data starts here */
- };
+ short key; /* Use GUS_PATCH here */
+#define SYSEX_PATCH _PATCHKEY(0x05)
+#define MAUI_PATCH _PATCHKEY(0x06)
+ short device_no; /* Synthesizer number */
+ long len; /* Size of the sysex data in bytes */
+ u_char data[1]; /* Sysex data starts here */
+};
/*
* Patch management interface (/dev/sequencer, /dev/patmgr#)
@@ -260,7 +261,7 @@ struct sysex_info {
*/
struct patmgr_info { /* Note! size must be < 4k since kmalloc() is used */
- unsigned long key; /* Don't worry. Reserved for communication
+ u_long key; /* Don't worry. Reserved for communication
between the patch manager and the driver. */
#define PM_K_EVENT 1 /* Event from the /dev/sequencer driver */
#define PM_K_COMMAND 2 /* Request from a application */
@@ -294,17 +295,17 @@ struct patmgr_info { /* Note! size must be < 4k since kmalloc() is used */
* Commands above 0xffff reserved for device specific use
*/
- long parm1;
- long parm2;
- long parm3;
+ long parm1;
+ long parm2;
+ long parm3;
- union {
- unsigned char data8[4000];
- unsigned short data16[2000];
- unsigned long data32[1000];
+ union {
+ u_char data8[4000];
+ u_short data16[2000];
+ u_long data32[1000];
struct patch_info patch;
- } data;
- };
+ } data;
+};
/*
* When a patch manager daemon is present, it will be informed by the
@@ -389,7 +390,7 @@ struct patmgr_info { /* Note! size must be < 4k since kmalloc() is used */
/* 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 recognized by the driver. */
+/* 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) */
@@ -475,66 +476,66 @@ struct patmgr_info { /* Note! size must be < 4k since kmalloc() is used */
* Record for FM patches
*/
-typedef unsigned char sbi_instr_data[32];
+typedef u_char sbi_instr_data[32];
struct sbi_instrument {
- unsigned short key; /* Initialize to FM_PATCH or OPL3_PATCH */
-#define FM_PATCH 0x01fd
-#define OPL3_PATCH 0x03fd
- short device; /* Synth# (0-4) */
- int channel; /* Program# to be initialized */
- sbi_instr_data operators; /* Register settings for operator cells (.SBI format) */
- };
+ u_short key; /* FM_PATCH or OPL3_PATCH */
+#define FM_PATCH _PATCHKEY(0x01)
+#define OPL3_PATCH _PATCHKEY(0x03)
+ short device; /* Synth# (0-4) */
+ int channel; /* Program# to be initialized */
+ sbi_instr_data operators; /* Reg. settings for operator cells
+ * (.SBI format) */
+};
struct synth_info { /* Read only */
- char name[30];
- int device; /* 0-N. INITIALIZE BEFORE CALLING */
- int synth_type;
+ char name[30];
+ int device; /* 0-N. INITIALIZE BEFORE CALLING */
+ int synth_type;
#define SYNTH_TYPE_FM 0
#define SYNTH_TYPE_SAMPLE 1
#define SYNTH_TYPE_MIDI 2 /* Midi interface */
- int synth_subtype;
+ int synth_subtype;
#define FM_TYPE_ADLIB 0x00
#define FM_TYPE_OPL3 0x01
#define SAMPLE_TYPE_GUS 0x10
-#define SAMPLE_TYPE_AWE32 0x20
- int perc_mode; /* No longer supported */
- int nr_voices;
- int nr_drums; /* Obsolete field */
- int instr_bank_size;
- unsigned long capabilities;
+ int perc_mode; /* No longer supported */
+ int nr_voices;
+ int nr_drums; /* Obsolete field */
+ int instr_bank_size;
+ u_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 */
- };
+ int dummies[19]; /* Reserve space */
+};
struct sound_timer_info {
- char name[30];
- int caps;
- };
+ char name[32];
+ int caps;
+};
#define MIDI_CAP_MPU401 1 /* MPU-401 intelligent mode */
struct midi_info {
- char name[30];
- int device; /* 0-N. INITIALIZE BEFORE CALLING */
- unsigned long capabilities; /* To be defined later */
- int dev_type;
- int dummies[18]; /* Reserve space */
- };
+ char name[30];
+ int device; /* 0-N. INITIALIZE BEFORE CALLING */
+ u_long capabilities; /* To be defined later */
+ int dev_type;
+ int dummies[18]; /* Reserve space */
+};
/********************************************
* ioctl commands for the /dev/midi##
*/
typedef struct {
- unsigned char cmd;
- char nr_args, nr_returns;
- unsigned char data[30];
- } mpu_command_rec;
+ u_char cmd;
+ char nr_args, nr_returns;
+ u_char data[30];
+} mpu_command_rec;
#define SNDCTL_MIDI_PRETIME _IOWR('m', 0, int)
#define SNDCTL_MIDI_MPUMODE _IOWR('m', 1, int)
@@ -549,7 +550,7 @@ typedef struct {
#define SNDCTL_DSP_SPEED _IOWR('P', 2, int)
#define SNDCTL_DSP_STEREO _IOWR('P', 3, int)
#define SNDCTL_DSP_GETBLKSIZE _IOR('P', 4, int)
-#define SNDCTL_DSP_SETBLKSIZE _IOW('P', 4, int)
+#define SNDCTL_DSP_SETBLKSIZE _IOW('P', 4, int)
#define SNDCTL_DSP_SAMPLESIZE SNDCTL_DSP_SETFMT
#define SOUND_PCM_WRITE_CHANNELS _IOWR('P', 6, int)
#define SOUND_PCM_WRITE_FILTER _IOWR('P', 7, int)
@@ -557,6 +558,7 @@ typedef struct {
#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*/
@@ -576,17 +578,59 @@ typedef struct {
* Buffer status queries.
*/
typedef struct audio_buf_info {
- int fragments; /* # of available fragments (partially usend ones not counted) */
- int fragstotal; /* Total # of fragments allocated */
- int fragsize; /* Size of a fragment in bytes */
+ int fragments; /* # of available fragments (partially used
+ * ones not counted) */
+ int fragstotal; /* Total # of fragments allocated */
+ int fragsize; /* Size of a fragment in bytes */
- int bytes; /* Available space in bytes (includes partially used fragments) */
- /* Note! 'bytes' could be more than fragments*fragsize */
- } audio_buf_info;
+ int bytes; /* Available space in bytes (includes
+ * partially used fragments) */
+ /* Note! 'bytes' could be more than fragments*fragsize */
+} audio_buf_info;
#define SNDCTL_DSP_GETOSPACE _IOR ('P',12, audio_buf_info)
#define SNDCTL_DSP_GETISPACE _IOR ('P',13, audio_buf_info)
#define SNDCTL_DSP_NONBLOCK _IO ('P',14)
+#define SNDCTL_DSP_GETCAPS _IOR ('P',15, int)
+#define DSP_CAP_REVISION 0x000000ff /* Bits for revision level (0 to 255) */
+#define DSP_CAP_DUPLEX 0x00000100 /* Full duplex record/playback */
+#define DSP_CAP_REALTIME 0x00000200 /* Real time capability */
+#define DSP_CAP_BATCH 0x00000400 /* Device has some kind of */
+
+/* internal buffers which may */
+/* cause some delays and */
+/* decrease precision of timing */
+# define DSP_CAP_COPROC 0x00000800 /* Has a coprocessor */
+/* Sometimes it's a DSP */
+/* but usually not */
+# define DSP_CAP_TRIGGER 0x00001000 /* Supports SETTRIGGER */
+# define DSP_CAP_MMAP 0x00002000 /* Supports mmap() */
+
+
+
+#define SNDCTL_DSP_GETCAPS _IOR ('P',15, int)
+#define SNDCTL_DSP_GETTRIGGER _IOR ('P',16, int)
+#define SNDCTL_DSP_SETTRIGGER _IOW ('P',16, int)
+#define PCM_ENABLE_INPUT 0x00000001
+#define PCM_ENABLE_OUTPUT 0x00000002
+
+typedef struct count_info {
+ int bytes; /* Total # of bytes processed */
+ int blocks; /* # of fragment transitions since last time */
+ int ptr; /* Current DMA pointer value */
+} count_info;
+
+#define SNDCTL_DSP_GETIPTR _IOR ('P',17, count_info)
+#define SNDCTL_DSP_GETOPTR _IOR ('P',18, count_info)
+
+typedef struct buffmem_desc {
+ caddr_t buffer;
+ int size;
+} buffmem_desc;
+
+#define SNDCTL_DSP_MAPINBUF _IOR ('P', 19, buffmem_desc)
+#define SNDCTL_DSP_MAPOUTBUF _IOR ('P', 20, buffmem_desc)
+#define SNDCTL_DSP_SETSYNCRO _IO ('P', 21)
#define SOUND_PCM_READ_RATE _IOR ('P', 2, int)
#define SOUND_PCM_READ_CHANNELS _IOR ('P', 6, int)
@@ -606,6 +650,14 @@ typedef struct audio_buf_info {
#define SOUND_PCM_GETOSPACE SNDCTL_DSP_GETOSPACE
#define SOUND_PCM_GETISPACE SNDCTL_DSP_GETISPACE
#define SOUND_PCM_NONBLOCK SNDCTL_DSP_NONBLOCK
+#define SOUND_PCM_GETCAPS SNDCTL_DSP_GETCAPS
+#define SOUND_PCM_GETTRIGGER SNDCTL_DSP_GETTRIGGER
+#define SOUND_PCM_SETTRIGGER SNDCTL_DSP_SETTRIGGER
+#define SOUND_PCM_SETSYNCRO SNDCTL_DSP_SETSYNCRO
+#define SOUND_PCM_GETIPTR SNDCTL_DSP_GETIPTR
+#define SOUND_PCM_GETOPTR SNDCTL_DSP_GETOPTR
+#define SOUND_PCM_MAPINBUF SNDCTL_DSP_MAPINBUF
+#define SOUND_PCM_MAPOUTBUF SNDCTL_DSP_MAPOUTBUF
/*
* ioctl calls to be used in communication with coprocessors and
@@ -613,29 +665,29 @@ typedef struct audio_buf_info {
*/
typedef struct copr_buffer {
- int command; /* Set to 0 if not used */
- int flags;
+ int command; /* Set to 0 if not used */
+ int flags;
#define CPF_NONE 0x0000
#define CPF_FIRST 0x0001 /* First block */
#define CPF_LAST 0x0002 /* Last block */
- int len;
- int offs; /* If required by the device (0 if not used) */
+ int len;
+ int offs; /* If required by the device (0 if not used) */
- unsigned char data[4000]; /* NOTE! 4000 is not 4k */
- } copr_buffer;
+ u_char data[4000]; /* NOTE! 4000 is not 4k */
+} copr_buffer;
typedef struct copr_debug_buf {
- int command; /* Used internally. Set to 0 */
- int parm1;
- int parm2;
- int flags;
- int len; /* Length of data in bytes */
- } copr_debug_buf;
+ int command; /* Used internally. Set to 0 */
+ int parm1;
+ int parm2;
+ int flags;
+ int len; /* Length of data in bytes */
+} copr_debug_buf;
typedef struct copr_msg {
- int len;
- unsigned char data[4000];
- } copr_msg;
+ int len;
+ u_char data[4000];
+} copr_msg;
#define SNDCTL_COPR_RESET _IO ('C', 0)
#define SNDCTL_COPR_LOAD _IOWR('C', 1, copr_buffer)
@@ -679,7 +731,7 @@ typedef struct copr_msg {
/*
* The AD1848 codec and compatibles have three line level inputs
* (line, aux1 and aux2). Since each card manufacturer have assigned
- * different meanings to these inputs, it's impractical to assign
+ * different meanings to these inputs, it's inpractical to assign
* specific meanings (line, cd, synth etc.) to them.
*/
#define SOUND_MIXER_LINE1 14 /* Input source 1 (aux1) */
@@ -696,21 +748,23 @@ typedef struct copr_msg {
/* Note! Number 31 cannot be used since the sign bit is reserved */
-#define SOUND_DEVICE_LABELS {"Vol ", "Bass ", "Trebl", "Synth", "Pcm ", "Spkr ", "Line ", \
- "Mic ", "CD ", "Mix ", "Pcm2 ", "Rec ", "IGain", "OGain", \
- "Line1", "Line2", "Line3"}
+#define SOUND_DEVICE_LABELS { \
+ "Vol ", "Bass ", "Trebl", "Synth", "Pcm ", "Spkr ", "Line ", \
+ "Mic ", "CD ", "Mix ", "Pcm2 ", "Rec ", "IGain", "OGain", \
+ "Line1", "Line2", "Line3"}
-#define SOUND_DEVICE_NAMES {"vol", "bass", "treble", "synth", "pcm", "speaker", "line", \
- "mic", "cd", "mix", "pcm2", "rec", "igain", "ogain", \
- "line1", "line2", "line3"}
+#define SOUND_DEVICE_NAMES { \
+ "vol", "bass", "treble", "synth", "pcm", "speaker", "line", \
+ "mic", "cd", "mix", "pcm2", "rec", "igain", "ogain", \
+ "line1", "line2", "line3"}
/* Device bitmask identifiers */
-#define SOUND_MIXER_RECSRC 0xff /* Arg contains a bit for each recording source */
-#define SOUND_MIXER_DEVMASK 0xfe /* Arg contains a bit for each supported device */
-#define SOUND_MIXER_RECMASK 0xfd /* Arg contains a bit for each supported recording source */
+#define SOUND_MIXER_RECSRC 0xff /* 1 bit per recording source */
+#define SOUND_MIXER_DEVMASK 0xfe /* 1 bit per supported device */
+#define SOUND_MIXER_RECMASK 0xfd /* 1 bit per supp. recording source */
#define SOUND_MIXER_CAPS 0xfc
- #define SOUND_CAP_EXCL_INPUT 0x00000001 /* Only one recording source at a time */
+#define SOUND_CAP_EXCL_INPUT 0x00000001 /* Only 1 rec. src at a time */
#define SOUND_MIXER_STEREODEVS 0xfb /* Mixer channels supporting stereo */
/* Device mask bits */
@@ -811,6 +865,7 @@ typedef struct copr_msg {
#define EV_TIMING 0x81
#define EV_CHN_COMMON 0x92
#define EV_CHN_VOICE 0x93
+#define EV_SYSEX 0x94
/*
* Event types 200 to 220 are reserved for application use.
* These numbers will not be used by the driver.
@@ -849,6 +904,11 @@ typedef struct copr_msg {
#define TMR_SPP 10 /* Song position pointer */
#define TMR_TIMESIG 11 /* Time signature */
+/*
+ * Local event types
+ */
+#define LOCL_STARTAUDIO 1
+
#if (!defined(__KERNEL__) && !defined(KERNEL) && !defined(INKERNEL) && !defined(_KERNEL)) || defined(USE_SEQ_MACROS)
/*
* Some convenience macros to simplify programming of the
@@ -879,11 +939,16 @@ void seqbuf_dump(void); /* This function must be provided by programs */
* }
*/
-#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_DEFINEBUF(len) \
+ u_char _seqbuf[len]; int _seqbuflen = len;int _seqbufptr = 0
+#define SEQ_USE_EXTBUF() \
+ extern u_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_NEEDBUF(len) \
+ if ((_seqbufptr+(len)) > _seqbuflen) \
+ seqbuf_dump()
#define _SEQ_ADVBUF(len) _seqbufptr += len
#define SEQ_DUMPBUF seqbuf_dump
#else
@@ -894,7 +959,7 @@ void seqbuf_dump(void); /* This function must be provided by programs */
* The program using the macro library must define the following macros before
* using this library.
*
- * #define _seqbuf name of the buffer (unsigned char[])
+ * #define _seqbuf name of the buffer (u_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.
@@ -904,41 +969,44 @@ void seqbuf_dump(void); /* This function must be provided by programs */
#define _SEQ_NEEDBUF(len) /* empty */
#endif
-#define PM_LOAD_PATCH(dev, bank, pgm) (SEQ_DUMPBUF(), _pm_info.command = _PM_LOAD_PATCH, \
- _pm_info.device=dev, _pm_info.data.data8[0]=pgm, \
- _pm_info.parm1 = bank, _pm_info.parm2 = 1, \
- ioctl(seqfd, SNDCTL_PMGR_ACCESS, &_pm_info))
-#define PM_LOAD_PATCHES(dev, bank, pgm) (SEQ_DUMPBUF(), _pm_info.command = _PM_LOAD_PATCH, \
- _pm_info.device=dev, memcpy(_pm_info.data.data8, pgm, 128), \
- _pm_info.parm1 = bank, _pm_info.parm2 = 128, \
- ioctl(seqfd, SNDCTL_PMGR_ACCESS, &_pm_info))
-
-#define SEQ_VOLUME_MODE(dev, mode) {_SEQ_NEEDBUF(8);\
- _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
- _seqbuf[_seqbufptr+1] = SEQ_VOLMODE;\
- _seqbuf[_seqbufptr+2] = (dev);\
- _seqbuf[_seqbufptr+3] = (mode);\
- _seqbuf[_seqbufptr+4] = 0;\
- _seqbuf[_seqbufptr+5] = 0;\
- _seqbuf[_seqbufptr+6] = 0;\
- _seqbuf[_seqbufptr+7] = 0;\
- _SEQ_ADVBUF(8);}
+#define PM_LOAD_PATCH(dev, bank, pgm) \
+ (SEQ_DUMPBUF(), _pm_info.command = _PM_LOAD_PATCH, \
+ _pm_info.device=dev, _pm_info.data.data8[0]=pgm, \
+ _pm_info.parm1 = bank, _pm_info.parm2 = 1, \
+ ioctl(seqfd, SNDCTL_PMGR_ACCESS, &_pm_info))
+#define PM_LOAD_PATCHES(dev, bank, pgm) \
+ (SEQ_DUMPBUF(), _pm_info.command = _PM_LOAD_PATCH, \
+ _pm_info.device=dev, bcopy( pgm, _pm_info.data.data8, 128), \
+ _pm_info.parm1 = bank, _pm_info.parm2 = 128, \
+ ioctl(seqfd, SNDCTL_PMGR_ACCESS, &_pm_info))
+
+#define SEQ_VOLUME_MODE(dev, mode) { \
+ _SEQ_NEEDBUF(8);\
+ _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
+ _seqbuf[_seqbufptr+1] = SEQ_VOLMODE;\
+ _seqbuf[_seqbufptr+2] = (dev);\
+ _seqbuf[_seqbufptr+3] = (mode);\
+ _seqbuf[_seqbufptr+4] = 0;\
+ _seqbuf[_seqbufptr+5] = 0;\
+ _seqbuf[_seqbufptr+6] = 0;\
+ _seqbuf[_seqbufptr+7] = 0;\
+ _SEQ_ADVBUF(8);}
/*
* Midi voice messages
*/
-#define _CHN_VOICE(dev, event, chn, note, parm) \
- {_SEQ_NEEDBUF(8);\
- _seqbuf[_seqbufptr] = EV_CHN_VOICE;\
- _seqbuf[_seqbufptr+1] = (dev);\
- _seqbuf[_seqbufptr+2] = (event);\
- _seqbuf[_seqbufptr+3] = (chn);\
- _seqbuf[_seqbufptr+4] = (note);\
- _seqbuf[_seqbufptr+5] = (parm);\
- _seqbuf[_seqbufptr+6] = (0);\
- _seqbuf[_seqbufptr+7] = 0;\
- _SEQ_ADVBUF(8);}
+#define _CHN_VOICE(dev, event, chn, note, parm) { \
+ _SEQ_NEEDBUF(8);\
+ _seqbuf[_seqbufptr] = EV_CHN_VOICE;\
+ _seqbuf[_seqbufptr+1] = (dev);\
+ _seqbuf[_seqbufptr+2] = (event);\
+ _seqbuf[_seqbufptr+3] = (chn);\
+ _seqbuf[_seqbufptr+4] = (note);\
+ _seqbuf[_seqbufptr+5] = (parm);\
+ _seqbuf[_seqbufptr+6] = (0);\
+ _seqbuf[_seqbufptr+7] = 0;\
+ _SEQ_ADVBUF(8);}
#define SEQ_START_NOTE(dev, chn, note, vol) \
_CHN_VOICE(dev, MIDI_NOTEON, chn, note, vol)
@@ -953,72 +1021,92 @@ void seqbuf_dump(void); /* This function must be provided by programs */
* 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 _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);}
+/*
+ * SEQ_SYSEX permits sending of sysex messages. (It may look that it permits
+ * sending any MIDI bytes but it's absolutely not possible. Trying to do
+ * so _will_ cause problems with MPU401 intelligent mode).
+ *
+ * Sysex messages are sent in blocks of 1 to 6 bytes. Longer messages must be
+ * sent by calling SEQ_SYSEX() several times (there must be no other events
+ * between them). First sysex fragment must have 0xf0 in the first byte
+ * and the last byte (buf[len-1] of the last fragment must be 0xf7. No byte
+ * between these sysex start and end markers cannot be larger than 0x7f. Also
+ * lengths of each fragments (except the last one) must be 6.
+ *
+ * Breaking the above rules may work with some MIDI ports but is likely to
+ * cause fatal problems with some other devices (such as MPU401).
+ */
+#define SEQ_SYSEX(dev, buf, len) { \
+ int i, l=(len); if (l>6)l=6;\
+ _SEQ_NEEDBUF(8);\
+ _seqbuf[_seqbufptr] = EV_SYSEX;\
+ for(i=0;i<l;i++)_seqbuf[_seqbufptr+i+1] = (buf)[i];\
+ for(i=l;i<6;i++)_seqbuf[_seqbufptr+i+1] = 0xff;\
+ _SEQ_ADVBUF(8);}
#define SEQ_CHN_PRESSURE(dev, chn, pressure) \
- _CHN_COMMON(dev, MIDI_CHN_PRESSURE, chn, pressure, 0, 0)
+ _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)
+ _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)
+ _CHN_COMMON(dev, MIDI_CTL_CHANGE, chn, controller, 0, value)
#define SEQ_BENDER(dev, chn, value) \
- _CHN_COMMON(dev, MIDI_PITCH_BEND, chn, 0, 0, value)
-
-
-#define SEQ_V2_X_CONTROL(dev, voice, controller, value) {_SEQ_NEEDBUF(8);\
- _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
- _seqbuf[_seqbufptr+1] = SEQ_CONTROLLER;\
- _seqbuf[_seqbufptr+2] = (dev);\
- _seqbuf[_seqbufptr+3] = (voice);\
- _seqbuf[_seqbufptr+4] = (controller);\
- *(short *)&_seqbuf[_seqbufptr+5] = (value);\
- _seqbuf[_seqbufptr+7] = 0;\
- _SEQ_ADVBUF(8);}
+ _CHN_COMMON(dev, MIDI_PITCH_BEND, chn, 0, 0, value)
+
+
+#define SEQ_V2_X_CONTROL(dev, voice, controller, value) { \
+ _SEQ_NEEDBUF(8);\
+ _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
+ _seqbuf[_seqbufptr+1] = SEQ_CONTROLLER;\
+ _seqbuf[_seqbufptr+2] = (dev);\
+ _seqbuf[_seqbufptr+3] = (voice);\
+ _seqbuf[_seqbufptr+4] = (controller);\
+ *(short *)&_seqbuf[_seqbufptr+5] = (value);\
+ _seqbuf[_seqbufptr+7] = 0;\
+ _SEQ_ADVBUF(8);}
+
/*
* The following 5 macros are incorrectly implemented and obsolete.
* Use SEQ_BENDER and SEQ_CONTROL (with proper controller) instead.
*/
-#define SEQ_PITCHBEND(dev, voice, value) SEQ_V2_X_CONTROL(dev, voice, CTRL_PITCH_BENDER, value)
-#define SEQ_BENDER_RANGE(dev, voice, value) SEQ_V2_X_CONTROL(dev, voice, CTRL_PITCH_BENDER_RANGE, value)
-#define SEQ_EXPRESSION(dev, voice, value) SEQ_CONTROL(dev, voice, CTL_EXPRESSION, value*128)
-#define SEQ_MAIN_VOLUME(dev, voice, value) SEQ_CONTROL(dev, voice, CTL_MAIN_VOLUME, (value*16383)/100)
-#define SEQ_PANNING(dev, voice, pos) SEQ_CONTROL(dev, voice, CTL_PAN, (pos+128) / 2)
-#if 0
-#define SEQ_PANNING(dev, voice, pos) {_SEQ_NEEDBUF(8);\
- _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
- _seqbuf[_seqbufptr+1] = SEQ_BALANCE;\
- _seqbuf[_seqbufptr+2] = (dev);\
- _seqbuf[_seqbufptr+3] = (voice);\
- (char)_seqbuf[_seqbufptr+4] = (pos);\
- _seqbuf[_seqbufptr+5] = 0;\
- _seqbuf[_seqbufptr+6] = 0;\
- _seqbuf[_seqbufptr+7] = 1;\
- _SEQ_ADVBUF(8);}
-#endif
+
+#define SEQ_PITCHBEND(dev, voice, value) \
+ SEQ_V2_X_CONTROL(dev, voice, CTRL_PITCH_BENDER, value)
+#define SEQ_BENDER_RANGE(dev, voice, value) \
+ SEQ_V2_X_CONTROL(dev, voice, CTRL_PITCH_BENDER_RANGE, value)
+#define SEQ_EXPRESSION(dev, voice, value) \
+ SEQ_CONTROL(dev, voice, CTL_EXPRESSION, value*128)
+#define SEQ_MAIN_VOLUME(dev, voice, value) \
+ SEQ_CONTROL(dev, voice, CTL_MAIN_VOLUME, (value*16383)/100)
+#define SEQ_PANNING(dev, voice, pos) \
+ SEQ_CONTROL(dev, voice, CTL_PAN, (pos+128) / 2)
/*
- * Timing and synchronization macros
+ * Timing and syncronization macros
*/
-#define _TIMER_EVENT(ev, parm) {_SEQ_NEEDBUF(8);\
- _seqbuf[_seqbufptr+0] = EV_TIMING; \
- _seqbuf[_seqbufptr+1] = (ev); \
- _seqbuf[_seqbufptr+2] = 0;\
- _seqbuf[_seqbufptr+3] = 0;\
- *(unsigned int *)&_seqbuf[_seqbufptr+4] = (parm); \
- _SEQ_ADVBUF(8);}
+#define _TIMER_EVENT(ev, parm) { \
+ _SEQ_NEEDBUF(8);\
+ _seqbuf[_seqbufptr+0] = EV_TIMING; \
+ _seqbuf[_seqbufptr+1] = (ev); \
+ _seqbuf[_seqbufptr+2] = 0;\
+ _seqbuf[_seqbufptr+3] = 0;\
+ *(u_int *)&_seqbuf[_seqbufptr+4] = (parm); \
+ _SEQ_ADVBUF(8); \
+ }
#define SEQ_START_TIMER() _TIMER_EVENT(TMR_START, 0)
#define SEQ_STOP_TIMER() _TIMER_EVENT(TMR_STOP, 0)
@@ -1031,24 +1119,43 @@ void seqbuf_dump(void); /* This function must be provided by programs */
#define SEQ_TIME_SIGNATURE(sig) _TIMER_EVENT(TMR_TIMESIG, sig)
/*
+ * Local control events
+ */
+
+#define _LOCAL_EVENT(ev, parm) { \
+ _SEQ_NEEDBUF(8);\
+ _seqbuf[_seqbufptr+0] = EV_SEQ_LOCAL; \
+ _seqbuf[_seqbufptr+1] = (ev); \
+ _seqbuf[_seqbufptr+2] = 0;\
+ _seqbuf[_seqbufptr+3] = 0;\
+ *(u_int *)&_seqbuf[_seqbufptr+4] = (parm); \
+ _SEQ_ADVBUF(8); \
+ }
+
+#define SEQ_PLAYAUDIO(devmask) _LOCAL_EVENT(LOCL_STARTAUDIO, devmask)
+/*
* 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_MIDIOUT(device, byte) { \
+ _SEQ_NEEDBUF(4);\
+ _seqbuf[_seqbufptr] = SEQ_MIDIPUTC;\
+ _seqbuf[_seqbufptr+1] = (byte);\
+ _seqbuf[_seqbufptr+2] = (device);\
+ _seqbuf[_seqbufptr+3] = 0;\
+ _SEQ_ADVBUF(4);}
/*
* Patch loading.
*/
-#define SEQ_WRPATCH(patchx, len) {if (_seqbufptr) seqbuf_dump();\
- if (write(seqfd, (char*)(patchx), len)==-1) \
- perror("Write patch: /dev/sequencer");}
-#define SEQ_WRPATCH2(patchx, len) (seqbuf_dump(), write(seqfd, (char*)(patchx), len))
+#define SEQ_WRPATCH(patchx, len) { \
+ if (_seqbufptr) seqbuf_dump(); \
+ if (write(seqfd, (char*)(patchx), len)==-1) \
+ perror("Write patch: /dev/sequencer"); \
+ }
-#endif /* !KERNEL_SPAM */
+#define SEQ_WRPATCH2(patchx, len) \
+ ( seqbuf_dump(), write(seqfd, (char*)(patchx), len) )
-#endif /* !_MACHINE_SOUNDCARD_H_ */
+#endif
+#endif
diff --git a/sys/i386/isa/sound/CHANGELOG b/sys/i386/isa/sound/CHANGELOG
index e21dfaa..878e2b7 100644
--- a/sys/i386/isa/sound/CHANGELOG
+++ b/sys/i386/isa/sound/CHANGELOG
@@ -1,5 +1,83 @@
-Changelog for version 3.0-950506
-------------------------------------
+Changelog for version 3.5-alpha7
+--------------------------------
+
+Since 3.5-alpha6
+- Changed all #ifndef EXCLUDE_xx stuff to #ifdef CONFIG_xx. Modified
+configure to handle this.
+- Removed initialization messages from the
+modularized version. They can be enabled by using init_trace=1 in
+the insmod command line (insmod sound init_trace=1).
+- More AIX stuff.
+- Added support for syncronizing dsp/audio devices with /dev/sequencer.
+- mmap() support for dsp/audio devices.
+
+Since 3.5-alpha5
+- AIX port.
+- Changed some xxx_PATCH macros in soundcard.h to work with
+ big endian machines.
+
+Since 3.5-alpha4
+- Removed the 'setfx' stuff from the version distributed with kernel
+ sources.
+
+Since 3.5-alpha3
+- Moved stuff from the 'setfx' program to the AudioTriX Pro driver.
+
+Since 3.5-alpha2
+- Modifications to makefile and configure.c. Unnecessary sources
+ are no longer compiled. Newly created local.h is also copied to
+ /etc/soundconf. "make oldconfig" reads /etc/soundconf and produces
+ new local.h which is compatible with current version of the driver.
+- Some fixes to the SB16 support.
+- Fixed random protection fault in gus_wave.c
+
+Since 3.5-alpha1
+- Modified to work with Linux-1.3.33 and leater
+- Some minor changes
+
+Since 3.0.2
+- Support for CS4232 based PnP cards (AcerMagic S23 etc).
+- Full duplex support for some CS4231, CS4232 and AD1845 based cards
+(GUA MAX, AudioTrix Pro, AcerMagic S23 and many MAD16/Mozart cards
+having a codec mentioned above).
+- Almost fully rewritten loadable modules support.
+- Fixed some bugs.
+- Huge amount of testing (more testing is still required).
+- mmap() support (works with some cards). Requires much more testing.
+- Sample/patch/program loading for TB Maui/Tropez. No initialization
+since TB doesn't allow me to release that code.
+- Using CS4231 compatible codecs as timer for /dev/music.
+
+Since 3.0.1
+- Added allocation of I/O ports, DMA channels and interrupts
+to the initialization code. This may break modules support since
+the driver may not free some resources on unload. Should be fixed soon.
+
+Since 3.0
+- Some important bug fixes.
+- select() for /dev/dsp and /dev/audio (Linux only).
+(To use select() with read, you have to call read() to start
+the recording. Calling write() kills recording immediately so
+use select() carefully when you are writing a half duplex app.
+Full duplex mode is not implemented yet.) Select works also with
+/dev/sequencer and /dev/music. Maybe with /dev/midi## too.
+
+Since 3.0-beta2
+- Minor fixes.
+- Added Readme.cards
+
+Since 3.0-beta1
+- Minor fixes to the modules support.
+- Eliminated call to sb_free_irq() in ad1848.c
+- Rewritten MAD16&Mozart support (not tested with MAD16 Pro).
+- Fix to DMA initialization of PSS cards.
+- Some fixes to ad1848/cs42xx mixer support (GUS MAX, MSS, etc.)
+- Fixed some bugs in the PSS driver which caused I/O errors with
+ the MSS mode (/dev/dsp).
+
+Since 3.0-950506
+- Recording with GUS MAX fixed. It works when the driver is configured
+ to use two DMA channels with GUS MAX (16 bit ones recommended).
Since 3.0-94xxxx
- Too many changes
diff --git a/sys/i386/isa/sound/README.FREEBSD b/sys/i386/isa/sound/README.FREEBSD
new file mode 100644
index 0000000..3603bfe
--- /dev/null
+++ b/sys/i386/isa/sound/README.FREEBSD
@@ -0,0 +1,165 @@
+GUSPNP15 8/6//97
+ftp://rah.star-gate.com/pub/guspnp.tar.gz
+
+This sound driver is for FreeBSD 3.0-current .
+
+
+Major enhancement we now support mapping the dma buffer to user
+space for write operations only. This features is useful for
+games like xquake . So far the mmap features seems to work
+with the GUS PnP Pro and with the SB16.
+
+For xquake you will need:
+
+1. a few mods to the linux loadable module so just download it and
+ replace yours:
+cd /sys/i386/
+tar -xzf linux_ioctl.tar.gz
+cd /usr/src/lkm/linux
+make
+make install
+modunload -i 0 (if you have the linux up and running)
+linux
+ftp://rah.star-gate.com/linux_ioctl.tar.gz
+
+2. Install the linux lib 2.4 package:
+pkg_add linux_lib-2.4.tgz
+
+ftp://ftp.freebsd.org/pub/FreeBSD/packages-current/emulators/linux_lib-2.4.tgz
+
+If you don't have xquake you can get it from:
+
+3. ftp://ftp.freebsd.org/pub/idgames/idstuff/unsup/intel_linux_quake101.tgz
+
+
+A simple test program mmap_test.c is provided in the sound driver directory.
+So copy it to your home directory or favorite place and compile it.
+cc -o mmap_test mmap_test.c
+
+record a sample session:
+cat /dev/dsp >smpl
+
+now run mmap_test . You will hear a loud pop thats a test program
+then the sample stream will loop .
+
+
+Phew, now back to sound driver land 8)
+
+
+This is a minor sound driver release for the GUS PnP Pro , GUS MAX,
+AudioTrix Pro , SB16 and SB16 PnP. There is also an experimental
+AWE sub model.
+
+Included Luigi's clean up work . Tnks!
+
+Randall Hopper's SB16 speed setting fix . Tnks!
+
+Fixed signal handling throught out the sound driver. The problem
+first surfaced with the SB16 not generating an interrupt on the
+last dma request and SB afficionados quickly pointed out the
+bug in the driver. I had to put back the auto dma feature for
+xquake :(
+
+
+NOTE YOU DON'T NEED THE PNP DRIVER FOR THE GUS PNP SINCE THE DRIVER
+HAS BUILTIN PNP SUPPORT FOR THE GUS.
+
+My P133 Bios supports PnP. To first figured out what my SB16 PnP
+was being configured to I booted win95 and checked out what Win95
+ended up with . Alternatively, if you want to you can also down
+load Sujal Patel's PnP driver:
+
+ ftp://rah.start-gate.com/pub/FreeBSD-ISA_PnP_June8.tar.gz
+
+follow the instructions on how to configure your PnP soundcard or
+ISA device.
+Lugi also has Sujal's PnP driver .
+
+
+---
+
+ http://www.iet.unipi.it/~luigi/pnp.c
+ http://www.iet.unipi.it/~luigi/pnp.h
+
+ the two main files. Follow Sujal Patel's instructions
+ for installing pnp support.
+
+ http://www.iet.unipi.it/~luigi/pnpinfo.tgz
+---
+
+This is my kernel configuration for my SB16 PnP:
+
+controller snd0
+device sb0 at isa? port 0x220 irq 10 conflicts drq 3 vector sbintr
+device sbxvi0 at isa? port? irq? drq 5 conflicts
+device opl0 at isa? port 0x388 conflicts
+device sbmidi0 at isa? port 0x300 irq? conflicts
+
+----
+
+
+The difference between a GUS PnP and a GUS PnP PRO is that the Pro
+comes with 512kb. I went out an got a 1mb 60ns 30pin simm and installed
+it on my GUS PnP. I own a GUS PnP and a GUS PnP PRO.
+
+
+To unpack:
+cd /
+mv /sys/i386/isa/sound /sys/i386/isa/sound.old
+cd /sys/i386/isa/
+tar -xzf guspnp15.tar.gz
+
+
+cd /sys/i386/conf
+Edit the kernel config file in /sys/i386/conf
+
+IF YOU HAVE A GUS MAX or GUS add the option NOGUSPNP to the config file
+ OPTIONS NOGUSPNP
+ THEN follow the instructions for NONPNP CONFIGURATION
+
+
+PNP CONFIGURATION
+To configure your guspnp PRO if you have a motherboard which supports
+PnP:
+
+ controller snd0
+ device gus0 at isa? vector gusintr
+
+NONPNP CONFIGURATION
+To configure your guspnp PRO if your motherboard does NOT support
+PnP:
+
+device gus0 at isa? port 0x220 irq 11 drq 1 flags 0x3 vector gusintr
+
+
+the gus pnp is fully software configurable and the above configuration
+is setup for full duplex audio. The dma channel settings are:
+
+drq 1 --- DMA channel for playback
+
+flags 0x3 --- DMAN channel for recording
+
+In the event that you have to configure a GUS PnP manually or a GUS MAX:
+
+ Available IRQs for the GUS are:
+ 3, 5, 7, 9, 11, 12, 15
+
+ Available DMA channels for the GUS are:
+ 1, 3, 5, 6, 7
+
+
+config <kernel-file>
+cd /sys/compile/<kernel-file>
+make
+make install
+
+THERE IS NO NEED TO BOOT TO DOS TO CONFIGURE YOUR GUS PNP.
+THE DRIVER HAS BUILTIN SUPPORT FOR PNP WHICH I GOT
+FROM THE GRAVIS DRIVER DEVELOPMENT KIT
+
+Many thanks to Brian Litzinger <brian@MediaCity.com> for
+porting the sound driver 3.5 to 2.2-current. Well, thats a while
+ago hence the reference to 2.2.
+
+ Have fun,
+ Amancio
diff --git a/sys/i386/isa/sound/Readme b/sys/i386/isa/sound/Readme
new file mode 100644
index 0000000..2594143
--- /dev/null
+++ b/sys/i386/isa/sound/Readme
@@ -0,0 +1,248 @@
+
+VoxWare v3.5-alpha5 release notes
+---------------------------------
+
+IMPORTANT! This version of the driver is compatible only with Linux versions
+ 1.3.33 and later. It may work with earlier ones as a loadable
+ module but...
+
+ Also this is an ALPHA test version which has not been tested
+ with all cards. At least AEDSP16 support will not work. PAS16
+ and PSS supports have not been tested. /dev/dsp and /dev/audio
+ playback with standard GUS sounds scrambled. 16 bit mode of
+ SB16 doesn't work.
+
+Please read the SOUND-HOWTO (available from sunsite.unc.edu and other Linux ftp
+sites). It contains much more information than this file.
+
+*****************************************************************
+* NEW! VoxWare home page is http://personal.eunet.fi/pp/voxware *
+* The file Readme.cards contains card specific instructions *
+* about configuring various cards. *
+*****************************************************************
+
+There are some programming information (little bit old) in the
+Hacker's Guide
+(ftp://nic.funet.fi/pub/OS/Linux/ALPHA/sound/snd-sdk-doc-0.1.ps.gz).
+Believe me: The file is really there. The directory is just hidden and
+you have to cd into it before the file is visible. Note: This directory
+was accidently removed some time ago but it's now back.
+
+I have got many patches from various persons during last year. Some of
+them are still on my mailbox and they should be included in versions
+after v3.0 (I will not add aditional features before v3.0 is ready).
+
+ ====================================================
+- THIS VERSION ____REQUIRES____ Linux 1.3.33 OR LATER.
+ ====================================================
+
+- THIS VERSION MAY NOT WORK WITH Linux VERSIONS RELEASED
+ AFTER end of Nov 1995. If this version doesn't compile with
+ your kernel version, please use the sound driver version
+ included in your kernel.
+
+You will need the snd-util-3.0.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 linux/Readme.
+
+Supported soundcards
+--------------------
+
+Gravis Ultrasound (GUS)
+GUS MAX
+GUS with the 16 bit sampling daughtercard
+PAS16
+Windows Sound System compatible soundcards
+ECHO-PSS (cards based on the PSS architecture by Analog Devices.
+ Including Orchid SW32, Cardinal DSP16 among others).
+ (NOTE! WSS mode may not work (DMA channel setup problem)).
+MediaTriX AudioTriX Pro (OPL4 and the optional effect daughtercard
+ require special initialization. There is a program (setfx) in
+ the snd-util-3.0.tar.gz package which does it).
+Ensoniq SoundScape (works but needs some improvements)
+MV Jazz16 based soundcards (ProSonic, 3D etc).
+SoundMan Wave (recording may not work, mixer support is limited)
+Mozart (OAK OTI-601 interface chip) based soundcards.
+MAD16 (an interface chip by OPTi) based soundcards (TB Tropez ???).
+(NOTE! The MAD16 looks similar to the Mozart chip. It could be a good
+idea to configure MAD16 cards as Mozart ones. The MAD16 driver doesn't set
+up MPU401 which the Mozart one does.
+CS4232 based cards such as AcerMagic S23.
+
+
+In addition all Sound Blaster models and clones (up to AWE32) work if
+you want to use them.
+
+The Emu synthesizer chip of AWE32 is not and will not be supported. The same is
+true with the ASP chip also. Creative Technology will not release detailed
+information about them so it's not possible to support them.
+
+If you want to get support for AWE32 or ASP, please contact Creative Labs.
+Ask _politely_ if they are going to support Linux. Maybe they change
+their policy if there is enough demand.
+
+===========================================================================
+If your card is compatible with SB, MPU401 or Windows Sound System, it
+may work with the driver even if it's not listed in the above list. In this
+case it may require initialization using DOS. Just start DOS and cold
+boot to Linux (etc.) by hitting ctrl-alt-del.
+===========================================================================
+
+Compatibility with the earlier versions
+---------------------------------------
+
+There have been some changes in soundcard.h after v2.5 of the driver
+(v2.90 is compatible with this one). Binaries compiled with this version
+of soundcard.h will not work with v2.0 and earlier.
+
+Contributors
+------------
+
+This driver contains code by several contributors. In addition several other
+persons have given usefull suggestions. The following is a list of major
+contributors. (I could have forgotten some names.)
+
+ Craig Metz 1/2 of the PAS16 Mixer and PCM support
+ Rob Hooft Volume computation algorithm for the FM synth.
+ Mika Liljeberg uLaw encoding and decoding routines
+ Andy Fingerhut New ulaw conversion tables (ulaw.h)
+ Jeff Tranter Linux SOUND HOWTO document
+ Greg Lee Volume computation algorithm for the GUS and
+ lot's of valuable suggestions.
+ Andy Warner ISC port
+ Jim Lowe,
+ Amancio Hasty Jr FreeBSD/NetBSD 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.
+ Mikael Nordqvist Linear volume support for GUS and
+ nonblocking /dev/sequencer.
+ Ian Hartas SVR4.2 port
+ Markus Aroharju and
+ Risto Kankkunen Major contributions to the mixer support
+ of GUS v3.7.
+ Hunyue Yau Mixer support for SG NX Pro.
+ Marc Hoffman PSS support.
+ Rainer Vranken Initialization for Jazz16 (ProSonic, MV3D, SM Wave).
+ Peter Trattler Initial version of loadable module support for Linux.
+ JRA Gibson 16 bit mode for Jazz16
+ Davor Jadrijevic MAD16 support
+ Gregor Hoffleit Mozart support
+ Riccardo Facchetti Audio Excel DSP 16 (aedsp16) support
+
+There are propably many other names missing. If you have sent me some
+patches and your name is not in the above list, please inform me.
+
+Sponsors etc.
+-------------
+
+The following companies have greatly helped development of this driver
+in form of a free copy of their product:
+
+Novell, Inc. UnixWare personal edition + SDK
+The Santa Cruz Operation, Inc. A SCO OpenServer + SDK
+Ensoniq Corp, a SoundScape card and extensive amount of assistance
+MediaTriX Peripherals Inc, a AudioTriX Pro card + SDK
+Acer, Inc. a pair of AcerMagic S23 cards.
+
+In addition the following companies have provided me sufficial amount
+of technical information at least some of their products (free or $$$):
+
+Advanced Gravis Computer Technology Ltd.
+Media Vision Inc.
+Analog Devices Inc.
+Logitech Inc.
+Aztech Labs Inc.
+Crystal Semiconductor Corporation,
+Integrated Circuit Systems Inc.
+OAK Technology
+OPTi
+Ad Lib Inc. ($$)
+Music Quest Inc. ($$)
+Creative Labs ($$$)
+
+If you have some problems
+=========================
+
+Read the sound HOWTO (sunsite.unc.edu:/pub/Linux/docs/...?).
+Also look at the home page (http://personal.eunet.fi/pp/voxware). It may
+contain info about some recent bug fixes.
+
+It's likely that you have some problems when trying to use the sound driver
+first time. Soundcards don't have standard configuration so there are no
+good default configuration to use. Please try to use same I/O, DMA and IRQ
+values for the soundcard than with DOS.
+
+If you get an error message when trying to use the driver, please look
+at /var/adm/messages for more verbose error message.
+
+
+In general the easiest way to diagnoze problems is to do "cat /dev/sndstat".
+
+If you get an error message, there are some problems with the driver setup:
+
+ - "No such file or directory" tells that the device files for
+ the sound driver are missing. Use the script at the end of
+ linux/drivers/sound/Readme.linux to create them.
+
+ - "No such device" telss that the sound driver is not in the kernel.
+ You have to reconfigure and recompile the kernel to have the sound
+ driver. Compiling the driver doesn't help alone. You have to boot
+ with the newly compiled one before the driver becomes active.
+ The Linux-HOWTO should help in this step.
+
+The following errors are likely with /dev/dsp and /dev/audio.
+
+ - "No such device or address". This error message should not happen
+ with /dev/sndstat but it's possible with the other sound devices.
+ This error indicates that there are no suitable hardware for the
+ device file or the sound driver has been compiled without support for
+ this particular device. For example /dev/audio and /dev/dsp will not
+ work if "digitized voice support" was not enabled during "make config".
+
+ - "Device or resource busy". Propably the IRQ (or DMA) channel
+ required by the soundcard is in use by some other device/driver.
+
+ - "I/O error". Almost certainly (99%) it's an IRQ or DMA conflict.
+ Look at the kernel messages in /var/adm/notice for more info.
+
+ - "Invalid argument". The application is calling ioctl()
+ with impossible parameters. Check that the application is
+ for sound driver version 2.X or later.
+
+In general the printout of of /dev/sndstat should tell what is the problem.
+It's possible that there are bugs in the sound driver but 99% of the problems
+reported to me are caused by somehow incorrect setup during "make config".
+
+For owners of TI TM4000M notebooks
+----------------------------------
+
+There appears to be some kind of conflict between the sound support
+(MV Jazz), mouse port and VoxWare. You could try to configure kernel
+with the C&T 82C710 mouse port support disabled.
+
+Hannu
+
+Regards,
+
+Hannu Savolainen
+hannu@voxware.pp.fi
+(or Hannu.Savolainen@cctap.carel.fi in case the above bounces)
+
+Snail mail: Hannu Savolainen
+ Hiekkalaiturintie 3 A 8
+ 00980 Helsinki
+ Finland
+
+NOTE! I propably don't answer to Snail mail or FAX messages. Sending answer
+ to each of them is simply too expensive and time consuming. However I
+ try to reply every email message I get (within a week). If you don't
+ get response, please check how your address is written in the message
+ header. I can't answer if I don't have a valid reply address.
+
+VoxWare home page is http://personal.eunet.fi/pp/voxware
diff --git a/sys/i386/isa/sound/Readme.cards b/sys/i386/isa/sound/Readme.cards
new file mode 100644
index 0000000..fe17aa06
--- /dev/null
+++ b/sys/i386/isa/sound/Readme.cards
@@ -0,0 +1,845 @@
+Configuring VoxWare 3.0 (for Linux) with some most common soundcards
+====================================================================
+
+NOTE! This document may contain some error. Please inform me
+ if you find any mistakes.
+
+Read this before trying to configure the driver
+-----------------------------------------------
+
+There are currently many cards that work with VoxWare. Some of the cards
+have native support while the others work since they emulate some other
+cards (usually SB, MSS/WSS and/or MPU401). The following cards have native
+support in VoxWare. Detailed instructions for configuring these cards
+will be given later in this document.
+
+Pro Audio Spectrum 16 (PAS16) and compatibles:
+ Pro Audio Spectrum 16
+ Pro Audio Studio 16
+ Logitech Sound Man 16
+ NOTE! The original Pro Audio Spectrum as well as the PAS+ are not
+ and will not be supported by VoxWare.
+
+Media Vision Jazz16 based cards
+ Pro Sonic 16
+ Logitech SoundMan Wave
+ (Other Jazz based cards should work but I don't have any reports
+ about them).
+
+Sound Blasters
+ SB 1.0 to 2.0
+ SB Pro
+ SB 16
+ NOTE! The ASP chip and the EMU synth of the AWE32 is not supported
+ since their manufacturer doesn't release information about
+ the card. However both the AB16ASP and the AWE32 work with
+ VoxWare just like a SB16. Also see the comment about some
+ unsupported cards at the end of this file.
+ SB16 compatible cards by other manufacturers than Creative.
+ You have been fooled since there are no SB16 compatible
+ cards in the market (July95). It's likely that your card
+ is compatible just with SB Pro but there is also a non SB
+ compatible 16 bit mode. Usually it's MSS/WSS but could also
+ be a proprietary one like MV Jazz16.
+
+Gravis Ultrasound (GUS)
+ GUS
+ GUS + the 16 bit option
+ GUS MAX
+ GUS ACE (No MIDI port and audio recording)
+
+MPU-401 and compatibles
+ The driver works both with the full (intelligent mode) MPU-401
+ cards (such as MPU IPC-T and MQX-32M) and with the UART only
+ dumb MIDI ports. MPU-401 is currently the most common MIDI
+ interface. Most soundcards are compatible with it. However
+ don't enable MPU401 mode blindly. Many cards having native support
+ in VoxWare have their own MPU401 driver. Enabling the standard one
+ will cause a conflict with these cards. So look if your card is
+ in the list of supported cards before enabling MPU401.
+
+Windows Sound System (MSS/WSS)
+ Even Microsoft has discontinued their own Sound System card, they
+ managed to make a standard. MSS compatible cards are based on a
+ codec chip which is easily available from at least two manufacturers
+ (AD1848 by Analog Devices and CS4231/CS4248 by Crystal Semiconductor).
+ Currently most soundcards are based on one of the MSS compatible codec
+ chip. The CS4231 is used in the high quality cards such as GUS MAX,
+ MediaTriX AudioTriX Pro and TB Tropez (GUS MAX is not MSS compatible).
+
+ Having a AD1848, CS4248 or CS4231 codec chip on the card is a good
+ sign. Even if the card is not MSS compatible, it could be easy to write
+ support for it to VoxWare. Note also that most MSS compatible cards
+ require special boot time initialization which may not be present
+ in VoxWare. Also some MSS compatible cards have native support in
+ VoxWare. Enabling the MSS support with these cards is likely to
+ cause a conflict. So check if your card is listed in this file before
+ enabling the MSS support.
+
+6850 UART MIDI
+ This UART chip is used in the MIDI interface of some (rare)
+ soundcards. It's supported by VoxWare in case you need it.
+
+Yamaha FM synthesizers (OPL2, OPL3 and OPL4)
+ Most soundcards have a FM synthesizer chip. The OPL2 is a 2
+ operator chip used in the original AdLib card. Currently it's used
+ only in the cheapest (8 bit mono) cards. The OPL3 is a 4 operator
+ FM chip which provides better sound quality and/or more available
+ voices than the OPL2. The OPL4 is a new chip which has a OPL3 and
+ a wave table synthesizer packed on the same chip. VoxWare supports
+ just the OPL3 mode directly. Most cards having a OPL4 (like
+ SM Wave and AudioTriX Pro) support the OPL4 mode using MPU401
+ emulation. Writing a native OPL4 support to VoxWare is difficult
+ since Yamaha doesn't give information about their sample ROM chip.
+
+ Enable the generic OPL2/OPL3 FM synthesizer support if your
+ card has a FM chip made by Yamaha. Don't enable it if your card
+ has a software (TRS) based FM emulator.
+
+PSS based cards (AD1848 + ADSP-2115 + Echo ESC614 ASIC)
+ Analog Devices and Echo Speech have together defined a soundcard
+ architecture based on the above chips. The DSP chip is used
+ for emulation of SB Pro, FM and General MIDI/MT32.
+
+ There are several cards based on this architecture. The most known
+ ones are Orchid SW32 and Cardinal DSP16.
+
+ VoxWare supports downloading DSP algorithms to these cards.
+
+MediaTriX AudioTriX Pro
+ The ATP card is built around a CS4231 codec and a OPL4 synthesizer
+ chips. The OPL4 mode is supported by a microcontroller running a
+ General MIDI emulator. There is also a SB 1.5 compatible playback mode.
+
+Ensoniq SoundScape and compatibles
+ Ensoniq has designed a soundcard architecture based on the
+ OTTO synthesizer chip used in their professional MIDI synthesizers.
+ Several companies (including Ensoniq, Reveal and Spea) are selling
+ cards based on this architecture.
+
+MAD16 and Mozart based cards
+ The Mozart (OAK OTI-601) and MAD16 Pro (OPTi 82C929) interface
+ chips are used in many different soundcards, including some
+ cards by Reveal and Turtle Beach (Tropez). Purpose of these
+ chips is to connect other audio components to the PC bus. The
+ interface chip performs address decoding for the other chips.
+
+Audio Excell DSP16
+ Support for this card is made by Riccardo Faccetti
+ (riccardo@cdc8g5.cdc.polimi.it). See aedsp16.c for more info.
+
+Crystal CS4232 based cards such as AcerMagic S23
+ CS4232 is a PnP multimedia chip which contains a CS3231A codec,
+ SB and MPU401 emulations. There is support for OPL3 too.
+ (Unfortunately the MPU401 mode doesn't work).
+
+Turtle Beach Maui and Tropez
+ VoxWare supports sample, parch and program loading commands
+ described in the Maui/Tropez User's manual. There is no initialization
+ code for Maui so it must be initialized using DOS. Audio side of Tropez
+ is based on the MAD16 chip (see above).
+
+Jumpers and software configuration
+----------------------------------
+
+Some of the earliest soundcards were jumper configurable. You have to
+configure VoxWare to configure VoxWare use I/O, IRQ and DMA settings
+that match the jumpers. Just few 8 bit cards are fully jumper
+configurable (SB 1.x/2.x, SB Pro and clones).
+Some cards made by Aztech have an EEPROM which contains the
+config info. These cards behave much like hardware jumpered cards.
+
+Most cards have jumper for the base I/O address but other parameters
+are software configurable. Sometimes there are few other jumpers too.
+
+Latest cards are fully software configurable or they are PnP ISA
+compatible. There are no jumpers on the board.
+
+VoxWare handles software configurable cards automaticly. Just configure
+the driver to use I/O, IRQ and DMA settings which are known to work.
+You could usually use the same values than with DOS and/or Windows.
+Using different settings is possible but not recommended since it may cause
+some trouble (for example when warm booting from an OS to another or
+when installing new hardware to the machine).
+
+VoxWare sets the soft configurable parameters of the card automaticly
+during boot. Usually you don't need to run any extra initialization
+programs when booting Linux but there are some exceptions. See the
+card specific instructions (below) for more info.
+
+The drawback of software configuration is that the driver needs to know
+how the card must be initialized. It cannot initialize unknown cards
+even if they are otherwise compatible with some other cards (like SB,
+MPU401 or Windows Sound System).
+
+What if your card was not listed above?
+---------------------------------------
+
+The first thing to do is to look at the major IC chips on the card.
+Many of the latest soundcards are based on some standard chips. If you
+are lucky, all of them could be supported by VoxWare. The most common ones
+are the OPTi MAD16, Mozart, SoundScape (Ensoniq) and the PSS architectures
+listed above. Also look at the end of this file for list of unsupported
+cards and the ones which could be supported later.
+
+The last resort is to send _exact_ name and model information of the card
+to me together with a list of the major IC chips (manufactured, model) to
+me. I could then try to check if your card looks like something familiar.
+
+There are much more cards in the word than listed above. The first thing to
+do with these cards is to check if they emulate some other card/interface
+such as SB, MSS and/or MPU401. In this case there is a chance to get the
+card to work by booting DOS before starting Linux (boot DOS, hit ctrl-alt-del
+and boot Linux without hard resetting the machine). In this method the
+DOS based driver initializes the hardware to use a known I/O, IRQ and DMA
+settings. If VoxWare is configured to use the same settings, everything should
+work OK.
+
+
+Configuring VoxWare (with Linux)
+================================
+
+VoxWare sound driver is currently a part of Linux kernel distribution. The
+driver files are located in directory /usr/src/linux/drivers/sound.
+
+****************************************************************************
+* VoxWare MUST BE CONFIGURED AND COMPILED WITH THE KERNEL. TRYING *
+* TO COMPILE IT ALONE WILL _NOT_ WORK. *
+* *
+* ALWAYS USE THE SOUND DRIVER VERSION WHICH IS DISTRIBUTED WITH *
+* THE KERNEL SOURCE PACKAGE YOU ARE USING. SOME ALPHA AND BETA TEST *
+* VERSIONS CAN BE INSTALLED FROM A SEPARATELY DISTRIBUTED PACKAGE *
+* BUT CHECK THAT THE PACKAGE IS NOT MUCH OLDER (OR NEWER) THAN THE *
+* KERNEL YOU ARE USING. IT'S POSSIBLE THAT THE KERNEL/DRIVER *
+* INTERFACE CHANGES BETWEEN KERNEL RELEASES WHICH MAY CAUSE SOME *
+* INCOMPATIBILITY PROBLEMS. *
+* *
+* IN CASE YOU INSTALL A SEPARATELY DISTRIBUTED SOUND DRIVER VERSION, *
+* BE SURE TO REMOVE OR RENAME THE OLD SOUND DRIVER DIRECTORY BEFORE *
+* INSTALLING THE NEW ONE. LEAVING OLD FILES TO THE SOUND DRIVER *
+* DIRECTORY _WILL_ CAUSE PROBLEMS WHEN THE DRIVER IS USED OR *
+* COMPILED. *
+****************************************************************************
+
+To configure the driver, run "make config" in the kernel source directory
+(/usr/src/linux). Answer y to the question about Sound card support (after
+questions about mouse, CD-ROM, ftape, etc. supports). Sound config options
+will then be asked after some additional questions.
+
+After configuring the kernel and sound driver, run "make dep" and compile
+the kernel following instructions in the kernel README.
+
+The sound driver configuration dialog
+-------------------------------------
+
+All config information of the sound driver is written to file
+linux/drivers/sound/local.h. You may save the old version is this file and
+use it again in case you want to use the same config later. In this case
+just answer n to each question made by the sound config program and put
+the original local.h back before running "make dep".
+Don't do this if the version number of the sound driver has changed. In this
+case you have to enter the configuration information again.
+
+If you already have the sound driver installed, consult printout of
+"cat /dev/sndstat" when configuring the driver again. It gives the I/O,
+IRQ and DMA settings you have used earlier.
+
+
+The sound config program (linux/drivers/sound/configure) starts by making
+some yes/no questions. Be careful when answering to these questions since
+answering y to a question may prevent some later ones from being asked. For
+example don't answer y to the first question (PAS16) if you don't really
+have a PAS16. Don't enable more cards than you really need since they
+just consume memory. Also some drivers (like MPU401) may conflict with your
+SCSI controller and prevent kernel from booting. If you card was in the list
+of supported cards (above), please look at the card specific config
+instructions (later in this file) before starting to configure. Some cards
+must be configured in way which is not obvious.
+
+So here is the beginning of the config dialog. Answer 'y' or 'n' to these
+questions. The default answer is shown so that (y/n) means 'y' by default and
+(n/y) means 'n'. To use the default value, just hit ENTER. But be careful
+since using the default _doesn't_ guarantee anything.
+
+Note also that all questions may not be asked. The configuration program
+may disable some questions dependig on the earlier choices. It may also
+select some options automaticly as well.
+
+ "ProAudioSpectrum 16 support",
+ - Answer 'y'_ONLY_ if you have a Pro Audio Spectrum _16_,
+ ProAudio Studio 16 or Logitech SoundMan 16 (be sure that
+ you read the above list correctly). Don't answer 'y' if you
+ have some other card made by Media Vision or Logitech since they
+ are not PAS16 compatible.
+ "SoundBlaster support",
+ - Answer 'y' if you have an original SB card made by Creative Labs
+ or a full 100% hardware compatible clone (like Thunderboard or
+ SM Games). If your card was in the list of supported cards (above),
+ please look at the card specific instructions later in this file
+ before answering this question. For an unknown card you may answer
+ 'y' if the card claims to be SB compatible.
+
+ Don't enable SB if you have a MAD16 or Mozart compatible card.
+
+ "Generic OPL2/OPL3 FM synthesizer support",
+ - Answer 'y' if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
+ Answering 'y' is usually a safe and recommended choice. However some
+ cards may have software (TSR) FM emulation. Enabling FM support
+ with these cards may cause trouble. However I don't currently know
+ such cards.
+ "Gravis Ultrasound support",
+ - Answer 'y' if you have GUS or GUS MAX. Answer 'n' if you don't
+ have GUS since the GUS driver consumes much memory.
+ Currently I don't have experiences with the GUS ACE so I don't
+ know what to answer with it.
+ "MPU-401 support (NOT for SB16)",
+ - Be careful with this question. The MPU401 interface is supported
+ by almost any soundcard today. However some natively supported cards
+ have their own driver for MPU401. Enabling the MPU401 option with
+ these cards wil cause a conflict. Also enabling MPU401 on a system
+ that doesn't really have a MPU401 could cause some trouble. If your
+ card was in the list of supported cards (above), please look at
+ the card specific instructions later in this file.
+ It's safe to answer 'y' if you have a true MPU401 MIDI interface
+ card.
+ "6850 UART Midi support",
+ - It's safe to answer 'n' to this question in all cases. The 6850
+ UART interface is so rarely used.
+ "PSS (ECHO-ADI2111) support",
+ - Answer 'y' only if you have Orchid SW32, Cardinal DSP16 or some
+ other card based on the PSS chipset (AD1848 codec + ADSP-2115
+ DSP chip + Echo ESC614 ASIC CHIP).
+ "16 bit sampling option of GUS (_NOT_ GUS MAX)",
+ - Answer 'y' if you have installed the 16 bit sampling daughtercard
+ to your GUS. Answer 'n' if you have GUS MAX. Enabling this option
+ disables GUS MAX support.
+ "GUS MAX support",
+ - Answer 'y' only if you have a GUS MAX.
+ "Microsoft Sound System support",
+ - Again think carefully before answering 'y' to this question. It's
+ safe to answer 'y' in case you have the original Windows Sound
+ System card made by Microsoft or Aztech SG 16 Pro (or NX16 Pro).
+ Also you may answer 'y' in case your card was not listed earlier
+ in this file. For cards having native support in VoxWare, consult
+ the card specific instructions later in this file. Some drivers
+ have their own MSS support and enabling this option wil cause a
+ conflict.
+ "Ensoniq Soundscape support",
+ - Answer 'y' if you have a soundcard based on the Ensoniq SoundScape
+ chipset. Suach cards are being manufactured at least by Ensoniq,
+ Spea and Reveal (note that Reveal makes other cards also).
+ "MediaTriX AudioTriX Pro support",
+ - Answer 'y' if you have the AudioTriX Pro.
+ "Support for MAD16 and/or Mozart based cards",
+ - Answer y if your card has a Mozart (OAK OTI-601) or MAD16
+ (OPTi 82C928 or 82C929) audio interface chip. These chips are
+ currently quite common so it's possible that many no-name cards
+ have one of them. In addition the MAD16 chip is used in some
+ cards made by known manufacturers such as Turtle Beach (Tropez),
+ Reveal (some models) and Diamond (latest ones).
+ "SoundBlaster Pro support",
+ - Enable this option if your card is SB Pro or SB16. Enable it
+ also with any SB Pro clones. Answering 'n' saves some amount of
+ memory but 'y' is the safe alterative.
+ "SoundBlaster 16 support",
+ - Enable if you have a SB16 (including the AWE32).
+ "Audio Excel DSP 16 initialization support",
+ - Don't know much about this card. Look at aedsp16.c for more info.
+
+Then the configuration program asks some y/n questions about the higher
+level services. It's recommended to answer 'y' to each of these questions.
+Answer 'n' only if you know you will not need the option.
+
+ "/dev/dsp and /dev/audio supports (usually required)",
+ - Answering 'n' disables /dev/dsp and /dev/audio. Answer 'y'.
+ "MIDI interface support",
+ - Answering 'n' disables /dev/midi## devices and access to any
+ MIDI ports using /dev/sequencer and /dev/music. This option
+ also affects any MPU401 and/or General MIDI compatible devices.
+ "FM synthesizer (YM3812/OPL-3) support",
+ - Answer 'y' here.
+ "/dev/sequencer support",
+ - Answering 'n' disables /dev/sequencer and /dev/music.
+
+Entering the I/O, IRQ and DMA config parameters
+-----------------------------------------------
+
+After the above questions the configuration program prompts for the
+card specific configuration information. Usually just a set of
+I/O address, IRQ and DMA numbers are asked. With some cards the program
+asks for some files to be used during initialization of the card. For example
+many cards have a DSP chip or microprocessor which must be initialized by
+downloading a program (microcode) file to the card. In some cases this file
+is written to a .h file by the config program and then included to the driver
+during compile.
+
+Instructions for answering these questions are given in the next section.
+
+
+Card specific information
+=========================
+
+This section gives additional instructions about configuring some cards.
+Please refer manual of your card for valid I/O, IRQ and DMA numbers. Using
+the same settings with DOS/Windows and VoxWare is recommended. Using
+different values could cause some problems when switching between
+different operating systems.
+
+SoundBlasters (the original ones by Creative)
+---------------------------------------------
+
+It's possible to configure these cards to use different I/O, IRQ and
+DMA settings. Since the available settings have changed between various
+models, you have to consult manual of your card for the proper ones. It's
+a good idea to use the same values than with DOS/Windows. With SB and SB Pro
+it's the only choice. SB16 has software selectable IRQ and DMA channels but
+using different values with DOS and Linux is likely to cause troubles. The
+DOS driver is not able to reset the card properly after warm boot from Linux
+if Linux has used different IRQ or DMA values.
+
+The original (steam) Sound Blaster (versions 1.x and 2.x) use always
+DMA1. There is no way to change it.
+
+The SB16 needs two DMA channels. A 8 bit one (1 or 3) is required for
+8 bit operation and a 16 bit one (5, 6 or 7) for the 16 bit mode. In theory
+it's possible to use just one (8 bit) DMA channel by answering the 8 bit
+one when the configuration program asks for the 16 bit one. This may work
+in some systems but is likely to cause terrible noise on some other systems.
+
+NOTE! Don't enable the SM Games option (asked by the configuration program)
+ if you are not 101% sure that your card is a Logitech Soundman Games
+ (not a SM Wave or SM16).
+
+SB Clones
+---------
+
+First of all: There are no SB16 clones. There are SB Pro clones with a
+16 bit mode which is not SB16 compatible. The most likely alternative is that
+the 16 bit mode means MSS/WSS.
+
+There are just few fully 100% hardware SB or SB Pro compatible cards.
+I know just Thunderboard and SM Games. Other cards require some kind of
+hardware initialization before they become SB compatible. Check if your card
+was listed in the beginning of this file. In this case you should follow
+instructions for your card later in this file.
+
+For other not fully SB clones yoy may try initialization using DOS in
+the following way:
+
+ - Boot DOS so that the card specific driver gets run.
+ - Hit ctrl-alt-del (or use loadlin) to boot Linux. Don't
+ switch off power or press the reset button.
+ - If you use the same I/O, IRQ and DMA settings in Linux, the
+ card should work.
+
+If your card is both SB and MSS compatible, I recommend using the MSS mode.
+Most cards of this kind are not able to work in the SB and the MSS mode
+simultaneously. Using the MSS mode provides 16 bit recording and playback.
+
+ProAudioSpectrum 16 and compatibles
+-----------------------------------
+
+There are nothing special with these cards. Just don't enable any
+other cards in case you don't have them also. The PAS16 has
+a SB mode so the driver config program will prompt for the SB settings
+do. Use I/O 0x220 and DMA1 for the SB mode. Ensure that you assign different
+IRQ numbers for the SB and PAS16 modes.
+
+With PAS16 you can use two audio device files at the same time. /dev/dsp (and
+/dev/audio) is connected to the 8/16 bit native codec and the /dev/dsp1 (and
+/dev/audio1) is connected to the SB emulation (8 bit mono only).
+
+Gravis Ultrasound
+-----------------
+
+There are many different revisions of the Ultrasound card (GUS). The
+earliest ones (pre 3.7) don't have a hardware mixer. With these cards
+the driver uses a software emulation for synth and pcm playbacks. It's
+also possible to switch some of the inputs (line in, mic) off by setting
+mixer volume of the channel level below 10%. For recording you have
+to select the channel as a recording source and to use volume above 10%.
+
+GUS 3.7 has a hardware mixer.
+
+GUS MAX and the 16 bit sampling daughtercard have a CS4231 codec chip which
+also contains a mixer.
+
+Configuring GUS is simple. Just enable the GUS support and GUS MAX or
+the 16 bit daughtercard if you have them. Note that enabling the daughter
+card disables GUS MAX driver.
+
+With just the standard GUS enabled the configuration program prompts
+for the I/O, IRQ and DMA numbers for the card. Use the same values than
+with DOS.
+
+With the daughter card option enabled you will be prompted for the I/O,
+IRQ and DMA numbers for the daughter card. You have to use different I/O
+and DMA values than for the standard GUS. The daughter card permits
+simultaneous recording and playback. Use /dev/dsp (the daughtercard) for
+recording and /dev/dsp1 (GUS GF1) for playback.
+
+GUS MAX uses the same I/O address and IRQ settings than the original GUS
+(GUS MAX = GUS + a CS4231 codec). In addition an extra DMA channel may be used.
+Using two DMA channels permits simultaneous playback using two devices
+(dev/dsp0 and /dev/dsp1). The second DMA channel is required for
+full duplex audio.
+To enable the second DMA channels, give a valid DMA channel when the config
+program asks for the GUS MAX DMA (entering -1 disables the second DMA).
+Using 16 bit DMA channels (5,6 or 7) is recommended.
+
+If you have problems in recording with GUS MAX, you could try to use
+just one 8 bit DMA channel. Recording will not work with one DMA
+channel if it's a 16 bit one.
+
+
+
+MPU401 and Windows Sound System
+-------------------------------
+
+Again. Don't enable these options in case your card is listed
+somewhere else in this file.
+
+Configuring these cards is obvious (or it should be). With MSS
+you should propably enable the OPL3 synth also since
+most MSS compatible cards have it. However check that this is true
+before enabling OPL3.
+
+VoxWare supports more than one MPU401 compatible cards at the same time
+but the config program asks config info for just the first of them.
+Adding the second or third MPU interfaces must be done manually by
+editing sound/local.h (after running the config program). Add defines for
+MPU2_BASE & MPU2_IRQ (and MPU3_BASE & MPU3_IRQ) to the file.
+
+CAUTION!
+
+The default I/O base of Adaptec AHA-1542 SCSI controller is 0x330 which
+is also the default of the MPU401 driver. Don't configure the sound driver to
+use 0x330 as the MPU401 base if you have a AHA1542. The kernel will not boot
+if you make this mistake.
+
+PSS
+---
+
+Even the PSS cards are compatible with SB, MSS and MPU401, you must not
+enable these options when configuring the driver. The configuration
+program handles these options itself. (You may use the SB, MPU and MSS options
+together with PSS if you have another card on the system).
+
+The PSS driver enables MSS and MPU401 modes of the card. SB is not enabled
+since it doesn't work concurrently with MSS. The driver loads also a
+DSP algorithm which is used to for the general MIDI emulation. The
+algorithm file (.ld) is read by the config program and written to a
+file included when the pss.c is compiled. For this reason the config
+program asks if you want to download the file. Use the genmidi.ld file
+distributed with the DOS/Windows drivers of the card (don't use the mt32.ld).
+With some cards the file is called 'synth.ld'. You must have access to
+the file when configuring the driver. The easiest way is to mount the DOS
+partition containing the file with Linux.
+
+It's possible to load your own DSP algorithms and run them with the card.
+Look at the directory sound/pss_test for more info (in the VoxWare-3.0.tar.gz)
+package.
+
+AudioTriX Pro
+-------------
+
+You have to enable the OPL3 and SB (not SB Pro or SB16) drivers in addition
+to the native AudioTriX driver. Don't enable MSS or MPU drivers.
+
+Configuring ATP is little bit tricky since it uses so many I/O, IRQ and
+DMA numbers. Using the same values than with DOS/Win is a good idea. Don't
+attemp to use the same IRQ or DMA channels twice.
+
+The SB mode of ATP is implemented so the the ATP driver just enables SB
+in the proper address. The SB driver handles the rest. Yoy have to configure
+both the SB driver and the SB mode of ATP to use the same IRQ, DMA and I/O
+settings.
+
+Also the ATP has a microcontroller for the General MIDI emulation (OPL4).
+For this reason the driver asks for the name of a file containing the
+microcode (TRXPRO.HEX). This file is usually located in the directory
+where the DOS drivers were installed. You must have access to this file
+when configuring the driver.
+
+If you have the effects daughtercard, it must be initialized by running
+the setfx program of snd-util-3.0.tar.gz package. This step is not required
+when using the (future) binary distribution version of the driver.
+
+Ensoniq SoundScape
+------------------
+
+The SoundScape driver handles initialization of MSS and MPU supports
+itself so you don't need to enable other drivers than SoundScape
+(enable also the /dev/dsp, /dev/sequencer and MIDI supports).
+
+SoundScape driver uses the MSS compatible codec of the card. It's important
+to note that /dev/dsp0 (/dev/dsp is linked to /dev/dsp0 by default)
+doesn't work with SoundScape (yet). The 'ssinit' program needs /dev/dsp0 so
+that's the reason why it's there. It's possible that 'primary' pcm channel
+becomes supported later. Currently the card's firmware doesn't contain
+support for it.
+
+With 3.0 of VoxWare you have to change your system to use /dev/dsp1 by default
+so execute: cd /dev;rm dsp;ln -s dsp1 dsp after you have installed VoxWare
+3.0 (first time).
+
+The configuration program asks two DMA channels and two interrupts. One IRQ
+and one DMA is used by the MSS codec. The second IRQ is required for the
+MPU401 mode (you have to use different IRQs for both purposes).
+The second DMA channel is required for initialization of the microcontroller.
+You have to use separate DMA channels.
+
+The SoundScape card has a Motorola microcontroller which must initialized
+_after_ boot (the driver doesn't initialize it during boot).
+The initialization is done by running the 'ssinit' program which is
+distributed in the snd-util-3.0.tar.gz package. You have to edit two
+defines in the ssinit.c and then compile the program. You may run ssinit
+manually (after each boot) or add it to /etc/rc.d/rc.local.
+
+The ssinit program needs the microcode file that comes with the DOS/Windows
+driver of the card. You will need to use version 1.30.00 or later
+of the microcode file (sndscape.co0 or sndscape.co1 depending on
+your card model). THE OLD sndscape.cod WILL NOT WORK. IT WILL HANG YOUR
+MACHINE. The only way to get the new microcode file is to download
+and install the DOS/Windows driver from ftp://ftp.ensoniq.com/pub.
+
+Then you have to select the proper microcode file to use: soundscape.co0
+is the right one for most cards and sndscape.co1 is for few (older) cards
+made by Reveal and/or Spea. The driver has capability to detect the card
+version during boot. Look at the boot log messages in /var/adm/messages
+and locate the sound driver initialization message for the SoundScape
+card. If the driver displays string <Ensoniq Soundscape (old)>, you have
+an old card and you will need to use sndscape.co1. For other cards use
+soundscape.co0.
+
+Check /var/adm/messages after running ssinit. The driver prints
+the board version after downloading the microcode file. That version
+number must match the number in the name of the microcode file (extension).
+
+Running ssinit with a wrong version of the sndscape.co? file is not
+dangerous as long as you don't try to use a file called sndscape.cod.
+If you have initialized the card using a wrong microcode file (sounds
+are terrible), just modify ssinit.c to use another microcode file and try
+again. It's possible to use an earlier version of sndscape.co[01] but it
+may sound wierd.
+
+Btw, The driver may complain something about "sscapeintr()" after
+running ssinit. You should just ignore these messages.
+
+MAD16 (Pro) and Mozart
+----------------------
+
+You need to enable just the MAD16 /Mozart support when configuring
+the driver. _Don't_ enable SB, MPU401 or MSS. However you will need the
+/dev/audio, /dev/sequencer and MIDI supports.
+
+Mozart and OPTi 82C928 (the original MAD16) chips don't support
+MPU401 mode so enter just 0 when the configuration program asks the
+MPU/MIDI I/O base. The MAD16 Pro (OPTi 82C929) has MPU401 mode.
+
+TB Tropez is based on the 82C929 chip. It has two MIDI ports.
+The one connected to the MAD16 chip is the second one (there is a second
+MIDI connector/pins somewhere??). If you have not connected the second MIDI
+port, just disable the MIDI port of MAD16. The 'Maui' compatible synth of
+Tropez is jumper configurable and not connected to the MAD16 chip.
+It can be used by enabling the stand alone MPU401 support but you have
+to initialize it by using the MS-DOS SNDSETUP program.
+
+There are some other OPTi chips which may be used in soundcards such as
+82C930 and MAC32. These chips are not supported by VoxWare yet. Please
+contact me if you have a soundcard which uses these chips.
+
+Some MAD16 based cards may cause feedback, whistle or terrible noise if the
+line3 mixer channel is turned too high.
+
+If you have a MAD16 card which have an OPL4 (FM + Wave table) synthesizer
+chip (_not_ an OPL3), you have to apped line containing #define MAD16_OPL4
+to the file linux/dirvers/sound/local.h (after running make config).
+
+MV Jazz (ProSonic)
+------------------
+
+The Jazz16 driver is just a hack made to the SB Pro driver. However it works
+fairly well. You have to enable SB, SB Pro (_not_ SB16) and MPU401 supports
+when configuring the driver. The configuration program asks later if you
+want support for MV Jazz16 based cards (after asking SB base address). Answer
+'y' here and the driver asks the second (16 bit) DMA channel.
+
+The Jazz16 driver uses the MPU401 driver in a way which will cause
+problems if you have another MPU401 compatible card. In this case you must
+give address of the Jazz16 based MPU401 interface when the config
+program prompts for the MPU401 information. Then look at the MPU401
+spesific section for instructions about configuring more than one MPU401 cards.
+
+Logitech Soundman Wave
+----------------------
+
+Read the above MV Jazz spesific instructions first.
+
+The Logitech SoundMan Wave (don't confuse with the SM16 or SM Games) is
+a MV Jazz based card which has an additional OPL4 based wave table
+synthesizer. The OPL4 chip is handled by an on board microcontroller
+which must be initialized during boot. The config program asks if
+you have a SM Wave immediately after asking the second DMA channel of jazz16.
+If you answer 'y', the config program will ask name of the file containing
+code to be loaded to the microcontroller. The file is usually called
+MIDI0001.BIN and it's located in the DOS/Windows driver directory. The file
+may also be called as TSUNAMI.BIN or something else (older cards?).
+
+The OPL4 synth will be inaccessible without loading the microcontroller code.
+Also remember to enable MPU401 support if you want to use the OPL4 mode.
+
+NOTE! Don't answer 'y' when the driver asks about SM Games support
+ (the next question after the MIDI0001.BIN name). However
+ aneswering 'y' is not dangerous.
+
+Sound Galaxies
+--------------
+
+There are many different Sound Galaxy cards made by Aztech. The 8 bit
+ones are fully SB or SB Pro compatible and there should be no problems
+with them.
+
+The older 16 bit cards (SG Pro16, SG NX Pro16, Nova and Lyra) have
+an EEPROM chip for storing the configuration data. There is a microcontroller
+which initializes the card to match the EEPROM settigs when the machine
+is powered on. These cards actually behave just like they have jumpers
+for all of the settings. Configure VoxWare for MSS, MPU, SB/SB Pro and OPL3
+supports with these cards.
+
+The config program asks if you want support for the mixer of
+SG NX Pro. Answer 'y' to these questions if you have one of the above 8 or
+16 bit Aztech cards.
+
+There are some new Sound Galaxies in the market. I have no experience with
+them so read the card's manual carefully.
+
+
+Reveal cards
+------------
+
+There are several different cards made/marketed by Reveal. Some of them
+are compatible with SoundScape and some use the MAD16 chip. You may have
+to look at the card and try to identify origin of the card.
+
+Diamond
+-------
+
+The oldest (Sierra Aria based) soundcards made by Diamond are not supported
+(they may work if the card is initialized using DOS). The recent (LX?)
+models are based on the MAD16 chip which is supported by VoxWare.
+
+Audio Excel DSP16
+-----------------
+
+See comments in aedsp16.c.
+
+
+PCMCIA cards
+------------
+
+Sorry, can't help. Some cards may work and some don't.
+
+TI TM4000M notebooks
+--------------------
+
+These computers have a built in sound support based on the Jazz chipset.
+Look at the instructions for MV Jazz (above). It's also important to note
+that there is something wrong with the mouse port and sound at least on
+some TM models. Don't enable the "C&T 82C710 mouse port support" when
+configuring Linux. Having it enabled is likely to cause mysterious problems
+and kernel failures when sound is used.
+
+Others?
+-------
+
+Since there are so many different soundcards, it's likely that I have
+forgotten to mention many of them. Please inform me if you know yet another
+card which works with Linux, please inform me (or is anybody else
+willing to maintain a database of supported cards (just like in XF86)?).
+
+Cards not supported yet
+=======================
+
+First of all. There is an easy way to make most soundcards to work
+with Linux. Just use the DOS based driver to initialize the card
+to a _known_ state. Then ctrl-alt-del to Linux. If Linux is configured
+to use the sama I/O, IRQ and DMA numbers than DOS, the card could work.
+
+Don't get fooled with SB compatibility. Most cards are compatible with
+SB but that may require a TSR which is not possible with Linux. If
+the card is compatible with MSS, it's a better choise. Some cards
+don't work in the SB and MSS modes at the same time.
+
+There are some cards which will be supported by VoxWare sooner or later
+(currently at least cards based on the ESS chipset). Such cards are
+so common that there is some idea in writing the driver. Check the
+VoxWare home page (http://personal.eunet.fi/pp/voxware) for latest
+information.
+
+Then there are cards which are no longer manufactured and/or which
+are relatively rarely used (such as the 8 bit ProAudioSpectrum
+models). It's extremely unlikely that such cards never get supported.
+Adding support for a new card requires much work and increases time
+required in maintaining the driver (some changes need to be done
+to all low level drivers and be tested too, maybe with multiple
+operating systems). For this reason I have made a desicion to not support
+obsolete cards. It's possible that someone else makes a separately
+distributed driver (diffs) for the card. Version v4.0 will be much more
+modular so making separately distributed drivers will be easier with it.
+(The bad news is that v4.0 will not be available before late -96).
+
+Writing a driver for a new card is not possible if there are no
+programming information available about the card. If you don't
+find your new card from this file, look from the home page
+(http://personal.eunet.fi/pp/voxware). Then please contact
+manufacturer of the card and ask if they have (or are willing to)
+released technical details of the card. Do this before contacting me. I
+can only answer 'no' if there are no programming information available.
+
+Some companies don't give low level technical information about their
+products to public or at least their require signing a NDA.
+
+I have also made decicion to not accept code based on reverse engineering
+to VoxWare. There are three main reasons: First I don't want to break
+relationships to sound card manufacturers. The second reason is that
+maintaining and supporting a driver withoun any specs will be a pain. The
+third reason is that why shoud we help such companies in selling their
+products to Linux users when they don't want to sell to Linux users
+at all?
+
+Unfortunately many of the leading soundcard manufacturers are not willing
+to co-operate with Linux/Unix community. For example: Creative Technology
+doesn't give information about the ASP chip and the Emu synth chip of AWE32
+and SB32. Turtle Beach don't give information about any of their
+products. MediaVision requires NDA before they are willing to
+give information about the Jazz16 chip (fortunately Logitech gave
+the info about SM Wave).
+
+So at least the above three companies are out until they are willing to
+release documentation about their products (the situation is the
+same with many DOS based freeware/shareware games and utilities). If
+you want to use Linux/Unix with their cards, please don't try to push
+me. It's a better idea to contact the manufacturer and explain that
+you want to use your card with Linux/Unix. You could also try to sell
+your card to somebody else and then buy a card that is supported by VoxWare.
+
+However it's possible that things change and a driver gets written
+for some of the banned cards. Please, don't send me messages asking if
+there is any plans to write a driver for the cards mentioned above. I
+will put any news to the VoxWare www home page (see below).
+
+There are some common audio chipsets that are supported yet. For example
+the ESS chips and Sierra Aria. It's likely that these architectures
+get some support in future but I can't make any promises. Just look
+at the home page for latest info.
+
+Information about unsupported soundcards and chipsets is welcome as well
+as free copies of soundcards, SDKs and operating systems.
+
+If you have any corrections and/or comments, please contact me.
+
+Hannu Savolainen
+hannu@voxware.pp.fi
+VoxWare www home page: http://personal.eunet.fi/pp/voxware
+
diff --git a/sys/i386/isa/sound/Readme.modules b/sys/i386/isa/sound/Readme.modules
index 315540f..2dab125 100644
--- a/sys/i386/isa/sound/Readme.modules
+++ b/sys/i386/isa/sound/Readme.modules
@@ -1,87 +1,99 @@
- Linux sound-driver module
- (c) Peter Trattler
- License: GPL (Gnu Public License)
-
-
-Idea:
-
-I've modified the sources for the sound driver to allow simply insert and
-remove the sound driver from the kernel by calling (only available for Linux)
-
- insmod /usr/src/linux/modules/sound.o
-
-and
-
- rmmod sound
-
-This may be useful if you are doing one of the following things:
-
-1) Debugging the sound driver
-2) Creating a new device within the sound-driver
-3) You do not the sound driver all the time (as it wastes quite a lot of
-memory for its buffers)
-
-
-Compilation:
-
-Go to /usr/src/linux and make the following steps:
-
-a) configure the sound driver: To do that call "make config" and enable the
-sound-driver -- you will be asked different questions about your
-sound-hardware (remember not to use a too big DMA-Buffer size; you
-should use 16kB, if you have 16Bit devices, otherwise you can use 32kB)
-
-b) disable the sound driver in the kernel: call make config again but answer
-'N' to "Sound card support"
-
-c) run "make modules"; the sound-driver sound.o should end up in
-/usr/src/linux/modules
-
-
-If memory is tight:
-
-I've allocated at about 70kB for the sound-drivers internal tables. If this
-is too much, 'insmod sound.o' will generate the following warning
-...
-use 'insmod memsize=xxxx'
-...
-You can only use this command, if you have (I think) at least
-modules-1.1.87 or up. You can also switch debugging on by running the command
-
-insmod sound.o debugmem=1
-
-
-Files I changed:
-
-I've only changed the files soundcard.c(most changes) and some changes within
-the Makefile, sound_config.h and the Makefile in /usr/src/linux/drivers
-
-
-Bugs:
-
-a) As the kmalloc (..., GFP_DMA) caused some unexpected errors (I don't know if
-it is my fault), I created some code, which is (by default) enabled by
-
-#define KMALLOC_DMA_BROKEN 1 (within soundcard.c).
-
-It trys to allocate a large enough region, so that the complete dma-buffer
-can be occupied in this space. If it does not fit within this region it
-doubles the size of it. But this can cause problems, if the sound-buffer is
-too big (as kmalloc can only handle regions at up to circa 100kB).
-
-So take care to use for 8Bit devices a sound-DMA-buffer of 32kB (maximum)
-and for 16Bit devices a maximum of 16kB. Otherwise the allocation scheme
-might fail.
-
-b) Buffers allocated by the different sound devices via calls to kmalloc are
-not freed, if the sound driver is removed again (these buffers tend to be
-quite small -- so it does not harm a lot)
-
-c) If there is not enough (kernel-) memory available, the installation of
-the sound-driver fails. (This happens quite often, if you did not install the
-driver right after booting -- [PS: I've only got 5MB of Ram, so this might
-be the source for this problem])
-
-
-Author:
- Peter Trattler (peter@sbox.tu-graz.ac.at)
+Building a loadable sound driver
+================================
+
+Loadable module support in version 3.5 of VoxWare is mostly rewritten since
+the previous version (3.0.1). This means that some things have changed.
+
+To compile the sound driver as a loadable module you have to perform
+the following steps:
+
+1) Install modules-1.2.8.tar.gz package (or later if available).
+2a) Check that symbol remap_page_range is defined in linux/init/ksyms.c.
+Insert a line containing "X(remap_page_range)," if required. The driver will
+not load if this line is missing.
+2b) Recompile kernel with soundcard support disabled.
+3) Boot the new kernel.
+4) cd to the sound driver source directory (this directory). It's no
+longer required that the sound driver sources are installed in the
+kernel source tree (linux/drivers/sound). When installing a separately
+distributed sound driver you may install the sources for example to
+/usr/src/sound.
+5) Execute make in the sound driver source directory. Enter
+configuration parameters as described in Readme.cards. Then just wait until
+the driver is compiled OK.
+6) Copy sound.o to the directory where insmod expects to find it.
+("make install" copies it to /lib/modules/misc).
+7) Use command "insmod sound" to load the driver.
+
+8) The sound driver can be removed using command "rmmod sound".
+
+
+Parameters accepted by the loadable sound driver
+================================================
+
+Setting DMA buffer size
+-----------------------
+
+The driver allocates a DMA buffer (or two for full duplex devices)
+every time the audio device (/dev/dsp or /dev/audio) is opened
+and frees it when the device is closed. Size of this buffer is defined
+when the driver is configured (the last question). The buffer size
+can be redefined when loading the driver if required (note that this is
+an optional feature which is not normally required). The buffer size
+is redefined by adding dma_pagesize= parameter to the insmod command line.
+For example:
+
+ insmod sound dma_buffsize=32768
+
+Minimum buffer size is 4096 and the maximum depends on the DMA channe.
+For 8 bit channels (0 to 3) the limit is 64k and for 16 bit ones (5 to 7)
+it's 128k. Driver selects a suitable buffer size automaticly in case
+you try to spesify an invalid size.
+
+Q: What is the right DMA buffer size?
+
+A: It depends on the sampling rate, machine speed and the load of the system.
+Large buffers are required on slow machines, when recording/playing CD-quality
+audio or when there are other processes running on the same system. Also
+recording to hard disk is likely to require large buffers.
+
+Very small buffers are sufficient when you are just playing 8kHz audio files
+on an empty P133 system. Using a 128k byffer just wastes 120k (or 250k)
+of valuable physical RAM memory.
+
+The right buffer sice can be easily found by making some experiments
+with the dma_buffsize= parameter. I use usually 16k buffers on a DX4/100 system
+and 64k on an old 386 system.
+
+NOTE! DMA buffers are used only by /dev/audio# and /dev/dsp# devices.
+ Other device files don't use them but there are two exceptions:
+ GUS driver uses DMA buffers when loading samples to the card.
+ Ensoniq SoundScape driver uses them when doanloading the microcode
+ file (sndscape.co[012]) to the card. Using large buffers doesn't
+ increase performance in these cases.
+
+Configuring device parameters when loading the driver
+-----------------------------------------------------
+
+The loadable version of the sound driver accepts now the same
+sound= parameter that has been available in the LILO command line.
+In this way it's possible to change I/O port, IRQ and DMA addresses
+and to enable/disable various cards at load time. Normally
+the driver uses the configuration parameters entered when compiling
+and configuring the driver.
+Look at Readme.linux for more info.
+
+NOTE! This method is not normally required. You should use it only when
+ you have to use different configuration than normally. The sound=
+ command line parameter is error phrone and not recommended.
+
+Debugging and tracing
+---------------------
+
+Modularized sound driver doesn't display messages during initialization as
+the kernel compiled one does. This feature can be turned on by adding
+init_trace=1 to the insmod command line.
+
+For example:
+
+ insmod sound init_trace=1
diff --git a/sys/i386/isa/sound/Readme.v30 b/sys/i386/isa/sound/Readme.v30
index 8884ad8..826710e 100644
--- a/sys/i386/isa/sound/Readme.v30
+++ b/sys/i386/isa/sound/Readme.v30
@@ -1,8 +1,6 @@
VoxWare v3.0
------------
-This is a late alpha/early beta of the VoxWare v3.0 to be relased May/June 95.
-
All features of v2.90-2 should work as earlier. There could be some
omissions but they are unintentional. I started this version thread
after v2.3 so all features implemented before it are there.
diff --git a/sys/i386/isa/sound/ad1848.c b/sys/i386/isa/sound/ad1848.c
index 73e0edc..39a0e55 100644
--- a/sys/i386/isa/sound/ad1848.c
+++ b/sys/i386/isa/sound/ad1848.c
@@ -1,14 +1,29 @@
/*
* sound/ad1848.c
+ *
+ * Modified by Luigi Rizzo (luigi@iet.unipi.it)
*
- * 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.
+ * 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.
+ *
+ * CS4231A and AD1845 are upward compatible with CS4231. However the new
+ * features of these chips are different.
+ *
+ * CS4232 is a PnP audio chip which contains a CS4231A (and SB, MPU). CS4232A is
+ * an improved version of CS4232.
+ *
+ * CS4236 is also a PnP audio chip similar to the 4232
*
+ * OPTi931 is another high-end 1848-type chip. It differs in the use
+ * of the high 16 registers and configuration stuff. Luckily, being a
+ * PnP device, we can avoid black magic to identify the chip and be
+ * sure of its identity.
+ *
* Copyright by Hannu Savolainen 1994, 1995
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -16,7 +31,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -28,69 +43,88 @@
* 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:
- * Riccardo Facchetti 24 Mar 1995
- * - Added the Audio Excel DSP 16 initialization routine.
+ *
+ * Modified: Riccardo Facchetti 24 Mar 1995 - Added the Audio Excel DSP 16
+ * initialization routine.
*/
#define DEB(x)
#define DEB1(x)
#include <i386/isa/sound/sound_config.h>
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AD1848)
+#if defined(CONFIG_AD1848)
#include <i386/isa/sound/ad1848_mixer.h>
-
-#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;
- unsigned char saved_regs[16];
-
- int speed;
- unsigned char speed_bits;
- int channels;
- int audio_format;
- unsigned char format_bits;
-
- int xfer_count;
- int irq_mode;
- int intr_active;
- int opened;
- char *chip_name;
- int mode;
-
- /* Mixer parameters */
- int recmask;
- int supported_devices;
- int supported_rec_devices;
- unsigned short levels[32];
- }
-
-ad1848_info;
+#include <i386/isa/sound/iwdefs.h>
+
+extern struct isa_driver mssdriver;
+
+extern void IwaveStopDma(BYTE path);
+
+typedef struct {
+ int base;
+ int irq;
+ int dual_dma; /* 1, when two DMA channels allocated */
+ u_char MCE_bit;
+ u_char saved_regs[16];
+
+ int speed;
+ u_char speed_bits;
+ int channels;
+ int audio_format;
+ u_char format_bits;
+
+ u_long xfer_count;
+ int irq_mode;
+ int intr_active;
+ int opened;
+ char *chip_name;
+ int mode;
+#define MD_1848 1
+#define MD_4231 2
+#define MD_4231A 3
+#define MD_1845 4
+#define MD_MAXMODE 5
+
+ /* Mixer parameters */
+ int recmask;
+ int supported_devices;
+ int supported_rec_devices;
+ u_short levels[32];
+ int dev_no;
+ volatile u_long timer_ticks;
+ int timer_running;
+ int irq_ok;
+ sound_os_info *osp;
+} 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 volatile char irq2dev[17] =
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
-static char mixer2codec[MAX_MIXER_DEV] =
-{0};
+static int timer_installed = -1;
+static int mute_flag = 0;
+static char mixer2codec[MAX_MIXER_DEV] = {0};
-static int ad_format_mask[3 /*devc->mode */ ] =
+static int ad_format_mask[MD_MAXMODE /* devc->mode */ ] =
{
- 0,
- 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
+ /* 0 - none */ 0,
+ /* 1 - AD1848 */ 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,
+ */
+
+ /* 2 - CS4231 */ AFMT_U8 | AFMT_S16_LE | AFMT_U16_LE,
+
+ /*
+ * AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE |
+ * AFMT_IMA_ADPCM,
+ */
+
+ /* 3 - CS4231A */ AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW,
+ /* 4 - AD1845 */ AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW
};
static ad1848_info dev_info[MAX_AUDIO_DEV];
@@ -100,1426 +134,1728 @@ static ad1848_info dev_info[MAX_AUDIO_DEV];
#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);
+static int ad1848_open(int dev, int mode);
+static void ad1848_close(int dev);
+static int ad1848_ioctl(int dev, u_int cmd, ioctl_arg arg, int local);
+static void ad1848_output_block(int dev, u_long buf, int count, int intrflag, int dma_restart);
+static void ad1848_start_input(int dev, u_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);
+static void ad1848_halt_input(int dev);
+static void ad1848_halt_output(int dev);
+static void ad1848_trigger(int dev, int bits);
+static int ad1848_tmr_install(int dev);
+static void ad1848_tmr_reprogram(int dev);
+void adintr(int);
-static int
-ad_read (ad1848_info * devc, int reg)
+/*
+ * AD_WAIT_INIT waits if we are initializing the board and we cannot modify
+ * its settings
+ */
+#define AD_WAIT_INIT(x) {int t=x; while(t>0 && inb(devc->base) == 0x80) t-- ; }
+
+short ipri_to_irq(u_short ipri);
+
+void
+adintr(unit)
{
- unsigned long flags;
- int x;
- int timeout = 100;
+ static short unit_to_irq[4] = {9, -1, -1, -1};
+ struct isa_device *dev;
+
+ if (unit_to_irq[unit] > 0)
+ ad1848_interrupt(unit_to_irq[unit]);
+ else {
+ dev = find_isadev(isa_devtab_null, &mssdriver, unit);
+ if (!dev)
+ printf("ad1848: Couldn't determine unit\n");
+ else {
+ unit_to_irq[unit] = ipri_to_irq(dev->id_irq);
+ ad1848_interrupt(unit_to_irq[unit]);
+ }
+ }
+}
- while (timeout > 0 && INB (devc->base) == 0x80) /*Are we initializing */
- timeout--;
+static int
+ad_read(ad1848_info * devc, int reg)
+{
+ u_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);
+ AD_WAIT_INIT(900000);
+ flags = splhigh();
+ outb(io_Index_Addr(devc), (u_char) (reg & 0xff) | devc->MCE_bit);
+ x = inb(io_Indexed_Data(devc));
+ splx(flags);
- return x;
+ return x;
}
static void
-ad_write (ad1848_info * devc, int reg, int data)
+ad_write(ad1848_info * devc, int reg, u_char data)
{
- unsigned long flags;
- int timeout = 100;
+ u_long flags;
- while (timeout > 0 && INB (devc->base) == 0x80) /*Are we initializing */
- timeout--;
+ AD_WAIT_INIT(90000);
- 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);
+ flags = splhigh();
+ outb(io_Index_Addr(devc), (u_char) (reg & 0xff) | devc->MCE_bit);
+ outb(io_Indexed_Data(devc), (u_char) (data & 0xff));
+ splx(flags);
}
static void
-wait_for_calibration (ad1848_info * devc)
+wait_for_calibration(ad1848_info * devc)
{
- int timeout = 0;
+ 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;
-#ifdef PC98
- while (timeout > 0 && (INB (devc->base) & 0x80) == 0x80)
- timeout--;
- if ((INB (devc->base) & 0x80) == 0x80)
-#else
- while (timeout > 0 && INB (devc->base) & 0x80)
- timeout--;
- if (INB (devc->base) & 0x80)
-#endif
- printk ("ad1848: Auto calibration timed out(1).\n");
-
- timeout = 100;
- while (timeout > 0 && !(ad_read (devc, 11) & 0x20))
- timeout--;
- if (!(ad_read (devc, 11) & 0x20))
- return;
-
- timeout = 10000;
- while (timeout > 0 && ad_read (devc, 11) & 0x20)
- timeout--;
- if (ad_read (devc, 11) & 0x20)
- printk ("ad1848: Auto calibration timed out(3).\n");
+ AD_WAIT_INIT(100000);
+ if (inb(devc->base) & 0x80)
+ printf("ad1848: Auto calibration timed out(1).\n");
+
+ timeout = 100;
+ while (timeout > 0 && !(ad_read(devc, 11) & 0x20))
+ timeout--;
+ if (!(ad_read(devc, 11) & 0x20))
+ return;
+
+ timeout = 20000;
+ while (timeout > 0 && ad_read(devc, 11) & 0x20)
+ timeout--;
+ if (ad_read(devc, 11) & 0x20)
+ printf("ad1848: Auto calibration timed out(3).\n");
}
static void
-ad_mute (ad1848_info * devc)
+ad_mute(ad1848_info * devc)
{
- int i;
- unsigned char prev;
+ int i;
+ u_char prev;
+
+ mute_flag = 1;
- /*
+ /*
* Save old register settings and mute output channels
- */
- for (i = 6; i < 8; i++)
- {
- prev = devc->saved_regs[i] = ad_read (devc, i);
- ad_write (devc, i, prev | 0x80);
+ */
+ for (i = 6; i < 8; i++) {
+ prev = devc->saved_regs[i] = ad_read(devc, i);
+ ad_write(devc, i, prev | 0x80);
}
}
static void
-ad_unmute (ad1848_info * devc)
+ad_unmute(ad1848_info * devc)
{
- int i;
+ int i;
- /*
+ mute_flag = 0;
+ /*
* Restore back old volume registers (unmute)
- */
- for (i = 6; i < 8; i++)
- {
- ad_write (devc, i, devc->saved_regs[i] & ~0x80);
+ */
+ for (i = 6; i < 8; i++)
+ ad_write(devc, i, devc->saved_regs[i] & ~0x80);
}
-}
static void
-ad_enter_MCE (ad1848_info * devc)
+ad_enter_MCE(ad1848_info * devc)
{
- unsigned long flags;
- int timeout = 1000;
- unsigned short prev;
-
- while (timeout > 0 && INB (devc->base) == 0x80) /*Are we initializing */
- timeout--;
-
- DISABLE_INTR (flags);
-
- devc->MCE_bit = 0x40;
- prev = INB (io_Index_Addr (devc));
- if (prev & 0x40)
- {
- RESTORE_INTR (flags);
- return;
- }
-
- OUTB (devc->MCE_bit, io_Index_Addr (devc));
- RESTORE_INTR (flags);
+ u_long flags;
+
+ AD_WAIT_INIT(1000);
+ devc->MCE_bit = 0x40;
+ flags = splhigh();
+ if ( ( inb(io_Index_Addr(devc)) & 0x40) == 0 )
+ outb(io_Index_Addr(devc), devc->MCE_bit);
+ splx(flags);
}
static void
-ad_leave_MCE (ad1848_info * devc)
+ad_leave_MCE(ad1848_info * devc)
{
- unsigned long flags;
- unsigned char prev;
- int timeout = 1000;
+ u_long flags;
+ u_char prev;
- while (timeout > 0 && INB (devc->base) == 0x80) /*Are we initializing */
- timeout--;
+ AD_WAIT_INIT(1000);
- DISABLE_INTR (flags);
+ flags = splhigh();
- devc->MCE_bit = 0x00;
- prev = INB (io_Index_Addr (devc));
- OUTB (0x00, io_Index_Addr (devc)); /* Clear the MCE bit */
+ devc->MCE_bit = 0x00;
+ prev = inb(io_Index_Addr(devc));
+ /* XXX the next call is redundant ? */
+ outb(io_Index_Addr(devc), 0x00); /* Clear the MCE bit */
- if (prev & 0x40 == 0) /* Not in MCE mode */
- {
- RESTORE_INTR (flags);
- return;
+ if ((prev & 0x40) == 0) { /* Not in MCE mode */
+ splx(flags);
+ return;
}
-
- OUTB (0x00, io_Index_Addr (devc)); /* Clear the MCE bit */
- wait_for_calibration (devc);
- RESTORE_INTR (flags);
+ outb(io_Index_Addr(devc), 0x00); /* Clear the MCE bit */
+ wait_for_calibration(devc);
+ splx(flags);
}
static int
-ad1848_set_recmask (ad1848_info * devc, int mask)
+ad1848_set_recmask(ad1848_info * devc, int mask)
{
- unsigned char recdev;
- int i, n;
+ u_char recdev;
+ int i, n;
- mask &= devc->supported_rec_devices;
+ mask &= devc->supported_rec_devices;
- n = 0;
- for (i = 0; i < 32; i++) /* Count selected device bits */
- if (mask & (1 << i))
- n++;
-
- if (n == 0)
- mask = SOUND_MASK_MIC;
- else if (n != 1) /* Too many devices selected */
- {
- mask &= ~devc->recmask; /* Filter out active settings */
-
- n = 0;
- for (i = 0; i < 32; i++) /* Count selected device bits */
+ n = 0;
+ for (i = 0; i < 32; i++)/* Count selected device bits */
if (mask & (1 << i))
- n++;
+ n++;
- if (n != 1)
+ if (n == 0)
mask = SOUND_MASK_MIC;
- }
+ else if (n != 1) { /* Too many devices selected */
+ mask &= ~devc->recmask; /* Filter out active settings */
- switch (mask)
- {
+ n = 0;
+ for (i = 0; i < 32; i++) /* Count selected device bits */
+ if (mask & (1 << i))
+ n++;
+
+ if (n != 1)
+ mask = SOUND_MASK_MIC;
+ }
+ switch (mask) {
case SOUND_MASK_MIC:
- recdev = 2;
- break;
+ recdev = 2;
+ break;
case SOUND_MASK_LINE:
case SOUND_MASK_LINE3:
- recdev = 0;
- break;
+ recdev = 0;
+ break;
case SOUND_MASK_CD:
case SOUND_MASK_LINE1:
- recdev = 1;
- break;
+ recdev = 1;
+ break;
+
+ case SOUND_MASK_IMIX:
+ recdev = 3;
+ break;
default:
- mask = SOUND_MASK_MIC;
- recdev = 2;
+ mask = SOUND_MASK_MIC;
+ recdev = 2;
}
- recdev <<= 6;
- ad_write (devc, 0, (ad_read (devc, 0) & 0x3f) | recdev);
- ad_write (devc, 1, (ad_read (devc, 1) & 0x3f) | recdev);
+ recdev <<= 6;
+ ad_write(devc, 0, (ad_read(devc, 0) & 0x3f) | recdev);
+ ad_write(devc, 1, (ad_read(devc, 1) & 0x3f) | recdev);
- devc->recmask = mask;
- return mask;
+ devc->recmask = mask;
+ return mask;
}
static void
-change_bits (unsigned char *regval, int dev, int chn, int newval)
+change_bits(u_char *regval, int dev, int chn, int newval)
{
- unsigned char mask;
- int shift;
+ u_char mask;
+ int shift;
- if (mix_devices[dev][chn].polarity == 1) /* Reverse */
- newval = 100 - newval;
+ if (mix_devices[dev][chn].polarity == 1) /* Reverse */
+ newval = 100 - newval;
- mask = (1 << mix_devices[dev][chn].nbits) - 1;
- shift = mix_devices[dev][chn].bitpos;
- newval = (int) ((newval * mask) + 50) / 100; /* Scale it */
+ mask = (1 << mix_devices[dev][chn].nbits) - 1;
+ shift = mix_devices[dev][chn].bitpos;
+ newval = (int) ((newval * mask) + 50) / 100; /* Scale it */
- *regval &= ~(mask << shift); /* Clear bits */
- *regval |= (newval & mask) << shift; /* Set new value */
+ *regval &= ~(mask << shift); /* Clear bits */
+ *regval |= (newval & mask) << shift; /* Set new value */
}
static int
-ad1848_mixer_get (ad1848_info * devc, int dev)
+ad1848_mixer_get(ad1848_info * devc, int dev)
{
- if (!((1 << dev) & devc->supported_devices))
- return RET_ERROR (EINVAL);
+ if (!((1 << dev) & devc->supported_devices))
+ return -(EINVAL);
- return devc->levels[dev];
+ return devc->levels[dev];
}
+#define CLMICI 0x00781601
+#define CRMICI 0x00791701
+
static int
-ad1848_mixer_set (ad1848_info * devc, int dev, int value)
+ad1848_mixer_set(ad1848_info * devc, int dev, int value)
{
- int left = value & 0x000000ff;
- int right = (value & 0x0000ff00) >> 8;
+ int left = value & 0x000000ff;
+ int right = (value & 0x0000ff00) >> 8;
+ int retvol;
+
+ int regoffs;
+ u_char val;
+ /* u_char clci, crmici, clmici, clici, crici; */
+
+ if (left > 100)
+ left = 100;
+ if (right > 100)
+ right = 100;
- int regoffs;
- unsigned char val;
+ if (mix_devices[dev][RIGHT_CHN].nbits == 0) /* Mono control */
+ right = left;
- if (left > 100)
- left = 100;
- if (right > 100)
- right = 100;
+ retvol = left | (left << 8);
- if (dev > 31)
- return RET_ERROR (EINVAL);
+ /* Scale volumes */
+ left = mix_cvt[left];
+ right = mix_cvt[right];
- if (!(devc->supported_devices & (1 << dev)))
- return RET_ERROR (EINVAL);
+ /* Scale it again */
+ left = mix_cvt[left];
+ right = mix_cvt[right];
- if (mix_devices[dev][LEFT_CHN].nbits == 0)
- return RET_ERROR (EINVAL);
+ if (dev > 31)
+ return -(EINVAL);
- /*
+ if (!(devc->supported_devices & (1 << dev)))
+ return -(EINVAL);
+
+ if (mix_devices[dev][LEFT_CHN].nbits == 0)
+ return -(EINVAL);
+
+ devc->levels[dev] = retvol;
+
+ /*
* Set the left channel
- */
-
- regoffs = mix_devices[dev][LEFT_CHN].regno;
- val = ad_read (devc, regoffs);
- change_bits (&val, dev, LEFT_CHN, left);
- devc->levels[dev] = left | (left << 8);
- ad_write (devc, regoffs, val);
- devc->saved_regs[regoffs] = val;
-
- /*
- * Set the left right
- */
-
- if (mix_devices[dev][RIGHT_CHN].nbits == 0)
- return left | (left << 8); /* Was just a mono channel */
-
- regoffs = mix_devices[dev][RIGHT_CHN].regno;
- val = ad_read (devc, regoffs);
- change_bits (&val, dev, RIGHT_CHN, right);
- ad_write (devc, regoffs, val);
- devc->saved_regs[regoffs] = val;
-
- devc->levels[dev] = left | (right << 8);
- return left | (right << 8);
+ */
+ /* IwaveCodecMode(CODEC_MODE3); Default codec mode */
+
+ regoffs = mix_devices[dev][LEFT_CHN].regno;
+ val = ad_read(devc, regoffs);
+
+ change_bits(&val, dev, LEFT_CHN, left);
+ ad_write(devc, regoffs, val);
+ devc->saved_regs[regoffs] = val;
+
+ /*
+ * Set the right channel
+ */
+
+ if (mix_devices[dev][RIGHT_CHN].nbits == 0)
+ return retvol; /* Was just a mono channel */
+
+ regoffs = mix_devices[dev][RIGHT_CHN].regno;
+ val = ad_read(devc, regoffs);
+ change_bits(&val, dev, RIGHT_CHN, right);
+ ad_write(devc, regoffs, val);
+ devc->saved_regs[regoffs] = val;
+
+ return retvol;
}
static void
-ad1848_mixer_reset (ad1848_info * devc)
+ad1848_mixer_reset(ad1848_info * devc)
{
- int i;
+ int i;
- devc->recmask = 0;
- if (devc->mode == 2)
- devc->supported_devices = MODE2_MIXER_DEVICES;
- else
- devc->supported_devices = MODE1_MIXER_DEVICES;
+ devc->recmask = 0;
+ if (devc->mode != MD_1848)
+ devc->supported_devices = MODE2_MIXER_DEVICES;
+ else
+ devc->supported_devices = MODE1_MIXER_DEVICES;
- devc->supported_rec_devices = MODE1_REC_DEVICES;
+ devc->supported_rec_devices = MODE1_REC_DEVICES;
- for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- ad1848_mixer_set (devc, i, devc->levels[i] = default_mixer_levels[i]);
- ad1848_set_recmask (devc, SOUND_MASK_MIC);
+ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+ if (devc->supported_devices & (1 << i))
+ ad1848_mixer_set(devc, i, default_mixer_levels[i]);
+ ad1848_set_recmask(devc, SOUND_MASK_MIC);
}
static int
-ad1848_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
+ad1848_mixer_ioctl(int dev, u_int cmd, ioctl_arg arg)
{
- ad1848_info *devc;
+ ad1848_info *devc;
+ int codec_dev = mixer2codec[dev];
- int codec_dev = mixer2codec[dev];
+ if (!codec_dev)
+ return -(ENXIO);
- if (!codec_dev)
- return RET_ERROR (ENXIO);
+ codec_dev--;
- codec_dev--;
+ devc = (ad1848_info *) audio_devs[codec_dev]->devc;
- devc = (ad1848_info *) audio_devs[codec_dev]->devc;
+ if (((cmd >> 8) & 0xff) == 'M') {
+ if (cmd & IOC_IN)
+ switch (cmd & 0xff) {
+ case SOUND_MIXER_RECSRC:
+ return *(int *) arg = ad1848_set_recmask(devc, (*(int *) arg));
+ break;
- if (((cmd >> 8) & 0xff) == 'M')
- {
- if (cmd & IOC_IN)
- switch (cmd & 0xff)
- {
- case SOUND_MIXER_RECSRC:
- return IOCTL_OUT (arg, ad1848_set_recmask (devc, IOCTL_IN (arg)));
- break;
-
- default:
- return IOCTL_OUT (arg, ad1848_mixer_set (devc, cmd & 0xff, IOCTL_IN (arg)));
- }
- else
- switch (cmd & 0xff) /*
- * Return parameters
- */
- {
-
- case SOUND_MIXER_RECSRC:
- return IOCTL_OUT (arg, devc->recmask);
- break;
-
- case SOUND_MIXER_DEVMASK:
- return IOCTL_OUT (arg, devc->supported_devices);
- break;
-
- case SOUND_MIXER_STEREODEVS:
- return IOCTL_OUT (arg, devc->supported_devices &
- ~(SOUND_MASK_SPEAKER | SOUND_MASK_IMIX));
- break;
-
- case SOUND_MIXER_RECMASK:
- return IOCTL_OUT (arg, devc->supported_rec_devices);
- break;
-
- case SOUND_MIXER_CAPS:
- return IOCTL_OUT (arg, SOUND_CAP_EXCL_INPUT);
- break;
-
- default:
- return IOCTL_OUT (arg, ad1848_mixer_get (devc, cmd & 0xff));
- }
- }
- else
- return RET_ERROR (EINVAL);
+ default:
+ return *(int *) arg = ad1848_mixer_set(devc, cmd & 0xff, (*(int *) arg));
+ }
+ else
+ switch (cmd & 0xff) { /* Return parameters */
+
+ case SOUND_MIXER_RECSRC:
+ return *(int *) arg = devc->recmask;
+ break;
+
+ case SOUND_MIXER_DEVMASK:
+ return *(int *) arg = devc->supported_devices;
+ break;
+
+ case SOUND_MIXER_STEREODEVS:
+ return *(int *) arg = devc->supported_devices & ~(SOUND_MASK_SPEAKER | SOUND_MASK_IMIX);
+ break;
+
+ case SOUND_MIXER_RECMASK:
+ return *(int *) arg = devc->supported_rec_devices;
+ break;
+
+ case SOUND_MIXER_CAPS:
+ return *(int *) arg = SOUND_CAP_EXCL_INPUT;
+ break;
+
+ default:
+ return *(int *) arg = ad1848_mixer_get(devc, cmd & 0xff);
+ }
+ } else
+ return -(EINVAL);
}
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
- }};
+ {
+ "Generic AD1848 codec",
+ /* DMA_AUTOMODE | DMA_DUPLEX, */
+ 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,
+ ad1848_halt_input,
+ ad1848_halt_output,
+ ad1848_trigger
+ }
+};
static struct mixer_operations ad1848_mixer_operations =
{
- "AD1848/CS4248/CS4231",
- ad1848_mixer_ioctl
+ "AD1848/CS4248/CS4231",
+ ad1848_mixer_ioctl
};
static int
-ad1848_open (int dev, int mode)
+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);
+ ad1848_info *devc = NULL;
+ u_long flags;
+ int otherside = audio_devs[dev]->otherside;
- devc = (ad1848_info *) audio_devs[dev]->devc;
+ if (dev < 0 || dev >= num_audiodevs)
+ return -(ENXIO);
- DISABLE_INTR (flags);
- if (devc->opened)
- {
- RESTORE_INTR (flags);
- printk ("ad1848: Already opened\n");
- return RET_ERROR (EBUSY);
+ if (otherside != -1) {
+ if (audio_devs[otherside]->busy)
+ return -(EBUSY);
}
+ if (audio_devs[dev]->busy)
+ return -(EBUSY);
- if (devc->irq) /* Not managed by another driver */
- if ((err = snd_set_irq_handler (devc->irq, ad1848_interrupt,
- audio_devs[dev]->name)) < 0)
- {
- printk ("ad1848: IRQ in use\n");
- RESTORE_INTR (flags);
- return err;
- }
+ devc = (ad1848_info *) audio_devs[dev]->devc;
- if (DMAbuf_open_dma (dev) < 0)
- {
- RESTORE_INTR (flags);
- printk ("ad1848: DMA in use\n");
- return RET_ERROR (EBUSY);
+ flags = splhigh();
+ if (audio_devs[dev]->busy) {
+ splx(flags);
+ return -(EBUSY);
}
+ devc->dual_dma = 0;
- devc->intr_active = 0;
- devc->opened = 1;
- RESTORE_INTR (flags);
-
- return 0;
+ if (audio_devs[dev]->flags & DMA_DUPLEX) {
+ devc->dual_dma = 1;
+ }
+ devc->intr_active = 0;
+ audio_devs[dev]->busy = 1;
+ devc->irq_mode = 0;
+ ad1848_trigger(dev, 0);
+ splx(flags);
+ /*
+ * Mute output until the playback really starts. This decreases
+ * clicking.
+ */
+ ad_mute(devc);
+
+ return 0;
}
static void
-ad1848_close (int dev)
+ad1848_close(int dev)
{
- unsigned long flags;
- ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+ u_long flags;
+ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+ int otherside = audio_devs[dev]->otherside;
+
+ if (otherside != -1) {
+ if (audio_devs[otherside]->busy)
+ return;
+ }
+ DEB(printf("ad1848_close(void)\n"));
+
+ flags = splhigh();
- DEB (printk ("ad1848_close(void)\n"));
+ ad_mute(devc);
- DISABLE_INTR (flags);
+ ad_write(devc, 9, ad_read(devc, 9) & ~0x1);
+ outb(io_Status(devc), 0); /* Clear interrupt status */
+ /*
+ * ad_write (devc, 15,0); ad_write (devc, 14,0);
+ */
+ devc->irq_mode &= ~PCM_ENABLE_OUTPUT;
- 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;
+ devc->intr_active = 0;
+ ad1848_reset(dev);
- RESTORE_INTR (flags);
+ devc->opened = 0;
+ devc->irq_mode = 0;
+ audio_devs[dev]->busy = 0;
+ ad_unmute(devc);
+ splx(flags);
}
static int
-set_speed (ad1848_info * devc, int arg)
+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 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;
+ */
+ typedef struct {
+ int speed;
+ u_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 (devc->mode == MD_1845) { /* AD1845 has different timer than others */
+ RANGE (arg, 4000, 50000) ;
+
+ devc->speed = arg;
+ devc->speed_bits = speed_table[selected].bits;
+ return devc->speed;
}
-
- devc->speed = speed_table[selected].speed;
- devc->speed_bits = speed_table[selected].bits;
- return devc->speed;
+ 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) {
+ printf("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)
+set_channels(ad1848_info * devc, int arg)
{
- if (arg != 1 && arg != 2)
- return devc->channels;
+ if (arg != 1 && arg != 2)
+ return devc->channels;
- devc->channels = arg;
- return arg;
+ devc->channels = arg;
+ return arg;
}
static int
-set_format (ad1848_info * devc, int arg)
+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 struct format_tbl {
+ int format;
+ u_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;
}
+/* XXX check what is arg, (int) or *(int *) lr970705 */
static int
-ad1848_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
+ad1848_ioctl(int dev, u_int cmd, ioctl_arg arg, int local)
{
- ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
- switch (cmd)
- {
+ switch (cmd) {
case SOUND_PCM_WRITE_RATE:
- if (local)
- return set_speed (devc, arg);
- return IOCTL_OUT (arg, set_speed (devc, IOCTL_IN (arg)));
+ if (local)
+ return set_speed(devc, (int) arg);
+ return *(int *) arg = set_speed(devc, (*(int *) arg));
case SOUND_PCM_READ_RATE:
- if (local)
- return devc->speed;
- return IOCTL_OUT (arg, devc->speed);
+ if (local)
+ return devc->speed;
+ return *(int *) 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);
+ if (local)
+ return set_channels(devc, (int) arg + 1) - 1;
+ return *(int *) arg = set_channels(devc, (*(int *) 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)));
+ if (local)
+ return set_channels(devc, (int) arg);
+ return *(int *) arg = set_channels(devc, (*(int *) arg));
case SOUND_PCM_READ_CHANNELS:
- if (local)
- return devc->channels;
- return IOCTL_OUT (arg, devc->channels);
+ if (local)
+ return devc->channels;
+ return *(int *) arg = devc->channels;
case SNDCTL_DSP_SAMPLESIZE:
- if (local)
- return set_format (devc, arg);
- return IOCTL_OUT (arg, set_format (devc, IOCTL_IN (arg)));
+ if (local)
+ return set_format(devc, (int) arg);
+ return *(int *) arg = set_format(devc, (*(int *) arg));
case SOUND_PCM_READ_BITS:
- if (local)
- return devc->audio_format;
- return IOCTL_OUT (arg, devc->audio_format);
+ if (local)
+ return devc->audio_format;
+ return *(int *) arg = devc->audio_format;
+
+
+ case FIOASYNC:
+ if (local)
+ return 1;
+ return *(int *) arg = 1;
+
+ case FIONBIO:
+ if (local)
+ return 1;
+ return *(int *) arg = 1;
+
default:;
}
- return RET_ERROR (EINVAL);
+ return -(EINVAL);
}
static void
-ad1848_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
+ad1848_output_block(int dev, u_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;
+ u_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;
}
- else
- {
- if (devc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */
+ if (devc->channels > 1)
cnt >>= 1;
- }
- if (devc->channels > 1)
- cnt >>= 1;
- cnt--;
+ cnt--;
+ if (mute_flag)
+ ad_unmute(devc);
- 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 ( devc->irq_mode & PCM_ENABLE_OUTPUT &&
+ audio_devs[dev]->flags & DMA_AUTOMODE && intrflag &&
+ cnt == devc->xfer_count) {
+ devc->irq_mode |= PCM_ENABLE_OUTPUT;
+ devc->intr_active = 1;
- if (dma_restart)
- {
- /* ad1848_halt (dev); */
- DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
}
+ flags = splhigh();
- ad_enter_MCE (devc);
-
- ad_write (devc, 15, (unsigned char) (cnt & 0xff));
- ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff));
+ if (dma_restart) {
- ad_write (devc, 9, 0x0d); /*
- * Playback enable, single DMA channel mode,
- * auto calibration on.
- */
-
- ad_leave_MCE (devc); /*
- * Starts the calibration process and
- * enters playback mode after it.
- */
- ad_unmute (devc);
+ DMAbuf_start_dma(dev, buf, count, 1);
+ }
+ ad_write(devc, 15, (u_char) (cnt & 0xff));
+ ad_write(devc, 14, (u_char) ((cnt >> 8) & 0xff));
- devc->xfer_count = cnt;
- devc->irq_mode = IMODE_OUTPUT;
- devc->intr_active = 1;
- INB (io_Status (devc));
- OUTB (0, io_Status (devc)); /* Clear pending interrupts */
- RESTORE_INTR (flags);
+ devc->xfer_count = cnt;
+ devc->irq_mode |= PCM_ENABLE_OUTPUT;
+ devc->intr_active = 1;
+ splx(flags);
}
static void
-ad1848_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
+ad1848_start_input(int dev, u_long buf, int count,
+ int intrflag, int dma_restart)
{
- unsigned long flags, cnt;
- ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+ u_long flags, cnt;
+ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
- int count_reg = 14; /* (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 = 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 ( devc->irq_mode & PCM_ENABLE_INPUT &&
+ audio_devs[dev]->flags & DMA_AUTOMODE && intrflag &&
+ cnt == devc->xfer_count) {
+ devc->irq_mode |= PCM_ENABLE_INPUT;
+ devc->intr_active = 1;
+ return; /* Auto DMA mode on. No need to react */
}
- if (devc->channels > 1)
- cnt >>= 1;
- cnt--;
+ flags = splhigh();
- 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
- */
+ if (dma_restart) {
+ /* ad1848_halt (dev); */
+ DMAbuf_start_dma(dev, buf, count, 0);
}
- DISABLE_INTR (flags);
-
- if (dma_restart)
- {
- /* ad1848_halt (dev); */
- DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
+ if (devc->mode == MD_1848 || !devc->dual_dma) {/* Single DMA chan. mode */
+ ad_write(devc, 15, (u_char) (cnt & 0xff));
+ ad_write(devc, 14, (u_char) ((cnt >> 8) & 0xff));
+ } else { /* Dual DMA channel mode */
+ ad_write(devc, 31, (u_char) (cnt & 0xff));
+ ad_write(devc, 30, (u_char) ((cnt >> 8) & 0xff));
}
- ad_enter_MCE (devc);
-
- ad_write (devc, count_reg + 1, (unsigned char) (cnt & 0xff));
- ad_write (devc, count_reg, (unsigned char) ((cnt >> 8) & 0xff));
-
- ad_write (devc, 9, 0x0e); /*
- * Capture enable, single DMA channel mode,
- * auto calibration on.
- */
+ /* ad_write (devc, 9, ad_read (devc, 9) | 0x02); *//* Capture enable */
+ ad_unmute(devc);
- ad_leave_MCE (devc); /*
- * Starts the calibration process and
- * enters playback mode after it.
- */
- ad_unmute (devc);
-
- devc->xfer_count = cnt;
- devc->irq_mode = IMODE_INPUT;
- devc->intr_active = 1;
- INB (io_Status (devc));
- OUTB (0, io_Status (devc)); /* Clear interrupt status */
- RESTORE_INTR (flags);
+ devc->xfer_count = cnt;
+ devc->irq_mode |= PCM_ENABLE_INPUT;
+ devc->intr_active = 1;
+ splx(flags);
}
static int
-ad1848_prepare_for_IO (int dev, int bsize, int bcount)
+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_enter_MCE (devc); /* 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;
-#ifdef PC98
- while (timeout > 0 && (INB (devc->base) & 0x80) == 0x80)
-#else
- while (timeout > 0 && INB (devc->base) == 0x80)
-#endif
- timeout--;
-
-#ifdef PC98
- ad_write (devc, 8, fs);
- /*
- * Write to I8 starts resyncronization. Wait until it completes.
- */
- timeout = 10000;
- while (timeout > 0 && (INB (devc->base) & 0x80) == 0x80)
- timeout--;
-#endif
+ int timeout;
+ u_char fs, old_fs;
+ u_long flags;
+ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
- /*
- * If mode == 2 (CS4231), set I28 also. It's the capture format register.
- */
- if (devc->mode == 2)
- {
- ad_write (devc, 28, fs);
-
- /*
- * Write to I28 starts resyncronization. Wait until it completes.
- */
- timeout = 10000;
-#ifdef PC98
- while (timeout > 0 && (INB (devc->base) & 0x80) == 0x80)
-#else
- while (timeout > 0 && INB (devc->base) == 0x80)
-#endif
- timeout--;
+ if (devc->irq_mode)
+ return 0;
+
+ flags = splhigh();
+ fs = devc->speed_bits | (devc->format_bits << 5);
+ if (devc->channels > 1)
+ fs |= 0x10;
+ old_fs = fs;
+ if (devc->mode == MD_1845) { /* Use alternate speed select regs */
+ fs &= 0xf0; /* Mask off the rate select bits */
+
+ ad_write(devc, 22, (devc->speed >> 8) & 0xff); /* Speed MSB */
+ ad_write(devc, 23, devc->speed & 0xff); /* Speed LSB */
}
-#ifdef PC98
- ad_write (devc, 28, fs);
+ ad_enter_MCE(devc); /* Enables changes to the format select reg */
+ ad_write(devc, 8, fs);
+
+ /*
+ * Write to I8 starts resyncronization. Wait until it completes.
+ */
+ AD_WAIT_INIT(10000);
+
+ /*
+ * If mode == 2 (CS4231), set I28 also. It's the capture format
+ * register.
+ */
+ if (devc->mode != MD_1848) {
+ ad_write(devc, 28, fs);
+
+ /*
+ * Write to I28 starts resyncronization. Wait until it completes.
+ */
+ AD_WAIT_INIT(10000);
+ }
+ ad_leave_MCE(devc); /* Starts the calibration process. */
+
+ /* amancio */
+ ad_enter_MCE(devc); /* Enables changes to the format select reg */
+
+ ad_write(devc, 8, fs);
+ /*
+ * Write to I8 starts resyncronization. Wait until it completes.
+ */
+ AD_WAIT_INIT(10000);
+ ad_write(devc, 9, ad_read(devc, 9) & ~0x08);
+ /* ad_write (devc, 9, ad_read (devc, 9) | 0x08); */
+
+ /*
+ * If mode == 2 (CS4231), set I28 also. It's the capture format
+ * register.
+ */
+ if (devc->mode != MD_1848) {
+ ad_write(devc, 28, fs);
+
+ /*
+ * Write to I28 starts resyncronization. Wait until it
+ * completes.
+ */
+ AD_WAIT_INIT(10000);
+ }
- /*
- * Write to I28 starts resyncronization. Wait until it completes.
- */
- timeout = 10000;
- while (timeout > 0 && (INB (devc->base) & 0x80) == 0x80)
- timeout--;
+ ad_leave_MCE(devc); /* Starts the calibration process. */
+ /* amancio */
+ splx(flags);
+ devc->xfer_count = 0;
+#ifdef CONFIG_SEQUENCER
+ if (dev == timer_installed && devc->timer_running)
+ if ((fs & 0x01) != (old_fs & 0x01)) {
+ ad1848_tmr_reprogram(dev);
+ }
#endif
-
- ad_leave_MCE (devc); /*
- * Starts the calibration process and
- * enters playback mode after it.
- */
- RESTORE_INTR (flags);
- devc->xfer_count = 0;
- return 0;
+ return 0;
}
static void
-ad1848_reset (int dev)
+ad1848_reset(int dev)
{
- ad1848_halt (dev);
+ ad1848_halt(dev);
}
static void
-ad1848_halt (int dev)
+ad1848_halt(int dev)
{
- ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+ u_long flags;
+ int timeout;
+ flags = splhigh();
+
+ ad_mute(devc);
+ ad_enter_MCE(devc);
+ ad_write(devc, 9, ad_read(devc, 9) & ~0x03); /* Stop DMA */
+ ad_write(devc, 9, ad_read(devc, 9) | 0x8);
+
+ ad_write(devc, 9, ad_read(devc, 9) & ~0x03); /* Stop DMA */
+ /*
+ * ad_write (devc, 15, 0); Clear DMA counter ad_write (devc,
+ * 14, 0); Clear DMA counter
+ */
+
+ if (devc->mode != MD_1848) {
+ ad_write(devc, 30, 0); /* Clear DMA counter */
+ ad_write(devc, 31, 0); /* Clear DMA counter */
+ }
+ for (timeout = 0; timeout < 1000 && !(inb(io_Status(devc)) & 0x80);
+ timeout++); /* Wait for interrupt */
- ad_mute (devc);
-#ifdef PC98
- ad_enter_MCE (devc);
-#endif
- ad_write (devc, 9, ad_read (devc, 9) & ~0x03); /* Stop DMA */
-#ifdef PC98
- ad_leave_MCE (devc);
-#endif
- OUTB (0, io_Status (devc)); /* Clear interrupt status */
+ ad_write(devc, 9, ad_read(devc, 9) & ~0x03); /* Stop DMA */
+ outb(io_Status(devc), 0); /* Clear interrupt status */
+ outb(io_Status(devc), 0); /* Clear interrupt status */
+ devc->irq_mode = 0;
+ ad_leave_MCE(devc);
- ad_enter_MCE (devc);
- OUTB (0, io_Status (devc)); /* Clear interrupt status */
- ad_write (devc, 15, 0); /* Clear DMA counter */
- ad_write (devc, 14, 0); /* Clear DMA counter */
+ /* DMAbuf_reset_dma (dev); */
+ splx(flags);
+}
- if (devc->mode == 2)
- {
- ad_write (devc, 30, 0); /* Clear DMA counter */
- ad_write (devc, 31, 0); /* Clear DMA counter */
+static void
+ad1848_halt_input(int dev)
+{
+ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+ u_long flags;
+ u_char playing;
+ if (devc->mode == MD_1848) {
+ ad1848_halt(dev);
+ return;
}
+ playing = ad_read(devc, 9);
+ if (!(playing & 0x2))
+ return;
- ad_write (devc, 9, ad_read (devc, 9) & ~0x03); /* Stop DMA */
+ flags = splhigh();
- OUTB (0, io_Status (devc)); /* Clear interrupt status */
- OUTB (0, io_Status (devc)); /* Clear interrupt status */
- ad_leave_MCE (devc);
+ ad_mute(devc);
+ ad_write(devc, 9, playing & ~0x02); /* Stop capture */
- DMAbuf_reset_dma (dev);
-}
+ outb(io_Status(devc), 0); /* Clear interrupt status */
+ outb(io_Status(devc), 0); /* Clear interrupt status */
-int
-ad1848_detect (int io_base)
-{
+ devc->irq_mode &= ~PCM_ENABLE_INPUT;
- unsigned char tmp;
- int i;
- ad1848_info *devc = &dev_info[nr_ad1848_devs];
- unsigned char tmp1 = 0xff, tmp2 = 0xff;
+ splx(flags);
+}
- if (nr_ad1848_devs >= MAX_AUDIO_DEV)
- {
- AUDIO_DDB (printk ("ad1848 detect error - step 0\n"));
- return 0;
+static void
+ad1848_halt_output(int dev)
+{
+ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+ u_long flags;
+ u_char playing;
+
+ playing = ad_read(devc, 9);
+ if (!(playing & 0x1)) {
+ devc->irq_mode &= ~PCM_ENABLE_OUTPUT;
+ return;
+ }
+ /* IwaveStopDma(PLAYBACK); */
+ if (devc->mode == MD_1848) {
+ ad1848_halt(dev);
+ return;
}
+ flags = splhigh();
+ /* ad_mute (devc); */
- 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 */
+ ad_write(devc, 9, playing & ~0x1);
+ outb(io_Status(devc), 0); /* Clear interrupt status */
+ /*
+ * ad_write (devc, 15,0); ad_write (devc, 14,0);
+ */
+ devc->irq_mode &= ~PCM_ENABLE_OUTPUT;
- /*
- * 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.
- */
+ splx(flags);
+}
- if ((INB (devc->base) & 0x80) != 0x00) /* Not a AD1884 */
- {
- AUDIO_DDB (printk ("ad1848 detect error - step A\n"));
- return 0;
+static void
+ad1848_trigger(int dev, int state)
+{
+ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+ u_long flags;
+ u_char tmp;
+
+ flags = splhigh();
+ state &= devc->irq_mode;
+
+ tmp = ad_read(devc, 9) & ~0x03;
+ if (state & PCM_ENABLE_INPUT)
+ tmp |= 0x02;
+ if (state & PCM_ENABLE_OUTPUT) {
+ tmp |= 0x01;
}
+ ad_write(devc, 9, tmp);
- /*
- * 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.
- */
+ splx(flags);
+}
- ad_write (devc, 0, 0xaa);
- ad_write (devc, 1, 0x45); /* 0x55 with bit 0x10 clear */
- if ((tmp1 = ad_read (devc, 0)) != 0xaa || (tmp2 = ad_read (devc, 1)) != 0x45)
- {
- AUDIO_DDB (printk ("ad1848 detect error - step B (%x/%x)\n", tmp1, tmp2));
- return 0;
+int
+ad1848_detect(int io_base, int *ad_flags, sound_os_info * osp)
+{
+ static int last_probe_addr=0, last_result=0; /* to avoid multiple probes*/
+ int i;
+ ad1848_info *devc = &dev_info[nr_ad1848_devs];
+ u_char tmp, tmp1, tmp2 ;
+
+ DDB(printf("ad1848_detect(%x)\n", io_base));
+ if (io_base == last_probe_addr)
+ return last_result;
+ else {
+ last_result = 0; /* default value for detect */
+ last_probe_addr = io_base ;
}
- ad_write (devc, 0, 0x45);
- ad_write (devc, 1, 0xaa);
+ if (ad_flags)
+ *ad_flags = 0;
- if ((tmp1 = ad_read (devc, 0)) != 0x45 || (tmp2 = ad_read (devc, 1)) != 0xaa)
- {
- AUDIO_DDB (printk ("ad1848 detect error - step C (%x/%x)\n", tmp1, tmp2));
- return 0;
+ if (nr_ad1848_devs >= MAX_AUDIO_DEV) {
+ DDB(printf("ad1848 detect error - step 0\n"));
+ return 0 ;
}
+ devc->base = io_base;
+ devc->irq_ok = 0;
+ devc->timer_running = 0;
+ devc->MCE_bit = 0x40;
+ devc->irq = 0;
+ devc->opened = 0;
+ devc->chip_name = "AD1848";
+ devc->mode = MD_1848; /* AD1848 or CS4248 */
+ devc->osp = osp;
+
+ /*
+ * 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.
+ */
- /*
- * 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);
+ DDB(printf("ad1848_detect() - step A\n"));
- if ((tmp & 0x0f) != ((tmp1 = ad_read (devc, 12)) & 0x0f))
- {
- AUDIO_DDB (printk ("ad1848 detect error - step D (%x)\n", tmp1));
- return 0;
+ if ((inb(devc->base) & 0x80) != 0x00) { /* Not a AD1848 */
+ DDB(printf("ad1848 detect error - step A,"
+ " inb(base) = 0x%02x, want 0XXX.XXXX\n",
+ inb(devc->base)));
+ 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.
+ */
+
+ DDB(printf("ad1848_detect() - step B, test indirect register\n"));
+
+ ad_write(devc, 0, 0xaa);
+ ad_write(devc, 1, 0x45);/* 0x55 with bit 0x10 clear */
+ tmp1 = ad_read(devc, 0) ;
+ tmp2 = ad_read(devc, 1) ;
+ if ( tmp1 != 0xaa || tmp2 != 0x45) {
+ DDB(printf("ad1848 detect error - step B (0x%02x/0x%02x) want 0xaa/0x45\n", tmp1, tmp2));
+ return 0;
+ }
+ DDB(printf("ad1848_detect() - step C\n"));
+ ad_write(devc, 0, 0x45);
+ ad_write(devc, 1, 0xaa);
+ tmp1 = ad_read(devc, 0) ;
+ tmp2 = ad_read(devc, 1) ;
- /*
- * NOTE! Last 4 bits of the reg I12 tell the chip revision.
- * 0x01=RevB and 0x0A=RevC.
- */
+ if (tmp1 != 0x45 || tmp2 != 0xaa) {
+ DDB(printf("ad1848 detect error - step C (%x/%x)\n", tmp1, tmp2));
- /*
- * 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.
- */
+ return 0;
+ }
+ /*
+ * The indirect register I12 has some read only bits. Lets try to
+ * change them.
+ */
+
+ DDB(printf("ad1848_detect() - step D, last 4 bits of I12 readonly\n"));
+ tmp = ad_read(devc, 12);
+ ad_write(devc, 12, (~tmp) & 0x0f);
+ tmp1 = ad_read(devc, 12);
+
+ if ((tmp & 0x0f) != (tmp1 & 0x0f)) {
+ DDB(printf("ad1848 detect error - step D, I12 (0x%02x was 0x%02x)\n",
+ tmp1, tmp));
+ return 0;
+ }
- ad_write (devc, 12, 0); /* Mode2=disabled */
+ /*
+ * NOTE! Last 4 bits of the reg I12 tell the chip revision.
+ * 0x01=RevB
+ * 0x0A=RevC. also CS4231/CS4231A and OPTi931
+ */
- for (i = 0; i < 16; i++)
- if ((tmp1 = ad_read (devc, i)) != (tmp2 = ad_read (devc, i + 16)))
- {
- AUDIO_DDB (printk ("ad1848 detect error - step F(%d/%x/%x)\n", i, tmp1, tmp2));
- return 0;
- }
- /*
- * Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit (0x40).
- * The bit 0x80 is always 1 in CS4248 and CS4231.
- */
+ /*
+ * 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.
+ */
+
+ DDB(printf("ad1848_detect() - step F\n"));
+ 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(printf("ad1848 detect warning - step F(I%d/0x%02x/0x%02x)\n",
+ i, tmp1, tmp2));
+ /*
+ * note - this seems to fail on the 4232 on I11. So we just break
+ * rather than fail.
+ */
+ break ; /* 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.
+ *
+ * On the OPTi931, however, I12 is readonly and only contains the
+ * chip revision ID (as in the CS4231A). The upper bits return 0.
+ */
- ad_write (devc, 12, 0x40); /* Set mode2, clear 0x80 */
+ DDB(printf("ad1848_detect() - step G\n"));
+ ad_write(devc, 12, 0x40); /* Set mode2, clear 0x80 */
- tmp1 = ad_read (devc, 12);
- if (tmp1 & 0x80)
- devc->chip_name = "CS4248"; /* Our best knowledge just now */
+ tmp1 = ad_read(devc, 12);
+ if (tmp1 & 0x80) {
+ if (ad_flags)
+ *ad_flags |= AD_F_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? */
- {
- AUDIO_DDB (printk ("ad1848 detect error - step H(%x)\n", tmp1));
- return 0;
+ devc->chip_name = "CS4248"; /* Our best knowledge just now */
+ }
+ if ((tmp1 & 0xf0) == 0x00) {
+ printf("this should be an OPTi931\n");
+ } else if ((tmp1 & 0xc0) == 0xC0) {
+ /*
+ * The 4231 has bit7=1 always, and bit6 we just set to 1.
+ * We want to check that this is really a CS4231
+ * Verify that setting I0 doesn't change I16.
+ */
+ DDB(printf("ad1848_detect() - step H\n"));
+ 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(printf("ad1848 detect error - step H(%x)\n", tmp1));
+ return 0;
}
-
- /*
+ /*
* Verify that some bits of I25 are read only.
- */
-
- tmp1 = ad_read (devc, 25); /* Original bits */
- ad_write (devc, 25, ~tmp1); /* Invert all bits */
- if ((ad_read (devc, 25) & 0xe7) == (tmp1 & 0xe7))
- {
- /*
- * It's a CS4231
- */
- devc->chip_name = "CS4231";
-
-
-#ifdef MOZART_PORT
- if (devc->base != MOZART_PORT)
-#endif
- devc->mode = 2;
-
-
+ */
+
+ DDB(printf("ad1848_detect() - step I\n"));
+ tmp1 = ad_read(devc, 25); /* Original bits */
+ ad_write(devc, 25, ~tmp1); /* Invert all bits */
+ if ((ad_read(devc, 25) & 0xe7) == (tmp1 & 0xe7)) {
+ int id;
+
+ /*
+ * It's at least CS4231
+ */
+ devc->chip_name = "CS4231";
+ devc->mode = MD_4231;
+
+ /*
+ * It could be an AD1845 or CS4231A as well.
+ * CS4231 and AD1845 report the same revision info in I25
+ * while the CS4231A reports different.
+ */
+
+ DDB(printf("ad1848_detect() - step I\n"));
+ id = ad_read(devc, 25) & 0xe7;
+ /*
+ * b7-b5 = version number;
+ * 100 : all CS4231
+ * 101 : CS4231A
+ *
+ * b2-b0 = chip id;
+ */
+ switch (id) {
+
+ case 0xa0:
+ devc->chip_name = "CS4231A";
+ devc->mode = MD_4231A;
+ break;
+
+ case 0xa2:
+ devc->chip_name = "CS4232";
+ devc->mode = MD_4231A;
+ break;
+
+ case 0xb2:
+ /* strange: the 4231 data sheet says b4-b3 are XX
+ * so this should be the same as 0xa2
+ */
+ devc->chip_name = "CS4232A";
+ devc->mode = MD_4231A;
+ break;
+
+ case 0x80:
+ /*
+ * It must be a CS4231 or AD1845. The register I23
+ * of CS4231 is undefined and it appears to be read
+ * only. AD1845 uses I23 for setting sample rate.
+ * Assume the chip is AD1845 if I23 is changeable.
+ */
+
+ tmp = ad_read(devc, 23);
+
+ ad_write(devc, 23, ~tmp);
+ if (ad_read(devc, 23) != tmp) { /* AD1845 ? */
+ devc->chip_name = "AD1845";
+ devc->mode = MD_1845;
+ }
+ ad_write(devc, 23, tmp); /* Restore */
+ break;
+
+ case 0x83: /* CS4236 */
+ default: /* Assume CS4231 */
+ printf("unknown id 0x%02x, assuming CS4231\n", id);
+ devc->mode = MD_4231;
+
+ }
}
- ad_write (devc, 25, tmp1); /* Restore bits */
+ ad_write(devc, 25, tmp1); /* Restore bits */
+
+ DDB(printf("ad1848_detect() - step K\n"));
}
}
+ DDB(printf("ad1848_detect() - step L\n"));
- return 1;
+ if (ad_flags) {
+ if (devc->mode != MD_1848)
+ *ad_flags |= AD_F_CS4231;
+ }
+ DDB(printf("ad1848_detect() - Detected OK\n"));
+ return (last_result = 1);
}
void
-ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture)
+ad1848_init(char *name, int io_base, int irq,
+ int dma_playback, int dma_capture, int share_dma, sound_os_info * osp)
{
- /*
- * NOTE! If irq < 0, there is another driver which has allocated the IRQ
- * so that this driver doesn't need to allocate/deallocate it.
- * The actually used IRQ is ABS(irq).
- */
- /*
+ /*
+ * NOTE! If irq < 0, there is another driver which has allocated the
+ * IRQ so that this driver doesn't need to allocate/deallocate it.
+ * The actually used IRQ is ABS(irq).
+ */
+
+ /*
* Initial values for the indirect registers of CS4248/AD1848.
- */
- static int init_values[] =
- {
- 0xa8, 0xa8, 0x08, 0x08, 0x08, 0x08, 0x80, 0x80,
- 0x00, 0x08, 0x02, 0x00, 0x8a, 0x01, 0x00, 0x00,
-
- /* Positions 16 to 31 just for CS4231 */
- 0x80, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
- };
- int i, my_dev;
- ad1848_info *devc = &dev_info[nr_ad1848_devs];
-
- 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));
+ */
+ static int init_values[] = {
+ 0xa8, /* MIXOUTL: src:mic, +20dB, gain +12dB */
+ 0xa8, /* MIXOUTR: src:mic, +20dB, gain +12dB */
+ 0x08, /* CDL Input: mute, +6dB */
+ 0x08, /* CDR Input: mute, +6dB */
+ 0x08, /* FML Input: mute, +6dB */
+ 0x08, /* FMR Input: mute, +6dB */
+ 0x80, /* DAC-L Input: enable, 0dB */
+ 0x80, /* DAC-R Input: enable, 0dB */
+ /* 0xa8, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, */
+ 0x00, /* 8bit, lin, uns, mono, 8KHz */
+ 0x0c, /* dma-cap, dma-pb, autocal, single dma, disable cap/pb */
+ 0x02, /* int enable */
+ 0x00, /* clear error status */
+ 0x8a, /* rev. id (low bytes readonly) */
+ 0x00,
+ 0x00, /* playback upper base count */
+ 0x00, /* playback lower base count */
+
+ /* Positions 16 to 31 just for CS4231 and newer devices */
+ /* I16-I17: alt. feature enable on the 4231, but AUXL Input
+ * on the OPTi931 (where the features are set elsewhere
+ */
+ 0x81, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ int i, my_dev;
+
+ ad1848_info *devc = &dev_info[nr_ad1848_devs];
+
+ if (!ad1848_detect(io_base, NULL, osp))
+ return;
+
+ devc->irq = (irq > 0) ? irq : 0;
+ devc->opened = 0;
+ devc->timer_ticks = 0;
+ devc->osp = osp;
+
+ if (nr_ad1848_devs != 0) {
+ bcopy((char *) &ad1848_pcm_operations[0],
+ (char *) &ad1848_pcm_operations[nr_ad1848_devs],
+ sizeof(struct audio_operations));
}
+ for (i = 0; i < 16; i++)
+ ad_write(devc, i, init_values[i]);
+
+ ad_mute(devc); /* Initialize some variables */
+ ad_unmute(devc); /* Leave it unmuted now */
+
+ if (devc->mode > MD_1848) {
+ if (dma_capture == dma_playback ||
+ dma_capture == -1 || dma_playback == -1) {
+ ad_write(devc, 9, ad_read(devc, 9) | 0x04); /* Single DMA mode */
+ ad1848_pcm_operations[nr_ad1848_devs].flags &= ~DMA_DUPLEX;
+ } else {
+ ad_write(devc, 9, ad_read(devc, 9) & ~0x04); /* Dual DMA mode */
+ ad1848_pcm_operations[nr_ad1848_devs].flags |= DMA_DUPLEX;
+ }
- for (i = 0; i < 16; i++)
- ad_write (devc, i, init_values[i]);
+ ad_write(devc, 12, ad_read(devc, 12) | 0x40); /* Mode2 = enabled */
+ for (i = 16; i < 32; i++)
+ ad_write(devc, i, init_values[i]);
- ad_mute (devc);
+ if (devc->mode == MD_4231A) {
+ /* Enable full * calibration */
+ ad_write(devc, 9, init_values[9] | 0x18);
+ }
- if (devc->mode == 2)
- {
- ad_write (devc, 12, ad_read (devc, 12) | 0x40); /* Mode2 = enabled */
- for (i = 16; i < 32; i++)
- ad_write (devc, i, init_values[i]);
+ if (devc->mode == MD_1845) {
+ /* Alternate freq select enabled */
+ ad_write(devc, 27, init_values[27] | 0x08);
+ }
+ } else {
+ ad1848_pcm_operations[nr_ad1848_devs].flags &= ~DMA_DUPLEX;
+ ad_write(devc, 9, ad_read(devc, 9) | 0x04); /* Single DMA mode */
}
- OUTB (0, io_Status (devc)); /* Clear pending interrupts */
+ outb(io_Status(devc), 0); /* Clear pending interrupts */
+
+ if (name != NULL && name[0] != 0)
+ sprintf(ad1848_pcm_operations[nr_ad1848_devs].name,
+ "%s (%s)", name, devc->chip_name);
+ else
+ sprintf(ad1848_pcm_operations[nr_ad1848_devs].name,
+ "Generic audio codec (%s)", devc->chip_name);
+
+ conf_printf2(ad1848_pcm_operations[nr_ad1848_devs].name,
+ devc->base, devc->irq, dma_playback, dma_capture);
+
+
+ /* ad1848_pcm_operations[nr_ad1848_devs].flags |= DMA_AUTOMODE ; */
+
+ if (num_audiodevs < MAX_AUDIO_DEV) {
+ audio_devs[my_dev = num_audiodevs++] =
+ &ad1848_pcm_operations[nr_ad1848_devs];
+ if (irq > 0) {
+ audio_devs[my_dev]->devc = devc;
+ irq2dev[irq] = my_dev;
+ if (snd_set_irq_handler(devc->irq, ad1848_interrupt, devc->osp)<0) {
+ printf("ad1848: IRQ in use\n");
+ }
+#ifdef NO_IRQ_TEST
+ if (devc->mode != MD_1848) {
+ int x;
+ u_char tmp = ad_read(devc, 16);
+
+ devc->timer_ticks = 0;
+
+ ad_write(devc, 21, 0x00); /* Timer msb */
+ ad_write(devc, 20, 0x10); /* Timer lsb */
- if (name[0] != 0)
- sprintf (ad1848_pcm_operations[nr_ad1848_devs].name,
- "%s (%s)", name, devc->chip_name);
- else
- sprintf (ad1848_pcm_operations[nr_ad1848_devs].name,
- "Generic audio codec (%s)", devc->chip_name);
+ ad_write(devc, 16, tmp | 0x40); /* Enable timer */
+ for (x = 0; x < 100000 && devc->timer_ticks == 0; x++);
+ ad_write(devc, 16, tmp & ~0x40); /* Disable timer */
-#if defined(__FreeBSD__)
- if (strcmp(name, "MS Sound System")) /* *sigh* */
- printk ("\ngus0: <%s>", ad1848_pcm_operations[nr_ad1848_devs].name);
- else
- printk ("mss0: <%s>", ad1848_pcm_operations[nr_ad1848_devs].name);
+ if (devc->timer_ticks == 0)
+ printf("[IRQ conflict???]");
+ else
+ devc->irq_ok = 1;
+
+ } else
+ devc->irq_ok = 1; /* Couldn't test. assume it's OK */
#else
- printk (" <%s>", ad1848_pcm_operations[nr_ad1848_devs].name);
+ devc->irq_ok = 1;
+#endif
+ } else if (irq < 0)
+ irq2dev[-irq] = devc->dev_no = my_dev;
+
+ audio_devs[my_dev]->otherside = -1 ;
+ audio_devs[my_dev]->flags = DMA_AUTOMODE | DMA_DUPLEX;
+ audio_devs[my_dev]->dmachan1 = dma_playback;
+ audio_devs[my_dev]->dmachan2 = dma_capture;
+ audio_devs[my_dev]->buffsize = DSP_BUFFSIZE;
+ audio_devs[my_dev]->devc = devc;
+ audio_devs[my_dev]->format_mask = ad_format_mask[devc->mode];
+ nr_ad1848_devs++;
+
+#ifdef CONFIG_SEQUENCER
+ if (devc->mode != MD_1848 && devc->irq_ok)
+ ad1848_tmr_install(my_dev);
#endif
- 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;
- audio_devs[my_dev]->devc = devc;
- audio_devs[my_dev]->format_mask = ad_format_mask[devc->mode];
- nr_ad1848_devs++;
-
- /*
- * Toggle the MCE bit. It completes the initialization phase.
- */
-
- ad_enter_MCE (devc); /* In case the bit was off */
- ad_leave_MCE (devc);
-
- if (num_mixers < MAX_MIXER_DEV)
- {
- mixer2codec[num_mixers] = my_dev + 1;
- audio_devs[my_dev]->mixer_dev = num_mixers;
- mixer_devs[num_mixers++] = &ad1848_mixer_operations;
- ad1848_mixer_reset (devc);
+ /*
+ * Toggle the MCE bit. It completes the initialization phase.
+ */
+
+ ad_enter_MCE(devc); /* In case the bit was off */
+ ad_leave_MCE(devc);
+
+ if (num_mixers < MAX_MIXER_DEV) {
+ mixer2codec[num_mixers] = my_dev + 1;
+ audio_devs[my_dev]->mixer_dev = num_mixers;
+ mixer_devs[num_mixers++] = &ad1848_mixer_operations;
+ ad1848_mixer_reset(devc);
}
- }
- else
- printk ("AD1848: Too many PCM devices available\n");
+ } else
+ printf("AD1848: Too many PCM devices available\n");
}
void
-ad1848_interrupt (INT_HANDLER_PARMS (irq, dummy))
+ad1848_interrupt(int irq)
{
- unsigned char status;
- ad1848_info *devc;
- int dev;
+ u_char status;
+ ad1848_info *devc;
+ int dev;
+
+ if (irq < 0 || irq > 15)
+ dev = -1;
+ else
+ dev = irq2dev[irq];
+
+ if (dev < 0 || dev >= num_audiodevs) {
+ for (irq = 0; irq < 17; irq++)
+ if (irq2dev[irq] != -1)
+ break;
+
+ if (irq > 15) {
+ printf("ad1848.c: Bogus interrupt %d\n", irq);
+ return;
+ }
+ dev = irq2dev[irq];
+ }
+ devc = (ad1848_info *) audio_devs[dev]->devc;
+
+ status = inb(io_Status(devc));
+
+ if (status & 0x01) { /* we have an interrupt */
+ int alt_stat = 0xff ;
+
+ if (devc->mode != MD_1848) {
+ /*
+ * high-end devices have full-duplex dma and timer.
+ * the exact reason for the interrupt is in reg. I24.
+ * For old devices, we fake the interrupt bits, and
+ * determine the real reason basing on the device mode.
+ */
+ alt_stat = ad_read(devc, 24);
+ if (alt_stat & 0x40) { /* Timer interrupt */
+ devc->timer_ticks++;
+#ifdef CONFIG_SEQUENCER
+ if (timer_installed == dev && devc->timer_running)
+ sound_timer_interrupt();
+#endif
+ }
+ }
- if (irq < 0 || irq > 15)
- return; /* Bogus irq */
- dev = irq2dev[irq];
- if (dev < 0 || dev >= num_audiodevs)
- return; /* Bogus dev */
+ outb(io_Status(devc), 0); /* Clear interrupt status */
- devc = (ad1848_info *) audio_devs[dev]->devc;
- status = INB (io_Status (devc));
+ if (audio_devs[dev]->busy) {
- if (status == 0x80)
- printk ("ad1848_interrupt: Why?\n");
+ if (devc->irq_mode & PCM_ENABLE_OUTPUT && alt_stat & 0x10)
+ DMAbuf_outputintr(dev, 1);
- if (status & 0x01)
- {
- if (devc->opened && devc->irq_mode == IMODE_OUTPUT)
- {
- DMAbuf_outputintr (dev, 1);
+ if (devc->irq_mode & PCM_ENABLE_INPUT && alt_stat & 0x20)
+ DMAbuf_inputintr(dev);
}
-
- if (devc->opened && devc->irq_mode == IMODE_INPUT)
- DMAbuf_inputintr (dev);
}
+}
- OUTB (0, io_Status (devc)); /* Clear interrupt status */
+/*
+ * Some extra code for the MS Sound System
+ */
- status = INB (io_Status (devc));
- if (status == 0x80 || status & 0x01)
- {
- printk ("ad1848: Problems when clearing interrupt, status=%x\n", status);
- OUTB (0, io_Status (devc)); /* Try again */
- }
+#ifdef amancio
+void
+check_opl3(int base, struct address_info * hw_config)
+{
+
+ if (!opl3_detect(base, hw_config->osp))
+ return;
+
+ opl3_init(0, base, hw_config->osp);
}
+#endif
-#ifdef MOZART_PORT
/*
- * Experimental initialization sequence for Mozart soundcard
- * (OAK OTI-601 sound chip).
- * by Gregor Hoffleit <flight@mathi.uni-heidelberg.de>
- * Some comments by Hannu Savolainen.
+ * this is the probe routine. Note, it is not necessary to
+ * go through this for PnP devices, since they are already
+ * indentified precisely using their PnP id.
+ *
*/
int
-mozart_init (int io_base)
+probe_mss(struct address_info * hw_config)
{
- int i;
- unsigned char byte;
- static int mozart_detected_here = 0;
+ u_char tmp;
- /*
- * Valid ports are 0x530 and 0xf40. The DOS based software doesn't allow
- * other ports. The OTI-601 preliminary specification says that
- * 0xe80 and 0x604 are also possible but it's safest to ignore them.
- */
+ DDB(printf("Entered probe_mss(io 0x%x, type %d)\n",
+ hw_config->io_base, hw_config->card_subtype));
- if ((io_base != 0x530) && (io_base != 0xf40))
- {
- printk ("Mozart: invalid io_base(%x)\n", io_base);
- return 0;
+ if (hw_config->card_subtype == 1) { /* Has no IRQ/DMA registers */
+ /* check_opl3(0x388, hw_config); */
+ goto probe_ms_end;
}
- if (mozart_detected_here == io_base) /* Already detected this card */
- return 1;
-
- if (mozart_detected_here != 0)
- return 0; /* Don't allow detecting another Mozart card. */
+#if defined(CONFIG_AEDSP16) && defined(AEDSP16_MSS)
+ /*
+ * Initialize Audio Excel DSP 16 to MSS: before any operation we must
+ * enable MSS I/O ports.
+ */
+ InitAEDSP16_MSS(hw_config);
+#endif
- /*
- * The Mozart chip (OAK OTI-601) must be enabled before _each_ write
- * by writing a secret password (0xE2) to the password register (0xf8f).
- * Any I/O cycle after writing the password closes the gate and disbles
- * further access.
- */
+ /*
+ * Check if the IO port returns valid signature. The original MS
+ * Sound system returns 0x04 while some cards (AudioTriX Pro for
+ * example) return 0x00 or 0x0f.
+ */
- if (INB (0xf88) != 0) /* Appears to return 0 while the gate is closed */
- {
- AUDIO_DDB (printk ("No Mozart signature detected on port 0xf88\n"));
- return 0;
+ if ((tmp = inb(hw_config->io_base + 3)) == 0xff) { /* Bus float */
+ DDB(printf("I/O address inactive (%x), force type 1\n", tmp));
+ hw_config->card_subtype = 1 ;
+ goto probe_ms_end;
}
- OUTB (0xe2, 0xf8f); /* A secret password which opens the gate */
- OUTB (0x10, 0xf91); /* Enable access to codec registers during SB mode */
- for (i = 0; i < 100; i++) /* Delay */
- tenmicrosec ();
- OUTB (0xe2, 0xf8f); /* Sesam */
- byte = INB (0xf8d); /* Read MC1 (Mode control register) */
+ if ((tmp & 0x3f) != 0x04 &&
+ (tmp & 0x3f) != 0x0f &&
+ (tmp & 0x3f) != 0x00) {
+ DDB(printf("No MSS signature detected on port 0x%x (0x%x)\n",
+ hw_config->io_base, inb(hw_config->io_base + 3)));
+ return 0;
+ }
+ if (hw_config->irq > 11) {
+ printf("MSS: Bad IRQ %d\n", hw_config->irq);
+ return 0;
+ }
+ if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) {
+ printf("MSS: Bad DMA %d\n", hw_config->dma);
+ return 0;
+ }
+ /*
+ * Check that DMA0 is not in use with a 8 bit board.
+ */
- /* Read the same register again but with gate closed at this time. */
- if (INB (0xf8d) == 0xff) /* Bus float. Should be 0 if Mozart present */
- {
- AUDIO_DDB (printk ("Seems to be no Mozart chip set\n"));
- return 0;
+ if (hw_config->dma == 0 && inb(hw_config->io_base + 3) & 0x80) {
+ printf("MSS: Can't use DMA0 with a 8 bit card/slot\n");
+ return 0;
+ }
+ if (hw_config->irq > 7 && hw_config->irq != 9 &&
+ inb(hw_config->io_base + 3) & 0x80) {
+ printf("MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq);
+ return 0;
}
- AUDIO_DDB (printk ("mozart_init: read 0x%x on 0xf8d\n", byte));
- byte = byte | 0x80; /* Switch to WSS mode (disables SB) */
- byte = byte & 0xcf; /* Clear sound base, disable CD, enable joystick */
-
- if (io_base == 0xf40)
- byte = byte | 0x20;
- for (i = 0; i < 100; i++)
- tenmicrosec ();
- OUTB (0xe2, 0xf8f); /* Open the gate again */
- OUTB (byte, 0xf8d); /* Write the modified value back to MC1 */
- AUDIO_DDB (printk ("mozart_init: wrote 0x%x on 0xf8d\n", byte));
- OUTB (0xe2, 0xf8f); /* Here we come again */
- OUTB (0x20, 0xf91); /* Protect WSS shadow registers against write */
-
- for (i = 0; i < 1000; i++)
- tenmicrosec ();
-
- return 1;
+probe_ms_end:
+ return ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp);
}
-#endif /* MOZART_PORT */
+void
+attach_mss(struct address_info * hw_config)
+{
-#ifdef OPTI_MAD16_PORT
-#include <i386/isa/sound/mad16.h>
+#if 0
+ /*
+ * XXX do we really need to detect it again ? - lr970712
+ */
+ if (!ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp))
+ return ;
#endif
+ if (hw_config->card_subtype == 1) { /* Has no IRQ/DMA registers */
+ ad1848_init("MS Sound System1", hw_config->io_base + 4,
+ hw_config->irq,
+ hw_config->dma,
+ hw_config->dma2, 0, hw_config->osp);
+ } else {
+ /*
+ * Set the IRQ and DMA addresses.
+ */
+ static char interrupt_bits[12] = {
+ -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20
+ };
+ static char dma_bits[4] = {
+ 1, 2, 0, 3
+ };
+
+ int config_port = hw_config->io_base + 0;
+ int version_port = hw_config->io_base + 3;
+ char bits = interrupt_bits[hw_config->irq];
+
+ if (bits == -1)
+ return ;
+
+ outb(config_port, bits | 0x40);
+ if ((inb(version_port) & 0x40) == 0)
+ printf("[IRQ Conflict?]");
+
+ /* Write IRQ+DMA setup */
+ outb(config_port, bits | dma_bits[hw_config->dma]);
+
+ ad1848_init("MS Sound System0", hw_config->io_base + 4,
+ hw_config->irq,
+ hw_config->dma,
+ hw_config->dma, 0, hw_config->osp);
+ }
+ return ;
+}
+
/*
- * Some extra code for the MS Sound System
+ * WSS compatible PnP codec support.
+ * XXX I doubt it works now - lr970712
*/
int
-probe_ms_sound (struct address_info *hw_config)
+probe_pnp_ad1848(struct address_info * hw_config)
{
-#if !defined(EXCLUDE_AEDSP16) && defined(AEDSP16_MSS)
- /*
- * Initialize Audio Excel DSP 16 to MSS: before any operation
- * we must enable MSS I/O ports.
- */
-
- InitAEDSP16_MSS (hw_config);
-#endif
-
- /*
- * Check if the IO port returns valid signature. The original MS Sound
- * system returns 0x04 while some cards (AudioTriX Pro for example)
- * return 0x00.
- */
-
-#ifdef MOZART_PORT
- if (hw_config->io_base == MOZART_PORT)
- mozart_init (hw_config->io_base);
-#endif
-
-#ifdef OPTI_MAD16_PORT
- if (hw_config->io_base == OPTI_MAD16_PORT)
- mad16init (hw_config->io_base);
-#endif
+ return ad1848_detect(hw_config->io_base, NULL, hw_config->osp);
+}
- if ((INB (hw_config->io_base + 3) & 0x3f) != 0x04 &&
- (INB (hw_config->io_base + 3) & 0x3f) != 0x00)
- {
- AUDIO_DDB (printk ("No MSS signature detected on port 0x%x (0x%x)\n",
- hw_config->io_base, INB (hw_config->io_base + 3)));
- return 0;
- }
+void
+attach_pnp_ad1848(struct address_info * hw_config)
+{
-#ifdef PC98
- if (hw_config->irq > 12)
-#else
- if (hw_config->irq > 11)
-#endif
- {
- printk ("MSS: Bad IRQ %d\n", hw_config->irq);
- return 0;
- }
+ ad1848_init(hw_config->name, hw_config->io_base,
+ hw_config->irq,
+ hw_config->dma,
+ hw_config->dma2, 0, hw_config->osp);
+}
- if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3)
- {
- printk ("MSS: Bad DMA %d\n", hw_config->dma);
- return 0;
- }
+#ifdef CONFIG_SEQUENCER
+/*
+ * Timer stuff (for /dev/music).
+ */
- /*
- * Check that DMA0 is not in use with a 8 bit board.
- */
+static u_int current_interval = 0;
- if (hw_config->dma == 0 && INB (hw_config->io_base + 3) & 0x80)
- {
- printk ("MSS: Can't use DMA0 with a 8 bit card/slot\n");
- return 0;
- }
+static u_int
+ad1848_tmr_start(int dev, u_int usecs)
+{
+ u_long flags;
+ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
+ u_long xtal_nsecs; /* nanoseconds per xtal oscillaror tick */
+ u_long divider;
+
+ flags = splhigh();
+
+ /*
+ * Length of the timer interval (in nanoseconds) depends on the
+ * selected crystal oscillator. Check this from bit 0x01 of I8.
+ *
+ * AD1845 has just one oscillator which has cycle time of 10.050 us
+ * (when a 24.576 MHz xtal oscillator is used).
+ *
+ * Convert requested interval to nanoseconds before computing the timer
+ * divider.
+ */
+
+ if (devc->mode == MD_1845)
+ xtal_nsecs = 10050;
+ else if (ad_read(devc, 8) & 0x01)
+ xtal_nsecs = 9920;
+ else
+ xtal_nsecs = 9969;
+
+ divider = (usecs * 1000 + xtal_nsecs / 2) / xtal_nsecs;
+
+ if (divider < 100) /* Don't allow shorter intervals than about 1ms */
+ divider = 100;
+
+ if (divider > 65535) /* Overflow check */
+ divider = 65535;
+
+ ad_write(devc, 21, (divider >> 8) & 0xff); /* Set upper bits */
+ ad_write(devc, 20, divider & 0xff); /* Set lower bits */
+ ad_write(devc, 16, ad_read(devc, 16) | 0x40); /* Start the timer */
+ devc->timer_running = 1;
+ splx(flags);
+
+ return current_interval = (divider * xtal_nsecs + 500) / 1000;
+}
- if (hw_config->irq > 7 && hw_config->irq != 9 && INB (hw_config->io_base + 3) & 0x80)
- {
- printk ("MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq);
- return 0;
- }
+static void
+ad1848_tmr_reprogram(int dev)
+{
+ /*
+ * Audio driver has changed sampling rate so that a different xtal
+ * oscillator was selected. We have to reprogram the timer rate.
+ */
- return ad1848_detect (hw_config->io_base + 4);
+ ad1848_tmr_start(dev, current_interval);
+ sound_timer_syncinterval(current_interval);
}
-long
-attach_ms_sound (long mem_start, struct address_info *hw_config)
+static void
+ad1848_tmr_disable(int dev)
{
-#ifdef PC98
- static char interrupt_bits[13] =
- {
- -1, -1, -1, 0x08, -1, 0x10, -1, -1, -1, -1, 0x18, -1, 0x20
- };
-#else
- static char interrupt_bits[12] =
- {
- -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20
- };
-#endif
- char bits;
+ u_long flags;
+ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
- static char dma_bits[4] =
- {
- 1, 2, 0, 3
- };
+ flags = splhigh();
+ ad_write(devc, 16, ad_read(devc, 16) & ~0x40);
+ devc->timer_running = 0;
+ splx(flags);
+}
- int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3;
+static void
+ad1848_tmr_restart(int dev)
+{
+ u_long flags;
+ ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc;
- if (!ad1848_detect (hw_config->io_base + 4))
- return mem_start;
+ if (current_interval == 0)
+ return;
- /*
- * Set the IRQ and DMA addresses.
- */
+ flags = splhigh();
+ ad_write(devc, 16, ad_read(devc, 16) | 0x40);
+ devc->timer_running = 1;
+ splx(flags);
+}
- bits = interrupt_bits[hw_config->irq];
- if (bits == -1)
- return mem_start;
+static struct sound_lowlev_timer ad1848_tmr = {
+ 0,
+ ad1848_tmr_start,
+ ad1848_tmr_disable,
+ ad1848_tmr_restart
+};
- OUTB (bits | 0x40, config_port);
- if ((INB (version_port) & 0x40) == 0)
- printk ("[IRQ Conflict?]");
+static int
+ad1848_tmr_install(int dev)
+{
+ if (timer_installed != -1)
+ return 0; /* Don't install another timer */
- OUTB (bits | dma_bits[hw_config->dma], config_port); /* Write IRQ+DMA setup */
+ timer_installed = ad1848_tmr.dev = dev;
+ sound_timer_init(&ad1848_tmr, audio_devs[dev]->name);
- ad1848_init ("MS Sound System", hw_config->io_base + 4,
- hw_config->irq,
- hw_config->dma,
- hw_config->dma);
- return mem_start;
+ return 1;
}
-
+#endif
#endif
diff --git a/sys/i386/isa/sound/ad1848_mixer.h b/sys/i386/isa/sound/ad1848_mixer.h
index 2c1bddb..7a1d323 100644
--- a/sys/i386/isa/sound/ad1848_mixer.h
+++ b/sys/i386/isa/sound/ad1848_mixer.h
@@ -35,9 +35,10 @@
* (Actually this is not a mapping but rather some kind of interleaving
* solution).
*/
+#define GUSMAX_MIXER
#ifdef GUSMAX_MIXER
#define MODE1_REC_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | \
- SOUND_MASK_CD)
+ SOUND_MASK_CD|SOUND_MASK_IMIX)
#define MODE1_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_MIC | \
SOUND_MASK_CD | \
@@ -50,7 +51,7 @@
SOUND_MASK_PCM | SOUND_MASK_IMIX)
#else /* Generic mapping */
#define MODE1_REC_DEVICES (SOUND_MASK_LINE3 | SOUND_MASK_MIC | \
- SOUND_MASK_LINE1)
+ SOUND_MASK_LINE1|SOUND_MASK_IMIX)
#define MODE1_MIXER_DEVICES (SOUND_MASK_LINE1 | SOUND_MASK_MIC | \
SOUND_MASK_LINE2 | \
@@ -70,6 +71,14 @@ struct mixer_def {
unsigned int nbits:4;
};
+static char mix_cvt[101] = {
+ 0, 0,3,7,10,13,16,19,21,23,26,28,30,32,34,35,37,39,40,42,
+ 43,45,46,47,49,50,51,52,53,55,56,57,58,59,60,61,62,63,64,65,
+ 65,66,67,68,69,70,70,71,72,73,73,74,75,75,76,77,77,78,79,79,
+ 80,81,81,82,82,83,84,84,85,85,86,86,87,87,88,88,89,89,90,90,
+ 91,91,92,92,93,93,94,94,95,95,96,96,96,97,97,98,98,98,99,99,
+ 100
+};
typedef struct mixer_def mixer_ent;
@@ -83,9 +92,9 @@ typedef struct mixer_def mixer_ent;
*/
#define MIX_ENT(name, reg_l, pola_l, pos_l, len_l, reg_r, pola_r, pos_r, len_r) \
- {{reg_l, pola_l, pos_r, len_l}, {reg_r, pola_r, pos_r, len_r}}
+ {{reg_l, pola_l, pos_l, len_l}, {reg_r, pola_r, pos_r, len_r}}
-static mixer_ent mix_devices[32][2] = { /* As used in GUS MAX */
+mixer_ent mix_devices[32][2] = { /* As used in GUS MAX */
MIX_ENT(SOUND_MIXER_VOLUME, 0, 0, 0, 0, 0, 0, 0, 0),
MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0),
MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0),
@@ -93,7 +102,7 @@ MIX_ENT(SOUND_MIXER_SYNTH, 4, 1, 0, 5, 5, 1, 0, 5),
MIX_ENT(SOUND_MIXER_PCM, 6, 1, 0, 6, 7, 1, 0, 6),
MIX_ENT(SOUND_MIXER_SPEAKER, 26, 1, 0, 4, 0, 0, 0, 0),
MIX_ENT(SOUND_MIXER_LINE, 18, 1, 0, 5, 19, 1, 0, 5),
-MIX_ENT(SOUND_MIXER_MIC, 0, 1, 5, 1, 1, 1, 5, 1),
+MIX_ENT(SOUND_MIXER_MIC, 0, 0, 5, 1, 1, 0, 5, 1),
MIX_ENT(SOUND_MIXER_CD, 2, 1, 0, 5, 3, 1, 0, 5),
MIX_ENT(SOUND_MIXER_IMIX, 13, 1, 2, 6, 0, 0, 0, 0),
MIX_ENT(SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0),
@@ -111,20 +120,23 @@ static unsigned short default_mixer_levels[SOUND_MIXER_NRDEVICES] =
0x3232, /* Bass */
0x3232, /* Treble */
0x4b4b, /* FM */
- 0x6464, /* PCM */
+ 0x4040, /* PCM */
0x4b4b, /* PC Speaker */
- 0x4b4b, /* Ext Line */
- 0x1010, /* Mic */
+ /* 0x2020, Ext Line */
+ 0x0000, /* Ext Line */
+ 0x4040, /* Mic */
0x4b4b, /* CD */
0x0000, /* Recording monitor */
0x4b4b, /* SB PCM */
0x4b4b, /* Recording level */
- 0x4b4b, /* Input gain */
- 0x4b4b, /* Output gain */
- 0x4b4b, /* Line1 */
- 0x4b4b, /* Line2 */
- 0x4b4b /* Line3 */
+ 0x2525, /* Input gain */
+ 0x0000, /* Output gain */
+ /* 0x4040, Line1 */
+ 0x0000, /* Line1 */
+ 0x0000, /* Line2 */
+ 0x1515, /* Line3 (usually line in)*/
};
#define LEFT_CHN 0
#define RIGHT_CHN 1
+
diff --git a/sys/i386/isa/sound/adlib_card.c b/sys/i386/isa/sound/adlib_card.c
index a2e7b05..41039b9 100644
--- a/sys/i386/isa/sound/adlib_card.c
+++ b/sys/i386/isa/sound/adlib_card.c
@@ -1,10 +1,10 @@
/*
* sound/adlib_card.c
- *
+ *
* Detection routine for the AdLib card.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,31 +24,23 @@
* 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 <i386/isa/sound/sound_config.h>
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_YM3812)
+#if defined(CONFIG_YM3812)
-long
-attach_adlib_card (long mem_start, struct address_info *hw_config)
+void
+attach_adlib_card(struct address_info * hw_config)
{
-
- if (opl3_detect (FM_MONO))
- {
- mem_start = opl3_init (mem_start);
- }
- return mem_start;
+ opl3_init(hw_config->io_base, hw_config->osp);
}
int
-probe_adlib (struct address_info *hw_config)
+probe_adlib(struct address_info * hw_config)
{
- if (opl3_detect (FM_MONO))
- return 4;
- else
- return 0;
+ return opl3_detect(hw_config->io_base, hw_config->osp);
}
#endif
diff --git a/sys/i386/isa/sound/aedsp16.c b/sys/i386/isa/sound/aedsp16.c
index a292d9e..e69de29 100644
--- a/sys/i386/isa/sound/aedsp16.c
+++ b/sys/i386/isa/sound/aedsp16.c
@@ -1,838 +0,0 @@
-/*
- sound/aedsp16.c
-
- Audio Excel DSP 16 software configuration routines
-
- Copyright (C) 1995 Riccardo Facchetti (riccardo@cdc8g5.cdc.polimi.it)
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are
- met: 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer. 2.
- Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
-
- READ THIS
-
- This module is intended for Audio Excel DSP 16 Sound Card.
-
- Audio Excel DSP 16 is an SB pro II, Microsoft Sound System
- and MPU-401 compatible card.
- It is software-only configurable (no jumpers to hard-set irq/dma/mpu-irq),
- so before this module, the only way to configure the DSP under linux was
- boot the MS-BAU loading the sound.sys device driver (this driver soft-
- configure the sound board hardware by massaging someone of its registers),
- and then ctrl-alt-del to boot linux with the DSP configured by the DOG
- driver.
-
- This module works configuring your Audio Excel DSP 16's
- irq, dma and mpu-401-irq. The voxware probe routines rely on the
- fact that if the hardware is there, they can detect it. The problem
- with AEDSP16 is that no hardware can be found by the probe routines
- if the sound card is not well configured. Sometimes the kernel probe
- routines can find an SBPRO even when the card is not configured (this
- is the standard setup of the card), but the SBPRO emulation don't work
- well if the card is not properly initialized. For this reason
-
- InitAEDSP16_...()
-
- routines are called before the voxware probe routines try to detect the
- hardware.
-
- NOTE (READ THE NOTE TOO, IT CONTAIN USEFUL INFORMATIONS)
-
- The Audio Excel DSP 16 Sound Card emulates both SBPRO and MSS;
- the voxware sound driver can be configured for SBPRO and MSS cards
- at the same time, but the aedsp16 can't be two cards!!
- When we configure it, we have to choose the SBPRO or the MSS emulation
- for AEDSP16. We also can install a *REAL* card of the other type
- (see [1], not tested but I can't see any reason for it to fail).
-
- NOTE: If someone can test the combination AEDSP16+MSS or AEDSP16+SBPRO
- please let me know if it works.
-
- The MPU-401 support can be compiled in together with one of the other
- two operating modes.
-
- The board configuration calls, are in the probe_...() routines because
- we have to configure the board before probing it for a particular
- hardware. After card configuration, we can probe the hardware.
-
- NOTE: This is something like plug-and-play: we have only to plug
- the AEDSP16 board in the socket, and then configure and compile
- a kernel that uses the AEDSP16 software configuration capability.
- No jumper setting is needed!
-
- For example, if you want AEDSP16 to be an SBPro, on irq 10, dma 3
- you have just to make config the voxware package, configuring
- the SBPro sound card with that parameters, then when configure
- asks if you have an AEDSP16, answer yes. That's it.
- Compile the kernel and run it.
-
- NOTE: This means that you can choose irq and dma, but not the
- I/O addresses. To change I/O addresses you have to set them
- with jumpers.
-
- NOTE: InitAEDSP16_...() routines get as parameter the hw_config,
- the hardware configuration of the - to be configured - board.
- The InitAEDSP16() routine, configure the board following our
- wishes, that are in the hw_config structure.
-
- You can change the irq/dma/mirq settings WITHOUT THE NEED to open
- your computer and massage the jumpers (there are no irq/dma/mirq
- jumpers to be configured anyway, only I/O port ones have to be
- configured with jumpers)
-
- For some ununderstandable reason, the card default of irq 7, dma 1,
- don't work for me. Seems to be an IRQ or DMA conflict. Under heavy
- HDD work, the kernel start to erupt out a lot of messages like:
-
- 'Sound: DMA timed out - IRQ/DRQ config error?'
-
- For what I can say, I have NOT any conflict at irq 7 (under linux I'm
- using the lp polling driver), and dma line 1 is unused as stated by
- /proc/dma. I can suppose this is a bug of AEDSP16. I know my hardware so
- I'm pretty sure I have not any conflict, but may be I'm wrong. Who knows!
- Anyway a setting of irq 10, dma 3 works really fine.
-
- NOTE: if someone can use AEDSP16 with irq 7, dma 1, please let me know
- the emulation mode, all the installed hardware and the hardware
- configuration (irq and dma settings of all the hardware).
-
- This init module should work with SBPRO+MSS, when one of the two is
- the AEDSP16 emulation and the other the real card. (see [1])
- For example:
-
- AEDSP16 (0x220) in SBPRO emu (0x220) + real MSS + other
- AEDSP16 (0x220) in MSS emu + real SBPRO (0x240) + other
-
- MPU401 should work. (see [1])
-
- [1] Not tested by me for lack of hardware.
-
- TODO, WISHES AND TECH
-
- May be there's lot of redundant delays, but for now I want to leave it
- this way.
-
- Should be interesting eventually write down a new ioctl for the
- aedsp16, to let the suser() change the irq/dma/mirq on the fly.
- The thing is not trivial.
- In the real world, there's no need to have such an ioctl because
- when we configure the kernel for compile, we can choose the config
- parameters. If we change our mind, we can easily re-config the kernel
- and re-compile.
- Why let the suser() change the config parameters on the fly ?
- If anyone have a reasonable answer to this question, I will write down
- the code to do it.
-
- More integration with voxware, using voxware low level routines to
- read-write dsp is not possible because you may want to have MSS
- support and in that case we can not rely on the functions included
- in sb_dsp.c to control 0x2yy I/O ports. I will continue to use my
- own I/O functions.
-
- - About I/O ports allocation -
-
- The request_region should be done at device probe in every sound card
- module. This module is not the best site for requesting regions.
- When the request_region code will be added to the main modules such as
- sb, adlib, gus, ad1848, etc, the requesting code in this module should
- go away.
-
- I think the request regions should be done this way:
-
- if (check_region(...))
- return ERR; // I/O region alredy reserved
- device_probe(...);
- device_attach(...);
- request_region(...); // reserve only when we are sure all is okay
-
- Request the 2x0h region in any case if we are using this card.
-
- NOTE: the "(sbpro)" string with which we are requesting the aedsp16 region
- (see code) does not mean necessarly that we are emulating sbpro.
- It mean that the region is the sbpro I/O ports region. We use this
- region to access the control registers of the card, and if emulating
- sbpro, I/O sbpro registers too. If we are emulating MSS, the sbpro
- registers are not used, in no way, to emulate an sbpro: they are
- used only for configuration pourposes.
-
- Someone pointed out that should be possible use both the SBPRO and MSS
- modes because the sound card have all the two chipsets, supposing that
- the card is really two cards. I have tried something to have the two
- modes work together, but, for some reason unknown to me, without success.
-
- I think all the soft-config only cards have an init sequence similar to
- this. If you have a card that is not an aedsp16, you can try to start
- with this module changing it (mainly in the CMD? I think) to fit your
- needs.
-
- Started Fri Mar 17 16:13:18 MET 1995
-
- v0.1 (ALPHA, was an user-level program called AudioExcelDSP16.c)
- - Initial code.
- v0.2 (ALPHA)
- - Cleanups.
- - Integrated with Linux voxware v 2.90-2 kernel sound driver.
- - SoundBlaster Pro mode configuration.
- - Microsoft Sound System mode configuration.
- - MPU-401 mode configuration.
- v0.3 (ALPHA)
- - Cleanups.
- - Rearranged the code to let InitAEDSP16 be more general.
- - Erased the REALLY_SLOW_IO. We don't need it. Erased the linux/io.h
- inclusion too. We rely on os.h
- - Used the INB and OUTB #defined in os.h instead of inb and outb.
- - Corrected the code for GetCardName (DSP Copyright) to get a variable
- len string (we are not sure about the len of Copyright string).
- This works with any SB and compatible.
- - Added the code to request_region at device init (should go in
- the main body of voxware).
- v0.4 (BETA)
- - Better configure.c patch for aedsp16 configuration (better
- logic of inclusion of AEDSP16 support)
- - Modified the conditional compilation to better support more than
- one sound card of the emulated type (read the NOTES above)
- - Moved the sb init routine from the attach to the very first
- probe in sb_card.c
- - Rearrangemens and cleanups
- - Wiped out some unnecessary code and variables: this is kernel
- code so it is better save some TEXT and DATA
- - Fixed the request_region code. We must allocate the aedsp16 (sbpro)
- I/O ports in any case because they are used to access the DSP
- configuration registers and we can not allow anyone to get them.
- v0.5
- - cleanups on comments
- - prep for diffs against v3.0-proto-950402
-
- */
-
-/*
- * Include the main voxware header file. It include all the os/voxware/etc
- * headers needed by this source.
- */
-#include <i386/isa/sound/sound_config.h>
-/*
- * all but ioport.h :)
- */
-#include <linux/ioport.h>
-
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AEDSP16)
-
-#define VERSION "0.5" /* Version of Audio Excel DSP 16 driver */
-
-#undef AEDSP16_DEBUG /* Define this to enable debug code */
-/* Actually no debug code is activated */
-
-/*
- * Hardware related defaults
- */
-#define IRQ 7 /* 5 7(default) 9 10 11 */
-#define MIRQ 0 /* 5 7 9 10 0(default), 0 means disable */
-#define DMA 1 /* 0 1(default) 3 */
-
-/*
- * Commands of AEDSP16's DSP (SBPRO+special).
- * For now they are CMDn, in the future they may change.
- */
-#define CMD1 0xe3 /* Get DSP Copyright */
-#define CMD2 0xe1 /* Get DSP Version */
-#define CMD3 0x88 /* */
-#define CMD4 0x5c /* */
-#define CMD5 0x50 /* Set M&I&DRQ mask (the real config) */
-#define CMD6 0x8c /* Enable Microsoft Sound System mode */
-
-/*
- * Offsets of AEDSP16 DSP I/O ports. The offest is added to portbase
- * to have the actual I/O port.
- * Register permissions are:
- * (wo) == Write Only
- * (ro) == Read Only
- * (w-) == Write
- * (r-) == Read
- */
-#define DSP_RESET 0x06 /* offset of DSP RESET (wo) */
-#define DSP_READ 0x0a /* offset of DSP READ (ro) */
-#define DSP_WRITE 0x0c /* offset of DSP WRITE (w-) */
-#define DSP_COMMAND 0x0c /* offset of DSP COMMAND (w-) */
-#define DSP_STATUS 0x0c /* offset of DSP STATUS (r-) */
-#define DSP_DATAVAIL 0x0e /* offset of DSP DATA AVAILABLE (ro) */
-
-
-#define RETRY 10 /* Various retry values on I/O opera- */
-#define STATUSRETRY 1000 /* tions. Sometimes we have to */
-#define HARDRETRY 500000 /* wait for previous cmd to complete */
-
-/*
- * Size of character arrays that store name and version of sound card
- */
-#define CARDNAMELEN 15 /* Size of the card's name in chars */
-#define CARDVERLEN 2 /* Size of the card's version in chars */
-
-/*
- * Bit mapped flags for calling InitAEDSP16(), and saving the current
- * emulation mode.
- */
-#define INIT_NONE (0 )
-#define INIT_SBPRO (1<<0)
-#define INIT_MSS (1<<1)
-#define INIT_MPU401 (1<<2)
-#define RESET_DSP16 (1<<3)
-
-/* Base HW Port for Audio Card */
-static int portbase = AEDSP16_BASE;
-static int irq = IRQ; /* irq for DSP I/O */
-static int mirq = MIRQ; /* irq for MPU-401 I/O */
-static int dma = DMA; /* dma for DSP I/O */
-
-/* Init status of the card */
-static int ae_init = INIT_NONE; /* (bitmapped variable) */
-static int oredparams = 0; /* Will contain or'ed values of params */
-static int gc = 0; /* generic counter (utility counter) */
-struct orVals
- { /* Contain the values to be or'ed */
- int val; /* irq|mirq|dma */
- int or; /* oredparams |= TheStruct.or */
- };
-
-/*
- * Magic values that the DSP will eat when configuring irq/mirq/dma
- */
-/* DSP IRQ conversion array */
-static struct orVals orIRQ[] =
-{
- {0x05, 0x28},
- {0x07, 0x08},
- {0x09, 0x10},
- {0x0a, 0x18},
- {0x0b, 0x20},
- {0x00, 0x00}
-};
-
-/* MPU-401 IRQ conversion array */
-static struct orVals orMIRQ[] =
-{
- {0x05, 0x04},
- {0x07, 0x44},
- {0x09, 0x84},
- {0x0a, 0xc4},
- {0x00, 0x00}
-};
-
-/* DMA Channels conversion array */
-static struct orVals orDMA[] =
-{
- {0x00, 0x01},
- {0x01, 0x02},
- {0x03, 0x03},
- {0x00, 0x00}
-};
-
-/*
- * Buffers to store audio card informations
- */
-static char AudioExcelName[CARDNAMELEN + 1];
-static char AudioExcelVersion[CARDVERLEN + 1];
-
-static void
-tenmillisec (void)
-{
-
- for (gc = 0; gc < 1000; gc++)
- tenmicrosec ();
-}
-
-static int
-WaitForDataAvail (int port)
-{
- int loop = STATUSRETRY;
- unsigned char ret = 0;
-
- do
- {
- ret = INB (port + DSP_DATAVAIL);
- /*
- * Wait for data available (bit 7 of ret == 1)
- */
- }
- while (!(ret & 0x80) && loop--);
-
- if (ret & 0x80)
- return 0;
-
- return -1;
-}
-
-static int
-ReadData (int port)
-{
- if (WaitForDataAvail (port))
- return -1;
- return INB (port + DSP_READ);
-}
-
-static int
-CheckDSPOkay (int port)
-{
- return ((ReadData (port) == 0xaa) ? 0 : -1);
-}
-
-static int
-ResetBoard (int port)
-{
- /*
- * Reset DSP
- */
- OUTB (1, (port + DSP_RESET));
- tenmicrosec ();
- OUTB (0, (port + DSP_RESET));
- tenmicrosec ();
- tenmicrosec ();
- return CheckDSPOkay (port);
-}
-
-static int
-WriteDSPCommand (int port, int cmd)
-{
- unsigned char ret;
- int loop = HARDRETRY;
-
- do
- {
- ret = INB (port + DSP_STATUS);
- /*
- * DSP ready to receive data if bit 7 of ret == 0
- */
- if (!(ret & 0x80))
- {
- OUTB (cmd, port + DSP_COMMAND);
- return 0;
- }
- }
- while (loop--);
-
- printk ("[aedsp16] DSP Command (0x%x) timeout.\n", cmd);
- return -1;
-}
-
-int
-InitMSS (int port)
-{
-
- tenmillisec ();
-
- if (WriteDSPCommand (port, CMD6))
- {
- printk ("[aedsp16] CMD 0x%x: failed!\n", CMD6);
- return -1;
- }
-
- tenmillisec ();
-
- return 0;
-}
-
-static int
-SetUpBoard (int port)
-{
- int loop = RETRY;
-
- do
- {
- if (WriteDSPCommand (portbase, CMD3))
- {
- printk ("[aedsp16] CMD 0x%x: failed!\n", CMD3);
- return -1;
- }
-
- tenmillisec ();
-
- }
- while (WaitForDataAvail (port) && loop--);
-
-#if defined(THIS_SHOULD_GO_AWAY)
- if (CheckDSPOkay (port))
- {
- printk ("[aedsp16] CheckDSPOkay: failed\n");
- return -1;
- }
-#else
- if (ReadData (port) == -1)
- {
- printk ("[aedsp16] ReadData after CMD 0x%x: failed\n", CMD3);
- return -1;
- }
-#endif
-
- if (WriteDSPCommand (portbase, CMD4))
- {
- printk ("[aedsp16] CMD 0x%x: failed!\n", CMD4);
- return -1;
- }
-
- if (WriteDSPCommand (portbase, CMD5))
- {
- printk ("[aedsp16] CMD 0x%x: failed!\n", CMD5);
- return -1;
- }
-
- if (WriteDSPCommand (portbase, oredparams))
- {
- printk ("[aedsp16] Initialization of (M)IRQ and DMA: failed!\n");
- return -1;
- }
- return 0;
-}
-
-static int
-GetCardVersion (int port)
-{
- int len = 0;
- int ret;
- int ver[3];
-
- do
- {
- if ((ret = ReadData (port)) == -1)
- return -1;
- /*
- * We alredy know how many int are stored (2), so we know when the
- * string is finished.
- */
- ver[len++] = ret;
- }
- while (len < CARDVERLEN);
- sprintf (AudioExcelVersion, "%d.%d", ver[0], ver[1]);
- return 0;
-}
-
-static int
-GetCardName (int port)
-{
- int len = 0;
- int ret;
-
- do
- {
- if ((ret = ReadData (port)) == -1)
- /*
- * If no more data availabe, return to the caller, no error if len>0.
- * We have no other way to know when the string is finished.
- */
- return (len ? 0 : -1);
-
- AudioExcelName[len++] = ret;
-
- }
- while (len < CARDNAMELEN);
- return 0;
-}
-
-static void
-InitializeHardParams (void)
-{
-
- memset (AudioExcelName, 0, CARDNAMELEN + 1);
- memset (AudioExcelVersion, 0, CARDVERLEN + 1);
-
- for (gc = 0; orIRQ[gc].or; gc++)
- if (orIRQ[gc].val == irq)
- oredparams |= orIRQ[gc].or;
-
- for (gc = 0; orMIRQ[gc].or; gc++)
- if (orMIRQ[gc].or == mirq)
- oredparams |= orMIRQ[gc].or;
-
- for (gc = 0; orDMA[gc].or; gc++)
- if (orDMA[gc].val == dma)
- oredparams |= orDMA[gc].or;
-}
-
-static int
-InitAEDSP16 (int which)
-{
- static char *InitName = NULL;
-
- InitializeHardParams ();
-
- if (ResetBoard (portbase))
- {
- printk ("[aedsp16] ResetBoard: failed!\n");
- return -1;
- }
-
-#if defined(THIS_SHOULD_GO_AWAY)
- if (CheckDSPOkay (portbase))
- {
- printk ("[aedsp16] CheckDSPOkay: failed!\n");
- return -1;
- }
-#endif
-
- if (WriteDSPCommand (portbase, CMD1))
- {
- printk ("[aedsp16] CMD 0x%x: failed!\n", CMD1);
- return -1;
- }
-
- if (GetCardName (portbase))
- {
- printk ("[aedsp16] GetCardName: failed!\n");
- return -1;
- }
-
- /*
- * My AEDSP16 card return SC-6000 in AudioExcelName, so
- * if we have something different, we have to be warned.
- */
- if (strcmp ("SC-6000", AudioExcelName))
- printk ("[aedsp16] Warning: non SC-6000 audio card!\n");
-
- if (WriteDSPCommand (portbase, CMD2))
- {
- printk ("[aedsp16] CMD 0x%x: failed!\n", CMD2);
- return -1;
- }
-
- if (GetCardVersion (portbase))
- {
- printk ("[aedsp16] GetCardVersion: failed!\n");
- return -1;
- }
-
- if (SetUpBoard (portbase))
- {
- printk ("[aedsp16] SetUpBoard: failed!\n");
- return -1;
- }
-
- if (which == INIT_MSS)
- {
- if (InitMSS (portbase))
- {
- printk ("[aedsp16] Can't initialize Microsoft Sound System mode.\n");
- return -1;
- }
- }
-
- /*
- * If we are resetting, do not print any message because we may be
- * in playing and we do not want lost too much time.
- */
- if (!(which & RESET_DSP16))
- {
- if (which & INIT_MPU401)
- InitName = "MPU401";
- else if (which & INIT_SBPRO)
- InitName = "SBPro";
- else if (which & INIT_MSS)
- InitName = "MSS";
- else
- InitName = "None";
-
- printk ("Audio Excel DSP 16 init v%s (%s %s) [%s]\n",
- VERSION, AudioExcelName,
- AudioExcelVersion, InitName);
- }
-
- tenmillisec ();
-
- return 0;
-}
-
-#if defined(AEDSP16_SBPRO)
-
-int
-InitAEDSP16_SBPRO (struct address_info *hw_config)
-{
- /*
- * If the card is alredy init'ed MSS, we can not init it to SBPRO too
- * because the board can not emulate simultaneously MSS and SBPRO.
- */
- if (ae_init & INIT_MSS)
- return -1;
- if (ae_init & INIT_SBPRO)
- return 0;
-
- /*
- * For now we will leave this
- * code included only when INCLUDE_AEDSP16 is configured in, but it should
- * be better include it every time.
- */
- if (!(ae_init & INIT_MPU401))
- {
- if (check_region (hw_config->io_base, 0x0f))
- {
- printk ("AEDSP16/SBPRO I/O port region is alredy in use.\n");
- return -1;
- }
- }
-
- /*
- * Set up the internal hardware parameters, to let the driver reach
- * the Sound Card.
- */
- portbase = hw_config->io_base;
- irq = hw_config->irq;
- dma = hw_config->dma;
- if (InitAEDSP16 (INIT_SBPRO))
- return -1;
-
- if (!(ae_init & INIT_MPU401))
- request_region (hw_config->io_base, 0x0f, "aedsp16 (sbpro)");
-
- ae_init |= INIT_SBPRO;
- return 0;
-}
-
-#endif /* AEDSP16_SBPRO */
-
-#if defined(AEDSP16_MSS)
-
-int
-InitAEDSP16_MSS (struct address_info *hw_config)
-{
- /*
- * If the card is alredy init'ed SBPRO, we can not init it to MSS too
- * because the board can not emulate simultaneously MSS and SBPRO.
- */
- if (ae_init & INIT_SBPRO)
- return -1;
- if (ae_init & INIT_MSS)
- return 0;
-
- /*
- * For now we will leave this
- * code included only when INCLUDE_AEDSP16 is configured in, but it should
- * be better include it every time.
- */
- if (check_region (hw_config->io_base, 0x08))
- {
- printk ("MSS I/O port region is alredy in use.\n");
- return -1;
- }
-
- /*
- * We must allocate the AEDSP16 region too because these are the I/O ports
- * to access card's control registers.
- */
- if (!(ae_init & INIT_MPU401))
- {
- if (check_region (AEDSP16_BASE, 0x0f))
- {
- printk ("AEDSP16 I/O port region is alredy in use.\n");
- return -1;
- }
- }
-
-
- /*
- * If we are configuring the card for MSS, the portbase for card configuration
- * is the default one (0x220 unless you have changed the factory default
- * with board switches), so no need to modify the portbase variable.
- * The default is AEDSP16_BASE, that is the right value.
- */
- irq = hw_config->irq;
- dma = hw_config->dma;
- if (InitAEDSP16 (INIT_MSS))
- return -1;
-
- request_region (hw_config->io_base, 0x08, "aedsp16 (mss)");
-
- if (!(ae_init & INIT_MPU401))
- request_region (AEDSP16_BASE, 0x0f, "aedsp16 (sbpro)");
-
- ae_init |= INIT_MSS;
- return 0;
-}
-
-#endif /* AEDSP16_MSS */
-
-#if defined(AEDSP16_MPU401)
-
-int
-InitAEDSP16_MPU401 (struct address_info *hw_config)
-{
- if (ae_init & INIT_MPU401)
- return 0;
-
- /*
- * For now we will leave this
- * code included only when INCLUDE_AEDSP16 is configured in, but it should
- * be better include it every time.
- */
- if (check_region (hw_config->io_base, 0x02))
- {
- printk ("SB I/O port region is alredy in use.\n");
- return -1;
- }
-
- /*
- * We must allocate the AEDSP16 region too because these are the I/O ports
- * to access card's control registers.
- */
- if (!(ae_init & (INIT_MSS | INIT_SBPRO)))
- {
- if (check_region (AEDSP16_BASE, 0x0f))
- {
- printk ("AEDSP16 I/O port region is alredy in use.\n");
- return -1;
- }
- }
-
- /*
- * If mpu401, the irq and dma are not important, do not touch it
- * because we may use the default if sbpro is not yet configured,
- * we may use the sbpro ones if configured, and nothing wrong
- * should happen.
- *
- * The mirq default is 0, but once set it to non-0 value, we should
- * not touch it anymore (unless I write an ioctl to do it, of course).
- */
- mirq = hw_config->irq;
- if (InitAEDSP16 (INIT_MPU401))
- return -1;
-
- request_region (hw_config->io_base, 0x02, "aedsp16 (mpu401)");
-
- if (!(ae_init & (INIT_MSS | INIT_SBPRO)))
- request_region (AEDSP16_BASE, 0x0f, "aedsp16 (sbpro)");
-
- ae_init |= INIT_MPU401;
- return 0;
-}
-
-#endif /* AEDSP16_MPU401 */
-
-#if 0 /* Leave it out for now. We are not using this portion of code. */
-
-/*
- * Entry point for a reset function.
- * May be I will write the infamous ioctl :)
- */
-int
-ResetAEDSP16 (void)
-{
-#if defined(AEDSP16_DEBUG)
- printk ("[aedsp16] ResetAEDSP16 called.\n");
-#endif
- return InitAEDSP16 (RESET_DSP16);
-}
-
-#endif /* 0 */
-
-#endif /* !EXCLUDE_AEDSP16 */
diff --git a/sys/i386/isa/sound/audio.c b/sys/i386/isa/sound/audio.c
index b73cf4a..8e1a3c8 100644
--- a/sys/i386/isa/sound/audio.c
+++ b/sys/i386/isa/sound/audio.c
@@ -1,10 +1,10 @@
/*
* sound/audio.c
- *
+ *
* Device file manager for /dev/audio
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,13 +24,12 @@
* 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 <i386/isa/sound/sound_config.h>
-#ifdef CONFIGURE_SOUNDCARD
-#ifndef EXCLUDE_AUDIO
+#ifdef CONFIG_AUDIO
#include <i386/isa/sound/ulaw.h>
#include <i386/isa/sound/coproc.h>
@@ -38,12 +37,8 @@
#define ON 1
#define OFF 0
-static int wr_buff_no[MAX_AUDIO_DEV]; /*
-
- * != -1, if there is
- * a incomplete output
- * block in the queue.
- */
+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];
static int audio_mode[MAX_AUDIO_DEV];
@@ -57,521 +52,413 @@ static char *wr_dma_buf[MAX_AUDIO_DEV];
static int audio_format[MAX_AUDIO_DEV];
static int local_conversion[MAX_AUDIO_DEV];
+#if defined(NO_INLINE_ASM) || !defined(i386)
+static void
+translate_bytes(const u_char *table, u_char *buff, int n);
+
+#else
+extern inline void
+translate_bytes(const void *table, void *buff, int n);
+#endif
+
static int
-set_format (int dev, int fmt)
+set_format(int dev, int fmt)
{
- if (fmt != AFMT_QUERY)
- {
+ if (fmt != AFMT_QUERY) {
- local_conversion[dev] = 0;
+ 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 */
+ 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);
+ audio_format[dev] = DMAbuf_ioctl(dev, SNDCTL_DSP_SETFMT,
+ (ioctl_arg) fmt, 1);
}
+ if (local_conversion[dev]) /* This shadows the HW format */
+ return local_conversion[dev];
- if (local_conversion[dev]) /* This shadows the HW format */
- return local_conversion[dev];
-
- return audio_format[dev];
+ return audio_format[dev];
}
int
-audio_open (int dev, struct fileinfo *file)
+audio_open(int dev, struct fileinfo * file)
{
- int ret;
- int bits;
- int dev_type = dev & 0x0f;
- int mode = file->mode & O_ACCMODE;
-
- dev = dev >> 4;
+ int ret;
+ int bits;
+ int dev_type = dev & 0x0f;
+ int mode = file->mode & O_ACCMODE;
- if (dev_type == SND_DEV_DSP16)
- bits = 16;
- else
- bits = 8;
+ dev = dev >> 4;
- if ((ret = DMAbuf_open (dev, mode)) < 0)
- return ret;
-
- if (audio_devs[dev]->coproc)
- if ((ret = audio_devs[dev]->coproc->
- open (audio_devs[dev]->coproc->devc, COPR_PCM)) < 0)
- {
- audio_release (dev, file);
- printk ("Sound: Can't access coprocessor device\n");
+ bits = (dev_type == SND_DEV_DSP16) ? 16 : 8 ;
+ if ((ret = DMAbuf_open(dev, mode)) < 0)
return ret;
- }
- local_conversion[dev] = 0;
+ if (audio_devs[dev]->coproc)
+ if ((ret = audio_devs[dev]->coproc->
+ open(audio_devs[dev]->coproc->devc, COPR_PCM)) < 0) {
+ audio_release(dev, file);
+ printf("Sound: Can't access coprocessor device\n");
- if (DMAbuf_ioctl (dev, SNDCTL_DSP_SETFMT, bits, 1) != bits)
- {
- audio_release (dev, file);
- return RET_ERROR (ENXIO);
- }
+ return ret;
+ }
+ local_conversion[dev] = 0;
- if (dev_type == SND_DEV_AUDIO)
- {
- set_format (dev, AFMT_MU_LAW);
+ if (DMAbuf_ioctl(dev, SNDCTL_DSP_SETFMT, (ioctl_arg) bits, 1) != bits) {
+ audio_release(dev, file);
+ return -(ENXIO);
}
- else
- set_format (dev, bits);
- wr_buff_no[dev] = -1;
- audio_mode[dev] = AM_NONE;
- wr_buff_size[dev] = wr_buff_ptr[dev] = 0;
- dev_nblock[dev] = 0;
+ set_format(dev, (dev_type == SND_DEV_AUDIO) ? AFMT_MU_LAW : bits ) ;
- return ret;
+ wr_buff_no[dev] = -1;
+ audio_mode[dev] = AM_NONE;
+ wr_buff_size[dev] = wr_buff_ptr[dev] = 0;
+ dev_nblock[dev] = 0;
+
+ return ret;
}
void
-audio_release (int dev, struct fileinfo *file)
+audio_release(int dev, struct fileinfo * file)
{
- int mode;
-
- dev = dev >> 4;
- mode = file->mode & O_ACCMODE;
+ int mode;
- if (wr_buff_no[dev] >= 0)
- {
- DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+ dev = dev >> 4;
+ mode = file->mode & O_ACCMODE;
- wr_buff_no[dev] = -1;
+ if (wr_buff_no[dev] >= 0) {
+ DMAbuf_start_output(dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+ wr_buff_no[dev] = -1;
}
+ if (audio_devs[dev]->coproc)
+ audio_devs[dev]->coproc->close(audio_devs[dev]->coproc->devc,COPR_PCM);
+ DMAbuf_release(dev, mode);
+ audio_devs[dev]->dmap_out->mapping_flags &= ~DMA_MAP_MAPPED ;
- if (audio_devs[dev]->coproc)
- audio_devs[dev]->coproc->close (audio_devs[dev]->coproc->devc, COPR_PCM);
- DMAbuf_release (dev, mode);
}
-#ifdef NO_INLINE_ASM
+#if defined(NO_INLINE_ASM) || !defined(i386)
static void
-translate_bytes (const unsigned char *table, unsigned char *buff, unsigned long n)
+translate_bytes(const u_char *table, u_char *buff, int n)
{
- unsigned long i;
+ u_long i;
+
+ if (n <= 0)
+ return;
- for (i = 0; i < n; ++i)
- buff[i] = table[buff[i]];
+ for (i = 0; i < n; ++i)
+ buff[i] = table[buff[i]];
}
#else
-static inline void
-translate_bytes (const void *table, void *buff, unsigned long n)
+extern inline void
+translate_bytes(const void *table, void *buff, int n)
{
- __asm__ ("cld\n"
- "1:\tlodsb\n\t"
- "xlatb\n\t"
- "stosb\n\t"
-"loop 1b\n\t":
-: "b" ((long) table), "c" (n), "D" ((long) buff), "S" ((long) buff)
-: "bx", "cx", "di", "si", "ax");
+ if (n > 0) {
+ __asm__("cld\n"
+ "1:\tlodsb\n\t"
+ "xlatb\n\t"
+ "stosb\n\t"
+ "loop 1b\n\t":
+ :"b"((long) table), "c"(n), "D"((long) buff), "S"((long) buff)
+ :"bx", "cx", "di", "si", "ax");
+ }
}
#endif
int
-audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+audio_write(int dev, struct fileinfo * file, snd_rw_buf * buf, int count)
{
- int c, p, l;
- int err;
+ int c, p, l;
+ int err;
- dev = dev >> 4;
+ dev = dev >> 4;
- p = 0;
- c = count;
+ p = 0;
+ c = count;
- if (audio_mode[dev] == AM_READ) /*
- * Direction changed
- */
- {
- wr_buff_no[dev] = -1;
+ if ((audio_mode[dev] & AM_READ) &&
+ !(audio_devs[dev]->flags & DMA_DUPLEX)) { /* Direction change */
+ wr_buff_no[dev] = -1;
}
-
- audio_mode[dev] = AM_WRITE;
-
- if (!count) /*
- * Flush output
- */
- {
- if (wr_buff_no[dev] >= 0)
- {
- DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
-
- wr_buff_no[dev] = -1;
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ audio_mode[dev] |= AM_WRITE;
+ else
+ audio_mode[dev] = AM_WRITE;
+
+ if (!count) { /* Flush output */
+ if (wr_buff_no[dev] >= 0) {
+ DMAbuf_start_output(dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+ wr_buff_no[dev] = -1;
}
- return 0;
+ return 0;
}
-
- while (c)
- { /*
- * 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],
- dev_nblock[dev])) < 0)
- {
- /* Handle nonblocking mode */
-#if defined(__FreeBSD__)
- if (dev_nblock[dev] && wr_buff_no[dev] == RET_ERROR (EWOULDBLOCK))
- return wr_buff_no[dev]; /*
- * XXX Return error, write() will
- * supply # of accepted bytes.
- * In fact, in FreeBSD the check
- * above should not be needed
- */
-#else
- if (dev_nblock[dev] && wr_buff_no[dev] == RET_ERROR (EAGAIN))
- return p; /* No more space. Return # of accepted bytes */
-#endif
- return wr_buff_no[dev];
+ while (c) { /* 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],
+ dev_nblock[dev])) < 0) {
+ /* Handle nonblocking mode */
+ if (dev_nblock[dev] && wr_buff_no[dev] == -(EAGAIN))
+ return p; /* No more space. Return # of accepted bytes */
+ return wr_buff_no[dev];
}
- wr_buff_ptr[dev] = 0;
+ wr_buff_ptr[dev] = 0;
}
+ l = c;
+ if (l > (wr_buff_size[dev] - wr_buff_ptr[dev]))
+ l = (wr_buff_size[dev] - wr_buff_ptr[dev]);
- l = c;
- if (l > (wr_buff_size[dev] - wr_buff_ptr[dev]))
- l = (wr_buff_size[dev] - wr_buff_ptr[dev]);
+ if (!audio_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
- audio_devs[dev]->copy_from_user (dev,
- wr_dma_buf[dev], wr_buff_ptr[dev], buf, p, l);
-
-
- /*
- * Insert local processing here
- */
-
- if (local_conversion[dev] == AFMT_MU_LAW)
- {
-#ifdef linux
- /*
- * 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);
- }
+ if (uiomove(&wr_dma_buf[dev][wr_buff_ptr[dev]], l, buf)) {
+ printf("sb: Bad copyin()!\n");
+ };
+ } else
+ audio_devs[dev]->copy_from_user(dev,
+ wr_dma_buf[dev], wr_buff_ptr[dev], buf, p, l);
- c -= l;
- p += l;
- wr_buff_ptr[dev] += l;
- 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;
- }
+ /*
+ * Insert local processing here
+ */
- wr_buff_no[dev] = -1;
+ if (local_conversion[dev] == AFMT_MU_LAW) {
+ translate_bytes(ulaw_dsp,
+ (u_char *) &wr_dma_buf[dev][wr_buff_ptr[dev]], l);
+ }
+ c -= l;
+ p += l;
+ wr_buff_ptr[dev] += l;
+
+ 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;
+ }
+ wr_buff_no[dev] = -1;
}
-
}
- return count;
+ return count;
}
int
-audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+audio_read(int dev, struct fileinfo * file, snd_rw_buf * buf, int count)
{
- int c, p, l;
- char *dmabuf;
- int buff_no;
-
- dev = dev >> 4;
- p = 0;
- c = count;
-
- if (audio_mode[dev] == AM_WRITE)
- {
- if (wr_buff_no[dev] >= 0)
- {
- DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
-
- wr_buff_no[dev] = -1;
+ int c, p, l;
+ char *dmabuf;
+ int buff_no;
+
+ dev = dev >> 4;
+ p = 0;
+ c = count;
+ if ((audio_mode[dev] & AM_WRITE) &&
+ !(audio_devs[dev]->flags & DMA_DUPLEX)) {
+ if (wr_buff_no[dev] >= 0) {
+ DMAbuf_start_output(dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+
+ if (!(audio_devs[dev]->flags & DMA_DUPLEX))
+ wr_buff_no[dev] = -1;
}
}
-
- audio_mode[dev] = AM_READ;
-
- while (c)
- {
- if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l,
- dev_nblock[dev])) < 0)
- {
- /* Nonblocking mode handling. Return current # of bytes */
-
-#if defined(__FreeBSD__)
- if (dev_nblock[dev] && buff_no == RET_ERROR (EWOULDBLOCK))
- return buff_no; /*
- * XXX Return error, read() will supply
- * # of bytes actually read. In fact,
- * in FreeBSD the check above should not
- * be needed
- */
-#else
- if (dev_nblock[dev] && buff_no == RET_ERROR (EAGAIN))
- return p;
-#endif
-
- return buff_no;
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ audio_mode[dev] |= AM_READ;
+ else
+ audio_mode[dev] = AM_READ;
+
+ while (c) {
+ if ((buff_no = DMAbuf_getrdbuffer(dev, &dmabuf, &l,
+ dev_nblock[dev])) < 0) {
+ /*
+ * Nonblocking mode handling. Return current # of bytes
+ */
+
+ if (dev_nblock[dev] && buff_no == -(EAGAIN))
+ return p;
+
+ return buff_no;
}
+ if (l > c)
+ l = c;
- if (l > c)
- l = c;
+ /*
+ * Insert any local processing here.
+ */
- /*
- * Insert any local processing here.
- */
-
- if (local_conversion[dev] == AFMT_MU_LAW)
- {
-#ifdef linux
- /*
- * This just allows interrupts while the conversion is running
- */
- __asm__ ("sti");
-#endif
-
- translate_bytes (dsp_ulaw, (unsigned char *) dmabuf, l);
+ if (local_conversion[dev] == AFMT_MU_LAW) {
+ translate_bytes(dsp_ulaw, (u_char *) dmabuf, l);
}
+ if (uiomove(dmabuf, l, buf)) {
+ printf("sb: Bad copyout()!\n");
+ };
- COPY_TO_USER (buf, p, dmabuf, l);
-
- DMAbuf_rmchars (dev, buff_no, l);
+ DMAbuf_rmchars(dev, buff_no, l);
- p += l;
- c -= l;
+ p += l;
+ c -= l;
}
-
- return count - c;
+ return count - c;
}
int
-audio_ioctl (int dev, struct fileinfo *file,
- unsigned int cmd, unsigned int arg)
+audio_ioctl(int dev, struct fileinfo * file, u_int cmd, ioctl_arg arg)
{
+ dev = dev >> 4;
+ if (((cmd >> 8) & 0xff) == 'C') {
+ if (audio_devs[dev]->coproc) /* Coprocessor ioctl */
+ return audio_devs[dev]->coproc->ioctl(audio_devs[dev]->coproc->devc, cmd, arg, 0);
+ else
+ printf("/dev/dsp%d: No coprocessor for this device\n", dev);
- dev = dev >> 4;
+ return -(ENXIO);
+ } else
+ switch (cmd) {
- if (((cmd >> 8) & 0xff) == 'C')
- {
- if (audio_devs[dev]->coproc) /* Coprocessor ioctl */
- return audio_devs[dev]->coproc->ioctl (audio_devs[dev]->coproc->devc, cmd, arg, 0);
- else
- printk ("/dev/dsp%d: No coprocessor for this device\n", dev);
+ case SNDCTL_DSP_SYNC:
+ if (wr_buff_no[dev] >= 0) {
+ DMAbuf_start_output(dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+ wr_buff_no[dev] = -1;
+ }
+ return DMAbuf_ioctl(dev, cmd, arg, 0);
+ break;
- return RET_ERROR (EREMOTEIO);
- }
- else
- switch (cmd)
- {
- case SNDCTL_DSP_SYNC:
- if (wr_buff_no[dev] >= 0)
- {
- DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+ case SNDCTL_DSP_POST:
+ if (wr_buff_no[dev] >= 0) {
+ DMAbuf_start_output(dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+ wr_buff_no[dev] = -1;
+ }
+ return 0;
+ break;
+ case SNDCTL_DSP_RESET:
wr_buff_no[dev] = -1;
- }
- return DMAbuf_ioctl (dev, cmd, arg, 0);
- break;
+ audio_mode[dev] = AM_NONE;
+ return DMAbuf_ioctl(dev, cmd, arg, 0);
+ break;
- case SNDCTL_DSP_POST:
- if (wr_buff_no[dev] >= 0)
- {
- DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
-
- wr_buff_no[dev] = -1;
- }
- return 0;
- break;
+ case SNDCTL_DSP_GETFMTS:
+ return *(int *) arg = audio_devs[dev]->format_mask;
+ break;
- case SNDCTL_DSP_RESET:
- wr_buff_no[dev] = -1;
- return DMAbuf_ioctl (dev, cmd, arg, 0);
- break;
+ case SNDCTL_DSP_SETFMT:
+ return *(int *) arg = set_format(dev, (*(int *) arg));
- case SNDCTL_DSP_GETFMTS:
- return IOCTL_OUT (arg, audio_devs[dev]->format_mask);
- break;
+ case SNDCTL_DSP_GETISPACE:
+ if ((audio_mode[dev] & AM_WRITE) &&
+ !(audio_devs[dev]->flags & DMA_DUPLEX))
+ return -(EBUSY);
- case SNDCTL_DSP_SETFMT:
- return IOCTL_OUT (arg, set_format (dev, IOCTL_IN (arg)));
+ else {
+ audio_buf_info info;
+ int err = DMAbuf_ioctl(dev, cmd, (ioctl_arg) & info, 1);
- case SNDCTL_DSP_GETISPACE:
- if (audio_mode[dev] == AM_WRITE)
- return RET_ERROR (EBUSY);
+ if (err < 0)
+ return err;
- {
- audio_buf_info info;
+ bcopy((char *) &info, &(((char *) arg)[0]), sizeof(info));
+ return 0;
+ }
- int err = DMAbuf_ioctl (dev, cmd, (unsigned long) &info, 1);
+ case SNDCTL_DSP_GETOSPACE:
+ if ((audio_mode[dev] & AM_READ) &&
+ !(audio_devs[dev]->flags & DMA_DUPLEX))
+ return -(EBUSY);
+ else {
+ audio_buf_info info;
+ int err = DMAbuf_ioctl(dev, cmd, (ioctl_arg) & info, 1);
- if (err < 0)
- return err;
+ if (err < 0)
+ return err;
- if (wr_buff_no[dev] != -1)
- info.bytes += wr_buff_ptr[dev];
+ if (wr_buff_no[dev] != -1)
+ info.bytes += wr_buff_size[dev] - wr_buff_ptr[dev];
- IOCTL_TO_USER ((char *) arg, 0, (char *) &info, sizeof (info));
- return 0;
- }
+ bcopy((char *) &info, &(((char *) arg)[0]), sizeof(info));
+ return 0;
+ }
- case SNDCTL_DSP_GETOSPACE:
- if (audio_mode[dev] == AM_READ)
- return RET_ERROR (EBUSY);
+ case SNDCTL_DSP_NONBLOCK:
+ dev_nblock[dev] = 1;
+ return 0;
+ break;
- {
- audio_buf_info info;
+ case SNDCTL_DSP_GETCAPS:
+ {
+ int info = 1; /* Revision level of this ioctl() */
- int err = DMAbuf_ioctl (dev, cmd, (unsigned long) &info, 1);
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ info |= DSP_CAP_DUPLEX;
- if (err < 0)
- return err;
+ if (audio_devs[dev]->coproc)
+ info |= DSP_CAP_COPROC;
- if (wr_buff_no[dev] != -1)
- info.bytes += wr_buff_size[dev] - wr_buff_ptr[dev];
+ if (audio_devs[dev]->local_qlen) /* Dev. has hidden buffs */
+ info |= DSP_CAP_BATCH;
- IOCTL_TO_USER ((char *) arg, 0, (char *) &info, sizeof (info));
- return 0;
- }
+ if (audio_devs[dev]->trigger) /* Supports SETTRIGGER */
+ info |= DSP_CAP_TRIGGER;
- case SNDCTL_DSP_NONBLOCK:
- dev_nblock[dev] = 1;
- return 0;
- break;
+ info |= DSP_CAP_MMAP;
+ bcopy((char *) &info, &(((char *) arg)[0]), sizeof(info));
+ return 0;
+ }
+ break;
-#ifdef __FreeBSD__
- case FIONBIO: /* XXX Is this the same in Linux? */
- if (*(int *)arg)
- dev_nblock[dev] = 1;
- else
- dev_nblock[dev] = 0;
- return 0;
- break;
- case FIOASYNC:
- return 0; /* XXX Useful for ampling input notification? */
- break;
-#endif
+ case FIOASYNC:
+ return *(int *) arg = 1;
- default:
- return DMAbuf_ioctl (dev, cmd, arg, 0);
- }
-}
+ case FIONBIO:
+ return *(int *) arg = 1;
-long
-audio_init (long mem_start)
-{
- /*
- * NOTE! This routine could be called several times during boot.
- */
- return mem_start;
+ default:
+ return DMAbuf_ioctl(dev, cmd, arg, 0);
+ }
}
#ifdef ALLOW_SELECT
+ /*
+ * XXX should we use spltty() in the select calls ? - lr970714
+ *
+ */
+
int
-audio_poll (int dev, struct fileinfo *file, int events, select_table * wait)
+audio_poll(int dev, struct fileinfo * file, int events, select_table * wait)
{
- int l;
- char *dmabuf;
- int revents = 0;
+ dev = dev >> 4;
- dev = dev >> 4;
+ if (events & (POLLOUT | POLLWRNORM)) {
+ if ((audio_mode[dev] & AM_WRITE) &&
+ !(audio_devs[dev]->flags & DMA_DUPLEX))
+ return 0; /* Not recording */
- if (events & (POLLIN | POLLRDNORM)) {
- if (audio_mode[dev] == AM_READ || /* Right direction */
- audio_mode[dev] == AM_NONE)
- if (DMAbuf_getrdbuffer (dev, &dmabuf, &l, 1 /* Don't block */ ) >= 0)
- revents |= events & (POLLIN | POLLRDNORM); /* We have data */
- else
- revents |= DMAbuf_poll (dev, file, events, wait);
+ return (DMAbuf_poll(dev, file, events, wait));
+ }
- }
+ if (events & (POLLIN | POLLRDNORM)) {
+ if ((audio_mode[dev] & AM_READ) &&
+ !(audio_devs[dev]->flags & DMA_DUPLEX))
+ return 0; /* Wrong direction */
- if (events & (POLLOUT | POLLWRNORM)) {
- if (audio_mode[dev] == AM_WRITE || /* Right direction */
- audio_mode[dev] == AM_NONE)
+ if (wr_buff_no[dev] != -1)
+ return 1; /* There is space in the current buffer */
- if (wr_buff_no[dev] != -1)
- revents |= events & (POLLOUT | POLLWRNORM); /* There is space in the current buffer */
- else
- revents |= DMAbuf_poll (dev, file, events, wait);
+ return ( DMAbuf_poll(dev, file, events, wait) );
- }
-
- return (revents);
+ }
+ return 0;
}
-
-#endif /* ALLOW_SELECT */
-
-#else /* EXCLUDE_AUDIO */
-/*
- * Stub versions
- */
-
-int
-audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
-{
- return RET_ERROR (EIO);
-}
-
-int
-audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
-{
- return RET_ERROR (EIO);
-}
-
-int
-audio_open (int dev, struct fileinfo *file)
-{
- return RET_ERROR (ENXIO);
-}
-
-void
-audio_release (int dev, struct fileinfo *file)
-{
-};
-int
-audio_ioctl (int dev, struct fileinfo *file,
- unsigned int cmd, unsigned int arg)
-{
- return RET_ERROR (EIO);
-}
-
-int
-audio_lseek (int dev, struct fileinfo *file, off_t offset, int orig)
-{
- return RET_ERROR (EIO);
-}
-
-long
-audio_init (long mem_start)
-{
- return mem_start;
-}
-
-#endif
+#endif /* ALLOW_SELECT */
#endif
diff --git a/sys/i386/isa/sound/awe_wave.c b/sys/i386/isa/sound/awe_wave.c
index 4781816..dec20b2 100644
--- a/sys/i386/isa/sound/awe_wave.c
+++ b/sys/i386/isa/sound/awe_wave.c
@@ -31,8 +31,8 @@
/* if you're using obsolete VoxWare 3.0.x on Linux 1.2.x (or FreeBSD),
* uncomment the following line
*/
-#define AWE_OBSOLETE_VOXWARE
+#define AWE_OBSOLETE_VOXWARE
#ifdef AWE_OBSOLETE_VOXWARE
@@ -88,9 +88,6 @@
#include <i386/isa/sound/awe_voice.h>
#ifdef AWE_OBSOLETE_VOXWARE
-#ifdef __FreeBSD__
-#define SEQUENCER_C
-#endif
#include <i386/isa/sound/tuning.h>
#else
#include "../tuning.h"
@@ -333,11 +330,25 @@ static void awe_set_reverb_mode(int mode);
#define awe_request_region() /* nothing */
#define awe_release_region() /* nothing */
+#ifdef __FreeBSD__
+# ifndef PERMANENT_MALLOC
+# define PERMANENT_MALLOC(typecast, mem_ptr, size) \
+ {mem_ptr = (typecast)malloc(size, M_DEVBUF, M_NOWAIT); \
+ if (!mem_ptr)panic("SOUND: Cannot allocate memory\n");}
+# endif
+# ifndef printk
+# define printk printf
+# endif
+# ifndef RET_ERROR
+# define RET_ERROR(err) -(err)
+# endif
+#endif
+
#else /* AWE_OBSOLETE_VOXWARE */
/* the following macros are osbolete */
-#define PERMANENT_MALLOC(type,var,size,memptr) \
+#define PERMANENT_MALLOC(type,var,size) \
var = (type)(sound_mem_blocks[sound_nblocks++] = vmalloc(size))
#define RET_ERROR(err) -err
@@ -431,8 +442,8 @@ static struct synth_operations awe_operations =
* attach / unload interface
*================================================================*/
-#ifdef AWE_OBSOLETE_VOXWARE
-long attach_awe_obsolete(long mem_start, struct address_info *hw_config)
+#if defined(AWE_OBSOLETE_VOXWARE) || defined(__FreeBSD__)
+void attach_awe_obsolete(struct address_info *hw_config)
#else
int attach_awe(void)
#endif
@@ -440,23 +451,23 @@ int attach_awe(void)
/* check presence of AWE32 card */
if (! awe_detect()) {
printk("AWE32: not detected\n");
- return 0;
+ return ;
}
/* check AWE32 ports are available */
if (awe_check_port()) {
printk("AWE32: I/O area already used.\n");
- return 0;
+ return ;
}
/* allocate sample tables */
PERMANENT_MALLOC(awe_sample_info *, samples,
- AWE_MAX_SAMPLES * sizeof(awe_sample_info), mem_start);
+ AWE_MAX_SAMPLES * sizeof(awe_sample_info) );
PERMANENT_MALLOC(awe_voice_list *, infos,
- AWE_MAX_INFOS * sizeof(awe_voice_list), mem_start);
+ AWE_MAX_INFOS * sizeof(awe_voice_list) );
if (samples == NULL || infos == NULL) {
printk("AWE32: can't allocate sample tables\n");
- return 0;
+ return ;
}
if (num_synths >= MAX_SYNTH_DEV)
@@ -488,29 +499,19 @@ int attach_awe(void)
awe_present = 1;
#ifdef AWE_OBSOLETE_VOXWARE
- return mem_start;
+ return ;
#else
return 1;
#endif
}
-
-void unload_awe(void)
-{
- if (awe_present) {
- awe_reset_samples();
- awe_release_region();
- }
-}
-
-
#ifdef AWE_OBSOLETE_VOXWARE
-int probe_awe_obsolete(struct address_info *hw_config)
+int
+probe_awe_obsolete(struct address_info *hw_config)
{
return 1;
/*return awe_detect();*/
}
-
#endif
/*================================================================
diff --git a/sys/i386/isa/sound/cs4232.c b/sys/i386/isa/sound/cs4232.c
new file mode 100644
index 0000000..4b2c38d
--- /dev/null
+++ b/sys/i386/isa/sound/cs4232.c
@@ -0,0 +1,206 @@
+/*
+ * sound/cs4232.c
+ *
+ * The low level driver for Crystal CS4232 based cards. The CS4232 is a PnP
+ * compatible chip which contains a CS4231A codec, SB emulation, a MPU401
+ * compatible MIDI port, joystick and synthesizer and IDE CD-ROM interfaces.
+ * This is just a temporary driver until full PnP support gets inplemented.
+ * Just the WSS codec, FM synth and the MIDI ports are supported. Other
+ * interfaces are left uninitialized.
+ *
+ * Copyright by Hannu Savolainen 1995
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <i386/isa/sound/sound_config.h>
+
+#if defined(CONFIG_CS4232)
+
+#define KEY_PORT 0x279 /* Same as LPT1 status port */
+#define CSN_NUM 0x99 /* Just a random number */
+
+#define CS_OUT(a) outb( KEY_PORT, a)
+#define CS_OUT2(a, b) {CS_OUT(a);CS_OUT(b);}
+#define CS_OUT3(a, b, c) {CS_OUT(a);CS_OUT(b);CS_OUT(c);}
+
+static int mpu_base = 0, mpu_irq = 0;
+static int mpu_detected = 0;
+
+int
+probe_cs4232_mpu(struct address_info * hw_config)
+{
+ /*
+ * Just write down the config values.
+ */
+
+ mpu_base = hw_config->io_base;
+ mpu_irq = hw_config->irq;
+ return 0;
+}
+
+void
+attach_cs4232_mpu(struct address_info * hw_config)
+{
+}
+
+static unsigned char crystal_key[] = /* A 32 byte magic key sequence */
+{
+ 0x96, 0x35, 0x9a, 0xcd, 0xe6, 0xf3, 0x79, 0xbc,
+ 0x5e, 0xaf, 0x57, 0x2b, 0x15, 0x8a, 0xc5, 0xe2,
+ 0xf1, 0xf8, 0x7c, 0x3e, 0x9f, 0x4f, 0x27, 0x13,
+ 0x09, 0x84, 0x42, 0xa1, 0xd0, 0x68, 0x34, 0x1a
+};
+
+int
+probe_cs4232(struct address_info * hw_config)
+{
+ int i;
+ int base = hw_config->io_base, irq = hw_config->irq;
+ int dma1 = hw_config->dma, dma2 = hw_config->dma2;
+
+ /*
+ * Verify that the I/O port range is free.
+ */
+
+ if (0) {
+ printf("cs4232.c: I/O port 0x%03x not free\n", base);
+ return 0;
+ }
+ /*
+ * This version of the driver doesn't use the PnP method when
+ * configuring the card but a simplified method defined by Crystal.
+ * This means that just one CS4232 compatible device can exist on the
+ * system. Also this method conflicts with possible PnP support in
+ * the OS. For this reason driver is just a temporary kludge.
+ */
+
+ /*
+ * Wake up the card by sending a 32 byte Crystal key to the key port.
+ */
+ for (i = 0; i < 32; i++)
+ CS_OUT(crystal_key[i]);
+
+ /*
+ * Now set the CSN (Card Select Number).
+ */
+
+ CS_OUT2(0x06, CSN_NUM);
+
+ /*
+ * Ensure that there is no other codec using the same address.
+ */
+
+ CS_OUT2(0x15, 0x00); /* Select logical device 0 (WSS/SB/FM) */
+ CS_OUT2(0x33, 0x00); /* Inactivate logical dev 0 */
+ if (ad1848_detect(hw_config->io_base, NULL, hw_config->osp))
+ return 0;
+
+ /*
+ * Then set some config bytes. First logical device 0
+ */
+
+ CS_OUT2(0x15, 0x00); /* Select logical device 0 (WSS/SB/FM) */
+ CS_OUT3(0x47, (base >> 8) & 0xff, base & 0xff); /* WSSbase */
+
+ if (0) /* Not free */
+ CS_OUT3(0x48, 0x00, 0x00) /* FMbase off */
+ else
+ CS_OUT3(0x48, 0x03, 0x88); /* FMbase 0x388 */
+
+ CS_OUT3(0x42, 0x00, 0x00); /* SBbase off */
+ CS_OUT2(0x22, irq); /* SB+WSS IRQ */
+ CS_OUT2(0x2a, dma1); /* SB+WSS DMA */
+
+ if (dma2 != -1)
+ CS_OUT2(0x25, dma2) /* WSS DMA2 */
+ else
+ CS_OUT2(0x25, 4); /* No WSS DMA2 */
+
+ CS_OUT2(0x33, 0x01); /* Activate logical dev 0 */
+
+ /*
+ * Initialize logical device 3 (MPU)
+ */
+
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
+ if (mpu_base != 0 && mpu_irq != 0) {
+ CS_OUT2(0x15, 0x03); /* Select logical device 3 (MPU) */
+ CS_OUT3(0x47, (mpu_base >> 8) & 0xff, mpu_base & 0xff); /* MPUbase */
+ CS_OUT2(0x22, mpu_irq); /* MPU IRQ */
+ CS_OUT2(0x33, 0x01); /* Activate logical dev 3 */
+ }
+#endif
+
+ /*
+ * Finally activate the chip
+ */
+ CS_OUT(0x79);
+
+ /*
+ * Then try to detect the codec part of the chip
+ */
+
+ return ad1848_detect(hw_config->io_base, NULL, hw_config->osp);
+}
+
+void
+attach_cs4232(struct address_info * hw_config)
+{
+ int base = hw_config->io_base, irq = hw_config->irq;
+ int dma1 = hw_config->dma, dma2 = hw_config->dma2;
+
+ if (dma2 == -1)
+ dma2 = dma1;
+
+ ad1848_init("CS4232", base,
+ irq,
+ dma1, /* Playback DMA */
+ dma2, /* Capture DMA */
+ 0,
+ hw_config->osp);
+
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
+ if (mpu_base != 0 && mpu_irq != 0) {
+ static struct address_info hw_config2 =
+ {0}; /* Ensure it's initialized */
+
+ hw_config2.io_base = mpu_base;
+ hw_config2.irq = mpu_irq;
+ hw_config2.dma = -1;
+ hw_config2.dma2 = -1;
+ hw_config2.always_detect = 0;
+ hw_config2.name = NULL;
+ hw_config2.card_subtype = 0;
+ hw_config2.osp = hw_config->osp;
+
+ if (probe_mpu401(&hw_config2)) {
+ mpu_detected = 1;
+ attach_mpu401(&hw_config2);
+ } else {
+ mpu_base = mpu_irq = 0;
+ }
+ }
+#endif
+}
+
+#endif
diff --git a/sys/i386/isa/sound/dev_table.c b/sys/i386/isa/sound/dev_table.c
index ed01fd4..42e5197 100644
--- a/sys/i386/isa/sound/dev_table.c
+++ b/sys/i386/isa/sound/dev_table.c
@@ -1,10 +1,10 @@
/*
* sound/dev_table.c
- *
+ *
* Device call tables.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,159 +24,280 @@
* 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 _DEV_TABLE_C_
#include <i386/isa/sound/sound_config.h>
-#ifdef CONFIGURE_SOUNDCARD
+#if NSND > 0
+
+int sound_started = 0;
+
+int sndtable_get_cardcount(void);
+int snd_find_driver(int type);
+void sndtable_init(void);
+int sndtable_probe(int unit, struct address_info * hw_config);
+int sndtable_init_card(int unit, struct address_info * hw_config);
+int sndtable_identify_card(char *name);
+void sound_chconf(int card_type, int ioaddr, int irq, int dma);
+static void start_services(void);
+static void start_cards(void);
+struct address_info *sound_getconf(int card_type);
int
-snd_find_driver (int type)
+snd_find_driver(int type)
{
- int i, n = sizeof (sound_drivers) / sizeof (struct driver_info);
+ int i, n = num_sound_drivers;
- for (i = 0; i < (n - 1); i++)
- if (sound_drivers[i].card_type == type)
- return i;
+ for (i = 0; i < n; i++)
+ if (sound_drivers[i].card_type == type)
+ return i;
- return -1; /*
- * Not found
- */
+ return -1;
}
-static long
-sndtable_init (long mem_start)
+static void
+start_services()
{
- int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
- int drv;
-
- printk ("Sound initialization started\n");
-
- for (i = 0; i < (n - 1); i++)
- if (snd_installed_cards[i].enabled)
- if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1)
- 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",
- snd_installed_cards[i].card_type);
+ int soundcards_installed;
+
+ if (!(soundcards_installed = sndtable_get_cardcount()))
+ return ; /* No cards detected */
+
+#ifdef CONFIG_AUDIO
+ if (num_audiodevs) /* Audio devices present */
+ DMAbuf_init();
#endif
- 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",
- snd_installed_cards[i].config.io_base,
- snd_installed_cards[i].config.irq,
- snd_installed_cards[i].config.dma);
+#ifdef CONFIG_MIDI
+ if (num_midis)
+ /* MIDIbuf_init(0) */;
#endif
+
+#ifdef CONFIG_SEQUENCER
+ if (num_midis + num_synths)
+ sequencer_init();
+#endif
+}
+
+static void
+start_cards()
+{
+ int drv, i, n = num_sound_cards;
+ struct card_info *ci = snd_installed_cards ;
+
+ sound_started = 1;
+ if (trace_init)
+ printf("Sound initialization started\n");
+
+ /*
+ * Check the number of cards actually defined in the table
+ */
+
+ for (i = 0; i < n && snd_installed_cards[i].card_type; i++)
+ num_sound_cards = i + 1;
+
+ for (i = 0; i < n && ci->card_type; ci++, i++)
+ if (ci->enabled) {
+ if ((drv = snd_find_driver(ci->card_type)) == -1) {
+ ci->enabled = 0; /* Mark as not detected */
+ continue;
+ }
+ ci->config.card_subtype = sound_drivers[drv].card_subtype;
+
+ if (sound_drivers[drv].probe(&(ci->config)))
+ sound_drivers[drv].attach(&(ci->config));
+ else
+ ci->enabled = 0; /* Mark as not detected */
}
- else
- snd_installed_cards[i].enabled = 0; /*
- * Mark as not detected
- */
- printk ("Sound initialization complete\n");
- return mem_start;
+ if (trace_init)
+ printf("Sound initialization complete\n");
}
+void
+sndtable_init()
+{
+ start_cards();
+}
+
+/*
+ * sndtable_probe probes a specific device. unit is the voxware unit number.
+ */
+
int
-sndtable_probe (int unit, struct address_info *hw_config)
+sndtable_probe(int unit, struct address_info * hw_config)
{
- int r, i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
+ int i, sel = -1, n = num_sound_cards;
+ struct card_info *ci = snd_installed_cards ;
- if (!unit)
- return 0;
+ DDB(printf("-- sndtable_probe(%d)\n", unit));
+
+
+ /*
+ * for some reason unit 0 always succeeds ?
+ */
+ if (!unit)
+ return TRUE;
+
+ sound_started = 1;
+
+ for (i=0; i<n && sel== -1 && ci->card_type; ci++, i++)
+ if ( (ci->enabled) && (ci->card_type == unit) ) {
+ /* DDB(printf("-- found card %d\n", i) ); */
+ sel = i; /* and break */
+ }
- 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 ((r = sound_drivers[drv].probe (hw_config)))
- return r;
- snd_installed_cards[i].enabled = 0; /*
- * Mark as not detected
- */
- return 0;
+ /*
+ * not found. Creates a new entry in the table for this unit.
+ */
+ if (sel == -1 && num_sound_cards < max_sound_cards) {
+ int i;
+
+ i = sel = (num_sound_cards++);
+ DDB(printf("-- installing card %d\n", i) );
+
+ ci = &snd_installed_cards[sel] ;
+ ci->card_type = unit;
+ ci->enabled = 1;
+ }
+ /* DDB(printf("-- installed card %d\n", sel) ); */
+ if (sel != -1) {
+ int drv;
+
+ ci->config.io_base = hw_config->io_base;
+ ci->config.irq = hw_config->irq;
+ ci->config.dma = hw_config->dma;
+ ci->config.dma2 = hw_config->dma2;
+ ci->config.name = hw_config->name;
+ ci->config.always_detect = hw_config->always_detect;
+ ci->config.card_subtype = hw_config->card_subtype;
+ ci->config.osp = hw_config->osp;
+
+ if ((drv = snd_find_driver(ci->card_type)) == -1) {
+ ci->enabled = 0;
+ DDB(printf("Failed to find driver\n"));
+ return FALSE;
}
+ DDB(printf("-- Driver name '%s' probe 0x%08x\n",
+ sound_drivers[drv].name, sound_drivers[drv].probe));
+
+ hw_config->card_subtype =
+ ci->config.card_subtype = sound_drivers[drv].card_subtype;
- return 0;
+ if (sound_drivers[drv].probe(hw_config)) {
+ DDB(printf("-- Hardware probed OK\n"));
+ return TRUE;
+ }
+ DDB(printf("-- Failed to find hardware\n"));
+ ci->enabled = 0; /* mark as not detected */
+ return FALSE;
+ }
+ return FALSE;
}
int
-sndtable_init_card (int unit, struct address_info *hw_config)
+sndtable_init_card(int unit, struct address_info * hw_config)
{
- int i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
+ int i, n = num_sound_cards;
+ struct card_info *ci = snd_installed_cards ;
- if (!unit)
- {
- if (sndtable_init (0) != 0)
- panic ("snd: Invalid memory allocation\n");
- return TRUE;
- }
+ DDB(printf("sndtable_init_card(%d) entered\n", unit));
- 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");
+ if (!unit) {
+ sndtable_init() ;
return TRUE;
- }
+ }
+ for (i = 0; i < n && ci->card_type; ci++, i++)
+ if (ci->card_type == unit) {
+ int drv;
+
+ ci->config.io_base = hw_config->io_base;
+ ci->config.irq = hw_config->irq;
+ ci->config.dma = hw_config->dma;
+ ci->config.dma2 = hw_config->dma2;
+ ci->config.name = hw_config->name;
+ ci->config.always_detect = hw_config->always_detect;
+ ci->config.card_subtype = hw_config->card_subtype;
+ ci->config.osp = hw_config->osp;
- return FALSE;
+ if ((drv = snd_find_driver(ci->card_type)) == -1)
+ ci->enabled = 0; /* Mark not fnd */
+ else {
+ DDB(printf("Located card - calling attach routine\n"));
+ sound_drivers[drv].attach(hw_config) ;
+ DDB(printf("attach routine finished\n"));
+ }
+ start_services();
+ return TRUE;
+ }
+ DDB(printf("sndtable_init_card: No card defined with type=%d, num cards: %d\n",
+ unit, num_sound_cards));
+ return FALSE;
}
int
-sndtable_get_cardcount (void)
+sndtable_get_cardcount(void)
{
- return num_audiodevs + num_mixers + num_synths + num_midis;
+ return num_audiodevs + num_mixers + num_synths + num_midis;
}
-struct address_info *
-sound_getconf (int card_type)
+int
+sndtable_identify_card(char *name)
{
- int j, ptr;
- int n = sizeof (snd_installed_cards) / sizeof (struct card_info);
+ int i, n = num_sound_drivers;
- ptr = -1;
- for (j = 0; j < n && ptr == -1; j++)
- if (snd_installed_cards[j].card_type == card_type)
- ptr = j;
+ if (name == NULL)
+ return 0;
- if (ptr == -1)
- return (struct address_info *) NULL;
+ for (i = 0; i < n; i++)
+ if (sound_drivers[i].driver_id != NULL) {
+ char *id = sound_drivers[i].driver_id;
+ int j;
- return &snd_installed_cards[ptr].config;
+ for (j = 0; j < 80 && name[j] == id[j]; j++)
+ if (id[j] == 0 && name[j] == 0) /* Match */
+ return sound_drivers[i].card_type;
+ }
+ return 0;
}
-#else
-
void
-sound_setup (char *str, int *ints)
+sound_chconf(int card_type, int ioaddr, int irq, int dma)
+{
+ int j, ptr = -1, n = num_sound_cards;
+
+ for (j = 0; j < n && ptr == -1 && snd_installed_cards[j].card_type; j++)
+ if (snd_installed_cards[j].card_type == card_type &&
+ !snd_installed_cards[j].enabled) /* Not already found */
+ ptr = j;
+
+ if (ptr != -1) {
+ snd_installed_cards[ptr].enabled = 1;
+ if (ioaddr)
+ snd_installed_cards[ptr].config.io_base = ioaddr;
+ if (irq)
+ snd_installed_cards[ptr].config.irq = irq;
+ if (dma)
+ snd_installed_cards[ptr].config.dma = dma;
+ snd_installed_cards[ptr].config.dma2 = -1;
+ }
+}
+
+
+struct address_info *
+sound_getconf(int card_type)
{
+ int j, ptr = -1, n = num_sound_cards;
+
+ for (j = 0; j < n && ptr == -1 && snd_installed_cards[j].card_type; j++)
+ if (snd_installed_cards[j].card_type == card_type)
+ ptr = j;
+
+ if (ptr == -1)
+ return (struct address_info *) NULL;
+
+ return &snd_installed_cards[ptr].config;
}
#endif
diff --git a/sys/i386/isa/sound/dev_table.h b/sys/i386/isa/sound/dev_table.h
index 96a7f98..63067a4 100644
--- a/sys/i386/isa/sound/dev_table.h
+++ b/sys/i386/isa/sound/dev_table.h
@@ -1,58 +1,66 @@
/*
- * dev_table.h
- *
- * Global definitions for device call tables
+ * dev_table.h
+ *
+ * Global definitions for device call tables
*
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
- * 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
+ * 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.
- *
-
-*/
+ *
+ */
#ifndef _DEV_TABLE_H_
#define _DEV_TABLE_H_
/*
- * NOTE! NOTE! NOTE! NOTE!
- *
- * If you modify this file, please check the dev_table.c also.
- *
- * NOTE! NOTE! NOTE! NOTE!
+ * NOTE! NOTE! NOTE! NOTE!
+ *
+ * If you modify this file, please check the dev_table.c also.
+ *
+ * NOTE! NOTE! NOTE! NOTE!
*/
+extern int sound_started;
+
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);
+ char *driver_id;
+ int card_subtype; /* Driver specific. Usually 0 */
+ int card_type; /* From soundcard.h */
+ char *name;
+ void (*attach) (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 */
+ int card_type; /* Link (search key) to the driver list */
struct address_info config;
- int enabled;
+ int enabled;
};
+typedef struct pnp_sounddev {
+ int id;
+ void (*setup) (void *dev);
+ char *driver_name;
+} pnp_sounddev;
+
/*
* Device specific parameters (used only by dmabuf.c)
*/
@@ -63,373 +71,523 @@ struct card_info {
#define DMODE_INPUT 2
struct dma_buffparms {
- int dma_mode; /* DMODE_INPUT, DMODE_OUTPUT or DMODE_NONE */
-
- /*
- * Pointers to raw buffers
- */
+ int dma_mode; /* DMODE_INPUT, DMODE_OUTPUT or DMODE_NONE */
- char *raw_buf[DSP_BUFFCOUNT];
- unsigned long raw_buf_phys[DSP_BUFFCOUNT];
- int raw_count;
+ char *raw_buf; /* Pointers to raw buffers */
+ u_long raw_buf_phys;
- /*
- * Device state tables
- */
+ /*
+ * Device state tables
+ */
- unsigned long flags;
+ u_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;
+ int open_mode;
/*
* Queue parameters.
*/
- int qlen;
- int qhead;
- int qtail;
+ int qlen;
+ int qhead;
+ int qtail;
+
+ int nbufs;
+ int counts[MAX_SUB_BUFFERS];
+ int subdivision;
- 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 fragment_size;
- int max_fragments;
+ int bytes_in_use;
- int bytes_in_use;
+ int underrun_count;
+ int byte_counter;
- int underrun_count;
+ int mapping_flags;
+#define DMA_MAP_MAPPED 0x00000001
+ char neutral_byte;
};
/*
- * Structure for use with various microcontrollers and DSP processors
- * in the recent soundcards.
+ * Structure for use with various microcontrollers and DSP processors in the
+ * recent soundcards.
*/
typedef struct coproc_operations {
- char name[32];
- int (*open) (void *devc, int sub_device);
- void (*close) (void *devc, int sub_device);
- int (*ioctl) (void *devc, unsigned int cmd, unsigned int arg, int local);
- void (*reset) (void *devc);
+ char name[32];
+ int (*open) (void *devc, int sub_device);
+ void (*close) (void *devc, int sub_device);
+ int (*ioctl) (void *devc, u_int cmd, ioctl_arg arg, int local);
+ void (*reset) (void *devc);
- void *devc; /* Driver specific info */
- } coproc_operations;
+ void *devc; /* Driver specific info */
+} coproc_operations;
struct audio_operations {
- char name[32];
- int flags;
+ char name[32];
+ 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,
- int count, int intrflag, int dma_restart);
- void (*start_input) (int dev, unsigned long buf,
- int count, int intrflag, int dma_restart);
- int (*ioctl) (int dev, unsigned int cmd, unsigned int arg, int local);
- int (*prepare_for_input) (int dev, int bufsize, int nbufs);
- int (*prepare_for_output) (int dev, int bufsize, int nbufs);
- void (*reset) (int dev);
- void (*halt_xfer) (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;
+#define DMA_DUPLEX 4
+ 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,
+ int count, int intrflag, int dma_restart);
+ void (*start_input) (int dev, unsigned long buf,
+ int count, int intrflag, int dma_restart);
+ int (*ioctl) (int dev, u_int cmd, ioctl_arg arg, int local);
+ int (*prepare_for_input) (int dev, int bufsize, int nbufs);
+ int (*prepare_for_output) (int dev, int bufsize, int nbufs);
+ void (*reset) (int dev);
+ void (*halt_xfer) (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);
+ void (*halt_input) (int dev);
+ void (*halt_output) (int dev);
+ void (*trigger) (int dev, int bits);
+ long buffsize;
+ int dmachan1, dmachan2;
+ struct dma_buffparms *dmap_in, *dmap_out;
struct coproc_operations *coproc;
- int mixer_dev;
+ int mixer_dev;
+ int enable_bits;
+ int open_mode;
+ int go;
+ int otherside;
+ int busy;
};
struct mixer_operations {
- char name[32];
- int (*ioctl) (int dev, unsigned int cmd, unsigned int arg);
+ char name[32];
+ int (*ioctl) (int dev, unsigned int cmd, ioctl_arg arg);
};
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 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);
- void (*hw_control) (int dev, unsigned char *event);
- int (*load_patch) (int dev, int format, snd_rw_buf *addr,
- int offs, int count, int pmgr_flag);
- void (*aftertouch) (int dev, int voice, int pressure);
- void (*controller) (int dev, int voice, int ctrl_num, int value);
- 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);
- void (*setup_voice) (int dev, int voice, int chn);
-
- struct voice_alloc_info alloc;
- struct channel_info chn_info[16];
+ 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, ioctl_arg arg);
+ 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);
+ void (*hw_control) (int dev, unsigned char *event);
+ int (*load_patch) (int dev, int format, snd_rw_buf * addr,
+ int offs, int count, int pmgr_flag);
+ void (*aftertouch) (int dev, int voice, int pressure);
+ void (*controller) (int dev, int voice, int ctrl_num, int value);
+ 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);
+ void (*setup_voice) (int dev, int voice, int chn);
+ int (*send_sysex) (int dev, unsigned char *bytes, int len);
+
+ struct voice_alloc_info alloc;
+ struct channel_info chn_info[16];
};
-struct midi_input_info { /* MIDI input scanner variables */
+struct midi_input_info { /* MIDI input scanner variables */
#define MI_MAX 10
- int m_busy;
- unsigned char m_buf[MI_MAX];
- unsigned char m_prev_status; /* For running status */
- int m_ptr;
+ int m_busy;
+ unsigned char m_buf[MI_MAX];
+ unsigned char m_prev_status; /* For running status */
+ int m_ptr;
#define MST_INIT 0
#define MST_DATA 1
#define MST_SYSEX 2
- int m_state;
- int m_left;
- };
+ int m_state;
+ int m_left;
+};
struct midi_operations {
struct midi_info info;
struct synth_operations *converter;
struct midi_input_info in_info;
- int (*open) (int dev, int mode,
- void (*inputintr)(int dev, unsigned char data),
- void (*outputintr)(int dev)
- );
- void (*close) (int dev);
- int (*ioctl) (int dev, unsigned int cmd, unsigned int arg);
- int (*putc) (int dev, unsigned char data);
- int (*start_read) (int dev);
- int (*end_read) (int dev);
- void (*kick)(int dev);
- int (*command) (int dev, unsigned char *data);
- int (*buffer_status) (int dev);
- int (*prefix_cmd) (int dev, unsigned char status);
+ int (*open) (int dev, int mode,
+ void (*inputintr) (int dev, unsigned char data),
+ void (*outputintr) (int dev) );
+ void (*close) (int dev);
+ int (*ioctl) (int dev, unsigned int cmd, ioctl_arg arg);
+ int (*putc) (int dev, unsigned char data);
+ int (*start_read) (int dev);
+ int (*end_read) (int dev);
+ void (*kick) (int dev);
+ int (*command) (int dev, unsigned char *data);
+ int (*buffer_status) (int dev);
+ int (*prefix_cmd) (int dev, unsigned char status);
struct coproc_operations *coproc;
};
+struct sound_lowlev_timer {
+ int dev;
+ u_int (*tmr_start) (int dev, unsigned int usecs);
+ void (*tmr_disable) (int dev);
+ void (*tmr_restart) (int dev);
+};
+
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);
+ int priority;
+ int devlink;
+ int (*open) (int dev, int mode);
+ void (*close) (int dev);
+ int (*event) (int dev, unsigned char *ev);
+ u_long (*get_time) (int dev);
+ int (*ioctl) (int dev, unsigned int cmd, ioctl_arg arg);
+ void (*arm_timer) (int dev, long time);
};
-#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;
+#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;
+
+#ifdef CONFIG_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;
+struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = {NULL};
+int num_sound_timers = 0;
#endif
/*
* List of low level drivers compiled into the kernel.
+ *
+ * remember, each entry contains:
+
+ char *driver_id;
+ int card_subtype; (Driver specific. Usually 0)
+ int card_type; (From soundcard.h)
+ char *name;
+ void (*attach) (struct address_info * hw_config);
+ int (*probe) (struct address_info * hw_config);
+ *
*/
- struct driver_info sound_drivers[] = {
-#ifndef EXCLUDE_PSS
- {SNDCARD_PSS, "Echo Personal Sound System PSS (ESC614)", attach_pss, probe_pss},
-# ifdef PSS_MPU_BASE
- {SNDCARD_PSS_MPU, "PSS-MPU", attach_pss_mpu, probe_pss_mpu},
-# endif
-# ifdef PSS_MSS_BASE
- {SNDCARD_PSS_MSS, "PSS-MSS", attach_pss_mss, probe_pss_mss},
-# endif
+struct driver_info sound_drivers[] = {
+
+#ifdef CONFIG_PSS
+ {"PSSECHO", 0, SNDCARD_PSS, "Echo Personal Sound System PSS (ESC614)",
+ attach_pss, probe_pss},
+ {"PSSMPU", 0, SNDCARD_PSS_MPU, "PSS-MPU",
+ attach_pss_mpu, probe_pss_mpu},
+ {"PSSMSS", 0, SNDCARD_PSS_MSS, "PSS-MSS",
+ attach_pss_mss, probe_pss_mss},
#endif
-#ifndef EXCLUDE_YM3812
- {SNDCARD_ADLIB, "OPL-2/OPL-3 FM", attach_adlib_card, probe_adlib},
+
+#ifdef CONFIG_MSS
+ /* XXX changed type from 0 to 1 -lr 970705 */
+ {"MSS", 1, SNDCARD_MSS, "MS Sound System",
+ attach_mss, probe_mss},
+ /* MSS without IRQ/DMA config registers (for DEC Alphas) */
+ {"PCXBJ", 1, SNDCARD_PSEUDO_MSS, "MS Sound System (AXP)",
+ attach_mss, probe_mss},
#endif
-#ifndef EXCLUDE_PAS
- {SNDCARD_PAS, "ProAudioSpectrum", attach_pas_card, probe_pas},
+
+#ifdef CONFIG_MAD16
+ {"MAD16", 0, SNDCARD_MAD16, "MAD16/Mozart (MSS)",
+ attach_mad16, probe_mad16},
+ {"MAD16MPU", 0, SNDCARD_MAD16_MPU, "MAD16/Mozart (MPU)",
+ attach_mad16_mpu, probe_mad16_mpu},
#endif
-#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI)
- {SNDCARD_MPU401,"Roland MPU-401", attach_mpu401, probe_mpu401},
+
+#ifdef CONFIG_CS4232
+ {"CS4232", 0, SNDCARD_CS4232, "CS4232",
+ attach_cs4232, probe_cs4232},
+ {"CS4232MPU", 0, SNDCARD_CS4232_MPU, "CS4232 MIDI",
+ attach_cs4232_mpu, probe_cs4232_mpu},
#endif
-#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI)
- {SNDCARD_UART6850,"6860 UART Midi", attach_uart6850, probe_uart6850},
+
+#ifdef CONFIG_YM3812
+ {"OPL3", 0, SNDCARD_ADLIB, "OPL-2/OPL-3 FM",
+ attach_adlib_card, probe_adlib},
#endif
-#ifndef EXCLUDE_SB
- {SNDCARD_SB, "SoundBlaster", attach_sb_card, probe_sb},
+
+#ifdef CONFIG_PAS
+ {"PAS16", 0, SNDCARD_PAS, "ProAudioSpectrum",
+ attach_pas_card, probe_pas},
+#endif
+
+#if defined(CONFIG_MPU401) && defined(CONFIG_MIDI)
+ {"MPU401", 0, SNDCARD_MPU401, "Roland MPU-401",
+ attach_mpu401, probe_mpu401},
+#endif
+
+#if defined(CONFIG_MAUI)
+ {"MAUI", 0, SNDCARD_MAUI, "TB Maui",
+ attach_maui, probe_maui},
#endif
-#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16)
-#ifndef EXCLUDE_AUDIO
- {SNDCARD_SB16, "SoundBlaster16", sb16_dsp_init, sb16_dsp_detect},
+
+#if defined(CONFIG_UART6850) && defined(CONFIG_MIDI)
+ {"MIDI6850", 0, SNDCARD_UART6850, "6860 UART Midi",
+ attach_uart6850, probe_uart6850},
#endif
-#ifndef EXCLUDE_AWE32
- {SNDCARD_AWE32, "AWE32 Synth", attach_awe_obsolete, probe_awe_obsolete},
+
+#ifdef CONFIG_SB
+ {"SBLAST", 0, SNDCARD_SB, "SoundBlaster",
+ attach_sb_card, probe_sb},
#endif
-#ifndef EXCLUDE_MIDI
- {SNDCARD_SB16MIDI,"SB16 MIDI", attach_sb16midi, probe_sb16midi},
+
+#if defined(CONFIG_SB) && defined(CONFIG_SB16)
+#ifdef CONFIG_AUDIO
+ {"SB16", 0, SNDCARD_SB16, "SoundBlaster16",
+ sb16_dsp_init, sb16_dsp_detect},
#endif
+#ifdef CONFIG_AWE32
+ {"AWE32", 0, SNDCARD_AWE32, "AWE32 Synth",
+ attach_awe_obsolete, probe_awe_obsolete},
#endif
-#ifndef EXCLUDE_GUS16
- {SNDCARD_GUS16, "Ultrasound 16-bit opt.", attach_gus_db16, probe_gus_db16},
+#ifdef CONFIG_MIDI
+ {"SB16MIDI", 0, SNDCARD_SB16MIDI, "SB16 MIDI",
+ attach_sb16midi, probe_sb16midi},
#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},
+
+#ifdef CONFIG_GUS16
+ {"GUS16", 0, SNDCARD_GUS16, "Ultrasound 16-bit opt.",
+ attach_gus_db16, probe_gus_db16},
#endif
-#ifndef EXCLUDE_SSCAPE
- {SNDCARD_SSCAPE, "Ensoniq Soundscape", attach_sscape, probe_sscape},
- {SNDCARD_SSCAPE_MSS, "MS Sound System (SoundScape)", attach_ss_ms_sound, probe_ss_ms_sound},
+
+#ifdef CONFIG_GUS
+ {"GUS", 0, SNDCARD_GUS, "Gravis Ultrasound",
+ attach_gus_card, probe_gus},
#endif
-#ifndef EXCLUDE_TRIX
- {SNDCARD_TRXPRO, "MediaTriX AudioTriX Pro", attach_trix_wss, probe_trix_wss},
- {SNDCARD_TRXPRO_SB, "AudioTriX (SB mode)", attach_trix_sb, probe_trix_sb},
- {SNDCARD_TRXPRO_MPU, "AudioTriX MIDI", attach_trix_mpu, probe_trix_mpu},
+
+#ifdef CONFIG_SSCAPE
+ {"SSCAPE", 0, SNDCARD_SSCAPE, "Ensoniq Soundscape",
+ attach_sscape, probe_sscape},
+ {"SSCAPEMSS", 0, SNDCARD_SSCAPE_MSS, "MS Sound System (SoundScape)",
+ attach_ss_mss, probe_ss_mss},
#endif
-#ifdef PC98
-#ifndef EXCLUDE_PCM86
- {SNDCARD_PCM86, "PC-9801-86/73", attach_pcm86, probe_pcm86},
+
+#if NTRIX > 0
+ {"TRXPRO", 0, SNDCARD_TRXPRO, "MediaTriX AudioTriX Pro",
+ attach_trix_wss, probe_trix_wss},
+ {"TRXPROSB", 0, SNDCARD_TRXPRO_SB, "AudioTriX (SB mode)",
+ attach_trix_sb, probe_trix_sb},
+ {"TRXPROMPU", 0, SNDCARD_TRXPRO_MPU, "AudioTriX MIDI",
+ attach_trix_mpu, probe_trix_mpu},
#endif
+
+#ifdef CONFIG_PNP
+ {"AD1848", 0, 500, "PnP MSS",
+ attach_pnp_ad1848, probe_pnp_ad1848},
#endif
- {0, "*?*", NULL, NULL}
- };
-#if defined(linux) || defined(__FreeBSD__)
+ {NULL, 0, 0, "*?*", NULL, NULL}
+};
+
+int num_sound_drivers =
+sizeof(sound_drivers) / sizeof(struct driver_info);
+int max_sound_drivers =
+sizeof(sound_drivers) / sizeof(struct driver_info);
+
+#define FULL_SOUND
+
+#ifndef FULL_SOUND
/*
- * List of devices actually configured in the system.
+ * List of devices actually configured in the system.
+ *
+ * Note! The detection order is significant. Don't change it.
+ *
+ * remember, the list contains
+ *
+ * int card_type; (Link (search key) to the driver list)
+ * struct address_info config;
+ * io_base, irq, dma, dma2,
+ * always_detect, char *name, struct... *osp
+ * int enabled;
+ * void *for_driver_use;
*
- * Note! The detection order is significant. Don't change it.
*/
- struct card_info snd_installed_cards[] = {
-#ifndef EXCLUDE_PSS
- {SNDCARD_PSS, {PSS_BASE, PSS_IRQ, PSS_DMA}, SND_DEFAULT_ENABLE},
-# ifdef PSS_MPU_BASE
- {SNDCARD_PSS_MPU, {PSS_MPU_BASE, PSS_MPU_IRQ, 0}, SND_DEFAULT_ENABLE},
-# endif
-# ifdef PSS_MSS_BASE
- {SNDCARD_PSS_MSS, {PSS_MSS_BASE, PSS_MSS_IRQ, PSS_MSS_DMA}, SND_DEFAULT_ENABLE},
-# endif
+struct card_info snd_installed_cards[] = {
+#ifdef CONFIG_PSS
+ {SNDCARD_PSS, {PSS_BASE, 0, -1, -1}, SND_DEFAULT_ENABLE},
+#ifdef PSS_MPU_BASE
+ {SNDCARD_PSS_MPU, {PSS_MPU_BASE, PSS_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
+#endif
+#ifdef PSS_MSS_BASE
+ {SNDCARD_PSS_MSS, {PSS_MSS_BASE, PSS_MSS_IRQ, PSS_MSS_DMA, -1}, SND_DEFAULT_ENABLE},
+#endif
+#endif /* config PSS */
+
+#if NTRIX > 0
+ {SNDCARD_TRXPRO, {TRIX_BASE, TRIX_IRQ, TRIX_DMA, TRIX_DMA2}, SND_DEFAULT_ENABLE},
+#ifdef TRIX_SB_BASE
+ {SNDCARD_TRXPRO_SB, {TRIX_SB_BASE, TRIX_SB_IRQ, TRIX_SB_DMA, -1}, SND_DEFAULT_ENABLE},
#endif
-#ifndef EXCLUDE_TRIX
- {SNDCARD_TRXPRO, {TRIX_BASE, TRIX_IRQ, TRIX_DMA}, SND_DEFAULT_ENABLE},
-# ifdef TRIX_SB_BASE
- {SNDCARD_TRXPRO_SB, {TRIX_SB_BASE, TRIX_SB_IRQ, TRIX_SB_DMA}, SND_DEFAULT_ENABLE},
-# endif
-# ifdef TRIX_MPU_BASE
- {SNDCARD_TRXPRO_MPU, {TRIX_MPU_BASE, TRIX_MPU_IRQ, 0}, SND_DEFAULT_ENABLE},
-# endif
+#ifdef TRIX_MPU_BASE
+ {SNDCARD_TRXPRO_MPU, {TRIX_MPU_BASE, TRIX_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
#endif
-#ifndef EXCLUDE_SSCAPE
- {SNDCARD_SSCAPE, {SSCAPE_BASE, SSCAPE_IRQ, SSCAPE_DMA}, SND_DEFAULT_ENABLE},
- {SNDCARD_SSCAPE_MSS, {SSCAPE_MSS_BASE, SSCAPE_MSS_IRQ, SSCAPE_MSS_DMA}, SND_DEFAULT_ENABLE},
+#endif /* NTRIX > 0 */
+
+#ifdef CONFIG_SSCAPE
+ {SNDCARD_SSCAPE, {SSCAPE_BASE, SSCAPE_IRQ, SSCAPE_DMA, -1}, SND_DEFAULT_ENABLE},
+ {SNDCARD_SSCAPE_MSS, {SSCAPE_MSS_BASE, SSCAPE_MSS_IRQ, SSCAPE_MSS_DMA, -1}, SND_DEFAULT_ENABLE},
#endif
-#ifndef EXCLUDE_MSS
- {SNDCARD_MSS, {MSS_BASE, MSS_IRQ, MSS_DMA}, SND_DEFAULT_ENABLE},
-# ifdef MSS2_BASE
- {SNDCARD_MSS, {MSS2_BASE, MSS2_IRQ, MSS2_DMA}, SND_DEFAULT_ENABLE},
-# endif
+#ifdef CONFIG_MAD16
+ {SNDCARD_MAD16, {MAD16_BASE, MAD16_IRQ, MAD16_DMA, MAD16_DMA2}, SND_DEFAULT_ENABLE},
+#ifdef MAD16_MPU_BASE
+ {SNDCARD_MAD16_MPU, {MAD16_MPU_BASE, MAD16_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
#endif
+#endif /* CONFIG_MAD16 */
-#ifndef EXCLUDE_PAS
- {SNDCARD_PAS, {PAS_BASE, PAS_IRQ, PAS_DMA}, SND_DEFAULT_ENABLE},
+#ifdef CONFIG_CS4232
+#ifdef CS4232_MPU_BASE
+ {SNDCARD_CS4232_MPU, {CS4232_MPU_BASE, CS4232_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
+#endif
+ {SNDCARD_CS4232, {CS4232_BASE, CS4232_IRQ, CS4232_DMA, CS4232_DMA2}, SND_DEFAULT_ENABLE},
#endif
-#ifndef EXCLUDE_SB
- {SNDCARD_SB, {SBC_BASE, SBC_IRQ, SBC_DMA}, SND_DEFAULT_ENABLE},
+#ifdef CONFIG_MSS
+#ifdef PSEUDO_MSS
+ {SNDCARD_MSS, {MSS_BASE, MSS_IRQ, MSS_DMA, -1}, SND_DEFAULT_ENABLE},
+#else
+ {SNDCARD_PSEUDO_MSS, {MSS_BASE, MSS_IRQ, MSS_DMA, -1}, SND_DEFAULT_ENABLE},
#endif
+#ifdef MSS2_BASE
+ {SNDCARD_MSS, {MSS2_BASE, MSS2_IRQ, MSS2_DMA, -1}, SND_DEFAULT_ENABLE},
+#endif
+#endif /* CONFIG_MSS */
-#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI)
- {SNDCARD_MPU401, {MPU_BASE, MPU_IRQ, 0}, SND_DEFAULT_ENABLE},
-#ifdef MPU2_BASE
- {SNDCARD_MPU401, {MPU2_BASE, MPU2_IRQ, 0}, SND_DEFAULT_ENABLE},
+#ifdef CONFIG_PAS
+ {SNDCARD_PAS, {PAS_BASE, PAS_IRQ, PAS_DMA, -1}, SND_DEFAULT_ENABLE},
#endif
-#ifdef MPU3_BASE
- {SNDCARD_MPU401, {MPU3_BASE, MPU2_IRQ, 0}, SND_DEFAULT_ENABLE},
+
+#ifdef CONFIG_SB
+#ifndef SBC_DMA
+#define SBC_DMA 1
#endif
+ {SNDCARD_SB, {SBC_BASE, SBC_IRQ, SBC_DMA, -1}, SND_DEFAULT_ENABLE},
#endif
-#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI)
- {SNDCARD_UART6850, {U6850_BASE, U6850_IRQ, 0}, SND_DEFAULT_ENABLE},
+#if defined(CONFIG_MAUI)
+ {SNDCARD_MAUI, {MAUI_BASE, MAUI_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
#endif
-#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16)
-#ifndef EXCLUDE_AUDIO
- {SNDCARD_SB16, {SBC_BASE, SBC_IRQ, SB16_DMA}, SND_DEFAULT_ENABLE},
+#if defined(CONFIG_MPU401) && defined(CONFIG_MIDI)
+ {SNDCARD_MPU401, {MPU_BASE, MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
+#ifdef MPU2_BASE
+ {SNDCARD_MPU401, {MPU2_BASE, MPU2_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
#endif
-#ifndef EXCLUDE_MIDI
- {SNDCARD_SB16MIDI,{SB16MIDI_BASE, SBC_IRQ, 0}, SND_DEFAULT_ENABLE},
+#ifdef MPU3_BASE
+ {SNDCARD_MPU401, {MPU3_BASE, MPU2_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
#endif
-#ifndef EXCLUDE_AWE32
- {SNDCARD_AWE32,{AWE32_BASE, 0, 0}, SND_DEFAULT_ENABLE},
#endif
+
+#if defined(CONFIG_UART6850) && defined(CONFIG_MIDI)
+ {SNDCARD_UART6850, {U6850_BASE, U6850_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
#endif
-#ifndef EXCLUDE_GUS
-#ifndef EXCLUDE_GUS16
- {SNDCARD_GUS16, {GUS16_BASE, GUS16_IRQ, GUS16_DMA, GUS_DMA_READ}, SND_DEFAULT_ENABLE},
+#if defined(CONFIG_SB) && defined(CONFIG_SB16)
+#ifdef CONFIG_AUDIO
+ {SNDCARD_SB16, {SBC_BASE, SBC_IRQ, SB16_DMA, -1}, SND_DEFAULT_ENABLE},
+#endif
+#ifdef CONFIG_MIDI
+ {SNDCARD_SB16MIDI, {SB16MIDI_BASE, SBC_IRQ, 0, -1}, SND_DEFAULT_ENABLE},
+#endif
+#ifdef CONFIG_AWE32
+ {SNDCARD_AWE32,{AWE32_BASE, 0, 0, -1}, SND_DEFAULT_ENABLE},
#endif
- {SNDCARD_GUS, {GUS_BASE, GUS_IRQ, GUS_DMA, GUS_DMA_READ}, SND_DEFAULT_ENABLE},
#endif
-#ifndef EXCLUDE_YM3812
- {SNDCARD_ADLIB, {FM_MONO, 0, 0}, SND_DEFAULT_ENABLE},
+#ifdef CONFIG_GUS
+#ifdef CONFIG_GUS16
+ {SNDCARD_GUS16, {GUS16_BASE, GUS16_IRQ, GUS16_DMA, -1}, SND_DEFAULT_ENABLE},
#endif
-#ifdef PC98
-#ifndef EXCLUDE_PCM86
- {SNDCARD_PCM86, {0, 0, 0}, SND_DEFAULT_ENABLE},
+ {SNDCARD_GUS, {GUS_BASE, GUS_IRQ, GUS_DMA, GUS_DMA2}, SND_DEFAULT_ENABLE},
#endif
+
+#ifdef CONFIG_YM3812
+ {SNDCARD_ADLIB, {FM_MONO, 0, 0, -1}, SND_DEFAULT_ENABLE},
#endif
- {0, {0}, 0}
- };
+ /* Define some expansion space */
+ {0, {0}, 0},
+ {0, {0}, 0},
+ {0, {0}, 0},
+ {0, {0}, 0},
+ {0, {0}, 0}
+};
- int num_sound_cards =
- sizeof(snd_installed_cards) / sizeof (struct card_info);
+int num_sound_cards = sizeof(snd_installed_cards) / sizeof(struct card_info);
+int max_sound_cards = sizeof(snd_installed_cards) / sizeof(struct card_info);
#else
- int num_sound_cards = 0;
-#endif /* linux */
+int num_sound_cards = 0;
+struct card_info snd_installed_cards[20] = {{0}};
+int max_sound_cards = 20;
+#endif
- int num_sound_drivers =
- sizeof(sound_drivers) / sizeof (struct driver_info);
+#ifdef MODULE
+int trace_init = 0;
+#else
+int trace_init = 1;
+#endif
#else
- extern struct audio_operations * audio_devs[MAX_AUDIO_DEV]; extern 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+MAX_MIDI_DEV]; extern int num_synths;
- extern struct midi_operations * midi_devs[MAX_MIDI_DEV]; extern int num_midis;
- extern struct sound_timer_operations * sound_timer_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV]; extern int num_sound_timers;
-
- extern struct driver_info sound_drivers[];
- extern int num_sound_drivers;
- extern struct card_info snd_installed_cards[];
- extern int num_sound_cards;
-#endif /* _DEV_TABLE_C_ */
-
-int sndtable_probe(int unit, struct address_info *hw_config);
-int sndtable_init_card(int unit, struct address_info *hw_config);
-int sndtable_get_cardcount (void);
+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 + MAX_MIDI_DEV];
+extern int num_synths;
+extern struct midi_operations *midi_devs[MAX_MIDI_DEV];
+extern int num_midis;
+extern struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV];
+extern int num_sound_timers;
+
+extern struct driver_info sound_drivers[];
+extern int num_sound_drivers;
+extern int max_sound_drivers;
+extern struct card_info snd_installed_cards[];
+extern int num_sound_cards;
+extern int max_sound_cards;
+
+extern int trace_init;
+
+void sndtable_init(void);
+int sndtable_get_cardcount(void);
struct address_info *sound_getconf(int card_type);
-int snd_find_driver(int type);
-
-#endif /* _DEV_TABLE_H_ */
+void sound_chconf(int card_type, int ioaddr, int irq, int dma);
+int snd_find_driver(int type);
+int sndtable_identify_card(char *name);
+void sound_setup(char *str, int *ints);
+
+int sound_alloc_dmap(int dev, struct dma_buffparms * dmap, int chan);
+void sound_free_dmap(int dev, struct dma_buffparms * dmap);
+extern int soud_map_buffer(int dev, struct dma_buffparms * dmap, buffmem_desc * info);
+void install_pnp_sounddrv(struct pnp_sounddev * drv);
+int sndtable_probe(int unit, struct address_info * hw_config);
+int sndtable_init_card(int unit, struct address_info * hw_config);
+void sound_timer_init(struct sound_lowlev_timer * t, char *name);
+int
+sound_start_dma(int dev, struct dma_buffparms * dmap, int chan,
+ unsigned long physaddr,
+ int count, int dma_mode, int autoinit);
+void sound_dma_intr(int dev, struct dma_buffparms * dmap, int chan);
+
+#endif /* _DEV_TABLE_C_ */
+#endif /* _DEV_TABLE_H_ */
diff --git a/sys/i386/isa/sound/dmabuf.c b/sys/i386/isa/sound/dmabuf.c
index 02ad992..55b8ff1 100644
--- a/sys/i386/isa/sound/dmabuf.c
+++ b/sys/i386/isa/sound/dmabuf.c
@@ -1,10 +1,10 @@
/*
* sound/dmabuf.c
- *
+ *
* The DMA buffer manager for digitized voice applications
- *
+ *
* Copyright by Hannu Savolainen 1993, 1994, 1995
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,1112 +24,1570 @@
* 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 <i386/isa/sound/sound_config.h>
-#ifdef CONFIGURE_SOUNDCARD
+#if defined(CONFIG_AUDIO) || defined(CONFIG_GUS)
-#if !defined(EXCLUDE_AUDIO) || !defined(EXCLUDE_GUS)
+static int *in_sleeper[MAX_AUDIO_DEV] = {NULL};
+static volatile struct snd_wait in_sleep_flag[MAX_AUDIO_DEV] = {{0}};
+static int *out_sleeper[MAX_AUDIO_DEV] = {NULL};
+static volatile struct snd_wait out_sleep_flag[MAX_AUDIO_DEV] = {{0}};
-DEFINE_WAIT_QUEUES (dev_sleeper[MAX_AUDIO_DEV], dev_sleep_flag[MAX_AUDIO_DEV]);
+static int ndmaps = 0;
-static struct dma_buffparms dmaps[MAX_AUDIO_DEV] =
-{
- {0}}; /*
+#define MAX_DMAP (MAX_AUDIO_DEV*2)
+
+static struct dma_buffparms dmaps[MAX_DMAP] = {{0}};
+/*
+ * Primitive way to allocate such a large array. Needs dynamic run-time
+ * alloction.
+ */
- * Primitive way to allocate
- * such a large array.
- * Needs dynamic run-time alloction.
- */
+static int space_in_queue(int dev);
-static int space_in_queue (int);
-static void reorganize_buffers (int);
-static void dma_init_buffers (int);
+static void dma_reset_output(int dev);
+static void dma_reset_input(int dev);
static void
-reorganize_buffers (int dev)
+reorganize_buffers(int dev, struct dma_buffparms * dmap)
{
- /*
- * 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];
+ /*
+ * This routine breaks the physical device buffers to logical ones.
+ */
- unsigned i, p, n;
- unsigned sr, nc, sz, bsz;
+ struct audio_operations *dsp_dev = audio_devs[dev];
+ u_int sr, nc;
+ int bsz, sz, n, i;
- if (dmap->fragment_size == 0)
- { /* Compute the fragment size using the default algorithm */
+ if (dmap->fragment_size == 0) {
+ /* Compute the fragment size using the default algorithm */
- 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);
+ 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;
+ if (sz == 8)
+ dmap->neutral_byte = 254;
+ else
+ dmap->neutral_byte = 0x00;
+
+ if (sr < 1 || nc < 1 || sz < 1) {
+ printf("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 = sr * nc * sz;
+
+ sz /= 8; /* #bits -> #bytes */
- sz = sr * nc * sz;
+ /*
+ * Compute a buffer size for time not exeeding 1 second.
+ * Usually this algorithm gives a buffer size for 0.5 to 1.0
+ * seconds of sound (using the current speed, sample size and
+ * #channels).
+ */
- sz /= 8; /* #bits -> #bytes */
+ bsz = dsp_dev->buffsize;
+ while (bsz > sz)
+ bsz /= 2;
- /*
- * 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).
- */
+ if (bsz == dsp_dev->buffsize)
+ bsz /= 2; /* Needs at least 2 buffers */
- bsz = dsp_dev->buffsize;
- while (bsz > sz)
- bsz /= 2;
+ if (dmap->subdivision == 0) /* Not already set */
+ dmap->subdivision = 1; /* Init to default value */
+ else
+ bsz /= dmap->subdivision;
+
+ if (bsz < 16)
+ bsz = 16; /* Just a sanity check */
+
+ 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 / 2))
+ dmap->fragment_size = (audio_devs[dev]->buffsize / 2);
+ bsz = dmap->fragment_size;
+ }
- if (dsp_dev->buffcount == 1 && bsz == dsp_dev->buffsize)
- bsz /= 2; /* Needs at least 2 buffers */
+ bsz &= ~0x03; /* Force size which is multiple of 4 bytes */
+#ifdef OS_DMA_ALIGN_CHECK
+ OS_DMA_ALIGN_CHECK(bsz);
+#endif
- if (dmap->subdivision == 0) /* Not already set */
- dmap->subdivision = 1; /* Init to default value */
- else
- bsz /= dmap->subdivision;
+ n = dsp_dev->buffsize / bsz;
- if (bsz < 16)
- bsz = 16; /* Just a sanity check */
+ if (n > MAX_SUB_BUFFERS)
+ n = MAX_SUB_BUFFERS;
- while ((dsp_dev->buffsize * dsp_dev->buffcount) / bsz > MAX_SUB_BUFFERS)
- bsz *= 2;
+ if (n > dmap->max_fragments)
+ n = dmap->max_fragments;
+ dmap->nbufs = n;
+ dmap->bytes_in_use = n * bsz;
- dmap->fragment_size = bsz;
+ for (i = 0; i < dmap->nbufs; i++) {
+ dmap->counts[i] = 0;
}
- 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 / 2))
- dmap->fragment_size = (audio_devs[dev]->buffsize / 2);
- bsz = dmap->fragment_size;
+
+ if (dmap->raw_buf)
+ fillw (dmap->neutral_byte, dmap->raw_buf,
+ dmap->bytes_in_use/2);
+
+ dmap->flags |= DMA_ALLOC_DONE;
+
+}
+
+static void
+dma_init_buffers(int dev, struct dma_buffparms * dmap)
+{
+ if (dmap == audio_devs[dev]->dmap_out) {
+ out_sleep_flag[dev].aborting = 0;
+ out_sleep_flag[dev].mode = WK_NONE;
+ } else {
+ in_sleep_flag[dev].aborting = 0;
+ in_sleep_flag[dev].mode = WK_NONE;
}
- bsz &= ~0x03; /* Force size which is multiple of 4 bytes */
+ dmap->flags = DMA_BUSY; /* Other flags off */
+ dmap->qlen = dmap->qhead = dmap->qtail = 0;
+ dmap->nbufs = 1;
+ dmap->bytes_in_use = audio_devs[dev]->buffsize;
- /*
- * Now computing addresses for the logical buffers
- */
+ dmap->dma_mode = DMODE_NONE;
+ dmap->mapping_flags = 0;
+ dmap->neutral_byte = 0x00;
+}
- n = 0;
- for (i = 0; i < dmap->raw_count &&
- n < dmap->max_fragments &&
- n < MAX_SUB_BUFFERS; i++)
+static int
+open_dmap(int dev, int mode, struct dma_buffparms * dmap, int chan)
+{
+ if (dmap->flags & DMA_BUSY)
+ return -(EBUSY);
+
+#ifdef RUNTIME_DMA_ALLOC
{
- p = 0;
+ int err;
- while ((p + bsz) <= dsp_dev->buffsize &&
- n < dmap->max_fragments &&
- n < MAX_SUB_BUFFERS)
- {
- dmap->buf[n] = dmap->raw_buf[i] + p;
- dmap->buf_phys[n] = dmap->raw_buf_phys[i] + p;
- p += bsz;
- n++;
- }
+ if ((err = sound_alloc_dmap(dev, dmap, chan)) < 0)
+ return err;
}
+#endif
- dmap->nbufs = n;
- dmap->bytes_in_use = n * bsz;
+ if (dmap->raw_buf == NULL)
+ return -(ENOSPC); /* Memory allocation failed during boot */
- for (i = 0; i < dmap->nbufs; i++)
- {
- dmap->counts[i] = 0;
+ if (0) {
+ printf("Unable to grab(2) DMA%d for the audio driver\n", chan);
+ return -(EBUSY);
}
+ dmap->open_mode = mode;
+ dmap->subdivision = dmap->underrun_count = 0;
+ dmap->fragment_size = 0;
+ dmap->max_fragments = 65536; /* Just a large value */
+ dmap->byte_counter = 0;
+ isa_dma_acquire(chan);
+
+ dma_init_buffers(dev, dmap);
- dmap->flags |= DMA_ALLOC_DONE;
+ return 0;
}
static void
-dma_init_buffers (int dev)
+close_dmap(int dev, struct dma_buffparms * dmap, int chan)
{
- struct dma_buffparms *dmap = audio_devs[dev]->dmap = &dmaps[dev];
-
- RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]);
-
- dmap->flags = DMA_BUSY; /* Other flags off */
- dmap->qlen = dmap->qhead = dmap->qtail = 0;
- dmap->nbufs = 1;
- dmap->bytes_in_use = audio_devs[dev]->buffsize;
-
- dmap->dma_mode = DMODE_NONE;
+ if (dmap->flags & DMA_BUSY)
+ dmap->dma_mode = DMODE_NONE;
+ dmap->flags &= ~DMA_BUSY;
+ isa_dma_release(chan);
+#ifdef RUNTIME_DMA_ALLOC
+ sound_free_dmap(dev, dmap);
+#endif
}
int
-DMAbuf_open (int dev, int mode)
+DMAbuf_open(int dev, int mode)
{
- int retval;
- struct dma_buffparms *dmap = NULL;
+ int retval;
+ struct dma_buffparms *dmap_in = NULL;
+ struct dma_buffparms *dmap_out = NULL;
- if (dev >= num_audiodevs)
- {
- printk ("PCM device %d not installed.\n", dev);
- return RET_ERROR (ENXIO);
+ if (dev >= num_audiodevs) {
+ printf("PCM device %d not installed.\n", dev);
+ return -(ENXIO);
}
-
- if (!audio_devs[dev])
- {
- printk ("PCM device %d not initialized\n", dev);
- return RET_ERROR (ENXIO);
+ if (!audio_devs[dev]) {
+ printf("PCM device %d not initialized\n", dev);
+ return -(ENXIO);
}
+ if (!(audio_devs[dev]->flags & DMA_DUPLEX)) {
+ audio_devs[dev]->dmap_in = audio_devs[dev]->dmap_out;
+ audio_devs[dev]->dmachan2 = audio_devs[dev]->dmachan1;
+ }
+ if ((retval = audio_devs[dev]->open(dev, mode)) < 0)
+ return retval;
- dmap = audio_devs[dev]->dmap = &dmaps[dev];
-
- if (dmap->flags & DMA_BUSY)
- return RET_ERROR (EBUSY);
+ dmap_out = audio_devs[dev]->dmap_out;
+ dmap_in = audio_devs[dev]->dmap_in;
-#ifdef USE_RUNTIME_DMAMEM
- dmap->raw_buf[0] = NULL;
- sound_dma_malloc (dev);
-#endif
+ if ((retval = open_dmap(dev, mode, dmap_out, audio_devs[dev]->dmachan1)) < 0) {
+ audio_devs[dev]->close(dev);
+ return retval;
+ }
+ audio_devs[dev]->enable_bits = mode;
- if (dmap->raw_buf[0] == NULL)
- return RET_ERROR (ENOSPC); /* Memory allocation failed during boot */
+ if (audio_devs[dev]->flags & DMA_DUPLEX && dmap_out != dmap_in) {
+ if ((retval = open_dmap(dev, mode, dmap_in, audio_devs[dev]->dmachan2)) < 0) {
+ audio_devs[dev]->close(dev);
+ close_dmap(dev, dmap_out, audio_devs[dev]->dmachan1);
+ return retval;
+ }
+ }
+ audio_devs[dev]->open_mode = mode;
+ audio_devs[dev]->go = 1;
- if ((retval = audio_devs[dev]->open (dev, mode)) < 0)
- return retval;
+ in_sleep_flag[dev].aborting = 0;
+ in_sleep_flag[dev].mode = WK_NONE;
- dmap->open_mode = mode;
- dmap->subdivision = dmap->underrun_count = 0;
- dmap->fragment_size = 0;
- dmap->max_fragments = 65536; /* Just a large value */
+ out_sleep_flag[dev].aborting = 0;
+ out_sleep_flag[dev].mode = WK_NONE;
- dma_init_buffers (dev);
- 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);
+ audio_devs[dev]->ioctl(dev, SOUND_PCM_WRITE_BITS, (ioctl_arg) 8, 1);
+ audio_devs[dev]->ioctl(dev, SOUND_PCM_WRITE_CHANNELS, (ioctl_arg) 1, 1);
+ audio_devs[dev]->ioctl(dev, SOUND_PCM_WRITE_RATE, (ioctl_arg) DSP_DEFAULT_SPEED, 1);
- return 0;
+ return 0;
}
static void
-dma_reset (int dev)
+dma_reset(int dev)
{
- int retval;
- unsigned long flags;
+ u_long flags;
- DISABLE_INTR (flags);
+ flags = splhigh();
+ audio_devs[dev]->reset(dev);
+ splx(flags);
- audio_devs[dev]->reset (dev);
- audio_devs[dev]->close (dev);
+ dma_reset_output(dev);
- 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);
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ dma_reset_input(dev);
+}
- dma_init_buffers (dev);
- reorganize_buffers (dev);
+static void
+dma_reset_output(int dev)
+{
+ u_long flags;
+
+ flags = splhigh();
+ if (!(audio_devs[dev]->flags & DMA_DUPLEX) ||
+ !audio_devs[dev]->halt_output)
+ audio_devs[dev]->reset(dev);
+ else
+ audio_devs[dev]->halt_output(dev);
+ splx(flags);
+
+ dma_init_buffers(dev, audio_devs[dev]->dmap_out);
+ reorganize_buffers(dev, audio_devs[dev]->dmap_out);
+}
+
+static void
+dma_reset_input(int dev)
+{
+ u_long flags;
+
+ flags = splhigh();
+ if (!(audio_devs[dev]->flags & DMA_DUPLEX) ||
+ !audio_devs[dev]->halt_input)
+ audio_devs[dev]->reset(dev);
+ else
+ audio_devs[dev]->halt_input(dev);
+ splx(flags);
+
+ dma_init_buffers(dev, audio_devs[dev]->dmap_in);
+ reorganize_buffers(dev, audio_devs[dev]->dmap_in);
}
static int
-dma_sync (int dev)
+dma_sync(int dev)
{
- unsigned long flags;
+ u_long flags;
+ int i = 0;
+
+ if (!audio_devs[dev]->go && (!audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT))
+ return 0;
+
+ if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) {
+ flags = splhigh();
+
+ out_sleep_flag[dev].aborting = 0;
+#ifdef ALLOW_BUFFER_MAPPING
+ if(audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED &&
+ audio_devs[dev]->dmap_out->qlen) {
+ splx(flags);
+
+ return audio_devs[dev]->dmap_out->qlen;
+ }
- if (audio_devs[dev]->dmap->dma_mode == DMODE_OUTPUT)
- {
- DISABLE_INTR (flags);
+#endif
+ while (!PROCESS_ABORTING (out_sleep_flag[dev])
+ && audio_devs[dev]->dmap_out->qlen){
+ int chn;
+
+ out_sleeper[dev] = &chn;
+ DO_SLEEP1(chn, out_sleep_flag[dev], 10 * hz);
+ if (TIMED_OUT (out_sleep_flag[dev]) ) {
+
+ splx(flags);
+
+ return audio_devs[dev]->dmap_out->qlen;
- 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]))
- {
- RESTORE_INTR (flags);
- return audio_devs[dev]->dmap->qlen;
- }
+ }
}
- RESTORE_INTR (flags);
- /*
- * Some devices such as GUS have huge amount of on board RAM for the
- * audio data. We have to wait until the device has finished playing.
- */
- DISABLE_INTR (flags);
- if (audio_devs[dev]->local_qlen) /* Device has hidden buffers */
- {
- 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);
+ splx(flags);
+
+ /*
+ * Some devices such as GUS have huge amount of on board RAM
+ * for the audio data. We have to wait until the device has
+ * finished playing.
+ */
+
+ flags = splhigh();
+ if (audio_devs[dev]->local_qlen) { /* Device has hidden buffers */
+ while (!(PROCESS_ABORTING (out_sleep_flag[dev]))
+ && audio_devs[dev]->local_qlen(dev)) {
+ int chn;
+ out_sleeper[dev] = &chn;
+ DO_SLEEP(chn, out_sleep_flag[dev], 10 * hz);
+
}
}
- RESTORE_INTR (flags);
+ splx(flags);
}
- return audio_devs[dev]->dmap->qlen;
+ return audio_devs[dev]->dmap_out->qlen;
}
int
-DMAbuf_release (int dev, int mode)
+DMAbuf_release(int dev, int mode)
{
- unsigned long flags;
+ u_long flags;
- if (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]))
- && (audio_devs[dev]->dmap->dma_mode == DMODE_OUTPUT))
- {
- dma_sync (dev);
+ if (!((out_sleep_flag[dev].aborting))
+ && (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)) {
+ dma_sync(dev);
}
+ flags = splhigh();
-#ifdef USE_RUNTIME_DMAMEM
- sound_dma_free (dev);
-#endif
+ audio_devs[dev]->close(dev);
- DISABLE_INTR (flags);
- audio_devs[dev]->reset (dev);
+ close_dmap(dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);
- audio_devs[dev]->close (dev);
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ close_dmap(dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2);
+ audio_devs[dev]->open_mode = 0;
- audio_devs[dev]->dmap->dma_mode = DMODE_NONE;
- audio_devs[dev]->dmap->flags &= ~DMA_BUSY;
- RESTORE_INTR (flags);
+ splx(flags);
- return 0;
+ return 0;
}
-int
-DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock)
+static int
+activate_recording(int dev, struct dma_buffparms * dmap)
{
- unsigned long flags;
- int err = EIO;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+ if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT))
+ return 0;
- DISABLE_INTR (flags);
- if (!dmap->qlen)
- {
- if (dmap->flags & DMA_RESTART)
- {
- dma_reset (dev);
- dmap->flags &= ~DMA_RESTART;
- }
+ if (dmap->flags & DMA_RESTART) {
+ dma_reset_input(dev);
+ dmap->flags &= ~DMA_RESTART;
+ }
+ if (dmap->dma_mode == DMODE_OUTPUT) { /* Direction change */
+ dma_sync(dev);
+ dma_reset(dev);
+ dmap->dma_mode = DMODE_NONE;
+ }
+ if (!(dmap->flags & DMA_ALLOC_DONE))
+ reorganize_buffers(dev, dmap);
- if (dmap->dma_mode == DMODE_OUTPUT) /* Direction change */
- {
- dma_sync (dev);
- dma_reset (dev);
- dmap->dma_mode = DMODE_NONE;
- }
+ if (!dmap->dma_mode) {
+ int err;
- if (!(dmap->flags & DMA_ALLOC_DONE))
- reorganize_buffers (dev);
+ if ((err = audio_devs[dev]->prepare_for_input(dev,
+ dmap->fragment_size, dmap->nbufs)) < 0) {
+ return err;
+ }
+ dmap->dma_mode = DMODE_INPUT;
+ }
+ if (!(dmap->flags & DMA_ACTIVE)) {
+ audio_devs[dev]->start_input(dev,
+ dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size,
+ dmap->fragment_size, 0,
+ !(audio_devs[dev]->flags & DMA_AUTOMODE) ||
+ !(dmap->flags & DMA_STARTED));
+ dmap->flags |= DMA_ACTIVE | DMA_STARTED;
+ if (audio_devs[dev]->trigger)
+ audio_devs[dev]->trigger(dev,
+ audio_devs[dev]->enable_bits * audio_devs[dev]->go);
+ }
+ return 0;
+}
- if (!dmap->dma_mode)
- {
- int err;
+int
+DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock)
+{
+ u_long flags;
+ int err = EIO;
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
+
+ flags = splhigh();
+#ifdef ALLOW_BUFFER_MAPPING
+ if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) {
+ printf("Sound: Can't read from mmapped device (1)\n");
+ return -(EINVAL);
+ } else
+#endif
+ if (!dmap->qlen) {
+ int timeout;
- if ((err = audio_devs[dev]->prepare_for_input (dev,
- dmap->fragment_size, dmap->nbufs)) < 0)
- {
- RESTORE_INTR (flags);
- return err;
- }
- dmap->dma_mode = DMODE_INPUT;
+ if ((err = activate_recording(dev, dmap)) < 0) {
+ splx(flags);
+ return err;
}
+ /* Wait for the next block */
- if (!(dmap->flags & DMA_ACTIVE))
- {
- 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;
+ if (dontblock) {
+ splx(flags);
+ return -(EAGAIN);
}
+ if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT) &
+ audio_devs[dev]->go) {
+ splx(flags);
+ return -(EAGAIN);
+ }
+ if (!audio_devs[dev]->go)
+ timeout = 0;
+ else
+ timeout = 2 * hz;
- if (dontblock)
{
- RESTORE_INTR (flags);
-#if defined(__FreeBSD__)
- return RET_ERROR (EWOULDBLOCK);
-#else
- return RET_ERROR (EAGAIN);
+ int chn;
+
+ in_sleeper[dev] = &chn;
+ DO_SLEEP(chn, in_sleep_flag[dev], timeout);
+
+ };
+ /* XXX note -- nobody seems to set the mode to WK_TIMEOUT - lr */
+ if ((in_sleep_flag[dev].mode & WK_TIMEOUT)) {
+ /* XXX hey, we are in splhigh here ? lr 970705 */
+ printf("Sound: DMA (input) timed out - IRQ/DRQ config error?\n");
+ err = EIO;
+ audio_devs[dev]->reset(dev);
+ in_sleep_flag[dev].aborting = 1;
+ } else
+ err = EINTR;
+ }
+ splx(flags);
+
+ if (!dmap->qlen)
+ return -(err);
+
+ *buf = &dmap->raw_buf[dmap->qhead * dmap->fragment_size + dmap->counts[dmap->qhead]];
+ *len = dmap->fragment_size - dmap->counts[dmap->qhead];
+
+ return dmap->qhead;
+}
+
+int
+DMAbuf_rmchars(int dev, int buff_no, int c)
+{
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
+
+ int p = dmap->counts[dmap->qhead] + c;
+
+#ifdef ALLOW_BUFFER_MAPPING
+ if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) {
+ printf("Sound: Can't read from mmapped device (2)\n");
+ return -(EINVAL);
+ } else
#endif
- }
+ if (p >= dmap->fragment_size) { /* This buffer is completely empty */
+ dmap->counts[dmap->qhead] = 0;
+ if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
+ printf("\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
+ dmap->counts[dmap->qhead] = p;
- /* Wait for the next block */
+ return 0;
+}
- 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");
- dma_reset (dev);
- err = EIO;
- SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]);
- }
- else
- err = EINTR;
+static int
+dma_subdivide(int dev, struct dma_buffparms * dmap, ioctl_arg arg, int fact)
+{
+ if (fact == 0) {
+ fact = dmap->subdivision;
+ if (fact == 0)
+ fact = 1;
+ return *(int *) arg = fact;
}
- RESTORE_INTR (flags);
+ if (dmap->subdivision != 0 || dmap->fragment_size)/* Loo late to change */
+ return -(EINVAL);
- if (!dmap->qlen)
- return RET_ERROR (err);
+ if (fact > MAX_REALTIME_FACTOR)
+ return -(EINVAL);
- *buf = &dmap->buf[dmap->qhead][dmap->counts[dmap->qhead]];
- *len = dmap->fragment_size - dmap->counts[dmap->qhead];
+ if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16)
+ return -(EINVAL);
- return dmap->qhead;
+ dmap->subdivision = fact;
+ return *(int *) arg = fact;
}
-int
-DMAbuf_rmchars (int dev, int buff_no, int c)
+static int
+dma_set_fragment(int dev, struct dma_buffparms * dmap, ioctl_arg arg, int fact)
{
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
-
- int p = dmap->counts[dmap->qhead] + c;
-
- 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;
+ int bytes, count;
+
+ if (fact == 0)
+ return -(EIO);
+
+ if (dmap->subdivision != 0 || dmap->fragment_size)/* Loo late to change */
+ return -(EINVAL);
+
+ bytes = fact & 0xffff;
+ count = (fact >> 16) & 0xffff;
+
+ if (count == 0)
+ count = MAX_SUB_BUFFERS;
+
+#if amancio
+ if (bytes < 4 || bytes > 17) /* <16 || > 128k */
+ return -(EINVAL);
+#endif
+
+ if (count < 2)
+ return -(EINVAL);
+
+#ifdef OS_DMA_MINBITS
+ if (bytes < OS_DMA_MINBITS)
+ bytes = OS_DMA_MINBITS;
+#endif
+
+ 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 *(int *) arg = bytes | (count << 16);
+}
+
+static int
+get_buffer_pointer(int dev, int chan, struct dma_buffparms * dmap)
+{
+ int pos;
+ u_long flags;
+
+ flags = splhigh();
+
+ if (!(dmap->flags & DMA_ACTIVE))
+ pos = 0;
+ else
+ {
+ pos = isa_dmastatus(chan);
}
+
+ splx(flags);
+
+ pos = dmap->bytes_in_use - pos ;
+ if (audio_devs[dev]->flags & DMA_AUTOMODE)
+ return pos;
else
- dmap->counts[dmap->qhead] = p;
+ {
+ pos = dmap->fragment_size - pos;
+ if (pos < 0)
+ return 0;
+ return pos;
+ }
+
- return 0;
}
int
-DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
+DMAbuf_ioctl(int dev, u_int cmd, ioctl_arg arg, int local)
{
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+ struct dma_buffparms *dmap_out = audio_devs[dev]->dmap_out;
+ struct dma_buffparms *dmap_in = audio_devs[dev]->dmap_in;
+
+ switch (cmd) {
+
- switch (cmd)
- {
case SNDCTL_DSP_RESET:
- dma_reset (dev);
- return 0;
- break;
+ dma_reset(dev);
+ return 0;
+ break;
case SNDCTL_DSP_SYNC:
- dma_sync (dev);
- dma_reset (dev);
- return 0;
- break;
+ dma_sync(dev);
+ dma_reset(dev);
+ return 0;
+ break;
case SNDCTL_DSP_GETBLKSIZE:
- if (!(dmap->flags & DMA_ALLOC_DONE))
- reorganize_buffers (dev);
+ if (!(dmap_out->flags & DMA_ALLOC_DONE))
+ reorganize_buffers(dev, dmap_out);
- return IOCTL_OUT (arg, dmap->fragment_size);
- break;
+ return *(int *) arg = dmap_out->fragment_size;
+ break;
case SNDCTL_DSP_SETBLKSIZE:
- {
- int size = IOCTL_IN(arg);
-
- if(!(dmap->flags & DMA_ALLOC_DONE) && size)
- {
- dmap->fragment_size = size;
- return 0;
- }
- else
- return RET_ERROR (EINVAL); /* Too late to change */
- }
- break;
+ {
+ int size = (*(int *) arg);
- case SNDCTL_DSP_SUBDIVIDE:
- {
- int fact = IOCTL_IN (arg);
+ if (!(dmap_out->flags & DMA_ALLOC_DONE) && size) {
+ if ((size >> 16) > 0 )
+ dmap_out->fragment_size = size >> 16;
+ else {
+ dmap_out->fragment_size = size;
+ }
+ dmap_out->max_fragments = 8888;
- if (fact == 0)
- {
- fact = dmap->subdivision;
- if (fact == 0)
- fact = 1;
- return IOCTL_OUT (arg, fact);
- }
+ size &= 0xffff;
+
+ if (audio_devs[dev]->flags & DMA_DUPLEX) {
+ dmap_in->fragment_size = size;
+ dmap_in->max_fragments = 8888;
+ }
+ return 0;
- if (dmap->subdivision != 0 ||
- dmap->fragment_size) /* Loo late to change */
- return RET_ERROR (EINVAL);
+ } else
+ return -(EINVAL); /* Too late to change */
+
+ }
+ break;
+
+ case SNDCTL_DSP_SUBDIVIDE:
+ {
+ int fact = (*(int *) arg);
+ int ret;
- if (fact > MAX_REALTIME_FACTOR)
- return RET_ERROR (EINVAL);
+ ret = dma_subdivide(dev, dmap_out, arg, fact);
+ if (ret < 0)
+ return ret;
- if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16)
- return RET_ERROR (EINVAL);
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ ret = dma_subdivide(dev, dmap_in, arg, fact);
- dmap->subdivision = fact;
- return IOCTL_OUT (arg, fact);
- }
- break;
+ return ret;
+ }
+ break;
case SNDCTL_DSP_SETFRAGMENT:
- {
- int fact = IOCTL_IN (arg);
- int bytes, count;
+ {
+ int fact = (*(int *) arg);
+ int ret;
- if (fact == 0)
- return RET_ERROR (EIO);
+ ret = dma_set_fragment(dev, dmap_out, arg, fact);
+ if (ret < 0)
+ return ret;
- if (dmap->subdivision != 0 ||
- dmap->fragment_size) /* Loo late to change */
- return RET_ERROR (EINVAL);
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ ret = dma_set_fragment(dev, dmap_in, arg, fact);
- bytes = fact & 0xffff;
- count = (fact >> 16) & 0xffff;
+ return ret;
+ }
+ break;
- if (count == 0)
- count = MAX_SUB_BUFFERS;
+ case SNDCTL_DSP_GETISPACE:
+ case SNDCTL_DSP_GETOSPACE:
+ if (!local)
+ return -(EINVAL);
+ else {
+ struct dma_buffparms *dmap = dmap_out;
- if (bytes < 7 || bytes > 17) /* <64 || > 128k */
- return RET_ERROR (EINVAL);
+ audio_buf_info *info = (audio_buf_info *) arg;
- if (count < 2)
- return RET_ERROR (EINVAL);
+ if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX)
+ dmap = dmap_in;
- dmap->fragment_size = (1 << bytes);
- dmap->max_fragments = count;
+#ifdef ALLOW_BUFFER_MAPPING
+ if (dmap->mapping_flags & DMA_MAP_MAPPED)
+ return -(EINVAL);
+#endif
- if (dmap->fragment_size > audio_devs[dev]->buffsize)
- dmap->fragment_size = audio_devs[dev]->buffsize;
+ if (!(dmap->flags & DMA_ALLOC_DONE))
+ reorganize_buffers(dev, dmap);
- if (dmap->fragment_size == audio_devs[dev]->buffsize &&
- audio_devs[dev]->flags & DMA_AUTOMODE)
- dmap->fragment_size /= 2; /* Needs at least 2 buffers */
+ info->fragstotal = dmap->nbufs;
- dmap->subdivision = 1; /* Disable SNDCTL_DSP_SUBDIVIDE */
- return IOCTL_OUT (arg, bytes | (count << 16));
- }
- break;
+ if (cmd == SNDCTL_DSP_GETISPACE)
+ info->fragments = dmap->qlen;
+ else {
+ if (!space_in_queue(dev))
+ info->fragments = 0;
+ else {
+ info->fragments = dmap->nbufs - dmap->qlen;
+ if (audio_devs[dev]->local_qlen) {
+ int tmp = audio_devs[dev]->local_qlen(dev);
- case SNDCTL_DSP_GETISPACE:
- case SNDCTL_DSP_GETOSPACE:
- if (!local)
- return RET_ERROR (EINVAL);
- else
+ if (tmp & info->fragments)
+ tmp--; /* This buffer has been counted twice */
+ info->fragments -= tmp;
+ }
+ }
+ }
+
+ if (info->fragments < 0)
+ info->fragments = 0;
+ else if (info->fragments > dmap->nbufs)
+ info->fragments = dmap->nbufs;
+
+ info->fragsize = dmap->fragment_size;
+ info->bytes = info->fragments * dmap->fragment_size;
+
+ if (cmd == SNDCTL_DSP_GETISPACE && dmap->qlen)
+ info->bytes -= dmap->counts[dmap->qhead];
+ }
+ return 0;
+
+ case SNDCTL_DSP_SETTRIGGER:
{
- audio_buf_info *info = (audio_buf_info *) arg;
+ u_long flags;
- if (!(dmap->flags & DMA_ALLOC_DONE))
- reorganize_buffers (dev);
+ int bits = (*(int *) arg) & audio_devs[dev]->open_mode;
+ int changed;
- info->fragstotal = dmap->nbufs;
+ if (audio_devs[dev]->trigger == NULL)
+ return -(EINVAL);
- if (cmd == SNDCTL_DSP_GETISPACE)
- info->fragments = dmap->qlen;
- else
- {
- if (!space_in_queue (dev))
- info->fragments = 0;
- else
- {
- info->fragments = dmap->nbufs - dmap->qlen;
- if (audio_devs[dev]->local_qlen)
- {
- int tmp = audio_devs[dev]->local_qlen (dev);
-
- if (tmp & info->fragments)
- tmp--; /*
- * This buffer has been counted twice
- */
- info->fragments -= tmp;
- }
+ if (!(audio_devs[dev]->flags & DMA_DUPLEX))
+ if ((bits & PCM_ENABLE_INPUT) && (bits & PCM_ENABLE_OUTPUT)) {
+ printf("Sound: Device doesn't have full duplex capability\n");
+ return -(EINVAL);
}
+ flags = splhigh();
+ changed = audio_devs[dev]->enable_bits ^ bits;
+
+ if ((changed & bits) & PCM_ENABLE_INPUT && audio_devs[dev]->go) {
+ if (!(dmap_in->flags & DMA_ALLOC_DONE))
+ reorganize_buffers(dev, dmap_in);
+ activate_recording(dev, dmap_in);
+ }
+#ifdef ALLOW_BUFFER_MAPPING
+ if ((changed & bits) & PCM_ENABLE_OUTPUT &&
+ dmap_out->mapping_flags & DMA_MAP_MAPPED &&
+ audio_devs[dev]->go) {
+ if (!(dmap_out->flags & DMA_ALLOC_DONE))
+ reorganize_buffers(dev, dmap_out);
+
+ audio_devs[dev]->prepare_for_output (dev,
+ dmap_out->fragment_size, dmap_out->nbufs);
+
+ dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size;
+ DMAbuf_start_output(dev, 0, dmap_out->fragment_size);
+ dmap_out->dma_mode = DMODE_OUTPUT;
}
+#endif
+
+ audio_devs[dev]->enable_bits = bits;
+ if (changed && audio_devs[dev]->trigger)
+ audio_devs[dev]->trigger(dev, bits * audio_devs[dev]->go);
+ splx(flags);
+ }
+ case SNDCTL_DSP_GETTRIGGER:
+ return *(int *) arg = audio_devs[dev]->enable_bits;
+ break;
+
+ case SNDCTL_DSP_SETSYNCRO:
- if (info->fragments < 0)
- info->fragments = 0;
- else if (info->fragments > dmap->nbufs)
- info->fragments = dmap->nbufs;
+ if (!audio_devs[dev]->trigger)
+ return -(EINVAL);
- info->fragsize = dmap->fragment_size;
- info->bytes = info->fragments * dmap->fragment_size;
+ audio_devs[dev]->trigger(dev, 0);
+ audio_devs[dev]->go = 0;
+ return 0;
+ break;
- if (cmd == SNDCTL_DSP_GETISPACE && dmap->qlen)
- info->bytes -= dmap->counts[dmap->qhead];
+ case SNDCTL_DSP_GETIPTR:
+ {
+ count_info info;
+ u_long flags;
+
+ flags = splhigh();
+ info.bytes = audio_devs[dev]->dmap_in->byte_counter;
+ info.ptr = get_buffer_pointer(dev, audio_devs[dev]->dmachan2, audio_devs[dev]->dmap_in);
+ info.blocks = audio_devs[dev]->dmap_in->qlen;
+ info.bytes += info.ptr;
+
+ bcopy((char *) &info, &(((char *) arg)[0]), sizeof(info));
+
+#ifdef ALLOW_BUFFER_MAPPING
+ if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)
+ audio_devs[dev]->dmap_in->qlen = 0; /* Ack interrupts */
+#endif
+ splx(flags);
+ return 0;
}
- return 0;
+ break;
+
+ case SNDCTL_DSP_GETOPTR:
+ {
+ count_info info;
+ u_long flags;
+
+ flags = splhigh();
+ info.bytes = audio_devs[dev]->dmap_out->byte_counter;
+ info.ptr = get_buffer_pointer(dev, audio_devs[dev]->dmachan1, audio_devs[dev]->dmap_out);
+ info.blocks = audio_devs[dev]->dmap_out->qlen;
+ info.bytes += info.ptr;
+ bcopy((char *) &info, &(((char *) arg)[0]), sizeof(info));
+
+#ifdef ALLOW_BUFFER_MAPPING
+ if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED)
+ audio_devs[dev]->dmap_out->qlen = 0; /* Ack interrupts */
+#endif
+ splx(flags);
+ return 0;
+ }
+ break;
default:
- return audio_devs[dev]->ioctl (dev, cmd, arg, local);
+ return audio_devs[dev]->ioctl(dev, cmd, arg, local);
}
+}
+/*
+ * DMAbuf_start_devices() is called by the /dev/music driver to start one or
+ * more audio devices at desired moment.
+ */
+
+void
+DMAbuf_start_devices(u_int devmask)
+{
+ int dev;
+
+ for (dev = 0; dev < num_audiodevs; dev++)
+ if (devmask & (1 << dev))
+ if (audio_devs[dev]->open_mode != 0)
+ if (!audio_devs[dev]->go) {
+ /* OK to start the device */
+ audio_devs[dev]->go = 1;
+
+ if (audio_devs[dev]->trigger)
+ audio_devs[dev]->trigger(dev,
+ audio_devs[dev]->enable_bits * audio_devs[dev]->go);
+ }
}
static int
-space_in_queue (int dev)
+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;
+ int len, max, tmp;
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+ 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;
+ 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 (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;
+ if (len >= max)
+ return 0;
+ return 1;
}
int
-DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock)
+DMAbuf_getwrbuffer(int dev, char **buf, int *size, int dontblock)
{
- unsigned long flags;
- int abort, err = EIO;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
-
- if (dmap->dma_mode == DMODE_INPUT) /* Direction change */
- {
- dma_reset (dev);
- dmap->dma_mode = DMODE_NONE;
- }
- else if (dmap->flags & DMA_RESTART) /* Restart buffering */
- {
- dma_sync (dev);
- dma_reset (dev);
+ u_long flags;
+ int abort, err = EIO;
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+
+#ifdef ALLOW_BUFFER_MAPPING
+ if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED) {
+ printf("Sound: Can't write to mmapped device (3)\n");
+ return -(EINVAL);
}
+#endif
- dmap->flags &= ~DMA_RESTART;
+ if (dmap->dma_mode == DMODE_INPUT) { /* Direction change */
+ dma_reset(dev);
+ dmap->dma_mode = DMODE_NONE;
+ } else if (dmap->flags & DMA_RESTART) { /* Restart buffering */
+ dma_sync(dev);
+ dma_reset_output(dev);
+ }
+ dmap->flags &= ~DMA_RESTART;
- if (!(dmap->flags & DMA_ALLOC_DONE))
- reorganize_buffers (dev);
+ if (!(dmap->flags & DMA_ALLOC_DONE))
+ reorganize_buffers(dev, dmap);
- if (!dmap->dma_mode)
- {
- int err;
+ if (!dmap->dma_mode) {
+ int err;
- dmap->dma_mode = DMODE_OUTPUT;
- if ((err = audio_devs[dev]->prepare_for_output (dev,
- dmap->fragment_size, dmap->nbufs)) < 0)
- return err;
+ dmap->dma_mode = DMODE_OUTPUT;
+ if ((err = audio_devs[dev]->prepare_for_output(dev,
+ dmap->fragment_size, dmap->nbufs)) < 0)
+ return err;
}
+ flags = splhigh();
- DISABLE_INTR (flags);
-
- abort = 0;
- while (!space_in_queue (dev) &&
- !abort)
- {
+ abort = 0;
+ while (!space_in_queue(dev) && !abort) {
+ int timeout;
- if (dontblock)
- {
- RESTORE_INTR (flags);
- return RET_ERROR (EAGAIN);
+ if (dontblock) {
+ splx(flags);
+ return -(EAGAIN);
+ }
+ if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT) &&
+ audio_devs[dev]->go) {
+ splx(flags);
+ return -(EAGAIN);
}
+ /*
+ * Wait for free space
+ */
+ if (!audio_devs[dev]->go)
+ timeout = 0;
+ else
+ timeout = 2 * hz;
- /*
- * 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");
- dma_reset (dev);
- err = EIO;
- abort = 1;
- SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]);
+ int chn;
+
+ out_sleep_flag[dev].mode = WK_SLEEP;
+ out_sleeper[dev] = &chn;
+ DO_SLEEP2(chn, out_sleep_flag[dev], timeout);
+
+ if ((out_sleep_flag[dev].mode & WK_TIMEOUT)) {
+ printf("Sound: DMA (output) timed out - IRQ/DRQ config error?\n");
+ err = EIO;
+ abort = 1;
+ out_sleep_flag[dev].aborting = 1;
+ audio_devs[dev]->reset(dev);
+ } else if ((out_sleep_flag[dev].aborting) ||
+ CURSIG(curproc)) {
+ err = EINTR;
+ abort = 1;
}
- else if (PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]))
- {
- err = EINTR;
- abort = 1;
}
}
- RESTORE_INTR (flags);
+ splx(flags);
- if (!space_in_queue (dev))
- {
- return RET_ERROR (err); /* Caught a signal ? */
+ if (!space_in_queue(dev)) {
+ return -(err); /* Caught a signal ? */
}
-
- *buf = dmap->buf[dmap->qtail];
- *size = dmap->fragment_size;
- dmap->counts[dmap->qtail] = 0;
-
- return dmap->qtail;
+ *buf = dmap->raw_buf + dmap->qtail * dmap->fragment_size;
+ *size = dmap->fragment_size;
+ dmap->counts[dmap->qtail] = 0;
+ return dmap->qtail;
}
int
-DMAbuf_start_output (int dev, int buff_no, int l)
+DMAbuf_start_output(int dev, int buff_no, int l)
{
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
- if (buff_no != dmap->qtail)
- printk ("Sound warning: DMA buffers out of sync %d != %d\n", buff_no, dmap->qtail);
+ /*
+ * Bypass buffering if using mmaped access
+ */
- 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);
+#ifdef ALLOW_BUFFER_MAPPING
+ if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED) {
+ l = dmap->fragment_size;
+ dmap->counts[dmap->qtail] = l;
+ dmap->flags &= ~DMA_RESTART;
+ dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+ } else
+#else
+ if (dmap != NULL)
+#endif
+ {
- dmap->counts[dmap->qtail] = l;
+ if (buff_no != dmap->qtail)
+ printf("Sound warning: DMA buffers out of sync %d != %d\n", buff_no, dmap->qtail);
- 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;
+ dmap->qlen++;
+ if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
+ printf("\nSound: Audio queue2 corrupted for dev%d (%d/%d)\n",
+ dev, dmap->qlen, dmap->nbufs);
- dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+ dmap->counts[dmap->qtail] = l;
- if (!(dmap->flags & DMA_ACTIVE))
- {
- 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;
- }
+ 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;
- return 0;
+ dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+ }
+ if (!(dmap->flags & DMA_ACTIVE)) {
+ dmap->flags |= DMA_ACTIVE;
+ audio_devs[dev]->output_block(dev, dmap->raw_buf_phys +
+ dmap->qhead * dmap->fragment_size,
+ dmap->counts[dmap->qhead], 0,
+ !(audio_devs[dev]->flags & DMA_AUTOMODE) ||
+ !(dmap->flags & DMA_STARTED));
+ dmap->flags |= DMA_STARTED;
+ if (audio_devs[dev]->trigger)
+ audio_devs[dev]->trigger(dev,
+ audio_devs[dev]->enable_bits * audio_devs[dev]->go);
+ }
+ return 0;
}
int
-DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
+DMAbuf_start_dma(int dev, u_long physaddr, int count, int dma_mode)
{
- int chan = audio_devs[dev]->dmachan;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
-#ifdef linux
- unsigned long flags;
-#endif
- /*
- * This function is not as portable as it should be.
- */
+ int chan;
+ struct dma_buffparms *dmap;
- /*
- * The count must be one less than the actual size. This is handled by
- * set_dma_addr()
- */
+ if (dma_mode == 1) {
+ chan = audio_devs[dev]->dmachan1;
+ dmap = audio_devs[dev]->dmap_out;
- 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, dmap->raw_buf_phys[0]);
- set_dma_count (chan, dmap->bytes_in_use);
- enable_dma (chan);
- RESTORE_INTR (flags);
-#else
+ } else {
+ chan = audio_devs[dev]->dmachan2;
+ dmap = audio_devs[dev]->dmap_in;
+ }
-#if defined(__FreeBSD__)
+ /*
+ * The count must be one less than the actual size. This is handled
+ * by set_dma_addr()
+ */
- isa_dmastart (B_RAW | ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE),
- (caddr_t)dmap->raw_buf_phys[0],
- dmap->bytes_in_use,
- chan);
-#else /* else __FreeBSD__ */
-#if defined(GENERIC_SYSV)
-#ifndef DMAMODE_AUTO
- printk ("sound: Invalid DMA mode for device %d\n", dev);
-#endif
-#if defined(SVR42)
-
- /*
- ** send full count to snd_dma_prog, it will take care of subtracting
- ** one if it is required.
- */
- snd_dma_prog (chan, dmap->raw_buf_phys[0], dmap->bytes_in_use,
- dma_mode, TRUE);
-
-#else /* !SVR42 */
- dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode)
-#ifdef DMAMODE_AUTO
- | DMAMODE_AUTO
-#endif
- ,
- dmap->raw_buf_phys[0], dmap->bytes_in_use - 1);
- dma_enable (chan);
-#endif /* ! SVR42 */
-#else
-#error This routine is not valid for this OS.
-#endif
-#endif
+#ifndef PSEUDO_DMA_AUTOINIT
+ if (audio_devs[dev]->flags & DMA_AUTOMODE) {
+ /* Auto restart mode. Transfer the whole buffer */
+ isa_dmastart(B_RAW | ((dma_mode == 0) ? B_READ : B_WRITE),
+ (caddr_t) dmap->raw_buf_phys, dmap->bytes_in_use, chan);
+ } else
#endif
- }
- else
{
-#ifdef linux
- DISABLE_INTR (flags);
- disable_dma (chan);
- clear_dma_ff (chan);
- set_dma_mode (chan, dma_mode);
- set_dma_addr (chan, physaddr);
- set_dma_count (chan, count);
- enable_dma (chan);
- RESTORE_INTR (flags);
-#else
-#if defined(__FreeBSD__)
- isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE,
- (caddr_t)physaddr,
- count,
- chan);
-#else /* FreeBSD */
-
-#if defined(GENERIC_SYSV)
-#if defined(SVR42)
-
- snd_dma_prog (chan, physaddr, count, dma_mode, FALSE);
-
-#else /* ! SVR42 */
- dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode),
- physaddr, count);
- dma_enable (chan);
-#endif /* SVR42 */
-#else
-#error This routine is not valid for this OS.
-#endif /* GENERIC_SYSV */
-#endif
-
-#endif
+ isa_dmastart((dma_mode == 0) ? B_READ : B_WRITE,
+ (caddr_t) physaddr, count, chan);
}
-
- return count;
+ return count;
}
-long
-DMAbuf_init (long mem_start)
+void
+DMAbuf_init()
{
- int dev;
+ int dev;
-#if defined(SVR42)
- snd_dma_init ();
-#endif /* SVR42 */
-
- /*
+ /*
* NOTE! This routine could be called several times.
- */
+ * XXX is it ok to make it run only the first time ? -- lr970710
+ */
+
+ for (dev = 0; dev < num_audiodevs; dev++)
+ if (audio_devs[dev]->dmap_out == NULL) {
+ audio_devs[dev]->dmap_out =
+ audio_devs[dev]->dmap_in = &dmaps[ndmaps++];
- for (dev = 0; dev < num_audiodevs; dev++)
- audio_devs[dev]->dmap = &dmaps[dev];
- return mem_start;
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ audio_devs[dev]->dmap_in = &dmaps[ndmaps++];
+ }
}
void
-DMAbuf_outputintr (int dev, int event_type)
+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;
-
-#if defined(SVR42)
- snd_dma_intr (audio_devs[dev]->dmachan);
-#endif /* SVR42 */
-
- 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;
+ /*
+ * 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.
+ */
+
+ u_long flags;
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+ dmap->byte_counter += dmap->counts[dmap->qhead];
+#ifdef OS_DMA_INTR
+ sound_dma_intr(dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);
+#endif
+#ifdef ALLOW_BUFFER_MAPPING
+ if (dmap->mapping_flags & DMA_MAP_MAPPED) {
+ /* mmapped access */
+
+ int p = dmap->fragment_size * dmap->qhead;
+
+ dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
+ dmap->qlen++; /* Yes increment it (don't decrement) */
+ dmap->flags &= ~DMA_ACTIVE;
+ dmap->counts[dmap->qhead] = dmap->fragment_size;
+
+ if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) {
+ audio_devs[dev]->output_block(dev, dmap->raw_buf_phys +
+ dmap->qhead * dmap->fragment_size,
+ dmap->counts[dmap->qhead], 1,
+ !(audio_devs[dev]->flags & DMA_AUTOMODE));
+ if (audio_devs[dev]->trigger)
+ audio_devs[dev]->trigger(dev,
+ audio_devs[dev]->enable_bits * audio_devs[dev]->go);
+ }
+#ifdef PSEUDO_DMA_AUTOINIT
+ else {
+ DMAbuf_start_dma(dev, dmap->raw_buf_phys +
+ dmap->qhead * dmap->fragment_size,
+ dmap->counts[dmap->qhead], 1);
}
-
- dmap->qlen--;
- dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
- dmap->flags &= ~DMA_ACTIVE;
-
-#ifdef __FreeBSD__
- isa_dmadone(0, 0, 0, audio_devs[dev]->dmachan);
#endif
+ 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
+#endif
+ if (event_type != 2) {
+ if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs) {
+ printf("\nSound: Audio queue3 corrupted for dev%d (%d/%d)\n",
+ dev, dmap->qlen, dmap->nbufs);
+ return;
}
- 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;
+ isa_dmadone(0, 0, 0, audio_devs[dev]->dmachan1);
+
+ dmap->qlen--;
+ dmap->qhead = (dmap->qhead + 1) % dmap->nbufs;
+ dmap->flags &= ~DMA_ACTIVE;
+ if (dmap->qlen) {
+ /* if (!(audio_devs[dev]->flags & NEEDS_RESTART)) */
+ {
+ audio_devs[dev]->output_block(dev, dmap->raw_buf_phys +
+ dmap->qhead * dmap->fragment_size,
+ dmap->counts[dmap->qhead], 1,
+ !(audio_devs[dev]->flags & DMA_AUTOMODE));
+ if (audio_devs[dev]->trigger)
+ audio_devs[dev]->trigger(dev,
+ audio_devs[dev]->enable_bits * audio_devs[dev]->go);
+ }
+
+#ifdef PSEUDO_DMA_AUTOINIT
+ /* else */
+ {
+ DMAbuf_start_dma(dev, dmap->raw_buf_phys +
+ dmap->qhead * dmap->fragment_size,
+ dmap->counts[dmap->qhead], 1);
+ }
+#endif
+ dmap->flags |= DMA_ACTIVE;
+ } else if (event_type == 1) {
+ dmap->underrun_count++;
+ if ((audio_devs[dev]->flags & DMA_DUPLEX) &&
+ audio_devs[dev]->halt_output)
+ audio_devs[dev]->halt_output(dev);
+ else
+ 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 */
+ } /* event_type != 2 */
+ flags = splhigh();
- DISABLE_INTR (flags);
- if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev]))
- {
- WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]);
+ if ((out_sleep_flag[dev].mode & WK_SLEEP)) {
+ out_sleep_flag[dev].mode = WK_WAKEUP;
+ wakeup(out_sleeper[dev]);
}
- RESTORE_INTR (flags);
-#if defined(__FreeBSD__)
- if(selinfo[dev].si_pid)
- selwakeup(&selinfo[dev]);
-#endif
+
+ if(selinfo[dev].si_pid) {
+ selwakeup(&selinfo[dev]);
+ }
+
+ splx(flags);
}
void
-DMAbuf_inputintr (int dev)
+DMAbuf_inputintr(int dev)
{
- unsigned long flags;
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+ u_long flags;
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_in;
-#if defined(SVR42)
- snd_dma_intr (audio_devs[dev]->dmachan);
-#endif /* SVR42 */
-
-#ifdef __FreeBSD__
- isa_dmadone(0, 0, 0, audio_devs[dev]->dmachan);
+ dmap->byte_counter += dmap->fragment_size;
+
+#ifdef OS_DMA_INTR
+ sound_dma_intr(dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2);
+#endif
+ isa_dmadone(0, 0, 0, audio_devs[dev]->dmachan2);
+
+#ifdef ALLOW_BUFFER_MAPPING
+ if (dmap->mapping_flags & DMA_MAP_MAPPED) {
+ dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+ dmap->qlen++;
+
+ if (!(audio_devs[dev]->flags & NEEDS_RESTART)) {
+ audio_devs[dev]->start_input(dev, dmap->raw_buf_phys +
+ dmap->qtail * dmap->fragment_size,
+ dmap->fragment_size, 1,
+ !(audio_devs[dev]->flags & DMA_AUTOMODE));
+ if (audio_devs[dev]->trigger)
+ audio_devs[dev]->trigger(dev,
+ audio_devs[dev]->enable_bits * audio_devs[dev]->go);
+ }
+#ifdef PSEUDO_DMA_AUTOINIT
+ else {
+ DMAbuf_start_dma(dev, dmap->raw_buf_phys +
+ dmap->qtail * dmap->fragment_size,
+ dmap->counts[dmap->qtail], 0);
+ }
#endif
- if (dmap->qlen == (dmap->nbufs - 1))
- {
-#if !defined(__FreeBSD__) /* ignore console message. */
- printk ("Sound: Recording overrun\n");
+ dmap->flags |= DMA_ACTIVE;
+ } else
#endif
- 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
- {
- 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;
+ if (dmap->qlen == (dmap->nbufs - 1)) {
+ /* printf ("Sound: Recording overrun\n"); */
+ dmap->underrun_count++;
+ if ((audio_devs[dev]->flags & DMA_DUPLEX) &&
+ audio_devs[dev]->halt_input)
+ audio_devs[dev]->halt_input(dev);
+ else
+ 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 {
+ dmap->qlen++;
+ if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
+ printf("\nSound: Audio queue4 corrupted for dev%d (%d/%d)\n",
+ dev, dmap->qlen, dmap->nbufs);
+ dmap->qtail = (dmap->qtail + 1) % dmap->nbufs;
+
+ /* if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) */
+ {
+ audio_devs[dev]->start_input(dev, dmap->raw_buf_phys +
+ dmap->qtail * dmap->fragment_size,
+ dmap->fragment_size, 1,
+ !(audio_devs[dev]->flags & DMA_AUTOMODE));
+ if (audio_devs[dev]->trigger)
+ audio_devs[dev]->trigger(dev,
+ audio_devs[dev]->enable_bits * audio_devs[dev]->go);
+ }
+#ifdef PSEUDO_DMA_AUTOINIT
+ /* else */
+ {
+ DMAbuf_start_dma(dev, dmap->raw_buf_phys +
+ dmap->qtail * dmap->fragment_size,
+ dmap->counts[dmap->qtail], 0);
+ }
+#endif
+
+ dmap->flags |= DMA_ACTIVE;
}
- DISABLE_INTR (flags);
- if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev]))
- {
- WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]);
+ flags = splhigh();
+ if ((in_sleep_flag[dev].mode & WK_SLEEP)) {
+ in_sleep_flag[dev].mode = WK_WAKEUP;
+ wakeup(in_sleeper[dev]);
}
- RESTORE_INTR (flags);
-#if defined(__FreeBSD__)
- if(selinfo[dev].si_pid)
- selwakeup(&selinfo[dev]);
-#endif
+ if (selinfo[dev].si_pid)
+ selwakeup(&selinfo[dev]);
+ splx(flags);
}
int
-DMAbuf_open_dma (int dev)
+DMAbuf_open_dma(int dev)
{
- unsigned long flags;
- int chan = audio_devs[dev]->dmachan;
-
- if (ALLOC_DMA_CHN (chan, audio_devs[dev]->name))
- {
-#if 0
- /* Enough already! This error is reported twice elsewhere */
- printk ("Unable to grab DMA%d for the audio driver\n", chan);
-#endif
- return RET_ERROR (EBUSY);
+ int err;
+ u_long flags;
+ flags = splhigh();
+
+ if ((err = open_dmap(dev, OPEN_READWRITE, audio_devs[dev]->dmap_out,
+ audio_devs[dev]->dmachan1)) < 0) {
+ splx(flags);
+ return -(EBUSY);
+ }
+ dma_init_buffers(dev, audio_devs[dev]->dmap_out);
+ /* audio_devs[dev]->dmap_out->flags |= DMA_ALLOC_DONE; */
+ audio_devs[dev]->dmap_out->fragment_size = audio_devs[dev]->buffsize;
+ /* reorganize_buffers (dev, audio_devs[dev]->dmap_out); */
+
+ if (audio_devs[dev]->flags & DMA_DUPLEX) {
+ if ((err = open_dmap(dev, OPEN_READWRITE,
+ audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2)) < 0) {
+ printf("Unable to grab DMA%d for the audio driver\n",
+ audio_devs[dev]->dmachan2);
+ close_dmap(dev, audio_devs[dev]->dmap_out,
+ audio_devs[dev]->dmachan1);
+ splx(flags);
+ return -(EBUSY);
+ }
+ dma_init_buffers(dev, audio_devs[dev]->dmap_in);
+ /* audio_devs[dev]->dmap_in->flags |= DMA_ALLOC_DONE; */
+ audio_devs[dev]->dmap_in->fragment_size = audio_devs[dev]->buffsize;
+ /* reorganize_buffers (dev, audio_devs[dev]->dmap_in); */
+ } else {
+ audio_devs[dev]->dmap_in = audio_devs[dev]->dmap_out;
+ audio_devs[dev]->dmachan2 = audio_devs[dev]->dmachan1;
}
- DISABLE_INTR (flags);
-#ifdef linux
- disable_dma (chan);
- clear_dma_ff (chan);
-#endif
- RESTORE_INTR (flags);
-
- return 0;
+ splx(flags);
+ return 0;
}
void
-DMAbuf_close_dma (int dev)
+DMAbuf_close_dma(int dev)
{
- int chan = audio_devs[dev]->dmachan;
+ DMAbuf_reset_dma(dev);
+ close_dmap(dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1);
+
+ if (audio_devs[dev]->flags & DMA_DUPLEX)
+ close_dmap(dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2);
- DMAbuf_reset_dma (dev);
- RELEASE_DMA_CHN (chan);
}
void
-DMAbuf_reset_dma (int dev)
+DMAbuf_reset_dma(int dev)
{
}
#ifdef ALLOW_SELECT
+
int
-DMAbuf_poll (int dev, struct fileinfo *file, int events, select_table * wait)
+DMAbuf_poll(int dev, struct fileinfo * file, int events, select_table * wait)
{
- struct dma_buffparms *dmap = audio_devs[dev]->dmap;
- unsigned long flags;
- int revents = 0;
+ struct dma_buffparms *dmap;
+ u_long flags;
+ int revents = 0;
+
+ dmap = audio_devs[dev]->dmap_in;
+
+ if (events & (POLLIN | POLLRDNORM)) {
+ if (dmap->dma_mode != DMODE_INPUT) {
+ if ((audio_devs[dev]->flags & DMA_DUPLEX) && !dmap->qlen &&
+ audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT &&
+ audio_devs[dev]->go) {
+ u_long flags;
+
+ flags = splhigh();
+
+ activate_recording(dev, dmap);
+ splx(flags);
+
+ }
+ return 0;
+ }
+ if (!dmap->qlen) {
+ flags = splhigh();
- if (events & (POLLIN | POLLRDNORM))
- if (dmap->dma_mode == DMODE_INPUT) {
+ selrecord(wait, &selinfo[dev]);
- DISABLE_INTR (flags);
+ splx(flags);
- if (!dmap->qlen)
- selrecord(wait, &selinfo[dev]);
- else
- revents |= events & (POLLIN | POLLRDNORM);
+ return 0;
+ } else
+ revents |= events & (POLLIN | POLLRDNORM);
- RESTORE_INTR (flags);
}
- if (events & (POLLOUT | POLLWRNORM))
- if (dmap->dma_mode != DMODE_INPUT) {
-
- if (dmap->dma_mode == DMODE_NONE)
- revents |= events & (POLLOUT | POLLWRNORM);
- else {
- DISABLE_INTR (flags);
+ if (events & (POLLOUT | POLLWRNORM)) {
+
+ dmap = audio_devs[dev]->dmap_out;
+ if (dmap->dma_mode == DMODE_INPUT)
+ return 0;
+
+ if (dmap->dma_mode == DMODE_NONE)
+ return ( events & (POLLOUT | POLLWRNORM));
+
+ if (dmap->mapping_flags & DMA_MAP_MAPPED) {
+
+ if(dmap->qlen)
+ return 1;
+ flags = splhigh();
+ selrecord(wait, &selinfo[dev]);
+
+ splx(flags);
+
+ return 0;
+
+ }
+ if (!space_in_queue(dev)) {
+ flags = splhigh();
+ selrecord(wait, &selinfo[dev]);
+ splx(flags);
- if (!space_in_queue (dev))
- selrecord(wait, &selinfo[dev]);
- else
+ } else
revents |= events & (POLLOUT | POLLWRNORM);
- RESTORE_INTR (flags);
- }
+
+ }
+
+ return (revents);
+}
+
+
+#ifdef amancio
+int
+DMAbuf_select(int dev, struct fileinfo * file, int sel_type, select_table * wait)
+{
+ struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
+ struct dma_buffparms *dmapin = audio_devs[dev]->dmap_in;
+ u_long flags;
+
+ switch (sel_type) {
+ case FREAD:
+ if (dmapin->dma_mode != DMODE_INPUT)
+ return 0;
+
+ if (!dmap->qlen) {
+ flags = splhigh();
+ selrecord(wait, &selinfo[dev]);
+ splx(flags);
+
+ return 0;
+ }
+ return 1;
+ break;
+
+ case FWRITE:
+ if (dmap->dma_mode == DMODE_INPUT)
+ return 0;
+
+ if (dmap->dma_mode == DMODE_NONE)
+ return 1;
+
+ if (!space_in_queue(dev)) {
+ flags = splhigh();
+
+ selrecord(wait, &selinfo[dev]);
+ splx(flags);
+
+ return 0;
+ }
+ return 1;
+ break;
+
}
- return (revents);
+ return 0;
}
-#endif /* ALLOW_SELECT */
+#endif /* ALLOW_SELECT */
+#endif
-#else /* EXCLUDE_AUDIO */
+#else /* CONFIG_AUDIO */
/*
* Stub versions if audio services not included
*/
int
-DMAbuf_open (int dev, int mode)
+DMAbuf_open(int dev, int mode)
{
- return RET_ERROR (ENXIO);
+ return -(ENXIO);
}
int
-DMAbuf_release (int dev, int mode)
+DMAbuf_release(int dev, int mode)
{
- return 0;
+ return 0;
}
int
-DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock)
+DMAbuf_getwrbuffer(int dev, char **buf, int *size, int dontblock)
{
- return RET_ERROR (EIO);
+ return -(EIO);
}
int
-DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock)
+DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock)
{
- return RET_ERROR (EIO);
+ return -(EIO);
}
int
-DMAbuf_rmchars (int dev, int buff_no, int c)
+DMAbuf_rmchars(int dev, int buff_no, int c)
{
- return RET_ERROR (EIO);
+ return -(EIO);
}
int
-DMAbuf_start_output (int dev, int buff_no, int l)
+DMAbuf_start_output(int dev, int buff_no, int l)
{
- return RET_ERROR (EIO);
+ return -(EIO);
}
int
-DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
+DMAbuf_ioctl(int dev, u_int cmd, ioctl_arg arg, int local)
{
- return RET_ERROR (EIO);
+ return -(EIO);
}
-long
-DMAbuf_init (long mem_start)
+void
+DMAbuf_init()
{
- return mem_start;
}
int
-DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
+DMAbuf_start_dma(int dev, u_long physaddr, int count, int dma_mode)
{
- return RET_ERROR (EIO);
+ return -(EIO);
}
int
-DMAbuf_open_dma (int dev)
+DMAbuf_open_dma(int dev)
{
- return RET_ERROR (ENXIO);
+ return -(ENXIO);
}
void
-DMAbuf_close_dma (int dev)
+DMAbuf_close_dma(int dev)
{
- return;
+ return;
}
void
-DMAbuf_reset_dma (int dev)
+DMAbuf_reset_dma(int dev)
{
- return;
+ return;
}
void
-DMAbuf_inputintr (int dev)
+DMAbuf_inputintr(int dev)
{
- return;
+ return;
}
void
-DMAbuf_outputintr (int dev, int underrun_flag)
+DMAbuf_outputintr(int dev, int underrun_flag)
{
- return;
+ return;
}
-
-#endif
-
-#endif
+#endif /* CONFIG_AUDIO */
diff --git a/sys/i386/isa/sound/gus_card.c b/sys/i386/isa/sound/gus_card.c
index 0e96df1..2f73ce6 100644
--- a/sys/i386/isa/sound/gus_card.c
+++ b/sys/i386/isa/sound/gus_card.c
@@ -1,10 +1,10 @@
/*
* sound/gus_card.c
- *
+ *
* Detection routine for the Gravis Ultrasound.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,147 +24,138 @@
* 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 <i386/isa/sound/sound_config.h>
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)
+#if defined(CONFIG_GUS)
#include <i386/isa/sound/gus_hw.h>
+#include <i386/isa/sound/iwdefs.h>
int gus_base, gus_irq, gus_dma;
extern int gus_wave_volume;
extern int gus_pcm_volume;
extern int have_gus_max;
+extern int gus_timer_enabled;
-long
-attach_gus_card (long mem_start, struct address_info *hw_config)
-{
- int io_addr;
-
- snd_set_irq_handler (hw_config->irq, gusintr, "Gravis Ultrasound");
-
- if (gus_wave_detect (hw_config->io_base)) /*
- * Try first the default
- */
- {
- mem_start = gus_wave_init (mem_start, hw_config->irq, hw_config->dma,
- hw_config->dma_read);
-#ifndef EXCLUDE_MIDI
- mem_start = gus_midi_init (mem_start);
+sound_os_info *gus_osp;
+
+#ifndef NOGUSPNP
+int IwaveOpen(char voices, char mode, struct address_info * hw);
#endif
-#ifndef EXCLUDE_SEQUENCER
- sound_timer_init (hw_config->io_base + 8);
+
+void
+attach_gus_card(struct address_info * hw_config)
+{
+ int io_addr;
+
+ gus_osp = hw_config->osp;
+
+ snd_set_irq_handler(hw_config->irq, gusintr, hw_config->osp);
+
+ if (gus_wave_detect(hw_config->io_base)) {
+ /* Try first the default */
+ gus_wave_init(hw_config);
+
+ /* 0x10c-> is MAX */
+
+ if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma)
+ if (0)
+ printf("gus_card.c: Can't allocate DMA channel2\n");
+#ifdef CONFIG_MIDI
+ gus_midi_init();
#endif
- return mem_start;
+ return ;
}
-
#ifndef EXCLUDE_GUS_IODETECT
- /*
- * Look at the possible base addresses (0x2X0, X=1, 2, 3, 4, 5, 6)
- */
-
- for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10)
- 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);
- mem_start = gus_wave_init (mem_start, hw_config->irq, hw_config->dma,
- hw_config->dma_read);
-#ifndef EXCLUDE_MIDI
- mem_start = gus_midi_init (mem_start);
-#endif
-#ifndef EXCLUDE_SEQUENCER
- sound_timer_init (io_addr + 8);
+ /*
+ * Look at the possible base addresses (0x2X0, X=1, 2, 3, 4, 5, 6)
+ */
+
+ for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10)
+ if ( (io_addr != hw_config->io_base) /* Already tested */
+ && (gus_wave_detect(io_addr)) ) {
+ hw_config->io_base = io_addr;
+
+ printf(" WARNING! GUS found at %x, config was %x ",
+ io_addr, hw_config->io_base);
+ gus_wave_init(hw_config);
+ /* 0x10c-> is MAX */
+ if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma)
+ if (0)
+ printf("gus_card.c: Can't allocate DMA channel2\n");
+#ifdef CONFIG_MIDI
+ gus_midi_init();
#endif
- return mem_start;
+ return ;
}
-
#endif
-
- return mem_start; /*
- * Not detected
- */
}
int
-probe_gus (struct address_info *hw_config)
+probe_gus(struct address_info * hw_config)
{
- int io_addr;
-
- if (gus_wave_detect (hw_config->io_base))
- return 1;
+ int io_addr;
-#ifndef EXCLUDE_GUS_IODETECT
-
- /*
- * Look at the possible base addresses (0x2X0, X=1, 2, 3, 4, 5, 6)
- */
-
- for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10)
- if (io_addr != hw_config->io_base) /*
- * Already tested
- */
- if (gus_wave_detect (io_addr))
+ gus_osp = hw_config->osp;
+#ifndef NOGUSPNP
+ IwaveOpen((char) 32, (char) GUS_MODE, hw_config);
+#endif
+ if (gus_wave_detect(hw_config->io_base))
return 1;
+ printf("oops I didnt find gus \n");
+#undef EXCLUDE_GUS_IODETECT
+#ifndef EXCLUDE_GUS_IODETECT
+ /*
+ * Look at the possible base addresses (0x2X0, X=1, 2, 3, 4, 5, 6)
+ */
+ for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10)
+ if ( (io_addr != hw_config->io_base) /* Already tested */
+ && (gus_wave_detect(io_addr)) ) {
+ hw_config->io_base = io_addr;
+ return 1;
+ }
#endif
- return 0;
+ return 0;
}
void
-gusintr (INT_HANDLER_PARMS (irq, dummy))
+gusintr(int irq)
{
- unsigned char src;
-
-#ifdef linux
- sti ();
-#endif
+ u_char src;
-#ifndef EXCLUDE_GUSMAX
- if (have_gus_max)
-# if defined(__FreeBSD__)
- ad1848_interrupt (INT_HANDLER_CALL (gus_irq));
-# else
- ad1848_interrupt (INT_HANDLER_CALL (irq));
-# endif
+#ifdef CONFIG_GUSMAX
+ if (have_gus_max)
+ ad1848_interrupt(irq);
#endif
- while (1)
- {
- if (!(src = INB (u_IrqStatus)))
- return;
+ for (;;) {
+ if (!(src = inb(u_IrqStatus)))
+ return;
- if (src & DMA_TC_IRQ)
- {
- guswave_dma_irq ();
- }
-
- if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ))
- {
-#ifndef EXCLUDE_MIDI
- gus_midi_interrupt (0);
+ if (src & DMA_TC_IRQ)
+ guswave_dma_irq();
+#ifdef CONFIG_MIDI
+ if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ))
+ gus_midi_interrupt(0);
#endif
- }
-
- if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ))
- {
-#ifndef EXCLUDE_SEQUENCER
- sound_timer_interrupt ();
+ if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ)) {
+#ifdef CONFIG_SEQUENCER
+ if (gus_timer_enabled)
+ sound_timer_interrupt();
+ gus_write8(0x45, 0); /* Ack IRQ */
+ gus_timer_command(4, 0x80); /* Reset IRQ flags */
#else
- gus_write8 (0x45, 0); /* Stop timers */
+ gus_write8(0x45, 0); /* Stop timers */
#endif
}
-
- if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ))
- {
- gus_voice_irq ();
- }
+ if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ))
+ gus_voice_irq();
}
}
@@ -173,25 +164,25 @@ gusintr (INT_HANDLER_PARMS (irq, dummy))
/*
* Some extra code for the 16 bit sampling option
*/
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS16)
+#if defined(CONFIG_GUS16)
int
-probe_gus_db16 (struct address_info *hw_config)
+probe_gus_db16(struct address_info * hw_config)
{
- return ad1848_detect (hw_config->io_base);
+ return ad1848_detect(hw_config->io_base, NULL, hw_config->osp);
}
-long
-attach_gus_db16 (long mem_start, struct address_info *hw_config)
+void
+attach_gus_db16(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;
+ 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, 0,
+ hw_config->osp);
}
#endif
diff --git a/sys/i386/isa/sound/gus_midi.c b/sys/i386/isa/sound/gus_midi.c
index 876c665..0dfc7c5 100644
--- a/sys/i386/isa/sound/gus_midi.c
+++ b/sys/i386/isa/sound/gus_midi.c
@@ -1,10 +1,10 @@
/*
* sound/gus2_midi.c
- *
+ *
* The low level driver for the GUS Midi Interface.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,17 +24,14 @@
* 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 <i386/isa/sound/sound_config.h>
-#ifdef CONFIGURE_SOUNDCARD
-
+#if defined(CONFIG_GUS) && defined(CONFIG_MIDI)
#include <i386/isa/sound/gus_hw.h>
-#if !defined(EXCLUDE_GUS) && !defined(EXCLUDE_MIDI)
-
static int midi_busy = 0, input_opened = 0;
static int my_dev;
static int output_used = 0;
@@ -46,181 +43,164 @@ static unsigned char tmp_queue[256];
static volatile int qlen;
static volatile unsigned char qhead, qtail;
extern int gus_base, gus_irq, gus_dma;
+extern sound_os_info *gus_osp;
-#define GUS_MIDI_STATUS() INB(u_MidiStatus)
+#define GUS_MIDI_STATUS() inb( u_MidiStatus)
static int
-gus_midi_open (int dev, int mode,
- void (*input) (int dev, unsigned char data),
- void (*output) (int dev)
+gus_midi_open(int dev, int mode,
+ void (*input) (int dev, unsigned char data),
+ void (*output) (int dev)
)
{
- if (midi_busy)
- {
- printk ("GUS: Midi busy\n");
- return RET_ERROR (EBUSY);
- }
-
- OUTB (MIDI_RESET, u_MidiControl);
- gus_delay ();
-
- gus_midi_control = 0;
- input_opened = 0;
-
- if (mode == OPEN_READ || mode == OPEN_READWRITE)
- {
- gus_midi_control |= MIDI_ENABLE_RCV;
- input_opened = 1;
- }
+ if (midi_busy) {
+ printf("GUS: Midi busy\n");
+ return -(EBUSY);
+ }
+ outb(u_MidiControl, MIDI_RESET);
+ gus_delay();
- if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
- {
- gus_midi_control |= MIDI_ENABLE_XMIT;
- }
+ gus_midi_control = 0;
+ input_opened = 0;
- OUTB (gus_midi_control, u_MidiControl); /*
- * Enable
- */
+ if (mode == OPEN_READ || mode == OPEN_READWRITE) {
+ gus_midi_control |= MIDI_ENABLE_RCV;
+ input_opened = 1;
+ }
+ if (mode == OPEN_WRITE || mode == OPEN_READWRITE) {
+ gus_midi_control |= MIDI_ENABLE_XMIT;
+ }
+ outb(u_MidiControl, gus_midi_control); /* Enable */
- midi_busy = 1;
- qlen = qhead = qtail = output_used = 0;
- midi_input_intr = input;
+ midi_busy = 1;
+ qlen = qhead = qtail = output_used = 0;
+ midi_input_intr = input;
- return 0;
+ return 0;
}
static int
-dump_to_midi (unsigned char midi_byte)
+dump_to_midi(unsigned char midi_byte)
{
- unsigned long flags;
- int ok = 0;
-
- output_used = 1;
-
- DISABLE_INTR (flags);
-
- if (GUS_MIDI_STATUS () & MIDI_XMIT_EMPTY)
- {
- ok = 1;
- OUTB (midi_byte, u_MidiData);
- }
- else
- {
- /*
- * Enable Midi xmit interrupts (again)
- */
- gus_midi_control |= MIDI_ENABLE_XMIT;
- OUTB (gus_midi_control, u_MidiControl);
- }
-
- RESTORE_INTR (flags);
- return ok;
+ unsigned long flags;
+ int ok = 0;
+
+ output_used = 1;
+
+ flags = splhigh();
+
+ if (GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY) {
+ ok = 1;
+ outb(u_MidiData, midi_byte);
+ } else {
+ /*
+ * Enable Midi xmit interrupts (again)
+ */
+ gus_midi_control |= MIDI_ENABLE_XMIT;
+ outb(u_MidiControl, gus_midi_control);
+ }
+
+ splx(flags);
+ return ok;
}
static void
-gus_midi_close (int dev)
+gus_midi_close(int dev)
{
- /*
- * Reset FIFO pointers, disable intrs
- */
+ /*
+ * Reset FIFO pointers, disable intrs
+ */
- OUTB (MIDI_RESET, u_MidiControl);
- midi_busy = 0;
+ outb(u_MidiControl, MIDI_RESET);
+ midi_busy = 0;
}
static int
-gus_midi_out (int dev, unsigned char midi_byte)
+gus_midi_out(int dev, unsigned char midi_byte)
{
- unsigned long flags;
+ unsigned long flags;
- /*
- * Drain the local queue first
- */
+ /*
+ * Drain the local queue first
+ */
- DISABLE_INTR (flags);
+ flags = splhigh();
- while (qlen && dump_to_midi (tmp_queue[qhead]))
- {
- qlen--;
- qhead++;
- }
+ while (qlen && dump_to_midi(tmp_queue[qhead])) {
+ qlen--;
+ qhead++;
+ }
- RESTORE_INTR (flags);
+ splx(flags);
- /*
- * Output the byte if the local queue is empty.
- */
+ /*
+ * Output the byte if the local queue is empty.
+ */
- if (!qlen)
- if (dump_to_midi (midi_byte))
- return 1; /*
- * OK
- */
+ if (!qlen)
+ if (dump_to_midi(midi_byte))
+ return 1; /* OK */
- /*
- * Put to the local queue
- */
+ /*
+ * Put to the local queue
+ */
- if (qlen >= 256)
- return 0; /*
- * Local queue full
- */
+ if (qlen >= 256)
+ return 0; /* Local queue full */
- DISABLE_INTR (flags);
+ flags = splhigh();
- tmp_queue[qtail] = midi_byte;
- qlen++;
- qtail++;
+ tmp_queue[qtail] = midi_byte;
+ qlen++;
+ qtail++;
- RESTORE_INTR (flags);
+ splx(flags);
- return 1;
+ return 1;
}
static int
-gus_midi_start_read (int dev)
+gus_midi_start_read(int dev)
{
- return 0;
+ return 0;
}
static int
-gus_midi_end_read (int dev)
+gus_midi_end_read(int dev)
{
- return 0;
+ return 0;
}
static int
-gus_midi_ioctl (int dev, unsigned cmd, unsigned arg)
+gus_midi_ioctl(int dev, unsigned cmd, ioctl_arg arg)
{
- return RET_ERROR (EINVAL);
+ return -(EINVAL);
}
static void
-gus_midi_kick (int dev)
+gus_midi_kick(int dev)
{
}
static int
-gus_midi_buffer_status (int dev)
+gus_midi_buffer_status(int dev)
{
- unsigned long flags;
-
- if (!output_used)
- return 0;
+ unsigned long flags;
- DISABLE_INTR (flags);
+ if (!output_used)
+ return 0;
- if (qlen && dump_to_midi (tmp_queue[qhead]))
- {
- qlen--;
- qhead++;
- }
+ flags = splhigh();
- RESTORE_INTR (flags);
+ if (qlen && dump_to_midi(tmp_queue[qhead])) {
+ qlen--;
+ qhead++;
+ }
+ splx(flags);
- return (qlen > 0) | !(GUS_MIDI_STATUS () & MIDI_XMIT_EMPTY);
+ return (qlen > 0) | !(GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY);
}
#define MIDI_SYNTH_NAME "Gravis Ultrasound Midi"
@@ -229,84 +209,66 @@ gus_midi_buffer_status (int dev)
static struct midi_operations gus_midi_operations =
{
- {"Gravis UltraSound Midi", 0, 0, SNDCARD_GUS},
- &std_midi_synth,
- {0},
- gus_midi_open,
- gus_midi_close,
- gus_midi_ioctl,
- gus_midi_out,
- gus_midi_start_read,
- gus_midi_end_read,
- gus_midi_kick,
- NULL, /*
- * command
- */
- gus_midi_buffer_status,
- NULL
+ {"Gravis UltraSound Midi", 0, 0, SNDCARD_GUS},
+ &std_midi_synth,
+ {0},
+ gus_midi_open,
+ gus_midi_close,
+ gus_midi_ioctl,
+ gus_midi_out,
+ gus_midi_start_read,
+ gus_midi_end_read,
+ gus_midi_kick,
+ NULL, /* command */
+ gus_midi_buffer_status,
+ NULL
};
-long
-gus_midi_init (long mem_start)
+void
+gus_midi_init()
{
- if (num_midis >= MAX_MIDI_DEV)
- {
- printk ("Sound: Too many midi devices detected\n");
- return mem_start;
- }
-
- OUTB (MIDI_RESET, u_MidiControl);
+ if (num_midis >= MAX_MIDI_DEV) {
+ printf("Sound: Too many midi devices detected\n");
+ return;
+ }
+ outb(u_MidiControl, MIDI_RESET);
- std_midi_synth.midi_dev = my_dev = num_midis;
- midi_devs[num_midis++] = &gus_midi_operations;
- return mem_start;
+ std_midi_synth.midi_dev = my_dev = num_midis;
+ midi_devs[num_midis++] = &gus_midi_operations;
+ return;
}
void
-gus_midi_interrupt (int dummy)
+gus_midi_interrupt(int dummy)
{
- unsigned char stat, data;
- unsigned long flags;
-
- DISABLE_INTR (flags);
-
- stat = GUS_MIDI_STATUS ();
-
- if (stat & MIDI_RCV_FULL)
- {
- data = INB (u_MidiData);
- if (input_opened)
- midi_input_intr (my_dev, data);
- }
-
- if (stat & MIDI_XMIT_EMPTY)
- {
- while (qlen && dump_to_midi (tmp_queue[qhead]))
- {
- qlen--;
- qhead++;
- }
+ unsigned char stat, data;
+ unsigned long flags;
- if (!qlen)
- {
- /*
- * Disable Midi output interrupts, since no data in the buffer
- */
- gus_midi_control &= ~MIDI_ENABLE_XMIT;
- OUTB (gus_midi_control, u_MidiControl);
- }
- }
+ flags = splhigh();
-#if 0
- if (stat & MIDI_FRAME_ERR)
- printk ("GUS: Midi framing error\n");
- if (stat & MIDI_OVERRUN && input_opened)
- printk ("GUS: Midi input overrun\n");
-#endif
+ stat = GUS_MIDI_STATUS();
- RESTORE_INTR (flags);
+ if (stat & MIDI_RCV_FULL) {
+ data = inb(u_MidiData);
+ if (input_opened)
+ midi_input_intr(my_dev, data);
+ }
+ if (stat & MIDI_XMIT_EMPTY) {
+ while (qlen && dump_to_midi(tmp_queue[qhead])) {
+ qlen--;
+ qhead++;
+ }
+
+ if (!qlen) {
+ /*
+ * Disable Midi output interrupts, since no data in
+ * the buffer
+ */
+ gus_midi_control &= ~MIDI_ENABLE_XMIT;
+ outb(u_MidiControl, gus_midi_control);
+ }
+ }
+ splx(flags);
}
#endif
-
-#endif
diff --git a/sys/i386/isa/sound/gus_vol.c b/sys/i386/isa/sound/gus_vol.c
index a8f1121..fc66618 100644
--- a/sys/i386/isa/sound/gus_vol.c
+++ b/sys/i386/isa/sound/gus_vol.c
@@ -1,19 +1,19 @@
/*
* gus_vol.c - Compute volume for GUS.
- *
+ *
* Greg Lee 1993.
*/
#include <i386/isa/sound/sound_config.h>
-#ifndef EXCLUDE_GUS
-#include <i386/isa/sound/gus_linearvol.h>
-extern unsigned short gus_adagio_vol (int vel, int mainv, int xpn, int voicev);
-extern unsigned short gus_linear_vol (int vol, int mainvol);
+#ifdef CONFIG_GUS
+#include <i386/isa/sound/gus_linearvol.h>
#define GUS_VOLUME gus_wave_volume
extern int gus_wave_volume;
+unsigned short gus_adagio_vol(int vel, int mainv, int xpn, int voicev);
+unsigned short gus_linear_vol(int vol, int mainvol);
/*
* Calculate gus volume from note velocity, main volume, expression, and
@@ -24,93 +24,87 @@ extern int gus_wave_volume;
* to expression controller messages, if they were found to be used for
* dynamic volume adjustments, so here, main volume can be assumed to be
* constant throughout a song.)
- *
+ *
* Intrinsic patch volume is added in, but if over 64 is also multiplied in, so
* we can give a big boost to very weak voices like nylon guitar and the
* basses. The normal value is 64. Strings are assigned lower values.
*/
unsigned short
-gus_adagio_vol (int vel, int mainv, int xpn, int voicev)
+gus_adagio_vol(int vel, int mainv, int xpn, int voicev)
{
- int i, m, n, x;
-
-
- /*
- * A voice volume of 64 is considered neutral, so adjust the main volume if
- * something other than this neutral value was assigned in the patch
- * library.
- */
- x = 256 + 6 * (voicev - 64);
-
- /*
- * Boost expression by voice volume above neutral.
- */
- if (voicev > 65)
- xpn += voicev - 64;
- xpn += (voicev - 64) / 2;
-
- /*
- * Combine multiplicative and level components.
- */
- x = vel * xpn * 6 + (voicev / 4) * x;
+ int i, m, n, x;
+
+ /*
+ * A voice volume of 64 is considered neutral, so adjust the main
+ * volume if something other than this neutral value was assigned in
+ * the patch library.
+ */
+ x = 256 + 6 * (voicev - 64);
+
+ /*
+ * Boost expression by voice volume above neutral.
+ */
+ if (voicev > 65)
+ xpn += voicev - 64;
+ xpn += (voicev - 64) / 2;
+
+ /*
+ * Combine multiplicative and level components.
+ */
+ x = vel * xpn * 6 + (voicev / 4) * x;
#ifdef GUS_VOLUME
- /*
- * Further adjustment by installation-specific master volume control
- * (default 60).
- */
- x = (x * GUS_VOLUME * GUS_VOLUME) / 10000;
+ /*
+ * Further adjustment by installation-specific master volume control
+ * (default 60).
+ */
+ x = (x * GUS_VOLUME * GUS_VOLUME) / 10000;
#endif
#ifdef GUS_USE_CHN_MAIN_VOLUME
- /*
- * Experimental support for the channel main volume
- */
+ /*
+ * Experimental support for the channel main volume
+ */
- mainv = (mainv / 2) + 64; /* Scale to 64 to 127 */
- x = (x * mainv * mainv) / 16384;
+ mainv = (mainv / 2) + 64; /* Scale to 64 to 127 */
+ x = (x * mainv * mainv) / 16384;
#endif
- if (x < 2)
- return (0);
- else if (x >= 65535)
- return ((15 << 8) | 255);
-
- /*
- * Convert to gus's logarithmic form with 4 bit exponent i and 8 bit
- * mantissa m.
- */
- n = x;
- i = 7;
- if (n < 128)
- {
- while (i > 0 && n < (1 << i))
- i--;
- }
- else
- while (n > 255)
- {
- n >>= 1;
- i++;
- }
- /*
- * Mantissa is part of linear volume not expressed in exponent. (This is
- * not quite like real logs -- I wonder if it's right.)
- */
- m = x - (1 << i);
-
- /*
- * Adjust mantissa to 8 bits.
- */
- if (m > 0)
- {
- if (i > 8)
- m >>= i - 8;
- else if (i < 8)
- m <<= 8 - i;
+ if (x < 2)
+ return (0);
+ else if (x >= 65535)
+ return ((15 << 8) | 255);
+
+ /*
+ * Convert to gus's logarithmic form with 4 bit exponent i and 8 bit
+ * mantissa m.
+ */
+ n = x;
+ i = 7;
+ if (n < 128) {
+ while (i > 0 && n < (1 << i))
+ i--;
+ } else
+ while (n > 255) {
+ n >>= 1;
+ i++;
+ }
+ /*
+ * Mantissa is part of linear volume not expressed in exponent.
+ * (This is not quite like real logs -- I wonder if it's right.)
+ */
+ m = x - (1 << i);
+
+ /*
+ * Adjust mantissa to 8 bits.
+ */
+ if (m > 0) {
+ if (i > 8)
+ m >>= i - 8;
+ else if (i < 8)
+ m <<= 8 - i;
}
-
- return ((i << 8) + m);
+ return ((i << 8) + m);
}
/*
@@ -120,31 +114,25 @@ gus_adagio_vol (int vel, int mainv, int xpn, int voicev)
*/
unsigned short
-gus_linear_vol (int vol, int mainvol)
+gus_linear_vol(int vol, int mainvol)
{
- int mixer_mainvol;
+ int mixer_mainvol;
- if (vol <= 0)
- vol = 0;
- else if (vol >= 127)
- vol = 127;
+ RANGE (vol, 0, 127) ;
#ifdef GUS_VOLUME
- mixer_mainvol = GUS_VOLUME;
+ mixer_mainvol = GUS_VOLUME;
#else
- mixer_mainvol = 100;
+ mixer_mainvol = 100;
#endif
#ifdef GUS_USE_CHN_MAIN_VOLUME
- if (mainvol <= 0)
- mainvol = 0;
- else if (mainvol >= 127)
- mainvol = 127;
+ RANGE (mainvol, 0, 127);
#else
- mainvol = 128;
+ mainvol = 127;
#endif
- return gus_linearvol[(((vol * mainvol) / 128) * mixer_mainvol) / 100];
+ return gus_linearvol[(((vol * mainvol) / 127) * mixer_mainvol) / 100];
}
#endif
diff --git a/sys/i386/isa/sound/gus_wave.c b/sys/i386/isa/sound/gus_wave.c
index e0f946d6..f1269f5 100644
--- a/sys/i386/isa/sound/gus_wave.c
+++ b/sys/i386/isa/sound/gus_wave.c
@@ -1,10 +1,10 @@
/*
* sound/gus_wave.c
- *
+ *
* Driver for the Gravis UltraSound wave table synth.
- *
+ *
* 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
* met: 1. Redistributions of source code must retain the above copyright
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,83 +24,109 @@
* 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 <i386/isa/sound/sound_config.h>
-#include <machine/ultrasound.h>
+#include <i386/isa/sound/ultrasound.h>
#include <i386/isa/sound/gus_hw.h>
+#include <i386/isa/sound/iwdefs.h>
+#include <machine/clock.h>
-static unsigned char gus_look8 __P((int reg));
-static unsigned short gus_read16 __P((int reg));
-static void gus_write_addr __P((int reg, unsigned long address, int is16bit));
-static void gus_write16 __P((int reg, unsigned int data));
+/* PnP stuff */
+#define GUS_PNP_ID 0x100561e
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)
+#define MAX_CARDS 8
+#define MAX_GUS_PNP 8
+
+
+/* Static ports */
+#define PADDRESS 0x279
+#define PWRITE_DATA 0xa79
+#define SET_CSN 0x06
+#define PSTATUS 0x05
+
+/* PnP Registers. Write to ADDRESS and then use WRITE/READ_DATA */
+#define SET_RD_DATA 0x00
+#define SERIAL_ISOLATION 0x01
+#define WAKE 0x03
+
+#if defined(CONFIG_GUS)
+
+IWAVE iw;
+#define ENTER_CRITICAL
+
+#define LEAVE_CRITICAL
#define MAX_SAMPLE 150
#define MAX_PATCH 256
-struct voice_info
- {
- unsigned long orig_freq;
- unsigned long current_freq;
- unsigned long mode;
- int bender;
- int bender_range;
- int panning;
- int midi_volume;
- unsigned int initial_volume;
- unsigned int current_volume;
- int loop_irq_mode, loop_irq_parm;
+#define MAX_GUS_PNP 12
+u_int gus_pnp_found[MAX_GUS_PNP] =
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+struct voice_info {
+ u_long orig_freq;
+ u_long current_freq;
+ u_long mode;
+ int bender;
+ int bender_range;
+ int panning;
+ int midi_volume;
+ u_int initial_volume;
+ u_int current_volume;
+ int loop_irq_mode, loop_irq_parm;
#define LMODE_FINISH 1
#define LMODE_PCM 2
#define LMODE_PCM_STOP 3
- int volume_irq_mode, volume_irq_parm;
+ int volume_irq_mode, volume_irq_parm;
#define VMODE_HALT 1
#define VMODE_ENVELOPE 2
#define VMODE_START_NOTE 3
- int env_phase;
- unsigned char env_rate[6];
- unsigned char env_offset[6];
+ int env_phase;
+ u_char env_rate[6];
+ u_char env_offset[6];
- /*
- * Volume computation parameters for gus_adagio_vol()
- */
- int main_vol, expression_vol, patch_vol;
+ /*
+ * Volume computation parameters for gus_adagio_vol()
+ */
+ int main_vol, expression_vol, patch_vol;
- /* Variables for "Ultraclick" removal */
- int dev_pending, note_pending, volume_pending, sample_pending;
- char kill_pending;
- long offset_pending;
+ /* Variables for "Ultraclick" removal */
+ int dev_pending, note_pending, volume_pending, sample_pending;
+ char kill_pending;
+ long offset_pending;
- };
+};
static struct voice_alloc_info *voice_alloc;
extern int gus_base;
extern int gus_irq, gus_dma;
+static int gus_dma2 = -1;
+static int dual_dma_mode = 0;
static long gus_mem_size = 0;
static long free_mem_ptr = 0;
-static int gus_busy[MAX_AUDIO_DEV], gus_dspnum=0;
-static int gus_dma_read=0;
+static int gus_no_dma = 0;
static int nr_voices = 0;
static int gus_devnum = 0;
static int volume_base, volume_scale, volume_method;
static int gus_recmask = SOUND_MASK_MIC;
static int recording_active = 0;
static int only_read_access = 0;
+static int only_8_bits = 0;
int gus_wave_volume = 60;
-static int gus_pcm_volume = 80;
+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;
+static u_char mix_image = 0x00;
+int gus_timer_enabled = 0;
/*
- * Current version of this driver doesn't allow synth and PCM functions
- * at the same time. The active_device specifies the active driver
+ * Current version of this driver doesn't allow synth and PCM functions at
+ * the same time. The active_device specifies the active driver
*/
static int active_device = 0;
@@ -112,7 +138,9 @@ static int gus_sampling_speed;
static int gus_sampling_channels;
static int gus_sampling_bits;
-DEFINE_WAIT_QUEUE (dram_sleeper, dram_sleep_flag);
+static int *dram_sleeper = NULL;
+static volatile struct snd_wait dram_sleep_flag =
+{0};
/*
* Variables and buffers for PCM output
@@ -127,43 +155,45 @@ static volatile int dma_active;
static int pcm_opened = 0;
static int pcm_current_dev;
static int pcm_current_block;
-static unsigned long pcm_current_buf;
+static u_long pcm_current_buf;
static int pcm_current_count;
static int pcm_current_intrflag;
-#if defined(__FreeBSD__)
-static char *gus_copy_buf;
-#endif
+extern sound_os_info *gus_osp;
-static struct voice_info voices[32];
+struct voice_info voices[32];
static int freq_div_table[] =
{
- 44100, /* 14 */
- 41160, /* 15 */
- 38587, /* 16 */
- 36317, /* 17 */
- 34300, /* 18 */
- 32494, /* 19 */
- 30870, /* 20 */
- 29400, /* 21 */
- 28063, /* 22 */
- 26843, /* 23 */
- 25725, /* 24 */
- 24696, /* 25 */
- 23746, /* 26 */
- 22866, /* 27 */
- 22050, /* 28 */
- 21289, /* 29 */
- 20580, /* 30 */
- 19916, /* 31 */
- 19293 /* 32 */
+ 44100, /* 14 */
+ 41160, /* 15 */
+ 38587, /* 16 */
+ 36317, /* 17 */
+ 34300, /* 18 */
+ 32494, /* 19 */
+ 30870, /* 20 */
+ 29400, /* 21 */
+ 28063, /* 22 */
+ 26843, /* 23 */
+ 25725, /* 24 */
+ 24696, /* 25 */
+ 23746, /* 26 */
+ 22866, /* 27 */
+ 22050, /* 28 */
+ 21289, /* 29 */
+ 20580, /* 30 */
+ 19916, /* 31 */
+ 19293 /* 32 */
};
static struct patch_info *samples;
+struct patch_info *dbg_samples;
+int dbg_samplep;
+
static long sample_ptrs[MAX_SAMPLE + 1];
static int sample_map[32];
static int free_sample;
+static int mixer_type = 0;
static int patch_table[MAX_PATCH];
@@ -172,3274 +202,4673 @@ static int patch_map[32];
static struct synth_info gus_info =
{"Gravis UltraSound", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS, 0, 16, 0, MAX_PATCH};
-static void gus_poke (long addr, unsigned char data);
-static void compute_and_set_volume (int voice, int volume, int ramp_time);
-extern unsigned short gus_adagio_vol (int vel, int mainv, int xpn, int voicev);
-extern unsigned short gus_linear_vol (int vol, int mainvol);
-static void compute_volume (int voice, int volume);
-static void do_volume_irq (int voice);
-static void set_input_volumes (void);
+static void gus_default_mixer_init(void);
+
+int guswave_start_note2(int dev, int voice, int note_num, int volume);
+static void gus_poke(long addr, u_char data);
+void compute_and_set_volume(int voice, int volume, int ramp_time);
+extern u_short gus_adagio_vol(int vel, int mainv, int xpn, int voicev);
+extern u_short gus_linear_vol(int vol, int mainvol);
+void compute_volume(int voice, int volume);
+void do_volume_irq(int voice);
+static void set_input_volumes(void);
+static void gus_tmr_install(int io_base);
+
+void SEND(int d, int r);
+int get_serial(int rd_port, u_char *data);
+void send_Initiation_LFSR(void);
+int isolation_protocol(int rd_port);
+
#define INSTANT_RAMP -1 /* Instant change. No ramping */
#define FAST_RAMP 0 /* Fastest possible ramp */
+
+/* Crystal Select */
+#define CODEC_XTAL2 0x01 /* 16.9344 crystal */
+#define CODEC_XTAL1 0x00 /* 24.576 crystal */
+/************************************************************************/
+
+/************************************************************************/
+/* Definitions for CONFIG_1 register */
+#define CODEC_CFIG1I_DEFAULT 0x03 | 0x8
+#define CODEC_CAPTURE_PIO 0x80 /* Capture PIO enable */
+#define CODEC_PLAYBACK_PIO 0x40 /* Playback PIO enable */
+#define CODEC_AUTOCALIB 0x08 /* auto calibrate */
+#define CODEC_SINGLE_DMA 0x04 /* Use single DMA channel */
+#define CODEC_RE 0x02 /* Capture enable */
+#define CODEC_PE 0x01 /* playback enable */
+/************************************************************************/
+
+/************************************************************************/
+/* Definitions for CONFIG_2 register */
+#define CODEC_CFIG2I_DEFAULT 0x81
+#define CODEC_OFVS 0x80 /* Output Full Scale Voltage */
+#define CODEC_TE 0x40 /* Timer Enable */
+#define CODEC_RSCD 0x20 /* Recors Sample Counter Disable */
+#define CODEC_PSCD 0x10 /* Playback Sample Counter Disable */
+#define CODEC_DAOF 0x01 /* D/A Ouput Force Enable */
+/************************************************************************/
+
+/************************************************************************/
+/* Definitions for CONFIG_3 register */
+/* #define CODEC_CFIG3I_DEFAULT 0xe0 0x02 when synth DACs are working */
+
+#define CODEC_CFIG3I_DEFAULT 0xc0 /* 0x02 when synth DACs are working */
+#define CODEC_RPIE 0x80 /* Record FIFO IRQ Enable */
+#define CODEC_PPIE 0x40 /* Playback FIFO IRQ Enable */
+#define CODEC_FT_MASK 0x30 /* FIFO Threshold Select */
+#define CODEC_PVFM 0x04 /* Playback Variable Frequency Mode */
+#define CODEC_SYNA 0x02 /* AUX1/Synth Signal Select */
+/************************************************************************/
+
+/************************************************************************/
+/* Definitions for EXTERNAL_CONTROL register */
+#define CODEC_CEXTI_DEFAULT 0x00
+#define CODEC_IRQ_ENABLE 0x02 /* interrupt enable */
+#define CODEC_GPOUT1 0x80 /* external control #1 */
+#define CODEC_GPOUT0 0x40 /* external control #0 */
+/************************************************************************/
+
+/************************************************************************/
+/* Definitions for MODE_SELECT_ID register */
+#define CODEC_MODE_DEFAULT 0x40
+#define CODEC_MODE_MASK 0x60
+#define CODEC_ID_BIT4 0x80
+#define CODEC_ID_BIT3_0 0x0F
+/************************************************************************/
+#define CONFIG_1 0x09
+#define EXTERNAL_CONTROL 0x0a/* Pin control */
+#define STATUS_2 0x0b/* Test and initialization */
+#define MODE_SELECT_ID 0x0c/* Miscellaneaous information */
+#define LOOPBACK 0x0d/* Digital Mix */
+#define UPPER_PLAY_COUNT 0x0e/* Playback Upper Base Count */
+#define LOWER_PLAY_COUNT 0x0f/* Playback Lower Base Count */
+#define CONFIG_2 0x10
+#define CONFIG_3 0x11
+
+
+#define IWL_CODEC_OUT(reg, val) \
+ { outb(iwl_codec_base, reg); outb(iwl_codec_data, val); }
+
+#define IWL_CODEC_IN(reg, val) \
+ { outb(iwl_codec_base, reg); val = inb(iwl_codec_data); }
+
+
+u_char gus_look8(int reg);
+
+void gus_write16(int reg, u_int data);
+
+u_short gus_read16(int reg);
+
+void gus_write_addr(int reg, u_long address, int is16bit);
+void IwaveLineLevel(char level, char index);
+void IwaveInputSource(BYTE index, BYTE source);
+void IwaveDelay(WORD count);
+void IwaveStopDma(BYTE path);
+void IwavePnpGetCfg(void);
+void IwavePnpDevice(BYTE dev);
+void IwavePnpSetCfg(void);
+void IwavePnpKey(void);
+BYTE IwavePnpIsol(PORT * pnpread);
+void IwaveCfgIOSpace(void);
+
+void IwavePnpSerial(PORT pnprdp, BYTE csn, BYTE * vendor, DWORD * serial);
+
+
+void IwavePnpPeek(PORT pnprdp, WORD bytes, BYTE * data);
+void IwavePnpEeprom(BYTE ctrl);
+void IwavePnpActivate(BYTE dev, BYTE bool);
+
+void IwavePnpPower(BYTE mode);
+void IwavePnpWake(BYTE csn);
+PORT IwavePnpIOcheck(PORT base, BYTE no_ports);
+
+BYTE IwavePnpGetCSN(DWORD VendorID, BYTE csn_max);
+BYTE IwavePnpPing(DWORD VendorID);
+WORD IwaveMemSize(void);
+BYTE IwaveMemPeek(ADDRESS addr);
+void IwaveMemPoke(ADDRESS addr, BYTE datum);
+void IwaveMemCfg(DWORD * lpbanks);
+void IwaveCodecIrq(BYTE mode);
+WORD IwaveRegPeek(DWORD reg_mnem);
+
+void IwaveRegPoke(DWORD reg_mnem, WORD datum);
+void IwaveCodecMode(char mode);
+void IwaveLineMute(BYTE mute, BYTE inx);
+void Iwaveinitcodec(void);
+int IwaveOpen(char voices, char mode, struct address_info * hw);
+
+
static void
-reset_sample_memory (void)
+reset_sample_memory(void)
{
- int i;
+ int i;
- for (i = 0; i <= MAX_SAMPLE; i++)
- sample_ptrs[i] = -1;
- for (i = 0; i < 32; i++)
- sample_map[i] = -1;
- for (i = 0; i < 32; i++)
- patch_map[i] = -1;
+ for (i = 0; i <= MAX_SAMPLE; i++)
+ sample_ptrs[i] = -1;
+ for (i = 0; i < 32; i++)
+ sample_map[i] = -1;
+ for (i = 0; i < 32; i++)
+ patch_map[i] = -1;
- gus_poke (0, 0); /* Put a silent sample to the beginning */
- gus_poke (1, 0);
- free_mem_ptr = 2;
+ gus_poke(0, 0); /* Put a silent sample to the beginning */
+ gus_poke(1, 0);
+ free_mem_ptr = 2;
- free_sample = 0;
+ free_sample = 0;
- for (i = 0; i < MAX_PATCH; i++)
- patch_table[i] = -1;
+ for (i = 0; i < MAX_PATCH; i++)
+ patch_table[i] = -1;
}
void
-gus_delay (void)
+gus_delay(void)
{
- int i;
+ int i;
- for (i = 0; i < 7; i++)
- INB (u_DRAMIO);
+ for (i = 0; i < 7; i++)
+ inb(u_DRAMIO);
}
static void
-gus_poke (long addr, unsigned char data)
+gus_poke(long addr, u_char data)
{ /* Writes a byte to the DRAM */
- unsigned long flags;
+ u_long flags;
- DISABLE_INTR (flags);
- OUTB (0x43, u_Command);
- OUTB (addr & 0xff, u_DataLo);
- OUTB ((addr >> 8) & 0xff, u_DataHi);
+ flags = splhigh();
+ outb(u_Command, 0x43);
+ outb(u_DataLo, addr & 0xff);
+ outb(u_DataHi, (addr >> 8) & 0xff);
- OUTB (0x44, u_Command);
- OUTB ((addr >> 16) & 0xff, u_DataHi);
- OUTB (data, u_DRAMIO);
- RESTORE_INTR (flags);
+ outb(u_Command, 0x44);
+ outb(u_DataHi, (addr >> 16) & 0xff);
+ outb(u_DRAMIO, data);
+ splx(flags);
}
-static unsigned char
-gus_peek (long addr)
+static u_char
+gus_peek(long addr)
{ /* Reads a byte from the DRAM */
- unsigned long flags;
- unsigned char tmp;
+ u_long flags;
+ u_char tmp;
- DISABLE_INTR (flags);
- OUTB (0x43, u_Command);
- OUTB (addr & 0xff, u_DataLo);
- OUTB ((addr >> 8) & 0xff, u_DataHi);
+ flags = splhigh();
+ outb(u_Command, 0x43);
+ outb(u_DataLo, addr & 0xff);
+ outb(u_DataHi, (addr >> 8) & 0xff);
- OUTB (0x44, u_Command);
- OUTB ((addr >> 16) & 0xff, u_DataHi);
- tmp = INB (u_DRAMIO);
- RESTORE_INTR (flags);
+ outb(u_Command, 0x44);
+ outb(u_DataHi, (addr >> 16) & 0xff);
+ tmp = inb(u_DRAMIO);
+ splx(flags);
- return tmp;
+ return tmp;
}
void
-gus_write8 (int reg, unsigned int data)
+gus_write8(int reg, u_int data)
{ /* Writes to an indirect register (8 bit) */
- unsigned long flags;
+ u_long flags;
- DISABLE_INTR (flags);
-
- OUTB (reg, u_Command);
- OUTB ((unsigned char) (data & 0xff), u_DataHi);
-
- RESTORE_INTR (flags);
+ flags = splhigh();
+ outb(u_Command, reg);
+ outb(u_DataHi, (u_char) (data & 0xff));
+ splx(flags);
}
-static unsigned char
-gus_read8 (int reg)
-{ /* Reads from an indirect register (8 bit). Offset 0x80. */
- unsigned long flags;
- unsigned char val;
+u_char
+gus_read8(int reg)
+{ /* Reads from an indirect register (8 bit). Offset 0x80. */
+ u_long flags;
+ u_char val;
- DISABLE_INTR (flags);
- OUTB (reg | 0x80, u_Command);
- val = INB (u_DataHi);
- RESTORE_INTR (flags);
+ flags = splhigh();
+ outb(u_Command, reg | 0x80);
+ val = inb(u_DataHi);
+ splx(flags);
- return val;
+ return val;
}
-static unsigned char
-gus_look8 (int reg)
-{ /* Reads from an indirect register (8 bit). No additional offset. */
- unsigned long flags;
- unsigned char val;
+u_char
+gus_look8(int reg)
+{ /* Reads from an indirect register (8 bit). No additional offset. */
+ u_long flags;
+ u_char val;
- DISABLE_INTR (flags);
- OUTB (reg, u_Command);
- val = INB (u_DataHi);
- RESTORE_INTR (flags);
+ flags = splhigh();
+ outb(u_Command, reg);
+ val = inb(u_DataHi);
+ splx(flags);
- return val;
+ return val;
}
-static void
-gus_write16 (int reg, unsigned int data)
-{ /* Writes to an indirect register (16 bit) */
- unsigned long flags;
+void
+gus_write16(int reg, u_int data)
+{ /* Writes to an indirect register (16 bit) */
+ u_long flags;
- DISABLE_INTR (flags);
+ flags = splhigh();
- OUTB (reg, u_Command);
+ outb(u_Command, reg);
- OUTB ((unsigned char) (data & 0xff), u_DataLo);
- OUTB ((unsigned char) ((data >> 8) & 0xff), u_DataHi);
+ outb(u_DataLo, (u_char) (data & 0xff));
+ outb(u_DataHi, (u_char) ((data >> 8) & 0xff));
- RESTORE_INTR (flags);
+ splx(flags);
}
-static unsigned short
-gus_read16 (int reg)
-{ /* Reads from an indirect register (16 bit). Offset 0x80. */
- unsigned long flags;
- unsigned char hi, lo;
+u_short
+gus_read16(int reg)
+{ /* Reads from an indirect register (16 bit). Offset 0x80. */
+ u_long flags;
+ u_char hi, lo;
- DISABLE_INTR (flags);
+ flags = splhigh();
- OUTB (reg | 0x80, u_Command);
+ outb(u_Command, reg | 0x80);
- lo = INB (u_DataLo);
- hi = INB (u_DataHi);
+ lo = inb(u_DataLo);
+ hi = inb(u_DataHi);
- RESTORE_INTR (flags);
+ splx(flags);
- return ((hi << 8) & 0xff00) | lo;
+ return ((hi << 8) & 0xff00) | lo;
}
-static void
-gus_write_addr (int reg, unsigned long address, int is16bit)
+void
+gus_write_addr(int reg, u_long address, int is16bit)
{ /* Writes an 24 bit memory address */
- unsigned long hold_address;
- unsigned long flags;
+ u_long hold_address;
+ u_long flags;
- DISABLE_INTR (flags);
- if (is16bit)
- {
- /*
- * Special processing required for 16 bit patches
- */
-
- hold_address = address;
- address = address >> 1;
- address &= 0x0001ffffL;
- address |= (hold_address & 0x000c0000L);
- }
+ flags = splhigh();
+ if (is16bit) {
+ /*
+ * Special processing required for 16 bit patches
+ */
- gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff));
- gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff));
- /* Could writing twice fix problems with GUS_VOICE_POS() ? Lets try... */
- gus_delay ();
- gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff));
- gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff));
- RESTORE_INTR (flags);
+ hold_address = address;
+ address = address >> 1;
+ address &= 0x0001ffffL;
+ address |= (hold_address & 0x000c0000L);
+ }
+ gus_write16(reg, (u_short) ((address >> 7) & 0xffff));
+ gus_write16(reg + 1, (u_short) ((address << 9) & 0xffff));
+ /*
+ * Could writing twice fix problems with GUS_VOICE_POS() ? Lets try...
+ */
+ gus_delay();
+ gus_write16(reg, (u_short) ((address >> 7) & 0xffff));
+ gus_write16(reg + 1, (u_short) ((address << 9) & 0xffff));
+ splx(flags);
}
static void
-gus_select_voice (int voice)
+gus_select_voice(int voice)
{
- if (voice < 0 || voice > 31)
- return;
+ if (voice < 0 || voice > 31)
+ return;
- OUTB (voice, u_Voice);
+ outb(u_Voice, voice);
}
static void
-gus_select_max_voices (int nvoices)
+gus_select_max_voices(int nvoices)
{
- if (nvoices < 14)
- nvoices = 14;
- if (nvoices > 32)
- nvoices = 32;
+ if (nvoices < 14)
+ nvoices = 14;
+ if (nvoices > 32)
+ nvoices = 32;
- voice_alloc->max_voice = nr_voices = nvoices;
+ voice_alloc->max_voice = nr_voices = nvoices;
- gus_write8 (0x0e, (nvoices - 1) | 0xc0);
+ gus_write8(0x0e, (nvoices - 1) | 0xc0);
}
static void
-gus_voice_on (unsigned int mode)
+gus_voice_on(u_int mode)
{
- gus_write8 (0x00, (unsigned char) (mode & 0xfc));
- gus_delay ();
- gus_write8 (0x00, (unsigned char) (mode & 0xfc));
+ gus_write8(0x00, (u_char) (mode & 0xfc));
+ gus_delay();
+ gus_write8(0x00, (u_char) (mode & 0xfc));
}
static void
-gus_voice_off (void)
+gus_voice_off(void)
{
- gus_write8 (0x00, gus_read8 (0x00) | 0x03);
+ gus_write8(0x00, gus_read8(0x00) | 0x03);
}
static void
-gus_voice_mode (unsigned int m)
+gus_voice_mode(u_int m)
{
- unsigned char mode = (unsigned char) (m & 0xff);
+ u_char mode = (u_char) (m & 0xff);
- 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));
+ 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));
}
static void
-gus_voice_freq (unsigned long freq)
+gus_voice_freq(u_long freq)
{
- unsigned long divisor = freq_div_table[nr_voices - 14];
- unsigned short fc;
+ u_long divisor = freq_div_table[nr_voices - 14];
+ u_short fc;
- fc = (unsigned short) (((freq << 9) + (divisor >> 1)) / divisor);
- fc = fc << 1;
+ fc = (u_short) (((freq << 9) + (divisor >> 1)) / divisor);
+ fc = fc << 1;
- gus_write16 (0x01, fc);
+ gus_write16(0x01, fc);
}
static void
-gus_voice_volume (unsigned int vol)
+gus_voice_volume(u_int vol)
{
- gus_write8 (0x0d, 0x03); /* Stop ramp before setting volume */
- gus_write16 (0x09, (unsigned short) (vol << 4));
+ gus_write8(0x0d, 0x03); /* Stop ramp before setting volume */
+ gus_write16(0x09, (u_short) (vol << 4));
}
static void
-gus_voice_balance (unsigned int balance)
+gus_voice_balance(u_int balance)
{
- gus_write8 (0x0c, (unsigned char) (balance & 0xff));
+ gus_write8(0x0c, (u_char) (balance & 0xff));
}
static void
-gus_ramp_range (unsigned int low, unsigned int high)
+gus_ramp_range(u_int low, u_int high)
{
- gus_write8 (0x07, (unsigned char) ((low >> 4) & 0xff));
- gus_write8 (0x08, (unsigned char) ((high >> 4) & 0xff));
+ gus_write8(0x07, (u_char) ((low >> 4) & 0xff));
+ gus_write8(0x08, (u_char) ((high >> 4) & 0xff));
}
static void
-gus_ramp_rate (unsigned int scale, unsigned int rate)
+gus_ramp_rate(u_int scale, u_int rate)
{
- gus_write8 (0x06, (unsigned char) (((scale & 0x03) << 6) | (rate & 0x3f)));
+ gus_write8(0x06, (u_char) (((scale & 0x03) << 6) | (rate & 0x3f)));
}
static void
-gus_rampon (unsigned int m)
+gus_rampon(u_int m)
{
- unsigned char mode = (unsigned char) (m & 0xff);
+ u_char mode = (u_char) (m & 0xff);
- gus_write8 (0x0d, mode & 0xfc);
- gus_delay ();
- gus_write8 (0x0d, mode & 0xfc);
+ gus_write8(0x0d, mode & 0xfc);
+ gus_delay();
+ gus_write8(0x0d, mode & 0xfc);
}
static void
-gus_ramp_mode (unsigned int m)
+gus_ramp_mode(u_int m)
{
- unsigned char mode = (unsigned char) (m & 0xff);
+ u_char mode = (u_char) (m & 0xff);
- 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));
+ 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));
}
static void
-gus_rampoff (void)
+gus_rampoff(void)
{
- gus_write8 (0x0d, 0x03);
+ gus_write8(0x0d, 0x03);
}
static void
-gus_set_voice_pos (int voice, long position)
+gus_set_voice_pos(int voice, long position)
{
- int sample_no;
-
- if ((sample_no = sample_map[voice]) != -1)
- if (position < samples[sample_no].len)
- if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
- voices[voice].offset_pending = position;
- else
- gus_write_addr (0x0a, sample_ptrs[sample_no] + position,
- samples[sample_no].mode & WAVE_16_BITS);
+ int sample_no;
+
+ if ((sample_no = sample_map[voice]) != -1)
+ if (position < samples[sample_no].len)
+ if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
+ voices[voice].offset_pending = position;
+ else
+ gus_write_addr(0x0a, sample_ptrs[sample_no] + position,
+ samples[sample_no].mode & WAVE_16_BITS);
}
static void
-gus_voice_init (int voice)
+gus_voice_init(int voice)
{
- unsigned long flags;
-
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_voice_volume (0);
- gus_voice_off ();
- gus_write_addr (0x0a, 0, 0); /* Set current position to 0 */
- gus_write8 (0x00, 0x03); /* Voice off */
- gus_write8 (0x0d, 0x03); /* Ramping off */
- voice_alloc->map[voice] = 0;
- voice_alloc->alloc_times[voice] = 0;
- RESTORE_INTR (flags);
+ u_long flags;
+
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_voice_volume(0);
+ gus_voice_off();
+ gus_write_addr(0x0a, 0, 0); /* Set current position to 0 */
+ gus_write8(0x00, 0x03); /* Voice off */
+ gus_write8(0x0d, 0x03); /* Ramping off */
+ voice_alloc->map[voice] = 0;
+ voice_alloc->alloc_times[voice] = 0;
+ splx(flags);
}
static void
-gus_voice_init2 (int voice)
-{
- voices[voice].panning = 0;
- voices[voice].mode = 0;
- voices[voice].orig_freq = 20000;
- voices[voice].current_freq = 20000;
- voices[voice].bender = 0;
- voices[voice].bender_range = 200;
- voices[voice].initial_volume = 0;
- voices[voice].current_volume = 0;
- voices[voice].loop_irq_mode = 0;
- voices[voice].loop_irq_parm = 0;
- voices[voice].volume_irq_mode = 0;
- voices[voice].volume_irq_parm = 0;
- voices[voice].env_phase = 0;
- voices[voice].main_vol = 127;
- voices[voice].patch_vol = 127;
- voices[voice].expression_vol = 127;
- voices[voice].sample_pending = -1;
+gus_voice_init2(int voice)
+{
+ voices[voice].panning = 0;
+ voices[voice].mode = 0;
+ voices[voice].orig_freq = 20000;
+ voices[voice].current_freq = 20000;
+ voices[voice].bender = 0;
+ voices[voice].bender_range = 200;
+ voices[voice].initial_volume = 0;
+ voices[voice].current_volume = 0;
+ voices[voice].loop_irq_mode = 0;
+ voices[voice].loop_irq_parm = 0;
+ voices[voice].volume_irq_mode = 0;
+ voices[voice].volume_irq_parm = 0;
+ voices[voice].env_phase = 0;
+ voices[voice].main_vol = 127;
+ voices[voice].patch_vol = 127;
+ voices[voice].expression_vol = 127;
+ voices[voice].sample_pending = -1;
}
static void
-step_envelope (int voice)
+step_envelope(int voice)
{
- unsigned vol, prev_vol, phase;
- unsigned char rate;
- long int flags;
-
- if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2)
- {
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_rampoff ();
- RESTORE_INTR (flags);
- return;
- /*
- * Sustain phase begins. Continue envelope after receiving note off.
- */
+ u_int vol, prev_vol, phase;
+ u_char rate;
+ long int flags;
+
+ if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2) {
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_rampoff();
+ splx(flags);
+ return;
+ /*
+ * 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;
+ if (voices[voice].env_phase >= 5) { /* Envelope finished. Shoot
+ * the voice down */
+ gus_voice_init(voice);
+ return;
}
-
- prev_vol = voices[voice].current_volume;
- phase = ++voices[voice].env_phase;
- compute_volume (voice, voices[voice].midi_volume);
- vol = voices[voice].initial_volume * voices[voice].env_offset[phase] / 255;
- rate = voices[voice].env_rate[phase];
-
- DISABLE_INTR (flags);
- gus_select_voice (voice);
-
- gus_voice_volume (prev_vol);
-
-
- gus_write8 (0x06, rate); /* Ramping rate */
-
- voices[voice].volume_irq_mode = VMODE_ENVELOPE;
-
- if (((vol - prev_vol) / 64) == 0) /* No significant volume change */
- {
- RESTORE_INTR (flags);
- step_envelope (voice); /* Continue the envelope on the next step */
- return;
+ prev_vol = voices[voice].current_volume;
+ phase = ++voices[voice].env_phase;
+ compute_volume(voice, voices[voice].midi_volume);
+ vol = voices[voice].initial_volume * voices[voice].env_offset[phase] / 255;
+ rate = voices[voice].env_rate[phase];
+
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_voice_volume(prev_vol);
+ gus_write8(0x06, rate); /* Ramping rate */
+
+ voices[voice].volume_irq_mode = VMODE_ENVELOPE;
+
+ if (((vol - prev_vol) / 64) == 0) { /* No significant volume
+ * change */
+ splx(flags);
+ step_envelope(voice); /* Continue the envelope on the next
+ * step */
+ return;
}
-
- if (vol > prev_vol)
- {
- if (vol >= (4096 - 64))
- vol = 4096 - 65;
- gus_ramp_range (0, vol);
- gus_rampon (0x20); /* Increasing volume, with IRQ */
- }
- else
- {
- if (vol <= 64)
- vol = 65;
- gus_ramp_range (vol, 4030);
- gus_rampon (0x60); /* Decreasing volume, with IRQ */
+ if (vol > prev_vol) {
+ if (vol >= (4096 - 64))
+ vol = 4096 - 65;
+ gus_ramp_range(0, vol);
+ gus_rampon(0x20); /* Increasing volume, with IRQ */
+ } else {
+ if (vol <= 64)
+ vol = 65;
+ gus_ramp_range(vol, 4030);
+ gus_rampon(0x60); /* Decreasing volume, with IRQ */
}
- voices[voice].current_volume = vol;
- RESTORE_INTR (flags);
+ voices[voice].current_volume = vol;
+ splx(flags);
}
static void
-init_envelope (int voice)
+init_envelope(int voice)
{
- voices[voice].env_phase = -1;
- voices[voice].current_volume = 64;
+ voices[voice].env_phase = -1;
+ voices[voice].current_volume = 64;
- step_envelope (voice);
+ step_envelope(voice);
}
static void
-start_release (int voice, long int flags)
+start_release(int voice, long int flags)
{
- if (gus_read8 (0x00) & 0x03)
- return; /* Voice already stopped */
+ if (gus_read8(0x00) & 0x03)
+ 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].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 ();
- RESTORE_INTR (flags);
- step_envelope (voice);
+ voices[voice].mode &= ~WAVE_SUSTAIN_ON;
+ gus_rampoff();
+ splx(flags);
+ step_envelope(voice);
}
static void
-gus_voice_fade (int voice)
+gus_voice_fade(int voice)
{
- int instr_no = sample_map[voice], is16bits;
- long int flags;
+ int instr_no = sample_map[voice], is16bits;
+ long int flags;
- DISABLE_INTR (flags);
- gus_select_voice (voice);
+ flags = splhigh();
+ gus_select_voice(voice);
- if (instr_no < 0 || instr_no > MAX_SAMPLE)
- {
- gus_write8 (0x00, 0x03); /* Hard stop */
- voice_alloc->map[voice] = 0;
- RESTORE_INTR (flags);
- return;
+ if (instr_no < 0 || instr_no > MAX_SAMPLE) {
+ gus_write8(0x00, 0x03); /* Hard stop */
+ voice_alloc->map[voice] = 0;
+ splx(flags);
+ return;
}
+ is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /* 8 or 16 bits */
- is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /* 8 or 16 bits */
-
- if (voices[voice].mode & WAVE_ENVELOPES)
- {
- start_release (voice, flags);
- return;
+ if (voices[voice].mode & WAVE_ENVELOPES) {
+ start_release(voice, flags);
+ return;
}
-
- /*
- * Ramp the volume down but not too quickly.
- */
- if ((int) (gus_read16 (0x09) >> 4) < 100) /* Get current volume */
- {
- gus_voice_off ();
- gus_rampoff ();
- gus_voice_init (voice);
- return;
+ /*
+ * Ramp the volume down but not too quickly.
+ */
+ if ((int) (gus_read16(0x09) >> 4) < 100) { /* Get current volume */
+ gus_voice_off();
+ gus_rampoff();
+ gus_voice_init(voice);
+ return;
}
-
- gus_ramp_range (65, 4030);
- gus_ramp_rate (2, 4);
- gus_rampon (0x40 | 0x20); /* Down, once, with IRQ */
- voices[voice].volume_irq_mode = VMODE_HALT;
- RESTORE_INTR (flags);
+ gus_ramp_range(65, 4030);
+ gus_ramp_rate(2, 4);
+ gus_rampon(0x40 | 0x20);/* Down, once, with IRQ */
+ voices[voice].volume_irq_mode = VMODE_HALT;
+ splx(flags);
}
static void
-gus_reset (void)
+gus_reset(void)
{
- int i;
+ int i;
- gus_select_max_voices (24);
- volume_base = 3071;
- volume_scale = 4;
- volume_method = VOL_METHOD_ADAGIO;
+ gus_select_max_voices(24);
+ volume_base = 3071;
+ volume_scale = 4;
+ volume_method = VOL_METHOD_ADAGIO;
- for (i = 0; i < 32; i++)
- {
- gus_voice_init (i); /* Turn voice off */
- gus_voice_init2 (i);
+ for (i = 0; i < 32; i++) {
+ 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_look8(0x41); /* Clear any pending DMA IRQs */
+ gus_look8(0x49); /* Clear any pending sample IRQs */
- gus_read8 (0x0f); /* Clear pending IRQs */
+ gus_read8(0x0f); /* Clear pending IRQs */
}
static void
-gus_initialize (void)
+gus_initialize(void)
{
- unsigned long flags;
- unsigned char dma_image, irq_image, tmp;
+ u_long flags;
+ u_char dma_image, irq_image, tmp;
- static unsigned char gus_irq_map[16] =
- {0, 0, 0, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7};
+ static u_char gus_irq_map[16] =
+ {0, 0, 0, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7};
- static unsigned char gus_dma_map[8] =
- {0, 1, 0, 2, 0, 3, 4, 5};
+ static u_char gus_dma_map[8] =
+ {0, 1, 0, 2, 0, 3, 4, 5};
- DISABLE_INTR (flags);
- gus_write8 (0x4c, 0); /* Reset GF1 */
- gus_delay ();
- gus_delay ();
+ flags = splhigh();
+ gus_write8(0x4c, 0); /* Reset GF1 */
+ gus_delay();
+ gus_delay();
- gus_write8 (0x4c, 1); /* Release Reset */
- gus_delay ();
- gus_delay ();
+ gus_write8(0x4c, 1); /* Release Reset */
+ gus_delay();
+ gus_delay();
- /*
- * Clear all interrupts
- */
-
- gus_write8 (0x41, 0); /* DMA control */
- gus_write8 (0x45, 0); /* Timer control */
- gus_write8 (0x49, 0); /* Sample control */
+ /*
+ * Clear all interrupts
+ */
- gus_select_max_voices (24);
+ gus_write8(0x41, 0); /* DMA control */
+ gus_write8(0x45, 0); /* Timer control */
+ gus_write8(0x49, 0); /* Sample control */
- INB (u_Status); /* Touch the status register */
+ gus_select_max_voices(24);
- gus_look8 (0x41); /* Clear any pending DMA IRQs */
- gus_look8 (0x49); /* Clear any pending sample IRQs */
- gus_read8 (0x0f); /* Clear pending IRQs */
+ inb(u_Status); /* Touch the status register */
- 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_reset(); /* Resets all voices */
- gus_write8 (0x4c, 7); /* Master reset | DAC enable | IRQ enable */
+ gus_look8(0x41); /* Clear any pending DMA IRQs */
+ gus_look8(0x49); /* Clear any pending sample IRQs */
+ gus_read8(0x0f); /* Clear pending IRQs */
- /*
- * Set up for Digital ASIC
- */
+ gus_write8(0x4c, 7); /* Master reset | DAC enable | IRQ enable */
- OUTB (0x05, gus_base + 0x0f);
+ /*
+ * Set up for Digital ASIC
+ */
- mix_image |= 0x02; /* Disable line out */
- OUTB (mix_image, u_Mixer);
+ outb(gus_base + 0x0f, 0x05);
- OUTB (0x00, u_IRQDMAControl);
+ mix_image |= 0x02; /* Disable line out (for a moment) */
+ outb(u_Mixer, mix_image);
- OUTB (0x00, gus_base + 0x0f);
+ outb(u_IRQDMAControl, 0x00);
- /*
- * Now set up the DMA and IRQ interface
- *
- * The GUS supports two IRQs and two DMAs.
- *
- * Just one DMA channel is used. This prevents simultaneous ADC and DAC.
- * Adding this support requires significant changes to the dmabuf.c, dsp.c
- * and audio.c also.
- */
+ outb(gus_base + 0x0f, 0x00);
- irq_image = 0;
- tmp = gus_irq_map[gus_irq];
- if (!tmp)
- printk ("Warning! GUS IRQ not selected\n");
- irq_image |= tmp;
- irq_image |= 0x40; /* Combine IRQ1 (GF1) and IRQ2 (Midi) */
+ /*
+ * Now set up the DMA and IRQ interface
+ *
+ * The GUS supports two IRQs and two DMAs.
+ *
+ * Just one DMA channel is used. This prevents simultaneous ADC and DAC.
+ * Adding this support requires significant changes to the dmabuf.c,
+ * dsp.c and audio.c also.
+ */
- dma_image = gus_dma_map[gus_dma_read] << 3;
- if(!dma_image)
- printk ("Warning! GUS DMA read channel not selected.\n");
- if(gus_dma_read == gus_dma)
+ irq_image = 0;
+ tmp = gus_irq_map[gus_irq];
+ if (!tmp)
+ printf("Warning! GUS IRQ not selected\n");
+ irq_image |= tmp;
+ irq_image |= 0x40; /* Combine IRQ1 (GF1) and IRQ2 (Midi) */
+
+ dual_dma_mode = 1;
+ if (gus_dma2 == gus_dma || gus_dma2 == -1) {
+ dual_dma_mode = 0;
+ dma_image = 0x40; /* Combine DMA1 (DRAM) and IRQ2 (ADC) */
+
+ tmp = gus_dma_map[gus_dma];
+ if (!tmp)
+ printf("Warning! GUS DMA not selected\n");
+
+ dma_image |= tmp;
+ } else
+ /* Setup dual DMA channel mode for GUS MAX */
{
- dma_image = 0x40; /* dual dma inhibited
- Combine DMA1 (DRAM) and IRQ2 (ADC) */
+ dma_image = gus_dma_map[gus_dma];
+ if (!dma_image)
+ printf("Warning! GUS DMA not selected\n");
+
+ tmp = gus_dma_map[gus_dma2] << 3;
+ if (!tmp) {
+ printf("Warning! Invalid GUS MAX DMA\n");
+ tmp = 0x40; /* Combine DMA channels */
+ dual_dma_mode = 0;
+ }
+ dma_image |= tmp;
}
- tmp = gus_dma_map[gus_dma];
- if (!tmp)
- printk ("Warning! GUS DMA not selected\n");
- dma_image |= tmp;
- /*
- * For some reason the IRQ and DMA addresses must be written twice
- */
+ /*
+ * For some reason the IRQ and DMA addresses must be written twice
+ */
- /*
- * Doing it first time
- */
+ /*
+ * Doing it first time
+ */
- OUTB (mix_image, u_Mixer); /* Select DMA control */
- OUTB (dma_image | 0x80, u_IRQDMAControl); /* Set DMA address */
+ outb(u_Mixer, mix_image); /* Select DMA control */
+ outb(u_IRQDMAControl, dma_image | 0x80); /* Set DMA address */
- OUTB (mix_image | 0x40, u_Mixer); /* Select IRQ control */
- OUTB (irq_image, u_IRQDMAControl); /* Set IRQ address */
+ outb(u_Mixer, mix_image | 0x40); /* Select IRQ control */
+ outb(u_IRQDMAControl, irq_image); /* Set IRQ address */
- /*
- * Doing it second time
- */
+ /*
+ * Doing it second time
+ */
- OUTB (mix_image, u_Mixer); /* Select DMA control */
- OUTB (dma_image, u_IRQDMAControl); /* Set DMA address */
+ outb(u_Mixer, mix_image); /* Select DMA control */
+ outb(u_IRQDMAControl, dma_image); /* Set DMA address */
- OUTB (mix_image | 0x40, u_Mixer); /* Select IRQ control */
- OUTB (irq_image, u_IRQDMAControl); /* Set IRQ address */
+ outb(u_Mixer, mix_image | 0x40); /* Select IRQ control */
+ outb(u_IRQDMAControl, irq_image); /* Set IRQ address */
- gus_select_voice (0); /* This disables writes to IRQ/DMA reg */
+ gus_select_voice(0); /* This disables writes to IRQ/DMA reg */
- mix_image &= ~0x02; /* Enable line out */
- mix_image |= 0x08; /* Enable IRQ */
- OUTB (mix_image, u_Mixer); /*
- * Turn mixer channels on
- * Note! Mic in is left off.
- */
+ mix_image &= ~0x02; /* Enable line out */
+ mix_image |= 0x08; /* Enable IRQ */
+ outb(u_Mixer, mix_image); /* 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 (INT_HANDLER_CALL (0)); /* Serve pending interrupts */
- RESTORE_INTR (flags);
+ gusintr(0); /* Serve pending interrupts */
+ splx(flags);
}
int
-gus_wave_detect (int baseaddr)
+gus_wave_detect(int baseaddr)
{
- unsigned long i;
- unsigned long loc;
-
- gus_base = baseaddr;
-
- gus_write8 (0x4c, 0); /* Reset GF1 */
- gus_delay ();
- gus_delay ();
-
- gus_write8 (0x4c, 1); /* Release Reset */
- gus_delay ();
- gus_delay ();
-
- /* See if there is first block there.... */
- gus_poke (0L, 0xaa);
- if (gus_peek (0L) != 0xaa)
- return (0);
-
- /* Now zero it out so that I can check for mirroring .. */
- gus_poke (0L, 0x00);
- for (i = 1L; i < 1024L; i++)
- {
- int n, failed;
-
- /* check for mirroring ... */
- if (gus_peek (0L) != 0)
- break;
- loc = i << 10;
-
- for (n = loc - 1, failed = 0; n <= loc; n++)
- {
- gus_poke (loc, 0xaa);
- if (gus_peek (loc) != 0xaa)
- failed = 1;
-
- gus_poke (loc, 0x55);
- if (gus_peek (loc) != 0x55)
- failed = 1;
+ u_long i;
+ u_long loc;
+ gus_base = baseaddr;
+
+ gus_write8(0x4c, 0); /* Reset GF1 */
+ gus_delay();
+ gus_delay();
+
+ gus_write8(0x4c, 1); /* Release Reset */
+ gus_delay();
+ gus_delay();
+
+ /* See if there is first block there.... */
+ gus_poke(0L, 0xaa);
+ if (gus_peek(0L) != 0xaa)
+ return (0);
+
+ /* Now zero it out so that I can check for mirroring .. */
+ gus_poke(0L, 0x00);
+ for (i = 1L; i < 1024L; i++) {
+ int n, failed;
+
+ /* check for mirroring ... */
+ if (gus_peek(0L) != 0)
+ break;
+ loc = i << 10;
+
+ for (n = loc - 1, failed = 0; n <= loc; n++) {
+ gus_poke(loc, 0xaa);
+ if (gus_peek(loc) != 0xaa)
+ failed = 1;
+
+ gus_poke(loc, 0x55);
+ if (gus_peek(loc) != 0x55)
+ failed = 1;
+ }
+
+ if (failed)
+ break;
}
-
- if (failed)
- break;
- }
- gus_mem_size = i << 10;
- return 1;
+ gus_mem_size = i << 10;
+ return 1;
}
static int
-guswave_ioctl (int dev,
- unsigned int cmd, unsigned int arg)
+guswave_ioctl(int dev,
+ u_int cmd, ioctl_arg arg)
{
- switch (cmd)
- {
+ switch (cmd) {
case SNDCTL_SYNTH_INFO:
- gus_info.nr_voices = nr_voices;
- IOCTL_TO_USER ((char *) arg, 0, &gus_info, sizeof (gus_info));
- return 0;
- break;
+ gus_info.nr_voices = nr_voices;
+ bcopy(&gus_info, &(((char *) arg)[0]), sizeof(gus_info));
+ return 0;
+ break;
case SNDCTL_SEQ_RESETSAMPLES:
- reset_sample_memory ();
- return 0;
- break;
+ reset_sample_memory();
+ return 0;
+ break;
case SNDCTL_SEQ_PERCMODE:
- return 0;
- break;
+ return 0;
+ break;
case SNDCTL_SYNTH_MEMAVL:
- return gus_mem_size - free_mem_ptr - 32;
+ return gus_mem_size - free_mem_ptr - 32;
default:
- return RET_ERROR (EINVAL);
+ return -(EINVAL);
}
}
static int
-guswave_set_instr (int dev, int voice, int instr_no)
+guswave_set_instr(int dev, int voice, int instr_no)
{
- int sample_no;
-
- if (instr_no < 0 || instr_no > MAX_PATCH)
- return RET_ERROR (EINVAL);
-
- if (voice < 0 || voice > 31)
- return RET_ERROR (EINVAL);
-
- if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
- {
- voices[voice].sample_pending = instr_no;
- return 0;
- }
+ int sample_no;
- sample_no = patch_table[instr_no];
- patch_map[voice] = -1;
+ if (instr_no < 0 || instr_no > MAX_PATCH)
+ return -(EINVAL);
- if (sample_no < 0)
- {
- printk ("GUS: Undefined patch %d for voice %d\n", instr_no, voice);
- return RET_ERROR (EINVAL); /* Patch not defined */
- }
+ if (voice < 0 || voice > 31)
+ return -(EINVAL);
- if (sample_ptrs[sample_no] == -1) /* Sample not loaded */
- {
- printk ("GUS: Sample #%d not loaded for patch %d (voice %d)\n",
- sample_no, instr_no, voice);
- return RET_ERROR (EINVAL);
- }
+ if (voices[voice].volume_irq_mode == VMODE_START_NOTE) {
+ voices[voice].sample_pending = instr_no;
+ return 0;
+ }
+ sample_no = patch_table[instr_no];
+ patch_map[voice] = -1;
- sample_map[voice] = sample_no;
- patch_map[voice] = instr_no;
- return 0;
+ if (sample_no < 0) {
+ printf("GUS: Undefined patch %d for voice %d\n", instr_no, voice);
+ return -(EINVAL); /* Patch not defined */
+ }
+ if (sample_ptrs[sample_no] == -1) { /* Sample not loaded */
+ printf("GUS: Sample #%d not loaded for patch %d (voice %d)\n",
+ sample_no, instr_no, voice);
+ return -(EINVAL);
+ }
+ sample_map[voice] = sample_no;
+ patch_map[voice] = instr_no;
+ return 0;
}
static int
-guswave_kill_note (int dev, int voice, int note, int velocity)
+guswave_kill_note(int dev, int voice, int note, int velocity)
{
- 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;
- RESTORE_INTR (flags);
- }
- else
- {
- RESTORE_INTR (flags);
- gus_voice_fade (voice);
+ u_long flags;
+
+ flags = splhigh();
+ /* voice_alloc->map[voice] = 0xffff; */
+ if (voices[voice].volume_irq_mode == VMODE_START_NOTE) {
+ voices[voice].kill_pending = 1;
+ splx(flags);
+ } else {
+ splx(flags);
+ gus_voice_fade(voice);
}
- RESTORE_INTR (flags);
- return 0;
+ splx(flags);
+ return 0;
}
static void
-guswave_aftertouch (int dev, int voice, int pressure)
+guswave_aftertouch(int dev, int voice, int pressure)
{
-#if 0
- short lo_limit, hi_limit;
- unsigned long flags;
-
- if (voice < 0 || voice > 31)
- return;
-
- if (voices[voice].mode & WAVE_ENVELOPES && voices[voice].env_phase != 2)
- 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 */
- RESTORE_INTR (flags);
- return;
- }
-
- hi_limit = voices[voice].current_volume;
- lo_limit = hi_limit * 99 / 100;
- if (lo_limit < 65)
- lo_limit = 65;
-
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- if (hi_limit > (4095 - 65))
- {
- hi_limit = 4095 - 65;
- gus_voice_volume (hi_limit);
- }
- gus_ramp_range (lo_limit, hi_limit);
- gus_ramp_rate (3, 8);
- gus_rampon (0x58); /* Bidirectional, dow, loop */
- RESTORE_INTR (flags);
-#endif /* 0 */
}
static void
-guswave_panning (int dev, int voice, int value)
+guswave_panning(int dev, int voice, int value)
{
- if (voice >= 0 || voice < 32)
- voices[voice].panning = value;
+ if (voice >= 0 || voice < 32)
+ voices[voice].panning = value;
}
static void
-guswave_volume_method (int dev, int mode)
+guswave_volume_method(int dev, int mode)
{
- if (mode == VOL_METHOD_LINEAR || mode == VOL_METHOD_ADAGIO)
- volume_method = mode;
+ if (mode == VOL_METHOD_LINEAR || mode == VOL_METHOD_ADAGIO)
+ volume_method = mode;
}
-static void
-compute_volume (int voice, int volume)
+void
+compute_volume(int voice, int volume)
{
- if (volume < 128)
- voices[voice].midi_volume = volume;
+ if (volume < 128)
+ voices[voice].midi_volume = volume;
- switch (volume_method)
- {
+ switch (volume_method) {
case VOL_METHOD_ADAGIO:
- voices[voice].initial_volume =
- gus_adagio_vol (voices[voice].midi_volume, voices[voice].main_vol,
- voices[voice].expression_vol,
- voices[voice].patch_vol);
- break;
+ voices[voice].initial_volume =
+ gus_adagio_vol(voices[voice].midi_volume, voices[voice].main_vol,
+ voices[voice].expression_vol, voices[voice].patch_vol);
+ break;
- case VOL_METHOD_LINEAR: /* Totally ignores patch-volume and expression */
- voices[voice].initial_volume =
- gus_linear_vol (volume, voices[voice].main_vol);
- break;
+ case VOL_METHOD_LINEAR:/* Totally ignores patch-volume and expression */
+ voices[voice].initial_volume =
+ gus_linear_vol(volume, voices[voice].main_vol);
+ break;
default:
- voices[voice].initial_volume = volume_base +
- (voices[voice].midi_volume * volume_scale);
+ voices[voice].initial_volume = volume_base +
+ (voices[voice].midi_volume * volume_scale);
}
- if (voices[voice].initial_volume > 4030)
- voices[voice].initial_volume = 4030;
+ if (voices[voice].initial_volume > 4030)
+ voices[voice].initial_volume = 4030;
}
-static void
-compute_and_set_volume (int voice, int volume, int ramp_time)
+void
+compute_and_set_volume(int voice, int volume, int ramp_time)
{
- int current, target, rate;
- unsigned long flags;
+ int curr, target, rate;
+ u_long flags;
- compute_volume (voice, volume);
- voices[voice].current_volume = voices[voice].initial_volume;
+ compute_volume(voice, volume);
+ voices[voice].current_volume = voices[voice].initial_volume;
- DISABLE_INTR (flags);
- /*
+ flags = splhigh();
+ /*
* CAUTION! Interrupts disabled. Enable them before returning
- */
-
- gus_select_voice (voice);
-
- current = gus_read16 (0x09) >> 4;
- target = voices[voice].initial_volume;
+ */
- if (ramp_time == INSTANT_RAMP)
- {
- gus_rampoff ();
- gus_voice_volume (target);
- RESTORE_INTR (flags);
- return;
- }
+ gus_select_voice(voice);
- if (ramp_time == FAST_RAMP)
- rate = 63;
- else
- rate = 16;
- gus_ramp_rate (0, rate);
+ curr = gus_read16(0x09) >> 4;
+ target = voices[voice].initial_volume;
- if ((target - current) / 64 == 0) /* Close enough to target. */
- {
- gus_rampoff ();
- gus_voice_volume (target);
- RESTORE_INTR (flags);
- return;
+ if (ramp_time == INSTANT_RAMP) {
+ gus_rampoff();
+ gus_voice_volume(target);
+ splx(flags);
+ return;
}
-
- if (target > current)
- {
- if (target > (4095 - 65))
- target = 4095 - 65;
- gus_ramp_range (current, target);
- gus_rampon (0x00); /* Ramp up, once, no IRQ */
+ if (ramp_time == FAST_RAMP)
+ rate = 63;
+ else
+ rate = 16;
+ gus_ramp_rate(0, rate);
+
+ if ((target - curr) / 64 == 0) { /* Close enough to target. */
+ gus_rampoff();
+ gus_voice_volume(target);
+ splx(flags);
+ return;
}
- else
- {
- if (target < 65)
- target = 65;
-
- gus_ramp_range (target, current);
- gus_rampon (0x40); /* Ramp down, once, no irq */
+ if (target > curr) {
+ if (target > (4095 - 65))
+ target = 4095 - 65;
+ gus_ramp_range(curr, target);
+ gus_rampon(0x00); /* Ramp up, once, no IRQ */
+ } else {
+ if (target < 65)
+ target = 65;
+
+ gus_ramp_range(target, curr);
+ gus_rampon(0x40); /* Ramp down, once, no irq */
}
- RESTORE_INTR (flags);
+ splx(flags);
}
static void
-dynamic_volume_change (int voice)
+dynamic_volume_change(int voice)
{
- unsigned char status;
- unsigned long flags;
-
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- status = gus_read8 (0x00); /* Get voice status */
- RESTORE_INTR (flags);
+ u_char status;
+ u_long flags;
- if (status & 0x03)
- return; /* Voice was not running */
-
- if (!(voices[voice].mode & WAVE_ENVELOPES))
- {
- compute_and_set_volume (voice, voices[voice].midi_volume, 1);
- return;
- }
+ flags = splhigh();
+ gus_select_voice(voice);
+ status = gus_read8(0x00); /* Get voice status */
+ splx(flags);
- /*
- * Voice is running and has envelopes.
- */
+ if (status & 0x03)
+ return; /* Voice was not running */
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- status = gus_read8 (0x0d); /* Ramping status */
- RESTORE_INTR (flags);
+ if (!(voices[voice].mode & WAVE_ENVELOPES)) {
+ compute_and_set_volume(voice, voices[voice].midi_volume, 1);
+ return;
+ }
+ /*
+ * Voice is running and has envelopes.
+ */
- if (status & 0x03) /* Sustain phase? */
- {
- compute_and_set_volume (voice, voices[voice].midi_volume, 1);
- return;
- }
+ flags = splhigh();
+ gus_select_voice(voice);
+ status = gus_read8(0x0d); /* Ramping status */
+ splx(flags);
- if (voices[voice].env_phase < 0)
- return;
+ if (status & 0x03) { /* Sustain phase? */
+ compute_and_set_volume(voice, voices[voice].midi_volume, 1);
+ return;
+ }
+ if (voices[voice].env_phase < 0)
+ return;
- compute_volume (voice, voices[voice].midi_volume);
+ compute_volume(voice, voices[voice].midi_volume);
}
static void
-guswave_controller (int dev, int voice, int ctrl_num, int value)
+guswave_controller(int dev, int voice, int ctrl_num, int value)
{
- unsigned long flags;
- unsigned long freq;
-
- if (voice < 0 || voice > 31)
- return;
-
- switch (ctrl_num)
- {
- case CTRL_PITCH_BENDER:
- voices[voice].bender = value;
-
- if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
- {
- freq = compute_finetune (voices[voice].orig_freq, value,
- voices[voice].bender_range);
- voices[voice].current_freq = freq;
-
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_voice_freq (freq);
- RESTORE_INTR (flags);
- }
- break;
-
- case CTRL_PITCH_BENDER_RANGE:
- voices[voice].bender_range = value;
- break;
- case CTL_EXPRESSION:
- value /= 128;
- case CTRL_EXPRESSION:
- if (volume_method == VOL_METHOD_ADAGIO)
- {
- voices[voice].expression_vol = value;
- if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
- dynamic_volume_change (voice);
- }
- break;
-
- case CTL_PAN:
- voices[voice].panning = (value * 2) - 128;
- break;
-
- case CTL_MAIN_VOLUME:
- value = (value * 100) / 16383;
-
- case CTRL_MAIN_VOLUME:
- voices[voice].main_vol = value;
- if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
- dynamic_volume_change (voice);
- break;
-
- default:
- break;
- }
+ u_long flags;
+ u_long freq;
+
+ if (voice < 0 || voice > 31)
+ return;
+
+ switch (ctrl_num) {
+ case CTRL_PITCH_BENDER:
+ voices[voice].bender = value;
+
+ if (voices[voice].volume_irq_mode != VMODE_START_NOTE) {
+ freq = compute_finetune(voices[voice].orig_freq, value,
+ voices[voice].bender_range);
+ voices[voice].current_freq = freq;
+
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_voice_freq(freq);
+ splx(flags);
+ }
+ break;
+
+ case CTRL_PITCH_BENDER_RANGE:
+ voices[voice].bender_range = value;
+ break;
+ case CTL_EXPRESSION:
+ value /= 128;
+ case CTRL_EXPRESSION:
+ if (volume_method == VOL_METHOD_ADAGIO) {
+ voices[voice].expression_vol = value;
+ if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
+ dynamic_volume_change(voice);
+ }
+ break;
+
+ case CTL_PAN:
+ voices[voice].panning = (value * 2) - 128;
+ break;
+
+ case CTL_MAIN_VOLUME:
+ value = (value * 100) / 16383;
+
+ case CTRL_MAIN_VOLUME:
+ voices[voice].main_vol = value;
+ if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
+ dynamic_volume_change(voice);
+ break;
+
+ default:
+ break;
+ }
}
-static int
-guswave_start_note2 (int dev, int voice, int note_num, int volume)
+int
+guswave_start_note2(int dev, int voice, int note_num, int volume)
{
- int sample, best_sample, best_delta, delta_freq;
- int is16bits, samplep, patch, pan;
- unsigned long note_freq, base_note, freq, flags;
- unsigned char mode = 0;
-
- if (voice < 0 || voice > 31)
- {
- printk ("GUS: Invalid voice\n");
- return RET_ERROR (EINVAL);
+ int sample, best_sample, best_delta, delta_freq;
+ int is16bits, samplep, patch, pan;
+ u_long note_freq, base_note, freq, flags;
+ u_char mode = 0;
+
+ if (voice < 0 || voice > 31) {
+ printf("GUS: Invalid voice\n");
+ return -(EINVAL);
}
-
- if (note_num == 255)
- {
- if (voices[voice].mode & WAVE_ENVELOPES)
- {
- voices[voice].midi_volume = volume;
- dynamic_volume_change (voice);
- return 0;
+ if (note_num == 255) {
+ if (voices[voice].mode & WAVE_ENVELOPES) {
+ voices[voice].midi_volume = volume;
+ dynamic_volume_change(voice);
+ return 0;
}
-
- compute_and_set_volume (voice, volume, 1);
- return 0;
- }
-
- if ((patch = patch_map[voice]) == -1)
- {
- return RET_ERROR (EINVAL);
- }
-
- if ((samplep = patch_table[patch]) == -1)
- {
- return RET_ERROR (EINVAL);
+ compute_and_set_volume(voice, volume, 1);
+ return 0;
}
+ if ((patch = patch_map[voice]) == -1)
+ return -(EINVAL);
+ if ((samplep = patch_table[patch]) == -1)
+ return -(EINVAL);
+ note_freq = note_to_freq(note_num);
- note_freq = note_to_freq (note_num);
-
- /*
- * Find a sample within a patch so that the note_freq is between low_note
- * and high_note.
- */
- sample = -1;
-
- best_sample = samplep;
- best_delta = 1000000;
- while (samplep >= 0 && sample == -1)
- {
- delta_freq = note_freq - samples[samplep].base_note;
- if (delta_freq < 0)
- delta_freq = -delta_freq;
- if (delta_freq < best_delta)
- {
- best_sample = samplep;
- best_delta = delta_freq;
- }
- if (samples[samplep].low_note <= note_freq &&
- note_freq <= samples[samplep].high_note)
- sample = samplep;
- else
- samplep = samples[samplep].key; /*
- * Follow link
- */
+ /*
+ * Find a sample within a patch so that the note_freq is between
+ * low_note and high_note.
+ */
+ sample = -1;
+
+ best_sample = samplep;
+ best_delta = 1000000;
+ while (samplep >= 0 && sample == -1) {
+ dbg_samples = samples;
+ dbg_samplep = samplep;
+
+ delta_freq = note_freq - samples[samplep].base_note;
+ if (delta_freq < 0)
+ delta_freq = -delta_freq;
+ if (delta_freq < best_delta) {
+ best_sample = samplep;
+ best_delta = delta_freq;
+ }
+ if (samples[samplep].low_note <= note_freq &&
+ note_freq <= samples[samplep].high_note)
+ sample = samplep;
+ else
+ samplep = samples[samplep].key; /* Follow link */
}
- if (sample == -1)
- sample = best_sample;
+ if (sample == -1)
+ sample = best_sample;
- if (sample == -1)
- {
- printk ("GUS: Patch %d not defined for note %d\n", patch, note_num);
- return 0; /* Should play default patch ??? */
+ if (sample == -1) {
+ printf("GUS: Patch %d not defined for note %d\n", patch, note_num);
+ return 0; /* Should play default patch ??? */
}
+ is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0;
+ voices[voice].mode = samples[sample].mode;
+ voices[voice].patch_vol = samples[sample].volume;
- is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0;
- voices[voice].mode = samples[sample].mode;
- voices[voice].patch_vol = samples[sample].volume;
-
- if (voices[voice].mode & WAVE_ENVELOPES)
- {
- int i;
+ if (voices[voice].mode & WAVE_ENVELOPES) {
+ int i;
- for (i = 0; i < 6; i++)
- {
- voices[voice].env_rate[i] = samples[sample].env_rate[i];
- voices[voice].env_offset[i] = samples[sample].env_offset[i];
+ for (i = 0; i < 6; i++) {
+ voices[voice].env_rate[i] = samples[sample].env_rate[i];
+ voices[voice].env_offset[i] = samples[sample].env_offset[i];
}
}
+ sample_map[voice] = sample;
- sample_map[voice] = sample;
+ base_note = samples[sample].base_note / 100; /* Try to avoid overflows */
+ note_freq /= 100;
- base_note = samples[sample].base_note / 100; /* Try to avoid overflows */
- note_freq /= 100;
+ freq = samples[sample].base_freq * note_freq / base_note;
- freq = samples[sample].base_freq * note_freq / base_note;
+ voices[voice].orig_freq = freq;
- voices[voice].orig_freq = freq;
-
- /*
- * Since the pitch bender may have been set before playing the note, we
- * have to calculate the bending now.
- */
-
- 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;
- pan += 7;
- if (pan < 0)
- pan = 0;
- if (pan > 15)
- pan = 15;
+ /*
+ * Since the pitch bender may have been set before playing the note,
+ * we have to calculate the bending now.
+ */
- if (samples[sample].mode & WAVE_16_BITS)
- {
- mode |= 0x04; /* 16 bits */
- if ((sample_ptrs[sample] >> 18) !=
- ((sample_ptrs[sample] + samples[sample].len) >> 18))
- printk ("GUS: Sample address error\n");
+ 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;
+ pan += 7;
+ if (pan < 0)
+ pan = 0;
+ if (pan > 15)
+ pan = 15;
+
+ if (samples[sample].mode & WAVE_16_BITS) {
+ mode |= 0x04; /* 16 bits */
+ if ((sample_ptrs[sample] >> 18) !=
+ ((sample_ptrs[sample] + samples[sample].len) >> 18))
+ printf("GUS: Sample address error\n");
}
+ /*
+ * CAUTION! Interrupts disabled. Don't return before enabling
+ */
- /*************************************************************************
- * CAUTION! Interrupts disabled. Don't return before enabling
- *************************************************************************/
-
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_voice_off ();
- gus_rampoff ();
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_voice_off();
+ gus_rampoff();
- RESTORE_INTR (flags);
+ splx(flags);
- if (voices[voice].mode & WAVE_ENVELOPES)
- {
- compute_volume (voice, volume);
- init_envelope (voice);
+ if (voices[voice].mode & WAVE_ENVELOPES) {
+ compute_volume(voice, volume);
+ init_envelope(voice);
+ } else {
+ compute_and_set_volume(voice, volume, 0);
}
- else
- compute_and_set_volume (voice, volume, 0);
- DISABLE_INTR (flags);
- gus_select_voice (voice);
+ flags = splhigh();
+ gus_select_voice(voice);
- if (samples[sample].mode & WAVE_LOOP_BACK)
- gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].len -
- 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_LOOP_BACK)
+ gus_write_addr(0x0a, sample_ptrs[sample] + samples[sample].len -
+ 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;
+ if (samples[sample].mode & WAVE_LOOPING) {
+ mode |= 0x08;
- if (samples[sample].mode & WAVE_BIDIR_LOOP)
- mode |= 0x10;
+ if (samples[sample].mode & WAVE_BIDIR_LOOP)
+ mode |= 0x10;
- if (samples[sample].mode & WAVE_LOOP_BACK)
- {
- gus_write_addr (0x0a,
- sample_ptrs[sample] + samples[sample].loop_end -
- voices[voice].offset_pending, is16bits);
- mode |= 0x40;
+ if (samples[sample].mode & WAVE_LOOP_BACK) {
+ gus_write_addr(0x0a,
+ sample_ptrs[sample] + samples[sample].loop_end -
+ voices[voice].offset_pending, is16bits);
+ mode |= 0x40;
}
-
- gus_write_addr (0x02, sample_ptrs[sample] + samples[sample].loop_start,
- is16bits); /* Loop start location */
- gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end,
- is16bits); /* Loop end location */
- }
- else
- {
- 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] + 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 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_voice_freq (freq);
- gus_voice_balance (pan);
- gus_voice_on (mode);
- RESTORE_INTR (flags);
+ gus_voice_freq(freq);
+ gus_voice_balance(pan);
+ gus_voice_on(mode);
+ splx(flags);
- return 0;
+ return 0;
}
/*
* New guswave_start_note by Andrew J. Robinson attempts to minimize clicking
- * when the note playing on the voice is changed. It uses volume
- * ramping.
+ * 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)
+guswave_start_note(int dev, int voice, int note_num, int volume)
{
- long int flags;
- int mode;
- int ret_val = 0;
-
- DISABLE_INTR (flags);
- if (note_num == 255)
- {
- if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
- voices[voice].volume_pending = volume;
- else
- {
- ret_val = guswave_start_note2 (gus_devnum, voice, note_num, volume);
+ long int flags;
+ int mode;
+ int ret_val = 0;
+
+ flags = splhigh();
+ if (note_num == 255) {
+ if (voices[voice].volume_irq_mode == VMODE_START_NOTE) {
+ voices[voice].volume_pending = volume;
+ } else {
+ ret_val = guswave_start_note2(dev, voice, note_num, volume);
}
- }
- else
- {
- gus_select_voice (voice);
- mode = gus_read8 (0x00);
- if (mode & 0x20)
- gus_write8 (0x00, mode & 0xdf); /* No interrupt! */
-
- voices[voice].offset_pending = 0;
- voices[voice].kill_pending = 0;
- voices[voice].volume_irq_mode = 0;
- voices[voice].loop_irq_mode = 0;
-
- if (voices[voice].sample_pending >= 0)
- {
- RESTORE_INTR (flags); /* Run temporarily with interrupts enabled */
- guswave_set_instr (voices[voice].dev_pending, voice,
- voices[voice].sample_pending);
- voices[voice].sample_pending = -1;
- DISABLE_INTR (flags);
- gus_select_voice (voice); /* Reselect the voice (just to be sure) */
- }
-
- if ((mode & 0x01) || (int) ((gus_read16 (0x09) >> 4) < 2065))
- {
- ret_val = guswave_start_note2 (gus_devnum, voice, note_num, volume);
- }
- else
- {
- voices[voice].dev_pending = gus_devnum;
- voices[voice].note_pending = note_num;
- voices[voice].volume_pending = volume;
- voices[voice].volume_irq_mode = VMODE_START_NOTE;
-
- gus_rampoff ();
- gus_ramp_range (2000, 4065);
- gus_ramp_rate (0, 63); /* Fastest possible rate */
- gus_rampon (0x20 | 0x40); /* Ramp down, once, irq */
+ } else {
+ gus_select_voice(voice);
+ mode = gus_read8(0x00);
+ if (mode & 0x20)
+ gus_write8(0x00, mode & 0xdf); /* No interrupt! */
+
+ voices[voice].offset_pending = 0;
+ voices[voice].kill_pending = 0;
+ voices[voice].volume_irq_mode = 0;
+ voices[voice].loop_irq_mode = 0;
+
+ if (voices[voice].sample_pending >= 0) {
+ splx(flags); /* Run temporarily with interrupts
+ * enabled */
+ guswave_set_instr(voices[voice].dev_pending, voice,
+ voices[voice].sample_pending);
+ voices[voice].sample_pending = -1;
+ flags = splhigh();
+ gus_select_voice(voice); /* Reselect the voice
+ * (just to be sure) */
+ }
+ if ((mode & 0x01) || (int) ((gus_read16(0x09) >> 4) < 2065)) {
+ ret_val = guswave_start_note2(dev, voice, note_num, volume);
+ } else {
+ voices[voice].dev_pending = dev;
+ voices[voice].note_pending = note_num;
+ voices[voice].volume_pending = volume;
+ voices[voice].volume_irq_mode = VMODE_START_NOTE;
+
+ gus_rampoff();
+ gus_ramp_range(2000, 4065);
+ gus_ramp_rate(0, 63); /* Fastest possible rate */
+ gus_rampon(0x20 | 0x40); /* Ramp down, once, irq */
}
}
- RESTORE_INTR (flags);
- return ret_val;
+ splx(flags);
+ return ret_val;
}
static void
-guswave_reset (int dev)
+guswave_reset(int dev)
{
- int i;
+ int i;
- for (i = 0; i < 32; i++)
- {
- gus_voice_init (i);
- gus_voice_init2 (i);
+ for (i = 0; i < 32; i++) {
+ gus_voice_init(i);
+ gus_voice_init2(i);
}
}
static int
-guswave_open (int dev, int mode)
+guswave_open(int dev, int mode)
{
- int err;
+ int err;
+ int otherside = audio_devs[dev]->otherside;
- if (mode & OPEN_WRITE && gus_busy[gus_devnum] ||
- mode & OPEN_READ && gus_busy[gus_dspnum])
- return RET_ERROR (EBUSY);
+ if (otherside != -1) {
+ if (audio_devs[otherside]->busy)
+ return -(EBUSY);
+ }
+ if (audio_devs[dev]->busy)
+ return -(EBUSY);
- if(gus_busy[gus_devnum] == 0 && gus_busy[gus_dspnum] == 0)
- gus_initialize ();
- voice_alloc->timestamp = 0;
+ gus_initialize();
+ voice_alloc->timestamp = 0;
- if ((err = DMAbuf_open_dma (gus_devnum)) < 0)
- return err;
+ if ((err = DMAbuf_open_dma(gus_devnum)) < 0) {
+ printf("GUS: Loading saples without DMA\n");
+ gus_no_dma = 1; /* Upload samples using PIO */
+ } else
+ gus_no_dma = 0;
- RESET_WAIT_QUEUE (dram_sleeper, dram_sleep_flag);
- gus_busy[gus_devnum] = 1;
- active_device = GUS_DEV_WAVE;
+ dram_sleep_flag.aborting = 0;
+ dram_sleep_flag.mode = WK_NONE;
+ active_device = GUS_DEV_WAVE;
- gus_reset ();
+ audio_devs[dev]->busy = 1;
+ gus_reset();
- return 0;
+ return 0;
}
static void
-guswave_close (int dev)
+guswave_close(int dev)
{
- gus_busy[gus_devnum] = 0;
- active_device = 0;
- gus_reset ();
+ int otherside = audio_devs[dev]->otherside;
+
+ if (otherside != -1) {
+ if (audio_devs[otherside]->busy)
+ return;
+ }
+ audio_devs[dev]->busy = 0;
- DMAbuf_close_dma (gus_devnum);
+ active_device = 0;
+ gus_reset();
+
+ if (!gus_no_dma)
+ DMAbuf_close_dma(gus_devnum);
}
static int
-guswave_load_patch (int dev, int format, snd_rw_buf * addr,
- int offs, int count, int pmgr_flag)
+guswave_load_patch(int dev, int format, snd_rw_buf * addr,
+ int offs, int count, int pmgr_flag)
{
- struct patch_info patch;
- int instr;
- long sizeof_patch;
+ struct patch_info patch;
+ int instr;
+ long sizeof_patch;
- unsigned long blk_size, blk_end, left, src_offs, target;
+ u_long blk_size, blk_end, left, src_offs, target;
- sizeof_patch = (long) &patch.data[0] - (long) &patch; /* Header size */
+ sizeof_patch = (long) &patch.data[0] - (long) &patch; /* Header size */
- if (format != GUS_PATCH)
- {
- printk ("GUS Error: Invalid patch format (key) 0x%x\n", format);
- return RET_ERROR (EINVAL);
+ if (format != GUS_PATCH) {
+ printf("GUS Error: Invalid patch format (key) 0x%x\n", format);
+ return -(EINVAL);
}
-
- if (count < sizeof_patch)
- {
- printk ("GUS Error: Patch header too short\n");
- return RET_ERROR (EINVAL);
+ if (count < sizeof_patch) {
+ printf("GUS Error: Patch header too short\n");
+ return -(EINVAL);
}
+ count -= sizeof_patch;
- count -= sizeof_patch;
-
- if (free_sample >= MAX_SAMPLE)
- {
- printk ("GUS: Sample table full\n");
- return RET_ERROR (ENOSPC);
+ if (free_sample >= MAX_SAMPLE) {
+ printf("GUS: Sample table full\n");
+ return -(ENOSPC);
}
+ /*
+ * Copy the header from user space but ignore the first bytes which
+ * have been transferred already.
+ */
- /*
- * Copy the header from user space but ignore the first bytes which have
- * been transferred already.
- */
-
- COPY_FROM_USER (&((char *) &patch)[offs], addr, offs, sizeof_patch - offs);
+ if (uiomove(&((char *) &patch)[offs], sizeof_patch - offs, addr)) {
+ printf("audio: Bad copyin()!\n");
+ };
- instr = patch.instr_no;
+ instr = patch.instr_no;
- if (instr < 0 || instr > MAX_PATCH)
- {
- printk ("GUS: Invalid patch number %d\n", instr);
- return RET_ERROR (EINVAL);
+ if (instr < 0 || instr > MAX_PATCH) {
+ printf("GUS: Invalid patch number %d\n", instr);
+ return -(EINVAL);
}
-
- if (count < patch.len)
- {
- printk ("GUS Warning: Patch record too short (%d<%d)\n",
- count, (int) patch.len);
- patch.len = count;
+ if (count < patch.len) {
+ printf("GUS Warning: Patch record too short (%d<%d)\n",
+ count, (int) patch.len);
+ patch.len = count;
}
-
- if (patch.len <= 0 || patch.len > gus_mem_size)
- {
- printk ("GUS: Invalid sample length %d\n", (int) patch.len);
- return RET_ERROR (EINVAL);
+ if (patch.len <= 0 || patch.len > gus_mem_size) {
+ printf("GUS: Invalid sample length %d\n", (int) patch.len);
+ return -(EINVAL);
}
-
- if (patch.mode & WAVE_LOOPING)
- {
- if (patch.loop_start < 0 || patch.loop_start >= patch.len)
- {
- printk ("GUS: Invalid loop start\n");
- return RET_ERROR (EINVAL);
+ if (patch.mode & WAVE_LOOPING) {
+ if (patch.loop_start < 0 || patch.loop_start >= patch.len) {
+ printf("GUS: Invalid loop start\n");
+ return -(EINVAL);
}
-
- if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len)
- {
- printk ("GUS: Invalid loop end\n");
- return RET_ERROR (EINVAL);
+ if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len) {
+ printf("GUS: Invalid loop end\n");
+ return -(EINVAL);
}
}
-
- free_mem_ptr = (free_mem_ptr + 31) & ~31; /* 32 byte alignment */
+ free_mem_ptr = (free_mem_ptr + 31) & ~31; /* 32 byte alignment */
#define GUS_BANK_SIZE (256*1024)
- if (patch.mode & WAVE_16_BITS)
- {
- /*
- * 16 bit samples must fit one 256k bank.
- */
- if (patch.len >= GUS_BANK_SIZE)
- {
- printk ("GUS: Sample (16 bit) too long %d\n", (int) patch.len);
- return RET_ERROR (ENOSPC);
+ if (patch.mode & WAVE_16_BITS) {
+ /*
+ * 16 bit samples must fit one 256k bank.
+ */
+ if (patch.len >= GUS_BANK_SIZE) {
+ printf("GUS: Sample (16 bit) too long %d\n", (int) patch.len);
+ return -(ENOSPC);
}
+ if ((free_mem_ptr / GUS_BANK_SIZE) !=
+ ((free_mem_ptr + patch.len) / GUS_BANK_SIZE)) {
+ u_long tmp_mem = /* Aligning to 256K */
+ ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE;
- if ((free_mem_ptr / GUS_BANK_SIZE) !=
- ((free_mem_ptr + patch.len) / GUS_BANK_SIZE))
- {
- 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);
+ if ((tmp_mem + patch.len) > gus_mem_size)
+ return -(ENOSPC);
- free_mem_ptr = tmp_mem; /* This leaves unusable memory */
+ free_mem_ptr = tmp_mem; /* This leaves unusable memory */
}
}
+ if ((free_mem_ptr + patch.len) > gus_mem_size)
+ return -(ENOSPC);
- if ((free_mem_ptr + patch.len) > gus_mem_size)
- return RET_ERROR (ENOSPC);
-
- sample_ptrs[free_sample] = free_mem_ptr;
-
- /*
- * Tremolo is not possible with envelopes
- */
-
- if (patch.mode & WAVE_ENVELOPES)
- patch.mode &= ~WAVE_TREMOLO;
-
- memcpy ((char *) &samples[free_sample], &patch, sizeof_patch);
-
- /*
- * Link this_one sample to the list of samples for patch 'instr'.
- */
-
- samples[free_sample].key = patch_table[instr];
- patch_table[instr] = free_sample;
+ sample_ptrs[free_sample] = free_mem_ptr;
- /*
- * Use DMA to transfer the wave data to the DRAM
- */
-
- left = patch.len;
- src_offs = 0;
- target = free_mem_ptr;
+ /*
+ * Tremolo is not possible with envelopes
+ */
- while (left) /* Not completely transferred yet */
- {
- blk_size = audio_devs[gus_devnum]->buffsize;
- if (blk_size > left)
- blk_size = left;
+ if (patch.mode & WAVE_ENVELOPES)
+ patch.mode &= ~WAVE_TREMOLO;
- /*
- * DMA cannot cross 256k bank boundaries. Check for that.
- */
- blk_end = target + blk_size;
+ bcopy(&patch, (char *) &samples[free_sample], sizeof_patch);
- if ((target >> 18) != (blk_end >> 18))
- { /* Split the block */
+ /*
+ * Link this_one sample to the list of samples for patch 'instr'.
+ */
- blk_end &= ~(256 * 1024 - 1);
- blk_size = blk_end - target;
- }
+ samples[free_sample].key = patch_table[instr];
+ patch_table[instr] = free_sample;
-#if defined(GUS_NO_DMA) || defined(GUS_PATCH_NO_DMA)
- /*
- * For some reason the DMA is not possible. We have to use PIO.
- */
- {
- long i;
- unsigned char data;
+ /*
+ * Use DMA to transfer the wave data to the DRAM
+ */
- for (i = 0; i < blk_size; i++)
- {
- GET_BYTE_FROM_USER (data, addr, sizeof_patch + i);
- if (patch.mode & WAVE_UNSIGNED)
+ left = patch.len;
+ src_offs = 0;
+ target = free_mem_ptr;
- if (!(patch.mode & WAVE_16_BITS) || (i & 0x01))
- data ^= 0x80; /* Convert to signed */
- gus_poke (target + i, data);
- }
- }
-#else /* GUS_NO_DMA */
- {
- unsigned long address, hold_address;
- unsigned char dma_command;
- unsigned long flags;
+ while (left) { /* Not completely transferred yet */
+ /* blk_size = audio_devs[gus_devnum]->buffsize; */
+ blk_size = audio_devs[gus_devnum]->dmap_out->bytes_in_use;
+ if (blk_size > left)
+ blk_size = left;
/*
- * OK, move now. First in and then out.
+ * DMA cannot cross 256k bank boundaries. Check for that.
*/
+ blk_end = target + blk_size;
- COPY_FROM_USER (audio_devs[gus_devnum]->dmap->raw_buf[0],
- addr, sizeof_patch + src_offs,
- blk_size);
+ if ((target >> 18) != (blk_end >> 18)) { /* Split the block */
+ blk_end &= ~(256 * 1024 - 1);
+ blk_size = blk_end - target;
+ }
+ if (gus_no_dma) {
+ /*
+ * For some reason the DMA is not possible. We have
+ * to use PIO.
+ */
+ long i;
+ u_char data;
+
+ for (i = 0; i < blk_size; i++) {
+ uiomove((char *) &(data), 1, addr);
+ if (patch.mode & WAVE_UNSIGNED)
+ if (!(patch.mode & WAVE_16_BITS) || (i & 0x01))
+ data ^= 0x80; /* Convert to signed */
+ gus_poke(target + i, data);
+ }
+ } else {
+ u_long address, hold_address;
+ u_char dma_command;
+ u_long flags;
+
+ /*
+ * OK, move now. First in and then out.
+ */
+
+ if (uiomove(audio_devs[gus_devnum]->dmap_out->raw_buf, blk_size, addr)) {
+ printf("audio: Bad copyin()!\n");
+ };
+
+ flags = splhigh();
+ /******** INTERRUPTS DISABLED NOW ********/
+ gus_write8(0x41, 0); /* Disable GF1 DMA */
+ DMAbuf_start_dma(gus_devnum,
+ audio_devs[gus_devnum]->dmap_out->raw_buf_phys,
+ blk_size, 1);
+
+ /*
+ * Set the DRAM address for the wave data
+ */
+
+ address = target;
+
+ if (audio_devs[gus_devnum]->dmachan1 > 3) {
+ hold_address = address;
+ address = address >> 1;
+ address &= 0x0001ffffL;
+ address |= (hold_address & 0x000c0000L);
+ }
+ gus_write16(0x42, (address >> 4) & 0xffff); /* DRAM DMA address */
- DISABLE_INTR (flags);
-/******** INTERRUPTS DISABLED NOW ********/
- gus_write8 (0x41, 0); /* Disable GF1 DMA */
- DMAbuf_start_dma (gus_devnum,
- audio_devs[gus_devnum]->dmap->raw_buf_phys[0],
- blk_size, DMA_MODE_WRITE);
+ /*
+ * Start the DMA transfer
+ */
- /*
- * Set the DRAM address for the wave data
- */
+ dma_command = 0x21; /* IRQ enable, DMA start */
+ if (patch.mode & WAVE_UNSIGNED)
+ dma_command |= 0x80; /* Invert MSB */
+ if (patch.mode & WAVE_16_BITS)
+ dma_command |= 0x40; /* 16 bit _DATA_ */
+ if (audio_devs[gus_devnum]->dmachan1 > 3)
+ dma_command |= 0x04; /* 16 bit DMA _channel_ */
- address = target;
+ gus_write8(0x41, dma_command); /* Lets bo luteet (=bugs) */
- if (audio_devs[gus_devnum]->dmachan > 3)
- {
- hold_address = address;
- address = address >> 1;
- address &= 0x0001ffffL;
- address |= (hold_address & 0x000c0000L);
- }
+ /*
+ * Sleep here until the DRAM DMA done interrupt is
+ * served
+ */
+ active_device = GUS_DEV_WAVE;
- gus_write16 (0x42, (address >> 4) & 0xffff); /* DRAM DMA address */
- /*
- * Start the DMA transfer
- */
+ {
+ int chn;
- dma_command = 0x21; /* IRQ enable, DMA start */
- if (patch.mode & WAVE_UNSIGNED)
- dma_command |= 0x80; /* Invert MSB */
- if (patch.mode & WAVE_16_BITS)
- dma_command |= 0x40; /* 16 bit _DATA_ */
- if (audio_devs[gus_devnum]->dmachan > 3)
- dma_command |= 0x04; /* 16 bit DMA _channel_ */
+ dram_sleep_flag.mode = WK_SLEEP;
+ dram_sleeper = &chn;
+ DO_SLEEP(chn, dram_sleep_flag, hz);
- gus_write8 (0x41, dma_command); /* Lets bo luteet (=bugs) */
+ };
+ if ((dram_sleep_flag.mode & WK_TIMEOUT))
+ printf("GUS: DMA Transfer timed out\n");
+ splx(flags);
+ }
/*
- * Sleep here until the DRAM DMA done interrupt is served
+ * Now the next part
*/
- active_device = GUS_DEV_WAVE;
- DO_SLEEP (dram_sleeper, dram_sleep_flag, HZ);
- if (TIMED_OUT (dram_sleeper, dram_sleep_flag))
- printk ("GUS: DMA Transfer timed out\n");
- RESTORE_INTR (flags);
- }
-#endif /* GUS_NO_DMA */
+ left -= blk_size;
+ src_offs += blk_size;
+ target += blk_size;
- /*
- * Now the next part
- */
-
- left -= blk_size;
- src_offs += blk_size;
- target += blk_size;
-
- gus_write8 (0x41, 0); /* Stop DMA */
+ gus_write8(0x41, 0); /* Stop DMA */
}
- free_mem_ptr += patch.len;
+ free_mem_ptr += patch.len;
- if (!pmgr_flag)
- pmgr_inform (gus_devnum, PM_E_PATCH_LOADED, instr, free_sample, 0, 0);
- free_sample++;
- return 0;
+ if (!pmgr_flag)
+ pmgr_inform(dev, PM_E_PATCH_LOADED, instr, free_sample, 0, 0);
+ free_sample++;
+ return 0;
}
static void
-guswave_hw_control (int dev, unsigned char *event)
+guswave_hw_control(int dev, u_char *event)
{
- int voice, cmd;
- unsigned short p1, p2;
- unsigned long plong, flags;
-
- cmd = event[2];
- voice = event[3];
- p1 = *(unsigned short *) &event[4];
- p2 = *(unsigned short *) &event[6];
- plong = *(unsigned long *) &event[4];
-
- if ((voices[voice].volume_irq_mode == VMODE_START_NOTE) &&
- (cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS))
- do_volume_irq (voice);
-
- switch (cmd)
- {
-
- case _GUS_NUMVOICES:
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_select_max_voices (p1);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_VOICESAMPLE:
- guswave_set_instr (dev, voice, p1);
- break;
-
- case _GUS_VOICEON:
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- p1 &= ~0x20; /* Don't allow interrupts */
- gus_voice_on (p1);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_VOICEOFF:
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_voice_off ();
- RESTORE_INTR (flags);
- break;
-
- case _GUS_VOICEFADE:
- gus_voice_fade (voice);
- break;
-
- case _GUS_VOICEMODE:
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- p1 &= ~0x20; /* Don't allow interrupts */
- gus_voice_mode (p1);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_VOICEBALA:
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_voice_balance (p1);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_VOICEFREQ:
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_voice_freq (plong);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_VOICEVOL:
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_voice_volume (p1);
- RESTORE_INTR (flags);
- break;
-
- 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 */
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_ramp_range (p1, p2);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_RAMPRATE:
- if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* NJET-NJET */
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_ramp_rate (p1, p2);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_RAMPMODE:
- if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* NO-NO */
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- p1 &= ~0x20; /* Don't allow interrupts */
- gus_ramp_mode (p1);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_RAMPON:
- if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* EI-EI */
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- p1 &= ~0x20; /* Don't allow interrupts */
- gus_rampon (p1);
- RESTORE_INTR (flags);
- break;
-
- case _GUS_RAMPOFF:
- if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* NEJ-NEJ */
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_rampoff ();
- RESTORE_INTR (flags);
- break;
-
- case _GUS_VOLUME_SCALE:
- volume_base = p1;
- volume_scale = p2;
- break;
-
- case _GUS_VOICE_POS:
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_set_voice_pos (voice, plong);
- RESTORE_INTR (flags);
- break;
-
- default:;
- }
+ int voice, cmd;
+ u_short p1, p2;
+ u_long plong, flags;
+
+ cmd = event[2];
+ voice = event[3];
+ p1 = *(u_short *) &event[4];
+ p2 = *(u_short *) &event[6];
+ plong = *(u_long *) &event[4];
+
+ if ((voices[voice].volume_irq_mode == VMODE_START_NOTE) &&
+ (cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS))
+ do_volume_irq(voice);
+
+ switch (cmd) {
+
+ case _GUS_NUMVOICES:
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_select_max_voices(p1);
+ splx(flags);
+ break;
+
+ case _GUS_VOICESAMPLE:
+ guswave_set_instr(dev, voice, p1);
+ break;
+
+ case _GUS_VOICEON:
+ flags = splhigh();
+ gus_select_voice(voice);
+ p1 &= ~0x20; /* Don't allow interrupts */
+ gus_voice_on(p1);
+ splx(flags);
+ break;
+
+ case _GUS_VOICEOFF:
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_voice_off();
+ splx(flags);
+ break;
+
+ case _GUS_VOICEFADE:
+ gus_voice_fade(voice);
+ break;
+
+ case _GUS_VOICEMODE:
+ flags = splhigh();
+ gus_select_voice(voice);
+ p1 &= ~0x20; /* Don't allow interrupts */
+ gus_voice_mode(p1);
+ splx(flags);
+ break;
+
+ case _GUS_VOICEBALA:
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_voice_balance(p1);
+ splx(flags);
+ break;
+
+ case _GUS_VOICEFREQ:
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_voice_freq(plong);
+ splx(flags);
+ break;
+
+ case _GUS_VOICEVOL:
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_voice_volume(p1);
+ splx(flags);
+ break;
+
+ 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 */
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_ramp_range(p1, p2);
+ splx(flags);
+ break;
+
+ case _GUS_RAMPRATE:
+ if (voices[voice].mode & WAVE_ENVELOPES)
+ break; /* NJET-NJET */
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_ramp_rate(p1, p2);
+ splx(flags);
+ break;
+
+ case _GUS_RAMPMODE:
+ if (voices[voice].mode & WAVE_ENVELOPES)
+ break; /* NO-NO */
+ flags = splhigh();
+ gus_select_voice(voice);
+ p1 &= ~0x20; /* Don't allow interrupts */
+ gus_ramp_mode(p1);
+ splx(flags);
+ break;
+
+ case _GUS_RAMPON:
+ if (voices[voice].mode & WAVE_ENVELOPES)
+ break; /* EI-EI */
+ flags = splhigh();
+ gus_select_voice(voice);
+ p1 &= ~0x20; /* Don't allow interrupts */
+ gus_rampon(p1);
+ splx(flags);
+ break;
+
+ case _GUS_RAMPOFF:
+ if (voices[voice].mode & WAVE_ENVELOPES)
+ break; /* NEJ-NEJ */
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_rampoff();
+ splx(flags);
+ break;
+
+ case _GUS_VOLUME_SCALE:
+ volume_base = p1;
+ volume_scale = p2;
+ break;
+
+ case _GUS_VOICE_POS:
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_set_voice_pos(voice, plong);
+ splx(flags);
+ break;
+
+ default:;
+ }
}
static int
-gus_sampling_set_speed (int speed)
+gus_sampling_set_speed(int speed)
{
- if (speed <= 0)
- speed = gus_sampling_speed;
+ if (speed <= 0)
+ speed = gus_sampling_speed;
- if (speed < 4000)
- speed = 4000;
+ RANGE(speed, 4000, 44100);
+ gus_sampling_speed = speed;
- if (speed > 44100)
- speed = 44100;
+ if (only_read_access) {
+ /* Compute nearest valid recording speed and return it */
- gus_sampling_speed = speed;
-
- if (only_read_access)
- {
- /* Compute nearest valid recording speed and return it */
-
- speed = (9878400 / (gus_sampling_speed + 2)) / 16;
- speed = (9878400 / (speed * 16)) - 2;
- }
- return speed;
+ speed = (9878400 / (gus_sampling_speed + 2)) / 16;
+ speed = (9878400 / (speed * 16)) - 2;
+ }
+ return speed;
}
static int
-gus_sampling_set_channels (int channels)
+gus_sampling_set_channels(int channels)
{
- if (!channels)
- return gus_sampling_channels;
- if (channels > 2)
- channels = 2;
- if (channels < 1)
- channels = 1;
- gus_sampling_channels = channels;
- return channels;
+ if (!channels)
+ return gus_sampling_channels;
+ RANGE(channels, 1, 2);
+ gus_sampling_channels = channels;
+ return channels;
}
static int
-gus_sampling_set_bits (int bits)
+gus_sampling_set_bits(int bits)
{
- if (!bits)
- return gus_sampling_bits;
+ if (!bits)
+ return gus_sampling_bits;
+
+ if (bits != 8 && bits != 16)
+ bits = 8;
- if (bits != 8 && bits != 16)
- bits = 8;
+ if (only_8_bits)
+ bits = 8;
- gus_sampling_bits = bits;
- return bits;
+ gus_sampling_bits = bits;
+ return bits;
}
static int
-gus_sampling_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
+gus_sampling_ioctl(int dev, u_int cmd, ioctl_arg arg, int local)
{
- switch (cmd)
- {
- case SOUND_PCM_WRITE_RATE:
- if (local)
- return gus_sampling_set_speed (arg);
- return IOCTL_OUT (arg, gus_sampling_set_speed (IOCTL_IN (arg)));
- break;
-
- case SOUND_PCM_READ_RATE:
- if (local)
- return gus_sampling_speed;
- return IOCTL_OUT (arg, gus_sampling_speed);
- break;
-
- case SNDCTL_DSP_STEREO:
- if (local)
- return gus_sampling_set_channels (arg + 1) - 1;
- return IOCTL_OUT (arg, gus_sampling_set_channels (IOCTL_IN (arg) + 1) - 1);
- break;
-
- case SOUND_PCM_WRITE_CHANNELS:
- if (local)
- return gus_sampling_set_channels (arg);
- return IOCTL_OUT (arg, gus_sampling_set_channels (IOCTL_IN (arg)));
- break;
-
- case SOUND_PCM_READ_CHANNELS:
- if (local)
- return gus_sampling_channels;
- return IOCTL_OUT (arg, gus_sampling_channels);
- break;
-
- case SNDCTL_DSP_SETFMT:
- if (local)
- return gus_sampling_set_bits (arg);
- return IOCTL_OUT (arg, gus_sampling_set_bits (IOCTL_IN (arg)));
- break;
-
- case SOUND_PCM_READ_BITS:
- if (local)
- return gus_sampling_bits;
- return IOCTL_OUT (arg, gus_sampling_bits);
-
- case SOUND_PCM_WRITE_FILTER: /* NOT POSSIBLE */
- return IOCTL_OUT (arg, RET_ERROR (EINVAL));
- break;
-
- case SOUND_PCM_READ_FILTER:
- return IOCTL_OUT (arg, RET_ERROR (EINVAL));
- break;
+ switch (cmd) {
+ case SOUND_PCM_WRITE_RATE:
+ if (local)
+ return gus_sampling_set_speed((int) arg);
+ return *(int *) arg = gus_sampling_set_speed((*(int *) arg));
+ break;
+
+ case SOUND_PCM_READ_RATE:
+ if (local)
+ return gus_sampling_speed;
+ return *(int *) arg = gus_sampling_speed;
+ break;
+
+ case SNDCTL_DSP_STEREO:
+ if (local)
+ return gus_sampling_set_channels((int) arg + 1) - 1;
+ return *(int *) arg = gus_sampling_set_channels((*(int *) arg) + 1) - 1;
+ break;
+
+ case SOUND_PCM_WRITE_CHANNELS:
+ if (local)
+ return gus_sampling_set_channels((int) arg);
+ return *(int *) arg = gus_sampling_set_channels((*(int *) arg));
+ break;
+
+ case SOUND_PCM_READ_CHANNELS:
+ if (local)
+ return gus_sampling_channels;
+ return *(int *) arg = gus_sampling_channels;
+ break;
+
+ case SNDCTL_DSP_SETFMT:
+ if (local)
+ return gus_sampling_set_bits((int) arg);
+ return *(int *) arg = gus_sampling_set_bits((*(int *) arg));
+ break;
+
+ case SOUND_PCM_READ_BITS:
+ if (local)
+ return gus_sampling_bits;
+ return *(int *) arg = gus_sampling_bits;
+
+ case SOUND_PCM_WRITE_FILTER: /* NOT POSSIBLE */
+ return *(int *) arg = -(EINVAL);
+ break;
+
+ case SOUND_PCM_READ_FILTER:
+ return *(int *) arg = -(EINVAL);
+ break;
- }
- return RET_ERROR (EINVAL);
+ }
+ return -(EINVAL);
}
static void
-gus_sampling_reset (int dev)
+gus_sampling_reset(int dev)
{
+ if (recording_active) {
+ gus_write8(0x49, 0x00); /* Halt recording */
+ set_input_volumes();
+ }
}
static int
-gus_sampling_open (int dev, int mode)
+gus_sampling_open(int dev, int mode)
{
- int dev_flag;
- int init_flag;
-#ifdef GUS_NO_DMA
- printk ("GUS: DMA mode not enabled. Device not supported\n");
- return RET_ERROR (ENXIO);
-#endif
- dev_flag = 0;
- init_flag = (gus_busy[gus_devnum] == 0 && gus_busy[gus_dspnum] == 0);
- if(mode & OPEN_WRITE)
- {
- if (gus_busy[gus_devnum])
- return RET_ERROR(EBUSY);
- if(dev != gus_devnum)
- return RET_ERROR(ENXIO);
- dev_flag = gus_busy[gus_devnum] = 1;
- }
- if(mode & OPEN_READ)
- {
- if(gus_busy[gus_dspnum]) {
- if (dev_flag) gus_busy[gus_devnum] = 0;
- return RET_ERROR(EBUSY);
- }
-
- if(dev != gus_dspnum) {
- if (dev_flag) gus_busy[gus_devnum] = 0;
- return RET_ERROR(ENXIO);
- }
- }
-
- if(init_flag)
- {
- gus_initialize ();
- active_device = 0;
+ int otherside = audio_devs[dev]->otherside;
+ if (otherside != -1) {
+ if (audio_devs[otherside]->busy)
+ return -(EBUSY);
+ }
+ if (audio_devs[dev]->busy)
+ return -(EBUSY);
- gus_reset ();
- reset_sample_memory ();
- gus_select_max_voices (14);
- pcm_active = 0;
- dma_active = 0;
- pcm_opened = 1;
- }
- if (mode & OPEN_READ)
- {
- recording_active = 1;
- set_input_volumes ();
+ gus_initialize();
+
+ active_device = 0;
+
+ gus_reset();
+ reset_sample_memory();
+ gus_select_max_voices(14);
+
+ pcm_active = 0;
+ dma_active = 0;
+ pcm_opened = 1;
+ audio_devs[dev]->busy = 1;
+
+ if (mode & OPEN_READ) {
+ recording_active = 1;
+ set_input_volumes();
}
- only_read_access = !(mode & OPEN_WRITE);
+ only_read_access = !(mode & OPEN_WRITE);
+ only_8_bits = mode & OPEN_READ;
+ if (only_8_bits)
+ audio_devs[dev]->format_mask = AFMT_U8;
+ else
+ audio_devs[dev]->format_mask = AFMT_U8 | AFMT_S16_LE;
- return 0;
+ return 0;
}
static void
-gus_sampling_close (int dev)
+gus_sampling_close(int dev)
{
- gus_busy[dev] = 0;
- if (gus_busy[gus_devnum] == 0 && gus_busy[gus_dspnum] == 0) {
- active_device = 0;
- gus_reset();
- pcm_opened = 0;
- }
+ int otherside = audio_devs[dev]->otherside;
+ audio_devs[dev]->busy = 0;
- if (recording_active)
- set_input_volumes ();
+ if (otherside != -1) {
+ if (audio_devs[otherside]->busy)
+ return;
+ }
+ gus_reset();
+
+ pcm_opened = 0;
+ active_device = 0;
- recording_active = 0;
+ if (recording_active) {
+ gus_write8(0x49, 0x00); /* Halt recording */
+ set_input_volumes();
+ }
+ recording_active = 0;
}
static void
-gus_sampling_update_volume (void)
+gus_sampling_update_volume(void)
{
- unsigned long flags;
- int voice;
-
- if (pcm_active && pcm_opened)
- for (voice = 0; voice < gus_sampling_channels; voice++)
- {
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_rampoff ();
- gus_voice_volume (1530 + (25 * gus_pcm_volume));
- gus_ramp_range (65, 1530 + (25 * gus_pcm_volume));
- RESTORE_INTR (flags);
- }
+ u_long flags;
+ int voice;
+
+ if (pcm_active && pcm_opened)
+ for (voice = 0; voice < gus_sampling_channels; voice++) {
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_rampoff();
+ gus_voice_volume(1530 + (25 * gus_pcm_volume));
+ gus_ramp_range(65, 1530 + (25 * gus_pcm_volume));
+ splx(flags);
+ }
}
static void
-play_next_pcm_block (void)
+play_next_pcm_block(void)
{
- unsigned long flags;
- int speed = gus_sampling_speed;
- int this_one, is16bits, chn;
- unsigned long dram_loc;
- unsigned char mode[2], ramp_mode[2];
+ u_long flags;
+ int speed = gus_sampling_speed;
+ int this_one, is16bits, chn;
+ u_long dram_loc;
+ u_char mode[2], ramp_mode[2];
- if (!pcm_qlen)
- return;
+ if (!pcm_qlen)
+ return;
- this_one = pcm_head;
+ this_one = pcm_head;
- for (chn = 0; chn < gus_sampling_channels; chn++)
- {
- mode[chn] = 0x00;
- ramp_mode[chn] = 0x03; /* Ramping and rollover off */
-
- if (chn == 0)
- {
- 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 */
- }
- else
- is16bits = 0;
-
- dram_loc = this_one * pcm_bsize;
- dram_loc += chn * pcm_banksize;
-
- if (this_one == (pcm_nblk - 1)) /* Last fragment of the DRAM buffer */
- {
- mode[chn] |= 0x08; /* Enable loop */
- ramp_mode[chn] = 0x03; /* Disable rollover bit */
- }
- else
- {
- if (chn == 0)
- ramp_mode[chn] = 0x04; /* Enable rollover bit */
- }
-
- DISABLE_INTR (flags);
- gus_select_voice (chn);
- gus_voice_freq (speed);
-
- if (gus_sampling_channels == 1)
- gus_voice_balance (7); /* mono */
- else if (chn == 0)
- gus_voice_balance (0); /* left */
- else
- gus_voice_balance (15); /* right */
-
- if (!pcm_active) /* Playback not already active */
- {
- /*
- * The playback was not started yet (or there has been a pause).
- * Start the voice (again) and ask for a rollover irq at the end of
- * this_one block. If this_one one is last of the buffers, use just
- * the normal loop with irq.
- */
-
- gus_voice_off ();
- 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 */
-
- if (chn != 0)
- gus_write_addr (0x04, pcm_banksize + (pcm_bsize * pcm_nblk) - 1,
- is16bits); /* Loop end location */
- }
-
- if (chn == 0)
- gus_write_addr (0x04, dram_loc + pcm_datasize[this_one] - 1,
- is16bits); /* Loop end location */
- else
- mode[chn] |= 0x08; /* Enable looping */
-
- if (pcm_datasize[this_one] != pcm_bsize)
- {
- /*
- * Incompletely filled block. Possibly the last one.
- */
- if (chn == 0)
- {
- 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 */
- }
- else
- {
- gus_write_addr (0x04, dram_loc + pcm_datasize[this_one],
- is16bits); /* Loop end location */
- mode[chn] &= ~0x08; /* Disable looping */
- }
+ for (chn = 0; chn < gus_sampling_channels; chn++) {
+ mode[chn] = 0x00;
+ ramp_mode[chn] = 0x03; /* Ramping and rollover off */
+
+ if (chn == 0) {
+ 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 */
+ } else
+ is16bits = 0;
+
+ dram_loc = this_one * pcm_bsize;
+ dram_loc += chn * pcm_banksize;
+
+ if (this_one == (pcm_nblk - 1)) { /* Last fragment of the
+ * DRAM buffer */
+ mode[chn] |= 0x08; /* Enable loop */
+ ramp_mode[chn] = 0x03; /* Disable rollover bit */
+ } else {
+ if (chn == 0)
+ ramp_mode[chn] = 0x04; /* Enable rollover bit */
}
- RESTORE_INTR (flags);
+ flags = splhigh();
+ gus_select_voice(chn);
+ gus_voice_freq(speed);
+
+ if (gus_sampling_channels == 1)
+ gus_voice_balance(7); /* mono */
+ else if (chn == 0)
+ gus_voice_balance(0); /* left */
+ else
+ gus_voice_balance(15); /* right */
+
+ if (!pcm_active) { /* Playback not already active */
+ /*
+ * The playback was not started yet (or there has
+ * been a pause). Start the voice (again) and ask for
+ * a rollover irq at the end of this_one block. If
+ * this_one one is last of the buffers, use just the
+ * normal loop with irq.
+ */
+
+ gus_voice_off();
+ 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 */
+
+ if (chn != 0)
+ gus_write_addr(0x04, pcm_banksize + (pcm_bsize * pcm_nblk) - 1,
+ is16bits); /* Loop end location */
+ }
+ if (chn == 0)
+ gus_write_addr(0x04, dram_loc + pcm_datasize[this_one] - 1,
+ is16bits); /* Loop end location */
+ else
+ mode[chn] |= 0x08; /* Enable looping */
+
+ if (pcm_datasize[this_one] != pcm_bsize) {
+ /*
+ * Incompletely filled block. Possibly the last one.
+ */
+ if (chn == 0) {
+ 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 */
+ } else {
+ gus_write_addr(0x04, dram_loc + pcm_datasize[this_one],
+ is16bits); /* Loop end location */
+ mode[chn] &= ~0x08; /* Disable looping */
+ }
+ }
+ splx(flags);
}
- for (chn = 0; chn < gus_sampling_channels; chn++)
- {
- DISABLE_INTR (flags);
- gus_select_voice (chn);
- gus_write8 (0x0d, ramp_mode[chn]);
- gus_voice_on (mode[chn]);
- RESTORE_INTR (flags);
+ for (chn = 0; chn < gus_sampling_channels; chn++) {
+ flags = splhigh();
+ gus_select_voice(chn);
+ gus_write8(0x0d, ramp_mode[chn]);
+ gus_voice_on(mode[chn]);
+ splx(flags);
}
- pcm_active = 1;
+ pcm_active = 1;
}
static void
-gus_transfer_output_block (int dev, unsigned long buf,
- int total_count, int intrflag, int chn)
+gus_transfer_output_block(int dev, u_long buf,
+ int total_count, int intrflag, int chn)
{
- /*
- * This routine transfers one block of audio data to the DRAM. In mono mode
- * it's called just once. When in stereo mode, this_one routine is called
- * once for both channels.
- *
- * The left/mono channel data is transferred to the beginning of dram and the
- * right data to the area pointed by gus_page_size.
- */
-
- int this_one, count;
- unsigned long flags;
- unsigned char dma_command;
- unsigned long address, hold_address;
-
- DISABLE_INTR (flags);
-
- count = total_count / gus_sampling_channels;
-
- if (chn == 0)
- {
- if (pcm_qlen >= pcm_nblk)
- printk ("GUS Warning: PCM buffers out of sync\n");
+ /*
+ * This routine transfers one block of audio data to the DRAM. In
+ * mono mode it's called just once. When in stereo mode, this_one
+ * routine is called once for both channels.
+ *
+ * The left/mono channel data is transferred to the beginning of dram
+ * and the right data to the area pointed by gus_page_size.
+ */
- this_one = pcm_current_block = pcm_tail;
- pcm_qlen++;
- pcm_tail = (pcm_tail + 1) % pcm_nblk;
- pcm_datasize[this_one] = count;
- }
- else
- this_one = pcm_current_block;
+ int this_one, count;
+ u_long flags;
+ u_char dma_command;
+ u_long address, hold_address;
- gus_write8 (0x41, 0); /* Disable GF1 DMA */
- DMAbuf_start_dma (gus_devnum, buf + (chn * count), count, DMA_MODE_WRITE);
+ flags = splhigh();
- address = this_one * pcm_bsize;
- address += chn * pcm_banksize;
+ count = total_count / gus_sampling_channels;
- if (audio_devs[gus_devnum]->dmachan > 3)
- {
- hold_address = address;
- address = address >> 1;
- address &= 0x0001ffffL;
- address |= (hold_address & 0x000c0000L);
- }
+ if (chn == 0) {
+ if (pcm_qlen >= pcm_nblk)
+ printf("GUS Warning: PCM buffers out of sync\n");
- gus_write16 (0x42, (address >> 4) & 0xffff); /* DRAM DMA address */
+ this_one = pcm_current_block = pcm_tail;
+ pcm_qlen++;
+ pcm_tail = (pcm_tail + 1) % pcm_nblk;
+ pcm_datasize[this_one] = count;
+ } else
+ this_one = pcm_current_block;
- dma_command = 0x21; /* IRQ enable, DMA start */
+ gus_write8(0x41, 0); /* Disable GF1 DMA */
+ DMAbuf_start_dma(dev, buf + (chn * count), count, 1);
- if (gus_sampling_bits != 8)
- dma_command |= 0x40; /* 16 bit _DATA_ */
- else
- dma_command |= 0x80; /* Invert MSB */
+ address = this_one * pcm_bsize;
+ address += chn * pcm_banksize;
- if (audio_devs[gus_devnum]->dmachan > 3)
- dma_command |= 0x04; /* 16 bit DMA channel */
+ if (audio_devs[dev]->dmachan1 > 3) {
+ hold_address = address;
+ address = address >> 1;
+ address &= 0x0001ffffL;
+ address |= (hold_address & 0x000c0000L);
+ }
+ gus_write16(0x42, (address >> 4) & 0xffff); /* DRAM DMA address */
- gus_write8 (0x41, dma_command); /* Kickstart */
+ dma_command = 0x21; /* IRQ enable, DMA start */
- 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 > 0 || count < pcm_bsize))
- {
- play_next_pcm_block ();
+ if (gus_sampling_bits != 8)
+ dma_command |= 0x40; /* 16 bit _DATA_ */
+ else
+ dma_command |= 0x80; /* Invert MSB */
+
+ if (audio_devs[dev]->dmachan1 > 3)
+ dma_command |= 0x04; /* 16 bit DMA channel */
+
+ gus_write8(0x41, dma_command); /* Kickstart */
+
+ 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 > 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);
+ splx(flags);
}
static void
-gus_sampling_output_block (int dev, unsigned long buf, int total_count,
- int intrflag, int restart_dma)
+gus_sampling_output_block(int dev, u_long buf, int total_count,
+ int intrflag, int restart_dma)
{
- pcm_current_buf = buf;
- pcm_current_count = total_count;
- pcm_current_intrflag = intrflag;
- pcm_current_dev = gus_devnum;
- gus_transfer_output_block (gus_devnum, buf, total_count, intrflag, 0);
+ pcm_current_buf = buf;
+ pcm_current_count = total_count;
+ pcm_current_intrflag = intrflag;
+ pcm_current_dev = dev;
+ gus_transfer_output_block(dev, buf, total_count, intrflag, 0);
}
static void
-gus_sampling_start_input (int dev, unsigned long buf, int count,
- int intrflag, int restart_dma)
+gus_sampling_start_input(int dev, u_long buf, int count,
+ int intrflag, int restart_dma)
{
- unsigned long flags;
- unsigned char mode;
+ u_long flags;
+ u_char mode;
- DISABLE_INTR (flags);
+ flags = splhigh();
- DMAbuf_start_dma (gus_dspnum, buf, count, DMA_MODE_READ);
+ DMAbuf_start_dma(dev, buf, count, 0);
- mode = 0xa0; /* DMA IRQ enabled, invert MSB */
+ mode = 0xa0; /* DMA IRQ enabled, invert MSB */
- if (audio_devs[gus_dspnum]->dmachan > 3)
- mode |= 0x04; /* 16 bit DMA channel */
- if (gus_sampling_channels > 1)
- mode |= 0x02; /* Stereo */
- mode |= 0x01; /* DMA enable */
+ if (audio_devs[dev]->dmachan2 > 3)
+ mode |= 0x04; /* 16 bit DMA channel */
+ if (gus_sampling_channels > 1)
+ mode |= 0x02; /* Stereo */
+ mode |= 0x01; /* DMA enable */
- gus_write8 (0x49, mode);
+ gus_write8(0x49, mode);
- RESTORE_INTR (flags);
+ splx(flags);
}
static int
-gus_sampling_prepare_for_input (int dev, int bsize, int bcount)
+gus_sampling_prepare_for_input(int dev, int bsize, int bcount)
{
- unsigned int rate;
+ u_int rate;
- rate = (9878400 / (gus_sampling_speed + 2)) / 16;
+ rate = (9878400 / (gus_sampling_speed + 2)) / 16;
- gus_write8 (0x48, rate & 0xff); /* Set sampling rate */
+ gus_write8(0x48, rate & 0xff); /* Set sampling rate */
- if (gus_sampling_bits != 8)
- {
- printk ("GUS Error: 16 bit recording not supported\n");
- return RET_ERROR (EINVAL);
+ if (gus_sampling_bits != 8) {
+ printf("GUS Error: 16 bit recording not supported\n");
+ return -(EINVAL);
}
-
- return 0;
+ return 0;
}
static int
-gus_sampling_prepare_for_output (int dev, int bsize, int bcount)
+gus_sampling_prepare_for_output(int dev, int bsize, int bcount)
{
- int i;
+ int i;
- long mem_ptr, mem_size;
+ long mem_ptr, mem_size;
- mem_ptr = 0;
- mem_size = gus_mem_size / gus_sampling_channels;
+ mem_ptr = 0;
+ mem_size = gus_mem_size / gus_sampling_channels;
- if (mem_size > (256 * 1024))
- mem_size = 256 * 1024;
+ if (mem_size > (256 * 1024))
+ mem_size = 256 * 1024;
- pcm_bsize = bsize / gus_sampling_channels;
- pcm_head = pcm_tail = pcm_qlen = 0;
+ pcm_bsize = bsize / gus_sampling_channels;
+ pcm_head = pcm_tail = pcm_qlen = 0;
- pcm_nblk = MAX_PCM_BUFFERS;
- if ((pcm_bsize * pcm_nblk) > mem_size)
- pcm_nblk = mem_size / pcm_bsize;
+ pcm_nblk = MAX_PCM_BUFFERS;
+ if ((pcm_bsize * pcm_nblk) > mem_size)
+ pcm_nblk = mem_size / pcm_bsize;
- for (i = 0; i < pcm_nblk; i++)
- pcm_datasize[i] = 0;
+ for (i = 0; i < pcm_nblk; i++)
+ pcm_datasize[i] = 0;
- pcm_banksize = pcm_nblk * pcm_bsize;
+ pcm_banksize = pcm_nblk * pcm_bsize;
- if (gus_sampling_bits != 8 && pcm_banksize == (256 * 1024))
- pcm_nblk--;
+ if (gus_sampling_bits != 8 && pcm_banksize == (256 * 1024))
+ pcm_nblk--;
- return 0;
+ return 0;
}
static int
-gus_local_qlen (int dev)
+gus_local_qlen(int dev)
{
- return pcm_qlen;
+ return pcm_qlen;
}
static void
-gus_copy_from_user (int dev, char *localbuf, int localoffs,
- snd_rw_buf * userbuf, int useroffs, int len)
+gus_copy_from_user(int dev, char *localbuf, int localoffs,
+ snd_rw_buf * userbuf, int useroffs, int len)
{
- if (gus_sampling_channels == 1)
- {
- COPY_FROM_USER (&localbuf[localoffs], userbuf, useroffs, len);
- }
- else if (gus_sampling_bits == 8)
-#if defined(__FreeBSD__)
- {
- char *in_left = gus_copy_buf;
- char *in_right = in_left + 1;
- char *out_left = localbuf + (localoffs / 2);
- char *out_right = out_left + pcm_bsize;
- int i;
+ if (gus_sampling_channels == 1) {
+
+ if (uiomove(&localbuf[localoffs], len, userbuf)) {
+ printf("audio: Bad copyin()!\n");
+ };
+ } else if (gus_sampling_bits == 8) {
+ int in_left = useroffs;
+ int in_right = useroffs + 1;
+ char *out_left, *out_right;
+ int i;
+
+ len /= 2;
+ localoffs /= 2;
+ out_left = &localbuf[localoffs];
+ out_right = out_left + pcm_bsize;
+
+ for (i = 0; i < len; i++) {
+ uiomove((char *) &(*out_left++), 1, userbuf);
+ in_left += 2;
+ uiomove((char *) &(*out_right++), 1, userbuf);
+ in_right += 2;
+ }
+ } else {
+ int in_left = useroffs;
+ int in_right = useroffs + 2;
+ short *out_left, *out_right;
+ int i;
+
+ len /= 4;
+ localoffs /= 2;
+
+ out_left = (short *) &localbuf[localoffs];
+ out_right = out_left + (pcm_bsize / 2);
+
+ for (i = 0; i < len; i++) {
+ uiomove((char *) &(*out_left++), 2, userbuf);
+ in_left += 2;
+ uiomove((char *) &(*out_right++), 2, userbuf);
+ in_right += 2;
+ }
+ }
+}
- COPY_FROM_USER (gus_copy_buf, userbuf, useroffs, len);
+static struct audio_operations gus_sampling_operations =
+{
+ "Gravis UltraSound",
+ NEEDS_RESTART,
+ AFMT_U8 | AFMT_S16_LE,
+ NULL,
+ gus_sampling_open,
+ gus_sampling_close,
+ gus_sampling_output_block,
+ gus_sampling_start_input,
+ gus_sampling_ioctl,
+ gus_sampling_prepare_for_input,
+ gus_sampling_prepare_for_output,
+ gus_sampling_reset,
+ gus_sampling_reset,
+ gus_local_qlen,
+ gus_copy_from_user
+};
- len /= 2;
+static void
+guswave_setup_voice(int dev, int voice, int chn)
+{
+ struct channel_info *info =
+ &synth_devs[dev]->chn_info[chn];
+
+ guswave_set_instr(dev, voice, info->pgm_num);
+
+ voices[voice].expression_vol =
+ info->controllers[CTL_EXPRESSION]; /* Just msb */
+ voices[voice].main_vol =
+ (info->controllers[CTL_MAIN_VOLUME] * 100) / 128;
+ voices[voice].panning =
+ (info->controllers[CTL_PAN] * 2) - 128;
+ voices[voice].bender = info->bender_value;
+}
- for (i = 0; i < len; i++)
- {
- *out_left++ = *in_left++;
- in_left++;
- *out_right++ = *in_right++;
- in_right++;
- }
- }
- else
- {
- short *in_left = (short *)gus_copy_buf;
- short *in_right = in_left + 1;
- short *out_left = (short *)localbuf + (localoffs / 4);
- short *out_right = out_left + (pcm_bsize / 2);
- int i;
+static void
+guswave_bender(int dev, int voice, int value)
+{
+ int freq;
+ u_long flags;
+
+ voices[voice].bender = value - 8192;
+ freq = compute_finetune(voices[voice].orig_freq, value - 8192,
+ voices[voice].bender_range);
+ voices[voice].current_freq = freq;
+
+ flags = splhigh();
+ gus_select_voice(voice);
+ gus_voice_freq(freq);
+ splx(flags);
+}
+
+static int
+guswave_patchmgr(int dev, struct patmgr_info * rec)
+{
+ int i, n;
+
+ switch (rec->command) {
+ case PM_GET_DEVTYPE:
+ rec->parm1 = PMTYPE_WAVE;
+ return 0;
+ break;
+
+ case PM_GET_NRPGM:
+ rec->parm1 = MAX_PATCH;
+ return 0;
+ break;
+
+ case PM_GET_PGMMAP:
+ rec->parm1 = MAX_PATCH;
+
+ for (i = 0; i < MAX_PATCH; i++) {
+ int ptr = patch_table[i];
+
+ rec->data.data8[i] = 0;
+
+ while (ptr >= 0 && ptr < free_sample) {
+ rec->data.data8[i]++;
+ ptr = samples[ptr].key; /* Follow link */
+ }
+ }
+ return 0;
+ break;
+
+ case PM_GET_PGM_PATCHES:
+ {
+ int ptr = patch_table[rec->parm1];
+
+ n = 0;
+
+ while (ptr >= 0 && ptr < free_sample) {
+ rec->data.data32[n++] = ptr;
+ ptr = samples[ptr].key; /* Follow link */
+ }
+ }
+ rec->parm1 = n;
+ return 0;
+ break;
+
+ case PM_GET_PATCH:
+ {
+ int ptr = rec->parm1;
+ struct patch_info *pat;
+
+ if (ptr < 0 || ptr >= free_sample)
+ return -(EINVAL);
+
+ bcopy((char *) &samples[ptr], rec->data.data8, sizeof(struct patch_info));
+
+ pat = (struct patch_info *) rec->data.data8;
+
+ pat->key = GUS_PATCH; /* Restore patch type */
+ rec->parm1 = sample_ptrs[ptr]; /* DRAM location */
+ rec->parm2 = sizeof(struct patch_info);
+ }
+ return 0;
+ break;
+
+ case PM_SET_PATCH:
+ {
+ int ptr = rec->parm1;
+ struct patch_info *pat;
+
+ if (ptr < 0 || ptr >= free_sample)
+ return -(EINVAL);
+
+ pat = (struct patch_info *) rec->data.data8;
+
+ if (pat->len > samples[ptr].len) /* Cannot expand sample */
+ return -(EINVAL);
+
+ pat->key = samples[ptr].key; /* Ensure the link is
+ * correct */
- COPY_FROM_USER (gus_copy_buf, userbuf, useroffs, len);
+ bcopy(rec->data.data8, (char *) &samples[ptr], sizeof(struct patch_info));
- len /= 4;
+ pat->key = GUS_PATCH;
+ }
+ return 0;
+ break;
- for (i = 0; i < len; i++)
- {
- *out_left++ = *in_left++;
- in_left++;
- *out_right++ = *in_right++;
- in_right++;
+ case PM_READ_PATCH: /* Returns a block of wave data from the DRAM */
+ {
+ int sample = rec->parm1;
+ int n;
+ long offs = rec->parm2;
+ int l = rec->parm3;
+
+ if (sample < 0 || sample >= free_sample)
+ return -(EINVAL);
+
+ if (offs < 0 || offs >= samples[sample].len)
+ return -(EINVAL); /* Invalid offset */
+
+ n = samples[sample].len - offs; /* Num of bytes left */
+
+ if (l > n)
+ l = n;
+
+ if (l > sizeof(rec->data.data8))
+ l = sizeof(rec->data.data8);
+
+ if (l <= 0)
+ return -(EINVAL); /* Was there a bug? */
+
+ offs += sample_ptrs[sample]; /* Begin offsess +
+ * offset to DRAM */
+
+ for (n = 0; n < l; n++)
+ rec->data.data8[n] = gus_peek(offs++);
+ rec->parm1 = n; /* Nr of bytes copied */
+ }
+ return 0;
+ break;
+
+ case PM_WRITE_PATCH: /* Writes a block of wave data to the DRAM */
+ {
+ int sample = rec->parm1;
+ int n;
+ long offs = rec->parm2;
+ int l = rec->parm3;
+
+ if (sample < 0 || sample >= free_sample)
+ return -(EINVAL);
+
+ if (offs < 0 || offs >= samples[sample].len)
+ return -(EINVAL); /* Invalid offset */
+
+ n = samples[sample].len - offs; /* Nr of bytes left */
+
+ if (l > n)
+ l = n;
+
+ if (l > sizeof(rec->data.data8))
+ l = sizeof(rec->data.data8);
+
+ if (l <= 0)
+ return -(EINVAL); /* Was there a bug? */
+
+ offs += sample_ptrs[sample]; /* Begin offsess +
+ * offset to DRAM */
+
+ for (n = 0; n < l; n++)
+ gus_poke(offs++, rec->data.data8[n]);
+ rec->parm1 = n; /* Nr of bytes copied */
+ }
+ return 0;
+ break;
+
+ default:
+ return -(EINVAL);
}
- }
-#else
- {
- int in_left = useroffs;
- int in_right = useroffs + 1;
- char *out_left, *out_right;
- int i;
-
- len /= 2;
- localoffs /= 2;
- out_left = &localbuf[localoffs];
- out_right = out_left + pcm_bsize;
-
- for (i = 0; i < len; i++)
- {
- GET_BYTE_FROM_USER (*out_left++, userbuf, in_left);
- in_left += 2;
- GET_BYTE_FROM_USER (*out_right++, userbuf, in_right);
- in_right += 2;
+}
+
+static int
+guswave_alloc(int dev, int chn, int note, struct voice_alloc_info * alloc)
+{
+ int i, p, best = -1, best_time = 0x7fffffff;
+
+ 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;
+ }
+ if (alloc->alloc_times[p] < best_time) {
+ best = p;
+ best_time = alloc->alloc_times[p];
+ }
+ p = (p + 1) % alloc->max_voice;
}
- }
- else
- {
- int in_left = useroffs / 2;
- int in_right = useroffs / 2 + 1;
- short *out_left, *out_right;
- int i;
-
- len /= 4;
- localoffs /= 2;
-
- out_left = (short *) &localbuf[localoffs];
- out_right = out_left + (pcm_bsize / 2);
-
- for (i = 0; i < len; i++)
- {
-#ifdef __FreeBSD__
- GET_SHORT_FROM_USER (*out_left++, userbuf, in_left);
- in_left += 2;
- GET_SHORT_FROM_USER (*out_right++, userbuf, in_right);
- in_right += 2;
-#else
- GET_SHORT_FROM_USER (*out_left++, (short *) userbuf, in_left);
- in_left += 2;
- GET_SHORT_FROM_USER (*out_right++, (short *) userbuf, in_right);
- in_right += 2;
-#endif
+
+ /*
+ * 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;
}
- }
-#endif
+
+ if (best >= 0)
+ p = best;
+
+ alloc->ptr = p;
+ return p;
}
-static struct audio_operations gus_sampling_operations =
+static struct synth_operations guswave_operations =
{
- "Gravis UltraSound",
- NEEDS_RESTART,
- AFMT_U8 | AFMT_S16_LE,
- NULL,
- gus_sampling_open,
- gus_sampling_close,
- gus_sampling_output_block,
- gus_sampling_start_input,
- gus_sampling_ioctl,
- gus_sampling_prepare_for_input,
- gus_sampling_prepare_for_output,
- gus_sampling_reset,
- gus_sampling_reset,
- gus_local_qlen,
- gus_copy_from_user
-};
-
-static struct audio_operations gus_sampling_operations_read =
-{
- "Gravis UltraSound - read only",
- NEEDS_RESTART,
- AFMT_U8 | AFMT_S16_LE,
- NULL,
- gus_sampling_open,
- gus_sampling_close,
- gus_sampling_output_block,
- gus_sampling_start_input,
- gus_sampling_ioctl,
- gus_sampling_prepare_for_input,
- gus_sampling_prepare_for_output,
- gus_sampling_reset,
- gus_sampling_reset,
- gus_local_qlen,
- gus_copy_from_user
+ &gus_info,
+ 0,
+ SYNTH_TYPE_SAMPLE,
+ SAMPLE_TYPE_GUS,
+ guswave_open,
+ guswave_close,
+ guswave_ioctl,
+ guswave_kill_note,
+ guswave_start_note,
+ guswave_set_instr,
+ guswave_reset,
+ guswave_hw_control,
+ guswave_load_patch,
+ guswave_aftertouch,
+ guswave_controller,
+ guswave_panning,
+ guswave_volume_method,
+ guswave_patchmgr,
+ guswave_bender,
+ guswave_alloc,
+ guswave_setup_voice
};
static void
-guswave_setup_voice (int dev, int voice, int chn)
+set_input_volumes(void)
{
- struct channel_info *info =
- &synth_devs[gus_devnum]->chn_info[chn];
+ u_long flags;
+ u_char mask = 0xff & ~0x06; /* Just line out enabled */
+
+ if (have_gus_max) /* Don't disturb GUS MAX */
+ return;
- guswave_set_instr (gus_devnum, voice, info->pgm_num);
+ flags = splhigh();
- voices[voice].expression_vol =
- info->controllers[CTL_EXPRESSION]; /* Just msb */
- voices[voice].main_vol =
- (info->controllers[CTL_MAIN_VOLUME] * 100) / 128;
- voices[voice].panning =
- (info->controllers[CTL_PAN] * 2) - 128;
- voices[voice].bender = info->bender_value;
+ /*
+ * Enable channels having vol > 10% Note! bit 0x01 means the line in
+ * DISABLED while 0x04 means the mic in ENABLED.
+ */
+ if (gus_line_vol > 10)
+ mask &= ~0x01;
+ if (gus_mic_vol > 10)
+ mask |= 0x04;
+
+ if (recording_active) {
+ /*
+ * Disable channel, if not selected for recording
+ */
+ if (!(gus_recmask & SOUND_MASK_LINE))
+ mask |= 0x01;
+ if (!(gus_recmask & SOUND_MASK_MIC))
+ mask &= ~0x04;
+ }
+ mix_image &= ~0x07;
+ mix_image |= mask & 0x07;
+ outb(u_Mixer, mix_image);
+
+ splx(flags);
+}
+
+int
+gus_default_mixer_ioctl(int dev, u_int cmd, ioctl_arg arg)
+{
+
+#define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \
+ SOUND_MASK_SYNTH|SOUND_MASK_PCM)
+
+ if (((cmd >> 8) & 0xff) == 'M') {
+ if (cmd & IOC_IN)
+ switch (cmd & 0xff) {
+ case SOUND_MIXER_RECSRC:
+ gus_recmask = (*(int *) arg) & MIX_DEVS;
+ if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE)))
+ gus_recmask = SOUND_MASK_MIC;
+ /*
+ * Note! Input volumes are updated during
+ * next open for recording
+ */
+ return *(int *) arg = gus_recmask;
+ break;
+
+ case SOUND_MIXER_MIC:
+ {
+ int vol = (*(int *) arg) & 0xff;
+
+ if (vol < 0)
+ vol = 0;
+ if (vol > 100)
+ vol = 100;
+ gus_mic_vol = vol;
+ set_input_volumes();
+ return *(int *) arg = vol | (vol << 8);
+ }
+ break;
+
+ case SOUND_MIXER_LINE:
+ {
+ int vol = (*(int *) arg) & 0xff;
+
+ if (vol < 0)
+ vol = 0;
+ if (vol > 100)
+ vol = 100;
+ gus_line_vol = vol;
+ set_input_volumes();
+ return *(int *) arg = vol | (vol << 8);
+ }
+ break;
+
+ case SOUND_MIXER_PCM:
+ gus_pcm_volume = (*(int *) arg) & 0xff;
+ RANGE (gus_pcm_volume, 0, 100);
+ gus_sampling_update_volume();
+ return *(int *) arg = gus_pcm_volume | (gus_pcm_volume << 8);
+ break;
+
+ case SOUND_MIXER_SYNTH:
+ {
+ int voice;
+
+ gus_wave_volume = (*(int *) arg) & 0xff;
+
+ RANGE (gus_wave_volume , 0, 100);
+
+ if (active_device == GUS_DEV_WAVE)
+ for (voice = 0; voice < nr_voices; voice++)
+ dynamic_volume_change(voice); /* Apply the new vol */
+
+ return *(int *) arg = gus_wave_volume | (gus_wave_volume << 8);
+ }
+ break;
+
+ default:
+ return -(EINVAL);
+ }
+ else
+ switch (cmd & 0xff) { /* Return parameters */
+
+ case SOUND_MIXER_RECSRC:
+ return *(int *) arg = gus_recmask;
+ break;
+
+ case SOUND_MIXER_DEVMASK:
+ return *(int *) arg = MIX_DEVS;
+ break;
+
+ case SOUND_MIXER_STEREODEVS:
+ return *(int *) arg = 0;
+ break;
+
+ case SOUND_MIXER_RECMASK:
+ return *(int *) arg = SOUND_MASK_MIC | SOUND_MASK_LINE;
+ break;
+
+ case SOUND_MIXER_CAPS:
+ return *(int *) arg = 0;
+ break;
+
+ case SOUND_MIXER_MIC:
+ return *(int *) arg = gus_mic_vol | (gus_mic_vol << 8);
+ break;
+
+ case SOUND_MIXER_LINE:
+ return *(int *) arg = gus_line_vol | (gus_line_vol << 8);
+ break;
+
+ case SOUND_MIXER_PCM:
+ return *(int *) arg = gus_pcm_volume | (gus_pcm_volume << 8);
+ break;
+
+ case SOUND_MIXER_SYNTH:
+ return *(int *) arg = gus_wave_volume | (gus_wave_volume << 8);
+ break;
+
+ default:
+ return -(EINVAL);
+ }
+} else
+ return -(EINVAL);
}
+static struct mixer_operations gus_mixer_operations = {"Gravis Ultrasound", gus_default_mixer_ioctl};
+
static void
-guswave_bender (int dev, int voice, int value)
+gus_default_mixer_init()
{
- int freq;
- unsigned long flags;
+if (num_mixers < MAX_MIXER_DEV) /* Don't install if there is another
+ * mixer */
+ mixer_devs[num_mixers++] = &gus_mixer_operations;
- voices[voice].bender = value - 8192;
- freq = compute_finetune (voices[voice].orig_freq, value,
- voices[voice].bender_range);
- voices[voice].current_freq = freq;
+if (have_gus_max) {
+ /*
+ * Enable all mixer channels on the GF1 side. Otherwise
+ * recording will not be possible using GUS MAX.
+ */
+ mix_image &= ~0x07;
+ mix_image |= 0x04; /* All channels enabled */
+ outb(u_Mixer, mix_image);
+}
+}
+
+/* start of pnp code */
- DISABLE_INTR (flags);
- gus_select_voice (voice);
- gus_voice_freq (freq);
- RESTORE_INTR (flags);
+void
+SEND(int d, int r)
+{
+outb(PADDRESS, d);
+outb(PWRITE_DATA, r);
}
-static int
-guswave_patchmgr (int dev, struct patmgr_info *rec)
+
+
+
+/*
+ * Get the device's serial number. Returns 1 if the serial is valid.
+ */
+int
+get_serial(int rd_port, u_char *data)
{
- int i, n;
+ int i, bit, valid = 0, sum = 0x6a;
- switch (rec->command)
- {
- case PM_GET_DEVTYPE:
- rec->parm1 = PMTYPE_WAVE;
- return 0;
- break;
+ bzero(data, sizeof(char) * 9);
- case PM_GET_NRPGM:
- rec->parm1 = MAX_PATCH;
- return 0;
- break;
+ for (i = 0; i < 72; i++) {
+ bit = inb((rd_port << 2) | 0x3) == 0x55;
+ DELAY(250); /* Delay 250 usec */
- case PM_GET_PGMMAP:
- rec->parm1 = MAX_PATCH;
+ /* Can't Short Circuit the next evaluation, so 'and' is last */
+ bit = (inb((rd_port << 2) | 0x3) == 0xaa) && bit;
+ DELAY(250); /* Delay 250 usec */
- for (i = 0; i < MAX_PATCH; i++)
- {
- int ptr = patch_table[i];
+ valid = valid || bit;
- rec->data.data8[i] = 0;
+ if (i < 64)
+ sum = (sum >> 1) |
+ (((sum ^ (sum >> 1) ^ bit) << 7) & 0xff);
- while (ptr >= 0 && ptr < free_sample)
- {
- rec->data.data8[i]++;
- ptr = samples[ptr].key; /* Follow link */
- }
+ data[i / 8] = (data[i / 8] >> 1) | (bit ? 0x80 : 0);
}
- return 0;
- break;
+ valid = valid && (data[8] == sum);
+
+ return valid;
+}
- case PM_GET_PGM_PATCHES:
- {
- int ptr = patch_table[rec->parm1];
-
- n = 0;
-
- while (ptr >= 0 && ptr < free_sample)
- {
- rec->data.data32[n++] = ptr;
- ptr = samples[ptr].key; /* Follow link */
- }
- }
- rec->parm1 = n;
- return 0;
- break;
-
- case PM_GET_PATCH:
- {
- int ptr = rec->parm1;
- struct patch_info *pat;
-
- if (ptr < 0 || ptr >= free_sample)
- return RET_ERROR (EINVAL);
-
- memcpy (rec->data.data8, (char *) &samples[ptr],
- sizeof (struct patch_info));
+void
+send_Initiation_LFSR()
+{
+ int cur, i;
- pat = (struct patch_info *) rec->data.data8;
-
- pat->key = GUS_PATCH; /* Restore patch type */
- rec->parm1 = sample_ptrs[ptr]; /* DRAM location */
- rec->parm2 = sizeof (struct patch_info);
- }
- return 0;
- break;
-
- case PM_SET_PATCH:
- {
- int ptr = rec->parm1;
- struct patch_info *pat;
-
- if (ptr < 0 || ptr >= free_sample)
- return RET_ERROR (EINVAL);
-
- pat = (struct patch_info *) rec->data.data8;
-
- if (pat->len > samples[ptr].len) /* Cannot expand sample */
- return RET_ERROR (EINVAL);
-
- pat->key = samples[ptr].key; /* Ensure the link is correct */
-
- memcpy ((char *) &samples[ptr], rec->data.data8,
- sizeof (struct patch_info));
-
- pat->key = GUS_PATCH;
- }
- return 0;
- break;
-
- case PM_READ_PATCH: /* Returns a block of wave data from the DRAM */
- {
- int sample = rec->parm1;
- int n;
- long offs = rec->parm2;
- int l = rec->parm3;
-
- if (sample < 0 || sample >= free_sample)
- return RET_ERROR (EINVAL);
-
- if (offs < 0 || offs >= samples[sample].len)
- return RET_ERROR (EINVAL); /* Invalid offset */
-
- n = samples[sample].len - offs; /* Num of bytes left */
-
- if (l > n)
- l = n;
-
- if (l > sizeof (rec->data.data8))
- l = sizeof (rec->data.data8);
-
- if (l <= 0)
- return RET_ERROR (EINVAL); /*
- * Was there a bug?
- */
-
- offs += sample_ptrs[sample]; /*
- * Begin offsess + offset to DRAM
- */
-
- for (n = 0; n < l; n++)
- rec->data.data8[n] = gus_peek (offs++);
- rec->parm1 = n; /*
- * Nr of bytes copied
- */
- }
- return 0;
- break;
-
- case PM_WRITE_PATCH: /*
- * Writes a block of wave data to the DRAM
- */
- {
- int sample = rec->parm1;
- int n;
- long offs = rec->parm2;
- int l = rec->parm3;
-
- if (sample < 0 || sample >= free_sample)
- return RET_ERROR (EINVAL);
-
- if (offs < 0 || offs >= samples[sample].len)
- return RET_ERROR (EINVAL); /*
- * Invalid offset
- */
-
- n = samples[sample].len - offs; /*
- * Nr of bytes left
- */
-
- if (l > n)
- l = n;
-
- if (l > sizeof (rec->data.data8))
- l = sizeof (rec->data.data8);
-
- if (l <= 0)
- return RET_ERROR (EINVAL); /*
- * Was there a bug?
- */
-
- offs += sample_ptrs[sample]; /*
- * Begin offsess + offset to DRAM
- */
-
- for (n = 0; n < l; n++)
- gus_poke (offs++, rec->data.data8[n]);
- rec->parm1 = n; /*
- * Nr of bytes copied
- */
- }
- return 0;
- break;
+ /* Reset the LSFR */
+ outb(PADDRESS, 0);
+ outb(PADDRESS, 0);
- default:
- return RET_ERROR (EINVAL);
- }
+ cur = 0x6a;
+ outb(PADDRESS, cur);
+
+ for (i = 1; i < 32; i++) {
+ cur = (cur >> 1) | (((cur ^ (cur >> 1)) << 7) & 0xff);
+ outb(PADDRESS, cur);
+ }
}
-static int
-guswave_alloc (int dev, int chn, int note, struct voice_alloc_info *alloc)
+
+
+int
+isolation_protocol(int rd_port)
{
- int i, p, best = -1, best_time = 0x7fffffff;
+ int csn;
+ u_char data[9];
- p = alloc->ptr;
- /*
- * First look for a completely stopped voice
- */
+ send_Initiation_LFSR();
- for (i = 0; i < alloc->max_voice; i++)
- {
- if (alloc->map[p] == 0)
- {
- alloc->ptr = p;
- return p;
- }
- if (alloc->alloc_times[p] < best_time)
- {
- best = p;
- best_time = alloc->alloc_times[p];
+ /* Reset CSN for All Cards */
+ SEND(0x02, 0x04);
+
+ for (csn = 1; (csn < MAX_CARDS); csn++) {
+ /* Wake up cards without a CSN */
+
+ SEND(WAKE, 0);
+ SEND(SET_RD_DATA, rd_port);
+ outb(PADDRESS, SERIAL_ISOLATION);
+ DELAY(1000); /* Delay 1 msec */
+ if (get_serial(rd_port, data)) {
+ printf("Board Vendor ID: %c%c%c%02x%02x",
+ ((data[0] & 0x7c) >> 2) + 64,
+ (((data[0] & 0x03) << 3) | ((data[1] & 0xe0) >> 5)) + 64,
+ (data[1] & 0x1f) + 64, data[2], data[3]);
+ printf(" Board Serial Number: %08x\n", *(int *) &(data[4]));
+
+ SEND(SET_CSN, csn); /* Move this out of this
+ * function XXX */
+ outb(PADDRESS, PSTATUS);
+
+
+ return rd_port;
+ } else
+ break;
}
- p = (p + 1) % alloc->max_voice;
- }
- /*
- * Then look for a releasing voice
- */
+ return 0;
+}
+
- for (i = 0; i < alloc->max_voice; i++)
- {
- if (alloc->map[p] == 0xffff)
- {
- alloc->ptr = p;
- return p;
+
+void
+IwaveDelay(WORD count)
+{
+ WORD cur_cnt = 0, last_cnt;
+ BYTE reg, portb;
+
+ count = 1193 * count; /* convert number of ms to counter */
+ last_cnt = count;
+ portb = inb(0x61) & 0xFC;
+ outb(0x61, portb); /* disable counter */
+ outb(0x43, 0xB0); /* load LSB first then MSB */
+ outb(0x42, (BYTE) count);
+ outb(0x42, (BYTE) (count >> 8));
+ outb(0x61, (BYTE) (portb | 0x01)); /* enable counter */
+ while (cur_cnt <= count) {
+ outb(0x43, 0x80); /* latch counter */
+ reg = inb(0x42);/* read latched value */
+ cur_cnt = (((WORD) inb(0x42)) << 8) | reg;
+ if (cur_cnt > last_cnt)
+ break;
+ last_cnt = cur_cnt;
}
- p = (p + 1) % alloc->max_voice;
- }
+ outb(0x61, portb); /* disable counter */
+}
- if (best >= 0)
- p = best;
+/*
+ * ########################################################################
+ *
+ * FUNCTION: IwaveStopDma
+ *
+ * PROFILE: This function stops an active DMA transfer to or from the record or
+ * playback FIFOs. Set the "path" variable to either PLAYBACK or RECORD.
+ * ########################################################################
+ */
+
+void
+IwaveStopDma(BYTE path)
+{
+ BYTE reg;
- alloc->ptr = p;
- return p;
+ ENTER_CRITICAL;
+ reg = inb(iw.pcodar) & 0xE0;
+ outb(iw.pcodar, reg | _CFIG1I); /* select CFIG1I */
+ outb(iw.cdatap, (BYTE) (inb(iw.cdatap) & ~path)); /* disable playback path */
+ LEAVE_CRITICAL;
}
-static struct synth_operations guswave_operations =
+/*
+ * ########################################################################
+ *
+ * FUNCTION : IwaveInputSource
+ *
+ * PROFILE: This function allows the calling program to select among any of
+ * several possible sources to the ADC's. The possible input sources and
+ * their corresponding symbolic constants are: - Line (LINE_IN) - Aux1
+ * (AUX1_IN) - Microphone (MIC_IN) - Mixer (MIX_IN)
+ *
+ * Set the first argument to either LEFT_SOURCE or RIGHT_SOURCE. Always use the
+ * symbolic contants for the arguments.
+ *
+ * ########################################################################
+ */
+void
+IwaveInputSource(BYTE index, BYTE source)
{
- &gus_info,
- 0,
- SYNTH_TYPE_SAMPLE,
- SAMPLE_TYPE_GUS,
- guswave_open,
- guswave_close,
- guswave_ioctl,
- guswave_kill_note,
- guswave_start_note,
- guswave_set_instr,
- guswave_reset,
- guswave_hw_control,
- guswave_load_patch,
- guswave_aftertouch,
- guswave_controller,
- guswave_panning,
- guswave_volume_method,
- guswave_patchmgr,
- guswave_bender,
- guswave_alloc,
- guswave_setup_voice
-};
+ BYTE reg;
+
+ ENTER_CRITICAL;
+ reg = inb(iw.pcodar) & 0xE0;
+ outb(iw.pcodar, reg | index); /* select register CLICI or CRICI */
+ reg = inb(iw.cdatap) & ~MIX_IN;
+ source &= MIX_IN;
+ outb(iw.cdatap, (BYTE) (reg | source));
+ LEAVE_CRITICAL;
+}
+void
+IwavePnpGetCfg(void)
+{
+ WORD val;
+
+
+ ENTER_CRITICAL;
+ IwavePnpDevice(AUDIO);
+ outb(_PIDXR, 0x60); /* select P2X0HI */
+ val = ((WORD) inb(iw.pnprdp)) << 8; /* get P2XR[9:8] */
+ outb(_PIDXR, 0x61); /* select P2XRLI */
+ iw.p2xr = val + (WORD) inb(iw.pnprdp); /* get P2XR[7:4] */
+
+ outb(_PIDXR, 0x62); /* select P3X0HI */
+ val = ((WORD) inb(iw.pnprdp)) << 8; /* get P3XR[9:8] */
+ outb(_PIDXR, 0x63); /* select P3X0LI */
+ iw.p3xr = val + (WORD) inb(iw.pnprdp); /* get P3XR[7:3] */
+
+ outb(_PIDXR, 0x64); /* select PHCAI */
+ val = ((WORD) inb(iw.pnprdp)) << 8; /* get PCODAR[9:8] */
+ outb(_PIDXR, 0x65); /* select PLCAI */
+ iw.pcodar = val + (WORD) inb(iw.pnprdp); /* get PCODAR[7:2] */
+
+ outb(_PIDXR, 0x70); /* select PUI1SI */
+ iw.synth_irq = (WORD) (inb(iw.pnprdp) & 0x0F); /* Synth IRQ number */
+
+ outb(_PIDXR, 0x72); /* select PUI2SI */
+ iw.midi_irq = (WORD) (inb(iw.pnprdp) & 0x0F); /* MIDI IRQ number */
+
+ outb(_PIDXR, 0x74); /* select PUD1SI */
+ iw.dma1_chan = inb(iw.pnprdp) & 0x07; /* DMA1 chan (LMC/Codec Rec) */
+
+ outb(_PIDXR, 0x75); /* select PUD2SI */
+ iw.dma2_chan = inb(iw.pnprdp) & 0x07; /* DMA2 chan (codec play) */
+
+
+ IwavePnpDevice(EXT); /* select external device */
+ outb(_PIDXR, 0x60); /* select PRAHI */
+ val = ((WORD) inb(iw.pnprdp)) << 8; /* get PCDRAR[9:8] */
+ outb(_PIDXR, 0x61); /* select PRALI */
+ iw.pcdrar = val + (WORD) inb(iw.pnprdp); /* get PCDRAR[7:4] */
+ outb(_PIDXR, 0x62); /* select PATAHI */
+ val = ((WORD) inb(iw.pnprdp)) << 8; /* get PATAAR[9:8] */
+ outb(_PIDXR, 0x63); /* select PATALI */
+ iw.pataar = val + (WORD) inb(iw.pnprdp); /* get PATAAR[7:1] */
+
+ outb(_PIDXR, 0x70); /* select PRISI */
+ iw.ext_irq = (WORD) (inb(iw.pnprdp) & 0x0F); /* Ext Dev IRQ number */
+
+ outb(_PIDXR, 0x74); /* select PRDSI */
+ iw.ext_chan = inb(iw.pnprdp) & 0x07; /* Ext Dev DMA channel */
+
+ IwavePnpDevice(MPU401); /* Select MPU401 Device */
+ outb(_PIDXR, 0x60); /* select P401HI */
+ val = ((WORD) inb(iw.pnprdp)) << 8; /* get P401AR[9:8] */
+ outb(_PIDXR, 0x61); /* select P401LI */
+ iw.p401ar = val + (WORD) inb(iw.pnprdp); /* get P401AR[7:1] */
+
+ outb(_PIDXR, 0x70); /* select PMISI */
+ iw.mpu_irq = (WORD) (inb(iw.pnprdp) & 0x0F); /* MPU401 Dev IRQ number */
+
+ IwavePnpDevice(GAME); /* Select GAME logical Device */
+ outb(_PIDXR, 0x60); /* select P201HI */
+ val = ((WORD) inb(iw.pnprdp)) << 8; /* get P201AR[9:8] */
+ outb(_PIDXR, 0x61); /* select P201LI */
+ iw.p201ar = val + (WORD) inb(iw.pnprdp); /* get P201AR[7:6] */
+
+ IwavePnpDevice(EMULATION); /* Select SB and ADLIB Device */
+ outb(_PIDXR, 0x60); /* select P388HI */
+ val = ((WORD) inb(iw.pnprdp)) << 8; /* get P388AR[9:8] */
+ outb(_PIDXR, 0x61); /* select P388LI */
+ iw.p388ar = val + inb(iw.pnprdp); /* get P388AR[7:6] */
+ outb(_PIDXR, 0x70); /* select PSBISI */
+ iw.emul_irq = (WORD) (inb(iw.pnprdp) & 0x0F); /* emulation Dev IRQ
+ * number */
+ LEAVE_CRITICAL;
+}
-static void
-set_input_volumes (void)
+void
+IwavePnpSetCfg(void)
{
- unsigned long flags;
- unsigned char mask = 0xff & ~0x06; /* Just line out enabled */
+ ENTER_CRITICAL;
+ IwavePnpDevice(AUDIO); /* select audio device */
+ outb(_PIDXR, 0x60); /* select P2X0HI */
+ outb(_PNPWRP, (BYTE) (iw.p2xr >> 8)); /* set P2XR[9:8] */
+ outb(_PIDXR, 0x61); /* select P2X0LI */
+ outb(_PNPWRP, (BYTE) iw.p2xr); /* set P2XR[7:4] */
+ /* P2XR[3:0]=0 */
+ outb(_PIDXR, 0x62); /* select P3X0HI */
+ outb(_PNPWRP, (BYTE) (iw.p3xr >> 8)); /* set P3XR[9:8] */
+ outb(_PIDXR, 0x63); /* select P3X0LI */
+ outb(_PNPWRP, (BYTE) (iw.p3xr)); /* set P3XR[7:3] */
+ /* P3XR[2:0]=0 */
+ outb(_PIDXR, 0x64); /* select PHCAI */
+ outb(_PNPWRP, (BYTE) (iw.pcodar >> 8)); /* set PCODAR[9:8] */
+ outb(_PIDXR, 0x65); /* select PLCAI */
+ outb(_PNPWRP, (BYTE) iw.pcodar); /* set PCODAR[7:2] */
+
+ outb(_PIDXR, 0x70); /* select PUI1SI */
+ outb(_PNPWRP, (BYTE) (iw.synth_irq & 0x0F)); /* Synth IRQ number */
+ outb(_PIDXR, 0x72); /* select PUI2SI */
+ outb(_PNPWRP, (BYTE) (iw.midi_irq & 0x0F)); /* MIDI IRQ number */
+
+ outb(_PIDXR, 0x74); /* select PUD1SI */
+ outb(_PNPWRP, (BYTE) (iw.dma1_chan & 0x07)); /* DMA channel 1 */
+ outb(_PIDXR, 0x75); /* select PUD2SI */
+ outb(_PNPWRP, (BYTE) (iw.dma2_chan & 0x07)); /* DMA channel 2 */
+
+ IwavePnpDevice(EXT);
+ outb(_PIDXR, 0x60); /* select PRAHI */
+ outb(_PNPWRP, (BYTE) (iw.pcdrar >> 8)); /* set PCDRAR[9:8] */
+ outb(_PIDXR, 0x61); /* select PRALI */
+ outb(_PNPWRP, (BYTE) iw.pcdrar); /* set PCDRAR[7:3] */
+ /* PCDRAR[2:0]=0 */
+ outb(_PIDXR, 0x62); /* select PATAHI */
+ outb(_PNPWRP, (BYTE) (iw.pataar >> 8)); /* set PATAAR[9:8] */
+ outb(_PIDXR, 0x63); /* select PATALI */
+ outb(_PNPWRP, (BYTE) iw.pataar); /* set PATAAR[7:1] */
+ /* PATAAR[0]=0 */
+ outb(_PIDXR, 0x70); /* select PRISI */
+ outb(_PNPWRP, (BYTE) (iw.ext_irq & 0x0F)); /* Ext Dev IRQ number */
+ outb(_PIDXR, 0x74); /* select PRDSI */
+ outb(_PNPWRP, (BYTE) (iw.ext_chan & 0x07)); /* Ext Dev DMA channel */
+
+ IwavePnpDevice(GAME);
+ outb(_PIDXR, 0x60); /* select P201HI */
+ outb(_PNPWRP, (BYTE) (iw.p201ar >> 8)); /* set P201RAR[9:8] */
+ outb(_PIDXR, 0x61); /* select P201LI */
+ outb(_PNPWRP, (BYTE) iw.p201ar); /* set P201AR[7:6] */
+
+ IwavePnpDevice(EMULATION);
+ outb(_PIDXR, 0x60); /* select P388HI */
+ outb(_PNPWRP, (BYTE) (iw.p388ar >> 8)); /* set P388AR[9:8] */
+ outb(_PIDXR, 0x61); /* select P388LI */
+ outb(_PNPWRP, (BYTE) iw.p388ar); /* set P388AR[7:6] */
+
+ outb(_PIDXR, 0x70); /* select PSBISI */
+ outb(_PNPWRP, (BYTE) (iw.emul_irq & 0x0F)); /* emulation IRQ number */
+
+ IwavePnpDevice(MPU401);
+ outb(_PIDXR, 0x60); /* select P401HI */
+ outb(_PNPWRP, (BYTE) (iw.p401ar >> 8)); /* set P401AR[9:8] */
+ outb(_PIDXR, 0x61); /* select P401LI */
+ outb(_PNPWRP, (BYTE) iw.p401ar); /* set P401AR[7:1] */
+
+ outb(_PIDXR, 0x70); /* select PMISI */
+ outb(_PNPWRP, (BYTE) (iw.mpu_irq & 0x0F)); /* MPU emulation IRQ
+ * number */
+ LEAVE_CRITICAL;
+}
- DISABLE_INTR (flags);
+void
+IwaveCfgIOSpace(void)
+{
+ ENTER_CRITICAL;
+ IwavePnpDevice(AUDIO); /* select audio device */
+ outb(_PIDXR, 0x60); /* select P2X0HI */
+ outb(_PNPWRP, (BYTE) (iw.p2xr >> 8)); /* set P2XR[9:8] */
+ outb(_PIDXR, 0x61); /* select P2X0LI */
+ outb(_PNPWRP, (BYTE) iw.p2xr); /* set P2XR[7:4] */
+ /* P2XR[3:0]=0 */
+ outb(_PIDXR, 0x62); /* select P3X0HI */
+ outb(_PNPWRP, (BYTE) (iw.p3xr >> 8)); /* set P3XR[9:8] */
+ outb(_PIDXR, 0x63); /* select P3X0LI */
+ outb(_PNPWRP, (BYTE) (iw.p3xr)); /* set P3XR[7:3] */
+ /* P3XR[2:0]=0 */
+ outb(_PIDXR, 0x64); /* select PHCAI */
+ outb(_PNPWRP, (BYTE) (iw.pcodar >> 8)); /* set PCODAR[9:8] */
+ outb(_PIDXR, 0x65); /* select PLCAI */
+ outb(_PNPWRP, (BYTE) iw.pcodar); /* set PCODAR[7:2] */
+
+ IwavePnpDevice(EXT);
+ outb(_PIDXR, 0x60); /* select PRAHI */
+ outb(_PNPWRP, (BYTE) (iw.pcdrar >> 8)); /* set PCDRAR[9:8] */
+ outb(_PIDXR, 0x61); /* select PRALI */
+ outb(_PNPWRP, (BYTE) iw.pcdrar); /* set PCDRAR[7:3] */
+ /* PCDRAR[2:0]=0 */
+ outb(_PIDXR, 0x62); /* select PATAHI */
+ outb(_PNPWRP, (BYTE) (iw.pataar >> 8)); /* set PATAAR[9:8] */
+ outb(_PIDXR, 0x63); /* select PATALI */
+ outb(_PNPWRP, (BYTE) iw.pataar); /* set PATAAR[7:1] */
+ /* PATAAR[0]=0 */
+ IwavePnpDevice(GAME);
+ outb(_PIDXR, 0x60); /* select P201HI */
+ outb(_PNPWRP, (BYTE) (iw.p201ar >> 8)); /* set P201RAR[9:8] */
+ outb(_PIDXR, 0x61); /* select P201LI */
+ outb(_PNPWRP, (BYTE) iw.p201ar); /* set P201AR[7:6] */
+
+ IwavePnpDevice(EMULATION);
+ outb(_PIDXR, 0x60); /* select P388HI */
+ outb(_PNPWRP, (BYTE) (iw.p388ar >> 8)); /* set P388AR[9:8] */
+ outb(_PIDXR, 0x61); /* select P388LI */
+ outb(_PNPWRP, (BYTE) iw.p388ar); /* set P388AR[7:6] */
+
+ IwavePnpDevice(MPU401);
+ outb(_PIDXR, 0x60); /* select P401HI */
+ outb(_PNPWRP, (BYTE) (iw.p401ar >> 8)); /* set P401AR[9:8] */
+ outb(_PIDXR, 0x61); /* select P401LI */
+ outb(_PNPWRP, (BYTE) iw.p401ar); /* set P401AR[7:1] */
+ LEAVE_CRITICAL;
+}
- /*
- * Enable channels having vol > 10%
- * Note! bit 0x01 means line in DISABLED while 0x04 means
- * mic in ENABLED.
- */
- if (gus_line_vol > 10)
- mask &= ~0x01;
- if (gus_mic_vol > 10)
- mask |= 0x04;
- if (recording_active)
- {
- /*
- * Disable channel, if not selected for recording
- */
- if (!(gus_recmask & SOUND_MASK_LINE))
- mask |= 0x01;
- if (!(gus_recmask & SOUND_MASK_MIC))
- mask &= ~0x04;
- }
+/* ######################################################################## */
+/* FILE: iwpnp.c */
+/* */
+/* REMARKS: This file contains the definitions for the InterWave's DDK */
+/* functions dedicated to the configuration of the InterWave */
+/* PNP logic. */
+/* */
+/* UPDATE: 4/07/95 */
+/* ######################################################################## */
+/* */
+/* FUNCTION: IwavePnpKey */
+/* */
+/* PROFILE: This function issues the initiation key that places the PNP */
+/* logic into configuration mode. The PNP logic is quiescent at */
+/* power up and must be enabled by software. This function will */
+/* do 32 I/O writes to the PIDXR (0x0279). The function will */
+/* first reset the LFSR to its initial value by a sequence of two */
+/* write cycles of 0x00 to PIDXR before issuing the key. */
+/* */
+/* ######################################################################## */
+void
+IwavePnpKey(void)
+{
+ /* send_Initiation_LFSR(); */
+
+ BYTE code = 0x6A;
+ BYTE msb;
+ BYTE i;
- mix_image &= ~0x07;
- mix_image |= mask & 0x07;
- OUTB (mix_image, u_Mixer);
+ /* ############################################### */
+ /* Reset Linear Feedback Shift Reg. */
+ /* ############################################### */
+ outb(0x279, 0x00);
+ outb(0x279, 0x00);
+
+ outb(0x279, code); /* Initial value */
+
+ for (i = 1; i < 32; i++) {
+ msb = ((code & 0x01) ^ ((code & 0x02) >> 1)) << 7;
+ code = (code >> 1) | msb;
+ outb(0x279, code);
+ }
- RESTORE_INTR (flags);
}
-int
-gus_default_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
+BYTE
+IwavePnpIsol(PORT * pnpread)
{
-#define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \
- SOUND_MASK_SYNTH|SOUND_MASK_PCM)
- if (((cmd >> 8) & 0xff) == 'M')
- {
- if (cmd & IOC_IN)
- switch (cmd & 0xff)
- {
- case SOUND_MIXER_RECSRC:
- gus_recmask = IOCTL_IN (arg) & MIX_DEVS;
- if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE)))
- gus_recmask = SOUND_MASK_MIC;
- /* Note! Input volumes are updated during next open for recording */
- return IOCTL_OUT (arg, gus_recmask);
- break;
+ int num_pnp_devs;
+ int rd_port = 0;
+ printf("Checking for GUS Plug-n-Play ...\n");
+
+ /* Try various READ_DATA ports from 0x203-0x3ff */
+ for (rd_port = 0x80; (rd_port < 0xff); rd_port += 0x10) {
+ if (0)
+ printf("Trying Read_Port at %x\n",
+ (rd_port << 2) | 0x3);
+
+ num_pnp_devs = isolation_protocol(rd_port);
+ if (num_pnp_devs) {
+ *pnpread = rd_port << 2 | 0x3;
+ break;
+ }
+ }
+ if (!num_pnp_devs) {
+ printf("No Plug-n-Play devices were found\n");
+ return 0;
+ }
+ return 1;
+}
- case SOUND_MIXER_MIC:
- {
- int vol = IOCTL_IN (arg) & 0xff;
-
- if (vol < 0)
- vol = 0;
- if (vol > 100)
- vol = 100;
- gus_mic_vol = vol;
- set_input_volumes ();
- return IOCTL_OUT (arg, vol | (vol << 8));
- }
- break;
+/* ######################################################################## */
+/* */
+/* FUNCTION: IwavePnpSerial */
+/* */
+/* PROFILE: This function reads the first nine bytes of the data from */
+/* the serial EEPROM and returns the Vendor ID and the serial */
+/* number. First, it resets the EEPROM control logic by */
+/* issuing a WAKE[CSN] command. The function will return an */
+/* ASCII string for the vendor ID into the char array pointed */
+/* to by "vendor" in the VVVNNNN format. The serial number */
+/* is placed in the 32-bit variable pointed to by "serial". */
+/* Note that the 9th byte is read but not used as it is invalid */
+/* when the serial identifier is read via PRESDI. */
+/* */
+/* This function assumes that the PNP state machine is not in */
+/* the "wait for key state". Otherwise, unpredictable results */
+/* will be obtained. */
+/* */
+/* ######################################################################## */
+void
+IwavePnpSerial(PORT pnprdp,
+ BYTE csn,
+ BYTE * vendor,
+ DWORD * serial)
+{
+ BYTE presdi, digit, i;
+
+ *serial = 0L;
+
+ /* ####################################### */
+ /* Reset Serial EEPROM logic */
+ /* ####################################### */
+ IwavePnpWake(csn); /* Wake card up */
+
+ for (i = 1; i <= 4; i++) {
+ IwavePnpPeek(pnprdp, 1, &presdi);
+
+ switch (i) {
+ case 1:
+ *(vendor++) = ((presdi & 0x7C) >> 2) | 0x40; /* 1st char */
+ *vendor = (presdi & 0x03) << 3; /* isolate bits[4:3] of
+ * 2nd char */
+ break;
+ case 2:
+ *vendor = ((presdi & 0xE0) >> 5) | (*vendor);
+ *(vendor++) = (*vendor) | 0x40; /* 2nd char */
+ *vendor = (presdi & 0x1F) | 0x40; /* 3rd char */
+ break;
+ case 3:
+ case 4:
+ digit = (presdi & 0xF0) >> 4;
+ if (digit <= 0x09)
+ *(++vendor) = digit + 0x30; /* ASCII of digit */
+ else
+ *(++vendor) = (digit & 0x07) + 0x3F;
+ digit = presdi & 0x0F;
+ if (digit <= 0x09)
+ *(++vendor) = digit + 0x30;
+ else
+ *(++vendor) = (digit & 0x07) + 0x3F;
+ break;
+ }
+ }
+ *(++vendor) = '\0';
+ IwavePnpPeek(pnprdp, 4, (BYTE *) serial);
+ IwavePnpPeek(pnprdp, 1, NULL); /* discard checksum */
+}
+/* ######################################################################## */
+/* */
+/* FUNCTION: IwavePnpPeek */
+/* */
+/* PROFILE: This function will return the number of specified bytes of */
+/* resource data from the serial EEPROM. The function will NOT */
+/* reset the serial EEPROM logic to allow reading the entire */
+/* EEPROM by issuing repeated calls. The caller must supply a */
+/* pointer to where the data are to be stored. */
+/* It is assumed that the InterWave is not in either "sleep" */
+/* or "wait for key" states. Note that on the first call, if */
+/* the caller means to read from the beggining of data the */
+/* serial EEPROM logic must be reset. For this, the caller */
+/* should issue a WAKE[CSN] command */
+/* */
+/* ######################################################################## */
+void
+IwavePnpPeek(PORT pnprdp, WORD bytes, BYTE * data)
+{
+ WORD i;
+ BYTE datum;
+
+ for (i = 1; i <= bytes; i++) {
+ outb(_PIDXR, 0x05); /* select PRESSI */
+
+ while (TRUE) { /* wait til new data byte is ready */
+ if (inb(pnprdp) & PNP_DATA_RDY)
+ break; /* new resource byte ready */
+ }
+ outb(_PIDXR, 0x04); /* select PRESDI */
+ datum = inb(pnprdp); /* read resource byte */
+ if (data != NULL)
+ *(data++) = datum; /* store it */
+ }
+}
+/* ######################################################################## */
+/* */
+/* FUNCTION: IwavePnpEeprom */
+/* */
+/* PROFILE: This function allows the caller to control the serial */
+/* EEPROM directly while the audio device is inactive. To */
+/* de-activate the audio device issue the call */
+/* IwavePnpActivate(AUDIO,OFF). */
+/* */
+/* ######################################################################## */
+void
+IwavePnpEeprom(BYTE ctrl)
+{
+ ENTER_CRITICAL;
+ outb(_PIDXR, 0xF1); /* select PSECI */
+ outb(_PNPWRP, ctrl); /* write PSECI */
+ LEAVE_CRITICAL;
+}
+/* ######################################################################## */
+/* */
+/* FUNCTION: IwavePnpActivate */
+/* */
+/* PROFILE: This function will activate or de-activate the audio device */
+/* or the external device on the InterWave. Set the "dev" arg */
+/* to AUDIO for the audio device or EXT for the external device. */
+/* Set "bool" to ON or OFF to turn the device on or off the ISA */
+/* bus. Notice that for a logical device to work, it must be */
+/* activated. */
+/* */
+/* ######################################################################## */
+void
+IwavePnpActivate(BYTE dev, BYTE bool)
+{
+ IwavePnpDevice(dev); /* select audio device */
+ ENTER_CRITICAL;
+ outb(_PIDXR, ACTIVATE_DEV); /* select Activate Register */
+ outb(_PNPWRP, bool); /* write register */
+ LEAVE_CRITICAL;
- case SOUND_MIXER_LINE:
- {
- int vol = IOCTL_IN (arg) & 0xff;
-
- if (vol < 0)
- vol = 0;
- if (vol > 100)
- vol = 100;
- gus_line_vol = vol;
- set_input_volumes ();
- return IOCTL_OUT (arg, vol | (vol << 8));
- }
- break;
+}
+/* ######################################################################## */
+/* */
+/* FUNCTION: IwavePnpDevice */
+/* */
+/* PROFILE: This function allows the caller to select between five */
+/* logical devices available on the InterWave.It is assumed */
+/* that the PNP state machine is in configuration mode. */
+/* */
+/* ######################################################################## */
+void
+IwavePnpDevice(BYTE dev)
+{
+ ENTER_CRITICAL;
+ outb(_PIDXR, _PLDNI); /* select PLDNI */
+ outb(_PNPWRP, dev); /* write PLDNI */
+ LEAVE_CRITICAL;
+}
+/* ######################################################################## */
+/* */
+/* FUNCTION: IwavePnpPower */
+/* */
+/* PROFILE: This function allows the caller to disable major sections of */
+/* the InterWave to prevent them from consuming power and */
+/* loading the ISA bus. */
+/* */
+/* It is assumed that the PNP state machine is in configuration */
+/* mode. */
+/* */
+/* ######################################################################## */
+void
+IwavePnpPower(BYTE mode)
+{
+ ENTER_CRITICAL;
+ outb(_PIDXR, _PPWRI); /* select PPWRI */
+ outb(_PNPWRP, mode); /* write PPWRI */
+ LEAVE_CRITICAL;
+}
+/* ######################################################################## */
+/* */
+/* FUNCTION: IwavePnpWake */
+/* */
+/* PROFILE: This function issues a WAKE[CSN] command to the InterWave. If */
+/* the CSN matches the PNP state machine will enter the */
+/* configuration state. Otherwise it will enter the sleep mode. */
+/* */
+/* It is assumed that the PNP state machine is not in the */
+/* "wait for key" state. */
+/* */
+/* ######################################################################## */
+void
+IwavePnpWake(BYTE csn)
+{
+ ENTER_CRITICAL;
+ outb(_PIDXR, _PWAKEI); /* select PWAKEI */
+ outb(_PNPWRP, csn); /* write csn */
+ LEAVE_CRITICAL;
+}
+/* ######################################################################## */
+/* */
+/* FUNCTION: IwavePnpIOcheck */
+/* */
+/* PROFILE: This function allows the caller to perform a conflict check */
+/* on an I/O port to be used by a logical device. The function */
+/* receives the base address of the I/O range as well as the */
+/* number of ports in the range and then performs the I/O check */
+/* protocol. It returns the address of the port if a conflict */
+/* is detected or IO_CHK if no conflict is detected. */
+/* */
+/* This function assumes that the logical device has been de- */
+/* activated and that the PNP state machine is in config mode. */
+/* */
+/* ######################################################################## */
+PORT
+IwavePnpIOcheck(PORT base, BYTE no_ports)
+{
+ BYTE i;
+ PORT portid;
- case SOUND_MIXER_PCM:
- gus_pcm_volume = IOCTL_IN (arg) & 0xff;
- if (gus_pcm_volume < 0)
- gus_pcm_volume = 0;
- if (gus_pcm_volume > 100)
- gus_pcm_volume = 100;
- gus_sampling_update_volume ();
- return IOCTL_OUT (arg, gus_pcm_volume | (gus_pcm_volume << 8));
- break;
+ outb(_PIDXR, RANGE_IOCHK); /* select IO range check reg */
- case SOUND_MIXER_SYNTH:
- {
- int voice;
+ for (i = 0; i < no_ports; i++) {
+ portid = base + i; /* port to check */
+ outb(_PNPWRP, 0x02); /* must drive 0xAA onto bus */
+ if (inb(portid) != 0xAA)
+ return (portid); /* IO conflict detected */
- gus_wave_volume = IOCTL_IN (arg) & 0xff;
+ outb(_PNPWRP, 0x03); /* must drive 0x55 onto bus */
+ if (inb(portid) != 0x55)
+ return (portid); /* IO conflict detected */
+ }
+ return (IO_OK);
+}
+/* ######################################################################## */
+/* */
+/* FUNCTION: IwavePnpGetCSN */
+/* */
+/* PROFILE: This function allows the caller to detect an InterWave based */
+/* adapter board and will return its asigned CSN so that an */
+/* an application can access its PnP interface and determine the */
+/* borad's current configuration. In conducting its search for */
+/* the InterWave IC, the function will use the first 32 bits of */
+/* the Serial Identifier called the vendor ID in the PnP ISA */
+/* spec. The last 4 bits in the Vendor ID represent a revision */
+/* number for the particular product and this function gives the */
+/* caller the option of taking this revision number into account */
+/* or not in the search. If the function fails to find the */
+/* InterWave IC it will return FALSE. */
+/* */
+/* ######################################################################## */
+BYTE
+IwavePnpGetCSN(DWORD VendorID, BYTE csn_max)
+{
+ BYTE csn;
+ DWORD vendor;
+
+ IwavePnpKey(); /* Key to access PnP Interface */
+ VendorID &= (0xFFFFFFF0); /* reset 4 least significant bits */
+
+ for (csn = 1; csn <= csn_max; csn++) {
+ IwavePnpWake(csn); /* Select card */
+ IwavePnpPeek(iw.pnprdp, 4, (BYTE *) & vendor); /* get vendor ID */
+ vendor &= (0xFFFFFFF0);
+ if (vendor == VendorID) { /* If IDs match, InterWave is
+ * found */
+ outb(_PIDXR, 0x02); /* Place all cards in
+ * wait-for-key state */
+ outb(0x0A79, 0x02);
+ return (csn);
+ }
+ }
+ outb(_PIDXR, 0x02); /* Place all cards in wait-for-key state */
+ outb(0x0A79, 0x02);
+ return (FALSE); /* InterWave IC not found */
+}
+/* ######################################################################## */
+/* */
+/*
+ * FUNCTION: IwavePnpPing
+ */
+/* */
+/* PROFILE: This function allows the caller to detect an InterWave based */
+/* adapter board and will return its asigned CSN so that an */
+/* an application can access its PnP interface and determine the */
+/* borad's current configuration. In conducting its search for */
+/* the InterWave IC, the function will use the first 32 bits of */
+/* the Serial Identifier called the vendor ID in the PnP ISA */
+/* spec. The last 4 bits in the Vendor ID represent a revision */
+/* number for the particular product and will not be included */
+/* in the search. The function will return the Vendor ID and the */
+/* calling application should check the revision bits to make */
+/* sure they are compatible with the board. */
+/* */
+/* ######################################################################## */
+BYTE
+IwavePnpPing(DWORD VendorID)
+{
+ BYTE csn;
+
+ VendorID &= (0xFFFFFFF0); /* reset 4 least significant bits */
+ IwavePnpKey(); /* Key to access PnP Interface */
+ while (iw.pnprdp <= 0x23F) {
+ for (csn = 1; csn <= 10; csn++) {
+ IwavePnpWake(csn); /* Select card */
+ IwavePnpPeek(iw.pnprdp, 4, (BYTE *) & iw.vendor); /* get vendor ID */
+
+
+ if (((iw.vendor) & 0xFFFFFFF0) == VendorID) { /* If IDs match,
+ * InterWave is found */
+
+ outb(_PIDXR, 0x02); /* Place all cards in
+ * wait-for-key state */
+ outb(0x0A79, 0x02);
+ return (csn);
+ }
+ }
+ iw.pnprdp += 0x04;
+ }
+ outb(_PIDXR, 0x02); /* Place all cards in wait-for-key state */
+ outb(0x0A79, 0x02);
+ return (FALSE); /* InterWave IC not found */
+}
- if (gus_wave_volume < 0)
- gus_wave_volume = 0;
- if (gus_wave_volume > 100)
- gus_wave_volume = 100;
+/* end of pnp code */
- if (active_device == GUS_DEV_WAVE)
- for (voice = 0; voice < nr_voices; voice++)
- dynamic_volume_change (voice); /* Apply the new vol */
+WORD
+IwaveMemSize(void)
+{
+ BYTE datum = 0x55;
+ ADDRESS local = 0L;
+
+ outb(iw.igidxr, _LMCI);
+ outb(iw.i8dp, inb(iw.i8dp) & 0xFD); /* DRAM I/O cycles selected */
+
+ while (TRUE) {
+ IwaveMemPoke(local, datum);
+ IwaveMemPoke(local + 1L, datum + 1);
+ if (IwaveMemPeek(local) != datum || IwaveMemPeek(local + 1L) != (datum + 1) || IwaveMemPeek(0L) != 0x55)
+ break;
+ local += RAM_STEP;
+ datum++;
+ }
+ return ((WORD) (local >> 10));
+}
- return IOCTL_OUT (arg, gus_wave_volume | (gus_wave_volume << 8));
- }
- break;
+BYTE
+IwaveMemPeek(ADDRESS addr)
+{
+ PORT p3xr;
- default:
- return RET_ERROR (EINVAL);
- }
- else
- switch (cmd & 0xff) /*
- * Return parameters
- */
- {
-
- case SOUND_MIXER_RECSRC:
- return IOCTL_OUT (arg, gus_recmask);
- break;
+ p3xr = iw.p3xr;
- case SOUND_MIXER_DEVMASK:
- return IOCTL_OUT (arg, MIX_DEVS);
- break;
- case SOUND_MIXER_STEREODEVS:
- return IOCTL_OUT (arg, 0);
- break;
+ outb(iw.igidxr, 0x43); /* Select LMALI */
+ outw(iw.i16dp, (WORD) addr); /* Lower 16 bits of LM */
+ outb(iw.igidxr, 0x44); /* Select LMAHI */
+ outb(iw.i8dp, (BYTE) (addr >> 16)); /* Upper 8 bits of LM */
+ return (inb(iw.lmbdr)); /* return byte from LMBDR */
+}
- case SOUND_MIXER_RECMASK:
- return IOCTL_OUT (arg, SOUND_MASK_MIC | SOUND_MASK_LINE);
- break;
- case SOUND_MIXER_CAPS:
- return IOCTL_OUT (arg, 0);
- break;
+void
+IwaveMemPoke(ADDRESS addr, BYTE datum)
+{
+ PORT p3xr;
+ p3xr = iw.p3xr;
- case SOUND_MIXER_MIC:
- return IOCTL_OUT (arg, gus_mic_vol | (gus_mic_vol << 8));
- break;
- case SOUND_MIXER_LINE:
- return IOCTL_OUT (arg, gus_line_vol | (gus_line_vol << 8));
- break;
+ outb(iw.igidxr, 0x43); /* Select LMALI */
+ outw(iw.i16dp, (WORD) addr); /* Lower 16 bits of LM */
+ outb(iw.igidxr, 0x44); /* Select LMAHI */
+ outb(iw.i8dp, (BYTE) (addr >> 16)); /* Upper 8 bits of LM */
+ outb(iw.lmbdr, datum); /* Write byte to LMBDR */
+}
- case SOUND_MIXER_PCM:
- return IOCTL_OUT (arg, gus_pcm_volume | (gus_pcm_volume << 8));
- break;
+/* ######################################################################## */
+/* */
+/* FUNCTION: IwaveMemCfg */
+/* */
+/* PROFILE : This function determines the amount of DRAM from its */
+/* configuration accross all banks. It sets the configuration */
+/* into register LMCFI and stores the total amount of DRAM */
+/* into iw.size_mem (Kbytes). */
+/* */
+/* The function first places the IC in enhanced mode to allow */
+/* full access to all DRAM locations. Then it selects full */
+/* addressing span (LMCFI[3:0]=0x0C). Finally, it determines */
+/* the amount of DRAM in each bank and from this the actual */
+/* configuration. */
+/* */
+/* Note that if a configuration other than one indicated in */
+/* the manual is implemented, this function will select */
+/* full addressing span (LMCFI[3:0]=0xC). */
+/* */
+/* ######################################################################## */
+void
+IwaveMemCfg(DWORD * lpbanks)
+{
+ DWORD bank[4] = {0L, 0L, 0L, 0L};
+ DWORD addr = 0L, base = 0L, cnt = 0L;
+ BYTE i, reg, ram = FALSE;
+ WORD lmcfi;
+ /* */
+ ENTER_CRITICAL;
+ outb(iw.igidxr, 0x99);
+ reg = inb(iw.i8dp); /* image of sgmi */
+ outb(iw.igidxr, 0x19);
+ outb(iw.i8dp, (BYTE) (reg | 0x01)); /* enable enhaced mode */
+ outb(iw.igidxr, _LMCFI);/* select LM Conf Reg */
+ lmcfi = inw(iw.i16dp) & 0xFFF0;
+ outw(iw.i16dp, lmcfi | 0x000C); /* max addr span */
+ /* */
+ /* Clear every RAM_STEPth location */
+ /* */
+ while (addr < RAM_MAX) {
+ IwaveMemPoke(addr, 0x00);
+ addr += RAM_STEP;
+ }
+ /* */
+ /* Determine amount of RAM in each bank */
+ /* */
+ for (i = 0; i < 4; i++) {
+ IwaveMemPoke(base, 0xAA); /* mark start of bank */
+ IwaveMemPoke(base + 1L, 0x55);
+ if ((IwaveMemPeek(base) == 0xAA) && (IwaveMemPeek(base + 1L) == 0x55))
+ ram = TRUE;
+ if (ram) {
+ while (cnt < BANK_MAX) {
+ bank[i] += RAM_STEP;
+ cnt += RAM_STEP;
+ addr = base + cnt;
+ if (IwaveMemPeek(addr) == 0xAA)
+ break;
+ }
+ }
+ if (lpbanks != NULL) {
+ *lpbanks = bank[i];
+ lpbanks++;
+ }
+ bank[i] = bank[i] >> 10;
+ base += BANK_MAX;
+ cnt = 0L;
+ ram = FALSE;
+ }
+ /* */
+ iw.flags &= ~DRAM_HOLES;
+ outb(iw.igidxr, _LMCFI);
+ if (bank[0] == 256 && bank[1] == 0 && bank[2] == 0 && bank[3] == 0)
+ outw(iw.i16dp, lmcfi);
+ else if (bank[0] == 256 && bank[1] == 256 && bank[2] == 0 && bank[3] == 0)
+ outw(iw.i16dp, lmcfi | 0x01);
+ else if (bank[0] == 256 && bank[1] == 256 && bank[2] == 256 && bank[3] == 256)
+ outw(iw.i16dp, lmcfi | 0x02);
+ else if (bank[0] == 256 && bank[1] == 1024 && bank[2] == 0 && bank[3] == 0)
+ outw(iw.i16dp, lmcfi | 0x03);
+ else if (bank[0] == 256 && bank[1] == 1024 && bank[2] == 1024 && bank[3] == 1024)
+ outw(iw.i16dp, lmcfi | 0x04);
+ else if (bank[0] == 256 && bank[1] == 256 && bank[2] == 1024 && bank[3] == 0)
+ outw(iw.i16dp, lmcfi | 0x05);
+ else if (bank[0] == 256 && bank[1] == 256 && bank[2] == 1024 && bank[3] == 1024)
+ outw(iw.i16dp, lmcfi | 0x06);
+ else if (bank[0] == 1024 && bank[1] == 0 && bank[2] == 0 && bank[3] == 0)
+ outw(iw.i16dp, lmcfi | 0x07);
+ else if (bank[0] == 1024 && bank[1] == 1024 && bank[2] == 0 && bank[3] == 0)
+ outw(iw.i16dp, lmcfi | 0x08);
+ else if (bank[0] == 1024 && bank[1] == 1024 && bank[2] == 1024 && bank[3] == 1024)
+ outw(iw.i16dp, lmcfi | 0x09);
+ else if (bank[0] == 4096 && bank[1] == 0 && bank[2] == 0 && bank[3] == 0)
+ outw(iw.i16dp, lmcfi | 0x0A);
+ else if (bank[0] == 4096 && bank[1] == 4096 && bank[2] == 0 && bank[3] == 0)
+ outw(iw.i16dp, lmcfi | 0x0B);
+ else /* Flag the non-contiguous config of memory */
+ iw.flags |= DRAM_HOLES;
+ /* */
+ outb(iw.igidxr, 0x19); /* restore sgmi */
+ outb(iw.i8dp, reg);
+ LEAVE_CRITICAL;
+}
- case SOUND_MIXER_SYNTH:
- return IOCTL_OUT (arg, gus_wave_volume | (gus_wave_volume << 8));
- break;
- default:
- return RET_ERROR (EINVAL);
- }
- }
- else
- return RET_ERROR (EINVAL);
+/* ######################################################################## */
+/**/
+/* FUNCTION: IwaveCodecIrq */
+/**/
+/* PROFILE: This function disables or enables the Codec Interrupts. To */
+/* enable interrupts set CEXTI[2] high thus causing all interrupt */
+/* sources (CSR3I[6:4]) to pass onto the IRQ pin. To disable */
+/* interrupts set CEXTI[1]=0. To enable Code IRQs issue this call: */
+/**/
+/* IwaveCodecIrq(CODEC_IRQ_ENABLE). To disable IRQs issue the call */
+/**/
+/* IwaveCodeIrq(~CODEC_IRQ_ENABLE). */
+/**/
+/* ######################################################################## */
+void
+IwaveCodecIrq(BYTE mode)
+{
+ BYTE reg;
+
+ ENTER_CRITICAL;
+ reg = inb(iw.pcodar) & 0xE0;
+ outb(iw.pcodar, reg | _CSR3I); /* select CSR3I */
+ outb(iw.cdatap, 0x00); /* clear all interrupts */
+ outb(iw.pcodar + 0x02, 0x00); /* clear CSR1R */
+ outb(iw.pcodar, reg | _CEXTI); /* select CEXTI */
+ reg = inb(iw.cdatap);
+ if (mode == CODEC_IRQ_ENABLE) /* enable Codec Irqs */
+ outb(iw.cdatap, (BYTE) (reg | CODEC_IRQ_ENABLE));
+ else /* disable Codec Irqs */
+ outb(iw.cdatap, (BYTE) (reg & ~CODEC_IRQ_ENABLE));
+ LEAVE_CRITICAL;
}
-static struct mixer_operations gus_mixer_operations =
+
+/* ######################################################################### */
+/**/
+/* FUNCTION: IwaveRegPeek */
+/**/
+/* PROFILE : This function returns the value stored in any readable */
+/* InterWave register. It takes as input a pointer to a */
+/* structure containing the addresses of the relocatable I/O */
+/* space as well as a register mnemonic. To correctly use this */
+/* function, the programmer must use the mnemonics defined in */
+/* "iwdefs.h". These mnemonics contain coded information used */
+/* by the function to properly access the desired register. */
+/**/
+/* An attempt to read from a write-only register will return */
+/* meaningless data. */
+/**/
+/* ######################################################################### */
+WORD
+IwaveRegPeek(DWORD reg_mnem)
{
- "Gravis Ultrasound",
- gus_default_mixer_ioctl
-};
+ BYTE index, val;
+ WORD reg_id, offset;
+
+ offset = (WORD) ((BYTE) reg_mnem);
+ reg_id = (WORD) (reg_mnem >> 16);
+ index = (BYTE) (reg_mnem >> 8);
+
+ /* ################################################### */
+ /* Logic to read registers in P2XR block & GMCR */
+ /* ################################################### */
+
+ if (reg_id >= 0x0001 && reg_id <= 0x001A) { /* UMCR to GMCR */
+ if (reg_id <= 0x000E) /* UMCR to USRR */
+ return ((WORD) inb(iw.p2xr + offset));
+
+ if (reg_id == 0x0019)
+ return ((WORD) inb(iw.p201ar));
+
+ else { /* GUS Hidden registers or GMCR */
+ BYTE iveri;
+
+ outb(iw.igidxr, 0x5B); /* select IVERI */
+ iveri = inb(iw.i8dp); /* read IVERI */
+ outb(iw.i8dp, (BYTE) (iveri | 0x09)); /* set IVERI[3,0] */
+ if (reg_id == 0x001A) { /* GMCR */
+ val = inb(iw.p3xr);
+ outb(iw.i8dp, iveri); /* restore IVERI */
+ return ((WORD) val);
+ }
+ val = inb(iw.p2xr + 0x0F); /* read URCR */
+ val = (val & 0xF8) | index; /* value for URCR[2:0] */
+ outb(iw.p2xr + 0x0F, val); /* set URCR[2:0] */
+
+ if (reg_mnem == UDCI || reg_mnem == UICI) {
+ val = inb(iw.p2xr);
+ if (reg_mnem == UDCI)
+ outb(iw.p2xr, (BYTE) (val & 0xBF));
+ else
+ outb(iw.p2xr, (BYTE) (val | 0x40));
+ }
+ val = inb(iw.p2xr + 0x0B);
+ outb(iw.igidxr, 0x5B); /* select IVERI */
+ outb(iw.i8dp, iveri); /* restore IVERI */
+ return ((WORD) val); /* read register */
+ }
+ }
+ /* ################################################### */
+ /* Logic to read registers in P3XR block */
+ /* ################################################### */
+
+ if (reg_id >= 0x001B && reg_id <= 0x005C) { /* GMSR to LMBDR */
+ if (reg_id == 0x005C) /* LMBDR */
+ return ((WORD) inb(iw.lmbdr));
+
+ if (reg_id >= 0x001B && reg_id <= 0x0021) /* GMSR to I8DP */
+ if (offset == 0x04)
+ return (inw(iw.i16dp));
+ else
+ return ((WORD) inb(iw.p3xr + offset));
+ else { /* indexed registers */
+
+ if (reg_id <= 0x003F)
+ index |= 0x80; /* adjust for reading */
+
+ outb(iw.igidxr, index); /* select register */
+
+ if (offset == 0x04)
+ return (inw(iw.i16dp));
+ else
+ return ((WORD) inb(iw.i8dp));
+ }
+ }
+ /* #################################################### */
+ /* Logic to read registers in PCODAR block */
+ /* #################################################### */
+
+ if (reg_id >= 0x005D && reg_id <= 0x0081) { /* CIDXR to CLRCTI */
+ if (reg_id <= 0x0061)
+ return ((WORD) inb(iw.pcodar + offset)); /* CRDR */
+
+ else { /* indexed registers */
+ BYTE cidxr;
+
+ cidxr = inb(iw.pcodar);
+ cidxr = (cidxr & 0xE0) + index;
+ outb(iw.pcodar, cidxr); /* select register */
+ return ((WORD) inb(iw.cdatap));
+ }
+ }
+ /* ##################################################### */
+ /* Logic to read the PnP registers */
+ /* ##################################################### */
+ if (reg_id >= 0x0082 && reg_id <= 0x00B7) { /* PCSNBR to PMITI */
+ if (reg_id == 0x0085)
+ return ((WORD) inb(iw.pnprdp));
+
+ if (reg_id < 0x0085)
+ return ((WORD) inb((WORD) reg_mnem));
+
+ else { /* indexed registers */
+ if (reg_id >= 0x008E && reg_id <= 0x00B7) {
+ outb(0x0279, 0x07); /* select PLDNI */
+ outb(0xA79, (BYTE) offset); /* select logical dev */
+ }
+ outb(0x0279, index); /* select the register */
+ return ((WORD) inb(iw.pnprdp));
+ }
+ }
+ return 0;
+}
+/* ######################################################################### */
+/**/
+/* FUNCTION: IwaveRegPoke */
+/**/
+/* PROFILE : This function writes a value to any writable */
+/* InterWave register. It takes as input a pointer to a */
+/* structure containing the addresses of the relocatable I/O */
+/* space as well as a register mnemonic. To correctly use this */
+/* function, the programmer must use the mnemonics defined in */
+/* "iwdefs.h". These mnemonics contain coded information used */
+/* by the function to properly access the desired register. */
+/**/
+/* This function does not guard against writing to read-only */
+/* registers. It is the programmer's responsibility to ensure */
+/* that the writes are to valid registers. */
+/**/
+/* ######################################################################### */
+void
+IwaveRegPoke(DWORD reg_mnem, WORD datum)
+{
+ BYTE index;
+ BYTE val;
+ WORD reg_id;
+ WORD offset;
+
+ offset = (WORD) ((BYTE) reg_mnem);
+ reg_id = (WORD) (reg_mnem >> 16);
+ index = (BYTE) (reg_mnem >> 8);
+
+
+ /* ####################################################### */
+ /* Logic to write to registers in P2XR block */
+ /* ####################################################### */
+ if (reg_id >= 0x0001 && reg_id <= 0x0019) { /* UMCR to GGCR */
+ if (reg_id <= 0x000E) { /* UMCR to USRR */
+ outb(iw.p2xr + offset, (BYTE) datum);
+ return;
+ }
+ if (reg_id == 0x0019) {
+ outb(iw.p201ar, (BYTE) datum);
+ return;
+ } else { /* GUS Hidden registers */
+
+ BYTE iveri;
+
+ outb(iw.igidxr, 0x5B); /* select IVERI */
+ iveri = inb(iw.i8dp); /* read IVERI */
+ outb(iw.i8dp, (BYTE) (iveri | 0x09)); /* set IVERI[3,0] */
+ val = inb(iw.p2xr + 0x0F); /* read URCR */
+ val = (val & 0xF8) | index; /* value for URCR[2:0] */
+ outb(iw.p2xr + 0x0F, val); /* set URCR[2:0] */
+
+ if (reg_mnem == UDCI || reg_mnem == UICI) {
+ val = inb(iw.p2xr); /* read UMCR */
+ if (reg_mnem == UDCI)
+ outb(iw.p2xr, (BYTE) (val & 0xBF)); /* set UMCR[6]=0 */
+ else
+ outb(iw.p2xr, (BYTE) (val | 0x40)); /* set UMCR[6]=1 */
+ }
+ outb(iw.p2xr + 0x0B, (BYTE) datum); /* write register */
+ outb(iw.igidxr, 0x5B); /* select IVERI */
+ outb(iw.i8dp, iveri); /* restore IVERI */
+ return;
+ }
+ }
+ /* ############################################################# */
+ /* Logic to write to registers in P3XR block */
+ /* ############################################################# */
+
+ if (reg_id >= 0x001A && reg_id <= 0x005C) { /* GMCR to LMBDR */
+
+ if (reg_id == 0x005C) { /* LMBDR */
+ outb(iw.lmbdr, (BYTE) datum);
+ return;
+ }
+ if (reg_id == 0x001B) /* GMSR */
+ return;
+
+ if (reg_id >= 0x001A && reg_id <= 0x0021) /* GMCR to I8DP */
+ if (offset == 0x04)
+ outw(iw.i16dp, datum);
+ else
+ outb(iw.p3xr + offset, (BYTE) datum);
+ else { /* indexed registers */
+ outb(iw.igidxr, index); /* select register */
+
+ if (offset == 0x04)
+ outw(iw.i16dp, datum);
+ else
+ outb(iw.i8dp, (BYTE) datum);
+ }
+ }
+ /* /################################################### */
+ /* Logic to write to registers in PCODAR block */
+ /* ################################################### */
+
+ if (reg_id >= 0x005C && reg_id <= 0x0081) { /* CIDXR to CLRCTI */
+ if (reg_id <= 0x0061)
+ outb(iw.pcodar + offset, (BYTE) datum);
+
+ else { /* one of the indexed registers */
+ BYTE cidxr;
+
+ cidxr = inb(iw.pcodar);
+ cidxr = (cidxr & 0xE0) + index;
+ outb(iw.pcodar, cidxr); /* select register */
+ outb(iw.cdatap, (BYTE) datum);
+ }
+ }
+ /* ###################################################### */
+ /* Logic to write to the PnP registers */
+ /* ###################################################### */
+ if (reg_id >= 0x0082 && reg_id <= 0x00B7) {
+ if (reg_id == 0x0085) {
+ outb(iw.pnprdp, (BYTE) datum);
+ return;
+ }
+ if (reg_id < 0x0085)
+ outb((WORD) reg_mnem, (BYTE) datum);
+
+ else { /* one of the indexed registers */
+ if (reg_id >= 0x008E && reg_id <= 0x00B7) {
+ outb(0x0279, 0x07); /* select PLDNI */
+ outb(0xA79, (BYTE) offset); /* select logical dev */
+ }
+ outb(0x0279, index); /* select the register */
+ outb(0xA79, (BYTE) datum);
+ }
+ }
+}
-static long
-gus_default_mixer_init (long mem_start)
+
+void
+IwaveLineLevel(char level, char index)
{
- if (num_mixers < MAX_MIXER_DEV) /*
- * Don't install if there is another
- * mixer
- */
- mixer_devs[num_mixers++] = &gus_mixer_operations;
+ char reg;
- return mem_start;
+ level &= 0x1F;
+
+ ENTER_CRITICAL;
+ reg = inb(iw.pcodar) & 0xE0;
+ outb(iw.pcodar, reg | index); /* select register */
+ outb(iw.cdatap, (BYTE) ((inb(iw.cdatap) & 0x80) | level)); /* set level */
+ LEAVE_CRITICAL;
}
-long
-gus_wave_init (long mem_start, int irq, int dma, int dma_read)
+void
+IwaveCodecMode(char mode)
{
- unsigned long flags;
- unsigned char val;
- char *model_num = "2.4";
- int gus_type = 0x24; /* 2.4 */
- int mixer_type = 0;
+ char reg;
+
+ ENTER_CRITICAL;
+ reg = inb(iw.pcodar) & 0xE0;
+ outb(iw.pcodar, reg | _CMODEI); /* select CMODEI */
+ outb(iw.cdatap, mode);
+ LEAVE_CRITICAL;
+ iw.cmode = mode;
+}
- if (irq < 0 || irq > 15)
- {
- printk ("ERROR! Invalid IRQ#%d. GUS Disabled", irq);
- return mem_start;
- }
+void
+IwaveLineMute(BYTE mute, BYTE inx)
+{
+ BYTE reg;
- if (dma < 0 || dma > 7)
- {
- printk ("ERROR! Invalid DMA#%d. GUS Disabled", dma);
- return mem_start;
- }
+ ENTER_CRITICAL;
+ reg = inb(iw.pcodar) & 0xE0;
+ outb(iw.pcodar, reg | inx); /* select register */
+ if (mute == ON)
+ outb(iw.cdatap, (BYTE) (inb(iw.cdatap) | 0x80)); /* mute */
+ else
+ outb(iw.cdatap, (BYTE) (inb(iw.cdatap) & 0x7F)); /* unmute */
+ LEAVE_CRITICAL;
+}
- if (dma_read == 0) dma_read = dma;
- if (dma_read < 0 || dma_read > 7)
- {
- printk ("ERROR! Invalid DMA#%d. GUS DMA-read disabled", dma_read);
- dma_read = dma;
- }
- /*
- * Try to identify the GUS model.
- *
- * Versions < 3.6 don't have the digital ASIC. Try to probe it first.
- */
+void
+Iwaveinitcodec()
+{
- DISABLE_INTR (flags);
- OUTB (0x20, gus_base + 0x0f);
- val = INB (gus_base + 0x0f);
- RESTORE_INTR (flags);
+ u_short iwl_codec_base = iw.pcodar;
+ u_short iwl_codec_data = iw.pcodar + 1;
+ u_short foo;
- if (val != 0xff && (val & 0x06)) /* Should be 0x02?? */
- {
- /*
- * It has the digital ASIC so the card is at least v3.4.
- * Next try to detect the true model.
- */
-
- val = INB (u_MixSelect);
-
- /*
- * Value 255 means pre-3.7 which don't have mixer.
- * Values 5 thru 9 mean v3.7 which has a ICS2101 mixer.
- * 10 and above is GUS MAX which has the CS4231 codec/mixer.
- *
- * Sorry. No GUS max support yet but it should be available
- * soon after the SDK for GUS MAX is available.
- */
-
- if (val == 255 || val < 5)
- {
- model_num = "3.4";
- gus_type = 0x34;
- }
- else if (val < 10)
- {
- model_num = "3.7";
- gus_type = 0x37;
- mixer_type = ICS2101;
- }
- else
- {
- model_num = "MAX";
- gus_type = 0x40;
- mixer_type = CS4231;
+
+
+ /*
+ * Set the CEXTI register foo = CODEC_CEXTI_DEFAULT;
+ * IWL_CODEC_OUT(EXTERNAL_CONTROL, foo);
+ */
+ /*
+ * Disable Interrupts iwl_codec_disable_irqs();
+ */
+
+ /* Set the CODEC to Operate in Mode 3 */
+ IWL_CODEC_OUT(MODE_SELECT_ID, 0x6C);
+ foo = inb(iwl_codec_data);
+
+ /* Set the configuration registers to their default values */
+ foo = CODEC_CFIG1I_DEFAULT;
+ IWL_CODEC_OUT(CONFIG_1 | CODEC_MCE, foo);
+ outb(iwl_codec_base, CONFIG_1);
+ foo = CODEC_CFIG2I_DEFAULT;
+ IWL_CODEC_OUT(CONFIG_2, foo);
+
+ foo = CODEC_CFIG3I_DEFAULT;
+ IWL_CODEC_OUT(CONFIG_3, foo);
+
+}
+
+
+
+int
+IwaveOpen(char voices, char mode, struct address_info * hw)
+{
+
+ u_long flags;
+ u_char tmp;
+
+ flags = splhigh();
+
+ iw.pnprdp = 0;
+ if (IwavePnpIsol(&iw.pnprdp)) {
+
+ iw.vendor = GUS_PNP_ID;
+
+ iw.csn = IwavePnpPing(iw.vendor);
+
+ IwavePnpKey();
+
+ IwavePnpWake(iw.csn);
+
+ IwavePnpGetCfg();
+ IwavePnpKey();
+
+ IwavePnpWake(iw.csn);
}
- }
- else
- {
- /*
- * ASIC not detected so the card must be 2.2 or 2.4.
- * There could still be the 16-bit/mixer daughter card.
- * It has the same codec/mixer than MAX.
- * At this time there is no support for it but it will appear soon.
- */
- }
+ if (hw->irq > 0) {
+ /* I see the user wants to set the GUS PnP */
+ /* Okay lets do it */
+ iw.csn = 1;
+ iw.p2xr = hw->io_base;
+ iw.p3xr = hw->io_base + 0x100;
+ iw.pcodar = hw->io_base + 0x10c;
+ iw.synth_irq = hw->irq;
-#if defined(__FreeBSD__)
- printk ("gus0: <Gravis UltraSound %s (%dk)>", model_num,
- (int) gus_mem_size / 1024);
-#else
- printk (" <Gravis UltraSound %s (%dk)>", model_num, (int) gus_mem_size / 1024);
-#endif
+ iw.midi_irq = hw->irq;
- sprintf (gus_info.name, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024);
+ iw.dma1_chan = hw->dma;
- gus_irq = irq;
- gus_dma = dma;
- gus_dma_read = dma_read;
+ if (hw->dma2 == -1) {
+ iw.dma2_chan = hw->dma;
+ } else {
+ iw.dma2_chan = hw->dma2;
+ }
- if (num_synths >= MAX_SYNTH_DEV)
- printk ("GUS Error: Too many synthesizers\n");
- else
- {
- voice_alloc = &guswave_operations.alloc;
- synth_devs[num_synths++] = &guswave_operations;
- }
-#if defined(__FreeBSD__)
- PERMANENT_MALLOC (char *, gus_copy_buf, DSP_BUFFSIZE, mem_start);
-#endif
+ } else {
- PERMANENT_MALLOC (struct patch_info *, samples,
- (MAX_SAMPLE + 1) * sizeof (*samples), mem_start);
+ /* tell the os what we are doing 8) */
+ hw->io_base = iw.p2xr;
+ hw->irq = iw.synth_irq;
+ /*
+ * iw.dma1_chan = 1; iw.dma2_chan = 3 ;
+ */
+ hw->dma = iw.dma1_chan;
+ hw->dma2 = iw.dma2_chan;
- reset_sample_memory ();
- gus_initialize ();
+ }
- if (num_audiodevs < MAX_AUDIO_DEV)
- {
- 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;
- gus_dspnum = gus_devnum;
- gus_busy[gus_devnum] = 0;
- gus_busy[gus_dspnum] = 0;
- }
- else
- printk ("GUS: Too many PCM devices available\n");
-
- if (num_audiodevs < MAX_AUDIO_DEV)
- {
- if(dma_read && dma != dma_read)
- {
- audio_devs[gus_dspnum = num_audiodevs++]= &gus_sampling_operations_read;
- audio_devs[gus_dspnum]->dmachan = gus_dma_read;
- audio_devs[gus_dspnum]->buffcount = 1;
- audio_devs[gus_dspnum]->buffsize = DSP_BUFFSIZE;
- gus_busy[gus_dspnum] = 0;
- }
- else
- {
- gus_dspnum = gus_devnum;
- }
- }
- else
- printk ("GUS READ: Too many PCM devices available\n");
-
- /*
- * Mixer dependent initialization.
- */
- switch (mixer_type)
- {
- case ICS2101:
- gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
- gus_wave_volume = 90;
- return ics2101_mixer_init (mem_start);
+ if (iw.csn > 0 && iw.csn < MAX_GUS_PNP) {
+ gus_pnp_found[iw.csn] = hw->io_base;
- case CS4231:
- /* Initialized elsewhere (ad1848.c) */
-#ifndef EXCLUDE_GUSMAX
- {
- unsigned char max_config = 0x40; /* Codec enable */
- long mixer_init_return;
-
- if (dma > 3)
- max_config |= 0x30; /* 16 bit playback and capture DMAs */
-
- max_config |= (gus_base >> 4) & 0x0f; /* Extract the X from 2X0 */
-
- OUTB (max_config, gus_base + 0x106); /* UltraMax control */
- mixer_init_return = gus_default_mixer_init(mem_start);
-
- if (ad1848_detect (gus_base + 0x10c))
- {
- gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
- gus_wave_volume = 90;
- have_gus_max = 1;
- ad1848_init ("GUS MAX", gus_base + 0x10c,
- -irq,
- dma_read, /* read write reversed */
- dma);
- }
- else
- printk ("[Where's the CS4231?]");
- return mixer_init_return;
- }
-#endif
- default:
- return gus_default_mixer_init (mem_start);
- }
+ }
+ iw.cdatap = iw.pcodar + 1;
+ iw.csr1r = iw.pcodar + 2;
+ iw.cxdr = iw.pcodar + 3;/* CPDR or CRDR */
+ iw.gmxr = iw.p3xr;
+ iw.gmxdr = iw.p3xr + 1; /* GMTDR or GMRDR */
+ iw.svsr = iw.p3xr + 2;
+ iw.igidxr = iw.p3xr + 3;
+ iw.i16dp = iw.p3xr + 4;
+ iw.i8dp = iw.p3xr + 5;
+ iw.lmbdr = iw.p3xr + 7;
+ iw.voices = voices;
+
+ if (iw.pnprdp > 0 && iw.csn > 0) {
+ IwavePnpSetCfg();
+ IwavePnpActivate(AUDIO, ON);
+ IwavePnpActivate(EXT, ON);
+ }
+ /* IwavePnpActivate(EMULATION,ON); */
+
+
+ /* reset */
+ outb(iw.igidxr, _URSTI);/* Pull reset */
+ outb(iw.i8dp, 0x00);
+ DELAY(1000 * 30);
+
+ outb(iw.i8dp, 0x01); /* Release reset */
+ DELAY(1000 * 30);
+
+ /* end of reset */
+
+
+ IwaveMemCfg(NULL);
+
+
+ tmp = IwaveRegPeek(IDECI);
+
+ IwaveRegPoke(IDECI, tmp | 0x18);
+
+ IwaveCodecMode(CODEC_MODE2); /* Default codec mode */
+ IwaveRegPoke(ICMPTI, 0);
+
+ outb(iw.igidxr, 0x99);
+ tmp = inb(iw.i8dp);
+ outb(iw.igidxr, 0x19);
+ outb(iw.i8dp, tmp);
+
+
+
+ IwaveCodecIrq(~CODEC_IRQ_ENABLE);
+
+ Iwaveinitcodec();
+
+ outb(iw.p2xr, 0x0c); /* Disable line in, mic and line out */
+
+ IwaveRegPoke(CLCI, 0x3f << 2);
+
+ IwaveLineLevel(0, _CLOAI);
+ IwaveLineLevel(0, _CROAI);
+
+ IwaveLineMute(OFF, _CLOAI);
+ IwaveLineMute(OFF, _CROAI);
+
+ IwaveLineLevel(0, _CLLICI);
+ IwaveLineLevel(0, _CRLICI);
+ IwaveLineMute(OFF, _CLLICI);
+ IwaveLineMute(OFF, _CRLICI);
+
+ IwaveLineLevel(0, _CLDACI);
+ IwaveLineLevel(0, _CRDACI);
+ IwaveLineMute(ON, _CLDACI);
+ IwaveLineMute(ON, _CRDACI);
+
+ IwaveLineLevel(0, _CLLICI);
+ IwaveLineLevel(0, _CRLICI);
+ IwaveLineMute(ON, _CLLICI);
+ IwaveLineMute(ON, _CRLICI);
+
+
+ IwaveInputSource(LEFT_SOURCE, MIC_IN);
+ IwaveInputSource(RIGHT_SOURCE, MIC_IN);
+
+ outb(iw.pcodar, 0x9 | 0x40);
+ outb(iw.cdatap, 0);
+ IwaveCodecIrq(CODEC_IRQ_ENABLE);
+ outb(iw.pcodar, _CFIG3I | 0x20);
+
+
+ outb(iw.cdatap, 0xC2); /* Enable Mode 3 IRQs & Synth */
+
+ outb(iw.igidxr, _URSTI);
+ outb(iw.i8dp, GF1_SET | GF1_OUT_ENABLE | GF1_IRQ_ENABLE);
+ DELAY(1000 * 30);
+ iw.size_mem = IwaveMemSize(); /* Bytes of RAM in this mode */
+ outb(iw.p2xr, 0xc); /* enable output */
+ IwaveRegPoke(CLCI, 0x3f << 2);
+
+ IwaveCodecIrq(CODEC_IRQ_ENABLE);
+ splx(flags);
+
+ DELAY(1000 * 100);
+ IwaveRegPoke(CPDFI, 0);
+
+ return (TRUE);
}
-static void
-do_loop_irq (int voice)
+
+void
+gus_wave_init(struct address_info * hw_config)
{
- unsigned char tmp;
- int mode, parm;
- unsigned long flags;
+ u_long flags;
+ u_char val, gus_pnp_seen = 0;
+ char *model_num = "2.4";
+ int gus_type = 0x24; /* 2.4 */
+ int irq = hw_config->irq, dma = hw_config->dma, dma2 = hw_config->dma2;
+ int otherside = -1, i;
+
+ if (irq < 0 || irq > 15) {
+ printf("ERROR! Invalid IRQ#%d. GUS Disabled", irq);
+ return;
+ }
+ if (dma < 0 || dma > 7) {
+ printf("ERROR! Invalid DMA#%d. GUS Disabled", dma);
+ return;
+ }
+ for (i = 0; i < MAX_GUS_PNP; i++) {
+ if (gus_pnp_found[i] != 0 && gus_pnp_found[i] == hw_config->io_base)
+ gus_pnp_seen = 1;
+ }
+#ifdef NOGUSPNP
+ gus_pnp_seen = 0;
+#endif
- DISABLE_INTR (flags);
- gus_select_voice (voice);
+ gus_irq = irq;
+ gus_dma = dma;
+ gus_dma2 = dma2;
- tmp = gus_read8 (0x00);
- tmp &= ~0x20; /*
- * Disable wave IRQ for this_one voice
- */
- gus_write8 (0x00, tmp);
+ if (gus_dma2 == -1)
+ gus_dma2 = dma;
- if (tmp & 0x03) /* Voice stopped */
- voice_alloc->map[voice] = 0;
+ /*
+ * Try to identify the GUS model.
+ *
+ * Versions < 3.6 don't have the digital ASIC. Try to probe it first.
+ */
- mode = voices[voice].loop_irq_mode;
- voices[voice].loop_irq_mode = 0;
- parm = voices[voice].loop_irq_parm;
+ flags = splhigh();
+ outb(gus_base + 0x0f, 0x20);
+ val = inb(gus_base + 0x0f);
+ splx(flags);
- switch (mode)
- {
+ if (val != 0xff && (val & 0x06)) { /* Should be 0x02?? */
+ /*
+ * It has the digital ASIC so the card is at least v3.4. Next
+ * try to detect the true model.
+ */
- case LMODE_FINISH: /*
- * Final loop finished, shoot volume down
- */
-
- if ((int) (gus_read16 (0x09) >> 4) < 100) /*
- * Get current volume
- */
- {
- gus_voice_off ();
- gus_rampoff ();
- gus_voice_init (voice);
- break;
- }
- gus_ramp_range (65, 4065);
- gus_ramp_rate (0, 63); /*
- * Fastest possible rate
- */
- gus_rampon (0x20 | 0x40); /*
- * Ramp down, once, irq
- */
- voices[voice].volume_irq_mode = VMODE_HALT;
- break;
-
- case LMODE_PCM_STOP:
- pcm_active = 0; /* Signal to the play_next_pcm_block routine */
- case LMODE_PCM:
- {
- int flag; /* 0 or 2 */
-
- pcm_qlen--;
- pcm_head = (pcm_head + 1) % pcm_nblk;
- if (pcm_qlen && pcm_active)
- {
- play_next_pcm_block ();
- }
- else
- { /* Underrun. Just stop the voice */
- gus_select_voice (0); /* Left channel */
- gus_voice_off ();
- gus_rampoff ();
- gus_select_voice (1); /* Right channel */
- gus_voice_off ();
- gus_rampoff ();
- pcm_active = 0;
- }
+ val = inb(u_MixSelect);
/*
- * If the queue was full before this interrupt, the DMA transfer was
- * suspended. Let it continue now.
+ * Value 255 means pre-3.7 which don't have mixer. Values 5
+ * thru 9 mean v3.7 which has a ICS2101 mixer. 10 and above
+ * is GUS MAX which has the CS4231 codec/mixer.
+ *
*/
- if (dma_active)
- {
- if (pcm_qlen == 0)
- flag = 1; /* Underflow */
+
+ if (gus_pnp_seen)
+ val = 66;
+
+ if (val == 255 || val < 5) {
+ model_num = "3.4";
+ gus_type = 0x34;
+ } else if (val < 10) {
+ model_num = "3.7";
+ gus_type = 0x37;
+ mixer_type = ICS2101;
+ } else {
+ if (gus_pnp_seen)
+ model_num = "PNP";
else
- flag = 0;
- dma_active = 0;
- }
- else
- flag = 2; /* Just notify the dmabuf.c */
- DMAbuf_outputintr (gus_devnum, flag);
- }
- break;
+ model_num = "MAX";
+
+ gus_type = 0x40;
+ mixer_type = CS4231;
+#ifdef CONFIG_GUSMAX
+ {
+ u_char max_config = 0x40; /* Codec enable */
+
+ if (gus_dma2 == -1)
+ gus_dma2 = gus_dma;
+
+ if (gus_dma > 3)
+ max_config |= 0x10; /* 16 bit capture DMA */
+
+ if (gus_dma2 > 3)
+ max_config |= 0x20; /* 16 bit playback DMA */
+
+ max_config |= (gus_base >> 4) & 0x0f; /* Extract the X from
+ * 2X0 */
+
+ outb(gus_base + 0x106, max_config); /* UltraMax control */
+ }
+
+ if (ad1848_detect(gus_base + 0x10c, NULL, hw_config->osp)) {
+
+ gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
+ gus_wave_volume = 90;
+ have_gus_max = 1;
+ if (gus_pnp_seen) {
+
+ ad1848_init("GUS PNP", gus_base + 0x10c,
+ -irq,
+ gus_dma2, /* Playback DMA */
+ gus_dma, /* Capture DMA */
+ 1, /* Share DMA channels with GF1 */
+ hw_config->osp);
+
+
+ } else {
+ ad1848_init("GUS MAX", gus_base + 0x10c,
+ -irq,
+ gus_dma2, /* Playback DMA */
+ gus_dma, /* Capture DMA */
+ 1, /* Share DMA channels with GF1 */
+ hw_config->osp);
+ }
+ otherside = num_audiodevs - 1;
+
+ } else
+ printf("[Where's the CS4231?]");
+#else
+ printf("\n\n\nGUS MAX support was not compiled in!!!\n\n\n\n");
+#endif
+ }
+ } else {
+ /*
+ * ASIC not detected so the card must be 2.2 or 2.4. There
+ * could still be the 16-bit/mixer daughter card.
+ */
+ }
+
+ if (gus_pnp_seen) {
+ sprintf(gus_info.name, "Gravis %s (%dk)", model_num, (int) gus_mem_size / 1024);
+ } else {
+ sprintf(gus_info.name, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024);
+ }
+ conf_printf(gus_info.name, hw_config);
+
+ if (num_synths >= MAX_SYNTH_DEV)
+ printf("GUS Error: Too many synthesizers\n");
+ else {
+ voice_alloc = &guswave_operations.alloc;
+ synth_devs[num_synths++] = &guswave_operations;
+#ifdef CONFIG_SEQUENCER
+ gus_tmr_install(gus_base + 8);
+#endif
+ }
+ samples = (struct patch_info *) malloc((MAX_SAMPLE + 1) * sizeof(*samples), M_DEVBUF, M_NOWAIT);
+ if (!samples)
+ panic("SOUND: Cannot allocate memory\n");
+
+ reset_sample_memory();
+
+ gus_initialize();
+
+ if (num_audiodevs < MAX_AUDIO_DEV) {
+ audio_devs[gus_devnum = num_audiodevs++] = &gus_sampling_operations;
+ audio_devs[gus_devnum]->otherside = otherside;
+ audio_devs[gus_devnum]->dmachan1 = dma;
+ audio_devs[gus_devnum]->dmachan2 = dma2;
+ audio_devs[gus_devnum]->buffsize = DSP_BUFFSIZE;
+ if (otherside != -1) {
+ /*
+ * glue logic to prevent people from opening the gus
+ * max via the gf1 and the cs4231 side . Only the gf1
+ * or the cs4231 are allowed to be open
+ */
+
+ audio_devs[otherside]->otherside = gus_devnum;
+ }
+ if (dma2 != dma && dma2 != -1)
+ audio_devs[gus_devnum]->flags |= DMA_DUPLEX;
+ } else
+ printf("GUS: Too many PCM devices available\n");
+
+ /*
+ * Mixer dependent initialization.
+ */
+
+ switch (mixer_type) {
+ case ICS2101:
+ gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
+ gus_wave_volume = 90;
+ ics2101_mixer_init();
+ return;
- default:;
+ case CS4231:
+ /* Initialized elsewhere (ad1848.c) */
+ default:
+ gus_default_mixer_init();
+ return;
}
- RESTORE_INTR (flags);
}
static void
-do_volume_irq (int voice)
+do_loop_irq(int voice)
+{
+ u_char tmp;
+ int mode, parm;
+ u_long flags;
+
+ flags = splhigh();
+ gus_select_voice(voice);
+
+ tmp = gus_read8(0x00);
+ tmp &= ~0x20; /* Disable wave IRQ for this_one voice */
+ gus_write8(0x00, tmp);
+
+ if (tmp & 0x03) /* Voice stopped */
+ voice_alloc->map[voice] = 0;
+
+ mode = voices[voice].loop_irq_mode;
+ voices[voice].loop_irq_mode = 0;
+ parm = voices[voice].loop_irq_parm;
+
+ switch (mode) {
+
+ case LMODE_FINISH: /* Final loop finished, shoot volume down */
+
+ if ((int) (gus_read16(0x09) >> 4) < 100) { /* Get current volume */
+ gus_voice_off();
+ gus_rampoff();
+ gus_voice_init(voice);
+ break;
+ }
+ gus_ramp_range(65, 4065);
+ gus_ramp_rate(0, 63); /* Fastest possible rate */
+ gus_rampon(0x20 | 0x40); /* Ramp down, once, irq */
+ voices[voice].volume_irq_mode = VMODE_HALT;
+ break;
+
+ case LMODE_PCM_STOP:
+ pcm_active = 0; /* Signal to the play_next_pcm_block routine */
+ case LMODE_PCM:
+ {
+ int flag; /* 0 or 2 */
+
+ pcm_qlen--;
+ pcm_head = (pcm_head + 1) % pcm_nblk;
+ if (pcm_qlen && pcm_active) {
+ play_next_pcm_block();
+ } else {/* Underrun. Just stop the voice */
+ gus_select_voice(0); /* Left channel */
+ gus_voice_off();
+ gus_rampoff();
+ gus_select_voice(1); /* Right channel */
+ gus_voice_off();
+ gus_rampoff();
+ pcm_active = 0;
+ }
+
+ /*
+ * If the queue was full before this interrupt, the
+ * DMA transfer was suspended. Let it continue now.
+ */
+ if (dma_active) {
+ 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;
+
+ default:;
+ }
+ splx(flags);
+}
+
+void
+do_volume_irq(int voice)
{
- unsigned char tmp;
- int mode, parm;
- unsigned long flags;
+ u_char tmp;
+ int mode, parm;
+ u_long flags;
- DISABLE_INTR (flags);
+ flags = splhigh();
- gus_select_voice (voice);
+ gus_select_voice(voice);
- tmp = gus_read8 (0x0d);
- tmp &= ~0x20; /*
- * Disable volume ramp IRQ
- */
- gus_write8 (0x0d, tmp);
+ tmp = gus_read8(0x0d);
+ tmp &= ~0x20; /* Disable volume ramp IRQ */
+ gus_write8(0x0d, tmp);
- mode = voices[voice].volume_irq_mode;
- voices[voice].volume_irq_mode = 0;
- parm = voices[voice].volume_irq_parm;
+ mode = voices[voice].volume_irq_mode;
+ voices[voice].volume_irq_mode = 0;
+ parm = voices[voice].volume_irq_parm;
- switch (mode)
- {
- case VMODE_HALT: /*
- * Decay phase finished
- */
- RESTORE_INTR (flags);
- gus_voice_init (voice);
- break;
-
- case VMODE_ENVELOPE:
- gus_rampoff ();
- RESTORE_INTR (flags);
- step_envelope (voice);
- break;
-
- case VMODE_START_NOTE:
- RESTORE_INTR (flags);
- 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,
- voices[voice].note_pending, 0);
+ switch (mode) {
+ case VMODE_HALT: /* Decay phase finished */
+ splx(flags);
+ gus_voice_init(voice);
+ break;
- if (voices[voice].sample_pending >= 0)
- {
- guswave_set_instr (voices[voice].dev_pending, voice,
- voices[voice].sample_pending);
- voices[voice].sample_pending = -1;
+ case VMODE_ENVELOPE:
+ gus_rampoff();
+ splx(flags);
+ step_envelope(voice);
+ break;
+
+ case VMODE_START_NOTE:
+ splx(flags);
+ 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,
+ voices[voice].note_pending, 0);
+
+ if (voices[voice].sample_pending >= 0) {
+ guswave_set_instr(voices[voice].dev_pending, voice,
+ voices[voice].sample_pending);
+ voices[voice].sample_pending = -1;
+ }
+ break;
+
+ default:;
}
- break;
+}
- default:;
- }
+void
+gus_voice_irq(void)
+{
+ u_long wave_ignore = 0, volume_ignore = 0;
+ u_long voice_bit;
+
+ u_char src, voice;
+
+ while (1) {
+ src = gus_read8(0x0f); /* Get source info */
+ voice = src & 0x1f;
+ src &= 0xc0;
+
+ if (src == (0x80 | 0x40))
+ return; /* No interrupt */
+
+ voice_bit = 1 << voice;
+
+ if (!(src & 0x80)) /* Wave IRQ pending */
+ if (!(wave_ignore & voice_bit) && (int) voice < nr_voices) { /* Not done yet */
+ wave_ignore |= voice_bit;
+ do_loop_irq(voice);
+ }
+ if (!(src & 0x40)) /* Volume IRQ pending */
+ if (!(volume_ignore & voice_bit) && (int) voice < nr_voices) { /* Not done yet */
+ volume_ignore |= voice_bit;
+ do_volume_irq(voice);
+ }
+ }
}
void
-gus_voice_irq (void)
+guswave_dma_irq(void)
{
- unsigned long wave_ignore = 0, volume_ignore = 0;
- unsigned long voice_bit;
+ u_char status;
+
+ status = gus_look8(0x41); /* Get DMA IRQ Status */
+ if (status & 0x40) /* DMA interrupt pending */
+ switch (active_device) {
+ case GUS_DEV_WAVE:
+ if ((dram_sleep_flag.mode & WK_SLEEP)) {
+ dram_sleep_flag.mode = WK_WAKEUP;
+ wakeup(dram_sleeper);
+ };
+ break;
+
+ 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;
- unsigned char src, voice;
+ case GUS_DEV_PCM_DONE: /* Right or mono channel data transferred */
+ if (pcm_qlen < pcm_nblk) {
+ int flag = (1 - dma_active) * 2; /* 0 or 2 */
- while (1)
- {
- src = gus_read8 (0x0f); /*
- * Get source info
- */
- voice = src & 0x1f;
- src &= 0xc0;
-
- if (src == (0x80 | 0x40))
- return; /*
- * No interrupt
- */
-
- voice_bit = 1 << voice;
-
- if (!(src & 0x80)) /*
- * Wave IRQ pending
- */
- if (!(wave_ignore & voice_bit) && (int) voice < nr_voices) /*
- * Not done
- * yet
- */
- {
- wave_ignore |= voice_bit;
- do_loop_irq (voice);
- }
-
- if (!(src & 0x40)) /*
- * Volume IRQ pending
- */
- if (!(volume_ignore & voice_bit) && (int) voice < nr_voices) /*
- * Not done
- * yet
- */
- {
- volume_ignore |= voice_bit;
- do_volume_irq (voice);
- }
- }
+ if (pcm_qlen == 0)
+ flag = 1; /* Underrun */
+ dma_active = 0;
+ DMAbuf_outputintr(gus_devnum, flag);
+ }
+ break;
+
+ default:;
+ }
+
+ status = gus_look8(0x49); /* Get Sampling IRQ Status */
+ if (status & 0x40) { /* Sampling Irq pending */
+ DMAbuf_inputintr(gus_devnum);
+ }
}
+#ifdef CONFIG_SEQUENCER
+/*
+ * Timer stuff
+ */
+
+static volatile int select_addr, data_addr;
+static volatile int curr_timer = 0;
+
void
-guswave_dma_irq (void)
+gus_timer_command(u_int addr, u_int val)
{
- unsigned char status;
+ int i;
- status = gus_look8 (0x41); /* Get DMA IRQ Status */
- if (status & 0x40) /* DMA interrupt pending */
- switch (active_device)
- {
- case GUS_DEV_WAVE:
- if (SOMEONE_WAITING (dram_sleeper, dram_sleep_flag))
- WAKE_UP (dram_sleeper, dram_sleep_flag);
- break;
+ outb(select_addr, (u_char) (addr & 0xff));
- 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;
+ for (i = 0; i < 2; i++)
+ inb(select_addr);
- case GUS_DEV_PCM_DONE: /* Right or mono channel data transferred */
- if (pcm_qlen < pcm_nblk)
- {
- int flag = (1 - dma_active) * 2; /* 0 or 2 */
+ outb(data_addr, (u_char) (val & 0xff));
- if (pcm_qlen == 0)
- flag = 1; /* Underrun */
- dma_active = 0;
- DMAbuf_outputintr (gus_devnum, flag);
- }
- break;
+ for (i = 0; i < 2; i++)
+ inb(select_addr);
+}
+
+static void
+arm_timer(int timer, u_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 */
+ gus_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 */
+ gus_timer_command(0x04, 0x02); /* Start timer 2 */
+ }
- default:;
- }
+ gus_timer_enabled = 0;
+}
- status = gus_look8 (0x49); /*
- * Get Sampling IRQ Status
- */
- if (status & 0x40) /*
- * Sampling Irq pending
- */
- {
- if (gus_dma_read && gus_dma_read != gus_dma)
- DMAbuf_inputintr (gus_dspnum);
- else
- DMAbuf_inputintr (gus_devnum);
+static u_int
+gus_tmr_start(int dev, u_int usecs_per_tick)
+{
+ int timer_no, resolution;
+ int divisor;
+
+ 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;
+
+ arm_timer(timer_no, divisor);
+
+ return divisor * resolution;
+}
+
+static void
+gus_tmr_disable(int dev)
+{
+ gus_write8(0x45, 0); /* Disable both timers */
+ gus_timer_enabled = 0;
+}
+
+static void
+gus_tmr_restart(int dev)
+{
+ if (curr_timer == 1)
+ gus_write8(0x45, 0x04); /* Start timer 1 again */
+ else
+ gus_write8(0x45, 0x08); /* Start timer 2 again */
}
+static struct sound_lowlev_timer gus_tmr =
+{
+ 0,
+ gus_tmr_start,
+ gus_tmr_disable,
+ gus_tmr_restart
+};
+
+static void
+gus_tmr_install(int io_base)
+{
+ select_addr = io_base;
+ data_addr = io_base + 1;
+
+ sound_timer_init(&gus_tmr, "GUS");
+}
+#endif
#endif
diff --git a/sys/i386/isa/sound/hex2hex.h b/sys/i386/isa/sound/hex2hex.h
index ecd7b4c..5c90917 100644
--- a/sys/i386/isa/sound/hex2hex.h
+++ b/sys/i386/isa/sound/hex2hex.h
@@ -81,7 +81,7 @@ int hex2hex(char *source, char *target, char *varline)
}
fprintf(outf, "/*\n *\t Computer generated file. Do not edit.\n */\n");
- fprintf(outf, "%s[] = {\n", varline);
+ fprintf(outf, "static unsigned char %s[] = {\n", varline);
for (i=0;i<l;i++)
{
diff --git a/sys/i386/isa/sound/ics2101.c b/sys/i386/isa/sound/ics2101.c
index cec1e51..4df8bde 100644
--- a/sys/i386/isa/sound/ics2101.c
+++ b/sys/i386/isa/sound/ics2101.c
@@ -1,10 +1,10 @@
/*
* sound/ics2101.c
- *
+ *
* Driver for the ICS2101 mixer of GUS v3.7.
- *
+ *
* 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
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,241 +24,210 @@
* 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 <i386/isa/sound/sound_config.h>
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)
-#include <machine/ultrasound.h>
+#if defined(CONFIG_GUS)
+
+#include <i386/isa/sound/ultrasound.h>
#include <i386/isa/sound/gus_hw.h>
#define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \
SOUND_MASK_SYNTH| \
SOUND_MASK_CD | SOUND_MASK_VOLUME)
+extern sound_os_info *gus_osp;
extern int gus_base;
static int volumes[ICS_MIXDEVS];
-static int left_fix[ICS_MIXDEVS] =
-{1, 1, 1, 2, 1, 2};
-static int right_fix[ICS_MIXDEVS] =
-{2, 2, 2, 1, 2, 1};
+static int left_fix[ICS_MIXDEVS] = {1, 1, 1, 2, 1, 2};
+static int right_fix[ICS_MIXDEVS] = {2, 2, 2, 1, 2, 1};
static int
-scale_vol (int vol)
+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;
-
- 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--;
+ /*
+ * Experimental volume scaling by Risto Kankkunen. This should give
+ * smoother volume response than just a plain multiplication.
+ */
+ int e;
+
+ RANGE(vol, 0, 100);
+ vol = (31 * vol + 50) / 100;
+ e = 0;
+ if (vol) {
+ while (vol < 16) {
+ vol <<= 1;
+ e--;
}
- vol -= 16;
- e += 7;
+ vol -= 16;
+ e += 7;
}
- return ((e << 4) + vol);
-#else
- return ((vol * 127) + 50) / 100;
-#endif
+ return ((e << 4) + vol);
}
static void
-write_mix (int dev, int chn, int vol)
+write_mix(int dev, int chn, int vol)
{
- int *selector;
- unsigned long flags;
- int ctrl_addr = dev << 3;
- int attn_addr = dev << 3;
-
- vol = scale_vol (vol);
-
- if (chn == CHN_LEFT)
- {
- selector = left_fix;
- ctrl_addr |= 0x00;
- attn_addr |= 0x02;
- }
- else
- {
- selector = right_fix;
- ctrl_addr |= 0x01;
- attn_addr |= 0x03;
+ int *selector;
+ unsigned long flags;
+ int ctrl_addr = dev << 3;
+ int attn_addr = dev << 3;
+
+ vol = scale_vol(vol);
+
+ if (chn == CHN_LEFT) {
+ selector = left_fix;
+ ctrl_addr |= 0x00;
+ attn_addr |= 0x02;
+ } else {
+ selector = right_fix;
+ ctrl_addr |= 0x01;
+ attn_addr |= 0x03;
}
- DISABLE_INTR (flags);
- OUTB (ctrl_addr, u_MixSelect);
- OUTB (selector[dev], u_MixData);
- OUTB (attn_addr, u_MixSelect);
- OUTB ((unsigned char) vol, u_MixData);
- RESTORE_INTR (flags);
+ flags = splhigh();
+ outb(u_MixSelect, ctrl_addr);
+ outb(u_MixData, selector[dev]);
+ outb(u_MixSelect, attn_addr);
+ outb(u_MixData, (unsigned char) vol);
+ splx(flags);
}
static int
-set_volumes (int dev, int vol)
+set_volumes(int dev, int vol)
{
- int left = vol & 0x00ff;
- int right = (vol >> 8) & 0x00ff;
-
- if (left < 0)
- left = 0;
- if (left > 100)
- left = 100;
- if (right < 0)
- right = 0;
- if (right > 100)
- right = 100;
-
- write_mix (dev, CHN_LEFT, left);
- write_mix (dev, CHN_RIGHT, right);
-
- vol = left + (right << 8);
- volumes[dev] = vol;
- return vol;
+ int left = vol & 0x00ff;
+ int right = (vol >> 8) & 0x00ff;
+
+ RANGE (left, 0, 100);
+ RANGE (right, 0, 100);
+
+ write_mix(dev, CHN_LEFT, left);
+ write_mix(dev, CHN_RIGHT, right);
+
+ vol = left + (right << 8);
+ volumes[dev] = vol;
+ return vol;
}
static int
-ics2101_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
+ics2101_mixer_ioctl(int dev, unsigned int cmd, ioctl_arg arg)
{
- if (((cmd >> 8) & 0xff) == 'M')
- {
- if (cmd & IOC_IN)
- switch (cmd & 0xff)
- {
- case SOUND_MIXER_RECSRC:
- return gus_default_mixer_ioctl (dev, cmd, arg);
- break;
-
- case SOUND_MIXER_MIC:
- return IOCTL_OUT (arg, set_volumes (DEV_MIC, IOCTL_IN (arg)));
- break;
-
- case SOUND_MIXER_CD:
- return IOCTL_OUT (arg, set_volumes (DEV_CD, IOCTL_IN (arg)));
- break;
-
- case SOUND_MIXER_LINE:
- return IOCTL_OUT (arg, set_volumes (DEV_LINE, IOCTL_IN (arg)));
- break;
-
- case SOUND_MIXER_SYNTH:
- return IOCTL_OUT (arg, set_volumes (DEV_GF1, IOCTL_IN (arg)));
- break;
-
- case SOUND_MIXER_VOLUME:
- return IOCTL_OUT (arg, set_volumes (DEV_VOL, IOCTL_IN (arg)));
- break;
-
- default:
- return RET_ERROR (EINVAL);
- }
- else
- switch (cmd & 0xff) /*
- * Return parameters
- */
- {
-
- case SOUND_MIXER_RECSRC:
- return gus_default_mixer_ioctl (dev, cmd, arg);
- break;
-
- case SOUND_MIXER_DEVMASK:
- return IOCTL_OUT (arg, MIX_DEVS);
- break;
-
- case SOUND_MIXER_STEREODEVS:
- return IOCTL_OUT (arg, SOUND_MASK_LINE | SOUND_MASK_CD |
- SOUND_MASK_SYNTH | SOUND_MASK_VOLUME |
- SOUND_MASK_MIC);
- break;
-
- case SOUND_MIXER_RECMASK:
- return IOCTL_OUT (arg, SOUND_MASK_MIC | SOUND_MASK_LINE);
- break;
-
- case SOUND_MIXER_CAPS:
- return IOCTL_OUT (arg, 0);
- break;
-
- case SOUND_MIXER_MIC:
- return IOCTL_OUT (arg, volumes[DEV_MIC]);
- break;
-
- case SOUND_MIXER_LINE:
- return IOCTL_OUT (arg, volumes[DEV_LINE]);
- break;
-
- case SOUND_MIXER_CD:
- return IOCTL_OUT (arg, volumes[DEV_CD]);
- break;
-
- case SOUND_MIXER_VOLUME:
- return IOCTL_OUT (arg, volumes[DEV_VOL]);
- break;
-
- case SOUND_MIXER_SYNTH:
- return IOCTL_OUT (arg, volumes[DEV_GF1]);
- break;
-
- default:
- return RET_ERROR (EINVAL);
- }
+ if (((cmd >> 8) & 0xff) == 'M') {
+ if (cmd & IOC_IN)
+ switch (cmd & 0xff) {
+ case SOUND_MIXER_RECSRC:
+ return gus_default_mixer_ioctl(dev, cmd, arg);
+ break;
+
+ case SOUND_MIXER_MIC:
+ return *(int *) arg = set_volumes(DEV_MIC, (*(int *) arg));
+ break;
+
+ case SOUND_MIXER_CD:
+ return *(int *) arg = set_volumes(DEV_CD, (*(int *) arg));
+ break;
+
+ case SOUND_MIXER_LINE:
+ return *(int *) arg = set_volumes(DEV_LINE, (*(int *) arg));
+ break;
+
+ case SOUND_MIXER_SYNTH:
+ return *(int *) arg = set_volumes(DEV_GF1, (*(int *) arg));
+ break;
+
+ case SOUND_MIXER_VOLUME:
+ return *(int *) arg = set_volumes(DEV_VOL, (*(int *) arg));
+ break;
+
+ default:
+ return -(EINVAL);
+ }
+ else
+ switch (cmd & 0xff) { /* Return parameters */
+
+ case SOUND_MIXER_RECSRC:
+ return gus_default_mixer_ioctl(dev, cmd, arg);
+ break;
+
+ case SOUND_MIXER_DEVMASK:
+ return *(int *) arg = MIX_DEVS;
+ break;
+
+ case SOUND_MIXER_STEREODEVS:
+ return *(int *) arg = SOUND_MASK_LINE | SOUND_MASK_CD |
+ SOUND_MASK_SYNTH | SOUND_MASK_VOLUME | SOUND_MASK_MIC;
+ break;
+
+ case SOUND_MIXER_RECMASK:
+ return *(int *) arg = SOUND_MASK_MIC | SOUND_MASK_LINE;
+ break;
+
+ case SOUND_MIXER_CAPS:
+ return *(int *) arg = 0;
+ break;
+
+ case SOUND_MIXER_MIC:
+ return *(int *) arg = volumes[DEV_MIC];
+ break;
+
+ case SOUND_MIXER_LINE:
+ return *(int *) arg = volumes[DEV_LINE];
+ break;
+
+ case SOUND_MIXER_CD:
+ return *(int *) arg = volumes[DEV_CD];
+ break;
+
+ case SOUND_MIXER_VOLUME:
+ return *(int *) arg = volumes[DEV_VOL];
+ break;
+
+ case SOUND_MIXER_SYNTH:
+ return *(int *) arg = volumes[DEV_GF1];
+ break;
+
+ default:
+ return -(EINVAL);
+ }
}
-
- return RET_ERROR (EINVAL);
+ return -(EINVAL);
}
static struct mixer_operations ics2101_mixer_operations =
{
- "ICS2101 Multimedia Mixer",
- ics2101_mixer_ioctl
+ "ICS2101 Multimedia Mixer",
+ ics2101_mixer_ioctl
};
-long
-ics2101_mixer_init (long mem_start)
+void
+ics2101_mixer_init()
{
- int i;
-
- if (num_mixers < MAX_MIXER_DEV)
- {
- mixer_devs[num_mixers++] = &ics2101_mixer_operations;
-
- /*
- * Some GUS v3.7 cards had some channels flipped. Disable
- * the flipping feature if the model id is other than 5.
- */
-
- if (INB (u_MixSelect) != 5)
- {
- for (i = 0; i < ICS_MIXDEVS; i++)
- left_fix[i] = 1;
- for (i = 0; i < ICS_MIXDEVS; i++)
- right_fix[i] = 2;
- }
+ int i;
- set_volumes (DEV_GF1, 0x5a5a);
- set_volumes (DEV_CD, 0x5a5a);
- set_volumes (DEV_MIC, 0x0000);
- set_volumes (DEV_LINE, 0x5a5a);
- set_volumes (DEV_VOL, 0x5a5a);
- set_volumes (DEV_UNUSED, 0x0000);
- }
+ if (num_mixers < MAX_MIXER_DEV) {
+ mixer_devs[num_mixers++] = &ics2101_mixer_operations;
- return mem_start;
+ /*
+ * Some GUS v3.7 cards had some channels flipped. Disable the
+ * flipping feature if the model id is other than 5.
+ */
+
+ if (inb(u_MixSelect) != 5) {
+ for (i = 0; i < ICS_MIXDEVS; i++)
+ left_fix[i] = 1;
+ for (i = 0; i < ICS_MIXDEVS; i++)
+ right_fix[i] = 2;
+ }
+ set_volumes(DEV_GF1, 0x5a5a);
+ set_volumes(DEV_CD, 0x5a5a);
+ set_volumes(DEV_MIC, 0x0000);
+ set_volumes(DEV_LINE, 0x5a5a);
+ set_volumes(DEV_VOL, 0x5a5a);
+ set_volumes(DEV_UNUSED, 0x0000);
+ }
}
#endif
diff --git a/sys/i386/isa/sound/iwdefs.h b/sys/i386/isa/sound/iwdefs.h
new file mode 100644
index 0000000..60f50fc
--- /dev/null
+++ b/sys/i386/isa/sound/iwdefs.h
@@ -0,0 +1,712 @@
+/*#######################################################################*/
+/* FILE : iwdefs.h*/
+/**/
+/* REMARKS: This file contains all defines used by DDK functions. It*/
+/* should be included by all applications and should be*/
+/* referenced by programmers to make their code easy to read*/
+/* and understand.*/
+/**/
+/* UPDATE: 3/21/95*/
+/* 7/10/95 --- added #def DRAM_HOLES*/
+/*#######################################################################*/
+#ifndef IWDEFS
+#define IWDEFS
+/*#######################################################################*/
+/**/
+/* Macros for use in loading Synth Addr Regs*/
+/**/
+/*#######################################################################*/
+#define ADDR_HIGH(x) (short)(x>>7)
+#define ADDR_LOW(x) (short)(x<<9)
+/*#######################################################################*/
+/**/
+/* Defines for DMA Controllers*/
+/**/
+/*#######################################################################*/
+/* DMA Controler #1 (8-bit controller) */
+#define DMA1_STAT 0x08 /* read status register */
+#define DMA1_WCMD 0x08 /* write command register */
+#define DMA1_WREQ 0x09 /* write request register */
+#define DMA1_SNGL 0x0A /* write single bit register */
+#define DMA1_MODE 0x0B /* write mode register */
+#define DMA1_CLRFF 0x0C /* clear byte ptr flip/flop */
+#define DMA1_MCLR 0x0D /* master clear register */
+#define DMA1_CLRM 0x0E /* clear mask register */
+#define DMA1_WRTALL 0x0F /* write all mask register */
+
+/* DMA Controler #2 (16-bit controller) */
+#define DMA2_STAT 0xD0 /* read status register */
+#define DMA2_WCMD 0xD0 /* write command register */
+#define DMA2_WREQ 0xD2 /* write request register */
+#define DMA2_SNGL 0xD4 /* write single bit register */
+#define DMA2_MODE 0xD6 /* write mode register */
+#define DMA2_CLRFF 0xD8 /* clear byte ptr flip/flop */
+#define DMA2_MCLR 0xDA /* master clear register */
+#define DMA2_CLRM 0xDC /* clear mask register */
+#define DMA2_WRTALL 0xDE /* write all mask register */
+
+#define DMA0_ADDR 0x00 /* chan 0 base adddress */
+#define DMA0_CNT 0x01 /* chan 0 base count */
+#define DMA1_ADDR 0x02 /* chan 1 base adddress */
+#define DMA1_CNT 0x03 /* chan 1 base count */
+#define DMA2_ADDR 0x04 /* chan 2 base adddress */
+#define DMA2_CNT 0x05 /* chan 2 base count */
+#define DMA3_ADDR 0x06 /* chan 3 base adddress */
+#define DMA3_CNT 0x07 /* chan 3 base count */
+#define DMA4_ADDR 0xC0 /* chan 4 base adddress */
+#define DMA4_CNT 0xC2 /* chan 4 base count */
+#define DMA5_ADDR 0xC4 /* chan 5 base adddress */
+#define DMA5_CNT 0xC6 /* chan 5 base count */
+#define DMA6_ADDR 0xC8 /* chan 6 base adddress */
+#define DMA6_CNT 0xCA /* chan 6 base count */
+#define DMA7_ADDR 0xCC /* chan 7 base adddress */
+#define DMA7_CNT 0xCE /* chan 7 base count */
+
+#define DMA0_PAGE 0x87 /* chan 0 page register (refresh)*/
+#define DMA1_PAGE 0x83 /* chan 1 page register */
+#define DMA2_PAGE 0x81 /* chan 2 page register */
+#define DMA3_PAGE 0x82 /* chan 3 page register */
+#define DMA4_PAGE 0x8F /* chan 4 page register (unusable)*/
+#define DMA5_PAGE 0x8B /* chan 5 page register */
+#define DMA6_PAGE 0x89 /* chan 6 page register */
+#define DMA7_PAGE 0x8A /* chan 7 page register */
+/*#######################################################################*/
+/**/
+/* Defines for register UISR (Interrupt Status)*/
+/**/
+/*#######################################################################*/
+#define MIDI_TX_IRQ 0x01
+#define MIDI_RX_IRQ 0x02
+#define ALIB_TIMER1_IRQ 0x04
+#define ALIB_TIMER2_IRQ 0x08
+#define _UASBCI 0x45 /* UASBCI index */
+#define SAMPLE_CONTROL 0x49 /* Not used by IW */
+#define SET_VOICES 0x0E
+#define WAVETABLE_IRQ 0x20
+#define ENVELOPE_IRQ 0x40
+#define DMA_TC_IRQ 0x80
+/*#######################################################################*/
+/**/
+/* Synthesizer-related defines*/
+/**/
+/*#######################################################################*/
+#define GEN_INDEX 0x03 /* IGIDX offset into p3xr */
+#define VOICE_SELECT 0x02 /* SVSR offset into p3xr */
+#define VOICE_IRQS 0x8F /* SVII index (read) */
+#define _URSTI 0x4C /* URSTI index */
+#define GF1_SET 0x01 /* URSTI[0] */
+#define GF1_OUT_ENABLE 0x02 /* URSTI[1] */
+#define GF1_IRQ_ENABLE 0x04 /* URSTI[2] */
+#define GF1_RESET 0xFE /* URSTI[0]=0 */
+#define VOICE_VOLUME_IRQ 0x04 /* SVII[2] */
+#define VOICE_WAVE_IRQ 0x08 /* SVII[3] */
+#define VC_IRQ_ENABLE 0x20 /* SACI[5] or SVCI[5]*/
+#define VOICE_NUMBER 0x1F /* Mask for SVII[4:0] */
+#define VC_IRQ_PENDING 0x80 /* SACI[7] or SVCI[7] */
+#define VC_DIRECT 0x40 /* SACI[6] or SVCI[6]*/
+#define VC_DATA_WIDTH 0x04 /* SACI[2] */
+#define VOICE_STOP 0x02 /* SACI[1] */
+#define VOICE_STOPPED 0x01 /* SACI[0] */
+#define VOLUME_STOP 0x02 /* SVCI[1] */
+#define VOLUME_STOPPED 0x01 /* SVCI[0] */
+#define VC_ROLLOVER 0x04 /* SVCI[2] */
+#define VC_LOOP_ENABLE 0x08 /* SVCI[3] or SACI[3]*/
+#define VC_BI_LOOP 0x10 /* SVCI[4] or SACI[4]*/
+#define VOICE_OFFSET 0x20 /* SMSI[5] */
+#define VOLUME_RATE0 0x00 /* SVRI[7:6]=(0,0) */
+#define VOLUME_RATE1 0x40 /* SVRI[7:6]=(0,1) */
+#define VOLUME_RATE2 0x80 /* SVRI[7:6]=(1,0) */
+#define VOLUME_RATE3 0xC0 /* SVRI[7:6]=(1,1) */
+/*#######################################################################*/
+/**/
+/* Power-Mode Control Defines*/
+/**/
+/*#######################################################################*/
+#define SHUT_DOWN 0x7E /* shuts InterWave down */
+#define POWER_UP 0xFE /* enables all modules */
+#define CODEC_PWR_UP 0x81 /* enables Codec Analog Ckts */
+#define CODEC_PWR_DOWN 0x01 /* disables Codec Analog Ckts */
+#define CODEC_REC_UP 0x82 /* Enables Record Path */
+#define CODEC_REC_DOWN 0x02 /* Disables Record Path */
+#define CODEC_PLAY_UP 0x84 /* Enables Playback Path */
+#define CODEC_PLAY_DOWN 0x04 /* Disables Playback Path */
+#define CODEC_IRQ_ENABLE 0x02 /* CEXTI[2] */
+#define CODEC_TIMER_IRQ 0x40 /* CSR3I[6] */
+#define CODEC_REC_IRQ 0x20 /* CSR3I[5] */
+#define CODEC_PLAY_IRQ 0x10 /* CSR3I[4] */
+#define CODEC_INT 0x01 /* CSR1R[0] */
+#define MONO_INPUT 0x80 /* CMONOI[7] */
+#define MONO_OUTPUT 0x40 /* CMONOI[6] */
+#define MIDI_UP 0x88 /* Enables MIDI ports */
+#define MIDI_DOWN 0x08 /* Disables MIDI ports */
+#define SYNTH_UP 0x90 /* Enables Synthesizer */
+#define SYNTH_DOWN 0x10 /* Disables Synthesizer */
+#define LMC_UP 0xA0 /* Enables LM Module */
+#define LMC_DOWN 0x20 /* Disbales LM Module */
+#define XTAL24_UP 0xC0 /* Enables 24MHz Osc */
+#define XTAL24_DOWN 0x40 /* Disables 24MHz Osc */
+#define _PPWRI 0xF2 /* PPWRI index */
+#define PLAY 0x0F
+#define REC 0x1F
+#define LEFT_AUX1_INPUT 0x02
+#define RIGHT_AUX1_INPUT 0x03
+#define LEFT_AUX2_INPUT 0x04
+#define RIGHT_AUX2_INPUT 0x05
+#define LEFT_LINE_IN 0x12
+#define RIGHT_LINE_IN 0x13
+#define LEFT_LINE_OUT 0x19
+#define RIGHT_LINE_OUT 0x1B
+#define LEFT_SOURCE 0x00
+#define RIGHT_SOURCE 0x01
+#define LINE_IN 0x00
+#define AUX1_IN 0x40
+#define MIC_IN 0x80
+#define MIX_IN 0xC0
+#define LEFT_DAC 0x06
+#define RIGHT_DAC 0x07
+#define LEFT_MIC_IN 0x16
+#define RIGHT_MIC_IN 0x17
+#define _CUPCTI 0x0E
+#define _CLPCTI 0x0F
+#define _CURCTI 0x1E
+#define _CLRCTI 0x1F
+#define _CLAX1I 0x02
+#define _CRAX1I 0x03
+#define _CLAX2I 0x04
+#define _CRAX2I 0x05
+#define _CLLICI 0x12
+#define _CRLICI 0x13
+#define _CLOAI 0x19
+#define _CROAI 0x1B
+#define _CLICI 0x00
+#define _CRICI 0x01
+#define _CLDACI 0x06
+#define _CRDACI 0x07
+#define _CPVFI 0x1D
+/*#######################################################################*/
+/**/
+/* Defines for DMA transfer related operations*/
+/**/
+/*#######################################################################*/
+#define MAX_DMA 0x07
+#define DMA_DECREMENT 0x20
+#define AUTO_INIT 0x10
+#define DMA_READ 0x01
+#define DMA_WRITE 0x02
+#define AUTO_READ 0x03
+#define AUTO_WRITE 0x04
+#define IDMA_INV 0x0400
+#define IDMA_WIDTH_16 0x0100
+/*#######################################################################*/
+/**/
+/* Bits for dma flags within a DMA structure.*/
+/**/
+/*#######################################################################*/
+#define DMA_USED 0x0001
+
+#define DMA_SPLIT 0x0004 /* DMA Controller Page Crossover*/
+#define CODEC_DMA 0x0008 /* Indicates a Codec DMA*/
+#define DMA_WAIT 0x0020 /* Wait for DMA xfer to complete*/
+#define DMA_DOWN 0x0040 /* DMA xfer from PC to InterWave*/
+#define DRAM_HOLES 0x8000 /* Indicates Non-contiguous RAM configuration*/
+#define DMA_UP 0xFFBF /* DMA xfer from InterWave to PC */
+/*#######################################################################*/
+/**/
+/* Bits for DMA Control Register (LDMACI)*/
+/**/
+/*#######################################################################*/
+#define _LDMACI 0x41 /* Index */
+#define DMA_INV 0x80
+#define DMA_IRQ_ENABLE 0x20
+#define DMA_IRQ_PENDING 0x40 /* on reads of LDMACI[6] */
+#define DMA_DATA_16 0x40 /* on writes to LDMACI[6] */
+#define DMA_WIDTH_16 0x04 /* 1=16-bit, 0=8-bit (DMA channel) */
+#define DMA_RATE 0x18 /* 00=fastest,...,11=slowest */
+#define DMA_UPLOAD 0x02 /* From LM to PC */
+#define DMA_ENABLE 0x01
+/*#######################################################################*/
+/**/
+/* DMA Transfer Rates*/
+/**/
+/*#######################################################################*/
+#define DMA_R0 0xE7 /* Fastest (use ANDing to set) */
+#define DMA_R1 0x08
+#define DMA_R2 0x10
+#define DMA_R3 0x18 /* Slowest */
+/*#######################################################################*/
+/**/
+/* Interrupt Controller Defines*/
+/**/
+/*#######################################################################*/
+#define IW_HANDLERS_ON 0x80 /* Flag for when IVT is modified */
+#define EOI 0x20
+#define OCR1 0x20 /* 8259-1 Operation Control Reg. */
+#define IMR1 0x21 /* 8259-1 Interrupt Mask Reg. */
+#define OCR2 0xA0 /* 8259-2 Operation Control Reg. */
+#define IMR2 0xA1 /* 8259-2 Interrupt Mask Reg. */
+#define IRQ0_UNMASK 0xFE /* Mask to clear bit 0 in IMR */
+#define IRQ1_UNMASK 0xFD
+#define IRQ2_UNMASK 0xFB
+#define IRQ3_UNMASK 0xF7
+#define IRQ4_UNMASK 0xEF
+#define IRQ5_UNMASK 0xDF
+#define IRQ6_UNMASK 0xBF
+#define IRQ7_UNMASK 0x7F
+#define IRQ8_UNMASK 0xFE /* Mask to clear bit 0 in IMR */
+#define IRQ9_UNMASK 0xFD
+#define IRQ10_UNMASK 0xFB
+#define IRQ11_UNMASK 0xF7
+#define IRQ12_UNMASK 0xEF
+#define IRQ13_UNMASK 0xDF
+#define IRQ14_UNMASK 0xBF
+#define IRQ15_UNMASK 0x7F
+#define IRQ0_EOI 0x60 /* Spec EOI for IRQ0 */
+#define IRQ1_EOI 0x61
+#define IRQ2_EOI 0x62
+#define IRQ3_EOI 0x63
+#define IRQ4_EOI 0x64
+#define IRQ5_EOI 0x65
+#define IRQ6_EOI 0x66
+#define IRQ7_EOI 0x67
+#define IRQ8_EOI 0x60 /* Spec EOI for IRQ8 */
+#define IRQ9_EOI 0x61
+#define IRQ10_EOI 0x62
+#define IRQ11_EOI 0x63
+#define IRQ12_EOI 0x64
+#define IRQ13_EOI 0x65
+#define IRQ14_EOI 0x66
+#define IRQ15_EOI 0x67
+/*#######################################################################*/
+/**/
+/* Generic defines*/
+/**/
+/*#######################################################################*/
+/**/
+#define MEMBANK0 0L /* Addr of Memory Bank 0*/
+#define MEMBANK1 4194304L /* Addr of Memory Bank 1*/
+#define MEMBANK2 8388608L /* Addr of Memory Bank 2*/
+#define MEMBANK3 12582912L /* Addr of Memory Bank 3*/
+#define IRQ_UNAVAIL 0x0000
+#define IRQ_AVAIL 0x0001
+#define IRQ_USED 0x0002
+#define MAX_IRQ 16
+#define NEXT_OFFSET 0L
+#define PREV_OFFSET 4L
+#define SIZE_OFFSET 8L
+#define MEM_HEADER_SIZE 12L
+#define GF1_POOL (usigned long)(256L*1024L)
+#define GUS_MODE 0x00 /* SGMI[0]=0*/
+#define ENH_MODE 0x01 /* SGMI[0]=1*/
+#define ENABLE_LFOS 0x02 /* SGMI[1]*/
+#define NO_WAVETABLE 0x04 /* SGMI[2]*/
+#define RAM_TEST 0x08 /* SGMI[3]*/
+#define TRUE 1
+#define FALSE 0
+#define ON 1
+#define OFF 0
+#define AUDIO 0
+#define EXT 1
+#define GAME 2
+#define EMULATION 3
+#define MPU401 4
+#define AUDIO_EXT 2
+#define ALLOC_FAILURE 0xFFFFFFFFL
+#define MEM_EXHAUSTED 0xFFFFFFFFL
+#define RAM_MAX 16777216L
+#define RAM_STEP 65536L
+#define BANK_MAX 4194304L
+#define ILLEGAL_SIZE -1
+#define MEM_INIT 1
+#define NO_NEXT 0xFFFFFFFFL
+#define NO_PREV NO_NEXT
+#define DMA_BAD_ADDR -1
+#define DMA_ON -1
+#define DMA_OK 1
+#define MIDI_TX_IRQ 0x01
+#define MIDI_RX_IRQ 0x02
+#define ALIB_TIMER1_IRQ 0x04
+#define ALIB_TIMER2_IRQ 0x08
+#define WAVETABLE_IRQ 0x20
+#define ENVELOPE_IRQ 0x40
+#define DMA_TC_IRQ 0x80
+#define DMA_SET_MASK 0x04
+#define PNP_DATA_RDY 1 /* PRESSI[0] */
+#define IWAVE_ABSENT 2
+#define IWAVE_OPEN 4
+#define IWAVE_OK 5
+#define BAD_VOICES -1
+#define PNP_ABSENT 0xFF /* No PNP cards in system */
+#define DPMI_INT 0x31
+#define _PCCCI 0x02
+#define _PCSNI 0x06
+#define _PIDXR 0x279
+#define _PNPWRP 0xA79
+#define _LDSALI 0x42
+#define _LDSAHI 0x50
+#define _LMALI 0x43
+#define _LMAHI 0x44
+#define _LMCFI 0x52
+#define _LMCI 0x53
+#define _LDIBI 0x58
+#define _LDICI 0x57
+#define _LMSBAI 0x51
+#define _SVCI_RD 0x8D
+#define _SVCI_WR 0x0D
+#define _SACI_RD 0x80
+#define _SACI_WR 0x00
+#define _SALI_RD 0x8B
+#define _SALI_WR 0x0B
+#define _SAHI_RD 0x8A
+#define _SAHI_WR 0x0A
+#define _SASHI_RD 0x82
+#define _SASHI_WR 0x02
+#define _SASLI_RD 0x83
+#define _SASLI_WR 0x03
+#define _SAEHI_RD 0x84
+#define _SAEHI_WR 0x04
+#define _SAELI_RD 0x85
+#define _SAELI_WR 0x05
+#define _SVRI_RD 0x86
+#define _SVRI_WR 0x06
+#define _SVSI_RD 0x87
+#define _SVSI_WR 0x07
+#define _SVEI_RD 0x88
+#define _SVEI_WR 0x08
+#define _SVLI_RD 0x89
+#define _SVLI_WR 0x09
+#define _SROI_RD 0x8C
+#define _SROI_WR 0x0C
+#define _SLOI_RD 0x93
+#define _SLOI_WR 0x13
+#define _SMSI_RD 0x95
+#define _SMSI_WR 0x15
+#define _SGMI_RD 0x99
+#define _SGMI_WR 0x19
+#define _SFCI_RD 0x81
+#define _SFCI_WR 0x01
+#define _SUAI_RD 0x90
+#define _SUAI_WR 0x10
+#define _SVII 0x8F
+#define _CMODEI 0x0C /* index for CMODEI */
+#define _CFIG3I 0x11
+#define _CFIG2I 0x10
+#define _CLTIMI 0x14
+#define _CUTIMI 0x15
+#define _CSR3I 0x18 /* Index to CSR3I (Interrupt Status) */
+#define _CEXTI 0x0A /* Index to External Control Register */
+#define _CFIG1I 0x09 /* Index to Codec Conf Reg 1 */
+#define _CSR2I 0x0B /* Index to Codec Stat Reg 2 */
+#define _CPDFI 0x08 /* Index to Play Data Format Reg */
+#define _CRDFI 0x1C /* Index to Rec Data Format Reg */
+#define _CLMICI 0x16 /* Index to Left Mic Input Ctrl Register */
+#define _CRMICI 0x17 /* Index to Right Mic Input Ctrl Register */
+#define _CLCI 0x0D /* Index to Loopback Ctrl Register */
+#define _IVERI 0x5B /* Index to register IVERI */
+#define CODEC_MODE1 0x00
+#define CODEC_MODE2 0x40
+#define CODEC_MODE3 0x6C /* Enhanced Mode */
+#define CODEC_STATUS1 0x01
+#define CODEC_STATUS2 0x0B /* Index to CSR2I */
+#define CODEC_STATUS3 0x18 /* Index to CSR3I */
+#define PLAYBACK 0x01 /* Enable playback path CFIG1I[0]=1*/
+#define RECORD 0x02 /* Enable Record path CFIG1I[1]=1*/
+#define TIMER_ENABLE 0x40 /* CFIG2I[6] */
+#define CODEC_MCE 0x40 /* CIDXR[6] */
+#define CALIB_IN_PROGRESS 0x20 /* CSR2I[5] */
+#define CODEC_INIT 0x80 /* CIDXR[7] */
+#define BIT16_BIG 0xC0 /* 16-bit signed, big endian */
+#define IMA_ADPCM 0xA0 /* IMA-compliant ADPCM */
+#define BIT8_ALAW 0x60 /* 8-bit A-law */
+#define BIT16_LITTLE 0x40 /* 16-bit signed, lillte endian */
+#define BIT8_ULAW 0x20 /* 8-bit u-law */
+#define BIT8_LINEAR 0x00 /* 8-bit unsigned */
+#define REC_DFORMAT 0x1C
+#define PLAY_DFORMAT 0x08
+#define DMA_ACCESS 0x00
+#define PIO_ACCESS 0xC0
+#define DMA_SIMPLEX 0x04
+#define STEREO 0x10 /* CxDFI[4] */
+#define XTAL1 0x00 /* CxDFI[4]=0 selects 24.5Mhz XTAL */
+#define XTAL2 0x01 /* CxDFI[4]=1 selects 16.9Mhz XTAL */
+#define AUTOCALIB 0x08 /* CFIG1I[3] */
+#define ROM_IO 0x02 /* ROM I/O cycles - LMCI[1]=1 */
+#define DRAM_IO 0x4D /* DRAM I/O cycles - LMCI[1]=0 */
+#define AUTOI 0x01 /* LMCI[0]=1 */
+#define _PLDNI 0x07
+#define ACTIVATE_DEV 0x30
+#define _PWAKEI 0x03 /* Index for PWAKEI */
+#define _PISOCI 0x01 /* Index for PISOCI */
+#define _PSECI 0xF1 /* Index for PSECI */
+#define RANGE_IOCHK 0x31 /* PURCI or PRRCI Index */
+#define MIDI_RESET 0x03
+#define IO_OK 5 /* No IO conflict flag */
+#define IO_CONFLICT 6 /* IO Conflict detected */
+#define IO_0x55 0x01
+#define IO_0xAA 0xFE
+/*#######################################################################*/
+/**/
+/* Defines for Sound Handlers in "iw".*/
+/**/
+/*#######################################################################*/
+#define PLAY_DMA_HANDLER 0x01
+#define REC_DMA_HANDLER 0x02
+#define MIDI_TX_HANDLER 0x03
+#define MIDI_RX_HANDLER 0x04
+#define TIMER1_HANDLER 0x05
+#define TIMER2_HANDLER 0x06
+#define WAVE_HANDLER 0x07
+#define VOLUME_HANDLER 0x08
+#define CODEC_TIMER_HANDLER 0x09
+#define CODEC_PLAY_HANDLER 0x0A
+#define CODEC_REC_HANDLER 0x0B
+#define AUX_HANDLER 0x0C
+/*#######################################################################*/
+/**/
+/* Mapping for System Control Regs.*/
+/**/
+/*#######################################################################*/
+#define UMCR 0x00010000 /* Mix Control Reg.*/
+#define UISR 0x00020006 /* IRQ Stat Reg. (read) */
+#define U2X6R 0x00030006 /* SB 2X6 reg */
+#define UACWR 0x00040008 /* AdLib Command Write Reg */
+#define UASRR 0x00050008 /* AdLib Stat Read Reg */
+#define UADR 0x00060009 /* AdLib Data Register */
+#define UACRR 0x0007000A /* AdLib Cmd Read Reg */
+#define UASWR 0x0008000A /* AdLib Stat Write Reg */
+#define UHRDP 0x0009000B /* Hidden Reg Data Port */
+#define UI2XCR 0x000A000C /* SB IRQ 2xC Reg */
+#define U2XCR 0x000B000D /* SB 2xC Reg. (No IRQ) */
+#define U2XER 0x000C000E /* SB 2xE Reg. */
+#define URCR 0x000D000F /* Reg Control Register */
+#define USRR 0x000E000F /* Status Read Register */
+#define UDCI 0x000F000B /* DMA Channel Control Reg */
+#define UICI 0x0010000B /* Interrupt Ctrl Reg */
+#define UGP1I 0x0011010B /* GP Reg 1 (Back Door) */
+#define UGP2I 0x0012020B /* GP Reg 2 (Back Door) */
+#define UGPA1I 0x0013030B /* GP reg 1 Address */
+#define UGPA2I 0x0014040B /* GP reg 2 Address */
+#define UCLRII 0x0015050B /* Clear Interrupt Reg */
+#define UJMPI 0x0016060B /* Jumper Register */
+#define UGP1II 0x0017000B /* Gen. Purp Reg 1(Emulation) */
+#define UGP2II 0x0018000B /* Gen. Purp Reg 2(Emulation) */
+#define GGCR 0x00190201 /* Game Control Register */
+#define GMCR 0x001A0000 /* MIDI Control Register */
+#define GMSR 0x001B0000 /* MIDI Status Reg. */
+#define GMTDR 0x001C0001 /* MIDI xmit data reg */
+#define GMRDR 0x001D0001 /* MIDI rcv data reg */
+#define SVSR 0x001E0002 /* Synth Voice Select Reg */
+#define IGIDXR 0x001F0003 /* General Index Register */
+#define I16DP 0x00200004 /* General 16-bit Data Port */
+#define I8DP 0x00210005 /* General 8-bit Data Port */
+/*#######################################################################*/
+/**/
+/* Synth defines*/
+/**/
+/*#######################################################################*/
+#define SACI 0x00220005 /* Synth Addr Control */
+#define SFCI 0x00230104 /* Synth Freq Control */
+#define SASHI 0x00240204 /* Synth Addr Start High */
+#define SASLI 0x00250304 /* Synth Addr Start Low */
+#define SAEHI 0x00260404 /* Synth Addr End High */
+#define SAELI 0x00270504 /* Synth Addr End Low */
+#define SVRI 0x00280605 /* Synth Volume Rate */
+#define SVSI 0x00290705 /* Synth Volume Start */
+#define SVEI 0x002A0805 /* Synth Volume End */
+#define SVLI 0x002B0904 /* Synth Volume Level */
+#define SAHI 0x002C0A04 /* Synth Address High */
+#define SALI 0x002D0B04 /* Synth Address Low */
+#define SROI 0x002E0C04 /* Synth Right Offset */
+#define SVCI 0x002F0D05 /* Synth Volume Control */
+#define SAVI 0x00300E05 /* Synth Active Voices */
+#define SVII 0x00318F05 /* Synth Voice IRQ */
+#define SUAI 0x00321005 /* Synth Upper Addr */
+#define SEAHI 0x00331104 /* Synth Effect Addr High */
+#define SEALI 0x00341204 /* Synth Effect Addr Low */
+#define SLOI 0x00351304 /* Synth Left Offset */
+#define SEASI 0x00361405 /* Synth Effects Accum Sel */
+#define SMSI 0x00371505 /* Synth Mode Select */
+#define SEVI 0x00381604 /* Synth Effect Volume */
+#define SFLFOI 0x00391705 /* Synth Freq LFO */
+#define SVLFOI 0x003A1805 /* Synth Vol LFO */
+#define SGMI 0x003B1905 /* Synth Global Mode */
+#define SLFOBI 0x003C1A04 /* Synth LFO Base Address */
+#define SROFI 0x003D1B04
+#define SLOFI 0x003E1C04
+#define SEVFI 0x003F1D04
+#define SVIRI 0x00409F05 /* Synth Voice Read IRQ */
+#define LDMACI 0x00414105 /* DMA Control Reg. */
+#define LDSALI 0x00424204 /* LMC DMA Start Addr. Low Reg. */
+#define LMALI 0x00434304 /* LMC Addr Low (I/O) */
+#define LMAHI 0x00444405 /* LMC Addr High (I/O) */
+#define UASBCI 0x00454505 /* Adlib-SB Control */
+#define UAT1I 0x00464605 /* AdLib Timer 1 Count */
+#define UAT2I 0x00474705 /* AdLib Timer 2 Count */
+#define USCI 0x00484905 /* Sample Control Reg */
+#define GJTDI 0x00494B05
+#define URSTI 0x004A4C05
+#define LDSAHI 0x004B5005
+#define LMSBAI 0x004C5104
+#define LMCFI 0x004D5204
+#define LMCI 0x004E5305
+#define LMRFAI 0x004F5404
+#define LMPFAI 0x00505504
+#define LMSFI 0x00515604
+#define LDICI 0x00525704
+#define LDIBI 0x00535804
+#define ICMPTI 0x00545905
+#define IDECI 0x00555A05
+#define IVERI 0x00565B05
+#define IEMUAI 0x00575C05
+#define IEMUBI 0x00585D05
+#define GMRFAI 0x00595E05
+#define ITCI 0x005A5F05
+#define IEIRQI 0x005B6005
+#define LMBDR 0x005C0007
+/*##########################################################*/
+/* Mnemonics for Codec Registers*/
+/*##########################################################*/
+#define CIDXR 0x005D0000
+#define CDATAP 0x005E0001
+#define CSR1R 0x005F0002
+#define CPDR 0x00600003
+#define CRDR 0x00610003
+#define CLICI 0x00620001
+#define CRICI 0x00630101
+#define CLAX1I 0x00640201
+#define CRAX1I 0x00650301
+#define CLAX2I 0x00660401
+#define CRAX2I 0x00670501
+#define CLDACI 0x00680601
+#define CRDACI 0x00690701
+#define CPDFI 0x006A0801
+#define CFIG1I 0x006B0901
+#define CEXTI 0x006C0A01
+#define CSR2I 0x006D0B01
+#define CMODEI 0x006E0C01
+#define CLCI 0x006F0D01
+#define CUPCTI 0x00700E01
+#define CLPCTI 0x00710F01
+#define CFIG2I 0x00721001
+#define CFIG3I 0x00731101
+#define CLLICI 0x00741201
+#define CRLICI 0x00751301
+#define CLTIMI 0x00761401
+#define CUTIMI 0x00771501
+#define CLMICI 0x00781601
+#define CRMICI 0x00791701
+#define CSR3I 0x007A1801
+#define CLOAI 0x007B1901
+#define CMONOI 0x007C1A01
+#define CROAI 0x007D1B01
+#define CRDFI 0x007E1C01
+#define CPVFI 0x007F1D01
+#define CURCTI 0x00801E01
+#define CLRCTI 0x00811F01
+/*##########################################################*/
+/* Mnemonics for PnP Registers*/
+/*##########################################################*/
+#define PCSNBR 0x00820201
+#define PIDXR 0x00830279
+#define PNPWRP 0x00840A79
+#define PNPRDP 0x00850000
+#define PSRPAI 0x00860000
+#define PISOCI 0x00870100
+#define PCCCI 0x00880200
+#define PWAKEI 0x00890300
+#define PRESDI 0x008A0400
+#define PRESSI 0x008B0500
+#define PCSNI 0x008C0600
+#define PLDNI 0x008D0700
+#define PUACTI 0x008E3000
+#define PURCI 0x008F3100
+#define P2X0HI 0x00906000
+#define P2X0LI 0x00916100
+#define P3X0HI 0x00926200
+#define P3X0LI 0x00936300
+#define PHCAI 0x00946400
+#define PLCAI 0x00956500
+#define PUI1SI 0x00967000
+#define PUI1TI 0x00977100
+#define PUI2SI 0x00987200
+#define PUI2TI 0x00997300
+#define PUD1SI 0x009A7400
+#define PUD2SI 0x009B7500
+#define PSEENI 0x009CF000
+#define PSECI 0x009DF100
+#define PPWRI 0x009EF200
+#define PRACTI 0x009F3001
+#define PRRCI 0x00A03101
+#define PRAHI 0x00A16001
+#define PRALI 0x00A26101
+#define PATAHI 0x00A36201
+#define PATALI 0x00A46301
+#define PRISI 0x00A57001
+#define PRITI 0x00A67101
+#define PRDSI 0x00A77401
+#define PGACTI 0x00A83002
+#define PGRCI 0x00A93102
+#define P201HI 0x00AA6002
+#define P201LI 0x00AB6102
+#define PSACTI 0x00AC3003
+#define PSRCI 0x00AD3103
+#define P388HI 0x00AE6003
+#define P388LI 0x00AF6103
+#define PSBISI 0x00B07003
+#define PSBITI 0x00B17103
+#define PMACTI 0x00B23004
+#define PMRCI 0x00B33104
+#define P401HI 0x00B46004
+#define P401LI 0x00B56104
+#define PMISI 0x00B67004
+#define PMITI 0x00B77104
+
+typedef unsigned char BYTE;
+typedef unsigned short WORD;
+typedef unsigned short PORT;
+typedef unsigned long DWORD;
+typedef unsigned long ADDRESS;
+typedef int BOOL;
+typedef int FLAG;
+
+typedef struct
+ {
+ short flags; /* InterWave stat flags */
+ PORT pcodar; /* Base Port for Codec */
+ PORT pcdrar; /* Base Port for Ext Device */
+ PORT p2xr; /* Compatibility Base Port */
+ PORT p3xr; /* MIDI and Synth Base Port */
+ PORT p401ar; /* Gen Purpose Reg. 1 address */
+ PORT p201ar; /* Game Ctrl normally at 0x201 */
+ PORT pataar; /* Base Address for ATAPI I/O Space */
+ PORT p388ar; /* Base Port for AdLib. It should be 388h */
+ PORT pnprdp; /* PNP read data port */
+ PORT igidxr; /* Gen Index Reg at P3XR+0x03 */
+ PORT i16dp; /* 16-bit data port at P3XR+0x04 */
+ PORT i8dp; /* 8-bit data port at P3XR+0x05 */
+ PORT svsr; /* Synth Voice Select at P3XR+0x02 */
+ PORT cdatap; /* Codec Indexed Data Port at PCODAR+0x01 */
+ PORT csr1r; /* Codec Stat Reg 1 at PCODAR+0x02 */
+ PORT cxdr; /* Play or Record Data Reg at PCODAR+0x03 */
+ PORT gmxr; /* GMCR or GMSR at P3XR+0x00 */
+ PORT gmxdr; /* GMTDR or GMRDR at P3XR+0x01 */
+ PORT lmbdr; /* LMBDR at P3XR+0x07 */
+ BYTE csn; /* Card Select Number */
+ BYTE cmode; /* Codec Operation Mode */
+ int dma1_chan; /* DMA channel 1 (local DMA & codec rec) */
+ int dma2_chan; /* DMA channel 2 (codec play) */
+ int ext_chan; /* Ext Dev DMA channel */
+ BYTE voices; /* Number of active voices */
+ DWORD vendor; /* Vendor ID and Product Identifier */
+ int synth_irq; /* Synth IRQ number */
+ int midi_irq; /* MIDI IRQ number */
+ int ext_irq; /* Ext Dev IRQ */
+ int mpu_irq; /* MPU401 Dev IRQ */
+ int emul_irq; /* Sound Blaster/AdLib Dev IRQ */
+ ADDRESS free_mem; /* Address of First Free LM Block */
+ DWORD reserved_mem; /* Amount of LM reserved by app. */
+ BYTE smode; /* Synth Mode */
+ WORD size_mem; /* Total LM in Kbytes */
+
+ } IWAVE;
+
+#endif
diff --git a/sys/i386/isa/sound/local.h b/sys/i386/isa/sound/local.h
index fe78b4c..8c86bd8 100644
--- a/sys/i386/isa/sound/local.h
+++ b/sys/i386/isa/sound/local.h
@@ -1,138 +1,171 @@
-/* for FreeBSD */
/*
- * $Id: local.h,v 1.11 1994/11/01 17:26:50 ache Exp
+ * local.h
+ *
+ * This file was generated by configure. But then HAND-EDITED. It will
+ * probably disappear in future revisions once the configuration process
+ * will become more like that of standard bsd code.
+ * lr 970714
+ *
*/
-#ifdef PC98
-/* If a soundcard uses DMA AUTO mode, DPS_BUFFSIZE must be < 64KB. */
-#define DSP_BUFFSIZE 61440
-#else
-#define DSP_BUFFSIZE 65536
-#endif
-#define SELECTED_SOUND_OPTIONS 0xffffffff
-#define SOUND_CONFIG_DATE "Sun Feb 5 14:38:12 EST 1995"
-#define SOUND_CONFIG_BY "freebsd-hackers"
-#define SOUND_CONFIG_HOST "freefall"
-#define SOUND_CONFIG_DOMAIN "cdrom.com"
+/* build hex2hex /tmp/foo.x trix_boot.h trix_boot */
+
+/*
+ * make everything conditioned on NSND>0 so as to detect errors
+ * because of missing "controller snd0" statement
+ */
+#define ALLOW_BUFFER_MAPPING 1
-/* determine if sound code should be compiled */
#include "snd.h"
#if NSND > 0
-#define KERNEL_SOUNDCARD
-#endif
+#define CONFIGURE_SOUNDCARD
-#define ALLOW_SELECT
-
-/* PSS code does not work */
-#ifndef EXCLUDE_PSS
-#define EXCLUDE_PSS
-#endif
+#define CONFIG_SEQUENCER
#include "gus.h"
-#if NGUS == 0 && !defined(EXCLUDE_GUS)
-#define EXCLUDE_GUS
-#endif
-
-#include "gusxvi.h"
-#if NGUSXVI == 0 && !defined(EXCLUDE_GUS16)
-#define EXCLUDE_GUS16
-#endif
-
-#include "mss.h"
-#if NMSS == 0 && !defined(EXCLUDE_MSS)
-#define EXCLUDE_MSS
+#if NGUS != 0 && !defined(CONFIG_GUS)
+#define CONFIG_GUS
+#define CONFIG_GUSMAX
#endif
#include "trix.h"
-#if NTRIX == 0 && !defined(EXCLUDE_TRIX)
-#define EXCLUDE_TRIX
+#if NTRIX > 0
+#define INCLUDE_TRIX_BOOT
+#define CONFIG_TRIX /* can use NTRIX > 0 instead */
+#define CONFIG_YM3812
#endif
-#include "sscape.h"
-#if NSSCAPE == 0 && !defined(EXCLUDE_SSCAPE)
-#define EXCLUDE_SSCAPE
+#if defined(CONFIG_GUSMAX) || ( NTRIX > 0 )
+#define CONFIG_AD1848
#endif
-#if NGUS == 0 && !defined(EXCLUDE_GUSMAX)
-# define EXCLUDE_GUSMAX
-# if defined(EXCLUDE_GUS16) && defined(EXCLUDE_MSS) && !defined(EXCLUDE_AD1848)
-# define EXCLUDE_AD1848
-# endif
-#else
-# define GUSMAX_MIXER
+#if defined(CONFIG_SEQUENCER) && (NTRIX == 0)
+#define CONFIG_MIDI
#endif
#include "sb.h"
-#if NSB == 0 && !defined(EXCLUDE_SB)
-#define EXCLUDE_SB
+#if NSB > 0
+#define CONFIG_SB
+#endif
+
+#include "mss.h"
+#if NMSS != 0
+#define CONFIG_AD1848
+#define CONFIG_MSS
+#undef CONFIG_CS4232
#endif
#include "sbxvi.h"
-#if NSBXVI == 0 && !defined(EXCLUDE_SB16)
-#define EXCLUDE_SB16
+#if NSBXVI != 0 && !defined(CONFIG_SB16)
+#define CONFIG_SB16
+#define CONFIG_SBPRO /* FIXME: Also needs to be a sep option */
#endif
#include "sbmidi.h"
-#if NSBMIDI == 0 && !defined(EXCLUDE_SB16MIDI)
-#define EXCLUDE_SB16MIDI
+#if NSBMIDI != 0 && !defined(CONFIG_SB16MIDI)
+#define CONFIG_SB16MIDI
#endif
#include "awe.h"
-#if NAWE == 0 && !defined(EXCLUDE_AWE32)
-#define EXCLUDE_AWE32
+#if NAWE != 0 && !defined(CONFIG_AWE32)
+#define CONFIG_AWE32
#endif
#include "pas.h"
-#if NPAS == 0 && !defined(EXCLUDE_PAS)
-#define EXCLUDE_PAS
+#if NPAS != 0 && !defined(CONFIG_PAS)
+#define CONFIG_PAS
#endif
#include "mpu.h"
-#if NMPU == 0 && !defined(EXCLUDE_MPU401)
-#define EXCLUDE_MPU401
+#if NMPU != 0 && !defined(CONFIG_MPU401)
+#define CONFIG_MPU401
#endif
-
+
#include "opl.h"
-#if NOPL == 0 && !defined(EXCLUDE_YM3812)
-#define EXCLUDE_YM3812
+#if NOPL != 0 && !defined(CONFIG_YM3812)
+#define CONFIG_YM3812
#endif
-#include "uart.h"
-#if NUART == 0 && !defined(EXCLUDE_UART6850)
-#define EXCLUDE_UART6850
+#include "sscape.h"
+
+#define ALLOW_SELECT
+
+/* #undef CONFIG_PAS */
+/* #undef CONFIG_ADLIB */
+/* #define CONFIG_GUS */
+/* #undef CONFIG_MPU401 */
+#undef CONFIG_UART6850
+#undef CONFIG_PSS
+#undef CONFIG_GUS16
+/* #undef CONFIG_MSS */
+/* #undef CONFIG_SSCAPE */
+#undef CONFIG_MAD16
+/* #undef CONFIG_CS4232 */
+#undef CONFIG_MAUI
+#undef CONFIG_PNP
+/* #undef CONFIG_SBPRO */
+/* #undef CONFIG_SB16 */
+#undef CONFIG_AEDSP16
+#define CONFIG_AUDIO /* obvious ? */
+
+#define CONFIG_MPU_EMU
+
+#define DSP_BUFFSIZE 32768*2
+/* #define SELECTED_SOUND_OPTIONS 0x0188090a */
+
+#ifndef TRIX_SB_BASE
+#define TRIX_SB_BASE 0x220
+#endif
+
+#ifndef TRIX_SB_IRQ
+#define TRIX_SB_IRQ 7
#endif
-#ifdef PC98
-#include "pcm.h"
-#if NPCM == 0 && !defined(EXCLUDE_PCM86)
-#define EXCLUDE_PCM86
+#ifndef TRIX_SB_DMA
+#define TRIX_SB_DMA 1
#endif
+
+#ifndef TRIX_BASE
+#define TRIX_BASE 0x530
#endif
+#ifndef TRIX_IRQ
+#define TRIX_IRQ 9
+#endif
-/* nothing but a sequencer (Adlib/OPL) ? */
-#if NGUS == 0 && NSB == 0 && NSBMIDI == 0 && NPAS == 0 && NMPU == 0 && \
- NUART == 0 && NMSS == 0
-#ifndef EXCLUDE_MIDI
-#define EXCLUDE_MIDI
+#ifndef TRIX_DMA
+#define TRIX_DMA 3
#endif
-#ifndef EXCLUDE_AUDIO
-#if !defined(PC98) || defined(EXCLUDE_PCM86) && defined(EXCLUDE_MSS)
-#define EXCLUDE_AUDIO
+
+#ifndef TRIX_DMA2
+#define TRIX_DMA2 1
#endif
+
+#ifndef GUS_BASE
+#define GUS_BASE 0x220
#endif
+
+#ifndef GUS_IRQ
+#define GUS_IRQ 12
#endif
-/* nothing but a Midi (MPU/UART) ? */
-#if NGUS == 0 && NSB == 0 && NSBMIDI == 0 && NPAS == 0 && NOPL == 0 && \
- NMSS == 0
-/* MPU depends on sequencer timer */
-#if NMPU == 0 && !defined(EXCLUDE_SEQUENCER)
-#define EXCLUDE_SEQUENCER
+#ifndef GUS_MIDI_IRQ
+#define GUS_MIDI_IRQ GUS_IRQ
#endif
-#ifndef EXCLUDE_AUDIO
-#if !defined(PC98) || defined(EXCLUDE_PCM86) && defined(EXCLUDE_MSS)
-#define EXCLUDE_AUDIO
+
+#ifndef GUS_DMA
+#define GUS_DMA 4
#endif
+
+#ifndef GUS_DMA2
+#define GUS_DMA2 4
#endif
+
+#define SOUND_CONFIG_DATE "Wed Aug 6 22:58:35 PDT 1997"
+#define SOUND_CONFIG_BY "Amancio Hasty"
+#define SOUND_CONFIG_HOST "rah"
+#define SOUND_CONFIG_DOMAIN "star-gate.com"
+
+#else /* NSND = 0 */
+#undef CONFIGURE_SOUNDCARD
#endif
diff --git a/sys/i386/isa/sound/mad16.c b/sys/i386/isa/sound/mad16.c
new file mode 100644
index 0000000..0e2064a
--- /dev/null
+++ b/sys/i386/isa/sound/mad16.c
@@ -0,0 +1,524 @@
+/*
+ * sound/mad16.c
+ *
+ * Initialization code for OPTi MAD16 compatible audio chips. Including
+ *
+ * OPTi 82C928 MAD16 (replaced by C929) OAK OTI-601D Mozart
+ * OPTi 82C929 MAD16 Pro
+ *
+ * These audio interface chips don't prduce sound themselves. They just connect
+ * some other components (OPL-[234] and a WSS compatible codec) to the PC bus
+ * and perform I/O, DMA and IRQ address decoding. There is also a UART for
+ * the MPU-401 mode (not 82C928/Mozart). The Mozart chip appears to be
+ * compatible with the 82C928 (can anybody confirm this?).
+ *
+ * NOTE! If you want to set CD-ROM address and/or joystick enable, define
+ * MAD16_CONF in local.h as combination of the following bits:
+ *
+ * 0x01 - joystick disabled
+ *
+ * CD-ROM type selection (select just one): 0x00 - none 0x02 - Sony 31A
+ * 0x04 - Mitsumi 0x06 - Panasonic (type "LaserMate", not
+ * "SoundBlaster") 0x08 - Secondary IDE (address 0x170) 0x0a - Primary
+ * IDE (address 0x1F0)
+ *
+ * For example Mitsumi with joystick disabled = 0x04|0x01 = 0x05 For example
+ * LaserMate (for use with sbpcd) plus joystick = 0x06
+ *
+ * MAD16_CDSEL: This defaults to CD I/O 0x340, no IRQ and DMA3 (DMA5 with
+ * Mitsumi or IDE). If you like to change these, define MAD16_CDSEL with the
+ * following bits:
+ *
+ * CD-ROM port: 0x00=340, 0x40=330, 0x80=360 or 0xc0=320 OPL4 select: 0x20=OPL4,
+ * 0x00=OPL3 CD-ROM irq: 0x00=disabled, 0x04=IRQ5, 0x08=IRQ7, 0x0a=IRQ3,
+ * 0x10=IRQ9, 0x14=IRQ10 and 0x18=IRQ11.
+ *
+ * CD-ROM DMA (Sony or Panasonic): 0x00=DMA3, 0x01=DMA2, 0x02=DMA1 or
+ * 0x03=disabled or CD-ROM DMA (Mitsumi or IDE): 0x00=DMA5, 0x01=DMA6,
+ * 0x02=DMA7 or 0x03=disabled
+ *
+ * For use with sbpcd, address 0x340, set MAD16_CDSEL to 0x03 or 0x23.
+ *
+ * Copyright by Hannu Savolainen 1995
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <i386/isa/sound/sound_config.h>
+
+#if defined(CONFIG_MAD16)
+
+static int already_initialized = 0;
+
+#define C928 1
+#define MOZART 2
+#define C929 3
+
+/*
+ * Registers
+ *
+ * The MAD16 occupies I/O ports 0xf8d to 0xf93 (fixed locations). All ports are
+ * inactive by default. They can be activated by writing 0xE2 or 0xE3 to the
+ * password register. The password is valid only until the next I/O read or
+ * write.
+ */
+
+#define MC1_PORT 0xf8d /* SB address, CDROM interface type, joystick */
+#define MC2_PORT 0xf8e /* CDROM address, IRQ, DMA, plus OPL4 bit */
+#define MC3_PORT 0xf8f
+#define PASSWD_REG 0xf8f
+#define MC4_PORT 0xf90
+#define MC5_PORT 0xf91
+#define MC6_PORT 0xf92
+#define MC7_PORT 0xf93
+
+static int board_type = C928;
+
+static sound_os_info *mad16_osp;
+
+#ifndef DDB
+#define DDB(x)
+#endif
+
+static unsigned char
+mad_read(int port)
+{
+ unsigned long flags;
+ unsigned char tmp;
+
+ flags = splhigh();
+
+ switch (board_type) { /* Output password */
+ case C928:
+ case MOZART:
+ outb(PASSWD_REG, 0xE2);
+ break;
+
+ case C929:
+ outb(PASSWD_REG, 0xE3);
+ break;
+ }
+
+ tmp = inb(port);
+ splx(flags);
+
+ return tmp;
+}
+
+static void
+mad_write(int port, int value)
+{
+ unsigned long flags;
+
+ flags = splhigh();
+
+ switch (board_type) { /* Output password */
+ case C928:
+ case MOZART:
+ outb(PASSWD_REG, 0xE2);
+ break;
+
+ case C929:
+ outb(PASSWD_REG, 0xE3);
+ break;
+ }
+
+ outb(port, (unsigned char) (value & 0xff));
+ splx(flags);
+}
+
+static int
+detect_mad16(void)
+{
+ unsigned char tmp, tmp2;
+
+ /*
+ * Check that reading a register doesn't return bus float (0xff) when
+ * the card is accessed using password. This may fail in case the
+ * card is in low power mode. Normally at least the power saving mode
+ * bit should be 0.
+ */
+ if ((tmp = mad_read(MC1_PORT)) == 0xff) {
+ DDB(printf("MC1_PORT returned 0xff\n"));
+ return 0;
+ }
+ /*
+ * Now check that the gate is closed on first I/O after writing the
+ * password. (This is how a MAD16 compatible card works).
+ */
+
+ if ((tmp2 = inb(MC1_PORT)) == tmp) { /* It didn't close */
+ DDB(printf("MC1_PORT didn't close after read (0x%02x)\n", tmp2));
+ return 0;
+ }
+ mad_write(MC1_PORT, tmp ^ 0x80); /* Togge a bit */
+
+ if ((tmp2 = mad_read(MC1_PORT)) != (tmp ^ 0x80)) { /* Compare the bit */
+ mad_write(MC1_PORT, tmp); /* Restore */
+ DDB(printf("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2));
+ return 0;
+ }
+ mad_write(MC1_PORT, tmp); /* Restore */
+ return 1; /* Bingo */
+
+}
+
+int
+probe_mad16(struct address_info * hw_config)
+{
+ int i;
+ static int valid_ports[] =
+ {0x530, 0xe80, 0xf40, 0x604};
+ unsigned char tmp;
+ unsigned char cs4231_mode = 0;
+
+ int ad_flags = 0;
+
+ if (already_initialized)
+ return 0;
+
+ mad16_osp = hw_config->osp;
+ /*
+ * Check that all ports return 0xff (bus float) when no password is
+ * written to the password register.
+ */
+
+ DDB(printf("--- Detecting MAD16 / Mozart ---\n"));
+
+
+ /*
+ * Then try to detect with the old password
+ */
+ board_type = C928;
+
+ DDB(printf("Detect using password = 0xE2\n"));
+
+ if (!detect_mad16()) { /* No luck. Try different model */
+ board_type = C929;
+
+ DDB(printf("Detect using password = 0xE3\n"));
+
+ if (!detect_mad16())
+ return 0;
+
+ DDB(printf("mad16.c: 82C929 detected\n"));
+ } else {
+ unsigned char model;
+
+ if (((model = mad_read(MC3_PORT)) & 0x03) == 0x03) {
+ DDB(printf("mad16.c: Mozart detected\n"));
+ board_type = MOZART;
+ } else {
+ DDB(printf("mad16.c: 82C928 detected???\n"));
+ board_type = C928;
+ }
+ }
+
+ for (i = 0xf8d; i <= 0xf93; i++)
+ DDB(printf("port %03x = %03x\n", i, mad_read(i)));
+
+ /*
+ * Set the WSS address
+ */
+
+ tmp = 0x80; /* Enable WSS, Disable SB */
+
+ for (i = 0; i < 5; i++) {
+ if (i > 3) { /* Not a valid port */
+ printf("MAD16/Mozart: Bad WSS base address 0x%x\n", hw_config->io_base);
+ return 0;
+ }
+ if (valid_ports[i] == hw_config->io_base) {
+ tmp |= i << 4; /* WSS port select bits */
+ break;
+ }
+ }
+
+ /*
+ * Set optional CD-ROM and joystick settings.
+ */
+
+#ifdef MAD16_CONF
+ tmp |= ((MAD16_CONF) & 0x0f); /* CD-ROM and joystick bits */
+#endif
+ mad_write(MC1_PORT, tmp);
+
+#if defined(MAD16_CONF) && defined(MAD16_CDSEL)
+ tmp = MAD16_CDSEL;
+#else
+ tmp = 0x03;
+#endif
+
+#ifdef MAD16_OPL4
+ tmp |= 0x20; /* Enable OPL4 access */
+#endif
+
+ mad_write(MC2_PORT, tmp);
+ mad_write(MC3_PORT, 0xf0); /* Disable SB */
+
+ if (!ad1848_detect(hw_config->io_base + 4, &ad_flags, mad16_osp))
+ return 0;
+
+ if (ad_flags & (AD_F_CS4231 | AD_F_CS4248))
+ cs4231_mode = 0x02; /* CS4248/CS4231 sync delay switch */
+
+ if (board_type == C929) {
+ mad_write(MC4_PORT, 0xa2);
+ mad_write(MC5_PORT, 0xA5 | cs4231_mode);
+ mad_write(MC6_PORT, 0x03); /* Disable MPU401 */
+ } else {
+ mad_write(MC4_PORT, 0x02);
+ mad_write(MC5_PORT, 0x30 | cs4231_mode);
+ }
+
+ for (i = 0xf8d; i <= 0xf93; i++)
+ DDB(printf("port %03x after init = %03x\n", i, mad_read(i)));
+
+ /*
+ * Verify the WSS parameters
+ */
+
+ if (0) {
+ printf("MSS: I/O port conflict\n");
+ return 0;
+ }
+ /*
+ * Check if the IO port returns valid signature. The original MS
+ * Sound system returns 0x04 while some cards (AudioTriX Pro for
+ * example) return 0x00.
+ */
+
+ if ((inb(hw_config->io_base + 3) & 0x3f) != 0x04 &&
+ (inb(hw_config->io_base + 3) & 0x3f) != 0x00) {
+ DDB(printf("No MSS signature detected on port 0x%x (0x%x)\n",
+ hw_config->io_base, inb(hw_config->io_base + 3)));
+ return 0;
+ }
+ if (hw_config->irq > 11) {
+ printf("MSS: Bad IRQ %d\n", hw_config->irq);
+ return 0;
+ }
+ if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) {
+ printf("MSS: Bad DMA %d\n", hw_config->dma);
+ return 0;
+ }
+ /*
+ * Check that DMA0 is not in use with a 8 bit board.
+ */
+
+ if (hw_config->dma == 0 && inb(hw_config->io_base + 3) & 0x80) {
+ printf("MSS: Can't use DMA0 with a 8 bit card/slot\n");
+ return 0;
+ }
+ if (hw_config->irq > 7 && hw_config->irq != 9 && inb(hw_config->io_base + 3) & 0x80) {
+ printf("MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq);
+ return 0;
+ }
+ return 1;
+}
+
+void
+attach_mad16(struct address_info * hw_config)
+{
+
+ static char interrupt_bits[12] =
+ {
+ -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20
+ };
+ char bits;
+
+ static char dma_bits[4] =
+ {
+ 1, 2, 0, 3
+ };
+
+ int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3;
+ int ad_flags = 0, dma = hw_config->dma, dma2 = hw_config->dma2;
+ unsigned char dma2_bit = 0;
+
+ already_initialized = 1;
+
+ if (!ad1848_detect(hw_config->io_base + 4, &ad_flags, mad16_osp))
+ return;
+
+ /*
+ * Set the IRQ and DMA addresses.
+ */
+
+ bits = interrupt_bits[hw_config->irq];
+ if (bits == -1)
+ return;
+
+ outb(config_port, bits | 0x40);
+ if ((inb(version_port) & 0x40) == 0)
+ printf("[IRQ Conflict?]");
+
+ /*
+ * Handle the capture DMA channel
+ */
+
+ if (ad_flags & AD_F_CS4231 && dma2 != -1 && dma2 != dma) {
+ if ((dma == 0 && dma2 == 1) ||
+ (dma == 1 && dma2 == 0) ||
+ (dma == 3 && dma2 == 0)) {
+ dma2_bit = 0x04; /* Enable capture DMA */
+ } else {
+ printf("MAD16: Invalid capture DMA\n");
+ dma2 = dma;
+ }
+ } else
+ dma2 = dma;
+
+ outb(config_port, bits | dma_bits[dma] | dma2_bit); /* Write IRQ+DMA setup */
+
+ ad1848_init("MAD16 WSS", hw_config->io_base + 4,
+ hw_config->irq,
+ dma,
+ dma2, 0,
+ hw_config->osp);
+}
+
+void
+attach_mad16_mpu(struct address_info * hw_config)
+{
+ if (board_type < C929) {/* Early chip. No MPU support. Just SB MIDI */
+#ifdef CONFIG_MIDI
+
+ if (mad_read(MC1_PORT) & 0x20)
+ hw_config->io_base = 0x240;
+ else
+ hw_config->io_base = 0x220;
+
+ return mad16_sb_dsp_init(hw_config);
+#else
+ return 0;
+#endif
+ }
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
+ if (!already_initialized)
+ return;
+
+ attach_mpu401(hw_config);
+#endif
+}
+
+int
+probe_mad16_mpu(struct address_info * hw_config)
+{
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
+ static int mpu_attached = 0;
+ static int valid_ports[] =
+ {0x330, 0x320, 0x310, 0x300};
+ static short valid_irqs[] =
+ {9, 10, 5, 7};
+ unsigned char tmp;
+
+ int i; /* A variable with secret power */
+
+ if (!already_initialized) /* The MSS port must be initialized
+ * first */
+ return 0;
+
+ if (mpu_attached) /* Don't let them call this twice */
+ return 0;
+ mpu_attached = 1;
+
+ if (board_type < C929) {/* Early chip. No MPU support. Just SB MIDI */
+
+#ifdef CONFIG_MIDI
+ unsigned char tmp;
+
+ tmp = mad_read(MC3_PORT);
+
+ /*
+ * MAD16 SB base is defined by the WSS base. It cannot be
+ * changed alone. Ignore configured I/O base. Use the active
+ * setting.
+ */
+
+ if (mad_read(MC1_PORT) & 0x20)
+ hw_config->io_base = 0x240;
+ else
+ hw_config->io_base = 0x220;
+
+ switch (hw_config->irq) {
+ case 5:
+ tmp = (tmp & 0x3f) | 0x80;
+ break;
+ case 7:
+ tmp = (tmp & 0x3f);
+ break;
+ case 11:
+ tmp = (tmp & 0x3f) | 0x40;
+ break;
+ default:
+ printf("mad16/Mozart: Invalid MIDI IRQ\n");
+ return 0;
+ }
+
+ mad_write(MC3_PORT, tmp | 0x04);
+ return mad16_sb_dsp_detect(hw_config);
+#else
+ return 0;
+#endif
+ }
+ tmp = 0x83; /* MPU-401 enable */
+
+ /*
+ * Set the MPU base bits
+ */
+
+ for (i = 0; i < 5; i++) {
+ if (i > 3) { /* Out of array bounds */
+ printf("MAD16 / Mozart: Invalid MIDI port 0x%x\n", hw_config->io_base);
+ return 0;
+ }
+ if (valid_ports[i] == hw_config->io_base) {
+ tmp |= i << 5;
+ break;
+ }
+ }
+
+ /*
+ * Set the MPU IRQ bits
+ */
+
+ for (i = 0; i < 5; i++) {
+ if (i > 3) { /* Out of array bounds */
+ printf("MAD16 / Mozart: Invalid MIDI IRQ %d\n", hw_config->irq);
+ return 0;
+ }
+ if (valid_irqs[i] == hw_config->irq) {
+ tmp |= i << 3;
+ break;
+ }
+ }
+ mad_write(MC6_PORT, tmp); /* Write MPU401 config */
+
+ return probe_mpu401(hw_config);
+#else
+ return 0;
+#endif
+}
+
+/* That's all folks */
+#endif
diff --git a/sys/i386/isa/sound/mad16_sb_midi.c b/sys/i386/isa/sound/mad16_sb_midi.c
new file mode 100644
index 0000000..d1b3ad0
--- /dev/null
+++ b/sys/i386/isa/sound/mad16_sb_midi.c
@@ -0,0 +1,285 @@
+/*
+ * sound/mad16_sb_midi.c
+ *
+ * The low level driver for MAD16 SoundBlaster-DS-chip-based MIDI.
+ *
+ * Copyright by Hannu Savolainen 1993, Aaron Ucko 1995
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <i386/isa/sound/sound_config.h>
+
+#if defined(CONFIG_MAD16) && defined(CONFIG_MIDI)
+
+#define sbc_base mad16_sb_base
+#include <i386/isa/sound/sb_card.h>
+
+static int input_opened = 0;
+static int my_dev;
+static int mad16_sb_base = 0x220;
+static int mad16_sb_irq = 0;
+static int mad16_sb_dsp_ok = 0;
+static sound_os_info *midi_osp;
+
+int mad16_sb_midi_mode = NORMAL_MIDI;
+int mad16_sb_midi_busy = 0;
+
+int mad16_sb_duplex_midi = 0;
+volatile int mad16_sb_intr_active = 0;
+
+void (*midi_input_intr) (int dev, unsigned char data);
+
+static void mad16_sb_midi_init(int model);
+
+static int
+mad16_sb_dsp_command(unsigned char val)
+{
+ int i;
+ unsigned long limit;
+
+ limit = get_time() + hz / 10; /* The timeout is 0.1 secods */
+
+ /*
+ * Note! the i<500000 is an emergency exit. The
+ * mad16_sb_dsp_command() is sometimes called while interrupts are
+ * disabled. This means that the timer is disabled also. However the
+ * timeout situation is a abnormal condition. Normally the DSP should
+ * be ready to accept commands after just couple of loops.
+ */
+
+ for (i = 0; i < 500000 && get_time() < limit; i++) {
+ if ((inb(DSP_STATUS) & 0x80) == 0) {
+ outb(DSP_COMMAND, val);
+ return 1;
+ }
+ }
+
+ printf("MAD16 (SBP mode): DSP Command(%x) Timeout.\n", val);
+ printf("IRQ conflict???\n");
+ return 0;
+}
+
+void
+mad16_sbintr(int irq)
+{
+ int status;
+
+ unsigned long flags;
+ unsigned char data;
+
+ status = inb(DSP_DATA_AVAIL); /* Clear interrupt */
+
+ flags = splhigh();
+
+ data = inb(DSP_READ);
+ if (input_opened)
+ midi_input_intr(my_dev, data);
+
+ splx(flags);
+}
+
+static int
+mad16_sb_reset_dsp(void)
+{
+ int loopc;
+
+ outb(DSP_RESET, 1);
+ DELAY(10);
+ outb(DSP_RESET, 0);
+ DELAY(30);
+
+ for (loopc = 0; loopc < 100 && !(inb(DSP_DATA_AVAIL) & 0x80); loopc++)
+ DELAY(10);
+ /* Wait for data available status */
+
+ if (inb(DSP_READ) != 0xAA)
+ return 0; /* Sorry */
+
+ return 1;
+}
+
+int
+mad16_sb_dsp_detect(struct address_info * hw_config)
+{
+ mad16_sb_base = hw_config->io_base;
+ mad16_sb_irq = hw_config->irq;
+ midi_osp = hw_config->osp;
+
+ if (mad16_sb_dsp_ok)
+ return 0; /* Already initialized */
+ if (!mad16_sb_reset_dsp())
+ return 0;
+
+ return 1; /* Detected */
+}
+
+void
+mad16_sb_dsp_init(struct address_info * hw_config)
+/*
+ * this function now just verifies the reported version and calls
+ * mad16_sb_midi_init -- everything else is done elsewhere
+ */
+{
+
+ midi_osp = hw_config->osp;
+ if (snd_set_irq_handler(mad16_sb_irq, mad16_sbintr, midi_osp) < 0) {
+ printf("MAD16 SB MIDI: IRQ not free\n");
+ return;
+ }
+
+ conf_printf("MAD16 MIDI (SB mode)", hw_config);
+ mad16_sb_midi_init(2);
+
+ mad16_sb_dsp_ok = 1;
+ return;
+}
+
+static int
+mad16_sb_midi_open(int dev, int mode,
+ void (*input) (int dev, unsigned char data),
+ void (*output) (int dev)
+)
+{
+
+ if (!mad16_sb_dsp_ok) {
+ printf("MAD16_SB Error: MIDI hardware not installed\n");
+ return -(ENXIO);
+ }
+ if (mad16_sb_midi_busy)
+ return -(EBUSY);
+
+ if (mode != OPEN_WRITE && !mad16_sb_duplex_midi) {
+ if (num_midis == 1)
+ printf("MAD16 (SBP mode): Midi input not currently supported\n");
+ return -(EPERM);
+ }
+ mad16_sb_midi_mode = NORMAL_MIDI;
+ if (mode != OPEN_WRITE) {
+ if (mad16_sb_intr_active)
+ return -(EBUSY);
+ mad16_sb_midi_mode = UART_MIDI;
+ }
+ if (mad16_sb_midi_mode == UART_MIDI) {
+ mad16_sb_reset_dsp();
+
+ if (!mad16_sb_dsp_command(0x35))
+ return -(EIO); /* Enter the UART mode */
+ mad16_sb_intr_active = 1;
+
+ input_opened = 1;
+ midi_input_intr = input;
+ }
+ mad16_sb_midi_busy = 1;
+
+ return 0;
+}
+
+static void
+mad16_sb_midi_close(int dev)
+{
+ if (mad16_sb_midi_mode == UART_MIDI) {
+ mad16_sb_reset_dsp(); /* The only way to kill the UART mode */
+ }
+ mad16_sb_intr_active = 0;
+ mad16_sb_midi_busy = 0;
+ input_opened = 0;
+}
+
+static int
+mad16_sb_midi_out(int dev, unsigned char midi_byte)
+{
+ unsigned long flags;
+
+ if (mad16_sb_midi_mode == NORMAL_MIDI) {
+ flags = splhigh();
+ if (mad16_sb_dsp_command(0x38))
+ mad16_sb_dsp_command(midi_byte);
+ else
+ printf("MAD16_SB Error: Unable to send a MIDI byte\n");
+ splx(flags);
+ } else
+ mad16_sb_dsp_command(midi_byte); /* UART write */
+
+ return 1;
+}
+
+static int
+mad16_sb_midi_start_read(int dev)
+{
+ if (mad16_sb_midi_mode != UART_MIDI) {
+ printf("MAD16 (SBP mode): MIDI input not implemented.\n");
+ return -(EPERM);
+ }
+ return 0;
+}
+
+static int
+mad16_sb_midi_end_read(int dev)
+{
+ if (mad16_sb_midi_mode == UART_MIDI) {
+ mad16_sb_reset_dsp();
+ mad16_sb_intr_active = 0;
+ }
+ return 0;
+}
+
+static int
+mad16_sb_midi_ioctl(int dev, unsigned cmd, ioctl_arg arg)
+{
+ return -(EPERM);
+}
+
+#define MIDI_SYNTH_NAME "pseudo-SoundBlaster Midi"
+#define MIDI_SYNTH_CAPS 0
+#include <i386/isa/sound/midi_synth.h>
+
+static struct midi_operations mad16_sb_midi_operations =
+{
+ {"MAD16 (SBP mode)", 0, 0, SNDCARD_MAD16},
+ &std_midi_synth,
+ {0},
+ mad16_sb_midi_open,
+ mad16_sb_midi_close,
+ mad16_sb_midi_ioctl,
+ mad16_sb_midi_out,
+ mad16_sb_midi_start_read,
+ mad16_sb_midi_end_read,
+ NULL, /* Kick */
+ NULL, /* command */
+ NULL, /* buffer_status */
+ NULL
+};
+
+static void
+mad16_sb_midi_init(int model)
+{
+ if (num_midis >= MAX_MIDI_DEV) {
+ printf("Sound: Too many midi devices detected\n");
+ return;
+ }
+ std_midi_synth.midi_dev = num_midis;
+ my_dev = num_midis;
+ midi_devs[num_midis++] = &mad16_sb_midi_operations;
+}
+
+#endif
diff --git a/sys/i386/isa/sound/maui.c b/sys/i386/isa/sound/maui.c
new file mode 100644
index 0000000..e92b48a
--- /dev/null
+++ b/sys/i386/isa/sound/maui.c
@@ -0,0 +1,225 @@
+/*
+ * sound/maui.c
+ *
+ * The low level driver for Turtle Beach Maui and Tropez.
+ *
+ * Copyright by Hannu Savolainen 1995
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#define USE_SEQ_MACROS
+#define USE_SIMPLE_MACROS
+
+#include <i386/isa/sound/sound_config.h>
+
+
+#if defined(CONFIG_MAUI)
+
+static int maui_base = 0x330;
+
+static volatile int irq_ok = 0;
+static sound_os_info *maui_osp;
+
+#define HOST_DATA_PORT (maui_base + 2)
+#define HOST_STAT_PORT (maui_base + 3)
+#define HOST_CTRL_PORT (maui_base + 3)
+
+#define STAT_TX_INTR 0x40
+#define STAT_TX_AVAIL 0x20
+#define STAT_TX_IENA 0x10
+#define STAT_RX_INTR 0x04
+#define STAT_RX_AVAIL 0x02
+#define STAT_RX_IENA 0x01
+
+static int (*orig_load_patch) (int dev, int format, snd_rw_buf * addr,
+ int offs, int count, int pmgr_flag) = NULL;
+
+static int
+maui_read(void)
+{
+ int timeout;
+
+ for (timeout = 0; timeout < 1000000; timeout++)
+ if (inb(HOST_STAT_PORT) & STAT_RX_AVAIL)
+ return inb(HOST_DATA_PORT);
+
+ printf("Maui: Receive timeout\n");
+
+ return -1;
+}
+
+static int
+maui_write(u_char data)
+{
+ int timeout;
+
+ for (timeout = 0; timeout < 10000000; timeout++) {
+ if (inb(HOST_STAT_PORT) & STAT_TX_AVAIL) {
+ outb(HOST_DATA_PORT, data);
+ return 1;
+ }
+ }
+
+ printf("Maui: Write timeout\n");
+
+ return 0;
+}
+
+void
+mauiintr(int irq)
+{
+ irq_ok = 1;
+}
+
+
+int
+maui_load_patch(int dev, int format, snd_rw_buf * addr,
+ int offs, int count, int pmgr_flag)
+{
+
+ struct sysex_info header;
+ u_long left, src_offs;
+ int hdr_size = (u_long) &header.data[0] - (u_long) &header;
+ int i;
+
+ if (format == SYSEX_PATCH) /* Handled by midi_synth.c */
+ return orig_load_patch(dev, format, addr, offs, count, pmgr_flag);
+
+ if (format != MAUI_PATCH) {
+ printf("Maui: Unknown patch format\n");
+ }
+ if (count < hdr_size) {
+ printf("Maui error: Patch header too short\n");
+ return -(EINVAL);
+ }
+ count -= hdr_size;
+
+ /*
+ * Copy the header from user space but ignore the first bytes which
+ * have been transferred already.
+ */
+
+ if (uiomove(&((char *) &header)[offs], hdr_size - offs, addr)) {
+ printf("sb: Bad copyin()!\n");
+ };
+
+ if (count < header.len) {
+ printf("Maui warning: Host command record too short (%d<%d)\n",
+ count, (int) header.len);
+ header.len = count;
+ }
+ left = header.len;
+ src_offs = 0;
+
+ for (i = 0; i < left; i++) {
+ u_char data;
+ uiomove((char *) &(data), 1, addr);
+ if (i == 0 && !(data & 0x80))
+ return -(EINVAL);
+
+ if (maui_write(data) == -1)
+ return -(EIO);
+ }
+
+ if ((i = maui_read()) != 0x80) {
+ if (i != -1)
+ printf("Maui: Error status %02x\n", i);
+
+ return -(EIO);
+ }
+ return 0;
+}
+
+int
+probe_maui(struct address_info * hw_config)
+{
+ int i;
+ int tmp1, tmp2;
+
+ maui_base = hw_config->io_base;
+ maui_osp = hw_config->osp;
+
+ if (snd_set_irq_handler(hw_config->irq, mauiintr, maui_osp) < 0)
+ return 0;
+
+ if (!maui_write(0xCF)) {/* Report hardware version */
+ /* snd_release_irq(hw_config->irq); */
+ return 0;
+ }
+ if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1) {
+ /* snd_release_irq(hw_config->irq); */
+ return 0;
+ }
+ printf("WaveFront hardware version %d.%d\n", tmp1, tmp2);
+
+ if (!maui_write(0x9F)) /* Report firmware version */
+ return 0;
+ if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1)
+ return 0;
+ printf("WaveFront firmware version %d.%d\n", tmp1, tmp2);
+
+ if (!maui_write(0x85)) /* Report free DRAM */
+ return 0;
+ tmp1 = 0;
+ for (i = 0; i < 4; i++) {
+ tmp1 |= maui_read() << (7 * i);
+ }
+ printf("Available DRAM %dk\n", tmp1 / 1024);
+
+ for (i = 0; i < 1000; i++)
+ if (probe_mpu401(hw_config))
+ break;
+
+ return probe_mpu401(hw_config);
+}
+
+void
+attach_maui(struct address_info * hw_config)
+{
+ int this_dev = num_midis;
+
+ conf_printf("Maui", hw_config);
+
+ hw_config->irq *= -1;
+ attach_mpu401(hw_config);
+
+ if (num_midis > this_dev) { /* The MPU401 driver installed itself */
+ struct synth_operations *synth;
+
+ /*
+ * Intercept patch loading calls so that they canbe handled
+ * by the Maui driver.
+ */
+
+ synth = midi_devs[this_dev]->converter;
+
+ if (synth != NULL) {
+ orig_load_patch = synth->load_patch;
+ synth->load_patch = &maui_load_patch;
+ } else
+ printf("Maui: Can't install patch loader\n");
+ }
+ return;
+}
+
+#endif
diff --git a/sys/i386/isa/sound/midi_synth.c b/sys/i386/isa/sound/midi_synth.c
index fb1fdc4..86032e3 100644
--- a/sys/i386/isa/sound/midi_synth.c
+++ b/sys/i386/isa/sound/midi_synth.c
@@ -1,10 +1,10 @@
/*
* 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
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,7 +24,7 @@
* 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 USE_SEQ_MACROS
@@ -32,613 +32,642 @@
#include <i386/isa/sound/sound_config.h>
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MIDI)
+#if defined(CONFIGURE_SOUNDCARD) /* && defined(CONFIG_MIDI) */
#define _MIDI_SYNTH_C_
-DEFINE_WAIT_QUEUE (sysex_sleeper, sysex_sleep_flag);
+static int *sysex_sleeper = NULL;
+static volatile struct snd_wait sysex_sleep_flag = {0};
#include <i386/isa/sound/midi_synth.h>
static int midi2synth[MAX_MIDI_DEV];
+static int sysex_state[MAX_MIDI_DEV] =
+{0};
static unsigned char prev_out_status[MAX_MIDI_DEV];
-#define STORE(cmd) \
-{ \
+#ifndef CONFIG_SEQUENCER
+#define STORE(cmd)
+#else
+#define STORE(cmd) { \
int len; \
unsigned char obuf[8]; \
cmd; \
seq_input_event(obuf, len); \
}
+#endif
+
#define _seqbuf obuf
#define _seqbufptr 0
#define _SEQ_ADVBUF(x) len=x
void
-do_midi_msg (int synthno, unsigned char *msg, int mlen)
+do_midi_msg(int synthno, unsigned char *msg, int mlen)
{
- switch (msg[0] & 0xf0)
- {
+ switch (msg[0] & 0xf0) {
case 0x90:
- if (msg[2] != 0)
- {
- STORE (SEQ_START_NOTE (synthno, msg[0] & 0x0f, msg[1], msg[2]));
- break;
+ if (msg[2] != 0) {
+ STORE(SEQ_START_NOTE(synthno, msg[0] & 0x0f, msg[1], msg[2]));
+ break;
}
- msg[2] = 64;
+ msg[2] = 64;
case 0x80:
- STORE (SEQ_STOP_NOTE (synthno, msg[0] & 0x0f, msg[1], msg[2]));
- break;
+ STORE(SEQ_STOP_NOTE(synthno, msg[0] & 0x0f, msg[1], msg[2]));
+ break;
case 0xA0:
- STORE (SEQ_KEY_PRESSURE (synthno, msg[0] & 0x0f, msg[1], msg[2]));
- break;
+ STORE(SEQ_KEY_PRESSURE(synthno, msg[0] & 0x0f, msg[1], msg[2]));
+ break;
case 0xB0:
- STORE (SEQ_CONTROL (synthno, msg[0] & 0x0f,
- msg[1], msg[2]));
- break;
+ STORE(SEQ_CONTROL(synthno, msg[0] & 0x0f, msg[1], msg[2]));
+ break;
case 0xC0:
- STORE (SEQ_SET_PATCH (synthno, msg[0] & 0x0f, msg[1]));
- break;
+ STORE(SEQ_SET_PATCH(synthno, msg[0] & 0x0f, msg[1]));
+ break;
case 0xD0:
- STORE (SEQ_CHN_PRESSURE (synthno, msg[0] & 0x0f, msg[1]));
- break;
+ STORE(SEQ_CHN_PRESSURE(synthno, msg[0] & 0x0f, msg[1]));
+ break;
case 0xE0:
- STORE (SEQ_BENDER (synthno, msg[0] & 0x0f,
+ STORE(SEQ_BENDER(synthno, msg[0] & 0x0f,
(msg[1] % 0x7f) | ((msg[2] & 0x7f) << 7)));
- break;
+ break;
default:
- printk ("MPU: Unknown midi channel message %02x\n", msg[0]);
+ /*
+ * printf ("MPU: Unknown midi channel message %02x\n",
+ * msg[0]);
+ */
+ ;
}
}
static void
-midi_outc (int midi_dev, int data)
+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");
+ 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.
+ */
+ printf("Midi send timed out\n");
}
static int
-prefix_cmd (int midi_dev, unsigned char status)
+prefix_cmd(int midi_dev, unsigned char status)
{
- if ((char *) midi_devs[midi_dev]->prefix_cmd == NULL)
- return 1;
+ if ((char *) midi_devs[midi_dev]->prefix_cmd == NULL)
+ return 1;
- return midi_devs[midi_dev]->prefix_cmd (midi_dev, status);
+ return midi_devs[midi_dev]->prefix_cmd(midi_dev, status);
}
static void
-midi_synth_input (int dev, unsigned char data)
+midi_synth_input(int orig_dev, unsigned char data)
{
- int orig_dev;
- struct midi_input_info *inc;
-
- static unsigned char len_tab[] = /* # of data bytes following a status
- */
- {
- 2, /* 8x */
- 2, /* 9x */
- 2, /* Ax */
- 2, /* Bx */
- 1, /* Cx */
- 1, /* Dx */
- 2, /* Ex */
- 0 /* Fx */
- };
-
- if (dev < 0 || dev > num_synths)
- return;
-
- if (data == 0xfe) /* Ignore active sensing */
- return;
-
- orig_dev = midi2synth[dev];
- inc = &midi_devs[orig_dev]->in_info;
-
- switch (inc->m_state)
+ int dev;
+ struct midi_input_info *inc;
+
+ static unsigned char len_tab[] = /* # of data bytes following a status */
{
+ 2, /* 8x */
+ 2, /* 9x */
+ 2, /* Ax */
+ 2, /* Bx */
+ 1, /* Cx */
+ 1, /* Dx */
+ 2, /* Ex */
+ 0 /* Fx */
+ };
+
+ if (orig_dev < 0 || orig_dev > num_midis)
+ return;
+
+ if (data == 0xfe) /* Ignore active sensing */
+ return;
+
+ dev = midi2synth[orig_dev];
+ inc = &midi_devs[orig_dev]->in_info;
+
+ switch (inc->m_state) {
case MST_INIT:
- if (data & 0x80) /* MIDI status byte */
- {
- if ((data & 0xf0) == 0xf0) /* Common message */
- {
- switch (data)
- {
+ if (data & 0x80) { /* MIDI status byte */
+ if ((data & 0xf0) == 0xf0) { /* Common message */
+ switch (data) {
case 0xf0: /* Sysex */
- inc->m_state = MST_SYSEX;
- break; /* Sysex */
+ inc->m_state = MST_SYSEX;
+ break; /* Sysex */
case 0xf1: /* MTC quarter frame */
case 0xf3: /* Song select */
- inc->m_state = MST_DATA;
- inc->m_ptr = 1;
- inc->m_left = 1;
- inc->m_buf[0] = data;
- break;
+ inc->m_state = MST_DATA;
+ inc->m_ptr = 1;
+ inc->m_left = 1;
+ inc->m_buf[0] = data;
+ break;
case 0xf2: /* Song position pointer */
- inc->m_state = MST_DATA;
- inc->m_ptr = 1;
- inc->m_left = 2;
- inc->m_buf[0] = data;
- break;
+ inc->m_state = MST_DATA;
+ inc->m_ptr = 1;
+ inc->m_left = 2;
+ inc->m_buf[0] = data;
+ break;
default:
- inc->m_buf[0] = data;
- inc->m_ptr = 1;
- do_midi_msg (dev, inc->m_buf, inc->m_ptr);
- inc->m_ptr = 0;
- inc->m_left = 0;
+ inc->m_buf[0] = data;
+ inc->m_ptr = 1;
+ do_midi_msg(dev, inc->m_buf, inc->m_ptr);
+ inc->m_ptr = 0;
+ inc->m_left = 0;
}
+ } else {
+ inc->m_state = MST_DATA;
+ inc->m_ptr = 1;
+ inc->m_left = len_tab[(data >> 4) - 8];
+ inc->m_buf[0] = inc->m_prev_status = data;
}
- else
- {
- inc->m_state = MST_DATA;
- inc->m_ptr = 1;
- inc->m_left = len_tab[(data >> 4) - 8];
- inc->m_buf[0] = inc->m_prev_status = data;
- }
- }
- else if (inc->m_prev_status & 0x80) /* Ignore if no previous status (yet) */
- { /* Data byte (use running status) */
- inc->m_state = MST_DATA;
- inc->m_ptr = 2;
- inc->m_left = len_tab[(data >> 4) - 8] - 1;
- inc->m_buf[0] = inc->m_prev_status;
- inc->m_buf[1] = data;
+ } else if (inc->m_prev_status & 0x80) { /* Ignore if no previous
+ * status (yet) *//* Data byte (use running status) */
+ inc->m_state = MST_DATA;
+ inc->m_ptr = 2;
+ inc->m_left = len_tab[(data >> 4) - 8] - 1;
+ inc->m_buf[0] = inc->m_prev_status;
+ inc->m_buf[1] = data;
}
- break; /* MST_INIT */
+ break; /* MST_INIT */
case MST_DATA:
- inc->m_buf[inc->m_ptr++] = data;
- if (--inc->m_left <= 0)
- {
- inc->m_state = MST_INIT;
- do_midi_msg (dev, inc->m_buf, inc->m_ptr);
- inc->m_ptr = 0;
+ inc->m_buf[inc->m_ptr++] = data;
+ if (--inc->m_left <= 0) {
+ inc->m_state = MST_INIT;
+ do_midi_msg(dev, inc->m_buf, inc->m_ptr);
+ inc->m_ptr = 0;
}
- break; /* MST_DATA */
+ break; /* MST_DATA */
case MST_SYSEX:
- if (data == 0xf7) /* Sysex end */
- {
- inc->m_state = MST_INIT;
- inc->m_left = 0;
- inc->m_ptr = 0;
+ if (data == 0xf7) { /* Sysex end */
+ inc->m_state = MST_INIT;
+ inc->m_left = 0;
+ inc->m_ptr = 0;
}
- break; /* MST_SYSEX */
+ break; /* MST_SYSEX */
default:
- printk ("MIDI%d: Unexpected state %d (%02x)\n", orig_dev, inc->m_state,
- (int) data);
- inc->m_state = MST_INIT;
+ printf("MIDI%d: Unexpected state %d (%02x)\n", orig_dev, inc->m_state,
+ (int) data);
+ inc->m_state = MST_INIT;
}
}
static void
-midi_synth_output (int dev)
+leave_sysex(int dev)
{
- /*
- * Currently NOP
- */
+ int orig_dev = synth_devs[dev]->midi_dev;
+ int timeout = 0;
+
+ if (!sysex_state[dev])
+ return;
+
+ sysex_state[dev] = 0;
+
+ while (!midi_devs[orig_dev]->putc(orig_dev, 0xf7) && timeout < 1000)
+ timeout++;
+
+ sysex_state[dev] = 0;
+}
+
+static void
+midi_synth_output(int dev)
+{
+ /*
+ * Currently NOP
+ */
}
int
-midi_synth_ioctl (int dev,
- unsigned int cmd, unsigned int arg)
+midi_synth_ioctl(int dev, unsigned int cmd, ioctl_arg arg)
{
- /*
- * int orig_dev = synth_devs[dev]->midi_dev;
- */
+ /*
+ * int orig_dev = synth_devs[dev]->midi_dev;
+ */
- switch (cmd)
- {
+ switch (cmd) {
case SNDCTL_SYNTH_INFO:
- IOCTL_TO_USER ((char *) arg, 0, synth_devs[dev]->info,
- sizeof (struct synth_info));
-
- return 0;
- break;
+ bcopy(synth_devs[dev]->info, &(((char *) arg)[0]), sizeof(struct synth_info));
+ return 0;
+ break;
case SNDCTL_SYNTH_MEMAVL:
- return 0x7fffffff;
- break;
+ return 0x7fffffff;
+ break;
default:
- return RET_ERROR (EINVAL);
+ return -(EINVAL);
}
}
int
-midi_synth_kill_note (int dev, int channel, int note, int velocity)
+midi_synth_kill_note(int dev, int channel, int note, int velocity)
{
- int orig_dev = synth_devs[dev]->midi_dev;
- int msg, chn;
+ 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))
+ if (note < 0 || note > 127)
+ return 0;
+ if (channel < 0 || channel > 15)
return 0;
+ RANGE (velocity, 0, 127 ) ;
+ leave_sysex(dev);
- 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)))
+ 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, 0x80 | (channel & 0x0f)); /*
- * Note off
- */
- midi_outc (orig_dev, note);
- midi_outc (orig_dev, velocity);
+
+ 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;
+ return 0;
}
int
-midi_synth_set_instr (int dev, int channel, int instr_no)
+midi_synth_set_instr(int dev, int channel, int instr_no)
{
- int orig_dev = synth_devs[dev]->midi_dev;
+ 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 (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);
+ leave_sysex(dev);
- 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)
+midi_synth_start_note(int dev, int channel, int note, int velocity)
{
- int orig_dev = synth_devs[dev]->midi_dev;
- int msg, chn;
+ 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))
+ if (note < 0 || note > 127)
return 0;
- midi_outc (orig_dev, note);
- midi_outc (orig_dev, velocity);
- }
- else
- {
- if (!prefix_cmd (orig_dev, 0x90 | (channel & 0x0f)))
+ if (channel < 0 || channel > 15)
return 0;
- midi_outc (orig_dev, 0x90 | (channel & 0x0f)); /*
- * Note on
- */
- midi_outc (orig_dev, note);
- midi_outc (orig_dev, velocity);
+ RANGE (velocity, 0, 127 );
+ leave_sysex(dev);
+
+ 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;
+ return 0;
}
void
-midi_synth_reset (int dev)
+midi_synth_reset(int dev)
{
+
+ leave_sysex(dev);
}
int
-midi_synth_open (int dev, int mode)
+midi_synth_open(int dev, int mode)
{
- int orig_dev = synth_devs[dev]->midi_dev;
- int err;
- unsigned long flags;
- struct midi_input_info *inc;
+ int orig_dev = synth_devs[dev]->midi_dev;
+ int err;
+ unsigned long flags;
+ struct midi_input_info *inc;
- if (orig_dev < 0 || orig_dev > num_midis)
- return RET_ERROR (ENXIO);
+ if (orig_dev < 0 || orig_dev > num_midis)
+ return -(ENXIO);
- midi2synth[orig_dev] = dev;
- prev_out_status[orig_dev] = 0;
+ midi2synth[orig_dev] = dev;
+ sysex_state[dev] = 0;
+ 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;
+ if ((err = midi_devs[orig_dev]->open(orig_dev, mode,
+ midi_synth_input, midi_synth_output)) < 0)
+ return err;
- inc = &midi_devs[orig_dev]->in_info;
+ inc = &midi_devs[orig_dev]->in_info;
- DISABLE_INTR (flags);
- inc->m_busy = 0;
- inc->m_state = MST_INIT;
- inc->m_ptr = 0;
- inc->m_left = 0;
- inc->m_prev_status = 0x00;
- RESTORE_INTR (flags);
+ flags = splhigh();
+ inc->m_busy = 0;
+ inc->m_state = MST_INIT;
+ inc->m_ptr = 0;
+ inc->m_left = 0;
+ inc->m_prev_status = 0x00;
+ splx(flags);
- return 1;
+ sysex_sleep_flag.aborting = 0;
+ sysex_sleep_flag.mode = WK_NONE;
+
+ return 1;
}
void
-midi_synth_close (int dev)
+midi_synth_close(int dev)
{
- int orig_dev = synth_devs[dev]->midi_dev;
+ int orig_dev = synth_devs[dev]->midi_dev;
+
+ leave_sysex(dev);
- /*
+ /*
* Shut up the synths by sending just single active sensing message.
- */
- midi_devs[orig_dev]->putc (orig_dev, 0xfe);
+ */
+ midi_devs[orig_dev]->putc(orig_dev, 0xfe);
- midi_devs[orig_dev]->close (orig_dev);
+ midi_devs[orig_dev]->close(orig_dev);
}
void
-midi_synth_hw_control (int dev, unsigned char *event)
+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)
+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;
+ 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;
- int hdr_size = (unsigned long) &sysex.data[0] - (unsigned long) &sysex;
+ struct sysex_info sysex;
+ int i;
+ unsigned long left, src_offs, eox_seen = 0;
+ int first_byte = 1;
+ int hdr_size = (unsigned long) &sysex.data[0] - (unsigned long) &sysex;
- if (!prefix_cmd (orig_dev, 0xf0))
- return 0;
+ leave_sysex(dev);
- if (format != SYSEX_PATCH)
- {
- printk ("MIDI Error: Invalid patch format (key) 0x%x\n", format);
- return RET_ERROR (EINVAL);
- }
+ if (!prefix_cmd(orig_dev, 0xf0))
+ return 0;
- if (count < hdr_size)
- {
- printk ("MIDI Error: Patch header too short\n");
- return RET_ERROR (EINVAL);
+ if (format != SYSEX_PATCH) {
+ printf("MIDI Error: Invalid patch format (key) 0x%x\n", format);
+ return -(EINVAL);
+ }
+ if (count < hdr_size) {
+ printf("MIDI Error: Patch header too short\n");
+ return -(EINVAL);
}
+ count -= hdr_size;
- count -= hdr_size;
+ /*
+ * Copy the header from user space but ignore the first bytes which
+ * have been transferred already.
+ */
- /*
- * Copy the header from user space but ignore the first bytes which have
- * been transferred already.
- */
- COPY_FROM_USER (&((char *) &sysex)[offs], addr, offs, hdr_size - offs);
+ if (uiomove(&((char *) &sysex)[offs], hdr_size - offs, addr)) {
+ printf("sb: Bad copyin()!\n");
+ };
- if (count < sysex.len)
- {
- printk ("MIDI Warning: Sysex record too short (%d<%d)\n",
- count, (int) sysex.len);
- sysex.len = count;
+ if (count < sysex.len) {
+ printf("MIDI Warning: Sysex record too short (%d<%d)\n",
+ count, (int) sysex.len);
+ sysex.len = count;
}
+ left = sysex.len;
+ src_offs = 0;
- left = sysex.len;
- src_offs = 0;
-
- RESET_WAIT_QUEUE (sysex_sleeper, sysex_sleep_flag);
+ sysex_sleep_flag.aborting = 0;
+ sysex_sleep_flag.mode = WK_NONE;
- for (i = 0; i < left && !PROCESS_ABORTING (sysex_sleeper, sysex_sleep_flag); i++)
- {
- unsigned char data;
+ for (i = 0; i < left && !(sysex_sleep_flag.aborting); i++) {
+ unsigned char data;
- GET_BYTE_FROM_USER (data, addr, hdr_size + i);
+ uiomove((char *) &(data), 1, addr);
- eox_seen = (i > 0 && data & 0x80); /* End of sysex */
+ eox_seen = (i > 0 && data & 0x80); /* End of sysex */
- if (eox_seen && data != 0xf7)
- data = 0xf7;
+ if (eox_seen && data != 0xf7)
+ data = 0xf7;
- if (i == 0)
- {
- if (data != 0xf0)
- {
- printk ("Error: Sysex start missing\n");
- return RET_ERROR (EINVAL);
+ if (i == 0) {
+ if (data != 0xf0) {
+ printf("Error: Sysex start missing\n");
+ return -(EINVAL);
}
}
+ while (!midi_devs[orig_dev]->putc(orig_dev,
+ (unsigned char) (data & 0xff)) &&
+ !(sysex_sleep_flag.aborting)) {
+ int chn;
- 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;
+ sysex_sleeper = &chn;
+ DO_SLEEP(chn, 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;
+ if (!eox_seen)
+ midi_outc(orig_dev, 0xf7);
+ return 0;
}
void
-midi_synth_panning (int dev, int channel, int pressure)
+midi_synth_panning(int dev, int channel, int pressure)
{
}
void
-midi_synth_aftertouch (int dev, int channel, int pressure)
+midi_synth_aftertouch(int dev, int channel, int pressure)
{
- int orig_dev = synth_devs[dev]->midi_dev;
- int msg, chn;
+ int orig_dev = synth_devs[dev]->midi_dev;
+ int msg, chn;
+
+ if (pressure < 0 || pressure > 127)
+ return;
+ if (channel < 0 || channel > 15)
+ return;
- if (pressure < 0 || pressure > 127)
- return;
- if (channel < 0 || channel > 15)
- return;
+ leave_sysex(dev);
- msg = prev_out_status[orig_dev] & 0xf0;
- chn = prev_out_status[orig_dev] & 0x0f;
+ 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)))
+ 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, 0xd0 | (channel & 0x0f)); /*
- * Channel pressure
- */
- }
- else if (!prefix_cmd (orig_dev, pressure))
- return;
- midi_outc (orig_dev, pressure);
+ midi_outc(orig_dev, pressure);
}
void
-midi_synth_controller (int dev, int channel, int ctrl_num, int value)
+midi_synth_controller(int dev, int channel, int ctrl_num, int value)
{
- int orig_dev = synth_devs[dev]->midi_dev;
- int chn, msg;
+ 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;
+ 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;
+ leave_sysex(dev);
- if (msg != 0xb0 || chn != channel)
- {
- if (!prefix_cmd (orig_dev, 0xb0 | (channel & 0x0f)))
+ 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, 0xb0 | (channel & 0x0f));
- }
- else if (!prefix_cmd (orig_dev, ctrl_num))
- return;
- midi_outc (orig_dev, ctrl_num);
- midi_outc (orig_dev, value & 0x7f);
+ midi_outc(orig_dev, ctrl_num);
+ midi_outc(orig_dev, value & 0x7f);
}
int
-midi_synth_patchmgr (int dev, struct patmgr_info *rec)
+midi_synth_patchmgr(int dev, struct patmgr_info * rec)
{
- return RET_ERROR (EINVAL);
+ return -(EINVAL);
}
void
-midi_synth_bender (int dev, int channel, int value)
+midi_synth_bender(int dev, int channel, int value)
{
- int orig_dev = synth_devs[dev]->midi_dev;
- int msg, prev_chn;
+ int orig_dev = synth_devs[dev]->midi_dev;
+ int msg, prev_chn;
+
+ if (channel < 0 || channel > 15)
+ return;
- if (channel < 0 || channel > 15)
- return;
+ if (value < 0 || value > 16383)
+ return;
- if (value < 0 || value > 16383)
- return;
+ leave_sysex(dev);
- msg = prev_out_status[orig_dev] & 0xf0;
- prev_chn = prev_out_status[orig_dev] & 0x0f;
+ 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)))
+ 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, 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);
+ midi_outc(orig_dev, value & 0x7f);
+ midi_outc(orig_dev, (value >> 7) & 0x7f);
}
void
-midi_synth_setup_voice (int dev, int voice, int channel)
+midi_synth_setup_voice(int dev, int voice, int channel)
{
}
+int
+midi_synth_send_sysex(int dev, unsigned char *bytes, int len)
+{
+ int orig_dev = synth_devs[dev]->midi_dev;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ switch (bytes[i]) {
+ case 0xf0: /* Start sysex */
+ if (!prefix_cmd(orig_dev, 0xf0))
+ return 0;
+ sysex_state[dev] = 1;
+ break;
+
+ case 0xf7: /* End sysex */
+ if (!sysex_state[dev]) /* Orphan sysex end */
+ return 0;
+ sysex_state[dev] = 0;
+ break;
+
+ default:
+ if (!sysex_state[dev])
+ return 0;
+
+ if (bytes[i] & 0x80) { /* Error. Another message before sysex end */
+ bytes[i] = 0xf7; /* Sysex end */
+ sysex_state[dev] = 0;
+ }
+ }
+
+ if (!midi_devs[orig_dev]->putc(orig_dev, bytes[i])) {
+ /*
+ * Hardware leve buffer is full. Abort the sysex message.
+ */
+
+ int timeout = 0;
+
+ bytes[i] = 0xf7;
+ sysex_state[dev] = 0;
+
+ while (!midi_devs[orig_dev]->putc(orig_dev, bytes[i]) &&
+ timeout < 1000)
+ timeout++;
+ }
+ if (!sysex_state[dev])
+ return 0;
+ }
+
+ return 0;
+}
#endif
diff --git a/sys/i386/isa/sound/midi_synth.h b/sys/i386/isa/sound/midi_synth.h
index 22f56ac..80e627b 100644
--- a/sys/i386/isa/sound/midi_synth.h
+++ b/sys/i386/isa/sound/midi_synth.h
@@ -1,5 +1,5 @@
int midi_synth_ioctl (int dev,
- unsigned int cmd, unsigned int arg);
+ unsigned int cmd, ioctl_arg 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);
@@ -15,7 +15,7 @@ void midi_synth_controller (int dev, int channel, int ctrl_num, int value);
int midi_synth_patchmgr (int dev, struct patmgr_info *rec);
void midi_synth_bender (int dev, int chn, int value);
void midi_synth_setup_voice (int dev, int voice, int chn);
-
+int midi_synth_send_sysex(int dev, unsigned char *bytes,int len);
#ifndef _MIDI_SYNTH_C_
static struct synth_info std_synth_info =
@@ -43,6 +43,7 @@ static struct synth_operations std_midi_synth =
midi_synth_patchmgr,
midi_synth_bender,
NULL, /* alloc_voice */
- midi_synth_setup_voice
+ midi_synth_setup_voice,
+ midi_synth_send_sysex
};
#endif
diff --git a/sys/i386/isa/sound/midibuf.c b/sys/i386/isa/sound/midibuf.c
index 79e1a16..faddba9 100644
--- a/sys/i386/isa/sound/midibuf.c
+++ b/sys/i386/isa/sound/midibuf.c
@@ -1,10 +1,10 @@
/*
* sound/midibuf.c
- *
+ *
* Device file manager for /dev/midi#
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,14 +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.
- *
+ *
*/
#include <i386/isa/sound/sound_config.h>
-static void drain_midi_queue __P((int dev));
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MIDI)
+#if defined(CONFIG_MIDI)
/*
* Don't make MAX_QUEUE_SIZE larger than 4000
@@ -39,412 +38,359 @@ static void drain_midi_queue __P((int dev));
#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 int *midi_sleeper[MAX_MIDI_DEV] = {NULL};
+static volatile struct snd_wait midi_sleep_flag[MAX_MIDI_DEV] = { {0}};
+static int *input_sleeper[MAX_MIDI_DEV] = {NULL};
+static volatile struct snd_wait input_sleep_flag[MAX_MIDI_DEV] = { {0}};
+
+struct midi_buf {
+ int len, head, tail;
+ u_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 (void *dummy);
+static void midi_poll(void *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); \
+ if (SPACE_AVAIL(q)) { \
+ u_long flags; \
+ flags = splhigh(); \
q->queue[q->tail] = (data); \
q->len++; q->tail = (q->tail+1) % MAX_QUEUE_SIZE; \
- RESTORE_INTR(flags); \
+ splx(flags); \
}
#define REMOVE_BYTE(q, data) \
- if (DATA_AVAIL(q)) \
- { \
- unsigned long flags; \
- DISABLE_INTR(flags); \
+ if (DATA_AVAIL(q)) { \
+ u_long flags; \
+ flags = splhigh(); \
data = q->queue[q->head]; \
q->len--; q->head = (q->head+1) % MAX_QUEUE_SIZE; \
- RESTORE_INTR(flags); \
+ splx(flags); \
}
-static void
-drain_midi_queue (int dev)
+void
+drain_midi_queue(int dev)
{
- /*
- * Give the Midi driver time to drain its output queues
- */
+ /*
+ * Give the Midi driver time to drain its output queues
+ */
+
+ if (midi_devs[dev]->buffer_status != NULL)
+ while (!(PROCESS_ABORTING (midi_sleep_flag[dev])) &&
+ midi_devs[dev]->buffer_status(dev)) {
+ int chn;
- 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);
+ midi_sleeper[dev] = &chn;
+ DO_SLEEP(chn, midi_sleep_flag[dev], hz / 10);
+
+ };
}
static void
-midi_input_intr (int dev, unsigned char data)
+midi_input_intr(int dev, u_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]);
- }
-#if defined(__FreeBSD__)
- if (selinfo[dev].si_pid)
- selwakeup(&selinfo[dev]);
-#endif
+ 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 ((input_sleep_flag[dev].mode & WK_SLEEP)) {
+ input_sleep_flag[dev].mode = WK_WAKEUP;
+ wakeup(input_sleeper[dev]);
+ };
+ }
}
static void
-midi_output_intr (int dev)
+midi_output_intr(int dev)
{
- /*
- * Currently NOP
- */
-#if defined(__FreeBSD__)
- if (selinfo[dev].si_pid)
- selwakeup(&selinfo[dev]);
-#endif
+ /*
+ * Currently NOP
+ */
}
static void
-midi_poll (void *dummy)
+midi_poll(void *dummy)
{
- unsigned long flags;
- int dev;
-
- 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);
+ u_long flags;
+ int dev;
+
+ flags = splhigh();
+ 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 &&
+ (midi_sleep_flag[dev].mode & WK_SLEEP)) {
+ midi_sleep_flag[dev].mode = WK_WAKEUP;
+ wakeup(midi_sleeper[dev]);
+ };
+ }
+ timeout( midi_poll, 0, 1);; /* Come back later */
+ }
+ splx(flags);
}
int
-MIDIbuf_open (int dev, struct fileinfo *file)
+MIDIbuf_open(int dev, struct fileinfo * file)
{
- int mode, err;
- unsigned long flags;
-
- dev = dev >> 4;
- mode = file->mode & O_ACCMODE;
-
- if (num_midis > MAX_MIDI_DEV)
- {
- printk ("Sound: FATAL ERROR: Too many midi interfaces\n");
- num_midis = MAX_MIDI_DEV;
- }
-
- if (dev < 0 || dev >= num_midis)
- {
- printk ("Sound: Nonexistent MIDI interface %d\n", dev);
- return RET_ERROR (ENXIO);
- }
-
- /*
- * 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));
-
- 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 err;
+ int mode, err;
+
+ dev = dev >> 4;
+ mode = file->mode & O_ACCMODE;
+
+ if (num_midis > MAX_MIDI_DEV) {
+ printf("Sound: FATAL ERROR: Too many midi interfaces\n");
+ num_midis = MAX_MIDI_DEV;
+ }
+ if (dev < 0 || dev >= num_midis) {
+ printf("Sound: Nonexistent MIDI interface %d\n", dev);
+ return -(ENXIO);
+ }
+ /*
+ * Interrupts disabled. Be careful
+ */
+
+ if ((err = midi_devs[dev]->open(dev, mode,
+ midi_input_intr, midi_output_intr)) < 0) {
+ return err;
+ }
+ parms[dev].prech_timeout = 0;
+
+ midi_in_buf[dev] = (struct midi_buf *) malloc(sizeof(struct midi_buf), M_TEMP, M_WAITOK);
+
+ if (midi_in_buf[dev] == NULL) {
+ printf("midi: Can't allocate buffer\n");
+ midi_devs[dev]->close(dev);
+ return -(EIO);
+ }
+ midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0;
+
+ midi_out_buf[dev] = (struct midi_buf *) malloc(sizeof(struct midi_buf), M_TEMP, M_WAITOK);
+
+ if (midi_out_buf[dev] == NULL) {
+ printf("midi: Can't allocate buffer\n");
+ midi_devs[dev]->close(dev);
+ free(midi_in_buf[dev], M_TEMP);
+ midi_in_buf[dev] = NULL;
+ return -(EIO);
+ }
+ midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0;
+ open_devs++;
+
+ {
+ midi_sleep_flag[dev].aborting = 0;
+ midi_sleep_flag[dev].mode = WK_NONE;
+ };
+ {
+ input_sleep_flag[dev].aborting = 0;
+ input_sleep_flag[dev].mode = WK_NONE;
+ };
+
+ if (open_devs < 2) { /* This was first open */
+ {
+ };
+
+ timeout( midi_poll, 0, 1);; /* Start polling */
+ }
+ return err;
}
void
-MIDIbuf_release (int dev, struct fileinfo *file)
+MIDIbuf_release(int dev, struct fileinfo * file)
{
- int mode;
- unsigned long flags;
-
- dev = dev >> 4;
- mode = file->mode & O_ACCMODE;
-
- 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 mode;
+ u_long flags;
+
+ dev = dev >> 4;
+ mode = file->mode & O_ACCMODE;
+
+ if (dev < 0 || dev >= num_midis)
+ return;
+
+ flags = splhigh();
+
+ /*
+ * 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_sleep_flag[dev])) &&
+ DATA_AVAIL(midi_out_buf[dev])) {
+ int chn;
+ midi_sleeper[dev] = &chn;
+ DO_SLEEP(chn, midi_sleep_flag[dev], 0);
+
+ }; /* Sync */
+
+ drain_midi_queue(dev); /* Ensure the output queues are empty */
+ }
+ splx(flags);
+
+ midi_devs[dev]->close(dev);
+
+ free(midi_in_buf[dev], M_TEMP);
+ free(midi_out_buf[dev], M_TEMP);
+ midi_in_buf[dev] = NULL;
+ midi_out_buf[dev] = NULL;
+ if (open_devs < 2) {
+ };
+ open_devs--;
}
int
-MIDIbuf_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+MIDIbuf_write(int dev, struct fileinfo * file, snd_rw_buf * buf, int count)
{
- unsigned long flags;
- int c, n, i;
- unsigned char tmp_data;
+ u_long flags;
+ int c, n, i;
+ u_char tmp_data;
- dev = dev >> 4;
+ dev = dev >> 4;
- if (!count)
- return 0;
+ if (!count)
+ return 0;
- DISABLE_INTR (flags);
+ flags = splhigh();
- c = 0;
+ c = 0;
- while (c < count)
- {
- n = SPACE_AVAIL (midi_out_buf[dev]);
+ 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 == 0) { /* No space just now. We have to sleep */
- if (n > (count - c))
- n = count - c;
+ {
+ int chn;
- for (i = 0; i < n; i++)
- {
- COPY_FROM_USER (&tmp_data, buf, c, 1);
- QUEUE_BYTE (midi_out_buf[dev], tmp_data);
- c++;
+ midi_sleeper[dev] = &chn;
+ DO_SLEEP(chn, midi_sleep_flag[dev], 0);
+ };
+
+ if (PROCESS_ABORTING(midi_sleep_flag[dev])) {
+ splx(flags);
+ return -(EINTR);
+ }
+ n = SPACE_AVAIL(midi_out_buf[dev]);
+ }
+ if (n > (count - c))
+ n = count - c;
+
+ for (i = 0; i < n; i++) {
+
+ if (uiomove((char *) &tmp_data, 1, buf)) {
+ printf("sb: Bad copyin()!\n");
+ };
+ QUEUE_BYTE(midi_out_buf[dev], tmp_data);
+ c++;
+ }
}
- }
- RESTORE_INTR (flags);
+ splx(flags);
- return c;
+ return c;
}
int
-MIDIbuf_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+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;
-
- 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++;
- }
- }
+ int n, c = 0;
+ u_long flags;
+ u_char tmp_data;
- RESTORE_INTR (flags);
+ dev = dev >> 4;
- return c;
-}
+ flags = splhigh();
-int
-MIDIbuf_ioctl (int dev, struct fileinfo *file,
- unsigned int cmd, unsigned int arg)
-{
- int val;
-
- dev = dev >> 4;
-
- if (((cmd >> 8) & 0xff) == 'C')
- {
- if (midi_devs[dev]->coproc) /* Coprocessor ioctl */
- return midi_devs[dev]->coproc->ioctl (midi_devs[dev]->coproc->devc, cmd, arg, 0);
- else
- printk ("/dev/midi%d: No coprocessor for this device\n", dev);
-
- return RET_ERROR (EREMOTEIO);
- }
- else
- switch (cmd)
- {
-
- case SNDCTL_MIDI_PRETIME:
- val = IOCTL_IN (arg);
- if (val < 0)
- val = 0;
-
- val = (HZ * val) / 10;
- parms[dev].prech_timeout = val;
- return IOCTL_OUT (arg, val);
- break;
-
- default:
- return midi_devs[dev]->ioctl (dev, cmd, arg);
- }
+ if (!DATA_AVAIL(midi_in_buf[dev])) { /* No data yet, wait */
+
+ {
+ int chn;
+
+
+ input_sleeper[dev] = &chn;
+ DO_SLEEP(chn, input_sleep_flag[dev],
+ parms[dev].prech_timeout);
+
+ };
+ if (PROCESS_ABORTING(input_sleep_flag[dev]))
+ c = -(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);
+
+ if (uiomove((char *) &tmp_data, 1, buf)) {
+ printf("sb: Bad copyout()!\n");
+ };
+ c++;
+ }
+ }
+ splx(flags);
+
+ return c;
}
-#ifdef ALLOW_SELECT
int
-MIDIbuf_poll (int dev, struct fileinfo *file, int events, select_table * wait)
+MIDIbuf_ioctl(int dev, struct fileinfo * file, u_int cmd, ioctl_arg arg)
{
- int revents = 0;
+ int val;
- dev = dev >> 4;
+ dev = dev >> 4;
- if (events & (POLLIN | POLLRDNORM))
- if (!DATA_AVAIL (midi_in_buf[dev]))
- selrecord(wait, &selinfo[dev]);
- else
- revents |= events & (POLLIN | POLLRDNORM);
+ if (((cmd >> 8) & 0xff) == 'C') {
+ if (midi_devs[dev]->coproc) /* Coprocessor ioctl */
+ return midi_devs[dev]->coproc->ioctl(midi_devs[dev]->coproc->devc, cmd, arg, 0);
+ else
+ printf("/dev/midi%d: No coprocessor for this device\n", dev);
- if (events & (POLLOUT | POLLWRNORM))
- if (SPACE_AVAIL (midi_out_buf[dev]))
- selrecord(wait, &selinfo[dev]);
- else
- revents |= events & (POLLOUT | POLLWRNORM);
+ return -(ENXIO);
+ } else
+ switch (cmd) {
- return revents;
-}
+ case SNDCTL_MIDI_PRETIME:
+ val = (int) (*(int *) arg);
+ if (val < 0)
+ val = 0;
-#endif /* ALLOW_SELECT */
+ val = (hz * val) / 10;
+ parms[dev].prech_timeout = val;
+ return *(int *) arg = val;
+ break;
-long
-MIDIbuf_init (long mem_start)
-{
- return mem_start;
+ default:
+ return midi_devs[dev]->ioctl(dev, cmd, arg);
+ }
}
-
#endif
diff --git a/sys/i386/isa/sound/mmap_test.c b/sys/i386/isa/sound/mmap_test.c
new file mode 100644
index 0000000..2291449
--- /dev/null
+++ b/sys/i386/isa/sound/mmap_test.c
@@ -0,0 +1,274 @@
+/*
+ * This is a simple program which demonstrates use of mmapped DMA buffer
+ * of the sound driver directly from application program.
+ *
+ * This sample program works (currently) only with Linux, FreeBSD and BSD/OS
+ * (FreeBSD and BSD/OS require OSS version 3.8-beta16 or later.
+ *
+ * Note! Don't use mmapped DMA buffers (direct audio) unless you have
+ * very good reasons to do it. Programs using this feature will not
+ * work with all soundcards. GUS (GF1) is one of them (GUS MAX works).
+ *
+ * This program requires version 3.5-beta7 or later of OSS
+ * (3.8-beta16 or later in FreeBSD and BSD/OS).
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <machine/soundcard.h>
+#include <sys/time.h>
+
+main()
+{
+ int fd, sz, fsz, i, tmp, n, l, have_data=0, nfrag;
+ int caps;
+
+ int sd, sl=0, sp;
+
+ unsigned char data[500000], *dp = data;
+
+ struct buffmem_desc imemd, omemd;
+ caddr_t buf;
+ struct timeval tim;
+
+ unsigned char *op;
+
+ struct audio_buf_info info;
+
+ int frag = 0xffff000c; /* Max # fragments of 2^13=8k bytes */
+
+ fd_set writeset;
+
+ close(0);
+ if ((fd=open("/dev/dsp", O_RDWR, 0))==-1)
+ {
+ perror("/dev/dsp");
+ exit(-1);
+ }
+/*
+ * Then setup sampling parameters. Just sampling rate in this case.
+ */
+
+ tmp = 8000;
+ ioctl(fd, SNDCTL_DSP_SPEED, &tmp);
+
+/*
+ * Load some test data.
+ */
+
+ sl = sp = 0;
+ if ((sd=open("smpl", O_RDONLY, 0))!=-1)
+ {
+ sl = read(sd, data, sizeof(data));
+ printf("%d bytes read from file.\n", sl);
+ close(sd);
+ }
+ else perror("smpl");
+
+ if (ioctl(fd, SNDCTL_DSP_GETCAPS, &caps)==-1)
+ {
+ perror("/dev/dsp");
+ fprintf(stderr, "Sorry but your sound driver is too old\n");
+ exit(-1);
+ }
+
+/*
+ * Check that the device has capability to do this. Currently just
+ * CS4231 based cards will work.
+ *
+ * The application should also check for DSP_CAP_MMAP bit but this
+ * version of driver doesn't have it yet.
+ */
+/* ioctl(fd, SNDCTL_DSP_SETSYNCRO, 0); */
+
+/*
+ * You need version 3.5-beta7 or later of the sound driver before next
+ * two lines compile. There is no point to modify this program to
+ * compile with older driver versions since they don't have working
+ * mmap() support.
+ */
+ if (!(caps & DSP_CAP_TRIGGER) ||
+ !(caps & DSP_CAP_MMAP))
+ {
+ fprintf(stderr, "Sorry but your soundcard can't do this\n");
+ exit(-1);
+ }
+
+/*
+ * Select the fragment size. This is propably important only when
+ * the program uses select(). Fragment size defines how often
+ * select call returns.
+ */
+
+ ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag);
+
+/*
+ * Compute total size of the buffer. It's important to use this value
+ * in mmap() call.
+ */
+
+ if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info)==-1)
+ {
+ perror("GETOSPACE");
+ exit(-1);
+ }
+
+ sz = info.fragstotal * info.fragsize;
+ fsz = info.fragsize;
+/*
+ * Call mmap().
+ *
+ * IMPORTANT NOTE!!!!!!!!!!!
+ *
+ * Full duplex audio devices have separate input and output buffers.
+ * It is not possible to map both of them at the same mmap() call. The buffer
+ * is selected based on the prot argument in the following way:
+ *
+ * - PROT_READ (alone) selects the input buffer.
+ * - PROT_WRITE (alone) selects the output buffer.
+ * - PROT_WRITE|PROT_READ together select the output buffer. This combination
+ * is required in BSD to make the buffer accessible. With just PROT_WRITE
+ * every attempt to access the returned buffer will result in segmentation/bus
+ * error. PROT_READ|PROT_WRITE is also permitted in Linux with OSS version
+ * 3.8-beta16 and later (earlier versions don't accept it).
+ *
+ * Non duplex devices have just one buffer. When an application wants to do both
+ * input and output it's recommended that the device is closed and re-opened when
+ * switching between modes. PROT_READ|PROT_WRITE can be used to open the buffer
+ * for both input and output (with OSS 3.8-beta16 and later) but the result may be
+ * unpredictable.
+ */
+
+ if ((buf=mmap(NULL, sz, PROT_WRITE | PROT_READ, MAP_FILE|MAP_SHARED, fd, 0))==(caddr_t)-1)
+ {
+ perror("mmap (write)");
+ exit(-1);
+ }
+ printf("mmap (out) returned %08x\n", buf);
+ op=buf;
+
+/*
+ * op contains now a pointer to the DMA buffer
+ */
+
+/*
+ * Then it's time to start the engine. The driver doesn't allow read() and/or
+ * write() when the buffer is mapped. So the only way to start operation is
+ * to togle device's enable bits. First set them off. Setting them on enables
+ * recording and/or playback.
+ */
+
+ tmp = 0;
+ ioctl(fd, SNDCTL_DSP_SETTRIGGER, &tmp);
+
+/*
+ * It might be usefull to write some data to the buffer before starting.
+ */
+
+ tmp = PCM_ENABLE_OUTPUT;
+ ioctl(fd, SNDCTL_DSP_SETTRIGGER, &tmp);
+
+/*
+ * The machine is up and running now. Use SNDCTL_DSP_GETOPTR to get the
+ * buffer status.
+ *
+ * NOTE! The driver empties each buffer fragmen after they have been
+ * played. This prevents looping sound if there are some performance problems
+ * in the application side. For similar reasons it recommended that the
+ * application uses some amout of play ahead. It can rewrite the unplayed
+ * data later if necessary.
+ */
+
+ nfrag = 0;
+ while (1)
+ {
+ struct count_info count;
+ int p, l, extra;
+
+ FD_ZERO(&writeset);
+ FD_SET(fd, &writeset);
+
+ tim.tv_sec = 10;
+ tim.tv_usec= 0;
+
+ select(fd+1, &writeset, &writeset, NULL, NULL);
+/*
+ * SNDCTL_DSP_GETOPTR (and GETIPTR as well) return three items. The
+ * bytes field returns number of bytes played since start. It can be used
+ * as a real time clock.
+ *
+ * The blocks field returns number of fragment transitions (interrupts) since
+ * previous GETOPTR call. It can be used as a method to detect underrun
+ * situations.
+ *
+ * The ptr field is the DMA pointer inside the buffer area (in bytes from
+ * the beginning of total buffer area).
+ */
+
+ if (ioctl(fd, SNDCTL_DSP_GETOPTR, &count)==-1)
+ {
+ perror("GETOPTR");
+ exit(-1);
+ }
+ if (count.ptr < 0 ) count.ptr = 0;
+ nfrag += count.blocks;
+
+
+#ifdef VERBOSE
+
+ printf("\rTotal: %09d, Fragment: %03d, Ptr: %06d",
+ count.bytes, nfrag, count.ptr);
+ fflush(stdout);
+#endif
+
+/*
+ * Caution! This version doesn't check for bounds of the DMA
+ * memory area. It's possible that the returned pointer value is not aligned
+ * to fragment boundaries. It may be several samples behind the boundary
+ * in case there was extra delay between the actual hardware interrupt and
+ * the time when DSP_GETOPTR was called.
+ *
+ * Don't just call memcpy() with length set to 'fragment_size' without
+ * first checking that the transfer really fits to the buffer area.
+ * A mistake of just one byte causes seg fault. It may be easiest just
+ * to align the returned pointer value to fragment boundary before using it.
+ *
+ * It would be very good idea to write few extra samples to next fragment
+ * too. Otherwise several (uninitialized) samples from next fragment
+ * will get played before your program gets chance to initialize them.
+ * Take in count the fact thaat there are other processes batling about
+ * the same CPU. This effect is likely to be very annoying if fragment
+ * size is decreased too much.
+ */
+
+/*
+ * Just a minor clarification to the above. The following line alings
+ * the pointer to fragment boundaries. Note! Don't trust that fragment
+ * size is always a power of 2. It may not be so in future.
+ */
+ count.ptr = ((count.ptr+16)/fsz )*fsz;
+#ifdef VERBOSE
+ printf(" memcpy(%6d, %4d)", (dp-data), fsz);
+ fflush(stdout);
+#endif
+
+/*
+ * Set few bytes in the beginning of next fragment too.
+ */
+
+ if ((count.ptr+fsz+16) < sz) /* Last fragment? */
+ extra = 16;
+ else
+ extra = 0;
+ memcpy(op+count.ptr, dp, (fsz+extra));
+ dp += fsz;
+ if (dp > (data+sl-fsz))
+ dp = data;
+
+ }
+
+ exit(0);
+}
diff --git a/sys/i386/isa/sound/mpu401.c b/sys/i386/isa/sound/mpu401.c
index 62b5ecd..60b0c29 100644
--- a/sys/i386/isa/sound/mpu401.c
+++ b/sys/i386/isa/sound/mpu401.c
@@ -1,10 +1,10 @@
/*
* sound/mpu401.c
- *
+ *
* The low level driver for Roland MPU-401 compatible Midi cards.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,10 +24,9 @@
* 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:
- * Riccardo Facchetti 24 Mar 1995
- * - Added the Audio Excel DSP 16 initialization routine.
+ *
+ * Modified: Riccardo Facchetti 24 Mar 1995 - Added the Audio Excel DSP 16
+ * initialization routine.
*/
#define USE_SEQ_MACROS
@@ -35,64 +34,62 @@
#include <i386/isa/sound/sound_config.h>
-#ifdef CONFIGURE_SOUNDCARD
-
-#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI)
+#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
#include <i386/isa/sound/coproc.h>
static int init_sequence[20]; /* NOTE! pos 0 = len, start pos 1. */
+
+#ifdef CONFIG_SEQUENCER
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;
+#endif
+
+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;
+ u_char version, revision;
+ u_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;
+ 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);
- int shared_irq;
- };
+ {printf("MPU: Invalid buffer pointer %d/%d, s=%d\n", dc->m_ptr, dc->m_left, dc->m_state);dc->m_ptr--;}
+ int m_busy;
+ u_char m_buf[MBUF_MAX];
+ int m_ptr;
+ int m_state;
+ int m_left;
+ u_char last_status;
+ void (*inputintr) (int dev, u_char data);
+ int shared_irq;
+ sound_os_info *osp;
+};
#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 mpu401_status(devc) inb( STATPORT(devc->base))
+#define input_avail(devc) (!(mpu401_status(devc)&INPUT_AVAIL))
+#define output_ready(devc) (!(mpu401_status(devc)&OUTPUT_READY))
+#define write_command(devc, cmd) outb( COMDPORT(devc->base), cmd)
+#define read_data(devc) inb( DATAPORT(devc->base))
-#define write_data(base, byte) OUTB(byte, DATAPORT(base))
+#define write_data(devc, byte) outb( DATAPORT(devc->base), byte)
#define OUTPUT_READY 0x40
#define INPUT_AVAIL 0x80
@@ -100,20 +97,18 @@ struct mpu_config
#define MPU_RESET 0xFF
#define UART_MODE_ON 0x3F
-static struct mpu_config dev_conf[MAX_MIDI_DEV] =
-{
- {0}};
+static struct mpu_config dev_conf[MAX_MIDI_DEV] = { {0}};
static int n_mpu_devs = 0;
-static int irq2dev[16] =
-{-1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1};
+static volatile int irq2dev[17] =
+ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
-static int reset_mpu401 (struct mpu_config *devc);
-static void set_uart_mode (int dev, struct mpu_config *devc, int arg);
-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 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};
@@ -134,55 +129,57 @@ static struct synth_info mpu_synth_info[MAX_MIDI_DEV];
#define ST_SONGSEL 103 /* Song select */
#define ST_SONGPOS 104 /* Song position pointer */
-static unsigned char len_tab[] = /* # of data bytes following a status
- */
+static u_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 */
+ 2, /* 8x */
+ 2, /* 9x */
+ 2, /* Ax */
+ 2, /* Bx */
+ 1, /* Cx */
+ 1, /* Dx */
+ 2, /* Ex */
+ 0 /* Fx */
};
+#ifndef CONFIG_SEQUENCER
+#define STORE(cmd)
+#else
#define STORE(cmd) \
{ \
int len; \
- unsigned char obuf[8]; \
+ u_char obuf[8]; \
cmd; \
seq_input_event(obuf, len); \
}
+#endif
+
#define _seqbuf obuf
#define _seqbufptr 0
#define _SEQ_ADVBUF(x) len=x
static int
-mpu_input_scanner (struct mpu_config *devc, unsigned char midic)
+mpu_input_scanner(struct mpu_config * devc, u_char midic)
{
- switch (devc->m_state)
- {
+ switch (devc->m_state) {
case ST_INIT:
- switch (midic)
- {
+ switch (midic) {
case 0xf8:
- /* Timer overflow */
- break;
+ /* Timer overflow */
+ break;
case 0xfc:
- printk ("<all end>");
- break;
+ printf("<all end>");
+ break;
case 0xfd:
- if (devc->timer_flag)
- mpu_timer_interrupt ();
- break;
+ if (devc->timer_flag)
+ mpu_timer_interrupt();
+ break;
case 0xfe:
- return MPU_ACK;
- break;
+ return MPU_ACK;
+ break;
case 0xf0:
case 0xf1:
@@ -192,753 +189,656 @@ mpu_input_scanner (struct mpu_config *devc, unsigned char midic)
case 0xf5:
case 0xf6:
case 0xf7:
- printk ("<Trk data rq #%d>", midic & 0x0f);
- break;
+ printf("<Trk data rq #%d>", midic & 0x0f);
+ break;
case 0xf9:
- printk ("<conductor rq>");
- break;
+ printf("<conductor rq>");
+ break;
case 0xff:
- devc->m_state = ST_SYSMSG;
- break;
+ devc->m_state = ST_SYSMSG;
+ break;
default:
- if (midic <= 0xef)
- {
- /* printk("mpu time: %d ", midic); */
- devc->m_state = ST_TIMED;
- }
- else
- printk ("<MPU: Unknown event %#x> ", midic);
+ if (midic <= 0xef) {
+ /* printf("mpu time: %d ", midic); */
+ devc->m_state = ST_TIMED;
+ } else
+ printf("<MPU: Unknown event %02x> ", midic);
}
- break;
+ 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)
- {
+ {
+ int msg = ((int) (midic & 0xf0) >> 4);
+
+ devc->m_state = ST_DATABYTE;
+
+ if (msg < 8) { /* Data byte */
+ /* printf("midi msg (running status) "); */
+ msg = ((int) (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->synthno, devc->m_buf, devc->m_ptr);
+ devc->m_ptr = 0;
+ }
+ } else if (msg == 0xf) { /* MPU MARK */
devc->m_state = ST_INIT;
- do_midi_msg (devc->synthno, 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 %#x\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->synthno, devc->m_buf, devc->m_ptr);
- devc->m_ptr = 0;
- }
- }
- }
- break;
+ switch (midic) {
+ case 0xf8:
+ /* printf("NOP "); */
+ break;
+
+ case 0xf9:
+ /* printf("meas end "); */
+ break;
+
+ case 0xfc:
+ /* printf("data end "); */
+ break;
+
+ default:
+ printf("Unknown MPU mark %02x\n", midic);
+ }
+ } else {
+ devc->last_status = midic;
+ /* printf ("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->synthno, devc->m_buf, devc->m_ptr);
+ devc->m_ptr = 0;
+ }
+ }
+ }
+ break;
case ST_SYSMSG:
- switch (midic)
- {
+ switch (midic) {
case 0xf0:
- printk ("<SYX>");
- devc->m_state = ST_SYSEX;
- break;
+ printf("<SYX>");
+ devc->m_state = ST_SYSEX;
+ break;
case 0xf1:
- devc->m_state = ST_MTC;
- break;
+ devc->m_state = ST_MTC;
+ break;
case 0xf2:
- devc->m_state = ST_SONGPOS;
- devc->m_ptr = 0;
- break;
+ devc->m_state = ST_SONGPOS;
+ devc->m_ptr = 0;
+ break;
case 0xf3:
- devc->m_state = ST_SONGSEL;
- break;
+ devc->m_state = ST_SONGSEL;
+ break;
case 0xf6:
- /* printk("tune_request\n"); */
- devc->m_state = ST_INIT;
+ /* printf("tune_request\n"); */
+ devc->m_state = ST_INIT;
+ /* XXX do we need a break here ? - lr 970710 */
- /*
- * Real time messages
- */
+ /*
+ * Real time messages
+ */
case 0xf8:
- /* midi clock */
- devc->m_state = ST_INIT;
- timer_ext_event (devc, TMR_CLOCK, 0);
- break;
+ /* 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;
+ 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;
+ 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;
+ devc->m_state = ST_INIT;
+ timer_ext_event(devc, TMR_STOP, 0);
+ break;
case 0xFE:
- /* active sensing */
- devc->m_state = ST_INIT;
- break;
+ /* active sensing */
+ devc->m_state = ST_INIT;
+ break;
case 0xff:
- /* printk("midi hard reset"); */
- devc->m_state = ST_INIT;
- break;
+ /* printf("midi hard reset"); */
+ devc->m_state = ST_INIT;
+ break;
default:
- printk ("unknown MIDI sysmsg %#x\n", midic);
- devc->m_state = ST_INIT;
+ printf("unknown MIDI sysmsg %0x\n", midic);
+ devc->m_state = ST_INIT;
}
- break;
+ break;
case ST_MTC:
- devc->m_state = ST_INIT;
- printk ("MTC frame %#x\n", midic);
- break;
+ devc->m_state = ST_INIT;
+ printf("MTC frame %x02\n", midic);
+ break;
case ST_SYSEX:
- if (midic == 0xf7)
- {
- printk ("<EOX>");
- devc->m_state = ST_INIT;
- }
- else
- printk ("%#x ", midic);
- break;
+ if (midic == 0xf7) {
+ printf("<EOX>");
+ devc->m_state = ST_INIT;
+ } else
+ printf("%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));
+ 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;
+ 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->synthno, devc->m_buf, devc->m_ptr);
- devc->m_ptr = 0;
+ BUFTEST(devc);
+ devc->m_buf[devc->m_ptr++] = midic;
+ if ((--devc->m_left) <= 0) {
+ devc->m_state = ST_INIT;
+ do_midi_msg(devc->synthno, devc->m_buf, devc->m_ptr);
+ devc->m_ptr = 0;
}
- break;
+ break;
default:
- printk ("Bad state %d ", devc->m_state);
- devc->m_state = ST_INIT;
+ printf("Bad state %d ", devc->m_state);
+ devc->m_state = ST_INIT;
}
- return 1;
+ return 1;
}
static void
-mpu401_input_loop (struct mpu_config *devc)
+mpu401_input_loop(struct mpu_config * devc)
{
- unsigned long flags;
- int busy;
- int n;
+ u_long flags;
+ int n, busy;
- DISABLE_INTR (flags);
- busy = devc->m_busy;
- devc->m_busy = 1;
- RESTORE_INTR (flags);
+ flags = splhigh();
+ busy = devc->m_busy;
+ devc->m_busy = 1;
+ splx(flags);
- if (busy) /* Already inside the scanner */
- return;
+ if (busy) /* Already inside the scanner */
+ return;
- n = 50;
+ n = 50;
- while (input_avail (devc->base) && n-- > 0)
- {
- unsigned char c = read_data (devc->base);
+ while (input_avail(devc) && n-- > 0) {
+ u_char c = read_data(devc);
- if (devc->mode == MODE_SYNTH)
- {
- mpu_input_scanner (devc, c);
- }
- else if (devc->opened & OPEN_READ && devc->inputintr != NULL)
- devc->inputintr (devc->devno, c);
+ if (devc->mode == MODE_SYNTH) {
+ mpu_input_scanner(devc, c);
+ } else if (devc->opened & OPEN_READ && devc->inputintr != NULL)
+ devc->inputintr(devc->devno, c);
}
- devc->m_busy = 0;
+ devc->m_busy = 0;
}
void
-mpuintr (INT_HANDLER_PARMS (irq, dummy))
+mpuintr(int irq)
{
- struct mpu_config *devc;
- int dev;
+ struct mpu_config *devc;
+ int dev;
-#ifdef linux
- sti ();
-#endif
-
- if (irq < 1 || irq > 15)
- {
- printk ("MPU-401: Interrupt #%d?\n", irq);
- return;
- }
+ /*
+ * FreeBSD (and some others) pass unit number to the interrupt
+ * handler. In this case we have to scan the table for first handler.
+ */
- dev = irq2dev[irq];
- if (dev == -1)
- {
- /* printk ("MPU-401: Interrupt #%d?\n", irq); */
- return;
- }
+ if (irq < 1 || irq > 15) {
+ dev = -1;
+ } else
+ dev = irq2dev[irq];
- devc = &dev_conf[dev];
+ if (dev == -1) {
+ int origirq = irq;
- if (input_avail (devc->base))
- if (devc->base != 0 && (devc->opened & OPEN_READ || devc->mode == MODE_SYNTH))
- mpu401_input_loop (devc);
- else
- {
- /* Dummy read (just to acknowledge the interrupt) */
- read_data (devc->base);
- }
+ for (irq = 0; irq <= 16; irq++)
+ if (irq2dev[irq] != -1)
+ break;
+ if (irq > 15) {
+ printf("MPU-401: Bogus interrupt #%d?\n", origirq);
+ return;
+ }
+ dev = irq2dev[irq];
+ devc = &dev_conf[dev];
+ } else
+ devc = &dev_conf[dev];
+
+ if (input_avail(devc))
+ if (devc->base != 0 && (devc->opened & OPEN_READ || devc->mode == MODE_SYNTH))
+ mpu401_input_loop(devc);
+ else {
+ /* Dummy read (just to acknowledge the interrupt) */
+ read_data(devc);
+ }
}
static int
-mpu401_open (int dev, int mode,
- void (*input) (int dev, unsigned char data),
- void (*output) (int dev)
-)
+mpu401_open(int dev, int mode,
+ void (*input) (int dev, u_char data), void (*output) (int dev))
{
- int err;
- struct mpu_config *devc;
+ int err;
+ struct mpu_config *devc;
- if (dev < 0 || dev >= num_midis)
- return RET_ERROR (ENXIO);
+ if (dev < 0 || dev >= num_midis)
+ return -(ENXIO);
- devc = &dev_conf[dev];
+ devc = &dev_conf[dev];
- if (devc->opened)
- {
- printk ("MPU-401: Midi busy\n");
- return RET_ERROR (EBUSY);
+ if (devc->opened) {
+ printf("MPU-401: Midi busy\n");
+ return -(EBUSY);
}
-
- /*
- * Verify that the device is really running.
- * Some devices (such as Ensoniq SoundScape don't
- * work before the on board processor (OBP) is initialized
- * by downloadin it's microcode.
- */
-
- if (!devc->initialized)
- {
- if (mpu401_status (devc->base) == 0xff) /* Bus float */
- {
- printk ("MPU-401: Device not initialized properly\n");
- return RET_ERROR (EIO);
+ /*
+ * Verify that the device is really running. Some devices (such as
+ * Ensoniq SoundScape don't work before the on board processor (OBP)
+ * is initialized by downloadin it's microcode.
+ */
+
+ if (!devc->initialized) {
+ if (mpu401_status(devc) == 0xff) { /* Bus float */
+ printf("MPU-401: Device not initialized properly\n");
+ return -(EIO);
}
- reset_mpu401 (devc);
+ reset_mpu401(devc);
}
+ irq2dev[devc->irq] = dev;
- irq2dev[devc->irq] = dev;
- if (devc->shared_irq == 0)
- if ((err = snd_set_irq_handler (devc->irq, mpuintr, midi_devs[dev]->info.name) < 0))
- {
- return err;
- }
+ if (midi_devs[dev]->coproc)
+ if ((err = midi_devs[dev]->coproc->
+ open(midi_devs[dev]->coproc->devc, COPR_MIDI)) < 0) {
+ printf("MPU-401: Can't access coprocessor device\n");
- if (midi_devs[dev]->coproc)
- if ((err = midi_devs[dev]->coproc->
- open (midi_devs[dev]->coproc->devc, COPR_MIDI)) < 0)
- {
- if (devc->shared_irq == 0)
- snd_release_irq (devc->irq);
- printk ("MPU-401: Can't access coprocessor device\n");
-
- return err;
- }
-
- set_uart_mode (dev, devc, 1);
- devc->mode = MODE_MIDI;
- devc->synthno = 0;
+ return err;
+ }
+ set_uart_mode(dev, devc, 1);
+ devc->mode = MODE_MIDI;
+ devc->synthno = 0;
- mpu401_input_loop (devc);
+ mpu401_input_loop(devc);
- devc->inputintr = input;
- devc->opened = mode;
+ devc->inputintr = input;
+ devc->opened = mode;
- return 0;
+ return 0;
}
static void
-mpu401_close (int dev)
+mpu401_close(int dev)
{
- struct mpu_config *devc;
+ struct mpu_config *devc;
- devc = &dev_conf[dev];
+ devc = &dev_conf[dev];
- if (devc->uart_mode)
- reset_mpu401 (devc); /*
- * This disables the UART mode
- */
- devc->mode = 0;
+ if (devc->uart_mode)
+ reset_mpu401(devc); /* This disables the UART mode */
+ devc->mode = 0;
- if (devc->shared_irq == 0)
- snd_release_irq (devc->irq);
- devc->inputintr = NULL;
+ devc->inputintr = NULL;
- if (midi_devs[dev]->coproc)
- midi_devs[dev]->coproc->close (midi_devs[dev]->coproc->devc, COPR_MIDI);
- devc->opened = 0;
+ if (midi_devs[dev]->coproc)
+ midi_devs[dev]->coproc->close(midi_devs[dev]->coproc->devc, COPR_MIDI);
+ devc->opened = 0;
}
static int
-mpu401_out (int dev, unsigned char midi_byte)
+mpu401_out(int dev, u_char midi_byte)
{
- int timeout;
- unsigned long flags;
+ int timeout;
+ u_long flags;
- struct mpu_config *devc;
+ struct mpu_config *devc;
- devc = &dev_conf[dev];
+ devc = &dev_conf[dev];
-#if 0
- /*
- * Test for input since pending input seems to block the output.
- */
+ /*
+ * Sometimes it takes about 13000 loops before the output becomes
+ * ready (After reset). Normally it takes just about 10 loops.
+ */
- 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.
- */
-
- for (timeout = 3000; timeout > 0 && !output_ready (devc->base); timeout--);
-
- DISABLE_INTR (flags);
- if (!output_ready (devc->base))
- {
- printk ("MPU-401: Send data (%#x) timeout\n", midi_byte);
- RESTORE_INTR (flags);
- return 0;
- }
+ for (timeout = 3000; timeout > 0 && !output_ready(devc); timeout--);
- write_data (devc->base, midi_byte);
- RESTORE_INTR (flags);
- return 1;
+ flags = splhigh();
+ if (!output_ready(devc)) {
+ printf("MPU-401: Send data timeout\n");
+ splx(flags);
+ return 0;
+ }
+ write_data(devc, midi_byte);
+ splx(flags);
+ return 1;
}
static int
-mpu401_command (int dev, mpu_command_rec * cmd)
+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);
- }
+ int i, timeout, ok;
+ int ret = 0;
+ u_long flags;
+ struct mpu_config *devc;
- /*
- * Test for input since pending input seems to block the output.
- */
- if (input_avail (devc->base))
- mpu401_input_loop (devc);
+ devc = &dev_conf[dev];
- /*
- * Sometimes it takes about 30000 loops before the output becomes ready
- * (After reset). Normally it takes just about 10 loops.
- */
-
- timeout = 30000;
+ if (devc->uart_mode) { /* Not possible in UART mode */
+ printf("MPU-401 commands not possible in the UART mode\n");
+ return -(EINVAL);
+ }
+ /*
+ * Test for input since pending input seems to block the output.
+ */
+ if (input_avail(devc))
+ mpu401_input_loop(devc);
+
+ /*
+ * Sometimes it takes about 30000 loops before the output becomes
+ * ready (After reset). Normally it takes just about 10 loops.
+ */
+
+ timeout = 30000;
retry:
- if (timeout-- <= 0)
- {
- printk ("MPU-401: Command (%#x) timeout\n", (int) cmd->cmd);
- return RET_ERROR (EIO);
+ if (timeout-- <= 0) {
+ printf("MPU-401: Command (0x%x) timeout\n", (int) cmd->cmd);
+ return -(EIO);
}
+ flags = splhigh();
- DISABLE_INTR (flags);
-
- if (!output_ready (devc->base))
- {
- RESTORE_INTR (flags);
- goto retry;
+ if (!output_ready(devc)) {
+ splx(flags);
+ goto retry;
}
+ write_command(devc, cmd->cmd);
+ ok = 0;
+ for (timeout = 50000; timeout > 0 && !ok; timeout--)
+ if (input_avail(devc))
+ if (devc->opened && devc->mode == MODE_SYNTH) {
+ if (mpu_input_scanner(devc, read_data(devc)) == MPU_ACK)
+ ok = 1;
+ } else {/* Device is not currently open. Use simplier method */
+ if (read_data(devc) == MPU_ACK)
+ ok = 1;
+ }
- write_command (devc->base, cmd->cmd);
- ok = 0;
- for (timeout = 50000; timeout > 0 && !ok; timeout--)
- if (input_avail (devc->base))
- if (devc->opened && devc->mode == MODE_SYNTH)
- {
- if (mpu_input_scanner (devc, read_data (devc->base)) == MPU_ACK)
- ok = 1;
- }
- else
- { /* Device is not currently open. Use simplier method */
- if (read_data (devc->base) == MPU_ACK)
- ok = 1;
- }
-
- if (!ok)
- {
- RESTORE_INTR (flags);
- /* printk ("MPU: No ACK to command (%#x)\n", (int) cmd->cmd); */
- return RET_ERROR (EIO);
+ if (!ok) {
+ splx(flags);
+ /* printf ("MPU: No ACK to command (0x%x)\n", (int) cmd->cmd); */
+ return -(EIO);
}
-
- if (cmd->nr_args)
- for (i = 0; i < cmd->nr_args; i++)
- {
- for (timeout = 3000; timeout > 0 && !output_ready (devc->base); timeout--);
-
- if (!mpu401_out (dev, cmd->data[i]))
- {
- RESTORE_INTR (flags);
- printk ("MPU: Command (%#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 (cmd->nr_args)
+ for (i = 0; i < cmd->nr_args; i++) {
+ for (timeout = 3000; timeout > 0 && !output_ready(devc); timeout--);
+ if (!mpu401_out(dev, cmd->data[i])) {
+ splx(flags);
+ printf("MPU: Command (0x%x), parm send failed.\n", (int) cmd->cmd);
+ return -(EIO);
}
+ }
- if (!ok)
- {
- RESTORE_INTR (flags);
- /* printk ("MPU: No response(%d) to command (%#x)\n", i, (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)) {
+ cmd->data[i] = read_data(devc);
+ ok = 1;
+ }
+ if (!ok) {
+ splx(flags);
+ /* printf ("MPU: No response(%d) to command (0x%x)\n",
+ * i, (int) cmd->cmd);
+ */
+ return -(EIO);
+ }
+ }
- RESTORE_INTR (flags);
+ splx(flags);
- return ret;
+ return ret;
}
static int
-exec_cmd (int dev, int cmd, int data)
+mpu_cmd(int dev, int cmd, int data)
{
- int ret;
+ int ret;
- static mpu_command_rec rec;
+ 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;
+ 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];
+ if ((ret = mpu401_command(dev, &rec)) < 0) {
+ return ret;
+ }
+ return (u_char) rec.data[0];
}
static int
-mpu401_prefix_cmd (int dev, unsigned char status)
+mpu401_prefix_cmd(int dev, u_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;
- }
+ struct mpu_config *devc = &dev_conf[dev];
- switch (status)
- {
- case 0xF0:
- if (exec_cmd (dev, 0xDF, 0) < 0)
- return 0;
+ if (devc->uart_mode)
+ return 1;
- return 1;
- break;
+ if (status < 0xf0) {
+ if (mpu_cmd(dev, 0xD0, 0) < 0) {
+ return 0;
+ }
+ return 1;
+ }
+ switch (status) {
+ case 0xF0:
+ if (mpu_cmd(dev, 0xDF, 0) < 0) {
+ return 0;
+ }
+ return 1;
+ break;
- default:
- return 0;
- }
+ default:
+ return 0;
+ }
- return 0;
}
static int
-mpu401_start_read (int dev)
+mpu401_start_read(int dev)
{
- return 0;
+ return 0;
}
static int
-mpu401_end_read (int dev)
+mpu401_end_read(int dev)
{
- return 0;
+ return 0;
}
static int
-mpu401_ioctl (int dev, unsigned cmd, unsigned arg)
+mpu401_ioctl(int dev, u_int cmd, ioctl_arg arg)
{
- struct mpu_config *devc;
+ struct mpu_config *devc;
- devc = &dev_conf[dev];
+ devc = &dev_conf[dev];
- switch (cmd)
- {
+ switch (cmd) {
case 1:
- IOCTL_FROM_USER ((char *) &init_sequence, (char *) arg, 0, sizeof (init_sequence));
- return 0;
- break;
+ bcopy(&(((char *) arg)[0]), (char *) init_sequence, 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);
+ if (!(devc->capabilities & MPU_CAP_INTLG)) { /* No intelligent mode */
+ printf("MPU-401: Intelligent mode not supported by the HW\n");
+ return -(EINVAL);
}
- set_uart_mode (dev, devc, !IOCTL_IN (arg));
- return 0;
- break;
+ set_uart_mode(dev, devc, !(*(int *) arg));
+ return 0;
+ break;
case SNDCTL_MIDI_MPUCMD:
- {
- int ret;
- mpu_command_rec rec;
-
- IOCTL_FROM_USER ((char *) &rec, (char *) arg, 0, sizeof (rec));
+ {
+ int ret;
+ mpu_command_rec rec;
- if ((ret = mpu401_command (dev, &rec)) < 0)
- return ret;
+ bcopy(&(((char *) arg)[0]), (char *) &rec, sizeof(rec));
- IOCTL_TO_USER ((char *) arg, 0, (char *) &rec, sizeof (rec));
- return 0;
- }
- break;
+ if ((ret = mpu401_command(dev, &rec)) < 0)
+ return ret;
+ bcopy((char *) &rec, &(((char *) arg)[0]), sizeof(rec));
+ return 0;
+ }
+ break;
default:
- return RET_ERROR (EINVAL);
+ return -(EINVAL);
}
}
static void
-mpu401_kick (int dev)
+mpu401_kick(int dev)
{
}
static int
-mpu401_buffer_status (int dev)
+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)
+mpu_synth_ioctl(int dev,
+ u_int cmd, ioctl_arg arg)
{
- int midi_dev;
- struct mpu_config *devc;
+ int midi_dev;
+ struct mpu_config *devc;
- midi_dev = synth_devs[dev]->midi_dev;
+ midi_dev = synth_devs[dev]->midi_dev;
- if (midi_dev < 0 || midi_dev > num_midis)
- return RET_ERROR (ENXIO);
+ if (midi_dev < 0 || midi_dev > num_midis)
+ return -(ENXIO);
- devc = &dev_conf[midi_dev];
+ devc = &dev_conf[midi_dev];
- switch (cmd)
- {
+ switch (cmd) {
case SNDCTL_SYNTH_INFO:
- IOCTL_TO_USER ((char *) arg, 0, &mpu_synth_info[midi_dev],
- sizeof (struct synth_info));
-
- return 0;
- break;
+ bcopy(&mpu_synth_info[midi_dev], &(((char *) arg)[0]), sizeof(struct synth_info));
+ return 0;
+ break;
case SNDCTL_SYNTH_MEMAVL:
- return 0x7fffffff;
- break;
+ return 0x7fffffff;
+ break;
default:
- return RET_ERROR (EINVAL);
+ return -(EINVAL);
}
}
static int
-mpu_synth_open (int dev, int mode)
+mpu_synth_open(int dev, int mode)
{
- int midi_dev, err;
- struct mpu_config *devc;
+ int midi_dev, err;
+ struct mpu_config *devc;
- midi_dev = synth_devs[dev]->midi_dev;
+ midi_dev = synth_devs[dev]->midi_dev;
- if (midi_dev < 0 || midi_dev > num_midis)
- {
- return RET_ERROR (ENXIO);
+ if (midi_dev < 0 || midi_dev > num_midis) {
+ return -(ENXIO);
}
+ devc = &dev_conf[midi_dev];
+
+ /*
+ * Verify that the device is really running. Some devices (such as
+ * Ensoniq SoundScape don't work before the on board processor (OBP)
+ * is initialized by downloadin it's microcode.
+ */
+
+ if (!devc->initialized) {
+ if (mpu401_status(devc) == 0xff) { /* Bus float */
+ printf("MPU-401: Device not initialized properly\n");
+ return -(EIO);
+ }
+ reset_mpu401(devc);
+ }
+ if (devc->opened) {
+ printf("MPU-401: Midi busy\n");
+ return -(EBUSY);
+ }
+ devc->mode = MODE_SYNTH;
+ devc->synthno = dev;
- devc = &dev_conf[midi_dev];
+ devc->inputintr = NULL;
+ irq2dev[devc->irq] = midi_dev;
- /*
- * Verify that the device is really running.
- * Some devices (such as Ensoniq SoundScape don't
- * work before the on board processor (OBP) is initialized
- * by downloadin it's microcode.
- */
+ if (midi_devs[midi_dev]->coproc)
+ if ((err = midi_devs[midi_dev]->coproc->
+ open(midi_devs[midi_dev]->coproc->devc, COPR_MIDI)) < 0) {
+ printf("MPU-401: Can't access coprocessor device\n");
- if (!devc->initialized)
- {
- if (mpu401_status (devc->base) == 0xff) /* Bus float */
- {
- printk ("MPU-401: Device not initialized properly\n");
- return RET_ERROR (EIO);
+ return err;
}
- reset_mpu401 (devc);
- }
-
- if (devc->opened)
- {
- printk ("MPU-401: Midi busy\n");
- return RET_ERROR (EBUSY);
- }
+ devc->opened = mode;
+ reset_mpu401(devc);
- devc->mode = MODE_SYNTH;
- devc->synthno = dev;
-
- devc->inputintr = NULL;
- irq2dev[devc->irq] = midi_dev;
- if (devc->shared_irq == 0)
- if ((err = snd_set_irq_handler (devc->irq, mpuintr, midi_devs[midi_dev]->info.name) < 0))
- {
- return err;
- }
-
- if (midi_devs[midi_dev]->coproc)
- if ((err = midi_devs[midi_dev]->coproc->
- open (midi_devs[midi_dev]->coproc->devc, COPR_MIDI)) < 0)
- {
- if (devc->shared_irq == 0)
- snd_release_irq (devc->irq);
- printk ("MPU-401: Can't access coprocessor device\n");
-
- return err;
- }
-
- devc->opened = mode;
- reset_mpu401 (devc);
-
- if (mode & OPEN_READ)
- {
- exec_cmd (midi_dev, 0x8B, 0); /* Enable data in stop mode */
- exec_cmd (midi_dev, 0x34, 0); /* Return timing bytes in stop mode */
+ if (mode & OPEN_READ) {
+ mpu_cmd(midi_dev, 0x8B, 0); /* Enable data in stop mode */
+ mpu_cmd(midi_dev, 0x34, 0); /* Return timing bytes in stop mode */
}
-
- return 0;
+ return 0;
}
static void
-mpu_synth_close (int dev)
+mpu_synth_close(int dev)
{
- int midi_dev;
- struct mpu_config *devc;
+ int midi_dev;
+ struct mpu_config *devc;
- midi_dev = synth_devs[dev]->midi_dev;
+ 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 = &dev_conf[midi_dev];
+ mpu_cmd(midi_dev, 0x15, 0); /* Stop recording, playback and MIDI */
+ mpu_cmd(midi_dev, 0x8a, 0); /* Disable data in stopped mode */
- if (devc->shared_irq == 0)
- snd_release_irq (devc->irq);
- devc->inputintr = NULL;
+ devc->inputintr = NULL;
- if (midi_devs[midi_dev]->coproc)
- midi_devs[midi_dev]->coproc->close (midi_devs[midi_dev]->coproc->devc, COPR_MIDI);
- devc->opened = 0;
- devc->mode = 0;
+ if (midi_devs[midi_dev]->coproc)
+ midi_devs[midi_dev]->coproc->close(midi_devs[midi_dev]->coproc->devc, COPR_MIDI);
+ devc->opened = 0;
+ devc->mode = 0;
}
#define MIDI_SYNTH_NAME "MPU-401 UART Midi"
@@ -947,836 +847,782 @@ mpu_synth_close (int dev)
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,
- NULL, /* alloc */
- midi_synth_setup_voice
+ 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,
+ NULL, /* alloc */
+ midi_synth_setup_voice,
+ midi_synth_send_sysex
};
-static struct synth_operations mpu401_synth_operations[MAX_MIDI_DEV];
+static struct synth_operations *mpu401_synth_operations[MAX_MIDI_DEV];
static struct midi_operations mpu401_midi_proto =
{
- {"MPU-401 Midi", 0, MIDI_CAP_MPU401, SNDCARD_MPU401},
- NULL,
- {0},
- mpu401_open,
- mpu401_close,
- mpu401_ioctl,
- mpu401_out,
- mpu401_start_read,
- mpu401_end_read,
- mpu401_kick,
- NULL,
- mpu401_buffer_status,
- mpu401_prefix_cmd
+ {"MPU-401 Midi", 0, MIDI_CAP_MPU401, SNDCARD_MPU401},
+ NULL,
+ {0},
+ mpu401_open,
+ mpu401_close,
+ mpu401_ioctl,
+ mpu401_out,
+ mpu401_start_read,
+ mpu401_end_read,
+ mpu401_kick,
+ 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)
+mpu401_chk_version(struct mpu_config * devc)
{
- int tmp;
+ int tmp;
- devc->version = devc->revision = 0;
+ devc->version = devc->revision = 0;
- if ((tmp = exec_cmd (num_midis, 0xAC, 0)) < 0)
- return;
+ if ((tmp = mpu_cmd(num_midis, 0xAC, 0)) < 0)
+ return;
- if ((tmp & 0xf0) > 0x20) /* Why it's larger than 2.x ??? */
- return;
+ if ((tmp & 0xf0) > 0x20)/* Why it's larger than 2.x ??? */
+ return;
- devc->version = tmp;
+ devc->version = tmp;
- if ((tmp = exec_cmd (num_midis, 0xAD, 0)) < 0)
- {
- devc->version = 0;
- return;
+ if ((tmp = mpu_cmd(num_midis, 0xAD, 0)) < 0) {
+ devc->version = 0;
+ return;
}
- devc->revision = tmp;
+ devc->revision = tmp;
}
-long
-attach_mpu401 (long mem_start, struct address_info *hw_config)
+void
+attach_mpu401(struct address_info * hw_config)
{
- unsigned long flags;
- char revision_char;
+ u_long flags;
+ char revision_char;
- struct mpu_config *devc;
+ struct mpu_config *devc;
- if (num_midis >= MAX_MIDI_DEV)
- {
- printk ("MPU-401: Too many midi devices detected\n");
- return mem_start;
+ if (num_midis >= MAX_MIDI_DEV) {
+ printf("MPU-401: Too many midi devices detected\n");
+ return ;
}
-
- 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;
- devc->shared_irq = hw_config->always_detect;
-
- if (hw_config->always_detect)
- {
- /* Verify the hardware again */
- if (!reset_mpu401 (devc))
- return mem_start;
-
- DISABLE_INTR (flags);
- mpu401_chk_version (devc);
- if (devc->version == 0)
- mpu401_chk_version (devc);
- RESTORE_INTR (flags);
+ devc = &dev_conf[num_midis];
+
+ devc->base = hw_config->io_base;
+ devc->osp = hw_config->osp;
+ 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;
+ devc->shared_irq = hw_config->always_detect;
+ devc->irq = hw_config->irq;
+
+ if (devc->irq < 0) {
+ devc->irq *= -1;
+ devc->shared_irq = 1;
}
+ irq2dev[devc->irq] = num_midis;
+
+ if (!hw_config->always_detect) {
+ /* Verify the hardware again */
+ if (!reset_mpu401(devc))
+ return ;
- if (devc->version == 0)
- {
- memcpy ((char *) &mpu401_synth_operations[num_midis],
- (char *) &std_midi_synth,
- sizeof (struct synth_operations));
+ if (!devc->shared_irq)
+ if (snd_set_irq_handler(devc->irq, mpuintr, devc->osp) < 0) {
+ return ;
+ }
+ flags = splhigh();
+ mpu401_chk_version(devc);
+ if (devc->version == 0)
+ mpu401_chk_version(devc);
+ splx(flags);
+ };
+
+ if (devc->version != 0)
+ if (mpu_cmd(num_midis, 0xC5, 0) >= 0) /* Set timebase OK */
+ if (mpu_cmd(num_midis, 0xE0, 120) >= 0) /* Set tempo OK */
+ devc->capabilities |= MPU_CAP_INTLG; /* Supports intelligent
+ * mode */
+
+ mpu401_synth_operations[num_midis] = (struct synth_operations *) malloc(sizeof(struct synth_operations), M_DEVBUF, M_NOWAIT);
+
+ if (!mpu401_synth_operations[num_midis])
+ panic("SOUND: Cannot allocate memory\n");
+
+ if (mpu401_synth_operations[num_midis] == NULL) {
+ printf("mpu401: Can't allocate memory\n");
+ return ;
}
- else
- {
- devc->capabilities |= MPU_CAP_INTLG; /* Supports intelligent mode */
- memcpy ((char *) &mpu401_synth_operations[num_midis],
- (char *) &mpu401_synth_proto,
- sizeof (struct synth_operations));
+ if (!(devc->capabilities & MPU_CAP_INTLG)) { /* No intelligent mode */
+ bcopy((char *) &std_midi_synth, (char *) mpu401_synth_operations[num_midis], sizeof(struct synth_operations));
+ } else {
+ bcopy((char *) &mpu401_synth_proto, (char *) mpu401_synth_operations[num_midis], sizeof(struct synth_operations));
}
- memcpy ((char *) &mpu401_midi_operations[num_midis],
- (char *) &mpu401_midi_proto,
- sizeof (struct midi_operations));
+ bcopy((char *) &mpu401_midi_proto, (char *) &mpu401_midi_operations[num_midis], sizeof(struct midi_operations));
- mpu401_midi_operations[num_midis].converter =
- &mpu401_synth_operations[num_midis];
+ 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));
+ bcopy((char *) &mpu_synth_info_proto, (char *) &mpu_synth_info[num_midis], sizeof(struct synth_info));
- n_mpu_devs++;
+ n_mpu_devs++;
- if (devc->version == 0x20 && devc->revision >= 0x07) /* MusicQuest interface */
- {
- int ports = (devc->revision & 0x08) ? 32 : 16;
+ 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;
+ devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_SMPTE |
+ MPU_CAP_CLS | MPU_CAP_2PORT;
- revision_char = (devc->revision == 0x7f) ? 'M' : ' ';
-#if defined(__FreeBSD__)
- printk ("mpu0: <MQX-%d%c MIDI Interface>",
-#else
- printk (" <MQX-%d%c MIDI Interface>",
-#endif
- ports,
- revision_char);
- sprintf (mpu_synth_info[num_midis].name,
- "MQX-%d%c MIDI Interface #%d",
- ports,
- revision_char,
- n_mpu_devs);
- }
- else
- {
+ revision_char = (devc->revision == 0x7f) ? 'M' : ' ';
+ sprintf(mpu_synth_info[num_midis].name,
+ "MQX-%d%c MIDI Interface #%d",
+ ports,
+ revision_char,
+ n_mpu_devs);
+ } else {
- revision_char = devc->revision ? devc->revision + '@' : ' ';
- if (devc->revision > ('Z' - '@'))
- revision_char = '+';
+ revision_char = devc->revision ? devc->revision + '@' : ' ';
+ if ((int) devc->revision > ('Z' - '@'))
+ revision_char = '+';
- devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_FSK;
+ devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_FSK;
-#if defined(__FreeBSD__)
- printk ("mpu0: <MPU-401 MIDI Interface %d.%d%c>",
-#else
- printk (" <MPU-401 MIDI Interface %d.%d%c>",
-#endif
- (devc->version & 0xf0) >> 4,
- devc->version & 0x0f,
- revision_char);
- 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);
+ sprintf(mpu_synth_info[num_midis].name,
+ "MPU-401 %d.%d%c Midi interface #%d",
+ (int) (devc->version & 0xf0) >> 4,
+ devc->version & 0x0f,
+ revision_char,
+ n_mpu_devs);
}
- strcpy (mpu401_midi_operations[num_midis].info.name,
- mpu_synth_info[num_midis].name);
+ strcpy(mpu401_midi_operations[num_midis].info.name,
+ mpu_synth_info[num_midis].name);
+
+ conf_printf(mpu_synth_info[num_midis].name, hw_config);
- mpu401_synth_operations[num_midis].midi_dev = devc->devno = num_midis;
- mpu401_synth_operations[devc->devno].info =
- &mpu_synth_info[devc->devno];
+ mpu401_synth_operations[num_midis]->midi_dev = devc->devno = num_midis;
+ mpu401_synth_operations[devc->devno]->info =
+ &mpu_synth_info[devc->devno];
- if (devc->capabilities & MPU_CAP_INTLG) /* Has timer */
- mpu_timer_init (num_midis);
+ if (devc->capabilities & MPU_CAP_INTLG) /* Intelligent mode */
+ mpu_timer_init(num_midis);
- irq2dev[devc->irq] = num_midis;
- midi_devs[num_midis++] = &mpu401_midi_operations[devc->devno];
- return mem_start;
+ irq2dev[devc->irq] = num_midis;
+ midi_devs[num_midis++] = &mpu401_midi_operations[devc->devno];
+ return ;
}
static int
-reset_mpu401 (struct mpu_config *devc)
+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;
-
- timeout_limit = devc->initialized ? 30000 : 100000;
- devc->initialized = 1;
-
- for (n = 0; n < 2 && !ok; n++)
- {
- 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 = 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);
+ u_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;
+
+ timeout_limit = devc->initialized ? 30000 : 100000;
+ devc->initialized = 1;
+
+ for (n = 0; n < 2 && !ok; n++) {
+ for (timeout = timeout_limit; timeout > 0 && !ok; timeout--)
+ ok = output_ready(devc);
+
+ write_command(devc, 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 = timeout_limit * 2; timeout > 0 && !ok; timeout--) {
+ flags = splhigh();
+ if ( (input_avail(devc)) && (read_data(devc) == MPU_ACK) )
+ ok = 1;
+ splx(flags);
}
}
- devc->m_state = ST_INIT;
- devc->m_ptr = 0;
- devc->m_left = 0;
- devc->last_status = 0;
- devc->uart_mode = 0;
+ devc->m_state = ST_INIT;
+ devc->m_ptr = 0;
+ devc->m_left = 0;
+ devc->last_status = 0;
+ devc->uart_mode = 0;
- return ok;
+ return ok;
}
static void
-set_uart_mode (int dev, struct mpu_config *devc, int arg)
+set_uart_mode(int dev, struct mpu_config * devc, int arg)
{
-
- if (!arg && devc->version == 0)
- {
- return;
+ if (!arg && (devc->capabilities & MPU_CAP_INTLG))
+ return;
+ if ((devc->uart_mode == 0) == (arg == 0))
+ return; /* Already set */
+ reset_mpu401(devc); /* This exits the uart mode */
+
+ if (arg && (mpu_cmd(dev, UART_MODE_ON, 0) < 0) ) {
+ printf("MPU%d: Can't enter UART mode\n", devc->devno);
+ devc->uart_mode = 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;
-
+ devc->uart_mode = arg;
}
int
-probe_mpu401 (struct address_info *hw_config)
+probe_mpu401(struct address_info * hw_config)
{
- int ok = 0;
- struct mpu_config tmp_devc;
+ 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;
+ tmp_devc.base = hw_config->io_base;
+ tmp_devc.irq = hw_config->irq;
+ tmp_devc.initialized = 0;
+ tmp_devc.opened = 0;
+ tmp_devc.osp = hw_config->osp;
-#if !defined(EXCLUDE_AEDSP16) && defined(AEDSP16_MPU401)
- /*
+#if defined(CONFIG_AEDSP16) && defined(AEDSP16_MPU401)
+ /*
* Initialize Audio Excel DSP 16 to MPU-401, before any operation.
- */
- InitAEDSP16_MPU401 (hw_config);
+ */
+ InitAEDSP16_MPU401(hw_config);
#endif
- if (hw_config->always_detect)
- return 1;
-
- if (INB (hw_config->io_base + 1) == 0xff)
- return 0; /* Just bus float? */
+ if (hw_config->always_detect)
+ return 1;
- ok = reset_mpu401 (&tmp_devc);
+ if (inb(hw_config->io_base + 1) == 0xff) {
+ DDB(printf("MPU401: Port %x looks dead.\n", hw_config->io_base));
+ return 0; /* Just bus float? */
+ }
+ ok = reset_mpu401(&tmp_devc);
- return ok;
+ if (!ok) {
+ DDB(printf("MPU401: Reset failed on port %x\n", hw_config->io_base));
+ }
+ return ok;
}
-/*****************************************************
+
+/*
* Timer stuff
- ****************************************************/
+ */
-#if !defined(EXCLUDE_SEQUENCER)
+#if defined(CONFIG_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 volatile u_long next_event_time;
+static volatile u_long curr_ticks, curr_clocks;
+static u_long prev_event_time;
static int metronome_mode;
-static unsigned long
-clocks2ticks (unsigned long clocks)
+static u_long
+clocks2ticks(u_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;
+ /*
+ * 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)
+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;
+ int hw_val;
+
+ if (val < 48)
+ val = 48;
+ if (val > 1000)
+ val = 1000;
+ hw_val = val;
+ hw_val = (hw_val + 12) / 24;
+ if (hw_val > max_timebase)
+ hw_val = max_timebase;
+
+ if (mpu_cmd(midi_dev, 0xC0 | (hw_val & 0x0f), 0) < 0) {
+ printf("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)
+tmr_reset(void)
{
- unsigned long flags;
+ u_long flags;
- DISABLE_INTR (flags);
- next_event_time = 0xffffffff;
- prev_event_time = 0;
- curr_ticks = curr_clocks = 0;
- RESTORE_INTR (flags);
+ flags = splhigh();
+ next_event_time = 0xffffffff;
+ prev_event_time = 0;
+ curr_ticks = curr_clocks = 0;
+ splx(flags);
}
static void
-set_timer_mode (int midi_dev)
+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 */
+ if (timer_mode & TMR_MODE_CLS)
+ mpu_cmd(midi_dev, 0x3c, 0); /* Use CLS sync */
+ else if (timer_mode & TMR_MODE_SMPTE)
+ mpu_cmd(midi_dev, 0x3d, 0); /* Use SMPTE sync */
+
+ if (timer_mode & TMR_INTERNAL)
+ mpu_cmd(midi_dev, 0x80, 0); /* Use MIDI sync */
+ else {
+ if (timer_mode & (TMR_MODE_MIDI | TMR_MODE_CLS)) {
+ mpu_cmd(midi_dev, 0x82, 0); /* Use MIDI sync */
+ mpu_cmd(midi_dev, 0x91, 0); /* Enable ext MIDI ctrl */
+ } else if (timer_mode & TMR_MODE_FSK)
+ mpu_cmd(midi_dev, 0x81, 0); /* Use FSK sync */
}
}
static void
-stop_metronome (int midi_dev)
+stop_metronome(int midi_dev)
{
- exec_cmd (midi_dev, 0x84, 0); /* Disable metronome */
+ mpu_cmd(midi_dev, 0x84, 0); /* Disable metronome */
}
static void
-setup_metronome (int midi_dev)
+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 */
+ int numerator, denominator;
+ int clks_per_click, num_32nds_per_beat;
+ int beats_per_measure;
+
+ numerator = ((u_int) metronome_mode >> 24) & 0xff;
+ denominator = ((u_int) metronome_mode >> 16) & 0xff;
+ clks_per_click = ((u_int) metronome_mode >> 8) & 0xff;
+ num_32nds_per_beat = (u_int) metronome_mode & 0xff;
+ beats_per_measure = (numerator * 4) >> denominator;
+
+ if (!metronome_mode)
+ mpu_cmd(midi_dev, 0x84, 0); /* Disable metronome */
+ else {
+ mpu_cmd(midi_dev, 0xE4, clks_per_click);
+ mpu_cmd(midi_dev, 0xE6, beats_per_measure);
+ mpu_cmd(midi_dev, 0x83, 0); /* Enable metronome without
+ * accents */
}
}
static int
-start_timer (int midi_dev)
+mpu_start_timer(int midi_dev)
{
- tmr_reset ();
- set_timer_mode (midi_dev);
-
- if (tmr_running)
- return TIMER_NOT_ARMED; /* Already running */
-
- 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 */
+ tmr_reset();
+ set_timer_mode(midi_dev);
+
+ if (tmr_running)
+ return TIMER_NOT_ARMED; /* Already running */
+
+ if (timer_mode & TMR_INTERNAL) {
+ mpu_cmd(midi_dev, 0x02, 0); /* Send MIDI start */
+ tmr_running = 1;
+ return TIMER_NOT_ARMED;
+ } else {
+ mpu_cmd(midi_dev, 0x35, 0); /* Enable mode messages to PC */
+ mpu_cmd(midi_dev, 0x38, 0); /* Enable sys common messages to PC */
+ mpu_cmd(midi_dev, 0x39, 0); /* Enable real time messages to PC */
+ mpu_cmd(midi_dev, 0x97, 0); /* Enable system exclusive
+ * messages to PC */
}
- return TIMER_ARMED;
+ return TIMER_ARMED;
}
static int
-mpu_timer_open (int dev, int mode)
+mpu_timer_open(int dev, int mode)
{
- int midi_dev = sound_timer_devs[dev]->devlink;
+ int midi_dev = sound_timer_devs[dev]->devlink;
- if (timer_open)
- return RET_ERROR (EBUSY);
+ if (timer_open)
+ return -(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);
+ tmr_reset();
+ curr_tempo = 50;
+ mpu_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 */
+ mpu_cmd(midi_dev, 0xe7, 0x04); /* Send all clocks to host */
+ mpu_cmd(midi_dev, 0x95, 0); /* Enable clock to host */
- return 0;
+ return 0;
}
static void
-mpu_timer_close (int dev)
+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);
+ int midi_dev = sound_timer_devs[dev]->devlink;
+
+ timer_open = tmr_running = 0;
+ mpu_cmd(midi_dev, 0x15, 0); /* Stop all */
+ mpu_cmd(midi_dev, 0x94, 0); /* Disable clock to host */
+ mpu_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)
+mpu_timer_event(int dev, u_char *event)
{
- unsigned char command = event[1];
- unsigned long parm = *(unsigned int *) &event[4];
- int midi_dev = sound_timer_devs[dev]->devlink;
+ u_char command = event[1];
+ u_long parm = *(u_int *) &event[4];
+ int midi_dev = sound_timer_devs[dev]->devlink;
- switch (command)
- {
+ switch (command) {
case TMR_WAIT_REL:
- parm += prev_event_time;
+ parm += prev_event_time;
case TMR_WAIT_ABS:
- if (parm > 0)
- {
- long time;
+ if (parm > 0) {
+ long time;
- if (parm <= curr_ticks) /* It's the time */
- return TIMER_NOT_ARMED;
+ if (parm <= curr_ticks) /* It's the time */
+ return TIMER_NOT_ARMED;
- time = parm;
- next_event_time = prev_event_time = time;
+ time = parm;
+ next_event_time = prev_event_time = time;
- return TIMER_ARMED;
+ return TIMER_ARMED;
}
- break;
+ break;
case TMR_START:
- if (tmr_running)
+ if (tmr_running)
+ break;
+ return mpu_start_timer(midi_dev);
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;
+ mpu_cmd(midi_dev, 0x01, 0); /* Send MIDI stop */
+ stop_metronome(midi_dev);
+ tmr_running = 0;
+ break;
case TMR_CONTINUE:
- if (tmr_running)
+ if (tmr_running)
+ break;
+ mpu_cmd(midi_dev, 0x03, 0); /* Send MIDI continue */
+ setup_metronome(midi_dev);
+ tmr_running = 1;
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;
+ if (parm) {
+ if (parm < 8)
+ parm = 8;
+ if (parm > 250)
+ parm = 250;
+
+ if (mpu_cmd(midi_dev, 0xE0, parm) < 0)
+ printf("MPU: Can't set tempo to %d\n", (int) parm);
+ curr_tempo = parm;
}
- break;
+ break;
case TMR_ECHO:
- seq_copy_to_input (event, 8);
- break;
+ seq_copy_to_input(event, 8);
+ break;
case TMR_TIMESIG:
- if (metronome_mode) /* Metronome enabled */
- {
- metronome_mode = parm;
- setup_metronome (midi_dev);
+ if (metronome_mode) { /* Metronome enabled */
+ metronome_mode = parm;
+ setup_metronome(midi_dev);
}
- break;
+ break;
default:;
}
- return TIMER_NOT_ARMED;
+ return TIMER_NOT_ARMED;
}
-static unsigned long
-mpu_timer_get_time (int dev)
+static u_long
+mpu_timer_get_time(int dev)
{
- if (!timer_open)
- return 0;
+ if (!timer_open)
+ return 0;
- return curr_ticks;
+ return curr_ticks;
}
static int
-mpu_timer_ioctl (int dev,
- unsigned int command, unsigned int arg)
+mpu_timer_ioctl(int dev, u_int command, ioctl_arg arg)
{
- int midi_dev = sound_timer_devs[dev]->devlink;
+ int midi_dev = sound_timer_devs[dev]->devlink;
- switch (command)
- {
+ switch (command) {
case SNDCTL_TMR_SOURCE:
- {
- int parm = IOCTL_IN (arg) & timer_caps;
-
- if (parm != 0)
- {
- timer_mode = parm;
+ {
+ int parm = (int) (*(int *) arg) & timer_caps;
- 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 (parm != 0) {
+ timer_mode = parm;
- return IOCTL_OUT (arg, timer_mode);
- }
- break;
+ if (timer_mode & TMR_MODE_CLS)
+ mpu_cmd(midi_dev, 0x3c, 0); /* Use CLS sync */
+ else if (timer_mode & TMR_MODE_SMPTE)
+ mpu_cmd(midi_dev, 0x3d, 0); /* Use SMPTE sync */
+ }
+ return *(int *) arg = timer_mode;
+ }
+ break;
case SNDCTL_TMR_START:
- start_timer (midi_dev);
- return 0;
- break;
+ mpu_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;
+ tmr_running = 0;
+ mpu_cmd(midi_dev, 0x01, 0); /* Send MIDI stop */
+ stop_metronome(midi_dev);
+ return 0;
+ break;
case SNDCTL_TMR_CONTINUE:
- if (tmr_running)
+ if (tmr_running)
+ return 0;
+ tmr_running = 1;
+ mpu_cmd(midi_dev, 0x03, 0); /* Send MIDI continue */
return 0;
- tmr_running = 1;
- exec_cmd (midi_dev, 0x03, 0); /* Send MIDI continue */
- return 0;
- break;
+ break;
case SNDCTL_TMR_TIMEBASE:
- {
- int val = IOCTL_IN (arg);
+ {
+ int val = (int) (*(int *) arg);
- if (val)
- set_timebase (midi_dev, val);
+ if (val)
+ set_timebase(midi_dev, val);
- return IOCTL_OUT (arg, curr_timebase);
- }
- break;
+ return *(int *) 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;
+ {
+ int val = (int) (*(int *) arg);
+ int ret;
+
+ if (val) {
+ RANGE (val, 8 , 250 );
+ if ((ret = mpu_cmd(midi_dev, 0xE0, val)) < 0) {
+ printf("MPU: Can't set tempo to %d\n", (int) val);
+ return ret;
+ }
+ curr_tempo = val;
+ }
+ return *(int *) arg = curr_tempo;
+ }
+ break;
case SNDCTL_SEQ_CTRLRATE:
- if (IOCTL_IN (arg) != 0) /* Can't change */
- return RET_ERROR (EINVAL);
+ if ((*(int *) arg) != 0) /* Can't change */
+ return -(EINVAL);
- return IOCTL_OUT (arg, ((curr_tempo * curr_timebase) + 30) / 60);
- break;
+ return *(int *) arg = ((curr_tempo * curr_timebase) + 30) / 60;
+ break;
case SNDCTL_TMR_METRONOME:
- metronome_mode = IOCTL_IN (arg);
- setup_metronome (midi_dev);
- return 0;
- break;
+ metronome_mode = (int) (*(int *) arg);
+ setup_metronome(midi_dev);
+ return 0;
+ break;
- default:
+ default:;
}
- return RET_ERROR (EINVAL);
+ return -(EINVAL);
}
static void
-mpu_timer_arm (int dev, long time)
+mpu_timer_arm(int dev, long time)
{
- if (time < 0)
- time = curr_ticks + 1;
- else if (time <= curr_ticks) /* It's the time */
- return;
+ if (time < 0)
+ time = curr_ticks + 1;
+ else if (time <= curr_ticks) /* It's the time */
+ return;
- next_event_time = prev_event_time = time;
+ next_event_time = prev_event_time = time;
- return;
+ 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
+ {"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)
+mpu_timer_interrupt(void)
{
- if (!timer_open)
- return;
+ if (!timer_open)
+ return;
- if (!tmr_running)
- return;
+ if (!tmr_running)
+ return;
- curr_clocks++;
- curr_ticks = clocks2ticks (curr_clocks);
+ curr_clocks++;
+ curr_ticks = clocks2ticks(curr_clocks);
- if (curr_ticks >= next_event_time)
- {
- next_event_time = 0xffffffff;
- sequencer_timer (NULL);
+ if (curr_ticks >= next_event_time) {
+ next_event_time = 0xffffffff;
+ sequencer_timer(0);
}
}
static void
-timer_ext_event (struct mpu_config *devc, int event, int parm)
+timer_ext_event(struct mpu_config * devc, int event, int parm)
{
- int midi_dev = devc->devno;
+ int midi_dev = devc->devno;
- if (!devc->timer_flag)
- return;
+ if (!devc->timer_flag)
+ return;
- switch (event)
- {
+ switch (event) {
case TMR_CLOCK:
- printk ("<MIDI clk>");
- break;
+ printf("<MIDI clk>");
+ 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;
+ printf("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 ());
+ printf("Ext MIDI stop\n");
+ if (timer_mode & TMR_EXTERNAL) {
+ tmr_running = 0;
+ stop_metronome(midi_dev);
+ STORE(SEQ_STOP_TIMER());
}
- break;
+ 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 ());
+ printf("Ext MIDI continue\n");
+ if (timer_mode & TMR_EXTERNAL) {
+ tmr_running = 1;
+ setup_metronome(midi_dev);
+ STORE(SEQ_CONTINUE_TIMER());
}
- break;
+ break;
case TMR_SPP:
- printk ("Songpos: %d\n", parm);
- if (timer_mode & TMR_EXTERNAL)
- {
- STORE (SEQ_SONGPOS (parm));
+ printf("Songpos: %d\n", parm);
+ if (timer_mode & TMR_EXTERNAL) {
+ STORE(SEQ_SONGPOS(parm));
}
- break;
+ break;
}
}
static void
-mpu_timer_init (int midi_dev)
+mpu_timer_init(int midi_dev)
{
- struct mpu_config *devc;
- int n;
+ struct mpu_config *devc;
+ int n;
- devc = &dev_conf[midi_dev];
+ devc = &dev_conf[midi_dev];
- if (timer_initialized)
- return; /* There is already a similar timer */
+ if (timer_initialized)
+ return; /* There is already a similar timer */
- timer_initialized = 1;
+ timer_initialized = 1;
- mpu_timer.devlink = midi_dev;
- dev_conf[midi_dev].timer_flag = 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 (num_sound_timers >= MAX_TIMER_DEV)
+ n = 0; /* Overwrite the system timer */
+ else
+ n = num_sound_timers++;
+ sound_timer_devs[n] = &mpu_timer;
- if (devc->revision & 0x40)
- max_timebase = 10; /* Has the 216 and 240 ppqn modes */
- }
+ 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.
+ */
- timer_mode = (TMR_INTERNAL | TMR_MODE_MIDI) & timer_caps;
+ if (devc->revision)
+ timer_caps |= TMR_EXTERNAL | TMR_MODE_MIDI;
-}
+ if (devc->revision & 0x02)
+ timer_caps |= TMR_MODE_CLS;
-#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
diff --git a/sys/i386/isa/sound/opl3.c b/sys/i386/isa/sound/opl3.c
index 30d13a7..fbc4398 100644
--- a/sys/i386/isa/sound/opl3.c
+++ b/sys/i386/isa/sound/opl3.c
@@ -1,10 +1,10 @@
/*
* sound/opl3.c
- *
+ *
* A low level driver for Yamaha YM3812 and OPL-3 -chips
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,7 +24,7 @@
* 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.
- *
+ *
*/
/*
@@ -33,307 +33,280 @@
/*
* hooft@chem.ruu.nl
*/
-
#include <i386/isa/sound/sound_config.h>
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_YM3812)
+
+#if defined(CONFIG_YM3812)
#include <i386/isa/sound/opl3.h>
+#include <machine/clock.h>
#define MAX_VOICE 18
-#define OFFS_4OP 11 /*
- * * * Definitions for the operators OP3 and
- * * OP4 * * begin here */
-
-static int opl3_enabled = 0;
-static int opl4_enabled = 0;
-#ifdef PC98
-static int left_address = 0x28d2, right_address = 0x28d2, both_address = 0;
-#else
-static int left_address = 0x388, right_address = 0x388, both_address = 0;
-#endif
+#define OFFS_4OP 11
+
+struct voice_info {
+ u_char keyon_byte;
+ long bender;
+ long bender_range;
+ u_long orig_freq;
+ u_long current_freq;
+ int volume;
+ int mode;
+};
-static int nr_voices = 9;
-static int logical_voices[MAX_VOICE] =
-{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
+typedef struct opl_devinfo {
+ int left_io, right_io;
+ int nr_voice;
+ int lv_map[MAX_VOICE];
-struct voice_info
- {
- unsigned char keyon_byte;
- long bender;
- long bender_range;
- unsigned long orig_freq;
- unsigned long current_freq;
- int mode;
- };
+ struct voice_info voc[MAX_VOICE];
+ struct voice_alloc_info *v_alloc;
+ struct channel_info *chn_info;
-static struct voice_info voices[MAX_VOICE];
-static struct voice_alloc_info *voice_alloc;
-static struct channel_info *chn_info;
+ struct sbi_instrument i_map[SBFM_MAXINSTR];
+ struct sbi_instrument *act_i[MAX_VOICE];
-static struct sbi_instrument *instrmap;
-static struct sbi_instrument *active_instrument[MAX_VOICE] =
-{NULL};
+ struct synth_info fm_info;
-static struct synth_info fm_info =
-{"OPL-2", 0, SYNTH_TYPE_FM, FM_TYPE_ADLIB, 0, 9, 0, SBFM_MAXINSTR, 0};
+ int busy;
+ int model;
+ u_char cmask;
-static int already_initialized = 0;
+ int is_opl4;
+ sound_os_info *osp;
+}
+ opl_devinfo;
-static int opl3_ok = 0;
-static int opl3_busy = 0;
-static int fm_model = 0; /*
+static struct opl_devinfo *devc = NULL;
- * * * * 0=no fm, 1=mono, 2=SB Pro 1, 3=SB
- * Pro 2 * * */
+static int detected_model;
-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 note, int velocity);
-static unsigned char connection_mask = 0x00;
+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, u_int addr, u_int val);
+static int opl3_kill_note(int dev, int voice, int note, int velocity);
void
-enable_opl3_mode (int left, int right, int both)
+enable_opl3_mode(int left, int right, int both)
{
- if (opl3_enabled)
- return;
-
- opl3_enabled = 1;
- left_address = left;
- right_address = right;
- both_address = both;
- fm_info.capabilities = SYNTH_CAP_OPL3;
- fm_info.synth_subtype = FM_TYPE_OPL3;
+ /* NOP */
}
static void
-enter_4op_mode (void)
+enter_4op_mode(void)
{
- int i;
- static int voices_4op[MAX_VOICE] =
- {0, 1, 2, 9, 10, 11, 6, 7, 8, 15, 16, 17};
-
- 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++)
- physical_voices[i].voice_mode = 0;
-
- for (i = 9; i < 12; i++)
- physical_voices[i].voice_mode = 4;
- for (i = 12; i < 15; i++)
- physical_voices[i].voice_mode = 0;
-
- for (i = 0; i < 12; i++)
- logical_voices[i] = voices_4op[i];
- voice_alloc->max_voice = nr_voices = 12;
+ int i;
+ static int v4op[MAX_VOICE] =
+ {0, 1, 2, 9, 10, 11, 6, 7, 8, 15, 16, 17};
+
+ devc->cmask = 0x3f; /* Connect all possible 4 OP voice operators */
+ opl3_command(devc->right_io, CONNECTION_SELECT_REGISTER, 0x3f);
+
+ for (i = 0; i < 3; i++)
+ pv_map[i].voice_mode = 4;
+ for (i = 3; i < 6; i++)
+ pv_map[i].voice_mode = 0;
+
+ for (i = 9; i < 12; i++)
+ pv_map[i].voice_mode = 4;
+ for (i = 12; i < 15; i++)
+ pv_map[i].voice_mode = 0;
+
+ for (i = 0; i < 12; i++)
+ devc->lv_map[i] = v4op[i];
+ devc->v_alloc->max_voice = devc->nr_voice = 12;
}
static int
-opl3_ioctl (int dev,
- unsigned int cmd, unsigned int arg)
+opl3_ioctl(int dev,
+ u_int cmd, ioctl_arg arg)
{
- switch (cmd)
- {
+ switch (cmd) {
case SNDCTL_FM_LOAD_INSTR:
- {
- struct sbi_instrument ins;
-
- IOCTL_FROM_USER ((char *) &ins, (char *) arg, 0, sizeof (ins));
+ {
+ struct sbi_instrument ins;
- if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR)
- {
- printk ("FM Error: Invalid instrument number %d\n", ins.channel);
- return RET_ERROR (EINVAL);
- }
+ bcopy(&(((char *) arg)[0]), (char *) &ins, sizeof(ins));
- pmgr_inform (dev, PM_E_PATCH_LOADED, ins.channel, 0, 0, 0);
- return store_instr (ins.channel, &ins);
- }
- break;
+ if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) {
+ printf("FM Error: Invalid instrument number %d\n", ins.channel);
+ return -(EINVAL);
+ }
+ pmgr_inform(dev, PM_E_PATCH_LOADED, ins.channel, 0, 0, 0);
+ return store_instr(ins.channel, &ins);
+ }
+ break;
case SNDCTL_SYNTH_INFO:
- fm_info.nr_voices = (nr_voices == 12) ? 6 : nr_voices;
-
- IOCTL_TO_USER ((char *) arg, 0, &fm_info, sizeof (fm_info));
- return 0;
- break;
+ devc->fm_info.nr_voices = (devc->nr_voice == 12) ? 6 : devc->nr_voice;
+ bcopy(&devc->fm_info, &(((char *) arg)[0]), sizeof(devc->fm_info));
+ return 0;
+ break;
case SNDCTL_SYNTH_MEMAVL:
- return 0x7fffffff;
- break;
+ return 0x7fffffff;
+ break;
case SNDCTL_FM_4OP_ENABLE:
- if (opl3_enabled)
- enter_4op_mode ();
- return 0;
- break;
+ if (devc->model == 2)
+ enter_4op_mode();
+ return 0;
+ break;
default:
- return RET_ERROR (EINVAL);
+ return -(EINVAL);
}
}
int
-opl3_detect (int ioaddr)
+opl3_detect(int ioaddr, sound_os_info * osp)
{
- /*
- * This function returns 1 if the FM chicp is present at the given I/O port
- * The detection algorithm plays with the timer built in the FM chip and
- * looks for a change in the status register.
- *
- * Note! The timers of the FM chip are not connected to AdLib (and compatible)
- * boards.
- *
- * Note2! The chip is initialized if detected.
- */
-
- unsigned char stat1, stat2, signature;
- int i;
-
- if (already_initialized)
- {
- return 0; /*
- * Do avoid duplicate initializations
- */
+ /*
+ * This function returns 1 if the FM chip is present at the given
+ * I/O port The detection algorithm plays with the timer built in the
+ * FM chip and looks for a change in the status register.
+ *
+ * Note! The timers of the FM chip are not connected to AdLib (and
+ * compatible) boards.
+ *
+ * Note2! The chip is initialized if detected.
+ */
+
+ u_char stat1, stat2, signature;
+ int i;
+
+ if (devc != NULL)
+ return 0;
+
+ devc = (struct opl_devinfo *) malloc(sizeof(*devc), M_DEVBUF, M_NOWAIT);
+ if (!devc)
+ panic("SOUND: Cannot allocate memory\n");
+
+ if (devc == NULL) {
+ printf("OPL3: Can't allocate memory for device control structure\n");
+ return 0;
}
+ devc->osp = osp;
- if (opl3_enabled)
- ioaddr = left_address;
+ /* Reset timers 1 and 2 */
+ opl3_command(ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK);
- /* Reset timers 1 and 2 */
- opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK);
+ /* Reset the IRQ of the FM chip */
+ opl3_command(ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET);
- /* Reset the IRQ of the FM chip */
- opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET);
+ signature = stat1 = inb(ioaddr); /* Status register */
- signature = stat1 = INB (ioaddr); /* Status register */
-
- if ((stat1 & 0xE0) != 0x00)
- {
- return 0; /*
- * Should be 0x00
- */
+ if ((stat1 & 0xE0) != 0x00) {
+ return 0; /* Should be 0x00 */
}
+ opl3_command(ioaddr, TIMER1_REGISTER, 0xff); /* Set timer1 to 0xff */
- opl3_command (ioaddr, TIMER1_REGISTER, 0xff); /* Set timer1 to 0xff */
-
- opl3_command (ioaddr, TIMER_CONTROL_REGISTER,
- TIMER2_MASK | TIMER1_START); /*
- * Unmask and start timer 1
- */
+ opl3_command(ioaddr, TIMER_CONTROL_REGISTER,
+ TIMER2_MASK | TIMER1_START); /* Unmask and start timer 1 */
- /*
- * Now we have to delay at least 80 usec
- */
- for (i = 0; i < 50; i++)
- tenmicrosec ();
+ DELAY(150); /* Now we have to delay at least 80 usec */
- stat2 = INB (ioaddr); /*
- * Read status after timers have expired
- */
+ stat2 = inb(ioaddr); /* Read status after timers have expired */
- /*
- * Stop the timers
- */
+ /*
+ * Stop the timers
+ */
- /* Reset timers 1 and 2 */
- opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK);
- /* Reset the IRQ of the FM chip */
- opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET);
+ /* Reset timers 1 and 2 */
+ opl3_command(ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK);
+ /* Reset the IRQ of the FM chip */
+ opl3_command(ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET);
- if ((stat2 & 0xE0) != 0xc0)
- {
- return 0; /*
- * There is no YM3812
- */
+ if ((stat2 & 0xE0) != 0xc0) {
+ return 0; /* There is no YM3812 */
}
+ /*
+ * There is a FM chicp in this address. Detect the type (OPL2 to
+ * OPL4)
+ */
- /*
- * There is a FM chicp in this address. Detect the type (OPL2 to OPL4)
- */
+ if (signature == 0x06) {/* OPL2 */
+ detected_model = 2;
+ } else if (signature == 0x00) { /* OPL3 or OPL4 */
+ u_char tmp;
- if (signature == 0x06) /* OPL2 */
- {
- opl3_enabled = 0;
- }
- else if (signature == 0x00) /* OPL3 or OPL4 */
- {
- unsigned char tmp;
-
- if (!opl3_enabled) /* Was not already enabled */
- {
- left_address = ioaddr;
- right_address = ioaddr + 2;
- opl3_enabled = 1;
- }
+ detected_model = 3;
- /*
- * Detect availability of OPL4 (_experimental_). Works propably
- * only after a cold boot. In addition the OPL4 port
- * of the chip may not be connected to the PC bus at all.
- */
+ /*
+ * Detect availability of OPL4 (_experimental_). Works
+ * propably only after a cold boot. In addition the OPL4 port
+ * of the chip may not be connected to the PC bus at all.
+ */
- opl3_command (right_address, OPL3_MODE_REGISTER, 0x00);
- opl3_command (right_address, OPL3_MODE_REGISTER, OPL3_ENABLE | OPL4_ENABLE);
+ opl3_command(ioaddr + 2, OPL3_MODE_REGISTER, 0x00);
+ opl3_command(ioaddr + 2, OPL3_MODE_REGISTER, OPL3_ENABLE | OPL4_ENABLE);
- if ((tmp = INB (ioaddr)) == 0x02) /* Have a OPL4 */
- {
- opl4_enabled = 1;
+ if ((tmp = inb(ioaddr)) == 0x02) { /* Have a OPL4 */
+ detected_model = 4;
+ }
+ if (!0) { /* OPL4 port is free */ /* XXX check here lr970711 */
+ int tmp;
+
+ outb(ioaddr - 8, 0x02); /* Select OPL4 ID register */
+ DELAY(10);
+ tmp = inb(ioaddr - 7); /* Read it */
+ DELAY(10);
+
+ if (tmp == 0x20) { /* OPL4 should return 0x20 here */
+ detected_model = 4;
+
+ outb(ioaddr - 8, 0xF8); /* Select OPL4 FM mixer control */
+ DELAY(10);
+ outb(ioaddr - 7, 0x1B); /* Write value */
+ DELAY(10);
+ } else
+ detected_model = 3;
}
- opl3_command (right_address, OPL3_MODE_REGISTER, 0);
+ opl3_command(ioaddr + 2, OPL3_MODE_REGISTER, 0);
}
+ for (i = 0; i < 9; i++)
+ opl3_command(ioaddr, KEYON_BLOCK + i, 0); /* Note off */
- for (i = 0; i < 9; i++)
- 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, TEST_REGISTER, ENABLE_WAVE_SELECT);
- opl3_command (ioaddr, PERCUSSION_REGISTER, 0x00); /*
- * Melodic mode.
- */
-
- return 1;
+ return 1;
}
static int
-opl3_kill_note (int dev, int voice, int note, int velocity)
+opl3_kill_note(int dev, int voice, int note, int velocity)
{
- struct physical_voice_info *map;
+ struct physical_voice_info *map;
- if (voice < 0 || voice >= nr_voices)
- return 0;
+ if (voice < 0 || voice >= devc->nr_voice)
+ return 0;
- voice_alloc->map[voice] = 0;
+ devc->v_alloc->map[voice] = 0;
- map = &physical_voices[logical_voices[voice]];
+ map = &pv_map[devc->lv_map[voice]];
- DEB (printk ("Kill note %d\n", voice));
+ DEB(printf("Kill note %d\n", voice));
- if (map->voice_mode == 0)
- return 0;
+ if (map->voice_mode == 0)
+ return 0;
- opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, voices[voice].keyon_byte & ~0x20);
+ opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num,
+ devc->voc[voice].keyon_byte & ~0x20);
- voices[voice].keyon_byte = 0;
- voices[voice].bender = 0;
- voices[voice].bender_range = 200; /*
- * 200 cents = 2 semitones
- */
- voices[voice].orig_freq = 0;
- voices[voice].current_freq = 0;
- voices[voice].mode = 0;
+ devc->voc[voice].keyon_byte = 0;
+ devc->voc[voice].bender = 0;
+ devc->voc[voice].volume = 64;
+ devc->voc[voice].bender_range = 200; /* 200 cents = 2 semitones */
+ devc->voc[voice].orig_freq = 0;
+ devc->voc[voice].current_freq = 0;
+ devc->voc[voice].mode = 0;
- return 0;
+ return 0;
}
#define HIHAT 0
@@ -345,27 +318,28 @@ opl3_kill_note (int dev, int voice, int note, int velocity)
#define DEFAULT TOMTOM
static int
-store_instr (int instr_no, struct sbi_instrument *instr)
+store_instr(int instr_no, struct sbi_instrument * instr)
{
- if (instr->key != FM_PATCH && (instr->key != OPL3_PATCH || !opl3_enabled))
- printk ("FM warning: Invalid patch format field (key) 0x%x\n", instr->key);
- memcpy ((char *) &(instrmap[instr_no]), (char *) instr, sizeof (*instr));
+ if (instr->key !=FM_PATCH && (instr->key !=OPL3_PATCH || devc->model != 2))
+ printf("FM warning: Invalid patch format field (key) 0x%x\n",
+ instr->key);
+ bcopy((char *) instr, (char *) &(devc->i_map[instr_no]), sizeof(*instr));
- return 0;
+ return 0;
}
static int
-opl3_set_instr (int dev, int voice, int instr_no)
+opl3_set_instr(int dev, int voice, int instr_no)
{
- if (voice < 0 || voice >= nr_voices)
- return 0;
+ if (voice < 0 || voice >= devc->nr_voice)
+ return 0;
- if (instr_no < 0 || instr_no >= SBFM_MAXINSTR)
- return 0;
+ if (instr_no < 0 || instr_no >= SBFM_MAXINSTR)
+ return 0;
- active_instrument[voice] = &instrmap[instr_no];
- return 0;
+ devc->act_i[voice] = &devc->i_map[instr_no];
+ return 0;
}
/*
@@ -377,580 +351,465 @@ opl3_set_instr (int dev, int voice, int instr_no)
* volume -8 it was implemented as a table because it is only 128 bytes and
* it saves a lot of log() calculations. (RH)
*/
-static 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 */
+char fm_volume_table[128] =
+{
+ -64, -48, -40, -35, -32, -29, -27, -26,
+ -24, -23, -21, -20, -19, -18, -18, -17,
+ -16, -15, -15, -14, -13, -13, -12, -12,
+ -11, -11, -10, -10, -10, -9, -9, -8,
+ -8, -8, -7, -7, -7, -6, -6, -6,
+ -5, -5, -5, -5, -4, -4, -4, -4,
+ -3, -3, -3, -3, -2, -2, -2, -2,
+ -2, -1, -1, -1, -1, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 4,
+ 4, 4, 4, 4, 4, 4, 4, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 8, 8, 8, 8, 8};
static void
-calc_vol (unsigned char *regbyte, int volume)
+calc_vol(u_char *regbyte, int volume, int main_vol)
{
- int level = (~*regbyte & 0x3f);
+ int level = (~*regbyte & 0x3f);
+
+ if (main_vol > 127)
+ main_vol = 127;
+
+ volume = (volume * main_vol) / 127;
- if (level)
- level += fm_volume_table[volume];
+ if (level)
+ level += fm_volume_table[volume];
- if (level > 0x3f)
- level = 0x3f;
- if (level < 0)
- level = 0;
+ RANGE (level, 0, 0x3f );
- *regbyte = (*regbyte & 0xc0) | (~level & 0x3f);
+ *regbyte = (*regbyte & 0xc0) | (~level & 0x3f);
}
static void
-set_voice_volume (int voice, int volume)
+set_voice_volume(int voice, int volume, int main_vol)
{
- unsigned char vol1, vol2, vol3, vol4;
- struct sbi_instrument *instr;
- struct physical_voice_info *map;
+ u_char vol1, vol2, vol3, vol4;
+ struct sbi_instrument *instr;
+ struct physical_voice_info *map;
- if (voice < 0 || voice >= nr_voices)
- return;
+ if (voice < 0 || voice >= devc->nr_voice)
+ return;
- map = &physical_voices[logical_voices[voice]];
+ map = &pv_map[devc->lv_map[voice]];
- instr = active_instrument[voice];
+ instr = devc->act_i[voice];
- if (!instr)
- instr = &instrmap[0];
+ if (!instr)
+ instr = &devc->i_map[0];
- if (instr->channel < 0)
- return;
+ if (instr->channel < 0)
+ return;
- if (voices[voice].mode == 0)
- return;
+ if (devc->voc[voice].mode == 0)
+ return;
- if (voices[voice].mode == 2)
- { /*
- * 2 OP voice
- */
+ if (devc->voc[voice].mode == 2) {
- vol1 = instr->operators[2];
- vol2 = instr->operators[3];
+ vol1 = instr->operators[2];
+ vol2 = instr->operators[3];
- if ((instr->operators[10] & 0x01))
- { /*
- * Additive synthesis
- */
- calc_vol (&vol1, volume);
- calc_vol (&vol2, volume);
- }
- else
- { /*
- * FM synthesis
- */
- calc_vol (&vol2, volume);
+ if ((instr->operators[10] & 0x01)) {
+ calc_vol(&vol1, volume, main_vol);
}
+ calc_vol(&vol2, volume, main_vol);
- 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
- */
- int connection;
+ opl3_command(map->ioaddr, KSL_LEVEL + map->op[0], vol1);
+ opl3_command(map->ioaddr, KSL_LEVEL + map->op[1], vol2);
+ } else { /* 4 OP voice */
+ int connection;
- vol1 = instr->operators[2];
- vol2 = instr->operators[3];
- vol3 = instr->operators[OFFS_4OP + 2];
- vol4 = instr->operators[OFFS_4OP + 3];
+ vol1 = instr->operators[2];
+ vol2 = instr->operators[3];
+ vol3 = instr->operators[OFFS_4OP + 2];
+ vol4 = instr->operators[OFFS_4OP + 3];
- /*
- * The connection method for 4 OP voices is defined by the rightmost
- * bits at the offsets 10 and 10+OFFS_4OP
- */
+ /*
+ * The connection method for 4 OP devc->voc is defined by the
+ * rightmost bits at the offsets 10 and 10+OFFS_4OP
+ */
- connection = ((instr->operators[10] & 0x01) << 1) | (instr->operators[10 + OFFS_4OP] & 0x01);
+ connection = ((instr->operators[10] & 0x01) << 1) | (instr->operators[10 + OFFS_4OP] & 0x01);
- switch (connection)
- {
+ switch (connection) {
case 0:
- calc_vol (&vol4, volume); /*
- * Just the OP 4 is carrier
- */
- break;
+ calc_vol(&vol4, volume, main_vol);
+ break;
case 1:
- calc_vol (&vol2, volume);
- calc_vol (&vol4, volume);
- break;
+ calc_vol(&vol2, volume, main_vol);
+ calc_vol(&vol4, volume, main_vol);
+ break;
case 2:
- calc_vol (&vol1, volume);
- calc_vol (&vol4, volume);
- break;
+ calc_vol(&vol1, volume, main_vol);
+ calc_vol(&vol4, volume, main_vol);
+ break;
case 3:
- calc_vol (&vol1, volume);
- calc_vol (&vol3, volume);
- calc_vol (&vol4, volume);
- break;
-
- default: /*
- * Why ??
- */ ;
+ calc_vol(&vol1, volume, main_vol);
+ calc_vol(&vol3, volume, main_vol);
+ calc_vol(&vol4, volume, main_vol);
+ break;
+
+ default:;
}
- opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1);
- opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], vol2);
- opl3_command (map->ioaddr, KSL_LEVEL + map->op[2], vol3);
- opl3_command (map->ioaddr, KSL_LEVEL + map->op[3], vol4);
+ opl3_command(map->ioaddr, KSL_LEVEL + map->op[0], vol1);
+ opl3_command(map->ioaddr, KSL_LEVEL + map->op[1], vol2);
+ opl3_command(map->ioaddr, KSL_LEVEL + map->op[2], vol3);
+ opl3_command(map->ioaddr, KSL_LEVEL + map->op[3], vol4);
}
}
static int
-opl3_start_note (int dev, int voice, int note, int volume)
+opl3_start_note(int dev, int voice, int note, int volume)
{
- unsigned char data, fpc;
- int block, fnum, freq, voice_mode;
- struct sbi_instrument *instr;
- struct physical_voice_info *map;
+ u_char data, fpc;
+ int block, fnum, freq, voice_mode;
+ struct sbi_instrument *instr;
+ struct physical_voice_info *map;
- if (voice < 0 || voice >= nr_voices)
- return 0;
+ if (voice < 0 || voice >= devc->nr_voice)
+ return 0;
- map = &physical_voices[logical_voices[voice]];
+ map = &pv_map[devc->lv_map[voice]];
- if (map->voice_mode == 0)
- return 0;
+ if (map->voice_mode == 0)
+ return 0;
- if (note == 255) /*
- * Just change the volume
- */
- {
- set_voice_volume (voice, volume);
- return 0;
+ if (note == 255) { /* Just change the volume */
+ set_voice_volume(voice, volume, devc->voc[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
- */
-
- if (map->voice_mode == 4)
- {
- opl3_command (map->ioaddr, KSL_LEVEL + map->op[2], 0xff);
- opl3_command (map->ioaddr, KSL_LEVEL + map->op[3], 0xff);
+ /*
+ * 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) {
+ opl3_command(map->ioaddr, KSL_LEVEL + map->op[2], 0xff);
+ 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];
+ instr = devc->act_i[voice];
- if (!instr)
- instr = &instrmap[0];
+ if (!instr)
+ instr = &devc->i_map[0];
- if (instr->channel < 0)
- {
- printk (
- "OPL3: Initializing voice %d with undefined instrument\n",
+ if (instr->channel < 0) {
+ printf( "OPL3: Initializing voice %d with undefined instrument\n",
voice);
- return 0;
+ return 0;
}
+ if (map->voice_mode == 2 && instr->key == OPL3_PATCH)
+ return 0; /* Cannot play */
- if (map->voice_mode == 2 && instr->key == OPL3_PATCH)
- return 0; /*
- * Cannot play
- */
+ voice_mode = map->voice_mode;
- voice_mode = map->voice_mode;
+ if (voice_mode == 4) {
+ int voice_shift;
- if (voice_mode == 4)
- {
- int voice_shift;
+ voice_shift = (map->ioaddr == devc->left_io) ? 0 : 3;
+ voice_shift += map->voice_num;
- voice_shift = (map->ioaddr == left_address) ? 0 : 3;
- voice_shift += map->voice_num;
+ if (instr->key != OPL3_PATCH) { /* Just 2 OP patch */
+ voice_mode = 2;
+ devc->cmask &= ~(1 << voice_shift);
+ } else
+ devc->cmask |= (1 << voice_shift);
- if (instr->key != OPL3_PATCH) /*
- * Just 2 OP patch
- */
- {
- voice_mode = 2;
- connection_mask &= ~(1 << voice_shift);
- }
- else
- {
- connection_mask |= (1 << voice_shift);
- }
-
- opl3_command (right_address, CONNECTION_SELECT_REGISTER, connection_mask);
+ opl3_command(devc->right_io, CONNECTION_SELECT_REGISTER, devc->cmask);
}
-
- /*
- * 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
- */
- 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
- */
- 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
- */
- 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
- */
- fpc = instr->operators[10];
- if (!(fpc & 0x30))
- fpc |= 0x30; /*
- * Ensure that at least one chn is enabled
- */
- opl3_command (map->ioaddr, FEEDBACK_CONNECTION + map->voice_num,
- fpc);
-
- /*
- * If the voice is a 4 OP one, initialize the operators 3 and 4 also
- */
-
- if (voice_mode == 4)
- {
-
- /*
- * 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
- */
- 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
- */
- 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
- */
- 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
- */
- fpc = instr->operators[OFFS_4OP + 10];
- if (!(fpc & 0x30))
- fpc |= 0x30; /*
- * Ensure that at least one chn is enabled
- */
- opl3_command (map->ioaddr, FEEDBACK_CONNECTION + map->voice_num + 3, fpc);
+ /*
+ * 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
+ */
+ 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
+ */
+ 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
+ */
+ 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
+ */
+ fpc = instr->operators[10];
+ if (!(fpc & 0x30))
+ fpc |= 0x30; /* Ensure that at least one chn is enabled */
+ opl3_command(map->ioaddr, FEEDBACK_CONNECTION + map->voice_num, fpc);
+
+ /*
+ * If the voice is a 4 OP one, initialize the operators 3 and 4 also
+ */
+
+ if (voice_mode == 4) {
+
+ /*
+ * 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
+ */
+ 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
+ */
+ 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
+ */
+ 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
+ */
+ fpc = instr->operators[OFFS_4OP + 10];
+ if (!(fpc & 0x30))
+ fpc |= 0x30; /* Ensure that at least one chn is enabled */
+ opl3_command(map->ioaddr,FEEDBACK_CONNECTION + map->voice_num + 3, fpc);
}
+ devc->voc[voice].mode = voice_mode;
- voices[voice].mode = voice_mode;
+ set_voice_volume(voice, volume, devc->voc[voice].volume);
- set_voice_volume (voice, volume);
+ freq = devc->voc[voice].orig_freq = note_to_freq(note) / 1000;
- freq = voices[voice].orig_freq = note_to_freq (note) / 1000;
+ /*
+ * Since the pitch bender may have been set before playing the note,
+ * we have to calculate the bending now.
+ */
- /*
- * Since the pitch bender may have been set before playing the note, we
- * have to calculate the bending now.
- */
+ freq = compute_finetune(devc->voc[voice].orig_freq,
+ devc->voc[voice].bender, devc->voc[voice].bender_range);
+ devc->voc[voice].current_freq = freq;
- 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);
- freq_to_fnum (freq, &block, &fnum);
+ /*
+ * Play note
+ */
- /*
- * Play note
- */
+ data = fnum & 0xff; /* Least significant bits of fnumber */
+ opl3_command(map->ioaddr, FNUM_LOW + map->voice_num, data);
- 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);
+ devc->voc[voice].keyon_byte = data;
+ opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num, data);
+ if (voice_mode == 4)
+ opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num + 3, data);
- data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3);
- voices[voice].keyon_byte = data;
- opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, data);
- if (voice_mode == 4)
- opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num + 3, data);
-
- return 0;
+ return 0;
}
static void
-freq_to_fnum (int freq, int *block, int *fnum)
+freq_to_fnum(int freq, int *block, int *fnum)
{
- 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
- */
-
- f = freq;
-
- octave = 5;
-
- if (f == 0)
- octave = 0;
- else if (f < 261)
- {
- while (f < 261)
- {
- octave--;
- f <<= 1;
+ 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
+ */
+
+ f = freq;
+
+ octave = 5;
+
+ if (f == 0)
+ octave = 0;
+ else if (f < 261) {
+ while (f < 261) {
+ octave--;
+ f <<= 1;
}
- }
- else if (f > 493)
- {
- while (f > 493)
- {
- octave++;
- f >>= 1;
+ } else if (f > 493) {
+ while (f > 493) {
+ octave++;
+ f >>= 1;
}
}
+ if (octave > 7)
+ octave = 7;
- if (octave > 7)
- octave = 7;
-
- *fnum = freq * (1 << (20 - octave)) / 49716;
- *block = octave;
+ *fnum = freq * (1 << (20 - octave)) / 49716;
+ *block = octave;
}
static void
-opl3_command (int io_addr, unsigned int addr, unsigned int val)
+opl3_command(int io_addr, u_int addr, u_int val)
{
- int i;
-
- /*
- * The original 2-OP synth requires a quite long delay after writing to a
- * register. The OPL-3 survives with just two INBs
- */
-
- OUTB ((unsigned char) (addr & 0xff), io_addr); /*
- * Select register
- *
- */
-
- if (!opl3_enabled)
- tenmicrosec ();
- else
- for (i = 0; i < 2; i++)
- INB (io_addr);
-
-#ifdef PC98
- OUTB ((unsigned char) (val & 0xff), io_addr + 0x100);
-#else
- OUTB ((unsigned char) (val & 0xff), io_addr + 1); /*
- * Write to register
- *
- */
-#endif
+ int i;
- if (!opl3_enabled)
- {
- tenmicrosec ();
- tenmicrosec ();
- tenmicrosec ();
- }
- else
- for (i = 0; i < 2; i++)
- INB (io_addr);
+ /*
+ * The original 2-OP synth requires a quite long delay after writing
+ * to a register. The OPL-3 survives with just two INBs
+ */
+
+ outb(io_addr, (u_char) (addr & 0xff));
+
+ if (!devc->model != 2)
+ DELAY(10);
+ else
+ for (i = 0; i < 2; i++)
+ inb(io_addr);
+
+ outb(io_addr + 1, (u_char) (val & 0xff));
+
+ if (devc->model != 2)
+ DELAY(30);
+ else
+ for (i = 0; i < 2; i++)
+ inb(io_addr);
}
static void
-opl3_reset (int dev)
+opl3_reset(int dev)
{
- int i;
+ int i;
- 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);
+ for (i = 0; i < 18; i++)
+ devc->lv_map[i] = i;
- opl3_command (physical_voices[logical_voices[i]].ioaddr,
- KSL_LEVEL + physical_voices[logical_voices[i]].op[1], 0xff);
+ for (i = 0; i < devc->nr_voice; i++) {
+ opl3_command(pv_map[devc->lv_map[i]].ioaddr,
+ KSL_LEVEL + pv_map[devc->lv_map[i]].op[0], 0xff);
- 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);
+ opl3_command(pv_map[devc->lv_map[i]].ioaddr,
+ KSL_LEVEL + pv_map[devc->lv_map[i]].op[1], 0xff);
- opl3_command (physical_voices[logical_voices[i]].ioaddr,
- KSL_LEVEL + physical_voices[logical_voices[i]].op[3], 0xff);
- }
+ if (pv_map[devc->lv_map[i]].voice_mode == 4) {
+ opl3_command(pv_map[devc->lv_map[i]].ioaddr,
+ KSL_LEVEL + pv_map[devc->lv_map[i]].op[2], 0xff);
- opl3_kill_note (dev, i, 0, 64);
+ opl3_command(pv_map[devc->lv_map[i]].ioaddr,
+ KSL_LEVEL + pv_map[devc->lv_map[i]].op[3], 0xff);
+ }
+ opl3_kill_note(dev, i, 0, 64);
}
- if (opl3_enabled)
- {
- voice_alloc->max_voice = nr_voices = 18;
+ if (devc->model == 2) {
+ devc->v_alloc->max_voice = devc->nr_voice = 18;
- for (i = 0; i < 18; i++)
- logical_voices[i] = i;
-
- for (i = 0; i < 18; i++)
- physical_voices[i].voice_mode = 2;
+ for (i = 0; i < 18; i++)
+ pv_map[i].voice_mode = 2;
}
-
}
static int
-opl3_open (int dev, int mode)
+opl3_open(int dev, int mode)
{
- int i;
+ int i;
- if (!opl3_ok)
- return RET_ERROR (ENXIO);
- if (opl3_busy)
- return RET_ERROR (EBUSY);
- opl3_busy = 1;
+ if (devc->busy)
+ return -(EBUSY);
+ devc->busy = 1;
- voice_alloc->max_voice = nr_voices = opl3_enabled ? 18 : 9;
- voice_alloc->timestamp = 0;
+ devc->v_alloc->max_voice = devc->nr_voice = (devc->model == 2) ? 18 : 9;
+ devc->v_alloc->timestamp = 0;
- for (i = 0; i < 18; i++)
- {
- voice_alloc->map[i] = 0;
- voice_alloc->alloc_times[i] = 0;
+ for (i = 0; i < 18; i++) {
+ devc->v_alloc->map[i] = 0;
+ devc->v_alloc->alloc_times[i] = 0;
}
- connection_mask = 0x00; /*
- * Just 2 OP voices
- */
- if (opl3_enabled)
- opl3_command (right_address, CONNECTION_SELECT_REGISTER, connection_mask);
- return 0;
+ devc->cmask = 0x00; /* Just 2 OP mode */
+ if (devc->model == 2)
+ opl3_command(devc->right_io, CONNECTION_SELECT_REGISTER, devc->cmask);
+ return 0;
}
static void
-opl3_close (int dev)
+opl3_close(int dev)
{
- opl3_busy = 0;
- voice_alloc->max_voice = nr_voices = opl3_enabled ? 18 : 9;
+ devc->busy = 0;
+ devc->v_alloc->max_voice = devc->nr_voice = (devc->model == 2) ? 18 : 9;
- fm_info.nr_drums = 0;
- fm_info.perc_mode = 0;
+ devc->fm_info.nr_drums = 0;
+ devc->fm_info.perc_mode = 0;
- opl3_reset (dev);
+ opl3_reset(dev);
}
static void
-opl3_hw_control (int dev, unsigned char *event)
+opl3_hw_control(int dev, u_char *event)
{
}
static int
-opl3_load_patch (int dev, int format, snd_rw_buf * addr,
- int offs, int count, int pmgr_flag)
+opl3_load_patch(int dev, int format, snd_rw_buf * addr,
+ int offs, int count, int pmgr_flag)
{
- struct sbi_instrument ins;
+ struct sbi_instrument ins;
- if (count < sizeof (ins))
- {
- printk ("FM Error: Patch record too short\n");
- return RET_ERROR (EINVAL);
+ if (count < sizeof(ins)) {
+ printf("FM Error: Patch record too short\n");
+ return -(EINVAL);
}
+ if (uiomove(&((char *) &ins)[offs], sizeof(ins) - offs, addr)) {
+ printf("sb: Bad copyin()!\n");
+ };
- COPY_FROM_USER (&((char *) &ins)[offs], (char *) addr, offs, sizeof (ins) - offs);
-
- if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR)
- {
- printk ("FM Error: Invalid instrument number %d\n", ins.channel);
- return RET_ERROR (EINVAL);
+ if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) {
+ printf("FM Error: Invalid instrument number %d\n", ins.channel);
+ return -(EINVAL);
}
- ins.key = format;
+ ins.key = format;
- return store_instr (ins.channel, &ins);
+ return store_instr(ins.channel, &ins);
}
static void
-opl3_panning (int dev, int voice, int pressure)
+opl3_panning(int dev, int voice, int pressure)
{
}
static void
-opl3_volume_method (int dev, int mode)
+opl3_volume_method(int dev, int mode)
{
}
@@ -961,332 +820,313 @@ opl3_volume_method (int dev, int mode)
opl3_command (map->ioaddr, AM_VIB + map->op[cell-1], tmp);}
static void
-opl3_aftertouch (int dev, int voice, int pressure)
+opl3_aftertouch(int dev, int voice, int pressure)
{
- int tmp;
- struct sbi_instrument *instr;
- struct physical_voice_info *map;
+ int tmp;
+ struct sbi_instrument *instr;
+ struct physical_voice_info *map;
- if (voice < 0 || voice >= nr_voices)
- return;
+ if (voice < 0 || voice >= devc->nr_voice)
+ return;
- map = &physical_voices[logical_voices[voice]];
+ map = &pv_map[devc->lv_map[voice]];
- DEB (printk ("Aftertouch %d\n", voice));
+ DEB(printf("Aftertouch %d\n", voice));
- if (map->voice_mode == 0)
- return;
+ if (map->voice_mode == 0)
+ return;
- /*
- * Adjust the amount of vibrato depending the pressure
- */
+ /*
+ * Adjust the amount of vibrato depending the pressure
+ */
- instr = active_instrument[voice];
+ instr = devc->act_i[voice];
- if (!instr)
- instr = &instrmap[0];
+ if (!instr)
+ instr = &devc->i_map[0];
- if (voices[voice].mode == 4)
- {
- int connection = ((instr->operators[10] & 0x01) << 1) | (instr->operators[10 + OFFS_4OP] & 0x01);
+ if (devc->voc[voice].mode == 4) {
+ int connection = ((instr->operators[10] & 0x01) << 1) | (instr->operators[10 + OFFS_4OP] & 0x01);
- switch (connection)
- {
+ switch (connection) {
case 0:
- SET_VIBRATO (4);
- break;
+ SET_VIBRATO(4);
+ break;
case 1:
- SET_VIBRATO (2);
- SET_VIBRATO (4);
- break;
+ SET_VIBRATO(2);
+ SET_VIBRATO(4);
+ break;
case 2:
- SET_VIBRATO (1);
- SET_VIBRATO (4);
- break;
+ SET_VIBRATO(1);
+ SET_VIBRATO(4);
+ break;
case 3:
- SET_VIBRATO (1);
- SET_VIBRATO (3);
- SET_VIBRATO (4);
- break;
+ SET_VIBRATO(1);
+ SET_VIBRATO(3);
+ SET_VIBRATO(4);
+ break;
}
- /*
- * Not implemented yet
- */
- }
- else
- {
- SET_VIBRATO (1);
-
- if ((instr->operators[10] & 0x01)) /*
- * Additive synthesis
- */
- SET_VIBRATO (2);
+ /*
+ * Not implemented yet
+ */
+ } else {
+ SET_VIBRATO(1);
+
+ if ((instr->operators[10] & 0x01)) /* Additive synthesis */
+ SET_VIBRATO(2);
}
}
#undef SET_VIBRATO
static void
-bend_pitch (int dev, int voice, int value)
+bend_pitch(int dev, int voice, int value)
{
- unsigned char data;
- int block, fnum, freq;
- struct physical_voice_info *map;
-
- 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);
+ u_char data;
+ int block, fnum, freq;
+ struct physical_voice_info *map;
+
+ map = &pv_map[devc->lv_map[voice]];
+
+ if (map->voice_mode == 0)
+ return;
+
+ devc->voc[voice].bender = value;
+ if (!value)
+ return;
+ if (!(devc->voc[voice].keyon_byte & 0x20))
+ return; /* Not keyed on */
+
+ freq = compute_finetune(devc->voc[voice].orig_freq, devc->voc[voice].bender, devc->voc[voice].bender_range);
+ devc->voc[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 */
+ devc->voc[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)
+opl3_controller(int dev, int voice, int ctrl_num, int value)
{
- if (voice < 0 || voice >= nr_voices)
- return;
+ if (voice < 0 || voice >= devc->nr_voice)
+ return;
- switch (ctrl_num)
- {
+ switch (ctrl_num) {
case CTRL_PITCH_BENDER:
- bend_pitch (dev, voice, value);
- break;
+ bend_pitch(dev, voice, value);
+ break;
case CTRL_PITCH_BENDER_RANGE:
- voices[voice].bender_range = value;
- break;
+ devc->voc[voice].bender_range = value;
+ break;
+
+ case CTL_MAIN_VOLUME:
+ devc->voc[voice].volume = value / 128;
+ break;
}
}
static int
-opl3_patchmgr (int dev, struct patmgr_info *rec)
+opl3_patchmgr(int dev, struct patmgr_info * rec)
{
- return RET_ERROR (EINVAL);
+ return -(EINVAL);
}
static void
-opl3_bender (int dev, int voice, int value)
+opl3_bender(int dev, int voice, int value)
{
- if (voice < 0 || voice >= nr_voices)
- return;
+ if (voice < 0 || voice >= devc->nr_voice)
+ return;
- bend_pitch (dev, voice, value - 8192);
+ bend_pitch(dev, voice, value - 8192);
}
static int
-opl3_alloc_voice (int dev, int chn, int note, struct voice_alloc_info *alloc)
+opl3_alloc_voice(int dev, int chn, int note, struct voice_alloc_info * alloc)
{
- int i, p, best, first, avail_voices, best_time = 0x7fffffff;
- 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)
- {
- first = p = 0;
- avail_voices = 6;
- }
- else
- {
- if (nr_voices == 12) /* 4 OP mode. Use the '2 OP only' voices first */
- first = p = 6;
- else
+ int i, p, best, first, avail, best_time = 0x7fffffff;
+ struct sbi_instrument *instr;
+ int is4op;
+ int instr_no;
+
+ if (chn < 0 || chn > 15)
+ instr_no = 0;
+ else
+ instr_no = devc->chn_info[chn].pgm_num;
+
+ instr = &devc->i_map[instr_no];
+ if (instr->channel < 0 || /* Instrument not loaded */
+ devc->nr_voice != 12) /* Not in 4 OP mode */
+ is4op = 0;
+ else if (devc->nr_voice == 12) /* 4 OP mode */
+ is4op = (instr->key == OPL3_PATCH);
+ else
+ is4op = 0;
+
+ if (is4op) {
first = p = 0;
- avail_voices = nr_voices;
+ avail = 6;
+ } else {
+ if (devc->nr_voice == 12) /* 4 OP mode. Use the '2 OP
+ * only' operators first */
+ first = p = 6;
+ else
+ first = p = 0;
+ avail = devc->nr_voice;
}
- /*
- * Now try to find a free voice
- */
- best = first;
+ /*
+ * Now try to find a free voice
+ */
+ best = first;
- for (i = 0; i < avail_voices; i++)
- {
- if (alloc->map[p] == 0)
- {
- return p;
+ for (i = 0; i < avail; i++) {
+ if (alloc->map[p] == 0) {
+ return p;
}
- if (alloc->alloc_times[p] < best_time) /* Find oldest playing note */
- {
- best_time = alloc->alloc_times[p];
- best = p;
+ if (alloc->alloc_times[p] < best_time) { /* Find oldest playing note */
+ best_time = alloc->alloc_times[p];
+ best = p;
}
- p = (p + 1) % avail_voices;
+ p = (p + 1) % avail;
}
- /*
- * Insert some kind of priority mechanism here.
- */
+ /*
+ * Insert some kind of priority mechanism here.
+ */
- if (best < 0)
- best = 0;
- if (best > nr_voices)
- best -= nr_voices;
+ if (best < 0)
+ best = 0;
+ if (best > devc->nr_voice)
+ best -= devc->nr_voice;
- return best; /* All voices in use. Select the first one. */
+ return best; /* All devc->voc in use. Select the first
+ * one. */
}
static void
-opl3_setup_voice (int dev, int voice, int chn)
+opl3_setup_voice(int dev, int voice, int chn)
{
- struct channel_info *info =
- &synth_devs[dev]->chn_info[chn];
+ struct channel_info *info =
+ &synth_devs[dev]->chn_info[chn];
- opl3_set_instr (dev, voice,
- info->pgm_num);
+ opl3_set_instr(dev, voice, info->pgm_num);
- voices[voice].bender = info->bender_value;
+ devc->voc[voice].bender = info->bender_value;
+ devc->voc[voice].volume = info->controllers[CTL_MAIN_VOLUME];
}
static struct synth_operations opl3_operations =
{
- &fm_info,
- 0,
- SYNTH_TYPE_FM,
- FM_TYPE_ADLIB,
- opl3_open,
- opl3_close,
- opl3_ioctl,
- opl3_kill_note,
- opl3_start_note,
- opl3_set_instr,
- opl3_reset,
- opl3_hw_control,
- opl3_load_patch,
- opl3_aftertouch,
- opl3_controller,
- opl3_panning,
- opl3_volume_method,
- opl3_patchmgr,
- opl3_bender,
- opl3_alloc_voice,
- opl3_setup_voice
+ NULL,
+ 0,
+ SYNTH_TYPE_FM,
+ FM_TYPE_ADLIB,
+ opl3_open,
+ opl3_close,
+ opl3_ioctl,
+ opl3_kill_note,
+ opl3_start_note,
+ opl3_set_instr,
+ opl3_reset,
+ opl3_hw_control,
+ opl3_load_patch,
+ opl3_aftertouch,
+ opl3_controller,
+ opl3_panning,
+ opl3_volume_method,
+ opl3_patchmgr,
+ opl3_bender,
+ opl3_alloc_voice,
+ opl3_setup_voice
};
-long
-opl3_init (long mem_start)
+void
+opl3_init(int ioaddr, sound_os_info * osp)
{
- int i;
-
- PERMANENT_MALLOC (struct sbi_instrument *, instrmap,
- SBFM_MAXINSTR * sizeof (*instrmap), mem_start);
-
- 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];
+ int i;
+
+ if (num_synths >= MAX_SYNTH_DEV) {
+ printf("OPL3 Error: Too many synthesizers\n");
+ return ;
+ }
+ if (devc == NULL) {
+ printf("OPL3: Device control structure not initialized.\n");
+ return ;
+ }
+ bzero((char *) devc, sizeof(*devc));
+ devc->osp = osp;
+
+ devc->nr_voice = 9;
+ strcpy(devc->fm_info.name, "OPL2-");
+
+ devc->fm_info.device = 0;
+ devc->fm_info.synth_type = SYNTH_TYPE_FM;
+ devc->fm_info.synth_subtype = FM_TYPE_ADLIB;
+ devc->fm_info.perc_mode = 0;
+ devc->fm_info.nr_voices = 9;
+ devc->fm_info.nr_drums = 0;
+ devc->fm_info.instr_bank_size = SBFM_MAXINSTR;
+ devc->fm_info.capabilities = 0;
+ devc->left_io = ioaddr;
+ devc->right_io = ioaddr + 2;
+
+ if (detected_model <= 2)
+ devc->model = 1;
+ else {
+ devc->model = 2;
+ if (detected_model == 4)
+ devc->is_opl4 = 1;
}
- fm_model = 0;
- opl3_ok = 1;
- if (opl3_enabled)
- {
- if (opl4_enabled)
-#if defined(__FreeBSD__)
- printk ("opl0: <Yamaha OPL4/OPL3 FM>");
- else
- printk ("opl0: <Yamaha OPL-3 FM>");
-#else
- printk (" <Yamaha OPL4/OPL3 FM>");
- else
- printk (" <Yamaha OPL-3 FM>");
-#endif
+ opl3_operations.info = &devc->fm_info;
- fm_model = 2;
- voice_alloc->max_voice = nr_voices = 18;
- fm_info.nr_drums = 0;
- fm_info.capabilities |= SYNTH_CAP_OPL3;
- strcpy (fm_info.name, "Yamaha OPL-3");
+ synth_devs[num_synths++] = &opl3_operations;
+ devc->v_alloc = &opl3_operations.alloc;
+ devc->chn_info = &opl3_operations.chn_info[0];
- for (i = 0; i < 18; i++)
- if (physical_voices[i].ioaddr == USE_LEFT)
- physical_voices[i].ioaddr = left_address;
+ if (devc->model == 2) {
+ if (devc->is_opl4)
+ conf_printf2("Yamaha OPL4/OPL3 FM", ioaddr, 0, -1, -1);
else
- 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
- */
- }
- else
- {
-#if defined(__FreeBSD__)
- printk ("opl0: <Yamaha 2-OP FM>");
-#else
- printk (" <Yamaha 2-OP FM>");
-#endif
- fm_model = 1;
- voice_alloc->max_voice = nr_voices = 9;
- fm_info.nr_drums = 0;
-
- for (i = 0; i < 18; i++)
- physical_voices[i].ioaddr = left_address;
+ conf_printf2("Yamaha OPL3 FM", ioaddr, 0, -1, -1);
+
+ devc->v_alloc->max_voice = devc->nr_voice = 18;
+ devc->fm_info.nr_drums = 0;
+ devc->fm_info.capabilities |= SYNTH_CAP_OPL3;
+ strcpy(devc->fm_info.name, "Yamaha OPL-3");
+
+ for (i = 0; i < 18; i++)
+ if (pv_map[i].ioaddr == USE_LEFT)
+ pv_map[i].ioaddr = devc->left_io;
+ else
+ pv_map[i].ioaddr = devc->right_io;
+
+ opl3_command(devc->right_io, OPL3_MODE_REGISTER, OPL3_ENABLE);
+ opl3_command(devc->right_io, CONNECTION_SELECT_REGISTER, 0x00);
+ } else {
+ conf_printf2("Yamaha OPL2 FM", ioaddr, 0, -1, -1);
+ devc->v_alloc->max_voice = devc->nr_voice = 9;
+ devc->fm_info.nr_drums = 0;
+
+ for (i = 0; i < 18; i++)
+ pv_map[i].ioaddr = devc->left_io;
};
- already_initialized = 1;
- for (i = 0; i < SBFM_MAXINSTR; i++)
- instrmap[i].channel = -1;
+ for (i = 0; i < SBFM_MAXINSTR; i++)
+ devc->i_map[i].channel = -1;
- return mem_start;
+ return ;
}
#endif
diff --git a/sys/i386/isa/sound/opl3.h b/sys/i386/isa/sound/opl3.h
index d25116b..afa8d16 100644
--- a/sys/i386/isa/sound/opl3.h
+++ b/sys/i386/isa/sound/opl3.h
@@ -102,12 +102,12 @@
*
* AM/VIB/EG/KSR/Multiple (0x20 to 0x35)
*/
- #define AM_VIB 0x20
- #define TREMOLO_ON 0x80
- #define VIBRATO_ON 0x40
- #define SUSTAIN_ON 0x20
- #define KSR 0x10 /* Key scaling rate */
- #define MULTIPLE_MASK 0x0f /* Frequency multiplier */
+#define AM_VIB 0x20
+#define TREMOLO_ON 0x80
+#define VIBRATO_ON 0x40
+#define SUSTAIN_ON 0x20
+#define KSR 0x10 /* Key scaling rate */
+#define MULTIPLE_MASK 0x0f /* Frequency multiplier */
/*
* KSL/Total level (0x40 to 0x55)
@@ -231,7 +231,7 @@ struct physical_voice_info {
#define USE_LEFT 0
#define USE_RIGHT 1
-static struct physical_voice_info physical_voices[18] =
+static struct physical_voice_info pv_map[18] =
{
/* No Mode Side OP1 OP2 OP3 OP4 */
/* --------------------------------------------------- */
diff --git a/sys/i386/isa/sound/os.h b/sys/i386/isa/sound/os.h
index 055755b..159e460 100644
--- a/sys/i386/isa/sound/os.h
+++ b/sys/i386/isa/sound/os.h
@@ -1,23 +1,10 @@
-#ifndef _OS_H_
-#define _OS_H_
/*
- * OS specific settings for FreeBSD
- *
- * This chould be used as an example when porting the driver to a new
- * operating systems.
- *
- * What you should do is to rewrite the soundcard.c and os.h (this file).
- * You should create a new subdirectory and put these two files there.
- * In addition you have to do a makefile.<OS>.
+ * os.h -- only included by sound_config.h right after local.h
*
- * If you have to make changes to other than these two files, please contact me
- * before making the changes. It's possible that I have already made the
- * change.
*/
-/*
- * Insert here the includes required by your kernel.
- */
+#ifndef _OS_H_
+#define _OS_H_
#include <sys/param.h>
#include <sys/systm.h>
@@ -33,146 +20,29 @@
#include <sys/signalvar.h>
#if NSND > 0
-#define CONFIGURE_SOUNDCARD
-#else
-#undef CONFIGURED_SOUNDCARD
-#endif
-
-
-/*
- * Rest of the file is compiled only if the driver is really required.
- */
-#ifdef CONFIGURE_SOUNDCARD
-
-/*
- * select() is currently implemented in Linux specific way. Don't enable.
- * I don't remember what the SHORT_BANNERS means so forget it.
- */
-
-/*#undef ALLOW_SELECT*/
-#define SHORT_BANNERS
-/* The soundcard.h could be in a nonstandard place so inclyde it here. */
#include <machine/soundcard.h>
-
-/*
- * Here is the first portability problem. Every OS has it's own way to
- * pass a pointer to the buffer in read() and write() calls. In Linux it's
- * just a char*. In BSD it's struct uio. This parameter is passed to
- * all functions called from read() or write(). Since nothing can be
- * assumed about this structure, the driver uses set of macros for
- * accessing the user buffer.
- *
- * The driver reads/writes bytes in the user buffer sequentially which
- * means that calls like uiomove() can be used.
- *
- * snd_rw_buf is the type which is passed to the device file specific
- * read() and write() calls.
- *
- * The following macros are used to move date to and from the
- * user buffer. These macros should be used only when the
- * target or source parameter has snd_rw_buf type.
- * The offs parameter is a offset relative to the beginning of
- * the user buffer. In Linux the offset is required but for example
- * BSD passes the offset info in the uio structure. It could be usefull
- * if these macros verify that the offs parameter and the value in
- * the snd_rw_buf structure are equal.
- */
+#undef DELAY
+#define DELAY(x) tenmicrosec(x)
typedef struct uio snd_rw_buf;
-/*
- * Move bytes from the buffer which the application given in a
- * write() call.
- * offs is position relative to the beginning of the buffer in
- * user space. The count is number of bytes to be moved.
- */
-#define COPY_FROM_USER(target, source, offs, count) \
- do { if (uiomove((caddr_t ) target, count, (struct uio *)source)) { \
- printf ("sb: Bad copyin()!\n"); \
- } } while(0)
-
-/* Like COPY_FOM_USER but for writes. */
-
-#define COPY_TO_USER(target, offs, source, count) \
- do { if (uiomove(source, count, (struct uio *)target)) { \
- printf ("sb: Bad copyout()!\n"); \
- } } while(0)
-/*
- * The following macros are like COPY_*_USER but work just with one byte (8bit),
- * short (16 bit) or long (32 bit) at a time.
- * The same restrictions apply than for COPY_*_USER
- */
-#define GET_BYTE_FROM_USER(target, addr, offs) {uiomove((char*)&(target), 1, (struct uio *)addr);}
-#define GET_SHORT_FROM_USER(target, addr, offs) {uiomove((char*)&(target), 2, (struct uio *)addr);}
-#define GET_WORD_FROM_USER(target, addr, offs) {uiomove((char*)&(target), 4, (struct uio *)addr);}
-#define PUT_WORD_TO_USER(addr, offs, data) {uiomove((char*)&(data), 4, (struct uio *)addr);}
-
-
-#define EREMOTEIO -1
-
-/*
- * The way how the ioctl arguments are passed is another nonportable thing.
- * In Linux the argument is just a pointer directly to the user segment. On
- * FreeBSD the data is already moved to the kernel space. The following
- * macros should handle the difference.
- */
-
-/*
- * IOCTL_FROM_USER is used to copy a record pointed by the argument to
- * a buffer in the kernel space. On FreeBSD it can be done just by calling
- * memcpy. With Linux a memcpy_from_fs should be called instead.
- * Parameters of the following macros are like in the COPY_*_USER macros.
- */
+struct snd_wait {
+ int mode;
+ int aborting;
+};
-/*
- * When the ioctl argument points to a record or array (longer than 32 bits),
- * the macros IOCTL_*_USER are used. It's assumed that the source and target
- * parameters are direct memory addresses.
- */
-#define IOCTL_FROM_USER(target, source, offs, count) {memcpy(target, &((source)[offs]), count);}
-#define IOCTL_TO_USER(target, offs, source, count) {memcpy(&((target)[offs]), source, count);}
-/* The following macros are used if the ioctl argument points to 32 bit int */
-#define IOCTL_IN(arg) (*(int*)arg)
-#define IOCTL_OUT(arg, ret) *(int*)arg = ret
-/*
- * When the driver displays something to the console, printk() will be called.
- * The name can be changed here.
- */
-#define printk printf
+unsigned long get_time(void);
-/*
- * The following macros define an interface to the process management.
- */
+#endif /* NSND > 0 */
+#endif /* _OS_H_ */
-struct snd_wait {
- int mode;
- int aborting;
-};
+typedef caddr_t ioctl_arg;
-/*
- * DEFINE_WAIT_QUEUE is used where a wait queue is required. It must define
- * a structure which can be passed as a parameter to a sleep(). The second
- * parameter is name of a flag variable (must be defined as int).
- */
-#define DEFINE_WAIT_QUEUE(qname, flag) static int *qname = NULL; \
- static volatile struct snd_wait flag = {0}
-/* Like the above but defines an array of wait queues and flags */
-#define DEFINE_WAIT_QUEUES(qname, flag) static int *qname = {NULL}; \
- static volatile struct snd_wait flag = {{0}}
+typedef struct sound_os_info {
+ int unit;
+} sound_os_info;
-#define RESET_WAIT_QUEUE(q, f) {f.aborting = 0;f.mode = WK_NONE;}
-#define SET_ABORT_FLAG(q, f) f.aborting = 1
-#define TIMED_OUT(q, f) (f.mode & WK_TIMEOUT)
-#define SOMEONE_WAITING(q, f) (f.mode & WK_SLEEP)
-/*
- * This driver handles interrupts little bit nonstandard way. The following
- * macro is used to test if the current process has received a signal which
- * is aborts the process. This macro is called from close() to see if the
- * buffers should be discarded. If this kind info is not available, a constant
- * 1 or 0 could be returned (1 should be better than 0).
- */
-#define PROCESS_ABORTING(q, f) (f.aborting || CURSIG(curproc))
/*
* The following macro calls tsleep. It should be implemented such that
@@ -193,157 +63,37 @@ struct snd_wait {
} else \
f.aborting = flag; \
}
-/* An the following wakes up a process */
-#define WAKE_UP(q, f) wakeup(&q)
-
-/*
- * Timing macros. This driver assumes that there is a timer running in the
- * kernel. The timer should return a value which is increased once at every
- * timer tick. The macro HZ should return the number of such ticks/sec.
- */
-
-#ifndef HZ
-#define HZ hz
-#endif
-
-/*
- * GET_TIME() returns current value of the counter incremented at timer
- * ticks. This can overflow, so the timeout might be real big...
- *
- */
-
-extern unsigned long get_time(void);
-#define GET_TIME() get_time()
-/*#define GET_TIME() (lbolt) */ /* Returns current time (1/HZ secs since boot) */
-/*
- * The following three macros are called before and after atomic
- * code sequences. The flags parameter has always type of unsigned long.
- * The macro DISABLE_INTR() should ensure that all interrupts which
- * may invoke any part of the driver (timer, soundcard interrupts) are
- * disabled.
- * RESTORE_INTR() should return the interrupt status back to the
- * state when DISABLE_INTR() was called. The flags parameter is
- * a variable which can carry 32 bits of state information between
- * DISABLE_INTR() and RESTORE_INTR() calls.
- */
-#define DISABLE_INTR(flags) flags = splhigh()
-#define RESTORE_INTR(flags) splx(flags)
-
-/*
- * INB() and OUTB() should be obvious. NOTE! The order of
- * paratemeters of OUTB() is different than on some other
- * operating systems.
- */
-
-#define INB inb
-#define INW inb
-
-#if 0
-/*
- * outb(0x5f, 0) and outb(0x80, 0) are just for delay. They are a bit
- * unsafe since there might be a device at the magic address.
- */
-#ifdef PC98
-#define OUTB(data, addr) { outb(addr, data); outb(0x5f, 0); }
-#define OUTW(data, addr) { outw(addr, data); outb(0x5f, 0); }
-#else /* IBM-PC */
-#define OUTB(data, addr) { outb(addr, data); outb(0x80, 0); }
-#define OUTW(data, addr) { outw(addr, data); outb(0x80, 0); }
-#endif /* PC98 */
-#else
-#define OUTB(data, addr) outb(addr, data)
-#define OUTW(data, addr) outw(addr, data)
-#endif
-
-/* memcpy() was not defined on FreeBSD. Lets define it here */
-#define memcpy(d, s, c) bcopy(s, d, c)
-
-/*
- * When a error (such as EINVAL) is returned by a function,
- * the following macro is used. The driver assumes that a
- * error is signalled by returning a negative value.
- */
-
-#define RET_ERROR(err) -(err)
-
-/*
- KERNEL_MALLOC() allocates requested number of memory and
- KERNEL_FREE is used to free it.
- These macros are never called from interrupt, in addition the
- nbytes will never be more than 4096 bytes. Generally the driver
- will allocate memory in blocks of 4k. If the kernel has just a
- page level memory allocation, 4K can be safely used as the size
- (the nbytes parameter can be ignored).
-*/
-#define KERNEL_MALLOC(nbytes) malloc(nbytes, M_TEMP, M_WAITOK)
-#define KERNEL_FREE(addr) free(addr, M_TEMP)
-
-/*
- * The macro PERMANENT_MALLOC(typecast, mem_ptr, size, linux_ptr)
- * returns size bytes of
- * (kernel virtual) memory which will never get freed by the driver.
- * This macro is called only during boot. The linux_ptr is a linux specific
- * parameter which should be ignored in other operating systems.
- * The mem_ptr is a pointer variable where the macro assigns pointer to the
- * memory area. The type is the type of the mem_ptr.
- */
-#define PERMANENT_MALLOC(typecast, mem_ptr, size, linux_ptr) \
- {mem_ptr = (typecast)malloc(size, M_DEVBUF, M_NOWAIT); \
- if (!mem_ptr)panic("SOUND: Cannot allocate memory\n");}
-
-/*
- * The macro DEFINE_TIMER defines variables for the ACTIVATE_TIMER if
- * required. The name is the variable/name to be used and the proc is
- * the procedure to be called when the timer expires.
- */
-
-#define DEFINE_TIMER(name, proc)
-
-/*
- * The ACTIVATE_TIMER requests system to call 'proc' after 'time' ticks.
- */
-
-#define ACTIVATE_TIMER(name, proc, time) timeout(proc, 0, time)
-/*
- * The rest of this file is not complete yet. The functions using these
- * macros will not work
- */
-#define ALLOC_DMA_CHN(chn,deviceID) (isa_dma_acquire(chn))
-#define RELEASE_DMA_CHN(chn) (isa_dma_release(chn))
-#define DMA_MODE_READ 0
-#define DMA_MODE_WRITE 1
-#define RELEASE_IRQ(irq_no)
+#define DO_SLEEP1(q, f, time_limit) \
+ { \
+ int flag; \
+ f.mode = WK_SLEEP; \
+ flag=tsleep(&q, (PRIBIO-5)|PCATCH, "snd1", time_limit); \
+ f.mode &= ~WK_SLEEP; \
+ if (flag == EWOULDBLOCK) { \
+ f.mode |= WK_TIMEOUT; \
+ f.aborting = 0; \
+ } else \
+ f.aborting = flag; \
+ }
-/*
- * The macro DECLARE_FILE() adds an entry to struct fileinfo referencing the
- * connected filestructure.
- * This entry must be initialized in sound_open() in soundcard.c
- *
- * ISSET_FILE_FLAG() allows checking of flags like O_NONBLOCK on files
- *
- */
+#define DO_SLEEP2(q, f, time_limit) \
+ { \
+ int flag; \
+ f.mode = WK_SLEEP; \
+ flag=tsleep(&q, (PRIBIO-5)|PCATCH, "snd2", time_limit); \
+ f.mode &= ~WK_SLEEP; \
+ if (flag == EWOULDBLOCK) { \
+ f.mode |= WK_TIMEOUT; \
+ f.aborting = 0; \
+ } else \
+ f.aborting = flag; \
+ }
-#define DECLARE_FILE() struct file *filp
-#ifdef notdef
-#define ISSET_FILE_FLAG(fileinfo, flag) (fileinfo->filp->f_flag & (flag) ? \
- 1 : 0)
-#else
-#define ISSET_FILE_FLAG(fileinfo, flag) 0
-#endif
-#define INT_HANDLER_PROTO() void(*hndlr)(int)
-#define INT_HANDLER_PARMS(irq, parms) int irq
-#define INT_HANDLER_CALL(irq) irq
+#define PROCESS_ABORTING( f) (f.aborting || CURSIG(curproc))
+#define TIMED_OUT( f) (f.mode & WK_TIMEOUT)
-/*
- * For select call...
- */
#ifdef ALLOW_SELECT
typedef struct proc select_table;
-#define SEL_IN FREAD
-#define SEL_OUT FWRITE
-#define SEL_EX 0
extern struct selinfo selinfo[];
-#endif
-#endif
#endif
diff --git a/sys/i386/isa/sound/pas2_card.c b/sys/i386/isa/sound/pas2_card.c
index b609261..79acf57 100644
--- a/sys/i386/isa/sound/pas2_card.c
+++ b/sys/i386/isa/sound/pas2_card.c
@@ -1,11 +1,10 @@
-#define _PAS2_CARD_C_
/*
* sound/pas2_card.c
- *
+ *
* Detection routine for the Pro Audio Spectrum cards.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -13,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -25,19 +24,15 @@
* 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 <i386/isa/sound/sound_config.h>
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_PAS)
+#if defined(CONFIG_PAS)
+#define _PAS2_CARD_C_
#define DEFINE_TRANSLATIONS
-#include <i386/isa/sound/pas_defs.h>
-
-static int config_pas_hw __P((struct address_info *hw_config));
-static int detect_pas_hw __P((struct address_info *hw_config));
-static void pas2_msg __P((char *foo));
+#include <i386/isa/sound/pas_hw.h>
/*
* The Address Translation code is used to convert I/O register addresses to
@@ -48,13 +43,14 @@ int translat_code;
static int pas_intr_mask = 0;
static int pas_irq = 0;
+sound_os_info *pas_osp;
+
char pas_model;
static char *pas_model_names[] =
{"", "Pro AudioSpectrum+", "CDPC", "Pro AudioSpectrum 16", "Pro AudioSpectrum 16D"};
-extern void mix_write (unsigned char data, int ioaddr);
/*
- * pas_read() and pas_write() are equivalents of INB() and OUTB()
+ * pas_read() and pas_write() are equivalents of inb and outb
*/
/*
* These routines perform the I/O address translation required
@@ -62,359 +58,304 @@ extern void mix_write (unsigned char data, int ioaddr);
/*
* to support other than the default base address
*/
+extern void mix_write(u_char data, int ioaddr);
-unsigned char
-pas_read (int ioaddr)
+u_char
+pas_read(int ioaddr)
{
- return INB (ioaddr ^ translat_code);
+ return inb(ioaddr ^ translat_code);
}
void
-pas_write (unsigned char data, int ioaddr)
+pas_write(u_char data, int ioaddr)
{
- OUTB (data, ioaddr ^ translat_code);
+ outb(ioaddr ^ translat_code, data);
}
-static void
-pas2_msg (char *foo)
+void
+pas2_msg(char *foo)
{
- printk (" PAS2: %s.\n", foo);
+ printf(" PAS2: %s.\n", foo);
}
/******************* Begin of the Interrupt Handler ********************/
void
-pasintr (INT_HANDLER_PARMS (irq, dummy))
+pasintr(int irq)
{
- int status;
+ int status;
- status = pas_read (INTERRUPT_STATUS);
- pas_write (status, INTERRUPT_STATUS); /*
- * Clear interrupt
- */
+ status = pas_read(INTERRUPT_STATUS);
+ pas_write(status, INTERRUPT_STATUS); /* Clear interrupt */
- if (status & I_S_PCM_SAMPLE_BUFFER_IRQ)
- {
-#ifndef EXCLUDE_AUDIO
- pas_pcm_interrupt (status, 1);
-#endif
- status &= ~I_S_PCM_SAMPLE_BUFFER_IRQ;
- }
- if (status & I_S_MIDI_IRQ)
- {
-#ifndef EXCLUDE_MIDI
-#ifdef EXCLUDE_PRO_MIDI
- pas_midi_interrupt ();
+ if (status & I_S_PCM_SAMPLE_BUFFER_IRQ) {
+#ifdef CONFIG_AUDIO
+ pas_pcm_interrupt(status, 1);
#endif
+ status &= ~I_S_PCM_SAMPLE_BUFFER_IRQ;
+ }
+ if (status & I_S_MIDI_IRQ) {
+#ifdef CONFIG_MIDI
+ pas_midi_interrupt();
#endif
- status &= ~I_S_MIDI_IRQ;
- }
-
+ status &= ~I_S_MIDI_IRQ;
+ }
}
int
-pas_set_intr (int mask)
+pas_set_intr(int mask)
{
- int err;
+ if (!mask)
+ return 0;
- if (!mask)
- return 0;
+ pas_intr_mask |= mask;
- if (!pas_intr_mask)
- {
- if ((err = snd_set_irq_handler (pas_irq, pasintr, "PAS16")) < 0)
- return err;
- }
- pas_intr_mask |= mask;
-
- pas_write (pas_intr_mask, INTERRUPT_MASK);
- return 0;
+ pas_write(pas_intr_mask, INTERRUPT_MASK);
+ return 0;
}
int
-pas_remove_intr (int mask)
+pas_remove_intr(int mask)
{
- if (!mask)
- return 0;
+ if (!mask)
+ return 0;
- pas_intr_mask &= ~mask;
- pas_write (pas_intr_mask, INTERRUPT_MASK);
+ pas_intr_mask &= ~mask;
+ pas_write(pas_intr_mask, INTERRUPT_MASK);
- if (!pas_intr_mask)
- {
- snd_release_irq (pas_irq);
- }
- return 0;
+ return 0;
}
/******************* End of the Interrupt handler **********************/
/******************* Begin of the Initialization Code ******************/
-static int
-config_pas_hw (struct address_info *hw_config)
+int
+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 (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 (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 (I_C_1_BOOT_RESET_ENABLE
+ char ok = 1;
+ u_int 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(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(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(I_C_1_BOOT_RESET_ENABLE
#ifdef PAS_JOYSTICK_ENABLE
- | I_C_1_JOYSTICK_ENABLE
+ | I_C_1_JOYSTICK_ENABLE
#endif
- ,IO_CONFIGURATION_1);
-
- if (pas_irq < 0 || pas_irq > 15)
- {
- printk ("PAS2: Invalid IRQ %d", pas_irq);
- ok = 0;
- }
- else
- {
- 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);
- ok = 0;
+ ,IO_CONFIGURATION_1);
+
+ if (pas_irq < 0 || pas_irq > 15) {
+ printf("PAS2: Invalid IRQ %d", pas_irq);
+ ok = 0;
+ } else {
+ 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]) {
+ printf("PAS2: Invalid IRQ %d", pas_irq);
+ ok = 0;
+ } else {
+ if (snd_set_irq_handler(pas_irq, pasintr, hw_config->osp) < 0)
+ ok = 0;
+ }
}
- }
-
- if (hw_config->dma < 0 || hw_config->dma > 7)
- {
- printk ("PAS2: Invalid DMA selection %d", hw_config->dma);
- ok = 0;
- }
- else
- {
- pas_write (I_C_2_PCM_DMA_translate[hw_config->dma], IO_CONFIGURATION_2);
- if (!I_C_2_PCM_DMA_translate[hw_config->dma])
- {
- printk ("PAS2: Invalid DMA selection %d", hw_config->dma);
- ok = 0;
+
+ if (hw_config->dma < 0 || hw_config->dma > 7) {
+ printf("PAS2: Invalid DMA selection %d", hw_config->dma);
+ ok = 0;
+ } else {
+ pas_write(I_C_2_PCM_DMA_translate[hw_config->dma], IO_CONFIGURATION_2);
+ if (!I_C_2_PCM_DMA_translate[hw_config->dma]) {
+ printf("PAS2: Invalid DMA selection %d", hw_config->dma);
+ ok = 0;
+ } else {
+ if (0) {
+ printf("pas2_card.c: Can't allocate DMA channel\n");
+ ok = 0;
+ }
+ }
}
- }
- /*
- * This fixes the timing problems of the PAS due to the Symphony chipset
- * as per Media Vision. Only define this if your PAS doesn't work correctly.
- */
+ /*
+ * This fixes the timing problems of the PAS due to the Symphony
+ * chipset as per Media Vision. Only define this if your PAS doesn't
+ * work correctly.
+ */
#ifdef SYMPHONY_PAS
- OUTB (0x05, 0xa8);
- OUTB (0x60, 0xa9);
+ outb(0xa8, 0x05);
+ outb(0xa9, 0x60);
#endif
#ifdef BROKEN_BUS_CLOCK
- pas_write (S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND | S_C_1_FM_EMULATE_CLOCK, SYSTEM_CONFIGURATION_1);
+ pas_write(S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND | S_C_1_FM_EMULATE_CLOCK, SYSTEM_CONFIGURATION_1);
#else
- /*
- * pas_write(S_C_1_PCS_ENABLE, SYSTEM_CONFIGURATION_1);
- */
- pas_write (S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND, SYSTEM_CONFIGURATION_1);
+ /*
+ * 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(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(F_F_MIXER_UNMUTE | 0x01, FILTER_FREQUENCY); /* Sets mute off and *
+ * selects filter rate *
+ * of 17.897 kHz */
+ pas_write(8, PRESCALE_DIVIDER);
- if (pas_model == PAS_16 || pas_model == PAS_16D)
- pas_write (8, PRESCALE_DIVIDER);
- else
- pas_write (0, PRESCALE_DIVIDER);
+ mix_write(P_M_MV508_ADDRESS | 5, PARALLEL_MIXER);
+ mix_write(5, PARALLEL_MIXER);
- mix_write (P_M_MV508_ADDRESS | 5, PARALLEL_MIXER);
- mix_write (5, PARALLEL_MIXER);
+#if defined(CONFIG_SB_EMULATION) && defined(CONFIG_SB)
-#if !defined(EXCLUDE_SB_EMULATION) || !defined(EXCLUDE_SB)
+ {
+ struct address_info *sb_config;
+
+ if ((sb_config = sound_getconf(SNDCARD_SB))) {
+ u_char irq_dma;
+
+ /*
+ * Turn on Sound Blaster compatibility
+ */
+ /*
+ * bit 1 = SB emulation
+ */
+ /*
+ * bit 0 = MPU401 emulation (CDPC only :-( )
+ */
+ pas_write(0x02, COMPATIBILITY_ENABLE);
+
+ /*
+ * "Emulation address"
+ */
+ pas_write((sb_config->io_base >> 4) & 0x0f, EMULATION_ADDRESS);
+
+ if (!E_C_SB_DMA_translate[sb_config->dma])
+ printf("\n\nPAS16 Warning: Invalid SB DMA %d\n\n",
+ sb_config->dma);
+
+ if (!E_C_SB_IRQ_translate[sb_config->irq])
+ printf("\n\nPAS16 Warning: Invalid SB IRQ %d\n\n",
+ sb_config->irq);
+
+ irq_dma = E_C_SB_DMA_translate[sb_config->dma] |
+ E_C_SB_IRQ_translate[sb_config->irq];
+
+ pas_write(irq_dma, EMULATION_CONFIGURATION);
+ }
+ }
+#else
+ pas_write(0x00, COMPATIBILITY_ENABLE);
+#endif
- {
- struct address_info *sb_config;
+ if (!ok)
+ pas2_msg("Driver not enabled");
- if ((sb_config = sound_getconf (SNDCARD_SB)))
- {
- unsigned char irq_dma;
+ return ok;
+}
- /*
- * Turn on Sound Blaster compatibility
- */
- /*
- * bit 1 = SB emulation
- */
- /*
- * bit 0 = MPU401 emulation (CDPC only :-( )
- */
- pas_write (0x02, COMPATIBILITY_ENABLE);
+int
+detect_pas_hw(struct address_info * hw_config)
+{
+ u_char board_id, foo;
/*
- * "Emulation address"
+ * WARNING: Setting an option like W:1 or so that disables warm boot
+ * reset of the card will screw up this detect code something fierce.
+ * Adding code to handle this means possibly interfering with other
+ * cards on the bus if you have something on base port 0x388. SO be
+ * forewarned.
*/
- pas_write ((sb_config->io_base >> 4) & 0x0f, EMULATION_ADDRESS);
- if (!E_C_SB_DMA_translate[sb_config->dma])
- printk ("\n\nPAS16 Warning: Invalid SB DMA %d\n\n",
- sb_config->dma);
+ outb(MASTER_DECODE, 0xBC); /* Talk to first board */
+ outb(MASTER_DECODE, hw_config->io_base >> 2); /* Set base address */
+ translat_code = PAS_DEFAULT_BASE ^ hw_config->io_base;
+ pas_write(1, WAIT_STATE); /* One wait-state */
- if (!E_C_SB_IRQ_translate[sb_config->irq])
- printk ("\n\nPAS16 Warning: Invalid SB IRQ %d\n\n",
- sb_config->irq);
+ board_id = pas_read(INTERRUPT_MASK);
- irq_dma = E_C_SB_DMA_translate[sb_config->dma] |
- E_C_SB_IRQ_translate[sb_config->irq];
+ if (board_id == 0xff)
+ return 0;
- pas_write (irq_dma, EMULATION_CONFIGURATION);
- }
- }
-#endif
+ /*
+ * We probably have a PAS-series board, now check for a PAS2-series
+ * board by trying to change the board revision bits. PAS2-series
+ * hardware won't let you do this - the bits are read-only.
+ */
- if (!ok)
- pas2_msg ("Driver not enabled");
+ foo = board_id ^ 0xe0;
- return ok;
-}
+ pas_write(foo, INTERRUPT_MASK);
+ foo = inb(INTERRUPT_MASK);
+ pas_write(board_id, INTERRUPT_MASK);
-static int
-detect_pas_hw (struct address_info *hw_config)
-{
- unsigned char board_id, foo;
-
- /*
- * WARNING: Setting an option like W:1 or so that disables warm boot reset
- * of the card will screw up this detect code something fierce. Adding code
- * to handle this means possibly interfering with other cards on the bus if
- * 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
- */
- translat_code = PAS_DEFAULT_BASE ^ hw_config->io_base;
- pas_write (1, WAIT_STATE); /*
- * One wait-state
- */
-
- board_id = pas_read (INTERRUPT_MASK);
-
- if (board_id == 0xff)
- return 0;
-
- /*
- * We probably have a PAS-series board, now check for a PAS2-series board
- * by trying to change the board revision bits. PAS2-series hardware won't
- * let you do this - the bits are read-only.
- */
-
- foo = board_id ^ 0xe0;
-
- pas_write (foo, INTERRUPT_MASK);
- foo = INB (INTERRUPT_MASK);
- pas_write (board_id, INTERRUPT_MASK);
-
- if (board_id != foo) /*
- * Not a PAS2
- */
- return 0;
-
- pas_model = pas_read (CHIP_REV);
-
- return pas_model;
+ if (board_id != foo) /* Not a PAS2 */
+ return 0;
+
+ pas_model = pas_read(CHIP_REV);
+
+ return pas_model;
}
-long
-attach_pas_card (long mem_start, struct address_info *hw_config)
+void
+attach_pas_card(struct address_info * hw_config)
{
- pas_irq = hw_config->irq;
+ pas_irq = hw_config->irq;
+ pas_osp = hw_config->osp;
- if (detect_pas_hw (hw_config))
- {
+ if (detect_pas_hw(hw_config)) {
- if (pas_model = pas_read (CHIP_REV))
- {
-#ifdef __FreeBSD__
- printk ("pas0: <%s rev %d>", pas_model_names[(int) pas_model], pas_read (BOARD_REV_ID));
-#else
- printk (" <%s rev %d>", pas_model_names[(int) pas_model], pas_read (BOARD_REV_ID));
-#endif
- }
+ if ((pas_model = pas_read(CHIP_REV))) {
+ char temp[100];
- if (config_pas_hw (hw_config))
- {
+ sprintf(temp,
+ "%s rev %d", pas_model_names[(int) pas_model],
+ pas_read(BOARD_REV_ID));
+ conf_printf(temp, hw_config);
+ }
+ if (config_pas_hw(hw_config)) {
-#ifndef EXCLUDE_AUDIO
- mem_start = pas_pcm_init (mem_start, hw_config);
+#ifdef CONFIG_AUDIO
+ pas_pcm_init(hw_config);
#endif
-#if !defined(EXCLUDE_SB_EMULATION) && !defined(EXCLUDE_SB)
+#if defined(CONFIG_SB_EMULATION) && defined(CONFIG_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
- enable_opl3_mode (0x388, 0x38a, 0);
-#endif
-#ifndef EXCLUDE_MIDI
-#ifdef EXCLUDE_PRO_MIDI
- mem_start = pas_midi_init (mem_start);
+#ifdef CONFIG_MIDI
+ pas_midi_init();
#endif
-#endif
-
- pas_init_mixer ();
+ pas_init_mixer();
+ }
}
- }
-
- return mem_start;
}
int
-probe_pas (struct address_info *hw_config)
+probe_pas(struct address_info * hw_config)
{
- return detect_pas_hw (hw_config);
+ pas_osp = hw_config->osp;
+ return detect_pas_hw(hw_config);
}
#endif
diff --git a/sys/i386/isa/sound/pas2_midi.c b/sys/i386/isa/sound/pas2_midi.c
index ac4467b..006b7d4c 100644
--- a/sys/i386/isa/sound/pas2_midi.c
+++ b/sys/i386/isa/sound/pas2_midi.c
@@ -1,10 +1,10 @@
/*
* sound/pas2_midi.c
- *
+ *
* The low level driver for the PAS Midi Interface.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,211 +24,186 @@
* 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 <i386/isa/sound/sound_config.h>
-#ifdef CONFIGURE_SOUNDCARD
-
-#include <i386/isa/sound/pas_defs.h>
-
-#if !defined(EXCLUDE_PAS) && !defined(EXCLUDE_MIDI) && defined(EXCLUDE_PRO_MIDI)
+#if defined(CONFIG_PAS) && defined(CONFIG_MIDI)
+#include <i386/isa/sound/pas_hw.h>
static int midi_busy = 0, input_opened = 0;
static int my_dev;
static volatile int ofifo_bytes = 0;
-static unsigned char tmp_queue[256];
+static u_char tmp_queue[256];
static volatile int qlen;
-static volatile unsigned char qhead, qtail;
+static volatile u_char qhead, qtail;
-static void (*midi_input_intr) (int dev, unsigned char data);
+static void (*midi_input_intr) (int dev, u_char data);
static int
-pas_midi_open (int dev, int mode,
- void (*input) (int dev, unsigned char data),
- void (*output) (int dev)
+pas_midi_open(int dev, int mode,
+ void (*input) (int dev, u_char data),
+ void (*output) (int dev)
)
{
- int err;
- unsigned long flags;
- unsigned char ctrl;
-
-
- if (midi_busy)
- {
- printk ("PAS2: Midi busy\n");
- return RET_ERROR (EBUSY);
- }
-
- /*
- * Reset input and output FIFO pointers
- */
- pas_write (M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO,
- MIDI_CONTROL);
-
- DISABLE_INTR (flags);
-
- if ((err = pas_set_intr (I_M_MIDI_IRQ_ENABLE)) < 0)
- return err;
-
- /*
- * Enable input available and output FIFO empty interrupts
- */
-
- ctrl = 0;
- input_opened = 0;
- midi_input_intr = input;
-
- if (mode == OPEN_READ || mode == OPEN_READWRITE)
- {
- 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
- */
- M_C_ENA_OUTPUT_HALF_IRQ;
- }
-
- pas_write (ctrl,
- MIDI_CONTROL);
-
- /*
- * Acknowledge any pending interrupts
- */
-
- pas_write (0xff, MIDI_STATUS);
- ofifo_bytes = 0;
-
- RESTORE_INTR (flags);
-
- midi_busy = 1;
- qlen = qhead = qtail = 0;
- return 0;
+ int err;
+ u_long flags;
+ u_char ctrl;
+
+
+ if (midi_busy) {
+ printf("PAS2: Midi busy\n");
+ return -(EBUSY);
+ }
+ /*
+ * Reset input and output FIFO pointers
+ */
+ pas_write(M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO,
+ MIDI_CONTROL);
+
+ flags = splhigh();
+
+ if ((err = pas_set_intr(I_M_MIDI_IRQ_ENABLE)) < 0)
+ return err;
+
+ /*
+ * Enable input available and output FIFO empty interrupts
+ */
+
+ ctrl = 0;
+ input_opened = 0;
+ midi_input_intr = input;
+
+ if (mode == OPEN_READ || mode == OPEN_READWRITE) {
+ 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 */
+ M_C_ENA_OUTPUT_HALF_IRQ;
+ }
+ pas_write(ctrl,
+ MIDI_CONTROL);
+
+ /*
+ * Acknowledge any pending interrupts
+ */
+
+ pas_write(0xff, MIDI_STATUS);
+ ofifo_bytes = 0;
+
+ splx(flags);
+
+ midi_busy = 1;
+ qlen = qhead = qtail = 0;
+ return 0;
}
static void
-pas_midi_close (int dev)
+pas_midi_close(int dev)
{
- /*
- * Reset FIFO pointers, disable intrs
- */
- pas_write (M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO, MIDI_CONTROL);
+ /*
+ * 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);
- midi_busy = 0;
+ pas_remove_intr(I_M_MIDI_IRQ_ENABLE);
+ midi_busy = 0;
}
static int
-dump_to_midi (unsigned char midi_byte)
+dump_to_midi(u_char midi_byte)
{
- int fifo_space, x;
+ int fifo_space, x;
- fifo_space = ((x = pas_read (MIDI_FIFO_STATUS)) >> 4) & 0x0f;
+ fifo_space = ((x = pas_read(MIDI_FIFO_STATUS)) >> 4) & 0x0f;
- if (fifo_space == 15 || (fifo_space < 2 && ofifo_bytes > 13)) /*
- * Fifo
- * full
- */
- {
- return 0; /*
- * Upper layer will call again
- */
- }
-
- ofifo_bytes++;
+ if (fifo_space == 15 || (fifo_space < 2 && ofifo_bytes > 13)) { /* Fifo full */
+ return 0; /* Upper layer will call again */
+ }
+ ofifo_bytes++;
- pas_write (midi_byte, MIDI_DATA);
+ pas_write(midi_byte, MIDI_DATA);
- return 1;
+ return 1;
}
static int
-pas_midi_out (int dev, unsigned char midi_byte)
+pas_midi_out(int dev, u_char midi_byte)
{
- unsigned long flags;
+ u_long flags;
- /*
- * Drain the local queue first
- */
+ /*
+ * Drain the local queue first
+ */
- DISABLE_INTR (flags);
+ flags = splhigh();
- while (qlen && dump_to_midi (tmp_queue[qhead]))
- {
- qlen--;
- qhead++;
- }
+ while (qlen && dump_to_midi(tmp_queue[qhead])) {
+ qlen--;
+ qhead++;
+ }
- RESTORE_INTR (flags);
+ splx(flags);
- /*
- * Output the byte if the local queue is empty.
- */
+ /*
+ * Output the byte if the local queue is empty.
+ */
- if (!qlen)
- if (dump_to_midi (midi_byte))
- return 1; /*
- * OK
- */
+ if (!qlen)
+ if (dump_to_midi(midi_byte))
+ return 1; /* OK */
- /*
- * Put to the local queue
- */
+ /*
+ * Put to the local queue
+ */
- if (qlen >= 256)
- return 0; /*
- * Local queue full
- */
+ if (qlen >= 256)
+ return 0; /* Local queue full */
- DISABLE_INTR (flags);
+ flags = splhigh();
- tmp_queue[qtail] = midi_byte;
- qlen++;
- qtail++;
+ tmp_queue[qtail] = midi_byte;
+ qlen++;
+ qtail++;
- RESTORE_INTR (flags);
+ splx(flags);
- return 1;
+ return 1;
}
static int
-pas_midi_start_read (int dev)
+pas_midi_start_read(int dev)
{
- return 0;
+ return 0;
}
static int
-pas_midi_end_read (int dev)
+pas_midi_end_read(int dev)
{
- return 0;
+ return 0;
}
static int
-pas_midi_ioctl (int dev, unsigned cmd, unsigned arg)
+pas_midi_ioctl(int dev, u_int cmd, ioctl_arg arg)
{
- return RET_ERROR (EINVAL);
+ return -(EINVAL);
}
static void
-pas_midi_kick (int dev)
+pas_midi_kick(int dev)
{
- ofifo_bytes = 0;
+ ofifo_bytes = 0;
}
static int
-pas_buffer_status (int dev)
+pas_buffer_status(int dev)
{
- return !qlen;
+ return qlen;
}
#define MIDI_SYNTH_NAME "Pro Audio Spectrum Midi"
@@ -237,105 +212,74 @@ pas_buffer_status (int dev)
static struct midi_operations pas_midi_operations =
{
- {"Pro Audio Spectrum", 0, 0, SNDCARD_PAS},
- &std_midi_synth,
- {0},
- pas_midi_open,
- pas_midi_close,
- pas_midi_ioctl,
- pas_midi_out,
- pas_midi_start_read,
- pas_midi_end_read,
- pas_midi_kick,
- NULL, /*
- * command
- */
- pas_buffer_status,
- NULL
+ {"Pro Audio Spectrum", 0, 0, SNDCARD_PAS},
+ &std_midi_synth,
+ {0},
+ pas_midi_open,
+ pas_midi_close,
+ pas_midi_ioctl,
+ pas_midi_out,
+ pas_midi_start_read,
+ pas_midi_end_read,
+ pas_midi_kick,
+ NULL, /* command */
+ pas_buffer_status,
+ NULL
};
-long
-pas_midi_init (long mem_start)
+void
+pas_midi_init()
{
- 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;
+ if (num_midis >= MAX_MIDI_DEV) {
+ printf("Sound: Too many midi devices detected\n");
+ return;
+ }
+ std_midi_synth.midi_dev = my_dev = num_midis;
+ midi_devs[num_midis++] = &pas_midi_operations;
+ return;
}
void
-pas_midi_interrupt (void)
+pas_midi_interrupt(void)
{
- unsigned char stat;
- int i, incount;
- unsigned long flags;
-
- stat = pas_read (MIDI_STATUS);
-
- if (stat & M_S_INPUT_AVAIL) /*
- * Input byte available
- */
- {
- incount = pas_read (MIDI_FIFO_STATUS) & 0x0f; /*
- * Input FIFO count
- */
- if (!incount)
- incount = 16;
-
- for (i = 0; i < incount; i++)
- if (input_opened)
- {
- midi_input_intr (my_dev, pas_read (MIDI_DATA));
- }
- else
- pas_read (MIDI_DATA); /*
- * Flush
- */
- }
-
- if (stat & (M_S_OUTPUT_EMPTY | M_S_OUTPUT_HALF_EMPTY))
- {
- if (!(stat & M_S_OUTPUT_EMPTY))
- {
- ofifo_bytes = 8;
- }
- else
- {
- ofifo_bytes = 0;
+ u_char stat;
+ int i, incount;
+ u_long flags;
+
+ stat = pas_read(MIDI_STATUS);
+
+ if (stat & M_S_INPUT_AVAIL) { /* Input byte available */
+ incount = pas_read(MIDI_FIFO_STATUS) & 0x0f; /* Input FIFO count */
+ if (!incount)
+ incount = 16;
+
+ for (i = 0; i < incount; i++)
+ if (input_opened) {
+ midi_input_intr(my_dev, pas_read(MIDI_DATA));
+ } else
+ pas_read(MIDI_DATA); /* Flush */
}
+ if (stat & (M_S_OUTPUT_EMPTY | M_S_OUTPUT_HALF_EMPTY)) {
+ if (!(stat & M_S_OUTPUT_EMPTY)) {
+ ofifo_bytes = 8;
+ } else {
+ ofifo_bytes = 0;
+ }
- DISABLE_INTR (flags);
-
- while (qlen && dump_to_midi (tmp_queue[qhead]))
- {
- qlen--;
- qhead++;
- }
+ flags = splhigh();
- RESTORE_INTR (flags);
- }
+ while (qlen && dump_to_midi(tmp_queue[qhead])) {
+ qlen--;
+ qhead++;
+ }
-#if 0
- if (stat & M_S_FRAMING_ERROR)
- printk ("MIDI framing error\n");
-#endif
-
- if (stat & M_S_OUTPUT_OVERRUN)
- {
- printk ("MIDI output overrun %x,%x,%d \n", pas_read (MIDI_FIFO_STATUS), stat, ofifo_bytes);
- ofifo_bytes = 100;
- }
-
- pas_write (stat, MIDI_STATUS); /*
- * Acknowledge interrupts
- */
+ splx(flags);
+ }
+ if (stat & M_S_OUTPUT_OVERRUN) {
+ printf("MIDI output overrun %x,%x,%d \n", pas_read(MIDI_FIFO_STATUS), stat, ofifo_bytes);
+ ofifo_bytes = 100;
+ }
+ pas_write(stat, MIDI_STATUS); /* Acknowledge interrupts */
}
#endif
-
-#endif
diff --git a/sys/i386/isa/sound/pas2_mixer.c b/sys/i386/isa/sound/pas2_mixer.c
index 53ae8ad..4831bd2 100644
--- a/sys/i386/isa/sound/pas2_mixer.c
+++ b/sys/i386/isa/sound/pas2_mixer.c
@@ -1,12 +1,10 @@
-#define _PAS2_MIXER_C_
-
/*
* sound/pas2_mixer.c
- *
+ *
* Mixer routines for the Pro Audio Spectrum cards.
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -14,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -26,25 +24,24 @@
* 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 <i386/isa/sound/sound_config.h>
+#define _PAS2_MIXER_C_
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_PAS)
+#include <i386/isa/sound/sound_config.h>
-#include <i386/isa/sound/pas_defs.h>
+#if defined(CONFIG_PAS)
-extern void mix_write __P((unsigned char data, int ioaddr));
-static int pas_mixer_ioctl __P((int dev, unsigned int cmd, unsigned int arg));
-static void set_mode __P((int new_mode));
+#include <i386/isa/sound/pas_hw.h>
#define TRACE(what) /* (what) */
extern int translat_code;
extern char pas_model;
+extern sound_os_info *pas_osp;
-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 | \
@@ -55,286 +52,271 @@ static int mode_control = 0;
SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_RECLEV | \
SOUND_MASK_MUTE | SOUND_MASK_ENHANCE | SOUND_MASK_LOUD)
-static unsigned short levels[SOUND_MIXER_NRDEVICES] =
+static u_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 */
};
void
-mix_write (unsigned char data, int ioaddr)
+mix_write(u_char data, int ioaddr)
{
- /*
- * The Revision D cards have a problem with their MVA508 interface. The
- * kludge-o-rama fix is to make a 16-bit quantity with identical LSB and
- * MSBs out of the output byte and to do a 16-bit out to the mixer port -
- * 1. We need to do this because it isn't timing problem but chip access
- * sequence problem.
- */
-
- if (pas_model == PAS_16D)
- {
- OUTW (data | (data << 8), (ioaddr ^ translat_code) - 1);
- OUTB (0x80, 0);
- }
- else
- pas_write (data, ioaddr);
+ /*
+ * The Revision D cards have a problem with their MVA508 interface.
+ * The kludge-o-rama fix is to make a 16-bit quantity with identical
+ * LSB and MSBs out of the output byte and to do a 16-bit out to the
+ * mixer port - 1. We need to do this because it isn't timing problem
+ * but chip access sequence problem.
+ */
+
+ if (pas_model == PAS_16D) {
+ outw((ioaddr ^ translat_code) - 1, data | (data << 8));
+ outb(0, 0x80);
+ } else
+ pas_write(data, ioaddr);
}
static int
-mixer_output (int right_vol, int left_vol, int div, int bits,
- int mixer) /* Input or output mixer */
-{
- int left = left_vol * div / 100;
- int right = right_vol * div / 100;
-
-
- if (bits & P_M_MV508_MIXER)
- { /*
- * Select input or output mixer
- */
- left |= mixer;
- right |= mixer;
- }
-
- if (bits == P_M_MV508_BASS || bits == P_M_MV508_TREBLE)
- { /*
- * Bass and treble are mono devices
- */
- mix_write (P_M_MV508_ADDRESS | bits, PARALLEL_MIXER);
- mix_write (left, PARALLEL_MIXER);
- right_vol = left_vol;
- }
- else
- {
- mix_write (P_M_MV508_ADDRESS | P_M_MV508_LEFT | bits, PARALLEL_MIXER);
- mix_write (left, PARALLEL_MIXER);
- mix_write (P_M_MV508_ADDRESS | P_M_MV508_RIGHT | bits, PARALLEL_MIXER);
- mix_write (right, PARALLEL_MIXER);
- }
-
- return (left_vol | (right_vol << 8));
+mixer_output(int right_vol, int left_vol, int div, int bits,
+ int mixer)
+{ /* Input or output mixer */
+ int left = left_vol * div / 100;
+ int right = right_vol * div / 100;
+
+
+ if (bits & P_M_MV508_MIXER) { /* Select input or output mixer */
+ left |= mixer;
+ right |= mixer;
+ }
+ if (bits == P_M_MV508_BASS || bits == P_M_MV508_TREBLE) { /* Bass and treble are
+ * mono devices */
+ mix_write(P_M_MV508_ADDRESS | bits, PARALLEL_MIXER);
+ mix_write(left, PARALLEL_MIXER);
+ right_vol = left_vol;
+ } else {
+ mix_write(P_M_MV508_ADDRESS | P_M_MV508_LEFT | bits, PARALLEL_MIXER);
+ mix_write(left, PARALLEL_MIXER);
+ mix_write(P_M_MV508_ADDRESS | P_M_MV508_RIGHT | bits, PARALLEL_MIXER);
+ mix_write(right, PARALLEL_MIXER);
+ }
+
+ return (left_vol | (right_vol << 8));
}
static void
-set_mode (int new_mode)
+set_mode(int new_mode)
{
- mix_write (P_M_MV508_ADDRESS | P_M_MV508_MODE, PARALLEL_MIXER);
- mix_write (new_mode, PARALLEL_MIXER);
+ mix_write(P_M_MV508_ADDRESS | P_M_MV508_MODE, PARALLEL_MIXER);
+ mix_write(new_mode, PARALLEL_MIXER);
- mode_control = new_mode;
+ mode_control = new_mode;
}
static int
-pas_mixer_set (int whichDev, unsigned int level)
+pas_mixer_set(int whichDev, u_int level)
{
- int left, right, devmask, changed, i, mixer = 0;
-
- TRACE (printk ("static int pas_mixer_set(int whichDev = %d, unsigned int level = %X)\n", whichDev, level));
-
- left = level & 0x7f;
- right = (level & 0x7f00) >> 8;
-
- if (whichDev < SOUND_MIXER_NRDEVICES)
- if ((1 << whichDev) & rec_devices)
- mixer = P_M_MV508_INPUTMIX;
- else
- mixer = P_M_MV508_OUTPUTMIX;
-
- switch (whichDev)
- {
- case SOUND_MIXER_VOLUME: /* Master volume (0-63) */
- levels[whichDev] = mixer_output (right, left, 63, P_M_MV508_MASTER_A, 0);
- break;
-
- /*
- * Note! Bass and Treble are mono devices. Will use just the left
- * channel.
- */
- 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) */
- levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_TREBLE, 0);
- break;
-
- 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) */
- 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) */
- 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) */
- 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) */
- levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_LINE, mixer);
- break;
- 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) */
- 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) (Output mixer only) */
- levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_IMIXER,
- P_M_MV508_OUTPUTMIX);
- break;
- case SOUND_MIXER_RECLEV: /* Recording level (0-15) */
- levels[whichDev] = mixer_output (right, left, 15, P_M_MV508_MASTER_B, 0);
- break;
-
- case SOUND_MIXER_MUTE:
- return 0;
- break;
-
- case SOUND_MIXER_ENHANCE:
- i = 0;
- level &= 0x7f;
- if (level)
- i = (level / 20) - 1;
-
- mode_control &= ~P_M_MV508_ENHANCE_BITS;
- mode_control |= P_M_MV508_ENHANCE_BITS;
- set_mode (mode_control);
-
- if (i)
- i = (i + 1) * 20;
- return i;
- break;
-
- case SOUND_MIXER_LOUD:
- mode_control &= ~P_M_MV508_LOUDNESS;
- if (level)
- mode_control |= P_M_MV508_LOUDNESS;
- set_mode (mode_control);
- return !!level; /* 0 or 1 */
- break;
-
- case SOUND_MIXER_RECSRC:
- devmask = level & POSSIBLE_RECORDING_DEVICES;
-
- changed = devmask ^ rec_devices;
- rec_devices = devmask;
-
- for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- if (changed & (1 << i))
- {
- pas_mixer_set (i, levels[i]);
- }
- return rec_devices;
- break;
-
- default:
- return RET_ERROR (EINVAL);
- }
-
- return (levels[whichDev]);
+ int left, right, devmask, changed, i, mixer = 0;
+
+ TRACE(printf("static int pas_mixer_set(int whichDev = %d, u_int level = %X)\n", whichDev, level));
+
+ left = level & 0x7f;
+ right = (level & 0x7f00) >> 8;
+
+ if (whichDev < SOUND_MIXER_NRDEVICES)
+ if ((1 << whichDev) & rec_devices)
+ mixer = P_M_MV508_INPUTMIX;
+ else
+ mixer = P_M_MV508_OUTPUTMIX;
+
+ switch (whichDev) {
+ case SOUND_MIXER_VOLUME: /* Master volume (0-63) */
+ levels[whichDev] = mixer_output(right, left, 63, P_M_MV508_MASTER_A, 0);
+ break;
+
+ /*
+ * Note! Bass and Treble are mono devices. Will use just the
+ * left channel.
+ */
+ 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) */
+ levels[whichDev] = mixer_output(right, left, 12, P_M_MV508_TREBLE, 0);
+ break;
+
+ 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) */
+ 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) */
+ 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) */
+ 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) */
+ levels[whichDev] = mixer_output(right, left, 31, P_M_MV508_MIXER | P_M_MV508_LINE, mixer);
+ break;
+ 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) */
+ 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) (Output mixer
+ * only) */
+ levels[whichDev] = mixer_output(right, left, 31, P_M_MV508_MIXER | P_M_MV508_IMIXER,
+ P_M_MV508_OUTPUTMIX);
+ break;
+ case SOUND_MIXER_RECLEV: /* Recording level (0-15) */
+ levels[whichDev] = mixer_output(right, left, 15, P_M_MV508_MASTER_B, 0);
+ break;
+
+ case SOUND_MIXER_MUTE:
+ return 0;
+ break;
+
+ case SOUND_MIXER_ENHANCE:
+ i = 0;
+ level &= 0x7f;
+ if (level)
+ i = (level / 20) - 1;
+
+ mode_control &= ~P_M_MV508_ENHANCE_BITS;
+ mode_control |= P_M_MV508_ENHANCE_BITS;
+ set_mode(mode_control);
+
+ if (i)
+ i = (i + 1) * 20;
+ return i;
+ break;
+
+ case SOUND_MIXER_LOUD:
+ mode_control &= ~P_M_MV508_LOUDNESS;
+ if (level)
+ mode_control |= P_M_MV508_LOUDNESS;
+ set_mode(mode_control);
+ return !!level; /* 0 or 1 */
+ break;
+
+ case SOUND_MIXER_RECSRC:
+ devmask = level & POSSIBLE_RECORDING_DEVICES;
+
+ changed = devmask ^ rec_devices;
+ rec_devices = devmask;
+
+ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+ if (changed & (1 << i)) {
+ pas_mixer_set(i, levels[i]);
+ }
+ return rec_devices;
+ break;
+
+ default:
+ return -(EINVAL);
+ }
+
+ return (levels[whichDev]);
}
/*****/
static void
-pas_mixer_reset (void)
+pas_mixer_reset(void)
{
- int foo;
+ int foo;
- TRACE (printk ("pas2_mixer.c: void pas_mixer_reset(void)\n"));
+ TRACE(printf("pas2_mixer.c: void pas_mixer_reset(void)\n"));
- for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++)
- pas_mixer_set (foo, levels[foo]);
+ for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++)
+ pas_mixer_set(foo, levels[foo]);
- set_mode (P_M_MV508_LOUDNESS | P_M_MV508_ENHANCE_40);
+ set_mode(P_M_MV508_LOUDNESS | P_M_MV508_ENHANCE_40);
}
int
-pas_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
+pas_mixer_ioctl(int dev, u_int cmd, ioctl_arg arg)
{
- TRACE (printk ("pas2_mixer.c: int pas_mixer_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));
-
- if (((cmd >> 8) & 0xff) == 'M')
- {
- if (cmd & IOC_IN)
- return IOCTL_OUT (arg, pas_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
- else
- { /*
- * Read parameters
- */
-
- switch (cmd & 0xff)
- {
-
- case SOUND_MIXER_RECSRC:
- return IOCTL_OUT (arg, rec_devices);
- break;
-
- case SOUND_MIXER_STEREODEVS:
- return IOCTL_OUT (arg, SUPPORTED_MIXER_DEVICES & ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE));
- break;
-
- case SOUND_MIXER_DEVMASK:
- return IOCTL_OUT (arg, SUPPORTED_MIXER_DEVICES);
- break;
-
- case SOUND_MIXER_RECMASK:
- return IOCTL_OUT (arg, POSSIBLE_RECORDING_DEVICES & SUPPORTED_MIXER_DEVICES);
- break;
-
- case SOUND_MIXER_CAPS:
- return IOCTL_OUT (arg, 0); /* No special capabilities */
- break;
-
- case SOUND_MIXER_MUTE:
- return IOCTL_OUT (arg, 0); /* No mute yet */
- break;
-
- case SOUND_MIXER_ENHANCE:
- if (!(mode_control & P_M_MV508_ENHANCE_BITS))
- return IOCTL_OUT (arg, 0);
- return IOCTL_OUT (arg, ((mode_control & P_M_MV508_ENHANCE_BITS) + 1) * 20);
- break;
-
- case SOUND_MIXER_LOUD:
- if (mode_control & P_M_MV508_LOUDNESS)
- return IOCTL_OUT (arg, 1);
- return IOCTL_OUT (arg, 0);
- break;
-
- default:
- return IOCTL_OUT (arg, levels[cmd & 0xff]);
- }
+ TRACE(printf("pas2_mixer.c: int pas_mixer_ioctl(u_int cmd = %X, u_int arg = %X)\n", cmd, arg));
+
+ if (((cmd >> 8) & 0xff) == 'M') {
+ if (cmd & IOC_IN)
+ return *(int *) arg = pas_mixer_set(cmd & 0xff, (*(int *) arg));
+ else { /* Read parameters */
+
+ switch (cmd & 0xff) {
+
+ case SOUND_MIXER_RECSRC:
+ return *(int *) arg = rec_devices;
+ break;
+
+ case SOUND_MIXER_STEREODEVS:
+ return *(int *) arg = SUPPORTED_MIXER_DEVICES & ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE);
+ break;
+
+ case SOUND_MIXER_DEVMASK:
+ return *(int *) arg = SUPPORTED_MIXER_DEVICES;
+ break;
+
+ case SOUND_MIXER_RECMASK:
+ return *(int *) arg = POSSIBLE_RECORDING_DEVICES & SUPPORTED_MIXER_DEVICES;
+ break;
+
+ case SOUND_MIXER_CAPS:
+ return *(int *) arg = 0; /* No special
+ * capabilities */
+ break;
+
+ case SOUND_MIXER_MUTE:
+ return *(int *) arg = 0; /* No mute yet */
+ break;
+
+ case SOUND_MIXER_ENHANCE:
+ if (!(mode_control & P_M_MV508_ENHANCE_BITS))
+ return *(int *) arg = 0;
+ return *(int *) arg = ((mode_control & P_M_MV508_ENHANCE_BITS) + 1) * 20;
+ break;
+
+ case SOUND_MIXER_LOUD:
+ if (mode_control & P_M_MV508_LOUDNESS)
+ return *(int *) arg = 1;
+ return *(int *) arg = 0;
+ break;
+
+ default:
+ return *(int *) arg = levels[cmd & 0xff];
+ }
+ }
}
- }
- return RET_ERROR (EINVAL);
+ return -(EINVAL);
}
static struct mixer_operations pas_mixer_operations =
{
- "Pro Audio Spectrum 16",
- pas_mixer_ioctl
+ "Pro Audio Spectrum 16",
+ pas_mixer_ioctl
};
int
-pas_init_mixer (void)
+pas_init_mixer(void)
{
- pas_mixer_reset ();
+ pas_mixer_reset();
- if (num_mixers < MAX_MIXER_DEV)
- mixer_devs[num_mixers++] = &pas_mixer_operations;
- return 1;
+ if (num_mixers < MAX_MIXER_DEV)
+ mixer_devs[num_mixers++] = &pas_mixer_operations;
+ return 1;
}
#endif
diff --git a/sys/i386/isa/sound/pas2_pcm.c b/sys/i386/isa/sound/pas2_pcm.c
index 385ab1d..fd4d5c0 100644
--- a/sys/i386/isa/sound/pas2_pcm.c
+++ b/sys/i386/isa/sound/pas2_pcm.c
@@ -1,11 +1,11 @@
#define _PAS2_PCM_C_
/*
* sound/pas2_pcm.c
- *
+ *
* The low level driver for the Pro Audio Spectrum ADC/DAC.
- *
+ *
* 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
@@ -13,7 +13,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -25,23 +25,16 @@
* 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 <i386/isa/sound/sound_config.h>
-#ifdef CONFIGURE_SOUNDCARD
+#if defined(CONFIG_PAS) && defined(CONFIG_AUDIO)
+#include <i386/isa/sound/pas_hw.h>
-#include <i386/isa/sound/pas_defs.h>
-static int pcm_set_bits __P((int arg));
-static int pcm_set_channels __P((int arg));
-static int pcm_set_speed __P((int arg));
-
-#if !defined(EXCLUDE_PAS) && !defined(EXCLUDE_AUDIO)
-
-#define TRACE(WHAT) /*
- * * * (WHAT) */
+#define TRACE(WHAT) /* * * (WHAT) */
#define PAS_PCM_INTRBITS (0x08)
/*
@@ -52,406 +45,405 @@ static int pcm_set_speed __P((int arg));
#define PCM_DAC 1
#define PCM_ADC 2
-static unsigned long pcm_speed = 0; /* sampling rate */
-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;
-static unsigned long pcm_count = 0;
-static unsigned short pcm_bitsok = 8; /* mask of OK bits */
+static u_long pcm_speed = 0; /* sampling rate */
+static u_char pcm_channels = 1; /* channels (1 or 2) */
+static u_char pcm_bits = 8; /* bits/sample (8 or 16) */
+static u_char pcm_filter = 0; /* filter FLAG */
+static u_char pcm_mode = PCM_NON;
+static u_long pcm_count = 0;
+static u_short pcm_bitsok = 8; /* mask of OK bits */
static int my_devnum = 0;
+static int open_mode = 0;
-static int
-pcm_set_speed (int arg)
+int
+pcm_set_speed(int arg)
{
- int foo, tmp;
- unsigned long flags;
+ int foo, tmp;
+ u_long flags;
- if (arg > 44100)
- arg = 44100;
- if (arg < 5000)
- arg = 5000;
+ if (arg > 44100)
+ arg = 44100;
+ if (arg < 5000)
+ arg = 5000;
- foo = (1193180 + (arg / 2)) / arg;
- arg = 1193180 / foo;
+ foo = (1193180 + (arg / 2)) / arg;
+ arg = 1193180 / foo;
- if (pcm_channels & 2)
- foo = foo >> 1;
+ if (pcm_channels & 2)
+ foo = foo >> 1;
- pcm_speed = arg;
+ pcm_speed = arg;
- tmp = pas_read (FILTER_FREQUENCY);
+ 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/.
- */
+ /*
+ * 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;
+ 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);
+ flags = splhigh();
- pas_write (tmp & ~(F_F_PCM_RATE_COUNTER | F_F_PCM_BUFFER_COUNTER), FILTER_FREQUENCY);
- pas_write (S_C_C_SAMPLE_RATE | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);
- pas_write (foo & 0xff, SAMPLE_RATE_TIMER);
- pas_write ((foo >> 8) & 0xff, SAMPLE_RATE_TIMER);
- pas_write (tmp, FILTER_FREQUENCY);
+ pas_write(tmp & ~(F_F_PCM_RATE_COUNTER | F_F_PCM_BUFFER_COUNTER), FILTER_FREQUENCY);
+ pas_write(S_C_C_SAMPLE_RATE | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);
+ pas_write(foo & 0xff, SAMPLE_RATE_TIMER);
+ pas_write((foo >> 8) & 0xff, SAMPLE_RATE_TIMER);
+ pas_write(tmp, FILTER_FREQUENCY);
- RESTORE_INTR (flags);
+ splx(flags);
- return pcm_speed;
+ return pcm_speed;
}
-static int
-pcm_set_channels (int arg)
+int
+pcm_set_channels(int arg)
{
- if ((arg != 1) && (arg != 2))
- return pcm_channels;
-
- if (arg != pcm_channels)
- {
- pas_write (pas_read (PCM_CONTROL) ^ P_C_PCM_MONO, PCM_CONTROL);
+ if ((arg != 1) && (arg != 2))
+ return pcm_channels;
- pcm_channels = arg;
- pcm_set_speed (pcm_speed); /*
- * The speed must be reinitialized
- */
- }
+ if (arg != pcm_channels) {
+ pas_write(pas_read(PCM_CONTROL) ^ P_C_PCM_MONO, PCM_CONTROL);
- return pcm_channels;
+ pcm_channels = arg;
+ pcm_set_speed(pcm_speed); /* The speed must be
+ * reinitialized */
+ }
+ return pcm_channels;
}
-static int
-pcm_set_bits (int arg)
+int
+pcm_set_bits(int arg)
{
- if ((arg & pcm_bitsok) != arg)
- return pcm_bits;
+ if ((arg & pcm_bitsok) != arg)
+ return pcm_bits;
- if (arg != pcm_bits)
- {
- pas_write (pas_read (SYSTEM_CONFIGURATION_2) ^ S_C_2_PCM_16_BIT, SYSTEM_CONFIGURATION_2);
+ if (arg != pcm_bits) {
+ pas_write(pas_read(SYSTEM_CONFIGURATION_2) ^ S_C_2_PCM_16_BIT, SYSTEM_CONFIGURATION_2);
- pcm_bits = arg;
- }
-
- return pcm_bits;
+ pcm_bits = arg;
+ }
+ return pcm_bits;
}
static int
-pas_pcm_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
+pas_pcm_ioctl(int dev, u_int cmd, ioctl_arg arg, int local)
{
- TRACE (printk ("pas2_pcm.c: static int pas_pcm_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));
-
- switch (cmd)
- {
- case SOUND_PCM_WRITE_RATE:
- if (local)
- return pcm_set_speed (arg);
- return IOCTL_OUT (arg, pcm_set_speed (IOCTL_IN (arg)));
- break;
-
- case SOUND_PCM_READ_RATE:
- if (local)
- return pcm_speed;
- return IOCTL_OUT (arg, pcm_speed);
- break;
-
- case SNDCTL_DSP_STEREO:
- if (local)
- return pcm_set_channels (arg + 1) - 1;
- return IOCTL_OUT (arg, pcm_set_channels (IOCTL_IN (arg) + 1) - 1);
- break;
-
- case SOUND_PCM_WRITE_CHANNELS:
- if (local)
- return pcm_set_channels (arg);
- return IOCTL_OUT (arg, pcm_set_channels (IOCTL_IN (arg)));
- break;
-
- case SOUND_PCM_READ_CHANNELS:
- if (local)
- return pcm_channels;
- return IOCTL_OUT (arg, pcm_channels);
- break;
-
- case SNDCTL_DSP_SETFMT:
- if (local)
- return pcm_set_bits (arg);
- return IOCTL_OUT (arg, pcm_set_bits (IOCTL_IN (arg)));
- break;
-
- case SOUND_PCM_READ_BITS:
- if (local)
- return pcm_bits;
- return IOCTL_OUT (arg, pcm_bits);
-
- case SOUND_PCM_WRITE_FILTER: /*
- * NOT YET IMPLEMENTED
- */
- if (IOCTL_IN (arg) > 1)
- return IOCTL_OUT (arg, RET_ERROR (EINVAL));
- break;
-
- pcm_filter = IOCTL_IN (arg);
- case SOUND_PCM_READ_FILTER:
- return IOCTL_OUT (arg, pcm_filter);
- break;
+ TRACE(printf("pas2_pcm.c: static int pas_pcm_ioctl(u_int cmd = %X, u_int arg = %X)\n", cmd, arg));
+
+ switch (cmd) {
+ case SOUND_PCM_WRITE_RATE:
+ if (local)
+ return pcm_set_speed((int) arg);
+ return *(int *) arg = pcm_set_speed((*(int *) arg));
+ break;
+
+ case SOUND_PCM_READ_RATE:
+ if (local)
+ return pcm_speed;
+ return *(int *) arg = pcm_speed;
+ break;
+
+ case SNDCTL_DSP_STEREO:
+ if (local)
+ return pcm_set_channels((int) arg + 1) - 1;
+ return *(int *) arg = pcm_set_channels((*(int *) arg) + 1) - 1;
+ break;
+
+ case SOUND_PCM_WRITE_CHANNELS:
+ if (local)
+ return pcm_set_channels((int) arg);
+ return *(int *) arg = pcm_set_channels((*(int *) arg));
+ break;
+
+ case SOUND_PCM_READ_CHANNELS:
+ if (local)
+ return pcm_channels;
+ return *(int *) arg = pcm_channels;
+ break;
+
+ case SNDCTL_DSP_SETFMT:
+ if (local)
+ return pcm_set_bits((int) arg);
+ return *(int *) arg = pcm_set_bits((*(int *) arg));
+ break;
+
+ case SOUND_PCM_READ_BITS:
+ if (local)
+ return pcm_bits;
+ return *(int *) arg = pcm_bits;
+
+ case SOUND_PCM_WRITE_FILTER: /* NOT YET IMPLEMENTED */
+ if ((*(int *) arg) > 1)
+ return -(EINVAL);
+ pcm_filter = (*(int *) arg);
+ break;
+
+ case SOUND_PCM_READ_FILTER:
+ return *(int *) arg = pcm_filter;
+ break;
- default:
- return RET_ERROR (EINVAL);
- }
+ default:
+ return -(EINVAL);
+ }
- return RET_ERROR (EINVAL);
+ return -(EINVAL);
}
static void
-pas_pcm_reset (int dev)
+pas_pcm_reset(int dev)
{
- TRACE (printk ("pas2_pcm.c: static void pas_pcm_reset(void)\n"));
+ TRACE(printf("pas2_pcm.c: static void pas_pcm_reset(void)\n"));
- pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE, PCM_CONTROL);
+ pas_write(pas_read(PCM_CONTROL) & ~P_C_PCM_ENABLE, PCM_CONTROL);
}
static int
-pas_pcm_open (int dev, int mode)
+pas_pcm_open(int dev, int mode)
{
- int err;
+ int err;
- TRACE (printk ("pas2_pcm.c: static int pas_pcm_open(int mode = %X)\n", mode));
+ TRACE(printf("pas2_pcm.c: static int pas_pcm_open(int mode = %X)\n", mode));
- if ((err = pas_set_intr (PAS_PCM_INTRBITS)) < 0)
- return err;
+ if ((err = pas_set_intr(PAS_PCM_INTRBITS)) < 0)
+ return err;
- if (DMAbuf_open_dma (dev) < 0)
- {
- pas_remove_intr (PAS_PCM_INTRBITS);
- return RET_ERROR (EBUSY);
- }
- pcm_count = 0;
+ pcm_count = 0;
+ open_mode = mode;
- return 0;
+ return 0;
}
static void
-pas_pcm_close (int dev)
+pas_pcm_close(int dev)
{
- unsigned long flags;
+ u_long flags;
- TRACE (printk ("pas2_pcm.c: static void pas_pcm_close(void)\n"));
+ TRACE(printf("pas2_pcm.c: static void pas_pcm_close(void)\n"));
- DISABLE_INTR (flags);
+ flags = splhigh();
- pas_pcm_reset (dev);
- DMAbuf_close_dma (dev);
- pas_remove_intr (PAS_PCM_INTRBITS);
- pcm_mode = PCM_NON;
+ pas_pcm_reset(dev);
+ pas_remove_intr(PAS_PCM_INTRBITS);
+ pcm_mode = PCM_NON;
- RESTORE_INTR (flags);
+ open_mode = 0;
+
+ splx(flags);
}
static void
-pas_pcm_output_block (int dev, unsigned long buf, int count,
- int intrflag, int restart_dma)
+pas_pcm_output_block(int dev, u_long buf, int count,
+ int intrflag, int restart_dma)
{
- unsigned long flags, cnt;
+ u_long flags, cnt;
- TRACE (printk ("pas2_pcm.c: static void pas_pcm_output_block(char *buf = %P, int count = %X)\n", buf, count));
+ TRACE(printf("pas2_pcm.c: static void pas_pcm_output_block(char *buf = %P, int count = %X)\n", buf, count));
- cnt = count;
- if (audio_devs[dev]->dmachan > 3)
- cnt >>= 1;
+ cnt = count;
+ if (audio_devs[dev]->dmachan1 > 3)
+ cnt >>= 1;
- if (audio_devs[dev]->flags & DMA_AUTOMODE &&
- intrflag &&
- cnt == pcm_count)
- return; /*
- * Auto mode on. No need to react
- */
+ if (audio_devs[dev]->flags & DMA_AUTOMODE &&
+ intrflag &&
+ cnt == pcm_count)
+ return; /* Auto mode on. No need to react */
- DISABLE_INTR (flags);
+ flags = splhigh();
- pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE,
- PCM_CONTROL);
+ pas_write(pas_read(PCM_CONTROL) & ~P_C_PCM_ENABLE,
+ PCM_CONTROL);
- if (restart_dma)
- DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
+ if (restart_dma)
+ DMAbuf_start_dma(dev, buf, count, 1);
- if (audio_devs[dev]->dmachan > 3)
- count >>= 1;
+ if (audio_devs[dev]->dmachan1 > 3)
+ count >>= 1;
- if (count != pcm_count)
- {
- pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
- pas_write (S_C_C_SAMPLE_BUFFER | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);
- pas_write (count & 0xff, SAMPLE_BUFFER_COUNTER);
- pas_write ((count >> 8) & 0xff, SAMPLE_BUFFER_COUNTER);
- pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
+ if (count != pcm_count) {
+ pas_write(pas_read(FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
+ pas_write(S_C_C_SAMPLE_BUFFER | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);
+ pas_write(count & 0xff, SAMPLE_BUFFER_COUNTER);
+ pas_write((count >> 8) & 0xff, SAMPLE_BUFFER_COUNTER);
+ pas_write(pas_read(FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
- pcm_count = count;
- }
- pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY);
- pas_write (pas_read (PCM_CONTROL) | P_C_PCM_ENABLE | P_C_PCM_DAC_MODE, PCM_CONTROL);
+ pcm_count = count;
+ }
+ pas_write(pas_read(FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY);
+#ifdef NO_TRIGGER
+ pas_write(pas_read(PCM_CONTROL) | P_C_PCM_ENABLE | P_C_PCM_DAC_MODE, PCM_CONTROL);
+#endif
- pcm_mode = PCM_DAC;
+ pcm_mode = PCM_DAC;
- RESTORE_INTR (flags);
+ splx(flags);
}
static void
-pas_pcm_start_input (int dev, unsigned long buf, int count,
- int intrflag, int restart_dma)
+pas_pcm_start_input(int dev, u_long buf, int count,
+ int intrflag, int restart_dma)
{
- unsigned long flags;
- int cnt;
+ u_long flags;
+ int cnt;
+
+ TRACE(printf("pas2_pcm.c: static void pas_pcm_start_input(char *buf = %P, int count = %X)\n", buf, count));
- TRACE (printk ("pas2_pcm.c: static void pas_pcm_start_input(char *buf = %P, int count = %X)\n", buf, count));
+ cnt = count;
+ if (audio_devs[dev]->dmachan1 > 3)
+ cnt >>= 1;
- cnt = count;
- if (audio_devs[dev]->dmachan > 3)
- cnt >>= 1;
+ if (audio_devs[my_devnum]->flags & DMA_AUTOMODE &&
+ intrflag &&
+ cnt == pcm_count)
+ return; /* Auto mode on. No need to react */
- if (audio_devs[my_devnum]->flags & DMA_AUTOMODE &&
- intrflag &&
- cnt == pcm_count)
- return; /*
- * Auto mode on. No need to react
- */
+ flags = splhigh();
- DISABLE_INTR (flags);
+ if (restart_dma)
+ DMAbuf_start_dma(dev, buf, count, 0);
- if (restart_dma)
- DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
+ if (audio_devs[dev]->dmachan1 > 3)
+ count >>= 1;
- if (audio_devs[dev]->dmachan > 3)
- count >>= 1;
+ if (count != pcm_count) {
+ pas_write(pas_read(FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
+ pas_write(S_C_C_SAMPLE_BUFFER | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);
+ pas_write(count & 0xff, SAMPLE_BUFFER_COUNTER);
+ pas_write((count >> 8) & 0xff, SAMPLE_BUFFER_COUNTER);
+ pas_write(pas_read(FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
+
+ pcm_count = count;
+ }
+ pas_write(pas_read(FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY);
+#ifdef NO_TRIGGER
+ pas_write((pas_read(PCM_CONTROL) | P_C_PCM_ENABLE) & ~P_C_PCM_DAC_MODE, PCM_CONTROL);
+#endif
+
+ pcm_mode = PCM_ADC;
+
+ splx(flags);
+}
+#ifndef NO_TRIGGER
+static void
+pas_audio_trigger (int dev, int state)
+{
+ unsigned long flags;
- if (count != pcm_count)
- {
- pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
- pas_write (S_C_C_SAMPLE_BUFFER | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);
- pas_write (count & 0xff, SAMPLE_BUFFER_COUNTER);
- pas_write ((count >> 8) & 0xff, SAMPLE_BUFFER_COUNTER);
- pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
+ flags = splhigh();
- pcm_count = count;
- }
- pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY);
- pas_write ((pas_read (PCM_CONTROL) | P_C_PCM_ENABLE) & ~P_C_PCM_DAC_MODE, PCM_CONTROL);
+ state &= open_mode;
- pcm_mode = PCM_ADC;
+ if (state & PCM_ENABLE_OUTPUT)
+ pas_write (pas_read (0xF8A) | 0x40 | 0x10, 0xF8A);
+ else if (state & PCM_ENABLE_INPUT)
+ pas_write ((pas_read (0xF8A) | 0x40) & ~0x10, 0xF8A);
+ else
+ pas_write (pas_read (0xF8A) & ~0x40, 0xF8A);
- RESTORE_INTR (flags);
+ splx(flags);
}
+#endif
static int
-pas_pcm_prepare_for_input (int dev, int bsize, int bcount)
+pas_pcm_prepare_for_input(int dev, int bsize, int bcount)
{
- return 0;
+ return 0;
}
static int
-pas_pcm_prepare_for_output (int dev, int bsize, int bcount)
+pas_pcm_prepare_for_output(int dev, int bsize, int bcount)
{
- return 0;
+ return 0;
}
static struct audio_operations pas_pcm_operations =
{
- "Pro Audio Spectrum",
- DMA_AUTOMODE,
- AFMT_U8 | AFMT_S16_LE,
- NULL,
- pas_pcm_open,
- pas_pcm_close,
- pas_pcm_output_block,
- pas_pcm_start_input,
- pas_pcm_ioctl,
- pas_pcm_prepare_for_input,
- pas_pcm_prepare_for_output,
- pas_pcm_reset,
- pas_pcm_reset,
- NULL,
- NULL
+ "Pro Audio Spectrum",
+ DMA_AUTOMODE,
+ AFMT_U8 | AFMT_S16_LE,
+ NULL,
+ pas_pcm_open,
+ pas_pcm_close,
+ pas_pcm_output_block,
+ pas_pcm_start_input,
+ pas_pcm_ioctl,
+ pas_pcm_prepare_for_input,
+ pas_pcm_prepare_for_output,
+ pas_pcm_reset,
+ pas_pcm_reset,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ pas_audio_trigger
};
-long
-pas_pcm_init (long mem_start, struct address_info *hw_config)
+void
+pas_pcm_init(struct address_info * hw_config)
{
- TRACE (printk ("pas2_pcm.c: long pas_pcm_init(long mem_start = %X)\n", mem_start));
+ pcm_bitsok = 8;
+ if (pas_read(OPERATION_MODE_1) & O_M_1_PCM_TYPE)
+ pcm_bitsok |= 16;
- pcm_bitsok = 8;
- if (pas_read (OPERATION_MODE_1) & O_M_1_PCM_TYPE)
- pcm_bitsok |= 16;
+ pcm_set_speed(DSP_DEFAULT_SPEED);
- pcm_set_speed (DSP_DEFAULT_SPEED);
+ if (num_audiodevs < MAX_AUDIO_DEV) {
+ audio_devs[my_devnum = num_audiodevs++] = &pas_pcm_operations;
+ audio_devs[my_devnum]->dmachan1 = hw_config->dma;
+ audio_devs[my_devnum]->buffsize = DSP_BUFFSIZE;
+ } else
+ printf("PAS2: Too many PCM devices available\n");
- if (num_audiodevs < MAX_AUDIO_DEV)
- {
- 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 = DSP_BUFFSIZE;
- }
- else
- printk ("PAS2: Too many PCM devices available\n");
-
- return mem_start;
+ return;
}
void
-pas_pcm_interrupt (unsigned char status, int cause)
+pas_pcm_interrupt(u_char status, int cause)
{
- 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 (!(audio_devs[my_devnum]->flags & DMA_AUTOMODE))
- {
- pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE,
- PCM_CONTROL);
+ 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 (!(audio_devs[my_devnum]->flags & DMA_AUTOMODE)) {
+ pas_write(pas_read(PCM_CONTROL) & ~P_C_PCM_ENABLE,
+ PCM_CONTROL);
+ }
+ switch (pcm_mode) {
+
+ case PCM_DAC:
+ DMAbuf_outputintr(my_devnum, 1);
+ break;
+
+ case PCM_ADC:
+ DMAbuf_inputintr(my_devnum);
+ break;
+
+ default:
+ printf("PAS: Unexpected PCM interrupt\n");
+ }
}
-
- switch (pcm_mode)
- {
-
- case PCM_DAC:
- DMAbuf_outputintr (my_devnum, 1);
- break;
-
- case PCM_ADC:
- DMAbuf_inputintr (my_devnum);
- break;
-
- default:
- printk ("PAS: Unexpected PCM interrupt\n");
- }
- }
}
#endif
-
-#endif
diff --git a/sys/i386/isa/sound/pas_hw.h b/sys/i386/isa/sound/pas_hw.h
new file mode 100644
index 0000000..5f82328
--- /dev/null
+++ b/sys/i386/isa/sound/pas_hw.h
@@ -0,0 +1,236 @@
+/* */
+/* Port addresses and bit fields for the Media Vision Pro AudioSpectrum second generation sound cards. */
+/* */
+/* Feel free to use this header file in any application you create that has support for the Media Vision */
+/* Pro AudioSpectrum second generation sound cards. Other uses prohibited without prior permission. */
+/* */
+/* - cmetz@thor.tjhsst.edu */
+/* */
+/* Notes: */
+/* */
+/* * All of these ports go into the MVD101 multimedia controller chip, which then signals the other chips to do */
+/* the actual work. Many ports like the FM ones functionally attach directly to the destination chip though */
+/* they don't actually have a direct connection. */
+/* */
+/* * The PAS2 series cards have an MVD101 multimedia controller chip, the original PAS cards don't. The original */
+/* PAS cards are pretty defunct now, so no attempt is made here to support them. */
+/* */
+/* * The PAS2 series cards are all really different at the hardware level, though the MVD101 hides some of the */
+/* incompatibilities, there still are differences that need to be accounted for. */
+/* */
+/* Card CD-ROM interface PCM chip Mixer chip FM chip */
+/* PAS Plus Sony proprietary (Crystal?) 8-bit DAC National OPL3 */
+/* PAS 16 Zilog SCSI MVA416 16-bit Codec MVA508 OPL3 */
+/* CDPC Sony proprietary Sony 16-bit Codec National OPL3 */
+/* Fusion CD 16 Sony proprietary MVA416 16-bit Codec MVA508 OPL3 */
+/* Fusion CD Sony proprietary (Crystal?) 8-bit DAC National OPL3 */
+/* */
+#define PAS_DEFAULT_BASE 0x388
+
+/* Symbolic Name Value R W Subsystem Description */
+#define SPEAKER_CONTROL 0x61 /* W PC speaker Control register */
+#define SPEAKER_CONTROL_GHOST 0x738B /* R W PC speaker Control ghost register */
+#define SPEAKER_TIMER_CONTROL 0x43 /* W PC speaker Timer control register */
+#define SPEAKER_TIMER_CONTROL_GHOST 0x778B /* R W PC speaker Timer control register ghost */
+#define SPEAKER_TIMER_DATA 0x42 /* W PC speaker Timer data register */
+#define SPEAKER_TIMER_DATA_GHOST 0x138A /* R W PC speaker Timer data register ghost */
+
+#define WARM_BOOT 0x41 /* W Control Used to detect system warm boot */
+#define WARM_BOOT_GHOST 0x7789 /* ? W Control Use to get the card to fake warm boot */
+#define MASTER_DECODE 0x9A01 /* W Control Address >> 2 of card base address */
+#define PRESCALE_DIVIDER 0xBF8A /* R W PCM Ration between Codec clock and master clock */
+#define WAIT_STATE 0xBF88 /* R W Control Four-bit bus wait-state count (~140ns ea.) */
+#define BOARD_REV_ID 0x2789 /* R Control Extended Board Revision ID */
+
+#define CHIP_REV 0xFF88 /* R 0=PAS, 1=PAS+, 2=CDPC, 3=PAS16C, 4=PAS16D */
+
+#define SYSTEM_CONFIGURATION_1 0x8388 /* R W Control */
+# define S_C_1_PCS_ENABLE 0x01 /* R W PC speaker 1=enable, 0=disable PC speaker emulation */
+# define S_C_1_PCM_CLOCK_SELECT 0x02 /* R W PCM 1=14.31818Mhz/12, 0=28.224Mhz master clock */
+# define S_C_1_FM_EMULATE_CLOCK 0x04 /* R W FM 1=use 28.224Mhz/2, 0=use 14.31818Mhz clock */
+# define S_C_1_PCS_STEREO 0x10 /* R W PC speaker 1=enable PC speaker stereo effect, 0=disable */
+# define S_C_1_PCS_REALSOUND 0x20 /* R W PC speaker 1=enable RealSound enhancement, 0=disable */
+# define S_C_1_FORCE_EXT_RESET 0x40 /* R W Control Force external reset */
+# define S_C_1_FORCE_INT_RESET 0x80 /* R W Control Force internal reset */
+#define SYSTEM_CONFIGURATION_2 0x8389 /* R W Control */
+# define S_C_2_PCM_OVERSAMPLING 0x03 /* R W PCM 00=0x, 01=2x, 10=4x, 11=reserved */
+# define S_C_2_PCM_16_BIT 0x04 /* R W PCM 1=16-bit, 0=8-bit samples */
+#define SYSTEM_CONFIGURATION_3 0x838A /* R W Control */
+# define S_C_3_PCM_CLOCK_SELECT 0x02 /* R W PCM 1=use 1.008Mhz clock for PCM, 0=don't */
+#define SYSTEM_CONFIGURATION_4 0x838B /* R W Control CD-ROM interface controls */
+
+#define IO_CONFIGURATION_1 0xF388 /* R W Control */
+# define I_C_1_BOOT_RESET_ENABLE 0x80 /* R W Control 1=reset board on warm boot, 0=don't */
+# define I_C_1_JOYSTICK_ENABLE 0x40 /* R W Control 1=enable joystick port, 0=don't */
+#define IO_CONFIGURATION_2 0xF389 /* R W Control */
+# define I_C_2_PCM_DMA_DISABLED 0x00 /* R W PCM PCM DMA disabled */
+#define IO_CONFIGURATION_3 0xF38A /* R W Control */
+# define I_C_3_PCM_IRQ_DISABLED 0x00 /* R W PCM PCM IRQ disabled */
+
+#define COMPATIBILITY_ENABLE 0xF788 /* R W Control */
+# define C_E_MPU401_ENABLE 0x01 /* R W MIDI 1=enable, 0=disable MPU401 MIDI emulation */
+# define C_E_SB_ENABLE 0x02 /* R W PCM 1=enable, 0=disable Sound Blaster emulation */
+# define C_E_SB_ACTIVE 0x04 /* R PCM "Sound Blaster Interrupt active" */
+# define C_E_MPU401_ACTIVE 0x08 /* R MIDI "MPU UART mode active" */
+# define C_E_PCM_COMPRESSION 0x10 /* R W PCM 1=enable, 0=disabled compression */
+#define EMULATION_ADDRESS 0xF789 /* R W Control */
+# define E_A_SB_BASE 0x0f /* R W PCM bits A4-A7 for SB base port */
+# define E_A_MPU401_BASE 0xf0 /* R W MIDI bits A4-A7 for MPU401 base port */
+#define EMULATION_CONFIGURATION 0xFB8A /* R W ***** Only valid on newer PAS2 cards (?) ***** */
+# define E_C_MPU401_IRQ 0x07 /* R W MIDI MPU401 emulation IRQ */
+# define E_C_SB_IRQ 0x38 /* R W PCM SB emulation IRQ */
+# define E_C_SB_DMA 0xC0 /* R W PCM SB emulation DMA */
+
+#define OPERATION_MODE_1 0xEF8B /* R Control */
+# define O_M_1_CDROM_TYPE 0x03 /* R CD-ROM 3=SCSI, 2=Sony, 0=no CD-ROM interface */
+# define O_M_1_FM_TYPE 0x04 /* R FM 1=sterero, 0=mono FM chip */
+# define O_M_1_PCM_TYPE 0x08 /* R PCM 1=16-bit Codec, 0=8-bit DAC */
+#define OPERATION_MODE_2 0xFF8B /* R Control */
+# define O_M_2_PCS_ENABLED 0x02 /* R PC speaker PC speaker emulation 1=enabled, 0=disabled */
+# define O_M_2_BUS_TIMING 0x10 /* R Control 1=AT bus timing, 0=XT bus timing */
+# define O_M_2_BOARD_REVISION 0xe0 /* R Control Board revision */
+
+#define INTERRUPT_MASK 0x0B8B /* R W Control */
+# define I_M_FM_LEFT_IRQ_ENABLE 0x01 /* R W FM Enable FM left interrupt */
+# define I_M_FM_RIGHT_IRQ_ENABLE 0x02 /* R W FM Enable FM right interrupt */
+# define I_M_PCM_RATE_IRQ_ENABLE 0x04 /* R W PCM Enable Sample Rate interrupt */
+# define I_M_PCM_BUFFER_IRQ_ENABLE 0x08 /* R W PCM Enable Sample Buffer interrupt */
+# define I_M_MIDI_IRQ_ENABLE 0x10 /* R W MIDI Enable MIDI interrupt */
+# define I_M_BOARD_REV 0xE0 /* R Control Board revision */
+
+#define INTERRUPT_STATUS 0x0B89 /* R W Control */
+# define I_S_FM_LEFT_IRQ 0x01 /* R W FM Left FM Interrupt Pending */
+# define I_S_FM_RIGHT_IRQ 0x02 /* R W FM Right FM Interrupt Pending */
+# define I_S_PCM_SAMPLE_RATE_IRQ 0x04 /* R W PCM Sample Rate Interrupt Pending */
+# define I_S_PCM_SAMPLE_BUFFER_IRQ 0x08 /* R W PCM Sample Buffer Interrupt Pending */
+# define I_S_MIDI_IRQ 0x10 /* R W MIDI MIDI Interrupt Pending */
+# define I_S_PCM_CHANNEL 0x20 /* R W PCM 1=right, 0=left */
+# define I_S_RESET_ACTIVE 0x40 /* R W Control Reset is active (Timed pulse not finished) */
+# define I_S_PCM_CLIPPING 0x80 /* R W PCM Clipping has occurred */
+
+#define FILTER_FREQUENCY 0x0B8A /* R W Control */
+# define F_F_FILTER_DISABLED 0x00 /* R W Mixer No filter */
+# define F_F_MIXER_UNMUTE 0x20 /* R W Mixer 1=disable, 0=enable board mute */
+# define F_F_PCM_RATE_COUNTER 0x40 /* R W PCM 1=enable, 0=disable sample rate counter */
+# define F_F_PCM_BUFFER_COUNTER 0x80 /* R W PCM 1=enable, 0=disable sample buffer counter */
+
+#define PAS_NONE 0
+#define PAS_PLUS 1
+#define PAS_CDPC 2
+#define PAS_16 3
+#define PAS_16D 4
+
+#ifdef DEFINE_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 };
+ 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 };
+ unsigned char E_C_MPU401_IRQ_translate[] = /* R W MIDI MPU401 emulation IRQ value translation */
+ { 0x00, 0x00, 0x01, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x01, 0x05, 0x06, 0x07 };
+ unsigned char E_C_SB_IRQ_translate[] = /* R W PCM SB emulation IRQ translate */
+ { 0x00, 0x00, 0x08, 0x10, 0x00, 0x18, 0x00, 0x20, 0x00, 0x08, 0x28, 0x30, 0x38, 0, 0 };
+ unsigned char E_C_SB_DMA_translate[] = /* R W PCM SB emulation DMA translate */
+ { 0x00, 0x40, 0x80, 0xC0, 0, 0, 0, 0 };
+ unsigned char O_M_1_to_card[] = /* R W Control Translate (OM1 & 0x0f) to card type */
+ { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 4, 0, 2, 3 };
+#else
+ extern unsigned char I_C_2_PCM_DMA_translate[]; /* R W PCM PCM DMA channel value translations */
+ extern unsigned char I_C_3_PCM_IRQ_translate[]; /* R W PCM PCM IRQ level value translation */
+ 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?? */
+# define P_M_MV508_ADDRESS 0x80 /* W Mixer MVD508 Address/mixer select */
+# define P_M_MV508_DATA 0x00
+# define P_M_MV508_LEFT 0x20 /* W Mixer MVD508 Left channel select */
+# define P_M_MV508_RIGHT 0x40 /* W Mixer MVD508 Right channel select */
+# define P_M_MV508_BOTH 0x00 /* W Mixer MVD508 Both channel select */
+# define P_M_MV508_MIXER 0x10 /* W Mixer MVD508 Select a mixer (rather than a volume) */
+# define P_M_MV508_VOLUME 0x00
+
+# define P_M_MV508_INPUTMIX 0x20 /* W Mixer MVD508 Select mixer A */
+# define P_M_MV508_OUTPUTMIX 0x00 /* W Mixer MVD508 Select mixer B */
+
+# define P_M_MV508_MASTER_A 0x01 /* W Mixer MVD508 Master volume control A (output) */
+# define P_M_MV508_MASTER_B 0x02 /* W Mixer MVD508 Master volume control B (DSP input) */
+# define P_M_MV508_BASS 0x03 /* W Mixer MVD508 Bass control */
+# define P_M_MV508_TREBLE 0x04 /* W Mixer MVD508 Treble control */
+# define P_M_MV508_MODE 0x05 /* W Mixer MVD508 Master mode control */
+
+# define P_M_MV508_LOUDNESS 0x04 /* W Mixer MVD508 Mode control - Loudness filter */
+# define P_M_MV508_ENHANCE_BITS 0x03
+# define P_M_MV508_ENHANCE_NONE 0x00 /* W Mixer MVD508 Mode control - No stereo enhancement */
+# define P_M_MV508_ENHANCE_40 0x01 /* W Mixer MVD508 Mode control - 40% stereo enhancement */
+# define P_M_MV508_ENHANCE_60 0x02 /* W Mixer MVD508 Mode control - 60% stereo enhancement */
+# define P_M_MV508_ENHANCE_80 0x03 /* W Mixer MVD508 Mode control - 80% stereo enhancement */
+
+# define P_M_MV508_FM 0x00 /* W Mixer MVD508 Channel 0 - FM */
+# define P_M_MV508_IMIXER 0x01 /* W Mixer MVD508 Channel 1 - Input mixer (rec monitor) */
+# define P_M_MV508_LINE 0x02 /* W Mixer MVD508 Channel 2 - Line in */
+# define P_M_MV508_CDROM 0x03 /* W Mixer MVD508 Channel 3 - CD-ROM */
+# define P_M_MV508_MIC 0x04 /* W Mixer MVD508 Channel 4 - Microphone */
+# define P_M_MV508_PCM 0x05 /* W Mixer MVD508 Channel 5 - PCM */
+# define P_M_MV508_SPEAKER 0x06 /* W Mixer MVD508 Channel 6 - PC Speaker */
+# define P_M_MV508_SB 0x07 /* W Mixer MVD508 Channel 7 - SB DSP */
+
+#define SERIAL_MIXER 0xB88 /* R W Control Serial mixer control (used other ways) */
+# define S_M_PCM_RESET 0x01 /* R W PCM Codec/DSP reset */
+# define S_M_FM_RESET 0x02 /* R W FM FM chip reset */
+# define S_M_SB_RESET 0x04 /* R W PCM SB emulation chip reset */
+# define S_M_MIXER_RESET 0x10 /* R W Mixer Mixer chip reset */
+# define S_M_INTEGRATOR_ENABLE 0x40 /* R W Speaker Enable PC speaker integrator (FORCE RealSound) */
+# define S_M_OPL3_DUAL_MONO 0x80 /* R W FM Set the OPL-3 to dual mono mode */
+
+#define PCM_CONTROL 0xF8A /* R W PCM PCM Control Register */
+# define P_C_MIXER_CROSS_FIELD 0x0f
+# define P_C_MIXER_CROSS_R_TO_R 0x01 /* R W Mixer Connect Right to Right */
+# define P_C_MIXER_CROSS_L_TO_R 0x02 /* R W Mixer Connect Left to Right */
+# define P_C_MIXER_CROSS_R_TO_L 0x04 /* R W Mixer Connect Right to Left */
+# define P_C_MIXER_CROSS_L_TO_L 0x08 /* R W Mixer Connect Left to Left */
+# define P_C_PCM_DAC_MODE 0x10 /* R W PCM Playback (DAC) mode */
+# define P_C_PCM_ADC_MODE 0x00 /* R W PCM Record (ADC) mode */
+# define P_C_PCM_MONO 0x20 /* R W PCM Mono mode */
+# define P_C_PCM_STEREO 0x00 /* R W PCM Stereo mode */
+# define P_C_PCM_ENABLE 0x40 /* R W PCM Enable PCM engine */
+# define P_C_PCM_DMA_ENABLE 0x80 /* R W PCM Enable DRQ */
+
+#define SAMPLE_COUNTER_CONTROL 0x138B /* R W PCM Sample counter control register */
+# define S_C_C_SQUARE_WAVE 0x04 /* R W PCM Square wave generator (use for sample rate) */
+# define S_C_C_RATE 0x06 /* R W PCM Rate generator (use for sample buffer count) */
+# define S_C_C_LSB_THEN_MSB 0x30 /* R W PCM Change all 16 bits, LSB first, then MSB */
+
+ /* MVD101 and SDK documentations have S_C_C_SAMPLE_RATE and S_C_C_SAMPLE_BUFFER transposed. Only one works :-) */
+# define S_C_C_SAMPLE_RATE 0x00 /* R W PCM Select sample rate timer */
+# define S_C_C_SAMPLE_BUFFER 0x40 /* R W PCM Select sample buffer counter */
+
+# define S_C_C_PC_SPEAKER 0x80 /* R W PCM Select PC speaker counter */
+
+#define SAMPLE_RATE_TIMER 0x1388 /* W PCM Sample rate timer register (PCM wait interval) */
+#define SAMPLE_BUFFER_COUNTER 0x1389 /* R W PCM Sample buffer counter (DMA buffer size) */
+
+#define MIDI_CONTROL 0x178b /* R W MIDI Midi control register */
+# define M_C_ENA_TSTAMP_IRQ 0x01 /* R W MIDI Enable Time Stamp Interrupts */
+# define M_C_ENA_TME_COMP_IRQ 0x02 /* R W MIDI Enable time compare interrupts */
+# define M_C_ENA_INPUT_IRQ 0x04 /* R W MIDI Enable input FIFO interrupts */
+# define M_C_ENA_OUTPUT_IRQ 0x08 /* R W MIDI Enable output FIFO interrupts */
+# define M_C_ENA_OUTPUT_HALF_IRQ 0x10 /* R W MIDI Enable output FIFO half full interrupts */
+# define M_C_RESET_INPUT_FIFO 0x20 /* R W MIDI Reset input FIFO pointer */
+# define M_C_RESET_OUTPUT_FIFO 0x40 /* R W MIDI Reset output FIFO pointer */
+# define M_C_ENA_THRU_MODE 0x80 /* R W MIDI Echo input to output (THRU) */
+
+#define MIDI_STATUS 0x1B88 /* R W MIDI Midi (interrupt) status register */
+# define M_S_TIMESTAMP 0x01 /* R W MIDI Midi time stamp interrupt occurred */
+# define M_S_COMPARE 0x02 /* R W MIDI Midi compare time interrupt occurred */
+# define M_S_INPUT_AVAIL 0x04 /* R W MIDI Midi input data available interrupt occurred */
+# define M_S_OUTPUT_EMPTY 0x08 /* R W MIDI Midi output FIFO empty interrupt occurred */
+# define M_S_OUTPUT_HALF_EMPTY 0x10 /* R W MIDI Midi output FIFO half empty interrupt occurred */
+# define M_S_INPUT_OVERRUN 0x20 /* R W MIDI Midi input overrun error occurred */
+# define M_S_OUTPUT_OVERRUN 0x40 /* R W MIDI Midi output overrun error occurred */
+# define M_S_FRAMING_ERROR 0x80 /* R W MIDI Midi input framing error occurred */
+
+#define MIDI_FIFO_STATUS 0x1B89 /* R W MIDI Midi fifo status */
+#define MIDI_DATA 0x178A /* R W MIDI Midi data register */
+#define MIDI_INPUT_AVAILABLE 0x0f /* RW MIDI */
diff --git a/sys/i386/isa/sound/patmgr.c b/sys/i386/isa/sound/patmgr.c
index f013984..60f0ed6 100644
--- a/sys/i386/isa/sound/patmgr.c
+++ b/sys/i386/isa/sound/patmgr.c
@@ -1,10 +1,10 @@
/*
* sound/patmgr.c
- *
+ *
* The patch maneger interface for the /dev/sequencer
- *
+ *
* Copyright by Hannu Savolainen 1993
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
@@ -12,7 +12,7 @@
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -24,245 +24,244 @@
* 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 PATMGR_C
#include <i386/isa/sound/sound_config.h>
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SEQUENCER)
+#if defined(CONFIG_SEQUENCER)
-DEFINE_WAIT_QUEUES (server_procs[MAX_SYNTH_DEV],
- server_wait_flag[MAX_SYNTH_DEV]);
+static int *server_procs[MAX_SYNTH_DEV] = {NULL};
+static volatile struct snd_wait server_wait_flag[MAX_SYNTH_DEV] = { {0}};
-static struct patmgr_info *mbox[MAX_SYNTH_DEV] =
-{NULL};
-static volatile int msg_direction[MAX_SYNTH_DEV] =
-{0};
+static struct patmgr_info *mbox[MAX_SYNTH_DEV] = {NULL};
+static volatile int msg_direction[MAX_SYNTH_DEV] = {0};
-static int pmgr_opened[MAX_SYNTH_DEV] =
-{0};
+static int pmgr_opened[MAX_SYNTH_DEV] = {0};
#define A_TO_S 1
#define S_TO_A 2
-DEFINE_WAIT_QUEUE (appl_proc, appl_wait_flag);
+static int *appl_proc = NULL;
+static volatile struct snd_wait appl_wait_flag =
+{0};
int
-pmgr_open (int dev)
+pmgr_open(int dev)
{
- if (dev < 0 || dev >= num_synths)
- return RET_ERROR (ENXIO);
+ if (dev < 0 || dev >= num_synths)
+ return -(ENXIO);
- if (pmgr_opened[dev])
- return RET_ERROR (EBUSY);
- pmgr_opened[dev] = 1;
+ if (pmgr_opened[dev])
+ return -(EBUSY);
+ pmgr_opened[dev] = 1;
- RESET_WAIT_QUEUE (server_procs[dev], server_wait_flag[dev]);
+ server_wait_flag[dev].aborting = 0;
+ server_wait_flag[dev].mode = WK_NONE;
- return 0;
+ return 0;
}
void
-pmgr_release (int dev)
+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;
- mbox[dev]->parm1 = RET_ERROR (EIO);
+ mbox[dev]->key = PM_ERROR;
+ mbox[dev]->parm1 = -(EIO);
- if (SOMEONE_WAITING (appl_proc, appl_wait_flag))
- WAKE_UP (appl_proc, appl_wait_flag);
+ if ((appl_wait_flag.mode & WK_SLEEP)) {
+ appl_wait_flag.mode = WK_WAKEUP;
+ wakeup(appl_proc);
+ };
}
-
- pmgr_opened[dev] = 0;
+ pmgr_opened[dev] = 0;
}
int
-pmgr_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+pmgr_read(int dev, struct fileinfo * file, snd_rw_buf * buf, int count)
{
- unsigned long flags;
- int ok = 0;
+ u_long flags;
+ int ok = 0;
- if (count != sizeof (struct patmgr_info))
- {
- printk ("PATMGR%d: Invalid read count\n", dev);
- return RET_ERROR (EIO);
+ if (count != sizeof(struct patmgr_info)) {
+ printf("PATMGR%d: Invalid read count\n", dev);
+ return -(EIO);
}
+ while (!ok && !(server_wait_flag[dev].aborting)) {
+ flags = splhigh();
- while (!ok && !PROCESS_ABORTING (server_procs[dev], server_wait_flag[dev]))
- {
- DISABLE_INTR (flags);
+ while (!(mbox[dev] && msg_direction[dev] == A_TO_S) &&
+ !(server_wait_flag[dev].aborting)) {
- while (!(mbox[dev] && msg_direction[dev] == A_TO_S) &&
- !PROCESS_ABORTING (server_procs[dev], server_wait_flag[dev]))
- {
- DO_SLEEP (server_procs[dev], server_wait_flag[dev], 0);
- }
+ int chn;
+ server_procs[dev] = &chn;
+ DO_SLEEP(chn, server_wait_flag[dev], 0);
- if (mbox[dev] && msg_direction[dev] == A_TO_S)
- {
- COPY_TO_USER (buf, 0, (char *) mbox[dev], count);
- msg_direction[dev] = 0;
- ok = 1;
}
- RESTORE_INTR (flags);
+ if (mbox[dev] && msg_direction[dev] == A_TO_S) {
+
+ if (uiomove((char *) mbox[dev], count, buf)) {
+ printf("sb: Bad copyout()!\n");
+ };
+ msg_direction[dev] = 0;
+ ok = 1;
+ }
+ splx(flags);
}
- if (!ok)
- return RET_ERROR (EINTR);
- return count;
+ if (!ok)
+ return -(EINTR);
+ return count;
}
int
-pmgr_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+pmgr_write(int dev, struct fileinfo * file, snd_rw_buf * buf, int count)
{
- unsigned long flags;
+ u_long flags;
- if (count < 4)
- {
- printk ("PATMGR%d: Write count < 4\n", dev);
- return RET_ERROR (EIO);
+ if (count < 4) {
+ printf("PATMGR%d: Write count < 4\n", dev);
+ return -(EIO);
}
+ if (uiomove((char *) mbox[dev], 4, buf)) {
+ printf("sb: Bad copyin()!\n");
+ };
- COPY_FROM_USER (mbox[dev], buf, 0, 4);
-
- if (*(unsigned char *) mbox[dev] == SEQ_FULLSIZE)
- {
- int tmp_dev;
+ if (*(u_char *) mbox[dev] == SEQ_FULLSIZE) {
+ int tmp_dev;
- tmp_dev = ((unsigned short *) mbox[dev])[2];
- if (tmp_dev != dev)
- return RET_ERROR (ENXIO);
+ tmp_dev = ((u_short *) mbox[dev])[2];
+ if (tmp_dev != dev)
+ return -(ENXIO);
- return synth_devs[dev]->load_patch (dev, *(unsigned short *) mbox[dev],
- buf, 4, count, 1);
+ return synth_devs[dev]->load_patch(dev, *(u_short *) mbox[dev],
+ buf, 4, count, 1);
}
-
- if (count != sizeof (struct patmgr_info))
- {
- printk ("PATMGR%d: Invalid write count\n", dev);
- return RET_ERROR (EIO);
+ if (count != sizeof(struct patmgr_info)) {
+ printf("PATMGR%d: Invalid write count\n", dev);
+ return -(EIO);
}
+ /*
+ * If everything went OK, there should be a preallocated buffer in
+ * the mailbox and a client waiting.
+ */
- /*
- * If everything went OK, there should be a preallocated buffer in the
- * mailbox and a client waiting.
- */
+ flags = splhigh();
- DISABLE_INTR (flags);
+ if (mbox[dev] && !msg_direction[dev]) {
- if (mbox[dev] && !msg_direction[dev])
- {
- COPY_FROM_USER (&((char *) mbox[dev])[4], buf, 4, count - 4);
- msg_direction[dev] = S_TO_A;
+ if (uiomove(&((char *) mbox[dev])[4], count - 4, buf)) {
+ printf("sb: Bad copyin()!\n");
+ };
+ msg_direction[dev] = S_TO_A;
- if (SOMEONE_WAITING (appl_proc, appl_wait_flag))
- {
- WAKE_UP (appl_proc, appl_wait_flag);
+ if ((appl_wait_flag.mode & WK_SLEEP)) {
+ appl_wait_flag.mode = WK_WAKEUP;
+ wakeup(appl_proc);
}
}
+ splx(flags);
- RESTORE_INTR (flags);
-
- return count;
+ return count;
}
int
-pmgr_access (int dev, struct patmgr_info *rec)
+pmgr_access(int dev, struct patmgr_info * rec)
{
- unsigned long flags;
- int err = 0;
-
- DISABLE_INTR (flags);
-
- if (mbox[dev])
- printk (" PATMGR: Server %d mbox full. Why?\n", dev);
- else
- {
- rec->key = PM_K_COMMAND;
- mbox[dev] = rec;
- msg_direction[dev] = A_TO_S;
-
- if (SOMEONE_WAITING (server_procs[dev], server_wait_flag[dev]))
- {
- WAKE_UP (server_procs[dev], server_wait_flag[dev]);
- }
+ u_long flags;
+ int err = 0;
- DO_SLEEP (appl_proc, appl_wait_flag, 0);
+ flags = splhigh();
- if (msg_direction[dev] != S_TO_A)
- {
- rec->key = PM_ERROR;
- rec->parm1 = RET_ERROR (EIO);
- }
- else if (rec->key == PM_ERROR)
- {
- err = rec->parm1;
- if (err > 0)
- err = -err;
+ if (mbox[dev])
+ printf(" PATMGR: Server %d mbox full. Why?\n", dev);
+ else {
+ int flag, chn;
+
+ rec->key = PM_K_COMMAND;
+ mbox[dev] = rec;
+ msg_direction[dev] = A_TO_S;
+
+ if ((server_wait_flag[dev].mode & WK_SLEEP)) {
+ server_wait_flag[dev].mode = WK_WAKEUP;
+ wakeup(server_procs[dev]);
}
- mbox[dev] = NULL;
- msg_direction[dev] = 0;
+
+ appl_proc = &chn;
+ DO_SLEEP(chn, appl_wait_flag, 0);
+
+ if (msg_direction[dev] != S_TO_A) {
+ rec->key = PM_ERROR;
+ rec->parm1 = -(EIO);
+ } else if (rec->key == PM_ERROR) {
+ err = rec->parm1;
+ if (err > 0)
+ err = -err;
+ }
+ mbox[dev] = NULL;
+ msg_direction[dev] = 0;
}
- RESTORE_INTR (flags);
+ splx(flags);
- return err;
+ return err;
}
int
-pmgr_inform (int dev, int event, unsigned long p1, unsigned long p2,
- unsigned long p3, unsigned long p4)
+pmgr_inform(int dev, int event, u_long p1, u_long p2, u_long p3, u_long p4)
{
- unsigned long flags;
- int err = 0;
+ u_long flags;
+ int err = 0;
- if (!pmgr_opened[dev])
- return 0;
+ struct patmgr_info *tmp_mbox;
- DISABLE_INTR (flags);
-
- if (mbox[dev])
- printk (" PATMGR: Server %d mbox full. Why?\n", dev);
- else
- {
- if ((mbox[dev] =
- (struct patmgr_info *) KERNEL_MALLOC (sizeof (struct patmgr_info))) == NULL)
- {
- printk ("pmgr: Couldn't allocate memory for a message\n");
- return 0;
- }
+ if (!pmgr_opened[dev])
+ return 0;
- mbox[dev]->key = PM_K_EVENT;
- mbox[dev]->command = event;
- mbox[dev]->parm1 = p1;
- mbox[dev]->parm2 = p2;
- mbox[dev]->parm3 = p3;
- msg_direction[dev] = A_TO_S;
+ tmp_mbox = (struct patmgr_info *) malloc(sizeof(struct patmgr_info), M_TEMP, M_WAITOK);
- if (SOMEONE_WAITING (server_procs[dev], server_wait_flag[dev]))
- {
- WAKE_UP (server_procs[dev], server_wait_flag[dev]);
+ if (tmp_mbox == NULL) {
+ printf("pmgr: Couldn't allocate memory for a message\n");
+ return 0;
+ }
+ flags = splhigh();
+
+ if (mbox[dev])
+ printf(" PATMGR: Server %d mbox full. Why?\n", dev);
+ else {
+ int flag, chn;
+
+ mbox[dev] = tmp_mbox;
+ mbox[dev]->key = PM_K_EVENT;
+ mbox[dev]->command = event;
+ mbox[dev]->parm1 = p1;
+ mbox[dev]->parm2 = p2;
+ mbox[dev]->parm3 = p3;
+ msg_direction[dev] = A_TO_S;
+
+ if ((server_wait_flag[dev].mode & WK_SLEEP)) {
+ server_wait_flag[dev].mode = WK_WAKEUP;
+ wakeup(server_procs[dev]);
}
- DO_SLEEP (appl_proc, appl_wait_flag, 0);
- if (mbox[dev])
- KERNEL_FREE (mbox[dev]);
- mbox[dev] = NULL;
- msg_direction[dev] = 0;
+
+ appl_proc = &chn;
+ DO_SLEEP(chn, appl_wait_flag, 0);
+
+ mbox[dev] = NULL;
+ msg_direction[dev] = 0;
}
- RESTORE_INTR (flags);
+ splx(flags);
+ free(tmp_mbox, M_TEMP);
- return err;
+ return err;
}
#endif
diff --git a/sys/sys/soundcard.h b/sys/sys/soundcard.h
index b19b190..3b10c5d 100644
--- a/sys/sys/soundcard.h
+++ b/sys/sys/soundcard.h
@@ -1,3 +1,5 @@
+#ifndef SOUNDCARD_H
+#define SOUNDCARD_H
/*
* Copyright by Hannu Savolainen 1993
*
@@ -33,15 +35,18 @@
* Regards,
* Hannu Savolainen
* hannu@voxware.pp.fi
+ *
+ **********************************************************************
+ * PS. The Hacker's Guide to VoxWare available from
+ * nic.funet.fi:pub/OS/Linux/ALPHA/sound. The file is
+ * snd-sdk-doc-0.1.ps.gz (gzipped postscript). It contains
+ * some useful information about programming with VoxWare.
+ * (NOTE! The pub/OS/Linux/ALPHA/ directories are hidden. You have
+ * to cd inside them before the files are accessible.)
+ **********************************************************************
*/
-#ifndef _MACHINE_SOUNDCARD_H_
-#define _MACHINE_SOUNDCARD_H_
-
#define SOUND_VERSION 301
-#define VOXWARE
-
-#include <sys/ioccom.h>
/*
* Supported card ID numbers (Should be somewhere else?)
@@ -65,43 +70,26 @@
#define SNDCARD_TRXPRO 16
#define SNDCARD_TRXPRO_SB 17
#define SNDCARD_TRXPRO_MPU 18
-#ifdef PC98
-#define SNDCARD_PCM86 19
-#endif
-#define SNDCARD_AWE32 20
+#define SNDCARD_MAD16 19
+#define SNDCARD_MAD16_MPU 20
+#define SNDCARD_CS4232 21
+#define SNDCARD_CS4232_MPU 22
+#define SNDCARD_MAUI 23
+#define SNDCARD_PSEUDO_MSS 24
+#define SNDCARD_AWE32 25
-
-/***********************************
+/*
* IOCTL Commands for /dev/sequencer
*/
#ifndef _IOWR
-/* @(#)ioctlp.h */
-
-/* Ioctl's have the command encoded in the lower word,
- * and the size of any in or out parameters in the upper
- * word. The high 2 bits of the upper word are used
- * to encode the in/out status of the parameter; for now
- * we restrict parameters to at most 128 bytes.
- */
-/* #define IOCTYPE (0xff<<8) */
-#define IOCPARM_MASK 0x7f /* parameters must be < 128 bytes */
-#define IOC_VOID 0x00000000 /* no parameters */
-#define IOC_OUT 0x20000000 /* copy out parameters */
-#define IOC_IN 0x40000000 /* copy in parameters */
-#define IOC_INOUT (IOC_IN|IOC_OUT)
-/* the 0x20000000 is so we can distinguish new ioctl's from old */
-#define _IO(x,y) ((int)(IOC_VOID|(x<<8)|y))
-#define _IOR(x,y,t) ((int)(IOC_OUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y))
-#define _IOW(x,y,t) ((int)(IOC_IN|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y))
-/* this should be _IORW, but stdio got there first */
-#define _IOWR(x,y,t) ((int)(IOC_INOUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y))
+#include <sys/ioccom.h>
#endif /* !_IOWR */
#define SNDCTL_SEQ_RESET _IO ('Q', 0)
#define SNDCTL_SEQ_SYNC _IO ('Q', 1)
#define SNDCTL_SYNTH_INFO _IOWR('Q', 2, struct synth_info)
-#define SNDCTL_SEQ_CTRLRATE _IOWR('Q', 3, int) /* Set/get timer resolution (HZ) */
+#define SNDCTL_SEQ_CTRLRATE _IOWR('Q', 3, int) /* Set/get timer resolution (hz) */
#define SNDCTL_SEQ_GETOUTCOUNT _IOR ('Q', 4, int)
#define SNDCTL_SEQ_GETINCOUNT _IOR ('Q', 5, int)
#define SNDCTL_SEQ_PERCMODE _IOW ('Q', 6, int)
@@ -111,16 +99,17 @@
#define SNDCTL_SEQ_NRSYNTHS _IOR ('Q',10, int)
#define SNDCTL_SEQ_NRMIDIS _IOR ('Q',11, int)
#define SNDCTL_MIDI_INFO _IOWR('Q',12, struct midi_info)
-#define SNDCTL_SEQ_TRESHOLD _IOW ('Q',13, int)
+#define SNDCTL_SEQ_THRESHOLD _IOW ('Q',13, int)
+#define SNDCTL_SEQ_TRESHOLD SNDCTL_SEQ_THRESHOLD /* there was once a typo */
#define SNDCTL_SYNTH_MEMAVL _IOWR('Q',14, int) /* in=dev#, out=memsize */
#define SNDCTL_FM_4OP_ENABLE _IOW ('Q',15, int) /* in=dev# */
#define SNDCTL_PMGR_ACCESS _IOWR('Q',16, struct patmgr_info)
#define SNDCTL_SEQ_PANIC _IO ('Q',17)
#define SNDCTL_SEQ_OUTOFBAND _IOW ('Q',18, struct seq_event_rec)
- struct seq_event_rec {
- unsigned char arr[8];
- };
+struct seq_event_rec {
+ u_char arr[8];
+};
#define SNDCTL_TMR_TIMEBASE _IOWR('T', 1, int)
#define SNDCTL_TMR_START _IO ('T', 2)
@@ -138,20 +127,32 @@
#define SNDCTL_TMR_SELECT _IOW ('T', 8, int)
/*
+ * Endian aware patch key generation algorithm.
+ */
+
+#if defined(_AIX) || defined(AIX)
+# define _PATCHKEY(id) (0xfd00|id)
+#else
+# define _PATCHKEY(id) ((id<<8)|0xfd)
+#endif
+
+/*
* Sample loading mechanism for internal synthesizers (/dev/sequencer)
* The following patch_info structure has been designed to support
* Gravis UltraSound. It tries to be universal format for uploading
- * sample based patches but is probably too limited.
+ * sample based patches but is propably too limited.
*/
struct patch_info {
- short key; /* Use GUS_PATCH here */
-#define GUS_PATCH 0x04fd
-#define OBSOLETE_GUS_PATCH 0x02fd
- short device_no; /* Synthesizer number */
- short instr_no; /* Midi pgm# */
+/* u_short key; Use GUS_PATCH here */
+ short key; /* Use GUS_PATCH here */
+#define GUS_PATCH _PATCHKEY(0x04)
+#define OBSOLETE_GUS_PATCH _PATCHKEY(0x02)
+
+ short device_no; /* Synthesizer number */
+ short instr_no; /* Midi pgm# */
- unsigned long mode;
+ u_long mode;
/*
* The least significant byte has the same format than the GUS .PAT
* files
@@ -170,8 +171,8 @@ struct patch_info {
#define WAVE_SCALE 0x00040000 /* The scaling info is valid */
/* Other bits must be zeroed */
- long len; /* Size of the wave data in bytes */
- long loop_start, loop_end; /* Byte offsets from the beginning */
+ long len; /* Size of the wave data in bytes */
+ long loop_start, loop_end; /* Byte offsets from the beginning */
/*
* The base_freq and base_note fields are used when computing the
@@ -189,18 +190,18 @@ struct patch_info {
* middle A is 440*1000.
*/
- unsigned int base_freq;
- unsigned long base_note;
- unsigned long high_note;
- unsigned long low_note;
- int panning; /* -128=left, 127=right */
- int detuning;
+ u_int base_freq;
+ u_long base_note;
+ u_long high_note;
+ u_long low_note;
+ int panning; /* -128=left, 127=right */
+ int detuning;
/* New fields introduced in version 1.99.5 */
/* Envelope. Enabled by mode bit WAVE_ENVELOPES */
- unsigned char env_rate[ 6 ]; /* GUS HW ramping rate */
- unsigned char env_offset[ 6 ]; /* 255 == 100% */
+ u_char env_rate[ 6 ]; /* GUS HW ramping rate */
+ u_char env_offset[ 6 ]; /* 255 == 100% */
/*
* The tremolo, vibrato and scale info are not supported yet.
@@ -208,30 +209,30 @@ struct patch_info {
* WAVE_SCALE
*/
- unsigned char tremolo_sweep;
- unsigned char tremolo_rate;
- unsigned char tremolo_depth;
-
- unsigned char vibrato_sweep;
- unsigned char vibrato_rate;
- unsigned char vibrato_depth;
+ u_char tremolo_sweep;
+ u_char tremolo_rate;
+ u_char tremolo_depth;
- int scale_frequency;
- unsigned int scale_factor; /* from 0 to 2048 or 0 to 2 */
-
- int volume;
- int spare[4];
- char data[1]; /* The waveform data starts here */
- };
+ u_char vibrato_sweep;
+ u_char vibrato_rate;
+ u_char vibrato_depth;
+ int scale_frequency;
+ u_int scale_factor; /* from 0 to 2048 or 0 to 2 */
+
+ int volume;
+ int spare[4];
+ char data[1]; /* The waveform data starts here */
+};
struct sysex_info {
- short key; /* Use GUS_PATCH here */
-#define SYSEX_PATCH 0x05fd
- short device_no; /* Synthesizer number */
- long len; /* Size of the sysex data in bytes */
- unsigned char data[1]; /* Sysex data starts here */
- };
+ short key; /* Use GUS_PATCH here */
+#define SYSEX_PATCH _PATCHKEY(0x05)
+#define MAUI_PATCH _PATCHKEY(0x06)
+ short device_no; /* Synthesizer number */
+ long len; /* Size of the sysex data in bytes */
+ u_char data[1]; /* Sysex data starts here */
+};
/*
* Patch management interface (/dev/sequencer, /dev/patmgr#)
@@ -260,7 +261,7 @@ struct sysex_info {
*/
struct patmgr_info { /* Note! size must be < 4k since kmalloc() is used */
- unsigned long key; /* Don't worry. Reserved for communication
+ u_long key; /* Don't worry. Reserved for communication
between the patch manager and the driver. */
#define PM_K_EVENT 1 /* Event from the /dev/sequencer driver */
#define PM_K_COMMAND 2 /* Request from a application */
@@ -294,17 +295,17 @@ struct patmgr_info { /* Note! size must be < 4k since kmalloc() is used */
* Commands above 0xffff reserved for device specific use
*/
- long parm1;
- long parm2;
- long parm3;
+ long parm1;
+ long parm2;
+ long parm3;
- union {
- unsigned char data8[4000];
- unsigned short data16[2000];
- unsigned long data32[1000];
+ union {
+ u_char data8[4000];
+ u_short data16[2000];
+ u_long data32[1000];
struct patch_info patch;
- } data;
- };
+ } data;
+};
/*
* When a patch manager daemon is present, it will be informed by the
@@ -389,7 +390,7 @@ struct patmgr_info { /* Note! size must be < 4k since kmalloc() is used */
/* 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 recognized by the driver. */
+/* 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) */
@@ -475,66 +476,66 @@ struct patmgr_info { /* Note! size must be < 4k since kmalloc() is used */
* Record for FM patches
*/
-typedef unsigned char sbi_instr_data[32];
+typedef u_char sbi_instr_data[32];
struct sbi_instrument {
- unsigned short key; /* Initialize to FM_PATCH or OPL3_PATCH */
-#define FM_PATCH 0x01fd
-#define OPL3_PATCH 0x03fd
- short device; /* Synth# (0-4) */
- int channel; /* Program# to be initialized */
- sbi_instr_data operators; /* Register settings for operator cells (.SBI format) */
- };
+ u_short key; /* FM_PATCH or OPL3_PATCH */
+#define FM_PATCH _PATCHKEY(0x01)
+#define OPL3_PATCH _PATCHKEY(0x03)
+ short device; /* Synth# (0-4) */
+ int channel; /* Program# to be initialized */
+ sbi_instr_data operators; /* Reg. settings for operator cells
+ * (.SBI format) */
+};
struct synth_info { /* Read only */
- char name[30];
- int device; /* 0-N. INITIALIZE BEFORE CALLING */
- int synth_type;
+ char name[30];
+ int device; /* 0-N. INITIALIZE BEFORE CALLING */
+ int synth_type;
#define SYNTH_TYPE_FM 0
#define SYNTH_TYPE_SAMPLE 1
#define SYNTH_TYPE_MIDI 2 /* Midi interface */
- int synth_subtype;
+ int synth_subtype;
#define FM_TYPE_ADLIB 0x00
#define FM_TYPE_OPL3 0x01
#define SAMPLE_TYPE_GUS 0x10
-#define SAMPLE_TYPE_AWE32 0x20
- int perc_mode; /* No longer supported */
- int nr_voices;
- int nr_drums; /* Obsolete field */
- int instr_bank_size;
- unsigned long capabilities;
+ int perc_mode; /* No longer supported */
+ int nr_voices;
+ int nr_drums; /* Obsolete field */
+ int instr_bank_size;
+ u_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 */
- };
+ int dummies[19]; /* Reserve space */
+};
struct sound_timer_info {
- char name[30];
- int caps;
- };
+ char name[32];
+ int caps;
+};
#define MIDI_CAP_MPU401 1 /* MPU-401 intelligent mode */
struct midi_info {
- char name[30];
- int device; /* 0-N. INITIALIZE BEFORE CALLING */
- unsigned long capabilities; /* To be defined later */
- int dev_type;
- int dummies[18]; /* Reserve space */
- };
+ char name[30];
+ int device; /* 0-N. INITIALIZE BEFORE CALLING */
+ u_long capabilities; /* To be defined later */
+ int dev_type;
+ int dummies[18]; /* Reserve space */
+};
/********************************************
* ioctl commands for the /dev/midi##
*/
typedef struct {
- unsigned char cmd;
- char nr_args, nr_returns;
- unsigned char data[30];
- } mpu_command_rec;
+ u_char cmd;
+ char nr_args, nr_returns;
+ u_char data[30];
+} mpu_command_rec;
#define SNDCTL_MIDI_PRETIME _IOWR('m', 0, int)
#define SNDCTL_MIDI_MPUMODE _IOWR('m', 1, int)
@@ -549,7 +550,7 @@ typedef struct {
#define SNDCTL_DSP_SPEED _IOWR('P', 2, int)
#define SNDCTL_DSP_STEREO _IOWR('P', 3, int)
#define SNDCTL_DSP_GETBLKSIZE _IOR('P', 4, int)
-#define SNDCTL_DSP_SETBLKSIZE _IOW('P', 4, int)
+#define SNDCTL_DSP_SETBLKSIZE _IOW('P', 4, int)
#define SNDCTL_DSP_SAMPLESIZE SNDCTL_DSP_SETFMT
#define SOUND_PCM_WRITE_CHANNELS _IOWR('P', 6, int)
#define SOUND_PCM_WRITE_FILTER _IOWR('P', 7, int)
@@ -557,6 +558,7 @@ typedef struct {
#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*/
@@ -576,17 +578,59 @@ typedef struct {
* Buffer status queries.
*/
typedef struct audio_buf_info {
- int fragments; /* # of available fragments (partially usend ones not counted) */
- int fragstotal; /* Total # of fragments allocated */
- int fragsize; /* Size of a fragment in bytes */
+ int fragments; /* # of available fragments (partially used
+ * ones not counted) */
+ int fragstotal; /* Total # of fragments allocated */
+ int fragsize; /* Size of a fragment in bytes */
- int bytes; /* Available space in bytes (includes partially used fragments) */
- /* Note! 'bytes' could be more than fragments*fragsize */
- } audio_buf_info;
+ int bytes; /* Available space in bytes (includes
+ * partially used fragments) */
+ /* Note! 'bytes' could be more than fragments*fragsize */
+} audio_buf_info;
#define SNDCTL_DSP_GETOSPACE _IOR ('P',12, audio_buf_info)
#define SNDCTL_DSP_GETISPACE _IOR ('P',13, audio_buf_info)
#define SNDCTL_DSP_NONBLOCK _IO ('P',14)
+#define SNDCTL_DSP_GETCAPS _IOR ('P',15, int)
+#define DSP_CAP_REVISION 0x000000ff /* Bits for revision level (0 to 255) */
+#define DSP_CAP_DUPLEX 0x00000100 /* Full duplex record/playback */
+#define DSP_CAP_REALTIME 0x00000200 /* Real time capability */
+#define DSP_CAP_BATCH 0x00000400 /* Device has some kind of */
+
+/* internal buffers which may */
+/* cause some delays and */
+/* decrease precision of timing */
+# define DSP_CAP_COPROC 0x00000800 /* Has a coprocessor */
+/* Sometimes it's a DSP */
+/* but usually not */
+# define DSP_CAP_TRIGGER 0x00001000 /* Supports SETTRIGGER */
+# define DSP_CAP_MMAP 0x00002000 /* Supports mmap() */
+
+
+
+#define SNDCTL_DSP_GETCAPS _IOR ('P',15, int)
+#define SNDCTL_DSP_GETTRIGGER _IOR ('P',16, int)
+#define SNDCTL_DSP_SETTRIGGER _IOW ('P',16, int)
+#define PCM_ENABLE_INPUT 0x00000001
+#define PCM_ENABLE_OUTPUT 0x00000002
+
+typedef struct count_info {
+ int bytes; /* Total # of bytes processed */
+ int blocks; /* # of fragment transitions since last time */
+ int ptr; /* Current DMA pointer value */
+} count_info;
+
+#define SNDCTL_DSP_GETIPTR _IOR ('P',17, count_info)
+#define SNDCTL_DSP_GETOPTR _IOR ('P',18, count_info)
+
+typedef struct buffmem_desc {
+ caddr_t buffer;
+ int size;
+} buffmem_desc;
+
+#define SNDCTL_DSP_MAPINBUF _IOR ('P', 19, buffmem_desc)
+#define SNDCTL_DSP_MAPOUTBUF _IOR ('P', 20, buffmem_desc)
+#define SNDCTL_DSP_SETSYNCRO _IO ('P', 21)
#define SOUND_PCM_READ_RATE _IOR ('P', 2, int)
#define SOUND_PCM_READ_CHANNELS _IOR ('P', 6, int)
@@ -606,6 +650,14 @@ typedef struct audio_buf_info {
#define SOUND_PCM_GETOSPACE SNDCTL_DSP_GETOSPACE
#define SOUND_PCM_GETISPACE SNDCTL_DSP_GETISPACE
#define SOUND_PCM_NONBLOCK SNDCTL_DSP_NONBLOCK
+#define SOUND_PCM_GETCAPS SNDCTL_DSP_GETCAPS
+#define SOUND_PCM_GETTRIGGER SNDCTL_DSP_GETTRIGGER
+#define SOUND_PCM_SETTRIGGER SNDCTL_DSP_SETTRIGGER
+#define SOUND_PCM_SETSYNCRO SNDCTL_DSP_SETSYNCRO
+#define SOUND_PCM_GETIPTR SNDCTL_DSP_GETIPTR
+#define SOUND_PCM_GETOPTR SNDCTL_DSP_GETOPTR
+#define SOUND_PCM_MAPINBUF SNDCTL_DSP_MAPINBUF
+#define SOUND_PCM_MAPOUTBUF SNDCTL_DSP_MAPOUTBUF
/*
* ioctl calls to be used in communication with coprocessors and
@@ -613,29 +665,29 @@ typedef struct audio_buf_info {
*/
typedef struct copr_buffer {
- int command; /* Set to 0 if not used */
- int flags;
+ int command; /* Set to 0 if not used */
+ int flags;
#define CPF_NONE 0x0000
#define CPF_FIRST 0x0001 /* First block */
#define CPF_LAST 0x0002 /* Last block */
- int len;
- int offs; /* If required by the device (0 if not used) */
+ int len;
+ int offs; /* If required by the device (0 if not used) */
- unsigned char data[4000]; /* NOTE! 4000 is not 4k */
- } copr_buffer;
+ u_char data[4000]; /* NOTE! 4000 is not 4k */
+} copr_buffer;
typedef struct copr_debug_buf {
- int command; /* Used internally. Set to 0 */
- int parm1;
- int parm2;
- int flags;
- int len; /* Length of data in bytes */
- } copr_debug_buf;
+ int command; /* Used internally. Set to 0 */
+ int parm1;
+ int parm2;
+ int flags;
+ int len; /* Length of data in bytes */
+} copr_debug_buf;
typedef struct copr_msg {
- int len;
- unsigned char data[4000];
- } copr_msg;
+ int len;
+ u_char data[4000];
+} copr_msg;
#define SNDCTL_COPR_RESET _IO ('C', 0)
#define SNDCTL_COPR_LOAD _IOWR('C', 1, copr_buffer)
@@ -679,7 +731,7 @@ typedef struct copr_msg {
/*
* The AD1848 codec and compatibles have three line level inputs
* (line, aux1 and aux2). Since each card manufacturer have assigned
- * different meanings to these inputs, it's impractical to assign
+ * different meanings to these inputs, it's inpractical to assign
* specific meanings (line, cd, synth etc.) to them.
*/
#define SOUND_MIXER_LINE1 14 /* Input source 1 (aux1) */
@@ -696,21 +748,23 @@ typedef struct copr_msg {
/* Note! Number 31 cannot be used since the sign bit is reserved */
-#define SOUND_DEVICE_LABELS {"Vol ", "Bass ", "Trebl", "Synth", "Pcm ", "Spkr ", "Line ", \
- "Mic ", "CD ", "Mix ", "Pcm2 ", "Rec ", "IGain", "OGain", \
- "Line1", "Line2", "Line3"}
+#define SOUND_DEVICE_LABELS { \
+ "Vol ", "Bass ", "Trebl", "Synth", "Pcm ", "Spkr ", "Line ", \
+ "Mic ", "CD ", "Mix ", "Pcm2 ", "Rec ", "IGain", "OGain", \
+ "Line1", "Line2", "Line3"}
-#define SOUND_DEVICE_NAMES {"vol", "bass", "treble", "synth", "pcm", "speaker", "line", \
- "mic", "cd", "mix", "pcm2", "rec", "igain", "ogain", \
- "line1", "line2", "line3"}
+#define SOUND_DEVICE_NAMES { \
+ "vol", "bass", "treble", "synth", "pcm", "speaker", "line", \
+ "mic", "cd", "mix", "pcm2", "rec", "igain", "ogain", \
+ "line1", "line2", "line3"}
/* Device bitmask identifiers */
-#define SOUND_MIXER_RECSRC 0xff /* Arg contains a bit for each recording source */
-#define SOUND_MIXER_DEVMASK 0xfe /* Arg contains a bit for each supported device */
-#define SOUND_MIXER_RECMASK 0xfd /* Arg contains a bit for each supported recording source */
+#define SOUND_MIXER_RECSRC 0xff /* 1 bit per recording source */
+#define SOUND_MIXER_DEVMASK 0xfe /* 1 bit per supported device */
+#define SOUND_MIXER_RECMASK 0xfd /* 1 bit per supp. recording source */
#define SOUND_MIXER_CAPS 0xfc
- #define SOUND_CAP_EXCL_INPUT 0x00000001 /* Only one recording source at a time */
+#define SOUND_CAP_EXCL_INPUT 0x00000001 /* Only 1 rec. src at a time */
#define SOUND_MIXER_STEREODEVS 0xfb /* Mixer channels supporting stereo */
/* Device mask bits */
@@ -811,6 +865,7 @@ typedef struct copr_msg {
#define EV_TIMING 0x81
#define EV_CHN_COMMON 0x92
#define EV_CHN_VOICE 0x93
+#define EV_SYSEX 0x94
/*
* Event types 200 to 220 are reserved for application use.
* These numbers will not be used by the driver.
@@ -849,6 +904,11 @@ typedef struct copr_msg {
#define TMR_SPP 10 /* Song position pointer */
#define TMR_TIMESIG 11 /* Time signature */
+/*
+ * Local event types
+ */
+#define LOCL_STARTAUDIO 1
+
#if (!defined(__KERNEL__) && !defined(KERNEL) && !defined(INKERNEL) && !defined(_KERNEL)) || defined(USE_SEQ_MACROS)
/*
* Some convenience macros to simplify programming of the
@@ -879,11 +939,16 @@ void seqbuf_dump(void); /* This function must be provided by programs */
* }
*/
-#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_DEFINEBUF(len) \
+ u_char _seqbuf[len]; int _seqbuflen = len;int _seqbufptr = 0
+#define SEQ_USE_EXTBUF() \
+ extern u_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_NEEDBUF(len) \
+ if ((_seqbufptr+(len)) > _seqbuflen) \
+ seqbuf_dump()
#define _SEQ_ADVBUF(len) _seqbufptr += len
#define SEQ_DUMPBUF seqbuf_dump
#else
@@ -894,7 +959,7 @@ void seqbuf_dump(void); /* This function must be provided by programs */
* The program using the macro library must define the following macros before
* using this library.
*
- * #define _seqbuf name of the buffer (unsigned char[])
+ * #define _seqbuf name of the buffer (u_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.
@@ -904,41 +969,44 @@ void seqbuf_dump(void); /* This function must be provided by programs */
#define _SEQ_NEEDBUF(len) /* empty */
#endif
-#define PM_LOAD_PATCH(dev, bank, pgm) (SEQ_DUMPBUF(), _pm_info.command = _PM_LOAD_PATCH, \
- _pm_info.device=dev, _pm_info.data.data8[0]=pgm, \
- _pm_info.parm1 = bank, _pm_info.parm2 = 1, \
- ioctl(seqfd, SNDCTL_PMGR_ACCESS, &_pm_info))
-#define PM_LOAD_PATCHES(dev, bank, pgm) (SEQ_DUMPBUF(), _pm_info.command = _PM_LOAD_PATCH, \
- _pm_info.device=dev, memcpy(_pm_info.data.data8, pgm, 128), \
- _pm_info.parm1 = bank, _pm_info.parm2 = 128, \
- ioctl(seqfd, SNDCTL_PMGR_ACCESS, &_pm_info))
-
-#define SEQ_VOLUME_MODE(dev, mode) {_SEQ_NEEDBUF(8);\
- _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
- _seqbuf[_seqbufptr+1] = SEQ_VOLMODE;\
- _seqbuf[_seqbufptr+2] = (dev);\
- _seqbuf[_seqbufptr+3] = (mode);\
- _seqbuf[_seqbufptr+4] = 0;\
- _seqbuf[_seqbufptr+5] = 0;\
- _seqbuf[_seqbufptr+6] = 0;\
- _seqbuf[_seqbufptr+7] = 0;\
- _SEQ_ADVBUF(8);}
+#define PM_LOAD_PATCH(dev, bank, pgm) \
+ (SEQ_DUMPBUF(), _pm_info.command = _PM_LOAD_PATCH, \
+ _pm_info.device=dev, _pm_info.data.data8[0]=pgm, \
+ _pm_info.parm1 = bank, _pm_info.parm2 = 1, \
+ ioctl(seqfd, SNDCTL_PMGR_ACCESS, &_pm_info))
+#define PM_LOAD_PATCHES(dev, bank, pgm) \
+ (SEQ_DUMPBUF(), _pm_info.command = _PM_LOAD_PATCH, \
+ _pm_info.device=dev, bcopy( pgm, _pm_info.data.data8, 128), \
+ _pm_info.parm1 = bank, _pm_info.parm2 = 128, \
+ ioctl(seqfd, SNDCTL_PMGR_ACCESS, &_pm_info))
+
+#define SEQ_VOLUME_MODE(dev, mode) { \
+ _SEQ_NEEDBUF(8);\
+ _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
+ _seqbuf[_seqbufptr+1] = SEQ_VOLMODE;\
+ _seqbuf[_seqbufptr+2] = (dev);\
+ _seqbuf[_seqbufptr+3] = (mode);\
+ _seqbuf[_seqbufptr+4] = 0;\
+ _seqbuf[_seqbufptr+5] = 0;\
+ _seqbuf[_seqbufptr+6] = 0;\
+ _seqbuf[_seqbufptr+7] = 0;\
+ _SEQ_ADVBUF(8);}
/*
* Midi voice messages
*/
-#define _CHN_VOICE(dev, event, chn, note, parm) \
- {_SEQ_NEEDBUF(8);\
- _seqbuf[_seqbufptr] = EV_CHN_VOICE;\
- _seqbuf[_seqbufptr+1] = (dev);\
- _seqbuf[_seqbufptr+2] = (event);\
- _seqbuf[_seqbufptr+3] = (chn);\
- _seqbuf[_seqbufptr+4] = (note);\
- _seqbuf[_seqbufptr+5] = (parm);\
- _seqbuf[_seqbufptr+6] = (0);\
- _seqbuf[_seqbufptr+7] = 0;\
- _SEQ_ADVBUF(8);}
+#define _CHN_VOICE(dev, event, chn, note, parm) { \
+ _SEQ_NEEDBUF(8);\
+ _seqbuf[_seqbufptr] = EV_CHN_VOICE;\
+ _seqbuf[_seqbufptr+1] = (dev);\
+ _seqbuf[_seqbufptr+2] = (event);\
+ _seqbuf[_seqbufptr+3] = (chn);\
+ _seqbuf[_seqbufptr+4] = (note);\
+ _seqbuf[_seqbufptr+5] = (parm);\
+ _seqbuf[_seqbufptr+6] = (0);\
+ _seqbuf[_seqbufptr+7] = 0;\
+ _SEQ_ADVBUF(8);}
#define SEQ_START_NOTE(dev, chn, note, vol) \
_CHN_VOICE(dev, MIDI_NOTEON, chn, note, vol)
@@ -953,72 +1021,92 @@ void seqbuf_dump(void); /* This function must be provided by programs */
* 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 _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);}
+/*
+ * SEQ_SYSEX permits sending of sysex messages. (It may look that it permits
+ * sending any MIDI bytes but it's absolutely not possible. Trying to do
+ * so _will_ cause problems with MPU401 intelligent mode).
+ *
+ * Sysex messages are sent in blocks of 1 to 6 bytes. Longer messages must be
+ * sent by calling SEQ_SYSEX() several times (there must be no other events
+ * between them). First sysex fragment must have 0xf0 in the first byte
+ * and the last byte (buf[len-1] of the last fragment must be 0xf7. No byte
+ * between these sysex start and end markers cannot be larger than 0x7f. Also
+ * lengths of each fragments (except the last one) must be 6.
+ *
+ * Breaking the above rules may work with some MIDI ports but is likely to
+ * cause fatal problems with some other devices (such as MPU401).
+ */
+#define SEQ_SYSEX(dev, buf, len) { \
+ int i, l=(len); if (l>6)l=6;\
+ _SEQ_NEEDBUF(8);\
+ _seqbuf[_seqbufptr] = EV_SYSEX;\
+ for(i=0;i<l;i++)_seqbuf[_seqbufptr+i+1] = (buf)[i];\
+ for(i=l;i<6;i++)_seqbuf[_seqbufptr+i+1] = 0xff;\
+ _SEQ_ADVBUF(8);}
#define SEQ_CHN_PRESSURE(dev, chn, pressure) \
- _CHN_COMMON(dev, MIDI_CHN_PRESSURE, chn, pressure, 0, 0)
+ _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)
+ _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)
+ _CHN_COMMON(dev, MIDI_CTL_CHANGE, chn, controller, 0, value)
#define SEQ_BENDER(dev, chn, value) \
- _CHN_COMMON(dev, MIDI_PITCH_BEND, chn, 0, 0, value)
-
-
-#define SEQ_V2_X_CONTROL(dev, voice, controller, value) {_SEQ_NEEDBUF(8);\
- _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
- _seqbuf[_seqbufptr+1] = SEQ_CONTROLLER;\
- _seqbuf[_seqbufptr+2] = (dev);\
- _seqbuf[_seqbufptr+3] = (voice);\
- _seqbuf[_seqbufptr+4] = (controller);\
- *(short *)&_seqbuf[_seqbufptr+5] = (value);\
- _seqbuf[_seqbufptr+7] = 0;\
- _SEQ_ADVBUF(8);}
+ _CHN_COMMON(dev, MIDI_PITCH_BEND, chn, 0, 0, value)
+
+
+#define SEQ_V2_X_CONTROL(dev, voice, controller, value) { \
+ _SEQ_NEEDBUF(8);\
+ _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
+ _seqbuf[_seqbufptr+1] = SEQ_CONTROLLER;\
+ _seqbuf[_seqbufptr+2] = (dev);\
+ _seqbuf[_seqbufptr+3] = (voice);\
+ _seqbuf[_seqbufptr+4] = (controller);\
+ *(short *)&_seqbuf[_seqbufptr+5] = (value);\
+ _seqbuf[_seqbufptr+7] = 0;\
+ _SEQ_ADVBUF(8);}
+
/*
* The following 5 macros are incorrectly implemented and obsolete.
* Use SEQ_BENDER and SEQ_CONTROL (with proper controller) instead.
*/
-#define SEQ_PITCHBEND(dev, voice, value) SEQ_V2_X_CONTROL(dev, voice, CTRL_PITCH_BENDER, value)
-#define SEQ_BENDER_RANGE(dev, voice, value) SEQ_V2_X_CONTROL(dev, voice, CTRL_PITCH_BENDER_RANGE, value)
-#define SEQ_EXPRESSION(dev, voice, value) SEQ_CONTROL(dev, voice, CTL_EXPRESSION, value*128)
-#define SEQ_MAIN_VOLUME(dev, voice, value) SEQ_CONTROL(dev, voice, CTL_MAIN_VOLUME, (value*16383)/100)
-#define SEQ_PANNING(dev, voice, pos) SEQ_CONTROL(dev, voice, CTL_PAN, (pos+128) / 2)
-#if 0
-#define SEQ_PANNING(dev, voice, pos) {_SEQ_NEEDBUF(8);\
- _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
- _seqbuf[_seqbufptr+1] = SEQ_BALANCE;\
- _seqbuf[_seqbufptr+2] = (dev);\
- _seqbuf[_seqbufptr+3] = (voice);\
- (char)_seqbuf[_seqbufptr+4] = (pos);\
- _seqbuf[_seqbufptr+5] = 0;\
- _seqbuf[_seqbufptr+6] = 0;\
- _seqbuf[_seqbufptr+7] = 1;\
- _SEQ_ADVBUF(8);}
-#endif
+
+#define SEQ_PITCHBEND(dev, voice, value) \
+ SEQ_V2_X_CONTROL(dev, voice, CTRL_PITCH_BENDER, value)
+#define SEQ_BENDER_RANGE(dev, voice, value) \
+ SEQ_V2_X_CONTROL(dev, voice, CTRL_PITCH_BENDER_RANGE, value)
+#define SEQ_EXPRESSION(dev, voice, value) \
+ SEQ_CONTROL(dev, voice, CTL_EXPRESSION, value*128)
+#define SEQ_MAIN_VOLUME(dev, voice, value) \
+ SEQ_CONTROL(dev, voice, CTL_MAIN_VOLUME, (value*16383)/100)
+#define SEQ_PANNING(dev, voice, pos) \
+ SEQ_CONTROL(dev, voice, CTL_PAN, (pos+128) / 2)
/*
- * Timing and synchronization macros
+ * Timing and syncronization macros
*/
-#define _TIMER_EVENT(ev, parm) {_SEQ_NEEDBUF(8);\
- _seqbuf[_seqbufptr+0] = EV_TIMING; \
- _seqbuf[_seqbufptr+1] = (ev); \
- _seqbuf[_seqbufptr+2] = 0;\
- _seqbuf[_seqbufptr+3] = 0;\
- *(unsigned int *)&_seqbuf[_seqbufptr+4] = (parm); \
- _SEQ_ADVBUF(8);}
+#define _TIMER_EVENT(ev, parm) { \
+ _SEQ_NEEDBUF(8);\
+ _seqbuf[_seqbufptr+0] = EV_TIMING; \
+ _seqbuf[_seqbufptr+1] = (ev); \
+ _seqbuf[_seqbufptr+2] = 0;\
+ _seqbuf[_seqbufptr+3] = 0;\
+ *(u_int *)&_seqbuf[_seqbufptr+4] = (parm); \
+ _SEQ_ADVBUF(8); \
+ }
#define SEQ_START_TIMER() _TIMER_EVENT(TMR_START, 0)
#define SEQ_STOP_TIMER() _TIMER_EVENT(TMR_STOP, 0)
@@ -1031,24 +1119,43 @@ void seqbuf_dump(void); /* This function must be provided by programs */
#define SEQ_TIME_SIGNATURE(sig) _TIMER_EVENT(TMR_TIMESIG, sig)
/*
+ * Local control events
+ */
+
+#define _LOCAL_EVENT(ev, parm) { \
+ _SEQ_NEEDBUF(8);\
+ _seqbuf[_seqbufptr+0] = EV_SEQ_LOCAL; \
+ _seqbuf[_seqbufptr+1] = (ev); \
+ _seqbuf[_seqbufptr+2] = 0;\
+ _seqbuf[_seqbufptr+3] = 0;\
+ *(u_int *)&_seqbuf[_seqbufptr+4] = (parm); \
+ _SEQ_ADVBUF(8); \
+ }
+
+#define SEQ_PLAYAUDIO(devmask) _LOCAL_EVENT(LOCL_STARTAUDIO, devmask)
+/*
* 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_MIDIOUT(device, byte) { \
+ _SEQ_NEEDBUF(4);\
+ _seqbuf[_seqbufptr] = SEQ_MIDIPUTC;\
+ _seqbuf[_seqbufptr+1] = (byte);\
+ _seqbuf[_seqbufptr+2] = (device);\
+ _seqbuf[_seqbufptr+3] = 0;\
+ _SEQ_ADVBUF(4);}
/*
* Patch loading.
*/
-#define SEQ_WRPATCH(patchx, len) {if (_seqbufptr) seqbuf_dump();\
- if (write(seqfd, (char*)(patchx), len)==-1) \
- perror("Write patch: /dev/sequencer");}
-#define SEQ_WRPATCH2(patchx, len) (seqbuf_dump(), write(seqfd, (char*)(patchx), len))
+#define SEQ_WRPATCH(patchx, len) { \
+ if (_seqbufptr) seqbuf_dump(); \
+ if (write(seqfd, (char*)(patchx), len)==-1) \
+ perror("Write patch: /dev/sequencer"); \
+ }
-#endif /* !KERNEL_SPAM */
+#define SEQ_WRPATCH2(patchx, len) \
+ ( seqbuf_dump(), write(seqfd, (char*)(patchx), len) )
-#endif /* !_MACHINE_SOUNDCARD_H_ */
+#endif
+#endif
OpenPOWER on IntegriCloud