umss.c

来自「ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机」· C语言 代码 · 共 1,933 行 · 第 1/5 页

C
1,933
字号

                    inq->Versions = 0x04;

                    //
                    // the format is in scsi-2 format
                    //

                    inq->ResponseDataFormat = 0x02;

                    //
                    // we are the poor scsi device
                    //

                    inq->AdditionalLength = 31;
                    inq->SoftReset = 0;
                    inq->CommandQueue = 0;
                    inq->LinkedCommands = 0;
                    inq->RelativeAddressing = 0;
                    RtlCopyMemory(&inq->VendorId, "Unknown", 7);
                    RtlCopyMemory(&inq->ProductId, "USB Mass Storage", 16);
                    irp->IoStatus.Information = required_size;
                    EXIT_DISPATCH(STATUS_SUCCESS, irp);
                }
                case IOCTL_SCSI_GET_CAPABILITIES:
                {
                    PIO_SCSI_CAPABILITIES port_cap;

                    if (irp_stack->Parameters.DeviceIoControl.OutputBufferLength <
                        sizeof(IO_SCSI_CAPABILITIES))
                        EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);

                    port_cap = (PIO_SCSI_CAPABILITIES) irp->AssociatedIrp.SystemBuffer;
                    port_cap->Length = sizeof(IO_SCSI_CAPABILITIES);
                    port_cap->MaximumTransferLength = 65536;
                    port_cap->MaximumPhysicalPages = 65536 / PAGE_SIZE;
                    port_cap->SupportedAsynchronousEvents = 0;
                    port_cap->AlignmentMask = 0x10;
                    port_cap->TaggedQueuing = FALSE;
                    port_cap->AdapterScansDown = FALSE;
                    port_cap->AdapterUsesPio = FALSE;
                    irp->IoStatus.Information = sizeof(IO_SCSI_CAPABILITIES);
                    EXIT_DISPATCH(STATUS_SUCCESS, irp);
                }
                case IOCTL_SCSI_GET_ADDRESS:
                {
                    PSCSI_ADDRESS paddr;
                    if (irp_stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SCSI_ADDRESS))
                        EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);

                    paddr = (PSCSI_ADDRESS) irp->AssociatedIrp.SystemBuffer;

                    paddr->Length = sizeof(SCSI_ADDRESS);
                    paddr->PortNumber = 0;
                    paddr->PathId = 0;
                    paddr->TargetId = pdev_ext->umss_dev_id;
                    paddr->Lun = (UCHAR) (pdev_ext->dev_handle >> 16);
                    irp->IoStatus.Information = sizeof(SCSI_ADDRESS);
                    EXIT_DISPATCH(STATUS_SUCCESS, irp);
                }
                case IOCTL_SCSI_RESCAN_BUS:
                {
                    irp->IoStatus.Information = 0;
                    EXIT_DISPATCH(STATUS_SUCCESS, irp);
                }
                default:
                {
                    EXIT_DISPATCH(STATUS_INVALID_DEVICE_REQUEST, irp);
                }
            }
        }
    }
    EXIT_DISPATCH(STATUS_NOT_SUPPORTED, irp);
}

VOID
umss_reset_pipe_completion(PURB purb, PVOID context)
{
    PUMSS_DEVICE_EXTENSION pdev_ext;
    if (context == NULL)
        return;

    pdev_ext = (PUMSS_DEVICE_EXTENSION) context;
    pdev_ext->reset_pipe_status = purb->status;
    KeSetEvent(&pdev_ext->sync_event, 0, FALSE);
    return;
}

//can only be called at passive level
NTSTATUS
umss_reset_pipe(PUMSS_DEVICE_EXTENSION pdev_ext, DEV_HANDLE endp_handle)
{
    NTSTATUS status;
    PUSB_DEV pdev;

    if (pdev_ext == NULL)
        return STATUS_INVALID_PARAMETER;

    status = usb_query_and_lock_dev(pdev_ext->dev_mgr, pdev_ext->dev_handle, &pdev);

    if (status != STATUS_SUCCESS)
        return STATUS_UNSUCCESSFUL;

    status = usb_reset_pipe_ex(pdev_ext->dev_mgr, endp_handle, umss_reset_pipe_completion, pdev_ext);

    if (status == STATUS_PENDING)
    {
        KeWaitForSingleObject(&pdev_ext->sync_event, Executive, KernelMode, TRUE, NULL);
        status = pdev_ext->reset_pipe_status;
    }
    usb_unlock_dev(pdev);
    return status;
}

BOOLEAN
umss_gen_result_srb(PIO_PACKET io_packet, PSCSI_REQUEST_BLOCK srb, NTSTATUS status)
{

    if (srb == NULL || io_packet == NULL)
    {
        return FALSE;
    }
    if (status == STATUS_SUCCESS)
    {
        PULONG dest_buf, src_buf;
        ULONG i;

        srb->SrbStatus = SRB_STATUS_SUCCESS;

        io_packet->pirp->IoStatus.Information = srb->DataTransferLength;
        if ((io_packet->pirp->Flags & IRP_READ_OPERATION) && !(io_packet->pirp->Flags & IRP_PAGING_IO))
        {
            src_buf = (PULONG) io_packet->data_buffer;
            dest_buf = (PULONG) srb->DataBuffer;
            if (src_buf && dest_buf)
            {
                for(i = 0; i < (srb->DataTransferLength >> 2); i++)
                {
                    dest_buf[i] = src_buf[i];
                }
            }
        }
    }
    else if (status == STATUS_DEVICE_DOES_NOT_EXIST)
    {
        PSENSE_DATA sense_buf;
        srb->SrbStatus = SRB_STATUS_NO_DEVICE;
        srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;

        //
        // let's build the srb status for class driver
        //

        srb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
        sense_buf = (PSENSE_DATA) srb->SenseInfoBuffer;

        if (!(srb->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE))
        {
            RtlZeroMemory(srb->SenseInfoBuffer, srb->SenseInfoBufferLength);
            sense_buf->ErrorCode = 0x70;
            sense_buf->Valid = 1;
            sense_buf->SenseKey = SCSI_SENSE_NOT_READY;
            sense_buf->AdditionalSenseCode = SCSI_ADSENSE_NO_MEDIA_IN_DEVICE;
            sense_buf->AdditionalSenseLength = 10;
        }
    }
    else if (status == USB_STATUS_STALL_PID || status == USB_STATUS_CRC ||
             status == USB_STATUS_BTSTUFF || status == USB_STATUS_DATA_OVERRUN)
    {
        PSENSE_DATA sense_buf;
        srb->SrbStatus = SRB_STATUS_ERROR;
        srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;

        srb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
        sense_buf = (PSENSE_DATA) srb->SenseInfoBuffer;

        if (!(srb->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE))
        {
            RtlZeroMemory(srb->SenseInfoBuffer, srb->SenseInfoBufferLength);
            sense_buf->ErrorCode = 0x70;
            sense_buf->Valid = 1;
            sense_buf->SenseKey = SCSI_SENSE_HARDWARE_ERROR;
            sense_buf->AdditionalSenseCode = 0;
            sense_buf->AdditionalSenseLength = 10;
        }
    }
    else
    {
        srb->SrbStatus = SRB_STATUS_ERROR;
    }

    if ((io_packet->pirp->Flags & (IRP_READ_OPERATION | IRP_WRITE_OPERATION))
        && !(io_packet->pirp->Flags & IRP_PAGING_IO))
    {
        if (io_packet->data_buffer)
        {
            usb_free_mem(io_packet->data_buffer);
            io_packet->data_buffer = NULL;
        }
    }
    return TRUE;
}

BOOLEAN
umss_gen_result_ctrl(PDEVICE_OBJECT dev_obj, PIRP irp, NTSTATUS status)
{
    PIO_STACK_LOCATION irp_stack;
    ULONG ctrl_code;
    PUMSS_DEVICE_EXTENSION pdev_ext;

    if (irp == NULL)
        return FALSE;

    irp->IoStatus.Information = 0;
    irp_stack = IoGetCurrentIrpStackLocation(irp);
    ctrl_code = irp_stack->Parameters.DeviceIoControl.IoControlCode;
    pdev_ext = dev_obj->DeviceExtension;

    switch (ctrl_code)
    {
        case IOCTL_SCSI_PASS_THROUGH:
        {
            PSCSI_PASS_THROUGH pass_through;
            pass_through = irp->AssociatedIrp.SystemBuffer;
            irp->IoStatus.Status = status;

            // we have set these two value in bulkonly.c when data transfer complete
            // pass_through_direct->DataTransferLength = pdev_ext->io_packet.data_length;
            // pass_through_direct->SenseInfoLength = pdev_ext->io_packet.sense_data_length;

            if (status == STATUS_SUCCESS)
                irp->IoStatus.Information = pass_through->SenseInfoOffset + pass_through->SenseInfoLength;
            else
                pass_through->ScsiStatus = SCSISTAT_CHECK_CONDITION;
            return TRUE;
        }
        case IOCTL_SCSI_PASS_THROUGH_DIRECT:
        {
            PSCSI_PASS_THROUGH_DIRECT pass_through_direct;

            pass_through_direct = irp->AssociatedIrp.SystemBuffer;
            pass_through_direct->ScsiStatus = 0;
            irp->IoStatus.Status = status;

            // we have set these two value in bulkonly.c when data transfer complete
            // pass_through_direct->DataTransferLength = pdev_ext->io_packet.data_length;
            // pass_through_direct->SenseInfoLength = pdev_ext->io_packet.sense_data_length;

            if (status == STATUS_SUCCESS)
                irp->IoStatus.Information =
                    pass_through_direct->SenseInfoOffset + pass_through_direct->SenseInfoLength;
            else
                pass_through_direct->ScsiStatus = SCSISTAT_CHECK_CONDITION;

            return TRUE;
        }
    }
    return FALSE;
}


VOID
umss_complete_request(PUMSS_DEVICE_EXTENSION pdev_ext, NTSTATUS status)
{
    PIRP pirp;
    KIRQL old_irql;

    PDEVICE_OBJECT dev_obj;
    PIO_STACK_LOCATION irp_stack;

    usb_dbg_print(DBGLVL_MAXIMUM, ("umss_complete_request(): entering...\n"));

    pirp = pdev_ext->io_packet.pirp;
    dev_obj = pdev_ext->pdo;

    irp_stack = IoGetCurrentIrpStackLocation(pirp);

    if (pdev_ext->io_packet.flags & IOP_FLAG_SRB_TRANSFER)
    {
        if (pdev_ext->pif_desc->bInterfaceSubClass == UMSS_SUBCLASS_SFF8070I)
        {
            umss_fix_sff_result(&pdev_ext->io_packet, irp_stack->Parameters.Scsi.Srb);
        }
        umss_gen_result_srb(&pdev_ext->io_packet, irp_stack->Parameters.Scsi.Srb, status);
    }
    else if (pdev_ext->io_packet.flags & IOP_FLAG_SCSI_CTRL_TRANSFER)
        umss_gen_result_ctrl(dev_obj, pirp, status);

    //this device has its irp queued
    if (status == STATUS_CANCELLED)
    {
        IoAcquireCancelSpinLock(&old_irql);
        if (dev_obj->CurrentIrp == pirp)
        {
            IoReleaseCancelSpinLock(old_irql);
            IoStartNextPacket(dev_obj, FALSE);
        }
        else
        {
            KeRemoveEntryDeviceQueue(&dev_obj->DeviceQueue, &pirp->Tail.Overlay.DeviceQueueEntry);
            IoReleaseCancelSpinLock(old_irql);
        }
    }
    else
        // all requests come to this point from the irp queue
        IoStartNextPacket(dev_obj, FALSE);

    pirp->IoStatus.Status = status;

    if (status != STATUS_SUCCESS)
        pirp->IoStatus.Information = 0;

    IoCompleteRequest(pirp, IO_NO_INCREMENT);
    return;
}

BOOLEAN
umss_if_connect(PDEV_CONNECT_DATA params, DEV_HANDLE if_handle)
{
    PURB purb;
    LONG if_idx, i;
    PUCHAR desc_buf;
    NTSTATUS status;
    PUSB_DEV pdev;
    PUSB_DRIVER pdrvr;
    PUSB_INTERFACE_DESC pif_desc;
    PUSB_CTRL_SETUP_PACKET psetup;
    PUMSS_DEVICE_EXTENSION pdev_ext;
    PUSB_CONFIGURATION_DESC pconfig_desc;
    PUSB_DEV_MANAGER dev_mgr;
    PUSB_ENDPOINT_DESC pendp_desc;
    PUMSS_DRVR_EXTENSION pdrvr_ext;
    PDEVICE_OBJECT pdev_obj;
    USE_BASIC_NON_PENDING_IRQL;

    //configuration is already set
    purb = NULL;
    desc_buf = NULL;
    pdev = NULL;

    usb_dbg_print(DBGLVL_MAXIMUM, ("umss_if_connect(): entering...\n"));

    if (params == NULL)
        return FALSE;

    dev_mgr = params->dev_mgr;
    pdrvr = params->pdriver;

    if_idx = if_idx_from_handle(if_handle);

    purb = usb_alloc_mem(NonPagedPool, sizeof(URB));
    if (purb == NULL)
        goto ERROR_OUT;

    desc_buf = usb_alloc_mem(NonPagedPool, 512);
    if (desc_buf == NULL)
        goto ERROR_OUT;

    psetup = (PUSB_CTRL_SETUP_PACKET) (purb)->setup_packet;
    urb_init((purb));

    // now let's get the descs, one configuration, one interface and two endpoint
    psetup = (PUSB_CTRL_SETUP_PACKET) (purb)->setup_packet;
    purb->endp_handle = if_handle | 0xffff;
    purb->data_buffer = desc_buf;
    purb->data_length = 512;
    purb->completion = NULL;    // this is an immediate request, no needs completion
    purb->context = dev_mgr;
    purb->reference = 0;
    psetup->bmRequestType = 0x80;
    psetup->bRequest = USB_REQ_GET_DESCRIPTOR;
    psetup->wValue = USB_DT_CONFIG << 8;
    psetup->wIndex = 0;
    psetup->wLength = 512;

    status = usb_submit_urb(dev_mgr, purb);
    if (status == STATUS_PENDING)
    {
        TRAP();
    }
    usb_free_mem(purb);
    purb = NULL;

    if (status != STATUS_SUCCESS)
    {
        goto ERROR_OUT;
    }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?