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 } 212