Merge 14981:15268 from trunk
[reactos.git] / reactos / drivers / dd / mpu401 / mpu401.c
1 /*
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: services/dd/mpu401/mpu401.c
6 * PURPOSE: MPU-401 MIDI device driver
7 * PROGRAMMER: Andrew Greenwood
8 * UPDATE HISTORY:
9 * Sept 26, 2003: Copied from beep.c as template
10 * Sept 27, 2003: Implemented MPU-401 init & playback
11 */
12
13 /* INCLUDES ****************************************************************/
14
15 #include <ddk/ntddk.h>
16 #include <rosrtl/string.h>
17 //#include <ddk/ntddbeep.h>
18
19 //#define NDEBUG
20 #include <debug.h>
21
22 #include "mpu401.h"
23
24
25 /* INTERNAL VARIABLES ******************************************************/
26
27 UINT DeviceCount = 0;
28
29
30 /* FUNCTIONS ***************************************************************/
31
32 NTSTATUS InitDevice(
33 IN PUNICODE_STRING RegistryPath,
34 IN PVOID Context)
35 {
36 // PDEVICE_INSTANCE Instance = Context;
37 PDEVICE_OBJECT DeviceObject; // = Context;
38 PDEVICE_EXTENSION Parameters; // = DeviceObject->DeviceExtension;
39 UNICODE_STRING DeviceName = ROS_STRING_INITIALIZER(L"\\Device\\MidiOut0");
40 UNICODE_STRING SymlinkName = ROS_STRING_INITIALIZER(L"\\??\\MidiOut0");
41 // CONFIG Config;
42 RTL_QUERY_REGISTRY_TABLE Table[2];
43 NTSTATUS s;
44
45 // This is TEMPORARY, to ensure that we don't process more than 1 device.
46 // I'll remove this limitation in the future.
47 if (DeviceCount > 0)
48 {
49 DPRINT("Sorry - only 1 device supported by MPU401 driver at present :(\n");
50 return STATUS_NOT_IMPLEMENTED;
51 }
52
53 DPRINT("Creating IO device\n");
54
55 s = IoCreateDevice(Context, // driverobject
56 sizeof(DEVICE_EXTENSION),
57 &DeviceName,
58 FILE_DEVICE_SOUND, // Correct?
59 0,
60 FALSE,
61 &DeviceObject);
62
63 if (!NT_SUCCESS(s))
64 return s;
65
66 DPRINT("Device Extension at 0x%x\n", DeviceObject->DeviceExtension);
67 Parameters = DeviceObject->DeviceExtension;
68
69 DPRINT("Creating DOS link\n");
70
71 /* Create the dos device link */
72 IoCreateSymbolicLink(&SymlinkName,
73 &DeviceName);
74
75 DPRINT("Initializing device\n");
76
77 // DPRINT("Allocating memory for parameters structure\n");
78 // Bodged:
79 // Parameters = (PDEVICE_EXTENSION)ExAllocatePool(NonPagedPool, sizeof(DEVICE_EXTENSION));
80 // DeviceObject->DeviceExtension = Parameters;
81 // Parameters = Instance->DriverObject->DriverExtension;
82
83 DPRINT("DeviceObject at 0x%x, DeviceExtension at 0x%x\n", DeviceObject, Parameters);
84
85 if (! Parameters)
86 {
87 DPRINT("NULL POINTER!\n");
88 return STATUS_INSUFFICIENT_RESOURCES;
89 }
90
91 // Instance->DriverObject->DriverExtension = Parameters;
92
93 DPRINT("Setting reg path\n");
94 Parameters->RegistryPath = RegistryPath;
95 // Parameters->DriverObject = Instance->DriverObject;
96
97 DPRINT("Zeroing table memory and setting query routine\n");
98 RtlZeroMemory(Table, sizeof(Table));
99 Table[0].QueryRoutine = LoadSettings;
100
101 DPRINT("Setting port and IRQ defaults\n");
102 Parameters->Port = DEFAULT_PORT;
103 Parameters->IRQ = DEFAULT_IRQ;
104
105 // Only to be enabled once we can get support for multiple cards working :)
106 /*
107 DPRINT("Loading settings from: %S\n", RegistryPath);
108
109 s = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, RegistryPath, Table,
110 &Parameters, NULL);
111 */
112
113 if (! NT_SUCCESS(s))
114 return s;
115
116 DPRINT("Port 0x%x IRQ %d\n", Parameters->Port, Parameters->IRQ);
117
118 // Instance->P
119
120 // Enter UART mode (should be done in init phase
121 if (! InitUARTMode(Parameters->Port))
122 {
123 DPRINT("UART mode initialization FAILED!\n");
124 // Set state indication somehow
125 // Failure - what error code do we give?!
126 // return STATUS_????
127 }
128
129 DeviceCount ++;
130
131 return STATUS_SUCCESS;
132 }
133
134
135 static NTSTATUS STDCALL
136 MPU401Create(PDEVICE_OBJECT DeviceObject,
137 PIRP Irp)
138 /*
139 * FUNCTION: Handles user mode requests
140 * ARGUMENTS:
141 * DeviceObject = Device for request
142 * Irp = I/O request packet describing request
143 * RETURNS: Success or failure
144 */
145 {
146 DPRINT("MPU401Create() called!\n");
147
148 // Initialize the MPU-401?
149 // ... do stuff ...
150
151
152 // Play a note to say we're alive:
153 WaitToSend(MPU401_PORT);
154 MPU401_WRITE_DATA(MPU401_PORT, 0x90);
155 WaitToSend(MPU401_PORT);
156 MPU401_WRITE_DATA(MPU401_PORT, 0x50);
157 WaitToSend(MPU401_PORT);
158 MPU401_WRITE_DATA(MPU401_PORT, 0x7f);
159
160 Irp->IoStatus.Status = STATUS_SUCCESS;
161 Irp->IoStatus.Information = 0;
162 IoCompleteRequest(Irp,
163 IO_NO_INCREMENT);
164
165 return(STATUS_SUCCESS);
166 }
167
168
169 static NTSTATUS STDCALL
170 MPU401Close(PDEVICE_OBJECT DeviceObject,
171 PIRP Irp)
172 /*
173 * FUNCTION: Handles user mode requests
174 * ARGUMENTS:
175 * DeviceObject = Device for request
176 * Irp = I/O request packet describing request
177 * RETURNS: Success or failure
178 */
179 {
180 PDEVICE_EXTENSION DeviceExtension;
181 NTSTATUS Status;
182
183 DPRINT("MPU401Close() called!\n");
184
185 DeviceExtension = DeviceObject->DeviceExtension;
186
187 Status = STATUS_SUCCESS;
188
189 Irp->IoStatus.Status = Status;
190 Irp->IoStatus.Information = 0;
191 IoCompleteRequest(Irp,
192 IO_NO_INCREMENT);
193
194 return(Status);
195 }
196
197
198 static NTSTATUS STDCALL
199 MPU401Cleanup(PDEVICE_OBJECT DeviceObject,
200 PIRP Irp)
201 /*
202 * FUNCTION: Handles user mode requests
203 * ARGUMENTS:
204 * DeviceObject = Device for request
205 * Irp = I/O request packet describing request
206 * RETURNS: Success or failure
207 */
208 {
209 UINT Channel;
210 DPRINT("MPU401Cleanup() called!\n");
211
212 // Reset the device (should we do this?)
213 for (Channel = 0; Channel <= 15; Channel ++)
214 {
215 // All notes off
216 // MPU401_WRITE_MESSAGE(MPU401_PORT, 0xb0 + Channel, 123, 0);
217 // All controllers off
218 // MPU401_WRITE_MESSAGE(MPU401_PORT, 0xb0 + Channel, 121, 0);
219 }
220
221
222 Irp->IoStatus.Status = STATUS_SUCCESS;
223 Irp->IoStatus.Information = 0;
224 IoCompleteRequest(Irp,
225 IO_NO_INCREMENT);
226
227 return(STATUS_SUCCESS);
228 }
229
230
231 static NTSTATUS STDCALL
232 MPU401DeviceControl(PDEVICE_OBJECT DeviceObject,
233 PIRP Irp)
234 /*
235 * FUNCTION: Handles user mode requests
236 * ARGUMENTS:
237 * DeviceObject = Device for request
238 * Irp = I/O request packet describing request
239 * RETURNS: Success or failure
240 */
241 {
242 PIO_STACK_LOCATION Stack;
243 PDEVICE_EXTENSION DeviceExtension;
244 UINT ByteCount;
245 PBYTE Data;
246
247 DPRINT("MPU401DeviceControl() called!\n");
248
249 DeviceExtension = DeviceObject->DeviceExtension;
250 Stack = IoGetCurrentIrpStackLocation(Irp);
251
252 DPRINT("Control code %d [0x%x]\n", Stack->Parameters.DeviceIoControl.IoControlCode,
253 Stack->Parameters.DeviceIoControl.IoControlCode);
254
255 switch(Stack->Parameters.DeviceIoControl.IoControlCode)
256 {
257 case IOCTL_MIDI_PLAY :
258 {
259 DPRINT("Received IOCTL_MIDI_PLAY\n");
260 Data = (PBYTE) Irp->AssociatedIrp.SystemBuffer;
261
262 DPRINT("Sending %d bytes of MIDI data to 0x%d:\n", Stack->Parameters.DeviceIoControl.InputBufferLength, DeviceExtension->Port);
263
264 for (ByteCount = 0; ByteCount < Stack->Parameters.DeviceIoControl.InputBufferLength; ByteCount ++)
265 {
266 DPRINT("0x%x ", Data[ByteCount]);
267
268 MPU401_WRITE_BYTE(DeviceExtension->Port, Data[ByteCount]);
269 // if (WaitToSend(MPU401_PORT))
270 // MPU401_WRITE_DATA(MPU401_PORT, Data[ByteCount]);
271 }
272
273 Irp->IoStatus.Status = STATUS_SUCCESS;
274 IoCompleteRequest(Irp, IO_NO_INCREMENT);
275
276 return(STATUS_SUCCESS);
277 }
278 }
279
280 return(STATUS_SUCCESS);
281
282 /*
283 DeviceExtension = DeviceObject->DeviceExtension;
284 Stack = IoGetCurrentIrpStackLocation(Irp);
285 BeepParam = (PBEEP_SET_PARAMETERS)Irp->AssociatedIrp.SystemBuffer;
286
287 Irp->IoStatus.Information = 0;
288
289 if (Stack->Parameters.DeviceIoControl.IoControlCode != IOCTL_BEEP_SET)
290 {
291 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
292 IoCompleteRequest(Irp,
293 IO_NO_INCREMENT);
294 return(STATUS_NOT_IMPLEMENTED);
295 }
296
297 if ((Stack->Parameters.DeviceIoControl.InputBufferLength != sizeof(BEEP_SET_PARAMETERS))
298 || (BeepParam->Frequency < BEEP_FREQUENCY_MINIMUM)
299 || (BeepParam->Frequency > BEEP_FREQUENCY_MAXIMUM))
300 {
301 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
302 IoCompleteRequest(Irp,
303 IO_NO_INCREMENT);
304 return(STATUS_INVALID_PARAMETER);
305 }
306
307 DueTime.QuadPart = 0;
308 */
309 /* do the beep!! */
310 /* DPRINT("Beep:\n Freq: %lu Hz\n Dur: %lu ms\n",
311 pbsp->Frequency,
312 pbsp->Duration);
313
314 if (BeepParam->Duration >= 0)
315 {
316 DueTime.QuadPart = (LONGLONG)BeepParam->Duration * -10000;
317
318 KeSetTimer(&DeviceExtension->Timer,
319 DueTime,
320 &DeviceExtension->Dpc);
321
322 HalMakeBeep(BeepParam->Frequency);
323 DeviceExtension->BeepOn = TRUE;
324 KeWaitForSingleObject(&DeviceExtension->Event,
325 Executive,
326 KernelMode,
327 FALSE,
328 NULL);
329 }
330 else if (BeepParam->Duration == (DWORD)-1)
331 {
332 if (DeviceExtension->BeepOn == TRUE)
333 {
334 HalMakeBeep(0);
335 DeviceExtension->BeepOn = FALSE;
336 }
337 else
338 {
339 HalMakeBeep(BeepParam->Frequency);
340 DeviceExtension->BeepOn = TRUE;
341 }
342 }
343
344 DPRINT("Did the beep!\n");
345
346 Irp->IoStatus.Status = STATUS_SUCCESS;
347 IoCompleteRequest(Irp,
348 IO_NO_INCREMENT);
349 return(STATUS_SUCCESS);
350 */
351 }
352
353
354 static VOID STDCALL
355 MPU401Unload(PDRIVER_OBJECT DriverObject)
356 {
357 DPRINT("MPU401Unload() called!\n");
358 }
359
360
361 NTSTATUS STDCALL
362 DriverEntry(PDRIVER_OBJECT DriverObject,
363 PUNICODE_STRING RegistryPath)
364 /*
365 * FUNCTION: Called by the system to initalize the driver
366 * ARGUMENTS:
367 * DriverObject = object describing this driver
368 * RegistryPath = path to our configuration entries
369 * RETURNS: Success or failure
370 */
371 {
372 // PDEVICE_EXTENSION DeviceExtension;
373 // PDEVICE_OBJECT DeviceObject;
374 // DEVICE_INSTANCE Instance;
375 // Doesn't support multiple instances (yet ...)
376 NTSTATUS Status;
377
378 DPRINT("MPU401 Device Driver 0.0.1\n");
379
380 // Is this really necessary? Yes! (Talking to myself again...)
381 // Instance.DriverObject = DriverObject;
382 // previous instance = NULL...
383
384 // DeviceExtension->RegistryPath = RegistryPath;
385
386 DriverObject->Flags = 0;
387 DriverObject->MajorFunction[IRP_MJ_CREATE] = MPU401Create;
388 DriverObject->MajorFunction[IRP_MJ_CLOSE] = MPU401Close;
389 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = MPU401Cleanup;
390 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MPU401DeviceControl;
391 DriverObject->DriverUnload = MPU401Unload;
392
393 // Major hack to just get this damn thing working:
394 Status = InitDevice(RegistryPath, DriverObject); // ????
395
396 // DPRINT("Enumerating devices at %wZ\n", RegistryPath);
397
398 // Status = EnumDeviceKeys(RegistryPath, PARMS_SUBKEY, InitDevice, (PVOID)&DeviceObject); // &Instance;
399
400 // check error
401
402 /* set up device extension */
403 // DeviceExtension = DeviceObject->DeviceExtension;
404 // DeviceExtension->BeepOn = FALSE;
405
406 return(STATUS_SUCCESS);
407 }
408
409 /* EOF */