⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 io.c

📁 鼠标Windows驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
    PDEVICE_OBJECT      self;
    LONG                oldInterlock;
    KIRQL               irql;

    Print(DeviceExtension, DBG_READ_TRACE, ("Start Read: Enter\n"));

    irp = DeviceExtension->ReadIrp;

    while (1) {
        if ((DeviceExtension->Removed)  ||
            (!DeviceExtension->Started) ||
            (DeviceExtension->EnableCount == 0)) {

            Print(DeviceExtension, DBG_READ_INFO | DBG_READ_ERROR,
                  ("removing lock on start read\n"));

            //
            // Set the event so that the stop code can continue processing
            //
            KeSetEvent(&DeviceExtension->StopEvent, 0, FALSE);

            IoReleaseRemoveLock(&DeviceExtension->RemoveLock,
                                DeviceExtension->ReadIrp);

            return STATUS_UNSUCCESSFUL;
        }

        //
        // Make sure we have not been stopped
        //
        KeAcquireSpinLock(&DeviceExtension->PnpStateLock, &irql);
        if (DeviceExtension->Stopped) {
            KeReleaseSpinLock(&DeviceExtension->PnpStateLock, irql);

            //
            // Set the event so that the stop code can continue processing
            //
            KeSetEvent(&DeviceExtension->StopEvent, 0, FALSE);

            //
            // Release the remove lock that we acquired when we started the read
            // spinner irp
            //
            IoReleaseRemoveLock(&DeviceExtension->RemoveLock,
                                DeviceExtension->ReadIrp);

            return STATUS_SUCCESS;
        }

        //
        // It is important to only reuse the irp when we are holding onto the
        // spinlock, otherwise we can race
        //
        IoReuseIrp(irp, STATUS_SUCCESS);

        KeReleaseSpinLock(&DeviceExtension->PnpStateLock, irql);

        //
        // This is where things get interesting.  We don't want to call
        // SerialMouseStartRead if this read was completed synchronously by the
        // serial provider because we can potentially run out of stack space.
        //
        // Here is how we solve this:
        // At the beginning of StartRead(), the interlock is set to START_READ

        // IoCallDriver is called...
        //  o  If the read will be completed asynchronously, then StartRead()
        //     will continue executing and set the interlock to END_READ.
        //  o  If the request will be completed synchronously, then the
        //     completion routine will run before StartRead() has the chance of
        //     setting the interlock to END_READ.  We note this situation by
        //     setting the interlock to IMMEDIATE_READ in the completion function.
        //     Furthermore, StartRead() will not be called from the completion
        //     routine as it would be in the async case
        //  o  Upon setting the interlock to END_READ in StartReaD(), the
        //     previous value is examined.  If it is IMMEDIATE_READ, then
        //     StartRead() loops and calls IoCallDriver from the same location
        //     within the (call) stack frame.  If the previous value was *not*
        //     IMMEDIATE_READ, then StartRead() exits and the completion routine
        //     will be called in another context (and, thus, another stack) and
        //     make the next call to StartRead()
        //
#if DBG
        oldInterlock =
#endif
        InterlockedExchange(&DeviceExtension->ReadInterlock,
                            SERIAL_MOUSE_START_READ);

        //
        // END_READ should be the only value here!!!  If not, the state machine
        // of the interlock has been broken
        //
        ASSERT(oldInterlock == SERIAL_MOUSE_END_READ);

        //
        // start this read.
        //
        self = DeviceExtension->Self;

        //
        // Set the stack location for the serenum stack
        //
        // Remember to get the file pointer correct.
        // NOTE: we do not have any of the cool thread stuff set.
        //       therefore we need to make sure that we cut this IRP off
        //       at the knees when it returns. (STATUS_MORE_PROCESSING_REQUIRED)
        //
        // Note also that serial does buffered i/o
        //

        irp->AssociatedIrp.SystemBuffer = (PVOID) DeviceExtension->ReadBuffer;

        stack = IoGetNextIrpStackLocation(irp);
        stack->Parameters.Read.Length = 1;
        stack->Parameters.Read.ByteOffset.QuadPart = (LONGLONG) 0;
        stack->MajorFunction = IRP_MJ_READ;

        //
        // Hook a completion routine for when the device completes.
        //
        IoSetCompletionRoutine(irp,
                               SerialMouseReadComplete,
                               DeviceExtension,
                               TRUE,
                               TRUE,
                               TRUE);

        status = IoCallDriver(DeviceExtension->TopOfStack, irp);

        if (InterlockedExchange(&DeviceExtension->ReadInterlock,
                                SERIAL_MOUSE_END_READ) !=
            SERIAL_MOUSE_IMMEDIATE_READ) {
            //
            // The read is asynch, will call SerialMouseStartRead from the
            // completion routine
            //
            Print(DeviceExtension, DBG_READ_NOISE, ("read is pending\n"));
            break;
        }
#if DBG
        else {
            //
            // The read was synchronous (probably bytes in the buffer).  The
            // completion routine will not call SerialMouseStartRead, so we
            // just loop here.  This is to prevent us from running out of stack
            // space if always call StartRead from the completion routine
            //
            Print(DeviceExtension, DBG_READ_NOISE, ("read is looping\n"));
        }
#endif
    }

    return status;
}

//
// Stripped down version of SerialMouseIoSyncIoctlEx that
// doesn't use input or output buffers
//
NTSTATUS
SerialMousepIoSyncIoctl(
    BOOLEAN          Internal,
    ULONG            Ioctl,
    PDEVICE_OBJECT   DeviceObject,
    PKEVENT          Event,
    PIO_STATUS_BLOCK Iosb)
{
    return SerialMousepIoSyncIoctlEx(Internal,
                                     Ioctl,
                                     DeviceObject,
                                     Event,
                                     Iosb,
                                     NULL,
                                     0,
                                     NULL,
                                     0);
}

NTSTATUS
SerialMousepIoSyncIoctlEx(
    BOOLEAN          Internal,
    ULONG            Ioctl,                     // io control code
    PDEVICE_OBJECT   DeviceObject,              // object to call
    PKEVENT          Event,                     // event to wait on
    PIO_STATUS_BLOCK Iosb,                      // used inside IRP
    PVOID            InBuffer,      OPTIONAL    // input buffer
    ULONG            InBufferLen,   OPTIONAL    // input buffer length
    PVOID            OutBuffer,     OPTIONAL    // output buffer
    ULONG            OutBufferLen)  OPTIONAL    // output buffer length
/*++

Routine Description:
    Performs a synchronous IO control request by waiting on the event object
    passed to it.  The IRP is deallocated by the IO system when finished.

Return value:
    NTSTATUS

--*/
{
    PIRP                irp;
    NTSTATUS            status;

    KeClearEvent(Event);

    //
    // Allocate an IRP - No need to release
    // When the next-lower driver completes this IRP, the I/O Manager releases it.
    //
    if (NULL == (irp = IoBuildDeviceIoControlRequest(Ioctl,
                                                     DeviceObject,
                                                     InBuffer,
                                                     InBufferLen,
                                                     OutBuffer,
                                                     OutBufferLen,
                                                     Internal,
                                                     Event,
                                                     Iosb))) {

        return STATUS_INSUFFICIENT_RESOURCES;
    }

     status = IoCallDriver(DeviceObject, irp);

     if (STATUS_PENDING == status) {
         //
         // wait for it...
         //
         status = KeWaitForSingleObject(Event,
                                        Executive,
                                        KernelMode,
                                        FALSE, // Not alertable
                                        NULL); // No timeout structure
     }

     if (NT_SUCCESS(status)) {
         status = Iosb->Status;
     }

     return status;
}

NTSTATUS
SerialMouseSetReadTimeouts(
    PDEVICE_EXTENSION DeviceExtension,
    ULONG               Timeout
    )
{
    NTSTATUS        status;
    SERIAL_TIMEOUTS serialTimeouts;
    KEVENT          event;
    IO_STATUS_BLOCK iosb;

    KeInitializeEvent(&event, NotificationEvent, FALSE);
    RtlZeroMemory(&serialTimeouts, sizeof(SERIAL_TIMEOUTS));

    if (Timeout != 0) {
        serialTimeouts.ReadIntervalTimeout = MAXULONG;
        serialTimeouts.ReadTotalTimeoutMultiplier = MAXULONG;
        serialTimeouts.ReadTotalTimeoutConstant = Timeout;
    }

    status =  SerialMouseIoSyncIoctlEx(IOCTL_SERIAL_SET_TIMEOUTS,
                                       DeviceExtension->TopOfStack,
                                       &event,
                                       &iosb,
                                       &serialTimeouts,
                                       sizeof(SERIAL_TIMEOUTS),
                                       NULL,
                                       0);

    return status;
}

NTSTATUS
SerialMouseReadSerialPortComplete(
    IN PDEVICE_OBJECT       DeviceObject,
    IN PIRP                 Irp,
    IN PKEVENT              Event
    )
{
    UNREFERENCED_PARAMETER(DeviceObject);

    KeSetEvent(Event, 0, FALSE);

    return STATUS_MORE_PROCESSING_REQUIRED;
}

NTSTATUS
SerialMouseReadSerialPort (
    PDEVICE_EXTENSION   DeviceExtension,
    PCHAR               ReadBuffer,
    USHORT              Buflen,
    PUSHORT             ActualBytesRead
    )
/*++

Routine Description:
    Performs a synchronous read on the serial port.  Used during setup so that
    the type of device can be determined.

Return value:
    NTSTATUS - STATUS_SUCCESS if the read was successful, error code otherwise

--*/
{
    NTSTATUS            status = STATUS_SUCCESS;
    PIRP                irp;
    KEVENT              event;
    IO_STATUS_BLOCK     iosb;
    PDEVICE_OBJECT      self;
    PIO_STACK_LOCATION  stack;
    SERIAL_TIMEOUTS     serialTimeouts;

⌨️ 快捷键说明

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