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