umss.c

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

C
1,933
字号
    PUSB_DEV pdev;

    pdev_ext = dev_obj->DeviceExtension;

    // lock the dev, the pdev_ext->pif_desc won't go away.
    if ((status = usb_query_and_lock_dev(pdev_ext->dev_mgr, pdev_ext->dev_handle, &pdev)) != STATUS_SUCCESS)
    {
        usb_dbg_print(DBGLVL_MAXIMUM, ("umss_start_io(): error, device is not valid\n"));
        UMSS_COMPLETE_START_IO(dev_obj, status, io_packet->pirp);
        return;
    }

    if (pdev_ext->pif_desc->bInterfaceProtocol == PROTOCOL_BULKONLY)
    {
        status = umss_bulkonly_startio(pdev_ext, io_packet);
    }
    else if (pdev_ext->pif_desc->bInterfaceProtocol == PROTOCOL_CB
             || pdev_ext->pif_desc->bInterfaceProtocol == PROTOCOL_CBI)
    {
        status = umss_cbi_startio(pdev_ext, io_packet);
    }
    else
    {
        status = STATUS_DEVICE_PROTOCOL_ERROR;
    }
    usb_unlock_dev(pdev);
    UMSS_COMPLETE_START_IO(dev_obj, status, io_packet->pirp);
    return;
}

VOID
NTAPI
umss_start_io(IN PDEVICE_OBJECT dev_obj, IN PIRP irp)
{
    ULONG ctrl_code;
    NTSTATUS status;
    PIO_STACK_LOCATION irp_stack;
    PUMSS_DEVICE_EXTENSION pdev_ext;
    IO_PACKET io_packet;
    PUSER_IO_PACKET user_io_packet;

    if (dev_obj == NULL || irp == NULL)
        return;

    status = STATUS_SUCCESS;

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

    if (irp_stack->MajorFunction == IRP_MJ_SCSI)
    {
        umss_process_srb(dev_obj, irp);
        return;
    }

    if (irp_stack->MajorFunction != IRP_MJ_DEVICE_CONTROL)
    {
        UMSS_COMPLETE_START_IO(dev_obj, STATUS_INVALID_DEVICE_REQUEST, irp);
    }

    switch (ctrl_code)
    {
        case IOCTL_UMSS_SUBMIT_CDB_IN:
        case IOCTL_UMSS_SUBMIT_CDB_OUT:
        case IOCTL_UMSS_SUBMIT_CDB:
        {
            if (irp_stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(USER_IO_PACKET))
            {
                UMSS_COMPLETE_START_IO(dev_obj, STATUS_INVALID_PARAMETER, irp);
            }

            user_io_packet = (PUSER_IO_PACKET) irp->AssociatedIrp.SystemBuffer;

            if (user_io_packet->sub_class != pdev_ext->pif_desc->bInterfaceSubClass)
            {
                // not agree with the dev's subclass
                UMSS_COMPLETE_START_IO(dev_obj, STATUS_DEVICE_PROTOCOL_ERROR, irp);
            }

            RtlZeroMemory(&io_packet, sizeof(io_packet));
            io_packet.cdb_length = user_io_packet->cdb_length;
            io_packet.lun = user_io_packet->lun;

            RtlCopyMemory(io_packet.cdb, user_io_packet->cdb, MAX_CDB_LENGTH);

            if (ctrl_code == IOCTL_UMSS_SUBMIT_CDB_IN)
                io_packet.flags |= USB_DIR_IN;

            if (ctrl_code != IOCTL_UMSS_SUBMIT_CDB)
            {
                if (irp_stack->Parameters.DeviceIoControl.OutputBufferLength == 0)
                    UMSS_COMPLETE_START_IO(dev_obj, STATUS_BUFFER_TOO_SMALL, irp);

                io_packet.data_buffer = MmGetSystemAddressForMdl(irp->MdlAddress);
                io_packet.data_length = irp_stack->Parameters.DeviceIoControl.OutputBufferLength;

                if (io_packet.data_length > MAX_BULK_TRANSFER_LENGTH)
                    UMSS_COMPLETE_START_IO(dev_obj, STATUS_BUFFER_TOO_SMALL, irp);

                //synchronize the buffer
                if (io_packet.flags & USB_DIR_IN)
                    KeFlushIoBuffers(irp->MdlAddress, TRUE, TRUE);
                else
                    KeFlushIoBuffers(irp->MdlAddress, FALSE, TRUE);
            }

            io_packet.pirp = irp;
            umss_submit_io_packet(dev_obj, &io_packet);
            return;
        }
        case IOCTL_SCSI_PASS_THROUGH:
        {
            PSCSI_PASS_THROUGH pass_through;
            IO_PACKET io_packet;

            pass_through = irp->AssociatedIrp.SystemBuffer;

            if (pass_through->DataTransferLength &&
                pass_through->DataBufferOffset != sizeof(SCSI_PASS_THROUGH))
                UMSS_COMPLETE_START_IO(dev_obj, STATUS_INVALID_PARAMETER, irp);

            if (pass_through->SenseInfoLength &&
                (pass_through->SenseInfoOffset !=
                 pass_through->DataBufferOffset + pass_through->DataTransferLength))
                UMSS_COMPLETE_START_IO(dev_obj, STATUS_INVALID_PARAMETER, irp);

            if (irp_stack->Parameters.DeviceIoControl.InputBufferLength <
                (sizeof(SCSI_PASS_THROUGH) +
                 pass_through->SenseInfoLength + pass_through->DataTransferLength))
                UMSS_COMPLETE_START_IO(dev_obj, STATUS_BUFFER_TOO_SMALL, irp);

            RtlZeroMemory(&io_packet, sizeof(io_packet));

            io_packet.flags |= IOP_FLAG_SCSI_CTRL_TRANSFER;
            if (pass_through->DataIn)
                io_packet.flags |= IOP_FLAG_DIR_IN;

            io_packet.data_buffer = (PVOID) & pass_through[1];
            io_packet.data_length = pass_through->DataTransferLength;

            if (pass_through->SenseInfoLength)
            {
                io_packet.sense_data = ((PUCHAR) pass_through) + pass_through->SenseInfoOffset;
                io_packet.sense_data_length = pass_through->SenseInfoLength;
                io_packet.flags |= IOP_FLAG_REQ_SENSE;
            }

            io_packet.cdb_length = pass_through->CdbLength;
            RtlCopyMemory(io_packet.cdb, pass_through->Cdb, sizeof(io_packet.cdb));
            io_packet.lun = 0;
            io_packet.pirp = irp;
            umss_submit_io_packet(dev_obj, &io_packet);
            return;
        }
        case IOCTL_SCSI_PASS_THROUGH_DIRECT:
        {
            PSCSI_PASS_THROUGH_DIRECT pass_through_direct;
            IO_PACKET io_packet;

            pass_through_direct = irp->AssociatedIrp.SystemBuffer;

            if (pass_through_direct->SenseInfoLength &&
                pass_through_direct->SenseInfoOffset != sizeof(SCSI_PASS_THROUGH_DIRECT))
                UMSS_COMPLETE_START_IO(dev_obj, STATUS_INVALID_PARAMETER, irp);

            if (irp_stack->Parameters.DeviceIoControl.InputBufferLength <
                sizeof(SCSI_PASS_THROUGH_DIRECT) + pass_through_direct->SenseInfoLength)
                UMSS_COMPLETE_START_IO(dev_obj, STATUS_BUFFER_TOO_SMALL, irp);

            RtlZeroMemory(&io_packet, sizeof(io_packet));

            io_packet.flags |= IOP_FLAG_SCSI_CTRL_TRANSFER;
            if (pass_through_direct->DataIn)
                io_packet.flags |= IOP_FLAG_DIR_IN;

            io_packet.data_buffer = pass_through_direct->DataBuffer;
            io_packet.data_length = pass_through_direct->DataTransferLength;

            if (pass_through_direct->SenseInfoLength)
            {
                io_packet.sense_data = ((PUCHAR) pass_through_direct) + pass_through_direct->SenseInfoOffset;
                io_packet.sense_data_length = pass_through_direct->SenseInfoLength;
                io_packet.flags |= IOP_FLAG_REQ_SENSE;
            }

            io_packet.cdb_length = pass_through_direct->CdbLength;
            RtlCopyMemory(io_packet.cdb, pass_through_direct->Cdb, sizeof(io_packet.cdb));
            io_packet.lun = 0;
            io_packet.pirp = irp;
            umss_submit_io_packet(dev_obj, &io_packet);
            return;
        }
        case IOCTL_SUBMIT_URB_RD:
        case IOCTL_SUBMIT_URB_NOIO:
        case IOCTL_SUBMIT_URB_WR:
        {
            gendrv_startio(dev_obj, irp);
            return;
        }
        default:
            UMSS_COMPLETE_START_IO(dev_obj, STATUS_INVALID_DEVICE_REQUEST, irp);
    }
    return;
}

// bugbug!!! there can not be sent IOCTL_SUBMIT_URB_XXX while
// the IOCTL_SUBMIT_CDB_XXX are active. may confuse the device.
// not resolved yet.
NTSTATUS
umss_dispatch_routine(PDEVICE_OBJECT pdev_obj, PIRP irp)
{
    ULONG ctrl_code;
    NTSTATUS status;
    PIO_STACK_LOCATION irp_stack;
    PUMSS_DEVICE_EXTENSION pdev_ext;
    USE_BASIC_NON_PENDING_IRQL;

    if (pdev_obj == NULL || irp == NULL)
        return STATUS_INVALID_PARAMETER;

    status = STATUS_SUCCESS;
    irp_stack = IoGetCurrentIrpStackLocation(irp);
    ctrl_code = irp_stack->Parameters.DeviceIoControl.IoControlCode;

    pdev_ext = (PUMSS_DEVICE_EXTENSION) pdev_obj->DeviceExtension;

    switch (irp_stack->MajorFunction)
    {
        case IRP_MJ_CREATE:
        case IRP_MJ_CLOSE:
        {
            return dev_mgr_dispatch(pdev_ext->dev_mgr, irp);
        }
        case IRP_MJ_INTERNAL_DEVICE_CONTROL:
        {
            // function code to receive scsi request
            UMSS_EXIT_DISPATCH(pdev_obj, STATUS_PENDING, irp);
        }
        case IRP_MJ_DEVICE_CONTROL:
        {
            switch (ctrl_code)
            {
                case IOCTL_UMSS_SET_FDO:
                {
                    PDEVICE_OBJECT fdo;
                    PUSB_DEV pdev;

                    if (irp_stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(PDEVICE_OBJECT))
                    {
                        EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
                    }

                    fdo = (PDEVICE_OBJECT) ((PULONG) irp->AssociatedIrp.SystemBuffer)[0];
                    if (fdo == NULL)
                        EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
                    //
                    // we have to test the usb dev's state to determine whether set or not the fdo
                    //

                    if (usb_query_and_lock_dev(pdev_ext->dev_mgr, pdev_ext->dev_handle, &pdev) !=
                        STATUS_SUCCESS)
                        EXIT_DISPATCH(STATUS_DEVICE_DOES_NOT_EXIST, irp);

                    lock_dev(pdev, FALSE);

                    if (dev_state(pdev) >= USB_DEV_STATE_BEFORE_ZOMB || dev_state(pdev) == USB_DEV_STATE_ZOMB)
                    {
                        unlock_dev(pdev, FALSE);
                        usb_unlock_dev(pdev);
                        EXIT_DISPATCH(STATUS_DEVICE_DOES_NOT_EXIST, irp);
                    }

                    pdev_ext->fdo = fdo;
                    unlock_dev(pdev, FALSE);
                    usb_unlock_dev(pdev);
                    irp->IoStatus.Information = 0;
                    EXIT_DISPATCH(STATUS_SUCCESS, irp);
                }

                case IOCTL_GET_DEV_DESC:
                {
                    PGET_DEV_DESC_REQ pgddr;
                    if (irp_stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(GET_DEV_DESC_REQ))
                    {
                        EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
                    }
                    pgddr = irp->AssociatedIrp.SystemBuffer;
                    if (pgddr->dev_handle != (pdev_ext->dev_handle & 0xffff0000))
                    {
                        EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
                    }
                    // an immediate request
                    return dev_mgr_dispatch(pdev_ext->dev_mgr, irp);
                }
                case IOCTL_SUBMIT_URB_RD:
                case IOCTL_SUBMIT_URB_NOIO:
                case IOCTL_SUBMIT_URB_WR:
                {
                    PURB purb;
                    DEV_HANDLE endp_handle;

                    if (irp_stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(URB))
                    {
                        EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
                    }

                    purb = (PURB) irp->AssociatedIrp.SystemBuffer;
                    endp_handle = purb->endp_handle;
                    if (!default_endp_handle(endp_handle))
                    {
                        //no permit to other interface if interface dev
                        if ((pdev_ext->flags & UMSS_DEV_FLAG_IF_DEV)
                            && if_idx_from_handle(endp_handle) != pdev_ext->if_idx)
                            EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
                    }
                    // FIXME: this is dangeous
                    // return dev_mgr_dispatch( pdev_ext->dev_mgr, irp );
                    UMSS_EXIT_DISPATCH(pdev_obj, STATUS_PENDING, irp);
                }
                case IOCTL_GET_DEV_HANDLE:
                {
                    if (irp_stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(LONG))
                        EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);

                    *((PLONG) irp->AssociatedIrp.SystemBuffer) = pdev_ext->dev_handle;
                    irp->IoStatus.Information = sizeof(LONG);
                    EXIT_DISPATCH(STATUS_SUCCESS, irp);
                }

                    //
                    // request from scsi class driver
                    //
                case IOCTL_SCSI_PASS_THROUGH:
                case IOCTL_SCSI_PASS_THROUGH_DIRECT:
                    //
                    // direct cdb request
                    //
                case IOCTL_UMSS_SUBMIT_CDB:
                case IOCTL_UMSS_SUBMIT_CDB_OUT:
                case IOCTL_UMSS_SUBMIT_CDB_IN:
                {
                    UMSS_EXIT_DISPATCH(pdev_obj, STATUS_PENDING, irp);
                }
                case IOCTL_SCSI_GET_INQUIRY_DATA:
                {
                    PSCSI_ADAPTER_BUS_INFO adapter_info;
                    PSCSI_BUS_DATA bus_data;
                    PSCSI_INQUIRY_DATA inq_dat;
                    PINQUIRYDATA inq;
                    IO_PACKET io_packet;
                    ULONG required_size;

                    required_size = sizeof(SCSI_ADAPTER_BUS_INFO)
                        + sizeof(SCSI_BUS_DATA) + sizeof(SCSI_INQUIRY_DATA) + INQUIRYDATABUFFERSIZE;

                    if (irp_stack->Parameters.DeviceIoControl.OutputBufferLength < required_size)
                        UMSS_EXIT_DISPATCH(pdev_obj, STATUS_BUFFER_TOO_SMALL, irp);

                    RtlZeroMemory(&io_packet, sizeof(io_packet));

                    adapter_info = irp->AssociatedIrp.SystemBuffer;
                    adapter_info->NumberOfBuses = 1;
                    bus_data = &adapter_info->BusData[0];
                    bus_data->NumberOfLogicalUnits = 1;
                    bus_data->InitiatorBusId = 0;
                    bus_data->InquiryDataOffset = sizeof(SCSI_ADAPTER_BUS_INFO);
                    inq_dat = (PVOID) & bus_data[1];
                    inq_dat->PathId = 0;
                    inq_dat->TargetId = pdev_ext->umss_dev_id;
                    //
                    // this is the dev_id for usb dev_manager
                    //
                    inq_dat->Lun = (UCHAR) (pdev_ext->dev_handle >> 16);
                    inq_dat->DeviceClaimed = FALSE;
                    inq_dat->InquiryDataLength = 36;
                    inq_dat->NextInquiryDataOffset = 0;
                    inq = (PINQUIRYDATA) inq_dat->InquiryData;

                    RtlZeroMemory(inq, sizeof(INQUIRYDATA));
                    inq->DeviceType = DIRECT_ACCESS_DEVICE;
                    inq->DeviceTypeQualifier = 0;
                    inq->RemovableMedia = 1;

                    //
                    // pretend to comply scsi primary 2 command set
                    //

⌨️ 快捷键说明

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