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
;
51 IN PDEVICE_OBJECT DeviceObject
,
52 IN UCHAR CommandBlockLength
,
53 IN PUCHAR CommandBlock
,
54 IN ULONG DataTransferLength
,
60 PPDO_DEVICE_EXTENSION PDODeviceExtension
;
61 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
64 // get PDO device extension
66 PDODeviceExtension
= (PPDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
69 // get FDO device extension
71 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)PDODeviceExtension
->LowerDeviceObject
->DeviceExtension
;
76 Control
= (PCBW
)AllocateItem(NonPagedPool
, 512);
82 return STATUS_INSUFFICIENT_RESOURCES
;
88 Status
= USBSTOR_BuildCBW(0xDEADDEAD, DataTransferLength
, PDODeviceExtension
->LUN
, CommandBlockLength
, CommandBlock
, Control
);
89 if (!NT_SUCCESS(Status
))
92 // failed to build CBW
100 Urb
= (PURB
)AllocateItem(NonPagedPool
, sizeof(URB
));
104 // failed to allocate urb
107 return STATUS_INSUFFICIENT_RESOURCES
;
111 // now initialize the urb
113 Urb
->UrbBulkOrInterruptTransfer
.Hdr
.Length
= sizeof(URB
);
114 Urb
->UrbBulkOrInterruptTransfer
.Hdr
.Function
= URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
;
115 Urb
->UrbBulkOrInterruptTransfer
.PipeHandle
= FDODeviceExtension
->InterfaceInformation
->Pipes
[FDODeviceExtension
->BulkOutPipeIndex
].PipeHandle
;
116 Urb
->UrbBulkOrInterruptTransfer
.TransferBuffer
= (PVOID
)Control
;
117 Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
= sizeof(CBW
);
118 Urb
->UrbBulkOrInterruptTransfer
.TransferFlags
= USBD_TRANSFER_DIRECTION_OUT
| USBD_SHORT_TRANSFER_OK
;
123 Status
= USBSTOR_SyncUrbRequest(FDODeviceExtension
->LowerDeviceObject
, Urb
);
133 *OutControl
= Control
;
136 // return operation status
143 IN PDEVICE_OBJECT DeviceObject
,
144 IN ULONG DataTransferLength
,
145 IN PVOID DataTransfer
)
147 PMDL TransferBufferMDL
;
150 PPDO_DEVICE_EXTENSION PDODeviceExtension
;
151 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
154 // get PDO device extension
156 PDODeviceExtension
= (PPDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
159 // get FDO device extension
161 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)PDODeviceExtension
->LowerDeviceObject
->DeviceExtension
;
164 // allocate mdl for buffer, buffer must be allocated from NonPagedPool
166 TransferBufferMDL
= IoAllocateMdl(DataTransfer
, DataTransferLength
, FALSE
, FALSE
, NULL
);
167 if (!TransferBufferMDL
)
170 // failed to allocate MDL
172 return STATUS_INSUFFICIENT_RESOURCES
;
176 // build mdl for nonpaged pool
178 MmBuildMdlForNonPagedPool(TransferBufferMDL
);
183 Urb
= (PURB
)AllocateItem(NonPagedPool
, sizeof(URB
));
187 // failed to allocate urb
189 IoFreeMdl(TransferBufferMDL
);
190 return STATUS_INSUFFICIENT_RESOURCES
;
194 // now initialize the urb
196 Urb
->UrbBulkOrInterruptTransfer
.Hdr
.Length
= sizeof(URB
);
197 Urb
->UrbBulkOrInterruptTransfer
.Hdr
.Function
= URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
;
198 Urb
->UrbBulkOrInterruptTransfer
.PipeHandle
= FDODeviceExtension
->InterfaceInformation
->Pipes
[FDODeviceExtension
->BulkInPipeIndex
].PipeHandle
;
199 Urb
->UrbBulkOrInterruptTransfer
.TransferBufferMDL
= TransferBufferMDL
;
200 Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
= DataTransferLength
;
201 Urb
->UrbBulkOrInterruptTransfer
.TransferFlags
= USBD_TRANSFER_DIRECTION_IN
| USBD_SHORT_TRANSFER_OK
;
206 Status
= USBSTOR_SyncUrbRequest(FDODeviceExtension
->LowerDeviceObject
, Urb
);
216 IoFreeMdl(TransferBufferMDL
);
226 IN PDEVICE_OBJECT DeviceObject
,
232 PPDO_DEVICE_EXTENSION PDODeviceExtension
;
233 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
237 // get PDO device extension
239 PDODeviceExtension
= (PPDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
242 // get FDO device extension
244 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)PDODeviceExtension
->LowerDeviceObject
->DeviceExtension
;
249 Urb
= (PURB
)AllocateItem(NonPagedPool
, sizeof(URB
));
253 // failed to allocate urb
255 return STATUS_INSUFFICIENT_RESOURCES
;
259 // now initialize the urb
261 Urb
->UrbBulkOrInterruptTransfer
.Hdr
.Length
= sizeof(URB
);
262 Urb
->UrbBulkOrInterruptTransfer
.Hdr
.Function
= URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
;
263 Urb
->UrbBulkOrInterruptTransfer
.PipeHandle
= FDODeviceExtension
->InterfaceInformation
->Pipes
[FDODeviceExtension
->BulkInPipeIndex
].PipeHandle
;
264 Urb
->UrbBulkOrInterruptTransfer
.TransferBuffer
= Data
;
265 Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
= DataLength
;
266 Urb
->UrbBulkOrInterruptTransfer
.TransferFlags
= USBD_TRANSFER_DIRECTION_IN
| USBD_SHORT_TRANSFER_OK
;
271 Status
= USBSTOR_SyncUrbRequest(FDODeviceExtension
->LowerDeviceObject
, Urb
);
273 if (NT_SUCCESS(Status
))
278 RtlCopyMemory(OutCSW
, Data
, sizeof(CSW
));
293 USBSTOR_SendInquiryCmd(
294 IN PDEVICE_OBJECT DeviceObject
)
299 PUFI_INQUIRY_RESPONSE Response
;
300 PPDO_DEVICE_EXTENSION PDODeviceExtension
;
304 // get PDO device extension
306 PDODeviceExtension
= (PPDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
309 // allocate inquiry response
311 Response
= (PUFI_INQUIRY_RESPONSE
)AllocateItem(NonPagedPool
, sizeof(UFI_INQUIRY_RESPONSE
));
317 return STATUS_INSUFFICIENT_RESOURCES
;
321 // initialize inquiry cmd
323 RtlZeroMemory(&Cmd
, sizeof(UFI_INQUIRY_CMD
));
324 Cmd
.Code
= SCSIOP_INQUIRY
;
325 Cmd
.LUN
= (PDODeviceExtension
->LUN
& MAX_LUN
);
326 Cmd
.AllocationLength
= sizeof(UFI_INQUIRY_RESPONSE
);
329 // now send inquiry cmd
331 Status
= USBSTOR_SendCBW(DeviceObject
, UFI_INQUIRY_CMD_LEN
, (PUCHAR
)&Cmd
, sizeof(UFI_INQUIRY_RESPONSE
), &OutControl
);
332 if (!NT_SUCCESS(Status
))
335 // failed to send CBW
337 DPRINT1("USBSTOR_SendInquiryCmd> USBSTOR_SendCBW failed with %x\n", Status
);
344 // now send inquiry response
346 Status
= USBSTOR_SendData(DeviceObject
, sizeof(UFI_INQUIRY_RESPONSE
), Response
);
347 if (!NT_SUCCESS(Status
))
350 // failed to send CBW
352 DPRINT1("USBSTOR_SendInquiryCmd> USBSTOR_SendData failed with %x\n", Status
);
358 DPRINT1("Response %p\n", Response
);
359 DPRINT1("DeviceType %x\n", Response
->DeviceType
);
360 DPRINT1("RMB %x\n", Response
->RMB
);
361 DPRINT1("Version %x\n", Response
->Version
);
362 DPRINT1("Format %x\n", Response
->Format
);
363 DPRINT1("Length %x\n", Response
->Length
);
364 DPRINT1("Reserved %x\n", Response
->Reserved
);
365 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]);
366 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],
367 Response
->Product
[4], Response
->Product
[5], Response
->Product
[6], Response
->Product
[7],
368 Response
->Product
[8], Response
->Product
[9], Response
->Product
[10], Response
->Product
[11],
369 Response
->Product
[12], Response
->Product
[13], Response
->Product
[14], Response
->Product
[15]);
371 DPRINT1("Revision %c%c%c%c\n", Response
->Revision
[0], Response
->Revision
[1], Response
->Revision
[2], Response
->Revision
[3]);
376 Status
= USBSTOR_SendCSW(DeviceObject
, OutControl
, 512, &CSW
);
378 DPRINT1("------------------------\n");
379 DPRINT1("CSW %p\n", &CSW
);
380 DPRINT1("Signature %x\n", CSW
.Signature
);
381 DPRINT1("Tag %x\n", CSW
.Tag
);
382 DPRINT1("DataResidue %x\n", CSW
.DataResidue
);
383 DPRINT1("Status %x\n", CSW
.Status
);
388 FreeItem(OutControl
);
391 // store inquiry data
393 PDODeviceExtension
->InquiryData
= (PVOID
)Response
;
396 // FIXME: handle error
398 ASSERT(CSW
.Status
== 0);
408 USBSTOR_SendCapacityCmd(
409 IN PDEVICE_OBJECT DeviceObject
,
410 OUT PREAD_CAPACITY_DATA_EX CapacityDataEx
,
411 OUT PREAD_CAPACITY_DATA CapacityData
)
413 UFI_CAPACITY_CMD Cmd
;
416 PUFI_CAPACITY_RESPONSE Response
;
417 PPDO_DEVICE_EXTENSION PDODeviceExtension
;
421 // get PDO device extension
423 PDODeviceExtension
= (PPDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
426 // allocate capacity response
428 Response
= (PUFI_CAPACITY_RESPONSE
)AllocateItem(NonPagedPool
, sizeof(UFI_CAPACITY_RESPONSE
));
434 return STATUS_INSUFFICIENT_RESOURCES
;
438 // initialize capacity cmd
440 RtlZeroMemory(&Cmd
, sizeof(UFI_INQUIRY_CMD
));
441 Cmd
.Code
= SCSIOP_READ_CAPACITY
;
442 Cmd
.LUN
= (PDODeviceExtension
->LUN
& MAX_LUN
);
445 // now send capacity cmd
447 Status
= USBSTOR_SendCBW(DeviceObject
, UFI_CAPACITY_CMD_LEN
, (PUCHAR
)&Cmd
, sizeof(UFI_CAPACITY_RESPONSE
), &OutControl
);
448 if (!NT_SUCCESS(Status
))
451 // failed to send CBW
453 DPRINT1("USBSTOR_SendCapacityCmd> USBSTOR_SendCBW failed with %x\n", Status
);
460 // now send inquiry response
462 Status
= USBSTOR_SendData(DeviceObject
, sizeof(UFI_CAPACITY_RESPONSE
), Response
);
463 if (!NT_SUCCESS(Status
))
466 // failed to send CBW
468 DPRINT1("USBSTOR_SendCapacityCmd> USBSTOR_SendData failed with %x\n", Status
);
474 DPRINT1("LastLogicalBlockAddress %lu\n", NTOHL(Response
->LastLogicalBlockAddress
));
475 DPRINT1("BlockLength %lu\n", NTOHL(Response
->BlockLength
));
476 DPRINT1("Medium Length %lu\n", NTOHL(Response
->BlockLength
) * NTOHL(Response
->LastLogicalBlockAddress
));
483 CapacityDataEx
->LogicalBlockAddress
.QuadPart
= Response
->LastLogicalBlockAddress
;
484 CapacityDataEx
->BytesPerBlock
= Response
->BlockLength
;
488 CapacityData
->LogicalBlockAddress
= Response
->LastLogicalBlockAddress
;
489 CapacityData
->BytesPerBlock
= Response
->BlockLength
;
495 Status
= USBSTOR_SendCSW(DeviceObject
, OutControl
, 512, &CSW
);
497 DPRINT1("------------------------\n");
498 DPRINT1("CSW %p\n", &CSW
);
499 DPRINT1("Signature %x\n", CSW
.Signature
);
500 DPRINT1("Tag %x\n", CSW
.Tag
);
501 DPRINT1("DataResidue %x\n", CSW
.DataResidue
);
502 DPRINT1("Status %x\n", CSW
.Status
);
505 // FIXME: handle error
507 ASSERT(CSW
.Status
== 0);
512 FreeItem(OutControl
);
526 USBSTOR_SendModeSenseCmd(
527 IN PDEVICE_OBJECT DeviceObject
,
528 IN OUT PSCSI_REQUEST_BLOCK Request
,
529 OUT PULONG TransferBufferLength
)
535 PPDO_DEVICE_EXTENSION PDODeviceExtension
;
538 PUFI_MODE_PARAMETER_HEADER Header
;
541 // get SCSI command data block
543 pCDB
= (PCDB
)Request
->Cdb
;
546 // get PDO device extension
548 PDODeviceExtension
= (PPDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
551 // allocate sense response from non paged pool
553 Response
= (PUFI_CAPACITY_RESPONSE
)AllocateItem(NonPagedPool
, Request
->DataTransferLength
);
559 return STATUS_INSUFFICIENT_RESOURCES
;
568 // MODE_PAGE_ERROR_RECOVERY
569 // MODE_PAGE_FLEXIBILE
570 // MODE_PAGE_LUN_MAPPING
571 // MODE_PAGE_FAULT_REPORTING
572 // MODE_SENSE_RETURN_ALL
575 // initialize mode sense cmd
577 RtlZeroMemory(&Cmd
, sizeof(UFI_INQUIRY_CMD
));
578 Cmd
.Code
= SCSIOP_MODE_SENSE
;
579 Cmd
.LUN
= (PDODeviceExtension
->LUN
& MAX_LUN
);
580 Cmd
.PageCode
= pCDB
->MODE_SENSE
.PageCode
;
581 Cmd
.PC
= pCDB
->MODE_SENSE
.Pc
;
582 Cmd
.AllocationLength
= HTONS(pCDB
->MODE_SENSE
.AllocationLength
);
584 DPRINT1("PageCode %x\n", pCDB
->MODE_SENSE
.PageCode
);
585 DPRINT1("PC %x\n", pCDB
->MODE_SENSE
.Pc
);
588 // now send mode sense cmd
590 Status
= USBSTOR_SendCBW(DeviceObject
, UFI_SENSE_CMD_LEN
, (PUCHAR
)&Cmd
, Request
->DataTransferLength
, &OutControl
);
591 if (!NT_SUCCESS(Status
))
594 // failed to send CBW
596 DPRINT1("USBSTOR_SendCapacityCmd> USBSTOR_SendCBW failed with %x\n", Status
);
603 // now send data block response
605 Status
= USBSTOR_SendData(DeviceObject
, Request
->DataTransferLength
, Response
);
606 if (!NT_SUCCESS(Status
))
609 // failed to send CBW
611 DPRINT1("USBSTOR_SendCapacityCmd> USBSTOR_SendData failed with %x\n", Status
);
617 Header
= (PUFI_MODE_PARAMETER_HEADER
)Response
;
620 // TODO: build layout
622 // first struct is the header
623 // MODE_PARAMETER_HEADER / _MODE_PARAMETER_HEADER10
626 // MODE_PARAMETER_BLOCK
634 Status
= USBSTOR_SendCSW(DeviceObject
, OutControl
, 512, &CSW
);
636 DPRINT1("------------------------\n");
637 DPRINT1("CSW %p\n", &CSW
);
638 DPRINT1("Signature %x\n", CSW
.Signature
);
639 DPRINT1("Tag %x\n", CSW
.Tag
);
640 DPRINT1("DataResidue %x\n", CSW
.DataResidue
);
641 DPRINT1("Status %x\n", CSW
.Status
);
644 // FIXME: handle error
646 ASSERT(CSW
.Status
== 0);
647 ASSERT(CSW
.DataResidue
== 0);
650 // calculate transfer length
652 *TransferBufferLength
= Request
->DataTransferLength
- CSW
.DataResidue
;
657 RtlCopyMemory(Request
->DataBuffer
, Response
, *TransferBufferLength
);
662 FreeItem(OutControl
);