-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathODCom.c
More file actions
3774 lines (3145 loc) · 109 KB
/
Copy pathODCom.c
File metadata and controls
3774 lines (3145 loc) · 109 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* OpenDoors Online Software Programming Toolkit
* (C) Copyright 1991 - 1999 by Brian Pirie.
*
* Oct-2001 door32.sys/socket modifications by Rob Swindell (www.synchro.net)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*
* File: ODCom.c
*
* Description: Generic serial I/O routines, provide a single interface to
* serial ports on any platform.
*
* Revisions: Date Ver Who Change
* ---------------------------------------------------------------
* Oct 13, 1994 6.00 BP New file header format.
* Oct 20, 1994 6.00 BP Handle BIOS missing port addrs.
* Oct 20, 1994 6.00 BP Standardized coding style.
* Oct 21, 1994 6.00 BP Further isolated com routines.
* Dec 07, 1994 6.00 BP Support for RTS/CTS flow control.
* Dec 10, 1994 6.00 BP Allow word frmt setting for intern I/O
* Dec 13, 1994 6.00 BP Remove include of dir.h.
* Dec 31, 1994 6.00 BP Remove #ifndef USEINLINE DOS code.
* Jan 01, 1995 6.00 BP Integrate in Win32 code.
* Jan 01, 1995 6.00 BP Add FLOW_DEFAULT setting.
* Jan 01, 1995 6.00 BP Added ODComWaitEvent().
* Nov 16, 1995 6.00 BP Removed oddoor.h, added odcore.h.
* Nov 21, 1995 6.00 BP Ported to Win32.
* Dec 21, 1995 6.00 BP Add ability to use already open port.
* Jan 09, 1996 6.00 BP Supply actual in/out buffer size used.
* Feb 19, 1996 6.00 BP Changed version number to 6.00.
* Mar 03, 1996 6.10 BP Begin version 6.10.
* Mar 06, 1996 6.10 BP Initial support for Door32 interface.
* Mar 19, 1996 6.10 BP MSVC15 source-level compatibility.
* Jan 13, 1997 6.10 BP Fixes for Door32 support.
* Oct 19, 2001 6.20 RS Added TCP/IP socket (telnet) support.
* Oct 22, 2001 6.21 RS Fixed disconnected socket detection.
* Aug 22, 2002 6.22 RS Fixed bugs in ODComCarrier and ODComWaitEvent
* Aug 22, 2002 6.22 MD Modified socket functions for non-blocking use.
* Sep 18, 2002 6.22 MD Fixed bugs in ODComWaitEvent for non-blocking sockets.
* Aug 10, 2003 6.23 SH *nix support
*/
#define BUILDING_OPENDOORS
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include "OpenDoor.h"
#ifdef ODPLAT_NIX
#include <sys/ioctl.h>
#include <signal.h>
#include <termios.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#endif
#ifndef ODPLAT_WIN32
#include <poll.h>
#endif
#include "ODCore.h"
#include "ODGen.h"
#include "ODPlat.h"
#include "ODCom.h"
#include "ODUtil.h"
/* The following define determines whether serial port function should */
/* ASSERT or return an error code on programmer erorrs (e.g. invalid */
/* parameters. */
#define ASSERT_ON_INVALID_CALLS
/* The following code defines the VERIFY_CALL() macro, which maps to an */
/* ASSERT if ASSERT_ON_INVALID_CALLS is defined. Otherwise, this macro */
/* maps to a test which will return an error code to the caller. */
#ifdef ASSERT_ON_INVALID_CALLS
#define VERIFY_CALL(x) ASSERT(x)
#else /* !ASSERT_ON_INVALID_CALLS */
#define VERIFY_CALL(x) if(x) return(kODRCInvalidCall)
#endif /* !ASSERT_ON_INVALID_CALLS */
/* The following defines determine which serial I/O mechanisms should be */
/* supported. */
/* Serial I/O mechanisms supported under MS-DOS version. */
#ifdef ODPLAT_DOS
#define INCLUDE_FOSSIL_COM /* INT 14h FOSSIL-based I/O. */
#define INCLUDE_UART_COM /* Internal interrupt driven I/O. */
#endif /* ODPLAT_DOS */
/* Serial I/O mechanisms supported under Win32 version. */
#ifdef ODPLAT_WIN32
#define INCLUDE_WIN32_COM /* Win32 API serial I/O. */
#define INCLUDE_DOOR32_COM /* Door32 I/O interface. */
#define INCLUDE_SOCKET_COM /* TCP/IP socket I/O. */
#endif /* ODPLAT_WIN32 */
/* Serial I/O mechanisms supported inder *nix version */
#ifdef ODPLAT_NIX
#define INCLUDE_STDIO_COM
#define INCLUDE_SOCKET_COM /* TCP/IP socket I/O. */
/* Win32 Compat. Stuff */
#define SOCKET int
#define WSAEWOULDBLOCK EAGAIN
#define SOCKET_ERROR -1
#define WSAGetLastError() errno
#define ioctlsocket ioctl
#define closesocket close
#endif /* ODPLAT_NIX */
/* Include "windows.h" for Win32-API based serial I/O. */
#ifdef INCLUDE_WIN32_COM
#include "windows.h"
#endif /* INCLUDE_WIN32_COM */
/* terminal variables */
#ifdef INCLUDE_STDIO_COM
struct termios sio_tio_default; /* Initial term settings */
#endif
#if defined(_WIN32) && defined(INCLUDE_SOCKET_COM)
#include <winsock.h>
static WSADATA WSAData; /* WinSock data */
#endif
/* ========================================================================= */
/* Serial port object structure. */
/* ========================================================================= */
/* Win32-API serial I/O implementation requires current timeout setting */
/* status variable in serial port object structure. */
#ifdef INCLUDE_WIN32_COM
typedef enum
{
kNotSet,
kBlocking,
kNonBlocking
} tReadTimeoutState;
#endif /* INCLUDE_WIN32_COM */
/* Structure associated with each serial port handle. */
typedef struct
{
BOOL bIsOpen;
BOOL bUsingClientsHandle;
BYTE btFlowControlSetting;
long lSpeed;
BYTE btPort;
int nPortAddress;
BYTE btIRQLevel;
BYTE btWordFormat;
int nReceiveBufferSize;
int nTransmitBufferSize;
BYTE btFIFOSetting;
tComMethod Method;
void (*pfIdleCallback)(void);
#ifdef INCLUDE_WIN32_COM
HANDLE hCommDev;
tReadTimeoutState ReadTimeoutState;
#endif /* INCLUDE_WIN32_COM */
#ifdef INCLUDE_DOOR32_COM
HINSTANCE hinstDoor32DLL;
BOOL (WINAPI *pfDoorInitialize)(void);
BOOL (WINAPI *pfDoorShutdown)(void);
BOOL (WINAPI *pfDoorWrite)(const BYTE *pbData, DWORD dwSize);
DWORD (WINAPI *pfDoorRead)(BYTE *pbData, DWORD dwSize);
HANDLE (WINAPI *pfDoorGetAvailableEventHandle)(void);
HANDLE (WINAPI *pfDoorGetOfflineEventHandle)(void);
#endif /* INCLUDE_DOOR32_COM */
#ifdef INCLUDE_SOCKET_COM
SOCKET socket;
int old_delay;
#endif
} tPortInfo;
/* ========================================================================= */
/* Internal interrupt-driven serial I/O specific defintions & functions. */
/* ========================================================================= */
#ifdef INCLUDE_UART_COM
/* Private function prototypes, used by internal UART async serial I/O. */
static void ODComSetVect(BYTE btVector, void (INTERRUPT far *pfISR)(void));
static void (INTERRUPT far *ODComGetVect(BYTE btVector))(void);
static void INTERRUPT ODComInternalISR();
static BOOL ODComInternalTXReady(void);
static void ODComInternalResetRX(void);
static void ODComInternalResetTX(void);
/* Offsets of UART registers. */
#define TXBUFF 0 /* Transmit buffer register. */
#define RXBUFF 0 /* Receive buffer register. */
#define DLLSB 0 /* Divisor latch LS byte. */
#define DLMSB 1 /* Divisor latch MS byte. */
#define IER 1 /* Interrupt enable register. */
#define IIR 2 /* Interrupt ID register. */
#define LCR 3 /* Line control register. */
#define MCR 4 /* Modem control register. */
#define LSR 5 /* Line status register. */
#define MSR 6 /* Modem status register. */
/* FIFO control register bits. */
#define FE 0x01 /* FIFO enable. */
#define RR 0x02 /* FIFO receive buffer reset. */
#define TR 0x04 /* FIFO transmit buffer reset. */
#define FTS_1 0x00 /* FIFO trigger size 1 byte. */
#define FTS_4 0x40 /* FIFO trigger size 4 bytes. */
#define FTS_8 0x80 /* FIFO trigger size 8 bytes. */
#define FTS_14 0xc0 /* FIFO trigger size 14 bytes. */
/* Modem control register (MCR) bits. */
#define DTR 0x01 /* Data terminal ready. */
#define NOT_DTR 0xfe /* All bits other than DTR. */
#define RTS 0x02 /* Request to send. */
#define NOT_RTS 0xfd /* All bits other than RTS. */
#define OUT1 0x04 /* Output #1. */
#define OUT2 0x08 /* Output #2. */
#define LPBK 0x10 /* Loopback mode bit. */
/* Modem status register (MSR) bits. */
#define DCTS 0x01 /* Delta clear to send. */
#define DDSR 0x02 /* Delta data set ready. */
#define TERI 0x04 /* Trailing edge ring indicator. */
#define DRLSD 0x08 /* Delta Rx line signal detect. */
#define CTS 0x10 /* Clear to send. */
#define DSR 0x20 /* Data set ready. */
#define RI 0x40 /* Ring indicator. */
#define RLSD 0x80 /* Receive line signal detect. */
/* Line control register (LCR) bits. */
#define DATA5 0x00 /* 5 Data bits. */
#define DATA6 0x01 /* 6 Data bits. */
#define DATA7 0x02 /* 7 Data bits. */
#define DATA8 0x03 /* 8 Data bits. */
#define STOP1 0x00 /* 1 Stop bit. */
#define STOP2 0x04 /* 2 Stop bits. */
#define NOPAR 0x00 /* No parity. */
#define ODDPAR 0x08 /* Odd parity. */
#define EVNPAR 0x18 /* Even parity. */
#define STKPAR 0x28 /* Sticky parity. */
#define ZROPAR 0x38 /* Zero parity. */
#define DLATCH 0x80 /* Baud rate divisor latch. */
#define NOT_DL 0x7f /* Turns off divisor latch. */
/* Line status register (LSR) bits. */
#define RDR 0x01 /* Receive data ready. */
#define ERRS 0x1E /* All the error bits. */
#define TXR 0x20 /* Transmitter ready. */
/* Interrupt enable register (IER) bits. */
#define DR 0x01 /* Data ready. */
#define THRE 0x02 /* Transmit holding register empty. */
#define RLS 0x04 /* Receive line status. */
#define MS 0x08 /* Modem status. */
/* Flow control receive buffer limits. */
#define RECEIVE_LOW_NUM 1 /* Numerator for low water mark. */
#define RECEIVE_LOW_DENOM 4 /* Denominator for low water mark. */
#define RECEIVE_HIGH_NUM 3 /* Numerator for high water mark. */
#define RECEIVE_HIGH_DENOM 4 /* Denominator for high water mark. */
/* Built-in async serial I/O global variables. */
/* These variabes are shared throughout the functions that handle the */
/* built-in UART-base serial I/O, including the interrupt service routine. */
/* Since only one copy of these variables exist, the built-in serial I/O */
/* routines may only be used to access one port at a time. */
/* Default port addresses. */
/* First 4 addresses are standard addresses used for PC/AT COM1 thru COM4. */
/* Second 4 addresses are PS/2 standard addresses used for COM5 thru COM8. */
static int anDefaultPortAddr[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8,
0x4220, 0x4228, 0x5220, 0x5228};
/* UART address variables. */
static int nDataRegAddr; /* Data register address. */
static int nIntEnableRegAddr; /* Interrupt enable register. */
static int nIntIDRegAddr; /* Interrupt ID register address. */
static int nLineCtrlRegAddr; /* Line control register address. */
static int nModemCtrlRegAddr; /* Modem control register address. */
static int nLineStatusRegAddr; /* Line status register address. */
static int nModemStatusRegAddr; /* Modem status register address. */
/* General variables. */
static BYTE btIntVector; /* Interrupt vector number for port. */
static char btI8259Bit; /* 8259 bit mask. */
static char btI8259Mask; /* Copy as it was before open. */
static int nI8259MaskRegAddr; /* Address of i8259 mask register. */
static int nI8259EndOfIntRegAddr; /* Address of i8259 EOI register. */
static int nI8259MasterEndOfIntRegAddr; /* Address of master PIC EOI reg. */
static char btOldIntEnableReg; /* Original IER contents. */
static char btOldModemCtrlReg; /* Original MCR contents. */
static void (INTERRUPT far *pfOldISR)();/* Original ISR routine for IRQ. */
static char bUsingFIFO = FALSE; /* Are we using 16550 FIFOs? */
static unsigned char btBaseFIFOCtrl; /* FIFO control register byte. */
/* Transmit queue variables. */
static int nTXQueueSize; /* Actual size of transmit queue. */
static char *pbtTXQueue; /* Pointer to transmit queue. */
static int nTXInIndex; /* Location to store next byte. */
static int nTXOutIndex; /* Location to get next byte. */
static int nTXChars; /* Count of characters in queue. */
/* Receive queue variables. */
static int nRXQueueSize; /* Actual size of receive queue. */
static char *pbtRXQueue; /* Pointer to receive queue. */
static int nRXInIndex; /* Location to store next byte. */
static int nRXOutIndex; /* Location to retrieve next byte. */
static int nRXChars; /* Count of characters in queue. */
/* Flow control variables. */
static int nRXHighWaterMark; /* High water mark for queue size. */
static int nRXLowWaterMark; /* Low water mark for queue size. */
static BYTE btFlowControl; /* Flow control method. */
static BOOL bStopTrans; /* Flag set to stop transmitting. */
/* ----------------------------------------------------------------------------
* ODComSetVect() *** PRIVATE FUNCTION ***
*
* Sets the function to be called for the specified interrupt level.
*
* Parameters: btVector - Interrupt vector level, a value from 0 to 255.
*
* pfISR - Pointer to the ISR function to be called.
*
* Return: void
*/
static void ODComSetVect(BYTE btVector, void (INTERRUPT far *pfISR)(void))
{
ASM push ds
ASM mov ah, 0x25
ASM mov al, btVector
ASM lds dx, pfISR
ASM int 0x21
ASM pop ds
}
/* ----------------------------------------------------------------------------
* ODComGetVect() *** PRIVATE FUNCTION ***
*
* Returns the address of the function that is currently called for the
* specified interrupt level.
*
* Parameters: btVector - Interrupt vector level, a value from 0 to 255.
*
* Return: A pointer to the code that is currently executed on an interrupt
* of the speceified level.
*/
static void (INTERRUPT far *ODComGetVect(BYTE btVector))(void)
{
void (INTERRUPT far *pfISR)(void);
ASM push es
ASM mov ah, 0x35
ASM mov al, btVector
ASM int 0x21
ASM mov word ptr pfISR, bx
ASM mov word ptr [pfISR+2], bx
ASM pop es
return(pfISR);
}
/* ----------------------------------------------------------------------------
* ODComInternalTXReady() *** PRIVATE FUNCTION ***
*
* Returns TRUE if the internal serial I/O transmit buffer is not full.
*
* Parameters: none
*
* Return: void
*/
static BOOL ODComInternalTXReady(void)
{
/* Return TRUE if tx_chars is less than total tx buffer size. */
return(nTXChars < nTXQueueSize);
}
/* ----------------------------------------------------------------------------
* ODComInternalResetTX() *** PRIVATE FUNCTION ***
*
* Clears transmit buffer used by internal serial I/O routines.
*
* Parameters: none
*
* Return: void
*/
static void ODComInternalResetTX(void)
{
/* Disable interrupts. */
ASM cli
/* If we are using 16550A FIFO buffers, then clear the FIFO transmit */
/* buffer. */
if(bUsingFIFO)
{
ASM mov al, btBaseFIFOCtrl
ASM or al, TR
ASM mov dx, nIntIDRegAddr
ASM out dx, al
}
/* Reset start, end and total count of characters in buffer */
/* If buffer is still empty on next transmit interrupt, transmit */
/* interrupts will be turned off. */
nTXChars = nTXInIndex = nTXOutIndex = 0;
/* Re-enable interrupts. */
ASM sti
}
/* ----------------------------------------------------------------------------
* ODComInternalResetRX() *** PRIVATE FUNCTION ***
*
* Clears receive buffer used by internal serial I/O routines.
*
* Parameters: none
*
* Return: void
*/
static void ODComInternalResetRX(void)
{
/* Disable interrupts. */
ASM cli
/* If we are using 16550A FIFO buffers, then clear the FIFO receive */
/* buffer. */
if(bUsingFIFO)
{
ASM mov al, btBaseFIFOCtrl
ASM or al, RR
ASM mov dx, nIntIDRegAddr
ASM out dx, al
}
/* Reset start, end and total count of characters in buffer */
/* On the next receive interrupt, data will be added at the beginning */
/* of the buffer. */
nRXChars = nRXInIndex = nRXOutIndex = 0;
/* Re-enable interrupts. */
ASM sti
}
/* ----------------------------------------------------------------------------
* ODComInternalISR() *** PRIVATE FUNCTION ***
*
* Interrupt service routine for internal UART-based serial I/O.
*
* Parameters: none
*
* Return: void
*/
static void INTERRUPT ODComInternalISR()
{
char btIIR;
BYTE btTemp;
/* Loop until there are no more pending operations to perform with the */
/* UART. */
for(;;)
{
/* While bit 0 of the UART IIR is 0, there remains pending operations. */
/* Read IIR. */
ASM mov dx, nIntIDRegAddr
ASM in al, dx
ASM mov btIIR, al
/* If IIR bit 0 is set, then UART processing is finished. */
if(btIIR & 0x01) break;
/* Bits 1 and 2 of the IIR register identify the type of operation */
/* to be performed with the UART. */
/* Switch on bits 1 and 2 of IIR register. */
switch(btIIR & 0x06)
{
case 0x00:
/* Operation: modem status has changed. */
/* Read modem status register. */
ASM mov dx, nModemStatusRegAddr
ASM in al, dx
ASM mov btTemp, al
/* We only care about the modem status register if we are */
/* using RTS/CTS flow control, and the CTS register has */
/* changed. */
if((btFlowControl & FLOW_RTSCTS) && (btTemp & DCTS))
{
if(btTemp & CTS)
{
/* If CTS has gone high, then re-enable transmission. */
bStopTrans = FALSE;
/* Restart transmission if there is anything in the */
/* transmit buffer. */
if(nTXChars > 0)
{
/* Enable transmit interrupt. */
ASM mov dx, nIntEnableRegAddr
ASM in al, dx
ASM or al, THRE
ASM out dx, al
}
}
else
{
/* If CTS has gone low, then stop transmitting. */
bStopTrans = TRUE;
}
}
break;
case 0x02:
/* Operation: room in transmit register/FIFO. */
/* Check whether we can send further characters to transmit. */
if(nTXChars <= 0 || bStopTrans)
{
/* If we cannot send more characters, then turn off */
/* transmit interrupts. */
ASM mov dx, nIntEnableRegAddr
ASM in al, dx
ASM and al, 0xfd
ASM out dx, al
}
else
{
/* If we still have characters to transmit ... */
/* Check line status register to determine whether transmit */
/* register/FIFO truly has room. Some UARTs trigger transmit */
/* interrupts before the character has been tranmistted, */
/* causing transmitted characters to be lost. */
ASM mov dx, nLineStatusRegAddr
ASM in al, dx
ASM mov btTemp, al
if(btTemp & TXR)
{
/* There is room in the transmit register/FIFO. */
/* Get next character to transmit. */
btTemp = pbtTXQueue[nTXOutIndex++];
/* Write character to UART data register. */
ASM mov dx, nDataRegAddr
ASM mov al, btTemp
ASM out dx, al
/* Wrap-around transmit buffer pointer, if needed. */
if (nTXOutIndex == nTXQueueSize)
{
nTXOutIndex = 0;
}
/* Decrease count of characters in transmit buffer. */
nTXChars--;
}
}
break;
case 0x04:
/* Operation: Receive Data. */
/* Get character from receive buffer ASAP. */
ASM mov dx, nDataRegAddr
ASM in al, dx
ASM mov btTemp, al
/* If receive buffer is above high water mark. */
if(nRXChars >= nRXHighWaterMark)
{
/* If we are using flow control, then stop sender from */
/* sending. */
if(btFlowControl & FLOW_RTSCTS)
{
/* If using RTS/CTS flow control, then lower RTS line. */
ASM mov dx, nModemCtrlRegAddr
ASM in al, dx
ASM and al, NOT_RTS
ASM out dx, al
}
}
/* If there is room in receive buffer. */
if(nRXChars < nRXQueueSize)
{
/* Store the new character in the receive buffer. */
pbtRXQueue[nRXInIndex++] = btTemp;
/* Wrap-around buffer index, if needed. */
if (nRXInIndex == nRXQueueSize)
nRXInIndex = 0;
/* Increment count of characters in the buffer. */
nRXChars++;
}
break;
case 0x06:
/* Operation: Change in line status register. */
/* We just read the register to move on to further operations. */
ASM mov dx, nLineStatusRegAddr
ASM in al, dx
break;
}
}
/* Send end of interrupt to interrupt controller(s). */
ASM mov dx, nI8259EndOfIntRegAddr
ASM mov al, 0x20
ASM out dx, al
if(nI8259MasterEndOfIntRegAddr != 0)
{
ASM mov dx, nI8259MasterEndOfIntRegAddr
ASM mov al, 0x20
ASM out dx, al
}
}
#endif /* INCLUDE_UART_COM */
/* ========================================================================= */
/* Win32-API base serial I/O specific functions. */
/* ========================================================================= */
#ifdef INCLUDE_WIN32_COM
/* Function prototypes. */
static tODResult ODComWin32SetReadTimeouts(tPortInfo *pPortInfo,
tReadTimeoutState RequiredTimeoutState);
/* ----------------------------------------------------------------------------
* ODComWin32SetReadTimeouts() *** PRIVATE FUNCTION ***
*
* Ensures that read timeout state is set appropriately.
*
* Parameters: pPortInfo - Pointer to serial port handle structure.
*
* RequiredTimeoutState - Timeout state that should be set.
*
* Return: kODRCSuccess on success, or an error code on failure.
*/
static tODResult ODComWin32SetReadTimeouts(tPortInfo *pPortInfo,
tReadTimeoutState RequiredTimeoutState)
{
ASSERT(pPortInfo != NULL);
/* If timeout state must be changed ... */
if(RequiredTimeoutState != pPortInfo->ReadTimeoutState)
{
COMMTIMEOUTS CommTimeouts;
/* Obtain current timeout settings. */
if(!GetCommTimeouts(pPortInfo->hCommDev, &CommTimeouts))
{
return(kODRCGeneralFailure);
}
/* Setup timeout setting structure appropriately. */
switch(RequiredTimeoutState)
{
case kBlocking:
CommTimeouts.ReadIntervalTimeout = 0;
CommTimeouts.ReadTotalTimeoutMultiplier = 0;
CommTimeouts.ReadTotalTimeoutConstant = 0;
break;
case kNonBlocking:
CommTimeouts.ReadIntervalTimeout = INFINITE;
CommTimeouts.ReadTotalTimeoutMultiplier = 0;
CommTimeouts.ReadTotalTimeoutConstant = 0;
break;
default:
ASSERT(FALSE);
}
/* Write settings. */
if(!SetCommTimeouts(pPortInfo->hCommDev, &CommTimeouts))
{
return(kODRCGeneralFailure);
}
/* Record current read timeout setting state for subsequent */
/* calls to this function. */
pPortInfo->ReadTimeoutState = RequiredTimeoutState;
}
return(kODRCSuccess);
}
#endif /* INCLUDE_WIN32_COM */
/* ========================================================================= */
/* Implementation of generic serial I/O functions. */
/* ========================================================================= */
/* ----------------------------------------------------------------------------
* ODComAlloc()
*
* Allocates a serial port handle, which can be passed to other ODCom...()
* functions.
*
* Parameters: phPort - Pointer to serial port handle.
*
* Return: kODRCSuccess on success, or an error code on failure.
*/
tODResult ODComAlloc(tPortHandle *phPort)
{
tPortInfo *pPortInfo;
VERIFY_CALL(phPort != NULL);
/* Attempt to allocate a serial port information structure. */
pPortInfo = malloc(sizeof(tPortInfo));
/* If memory allocation failed, return with failure. */
if(pPortInfo == NULL)
{
*phPort = ODPTR2HANDLE(NULL, tPortInfo);
return(kODRCNoMemory);
}
/* Initialize serial port information structure. */
pPortInfo->bIsOpen = FALSE;
pPortInfo->bUsingClientsHandle = FALSE;
pPortInfo->btFlowControlSetting = FLOW_DEFAULT;
pPortInfo->lSpeed = SPEED_UNSPECIFIED;
pPortInfo->btWordFormat = ODPARITY_NONE | DATABITS_EIGHT | STOP_ONE;
pPortInfo->nReceiveBufferSize = 1024;
pPortInfo->nTransmitBufferSize = 1024;
pPortInfo->btFIFOSetting = FIFO_ENABLE | FIFO_TRIGGER_8;
pPortInfo->Method = kComMethodUnspecified;
pPortInfo->pfIdleCallback = NULL;
/* Convert serial port information structure pointer to a handle. */
*phPort = ODPTR2HANDLE(pPortInfo, tPortInfo);
/* Set default port number. */
ODComSetPort(*phPort, 0);
#if defined(INCLUDE_SOCKET_COM) && defined(_WINSOCKAPI_)
WSAStartup(MAKEWORD(1,1), &WSAData);
#endif
/* Return with success. */
return(kODRCSuccess);
}
/* ----------------------------------------------------------------------------
* ODComFree()
*
* Deallocates a serial port handle that is no longer required.
*
* Parameters: hPort - Handle to a serial port object.
*
* Return: kODRCSuccess on success, or an error code on failure.
*/
tODResult ODComFree(tPortHandle hPort)
{
tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
VERIFY_CALL(pPortInfo != NULL);
VERIFY_CALL(!pPortInfo->bIsOpen);
/* Deallocate port information structure. */
free(pPortInfo);
/* Return with success. */
return(kODRCSuccess);
}
/* ----------------------------------------------------------------------------
* ODComSetIdleFunction()
*
* Sets function to call when serial I/O module is idle, or NULL for none.
*
* Parameters: hPort - Handle to a serial port object.
*
* pfCallback - Pointer to function to call when idle.
*
* Return: kODRCSuccess on success, or an error code on failure.
*/
tODResult ODComSetIdleFunction(tPortHandle hPort,
void (*pfCallback)(void))
{
tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
VERIFY_CALL(pPortInfo != NULL);
VERIFY_CALL(!pPortInfo->bIsOpen);
pPortInfo->pfIdleCallback = pfCallback;
/* Return with success. */
return(kODRCSuccess);
}
/* ----------------------------------------------------------------------------
* ODComSetFlowControl()
*
* Sets the flow control method(s) to use. If this function is not called,
* RTS/CTS flow control is used by default. This function should not be
* called while the port is open.
*
* Parameters: hPort - Handle to a serial port object.
*
* btFlowControlSetting - One or more FLOW_* settings, joined
* by bitwise-or (|) operators. If
* FLOW_DEFAULT is included, all other
* settings are ignored, and the default
* settings for this serial I/O method
* are used.
*
* Return: kODRCSuccess on success, or an error code on failure.
*/
tODResult ODComSetFlowControl(tPortHandle hPort, BYTE btFlowControlSetting)
{
tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
VERIFY_CALL(pPortInfo != NULL);
VERIFY_CALL(!pPortInfo->bIsOpen);
pPortInfo->btFlowControlSetting = btFlowControlSetting;
/* Return with success. */
return(kODRCSuccess);
}
/* ----------------------------------------------------------------------------
* ODComSetSpeed()
*
* Sets the serial port BPS (baud) rate to use. Depending upon the serial I/O
* method being used, this setting may be controlled by the user's system
* configuration, in which case the value passed to this function wil have
* no effect. A setting of SPEED_UNSPECIFIED, indicates that the serial port
* speed should not be changed, if it is possible not to do so with the serial
* I/O method being used. This function cannot be called while the port is
* open.
*
* Parameters: hPort - Handle to a serial port object.
*
* lSpeed - A valid BPS rate, or SPEED_UNSPECIFIED.
*
* Return: kODRCSuccess on success, or an error code on failure.
*/
tODResult ODComSetSpeed(tPortHandle hPort, long lSpeed)
{
tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
VERIFY_CALL(pPortInfo != NULL);
VERIFY_CALL(!pPortInfo->bIsOpen);
pPortInfo->lSpeed = lSpeed;
/* Return with success. */
return(kODRCSuccess);
}
/* ----------------------------------------------------------------------------
* ODComSetPort()
*
* Sets the serial port number to be associated with this port handle. This
* function cannot be called while the port is open. Calling this function
* also sets the IRQ line number and serial port address to their defaults
* for this port number, if this values can be set for the serial I/O method
* being used.
*
* Parameters: hPort - Handle to a serial port object.
*
* btPort - Serial port identification, where 0 typically
* corresponds to COM1, 1 to COM2, and so on.
*
* Return: kODRCSuccess on success, or an error code on failure.
*/
tODResult ODComSetPort(tPortHandle hPort, BYTE btPort)
{
tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
VERIFY_CALL(pPortInfo != NULL);
VERIFY_CALL(!pPortInfo->bIsOpen);
/* Store port number in port information structure. */
pPortInfo->btPort = btPort;
#ifdef INCLUDE_UART_COM
/* Get default address for this port number, if possible. */
pPortInfo->nPortAddress = 0;
if(btPort < 4)
{
/* Get port address from BIOS data area. */
pPortInfo->nPortAddress = *(((int far *)0x400) + btPort);
}
/* If port address is still unknown, and we know the default */
/* address, then use that address. */
if(pPortInfo->nPortAddress == 0
&& btPort < DIM(anDefaultPortAddr))
{
pPortInfo->nPortAddress = anDefaultPortAddr[btPort];
}
/* Set default IRQ number for this port number. */
/* Ports 0 and 2 (COM1:, COM3:) default to IRQ 4, all others */
/* default to IRQ 3. */
if(btPort == 0 || btPort == 2)
{
pPortInfo->btIRQLevel = 4;
}
else
{
pPortInfo->btIRQLevel = 3;
}
#endif /* INCLUDE_UART_COM */
/* Return with success. */
return(kODRCSuccess);
}
/* ----------------------------------------------------------------------------
* ODComSetPortAddress()
*
* Sets address of the serial port, if it can be set for the serial I/O method
* being used. This function cannot be called when the port is open.
*
* Parameters: hPort - Handle to a serial port object.
*
* nPortAddress - Address of serial port.
*
* Return: kODRCSuccess on success, or an error code on failure.
*/
tODResult ODComSetPortAddress(tPortHandle hPort, int nPortAddress)
{
tPortInfo *pPortInfo = ODHANDLE2PTR(hPort, tPortInfo);
VERIFY_CALL(pPortInfo != NULL);
VERIFY_CALL(!pPortInfo->bIsOpen);
pPortInfo->nPortAddress = nPortAddress;
/* Return with success. */
return(kODRCSuccess);
}
/* ----------------------------------------------------------------------------