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 = USBSTOR_SyncForwardIrp(DeviceExtension->LowerDeviceObject, Irp); 593 ASSERT(Status == STATUS_SUCCESS); 594 595 if (NT_SUCCESS(Status)) 596 { 597 // check if no unique id 598 Caps = (PDEVICE_CAPABILITIES)IoStack->Parameters.DeviceCapabilities.Capabilities; 599 Caps->UniqueID = FALSE; // no unique id is supported 600 Caps->Removable = TRUE; //FIXME 601 } 602 break; 603 } 604 case IRP_MN_QUERY_REMOVE_DEVICE: 605 case IRP_MN_QUERY_STOP_DEVICE: 606 { 607 #if 0 608 // 609 // if we're not claimed it's ok 610 // 611 if (DeviceExtension->Claimed) 612 #else 613 if (TRUE) 614 #endif 615 { 616 Status = STATUS_UNSUCCESSFUL; 617 DPRINT1("[USBSTOR] Request %x fails because device is still claimed\n", IoStack->MinorFunction); 618 } 619 else 620 Status = STATUS_SUCCESS; 621 break; 622 } 623 case IRP_MN_START_DEVICE: 624 { 625 // no-op for PDO 626 Status = STATUS_SUCCESS; 627 break; 628 } 629 case IRP_MN_SURPRISE_REMOVAL: 630 { 631 Status = STATUS_SUCCESS; 632 break; 633 } 634 default: 635 { 636 // do nothing 637 Status = Irp->IoStatus.Status; 638 } 639 } 640 641 if (Status != STATUS_PENDING) 642 { 643 Irp->IoStatus.Status = Status; 644 IoCompleteRequest(Irp, IO_NO_INCREMENT); 645 } 646 647 return Status; 648 } 649 650 NTSTATUS 651 NTAPI 652 USBSTOR_SyncCompletionRoutine( 653 IN PDEVICE_OBJECT DeviceObject, 654 IN PIRP Irp, 655 IN PVOID Ctx) 656 { 657 KeSetEvent((PKEVENT)Ctx, IO_NO_INCREMENT, FALSE); 658 return STATUS_MORE_PROCESSING_REQUIRED; 659 } 660 661 /* 662 * @name USBSTOR_SendInternalCdb 663 * 664 * Issues an internal SCSI request to device. 665 * The request is sent in a synchronous way. 666 */ 667 static 668 NTSTATUS 669 USBSTOR_SendInternalCdb( 670 IN PDEVICE_OBJECT PdoDevice, 671 IN PCDB Cdb, 672 IN UCHAR CdbLength, 673 IN ULONG TimeOutValue, 674 OUT PVOID OutDataBuffer, 675 OUT PULONG OutDataTransferLength) 676 { 677 PSCSI_REQUEST_BLOCK Srb; 678 PSENSE_DATA SenseBuffer; 679 PIO_STACK_LOCATION IoStack; 680 KEVENT Event; 681 PIRP Irp = NULL; 682 PMDL Mdl = NULL; 683 ULONG ix = 0; 684 NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES; 685 UCHAR SrbStatus; 686 687 DPRINT("USBSTOR_SendInternalCdb SCSIOP %x\n", Cdb->CDB6GENERIC.OperationCode); 688 689 Srb = ExAllocatePoolWithTag(NonPagedPool, 690 sizeof(SCSI_REQUEST_BLOCK), 691 USB_STOR_TAG); 692 693 if (Srb) 694 { 695 SenseBuffer = ExAllocatePoolWithTag(NonPagedPool, 696 SENSE_BUFFER_SIZE, 697 USB_STOR_TAG); 698 699 if (SenseBuffer) 700 { 701 Mdl = IoAllocateMdl(OutDataBuffer, 702 *OutDataTransferLength, 703 FALSE, 704 FALSE, 705 NULL); 706 707 if (!Mdl) 708 { 709 ExFreePoolWithTag(SenseBuffer, USB_STOR_TAG); 710 ExFreePoolWithTag(Srb, USB_STOR_TAG); 711 return Status; 712 } 713 714 MmBuildMdlForNonPagedPool(Mdl); 715 716 // make 3 attempts - the device may be in STALL state after the first one 717 do 718 { 719 Irp = IoAllocateIrp(PdoDevice->StackSize, FALSE); 720 721 if (!Irp) 722 { 723 break; 724 } 725 726 IoStack = IoGetNextIrpStackLocation(Irp); 727 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; 728 IoStack->Parameters.Scsi.Srb = Srb; 729 730 RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK)); 731 732 Srb->Length = sizeof(SCSI_REQUEST_BLOCK); 733 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 734 Srb->CdbLength = CdbLength; 735 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; 736 Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_NO_QUEUE_FREEZE; 737 Srb->DataTransferLength = *OutDataTransferLength; 738 Srb->TimeOutValue = TimeOutValue; 739 Srb->DataBuffer = OutDataBuffer; 740 Srb->SenseInfoBuffer = SenseBuffer; 741 742 RtlCopyMemory(Srb->Cdb, Cdb, CdbLength); 743 744 Irp->MdlAddress = Mdl; 745 746 KeInitializeEvent(&Event, SynchronizationEvent, FALSE); 747 748 IoSetCompletionRoutine(Irp, 749 USBSTOR_SyncCompletionRoutine, 750 &Event, 751 TRUE, 752 TRUE, 753 TRUE); 754 755 if (IoCallDriver(PdoDevice, Irp) == STATUS_PENDING) 756 { 757 KeWaitForSingleObject(&Event, 758 Executive, 759 KernelMode, 760 FALSE, 761 NULL); 762 } 763 764 SrbStatus = SRB_STATUS(Srb->SrbStatus); 765 766 IoFreeIrp(Irp); 767 Irp = NULL; 768 769 if (SrbStatus == SRB_STATUS_SUCCESS || 770 SrbStatus == SRB_STATUS_DATA_OVERRUN) 771 { 772 Status = STATUS_SUCCESS; 773 *OutDataTransferLength = Srb->DataTransferLength; 774 break; 775 } 776 777 Status = STATUS_UNSUCCESSFUL; 778 779 ++ix; 780 } while (ix < 3); 781 782 if (Mdl) 783 { 784 IoFreeMdl(Mdl); 785 } 786 787 ExFreePoolWithTag(SenseBuffer, USB_STOR_TAG); 788 } 789 790 ExFreePoolWithTag(Srb, USB_STOR_TAG); 791 } 792 793 return Status; 794 } 795 796 /* 797 * @name USBSTOR_FillInquiryData 798 * 799 * Sends a SCSI Inquiry request and fills in the PDODeviceExtension->InquiryData field with a result. 800 */ 801 static 802 NTSTATUS 803 USBSTOR_FillInquiryData( 804 IN PDEVICE_OBJECT PDODeviceObject) 805 { 806 NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES; 807 PPDO_DEVICE_EXTENSION PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension; 808 CDB Cdb; 809 ULONG DataTransferLength = INQUIRYDATABUFFERSIZE; 810 PINQUIRYDATA InquiryData = (PINQUIRYDATA)&PDODeviceExtension->InquiryData; 811 812 RtlZeroMemory(&Cdb, sizeof(Cdb)); 813 Cdb.CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY; 814 Cdb.CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE; 815 816 Status = USBSTOR_SendInternalCdb(PDODeviceObject, &Cdb, CDB6GENERIC_LENGTH, 20, InquiryData, &DataTransferLength); 817 818 if (!NT_SUCCESS(Status)) 819 { 820 DPRINT1("USBSTOR_FillInquiryData failed with %x\n", Status); 821 return Status; 822 } 823 824 DPRINT("DeviceType %x\n", InquiryData->DeviceType); 825 DPRINT("DeviceTypeModifier %x\n", InquiryData->DeviceTypeModifier); 826 DPRINT("RemovableMedia %x\n", InquiryData->RemovableMedia); 827 DPRINT("Version %x\n", InquiryData->Versions); 828 DPRINT("Format %x\n", InquiryData->ResponseDataFormat); 829 DPRINT("Length %x\n", InquiryData->AdditionalLength); 830 DPRINT("Reserved %p\n", InquiryData->Reserved); 831 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]); 832 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], 833 InquiryData->ProductId[4], InquiryData->ProductId[5], InquiryData->ProductId[6], InquiryData->ProductId[7], 834 InquiryData->ProductId[8], InquiryData->ProductId[9], InquiryData->ProductId[10], InquiryData->ProductId[11], 835 InquiryData->ProductId[12], InquiryData->ProductId[13], InquiryData->ProductId[14], InquiryData->ProductId[15]); 836 837 DPRINT("Revision %c%c%c%c\n", InquiryData->ProductRevisionLevel[0], InquiryData->ProductRevisionLevel[1], InquiryData->ProductRevisionLevel[2], InquiryData->ProductRevisionLevel[3]); 838 839 return Status; 840 } 841 842 NTSTATUS 843 USBSTOR_CreatePDO( 844 IN PDEVICE_OBJECT DeviceObject, 845 IN UCHAR LUN) 846 { 847 PDEVICE_OBJECT PDO; 848 NTSTATUS Status; 849 PPDO_DEVICE_EXTENSION PDODeviceExtension; 850 PFDO_DEVICE_EXTENSION FDODeviceExtension; 851 PINQUIRYDATA InquiryData; 852 853 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 854 855 // create child device object 856 Status = IoCreateDevice(DeviceObject->DriverObject, sizeof(PDO_DEVICE_EXTENSION), NULL, FILE_DEVICE_MASS_STORAGE, FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, FALSE, &PDO); 857 if (!NT_SUCCESS(Status)) 858 { 859 DPRINT1("Failed to create PDO, status %x\n", Status); 860 return Status; 861 } 862 863 // patch the stack size 864 PDO->StackSize = DeviceObject->StackSize; 865 866 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDO->DeviceExtension; 867 InquiryData = (PINQUIRYDATA)&PDODeviceExtension->InquiryData; 868 869 // initialize device extension 870 RtlZeroMemory(PDODeviceExtension, sizeof(PDO_DEVICE_EXTENSION)); 871 PDODeviceExtension->Common.IsFDO = FALSE; 872 PDODeviceExtension->LowerDeviceObject = DeviceObject; 873 PDODeviceExtension->PDODeviceObject = &FDODeviceExtension->ChildPDO[LUN]; 874 PDODeviceExtension->Self = PDO; 875 PDODeviceExtension->LUN = LUN; 876 877 PDO->Flags |= DO_DIRECT_IO; 878 879 // device is initialized 880 PDO->Flags &= ~DO_DEVICE_INITIALIZING; 881 882 // output device object 883 FDODeviceExtension->ChildPDO[LUN] = PDO; 884 885 // send inquiry command by irp 886 Status = USBSTOR_FillInquiryData(PDO); 887 888 if (!NT_SUCCESS(Status)) 889 { 890 return Status; 891 } 892 893 if (InquiryData->DeviceType != DIRECT_ACCESS_DEVICE && 894 InquiryData->DeviceType != READ_ONLY_DIRECT_ACCESS_DEVICE) 895 { 896 return STATUS_NOT_SUPPORTED; 897 } 898 899 return Status; 900 } 901