|
|
1.1 ! root 1: /**************************************************************************** ! 2: * ! 3: * drvutil.c ! 4: * ! 5: * Multimedia kernel driver support component (mmdrv) ! 6: * ! 7: * Copyright (c) Microsoft Corporation 1992. All rights reserved. ! 8: * ! 9: * Support functions common to multiple multi-media drivers : ! 10: * ! 11: * -- Open a device ! 12: * -- Translate a kernel IO return code to a multi-media return code ! 13: * -- Count the number of devices of a given type ! 14: * -- Set and Get data synchronously to a kernel device ! 15: * ! 16: * History ! 17: * 01-Feb-1992 - Robin Speed (RobinSp) wrote it ! 18: * 04-Feb-1992 - Reviewed by SteveDav ! 19: * ! 20: ***************************************************************************/ ! 21: ! 22: #include "mmdrv.h" ! 23: #include <ntddwave.h> ! 24: #include <ntddmidi.h> ! 25: #include <ntddaux.h> ! 26: ! 27: /**************************************************************************** ! 28: * @doc INTERNAL ! 29: * ! 30: * @api MMRESULT | sndOpenDev | Open the kernel driver device corresponding ! 31: * to a logical wave device id ! 32: * ! 33: * @parm UINT | DeviceType | The type of device ! 34: * ! 35: * @parm DWORD | dwId | The device id ! 36: * ! 37: * @parm PHANDLE | phDev | Where to return the kernel device handle ! 38: * ! 39: * @parm ACCESS_MASK | Access | The desired access ! 40: * ! 41: * @comm For our sound devices the only relevant access are read and ! 42: * read/write. Device should ALWAYS allow opens for read unless some ! 43: * resource or access-rights restriction occurs. ! 44: ***************************************************************************/ ! 45: MMRESULT sndOpenDev(UINT DeviceType, DWORD dwId, ! 46: PHANDLE phDev, DWORD Access) ! 47: { ! 48: WCHAR cDev[SOUND_MAX_DEVICE_NAME]; ! 49: ! 50: WinAssert(DeviceType == WaveOutDevice || ! 51: DeviceType == WaveInDevice || ! 52: DeviceType == MidiOutDevice || ! 53: DeviceType == MidiInDevice || ! 54: DeviceType == AuxDevice); ! 55: ! 56: // ! 57: // Check it's not out of range ! 58: // ! 59: ! 60: if (dwId > SOUND_MAX_DEVICES) { ! 61: return MMSYSERR_BADDEVICEID; ! 62: } ! 63: // ! 64: // Create the device name and open it - remove '\Device' ! 65: // ! 66: ! 67: wsprintf(cDev, L"\\\\.%ls%d", ! 68: (DeviceType == WaveOutDevice ? DD_WAVE_OUT_DEVICE_NAME_U : ! 69: DeviceType == WaveInDevice ? DD_WAVE_IN_DEVICE_NAME_U : ! 70: DeviceType == MidiOutDevice ? DD_MIDI_OUT_DEVICE_NAME_U : ! 71: DeviceType == MidiInDevice ? DD_MIDI_IN_DEVICE_NAME_U : ! 72: DD_AUX_DEVICE_NAME_U) + ! 73: strlen("\\Device"), ! 74: dwId); ! 75: ! 76: *phDev = INVALID_HANDLE_VALUE; ! 77: ! 78: *phDev = CreateFile(cDev, ! 79: Access, ! 80: FILE_SHARE_WRITE, ! 81: NULL, ! 82: OPEN_EXISTING, ! 83: Access != GENERIC_READ ? FILE_FLAG_OVERLAPPED : 0, ! 84: NULL); ! 85: ! 86: // ! 87: // Check up on the driver for refusing to open ! 88: // multiply for read ! 89: // ! 90: ! 91: WinAssert(!(GetLastError() == ERROR_ACCESS_DENIED && ! 92: Access == GENERIC_READ)); ! 93: ! 94: // ! 95: // Return status to caller ! 96: // ! 97: ! 98: return *phDev != INVALID_HANDLE_VALUE ? MMSYSERR_NOERROR : sndTranslateStatus(); ! 99: } ! 100: ! 101: /**************************************************************************** ! 102: * @doc INTERNAL ! 103: * ! 104: * @api void | sndTranslateStatus | This function translates an NT status ! 105: * code into a multi-media error code as far as possible. ! 106: * ! 107: * @parm NTSTATUS | Status | The NT base operating system return status. ! 108: * ! 109: * ! 110: * @rdesc The multi-media error code. ! 111: ***************************************************************************/ ! 112: DWORD sndTranslateStatus(void) ! 113: { ! 114: #if DBG ! 115: UINT n; ! 116: switch (n=GetLastError()) { ! 117: #else ! 118: switch (GetLastError()) { ! 119: #endif ! 120: case NO_ERROR: ! 121: case ERROR_IO_PENDING: ! 122: return MMSYSERR_NOERROR; ! 123: ! 124: case ERROR_BUSY: ! 125: return MMSYSERR_ALLOCATED; ! 126: ! 127: case ERROR_NOT_SUPPORTED: ! 128: case ERROR_INVALID_FUNCTION: ! 129: return MMSYSERR_NOTSUPPORTED; ! 130: ! 131: case ERROR_NOT_ENOUGH_MEMORY: ! 132: return MMSYSERR_NOMEM; ! 133: ! 134: case ERROR_ACCESS_DENIED: ! 135: return MMSYSERR_BADDEVICEID; ! 136: ! 137: case ERROR_INSUFFICIENT_BUFFER: ! 138: return MMSYSERR_INVALPARAM; ! 139: ! 140: default: ! 141: dprintf2(("sndTranslateStatus: LastError = %d", n)); ! 142: return MMSYSERR_ERROR; ! 143: } ! 144: } ! 145: ! 146: /**************************************************************************** ! 147: * @doc INTERNAL ! 148: * ! 149: * @api DWORD | sndGetNumDevs | This function returns the number of (kernel) ! 150: * ! 151: * @parm UINT | DeviceType | The Device type ! 152: * ! 153: * @rdesc The number of devices. ! 154: ***************************************************************************/ ! 155: ! 156: DWORD sndGetNumDevs(UINT DeviceType) ! 157: { ! 158: // ! 159: // Look for devices until we don't find one ! 160: // ! 161: int i; ! 162: HANDLE h; ! 163: ! 164: for (i=0; ! 165: sndOpenDev(DeviceType, i, &h, GENERIC_READ) == MMSYSERR_NOERROR; ! 166: i++) { ! 167: ! 168: // ! 169: // BUGBUG try something to make sure ! ! 170: // ! 171: ! 172: CloseHandle(h); ! 173: } ! 174: // ! 175: // We incremented i each time we found a good device ! 176: // ! 177: ! 178: return i; ! 179: } ! 180: ! 181: /**************************************************************************** ! 182: * @doc INTERNAL ! 183: * ! 184: * @api DWORD | sndSetData | This function sets the volume given a device id ! 185: * and could be used for other soft value setting ! 186: * when only read access is required to the device ! 187: * ! 188: * @parm UINT | DeviceType | The Device type ! 189: * ! 190: * @parm UINT | DeviceId | The device id ! 191: * ! 192: * @parm UINT | Length | Length of data to set ! 193: * ! 194: * @parm PBYTE | Data | Data to set ! 195: * ! 196: * @parm ULONG | Ioctl | The Ioctl to use ! 197: * ! 198: * @rdesc MM... return code. ! 199: ***************************************************************************/ ! 200: ! 201: MMRESULT sndSetData(UINT DeviceType, UINT DeviceId, UINT Length, PBYTE Data, ! 202: ULONG Ioctl) ! 203: { ! 204: ! 205: HANDLE hDev; ! 206: MMRESULT mRet; ! 207: DWORD BytesReturned; ! 208: ! 209: // ! 210: // Open the wave output device ! 211: // ! 212: ! 213: mRet = sndOpenDev(DeviceType, DeviceId, &hDev, GENERIC_READ); ! 214: if (mRet != MMSYSERR_NOERROR) { ! 215: return mRet; ! 216: } ! 217: ! 218: // ! 219: // Set our data. ! 220: // ! 221: // Setting the overlapped parameter (last) to null means we ! 222: // wait until the operation completes. ! 223: // ! 224: ! 225: mRet = DeviceIoControl(hDev, Ioctl, Data, Length, NULL, 0, ! 226: &BytesReturned, NULL) ? ! 227: MMSYSERR_NOERROR : sndTranslateStatus(); ! 228: ! 229: ! 230: // ! 231: // Close our file and return ! 232: // ! 233: ! 234: CloseHandle(hDev); ! 235: ! 236: return mRet; ! 237: } ! 238: ! 239: /**************************************************************************** ! 240: * @doc INTERNAL ! 241: * ! 242: * @api DWORD | sndGetData | This function gets data from a given device ! 243: * specified by device id when read-only access is ! 244: * sufficient ! 245: * ! 246: * @parm UINT | DeviceType | The Device type ! 247: * ! 248: * @parm UINT | DeviceId | The device id ! 249: * ! 250: * @parm UINT | Length | Length of data to set ! 251: * ! 252: * @parm PBYTE | Data | Data to set ! 253: * ! 254: * @parm ULONG | Ioctl | The Ioctl to use ! 255: * ! 256: * @rdesc MM... return code. ! 257: ***************************************************************************/ ! 258: ! 259: MMRESULT sndGetData(UINT DeviceType, UINT DeviceId, UINT Length, PBYTE Data, ! 260: ULONG Ioctl) ! 261: { ! 262: ! 263: HANDLE hDev; ! 264: MMRESULT mRet; ! 265: DWORD BytesReturned; ! 266: ! 267: // ! 268: // Open the wave output device ! 269: // ! 270: ! 271: mRet = sndOpenDev(DeviceType, DeviceId, &hDev, GENERIC_READ); ! 272: if (mRet != MMSYSERR_NOERROR) { ! 273: return mRet; ! 274: } ! 275: ! 276: // ! 277: // Set our data. ! 278: // ! 279: // Setting the overlapped parameter (last) to null means we ! 280: // wait until the operation completes. ! 281: // ! 282: ! 283: mRet = DeviceIoControl(hDev, Ioctl, NULL, 0, (LPVOID)Data, Length, ! 284: &BytesReturned, NULL) ? ! 285: MMSYSERR_NOERROR : sndTranslateStatus(); ! 286: ! 287: ! 288: // ! 289: // Close our file and return ! 290: // ! 291: ! 292: CloseHandle(hDev); ! 293: ! 294: return mRet; ! 295: } ! 296: ! 297: ! 298: /**************************************************************************** ! 299: * @doc INTERNAL ! 300: * ! 301: * @api MMRESULT | sndGetHandleData | Get data from a device using its handle ! 302: * ! 303: * @parm PWAVEALLOC | pClient | Client handle. ! 304: * ! 305: * @parm DWORD | dwSize | Size of the data ! 306: * ! 307: * @parm PVOID | pData | Where to put the data. ! 308: * ! 309: * @parm ULONG | Function | The Ioctl to use ! 310: * ! 311: * @rdesc MMSYS... return value. ! 312: ***************************************************************************/ ! 313: ! 314: MMRESULT sndGetHandleData(HANDLE hDev, ! 315: DWORD dwSize, ! 316: PVOID pData, ! 317: ULONG Ioctl, ! 318: HANDLE hEvent) ! 319: { ! 320: OVERLAPPED Overlap; ! 321: DWORD BytesReturned; ! 322: ! 323: WinAssert(hDev != NULL); ! 324: ! 325: memset(&Overlap, 0, sizeof(Overlap)); ! 326: ! 327: Overlap.hEvent = hEvent; ! 328: ! 329: // ! 330: // Issue the IO control. We must wait with our own event because ! 331: // setting the overlapped object to null will complete if other ! 332: // IOs complete. ! 333: // ! 334: ! 335: if (!DeviceIoControl(hDev, ! 336: Ioctl, ! 337: NULL, ! 338: 0, ! 339: pData, ! 340: dwSize, ! 341: &BytesReturned, ! 342: &Overlap)) { ! 343: DWORD cbTransfer; ! 344: ! 345: // ! 346: // Wait for completion if necessary ! 347: // ! 348: ! 349: if (GetLastError() == ERROR_IO_PENDING) { ! 350: if (!GetOverlappedResult(hDev, &Overlap, &cbTransfer, ! 351: TRUE)) { ! 352: return sndTranslateStatus(); ! 353: } ! 354: } else { ! 355: return sndTranslateStatus(); ! 356: } ! 357: } ! 358: ! 359: // ! 360: // We'd better peek aleratbly to flush out any IO ! 361: // completions so that things like RESET only ! 362: // return when all buffers have been completed ! 363: // ! 364: // This relies on the fact that SleepEx will return ! 365: // WAIT_IO_COMPLETION in preference to OK ! 366: // ! 367: ! 368: while (SetEvent(hEvent) && ! 369: WaitForSingleObjectEx(hEvent, 0, TRUE) == WAIT_IO_COMPLETION) {} ! 370: ! 371: ! 372: return MMSYSERR_NOERROR; ! 373: } ! 374: ! 375: /**************************************************************************** ! 376: * @doc INTERNAL ! 377: * ! 378: * @api MMRESULT | sndSetHandleData | Pass data to a device using its handle ! 379: * ! 380: * @parm PWAVEALLOC | pClient | Client handle. ! 381: * ! 382: * @parm DWORD | dwSize | Size of the data ! 383: * ! 384: * @parm PVOID | pData | Data to send. ! 385: * ! 386: * @parm ULONG | Function | The Ioctl to use ! 387: * ! 388: * @rdesc MMSYS... return value. ! 389: ***************************************************************************/ ! 390: MMRESULT sndSetHandleData(HANDLE hDev, ! 391: DWORD dwSize, ! 392: PVOID pData, ! 393: ULONG Ioctl, ! 394: HANDLE hEvent) ! 395: { ! 396: OVERLAPPED Overlap; ! 397: DWORD BytesReturned; ! 398: ! 399: WinAssert(hDev != NULL); ! 400: ! 401: memset((PVOID)&Overlap, 0, sizeof(Overlap)); ! 402: ! 403: Overlap.hEvent = hEvent; ! 404: ! 405: // ! 406: // Issue the IO control. We must wait with our own event because ! 407: // setting the overlapped object to null will complete if other ! 408: // IOs complete. ! 409: // ! 410: ! 411: if (!DeviceIoControl(hDev, ! 412: Ioctl, ! 413: pData, ! 414: dwSize, ! 415: NULL, ! 416: 0, ! 417: &BytesReturned, ! 418: &Overlap)) { ! 419: DWORD cbTransfer; ! 420: ! 421: // ! 422: // Wait for completion if necessary ! 423: // ! 424: ! 425: if (GetLastError() == ERROR_IO_PENDING) { ! 426: if (!GetOverlappedResult(hDev, &Overlap, &cbTransfer, ! 427: TRUE)) { ! 428: return sndTranslateStatus(); ! 429: } ! 430: } else { ! 431: return sndTranslateStatus(); ! 432: } ! 433: } ! 434: ! 435: // ! 436: // We'd better peek aleratbly to flush out any IO ! 437: // completions so that things like RESET only ! 438: // return when all buffers have been completed ! 439: // ! 440: // This relies on the fact that SleepEx will return ! 441: // WAIT_IO_COMPLETION in preference to OK ! 442: // ! 443: ! 444: while (SleepEx(0, TRUE) == WAIT_IO_COMPLETION) {} ! 445: ! 446: return MMSYSERR_NOERROR; ! 447: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.