Annotation of ntddk/src/mmedia/soundlib/soundlib.c, revision 1.1.1.1

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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.