[USBSTOR] Do not leak fields of DeviceExtensions upon device removal
[reactos.git] / drivers / usb / usbstor / pdo.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 * 2017 Vadim Galyant
9 * 2019 Victor Perevertkin (victor.perevertkin@reactos.org)
10 */
11
12 #include "usbstor.h"
13
14 #define NDEBUG
15 #include <debug.h>
16
17
18 LPCSTR
19 USBSTOR_GetDeviceType(
20 IN PINQUIRYDATA InquiryData,
21 IN UCHAR IsFloppy)
22 {
23 if (InquiryData->DeviceType == 0)
24 {
25 if (IsFloppy)
26 {
27 // floppy device
28 return "SFloppy";
29 }
30
31 // direct access device
32 return "Disk";
33 }
34
35 switch (InquiryData->DeviceType)
36 {
37 case 1:
38 {
39 // sequential device, i.e magnetic tape
40 return "Sequential";
41 }
42 case 4:
43 {
44 // write once device
45 return "Worm";
46 }
47 case 5:
48 {
49 // CDROM device
50 return "CdRom";
51 }
52 case 7:
53 {
54 // optical memory device
55 return "Optical";
56 }
57 case 8:
58 {
59 // medium change device
60 return "Changer";
61 }
62 default:
63 {
64 // other device
65 return "Other";
66 }
67 }
68 }
69
70 LPCSTR
71 USBSTOR_GetGenericType(
72 IN PINQUIRYDATA InquiryData,
73 IN UCHAR IsFloppy)
74 {
75 if (InquiryData->DeviceType == 0)
76 {
77 if (IsFloppy)
78 {
79 // floppy device
80 return "GenSFloppy";
81 }
82
83 // direct access device
84 return "GenDisk";
85 }
86
87 switch (InquiryData->DeviceType)
88 {
89 case 1:
90 {
91 // sequential device, i.e magnetic tape
92 return "GenSequential";
93 }
94 case 4:
95 {
96 // write once device
97 return "GenWorm";
98 }
99 case 5:
100 {
101 // CDROM device
102 return "GenCdRom";
103 }
104 case 7:
105 {
106 // optical memory device
107 return "GenOptical";
108 }
109 case 8:
110 {
111 // medium change device
112 return "GenChanger";
113 }
114 default:
115 {
116 // other device
117 return "UsbstorOther";
118 }
119 }
120 }
121
122 ULONG
123 CopyField(
124 IN PUCHAR Name,
125 IN PCHAR Buffer,
126 IN ULONG MaxLength)
127 {
128 ULONG Index;
129
130 for (Index = 0; Index < MaxLength; Index++)
131 {
132 if (Name[Index] <= ' ' || Name[Index] >= 0x7F /* last printable ascii character */ || Name[Index] == ',')
133 {
134 // convert to underscore
135 Buffer[Index] = '_';
136 }
137 else
138 {
139 // just copy character
140 Buffer[Index] = Name[Index];
141 }
142 }
143
144 return MaxLength;
145 }
146
147 NTSTATUS
148 USBSTOR_PdoHandleQueryDeviceText(
149 IN PDEVICE_OBJECT DeviceObject,
150 IN PIRP Irp)
151 {
152 PIO_STACK_LOCATION IoStack;
153 LPWSTR Buffer;
154 static WCHAR DeviceText[] = L"USB Mass Storage Device";
155
156 IoStack = IoGetCurrentIrpStackLocation(Irp);
157
158 if (IoStack->Parameters.QueryDeviceText.DeviceTextType == DeviceTextDescription)
159 {
160 DPRINT("USBSTOR_PdoHandleQueryDeviceText DeviceTextDescription\n");
161
162 Buffer = (LPWSTR)AllocateItem(PagedPool, sizeof(DeviceText));
163 if (!Buffer)
164 {
165 Irp->IoStatus.Information = 0;
166 return STATUS_INSUFFICIENT_RESOURCES;
167 }
168
169 wcscpy(Buffer, DeviceText);
170
171 Irp->IoStatus.Information = (ULONG_PTR)Buffer;
172 return STATUS_SUCCESS;
173 }
174 else
175 {
176 DPRINT("USBSTOR_PdoHandleQueryDeviceText DeviceTextLocationInformation\n");
177
178 Buffer = (LPWSTR)AllocateItem(PagedPool, sizeof(DeviceText));
179 if (!Buffer)
180 {
181 Irp->IoStatus.Information = 0;
182 return STATUS_INSUFFICIENT_RESOURCES;
183 }
184
185 wcscpy(Buffer, DeviceText);
186
187 Irp->IoStatus.Information = (ULONG_PTR)Buffer;
188 return STATUS_SUCCESS;
189 }
190
191 }
192
193 NTSTATUS
194 USBSTOR_PdoHandleQueryDeviceId(
195 IN PDEVICE_OBJECT DeviceObject,
196 IN PIRP Irp)
197 {
198 PPDO_DEVICE_EXTENSION DeviceExtension;
199 NTSTATUS Status;
200 CHAR Buffer[100] = {0};
201 LPCSTR DeviceType;
202 ULONG Offset = 0;
203 PINQUIRYDATA InquiryData;
204 ANSI_STRING AnsiString;
205 UNICODE_STRING DeviceId;
206
207 DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
208 ASSERT(DeviceExtension->InquiryData);
209 InquiryData = DeviceExtension->InquiryData;
210
211 DeviceType = USBSTOR_GetDeviceType(InquiryData, DeviceExtension->IsFloppy);
212
213 // lets create device string
214 Offset = sprintf(&Buffer[Offset], "USBSTOR\\");
215 Offset += sprintf(&Buffer[Offset], DeviceType);
216 Offset += sprintf(&Buffer[Offset], "&Ven_");
217 Offset += CopyField(InquiryData->VendorId, &Buffer[Offset], 8);
218 Offset += sprintf(&Buffer[Offset], "&Prod_");
219 Offset += CopyField(InquiryData->ProductId, &Buffer[Offset], 16);
220 Offset += sprintf(&Buffer[Offset], "&Rev_");
221 Offset += CopyField(InquiryData->ProductRevisionLevel, &Buffer[Offset], 4);
222
223 RtlInitAnsiString(&AnsiString, (PCSZ)Buffer);
224
225 // allocate DeviceId string
226 DeviceId.Length = 0;
227 DeviceId.MaximumLength = (USHORT)((strlen((PCHAR)Buffer) + 1) * sizeof(WCHAR));
228 DeviceId.Buffer = (LPWSTR)AllocateItem(PagedPool, DeviceId.MaximumLength);
229 if (!DeviceId.Buffer)
230 {
231 Irp->IoStatus.Information = 0;
232 return STATUS_INSUFFICIENT_RESOURCES;
233 }
234
235 Status = RtlAnsiStringToUnicodeString(&DeviceId, &AnsiString, FALSE);
236
237 if (NT_SUCCESS(Status))
238 {
239 Irp->IoStatus.Information = (ULONG_PTR)DeviceId.Buffer;
240 }
241
242 DPRINT("DeviceId %wZ Status %x\n", &DeviceId, Status);
243
244 return Status;
245 }
246
247 VOID
248 USBSTOR_ConvertToUnicodeString(
249 IN CHAR * Buffer,
250 IN ULONG ResultBufferLength,
251 IN ULONG ResultBufferOffset,
252 OUT LPWSTR ResultBuffer,
253 OUT PULONG NewResultBufferOffset)
254 {
255 UNICODE_STRING DeviceString;
256 ANSI_STRING AnsiString;
257 NTSTATUS Status;
258
259 ASSERT(ResultBufferLength);
260 ASSERT(ResultBufferLength > ResultBufferOffset);
261
262 DPRINT("ResultBufferOffset %lu ResultBufferLength %lu Buffer %s Length %lu\n", ResultBufferOffset, ResultBufferLength, Buffer, strlen(Buffer));
263
264 // construct destination string
265 DeviceString.Buffer = &ResultBuffer[ResultBufferOffset];
266 DeviceString.Length = 0;
267 DeviceString.MaximumLength = (ResultBufferLength - ResultBufferOffset) * sizeof(WCHAR);
268
269 // initialize source string
270 RtlInitAnsiString(&AnsiString, Buffer);
271
272 Status = RtlAnsiStringToUnicodeString(&DeviceString, &AnsiString, FALSE);
273 ASSERT(Status == STATUS_SUCCESS);
274
275 // subtract consumed bytes
276 ResultBufferLength -= (DeviceString.Length + sizeof(WCHAR)) / sizeof(WCHAR);
277 ResultBufferOffset += (DeviceString.Length + sizeof(WCHAR)) / sizeof(WCHAR);
278
279 *NewResultBufferOffset = ResultBufferOffset;
280 }
281
282 NTSTATUS
283 USBSTOR_PdoHandleQueryHardwareId(
284 IN PDEVICE_OBJECT DeviceObject,
285 IN OUT PIRP Irp)
286 {
287 PPDO_DEVICE_EXTENSION PDODeviceExtension;
288 PFDO_DEVICE_EXTENSION FDODeviceExtension;
289 LPCSTR GenericType, DeviceType;
290 LPWSTR Buffer;
291 CHAR Id1[50], Id2[50], Id3[50], Id4[50], Id5[50], Id6[50];
292 ULONG Id1Length, Id2Length, Id3Length, Id4Length, Id5Length,Id6Length;
293 ULONG Offset, TotalLength, Length;
294 PINQUIRYDATA InquiryData;
295
296 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
297 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
298 ASSERT(FDODeviceExtension->DeviceDescriptor);
299 InquiryData = PDODeviceExtension->InquiryData;
300
301 DeviceType = USBSTOR_GetDeviceType(InquiryData, PDODeviceExtension->IsFloppy);
302 GenericType = USBSTOR_GetGenericType(InquiryData, PDODeviceExtension->IsFloppy);
303
304 ASSERT(GenericType);
305
306 // generate id 1
307 // USBSTOR\SCSIType_VendorId(8)_ProductId(16)_Revision(4)
308 RtlZeroMemory(Id1, sizeof(Id1));
309 Offset = 0;
310 Offset = sprintf(&Id1[Offset], "USBSTOR\\");
311 Offset += sprintf(&Id1[Offset], DeviceType);
312 Offset += CopyField(InquiryData->VendorId, &Id1[Offset], 8);
313 Offset += CopyField(InquiryData->ProductId, &Id1[Offset], 16);
314 Offset += CopyField(InquiryData->ProductRevisionLevel, &Id1[Offset], 4);
315 Id1Length = strlen(Id1) + 1;
316 DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId1 %s\n", Id1);
317
318 // generate id 2
319 // USBSTOR\SCSIType_VendorId(8)_ProductId(16)
320 RtlZeroMemory(Id2, sizeof(Id2));
321 Offset = 0;
322 Offset = sprintf(&Id2[Offset], "USBSTOR\\");
323 Offset += sprintf(&Id2[Offset], DeviceType);
324 Offset += CopyField(InquiryData->VendorId, &Id2[Offset], 8);
325 Offset += CopyField(InquiryData->ProductId, &Id2[Offset], 16);
326 Id2Length = strlen(Id2) + 1;
327 DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId2 %s\n", Id2);
328
329 // generate id 3
330 // USBSTOR\SCSIType_VendorId(8)
331 RtlZeroMemory(Id3, sizeof(Id3));
332 Offset = 0;
333 Offset = sprintf(&Id3[Offset], "USBSTOR\\");
334 Offset += sprintf(&Id3[Offset], DeviceType);
335 Offset += CopyField(InquiryData->VendorId, &Id3[Offset], 8);
336 Id3Length = strlen(Id3) + 1;
337 DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId3 %s\n", Id3);
338
339 // generate id 4
340 // USBSTOR\SCSIType_VendorId(8)_ProductId(16)_Revision(1)
341 RtlZeroMemory(Id4, sizeof(Id4));
342 Offset = 0;
343 Offset = sprintf(&Id4[Offset], "USBSTOR\\");
344 Offset += sprintf(&Id4[Offset], DeviceType);
345 Offset += CopyField(InquiryData->VendorId, &Id4[Offset], 8);
346 Offset += CopyField(InquiryData->ProductId, &Id4[Offset], 16);
347 Offset += CopyField(InquiryData->ProductRevisionLevel, &Id4[Offset], 1);
348 Id4Length = strlen(Id4) + 1;
349 DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId4 %s\n", Id4);
350
351 // generate id 5
352 // USBSTOR\SCSIType
353 RtlZeroMemory(Id5, sizeof(Id5));
354 Offset = 0;
355 Offset = sprintf(&Id5[Offset], "USBSTOR\\");
356 Offset += sprintf(&Id5[Offset], GenericType);
357 Id5Length = strlen(Id5) + 1;
358 DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId5 %s\n", Id5);
359
360 // generate id 6
361 // SCSIType
362 RtlZeroMemory(Id6, sizeof(Id6));
363 Offset = 0;
364 Offset = sprintf(&Id6[Offset], GenericType);
365 Id6Length = strlen(Id6) + 1;
366 DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId6 %s\n", Id6);
367
368 TotalLength = Id1Length + Id2Length + Id3Length + Id4Length + Id5Length + Id6Length + 1;
369
370 Buffer = (LPWSTR)AllocateItem(PagedPool, TotalLength * sizeof(WCHAR));
371 if (!Buffer)
372 {
373 Irp->IoStatus.Information = 0;
374 return STATUS_INSUFFICIENT_RESOURCES;
375 }
376
377 // reset offset
378 Offset = 0;
379 Length = TotalLength;
380
381 USBSTOR_ConvertToUnicodeString(Id1, Length, Offset, Buffer, &Offset);
382 USBSTOR_ConvertToUnicodeString(Id2, Length, Offset, Buffer, &Offset);
383 USBSTOR_ConvertToUnicodeString(Id3, Length, Offset, Buffer, &Offset);
384 USBSTOR_ConvertToUnicodeString(Id4, Length, Offset, Buffer, &Offset);
385 USBSTOR_ConvertToUnicodeString(Id5, Length, Offset, Buffer, &Offset);
386 USBSTOR_ConvertToUnicodeString(Id6, Length, Offset, Buffer, &Offset);
387
388 ASSERT(Offset + 1 == Length);
389
390 Irp->IoStatus.Information = (ULONG_PTR)Buffer;
391 return STATUS_SUCCESS;
392 }
393
394 NTSTATUS
395 USBSTOR_PdoHandleQueryCompatibleId(
396 IN PDEVICE_OBJECT DeviceObject,
397 IN OUT PIRP Irp)
398 {
399 PPDO_DEVICE_EXTENSION PDODeviceExtension;
400 PFDO_DEVICE_EXTENSION FDODeviceExtension;
401 CHAR Buffer[100] = {0};
402 ULONG Length, Offset;
403 LPWSTR InstanceId;
404 LPCSTR DeviceType;
405
406 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
407 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
408 ASSERT(FDODeviceExtension->DeviceDescriptor);
409 DeviceType = USBSTOR_GetDeviceType(PDODeviceExtension->InquiryData, PDODeviceExtension->IsFloppy);
410
411 // format instance id
412 Length = sprintf(Buffer, "USBSTOR\\%s", DeviceType) + 1;
413 Length += sprintf(&Buffer[Length], "USBSTOR\\%s", "RAW") + 2;
414
415 InstanceId = (LPWSTR)AllocateItem(PagedPool, Length * sizeof(WCHAR));
416 if (!InstanceId)
417 {
418 Irp->IoStatus.Information = 0;
419 return STATUS_INSUFFICIENT_RESOURCES;
420 }
421
422 USBSTOR_ConvertToUnicodeString(Buffer, Length, 0, InstanceId, &Offset);
423 USBSTOR_ConvertToUnicodeString(&Buffer[Offset], Length, Offset, InstanceId, &Offset);
424
425 DPRINT("USBSTOR_PdoHandleQueryCompatibleId %S\n", InstanceId);
426
427 Irp->IoStatus.Information = (ULONG_PTR)InstanceId;
428 return STATUS_SUCCESS;
429 }
430
431 NTSTATUS
432 USBSTOR_PdoHandleQueryInstanceId(
433 IN PDEVICE_OBJECT DeviceObject,
434 IN OUT PIRP Irp)
435 {
436 PPDO_DEVICE_EXTENSION PDODeviceExtension;
437 PFDO_DEVICE_EXTENSION FDODeviceExtension;
438 WCHAR Buffer[100];
439 ULONG Length;
440 LPWSTR InstanceId;
441
442 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
443 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
444
445 // format instance id
446 if (FDODeviceExtension->SerialNumber)
447 {
448 // using serial number from device
449 swprintf(Buffer, L"%s&%c", FDODeviceExtension->SerialNumber->bString, PDODeviceExtension->LUN);
450 }
451 else
452 {
453 // use instance count and LUN
454 swprintf(Buffer, L"%04lu&%c", FDODeviceExtension->InstanceCount, PDODeviceExtension->LUN);
455 }
456
457 Length = wcslen(Buffer) + 1;
458
459 InstanceId = (LPWSTR)AllocateItem(PagedPool, Length * sizeof(WCHAR));
460 if (!InstanceId)
461 {
462 Irp->IoStatus.Information = 0;
463 return STATUS_INSUFFICIENT_RESOURCES;
464 }
465
466 wcscpy(InstanceId, Buffer);
467
468 DPRINT("USBSTOR_PdoHandleQueryInstanceId %S\n", InstanceId);
469
470 Irp->IoStatus.Information = (ULONG_PTR)InstanceId;
471 return STATUS_SUCCESS;
472 }
473
474 NTSTATUS
475 USBSTOR_PdoHandleDeviceRelations(
476 IN PDEVICE_OBJECT DeviceObject,
477 IN OUT PIRP Irp)
478 {
479 PDEVICE_RELATIONS DeviceRelations;
480 PIO_STACK_LOCATION IoStack;
481
482 DPRINT("USBSTOR_PdoHandleDeviceRelations\n");
483
484 IoStack = IoGetCurrentIrpStackLocation(Irp);
485
486 // check if relation type is BusRelations
487 if (IoStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
488 {
489 // PDO handles only target device relation
490 return Irp->IoStatus.Status;
491 }
492
493 DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(PagedPool, sizeof(DEVICE_RELATIONS));
494 if (!DeviceRelations)
495 {
496 return STATUS_INSUFFICIENT_RESOURCES;
497 }
498
499 // initialize device relations
500 DeviceRelations->Count = 1;
501 DeviceRelations->Objects[0] = DeviceObject;
502 ObReferenceObject(DeviceObject);
503
504 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
505 return STATUS_SUCCESS;
506 }
507
508 NTSTATUS
509 USBSTOR_PdoHandlePnp(
510 IN PDEVICE_OBJECT DeviceObject,
511 IN OUT PIRP Irp)
512 {
513 PIO_STACK_LOCATION IoStack;
514 PPDO_DEVICE_EXTENSION DeviceExtension;
515 NTSTATUS Status;
516 PDEVICE_CAPABILITIES Caps;
517 ULONG bDelete;
518
519 IoStack = IoGetCurrentIrpStackLocation(Irp);
520 DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
521 ASSERT(DeviceExtension->Common.IsFDO == FALSE);
522
523 switch(IoStack->MinorFunction)
524 {
525 case IRP_MN_QUERY_DEVICE_RELATIONS:
526 {
527 Status = USBSTOR_PdoHandleDeviceRelations(DeviceObject, Irp);
528 break;
529 }
530 case IRP_MN_QUERY_DEVICE_TEXT:
531 {
532 Status = USBSTOR_PdoHandleQueryDeviceText(DeviceObject, Irp);
533 break;
534 }
535 case IRP_MN_QUERY_ID:
536 {
537 if (IoStack->Parameters.QueryId.IdType == BusQueryDeviceID)
538 {
539 Status = USBSTOR_PdoHandleQueryDeviceId(DeviceObject, Irp);
540 break;
541 }
542 else if (IoStack->Parameters.QueryId.IdType == BusQueryHardwareIDs)
543 {
544 Status = USBSTOR_PdoHandleQueryHardwareId(DeviceObject, Irp);
545 break;
546 }
547 else if (IoStack->Parameters.QueryId.IdType == BusQueryInstanceID)
548 {
549 Status = USBSTOR_PdoHandleQueryInstanceId(DeviceObject, Irp);
550 break;
551 }
552 else if (IoStack->Parameters.QueryId.IdType == BusQueryCompatibleIDs)
553 {
554 Status = USBSTOR_PdoHandleQueryCompatibleId(DeviceObject, Irp);
555 break;
556 }
557
558 DPRINT1("USBSTOR_PdoHandlePnp: IRP_MN_QUERY_ID IdType %x unimplemented\n", IoStack->Parameters.QueryId.IdType);
559 Status = STATUS_NOT_SUPPORTED;
560 Irp->IoStatus.Information = 0;
561 break;
562 }
563 case IRP_MN_REMOVE_DEVICE:
564 {
565 DPRINT("IRP_MN_REMOVE_DEVICE\n");
566
567 if(*DeviceExtension->PDODeviceObject != NULL)
568 {
569 *DeviceExtension->PDODeviceObject = NULL;
570 bDelete = TRUE;
571 }
572 else
573 {
574 // device object already marked for deletion
575 bDelete = FALSE;
576 }
577
578 // clean up the device extension
579 ASSERT(DeviceExtension->InquiryData);
580 ExFreePoolWithTag(DeviceExtension->InquiryData, USB_STOR_TAG);
581
582 Irp->IoStatus.Status = STATUS_SUCCESS;
583 IoCompleteRequest(Irp, IO_NO_INCREMENT);
584
585 if (bDelete)
586 {
587 IoDeleteDevice(DeviceObject);
588 }
589 return STATUS_SUCCESS;
590 }
591 case IRP_MN_QUERY_CAPABILITIES:
592 {
593 // just forward irp to lower device
594 Status = USBSTOR_SyncForwardIrp(DeviceExtension->LowerDeviceObject, Irp);
595 ASSERT(Status == STATUS_SUCCESS);
596
597 if (NT_SUCCESS(Status))
598 {
599 // check if no unique id
600 Caps = (PDEVICE_CAPABILITIES)IoStack->Parameters.DeviceCapabilities.Capabilities;
601 Caps->UniqueID = FALSE; // no unique id is supported
602 Caps->Removable = TRUE; //FIXME
603 }
604 break;
605 }
606 case IRP_MN_QUERY_REMOVE_DEVICE:
607 case IRP_MN_QUERY_STOP_DEVICE:
608 {
609 #if 0
610 //
611 // if we're not claimed it's ok
612 //
613 if (DeviceExtension->Claimed)
614 #else
615 if (TRUE)
616 #endif
617 {
618 Status = STATUS_UNSUCCESSFUL;
619 DPRINT1("[USBSTOR] Request %x fails because device is still claimed\n", IoStack->MinorFunction);
620 }
621 else
622 Status = STATUS_SUCCESS;
623 break;
624 }
625 case IRP_MN_START_DEVICE:
626 {
627 // no-op for PDO
628 Status = STATUS_SUCCESS;
629 break;
630 }
631 case IRP_MN_SURPRISE_REMOVAL:
632 {
633 Status = STATUS_SUCCESS;
634 break;
635 }
636 default:
637 {
638 // do nothing
639 Status = Irp->IoStatus.Status;
640 }
641 }
642
643 if (Status != STATUS_PENDING)
644 {
645 Irp->IoStatus.Status = Status;
646 IoCompleteRequest(Irp, IO_NO_INCREMENT);
647 }
648
649 return Status;
650 }
651
652 NTSTATUS
653 NTAPI
654 USBSTOR_SyncCompletionRoutine(
655 IN PDEVICE_OBJECT DeviceObject,
656 IN PIRP Irp,
657 IN PVOID Ctx)
658 {
659 KeSetEvent((PKEVENT)Ctx, IO_NO_INCREMENT, FALSE);
660 return STATUS_MORE_PROCESSING_REQUIRED;
661 }
662
663 /*
664 * @name USBSTOR_SendInternalCdb
665 *
666 * Issues an internal SCSI request to device.
667 * The request is sent in a synchronous way.
668 */
669 static
670 NTSTATUS
671 USBSTOR_SendInternalCdb(
672 IN PDEVICE_OBJECT PdoDevice,
673 IN PCDB Cdb,
674 IN UCHAR CdbLength,
675 IN ULONG TimeOutValue,
676 OUT PVOID OutDataBuffer,
677 OUT PULONG OutDataTransferLength)
678 {
679 PSCSI_REQUEST_BLOCK Srb;
680 PSENSE_DATA SenseBuffer;
681 PIO_STACK_LOCATION IoStack;
682 KEVENT Event;
683 PIRP Irp = NULL;
684 PMDL Mdl = NULL;
685 ULONG ix = 0;
686 NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
687 UCHAR SrbStatus;
688
689 DPRINT("USBSTOR_SendInternalCdb SCSIOP %x\n", Cdb->CDB6GENERIC.OperationCode);
690
691 Srb = ExAllocatePoolWithTag(NonPagedPool,
692 sizeof(SCSI_REQUEST_BLOCK),
693 USB_STOR_TAG);
694
695 if (Srb)
696 {
697 SenseBuffer = ExAllocatePoolWithTag(NonPagedPool,
698 SENSE_BUFFER_SIZE,
699 USB_STOR_TAG);
700
701 if (SenseBuffer)
702 {
703 Mdl = IoAllocateMdl(OutDataBuffer,
704 *OutDataTransferLength,
705 FALSE,
706 FALSE,
707 NULL);
708
709 if (!Mdl)
710 {
711 ExFreePoolWithTag(SenseBuffer, USB_STOR_TAG);
712 ExFreePoolWithTag(Srb, USB_STOR_TAG);
713 return Status;
714 }
715
716 MmBuildMdlForNonPagedPool(Mdl);
717
718 // make 3 attempts - the device may be in STALL state after the first one
719 do
720 {
721 Irp = IoAllocateIrp(PdoDevice->StackSize, FALSE);
722
723 if (!Irp)
724 {
725 break;
726 }
727
728 IoStack = IoGetNextIrpStackLocation(Irp);
729 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
730 IoStack->Parameters.Scsi.Srb = Srb;
731
732 RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
733
734 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
735 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
736 Srb->CdbLength = CdbLength;
737 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
738 Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_NO_QUEUE_FREEZE;
739 Srb->DataTransferLength = *OutDataTransferLength;
740 Srb->TimeOutValue = TimeOutValue;
741 Srb->DataBuffer = OutDataBuffer;
742 Srb->SenseInfoBuffer = SenseBuffer;
743
744 RtlCopyMemory(Srb->Cdb, Cdb, CdbLength);
745
746 Irp->MdlAddress = Mdl;
747
748 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
749
750 IoSetCompletionRoutine(Irp,
751 USBSTOR_SyncCompletionRoutine,
752 &Event,
753 TRUE,
754 TRUE,
755 TRUE);
756
757 if (IoCallDriver(PdoDevice, Irp) == STATUS_PENDING)
758 {
759 KeWaitForSingleObject(&Event,
760 Executive,
761 KernelMode,
762 FALSE,
763 NULL);
764 }
765
766 SrbStatus = SRB_STATUS(Srb->SrbStatus);
767
768 IoFreeIrp(Irp);
769 Irp = NULL;
770
771 if (SrbStatus == SRB_STATUS_SUCCESS ||
772 SrbStatus == SRB_STATUS_DATA_OVERRUN)
773 {
774 Status = STATUS_SUCCESS;
775 *OutDataTransferLength = Srb->DataTransferLength;
776 break;
777 }
778
779 Status = STATUS_UNSUCCESSFUL;
780
781 ++ix;
782 } while (ix < 3);
783
784 if (Mdl)
785 {
786 IoFreeMdl(Mdl);
787 }
788
789 ExFreePoolWithTag(SenseBuffer, USB_STOR_TAG);
790 }
791
792 ExFreePoolWithTag(Srb, USB_STOR_TAG);
793 }
794
795 return Status;
796 }
797
798 /*
799 * @name USBSTOR_FillInquiryData
800 *
801 * Sends a SCSI Inquiry request and fills in the PDODeviceExtension->InquiryData field with a result.
802 */
803 static
804 NTSTATUS
805 USBSTOR_FillInquiryData(
806 IN PDEVICE_OBJECT PDODeviceObject)
807 {
808 NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
809 PPDO_DEVICE_EXTENSION PDODeviceExtension;
810 CDB Cdb;
811 ULONG DataTransferLength = INQUIRYDATABUFFERSIZE;
812 PINQUIRYDATA InquiryData;
813
814 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension;
815 InquiryData = ExAllocatePoolWithTag(NonPagedPool, INQUIRYDATABUFFERSIZE, USB_STOR_TAG);
816
817 if (!InquiryData)
818 {
819 DPRINT1("USBSTOR_FillInquiryData failed with %x\n", Status);
820 return Status;
821 }
822
823 RtlZeroMemory(&Cdb, sizeof(Cdb));
824 Cdb.CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
825 Cdb.CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
826
827 Status = USBSTOR_SendInternalCdb(PDODeviceObject, &Cdb, CDB6GENERIC_LENGTH, 20, InquiryData, &DataTransferLength);
828
829 if (!NT_SUCCESS(Status))
830 {
831 DPRINT1("USBSTOR_FillInquiryData failed with %x\n", Status);
832 ExFreePoolWithTag(InquiryData, USB_STOR_TAG);
833 return Status;
834 }
835
836 DPRINT("DeviceType %x\n", InquiryData->DeviceType);
837 DPRINT("DeviceTypeModifier %x\n", InquiryData->DeviceTypeModifier);
838 DPRINT("RemovableMedia %x\n", InquiryData->RemovableMedia);
839 DPRINT("Version %x\n", InquiryData->Versions);
840 DPRINT("Format %x\n", InquiryData->ResponseDataFormat);
841 DPRINT("Length %x\n", InquiryData->AdditionalLength);
842 DPRINT("Reserved %p\n", InquiryData->Reserved);
843 DPRINT("VendorId %c%c%c%c%c%c%c%c\n", InquiryData->VendorId[0], InquiryData->VendorId[1], InquiryData->VendorId[2], InquiryData->VendorId[3], InquiryData->VendorId[4], InquiryData->VendorId[5], InquiryData->VendorId[6], InquiryData->VendorId[7]);
844 DPRINT("ProductId %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", InquiryData->ProductId[0], InquiryData->ProductId[1], InquiryData->ProductId[2], InquiryData->ProductId[3],
845 InquiryData->ProductId[4], InquiryData->ProductId[5], InquiryData->ProductId[6], InquiryData->ProductId[7],
846 InquiryData->ProductId[8], InquiryData->ProductId[9], InquiryData->ProductId[10], InquiryData->ProductId[11],
847 InquiryData->ProductId[12], InquiryData->ProductId[13], InquiryData->ProductId[14], InquiryData->ProductId[15]);
848
849 DPRINT("Revision %c%c%c%c\n", InquiryData->ProductRevisionLevel[0], InquiryData->ProductRevisionLevel[1], InquiryData->ProductRevisionLevel[2], InquiryData->ProductRevisionLevel[3]);
850
851 PDODeviceExtension->InquiryData = InquiryData;
852 return Status;
853 }
854
855 NTSTATUS
856 USBSTOR_CreatePDO(
857 IN PDEVICE_OBJECT DeviceObject,
858 IN UCHAR LUN)
859 {
860 PDEVICE_OBJECT PDO;
861 NTSTATUS Status;
862 PPDO_DEVICE_EXTENSION PDODeviceExtension;
863 PFDO_DEVICE_EXTENSION FDODeviceExtension;
864
865 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
866
867 // create child device object
868 Status = IoCreateDevice(DeviceObject->DriverObject, sizeof(PDO_DEVICE_EXTENSION), NULL, FILE_DEVICE_MASS_STORAGE, FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, FALSE, &PDO);
869 if (!NT_SUCCESS(Status))
870 {
871 DPRINT1("Failed to create PDO, status %x\n", Status);
872 return Status;
873 }
874
875 // patch the stack size
876 PDO->StackSize = DeviceObject->StackSize;
877
878 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDO->DeviceExtension;
879
880 // initialize device extension
881 RtlZeroMemory(PDODeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
882 PDODeviceExtension->Common.IsFDO = FALSE;
883 PDODeviceExtension->LowerDeviceObject = DeviceObject;
884 PDODeviceExtension->PDODeviceObject = &FDODeviceExtension->ChildPDO[LUN];
885 PDODeviceExtension->Self = PDO;
886 PDODeviceExtension->LUN = LUN;
887
888 PDO->Flags |= DO_DIRECT_IO;
889
890 // device is initialized
891 PDO->Flags &= ~DO_DEVICE_INITIALIZING;
892
893 // output device object
894 FDODeviceExtension->ChildPDO[LUN] = PDO;
895
896 // send inquiry command by irp
897 Status = USBSTOR_FillInquiryData(PDO);
898
899 if (!NT_SUCCESS(Status))
900 {
901 return Status;
902 }
903
904 if (PDODeviceExtension->InquiryData->DeviceType == DIRECT_ACCESS_DEVICE || PDODeviceExtension->InquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE)
905 {
906 PDODeviceExtension->IsFloppy = FALSE; // TODO: implement the actual check
907 }
908 else
909 {
910 // we work only with DIRECT_ACCESS_DEVICE for now
911 return STATUS_NOT_SUPPORTED;
912 }
913
914 return Status;
915 }