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