bulkonly.c
来自「这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统」· C语言 代码 · 共 793 行 · 第 1/2 页
C
793 行
usb_free_mem(buf), buf = NULL;
usb_dbg_print(DBGLVL_MINIMUM,
("umss_transfer_data_complete(): Failed to allocate work-item to reset pipe!\n"));
TRAP();
umss_complete_request(pdev_ext, status);
}
}
else
{
//finish our request
umss_complete_request(pdev_ext, status);
}
}
else
{
// Start next part of data phase
//umss_bulkonly_transfer_data( pdev_ext );
umss_bulkonly_get_status(pdev_ext);
//umss_complete_request( pdev_ext, status );
}
usb_free_mem(purb);
purb = NULL;
return; // STATUS_MORE_PROCESSING_REQUIRED;
}
VOID
umss_bulkonly_reset_pipe_and_get_status(IN PVOID reference)
{
PUMSS_DEVICE_EXTENSION pdev_ext;
DEV_HANDLE endp_handle;
NTSTATUS status;
usb_dbg_print(DBGLVL_MINIMUM, ("umss_bulkonly_reset_pipe_and_get_status(): entering...\n"));
pdev_ext = (PUMSS_DEVICE_EXTENSION) (((PULONG) reference)[0]);
endp_handle = (DEV_HANDLE) ((PULONG) reference)[1];
usb_free_mem(reference);
reference = NULL;
// Reset the endpoint
if ((status = umss_reset_pipe(pdev_ext, endp_handle)) != STATUS_SUCCESS)
{
usb_dbg_print(DBGLVL_MINIMUM, ("umss_bulkonly_reset_pipe_and_get_status(): reset pipe failed\n"));
umss_complete_request(pdev_ext, status);
return;
}
// Data phase is finished since the endpoint stalled, so go to status phase
usb_dbg_print(DBGLVL_MINIMUM,
("umss_bulkonly_reset_pipe_and_get_status(): reset pipe succeeds, continue to get status\n"));
umss_bulkonly_get_status(pdev_ext);
}
VOID
umss_bulkonly_get_status(PUMSS_DEVICE_EXTENSION pdev_ext)
{
NTSTATUS status;
// Schedule bulk transfer to get command status wrapper from device
status = umss_bulk_transfer(pdev_ext,
USB_DIR_IN,
&(pdev_ext->csw),
sizeof(COMMAND_STATUS_WRAPPER), umss_bulkonly_get_status_complete);
if (status != STATUS_PENDING)
{
umss_complete_request(pdev_ext, status);
}
}
/*++
Routine Description:
Completion handler for bulk data transfer request.
Arguments:
DeviceObject - Previous device object.
Irp - Irp used for sending command.
Reference - Our FDO.
Return Value:
Driver-originated IRPs always return STATUS_MORE_PROCESSING_REQUIRED.
--*/
VOID
umss_bulkonly_get_status_complete(IN PURB purb, IN PVOID context)
{
NTSTATUS status;
PUMSS_DEVICE_EXTENSION pdev_ext;
PCOMMAND_STATUS_WRAPPER csw;
pdev_ext = (PUMSS_DEVICE_EXTENSION) context;
status = purb->status;
dev_mgr_remove_irp(pdev_ext->dev_mgr, pdev_ext->io_packet.pirp);
csw = &(pdev_ext->csw);
if (status == STATUS_SUCCESS &&
((csw->dCSWSignature == CSW_SIGNATURE) || OLYMPUS_CSW(pdev_ext, csw->dCSWSignature)))
{
if (csw->bCSWStatus == CSW_STATUS_PASSED)
{
// Received valid CSW with good status
if ((pdev_ext->io_packet.flags & IOP_FLAG_STAGE_MASK) == IOP_FLAG_STAGE_NORMAL &&
(pdev_ext->io_packet.flags & IOP_FLAG_REQ_SENSE) && pdev_ext->io_packet.sense_data != NULL)
UMSS_FORGE_GOOD_SENSE(pdev_ext->io_packet.sense_data)
umss_complete_request(pdev_ext, STATUS_SUCCESS);
}
else if (csw->bCSWStatus == CSW_STATUS_FAILED)
{
// start a request sense if necessary
if ((pdev_ext->io_packet.flags & IOP_FLAG_REQ_SENSE) &&
(pdev_ext->io_packet.flags & IOP_FLAG_STAGE_MASK) == IOP_FLAG_STAGE_NORMAL)
{
if (umss_bulkonly_send_sense_req(pdev_ext) != STATUS_PENDING)
{
// don't know how to handle.
umss_complete_request(pdev_ext, STATUS_IO_DEVICE_ERROR);
}
else
{
// fall through to free the urb
}
}
else
{
// error occurred, reset device
if (!umss_schedule_workitem
((PVOID) pdev_ext, umss_bulkonly_reset_recovery, pdev_ext->dev_mgr, pdev_ext->dev_handle))
{
umss_complete_request(pdev_ext, STATUS_IO_DEVICE_ERROR);
}
}
}
else
{
// error occurred, reset device
if (!umss_schedule_workitem
((PVOID) pdev_ext, umss_bulkonly_reset_recovery, pdev_ext->dev_mgr, pdev_ext->dev_handle))
{
umss_complete_request(pdev_ext, STATUS_IO_DEVICE_ERROR);
}
}
}
else if ((status != STATUS_SUCCESS) && (usb_halted(status)) && (pdev_ext->retry))
{
// Device stalled CSW transfer, retry once before failing
PULONG buf;
pdev_ext->retry = FALSE;
buf = usb_alloc_mem(NonPagedPool, 32);
buf[0] = (ULONG) pdev_ext;
buf[1] = (ULONG) purb->endp_handle;
if (!umss_schedule_workitem
((PVOID) buf, umss_bulkonly_reset_pipe_and_get_status, pdev_ext->dev_mgr, pdev_ext->dev_handle))
{
usb_free_mem(buf), buf = NULL;
usb_dbg_print(DBGLVL_MINIMUM,
("umss_bulkonly_get_status_complete(): Failed to allocate work-item to reset pipe!\n"));
TRAP();
umss_complete_request(pdev_ext, status);
}
}
else if (status != STATUS_CANCELLED)
{
// An error has occured. Reset the device.
if (!umss_schedule_workitem
((PVOID) pdev_ext, umss_bulkonly_reset_recovery, pdev_ext->dev_mgr, pdev_ext->dev_handle))
{
usb_dbg_print(DBGLVL_MINIMUM,
("umss_bulkonly_get_status_complete(): Failed to schedule work-item to reset pipe!\n"));
TRAP();
umss_complete_request(pdev_ext, status);
}
}
else
{
// the request is canceled
usb_dbg_print(DBGLVL_MINIMUM, ("umss_bulkonly_get_status_complete(): the request is canceled\n"));
umss_complete_request(pdev_ext, STATUS_CANCELLED);
}
usb_free_mem(purb);
purb = NULL;
return;
}
/*++
Routine Description:
Queries Bulk-Only device for maximum LUN number
Arguments:
DeviceExtension - Our device extension.
Return Value:
Maximum LUN number for device, or 0 if error occurred.
--*/
CHAR
umss_bulkonly_get_maxlun(IN PUMSS_DEVICE_EXTENSION pdev_ext)
{
PURB purb = NULL;
UCHAR max_lun;
NTSTATUS status;
purb = usb_alloc_mem(NonPagedPool, sizeof(URB));
if (!purb)
{
usb_dbg_print(DBGLVL_MINIMUM,
("umss_bulkonly_get_maxlun(): Failed to allocate URB, setting max LUN to 0\n"));
max_lun = 0;
}
else
{
// Build the get max lun command
UsbBuildVendorRequest(purb, (pdev_ext->dev_handle | 0xffff), &max_lun, sizeof(max_lun), 0xb1, //class, interface, in
BULK_ONLY_GET_MAX_LUN, 0, pdev_ext->pif_desc->bInterfaceNumber, NULL, NULL, 0);
// Send get max lun command to device
status = umss_sync_submit_urb(pdev_ext, purb);
if (status != STATUS_PENDING)
{
usb_dbg_print(DBGLVL_MINIMUM,
("umss_bulkonly_get_maxlun(): Get Max LUN command failed, setting max LUN to 0!\n"));
max_lun = 0;
}
}
if (purb)
usb_free_mem(purb);
usb_dbg_print(DBGLVL_MINIMUM, ("umss_bulkonly_get_maxlun(): Max LUN = %x\n", max_lun));
return max_lun;
}
PVOID
umss_get_buffer(PUMSS_DEVICE_EXTENSION pdev_ext, ULONG * buf_length)
{
PVOID buffer;
if ((pdev_ext->io_packet.flags & IOP_FLAG_STAGE_MASK) == IOP_FLAG_STAGE_NORMAL)
{
buffer = (PVOID) pdev_ext->io_packet.data_buffer;
*buf_length = pdev_ext->io_packet.data_length;
}
else if ((pdev_ext->io_packet.flags & IOP_FLAG_STAGE_MASK) == IOP_FLAG_STAGE_SENSE)
{
buffer = (PVOID) pdev_ext->io_packet.sense_data;
*buf_length = pdev_ext->io_packet.sense_data_length;
}
else
{
buffer = NULL;
*buf_length = 0;
}
return buffer;
}
BOOLEAN
umss_bulkonly_build_sense_cdb(PUMSS_DEVICE_EXTENSION pdev_ext, PCOMMAND_BLOCK_WRAPPER cbw)
{
UCHAR sub_class;
PUCHAR cdb;
if (pdev_ext == NULL || cbw == NULL)
return FALSE;
cdb = cbw->CBWCB;
RtlZeroMemory(cdb, MAX_CDB_LENGTH);
sub_class = pdev_ext->pif_desc->bInterfaceSubClass;
cdb[0] = SFF_REQUEST_SENSEE;
cdb[1] = pdev_ext->io_packet.lun << 5;
cdb[4] = 18;
switch (sub_class)
{
case UMSS_SUBCLASS_SFF8070I:
case UMSS_SUBCLASS_UFI:
{
cbw->bCBWLength = 12;
break;
}
case UMSS_SUBCLASS_RBC:
case UMSS_SUBCLASS_SCSI_TCS:
{
cbw->bCBWLength = 6;
break;
}
default:
return FALSE;
}
return TRUE;
}
NTSTATUS
umss_bulkonly_send_sense_req(PUMSS_DEVICE_EXTENSION pdev_ext)
{
PCOMMAND_BLOCK_WRAPPER cbw;
NTSTATUS status;
if (pdev_ext == NULL || pdev_ext->io_packet.sense_data == NULL
|| pdev_ext->io_packet.sense_data_length < 18)
return STATUS_INVALID_PARAMETER;
pdev_ext->retry = TRUE;
cbw = usb_alloc_mem(NonPagedPool, sizeof(COMMAND_BLOCK_WRAPPER));
RtlZeroMemory(cbw, sizeof(COMMAND_BLOCK_WRAPPER));
pdev_ext->io_packet.flags &= ~IOP_FLAG_STAGE_MASK;
pdev_ext->io_packet.flags |= IOP_FLAG_STAGE_SENSE;
cbw->dCBWSignature = CBW_SIGNATURE;
cbw->dCBWTag = 0;
cbw->dCBWDataTransferLength = pdev_ext->io_packet.sense_data_length;
cbw->bmCBWFlags = USB_DIR_IN;
cbw->bCBWLun = 0;
if (umss_bulkonly_build_sense_cdb(pdev_ext, cbw) == FALSE)
{
usb_free_mem(cbw);
cbw = NULL;
return STATUS_UNSUCCESSFUL;
}
status = umss_bulk_transfer(pdev_ext,
USB_DIR_OUT,
cbw, sizeof(COMMAND_BLOCK_WRAPPER), umss_bulkonly_send_cbw_completion);
if (status != STATUS_PENDING)
{
usb_free_mem(cbw);
cbw = NULL;
}
return status;
}
BOOLEAN
umss_clear_pass_through_length(PIO_PACKET io_packet)
{
//
// clear the respective data length to meet request of scsi pass through requirement.
//
BOOLEAN sense_stage;
ULONG ctrl_code;
PIO_STACK_LOCATION cur_stack;
PSCSI_PASS_THROUGH pass_through;
PSCSI_PASS_THROUGH_DIRECT pass_through_direct;
if (io_packet == NULL)
return FALSE;
if ((io_packet->flags & IOP_FLAG_SCSI_CTRL_TRANSFER) == 0)
return FALSE;
sense_stage = FALSE;
if (io_packet->flags & IOP_FLAG_STAGE_SENSE)
sense_stage = TRUE;
cur_stack = IoGetCurrentIrpStackLocation(io_packet->pirp);
ctrl_code = cur_stack->Parameters.DeviceIoControl.IoControlCode;
if (ctrl_code == IOCTL_SCSI_PASS_THROUGH_DIRECT)
{
pass_through_direct = io_packet->pirp->AssociatedIrp.SystemBuffer;
if (sense_stage)
pass_through_direct->SenseInfoLength = 0;
else
pass_through_direct->DataTransferLength = 0;
}
else if (ctrl_code == IOCTL_SCSI_PASS_THROUGH)
{
pass_through = io_packet->pirp->AssociatedIrp.SystemBuffer;
if (sense_stage)
pass_through->SenseInfoLength = 0;
else
pass_through->DataTransferLength = 0;
}
else
return FALSE;
return TRUE;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?