|
|
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.