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