1081 lines
26 KiB
C
1081 lines
26 KiB
C
/*++
|
|
Copyright (c) 1998 Gemplus developpement
|
|
|
|
Name:
|
|
GNTSER.C (Gemplus Win NT SERial port management)
|
|
|
|
Description :
|
|
This module holds the functions needed for a communication on a serial line.
|
|
|
|
Environment:
|
|
Kernel mode
|
|
|
|
Revision History :
|
|
dd/mm/yy
|
|
13/03/98: V1.00.001 (GPZ)
|
|
- Start of development.
|
|
26/04/98: V1.00.002 (GPZ)
|
|
22/01/99: V1.00.003 (YN)
|
|
- Remove the IRPCancel durnig call the serial driver
|
|
|
|
--*/
|
|
|
|
#include <stdio.h>
|
|
#include "gntscr.h"
|
|
#include "gntser.h"
|
|
|
|
|
|
//
|
|
// Type section:
|
|
// TPORT_CONFIG:
|
|
// - WaitRelease holds the timeout for the release of the semaphore.
|
|
// - Counter holds the number of opened session. If its value is 0, the port is
|
|
// closed.
|
|
// - Error holds Rx over state.
|
|
// - TimeOut holds the character level time out.
|
|
// - TxSize memorises the transmit buffer size.
|
|
// - RxSize memorises the reception buffer size.
|
|
// - pSerialPortDevice is a pointer on the serial Device Object.
|
|
//
|
|
typedef struct
|
|
{
|
|
ULONG WaitRelease;
|
|
USHORT Counter;
|
|
short Error;
|
|
ULONG TimeOut;
|
|
USHORT TxSize;
|
|
USHORT RxSize;
|
|
PDEVICE_OBJECT pSerialPortDevice;
|
|
PKMUTEX pExchangeMutex;
|
|
} TPORT_CONFIG;
|
|
|
|
#define GTSER_DEF_WAIT_RELEASE 2000
|
|
#define GTSER_IOCTL_WRITE SCARD_CTL_CODE(1001)
|
|
#define GTSER_IOCTL_READ SCARD_CTL_CODE(1000)
|
|
|
|
//
|
|
// Macro section:
|
|
// - WORD_LEN, PARITY and STOP retreive the configuration values to pass to
|
|
// Windows to configure the port.
|
|
//
|
|
#define WORD_LEN(x) (BYTE)(((x) & 0x03) + 5)
|
|
#define PARITY(x) (BYTE)(parity[((BYTE)(x) >> 3) & 3])
|
|
#define STOP(x) (BYTE)(stop[((x) >> 2) & 1])
|
|
|
|
//
|
|
// Global variable section:
|
|
// - port_config is an array of TPORT_CONFIG which memorises the port
|
|
// configuration at each time.
|
|
//
|
|
TPORT_CONFIG
|
|
port_config[HGTSER_MAX_PORT] =
|
|
{
|
|
{0,0,0,0,0,0,NULL,NULL},
|
|
{0,0,0,0,0,0,NULL,NULL},
|
|
{0,0,0,0,0,0,NULL,NULL},
|
|
{0,0,0,0,0,0,NULL,NULL}
|
|
};
|
|
|
|
static USHORT
|
|
parity[] = {
|
|
NO_PARITY,
|
|
ODD_PARITY,
|
|
NO_PARITY,
|
|
EVEN_PARITY
|
|
};
|
|
static USHORT
|
|
stop[] = {
|
|
STOP_BIT_1,
|
|
STOP_BITS_2
|
|
};
|
|
//
|
|
// Local function definition section:
|
|
//
|
|
static NTSTATUS GDDKNT_GetCommStatus
|
|
(
|
|
const SHORT Handle,
|
|
SERIAL_STATUS *SerialStatus
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
GDDK_SerPortOpen(
|
|
const TGTSER_PORT *Param,
|
|
SHORT *Handle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine opens a serial port and initializes it according to the
|
|
parameters found in Param.
|
|
|
|
Arguments:
|
|
|
|
Param holds the following parameters:
|
|
- Port indicates the selected port.
|
|
- BaudRate is used to set port baud rate.
|
|
- Mode gathers
|
|
* word size WORD_5 (0), WORD_6 (1), WORD_7 (2) or WORD_8 (3),
|
|
* stop bit number STOP_BIT_1 (0) or STOP_BIT_2 (4) and
|
|
* parity NO_PARITY (0), ODD_PARITY (8) or EVEN_PARITY (24).
|
|
- TxSize is the transmit buffer size, in bytes.
|
|
- RxSize is the reception buffer size, in bytes.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
PSMARTCARD_EXTENSION SmartcardExtension;
|
|
SERIAL_READER_CONFIG SerialConfig;
|
|
PREADER_EXTENSION pReaderExtension;
|
|
SERIAL_QUEUE_SIZE SerialQueueSize;
|
|
USHORT LengthOut = 0;
|
|
SHORT handle = Param->Port - 1;
|
|
|
|
// Controls the given parameters:
|
|
if ((handle < 0) || (handle >= HGTSER_MAX_PORT)) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
if (port_config[handle].Counter != 0) {
|
|
return STATUS_DEVICE_ALREADY_ATTACHED;
|
|
}
|
|
// Retrieve the SmartcardExtension structure of the current device.
|
|
SmartcardExtension = (PSMARTCARD_EXTENSION)(Param->pSmartcardExtension);
|
|
pReaderExtension = SmartcardExtension->ReaderExtension;
|
|
port_config[handle].pSerialPortDevice = pReaderExtension->AttachedDeviceObject;
|
|
port_config[handle].pExchangeMutex = &pReaderExtension->ExchangeMutex;
|
|
|
|
// The current port state is read and stored in current_dcb structure by
|
|
// calling GetCommState function.
|
|
// If the reading is possible (GetCommState return 0)
|
|
// Then
|
|
// The current_dcb structure is updated with the given parameter (baud
|
|
// rate, ByteSize, Parity, StopBits).
|
|
// The modified state is written by calling SetCommState.
|
|
status = GDDKNT_GetCommState(handle,&SerialConfig);
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
SerialQueueSize.InSize = 4096L;
|
|
SerialQueueSize.OutSize = 4096L;
|
|
status = GDDKNT_SerPortIoRequest(
|
|
handle,
|
|
IOCTL_SERIAL_SET_QUEUE_SIZE,
|
|
500UL,
|
|
sizeof(SERIAL_QUEUE_SIZE),
|
|
(PUCHAR)&SerialQueueSize,
|
|
&LengthOut,
|
|
NULL
|
|
);
|
|
|
|
// Set the serial port communication parameters
|
|
SerialConfig.BaudRate.BaudRate = Param->BaudRate;
|
|
SerialConfig.LineControl.WordLength = WORD_LEN(Param->Mode);
|
|
SerialConfig.LineControl.Parity = PARITY(Param->Mode);
|
|
SerialConfig.LineControl.StopBits = STOP(Param->Mode);
|
|
// Set timeouts
|
|
SerialConfig.Timeouts.ReadIntervalTimeout = 1000;
|
|
SerialConfig.Timeouts.ReadTotalTimeoutConstant = 50000;
|
|
SerialConfig.Timeouts.ReadTotalTimeoutMultiplier = 0; // 50;
|
|
// Set special characters
|
|
SerialConfig.SerialChars.ErrorChar = 0;
|
|
SerialConfig.SerialChars.EofChar = 0;
|
|
SerialConfig.SerialChars.EventChar = 0;
|
|
SerialConfig.SerialChars.XonChar = 0;
|
|
SerialConfig.SerialChars.XoffChar = 0;
|
|
SerialConfig.SerialChars.BreakChar = 0xFF;
|
|
// Set handflow
|
|
SerialConfig.HandFlow.XonLimit = 0;
|
|
SerialConfig.HandFlow.XoffLimit = 0;
|
|
SerialConfig.HandFlow.FlowReplace = SERIAL_XOFF_CONTINUE ;
|
|
SerialConfig.HandFlow.ControlHandShake = 0;
|
|
status = GDDKNT_SetCommState(handle,&SerialConfig);
|
|
}
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
return status;
|
|
}
|
|
|
|
// Memorises the given parameters in port_config structure.
|
|
// Counter, Error, TimeOut, TxSize and RxSize fields are updated.
|
|
port_config[handle].Counter = 1;
|
|
port_config[handle].Error = 0;
|
|
port_config[handle].TimeOut = Param->TimeOut;
|
|
port_config[handle].TxSize = Param->TxSize;
|
|
port_config[handle].RxSize = Param->RxSize;
|
|
// We update the handle value.
|
|
*Handle = handle;
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
GDDK_SerPortAddUser(
|
|
const SHORT Port,
|
|
SHORT *Handle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add a new user on a port. This function return the handle of a previously
|
|
opened port.
|
|
When this function is successful, it is mandatory to call G_SerPortClose
|
|
to decrement the user number.
|
|
|
|
Arguments:
|
|
|
|
Port - indicates the selected port: G_COMx
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
// Controls the given parameters:
|
|
if ((Port < G_COM1) || (Port > G_COM4)) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
if (port_config[Port - 1].Counter == 0) {
|
|
return STATUS_PORT_DISCONNECTED;
|
|
}
|
|
if (port_config[Port - 1].Counter == 65535lu) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
// Increments the port_config.Counter.
|
|
port_config[Port - 1].Counter += 1;
|
|
|
|
// We return the Port number.
|
|
*Handle = Port - 1;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
GDDK_SerPortClose (
|
|
const SHORT Handle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine closes a previously opened serial port.
|
|
When port is shared, the close will be effective only when all clients will
|
|
have closed the port.
|
|
|
|
Arguments:
|
|
|
|
Handle - holds the port handle.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
// Controls the given parameters:
|
|
if ((Handle < 0) || (Handle >= HGTSER_MAX_PORT)) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
if (port_config[Handle].Counter == 0) {
|
|
return STATUS_PORT_DISCONNECTED;
|
|
}
|
|
// Decrements the port_config.Counter field.
|
|
port_config[Handle].Counter -= 1;
|
|
// Closes really the port for the last user:
|
|
// The queues are flushed.
|
|
if (port_config[Handle].Counter == 0) {
|
|
GDDK_SerPortFlush(Handle,SERIAL_PURGE_TXCLEAR | SERIAL_PURGE_TXABORT);
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
GDDK_SerPortWrite(
|
|
const SHORT Handle,
|
|
const USHORT Length,
|
|
const BYTE Buffer[]
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine writes bytes on a previously opened serial port.
|
|
|
|
Arguments:
|
|
|
|
Handle - holds the port handle.
|
|
Length - holds the number of bytes to write.
|
|
Buffer - holds the bytes to write.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
SERIAL_STATUS SerialStatus;
|
|
USHORT LengthOut;
|
|
|
|
ASSERT(Buffer != NULL);
|
|
// Controls the given parameters:
|
|
if ((Handle < 0) || (Handle >= HGTSER_MAX_PORT)) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
if (port_config[Handle].Counter == 0) {
|
|
return STATUS_PORT_DISCONNECTED;
|
|
}
|
|
|
|
// Control if the write can be made in one time:
|
|
// The windows port status is read by calling GetCommError to know how many
|
|
// bytes remain in Tx queue (port_config.Error field is updated if needed).
|
|
status = GDDKNT_GetCommStatus(Handle,&SerialStatus);
|
|
ASSERT(status == STATUS_SUCCESS);
|
|
if (status != STATUS_SUCCESS) {
|
|
|
|
return status;
|
|
}
|
|
|
|
port_config[Handle].Error |= (USHORT)(SERIAL_ERROR_OVERRUN & SerialStatus.Errors);
|
|
if (Length > ( port_config[Handle].TxSize - SerialStatus.AmountInOutQueue)) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
// Writes the given byte in Tx queue .
|
|
// If an error occurs during this operation
|
|
// Then
|
|
// The ClearCommError function is called to unblock the port
|
|
// (port_config.Error field is updated if needed).
|
|
LengthOut = 0;
|
|
status = GDDKNT_SerPortIoRequest(
|
|
Handle,
|
|
GTSER_IOCTL_WRITE,
|
|
500UL,
|
|
Length,
|
|
Buffer,
|
|
&LengthOut,
|
|
NULL
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
GDDKNT_GetCommStatus(Handle,&SerialStatus);
|
|
port_config[Handle].Error |= (USHORT)(SERIAL_ERROR_OVERRUN & SerialStatus.Errors);
|
|
LengthOut = 0;
|
|
status = GDDKNT_SerPortIoRequest(
|
|
Handle,
|
|
IOCTL_SERIAL_RESET_DEVICE,
|
|
500UL,
|
|
0,
|
|
NULL,
|
|
&LengthOut,
|
|
NULL
|
|
);
|
|
return STATUS_PORT_DISCONNECTED;
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
GDDK_SerPortRead(
|
|
const SHORT Handle,
|
|
USHORT *Length,
|
|
BYTE Buffer[]
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine reads bytes on a previously opened serial port.
|
|
It ends when required length = read length or when a character level timeout
|
|
is detected.
|
|
|
|
Arguments:
|
|
|
|
Handle - holds the port handle.
|
|
Length - holds the number of bytes to read.
|
|
Buffer - is a free area of, at least, Length bytes.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
|
|
ASSERT(Buffer != NULL);
|
|
// Controls the given parameters:
|
|
if ((Handle < 0) || (Handle >= HGTSER_MAX_PORT)) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
if (port_config[Handle].Counter == 0) {
|
|
*Length = 0;
|
|
return STATUS_PORT_DISCONNECTED;
|
|
}
|
|
|
|
// Try to read the bytes.
|
|
status = GDDKNT_SerPortIoRequest(
|
|
Handle,
|
|
GTSER_IOCTL_READ,
|
|
port_config[Handle].TimeOut,
|
|
0,
|
|
NULL,
|
|
Length,
|
|
Buffer
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
} else {
|
|
if (*Length == 0) {
|
|
return STATUS_INVALID_DEVICE_STATE;
|
|
}
|
|
}
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
GDDK_SerPortFlush(
|
|
const SHORT Handle,
|
|
const USHORT Select
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function clears Tx and Rx buffers.
|
|
When RX_QUEUE is selected, the RX_OVER flag is reseted.
|
|
|
|
Arguments:
|
|
|
|
Handle - holds the port handle.
|
|
Select - holds the buffers to clear:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
USHORT LengthOut = 0;
|
|
ULONG PurgeMask;
|
|
|
|
// Controls the given parameters:
|
|
if ((Handle < 0) || (Handle >= HGTSER_MAX_PORT)) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
if (port_config[Handle].Counter == 0) {
|
|
return STATUS_PORT_DISCONNECTED;
|
|
}
|
|
// Clears the selected queues
|
|
if (Select & HGTSER_TX_QUEUE) {
|
|
PurgeMask = SERIAL_PURGE_TXCLEAR;
|
|
}
|
|
if (Select & HGTSER_RX_QUEUE) {
|
|
PurgeMask = SERIAL_PURGE_RXCLEAR;
|
|
port_config[Handle].Error = 0;
|
|
}
|
|
|
|
status = GDDKNT_SerPortIoRequest(
|
|
Handle,
|
|
IOCTL_SERIAL_PURGE,
|
|
500UL,
|
|
sizeof(PurgeMask),
|
|
(PUCHAR)&PurgeMask,
|
|
&LengthOut,
|
|
NULL
|
|
);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
GDDK_SerPortGetState(
|
|
const SHORT Handle,
|
|
TGTSER_PORT *Param,
|
|
USHORT *UserNb
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine read the currently in use parameters for an opened serial port.
|
|
|
|
Arguments:
|
|
|
|
Handle - holds the port handle.
|
|
Param - is a pointer on the Param structure.
|
|
UserNb - is a pointer on the number of user for this port.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
SERIAL_READER_CONFIG SerialConfig;
|
|
|
|
ASSERT(Param != NULL);
|
|
ASSERT(UserNb != NULL);
|
|
// Controls the given parameters:
|
|
if ((Handle < 0) || (Handle >= HGTSER_MAX_PORT)) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
if (port_config[Handle].Counter == 0) {
|
|
return STATUS_PORT_DISCONNECTED;
|
|
}
|
|
// The current port state is read and stored in current_dcb structure by calling
|
|
// GetCommState function.
|
|
status = GDDKNT_GetCommState(Handle,&SerialConfig);
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
// The parameters are updated with the read values.
|
|
Param->BaudRate = SerialConfig.BaudRate.BaudRate;
|
|
switch (SerialConfig.LineControl.WordLength) {
|
|
|
|
case 5:
|
|
Param->Mode = HGTSER_WORD_5;
|
|
break;
|
|
case 6:
|
|
Param->Mode = HGTSER_WORD_6;
|
|
break;
|
|
case 7:
|
|
Param->Mode = HGTSER_WORD_7;
|
|
break;
|
|
case 8:
|
|
Param->Mode = HGTSER_WORD_8;
|
|
break;
|
|
default:
|
|
return STATUS_INVALID_DEVICE_STATE;
|
|
}
|
|
|
|
switch (SerialConfig.LineControl.Parity) {
|
|
|
|
case NO_PARITY:
|
|
Param->Mode |= HGTSER_NO_PARITY;
|
|
break;
|
|
case ODD_PARITY:
|
|
Param->Mode |= HGTSER_ODD_PARITY;
|
|
break;
|
|
case EVEN_PARITY:
|
|
Param->Mode |= HGTSER_EVEN_PARITY;
|
|
break;
|
|
case SERIAL_PARITY_MARK:
|
|
case SERIAL_PARITY_SPACE:
|
|
default:
|
|
return STATUS_INVALID_DEVICE_STATE;
|
|
}
|
|
|
|
switch (SerialConfig.LineControl.StopBits) {
|
|
|
|
case STOP_BIT_1:
|
|
Param->Mode |= HGTSER_STOP_BIT_1;
|
|
break;
|
|
case STOP_BITS_2:
|
|
Param->Mode |= HGTSER_STOP_BIT_2;
|
|
break;
|
|
case STOP_BITS_1_5:
|
|
default:
|
|
return STATUS_INVALID_DEVICE_STATE;
|
|
}
|
|
// Updates the library fields TimeOut, TxSize and RxSize.
|
|
Param->TimeOut = port_config[Handle].TimeOut;
|
|
Param->TxSize = port_config[Handle].TxSize;
|
|
Param->RxSize = port_config[Handle].RxSize;
|
|
// The UserNb parameter is filled with the port_config.Counter.
|
|
*UserNb = port_config[Handle].Counter;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
GDDK_SerPortSetState(
|
|
const SHORT Handle,
|
|
TGTSER_PORT *Param
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine alters the currently in use parameters for an opened serial port.
|
|
|
|
Arguments:
|
|
|
|
Handle - holds the port handle.
|
|
Param - is a pointer on the Param structure.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
SERIAL_READER_CONFIG SerialConfig;
|
|
ULONG error = 0;
|
|
|
|
ASSERT(Param != NULL);
|
|
// Controls the given parameters:
|
|
if ((Handle < 0) || (Handle >= HGTSER_MAX_PORT)) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
if (port_config[Handle].Counter == 0) {
|
|
return STATUS_PORT_DISCONNECTED;
|
|
}
|
|
|
|
status = GDDKNT_GetCommState(Handle,&SerialConfig);
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
SerialConfig.BaudRate.BaudRate = Param->BaudRate;
|
|
SerialConfig.LineControl.WordLength = WORD_LEN(Param->Mode);
|
|
SerialConfig.LineControl.Parity = PARITY(Param->Mode);
|
|
SerialConfig.LineControl.StopBits = STOP(Param->Mode);
|
|
status = GDDKNT_SetCommState(Handle,&SerialConfig);
|
|
}
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
// Updates the library fields TimeOut, TxSize and RxSize.
|
|
port_config[Handle].TimeOut = Param->TimeOut;
|
|
port_config[Handle].TxSize = Param->TxSize;
|
|
port_config[Handle].RxSize = Param->RxSize;
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
GDDK_SerPortLockComm(
|
|
const SHORT Handle,
|
|
const ULONG WaitRelease
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Take the mutex for a serial port communication if is free or wait
|
|
the release
|
|
|
|
Arguments:
|
|
|
|
Handle - holds the port handle
|
|
WaitRelease - holds the new time to wait the release
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
LARGE_INTEGER timeout;
|
|
|
|
// Controls the given parameters:
|
|
if ((Handle < 0) || (Handle >= HGTSER_MAX_PORT)) {
|
|
return FALSE;
|
|
}
|
|
timeout.QuadPart = -((LONGLONG)(
|
|
port_config[Handle].WaitRelease > GTSER_DEF_WAIT_RELEASE ?
|
|
port_config[Handle].WaitRelease : GTSER_DEF_WAIT_RELEASE)*10*1000);
|
|
status = KeWaitForMutexObject(
|
|
port_config[Handle].pExchangeMutex,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
&timeout
|
|
);
|
|
if (status != STATUS_SUCCESS) {
|
|
return FALSE;
|
|
} else {
|
|
port_config[Handle].WaitRelease = WaitRelease;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
GDDK_SerPortUnlockComm(
|
|
const SHORT Handle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Release the mutex for a serial port communication.
|
|
|
|
Arguments:
|
|
|
|
Handle - holds the port handle
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
|
|
// Controls the given parameters:
|
|
if ((Handle >= 0) && (Handle < HGTSER_MAX_PORT)) {
|
|
status = KeReleaseMutex(port_config[Handle].pExchangeMutex,FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
GDDKNT_SerPortIoRequest(
|
|
CONST SHORT Handle,
|
|
CONST ULONG SerialIoControlCode,
|
|
CONST ULONG CmdTimeout,
|
|
CONST USHORT LengthIn,
|
|
CONST BYTE *BufferIn,
|
|
USHORT *pLengthOut,
|
|
BYTE *BufferOut
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function sends an IOCTL's to the serial driver. It waits on for their
|
|
completion, and then returns.
|
|
|
|
Arguments:
|
|
|
|
Handle - holds the port handle
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
PIRP irp;
|
|
PIO_STACK_LOCATION irpNextStack;
|
|
IO_STATUS_BLOCK ioStatus;
|
|
KEVENT event;
|
|
|
|
KeInitializeEvent(&event,NotificationEvent,FALSE);
|
|
// Build an Irp to be send to serial driver
|
|
irp = IoBuildDeviceIoControlRequest(
|
|
SerialIoControlCode,
|
|
port_config[Handle].pSerialPortDevice,
|
|
(PVOID)BufferIn,
|
|
(ULONG)LengthIn,
|
|
(PVOID)BufferOut,
|
|
(ULONG)(*pLengthOut),
|
|
FALSE,
|
|
&event,
|
|
&ioStatus
|
|
);
|
|
|
|
if (irp == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
irpNextStack = IoGetNextIrpStackLocation(irp);
|
|
|
|
switch (SerialIoControlCode) {
|
|
case GTSER_IOCTL_WRITE:
|
|
irpNextStack->MajorFunction = IRP_MJ_WRITE;
|
|
irpNextStack->Parameters.Write.Length = (ULONG)LengthIn;
|
|
break;
|
|
|
|
case GTSER_IOCTL_READ:
|
|
irpNextStack->MajorFunction = IRP_MJ_READ;
|
|
irpNextStack->Parameters.Read.Length = (ULONG)(*pLengthOut);
|
|
break;
|
|
}
|
|
// Call the serial driver
|
|
status = IoCallDriver(
|
|
port_config[Handle].pSerialPortDevice,
|
|
irp
|
|
);
|
|
|
|
if (status == STATUS_PENDING) {
|
|
// Wait until the serial driver has processed the Irp
|
|
status = KeWaitForSingleObject(
|
|
&event,
|
|
Suspended,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
//ASSERT(status == STATUS_SUCCESS);
|
|
}
|
|
|
|
if(status == STATUS_SUCCESS)
|
|
{
|
|
status = ioStatus.Status;
|
|
switch (SerialIoControlCode) {
|
|
|
|
case GTSER_IOCTL_WRITE:
|
|
if (ioStatus.Status == STATUS_TIMEOUT) {
|
|
// STATUS_TIMEOUT isn't correctly mapped
|
|
// to a WIN32 error, that's why we change it here to STATUS_IO_TIMEOUT
|
|
status = STATUS_IO_TIMEOUT;
|
|
}
|
|
break;
|
|
|
|
case GTSER_IOCTL_READ:
|
|
if (ioStatus.Status == STATUS_TIMEOUT) {
|
|
// STATUS_TIMEOUT isn't correctly mapped
|
|
// to a WIN32 error, that's why we change it here to STATUS_IO_TIMEOUT
|
|
status = STATUS_IO_TIMEOUT;
|
|
*pLengthOut = 0;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
*pLengthOut = (USHORT)(ioStatus.Information);
|
|
break;
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
GDDKNT_SetCommState(
|
|
const SHORT Handle,
|
|
SERIAL_READER_CONFIG *SerialConfig
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will appropriately configure the serial port.
|
|
It makes synchronous calls to the serial port.
|
|
|
|
Arguments:
|
|
|
|
Handle - holds the port handle
|
|
SerialConfig - holds the configuration to set.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
USHORT i;
|
|
ULONG SerialIoControlCode;
|
|
USHORT LengthIn,LengthOut;
|
|
PUCHAR pBufferIn;
|
|
|
|
ASSERT(SerialConfig != NULL);
|
|
for (i=0; NT_SUCCESS(status); i++) {
|
|
switch (i) {
|
|
case 0:
|
|
// Set up baudrate
|
|
SerialIoControlCode = IOCTL_SERIAL_SET_BAUD_RATE;
|
|
pBufferIn = (PUCHAR)&SerialConfig->BaudRate;
|
|
LengthIn = sizeof(SERIAL_BAUD_RATE);
|
|
break;
|
|
|
|
case 1:
|
|
// Set up line control parameters
|
|
SerialIoControlCode = IOCTL_SERIAL_SET_LINE_CONTROL;
|
|
pBufferIn = (PUCHAR)&SerialConfig->LineControl;
|
|
LengthIn = sizeof(SERIAL_LINE_CONTROL);
|
|
break;
|
|
|
|
case 2:
|
|
// Set serial special characters
|
|
SerialIoControlCode = IOCTL_SERIAL_SET_CHARS;
|
|
pBufferIn = (PUCHAR)&SerialConfig->SerialChars;
|
|
LengthIn = sizeof(SERIAL_CHARS);
|
|
break;
|
|
|
|
case 3:
|
|
// Set up timeouts
|
|
SerialIoControlCode = IOCTL_SERIAL_SET_TIMEOUTS;
|
|
pBufferIn = (PUCHAR)&SerialConfig->Timeouts;
|
|
LengthIn = sizeof(SERIAL_TIMEOUTS);
|
|
break;
|
|
|
|
case 4:
|
|
// Set flowcontrol and handshaking
|
|
SerialIoControlCode = IOCTL_SERIAL_SET_HANDFLOW;
|
|
pBufferIn = (PUCHAR)&SerialConfig->HandFlow;
|
|
LengthIn = sizeof(SERIAL_HANDFLOW);
|
|
break;
|
|
|
|
case 5:
|
|
// Set break off
|
|
SerialIoControlCode = IOCTL_SERIAL_SET_BREAK_OFF;
|
|
LengthIn = 0;
|
|
break;
|
|
|
|
case 6:
|
|
// Set DTR
|
|
SerialIoControlCode = IOCTL_SERIAL_SET_DTR;
|
|
LengthIn = 0;
|
|
break;
|
|
|
|
case 7:
|
|
// Set RTS
|
|
SerialIoControlCode = IOCTL_SERIAL_SET_RTS;
|
|
LengthIn = 0;
|
|
break;
|
|
|
|
case 8:
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
LengthOut = 0;
|
|
status = GDDKNT_SerPortIoRequest(Handle,
|
|
SerialIoControlCode,
|
|
500UL,
|
|
LengthIn,
|
|
pBufferIn,
|
|
&LengthOut,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
GDDKNT_GetCommState(
|
|
const SHORT Handle,
|
|
SERIAL_READER_CONFIG *SerialConfig
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will get the configuration of the serial port.
|
|
It makes synchronous calls to the serial port.
|
|
|
|
Arguments:
|
|
|
|
Handle - holds the port handle
|
|
SerialConfig - holds the configuration of the serial port.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
USHORT i;
|
|
ULONG SerialIoControlCode;
|
|
USHORT LengthOut;
|
|
PUCHAR pBufferOut;
|
|
|
|
ASSERT(SerialConfig != NULL);
|
|
|
|
for (i=0; NT_SUCCESS(status); i++) {
|
|
switch (i) {
|
|
|
|
case 0:
|
|
// Get up baudrate
|
|
SerialIoControlCode = IOCTL_SERIAL_GET_BAUD_RATE;
|
|
pBufferOut = (PUCHAR)&SerialConfig->BaudRate;
|
|
LengthOut = sizeof(SERIAL_BAUD_RATE);
|
|
break;
|
|
|
|
case 1:
|
|
// Get up line control parameters
|
|
SerialIoControlCode = IOCTL_SERIAL_GET_LINE_CONTROL;
|
|
pBufferOut = (PUCHAR)&SerialConfig->LineControl;
|
|
LengthOut = sizeof(SERIAL_LINE_CONTROL);
|
|
break;
|
|
|
|
case 2:
|
|
// Get serial special characters
|
|
SerialIoControlCode = IOCTL_SERIAL_GET_CHARS;
|
|
pBufferOut = (PUCHAR)&SerialConfig->SerialChars;
|
|
LengthOut = sizeof(SERIAL_CHARS);
|
|
break;
|
|
|
|
case 3:
|
|
// Get up timeouts
|
|
SerialIoControlCode = IOCTL_SERIAL_GET_TIMEOUTS;
|
|
pBufferOut = (PUCHAR)&SerialConfig->Timeouts;
|
|
LengthOut = sizeof(SERIAL_TIMEOUTS);
|
|
break;
|
|
|
|
case 4:
|
|
// Get flowcontrol and handshaking
|
|
SerialIoControlCode = IOCTL_SERIAL_GET_HANDFLOW;
|
|
pBufferOut = (PUCHAR)&SerialConfig->HandFlow;
|
|
LengthOut = sizeof(SERIAL_HANDFLOW);
|
|
break;
|
|
|
|
case 5:
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
status = GDDKNT_SerPortIoRequest(Handle,
|
|
SerialIoControlCode,
|
|
500UL,
|
|
0,
|
|
NULL,
|
|
&LengthOut,
|
|
pBufferOut
|
|
);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
static NTSTATUS
|
|
GDDKNT_GetCommStatus(
|
|
const SHORT Handle,
|
|
SERIAL_STATUS *SerialStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will appropriately get status information of the serial port.
|
|
It makes synchronous calls to the serial port.
|
|
|
|
Arguments:
|
|
|
|
Handle - holds the port handle
|
|
SerialStatus - holds the status of the serial port.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
USHORT LengthOut;
|
|
|
|
ASSERT(SerialStatus != NULL);
|
|
LengthOut = sizeof(SERIAL_STATUS);
|
|
status = GDDKNT_SerPortIoRequest(Handle,
|
|
IOCTL_SERIAL_GET_COMMSTATUS,
|
|
500UL,
|
|
0,
|
|
NULL,
|
|
&LengthOut,
|
|
(PUCHAR)SerialStatus
|
|
);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS SER_SetPortTimeout( const short Handle, ULONG Timeout)
|
|
{ // Controls the given parameters:
|
|
short portcom;
|
|
if(GDDK_GBPChannelToPortComm(Handle,&portcom)) return STATUS_INVALID_PARAMETER;
|
|
port_config[portcom].TimeOut = Timeout;
|
|
return STATUS_SUCCESS;
|
|
}
|