Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

472 lines
11 KiB

  1. /***************************************************************************
  2. *
  3. * vsb.c
  4. *
  5. * Copyright (c) 1991-1996 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * This code provides VDD support for SB 2.0 sound output, specifically:
  8. * DSP 2.01+ (excluding SB-MIDI port)
  9. * Mixer Chip CT1335 (not strictly part of SB 2.0, but apps seem to like it)
  10. * FM Chip OPL2 (a.k.a. Adlib)
  11. *
  12. ***************************************************************************/
  13. /*****************************************************************************
  14. *
  15. * #includes
  16. *
  17. *****************************************************************************/
  18. #include <windows.h> // The VDD is a win32 DLL
  19. #include <mmsystem.h> // Multi-media APIs
  20. #include <vddsvc.h> // Definition of VDD calls
  21. #include <vsb.h>
  22. #include <dsp.h>
  23. #include <mixer.h>
  24. #include <fm.h>
  25. /*****************************************************************************
  26. *
  27. * Globals
  28. *
  29. *****************************************************************************/
  30. //
  31. // Definitions for MM api entry points. The functions will be linked
  32. // dynamically to avoid bringing winmm.dll in before wow32.
  33. //
  34. SETVOLUMEPROC SetVolumeProc;
  35. GETNUMDEVSPROC GetNumDevsProc;
  36. GETDEVCAPSPROC GetDevCapsProc;
  37. OPENPROC OpenProc;
  38. RESETPROC ResetProc;
  39. CLOSEPROC CloseProc;
  40. GETPOSITIONPROC GetPositionProc;
  41. WRITEPROC WriteProc;
  42. PREPAREHEADERPROC PrepareHeaderProc;
  43. UNPREPAREHEADERPROC UnprepareHeaderProc;
  44. BOOL bWaveOutActive = FALSE;
  45. BOOL bWinmmLoaded = FALSE;
  46. BOOL LoadWinmm(VOID);
  47. BOOL InitDevices(VOID);
  48. HINSTANCE hWinmm;
  49. /*
  50. * General globals
  51. */
  52. HINSTANCE GlobalHInstance; // handle passed to dll entry point
  53. WORD BasePort; // Where the card is mapped
  54. /*****************************************************************************
  55. *
  56. * General Functions
  57. *
  58. *****************************************************************************/
  59. /*
  60. * DLL entry point routine.
  61. * Returns TRUE on success.
  62. */
  63. BOOL WINAPI
  64. DllEntryPoint(
  65. HINSTANCE hInstance,
  66. DWORD reason,
  67. LPVOID reserved
  68. )
  69. {
  70. switch (reason) {
  71. case DLL_PROCESS_ATTACH:
  72. DisableThreadLibraryCalls(hInstance);
  73. // save instance
  74. GlobalHInstance = hInstance;
  75. // Hook i/o ports
  76. if (!InstallIoHook(hInstance)) {
  77. dprintf1(("VDD failed to load"));
  78. #if 0
  79. MessageBoxA(NULL, "Unable to load wave out device",
  80. "Sound Blaster VDD", MB_OK | MB_ICONEXCLAMATION);
  81. #endif
  82. return FALSE;
  83. }
  84. if (!DspProcessAttach()) {
  85. DeInstallIoHook(hInstance);
  86. return FALSE;
  87. }
  88. #if 0
  89. {
  90. char buf[256];
  91. wsprintfA(buf, "Sound blaster VDD loaded at port %3X, IRQ %d, DMA Channel %d, %s OPL2/Adlib support.",
  92. BasePort, SB_INTERRUPT, SB_DMA_CHANNEL,
  93. (FMActive ? "with" : "without"));
  94. MessageBoxA(NULL, buf, "Sound Blaster VDD", MB_OK | MB_ICONINFORMATION);
  95. }
  96. #endif // DBG
  97. return TRUE;
  98. case DLL_PROCESS_DETACH:
  99. DspProcessDetach();
  100. DeInstallIoHook(hInstance);
  101. if (bWaveOutActive) {
  102. CloseFMDevice();
  103. SetSpeaker(TRUE);
  104. }
  105. if (bWinmmLoaded) {
  106. FreeLibrary(hWinmm);
  107. }
  108. return TRUE;
  109. default:
  110. return TRUE;
  111. }
  112. }
  113. /***************************************************************************/
  114. //
  115. // LoadWinmm()
  116. //
  117. // This function dynamically loads the "waveOutxxx" entry points. This
  118. // is done because there is code in WINMM which does certain things in a
  119. // WOW vdm. If we do static links, then winmm may get loaded way before
  120. // WOW32, in which case it can't do the things it should.
  121. //
  122. BOOL
  123. LoadWinmm(
  124. VOID
  125. )
  126. {
  127. if (!(hWinmm = LoadLibrary(L"WINMM.DLL"))) {
  128. return FALSE;
  129. }
  130. //BUGBUG: Should check for error return from getprocaddress
  131. //
  132. SetVolumeProc = (SETVOLUMEPROC) GetProcAddress(hWinmm, "waveOutSetVolume");
  133. GetNumDevsProc = (GETNUMDEVSPROC) GetProcAddress(hWinmm, "waveOutGetNumDevs");
  134. GetDevCapsProc = (GETDEVCAPSPROC) GetProcAddress(hWinmm, "waveOutGetDevCapsW");
  135. OpenProc = (OPENPROC) GetProcAddress(hWinmm, "waveOutOpen");
  136. ResetProc = (RESETPROC) GetProcAddress(hWinmm, "waveOutReset");
  137. CloseProc = (CLOSEPROC) GetProcAddress(hWinmm, "waveOutClose");
  138. GetPositionProc = (GETPOSITIONPROC) GetProcAddress(hWinmm, "waveOutGetPosition");
  139. WriteProc = (WRITEPROC) GetProcAddress(hWinmm, "waveOutWrite");
  140. PrepareHeaderProc = (PREPAREHEADERPROC) GetProcAddress(hWinmm, "waveOutPrepareHeader");
  141. UnprepareHeaderProc = (UNPREPAREHEADERPROC) GetProcAddress(hWinmm, "waveOutUnprepareHeader");
  142. return TRUE;
  143. }
  144. /***************************************************************************/
  145. //
  146. // InitDevices()
  147. //
  148. // This function tries to get handles to the waveout and FM devices.
  149. //
  150. BOOL
  151. InitDevices(
  152. VOID
  153. )
  154. {
  155. static BOOL bTriedLoadAndFailed = FALSE;
  156. if (bWaveOutActive) {
  157. return TRUE;
  158. }
  159. if (bTriedLoadAndFailed) {
  160. return FALSE;
  161. }
  162. if (!bWinmmLoaded) {
  163. if (!LoadWinmm()) {
  164. bTriedLoadAndFailed = TRUE;
  165. return FALSE;
  166. }
  167. bWinmmLoaded = TRUE;
  168. }
  169. if (!FindWaveDevice()) {
  170. return FALSE;
  171. }
  172. bWaveOutActive = TRUE;
  173. OpenFMDevice();
  174. return TRUE;
  175. }
  176. /***************************************************************************/
  177. /*
  178. * Hooks i/o ports with i/o handlers.
  179. * Sets BasePort and returns TRUE if successful.
  180. */
  181. BOOL
  182. InstallIoHook(
  183. HINSTANCE hInstance
  184. )
  185. {
  186. int i;
  187. WORD ports[] = { 0x220, 0x210, 0x230, 0x240, 0x250, 0x260, 0x270 };
  188. VDD_IO_HANDLERS handlers = {
  189. VsbByteIn,
  190. NULL,
  191. NULL,
  192. NULL,
  193. VsbByteOut,
  194. NULL,
  195. NULL,
  196. NULL};
  197. // try each base port until success is achieved
  198. for (i = 0; i < sizeof(ports) / sizeof(ports[0]); i++ ) {
  199. VDD_IO_PORTRANGE PortRange[5];
  200. PortRange[0].First = ports[i] + 0x04;
  201. PortRange[0].Last = ports[i] + 0x06;
  202. PortRange[1].First = ports[i] + 0x08;
  203. PortRange[1].Last = ports[i] + 0x0A;
  204. PortRange[2].First = ports[i] + 0x0C;
  205. PortRange[2].Last = ports[i] + 0x0C;
  206. PortRange[3].First = ports[i] + 0x0E;
  207. PortRange[3].Last = ports[i] + 0x0E;
  208. PortRange[4].First = 0x388;
  209. PortRange[4].Last = 0x389;
  210. if (VDDInstallIOHook((HANDLE)hInstance, 5, PortRange, &handlers)) {
  211. dprintf2(("Device installed at %X", ports[i]));
  212. BasePort = ports[i];
  213. return TRUE;
  214. }
  215. }
  216. return FALSE;
  217. }
  218. /***************************************************************************/
  219. /*
  220. * Remove our i/o hook.
  221. */
  222. VOID
  223. DeInstallIoHook(
  224. HINSTANCE hInstance
  225. )
  226. {
  227. VDD_IO_PORTRANGE PortRange[5];
  228. PortRange[0].First = BasePort + 0x04;
  229. PortRange[0].Last = BasePort + 0x06;
  230. PortRange[1].First = BasePort + 0x08;
  231. PortRange[1].Last = BasePort + 0x0A;
  232. PortRange[2].First = BasePort + 0x0C;
  233. PortRange[2].Last = BasePort + 0x0C;
  234. PortRange[3].First = BasePort + 0x0E;
  235. PortRange[3].Last = BasePort + 0x0E;
  236. PortRange[4].First = 0x388;
  237. PortRange[4].Last = 0x389;
  238. VDDDeInstallIOHook((HANDLE)hInstance, 5, PortRange);
  239. }
  240. /***************************************************************************/
  241. /*
  242. * Gets called when the application reads from port.
  243. * Returns results to application in data.
  244. */
  245. VOID
  246. VsbByteIn(
  247. WORD port,
  248. BYTE * data
  249. )
  250. {
  251. // If we fail simulate nothing at the port
  252. *data = 0xFF;
  253. //
  254. // make sure we are linked in with winmm
  255. //
  256. if (!bWaveOutActive) {
  257. if (!InitDevices()) {
  258. // no wave device, forget it
  259. return;
  260. }
  261. }
  262. switch (port - BasePort) {
  263. case READ_STATUS:
  264. DspReadStatus(data);
  265. break;
  266. case READ_DATA:
  267. DspReadData(data);
  268. break;
  269. case WRITE_STATUS:
  270. // Can always write
  271. *data = 0x7F;
  272. break;
  273. case MIXER_ADDRESS:
  274. // apps sometimes read from this port??
  275. break;
  276. case MIXER_DATA:
  277. MixerDataRead(data);
  278. break;
  279. case 0x8:
  280. // remap to ADLIB_STATUS_PORT
  281. port = ADLIB_STATUS_PORT;
  282. break;
  283. }
  284. switch(port) {
  285. case ADLIB_STATUS_PORT:
  286. FMStatusRead(data);
  287. break;
  288. }
  289. dprintf4(("Read %4X, <= %2X", port, *data));
  290. }
  291. /***************************************************************************/
  292. /*
  293. * Gets called when an application writes data to port.
  294. */
  295. VOID
  296. VsbByteOut(
  297. WORD port,
  298. BYTE data
  299. )
  300. {
  301. //
  302. // make sure we are linked in with winmm
  303. //
  304. if (!bWaveOutActive) {
  305. if (!InitDevices()) {
  306. // no wave device, forget it
  307. return;
  308. }
  309. }
  310. dprintf4(("Write %4X, => %2X", port, data));
  311. switch (port - BasePort) {
  312. case RESET_PORT:
  313. DspResetWrite(data);
  314. break;
  315. case WRITE_PORT:
  316. DspWrite(data);
  317. break;
  318. case MIXER_ADDRESS:
  319. MixerAddrWrite(data);
  320. break;
  321. case MIXER_DATA:
  322. MixerDataWrite(data);
  323. break;
  324. case 0x8:
  325. // remap to ADLIB_REGISTER_SELECT_PORT
  326. port = ADLIB_REGISTER_SELECT_PORT;
  327. break;
  328. case 0x9:
  329. // remap to ADLIB_DATA_PORT
  330. port = ADLIB_DATA_PORT;
  331. break;
  332. }
  333. switch(port) {
  334. case ADLIB_REGISTER_SELECT_PORT:
  335. FMRegisterSelect(data);
  336. break;
  337. case ADLIB_DATA_PORT:
  338. FMDataWrite(data);
  339. break;
  340. }
  341. }
  342. /***************************************************************************/
  343. /*
  344. * Reset all devices
  345. */
  346. VOID
  347. ResetAll(
  348. VOID
  349. )
  350. {
  351. dprintf2(("Resetting"));
  352. ResetDSP();
  353. ResetFM();
  354. ResetMixer();
  355. }
  356. /***************************************************************************/
  357. /*
  358. * Debug
  359. */
  360. #if DBG
  361. int VddDebugLevel = 3;
  362. int VddDebugCount = 0;
  363. #define DEBUG_START 0
  364. /*
  365. * Generate debug output in printf type format.
  366. */
  367. void VddDbgOut(LPSTR lpszFormat, ...)
  368. {
  369. char buf[256];
  370. char buf2[300] = "VSBD: ";
  371. va_list va;
  372. if (++VddDebugCount < DEBUG_START) {
  373. return;
  374. }
  375. va_start(va, lpszFormat);
  376. wvsprintfA(buf, lpszFormat, va);
  377. va_end(va);
  378. strcat(buf2, buf);
  379. strcat(buf2, "\r\n");
  380. OutputDebugStringA(buf2);
  381. }
  382. #endif