[USBSTOR] Do not leak fields of DeviceExtensions upon device removal
[reactos.git] / drivers / usb / usbstor / fdo.c
1 /*
2 * PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: USB block storage device driver.
5 * COPYRIGHT: 2005-2006 James Tabor
6 * 2011-2012 Michael Martin (michael.martin@reactos.org)
7 * 2011-2013 Johannes Anderwald (johannes.anderwald@reactos.org)
8 */
9
10 #include "usbstor.h"
11
12 #define NDEBUG
13 #include <debug.h>
14
15
16 VOID
17 USBSTOR_DumpDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor)
18 {
19 DPRINT1("Dumping Device Descriptor %p\n", DeviceDescriptor);
20 DPRINT1("bLength %x\n", DeviceDescriptor->bLength);
21 DPRINT1("bDescriptorType %x\n", DeviceDescriptor->bDescriptorType);
22 DPRINT1("bcdUSB %x\n", DeviceDescriptor->bcdUSB);
23 DPRINT1("bDeviceClass %x\n", DeviceDescriptor->bDeviceClass);
24 DPRINT1("bDeviceSubClass %x\n", DeviceDescriptor->bDeviceSubClass);
25 DPRINT1("bDeviceProtocol %x\n", DeviceDescriptor->bDeviceProtocol);
26 DPRINT1("bMaxPacketSize0 %x\n", DeviceDescriptor->bMaxPacketSize0);
27 DPRINT1("idVendor %x\n", DeviceDescriptor->idVendor);
28 DPRINT1("idProduct %x\n", DeviceDescriptor->idProduct);
29 DPRINT1("bcdDevice %x\n", DeviceDescriptor->bcdDevice);
30 DPRINT1("iManufacturer %x\n", DeviceDescriptor->iManufacturer);
31 DPRINT1("iProduct %x\n", DeviceDescriptor->iProduct);
32 DPRINT1("iSerialNumber %x\n", DeviceDescriptor->iSerialNumber);
33 DPRINT1("bNumConfigurations %x\n", DeviceDescriptor->bNumConfigurations);
34 }
35
36 NTSTATUS
37 USBSTOR_FdoHandleDeviceRelations(
38 IN PFDO_DEVICE_EXTENSION DeviceExtension,
39 IN OUT PIRP Irp)
40 {
41 ULONG DeviceCount = 0;
42 LONG Index;
43 PDEVICE_RELATIONS DeviceRelations;
44 PIO_STACK_LOCATION IoStack;
45
46 IoStack = IoGetCurrentIrpStackLocation(Irp);
47
48 // check if relation type is BusRelations
49 if (IoStack->Parameters.QueryDeviceRelations.Type != BusRelations)
50 {
51 // FDO always only handles bus relations
52 return USBSTOR_SyncForwardIrp(DeviceExtension->LowerDeviceObject, Irp);
53 }
54
55 // go through array and count device objects
56 for (Index = 0; Index < max(DeviceExtension->MaxLUN, 1); Index++)
57 {
58 if (DeviceExtension->ChildPDO[Index])
59 {
60 DeviceCount++;
61 }
62 }
63
64 DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(PagedPool, sizeof(DEVICE_RELATIONS) + (DeviceCount > 1 ? (DeviceCount-1) * sizeof(PDEVICE_OBJECT) : 0));
65 if (!DeviceRelations)
66 {
67 return STATUS_INSUFFICIENT_RESOURCES;
68 }
69
70 // add device objects
71 for (Index = 0; Index < max(DeviceExtension->MaxLUN, 1); Index++)
72 {
73 if (DeviceExtension->ChildPDO[Index])
74 {
75 // store child pdo
76 DeviceRelations->Objects[DeviceRelations->Count] = DeviceExtension->ChildPDO[Index];
77
78 // add reference
79 ObReferenceObject(DeviceExtension->ChildPDO[Index]);
80
81 DeviceRelations->Count++;
82 }
83 }
84
85 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
86
87 return STATUS_SUCCESS;
88 }
89
90 NTSTATUS
91 USBSTOR_FdoHandleRemoveDevice(
92 IN PDEVICE_OBJECT DeviceObject,
93 IN PFDO_DEVICE_EXTENSION DeviceExtension,
94 IN OUT PIRP Irp)
95 {
96 NTSTATUS Status;
97 ULONG Index;
98
99 DPRINT("Handling FDO removal %p\n", DeviceObject);
100
101 // FIXME: wait for devices finished processing
102 for (Index = 0; Index < 16; Index++)
103 {
104 if (DeviceExtension->ChildPDO[Index] != NULL)
105 {
106 DPRINT("Deleting PDO %p RefCount %x AttachedDevice %p \n", DeviceExtension->ChildPDO[Index], DeviceExtension->ChildPDO[Index]->ReferenceCount, DeviceExtension->ChildPDO[Index]->AttachedDevice);
107 IoDeleteDevice(DeviceExtension->ChildPDO[Index]);
108 }
109 }
110
111 // Freeing everything in DeviceExtension
112 ASSERT(
113 DeviceExtension->DeviceDescriptor &&
114 DeviceExtension->ConfigurationDescriptor &&
115 DeviceExtension->InterfaceInformation &&
116 DeviceExtension->ResetDeviceWorkItem
117 );
118
119 ExFreePoolWithTag(DeviceExtension->DeviceDescriptor, USB_STOR_TAG);
120 ExFreePoolWithTag(DeviceExtension->ConfigurationDescriptor, USB_STOR_TAG);
121 ExFreePoolWithTag(DeviceExtension->InterfaceInformation, USB_STOR_TAG);
122 IoFreeWorkItem(DeviceExtension->ResetDeviceWorkItem);
123
124 if (DeviceExtension->SerialNumber)
125 {
126 ExFreePoolWithTag(DeviceExtension->SerialNumber, USB_STOR_TAG);
127 }
128
129 // Send the IRP down the stack
130 IoSkipCurrentIrpStackLocation(Irp);
131 Irp->IoStatus.Status = STATUS_SUCCESS;
132 Status = IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
133
134 // Detach from the device stack
135 IoDetachDevice(DeviceExtension->LowerDeviceObject);
136
137 IoDeleteDevice(DeviceObject);
138
139 return Status;
140 }
141
142 NTSTATUS
143 USBSTOR_FdoHandleStartDevice(
144 IN PDEVICE_OBJECT DeviceObject,
145 IN PFDO_DEVICE_EXTENSION DeviceExtension,
146 IN OUT PIRP Irp)
147 {
148 PUSB_INTERFACE_DESCRIPTOR InterfaceDesc;
149 NTSTATUS Status;
150 UCHAR Index = 0;
151 PIO_WORKITEM WorkItem;
152
153 // forward irp to lower device
154 Status = USBSTOR_SyncForwardIrp(DeviceExtension->LowerDeviceObject, Irp);
155 if (!NT_SUCCESS(Status))
156 {
157 DPRINT1("USBSTOR_FdoHandleStartDevice Lower device failed to start %x\n", Status);
158 return Status;
159 }
160
161 if (!DeviceExtension->ResetDeviceWorkItem)
162 {
163 WorkItem = IoAllocateWorkItem(DeviceObject);
164 DeviceExtension->ResetDeviceWorkItem = WorkItem;
165
166 if (!WorkItem)
167 {
168 return STATUS_INSUFFICIENT_RESOURCES;
169 }
170 }
171
172 // initialize irp queue
173 USBSTOR_QueueInitialize(DeviceExtension);
174
175 // first get device & configuration & string descriptor
176 Status = USBSTOR_GetDescriptors(DeviceObject);
177 if (!NT_SUCCESS(Status))
178 {
179 DPRINT1("USBSTOR_FdoHandleStartDevice failed to get device descriptor with %x\n", Status);
180 return Status;
181 }
182
183 USBSTOR_DumpDeviceDescriptor(DeviceExtension->DeviceDescriptor);
184
185
186 // Check that this device uses bulk transfers and is SCSI
187
188 InterfaceDesc = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)DeviceExtension->ConfigurationDescriptor + sizeof(USB_CONFIGURATION_DESCRIPTOR));
189 ASSERT(InterfaceDesc->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE);
190 ASSERT(InterfaceDesc->bLength == sizeof(USB_INTERFACE_DESCRIPTOR));
191
192 DPRINT("bInterfaceSubClass %x\n", InterfaceDesc->bInterfaceSubClass);
193 if (InterfaceDesc->bInterfaceProtocol != 0x50)
194 {
195 DPRINT1("USB Device is not a bulk only device and is not currently supported\n");
196 return STATUS_NOT_SUPPORTED;
197 }
198
199 if (InterfaceDesc->bInterfaceSubClass == 0x04) // UFI subclass
200 {
201 // FIXME: need to pad CDBs to 12 byte
202 // mode select commands must be translated from 1AH / 15h to 5AH / 55h
203 DPRINT1("[USBSTOR] Error: need to pad CDBs\n");
204 return STATUS_NOT_SUPPORTED;
205 }
206
207 // now select an interface
208 Status = USBSTOR_SelectConfigurationAndInterface(DeviceObject, DeviceExtension);
209 if (!NT_SUCCESS(Status))
210 {
211 // failed to get device descriptor
212 DPRINT1("USBSTOR_FdoHandleStartDevice failed to select configuration / interface with %x\n", Status);
213 return Status;
214 }
215
216 // check if we got a bulk in + bulk out endpoint
217 Status = USBSTOR_GetPipeHandles(DeviceExtension);
218 if (!NT_SUCCESS(Status))
219 {
220 DPRINT1("USBSTOR_FdoHandleStartDevice no pipe handles %x\n", Status);
221 return Status;
222 }
223
224 Status = USBSTOR_GetMaxLUN(DeviceExtension->LowerDeviceObject, DeviceExtension);
225 if (!NT_SUCCESS(Status))
226 {
227 DPRINT1("USBSTOR_FdoHandleStartDevice failed to get max lun %x\n", Status);
228 return Status;
229 }
230
231 // now create for each LUN a device object, 1 minimum
232 do
233 {
234 Status = USBSTOR_CreatePDO(DeviceObject, Index);
235
236 if (!NT_SUCCESS(Status))
237 {
238 DPRINT1("USBSTOR_FdoHandleStartDevice USBSTOR_CreatePDO failed for Index %lu with Status %x\n", Index, Status);
239 return Status;
240 }
241
242 Index++;
243 DeviceExtension->InstanceCount++;
244
245 } while(Index < DeviceExtension->MaxLUN);
246
247 #if 0
248 //
249 // finally get usb device interface
250 //
251 Status = USBSTOR_GetBusInterface(DeviceExtension->LowerDeviceObject, &DeviceExtension->BusInterface);
252 if (!NT_SUCCESS(Status))
253 {
254 //
255 // failed to device interface
256 //
257 DPRINT1("USBSTOR_FdoHandleStartDevice failed to get device interface %x\n", Status);
258 return Status;
259 }
260 #endif
261
262 //IoStartTimer(DeviceObject);
263
264 DPRINT("USBSTOR_FdoHandleStartDevice FDO is initialized\n");
265 return STATUS_SUCCESS;
266 }
267
268 NTSTATUS
269 USBSTOR_FdoHandlePnp(
270 IN PDEVICE_OBJECT DeviceObject,
271 IN OUT PIRP Irp)
272 {
273 PIO_STACK_LOCATION IoStack;
274 PFDO_DEVICE_EXTENSION DeviceExtension;
275 NTSTATUS Status;
276
277 IoStack = IoGetCurrentIrpStackLocation(Irp);
278 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
279 ASSERT(DeviceExtension->Common.IsFDO);
280
281 switch(IoStack->MinorFunction)
282 {
283 case IRP_MN_SURPRISE_REMOVAL:
284 {
285 DPRINT("IRP_MN_SURPRISE_REMOVAL %p\n", DeviceObject);
286 Irp->IoStatus.Status = STATUS_SUCCESS;
287
288 // forward irp to next device object
289 IoSkipCurrentIrpStackLocation(Irp);
290 return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
291 }
292 case IRP_MN_QUERY_DEVICE_RELATIONS:
293 {
294 DPRINT("IRP_MN_QUERY_DEVICE_RELATIONS %p\n", DeviceObject);
295 Status = USBSTOR_FdoHandleDeviceRelations(DeviceExtension, Irp);
296 break;
297 }
298 case IRP_MN_STOP_DEVICE:
299 {
300 DPRINT1("USBSTOR_FdoHandlePnp: IRP_MN_STOP_DEVICE unimplemented\n");
301 IoStopTimer(DeviceObject);
302 Irp->IoStatus.Status = STATUS_SUCCESS;
303
304 // forward irp to next device object
305 IoSkipCurrentIrpStackLocation(Irp);
306 return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
307 }
308 case IRP_MN_REMOVE_DEVICE:
309 {
310 DPRINT("IRP_MN_REMOVE_DEVICE\n");
311
312 return USBSTOR_FdoHandleRemoveDevice(DeviceObject, DeviceExtension, Irp);
313 }
314 case IRP_MN_QUERY_CAPABILITIES:
315 {
316 // FIXME: set custom capabilities
317 IoSkipCurrentIrpStackLocation(Irp);
318 return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
319 }
320 case IRP_MN_QUERY_STOP_DEVICE:
321 case IRP_MN_QUERY_REMOVE_DEVICE:
322 {
323 #if 0
324 //
325 // we can if nothing is pending
326 //
327 if (DeviceExtension->IrpPendingCount != 0 ||
328 DeviceExtension->ActiveSrb != NULL)
329 #else
330 if (TRUE)
331 #endif
332 {
333 /* We have pending requests */
334 DPRINT1("Failing removal/stop request due to pending requests present\n");
335 Status = STATUS_UNSUCCESSFUL;
336 }
337 else
338 {
339 /* We're all clear */
340 Irp->IoStatus.Status = STATUS_SUCCESS;
341
342 IoSkipCurrentIrpStackLocation(Irp);
343 return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
344 }
345 break;
346 }
347 case IRP_MN_START_DEVICE:
348 {
349 Status = USBSTOR_FdoHandleStartDevice(DeviceObject, DeviceExtension, Irp);
350 break;
351 }
352 default:
353 {
354 // forward irp to next device object
355 IoSkipCurrentIrpStackLocation(Irp);
356 return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
357 }
358 }
359
360 if (Status != STATUS_PENDING)
361 {
362 Irp->IoStatus.Status = Status;
363 IoCompleteRequest(Irp, IO_NO_INCREMENT);
364 }
365
366 return Status;
367 }