📄 nt_com.c
字号:
/*
* NT_com.c - Windows NT serial interface
*
* This module handles serial input and output to Windows NT.
*
* copyright 1992, 1993 by Microsoft Corporation
* portions copyright 1991 by Insignia Solutions Ltd., used by permission.
*
* revision history:
* 24-Dec-1992 John Morgan: written
* based (in part) on serial driver support from Windows NT VDM.
* 4-Jan-1993 John Morgan: added support for transmit buffering
*/
//
// useful utility macros
//
#include "util_def.h"
//
// standard library include files
//
#include <windows.h>
#include <math.h>
#include <malloc.h>
#include <stdlib.h>
//
// COM_VDD specific include files
//
#include "com_vdd.h"
#include "pc_com.h"
#include "nt_com.h"
#include "vddsvc.h"
//
// Serial driver magic numbers
//
#define INPUT_QUEUE_SIZE (4*1024)
#define OUTPUT_QUEUE_SIZE 100
#define XON_CHARACTER (17) /* XON character, Cntrl-Q */
#define XOFF_CHARACTER (19) /* XOFF character, Cntrl-S */
#define REOPEN_DELAY (36) /* Reopen delay in 55ms (2 secs) */
//
// Serial status structure
// this incorporates the UART status as a substucture
//
tHostCom host_com[NUM_SERIAL_PORTS]; /* 4 comm ports - the insignia MAX */
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*::::::::::::::::::::::::::: Wait for Comm Event ::::::::::::::::::::::::::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
static BOOL wait_comm( pHostCom current )
{
ResetEvent( current->WaitOverlap.hEvent );
if (WaitCommEvent( current->handle, ¤t->EvtMask, ¤t->WaitOverlap ))
return TRUE;
if (GetLastError() == ERROR_IO_PENDING)
return GetOverlappedResult( current->handle, ¤t->WaitOverlap, NULL, TRUE );
return FALSE;
}
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*::::::::::::::::::::::::::::: Read Comm Port :::::::::::::::::::::::::::::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
static BOOL read_comm( pHostCom current, DWORD *bytesread )
{
ResetEvent( current->WaitOverlap.hEvent );
if (ReadFile( current->handle, current->rx_buffer, RX_BUFFER_SIZE, bytesread, ¤t->RXOverlap ))
return TRUE;
if (GetLastError() == ERROR_IO_PENDING)
return GetOverlappedResult( current->handle, ¤t->RXOverlap, NULL, TRUE );
return FALSE;
}
#if (!XMIT_BUFFER)
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*::::::::::::::::::::::::::::: Write Comm Port ::::::::::::::::::::::::::::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
static BOOL write_comm( pHostCom current, BYTE *buffer, DWORD length )
{
DWORD byteswritten;
ResetEvent( current->WaitOverlap.hEvent );
if (WriteFile( current->handle, buffer, length, &byteswritten, ¤t->TXOverlap ))
return TRUE;
if (GetLastError() == ERROR_IO_PENDING)
return GetOverlappedResult( current->handle, ¤t->TXOverlap, NULL, TRUE );
return FALSE;
}
#else
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*::::::::::::::::::::::::::::: TX buffer pool :::::::::::::::::::::::::::::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
// the number of transmit buffers available
#define NUM_TX_BUFFERS 4
typedef struct tTX_qitem
{
struct tTX_qitem *next; // pointer to next buffer (for queues)
tTX_buffer buffer;
} tTX_qitem, *pTX_qitem;
static tTX_qitem TX_q_buff[NUM_TX_BUFFERS];
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*::::::::::::::::::::::::::: TX transmit queues :::::::::::::::::::::::::::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
// queue selector type
typedef DWORD tQueueSel;
// the queue number for the free pool
#define NUM_TX_QUEUES (NUM_SERIAL_PORTS+1)
#define TX_FREE_QUEUE (NUM_TX_QUEUES-1)
typedef struct tTX_queue
{
HANDLE wait[2]; // mutal exclusion & buffer available
pTX_qitem head;
pTX_qitem tail;
} tTX_queue, *pTX_queue;
static tTX_queue TX_queue[NUM_TX_QUEUES];
static pTX_qitem TX_dequeue( tQueueSel queue_sel )
{
pTX_queue queue = &TX_queue[queue_sel];
pTX_qitem item;
// wait until buffer available
WaitForMultipleObjects( 2, queue -> wait, TRUE, INFINITE );
if ((item = queue -> tail) != NULL)
{
if ((queue -> tail = item -> next) == NULL)
queue -> head = NULL;
item -> next = NULL;
}
ReleaseMutex( queue -> wait[0] );
return item;
}
static void TX_enqueue( tQueueSel queue_sel, pTX_qitem item )
{
pTX_queue queue = &TX_queue[queue_sel];
WaitForSingleObject( queue -> wait[0], INFINITE );
item -> next = NULL;
if (queue -> head == NULL)
queue -> tail = item;
else
queue -> head -> next = item;
queue -> head = item;
ReleaseSemaphore( queue -> wait[1], 1, NULL );
ReleaseMutex( queue -> wait[0] );
}
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*:::::::::::::::::::::::::::: transmit buffers ::::::::::::::::::::::::::::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
// the maximum wait time before writing a buffer even if it isn't full
#define TX_BUFF_DELAY 130
static DWORD transmit_buffers( DWORD adapter )
{
DWORD byteswritten;
pTX_qitem item;
while ((item = TX_dequeue( adapter )) != NULL) // Get next buffer to transmit
{
// wait until full, or timeout
if (WaitForMultipleObjects( 2, item -> buffer.wait, TRUE, TX_BUFF_DELAY ) == WAIT_TIMEOUT)
{
// must have mutual exclusion regardless
WaitForSingleObject( item -> buffer.wait[0], INFINITE );
}
// signal that buffer has been written
item -> buffer.adapter = TX_FREE_QUEUE; // not a legal port number
// OK to release now (WE DON'T HAVE TO WAIT FOR ACTUAL WRITE!)
ReleaseMutex( item -> buffer.wait[0] );
// Wait for previous write (if any to complete)
WaitForSingleObject( item -> buffer.Overlap.hEvent, INFINITE);
ResetEvent( item -> buffer.Overlap.hEvent );
// write buffer to com port
WriteFile( host_com[adapter].handle, item -> buffer.bytes, item -> buffer.byte_count,
&byteswritten, &item -> buffer.Overlap );
// now buffer should be moved to free pool
TX_enqueue( TX_FREE_QUEUE, item );
}
// close buffer queue
CloseHandle( TX_queue[adapter].wait[0] );
CloseHandle( TX_queue[adapter].wait[1] );
return TRUE;
}
static void post_transmit( tAdapter adapter, BYTE data )
{
register pHostCom current = & host_com[adapter];
pTX_buffer buffer;
pTX_qitem item;
// check to see if buffer available
if ((buffer = current -> tx_buffer) != NULL && buffer -> adapter == adapter)
{
// get mutual exclusion on buffer
WaitForSingleObject( buffer -> wait[0], INFINITE );
// check for buffer written before we could get MX
if (buffer -> adapter == adapter)
{
// add another byte
buffer -> bytes[(buffer -> byte_count)++] = data;
// signal if buffer full
if ((int)(buffer -> byte_count) >= current -> TX_full_length)
{
SetEvent( buffer -> wait[1] );
current -> tx_buffer = NULL;
}
// release buffer MX
ReleaseMutex( buffer -> wait[0] );
return;
}
// Oops buffer written, but no harm done.
ReleaseMutex( buffer -> wait[0] );
}
// expand buffer size by one character
if (++(current -> TX_full_length) > TX_BUFFER_SIZE)
current -> TX_full_length = TX_BUFFER_SIZE;
// buffer written or unavailable.
item = TX_dequeue( TX_FREE_QUEUE );
item -> buffer.adapter = adapter;
item -> buffer.bytes[0] = data;
if ((int)(item -> buffer.byte_count = 1) >= current -> TX_full_length)
{
SetEvent( item -> buffer.wait[1] ); // signal buffer full
current -> tx_buffer = NULL;
}
else
{
ResetEvent( item -> buffer.wait[1] ); // buffer not full
current -> tx_buffer = &(item -> buffer);
}
TX_enqueue( adapter, item );
}
static void shrink_TX_buffer( tAdapter adapter )
{
// collapse buffer by one character
if (--(host_com[adapter].TX_full_length) < 0)
host_com[adapter].TX_full_length = 0;
}
#endif //(XMIT_BUFFER)
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*::::::::::::::::::: Enter critical section for adapter :::::::::::::::::::*/
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
void host_com_lock( tAdapter adapter )
{
register pHostCom current = & host_com[adapter];
if (current->host_adapter_status != HOST_ADAPTER_OPEN)
return; /* Exit, NULL adapter */
EnterCriticalSection(¤t->AdapterLock);
current->AdapterLockCnt++;
}
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -