TOOLPREFIX = i586-pc-msdosdjgpp-
endif
-inc = -Isrc -Isrc/dos -Ilibs/imago/src -Ilibs/oldmik/src
+inc = -Isrc -Isrc/dos -Ilibs/imago/src -Ilibs/mikmod/include
opt = -O3 -ffast-math
dbg = -g
CC = $(TOOLPREFIX)gcc
AR = $(TOOLPREFIX)ar
CFLAGS = -pedantic -Wall -march=pentium $(dbg) $(opt) $(inc)
-LDFLAGS = libs/imago/imago.dja libs/oldmik/mikmod.dja
+LDFLAGS = libs/imago/imago.dja libs/mikmod/dos/libmikmod.a
$(bin): $(obj) imago mikmod
$(CC) -o $@ -Wl,-Map=ld.map $(obj) $(LDFLAGS)
.PHONY: mikmod
mikmod:
- $(MAKE) -C libs/oldmik -f Makefile.dj
+ $(MAKE) -C libs/mikmod/dos -f Makefile.dj
.PHONY: cleanlibs
cleanlibs:
$(MAKE) -C libs/imago -f Makefile.dj clean
- $(MAKE) -C libs/oldmik -f Makefile.dj clean
+ $(MAKE) -C libs/mikmod/dos -f Makefile.dj clean
.PHONY: clean
.PHONY: cleandep
dbg = -d1
def = -DPNG_NO_SNPRINTF
+!ifdef __UNIX__
+RM = rm -f
+!else
+RM = del
+!endif
+
CC = wcc386
CFLAGS = $(dbg) $(opt) $(def) -zq -bt=dos -Ilibpng -Izlib -Ijpeglib
$(CC) -fo=$@ @cflags.occ $[*
clean: .symbolic
- del *.obj
- del *.occ
- del *.lbc
- del $(alib)
+ $(RM) *.obj
+ $(RM) *.occ
+ $(RM) *.lbc
+ $(RM) $(alib)
--- /dev/null
+# GNU Makefile for building libMikMod using GCC / DJGPP environment
+#
+# Edit config.h to disable/enable certain drivers, etc, if necessary.
+#
+# Targets:
+# - all (default): make libmikmod.a, static MikMod sound library
+# - clean: clean up (remove all generated files)
+
+# Set to 1 for debug build
+DEBUG = 0
+CROSS = i586-pc-msdosdjgpp
+
+# The tools
+ifeq ($(CROSS),)
+CC=gcc
+AS=as
+AR=ar
+RANLIB=ranlib
+else
+CC=$(CROSS)-gcc
+AS=$(CROSS)-as
+AR=$(CROSS)-ar
+RANLIB=$(CROSS)-ranlib
+endif
+CFLAGS = -DMIKMOD_BUILD -DHAVE_CONFIG_H $(INCLUDE)
+INCLUDE = -I../dos -I../drivers/dos -I../include
+ARFLAGS = cr
+
+ifeq ($(DEBUG),1)
+CFLAGS += -g -Wall
+else
+CFLAGS += -O2 -Wall -fomit-frame-pointer -ffast-math
+endif
+
+.SUFFIXES:
+.SUFFIXES: .o .c
+
+COMPILE=$(CC) -c $(CFLAGS)
+
+OBJ=out/dosdma.o \
+ out/dosirq.o \
+ out/dosgus.o \
+ out/drv_ultra.o \
+ out/dossb.o \
+ out/drv_sb.o \
+ out/doswss.o \
+ out/drv_wss.o \
+ out/drv_nos.o \
+ out/strcasecmp.o \
+ out/load_it.o \
+ out/load_mod.o \
+ out/load_s3m.o \
+ out/load_xm.o \
+ out/mmalloc.o \
+ out/mmerror.o \
+ out/mmio.o \
+ out/mdriver.o \
+ out/mdreg.o \
+ out/mmcmp.o \
+ out/pp20.o \
+ out/s404.o \
+ out/xpk.o \
+ out/mloader.o \
+ out/mlreg.o \
+ out/mlutil.o \
+ out/mplayer.o \
+ out/munitrk.o \
+ out/mwav.o \
+ out/npertab.o \
+ out/sloader.o \
+ out/virtch.o \
+ out/virtch2.o \
+ out/virtch_common.o
+# out/mdulaw.o
+
+.PHONY: clean
+
+# The build targets
+TARGETS = libmikmod.a
+
+all: $(TARGETS)
+
+clean:
+ rm -rf out/*.o $(TARGETS)
+
+libmikmod.a: $(OBJ)
+ $(AR) $(ARFLAGS) $@ $^
+ $(RANLIB) $@
+
+HEADER_DEPS=../dos/config.h ../include/mikmod.h ../include/mikmod_internals.h ../include/mikmod_ctype.h
+out/drv_ultra.o: ../drivers/drv_ultra.c $(HEADER_DEPS) ../drivers/dos/libgus.h
+ $(COMPILE) ../drivers/drv_ultra.c -o out/drv_ultra.o
+out/drv_sb.o: ../drivers/drv_sb.c $(HEADER_DEPS) ../drivers/dos/dossb.h
+ $(COMPILE) ../drivers/drv_sb.c -o out/drv_sb.o
+out/drv_wss.o: ../drivers/drv_wss.c $(HEADER_DEPS) ../drivers/dos/doswss.h
+ $(COMPILE) ../drivers/drv_wss.c -o out/drv_wss.o
+out/dosgus.o: ../drivers/dos/dosgus.c $(HEADER_DEPS) ../drivers/dos/libgus.h
+ $(COMPILE) ../drivers/dos/dosgus.c -o out/dosgus.o
+out/dossb.o: ../drivers/dos/dossb.c $(HEADER_DEPS) ../drivers/dos/dossb.h
+ $(COMPILE) ../drivers/dos/dossb.c -o out/dossb.o
+out/doswss.o: ../drivers/dos/doswss.c $(HEADER_DEPS) ../drivers/dos/doswss.h
+ $(COMPILE) ../drivers/dos/doswss.c -o out/doswss.o
+out/dosdma.o: ../drivers/dos/dosdma.c $(HEADER_DEPS) ../drivers/dos/dosdma.h
+ $(COMPILE) ../drivers/dos/dosdma.c -o out/dosdma.o
+out/dosirq.o: ../drivers/dos/dosirq.c $(HEADER_DEPS) ../drivers/dos/dosirq.h
+ $(COMPILE) ../drivers/dos/dosirq.c -o out/dosirq.o
+out/drv_nos.o: ../drivers/drv_nos.c $(HEADER_DEPS)
+ $(COMPILE) ../drivers/drv_nos.c -o out/drv_nos.o
+out/drv_raw.o: ../drivers/drv_raw.c $(HEADER_DEPS)
+ $(COMPILE) ../drivers/drv_raw.c -o out/drv_raw.o
+out/drv_aiff.o: ../drivers/drv_aiff.c $(HEADER_DEPS)
+ $(COMPILE) ../drivers/drv_aiff.c -o out/drv_aiff.o
+out/drv_wav.o: ../drivers/drv_wav.c $(HEADER_DEPS)
+ $(COMPILE) ../drivers/drv_wav.c -o out/drv_wav.o
+out/drv_stdout.o: ../drivers/drv_stdout.c $(HEADER_DEPS)
+ $(COMPILE) ../drivers/drv_stdout.c -o out/drv_stdout.o
+out/drv_pipe.o: ../drivers/drv_pipe.c $(HEADER_DEPS)
+ $(COMPILE) ../drivers/drv_pipe.c -o out/drv_pipe.o
+out/load_669.o: ../loaders/load_669.c $(HEADER_DEPS)
+ $(COMPILE) ../loaders/load_669.c -o out/load_669.o
+out/load_amf.o: ../loaders/load_amf.c $(HEADER_DEPS)
+ $(COMPILE) ../loaders/load_amf.c -o out/load_amf.o
+out/load_asy.o: ../loaders/load_asy.c $(HEADER_DEPS)
+ $(COMPILE) ../loaders/load_asy.c -o out/load_asy.o
+out/load_dsm.o: ../loaders/load_dsm.c $(HEADER_DEPS)
+ $(COMPILE) ../loaders/load_dsm.c -o out/load_dsm.o
+out/load_far.o: ../loaders/load_far.c $(HEADER_DEPS)
+ $(COMPILE) ../loaders/load_far.c -o out/load_far.o
+out/load_gdm.o: ../loaders/load_gdm.c $(HEADER_DEPS)
+ $(COMPILE) ../loaders/load_gdm.c -o out/load_gdm.o
+out/load_gt2.o: ../loaders/load_gt2.c $(HEADER_DEPS)
+ $(COMPILE) ../loaders/load_gt2.c -o out/load_gt2.o
+out/load_it.o: ../loaders/load_it.c $(HEADER_DEPS)
+ $(COMPILE) ../loaders/load_it.c -o out/load_it.o
+out/load_imf.o: ../loaders/load_imf.c $(HEADER_DEPS)
+ $(COMPILE) ../loaders/load_imf.c -o out/load_imf.o
+out/load_m15.o: ../loaders/load_m15.c $(HEADER_DEPS)
+ $(COMPILE) ../loaders/load_m15.c -o out/load_m15.o
+out/load_med.o: ../loaders/load_med.c $(HEADER_DEPS)
+ $(COMPILE) ../loaders/load_med.c -o out/load_med.o
+out/load_mod.o: ../loaders/load_mod.c $(HEADER_DEPS)
+ $(COMPILE) ../loaders/load_mod.c -o out/load_mod.o
+out/load_mtm.o: ../loaders/load_mtm.c $(HEADER_DEPS)
+ $(COMPILE) ../loaders/load_mtm.c -o out/load_mtm.o
+out/load_okt.o: ../loaders/load_okt.c $(HEADER_DEPS)
+ $(COMPILE) ../loaders/load_okt.c -o out/load_okt.o
+out/load_s3m.o: ../loaders/load_s3m.c $(HEADER_DEPS)
+ $(COMPILE) ../loaders/load_s3m.c -o out/load_s3m.o
+out/load_stm.o: ../loaders/load_stm.c $(HEADER_DEPS)
+ $(COMPILE) ../loaders/load_stm.c -o out/load_stm.o
+out/load_stx.o: ../loaders/load_stx.c $(HEADER_DEPS)
+ $(COMPILE) ../loaders/load_stx.c -o out/load_stx.o
+out/load_ult.o: ../loaders/load_ult.c $(HEADER_DEPS)
+ $(COMPILE) ../loaders/load_ult.c -o out/load_ult.o
+out/load_umx.o: ../loaders/load_umx.c $(HEADER_DEPS)
+ $(COMPILE) ../loaders/load_umx.c -o out/load_umx.o
+out/load_uni.o: ../loaders/load_uni.c $(HEADER_DEPS)
+ $(COMPILE) ../loaders/load_uni.c -o out/load_uni.o
+out/load_xm.o: ../loaders/load_xm.c $(HEADER_DEPS)
+ $(COMPILE) ../loaders/load_xm.c -o out/load_xm.o
+out/mmalloc.o: ../mmio/mmalloc.c $(HEADER_DEPS)
+ $(COMPILE) ../mmio/mmalloc.c -o out/mmalloc.o
+out/mmerror.o: ../mmio/mmerror.c $(HEADER_DEPS)
+ $(COMPILE) ../mmio/mmerror.c -o out/mmerror.o
+out/mmio.o: ../mmio/mmio.c $(HEADER_DEPS)
+ $(COMPILE) ../mmio/mmio.c -o out/mmio.o
+out/mmcmp.o: ../depackers/mmcmp.c $(HEADER_DEPS)
+ $(COMPILE) ../depackers/mmcmp.c -o out/mmcmp.o
+out/pp20.o: ../depackers/pp20.c $(HEADER_DEPS)
+ $(COMPILE) ../depackers/pp20.c -o out/pp20.o
+out/s404.o: ../depackers/s404.c $(HEADER_DEPS)
+ $(COMPILE) ../depackers/s404.c -o out/s404.o
+out/xpk.o: ../depackers/xpk.c $(HEADER_DEPS)
+ $(COMPILE) ../depackers/xpk.c -o out/xpk.o
+out/mdriver.o: ../playercode/mdriver.c $(HEADER_DEPS)
+ $(COMPILE) ../playercode/mdriver.c -o out/mdriver.o
+out/mdreg.o: ../playercode/mdreg.c $(HEADER_DEPS)
+ $(COMPILE) ../playercode/mdreg.c -o out/mdreg.o
+out/mdulaw.o: ../playercode/mdulaw.c $(HEADER_DEPS)
+ $(COMPILE) ../playercode/mdulaw.c -o out/mdulaw.o
+out/mloader.o: ../playercode/mloader.c $(HEADER_DEPS)
+ $(COMPILE) ../playercode/mloader.c -o out/mloader.o
+out/mlreg.o: ../playercode/mlreg.c $(HEADER_DEPS)
+ $(COMPILE) ../playercode/mlreg.c -o out/mlreg.o
+out/mlutil.o: ../playercode/mlutil.c $(HEADER_DEPS)
+ $(COMPILE) ../playercode/mlutil.c -o out/mlutil.o
+out/mplayer.o: ../playercode/mplayer.c $(HEADER_DEPS)
+ $(COMPILE) ../playercode/mplayer.c -o out/mplayer.o
+out/munitrk.o: ../playercode/munitrk.c $(HEADER_DEPS)
+ $(COMPILE) ../playercode/munitrk.c -o out/munitrk.o
+out/mwav.o: ../playercode/mwav.c $(HEADER_DEPS)
+ $(COMPILE) ../playercode/mwav.c -o out/mwav.o
+out/npertab.o: ../playercode/npertab.c $(HEADER_DEPS)
+ $(COMPILE) ../playercode/npertab.c -o out/npertab.o
+out/sloader.o: ../playercode/sloader.c $(HEADER_DEPS)
+ $(COMPILE) ../playercode/sloader.c -o out/sloader.o
+out/virtch.o: ../playercode/virtch.c ../playercode/virtch_common.c $(HEADER_DEPS)
+ $(COMPILE) ../playercode/virtch.c -o out/virtch.o
+out/virtch2.o: ../playercode/virtch2.c ../playercode/virtch_common.c $(HEADER_DEPS)
+ $(COMPILE) ../playercode/virtch2.c -o out/virtch2.o
+out/virtch_common.o: ../playercode/virtch_common.c $(HEADER_DEPS)
+ $(COMPILE) ../playercode/virtch_common.c -o out/virtch_common.o
+out/strcasecmp.o: ../posix/strcasecmp.c $(HEADER_DEPS)
+ $(COMPILE) ../posix/strcasecmp.c -o out/strcasecmp.o
--- /dev/null
+ Hello folks !\r
+\r
+\r
+This is libmikmod, version 3.3.10, a portable sound library for DOS.\r
+Comments & feedback are welcome.\r
+\r
+\r
+>> BUILDING LIBMIKMOD\r
+---------------------\r
+\r
+- If you're not building libmikmod for DOS, then you're lost in the sources.\r
+ Go up one directory, and read the main README file.\r
+\r
+This port has been designed to work only with DJGPP compiler. However, it\r
+should not be too complex to make it compile with any other compiler. If you\r
+manage to make libmikmod compile and work with another compiler, we'd like to\r
+hear from you. You'll likely have to write an appropiate makefile, or build\r
+things manually ...\r
+\r
+If you have all proper tools installed, just type\r
+\r
+ make -f Makefile.dj\r
+\r
+To make your library ready to use, copy the files 'libmikmod.a' and\r
+'include/mikmod.h' to your '%DJGPP%/lib' and '%DJGPP%/include' directories\r
+respectively.\r
+\r
+HTML documentation of the library, for programmers, is located in the doc\r
+directory.\r
+\r
+\r
+>> SUPPORTED SOUNDCARDS\r
+-----------------------\r
+\r
+Currently three brands of sound cards are supported under DOS:\r
+\r
+- Gravis Ultrasound and compatibles. Not tested with Interwave cards. If\r
+ somebody has one and can debug the code under Interwave, please drop us a note\r
+ (see email at bottom).\r
+\r
+- SoundBlaster and compatibles. There is only one driver that supports all\r
+ flavours of SoundBlasters:\r
+\r
+ + SB original (8-bit mono, 22KHz)\r
+ + SB 2.0 (DMA autoinit mode -> less clicks, 44KHz 8-bit mono).\r
+ + SB Pro (8-bit 22KHz stereo, 8-bit 44KHz mono)\r
+ + SB 16+ (8- and 16-bit stereo, up to 44Khz both)\r
+\r
+ Note that SB16 should cover AWE32/64 as well...\r
+\r
+- Windows Sound System and compatibles. Most today SoundBlaster clones\r
+ (including the CS4236B card used for testing) emulates (in hardware) WSS.\r
+ That's because Creative Labs copyrighted the SB16 interface and thus\r
+ clonemakers cannot do similar hardware without violating their rights, so\r
+ most of them only emulate SB Pro (see above).\r
+\r
+ WSS supports up to 44KHz 16-bit stereo. The following playback rates (in both\r
+ 8- and 16-bit) are supported: 5510, 6620, 8000, 9600, 11025, 16000, 18900,\r
+ 22050, 27420, 32000, 33075, 37800, 44100 and 48000 Hz.\r
+\r
+\r
+>> THANKS\r
+---------\r
+\r
+We would like to thank everyone who contributed to libmikmod. Their names\r
+are in the AUTHORS file for the significative contributions, but some other\r
+names can be found in the NEWS file. Thanks a lot ! Keeping libmikmod alive\r
+wouldn't be much fun without you.\r
+\r
+\r
+>> LICENSE\r
+----------\r
+\r
+The libmikmod sound library is covered by the GNU Library General Public\r
+License as published by the Free Software Fundation (you'll find it in the\r
+file COPYING.LIB) ; either version 2 of the licence, or (at your option)\r
+any later version.\r
+\r
+The GNU Lesser General Public License, version 2.1, in file COPYING.LESSER, can\r
+be considered as a later version of the LGPL, and is strongly recommended for\r
+people who will embed libmikmod in their application as a shared library.\r
+\r
+\r
+>> CONTACT AND DOWNLOAD INFO\r
+----------------------------\r
+\r
+libmikmod home page is located at SourceForge:\r
+\r
+ http://mikmod.sourceforge.net/\r
+ http://sourceforge.net/projects/mikmod/\r
+\r
+There's a mailing list (mikmod-public) for discussing the development\r
+of MikMod (new features, bugs, ideas...) Look for more information on\r
+the web site.\r
+\r
+Things related to the DOS port should also be forwarded to the DOS\r
+``portmaster'', Andrew Zabolotny, at: bit@eltech.ru\r
+\r
+\r
+>> LAST NOTES\r
+-------------\r
+\r
+We hope you'll enjoy using this version of libmikmod as well as we enjoyed\r
+debugging and improving it.\r
+\r
+-- Miodrag ("Miod") Vallat, 10/19/1999\r
+ miodrag@mikmod.darkorb.net\r
+\r
+ Andrew Zabolotny\r
+ bit@eltech.ru\r
--- /dev/null
+/* config.h.in. Generated manually for DJGPP. */
+
+/* djgpp-v2.04 and newer provide snprintf() and vsnprintf().
+ * djgpp-v2.05 is already released, so let's enable them by
+ * default here. */
+/* Define if you have the snprintf function. */
+#define HAVE_SNPRINTF
+/* Define if you have the vsnprintf function. */
+#define HAVE_VSNPRINTF
+
+/* Define to disable the high quality mixer (build only with the standart mixer) */
+/*#define NO_HQMIXER*/
+
+/* Define if your system supports binary pipes (i.e. Unix) */
+/*#define DRV_PIPE*/
+/* Define if you want support for output to stdout */
+/*#define DRV_STDOUT*/
+
+/* Define if you want an .aiff file writer driver */
+#undef DRV_AIFF
+/* Define if you want a raw pcm data file writer driver */
+#undef DRV_RAW
+/* Define if you want a .wav file writer driver */
+#undef DRV_WAV
+
+/* Define if the Gravis UltraSound driver is compiled */
+#define DRV_ULTRA
+/* Define if the Windows Sound System driver is compiled */
+#define DRV_WSS
+/* Define if the SoundBlaster driver is compiled */
+#define DRV_SB
+
+/* Define if you want a debug version of the library */
+#undef MIKMOD_DEBUG
+
+/* Define if you have the ANSI C header files. */
+#define STDC_HEADERS
+
+/* Define if you have the setenv function. */
+#define HAVE_SETENV
+
+/* Define if you have the srandom function. */
+#define HAVE_SRANDOM
+
+/* Define if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H
+
+/* Define if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H
+
+/* Define if you have the <malloc.h> header file. */
+#define HAVE_MALLOC_H
+
+/* Define if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H
+
--- /dev/null
+/*
+ Implementation of DMA routines on DOS
+ Copyright (C) 1999 by Andrew Zabolotny, <bit@eltech.ru>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "dosdma.h"
+
+#include <go32.h> /* includes sys/version.h (djgpp >= 2.02) */
+#include <dos.h>
+#include <dpmi.h>
+#include <sys/nearptr.h>
+#include <malloc.h>
+#include "mikmod.h" /* for MikMod_malloc() & co */
+
+/* BUG WARNING: there is an error in DJGPP libraries <= 2.01:
+ * src/libc/dpmi/api/d0102.s loads the selector and allocsize
+ * arguments in the wrong order. DJGPP >= 2.02 have it fixed. */
+#if (!defined(__DJGPP_MINOR__) || (__DJGPP_MINOR__+0) < 2)
+#warning __dpmi_resize_dos_memory() from DJGPP <= 2.01 is broken!
+#endif
+
+__dma_regs dma[8] = {
+/* *INDENT-OFF* */
+ {DMA_ADDR_0, DMA_PAGE_0, DMA_SIZE_0,
+ DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG},
+ {DMA_ADDR_1, DMA_PAGE_1, DMA_SIZE_1,
+ DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG},
+
+ {DMA_ADDR_2, DMA_PAGE_2, DMA_SIZE_2,
+ DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG},
+ {DMA_ADDR_3, DMA_PAGE_3, DMA_SIZE_3,
+ DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG},
+
+ {DMA_ADDR_4, 0, DMA_SIZE_4,
+ DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG},
+ {DMA_ADDR_5, DMA_PAGE_5, DMA_SIZE_5,
+ DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG},
+
+ {DMA_ADDR_6, DMA_PAGE_6, DMA_SIZE_6,
+ DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG},
+ {DMA_ADDR_7, DMA_PAGE_7, DMA_SIZE_7,
+ DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG}
+/* *INDENT-ON* */
+};
+
+static int __initialized = 0;
+static int __buffer_count = 0;
+static __dpmi_meminfo __locked_data;
+
+int dma_initialize()
+{
+ if (!__djgpp_nearptr_enable())
+ return 0;
+
+ /* Trick: Avoid re-setting DS selector limit on each memory allocation
+ call */
+ __djgpp_selector_limit = 0xffffffff;
+
+ __locked_data.address = __djgpp_base_address + (unsigned long)&dma;
+ __locked_data.size = sizeof(dma);
+ if (__dpmi_lock_linear_region(&__locked_data))
+ return 0;
+
+ return (__initialized = 1);
+}
+
+void dma_finalize()
+{
+ if (!__initialized)
+ return;
+ __dpmi_unlock_linear_region(&__locked_data);
+ __djgpp_nearptr_disable();
+}
+
+dma_buffer *dma_allocate(unsigned int channel, unsigned int size)
+{
+ int parsize = (size + 15) >> 4; /* size in paragraphs */
+ int par = 0; /* Real-mode paragraph */
+ int selector = 0; /* Protected-mode selector */
+ int mask = channel <= 3 ? 0xfff : 0x1fff; /* Alignment mask in para. */
+ int allocsize = parsize; /* Allocated size in paragraphs */
+ int count; /* Try count */
+ int bound = 0; /* Nearest bound address */
+ int maxsize; /* Maximal possible block size */
+ dma_buffer *buffer = NULL;
+ __dpmi_meminfo buff_info, struct_info;
+
+ if (!dma_initialize())
+ return NULL;
+
+ /* Loop until we'll get a properly aligned memory block */
+ for (count = 8; count; count--) {
+ int resize = (selector != 0);
+
+ /* Try first to resize (possibly previously) allocated block */
+ if (resize) {
+ maxsize = (bound + parsize) - par;
+ if (maxsize > parsize * 2)
+ maxsize = parsize * 2;
+ if (maxsize == allocsize)
+ resize = 0;
+ else {
+ allocsize = maxsize;
+ if (__dpmi_resize_dos_memory(selector, allocsize, &maxsize) !=
+ 0) resize = 0;
+ }
+ }
+
+ if (!resize) {
+ if (selector)
+ __dpmi_free_dos_memory(selector), selector = 0;
+ par = __dpmi_allocate_dos_memory(allocsize, &selector);
+ }
+
+ if ((par == 0) || (par == -1))
+ goto exit;
+
+ /* If memory block contains a properly aligned portion, quit loop */
+ bound = (par + mask + 1) & ~mask;
+ if (par + parsize <= bound)
+ break;
+ if (bound + parsize <= par + allocsize) {
+ par = bound;
+ break;
+ }
+ }
+ if (!count) {
+ __dpmi_free_dos_memory(selector);
+ goto exit;
+ }
+
+ buffer = (dma_buffer *) MikMod_malloc(sizeof(dma_buffer));
+ buffer->linear = (unsigned char *)(__djgpp_conventional_base + bound * 16);
+ buffer->physical = bound * 16;
+ buffer->size = parsize * 16;
+ buffer->selector = selector;
+ buffer->channel = channel;
+
+ buff_info.address = buffer->physical;
+ buff_info.size = buffer->size;
+ /*
+ Don't pay attention to return code since under plain DOS it often
+ returns error (at least under HIMEM/CWSDPMI and EMM386/DPMI)
+ */
+ __dpmi_lock_linear_region(&buff_info);
+
+ /* Lock the DMA buffer control structure as well */
+ struct_info.address = __djgpp_base_address + (unsigned long)buffer;
+ struct_info.size = sizeof(dma_buffer);
+ if (__dpmi_lock_linear_region(&struct_info)) {
+ __dpmi_unlock_linear_region(&buff_info);
+ __dpmi_free_dos_memory(selector);
+ MikMod_free(buffer);
+ buffer = NULL;
+ goto exit;
+ }
+
+ exit:
+ if (buffer)
+ __buffer_count++;
+ else if (--__buffer_count == 0)
+ dma_finalize();
+ return buffer;
+}
+
+void dma_free(dma_buffer * buffer)
+{
+ __dpmi_meminfo buff_info;
+
+ if (!buffer)
+ return;
+
+ buff_info.address = buffer->physical;
+ buff_info.size = buffer->size;
+ __dpmi_unlock_linear_region(&buff_info);
+
+ __dpmi_free_dos_memory(buffer->selector);
+ MikMod_free(buffer);
+
+ if (--__buffer_count == 0)
+ dma_finalize();
+}
+
+void dma_start(dma_buffer * buffer, unsigned long count, unsigned char mode)
+{
+ /* Disable interrupts */
+ int old_ints = disable();
+ dma_disable(buffer->channel);
+ dma_set_mode(buffer->channel, mode);
+ dma_clear_ff(buffer->channel);
+ dma_set_addr(buffer->channel, buffer->physical);
+ dma_clear_ff(buffer->channel);
+ dma_set_count(buffer->channel, count);
+ dma_enable(buffer->channel);
+ /* Re-enable interrupts */
+ if (old_ints)
+ enable();
+}
+
+/* ex:set ts=4: */
--- /dev/null
+/*
+ Interface for DMA routines on DOS
+ Copyright (C) 1999 by Andrew Zabolotny, <bit@eltech.ru>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __DOSDMA_H__
+#define __DOSDMA_H__
+
+#include <pc.h>
+
+#define DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */
+#define DMA2_BASE 0xC0 /* 16 bit master DMA, ch 4(=slave input)..7 */
+
+#define DMA1_CMD_REG 0x08 /* command register (w) */
+#define DMA1_STAT_REG 0x08 /* status register (r) */
+#define DMA1_REQ_REG 0x09 /* request register (w) */
+#define DMA1_MASK_REG 0x0A /* single-channel mask (w) */
+#define DMA1_MODE_REG 0x0B /* mode register (w) */
+#define DMA1_CLEAR_FF_REG 0x0C /* clear pointer flip-flop (w) */
+#define DMA1_TEMP_REG 0x0D /* Temporary Register (r) */
+#define DMA1_RESET_REG 0x0D /* Master Clear (w) */
+#define DMA1_CLR_MASK_REG 0x0E /* Clear Mask */
+#define DMA1_MASK_ALL_REG 0x0F /* all-channels mask (w) */
+
+#define DMA2_CMD_REG 0xD0 /* command register (w) */
+#define DMA2_STAT_REG 0xD0 /* status register (r) */
+#define DMA2_REQ_REG 0xD2 /* request register (w) */
+#define DMA2_MASK_REG 0xD4 /* single-channel mask (w) */
+#define DMA2_MODE_REG 0xD6 /* mode register (w) */
+#define DMA2_CLEAR_FF_REG 0xD8 /* clear pointer flip-flop (w) */
+#define DMA2_TEMP_REG 0xDA /* Temporary Register (r) */
+#define DMA2_RESET_REG 0xDA /* Master Clear (w) */
+#define DMA2_CLR_MASK_REG 0xDC /* Clear Mask */
+#define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */
+
+#define DMA_ADDR_0 0x00 /* DMA address registers */
+#define DMA_ADDR_1 0x02
+#define DMA_ADDR_2 0x04
+#define DMA_ADDR_3 0x06
+#define DMA_ADDR_4 0xC0
+#define DMA_ADDR_5 0xC4
+#define DMA_ADDR_6 0xC8
+#define DMA_ADDR_7 0xCC
+
+#define DMA_SIZE_0 0x01 /* DMA transfer size registers */
+#define DMA_SIZE_1 0x03
+#define DMA_SIZE_2 0x05
+#define DMA_SIZE_3 0x07
+#define DMA_SIZE_4 0xC2
+#define DMA_SIZE_5 0xC6
+#define DMA_SIZE_6 0xCA
+#define DMA_SIZE_7 0xCE
+
+#define DMA_PAGE_0 0x87 /* DMA page registers */
+#define DMA_PAGE_1 0x83
+#define DMA_PAGE_2 0x81
+#define DMA_PAGE_3 0x82
+#define DMA_PAGE_5 0x8B
+#define DMA_PAGE_6 0x89
+#define DMA_PAGE_7 0x8A
+
+#define DMA_MODE_AUTOINIT 0x10 /* Auto-init mode bit */
+#define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */
+#define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */
+#define DMA_MODE_CASCADE 0xC0 /* pass thru DREQ->HRQ, DACK<-HLDA only */
+
+/* Indexable specific DMA registers */
+typedef struct __dma_regs_s {
+ unsigned char addr; /* DMA transfer address register */
+ unsigned char page; /* DMA page register */
+ unsigned char size; /* DMA transfer size register */
+ unsigned char mask; /* DMA mask/unmask register */
+ unsigned char flip; /* DMA flip-flop reset register */
+ unsigned char mode; /* DMA mode register */
+} __dma_regs;
+
+extern __dma_regs dma[8];
+
+/* Enable a specific DMA channel */
+static inline void dma_enable(unsigned int channel)
+{
+ outportb(dma[channel].mask, channel & 3);
+}
+
+/* Disable a specific DMA channel */
+static inline void dma_disable(unsigned int channel)
+{
+ outportb(dma[channel].mask, (channel & 3) | 0x04);
+}
+
+/* Clear the 'DMA Flip Flop' flag */
+static inline void dma_clear_ff(unsigned int channel)
+{
+ outportb(dma[channel].flip, 0);
+}
+
+/* Set mode for a specific DMA channel */
+static inline void dma_set_mode(unsigned int channel, char mode)
+{
+ outportb(dma[channel].mode, mode | (channel & 3));
+}
+
+/* Set DMA page register */
+static inline void dma_set_page(unsigned int channel, char page)
+{
+ if (channel > 3)
+ page &= 0xfe;
+ outportb(dma[channel].page, page);
+}
+
+/*
+ Set transfer address & page bits for specific DMA channel.
+ Assumes dma flipflop is clear.
+*/
+static inline void dma_set_addr(unsigned int channel, unsigned int address)
+{
+ unsigned char dma_reg = dma[channel].addr;
+ dma_set_page(channel, address >> 16);
+ if (channel <= 3) {
+ outportb(dma_reg, (address) & 0xff);
+ outportb(dma_reg, (address >> 8) & 0xff);
+ } else {
+ outportb(dma_reg, (address >> 1) & 0xff);
+ outportb(dma_reg, (address >> 9) & 0xff);
+ }
+}
+
+/*
+ Set transfer size for a specific DMA channel.
+ Assumes dma flip-flop is clear.
+*/
+static inline void dma_set_count(unsigned int channel, unsigned int count)
+{
+ unsigned char dma_reg = dma[channel].size;
+ count--; /* number of DMA transfers is bigger by one */
+ if (channel > 3)
+ count >>= 1;
+ outportb(dma_reg, (count) & 0xff);
+ outportb(dma_reg, (count >> 8) & 0xff);
+}
+
+/*
+ Query the number of bytes left to transfer.
+ Assumes DMA flip-flop is clear.
+*/
+static inline int dma_get_count(unsigned int channel)
+{
+ unsigned char dma_reg = dma[channel].size;
+
+ /* using short to get 16-bit wrap around */
+ unsigned short count;
+ count = inportb(dma_reg);
+ count |= inportb(dma_reg) << 8;
+ count++;
+ return (channel <= 3) ? count : (count << 1);
+}
+
+typedef struct dma_buffer_s {
+ unsigned char *linear; /* Linear address */
+ unsigned long physical; /* Physical address */
+ unsigned long size; /* Buffer size */
+ unsigned short selector; /* The selector assigned to this memory */
+ unsigned char channel; /* The DMA channel */
+} dma_buffer;
+
+/* Allocate a block of memory suitable for using as a DMA buffer */
+extern dma_buffer *dma_allocate(unsigned int channel, unsigned int size);
+/* Deallocate a DMA buffer */
+extern void dma_free(dma_buffer * buffer);
+/* Start DMA transfer to or from given buffer */
+extern void dma_start(dma_buffer * buffer, unsigned long count,
+ unsigned char mode);
+
+#endif /* __DOSDMA_H__ */
+
+/* ex:set ts=4: */
--- /dev/null
+/* MikMod sound library
+ (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
+ complete list.
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+/*==============================================================================
+
+ Driver for GUS cards under DOS
+ Written by Andrew Zabolotny <bit@eltech.ru>
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef DRV_ULTRA
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <dos.h>
+#include <dpmi.h>
+#include <sys/farptr.h>
+#include <sys/nearptr.h>
+#include <go32.h>
+#include <string.h>
+
+#include "dosgus.h"
+#include "mikmod.h" /* for MikMod_malloc() & co */
+
+/********************************************* Private variables/routines *****/
+
+/* The Gravis Ultrasound state/info */
+__gus_state gus;
+
+/* Try to avoid holes in DRAM less than this size */
+#define DRAM_HOLE_THRESHOLD 8192
+/* If hole is larger than that, create a free block describing it */
+#define DRAM_SPLIT_THRESHOLD 64
+/* The size of DMA buffer used for RAM->DRAM transfers */
+#define GF1_DMA_BUFFER_SIZE 8192
+
+/* Debug macro: useful to change screen locations when some event occurs */
+#ifdef MIKMOD_DEBUG
+# define DEBUG_PRINT(x) printf x;
+# define DEBUG_OFS(addr, attr) \
+ { \
+ unsigned short x; \
+ _dosmemgetw (0xb8780 + addr*2, 1, &x); \
+ if ((x >> 8) != attr) x = '0'; \
+ x = ((x + 1) & 0xff) | (attr << 8); \
+ _dosmemputw (&x, 1, 0xb8780 + addr*2); \
+ }
+#else
+# define DEBUG_PRINT(x)
+# define DEBUG_OFS(addr, attr)
+#endif
+
+static unsigned short __gus_volume_table[512] = {
+ 0x0000, 0x7000, 0x7ff0, 0x8800, 0x8ff0, 0x9400, 0x9800, 0x9c00,
+ 0x9ff0, 0xa200, 0xa400, 0xa600, 0xa800, 0xaa00, 0xac00, 0xae00,
+ 0xaff0, 0xb100, 0xb200, 0xb300, 0xb400, 0xb500, 0xb600, 0xb700,
+ 0xb800, 0xb900, 0xba00, 0xbb00, 0xbc00, 0xbd00, 0xbe00, 0xbf00,
+ 0xbff0, 0xc080, 0xc100, 0xc180, 0xc200, 0xc280, 0xc300, 0xc380,
+ 0xc400, 0xc480, 0xc500, 0xc580, 0xc600, 0xc680, 0xc700, 0xc780,
+ 0xc800, 0xc880, 0xc900, 0xc980, 0xca00, 0xca80, 0xcb00, 0xcb80,
+ 0xcc00, 0xcc80, 0xcd00, 0xcd80, 0xce00, 0xce80, 0xcf00, 0xcf80,
+ 0xcff0, 0xd040, 0xd080, 0xd0c0, 0xd100, 0xd140, 0xd180, 0xd1c0,
+ 0xd200, 0xd240, 0xd280, 0xd2c0, 0xd300, 0xd340, 0xd380, 0xd3c0,
+ 0xd400, 0xd440, 0xd480, 0xd4c0, 0xd500, 0xd540, 0xd580, 0xd5c0,
+ 0xd600, 0xd640, 0xd680, 0xd6c0, 0xd700, 0xd740, 0xd780, 0xd7c0,
+ 0xd800, 0xd840, 0xd880, 0xd8c0, 0xd900, 0xd940, 0xd980, 0xd9c0,
+ 0xda00, 0xda40, 0xda80, 0xdac0, 0xdb00, 0xdb40, 0xdb80, 0xdbc0,
+ 0xdc00, 0xdc40, 0xdc80, 0xdcc0, 0xdd00, 0xdd40, 0xdd80, 0xddc0,
+ 0xde00, 0xde40, 0xde80, 0xdec0, 0xdf00, 0xdf40, 0xdf80, 0xdfc0,
+ 0xdff0, 0xe020, 0xe040, 0xe060, 0xe080, 0xe0a0, 0xe0c0, 0xe0e0,
+ 0xe100, 0xe120, 0xe140, 0xe160, 0xe180, 0xe1a0, 0xe1c0, 0xe1e0,
+ 0xe200, 0xe220, 0xe240, 0xe260, 0xe280, 0xe2a0, 0xe2c0, 0xe2e0,
+ 0xe300, 0xe320, 0xe340, 0xe360, 0xe380, 0xe3a0, 0xe3c0, 0xe3e0,
+ 0xe400, 0xe420, 0xe440, 0xe460, 0xe480, 0xe4a0, 0xe4c0, 0xe4e0,
+ 0xe500, 0xe520, 0xe540, 0xe560, 0xe580, 0xe5a0, 0xe5c0, 0xe5e0,
+ 0xe600, 0xe620, 0xe640, 0xe660, 0xe680, 0xe6a0, 0xe6c0, 0xe6e0,
+ 0xe700, 0xe720, 0xe740, 0xe760, 0xe780, 0xe7a0, 0xe7c0, 0xe7e0,
+ 0xe800, 0xe820, 0xe840, 0xe860, 0xe880, 0xe8a0, 0xe8c0, 0xe8e0,
+ 0xe900, 0xe920, 0xe940, 0xe960, 0xe980, 0xe9a0, 0xe9c0, 0xe9e0,
+ 0xea00, 0xea20, 0xea40, 0xea60, 0xea80, 0xeaa0, 0xeac0, 0xeae0,
+ 0xeb00, 0xeb20, 0xeb40, 0xeb60, 0xeb80, 0xeba0, 0xebc0, 0xebe0,
+ 0xec00, 0xec20, 0xec40, 0xec60, 0xec80, 0xeca0, 0xecc0, 0xece0,
+ 0xed00, 0xed20, 0xed40, 0xed60, 0xed80, 0xeda0, 0xedc0, 0xede0,
+ 0xee00, 0xee20, 0xee40, 0xee60, 0xee80, 0xeea0, 0xeec0, 0xeee0,
+ 0xef00, 0xef20, 0xef40, 0xef60, 0xef80, 0xefa0, 0xefc0, 0xefe0,
+ 0xeff0, 0xf010, 0xf020, 0xf030, 0xf040, 0xf050, 0xf060, 0xf070,
+ 0xf080, 0xf090, 0xf0a0, 0xf0b0, 0xf0c0, 0xf0d0, 0xf0e0, 0xf0f0,
+ 0xf100, 0xf110, 0xf120, 0xf130, 0xf140, 0xf150, 0xf160, 0xf170,
+ 0xf180, 0xf190, 0xf1a0, 0xf1b0, 0xf1c0, 0xf1d0, 0xf1e0, 0xf1f0,
+ 0xf200, 0xf210, 0xf220, 0xf230, 0xf240, 0xf250, 0xf260, 0xf270,
+ 0xf280, 0xf290, 0xf2a0, 0xf2b0, 0xf2c0, 0xf2d0, 0xf2e0, 0xf2f0,
+ 0xf300, 0xf310, 0xf320, 0xf330, 0xf340, 0xf350, 0xf360, 0xf370,
+ 0xf380, 0xf390, 0xf3a0, 0xf3b0, 0xf3c0, 0xf3d0, 0xf3e0, 0xf3f0,
+ 0xf400, 0xf410, 0xf420, 0xf430, 0xf440, 0xf450, 0xf460, 0xf470,
+ 0xf480, 0xf490, 0xf4a0, 0xf4b0, 0xf4c0, 0xf4d0, 0xf4e0, 0xf4f0,
+ 0xf500, 0xf510, 0xf520, 0xf530, 0xf540, 0xf550, 0xf560, 0xf570,
+ 0xf580, 0xf590, 0xf5a0, 0xf5b0, 0xf5c0, 0xf5d0, 0xf5e0, 0xf5f0,
+ 0xf600, 0xf610, 0xf620, 0xf630, 0xf640, 0xf650, 0xf660, 0xf670,
+ 0xf680, 0xf690, 0xf6a0, 0xf6b0, 0xf6c0, 0xf6d0, 0xf6e0, 0xf6f0,
+ 0xf700, 0xf710, 0xf720, 0xf730, 0xf740, 0xf750, 0xf760, 0xf770,
+ 0xf780, 0xf790, 0xf7a0, 0xf7b0, 0xf7c0, 0xf7d0, 0xf7e0, 0xf7f0,
+ 0xf800, 0xf810, 0xf820, 0xf830, 0xf840, 0xf850, 0xf860, 0xf870,
+ 0xf880, 0xf890, 0xf8a0, 0xf8b0, 0xf8c0, 0xf8d0, 0xf8e0, 0xf8f0,
+ 0xf900, 0xf910, 0xf920, 0xf930, 0xf940, 0xf950, 0xf960, 0xf970,
+ 0xf980, 0xf990, 0xf9a0, 0xf9b0, 0xf9c0, 0xf9d0, 0xf9e0, 0xf9f0,
+ 0xfa00, 0xfa10, 0xfa20, 0xfa30, 0xfa40, 0xfa50, 0xfa60, 0xfa70,
+ 0xfa80, 0xfa90, 0xfaa0, 0xfab0, 0xfac0, 0xfad0, 0xfae0, 0xfaf0,
+ 0xfb00, 0xfb10, 0xfb20, 0xfb30, 0xfb40, 0xfb50, 0xfb60, 0xfb70,
+ 0xfb80, 0xfb90, 0xfba0, 0xfbb0, 0xfbc0, 0xfbd0, 0xfbe0, 0xfbf0,
+ 0xfc00, 0xfc10, 0xfc20, 0xfc30, 0xfc40, 0xfc50, 0xfc60, 0xfc70,
+ 0xfc80, 0xfc90, 0xfca0, 0xfcb0, 0xfcc0, 0xfcd0, 0xfce0, 0xfcf0,
+ 0xfd00, 0xfd10, 0xfd20, 0xfd30, 0xfd40, 0xfd50, 0xfd60, 0xfd70,
+ 0xfd80, 0xfd90, 0xfda0, 0xfdb0, 0xfdc0, 0xfdd0, 0xfde0, 0xfdf0,
+ 0xfe00, 0xfe10, 0xfe20, 0xfe30, 0xfe40, 0xfe50, 0xfe60, 0xfe70,
+ 0xfe80, 0xfe90, 0xfea0, 0xfeb0, 0xfec0, 0xfed0, 0xfee0, 0xfef0,
+ 0xff00, 0xff10, 0xff20, 0xff30, 0xff40, 0xff50, 0xff60, 0xff70,
+ 0xff80, 0xff90, 0xffa0, 0xffb0, 0xffc0, 0xffd0, 0xffe0, 0xfff0
+};
+
+/* Wait a bit for GUS before doing something
+ * Mark function as volatile: don't allow it to be inlined.
+ * It *should* be slow, no need to make it work faster :-)
+ */
+#if !defined(__GNUC__) || (__GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ == 0)
+# define _func_noinline volatile /* match original code */
+# define _func_noclone
+#else
+/* avoid warnings from newer gcc:
+ * "function definition has qualified void return type" and
+ * function return types not compatible due to 'volatile' */
+# define _func_noinline __attribute__((__noinline__))
+# if (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 5)
+# define _func_noclone
+# else
+# define _func_noclone __attribute__((__noclone__))
+# endif
+#endif
+_func_noinline
+_func_noclone
+ void __gus_delay()
+{
+ inportb(GF1_MIX_CTRL);
+ inportb(GF1_MIX_CTRL);
+ inportb(GF1_MIX_CTRL);
+ inportb(GF1_MIX_CTRL);
+ inportb(GF1_MIX_CTRL);
+ inportb(GF1_MIX_CTRL);
+ inportb(GF1_MIX_CTRL);
+ inportb(GF1_MIX_CTRL);
+}
+
+static void __gus_stop_controller(unsigned char gf1reg)
+{
+ register unsigned char value = __gus_inregb(gf1reg);
+ __gus_outregb(gf1reg, (value | GF1VC_STOPPED | GF1VC_STOP) &
+ ~(GF1VC_IRQ_PENDING | GF1VC_IRQ));
+}
+
+/* Returns 1 if volume is already at given position */
+static boolean __gus_volume_ramp_to(unsigned short volume,
+ unsigned char rate,
+ unsigned char vol_ctrl)
+{
+ int svol = __gus_inregw(GF1R_VOLUME) & 0xfff0;
+ int evol = volume;
+
+ /* First of all, disable volume ramp */
+ __gus_stop_controller(GF1R_VOLUME_CONTROL);
+
+ /* If voice is stopped, set the volume to zero and return */
+ if (__gus_inregb(GF1R_VOICE_CONTROL) & GF1VC_STOPPED) {
+ __gus_outregw(GF1R_VOLUME, 0);
+ return 1;
+ }
+
+ /* Avoid clicks when volume ramp goes too high or too low */
+ if (svol < 0x0400)
+ svol = 0x0400;
+ if (svol > 0xfc00)
+ svol = 0xfc00;
+ if (evol < 0x0400)
+ evol = 0x0400;
+ if (evol > 0xfc00)
+ evol = 0xfc00;
+
+ /* Adjust start/end positions */
+ if (svol > evol) {
+ unsigned short tmp = evol;
+ evol = svol;
+ svol = tmp;
+ vol_ctrl |= GF1VL_BACKWARD;
+ }
+
+ /* If we already are (near) the target volume, quit */
+ if (evol - svol < 0x1000) {
+ __gus_outregw(GF1R_VOLUME, volume);
+ return 1;
+ }
+
+ __gus_outregb(GF1R_VOLUME_START, svol >> 8);
+ __gus_outregb(GF1R_VOLUME_END, evol >> 8);
+ __gus_outregb(GF1R_VOLUME_RATE, rate);
+ __gus_outregb_slow(GF1R_VOLUME_CONTROL, vol_ctrl);
+ return 0;
+}
+
+static inline void __gus_stop_voice()
+{
+ __gus_stop_controller(GF1R_VOICE_CONTROL);
+ __gus_outregb_slow(GF1R_VOICE_CONTROL, GF1VC_STOPPED | GF1VC_STOP);
+}
+
+/* The GUS IRQ handler */
+static void gf1_irq()
+{
+ unsigned char irq_source; /* The contents of GF1_IRQ_STATUS register */
+ boolean timer_cb = 0; /* Call timer callback function */
+
+ DEBUG_OFS(0, 0xCE)
+ gus.eow_ignore = 0;
+ while ((irq_source = inportb(GF1_IRQ_STATUS))) {
+ DEBUG_OFS(1, 0xCE)
+
+ if (irq_source & GF1M_IRQ_DMA_COMPLETE) {
+ DEBUG_OFS(4, 0x9F)
+ /* reset the IRQ pending bit */
+ __gus_inregb(GF1R_DMA_CONTROL);
+ gus.dma_active = 0;
+
+ if (gus.dma_callback)
+ gus.dma_callback();
+ }
+
+ if (irq_source & (GF1M_IRQ_WAVETABLE | GF1M_IRQ_ENVELOPE)) {
+ unsigned char vcirq;
+ unsigned int done_mask = 0;
+
+ /* IRQ bits are inverse (i.e. 0 = IRQ pending) */
+ while ((vcirq = __gus_inregb(GF1R_IRQ_SOURCE) ^
+ (GF1IRQ_WAVE | GF1IRQ_VOLUME)) &
+ (GF1IRQ_WAVE | GF1IRQ_VOLUME)) {
+ unsigned long voice = (vcirq & 0x1f);
+ unsigned char voice_ctl, volume_ctl;
+ unsigned int voice_mask = (1 << voice);
+
+ /* Don't handle more than one IRQ from same voice */
+ if (done_mask & voice_mask)
+ continue;
+
+ done_mask |= voice_mask;
+
+ /* Read voice/volume selection registers */
+ __gus_select_voice(voice);
+ voice_ctl = __gus_inregb(GF1R_VOICE_CONTROL);
+ volume_ctl = __gus_inregb(GF1R_VOLUME_CONTROL);
+
+ if ((vcirq & GF1IRQ_WAVE) && (gus.wt_callback)
+ && !(gus.eow_ignore & voice_mask)) {
+ DEBUG_OFS(5, 0xAF)
+ gus.wt_callback(voice, voice_ctl, volume_ctl);
+ }
+
+ if ((vcirq & GF1IRQ_VOLUME) && (gus.vl_callback)) {
+ DEBUG_OFS(6, 0xAF)
+ gus.vl_callback(voice, voice_ctl, volume_ctl);
+ }
+ }
+ }
+
+ /* Reset timers that sent this IRQ */
+ if (irq_source & (GF1M_IRQ_TIMER1 | GF1M_IRQ_TIMER2)) {
+ unsigned char timer_ctl = gus.timer_ctl_reg;
+
+ if (irq_source & GF1M_IRQ_TIMER1)
+ timer_ctl &= ~GF1M_TIMER1;
+
+ if (irq_source & GF1M_IRQ_TIMER2)
+ timer_ctl &= ~GF1M_TIMER2;
+
+ __gus_outregb_slow(GF1R_TIMER_CONTROL, timer_ctl);
+ __gus_outregb_slow(GF1R_TIMER_CONTROL, gus.timer_ctl_reg);
+ }
+
+ if (irq_source & GF1M_IRQ_TIMER1)
+ if (--gus.t1_countdown == 0) {
+ gus.t1_countdown = gus.t1_multiple;
+ gus.t1_ticks++;
+
+ DEBUG_OFS(2, 0xCF)
+
+ if (gus.t1_callback) {
+ timer_cb = 1;
+ gus.t1_callback();
+ }
+ }
+
+ if (irq_source & GF1M_IRQ_TIMER2)
+ if (--gus.t2_countdown == 0) {
+ gus.t2_countdown = gus.t2_multiple;
+ gus.t2_ticks++;
+
+ DEBUG_OFS(3, 0xCF)
+
+ if (gus.t2_callback)
+ gus.t2_callback();
+ }
+#if 0
+ /* The following are not used and implemented yet */
+ if (irq_source & (GF1M_IRQ_MIDI_TX | GF1M_IRQ_MIDI_RX)) {
+ }
+#endif
+ }
+
+ irq_ack(gus.gf1_irq);
+
+ if (timer_cb && gus.timer_callback)
+ gus.timer_callback();
+}
+
+static void gf1_irq_end()
+{
+}
+
+static boolean __gus_detect()
+{
+ /* A relatively relaxed autodetection;
+ We don't count on DRAM: GUS PnP could not have it
+ (although its anyway bad for us)
+ */
+ __gus_select_voice(0);
+ __gus_stop_voice();
+ __gus_outregw(GF1R_FREQUENCY, 0x1234);
+ __gus_outregw(GF1R_VOLUME, 0x5670);
+ return ((__gus_inregw(GF1R_FREQUENCY) & 0xfffe) == 0x1234)
+ && ((__gus_inregw(GF1R_VOLUME) & 0xfff0) == 0x5670);
+}
+
+static void __gus_reset(boolean reset_io_dma)
+{
+ static unsigned char irqctl[16] = { 0, 0, 1, 3, 0, 2, 0, 4, 0, 0, 0, 5, 6, 0, 0, 7 };
+ static unsigned char dmactl[8] = { 0, 1, 0, 2, 0, 3, 4, 5 };
+ unsigned char irqtmp, dmatmp;
+
+ /* Disable interrupts while resetting to avoid spurious IRQs */
+ int i, timer, old_ints = disable();
+
+ /* Stop the timer so that GUS IRQ won't clobber registers */
+ timer = (gus.timer_ctl_reg & GF1M_TIMER1);
+ if (timer)
+ gus_timer_stop();
+
+ gus.dma_active = 0;
+
+ __gus_outregb(GF1R_RESET, 0);
+ for (i = 0; i < 10; i++)
+ __gus_delay();
+ __gus_outregb(GF1R_RESET, GF1M_MASTER_RESET);
+ for (i = 0; i < 10; i++)
+ __gus_delay();
+
+ outportb(GF1_MIDI_CTRL, GF1M_MIDI_RESET);
+ for (i = 0; i < 10; i++)
+ __gus_delay();
+ outportb(GF1_MIDI_CTRL, 0);
+
+ /* Reset all IRQ sources */
+ __gus_outregb(GF1R_DMA_CONTROL, 0);
+ __gus_outregb(GF1R_TIMER_CONTROL, 0);
+ __gus_outregb(GF1R_SAMPLE_CONTROL, 0);
+
+ /* Reset all voices */
+ gus_reset(gus.voices, gus.dynmask);
+
+ /* Flush any pending IRQs */
+ inportb(GF1_IRQ_STATUS);
+ __gus_inregb(GF1R_DMA_CONTROL);
+ __gus_inregb(GF1R_SAMPLE_CONTROL);
+ __gus_inregb(GF1R_IRQ_SOURCE);
+
+ if (reset_io_dma) {
+ /* Now set up the GUS card to required IRQs and DMAs */
+ if (gus.irq[0] == gus.irq[1])
+ irqtmp = irqctl[gus.irq[0]] | GF1M_IRQ_EQUAL;
+ else
+ irqtmp = irqctl[gus.irq[0]] | (irqctl[gus.irq[1]] << 3);
+
+ if (gus.dma[0] == gus.dma[1])
+ dmatmp = dmactl[gus.dma[0]] | GF1M_DMA_EQUAL;
+ else
+ dmatmp = dmactl[gus.dma[0]] | (dmactl[gus.dma[1]] << 3);
+
+ /* Reset IRQs if possible */
+ gus.mixer =
+ GF1M_MIXER_NO_LINE_IN | GF1M_MIXER_NO_OUTPUT | GF1M_MIXER_GF1_IRQ;
+ if (gus.version >= GUS_CARD_VERSION_CLASSIC1) {
+ outportb(GF1_REG_CTRL, 0x05);
+ outportb(GF1_MIX_CTRL, gus.mixer);
+ outportb(GF1_IRQ_CTRL, 0x00); /* Reset IRQs */
+ outportb(GF1_REG_CTRL, 0x00);
+ }
+
+ /* Set up DMA channels: NEVER disable MIXER_GF1_IRQ in the future */
+ outportb(GF1_MIX_CTRL, gus.mixer);
+ outportb(GF1_IRQ_CTRL, dmatmp);
+
+ /* Set up IRQ channels */
+ outportb(GF1_MIX_CTRL, gus.mixer | GF1M_CONTROL_SELECT);
+ outportb(GF1_IRQ_CTRL, irqtmp);
+ }
+
+ __gus_outregb(GF1R_RESET, GF1M_MASTER_RESET | GF1M_OUTPUT_ENABLE | GF1M_MASTER_IRQ);
+ __gus_delay();
+
+ /* Flush IRQs again */
+ inportb(GF1_IRQ_STATUS);
+ __gus_inregb(GF1R_DMA_CONTROL);
+ __gus_inregb(GF1R_SAMPLE_CONTROL);
+ __gus_inregb(GF1R_IRQ_SOURCE);
+
+ _irq_ack(gus.irq[0]);
+ _irq_ack(gus.irq[1]);
+
+ if (timer)
+ gus_timer_continue();
+
+ if (old_ints)
+ enable();
+
+ /* Enable output */
+ __gus_mixer_output(1);
+}
+
+/* Transfer a block of data from GUS DRAM to main RAM through port I/O */
+static void __gus_transfer_io_in(unsigned long address, unsigned char *source,
+ unsigned long size)
+{
+ while (size) {
+ register unsigned int size64k;
+
+ size64k = 0x10000 - (address & 0xffff);
+ if (size64k > size)
+ size64k = size;
+ size -= size64k;
+
+ __gus_outregb(GF1R_DRAM_HIGH, address >> 16);
+ while (size64k--) {
+ __gus_outregw(GF1R_DRAM_LOW, address++);
+ *source++ = inportb(GF1_DRAM);
+ }
+ }
+}
+
+/* Transfer a block of data into GUS DRAM through port I/O */
+static void __gus_transfer_io(unsigned long address, unsigned char *source,
+ unsigned long size, int flags)
+{
+ while (size) {
+ register unsigned int size64k;
+
+ size64k = 0x10000 - (address & 0xffff);
+ if (size64k > size)
+ size64k = size;
+ size -= size64k;
+
+ __gus_outregb(GF1R_DRAM_HIGH, address >> 16);
+ if (flags & GUS_WAVE_INVERT)
+ if (flags & GUS_WAVE_16BIT)
+ while (size64k-- && size64k--) {
+ __gus_outregw(GF1R_DRAM_LOW, address++);
+ outportb(GF1_DRAM, *source++);
+ __gus_outregw(GF1R_DRAM_LOW, address++);
+ outportb(GF1_DRAM, (*source++) ^ 0x80);
+ } else
+ while (size64k--) {
+ __gus_outregw(GF1R_DRAM_LOW, address++);
+ outportb(GF1_DRAM, (*source++) ^ 0x80);
+ } else
+ while (size64k--) {
+ __gus_outregw(GF1R_DRAM_LOW, address++);
+ outportb(GF1_DRAM, *source++);
+ }
+ }
+}
+
+/* Wait for DMA transfer to finish between 8-9 1/18sec timer ticks */
+static int __gus_wait_dma()
+{
+ unsigned long timer;
+ _farsetsel(_dos_ds);
+ timer = _farnspeekl(0x46c);
+ while (gus.dma_active)
+ if (_farnspeekl(0x46c) - timer > 8) {
+ /* Force DMA abort since something went wrong */
+ __gus_reset(0);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Transfer a block of data into GUS DRAM through DMA controller */
+static void __gus_transfer_dma(unsigned long address, unsigned char *source,
+ unsigned long size, int flags)
+{
+ unsigned char dma_control;
+ unsigned long bytes_left;
+ unsigned long cur_size;
+ unsigned long dest_addr;
+
+ if ((gus.dma[0] > 3) || (flags & GUS_WAVE_16BIT))
+ size = (size + 1) & ~1;
+
+ bytes_left = size;
+ while (bytes_left) {
+ __gus_wait_dma();
+
+ cur_size = gus.dma_buff->size;
+ if (cur_size > bytes_left)
+ cur_size = bytes_left;
+ bytes_left -= cur_size;
+ dest_addr = address;
+
+ if (gus.dma_buff->linear != source)
+ memmove(gus.dma_buff->linear, source, cur_size);
+ source += cur_size;
+ address += cur_size;
+
+ /* Disable GUS -> DMA tie */
+ __gus_outregb(GF1R_DMA_CONTROL, 0);
+ __gus_delay();
+
+ /* Set up the DMA */
+ dma_start(gus.dma_buff, cur_size, DMA_MODE_WRITE);
+ gus.dma_active = 1;
+
+ /* Reset the DMA IRQ pending bit if set */
+ __gus_inregb(GF1R_DMA_CONTROL);
+
+ /* The 16-bit DMA channels needs a slightly different approach */
+ dma_control = GF1M_DMAR_ENABLE | GF1M_DMAR_IRQ_ENABLE | gus.dma_rate;
+ if (gus.dma[0] > 3) {
+ dest_addr = __gus_convert_addr16(dest_addr);
+ dma_control |= GF1M_DMAR_CHAN16;
+ }
+
+ __gus_outregw(GF1R_DMA_ADDRESS, dest_addr >> 4);
+
+ if (flags & GUS_WAVE_16BIT)
+ dma_control |= GF1M_DMAR_DATA16;
+ if (flags & GUS_WAVE_INVERT)
+ dma_control |= GF1M_DMAR_TOGGLE_SIGN;
+
+ /* Tell GUS to start transfer */
+ __gus_outregb(GF1R_DMA_CONTROL, dma_control);
+ }
+}
+
+static void __gus_detect_version()
+{
+ unsigned char tmp;
+
+ switch (gus.version = inportb(GF1_REVISION)) {
+ case 5:
+ gus.version = GUS_CARD_VERSION_CLASSIC_ICS;
+ gus.ics = 1;
+ gus.ics_flipped = 1;
+ break;
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ gus.version = GUS_CARD_VERSION_CLASSIC_ICS;
+ gus.ics = 1;
+ break;
+ case 10:
+ gus.version = GUS_CARD_VERSION_MAX;
+ gus.codec = 1;
+ break;
+ case 11:
+ gus.version = GUS_CARD_VERSION_MAX1;
+ gus.codec = 1;
+ break;
+ case 0x30:
+ gus.version = GUS_CARD_VERSION_ACE;
+ break;
+ case 0x50:
+ gus.version = GUS_CARD_VERSION_EXTREME;
+ break;
+ case 0xff:
+ /* Pre-3.7 board */
+ outportb(GF1_REG_CTRL, 0x20);
+ tmp = inportb(GF1_REG_CTRL);
+ if ((tmp != 0xff) && (tmp & 0x06))
+ gus.version = GUS_CARD_VERSION_CLASSIC1;
+ else
+ gus.version = GUS_CARD_VERSION_CLASSIC;
+ break;
+ default:
+ /* Hmm... unknown revision. Assume a safe Classic model */
+#ifdef MIKMOD_DEBUG
+ fprintf(stderr, "libgus: Unknown board revision (%02x)\n",
+ gus.version);
+#endif
+ gus.version = GUS_CARD_VERSION_CLASSIC;
+ break;
+ }
+}
+
+static void __gus_detect_transfer()
+{
+ unsigned char *outbuff, *inbuff;
+ unsigned int i, j, seed = 0x13243546;
+ __gus_transfer_func func;
+
+#define TRANSFER_SIZE 0x4000
+
+ outbuff = (unsigned char *) MikMod_malloc(TRANSFER_SIZE);
+ inbuff = (unsigned char *) MikMod_malloc(TRANSFER_SIZE);
+
+ /* Suppose we have an malfunctioning GUS */
+ gus.transfer = NULL;
+
+ for (i = (gus.dma_buff ? 0 : 4); i <= 4; i++) {
+ switch (i) {
+ case 0:
+ gus.dma_rate = GF1M_DMAR_RATE0;
+ func = __gus_transfer_dma;
+ break;
+ case 1:
+ gus.dma_rate = GF1M_DMAR_RATE1;
+ func = __gus_transfer_dma;
+ break;
+ case 2:
+ gus.dma_rate = GF1M_DMAR_RATE2;
+ func = __gus_transfer_dma;
+ break;
+ case 3:
+ gus.dma_rate = GF1M_DMAR_RATE3;
+ func = __gus_transfer_dma;
+ break;
+ case 4:
+ func = __gus_transfer_io;
+ break;
+ }
+
+ /* Fill data array each time with pseudo-random values */
+ for (j = 0; j < TRANSFER_SIZE; j++)
+ outbuff[j] = seed, seed =
+ ((seed + 358979323) ^ (seed >> 16)) * 314159265;
+
+ /* Transfer the random array to GUS */
+ /* Poke a security fence around dest block */
+ __gus_poke(0x100 - 1, 0xAA);
+ __gus_poke(0x100 - 2, 0x55);
+ __gus_poke(0x100 + TRANSFER_SIZE + 0, 0xAA);
+ __gus_poke(0x100 + TRANSFER_SIZE + 1, 0x55);
+
+ func(0x100, outbuff, TRANSFER_SIZE, 0);
+
+ if (__gus_wait_dma() == 0) {
+ /* Check if the security fence was not damaged */
+ if ((__gus_peek(0x100 - 1) != 0xAA)
+ || (__gus_peek(0x100 - 2) != 0x55)
+ || (__gus_peek(0x100 + TRANSFER_SIZE + 0) != 0xAA)
+ || (__gus_peek(0x100 + TRANSFER_SIZE + 1) != 0x55))
+ continue;
+
+ /* Now check if GUS DRAM really data that we expects to be transferred */
+ __gus_transfer_io_in(0x100, inbuff, TRANSFER_SIZE);
+ if (memcmp(outbuff, inbuff, TRANSFER_SIZE) == 0) {
+ gus.transfer = func;
+ break;
+ }
+ }
+ }
+
+#undef TRANSFER_SIZE
+
+ MikMod_free(inbuff);
+ MikMod_free(outbuff);
+}
+
+static void __gus_detect_memory()
+{
+ unsigned int size;
+ for (size = 0; size < 1024; size += 256) {
+ __gus_poke(size * 1024, 0xaa);
+ if (__gus_peek(size * 1024) != 0xaa)
+ break;
+ __gus_poke(size * 1024, 0x55);
+ if (__gus_peek(size * 1024) != 0x55)
+ break;
+ }
+ gus.ram = size;
+}
+
+static void __gus_init()
+{
+ char *gusenv = getenv("ULTRASND");
+
+ memset((void *)&gus, 0, sizeof(gus));
+ gus.cmd_voice = -1;
+
+ if (!gusenv)
+ return;
+
+ sscanf(gusenv, "%x,%d,%d,%d,%d", &gus.port, &gus.dma[0], &gus.dma[1],
+ &gus.irq[0], &gus.irq[1]);
+
+ /* A relaxed sanity check */
+ if ((gus.port < 0x100) || (gus.port > 0x1000)
+ || (gus.irq[0] < 2) || (gus.irq[0] > 15)
+ || (gus.irq[1] < 2) || (gus.irq[1] > 15)
+ || (gus.dma[0] < 0) || (gus.dma[0] > 7)
+ || (gus.dma[1] < 0) || (gus.dma[1] > 7))
+ return;
+
+ gus.voices = 32;
+ gus.timer_ctl = GF1M_MASK_TIMER1 | GF1M_MASK_TIMER2;
+
+ /* Detect if the card is really there */
+ if (__gus_detect() == 0)
+ return;
+
+ /* Detect the version of Gravis Ultrasound */
+ __gus_detect_version();
+
+ /* Reset the card */
+ __gus_reset(1);
+
+ /* Detect the amount of on-board memory */
+ __gus_detect_memory();
+
+ gus.ok = 1;
+}
+
+static void __gus_kick(gus_wave_t * wave, unsigned int wave_offset)
+{
+ unsigned char vc;
+
+ vc = GF1VC_IRQ;
+ if (wave->format & GUS_WAVE_16BIT)
+ vc |= GF1VC_DATA16;
+ if (wave->format & GUS_WAVE_BACKWARD)
+ vc |= GF1VC_BACKWARD;
+ if (wave->format & GUS_WAVE_LOOP) {
+ vc |= GF1VC_LOOP_ENABLE;
+ if (wave->format & GUS_WAVE_BIDIR)
+ vc |= GF1VC_BI_LOOP;
+ }
+ __gus_set_loop_start(vc, (wave->begin.memory << 4) + wave->loop_start);
+ if (wave->format & GUS_WAVE_LOOP)
+ __gus_set_loop_end(vc, (wave->begin.memory << 4) + wave->loop_end);
+ else
+ __gus_set_loop_end(vc, (wave->begin.memory + wave->size) << 4);
+ __gus_set_current(vc, (wave->begin.memory << 4) + wave_offset + 100);
+ __gus_outregb_slow(GF1R_VOICE_CONTROL, vc);
+}
+
+/* Timer 1 callback function (updates voices) */
+static void __gus_timer_update()
+{
+ gus_wave_t *wave;
+ unsigned long wave_offset;
+ unsigned char *src, *top;
+ unsigned int vmask = (1 << gus.cur_voice);
+
+ if (!gus.cmd_pool_ready)
+ return;
+
+ __gus_select_voice(gus.cur_voice);
+ wave_offset = 0;
+ src = gus.cmd_pool;
+ top = gus.cmd_pool + gus.cmd_pool_top;
+
+#define GET_B *src
+#define GET_W *((unsigned short *)src)
+#define GET_L *((unsigned long *)src)
+
+ while (src < top) {
+ __gus_delay();
+ switch (GET_B++) {
+ case PCMD_VOICE:
+ __gus_select_voice(gus.cur_voice = GET_B++);
+ vmask = (1 << gus.cur_voice);
+ break;
+ case PCMD_FREQ:
+ /* __gus_outregw(GF1R_FREQUENCY, GET_W++);*/
+ __gus_outregw(GF1R_FREQUENCY, *(unsigned short *)src);
+ src += 2;
+ break;
+ case PCMD_PAN:
+ __gus_outregb(GF1R_BALANCE, GET_B++);
+ break;
+ case PCMD_VOLUME:
+ __gus_volume_ramp_to(gus.cur_vol[gus.cur_voice] =
+ /* GET_W++, GUS_VOLCHANGE_RAMP, GF1VL_IRQ);*/
+ *(unsigned short *)src, GUS_VOLCHANGE_RAMP, GF1VL_IRQ);
+ src += 2;
+ break;
+ case PCMD_VOLUME_PREPARE:
+ /* gus.cur_vol[gus.cur_voice] = GET_W++;*/
+ gus.cur_vol[gus.cur_voice] = *(unsigned short *)src;
+ src += 2;
+ break;
+ case PCMD_OFFSET:
+ /* wave_offset = GET_L++;*/
+ wave_offset = *(unsigned long *)src;
+ src += 4;
+ break;
+ case PCMD_START:
+ /* wave = (gus_wave_t *) GET_L++;*/
+ wave = (gus_wave_t *) *(unsigned long *)src;
+ src += 4;
+ gus.cur_wave[gus.cur_voice] = wave;
+ gus.kick_offs[gus.cur_voice] = wave_offset;
+ if (__gus_volume_ramp_to(0, GUS_VOLCHANGE_RAMP, GF1VL_IRQ)) {
+ __gus_kick(wave, wave_offset);
+ __gus_volume_ramp_to(gus.cur_vol[gus.cur_voice],
+ GUS_VOLCHANGE_RAMP, GF1VL_IRQ);
+ } else
+ gus.voice_kick[gus.cur_voice] = 1;
+ wave_offset = 0;
+ gus.eow_ignore |= vmask;
+ break;
+ case PCMD_STOP:
+ /* If volume is close to nothing, abort immediately instead of
+ ramping */
+ gus.cur_vol[gus.cur_voice] = 0;
+ gus.cur_wave[gus.cur_voice] = NULL;
+ if (__gus_volume_ramp_to(0, GUS_VOLCHANGE_RAMP, GF1VL_IRQ))
+ __gus_stop_voice();
+ break;
+ case PCMD_STOP_LOOP:
+ __gus_outregb_slow(GF1R_VOICE_CONTROL,
+ (__gus_inregb(GF1R_VOICE_CONTROL) | GF1VC_IRQ)
+ & ~GF1VC_LOOP_ENABLE);
+ __gus_outregb_slow(GF1R_VOLUME_CONTROL,
+ __gus_inregb(GF1R_VOLUME_CONTROL) &
+ ~GF1VL_ROLLOVER);
+ break;
+ default:
+ /* Alarm! Break out immediately */
+ src = top;
+ break;
+ }
+ }
+
+#undef GET_B
+#undef GET_W
+#undef GET_L
+
+ gus.cmd_pool_ready = 0;
+ gus.cmd_pool_top = 0;
+}
+
+static void __gus_wavetable_update(unsigned int voice, unsigned int voice_ctl,
+ unsigned int volume_ctl)
+{
+ gus_wave_t *wave = gus.cur_wave[voice];
+
+ if (!wave || !(wave->format & GUS_WAVE_LOOP)) {
+ __gus_stop_voice();
+ gus.cur_wave[voice] = NULL;
+ gus.cur_vol[voice] = 0;
+ if (__gus_volume_ramp_to(0, GUS_VOLCHANGE_RAMP, GF1VL_IRQ))
+ __gus_stop_voice();
+ }
+}
+
+static void __gus_volume_update(unsigned int voice, unsigned int voice_ctl,
+ unsigned int volume_ctl)
+{
+ __gus_volume_ramp_to(gus.cur_vol[voice], GUS_VOLCHANGE_RAMP, GF1VL_IRQ);
+ if (!gus.cur_wave[voice])
+ __gus_stop_voice();
+ else if (gus.voice_kick[voice])
+ __gus_kick(gus.cur_wave[voice], gus.kick_offs[voice]);
+ gus.voice_kick[voice] = 0;
+}
+
+/***************************************************** GUS memory manager *****/
+
+/* Mark all GUS memory as available */
+static void __gus_mem_clear()
+{
+ __gus_mcb *cur = gus.mcb;
+
+ while (cur) {
+ __gus_mcb *next = cur->next;
+ if (cur != gus.mcb)
+ MikMod_free(cur);
+ cur = next;
+ }
+
+ if (!gus.mcb)
+ gus.mcb = (__gus_mcb *) MikMod_malloc(sizeof(__gus_mcb));
+
+ gus.mcb->next = gus.mcb->prev = NULL;
+ gus.mcb->addr = 0;
+ gus.mcb->size = gus.ram * 1024;
+ gus.mcb->free = 1;
+}
+
+/* Return amount of free memory */
+static unsigned int __gus_mem_get_free()
+{
+ __gus_mcb *cur = gus.mcb;
+ unsigned int size = 0;
+
+ if (!gus.open)
+ return gus.ram * 1024;
+
+ while (cur) {
+ if (cur->free)
+ size += cur->size;
+ cur = cur->next;
+ }
+
+ return size;
+}
+
+/* Return largest size for a 8-bit sample */
+static unsigned int __gus_mem_get_free_8()
+{
+ __gus_mcb *cur = gus.mcb;
+ unsigned int size = 0;
+
+ if (!gus.open)
+ return 0;
+
+ while (cur) {
+ if (cur->free && (cur->size > size))
+ size = cur->size;
+ cur = cur->next;
+ }
+
+ return size;
+}
+
+/* Return largest size for a 16-bit sample */
+static unsigned int __gus_mem_get_free_16()
+{
+ __gus_mcb *cur = gus.mcb;
+ unsigned int size = 0;
+
+ if (!gus.open)
+ return 0;
+
+ while (cur) {
+ if (cur->free) {
+ unsigned int size16 = cur->size;
+ unsigned int tmp;
+ /* 16-bit samples cannot cross 256K boundaries */
+ tmp = 0x40000 - (cur->addr & 0x3ffff);
+ if (size16 > tmp)
+ size16 = tmp;
+ /* 16-bit samples should be aligned on a 32-byte boundary */
+ size16 -= (32 - cur->addr) & 0x1f;
+
+ if (size16 > size)
+ size = size16;
+
+ /* Now try vice versa: skip a portion of aligned memory */
+ size16 =
+ (cur->addr + cur->size) - ((cur->addr + 0x3ffff) & ~0x3ffff);
+ if ((size16 < 0x7fffffff) && (size16 > size))
+ size = size16;
+ }
+ cur = cur->next;
+ }
+
+ return size;
+}
+
+/* Allocate a segment of GUS DRAM for a sample with given bits per sample.
+ * The algorithm tries to find the smallest free block that fits requested
+ * size; but if found free block is larger by some (large) delta than
+ * requested block size, the largest possible block is preffered.
+ */
+static unsigned int __gus_mem_alloc(unsigned int size, int bits16)
+{
+ __gus_mcb *cur = gus.mcb;
+ __gus_mcb *best_max = NULL, *best_min = NULL;
+ unsigned int best_max_delta = 0, best_min_delta = 0xffffffff;
+ unsigned int best_max_prefix = 0, best_min_prefix = 0;
+ unsigned int memaddr, memsize;
+
+ if (!gus.open || !size || (bits16 && size > 0x40000))
+ return -1;
+
+ /* Round block size up to nearest acceptable DMA bound */
+ if (bits16)
+ size = (size + 0x1f) & ~0x1f;
+ else
+ size = (size + 0x0f) & ~0x0f;
+
+ while (cur) {
+ if (cur->free) {
+ unsigned char fits = 0;
+
+ memsize = cur->size;
+ memaddr = cur->addr;
+
+ if (bits16) {
+ /* 16-bit samples cannot cross 256K boundaries */
+ unsigned int tmp = 256 * 1024 - (memaddr & 0x3ffff);
+ if (memsize > tmp)
+ memsize = tmp;
+ /* 16-bit samples should be aligned on a 32-byte boundary */
+ memsize -= (32 - memaddr) & 0x1f;
+ memaddr = (memaddr + 0x1f) & ~0x1f;
+ }
+
+ /* If block fits, analyze it */
+ if (size <= memsize)
+ fits = 1;
+ /* Look if we still can complete the request by creating a free
+ block */
+ else if (size <= cur->size) {
+ /* Align start address to next 256k boundary */
+ unsigned int endaddr = cur->addr + cur->size;
+ memaddr = (cur->addr + 0x3ffff) & ~0x3ffff;
+ /* Can we split current block by inserting a free block at the
+ beginning? */
+ if ((memaddr < endaddr) && (memaddr + size <= endaddr))
+ fits = 1;
+ }
+
+ if (fits) {
+ unsigned int size_delta = cur->size - size;
+ unsigned int size_prefix = memaddr - cur->addr;
+ if (size_delta < best_min_delta)
+ best_min = cur, best_min_delta =
+ size_delta, best_min_prefix = size_prefix;
+ if (size_delta > best_max_delta)
+ best_max = cur, best_max_delta =
+ size_delta, best_max_prefix = size_prefix;
+ }
+ }
+
+ cur = cur->next;
+ }
+
+ if (!best_min)
+ return -1;
+
+ /* If minimal block that fits is too large, use largest block that fits */
+ /* But if using the maximal block is going to create a small hole, forget
+ it */
+ if ((best_max_prefix == 0)
+ || (best_max_prefix >= DRAM_HOLE_THRESHOLD)
+ || (best_min_prefix != 0))
+ if (
+ ((best_min_delta < DRAM_HOLE_THRESHOLD) &&
+ (best_max_delta >= DRAM_HOLE_THRESHOLD)) ||
+ ((best_min_prefix > 0) && (best_min_prefix < DRAM_HOLE_THRESHOLD)
+ && ((best_max_prefix == 0) ||
+ (best_max_prefix > best_min_prefix))) ||
+ ((best_min_prefix != 0) && (best_max_prefix == 0))) {
+ best_min = best_max;
+ best_min_delta = best_max_delta;
+ best_min_prefix = best_max_prefix;
+ }
+
+ /* Compute the DRAM address to return */
+ memaddr = best_min->addr + best_min_prefix;
+ if (bits16)
+ memaddr = (memaddr + 0x1f) & ~0x1f;
+ else
+ memaddr = (memaddr + 0x0f) & ~0x0f;
+
+ /* If we have a considerable hole at the beginning of sample,
+ create a free node describing the hole */
+ if (memaddr - best_min->addr >= DRAM_SPLIT_THRESHOLD) {
+ __gus_mcb *newmcb = (__gus_mcb *) MikMod_malloc(sizeof(__gus_mcb));
+ newmcb->prev = best_min->prev;
+ newmcb->next = best_min;
+ newmcb->addr = best_min->addr;
+ newmcb->size = memaddr - best_min->addr;
+ newmcb->free = 1;
+ best_min->addr = memaddr;
+ best_min->size -= newmcb->size;
+ best_min->prev = newmcb;
+ if (newmcb->prev)
+ newmcb->prev->next = newmcb;
+ }
+
+ /* Compute the size of hole at the end of block */
+ memsize = (best_min->addr + best_min->size) - (memaddr + size);
+
+ /* Split the block if the block is larger than requested amount */
+ if (memsize > DRAM_SPLIT_THRESHOLD) {
+ /* The next node cannot be free since free blocks are always glued
+ together */
+ __gus_mcb *newmcb = (__gus_mcb *) MikMod_malloc(sizeof(__gus_mcb));
+ best_min->size -= memsize;
+ newmcb->prev = best_min;
+ newmcb->next = best_min->next;
+ newmcb->addr = best_min->addr + best_min->size;
+ newmcb->size = memsize;
+ newmcb->free = 1;
+ if (best_min->next)
+ best_min->next->prev = newmcb;
+ best_min->next = newmcb;
+ }
+ best_min->free = 0;
+
+ return memaddr;
+}
+
+static void __gus_mem_free(unsigned int addr)
+{
+ __gus_mcb *cur = gus.mcb;
+ while (cur) {
+ if (!cur->free && (cur->addr <= addr) &&
+ (cur->addr + cur->size > addr)) {
+ cur->free = 1;
+
+ /* If next block is free as well, link them together */
+ if (cur->next && cur->next->free) {
+ __gus_mcb *next = cur->next;
+ cur->size += next->size;
+ cur->next = next->next;
+ if (next->next)
+ next->next->prev = cur;
+ MikMod_free(next);
+ }
+
+ /* If previous block is free, link current block with it */
+ if (cur->prev && cur->prev->free) {
+ cur->prev->size += cur->size;
+ cur->prev->next = cur->next;
+ if (cur->next)
+ cur->next->prev = cur->prev;
+ MikMod_free(cur);
+ }
+ return;
+ }
+ cur = cur->next;
+ }
+}
+
+static void __gus_mem_pack()
+{
+}
+
+#ifdef MIKMOD_DEBUG
+
+/* Debug dump of GUS DRAM heap */
+void __gus_mem_dump()
+{
+ __gus_mcb *cur = gus.mcb;
+ fprintf(stderr, "/-- Offset --+-- Prev --+-- Size --+-- Free --\\\n");
+ while (cur) {
+ fprintf(stderr, "| %08X | %08X | %6d | %s |\n",
+ cur->addr, cur->prev ? cur->prev->addr : -1, cur->size,
+ cur->free ? "yes" : " no");
+ cur = cur->next;
+ }
+ fprintf(stderr, "\\------------+----------+----------+----------/\n");
+}
+
+#endif
+
+/************************************************** Middle-level routines *****/
+
+static int __gus_instrument_free(gus_instrument_t * instrument)
+{
+ gus_instrument_t **cur_instr;
+ gus_layer_t *cur_layer;
+ gus_wave_t *cur_wave, *wave_head;
+
+ /* Remove the instrument from the list of registered instruments */
+ cur_instr = (gus_instrument_t **) & gus.instr;
+ while (*cur_instr) {
+ if (*cur_instr == instrument) {
+ *cur_instr = instrument->next;
+ goto instr_loaded;
+ }
+ cur_instr = &(*cur_instr)->next;
+ }
+ return -1;
+
+instr_loaded:
+ wave_head = NULL;
+ for (cur_layer = instrument->info.layer; cur_layer;
+ cur_layer = cur_layer->next)
+ /* Free all waves */
+ for (cur_wave = cur_layer->wave; cur_wave; cur_wave = cur_wave->next) {
+ if (!wave_head)
+ wave_head = cur_wave;
+ if (cur_wave->begin.memory != (unsigned int)-1)
+ __gus_mem_free(cur_wave->begin.memory);
+ }
+ if (wave_head)
+ MikMod_free(wave_head);
+
+ MikMod_free(instrument->info.layer);
+ if (instrument->name)
+ MikMod_free(instrument->name);
+ MikMod_free(instrument);
+ return 0;
+}
+
+static gus_instrument_t *__gus_instrument_get(int program)
+{
+ gus_instrument_t *cur_instr = (gus_instrument_t *) gus.instr;
+ while (cur_instr) {
+ if (cur_instr->number.instrument == program)
+ return cur_instr;
+ cur_instr = cur_instr->next;
+ }
+ return NULL;
+}
+
+static gus_instrument_t *__gus_instrument_copy(gus_instrument_t * instrument)
+{
+ gus_instrument_t **cur_instr, *instr;
+ gus_layer_t *cur_layer, *dest_layer;
+ gus_wave_t *cur_wave, *dest_wave;
+ unsigned int waves, layers;
+
+ if (!instrument || !instrument->info.layer || !gus.open)
+ return NULL;
+
+ if (__gus_instrument_get(instrument->number.instrument))
+ return NULL;
+
+ instr = (gus_instrument_t *) MikMod_malloc(sizeof(gus_instrument_t));
+ *instr = *instrument;
+
+ if (instrument->name)
+ instr->name = MikMod_strdup(instrument->name);
+
+ /* Make a copy of all layers at once */
+ for (layers = 0, cur_layer = instrument->info.layer; cur_layer; layers++)
+ cur_layer = cur_layer->next;
+
+ if (!(dest_layer = instr->info.layer = (gus_layer_t *) MikMod_malloc(sizeof(gus_layer_t) * layers))) {
+ if (instr->name)
+ MikMod_free(instr->name);
+ MikMod_free(instr);
+ return NULL;
+ }
+ for (waves = 0, cur_layer = instrument->info.layer; cur_layer;
+ cur_layer = cur_layer->next) {
+ *dest_layer = *cur_layer;
+ dest_layer->wave = NULL;
+ /* Count the total number of waves */
+ for (cur_wave = cur_layer->wave; cur_wave; cur_wave = cur_wave->next)
+ waves++;
+ if (cur_layer->next)
+ dest_layer->next = dest_layer + 1;
+ else
+ dest_layer->next = NULL;
+ dest_layer++;
+ }
+
+ /* Allocate memory for waves */
+ if (!(dest_wave = (gus_wave_t *) MikMod_malloc(sizeof(gus_wave_t) * waves))) {
+ MikMod_free(instr->info.layer);
+ if (instr->name)
+ MikMod_free(instr->name);
+ MikMod_free(instr);
+ return NULL;
+ }
+ for (cur_layer = instrument->info.layer, dest_layer = instr->info.layer;
+ cur_layer; cur_layer = cur_layer->next, dest_layer = dest_layer->next)
+ /* Copy all waves */
+ for (cur_wave = cur_layer->wave; cur_wave; cur_wave = cur_wave->next) {
+ if (!dest_layer->wave)
+ dest_layer->wave = dest_wave;
+
+ *dest_wave = *cur_wave;
+ /* Mark DRAM address as unallocated */
+ dest_wave->begin.memory = -1;
+
+ if (cur_wave->next)
+ dest_wave->next = (dest_wave + 1);
+ else
+ dest_wave->next = NULL;
+ dest_wave++;
+ }
+
+ /* Insert the instrument into list of registered instruments */
+ cur_instr = (gus_instrument_t **) & gus.instr;
+ while (*cur_instr)
+ cur_instr = &(*cur_instr)->next;
+ *cur_instr = instr;
+
+ return instr;
+}
+
+static void __gus_instruments_clear()
+{
+ gus_instrument_t *next_instr, *cur_instr = (gus_instrument_t *) gus.instr;
+ while (cur_instr) {
+ next_instr = cur_instr->next;
+ __gus_instrument_free(cur_instr);
+ cur_instr = next_instr;
+ }
+}
+
+/******************************************************* libGUS interface *****/
+
+/* return value: number of GUS cards installed in system */
+int gus_cards()
+{
+ if (!gus.ok)
+ __gus_init();
+ return gus.ok ? 1 : 0;
+}
+
+int gus_info(gus_info_t * info, int reread)
+{
+ if (!gus.ok)
+ __gus_init();
+ if (!gus.ok)
+ return -1;
+
+ strcpy((char *)info->id, "gus0");
+ info->flags = (gus.ram ? GUS_STRU_INFO_F_PCM : 0);
+ info->version = gus.version;
+ info->port = gus.port;
+ info->irq = gus.irq[0];
+ info->dma1 = gus.dma[0];
+ info->dma2 = gus.dma[1];
+
+ info->mixing_freq = gus.freq;
+
+ info->memory_size = gus.ram * 1024;
+ info->memory_free = __gus_mem_get_free();
+ info->memory_block_8 = __gus_mem_get_free_8();
+ info->memory_block_16 = __gus_mem_get_free_16();
+ return 0;
+}
+
+int gus_open(int card, size_t queue_buffer_size, int non_block)
+{
+ __dpmi_meminfo struct_info, pool_info;
+
+ if (!gus.ok)
+ __gus_init();
+
+ if (!gus.ok || gus.open || card != 0)
+ return -1;
+
+ /* Now lock the gus structure in memory */
+ struct_info.address = __djgpp_base_address + (unsigned long)&gus;
+ struct_info.size = sizeof(gus);
+ if (__dpmi_lock_linear_region(&struct_info))
+ return -1;
+
+ /* And hook the GF1 interrupt */
+ __irq_stack_count = 4;
+ gus.gf1_irq =
+ irq_hook(gus.irq[0], gf1_irq, (long)gf1_irq_end - (long)gf1_irq);
+ __irq_stack_count = 1;
+ if (!gus.gf1_irq) {
+ __dpmi_unlock_linear_region(&struct_info);
+ return -1;
+ }
+
+ /* Enable the interrupt */
+ irq_enable(gus.gf1_irq);
+ if (gus.irq[0] > 7)
+ _irq_enable(2);
+
+ /* Allocate a DMA buffer: if we fail, we just use I/O so don't fail */
+ if ((gus.transfer == NULL) || (gus.transfer == __gus_transfer_dma))
+ gus.dma_buff = dma_allocate(gus.dma[0], GF1_DMA_BUFFER_SIZE);
+ else
+ gus.dma_buff = NULL;
+
+ /* Detect the best available RAM -> DRAM transfer function */
+ if (!gus.transfer) {
+ __gus_detect_transfer();
+ if (gus.transfer != __gus_transfer_dma || !gus.transfer)
+ dma_free(gus.dma_buff), gus.dma_buff = NULL;
+
+ /* If no transfer function worked, fail */
+ if (!gus.transfer) {
+ if (gus.dma_buff) {
+ dma_free(gus.dma_buff);
+ gus.dma_buff = NULL;
+ }
+ __dpmi_unlock_linear_region(&struct_info);
+ irq_unhook(gus.gf1_irq);
+ gus.gf1_irq = NULL;
+ return -1;
+ }
+ }
+
+ /* Allocate and lock command pool buffer */
+ if (queue_buffer_size < 64)
+ queue_buffer_size = 64;
+ if (queue_buffer_size > 16384)
+ queue_buffer_size = 16384;
+ gus.cmd_pool = (unsigned char *) MikMod_malloc(queue_buffer_size);
+ pool_info.address = __djgpp_base_address + (unsigned long)&gus.cmd_pool;
+ pool_info.size = sizeof(queue_buffer_size);
+ if (__dpmi_lock_linear_region(&pool_info)) {
+ if (gus.dma_buff) {
+ dma_free(gus.dma_buff);
+ gus.dma_buff = NULL;
+ }
+ __dpmi_unlock_linear_region(&struct_info);
+ irq_unhook(gus.gf1_irq);
+ gus.gf1_irq = NULL;
+ return -1;
+ }
+
+ gus.open++;
+
+ __gus_mem_clear();
+ gus.t1_callback = __gus_timer_update;
+ gus.wt_callback = __gus_wavetable_update;
+ gus.vl_callback = __gus_volume_update;
+ gus_do_tempo(60); /* Default is 60 Hz */
+
+ return 0;
+}
+
+int gus_close(int card)
+{
+ __dpmi_meminfo struct_info;
+
+ if (!gus.open || card != 0)
+ return -1;
+
+ /* First reset the card: disable any operation it can currently perform */
+ __gus_reset(0);
+
+ gus.open--;
+
+ /* Stop the timer */
+ gus_timer_stop();
+
+ /* Free DMA buffer if used */
+ if (gus.dma_buff) {
+ dma_free(gus.dma_buff);
+ gus.dma_buff = NULL;
+ }
+
+ /* And unhook the GF1 interrupt */
+ irq_unhook(gus.gf1_irq);
+ gus.gf1_irq = NULL;
+
+ /* Unlock the gus structure */
+ struct_info.address = __djgpp_base_address + (unsigned long)&gus;
+ struct_info.size = sizeof(gus);
+ __dpmi_unlock_linear_region(&struct_info);
+
+ __gus_mem_clear();
+ __gus_instruments_clear();
+
+ return 0;
+}
+
+int gus_select(int card)
+{
+ if (!gus.open || (card != 0))
+ return -1;
+
+ return 0;
+}
+
+/* return value: same as gus_reset function
+ note: this command doesn't change number of active voices and doesn't do
+ hardware reset */
+int gus_reset_engine_only()
+{
+ gus.timer_base = 100;
+ return 0;
+}
+
+int gus_reset(int voices, unsigned int channel_voices)
+{
+ static unsigned short freq_table[32 - 14 + 1] = {
+ 44100, 41160, 38587, 36317, 34300, 32494, 30870, 29400, 28063, 26843,
+ 25725, 24696, 23746, 22866, 22050, 21289, 20580, 19916, 19293
+ };
+ int voice;
+ int timer;
+
+ /* No support for dynamically allocated voices for now */
+ gus.dynmask = channel_voices;
+
+ if (voices < 14)
+ voices = 14;
+ if (voices > 32)
+ voices = 32;
+
+ /* Stop the timer so that GUS IRQ won't clobber registers */
+ timer = (gus.timer_ctl_reg & GF1M_TIMER1);
+ if (timer)
+ gus_timer_stop();
+
+ /* Stop all voices */
+ for (voice = 0; voice < 32; voice++) {
+ __gus_select_voice(voice);
+ __gus_stop_voice();
+ gus.cur_wave[voice] = NULL;
+ gus.cur_vol[voice] = 0;
+
+ __gus_delay();
+
+ /* Reset voice parameters to reasonable values */
+ __gus_set_current(0, 0);
+ __gus_set_loop_start(0, 0);
+ __gus_set_loop_end(0, 0);
+ __gus_outregw(GF1R_VOLUME, 0);
+ __gus_outregb(GF1R_VOLUME_RATE, 0);
+ __gus_outregb(GF1R_VOLUME_START, 0);
+ __gus_outregb(GF1R_VOLUME_END, 0);
+ __gus_outregb(GF1R_BALANCE, 0x7);
+ }
+
+ voice = (__gus_inregb(GF1R_VOICES) & 0x1f) + 1;
+
+ if (voice != voices) {
+ int reset = __gus_inregb(GF1R_RESET);
+ __gus_outregb(GF1R_RESET, reset & ~GF1M_OUTPUT_ENABLE);
+ __gus_delay();
+ __gus_outregb(GF1R_VOICES, 0xc0 | (voices - 1));
+ __gus_delay();
+ __gus_outregb(GF1R_RESET, reset);
+ }
+
+ /* Compute the discretization frequence */
+ gus.voices = voices;
+ if (gus.interwave)
+ gus.freq = 44100;
+ else
+ gus.freq = freq_table[voices - 14];
+
+ gus_reset_engine_only();
+
+ if (timer)
+ gus_timer_continue();
+
+ return gus.voices;
+}
+
+int gus_do_flush()
+{
+ DEBUG_PRINT(("gus_do_flush: top = %d\n", gus.cmd_pool_top))
+ gus.cmd_pool_ready = 1;
+ return 0;
+}
+
+/* set new tempo */
+void gus_do_tempo(unsigned int tempo)
+{
+ DEBUG_PRINT(("gus_do_tempo (%d)\n", tempo))
+ gus_timer_tempo(tempo);
+ gus_timer_start();
+}
+
+/* set voice frequency in Hz */
+void gus_do_voice_frequency(unsigned char voice, unsigned int freq)
+{
+ DEBUG_PRINT(("gus_do_voice_frequency (%d, %d)\n", voice, freq))
+ __pool_select_voice(voice);
+ __pool_command_w(PCMD_FREQ,
+ (((freq << 9) + (gus.freq >> 1)) / gus.freq) << 1);
+}
+
+/* set voice pan (0-16384) (full left - full right) */
+void gus_do_voice_pan(unsigned char voice, unsigned short pan)
+{
+ DEBUG_PRINT(("gus_do_voice_pan (%d, %d)\n", voice, pan))
+ pan >>= 10;
+ if (pan > 15)
+ pan = 15;
+ __pool_select_voice(voice);
+ __pool_command_b(PCMD_PAN, pan);
+}
+
+/* set voice volume level 0-16384 (linear) */
+void gus_do_voice_volume(unsigned char voice, unsigned short vol)
+{
+ DEBUG_PRINT(("gus_do_voice_volume (%d, %d)\n", voice, vol))
+ if (vol > 0x3fff)
+ vol = 0x3fff;
+ __pool_select_voice(voice);
+ __pool_command_w(PCMD_VOLUME, __gus_volume_table[vol >> 5]);
+}
+
+/* start voice
+ * voice : voice #
+ * program : program # or ~0 = current
+ * freq : frequency in Hz
+ * volume : volume level (0-16384) or ~0 = current
+ * pan : pan level (0-16384) or ~0 = current
+ */
+void gus_do_voice_start(unsigned char voice, unsigned int program,
+ unsigned int freq, unsigned short volume,
+ unsigned short pan)
+{
+ gus_do_voice_start_position(voice, program, freq, volume, pan, 0);
+}
+
+/* start voice
+ * voice : voice #
+ * program : program # or ~0 = current
+ * freq : frequency in Hz
+ * volume : volume level (0-16384) or ~0 = current
+ * pan : pan level (0-16384) or ~0 = current
+ * position : offset to wave in bytes * 16 (lowest 4 bits - fraction)
+ */
+void gus_do_voice_start_position(unsigned char voice, unsigned int program,
+ unsigned int freq, unsigned short volume,
+ unsigned short pan, unsigned int position)
+{
+ gus_instrument_t *instrument;
+ gus_wave_t *wave;
+
+ DEBUG_PRINT(
+ ("gus_do_voice_start_position (%d, %d, pos: %d)\n", voice,
+ program, position))
+
+ instrument = __gus_instrument_get(program);
+
+ if (!instrument
+ || !instrument->info.layer
+ || !instrument->info.layer->wave
+ || instrument->flags == GUS_INSTR_F_NOT_FOUND
+ || instrument->flags == GUS_INSTR_F_NOT_LOADED) return;
+
+ gus_do_voice_frequency(voice, freq);
+ gus_do_voice_pan(voice, pan);
+
+ /* We have to set volume different way, to avoid unneeded work in handler */
+ if (volume > 0x3fff)
+ volume = 0x3fff;
+ __pool_command_w(PCMD_VOLUME_PREPARE, __gus_volume_table[volume >> 5]);
+
+ switch (instrument->mode) {
+ case GUS_INSTR_SIMPLE:
+ wave = instrument->info.layer->wave;
+ if (position)
+ __pool_command_l(PCMD_OFFSET, position);
+ __pool_command_l(PCMD_START, (unsigned long)wave);
+ break;
+ }
+}
+
+/* stop voice
+ * mode = 0 : stop voice now
+ * mode = 1 : disable wave loop and finish it
+ */
+void gus_do_voice_stop(unsigned char voice, unsigned char mode)
+{
+ __pool_select_voice(voice);
+ if (mode)
+ __pool_command(PCMD_STOP_LOOP);
+ else
+ __pool_command(PCMD_STOP);
+}
+
+/* wait x ticks - this command is block separator
+ all commands between blocks are interpreted in the begining of one tick */
+void gus_do_wait(unsigned int ticks)
+{
+ DEBUG_PRINT(("gus_do_wait (%d)\n", ticks))
+
+ ticks += gus.t1_ticks;
+ while ((int)(ticks - gus.t1_ticks) > 0);
+}
+
+int gus_get_voice_status(int voice)
+{
+ __gus_select_voice(voice);
+ return __gus_inregb(GF1R_VOICE_CONTROL) & GF1VC_STOPPED ? 0 : 1;
+}
+
+/* return value: file handle (descriptor) for /dev/gus */
+int gus_get_handle()
+{
+ /* Return stdout handle so that select() will "work" with it */
+ return 0;
+}
+
+/* return value: zero if instrument was successfully allocated */
+int gus_memory_alloc(gus_instrument_t * instrument)
+{
+ gus_instrument_t *instr = __gus_instrument_copy(instrument);
+ gus_layer_t *cur_layer;
+ gus_wave_t *cur_wave;
+
+ DEBUG_PRINT(("gus_memory_alloc (%d)\n", instrument->number.instrument))
+
+ if (!instr)
+ return -1;
+
+ for (cur_layer = instr->info.layer; cur_layer;
+ cur_layer = cur_layer->next) for (cur_wave = cur_layer->wave;
+ cur_wave;
+ cur_wave = cur_wave->next) {
+ if (cur_layer->mode == GUS_INSTR_SIMPLE) {
+ cur_wave->begin.memory = __gus_mem_alloc(cur_wave->size,
+ cur_wave->format &
+ GUS_WAVE_16BIT);
+ if (cur_wave->begin.memory == (unsigned int)-1) {
+ __gus_instrument_free(instr);
+ return -1;
+ }
+ gus.transfer(cur_wave->begin.memory, cur_wave->begin.ptr,
+ cur_wave->size, cur_wave->format);
+ } else if (cur_layer->mode == GUS_INSTR_PATCH)
+ /* not supported yet */ ;
+ }
+
+ return 0;
+}
+
+/* return value: zero if instrument was successfully removed */
+int gus_memory_free(gus_instrument_t * instrument)
+{
+ gus_instrument_t *cur_instr = gus.instr;
+
+ DEBUG_PRINT(("gus_memory_free (%d)\n", instrument->number.instrument))
+
+ for (; cur_instr; cur_instr = cur_instr->next)
+ if (cur_instr->number.instrument == instrument->number.instrument)
+ return __gus_instrument_free(cur_instr);
+
+ return -1;
+}
+
+/* return value: unused gus memory in bytes */
+int gus_memory_free_size()
+{
+ return __gus_mem_get_free();
+}
+
+/* return value: zero if success */
+int gus_memory_pack()
+{
+ __gus_mem_pack();
+ return 0;
+}
+
+/* return value: gus memory size in bytes */
+int gus_memory_size()
+{
+ return gus.ram * 1024;
+}
+
+/* return value: current largest free block for 8-bit or 16-bit wave */
+int gus_memory_free_block(int w_16bit)
+{
+ return w_16bit ? __gus_mem_get_free_16() : __gus_mem_get_free_8();
+}
+
+/* input value: see to GUS_DOWNLOAD_MODE_XXXX constants (gus.h)
+ return value: zero if samples & instruments was successfully removed from
+ GF1 memory manager */
+int gus_memory_reset(int mode)
+{
+ __gus_mem_clear();
+ __gus_instruments_clear();
+ return 0;
+}
+
+/* return value: zero if command queue was successfully flushed */
+int gus_queue_flush()
+{
+ return 0;
+}
+
+/* input value: echo buffer size in items (if 0 - erase echo buffer) */
+int gus_queue_read_set_size(int items)
+{
+ return 0;
+}
+
+/* input value: write queue size in items (each item have 8 bytes) */
+int gus_queue_write_set_size(int items)
+{
+ return 0;
+}
+
+/* return value: zero if successfull */
+int gus_timer_start()
+{
+ gus.timer_ctl_reg |= GF1M_TIMER1;
+ __gus_outregb_slow(GF1R_TIMER_CONTROL, gus.timer_ctl_reg);
+
+ gus.timer_ctl = gus.timer_ctl & ~GF1M_MASK_TIMER1;
+ outportb(GF1_TIMER_CTRL, 0x04);
+ outportb(GF1_TIMER_DATA, gus.timer_ctl | GF1M_START_TIMER1);
+ return 0;
+}
+
+/* return value: zero if timer was stoped */
+int gus_timer_stop()
+{
+ gus.timer_ctl_reg &= ~GF1M_TIMER1;
+ __gus_outregb_slow(GF1R_TIMER_CONTROL, gus.timer_ctl_reg);
+
+ gus.timer_ctl = gus.timer_ctl | GF1M_MASK_TIMER1;
+ outportb(GF1_TIMER_CTRL, 0x04);
+ outportb(GF1_TIMER_DATA, gus.timer_ctl);
+ return 0;
+}
+
+/* return value: zero if setup was success */
+int gus_timer_tempo(int ticks)
+{
+ unsigned int counter;
+
+ /* Limit ticks per second to 1..1000 range */
+ if (ticks < 1)
+ ticks = 1;
+ if (ticks > 1000)
+ ticks = 1000;
+
+ /* GF1 timer1 period is 80 usecs, 12500 times per second */
+ counter = 1250000 / (ticks * gus.timer_base);
+ gus.t1_multiple = 1;
+ while (counter > 255) {
+ counter >>= 1;
+ gus.t1_multiple <<= 1;
+ }
+ gus.t1_countdown = gus.t1_multiple;
+ __gus_outregb(GF1R_TIMER1, 256 - counter);
+ return 0;
+}
+
+/* return value: zero if timer will be continue */
+int gus_timer_continue()
+{
+ return gus_timer_start();
+}
+
+/* return value: zero if setup was success (default timebase = 100) */
+int gus_timer_base(int base)
+{
+ gus.timer_base = base;
+ return 0;
+}
+
+void gus_timer_callback(void (*timer_callback) ())
+{
+ gus.timer_callback = timer_callback;
+}
+
+void gus_convert_delta(unsigned int type, unsigned char *dest,
+ unsigned char *src, size_t size)
+{
+ if (!(type & GUS_WAVE_DELTA))
+ return;
+
+ /* This doesn't depend much on wave signedness, since addition/subtraction
+ do not depend on operand signedness */
+ if (type & GUS_WAVE_16BIT) {
+ unsigned short delta = type & GUS_WAVE_UNSIGNED ? 0x8000 : 0;
+ while (size--) {
+ delta = *(unsigned short *)dest = *(unsigned short *)src + delta;
+ src += sizeof(unsigned short);
+ dest += sizeof(unsigned short);
+ }
+ } else {
+ unsigned char delta = type & GUS_WAVE_UNSIGNED ? 0x80 : 0;
+ while (size--) {
+ delta = *(unsigned char *)dest = *(unsigned char *)src + delta;
+ src++;
+ dest++;
+ }
+ }
+}
+
+int gus_dma_usage (int use)
+{
+ if (gus.dma_buff)
+ return -1;
+ gus.transfer = __gus_transfer_io;
+ return 0;
+}
+
+#endif /* DRV_ULTRA */
+
+/* ex:set ts=4: */
--- /dev/null
+/* MikMod sound library
+ (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
+ complete list.
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+/*==============================================================================
+
+ $Id$
+
+ libGUS-alike definitions for DOS
+
+==============================================================================*/
+
+#ifndef __DOSGUS_H__
+#define __DOSGUS_H__
+
+#include <pc.h>
+#include "dosdma.h"
+#include "dosirq.h"
+#include "libgus.h"
+
+/* Private header file for a libGUS-alike library for DOS */
+
+#define JOYSTICK_TIMER (gus.port+0x201) /* 201 */
+#define JOYSTICK_DATA (gus.port+0x201) /* 201 */
+
+#define GF1_MIDI_CTRL (gus.port+0x100) /* 3X0 */
+#define GF1_MIDI_DATA (gus.port+0x101) /* 3X1 */
+
+#define GF1_VOICESEL (gus.port+0x102) /* 3X2 */
+#define GF1_REGSEL (gus.port+0x103) /* 3X3 */
+#define GF1_DATA (gus.port+0x104) /* 3X4 */
+#define GF1_DATA_LOW (gus.port+0x104) /* 3X4 */
+#define GF1_DATA_HIGH (gus.port+0x105) /* 3X5 */
+#define GF1_IRQ_STATUS (gus.port+0x006) /* 2X6 */
+#define GF1_DRAM (gus.port+0x107) /* 3X7 */
+
+#define GF1_MIX_CTRL (gus.port+0x000) /* 2X0 */
+#define GF1_TIMER_CTRL (gus.port+0x008) /* 2X8 */
+#define GF1_TIMER_DATA (gus.port+0x009) /* 2X9 */
+#define GF1_IRQ_CTRL (gus.port+0x00B) /* 2XB */
+#define GF1_REG_CTRL (gus.port+0x00F) /* 2XF */
+
+#define GF1_REVISION (gus.port+0x506) /* 7X6 */
+
+/* The GF1 hardware clock rate */
+#define CLOCK_RATE 9878400L
+
+/* GF1 voice-independent registers */
+#define GF1R_DMA_CONTROL 0x41
+#define GF1R_DMA_ADDRESS 0x42
+#define GF1R_DRAM_LOW 0x43
+#define GF1R_DRAM_HIGH 0x44
+
+#define GF1R_TIMER_CONTROL 0x45
+#define GF1R_TIMER1 0x46
+#define GF1R_TIMER2 0x47
+
+#define GF1R_SAMPLE_RATE 0x48
+#define GF1R_SAMPLE_CONTROL 0x49
+
+#define GF1R_JOYSTICK 0x4B
+#define GF1R_RESET 0x4C
+
+/* GF1 voice-specific registers */
+#define GF1R_VOICE_CONTROL 0x00
+#define GF1R_FREQUENCY 0x01
+#define GF1R_START_HIGH 0x02
+#define GF1R_START_LOW 0x03
+#define GF1R_END_HIGH 0x04
+#define GF1R_END_LOW 0x05
+#define GF1R_VOLUME_RATE 0x06
+#define GF1R_VOLUME_START 0x07
+#define GF1R_VOLUME_END 0x08
+#define GF1R_VOLUME 0x09
+#define GF1R_ACC_HIGH 0x0a
+#define GF1R_ACC_LOW 0x0b
+#define GF1R_BALANCE 0x0c
+#define GF1R_VOLUME_CONTROL 0x0d
+#define GF1R_VOICES 0x0e
+#define GF1R_IRQ_SOURCE 0x0f
+
+/* Add this to above registers for reading */
+#define GF1R_READ_MASK 0x80
+
+/* MIDI */
+#define GF1M_MIDI_RESET 0x03
+#define GF1M_MIDI_ENABLE_XMIT 0x20
+#define GF1M_MIDI_ENABLE_RCV 0x80
+
+#define GF1M_MIDI_RCV_FULL 0x01
+#define GF1M_MIDI_XMIT_EMPTY 0x02
+#define GF1M_MIDI_FRAME_ERR 0x10
+#define GF1M_MIDI_OVERRUN 0x20
+#define GF1M_MIDI_IRQ_PEND 0x80
+
+/* Joystick */
+#define GF1M_JOY_POSITION 0x0f
+#define GF1M_JOY_BUTTONS 0xf0
+
+/* GF1_IRQ_STATUS (port 2X6) */
+#define GF1M_IRQ_MIDI_TX 0x01 /* pending MIDI xmit IRQ */
+#define GF1M_IRQ_MIDI_RX 0x02 /* pending MIDI recv IRQ */
+#define GF1M_IRQ_TIMER1 0x04 /* general purpose timer */
+#define GF1M_IRQ_TIMER2 0x08 /* general purpose timer */
+#define GF1M_IRQ_WAVETABLE 0x20 /* pending wavetable IRQ */
+#define GF1M_IRQ_ENVELOPE 0x40 /* pending volume envelope IRQ */
+#define GF1M_IRQ_DMA_COMPLETE 0x80 /* pending dma transfer complete IRQ */
+
+/* GF1_MIX_CTRL (port 2X0) */
+#define GF1M_MIXER_NO_LINE_IN 0x01 /* 0: enable */
+#define GF1M_MIXER_NO_OUTPUT 0x02 /* 0: enable */
+#define GF1M_MIXER_MIC_IN 0x04 /* 1: enable */
+#define GF1M_MIXER_GF1_IRQ 0x08 /* 1: enable */
+#define GF1M_GF1_COMBINED_IRQ 0x10 /* 1: IRQ1 == IRQ2 */
+#define GF1M_MIDI_LOOPBACK 0x20 /* 1: enable loop back */
+#define GF1M_CONTROL_SELECT 0x40 /* 0: DMA latches; 1: IRQ latches */
+
+/* Timer data register (2X9) */
+#define GF1M_START_TIMER1 0x01
+#define GF1M_START_TIMER2 0x02
+#define GF1M_MASK_TIMER1 0x20
+#define GF1M_MASK_TIMER2 0x40
+#define GF1M_TIMER_CLRIRQ 0x80
+
+/* IRQ/DMA control register (2XB) */
+#define GF1M_IRQ_EQUAL 0x40
+#define GF1M_DMA_EQUAL 0x40
+
+/* (0x41) DMA control register bits */
+#define GF1M_DMAR_ENABLE 0x01 /* 1: go */
+#define GF1M_DMAR_READ 0x02 /* 1: read (->RAM), 0: write (->DRAM) */
+#define GF1M_DMAR_CHAN16 0x04 /* 1: 16 bit, 0: 8 bit DMA channel */
+#define GF1M_DMAR_RATE 0x18 /* 00: fast, 11: slow */
+#define GF1M_DMAR_IRQ_ENABLE 0x20 /* 1: enable */
+#define GF1M_DMAR_IRQ_PENDING 0x40 /* R: DMA irq pending */
+#define GF1M_DMAR_DATA16 0x40 /* W: 0: 8 bits; 1: 16 bits per sample */
+#define GF1M_DMAR_TOGGLE_SIGN 0x80 /* W: 1: invert high bit */
+
+/* DMA transfer rate divisors */
+#define GF1M_DMAR_RATE0 0x00 /* Fastest DMA xfer (~650khz) */
+#define GF1M_DMAR_RATE1 0x08 /* fastest / 2 */
+#define GF1M_DMAR_RATE2 0x10 /* fastest / 4 */
+#define GF1M_DMAR_RATE3 0x18 /* Slowest DMA xfer (fastest / 8) */
+
+/* (0x45) Timer Control */
+#define GF1M_TIMER1 0x04 /* Enable timer 1 IRQ */
+#define GF1M_TIMER2 0x08 /* Enable timer 2 IRQ */
+
+/* (0x49) Sampling (ADC) control register */
+#define GF1M_DMAW_ENABLE 0x01 /* 1: Start sampling */
+#define GF1M_DMAW_MODE 0x02 /* 0: mono, 1: stereo */
+#define GF1M_DMAW_CHAN16 0x04 /* 0: 8 bit, 1: 16 bit */
+#define GF1M_DMAW_IRQ_ENABLE 0x20 /* 1: enable IRQ */
+#define GF1M_DMAW_IRQ_PENDING 0x40 /* 1: irq pending */
+#define GF1M_DMAW_TOGGLE_SIGN 0x80 /* 1: invert sign bit */
+
+/* (0x4C) GF1 reset register */
+#define GF1M_MASTER_RESET 0x01 /* 0: hold in reset */
+#define GF1M_OUTPUT_ENABLE 0x02 /* 1: enable output */
+#define GF1M_MASTER_IRQ 0x04 /* 1: master IRQ enable */
+
+/* (0x0,0x80) Voice control register - GF1R_VOICE_CONTROL */
+#define GF1VC_STOPPED 0x01 /* 1: voice has stopped */
+#define GF1VC_STOP 0x02 /* 1: stop voice */
+#define GF1VC_DATA16 0x04 /* 0: 8 bit, 1: 16 bit */
+#define GF1VC_LOOP_ENABLE 0x08 /* 1: enable */
+#define GF1VC_BI_LOOP 0x10 /* 1: bi directional looping */
+#define GF1VC_IRQ 0x20 /* 1: enable voice's wave irq */
+#define GF1VC_BACKWARD 0x40 /* 0: increasing, 1: decreasing */
+#define GF1VC_IRQ_PENDING 0x80 /* 1: wavetable irq pending */
+
+/* (0x01,0x81) Frequency control */
+/* Bit 0 - Unused */
+/* Bits 1-9 - Fractional portion */
+/* Bits 10-15 - Integer portion */
+
+/* (0x02,0x82) Accumulator start address - GF1R_START_HIGH */
+/* Bits 0-11 - HIGH 12 bits of address */
+/* Bits 12-15 - Unused */
+
+/* (0x03,0x83) Accumulator start address - GF1R_START_LOW */
+/* Bits 0-4 - Unused */
+/* Bits 5-8 - Fractional portion */
+/* Bits 9-15 - Low 7 bits of integer portion */
+
+/* (0x04,0x84) Accumulator end address - GF1R_END_HIGH */
+/* Bits 0-11 - HIGH 12 bits of address */
+/* Bits 12-15 - Unused */
+
+/* (0x05,0x85) Accumulator end address - GF1R_END_LOW */
+/* Bits 0-4 - Unused */
+/* Bits 5-8 - Fractional portion */
+/* Bits 9-15 - Low 7 bits of integer portion */
+
+/* (0x06,0x86) Volume Envelope control register - GF1R_VOLUME_RATE */
+#define GF1VL_RATE_MANTISSA 0x3f
+#define GF1VL_RATE_RANGE 0xC0
+
+/* (0x07,0x87) Volume envelope start - GF1R_VOLUME_START */
+#define GF1VL_START_MANT 0x0F
+#define GF1VL_START_EXP 0xF0
+
+/* (0x08,0x88) Volume envelope end - GF1R_VOLUME_END */
+#define GF1VL_END_MANT 0x0F
+#define GF1VL_END_EXP 0xF0
+
+/* (0x09,0x89) Current volume register - GF1R_VOLUME */
+/* Bits 0-3 - Unused */
+/* Bits 4-11 - Mantissa of current volume */
+/* Bits 10-15 - Exponent of current volume */
+
+/* (0x0A,0x8A) Accumulator value (high) */
+/* Bits 0-12 - HIGH 12 bits of current position (a19-a7) */
+
+/* (0x0B,0x8B) Accumulator value (low) */
+/* Bits 0-8 - Fractional portion */
+/* Bits 9-15 - Integer portion of low adress (a6-a0) */
+
+/* (0x0C,0x8C) Pan (balance) position */
+/* Bits 0-3 - Balance position 0=full left, 0x0f=full right */
+
+/* (0x0D,0x8D) Volume control register - GF1R_VOLUME_CONTROL */
+#define GF1VL_STOPPED 0x01 /* volume has stopped */
+#define GF1VL_STOP 0x02 /* stop volume */
+#define GF1VL_ROLLOVER 0x04 /* Roll PAST end & gen IRQ */
+#define GF1VL_LOOP_ENABLE 0x08 /* 1: enable */
+#define GF1VL_BI_LOOP 0x10 /* 1: bi directional looping */
+#define GF1VL_IRQ 0x20 /* 1: enable voice's volume irq */
+#define GF1VL_BACKWARD 0x40 /* 0: increasing, 1: decreasing */
+#define GF1VL_IRQ_PENDING 0x80 /* 1: wavetable irq pending */
+
+/* (0x0E,0x8E) Number of active voices */
+/* Bits 0-5 - Number of active voices - 1 */
+
+/* (0x0F,0x8F) Sources of IRQs */
+/* Bits 0-4 - interrupting voice number */
+/* Bit 5 - Always a 1 */
+#define GF1IRQ_VOLUME 0x40 /* individual voice irq bit */
+#define GF1IRQ_WAVE 0x80 /* individual waveform irq bit */
+
+/* Commands are pooled and executed ON TIMER (1st timer) interrupt.
+ * Currently there is a limit on the number of commands that you can
+ * issue between gus_do_flush (...); this should not be an issue however
+ * because each voice has a limited (little) set of parameters that
+ * you can change (freq, vol, pan... what else?)
+ *
+ * The pool is a pseudo-CPU code that gets executed once per timer interrupt.
+ */
+
+/* Below are definitions for commands placed in GUS command pool */
+#define PCMD_NOP 0x00 /* Traditionally ... */
+#define PCMD_VOICE 0x01 /* +B: select voice */
+#define PCMD_START 0x02 /* +L: start voice */
+#define PCMD_STOP 0x03 /* stop voice */
+#define PCMD_FREQ 0x04 /* +W: set frequence */
+#define PCMD_VOLUME 0x05 /* +W: set volume */
+#define PCMD_VOLUME_PREPARE 0x06 /* +W: prepare to set volume on (soon to follow) kick */
+#define PCMD_PAN 0x07 /* +B: set panning */
+#define PCMD_OFFSET 0x08 /* +L: set DRAM offset */
+#define PCMD_STOP_LOOP 0x09 /* stop looping */
+
+#define GUS_VOLCHANGE_RAMP 0x20 /* Volume change ramp speed */
+
+/* Definition for the boolean type */
+typedef unsigned char boolean;
+/* Prototype for functions that do block transfers to GUS DRAM:
+ flags can contain any of the following bits:
+ GUS_WAVE_16BIT - sample is 16-bit
+ GUS_WAVE_UNSIGNED - do not invert sign bit while downloading
+ */
+typedef void (*__gus_transfer_func) (unsigned long address,
+ unsigned char *source,
+ unsigned long size, int flags);
+typedef void (*__gus_callback) ();
+typedef void (*__gus_callback_3) (unsigned int, unsigned int, unsigned int);
+
+/* Structure used to keep track of all on-board GUS memory */
+typedef struct __struct_gus_mcb {
+ struct __struct_gus_mcb *next; /* Next MCB in chain */
+ struct __struct_gus_mcb *prev; /* Previous MCB in chain */
+ unsigned int addr; /* GUS DRAM address */
+ unsigned int size; /* Memory block size */
+ int free; /* 1: block is free */
+} __gus_mcb;
+
+/* Structure defining overall GUS state/information */
+typedef struct __gus_state_s {
+ unsigned int port; /* Base I/O port (0x220, 0x240, ...) */
+ unsigned int irq[2]; /* GF1 IRQ and MIDI IRQ */
+ unsigned int dma[2]; /* Play / record DMA */
+ unsigned int ram; /* Memory size (K), i.e. 256, 1024 etc */
+ unsigned int version; /* GUS version (see GUS_CARD_VERSION_XXX in libgus.h */
+ unsigned int freq; /* Current mixing frequency */
+ unsigned int voices; /* Active voices (14-32) */
+ unsigned int dynmask; /* Dynamically allocated voices mask */
+ unsigned int timer_base; /* The relative timer speed in percents (def: 100) */
+ volatile unsigned int t1_ticks; /* Incremented per each timer1 tick */
+ volatile unsigned int t2_ticks; /* Incremented per each timer2 tick */
+ volatile unsigned int t1_countdown; /* t1_callback is called when this reaches zero */
+ volatile unsigned int t2_countdown; /* t2_callback is called when this reaches zero */
+ unsigned int t1_multiple; /* Timer1 handler is called once per such many ticks */
+ unsigned int t2_multiple; /* Timer2 handler is called once per such many ticks */
+ struct irq_handle *gf1_irq; /* The interrupt handler for GF1 events */
+ dma_buffer *dma_buff; /* Pre-allocated DMA buffer */
+ __gus_callback dma_callback; /* Routine called at end of DMA transfers */
+ __gus_callback t1_callback; /* Routine called on Timer1 events */
+ __gus_callback t2_callback; /* Routine called on Timer1 events */
+ __gus_callback timer_callback; /* Called once per TEMPO ticks */
+ __gus_callback_3 wt_callback; /* Routine called on WaveTable events */
+ __gus_callback_3 vl_callback; /* Routine called on Volume ramp events */
+ __gus_mcb *mcb; /* Chained list of memory control blocks */
+ __gus_transfer_func transfer; /* Best working function for DRAM transfer */
+ gus_instrument_t *instr; /* The list of registered instruments */
+ unsigned short mixer; /* Current mixer register state */
+ unsigned char dma_rate; /* One of GF1M_DMAR_RATEX constants defined above */
+ unsigned char timer_ctl; /* Timer control register value (2x8/2x9) */
+ unsigned char timer_ctl_reg; /* Timer control register value (GF1/0x45) */
+ boolean ok; /* Is the information below okay? */
+ boolean open; /* 1 if between gus_open() and gus_close() */
+ boolean ics; /* Is it equipped with an ICS mixer? */
+ boolean ics_flipped; /* rev 5 (3.7) has flipped R/L mixer */
+ boolean codec; /* Is it equipped with a GUS MAX codec? */
+ boolean interwave; /* GUS InterWave card */
+ volatile boolean dma_active; /* DMA is transferring data */
+ volatile boolean cmd_pool_ready; /* Flush cmd_pool during timer interrupt */
+ unsigned char cmd_voice; /* Pool selection index cache */
+ unsigned int cmd_pool_top; /* Command pool top */
+ unsigned char *cmd_pool; /* Async commands pool */
+ /* The following data is for private use only by interrupt routines! */
+ gus_wave_t *cur_wave[32]; /* Currently played waves */
+ boolean voice_kick[32]; /* Kick wave on next volume ramp IRQ */
+ unsigned int kick_offs[32]; /* Sample start position on kick */
+ unsigned short cur_vol[32]; /* Current voice volumes */
+ unsigned int cur_voice; /* Current voice */
+ unsigned int eow_ignore; /* Temp ignore end-of-wave IRQ for these voices */
+} __gus_state;
+
+extern __gus_state gus;
+extern void __gus_delay();
+
+static unsigned long __gus_convert_addr16(unsigned long address)
+{
+ return ((address & 0x0003ffff) >> 1) | (address & ~0x0003ffff);
+}
+
+/* The XXX_slow routines cannot be used outside IRQ handler! */
+static inline void __gus_outregb_slow(unsigned char reg, unsigned char value)
+{
+ outportb(GF1_REGSEL, reg);
+ outportb(GF1_DATA_HIGH, value);
+ __gus_delay();
+ outportb(GF1_DATA_HIGH, value);
+}
+
+static inline void __gus_outregw_slow(unsigned char reg, unsigned short value)
+{
+ outportb(GF1_REGSEL, reg);
+ outportw(GF1_DATA, value);
+ __gus_delay();
+ outportw(GF1_DATA, value);
+}
+
+static inline void __gus_outregb(unsigned char reg, unsigned char value)
+{
+ outportb(GF1_REGSEL, reg);
+ outportb(GF1_DATA_HIGH, value);
+}
+
+static inline void __gus_outregw(unsigned char reg, unsigned short value)
+{
+ outportb(GF1_REGSEL, reg);
+ outportw(GF1_DATA, value);
+}
+
+static inline unsigned char __gus_inregb(unsigned char reg)
+{
+ if (reg < 0x10)
+ reg |= GF1R_READ_MASK;
+ outportb(GF1_REGSEL, reg);
+ return inportb(GF1_DATA_HIGH);
+}
+
+static inline unsigned short __gus_inregw(unsigned char reg)
+{
+ if (reg < 0x10)
+ reg |= GF1R_READ_MASK;
+ outportb(GF1_REGSEL, reg);
+ return inportw(GF1_DATA);
+}
+
+static inline void __gus_set_dram_address(unsigned int address)
+{
+ __gus_outregb(GF1R_DRAM_HIGH, address >> 16);
+ __gus_outregw(GF1R_DRAM_LOW, address);
+}
+
+static inline unsigned char __gus_peek(unsigned int address)
+{
+ __gus_set_dram_address(address);
+ return inportb(GF1_DRAM);
+}
+
+static inline void __gus_poke(unsigned int address, unsigned char value)
+{
+ __gus_set_dram_address(address);
+ outportb(GF1_DRAM, value);
+}
+
+static inline void __gus_select_voice(unsigned char voice)
+{
+ outportb(GF1_VOICESEL, voice);
+}
+
+static inline void __gus_set_current(unsigned char mode,
+ unsigned long address)
+{
+ if (mode & GF1VC_DATA16)
+ address = __gus_convert_addr16(address);
+ __gus_outregw_slow(GF1R_ACC_HIGH, address >> 11);
+ __gus_outregw_slow(GF1R_ACC_LOW, address << 5);
+}
+
+static inline void __gus_set_loop_start(unsigned char mode,
+ unsigned long address)
+{
+ if (mode & GF1VC_DATA16)
+ address = __gus_convert_addr16(address);
+ __gus_outregw_slow(GF1R_START_HIGH, address >> 11);
+ __gus_outregw_slow(GF1R_START_LOW, address << 5);
+}
+
+static inline void __gus_set_loop_end(unsigned char mode,
+ unsigned long address)
+{
+ address--;
+ if (mode & GF1VC_DATA16)
+ address = __gus_convert_addr16(address);
+ __gus_outregw_slow(GF1R_END_HIGH, address >> 11);
+ __gus_outregw_slow(GF1R_END_LOW, address << 5);
+}
+
+static inline void __gus_mixer_output(boolean state)
+{
+ if (state)
+ gus.mixer &= ~GF1M_MIXER_NO_OUTPUT;
+ else
+ gus.mixer |= GF1M_MIXER_NO_OUTPUT;
+ outportb(GF1_MIX_CTRL, gus.mixer);
+ /* Dummy read to avoid touching DMA latches */
+ __gus_inregb(GF1R_BALANCE);
+}
+
+/* Inline routines for working with command pools */
+
+/* WARNING: no bounds checking due to performance reasons */
+#define __POOL_VALUE(type,value) \
+ *((unsigned type *)&gus.cmd_pool [gus.cmd_pool_top]) = value; \
+ gus.cmd_pool_top += sizeof (type);
+
+static inline void __pool_command(unsigned char command)
+{
+ __POOL_VALUE(char, command);
+}
+
+static inline void __pool_command_b(unsigned char command, unsigned char arg)
+{
+ __POOL_VALUE(char, command);
+ __POOL_VALUE(char, arg);
+}
+
+static inline void __pool_command_w(unsigned char command, unsigned short arg)
+{
+ __POOL_VALUE(char, command);
+ __POOL_VALUE(short, arg);
+}
+
+static inline void __pool_command_l(unsigned char command, unsigned long arg)
+{
+ __POOL_VALUE(char, command);
+ __POOL_VALUE(long, arg);
+}
+
+static inline void __pool_select_voice(unsigned char voice)
+{
+ if (gus.cmd_voice != voice)
+ __pool_command_b(PCMD_VOICE, gus.cmd_voice = voice);
+}
+
+#undef __POOL_VALUE
+
+#ifdef DEBUG
+/* Debug dump of GUS DRAM heap */
+extern void __gus_mem_dump();
+#endif
+
+#endif /* __DOSGUS_H__ */
+
+/* ex:set ts=4: */
--- /dev/null
+/*
+ Implementation of IRQ routines on DOS
+ Copyright (C) 1999 by Andrew Zabolotny, <bit@eltech.ru>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "dosirq.h"
+
+#include <dpmi.h>
+#include <go32.h>
+#include <dos.h>
+#include <sys/nearptr.h>
+#include <malloc.h>
+#include <string.h>
+#include "mikmod.h" /* for MikMod_malloc() & co */
+
+unsigned int __irq_stack_size = 0x4000;
+unsigned int __irq_stack_count = 1;
+
+static void __int_stub_template (void)
+{
+/* *INDENT-OFF* */
+ asm(" pushal\n"
+ " pushl %ds\n"
+ " pushl %es\n"
+ " pushl %fs\n"
+ " pushl %gs\n"
+ " movw $0x1234,%ax\n" /* Get DPMI data selector */
+ " movw %ax,%ds\n" /* Set DS and ES to data selector */
+ " movw %ax,%es\n"
+ " movl $0x12345678,%ebx\n" /* Interrupt stack top */
+ " movl (%ebx),%ecx\n"
+ " movl %ecx,%edx\n"
+ " subl $0x12345678,%ecx\n" /* Subtract irq_stack_count */
+ " movl %ecx,(%ebx)\n"
+ " movw %ss,%si\n" /* Save old SS:ESP */
+ " movl %esp,%edi\n"
+ " movl %edx,%esp\n" /* Set SS:ESP to interrupt stack */
+ " movw %ax,%ss\n"
+ " pushl %esi\n"
+ " pushl %edi\n"
+ " pushl %ebx\n"
+ " pushl %edx\n"
+ " call 1f\n" /* Call user interrupt handler */
+ "1: popl %edx\n"
+ " popl %ebx\n"
+ " movl %edx,(%ebx)\n"
+ " popl %edi\n"
+ " popl %esi\n"
+ " movl %edi,%esp\n" /* Restore old SS:ESP */
+ " movw %si,%ss\n"
+ " popl %gs\n"
+ " popl %fs\n"
+ " popl %es\n"
+ " popl %ds\n"
+ " popal\n"
+ " iret\n");
+/* *INDENT-ON* */
+}
+
+#include <stdio.h>
+
+static int _allocate_iret_wrapper(_go32_dpmi_seginfo * info)
+{
+ unsigned char *irqtpl = (unsigned char *)__int_stub_template;
+ unsigned char *irqend, *irqwrapper, *tmp;
+ __dpmi_meminfo handler_info;
+ unsigned int wrappersize;
+
+ /* First, skip until pushal */
+ while (*irqtpl != 0x60)
+ irqtpl++;
+ /* Now find the iret */
+ irqend = irqtpl;
+ while (*irqend++ != 0xcf);
+
+ wrappersize = 4 + __irq_stack_size * __irq_stack_count + 4 +
+ ((long)irqend - (long)irqtpl);
+ irqwrapper = (unsigned char *) MikMod_malloc(wrappersize);
+ /* Lock the wrapper */
+ handler_info.address = __djgpp_base_address + (unsigned long)irqwrapper;
+ handler_info.size = wrappersize;
+ if (__dpmi_lock_linear_region(&handler_info)) {
+ MikMod_free(irqwrapper);
+ return -1;
+ }
+
+ /* First comes the interrupt wrapper size */
+ *(unsigned long *)irqwrapper = wrappersize;
+
+ /* Next comes the interrupt stack */
+ tmp = irqwrapper + 4 + __irq_stack_size * __irq_stack_count;
+
+ /* The following dword is interrupt stack pointer */
+ *((void **)tmp) = tmp;
+ tmp += 4;
+
+ /* Now comes the interrupt wrapper itself */
+ memcpy(tmp, irqtpl, irqend - irqtpl);
+ *(unsigned short *)(tmp + 9) = _my_ds();
+ *(unsigned long *)(tmp + 16) = (unsigned long)tmp - 4;
+ *(unsigned long *)(tmp + 26) = __irq_stack_size;
+ *(unsigned long *)(tmp + 46) =
+ info->pm_offset - (unsigned long)(tmp + 50);
+
+ info->pm_offset = (unsigned long)tmp;
+ info->pm_selector = _my_cs();
+
+ return 0;
+}
+
+static void _free_iret_wrapper(_go32_dpmi_seginfo * info)
+{
+ __dpmi_meminfo handler_info;
+
+ info->pm_offset -= 4 + __irq_stack_size * __irq_stack_count + 4;
+
+ handler_info.address = __djgpp_base_address + info->pm_offset;
+ handler_info.size = *(unsigned long *)info->pm_offset;
+ __dpmi_unlock_linear_region(&handler_info);
+
+ MikMod_free((void *)info->pm_offset);
+}
+
+struct irq_handle *irq_hook(int irqno, void (*handler)(), unsigned long size)
+{
+ int interrupt;
+ struct irq_handle *irq;
+ __dpmi_version_ret version;
+ __dpmi_meminfo handler_info, struct_info;
+ _go32_dpmi_seginfo info;
+ unsigned long old_sel, old_ofs;
+
+ __dpmi_get_version(&version);
+ if (irqno < 8)
+ interrupt = version.master_pic + irqno;
+ else
+ interrupt = version.slave_pic + (irqno - 8);
+
+ if (_go32_dpmi_get_protected_mode_interrupt_vector(interrupt, &info))
+ return NULL;
+
+ old_sel = info.pm_selector;
+ old_ofs = info.pm_offset;
+
+ info.pm_offset = (unsigned long)handler;
+ if (_allocate_iret_wrapper(&info))
+ return NULL;
+
+ /* Lock the interrupt handler in memory */
+ handler_info.address = __djgpp_base_address + (unsigned long)handler;
+ handler_info.size = size;
+ if (__dpmi_lock_linear_region(&handler_info)) {
+ _free_iret_wrapper(&info);
+ return NULL;
+ }
+
+ irq = (struct irq_handle *) MikMod_malloc(sizeof(struct irq_handle));
+ irq->c_handler = handler;
+ irq->handler_size = size;
+ irq->handler = info.pm_offset;
+ irq->prev_selector = old_sel;
+ irq->prev_offset = old_ofs;
+ irq->int_num = interrupt;
+ irq->irq_num = irqno;
+ irq->pic_base = irqno < 8 ? PIC1_BASE : PIC2_BASE;
+
+ struct_info.address = __djgpp_base_address + (unsigned long)irq;
+ struct_info.size = sizeof(struct irq_handle);
+ if (__dpmi_lock_linear_region(&struct_info)) {
+ MikMod_free(irq);
+ __dpmi_unlock_linear_region(&handler_info);
+ _free_iret_wrapper(&info);
+ return NULL;
+ }
+
+ _go32_dpmi_set_protected_mode_interrupt_vector(interrupt, &info);
+
+ irq->pic_mask = irq_state(irq);
+ return irq;
+}
+
+void irq_unhook(struct irq_handle *irq)
+{
+ _go32_dpmi_seginfo info;
+ __dpmi_meminfo mem_info;
+
+ if (!irq)
+ return;
+
+ /* Restore the interrupt vector */
+ irq_disable(irq);
+ info.pm_offset = irq->prev_offset;
+ info.pm_selector = irq->prev_selector;
+ _go32_dpmi_set_protected_mode_interrupt_vector(irq->int_num, &info);
+
+ /* Unlock the interrupt handler */
+ mem_info.address = __djgpp_base_address + (unsigned long)irq->c_handler;
+ mem_info.size = irq->handler_size;
+ __dpmi_unlock_linear_region(&mem_info);
+
+ /* Unlock the irq_handle structure */
+ mem_info.address = __djgpp_base_address + (unsigned long)irq;
+ mem_info.size = sizeof(struct irq_handle);
+ __dpmi_unlock_linear_region(&mem_info);
+
+ info.pm_offset = irq->handler;
+ _free_iret_wrapper(&info);
+
+ /* If IRQ was enabled before we hooked, restore enabled state */
+ if (irq->pic_mask)
+ irq_enable(irq);
+ else
+ irq_disable(irq);
+
+ MikMod_free(irq);
+}
+
+/*---------------------------------------------- IRQ detection mechanism -----*/
+static struct irq_handle *__irqs[16];
+static int (*__irq_confirm) (int irqno);
+static volatile unsigned int __irq_mask;
+static volatile unsigned int __irq_count[16];
+
+#define DECLARE_IRQ_HANDLER(irqno) \
+static void __irq##irqno##_handler () \
+{ \
+ if (irq_check (__irqs [irqno]) && __irq_confirm (irqno)) \
+ { \
+ __irq_count [irqno]++; \
+ __irq_mask |= (1 << irqno); \
+ } \
+ irq_ack (__irqs [irqno]); \
+}
+
+/* *INDENT-OFF* */
+DECLARE_IRQ_HANDLER(0)
+DECLARE_IRQ_HANDLER(1)
+DECLARE_IRQ_HANDLER(2)
+DECLARE_IRQ_HANDLER(3)
+DECLARE_IRQ_HANDLER(4)
+DECLARE_IRQ_HANDLER(5)
+DECLARE_IRQ_HANDLER(6)
+DECLARE_IRQ_HANDLER(7)
+DECLARE_IRQ_HANDLER(8)
+DECLARE_IRQ_HANDLER(9)
+DECLARE_IRQ_HANDLER(10)
+DECLARE_IRQ_HANDLER(11)
+DECLARE_IRQ_HANDLER(12)
+DECLARE_IRQ_HANDLER(13)
+DECLARE_IRQ_HANDLER(14)
+DECLARE_IRQ_HANDLER(15)
+/* *INDENT-ON* */
+
+static void (*__irq_handlers[16]) () = {
+ __irq0_handler, __irq1_handler, __irq2_handler, __irq3_handler,
+ __irq4_handler, __irq5_handler, __irq6_handler, __irq7_handler,
+ __irq8_handler, __irq9_handler, __irq10_handler, __irq11_handler,
+ __irq12_handler, __irq13_handler, __irq14_handler, __irq15_handler};
+
+void irq_detect_start(unsigned int irqs, int (*irq_confirm) (int irqno))
+{
+ int i;
+
+ __irq_mask = 0;
+ __irq_confirm = irq_confirm;
+ memset(&__irqs, 0, sizeof(__irqs));
+ memset((void *) &__irq_count, 0, sizeof(__irq_count));
+
+ /* Hook all specified IRQs */
+ for (i = 1; i <= 15; i++)
+ if (irqs & (1 << i)) {
+ __irqs[i] = irq_hook(i, __irq_handlers[i], 200);
+ /* Enable the interrupt */
+ irq_enable(__irqs[i]);
+ }
+ /* Enable IRQ2 if we need at least one IRQ above 7 */
+ if (irqs & 0xff00)
+ _irq_enable(2);
+}
+
+void irq_detect_end()
+{
+ int i;
+ for (i = 15; i >= 1; i--)
+ if (__irqs[i])
+ irq_unhook(__irqs[i]);
+}
+
+int irq_detect_get(int irqno, unsigned int *irqmask)
+{
+ int oldirq = disable();
+ int count = __irq_count[irqno];
+ *irqmask = __irq_mask;
+ __irq_mask = 0;
+ if (oldirq)
+ enable();
+ return count;
+}
+
+void irq_detect_clear()
+{
+ int oldirq = disable();
+ memset((void *) &__irq_count, 0, sizeof(__irq_count));
+ __irq_mask = 0;
+ if (oldirq)
+ enable();
+}
+
+/* ex:set ts=4: */
--- /dev/null
+/*
+ Interface for IRQ routines on DOS
+ Copyright (C) 1999 by Andrew Zabolotny, <bit@eltech.ru>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __DOSIRQ_H__
+#define __DOSIRQ_H__
+
+#include <pc.h>
+
+#define PIC1_BASE 0x20 /* PIC1 base */
+#define PIC2_BASE 0xA0 /* PIC2 base */
+
+struct irq_handle {
+ void (*c_handler) (); /* The real interrupt handler */
+ unsigned long handler_size; /* The size of interrupt handler */
+ unsigned long handler; /* Interrupt wrapper address */
+ unsigned long prev_selector; /* Selector of previous handler */
+ unsigned long prev_offset; /* Offset of previous handler */
+ unsigned char irq_num; /* IRQ number */
+ unsigned char int_num; /* Interrupt number */
+ unsigned char pic_base; /* PIC base (0x20 or 0xA0) */
+ unsigned char pic_mask; /* Old PIC mask state */
+};
+
+/* Return the enabled state for specific IRQ */
+static inline unsigned char irq_state(struct irq_handle * irq)
+{
+ return ((~inportb(irq->pic_base + 1)) & (0x01 << (irq->irq_num & 7)));
+}
+
+/* Acknowledge the end of interrupt */
+static inline void _irq_ack(int irqno)
+{
+ outportb(irqno > 7 ? PIC2_BASE : PIC1_BASE, 0x60 | (irqno & 7));
+ /* For second controller we also should acknowledge first controller */
+ if (irqno > 7)
+ outportb(PIC1_BASE, 0x20); /* 0x20, 0x62? */
+}
+
+/* Acknowledge the end of interrupt */
+static inline void irq_ack(struct irq_handle * irq)
+{
+ outportb(irq->pic_base, 0x60 | (irq->irq_num & 7));
+ /* For second controller we also should acknowledge first controller */
+ if (irq->pic_base != PIC1_BASE)
+ outportb(PIC1_BASE, 0x20); /* 0x20, 0x62? */
+}
+
+/* Mask (disable) the particular IRQ given his ordinal */
+static inline void _irq_disable(int irqno)
+{
+ unsigned int port_no = (irqno < 8 ? PIC1_BASE : PIC2_BASE) + 1;
+ outportb(port_no, inportb(port_no) | (1 << (irqno & 7)));
+}
+
+/* Unmask (enable) the particular IRQ given its ordinal */
+static inline void _irq_enable(int irqno)
+{
+ unsigned int port_no = (irqno < 8 ? PIC1_BASE : PIC2_BASE) + 1;
+ outportb(port_no, inportb(port_no) & ~(1 << (irqno & 7)));
+}
+
+/* Mask (disable) the particular IRQ given its irq_handle structure */
+static inline void irq_disable(struct irq_handle * irq)
+{
+ outportb(irq->pic_base + 1,
+ inportb(irq->pic_base + 1) | (1 << (irq->irq_num & 7)));
+}
+
+/* Unmask (enable) the particular IRQ given its irq_handle structure */
+static inline void irq_enable(struct irq_handle * irq)
+{
+ outportb(irq->pic_base + 1,
+ inportb(irq->pic_base + 1) & ~(1 << (irq->irq_num & 7)));
+}
+
+/* Check if a specific IRQ is pending: return 0 is no */
+static inline int irq_check(struct irq_handle * irq)
+{
+ outportb(irq->pic_base, 0x0B); /* Read IRR vector */
+ return (inportb(irq->pic_base) & (1 << (irq->irq_num & 7)));
+}
+
+/* Hook a specific IRQ; NOTE: IRQ is disabled upon return, irq_enable() it */
+extern struct irq_handle *irq_hook(int irqno, void (*handler)(),
+ unsigned long size);
+/* Unhook a previously hooked IRQ */
+extern void irq_unhook(struct irq_handle * irq);
+/* Start IRQ detection process (IRQ list is given with irq mask) */
+/* irq_confirm should return "1" if the IRQ really comes from the device */
+extern void irq_detect_start(unsigned int irqs,
+ int (*irq_confirm) (int irqno));
+/* Finish IRQ detection process */
+extern void irq_detect_end();
+/* Get the count of specific irqno that happened */
+extern int irq_detect_get(int irqno, unsigned int *irqmask);
+/* Clear IRQ counters */
+extern void irq_detect_clear();
+
+/* The size of interrupt stack */
+extern unsigned int __irq_stack_size;
+/* The number of nested interrupts that can be handled */
+extern unsigned int __irq_stack_count;
+
+#endif /* __DOSIRQ_H__ */
+
+/* ex:set ts=4: */
--- /dev/null
+/* MikMod sound library
+ (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
+ complete list.
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+/*==============================================================================
+
+ Sound Blaster I/O routines, common for SB8, SBPro and SB16
+ Written by Andrew Zabolotny <bit@eltech.ru>
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef DRV_SB
+
+#include <stdlib.h>
+#include <dpmi.h>
+#include <go32.h>
+#include <dos.h>
+#include <sys/nearptr.h>
+#include <sys/farptr.h>
+#include <string.h>
+
+#include "dossb.h"
+
+/********************************************* Private variables/routines *****/
+
+__sb_state sb;
+
+/* Wait for SoundBlaster for some time */
+#if !defined(__GNUC__) || (__GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ == 0)
+# define _func_noinline volatile /* match original code */
+# define _func_noclone
+#else
+/* avoid warnings from newer gcc:
+ * "function definition has qualified void return type" and
+ * function return types not compatible due to 'volatile' */
+# define _func_noinline __attribute__((__noinline__))
+# if (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 5)
+# define _func_noclone
+# else
+# define _func_noclone __attribute__((__noclone__))
+# endif
+#endif
+_func_noinline
+_func_noclone
+ void __sb_wait()
+{
+ inportb(SB_DSP_RESET);
+ inportb(SB_DSP_RESET);
+ inportb(SB_DSP_RESET);
+ inportb(SB_DSP_RESET);
+ inportb(SB_DSP_RESET);
+ inportb(SB_DSP_RESET);
+}
+
+static void sb_irq()
+{
+ /* Make sure its not a spurious IRQ */
+ if (!irq_check(sb.irq_handle))
+ return;
+
+ sb.irqcount++;
+
+ /* Acknowledge DMA transfer is complete */
+ if (sb.mode & SBMODE_16BITS)
+ __sb_dsp_ack_dma16();
+ else
+ __sb_dsp_ack_dma8();
+
+ /* SoundBlaster 1.x cannot do autoinit ... */
+ if (sb.dspver < SBVER_20)
+ __sb_dspreg_outwlh(SBDSP_DMA_PCM8, (sb.dma_buff->size >> 1) - 1);
+
+ /* Send EOI */
+ irq_ack(sb.irq_handle);
+
+ enable();
+ if (sb.timer_callback)
+ sb.timer_callback();
+}
+
+static void sb_irq_end()
+{
+}
+
+static boolean __sb_reset()
+{
+ /* Disable the output */
+ sb_output(FALSE);
+
+ /* Clear pending ints if any */
+ __sb_dsp_ack_dma8();
+ __sb_dsp_ack_dma16();
+
+ /* Reset the DSP */
+ outportb(SB_DSP_RESET, SBM_DSP_RESET);
+ __sb_wait();
+ __sb_wait();
+ outportb(SB_DSP_RESET, 0);
+
+ /* Now wait for AA coming from datain port */
+ if (__sb_dsp_in() != 0xaa)
+ return FALSE;
+
+ /* Finally, get the DSP version */
+ if ((sb.dspver = __sb_dsp_version()) == 0xffff)
+ return FALSE;
+ /* Check again */
+ if (sb.dspver != __sb_dsp_version())
+ return FALSE;
+
+ return TRUE;
+}
+
+/***************************************************** SB detection stuff *****/
+
+static int __sb_irq_irqdetect(int irqno)
+{
+ __sb_dsp_ack_dma8();
+ return 1;
+}
+
+static void __sb_irq_dmadetect()
+{
+ /* Make sure its not a spurious IRQ */
+ if (!irq_check(sb.irq_handle))
+ return;
+
+ sb.irqcount++;
+
+ /* Acknowledge DMA transfer is complete */
+ if (sb.mode & SBMODE_16BITS)
+ __sb_dsp_ack_dma16();
+ else
+ __sb_dsp_ack_dma8();
+
+ /* Send EOI */
+ irq_ack(sb.irq_handle);
+}
+
+static boolean __sb_detect()
+{
+ /* First find the port number */
+ if (!sb.port) {
+ int i;
+ for (i = 5; i >= 0; i--) {
+ sb.port = 0x210 + i * 0x10;
+ if (__sb_reset())
+ break;
+ }
+ if (i < 0) {
+ sb.port = 0;
+ return FALSE;
+ }
+ }
+
+ /* Now detect the IRQ and DMA numbers */
+ if (!sb.irq) {
+ unsigned int irqmask, sbirqmask, sbirqcount;
+ unsigned long timer;
+
+ /* IRQ can be one of 2,3,5,7,10 */
+ irq_detect_start(0x04ac, __sb_irq_irqdetect);
+
+ /* Prepare timeout counter */
+ _farsetsel(_dos_ds);
+ timer = _farnspeekl(0x46c);
+
+ sbirqmask = 0;
+ sbirqcount = 10; /* Emit 10 SB irqs */
+
+ /* Tell SoundBlaster to emit IRQ for 8-bit transfers */
+ __sb_dsp_out(SBDSP_GEN_IRQ8);
+ __sb_wait();
+ for (;;) {
+ irq_detect_get(0, &irqmask);
+ if (irqmask) {
+ sbirqmask |= irqmask;
+ if (!--sbirqcount)
+ break;
+ __sb_dsp_out(SBDSP_GEN_IRQ8);
+ }
+ if (_farnspeekl(0x46c) - timer >= 9) /* Wait ~1/2 secs */
+ break;
+ }
+ if (sbirqmask)
+ for (sb.irq = 15; sb.irq > 0; sb.irq--)
+ if (irq_detect_get(sb.irq, &irqmask) == 10)
+ break;
+
+ irq_detect_end();
+ if (!sb.irq)
+ return FALSE;
+ }
+
+ /* Detect the 8-bit and 16-bit DMAs */
+ if (!sb.dma8 || ((sb.dspver >= SBVER_16) && !sb.dma16)) {
+ static int __dma8[] = { 0, 1, 3 };
+ static int __dma16[] = { 5, 6, 7 };
+ int *dma;
+
+ sb_output(FALSE);
+ /* Temporary hook SB IRQ */
+ sb.irq_handle = irq_hook(sb.irq, __sb_irq_dmadetect, 200);
+ irq_enable(sb.irq_handle);
+ if (sb.irq > 7)
+ _irq_enable(2);
+
+ /* Start a short DMA transfer and check if IRQ happened */
+ for (;;) {
+ int i;
+ unsigned int timer, oldcount;
+
+ if (!sb.dma8)
+ dma = &sb.dma8;
+ else if ((sb.dspver >= SBVER_16) && !sb.dma16)
+ dma = &sb.dma16;
+ else
+ break;
+
+ for (i = 0; i < 3; i++) {
+ boolean success = 1;
+
+ *dma = (dma == &sb.dma8) ? __dma8[i] : __dma16[i];
+ oldcount = sb.irqcount;
+
+ dma_disable(*dma);
+ dma_set_mode(*dma, DMA_MODE_WRITE);
+ dma_clear_ff(*dma);
+ dma_set_count(*dma, 2);
+ dma_enable(*dma);
+
+ __sb_dspreg_out(SBDSP_SET_TIMING, 206); /* 20KHz */
+ if (dma == &sb.dma8) {
+ sb.mode = 0;
+ __sb_dspreg_outwlh(SBDSP_DMA_PCM8, 1);
+ } else {
+ sb.mode = SBMODE_16BITS;
+ __sb_dspreg_out(SBDSP_DMA_GENERIC16, 0);
+ __sb_dsp_out(0);
+ __sb_dsp_out(1);
+ }
+
+ _farsetsel(_dos_ds);
+ timer = _farnspeekl(0x46c);
+
+ while (oldcount == sb.irqcount)
+ if (_farnspeekl(0x46c) - timer >= 2) {
+ success = 0;
+ break;
+ }
+ dma_disable(*dma);
+ if (success)
+ break;
+ *dma = 0;
+ }
+ if (!*dma)
+ break;
+ }
+
+ irq_unhook(sb.irq_handle);
+ sb.irq_handle = NULL;
+ if (!sb.dma8 || ((sb.dspver >= SBVER_16) && !sb.dma16))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*************************************************** High-level interface *****/
+
+/* Detect whenever SoundBlaster is present and fill "sb" structure */
+boolean sb_detect()
+{
+ char *env;
+
+ /* Try to find the port and DMA from environment */
+ env = getenv("BLASTER");
+
+ while (env && *env) {
+ /* Skip whitespace */
+ while ((*env == ' ') || (*env == '\t'))
+ env++;
+ if (!*env)
+ break;
+
+ switch (*env++) {
+ case 'A':
+ case 'a':
+ if (!sb.port)
+ sb.port = strtol(env, &env, 16);
+ break;
+ case 'E':
+ case 'e':
+ if (!sb.aweport)
+ sb.aweport = strtol(env, &env, 16);
+ break;
+ case 'I':
+ case 'i':
+ if (!sb.irq)
+ sb.irq = strtol(env, &env, 10);
+ break;
+ case 'D':
+ case 'd':
+ if (!sb.dma8)
+ sb.dma8 = strtol(env, &env, 10);
+ break;
+ case 'H':
+ case 'h':
+ if (!sb.dma16)
+ sb.dma16 = strtol(env, &env, 10);
+ break;
+ default:
+ /* Skip other values (H == MIDI, T == model, any other?) */
+ while (*env && (*env != ' ') && (*env != '\t'))
+ env++;
+ break;
+ }
+ }
+
+ /* Try to detect missing sound card parameters */
+ __sb_detect();
+
+ if (!sb.port || !sb.irq || !sb.dma8)
+ return FALSE;
+
+ if (!__sb_reset())
+ return FALSE;
+
+ if ((sb.dspver >= SBVER_16) && !sb.dma16)
+ return FALSE;
+
+ if (sb.dspver >= SBVER_PRO)
+ sb.caps |= SBMODE_STEREO;
+ if (sb.dspver >= SBVER_16 && sb.dma16)
+ sb.caps |= SBMODE_16BITS;
+ if (sb.dspver < SBVER_20)
+ sb.maxfreq_mono = 22222;
+ else
+ sb.maxfreq_mono = 45454;
+ if (sb.dspver <= SBVER_16)
+ sb.maxfreq_stereo = 22727;
+ else
+ sb.maxfreq_stereo = 45454;
+
+ sb.ok = 1;
+ return TRUE;
+}
+
+/* Reset SoundBlaster */
+void sb_reset()
+{
+ sb_stop_dma();
+ __sb_reset();
+}
+
+/* Start working with SoundBlaster */
+boolean sb_open()
+{
+ __dpmi_meminfo struct_info;
+
+ if (!sb.ok)
+ if (!sb_detect())
+ return FALSE;
+
+ if (sb.open)
+ return FALSE;
+
+ /* Now lock the sb structure in memory */
+ struct_info.address = __djgpp_base_address + (unsigned long)&sb;
+ struct_info.size = sizeof(sb);
+ if (__dpmi_lock_linear_region(&struct_info))
+ return FALSE;
+
+ /* Hook the SB IRQ */
+ sb.irq_handle = irq_hook(sb.irq, sb_irq, (long)sb_irq_end - (long)sb_irq);
+ if (!sb.irq_handle) {
+ __dpmi_unlock_linear_region(&struct_info);
+ return FALSE;
+ }
+
+ /* Enable the interrupt */
+ irq_enable(sb.irq_handle);
+ if (sb.irq > 7)
+ _irq_enable(2);
+
+ sb.open++;
+
+ return TRUE;
+}
+
+/* Finish working with SoundBlaster */
+boolean sb_close()
+{
+ __dpmi_meminfo struct_info;
+ if (!sb.open)
+ return FALSE;
+
+ sb.open--;
+
+ /* Stop/free DMA buffer */
+ sb_stop_dma();
+
+ /* Unhook IRQ */
+ irq_unhook(sb.irq_handle);
+ sb.irq_handle = NULL;
+
+ /* Unlock the sb structure */
+ struct_info.address = __djgpp_base_address + (unsigned long)&sb;
+ struct_info.size = sizeof(sb);
+ __dpmi_unlock_linear_region(&struct_info);
+
+ return TRUE;
+}
+
+/* Enable/disable stereo DSP mode */
+/* Enable/disable speaker output */
+void sb_output(boolean enable)
+{
+ __sb_dsp_out(enable ? SBDSP_SPEAKER_ENA : SBDSP_SPEAKER_DIS);
+}
+
+/* Start playing from DMA buffer */
+boolean sb_start_dma(unsigned char mode, unsigned int freq)
+{
+ int dmachannel = (mode & SBMODE_16BITS) ? sb.dma16 : sb.dma8;
+ int dmabuffsize;
+ unsigned int tc = 0; /* timing constant (<=sbpro only) */
+
+ /* Stop DMA transfer if it is enabled */
+ sb_stop_dma();
+
+ /* Sanity check */
+ if ((mode & SBMODE_MASK & sb.caps) != (mode & SBMODE_MASK))
+ return FALSE;
+
+ /* Check this SB can perform at requested frequency */
+ if (((mode & SBMODE_STEREO) && (freq > sb.maxfreq_stereo))
+ || (!(mode & SBMODE_STEREO) && (freq > sb.maxfreq_mono)))
+ return FALSE;
+
+ /* Check the timing constant here to avoid failing later */
+ if (sb.dspver < SBVER_16) {
+ /* SBpro cannot do signed transfer */
+ if (mode & SBMODE_SIGNED)
+ return FALSE;
+
+ /* Old SBs have a different way on setting DMA timing constant */
+ tc = freq;
+ if (mode & SBMODE_STEREO)
+ tc *= 2;
+ tc = 1000000 / tc;
+ if (tc > 255)
+ return FALSE;
+ }
+
+ sb.mode = mode;
+
+ /* Get a DMA buffer enough for a 1/4sec interval... 4K <= dmasize <= 32K */
+ dmabuffsize = freq;
+ if (mode & SBMODE_STEREO)
+ dmabuffsize *= 2;
+ if (mode & SBMODE_16BITS)
+ dmabuffsize *= 2;
+ dmabuffsize >>= 2;
+ if (dmabuffsize < 4096)
+ dmabuffsize = 4096;
+ if (dmabuffsize > 32768)
+ dmabuffsize = 32768;
+ dmabuffsize = (dmabuffsize + 255) & 0xffffff00;
+
+ sb.dma_buff = dma_allocate(dmachannel, dmabuffsize);
+ if (!sb.dma_buff)
+ return FALSE;
+
+ /* Fill DMA buffer with silence */
+ dmabuffsize = sb.dma_buff->size;
+ if (mode & SBMODE_SIGNED)
+ memset(sb.dma_buff->linear, 0, dmabuffsize);
+ else
+ memset(sb.dma_buff->linear, 0x80, dmabuffsize);
+
+ /* Prime DMA for transfer */
+ dma_start(sb.dma_buff, dmabuffsize, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
+
+ /* Tell SoundBlaster to start transfer */
+ if (sb.dspver >= SBVER_16) { /* SB16 */
+ __sb_dspreg_outwhl(SBDSP_SET_RATE, freq);
+
+ /* Start DMA->DAC transfer */
+ __sb_dspreg_out(SBM_GENDAC_AUTOINIT | SBM_GENDAC_FIFO |
+ ((mode & SBMODE_16BITS) ? SBDSP_DMA_GENERIC16 :
+ SBDSP_DMA_GENERIC8),
+ ((mode & SBMODE_SIGNED) ? SBM_GENDAC_SIGNED : 0) |
+ ((mode & SBMODE_STEREO) ? SBM_GENDAC_STEREO : 0));
+
+ /* Write the length of transfer */
+ dmabuffsize = (dmabuffsize >> 2) - 1;
+ __sb_dsp_out(dmabuffsize);
+ __sb_dsp_out(dmabuffsize >> 8);
+ } else {
+ __sb_dspreg_out(SBDSP_SET_TIMING, 256 - tc);
+ dmabuffsize = (dmabuffsize >> 1) - 1;
+ if (sb.dspver >= SBVER_20) { /* SB 2.0/Pro */
+ /* Set stereo mode */
+ __sb_stereo((mode & SBMODE_STEREO) ? TRUE : FALSE);
+ __sb_dspreg_outwlh(SBDSP_SET_DMA_BLOCK, dmabuffsize);
+ if (sb.dspver >= SBVER_PRO)
+ __sb_dsp_out(SBDSP_HS_DMA_DAC8_AUTO);
+ else
+ __sb_dsp_out(SBDSP_DMA_PCM8_AUTO);
+ } else { /* Original SB */
+ /* Start DMA->DAC transfer */
+ __sb_dspreg_outwlh(SBDSP_DMA_PCM8, dmabuffsize);
+ }
+ }
+
+ return TRUE;
+}
+
+/* Stop playing from DMA buffer */
+void sb_stop_dma()
+{
+ if (!sb.dma_buff)
+ return;
+
+ if (sb.mode & SBMODE_16BITS)
+ __sb_dsp_out(SBDSP_DMA_HALT16);
+ else
+ __sb_dsp_out(SBDSP_DMA_HALT8);
+
+ dma_disable(sb.dma_buff->channel);
+ dma_free(sb.dma_buff);
+ sb.dma_buff = NULL;
+}
+
+/* Query current position/total size of the DMA buffer */
+void sb_query_dma(unsigned int *dma_size, unsigned int *dma_pos)
+{
+ unsigned int dma_left;
+ *dma_size = sb.dma_buff->size;
+ /* It can happen we try to read DMA count when HI/LO bytes will be
+ inconsistent */
+ for (;;) {
+ unsigned int dma_left_test;
+ dma_clear_ff(sb.dma_buff->channel);
+ dma_left_test = dma_get_count(sb.dma_buff->channel);
+ dma_left = dma_get_count(sb.dma_buff->channel);
+ if ((dma_left >= dma_left_test) && (dma_left - dma_left_test < 10))
+ break;
+ }
+ *dma_pos = *dma_size - dma_left;
+}
+
+#endif /* DRV_SB */
+
+/* ex:set ts=4: */
--- /dev/null
+/* MikMod sound library
+ (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
+ complete list.
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+/*==============================================================================
+
+ $Id$
+
+ SoundBlaster and compatible soundcards definitions
+
+==============================================================================*/
+
+#ifndef __DOSSB_H__
+#define __DOSSB_H__
+
+#include "dosdma.h"
+#include "dosirq.h"
+
+#define SB_FM_LEFT_STATUS (sb.port + 0x00) /* (r) Left FM status */
+#define SB_FM_LEFT_REGSEL (sb.port + 0x00) /* (w) Left FM register select */
+#define SB_FM_LEFT_DATA (sb.port + 0x01) /* (w) Left FM data */
+#define SB_FM_RIGHT_STATUS (sb.port + 0x02) /* (r) Right FM status */
+#define SB_FM_RIGHT_REGSEL (sb.port + 0x02) /* (w) Right FM register select */
+#define SB_FM_RIGHT_DATA (sb.port + 0x03) /* (w) Right FM data */
+#define SB_MIXER_REGSEL (sb.port + 0x04) /* (w) Mixer register select */
+#define SB_MIXER_DATA (sb.port + 0x05) /* (rw)Mixer data */
+#define SB_DSP_RESET (sb.port + 0x06) /* (w) DSP reset */
+#define SB_FM_STATUS (sb.port + 0x08) /* (r) FM status */
+#define SB_FM_REGSEL (sb.port + 0x08) /* (w) FM register select */
+#define SB_FM_DATA (sb.port + 0x09) /* (w) FM data */
+#define SB_DSP_DATA_IN (sb.port + 0x0a) /* (r) DSP data input */
+#define SB_DSP_DATA_OUT (sb.port + 0x0c) /* (w) DSP data output */
+#define SB_DSP_DATA_OUT_STATUS (sb.port + 0x0c) /* (r) DSP data output status */
+#define SB_DSP_TIMER_IRQ (sb.port + 0x0d) /* (r) clear timer IRQ? */
+#define SB_DSP_DATA_IN_STATUS (sb.port + 0x0e) /* (r) DSP data input status */
+#define SB_DSP_DMA8_IRQ (sb.port + 0x0e) /* (r) Acknowledge 8-bit DMA transfer */
+#define SB_DSP_DMA16_IRQ (sb.port + 0x0f) /* (r) Acknowledge 16-bit DMA transfer */
+
+/* DSP commands */
+#define SBDSP_ASP_STATUS 0x03 /* ASP Status (SB16ASP) */
+#define SBDSP_STATUS_OLD 0x04 /* DSP Status (Obsolete) (SB2.0-Pro2) */
+#define SBDSP_DIRECT_DAC 0x10 /* Direct DAC, 8-bit (SB) */
+#define SBDSP_DMA_PCM8 0x14 /* DMA DAC, 8-bit (SB) */
+#define SBDSP_DMA_ADPCM2 0x16 /* DMA DAC, 2-bit ADPCM (SB) */
+#define SBDSP_DMA_ADPCM2R 0x17 /* DMA DAC, 2-bit ADPCM Reference (SB) */
+#define SBDSP_DMA_PCM8_AUTO 0x1C /* Auto-Initialize DMA DAC, 8-bit (SB2.0) */
+#define SBDSP_DMA_ADPCM2R_AUTO 0x1F /* Auto-Initialize DMA DAC, 2-bit ADPCM Reference (SB2.0) */
+#define SBDSP_DIRECT_ADC 0x20 /* Direct ADC, 8-bit (SB) */
+#define SBDSP_DMA_ADC8 0x24 /* DMA ADC, 8-bit (SB) */
+#define SBDSP_DIRECT_ADC8_BURST 0x28 /* Direct ADC, 8-bit (Burst) (SB-Pro2) */
+#define SBDSP_DMA_ADC8_AUTO 0x2C /* Auto-Initialize DMA ADC, 8-bit (SB2.0) */
+#define SBDSP_MIDI_READ_POLL 0x30 /* MIDI Read Poll (SB) */
+#define SBDSP_MIDI_READ_IRQ 0x31 /* MIDI Read Interrupt (SB) */
+#define SBDSP_MIDI_READ_TIME 0x32 /* MIDI Read Timestamp Poll (SB???) */
+#define SBDSP_MIDI_READ_TIME_IRQ 0x33 /* MIDI Read Timestamp Interrupt (SB???) */
+#define SBDSP_MIDI_RW_POLL 0x34 /* MIDI Read Poll + Write Poll (UART) (SB2.0) */
+#define SBDSP_MIDI_RW_IRQ 0x35 /* MIDI Read Interrupt + Write Poll (UART) (SB2.0???) */
+#define SBDSP_MIDI_RW_TIME_IRQ 0x37 /* MIDI Read Timestamp Interrupt + Write Poll (UART) (SB2.0???) */
+#define SBDSP_MIDI_WRITE_POLL 0x38 /* MIDI Write Poll (SB) */
+#define SBDSP_SET_TIMING 0x40 /* Set Time Constant (SB) */
+#define SBDSP_SET_RATE 0x41 /* Set Sample Rate, Hz (SB16) */
+#define SBDSP_DMA_CONT8_AUTO 0x45 /* Continue Auto-Initialize DMA, 8-bit (SB16) */
+#define SBDSP_DMA_CONT16_AUTO 0x47 /* Continue Auto-Initialize DMA, 16-bit (SB16) */
+#define SBDSP_SET_DMA_BLOCK 0x48 /* Set DMA Block Size (SB2.0) */
+#define SBDSP_DMA_ADPCM4 0x74 /* DMA DAC, 4-bit ADPCM (SB) */
+#define SBDSP_DMA_ADPCM4_REF 0x75 /* DMA DAC, 4-bit ADPCM Reference (SB) */
+#define SBDSP_DMA_ADPCM26 0x76 /* DMA DAC, 2.6-bit ADPCM (SB) */
+#define SBDSP_DMA_ADPCM26_REF 0x77 /* DMA DAC, 2.6-bit ADPCM Reference (SB) */
+#define SBDSP_DMA_ADPCM4R_AUTO 0x7D /* Auto-Initialize DMA DAC, 4-bit ADPCM Reference (SB2.0) */
+#define SBDSP_DMA_ADPCM26R_AUTO 0x7F /* Auto-Initialize DMA DAC, 2.6-bit ADPCM Reference (SB2.0) */
+#define SBDSP_DISABLE_DAC 0x80 /* Silence DAC (SB) */
+#define SBDSP_HS_DMA_DAC8_AUTO 0x90 /* Auto-Initialize DMA DAC, 8-bit (High Speed) (SB2.0-Pro2) */
+#define SBDSP_HS_DMA_ADC8_AUTO 0x98 /* Auto-Initialize DMA ADC, 8-bit (High Speed) (SB2.0-Pro2) */
+#define SBDSP_STEREO_ADC_DIS 0xA0 /* Disable Stereo Input Mode (SBPro Only) */
+#define SBDSP_STEREO_ADC_ENA 0xA8 /* Enable Stereo Input Mode (SBPro Only) */
+#define SBDSP_DMA_GENERIC16 0xB0 /* Generic DAC/ADC DMA (16-bit) (SB16) */
+#define SBDSP_DMA_GENERIC8 0xC0 /* Generic DAC/ADC DMA (8-bit) (SB16) */
+#define SBDSP_DMA_HALT8 0xD0 /* Halt DMA Operation, 8-bit (SB) */
+#define SBDSP_SPEAKER_ENA 0xD1 /* Enable Speaker (SB) */
+#define SBDSP_SPEAKER_DIS 0xD3 /* Disable Speaker (SB) */
+#define SBDSP_DMA_CONT8 0xD4 /* Continue DMA Operation, 8-bit (SB) */
+#define SBDSP_DMA_HALT16 0xD5 /* Halt DMA Operation, 16-bit (SB16) */
+#define SBDSP_DMA_CONT16 0xD6 /* Continue DMA Operation, 16-bit (SB16) */
+#define SBDSP_SPEAKER_STATUS 0xD8 /* Speaker Status (SB) */
+#define SBDSP_DMA_EXIT16_AUTO 0xD9 /* Exit Auto-Initialize DMA Operation, 16-bit (SB16) */
+#define SBDSP_DMA_EXIT8_AUTO 0xDA /* Exit Auto-Initialize DMA Operation, 8-bit (SB2.0) */
+#define SBDSP_IDENTIFY 0xE0 /* DSP Identification (SB2.0) */
+#define SBDSP_VERSION 0xE1 /* DSP Version (SB) */
+#define SBDSP_COPYRIGHT 0xE3 /* DSP Copyright (SBPro2???) */
+#define SBDSP_WRITE_TEST 0xE4 /* Write Test Register (SB2.0) */
+#define SBDSP_READ_TEST 0xE8 /* Read Test Register (SB2.0) */
+#define SBDSP_SINE_GEN 0xF0 /* Sine Generator (SB) */
+#define SBDSP_AUX_STATUS_PRO 0xF1 /* DSP Auxiliary Status (Obsolete) (SB-Pro2) */
+#define SBDSP_GEN_IRQ8 0xF2 /* IRQ Request, 8-bit (SB) */
+#define SBDSP_GEN_IRQ16 0xF3 /* IRQ Request, 16-bit (SB16) */
+#define SBDSP_STATUS 0xFB /* DSP Status (SB16) */
+#define SBDSP_AUX_STATUS_16 0xFC /* DSP Auxiliary Status (SB16) */
+#define SBDSP_CMD_STATUS 0xFD /* DSP Command Status (SB16) */
+
+/* Mixer commands */
+#define SBMIX_RESET 0x00 /* Reset Write SBPro */
+#define SBMIX_STATUS 0x01 /* Status Read SBPro */
+#define SBMIX_MASTER_LEVEL1 0x02 /* Master Volume Read/Write SBPro Only */
+#define SBMIX_DAC_LEVEL 0x04 /* DAC Level Read/Write SBPro */
+#define SBMIX_FM_OUTPUT 0x06 /* FM Output Control Read/Write SBPro Only */
+#define SBMIX_MIC_LEVEL 0x0A /* Microphone Level Read/Write SBPro */
+#define SBMIX_INPUT_SELECT 0x0C /* Input/Filter Select Read/Write SBPro Only */
+#define SBMIX_OUTPUT_SELECT 0x0E /* Output/Stereo Select Read/Write SBPro Only */
+#define SBMIX_FM_LEVEL 0x22 /* Master Volume Read/Write SBPro */
+#define SBMIX_MASTER_LEVEL 0x26 /* FM Level Read/Write SBPro */
+#define SBMIX_CD_LEVEL 0x28 /* CD Audio Level Read/Write SBPro */
+#define SBMIX_LINEIN_LEVEL 0x2E /* Line In Level Read/Write SBPro */
+#define SBMIX_MASTER_LEVEL_L 0x30 /* Master Volume Left Read/Write SB16 */
+#define SBMIX_MASTER_LEVEL_R 0x31 /* Master Volume Right Read/Write SB16 */
+#define SBMIX_DAC_LEVEL_L 0x32 /* DAC Level Left Read/Write SB16 */
+#define SBMIX_DAC_LEVEL_R 0x33 /* DAC Level Right Read/Write SB16 */
+#define SBMIX_FM_LEVEL_L 0x34 /* FM Level Left Read/Write SB16 */
+#define SBMIX_FM_LEVEL_R 0x35 /* FM Level Right Read/Write SB16 */
+#define SBMIX_CD_LEVEL_L 0x36 /* CD Audio Level Left Read/Write SB16 */
+#define SBMIX_CD_LEVEL_R 0x37 /* CD Audio Level Right Read/Write SB16 */
+#define SBMIX_LINEIN_LEVEL_L 0x38 /* Line In Level Left Read/Write SB16 */
+#define SBMIX_LINEIN_LEVEL_R 0x39 /* Line In Level Right Read/Write SB16 */
+#define SBMIX_MIC_LEVEL_16 0x3A /* Microphone Level Read/Write SB16 */
+#define SBMIX_PCSPK_LEVEL 0x3B /* PC Speaker Level Read/Write SB16 */
+#define SBMIX_OUTPUT_CONTROL 0x3C /* Output Control Read/Write SB16 */
+#define SBMIX_INPUT_CONTROL_L 0x3D /* Input Control Left Read/Write SB16 */
+#define SBMIX_INPUT_CONTROL_R 0x3E /* Input Control Right Read/Write SB16 */
+#define SBMIX_INPUT_GAIN_L 0x3F /* Input Gain Control Left Read/Write SB16 */
+#define SBMIX_INPUT_GAIN_R 0x40 /* Input Gain Control Right Read/Write SB16 */
+#define SBMIX_OUTPUT_GAIN_L 0x41 /* Output Gain Control Left Read/Write SB16 */
+#define SBMIX_OUTPUT_GAIN_R 0x42 /* Output Gain Control Right Read/Write SB16 */
+#define SBMIX_AGC_CONTROL 0x43 /* Automatic Gain Control (AGC) Read/Write SB16 */
+#define SBMIX_TREBLE_L 0x44 /* Treble Left Read/Write SB16 */
+#define SBMIX_TREBLE_R 0x45 /* Treble Right Read/Write SB16 */
+#define SBMIX_BASS_L 0x46 /* Bass Left Read/Write SB16 */
+#define SBMIX_BASS_R 0x47 /* Bass Right Read/Write SB16 */
+#define SBMIX_IRQ_SELECT 0x80 /* IRQ Select Read/Write SB16 */
+#define SBMIX_DMA_SELECT 0x81 /* DMA Select Read/Write SB16 */
+#define SBMIX_IRQ_STATUS 0x82 /* IRQ Status Read SB16 */
+
+/* SB_DSP_DATA_OUT_STATUS and SB_DSP_DATA_IN_STATUS bits */
+#define SBM_DSP_READY 0x80
+
+/* SB_DSP_RESET / SBMIX_RESET */
+#define SBM_DSP_RESET 0x01
+
+/* SBMIX_OUTPUT_SELECT */
+#define SBM_MIX_STEREO 0x02
+#define SBM_MIX_FILTER 0x20
+
+/* SBDSP_DMA_GENERIC16/SBDSP_DMA_GENERIC8 */
+#define SBM_GENDAC_FIFO 0x02
+#define SBM_GENDAC_AUTOINIT 0x04
+#define SBM_GENDAC_ADC 0x08
+/* Second (mode) byte */
+#define SBM_GENDAC_SIGNED 0x10
+#define SBM_GENDAC_STEREO 0x20
+
+/* DSP version masks */
+#define SBVER_10 0x0100 /* Original SoundBlaster */
+#define SBVER_15 0x0105 /* SoundBlaster 1.5 */
+#define SBVER_20 0x0200 /* SoundBlaster 2.0 */
+#define SBVER_PRO 0x0300 /* SoundBlaster Pro */
+#define SBVER_PRO2 0x0301 /* SoundBlaster Pro 2 */
+#define SBVER_16 0x0400 /* SoundBlaster 16 */
+#define SBVER_AWE32 0x040c /* SoundBlaster AWE32 */
+
+typedef unsigned char boolean;
+
+#ifndef FALSE
+#define FALSE 0
+#define TRUE 1
+#endif
+
+/* Play mode bits */
+#define SBMODE_16BITS 0x0001
+#define SBMODE_STEREO 0x0002
+#define SBMODE_SIGNED 0x0004
+
+/* Mask for capabilities that never change */
+#define SBMODE_MASK (SBMODE_16BITS | SBMODE_STEREO)
+
+/* You can fill some members of this struct (i.e. port,irq,dma) before
+ * calling sb_detect() or sb_open()... this will ignore environment settings.
+ */
+typedef struct __sb_state_s {
+ boolean ok; /* Are structure contents valid? */
+ int port, aweport; /* sb/awe32 base port */
+ int irq; /* SoundBlaster IRQ */
+ int dma8, dma16; /* 8-bit and 16-bit DMAs */
+ int maxfreq_mono; /* Maximum discretization frequency / mono mode */
+ int maxfreq_stereo; /* Maximum discretization frequency / stereo mode */
+ unsigned short dspver; /* DSP version number */
+ struct irq_handle *irq_handle; /* The interrupt handler */
+ dma_buffer *dma_buff; /* Pre-allocated DMA buffer */
+ unsigned char caps; /* SoundBlaster capabilities (SBMODE_XXX) */
+ unsigned char mode; /* Current SB mode (SBMODE_XXX) */
+ boolean open; /* Whenever the card has been opened */
+ volatile int irqcount; /* Incremented on each IRQ... for diagnostics */
+ void (*timer_callback) (); /* Called TWICE per buffer play */
+} __sb_state;
+
+extern __sb_state sb;
+
+extern void __sb_wait();
+
+static inline boolean __sb_dsp_ready_in()
+{
+ int count;
+ for (count = 10000; count >= 0; count--)
+ if (inportb(SB_DSP_DATA_IN_STATUS) & SBM_DSP_READY)
+ return TRUE;
+ return FALSE;
+}
+
+static inline boolean __sb_dsp_ready_out()
+{
+ int count;
+ for (count = 10000; count >= 0; count--)
+ if ((inportb(SB_DSP_DATA_OUT_STATUS) & SBM_DSP_READY) == 0)
+ return TRUE;
+ return FALSE;
+}
+
+static inline void __sb_dsp_out(unsigned char reg)
+{
+ __sb_dsp_ready_out();
+ outportb(SB_DSP_DATA_OUT, reg);
+}
+
+static inline unsigned char __sb_dsp_in()
+{
+ __sb_dsp_ready_in();
+ return inportb(SB_DSP_DATA_IN);
+}
+
+static inline void __sb_dspreg_out(unsigned char reg, unsigned char val)
+{
+ __sb_dsp_out(reg);
+ __sb_dsp_out(val);
+}
+
+static inline void __sb_dspreg_outwlh(unsigned char reg, unsigned short val)
+{
+ __sb_dsp_out(reg);
+ __sb_dsp_out(val);
+ __sb_dsp_out(val >> 8);
+}
+
+static inline void __sb_dspreg_outwhl(unsigned char reg, unsigned short val)
+{
+ __sb_dsp_out(reg);
+ __sb_dsp_out(val >> 8);
+ __sb_dsp_out(val);
+}
+
+static inline unsigned char __sb_dspreg_in(unsigned char reg)
+{
+ __sb_dsp_out(reg);
+ return __sb_dsp_in();
+}
+
+static inline void __sb_dsp_ack_dma8()
+{
+ inportb(SB_DSP_DMA8_IRQ);
+}
+
+static inline void __sb_dsp_ack_dma16()
+{
+ inportb(SB_DSP_DMA16_IRQ);
+}
+
+static inline unsigned short __sb_dsp_version()
+{
+ unsigned short ver;
+ __sb_dsp_out(SBDSP_VERSION);
+ __sb_dsp_ready_in();
+ ver = ((unsigned short)__sb_dsp_in()) << 8;
+ ver |= __sb_dsp_in();
+ return ver;
+}
+
+static inline void __sb_mixer_out(unsigned char reg, unsigned char val)
+{
+ outportb(SB_MIXER_REGSEL, reg);
+ outportb(SB_MIXER_DATA, val);
+}
+
+static inline unsigned char __sb_mixer_in(unsigned char reg)
+{
+ outportb(SB_MIXER_REGSEL, reg);
+ return inportb(SB_MIXER_DATA);
+}
+
+/* Enable stereo transfers: sbpro mode only */
+static inline void __sb_stereo(boolean stereo)
+{
+ unsigned char val = __sb_mixer_in(SBMIX_OUTPUT_SELECT);
+ if (stereo)
+ val |= SBM_MIX_STEREO;
+ else
+ val &= ~SBM_MIX_STEREO;
+ __sb_mixer_out(SBMIX_OUTPUT_SELECT, val);
+}
+
+/* Detect whenever SoundBlaster is present and fill "sb" structure */
+extern boolean sb_detect();
+/* Reset SoundBlaster */
+extern void sb_reset();
+/* Start working with SoundBlaster */
+extern boolean sb_open();
+/* Finish working with SoundBlaster */
+extern boolean sb_close();
+/* Enable/disable speaker output */
+extern void sb_output(boolean enable);
+/* Start playing from DMA buffer in either 8/16 bit mono/stereo */
+extern boolean sb_start_dma(unsigned char mode, unsigned int freq);
+/* Stop playing from DMA buffer */
+extern void sb_stop_dma();
+/* Query current position/total size of the DMA buffer */
+extern void sb_query_dma(unsigned int *dma_size, unsigned int *dma_pos);
+
+#endif /* __DOSSB_H__ */
+
+/* ex:set ts=4: */
--- /dev/null
+/* MikMod sound library
+ (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
+ complete list.
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+/*==============================================================================
+
+ Windows Sound System I/O routines (CS42XX, ESS18XX, GUS+DaughterBoard etc)
+ Written by Andrew Zabolotny <bit@eltech.ru>
+
+==============================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef DRV_WSS
+
+#include <stdlib.h>
+#include <dpmi.h>
+#include <go32.h>
+#include <dos.h>
+#include <sys/nearptr.h>
+#include <sys/farptr.h>
+#include <string.h>
+
+#include "doswss.h"
+
+/********************************************* Private variables/routines *****/
+
+__wss_state wss;
+
+/* WSS frequency rates... lower bit selects one of two frequency generators */
+static unsigned int wss_rates[14][2] = {
+ {5510, 0x00 | WSSM_XTAL2},
+ {6620, 0x0E | WSSM_XTAL2},
+ {8000, 0x00 | WSSM_XTAL1},
+ {9600, 0x0E | WSSM_XTAL1},
+ {11025, 0x02 | WSSM_XTAL2},
+ {16000, 0x02 | WSSM_XTAL1},
+ {18900, 0x04 | WSSM_XTAL2},
+ {22050, 0x06 | WSSM_XTAL2},
+ {27420, 0x04 | WSSM_XTAL1},
+ {32000, 0x06 | WSSM_XTAL1},
+ {33075, 0x0C | WSSM_XTAL2},
+ {37800, 0x08 | WSSM_XTAL2},
+ {44100, 0x0A | WSSM_XTAL2},
+ {48000, 0x0C | WSSM_XTAL1}
+};
+
+static void wss_irq()
+{
+ /* Make sure its not a spurious IRQ */
+ if (!irq_check(wss.irq_handle))
+ return;
+
+ wss.irqcount++;
+
+ /* Clear IRQ status */
+ outportb(WSS_STATUS, 0);
+
+ /* Write transfer count again */
+ __wss_outreg(WSSR_COUNT_LOW, wss.samples & 0xff);
+ __wss_outreg(WSSR_COUNT_HIGH, wss.samples >> 8);
+ irq_ack(wss.irq_handle);
+
+ enable();
+ if (wss.timer_callback)
+ wss.timer_callback();
+}
+
+static void wss_irq_end()
+{
+}
+
+/* WSS accepts some conventional values instead of frequency in Hz... */
+static unsigned char __wss_getrate(unsigned int *freq)
+{
+ int i, best = -1, delta = 0xffff;
+
+ for (i = 0; i < 14; i++) {
+ int newdelta = abs(wss_rates[i][0] - *freq);
+ if (newdelta < delta)
+ best = i, delta = newdelta;
+ }
+
+ *freq = wss_rates[best][0];
+ return wss_rates[best][1];
+}
+
+/* Check if we really have a WSS compatible card on given address */
+static boolean __wss_ping()
+{
+ /* Disable CODEC operations first */
+ __wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
+ /* Now put some harmless values in registers and check them */
+ __wss_outreg(WSSR_COUNT_LOW, 0xaa);
+ __wss_outreg(WSSR_COUNT_HIGH, 0x55);
+ return (__wss_inreg(WSSR_COUNT_LOW) == 0xaa)
+ && (__wss_inreg(WSSR_COUNT_HIGH) == 0x55);
+}
+
+static boolean __wss_reset()
+{
+ int count;
+
+ /* Disable output */
+ wss_output(FALSE);
+
+ /* Now select the test/initialization register */
+ count = 10000;
+ while (inportb(WSS_ADDR) != WSSR_TEST_INIT) {
+ outportb(WSS_ADDR, WSSR_TEST_INIT);
+ if (!--count)
+ return FALSE;
+ }
+
+ count = 10000;
+ while (inportb(WSS_DATA) & WSSM_CALIB_IN_PROGRESS) {
+ outportb(WSS_ADDR, WSSR_TEST_INIT);
+ if (!--count)
+ return FALSE;
+ }
+
+ /* Enable playback IRQ */
+ __wss_regbit_set(WSSR_PIN_CTRL, WSSM_IRQ_ENABLE);
+ __wss_outreg(WSSR_IRQ_STATUS, WSSM_PLAYBACK_IRQ);
+
+ /* Clear IRQ status */
+ outportb(WSS_STATUS, 0);
+
+ return TRUE;
+}
+
+static boolean __wss_setformat(unsigned char format)
+{
+ int count;
+
+ outportb(WSS_ADDR, WSSM_MCE | WSSR_PLAY_FORMAT);
+ outportb(WSS_DATA, format);
+ inportb(WSS_DATA); /* ERRATA SHEETS ... */
+ inportb(WSS_DATA); /* ERRATA SHEETS ... */
+
+ /* Wait end of syncronization ... */
+ if (!__wss_wait())
+ return FALSE;
+
+ /* Turn off the ModeChangeEnable bit: do it until it works */
+ count = 10000;
+ while (inportb(WSS_ADDR) != WSSR_PLAY_FORMAT) {
+ outportb(WSS_ADDR, WSSR_PLAY_FORMAT);
+ if (!--count)
+ return FALSE;
+ }
+
+ return __wss_reset();
+}
+
+/**************************************************** WSS detection stuff *****/
+
+static int __wss_irq_irqdetect(int irqno)
+{
+ unsigned char status = inportb(WSS_STATUS);
+ /* Clear IRQ status */
+ outportb(WSS_STATUS, 0);
+ /* Reset transfer counter */
+ __wss_outreg(WSSR_COUNT_LOW, 0);
+ __wss_outreg(WSSR_COUNT_HIGH, 0);
+ return (status & WSSM_INT);
+}
+
+static boolean __wss_detect()
+{
+ /* First find the port number */
+ if (!wss.port) {
+ static unsigned int wss_ports[] =
+ { 0x32c, 0x530, 0x604, 0xE80, 0xF40 };
+ int i;
+ for (i = 0; i < 5; i++) {
+ wss.port = wss_ports[i];
+ if (__wss_ping())
+ break;
+ }
+ if (i < 0) {
+ wss.port = 0;
+ return FALSE;
+ }
+ }
+
+ /* Now disable output */
+ wss_output(FALSE);
+
+ /* Detect the DMA channel */
+ if (!wss.dma) {
+ static int __dma[] = { 0, 1, 3 };
+ int i;
+
+ /* Enable playback IRQ */
+ __wss_regbit_set(WSSR_PIN_CTRL, WSSM_IRQ_ENABLE);
+ __wss_outreg(WSSR_IRQ_STATUS, WSSM_PLAYBACK_IRQ);
+
+ /* Start a short DMA transfer and check if DMA count is zero */
+ for (i = 0; i < 3; i++) {
+ unsigned int timer, status, freq = 44100;
+
+ wss.dma = __dma[i];
+
+ dma_disable(wss.dma);
+ dma_set_mode(wss.dma, DMA_MODE_WRITE);
+ dma_clear_ff(wss.dma);
+ dma_set_count(wss.dma, 10);
+ dma_enable(wss.dma);
+
+ /* Clear IRQ status */
+ outportb(WSS_STATUS, 0);
+
+ __wss_setformat(__wss_getrate(&freq));
+ __wss_outreg(WSSR_COUNT_LOW, 1);
+ __wss_outreg(WSSR_COUNT_HIGH, 0);
+ /* Tell codec to start transfer */
+ __wss_regbit_set(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
+
+ _farsetsel(_dos_ds);
+ timer = _farnspeekl(0x46c);
+
+ while (_farnspeekl(0x46c) - timer <= 2)
+ if (dma_get_count(wss.dma) == 0)
+ break;
+ __wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
+ dma_disable(wss.dma);
+
+ /* Now check if DMA transfer count is zero and an IRQ is pending */
+ status = inportb(WSS_STATUS);
+ outportb(WSS_STATUS, 0);
+ if ((dma_get_count(wss.dma) == 0) && (status & WSSM_INT))
+ break;
+
+ wss.dma = 0;
+ }
+
+ if (!wss.dma)
+ return FALSE;
+ }
+
+ /* Now detect the IRQ number */
+ if (!wss.irq) {
+ unsigned int i, irqmask, freq = 5510;
+ unsigned long timer, delta = 0x7fffffff;
+
+ /* IRQ can be one of 2,3,5,7,10 */
+ irq_detect_start(0x04ac, __wss_irq_irqdetect);
+
+ dma_disable(wss.dma);
+ dma_set_mode(wss.dma, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
+ dma_clear_ff(wss.dma);
+ dma_set_count(wss.dma, 1);
+ dma_enable(wss.dma);
+
+ __wss_setformat(__wss_getrate(&freq));
+
+ /* Clear IRQ status */
+ outportb(WSS_STATUS, 0);
+
+ __wss_outreg(WSSR_COUNT_LOW, 0);
+ __wss_outreg(WSSR_COUNT_HIGH, 0);
+
+ /* Prepare timeout counter */
+ _farsetsel(_dos_ds);
+ timer = _farnspeekl(0x46c);
+ while (timer == _farnspeekl(0x46c));
+ timer = _farnspeekl(0x46c);
+
+ /* Reset all IRQ counters */
+ irq_detect_clear();
+
+ /* Tell codec to start transfer */
+ __wss_regbit_set(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
+
+ /* Now wait 1/18 seconds */
+ while (timer == _farnspeekl(0x46c));
+ __wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
+ dma_disable(wss.dma);
+
+ /* Given frequency 5510Hz, a buffer size of 1 byte and a time interval
+ of 1/18.2 second, we should have received about 302 interrupts */
+ for (i = 2; i <= 10; i++) {
+ int count = abs(302 - irq_detect_get(i, &irqmask));
+ if (count < delta)
+ wss.irq = i, delta = count;
+ }
+ if (delta > 150)
+ wss.irq = 0;
+
+ irq_detect_end();
+ if (!wss.irq)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*************************************************** High-level interface *****/
+
+/* Detect whenever WSS is present and fill "wss" structure */
+boolean wss_detect()
+{
+ char *env;
+
+ /* Try to find the port and DMA from environment */
+ env = getenv("WSS");
+
+ while (env && *env) {
+ /* Skip whitespace */
+ while ((*env == ' ') || (*env == '\t'))
+ env++;
+ if (!*env)
+ break;
+
+ switch (*env++) {
+ case 'A':
+ case 'a':
+ if (!wss.port)
+ wss.port = strtol(env, &env, 16);
+ break;
+ case 'I':
+ case 'i':
+ if (!wss.irq)
+ wss.irq = strtol(env, &env, 10);
+ break;
+ case 'D':
+ case 'd':
+ if (!wss.dma)
+ wss.dma = strtol(env, &env, 10);
+ break;
+ default:
+ /* Skip other values */
+ while (*env && (*env != ' ') && (*env != '\t'))
+ env++;
+ break;
+ }
+ }
+
+ /* Try to fill the gaps in wss hardware parameters */
+ __wss_detect();
+
+ if (!wss.port || !wss.irq || !wss.dma)
+ return FALSE;
+
+ if (!__wss_ping())
+ return FALSE;
+
+ if (!__wss_reset())
+ return FALSE;
+
+ wss.ok = 1;
+ return TRUE;
+}
+
+/* Reset WSS */
+void wss_reset()
+{
+ wss_stop_dma();
+ __wss_reset();
+}
+
+/* Open WSS for usage */
+boolean wss_open()
+{
+ __dpmi_meminfo struct_info;
+
+ if (!wss.ok)
+ if (!wss_detect())
+ return FALSE;
+
+ if (wss.open)
+ return FALSE;
+
+ /* Now lock the wss structure in memory */
+ struct_info.address = __djgpp_base_address + (unsigned long)&wss;
+ struct_info.size = sizeof(wss);
+ if (__dpmi_lock_linear_region(&struct_info))
+ return FALSE;
+
+ /* Hook the WSS IRQ */
+ wss.irq_handle =
+ irq_hook(wss.irq, wss_irq, (long)wss_irq_end - (long)wss_irq);
+ if (!wss.irq_handle) {
+ __dpmi_unlock_linear_region(&struct_info);
+ return FALSE;
+ }
+
+ /* Enable the interrupt */
+ irq_enable(wss.irq_handle);
+ if (wss.irq > 7)
+ _irq_enable(2);
+
+ wss.open++;
+
+ return TRUE;
+}
+
+/* Finish working with WSS */
+boolean wss_close()
+{
+ __dpmi_meminfo struct_info;
+ if (!wss.open)
+ return FALSE;
+
+ wss.open--;
+
+ /* Stop/free DMA buffer */
+ wss_stop_dma();
+
+ /* Unhook IRQ */
+ irq_unhook(wss.irq_handle);
+ wss.irq_handle = NULL;
+
+ /* Unlock the wss structure */
+ struct_info.address = __djgpp_base_address + (unsigned long)&wss;
+ struct_info.size = sizeof(wss);
+ __dpmi_unlock_linear_region(&struct_info);
+
+ return TRUE;
+}
+
+/* Adjust frequency rate to nearest WSS available */
+unsigned int wss_adjust_freq(unsigned int freq)
+{
+ __wss_getrate(&freq);
+ return freq;
+}
+
+/* Enable/disable speaker output */
+/* Start playing from DMA buffer in either 8/16 bit mono/stereo */
+boolean wss_start_dma(unsigned char mode, unsigned int freq)
+{
+ int dmabuffsize;
+ unsigned char format;
+
+ /* Stop DMA transfer if it is enabled */
+ wss_stop_dma();
+
+ /* Sanity check: we support only 8-bit unsigned and 16-bit signed formats */
+ if (((mode & WSSMODE_16BITS) && !(mode & WSSMODE_SIGNED))
+ || (!(mode & WSSMODE_16BITS) && (mode & WSSMODE_SIGNED)))
+ return FALSE;
+
+ /* Find the nearest frequency divisor (rate) */
+ format = __wss_getrate(&freq);
+ wss.mode = mode;
+
+ /* Get a DMA buffer enough for a 1sec interval... 4K <= dmasize <= 32K */
+ dmabuffsize = freq;
+ if (mode & WSSMODE_STEREO)
+ dmabuffsize *= 2;
+ if (mode & WSSMODE_16BITS)
+ dmabuffsize *= 2;
+ dmabuffsize >>= 2;
+ if (dmabuffsize < 4096)
+ dmabuffsize = 4096;
+ if (dmabuffsize > 32768)
+ dmabuffsize = 32768;
+ dmabuffsize = (dmabuffsize + 255) & 0xffffff00;
+
+ wss.dma_buff = dma_allocate(wss.dma, dmabuffsize);
+ if (!wss.dma_buff)
+ return FALSE;
+
+ /* Fill DMA buffer with silence */
+ dmabuffsize = wss.dma_buff->size;
+ if (mode & WSSMODE_SIGNED)
+ memset(wss.dma_buff->linear, 0, dmabuffsize);
+ else
+ memset(wss.dma_buff->linear, 0x80, dmabuffsize);
+
+ /* Check data size and build a WSSR_PLAY_FORMAT value accordingly */
+ wss.samples = dmabuffsize;
+ if (mode & WSSMODE_16BITS) {
+ wss.samples >>= 1;
+ format |= WSSM_16BITS;
+ }
+
+ if (mode & WSSMODE_STEREO) {
+ wss.samples >>= 1;
+ format |= WSSM_STEREO;
+ }
+
+ if (!__wss_setformat(format)) {
+ wss_stop_dma();
+ return FALSE;
+ }
+
+ /* Prime DMA for transfer */
+ dma_start(wss.dma_buff, dmabuffsize, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
+
+ /* Tell codec how many samples to transfer */
+ wss.samples = (wss.samples >> 1) - 1;
+ __wss_outreg(WSSR_COUNT_LOW, wss.samples & 0xff);
+ __wss_outreg(WSSR_COUNT_HIGH, wss.samples >> 8);
+
+ /* Tell codec to start transfer */
+ __wss_regbit_set(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
+
+ return TRUE;
+}
+
+/* Stop playing from DMA buffer */
+void wss_stop_dma()
+{
+ if (!wss.dma_buff)
+ return;
+
+ __wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
+ dma_disable(wss.dma);
+ dma_free(wss.dma_buff);
+ wss.dma_buff = NULL;
+}
+
+/* Query current position/total size of the DMA buffer */
+void wss_query_dma(unsigned int *dma_size, unsigned int *dma_pos)
+{
+ unsigned int dma_left;
+ *dma_size = wss.dma_buff->size;
+ /* It can happen we try to read DMA count when HI/LO bytes will be
+ inconsistent */
+ for (;;) {
+ unsigned int dma_left_test;
+ dma_clear_ff(wss.dma);
+ dma_left_test = dma_get_count(wss.dma);
+ dma_left = dma_get_count(wss.dma);
+ if ((dma_left >= dma_left_test) && (dma_left - dma_left_test < 10))
+ break;
+ }
+ *dma_pos = *dma_size - dma_left;
+}
+
+void wss_output(boolean enable)
+{
+ if (enable)
+ wss.curlevel = wss.level;
+ else
+ wss.curlevel = 0x3f;
+
+ __wss_outreg(WSSR_MASTER_L, wss.curlevel);
+ __wss_outreg(WSSR_MASTER_R, wss.curlevel);
+}
+
+void wss_level(int level)
+{
+ if (level < 0)
+ level = 0;
+ if (level > 63)
+ level = 63;
+ wss.curlevel = wss.level = level ^ 63;
+
+ __wss_outreg(WSSR_MASTER_L, wss.curlevel);
+ __wss_outreg(WSSR_MASTER_R, wss.curlevel);
+}
+
+#endif /* DRV_WSS */
+
+/* ex:set ts=4: */
--- /dev/null
+/* MikMod sound library
+ (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
+ complete list.
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+/*==============================================================================
+
+ $Id$
+
+ Windows Sound System and compatible soundcards definitions
+
+==============================================================================*/
+
+#ifndef __DOSWSS_H__
+#define __DOSWSS_H__
+
+#include "dosdma.h"
+#include "dosirq.h"
+
+#define WSS_ADDR (wss.port + 0x04)
+#define WSS_DATA (wss.port + 0x05)
+#define WSS_STATUS (wss.port + 0x06)
+#define WSS_PIO (wss.port + 0x07)
+
+/* WSS_ADDR: Bits 0-4 select an internal register to read/write */
+#define WSSR_INPUT_L 0x00 /* Left input control register */
+#define WSSR_INPUT_R 0x01 /* RIght input control register */
+#define WSSR_AUX1_L 0x02 /* Left Aux #1 input control */
+#define WSSR_AUX1_R 0x03 /* Right Aux #1 input control */
+#define WSSR_CD_L 0x04 /* Left Aux #2 input control */
+#define WSSR_CD_R 0x05 /* Right Aux #2 input control */
+#define WSSR_MASTER_L 0x06 /* Left output control */
+#define WSSR_MASTER_R 0x07 /* Right output control */
+#define WSSR_PLAY_FORMAT 0x08 /* Clock and data format */
+#define WSSR_IFACE_CTRL 0x09 /* Interface control */
+#define WSSR_PIN_CTRL 0x0a /* Pin control */
+#define WSSR_TEST_INIT 0x0b /* Test and initialization */
+#define WSSR_MISC_INFO 0x0c /* Miscellaneaous information */
+#define WSSR_LOOPBACK 0x0d /* Digital Mix */
+#define WSSR_COUNT_HIGH 0x0e /* Playback Upper Base Count */
+#define WSSR_COUNT_LOW 0x0f /* Playback Lower Base Count */
+#define WSSR_ALT_FEATURE_1 0x10 /* alternate #1 feature enable */
+#define WSSR_ALT_FEATURE_2 0x11 /* alternate #2 feature enable */
+#define WSSR_LINE_IN_L 0x12 /* left line input control */
+#define WSSR_LINE_IN_R 0x13 /* right line input control */
+#define WSSR_TIMER_LOW 0x14 /* timer low byte */
+#define WSSR_TIMER_HIGH 0x15 /* timer high byte */
+#define WSSR_IRQ_STATUS 0x18 /* irq status register */
+#define WSSR_MONO_IO_CTRL 0x1a /* mono input/output control */
+#define WSSR_REC_FORMAT 0x1c /* record format */
+#define WSSR_REC_COUNT_HIGH 0x1e /* record upper count */
+#define WSSR_REC_COUNT_LOW 0x1f /* record lower count */
+
+/* WSS_ADDR bits 7-5 definition */
+#define WSSM_INIT 0x80 /* Codec is initializing */
+#define WSSM_MCE 0x40 /* Mode change enable */
+#define WSSM_TRD 0x20 /* Transfer Request Disable */
+/* bits 4-0 are indirect register address (0-15) */
+
+/* WSS_STATUS bit masks */
+#define WSSM_CUL 0x80 /* Capture data upper/lower byte */
+#define WSSM_CLR 0x40 /* Capture left/right sample */
+#define WSSM_CRDY 0x20 /* Capture data read */
+#define WSSM_SOUR 0x10 /* Playback over/under run error */
+#define WSSM_PUL 0x08 /* Playback upper/lower byte */
+#define WSSM_PLR 0x04 /* Playback left/right sample */
+#define WSSM_PRDY 0x02 /* Playback data register read */
+#define WSSM_INT 0x01 /* interrupt status */
+
+/* Definitions for output level registers */
+#define WSSM_MUTE 0x80 /* Mute this output source */
+/* bits 5-0 are left output attenuation select (0-63) */
+/* bits 5-0 are right output attenuation select (0-63) */
+
+/* Definitions for clock and data format register (WSSR_PLAY_FORMAT) */
+#define WSSM_STEREO 0x10 /* stero mode */
+#define WSSM_ULAW_8 0x20 /* 8-bit U-law companded */
+#define WSSM_16BITS 0x40 /* 16 bit twos complement data - little endian */
+#define WSSM_ALAW_8 0x60 /* 8-bit A-law companded */
+#define WSSM_16BITS_BE 0xc0 /* 16-bit twos complement data - big endian */
+#define WSSM_ADPCM_16 0xa0 /* 16-bit ADPCM */
+/* Bits 3-1 define frequency divisor */
+#define WSSM_XTAL1 0x00 /* 24.576 crystal */
+#define WSSM_XTAL2 0x01 /* 16.9344 crystal */
+
+/* Definitions for interface control register (WSSR_IFACE_CTRL) */
+#define WSSM_CAPTURE_PIO 0x80 /* Capture PIO enable */
+#define WSSM_PLAYBACK_PIO 0x40 /* Playback PIO enable */
+#define WSSM_AUTOCALIB 0x08 /* auto calibrate */
+#define WSSM_SINGLE_DMA 0x04 /* Use single DMA channel */
+#define WSSM_PLAYBACK_ENABLE 0x01 /* playback enable */
+
+/* Definitions for Pin control register (WSSR_PIN_CTRL) */
+#define WSSM_IRQ_ENABLE 0x02 /* interrupt enable */
+#define WSSM_XCTL1 0x40 /* external control #1 */
+#define WSSM_XCTL0 0x80 /* external control #0 */
+
+/* Definitions for WSSR_TEST_INIT register */
+#define WSSM_CALIB_IN_PROGRESS 0x20 /* auto calibrate in progress */
+
+/* Definitions for misc control register (WSR_MISC_INFO) */
+#define WSSM_MODE2 0x40 /* MODE 2 */
+#define WSSM_MODE3 0x6c /* MODE 3 - enhanced mode */
+
+/* Definitions for codec irq status (WSSR_IRQ_STATUS) */
+#define WSSM_PLAYBACK_IRQ 0x10
+#define WSSM_RECORD_IRQ 0x20
+#define WSSM_TIMER_IRQ 0x40
+
+typedef unsigned char boolean;
+
+#ifndef FALSE
+#define FALSE 0
+#define TRUE 1
+#endif
+
+/* Play mode bits */
+#define WSSMODE_16BITS 0x0001
+#define WSSMODE_STEREO 0x0002
+#define WSSMODE_SIGNED 0x0004
+
+/* You can fill some members of this struct (i.e. port,irq,dma) before
+ * calling wss_detect() or wss_open()... this will ignore environment settings.
+ */
+typedef struct __wss_state_s {
+ boolean ok; /* Set if this structure is properly filled */
+ int port; /* Base codec port */
+ int irq; /* codec IRQ */
+ int dma; /* codec DMA */
+ struct irq_handle *irq_handle; /* The interrupt handler */
+ dma_buffer *dma_buff; /* Pre-allocated DMA buffer */
+ unsigned char mode; /* Current WSS mode (WSSMODE_XXX) */
+ boolean open; /* Whenever the card has been opened */
+ int samples; /* Number of samples in DMA buffer */
+ unsigned char level; /* Output level (63..0): doesn't change when mute */
+ unsigned char curlevel; /* Current output level (63(min)..0(max)) */
+ volatile int irqcount; /* Incremented on each IRQ... for diagnostics */
+ void (*timer_callback) (); /* Called TWICE per buffer play */
+} __wss_state;
+
+extern __wss_state wss;
+
+/* Wait until codec finishes initialization */
+static inline boolean __wss_wait()
+{
+ int count;
+ for (count = 10000; count >= 0; count--)
+ if (!(inportb(WSS_ADDR) & WSSM_INIT))
+ return TRUE;
+ return FALSE;
+}
+
+static inline void __wss_outreg(unsigned char reg, unsigned char val)
+{
+ outportb(WSS_ADDR, reg);
+ outportb(WSS_DATA, val);
+}
+
+static inline unsigned char __wss_inreg(unsigned char reg)
+{
+ outportb(WSS_ADDR, reg);
+ return inportb(WSS_DATA);
+}
+
+/* Set some bits in a specific register */
+static inline void __wss_regbit_set(unsigned char reg, unsigned char mask)
+{
+ outportb(WSS_ADDR, reg);
+ outportb(WSS_DATA, inportb(WSS_DATA) | mask);
+}
+
+/* Reset some bits in a specific register */
+static inline void __wss_regbit_reset(unsigned char reg, unsigned char mask)
+{
+ outportb(WSS_ADDR, reg);
+ outportb(WSS_DATA, inportb(WSS_DATA) & ~mask);
+}
+
+/* Detect whenever WSS is present and fill "wss" structure */
+extern boolean wss_detect();
+/* Reset WSS */
+extern void wss_reset();
+/* Open WSS for usage */
+extern boolean wss_open();
+/* Finish working with WSS */
+extern boolean wss_close();
+/* Enable/disable speaker output */
+extern void wss_output(boolean enable);
+/* Adjust frequency rate to nearest WSS available */
+extern unsigned int wss_adjust_freq(unsigned int freq);
+/* Start playing from DMA buffer in either 8/16 bit mono/stereo */
+extern boolean wss_start_dma(unsigned char mode, unsigned int freq);
+/* Stop playing from DMA buffer */
+extern void wss_stop_dma();
+/* Query current position/total size of the DMA buffer */
+extern void wss_query_dma(unsigned int *dma_size, unsigned int *dma_pos);
+/* Set output level (0(min)-63(max)) */
+extern void wss_level(int level);
+
+#endif /* __DOSWSS_H__ */
+
+/* ex:set ts=4: */
--- /dev/null
+/* MikMod sound library
+ (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
+ complete list.
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+*/
+
+/*==============================================================================
+
+ $Id$
+
+ Linux libGUS-alike library for DOS, used by drv_ultra.c under DOS.
+
+==============================================================================*/
+
+/*
+ Current limitations:
+ - Only a subset of libgus is supported
+ - Only one GUS card is supported (due to the fact that ULTRASND environment
+ variable is used)
+ - No Interwawe support (if IW works the old way, it's ok).
+*/
+
+#ifndef __LIBGUS_H__
+#define __LIBGUS_H__
+
+#include <stddef.h>
+
+#define __LITTLE_ENDIAN
+
+typedef struct _gus_info_t gus_info_t;
+typedef struct _gus_instrument_t gus_instrument_t;
+typedef struct _gus_wave_t gus_wave_t;
+typedef struct _gus_layer_t gus_layer_t;
+
+#define GUS_CARD_VERSION_CLASSIC 0x0024 /* revision 2.4 */
+#define GUS_CARD_VERSION_CLASSIC1 0x0034 /* revision 3.4? */
+#define GUS_CARD_VERSION_CLASSIC_ICS 0x0037 /* revision 3.7 (ICS mixer) */
+#define GUS_CARD_VERSION_EXTREME 0x0050 /* GUS Extreme */
+#define GUS_CARD_VERSION_ACE 0x0090 /* GUS ACE */
+#define GUS_CARD_VERSION_MAX 0x00a0 /* GUS MAX - revision 10 */
+#define GUS_CARD_VERSION_MAX1 0x00a1 /* GUS MAX - revision 11 */
+#define GUS_CARD_VERSION_PNP 0x0100 /* GUS Plug & Play */
+
+#define GUS_STRU_INFO_F_DB16 0x00000001 /* 16-bit daughter board present */
+#define GUS_STRU_INFO_F_PCM 0x00000004 /* GF1 PCM during SYNTH enabled */
+#define GUS_STRU_INFO_F_ENHANCED 0x00000008 /* InterWave - enhanced mode */
+#define GUS_STRU_INFO_F_DAEMON 0x00000010 /* instrument daemon is present */
+
+struct _gus_info_t {
+ unsigned char id[8]; /* id of this card (warning! maybe unterminated!!!) */
+
+ unsigned int flags; /* some info flags - see to GUS_STRU_INFO_F_XXXX */
+ unsigned int version; /* see to GUS_CARD_VERSION_XXXX constants */
+
+ unsigned short port;
+ unsigned short irq;
+ unsigned short dma1; /* DMA1 - GF1 download & codec record */
+ unsigned short dma2; /* DMA2 - GF1 record & codec playback */
+
+ unsigned int mixing_freq; /* mixing frequency in Hz */
+
+ unsigned int memory_size; /* in bytes */
+ unsigned int memory_free; /* in bytes */
+ unsigned int memory_block_8; /* largest free 8-bit block in memory */
+ unsigned int memory_block_16; /* largest free 16-bit block in memory */
+};
+
+/* struct gus_instrument_t - mode */
+
+#define GUS_INSTR_SIMPLE 0x00 /* simple format - for MOD players */
+#define GUS_INSTR_PATCH 0x01 /* old GF1 patch format */
+#define GUS_INSTR_COUNT 2
+
+#define GUS_INSTR_F_NORMAL 0x0000 /* normal mode */
+#define GUS_INSTR_F_NOT_FOUND 0x0001 /* instrument can't be loaded */
+#define GUS_INSTR_F_ALIAS 0x0002 /* alias */
+#define GUS_INSTR_F_NOT_LOADED 0x00ff /* instrument not loaded (not found) */
+
+#define GUS_INSTR_E_NONE 0x0000 /* exclusion mode - none */
+#define GUS_INSTR_E_SINGLE 0x0001 /* exclude single - single note from this instrument */
+#define GUS_INSTR_E_MULTIPLE 0x0002 /* exclude multiple - stop only same note from this instrument */
+
+#define GUS_INSTR_L_NONE 0x0000 /* not layered */
+#define GUS_INSTR_L_ON 0x0001 /* layered */
+#define GUS_INSTR_L_VELOCITY 0x0002 /* layered by velocity */
+#define GUS_INSTR_L_FREQUENCY 0x0003 /* layered by frequency */
+
+struct _gus_instrument_t {
+ union {
+ unsigned int instrument;/* instrument number */
+ } number;
+
+ char *name; /* name of this instrument or NULL */
+
+ unsigned int mode:8, /* see to GUS_INSTR_XXXX */
+ flags:8, /* see to GUS_INSTR_F_XXXX */
+ exclusion:4, /* see to GUS_INSTR_E_XXXX */
+ layer:4; /* see to GUS_INSTR_L_XXXX */
+ unsigned short exclusion_group; /* 0 - none, 1-65535 */
+
+ struct {
+ unsigned char effect1:4,/* use global effect if available */
+ effect2:4; /* use global effect if available */
+ unsigned char effect1_depth;/* 0-127 */
+ unsigned char effect2_depth;/* 0-127 */
+ } patch;
+
+ union {
+ gus_layer_t *layer; /* first layer */
+ unsigned int alias; /* pointer to instrument */
+ } info;
+ gus_instrument_t *next; /* next instrument */
+};
+
+struct _gus_layer_t {
+ unsigned char mode; /* see to GUS_INSTR_XXXX constants */
+
+ gus_wave_t *wave;
+ gus_layer_t *next;
+};
+
+/* bits for format variable in gus_wave_t */
+
+#define GUS_WAVE_16BIT 0x0001 /* 16-bit wave */
+#define GUS_WAVE_UNSIGNED 0x0002 /* unsigned wave */
+#define GUS_WAVE_INVERT 0x0002 /* same as unsigned wave */
+#define GUS_WAVE_BACKWARD 0x0004 /* forward mode */
+#define GUS_WAVE_LOOP 0x0008 /* loop mode */
+#define GUS_WAVE_BIDIR 0x0010 /* bidirectional mode */
+#define GUS_WAVE_ULAW 0x0020 /* uLaw compressed wave */
+#define GUS_WAVE_RAM 0x0040 /* wave is _preloaded_ in RAM (it is used for ROM simulation) */
+#define GUS_WAVE_ROM 0x0080 /* wave is in ROM */
+#define GUS_WAVE_DELTA 0x0100
+
+#define GUS_WAVE_PATCH_ENVELOPE 0x01 /* envelopes on */
+#define GUS_WAVE_PATCH_SUSTAIN 0x02 /* sustain mode */
+
+struct _gus_wave_t {
+ unsigned char mode; /* see to GUS_INSTR_XXXX constants */
+ unsigned char format; /* see to GUS_WAVE_XXXX constants */
+ unsigned int size; /* size of waveform in bytes */
+ unsigned int start; /* start offset in bytes * 16 (lowest 4 bits - fraction) */
+ unsigned int loop_start; /* bits loop start offset in bytes * 16 (lowest 4 bits - fraction) */
+ unsigned int loop_end; /* loop start offset in bytes * 16 (lowest 4 bits - fraction) */
+ unsigned short loop_repeat; /* loop repeat - 0 = forever */
+ struct {
+ unsigned int memory; /* begin of waveform in GUS's memory */
+ unsigned char *ptr; /* pointer to waveform in system memory */
+ } begin;
+
+ struct {
+ unsigned char flags;
+ unsigned int sample_rate;
+ unsigned int low_frequency;/* low frequency range for this waveform */
+ unsigned int high_frequency;/* high frequency range for this waveform */
+ unsigned int root_frequency;/* root frequency for this waveform */
+ signed short tune;
+ unsigned char balance;
+ unsigned char envelope_rate[6];
+ unsigned char envelope_offset[6];
+ unsigned char tremolo_sweep;
+ unsigned char tremolo_rate;
+ unsigned char tremolo_depth;
+ unsigned char vibrato_sweep;
+ unsigned char vibrato_rate;
+ unsigned char vibrato_depth;
+ unsigned short scale_frequency;
+ unsigned short scale_factor;/* 0-2048 or 0-2 */
+ } patch;
+
+ gus_wave_t *next;
+};
+
+/* defines for gus_memory_reset () */
+#define GUS_DOWNLOAD_MODE_NORMAL 0x0000
+#define GUS_DOWNLOAD_MODE_TEST 0x0001
+
+/*
+ A subset of libgus functions (used by MikMod Ultrasound driver)
+*/
+int gus_cards(void);
+ /*
+ * return value: number of GUS cards installed in system or
+ * zero if driver isn't installed
+ */
+int gus_close(int card);
+ /*
+ * close file (gus synthesizer) previously opened with gusOpen function
+ * return value: zero if success
+ */
+int gus_do_flush(void);
+ /*
+ * return value: zero if command queue was successfully flushed
+ * in non block mode - number of written bytes
+ */
+void gus_do_tempo(unsigned int tempo);
+ /*
+ * set new tempo
+ */
+void gus_do_voice_frequency(unsigned char voice, unsigned int freq);
+ /*
+ * set voice frequency in Hz
+ */
+void gus_do_voice_pan(unsigned char voice, unsigned short pan);
+ /*
+ * set voice pan (0-16384) (full left - full right)
+ */
+void gus_do_voice_start(unsigned char voice, unsigned int program,
+ unsigned int freq, unsigned short volume,
+ unsigned short pan);
+ /*
+ * start voice
+ * voice : voice #
+ * program : program # or ~0 = current
+ * freq : frequency in Hz
+ * volume : volume level (0-16384) or ~0 = current
+ * pan : pan level (0-16384) or ~0 = current
+ */
+void gus_do_voice_start_position(unsigned char voice, unsigned int program,
+ unsigned int freq, unsigned short volume,
+ unsigned short pan, unsigned int position);
+ /*
+ * start voice
+ * voice : voice #
+ * program : program # or ~0 = current
+ * freq : frequency in Hz
+ * volume : volume level (0-16384) or ~0 = current
+ * pan : pan level (0-16384) or ~0 = current
+ * position : offset to wave in bytes * 16 (lowest 4 bits - fraction)
+ */
+void gus_do_voice_stop(unsigned char voice, unsigned char mode);
+ /*
+ * stop voice
+ * mode = 0 : stop voice now
+ * mode = 1 : disable wave loop and finish it
+ */
+void gus_do_voice_volume(unsigned char voice, unsigned short vol);
+ /*
+ * set voice volume level 0-16384 (linear)
+ */
+void gus_do_wait(unsigned int ticks);
+ /*
+ * wait x ticks - this command is block separator
+ * all commands between blocks are interpreted in the begining of one tick
+ */
+int gus_get_voice_status(int voice);
+ /*
+ * THIS IS NOT A FUNCTION OF ORIGINAL libGUS!
+ * Return voice status: -1 on error, 0 if voice stopped, 1 if playing
+ */
+int gus_get_handle(void);
+ /*
+ * return value: file handle (descriptor) for /dev/gus
+ */
+int gus_info(gus_info_t * info, int reread);
+ /*
+ * return value: filled info variable with actual values
+ * (look at gus.h header file for more informations)
+ * version field: 0x0024 - GUS revision 2.4
+ * 0x0035 - GUS revision 3.7 with flipped mixer channels
+ * 0x0037 - GUS revision 3.7
+ * 0x0090 - GUS ACE
+ * 0x00a0 - GUS MAX revision 10
+ * 0x00a1 - GUS MAX revision 11
+ * 0x0100 - InterWave (full version)
+ * flags field: see to GUS_STRU_INFO_F_???? constants (gus.h header file)
+ * port field: port number (for example 0x220)
+ * irq field: irq number (for example 11)
+ * dma1 field: dma1 number (for example 5)
+ * dma2 field: dma2 number (for example 6)
+ * note: dma1 and dma2 could be same in case of only one dma channel used
+ */
+int gus_memory_alloc(gus_instrument_t * instrument);
+ /*
+ * input value: look at gus.h for more details about gus_instrument_t structure
+ * return value: zero if instrument was successfully allocated
+ */
+int gus_memory_free(gus_instrument_t * instrument);
+ /*
+ * input value: look at gus.h for more details about gus_instrument_t structure
+ * return value: zero if instrument was successfully removed
+ */
+int gus_memory_size(void);
+ /*
+ * return value: gus memory size in bytes
+ */
+int gus_memory_free_size(void);
+ /*
+ * return value: unused gus memory in bytes
+ * warning: reset function must be called before
+ */
+int gus_memory_free_block(int w_16bit);
+ /*
+ * return value: current largest free block for 8-bit or 16-bit wave
+ */
+int gus_memory_pack(void);
+ /*
+ * return value: zero if success
+ */
+int gus_memory_reset(int mode);
+ /*
+ * input value: see to GUS_DOWNLOAD_MODE_XXXX constants (gus.h)
+ * return value: zero if samples & instruments was successfully removed
+ * from GF1 memory manager
+ */
+
+int gus_open(int card, size_t queue_buffer_size, int non_block);
+ /*
+ * input values: card number,
+ * size of command queue buffer (512-1MB)
+ * buffer is allocated dynamically,
+ * non block mode
+ * return value: zero if success
+ * note 1: this function must be called as first
+ * open file /dev/gus
+ * note 2: you can open more cards with one process
+ */
+int gus_queue_flush(void);
+ /*
+ * return value: zero if command queue was successfully flushed
+ */
+int gus_queue_read_set_size(int items);
+ /*
+ * input value: echo buffer size in items (if 0 - erase echo buffer)
+ */
+int gus_queue_write_set_size(int items);
+ /*
+ * input value: write queue size in items (each item have 8 bytes)
+ */
+int gus_reset(int voices, unsigned int channel_voices);
+ /*
+ * input values: active voices and channel voices (for dynamic allocation)
+ * return value: number of active voices if reset was successfull (GF1 chip active)
+ */
+int gus_reset_engine_only(void);
+ /*
+ * return value: same as gus_reset function
+ * note: this command doesn't change number of active
+ * voices and doesn't do hardware reset
+ */
+int gus_select(int card);
+ /*
+ * select specified card
+ * return value: zero if success
+ */
+int gus_timer_start(void);
+ /*
+ * return value: zero if successfull
+ */
+int gus_timer_stop(void);
+ /*
+ * return value: zero if timer was stoped
+ */
+int gus_timer_continue(void);
+ /*
+ * return value: zero if timer will be continue
+ */
+int gus_timer_tempo(int ticks);
+ /*
+ * return value: zero if setup was success
+ */
+int gus_timer_base(int base);
+ /*
+ * return value: zero if setup was success (default timebase = 100)
+ */
+
+void gus_convert_delta(unsigned int type, unsigned char *dest,
+ unsigned char *src, size_t size);
+ /*
+ * note: dest and src pointers can be equal
+ */
+
+void gus_timer_callback(void (*timer_callback) ());
+ /*
+ * Set a callback to be called once per tempo tick
+ */
+
+int gus_dma_usage (int use);
+ /*
+ * Tell GUS library to use/to not use DMA for sample transfer.
+ * In some environments/on some hardware platforms you will need
+ * to disable DMA in order to function properly. You should call
+ * this function before opening the card.
+ */
+
+#endif /* __LIBGUS_H__ */
+
+/* ex:set ts=4: */
+++ /dev/null
-/*
- Implementation of DMA routines on DOS
- Copyright (C) 1999 by Andrew Zabolotny, <bit@eltech.ru>
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free
- Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "dosdma.h"
-
-#include <go32.h> /* includes sys/version.h (djgpp >= 2.02) */
-#include <dos.h>
-#include <dpmi.h>
-#include <sys/nearptr.h>
-#include <malloc.h>
-#include "mikmod.h" /* for MikMod_malloc() & co */
-
-/* BUG WARNING: there is an error in DJGPP libraries <= 2.01:
- * src/libc/dpmi/api/d0102.s loads the selector and allocsize
- * arguments in the wrong order. DJGPP >= 2.02 have it fixed. */
-#if (!defined(__DJGPP_MINOR__) || (__DJGPP_MINOR__+0) < 2)
-#warning __dpmi_resize_dos_memory() from DJGPP <= 2.01 is broken!
-#endif
-
-__dma_regs dma[8] = {
-/* *INDENT-OFF* */
- {DMA_ADDR_0, DMA_PAGE_0, DMA_SIZE_0,
- DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG},
- {DMA_ADDR_1, DMA_PAGE_1, DMA_SIZE_1,
- DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG},
-
- {DMA_ADDR_2, DMA_PAGE_2, DMA_SIZE_2,
- DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG},
- {DMA_ADDR_3, DMA_PAGE_3, DMA_SIZE_3,
- DMA1_MASK_REG, DMA1_CLEAR_FF_REG, DMA1_MODE_REG},
-
- {DMA_ADDR_4, 0, DMA_SIZE_4,
- DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG},
- {DMA_ADDR_5, DMA_PAGE_5, DMA_SIZE_5,
- DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG},
-
- {DMA_ADDR_6, DMA_PAGE_6, DMA_SIZE_6,
- DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG},
- {DMA_ADDR_7, DMA_PAGE_7, DMA_SIZE_7,
- DMA2_MASK_REG, DMA2_CLEAR_FF_REG, DMA2_MODE_REG}
-/* *INDENT-ON* */
-};
-
-static int __initialized = 0;
-static int __buffer_count = 0;
-static __dpmi_meminfo __locked_data;
-
-int dma_initialize()
-{
- if (!__djgpp_nearptr_enable())
- return 0;
-
- /* Trick: Avoid re-setting DS selector limit on each memory allocation
- call */
- __djgpp_selector_limit = 0xffffffff;
-
- __locked_data.address = __djgpp_base_address + (unsigned long)&dma;
- __locked_data.size = sizeof(dma);
- if (__dpmi_lock_linear_region(&__locked_data))
- return 0;
-
- return (__initialized = 1);
-}
-
-void dma_finalize()
-{
- if (!__initialized)
- return;
- __dpmi_unlock_linear_region(&__locked_data);
- __djgpp_nearptr_disable();
-}
-
-dma_buffer *dma_allocate(unsigned int channel, unsigned int size)
-{
- int parsize = (size + 15) >> 4; /* size in paragraphs */
- int par = 0; /* Real-mode paragraph */
- int selector = 0; /* Protected-mode selector */
- int mask = channel <= 3 ? 0xfff : 0x1fff; /* Alignment mask in para. */
- int allocsize = parsize; /* Allocated size in paragraphs */
- int count; /* Try count */
- int bound = 0; /* Nearest bound address */
- int maxsize; /* Maximal possible block size */
- dma_buffer *buffer = NULL;
- __dpmi_meminfo buff_info, struct_info;
-
- if (!dma_initialize())
- return NULL;
-
- /* Loop until we'll get a properly aligned memory block */
- for (count = 8; count; count--) {
- int resize = (selector != 0);
-
- /* Try first to resize (possibly previously) allocated block */
- if (resize) {
- maxsize = (bound + parsize) - par;
- if (maxsize > parsize * 2)
- maxsize = parsize * 2;
- if (maxsize == allocsize)
- resize = 0;
- else {
- allocsize = maxsize;
- if (__dpmi_resize_dos_memory(selector, allocsize, &maxsize) !=
- 0) resize = 0;
- }
- }
-
- if (!resize) {
- if (selector)
- __dpmi_free_dos_memory(selector), selector = 0;
- par = __dpmi_allocate_dos_memory(allocsize, &selector);
- }
-
- if ((par == 0) || (par == -1))
- goto exit;
-
- /* If memory block contains a properly aligned portion, quit loop */
- bound = (par + mask + 1) & ~mask;
- if (par + parsize <= bound)
- break;
- if (bound + parsize <= par + allocsize) {
- par = bound;
- break;
- }
- }
- if (!count) {
- __dpmi_free_dos_memory(selector);
- goto exit;
- }
-
- buffer = (dma_buffer *) MikMod_malloc(sizeof(dma_buffer));
- buffer->linear = (unsigned char *)(__djgpp_conventional_base + bound * 16);
- buffer->physical = bound * 16;
- buffer->size = parsize * 16;
- buffer->selector = selector;
- buffer->channel = channel;
-
- buff_info.address = buffer->physical;
- buff_info.size = buffer->size;
- /*
- Don't pay attention to return code since under plain DOS it often
- returns error (at least under HIMEM/CWSDPMI and EMM386/DPMI)
- */
- __dpmi_lock_linear_region(&buff_info);
-
- /* Lock the DMA buffer control structure as well */
- struct_info.address = __djgpp_base_address + (unsigned long)buffer;
- struct_info.size = sizeof(dma_buffer);
- if (__dpmi_lock_linear_region(&struct_info)) {
- __dpmi_unlock_linear_region(&buff_info);
- __dpmi_free_dos_memory(selector);
- MikMod_free(buffer);
- buffer = NULL;
- goto exit;
- }
-
- exit:
- if (buffer)
- __buffer_count++;
- else if (--__buffer_count == 0)
- dma_finalize();
- return buffer;
-}
-
-void dma_free(dma_buffer * buffer)
-{
- __dpmi_meminfo buff_info;
-
- if (!buffer)
- return;
-
- buff_info.address = buffer->physical;
- buff_info.size = buffer->size;
- __dpmi_unlock_linear_region(&buff_info);
-
- __dpmi_free_dos_memory(buffer->selector);
- MikMod_free(buffer);
-
- if (--__buffer_count == 0)
- dma_finalize();
-}
-
-void dma_start(dma_buffer * buffer, unsigned long count, unsigned char mode)
-{
- /* Disable interrupts */
- int old_ints = disable();
- dma_disable(buffer->channel);
- dma_set_mode(buffer->channel, mode);
- dma_clear_ff(buffer->channel);
- dma_set_addr(buffer->channel, buffer->physical);
- dma_clear_ff(buffer->channel);
- dma_set_count(buffer->channel, count);
- dma_enable(buffer->channel);
- /* Re-enable interrupts */
- if (old_ints)
- enable();
-}
-
-/* ex:set ts=4: */
+++ /dev/null
-/*
- Interface for DMA routines on DOS
- Copyright (C) 1999 by Andrew Zabolotny, <bit@eltech.ru>
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free
- Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __DOSDMA_H__
-#define __DOSDMA_H__
-
-#include <pc.h>
-
-#define DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */
-#define DMA2_BASE 0xC0 /* 16 bit master DMA, ch 4(=slave input)..7 */
-
-#define DMA1_CMD_REG 0x08 /* command register (w) */
-#define DMA1_STAT_REG 0x08 /* status register (r) */
-#define DMA1_REQ_REG 0x09 /* request register (w) */
-#define DMA1_MASK_REG 0x0A /* single-channel mask (w) */
-#define DMA1_MODE_REG 0x0B /* mode register (w) */
-#define DMA1_CLEAR_FF_REG 0x0C /* clear pointer flip-flop (w) */
-#define DMA1_TEMP_REG 0x0D /* Temporary Register (r) */
-#define DMA1_RESET_REG 0x0D /* Master Clear (w) */
-#define DMA1_CLR_MASK_REG 0x0E /* Clear Mask */
-#define DMA1_MASK_ALL_REG 0x0F /* all-channels mask (w) */
-
-#define DMA2_CMD_REG 0xD0 /* command register (w) */
-#define DMA2_STAT_REG 0xD0 /* status register (r) */
-#define DMA2_REQ_REG 0xD2 /* request register (w) */
-#define DMA2_MASK_REG 0xD4 /* single-channel mask (w) */
-#define DMA2_MODE_REG 0xD6 /* mode register (w) */
-#define DMA2_CLEAR_FF_REG 0xD8 /* clear pointer flip-flop (w) */
-#define DMA2_TEMP_REG 0xDA /* Temporary Register (r) */
-#define DMA2_RESET_REG 0xDA /* Master Clear (w) */
-#define DMA2_CLR_MASK_REG 0xDC /* Clear Mask */
-#define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */
-
-#define DMA_ADDR_0 0x00 /* DMA address registers */
-#define DMA_ADDR_1 0x02
-#define DMA_ADDR_2 0x04
-#define DMA_ADDR_3 0x06
-#define DMA_ADDR_4 0xC0
-#define DMA_ADDR_5 0xC4
-#define DMA_ADDR_6 0xC8
-#define DMA_ADDR_7 0xCC
-
-#define DMA_SIZE_0 0x01 /* DMA transfer size registers */
-#define DMA_SIZE_1 0x03
-#define DMA_SIZE_2 0x05
-#define DMA_SIZE_3 0x07
-#define DMA_SIZE_4 0xC2
-#define DMA_SIZE_5 0xC6
-#define DMA_SIZE_6 0xCA
-#define DMA_SIZE_7 0xCE
-
-#define DMA_PAGE_0 0x87 /* DMA page registers */
-#define DMA_PAGE_1 0x83
-#define DMA_PAGE_2 0x81
-#define DMA_PAGE_3 0x82
-#define DMA_PAGE_5 0x8B
-#define DMA_PAGE_6 0x89
-#define DMA_PAGE_7 0x8A
-
-#define DMA_MODE_AUTOINIT 0x10 /* Auto-init mode bit */
-#define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */
-#define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */
-#define DMA_MODE_CASCADE 0xC0 /* pass thru DREQ->HRQ, DACK<-HLDA only */
-
-/* Indexable specific DMA registers */
-typedef struct __dma_regs_s {
- unsigned char addr; /* DMA transfer address register */
- unsigned char page; /* DMA page register */
- unsigned char size; /* DMA transfer size register */
- unsigned char mask; /* DMA mask/unmask register */
- unsigned char flip; /* DMA flip-flop reset register */
- unsigned char mode; /* DMA mode register */
-} __dma_regs;
-
-extern __dma_regs dma[8];
-
-/* Enable a specific DMA channel */
-static inline void dma_enable(unsigned int channel)
-{
- outportb(dma[channel].mask, channel & 3);
-}
-
-/* Disable a specific DMA channel */
-static inline void dma_disable(unsigned int channel)
-{
- outportb(dma[channel].mask, (channel & 3) | 0x04);
-}
-
-/* Clear the 'DMA Flip Flop' flag */
-static inline void dma_clear_ff(unsigned int channel)
-{
- outportb(dma[channel].flip, 0);
-}
-
-/* Set mode for a specific DMA channel */
-static inline void dma_set_mode(unsigned int channel, char mode)
-{
- outportb(dma[channel].mode, mode | (channel & 3));
-}
-
-/* Set DMA page register */
-static inline void dma_set_page(unsigned int channel, char page)
-{
- if (channel > 3)
- page &= 0xfe;
- outportb(dma[channel].page, page);
-}
-
-/*
- Set transfer address & page bits for specific DMA channel.
- Assumes dma flipflop is clear.
-*/
-static inline void dma_set_addr(unsigned int channel, unsigned int address)
-{
- unsigned char dma_reg = dma[channel].addr;
- dma_set_page(channel, address >> 16);
- if (channel <= 3) {
- outportb(dma_reg, (address) & 0xff);
- outportb(dma_reg, (address >> 8) & 0xff);
- } else {
- outportb(dma_reg, (address >> 1) & 0xff);
- outportb(dma_reg, (address >> 9) & 0xff);
- }
-}
-
-/*
- Set transfer size for a specific DMA channel.
- Assumes dma flip-flop is clear.
-*/
-static inline void dma_set_count(unsigned int channel, unsigned int count)
-{
- unsigned char dma_reg = dma[channel].size;
- count--; /* number of DMA transfers is bigger by one */
- if (channel > 3)
- count >>= 1;
- outportb(dma_reg, (count) & 0xff);
- outportb(dma_reg, (count >> 8) & 0xff);
-}
-
-/*
- Query the number of bytes left to transfer.
- Assumes DMA flip-flop is clear.
-*/
-static inline int dma_get_count(unsigned int channel)
-{
- unsigned char dma_reg = dma[channel].size;
-
- /* using short to get 16-bit wrap around */
- unsigned short count;
- count = inportb(dma_reg);
- count |= inportb(dma_reg) << 8;
- count++;
- return (channel <= 3) ? count : (count << 1);
-}
-
-typedef struct dma_buffer_s {
- unsigned char *linear; /* Linear address */
- unsigned long physical; /* Physical address */
- unsigned long size; /* Buffer size */
- unsigned short selector; /* The selector assigned to this memory */
- unsigned char channel; /* The DMA channel */
-} dma_buffer;
-
-/* Allocate a block of memory suitable for using as a DMA buffer */
-extern dma_buffer *dma_allocate(unsigned int channel, unsigned int size);
-/* Deallocate a DMA buffer */
-extern void dma_free(dma_buffer * buffer);
-/* Start DMA transfer to or from given buffer */
-extern void dma_start(dma_buffer * buffer, unsigned long count,
- unsigned char mode);
-
-#endif /* __DOSDMA_H__ */
-
-/* ex:set ts=4: */
+++ /dev/null
-/* MikMod sound library
- (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
- complete list.
-
- This library is free software; you can redistribute it and/or modify
- it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA.
-*/
-
-/*==============================================================================
-
- Driver for GUS cards under DOS
- Written by Andrew Zabolotny <bit@eltech.ru>
-
-==============================================================================*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef DRV_ULTRA
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <dos.h>
-#include <dpmi.h>
-#include <sys/farptr.h>
-#include <sys/nearptr.h>
-#include <go32.h>
-#include <string.h>
-
-#include "dosgus.h"
-#include "mikmod.h" /* for MikMod_malloc() & co */
-
-/********************************************* Private variables/routines *****/
-
-/* The Gravis Ultrasound state/info */
-__gus_state gus;
-
-/* Try to avoid holes in DRAM less than this size */
-#define DRAM_HOLE_THRESHOLD 8192
-/* If hole is larger than that, create a free block describing it */
-#define DRAM_SPLIT_THRESHOLD 64
-/* The size of DMA buffer used for RAM->DRAM transfers */
-#define GF1_DMA_BUFFER_SIZE 8192
-
-/* Debug macro: useful to change screen locations when some event occurs */
-#ifdef MIKMOD_DEBUG
-# define DEBUG_PRINT(x) printf x;
-# define DEBUG_OFS(addr, attr) \
- { \
- unsigned short x; \
- _dosmemgetw (0xb8780 + addr*2, 1, &x); \
- if ((x >> 8) != attr) x = '0'; \
- x = ((x + 1) & 0xff) | (attr << 8); \
- _dosmemputw (&x, 1, 0xb8780 + addr*2); \
- }
-#else
-# define DEBUG_PRINT(x)
-# define DEBUG_OFS(addr, attr)
-#endif
-
-static unsigned short __gus_volume_table[512] = {
- 0x0000, 0x7000, 0x7ff0, 0x8800, 0x8ff0, 0x9400, 0x9800, 0x9c00,
- 0x9ff0, 0xa200, 0xa400, 0xa600, 0xa800, 0xaa00, 0xac00, 0xae00,
- 0xaff0, 0xb100, 0xb200, 0xb300, 0xb400, 0xb500, 0xb600, 0xb700,
- 0xb800, 0xb900, 0xba00, 0xbb00, 0xbc00, 0xbd00, 0xbe00, 0xbf00,
- 0xbff0, 0xc080, 0xc100, 0xc180, 0xc200, 0xc280, 0xc300, 0xc380,
- 0xc400, 0xc480, 0xc500, 0xc580, 0xc600, 0xc680, 0xc700, 0xc780,
- 0xc800, 0xc880, 0xc900, 0xc980, 0xca00, 0xca80, 0xcb00, 0xcb80,
- 0xcc00, 0xcc80, 0xcd00, 0xcd80, 0xce00, 0xce80, 0xcf00, 0xcf80,
- 0xcff0, 0xd040, 0xd080, 0xd0c0, 0xd100, 0xd140, 0xd180, 0xd1c0,
- 0xd200, 0xd240, 0xd280, 0xd2c0, 0xd300, 0xd340, 0xd380, 0xd3c0,
- 0xd400, 0xd440, 0xd480, 0xd4c0, 0xd500, 0xd540, 0xd580, 0xd5c0,
- 0xd600, 0xd640, 0xd680, 0xd6c0, 0xd700, 0xd740, 0xd780, 0xd7c0,
- 0xd800, 0xd840, 0xd880, 0xd8c0, 0xd900, 0xd940, 0xd980, 0xd9c0,
- 0xda00, 0xda40, 0xda80, 0xdac0, 0xdb00, 0xdb40, 0xdb80, 0xdbc0,
- 0xdc00, 0xdc40, 0xdc80, 0xdcc0, 0xdd00, 0xdd40, 0xdd80, 0xddc0,
- 0xde00, 0xde40, 0xde80, 0xdec0, 0xdf00, 0xdf40, 0xdf80, 0xdfc0,
- 0xdff0, 0xe020, 0xe040, 0xe060, 0xe080, 0xe0a0, 0xe0c0, 0xe0e0,
- 0xe100, 0xe120, 0xe140, 0xe160, 0xe180, 0xe1a0, 0xe1c0, 0xe1e0,
- 0xe200, 0xe220, 0xe240, 0xe260, 0xe280, 0xe2a0, 0xe2c0, 0xe2e0,
- 0xe300, 0xe320, 0xe340, 0xe360, 0xe380, 0xe3a0, 0xe3c0, 0xe3e0,
- 0xe400, 0xe420, 0xe440, 0xe460, 0xe480, 0xe4a0, 0xe4c0, 0xe4e0,
- 0xe500, 0xe520, 0xe540, 0xe560, 0xe580, 0xe5a0, 0xe5c0, 0xe5e0,
- 0xe600, 0xe620, 0xe640, 0xe660, 0xe680, 0xe6a0, 0xe6c0, 0xe6e0,
- 0xe700, 0xe720, 0xe740, 0xe760, 0xe780, 0xe7a0, 0xe7c0, 0xe7e0,
- 0xe800, 0xe820, 0xe840, 0xe860, 0xe880, 0xe8a0, 0xe8c0, 0xe8e0,
- 0xe900, 0xe920, 0xe940, 0xe960, 0xe980, 0xe9a0, 0xe9c0, 0xe9e0,
- 0xea00, 0xea20, 0xea40, 0xea60, 0xea80, 0xeaa0, 0xeac0, 0xeae0,
- 0xeb00, 0xeb20, 0xeb40, 0xeb60, 0xeb80, 0xeba0, 0xebc0, 0xebe0,
- 0xec00, 0xec20, 0xec40, 0xec60, 0xec80, 0xeca0, 0xecc0, 0xece0,
- 0xed00, 0xed20, 0xed40, 0xed60, 0xed80, 0xeda0, 0xedc0, 0xede0,
- 0xee00, 0xee20, 0xee40, 0xee60, 0xee80, 0xeea0, 0xeec0, 0xeee0,
- 0xef00, 0xef20, 0xef40, 0xef60, 0xef80, 0xefa0, 0xefc0, 0xefe0,
- 0xeff0, 0xf010, 0xf020, 0xf030, 0xf040, 0xf050, 0xf060, 0xf070,
- 0xf080, 0xf090, 0xf0a0, 0xf0b0, 0xf0c0, 0xf0d0, 0xf0e0, 0xf0f0,
- 0xf100, 0xf110, 0xf120, 0xf130, 0xf140, 0xf150, 0xf160, 0xf170,
- 0xf180, 0xf190, 0xf1a0, 0xf1b0, 0xf1c0, 0xf1d0, 0xf1e0, 0xf1f0,
- 0xf200, 0xf210, 0xf220, 0xf230, 0xf240, 0xf250, 0xf260, 0xf270,
- 0xf280, 0xf290, 0xf2a0, 0xf2b0, 0xf2c0, 0xf2d0, 0xf2e0, 0xf2f0,
- 0xf300, 0xf310, 0xf320, 0xf330, 0xf340, 0xf350, 0xf360, 0xf370,
- 0xf380, 0xf390, 0xf3a0, 0xf3b0, 0xf3c0, 0xf3d0, 0xf3e0, 0xf3f0,
- 0xf400, 0xf410, 0xf420, 0xf430, 0xf440, 0xf450, 0xf460, 0xf470,
- 0xf480, 0xf490, 0xf4a0, 0xf4b0, 0xf4c0, 0xf4d0, 0xf4e0, 0xf4f0,
- 0xf500, 0xf510, 0xf520, 0xf530, 0xf540, 0xf550, 0xf560, 0xf570,
- 0xf580, 0xf590, 0xf5a0, 0xf5b0, 0xf5c0, 0xf5d0, 0xf5e0, 0xf5f0,
- 0xf600, 0xf610, 0xf620, 0xf630, 0xf640, 0xf650, 0xf660, 0xf670,
- 0xf680, 0xf690, 0xf6a0, 0xf6b0, 0xf6c0, 0xf6d0, 0xf6e0, 0xf6f0,
- 0xf700, 0xf710, 0xf720, 0xf730, 0xf740, 0xf750, 0xf760, 0xf770,
- 0xf780, 0xf790, 0xf7a0, 0xf7b0, 0xf7c0, 0xf7d0, 0xf7e0, 0xf7f0,
- 0xf800, 0xf810, 0xf820, 0xf830, 0xf840, 0xf850, 0xf860, 0xf870,
- 0xf880, 0xf890, 0xf8a0, 0xf8b0, 0xf8c0, 0xf8d0, 0xf8e0, 0xf8f0,
- 0xf900, 0xf910, 0xf920, 0xf930, 0xf940, 0xf950, 0xf960, 0xf970,
- 0xf980, 0xf990, 0xf9a0, 0xf9b0, 0xf9c0, 0xf9d0, 0xf9e0, 0xf9f0,
- 0xfa00, 0xfa10, 0xfa20, 0xfa30, 0xfa40, 0xfa50, 0xfa60, 0xfa70,
- 0xfa80, 0xfa90, 0xfaa0, 0xfab0, 0xfac0, 0xfad0, 0xfae0, 0xfaf0,
- 0xfb00, 0xfb10, 0xfb20, 0xfb30, 0xfb40, 0xfb50, 0xfb60, 0xfb70,
- 0xfb80, 0xfb90, 0xfba0, 0xfbb0, 0xfbc0, 0xfbd0, 0xfbe0, 0xfbf0,
- 0xfc00, 0xfc10, 0xfc20, 0xfc30, 0xfc40, 0xfc50, 0xfc60, 0xfc70,
- 0xfc80, 0xfc90, 0xfca0, 0xfcb0, 0xfcc0, 0xfcd0, 0xfce0, 0xfcf0,
- 0xfd00, 0xfd10, 0xfd20, 0xfd30, 0xfd40, 0xfd50, 0xfd60, 0xfd70,
- 0xfd80, 0xfd90, 0xfda0, 0xfdb0, 0xfdc0, 0xfdd0, 0xfde0, 0xfdf0,
- 0xfe00, 0xfe10, 0xfe20, 0xfe30, 0xfe40, 0xfe50, 0xfe60, 0xfe70,
- 0xfe80, 0xfe90, 0xfea0, 0xfeb0, 0xfec0, 0xfed0, 0xfee0, 0xfef0,
- 0xff00, 0xff10, 0xff20, 0xff30, 0xff40, 0xff50, 0xff60, 0xff70,
- 0xff80, 0xff90, 0xffa0, 0xffb0, 0xffc0, 0xffd0, 0xffe0, 0xfff0
-};
-
-/* Wait a bit for GUS before doing something
- * Mark function as volatile: don't allow it to be inlined.
- * It *should* be slow, no need to make it work faster :-)
- */
-#if !defined(__GNUC__) || (__GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ == 0)
-# define _func_noinline volatile /* match original code */
-# define _func_noclone
-#else
-/* avoid warnings from newer gcc:
- * "function definition has qualified void return type" and
- * function return types not compatible due to 'volatile' */
-# define _func_noinline __attribute__((__noinline__))
-# if (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 5)
-# define _func_noclone
-# else
-# define _func_noclone __attribute__((__noclone__))
-# endif
-#endif
-_func_noinline
-_func_noclone
- void __gus_delay()
-{
- inportb(GF1_MIX_CTRL);
- inportb(GF1_MIX_CTRL);
- inportb(GF1_MIX_CTRL);
- inportb(GF1_MIX_CTRL);
- inportb(GF1_MIX_CTRL);
- inportb(GF1_MIX_CTRL);
- inportb(GF1_MIX_CTRL);
- inportb(GF1_MIX_CTRL);
-}
-
-static void __gus_stop_controller(unsigned char gf1reg)
-{
- register unsigned char value = __gus_inregb(gf1reg);
- __gus_outregb(gf1reg, (value | GF1VC_STOPPED | GF1VC_STOP) &
- ~(GF1VC_IRQ_PENDING | GF1VC_IRQ));
-}
-
-/* Returns 1 if volume is already at given position */
-static boolean __gus_volume_ramp_to(unsigned short volume,
- unsigned char rate,
- unsigned char vol_ctrl)
-{
- int svol = __gus_inregw(GF1R_VOLUME) & 0xfff0;
- int evol = volume;
-
- /* First of all, disable volume ramp */
- __gus_stop_controller(GF1R_VOLUME_CONTROL);
-
- /* If voice is stopped, set the volume to zero and return */
- if (__gus_inregb(GF1R_VOICE_CONTROL) & GF1VC_STOPPED) {
- __gus_outregw(GF1R_VOLUME, 0);
- return 1;
- }
-
- /* Avoid clicks when volume ramp goes too high or too low */
- if (svol < 0x0400)
- svol = 0x0400;
- if (svol > 0xfc00)
- svol = 0xfc00;
- if (evol < 0x0400)
- evol = 0x0400;
- if (evol > 0xfc00)
- evol = 0xfc00;
-
- /* Adjust start/end positions */
- if (svol > evol) {
- unsigned short tmp = evol;
- evol = svol;
- svol = tmp;
- vol_ctrl |= GF1VL_BACKWARD;
- }
-
- /* If we already are (near) the target volume, quit */
- if (evol - svol < 0x1000) {
- __gus_outregw(GF1R_VOLUME, volume);
- return 1;
- }
-
- __gus_outregb(GF1R_VOLUME_START, svol >> 8);
- __gus_outregb(GF1R_VOLUME_END, evol >> 8);
- __gus_outregb(GF1R_VOLUME_RATE, rate);
- __gus_outregb_slow(GF1R_VOLUME_CONTROL, vol_ctrl);
- return 0;
-}
-
-static inline void __gus_stop_voice()
-{
- __gus_stop_controller(GF1R_VOICE_CONTROL);
- __gus_outregb_slow(GF1R_VOICE_CONTROL, GF1VC_STOPPED | GF1VC_STOP);
-}
-
-/* The GUS IRQ handler */
-static void gf1_irq()
-{
- unsigned char irq_source; /* The contents of GF1_IRQ_STATUS register */
- boolean timer_cb = 0; /* Call timer callback function */
-
- DEBUG_OFS(0, 0xCE)
- gus.eow_ignore = 0;
- while ((irq_source = inportb(GF1_IRQ_STATUS))) {
- DEBUG_OFS(1, 0xCE)
-
- if (irq_source & GF1M_IRQ_DMA_COMPLETE) {
- DEBUG_OFS(4, 0x9F)
- /* reset the IRQ pending bit */
- __gus_inregb(GF1R_DMA_CONTROL);
- gus.dma_active = 0;
-
- if (gus.dma_callback)
- gus.dma_callback();
- }
-
- if (irq_source & (GF1M_IRQ_WAVETABLE | GF1M_IRQ_ENVELOPE)) {
- unsigned char vcirq;
- unsigned int done_mask = 0;
-
- /* IRQ bits are inverse (i.e. 0 = IRQ pending) */
- while ((vcirq = __gus_inregb(GF1R_IRQ_SOURCE) ^
- (GF1IRQ_WAVE | GF1IRQ_VOLUME)) &
- (GF1IRQ_WAVE | GF1IRQ_VOLUME)) {
- unsigned long voice = (vcirq & 0x1f);
- unsigned char voice_ctl, volume_ctl;
- unsigned int voice_mask = (1 << voice);
-
- /* Don't handle more than one IRQ from same voice */
- if (done_mask & voice_mask)
- continue;
-
- done_mask |= voice_mask;
-
- /* Read voice/volume selection registers */
- __gus_select_voice(voice);
- voice_ctl = __gus_inregb(GF1R_VOICE_CONTROL);
- volume_ctl = __gus_inregb(GF1R_VOLUME_CONTROL);
-
- if ((vcirq & GF1IRQ_WAVE) && (gus.wt_callback)
- && !(gus.eow_ignore & voice_mask)) {
- DEBUG_OFS(5, 0xAF)
- gus.wt_callback(voice, voice_ctl, volume_ctl);
- }
-
- if ((vcirq & GF1IRQ_VOLUME) && (gus.vl_callback)) {
- DEBUG_OFS(6, 0xAF)
- gus.vl_callback(voice, voice_ctl, volume_ctl);
- }
- }
- }
-
- /* Reset timers that sent this IRQ */
- if (irq_source & (GF1M_IRQ_TIMER1 | GF1M_IRQ_TIMER2)) {
- unsigned char timer_ctl = gus.timer_ctl_reg;
-
- if (irq_source & GF1M_IRQ_TIMER1)
- timer_ctl &= ~GF1M_TIMER1;
-
- if (irq_source & GF1M_IRQ_TIMER2)
- timer_ctl &= ~GF1M_TIMER2;
-
- __gus_outregb_slow(GF1R_TIMER_CONTROL, timer_ctl);
- __gus_outregb_slow(GF1R_TIMER_CONTROL, gus.timer_ctl_reg);
- }
-
- if (irq_source & GF1M_IRQ_TIMER1)
- if (--gus.t1_countdown == 0) {
- gus.t1_countdown = gus.t1_multiple;
- gus.t1_ticks++;
-
- DEBUG_OFS(2, 0xCF)
-
- if (gus.t1_callback) {
- timer_cb = 1;
- gus.t1_callback();
- }
- }
-
- if (irq_source & GF1M_IRQ_TIMER2)
- if (--gus.t2_countdown == 0) {
- gus.t2_countdown = gus.t2_multiple;
- gus.t2_ticks++;
-
- DEBUG_OFS(3, 0xCF)
-
- if (gus.t2_callback)
- gus.t2_callback();
- }
-#if 0
- /* The following are not used and implemented yet */
- if (irq_source & (GF1M_IRQ_MIDI_TX | GF1M_IRQ_MIDI_RX)) {
- }
-#endif
- }
-
- irq_ack(gus.gf1_irq);
-
- if (timer_cb && gus.timer_callback)
- gus.timer_callback();
-}
-
-static void gf1_irq_end()
-{
-}
-
-static boolean __gus_detect()
-{
- /* A relatively relaxed autodetection;
- We don't count on DRAM: GUS PnP could not have it
- (although its anyway bad for us)
- */
- __gus_select_voice(0);
- __gus_stop_voice();
- __gus_outregw(GF1R_FREQUENCY, 0x1234);
- __gus_outregw(GF1R_VOLUME, 0x5670);
- return ((__gus_inregw(GF1R_FREQUENCY) & 0xfffe) == 0x1234)
- && ((__gus_inregw(GF1R_VOLUME) & 0xfff0) == 0x5670);
-}
-
-static void __gus_reset(boolean reset_io_dma)
-{
- static unsigned char irqctl[16] = { 0, 0, 1, 3, 0, 2, 0, 4, 0, 0, 0, 5, 6, 0, 0, 7 };
- static unsigned char dmactl[8] = { 0, 1, 0, 2, 0, 3, 4, 5 };
- unsigned char irqtmp, dmatmp;
-
- /* Disable interrupts while resetting to avoid spurious IRQs */
- int i, timer, old_ints = disable();
-
- /* Stop the timer so that GUS IRQ won't clobber registers */
- timer = (gus.timer_ctl_reg & GF1M_TIMER1);
- if (timer)
- gus_timer_stop();
-
- gus.dma_active = 0;
-
- __gus_outregb(GF1R_RESET, 0);
- for (i = 0; i < 10; i++)
- __gus_delay();
- __gus_outregb(GF1R_RESET, GF1M_MASTER_RESET);
- for (i = 0; i < 10; i++)
- __gus_delay();
-
- outportb(GF1_MIDI_CTRL, GF1M_MIDI_RESET);
- for (i = 0; i < 10; i++)
- __gus_delay();
- outportb(GF1_MIDI_CTRL, 0);
-
- /* Reset all IRQ sources */
- __gus_outregb(GF1R_DMA_CONTROL, 0);
- __gus_outregb(GF1R_TIMER_CONTROL, 0);
- __gus_outregb(GF1R_SAMPLE_CONTROL, 0);
-
- /* Reset all voices */
- gus_reset(gus.voices, gus.dynmask);
-
- /* Flush any pending IRQs */
- inportb(GF1_IRQ_STATUS);
- __gus_inregb(GF1R_DMA_CONTROL);
- __gus_inregb(GF1R_SAMPLE_CONTROL);
- __gus_inregb(GF1R_IRQ_SOURCE);
-
- if (reset_io_dma) {
- /* Now set up the GUS card to required IRQs and DMAs */
- if (gus.irq[0] == gus.irq[1])
- irqtmp = irqctl[gus.irq[0]] | GF1M_IRQ_EQUAL;
- else
- irqtmp = irqctl[gus.irq[0]] | (irqctl[gus.irq[1]] << 3);
-
- if (gus.dma[0] == gus.dma[1])
- dmatmp = dmactl[gus.dma[0]] | GF1M_DMA_EQUAL;
- else
- dmatmp = dmactl[gus.dma[0]] | (dmactl[gus.dma[1]] << 3);
-
- /* Reset IRQs if possible */
- gus.mixer =
- GF1M_MIXER_NO_LINE_IN | GF1M_MIXER_NO_OUTPUT | GF1M_MIXER_GF1_IRQ;
- if (gus.version >= GUS_CARD_VERSION_CLASSIC1) {
- outportb(GF1_REG_CTRL, 0x05);
- outportb(GF1_MIX_CTRL, gus.mixer);
- outportb(GF1_IRQ_CTRL, 0x00); /* Reset IRQs */
- outportb(GF1_REG_CTRL, 0x00);
- }
-
- /* Set up DMA channels: NEVER disable MIXER_GF1_IRQ in the future */
- outportb(GF1_MIX_CTRL, gus.mixer);
- outportb(GF1_IRQ_CTRL, dmatmp);
-
- /* Set up IRQ channels */
- outportb(GF1_MIX_CTRL, gus.mixer | GF1M_CONTROL_SELECT);
- outportb(GF1_IRQ_CTRL, irqtmp);
- }
-
- __gus_outregb(GF1R_RESET, GF1M_MASTER_RESET | GF1M_OUTPUT_ENABLE | GF1M_MASTER_IRQ);
- __gus_delay();
-
- /* Flush IRQs again */
- inportb(GF1_IRQ_STATUS);
- __gus_inregb(GF1R_DMA_CONTROL);
- __gus_inregb(GF1R_SAMPLE_CONTROL);
- __gus_inregb(GF1R_IRQ_SOURCE);
-
- _irq_ack(gus.irq[0]);
- _irq_ack(gus.irq[1]);
-
- if (timer)
- gus_timer_continue();
-
- if (old_ints)
- enable();
-
- /* Enable output */
- __gus_mixer_output(1);
-}
-
-/* Transfer a block of data from GUS DRAM to main RAM through port I/O */
-static void __gus_transfer_io_in(unsigned long address, unsigned char *source,
- unsigned long size)
-{
- while (size) {
- register unsigned int size64k;
-
- size64k = 0x10000 - (address & 0xffff);
- if (size64k > size)
- size64k = size;
- size -= size64k;
-
- __gus_outregb(GF1R_DRAM_HIGH, address >> 16);
- while (size64k--) {
- __gus_outregw(GF1R_DRAM_LOW, address++);
- *source++ = inportb(GF1_DRAM);
- }
- }
-}
-
-/* Transfer a block of data into GUS DRAM through port I/O */
-static void __gus_transfer_io(unsigned long address, unsigned char *source,
- unsigned long size, int flags)
-{
- while (size) {
- register unsigned int size64k;
-
- size64k = 0x10000 - (address & 0xffff);
- if (size64k > size)
- size64k = size;
- size -= size64k;
-
- __gus_outregb(GF1R_DRAM_HIGH, address >> 16);
- if (flags & GUS_WAVE_INVERT)
- if (flags & GUS_WAVE_16BIT)
- while (size64k-- && size64k--) {
- __gus_outregw(GF1R_DRAM_LOW, address++);
- outportb(GF1_DRAM, *source++);
- __gus_outregw(GF1R_DRAM_LOW, address++);
- outportb(GF1_DRAM, (*source++) ^ 0x80);
- } else
- while (size64k--) {
- __gus_outregw(GF1R_DRAM_LOW, address++);
- outportb(GF1_DRAM, (*source++) ^ 0x80);
- } else
- while (size64k--) {
- __gus_outregw(GF1R_DRAM_LOW, address++);
- outportb(GF1_DRAM, *source++);
- }
- }
-}
-
-/* Wait for DMA transfer to finish between 8-9 1/18sec timer ticks */
-static int __gus_wait_dma()
-{
- unsigned long timer;
- _farsetsel(_dos_ds);
- timer = _farnspeekl(0x46c);
- while (gus.dma_active)
- if (_farnspeekl(0x46c) - timer > 8) {
- /* Force DMA abort since something went wrong */
- __gus_reset(0);
- return -1;
- }
-
- return 0;
-}
-
-/* Transfer a block of data into GUS DRAM through DMA controller */
-static void __gus_transfer_dma(unsigned long address, unsigned char *source,
- unsigned long size, int flags)
-{
- unsigned char dma_control;
- unsigned long bytes_left;
- unsigned long cur_size;
- unsigned long dest_addr;
-
- if ((gus.dma[0] > 3) || (flags & GUS_WAVE_16BIT))
- size = (size + 1) & ~1;
-
- bytes_left = size;
- while (bytes_left) {
- __gus_wait_dma();
-
- cur_size = gus.dma_buff->size;
- if (cur_size > bytes_left)
- cur_size = bytes_left;
- bytes_left -= cur_size;
- dest_addr = address;
-
- if (gus.dma_buff->linear != source)
- memmove(gus.dma_buff->linear, source, cur_size);
- source += cur_size;
- address += cur_size;
-
- /* Disable GUS -> DMA tie */
- __gus_outregb(GF1R_DMA_CONTROL, 0);
- __gus_delay();
-
- /* Set up the DMA */
- dma_start(gus.dma_buff, cur_size, DMA_MODE_WRITE);
- gus.dma_active = 1;
-
- /* Reset the DMA IRQ pending bit if set */
- __gus_inregb(GF1R_DMA_CONTROL);
-
- /* The 16-bit DMA channels needs a slightly different approach */
- dma_control = GF1M_DMAR_ENABLE | GF1M_DMAR_IRQ_ENABLE | gus.dma_rate;
- if (gus.dma[0] > 3) {
- dest_addr = __gus_convert_addr16(dest_addr);
- dma_control |= GF1M_DMAR_CHAN16;
- }
-
- __gus_outregw(GF1R_DMA_ADDRESS, dest_addr >> 4);
-
- if (flags & GUS_WAVE_16BIT)
- dma_control |= GF1M_DMAR_DATA16;
- if (flags & GUS_WAVE_INVERT)
- dma_control |= GF1M_DMAR_TOGGLE_SIGN;
-
- /* Tell GUS to start transfer */
- __gus_outregb(GF1R_DMA_CONTROL, dma_control);
- }
-}
-
-static void __gus_detect_version()
-{
- unsigned char tmp;
-
- switch (gus.version = inportb(GF1_REVISION)) {
- case 5:
- gus.version = GUS_CARD_VERSION_CLASSIC_ICS;
- gus.ics = 1;
- gus.ics_flipped = 1;
- break;
- case 6:
- case 7:
- case 8:
- case 9:
- gus.version = GUS_CARD_VERSION_CLASSIC_ICS;
- gus.ics = 1;
- break;
- case 10:
- gus.version = GUS_CARD_VERSION_MAX;
- gus.codec = 1;
- break;
- case 11:
- gus.version = GUS_CARD_VERSION_MAX1;
- gus.codec = 1;
- break;
- case 0x30:
- gus.version = GUS_CARD_VERSION_ACE;
- break;
- case 0x50:
- gus.version = GUS_CARD_VERSION_EXTREME;
- break;
- case 0xff:
- /* Pre-3.7 board */
- outportb(GF1_REG_CTRL, 0x20);
- tmp = inportb(GF1_REG_CTRL);
- if ((tmp != 0xff) && (tmp & 0x06))
- gus.version = GUS_CARD_VERSION_CLASSIC1;
- else
- gus.version = GUS_CARD_VERSION_CLASSIC;
- break;
- default:
- /* Hmm... unknown revision. Assume a safe Classic model */
-#ifdef MIKMOD_DEBUG
- fprintf(stderr, "libgus: Unknown board revision (%02x)\n",
- gus.version);
-#endif
- gus.version = GUS_CARD_VERSION_CLASSIC;
- break;
- }
-}
-
-static void __gus_detect_transfer()
-{
- unsigned char *outbuff, *inbuff;
- unsigned int i, j, seed = 0x13243546;
- __gus_transfer_func func;
-
-#define TRANSFER_SIZE 0x4000
-
- outbuff = (unsigned char *) MikMod_malloc(TRANSFER_SIZE);
- inbuff = (unsigned char *) MikMod_malloc(TRANSFER_SIZE);
-
- /* Suppose we have an malfunctioning GUS */
- gus.transfer = NULL;
-
- for (i = (gus.dma_buff ? 0 : 4); i <= 4; i++) {
- switch (i) {
- case 0:
- gus.dma_rate = GF1M_DMAR_RATE0;
- func = __gus_transfer_dma;
- break;
- case 1:
- gus.dma_rate = GF1M_DMAR_RATE1;
- func = __gus_transfer_dma;
- break;
- case 2:
- gus.dma_rate = GF1M_DMAR_RATE2;
- func = __gus_transfer_dma;
- break;
- case 3:
- gus.dma_rate = GF1M_DMAR_RATE3;
- func = __gus_transfer_dma;
- break;
- case 4:
- func = __gus_transfer_io;
- break;
- }
-
- /* Fill data array each time with pseudo-random values */
- for (j = 0; j < TRANSFER_SIZE; j++)
- outbuff[j] = seed, seed =
- ((seed + 358979323) ^ (seed >> 16)) * 314159265;
-
- /* Transfer the random array to GUS */
- /* Poke a security fence around dest block */
- __gus_poke(0x100 - 1, 0xAA);
- __gus_poke(0x100 - 2, 0x55);
- __gus_poke(0x100 + TRANSFER_SIZE + 0, 0xAA);
- __gus_poke(0x100 + TRANSFER_SIZE + 1, 0x55);
-
- func(0x100, outbuff, TRANSFER_SIZE, 0);
-
- if (__gus_wait_dma() == 0) {
- /* Check if the security fence was not damaged */
- if ((__gus_peek(0x100 - 1) != 0xAA)
- || (__gus_peek(0x100 - 2) != 0x55)
- || (__gus_peek(0x100 + TRANSFER_SIZE + 0) != 0xAA)
- || (__gus_peek(0x100 + TRANSFER_SIZE + 1) != 0x55))
- continue;
-
- /* Now check if GUS DRAM really data that we expects to be transferred */
- __gus_transfer_io_in(0x100, inbuff, TRANSFER_SIZE);
- if (memcmp(outbuff, inbuff, TRANSFER_SIZE) == 0) {
- gus.transfer = func;
- break;
- }
- }
- }
-
-#undef TRANSFER_SIZE
-
- MikMod_free(inbuff);
- MikMod_free(outbuff);
-}
-
-static void __gus_detect_memory()
-{
- unsigned int size;
- for (size = 0; size < 1024; size += 256) {
- __gus_poke(size * 1024, 0xaa);
- if (__gus_peek(size * 1024) != 0xaa)
- break;
- __gus_poke(size * 1024, 0x55);
- if (__gus_peek(size * 1024) != 0x55)
- break;
- }
- gus.ram = size;
-}
-
-static void __gus_init()
-{
- char *gusenv = getenv("ULTRASND");
-
- memset((void *)&gus, 0, sizeof(gus));
- gus.cmd_voice = -1;
-
- if (!gusenv)
- return;
-
- sscanf(gusenv, "%x,%d,%d,%d,%d", &gus.port, &gus.dma[0], &gus.dma[1],
- &gus.irq[0], &gus.irq[1]);
-
- /* A relaxed sanity check */
- if ((gus.port < 0x100) || (gus.port > 0x1000)
- || (gus.irq[0] < 2) || (gus.irq[0] > 15)
- || (gus.irq[1] < 2) || (gus.irq[1] > 15)
- || (gus.dma[0] < 0) || (gus.dma[0] > 7)
- || (gus.dma[1] < 0) || (gus.dma[1] > 7))
- return;
-
- gus.voices = 32;
- gus.timer_ctl = GF1M_MASK_TIMER1 | GF1M_MASK_TIMER2;
-
- /* Detect if the card is really there */
- if (__gus_detect() == 0)
- return;
-
- /* Detect the version of Gravis Ultrasound */
- __gus_detect_version();
-
- /* Reset the card */
- __gus_reset(1);
-
- /* Detect the amount of on-board memory */
- __gus_detect_memory();
-
- gus.ok = 1;
-}
-
-static void __gus_kick(gus_wave_t * wave, unsigned int wave_offset)
-{
- unsigned char vc;
-
- vc = GF1VC_IRQ;
- if (wave->format & GUS_WAVE_16BIT)
- vc |= GF1VC_DATA16;
- if (wave->format & GUS_WAVE_BACKWARD)
- vc |= GF1VC_BACKWARD;
- if (wave->format & GUS_WAVE_LOOP) {
- vc |= GF1VC_LOOP_ENABLE;
- if (wave->format & GUS_WAVE_BIDIR)
- vc |= GF1VC_BI_LOOP;
- }
- __gus_set_loop_start(vc, (wave->begin.memory << 4) + wave->loop_start);
- if (wave->format & GUS_WAVE_LOOP)
- __gus_set_loop_end(vc, (wave->begin.memory << 4) + wave->loop_end);
- else
- __gus_set_loop_end(vc, (wave->begin.memory + wave->size) << 4);
- __gus_set_current(vc, (wave->begin.memory << 4) + wave_offset + 100);
- __gus_outregb_slow(GF1R_VOICE_CONTROL, vc);
-}
-
-/* Timer 1 callback function (updates voices) */
-static void __gus_timer_update()
-{
- gus_wave_t *wave;
- unsigned long wave_offset;
- unsigned char *src, *top;
- unsigned int vmask = (1 << gus.cur_voice);
-
- if (!gus.cmd_pool_ready)
- return;
-
- __gus_select_voice(gus.cur_voice);
- wave_offset = 0;
- src = gus.cmd_pool;
- top = gus.cmd_pool + gus.cmd_pool_top;
-
-#define GET_B *src
-#define GET_W *((unsigned short *)src)
-#define GET_L *((unsigned long *)src)
-
- while (src < top) {
- __gus_delay();
- switch (GET_B++) {
- case PCMD_VOICE:
- __gus_select_voice(gus.cur_voice = GET_B++);
- vmask = (1 << gus.cur_voice);
- break;
- case PCMD_FREQ:
- /* __gus_outregw(GF1R_FREQUENCY, GET_W++);*/
- __gus_outregw(GF1R_FREQUENCY, *(unsigned short *)src);
- src += 2;
- break;
- case PCMD_PAN:
- __gus_outregb(GF1R_BALANCE, GET_B++);
- break;
- case PCMD_VOLUME:
- __gus_volume_ramp_to(gus.cur_vol[gus.cur_voice] =
- /* GET_W++, GUS_VOLCHANGE_RAMP, GF1VL_IRQ);*/
- *(unsigned short *)src, GUS_VOLCHANGE_RAMP, GF1VL_IRQ);
- src += 2;
- break;
- case PCMD_VOLUME_PREPARE:
- /* gus.cur_vol[gus.cur_voice] = GET_W++;*/
- gus.cur_vol[gus.cur_voice] = *(unsigned short *)src;
- src += 2;
- break;
- case PCMD_OFFSET:
- /* wave_offset = GET_L++;*/
- wave_offset = *(unsigned long *)src;
- src += 4;
- break;
- case PCMD_START:
- /* wave = (gus_wave_t *) GET_L++;*/
- wave = (gus_wave_t *) *(unsigned long *)src;
- src += 4;
- gus.cur_wave[gus.cur_voice] = wave;
- gus.kick_offs[gus.cur_voice] = wave_offset;
- if (__gus_volume_ramp_to(0, GUS_VOLCHANGE_RAMP, GF1VL_IRQ)) {
- __gus_kick(wave, wave_offset);
- __gus_volume_ramp_to(gus.cur_vol[gus.cur_voice],
- GUS_VOLCHANGE_RAMP, GF1VL_IRQ);
- } else
- gus.voice_kick[gus.cur_voice] = 1;
- wave_offset = 0;
- gus.eow_ignore |= vmask;
- break;
- case PCMD_STOP:
- /* If volume is close to nothing, abort immediately instead of
- ramping */
- gus.cur_vol[gus.cur_voice] = 0;
- gus.cur_wave[gus.cur_voice] = NULL;
- if (__gus_volume_ramp_to(0, GUS_VOLCHANGE_RAMP, GF1VL_IRQ))
- __gus_stop_voice();
- break;
- case PCMD_STOP_LOOP:
- __gus_outregb_slow(GF1R_VOICE_CONTROL,
- (__gus_inregb(GF1R_VOICE_CONTROL) | GF1VC_IRQ)
- & ~GF1VC_LOOP_ENABLE);
- __gus_outregb_slow(GF1R_VOLUME_CONTROL,
- __gus_inregb(GF1R_VOLUME_CONTROL) &
- ~GF1VL_ROLLOVER);
- break;
- default:
- /* Alarm! Break out immediately */
- src = top;
- break;
- }
- }
-
-#undef GET_B
-#undef GET_W
-#undef GET_L
-
- gus.cmd_pool_ready = 0;
- gus.cmd_pool_top = 0;
-}
-
-static void __gus_wavetable_update(unsigned int voice, unsigned int voice_ctl,
- unsigned int volume_ctl)
-{
- gus_wave_t *wave = gus.cur_wave[voice];
-
- if (!wave || !(wave->format & GUS_WAVE_LOOP)) {
- __gus_stop_voice();
- gus.cur_wave[voice] = NULL;
- gus.cur_vol[voice] = 0;
- if (__gus_volume_ramp_to(0, GUS_VOLCHANGE_RAMP, GF1VL_IRQ))
- __gus_stop_voice();
- }
-}
-
-static void __gus_volume_update(unsigned int voice, unsigned int voice_ctl,
- unsigned int volume_ctl)
-{
- __gus_volume_ramp_to(gus.cur_vol[voice], GUS_VOLCHANGE_RAMP, GF1VL_IRQ);
- if (!gus.cur_wave[voice])
- __gus_stop_voice();
- else if (gus.voice_kick[voice])
- __gus_kick(gus.cur_wave[voice], gus.kick_offs[voice]);
- gus.voice_kick[voice] = 0;
-}
-
-/***************************************************** GUS memory manager *****/
-
-/* Mark all GUS memory as available */
-static void __gus_mem_clear()
-{
- __gus_mcb *cur = gus.mcb;
-
- while (cur) {
- __gus_mcb *next = cur->next;
- if (cur != gus.mcb)
- MikMod_free(cur);
- cur = next;
- }
-
- if (!gus.mcb)
- gus.mcb = (__gus_mcb *) MikMod_malloc(sizeof(__gus_mcb));
-
- gus.mcb->next = gus.mcb->prev = NULL;
- gus.mcb->addr = 0;
- gus.mcb->size = gus.ram * 1024;
- gus.mcb->free = 1;
-}
-
-/* Return amount of free memory */
-static unsigned int __gus_mem_get_free()
-{
- __gus_mcb *cur = gus.mcb;
- unsigned int size = 0;
-
- if (!gus.open)
- return gus.ram * 1024;
-
- while (cur) {
- if (cur->free)
- size += cur->size;
- cur = cur->next;
- }
-
- return size;
-}
-
-/* Return largest size for a 8-bit sample */
-static unsigned int __gus_mem_get_free_8()
-{
- __gus_mcb *cur = gus.mcb;
- unsigned int size = 0;
-
- if (!gus.open)
- return 0;
-
- while (cur) {
- if (cur->free && (cur->size > size))
- size = cur->size;
- cur = cur->next;
- }
-
- return size;
-}
-
-/* Return largest size for a 16-bit sample */
-static unsigned int __gus_mem_get_free_16()
-{
- __gus_mcb *cur = gus.mcb;
- unsigned int size = 0;
-
- if (!gus.open)
- return 0;
-
- while (cur) {
- if (cur->free) {
- unsigned int size16 = cur->size;
- unsigned int tmp;
- /* 16-bit samples cannot cross 256K boundaries */
- tmp = 0x40000 - (cur->addr & 0x3ffff);
- if (size16 > tmp)
- size16 = tmp;
- /* 16-bit samples should be aligned on a 32-byte boundary */
- size16 -= (32 - cur->addr) & 0x1f;
-
- if (size16 > size)
- size = size16;
-
- /* Now try vice versa: skip a portion of aligned memory */
- size16 =
- (cur->addr + cur->size) - ((cur->addr + 0x3ffff) & ~0x3ffff);
- if ((size16 < 0x7fffffff) && (size16 > size))
- size = size16;
- }
- cur = cur->next;
- }
-
- return size;
-}
-
-/* Allocate a segment of GUS DRAM for a sample with given bits per sample.
- * The algorithm tries to find the smallest free block that fits requested
- * size; but if found free block is larger by some (large) delta than
- * requested block size, the largest possible block is preffered.
- */
-static unsigned int __gus_mem_alloc(unsigned int size, int bits16)
-{
- __gus_mcb *cur = gus.mcb;
- __gus_mcb *best_max = NULL, *best_min = NULL;
- unsigned int best_max_delta = 0, best_min_delta = 0xffffffff;
- unsigned int best_max_prefix = 0, best_min_prefix = 0;
- unsigned int memaddr, memsize;
-
- if (!gus.open || !size || (bits16 && size > 0x40000))
- return -1;
-
- /* Round block size up to nearest acceptable DMA bound */
- if (bits16)
- size = (size + 0x1f) & ~0x1f;
- else
- size = (size + 0x0f) & ~0x0f;
-
- while (cur) {
- if (cur->free) {
- unsigned char fits = 0;
-
- memsize = cur->size;
- memaddr = cur->addr;
-
- if (bits16) {
- /* 16-bit samples cannot cross 256K boundaries */
- unsigned int tmp = 256 * 1024 - (memaddr & 0x3ffff);
- if (memsize > tmp)
- memsize = tmp;
- /* 16-bit samples should be aligned on a 32-byte boundary */
- memsize -= (32 - memaddr) & 0x1f;
- memaddr = (memaddr + 0x1f) & ~0x1f;
- }
-
- /* If block fits, analyze it */
- if (size <= memsize)
- fits = 1;
- /* Look if we still can complete the request by creating a free
- block */
- else if (size <= cur->size) {
- /* Align start address to next 256k boundary */
- unsigned int endaddr = cur->addr + cur->size;
- memaddr = (cur->addr + 0x3ffff) & ~0x3ffff;
- /* Can we split current block by inserting a free block at the
- beginning? */
- if ((memaddr < endaddr) && (memaddr + size <= endaddr))
- fits = 1;
- }
-
- if (fits) {
- unsigned int size_delta = cur->size - size;
- unsigned int size_prefix = memaddr - cur->addr;
- if (size_delta < best_min_delta)
- best_min = cur, best_min_delta =
- size_delta, best_min_prefix = size_prefix;
- if (size_delta > best_max_delta)
- best_max = cur, best_max_delta =
- size_delta, best_max_prefix = size_prefix;
- }
- }
-
- cur = cur->next;
- }
-
- if (!best_min)
- return -1;
-
- /* If minimal block that fits is too large, use largest block that fits */
- /* But if using the maximal block is going to create a small hole, forget
- it */
- if ((best_max_prefix == 0)
- || (best_max_prefix >= DRAM_HOLE_THRESHOLD)
- || (best_min_prefix != 0))
- if (
- ((best_min_delta < DRAM_HOLE_THRESHOLD) &&
- (best_max_delta >= DRAM_HOLE_THRESHOLD)) ||
- ((best_min_prefix > 0) && (best_min_prefix < DRAM_HOLE_THRESHOLD)
- && ((best_max_prefix == 0) ||
- (best_max_prefix > best_min_prefix))) ||
- ((best_min_prefix != 0) && (best_max_prefix == 0))) {
- best_min = best_max;
- best_min_delta = best_max_delta;
- best_min_prefix = best_max_prefix;
- }
-
- /* Compute the DRAM address to return */
- memaddr = best_min->addr + best_min_prefix;
- if (bits16)
- memaddr = (memaddr + 0x1f) & ~0x1f;
- else
- memaddr = (memaddr + 0x0f) & ~0x0f;
-
- /* If we have a considerable hole at the beginning of sample,
- create a free node describing the hole */
- if (memaddr - best_min->addr >= DRAM_SPLIT_THRESHOLD) {
- __gus_mcb *newmcb = (__gus_mcb *) MikMod_malloc(sizeof(__gus_mcb));
- newmcb->prev = best_min->prev;
- newmcb->next = best_min;
- newmcb->addr = best_min->addr;
- newmcb->size = memaddr - best_min->addr;
- newmcb->free = 1;
- best_min->addr = memaddr;
- best_min->size -= newmcb->size;
- best_min->prev = newmcb;
- if (newmcb->prev)
- newmcb->prev->next = newmcb;
- }
-
- /* Compute the size of hole at the end of block */
- memsize = (best_min->addr + best_min->size) - (memaddr + size);
-
- /* Split the block if the block is larger than requested amount */
- if (memsize > DRAM_SPLIT_THRESHOLD) {
- /* The next node cannot be free since free blocks are always glued
- together */
- __gus_mcb *newmcb = (__gus_mcb *) MikMod_malloc(sizeof(__gus_mcb));
- best_min->size -= memsize;
- newmcb->prev = best_min;
- newmcb->next = best_min->next;
- newmcb->addr = best_min->addr + best_min->size;
- newmcb->size = memsize;
- newmcb->free = 1;
- if (best_min->next)
- best_min->next->prev = newmcb;
- best_min->next = newmcb;
- }
- best_min->free = 0;
-
- return memaddr;
-}
-
-static void __gus_mem_free(unsigned int addr)
-{
- __gus_mcb *cur = gus.mcb;
- while (cur) {
- if (!cur->free && (cur->addr <= addr) &&
- (cur->addr + cur->size > addr)) {
- cur->free = 1;
-
- /* If next block is free as well, link them together */
- if (cur->next && cur->next->free) {
- __gus_mcb *next = cur->next;
- cur->size += next->size;
- cur->next = next->next;
- if (next->next)
- next->next->prev = cur;
- MikMod_free(next);
- }
-
- /* If previous block is free, link current block with it */
- if (cur->prev && cur->prev->free) {
- cur->prev->size += cur->size;
- cur->prev->next = cur->next;
- if (cur->next)
- cur->next->prev = cur->prev;
- MikMod_free(cur);
- }
- return;
- }
- cur = cur->next;
- }
-}
-
-static void __gus_mem_pack()
-{
-}
-
-#ifdef MIKMOD_DEBUG
-
-/* Debug dump of GUS DRAM heap */
-void __gus_mem_dump()
-{
- __gus_mcb *cur = gus.mcb;
- fprintf(stderr, "/-- Offset --+-- Prev --+-- Size --+-- Free --\\\n");
- while (cur) {
- fprintf(stderr, "| %08X | %08X | %6d | %s |\n",
- cur->addr, cur->prev ? cur->prev->addr : -1, cur->size,
- cur->free ? "yes" : " no");
- cur = cur->next;
- }
- fprintf(stderr, "\\------------+----------+----------+----------/\n");
-}
-
-#endif
-
-/************************************************** Middle-level routines *****/
-
-static int __gus_instrument_free(gus_instrument_t * instrument)
-{
- gus_instrument_t **cur_instr;
- gus_layer_t *cur_layer;
- gus_wave_t *cur_wave, *wave_head;
-
- /* Remove the instrument from the list of registered instruments */
- cur_instr = (gus_instrument_t **) & gus.instr;
- while (*cur_instr) {
- if (*cur_instr == instrument) {
- *cur_instr = instrument->next;
- goto instr_loaded;
- }
- cur_instr = &(*cur_instr)->next;
- }
- return -1;
-
-instr_loaded:
- wave_head = NULL;
- for (cur_layer = instrument->info.layer; cur_layer;
- cur_layer = cur_layer->next)
- /* Free all waves */
- for (cur_wave = cur_layer->wave; cur_wave; cur_wave = cur_wave->next) {
- if (!wave_head)
- wave_head = cur_wave;
- if (cur_wave->begin.memory != (unsigned int)-1)
- __gus_mem_free(cur_wave->begin.memory);
- }
- if (wave_head)
- MikMod_free(wave_head);
-
- MikMod_free(instrument->info.layer);
- if (instrument->name)
- MikMod_free(instrument->name);
- MikMod_free(instrument);
- return 0;
-}
-
-static gus_instrument_t *__gus_instrument_get(int program)
-{
- gus_instrument_t *cur_instr = (gus_instrument_t *) gus.instr;
- while (cur_instr) {
- if (cur_instr->number.instrument == program)
- return cur_instr;
- cur_instr = cur_instr->next;
- }
- return NULL;
-}
-
-static gus_instrument_t *__gus_instrument_copy(gus_instrument_t * instrument)
-{
- gus_instrument_t **cur_instr, *instr;
- gus_layer_t *cur_layer, *dest_layer;
- gus_wave_t *cur_wave, *dest_wave;
- unsigned int waves, layers;
-
- if (!instrument || !instrument->info.layer || !gus.open)
- return NULL;
-
- if (__gus_instrument_get(instrument->number.instrument))
- return NULL;
-
- instr = (gus_instrument_t *) MikMod_malloc(sizeof(gus_instrument_t));
- *instr = *instrument;
-
- if (instrument->name)
- instr->name = MikMod_strdup(instrument->name);
-
- /* Make a copy of all layers at once */
- for (layers = 0, cur_layer = instrument->info.layer; cur_layer; layers++)
- cur_layer = cur_layer->next;
-
- if (!(dest_layer = instr->info.layer = (gus_layer_t *) MikMod_malloc(sizeof(gus_layer_t) * layers))) {
- if (instr->name)
- MikMod_free(instr->name);
- MikMod_free(instr);
- return NULL;
- }
- for (waves = 0, cur_layer = instrument->info.layer; cur_layer;
- cur_layer = cur_layer->next) {
- *dest_layer = *cur_layer;
- dest_layer->wave = NULL;
- /* Count the total number of waves */
- for (cur_wave = cur_layer->wave; cur_wave; cur_wave = cur_wave->next)
- waves++;
- if (cur_layer->next)
- dest_layer->next = dest_layer + 1;
- else
- dest_layer->next = NULL;
- dest_layer++;
- }
-
- /* Allocate memory for waves */
- if (!(dest_wave = (gus_wave_t *) MikMod_malloc(sizeof(gus_wave_t) * waves))) {
- MikMod_free(instr->info.layer);
- if (instr->name)
- MikMod_free(instr->name);
- MikMod_free(instr);
- return NULL;
- }
- for (cur_layer = instrument->info.layer, dest_layer = instr->info.layer;
- cur_layer; cur_layer = cur_layer->next, dest_layer = dest_layer->next)
- /* Copy all waves */
- for (cur_wave = cur_layer->wave; cur_wave; cur_wave = cur_wave->next) {
- if (!dest_layer->wave)
- dest_layer->wave = dest_wave;
-
- *dest_wave = *cur_wave;
- /* Mark DRAM address as unallocated */
- dest_wave->begin.memory = -1;
-
- if (cur_wave->next)
- dest_wave->next = (dest_wave + 1);
- else
- dest_wave->next = NULL;
- dest_wave++;
- }
-
- /* Insert the instrument into list of registered instruments */
- cur_instr = (gus_instrument_t **) & gus.instr;
- while (*cur_instr)
- cur_instr = &(*cur_instr)->next;
- *cur_instr = instr;
-
- return instr;
-}
-
-static void __gus_instruments_clear()
-{
- gus_instrument_t *next_instr, *cur_instr = (gus_instrument_t *) gus.instr;
- while (cur_instr) {
- next_instr = cur_instr->next;
- __gus_instrument_free(cur_instr);
- cur_instr = next_instr;
- }
-}
-
-/******************************************************* libGUS interface *****/
-
-/* return value: number of GUS cards installed in system */
-int gus_cards()
-{
- if (!gus.ok)
- __gus_init();
- return gus.ok ? 1 : 0;
-}
-
-int gus_info(gus_info_t * info, int reread)
-{
- if (!gus.ok)
- __gus_init();
- if (!gus.ok)
- return -1;
-
- strcpy((char *)info->id, "gus0");
- info->flags = (gus.ram ? GUS_STRU_INFO_F_PCM : 0);
- info->version = gus.version;
- info->port = gus.port;
- info->irq = gus.irq[0];
- info->dma1 = gus.dma[0];
- info->dma2 = gus.dma[1];
-
- info->mixing_freq = gus.freq;
-
- info->memory_size = gus.ram * 1024;
- info->memory_free = __gus_mem_get_free();
- info->memory_block_8 = __gus_mem_get_free_8();
- info->memory_block_16 = __gus_mem_get_free_16();
- return 0;
-}
-
-int gus_open(int card, size_t queue_buffer_size, int non_block)
-{
- __dpmi_meminfo struct_info, pool_info;
-
- if (!gus.ok)
- __gus_init();
-
- if (!gus.ok || gus.open || card != 0)
- return -1;
-
- /* Now lock the gus structure in memory */
- struct_info.address = __djgpp_base_address + (unsigned long)&gus;
- struct_info.size = sizeof(gus);
- if (__dpmi_lock_linear_region(&struct_info))
- return -1;
-
- /* And hook the GF1 interrupt */
- __irq_stack_count = 4;
- gus.gf1_irq =
- irq_hook(gus.irq[0], gf1_irq, (long)gf1_irq_end - (long)gf1_irq);
- __irq_stack_count = 1;
- if (!gus.gf1_irq) {
- __dpmi_unlock_linear_region(&struct_info);
- return -1;
- }
-
- /* Enable the interrupt */
- irq_enable(gus.gf1_irq);
- if (gus.irq[0] > 7)
- _irq_enable(2);
-
- /* Allocate a DMA buffer: if we fail, we just use I/O so don't fail */
- if ((gus.transfer == NULL) || (gus.transfer == __gus_transfer_dma))
- gus.dma_buff = dma_allocate(gus.dma[0], GF1_DMA_BUFFER_SIZE);
- else
- gus.dma_buff = NULL;
-
- /* Detect the best available RAM -> DRAM transfer function */
- if (!gus.transfer) {
- __gus_detect_transfer();
- if (gus.transfer != __gus_transfer_dma || !gus.transfer)
- dma_free(gus.dma_buff), gus.dma_buff = NULL;
-
- /* If no transfer function worked, fail */
- if (!gus.transfer) {
- if (gus.dma_buff) {
- dma_free(gus.dma_buff);
- gus.dma_buff = NULL;
- }
- __dpmi_unlock_linear_region(&struct_info);
- irq_unhook(gus.gf1_irq);
- gus.gf1_irq = NULL;
- return -1;
- }
- }
-
- /* Allocate and lock command pool buffer */
- if (queue_buffer_size < 64)
- queue_buffer_size = 64;
- if (queue_buffer_size > 16384)
- queue_buffer_size = 16384;
- gus.cmd_pool = (unsigned char *) MikMod_malloc(queue_buffer_size);
- pool_info.address = __djgpp_base_address + (unsigned long)&gus.cmd_pool;
- pool_info.size = sizeof(queue_buffer_size);
- if (__dpmi_lock_linear_region(&pool_info)) {
- if (gus.dma_buff) {
- dma_free(gus.dma_buff);
- gus.dma_buff = NULL;
- }
- __dpmi_unlock_linear_region(&struct_info);
- irq_unhook(gus.gf1_irq);
- gus.gf1_irq = NULL;
- return -1;
- }
-
- gus.open++;
-
- __gus_mem_clear();
- gus.t1_callback = __gus_timer_update;
- gus.wt_callback = __gus_wavetable_update;
- gus.vl_callback = __gus_volume_update;
- gus_do_tempo(60); /* Default is 60 Hz */
-
- return 0;
-}
-
-int gus_close(int card)
-{
- __dpmi_meminfo struct_info;
-
- if (!gus.open || card != 0)
- return -1;
-
- /* First reset the card: disable any operation it can currently perform */
- __gus_reset(0);
-
- gus.open--;
-
- /* Stop the timer */
- gus_timer_stop();
-
- /* Free DMA buffer if used */
- if (gus.dma_buff) {
- dma_free(gus.dma_buff);
- gus.dma_buff = NULL;
- }
-
- /* And unhook the GF1 interrupt */
- irq_unhook(gus.gf1_irq);
- gus.gf1_irq = NULL;
-
- /* Unlock the gus structure */
- struct_info.address = __djgpp_base_address + (unsigned long)&gus;
- struct_info.size = sizeof(gus);
- __dpmi_unlock_linear_region(&struct_info);
-
- __gus_mem_clear();
- __gus_instruments_clear();
-
- return 0;
-}
-
-int gus_select(int card)
-{
- if (!gus.open || (card != 0))
- return -1;
-
- return 0;
-}
-
-/* return value: same as gus_reset function
- note: this command doesn't change number of active voices and doesn't do
- hardware reset */
-int gus_reset_engine_only()
-{
- gus.timer_base = 100;
- return 0;
-}
-
-int gus_reset(int voices, unsigned int channel_voices)
-{
- static unsigned short freq_table[32 - 14 + 1] = {
- 44100, 41160, 38587, 36317, 34300, 32494, 30870, 29400, 28063, 26843,
- 25725, 24696, 23746, 22866, 22050, 21289, 20580, 19916, 19293
- };
- int voice;
- int timer;
-
- /* No support for dynamically allocated voices for now */
- gus.dynmask = channel_voices;
-
- if (voices < 14)
- voices = 14;
- if (voices > 32)
- voices = 32;
-
- /* Stop the timer so that GUS IRQ won't clobber registers */
- timer = (gus.timer_ctl_reg & GF1M_TIMER1);
- if (timer)
- gus_timer_stop();
-
- /* Stop all voices */
- for (voice = 0; voice < 32; voice++) {
- __gus_select_voice(voice);
- __gus_stop_voice();
- gus.cur_wave[voice] = NULL;
- gus.cur_vol[voice] = 0;
-
- __gus_delay();
-
- /* Reset voice parameters to reasonable values */
- __gus_set_current(0, 0);
- __gus_set_loop_start(0, 0);
- __gus_set_loop_end(0, 0);
- __gus_outregw(GF1R_VOLUME, 0);
- __gus_outregb(GF1R_VOLUME_RATE, 0);
- __gus_outregb(GF1R_VOLUME_START, 0);
- __gus_outregb(GF1R_VOLUME_END, 0);
- __gus_outregb(GF1R_BALANCE, 0x7);
- }
-
- voice = (__gus_inregb(GF1R_VOICES) & 0x1f) + 1;
-
- if (voice != voices) {
- int reset = __gus_inregb(GF1R_RESET);
- __gus_outregb(GF1R_RESET, reset & ~GF1M_OUTPUT_ENABLE);
- __gus_delay();
- __gus_outregb(GF1R_VOICES, 0xc0 | (voices - 1));
- __gus_delay();
- __gus_outregb(GF1R_RESET, reset);
- }
-
- /* Compute the discretization frequence */
- gus.voices = voices;
- if (gus.interwave)
- gus.freq = 44100;
- else
- gus.freq = freq_table[voices - 14];
-
- gus_reset_engine_only();
-
- if (timer)
- gus_timer_continue();
-
- return gus.voices;
-}
-
-int gus_do_flush()
-{
- DEBUG_PRINT(("gus_do_flush: top = %d\n", gus.cmd_pool_top))
- gus.cmd_pool_ready = 1;
- return 0;
-}
-
-/* set new tempo */
-void gus_do_tempo(unsigned int tempo)
-{
- DEBUG_PRINT(("gus_do_tempo (%d)\n", tempo))
- gus_timer_tempo(tempo);
- gus_timer_start();
-}
-
-/* set voice frequency in Hz */
-void gus_do_voice_frequency(unsigned char voice, unsigned int freq)
-{
- DEBUG_PRINT(("gus_do_voice_frequency (%d, %d)\n", voice, freq))
- __pool_select_voice(voice);
- __pool_command_w(PCMD_FREQ,
- (((freq << 9) + (gus.freq >> 1)) / gus.freq) << 1);
-}
-
-/* set voice pan (0-16384) (full left - full right) */
-void gus_do_voice_pan(unsigned char voice, unsigned short pan)
-{
- DEBUG_PRINT(("gus_do_voice_pan (%d, %d)\n", voice, pan))
- pan >>= 10;
- if (pan > 15)
- pan = 15;
- __pool_select_voice(voice);
- __pool_command_b(PCMD_PAN, pan);
-}
-
-/* set voice volume level 0-16384 (linear) */
-void gus_do_voice_volume(unsigned char voice, unsigned short vol)
-{
- DEBUG_PRINT(("gus_do_voice_volume (%d, %d)\n", voice, vol))
- if (vol > 0x3fff)
- vol = 0x3fff;
- __pool_select_voice(voice);
- __pool_command_w(PCMD_VOLUME, __gus_volume_table[vol >> 5]);
-}
-
-/* start voice
- * voice : voice #
- * program : program # or ~0 = current
- * freq : frequency in Hz
- * volume : volume level (0-16384) or ~0 = current
- * pan : pan level (0-16384) or ~0 = current
- */
-void gus_do_voice_start(unsigned char voice, unsigned int program,
- unsigned int freq, unsigned short volume,
- unsigned short pan)
-{
- gus_do_voice_start_position(voice, program, freq, volume, pan, 0);
-}
-
-/* start voice
- * voice : voice #
- * program : program # or ~0 = current
- * freq : frequency in Hz
- * volume : volume level (0-16384) or ~0 = current
- * pan : pan level (0-16384) or ~0 = current
- * position : offset to wave in bytes * 16 (lowest 4 bits - fraction)
- */
-void gus_do_voice_start_position(unsigned char voice, unsigned int program,
- unsigned int freq, unsigned short volume,
- unsigned short pan, unsigned int position)
-{
- gus_instrument_t *instrument;
- gus_wave_t *wave;
-
- DEBUG_PRINT(
- ("gus_do_voice_start_position (%d, %d, pos: %d)\n", voice,
- program, position))
-
- instrument = __gus_instrument_get(program);
-
- if (!instrument
- || !instrument->info.layer
- || !instrument->info.layer->wave
- || instrument->flags == GUS_INSTR_F_NOT_FOUND
- || instrument->flags == GUS_INSTR_F_NOT_LOADED) return;
-
- gus_do_voice_frequency(voice, freq);
- gus_do_voice_pan(voice, pan);
-
- /* We have to set volume different way, to avoid unneeded work in handler */
- if (volume > 0x3fff)
- volume = 0x3fff;
- __pool_command_w(PCMD_VOLUME_PREPARE, __gus_volume_table[volume >> 5]);
-
- switch (instrument->mode) {
- case GUS_INSTR_SIMPLE:
- wave = instrument->info.layer->wave;
- if (position)
- __pool_command_l(PCMD_OFFSET, position);
- __pool_command_l(PCMD_START, (unsigned long)wave);
- break;
- }
-}
-
-/* stop voice
- * mode = 0 : stop voice now
- * mode = 1 : disable wave loop and finish it
- */
-void gus_do_voice_stop(unsigned char voice, unsigned char mode)
-{
- __pool_select_voice(voice);
- if (mode)
- __pool_command(PCMD_STOP_LOOP);
- else
- __pool_command(PCMD_STOP);
-}
-
-/* wait x ticks - this command is block separator
- all commands between blocks are interpreted in the begining of one tick */
-void gus_do_wait(unsigned int ticks)
-{
- DEBUG_PRINT(("gus_do_wait (%d)\n", ticks))
-
- ticks += gus.t1_ticks;
- while ((int)(ticks - gus.t1_ticks) > 0);
-}
-
-int gus_get_voice_status(int voice)
-{
- __gus_select_voice(voice);
- return __gus_inregb(GF1R_VOICE_CONTROL) & GF1VC_STOPPED ? 0 : 1;
-}
-
-/* return value: file handle (descriptor) for /dev/gus */
-int gus_get_handle()
-{
- /* Return stdout handle so that select() will "work" with it */
- return 0;
-}
-
-/* return value: zero if instrument was successfully allocated */
-int gus_memory_alloc(gus_instrument_t * instrument)
-{
- gus_instrument_t *instr = __gus_instrument_copy(instrument);
- gus_layer_t *cur_layer;
- gus_wave_t *cur_wave;
-
- DEBUG_PRINT(("gus_memory_alloc (%d)\n", instrument->number.instrument))
-
- if (!instr)
- return -1;
-
- for (cur_layer = instr->info.layer; cur_layer;
- cur_layer = cur_layer->next) for (cur_wave = cur_layer->wave;
- cur_wave;
- cur_wave = cur_wave->next) {
- if (cur_layer->mode == GUS_INSTR_SIMPLE) {
- cur_wave->begin.memory = __gus_mem_alloc(cur_wave->size,
- cur_wave->format &
- GUS_WAVE_16BIT);
- if (cur_wave->begin.memory == (unsigned int)-1) {
- __gus_instrument_free(instr);
- return -1;
- }
- gus.transfer(cur_wave->begin.memory, cur_wave->begin.ptr,
- cur_wave->size, cur_wave->format);
- } else if (cur_layer->mode == GUS_INSTR_PATCH)
- /* not supported yet */ ;
- }
-
- return 0;
-}
-
-/* return value: zero if instrument was successfully removed */
-int gus_memory_free(gus_instrument_t * instrument)
-{
- gus_instrument_t *cur_instr = gus.instr;
-
- DEBUG_PRINT(("gus_memory_free (%d)\n", instrument->number.instrument))
-
- for (; cur_instr; cur_instr = cur_instr->next)
- if (cur_instr->number.instrument == instrument->number.instrument)
- return __gus_instrument_free(cur_instr);
-
- return -1;
-}
-
-/* return value: unused gus memory in bytes */
-int gus_memory_free_size()
-{
- return __gus_mem_get_free();
-}
-
-/* return value: zero if success */
-int gus_memory_pack()
-{
- __gus_mem_pack();
- return 0;
-}
-
-/* return value: gus memory size in bytes */
-int gus_memory_size()
-{
- return gus.ram * 1024;
-}
-
-/* return value: current largest free block for 8-bit or 16-bit wave */
-int gus_memory_free_block(int w_16bit)
-{
- return w_16bit ? __gus_mem_get_free_16() : __gus_mem_get_free_8();
-}
-
-/* input value: see to GUS_DOWNLOAD_MODE_XXXX constants (gus.h)
- return value: zero if samples & instruments was successfully removed from
- GF1 memory manager */
-int gus_memory_reset(int mode)
-{
- __gus_mem_clear();
- __gus_instruments_clear();
- return 0;
-}
-
-/* return value: zero if command queue was successfully flushed */
-int gus_queue_flush()
-{
- return 0;
-}
-
-/* input value: echo buffer size in items (if 0 - erase echo buffer) */
-int gus_queue_read_set_size(int items)
-{
- return 0;
-}
-
-/* input value: write queue size in items (each item have 8 bytes) */
-int gus_queue_write_set_size(int items)
-{
- return 0;
-}
-
-/* return value: zero if successfull */
-int gus_timer_start()
-{
- gus.timer_ctl_reg |= GF1M_TIMER1;
- __gus_outregb_slow(GF1R_TIMER_CONTROL, gus.timer_ctl_reg);
-
- gus.timer_ctl = gus.timer_ctl & ~GF1M_MASK_TIMER1;
- outportb(GF1_TIMER_CTRL, 0x04);
- outportb(GF1_TIMER_DATA, gus.timer_ctl | GF1M_START_TIMER1);
- return 0;
-}
-
-/* return value: zero if timer was stoped */
-int gus_timer_stop()
-{
- gus.timer_ctl_reg &= ~GF1M_TIMER1;
- __gus_outregb_slow(GF1R_TIMER_CONTROL, gus.timer_ctl_reg);
-
- gus.timer_ctl = gus.timer_ctl | GF1M_MASK_TIMER1;
- outportb(GF1_TIMER_CTRL, 0x04);
- outportb(GF1_TIMER_DATA, gus.timer_ctl);
- return 0;
-}
-
-/* return value: zero if setup was success */
-int gus_timer_tempo(int ticks)
-{
- unsigned int counter;
-
- /* Limit ticks per second to 1..1000 range */
- if (ticks < 1)
- ticks = 1;
- if (ticks > 1000)
- ticks = 1000;
-
- /* GF1 timer1 period is 80 usecs, 12500 times per second */
- counter = 1250000 / (ticks * gus.timer_base);
- gus.t1_multiple = 1;
- while (counter > 255) {
- counter >>= 1;
- gus.t1_multiple <<= 1;
- }
- gus.t1_countdown = gus.t1_multiple;
- __gus_outregb(GF1R_TIMER1, 256 - counter);
- return 0;
-}
-
-/* return value: zero if timer will be continue */
-int gus_timer_continue()
-{
- return gus_timer_start();
-}
-
-/* return value: zero if setup was success (default timebase = 100) */
-int gus_timer_base(int base)
-{
- gus.timer_base = base;
- return 0;
-}
-
-void gus_timer_callback(void (*timer_callback) ())
-{
- gus.timer_callback = timer_callback;
-}
-
-void gus_convert_delta(unsigned int type, unsigned char *dest,
- unsigned char *src, size_t size)
-{
- if (!(type & GUS_WAVE_DELTA))
- return;
-
- /* This doesn't depend much on wave signedness, since addition/subtraction
- do not depend on operand signedness */
- if (type & GUS_WAVE_16BIT) {
- unsigned short delta = type & GUS_WAVE_UNSIGNED ? 0x8000 : 0;
- while (size--) {
- delta = *(unsigned short *)dest = *(unsigned short *)src + delta;
- src += sizeof(unsigned short);
- dest += sizeof(unsigned short);
- }
- } else {
- unsigned char delta = type & GUS_WAVE_UNSIGNED ? 0x80 : 0;
- while (size--) {
- delta = *(unsigned char *)dest = *(unsigned char *)src + delta;
- src++;
- dest++;
- }
- }
-}
-
-int gus_dma_usage (int use)
-{
- if (gus.dma_buff)
- return -1;
- gus.transfer = __gus_transfer_io;
- return 0;
-}
-
-#endif /* DRV_ULTRA */
-
-/* ex:set ts=4: */
+++ /dev/null
-/* MikMod sound library
- (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
- complete list.
-
- This library is free software; you can redistribute it and/or modify
- it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA.
-*/
-
-/*==============================================================================
-
- $Id$
-
- libGUS-alike definitions for DOS
-
-==============================================================================*/
-
-#ifndef __DOSGUS_H__
-#define __DOSGUS_H__
-
-#include <pc.h>
-#include "dosdma.h"
-#include "dosirq.h"
-#include "libgus.h"
-
-/* Private header file for a libGUS-alike library for DOS */
-
-#define JOYSTICK_TIMER (gus.port+0x201) /* 201 */
-#define JOYSTICK_DATA (gus.port+0x201) /* 201 */
-
-#define GF1_MIDI_CTRL (gus.port+0x100) /* 3X0 */
-#define GF1_MIDI_DATA (gus.port+0x101) /* 3X1 */
-
-#define GF1_VOICESEL (gus.port+0x102) /* 3X2 */
-#define GF1_REGSEL (gus.port+0x103) /* 3X3 */
-#define GF1_DATA (gus.port+0x104) /* 3X4 */
-#define GF1_DATA_LOW (gus.port+0x104) /* 3X4 */
-#define GF1_DATA_HIGH (gus.port+0x105) /* 3X5 */
-#define GF1_IRQ_STATUS (gus.port+0x006) /* 2X6 */
-#define GF1_DRAM (gus.port+0x107) /* 3X7 */
-
-#define GF1_MIX_CTRL (gus.port+0x000) /* 2X0 */
-#define GF1_TIMER_CTRL (gus.port+0x008) /* 2X8 */
-#define GF1_TIMER_DATA (gus.port+0x009) /* 2X9 */
-#define GF1_IRQ_CTRL (gus.port+0x00B) /* 2XB */
-#define GF1_REG_CTRL (gus.port+0x00F) /* 2XF */
-
-#define GF1_REVISION (gus.port+0x506) /* 7X6 */
-
-/* The GF1 hardware clock rate */
-#define CLOCK_RATE 9878400L
-
-/* GF1 voice-independent registers */
-#define GF1R_DMA_CONTROL 0x41
-#define GF1R_DMA_ADDRESS 0x42
-#define GF1R_DRAM_LOW 0x43
-#define GF1R_DRAM_HIGH 0x44
-
-#define GF1R_TIMER_CONTROL 0x45
-#define GF1R_TIMER1 0x46
-#define GF1R_TIMER2 0x47
-
-#define GF1R_SAMPLE_RATE 0x48
-#define GF1R_SAMPLE_CONTROL 0x49
-
-#define GF1R_JOYSTICK 0x4B
-#define GF1R_RESET 0x4C
-
-/* GF1 voice-specific registers */
-#define GF1R_VOICE_CONTROL 0x00
-#define GF1R_FREQUENCY 0x01
-#define GF1R_START_HIGH 0x02
-#define GF1R_START_LOW 0x03
-#define GF1R_END_HIGH 0x04
-#define GF1R_END_LOW 0x05
-#define GF1R_VOLUME_RATE 0x06
-#define GF1R_VOLUME_START 0x07
-#define GF1R_VOLUME_END 0x08
-#define GF1R_VOLUME 0x09
-#define GF1R_ACC_HIGH 0x0a
-#define GF1R_ACC_LOW 0x0b
-#define GF1R_BALANCE 0x0c
-#define GF1R_VOLUME_CONTROL 0x0d
-#define GF1R_VOICES 0x0e
-#define GF1R_IRQ_SOURCE 0x0f
-
-/* Add this to above registers for reading */
-#define GF1R_READ_MASK 0x80
-
-/* MIDI */
-#define GF1M_MIDI_RESET 0x03
-#define GF1M_MIDI_ENABLE_XMIT 0x20
-#define GF1M_MIDI_ENABLE_RCV 0x80
-
-#define GF1M_MIDI_RCV_FULL 0x01
-#define GF1M_MIDI_XMIT_EMPTY 0x02
-#define GF1M_MIDI_FRAME_ERR 0x10
-#define GF1M_MIDI_OVERRUN 0x20
-#define GF1M_MIDI_IRQ_PEND 0x80
-
-/* Joystick */
-#define GF1M_JOY_POSITION 0x0f
-#define GF1M_JOY_BUTTONS 0xf0
-
-/* GF1_IRQ_STATUS (port 2X6) */
-#define GF1M_IRQ_MIDI_TX 0x01 /* pending MIDI xmit IRQ */
-#define GF1M_IRQ_MIDI_RX 0x02 /* pending MIDI recv IRQ */
-#define GF1M_IRQ_TIMER1 0x04 /* general purpose timer */
-#define GF1M_IRQ_TIMER2 0x08 /* general purpose timer */
-#define GF1M_IRQ_WAVETABLE 0x20 /* pending wavetable IRQ */
-#define GF1M_IRQ_ENVELOPE 0x40 /* pending volume envelope IRQ */
-#define GF1M_IRQ_DMA_COMPLETE 0x80 /* pending dma transfer complete IRQ */
-
-/* GF1_MIX_CTRL (port 2X0) */
-#define GF1M_MIXER_NO_LINE_IN 0x01 /* 0: enable */
-#define GF1M_MIXER_NO_OUTPUT 0x02 /* 0: enable */
-#define GF1M_MIXER_MIC_IN 0x04 /* 1: enable */
-#define GF1M_MIXER_GF1_IRQ 0x08 /* 1: enable */
-#define GF1M_GF1_COMBINED_IRQ 0x10 /* 1: IRQ1 == IRQ2 */
-#define GF1M_MIDI_LOOPBACK 0x20 /* 1: enable loop back */
-#define GF1M_CONTROL_SELECT 0x40 /* 0: DMA latches; 1: IRQ latches */
-
-/* Timer data register (2X9) */
-#define GF1M_START_TIMER1 0x01
-#define GF1M_START_TIMER2 0x02
-#define GF1M_MASK_TIMER1 0x20
-#define GF1M_MASK_TIMER2 0x40
-#define GF1M_TIMER_CLRIRQ 0x80
-
-/* IRQ/DMA control register (2XB) */
-#define GF1M_IRQ_EQUAL 0x40
-#define GF1M_DMA_EQUAL 0x40
-
-/* (0x41) DMA control register bits */
-#define GF1M_DMAR_ENABLE 0x01 /* 1: go */
-#define GF1M_DMAR_READ 0x02 /* 1: read (->RAM), 0: write (->DRAM) */
-#define GF1M_DMAR_CHAN16 0x04 /* 1: 16 bit, 0: 8 bit DMA channel */
-#define GF1M_DMAR_RATE 0x18 /* 00: fast, 11: slow */
-#define GF1M_DMAR_IRQ_ENABLE 0x20 /* 1: enable */
-#define GF1M_DMAR_IRQ_PENDING 0x40 /* R: DMA irq pending */
-#define GF1M_DMAR_DATA16 0x40 /* W: 0: 8 bits; 1: 16 bits per sample */
-#define GF1M_DMAR_TOGGLE_SIGN 0x80 /* W: 1: invert high bit */
-
-/* DMA transfer rate divisors */
-#define GF1M_DMAR_RATE0 0x00 /* Fastest DMA xfer (~650khz) */
-#define GF1M_DMAR_RATE1 0x08 /* fastest / 2 */
-#define GF1M_DMAR_RATE2 0x10 /* fastest / 4 */
-#define GF1M_DMAR_RATE3 0x18 /* Slowest DMA xfer (fastest / 8) */
-
-/* (0x45) Timer Control */
-#define GF1M_TIMER1 0x04 /* Enable timer 1 IRQ */
-#define GF1M_TIMER2 0x08 /* Enable timer 2 IRQ */
-
-/* (0x49) Sampling (ADC) control register */
-#define GF1M_DMAW_ENABLE 0x01 /* 1: Start sampling */
-#define GF1M_DMAW_MODE 0x02 /* 0: mono, 1: stereo */
-#define GF1M_DMAW_CHAN16 0x04 /* 0: 8 bit, 1: 16 bit */
-#define GF1M_DMAW_IRQ_ENABLE 0x20 /* 1: enable IRQ */
-#define GF1M_DMAW_IRQ_PENDING 0x40 /* 1: irq pending */
-#define GF1M_DMAW_TOGGLE_SIGN 0x80 /* 1: invert sign bit */
-
-/* (0x4C) GF1 reset register */
-#define GF1M_MASTER_RESET 0x01 /* 0: hold in reset */
-#define GF1M_OUTPUT_ENABLE 0x02 /* 1: enable output */
-#define GF1M_MASTER_IRQ 0x04 /* 1: master IRQ enable */
-
-/* (0x0,0x80) Voice control register - GF1R_VOICE_CONTROL */
-#define GF1VC_STOPPED 0x01 /* 1: voice has stopped */
-#define GF1VC_STOP 0x02 /* 1: stop voice */
-#define GF1VC_DATA16 0x04 /* 0: 8 bit, 1: 16 bit */
-#define GF1VC_LOOP_ENABLE 0x08 /* 1: enable */
-#define GF1VC_BI_LOOP 0x10 /* 1: bi directional looping */
-#define GF1VC_IRQ 0x20 /* 1: enable voice's wave irq */
-#define GF1VC_BACKWARD 0x40 /* 0: increasing, 1: decreasing */
-#define GF1VC_IRQ_PENDING 0x80 /* 1: wavetable irq pending */
-
-/* (0x01,0x81) Frequency control */
-/* Bit 0 - Unused */
-/* Bits 1-9 - Fractional portion */
-/* Bits 10-15 - Integer portion */
-
-/* (0x02,0x82) Accumulator start address - GF1R_START_HIGH */
-/* Bits 0-11 - HIGH 12 bits of address */
-/* Bits 12-15 - Unused */
-
-/* (0x03,0x83) Accumulator start address - GF1R_START_LOW */
-/* Bits 0-4 - Unused */
-/* Bits 5-8 - Fractional portion */
-/* Bits 9-15 - Low 7 bits of integer portion */
-
-/* (0x04,0x84) Accumulator end address - GF1R_END_HIGH */
-/* Bits 0-11 - HIGH 12 bits of address */
-/* Bits 12-15 - Unused */
-
-/* (0x05,0x85) Accumulator end address - GF1R_END_LOW */
-/* Bits 0-4 - Unused */
-/* Bits 5-8 - Fractional portion */
-/* Bits 9-15 - Low 7 bits of integer portion */
-
-/* (0x06,0x86) Volume Envelope control register - GF1R_VOLUME_RATE */
-#define GF1VL_RATE_MANTISSA 0x3f
-#define GF1VL_RATE_RANGE 0xC0
-
-/* (0x07,0x87) Volume envelope start - GF1R_VOLUME_START */
-#define GF1VL_START_MANT 0x0F
-#define GF1VL_START_EXP 0xF0
-
-/* (0x08,0x88) Volume envelope end - GF1R_VOLUME_END */
-#define GF1VL_END_MANT 0x0F
-#define GF1VL_END_EXP 0xF0
-
-/* (0x09,0x89) Current volume register - GF1R_VOLUME */
-/* Bits 0-3 - Unused */
-/* Bits 4-11 - Mantissa of current volume */
-/* Bits 10-15 - Exponent of current volume */
-
-/* (0x0A,0x8A) Accumulator value (high) */
-/* Bits 0-12 - HIGH 12 bits of current position (a19-a7) */
-
-/* (0x0B,0x8B) Accumulator value (low) */
-/* Bits 0-8 - Fractional portion */
-/* Bits 9-15 - Integer portion of low adress (a6-a0) */
-
-/* (0x0C,0x8C) Pan (balance) position */
-/* Bits 0-3 - Balance position 0=full left, 0x0f=full right */
-
-/* (0x0D,0x8D) Volume control register - GF1R_VOLUME_CONTROL */
-#define GF1VL_STOPPED 0x01 /* volume has stopped */
-#define GF1VL_STOP 0x02 /* stop volume */
-#define GF1VL_ROLLOVER 0x04 /* Roll PAST end & gen IRQ */
-#define GF1VL_LOOP_ENABLE 0x08 /* 1: enable */
-#define GF1VL_BI_LOOP 0x10 /* 1: bi directional looping */
-#define GF1VL_IRQ 0x20 /* 1: enable voice's volume irq */
-#define GF1VL_BACKWARD 0x40 /* 0: increasing, 1: decreasing */
-#define GF1VL_IRQ_PENDING 0x80 /* 1: wavetable irq pending */
-
-/* (0x0E,0x8E) Number of active voices */
-/* Bits 0-5 - Number of active voices - 1 */
-
-/* (0x0F,0x8F) Sources of IRQs */
-/* Bits 0-4 - interrupting voice number */
-/* Bit 5 - Always a 1 */
-#define GF1IRQ_VOLUME 0x40 /* individual voice irq bit */
-#define GF1IRQ_WAVE 0x80 /* individual waveform irq bit */
-
-/* Commands are pooled and executed ON TIMER (1st timer) interrupt.
- * Currently there is a limit on the number of commands that you can
- * issue between gus_do_flush (...); this should not be an issue however
- * because each voice has a limited (little) set of parameters that
- * you can change (freq, vol, pan... what else?)
- *
- * The pool is a pseudo-CPU code that gets executed once per timer interrupt.
- */
-
-/* Below are definitions for commands placed in GUS command pool */
-#define PCMD_NOP 0x00 /* Traditionally ... */
-#define PCMD_VOICE 0x01 /* +B: select voice */
-#define PCMD_START 0x02 /* +L: start voice */
-#define PCMD_STOP 0x03 /* stop voice */
-#define PCMD_FREQ 0x04 /* +W: set frequence */
-#define PCMD_VOLUME 0x05 /* +W: set volume */
-#define PCMD_VOLUME_PREPARE 0x06 /* +W: prepare to set volume on (soon to follow) kick */
-#define PCMD_PAN 0x07 /* +B: set panning */
-#define PCMD_OFFSET 0x08 /* +L: set DRAM offset */
-#define PCMD_STOP_LOOP 0x09 /* stop looping */
-
-#define GUS_VOLCHANGE_RAMP 0x20 /* Volume change ramp speed */
-
-/* Definition for the boolean type */
-typedef unsigned char boolean;
-/* Prototype for functions that do block transfers to GUS DRAM:
- flags can contain any of the following bits:
- GUS_WAVE_16BIT - sample is 16-bit
- GUS_WAVE_UNSIGNED - do not invert sign bit while downloading
- */
-typedef void (*__gus_transfer_func) (unsigned long address,
- unsigned char *source,
- unsigned long size, int flags);
-typedef void (*__gus_callback) ();
-typedef void (*__gus_callback_3) (unsigned int, unsigned int, unsigned int);
-
-/* Structure used to keep track of all on-board GUS memory */
-typedef struct __struct_gus_mcb {
- struct __struct_gus_mcb *next; /* Next MCB in chain */
- struct __struct_gus_mcb *prev; /* Previous MCB in chain */
- unsigned int addr; /* GUS DRAM address */
- unsigned int size; /* Memory block size */
- int free; /* 1: block is free */
-} __gus_mcb;
-
-/* Structure defining overall GUS state/information */
-typedef struct __gus_state_s {
- unsigned int port; /* Base I/O port (0x220, 0x240, ...) */
- unsigned int irq[2]; /* GF1 IRQ and MIDI IRQ */
- unsigned int dma[2]; /* Play / record DMA */
- unsigned int ram; /* Memory size (K), i.e. 256, 1024 etc */
- unsigned int version; /* GUS version (see GUS_CARD_VERSION_XXX in libgus.h */
- unsigned int freq; /* Current mixing frequency */
- unsigned int voices; /* Active voices (14-32) */
- unsigned int dynmask; /* Dynamically allocated voices mask */
- unsigned int timer_base; /* The relative timer speed in percents (def: 100) */
- volatile unsigned int t1_ticks; /* Incremented per each timer1 tick */
- volatile unsigned int t2_ticks; /* Incremented per each timer2 tick */
- volatile unsigned int t1_countdown; /* t1_callback is called when this reaches zero */
- volatile unsigned int t2_countdown; /* t2_callback is called when this reaches zero */
- unsigned int t1_multiple; /* Timer1 handler is called once per such many ticks */
- unsigned int t2_multiple; /* Timer2 handler is called once per such many ticks */
- struct irq_handle *gf1_irq; /* The interrupt handler for GF1 events */
- dma_buffer *dma_buff; /* Pre-allocated DMA buffer */
- __gus_callback dma_callback; /* Routine called at end of DMA transfers */
- __gus_callback t1_callback; /* Routine called on Timer1 events */
- __gus_callback t2_callback; /* Routine called on Timer1 events */
- __gus_callback timer_callback; /* Called once per TEMPO ticks */
- __gus_callback_3 wt_callback; /* Routine called on WaveTable events */
- __gus_callback_3 vl_callback; /* Routine called on Volume ramp events */
- __gus_mcb *mcb; /* Chained list of memory control blocks */
- __gus_transfer_func transfer; /* Best working function for DRAM transfer */
- gus_instrument_t *instr; /* The list of registered instruments */
- unsigned short mixer; /* Current mixer register state */
- unsigned char dma_rate; /* One of GF1M_DMAR_RATEX constants defined above */
- unsigned char timer_ctl; /* Timer control register value (2x8/2x9) */
- unsigned char timer_ctl_reg; /* Timer control register value (GF1/0x45) */
- boolean ok; /* Is the information below okay? */
- boolean open; /* 1 if between gus_open() and gus_close() */
- boolean ics; /* Is it equipped with an ICS mixer? */
- boolean ics_flipped; /* rev 5 (3.7) has flipped R/L mixer */
- boolean codec; /* Is it equipped with a GUS MAX codec? */
- boolean interwave; /* GUS InterWave card */
- volatile boolean dma_active; /* DMA is transferring data */
- volatile boolean cmd_pool_ready; /* Flush cmd_pool during timer interrupt */
- unsigned char cmd_voice; /* Pool selection index cache */
- unsigned int cmd_pool_top; /* Command pool top */
- unsigned char *cmd_pool; /* Async commands pool */
- /* The following data is for private use only by interrupt routines! */
- gus_wave_t *cur_wave[32]; /* Currently played waves */
- boolean voice_kick[32]; /* Kick wave on next volume ramp IRQ */
- unsigned int kick_offs[32]; /* Sample start position on kick */
- unsigned short cur_vol[32]; /* Current voice volumes */
- unsigned int cur_voice; /* Current voice */
- unsigned int eow_ignore; /* Temp ignore end-of-wave IRQ for these voices */
-} __gus_state;
-
-extern __gus_state gus;
-extern void __gus_delay();
-
-static unsigned long __gus_convert_addr16(unsigned long address)
-{
- return ((address & 0x0003ffff) >> 1) | (address & ~0x0003ffff);
-}
-
-/* The XXX_slow routines cannot be used outside IRQ handler! */
-static inline void __gus_outregb_slow(unsigned char reg, unsigned char value)
-{
- outportb(GF1_REGSEL, reg);
- outportb(GF1_DATA_HIGH, value);
- __gus_delay();
- outportb(GF1_DATA_HIGH, value);
-}
-
-static inline void __gus_outregw_slow(unsigned char reg, unsigned short value)
-{
- outportb(GF1_REGSEL, reg);
- outportw(GF1_DATA, value);
- __gus_delay();
- outportw(GF1_DATA, value);
-}
-
-static inline void __gus_outregb(unsigned char reg, unsigned char value)
-{
- outportb(GF1_REGSEL, reg);
- outportb(GF1_DATA_HIGH, value);
-}
-
-static inline void __gus_outregw(unsigned char reg, unsigned short value)
-{
- outportb(GF1_REGSEL, reg);
- outportw(GF1_DATA, value);
-}
-
-static inline unsigned char __gus_inregb(unsigned char reg)
-{
- if (reg < 0x10)
- reg |= GF1R_READ_MASK;
- outportb(GF1_REGSEL, reg);
- return inportb(GF1_DATA_HIGH);
-}
-
-static inline unsigned short __gus_inregw(unsigned char reg)
-{
- if (reg < 0x10)
- reg |= GF1R_READ_MASK;
- outportb(GF1_REGSEL, reg);
- return inportw(GF1_DATA);
-}
-
-static inline void __gus_set_dram_address(unsigned int address)
-{
- __gus_outregb(GF1R_DRAM_HIGH, address >> 16);
- __gus_outregw(GF1R_DRAM_LOW, address);
-}
-
-static inline unsigned char __gus_peek(unsigned int address)
-{
- __gus_set_dram_address(address);
- return inportb(GF1_DRAM);
-}
-
-static inline void __gus_poke(unsigned int address, unsigned char value)
-{
- __gus_set_dram_address(address);
- outportb(GF1_DRAM, value);
-}
-
-static inline void __gus_select_voice(unsigned char voice)
-{
- outportb(GF1_VOICESEL, voice);
-}
-
-static inline void __gus_set_current(unsigned char mode,
- unsigned long address)
-{
- if (mode & GF1VC_DATA16)
- address = __gus_convert_addr16(address);
- __gus_outregw_slow(GF1R_ACC_HIGH, address >> 11);
- __gus_outregw_slow(GF1R_ACC_LOW, address << 5);
-}
-
-static inline void __gus_set_loop_start(unsigned char mode,
- unsigned long address)
-{
- if (mode & GF1VC_DATA16)
- address = __gus_convert_addr16(address);
- __gus_outregw_slow(GF1R_START_HIGH, address >> 11);
- __gus_outregw_slow(GF1R_START_LOW, address << 5);
-}
-
-static inline void __gus_set_loop_end(unsigned char mode,
- unsigned long address)
-{
- address--;
- if (mode & GF1VC_DATA16)
- address = __gus_convert_addr16(address);
- __gus_outregw_slow(GF1R_END_HIGH, address >> 11);
- __gus_outregw_slow(GF1R_END_LOW, address << 5);
-}
-
-static inline void __gus_mixer_output(boolean state)
-{
- if (state)
- gus.mixer &= ~GF1M_MIXER_NO_OUTPUT;
- else
- gus.mixer |= GF1M_MIXER_NO_OUTPUT;
- outportb(GF1_MIX_CTRL, gus.mixer);
- /* Dummy read to avoid touching DMA latches */
- __gus_inregb(GF1R_BALANCE);
-}
-
-/* Inline routines for working with command pools */
-
-/* WARNING: no bounds checking due to performance reasons */
-#define __POOL_VALUE(type,value) \
- *((unsigned type *)&gus.cmd_pool [gus.cmd_pool_top]) = value; \
- gus.cmd_pool_top += sizeof (type);
-
-static inline void __pool_command(unsigned char command)
-{
- __POOL_VALUE(char, command);
-}
-
-static inline void __pool_command_b(unsigned char command, unsigned char arg)
-{
- __POOL_VALUE(char, command);
- __POOL_VALUE(char, arg);
-}
-
-static inline void __pool_command_w(unsigned char command, unsigned short arg)
-{
- __POOL_VALUE(char, command);
- __POOL_VALUE(short, arg);
-}
-
-static inline void __pool_command_l(unsigned char command, unsigned long arg)
-{
- __POOL_VALUE(char, command);
- __POOL_VALUE(long, arg);
-}
-
-static inline void __pool_select_voice(unsigned char voice)
-{
- if (gus.cmd_voice != voice)
- __pool_command_b(PCMD_VOICE, gus.cmd_voice = voice);
-}
-
-#undef __POOL_VALUE
-
-#ifdef DEBUG
-/* Debug dump of GUS DRAM heap */
-extern void __gus_mem_dump();
-#endif
-
-#endif /* __DOSGUS_H__ */
-
-/* ex:set ts=4: */
+++ /dev/null
-/*
- Implementation of IRQ routines on DOS
- Copyright (C) 1999 by Andrew Zabolotny, <bit@eltech.ru>
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free
- Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "dosirq.h"
-
-#include <dpmi.h>
-#include <go32.h>
-#include <dos.h>
-#include <sys/nearptr.h>
-#include <malloc.h>
-#include <string.h>
-#include "mikmod.h" /* for MikMod_malloc() & co */
-
-unsigned int __irq_stack_size = 0x4000;
-unsigned int __irq_stack_count = 1;
-
-static void __int_stub_template (void)
-{
-/* *INDENT-OFF* */
- asm(" pushal\n"
- " pushl %ds\n"
- " pushl %es\n"
- " pushl %fs\n"
- " pushl %gs\n"
- " movw $0x1234,%ax\n" /* Get DPMI data selector */
- " movw %ax,%ds\n" /* Set DS and ES to data selector */
- " movw %ax,%es\n"
- " movl $0x12345678,%ebx\n" /* Interrupt stack top */
- " movl (%ebx),%ecx\n"
- " movl %ecx,%edx\n"
- " subl $0x12345678,%ecx\n" /* Subtract irq_stack_count */
- " movl %ecx,(%ebx)\n"
- " movw %ss,%si\n" /* Save old SS:ESP */
- " movl %esp,%edi\n"
- " movl %edx,%esp\n" /* Set SS:ESP to interrupt stack */
- " movw %ax,%ss\n"
- " pushl %esi\n"
- " pushl %edi\n"
- " pushl %ebx\n"
- " pushl %edx\n"
- " call 1f\n" /* Call user interrupt handler */
- "1: popl %edx\n"
- " popl %ebx\n"
- " movl %edx,(%ebx)\n"
- " popl %edi\n"
- " popl %esi\n"
- " movl %edi,%esp\n" /* Restore old SS:ESP */
- " movw %si,%ss\n"
- " popl %gs\n"
- " popl %fs\n"
- " popl %es\n"
- " popl %ds\n"
- " popal\n"
- " iret\n");
-/* *INDENT-ON* */
-}
-
-#include <stdio.h>
-
-static int _allocate_iret_wrapper(_go32_dpmi_seginfo * info)
-{
- unsigned char *irqtpl = (unsigned char *)__int_stub_template;
- unsigned char *irqend, *irqwrapper, *tmp;
- __dpmi_meminfo handler_info;
- unsigned int wrappersize;
-
- /* First, skip until pushal */
- while (*irqtpl != 0x60)
- irqtpl++;
- /* Now find the iret */
- irqend = irqtpl;
- while (*irqend++ != 0xcf);
-
- wrappersize = 4 + __irq_stack_size * __irq_stack_count + 4 +
- ((long)irqend - (long)irqtpl);
- irqwrapper = (unsigned char *) MikMod_malloc(wrappersize);
- /* Lock the wrapper */
- handler_info.address = __djgpp_base_address + (unsigned long)irqwrapper;
- handler_info.size = wrappersize;
- if (__dpmi_lock_linear_region(&handler_info)) {
- MikMod_free(irqwrapper);
- return -1;
- }
-
- /* First comes the interrupt wrapper size */
- *(unsigned long *)irqwrapper = wrappersize;
-
- /* Next comes the interrupt stack */
- tmp = irqwrapper + 4 + __irq_stack_size * __irq_stack_count;
-
- /* The following dword is interrupt stack pointer */
- *((void **)tmp) = tmp;
- tmp += 4;
-
- /* Now comes the interrupt wrapper itself */
- memcpy(tmp, irqtpl, irqend - irqtpl);
- *(unsigned short *)(tmp + 9) = _my_ds();
- *(unsigned long *)(tmp + 16) = (unsigned long)tmp - 4;
- *(unsigned long *)(tmp + 26) = __irq_stack_size;
- *(unsigned long *)(tmp + 46) =
- info->pm_offset - (unsigned long)(tmp + 50);
-
- info->pm_offset = (unsigned long)tmp;
- info->pm_selector = _my_cs();
-
- return 0;
-}
-
-static void _free_iret_wrapper(_go32_dpmi_seginfo * info)
-{
- __dpmi_meminfo handler_info;
-
- info->pm_offset -= 4 + __irq_stack_size * __irq_stack_count + 4;
-
- handler_info.address = __djgpp_base_address + info->pm_offset;
- handler_info.size = *(unsigned long *)info->pm_offset;
- __dpmi_unlock_linear_region(&handler_info);
-
- MikMod_free((void *)info->pm_offset);
-}
-
-struct irq_handle *irq_hook(int irqno, void (*handler)(), unsigned long size)
-{
- int interrupt;
- struct irq_handle *irq;
- __dpmi_version_ret version;
- __dpmi_meminfo handler_info, struct_info;
- _go32_dpmi_seginfo info;
- unsigned long old_sel, old_ofs;
-
- __dpmi_get_version(&version);
- if (irqno < 8)
- interrupt = version.master_pic + irqno;
- else
- interrupt = version.slave_pic + (irqno - 8);
-
- if (_go32_dpmi_get_protected_mode_interrupt_vector(interrupt, &info))
- return NULL;
-
- old_sel = info.pm_selector;
- old_ofs = info.pm_offset;
-
- info.pm_offset = (unsigned long)handler;
- if (_allocate_iret_wrapper(&info))
- return NULL;
-
- /* Lock the interrupt handler in memory */
- handler_info.address = __djgpp_base_address + (unsigned long)handler;
- handler_info.size = size;
- if (__dpmi_lock_linear_region(&handler_info)) {
- _free_iret_wrapper(&info);
- return NULL;
- }
-
- irq = (struct irq_handle *) MikMod_malloc(sizeof(struct irq_handle));
- irq->c_handler = handler;
- irq->handler_size = size;
- irq->handler = info.pm_offset;
- irq->prev_selector = old_sel;
- irq->prev_offset = old_ofs;
- irq->int_num = interrupt;
- irq->irq_num = irqno;
- irq->pic_base = irqno < 8 ? PIC1_BASE : PIC2_BASE;
-
- struct_info.address = __djgpp_base_address + (unsigned long)irq;
- struct_info.size = sizeof(struct irq_handle);
- if (__dpmi_lock_linear_region(&struct_info)) {
- MikMod_free(irq);
- __dpmi_unlock_linear_region(&handler_info);
- _free_iret_wrapper(&info);
- return NULL;
- }
-
- _go32_dpmi_set_protected_mode_interrupt_vector(interrupt, &info);
-
- irq->pic_mask = irq_state(irq);
- return irq;
-}
-
-void irq_unhook(struct irq_handle *irq)
-{
- _go32_dpmi_seginfo info;
- __dpmi_meminfo mem_info;
-
- if (!irq)
- return;
-
- /* Restore the interrupt vector */
- irq_disable(irq);
- info.pm_offset = irq->prev_offset;
- info.pm_selector = irq->prev_selector;
- _go32_dpmi_set_protected_mode_interrupt_vector(irq->int_num, &info);
-
- /* Unlock the interrupt handler */
- mem_info.address = __djgpp_base_address + (unsigned long)irq->c_handler;
- mem_info.size = irq->handler_size;
- __dpmi_unlock_linear_region(&mem_info);
-
- /* Unlock the irq_handle structure */
- mem_info.address = __djgpp_base_address + (unsigned long)irq;
- mem_info.size = sizeof(struct irq_handle);
- __dpmi_unlock_linear_region(&mem_info);
-
- info.pm_offset = irq->handler;
- _free_iret_wrapper(&info);
-
- /* If IRQ was enabled before we hooked, restore enabled state */
- if (irq->pic_mask)
- irq_enable(irq);
- else
- irq_disable(irq);
-
- MikMod_free(irq);
-}
-
-/*---------------------------------------------- IRQ detection mechanism -----*/
-static struct irq_handle *__irqs[16];
-static int (*__irq_confirm) (int irqno);
-static volatile unsigned int __irq_mask;
-static volatile unsigned int __irq_count[16];
-
-#define DECLARE_IRQ_HANDLER(irqno) \
-static void __irq##irqno##_handler () \
-{ \
- if (irq_check (__irqs [irqno]) && __irq_confirm (irqno)) \
- { \
- __irq_count [irqno]++; \
- __irq_mask |= (1 << irqno); \
- } \
- irq_ack (__irqs [irqno]); \
-}
-
-/* *INDENT-OFF* */
-DECLARE_IRQ_HANDLER(0)
-DECLARE_IRQ_HANDLER(1)
-DECLARE_IRQ_HANDLER(2)
-DECLARE_IRQ_HANDLER(3)
-DECLARE_IRQ_HANDLER(4)
-DECLARE_IRQ_HANDLER(5)
-DECLARE_IRQ_HANDLER(6)
-DECLARE_IRQ_HANDLER(7)
-DECLARE_IRQ_HANDLER(8)
-DECLARE_IRQ_HANDLER(9)
-DECLARE_IRQ_HANDLER(10)
-DECLARE_IRQ_HANDLER(11)
-DECLARE_IRQ_HANDLER(12)
-DECLARE_IRQ_HANDLER(13)
-DECLARE_IRQ_HANDLER(14)
-DECLARE_IRQ_HANDLER(15)
-/* *INDENT-ON* */
-
-static void (*__irq_handlers[16]) () = {
- __irq0_handler, __irq1_handler, __irq2_handler, __irq3_handler,
- __irq4_handler, __irq5_handler, __irq6_handler, __irq7_handler,
- __irq8_handler, __irq9_handler, __irq10_handler, __irq11_handler,
- __irq12_handler, __irq13_handler, __irq14_handler, __irq15_handler};
-
-void irq_detect_start(unsigned int irqs, int (*irq_confirm) (int irqno))
-{
- int i;
-
- __irq_mask = 0;
- __irq_confirm = irq_confirm;
- memset(&__irqs, 0, sizeof(__irqs));
- memset((void *) &__irq_count, 0, sizeof(__irq_count));
-
- /* Hook all specified IRQs */
- for (i = 1; i <= 15; i++)
- if (irqs & (1 << i)) {
- __irqs[i] = irq_hook(i, __irq_handlers[i], 200);
- /* Enable the interrupt */
- irq_enable(__irqs[i]);
- }
- /* Enable IRQ2 if we need at least one IRQ above 7 */
- if (irqs & 0xff00)
- _irq_enable(2);
-}
-
-void irq_detect_end()
-{
- int i;
- for (i = 15; i >= 1; i--)
- if (__irqs[i])
- irq_unhook(__irqs[i]);
-}
-
-int irq_detect_get(int irqno, unsigned int *irqmask)
-{
- int oldirq = disable();
- int count = __irq_count[irqno];
- *irqmask = __irq_mask;
- __irq_mask = 0;
- if (oldirq)
- enable();
- return count;
-}
-
-void irq_detect_clear()
-{
- int oldirq = disable();
- memset((void *) &__irq_count, 0, sizeof(__irq_count));
- __irq_mask = 0;
- if (oldirq)
- enable();
-}
-
-/* ex:set ts=4: */
+++ /dev/null
-/*
- Interface for IRQ routines on DOS
- Copyright (C) 1999 by Andrew Zabolotny, <bit@eltech.ru>
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free
- Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef __DOSIRQ_H__
-#define __DOSIRQ_H__
-
-#include <pc.h>
-
-#define PIC1_BASE 0x20 /* PIC1 base */
-#define PIC2_BASE 0xA0 /* PIC2 base */
-
-struct irq_handle {
- void (*c_handler) (); /* The real interrupt handler */
- unsigned long handler_size; /* The size of interrupt handler */
- unsigned long handler; /* Interrupt wrapper address */
- unsigned long prev_selector; /* Selector of previous handler */
- unsigned long prev_offset; /* Offset of previous handler */
- unsigned char irq_num; /* IRQ number */
- unsigned char int_num; /* Interrupt number */
- unsigned char pic_base; /* PIC base (0x20 or 0xA0) */
- unsigned char pic_mask; /* Old PIC mask state */
-};
-
-/* Return the enabled state for specific IRQ */
-static inline unsigned char irq_state(struct irq_handle * irq)
-{
- return ((~inportb(irq->pic_base + 1)) & (0x01 << (irq->irq_num & 7)));
-}
-
-/* Acknowledge the end of interrupt */
-static inline void _irq_ack(int irqno)
-{
- outportb(irqno > 7 ? PIC2_BASE : PIC1_BASE, 0x60 | (irqno & 7));
- /* For second controller we also should acknowledge first controller */
- if (irqno > 7)
- outportb(PIC1_BASE, 0x20); /* 0x20, 0x62? */
-}
-
-/* Acknowledge the end of interrupt */
-static inline void irq_ack(struct irq_handle * irq)
-{
- outportb(irq->pic_base, 0x60 | (irq->irq_num & 7));
- /* For second controller we also should acknowledge first controller */
- if (irq->pic_base != PIC1_BASE)
- outportb(PIC1_BASE, 0x20); /* 0x20, 0x62? */
-}
-
-/* Mask (disable) the particular IRQ given his ordinal */
-static inline void _irq_disable(int irqno)
-{
- unsigned int port_no = (irqno < 8 ? PIC1_BASE : PIC2_BASE) + 1;
- outportb(port_no, inportb(port_no) | (1 << (irqno & 7)));
-}
-
-/* Unmask (enable) the particular IRQ given its ordinal */
-static inline void _irq_enable(int irqno)
-{
- unsigned int port_no = (irqno < 8 ? PIC1_BASE : PIC2_BASE) + 1;
- outportb(port_no, inportb(port_no) & ~(1 << (irqno & 7)));
-}
-
-/* Mask (disable) the particular IRQ given its irq_handle structure */
-static inline void irq_disable(struct irq_handle * irq)
-{
- outportb(irq->pic_base + 1,
- inportb(irq->pic_base + 1) | (1 << (irq->irq_num & 7)));
-}
-
-/* Unmask (enable) the particular IRQ given its irq_handle structure */
-static inline void irq_enable(struct irq_handle * irq)
-{
- outportb(irq->pic_base + 1,
- inportb(irq->pic_base + 1) & ~(1 << (irq->irq_num & 7)));
-}
-
-/* Check if a specific IRQ is pending: return 0 is no */
-static inline int irq_check(struct irq_handle * irq)
-{
- outportb(irq->pic_base, 0x0B); /* Read IRR vector */
- return (inportb(irq->pic_base) & (1 << (irq->irq_num & 7)));
-}
-
-/* Hook a specific IRQ; NOTE: IRQ is disabled upon return, irq_enable() it */
-extern struct irq_handle *irq_hook(int irqno, void (*handler)(),
- unsigned long size);
-/* Unhook a previously hooked IRQ */
-extern void irq_unhook(struct irq_handle * irq);
-/* Start IRQ detection process (IRQ list is given with irq mask) */
-/* irq_confirm should return "1" if the IRQ really comes from the device */
-extern void irq_detect_start(unsigned int irqs,
- int (*irq_confirm) (int irqno));
-/* Finish IRQ detection process */
-extern void irq_detect_end();
-/* Get the count of specific irqno that happened */
-extern int irq_detect_get(int irqno, unsigned int *irqmask);
-/* Clear IRQ counters */
-extern void irq_detect_clear();
-
-/* The size of interrupt stack */
-extern unsigned int __irq_stack_size;
-/* The number of nested interrupts that can be handled */
-extern unsigned int __irq_stack_count;
-
-#endif /* __DOSIRQ_H__ */
-
-/* ex:set ts=4: */
+++ /dev/null
-/* MikMod sound library
- (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
- complete list.
-
- This library is free software; you can redistribute it and/or modify
- it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA.
-*/
-
-/*==============================================================================
-
- Sound Blaster I/O routines, common for SB8, SBPro and SB16
- Written by Andrew Zabolotny <bit@eltech.ru>
-
-==============================================================================*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef DRV_SB
-
-#include <stdlib.h>
-#include <dpmi.h>
-#include <go32.h>
-#include <dos.h>
-#include <sys/nearptr.h>
-#include <sys/farptr.h>
-#include <string.h>
-
-#include "dossb.h"
-
-/********************************************* Private variables/routines *****/
-
-__sb_state sb;
-
-/* Wait for SoundBlaster for some time */
-#if !defined(__GNUC__) || (__GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ == 0)
-# define _func_noinline volatile /* match original code */
-# define _func_noclone
-#else
-/* avoid warnings from newer gcc:
- * "function definition has qualified void return type" and
- * function return types not compatible due to 'volatile' */
-# define _func_noinline __attribute__((__noinline__))
-# if (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 5)
-# define _func_noclone
-# else
-# define _func_noclone __attribute__((__noclone__))
-# endif
-#endif
-_func_noinline
-_func_noclone
- void __sb_wait()
-{
- inportb(SB_DSP_RESET);
- inportb(SB_DSP_RESET);
- inportb(SB_DSP_RESET);
- inportb(SB_DSP_RESET);
- inportb(SB_DSP_RESET);
- inportb(SB_DSP_RESET);
-}
-
-static void sb_irq()
-{
- /* Make sure its not a spurious IRQ */
- if (!irq_check(sb.irq_handle))
- return;
-
- sb.irqcount++;
-
- /* Acknowledge DMA transfer is complete */
- if (sb.mode & SBMODE_16BITS)
- __sb_dsp_ack_dma16();
- else
- __sb_dsp_ack_dma8();
-
- /* SoundBlaster 1.x cannot do autoinit ... */
- if (sb.dspver < SBVER_20)
- __sb_dspreg_outwlh(SBDSP_DMA_PCM8, (sb.dma_buff->size >> 1) - 1);
-
- /* Send EOI */
- irq_ack(sb.irq_handle);
-
- enable();
- if (sb.timer_callback)
- sb.timer_callback();
-}
-
-static void sb_irq_end()
-{
-}
-
-static boolean __sb_reset()
-{
- /* Disable the output */
- sb_output(FALSE);
-
- /* Clear pending ints if any */
- __sb_dsp_ack_dma8();
- __sb_dsp_ack_dma16();
-
- /* Reset the DSP */
- outportb(SB_DSP_RESET, SBM_DSP_RESET);
- __sb_wait();
- __sb_wait();
- outportb(SB_DSP_RESET, 0);
-
- /* Now wait for AA coming from datain port */
- if (__sb_dsp_in() != 0xaa)
- return FALSE;
-
- /* Finally, get the DSP version */
- if ((sb.dspver = __sb_dsp_version()) == 0xffff)
- return FALSE;
- /* Check again */
- if (sb.dspver != __sb_dsp_version())
- return FALSE;
-
- return TRUE;
-}
-
-/***************************************************** SB detection stuff *****/
-
-static int __sb_irq_irqdetect(int irqno)
-{
- __sb_dsp_ack_dma8();
- return 1;
-}
-
-static void __sb_irq_dmadetect()
-{
- /* Make sure its not a spurious IRQ */
- if (!irq_check(sb.irq_handle))
- return;
-
- sb.irqcount++;
-
- /* Acknowledge DMA transfer is complete */
- if (sb.mode & SBMODE_16BITS)
- __sb_dsp_ack_dma16();
- else
- __sb_dsp_ack_dma8();
-
- /* Send EOI */
- irq_ack(sb.irq_handle);
-}
-
-static boolean __sb_detect()
-{
- /* First find the port number */
- if (!sb.port) {
- int i;
- for (i = 5; i >= 0; i--) {
- sb.port = 0x210 + i * 0x10;
- if (__sb_reset())
- break;
- }
- if (i < 0) {
- sb.port = 0;
- return FALSE;
- }
- }
-
- /* Now detect the IRQ and DMA numbers */
- if (!sb.irq) {
- unsigned int irqmask, sbirqmask, sbirqcount;
- unsigned long timer;
-
- /* IRQ can be one of 2,3,5,7,10 */
- irq_detect_start(0x04ac, __sb_irq_irqdetect);
-
- /* Prepare timeout counter */
- _farsetsel(_dos_ds);
- timer = _farnspeekl(0x46c);
-
- sbirqmask = 0;
- sbirqcount = 10; /* Emit 10 SB irqs */
-
- /* Tell SoundBlaster to emit IRQ for 8-bit transfers */
- __sb_dsp_out(SBDSP_GEN_IRQ8);
- __sb_wait();
- for (;;) {
- irq_detect_get(0, &irqmask);
- if (irqmask) {
- sbirqmask |= irqmask;
- if (!--sbirqcount)
- break;
- __sb_dsp_out(SBDSP_GEN_IRQ8);
- }
- if (_farnspeekl(0x46c) - timer >= 9) /* Wait ~1/2 secs */
- break;
- }
- if (sbirqmask)
- for (sb.irq = 15; sb.irq > 0; sb.irq--)
- if (irq_detect_get(sb.irq, &irqmask) == 10)
- break;
-
- irq_detect_end();
- if (!sb.irq)
- return FALSE;
- }
-
- /* Detect the 8-bit and 16-bit DMAs */
- if (!sb.dma8 || ((sb.dspver >= SBVER_16) && !sb.dma16)) {
- static int __dma8[] = { 0, 1, 3 };
- static int __dma16[] = { 5, 6, 7 };
- int *dma;
-
- sb_output(FALSE);
- /* Temporary hook SB IRQ */
- sb.irq_handle = irq_hook(sb.irq, __sb_irq_dmadetect, 200);
- irq_enable(sb.irq_handle);
- if (sb.irq > 7)
- _irq_enable(2);
-
- /* Start a short DMA transfer and check if IRQ happened */
- for (;;) {
- int i;
- unsigned int timer, oldcount;
-
- if (!sb.dma8)
- dma = &sb.dma8;
- else if ((sb.dspver >= SBVER_16) && !sb.dma16)
- dma = &sb.dma16;
- else
- break;
-
- for (i = 0; i < 3; i++) {
- boolean success = 1;
-
- *dma = (dma == &sb.dma8) ? __dma8[i] : __dma16[i];
- oldcount = sb.irqcount;
-
- dma_disable(*dma);
- dma_set_mode(*dma, DMA_MODE_WRITE);
- dma_clear_ff(*dma);
- dma_set_count(*dma, 2);
- dma_enable(*dma);
-
- __sb_dspreg_out(SBDSP_SET_TIMING, 206); /* 20KHz */
- if (dma == &sb.dma8) {
- sb.mode = 0;
- __sb_dspreg_outwlh(SBDSP_DMA_PCM8, 1);
- } else {
- sb.mode = SBMODE_16BITS;
- __sb_dspreg_out(SBDSP_DMA_GENERIC16, 0);
- __sb_dsp_out(0);
- __sb_dsp_out(1);
- }
-
- _farsetsel(_dos_ds);
- timer = _farnspeekl(0x46c);
-
- while (oldcount == sb.irqcount)
- if (_farnspeekl(0x46c) - timer >= 2) {
- success = 0;
- break;
- }
- dma_disable(*dma);
- if (success)
- break;
- *dma = 0;
- }
- if (!*dma)
- break;
- }
-
- irq_unhook(sb.irq_handle);
- sb.irq_handle = NULL;
- if (!sb.dma8 || ((sb.dspver >= SBVER_16) && !sb.dma16))
- return FALSE;
- }
- return TRUE;
-}
-
-/*************************************************** High-level interface *****/
-
-/* Detect whenever SoundBlaster is present and fill "sb" structure */
-boolean sb_detect()
-{
- char *env;
-
- /* Try to find the port and DMA from environment */
- env = getenv("BLASTER");
-
- while (env && *env) {
- /* Skip whitespace */
- while ((*env == ' ') || (*env == '\t'))
- env++;
- if (!*env)
- break;
-
- switch (*env++) {
- case 'A':
- case 'a':
- if (!sb.port)
- sb.port = strtol(env, &env, 16);
- break;
- case 'E':
- case 'e':
- if (!sb.aweport)
- sb.aweport = strtol(env, &env, 16);
- break;
- case 'I':
- case 'i':
- if (!sb.irq)
- sb.irq = strtol(env, &env, 10);
- break;
- case 'D':
- case 'd':
- if (!sb.dma8)
- sb.dma8 = strtol(env, &env, 10);
- break;
- case 'H':
- case 'h':
- if (!sb.dma16)
- sb.dma16 = strtol(env, &env, 10);
- break;
- default:
- /* Skip other values (H == MIDI, T == model, any other?) */
- while (*env && (*env != ' ') && (*env != '\t'))
- env++;
- break;
- }
- }
-
- /* Try to detect missing sound card parameters */
- __sb_detect();
-
- if (!sb.port || !sb.irq || !sb.dma8)
- return FALSE;
-
- if (!__sb_reset())
- return FALSE;
-
- if ((sb.dspver >= SBVER_16) && !sb.dma16)
- return FALSE;
-
- if (sb.dspver >= SBVER_PRO)
- sb.caps |= SBMODE_STEREO;
- if (sb.dspver >= SBVER_16 && sb.dma16)
- sb.caps |= SBMODE_16BITS;
- if (sb.dspver < SBVER_20)
- sb.maxfreq_mono = 22222;
- else
- sb.maxfreq_mono = 45454;
- if (sb.dspver <= SBVER_16)
- sb.maxfreq_stereo = 22727;
- else
- sb.maxfreq_stereo = 45454;
-
- sb.ok = 1;
- return TRUE;
-}
-
-/* Reset SoundBlaster */
-void sb_reset()
-{
- sb_stop_dma();
- __sb_reset();
-}
-
-/* Start working with SoundBlaster */
-boolean sb_open()
-{
- __dpmi_meminfo struct_info;
-
- if (!sb.ok)
- if (!sb_detect())
- return FALSE;
-
- if (sb.open)
- return FALSE;
-
- /* Now lock the sb structure in memory */
- struct_info.address = __djgpp_base_address + (unsigned long)&sb;
- struct_info.size = sizeof(sb);
- if (__dpmi_lock_linear_region(&struct_info))
- return FALSE;
-
- /* Hook the SB IRQ */
- sb.irq_handle = irq_hook(sb.irq, sb_irq, (long)sb_irq_end - (long)sb_irq);
- if (!sb.irq_handle) {
- __dpmi_unlock_linear_region(&struct_info);
- return FALSE;
- }
-
- /* Enable the interrupt */
- irq_enable(sb.irq_handle);
- if (sb.irq > 7)
- _irq_enable(2);
-
- sb.open++;
-
- return TRUE;
-}
-
-/* Finish working with SoundBlaster */
-boolean sb_close()
-{
- __dpmi_meminfo struct_info;
- if (!sb.open)
- return FALSE;
-
- sb.open--;
-
- /* Stop/free DMA buffer */
- sb_stop_dma();
-
- /* Unhook IRQ */
- irq_unhook(sb.irq_handle);
- sb.irq_handle = NULL;
-
- /* Unlock the sb structure */
- struct_info.address = __djgpp_base_address + (unsigned long)&sb;
- struct_info.size = sizeof(sb);
- __dpmi_unlock_linear_region(&struct_info);
-
- return TRUE;
-}
-
-/* Enable/disable stereo DSP mode */
-/* Enable/disable speaker output */
-void sb_output(boolean enable)
-{
- __sb_dsp_out(enable ? SBDSP_SPEAKER_ENA : SBDSP_SPEAKER_DIS);
-}
-
-/* Start playing from DMA buffer */
-boolean sb_start_dma(unsigned char mode, unsigned int freq)
-{
- int dmachannel = (mode & SBMODE_16BITS) ? sb.dma16 : sb.dma8;
- int dmabuffsize;
- unsigned int tc = 0; /* timing constant (<=sbpro only) */
-
- /* Stop DMA transfer if it is enabled */
- sb_stop_dma();
-
- /* Sanity check */
- if ((mode & SBMODE_MASK & sb.caps) != (mode & SBMODE_MASK))
- return FALSE;
-
- /* Check this SB can perform at requested frequency */
- if (((mode & SBMODE_STEREO) && (freq > sb.maxfreq_stereo))
- || (!(mode & SBMODE_STEREO) && (freq > sb.maxfreq_mono)))
- return FALSE;
-
- /* Check the timing constant here to avoid failing later */
- if (sb.dspver < SBVER_16) {
- /* SBpro cannot do signed transfer */
- if (mode & SBMODE_SIGNED)
- return FALSE;
-
- /* Old SBs have a different way on setting DMA timing constant */
- tc = freq;
- if (mode & SBMODE_STEREO)
- tc *= 2;
- tc = 1000000 / tc;
- if (tc > 255)
- return FALSE;
- }
-
- sb.mode = mode;
-
- /* Get a DMA buffer enough for a 1/4sec interval... 4K <= dmasize <= 32K */
- dmabuffsize = freq;
- if (mode & SBMODE_STEREO)
- dmabuffsize *= 2;
- if (mode & SBMODE_16BITS)
- dmabuffsize *= 2;
- dmabuffsize >>= 2;
- if (dmabuffsize < 4096)
- dmabuffsize = 4096;
- if (dmabuffsize > 32768)
- dmabuffsize = 32768;
- dmabuffsize = (dmabuffsize + 255) & 0xffffff00;
-
- sb.dma_buff = dma_allocate(dmachannel, dmabuffsize);
- if (!sb.dma_buff)
- return FALSE;
-
- /* Fill DMA buffer with silence */
- dmabuffsize = sb.dma_buff->size;
- if (mode & SBMODE_SIGNED)
- memset(sb.dma_buff->linear, 0, dmabuffsize);
- else
- memset(sb.dma_buff->linear, 0x80, dmabuffsize);
-
- /* Prime DMA for transfer */
- dma_start(sb.dma_buff, dmabuffsize, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
-
- /* Tell SoundBlaster to start transfer */
- if (sb.dspver >= SBVER_16) { /* SB16 */
- __sb_dspreg_outwhl(SBDSP_SET_RATE, freq);
-
- /* Start DMA->DAC transfer */
- __sb_dspreg_out(SBM_GENDAC_AUTOINIT | SBM_GENDAC_FIFO |
- ((mode & SBMODE_16BITS) ? SBDSP_DMA_GENERIC16 :
- SBDSP_DMA_GENERIC8),
- ((mode & SBMODE_SIGNED) ? SBM_GENDAC_SIGNED : 0) |
- ((mode & SBMODE_STEREO) ? SBM_GENDAC_STEREO : 0));
-
- /* Write the length of transfer */
- dmabuffsize = (dmabuffsize >> 2) - 1;
- __sb_dsp_out(dmabuffsize);
- __sb_dsp_out(dmabuffsize >> 8);
- } else {
- __sb_dspreg_out(SBDSP_SET_TIMING, 256 - tc);
- dmabuffsize = (dmabuffsize >> 1) - 1;
- if (sb.dspver >= SBVER_20) { /* SB 2.0/Pro */
- /* Set stereo mode */
- __sb_stereo((mode & SBMODE_STEREO) ? TRUE : FALSE);
- __sb_dspreg_outwlh(SBDSP_SET_DMA_BLOCK, dmabuffsize);
- if (sb.dspver >= SBVER_PRO)
- __sb_dsp_out(SBDSP_HS_DMA_DAC8_AUTO);
- else
- __sb_dsp_out(SBDSP_DMA_PCM8_AUTO);
- } else { /* Original SB */
- /* Start DMA->DAC transfer */
- __sb_dspreg_outwlh(SBDSP_DMA_PCM8, dmabuffsize);
- }
- }
-
- return TRUE;
-}
-
-/* Stop playing from DMA buffer */
-void sb_stop_dma()
-{
- if (!sb.dma_buff)
- return;
-
- if (sb.mode & SBMODE_16BITS)
- __sb_dsp_out(SBDSP_DMA_HALT16);
- else
- __sb_dsp_out(SBDSP_DMA_HALT8);
-
- dma_disable(sb.dma_buff->channel);
- dma_free(sb.dma_buff);
- sb.dma_buff = NULL;
-}
-
-/* Query current position/total size of the DMA buffer */
-void sb_query_dma(unsigned int *dma_size, unsigned int *dma_pos)
-{
- unsigned int dma_left;
- *dma_size = sb.dma_buff->size;
- /* It can happen we try to read DMA count when HI/LO bytes will be
- inconsistent */
- for (;;) {
- unsigned int dma_left_test;
- dma_clear_ff(sb.dma_buff->channel);
- dma_left_test = dma_get_count(sb.dma_buff->channel);
- dma_left = dma_get_count(sb.dma_buff->channel);
- if ((dma_left >= dma_left_test) && (dma_left - dma_left_test < 10))
- break;
- }
- *dma_pos = *dma_size - dma_left;
-}
-
-#endif /* DRV_SB */
-
-/* ex:set ts=4: */
+++ /dev/null
-/* MikMod sound library
- (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
- complete list.
-
- This library is free software; you can redistribute it and/or modify
- it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA.
-*/
-
-/*==============================================================================
-
- $Id$
-
- SoundBlaster and compatible soundcards definitions
-
-==============================================================================*/
-
-#ifndef __DOSSB_H__
-#define __DOSSB_H__
-
-#include "dosdma.h"
-#include "dosirq.h"
-
-#define SB_FM_LEFT_STATUS (sb.port + 0x00) /* (r) Left FM status */
-#define SB_FM_LEFT_REGSEL (sb.port + 0x00) /* (w) Left FM register select */
-#define SB_FM_LEFT_DATA (sb.port + 0x01) /* (w) Left FM data */
-#define SB_FM_RIGHT_STATUS (sb.port + 0x02) /* (r) Right FM status */
-#define SB_FM_RIGHT_REGSEL (sb.port + 0x02) /* (w) Right FM register select */
-#define SB_FM_RIGHT_DATA (sb.port + 0x03) /* (w) Right FM data */
-#define SB_MIXER_REGSEL (sb.port + 0x04) /* (w) Mixer register select */
-#define SB_MIXER_DATA (sb.port + 0x05) /* (rw)Mixer data */
-#define SB_DSP_RESET (sb.port + 0x06) /* (w) DSP reset */
-#define SB_FM_STATUS (sb.port + 0x08) /* (r) FM status */
-#define SB_FM_REGSEL (sb.port + 0x08) /* (w) FM register select */
-#define SB_FM_DATA (sb.port + 0x09) /* (w) FM data */
-#define SB_DSP_DATA_IN (sb.port + 0x0a) /* (r) DSP data input */
-#define SB_DSP_DATA_OUT (sb.port + 0x0c) /* (w) DSP data output */
-#define SB_DSP_DATA_OUT_STATUS (sb.port + 0x0c) /* (r) DSP data output status */
-#define SB_DSP_TIMER_IRQ (sb.port + 0x0d) /* (r) clear timer IRQ? */
-#define SB_DSP_DATA_IN_STATUS (sb.port + 0x0e) /* (r) DSP data input status */
-#define SB_DSP_DMA8_IRQ (sb.port + 0x0e) /* (r) Acknowledge 8-bit DMA transfer */
-#define SB_DSP_DMA16_IRQ (sb.port + 0x0f) /* (r) Acknowledge 16-bit DMA transfer */
-
-/* DSP commands */
-#define SBDSP_ASP_STATUS 0x03 /* ASP Status (SB16ASP) */
-#define SBDSP_STATUS_OLD 0x04 /* DSP Status (Obsolete) (SB2.0-Pro2) */
-#define SBDSP_DIRECT_DAC 0x10 /* Direct DAC, 8-bit (SB) */
-#define SBDSP_DMA_PCM8 0x14 /* DMA DAC, 8-bit (SB) */
-#define SBDSP_DMA_ADPCM2 0x16 /* DMA DAC, 2-bit ADPCM (SB) */
-#define SBDSP_DMA_ADPCM2R 0x17 /* DMA DAC, 2-bit ADPCM Reference (SB) */
-#define SBDSP_DMA_PCM8_AUTO 0x1C /* Auto-Initialize DMA DAC, 8-bit (SB2.0) */
-#define SBDSP_DMA_ADPCM2R_AUTO 0x1F /* Auto-Initialize DMA DAC, 2-bit ADPCM Reference (SB2.0) */
-#define SBDSP_DIRECT_ADC 0x20 /* Direct ADC, 8-bit (SB) */
-#define SBDSP_DMA_ADC8 0x24 /* DMA ADC, 8-bit (SB) */
-#define SBDSP_DIRECT_ADC8_BURST 0x28 /* Direct ADC, 8-bit (Burst) (SB-Pro2) */
-#define SBDSP_DMA_ADC8_AUTO 0x2C /* Auto-Initialize DMA ADC, 8-bit (SB2.0) */
-#define SBDSP_MIDI_READ_POLL 0x30 /* MIDI Read Poll (SB) */
-#define SBDSP_MIDI_READ_IRQ 0x31 /* MIDI Read Interrupt (SB) */
-#define SBDSP_MIDI_READ_TIME 0x32 /* MIDI Read Timestamp Poll (SB???) */
-#define SBDSP_MIDI_READ_TIME_IRQ 0x33 /* MIDI Read Timestamp Interrupt (SB???) */
-#define SBDSP_MIDI_RW_POLL 0x34 /* MIDI Read Poll + Write Poll (UART) (SB2.0) */
-#define SBDSP_MIDI_RW_IRQ 0x35 /* MIDI Read Interrupt + Write Poll (UART) (SB2.0???) */
-#define SBDSP_MIDI_RW_TIME_IRQ 0x37 /* MIDI Read Timestamp Interrupt + Write Poll (UART) (SB2.0???) */
-#define SBDSP_MIDI_WRITE_POLL 0x38 /* MIDI Write Poll (SB) */
-#define SBDSP_SET_TIMING 0x40 /* Set Time Constant (SB) */
-#define SBDSP_SET_RATE 0x41 /* Set Sample Rate, Hz (SB16) */
-#define SBDSP_DMA_CONT8_AUTO 0x45 /* Continue Auto-Initialize DMA, 8-bit (SB16) */
-#define SBDSP_DMA_CONT16_AUTO 0x47 /* Continue Auto-Initialize DMA, 16-bit (SB16) */
-#define SBDSP_SET_DMA_BLOCK 0x48 /* Set DMA Block Size (SB2.0) */
-#define SBDSP_DMA_ADPCM4 0x74 /* DMA DAC, 4-bit ADPCM (SB) */
-#define SBDSP_DMA_ADPCM4_REF 0x75 /* DMA DAC, 4-bit ADPCM Reference (SB) */
-#define SBDSP_DMA_ADPCM26 0x76 /* DMA DAC, 2.6-bit ADPCM (SB) */
-#define SBDSP_DMA_ADPCM26_REF 0x77 /* DMA DAC, 2.6-bit ADPCM Reference (SB) */
-#define SBDSP_DMA_ADPCM4R_AUTO 0x7D /* Auto-Initialize DMA DAC, 4-bit ADPCM Reference (SB2.0) */
-#define SBDSP_DMA_ADPCM26R_AUTO 0x7F /* Auto-Initialize DMA DAC, 2.6-bit ADPCM Reference (SB2.0) */
-#define SBDSP_DISABLE_DAC 0x80 /* Silence DAC (SB) */
-#define SBDSP_HS_DMA_DAC8_AUTO 0x90 /* Auto-Initialize DMA DAC, 8-bit (High Speed) (SB2.0-Pro2) */
-#define SBDSP_HS_DMA_ADC8_AUTO 0x98 /* Auto-Initialize DMA ADC, 8-bit (High Speed) (SB2.0-Pro2) */
-#define SBDSP_STEREO_ADC_DIS 0xA0 /* Disable Stereo Input Mode (SBPro Only) */
-#define SBDSP_STEREO_ADC_ENA 0xA8 /* Enable Stereo Input Mode (SBPro Only) */
-#define SBDSP_DMA_GENERIC16 0xB0 /* Generic DAC/ADC DMA (16-bit) (SB16) */
-#define SBDSP_DMA_GENERIC8 0xC0 /* Generic DAC/ADC DMA (8-bit) (SB16) */
-#define SBDSP_DMA_HALT8 0xD0 /* Halt DMA Operation, 8-bit (SB) */
-#define SBDSP_SPEAKER_ENA 0xD1 /* Enable Speaker (SB) */
-#define SBDSP_SPEAKER_DIS 0xD3 /* Disable Speaker (SB) */
-#define SBDSP_DMA_CONT8 0xD4 /* Continue DMA Operation, 8-bit (SB) */
-#define SBDSP_DMA_HALT16 0xD5 /* Halt DMA Operation, 16-bit (SB16) */
-#define SBDSP_DMA_CONT16 0xD6 /* Continue DMA Operation, 16-bit (SB16) */
-#define SBDSP_SPEAKER_STATUS 0xD8 /* Speaker Status (SB) */
-#define SBDSP_DMA_EXIT16_AUTO 0xD9 /* Exit Auto-Initialize DMA Operation, 16-bit (SB16) */
-#define SBDSP_DMA_EXIT8_AUTO 0xDA /* Exit Auto-Initialize DMA Operation, 8-bit (SB2.0) */
-#define SBDSP_IDENTIFY 0xE0 /* DSP Identification (SB2.0) */
-#define SBDSP_VERSION 0xE1 /* DSP Version (SB) */
-#define SBDSP_COPYRIGHT 0xE3 /* DSP Copyright (SBPro2???) */
-#define SBDSP_WRITE_TEST 0xE4 /* Write Test Register (SB2.0) */
-#define SBDSP_READ_TEST 0xE8 /* Read Test Register (SB2.0) */
-#define SBDSP_SINE_GEN 0xF0 /* Sine Generator (SB) */
-#define SBDSP_AUX_STATUS_PRO 0xF1 /* DSP Auxiliary Status (Obsolete) (SB-Pro2) */
-#define SBDSP_GEN_IRQ8 0xF2 /* IRQ Request, 8-bit (SB) */
-#define SBDSP_GEN_IRQ16 0xF3 /* IRQ Request, 16-bit (SB16) */
-#define SBDSP_STATUS 0xFB /* DSP Status (SB16) */
-#define SBDSP_AUX_STATUS_16 0xFC /* DSP Auxiliary Status (SB16) */
-#define SBDSP_CMD_STATUS 0xFD /* DSP Command Status (SB16) */
-
-/* Mixer commands */
-#define SBMIX_RESET 0x00 /* Reset Write SBPro */
-#define SBMIX_STATUS 0x01 /* Status Read SBPro */
-#define SBMIX_MASTER_LEVEL1 0x02 /* Master Volume Read/Write SBPro Only */
-#define SBMIX_DAC_LEVEL 0x04 /* DAC Level Read/Write SBPro */
-#define SBMIX_FM_OUTPUT 0x06 /* FM Output Control Read/Write SBPro Only */
-#define SBMIX_MIC_LEVEL 0x0A /* Microphone Level Read/Write SBPro */
-#define SBMIX_INPUT_SELECT 0x0C /* Input/Filter Select Read/Write SBPro Only */
-#define SBMIX_OUTPUT_SELECT 0x0E /* Output/Stereo Select Read/Write SBPro Only */
-#define SBMIX_FM_LEVEL 0x22 /* Master Volume Read/Write SBPro */
-#define SBMIX_MASTER_LEVEL 0x26 /* FM Level Read/Write SBPro */
-#define SBMIX_CD_LEVEL 0x28 /* CD Audio Level Read/Write SBPro */
-#define SBMIX_LINEIN_LEVEL 0x2E /* Line In Level Read/Write SBPro */
-#define SBMIX_MASTER_LEVEL_L 0x30 /* Master Volume Left Read/Write SB16 */
-#define SBMIX_MASTER_LEVEL_R 0x31 /* Master Volume Right Read/Write SB16 */
-#define SBMIX_DAC_LEVEL_L 0x32 /* DAC Level Left Read/Write SB16 */
-#define SBMIX_DAC_LEVEL_R 0x33 /* DAC Level Right Read/Write SB16 */
-#define SBMIX_FM_LEVEL_L 0x34 /* FM Level Left Read/Write SB16 */
-#define SBMIX_FM_LEVEL_R 0x35 /* FM Level Right Read/Write SB16 */
-#define SBMIX_CD_LEVEL_L 0x36 /* CD Audio Level Left Read/Write SB16 */
-#define SBMIX_CD_LEVEL_R 0x37 /* CD Audio Level Right Read/Write SB16 */
-#define SBMIX_LINEIN_LEVEL_L 0x38 /* Line In Level Left Read/Write SB16 */
-#define SBMIX_LINEIN_LEVEL_R 0x39 /* Line In Level Right Read/Write SB16 */
-#define SBMIX_MIC_LEVEL_16 0x3A /* Microphone Level Read/Write SB16 */
-#define SBMIX_PCSPK_LEVEL 0x3B /* PC Speaker Level Read/Write SB16 */
-#define SBMIX_OUTPUT_CONTROL 0x3C /* Output Control Read/Write SB16 */
-#define SBMIX_INPUT_CONTROL_L 0x3D /* Input Control Left Read/Write SB16 */
-#define SBMIX_INPUT_CONTROL_R 0x3E /* Input Control Right Read/Write SB16 */
-#define SBMIX_INPUT_GAIN_L 0x3F /* Input Gain Control Left Read/Write SB16 */
-#define SBMIX_INPUT_GAIN_R 0x40 /* Input Gain Control Right Read/Write SB16 */
-#define SBMIX_OUTPUT_GAIN_L 0x41 /* Output Gain Control Left Read/Write SB16 */
-#define SBMIX_OUTPUT_GAIN_R 0x42 /* Output Gain Control Right Read/Write SB16 */
-#define SBMIX_AGC_CONTROL 0x43 /* Automatic Gain Control (AGC) Read/Write SB16 */
-#define SBMIX_TREBLE_L 0x44 /* Treble Left Read/Write SB16 */
-#define SBMIX_TREBLE_R 0x45 /* Treble Right Read/Write SB16 */
-#define SBMIX_BASS_L 0x46 /* Bass Left Read/Write SB16 */
-#define SBMIX_BASS_R 0x47 /* Bass Right Read/Write SB16 */
-#define SBMIX_IRQ_SELECT 0x80 /* IRQ Select Read/Write SB16 */
-#define SBMIX_DMA_SELECT 0x81 /* DMA Select Read/Write SB16 */
-#define SBMIX_IRQ_STATUS 0x82 /* IRQ Status Read SB16 */
-
-/* SB_DSP_DATA_OUT_STATUS and SB_DSP_DATA_IN_STATUS bits */
-#define SBM_DSP_READY 0x80
-
-/* SB_DSP_RESET / SBMIX_RESET */
-#define SBM_DSP_RESET 0x01
-
-/* SBMIX_OUTPUT_SELECT */
-#define SBM_MIX_STEREO 0x02
-#define SBM_MIX_FILTER 0x20
-
-/* SBDSP_DMA_GENERIC16/SBDSP_DMA_GENERIC8 */
-#define SBM_GENDAC_FIFO 0x02
-#define SBM_GENDAC_AUTOINIT 0x04
-#define SBM_GENDAC_ADC 0x08
-/* Second (mode) byte */
-#define SBM_GENDAC_SIGNED 0x10
-#define SBM_GENDAC_STEREO 0x20
-
-/* DSP version masks */
-#define SBVER_10 0x0100 /* Original SoundBlaster */
-#define SBVER_15 0x0105 /* SoundBlaster 1.5 */
-#define SBVER_20 0x0200 /* SoundBlaster 2.0 */
-#define SBVER_PRO 0x0300 /* SoundBlaster Pro */
-#define SBVER_PRO2 0x0301 /* SoundBlaster Pro 2 */
-#define SBVER_16 0x0400 /* SoundBlaster 16 */
-#define SBVER_AWE32 0x040c /* SoundBlaster AWE32 */
-
-typedef unsigned char boolean;
-
-#ifndef FALSE
-#define FALSE 0
-#define TRUE 1
-#endif
-
-/* Play mode bits */
-#define SBMODE_16BITS 0x0001
-#define SBMODE_STEREO 0x0002
-#define SBMODE_SIGNED 0x0004
-
-/* Mask for capabilities that never change */
-#define SBMODE_MASK (SBMODE_16BITS | SBMODE_STEREO)
-
-/* You can fill some members of this struct (i.e. port,irq,dma) before
- * calling sb_detect() or sb_open()... this will ignore environment settings.
- */
-typedef struct __sb_state_s {
- boolean ok; /* Are structure contents valid? */
- int port, aweport; /* sb/awe32 base port */
- int irq; /* SoundBlaster IRQ */
- int dma8, dma16; /* 8-bit and 16-bit DMAs */
- int maxfreq_mono; /* Maximum discretization frequency / mono mode */
- int maxfreq_stereo; /* Maximum discretization frequency / stereo mode */
- unsigned short dspver; /* DSP version number */
- struct irq_handle *irq_handle; /* The interrupt handler */
- dma_buffer *dma_buff; /* Pre-allocated DMA buffer */
- unsigned char caps; /* SoundBlaster capabilities (SBMODE_XXX) */
- unsigned char mode; /* Current SB mode (SBMODE_XXX) */
- boolean open; /* Whenever the card has been opened */
- volatile int irqcount; /* Incremented on each IRQ... for diagnostics */
- void (*timer_callback) (); /* Called TWICE per buffer play */
-} __sb_state;
-
-extern __sb_state sb;
-
-extern void __sb_wait();
-
-static inline boolean __sb_dsp_ready_in()
-{
- int count;
- for (count = 10000; count >= 0; count--)
- if (inportb(SB_DSP_DATA_IN_STATUS) & SBM_DSP_READY)
- return TRUE;
- return FALSE;
-}
-
-static inline boolean __sb_dsp_ready_out()
-{
- int count;
- for (count = 10000; count >= 0; count--)
- if ((inportb(SB_DSP_DATA_OUT_STATUS) & SBM_DSP_READY) == 0)
- return TRUE;
- return FALSE;
-}
-
-static inline void __sb_dsp_out(unsigned char reg)
-{
- __sb_dsp_ready_out();
- outportb(SB_DSP_DATA_OUT, reg);
-}
-
-static inline unsigned char __sb_dsp_in()
-{
- __sb_dsp_ready_in();
- return inportb(SB_DSP_DATA_IN);
-}
-
-static inline void __sb_dspreg_out(unsigned char reg, unsigned char val)
-{
- __sb_dsp_out(reg);
- __sb_dsp_out(val);
-}
-
-static inline void __sb_dspreg_outwlh(unsigned char reg, unsigned short val)
-{
- __sb_dsp_out(reg);
- __sb_dsp_out(val);
- __sb_dsp_out(val >> 8);
-}
-
-static inline void __sb_dspreg_outwhl(unsigned char reg, unsigned short val)
-{
- __sb_dsp_out(reg);
- __sb_dsp_out(val >> 8);
- __sb_dsp_out(val);
-}
-
-static inline unsigned char __sb_dspreg_in(unsigned char reg)
-{
- __sb_dsp_out(reg);
- return __sb_dsp_in();
-}
-
-static inline void __sb_dsp_ack_dma8()
-{
- inportb(SB_DSP_DMA8_IRQ);
-}
-
-static inline void __sb_dsp_ack_dma16()
-{
- inportb(SB_DSP_DMA16_IRQ);
-}
-
-static inline unsigned short __sb_dsp_version()
-{
- unsigned short ver;
- __sb_dsp_out(SBDSP_VERSION);
- __sb_dsp_ready_in();
- ver = ((unsigned short)__sb_dsp_in()) << 8;
- ver |= __sb_dsp_in();
- return ver;
-}
-
-static inline void __sb_mixer_out(unsigned char reg, unsigned char val)
-{
- outportb(SB_MIXER_REGSEL, reg);
- outportb(SB_MIXER_DATA, val);
-}
-
-static inline unsigned char __sb_mixer_in(unsigned char reg)
-{
- outportb(SB_MIXER_REGSEL, reg);
- return inportb(SB_MIXER_DATA);
-}
-
-/* Enable stereo transfers: sbpro mode only */
-static inline void __sb_stereo(boolean stereo)
-{
- unsigned char val = __sb_mixer_in(SBMIX_OUTPUT_SELECT);
- if (stereo)
- val |= SBM_MIX_STEREO;
- else
- val &= ~SBM_MIX_STEREO;
- __sb_mixer_out(SBMIX_OUTPUT_SELECT, val);
-}
-
-/* Detect whenever SoundBlaster is present and fill "sb" structure */
-extern boolean sb_detect();
-/* Reset SoundBlaster */
-extern void sb_reset();
-/* Start working with SoundBlaster */
-extern boolean sb_open();
-/* Finish working with SoundBlaster */
-extern boolean sb_close();
-/* Enable/disable speaker output */
-extern void sb_output(boolean enable);
-/* Start playing from DMA buffer in either 8/16 bit mono/stereo */
-extern boolean sb_start_dma(unsigned char mode, unsigned int freq);
-/* Stop playing from DMA buffer */
-extern void sb_stop_dma();
-/* Query current position/total size of the DMA buffer */
-extern void sb_query_dma(unsigned int *dma_size, unsigned int *dma_pos);
-
-#endif /* __DOSSB_H__ */
-
-/* ex:set ts=4: */
+++ /dev/null
-/* MikMod sound library
- (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
- complete list.
-
- This library is free software; you can redistribute it and/or modify
- it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA.
-*/
-
-/*==============================================================================
-
- Windows Sound System I/O routines (CS42XX, ESS18XX, GUS+DaughterBoard etc)
- Written by Andrew Zabolotny <bit@eltech.ru>
-
-==============================================================================*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef DRV_WSS
-
-#include <stdlib.h>
-#include <dpmi.h>
-#include <go32.h>
-#include <dos.h>
-#include <sys/nearptr.h>
-#include <sys/farptr.h>
-#include <string.h>
-
-#include "doswss.h"
-
-/********************************************* Private variables/routines *****/
-
-__wss_state wss;
-
-/* WSS frequency rates... lower bit selects one of two frequency generators */
-static unsigned int wss_rates[14][2] = {
- {5510, 0x00 | WSSM_XTAL2},
- {6620, 0x0E | WSSM_XTAL2},
- {8000, 0x00 | WSSM_XTAL1},
- {9600, 0x0E | WSSM_XTAL1},
- {11025, 0x02 | WSSM_XTAL2},
- {16000, 0x02 | WSSM_XTAL1},
- {18900, 0x04 | WSSM_XTAL2},
- {22050, 0x06 | WSSM_XTAL2},
- {27420, 0x04 | WSSM_XTAL1},
- {32000, 0x06 | WSSM_XTAL1},
- {33075, 0x0C | WSSM_XTAL2},
- {37800, 0x08 | WSSM_XTAL2},
- {44100, 0x0A | WSSM_XTAL2},
- {48000, 0x0C | WSSM_XTAL1}
-};
-
-static void wss_irq()
-{
- /* Make sure its not a spurious IRQ */
- if (!irq_check(wss.irq_handle))
- return;
-
- wss.irqcount++;
-
- /* Clear IRQ status */
- outportb(WSS_STATUS, 0);
-
- /* Write transfer count again */
- __wss_outreg(WSSR_COUNT_LOW, wss.samples & 0xff);
- __wss_outreg(WSSR_COUNT_HIGH, wss.samples >> 8);
- irq_ack(wss.irq_handle);
-
- enable();
- if (wss.timer_callback)
- wss.timer_callback();
-}
-
-static void wss_irq_end()
-{
-}
-
-/* WSS accepts some conventional values instead of frequency in Hz... */
-static unsigned char __wss_getrate(unsigned int *freq)
-{
- int i, best = -1, delta = 0xffff;
-
- for (i = 0; i < 14; i++) {
- int newdelta = abs(wss_rates[i][0] - *freq);
- if (newdelta < delta)
- best = i, delta = newdelta;
- }
-
- *freq = wss_rates[best][0];
- return wss_rates[best][1];
-}
-
-/* Check if we really have a WSS compatible card on given address */
-static boolean __wss_ping()
-{
- /* Disable CODEC operations first */
- __wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
- /* Now put some harmless values in registers and check them */
- __wss_outreg(WSSR_COUNT_LOW, 0xaa);
- __wss_outreg(WSSR_COUNT_HIGH, 0x55);
- return (__wss_inreg(WSSR_COUNT_LOW) == 0xaa)
- && (__wss_inreg(WSSR_COUNT_HIGH) == 0x55);
-}
-
-static boolean __wss_reset()
-{
- int count;
-
- /* Disable output */
- wss_output(FALSE);
-
- /* Now select the test/initialization register */
- count = 10000;
- while (inportb(WSS_ADDR) != WSSR_TEST_INIT) {
- outportb(WSS_ADDR, WSSR_TEST_INIT);
- if (!--count)
- return FALSE;
- }
-
- count = 10000;
- while (inportb(WSS_DATA) & WSSM_CALIB_IN_PROGRESS) {
- outportb(WSS_ADDR, WSSR_TEST_INIT);
- if (!--count)
- return FALSE;
- }
-
- /* Enable playback IRQ */
- __wss_regbit_set(WSSR_PIN_CTRL, WSSM_IRQ_ENABLE);
- __wss_outreg(WSSR_IRQ_STATUS, WSSM_PLAYBACK_IRQ);
-
- /* Clear IRQ status */
- outportb(WSS_STATUS, 0);
-
- return TRUE;
-}
-
-static boolean __wss_setformat(unsigned char format)
-{
- int count;
-
- outportb(WSS_ADDR, WSSM_MCE | WSSR_PLAY_FORMAT);
- outportb(WSS_DATA, format);
- inportb(WSS_DATA); /* ERRATA SHEETS ... */
- inportb(WSS_DATA); /* ERRATA SHEETS ... */
-
- /* Wait end of syncronization ... */
- if (!__wss_wait())
- return FALSE;
-
- /* Turn off the ModeChangeEnable bit: do it until it works */
- count = 10000;
- while (inportb(WSS_ADDR) != WSSR_PLAY_FORMAT) {
- outportb(WSS_ADDR, WSSR_PLAY_FORMAT);
- if (!--count)
- return FALSE;
- }
-
- return __wss_reset();
-}
-
-/**************************************************** WSS detection stuff *****/
-
-static int __wss_irq_irqdetect(int irqno)
-{
- unsigned char status = inportb(WSS_STATUS);
- /* Clear IRQ status */
- outportb(WSS_STATUS, 0);
- /* Reset transfer counter */
- __wss_outreg(WSSR_COUNT_LOW, 0);
- __wss_outreg(WSSR_COUNT_HIGH, 0);
- return (status & WSSM_INT);
-}
-
-static boolean __wss_detect()
-{
- /* First find the port number */
- if (!wss.port) {
- static unsigned int wss_ports[] =
- { 0x32c, 0x530, 0x604, 0xE80, 0xF40 };
- int i;
- for (i = 0; i < 5; i++) {
- wss.port = wss_ports[i];
- if (__wss_ping())
- break;
- }
- if (i < 0) {
- wss.port = 0;
- return FALSE;
- }
- }
-
- /* Now disable output */
- wss_output(FALSE);
-
- /* Detect the DMA channel */
- if (!wss.dma) {
- static int __dma[] = { 0, 1, 3 };
- int i;
-
- /* Enable playback IRQ */
- __wss_regbit_set(WSSR_PIN_CTRL, WSSM_IRQ_ENABLE);
- __wss_outreg(WSSR_IRQ_STATUS, WSSM_PLAYBACK_IRQ);
-
- /* Start a short DMA transfer and check if DMA count is zero */
- for (i = 0; i < 3; i++) {
- unsigned int timer, status, freq = 44100;
-
- wss.dma = __dma[i];
-
- dma_disable(wss.dma);
- dma_set_mode(wss.dma, DMA_MODE_WRITE);
- dma_clear_ff(wss.dma);
- dma_set_count(wss.dma, 10);
- dma_enable(wss.dma);
-
- /* Clear IRQ status */
- outportb(WSS_STATUS, 0);
-
- __wss_setformat(__wss_getrate(&freq));
- __wss_outreg(WSSR_COUNT_LOW, 1);
- __wss_outreg(WSSR_COUNT_HIGH, 0);
- /* Tell codec to start transfer */
- __wss_regbit_set(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
-
- _farsetsel(_dos_ds);
- timer = _farnspeekl(0x46c);
-
- while (_farnspeekl(0x46c) - timer <= 2)
- if (dma_get_count(wss.dma) == 0)
- break;
- __wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
- dma_disable(wss.dma);
-
- /* Now check if DMA transfer count is zero and an IRQ is pending */
- status = inportb(WSS_STATUS);
- outportb(WSS_STATUS, 0);
- if ((dma_get_count(wss.dma) == 0) && (status & WSSM_INT))
- break;
-
- wss.dma = 0;
- }
-
- if (!wss.dma)
- return FALSE;
- }
-
- /* Now detect the IRQ number */
- if (!wss.irq) {
- unsigned int i, irqmask, freq = 5510;
- unsigned long timer, delta = 0x7fffffff;
-
- /* IRQ can be one of 2,3,5,7,10 */
- irq_detect_start(0x04ac, __wss_irq_irqdetect);
-
- dma_disable(wss.dma);
- dma_set_mode(wss.dma, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
- dma_clear_ff(wss.dma);
- dma_set_count(wss.dma, 1);
- dma_enable(wss.dma);
-
- __wss_setformat(__wss_getrate(&freq));
-
- /* Clear IRQ status */
- outportb(WSS_STATUS, 0);
-
- __wss_outreg(WSSR_COUNT_LOW, 0);
- __wss_outreg(WSSR_COUNT_HIGH, 0);
-
- /* Prepare timeout counter */
- _farsetsel(_dos_ds);
- timer = _farnspeekl(0x46c);
- while (timer == _farnspeekl(0x46c));
- timer = _farnspeekl(0x46c);
-
- /* Reset all IRQ counters */
- irq_detect_clear();
-
- /* Tell codec to start transfer */
- __wss_regbit_set(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
-
- /* Now wait 1/18 seconds */
- while (timer == _farnspeekl(0x46c));
- __wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
- dma_disable(wss.dma);
-
- /* Given frequency 5510Hz, a buffer size of 1 byte and a time interval
- of 1/18.2 second, we should have received about 302 interrupts */
- for (i = 2; i <= 10; i++) {
- int count = abs(302 - irq_detect_get(i, &irqmask));
- if (count < delta)
- wss.irq = i, delta = count;
- }
- if (delta > 150)
- wss.irq = 0;
-
- irq_detect_end();
- if (!wss.irq)
- return FALSE;
- }
-
- return TRUE;
-}
-
-/*************************************************** High-level interface *****/
-
-/* Detect whenever WSS is present and fill "wss" structure */
-boolean wss_detect()
-{
- char *env;
-
- /* Try to find the port and DMA from environment */
- env = getenv("WSS");
-
- while (env && *env) {
- /* Skip whitespace */
- while ((*env == ' ') || (*env == '\t'))
- env++;
- if (!*env)
- break;
-
- switch (*env++) {
- case 'A':
- case 'a':
- if (!wss.port)
- wss.port = strtol(env, &env, 16);
- break;
- case 'I':
- case 'i':
- if (!wss.irq)
- wss.irq = strtol(env, &env, 10);
- break;
- case 'D':
- case 'd':
- if (!wss.dma)
- wss.dma = strtol(env, &env, 10);
- break;
- default:
- /* Skip other values */
- while (*env && (*env != ' ') && (*env != '\t'))
- env++;
- break;
- }
- }
-
- /* Try to fill the gaps in wss hardware parameters */
- __wss_detect();
-
- if (!wss.port || !wss.irq || !wss.dma)
- return FALSE;
-
- if (!__wss_ping())
- return FALSE;
-
- if (!__wss_reset())
- return FALSE;
-
- wss.ok = 1;
- return TRUE;
-}
-
-/* Reset WSS */
-void wss_reset()
-{
- wss_stop_dma();
- __wss_reset();
-}
-
-/* Open WSS for usage */
-boolean wss_open()
-{
- __dpmi_meminfo struct_info;
-
- if (!wss.ok)
- if (!wss_detect())
- return FALSE;
-
- if (wss.open)
- return FALSE;
-
- /* Now lock the wss structure in memory */
- struct_info.address = __djgpp_base_address + (unsigned long)&wss;
- struct_info.size = sizeof(wss);
- if (__dpmi_lock_linear_region(&struct_info))
- return FALSE;
-
- /* Hook the WSS IRQ */
- wss.irq_handle =
- irq_hook(wss.irq, wss_irq, (long)wss_irq_end - (long)wss_irq);
- if (!wss.irq_handle) {
- __dpmi_unlock_linear_region(&struct_info);
- return FALSE;
- }
-
- /* Enable the interrupt */
- irq_enable(wss.irq_handle);
- if (wss.irq > 7)
- _irq_enable(2);
-
- wss.open++;
-
- return TRUE;
-}
-
-/* Finish working with WSS */
-boolean wss_close()
-{
- __dpmi_meminfo struct_info;
- if (!wss.open)
- return FALSE;
-
- wss.open--;
-
- /* Stop/free DMA buffer */
- wss_stop_dma();
-
- /* Unhook IRQ */
- irq_unhook(wss.irq_handle);
- wss.irq_handle = NULL;
-
- /* Unlock the wss structure */
- struct_info.address = __djgpp_base_address + (unsigned long)&wss;
- struct_info.size = sizeof(wss);
- __dpmi_unlock_linear_region(&struct_info);
-
- return TRUE;
-}
-
-/* Adjust frequency rate to nearest WSS available */
-unsigned int wss_adjust_freq(unsigned int freq)
-{
- __wss_getrate(&freq);
- return freq;
-}
-
-/* Enable/disable speaker output */
-/* Start playing from DMA buffer in either 8/16 bit mono/stereo */
-boolean wss_start_dma(unsigned char mode, unsigned int freq)
-{
- int dmabuffsize;
- unsigned char format;
-
- /* Stop DMA transfer if it is enabled */
- wss_stop_dma();
-
- /* Sanity check: we support only 8-bit unsigned and 16-bit signed formats */
- if (((mode & WSSMODE_16BITS) && !(mode & WSSMODE_SIGNED))
- || (!(mode & WSSMODE_16BITS) && (mode & WSSMODE_SIGNED)))
- return FALSE;
-
- /* Find the nearest frequency divisor (rate) */
- format = __wss_getrate(&freq);
- wss.mode = mode;
-
- /* Get a DMA buffer enough for a 1sec interval... 4K <= dmasize <= 32K */
- dmabuffsize = freq;
- if (mode & WSSMODE_STEREO)
- dmabuffsize *= 2;
- if (mode & WSSMODE_16BITS)
- dmabuffsize *= 2;
- dmabuffsize >>= 2;
- if (dmabuffsize < 4096)
- dmabuffsize = 4096;
- if (dmabuffsize > 32768)
- dmabuffsize = 32768;
- dmabuffsize = (dmabuffsize + 255) & 0xffffff00;
-
- wss.dma_buff = dma_allocate(wss.dma, dmabuffsize);
- if (!wss.dma_buff)
- return FALSE;
-
- /* Fill DMA buffer with silence */
- dmabuffsize = wss.dma_buff->size;
- if (mode & WSSMODE_SIGNED)
- memset(wss.dma_buff->linear, 0, dmabuffsize);
- else
- memset(wss.dma_buff->linear, 0x80, dmabuffsize);
-
- /* Check data size and build a WSSR_PLAY_FORMAT value accordingly */
- wss.samples = dmabuffsize;
- if (mode & WSSMODE_16BITS) {
- wss.samples >>= 1;
- format |= WSSM_16BITS;
- }
-
- if (mode & WSSMODE_STEREO) {
- wss.samples >>= 1;
- format |= WSSM_STEREO;
- }
-
- if (!__wss_setformat(format)) {
- wss_stop_dma();
- return FALSE;
- }
-
- /* Prime DMA for transfer */
- dma_start(wss.dma_buff, dmabuffsize, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
-
- /* Tell codec how many samples to transfer */
- wss.samples = (wss.samples >> 1) - 1;
- __wss_outreg(WSSR_COUNT_LOW, wss.samples & 0xff);
- __wss_outreg(WSSR_COUNT_HIGH, wss.samples >> 8);
-
- /* Tell codec to start transfer */
- __wss_regbit_set(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
-
- return TRUE;
-}
-
-/* Stop playing from DMA buffer */
-void wss_stop_dma()
-{
- if (!wss.dma_buff)
- return;
-
- __wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);
- dma_disable(wss.dma);
- dma_free(wss.dma_buff);
- wss.dma_buff = NULL;
-}
-
-/* Query current position/total size of the DMA buffer */
-void wss_query_dma(unsigned int *dma_size, unsigned int *dma_pos)
-{
- unsigned int dma_left;
- *dma_size = wss.dma_buff->size;
- /* It can happen we try to read DMA count when HI/LO bytes will be
- inconsistent */
- for (;;) {
- unsigned int dma_left_test;
- dma_clear_ff(wss.dma);
- dma_left_test = dma_get_count(wss.dma);
- dma_left = dma_get_count(wss.dma);
- if ((dma_left >= dma_left_test) && (dma_left - dma_left_test < 10))
- break;
- }
- *dma_pos = *dma_size - dma_left;
-}
-
-void wss_output(boolean enable)
-{
- if (enable)
- wss.curlevel = wss.level;
- else
- wss.curlevel = 0x3f;
-
- __wss_outreg(WSSR_MASTER_L, wss.curlevel);
- __wss_outreg(WSSR_MASTER_R, wss.curlevel);
-}
-
-void wss_level(int level)
-{
- if (level < 0)
- level = 0;
- if (level > 63)
- level = 63;
- wss.curlevel = wss.level = level ^ 63;
-
- __wss_outreg(WSSR_MASTER_L, wss.curlevel);
- __wss_outreg(WSSR_MASTER_R, wss.curlevel);
-}
-
-#endif /* DRV_WSS */
-
-/* ex:set ts=4: */
+++ /dev/null
-/* MikMod sound library
- (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
- complete list.
-
- This library is free software; you can redistribute it and/or modify
- it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA.
-*/
-
-/*==============================================================================
-
- $Id$
-
- Windows Sound System and compatible soundcards definitions
-
-==============================================================================*/
-
-#ifndef __DOSWSS_H__
-#define __DOSWSS_H__
-
-#include "dosdma.h"
-#include "dosirq.h"
-
-#define WSS_ADDR (wss.port + 0x04)
-#define WSS_DATA (wss.port + 0x05)
-#define WSS_STATUS (wss.port + 0x06)
-#define WSS_PIO (wss.port + 0x07)
-
-/* WSS_ADDR: Bits 0-4 select an internal register to read/write */
-#define WSSR_INPUT_L 0x00 /* Left input control register */
-#define WSSR_INPUT_R 0x01 /* RIght input control register */
-#define WSSR_AUX1_L 0x02 /* Left Aux #1 input control */
-#define WSSR_AUX1_R 0x03 /* Right Aux #1 input control */
-#define WSSR_CD_L 0x04 /* Left Aux #2 input control */
-#define WSSR_CD_R 0x05 /* Right Aux #2 input control */
-#define WSSR_MASTER_L 0x06 /* Left output control */
-#define WSSR_MASTER_R 0x07 /* Right output control */
-#define WSSR_PLAY_FORMAT 0x08 /* Clock and data format */
-#define WSSR_IFACE_CTRL 0x09 /* Interface control */
-#define WSSR_PIN_CTRL 0x0a /* Pin control */
-#define WSSR_TEST_INIT 0x0b /* Test and initialization */
-#define WSSR_MISC_INFO 0x0c /* Miscellaneaous information */
-#define WSSR_LOOPBACK 0x0d /* Digital Mix */
-#define WSSR_COUNT_HIGH 0x0e /* Playback Upper Base Count */
-#define WSSR_COUNT_LOW 0x0f /* Playback Lower Base Count */
-#define WSSR_ALT_FEATURE_1 0x10 /* alternate #1 feature enable */
-#define WSSR_ALT_FEATURE_2 0x11 /* alternate #2 feature enable */
-#define WSSR_LINE_IN_L 0x12 /* left line input control */
-#define WSSR_LINE_IN_R 0x13 /* right line input control */
-#define WSSR_TIMER_LOW 0x14 /* timer low byte */
-#define WSSR_TIMER_HIGH 0x15 /* timer high byte */
-#define WSSR_IRQ_STATUS 0x18 /* irq status register */
-#define WSSR_MONO_IO_CTRL 0x1a /* mono input/output control */
-#define WSSR_REC_FORMAT 0x1c /* record format */
-#define WSSR_REC_COUNT_HIGH 0x1e /* record upper count */
-#define WSSR_REC_COUNT_LOW 0x1f /* record lower count */
-
-/* WSS_ADDR bits 7-5 definition */
-#define WSSM_INIT 0x80 /* Codec is initializing */
-#define WSSM_MCE 0x40 /* Mode change enable */
-#define WSSM_TRD 0x20 /* Transfer Request Disable */
-/* bits 4-0 are indirect register address (0-15) */
-
-/* WSS_STATUS bit masks */
-#define WSSM_CUL 0x80 /* Capture data upper/lower byte */
-#define WSSM_CLR 0x40 /* Capture left/right sample */
-#define WSSM_CRDY 0x20 /* Capture data read */
-#define WSSM_SOUR 0x10 /* Playback over/under run error */
-#define WSSM_PUL 0x08 /* Playback upper/lower byte */
-#define WSSM_PLR 0x04 /* Playback left/right sample */
-#define WSSM_PRDY 0x02 /* Playback data register read */
-#define WSSM_INT 0x01 /* interrupt status */
-
-/* Definitions for output level registers */
-#define WSSM_MUTE 0x80 /* Mute this output source */
-/* bits 5-0 are left output attenuation select (0-63) */
-/* bits 5-0 are right output attenuation select (0-63) */
-
-/* Definitions for clock and data format register (WSSR_PLAY_FORMAT) */
-#define WSSM_STEREO 0x10 /* stero mode */
-#define WSSM_ULAW_8 0x20 /* 8-bit U-law companded */
-#define WSSM_16BITS 0x40 /* 16 bit twos complement data - little endian */
-#define WSSM_ALAW_8 0x60 /* 8-bit A-law companded */
-#define WSSM_16BITS_BE 0xc0 /* 16-bit twos complement data - big endian */
-#define WSSM_ADPCM_16 0xa0 /* 16-bit ADPCM */
-/* Bits 3-1 define frequency divisor */
-#define WSSM_XTAL1 0x00 /* 24.576 crystal */
-#define WSSM_XTAL2 0x01 /* 16.9344 crystal */
-
-/* Definitions for interface control register (WSSR_IFACE_CTRL) */
-#define WSSM_CAPTURE_PIO 0x80 /* Capture PIO enable */
-#define WSSM_PLAYBACK_PIO 0x40 /* Playback PIO enable */
-#define WSSM_AUTOCALIB 0x08 /* auto calibrate */
-#define WSSM_SINGLE_DMA 0x04 /* Use single DMA channel */
-#define WSSM_PLAYBACK_ENABLE 0x01 /* playback enable */
-
-/* Definitions for Pin control register (WSSR_PIN_CTRL) */
-#define WSSM_IRQ_ENABLE 0x02 /* interrupt enable */
-#define WSSM_XCTL1 0x40 /* external control #1 */
-#define WSSM_XCTL0 0x80 /* external control #0 */
-
-/* Definitions for WSSR_TEST_INIT register */
-#define WSSM_CALIB_IN_PROGRESS 0x20 /* auto calibrate in progress */
-
-/* Definitions for misc control register (WSR_MISC_INFO) */
-#define WSSM_MODE2 0x40 /* MODE 2 */
-#define WSSM_MODE3 0x6c /* MODE 3 - enhanced mode */
-
-/* Definitions for codec irq status (WSSR_IRQ_STATUS) */
-#define WSSM_PLAYBACK_IRQ 0x10
-#define WSSM_RECORD_IRQ 0x20
-#define WSSM_TIMER_IRQ 0x40
-
-typedef unsigned char boolean;
-
-#ifndef FALSE
-#define FALSE 0
-#define TRUE 1
-#endif
-
-/* Play mode bits */
-#define WSSMODE_16BITS 0x0001
-#define WSSMODE_STEREO 0x0002
-#define WSSMODE_SIGNED 0x0004
-
-/* You can fill some members of this struct (i.e. port,irq,dma) before
- * calling wss_detect() or wss_open()... this will ignore environment settings.
- */
-typedef struct __wss_state_s {
- boolean ok; /* Set if this structure is properly filled */
- int port; /* Base codec port */
- int irq; /* codec IRQ */
- int dma; /* codec DMA */
- struct irq_handle *irq_handle; /* The interrupt handler */
- dma_buffer *dma_buff; /* Pre-allocated DMA buffer */
- unsigned char mode; /* Current WSS mode (WSSMODE_XXX) */
- boolean open; /* Whenever the card has been opened */
- int samples; /* Number of samples in DMA buffer */
- unsigned char level; /* Output level (63..0): doesn't change when mute */
- unsigned char curlevel; /* Current output level (63(min)..0(max)) */
- volatile int irqcount; /* Incremented on each IRQ... for diagnostics */
- void (*timer_callback) (); /* Called TWICE per buffer play */
-} __wss_state;
-
-extern __wss_state wss;
-
-/* Wait until codec finishes initialization */
-static inline boolean __wss_wait()
-{
- int count;
- for (count = 10000; count >= 0; count--)
- if (!(inportb(WSS_ADDR) & WSSM_INIT))
- return TRUE;
- return FALSE;
-}
-
-static inline void __wss_outreg(unsigned char reg, unsigned char val)
-{
- outportb(WSS_ADDR, reg);
- outportb(WSS_DATA, val);
-}
-
-static inline unsigned char __wss_inreg(unsigned char reg)
-{
- outportb(WSS_ADDR, reg);
- return inportb(WSS_DATA);
-}
-
-/* Set some bits in a specific register */
-static inline void __wss_regbit_set(unsigned char reg, unsigned char mask)
-{
- outportb(WSS_ADDR, reg);
- outportb(WSS_DATA, inportb(WSS_DATA) | mask);
-}
-
-/* Reset some bits in a specific register */
-static inline void __wss_regbit_reset(unsigned char reg, unsigned char mask)
-{
- outportb(WSS_ADDR, reg);
- outportb(WSS_DATA, inportb(WSS_DATA) & ~mask);
-}
-
-/* Detect whenever WSS is present and fill "wss" structure */
-extern boolean wss_detect();
-/* Reset WSS */
-extern void wss_reset();
-/* Open WSS for usage */
-extern boolean wss_open();
-/* Finish working with WSS */
-extern boolean wss_close();
-/* Enable/disable speaker output */
-extern void wss_output(boolean enable);
-/* Adjust frequency rate to nearest WSS available */
-extern unsigned int wss_adjust_freq(unsigned int freq);
-/* Start playing from DMA buffer in either 8/16 bit mono/stereo */
-extern boolean wss_start_dma(unsigned char mode, unsigned int freq);
-/* Stop playing from DMA buffer */
-extern void wss_stop_dma();
-/* Query current position/total size of the DMA buffer */
-extern void wss_query_dma(unsigned int *dma_size, unsigned int *dma_pos);
-/* Set output level (0(min)-63(max)) */
-extern void wss_level(int level);
-
-#endif /* __DOSWSS_H__ */
-
-/* ex:set ts=4: */
+++ /dev/null
-/* MikMod sound library
- (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for
- complete list.
-
- This library is free software; you can redistribute it and/or modify
- it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA.
-*/
-
-/*==============================================================================
-
- $Id$
-
- Linux libGUS-alike library for DOS, used by drv_ultra.c under DOS.
-
-==============================================================================*/
-
-/*
- Current limitations:
- - Only a subset of libgus is supported
- - Only one GUS card is supported (due to the fact that ULTRASND environment
- variable is used)
- - No Interwawe support (if IW works the old way, it's ok).
-*/
-
-#ifndef __LIBGUS_H__
-#define __LIBGUS_H__
-
-#include <stddef.h>
-
-#define __LITTLE_ENDIAN
-
-typedef struct _gus_info_t gus_info_t;
-typedef struct _gus_instrument_t gus_instrument_t;
-typedef struct _gus_wave_t gus_wave_t;
-typedef struct _gus_layer_t gus_layer_t;
-
-#define GUS_CARD_VERSION_CLASSIC 0x0024 /* revision 2.4 */
-#define GUS_CARD_VERSION_CLASSIC1 0x0034 /* revision 3.4? */
-#define GUS_CARD_VERSION_CLASSIC_ICS 0x0037 /* revision 3.7 (ICS mixer) */
-#define GUS_CARD_VERSION_EXTREME 0x0050 /* GUS Extreme */
-#define GUS_CARD_VERSION_ACE 0x0090 /* GUS ACE */
-#define GUS_CARD_VERSION_MAX 0x00a0 /* GUS MAX - revision 10 */
-#define GUS_CARD_VERSION_MAX1 0x00a1 /* GUS MAX - revision 11 */
-#define GUS_CARD_VERSION_PNP 0x0100 /* GUS Plug & Play */
-
-#define GUS_STRU_INFO_F_DB16 0x00000001 /* 16-bit daughter board present */
-#define GUS_STRU_INFO_F_PCM 0x00000004 /* GF1 PCM during SYNTH enabled */
-#define GUS_STRU_INFO_F_ENHANCED 0x00000008 /* InterWave - enhanced mode */
-#define GUS_STRU_INFO_F_DAEMON 0x00000010 /* instrument daemon is present */
-
-struct _gus_info_t {
- unsigned char id[8]; /* id of this card (warning! maybe unterminated!!!) */
-
- unsigned int flags; /* some info flags - see to GUS_STRU_INFO_F_XXXX */
- unsigned int version; /* see to GUS_CARD_VERSION_XXXX constants */
-
- unsigned short port;
- unsigned short irq;
- unsigned short dma1; /* DMA1 - GF1 download & codec record */
- unsigned short dma2; /* DMA2 - GF1 record & codec playback */
-
- unsigned int mixing_freq; /* mixing frequency in Hz */
-
- unsigned int memory_size; /* in bytes */
- unsigned int memory_free; /* in bytes */
- unsigned int memory_block_8; /* largest free 8-bit block in memory */
- unsigned int memory_block_16; /* largest free 16-bit block in memory */
-};
-
-/* struct gus_instrument_t - mode */
-
-#define GUS_INSTR_SIMPLE 0x00 /* simple format - for MOD players */
-#define GUS_INSTR_PATCH 0x01 /* old GF1 patch format */
-#define GUS_INSTR_COUNT 2
-
-#define GUS_INSTR_F_NORMAL 0x0000 /* normal mode */
-#define GUS_INSTR_F_NOT_FOUND 0x0001 /* instrument can't be loaded */
-#define GUS_INSTR_F_ALIAS 0x0002 /* alias */
-#define GUS_INSTR_F_NOT_LOADED 0x00ff /* instrument not loaded (not found) */
-
-#define GUS_INSTR_E_NONE 0x0000 /* exclusion mode - none */
-#define GUS_INSTR_E_SINGLE 0x0001 /* exclude single - single note from this instrument */
-#define GUS_INSTR_E_MULTIPLE 0x0002 /* exclude multiple - stop only same note from this instrument */
-
-#define GUS_INSTR_L_NONE 0x0000 /* not layered */
-#define GUS_INSTR_L_ON 0x0001 /* layered */
-#define GUS_INSTR_L_VELOCITY 0x0002 /* layered by velocity */
-#define GUS_INSTR_L_FREQUENCY 0x0003 /* layered by frequency */
-
-struct _gus_instrument_t {
- union {
- unsigned int instrument;/* instrument number */
- } number;
-
- char *name; /* name of this instrument or NULL */
-
- unsigned int mode:8, /* see to GUS_INSTR_XXXX */
- flags:8, /* see to GUS_INSTR_F_XXXX */
- exclusion:4, /* see to GUS_INSTR_E_XXXX */
- layer:4; /* see to GUS_INSTR_L_XXXX */
- unsigned short exclusion_group; /* 0 - none, 1-65535 */
-
- struct {
- unsigned char effect1:4,/* use global effect if available */
- effect2:4; /* use global effect if available */
- unsigned char effect1_depth;/* 0-127 */
- unsigned char effect2_depth;/* 0-127 */
- } patch;
-
- union {
- gus_layer_t *layer; /* first layer */
- unsigned int alias; /* pointer to instrument */
- } info;
- gus_instrument_t *next; /* next instrument */
-};
-
-struct _gus_layer_t {
- unsigned char mode; /* see to GUS_INSTR_XXXX constants */
-
- gus_wave_t *wave;
- gus_layer_t *next;
-};
-
-/* bits for format variable in gus_wave_t */
-
-#define GUS_WAVE_16BIT 0x0001 /* 16-bit wave */
-#define GUS_WAVE_UNSIGNED 0x0002 /* unsigned wave */
-#define GUS_WAVE_INVERT 0x0002 /* same as unsigned wave */
-#define GUS_WAVE_BACKWARD 0x0004 /* forward mode */
-#define GUS_WAVE_LOOP 0x0008 /* loop mode */
-#define GUS_WAVE_BIDIR 0x0010 /* bidirectional mode */
-#define GUS_WAVE_ULAW 0x0020 /* uLaw compressed wave */
-#define GUS_WAVE_RAM 0x0040 /* wave is _preloaded_ in RAM (it is used for ROM simulation) */
-#define GUS_WAVE_ROM 0x0080 /* wave is in ROM */
-#define GUS_WAVE_DELTA 0x0100
-
-#define GUS_WAVE_PATCH_ENVELOPE 0x01 /* envelopes on */
-#define GUS_WAVE_PATCH_SUSTAIN 0x02 /* sustain mode */
-
-struct _gus_wave_t {
- unsigned char mode; /* see to GUS_INSTR_XXXX constants */
- unsigned char format; /* see to GUS_WAVE_XXXX constants */
- unsigned int size; /* size of waveform in bytes */
- unsigned int start; /* start offset in bytes * 16 (lowest 4 bits - fraction) */
- unsigned int loop_start; /* bits loop start offset in bytes * 16 (lowest 4 bits - fraction) */
- unsigned int loop_end; /* loop start offset in bytes * 16 (lowest 4 bits - fraction) */
- unsigned short loop_repeat; /* loop repeat - 0 = forever */
- struct {
- unsigned int memory; /* begin of waveform in GUS's memory */
- unsigned char *ptr; /* pointer to waveform in system memory */
- } begin;
-
- struct {
- unsigned char flags;
- unsigned int sample_rate;
- unsigned int low_frequency;/* low frequency range for this waveform */
- unsigned int high_frequency;/* high frequency range for this waveform */
- unsigned int root_frequency;/* root frequency for this waveform */
- signed short tune;
- unsigned char balance;
- unsigned char envelope_rate[6];
- unsigned char envelope_offset[6];
- unsigned char tremolo_sweep;
- unsigned char tremolo_rate;
- unsigned char tremolo_depth;
- unsigned char vibrato_sweep;
- unsigned char vibrato_rate;
- unsigned char vibrato_depth;
- unsigned short scale_frequency;
- unsigned short scale_factor;/* 0-2048 or 0-2 */
- } patch;
-
- gus_wave_t *next;
-};
-
-/* defines for gus_memory_reset () */
-#define GUS_DOWNLOAD_MODE_NORMAL 0x0000
-#define GUS_DOWNLOAD_MODE_TEST 0x0001
-
-/*
- A subset of libgus functions (used by MikMod Ultrasound driver)
-*/
-int gus_cards(void);
- /*
- * return value: number of GUS cards installed in system or
- * zero if driver isn't installed
- */
-int gus_close(int card);
- /*
- * close file (gus synthesizer) previously opened with gusOpen function
- * return value: zero if success
- */
-int gus_do_flush(void);
- /*
- * return value: zero if command queue was successfully flushed
- * in non block mode - number of written bytes
- */
-void gus_do_tempo(unsigned int tempo);
- /*
- * set new tempo
- */
-void gus_do_voice_frequency(unsigned char voice, unsigned int freq);
- /*
- * set voice frequency in Hz
- */
-void gus_do_voice_pan(unsigned char voice, unsigned short pan);
- /*
- * set voice pan (0-16384) (full left - full right)
- */
-void gus_do_voice_start(unsigned char voice, unsigned int program,
- unsigned int freq, unsigned short volume,
- unsigned short pan);
- /*
- * start voice
- * voice : voice #
- * program : program # or ~0 = current
- * freq : frequency in Hz
- * volume : volume level (0-16384) or ~0 = current
- * pan : pan level (0-16384) or ~0 = current
- */
-void gus_do_voice_start_position(unsigned char voice, unsigned int program,
- unsigned int freq, unsigned short volume,
- unsigned short pan, unsigned int position);
- /*
- * start voice
- * voice : voice #
- * program : program # or ~0 = current
- * freq : frequency in Hz
- * volume : volume level (0-16384) or ~0 = current
- * pan : pan level (0-16384) or ~0 = current
- * position : offset to wave in bytes * 16 (lowest 4 bits - fraction)
- */
-void gus_do_voice_stop(unsigned char voice, unsigned char mode);
- /*
- * stop voice
- * mode = 0 : stop voice now
- * mode = 1 : disable wave loop and finish it
- */
-void gus_do_voice_volume(unsigned char voice, unsigned short vol);
- /*
- * set voice volume level 0-16384 (linear)
- */
-void gus_do_wait(unsigned int ticks);
- /*
- * wait x ticks - this command is block separator
- * all commands between blocks are interpreted in the begining of one tick
- */
-int gus_get_voice_status(int voice);
- /*
- * THIS IS NOT A FUNCTION OF ORIGINAL libGUS!
- * Return voice status: -1 on error, 0 if voice stopped, 1 if playing
- */
-int gus_get_handle(void);
- /*
- * return value: file handle (descriptor) for /dev/gus
- */
-int gus_info(gus_info_t * info, int reread);
- /*
- * return value: filled info variable with actual values
- * (look at gus.h header file for more informations)
- * version field: 0x0024 - GUS revision 2.4
- * 0x0035 - GUS revision 3.7 with flipped mixer channels
- * 0x0037 - GUS revision 3.7
- * 0x0090 - GUS ACE
- * 0x00a0 - GUS MAX revision 10
- * 0x00a1 - GUS MAX revision 11
- * 0x0100 - InterWave (full version)
- * flags field: see to GUS_STRU_INFO_F_???? constants (gus.h header file)
- * port field: port number (for example 0x220)
- * irq field: irq number (for example 11)
- * dma1 field: dma1 number (for example 5)
- * dma2 field: dma2 number (for example 6)
- * note: dma1 and dma2 could be same in case of only one dma channel used
- */
-int gus_memory_alloc(gus_instrument_t * instrument);
- /*
- * input value: look at gus.h for more details about gus_instrument_t structure
- * return value: zero if instrument was successfully allocated
- */
-int gus_memory_free(gus_instrument_t * instrument);
- /*
- * input value: look at gus.h for more details about gus_instrument_t structure
- * return value: zero if instrument was successfully removed
- */
-int gus_memory_size(void);
- /*
- * return value: gus memory size in bytes
- */
-int gus_memory_free_size(void);
- /*
- * return value: unused gus memory in bytes
- * warning: reset function must be called before
- */
-int gus_memory_free_block(int w_16bit);
- /*
- * return value: current largest free block for 8-bit or 16-bit wave
- */
-int gus_memory_pack(void);
- /*
- * return value: zero if success
- */
-int gus_memory_reset(int mode);
- /*
- * input value: see to GUS_DOWNLOAD_MODE_XXXX constants (gus.h)
- * return value: zero if samples & instruments was successfully removed
- * from GF1 memory manager
- */
-
-int gus_open(int card, size_t queue_buffer_size, int non_block);
- /*
- * input values: card number,
- * size of command queue buffer (512-1MB)
- * buffer is allocated dynamically,
- * non block mode
- * return value: zero if success
- * note 1: this function must be called as first
- * open file /dev/gus
- * note 2: you can open more cards with one process
- */
-int gus_queue_flush(void);
- /*
- * return value: zero if command queue was successfully flushed
- */
-int gus_queue_read_set_size(int items);
- /*
- * input value: echo buffer size in items (if 0 - erase echo buffer)
- */
-int gus_queue_write_set_size(int items);
- /*
- * input value: write queue size in items (each item have 8 bytes)
- */
-int gus_reset(int voices, unsigned int channel_voices);
- /*
- * input values: active voices and channel voices (for dynamic allocation)
- * return value: number of active voices if reset was successfull (GF1 chip active)
- */
-int gus_reset_engine_only(void);
- /*
- * return value: same as gus_reset function
- * note: this command doesn't change number of active
- * voices and doesn't do hardware reset
- */
-int gus_select(int card);
- /*
- * select specified card
- * return value: zero if success
- */
-int gus_timer_start(void);
- /*
- * return value: zero if successfull
- */
-int gus_timer_stop(void);
- /*
- * return value: zero if timer was stoped
- */
-int gus_timer_continue(void);
- /*
- * return value: zero if timer will be continue
- */
-int gus_timer_tempo(int ticks);
- /*
- * return value: zero if setup was success
- */
-int gus_timer_base(int base);
- /*
- * return value: zero if setup was success (default timebase = 100)
- */
-
-void gus_convert_delta(unsigned int type, unsigned char *dest,
- unsigned char *src, size_t size);
- /*
- * note: dest and src pointers can be equal
- */
-
-void gus_timer_callback(void (*timer_callback) ());
- /*
- * Set a callback to be called once per tempo tick
- */
-
-int gus_dma_usage (int use);
- /*
- * Tell GUS library to use/to not use DMA for sample transfer.
- * In some environments/on some hardware platforms you will need
- * to disable DMA in order to function properly. You should call
- * this function before opening the card.
- */
-
-#endif /* __LIBGUS_H__ */
-
-/* ex:set ts=4: */
+++ /dev/null
-#include <stdlib.h>
-#include "music.h"
-#include "mikmod.h"
-
-static void update_callback(void);
-
-static UNIMOD *mod;
-static int initialized;
-
-static int init(void)
-{
- md_mixfreq = 44100;
- md_dmabufsize = 20000;
- md_mode = DMODE_STEREO | DMODE_16BITS | DMODE_INTERP;
- md_device = 0;
-
- ML_RegisterLoader(&load_m15);
- ML_RegisterLoader(&load_mod);
- ML_RegisterLoader(&load_mtm);
- ML_RegisterLoader(&load_s3m);
- ML_RegisterLoader(&load_stm);
- ML_RegisterLoader(&load_ult);
- ML_RegisterLoader(&load_uni);
- ML_RegisterLoader(&load_xm);
-
- MD_RegisterDriver(&drv_nos);
- MD_RegisterDriver(&drv_ss);
- MD_RegisterDriver(&drv_sb);
- MD_RegisterDriver(&drv_gus);
-
- MD_RegisterPlayer(update_callback);
-
- if(!MD_Init()) {
- fprintf(stderr, "mikmod init failed: %s\n", myerr);
- return -1;
- }
- printf("using mikmod driver %s\n", md_driver->Name);
- printf(" %d bits, %s, %s mixing at %d Hz\n", md_mode & DMODE_16BITS ? 16 : 8,
- md_mode & DMODE_STEREO ? "stereo" : "mono",
- md_mode & DMODE_INTERP ? "interpolated" : "normal",
- md_mixfreq);
-
- atexit(MD_Exit);
- return 0;
-}
-
-int music_open(const char *fname)
-{
- if(!initialized) {
- if(init() == -1) {
- return -1;
- }
- initialized = 1;
- }
-
- if(!(mod = ML_LoadFN((const signed char*)fname))) {
- fprintf(stderr, "failed to load music: %s: %s\n", fname, myerr);
- return -1;
- }
-
- MP_Init(mod);
- md_numchn = mod->numchn;
- printf("opened module %s (%d channels)\n", fname, md_numchn);
- return 0;
-}
-
-void music_close(void)
-{
- if(mod) {
- printf("shutting down music playback\n");
- music_stop();
- ML_Free(mod);
- mod = 0;
- }
-}
-
-void music_play(void)
-{
- MD_PlayStart();
-}
-
-void music_stop(void)
-{
- MD_PlayStop();
-}
-
-void music_update(void)
-{
- MD_Update();
-}
-
-static void update_callback(void)
-{
- MP_HandleTick();
- MD_SetBPM(mp_bpm);
-}
--- /dev/null
+#include <stdlib.h>
+#include "music.h"
+#include "mikmod.h"
+
+#ifdef __WATCOMC__
+#define USE_OLDMIK
+typedef UNIMOD MODULE;
+
+static void update_callback(void);
+static void MikMod_RegisterAllDrivers(void);
+static void MikMod_RegisterAllLoaders(void);
+#else
+#define USE_NEWMIK
+#endif
+
+static MODULE *mod;
+static int initialized;
+
+static int init(void)
+{
+ MikMod_RegisterAllDrivers();
+ MikMod_RegisterAllLoaders();
+
+#ifdef USE_NEWMIK
+ md_mode |= DMODE_SOFT_MUSIC | DMODE_16BITS | DMODE_STEREO | DMODE_INTERP;
+ if(MikMod_Init("") != 0) {
+ fprintf(stderr, "mikmod init failed: %s\n",
+ MikMod_strerror(MikMod_errno));
+ return -1;
+ }
+
+#else
+ md_mixfreq = 44100;
+ md_dmabufsize = 20000;
+ md_mode = DMODE_STEREO | DMODE_16BITS | DMODE_INTERP;
+ md_device = 0;
+
+ MD_RegisterPlayer(update_callback);
+
+ if(!MD_Init()) {
+ fprintf(stderr, "mikmod init failed: %s\n", myerr);
+ return -1;
+ }
+ printf("using mikmod driver %s\n", md_driver->Name);
+ printf(" %d bits, %s, %s mixing at %d Hz\n", md_mode & DMODE_16BITS ? 16 : 8,
+ md_mode & DMODE_STEREO ? "stereo" : "mono",
+ md_mode & DMODE_INTERP ? "interpolated" : "normal",
+ md_mixfreq);
+
+ atexit(MD_Exit);
+#endif
+ return 0;
+}
+
+int music_open(const char *fname)
+{
+ if(!initialized) {
+ if(init() == -1) {
+ return -1;
+ }
+ initialized = 1;
+ }
+
+#ifdef USE_NEWMIK
+ if(!(mod = Player_Load(fname, 64, 0))) {
+ fprintf(stderr, "failed to load music: %s: %s\n", fname,
+ MikMod_strerror(MikMod_errno));
+ return -1;
+ }
+#else
+ if(!(mod = ML_LoadFN((const signed char*)fname))) {
+ fprintf(stderr, "failed to load music: %s: %s\n", fname, myerr);
+ return -1;
+ }
+
+ MP_Init(mod);
+ md_numchn = mod->numchn;
+ printf("opened module %s (%d channels)\n", fname, md_numchn);
+#endif
+ return 0;
+}
+
+void music_close(void)
+{
+ if(mod) {
+ printf("shutting down music playback\n");
+ music_stop();
+#ifdef USE_NEWMIK
+ Player_Free(mod);
+#else
+ ML_Free(mod);
+#endif
+ mod = 0;
+ }
+}
+
+void music_play(void)
+{
+#ifdef USE_NEWMIK
+ Player_Start(mod);
+#else
+ MD_PlayStart();
+#endif
+}
+
+void music_stop(void)
+{
+#ifdef USE_NEWMIK
+ Player_Stop();
+#else
+ MD_PlayStop();
+#endif
+}
+
+void music_update(void)
+{
+#ifdef USE_NEWMIK
+ if(Player_Active()) {
+ MikMod_Update();
+ }
+#else
+ MD_Update();
+#endif
+}
+
+#ifdef USE_OLDMIK
+static void update_callback(void)
+{
+ MP_HandleTick();
+ MD_SetBPM(mp_bpm);
+}
+
+static void MikMod_RegisterAllDrivers(void)
+{
+ MD_RegisterDriver(&drv_nos);
+ MD_RegisterDriver(&drv_ss);
+ MD_RegisterDriver(&drv_sb);
+ MD_RegisterDriver(&drv_gus);
+}
+
+static void MikMod_RegisterAllLoaders(void)
+{
+ ML_RegisterLoader(&load_m15);
+ ML_RegisterLoader(&load_mod);
+ ML_RegisterLoader(&load_mtm);
+ ML_RegisterLoader(&load_s3m);
+ ML_RegisterLoader(&load_stm);
+ ML_RegisterLoader(&load_ult);
+ ML_RegisterLoader(&load_uni);
+ ML_RegisterLoader(&load_xm);
+}
+#endif
+++ /dev/null
-#include "music.h"
-#include "mikmod.h"
-
-static MODULE *mod;
-static int initialized;
-
-
-static int init(void)
-{
- MikMod_RegisterAllDrivers();
- MikMod_RegisterAllLoaders();
-
- md_mode |= DMODE_SOFT_MUSIC | DMODE_16BITS | DMODE_STEREO | DMODE_INTERP;
- if(MikMod_Init("") != 0) {
- fprintf(stderr, "mikmod init failed: %s\n",
- MikMod_strerror(MikMod_errno));
- return -1;
- }
- return 0;
-}
-
-int music_open(const char *fname)
-{
- if(!initialized) {
- if(init() == -1) {
- return -1;
- }
- initialized = 1;
- }
-
- if(!(mod = Player_Load(fname, 64, 0))) {
- fprintf(stderr, "failed to load music: %s: %s\n", fname,
- MikMod_strerror(MikMod_errno));
- return -1;
- }
- return 0;
-}
-
-void music_close(void)
-{
- if(mod) {
- music_stop();
- Player_Free(mod);
- mod = 0;
- }
-}
-
-void music_play(void)
-{
- Player_Start(mod);
-}
-
-void music_stop(void)
-{
- Player_Stop();
-}
-
-void music_update(void)
-{
- if(Player_Active()) {
- MikMod_Update();
- }
-}