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