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