[STORPORT] Fix resource list size calculation
[reactos.git] / drivers / storage / port / storport / misc.c
1 /*
2 * PROJECT: ReactOS Storport Driver
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Storport helper functions
5 * COPYRIGHT: Copyright 2017 Eric Kohl (eric.kohl@reactos.org)
6 */
7
8 /* INCLUDES *******************************************************************/
9
10 #include "precomp.h"
11
12 #define NDEBUG
13 #include <debug.h>
14
15
16 /* FUNCTIONS ******************************************************************/
17
18 static
19 NTSTATUS
20 NTAPI
21 ForwardIrpAndWaitCompletion(
22 _In_ PDEVICE_OBJECT DeviceObject,
23 _In_ PIRP Irp,
24 _In_ PVOID Context)
25 {
26 if (Irp->PendingReturned)
27 KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
28 return STATUS_MORE_PROCESSING_REQUIRED;
29 }
30
31
32 NTSTATUS
33 ForwardIrpAndWait(
34 _In_ PDEVICE_OBJECT LowerDevice,
35 _In_ PIRP Irp)
36 {
37 KEVENT Event;
38 NTSTATUS Status;
39
40 ASSERT(LowerDevice);
41
42 KeInitializeEvent(&Event, NotificationEvent, FALSE);
43 IoCopyCurrentIrpStackLocationToNext(Irp);
44
45 IoSetCompletionRoutine(Irp, ForwardIrpAndWaitCompletion, &Event, TRUE, TRUE, TRUE);
46
47 Status = IoCallDriver(LowerDevice, Irp);
48 if (Status == STATUS_PENDING)
49 {
50 Status = KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
51 if (NT_SUCCESS(Status))
52 Status = Irp->IoStatus.Status;
53 }
54
55 return Status;
56 }
57
58
59 NTSTATUS
60 NTAPI
61 ForwardIrpAndForget(
62 _In_ PDEVICE_OBJECT LowerDevice,
63 _In_ PIRP Irp)
64 {
65 ASSERT(LowerDevice);
66
67 IoSkipCurrentIrpStackLocation(Irp);
68 return IoCallDriver(LowerDevice, Irp);
69 }
70
71
72 INTERFACE_TYPE
73 GetBusInterface(
74 PDEVICE_OBJECT DeviceObject)
75 {
76 GUID Guid;
77 ULONG Length;
78 NTSTATUS Status;
79
80 Status = IoGetDeviceProperty(DeviceObject,
81 DevicePropertyBusTypeGuid,
82 sizeof(Guid),
83 &Guid,
84 &Length);
85 if (!NT_SUCCESS(Status))
86 return InterfaceTypeUndefined;
87
88 if (RtlCompareMemory(&Guid, &GUID_BUS_TYPE_PCMCIA, sizeof(GUID)) == sizeof(GUID))
89 return PCMCIABus;
90 else if (RtlCompareMemory(&Guid, &GUID_BUS_TYPE_PCI, sizeof(GUID)) == sizeof(GUID))
91 return PCIBus;
92 else if (RtlCompareMemory(&Guid, &GUID_BUS_TYPE_ISAPNP, sizeof(GUID)) == sizeof(GUID))
93 return PNPISABus;
94
95 return InterfaceTypeUndefined;
96 }
97
98
99 static
100 ULONG
101 GetResourceListSize(
102 PCM_RESOURCE_LIST ResourceList)
103 {
104 PCM_FULL_RESOURCE_DESCRIPTOR Descriptor;
105 ULONG Size;
106
107 DPRINT1("GetResourceListSize(%p)\n", ResourceList);
108
109 Size = sizeof(CM_RESOURCE_LIST);
110 if (ResourceList->Count == 0)
111 {
112 DPRINT1("Size: 0x%lx (%u)\n", Size, Size);
113 return Size;
114 }
115
116 DPRINT1("ResourceList->Count: %lu\n", ResourceList->Count);
117
118 Descriptor = &ResourceList->List[0];
119
120 DPRINT1("PartialResourceList->Count: %lu\n", Descriptor->PartialResourceList.Count);
121
122 /* Add the size of the partial descriptors */
123 if (Descriptor->PartialResourceList.Count > 1)
124 Size += (Descriptor->PartialResourceList.Count - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
125
126 DPRINT1("Size: 0x%lx (%u)\n", Size, Size);
127 return Size;
128 }
129
130
131 PCM_RESOURCE_LIST
132 CopyResourceList(
133 POOL_TYPE PoolType,
134 PCM_RESOURCE_LIST Source)
135 {
136 PCM_RESOURCE_LIST Destination;
137 ULONG Size;
138
139 DPRINT1("CopyResourceList(%lu %p)\n",
140 PoolType, Source);
141
142 /* Get the size of the resource list */
143 Size = GetResourceListSize(Source);
144
145 /* Allocate a new buffer */
146 Destination = ExAllocatePoolWithTag(PoolType,
147 Size,
148 TAG_RESOURCE_LIST);
149 if (Destination == NULL)
150 return NULL;
151
152 /* Copy the resource list */
153 RtlCopyMemory(Destination,
154 Source,
155 Size);
156
157 return Destination;
158 }
159
160
161 NTSTATUS
162 QueryBusInterface(
163 PDEVICE_OBJECT DeviceObject,
164 PGUID Guid,
165 USHORT Size,
166 USHORT Version,
167 PBUS_INTERFACE_STANDARD Interface,
168 PVOID InterfaceSpecificData)
169 {
170 KEVENT Event;
171 NTSTATUS Status;
172 PIRP Irp;
173 IO_STATUS_BLOCK IoStatus;
174 PIO_STACK_LOCATION Stack;
175
176 KeInitializeEvent(&Event, NotificationEvent, FALSE);
177
178 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
179 DeviceObject,
180 NULL,
181 0,
182 NULL,
183 &Event,
184 &IoStatus);
185 if (Irp == NULL)
186 return STATUS_INSUFFICIENT_RESOURCES;
187
188 Stack = IoGetNextIrpStackLocation(Irp);
189
190 Stack->MajorFunction = IRP_MJ_PNP;
191 Stack->MinorFunction = IRP_MN_QUERY_INTERFACE;
192 Stack->Parameters.QueryInterface.InterfaceType = Guid;
193 Stack->Parameters.QueryInterface.Size = Size;
194 Stack->Parameters.QueryInterface.Version = Version;
195 Stack->Parameters.QueryInterface.Interface = (PINTERFACE)Interface;
196 Stack->Parameters.QueryInterface.InterfaceSpecificData = InterfaceSpecificData;
197
198 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
199
200 Status = IoCallDriver(DeviceObject, Irp);
201 if (Status == STATUS_PENDING)
202 {
203 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
204
205 Status=IoStatus.Status;
206 }
207
208 return Status;
209 }
210
211
212 BOOLEAN
213 TranslateResourceListAddress(
214 PFDO_DEVICE_EXTENSION DeviceExtension,
215 INTERFACE_TYPE BusType,
216 ULONG SystemIoBusNumber,
217 STOR_PHYSICAL_ADDRESS IoAddress,
218 ULONG NumberOfBytes,
219 BOOLEAN InIoSpace,
220 PPHYSICAL_ADDRESS TranslatedAddress)
221 {
222 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptorA, FullDescriptorT;
223 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptorA, PartialDescriptorT;
224 INT i, j;
225
226 DPRINT1("TranslateResourceListAddress(%p)\n", DeviceExtension);
227
228 FullDescriptorA = DeviceExtension->AllocatedResources->List;
229 FullDescriptorT = DeviceExtension->TranslatedResources->List;
230 for (i = 0; i < DeviceExtension->AllocatedResources->Count; i++)
231 {
232 for (j = 0; j < FullDescriptorA->PartialResourceList.Count; j++)
233 {
234 PartialDescriptorA = FullDescriptorA->PartialResourceList.PartialDescriptors + j;
235 PartialDescriptorT = FullDescriptorT->PartialResourceList.PartialDescriptors + j;
236
237 switch (PartialDescriptorA->Type)
238 {
239 case CmResourceTypePort:
240 DPRINT1("Port: 0x%I64x (0x%lx)\n",
241 PartialDescriptorA->u.Port.Start.QuadPart,
242 PartialDescriptorA->u.Port.Length);
243 if (InIoSpace &&
244 IoAddress.QuadPart >= PartialDescriptorA->u.Port.Start.QuadPart &&
245 IoAddress.QuadPart + NumberOfBytes <= PartialDescriptorA->u.Port.Start.QuadPart + PartialDescriptorA->u.Port.Length)
246 {
247 TranslatedAddress->QuadPart = PartialDescriptorT->u.Port.Start.QuadPart +
248 (IoAddress.QuadPart - PartialDescriptorA->u.Port.Start.QuadPart);
249 return TRUE;
250 }
251 break;
252
253 case CmResourceTypeMemory:
254 DPRINT1("Memory: 0x%I64x (0x%lx)\n",
255 PartialDescriptorA->u.Memory.Start.QuadPart,
256 PartialDescriptorA->u.Memory.Length);
257 if (!InIoSpace &&
258 IoAddress.QuadPart >= PartialDescriptorA->u.Memory.Start.QuadPart &&
259 IoAddress.QuadPart + NumberOfBytes <= PartialDescriptorA->u.Memory.Start.QuadPart + PartialDescriptorA->u.Memory.Length)
260 {
261 TranslatedAddress->QuadPart = PartialDescriptorT->u.Memory.Start.QuadPart +
262 (IoAddress.QuadPart - PartialDescriptorA->u.Memory.Start.QuadPart);
263 return TRUE;
264 }
265 break;
266 }
267 }
268
269 /* Advance to next CM_FULL_RESOURCE_DESCRIPTOR block in memory. */
270 FullDescriptorA = (PCM_FULL_RESOURCE_DESCRIPTOR)(FullDescriptorA->PartialResourceList.PartialDescriptors +
271 FullDescriptorA->PartialResourceList.Count);
272
273 FullDescriptorT = (PCM_FULL_RESOURCE_DESCRIPTOR)(FullDescriptorT->PartialResourceList.PartialDescriptors +
274 FullDescriptorT->PartialResourceList.Count);
275 }
276
277 return FALSE;
278 }
279
280
281 NTSTATUS
282 GetResourceListInterrupt(
283 PFDO_DEVICE_EXTENSION DeviceExtension,
284 PULONG Vector,
285 PKIRQL Irql,
286 KINTERRUPT_MODE *InterruptMode,
287 PBOOLEAN ShareVector,
288 PKAFFINITY Affinity)
289 {
290 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
291 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
292 INT i, j;
293
294 DPRINT1("GetResourceListInterrupt(%p)\n",
295 DeviceExtension);
296
297 FullDescriptor = DeviceExtension->TranslatedResources->List;
298 for (i = 0; i < DeviceExtension->TranslatedResources->Count; i++)
299 {
300 for (j = 0; j < FullDescriptor->PartialResourceList.Count; j++)
301 {
302 PartialDescriptor = FullDescriptor->PartialResourceList.PartialDescriptors + j;
303
304 switch (PartialDescriptor->Type)
305 {
306 case CmResourceTypeInterrupt:
307 DPRINT1("Interrupt: Level %lu Vector %lu\n",
308 PartialDescriptor->u.Interrupt.Level,
309 PartialDescriptor->u.Interrupt.Vector);
310
311 *Vector = PartialDescriptor->u.Interrupt.Vector;
312 *Irql = (KIRQL)PartialDescriptor->u.Interrupt.Level;
313 *InterruptMode = (PartialDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive;
314 *ShareVector = (PartialDescriptor->ShareDisposition == CmResourceShareShared) ? TRUE : FALSE;
315 *Affinity = PartialDescriptor->u.Interrupt.Affinity;
316
317 return STATUS_SUCCESS;
318 }
319 }
320
321 /* Advance to next CM_FULL_RESOURCE_DESCRIPTOR block in memory. */
322 FullDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)(FullDescriptor->PartialResourceList.PartialDescriptors +
323 FullDescriptor->PartialResourceList.Count);
324 }
325
326 return STATUS_NOT_FOUND;
327 }
328
329
330 NTSTATUS
331 AllocateAddressMapping(
332 PMAPPED_ADDRESS *MappedAddressList,
333 STOR_PHYSICAL_ADDRESS IoAddress,
334 PVOID MappedAddress,
335 ULONG NumberOfBytes,
336 ULONG BusNumber)
337 {
338 PMAPPED_ADDRESS Mapping;
339
340 DPRINT1("AllocateAddressMapping()\n");
341
342 Mapping = ExAllocatePoolWithTag(NonPagedPool,
343 sizeof(MAPPED_ADDRESS),
344 TAG_ADDRESS_MAPPING);
345 if (Mapping == NULL)
346 {
347 DPRINT1("No memory!\n");
348 return STATUS_NO_MEMORY;
349 }
350
351 RtlZeroMemory(Mapping, sizeof(MAPPED_ADDRESS));
352
353 Mapping->NextMappedAddress = *MappedAddressList;
354 *MappedAddressList = Mapping;
355
356 Mapping->IoAddress = IoAddress;
357 Mapping->MappedAddress = MappedAddress;
358 Mapping->NumberOfBytes = NumberOfBytes;
359 Mapping->BusNumber = BusNumber;
360
361 return STATUS_SUCCESS;
362 }
363
364 /* EOF */