2 * DEC 93 Erik Bos <erik@xs4all.nl>
4 * Copyright 1996 Marcus Meissner
6 * Copyright 2001 Mike McCormack
8 * Mar 31, 1999. Ove Kåven <ovek@arcticnet.no>
9 * - Implemented buffers and EnableCommNotification.
11 * Apr 3, 1999. Lawson Whitney <lawson_whitney@juno.com>
12 * - Fixed the modem control part of EscapeCommFunction16.
14 * Mar 3, 1999. Ove Kåven <ovek@arcticnet.no>
15 * - Use port indices instead of unixfds for win16
16 * - Moved things around (separated win16 and win32 routines)
17 * - Added some hints on how to implement buffers and EnableCommNotification.
19 * May 26, 1997. Fixes and comments by Rick Richardson <rick@dgii.com> [RER]
20 * - ptr->fd wasn't getting cleared on close.
21 * - GetCommEventMask() and GetCommError() didn't do much of anything.
22 * IMHO, they are still wrong, but they at least implement the RXCHAR
23 * event and return I/O queue sizes, which makes the app I'm interested
24 * in (analog devices EZKIT DSP development system) work.
26 * August 12, 1997. Take a bash at SetCommEventMask - Lawson Whitney
27 * <lawson_whitney@juno.com>
28 * July 6, 1998. Fixes and comments by Valentijn Sessink
29 * <vsessink@ic.uva.nl> [V]
30 * Oktober 98, Rein Klazes [RHK]
31 * A program that wants to monitor the modem status line (RLSD/DCD) may
32 * poll the modem status register in the commMask structure. I update the bit
33 * in GetCommError, waiting for an implementation of communication events.
50 #include "wine/winuser16.h"
51 #include "wine/port.h"
55 #include "debugtools.h"
57 DEFAULT_DEBUG_CHANNEL(comm
);
59 /* window's semi documented modem status register */
60 #define COMM_MSR_OFFSET 35
65 #define MSR_MASK (MSR_CTS|MSR_DSR|MSR_RI|MSR_RLSD)
71 struct DosDeviceStruct
{
72 char *devicename
; /* /dev/ttyS0 */
79 int commerror
, eventmask
;
82 unsigned ibuf_size
,ibuf_head
,ibuf_tail
;
83 unsigned obuf_size
,obuf_head
,obuf_tail
;
85 int wnd
, n_read
, n_write
;
86 OVERLAPPED read_ov
, write_ov
;
87 /* save terminal states */
89 /* pointer to unknown(==undocumented) comm structure */
93 static struct DosDeviceStruct COM
[MAX_PORTS
];
94 static struct DosDeviceStruct LPT
[MAX_PORTS
];
96 /* update window's semi documented modem status register */
97 /* see knowledge base Q101417 */
98 static void COMM_MSRUpdate( HANDLE handle
, UCHAR
* pMsr
)
103 if(!GetCommModemStatus(handle
,&mstat
))
106 if(mstat
& MS_CTS_ON
) tmpmsr
|= MSR_CTS
;
107 if(mstat
& MS_DSR_ON
) tmpmsr
|= MSR_DSR
;
108 if(mstat
& MS_RING_ON
) tmpmsr
|= MSR_RI
;
109 if(mstat
& MS_RLSD_ON
) tmpmsr
|= MSR_RLSD
;
110 *pMsr
= (*pMsr
& ~MSR_MASK
) | tmpmsr
;
116 char option
[10], temp
[256], *btemp
;
119 for (x
=0; x
!=MAX_PORTS
; x
++) {
120 strcpy(option
,"COMx");
127 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config\\serialports", &hkey
))
129 DWORD type
, count
= sizeof(temp
);
131 RegQueryValueExA(hkey
, option
, 0, &type
, temp
, &count
);
135 if (!strcmp(temp
, "*") || *temp
== '\0')
136 COM
[x
].devicename
= NULL
;
138 btemp
= strchr(temp
,',');
141 COM
[x
].baudrate
= atoi(btemp
);
143 COM
[x
].baudrate
= -1;
145 if ((COM
[x
].devicename
= malloc(strlen(temp
)+1)) == NULL
)
146 WARN("Can't malloc for device info!\n");
149 strcpy(COM
[x
].devicename
, temp
);
151 TRACE("%s = %s\n", option
, COM
[x
].devicename
);
154 strcpy(option
, "LPTx");
161 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config\\parallelports", &hkey
))
163 DWORD type
, count
= sizeof(temp
);
165 RegQueryValueExA(hkey
, option
, 0, &type
, temp
, &count
);
169 if (!strcmp(temp
, "*") || *temp
== '\0')
170 LPT
[x
].devicename
= NULL
;
172 if ((LPT
[x
].devicename
= malloc(strlen(temp
)+1)) == NULL
)
173 WARN("Can't malloc for device info!\n");
176 strcpy(LPT
[x
].devicename
, temp
);
178 TRACE("%s = %s\n", option
, LPT
[x
].devicename
);
185 static struct DosDeviceStruct
*GetDeviceStruct(int index
)
187 if ((index
&0x7F)<=MAX_PORTS
) {
188 if (!(index
&FLAG_LPT
)) {
189 if (COM
[index
].handle
)
193 if (LPT
[index
].handle
)
201 static int GetCommPort_ov(LPOVERLAPPED ov
, int write
)
205 for (x
=0; x
<MAX_PORTS
; x
++) {
206 if (ov
== (write
?&COM
[x
].write_ov
:&COM
[x
].read_ov
))
213 static int ValidCOMPort(int x
)
215 return(x
< MAX_PORTS
? (int) COM
[x
].devicename
: 0);
218 static int ValidLPTPort(int x
)
220 return(x
< MAX_PORTS
? (int) LPT
[x
].devicename
: 0);
223 static int WinError(void)
225 TRACE("errno = %d\n", errno
);
232 static unsigned comm_inbuf(struct DosDeviceStruct
*ptr
)
234 return ((ptr
->ibuf_tail
> ptr
->ibuf_head
) ? ptr
->ibuf_size
: 0)
235 + ptr
->ibuf_head
- ptr
->ibuf_tail
;
238 static unsigned comm_outbuf(struct DosDeviceStruct
*ptr
)
240 return ((ptr
->obuf_tail
> ptr
->obuf_head
) ? ptr
->obuf_size
: 0)
241 + ptr
->obuf_head
- ptr
->obuf_tail
;
244 static void comm_waitread(struct DosDeviceStruct
*ptr
);
245 static void comm_waitwrite(struct DosDeviceStruct
*ptr
);
247 static VOID WINAPI
COMM16_ReadComplete(DWORD status
, DWORD len
, LPOVERLAPPED ov
)
251 int cid
= GetCommPort_ov(ov
,0);
252 struct DosDeviceStruct
*ptr
;
255 ERR("async write with bad overlapped pointer\n");
260 /* read data from comm port */
261 if (status
!= STATUS_SUCCESS
) {
262 ERR("async read failed\n");
263 COM
[cid
].commerror
= CE_RXOVER
;
266 TRACE("async read completed %ld bytes\n",len
);
268 prev
= comm_inbuf(ptr
);
270 /* check for events */
271 if ((ptr
->eventmask
& EV_RXFLAG
) &&
272 memchr(ptr
->inbuf
+ ptr
->ibuf_head
, ptr
->evtchar
, len
)) {
273 *(WORD
*)(COM
[cid
].unknown
) |= EV_RXFLAG
;
276 if (ptr
->eventmask
& EV_RXCHAR
) {
277 *(WORD
*)(COM
[cid
].unknown
) |= EV_RXCHAR
;
281 /* advance buffer position */
282 ptr
->ibuf_head
+= len
;
283 if (ptr
->ibuf_head
>= ptr
->ibuf_size
)
286 /* check for notification */
287 if (ptr
->wnd
&& (ptr
->n_read
>0) && (prev
<ptr
->n_read
) &&
288 (comm_inbuf(ptr
)>=ptr
->n_read
)) {
289 /* passed the receive notification threshold */
293 /* send notifications, if any */
294 if (ptr
->wnd
&& mask
) {
295 TRACE("notifying %04x: cid=%d, mask=%02x\n", ptr
->wnd
, cid
, mask
);
296 PostMessageA(ptr
->wnd
, WM_COMMNOTIFY
, cid
, mask
);
299 /* on real windows, this could cause problems, since it is recursive */
300 /* restart the receive */
304 static VOID WINAPI
COMM16_WriteComplete(DWORD status
, DWORD len
, LPOVERLAPPED ov
)
308 int cid
= GetCommPort_ov(ov
,1);
309 struct DosDeviceStruct
*ptr
;
312 ERR("async write with bad overlapped pointer\n");
317 /* read data from comm port */
318 if (status
!= STATUS_SUCCESS
) {
319 ERR("async write failed\n");
320 COM
[cid
].commerror
= CE_RXOVER
;
323 TRACE("async write completed %ld bytes\n",len
);
325 /* update the buffer pointers */
326 prev
= comm_outbuf(&COM
[cid
]);
327 ptr
->obuf_tail
+= len
;
328 if (ptr
->obuf_tail
>= ptr
->obuf_size
)
331 /* write any TransmitCommChar character */
333 if(!WriteFile(ptr
->handle
, &(ptr
->xmit
), 1, &len
, NULL
))
335 if (len
> 0) ptr
->xmit
= -1;
338 /* write from output queue */
339 bleft
= ((ptr
->obuf_tail
<= ptr
->obuf_head
) ?
340 ptr
->obuf_head
: ptr
->obuf_size
) - ptr
->obuf_tail
;
342 /* check for notification */
343 if (ptr
->wnd
&& (ptr
->n_write
>0) && (prev
>=ptr
->n_write
) &&
344 (comm_outbuf(ptr
)<ptr
->n_write
)) {
345 /* passed the transmit notification threshold */
349 /* send notifications, if any */
350 if (ptr
->wnd
&& mask
) {
351 TRACE("notifying %04x: cid=%d, mask=%02x\n", ptr
->wnd
, cid
, mask
);
352 PostMessageA(ptr
->wnd
, WM_COMMNOTIFY
, cid
, mask
);
355 /* start again if necessary */
360 static void comm_waitread(struct DosDeviceStruct
*ptr
)
364 bleft
= ((ptr
->ibuf_tail
> ptr
->ibuf_head
) ?
365 (ptr
->ibuf_tail
-1) : ptr
->ibuf_size
) - ptr
->ibuf_head
;
366 /* FIXME: get timeouts working properly so we can read bleft bytes */
367 ReadFileEx(ptr
->handle
,
368 ptr
->inbuf
+ ptr
->ibuf_head
,
371 COMM16_ReadComplete
);
374 static void comm_waitwrite(struct DosDeviceStruct
*ptr
)
378 bleft
= ((ptr
->obuf_tail
<= ptr
->obuf_head
) ?
379 ptr
->obuf_head
: ptr
->obuf_size
) - ptr
->obuf_tail
;
380 WriteFileEx(ptr
->handle
,
381 ptr
->outbuf
+ ptr
->obuf_tail
,
384 COMM16_WriteComplete
);
387 /*****************************************************************************
388 * COMM16_DCBtoDCB16 (Internal)
390 INT16
COMM16_DCBtoDCB16(LPDCB lpdcb
, LPDCB16 lpdcb16
)
392 if(lpdcb
->BaudRate
<0x10000)
393 lpdcb16
->BaudRate
= lpdcb
->BaudRate
;
394 else if(lpdcb
->BaudRate
==115200)
395 lpdcb16
->BaudRate
= 57601;
397 WARN("Baud rate can't be converted\n");
398 lpdcb16
->BaudRate
= 57601;
400 lpdcb16
->ByteSize
= lpdcb
->ByteSize
;
401 lpdcb16
->fParity
= lpdcb
->fParity
;
402 lpdcb16
->Parity
= lpdcb
->Parity
;
403 lpdcb16
->StopBits
= lpdcb
->StopBits
;
405 lpdcb16
->RlsTimeout
= 50;
406 lpdcb16
->CtsTimeout
= 50;
407 lpdcb16
->DsrTimeout
= 50;
410 lpdcb16
->fBinary
= 1;
411 lpdcb16
->fDtrDisable
= 0;
413 lpdcb16
->fDtrflow
= (lpdcb
->fDtrControl
==DTR_CONTROL_ENABLE
);
414 lpdcb16
->fRtsflow
= (lpdcb
->fRtsControl
==RTS_CONTROL_ENABLE
);
415 lpdcb16
->fOutxCtsFlow
= lpdcb
->fOutxCtsFlow
;
416 lpdcb16
->fOutxDsrFlow
= lpdcb
->fOutxDsrFlow
;
417 lpdcb16
->fDtrDisable
= (lpdcb
->fDtrControl
==DTR_CONTROL_DISABLE
);
419 lpdcb16
->fInX
= lpdcb
->fInX
;
421 lpdcb16
->fOutX
= lpdcb
->fOutX
;
426 lpdcb16
->XonLim
= 10;
427 lpdcb16
->XoffLim
= 10;
433 /**************************************************************************
434 * BuildCommDCB (USER.213)
436 * According to the ECMA-234 (368.3) the function will return FALSE on
437 * success, otherwise it will return -1.
439 INT16 WINAPI
BuildCommDCB16(LPCSTR device
, LPDCB16 lpdcb
)
441 /* "COM1:96,n,8,1" */
446 TRACE("(%s), ptr %p\n", device
, lpdcb
);
448 if (strncasecmp(device
,"COM",3))
450 port
= device
[3] - '0';
453 ERR("BUG ! COM0 can't exist!\n");
457 if (!ValidCOMPort(port
)) {
458 FIXME("invalid COM port %d?\n",port
);
462 memset(lpdcb
, 0, sizeof(DCB16
)); /* initialize */
465 dcb
.DCBlength
= sizeof(DCB
);
467 if (strchr(device
,'=')) /* block new style */
470 if(!BuildCommDCBA(device
,&dcb
))
473 return COMM16_DCBtoDCB16(&dcb
, lpdcb
);
476 /*****************************************************************************
477 * OpenComm (USER.200)
479 INT16 WINAPI
OpenComm16(LPCSTR device
,UINT16 cbInQueue
,UINT16 cbOutQueue
)
484 TRACE("%s, %d, %d\n", device
, cbInQueue
, cbOutQueue
);
486 if (strlen(device
) < 4)
489 port
= device
[3] - '0';
492 ERR("BUG ! COM0 or LPT0 don't exist !\n");
494 if (!strncasecmp(device
,"COM",3)) {
496 TRACE("%s = %s\n", device
, COM
[port
].devicename
);
498 if (!ValidCOMPort(port
))
501 if (COM
[port
].handle
)
504 handle
= CreateFileA(device
, GENERIC_READ
|GENERIC_WRITE
,
505 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, CREATE_ALWAYS
, 0, 0 );
506 if (handle
== INVALID_HANDLE_VALUE
) {
507 ERR("Couldn't open %s ! (%s)\n", COM
[port
].devicename
, strerror(errno
));
510 COM
[port
].unknown
= SEGPTR_ALLOC(40);
511 memset(COM
[port
].unknown
, 0, 40);
512 COM
[port
].handle
= handle
;
513 COM
[port
].commerror
= 0;
514 COM
[port
].eventmask
= 0;
515 COM
[port
].evtchar
= 0; /* FIXME: default? */
516 /* save terminal state */
517 GetCommState16(port
,&COM
[port
].dcb
);
518 /* set default parameters */
519 if(COM
[port
].baudrate
>-1){
521 memcpy(&dcb
,&COM
[port
].dcb
,sizeof dcb
);
522 dcb
.BaudRate
=COM
[port
].baudrate
;
524 * databits, parity, stopbits
526 SetCommState16( &dcb
);
528 /* init priority characters */
529 COM
[port
].unget
= -1;
531 /* allocate buffers */
532 COM
[port
].ibuf_size
= cbInQueue
;
533 COM
[port
].ibuf_head
= COM
[port
].ibuf_tail
= 0;
534 COM
[port
].obuf_size
= cbOutQueue
;
535 COM
[port
].obuf_head
= COM
[port
].obuf_tail
= 0;
537 COM
[port
].inbuf
= malloc(cbInQueue
);
538 if (COM
[port
].inbuf
) {
539 COM
[port
].outbuf
= malloc(cbOutQueue
);
540 if (!COM
[port
].outbuf
)
541 free(COM
[port
].inbuf
);
542 } else COM
[port
].outbuf
= NULL
;
543 if (!COM
[port
].outbuf
) {
544 /* not enough memory */
545 SetCommState16(&COM
[port
].dcb
);
546 CloseHandle(COM
[port
].handle
);
547 ERR("out of memory\n");
551 ZeroMemory(&COM
[port
].read_ov
,sizeof (OVERLAPPED
));
552 ZeroMemory(&COM
[port
].write_ov
,sizeof (OVERLAPPED
));
553 COM
[port
].read_ov
.hEvent
= CreateEventA(NULL
,0,0,NULL
);
554 COM
[port
].write_ov
.hEvent
= CreateEventA(NULL
,0,0,NULL
);
556 comm_waitread( &COM
[port
] );
562 if (!strncasecmp(device
,"LPT",3)) {
564 if (!ValidLPTPort(port
))
567 if (LPT
[port
].handle
)
570 handle
= CreateFileA(device
, GENERIC_READ
|GENERIC_WRITE
,
571 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, CREATE_ALWAYS
, 0, 0 );
572 if (handle
== INVALID_HANDLE_VALUE
) {
575 LPT
[port
].handle
= handle
;
576 LPT
[port
].commerror
= 0;
577 LPT
[port
].eventmask
= 0;
578 return port
|FLAG_LPT
;
584 /*****************************************************************************
585 * CloseComm (USER.207)
587 INT16 WINAPI
CloseComm16(INT16 cid
)
589 struct DosDeviceStruct
*ptr
;
591 TRACE("cid=%d\n", cid
);
592 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
593 FIXME("no cid=%d found!\n", cid
);
596 if (!(cid
&FLAG_LPT
)) {
598 SEGPTR_FREE(COM
[cid
].unknown
); /* [LW] */
600 CloseHandle(COM
[cid
].read_ov
.hEvent
);
601 CloseHandle(COM
[cid
].write_ov
.hEvent
);
607 /* reset modem lines */
608 SetCommState16(&COM
[cid
].dcb
);
611 if (!CloseHandle(ptr
->handle
)) {
612 ptr
->commerror
= WinError();
613 /* FIXME: should we clear ptr->handle here? */
622 /*****************************************************************************
623 * SetCommBreak (USER.210)
625 INT16 WINAPI
SetCommBreak16(INT16 cid
)
627 struct DosDeviceStruct
*ptr
;
629 TRACE("cid=%d\n", cid
);
630 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
631 FIXME("no cid=%d found!\n", cid
);
640 /*****************************************************************************
641 * ClearCommBreak (USER.211)
643 INT16 WINAPI
ClearCommBreak16(INT16 cid
)
645 struct DosDeviceStruct
*ptr
;
647 TRACE("cid=%d\n", cid
);
648 if (!(ptr
= GetDeviceStruct(cid
))) {
649 FIXME("no cid=%d found!\n", cid
);
657 /*****************************************************************************
658 * EscapeCommFunction (USER.214)
660 LONG WINAPI
EscapeCommFunction16(UINT16 cid
,UINT16 nFunction
)
662 struct DosDeviceStruct
*ptr
;
665 TRACE("cid=%d, function=%d\n", cid
, nFunction
);
669 TRACE("GETMAXCOM\n");
670 for (max
= MAX_PORTS
;!COM
[max
].devicename
;max
--)
675 TRACE("GETMAXLPT\n");
676 for (max
= MAX_PORTS
;!LPT
[max
].devicename
;max
--)
678 return FLAG_LPT
+ max
;
681 TRACE("GETBASEIRQ\n");
682 /* FIXME: use tables */
683 /* just fake something for now */
684 if (cid
& FLAG_LPT
) {
685 /* LPT1: irq 7, LPT2: irq 5 */
686 return (cid
& 0x7f) ? 5 : 7;
688 /* COM1: irq 4, COM2: irq 3,
689 COM3: irq 4, COM4: irq 3 */
690 return 4 - (cid
& 1);
694 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
695 FIXME("no cid=%d found!\n", cid
);
707 if(EscapeCommFunction(ptr
->handle
,nFunction
))
710 ptr
->commerror
= WinError();
717 WARN("(cid=%d,nFunction=%d): Unknown function\n",
723 /*****************************************************************************
724 * FlushComm (USER.215)
726 INT16 WINAPI
FlushComm16(INT16 cid
,INT16 fnQueue
)
729 struct DosDeviceStruct
*ptr
;
731 TRACE("cid=%d, queue=%d\n", cid
, fnQueue
);
732 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
733 FIXME("no cid=%d found!\n", cid
);
738 queue
= PURGE_TXABORT
;
739 ptr
->obuf_tail
= ptr
->obuf_head
;
742 queue
= PURGE_RXABORT
;
743 ptr
->ibuf_head
= ptr
->ibuf_tail
;
746 WARN("(cid=%d,fnQueue=%d):Unknown queue\n",
751 if (!PurgeComm(ptr
->handle
,queue
)) {
752 ptr
->commerror
= WinError();
760 /********************************************************************
761 * GetCommError (USER.203)
763 INT16 WINAPI
GetCommError16(INT16 cid
,LPCOMSTAT16 lpStat
)
766 struct DosDeviceStruct
*ptr
;
769 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
770 FIXME("no handle for cid = %0x!\n",cid
);
774 WARN(" cid %d not comm port\n",cid
);
777 stol
= (unsigned char *)COM
[cid
].unknown
+ COMM_MSR_OFFSET
;
778 COMM_MSRUpdate( ptr
->handle
, stol
);
785 rw_events
[0] = COM
[cid
].read_ov
.hEvent
;
786 rw_events
[1] = COM
[cid
].write_ov
.hEvent
;
788 WaitForMultipleObjectsEx(2,&rw_events
[0],FALSE
,1,TRUE
);
790 lpStat
->cbOutQue
= comm_outbuf(ptr
);
791 lpStat
->cbInQue
= comm_inbuf(ptr
);
793 TRACE("cid %d, error %d, stat %d in %d out %d, stol %x\n",
794 cid
, ptr
->commerror
, lpStat
->status
, lpStat
->cbInQue
,
795 lpStat
->cbOutQue
, *stol
);
798 TRACE("cid %d, error %d, lpStat NULL stol %x\n",
799 cid
, ptr
->commerror
, *stol
);
801 /* Return any errors and clear it */
802 temperror
= ptr
->commerror
;
807 /*****************************************************************************
808 * SetCommEventMask (USER.208)
810 SEGPTR WINAPI
SetCommEventMask16(INT16 cid
,UINT16 fuEvtMask
)
812 struct DosDeviceStruct
*ptr
;
815 TRACE("cid %d,mask %d\n",cid
,fuEvtMask
);
816 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
817 FIXME("no handle for cid = %0x!\n",cid
);
821 ptr
->eventmask
= fuEvtMask
;
823 if ((cid
&FLAG_LPT
) || !ValidCOMPort(cid
)) {
824 WARN(" cid %d not comm port\n",cid
);
827 /* it's a COM port ? -> modify flags */
828 stol
= (unsigned char *)COM
[cid
].unknown
+ COMM_MSR_OFFSET
;
829 COMM_MSRUpdate( ptr
->handle
, stol
);
831 TRACE(" modem dcd construct %x\n",*stol
);
832 return SEGPTR_GET(COM
[cid
].unknown
);
835 /*****************************************************************************
836 * GetCommEventMask (USER.209)
838 UINT16 WINAPI
GetCommEventMask16(INT16 cid
,UINT16 fnEvtClear
)
840 struct DosDeviceStruct
*ptr
;
843 TRACE("cid %d, mask %d\n", cid
, fnEvtClear
);
844 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
845 FIXME("no handle for cid = %0x!\n",cid
);
849 if ((cid
&FLAG_LPT
) || !ValidCOMPort(cid
)) {
850 WARN(" cid %d not comm port\n",cid
);
854 events
= *(WORD
*)(COM
[cid
].unknown
) & fnEvtClear
;
855 *(WORD
*)(COM
[cid
].unknown
) &= ~fnEvtClear
;
859 /*****************************************************************************
860 * SetCommState (USER.201)
862 INT16 WINAPI
SetCommState16(LPDCB16 lpdcb
)
864 struct DosDeviceStruct
*ptr
;
867 TRACE("cid %d, ptr %p\n", lpdcb
->Id
, lpdcb
);
868 if ((ptr
= GetDeviceStruct(lpdcb
->Id
)) == NULL
) {
869 FIXME("no handle for cid = %0x!\n",lpdcb
->Id
);
873 memset(&dcb
,0,sizeof dcb
);
874 dcb
.DCBlength
= sizeof dcb
;
875 if(lpdcb
->BaudRate
==57601)
876 dcb
.BaudRate
= 115200;
878 dcb
.BaudRate
= lpdcb
->BaudRate
;
880 dcb
.ByteSize
=lpdcb
->ByteSize
;
881 dcb
.StopBits
=lpdcb
->StopBits
;
883 dcb
.fParity
=lpdcb
->fParity
;
884 dcb
.Parity
=lpdcb
->Parity
;
886 dcb
.fOutxCtsFlow
= lpdcb
->fOutxCtsFlow
;
888 if (lpdcb
->fDtrflow
|| lpdcb
->fRtsflow
)
889 dcb
.fRtsControl
= TRUE
;
891 if (lpdcb
->fDtrDisable
)
892 dcb
.fDtrControl
= TRUE
;
894 ptr
->evtchar
= lpdcb
->EvtChar
;
896 dcb
.fInX
= lpdcb
->fInX
;
897 dcb
.fOutX
= lpdcb
->fOutX
;
899 if (!SetCommState(ptr
->handle
,&dcb
)) {
900 ptr
->commerror
= WinError();
908 /*****************************************************************************
909 * GetCommState (USER.202)
911 INT16 WINAPI
GetCommState16(INT16 cid
, LPDCB16 lpdcb
)
913 struct DosDeviceStruct
*ptr
;
916 TRACE("cid %d, ptr %p\n", cid
, lpdcb
);
917 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
918 FIXME("no handle for cid = %0x!\n",cid
);
921 if (!GetCommState(ptr
->handle
,&dcb
)) {
922 ptr
->commerror
= WinError();
928 COMM16_DCBtoDCB16(&dcb
,lpdcb
);
930 lpdcb
->EvtChar
= ptr
->evtchar
;
936 /*****************************************************************************
937 * TransmitCommChar (USER.206)
939 INT16 WINAPI
TransmitCommChar16(INT16 cid
,CHAR chTransmit
)
941 struct DosDeviceStruct
*ptr
;
943 TRACE("cid %d, data %d \n", cid
, chTransmit
);
944 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
945 FIXME("no handle for cid = %0x!\n",cid
);
949 if (ptr
->suspended
) {
950 ptr
->commerror
= IE_HARDWARE
;
954 if (ptr
->xmit
>= 0) {
955 /* character already queued */
956 /* FIXME: which error would Windows return? */
957 ptr
->commerror
= CE_TXFULL
;
961 if (ptr
->obuf_head
== ptr
->obuf_tail
) {
962 /* transmit queue empty, try to transmit directly */
964 if(!WriteFile(ptr
->handle
, &chTransmit
, 1, &len
, NULL
)) {
965 /* didn't work, queue it */
966 ptr
->xmit
= chTransmit
;
970 /* data in queue, let this char be transmitted next */
971 ptr
->xmit
= chTransmit
;
979 /*****************************************************************************
980 * UngetCommChar (USER.212)
982 INT16 WINAPI
UngetCommChar16(INT16 cid
,CHAR chUnget
)
984 struct DosDeviceStruct
*ptr
;
986 TRACE("cid %d (char %d)\n", cid
, chUnget
);
987 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
988 FIXME("no handle for cid = %0x!\n",cid
);
992 if (ptr
->suspended
) {
993 ptr
->commerror
= IE_HARDWARE
;
998 /* character already queued */
999 /* FIXME: which error would Windows return? */
1000 ptr
->commerror
= CE_RXOVER
;
1004 ptr
->unget
= chUnget
;
1010 /*****************************************************************************
1011 * ReadComm (USER.204)
1013 INT16 WINAPI
ReadComm16(INT16 cid
,LPSTR lpvBuf
,INT16 cbRead
)
1016 struct DosDeviceStruct
*ptr
;
1017 LPSTR orgBuf
= lpvBuf
;
1019 TRACE("cid %d, ptr %p, length %d\n", cid
, lpvBuf
, cbRead
);
1020 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
1021 FIXME("no handle for cid = %0x!\n",cid
);
1025 if (ptr
->suspended
) {
1026 ptr
->commerror
= IE_HARDWARE
;
1030 /* read unget character */
1031 if (ptr
->unget
>=0) {
1032 *lpvBuf
++ = ptr
->unget
;
1039 /* read from receive buffer */
1040 while (length
< cbRead
) {
1041 status
= ((ptr
->ibuf_head
< ptr
->ibuf_tail
) ?
1042 ptr
->ibuf_size
: ptr
->ibuf_head
) - ptr
->ibuf_tail
;
1044 if ((cbRead
- length
) < status
)
1045 status
= cbRead
- length
;
1047 memcpy(lpvBuf
, ptr
->inbuf
+ ptr
->ibuf_tail
, status
);
1048 ptr
->ibuf_tail
+= status
;
1049 if (ptr
->ibuf_tail
>= ptr
->ibuf_size
)
1055 TRACE("%.*s\n", length
, orgBuf
);
1060 /*****************************************************************************
1061 * WriteComm (USER.205)
1063 INT16 WINAPI
WriteComm16(INT16 cid
, LPSTR lpvBuf
, INT16 cbWrite
)
1066 struct DosDeviceStruct
*ptr
;
1068 TRACE("cid %d, ptr %p, length %d\n",
1069 cid
, lpvBuf
, cbWrite
);
1070 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
1071 FIXME("no handle for cid = %0x!\n",cid
);
1075 if (ptr
->suspended
) {
1076 ptr
->commerror
= IE_HARDWARE
;
1080 TRACE("%.*s\n", cbWrite
, lpvBuf
);
1083 while (length
< cbWrite
) {
1084 if ((ptr
->obuf_head
== ptr
->obuf_tail
) && (ptr
->xmit
< 0)) {
1085 /* no data queued, try to write directly */
1086 if(!WriteFile(ptr
->handle
, lpvBuf
, cbWrite
- length
, (LPDWORD
)&status
, NULL
))
1094 /* can't write directly, put into transmit buffer */
1095 status
= ((ptr
->obuf_tail
> ptr
->obuf_head
) ?
1096 (ptr
->obuf_tail
-1) : ptr
->obuf_size
) - ptr
->obuf_head
;
1098 if ((cbWrite
- length
) < status
)
1099 status
= cbWrite
- length
;
1100 memcpy(lpvBuf
, ptr
->outbuf
+ ptr
->obuf_head
, status
);
1101 ptr
->obuf_head
+= status
;
1102 if (ptr
->obuf_head
>= ptr
->obuf_size
)
1106 comm_waitwrite(ptr
);
1113 /***********************************************************************
1114 * EnableCommNotification (USER.245)
1116 BOOL16 WINAPI
EnableCommNotification16( INT16 cid
, HWND16 hwnd
,
1117 INT16 cbWriteNotify
, INT16 cbOutQueue
)
1119 struct DosDeviceStruct
*ptr
;
1121 TRACE("(%d, %x, %d, %d)\n", cid
, hwnd
, cbWriteNotify
, cbOutQueue
);
1122 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
1123 FIXME("no handle for cid = %0x!\n",cid
);
1127 ptr
->n_read
= cbWriteNotify
;
1128 ptr
->n_write
= cbOutQueue
;