* Sync up to trunk head (r65120).
[reactos.git] / dll / win32 / mmdrv / kernel.c
1 /*
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS Multimedia
5 * FILE: dll/win32/mmdrv/kernel.c
6 * PURPOSE: Multimedia User Mode Driver (kernel interface)
7 * PROGRAMMER: Andrew Greenwood
8 * UPDATE HISTORY:
9 * Jan 14, 2007: Created
10 */
11
12 #include "mmdrv.h"
13
14 #include <winuser.h>
15
16 #define NDEBUG
17 #include <debug.h>
18
19 /*
20 Devices that we provide access to follow a standard naming convention.
21 The first wave output, for example, appears as \Device\WaveOut0
22
23 I'm not entirely certain how drivers find a free name to use, or why
24 we need to strip the leading \Device from it when opening, but hey...
25 */
26
27 MMRESULT
28 CobbleDeviceName(
29 DeviceType device_type,
30 UINT device_id,
31 PWCHAR out_device_name)
32 {
33 WCHAR base_device_name[MAX_DEVICE_NAME_LENGTH];
34
35 /* Work out the base name from the device type */
36
37 switch ( device_type )
38 {
39 case WaveOutDevice :
40 wsprintf(base_device_name, L"%ls", WAVE_OUT_DEVICE_NAME);
41 break;
42
43 case WaveInDevice :
44 wsprintf(base_device_name, L"%ls", WAVE_IN_DEVICE_NAME);
45 break;
46
47 case MidiOutDevice :
48 wsprintf(base_device_name, L"%ls", MIDI_OUT_DEVICE_NAME);
49 break;
50
51 case MidiInDevice :
52 wsprintf(base_device_name, L"%ls", MIDI_IN_DEVICE_NAME);
53 break;
54
55 case AuxDevice :
56 wsprintf(base_device_name, L"%ls", AUX_DEVICE_NAME);
57 break;
58
59 default :
60 return MMSYSERR_BADDEVICEID;
61 };
62
63 /* Now append the device number, removing the leading \Device */
64
65 wsprintf(out_device_name,
66 L"\\\\.%ls%d",
67 base_device_name + strlen("\\Device"),
68 device_id);
69
70 return MMSYSERR_NOERROR;
71 }
72
73
74 /*
75 Takes a device type (eg: WaveOutDevice), a device ID, desired access and
76 a pointer to a location that will store the handle of the opened "file" if
77 the function succeeds.
78
79 The device type and ID are converted into a device name using the above
80 function.
81 */
82
83 MMRESULT
84 OpenKernelDevice(
85 DeviceType device_type,
86 UINT device_id,
87 DWORD access,
88 HANDLE* handle)
89 {
90 MMRESULT result;
91 WCHAR device_name[MAX_DEVICE_NAME_LENGTH];
92 DWORD open_flags = 0;
93
94 ASSERT(handle);
95
96 /* Glue the base device name and the ID together */
97
98 result = CobbleDeviceName(device_type, device_id, device_name);
99
100 DPRINT("Opening kernel device %ls\n", device_name);
101
102 if ( result != MMSYSERR_NOERROR )
103 return result;
104
105 /* We want overlapped I/O when writing */
106
107 if ( access != GENERIC_READ )
108 open_flags = FILE_FLAG_OVERLAPPED;
109
110 /* Now try opening... */
111
112 *handle = CreateFile(device_name,
113 access,
114 FILE_SHARE_WRITE,
115 NULL,
116 OPEN_EXISTING,
117 open_flags,
118 NULL);
119
120 if ( *handle == INVALID_HANDLE_VALUE )
121 return ErrorToMmResult(GetLastError());
122
123 return MMSYSERR_NOERROR;
124 }
125
126
127 /*
128 Just an alias for the benefit of having a pair of functions ;)
129 */
130
131 void
132 CloseKernelDevice(HANDLE device_handle)
133 {
134 CloseHandle(device_handle);
135 }
136
137
138 MMRESULT
139 SetDeviceData(
140 HANDLE device_handle,
141 DWORD ioctl,
142 PBYTE input_buffer,
143 DWORD buffer_size)
144 {
145 DPRINT("SetDeviceData\n");
146 /* TODO */
147 return 0;
148 }
149
150
151 MMRESULT
152 GetDeviceData(
153 HANDLE device_handle,
154 DWORD ioctl,
155 PBYTE output_buffer,
156 DWORD buffer_size)
157 {
158 OVERLAPPED overlap;
159 DWORD bytes_returned;
160 BOOL success;
161 DWORD transfer;
162
163 DPRINT("GetDeviceData\n");
164
165 memset(&overlap, 0, sizeof(overlap));
166
167 overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
168
169 if ( ! overlap.hEvent )
170 return MMSYSERR_NOMEM;
171
172 success = DeviceIoControl(device_handle,
173 ioctl,
174 NULL,
175 0,
176 output_buffer,
177 buffer_size,
178 &bytes_returned,
179 &overlap);
180
181 if ( ! success )
182 {
183 if ( GetLastError() == ERROR_IO_PENDING )
184 {
185 if ( ! GetOverlappedResult(device_handle, &overlap, &transfer, TRUE) )
186 {
187 CloseHandle(overlap.hEvent);
188 return ErrorToMmResult(GetLastError());
189 }
190 }
191 else
192 {
193 CloseHandle(overlap.hEvent);
194 return ErrorToMmResult(GetLastError());
195 }
196 }
197
198 while ( TRUE )
199 {
200 SetEvent(overlap.hEvent);
201
202 if ( WaitForSingleObjectEx(overlap.hEvent, 0, TRUE) != WAIT_IO_COMPLETION )
203 {
204 break;
205 }
206 }
207
208 CloseHandle(overlap.hEvent);
209
210 return MMSYSERR_NOERROR;
211 }