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.

273 lines
7.7 KiB

  1. /***************************************************************************
  2. *
  3. * fm.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. * FM Chip OPL2 (a.k.a. Adlib)
  9. *
  10. ***************************************************************************/
  11. /*****************************************************************************
  12. *
  13. * #includes
  14. *
  15. *****************************************************************************/
  16. #include <windows.h> // The VDD is a win32 DLL
  17. #include <mmsystem.h> // Multi-media APIs
  18. #include <vddsvc.h> // Definition of VDD calls
  19. #include <vsb.h>
  20. #include <fm.h>
  21. /*****************************************************************************
  22. *
  23. * Globals
  24. *
  25. *****************************************************************************/
  26. HANDLE HFM = NULL; // current open FM device
  27. BOOL FMActive = FALSE; // indicates whether we have an FM device
  28. BYTE AdlibRegister = 0x00; // register currently selected
  29. int Position = 0; // position in PortData array
  30. SYNTH_DATA PortData[BATCH_SIZE]; // batched data to be written to OPL2 device
  31. BOOL Timer1Started = FALSE; // if a timer interrupts then it's stopped
  32. BOOL Timer2Started = FALSE; // if a timer interrupts then it's stopped
  33. BYTE Status = 0x06; // or 0x00, see sb programming book page xi
  34. /****************************************************************************
  35. *
  36. * FM device routines
  37. *
  38. ****************************************************************************/
  39. VOID
  40. ResetFM(
  41. VOID
  42. )
  43. {
  44. AdlibRegister = 0x00; // register currently selected
  45. Position = 0;
  46. Timer1Started = FALSE;
  47. Timer2Started = FALSE;
  48. Status = 0x06;
  49. }
  50. VOID
  51. FMStatusRead(
  52. BYTE *data
  53. )
  54. {
  55. #if 0 // This should work but doesn't (ReadFile fails)
  56. // Are we expecting a state change ?
  57. if (Timer1Started || Timer2Started) {
  58. // Read the status port from the driver - this is how the
  59. // driver interprets read.
  60. // Well, actually don't because the WSS driver doesn't work!
  61. if (!ReadFile(HFM, &Status, 1, &bytesRead, NULL)) {
  62. #if DBG
  63. FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER |
  64. FORMAT_MESSAGE_FROM_SYSTEM,
  65. NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  66. (char *) &lpMsgBuf, 0, NULL);
  67. dprintf1(("FM read port failed: %d bytes of data read, error message: %s",
  68. bytesRead, lpMsgBuf));
  69. LocalFree( lpMsgBuf ); // Free the buffer.
  70. #endif DBG
  71. break;
  72. }
  73. else {
  74. // Look for state change
  75. if (Status & 0x40) {
  76. Timer1Started = FALSE;
  77. dprintf2(("Timer 1 finished"));
  78. }
  79. if (Status & 0x20) {
  80. Timer2Started = FALSE;
  81. dprintf2(("Timer 2 finished"));
  82. }
  83. }
  84. }
  85. #endif
  86. *data = Status;
  87. }
  88. VOID
  89. FMRegisterSelect(
  90. BYTE data
  91. )
  92. {
  93. AdlibRegister = data;
  94. }
  95. VOID
  96. FMDataWrite(
  97. BYTE data
  98. )
  99. {
  100. if(AdlibRegister==AD_NEW) {
  101. data &=0xFE; // don't enter opl3 mode
  102. }
  103. // put data in PortData array
  104. if(Position <= BATCH_SIZE-2) {
  105. PortData[Position].IoPort = ADLIB_REGISTER_SELECT_PORT;
  106. PortData[Position].PortData = AdlibRegister;
  107. PortData[Position + 1].IoPort = ADLIB_DATA_PORT;
  108. PortData[Position + 1].PortData = data;
  109. Position += 2;
  110. } else {
  111. dprintf1(("Attempting to write beyond end of PortData array"));
  112. }
  113. if (Position == BATCH_SIZE ||
  114. AdlibRegister>=0xB0 && AdlibRegister<=0xBD ||
  115. AdlibRegister == AD_MASK) {
  116. // PortData full or note-on/off command or changing status
  117. if (!FMPortWrite()) {
  118. dprintf1(("Failed to write to device!"));
  119. } else {
  120. // Work out what status change may have occurred
  121. if (AdlibRegister == AD_MASK) {
  122. // Look for RST and starting timers
  123. if (data & 0x80) {
  124. Status = 0x00; // reset both timers
  125. }
  126. // We ignore starting of timers if their interrupt
  127. // flag is set because the timer status will have to
  128. // be set again to make the status for this timer change
  129. if ((data & 1) && !(Status & 0x40)) {
  130. dprintf2(("Timer 1 started"));
  131. #if 0
  132. Timer1Started = TRUE;
  133. #else
  134. Status |= 0xC0; // simulate immediate expiry of timer1
  135. #endif
  136. } else {
  137. Timer1Started = FALSE;
  138. }
  139. if ((data & 2) && !(Status & 0x20)) {
  140. dprintf2(("Timer 2 started"));
  141. #if 0
  142. Timer2Started = TRUE;
  143. #else
  144. Status |= 0xA0; // simulate immediate expiry of timer2
  145. #endif
  146. Timer2Started = TRUE;
  147. } else {
  148. Timer2Started = FALSE;
  149. }
  150. }
  151. }
  152. }
  153. }
  154. /*
  155. * Opens opl2 device adlib.mid or adlib.mid0 as a file handle.
  156. * Returns TRUE on success.
  157. */
  158. BOOL
  159. OpenFMDevice(
  160. VOID
  161. )
  162. {
  163. DWORD dwBytesReturned;
  164. LPVOID lpMsgBuf;
  165. // attempt to open device file adlib.mid or adlib.mid0
  166. HFM = CreateFile(L"\\\\.\\adlib.mid", GENERIC_READ | GENERIC_WRITE,
  167. FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
  168. if (HFM == INVALID_HANDLE_VALUE) {
  169. HFM = CreateFile(L"\\\\.\\adlib.mid0", GENERIC_READ | GENERIC_WRITE,
  170. FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
  171. }
  172. if (HFM == INVALID_HANDLE_VALUE) {
  173. #if DBG
  174. FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER |
  175. FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
  176. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char *) &lpMsgBuf, 0, NULL);
  177. dprintf1(("Create FM out failed, error message: %s", lpMsgBuf));
  178. LocalFree( lpMsgBuf ); // Free the buffer.
  179. #endif // DBG
  180. return FALSE;
  181. }
  182. FMActive = TRUE;
  183. return TRUE;
  184. }
  185. /***************************************************************************/
  186. /*
  187. * Closes our FM device.
  188. */
  189. VOID
  190. CloseFMDevice(
  191. VOID
  192. )
  193. {
  194. dprintf2(("Closing FM device"));
  195. if (HFM) {
  196. CloseHandle(HFM);
  197. HFM = NULL;
  198. FMActive = FALSE;
  199. }
  200. }
  201. /***************************************************************************/
  202. /*
  203. * Sends FM data to the card.
  204. * Returns TRUE on success.
  205. */
  206. BOOL
  207. FMPortWrite(
  208. VOID
  209. )
  210. {
  211. DWORD bytesWritten = 0;
  212. LPVOID lpMsgBuf;
  213. if(FMActive) {
  214. dprintf4(("Writing %d bytes of data to port",
  215. Position * sizeof(PortData[0])));
  216. if(!WriteFile(HFM, &PortData, Position * sizeof(PortData[0]),
  217. &bytesWritten, NULL)) {
  218. #if DBG
  219. FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER |
  220. FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
  221. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char *) &lpMsgBuf,
  222. 0, NULL);
  223. dprintf1(("FM write failed: %d bytes of data written, error message: %s",
  224. bytesWritten, lpMsgBuf));
  225. LocalFree( lpMsgBuf ); // Free the buffer.
  226. #endif //DBG
  227. return FALSE;
  228. }
  229. }
  230. Position = 0;
  231. return TRUE;
  232. }
  233. /***************************************************************************/