271 lines
8.6 KiB
C
271 lines
8.6 KiB
C
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
serial.c
|
|
|
|
Abstract: Functions to talk to the serial port.
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Author:
|
|
|
|
Michael Tsang (MikeTs) 23-Mar-2000
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, SerialSyncSendIoctl)
|
|
#pragma alloc_text(PAGE, SerialSyncReadWritePort)
|
|
#endif /* ALLOC_PRAGMA */
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @doc INTERNAL
|
|
*
|
|
* @func NTSTATUS | SerialSyncSendIoctl |
|
|
* Performs a synchronous ioctl request to the serial port.
|
|
*
|
|
* @parm IN ULONG | IoctlCode | ioctl code.
|
|
* @parm IN PDEVICE_OBJECT | DevObj | Points to the device object.
|
|
* @parm IN PVOID | InBuffer OPTIONAL | Points to the input buffer.
|
|
* @parm IN ULONG | InBufferLen | Specifies the size of the input buffer.
|
|
* @parm OUT PVOID | OutBuffer OPTIONAL | Points to the output buffer.
|
|
* @parm IN ULONG | OutBufferLen | Specifies the size of the output buffer.
|
|
* @parm IN BOOLEAN | fInternal | If TRUE, an internal ioctl is sent.
|
|
* @parm OUT PIO_STATUS_BLOCK | Iosb | Points to the io status block.
|
|
*
|
|
* @rvalue SUCCESS | returns STATUS_SUCCESS
|
|
* @rvalue FAILURE | returns NT status code
|
|
*
|
|
*****************************************************************************/
|
|
|
|
NTSTATUS INTERNAL
|
|
SerialSyncSendIoctl(
|
|
IN ULONG IoctlCode,
|
|
IN PDEVICE_OBJECT DevObj,
|
|
IN PVOID InBuffer OPTIONAL,
|
|
IN ULONG InBufferLen,
|
|
OUT PVOID OutBuffer OPTIONAL,
|
|
IN ULONG OutBufferLen,
|
|
IN BOOLEAN fInternal,
|
|
OUT PIO_STATUS_BLOCK Iosb
|
|
)
|
|
{
|
|
PROCNAME("SerialSyncSendIoctl")
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
KEVENT event;
|
|
PIRP irp;
|
|
|
|
PAGED_CODE();
|
|
|
|
ENTER(3, ("(Ioctl=%s,DevObj=%p,InBuff=%p,InLen=%d,OutBuff=%p,OutLen=%d,fInternal=%x,Iosb=%p)\n",
|
|
LookupName(IoctlCode,
|
|
fInternal? SerialInternalIoctlNames: SerialIoctlNames),
|
|
DevObj, InBuffer, InBufferLen, OutBuffer, OutBufferLen,
|
|
fInternal, Iosb));
|
|
|
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|
irp = IoBuildDeviceIoControlRequest(IoctlCode,
|
|
DevObj,
|
|
InBuffer,
|
|
InBufferLen,
|
|
OutBuffer,
|
|
OutBufferLen,
|
|
fInternal,
|
|
&event,
|
|
Iosb);
|
|
if (irp != NULL)
|
|
{
|
|
status = IoCallDriver(DevObj, irp);
|
|
if (status == STATUS_PENDING)
|
|
{
|
|
status = KeWaitForSingleObject(&event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
}
|
|
|
|
if (status == STATUS_SUCCESS)
|
|
{
|
|
status = Iosb->Status;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERRPRINT(("failed to build ioctl irp (status=%x)\n", status));
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
EXIT(3, ("=%x\n", status));
|
|
return status;
|
|
} //SerialSyncSendIoctl
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @doc INTERNAL
|
|
*
|
|
* @func NTSTATUS | SerialAsyncReadWritePort |
|
|
* Read/Write data from/to the Serial Port asynchornously.
|
|
*
|
|
* @parm IN BOOLEAN | fRead | If TRUE, the access is a Read.
|
|
* @parm IN PDEVICE_EXTENSION | DevExt | Points to the device extension.
|
|
* @parm IN PIRP | Irp | Points to an I/O Request Packet.
|
|
* @parm IN PUCHAR | Buffer | Points to the data buffer.
|
|
* @parm IN ULONG | BuffLen | Specifies the data buffer length.
|
|
* @parm IN PIO_COMPLETION_ROUTINE | CompletionRoutine |
|
|
* Points to the completion callback routine.
|
|
* @parm IN PVOID | Context | Callback context.
|
|
*
|
|
* @rvalue SUCCESS | returns STATUS_SUCCESS
|
|
* @rvalue FAILURE | returns NT status code
|
|
*
|
|
*****************************************************************************/
|
|
|
|
NTSTATUS INTERNAL
|
|
SerialAsyncReadWritePort(
|
|
IN BOOLEAN fRead,
|
|
IN PDEVICE_EXTENSION DevExt,
|
|
IN PIRP Irp,
|
|
IN PUCHAR Buffer,
|
|
IN ULONG BuffLen,
|
|
IN PIO_COMPLETION_ROUTINE CompletionRoutine,
|
|
IN PVOID Context
|
|
)
|
|
{
|
|
PROCNAME("SerialAsyncReadWritePort")
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION irpsp;
|
|
|
|
ENTER(2, ("(fRead=%x,DevExt=%p,Irp=%p,Buff=%p,BuffLen=%d,pfnCompletion=%p,Context=%p)\n",
|
|
fRead, DevExt, Irp, Buffer, BuffLen, CompletionRoutine,
|
|
Context));
|
|
|
|
ASSERT(Buffer != NULL);
|
|
ASSERT(BuffLen > 0);
|
|
|
|
Irp->AssociatedIrp.SystemBuffer = Buffer;
|
|
irpsp = IoGetNextIrpStackLocation(Irp);
|
|
RtlZeroMemory(irpsp, sizeof(*irpsp));
|
|
irpsp->Parameters.Read.Length = BuffLen;
|
|
irpsp->Parameters.Read.ByteOffset.QuadPart = 0;
|
|
irpsp->MajorFunction = fRead? IRP_MJ_READ: IRP_MJ_WRITE;
|
|
IoSetCompletionRoutine(Irp,
|
|
CompletionRoutine,
|
|
Context,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
status = IoCallDriver(DevExt->SerialDevObj, Irp);
|
|
|
|
EXIT(2, ("=%x\n", status));
|
|
return status;
|
|
} //SerialAsyncReadWritePort
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* @doc INTERNAL
|
|
*
|
|
* @func NTSTATUS | SerialSyncReadWritePort |
|
|
* Read/Write data from/to the Serial Port.
|
|
*
|
|
* @parm IN BOOLEAN | fRead | If TRUE, the access is a Read.
|
|
* @parm IN PDEVICE_EXTENSION | DevExt | Points to the device extension.
|
|
* @parm IN PUCHAR | Buffer | Points to the data buffer.
|
|
* @parm IN ULONG | BuffLen | Specifies the data buffer length.
|
|
* @parm IN PLARGE_INTEGER | Timeout | Points to an optional timeout value
|
|
* @parm OUT PULONG | BytesAccessed | Optionally returns number of bytes
|
|
* accessed.
|
|
*
|
|
* @rvalue SUCCESS | returns STATUS_SUCCESS
|
|
* @rvalue FAILURE | returns NT status code
|
|
*
|
|
*****************************************************************************/
|
|
|
|
NTSTATUS INTERNAL
|
|
SerialSyncReadWritePort(
|
|
IN BOOLEAN fRead,
|
|
IN PDEVICE_EXTENSION DevExt,
|
|
IN PUCHAR Buffer,
|
|
IN ULONG BuffLen,
|
|
IN PLARGE_INTEGER Timeout OPTIONAL,
|
|
OUT PULONG BytesAccessed OPTIONAL
|
|
)
|
|
{
|
|
PROCNAME("SerialSyncReadWritePort")
|
|
NTSTATUS status;
|
|
KEVENT event;
|
|
PIRP irp;
|
|
LARGE_INTEGER StartingOffset = RtlConvertLongToLargeInteger(0);
|
|
IO_STATUS_BLOCK iosb;
|
|
|
|
PAGED_CODE();
|
|
|
|
ENTER(2, ("(fRead=%x,DevExt=%p,Buff=%p,BuffLen=%d,pTimeout=%p,pBytesAccessed=%p)\n",
|
|
fRead, DevExt, Buffer, BuffLen, Timeout, BytesAccessed));
|
|
|
|
ASSERT(Buffer != NULL);
|
|
ASSERT(BuffLen > 0);
|
|
|
|
if (BytesAccessed != NULL)
|
|
{
|
|
*BytesAccessed = 0;
|
|
}
|
|
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
|
irp = IoBuildSynchronousFsdRequest(fRead? IRP_MJ_READ: IRP_MJ_WRITE,
|
|
DevExt->SerialDevObj,
|
|
Buffer,
|
|
BuffLen,
|
|
&StartingOffset,
|
|
&event,
|
|
&iosb);
|
|
if (irp != NULL)
|
|
{
|
|
ENTER(2, (".IoCallDriver(DevObj=%p,Irp=%p)\n",
|
|
DevExt->SerialDevObj, irp));
|
|
status = IoCallDriver(DevExt->SerialDevObj, irp);
|
|
EXIT(2, (".IoCallDriver=%x\n", status));
|
|
|
|
if (status == STATUS_PENDING)
|
|
{
|
|
status = KeWaitForSingleObject(&event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
Timeout);
|
|
}
|
|
|
|
if (status == STATUS_SUCCESS)
|
|
{
|
|
status = iosb.Status;
|
|
if (BytesAccessed != NULL)
|
|
{
|
|
*BytesAccessed = (ULONG)iosb.Information;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERRPRINT(("failed accessing com port (status=%x)\n",
|
|
status));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ERRPRINT(("failed to allocate synchronous IRP\n"));
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
EXIT(2, ("=%x (BytesAccessed=%d)\n", status, iosb.Information));
|
|
return status;
|
|
} //SerialSyncReadWritePort
|