|
|
1.1 ! root 1: /*++ ! 2: ! 3: Copyright (c) 1992 Microsoft Corporation ! 4: ! 5: Module Name: ! 6: ! 7: soundlib.c ! 8: ! 9: Abstract: ! 10: ! 11: This module contains common code for Sound Kernel mode device ! 12: drivers. ! 13: ! 14: Author: ! 15: ! 16: Robin Speed (robinsp) 16-October-1992 ! 17: ! 18: Environment: ! 19: ! 20: Kernel mode ! 21: ! 22: Revision History: ! 23: ! 24: ! 25: --*/ ! 26: ! 27: #include <string.h> ! 28: #include <stdlib.h> ! 29: #include <stdio.h> // For vsprintf ! 30: #include <stdarg.h> // For va_list ! 31: #include <soundlib.h> // Definition of what's in here ! 32: ! 33: // ! 34: // Internal routine definintions ! 35: // ! 36: ! 37: NTSTATUS SoundConfigurationCallout( ! 38: IN PVOID Context, ! 39: IN PUNICODE_STRING PathName, ! 40: IN INTERFACE_TYPE BusType, ! 41: IN ULONG BusNumber, ! 42: IN PKEY_VALUE_FULL_INFORMATION *BusInformation, ! 43: IN CONFIGURATION_TYPE ControllerType, ! 44: IN ULONG ControllerNumber, ! 45: IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation, ! 46: IN CONFIGURATION_TYPE PeripheralType, ! 47: IN ULONG PeripheralNumber, ! 48: IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation ! 49: ); ! 50: ! 51: // ! 52: // Remove initialization stuff from resident memory ! 53: // ! 54: ! 55: #ifdef ALLOC_PRAGMA ! 56: #pragma alloc_text(init,SoundGetBusNumber) ! 57: #pragma alloc_text(init,SoundConfigurationCallout) ! 58: #pragma alloc_text(init,SoundReportResourceUsage) ! 59: #pragma alloc_text(init,SoundCreateDevice) ! 60: #pragma alloc_text(init,SoundMapPortAddress) ! 61: #pragma alloc_text(init,SoundConnectInterrupt) ! 62: #pragma alloc_text(init,SoundSetErrorCode) ! 63: #pragma alloc_text(init,SoundSaveRegistryPath) ! 64: #endif ! 65: ! 66: ! 67: NTSTATUS ! 68: SoundGetBusNumber( ! 69: IN OUT INTERFACE_TYPE InterfaceType, ! 70: OUT PULONG BusNumber ! 71: ) ! 72: /*++ ! 73: ! 74: Routine Description : ! 75: ! 76: Find the bus of the type we are looking for - and hope this is ! 77: the one with our card on! Actually if bus is not ! 78: bus number 0 we fail. ! 79: ! 80: Arguments : ! 81: ! 82: BusNumber - Where to put the answer ! 83: ! 84: Return Value : ! 85: ! 86: NT status code - STATUS_SUCCESS if no problems ! 87: ! 88: --*/ ! 89: { ! 90: ULONG TestBusNumber = 0; ! 91: NTSTATUS Status; ! 92: BOOLEAN Ok = FALSE; // Must match type passed by reference to ! 93: // SoundConfigurationCallout by ! 94: // IoQueryDeviceDescription. ! 95: ! 96: // ! 97: // See if our bus type exists by calling IoQueryDeviceDescription ! 98: // ! 99: ! 100: ! 101: Status = IoQueryDeviceDescription( ! 102: &InterfaceType, ! 103: &TestBusNumber, ! 104: NULL, ! 105: NULL, ! 106: NULL, ! 107: NULL, ! 108: SoundConfigurationCallout, ! 109: (PVOID)&Ok); ! 110: ! 111: ! 112: if (Ok) { ! 113: *BusNumber = TestBusNumber; ! 114: } ! 115: ! 116: return Ok ? STATUS_SUCCESS : STATUS_DEVICE_DOES_NOT_EXIST; ! 117: } ! 118: ! 119: ! 120: ! 121: ! 122: NTSTATUS ! 123: SoundConfigurationCallout( ! 124: IN PVOID Context, ! 125: IN PUNICODE_STRING PathName, ! 126: IN INTERFACE_TYPE BusType, ! 127: IN ULONG BusNumber, ! 128: IN PKEY_VALUE_FULL_INFORMATION *BusInformation, ! 129: IN CONFIGURATION_TYPE ControllerType, ! 130: IN ULONG ControllerNumber, ! 131: IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation, ! 132: IN CONFIGURATION_TYPE PeripheralType, ! 133: IN ULONG PeripheralNumber, ! 134: IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation ! 135: ) ! 136: /*++ ! 137: ! 138: Routine Description : ! 139: ! 140: Set the return to OK to indicate we've found the bus type ! 141: we were looking for. Merely being called is confirmation ! 142: that our bus is there. ! 143: ! 144: Arguments : ! 145: ! 146: See the arguments defined by PIO_QUERY_DEVICE_ROUTINE ! 147: ! 148: Return Value : ! 149: ! 150: STATUS_SUCCESS if no problems ! 151: ! 152: --*/ ! 153: { ! 154: *(PBOOLEAN)Context = (BOOLEAN)TRUE; ! 155: return STATUS_SUCCESS; ! 156: } ! 157: ! 158: ! 159: ! 160: ! 161: NTSTATUS SoundReportResourceUsage( ! 162: IN PDEVICE_OBJECT DeviceObject, ! 163: IN INTERFACE_TYPE BusType, ! 164: IN ULONG BusNumber, ! 165: IN PULONG InterruptNumber OPTIONAL, ! 166: IN KINTERRUPT_MODE InterruptMode, ! 167: IN BOOLEAN InterruptShareDisposition, ! 168: IN PULONG DmaChannel OPTIONAL, ! 169: IN PULONG FirstIoPort OPTIONAL, ! 170: IN ULONG IoPortLength ! 171: ) ! 172: /*++ ! 173: ! 174: Routine Description : ! 175: ! 176: Calls IoReportResourceUsage for the device and resources ! 177: passed in. NOTE that this supercedes previous resources ! 178: declared for this device. ! 179: ! 180: It is assumed that all resources owned by the device cannot ! 181: be shared, except for level-sensitive interrupts which can be ! 182: shared. ! 183: ! 184: Arguments : ! 185: ! 186: DeviceObject - The device which 'owns' the resources ! 187: This can also be a pointer to a driver object ! 188: BusType - The type of bus on which the device lives ! 189: BusNumber - The bus number (of type BusType) where the device is ! 190: InterruptNumber - The interrupt the devices uses (if any) ! 191: DmaChannel - The DMA channel the device uses ! 192: FirstIoPort - The start Io port for the device ! 193: IoPortLength - The number of bytes of IO space the device uses ! 194: (starting at FirstIoPort) ! 195: ! 196: Return Value : ! 197: ! 198: STATUS_SUCCESS if no problems ! 199: The return from IoReportResourceUsage if this fails ! 200: STATUS_DEVICE_CONFIGURATION_ERROR is IoReportResourceUsage reports ! 201: a conflict ! 202: ! 203: --*/ ! 204: ! 205: { ! 206: NTSTATUS Status; ! 207: ! 208: // ! 209: // Our resource list to report back to the system ! 210: // ! 211: ! 212: /* ! 213: ! 214: Compiler rejects this ! 215: ! 216: UCHAR ResBuffer[FIELD_OFFSET( ! 217: CM_RESOURCE_LIST, ! 218: List[0].PartialResourceList.PartialDescriptors[3].Type)]; ! 219: ! 220: */ ! 221: ! 222: UCHAR ResBuffer[3 * sizeof(CM_RESOURCE_LIST)]; ! 223: ! 224: BOOLEAN ResourceConflict; ! 225: ! 226: PCM_RESOURCE_LIST ResourceList; ! 227: PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor; ! 228: ! 229: ResourceList = (PCM_RESOURCE_LIST)ResBuffer; ! 230: Descriptor = ResourceList->List[0].PartialResourceList.PartialDescriptors; ! 231: ResourceConflict = FALSE; ! 232: ! 233: // ! 234: // Zero out any unused data ! 235: // ! 236: ! 237: RtlZeroMemory(ResBuffer, sizeof(ResBuffer)); ! 238: ! 239: // ! 240: // We assume there's only 1 bus so we only need one list. ! 241: // Fill in the bus description ! 242: // ! 243: ! 244: ResourceList->Count = 1; ! 245: ResourceList->List[0].InterfaceType = BusType; ! 246: ResourceList->List[0].BusNumber = BusNumber; ! 247: ! 248: // ! 249: // If the device is using IO Ports add this to the list ! 250: // ! 251: ! 252: if (ARGUMENT_PRESENT(FirstIoPort)) { ! 253: PHYSICAL_ADDRESS PortAddress; ! 254: ULONG MemType; ! 255: PHYSICAL_ADDRESS MappedAddress; ! 256: ! 257: PortAddress.LowPart = *FirstIoPort; ! 258: PortAddress.HighPart = 0; ! 259: MemType = 1; ! 260: ! 261: HalTranslateBusAddress( ! 262: BusType, ! 263: BusNumber, ! 264: PortAddress, ! 265: &MemType, ! 266: &MappedAddress); ! 267: ! 268: ! 269: ResourceList->List[0].PartialResourceList.Count++; ! 270: ! 271: Descriptor->Type = CmResourceTypePort; ! 272: ! 273: Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; ! 274: ! 275: Descriptor->u.Port.Start.LowPart = *FirstIoPort; ! 276: ! 277: Descriptor->u.Port.Length = IoPortLength; ! 278: ! 279: Descriptor->Flags = MemType == 0 ? CM_RESOURCE_PORT_MEMORY : ! 280: CM_RESOURCE_PORT_IO; ! 281: ! 282: // ! 283: // Move on to next resource descriptor entry ! 284: // ! 285: ! 286: Descriptor++; ! 287: } ! 288: ! 289: // ! 290: // Add interrupt information (if any) to the list ! 291: // ! 292: ! 293: if (ARGUMENT_PRESENT(InterruptNumber)) { ! 294: ResourceList->List[0].PartialResourceList.Count++; ! 295: ! 296: Descriptor->Type = CmResourceTypeInterrupt; ! 297: ! 298: Descriptor->ShareDisposition = InterruptShareDisposition ? ! 299: CmResourceShareShared : ! 300: CmResourceShareDeviceExclusive; ! 301: ! 302: Descriptor->Flags = ! 303: InterruptMode == Latched ? CM_RESOURCE_INTERRUPT_LATCHED : ! 304: CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; ! 305: ! 306: Descriptor->u.Interrupt.Level = *InterruptNumber; ! 307: ! 308: Descriptor->u.Interrupt.Vector = *InterruptNumber; ! 309: ! 310: // ! 311: // Move on to next resource descriptor entry ! 312: // ! 313: ! 314: Descriptor++; ! 315: } ! 316: ! 317: // ! 318: // Add DMA description if any ! 319: // ! 320: ! 321: if (ARGUMENT_PRESENT(DmaChannel)) { ! 322: ResourceList->List[0].PartialResourceList.Count++; ! 323: ! 324: Descriptor->Type = CmResourceTypeDma; ! 325: ! 326: Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; ! 327: ! 328: Descriptor->u.Dma.Channel = *DmaChannel; ! 329: ! 330: Descriptor->u.Dma.Port = 0; // ??? ! 331: ! 332: // ! 333: // Move on to next resource descriptor entry ! 334: // ! 335: ! 336: Descriptor++; ! 337: } ! 338: ! 339: // ! 340: // Report our resource usage and detect conflicts ! 341: // ! 342: ! 343: switch (DeviceObject->Type) { ! 344: case IO_TYPE_DEVICE: ! 345: Status = IoReportResourceUsage(NULL, ! 346: DeviceObject->DriverObject, ! 347: NULL, ! 348: 0, ! 349: DeviceObject, ! 350: ResourceList, ! 351: (PUCHAR)Descriptor - (PUCHAR)ResourceList, ! 352: FALSE, ! 353: &ResourceConflict); ! 354: break; ! 355: case IO_TYPE_DRIVER: ! 356: Status = IoReportResourceUsage(NULL, ! 357: (PDRIVER_OBJECT)DeviceObject, ! 358: ResourceList, ! 359: (PUCHAR)Descriptor - (PUCHAR)ResourceList, ! 360: NULL, ! 361: NULL, ! 362: 0, ! 363: FALSE, ! 364: &ResourceConflict); ! 365: break; ! 366: ! 367: default: ! 368: ASSERTMSG("SoundReportResourceUsage - invalid object", FALSE); ! 369: } ! 370: ! 371: if (ResourceConflict) { ! 372: dprintf1(("Resource conflict reported")); ! 373: Status = STATUS_DEVICE_CONFIGURATION_ERROR; ! 374: } ! 375: ! 376: return Status; ! 377: } ! 378: ! 379: ! 380: ! 381: ! 382: VOID ! 383: SoundFreeDevice( ! 384: IN PDEVICE_OBJECT DeviceObject ! 385: ) ! 386: /*++ ! 387: ! 388: Routine Description : ! 389: ! 390: Free the all resources related to this device : ! 391: ! 392: The device object itself ! 393: ! 394: Any declared hardware resources (via IoReportResourceUsage) ! 395: ! 396: Any symbolic link related to this device ! 397: ! 398: Arguments : ! 399: ! 400: DeviceObject - the device to free ! 401: ! 402: Return Value : ! 403: ! 404: None ! 405: ! 406: --*/ ! 407: { ! 408: CM_RESOURCE_LIST NullResourceList; ! 409: BOOLEAN ResourceConflict; ! 410: ! 411: ! 412: // ! 413: // Free the device if any ! 414: // ! 415: ! 416: if (DeviceObject != NULL) { ! 417: ! 418: ! 419: // ! 420: // Undeclare any resources used by the device ! 421: // (delete anything the driver has at the same time!) ! 422: // ! 423: ! 424: NullResourceList.Count = 0; ! 425: ! 426: IoReportResourceUsage(NULL, ! 427: DeviceObject->DriverObject, ! 428: &NullResourceList, ! 429: sizeof(ULONG), ! 430: DeviceObject, ! 431: &NullResourceList, ! 432: sizeof(ULONG), ! 433: FALSE, ! 434: &ResourceConflict); ! 435: ! 436: // ! 437: // Remove the device's symbolic link ! 438: // ! 439: ! 440: { ! 441: PLOCAL_DEVICE_INFO pLDI; ! 442: UNICODE_STRING DeviceName; ! 443: WCHAR Number[8]; ! 444: WCHAR TestName[SOUND_MAX_DEVICE_NAME]; ! 445: ! 446: pLDI = DeviceObject->DeviceExtension; ! 447: ! 448: DeviceName.Buffer = TestName; ! 449: DeviceName.MaximumLength = sizeof(TestName); ! 450: DeviceName.Length = 0; ! 451: ! 452: RtlAppendUnicodeToString(&DeviceName, L"\\DosDevices"); ! 453: ! 454: RtlAppendUnicodeToString( ! 455: &DeviceName, ! 456: pLDI->DeviceInit->PrototypeName + ! 457: (sizeof(L"\\Device") - sizeof(UNICODE_NULL)) / ! 458: sizeof(UNICODE_NULL)); ! 459: ! 460: if (!(pLDI->CreationFlags & SOUND_CREATION_NO_NAME_RANGE)) { ! 461: UNICODE_STRING UnicodeNum; ! 462: WCHAR Number[8]; ! 463: UnicodeNum.MaximumLength = sizeof(Number); ! 464: UnicodeNum.Buffer = Number; ! 465: ! 466: RtlIntegerToUnicodeString(pLDI->DeviceNumber, 10, &UnicodeNum); ! 467: RtlAppendUnicodeStringToString(&DeviceName, &UnicodeNum); ! 468: } ! 469: ! 470: IoDeleteSymbolicLink(&DeviceName); ! 471: } ! 472: ! 473: // ! 474: // Delete the device object ! 475: // ! 476: ! 477: IoDeleteDevice(DeviceObject); ! 478: } ! 479: } ! 480: ! 481: ! 482: NTSTATUS ! 483: SoundCreateDevice( ! 484: IN PSOUND_DEVICE_INIT DeviceInit, ! 485: IN UCHAR CreationFlags, ! 486: IN PDRIVER_OBJECT pDriverObject, ! 487: IN PVOID pGDI, ! 488: IN PVOID DeviceSpecificData, ! 489: IN PVOID pHw, ! 490: IN int i, ! 491: OUT PDEVICE_OBJECT *ppDevObj ! 492: ) ! 493: ! 494: /*++ ! 495: ! 496: Routine Description: ! 497: ! 498: Create a new device using a name derived from szPrototypeName ! 499: by adding a number on to the end such that the no device with the ! 500: qualified name exists. ! 501: ! 502: A symbolic link in \DosDevices is also created ! 503: ! 504: Arguments: ! 505: ! 506: DeviceInit - device initialization data ! 507: ! 508: NoRange - if this is set then no number is concatenated, the ! 509: explicit name is used. ! 510: ! 511: pDriverObject - our driver ! 512: ! 513: pGDI - global context ! 514: ! 515: pHw - hardware context ! 516: ! 517: i - device number for back reference ! 518: ! 519: ppDevObj - where to write back the device object pointer ! 520: ! 521: Return Value: ! 522: ! 523: An NTSTATUS code. ! 524: ! 525: --*/ ! 526: ! 527: { ! 528: ! 529: int DeviceNumber; ! 530: NTSTATUS Status; ! 531: UNICODE_STRING DeviceName; ! 532: UNICODE_STRING UnicodeNum; ! 533: WCHAR TestName[SOUND_MAX_DEVICE_NAME]; ! 534: WCHAR Number[8]; ! 535: OBJECT_ATTRIBUTES ObjectAttributes; ! 536: PLOCAL_DEVICE_INFO pLDI; ! 537: ! 538: #ifdef SOUND_DIRECTORIES ! 539: HANDLE DirectoryHandle = NULL; ! 540: ! 541: // ! 542: // Create the directory for this device type. ! 543: // ! 544: ! 545: RtlInitUnicodeString(&DeviceName, DeviceInit->PrototypeName); ! 546: InitializeObjectAttributes(&ObjectAttributes, ! 547: &DeviceName, ! 548: OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, ! 549: NULL, ! 550: (PSECURITY_DESCRIPTOR)NULL); ! 551: ! 552: // ! 553: // We create the directory if it doesn't exist. ! 554: // We must keep this handle open until we create something as ! 555: // we're not making it permanent. This means that if we unload ! 556: // the system may be able to get rid of the directory ! 557: // ! 558: ! 559: Status = ZwCreateDirectoryObject(&DirectoryHandle, ! 560: GENERIC_READ, ! 561: &ObjectAttributes); ! 562: ! 563: if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION) { ! 564: dprintf1(("Return code from NtCreateDirectoryObject = %x", Status)); ! 565: return Status; ! 566: } else { ! 567: // ! 568: // Directory is permanent so it won't go away. ! 569: // ! 570: ZwClose(DirectoryHandle); ! 571: } ! 572: #endif // SOUND_DIRECTORIES ! 573: ! 574: for (DeviceNumber = 0; DeviceNumber < SOUND_MAX_DEVICES; DeviceNumber ++) { ! 575: ! 576: // ! 577: // Create our test name ! 578: // ! 579: ! 580: DeviceName.Length = 0; ! 581: DeviceName.Buffer = TestName; ! 582: DeviceName.MaximumLength = sizeof(TestName); ! 583: ! 584: Status = RtlAppendUnicodeToString(&DeviceName, DeviceInit->PrototypeName); ! 585: ! 586: if (!NT_SUCCESS(Status)) { ! 587: return Status; ! 588: } ! 589: ! 590: #ifdef SOUND_DIRECTORIES ! 591: RtlAppendUnicodeToString(&DeviceName, "\\"); ! 592: #else ! 593: #endif // SOUND_DIRECTORIES ! 594: ! 595: // ! 596: // Append the device number if required ! 597: // ! 598: ! 599: if (!(CreationFlags & SOUND_CREATION_NO_NAME_RANGE)) { ! 600: UnicodeNum.MaximumLength = sizeof(Number); ! 601: UnicodeNum.Buffer = Number; ! 602: RtlIntegerToUnicodeString(DeviceNumber, 10, &UnicodeNum); ! 603: ! 604: RtlAppendUnicodeStringToString(&DeviceName, &UnicodeNum); ! 605: } else { ! 606: DeviceNumber = 255; ! 607: } ! 608: ! 609: Status = IoCreateDevice( ! 610: pDriverObject, ! 611: sizeof(LOCAL_DEVICE_INFO), ! 612: &DeviceName, ! 613: DeviceInit->Type, ! 614: 0, ! 615: FALSE, // Non-Exclusive ! 616: ppDevObj ! 617: ); ! 618: ! 619: if (NT_SUCCESS(Status)) { ! 620: dprintf2(("Created device %d", DeviceNumber)); ! 621: ! 622: // ! 623: // Set up the rest of the device stuff ! 624: // ! 625: ! 626: (*ppDevObj)->Flags |= DeviceInit->IoMethod; ! 627: (*ppDevObj)->AlignmentRequirement = FILE_BYTE_ALIGNMENT; ! 628: ! 629: if (DeviceInit->DeferredRoutine) { ! 630: IoInitializeDpcRequest((*ppDevObj), DeviceInit->DeferredRoutine); ! 631: } ! 632: ! 633: pLDI = (*ppDevObj)->DeviceExtension; ! 634: RtlZeroMemory(pLDI, sizeof(*pLDI)); ! 635: ! 636: // ! 637: // Try to create a symbolic link object for this device ! 638: // ! 639: // No security ! 640: // ! 641: // We make (eg) ! 642: // \DosDevices\WaveOut0 ! 643: // Point to ! 644: // \Device\WaveOut0 ! 645: // ! 646: ! 647: { ! 648: UNICODE_STRING LinkObject; ! 649: WCHAR LinkName[80]; ! 650: ULONG DeviceSize; ! 651: ! 652: LinkName[0] = UNICODE_NULL; ! 653: ! 654: RtlInitUnicodeString(&LinkObject, LinkName); ! 655: ! 656: LinkObject.MaximumLength = sizeof(LinkName); ! 657: ! 658: RtlAppendUnicodeToString(&LinkObject, L"\\DosDevices"); ! 659: ! 660: DeviceSize = sizeof(L"\\Device") - sizeof(UNICODE_NULL); ! 661: DeviceName.Buffer += DeviceSize / sizeof(WCHAR); ! 662: DeviceName.Length -= DeviceSize; ! 663: ! 664: RtlAppendUnicodeStringToString(&LinkObject, &DeviceName); ! 665: ! 666: DeviceName.Buffer -= DeviceSize / sizeof(WCHAR); ! 667: DeviceName.Length += DeviceSize; ! 668: ! 669: Status = IoCreateSymbolicLink(&LinkObject, &DeviceName); ! 670: ! 671: if (!NT_SUCCESS(Status)) { ! 672: dprintf1(("Failed to create symbolic link object")); ! 673: IoDeleteDevice(*ppDevObj); ! 674: *ppDevObj = NULL; ! 675: return Status; ! 676: } ! 677: } ! 678: ! 679: // ! 680: // Fill in the rest of the device information ! 681: // ! 682: ! 683: #ifdef VOLUME_NOTIFY ! 684: InitializeListHead(&pLDI->VolumeQueue); ! 685: #endif // VOLUME_NOTIFY ! 686: ! 687: pLDI->DeviceNumber = DeviceNumber; ! 688: pLDI->DeviceInit = DeviceInit; ! 689: pLDI->CreationFlags = CreationFlags; ! 690: ! 691: pLDI->Key = *(PULONG)DeviceInit->Key; ! 692: pLDI->DeviceType = DeviceInit->DeviceType; ! 693: pLDI->DeviceIndex = (UCHAR)i; ! 694: pLDI->pGlobalInfo = pGDI; ! 695: pLDI->DeviceSpecificData = DeviceSpecificData; ! 696: pLDI->HwContext = pHw; ! 697: ! 698: return STATUS_SUCCESS; ! 699: } ! 700: } ! 701: // ! 702: // Failed ! ! 703: // ! 704: ! 705: return STATUS_INSUFFICIENT_RESOURCES; ! 706: } ! 707: ! 708: ! 709: ! 710: ! 711: PUCHAR ! 712: SoundMapPortAddress( ! 713: INTERFACE_TYPE BusType, ! 714: ULONG BusNumber, ! 715: ULONG PortBase, ! 716: ULONG Length, ! 717: PULONG MemType ! 718: ) ! 719: /*++ ! 720: ! 721: Routine Description : ! 722: ! 723: Map a physical device port address to an address we can pass ! 724: to READ/WRITE_PORT_UCHAR/USHORT etc ! 725: ! 726: Arguments : ! 727: BusType - type of bus ! 728: BusNumber - bus number ! 729: PortBase - The port start address ! 730: Length - how many bytes of port space to map (needed by MmMapIoSpace) ! 731: ! 732: Return Value : ! 733: ! 734: The virtual port address ! 735: ! 736: --*/ ! 737: { ! 738: PHYSICAL_ADDRESS PortAddress; ! 739: PHYSICAL_ADDRESS MappedAddress; ! 740: ! 741: *MemType = 1; // IO space ! 742: PortAddress.LowPart = PortBase; ! 743: PortAddress.HighPart = 0; ! 744: HalTranslateBusAddress( ! 745: BusType, ! 746: BusNumber, ! 747: PortAddress, ! 748: MemType, ! 749: &MappedAddress); ! 750: ! 751: if (*MemType == 0) { ! 752: // ! 753: // Map memory type IO space into our address space ! 754: // ! 755: return (PUCHAR)MmMapIoSpace(MappedAddress, Length, FALSE); ! 756: } else { ! 757: return (PUCHAR)MappedAddress.LowPart; ! 758: } ! 759: } ! 760: ! 761: ! 762: ! 763: NTSTATUS ! 764: SoundConnectInterrupt( ! 765: IN ULONG InterruptNumber, ! 766: IN INTERFACE_TYPE BusType, ! 767: IN ULONG BusNumber, ! 768: IN PKSERVICE_ROUTINE Isr, ! 769: IN PVOID ServiceContext, ! 770: IN KINTERRUPT_MODE InterruptMode, ! 771: IN BOOLEAN ShareVector, ! 772: OUT PKINTERRUPT *Interrupt ! 773: ) ! 774: /*++ ! 775: ! 776: Routine Description : ! 777: ! 778: Connect to an interrupt. From this point on our interrupt service ! 779: routine can receive interrupts ! 780: ! 781: We assume that floating point arithmetic will not be used in the ! 782: service routine. ! 783: ! 784: Arguments : ! 785: ! 786: InterruptNumber - the interrupt number we're using ! 787: BusType - Our bus type ! 788: BusNumber - the number of our buse (of type BusType) ! 789: Isr - the interrupt service routine ! 790: ServiceContext - a value passed to the interrupt service routine ! 791: InterruptMode - whether it's latched or level sensitive ! 792: ShareVector - whether the interrupt can be shared ! 793: Interrupt - Returns the pointer to the interrupt object ! 794: ! 795: Return Value : ! 796: ! 797: An NTSTATUS return value - STATUS_SUCCESS if OK. ! 798: ! 799: --*/ ! 800: { ! 801: KAFFINITY Affinity; ! 802: KIRQL InterruptRequestLevel; ! 803: ULONG InterruptVector; ! 804: NTSTATUS Status; ! 805: ! 806: // ! 807: // Call HalGetInterruptVector to get the interrupt vector, ! 808: // processor affinity and request level to pass to IoConnectInterrupt ! 809: // ! 810: ! 811: InterruptVector = HalGetInterruptVector(Isa, ! 812: BusNumber, ! 813: InterruptNumber, ! 814: InterruptNumber, ! 815: &InterruptRequestLevel, ! 816: &Affinity); ! 817: ! 818: ! 819: Status = IoConnectInterrupt( ! 820: Interrupt, ! 821: Isr, ! 822: ServiceContext, ! 823: (PKSPIN_LOCK)NULL, ! 824: InterruptVector, ! 825: InterruptRequestLevel, ! 826: InterruptRequestLevel, ! 827: InterruptMode, ! 828: ShareVector, ! 829: Affinity, ! 830: FALSE // No floating point save ! 831: ); ! 832: ! 833: return Status == STATUS_INVALID_PARAMETER ? ! 834: STATUS_DEVICE_CONFIGURATION_ERROR : Status; ! 835: } ! 836: ! 837: ! 838: ! 839: NTSTATUS ! 840: SoundSetErrorCode( ! 841: IN PWSTR RegistryPath, ! 842: IN ULONG Value ! 843: ) ! 844: /*++ ! 845: ! 846: Routine Description : ! 847: ! 848: Write the given DWORD into the registry using the path ! 849: with a value name of SOUND_REG_CONFIGERROR ! 850: ! 851: Arguments : ! 852: ! 853: RegistryPath- path to registry key ! 854: ! 855: Value - value to store ! 856: ! 857: Return Value : ! 858: ! 859: NTSTATUS code ! 860: ! 861: --*/ ! 862: { ! 863: return SoundWriteRegistryDWORD(RegistryPath, SOUND_REG_CONFIGERROR, Value); ! 864: } ! 865: ! 866: ! 867: NTSTATUS ! 868: SoundWriteRegistryDWORD( ! 869: IN PWSTR RegistryPath, ! 870: IN PWSTR ValueName, ! 871: IN ULONG Value ! 872: ) ! 873: /*++ ! 874: ! 875: Routine Description : ! 876: ! 877: Write the given DWORD into the registry using the path and ! 878: value name supplied by calling RtlWriteRegistryValue ! 879: ! 880: Arguments : ! 881: ! 882: RegistryPath- path to registry key ! 883: ! 884: ValueName - name of value to write ! 885: ! 886: Value - value to store ! 887: ! 888: Return Value : ! 889: ! 890: NTSTATUS code ! 891: ! 892: --*/ ! 893: { ! 894: NTSTATUS Status; ! 895: ! 896: Status = RtlWriteRegistryValue( ! 897: RTL_REGISTRY_ABSOLUTE, ! 898: RegistryPath, ! 899: ValueName, ! 900: REG_DWORD, ! 901: &Value, ! 902: sizeof(Value)); ! 903: ! 904: if (!NT_SUCCESS(Status)) { ! 905: dprintf1(("Writing parameter %ls to registry failed status %8X", ! 906: ValueName, Status)); ! 907: } ! 908: ! 909: return Status; ! 910: } ! 911: ! 912: ! 913: VOID ! 914: SoundDelay( ! 915: IN ULONG Milliseconds ! 916: ) ! 917: /*++ ! 918: ! 919: Routine Description : ! 920: ! 921: Stall the current thread for the given number of milliseconds AT LEAST ! 922: ! 923: Arguments : ! 924: ! 925: Milliseconds - number of milliseconds to delay ! 926: ! 927: Return Value : ! 928: ! 929: None ! 930: ! 931: --*/ ! 932: { ! 933: LARGE_INTEGER Delay; ! 934: ! 935: // ! 936: // Can't call SoundDelay() from high irql ! 937: // ! 938: ! 939: if (KeGetCurrentIrql() >= DISPATCH_LEVEL) { ! 940: return; ! 941: } ! 942: ! 943: // ! 944: // First a tiny delay to synch us up with the timer otherwise we ! 945: // may wait up to 15ms less time than we expected! ! 946: // ! 947: ! 948: Delay = RtlConvertLongToLargeInteger(-1); ! 949: ! 950: KeDelayExecutionThread(KernelMode, ! 951: FALSE, // Not alertable ! 952: &Delay); ! 953: ! 954: Delay = RtlConvertLongToLargeInteger((-(LONG)Milliseconds) * 10000); ! 955: ! 956: KeDelayExecutionThread(KernelMode, ! 957: FALSE, // Not alertable ! 958: &Delay); ! 959: } ! 960: ! 961: ! 962: LARGE_INTEGER ! 963: SoundGetTime( ! 964: VOID ! 965: ) ! 966: /*++ ! 967: ! 968: Routine Description: ! 969: ! 970: Get an accurate estimate of the current time by calling ! 971: KeQueryPerformanceCounter and converting the result to 100ns units ! 972: ! 973: Arguments: ! 974: ! 975: ErrorText - text of message ! 976: ! 977: Return Value: ! 978: ! 979: --*/ ! 980: { ! 981: static LARGE_INTEGER StartTime100ns, StartTimeTicks, TicksPerSecond; ! 982: static BOOLEAN Initialized; ! 983: static ULONG Multiplier; ! 984: ULONG Remainder; ! 985: ! 986: if (!Initialized) { ! 987: ! 988: Initialized = TRUE; ! 989: ! 990: KeQuerySystemTime(&StartTime100ns); ! 991: StartTimeTicks = KeQueryPerformanceCounter(&TicksPerSecond); ! 992: ! 993: Multiplier = 10000000; ! 994: ! 995: while (TicksPerSecond.HighPart != 0) { ! 996: Multiplier = Multiplier / 10; ! 997: TicksPerSecond = ! 998: RtlExtendedLargeIntegerDivide(TicksPerSecond, 10, &Remainder); ! 999: } ! 1000: } ! 1001: ! 1002: // ! 1003: // Convert ticks to 100ns units (and hope we don't overflow!) ! 1004: // ! 1005: ! 1006: return RtlLargeIntegerAdd( ! 1007: RtlExtendedLargeIntegerDivide( ! 1008: RtlExtendedIntegerMultiply( ! 1009: RtlLargeIntegerSubtract( ! 1010: KeQueryPerformanceCounter(NULL), ! 1011: StartTimeTicks ! 1012: ), ! 1013: Multiplier ! 1014: ), ! 1015: TicksPerSecond.LowPart, ! 1016: &Remainder ! 1017: ), ! 1018: StartTime100ns ! 1019: ); ! 1020: } ! 1021: ! 1022: ! 1023: ! 1024: VOID ! 1025: SoundFreeQ( ! 1026: PLIST_ENTRY ListHead, ! 1027: NTSTATUS IoStatus ! 1028: ) ! 1029: /*++ ! 1030: ! 1031: Routine Description: ! 1032: ! 1033: Free a list of Irps - setting the specified status and completing ! 1034: them. The list will be empty on exit. ! 1035: ! 1036: Arguments: ! 1037: ! 1038: pListNode - the list to free ! 1039: IoStatus - the status to set in each Irp. ! 1040: ! 1041: Return Value: ! 1042: ! 1043: None. ! 1044: ! 1045: --*/ ! 1046: { ! 1047: // ! 1048: // Remove all the queue entries, completing all ! 1049: // the Irps represented by the entries ! 1050: // ! 1051: ! 1052: for (;;) { ! 1053: PIRP pIrp; ! 1054: ! 1055: // ! 1056: // The queue may be cancellable so use our routine to get the Irp ! 1057: // ! 1058: ! 1059: pIrp = SoundRemoveFromCancellableQ(ListHead); ! 1060: ! 1061: if (pIrp == NULL) { ! 1062: break; ! 1063: } ! 1064: ! 1065: pIrp->IoStatus.Status = IoStatus; ! 1066: ! 1067: // ! 1068: // Bump priority here because the application may still be trying ! 1069: // to be real-time ! 1070: // ! 1071: IoCompleteRequest(pIrp, IO_SOUND_INCREMENT); ! 1072: } ! 1073: } ! 1074: ! 1075: ! 1076: VOID ! 1077: SoundRemoveAndComplete( ! 1078: PDEVICE_OBJECT pDO, ! 1079: PIRP Irp ! 1080: ) ! 1081: /*++ ! 1082: ! 1083: Routine Description: ! 1084: ! 1085: Removes the Irp from any queue it's on ! 1086: Completes it as cancelled. ! 1087: ! 1088: Arguments: ! 1089: ! 1090: Irp - the Irp ! 1091: Cancellable - If it is to be made cancellable ! 1092: ! 1093: Return Value: ! 1094: ! 1095: None. ! 1096: ! 1097: Notes: ! 1098: ! 1099: This routine is called with the cancel spin lock held ! 1100: ! 1101: --*/ ! 1102: { ! 1103: dprintf2(("Cancelling Irp from cancel routine")); ! 1104: ! 1105: // ! 1106: // Remove the Irp from the queue ! 1107: // ! 1108: ! 1109: RemoveEntryList(&Irp->Tail.Overlay.ListEntry); ! 1110: ! 1111: // ! 1112: // Release the cancel spin lock ! 1113: // ! 1114: ! 1115: IoReleaseCancelSpinLock(Irp->CancelIrql); ! 1116: ! 1117: // ! 1118: // Set status and complete ! 1119: // ! 1120: ! 1121: Irp->IoStatus.Status = STATUS_CANCELLED; ! 1122: ! 1123: IoCompleteRequest(Irp, IO_NO_INCREMENT); ! 1124: } ! 1125: ! 1126: ! 1127: ! 1128: VOID ! 1129: SoundAddIrpToCancellableQ( ! 1130: PLIST_ENTRY QueueHead, ! 1131: PIRP Irp, ! 1132: BOOLEAN Head ! 1133: ) ! 1134: /*++ ! 1135: ! 1136: Routine Description: ! 1137: ! 1138: ! 1139: Add the Irp to the queue and set the cancel routine under the ! 1140: protection of the cancel spin lock. ! 1141: ! 1142: Arguments: ! 1143: ! 1144: QueueHead - the queue to add it to ! 1145: Irp - the Irp ! 1146: Head - if TRUE insert at the head of the queue ! 1147: ! 1148: Return Value: ! 1149: ! 1150: None. ! 1151: ! 1152: --*/ ! 1153: { ! 1154: KIRQL OldIrql; ! 1155: ! 1156: // ! 1157: // Get the cancel spin lock so we can mess with the cancel stuff ! 1158: // ! 1159: ! 1160: IoAcquireCancelSpinLock(&OldIrql); ! 1161: ! 1162: // ! 1163: // Well, it may ALREADY be cancelled! ! 1164: // ! 1165: ! 1166: if (Irp->Cancel) { ! 1167: ! 1168: dprintf2(("Irp already cancelled")); ! 1169: ! 1170: // ! 1171: // Release the cancel spin lock ! 1172: // ! 1173: ! 1174: IoReleaseCancelSpinLock(OldIrql); ! 1175: ! 1176: // ! 1177: // Set status and complete ! 1178: // ! 1179: ! 1180: Irp->IoStatus.Status = STATUS_CANCELLED; ! 1181: ! 1182: IoCompleteRequest(Irp, IO_NO_INCREMENT); ! 1183: return; ! 1184: } ! 1185: ! 1186: // ! 1187: // Set the cancel routine ! 1188: // ! 1189: ! 1190: IoSetCancelRoutine(Irp, SoundRemoveAndComplete); ! 1191: ! 1192: // ! 1193: // Insert it in the queue ! 1194: // ! 1195: ! 1196: if (Head) { ! 1197: InsertHeadList(QueueHead, &Irp->Tail.Overlay.ListEntry); ! 1198: } else { ! 1199: InsertTailList(QueueHead, &Irp->Tail.Overlay.ListEntry); ! 1200: } ! 1201: ! 1202: // ! 1203: // Free the spin lock ! 1204: // ! 1205: ! 1206: IoReleaseCancelSpinLock(OldIrql); ! 1207: } ! 1208: ! 1209: ! 1210: PIRP ! 1211: SoundRemoveFromCancellableQ( ! 1212: PLIST_ENTRY QueueHead ! 1213: ) ! 1214: /*++ ! 1215: ! 1216: Routine Description: ! 1217: ! 1218: ! 1219: Remove the Irp to the queue and remove the cancel routine under the ! 1220: protection of the cancel spin lock. ! 1221: ! 1222: Arguments: ! 1223: ! 1224: QueueHead - the queue to remove it from ! 1225: ! 1226: Return Value: ! 1227: ! 1228: The Irp at the head of the queue or NULL if the queue is empty. ! 1229: ! 1230: --*/ ! 1231: { ! 1232: KIRQL OldIrql; ! 1233: PIRP Irp; ! 1234: LIST_ENTRY ListNode; ! 1235: ! 1236: // ! 1237: // Get the cancel spin lock so we can mess with the cancel stuff ! 1238: // ! 1239: ! 1240: IoAcquireCancelSpinLock(&OldIrql); ! 1241: ! 1242: ! 1243: if (IsListEmpty(QueueHead)) { ! 1244: Irp = NULL; ! 1245: } else { ! 1246: ! 1247: PLIST_ENTRY ListNode; ! 1248: ListNode = RemoveHeadList(QueueHead); ! 1249: Irp = CONTAINING_RECORD(ListNode, IRP, Tail.Overlay.ListEntry); ! 1250: ! 1251: // ! 1252: // Remove the cancel routine ! 1253: // ! 1254: ! 1255: IoSetCancelRoutine(Irp, NULL); ! 1256: } ! 1257: ! 1258: // ! 1259: // Free the spin lock ! 1260: // ! 1261: ! 1262: IoReleaseCancelSpinLock(OldIrql); ! 1263: ! 1264: // ! 1265: // Return IRP (if any) ! 1266: // ! 1267: ! 1268: return Irp; ! 1269: } ! 1270: ! 1271: ! 1272: ! 1273: NTSTATUS ! 1274: SoundSaveRegistryPath( ! 1275: IN PUNICODE_STRING RegistryPathName, ! 1276: OUT PWSTR *SavedString ! 1277: ) ! 1278: /*++ ! 1279: ! 1280: Routine Description: ! 1281: ! 1282: Save the driver's registry path, appending the 'Parameters' key. ! 1283: ! 1284: NOTE this registry path must only be accessed BELOW dispatch level ! 1285: as the save area is allocated from paged pool. ! 1286: ! 1287: The caller must free the unicode string buffer if the driver unloads. ! 1288: ! 1289: Arguments: ! 1290: ! 1291: RegistryPathName - Our driver's registry entry ! 1292: SavedString - Saved version of RegistryPathName with the 'Parameters' ! 1293: subkey string appended ! 1294: ! 1295: Return Value: ! 1296: ! 1297: NTSTATUS code ! 1298: ! 1299: --*/ ! 1300: { ! 1301: int Length; ! 1302: ! 1303: ASSERT(*SavedString == NULL); ! 1304: ! 1305: Length = ! 1306: RegistryPathName->Length + sizeof(PARMS_SUBKEY) + ! 1307: sizeof(UNICODE_NULL); // Include backslash ! 1308: ! 1309: ! 1310: *SavedString = ! 1311: ExAllocatePool(PagedPool, Length); // Only access on caller thread ! 1312: ! 1313: if (*SavedString == NULL) { ! 1314: return STATUS_INSUFFICIENT_RESOURCES; ! 1315: } ! 1316: ! 1317: // ! 1318: // Copy the character data ! 1319: // ! 1320: ! 1321: RtlCopyMemory(*SavedString, RegistryPathName->Buffer, ! 1322: RegistryPathName->Length); ! 1323: ! 1324: (*SavedString)[RegistryPathName->Length / sizeof(WCHAR)] = L'\\'; ! 1325: (*SavedString)[RegistryPathName->Length / sizeof(WCHAR) + 1] = UNICODE_NULL; ! 1326: ! 1327: // ! 1328: // Append the parameters suffix prepended by a backslash ! 1329: // ! 1330: ! 1331: wcscat(*SavedString, PARMS_SUBKEY); ! 1332: ! 1333: return STATUS_SUCCESS; ! 1334: } ! 1335: ! 1336: ! 1337: VOID ! 1338: SoundFlushRegistryKey( ! 1339: IN PWSTR RegistryPathName ! 1340: ) ! 1341: /*++ ! 1342: ! 1343: Routine Description: ! 1344: ! 1345: Flush a key - usually the driver's parameters key - ! 1346: used mainly to save volume settings. ! 1347: ! 1348: Arguments: ! 1349: ! 1350: RegistryPathName - Our driver's parameters registry entry ! 1351: ! 1352: Return Value: ! 1353: ! 1354: None ! 1355: ! 1356: --*/ ! 1357: { ! 1358: ! 1359: HANDLE KeyHandle; ! 1360: OBJECT_ATTRIBUTES ObjectAttributes; ! 1361: UNICODE_STRING RegistryPathString; ! 1362: ! 1363: RtlInitUnicodeString(&RegistryPathString, RegistryPathName); ! 1364: ! 1365: InitializeObjectAttributes(&ObjectAttributes, ! 1366: &RegistryPathString, ! 1367: OBJ_CASE_INSENSITIVE, ! 1368: NULL, ! 1369: (PSECURITY_DESCRIPTOR)NULL); ! 1370: ! 1371: // ! 1372: // Just open the key and flush it. Not much we can do if this ! 1373: // fails. ! 1374: // ! 1375: ! 1376: if (NT_SUCCESS(ZwOpenKey(&KeyHandle, ! 1377: KEY_WRITE, ! 1378: &ObjectAttributes))) { ! 1379: ZwFlushKey(KeyHandle); ! 1380: ZwClose(KeyHandle); ! 1381: } else { ! 1382: dprintf1(("Could not open device's key for flushing")); ! 1383: } ! 1384: } ! 1385: ! 1386: #if 0 ! 1387: ! 1388: VOID ! 1389: SoundRaiseHardError( ! 1390: PWSTR ErrorText ! 1391: ) ! 1392: /*++ ! 1393: ! 1394: Routine Description: ! 1395: ! 1396: Cause a pop-up - note this doesn't seem to work! ! 1397: ! 1398: Arguments: ! 1399: ! 1400: ErrorText - text of message ! 1401: ! 1402: Return Value: ! 1403: ! 1404: None ! 1405: ! 1406: --*/ ! 1407: { ! 1408: UNICODE_STRING String; ! 1409: RtlInitUnicodeString(&String, ErrorText); ! 1410: IoRaiseInformationalHardError(STATUS_SUCCESS, ! 1411: &String, ! 1412: NULL); ! 1413: } ! 1414: #endif ! 1415: ! 1416: ! 1417: #if DBG ! 1418: ! 1419: char *DriverName = "Unknown Sound Driver"; ! 1420: ULONG SoundDebugLevel = 1; ! 1421: ! 1422: void dDbgOut(char * szFormat, ...) ! 1423: { ! 1424: char buf[256]; ! 1425: va_list va; ! 1426: ! 1427: va_start(va, szFormat); ! 1428: vsprintf(buf, szFormat, va); ! 1429: va_end(va); ! 1430: DbgPrint("SOUND: %s\n", buf); ! 1431: } ! 1432: ! 1433: #endif // DBG ! 1434: ! 1435: ! 1436:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.