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