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

📄 doswss.c

📁 tcpmp.src.0.72RC1 优秀的多媒体播放器TCPMP的源代码
💻 C
字号:
/*	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: doswss.c,v 1.1 2004/02/01 02:01:17 raph Exp $  Windows Sound System I/O routines (CS42XX, ESS18XX, GUS+DaughterBoard etc)==============================================================================*//*	Written by Andrew Zabolotny <bit@eltech.ru>*/#include <stdlib.h>#include <dpmi.h>#include <go32.h>#include <dos.h>#include <sys/nearptr.h>#include <sys/farptr.h>#include <string.h>#include "doswss.h"/********************************************* Private variables/routines *****/__wss_state wss;/* WSS frequency rates... lower bit selects one of two frequency generators */static unsigned int wss_rates[14][2] = {	{5510, 0x00 | WSSM_XTAL2},	{6620, 0x0E | WSSM_XTAL2},	{8000, 0x00 | WSSM_XTAL1},	{9600, 0x0E | WSSM_XTAL1},	{11025, 0x02 | WSSM_XTAL2},	{16000, 0x02 | WSSM_XTAL1},	{18900, 0x04 | WSSM_XTAL2},	{22050, 0x06 | WSSM_XTAL2},	{27420, 0x04 | WSSM_XTAL1},	{32000, 0x06 | WSSM_XTAL1},	{33075, 0x0C | WSSM_XTAL2},	{37800, 0x08 | WSSM_XTAL2},	{44100, 0x0A | WSSM_XTAL2},	{48000, 0x0C | WSSM_XTAL1}};static void wss_irq(){	/* Make sure its not a spurious IRQ */	if (!irq_check(wss.irq_handle))		return;	wss.irqcount++;	/* Clear IRQ status */	outportb(WSS_STATUS, 0);	/* Write transfer count again */	__wss_outreg(WSSR_COUNT_LOW, wss.samples & 0xff);	__wss_outreg(WSSR_COUNT_HIGH, wss.samples >> 8);	irq_ack(wss.irq_handle);	enable();	if (wss.timer_callback)		wss.timer_callback();}static void wss_irq_end(){}/* WSS accepts some conventional values instead of frequency in Hz... */static unsigned char __wss_getrate(unsigned int *freq){	int i, best = -1, delta = 0xffff;	for (i = 0; i < 14; i++) {		int newdelta = abs(wss_rates[i][0] - *freq);		if (newdelta < delta)			best = i, delta = newdelta;	}	*freq = wss_rates[best][0];	return wss_rates[best][1];}/* Check if we really have a WSS compatible card on given address */static boolean __wss_ping(){	/* Disable CODEC operations first */	__wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);	/* Now put some harmless values in registers and check them */	__wss_outreg(WSSR_COUNT_LOW, 0xaa);	__wss_outreg(WSSR_COUNT_HIGH, 0x55);	return (__wss_inreg(WSSR_COUNT_LOW) == 0xaa)	  && (__wss_inreg(WSSR_COUNT_HIGH) == 0x55);}static boolean __wss_reset(){	int count;	/* Disable output */	wss_output(FALSE);	/* Now select the test/initialization register */	count = 10000;	while (inportb(WSS_ADDR) != WSSR_TEST_INIT) {		outportb(WSS_ADDR, WSSR_TEST_INIT);		if (!--count)			return FALSE;	}	count = 10000;	while (inportb(WSS_DATA) & WSSM_CALIB_IN_PROGRESS) {		outportb(WSS_ADDR, WSSR_TEST_INIT);		if (!--count)			return FALSE;	}	/* Enable playback IRQ */	__wss_regbit_set(WSSR_PIN_CTRL, WSSM_IRQ_ENABLE);	__wss_outreg(WSSR_IRQ_STATUS, WSSM_PLAYBACK_IRQ);	/* Clear IRQ status */	outportb(WSS_STATUS, 0);	return TRUE;}static boolean __wss_setformat(unsigned char format){	int count;	outportb(WSS_ADDR, WSSM_MCE | WSSR_PLAY_FORMAT);	outportb(WSS_DATA, format);	inportb(WSS_DATA);			/* ERRATA SHEETS ... */	inportb(WSS_DATA);			/* ERRATA SHEETS ... */	/* Wait end of syncronization ... */	if (!__wss_wait())		return FALSE;	/* Turn off the ModeChangeEnable bit: do it until it works */	count = 10000;	while (inportb(WSS_ADDR) != WSSR_PLAY_FORMAT) {		outportb(WSS_ADDR, WSSR_PLAY_FORMAT);		if (!--count)			return FALSE;	}	return __wss_reset();}/**************************************************** WSS detection stuff *****/static int __wss_irq_irqdetect(int irqno){	unsigned char status = inportb(WSS_STATUS);	/* Clear IRQ status */	outportb(WSS_STATUS, 0);	/* Reset transfer counter */	__wss_outreg(WSSR_COUNT_LOW, 0);	__wss_outreg(WSSR_COUNT_HIGH, 0);	return (status & WSSM_INT);}static boolean __wss_detect(){	/* First find the port number */	if (!wss.port) {		static unsigned int wss_ports[] =		  { 0x32c, 0x530, 0x604, 0xE80, 0xF40 };		int i;		for (i = 0; i < 5; i++) {			wss.port = wss_ports[i];			if (__wss_ping())				break;		}		if (i < 0) {			wss.port = 0;			return FALSE;		}	}	/* Now disable output */	wss_output(FALSE);	/* Detect the DMA channel */	if (!wss.dma) {		static int __dma[] = { 0, 1, 3 };		int i;		/* Enable playback IRQ */		__wss_regbit_set(WSSR_PIN_CTRL, WSSM_IRQ_ENABLE);		__wss_outreg(WSSR_IRQ_STATUS, WSSM_PLAYBACK_IRQ);		/* Start a short DMA transfer and check if DMA count is zero */		for (i = 0; i < 3; i++) {			unsigned int timer, status, freq = 44100;			wss.dma = __dma[i];			dma_disable(wss.dma);			dma_set_mode(wss.dma, DMA_MODE_WRITE);			dma_clear_ff(wss.dma);			dma_set_count(wss.dma, 10);			dma_enable(wss.dma);			/* Clear IRQ status */			outportb(WSS_STATUS, 0);			__wss_setformat(__wss_getrate(&freq));			__wss_outreg(WSSR_COUNT_LOW, 1);			__wss_outreg(WSSR_COUNT_HIGH, 0);			/* Tell codec to start transfer */			__wss_regbit_set(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);			_farsetsel(_dos_ds);			timer = _farnspeekl(0x46c);			while (_farnspeekl(0x46c) - timer <= 2)				if (dma_get_count(wss.dma) == 0)					break;			__wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);			dma_disable(wss.dma);			/* Now check if DMA transfer count is zero and an IRQ is pending */			status = inportb(WSS_STATUS);			outportb(WSS_STATUS, 0);			if ((dma_get_count(wss.dma) == 0) && (status & WSSM_INT))				break;			wss.dma = 0;		}		if (!wss.dma)			return FALSE;	}	/* Now detect the IRQ number */	if (!wss.irq) {		unsigned int i, irqmask, freq = 5510;		unsigned long timer, delta = 0x7fffffff;		/* IRQ can be one of 2,3,5,7,10 */		irq_detect_start(0x04ac, __wss_irq_irqdetect);		dma_disable(wss.dma);		dma_set_mode(wss.dma, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);		dma_clear_ff(wss.dma);		dma_set_count(wss.dma, 1);		dma_enable(wss.dma);		__wss_setformat(__wss_getrate(&freq));		/* Clear IRQ status */		outportb(WSS_STATUS, 0);		__wss_outreg(WSSR_COUNT_LOW, 0);		__wss_outreg(WSSR_COUNT_HIGH, 0);		/* Prepare timeout counter */		_farsetsel(_dos_ds);		timer = _farnspeekl(0x46c);		while (timer == _farnspeekl(0x46c));		timer = _farnspeekl(0x46c);		/* Reset all IRQ counters */		irq_detect_clear();		/* Tell codec to start transfer */		__wss_regbit_set(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);		/* Now wait 1/18 seconds */		while (timer == _farnspeekl(0x46c));		__wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);		dma_disable(wss.dma);		/* Given frequency 5510Hz, a buffer size of 1 byte and a time interval		   of 1/18.2 second, we should have received about 302 interrupts */		for (i = 2; i <= 10; i++) {			int count = abs(302 - irq_detect_get(i, &irqmask));			if (count < delta)				wss.irq = i, delta = count;		}		if (delta > 150)			wss.irq = 0;		irq_detect_end();		if (!wss.irq)			return FALSE;	}	return TRUE;}/*************************************************** High-level interface *****//* Detect whenever WSS is present and fill "wss" structure */boolean wss_detect(){	char *env;	/* Try to find the port and DMA from environment */	env = getenv("WSS");	while (env && *env) {		/* Skip whitespace */		while ((*env == ' ') || (*env == '\t'))			env++;		if (!*env)			break;		switch (*env++) {		  case 'A':		  case 'a':			if (!wss.port)				wss.port = strtol(env, &env, 16);			break;		  case 'I':		  case 'i':			if (!wss.irq)				wss.irq = strtol(env, &env, 10);			break;		  case 'D':		  case 'd':			if (!wss.dma)				wss.dma = strtol(env, &env, 10);			break;		  default:			/* Skip other values */			while (*env && (*env != ' ') && (*env != '\t'))				env++;			break;		}	}	/* Try to fill the gaps in wss hardware parameters */	__wss_detect();	if (!wss.port || !wss.irq || !wss.dma)		return FALSE;	if (!__wss_ping())		return FALSE;	if (!__wss_reset())		return FALSE;	wss.ok = 1;	return TRUE;}/* Reset WSS */void wss_reset(){	wss_stop_dma();	__wss_reset();}/* Open WSS for usage */boolean wss_open(){	__dpmi_meminfo struct_info;	if (!wss.ok)		if (!wss_detect())			return FALSE;	if (wss.open)		return FALSE;	/* Now lock the wss structure in memory */	struct_info.address = __djgpp_base_address + (unsigned long)&wss;	struct_info.size = sizeof(wss);	if (__dpmi_lock_linear_region(&struct_info))		return FALSE;	/* Hook the WSS IRQ */	wss.irq_handle =	  irq_hook(wss.irq, wss_irq, (long)wss_irq_end - (long)wss_irq);	if (!wss.irq_handle) {		__dpmi_unlock_linear_region(&struct_info);		return FALSE;	}	/* Enable the interrupt */	irq_enable(wss.irq_handle);	if (wss.irq > 7)		_irq_enable(2);	wss.open++;	return TRUE;}/* Finish working with WSS */boolean wss_close(){	__dpmi_meminfo struct_info;	if (!wss.open)		return FALSE;	wss.open--;	/* Stop/free DMA buffer */	wss_stop_dma();	/* Unhook IRQ */	irq_unhook(wss.irq_handle);	wss.irq_handle = NULL;	/* Unlock the wss structure */	struct_info.address = __djgpp_base_address + (unsigned long)&wss;	struct_info.size = sizeof(wss);	__dpmi_unlock_linear_region(&struct_info);	return TRUE;}/* Adjust frequency rate to nearest WSS available */unsigned int wss_adjust_freq(unsigned int freq){	__wss_getrate(&freq);	return freq;}/* Enable/disable speaker output *//* Start playing from DMA buffer in either 8/16 bit mono/stereo */boolean wss_start_dma(unsigned char mode, unsigned int freq){	int dmabuffsize;	unsigned char format;	/* Stop DMA transfer if it is enabled */	wss_stop_dma();	/* Sanity check: we support only 8-bit unsigned and 16-bit signed formats */	if (((mode & WSSMODE_16BITS) && !(mode & WSSMODE_SIGNED))		|| (!(mode & WSSMODE_16BITS) && (mode & WSSMODE_SIGNED)))		return FALSE;	/* Find the nearest frequency divisor (rate) */	format = __wss_getrate(&freq);	wss.mode = mode;	/* Get a DMA buffer enough for a 1sec interval... 4K <= dmasize <= 32K */	dmabuffsize = freq;	if (mode & WSSMODE_STEREO)		dmabuffsize *= 2;	if (mode & WSSMODE_16BITS)		dmabuffsize *= 2;	dmabuffsize >>= 2;	if (dmabuffsize < 4096)		dmabuffsize = 4096;	if (dmabuffsize > 32768)		dmabuffsize = 32768;	dmabuffsize = (dmabuffsize + 255) & 0xffffff00;	wss.dma_buff = dma_allocate(wss.dma, dmabuffsize);	if (!wss.dma_buff)		return FALSE;	/* Fill DMA buffer with silence */	dmabuffsize = wss.dma_buff->size;	if (mode & WSSMODE_SIGNED)		memset(wss.dma_buff->linear, 0, dmabuffsize);	else		memset(wss.dma_buff->linear, 0x80, dmabuffsize);	/* Check data size and build a WSSR_PLAY_FORMAT value accordingly */	wss.samples = dmabuffsize;	if (mode & WSSMODE_16BITS) {		wss.samples >>= 1;		format |= WSSM_16BITS;	}	if (mode & WSSMODE_STEREO) {		wss.samples >>= 1;		format |= WSSM_STEREO;	}	if (!__wss_setformat(format)) {		wss_stop_dma();		return FALSE;	}	/* Prime DMA for transfer */	dma_start(wss.dma_buff, dmabuffsize, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);	/* Tell codec how many samples to transfer */	wss.samples = (wss.samples >> 1) - 1;	__wss_outreg(WSSR_COUNT_LOW, wss.samples & 0xff);	__wss_outreg(WSSR_COUNT_HIGH, wss.samples >> 8);	/* Tell codec to start transfer */	__wss_regbit_set(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);	return TRUE;}/* Stop playing from DMA buffer */void wss_stop_dma(){	if (!wss.dma_buff)		return;	__wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE);	dma_disable(wss.dma);	dma_free(wss.dma_buff);	wss.dma_buff = NULL;}/* Query current position/total size of the DMA buffer */void wss_query_dma(unsigned int *dma_size, unsigned int *dma_pos){	unsigned int dma_left;	*dma_size = wss.dma_buff->size;	/* It can happen we try to read DMA count when HI/LO bytes will be	   inconsistent */	for (;;) {		unsigned int dma_left_test;		dma_clear_ff(wss.dma);		dma_left_test = dma_get_count(wss.dma);		dma_left = dma_get_count(wss.dma);		if ((dma_left >= dma_left_test) && (dma_left - dma_left_test < 10))			break;	}	*dma_pos = *dma_size - dma_left;}void wss_output(boolean enable){	if (enable)		wss.curlevel = wss.level;	else		wss.curlevel = 0x3f;	__wss_outreg(WSSR_MASTER_L, wss.curlevel);	__wss_outreg(WSSR_MASTER_R, wss.curlevel);}void wss_level(int level){	if (level < 0)		level = 0;	if (level > 63)		level = 63;	wss.curlevel = wss.level = level ^ 63;	__wss_outreg(WSSR_MASTER_L, wss.curlevel);	__wss_outreg(WSSR_MASTER_R, wss.curlevel);}/* ex:set ts=4: */

⌨️ 快捷键说明

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