This patch intends to provide the necessary infrastrucure to enable sound in DOS games. The board is configured at address=0x220, irq=5 and dma=1. Irq and dma are just #define but can be set from a config file. The dma emulation is almost complete and the soundblaster emulation, altough it still needs a lot of work, works fairly with digital 8-bit sound. At least for the game Dreamweb I used to debug my code... This version is much cleaner that the previous one and fix the unresolved external (caused by a missing file in the diff). If something is wrong with this code, feel free to ask. Changelog: Add DMA and SOUNBLASTER emulation Added files: dlls/winedos/dma.h dlls/winedos/dma.c dlls/winedos/soundblaster.h dlls/winedos/soundblaster.c Modified files: dlls/winedos/ioports.c dlls/winedos/Makefile.in Christian Costa titan.costa@wanadoo.fr
/* * DMA Emulation * * Copyright 2002 Christian Costa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 */ #ifndef __WINE_DMA_H #define __WINE_DMA_H #include "winbase.h" int DMA_Transfer(int channel,int reqlength,void* buffer); void DMA_ioport_out( WORD port, BYTE val ); BYTE DMA_ioport_in( WORD port ); #endif /* __WINE_DMA_H */
/* * DMA Emulation * * Copyright 2002 Christian Costa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 */ #include "config.h" #include "windef.h" #include "dosexe.h" #include "dma.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(dma); /* Internal registers of the 2 DMA chips wich control 8 DMA channels */ static DWORD DMA_BaseAddress[8]; static WORD DMA_ByteCount[8]; static DWORD DMA_CurrentBaseAddress[8]; static WORD DMA_CurrentByteCount[8]; static BYTE DMA_Command[8]; static BYTE DMA_Mask[2]={0x0F,0x0F}; static BYTE DMA_Status[2]={0x00,0x00}; static BOOL DMA_Toggle[2]={FALSE,FALSE}; /* * DMA_Transfer : Try to perform a transfer of reqlen elements (8 or 16 bits) * on the specified channel and return the elements transferred */ int DMA_Transfer(int channel,int reqlen,void* buffer) { int i,size,ret=0; int opmode,increment,autoinit,trmode,dmachip; int regmode = DMA_Command[channel]; char *p,*dmabuf; dmabuf = buffer; dmachip = (channel<4) ? 0 : 1; TRACE("DMA_Command = %x reqlen=%d\n",regmode,reqlen); /* Exit if channel is masked */ if (DMA_Mask[dmachip]&(1<<(channel&3))) return 0; opmode = (regmode & 0xC0) >> 6; increment = !(regmode & 0x20); autoinit = regmode & 0x10; trmode = (regmode & 0x0C) >> 2; /* Transfer size : 8 bits for channels 0..3, 16 bits for channels 4..7 */ size = (channel<4) ? 1 : 2; /* Process operating mode */ switch(opmode) { case 0: /* Request mode */ FIXME("Request Mode - Not Implemented\n"); return 0; case 1: /* Single Mode */ break; case 2: /* Request mode */ FIXME("Block Mode - Not Implemented\n"); return 0; case 3: /* Cascade Mode */ ERR("Cascade Mode should not be used by regular apps\n"); return 0; } /* Perform one the 4 transfer modes */ if (trmode == 4) { /* Illegal */ ERR("DMA Transfer Type Illegal\n"); return 0; } ret = min(DMA_CurrentByteCount[channel],reqlen); /* Update DMA registers */ DMA_CurrentByteCount[channel]-=ret; if (increment) DMA_CurrentBaseAddress[channel] += ret * size; else DMA_CurrentBaseAddress[channel] -= ret * size; switch(trmode) { case 0: /* Verification (no real transfer)*/ TRACE("Verification DMA operation\n"); break; case 1: /* Write */ TRACE("Perform Write transfer of %d bytes at %lx with count %x\n",ret, DMA_CurrentBaseAddress[channel],DMA_CurrentByteCount[channel]); if (increment) memcpy((void*)DMA_CurrentBaseAddress[channel],dmabuf,ret*size); else for(i=0,p=(char*)DMA_CurrentBaseAddress[channel];i<ret*size;i++) /* FIXME: possible endianness issue for 16 bits DMA */ *(p-i) = dmabuf[i]; break; case 2: /* Read */ TRACE("Perform Read transfer of %d bytes at %lx with count %x\n",ret, DMA_CurrentBaseAddress[channel],DMA_CurrentByteCount[channel]); if (increment) memcpy(dmabuf,(void*)DMA_CurrentBaseAddress[channel],ret*size); else for(i=0,p=(char*)DMA_CurrentBaseAddress[channel];i<ret*size;i++) /* FIXME: possible endianness issue for 16 bits DMA */ dmabuf[i] = *(p-i); break; } /* Check for end of transfer */ if (DMA_CurrentByteCount[channel]==0) { TRACE("DMA buffer empty\n"); /* Update status register of the DMA chip corresponding to the channel */ DMA_Status[dmachip] |= 1 << (channel & 0x3); /* Mark transfer as finished */ DMA_Status[dmachip] &= ~(1 << ((channel & 0x3) + 4)); /* Reset soft request if any */ if (autoinit) { /* Reload Current* register to their initial values */ DMA_CurrentBaseAddress[channel] = DMA_BaseAddress[channel]; DMA_CurrentByteCount[channel] = DMA_ByteCount[channel]; } } return ret; } void DMA_ioport_out( WORD port, BYTE val ) { int channel,dmachip; switch(port) { case 0x00: case 0x02: case 0x04: case 0x06: case 0xC0: case 0xC4: case 0xC8: case 0xCC: /* Base Address*/ channel = (port&0xC0)?((port-0xC0)>>2):(port>>1); dmachip = (channel<4) ? 0 : 1; if (!DMA_Toggle[dmachip]) DMA_BaseAddress[channel]=(DMA_BaseAddress[channel] & ~0xFF)|(val & 0xFF); else { DMA_BaseAddress[channel]=(DMA_BaseAddress[channel] & (~(0xFF << 8)))|((val & 0xFF) << 8); DMA_CurrentBaseAddress[channel] = DMA_BaseAddress[channel]; TRACE("Write Base Address = %lx\n",DMA_BaseAddress[channel]); } DMA_Toggle[dmachip] = !DMA_Toggle[dmachip]; break; case 0x01: case 0x03: case 0x05: case 0x07: case 0xC2: case 0xC6: case 0xCA: case 0xCE: /* Count*/ channel = ((port-1)&0xC0)?(((port-1)-0xC0)>>2):(port>>1); dmachip = (channel<4) ? 0 : 1; if (!DMA_Toggle[dmachip]) DMA_ByteCount[channel]=(DMA_ByteCount[channel] & ~0xFF)|((val+1) & 0xFF); else { DMA_ByteCount[channel]=(DMA_ByteCount[channel] & (~(0xFF << 8)))|(((val+1) & 0xFF) << 8); DMA_CurrentByteCount[channel] = DMA_ByteCount[channel]; TRACE("Write Count = %x.\n",DMA_ByteCount[channel]); } DMA_Toggle[dmachip] = !DMA_Toggle[dmachip]; break; /* Low Page Base Address */ case 0x87: DMA_BaseAddress[0]=(DMA_BaseAddress[0] & (~0xFF << 16))|((val & 0xFF) << 16); break; case 0x83: DMA_BaseAddress[1]=(DMA_BaseAddress[1] & (~0xFF << 16))|((val & 0xFF) << 16); break; case 0x81: DMA_BaseAddress[2]=(DMA_BaseAddress[2] & (~0xFF << 16))|((val & 0xFF) << 16); break; case 0x82: DMA_BaseAddress[3]=(DMA_BaseAddress[3] & (~0xFF << 16))|((val & 0xFF) << 16); break; case 0x8B: DMA_BaseAddress[5]=(DMA_BaseAddress[5] & (~0xFF << 16))|((val & 0xFF) << 16); break; case 0x89: DMA_BaseAddress[6]=(DMA_BaseAddress[6] & (~0xFF << 16))|((val & 0xFF) << 16); break; case 0x8A: DMA_BaseAddress[7]=(DMA_BaseAddress[7] & (~0xFF << 16))|((val & 0xFF) << 16); break; /* Low Page Base Address (only 4 lower bits are significant) */ case 0x487: DMA_BaseAddress[0]=(DMA_BaseAddress[0] & (~0xFF << 24))|((val & 0x0F) << 24); break; case 0x483: DMA_BaseAddress[1]=(DMA_BaseAddress[1] & (~0xFF << 24))|((val & 0x0F) << 24); break; case 0x481: DMA_BaseAddress[2]=(DMA_BaseAddress[2] & (~0xFF << 24))|((val & 0x0F) << 24); break; case 0x482: DMA_BaseAddress[3]=(DMA_BaseAddress[3] & (~0xFF << 24))|((val & 0x0F) << 24); break; case 0x48B: DMA_BaseAddress[5]=(DMA_BaseAddress[5] & (~0xFF << 24))|((val & 0x0F) << 24); break; case 0x489: DMA_BaseAddress[6]=(DMA_BaseAddress[6] & (~0xFF << 24))|((val & 0x0F) << 24); break; case 0x48A: DMA_BaseAddress[7]=(DMA_BaseAddress[7] & (~0xFF << 24))|((val & 0x0F) << 24); break; case 0x08: case 0xD0: /* Command */ FIXME("Write Command (%x) - Not Implemented\n",val); break; case 0x0B: case 0xD6: /* Mode */ TRACE("Write Mode (%x)\n",val); DMA_Command[((port==0xD6)?4:0)+(val&0x3)]=val; switch(val>>6) { case 0: /* Request mode */ FIXME("Request Mode - Not Implemented\n"); break; case 1: /* Single Mode */ break; case 2: /* Block mode */ FIXME("Block Mode - Not Implemented\n"); break; case 3: /* Cascade Mode */ ERR("Cascade Mode should not be used by regular apps\n"); break; } break; case 0x0A: case 0xD4: /* Write Single Mask Bit */ TRACE("Write Single Mask Bit (%x)\n",val); dmachip = (port==0x0A) ? 0 : 1; if (val&4) DMA_Mask[dmachip] |= 1<<(val&3); else DMA_Mask[dmachip] &= ~(1<<(val&3)); break; case 0x0F: case 0xDE: /* Write All Mask Bits (only 4 lower bits are significant */ FIXME("Write All Mask Bits (%x)\n",val); dmachip = (port==0x0F) ? 0 : 1; DMA_Mask[dmachip] = val & 0x0F; break; case 0x09: case 0xD2: /* Software DRQx Request */ FIXME("Software DRQx Request (%x) - Not Implemented\n",val); break; case 0x0C: case 0xD8: /* Reset DMA Pointer Flip-Flop */ TRACE("Reset Flip-Flop\n"); DMA_Toggle[port==0xD8]=FALSE; break; case 0x0D: case 0xDA: /* Master Reset */ TRACE("Master Reset\n"); dmachip = (port==0x0D) ? 0 : 1; /* Reset DMA Pointer Flip-Flop */ DMA_Toggle[dmachip]=FALSE; /* Mask all channels */ DMA_Mask[dmachip] = 0x0F; break; case 0x0E: case 0xDC: /* Reset Mask Register */ FIXME("Reset Mask Register\n"); dmachip = (port==0x0E) ? 0 : 1; /* Unmask all channels */ DMA_Mask[dmachip] = 0x00; break; } } BYTE DMA_ioport_in( WORD port ) { int channel,dmachip; BYTE res = 0; switch(port) { case 0x00: case 0x02: case 0x04: case 0x06: case 0xC0: case 0xC4: case 0xC8: case 0xCC: /* Base Address*/ channel = (port&0xC0)?((port-0xC0)>>2):(port>>1); dmachip = (channel<4) ? 0 : 1; if (!DMA_Toggle[dmachip]) res = DMA_CurrentBaseAddress[channel] & 0xFF; else { res = (DMA_CurrentBaseAddress[channel] & (0xFF << 8))>>8; TRACE("Read Current Base Address = %lx\n",DMA_CurrentBaseAddress[channel]); } DMA_Toggle[dmachip] = !DMA_Toggle[dmachip]; break; case 0x01: case 0x03: case 0x05: case 0x07: case 0xC2: case 0xC6: case 0xCA: case 0xCE: /* Count*/ channel = ((port-1)&0xC0)?(((port-1)-0xC0)>>2):(port>>1); dmachip = (channel<4) ? 0 : 1; if (!DMA_Toggle[dmachip]) res = DMA_CurrentByteCount[channel] & 0xFF; else { res = (DMA_CurrentByteCount[channel] & (0xFF << 8))>>8; TRACE("Read Current Count = %x.\n",DMA_CurrentByteCount[channel]); } DMA_Toggle[dmachip] = !DMA_Toggle[dmachip]; break; /* Low Page Base Address */ case 0x87: res = (DMA_BaseAddress[0]&(0xFF<<16))>>16; break; case 0x83: res = (DMA_BaseAddress[1]&(0xFF<<16))>>16; break; case 0x81: res = (DMA_BaseAddress[2]&(0xFF<<16))>>16; break; case 0x82: res = (DMA_BaseAddress[3]&(0xFF<<16))>>16; break; case 0x8B: res = (DMA_BaseAddress[5]&(0xFF<<16))>>16; break; case 0x89: res = (DMA_BaseAddress[6]&(0xFF<<16))>>16; break; case 0x8A: res = (DMA_BaseAddress[7]&(0xFF<<16))>>16; break; /* High Page Base Address */ case 0x487: res = (DMA_BaseAddress[0]&(0xFF<<24))>>24; break; case 0x483: res = (DMA_BaseAddress[1]&(0xFF<<24))>>24; break; case 0x481: res = (DMA_BaseAddress[2]&(0xFF<<24))>>24; break; case 0x482: res = (DMA_BaseAddress[3]&(0xFF<<24))>>24; break; case 0x48B: res = (DMA_BaseAddress[5]&(0xFF<<24))>>24; break; case 0x489: res = (DMA_BaseAddress[6]&(0xFF<<24))>>24; break; case 0x48A: res = (DMA_BaseAddress[7]&(0xFF<<24))>>24; break; case 0x08: case 0xD0: /* Status */ TRACE("Status Register Read\n"); res = DMA_Status[(port==0x08)?0:1]; case 0x0D: case 0xDA: /* Temporary */ FIXME("Temporary Register Read- Not Implemented\n"); break; } return res; }
/* * Soundblaster Emulation * * Copyright 2002 Christian Costa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 */ #ifndef __WINE_SOUNDBLASTER_H #define __WINE_SOUNDBLASTER_H #include "winbase.h" void SB_ioport_out( WORD port, BYTE val ); BYTE SB_ioport_in( WORD port ); #endif /* __WINE_SOUNDBLASTER_H */
/* * Soundblaster Emulation * * Copyright 2002 Christian Costa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 */ #include "config.h" #include "windef.h" #include "dosexe.h" #include "soundblaster.h" #include "wine/debug.h" #include "dsound.h" #include "dma.h" WINE_DEFAULT_DEBUG_CHANNEL(sblaster); /* Board Configuration */ /* FIXME: Should be in a config file */ #define SB_IRQ 5 #define SB_IRQ_PRI 11 #define SB_DMA 1 /* Soundblaster state */ static int SampleMode; /* Mono / Stereo */ static int SampleRate; static int SamplesCount; static BYTE DSP_Command[256]; /* Store param numbers in bytes for each command */ static BYTE DSP_InBuffer[10]; /* Store DSP command bytes parameters from host */ static int InSize; /* Nb of bytes in InBuffer */ static BYTE DSP_OutBuffer[10]; /* Store DSP information bytes to host */ static int OutSize; /* Nb of bytes in InBuffer */ static int command; /* Current command */ static int end_sound_loop = 0; static int dma_enable = 0; /* The maximum size of a dma transfer can be 65536 */ #define DMATRFSIZE 1024 /* DMA can perform 8 or 16-bit transfer */ static BYTE dma_buffer[DMATRFSIZE*2]; /* Direct Sound buffer config */ #define DSBUFLEN 4096 /* FIXME: Only this value seems to work */ /* Direct Sound playback stuff */ static HMODULE hmodule; typedef HRESULT (WINAPI* fnDirectSoundCreate) (LPGUID,LPDIRECTSOUND*,LPUNKNOWN); fnDirectSoundCreate lpDirectSoundCreate; static LPDIRECTSOUND lpdsound; static LPDIRECTSOUNDBUFFER lpdsbuf; static DSBUFFERDESC buf_desc; static WAVEFORMATEX wav_fmt; static HANDLE SB_Thread; static UINT buf_off; extern HWND vga_hwnd; /* SB_Poll performs DMA transfers and fills the Direct Sound Buffer */ static DWORD CALLBACK SB_Poll( void *dummy ) { HRESULT result; LPBYTE lpbuf1 = NULL; LPBYTE lpbuf2 = NULL; DWORD dwsize1 = 0; DWORD dwsize2 = 0; DWORD dwbyteswritten1 = 0; DWORD dwbyteswritten2 = 0; int size; /* FIXME: this loop must be improved */ while(!end_sound_loop) { Sleep(10); if (dma_enable) { size = DMA_Transfer(SB_DMA,min(DMATRFSIZE,SamplesCount),dma_buffer); } else continue; result = IDirectSoundBuffer_Lock(lpdsbuf,buf_off,size,&lpbuf1,&dwsize1,&lpbuf2,&dwsize2,0); if (result != DS_OK) { ERR("Unable to lock sound buffer !\n"); continue; } dwbyteswritten1 = min(size,dwsize1); memcpy(lpbuf1,dma_buffer,dwbyteswritten1); if (size>dwsize1) { dwbyteswritten2 = min(size - dwbyteswritten1,dwsize2); memcpy(lpbuf2,dma_buffer+dwbyteswritten1,dwbyteswritten2); } buf_off = (buf_off + dwbyteswritten1 + dwbyteswritten2) % DSBUFLEN; result = IDirectSoundBuffer_Unlock(lpdsbuf,lpbuf1,dwbyteswritten1,lpbuf2,dwbyteswritten2); if (result!=DS_OK) ERR("Unable to unlock sound buffer !\n"); SamplesCount -= size; if (!SamplesCount) { DOSVM_QueueEvent(SB_IRQ,SB_IRQ_PRI,NULL,NULL); dma_enable = 0; } } return 0; } BOOL SB_Init() { HRESULT result; if (!lpdsound) { hmodule = LoadLibraryA("dsound.dll"); if (!hmodule) { ERR("Can't load dsound.dll !\n"); return 0; } lpDirectSoundCreate = (fnDirectSoundCreate)GetProcAddress(hmodule,"DirectSoundCreate"); if (!lpDirectSoundCreate) { /* CloseHandle(hmodule); */ ERR("Can't find DirectSoundCreate function !\n"); return 0; } result = (*lpDirectSoundCreate)(NULL,&lpdsound,NULL); if (result != DS_OK) { ERR("Unable to initialize Sound Subsystem err = %lx !\n",result); return 0; } /* FIXME: To uncomment when : - SetCooperative level is correctly implemented - an always valid and non changing handle to a windows (vga_hwnd) is available (this surely needs some work in vga.c) result = IDirectSound_SetCooperativeLevel(lpdsound,vga_hwnd,DSSCL_EXCLUSIVE|DSSCL_PRIORITY); if (result != DS_OK) { ERR("Can't set cooperative level !\n"); return 0; } */ /* Default format */ wav_fmt.wFormatTag = WAVE_FORMAT_PCM; wav_fmt.nChannels = 1; wav_fmt.nSamplesPerSec = 22050; wav_fmt.nAvgBytesPerSec = 22050; wav_fmt.nBlockAlign = 1; wav_fmt.wBitsPerSample = 8; wav_fmt.cbSize = 0; memset(&buf_desc,0,sizeof(DSBUFFERDESC)); buf_desc.dwSize = sizeof(DSBUFFERDESC); buf_desc.dwBufferBytes = DSBUFLEN; buf_desc.lpwfxFormat = &wav_fmt; result = IDirectSound_CreateSoundBuffer(lpdsound,&buf_desc,&lpdsbuf,NULL); if (result != DS_OK) { ERR("Can't create sound buffer !\n"); return 0; } result = IDirectSoundBuffer_Play(lpdsbuf,0, 0, DSBPLAY_LOOPING); if (result != DS_OK) { ERR("Can't start playing !\n"); return 0; } buf_off = 0; end_sound_loop = 0; SB_Thread = CreateThread(NULL, 0, SB_Poll, NULL, 0, NULL); TRACE("thread\n"); if (!SB_Thread) { ERR("Can't create thread !\n"); return 0; } } return 1; } void SB_Reset() { int i; for(i=0;i<256;i++) DSP_Command[i]=0; /* Set Time Constant */ DSP_Command[0x40]=1; /* Generate IRQ */ DSP_Command[0xF2]=0; /* DMA DAC 8-bits */ DSP_Command[0x14]=2; /* Generic DAC/ADC DMA (16-bit, 8-bit) */ for(i=0xB0;i<=0xCF;i++) DSP_Command[i]=3; /* DSP Indentification */ DSP_Command[0xE0]=1; /* Clear command and input buffer */ command = -1; InSize = 0; /* Put a garbage value in the output buffer */ OutSize = 1; if (SB_Init()) /* All right, let's put the magic value for autodetection */ DSP_OutBuffer[0] = 0xaa; else /* Something is wrong, put 0 to failed audetection */ DSP_OutBuffer[0] = 0x00; } /* Find a standard sampling rate for DirectSound */ int SB_StdSampleRate(int SampleRate) { if (SampleRate>((44100+48000)/2)) return 48000; if (SampleRate>((32000+44100)/2)) return 44100; if (SampleRate>((24000+32000)/2)) return 32000; if (SampleRate>((22050+24000)/2)) return 24000; if (SampleRate>((16000+22050)/2)) return 22050; if (SampleRate>((12000+16000)/2)) return 16000; if (SampleRate>((11025+12000)/2)) return 12000; if (SampleRate>((8000+11025)/2)) return 11025; return 8000; } void SB_ioport_out( WORD port, BYTE val ) { switch(port) { /* DSP - Reset */ case 0x226: TRACE("Resetting DSP.\n"); SB_Reset(); break; /* DSP - Write Data or Command */ case 0x22c: TRACE("val=%x\n",val); if (command == -1) { /* Clear input buffer and set the current command */ command = val; InSize = 0; } if (InSize!=DSP_Command[command]) /* Fill the input buffer the command parameters if any */ DSP_InBuffer[InSize++]=val; else { /* Process command */ switch(command) { case 0x10: /* SB */ FIXME("Direct DAC (8-bit) - Not Implemented\n"); break; case 0x14: /* SB */ SamplesCount = DSP_InBuffer[1]+(val<<8)+1; TRACE("DMA DAC (8-bit) for %x samples\n",SamplesCount); dma_enable = 1; break; case 0x20: FIXME("Direct ADC (8-bit) - Not Implemented\n"); break; case 0x24: /* SB */ FIXME("DMA ADC (8-bit) - Not Implemented\n"); break; case 0x40: /* SB */ SampleRate = 1000000/(256-val); TRACE("Set Time Constant (%d <-> %d Hz => %d Hz)\n",DSP_InBuffer[0], SampleRate,SB_StdSampleRate(SampleRate)); SampleRate = SB_StdSampleRate(SampleRate); wav_fmt.nSamplesPerSec = SampleRate; wav_fmt.nAvgBytesPerSec = SampleRate; IDirectSoundBuffer_SetFormat(lpdsbuf,&wav_fmt); break; /* case 0xBX/0xCX -> See below */ case 0xD0: /* SB */ TRACE("Halt DMA operation (8-bit)\n"); dma_enable = 0; break; case 0xD1: /* SB */ FIXME("Enable Speaker - Not Implemented\n"); break; case 0xD3: /* SB */ FIXME("Disable Speaker - Not Implemented\n"); break; case 0xD4: /* SB */ FIXME("Continue DMA operation (8-bit) - Not Implemented\n"); break; case 0xD8: /* SB */ FIXME("Speaker Status - Not Implemented\n"); break; case 0xE0: /* SB 2.0 */ TRACE("DSP Identification\n"); DSP_OutBuffer[OutSize++] = ~val; break; case 0xE1: /* SB */ FIXME("DSP Version - Not Implemented\n"); break; case 0xF2: /* SB */ TRACE("IRQ Request (8-bit)\n"); DOSVM_QueueEvent(SB_IRQ,SB_IRQ_PRI,NULL,NULL); break; default: if (((command&0xF0)==0xB0)||((DSP_InBuffer[0]&0xF0)==0xC0)) { /* SB16 */ FIXME("Generic DAC/ADC DMA (16-bit, 8-bit) - %d % d\n",command,DSP_InBuffer[1]); if (command&0x02) FIXME("Generic DAC/ADC fifo mode not supported\n"); if (command&0x04) FIXME("Generic DAC/ADC autoinit dma mode not supported\n"); if (command&0x08) FIXME("Generic DAC/ADC adc mode not supported\n"); switch(command>>4) { case 0xB: FIXME("Generic DAC/ADC 8-bit not supported\n"); SampleMode = 0; break; case 0xC: FIXME("Generic DAC/ADC 16-bit not supported\n"); SampleMode = 1; break; default: ERR("Generic DAC/ADC resolution unknown\n"); break; } if (DSP_InBuffer[1]&0x010) FIXME("Generic DAC/ADC signed sample mode not supported\n"); if (DSP_InBuffer[1]&0x020) FIXME("Generic DAC/ADC stereo mode not supported\n"); SamplesCount = DSP_InBuffer[2]+(val<<8)+1; TRACE("Generic DMA for %x samples\n",SamplesCount); dma_enable = 1; } else FIXME("DSP command %x not supported\n",val); } /* Empty the input buffer and end the command */ InSize = 0; command = -1; } } } BYTE SB_ioport_in( WORD port ) { BYTE res = 0; switch(port) { /* DSP Read Data */ case 0x22a: /* Value in the read buffer */ if (OutSize) res = DSP_OutBuffer[--OutSize]; else /* return the last byte */ res = DSP_OutBuffer[0]; break; /* DSP - Write Buffer Status */ case 0x22c: /* DSP always ready for writing */ res = 0x00; break; /* DSP - Data Available Status */ /* DSP - IRQ Acknowledge, 8-bit */ case 0x22e: /* DSP data availability check */ if (OutSize) res = 0x80; else res = 0x00; break; } return res; }
Index: ioports.c =================================================================== RCS file: /home/wine/wine/dlls/winedos/ioports.c,v retrieving revision 1.2 diff -u -r1.2 ioports.c --- ioports.c 9 Mar 2002 23:44:32 -0000 1.2 +++ ioports.c 15 May 2002 21:06:02 -0000 @@ -24,7 +24,8 @@ #include "windef.h" #include "dosexe.h" #include "vga.h" - +#include "soundblaster.h" +#include "dma.h" /********************************************************************** * DOSVM_inport @@ -36,10 +37,51 @@ case 0x60: *res = DOSVM_Int09ReadScan(NULL); break; + case 0x22a: + case 0x22c: + case 0x22e: + *res = (DWORD)SB_ioport_in( port ); + break; case 0x3ba: case 0x3da: *res = (DWORD)VGA_ioport_in( port ); break; + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0xC0: + case 0xC2: + case 0xC4: + case 0xC6: + case 0xC8: + case 0xCA: + case 0xCC: + case 0xCE: + case 0x87: + case 0x83: + case 0x81: + case 0x82: + case 0x8B: + case 0x89: + case 0x8A: + case 0x487: + case 0x483: + case 0x481: + case 0x482: + case 0x48B: + case 0x489: + case 0x48A: + case 0x08: + case 0xD0: + case 0x0D: + case 0xDA: + *res = (DWORD)DMA_ioport_in( port ); + break; default: return FALSE; /* not handled */ } @@ -57,9 +99,61 @@ case 0x20: DOSVM_PIC_ioport_out( port, (BYTE)value ); break; + case 0x226: + case 0x22c: + SB_ioport_out( port, (BYTE)value ); + break; case 0x3c8: case 0x3c9: VGA_ioport_out( port, (BYTE)value ); + break; + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0xC0: + case 0xC2: + case 0xC4: + case 0xC6: + case 0xC8: + case 0xCA: + case 0xCC: + case 0xCE: + case 0x87: + case 0x83: + case 0x81: + case 0x82: + case 0x8B: + case 0x89: + case 0x8A: + case 0x487: + case 0x483: + case 0x481: + case 0x482: + case 0x48B: + case 0x489: + case 0x48A: + case 0x08: + case 0xD0: + case 0x0B: + case 0xD6: + case 0x0A: + case 0xD4: + case 0x0F: + case 0xDE: + case 0x09: + case 0xD2: + case 0x0C: + case 0xD8: + case 0x0D: + case 0xDA: + case 0x0E: + case 0xDC: + DMA_ioport_out( port, (BYTE)value ); break; default: return FALSE; /* not handled */ Index: Makefile.in =================================================================== RCS file: /home/wine/wine/dlls/winedos/Makefile.in,v retrieving revision 1.10 diff -u -r1.10 Makefile.in --- Makefile.in 11 May 2002 23:06:35 -0000 1.10 +++ Makefile.in 15 May 2002 21:06:02 -0000 @@ -24,6 +24,8 @@ ioports.c \ module.c \ vga.c \ + soundblaster.c \ + dma.c \ xms.c @MAKE_DLL_RULES@