1 /* 2 ReactOS 3 Sound Blaster driver 4 5 Programmers: 6 Andrew Greenwood 7 8 Notes: 9 Compatible with NT4 10 */ 11 12 #define NDEBUG 13 #include <sndblst.h> 14 15 16 /* 17 IRP DISPATCH ROUTINES 18 */ 19 20 NTSTATUS NTAPI 21 CreateSoundBlaster( 22 PDEVICE_OBJECT DeviceObject, 23 PIRP Irp) 24 { 25 PSOUND_BLASTER_PARAMETERS sb_device = DeviceObject->DeviceExtension; 26 27 DPRINT("CreateSoundBlaster() called - extension 0x%x\n", sb_device); 28 29 EnableSpeaker(sb_device); 30 /*SetOutputSampleRate(sb_device, 22*/ 31 32 Irp->IoStatus.Status = STATUS_SUCCESS; 33 Irp->IoStatus.Information = 0; 34 35 IoCompleteRequest(Irp, IO_NO_INCREMENT); 36 37 return STATUS_SUCCESS; 38 } 39 40 NTSTATUS NTAPI 41 CloseSoundBlaster( 42 PDEVICE_OBJECT DeviceObject, 43 PIRP Irp) 44 { 45 //PSOUND_BLASTER_PARAMETERS sb_device = DeviceObject->DeviceExtension; 46 47 DPRINT("CloseSoundBlaster() called\n"); 48 49 Irp->IoStatus.Status = STATUS_SUCCESS; 50 Irp->IoStatus.Information = 0; 51 52 IoCompleteRequest(Irp, IO_NO_INCREMENT); 53 54 return STATUS_SUCCESS; 55 } 56 57 NTSTATUS NTAPI 58 CleanupSoundBlaster( 59 PDEVICE_OBJECT DeviceObject, 60 PIRP Irp) 61 { 62 //PSOUND_BLASTER_PARAMETERS sb_device = DeviceObject->DeviceExtension; 63 64 DPRINT("CleanupSoundBlaster() called\n"); 65 66 Irp->IoStatus.Status = STATUS_SUCCESS; 67 Irp->IoStatus.Information = 0; 68 69 IoCompleteRequest(Irp, IO_NO_INCREMENT); 70 71 return STATUS_SUCCESS; 72 } 73 74 NTSTATUS NTAPI 75 ControlSoundBlaster( 76 PDEVICE_OBJECT DeviceObject, 77 PIRP Irp) 78 { 79 PIO_STACK_LOCATION stack; 80 //PSOUND_BLASTER_PARAMETERS sb_device = DeviceObject->DeviceExtension; 81 82 DPRINT("ControlSoundBlaster() called\n"); 83 84 stack = IoGetCurrentIrpStackLocation(Irp); 85 86 switch ( stack->Parameters.DeviceIoControl.IoControlCode) 87 { 88 /* TODO */ 89 }; 90 91 Irp->IoStatus.Status = STATUS_SUCCESS; 92 Irp->IoStatus.Information = 0; 93 94 IoCompleteRequest(Irp, IO_NO_INCREMENT); 95 96 return STATUS_SUCCESS; 97 } 98 99 NTSTATUS NTAPI 100 WriteSoundBlaster( 101 PDEVICE_OBJECT DeviceObject, 102 PIRP Irp) 103 { 104 //PSOUND_BLASTER_PARAMETERS sb_device = DeviceObject->DeviceExtension; 105 106 DPRINT("WriteSoundBlaster() called\n"); 107 108 Irp->IoStatus.Status = STATUS_SUCCESS; 109 Irp->IoStatus.Information = 0; 110 111 IoCompleteRequest(Irp, IO_NO_INCREMENT); 112 113 return STATUS_SUCCESS; 114 } 115 116 VOID NTAPI 117 UnloadSoundBlaster( 118 PDRIVER_OBJECT DriverObject) 119 { 120 DPRINT("Sound Blaster driver unload\n"); 121 } 122 123 NTSTATUS NTAPI 124 OpenSubkey( 125 PUNICODE_STRING RegistryPath, 126 PWSTR Subkey, 127 ACCESS_MASK DesiredAccess, 128 OUT HANDLE* DevicesKeyHandle) 129 { 130 NTSTATUS status; 131 OBJECT_ATTRIBUTES attribs; 132 UNICODE_STRING subkey_name; 133 HANDLE key_handle; 134 135 /* TODO: Check for NULL ptr in DevicesKeyHandle */ 136 137 InitializeObjectAttributes(&attribs, 138 RegistryPath, 139 OBJ_CASE_INSENSITIVE, 140 NULL, 141 (PSECURITY_DESCRIPTOR) NULL); 142 143 status = ZwOpenKey(&key_handle, KEY_READ, &attribs); 144 145 if ( ! NT_SUCCESS(status) ) 146 { 147 DPRINT("Couldn't open subkey %wZ\n", Subkey); 148 return status; 149 } 150 151 RtlInitUnicodeString(&subkey_name, Subkey); 152 153 InitializeObjectAttributes(&attribs, 154 &subkey_name, 155 OBJ_CASE_INSENSITIVE, 156 key_handle, 157 (PSECURITY_DESCRIPTOR) NULL); 158 159 status = ZwOpenKey(*DevicesKeyHandle, DesiredAccess, &attribs); 160 ZwClose(key_handle); 161 162 return status; 163 } 164 165 166 PWSTR NTAPI 167 AllocateRegistryPathInfo( 168 PUNICODE_STRING BasePath, 169 PUNICODE_STRING ParametersPath, 170 PKEY_BASIC_INFORMATION KeyInfo) 171 { 172 PWSTR name; 173 PWSTR pos; 174 175 DPRINT("Allocating memory for path info\n"); 176 name = ExAllocatePool(PagedPool, 177 BasePath->Length + sizeof(WCHAR) + 178 ParametersPath->Length + sizeof(WCHAR) + 179 KeyInfo->NameLength + sizeof(UNICODE_NULL)); 180 181 if ( ! name ) 182 return NULL; 183 184 DPRINT("Copying info\n"); 185 pos = name; 186 187 RtlCopyMemory((PVOID)Pos, (PVOID)BasePath->Buffer, BasePath->Length); 188 pos += BasePath->Length / sizeof(WCHAR); 189 pos[0] = '\\'; 190 pos ++; 191 192 RtlCopyMemory((PVOID)Pos, (PVOID)ParametersPath->Buffer, ParametersPath->Length); 193 pos += ParametersPath->Length / sizeof(WCHAR); 194 pos[0] = '\\'; 195 pos ++; 196 197 RtlCopyMemory((PVOID)Pos, (PVOID)ParametersPath->Buffer, ParametersPath->Length); 198 pos += KeyInfo->NameLength / sizeof(WCHAR); 199 pos[0] = UNICODE_NULL; 200 201 DPRINT("All OK\n"); 202 return name; 203 } 204 205 #define FreeRegistryPathInfo(ptr) \ 206 ExFreePool(ptr) 207 208 209 #define TAG_REG_INFO 'RegI' 210 #define TAG_REG_NAME 'RegN' 211 212 NTSTATUS NTAPI 213 EnumerateSubkey( 214 PUNICODE_STRING RegistryPath, 215 PWSTR Subkey, 216 PREGISTRY_CALLBACK_ROUTINE Callback, 217 PDRIVER_OBJECT DriverObject) 218 { 219 NTSTATUS status; 220 UNICODE_STRING subkey_name; 221 HANDLE devices_key_handle; 222 223 ULONG key_index = 0; 224 ULONG result_length; 225 226 status = OpenSubkey(RegistryPath, Subkey, KEY_ENUMERATE_SUB_KEYS, &devices_key_handle); 227 228 if ( ! NT_SUCCESS(status) ) 229 return status; 230 231 while ( TRUE ) 232 { 233 KEY_BASIC_INFORMATION test_info; 234 PKEY_BASIC_INFORMATION info; 235 ULONG size; 236 PWSTR name; 237 238 status = ZwEnumerateKey(devices_key_handle, 239 key_index, 240 KeyBasicInformation, 241 &test_info, 242 sizeof(test_info), 243 &result_length); 244 245 if ( status == STATUS_NO_MORE_ENTRIES ) 246 break; 247 248 size = result_length + FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]); 249 250 info = (PKEY_BASIC_INFORMATION) ExAllocatePoolWithTag(PagedPool, size, TAG_REG_INFO); 251 252 if ( ! info ) 253 { 254 DPRINT("Out of memory\n"); 255 status = STATUS_INSUFFICIENT_RESOURCES; 256 break; 257 } 258 259 status = ZwEnumerateKey(devices_key_handle, 260 key_index, 261 KeyBasicInformation, 262 info, 263 size, 264 &result_length); 265 266 if ( ! NT_SUCCESS(status) ) 267 { 268 DPRINT("Unable to enumerate keys\n"); 269 ExFreePoolWithTag(info, TAG_REG_INFO); 270 status = STATUS_INTERNAL_ERROR; 271 break; 272 } 273 274 /* Is this ok? */ 275 RtlInitUnicodeString(&subkey_name, Subkey); 276 277 name = AllocateRegistryPathInfo(RegistryPath, &subkey_name, info); 278 279 if ( ! name ) 280 { 281 DPRINT("Out of memory\n"); 282 ExFreePoolWithTag(info, TAG_REG_INFO); 283 status = STATUS_INSUFFICIENT_RESOURCES; 284 break; 285 } 286 287 ExFreePoolWithTag(info, TAG_REG_INFO); 288 289 /* Call the callback */ 290 status = Callback(DriverObject, name); 291 292 FreeRegistryPathInfo(name); 293 294 if ( ! NT_SUCCESS(status) ) 295 { 296 DPRINT("Callback FAILED\n"); 297 break; 298 } 299 300 key_index ++; 301 } 302 303 ZwClose(devices_key_handle); 304 305 DPRINT("Found %d subkey entries\n", key_index); 306 307 if ( ( key_index == 0 ) && ( status == STATUS_NO_MORE_ENTRIES ) ) 308 return STATUS_DEVICE_CONFIGURATION_ERROR; 309 310 if ( status == STATUS_NO_MORE_ENTRIES ) 311 status = STATUS_SUCCESS; 312 313 return status; 314 } 315 316 #define EnumerateDeviceKeys(path, callback, driver_obj) \ 317 EnumerateSubkey(path, L"Devices", callback, driver_obj) 318 319 320 NTSTATUS 321 CreateDeviceName( 322 PCWSTR PrePrefix, 323 PCWSTR Prefix, 324 UCHAR Index, 325 PUNICODE_STRING DeviceName) 326 { 327 UNICODE_STRING number; 328 WCHAR number_buffer[5]; 329 UNICODE_STRING unicode_pre_prefix; 330 UNICODE_STRING unicode_prefix; 331 ULONG size; 332 333 RtlInitUnicodeString(&unicode_pre_prefix, PrePrefix); 334 RtlInitUnicodeString(&unicode_prefix, Prefix); 335 336 size = unicode_pre_prefix.Length + 337 unicode_prefix.Length + 338 sizeof(number_buffer) + 339 sizeof(UNICODE_NULL); 340 341 DeviceName->Buffer = ExAllocatePool(PagedPool, size); 342 DeviceName->MaximumLength = (USHORT) size; 343 344 if ( ! DeviceName->Buffer ) 345 return STATUS_INSUFFICIENT_RESOURCES; 346 347 RtlCopyUnicodeString(DeviceName, &unicode_pre_prefix); 348 RtlAppendUnicodeStringToString(DeviceName, &unicode_prefix); 349 350 if ( Index != 255 ) 351 { 352 number.Buffer = number_buffer; 353 number.MaximumLength = sizeof(number_buffer); 354 355 RtlIntegerToUnicodeString((ULONG) Index, 10, &number); 356 RtlAppendUnicodeStringToString(DeviceName, &number); 357 } 358 359 DeviceName->Buffer[DeviceName->Length / sizeof(UNICODE_NULL)] = UNICODE_NULL; 360 361 return STATUS_SUCCESS; 362 } 363 364 NTSTATUS NTAPI 365 InitializeSoundBlaster( 366 PDRIVER_OBJECT DriverObject, 367 PWSTR RegistryPath) 368 { 369 NTSTATUS status; 370 PDEVICE_OBJECT device_object; 371 PSOUND_BLASTER_PARAMETERS parameters = NULL; 372 UNICODE_STRING device_name; 373 UNICODE_STRING dos_device_name; 374 375 UCHAR device_index = 0; 376 377 DPRINT("Initializing a Sound Blaster device\n"); 378 379 /* Change these later */ 380 status = CreateDeviceName(L"", 381 L"\\Device\\WaveOut", 382 device_index, 383 &device_name); 384 385 if ( ! NT_SUCCESS(status) ) 386 return status; 387 388 status = CreateDeviceName(L"\\DosDevices\\", 389 L"\\Device\\WaveOut" + wcslen(L"\\Device\\"), 390 device_index, 391 &dos_device_name); 392 393 if ( ! NT_SUCCESS(status) ) 394 { 395 /* TODO */ 396 return status; 397 } 398 399 DPRINT("Device: %wZ\n", device_name); 400 DPRINT("Symlink: %wZ\n", dos_device_name); 401 402 /* 403 Create the device and DOS symlink 404 */ 405 406 status = IoCreateDevice(DriverObject, 407 sizeof(SOUND_BLASTER_PARAMETERS), 408 &device_name, 409 FILE_DEVICE_SOUND, 410 0, 411 FALSE, 412 &device_object); 413 414 if ( ! NT_SUCCESS(status) ) 415 return status; 416 417 DPRINT("Created a device extension at 0x%x\n", device_object->DeviceExtension); 418 parameters = device_object->DeviceExtension; 419 420 status = IoCreateSymbolicLink(&dos_device_name, &device_name); 421 422 ExFreePool(dos_device_name.Buffer); 423 ExFreePool(device_name.Buffer); 424 425 if ( ! NT_SUCCESS(status) ) 426 { 427 IoDeleteDevice(device_object); 428 device_object = NULL; 429 return status; 430 } 431 432 /* IoRegisterShutdownNotification( */ 433 434 /* 435 Settings 436 */ 437 438 device_object->AlignmentRequirement = FILE_BYTE_ALIGNMENT; 439 440 parameters->driver = DriverObject; 441 parameters->registry_path = RegistryPath; 442 parameters->port = DEFAULT_PORT; 443 parameters->irq = DEFAULT_IRQ; 444 parameters->dma = DEFAULT_DMA; 445 parameters->buffer_size = DEFAULT_BUFFER_SIZE; 446 447 /* TODO: Load the settings from the registry */ 448 449 DPRINT("Port %x IRQ %d DMA %d\n", parameters->port, parameters->irq, parameters->dma); 450 451 DPRINT("Resetting the sound card\n"); 452 453 if ( ! ResetSoundBlaster(parameters) ) 454 { 455 /* TODO */ 456 return STATUS_UNSUCCESSFUL; 457 } 458 459 /* 460 DPRINT("What kind of SB card is this?\n"); 461 GetSoundBlasterModel(parameters); 462 */ 463 464 return STATUS_SUCCESS; 465 } 466 467 468 NTSTATUS NTAPI 469 DriverEntry( 470 PDRIVER_OBJECT DriverObject, 471 PUNICODE_STRING RegistryPath) 472 { 473 NTSTATUS status; 474 475 DPRINT("Sound Blaster driver 0.1 by Silver Blade\n"); 476 477 DriverObject->Flags = 0; 478 DriverObject->MajorFunction[IRP_MJ_CREATE] = CreateSoundBlaster; 479 DriverObject->MajorFunction[IRP_MJ_CLOSE] = CloseSoundBlaster; 480 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = CleanupSoundBlaster; 481 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ControlSoundBlaster; 482 DriverObject->MajorFunction[IRP_MJ_WRITE] = WriteSoundBlaster; 483 DriverObject->DriverUnload = UnloadSoundBlaster; 484 485 DPRINT("Beginning device key enumeration\n"); 486 487 status = EnumerateDeviceKeys(RegistryPath, *InitializeSoundBlaster, DriverObject); 488 489 return status; 490 } 491