|
|
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.