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 WCHAR Buffer[100]; 441 ULONG Length; 442 LPWSTR InstanceId; 443 444 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 445 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension; 446 447 // format instance id 448 if (FDODeviceExtension->SerialNumber) 449 { 450 // using serial number from device 451 swprintf(Buffer, L"%s&%c", FDODeviceExtension->SerialNumber->bString, PDODeviceExtension->LUN); 452 } 453 else 454 { 455 // use instance count and LUN 456 swprintf(Buffer, L"%04lu&%c", FDODeviceExtension->InstanceCount, PDODeviceExtension->LUN); 457 } 458 459 Length = wcslen(Buffer) + 1; 460 461 InstanceId = ExAllocatePoolWithTag(PagedPool, Length * sizeof(WCHAR), USB_STOR_TAG); 462 if (!InstanceId) 463 { 464 Irp->IoStatus.Information = 0; 465 return STATUS_INSUFFICIENT_RESOURCES; 466 } 467 468 wcscpy(InstanceId, Buffer); 469 470 DPRINT("USBSTOR_PdoHandleQueryInstanceId %S\n", InstanceId); 471 472 Irp->IoStatus.Information = (ULONG_PTR)InstanceId; 473 return STATUS_SUCCESS; 474 } 475 476 NTSTATUS 477 USBSTOR_PdoHandleDeviceRelations( 478 IN PDEVICE_OBJECT DeviceObject, 479 IN OUT PIRP Irp) 480 { 481 PDEVICE_RELATIONS DeviceRelations; 482 PIO_STACK_LOCATION IoStack; 483 484 DPRINT("USBSTOR_PdoHandleDeviceRelations\n"); 485 486 IoStack = IoGetCurrentIrpStackLocation(Irp); 487 488 // check if relation type is BusRelations 489 if (IoStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation) 490 { 491 // PDO handles only target device relation 492 return Irp->IoStatus.Status; 493 } 494 495 DeviceRelations = ExAllocatePoolWithTag(PagedPool, sizeof(DEVICE_RELATIONS), USB_STOR_TAG); 496 if (!DeviceRelations) 497 { 498 return STATUS_INSUFFICIENT_RESOURCES; 499 } 500 501 // initialize device relations 502 DeviceRelations->Count = 1; 503 DeviceRelations->Objects[0] = DeviceObject; 504 ObReferenceObject(DeviceObject); 505 506 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations; 507 return STATUS_SUCCESS; 508 } 509 510 NTSTATUS 511 USBSTOR_PdoHandlePnp( 512 IN PDEVICE_OBJECT DeviceObject, 513 IN OUT PIRP Irp) 514 { 515 PIO_STACK_LOCATION IoStack; 516 PPDO_DEVICE_EXTENSION DeviceExtension; 517 NTSTATUS Status; 518 PDEVICE_CAPABILITIES Caps; 519 ULONG bDelete; 520 521 IoStack = IoGetCurrentIrpStackLocation(Irp); 522 DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 523 ASSERT(DeviceExtension->Common.IsFDO == FALSE); 524 525 switch(IoStack->MinorFunction) 526 { 527 case IRP_MN_QUERY_DEVICE_RELATIONS: 528 { 529 Status = USBSTOR_PdoHandleDeviceRelations(DeviceObject, Irp); 530 break; 531 } 532 case IRP_MN_QUERY_DEVICE_TEXT: 533 { 534 Status = USBSTOR_PdoHandleQueryDeviceText(DeviceObject, Irp); 535 break; 536 } 537 case IRP_MN_QUERY_ID: 538 { 539 if (IoStack->Parameters.QueryId.IdType == BusQueryDeviceID) 540 { 541 Status = USBSTOR_PdoHandleQueryDeviceId(DeviceObject, Irp); 542 break; 543 } 544 else if (IoStack->Parameters.QueryId.IdType == BusQueryHardwareIDs) 545 { 546 Status = USBSTOR_PdoHandleQueryHardwareId(DeviceObject, Irp); 547 break; 548 } 549 else if (IoStack->Parameters.QueryId.IdType == BusQueryInstanceID) 550 { 551 Status = USBSTOR_PdoHandleQueryInstanceId(DeviceObject, Irp); 552 break; 553 } 554 else if (IoStack->Parameters.QueryId.IdType == BusQueryCompatibleIDs) 555 { 556 Status = USBSTOR_PdoHandleQueryCompatibleId(DeviceObject, Irp); 557 break; 558 } 559 560 DPRINT1("USBSTOR_PdoHandlePnp: IRP_MN_QUERY_ID IdType %x unimplemented\n", IoStack->Parameters.QueryId.IdType); 561 Status = STATUS_NOT_SUPPORTED; 562 Irp->IoStatus.Information = 0; 563 break; 564 } 565 case IRP_MN_REMOVE_DEVICE: 566 { 567 DPRINT("IRP_MN_REMOVE_DEVICE\n"); 568 569 if(*DeviceExtension->PDODeviceObject != NULL) 570 { 571 *DeviceExtension->PDODeviceObject = NULL; 572 bDelete = TRUE; 573 } 574 else 575 { 576 // device object already marked for deletion 577 bDelete = FALSE; 578 } 579 580 Irp->IoStatus.Status = STATUS_SUCCESS; 581 IoCompleteRequest(Irp, IO_NO_INCREMENT); 582 583 if (bDelete) 584 { 585 IoDeleteDevice(DeviceObject); 586 } 587 return STATUS_SUCCESS; 588 } 589 case IRP_MN_QUERY_CAPABILITIES: 590 { 591 // just forward irp to lower device 592 Status = STATUS_UNSUCCESSFUL; 593 594 if (IoForwardIrpSynchronously(DeviceExtension->LowerDeviceObject, Irp)) 595 { 596 Status = Irp->IoStatus.Status; 597 ASSERT(Status == STATUS_SUCCESS); 598 599 if (NT_SUCCESS(Status)) 600 { 601 // check if no unique id 602 Caps = (PDEVICE_CAPABILITIES)IoStack->Parameters.DeviceCapabilities.Capabilities; 603 Caps->UniqueID = FALSE; // no unique id is supported 604 Caps->Removable = TRUE; //FIXME 605 } 606 } 607 break; 608 } 609 case IRP_MN_QUERY_REMOVE_DEVICE: 610 case IRP_MN_QUERY_STOP_DEVICE: 611 { 612 if (DeviceExtension->Claimed) 613 { 614 Status = STATUS_UNSUCCESSFUL; 615 DPRINT1("[USBSTOR] Request %x fails because device is still claimed\n", IoStack->MinorFunction); 616 } 617 else 618 Status = STATUS_SUCCESS; 619 break; 620 } 621 case IRP_MN_START_DEVICE: 622 { 623 // no-op for PDO 624 Status = STATUS_SUCCESS; 625 break; 626 } 627 case IRP_MN_SURPRISE_REMOVAL: 628 { 629 Status = STATUS_SUCCESS; 630 break; 631 } 632 default: 633 { 634 // do nothing 635 Status = Irp->IoStatus.Status; 636 } 637 } 638 639 if (Status != STATUS_PENDING) 640 { 641 Irp->IoStatus.Status = Status; 642 IoCompleteRequest(Irp, IO_NO_INCREMENT); 643 } 644 645 return Status; 646 } 647 648 NTSTATUS 649 NTAPI 650 USBSTOR_SyncCompletionRoutine( 651 IN PDEVICE_OBJECT DeviceObject, 652 IN PIRP Irp, 653 IN PVOID Ctx) 654 { 655 KeSetEvent((PKEVENT)Ctx, IO_NO_INCREMENT, FALSE); 656 return STATUS_MORE_PROCESSING_REQUIRED; 657 } 658 659 /* 660 * @name USBSTOR_SendInternalCdb 661 * 662 * Issues an internal SCSI request to device. 663 * The request is sent in a synchronous way. 664 */ 665 static 666 NTSTATUS 667 USBSTOR_SendInternalCdb( 668 IN PDEVICE_OBJECT PdoDevice, 669 IN PCDB Cdb, 670 IN UCHAR CdbLength, 671 IN ULONG TimeOutValue, 672 OUT PVOID OutDataBuffer, 673 OUT PULONG OutDataTransferLength) 674 { 675 PSCSI_REQUEST_BLOCK Srb; 676 PSENSE_DATA SenseBuffer; 677 PIO_STACK_LOCATION IoStack; 678 KEVENT Event; 679 PIRP Irp = NULL; 680 PMDL Mdl = NULL; 681 ULONG ix = 0; 682 NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES; 683 UCHAR SrbStatus; 684 685 DPRINT("USBSTOR_SendInternalCdb SCSIOP %x\n", Cdb->CDB6GENERIC.OperationCode); 686 687 Srb = ExAllocatePoolWithTag(NonPagedPool, 688 sizeof(SCSI_REQUEST_BLOCK), 689 USB_STOR_TAG); 690 691 if (Srb) 692 { 693 SenseBuffer = ExAllocatePoolWithTag(NonPagedPool, 694 SENSE_BUFFER_SIZE, 695 USB_STOR_TAG); 696 697 if (SenseBuffer) 698 { 699 Mdl = IoAllocateMdl(OutDataBuffer, 700 *OutDataTransferLength, 701 FALSE, 702 FALSE, 703 NULL); 704 705 if (!Mdl) 706 { 707 ExFreePoolWithTag(SenseBuffer, USB_STOR_TAG); 708 ExFreePoolWithTag(Srb, USB_STOR_TAG); 709 return Status; 710 } 711 712 MmBuildMdlForNonPagedPool(Mdl); 713 714 // make 3 attempts - the device may be in STALL state after the first one 715 do 716 { 717 Irp = IoAllocateIrp(PdoDevice->StackSize, FALSE); 718 719 if (!Irp) 720 { 721 break; 722 } 723 724 IoStack = IoGetNextIrpStackLocation(Irp); 725 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; 726 IoStack->Parameters.Scsi.Srb = Srb; 727 728 RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK)); 729 730 Srb->Length = sizeof(SCSI_REQUEST_BLOCK); 731 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 732 Srb->CdbLength = CdbLength; 733 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; 734 Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_NO_QUEUE_FREEZE; 735 Srb->DataTransferLength = *OutDataTransferLength; 736 Srb->TimeOutValue = TimeOutValue; 737 Srb->DataBuffer = OutDataBuffer; 738 Srb->SenseInfoBuffer = SenseBuffer; 739 740 RtlCopyMemory(Srb->Cdb, Cdb, CdbLength); 741 742 Irp->MdlAddress = Mdl; 743 744 KeInitializeEvent(&Event, SynchronizationEvent, FALSE); 745 746 IoSetCompletionRoutine(Irp, 747 USBSTOR_SyncCompletionRoutine, 748 &Event, 749 TRUE, 750 TRUE, 751 TRUE); 752 753 if (IoCallDriver(PdoDevice, Irp) == STATUS_PENDING) 754 { 755 KeWaitForSingleObject(&Event, 756 Executive, 757 KernelMode, 758 FALSE, 759 NULL); 760 } 761 762 SrbStatus = SRB_STATUS(Srb->SrbStatus); 763 764 IoFreeIrp(Irp); 765 Irp = NULL; 766 767 if (SrbStatus == SRB_STATUS_SUCCESS || 768 SrbStatus == SRB_STATUS_DATA_OVERRUN) 769 { 770 Status = STATUS_SUCCESS; 771 *OutDataTransferLength = Srb->DataTransferLength; 772 break; 773 } 774 775 Status = STATUS_UNSUCCESSFUL; 776 777 ++ix; 778 } while (ix < 3); 779 780 if (Mdl) 781 { 782 IoFreeMdl(Mdl); 783 } 784 785 ExFreePoolWithTag(SenseBuffer, USB_STOR_TAG); 786 } 787 788 ExFreePoolWithTag(Srb, USB_STOR_TAG); 789 } 790 791 return Status; 792 } 793 794 /* 795 * @name USBSTOR_FillInquiryData 796 * 797 * Sends a SCSI Inquiry request and fills in the PDODeviceExtension->InquiryData field with a result. 798 */ 799 static 800 NTSTATUS 801 USBSTOR_FillInquiryData( 802 IN PDEVICE_OBJECT PDODeviceObject) 803 { 804 NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES; 805 PPDO_DEVICE_EXTENSION PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension; 806 CDB Cdb; 807 ULONG DataTransferLength = INQUIRYDATABUFFERSIZE; 808 PINQUIRYDATA InquiryData = (PINQUIRYDATA)&PDODeviceExtension->InquiryData; 809 810 RtlZeroMemory(&Cdb, sizeof(Cdb)); 811 Cdb.CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY; 812 Cdb.CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE; 813 814 Status = USBSTOR_SendInternalCdb(PDODeviceObject, &Cdb, CDB6GENERIC_LENGTH, 20, InquiryData, &DataTransferLength); 815 816 if (!NT_SUCCESS(Status)) 817 { 818 DPRINT1("USBSTOR_FillInquiryData failed with %x\n", Status); 819 return Status; 820 } 821 822 DPRINT("DeviceType %x\n", InquiryData->DeviceType); 823 DPRINT("DeviceTypeModifier %x\n", InquiryData->DeviceTypeModifier); 824 DPRINT("RemovableMedia %x\n", InquiryData->RemovableMedia); 825 DPRINT("Version %x\n", InquiryData->Versions); 826 DPRINT("Format %x\n", InquiryData->ResponseDataFormat); 827 DPRINT("Length %x\n", InquiryData->AdditionalLength); 828 DPRINT("Reserved %p\n", InquiryData->Reserved); 829 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]); 830 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], 831 InquiryData->ProductId[4], InquiryData->ProductId[5], InquiryData->ProductId[6], InquiryData->ProductId[7], 832 InquiryData->ProductId[8], InquiryData->ProductId[9], InquiryData->ProductId[10], InquiryData->ProductId[11], 833 InquiryData->ProductId[12], InquiryData->ProductId[13], InquiryData->ProductId[14], InquiryData->ProductId[15]); 834 835 DPRINT("Revision %c%c%c%c\n", InquiryData->ProductRevisionLevel[0], InquiryData->ProductRevisionLevel[1], InquiryData->ProductRevisionLevel[2], InquiryData->ProductRevisionLevel[3]); 836 837 return Status; 838 } 839 840 NTSTATUS 841 USBSTOR_CreatePDO( 842 IN PDEVICE_OBJECT DeviceObject, 843 IN UCHAR LUN) 844 { 845 PDEVICE_OBJECT PDO; 846 NTSTATUS Status; 847 PPDO_DEVICE_EXTENSION PDODeviceExtension; 848 PFDO_DEVICE_EXTENSION FDODeviceExtension; 849 PINQUIRYDATA InquiryData; 850 851 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 852 853 // create child device object 854 Status = IoCreateDevice(DeviceObject->DriverObject, sizeof(PDO_DEVICE_EXTENSION), NULL, FILE_DEVICE_MASS_STORAGE, FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, FALSE, &PDO); 855 if (!NT_SUCCESS(Status)) 856 { 857 DPRINT1("Failed to create PDO, status %x\n", Status); 858 return Status; 859 } 860 861 // patch the stack size 862 PDO->StackSize = DeviceObject->StackSize; 863 864 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDO->DeviceExtension; 865 InquiryData = (PINQUIRYDATA)&PDODeviceExtension->InquiryData; 866 867 // initialize device extension 868 RtlZeroMemory(PDODeviceExtension, sizeof(PDO_DEVICE_EXTENSION)); 869 PDODeviceExtension->Common.IsFDO = FALSE; 870 PDODeviceExtension->LowerDeviceObject = DeviceObject; 871 PDODeviceExtension->PDODeviceObject = &FDODeviceExtension->ChildPDO[LUN]; 872 PDODeviceExtension->Self = PDO; 873 PDODeviceExtension->LUN = LUN; 874 875 PDO->Flags |= DO_DIRECT_IO; 876 877 // device is initialized 878 PDO->Flags &= ~DO_DEVICE_INITIALIZING; 879 880 // output device object 881 FDODeviceExtension->ChildPDO[LUN] = PDO; 882 883 // send inquiry command by irp 884 Status = USBSTOR_FillInquiryData(PDO); 885 886 if (!NT_SUCCESS(Status)) 887 { 888 return Status; 889 } 890 891 if (InquiryData->DeviceType != DIRECT_ACCESS_DEVICE && 892 InquiryData->DeviceType != READ_ONLY_DIRECT_ACCESS_DEVICE) 893 { 894 return STATUS_NOT_SUPPORTED; 895 } 896 897 return Status; 898 } 899