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