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