From b2c24e9d5b637bb78d18a377d9957c07d0759030 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Tue, 16 Jun 2020 07:08:58 +0300 Subject: [PATCH] dropping SDL for the cross-platform version almost done --- GNUmakefile | 3 +- libs/mikmod/config.h | 90 +- libs/mikmod/drivers/dos/dosdma.c | 214 ----- libs/mikmod/drivers/dos/dosdma.h | 190 ---- libs/mikmod/drivers/dos/dosgus.c | 1907 -------------------------------------- libs/mikmod/drivers/dos/dosgus.h | 514 ---------- libs/mikmod/drivers/dos/dosirq.c | 323 ------- libs/mikmod/drivers/dos/dosirq.h | 122 --- libs/mikmod/drivers/dos/dossb.c | 575 ------------ libs/mikmod/drivers/dos/dossb.h | 341 ------- libs/mikmod/drivers/dos/doswss.c | 577 ------------ libs/mikmod/drivers/dos/doswss.h | 217 ----- libs/mikmod/drivers/dos/libgus.h | 402 -------- libs/mikmod/drivers/drv_alsa.c | 490 ++++++++++ libs/mikmod/drivers/drv_ds.c | 417 +++++++++ libs/mikmod/drivers/drv_sb.c | 235 ----- libs/mikmod/drivers/drv_sgi.c | 229 +++++ libs/mikmod/drivers/drv_ultra.c | 1020 -------------------- libs/mikmod/drivers/drv_wss.c | 217 ----- libs/mikmod/posix/strcasecmp.c | 23 - libs/mikmod/posix/strccmp.c | 23 + src/cfgopt.c | 10 + src/cfgopt.h | 10 + src/demo.h | 1 + 24 files changed, 1209 insertions(+), 6941 deletions(-) delete mode 100644 libs/mikmod/drivers/dos/dosdma.c delete mode 100644 libs/mikmod/drivers/dos/dosdma.h delete mode 100644 libs/mikmod/drivers/dos/dosgus.c delete mode 100644 libs/mikmod/drivers/dos/dosgus.h delete mode 100644 libs/mikmod/drivers/dos/dosirq.c delete mode 100644 libs/mikmod/drivers/dos/dosirq.h delete mode 100644 libs/mikmod/drivers/dos/dossb.c delete mode 100644 libs/mikmod/drivers/dos/dossb.h delete mode 100644 libs/mikmod/drivers/dos/doswss.c delete mode 100644 libs/mikmod/drivers/dos/doswss.h delete mode 100644 libs/mikmod/drivers/dos/libgus.h create mode 100644 libs/mikmod/drivers/drv_alsa.c create mode 100644 libs/mikmod/drivers/drv_ds.c delete mode 100644 libs/mikmod/drivers/drv_sb.c create mode 100644 libs/mikmod/drivers/drv_sgi.c delete mode 100644 libs/mikmod/drivers/drv_ultra.c delete mode 100644 libs/mikmod/drivers/drv_wss.c delete mode 100644 libs/mikmod/posix/strcasecmp.c create mode 100644 libs/mikmod/posix/strccmp.c diff --git a/GNUmakefile b/GNUmakefile index a6c9936..c6e94c2 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -1,4 +1,5 @@ -src = $(wildcard src/*.c) $(wildcard src/scr/*.c) $(wildcard src/glut/*.c) +src = $(wildcard src/*.c) $(wildcard src/3dgfx/*.c) $(wildcard src/scr/*.c) \ + $(wildcard src/glut/*.c) asmsrc = $(wildcard src/*.asm) obj = $(src:.c=.o) $(asmsrc:.asm=.o) dep = $(obj:.o=.d) diff --git a/libs/mikmod/config.h b/libs/mikmod/config.h index 24caf3c..1872753 100644 --- a/libs/mikmod/config.h +++ b/libs/mikmod/config.h @@ -1,87 +1,51 @@ +#ifndef MIKMOD_CONFIG_H_ +#define MIKMOD_CONFIG_H_ + +#define HAVE_INTTYPES_H 1 #define HAVE_LIMITS_H 1 +#define HAVE_MALLOC_H 1 #define HAVE_MEMCMP 1 +#define HAVE_MEMORY_H 1 +#define HAVE_POSIX_MEMALIGN 1 +#define HAVE_SETENV 1 #define HAVE_STDLIB_H 1 +#define HAVE_STRINGS_H 1 #define HAVE_STRING_H 1 #define HAVE_STRSTR 1 -#ifdef DOS -#define DRV_SB 1 -#define DRV_ULTRA 1 -#define DRV_WSS 1 - -#define HAVE_UNISTD_H 1 -#define HAVE_FCNTL_H 1 -#define HAVE_SYS_STAT_H 1 -#define HAVE_SYS_TYPES_H 1 -#define HAVE_SYS_IOCTL_H 1 +#if !defined(_MSC_VER) || _MSC_VER >= 1800 +#define HAVE_STDINT_H 1 +#define HAVE_SNPRINTF 1 #endif -#if defined(__unix__) || defined(__APPLE__) -#define DRV_SDL 1 - +#ifdef __unix__ +#define HAVE_DLFCN_H 1 +#define HAVE_RTLD_GLOBAL 1 #define HAVE_FCNTL_H 1 -#define HAVE_INTTYPES_H 1 #define HAVE_SYS_IOCTL_H 1 -#define HAVE_SNPRINTF 1 #define HAVE_SYS_STAT_H 1 #define HAVE_SYS_TYPES_H 1 #define HAVE_SYS_WAIT_H 1 #define HAVE_UNISTD_H 1 -#define HAVE_POSIX_MEMALIGN 1 #define HAVE_PTHREAD 1 -#define HAVE_SETENV 1 -#define HAVE_SRANDOM 1 - -#define MIKMOD_UNIX 1 #endif +#define STDC_HEADERS 1 -#if defined(WIN32) -#define DRV_SDL 1 - -#define HAVE_WINDOWS_H 1 -#define HAVE_MALLOC_H 1 - -#define NO_SDL_CONFIG 1 +#ifdef __linux__ +#define DRV_ALSA 1 #endif -#undef MIKMOD_DEBUG - -/* disable the high quality mixer (build only with the standart mixer) */ -#undef NO_HQMIXER - -/* Name of package */ -#undef PACKAGE -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT -/* Define to the full name of this package. */ -#undef PACKAGE_NAME -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME -/* Define to the home page for this package. */ -#undef PACKAGE_URL -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* Version number of package */ -#undef VERSION +#ifdef __FreeBSD__ +#define DRV_OSS 1 +#endif -/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most - significant byte first (like Motorola and SPARC, unlike Intel). */ -#if defined AC_APPLE_UNIVERSAL_BUILD -# if defined __BIG_ENDIAN__ -# define WORDS_BIGENDIAN 1 -# endif -#else -# ifndef WORDS_BIGENDIAN -# undef WORDS_BIGENDIAN -# endif +#ifdef __sgi__ +#define DRV_SGI 1 #endif -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#if !defined(__cplusplus) && defined(_MSC_VER) -#define inline __inline +#ifdef _WIN32 +#define DRV_DS 1 #endif + +#endif /* MIKMOD_CONFIG_H_ */ diff --git a/libs/mikmod/drivers/dos/dosdma.c b/libs/mikmod/drivers/dos/dosdma.c deleted file mode 100644 index e232c30..0000000 --- a/libs/mikmod/drivers/dos/dosdma.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - Implementation of DMA routines on DOS - Copyright (C) 1999 by Andrew Zabolotny, - - 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 /* includes sys/version.h (djgpp >= 2.02) */ -#include -#include -#include -#include -#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: */ diff --git a/libs/mikmod/drivers/dos/dosdma.h b/libs/mikmod/drivers/dos/dosdma.h deleted file mode 100644 index 882c9ac..0000000 --- a/libs/mikmod/drivers/dos/dosdma.h +++ /dev/null @@ -1,190 +0,0 @@ -/* - Interface for DMA routines on DOS - Copyright (C) 1999 by Andrew Zabolotny, - - 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 - -#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: */ diff --git a/libs/mikmod/drivers/dos/dosgus.c b/libs/mikmod/drivers/dos/dosgus.c deleted file mode 100644 index 637b526..0000000 --- a/libs/mikmod/drivers/dos/dosgus.c +++ /dev/null @@ -1,1907 +0,0 @@ -/* 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 - -==============================================================================*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef DRV_ULTRA - -#include -#include -#include -#include -#include -#include -#include -#include - -#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: */ diff --git a/libs/mikmod/drivers/dos/dosgus.h b/libs/mikmod/drivers/dos/dosgus.h deleted file mode 100644 index ae3488a..0000000 --- a/libs/mikmod/drivers/dos/dosgus.h +++ /dev/null @@ -1,514 +0,0 @@ -/* 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 -#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: */ diff --git a/libs/mikmod/drivers/dos/dosirq.c b/libs/mikmod/drivers/dos/dosirq.c deleted file mode 100644 index 9b0e21f..0000000 --- a/libs/mikmod/drivers/dos/dosirq.c +++ /dev/null @@ -1,323 +0,0 @@ -/* - Implementation of IRQ routines on DOS - Copyright (C) 1999 by Andrew Zabolotny, - - 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 -#include -#include -#include -#include -#include -#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 - -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: */ diff --git a/libs/mikmod/drivers/dos/dosirq.h b/libs/mikmod/drivers/dos/dosirq.h deleted file mode 100644 index eaf60a1..0000000 --- a/libs/mikmod/drivers/dos/dosirq.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - Interface for IRQ routines on DOS - Copyright (C) 1999 by Andrew Zabolotny, - - 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 - -#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: */ diff --git a/libs/mikmod/drivers/dos/dossb.c b/libs/mikmod/drivers/dos/dossb.c deleted file mode 100644 index 344ac85..0000000 --- a/libs/mikmod/drivers/dos/dossb.c +++ /dev/null @@ -1,575 +0,0 @@ -/* 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 - -==============================================================================*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef DRV_SB - -#include -#include -#include -#include -#include -#include -#include - -#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: */ diff --git a/libs/mikmod/drivers/dos/dossb.h b/libs/mikmod/drivers/dos/dossb.h deleted file mode 100644 index cb8dc70..0000000 --- a/libs/mikmod/drivers/dos/dossb.h +++ /dev/null @@ -1,341 +0,0 @@ -/* 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: */ diff --git a/libs/mikmod/drivers/dos/doswss.c b/libs/mikmod/drivers/dos/doswss.c deleted file mode 100644 index 41cdf38..0000000 --- a/libs/mikmod/drivers/dos/doswss.c +++ /dev/null @@ -1,577 +0,0 @@ -/* 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 - -==============================================================================*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef DRV_WSS - -#include -#include -#include -#include -#include -#include -#include - -#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: */ diff --git a/libs/mikmod/drivers/dos/doswss.h b/libs/mikmod/drivers/dos/doswss.h deleted file mode 100644 index ae77bb5..0000000 --- a/libs/mikmod/drivers/dos/doswss.h +++ /dev/null @@ -1,217 +0,0 @@ -/* 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: */ diff --git a/libs/mikmod/drivers/dos/libgus.h b/libs/mikmod/drivers/dos/libgus.h deleted file mode 100644 index 0d66ee9..0000000 --- a/libs/mikmod/drivers/dos/libgus.h +++ /dev/null @@ -1,402 +0,0 @@ -/* 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 - -#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: */ diff --git a/libs/mikmod/drivers/drv_alsa.c b/libs/mikmod/drivers/drv_alsa.c new file mode 100644 index 0000000..d18d15f --- /dev/null +++ b/libs/mikmod/drivers/drv_alsa.c @@ -0,0 +1,490 @@ +/* MikMod sound library + (c) 1998, 1999, 2000 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$ + + Driver for Advanced Linux Sound Architecture (ALSA) + +==============================================================================*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mikmod_internals.h" + +#ifdef DRV_ALSA + +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_MEMORY_H +#include +#endif + +#ifdef MIKMOD_DYNAMIC +#include +#endif +#include +#include + +#include +#if defined(SND_LIB_VERSION) && (SND_LIB_VERSION >= 0x20000) +#undef DRV_ALSA +#endif + +#if defined(SND_LIB_VERSION) && (SND_LIB_VERSION < 0x600) +#error ALSA Version too old. Please upgrade your Linux distribution. +#endif +#endif /* DRV_ALSA */ + +#ifdef DRV_ALSA + +#ifdef MIKMOD_DYNAMIC +/* runtime link with libasound */ +#ifndef HAVE_RTLD_GLOBAL +#define RTLD_GLOBAL (0) +#endif +static int (*alsa_pcm_subformat_mask_malloc)(snd_pcm_subformat_mask_t **); +static const char * (*alsa_strerror)(int); +static int (*alsa_pcm_resume)(snd_pcm_t *); +static int (*alsa_pcm_prepare)(snd_pcm_t *); +static int (*alsa_pcm_hw_params_any)(snd_pcm_t *, snd_pcm_hw_params_t *); +static int (*alsa_pcm_hw_params)(snd_pcm_t *, snd_pcm_hw_params_t *); +static int (*alsa_pcm_hw_params_current)(snd_pcm_t *, snd_pcm_hw_params_t *); +static int (*alsa_pcm_hw_params_set_access)(snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_access_t); +static int (*alsa_pcm_hw_params_set_format)(snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_format_t); +static int (*alsa_pcm_hw_params_set_rate_near)(snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int *, int *); +static int (*alsa_pcm_hw_params_set_channels_near)(snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int *); +static int (*alsa_pcm_hw_params_set_buffer_time_near)(snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int *, int *); +static int (*alsa_pcm_hw_params_set_period_time_near)(snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int *, int *); +static int (*alsa_pcm_hw_params_get_buffer_size)(const snd_pcm_hw_params_t *, snd_pcm_uframes_t *); +static int (*alsa_pcm_hw_params_get_period_size)(const snd_pcm_hw_params_t *, snd_pcm_uframes_t *, int *); +static int (*alsa_pcm_sw_params_sizeof)(void); +static int (*alsa_pcm_hw_params_sizeof)(void); +static int (*alsa_pcm_open)(snd_pcm_t**, const char *, int, int); +static int (*alsa_pcm_close)(snd_pcm_t*); +static int (*alsa_pcm_drain)(snd_pcm_t*); +static int (*alsa_pcm_drop)(snd_pcm_t*); +static int (*alsa_pcm_start)(snd_pcm_t *); +static snd_pcm_sframes_t (*alsa_pcm_writei)(snd_pcm_t*,const void*,snd_pcm_uframes_t); + +static void* libasound = NULL; + +#else +/* compile-time link with libasound */ +#define alsa_pcm_subformat_mask_malloc snd_pcm_subformat_mask_malloc +#define alsa_strerror snd_strerror +#define alsa_pcm_hw_params_any snd_pcm_hw_params_any +#define alsa_pcm_hw_params snd_pcm_hw_params +#define alsa_pcm_hw_params_current snd_pcm_hw_params_current +#define alsa_pcm_hw_params_set_access snd_pcm_hw_params_set_access +#define alsa_pcm_hw_params_set_format snd_pcm_hw_params_set_format +#define alsa_pcm_hw_params_set_rate_near snd_pcm_hw_params_set_rate_near +#define alsa_pcm_hw_params_set_channels_near snd_pcm_hw_params_set_channels_near +#define alsa_pcm_hw_params_set_buffer_time_near snd_pcm_hw_params_set_buffer_time_near +#define alsa_pcm_hw_params_set_period_time_near snd_pcm_hw_params_set_period_time_near +#define alsa_pcm_hw_params_get_buffer_size snd_pcm_hw_params_get_buffer_size +#define alsa_pcm_hw_params_get_period_size snd_pcm_hw_params_get_period_size +#define alsa_pcm_resume snd_pcm_resume +#define alsa_pcm_prepare snd_pcm_prepare +#define alsa_pcm_close snd_pcm_close +#define alsa_pcm_drain snd_pcm_drain +#define alsa_pcm_drop snd_pcm_drop +#define alsa_pcm_start snd_pcm_start +#define alsa_pcm_open snd_pcm_open +#define alsa_pcm_writei snd_pcm_writei +#endif /* MIKMOD_DYNAMIC */ + +#if defined(MIKMOD_DEBUG) +# define dbgprint fprintf +#elif defined (__GNUC__) && !(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) +# define dbgprint(f, fmt, args...) do {} while (0) +#else +# define dbgprint(f, ...) do {} while (0) +#endif +static BOOL enabled = 0; +static snd_pcm_t *pcm_h = NULL; +static SBYTE *audiobuffer = NULL; +static snd_pcm_sframes_t period_size; +static int bytes_written = 0, bytes_played = 0; +static int global_frame_size; + +#ifdef MIKMOD_DYNAMIC +static int ALSA_Link(void) +{ + if (libasound) return 0; + + /* load libasound.so */ + libasound = dlopen("libasound.so.2",RTLD_LAZY|RTLD_GLOBAL); + if (!libasound) libasound = dlopen("libasound.so",RTLD_LAZY|RTLD_GLOBAL); + if (!libasound) return 1; + + if (!(alsa_pcm_subformat_mask_malloc = (int (*)(snd_pcm_subformat_mask_t **)) + dlsym(libasound,"snd_pcm_subformat_mask_malloc"))) return 1; + if (!(alsa_strerror = (const char* (*)(int)) + dlsym(libasound,"snd_strerror"))) return 1; + if (!(alsa_pcm_prepare = (int (*)(snd_pcm_t *)) + dlsym(libasound,"snd_pcm_prepare"))) return 1; + if (!(alsa_pcm_sw_params_sizeof = (int (*)(void)) + dlsym(libasound,"snd_pcm_sw_params_sizeof"))) return 1; + if (!(alsa_pcm_hw_params_sizeof = (int (*)(void)) + dlsym(libasound,"snd_pcm_hw_params_sizeof"))) return 1; + if (!(alsa_pcm_resume = (int (*)(snd_pcm_t *)) + dlsym(libasound,"snd_pcm_resume"))) return 1; + if (!(alsa_pcm_hw_params_any = (int (*)(snd_pcm_t *, snd_pcm_hw_params_t *)) + dlsym(libasound,"snd_pcm_hw_params_any"))) return 1; + if (!(alsa_pcm_hw_params = (int (*)(snd_pcm_t *, snd_pcm_hw_params_t *)) + dlsym(libasound,"snd_pcm_hw_params"))) return 1; + if (!(alsa_pcm_hw_params_current = (int (*)(snd_pcm_t *, snd_pcm_hw_params_t *)) + dlsym(libasound,"snd_pcm_hw_params_current"))) return 1; + if (!(alsa_pcm_hw_params_set_access = (int (*)(snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_access_t)) + dlsym(libasound,"snd_pcm_hw_params_set_access"))) return 1; + if (!(alsa_pcm_hw_params_set_format = (int (*)(snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_format_t)) + dlsym(libasound,"snd_pcm_hw_params_set_format"))) return 1; + if (!(alsa_pcm_hw_params_set_rate_near = (int (*)(snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int *, int *)) + dlsym(libasound,"snd_pcm_hw_params_set_rate_near"))) return 1; + if (!(alsa_pcm_hw_params_set_channels_near = (int (*)(snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int *)) + dlsym(libasound,"snd_pcm_hw_params_set_channels_near"))) return 1; + if (!(alsa_pcm_hw_params_set_buffer_time_near = (int (*)(snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int *, int *)) + dlsym(libasound,"snd_pcm_hw_params_set_buffer_time_near"))) return 1; + if (!(alsa_pcm_hw_params_set_period_time_near = (int (*)(snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int *, int *)) + dlsym(libasound,"snd_pcm_hw_params_set_period_time_near"))) return 1; + if (!(alsa_pcm_hw_params_get_buffer_size = (int (*)(const snd_pcm_hw_params_t *, snd_pcm_uframes_t *)) + dlsym(libasound,"snd_pcm_hw_params_get_buffer_size"))) return 1; + if (!(alsa_pcm_hw_params_get_period_size = (int (*)(const snd_pcm_hw_params_t *, snd_pcm_uframes_t *, int *)) + dlsym(libasound,"snd_pcm_hw_params_get_period_size"))) return 1; + if (!(alsa_pcm_open = (int (*)(snd_pcm_t**, const char *, int, int)) + dlsym(libasound,"snd_pcm_open"))) return 1; + if (!(alsa_pcm_close = (int (*)(snd_pcm_t*)) + dlsym(libasound,"snd_pcm_close"))) return 1; + if (!(alsa_pcm_drain = (int (*)(snd_pcm_t*)) + dlsym(libasound,"snd_pcm_drain"))) return 1; + if (!(alsa_pcm_drop = (int (*)(snd_pcm_t*)) + dlsym(libasound,"snd_pcm_drop"))) return 1; + if (!(alsa_pcm_start = (int (*)(snd_pcm_t *)) + dlsym(libasound,"snd_pcm_start"))) return 1; + if (!(alsa_pcm_writei = (snd_pcm_sframes_t (*)(snd_pcm_t*,const void*,snd_pcm_uframes_t)) + dlsym(libasound,"snd_pcm_writei"))) return 1; + + return 0; +} + +static void ALSA_Unlink(void) +{ + alsa_pcm_subformat_mask_malloc = NULL; + alsa_strerror = NULL; + alsa_pcm_resume = NULL; + alsa_pcm_prepare = NULL; + alsa_pcm_hw_params_any = NULL; + alsa_pcm_hw_params = NULL; + alsa_pcm_hw_params_current = NULL; + alsa_pcm_hw_params_set_access = NULL; + alsa_pcm_hw_params_set_format = NULL; + alsa_pcm_hw_params_set_rate_near = NULL; + alsa_pcm_hw_params_set_channels_near = NULL; + alsa_pcm_hw_params_set_buffer_time_near = NULL; + alsa_pcm_hw_params_set_period_time_near = NULL; + alsa_pcm_hw_params_get_buffer_size = NULL; + alsa_pcm_hw_params_get_period_size = NULL; + alsa_pcm_close = NULL; + alsa_pcm_drain = NULL; + alsa_pcm_drop = NULL; + alsa_pcm_start = NULL; + alsa_pcm_open = NULL; + alsa_pcm_writei = NULL; + + if (libasound) { + dlclose(libasound); + libasound = NULL; + } +} + +/* This is done to override the identifiers expanded + * in the macros provided by the ALSA includes which are + * not available. + * */ +#define snd_strerror alsa_strerror +#define snd_pcm_sw_params_sizeof alsa_pcm_sw_params_sizeof +#define snd_pcm_hw_params_sizeof alsa_pcm_hw_params_sizeof +#endif /* MIKMOD_DYNAMIC */ + +static void ALSA_CommandLine(const CHAR *cmdline) +{ + /* no options */ +} + +static BOOL ALSA_IsThere(void) +{ + snd_pcm_subformat_mask_t *ptr = NULL; + BOOL retval; + +#ifdef MIKMOD_DYNAMIC + if (ALSA_Link()) return 0; +#endif + retval = (alsa_pcm_subformat_mask_malloc(&ptr) == 0) && (ptr != NULL); + free(ptr); +#ifdef MIKMOD_DYNAMIC + ALSA_Unlink(); +#endif + return retval; +} + +static int ALSA_Init_internal(void) +{ + snd_pcm_format_t pformat; + unsigned int btime = 250000; /* 250ms */ + unsigned int ptime = 50000; /* 50ms */ + snd_pcm_uframes_t psize; + snd_pcm_uframes_t bsize; + unsigned int rate, channels; + snd_pcm_hw_params_t * hwparams; + int err; + + /* setup playback format structure */ + pformat = (md_mode&DMODE_FLOAT)? SND_PCM_FORMAT_FLOAT : + (md_mode&DMODE_16BITS)? SND_PCM_FORMAT_S16 : SND_PCM_FORMAT_U8; + channels = (md_mode&DMODE_STEREO)?2:1; + rate = md_mixfreq; + +#define MIKMOD_ALSA_DEVICE "default" + if ((err = alsa_pcm_open(&pcm_h, MIKMOD_ALSA_DEVICE, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) { + _mm_errno = MMERR_OPENING_AUDIO; + goto END; + } + + snd_pcm_hw_params_alloca(&hwparams); + err = alsa_pcm_hw_params_any(pcm_h, hwparams); + if (err < 0) { + _mm_errno = MMERR_ALSA_NOCONFIG; + goto END; + } + + err = alsa_pcm_hw_params_set_access(pcm_h, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); + if (!err) err = alsa_pcm_hw_params_set_format(pcm_h, hwparams, pformat); + if (!err) err = alsa_pcm_hw_params_set_rate_near(pcm_h, hwparams, &rate, NULL); + if (!err) err = alsa_pcm_hw_params_set_channels_near(pcm_h, hwparams, &channels); + if (!err) err = alsa_pcm_hw_params_set_buffer_time_near(pcm_h, hwparams, &btime, NULL); + if (!err) err = alsa_pcm_hw_params_set_period_time_near(pcm_h, hwparams, &ptime, NULL); + if (!err) err = alsa_pcm_hw_params(pcm_h, hwparams); + if (err < 0) { + _mm_errno = MMERR_ALSA_SETPARAMS; + goto END; + } + + if (rate != md_mixfreq) { + _mm_errno = MMERR_ALSA_SETRATE; + goto END; + } + if (!(md_mode&DMODE_STEREO) && channels != 1) { + _mm_errno = MMERR_ALSA_SETCHANNELS; + goto END; + } + if ((md_mode&DMODE_STEREO) && channels != 2) { + _mm_errno = MMERR_ALSA_SETCHANNELS; + goto END; + } + + err = alsa_pcm_hw_params_current(pcm_h, hwparams); + if (!err) err = alsa_pcm_hw_params_get_buffer_size(hwparams, &bsize); + if (!err) err = alsa_pcm_hw_params_get_period_size(hwparams, &psize, NULL); + if (err < 0) { + _mm_errno = MMERR_ALSA_BUFFERSIZE; + goto END; + } + + period_size = psize; + global_frame_size = channels * + ((md_mode&DMODE_FLOAT)? 4 : (md_mode&DMODE_16BITS)? 2 : 1); + + if (!(audiobuffer=(SBYTE*)MikMod_malloc(period_size * global_frame_size))) { + _mm_errno = MMERR_OUT_OF_MEMORY; + goto END; + } + + /* sound device is ready to work */ + if (!VC_Init()) { + enabled = 1; + return 0; + } +END: + alsa_pcm_close(pcm_h); + pcm_h = NULL; + return 1; +} + +static int ALSA_Init(void) +{ +#ifdef HAVE_SSE2 +/* TODO : Detect SSE2, then set md_mode |= DMODE_SIMDMIXER;*/ +#endif +#ifdef MIKMOD_DYNAMIC + if (ALSA_Link()) { + _mm_errno=MMERR_DYNAMIC_LINKING; + return 1; + } +#endif + return ALSA_Init_internal(); +} + +static void ALSA_Exit_internal(void) +{ + enabled = 0; + VC_Exit(); + if (pcm_h) { + alsa_pcm_drain(pcm_h); + alsa_pcm_close(pcm_h); + pcm_h = NULL; + } + MikMod_free(audiobuffer); + audiobuffer = NULL; +} + +static void ALSA_Exit(void) +{ + ALSA_Exit_internal(); +#ifdef MIKMOD_DYNAMIC + ALSA_Unlink(); +#endif +} + +/* Underrun and suspend recovery - from alsa-lib:test/pcm.c + */ +static int xrun_recovery(snd_pcm_t *handle, int err) +{ + if (err == -EPIPE) { /* under-run */ + err = alsa_pcm_prepare(handle); + if (err < 0) + dbgprint(stderr, "Can't recover from underrun, prepare failed: %s\n", snd_strerror(err)); + return 0; + } + else if (err == -ESTRPIPE) { + while ((err = alsa_pcm_resume(handle)) == -EAGAIN) + sleep(1); /* wait until the suspend flag is released */ + if (err < 0) { + err = alsa_pcm_prepare(handle); + if (err < 0) + dbgprint(stderr, "Can't recover from suspend, prepare failed: %s\n", snd_strerror(err)); + } + return 0; + } + return err; +} + +static void ALSA_Update(void) +{ + int err; + + if (!enabled) return; + + if (bytes_written == 0 || bytes_played == bytes_written) { + bytes_written = VC_WriteBytes(audiobuffer,period_size * global_frame_size); + bytes_played = 0; + } + + while (bytes_played < bytes_written) + { + err = alsa_pcm_writei(pcm_h, &audiobuffer[bytes_played], (bytes_written - bytes_played) / global_frame_size); + if (err == -EAGAIN) + continue; + if (err < 0) { + if ((err = xrun_recovery(pcm_h, err)) < 0) { + _mm_errno = MMERR_ALSA_PCM_RECOVER; + enabled = 0; + dbgprint(stderr, "Write error: %s\n", alsa_strerror(err)); + } + break; + } + bytes_played += err * global_frame_size; + } +} + +static int ALSA_PlayStart(void) +{ + int err; + + if (pcm_h == NULL) return 1; + err = alsa_pcm_prepare(pcm_h); + if (err == 0) + err = alsa_pcm_start(pcm_h); + if (err < 0) { + enabled = 0; + _mm_errno = MMERR_ALSA_PCM_START; + return 1; + } + + return VC_PlayStart(); +} + +static void ALSA_PlayStop(void) +{ + VC_PlayStop(); + if (pcm_h) alsa_pcm_drop(pcm_h); +} + +static int ALSA_Reset(void) +{ + ALSA_Exit_internal(); + return ALSA_Init_internal(); +} + +MIKMODAPI MDRIVER drv_alsa = { + NULL, + "ALSA", + "Advanced Linux Sound Architecture (ALSA) driver v1.11", + 0,255, + "alsa", + NULL, + ALSA_CommandLine, + ALSA_IsThere, + VC_SampleLoad, + VC_SampleUnload, + VC_SampleSpace, + VC_SampleLength, + ALSA_Init, + ALSA_Exit, + ALSA_Reset, + VC_SetNumVoices, + ALSA_PlayStart, + ALSA_PlayStop, + ALSA_Update, + NULL, + VC_VoiceSetVolume, + VC_VoiceGetVolume, + VC_VoiceSetFrequency, + VC_VoiceGetFrequency, + VC_VoiceSetPanning, + VC_VoiceGetPanning, + VC_VoicePlay, + VC_VoiceStop, + VC_VoiceStopped, + VC_VoiceGetPosition, + VC_VoiceRealVolume +}; + +#else + +MISSING(drv_alsa); + +#endif + +/* ex:set ts=8: */ diff --git a/libs/mikmod/drivers/drv_ds.c b/libs/mikmod/drivers/drv_ds.c new file mode 100644 index 0000000..69e4540 --- /dev/null +++ b/libs/mikmod/drivers/drv_ds.c @@ -0,0 +1,417 @@ +/* MikMod sound library + (c) 1998-2005 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$ + + Driver for output on win32 platforms using DirectSound + +==============================================================================*/ + +/* + + Written by Brian McKinney + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mikmod_internals.h" + +#ifdef DRV_DS + +#include +#include + +#define INITGUID +#if !defined(__cplusplus) && !defined(CINTERFACE) +#define CINTERFACE +#endif +#include + +#ifdef __WATCOMC__ +/* If you encounter build failures from Open Watcom's dsound.h, + * see: https://github.com/open-watcom/open-watcom-v2/pull/313 + */ +/* Open Watcom has broken __cdecl (leading underscore) name mangling for Windows + * internal var names. It is fixed in Open Watcom V2 fork as of May/2014: + * https://github.com/open-watcom/open-watcom-v2/commit/961ef1ff756f3ec5a7248cefcae00a6ecaa97ff4 + * Therefore, we define and use a local copy of IID_IDirectSoundNotify here. + */ +#include +DEFINE_GUID(IID_IDirectSoundNotify,0xB0210783,0x89cd,0x11d0,0xAF,0x08,0x00,0xA0,0xC9,0x25,0xCD,0x16); +#endif + +/* PF_XMMI64_INSTRUCTIONS_AVAILABLE not in all SDKs */ +#ifndef PF_XMMI64_INSTRUCTIONS_AVAILABLE +#define PF_XMMI64_INSTRUCTIONS_AVAILABLE 10 +#endif + +/* DSBCAPS_CTRLALL is not defined anymore with DirectX 7. Of course DirectSound + is a coherent, backwards compatible API... */ +#ifndef DSBCAPS_CTRLALL +#define DSBCAPS_CTRLALL ( DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_CTRLVOLUME | \ + DSBCAPS_CTRLPAN | DSBCAPS_CTRLFREQUENCY | \ + DSBCAPS_CTRL3D ) +#endif + +#ifndef WAVE_FORMAT_IEEE_FLOAT +#define WAVE_FORMAT_IEEE_FLOAT 0x0003 +#endif + +/* size of each buffer */ +#define FRAGSIZE 16 +/* buffer count */ +#define UPDATES 2 + +static LPDIRECTSOUND pSoundCard = NULL; +static LPDIRECTSOUNDBUFFER pPrimarySoundBuffer = NULL, pSoundBuffer = NULL; +static LPDIRECTSOUNDNOTIFY pSoundBufferNotify = NULL; + +static HANDLE notifyUpdateHandle = NULL, updateBufferHandle = NULL; +static BOOL threadInUse = FALSE; +static int fragsize=1<19)) buf=FRAGSIZE; + fragsize=1< - -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef DRV_SB - -#ifdef HAVE_UNISTD_H -#include -#endif -#ifdef HAVE_FCNTL_H -#include -#endif - -#include "mikmod_internals.h" - -#include "dossb.h" - -static void SB_CommandLine(const CHAR *cmdline) -{ - char *ptr, *end; - - if ((ptr=MD_GetAtom("port",cmdline,0)) != NULL) { - sb.port = strtol(ptr, &end, 16); - MikMod_free(ptr); - } - if ((ptr=MD_GetAtom("irq",cmdline,0)) != NULL) { - sb.irq = strtol(ptr, &end, 10); - MikMod_free(ptr); - } - if ((ptr=MD_GetAtom("dma",cmdline,0)) != NULL) { - sb.dma8 = strtol(ptr, &end, 10); - MikMod_free(ptr); - } - if ((ptr=MD_GetAtom("hidma",cmdline,0)) != NULL) { - sb.dma16 = strtol(ptr, &end, 10); - MikMod_free(ptr); - } -} - -static BOOL SB_IsThere(void) -{ - return sb_detect(); -} - -static int SB_Init(void) -{ - if (!sb_open()) { - _mm_errno = MMERR_INVALID_DEVICE; - return 1; - } - - /* Adjust md_mode according to sound card capabilities */ - if (!(sb.caps & SBMODE_STEREO)) - md_mode &= ~DMODE_STEREO; - if (!(sb.caps & SBMODE_16BITS)) - md_mode &= ~DMODE_16BITS; - - if (md_mixfreq < 4000) - md_mixfreq = 4000; - if (md_mode & DMODE_STEREO) { - if (md_mixfreq > sb.maxfreq_stereo) - md_mixfreq = sb.maxfreq_stereo; - } else { - if (md_mixfreq > sb.maxfreq_mono) - md_mixfreq = sb.maxfreq_mono; - } - - return VC_Init(); -} - -static void SB_Exit(void) -{ - VC_Exit(); - sb_close(); -} - -/* The last buffer byte filled with sound */ -static unsigned int buff_tail = 0; - -static void SB_Callback(void) -{ - unsigned int dma_size, dma_pos; - ULONG (*mixer)(SBYTE *buf, ULONG todo); - - sb_query_dma(&dma_size, &dma_pos); - /* There isn't much sense in filling less than 256 bytes */ - dma_pos &= ~255; - - /* If nothing to mix, quit */ - if (buff_tail == dma_pos) - return; - - if (Player_Paused_internal()) - mixer = VC_SilenceBytes; - else - mixer = VC_WriteBytes; - - /* If DMA pointer still didn't wrapped around ... */ - if (dma_pos > buff_tail) { - buff_tail += mixer ((SBYTE *)(sb.dma_buff->linear + buff_tail), dma_pos - buff_tail); - /* If we arrived right to the DMA buffer end, jump to the beginning */ - if (buff_tail >= dma_size) - buff_tail = 0; - } else { - /* If wrapped around, fill first to the end of buffer */ - mixer ((SBYTE *)(sb.dma_buff->linear + buff_tail), dma_size - buff_tail); - /* Now fill from buffer beginning to current DMA pointer */ - buff_tail = mixer ((SBYTE *)sb.dma_buff->linear, dma_pos); - } -} - -static void SB_Update(void) -{ - /* Do nothing: the real update is done during SB interrupts */ -} - -static int SB_PlayStart (void) -{ - if (VC_PlayStart()) - return 1; - - /* Enable speaker output */ - sb_output(TRUE); - - /* Set our routine to be called during SB IRQs */ - buff_tail = 0; - sb.timer_callback = SB_Callback; - - /* Start cyclic DMA transfer */ - if (!sb_start_dma(((md_mode & DMODE_16BITS) ? SBMODE_16BITS | SBMODE_SIGNED : 0) | - ((md_mode & DMODE_STEREO) ? SBMODE_STEREO : 0), md_mixfreq)) - { - _mm_errno = MMERR_DOSSB_STARTDMA; - return 1; - } - - return 0; -} - -static int SB_Reset(void) -{ - sb_reset(); - VC_Exit(); - return VC_Init(); -} - -static void SB_PlayStop(void) -{ - sb.timer_callback = NULL; - sb_output(FALSE); - sb_stop_dma(); - VC_PlayStop(); -} - -MDRIVER drv_sb = -{ - NULL, - "Sound Blaster", - "Sound Blaster Orig/2.0/Pro/16 v1.0", - 0, 255, - "sb", - "port:c:220,230,240,250,260,270,280,32C,530,604,E80,F40,220:Sound Blaster base I/O port\n" - "irq:c:2,3,5,7,10,5:Sound Blaster IRQ\n" - "dma:c:0,1,3,1:Sound Blaster 8 bit DMA channel\n" - "hidma:c:5,6,7,5:Sound Blaster 16 bit DMA channel (SB16/AWE32 only)\n", - - SB_CommandLine, - SB_IsThere, - VC_SampleLoad, - VC_SampleUnload, - VC_SampleSpace, - VC_SampleLength, - SB_Init, - SB_Exit, - SB_Reset, - VC_SetNumVoices, - SB_PlayStart, - SB_PlayStop, - SB_Update, - NULL, - VC_VoiceSetVolume, - VC_VoiceGetVolume, - VC_VoiceSetFrequency, - VC_VoiceGetFrequency, - VC_VoiceSetPanning, - VC_VoiceGetPanning, - VC_VoicePlay, - VC_VoiceStop, - VC_VoiceStopped, - VC_VoiceGetPosition, - VC_VoiceRealVolume -}; - -#else /* DRV_SB */ - -#include "mikmod_internals.h" -MISSING(drv_sb); - -#endif - -/* ex:set ts=4: */ diff --git a/libs/mikmod/drivers/drv_sgi.c b/libs/mikmod/drivers/drv_sgi.c new file mode 100644 index 0000000..4ad1c36 --- /dev/null +++ b/libs/mikmod/drivers/drv_sgi.c @@ -0,0 +1,229 @@ +/* MikMod sound library + (c) 1998, 1999, 2000 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$ + + Driver for output on SGI audio system (needs libaudio from the dmedia + package). + +==============================================================================*/ + +/* + + Written by Stephan Kanthak + + Fragment configuration: + ======================= + + You can use the driver options fragsize and bufsize to override the + default size of the audio buffer. If you experience crackles & pops, + try experimenting with these values. + + Please read the SGI section of libmikmod's README file first before + contacting the author because there are some things to know about the + specials of the SGI audio driver. + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mikmod_internals.h" + +#ifdef DRV_SGI + +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include + +#define DEFAULT_SGI_BUFSIZE 40000 +#define DEFAULT_SGI_FRAGSIZE (DEFAULT_SGI_BUFSIZE / 2) + +static ALconfig sgi_config; +static ALport sgi_port; +static int sample_factor; +static int sgi_fragsize=DEFAULT_SGI_FRAGSIZE; +static int sgi_bufsize=DEFAULT_SGI_BUFSIZE; +static SBYTE *audiobuffer=NULL; + +static void SGI_CommandLine(const CHAR *cmdline) +{ + CHAR *ptr; + + if ((ptr=MD_GetAtom("fragsize",cmdline,0)) != NULL) { + sgi_fragsize=atol(ptr); + MikMod_free(ptr); + } else sgi_fragsize=DEFAULT_SGI_FRAGSIZE; + + if ((ptr=MD_GetAtom("bufsize",cmdline,0)) != NULL) { + sgi_bufsize=atol(ptr); + MikMod_free(ptr); + } else sgi_bufsize=DEFAULT_SGI_BUFSIZE; +} + +static BOOL SGI_IsThere(void) +{ + ALseterrorhandler(0); + return(ALqueryparams(AL_DEFAULT_DEVICE,0,0))?1:0; +} + +static int SGI_Init(void) +{ + long chpars[] = { AL_OUTPUT_RATE, AL_RATE_22050 }; + + switch(md_mixfreq) { + case 8000: + chpars[1] = AL_RATE_8000; + break; + case 11025: + chpars[1] = AL_RATE_11025; + break; + case 16000: + chpars[1] = AL_RATE_16000; + break; + case 22050: + chpars[1] = AL_RATE_22050; + break; + case 32000: + chpars[1] = AL_RATE_32000; + break; + case 44100: + chpars[1] = AL_RATE_44100; + break; + case 48000: + chpars[1] = AL_RATE_48000; + break; + default: + _mm_errno=MMERR_SGI_SPEED; + return 1; + } + ALseterrorhandler(0); + ALsetparams(AL_DEFAULT_DEVICE, chpars, 2); + + if (!(sgi_config=ALnewconfig())) { + _mm_errno=MMERR_OPENING_AUDIO; + return 1; + } + + if (md_mode&DMODE_16BITS) { + if (ALsetwidth(sgi_config,AL_SAMPLE_16)<0) { + _mm_errno=MMERR_SGI_16BIT; + return 1; + } + sample_factor = 1; + } else { + if (ALsetwidth(sgi_config,AL_SAMPLE_8)<0) { + _mm_errno=MMERR_SGI_8BIT; + return 1; + } + sample_factor = 0; + } + + if (md_mode&DMODE_STEREO) { + if (ALsetchannels(sgi_config,AL_STEREO)<0) { + _mm_errno=MMERR_SGI_STEREO; + return 1; + } + } else { + if (ALsetchannels(sgi_config,AL_MONO)<0) { + _mm_errno=MMERR_SGI_MONO; + return 1; + } + } + + if ((getenv("MM_SGI_FRAGSIZE"))&&(sgi_fragsize!=DEFAULT_SGI_FRAGSIZE)) + sgi_fragsize=atol(getenv("MM_SGI_FRAGSIZE")); + if (!sgi_fragsize) sgi_fragsize=DEFAULT_SGI_FRAGSIZE; + if ((getenv("MM_SGI_BUFSIZE"))&&(sgi_bufsize!=DEFAULT_SGI_BUFSIZE)) + sgi_bufsize=atol(getenv("MM_SGI_BUFSIZE")); + if (!sgi_bufsize) sgi_fragsize=DEFAULT_SGI_BUFSIZE; + + ALsetqueuesize(sgi_config, sgi_bufsize); + if (!(sgi_port=ALopenport("libmikmod","w",sgi_config))) { + _mm_errno=MMERR_OPENING_AUDIO; + return 1; + } + + if(!(audiobuffer=(SBYTE*)MikMod_malloc(sgi_fragsize))) return 1; + + return VC_Init(); +} + +static void SGI_Exit(void) +{ + VC_Exit(); + MikMod_free(audiobuffer); + audiobuffer=NULL; +} + +static void SGI_Update(void) +{ + ALwritesamps(sgi_port,audiobuffer, + VC_WriteBytes(audiobuffer,sgi_fragsize)>>sample_factor); +} + +MIKMODAPI MDRIVER drv_sgi={ + NULL, + "SGI Audio System", + "SGI Audio System driver v0.5", + 0,255, + "sgi", + "fragsize:r:0,99999,20000:Sound buffer fragment size\n" + "bufsize:r:0,199999,40000:Sound buffer total size\n", + SGI_CommandLine, + SGI_IsThere, + VC_SampleLoad, + VC_SampleUnload, + VC_SampleSpace, + VC_SampleLength, + SGI_Init, + SGI_Exit, + NULL, + VC_SetNumVoices, + VC_PlayStart, + VC_PlayStop, + SGI_Update, + NULL, + VC_VoiceSetVolume, + VC_VoiceGetVolume, + VC_VoiceSetFrequency, + VC_VoiceGetFrequency, + VC_VoiceSetPanning, + VC_VoiceGetPanning, + VC_VoicePlay, + VC_VoiceStop, + VC_VoiceStopped, + VC_VoiceGetPosition, + VC_VoiceRealVolume +}; + +#else + +MISSING(drv_sgi); + +#endif + +/* ex:set ts=4: */ diff --git a/libs/mikmod/drivers/drv_ultra.c b/libs/mikmod/drivers/drv_ultra.c deleted file mode 100644 index dbd0b7c..0000000 --- a/libs/mikmod/drivers/drv_ultra.c +++ /dev/null @@ -1,1020 +0,0 @@ -/* 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$ - - Driver for Gravis Ultrasound cards using libGUS. - A subset of libGUS is provided for DOS/DJGPP and OS/2 - -==============================================================================*/ - -/* - - Written by Andy Lo A Foe - - Updated to work with later versions of both the ultrasound driver and - libmikmod by C. Ray C. - - Major fixes by Andrew Zabolotny - + Ported to OS/2 and DOS. - + Eight-bit samples are not converted to 16-bit anymore. - + Samples are no longer kept in normal memory. - + Removed sample 'unclick' logic... libGUS does unclick internally. - -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "mikmod_internals.h" - -#ifdef DRV_ULTRA - -#ifdef HAVE_UNISTD_H -#include -#endif -#ifdef HAVE_MEMORY_H -#include -#endif - -#ifdef MIKMOD_DYNAMIC -#include -#endif -#include -#include -#include - -#include - -#if !defined(GUS_INSTR_SIMPLE) || !defined(GUS_WAVE_BIDIR) -#error libgus version is too old -#endif -/* just in case */ -#ifndef LIBGUS_VERSION_MAJOR -#define LIBGUS_VERSION_MAJOR 0x0003 -#endif - -/* DOS/DJGPP and OS/2 libGUS'es have gus_get_voice_status() */ -#if defined(__EMX__) || defined(__DJGPP__) -#define HAVE_VOICE_STATUS -#else -#include -#endif - - -#ifdef MIKMOD_DYNAMIC -/* runtime link with libgus */ -static int (*_libgus_cards) (void); - -#if LIBGUS_VERSION_MAJOR < 0x0004 -static int (*_libgus_close) (int); -static int (*_libgus_do_flush) (void); -static void (*_libgus_do_tempo) (unsigned int); -static void (*_libgus_do_voice_frequency) (unsigned char, unsigned int); -static void (*_libgus_do_voice_pan) (unsigned char, unsigned short); -static void (*_libgus_do_voice_start) (unsigned char, unsigned int, - unsigned int, unsigned short, - unsigned short); -static void (*_libgus_do_voice_start_position) (unsigned char, unsigned int, - unsigned int, unsigned short, - unsigned short, unsigned int); -static void (*_libgus_do_voice_stop) (unsigned char, unsigned char); -static void (*_libgus_do_voice_volume) (unsigned char, unsigned short); -static void (*_libgus_do_wait) (unsigned int); -static int (*_libgus_get_handle) (void); -static int (*_libgus_info) (gus_info_t *, int); -static int (*_libgus_memory_alloc) (gus_instrument_t *); -static int (*_libgus_memory_free) (gus_instrument_t *); -static int (*_libgus_memory_free_size) (void); -static int (*_libgus_memory_pack) (void); -static int (*_libgus_open) (int, size_t, int); -static int (*_libgus_queue_flush) (void); -static int (*_libgus_queue_read_set_size) (int); -static int (*_libgus_queue_write_set_size) (int); -static int (*_libgus_reset) (int, unsigned int); -static int (*_libgus_select) (int); -static int (*_libgus_timer_start) (void); -static int (*_libgus_timer_stop) (void); -static int (*_libgus_timer_tempo) (int); -#else -static int (*_libgus_close) (void*); -static int (*_libgus_do_flush) (void*); -static void (*_libgus_do_tempo) (void*, unsigned int); -static void (*_libgus_do_voice_frequency) (void*, unsigned char, unsigned int); -static void (*_libgus_do_voice_pan) (void*, unsigned char,unsigned short); -static void (*_libgus_do_voice_start) (void*, unsigned char, unsigned int, - unsigned int, unsigned short, - unsigned short); -static void (*_libgus_do_voice_start_position) (void*, unsigned char, unsigned int, - unsigned int,unsigned short, - unsigned short, unsigned int); -static void (*_libgus_do_voice_stop) (void*, unsigned char, unsigned char); -static void (*_libgus_do_voice_volume) (void*, unsigned char, unsigned short); -static void (*_libgus_do_wait) (void*, unsigned int); -static int (*_libgus_get_file_descriptor) (void*); -static int (*_libgus_info) (void*, gus_info_t*, int); -static int (*_libgus_memory_alloc) (void*, gus_instrument_t*); -static int (*_libgus_memory_free) (void*, gus_instrument_t*); -static int (*_libgus_memory_free_size) (void*); -static int (*_libgus_memory_pack) (void*); -static int (*_libgus_open) (void**, int, int, size_t, int); -static int (*_libgus_queue_flush) (void*); -static int (*_libgus_queue_read_set_size) (void*, int); -static int (*_libgus_queue_write_set_size) (void*, int); -static int (*_libgus_reset) (void*, int, unsigned int); -static int (*_libgus_timer_start)(void*); -static int (*_libgus_timer_stop) (void*); -static int (*_libgus_timer_tempo) (void*, int); -#endif -#ifndef HAVE_RTLD_GLOBAL -#define RTLD_GLOBAL (0) -#endif -static void *libgus = NULL; - -#else -/* compile-time link with libgus */ -#define _libgus_cards gus_cards -#define _libgus_close gus_close -#define _libgus_do_flush gus_do_flush -#define _libgus_do_tempo gus_do_tempo -#define _libgus_do_voice_frequency gus_do_voice_frequency -#define _libgus_do_voice_pan gus_do_voice_pan -#define _libgus_do_voice_start gus_do_voice_start -#define _libgus_do_voice_start_position gus_do_voice_start_position -#define _libgus_do_voice_stop gus_do_voice_stop -#define _libgus_do_voice_volume gus_do_voice_volume -#define _libgus_do_wait gus_do_wait -#if LIBGUS_VERSION_MAJOR < 0x0004 -#define _libgus_get_handle gus_get_handle -#else -#define _libgus_get_file_descriptor gus_get_file_descriptor -#endif -#define _libgus_info gus_info -#define _libgus_memory_alloc gus_memory_alloc -#define _libgus_memory_free gus_memory_free -#define _libgus_memory_free_size gus_memory_free_size -#define _libgus_memory_pack gus_memory_pack -#define _libgus_open gus_open -#define _libgus_queue_flush gus_queue_flush -#define _libgus_queue_read_set_size gus_queue_read_set_size -#define _libgus_queue_write_set_size gus_queue_write_set_size -#define _libgus_reset gus_reset -#if LIBGUS_VERSION_MAJOR < 0x0004 -#define _libgus_select gus_select -#endif -#define _libgus_timer_start gus_timer_start -#define _libgus_timer_stop gus_timer_stop -#define _libgus_timer_tempo gus_timer_tempo -#endif - -#define libgus_cards _libgus_cards /* same between v3 and v4 */ -#define libgus_open _libgus_open /* different between v3 and v4: must use #ifdef */ -#define libgus_close _libgus_close /* different between v3 and v4: must use #ifdef */ -/* the following can be handled easily by macros: v4 only adds them the handle as the first param */ -#if LIBGUS_VERSION_MAJOR < 0x0004 -#define libgus_get_handle _libgus_get_handle /* only in v3 */ -#define libgus_do_flush _libgus_do_flush -#define libgus_do_tempo _libgus_do_tempo -#define libgus_do_voice_frequency _libgus_do_voice_frequency -#define libgus_do_voice_pan _libgus_do_voice_pan -#define libgus_do_voice_start _libgus_do_voice_start -#define libgus_do_voice_start_position _libgus_do_voice_start_position -#define libgus_do_voice_stop _libgus_do_voice_stop -#define libgus_do_voice_volume _libgus_do_voice_volume -#define libgus_do_wait _libgus_do_wait -#define libgus_info _libgus_info -#define libgus_memory_alloc _libgus_memory_alloc -#define libgus_memory_free _libgus_memory_free -#define libgus_memory_free_size _libgus_memory_free_size -#define libgus_memory_pack _libgus_memory_pack -#define libgus_queue_flush _libgus_queue_flush -#define libgus_queue_read_set_size _libgus_queue_read_set_size -#define libgus_queue_write_set_size _libgus_queue_write_set_size -#define libgus_reset _libgus_reset -#define libgus_select _libgus_select -#define libgus_timer_start _libgus_timer_start -#define libgus_timer_stop _libgus_timer_stop -#define libgus_timer_tempo _libgus_timer_tempo -#else -#define libgus_get_file_descriptor _libgus_get_file_descriptor /* only in v4 */ -#define libgus_do_flush() _libgus_do_flush(ultra_h) -#define libgus_do_tempo(t) _libgus_do_tempo(ultra_h,t) -#define libgus_do_voice_frequency(a,b) _libgus_do_voice_frequency(ultra_h,a,b) -#define libgus_do_voice_pan(a,b) _libgus_do_voice_pan(ultra_h,a,b) -#define libgus_do_voice_start(a,b,c,d,e) _libgus_do_voice_start(ultra_h,a,b,c,d,e) -#define libgus_do_voice_start_position(a,b,c,d,e,f) _libgus_do_voice_start_position(ultra_h,a,b,c,d,e,f) -#define libgus_do_voice_stop(a,b) _libgus_do_voice_stop(ultra_h,a,b) -#define libgus_do_voice_volume(a,b) _libgus_do_voice_volume(ultra_h,a,b) -#define libgus_do_wait(a) _libgus_do_wait(ultra_h,a) -#define libgus_info(a,b) _libgus_info(ultra_h,a,b) -#define libgus_memory_alloc(a) _libgus_memory_alloc(ultra_h,a) -#define libgus_memory_free(a) _libgus_memory_free(ultra_h,a) -#define libgus_memory_free_size() _libgus_memory_free_size(ultra_h) -#define libgus_memory_pack() _libgus_memory_pack(ultra_h) -#define libgus_queue_flush() _libgus_queue_flush(ultra_h) -#define libgus_queue_read_set_size(a) _libgus_queue_read_set_size(ultra_h,a) -#define libgus_queue_write_set_size(a) _libgus_queue_write_set_size(ultra_h,a) -#define libgus_reset(a,b) _libgus_reset(ultra_h,a,b) -#define libgus_timer_start() _libgus_timer_start(ultra_h) -#define libgus_timer_stop() _libgus_timer_stop(ultra_h) -#define libgus_timer_tempo(a) _libgus_timer_tempo(ultra_h,a) -#endif - -#define GUS_SAMPLES 256 /* Max. GUS samples loadable */ -#define GUS_CHANNELS 32 /* Max. GUS channels available */ -#define SIZE_OF_SEQBUF (8 * 1024) /* Size of the sequence buffer */ -#define ULTRA_PAN_MIDDLE (16383 >> 1) /* Middle balance position */ - -#define CH_FREQ 1 -#define CH_VOL 2 -#define CH_PAN 4 - -/* This structure holds the current state of a GUS voice channel. */ -typedef struct GUS_VOICE { - UBYTE kick; - UBYTE active; - UWORD flags; - SWORD handle; - ULONG start; - ULONG size; - ULONG reppos; - ULONG repend; - ULONG frq; - int vol; - int decvol; - int pan; - - int changes; -#ifndef HAVE_VOICE_STATUS - time_t started; -#endif -} GUS_VOICE; - -/* Global declarations follow */ - -static SAMPLE *samples[GUS_SAMPLES]; /* sample handles */ -static GUS_VOICE voices[GUS_CHANNELS]; /* channel status */ - -static int ultra_dev = 0; /* GUS index, if more than one card */ -#if LIBGUS_VERSION_MAJOR < 0x0004 -static int ultra_card = -1; /* returned by gus_open(ultra_dev,,) - must be same as ultra_dev */ -#else -static void* ultra_h = NULL; /* GUS handle */ -#endif -static int ultra_fd = -1; /* GUS file descriptor */ - - -#ifdef MIKMOD_DYNAMIC -static int Ultra_Link(void) -{ - if (libgus) - return 0; - - /* load libgus.so */ -#if LIBGUS_VERSION_MAJOR < 0x0004 - libgus = dlopen("libgus.so.3", RTLD_LAZY | RTLD_GLOBAL); -#else - libgus = dlopen("libgus.so.4", RTLD_LAZY | RTLD_GLOBAL); -#endif - if (!libgus) /* then this won't succeed either, but whatever.. */ - libgus = dlopen("libgus.so", RTLD_LAZY | RTLD_GLOBAL); - if (!libgus) - return 1; - - /* resolve function references */ -#define IMPORT_SYMBOL(x,ret,params) \ - if (!(_lib##x = (ret (*)params) dlsym(libgus, #x))) return 1 - - IMPORT_SYMBOL(gus_cards, int, (void)); -#if LIBGUS_VERSION_MAJOR < 0x0004 - IMPORT_SYMBOL(gus_close, int, (int)); - IMPORT_SYMBOL(gus_do_flush, int, (void)); - IMPORT_SYMBOL(gus_do_tempo, void, (unsigned int)); - IMPORT_SYMBOL(gus_do_voice_frequency, void, (unsigned char, unsigned int)); - IMPORT_SYMBOL(gus_do_voice_pan, void, (unsigned char, unsigned short)); - IMPORT_SYMBOL(gus_do_voice_start, void, (unsigned char, unsigned int, unsigned int, unsigned short, unsigned short)); - IMPORT_SYMBOL(gus_do_voice_start_position, void, (unsigned char, unsigned int, unsigned int, unsigned short, unsigned short, unsigned int)); - IMPORT_SYMBOL(gus_do_voice_stop, void, (unsigned char, unsigned char)); - IMPORT_SYMBOL(gus_do_voice_volume, void, (unsigned char, unsigned short)); - IMPORT_SYMBOL(gus_do_wait, void, (unsigned int)); - IMPORT_SYMBOL(gus_get_handle, int, (void)); - IMPORT_SYMBOL(gus_info, int, (gus_info_t *, int)); - IMPORT_SYMBOL(gus_memory_alloc, int, (gus_instrument_t *)); - IMPORT_SYMBOL(gus_memory_free, int, (gus_instrument_t *)); - IMPORT_SYMBOL(gus_memory_free_size, int, (void)); - IMPORT_SYMBOL(gus_memory_pack, int, (void)); - IMPORT_SYMBOL(gus_open, int, (int, size_t, int)); - IMPORT_SYMBOL(gus_queue_flush, int, (void)); - IMPORT_SYMBOL(gus_queue_read_set_size, int, (int)); - IMPORT_SYMBOL(gus_queue_write_set_size, int, (int)); - IMPORT_SYMBOL(gus_reset, int, (int, unsigned int)); - IMPORT_SYMBOL(gus_select, int, (int)); - IMPORT_SYMBOL(gus_timer_start, int, (void)); - IMPORT_SYMBOL(gus_timer_stop, int, (void)); - IMPORT_SYMBOL(gus_timer_tempo, int, (int)); -#else - IMPORT_SYMBOL(gus_close, int, (void*)); - IMPORT_SYMBOL(gus_do_flush, int, (void*)); - IMPORT_SYMBOL(gus_do_tempo, void, (void*, unsigned int)); - IMPORT_SYMBOL(gus_do_voice_frequency, void, (void*, unsigned char, unsigned int)); - IMPORT_SYMBOL(gus_do_voice_pan, void, (void*, unsigned char, unsigned short)); - IMPORT_SYMBOL(gus_do_voice_start, void, (void*, unsigned char, unsigned int, unsigned int, unsigned short, unsigned short)); - IMPORT_SYMBOL(gus_do_voice_start_position, void, (void*, unsigned char, unsigned int, unsigned int, unsigned short, unsigned short, unsigned int)); - IMPORT_SYMBOL(gus_do_voice_stop, void, (void*, unsigned char, unsigned char)); - IMPORT_SYMBOL(gus_do_voice_volume, void, (void*, unsigned char, unsigned short)); - IMPORT_SYMBOL(gus_do_wait, void, (void*, unsigned int)); - IMPORT_SYMBOL(gus_get_file_descriptor, int, (void*)); - IMPORT_SYMBOL(gus_info, int, (void*, gus_info_t *, int)); - IMPORT_SYMBOL(gus_memory_alloc, int, (void*, gus_instrument_t *)); - IMPORT_SYMBOL(gus_memory_free, int, (void*, gus_instrument_t *)); - IMPORT_SYMBOL(gus_memory_free_size, int, (void*)); - IMPORT_SYMBOL(gus_memory_pack, int, (void*)); - IMPORT_SYMBOL(gus_open, int, (void**, int, int, size_t, int)); - IMPORT_SYMBOL(gus_queue_flush, int, (void*)); - IMPORT_SYMBOL(gus_queue_read_set_size, int, (void*, int)); - IMPORT_SYMBOL(gus_queue_write_set_size, int, (void*, int)); - IMPORT_SYMBOL(gus_reset, int, (void*, int, unsigned int)); - IMPORT_SYMBOL(gus_timer_start, int, (void*)); - IMPORT_SYMBOL(gus_timer_stop, int, (void*)); - IMPORT_SYMBOL(gus_timer_tempo, int, (void*, int)); -#endif -#undef IMPORT_SYMBOL - - return 0; -} - -static void Ultra_Unlink(void) -{ - _libgus_cards = NULL; - _libgus_close = NULL; - _libgus_do_flush = NULL; - _libgus_do_tempo = NULL; - _libgus_do_voice_frequency = NULL; - _libgus_do_voice_pan = NULL; - _libgus_do_voice_start = NULL; - _libgus_do_voice_start_position = NULL; - _libgus_do_voice_stop = NULL; - _libgus_do_voice_volume = NULL; - _libgus_do_wait = NULL; -#if LIBGUS_VERSION_MAJOR < 0x0004 - _libgus_get_handle = NULL; -#else - _libgus_get_file_descriptor = NULL; -#endif - _libgus_info = NULL; - _libgus_memory_alloc = NULL; - _libgus_memory_free = NULL; - _libgus_memory_free_size = NULL; - _libgus_memory_pack = NULL; - _libgus_open = NULL; - _libgus_queue_flush = NULL; - _libgus_queue_read_set_size = NULL; - _libgus_queue_write_set_size = NULL; - _libgus_reset = NULL; -#if LIBGUS_VERSION_MAJOR < 0x0004 - _libgus_select = NULL; -#endif - _libgus_timer_start = NULL; - _libgus_timer_stop = NULL; - _libgus_timer_tempo = NULL; - - if (libgus) { - dlclose(libgus); - libgus = NULL; - } -} -#endif - -static void Ultra_CommandLine(const CHAR *cmdline) -{ - CHAR *ptr = MD_GetAtom("card", cmdline, 0); - - if (ptr) { - int buf = atoi(ptr); - - if (buf >= 0 && buf <= 8) - ultra_dev = buf; - MikMod_free(ptr); - } -#ifdef __DJGPP__ - ptr = MD_GetAtom("dma", cmdline, 0); - if (ptr) { - gus_dma_usage (atoi(ptr)); - MikMod_free(ptr); - } -#endif -} - -/* Checks for the presence of GUS cards */ -static BOOL Ultra_IsThere(void) -{ - BOOL retval; - -#ifdef MIKMOD_DYNAMIC - if (Ultra_Link()) - return 0; -#endif - retval = libgus_cards()? 1 : 0; -#ifdef MIKMOD_DYNAMIC - Ultra_Unlink(); -#endif - return retval; -} - -/* Load a new sample directly into GUS DRAM and return a handle */ -static SWORD Ultra_SampleLoad(struct SAMPLOAD *sload, int type) -{ - int handle; - SAMPLE *s = sload->sample; - gus_instrument_t instrument; - gus_layer_t layer; - gus_wave_t wave; - unsigned char *buffer; - unsigned int length, loopstart, loopend; - - /* Find empty slot to put sample in */ - for (handle = 0; handle < GUS_SAMPLES; handle++) - if (!samples[handle]) - break; - - if (handle == GUS_SAMPLES) { - _mm_errno = MMERR_OUT_OF_HANDLES; - return -1; - } - - /* Fill an gus_instrument_t structure and feed it to libgus. We can - download 8 and 16 bit, both signed and unsigned samples into GUS, so - don't bother much about formats here. */ - - /* convert position/length data from samples to bytes */ - length = s->length; - loopstart = s->loopstart; - loopend = s->loopend ? s->loopend : length; - /* sanity checks */ - if (loopend > length) - loopend = length; - if (loopstart > loopend) - loopstart = loopend; - if (s->flags & SF_16BITS) { - length <<= 1; - loopstart <<= 1; - loopend <<= 1; - } - - /* Load sample into normal memory */ - if (!(buffer = (unsigned char *) MikMod_malloc(length))) { - _mm_errno = MMERR_SAMPLE_TOO_BIG; - return -1; - } - - if (SL_Load(buffer, sload, s->length)) { - MikMod_free(buffer); - return -1; - } - - samples[handle] = s; - - memset(&wave, 0, sizeof(wave)); - memset(&layer, 0, sizeof(layer)); - memset(&instrument, 0, sizeof(instrument)); - - wave.format = - ((s->flags & SF_SIGNED) ? 0 : GUS_WAVE_INVERT) | - ((s->flags & SF_16BITS) ? GUS_WAVE_16BIT : 0) | - ((s->flags & SF_DELTA ) ? GUS_WAVE_DELTA : 0) | - ((s->flags & SF_LOOP ) ? GUS_WAVE_LOOP : 0) | - ((s->flags & SF_BIDI ) ? GUS_WAVE_BIDIR : 0); - wave.begin.ptr = buffer; - wave.loop_start = loopstart << 4; - wave.loop_end = loopend << 4; - wave.size = length; - - layer.wave = &wave; - - instrument.mode = layer.mode = wave.mode = GUS_INSTR_SIMPLE; - instrument.number.instrument = handle; - instrument.info.layer = &layer; - - /* Download the sample to GUS RAM */ - if (libgus_memory_alloc(&instrument)) { - MikMod_free(buffer); - _mm_errno = MMERR_SAMPLE_TOO_BIG; - return -1; - } - - MikMod_free(buffer); - return handle; -} - -/* Discards a sample from the GUS memory and mark handle as free */ -static void Ultra_SampleUnload(SWORD handle) -{ - gus_instrument_t instrument; - - if (handle >= GUS_SAMPLES || handle < 0 || !samples[handle]) - return; - - memset(&instrument, 0, sizeof(instrument)); - instrument.mode = GUS_INSTR_SIMPLE; - instrument.number.instrument = handle; - libgus_memory_free(&instrument); - samples[handle] = NULL; -} - -/* Reports available sample space */ -static ULONG Ultra_SampleSpace(int type) -{ - libgus_memory_pack(); - return (libgus_memory_free_size()); -} - -/* Reports the size of a sample */ -static ULONG Ultra_SampleLength(int type, SAMPLE *s) -{ - if (!s) - return 0; - - if (s->flags & SF_16BITS) - return ((s->length << 1) + 31) & ~31; - else - return ( s->length + 15) & ~15; -} - -/* Initializes the driver */ -static int Ultra_Init_internal(void) -{ - gus_info_t info; - -#if LIBGUS_VERSION_MAJOR < 0x0004 - if ((ultra_card = libgus_open(ultra_dev, SIZE_OF_SEQBUF, 0)) < 0) { - _mm_errno = (errno == ENOMEM)? MMERR_OUT_OF_MEMORY : MMERR_INVALID_DEVICE; - return 1; - } - libgus_select(ultra_card); - ultra_fd = libgus_get_handle(); -#else - if (libgus_open(&ultra_h, ultra_dev, 0, SIZE_OF_SEQBUF, GUS_OPEN_FLAG_NONE) < 0) { - _mm_errno = (errno == ENOMEM)? MMERR_OUT_OF_MEMORY : MMERR_INVALID_DEVICE; - return 1; - } - ultra_fd = libgus_get_file_descriptor(ultra_h); -#endif - - /* We support only 16-bit stereo with 44K mixing frequency. On UltraSound - Classic mixing frequency depends on number of channels, on Interwave it - is always 44KHz. */ - md_mode |= DMODE_16BITS | DMODE_STEREO; - md_mixfreq = info.mixing_freq; - - libgus_info(&info, 0); -#ifdef MIKMOD_DEBUG - switch (info.version) { - case 0x24: - fputs("GUS 2.4", stderr); - break; - case 0x35: - fputs("GUS 3.7 (flipped)", stderr); - break; - case 0x37: - fputs("GUS 3.7", stderr); - break; - case 0x90: - fputs("GUS ACE", stderr); - break; - case 0xa0: - fputs("GUS MAX 10", stderr); - break; - case 0xa1: - fputs("GUS MAX 11", stderr); - break; - case 0x100: - fputs("Interwave/GUS PnP", stderr); - break; - default: - fprintf(stderr, "Unknown GUS type %x", info.version); - break; - } - fprintf(stderr, " with %dKb RAM on board\n", info.memory_size >> 10); -#endif - - /* Zero the voice states and sample handles */ - memset (&voices, 0, sizeof (voices)); - memset (&samples, 0, sizeof (samples)); - - return 0; -} - -static int Ultra_Init(void) -{ -#ifdef MIKMOD_DYNAMIC - if (Ultra_Link()) { - _mm_errno = MMERR_DYNAMIC_LINKING; - return 1; - } -#endif - return Ultra_Init_internal(); -} - -/* Closes the driver */ -static void Ultra_Exit_internal(void) -{ -#if LIBGUS_VERSION_MAJOR < 0x0004 - if (ultra_card >= 0) { - ultra_card = -1; - libgus_close(ultra_dev); - } -#else - if (ultra_h) { - libgus_close(ultra_h); - ultra_h = NULL; - } -#endif - ultra_fd = -1; -} - -static void Ultra_Exit(void) -{ - Ultra_Exit_internal(); -#ifdef MIKMOD_DYNAMIC - Ultra_Unlink(); -#endif -} - -/* Poor man's reset function */ -static int Ultra_Reset(void) -{ - Ultra_Exit_internal(); - return Ultra_Init_internal(); -} - -static int Ultra_SetNumVoices(void) -{ - return 0; -} - -/* Module player tick function */ -static void UltraPlayer(void) -{ - int channel, panning; - struct GUS_VOICE *voice; - static BOOL ultra_pause = 1; /* paused status */ - - md_player(); - - if (ultra_pause != Player_Paused()) - if ((ultra_pause = Player_Paused())) - for (channel = 0, voice = voices; channel < md_numchn; - channel++, voice++) { - libgus_do_voice_volume (channel, 0); - voices->changes |= (CH_VOL | CH_FREQ | CH_PAN); - } - - if (ultra_pause) - return; - - for (channel = 0, voice = voices; channel < md_numchn; channel++, voice++) { - panning = (voice->pan == PAN_SURROUND) ? - ULTRA_PAN_MIDDLE : (voice->pan << 6); - - if (voice->kick) { - voice->kick = 0; - voice->decvol = voice->vol; - if (voice->start > 0) - libgus_do_voice_start_position(channel, voice->handle, - voice->frq, voice->vol << 6, panning, voice->start << 4); - else - libgus_do_voice_start(channel, voice->handle, voice->frq, - voice->vol << 6, voice->pan << 6); - } else { - if (voice->changes & CH_FREQ) - libgus_do_voice_frequency(channel, voice->frq); - if (voice->changes & CH_VOL) - libgus_do_voice_volume(channel, voice->vol << 6); - if (voice->changes & CH_PAN) - libgus_do_voice_pan(channel, panning); - if (voice->decvol) - voice->decvol -= 4; - } - voice->changes = 0; - } -} - -/* Play sound */ -#if defined(__DJGPP__) || defined(__EMX__) -static void Ultra_Callback(void) -{ - UltraPlayer(); - libgus_do_flush(); -} - -static void Ultra_Update(void) -{ - static UWORD ultra_bpm = 0; /* current GUS tempo */ - - /* All real work is done during GF1 timer 1 interrupt */ - if (ultra_bpm != md_bpm) { - libgus_do_tempo((md_bpm * 50) / 125); - ultra_bpm = md_bpm; - } -} - -#else -static void Ultra_Update(void) -{ - fd_set write_fds; - int need_write; - static UWORD ultra_bpm = 0; /* current GUS tempo */ - - if (ultra_bpm != md_bpm) { - libgus_do_tempo((md_bpm * 50) / 125); - ultra_bpm = md_bpm; - } - - UltraPlayer(); - - do { - need_write = libgus_do_flush(); - - FD_ZERO(&write_fds); - do { - FD_SET(ultra_fd, &write_fds); - - select(ultra_fd + 1, NULL, &write_fds, NULL, NULL); - } while (!FD_ISSET(ultra_fd, &write_fds)); - } while(need_write > 0); - - /* Wait so that all voice commands gets executed */ - libgus_do_wait (1); -} - -#endif - -/* Start playback */ -static int Ultra_PlayStart(void) -{ - int t; - gus_info_t info; - - for (t = 0; t < md_numchn; t++) { - voices[t].flags = 0; - voices[t].handle = 0; - voices[t].size = 0; - voices[t].start = 0; - voices[t].reppos = 0; - voices[t].repend = 0; - voices[t].changes = 0; - voices[t].kick = 0; - voices[t].frq = 10000; - voices[t].vol = 0; - voices[t].pan = ULTRA_PAN_MIDDLE; - voices[t].active = 0; - } - -#if LIBGUS_VERSION_MAJOR < 0x0004 - libgus_select(ultra_card); -#endif - if (libgus_reset(md_numchn, 0) < 0) { - _mm_errno = MMERR_GUS_RESET; - return 1; - } - - /* Query mixing frequency */ - libgus_info(&info, 0); - md_mixfreq = info.mixing_freq; - - libgus_queue_write_set_size(1024); - libgus_queue_read_set_size(128); - - if (libgus_timer_start() < 0) { - _mm_errno = MMERR_GUS_TIMER; - return 1; - } - -#if defined(__DJGPP__) || defined(__EMX__) - gus_timer_callback(Ultra_Callback); -#endif - - libgus_timer_tempo(50); - - for (t = 0; t < md_numchn; t++) { - libgus_do_voice_pan(t, ULTRA_PAN_MIDDLE); - libgus_do_voice_volume(t, 0 << 8); - } - - libgus_do_flush(); - - return 0; -} - -/* Stop playback */ -static void Ultra_PlayStop(void) -{ - int voice; - - libgus_queue_flush(); - libgus_timer_stop(); - libgus_queue_write_set_size(0); - libgus_queue_read_set_size(0); - for(voice = 0; voice < md_numchn; voice++) - libgus_do_voice_stop(voice, 0); - -#if defined(__DJGPP__) || defined(__EMX__) - gus_timer_callback(NULL); -#endif - - libgus_do_flush(); -} - -/* Set the volume for the given voice */ -static void Ultra_VoiceSetVolume(UBYTE voice, UWORD vol) -{ - if (voice < md_numchn) - if (vol != voices[voice].vol) { - voices[voice].decvol = - voices[voice].vol = vol; - voices[voice].changes |= CH_VOL; - } -} - -/* Returns the volume of the given voice */ -static UWORD Ultra_VoiceGetVolume(UBYTE voice) -{ - return (voice < md_numchn) ? voices[voice].vol : 0; -} - -/* Set the pitch for the given voice */ -static void Ultra_VoiceSetFrequency(UBYTE voice, ULONG frq) -{ - if (voice < md_numchn) - if (frq != voices[voice].frq) { - voices[voice].frq = frq; - voices[voice].changes |= CH_FREQ; - } -} - -/* Returns the frequency of the given voice */ -static ULONG Ultra_VoiceGetFrequency(UBYTE voice) -{ - return (voice < md_numchn) ? voices[voice].frq : 0; -} - -/* Set the panning position for the given voice */ -static void Ultra_VoiceSetPanning(UBYTE voice, ULONG pan) -{ - if (voice < md_numchn) - if (pan != voices[voice].pan) { - voices[voice].pan = pan; - voices[voice].changes |= CH_PAN; - } -} - -/* Returns the panning of the given voice */ -static ULONG Ultra_VoiceGetPanning(UBYTE voice) -{ - return (voice < md_numchn) ? voices[voice].pan : 0; -} - -/* Start a new sample on a voice */ -static void Ultra_VoicePlay(UBYTE voice, SWORD handle, ULONG start, - ULONG size, ULONG reppos, ULONG repend, - UWORD flags) -{ - if ((voice >= md_numchn) || (start >= size)) - return; - - if (flags & SF_LOOP) - if (repend > size) - repend = size; - - voices[voice].flags = flags; - voices[voice].handle = handle; - voices[voice].start = start; - voices[voice].size = size; - voices[voice].reppos = reppos; - voices[voice].repend = repend; - voices[voice].kick = 1; - voices[voice].active = 1; -#ifndef HAVE_VOICE_STATUS - voices[voice].started = time(NULL); -#endif -} - -/* Stops a voice */ -static void Ultra_VoiceStop(UBYTE voice) -{ - if (voice < md_numchn) - voices[voice].active = 0; -} - -/* Returns whether a voice is stopped */ -static BOOL Ultra_VoiceStopped(UBYTE voice) -{ - if (voice >= md_numchn) - return 1; - -#ifdef HAVE_VOICE_STATUS - if (voices[voice].active) - return gus_get_voice_status(voice) ? 0 : 1; - else - return 1; -#else - if (voices[voice].active) { - /* is sample looping ? */ - if (voices[voice].flags & (SF_LOOP | SF_BIDI)) - return 0; - else - if (time(NULL) - voices[voice].started >= - ((voices[voice].size - voices[voice].start + md_mixfreq -1) - / md_mixfreq)) { - voices[voice].active = 0; - return 1; - } - return 0; - } else - return 1; -#endif -} - -/* Returns current voice position */ -static SLONG Ultra_VoiceGetPosition(UBYTE voice) -{ - /* NOTE This information can not be determined. */ - return -1; -} - -/* Returns voice real volume */ -static ULONG Ultra_VoiceRealVolume(UBYTE voice) -{ - int retval = 0; - if (!Ultra_VoiceStopped (voice)) { - /* NOTE This information can not be accurately determined. */ - retval = (voices [voice].decvol) << 8; - if (retval > 0xffff) retval = 0xffff; - } - return retval; -} - -MDRIVER drv_ultra = { - NULL, - "Gravis Ultrasound native mode", - "Gravis Ultrasound native mode driver v1.2", - 0, (GUS_CHANNELS)-1, - "ultra", -#ifdef __DJGPP__ - "dma:b:1:Use DMA for transferring samples into GUS DRAM\n" -#endif - "card:r:0,8,0:Soundcard number\n", - - Ultra_CommandLine, - Ultra_IsThere, - Ultra_SampleLoad, - Ultra_SampleUnload, - Ultra_SampleSpace, - Ultra_SampleLength, - Ultra_Init, - Ultra_Exit, - Ultra_Reset, - Ultra_SetNumVoices, - Ultra_PlayStart, - Ultra_PlayStop, - Ultra_Update, - NULL, - Ultra_VoiceSetVolume, - Ultra_VoiceGetVolume, - Ultra_VoiceSetFrequency, - Ultra_VoiceGetFrequency, - Ultra_VoiceSetPanning, - Ultra_VoiceGetPanning, - Ultra_VoicePlay, - Ultra_VoiceStop, - Ultra_VoiceStopped, - Ultra_VoiceGetPosition, - Ultra_VoiceRealVolume -}; -#else - -MISSING(drv_ultra); - -#endif /* DRV_ULTRA */ - -/* ex:set ts=8: */ diff --git a/libs/mikmod/drivers/drv_wss.c b/libs/mikmod/drivers/drv_wss.c deleted file mode 100644 index a89d5ec..0000000 --- a/libs/mikmod/drivers/drv_wss.c +++ /dev/null @@ -1,217 +0,0 @@ -/* 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$ - - Driver for Windows Sound System under DOS - -==============================================================================*/ - -/* - - Written by Andrew Zabolotny - -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef DRV_WSS - -#ifdef HAVE_UNISTD_H -#include -#endif -#ifdef HAVE_FCNTL_H -#include -#endif - -#include "mikmod_internals.h" - -#include "doswss.h" - -static void WSS_CommandLine(const CHAR *cmdline) -{ - char *ptr, *end; - - if ((ptr=MD_GetAtom("port",cmdline,0)) != NULL) { - wss.port = strtol(ptr, &end, 16); - MikMod_free(ptr); - } - if ((ptr=MD_GetAtom("irq",cmdline,0)) != NULL) { - wss.irq = strtol(ptr, &end, 10); - MikMod_free(ptr); - } - if ((ptr=MD_GetAtom("dma",cmdline,0)) != NULL) { - wss.dma = strtol(ptr, &end, 10); - MikMod_free(ptr); - } -} - -static BOOL WSS_IsThere(void) -{ - return wss_detect(); -} - -static int WSS_Init(void) -{ - if (!wss_open()) { - _mm_errno = MMERR_INVALID_DEVICE; - return 1; - } - - /* Adjust mixing frequency according to card capabilities */ - md_mixfreq = wss_adjust_freq(md_mixfreq); - - return VC_Init(); -} - -static void WSS_Exit(void) -{ - VC_Exit(); - wss_close(); -} - -/* The last buffer byte filled with sound */ -static unsigned int buff_tail = 0; - -static void WSS_Callback(void) -{ - unsigned int dma_size, dma_pos; - ULONG (*mixer)(SBYTE *buf, ULONG todo); - - wss_query_dma(&dma_size, &dma_pos); - /* There isn't much sense in filling less than 256 bytes */ - dma_pos &= ~255; - - /* If nothing to mix, quit */ - if (buff_tail == dma_pos) - return; - - if (Player_Paused_internal()) - mixer = VC_SilenceBytes; - else - mixer = VC_WriteBytes; - - /* If DMA pointer still didn't wrapped around ... */ - if (dma_pos > buff_tail) { - buff_tail += mixer ((SBYTE *)(wss.dma_buff->linear + buff_tail), dma_pos - buff_tail); - /* If we arrived right to the DMA buffer end, jump to the beginning */ - if (buff_tail >= dma_size) - buff_tail = 0; - } else { - /* If wrapped around, fill first to the end of buffer */ - mixer ((SBYTE *)(wss.dma_buff->linear + buff_tail), dma_size - buff_tail); - /* Now fill from buffer beginning to current DMA pointer */ - buff_tail = mixer ((SBYTE *)wss.dma_buff->linear, dma_pos); - } -} - -static void WSS_Update(void) -{ - /* Do nothing: the real update is done during SB interrupts */ -} - -static int WSS_PlayStart(void) -{ - if (VC_PlayStart()) - return 1; - - /* Set our routine to be called during WSS IRQs */ - buff_tail = 0; - wss.timer_callback = WSS_Callback; - - /* Start cyclic DMA transfer */ - if (!wss_start_dma(((md_mode & DMODE_16BITS) ? WSSMODE_16BITS | WSSMODE_SIGNED : 0) | - ((md_mode & DMODE_STEREO) ? WSSMODE_STEREO : 0), md_mixfreq)) - { - _mm_errno = MMERR_DOSWSS_STARTDMA; - return 1; - } - - /* Enable speaker output */ - wss_output(TRUE); - - return 0; -} - -static int WSS_Reset(void) -{ - wss_reset(); - VC_Exit(); - return VC_Init(); -} - -static void WSS_PlayStop(void) -{ - wss.timer_callback = NULL; - wss_output(FALSE); - wss_stop_dma(); - VC_PlayStop(); -} - -MDRIVER drv_wss = -{ - NULL, - "Windows Sound System", - "Windows Sound System (CS423*,ESS*) v1.0", - 0, 255, - "wss", - "port:c:32C,530,604,E80,F40,530:Windows Sound System base I/O port\n" - "irq:c:2,3,5,7,10,5:Windows Sound System IRQ\n" - "dma:c:0,1,3,0:Windows Sound System DMA channel\n", - - WSS_CommandLine, - WSS_IsThere, - VC_SampleLoad, - VC_SampleUnload, - VC_SampleSpace, - VC_SampleLength, - WSS_Init, - WSS_Exit, - WSS_Reset, - VC_SetNumVoices, - WSS_PlayStart, - WSS_PlayStop, - WSS_Update, - NULL, - VC_VoiceSetVolume, - VC_VoiceGetVolume, - VC_VoiceSetFrequency, - VC_VoiceGetFrequency, - VC_VoiceSetPanning, - VC_VoiceGetPanning, - VC_VoicePlay, - VC_VoiceStop, - VC_VoiceStopped, - VC_VoiceGetPosition, - VC_VoiceRealVolume -}; - -#else /* ifdef DRV_WSS */ - -#include "mikmod_internals.h" -MISSING(drv_wss); - -#endif - -/* ex:set ts=4: */ diff --git a/libs/mikmod/posix/strcasecmp.c b/libs/mikmod/posix/strcasecmp.c deleted file mode 100644 index 5b9935f..0000000 --- a/libs/mikmod/posix/strcasecmp.c +++ /dev/null @@ -1,23 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "mikmod_internals.h" -#include "mikmod_ctype.h" - -int _mm_strcasecmp(const char *__s1, const char *__s2) -{ - const char *p1 = __s1; - const char *p2 = __s2; - char c1, c2; - - if (p1 == p2) return 0; - - do { - c1 = mik_tolower(*p1++); - c2 = mik_tolower(*p2++); - if (c1 == '\0') break; - } while (c1 == c2); - - return (int)(c1 - c2); -} diff --git a/libs/mikmod/posix/strccmp.c b/libs/mikmod/posix/strccmp.c new file mode 100644 index 0000000..5b9935f --- /dev/null +++ b/libs/mikmod/posix/strccmp.c @@ -0,0 +1,23 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mikmod_internals.h" +#include "mikmod_ctype.h" + +int _mm_strcasecmp(const char *__s1, const char *__s2) +{ + const char *p1 = __s1; + const char *p2 = __s2; + char c1, c2; + + if (p1 == p2) return 0; + + do { + c1 = mik_tolower(*p1++); + c2 = mik_tolower(*p2++); + if (c1 == '\0') break; + } while (c1 == c2); + + return (int)(c1 - c2); +} diff --git a/src/cfgopt.c b/src/cfgopt.c index 170e47f..2197858 100644 --- a/src/cfgopt.c +++ b/src/cfgopt.c @@ -58,6 +58,10 @@ int parse_args(int argc, char **argv) opt.fullscreen = 1; } else if(strcmp(argv[i], "-win") == 0) { opt.fullscreen = 0; + } else if(strcmp(argv[i], "-scaler-nearest") == 0) { + opt.scaler = SCALER_NEAREST; + } else if(strcmp(argv[i], "-scaler-linear") == 0) { + opt.scaler = SCALER_LINEAR; #endif } else { fprintf(stderr, "invalid option: %s\n", argv[i]); @@ -152,6 +156,12 @@ int load_config(const char *fname) #ifndef MSDOS } else if(strcmp(line, "fullscreen") == 0) { opt.fullscreen = bool_value(value); + } else if(strcmp(line, "scaler") == 0) { + if(strcmp(value, "linear") == 0) { + opt.scaler = SCALER_LINEAR; + } else { + opt.scaler = SCALER_NEAREST; + } #endif } else { fprintf(stderr, "%s:%d invalid option: %s\n", fname, nline, line); diff --git a/src/cfgopt.h b/src/cfgopt.h index 9fc8c36..2bbaffb 100644 --- a/src/cfgopt.h +++ b/src/cfgopt.h @@ -1,6 +1,15 @@ #ifndef CFGOPT_H_ #define CFGOPT_H_ +#ifndef MSDOS +enum { + SCALER_NEAREST, + SCALER_LINEAR, + + NUM_SCALERS +}; +#endif + struct options { const char *start_scr; int music; @@ -9,6 +18,7 @@ struct options { int dbginfo; #ifndef MSDOS int fullscreen; + int scaler; #endif }; diff --git a/src/demo.h b/src/demo.h index 2060630..de0654b 100644 --- a/src/demo.h +++ b/src/demo.h @@ -8,6 +8,7 @@ /*extern int fb_width, fb_height, fb_bpp;*/ #define FB_WIDTH 320 #define FB_HEIGHT 240 +#define FB_ASPECT ((float)FB_WIDTH / (float)FB_HEIGHT) #define FB_BPP 16 extern uint16_t *fb_pixels; extern uint16_t *vmem; -- 1.7.10.4