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