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