bulkonly.c

来自「ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机」· 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 + -
显示快捷键?