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

📄 io.c

📁 书中的主要程序文件。在打开例题的.dsw文件后,请读者在 tools菜单下的 Options 的 Directories 标签中选择 Executable files
💻 C
📖 第 1 页 / 共 2 页
字号:
    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;
    int                 i, numReads;

    KeInitializeEvent(&event, NotificationEvent, FALSE);

    if (!NT_SUCCESS(status)) {
        return status;
    }

    self = DeviceExtension->Self;
    irp = DeviceExtension->ReadIrp;

    Print(DeviceExtension, DBG_SS_TRACE, ("Read pending...\n"));

    *ActualBytesRead = 0;
    while (*ActualBytesRead < Buflen) {

        KeClearEvent(&event);
        IoReuseIrp(irp, STATUS_SUCCESS);
    
        irp->AssociatedIrp.SystemBuffer = ReadBuffer;
    
        stack = IoGetNextIrpStackLocation(irp);
        stack->Parameters.Read.Length = 1;          
        stack->Parameters.Read.ByteOffset.QuadPart = 0;
        stack->MajorFunction = IRP_MJ_READ;
        
        //
        // Hook a completion routine for when the device completes.
        //
        IoSetCompletionRoutine(irp,
                               SerialMouseReadSerialPortComplete,
                               &event,
                               TRUE,
                               TRUE,
                               TRUE);


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

        if (status == STATUS_PENDING) {
            //
            // Wait for the IRP
            //
            status = KeWaitForSingleObject(&event,
                                           Executive,
                                           KernelMode,
                                           FALSE,
                                           NULL);

            if (status == STATUS_SUCCESS) {
                status = irp->IoStatus.Status;
            }
        }

        if (!NT_SUCCESS(status) || status == STATUS_TIMEOUT) {
            Print(DeviceExtension, DBG_SS_NOISE, 
                  ("IO Call failed with status %x\n", status));
            return status;
        }

        ASSERT(irp->IoStatus.Information >= 0);
        ASSERT(irp->IoStatus.Information <= 1);

        *ActualBytesRead += (USHORT) irp->IoStatus.Information;
        ReadBuffer += (USHORT) irp->IoStatus.Information;
    }

    return status;
}

NTSTATUS
SerialMouseWriteSerialPort (
    PDEVICE_EXTENSION   DeviceExtension,
    PCHAR               WriteBuffer,
    ULONG               NumBytes,
    PIO_STATUS_BLOCK    IoStatusBlock
    )
/*++

Routine Description:
    Performs a synchronous write on the serial port.  Used during setup so that
    the device can be configured.
    
Return value:                      
    NTSTATUS - STATUS_SUCCESS if the read was successful, error code otherwise

--*/
{
    NTSTATUS        status;
    PIRP            irp;
    LARGE_INTEGER   startingOffset = RtlConvertLongToLargeInteger(0);
    KEVENT          event;

    int             i, numReads;

    KeInitializeEvent(&event,
                      NotificationEvent,
                      FALSE);
    
    Print(DeviceExtension, DBG_SS_TRACE, ("Write pending...\n"));

    //
    // Create a new IRP because there's a chance that it might get cancelled.
    // Can't cancel irps that I received.
    // IRP_MJ_READ with completion routine
    //
    if (NULL == (irp = IoBuildSynchronousFsdRequest(
                IRP_MJ_WRITE,
                DeviceExtension->TopOfStack,
                WriteBuffer,        
                NumBytes,   
                &startingOffset,    
                &event,
                IoStatusBlock   
                ))) {
        Print(DeviceExtension, DBG_SS_ERROR, ("Failed to allocate IRP\n"));

        return STATUS_INSUFFICIENT_RESOURCES;
    }

    status = IoCallDriver(DeviceExtension->TopOfStack, irp);
        
    if (status == STATUS_PENDING) {
            
        // I don't know at this time if I can wait with the default time of
        // 200 ms as I'm doing.  In the help file for IoBuildSynchronousFsdRequest
        // I think that it says I can't, but I'm not quite sure.
        // Presently I will.  I'll cancel the Irp if it isn't done.
        status = KeWaitForSingleObject(
                            &event,
                            Executive,
                            KernelMode,
                            FALSE, // Not alertable
                            NULL);
    }

    status = IoStatusBlock->Status;
                
    if (!NT_SUCCESS(status)) {
        Print(DeviceExtension, DBG_SS_ERROR,
              ("IO Call failed with status %x\n",
              status
              ));
        return status;
    }

    if (!NT_SUCCESS(status)) {
        Print(DeviceExtension, DBG_SS_ERROR,
              ("IO Call failed with status %x\n",
              status
              ));
    }

    return status;
}

NTSTATUS
SerialMouseWait (
    IN PDEVICE_EXTENSION    DeviceExtension,
    IN LONG                 Timeout
    )
/*++

Routine Description:
    Performs a wait for the specified time.  
    NB: Negative time is relative to the current time.  Positive time 
    represents an absolute time to wait until.
        
Return value:                      
    NTSTATUS

--*/
{
    LARGE_INTEGER time = RtlConvertLongToLargeInteger(Timeout); 

    Print(DeviceExtension, DBG_READ_NOISE,
          ("waiting for %d micro secs\n", Timeout));

    if (KeSetTimer(&DeviceExtension->DelayTimer,
                   time,
                   NULL)) {
        Print(DeviceExtension, DBG_SS_INFO, ("Timer already set\n"));
    }

    return KeWaitForSingleObject(&DeviceExtension->DelayTimer,
                                 Executive,
                                 KernelMode,
                                 FALSE,             // Not allertable
                                 NULL);             // No timeout structure
}

NTSTATUS
SerialMouseInitializePort(
    PDEVICE_EXTENSION DeviceExtension
    )
{
    NTSTATUS        status;
    KEVENT          event;
    IO_STATUS_BLOCK iosb;
    SERIAL_TIMEOUTS serialTimeouts;
    SERIAL_HANDFLOW serialHandFlow;

    KeInitializeEvent(&event, NotificationEvent, FALSE);

    status =
        SerialMouseIoSyncInternalIoctlEx(IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS,
                                         DeviceExtension->TopOfStack,
                                         &event,
                                         &iosb,
                                         NULL,
                                         0,
                                         &DeviceExtension->SerialBasicSettings,
                                         sizeof(SERIAL_BASIC_SETTINGS));

    //
    // In case we are running on a port that does not support basic settings
    //
    if (!NT_SUCCESS(status)) {
        SerialMouseIoSyncIoctlEx(IOCTL_SERIAL_GET_TIMEOUTS,
                                 DeviceExtension->TopOfStack,
                                 &event,
                                 &iosb,
                                 NULL,
                                 0,
                                 &DeviceExtension->SerialBasicSettings.Timeouts,
                                 sizeof(SERIAL_TIMEOUTS));
  
        RtlZeroMemory(&serialTimeouts, sizeof(SERIAL_TIMEOUTS));
  
        SerialMouseIoSyncIoctlEx(IOCTL_SERIAL_SET_TIMEOUTS,
                                 DeviceExtension->TopOfStack,
                                 &event,
                                 &iosb,
                                 &serialTimeouts,
                                 sizeof(SERIAL_TIMEOUTS),
                                 NULL,
                                 0);

        SerialMouseIoSyncIoctlEx(IOCTL_SERIAL_GET_HANDFLOW,
                                 DeviceExtension->TopOfStack,
                                 &event,
                                 &iosb,
                                 NULL,
                                 0,
                                 &DeviceExtension->SerialBasicSettings.HandFlow,
                                 sizeof(SERIAL_HANDFLOW));

        serialHandFlow.ControlHandShake = SERIAL_DTR_CONTROL;
        serialHandFlow.FlowReplace = SERIAL_RTS_CONTROL;
        serialHandFlow.XonLimit = 0;
        serialHandFlow.XoffLimit = 0;
     
        status = SerialMouseIoSyncIoctlEx(IOCTL_SERIAL_SET_HANDFLOW, 
                                          DeviceExtension->TopOfStack,
                                          &event,
                                          &iosb,
                                          &serialHandFlow,
                                          sizeof(SERIAL_HANDFLOW),
                                          NULL,
                                          0);
    }

    return status;
}

VOID
SerialMouseRestorePort(
    PDEVICE_EXTENSION DeviceExtension
    )
{
    KEVENT          event;
    IO_STATUS_BLOCK iosb;
    NTSTATUS        status;

    KeInitializeEvent(&event, NotificationEvent, FALSE);

    status =
        SerialMouseIoSyncInternalIoctlEx(IOCTL_SERIAL_INTERNAL_RESTORE_SETTINGS,
                                         DeviceExtension->TopOfStack,
                                         &event,
                                         &iosb,
                                         &DeviceExtension->SerialBasicSettings,
                                         sizeof(SERIAL_BASIC_SETTINGS),
                                         NULL,
                                         0);
    //
    // 4-24 Once serial.sys supports this new IOCTL, this code can be removed
    //
    if (!NT_SUCCESS(status)) {
        SerialMouseIoSyncIoctlEx(IOCTL_SERIAL_SET_TIMEOUTS, 
                                 DeviceExtension->TopOfStack,
                                 &event,
                                 &iosb,
                                 &DeviceExtension->SerialBasicSettings.Timeouts,
                                 sizeof(SERIAL_TIMEOUTS),
                                 NULL,
                                 0);

        SerialMouseIoSyncIoctlEx(IOCTL_SERIAL_SET_HANDFLOW, 
                                 DeviceExtension->TopOfStack,
                                 &event,
                                 &iosb,
                                 &DeviceExtension->SerialBasicSettings.HandFlow,
                                 sizeof(SERIAL_HANDFLOW),
                                 NULL,
                                 0);
    }
}

⌨️ 快捷键说明

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