2 * DEC 93 Erik Bos <erik@xs4all.nl>
4 * Copyright 1996 Marcus Meissner
6 * Copyright 2001 Mike McCormack
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 * Mar 31, 1999. Ove Kåven <ovek@arcticnet.no>
25 * - Implemented buffers and EnableCommNotification.
27 * Apr 3, 1999. Lawson Whitney <lawson_whitney@juno.com>
28 * - Fixed the modem control part of EscapeCommFunction16.
30 * Mar 3, 1999. Ove Kåven <ovek@arcticnet.no>
31 * - Use port indices instead of unixfds for win16
32 * - Moved things around (separated win16 and win32 routines)
33 * - Added some hints on how to implement buffers and EnableCommNotification.
35 * May 26, 1997. Fixes and comments by Rick Richardson <rick@dgii.com> [RER]
36 * - ptr->fd wasn't getting cleared on close.
37 * - GetCommEventMask() and GetCommError() didn't do much of anything.
38 * IMHO, they are still wrong, but they at least implement the RXCHAR
39 * event and return I/O queue sizes, which makes the app I'm interested
40 * in (analog devices EZKIT DSP development system) work.
42 * August 12, 1997. Take a bash at SetCommEventMask - Lawson Whitney
43 * <lawson_whitney@juno.com>
44 * July 6, 1998. Fixes and comments by Valentijn Sessink
45 * <vsessink@ic.uva.nl> [V]
46 * Oktober 98, Rein Klazes [RHK]
47 * A program that wants to monitor the modem status line (RLSD/DCD) may
48 * poll the modem status register in the commMask structure. I update the bit
49 * in GetCommError, waiting for an implementation of communication events.
54 #include "wine/port.h"
65 #include "wine/winuser16.h"
66 #include "user_private.h"
68 #include "wine/debug.h"
70 WINE_DEFAULT_DEBUG_CHANNEL(comm
);
72 /* window's semi documented modem status register */
73 #define COMM_MSR_OFFSET 35
78 #define MSR_MASK (MSR_CTS|MSR_DSR|MSR_RI|MSR_RLSD)
84 struct DosDeviceStruct
{
90 int commerror
, eventmask
;
93 unsigned ibuf_size
,ibuf_head
,ibuf_tail
;
94 unsigned obuf_size
,obuf_head
,obuf_tail
;
98 OVERLAPPED read_ov
, write_ov
;
99 /* save terminal states */
101 /* pointer to unknown(==undocumented) comm structure */
106 static struct DosDeviceStruct COM
[MAX_PORTS
];
107 static struct DosDeviceStruct LPT
[MAX_PORTS
];
109 /* update window's semi documented modem status register */
110 /* see knowledge base Q101417 */
111 static void COMM_MSRUpdate( HANDLE handle
, UCHAR
* pMsr
)
116 if(!GetCommModemStatus(handle
,&mstat
))
119 if(mstat
& MS_CTS_ON
) tmpmsr
|= MSR_CTS
;
120 if(mstat
& MS_DSR_ON
) tmpmsr
|= MSR_DSR
;
121 if(mstat
& MS_RING_ON
) tmpmsr
|= MSR_RI
;
122 if(mstat
& MS_RLSD_ON
) tmpmsr
|= MSR_RLSD
;
123 *pMsr
= (*pMsr
& ~MSR_MASK
) | tmpmsr
;
126 static struct DosDeviceStruct
*GetDeviceStruct(int index
)
128 if ((index
&0x7F)<=MAX_PORTS
) {
129 if (!(index
&FLAG_LPT
)) {
130 if (COM
[index
].handle
)
134 if (LPT
[index
].handle
)
142 static int GetCommPort_ov(const OVERLAPPED
*ov
, int write
)
146 for (x
=0; x
<MAX_PORTS
; x
++) {
147 if (ov
== (write
?&COM
[x
].write_ov
:&COM
[x
].read_ov
))
154 static int WinError(void)
156 TRACE("errno = %d\n", errno
);
163 static unsigned comm_inbuf(const struct DosDeviceStruct
*ptr
)
165 return ((ptr
->ibuf_tail
> ptr
->ibuf_head
) ? ptr
->ibuf_size
: 0)
166 + ptr
->ibuf_head
- ptr
->ibuf_tail
;
169 static unsigned comm_outbuf(const struct DosDeviceStruct
*ptr
)
171 return ((ptr
->obuf_tail
> ptr
->obuf_head
) ? ptr
->obuf_size
: 0)
172 + ptr
->obuf_head
- ptr
->obuf_tail
;
175 static void comm_waitread(struct DosDeviceStruct
*ptr
);
176 static void comm_waitwrite(struct DosDeviceStruct
*ptr
);
178 static VOID WINAPI
COMM16_ReadComplete(DWORD dwErrorCode
, DWORD len
, LPOVERLAPPED ov
)
182 int cid
= GetCommPort_ov(ov
,0);
183 struct DosDeviceStruct
*ptr
;
186 ERR("async write with bad overlapped pointer\n");
191 /* we get cancelled when CloseComm is called */
192 if (dwErrorCode
==ERROR_OPERATION_ABORTED
)
194 TRACE("Cancelled\n");
198 /* read data from comm port */
199 if (dwErrorCode
!= NO_ERROR
) {
200 ERR("async read failed, error %d\n",dwErrorCode
);
201 COM
[cid
].commerror
= CE_RXOVER
;
204 TRACE("async read completed %d bytes\n",len
);
206 prev
= comm_inbuf(ptr
);
208 /* check for events */
209 if ((ptr
->eventmask
& EV_RXFLAG
) &&
210 memchr(ptr
->inbuf
+ ptr
->ibuf_head
, ptr
->evtchar
, len
)) {
211 *(WORD
*)(COM
[cid
].unknown
) |= EV_RXFLAG
;
214 if (ptr
->eventmask
& EV_RXCHAR
) {
215 *(WORD
*)(COM
[cid
].unknown
) |= EV_RXCHAR
;
219 /* advance buffer position */
220 ptr
->ibuf_head
+= len
;
221 if (ptr
->ibuf_head
>= ptr
->ibuf_size
)
224 /* check for notification */
225 if (ptr
->wnd
&& (ptr
->n_read
>0) && (prev
<ptr
->n_read
) &&
226 (comm_inbuf(ptr
)>=ptr
->n_read
)) {
227 /* passed the receive notification threshold */
231 /* send notifications, if any */
232 if (ptr
->wnd
&& mask
) {
233 TRACE("notifying %p: cid=%d, mask=%02x\n", ptr
->wnd
, cid
, mask
);
234 PostMessageA(ptr
->wnd
, WM_COMMNOTIFY
, cid
, mask
);
237 /* on real windows, this could cause problems, since it is recursive */
238 /* restart the receive */
242 /* this is meant to work like write() */
243 static INT
COMM16_WriteFile(HANDLE hComm
, LPCVOID buffer
, DWORD len
)
248 ZeroMemory(&ov
,sizeof(ov
));
249 ov
.hEvent
= CreateEventW(NULL
,0,0,NULL
);
250 if(ov
.hEvent
==INVALID_HANDLE_VALUE
)
253 if(!WriteFile(hComm
,buffer
,len
,&count
,&ov
))
255 if(GetLastError()==ERROR_IO_PENDING
)
257 GetOverlappedResult(hComm
,&ov
,&count
,TRUE
);
260 CloseHandle(ov
.hEvent
);
265 static VOID WINAPI
COMM16_WriteComplete(DWORD dwErrorCode
, DWORD len
, LPOVERLAPPED ov
)
269 int cid
= GetCommPort_ov(ov
,1);
270 struct DosDeviceStruct
*ptr
;
273 ERR("async write with bad overlapped pointer\n");
278 /* read data from comm port */
279 if (dwErrorCode
!= NO_ERROR
) {
280 ERR("async write failed, error %d\n",dwErrorCode
);
281 COM
[cid
].commerror
= CE_RXOVER
;
284 TRACE("async write completed %d bytes\n",len
);
286 /* update the buffer pointers */
287 prev
= comm_outbuf(&COM
[cid
]);
288 ptr
->obuf_tail
+= len
;
289 if (ptr
->obuf_tail
>= ptr
->obuf_size
)
292 /* write any TransmitCommChar character */
294 len
= COMM16_WriteFile(ptr
->handle
, &(ptr
->xmit
), 1);
295 if (len
> 0) ptr
->xmit
= -1;
298 /* write from output queue */
299 bleft
= ((ptr
->obuf_tail
<= ptr
->obuf_head
) ?
300 ptr
->obuf_head
: ptr
->obuf_size
) - ptr
->obuf_tail
;
302 /* check for notification */
303 if (ptr
->wnd
&& (ptr
->n_write
>0) && (prev
>=ptr
->n_write
) &&
304 (comm_outbuf(ptr
)<ptr
->n_write
)) {
305 /* passed the transmit notification threshold */
309 /* send notifications, if any */
310 if (ptr
->wnd
&& mask
) {
311 TRACE("notifying %p: cid=%d, mask=%02x\n", ptr
->wnd
, cid
, mask
);
312 PostMessageA(ptr
->wnd
, WM_COMMNOTIFY
, cid
, mask
);
315 /* start again if necessary */
320 static void comm_waitread(struct DosDeviceStruct
*ptr
)
325 /* FIXME: get timeouts working properly so we can read bleft bytes */
326 bleft
= ((ptr
->ibuf_tail
> ptr
->ibuf_head
) ?
327 (ptr
->ibuf_tail
-1) : ptr
->ibuf_size
) - ptr
->ibuf_head
;
329 /* find out how many bytes are left in the buffer */
330 if(ClearCommError(ptr
->handle
,NULL
,&stat
))
331 bleft
= (bleft
<stat
.cbInQue
) ? bleft
: stat
.cbInQue
;
335 /* always read at least one byte */
339 ReadFileEx(ptr
->handle
,
340 ptr
->inbuf
+ ptr
->ibuf_head
,
343 COMM16_ReadComplete
);
346 static void comm_waitwrite(struct DosDeviceStruct
*ptr
)
350 bleft
= ((ptr
->obuf_tail
<= ptr
->obuf_head
) ?
351 ptr
->obuf_head
: ptr
->obuf_size
) - ptr
->obuf_tail
;
352 WriteFileEx(ptr
->handle
,
353 ptr
->outbuf
+ ptr
->obuf_tail
,
356 COMM16_WriteComplete
);
359 /*****************************************************************************
360 * COMM16_DCBtoDCB16 (Internal)
362 static INT16
COMM16_DCBtoDCB16(const DCB
*lpdcb
, LPDCB16 lpdcb16
)
364 if(lpdcb
->BaudRate
<0x10000)
365 lpdcb16
->BaudRate
= lpdcb
->BaudRate
;
366 else if(lpdcb
->BaudRate
==115200)
367 lpdcb16
->BaudRate
= 57601;
369 WARN("Baud rate can't be converted\n");
370 lpdcb16
->BaudRate
= 57601;
372 lpdcb16
->ByteSize
= lpdcb
->ByteSize
;
373 lpdcb16
->fParity
= lpdcb
->fParity
;
374 lpdcb16
->Parity
= lpdcb
->Parity
;
375 lpdcb16
->StopBits
= lpdcb
->StopBits
;
377 lpdcb16
->RlsTimeout
= 50;
378 lpdcb16
->CtsTimeout
= 50;
379 lpdcb16
->DsrTimeout
= 50;
382 lpdcb16
->fBinary
= 1;
384 lpdcb16
->fDtrflow
= (lpdcb
->fDtrControl
==DTR_CONTROL_HANDSHAKE
);
385 lpdcb16
->fRtsflow
= (lpdcb
->fRtsControl
==RTS_CONTROL_HANDSHAKE
);
386 lpdcb16
->fOutxCtsFlow
= lpdcb
->fOutxCtsFlow
;
387 lpdcb16
->fOutxDsrFlow
= lpdcb
->fOutxDsrFlow
;
388 lpdcb16
->fDtrDisable
= (lpdcb
->fDtrControl
==DTR_CONTROL_DISABLE
);
390 lpdcb16
->fInX
= lpdcb
->fInX
;
392 lpdcb16
->fOutX
= lpdcb
->fOutX
;
397 lpdcb16
->XonLim
= 10;
398 lpdcb16
->XoffLim
= 10;
404 /**************************************************************************
405 * BuildCommDCB (USER.213)
407 * According to the ECMA-234 (368.3) the function will return FALSE on
408 * success, otherwise it will return -1.
410 INT16 WINAPI
BuildCommDCB16(LPCSTR device
, LPDCB16 lpdcb
)
412 /* "COM1:96,n,8,1" */
417 TRACE("(%s), ptr %p\n", device
, lpdcb
);
419 if (strncasecmp(device
,"COM",3))
421 port
= device
[3] - '0';
424 ERR("BUG ! COM0 can't exist!\n");
428 memset(lpdcb
, 0, sizeof(DCB16
)); /* initialize */
431 dcb
.DCBlength
= sizeof(DCB
);
433 if (strchr(device
,'=')) /* block new style */
436 if(!BuildCommDCBA(device
,&dcb
))
439 return COMM16_DCBtoDCB16(&dcb
, lpdcb
);
442 /*****************************************************************************
443 * OpenComm (USER.200)
445 INT16 WINAPI
OpenComm16(LPCSTR device
,UINT16 cbInQueue
,UINT16 cbOutQueue
)
450 TRACE("%s, %d, %d\n", device
, cbInQueue
, cbOutQueue
);
452 if (strlen(device
) < 4)
455 port
= device
[3] - '0';
458 ERR("BUG ! COM0 or LPT0 don't exist !\n");
460 if (!strncasecmp(device
,"COM",3))
462 if (COM
[port
].handle
)
465 handle
= CreateFileA(device
, GENERIC_READ
|GENERIC_WRITE
,
466 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, CREATE_ALWAYS
,
467 FILE_FLAG_OVERLAPPED
|FILE_FLAG_NO_BUFFERING
, 0 );
468 if (handle
== INVALID_HANDLE_VALUE
) {
471 memset(COM
[port
].unknown
, 0, sizeof(COM
[port
].unknown
));
472 COM
[port
].seg_unknown
= 0;
473 COM
[port
].handle
= handle
;
474 COM
[port
].commerror
= 0;
475 COM
[port
].eventmask
= 0;
476 COM
[port
].evtchar
= 0; /* FIXME: default? */
477 /* save terminal state */
478 GetCommState16(port
,&COM
[port
].dcb
);
479 /* init priority characters */
480 COM
[port
].unget
= -1;
482 /* allocate buffers */
483 COM
[port
].ibuf_size
= cbInQueue
;
484 COM
[port
].ibuf_head
= COM
[port
].ibuf_tail
= 0;
485 COM
[port
].obuf_size
= cbOutQueue
;
486 COM
[port
].obuf_head
= COM
[port
].obuf_tail
= 0;
488 COM
[port
].inbuf
= HeapAlloc(GetProcessHeap(), 0, cbInQueue
);
489 if (COM
[port
].inbuf
) {
490 COM
[port
].outbuf
= HeapAlloc( GetProcessHeap(), 0, cbOutQueue
);
491 if (!COM
[port
].outbuf
)
492 HeapFree( GetProcessHeap(), 0, COM
[port
].inbuf
);
493 } else COM
[port
].outbuf
= NULL
;
494 if (!COM
[port
].outbuf
) {
495 /* not enough memory */
496 CloseHandle(COM
[port
].handle
);
497 ERR("out of memory\n");
501 ZeroMemory(&COM
[port
].read_ov
,sizeof (OVERLAPPED
));
502 ZeroMemory(&COM
[port
].write_ov
,sizeof (OVERLAPPED
));
504 comm_waitread( &COM
[port
] );
505 USER16_AlertableWait
++;
511 if (!strncasecmp(device
,"LPT",3)) {
513 if (LPT
[port
].handle
)
516 handle
= CreateFileA(device
, GENERIC_READ
|GENERIC_WRITE
,
517 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, CREATE_ALWAYS
, 0, 0 );
518 if (handle
== INVALID_HANDLE_VALUE
) {
521 LPT
[port
].handle
= handle
;
522 LPT
[port
].commerror
= 0;
523 LPT
[port
].eventmask
= 0;
524 return port
|FLAG_LPT
;
530 /*****************************************************************************
531 * CloseComm (USER.207)
533 INT16 WINAPI
CloseComm16(INT16 cid
)
535 struct DosDeviceStruct
*ptr
;
537 TRACE("cid=%d\n", cid
);
538 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
539 FIXME("no cid=%d found!\n", cid
);
542 if (!(cid
&FLAG_LPT
)) {
544 UnMapLS( COM
[cid
].seg_unknown
);
545 USER16_AlertableWait
--;
546 CancelIo(ptr
->handle
);
549 HeapFree( GetProcessHeap(), 0, ptr
->outbuf
);
550 HeapFree( GetProcessHeap(), 0, ptr
->inbuf
);
552 /* reset modem lines */
553 SetCommState16(&COM
[cid
].dcb
);
556 if (!CloseHandle(ptr
->handle
)) {
557 ptr
->commerror
= WinError();
558 /* FIXME: should we clear ptr->handle here? */
567 /*****************************************************************************
568 * SetCommBreak (USER.210)
570 INT16 WINAPI
SetCommBreak16(INT16 cid
)
572 struct DosDeviceStruct
*ptr
;
574 TRACE("cid=%d\n", cid
);
575 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
576 FIXME("no cid=%d found!\n", cid
);
580 ptr
->suspended
= TRUE
;
585 /*****************************************************************************
586 * ClearCommBreak (USER.211)
588 INT16 WINAPI
ClearCommBreak16(INT16 cid
)
590 struct DosDeviceStruct
*ptr
;
592 TRACE("cid=%d\n", cid
);
593 if (!(ptr
= GetDeviceStruct(cid
))) {
594 FIXME("no cid=%d found!\n", cid
);
597 ptr
->suspended
= FALSE
;
602 /*****************************************************************************
603 * EscapeCommFunction (USER.214)
605 LONG WINAPI
EscapeCommFunction16(UINT16 cid
,UINT16 nFunction
)
607 struct DosDeviceStruct
*ptr
;
609 TRACE("cid=%d, function=%d\n", cid
, nFunction
);
613 TRACE("GETMAXCOM\n");
614 return 4; /* FIXME */
617 TRACE("GETMAXLPT\n");
618 return FLAG_LPT
+ 3; /* FIXME */
621 TRACE("GETBASEIRQ\n");
622 /* FIXME: use tables */
623 /* just fake something for now */
624 if (cid
& FLAG_LPT
) {
625 /* LPT1: irq 7, LPT2: irq 5 */
626 return (cid
& 0x7f) ? 5 : 7;
628 /* COM1: irq 4, COM2: irq 3,
629 COM3: irq 4, COM4: irq 3 */
630 return 4 - (cid
& 1);
634 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
635 FIXME("no cid=%d found!\n", cid
);
647 if(EscapeCommFunction(ptr
->handle
,nFunction
))
650 ptr
->commerror
= WinError();
657 WARN("(cid=%d,nFunction=%d): Unknown function\n",
663 /*****************************************************************************
664 * FlushComm (USER.215)
666 INT16 WINAPI
FlushComm16(INT16 cid
,INT16 fnQueue
)
669 struct DosDeviceStruct
*ptr
;
671 TRACE("cid=%d, queue=%d\n", cid
, fnQueue
);
672 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
673 FIXME("no cid=%d found!\n", cid
);
678 queue
= PURGE_TXABORT
;
679 ptr
->obuf_tail
= ptr
->obuf_head
;
682 queue
= PURGE_RXABORT
;
683 ptr
->ibuf_head
= ptr
->ibuf_tail
;
686 WARN("(cid=%d,fnQueue=%d):Unknown queue\n",
691 if (!PurgeComm(ptr
->handle
,queue
)) {
692 ptr
->commerror
= WinError();
700 /********************************************************************
701 * GetCommError (USER.203)
703 INT16 WINAPI
GetCommError16(INT16 cid
,LPCOMSTAT16 lpStat
)
706 struct DosDeviceStruct
*ptr
;
709 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
710 FIXME("no handle for cid = %0x!\n",cid
);
714 WARN(" cid %d not comm port\n",cid
);
717 stol
= (unsigned char *)COM
[cid
].unknown
+ COMM_MSR_OFFSET
;
718 COMM_MSRUpdate( ptr
->handle
, stol
);
723 if (comm_inbuf(ptr
) == 0)
726 lpStat
->cbOutQue
= comm_outbuf(ptr
);
727 lpStat
->cbInQue
= comm_inbuf(ptr
);
729 TRACE("cid %d, error %d, stat %d in %d out %d, stol %x\n",
730 cid
, ptr
->commerror
, lpStat
->status
, lpStat
->cbInQue
,
731 lpStat
->cbOutQue
, *stol
);
734 TRACE("cid %d, error %d, lpStat NULL stol %x\n",
735 cid
, ptr
->commerror
, *stol
);
737 /* Return any errors and clear it */
738 temperror
= ptr
->commerror
;
743 /*****************************************************************************
744 * SetCommEventMask (USER.208)
746 SEGPTR WINAPI
SetCommEventMask16(INT16 cid
,UINT16 fuEvtMask
)
748 struct DosDeviceStruct
*ptr
;
751 TRACE("cid %d,mask %d\n",cid
,fuEvtMask
);
752 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
753 FIXME("no handle for cid = %0x!\n",cid
);
757 ptr
->eventmask
= fuEvtMask
;
760 WARN(" cid %d not comm port\n",cid
);
763 /* it's a COM port ? -> modify flags */
764 stol
= (unsigned char *)COM
[cid
].unknown
+ COMM_MSR_OFFSET
;
765 COMM_MSRUpdate( ptr
->handle
, stol
);
767 TRACE(" modem dcd construct %x\n",*stol
);
768 if (!COM
[cid
].seg_unknown
) COM
[cid
].seg_unknown
= MapLS( COM
[cid
].unknown
);
769 return COM
[cid
].seg_unknown
;
772 /*****************************************************************************
773 * GetCommEventMask (USER.209)
775 UINT16 WINAPI
GetCommEventMask16(INT16 cid
,UINT16 fnEvtClear
)
777 struct DosDeviceStruct
*ptr
;
780 TRACE("cid %d, mask %d\n", cid
, fnEvtClear
);
781 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
782 FIXME("no handle for cid = %0x!\n",cid
);
787 WARN(" cid %d not comm port\n",cid
);
791 events
= *(WORD
*)(COM
[cid
].unknown
) & fnEvtClear
;
792 *(WORD
*)(COM
[cid
].unknown
) &= ~fnEvtClear
;
796 /*****************************************************************************
797 * SetCommState (USER.201)
799 INT16 WINAPI
SetCommState16(LPDCB16 lpdcb
)
801 struct DosDeviceStruct
*ptr
;
804 TRACE("cid %d, ptr %p\n", lpdcb
->Id
, lpdcb
);
805 if ((ptr
= GetDeviceStruct(lpdcb
->Id
)) == NULL
) {
806 FIXME("no handle for cid = %0x!\n",lpdcb
->Id
);
810 memset(&dcb
,0,sizeof(dcb
));
811 dcb
.DCBlength
= sizeof(dcb
);
814 * according to MSDN, we should first interpret lpdcb->BaudRate as follows:
815 * 1. if the baud rate is a CBR constant, interpret it.
816 * 2. if it is greater than 57600, the baud rate is 115200
817 * 3. use the actual baudrate
818 * steps 2 and 3 are equivalent to 16550 baudrate divisor = 115200/BaudRate
820 switch(lpdcb
->BaudRate
)
822 case CBR_110
: dcb
.BaudRate
= 110; break;
823 case CBR_300
: dcb
.BaudRate
= 300; break;
824 case CBR_600
: dcb
.BaudRate
= 600; break;
825 case CBR_1200
: dcb
.BaudRate
= 1200; break;
826 case CBR_2400
: dcb
.BaudRate
= 2400; break;
827 case CBR_4800
: dcb
.BaudRate
= 4800; break;
828 case CBR_9600
: dcb
.BaudRate
= 9600; break;
829 case CBR_14400
: dcb
.BaudRate
= 14400; break;
830 case CBR_19200
: dcb
.BaudRate
= 19200; break;
831 case CBR_38400
: dcb
.BaudRate
= 38400; break;
832 case CBR_56000
: dcb
.BaudRate
= 56000; break;
833 case CBR_128000
: dcb
.BaudRate
= 128000; break;
834 case CBR_256000
: dcb
.BaudRate
= 256000; break;
836 if(lpdcb
->BaudRate
>57600)
837 dcb
.BaudRate
= 115200;
839 dcb
.BaudRate
= lpdcb
->BaudRate
;
842 dcb
.ByteSize
=lpdcb
->ByteSize
;
843 dcb
.StopBits
=lpdcb
->StopBits
;
845 dcb
.fParity
=lpdcb
->fParity
;
846 dcb
.Parity
=lpdcb
->Parity
;
848 dcb
.fOutxCtsFlow
= lpdcb
->fOutxCtsFlow
;
850 if (lpdcb
->fDtrflow
|| lpdcb
->fRtsflow
)
851 dcb
.fRtsControl
= TRUE
;
853 if (lpdcb
->fDtrDisable
)
854 dcb
.fDtrControl
= TRUE
;
856 ptr
->evtchar
= lpdcb
->EvtChar
;
858 dcb
.fInX
= lpdcb
->fInX
;
859 dcb
.fOutX
= lpdcb
->fOutX
;
861 if (!SetCommState(ptr
->handle
,&dcb
)) {
862 ptr
->commerror
= WinError();
870 /*****************************************************************************
871 * GetCommState (USER.202)
873 INT16 WINAPI
GetCommState16(INT16 cid
, LPDCB16 lpdcb
)
875 struct DosDeviceStruct
*ptr
;
878 TRACE("cid %d, ptr %p\n", cid
, lpdcb
);
879 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
880 FIXME("no handle for cid = %0x!\n",cid
);
883 if (!GetCommState(ptr
->handle
,&dcb
)) {
884 ptr
->commerror
= WinError();
890 COMM16_DCBtoDCB16(&dcb
,lpdcb
);
892 lpdcb
->EvtChar
= ptr
->evtchar
;
898 /*****************************************************************************
899 * TransmitCommChar (USER.206)
901 INT16 WINAPI
TransmitCommChar16(INT16 cid
,CHAR chTransmit
)
903 struct DosDeviceStruct
*ptr
;
905 TRACE("cid %d, data %d\n", cid
, chTransmit
);
906 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
907 FIXME("no handle for cid = %0x!\n",cid
);
911 if (ptr
->suspended
) {
912 ptr
->commerror
= IE_HARDWARE
;
916 if (ptr
->xmit
>= 0) {
917 /* character already queued */
918 /* FIXME: which error would Windows return? */
919 ptr
->commerror
= CE_TXFULL
;
923 if (ptr
->obuf_head
== ptr
->obuf_tail
) {
924 /* transmit queue empty, try to transmit directly */
925 if(1!=COMM16_WriteFile(ptr
->handle
, &chTransmit
, 1))
927 /* didn't work, queue it */
928 ptr
->xmit
= chTransmit
;
932 /* data in queue, let this char be transmitted next */
933 ptr
->xmit
= chTransmit
;
941 /*****************************************************************************
942 * UngetCommChar (USER.212)
944 INT16 WINAPI
UngetCommChar16(INT16 cid
,CHAR chUnget
)
946 struct DosDeviceStruct
*ptr
;
948 TRACE("cid %d (char %d)\n", cid
, chUnget
);
949 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
950 FIXME("no handle for cid = %0x!\n",cid
);
954 if (ptr
->suspended
) {
955 ptr
->commerror
= IE_HARDWARE
;
960 /* character already queued */
961 /* FIXME: which error would Windows return? */
962 ptr
->commerror
= CE_RXOVER
;
966 ptr
->unget
= chUnget
;
972 /*****************************************************************************
973 * ReadComm (USER.204)
975 INT16 WINAPI
ReadComm16(INT16 cid
,LPSTR lpvBuf
,INT16 cbRead
)
978 struct DosDeviceStruct
*ptr
;
979 LPSTR orgBuf
= lpvBuf
;
981 TRACE("cid %d, ptr %p, length %d\n", cid
, lpvBuf
, cbRead
);
982 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
983 FIXME("no handle for cid = %0x!\n",cid
);
987 if (ptr
->suspended
) {
988 ptr
->commerror
= IE_HARDWARE
;
992 if(0==comm_inbuf(ptr
))
995 /* read unget character */
997 *lpvBuf
++ = ptr
->unget
;
1004 /* read from receive buffer */
1005 while (length
< cbRead
) {
1006 status
= ((ptr
->ibuf_head
< ptr
->ibuf_tail
) ?
1007 ptr
->ibuf_size
: ptr
->ibuf_head
) - ptr
->ibuf_tail
;
1009 if ((cbRead
- length
) < status
)
1010 status
= cbRead
- length
;
1012 memcpy(lpvBuf
, ptr
->inbuf
+ ptr
->ibuf_tail
, status
);
1013 ptr
->ibuf_tail
+= status
;
1014 if (ptr
->ibuf_tail
>= ptr
->ibuf_size
)
1020 TRACE("%s\n", debugstr_an( orgBuf
, length
));
1025 /*****************************************************************************
1026 * WriteComm (USER.205)
1028 INT16 WINAPI
WriteComm16(INT16 cid
, LPSTR lpvBuf
, INT16 cbWrite
)
1031 struct DosDeviceStruct
*ptr
;
1033 TRACE("cid %d, ptr %p, length %d\n",
1034 cid
, lpvBuf
, cbWrite
);
1035 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
1036 FIXME("no handle for cid = %0x!\n",cid
);
1040 if (ptr
->suspended
) {
1041 ptr
->commerror
= IE_HARDWARE
;
1045 TRACE("%s\n", debugstr_an( lpvBuf
, cbWrite
));
1048 while (length
< cbWrite
) {
1049 if ((ptr
->obuf_head
== ptr
->obuf_tail
) && (ptr
->xmit
< 0)) {
1050 /* no data queued, try to write directly */
1051 status
= COMM16_WriteFile(ptr
->handle
, lpvBuf
, cbWrite
- length
);
1058 /* can't write directly, put into transmit buffer */
1059 status
= ((ptr
->obuf_tail
> ptr
->obuf_head
) ?
1060 (ptr
->obuf_tail
-1) : ptr
->obuf_size
) - ptr
->obuf_head
;
1062 if ((cbWrite
- length
) < status
)
1063 status
= cbWrite
- length
;
1064 memcpy(lpvBuf
, ptr
->outbuf
+ ptr
->obuf_head
, status
);
1065 ptr
->obuf_head
+= status
;
1066 if (ptr
->obuf_head
>= ptr
->obuf_size
)
1070 comm_waitwrite(ptr
);
1077 /***********************************************************************
1078 * EnableCommNotification (USER.245)
1080 BOOL16 WINAPI
EnableCommNotification16( INT16 cid
, HWND16 hwnd
,
1081 INT16 cbWriteNotify
, INT16 cbOutQueue
)
1083 struct DosDeviceStruct
*ptr
;
1085 TRACE("(%d, %x, %d, %d)\n", cid
, hwnd
, cbWriteNotify
, cbOutQueue
);
1086 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
1087 FIXME("no handle for cid = %0x!\n",cid
);
1090 ptr
->wnd
= WIN_Handle32( hwnd
);
1091 ptr
->n_read
= cbWriteNotify
;
1092 ptr
->n_write
= cbOutQueue
;