initial import
[dosrtxon] / libs / mikmod / drivers / dos / dosgus.h
1 /*      MikMod sound library
2         (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
3         complete list.
4
5         This library is free software; you can redistribute it and/or modify
6         it under the terms of the GNU Library General Public License as
7         published by the Free Software Foundation; either version 2 of
8         the License, or (at your option) any later version.
9
10         This program is distributed in the hope that it will be useful,
11         but WITHOUT ANY WARRANTY; without even the implied warranty of
12         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13         GNU Library General Public License for more details.
14
15         You should have received a copy of the GNU Library General Public
16         License along with this library; if not, write to the Free Software
17         Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18         02111-1307, USA.
19 */
20
21 /*==============================================================================
22
23   $Id$
24
25   libGUS-alike definitions for DOS
26
27 ==============================================================================*/
28
29 #ifndef __DOSGUS_H__
30 #define __DOSGUS_H__
31
32 #include <pc.h>
33 #include "dosdma.h"
34 #include "dosirq.h"
35 #include "libgus.h"
36
37 /* Private header file for a libGUS-alike library for DOS */
38
39 #define JOYSTICK_TIMER                  (gus.port+0x201)        /* 201 */
40 #define JOYSTICK_DATA                   (gus.port+0x201)        /* 201 */
41
42 #define GF1_MIDI_CTRL                   (gus.port+0x100)        /* 3X0 */
43 #define GF1_MIDI_DATA                   (gus.port+0x101)        /* 3X1 */
44
45 #define GF1_VOICESEL                    (gus.port+0x102)        /* 3X2 */
46 #define GF1_REGSEL                      (gus.port+0x103)        /* 3X3 */
47 #define GF1_DATA                        (gus.port+0x104)        /* 3X4 */
48 #define GF1_DATA_LOW                    (gus.port+0x104)        /* 3X4 */
49 #define GF1_DATA_HIGH                   (gus.port+0x105)        /* 3X5 */
50 #define GF1_IRQ_STATUS                  (gus.port+0x006)        /* 2X6 */
51 #define GF1_DRAM                        (gus.port+0x107)        /* 3X7 */
52
53 #define GF1_MIX_CTRL                    (gus.port+0x000)        /* 2X0 */
54 #define GF1_TIMER_CTRL                  (gus.port+0x008)        /* 2X8 */
55 #define GF1_TIMER_DATA                  (gus.port+0x009)        /* 2X9 */
56 #define GF1_IRQ_CTRL                    (gus.port+0x00B)        /* 2XB */
57 #define GF1_REG_CTRL                    (gus.port+0x00F)        /* 2XF */
58
59 #define GF1_REVISION                    (gus.port+0x506)        /* 7X6 */
60
61 /* The GF1 hardware clock rate */
62 #define CLOCK_RATE                      9878400L
63
64 /* GF1 voice-independent registers */
65 #define GF1R_DMA_CONTROL                0x41
66 #define GF1R_DMA_ADDRESS                0x42
67 #define GF1R_DRAM_LOW                   0x43
68 #define GF1R_DRAM_HIGH                  0x44
69
70 #define GF1R_TIMER_CONTROL              0x45
71 #define GF1R_TIMER1                     0x46
72 #define GF1R_TIMER2                     0x47
73
74 #define GF1R_SAMPLE_RATE                0x48
75 #define GF1R_SAMPLE_CONTROL             0x49
76
77 #define GF1R_JOYSTICK                   0x4B
78 #define GF1R_RESET                      0x4C
79
80 /* GF1 voice-specific registers */
81 #define GF1R_VOICE_CONTROL              0x00
82 #define GF1R_FREQUENCY                  0x01
83 #define GF1R_START_HIGH                 0x02
84 #define GF1R_START_LOW                  0x03
85 #define GF1R_END_HIGH                   0x04
86 #define GF1R_END_LOW                    0x05
87 #define GF1R_VOLUME_RATE                0x06
88 #define GF1R_VOLUME_START               0x07
89 #define GF1R_VOLUME_END                 0x08
90 #define GF1R_VOLUME                     0x09
91 #define GF1R_ACC_HIGH                   0x0a
92 #define GF1R_ACC_LOW                    0x0b
93 #define GF1R_BALANCE                    0x0c
94 #define GF1R_VOLUME_CONTROL             0x0d
95 #define GF1R_VOICES                     0x0e
96 #define GF1R_IRQ_SOURCE                 0x0f
97
98 /* Add this to above registers for reading */
99 #define GF1R_READ_MASK                  0x80
100
101 /* MIDI */
102 #define GF1M_MIDI_RESET                 0x03
103 #define GF1M_MIDI_ENABLE_XMIT           0x20
104 #define GF1M_MIDI_ENABLE_RCV            0x80
105
106 #define GF1M_MIDI_RCV_FULL              0x01
107 #define GF1M_MIDI_XMIT_EMPTY            0x02
108 #define GF1M_MIDI_FRAME_ERR             0x10
109 #define GF1M_MIDI_OVERRUN               0x20
110 #define GF1M_MIDI_IRQ_PEND              0x80
111
112 /* Joystick */
113 #define GF1M_JOY_POSITION               0x0f
114 #define GF1M_JOY_BUTTONS                0xf0
115
116 /* GF1_IRQ_STATUS (port 2X6) */
117 #define GF1M_IRQ_MIDI_TX                0x01    /* pending MIDI xmit IRQ */
118 #define GF1M_IRQ_MIDI_RX                0x02    /* pending MIDI recv IRQ */
119 #define GF1M_IRQ_TIMER1                 0x04    /* general purpose timer */
120 #define GF1M_IRQ_TIMER2                 0x08    /* general purpose timer */
121 #define GF1M_IRQ_WAVETABLE              0x20    /* pending wavetable IRQ */
122 #define GF1M_IRQ_ENVELOPE               0x40    /* pending volume envelope IRQ */
123 #define GF1M_IRQ_DMA_COMPLETE           0x80    /* pending dma transfer complete IRQ */
124
125 /* GF1_MIX_CTRL (port 2X0) */
126 #define GF1M_MIXER_NO_LINE_IN           0x01    /* 0: enable */
127 #define GF1M_MIXER_NO_OUTPUT            0x02    /* 0: enable */
128 #define GF1M_MIXER_MIC_IN               0x04    /* 1: enable */
129 #define GF1M_MIXER_GF1_IRQ              0x08    /* 1: enable */
130 #define GF1M_GF1_COMBINED_IRQ           0x10    /* 1: IRQ1 == IRQ2 */
131 #define GF1M_MIDI_LOOPBACK              0x20    /* 1: enable loop back */
132 #define GF1M_CONTROL_SELECT             0x40    /* 0: DMA latches; 1: IRQ latches */
133
134 /* Timer data register (2X9) */
135 #define GF1M_START_TIMER1               0x01
136 #define GF1M_START_TIMER2               0x02
137 #define GF1M_MASK_TIMER1                0x20
138 #define GF1M_MASK_TIMER2                0x40
139 #define GF1M_TIMER_CLRIRQ               0x80
140
141 /* IRQ/DMA control register (2XB) */
142 #define GF1M_IRQ_EQUAL                  0x40
143 #define GF1M_DMA_EQUAL                  0x40
144
145 /* (0x41) DMA control register bits */
146 #define GF1M_DMAR_ENABLE                0x01    /* 1: go */
147 #define GF1M_DMAR_READ                  0x02    /* 1: read (->RAM), 0: write (->DRAM) */
148 #define GF1M_DMAR_CHAN16                0x04    /* 1: 16 bit, 0: 8 bit DMA channel */
149 #define GF1M_DMAR_RATE                  0x18    /* 00: fast, 11: slow */
150 #define GF1M_DMAR_IRQ_ENABLE            0x20    /* 1: enable */
151 #define GF1M_DMAR_IRQ_PENDING           0x40    /* R: DMA irq pending */
152 #define GF1M_DMAR_DATA16                0x40    /* W: 0: 8 bits; 1: 16 bits per sample */
153 #define GF1M_DMAR_TOGGLE_SIGN           0x80    /* W: 1: invert high bit */
154
155 /* DMA transfer rate divisors */
156 #define GF1M_DMAR_RATE0                 0x00    /* Fastest DMA xfer (~650khz) */
157 #define GF1M_DMAR_RATE1                 0x08    /* fastest / 2 */
158 #define GF1M_DMAR_RATE2                 0x10    /* fastest / 4 */
159 #define GF1M_DMAR_RATE3                 0x18    /* Slowest DMA xfer (fastest / 8) */
160
161 /* (0x45) Timer Control */
162 #define GF1M_TIMER1                     0x04    /* Enable timer 1 IRQ */
163 #define GF1M_TIMER2                     0x08    /* Enable timer 2 IRQ */
164
165 /* (0x49) Sampling (ADC) control register */
166 #define GF1M_DMAW_ENABLE                0x01    /* 1: Start sampling */
167 #define GF1M_DMAW_MODE                  0x02    /* 0: mono, 1: stereo */
168 #define GF1M_DMAW_CHAN16                0x04    /* 0: 8 bit, 1: 16 bit */
169 #define GF1M_DMAW_IRQ_ENABLE            0x20    /* 1: enable IRQ */
170 #define GF1M_DMAW_IRQ_PENDING           0x40    /* 1: irq pending */
171 #define GF1M_DMAW_TOGGLE_SIGN           0x80    /* 1: invert sign bit */
172
173 /* (0x4C) GF1 reset register */
174 #define GF1M_MASTER_RESET               0x01    /* 0: hold in reset */
175 #define GF1M_OUTPUT_ENABLE              0x02    /* 1: enable output */
176 #define GF1M_MASTER_IRQ                 0x04    /* 1: master IRQ enable */
177
178 /* (0x0,0x80) Voice control register - GF1R_VOICE_CONTROL */
179 #define GF1VC_STOPPED                   0x01    /* 1: voice has stopped */
180 #define GF1VC_STOP                      0x02    /* 1: stop voice */
181 #define GF1VC_DATA16                    0x04    /* 0: 8 bit, 1: 16 bit */
182 #define GF1VC_LOOP_ENABLE               0x08    /* 1: enable */
183 #define GF1VC_BI_LOOP                   0x10    /* 1: bi directional looping */
184 #define GF1VC_IRQ                       0x20    /* 1: enable voice's wave irq */
185 #define GF1VC_BACKWARD                  0x40    /* 0: increasing, 1: decreasing */
186 #define GF1VC_IRQ_PENDING               0x80    /* 1: wavetable irq pending */
187
188 /* (0x01,0x81) Frequency control */
189 /* Bit 0        - Unused */
190 /* Bits 1-9     - Fractional portion */
191 /* Bits 10-15   - Integer portion */
192
193 /* (0x02,0x82) Accumulator start address - GF1R_START_HIGH */
194 /* Bits 0-11    - HIGH 12 bits of address */
195 /* Bits 12-15   - Unused */
196
197 /* (0x03,0x83) Accumulator start address - GF1R_START_LOW */
198 /* Bits 0-4     - Unused */
199 /* Bits 5-8     - Fractional portion */
200 /* Bits 9-15    - Low 7 bits of integer portion */
201
202 /* (0x04,0x84) Accumulator end address - GF1R_END_HIGH */
203 /* Bits 0-11    - HIGH 12 bits of address */
204 /* Bits 12-15   - Unused */
205
206 /* (0x05,0x85) Accumulator end address - GF1R_END_LOW */
207 /* Bits 0-4     - Unused */
208 /* Bits 5-8     - Fractional portion */
209 /* Bits 9-15    - Low 7 bits of integer portion */
210
211 /* (0x06,0x86) Volume Envelope control register - GF1R_VOLUME_RATE */
212 #define GF1VL_RATE_MANTISSA             0x3f
213 #define GF1VL_RATE_RANGE                0xC0
214
215 /* (0x07,0x87) Volume envelope start - GF1R_VOLUME_START */
216 #define GF1VL_START_MANT                0x0F
217 #define GF1VL_START_EXP                 0xF0
218
219 /* (0x08,0x88) Volume envelope end - GF1R_VOLUME_END */
220 #define GF1VL_END_MANT                  0x0F
221 #define GF1VL_END_EXP                   0xF0
222
223 /* (0x09,0x89) Current volume register - GF1R_VOLUME */
224 /* Bits 0-3     - Unused */
225 /* Bits 4-11    - Mantissa of current volume */
226 /* Bits 10-15   - Exponent of current volume */
227
228 /* (0x0A,0x8A) Accumulator value (high) */
229 /* Bits 0-12    - HIGH 12 bits of current position (a19-a7) */
230
231 /* (0x0B,0x8B) Accumulator value (low) */
232 /* Bits 0-8     - Fractional portion */
233 /* Bits 9-15    - Integer portion of low adress (a6-a0) */
234
235 /* (0x0C,0x8C) Pan (balance) position */
236 /* Bits 0-3     - Balance position 0=full left, 0x0f=full right */
237
238 /* (0x0D,0x8D) Volume control register - GF1R_VOLUME_CONTROL */
239 #define GF1VL_STOPPED                   0x01    /* volume has stopped */
240 #define GF1VL_STOP                      0x02    /* stop volume */
241 #define GF1VL_ROLLOVER                  0x04    /* Roll PAST end & gen IRQ */
242 #define GF1VL_LOOP_ENABLE               0x08    /* 1: enable */
243 #define GF1VL_BI_LOOP                   0x10    /* 1: bi directional looping */
244 #define GF1VL_IRQ                       0x20    /* 1: enable voice's volume irq */
245 #define GF1VL_BACKWARD                  0x40    /* 0: increasing, 1: decreasing */
246 #define GF1VL_IRQ_PENDING               0x80    /* 1: wavetable irq pending */
247
248 /* (0x0E,0x8E) Number of active voices */
249 /* Bits 0-5     - Number of active voices - 1 */
250
251 /* (0x0F,0x8F) Sources of IRQs */
252 /* Bits 0-4     - interrupting voice number */
253 /* Bit 5        - Always a 1 */
254 #define GF1IRQ_VOLUME                   0x40    /* individual voice irq bit */
255 #define GF1IRQ_WAVE                     0x80    /* individual waveform irq bit */
256
257 /* Commands are pooled and executed ON TIMER (1st timer) interrupt.
258  * Currently there is a limit on the number of commands that you can
259  * issue between gus_do_flush (...); this should not be an issue however
260  * because each voice has a limited (little) set of parameters that
261  * you can change (freq, vol, pan... what else?)
262  *
263  * The pool is a pseudo-CPU code that gets executed once per timer interrupt.
264  */
265
266 /* Below are definitions for commands placed in GUS command pool */
267 #define PCMD_NOP                        0x00    /* Traditionally ... */
268 #define PCMD_VOICE                      0x01    /* +B: select voice */
269 #define PCMD_START                      0x02    /* +L: start voice */
270 #define PCMD_STOP                       0x03    /*     stop voice */
271 #define PCMD_FREQ                       0x04    /* +W: set frequence */
272 #define PCMD_VOLUME                     0x05    /* +W: set volume */
273 #define PCMD_VOLUME_PREPARE             0x06    /* +W: prepare to set volume on (soon to follow) kick */
274 #define PCMD_PAN                        0x07    /* +B: set panning */
275 #define PCMD_OFFSET                     0x08    /* +L: set DRAM offset */
276 #define PCMD_STOP_LOOP                  0x09    /*     stop looping */
277
278 #define GUS_VOLCHANGE_RAMP              0x20    /* Volume change ramp speed */
279
280 /* Definition for the boolean type */
281 typedef unsigned char boolean;
282 /* Prototype for functions that do block transfers to GUS DRAM:
283    flags can contain any of the following bits:
284    GUS_WAVE_16BIT    - sample is 16-bit
285    GUS_WAVE_UNSIGNED - do not invert sign bit while downloading
286  */
287 typedef void (*__gus_transfer_func) (unsigned long address,
288                                      unsigned char *source,
289                                      unsigned long size, int flags);
290 typedef void (*__gus_callback) ();
291 typedef void (*__gus_callback_3) (unsigned int, unsigned int, unsigned int);
292
293 /* Structure used to keep track of all on-board GUS memory */
294 typedef struct __struct_gus_mcb {
295         struct __struct_gus_mcb *next;          /* Next MCB in chain */
296         struct __struct_gus_mcb *prev;          /* Previous MCB in chain */
297         unsigned int addr;                      /* GUS DRAM address */
298         unsigned int size;                      /* Memory block size */
299         int free;                               /* 1: block is free */
300 } __gus_mcb;
301
302 /* Structure defining overall GUS state/information */
303 typedef struct __gus_state_s {
304         unsigned int port;                      /* Base I/O port (0x220, 0x240, ...) */
305         unsigned int irq[2];                    /* GF1 IRQ and MIDI IRQ */
306         unsigned int dma[2];                    /* Play / record DMA */
307         unsigned int ram;                       /* Memory size (K), i.e. 256, 1024 etc */
308         unsigned int version;                   /* GUS version (see GUS_CARD_VERSION_XXX in libgus.h */
309         unsigned int freq;                      /* Current mixing frequency */
310         unsigned int voices;                    /* Active voices (14-32) */
311         unsigned int dynmask;                   /* Dynamically allocated voices mask */
312         unsigned int timer_base;                /* The relative timer speed in percents (def: 100) */
313         volatile unsigned int t1_ticks;         /* Incremented per each timer1 tick */
314         volatile unsigned int t2_ticks;         /* Incremented per each timer2 tick */
315         volatile unsigned int t1_countdown;     /* t1_callback is called when this reaches zero */
316         volatile unsigned int t2_countdown;     /* t2_callback is called when this reaches zero */
317         unsigned int t1_multiple;               /* Timer1 handler is called once per such many ticks */
318         unsigned int t2_multiple;               /* Timer2 handler is called once per such many ticks */
319         struct irq_handle *gf1_irq;             /* The interrupt handler for GF1 events */
320         dma_buffer *dma_buff;                   /* Pre-allocated DMA buffer */
321         __gus_callback dma_callback;            /* Routine called at end of DMA transfers */
322         __gus_callback t1_callback;             /* Routine called on Timer1 events */
323         __gus_callback t2_callback;             /* Routine called on Timer1 events */
324         __gus_callback timer_callback;          /* Called once per TEMPO ticks */
325         __gus_callback_3 wt_callback;           /* Routine called on WaveTable events */
326         __gus_callback_3 vl_callback;           /* Routine called on Volume ramp events */
327         __gus_mcb *mcb;                         /* Chained list of memory control blocks */
328         __gus_transfer_func transfer;           /* Best working function for DRAM transfer */
329         gus_instrument_t *instr;                /* The list of registered instruments */
330         unsigned short mixer;                   /* Current mixer register state */
331         unsigned char dma_rate;                 /* One of GF1M_DMAR_RATEX constants defined above */
332         unsigned char timer_ctl;                /* Timer control register value (2x8/2x9) */
333         unsigned char timer_ctl_reg;            /* Timer control register value (GF1/0x45) */
334         boolean ok;                             /* Is the information below okay? */
335         boolean open;                           /* 1 if between gus_open() and gus_close() */
336         boolean ics;                            /* Is it equipped with an ICS mixer? */
337         boolean ics_flipped;                    /* rev 5 (3.7) has flipped R/L mixer */
338         boolean codec;                          /* Is it equipped with a GUS MAX codec? */
339         boolean interwave;                      /* GUS InterWave card */
340         volatile boolean dma_active;            /* DMA is transferring data */
341         volatile boolean cmd_pool_ready;        /* Flush cmd_pool during timer interrupt */
342         unsigned char cmd_voice;                /* Pool selection index cache */
343         unsigned int cmd_pool_top;              /* Command pool top */
344         unsigned char *cmd_pool;                /* Async commands pool */
345         /* The following data is for private use only by interrupt routines! */
346         gus_wave_t *cur_wave[32];               /* Currently played waves */
347         boolean voice_kick[32];                 /* Kick wave on next volume ramp IRQ */
348         unsigned int kick_offs[32];             /* Sample start position on kick */
349         unsigned short cur_vol[32];             /* Current voice volumes */
350         unsigned int cur_voice;                 /* Current voice */
351         unsigned int eow_ignore;                /* Temp ignore end-of-wave IRQ for these voices */
352 } __gus_state;
353
354 extern __gus_state gus;
355 extern void __gus_delay();
356
357 static unsigned long __gus_convert_addr16(unsigned long address)
358 {
359         return ((address & 0x0003ffff) >> 1) | (address & ~0x0003ffff);
360 }
361
362 /* The XXX_slow routines cannot be used outside IRQ handler! */
363 static inline void __gus_outregb_slow(unsigned char reg, unsigned char value)
364 {
365         outportb(GF1_REGSEL, reg);
366         outportb(GF1_DATA_HIGH, value);
367         __gus_delay();
368         outportb(GF1_DATA_HIGH, value);
369 }
370
371 static inline void __gus_outregw_slow(unsigned char reg, unsigned short value)
372 {
373         outportb(GF1_REGSEL, reg);
374         outportw(GF1_DATA, value);
375         __gus_delay();
376         outportw(GF1_DATA, value);
377 }
378
379 static inline void __gus_outregb(unsigned char reg, unsigned char value)
380 {
381         outportb(GF1_REGSEL, reg);
382         outportb(GF1_DATA_HIGH, value);
383 }
384
385 static inline void __gus_outregw(unsigned char reg, unsigned short value)
386 {
387         outportb(GF1_REGSEL, reg);
388         outportw(GF1_DATA, value);
389 }
390
391 static inline unsigned char __gus_inregb(unsigned char reg)
392 {
393         if (reg < 0x10)
394                 reg |= GF1R_READ_MASK;
395         outportb(GF1_REGSEL, reg);
396         return inportb(GF1_DATA_HIGH);
397 }
398
399 static inline unsigned short __gus_inregw(unsigned char reg)
400 {
401         if (reg < 0x10)
402                 reg |= GF1R_READ_MASK;
403         outportb(GF1_REGSEL, reg);
404         return inportw(GF1_DATA);
405 }
406
407 static inline void __gus_set_dram_address(unsigned int address)
408 {
409         __gus_outregb(GF1R_DRAM_HIGH, address >> 16);
410         __gus_outregw(GF1R_DRAM_LOW, address);
411 }
412
413 static inline unsigned char __gus_peek(unsigned int address)
414 {
415         __gus_set_dram_address(address);
416         return inportb(GF1_DRAM);
417 }
418
419 static inline void __gus_poke(unsigned int address, unsigned char value)
420 {
421         __gus_set_dram_address(address);
422         outportb(GF1_DRAM, value);
423 }
424
425 static inline void __gus_select_voice(unsigned char voice)
426 {
427         outportb(GF1_VOICESEL, voice);
428 }
429
430 static inline void __gus_set_current(unsigned char mode,
431                                      unsigned long address)
432 {
433         if (mode & GF1VC_DATA16)
434                 address = __gus_convert_addr16(address);
435         __gus_outregw_slow(GF1R_ACC_HIGH, address >> 11);
436         __gus_outregw_slow(GF1R_ACC_LOW, address << 5);
437 }
438
439 static inline void __gus_set_loop_start(unsigned char mode,
440                                                                                 unsigned long address)
441 {
442         if (mode & GF1VC_DATA16)
443                 address = __gus_convert_addr16(address);
444         __gus_outregw_slow(GF1R_START_HIGH, address >> 11);
445         __gus_outregw_slow(GF1R_START_LOW, address << 5);
446 }
447
448 static inline void __gus_set_loop_end(unsigned char mode,
449                                       unsigned long address)
450 {
451         address--;
452         if (mode & GF1VC_DATA16)
453                 address = __gus_convert_addr16(address);
454         __gus_outregw_slow(GF1R_END_HIGH, address >> 11);
455         __gus_outregw_slow(GF1R_END_LOW, address << 5);
456 }
457
458 static inline void __gus_mixer_output(boolean state)
459 {
460         if (state)
461                 gus.mixer &= ~GF1M_MIXER_NO_OUTPUT;
462         else
463                 gus.mixer |= GF1M_MIXER_NO_OUTPUT;
464         outportb(GF1_MIX_CTRL, gus.mixer);
465         /* Dummy read to avoid touching DMA latches */
466         __gus_inregb(GF1R_BALANCE);
467 }
468
469 /* Inline routines for working with command pools */
470
471 /* WARNING: no bounds checking due to performance reasons */
472 #define __POOL_VALUE(type,value)                                                                \
473   *((unsigned type *)&gus.cmd_pool [gus.cmd_pool_top]) = value; \
474   gus.cmd_pool_top += sizeof (type);
475
476 static inline void __pool_command(unsigned char command)
477 {
478         __POOL_VALUE(char, command);
479 }
480
481 static inline void __pool_command_b(unsigned char command, unsigned char arg)
482 {
483         __POOL_VALUE(char, command);
484         __POOL_VALUE(char, arg);
485 }
486
487 static inline void __pool_command_w(unsigned char command, unsigned short arg)
488 {
489         __POOL_VALUE(char, command);
490         __POOL_VALUE(short, arg);
491 }
492
493 static inline void __pool_command_l(unsigned char command, unsigned long arg)
494 {
495         __POOL_VALUE(char, command);
496         __POOL_VALUE(long, arg);
497 }
498
499 static inline void __pool_select_voice(unsigned char voice)
500 {
501         if (gus.cmd_voice != voice)
502                 __pool_command_b(PCMD_VOICE, gus.cmd_voice = voice);
503 }
504
505 #undef __POOL_VALUE
506
507 #ifdef DEBUG
508 /* Debug dump of GUS DRAM heap */
509 extern void __gus_mem_dump();
510 #endif
511
512 #endif /* __DOSGUS_H__ */
513
514 /* ex:set ts=4: */