[NTOS:MM] Implement and use MiAcquirePfnLockAtDpcLevel/MiReleasePfnLockFromDpcLevel.
[reactos.git] / drivers / serial / serenum / misc.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Serial enumerator driver
4 * FILE: drivers/dd/serenum/misc.c
5 * PURPOSE: Miscellaneous operations
6 *
7 * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.com)
8 */
9
10 #include "serenum.h"
11
12 #include <debug.h>
13
14 static IO_COMPLETION_ROUTINE ForwardIrpAndWaitCompletion;
15
16 /* I really want PCSZ strings as last arguments because
17 * PnP ids are ANSI-encoded in PnP device string
18 * identification */
19 NTSTATUS
20 SerenumInitMultiSzString(
21 OUT PUNICODE_STRING Destination,
22 ... /* list of PCSZ */)
23 {
24 va_list args;
25 PCSZ Source;
26 ANSI_STRING AnsiString;
27 UNICODE_STRING UnicodeString;
28 ULONG DestinationSize = 0;
29 NTSTATUS Status = STATUS_SUCCESS;
30
31 ASSERT(Destination);
32
33 /* Calculate length needed for destination unicode string */
34 va_start(args, Destination);
35 Source = va_arg(args, PCSZ);
36 while (Source != NULL)
37 {
38 RtlInitAnsiString(&AnsiString, Source);
39 DestinationSize += RtlAnsiStringToUnicodeSize(&AnsiString)
40 + sizeof(WCHAR) /* final NULL */;
41 Source = va_arg(args, PCSZ);
42 }
43 va_end(args);
44 if (DestinationSize == 0)
45 {
46 RtlInitUnicodeString(Destination, NULL);
47 return STATUS_SUCCESS;
48 }
49
50 /* Initialize destination string */
51 DestinationSize += sizeof(WCHAR); // final NULL
52 Destination->Buffer = (PWSTR)ExAllocatePoolWithTag(PagedPool, DestinationSize, SERENUM_TAG);
53 if (!Destination->Buffer)
54 return STATUS_INSUFFICIENT_RESOURCES;
55 Destination->Length = 0;
56 Destination->MaximumLength = (USHORT)DestinationSize;
57
58 /* Copy arguments to destination string */
59 /* Use a temporary unicode string, which buffer is shared with
60 * destination string, to copy arguments */
61 UnicodeString.Length = Destination->Length;
62 UnicodeString.MaximumLength = Destination->MaximumLength;
63 UnicodeString.Buffer = Destination->Buffer;
64 va_start(args, Destination);
65 Source = va_arg(args, PCSZ);
66 while (Source != NULL)
67 {
68 RtlInitAnsiString(&AnsiString, Source);
69 Status = RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, FALSE);
70 if (!NT_SUCCESS(Status))
71 {
72 ExFreePoolWithTag(Destination->Buffer, SERENUM_TAG);
73 break;
74 }
75 Destination->Length += UnicodeString.Length + sizeof(WCHAR);
76 UnicodeString.MaximumLength -= UnicodeString.Length + sizeof(WCHAR);
77 UnicodeString.Buffer += UnicodeString.Length / sizeof(WCHAR) + 1;
78 UnicodeString.Length = 0;
79 Source = va_arg(args, PCSZ);
80 }
81 va_end(args);
82 if (NT_SUCCESS(Status))
83 {
84 /* Finish multi-sz string */
85 Destination->Buffer[Destination->Length / sizeof(WCHAR)] = L'\0';
86 Destination->Length += sizeof(WCHAR);
87 }
88 return Status;
89 }
90
91 static NTSTATUS NTAPI
92 ForwardIrpAndWaitCompletion(
93 IN PDEVICE_OBJECT DeviceObject,
94 IN PIRP Irp,
95 IN PVOID Context)
96 {
97 if (Irp->PendingReturned)
98 KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
99 return STATUS_MORE_PROCESSING_REQUIRED;
100 }
101
102 NTSTATUS
103 ForwardIrpAndWait(
104 IN PDEVICE_OBJECT DeviceObject,
105 IN PIRP Irp)
106 {
107 PDEVICE_OBJECT LowerDevice;
108 KEVENT Event;
109 NTSTATUS Status;
110
111 ASSERT(((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsFDO);
112 LowerDevice = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
113
114 ASSERT(LowerDevice);
115
116 KeInitializeEvent(&Event, NotificationEvent, FALSE);
117 IoCopyCurrentIrpStackLocationToNext(Irp);
118
119 TRACE_(SERENUM, "Calling lower device %p\n", LowerDevice);
120 IoSetCompletionRoutine(Irp, ForwardIrpAndWaitCompletion, &Event, TRUE, TRUE, TRUE);
121
122 Status = IoCallDriver(LowerDevice, Irp);
123 if (Status == STATUS_PENDING)
124 {
125 Status = KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
126 if (NT_SUCCESS(Status))
127 Status = Irp->IoStatus.Status;
128 }
129
130 return Status;
131 }
132
133 NTSTATUS NTAPI
134 ForwardIrpToLowerDeviceAndForget(
135 IN PDEVICE_OBJECT DeviceObject,
136 IN PIRP Irp)
137 {
138 PFDO_DEVICE_EXTENSION DeviceExtension;
139 PDEVICE_OBJECT LowerDevice;
140
141 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
142 ASSERT(DeviceExtension->Common.IsFDO);
143
144 LowerDevice = DeviceExtension->LowerDevice;
145 ASSERT(LowerDevice);
146 TRACE_(SERENUM, "Calling lower device 0x%p\n", LowerDevice);
147 IoSkipCurrentIrpStackLocation(Irp);
148 return IoCallDriver(LowerDevice, Irp);
149 }
150
151 NTSTATUS NTAPI
152 ForwardIrpToAttachedFdoAndForget(
153 IN PDEVICE_OBJECT DeviceObject,
154 IN PIRP Irp)
155 {
156 PPDO_DEVICE_EXTENSION DeviceExtension;
157 PDEVICE_OBJECT Fdo;
158
159 DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
160 ASSERT(!DeviceExtension->Common.IsFDO);
161
162 Fdo = DeviceExtension->AttachedFdo;
163 ASSERT(Fdo);
164 TRACE_(SERENUM, "Calling attached Fdo 0x%p\n", Fdo);
165 IoSkipCurrentIrpStackLocation(Irp);
166 return IoCallDriver(Fdo, Irp);
167 }
168
169 NTSTATUS NTAPI
170 ForwardIrpAndForget(
171 IN PDEVICE_OBJECT DeviceObject,
172 IN PIRP Irp)
173 {
174 PDEVICE_OBJECT LowerDevice;
175
176 ASSERT(((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsFDO);
177 LowerDevice = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
178 ASSERT(LowerDevice);
179
180 IoSkipCurrentIrpStackLocation(Irp);
181 return IoCallDriver(LowerDevice, Irp);
182 }
183
184 NTSTATUS
185 DuplicateUnicodeString(
186 IN ULONG Flags,
187 IN PCUNICODE_STRING SourceString,
188 OUT PUNICODE_STRING DestinationString)
189 {
190 if (SourceString == NULL || DestinationString == NULL
191 || SourceString->Length > SourceString->MaximumLength
192 || (SourceString->Length == 0 && SourceString->MaximumLength > 0 && SourceString->Buffer == NULL)
193 || Flags == RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING || Flags >= 4)
194 {
195 return STATUS_INVALID_PARAMETER;
196 }
197
198
199 if ((SourceString->Length == 0)
200 && (Flags != (RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE |
201 RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING)))
202 {
203 DestinationString->Length = 0;
204 DestinationString->MaximumLength = 0;
205 DestinationString->Buffer = NULL;
206 }
207 else
208 {
209 USHORT DestMaxLength = SourceString->Length;
210
211 if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
212 DestMaxLength += sizeof(UNICODE_NULL);
213
214 DestinationString->Buffer = ExAllocatePoolWithTag(PagedPool, DestMaxLength, SERENUM_TAG);
215 if (DestinationString->Buffer == NULL)
216 return STATUS_NO_MEMORY;
217
218 RtlCopyMemory(DestinationString->Buffer, SourceString->Buffer, SourceString->Length);
219 DestinationString->Length = SourceString->Length;
220 DestinationString->MaximumLength = DestMaxLength;
221
222 if (Flags & RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE)
223 DestinationString->Buffer[DestinationString->Length / sizeof(WCHAR)] = 0;
224 }
225
226 return STATUS_SUCCESS;
227 }