2 * PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbstor/pdo.c
5 * PURPOSE: USB block storage device driver.
8 * Michael Martin (michael.martin@reactos.org)
9 * Johannes Anderwald (johannes.anderwald@reactos.org)
17 IN ULONG DataTransferLength
,
19 IN UCHAR CommandBlockLength
,
20 IN PUCHAR CommandBlock
,
26 ASSERT(CommandBlockLength
<= 16);
31 Control
->Signature
= CBW_SIGNATURE
;
33 Control
->DataTransferLength
= DataTransferLength
;
34 Control
->Flags
= 0x80;
35 Control
->LUN
= (LUN
& MAX_LUN
);
36 Control
->CommandBlockLength
= CommandBlockLength
;
41 RtlCopyMemory(Control
->CommandBlock
, CommandBlock
, CommandBlockLength
);
46 return STATUS_SUCCESS
;
50 USBSTOR_AllocateIrpContext()
55 // allocate irp context
57 Context
= (PIRP_CONTEXT
)AllocateItem(NonPagedPool
, sizeof(IRP_CONTEXT
));
69 Context
->cbw
= (PCBW
)AllocateItem(NonPagedPool
, 512);
89 IO_COMPLETION_ROUTINE USBSTOR_CSWCompletionRoutine
;
93 USBSTOR_CSWCompletionRoutine(
94 PDEVICE_OBJECT DeviceObject
,
99 PIO_STACK_LOCATION IoStack
;
100 PSCSI_REQUEST_BLOCK Request
;
102 PREAD_CAPACITY_DATA_EX CapacityDataEx
;
103 PREAD_CAPACITY_DATA CapacityData
;
104 PUFI_CAPACITY_RESPONSE Response
;
106 DPRINT1("USBSTOR_CSWCompletionRoutine Irp %p Ctx %p\n", Irp
, Ctx
);
111 Context
= (PIRP_CONTEXT
)Ctx
;
113 if (Context
->TransferBufferMDL
)
118 IoFreeMdl(Context
->TransferBufferMDL
);
124 // get current stack location
126 IoStack
= IoGetCurrentIrpStackLocation(Context
->Irp
);
131 Request
= (PSCSI_REQUEST_BLOCK
)IoStack
->Parameters
.Others
.Argument1
;
135 // FIXME: check status
137 Request
->SrbStatus
= SRB_STATUS_SUCCESS
;
140 // get SCSI command data block
142 pCDB
= (PCDB
)Request
->Cdb
;
145 // read capacity needs special work
147 if (pCDB
->AsByte
[0] == SCSIOP_READ_CAPACITY
)
152 Response
= (PUFI_CAPACITY_RESPONSE
)Context
->TransferData
;
157 Context
->PDODeviceExtension
->BlockLength
= NTOHL(Response
->BlockLength
);
158 Context
->PDODeviceExtension
->LastLogicBlockAddress
= NTOHL(Response
->LastLogicalBlockAddress
);
160 if (Request
->DataTransferLength
== sizeof(READ_CAPACITY_DATA_EX
))
165 CapacityDataEx
= (PREAD_CAPACITY_DATA_EX
)Request
->DataBuffer
;
170 CapacityDataEx
->BytesPerBlock
= Response
->BlockLength
;
171 CapacityDataEx
->LogicalBlockAddress
.QuadPart
= Response
->LastLogicalBlockAddress
;
172 Irp
->IoStatus
.Information
= sizeof(READ_CAPACITY_DATA_EX
);
179 CapacityData
= (PREAD_CAPACITY_DATA
)Request
->DataBuffer
;
184 CapacityData
->BytesPerBlock
= Response
->BlockLength
;
185 CapacityData
->LogicalBlockAddress
= Response
->LastLogicalBlockAddress
;
186 Irp
->IoStatus
.Information
= sizeof(READ_CAPACITY_DATA
);
192 FreeItem(Context
->TransferData
);
199 FreeItem(Context
->cbw
);
205 // FIXME: check status
207 Context
->Irp
->IoStatus
.Status
= Irp
->IoStatus
.Status
;
208 Context
->Irp
->IoStatus
.Information
= Context
->TransferDataLength
;
213 IoCompleteRequest(Context
->Irp
, IO_NO_INCREMENT
);
221 KeSetEvent(Context
->Event
, 0, FALSE
);
233 return STATUS_MORE_PROCESSING_REQUIRED
;
239 IO_COMPLETION_ROUTINE USBSTOR_DataCompletionRoutine
;
243 USBSTOR_DataCompletionRoutine(
244 PDEVICE_OBJECT DeviceObject
,
248 PIRP_CONTEXT Context
;
249 PIO_STACK_LOCATION IoStack
;
251 DPRINT1("USBSTOR_DataCompletionRoutine Irp %p Ctx %p\n", Irp
, Ctx
);
256 Context
= (PIRP_CONTEXT
)Ctx
;
259 // get next stack location
262 IoStack
= IoGetNextIrpStackLocation(Irp
);
265 // now initialize the urb for sending the csw
267 UsbBuildInterruptOrBulkTransferRequest(&Context
->Urb
,
268 sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER
),
269 Context
->FDODeviceExtension
->InterfaceInformation
->Pipes
[Context
->FDODeviceExtension
->BulkInPipeIndex
].PipeHandle
,
273 USBD_TRANSFER_DIRECTION_IN
| USBD_SHORT_TRANSFER_OK
,
277 // initialize stack location
279 IoStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
280 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_INTERNAL_USB_SUBMIT_URB
;
281 IoStack
->Parameters
.Others
.Argument1
= (PVOID
)&Context
->Urb
;
282 IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
= Context
->Urb
.UrbHeader
.Length
;
283 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
287 // setup completion routine
289 IoSetCompletionRoutine(Irp
, USBSTOR_CSWCompletionRoutine
, Context
, TRUE
, TRUE
, TRUE
);
294 IoCallDriver(Context
->FDODeviceExtension
->LowerDeviceObject
, Irp
);
296 return STATUS_MORE_PROCESSING_REQUIRED
;
302 IO_COMPLETION_ROUTINE USBSTOR_CBWCompletionRoutine
;
306 USBSTOR_CBWCompletionRoutine(
307 PDEVICE_OBJECT DeviceObject
,
311 PIRP_CONTEXT Context
;
312 PIO_STACK_LOCATION IoStack
;
314 DPRINT1("USBSTOR_CBWCompletionRoutine Irp %p Ctx %p\n", Irp
, Ctx
);
319 Context
= (PIRP_CONTEXT
)Ctx
;
323 // get next stack location
325 IoStack
= IoGetNextIrpStackLocation(Irp
);
328 // is there data to be submitted
330 if (Context
->TransferDataLength
)
333 // now initialize the urb for sending data
336 UsbBuildInterruptOrBulkTransferRequest(&Context
->Urb
,
337 sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER
),
338 Context
->FDODeviceExtension
->InterfaceInformation
->Pipes
[Context
->FDODeviceExtension
->BulkInPipeIndex
].PipeHandle
,
340 Context
->TransferBufferMDL
,
341 Context
->TransferDataLength
,
342 USBD_TRANSFER_DIRECTION_IN
| USBD_SHORT_TRANSFER_OK
,
346 // setup completion routine
348 IoSetCompletionRoutine(Irp
, USBSTOR_DataCompletionRoutine
, Context
, TRUE
, TRUE
, TRUE
);
353 // now initialize the urb for sending the csw
356 UsbBuildInterruptOrBulkTransferRequest(&Context
->Urb
,
357 sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER
),
358 Context
->FDODeviceExtension
->InterfaceInformation
->Pipes
[Context
->FDODeviceExtension
->BulkInPipeIndex
].PipeHandle
,
362 USBD_TRANSFER_DIRECTION_IN
| USBD_SHORT_TRANSFER_OK
,
366 // setup completion routine
368 IoSetCompletionRoutine(Irp
, USBSTOR_CSWCompletionRoutine
, Context
, TRUE
, TRUE
, TRUE
);
372 // initialize stack location
374 IoStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
375 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_INTERNAL_USB_SUBMIT_URB
;
376 IoStack
->Parameters
.Others
.Argument1
= (PVOID
)&Context
->Urb
;
377 IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
= Context
->Urb
.UrbHeader
.Length
;
378 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
383 IoCallDriver(Context
->FDODeviceExtension
->LowerDeviceObject
, Irp
);
385 return STATUS_MORE_PROCESSING_REQUIRED
;
390 IN PDEVICE_OBJECT DeviceObject
,
391 IN PIRP OriginalRequest
,
392 IN OPTIONAL PKEVENT Event
,
393 IN ULONG CommandLength
,
395 IN ULONG TransferDataLength
,
396 IN PUCHAR TransferData
)
398 PIRP_CONTEXT Context
;
399 PPDO_DEVICE_EXTENSION PDODeviceExtension
;
400 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
402 PIO_STACK_LOCATION IoStack
;
405 // first allocate irp context
407 Context
= USBSTOR_AllocateIrpContext();
413 return STATUS_INSUFFICIENT_RESOURCES
;
417 // get PDO device extension
419 PDODeviceExtension
= (PPDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
422 // get FDO device extension
424 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)PDODeviceExtension
->LowerDeviceObject
->DeviceExtension
;
429 USBSTOR_BuildCBW(0xDEADDEAD, // FIXME tag
431 PDODeviceExtension
->LUN
,
437 // now initialize the urb
439 UsbBuildInterruptOrBulkTransferRequest(&Context
->Urb
,
440 sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER
),
441 FDODeviceExtension
->InterfaceInformation
->Pipes
[FDODeviceExtension
->BulkOutPipeIndex
].PipeHandle
,
445 USBD_TRANSFER_DIRECTION_OUT
| USBD_SHORT_TRANSFER_OK
,
449 // initialize rest of context
451 Context
->Irp
= OriginalRequest
;
452 Context
->TransferData
= TransferData
;
453 Context
->TransferDataLength
= TransferDataLength
;
454 Context
->FDODeviceExtension
= FDODeviceExtension
;
455 Context
->PDODeviceExtension
= PDODeviceExtension
;
456 Context
->Event
= Event
;
459 // is there transfer data
461 if (Context
->TransferDataLength
)
464 // allocate mdl for buffer, buffer must be allocated from NonPagedPool
466 Context
->TransferBufferMDL
= IoAllocateMdl(Context
->TransferData
, Context
->TransferDataLength
, FALSE
, FALSE
, NULL
);
467 if (!Context
->TransferBufferMDL
)
470 // failed to allocate MDL
472 return STATUS_INSUFFICIENT_RESOURCES
;
476 // build mdl for nonpaged pool
478 MmBuildMdlForNonPagedPool(Context
->TransferBufferMDL
);
482 // now allocate the request
484 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
487 FreeItem(Context
->cbw
);
489 return STATUS_INSUFFICIENT_RESOURCES
;
493 // get next stack location
495 IoStack
= IoGetNextIrpStackLocation(Irp
);
498 // initialize stack location
500 IoStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
501 IoStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_INTERNAL_USB_SUBMIT_URB
;
502 IoStack
->Parameters
.Others
.Argument1
= (PVOID
)&Context
->Urb
;
503 IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
= Context
->Urb
.UrbHeader
.Length
;
504 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
507 // setup completion routine
509 IoSetCompletionRoutine(Irp
, USBSTOR_CBWCompletionRoutine
, Context
, TRUE
, TRUE
, TRUE
);
514 // mark orignal irp as pending
516 IoMarkIrpPending(OriginalRequest
);
522 IoCallDriver(FDODeviceExtension
->LowerDeviceObject
, Irp
);
527 return STATUS_PENDING
;
531 USBSTOR_SendInquiryCmd(
532 IN PDEVICE_OBJECT DeviceObject
)
537 PPDO_DEVICE_EXTENSION PDODeviceExtension
;
538 PUFI_INQUIRY_RESPONSE Response
;
542 // allocate inquiry response
544 Response
= AllocateItem(NonPagedPool
, PAGE_SIZE
);
550 return STATUS_INSUFFICIENT_RESOURCES
;
554 // get PDO device extension
556 PDODeviceExtension
= (PPDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
559 // initialize inquiry cmd
561 RtlZeroMemory(&Cmd
, sizeof(UFI_INQUIRY_CMD
));
562 Cmd
.Code
= SCSIOP_INQUIRY
;
563 Cmd
.LUN
= (PDODeviceExtension
->LUN
& MAX_LUN
);
564 Cmd
.AllocationLength
= sizeof(UFI_INQUIRY_RESPONSE
);
569 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
572 // now send the request
574 Status
= USBSTOR_SendRequest(DeviceObject
, NULL
, &Event
, UFI_INQUIRY_CMD_LEN
, (PUCHAR
)&Cmd
, sizeof(UFI_INQUIRY_RESPONSE
), (PUCHAR
)Response
);
577 // wait for the action to complete
579 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
581 DPRINT1("Response %p\n", Response
);
582 DPRINT1("DeviceType %x\n", Response
->DeviceType
);
583 DPRINT1("RMB %x\n", Response
->RMB
);
584 DPRINT1("Version %x\n", Response
->Version
);
585 DPRINT1("Format %x\n", Response
->Format
);
586 DPRINT1("Length %x\n", Response
->Length
);
587 DPRINT1("Reserved %x\n", Response
->Reserved
);
588 DPRINT1("Vendor %c%c%c%c%c%c%c%c\n", Response
->Vendor
[0], Response
->Vendor
[1], Response
->Vendor
[2], Response
->Vendor
[3], Response
->Vendor
[4], Response
->Vendor
[5], Response
->Vendor
[6], Response
->Vendor
[7]);
589 DPRINT1("Product %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", Response
->Product
[0], Response
->Product
[1], Response
->Product
[2], Response
->Product
[3],
590 Response
->Product
[4], Response
->Product
[5], Response
->Product
[6], Response
->Product
[7],
591 Response
->Product
[8], Response
->Product
[9], Response
->Product
[10], Response
->Product
[11],
592 Response
->Product
[12], Response
->Product
[13], Response
->Product
[14], Response
->Product
[15]);
594 DPRINT1("Revision %c%c%c%c\n", Response
->Revision
[0], Response
->Revision
[1], Response
->Revision
[2], Response
->Revision
[3]);
597 // store inquiry data
599 PDODeviceExtension
->InquiryData
= (PVOID
)Response
;
608 USBSTOR_SendCapacityCmd(
609 IN PDEVICE_OBJECT DeviceObject
,
612 UFI_CAPACITY_CMD Cmd
;
613 PUFI_CAPACITY_RESPONSE Response
;
614 PPDO_DEVICE_EXTENSION PDODeviceExtension
;
617 // get PDO device extension
619 PDODeviceExtension
= (PPDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
622 // allocate capacity response
624 Response
= (PUFI_CAPACITY_RESPONSE
)AllocateItem(NonPagedPool
, sizeof(UFI_CAPACITY_RESPONSE
));
630 return STATUS_INSUFFICIENT_RESOURCES
;
634 // initialize capacity cmd
636 RtlZeroMemory(&Cmd
, sizeof(UFI_INQUIRY_CMD
));
637 Cmd
.Code
= SCSIOP_READ_CAPACITY
;
638 Cmd
.LUN
= (PDODeviceExtension
->LUN
& MAX_LUN
);
641 // send request, response will be freed in completion routine
643 return USBSTOR_SendRequest(DeviceObject
, Irp
, NULL
, UFI_INQUIRY_CMD_LEN
, (PUCHAR
)&Cmd
, sizeof(UFI_CAPACITY_RESPONSE
), (PUCHAR
)Response
);
647 USBSTOR_SendModeSenseCmd(
648 IN PDEVICE_OBJECT DeviceObject
,
654 PPDO_DEVICE_EXTENSION PDODeviceExtension
;
657 PUFI_MODE_PARAMETER_HEADER Header
;
660 return STATUS_NOT_IMPLEMENTED
;
664 // get SCSI command data block
666 pCDB
= (PCDB
)Request
->Cdb
;
669 // get PDO device extension
671 PDODeviceExtension
= (PPDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
674 // allocate sense response from non paged pool
676 Response
= (PUFI_CAPACITY_RESPONSE
)AllocateItem(NonPagedPool
, Request
->DataTransferLength
);
682 return STATUS_INSUFFICIENT_RESOURCES
;
691 // MODE_PAGE_ERROR_RECOVERY
692 // MODE_PAGE_FLEXIBILE
693 // MODE_PAGE_LUN_MAPPING
694 // MODE_PAGE_FAULT_REPORTING
695 // MODE_SENSE_RETURN_ALL
698 // initialize mode sense cmd
700 RtlZeroMemory(&Cmd
, sizeof(UFI_INQUIRY_CMD
));
701 Cmd
.Code
= SCSIOP_MODE_SENSE
;
702 Cmd
.LUN
= (PDODeviceExtension
->LUN
& MAX_LUN
);
703 Cmd
.PageCode
= pCDB
->MODE_SENSE
.PageCode
;
704 Cmd
.PC
= pCDB
->MODE_SENSE
.Pc
;
705 Cmd
.AllocationLength
= HTONS(pCDB
->MODE_SENSE
.AllocationLength
);
707 DPRINT1("PageCode %x\n", pCDB
->MODE_SENSE
.PageCode
);
708 DPRINT1("PC %x\n", pCDB
->MODE_SENSE
.Pc
);
711 // now send mode sense cmd
713 Status
= USBSTOR_SendCBW(DeviceObject
, UFI_SENSE_CMD_LEN
, (PUCHAR
)&Cmd
, Request
->DataTransferLength
, &OutControl
);
714 if (!NT_SUCCESS(Status
))
717 // failed to send CBW
719 DPRINT1("USBSTOR_SendCapacityCmd> USBSTOR_SendCBW failed with %x\n", Status
);
726 // now send data block response
728 Status
= USBSTOR_SendData(DeviceObject
, Request
->DataTransferLength
, Response
);
729 if (!NT_SUCCESS(Status
))
732 // failed to send CBW
734 DPRINT1("USBSTOR_SendCapacityCmd> USBSTOR_SendData failed with %x\n", Status
);
740 Header
= (PUFI_MODE_PARAMETER_HEADER
)Response
;
743 // TODO: build layout
745 // first struct is the header
746 // MODE_PARAMETER_HEADER / _MODE_PARAMETER_HEADER10
749 // MODE_PARAMETER_BLOCK
757 Status
= USBSTOR_SendCSW(DeviceObject
, OutControl
, 512, &CSW
);
759 DPRINT1("------------------------\n");
760 DPRINT1("CSW %p\n", &CSW
);
761 DPRINT1("Signature %x\n", CSW
.Signature
);
762 DPRINT1("Tag %x\n", CSW
.Tag
);
763 DPRINT1("DataResidue %x\n", CSW
.DataResidue
);
764 DPRINT1("Status %x\n", CSW
.Status
);
767 // FIXME: handle error
769 ASSERT(CSW
.Status
== 0);
770 ASSERT(CSW
.DataResidue
== 0);
773 // calculate transfer length
775 *TransferBufferLength
= Request
->DataTransferLength
- CSW
.DataResidue
;
780 RtlCopyMemory(Request
->DataBuffer
, Response
, *TransferBufferLength
);
785 FreeItem(OutControl
);
801 IN PDEVICE_OBJECT DeviceObject
,
806 PPDO_DEVICE_EXTENSION PDODeviceExtension
;
809 PIO_STACK_LOCATION IoStack
;
810 PSCSI_REQUEST_BLOCK Request
;
813 // get current stack location
815 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
820 Request
= (PSCSI_REQUEST_BLOCK
)IoStack
->Parameters
.Others
.Argument1
;
823 // get SCSI command data block
825 pCDB
= (PCDB
)Request
->Cdb
;
828 // get PDO device extension
830 PDODeviceExtension
= (PPDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
833 // FIXME: support more logical blocks
835 DPRINT1("Request->DataTransferLength %x, PDODeviceExtension->BlockLength %x\n", Request
->DataTransferLength
, PDODeviceExtension
->BlockLength
);
836 ASSERT(Request
->DataTransferLength
== PDODeviceExtension
->BlockLength
);
841 BlockCount
= Request
->DataTransferLength
/ PDODeviceExtension
->BlockLength
;
844 // initialize read cmd
846 RtlZeroMemory(&Cmd
, sizeof(UFI_READ_CMD
));
847 Cmd
.Code
= SCSIOP_READ
;
848 Cmd
.LUN
= (PDODeviceExtension
->LUN
& MAX_LUN
);
849 Cmd
.ContiguousLogicBlocks
= _byteswap_ushort(BlockCount
);
851 RtlCopyMemory(&Cmd
.LogicalBlockAddress
, pCDB
->READ12
.LogicalBlock
, sizeof(UCHAR
) * 4);
853 DPRINT1("BlockAddress %lu BlockCount %lu BlockLength %lu\n", NTOHL(Cmd
.LogicalBlockAddress
), BlockCount
, PDODeviceExtension
->BlockLength
);
858 return USBSTOR_SendRequest(DeviceObject
, Irp
, NULL
, UFI_READ_CMD_LEN
, (PUCHAR
)&Cmd
, Request
->DataTransferLength
, (PUCHAR
)Request
->DataBuffer
);
862 USBSTOR_SendTestUnitCmd(
863 IN PDEVICE_OBJECT DeviceObject
,
866 UFI_TEST_UNIT_CMD Cmd
;
867 PPDO_DEVICE_EXTENSION PDODeviceExtension
;
868 PIO_STACK_LOCATION IoStack
;
869 PSCSI_REQUEST_BLOCK Request
;
872 // get current stack location
874 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
879 Request
= (PSCSI_REQUEST_BLOCK
)IoStack
->Parameters
.Others
.Argument1
;
882 // no transfer length
884 ASSERT(Request
->DataTransferLength
== 0);
887 // get PDO device extension
889 PDODeviceExtension
= (PPDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
892 // initialize test unit cmd
894 RtlZeroMemory(&Cmd
, sizeof(UFI_TEST_UNIT_CMD
));
895 Cmd
.Code
= SCSIOP_TEST_UNIT_READY
;
896 Cmd
.LUN
= (PDODeviceExtension
->LUN
& MAX_LUN
);
901 return USBSTOR_SendRequest(DeviceObject
, Irp
, NULL
, UFI_TEST_UNIT_CMD_LEN
, (PUCHAR
)&Cmd
, 0, NULL
);