⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dosgus.c

📁 tcpmp.src.0.72RC1 优秀的多媒体播放器TCPMP的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/*	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: dosgus.c,v 1.1 2004/02/01 02:01:17 raph Exp $    Driver for GUS cards under DOS==============================================================================*//*	Written by Andrew Zabolotny <bit@eltech.ru>*/#include <stdio.h>#include <stdlib.h>#include <dos.h>#include <dpmi.h>#include <sys/farptr.h>#include <sys/nearptr.h>#include <go32.h>#include <string.h>#include "dosgus.h"/********************************************* 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)#endifstatic 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 :-) */volatile 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;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -