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