xref: /reactos/dll/win32/mmdrv/kernel.c (revision c2c66aff)
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
CobbleDeviceName(DeviceType device_type,UINT device_id,PWCHAR out_device_name)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
OpenKernelDevice(DeviceType device_type,UINT device_id,DWORD access,HANDLE * handle)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
CloseKernelDevice(HANDLE device_handle)132 CloseKernelDevice(HANDLE device_handle)
133 {
134     CloseHandle(device_handle);
135 }
136 
137 
138 MMRESULT
SetDeviceData(HANDLE device_handle,DWORD ioctl,PBYTE input_buffer,DWORD buffer_size)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
GetDeviceData(HANDLE device_handle,DWORD ioctl,PBYTE output_buffer,DWORD buffer_size)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 }
212