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.

457 lines
11 KiB

  1. /****************************************************************************
  2. *
  3. * config.c
  4. *
  5. * Copyright (c) 1991 Microsoft Corporation. All Rights Reserved.
  6. *
  7. ***************************************************************************/
  8. /*
  9. * Definition of interface to kernel driver (synth.sys)
  10. *
  11. * The kernel driver's Dos device name is assumed fixed and known
  12. *
  13. * adlib.mid or adlib.mid0
  14. *
  15. * The kernel driver is opened in read/write mode.
  16. *
  17. * Writing to the driver sends a list of SYNTH_DATA structures
  18. * to the driver. The port number MUST be 0x388 or 0x389.
  19. *
  20. *
  21. * Reading always reads just 1 byte - the status port.
  22. */
  23. #include <windows.h> // The VDD is just a win32 DLL
  24. #include <vddsvc.h> // Definition of VDD calls
  25. #include "vdd.h" // Common data with kernel driver
  26. #include <stdio.h>
  27. /*
  28. * Debugging
  29. */
  30. #if DBG
  31. int VddDebugLevel = 1;
  32. /***************************************************************************
  33. Generate debug output in printf type format
  34. ****************************************************************************/
  35. void VddDbgOut(LPSTR lpszFormat, ...)
  36. {
  37. char buf[256];
  38. va_list va;
  39. OutputDebugStringA("Ad Lib VDD: ");
  40. va_start(va, lpszFormat);
  41. vsprintf(buf, lpszFormat, va);
  42. va_end(va);
  43. OutputDebugStringA(buf);
  44. OutputDebugStringA("\r\n");
  45. }
  46. #define dprintf( _x_ ) VddDbgOut _x_
  47. #define dprintf1( _x_ ) if (VddDebugLevel >= 1) VddDbgOut _x_
  48. #define dprintf2( _x_ ) if (VddDebugLevel >= 2) VddDbgOut _x_
  49. #define dprintf3( _x_ ) if (VddDebugLevel >= 3) VddDbgOut _x_
  50. #define dprintf4( _x_ ) if (VddDebugLevel >= 4) VddDbgOut _x_
  51. #else
  52. #define dprintf(x)
  53. #define dprintf1(x)
  54. #define dprintf2(x)
  55. #define dprintf3(x)
  56. #define dprintf4(x)
  57. #endif // DBG
  58. /*
  59. * Symbolic names for port addresses
  60. */
  61. #define ADLIB_DATA_PORT 0x389
  62. #define ADLIB_REGISTER_SELECT_PORT 0x388
  63. #define ADLIB_STATUS_PORT 0x388
  64. /*
  65. * Batch data to the device - for true Adlib use a size of 2
  66. */
  67. #define BATCH_SIZE 40
  68. int Position = 0;
  69. SYNTH_DATA PortData[BATCH_SIZE];
  70. /*
  71. * Internal Routines
  72. */
  73. void MyByteIn(WORD port, BYTE *data);
  74. void MyByteOut(WORD port, BYTE data);
  75. /*
  76. * IO handler table.
  77. *
  78. * There's no point in providing string handlers because the chip
  79. * can't respond very quickly (need gaps of at least 23 microseconds
  80. * between writes).
  81. */
  82. VDD_IO_HANDLERS handlers = {
  83. MyByteIn,
  84. NULL,
  85. NULL,
  86. NULL,
  87. MyByteOut,
  88. NULL,
  89. NULL,
  90. NULL};
  91. /*
  92. * Note that we rely on the kernel driver to pretend the device is
  93. * at address 388 even the driver supports it somewhere else.
  94. */
  95. VDD_IO_PORTRANGE ports[] = {
  96. {
  97. 0x228,
  98. 0x229
  99. },
  100. {
  101. 0x388,
  102. 0x389
  103. }
  104. };
  105. /*
  106. * Globals
  107. */
  108. //
  109. // Track timers. The basic rule is that if no timer is started then
  110. // the only way the status register can change is via the reset bit
  111. // in which case we know what will happen.
  112. //
  113. // If a timer interrupts then it's 'stopped'
  114. //
  115. BOOL Timer1Started;
  116. BOOL Timer2Started;
  117. BYTE Status;
  118. /*
  119. * Current device handle
  120. *
  121. * NULL if device is (potentially) free
  122. * INVALID_HANDLE_VALUE if device was not obtainable
  123. */
  124. HANDLE DeviceHandle;
  125. HANDLE OpenDevice(PWSTR DeviceName)
  126. {
  127. WCHAR DosDeviceName[MAX_PATH];
  128. /*
  129. * Make up a string suitable for opening a Dos device
  130. */
  131. wcscpy(DosDeviceName, TEXT("\\\\."));
  132. wcscat(DosDeviceName, DeviceName +
  133. wcslen(TEXT("\\Device")));
  134. /*
  135. * Open the device with GENERIC_READ and GENERIC_WRITE
  136. * Also use FILE_SHARE_WRITE so other applications can
  137. * set the device volume
  138. */
  139. return CreateFile(DosDeviceName,
  140. GENERIC_WRITE | GENERIC_READ,
  141. FILE_SHARE_WRITE,
  142. NULL,
  143. OPEN_EXISTING,
  144. 0,
  145. NULL);
  146. }
  147. /*
  148. * Open our device is it can be opened and we haven't tried before
  149. *
  150. * Returns FALSE if device can't be acquired.
  151. */
  152. BOOL CheckDeviceAccess(void)
  153. {
  154. /*
  155. * If we don't have a handle (valid or invalid) already try
  156. * opening the device
  157. */
  158. if (DeviceHandle == NULL) {
  159. DeviceHandle = OpenDevice(STR_ADLIB_DEVICENAME);
  160. if (DeviceHandle == INVALID_HANDLE_VALUE) {
  161. DeviceHandle = OpenDevice(STR_ADLIB_DEVICENAME L"0");
  162. }
  163. Position = 0;
  164. }
  165. return DeviceHandle != INVALID_HANDLE_VALUE;
  166. }
  167. /*
  168. * Map a write to a port
  169. *
  170. * How are we going to simulate timer stuff?
  171. * Answer: Allow reading of the status port.
  172. *
  173. * This is optimized to only write when we get a data port write
  174. */
  175. void MyByteOut(WORD port, BYTE data)
  176. {
  177. //
  178. // Remember what register is selected
  179. //
  180. static BYTE AdlibRegister;
  181. //
  182. // Just package the stuff up and call write file
  183. //
  184. DWORD BytesWritten;
  185. dprintf3(("Received write to Port %4X, Data %2X", port, data));
  186. port = (port & 1) | ADLIB_REGISTER_SELECT_PORT;
  187. /*
  188. * Check for special values - don't let them switch to
  189. * OPL3 mode.
  190. */
  191. #if 0
  192. if (port == ADLIB_DATA_PORT && AdlibRegister == AD_NEW) {
  193. data &= 0xFE;
  194. }
  195. #endif
  196. if (port == ADLIB_REGISTER_SELECT_PORT) {
  197. /*
  198. * Just remember which register is supposed to be selected
  199. * to cut down the number of times we go to the device driver
  200. */
  201. AdlibRegister = data;
  202. } else {
  203. /*
  204. * Write this one to the device
  205. */
  206. PortData[Position].IoPort = ADLIB_REGISTER_SELECT_PORT;
  207. PortData[Position].PortData = AdlibRegister;
  208. PortData[Position + 1].IoPort = port;
  209. PortData[Position + 1].PortData = data;
  210. Position += 2;
  211. if (Position == BATCH_SIZE ||
  212. AdlibRegister >= 0xA0 && AdlibRegister <= 0xBF ||
  213. AdlibRegister == AD_MASK) {
  214. /*
  215. * See if we have the device
  216. */
  217. if (CheckDeviceAccess()) {
  218. if (!WriteFile(DeviceHandle,
  219. &PortData,
  220. Position * sizeof(PortData[0]),
  221. &BytesWritten,
  222. NULL)) {
  223. dprintf1(("Failed to write to device!"));
  224. } else {
  225. /*
  226. * Work out what status change may have occurred
  227. */
  228. if (AdlibRegister == AD_MASK) {
  229. /*
  230. * Look for RST and starting timers
  231. */
  232. if (data & 0x80) {
  233. Status = 0;
  234. }
  235. /*
  236. * We ignore starting of timers if their interrupt
  237. * flag is set because the timer status will have to
  238. * be set again to make the status for this timer change
  239. */
  240. if ((data & 1) && !(Status & 0x40)) {
  241. dprintf2(("Timer 1 started"));
  242. #if 0
  243. Timer1Started = TRUE;
  244. #else
  245. Status |= 0xC0;
  246. #endif
  247. } else {
  248. Timer1Started = FALSE;
  249. }
  250. if ((data & 2) && !(Status & 0x20)) {
  251. dprintf2(("Timer 2 started"));
  252. #if 0
  253. Timer2Started = TRUE;
  254. #else
  255. Status |= 0xA0;
  256. #endif
  257. Timer2Started = TRUE;
  258. } else {
  259. Timer2Started = FALSE;
  260. }
  261. }
  262. }
  263. }
  264. Position = 0;
  265. }
  266. }
  267. }
  268. /*
  269. * Gets called when the application reads from one of our ports.
  270. * We know the device only returns interesting things in the status port.
  271. */
  272. void MyByteIn(WORD port, BYTE *data)
  273. {
  274. DWORD BytesRead;
  275. dprintf4(("Received read from Port %4X", port));
  276. port = (port & 1) | ADLIB_STATUS_PORT;
  277. /*
  278. * If we fail simulate nothing at the port
  279. */
  280. *data = 0xFF;
  281. /*
  282. * Say there's nothing there if we didn't get the device driver or
  283. * it's not the status port
  284. */
  285. if (port != ADLIB_STATUS_PORT || !CheckDeviceAccess()) {
  286. return;
  287. }
  288. #if 0 // WSS interrupt messed this up
  289. /*
  290. * Are we expecting a state change ?
  291. */
  292. if (Timer1Started || Timer2Started) {
  293. /*
  294. * Read the status port from the driver - this is how the
  295. * driver interprets read.
  296. * Well, actually don't because the WSS driver doesn't work!
  297. */
  298. if (!ReadFile(DeviceHandle,
  299. &Status,
  300. 1,
  301. &BytesRead,
  302. NULL)) {
  303. dprintf1(("Failed to read from device - code %d", GetLastError()));
  304. } else {
  305. /*
  306. * Look for state change
  307. */
  308. if (Status & 0x40) {
  309. Timer1Started = FALSE;
  310. dprintf2(("Timer 1 finished"));
  311. }
  312. if (Status & 0x20) {
  313. Timer2Started = FALSE;
  314. dprintf2(("Timer 2 finished"));
  315. }
  316. }
  317. }
  318. #endif
  319. dprintf3(("Data read was %2X", Status));
  320. *data = Status;
  321. }
  322. /*
  323. * Standard DLL entry point routine.
  324. */
  325. BOOL DllEntryPoint(HINSTANCE hInstance, DWORD Reason, LPVOID Reserved)
  326. {
  327. switch (Reason) {
  328. case DLL_PROCESS_ATTACH:
  329. if (!VDDInstallIOHook(hInstance, 2, ports, &handlers)) {
  330. dprintf2(("Ad Lib VDD failed to load - error in VDDInstallIoHook"));
  331. return FALSE;
  332. } else {
  333. dprintf2(("Ad Lib VDD loaded OK"));
  334. return TRUE;
  335. }
  336. case DLL_PROCESS_DETACH:
  337. VDDDeInstallIOHook(hInstance, 2, ports);
  338. /*
  339. * Note that this event corresponds to FreeLibrary on our DLL,
  340. * NOT termination of the process - so we can't rely on process
  341. * termination to close our device handle.
  342. *
  343. */
  344. if (DeviceHandle) {
  345. CloseHandle(DeviceHandle);
  346. DeviceHandle = NULL; // Redundant but neater.
  347. }
  348. return TRUE;
  349. default:
  350. return TRUE;
  351. }
  352. }
  353.