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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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"
69 #include "wine/winuser16.h"
73 #include "wine/debug.h"
75 WINE_DEFAULT_DEBUG_CHANNEL(comm
);
77 /* window's semi documented modem status register */
78 #define COMM_MSR_OFFSET 35
83 #define MSR_MASK (MSR_CTS|MSR_DSR|MSR_RI|MSR_RLSD)
89 struct DosDeviceStruct
{
95 int commerror
, eventmask
;
98 unsigned ibuf_size
,ibuf_head
,ibuf_tail
;
99 unsigned obuf_size
,obuf_head
,obuf_tail
;
103 OVERLAPPED read_ov
, write_ov
;
104 /* save terminal states */
106 /* pointer to unknown(==undocumented) comm structure */
111 static struct DosDeviceStruct COM
[MAX_PORTS
];
112 static struct DosDeviceStruct LPT
[MAX_PORTS
];
114 /* update window's semi documented modem status register */
115 /* see knowledge base Q101417 */
116 static void COMM_MSRUpdate( HANDLE handle
, UCHAR
* pMsr
)
121 if(!GetCommModemStatus(handle
,&mstat
))
124 if(mstat
& MS_CTS_ON
) tmpmsr
|= MSR_CTS
;
125 if(mstat
& MS_DSR_ON
) tmpmsr
|= MSR_DSR
;
126 if(mstat
& MS_RING_ON
) tmpmsr
|= MSR_RI
;
127 if(mstat
& MS_RLSD_ON
) tmpmsr
|= MSR_RLSD
;
128 *pMsr
= (*pMsr
& ~MSR_MASK
) | tmpmsr
;
131 static struct DosDeviceStruct
*GetDeviceStruct(int index
)
133 if ((index
&0x7F)<=MAX_PORTS
) {
134 if (!(index
&FLAG_LPT
)) {
135 if (COM
[index
].handle
)
139 if (LPT
[index
].handle
)
147 static int GetCommPort_ov(LPOVERLAPPED ov
, int write
)
151 for (x
=0; x
<MAX_PORTS
; x
++) {
152 if (ov
== (write
?&COM
[x
].write_ov
:&COM
[x
].read_ov
))
159 static int WinError(void)
161 TRACE("errno = %d\n", errno
);
168 static unsigned comm_inbuf(struct DosDeviceStruct
*ptr
)
170 return ((ptr
->ibuf_tail
> ptr
->ibuf_head
) ? ptr
->ibuf_size
: 0)
171 + ptr
->ibuf_head
- ptr
->ibuf_tail
;
174 static unsigned comm_outbuf(struct DosDeviceStruct
*ptr
)
176 return ((ptr
->obuf_tail
> ptr
->obuf_head
) ? ptr
->obuf_size
: 0)
177 + ptr
->obuf_head
- ptr
->obuf_tail
;
180 static void comm_waitread(struct DosDeviceStruct
*ptr
);
181 static void comm_waitwrite(struct DosDeviceStruct
*ptr
);
183 static VOID WINAPI
COMM16_ReadComplete(DWORD status
, DWORD len
, LPOVERLAPPED ov
)
187 int cid
= GetCommPort_ov(ov
,0);
188 struct DosDeviceStruct
*ptr
;
191 ERR("async write with bad overlapped pointer\n");
196 /* we get cancelled when CloseComm is called */
197 if (status
==STATUS_CANCELLED
)
199 TRACE("Cancelled\n");
203 /* read data from comm port */
204 if (status
!= STATUS_SUCCESS
) {
205 ERR("async read failed %08lx\n",status
);
206 COM
[cid
].commerror
= CE_RXOVER
;
209 TRACE("async read completed %ld bytes\n",len
);
211 prev
= comm_inbuf(ptr
);
213 /* check for events */
214 if ((ptr
->eventmask
& EV_RXFLAG
) &&
215 memchr(ptr
->inbuf
+ ptr
->ibuf_head
, ptr
->evtchar
, len
)) {
216 *(WORD
*)(COM
[cid
].unknown
) |= EV_RXFLAG
;
219 if (ptr
->eventmask
& EV_RXCHAR
) {
220 *(WORD
*)(COM
[cid
].unknown
) |= EV_RXCHAR
;
224 /* advance buffer position */
225 ptr
->ibuf_head
+= len
;
226 if (ptr
->ibuf_head
>= ptr
->ibuf_size
)
229 /* check for notification */
230 if (ptr
->wnd
&& (ptr
->n_read
>0) && (prev
<ptr
->n_read
) &&
231 (comm_inbuf(ptr
)>=ptr
->n_read
)) {
232 /* passed the receive notification threshold */
236 /* send notifications, if any */
237 if (ptr
->wnd
&& mask
) {
238 TRACE("notifying %p: cid=%d, mask=%02x\n", ptr
->wnd
, cid
, mask
);
239 PostMessageA(ptr
->wnd
, WM_COMMNOTIFY
, cid
, mask
);
242 /* on real windows, this could cause problems, since it is recursive */
243 /* restart the receive */
247 /* this is meant to work like write() */
248 static INT
COMM16_WriteFile(HANDLE hComm
, LPCVOID buffer
, DWORD len
)
253 ZeroMemory(&ov
,sizeof(ov
));
254 ov
.hEvent
= CreateEventA(NULL
,0,0,NULL
);
255 if(ov
.hEvent
==INVALID_HANDLE_VALUE
)
258 if(!WriteFile(hComm
,buffer
,len
,&count
,&ov
))
260 if(GetLastError()==ERROR_IO_PENDING
)
262 GetOverlappedResult(hComm
,&ov
,&count
,TRUE
);
265 CloseHandle(ov
.hEvent
);
270 static VOID WINAPI
COMM16_WriteComplete(DWORD status
, DWORD len
, LPOVERLAPPED ov
)
274 int cid
= GetCommPort_ov(ov
,1);
275 struct DosDeviceStruct
*ptr
;
278 ERR("async write with bad overlapped pointer\n");
283 /* read data from comm port */
284 if (status
!= STATUS_SUCCESS
) {
285 ERR("async write failed\n");
286 COM
[cid
].commerror
= CE_RXOVER
;
289 TRACE("async write completed %ld bytes\n",len
);
291 /* update the buffer pointers */
292 prev
= comm_outbuf(&COM
[cid
]);
293 ptr
->obuf_tail
+= len
;
294 if (ptr
->obuf_tail
>= ptr
->obuf_size
)
297 /* write any TransmitCommChar character */
299 len
= COMM16_WriteFile(ptr
->handle
, &(ptr
->xmit
), 1);
300 if (len
> 0) ptr
->xmit
= -1;
303 /* write from output queue */
304 bleft
= ((ptr
->obuf_tail
<= ptr
->obuf_head
) ?
305 ptr
->obuf_head
: ptr
->obuf_size
) - ptr
->obuf_tail
;
307 /* check for notification */
308 if (ptr
->wnd
&& (ptr
->n_write
>0) && (prev
>=ptr
->n_write
) &&
309 (comm_outbuf(ptr
)<ptr
->n_write
)) {
310 /* passed the transmit notification threshold */
314 /* send notifications, if any */
315 if (ptr
->wnd
&& mask
) {
316 TRACE("notifying %p: cid=%d, mask=%02x\n", ptr
->wnd
, cid
, mask
);
317 PostMessageA(ptr
->wnd
, WM_COMMNOTIFY
, cid
, mask
);
320 /* start again if necessary */
325 static void comm_waitread(struct DosDeviceStruct
*ptr
)
330 /* FIXME: get timeouts working properly so we can read bleft bytes */
331 bleft
= ((ptr
->ibuf_tail
> ptr
->ibuf_head
) ?
332 (ptr
->ibuf_tail
-1) : ptr
->ibuf_size
) - ptr
->ibuf_head
;
334 /* find out how many bytes are left in the buffer */
335 if(ClearCommError(ptr
->handle
,NULL
,&stat
))
336 bleft
= (bleft
<stat
.cbInQue
) ? bleft
: stat
.cbInQue
;
340 /* always read at least one byte */
344 ReadFileEx(ptr
->handle
,
345 ptr
->inbuf
+ ptr
->ibuf_head
,
348 COMM16_ReadComplete
);
351 static void comm_waitwrite(struct DosDeviceStruct
*ptr
)
355 bleft
= ((ptr
->obuf_tail
<= ptr
->obuf_head
) ?
356 ptr
->obuf_head
: ptr
->obuf_size
) - ptr
->obuf_tail
;
357 WriteFileEx(ptr
->handle
,
358 ptr
->outbuf
+ ptr
->obuf_tail
,
361 COMM16_WriteComplete
);
364 /*****************************************************************************
365 * COMM16_DCBtoDCB16 (Internal)
367 INT16
COMM16_DCBtoDCB16(LPDCB lpdcb
, LPDCB16 lpdcb16
)
369 if(lpdcb
->BaudRate
<0x10000)
370 lpdcb16
->BaudRate
= lpdcb
->BaudRate
;
371 else if(lpdcb
->BaudRate
==115200)
372 lpdcb16
->BaudRate
= 57601;
374 WARN("Baud rate can't be converted\n");
375 lpdcb16
->BaudRate
= 57601;
377 lpdcb16
->ByteSize
= lpdcb
->ByteSize
;
378 lpdcb16
->fParity
= lpdcb
->fParity
;
379 lpdcb16
->Parity
= lpdcb
->Parity
;
380 lpdcb16
->StopBits
= lpdcb
->StopBits
;
382 lpdcb16
->RlsTimeout
= 50;
383 lpdcb16
->CtsTimeout
= 50;
384 lpdcb16
->DsrTimeout
= 50;
387 lpdcb16
->fBinary
= 1;
389 lpdcb16
->fDtrflow
= (lpdcb
->fDtrControl
==DTR_CONTROL_HANDSHAKE
);
390 lpdcb16
->fRtsflow
= (lpdcb
->fRtsControl
==RTS_CONTROL_HANDSHAKE
);
391 lpdcb16
->fOutxCtsFlow
= lpdcb
->fOutxCtsFlow
;
392 lpdcb16
->fOutxDsrFlow
= lpdcb
->fOutxDsrFlow
;
393 lpdcb16
->fDtrDisable
= (lpdcb
->fDtrControl
==DTR_CONTROL_DISABLE
);
395 lpdcb16
->fInX
= lpdcb
->fInX
;
397 lpdcb16
->fOutX
= lpdcb
->fOutX
;
402 lpdcb16
->XonLim
= 10;
403 lpdcb16
->XoffLim
= 10;
409 /**************************************************************************
410 * BuildCommDCB (USER.213)
412 * According to the ECMA-234 (368.3) the function will return FALSE on
413 * success, otherwise it will return -1.
415 INT16 WINAPI
BuildCommDCB16(LPCSTR device
, LPDCB16 lpdcb
)
417 /* "COM1:96,n,8,1" */
422 TRACE("(%s), ptr %p\n", device
, lpdcb
);
424 if (strncasecmp(device
,"COM",3))
426 port
= device
[3] - '0';
429 ERR("BUG ! COM0 can't exist!\n");
433 memset(lpdcb
, 0, sizeof(DCB16
)); /* initialize */
436 dcb
.DCBlength
= sizeof(DCB
);
438 if (strchr(device
,'=')) /* block new style */
441 if(!BuildCommDCBA(device
,&dcb
))
444 return COMM16_DCBtoDCB16(&dcb
, lpdcb
);
447 /*****************************************************************************
448 * OpenComm (USER.200)
450 INT16 WINAPI
OpenComm16(LPCSTR device
,UINT16 cbInQueue
,UINT16 cbOutQueue
)
455 TRACE("%s, %d, %d\n", device
, cbInQueue
, cbOutQueue
);
457 if (strlen(device
) < 4)
460 port
= device
[3] - '0';
463 ERR("BUG ! COM0 or LPT0 don't exist !\n");
465 if (!strncasecmp(device
,"COM",3))
467 if (COM
[port
].handle
)
470 handle
= CreateFileA(device
, GENERIC_READ
|GENERIC_WRITE
,
471 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, CREATE_ALWAYS
,
472 FILE_FLAG_OVERLAPPED
|FILE_FLAG_NO_BUFFERING
, 0 );
473 if (handle
== INVALID_HANDLE_VALUE
) {
476 memset(COM
[port
].unknown
, 0, sizeof(COM
[port
].unknown
));
477 COM
[port
].seg_unknown
= 0;
478 COM
[port
].handle
= handle
;
479 COM
[port
].commerror
= 0;
480 COM
[port
].eventmask
= 0;
481 COM
[port
].evtchar
= 0; /* FIXME: default? */
482 /* save terminal state */
483 GetCommState16(port
,&COM
[port
].dcb
);
484 /* init priority characters */
485 COM
[port
].unget
= -1;
487 /* allocate buffers */
488 COM
[port
].ibuf_size
= cbInQueue
;
489 COM
[port
].ibuf_head
= COM
[port
].ibuf_tail
= 0;
490 COM
[port
].obuf_size
= cbOutQueue
;
491 COM
[port
].obuf_head
= COM
[port
].obuf_tail
= 0;
493 COM
[port
].inbuf
= HeapAlloc(GetProcessHeap(), 0, cbInQueue
);
494 if (COM
[port
].inbuf
) {
495 COM
[port
].outbuf
= HeapAlloc( GetProcessHeap(), 0, cbOutQueue
);
496 if (!COM
[port
].outbuf
)
497 HeapFree( GetProcessHeap(), 0, COM
[port
].inbuf
);
498 } else COM
[port
].outbuf
= NULL
;
499 if (!COM
[port
].outbuf
) {
500 /* not enough memory */
501 CloseHandle(COM
[port
].handle
);
502 ERR("out of memory\n");
506 ZeroMemory(&COM
[port
].read_ov
,sizeof (OVERLAPPED
));
507 ZeroMemory(&COM
[port
].write_ov
,sizeof (OVERLAPPED
));
509 comm_waitread( &COM
[port
] );
510 USER16_AlertableWait
++;
516 if (!strncasecmp(device
,"LPT",3)) {
518 if (LPT
[port
].handle
)
521 handle
= CreateFileA(device
, GENERIC_READ
|GENERIC_WRITE
,
522 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, CREATE_ALWAYS
, 0, 0 );
523 if (handle
== INVALID_HANDLE_VALUE
) {
526 LPT
[port
].handle
= handle
;
527 LPT
[port
].commerror
= 0;
528 LPT
[port
].eventmask
= 0;
529 return port
|FLAG_LPT
;
535 /*****************************************************************************
536 * CloseComm (USER.207)
538 INT16 WINAPI
CloseComm16(INT16 cid
)
540 struct DosDeviceStruct
*ptr
;
542 TRACE("cid=%d\n", cid
);
543 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
544 FIXME("no cid=%d found!\n", cid
);
547 if (!(cid
&FLAG_LPT
)) {
549 UnMapLS( COM
[cid
].seg_unknown
);
550 USER16_AlertableWait
--;
551 CancelIo(ptr
->handle
);
554 HeapFree( GetProcessHeap(), 0, ptr
->outbuf
);
555 HeapFree( GetProcessHeap(), 0, ptr
->inbuf
);
557 /* reset modem lines */
558 SetCommState16(&COM
[cid
].dcb
);
561 if (!CloseHandle(ptr
->handle
)) {
562 ptr
->commerror
= WinError();
563 /* FIXME: should we clear ptr->handle here? */
572 /*****************************************************************************
573 * SetCommBreak (USER.210)
575 INT16 WINAPI
SetCommBreak16(INT16 cid
)
577 struct DosDeviceStruct
*ptr
;
579 TRACE("cid=%d\n", cid
);
580 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
581 FIXME("no cid=%d found!\n", cid
);
590 /*****************************************************************************
591 * ClearCommBreak (USER.211)
593 INT16 WINAPI
ClearCommBreak16(INT16 cid
)
595 struct DosDeviceStruct
*ptr
;
597 TRACE("cid=%d\n", cid
);
598 if (!(ptr
= GetDeviceStruct(cid
))) {
599 FIXME("no cid=%d found!\n", cid
);
607 /*****************************************************************************
608 * EscapeCommFunction (USER.214)
610 LONG WINAPI
EscapeCommFunction16(UINT16 cid
,UINT16 nFunction
)
612 struct DosDeviceStruct
*ptr
;
614 TRACE("cid=%d, function=%d\n", cid
, nFunction
);
618 TRACE("GETMAXCOM\n");
619 return 4; /* FIXME */
622 TRACE("GETMAXLPT\n");
623 return FLAG_LPT
+ 3; /* FIXME */
626 TRACE("GETBASEIRQ\n");
627 /* FIXME: use tables */
628 /* just fake something for now */
629 if (cid
& FLAG_LPT
) {
630 /* LPT1: irq 7, LPT2: irq 5 */
631 return (cid
& 0x7f) ? 5 : 7;
633 /* COM1: irq 4, COM2: irq 3,
634 COM3: irq 4, COM4: irq 3 */
635 return 4 - (cid
& 1);
639 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
640 FIXME("no cid=%d found!\n", cid
);
652 if(EscapeCommFunction(ptr
->handle
,nFunction
))
655 ptr
->commerror
= WinError();
662 WARN("(cid=%d,nFunction=%d): Unknown function\n",
668 /*****************************************************************************
669 * FlushComm (USER.215)
671 INT16 WINAPI
FlushComm16(INT16 cid
,INT16 fnQueue
)
674 struct DosDeviceStruct
*ptr
;
676 TRACE("cid=%d, queue=%d\n", cid
, fnQueue
);
677 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
678 FIXME("no cid=%d found!\n", cid
);
683 queue
= PURGE_TXABORT
;
684 ptr
->obuf_tail
= ptr
->obuf_head
;
687 queue
= PURGE_RXABORT
;
688 ptr
->ibuf_head
= ptr
->ibuf_tail
;
691 WARN("(cid=%d,fnQueue=%d):Unknown queue\n",
696 if (!PurgeComm(ptr
->handle
,queue
)) {
697 ptr
->commerror
= WinError();
705 /********************************************************************
706 * GetCommError (USER.203)
708 INT16 WINAPI
GetCommError16(INT16 cid
,LPCOMSTAT16 lpStat
)
711 struct DosDeviceStruct
*ptr
;
714 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
715 FIXME("no handle for cid = %0x!\n",cid
);
719 WARN(" cid %d not comm port\n",cid
);
722 stol
= (unsigned char *)COM
[cid
].unknown
+ COMM_MSR_OFFSET
;
723 COMM_MSRUpdate( ptr
->handle
, stol
);
730 lpStat
->cbOutQue
= comm_outbuf(ptr
);
731 lpStat
->cbInQue
= comm_inbuf(ptr
);
733 TRACE("cid %d, error %d, stat %d in %d out %d, stol %x\n",
734 cid
, ptr
->commerror
, lpStat
->status
, lpStat
->cbInQue
,
735 lpStat
->cbOutQue
, *stol
);
738 TRACE("cid %d, error %d, lpStat NULL stol %x\n",
739 cid
, ptr
->commerror
, *stol
);
741 /* Return any errors and clear it */
742 temperror
= ptr
->commerror
;
747 /*****************************************************************************
748 * SetCommEventMask (USER.208)
750 SEGPTR WINAPI
SetCommEventMask16(INT16 cid
,UINT16 fuEvtMask
)
752 struct DosDeviceStruct
*ptr
;
755 TRACE("cid %d,mask %d\n",cid
,fuEvtMask
);
756 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
757 FIXME("no handle for cid = %0x!\n",cid
);
761 ptr
->eventmask
= fuEvtMask
;
764 WARN(" cid %d not comm port\n",cid
);
767 /* it's a COM port ? -> modify flags */
768 stol
= (unsigned char *)COM
[cid
].unknown
+ COMM_MSR_OFFSET
;
769 COMM_MSRUpdate( ptr
->handle
, stol
);
771 TRACE(" modem dcd construct %x\n",*stol
);
772 if (!COM
[cid
].seg_unknown
) COM
[cid
].seg_unknown
= MapLS( COM
[cid
].unknown
);
773 return COM
[cid
].seg_unknown
;
776 /*****************************************************************************
777 * GetCommEventMask (USER.209)
779 UINT16 WINAPI
GetCommEventMask16(INT16 cid
,UINT16 fnEvtClear
)
781 struct DosDeviceStruct
*ptr
;
784 TRACE("cid %d, mask %d\n", cid
, fnEvtClear
);
785 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
786 FIXME("no handle for cid = %0x!\n",cid
);
791 WARN(" cid %d not comm port\n",cid
);
795 events
= *(WORD
*)(COM
[cid
].unknown
) & fnEvtClear
;
796 *(WORD
*)(COM
[cid
].unknown
) &= ~fnEvtClear
;
800 /*****************************************************************************
801 * SetCommState (USER.201)
803 INT16 WINAPI
SetCommState16(LPDCB16 lpdcb
)
805 struct DosDeviceStruct
*ptr
;
808 TRACE("cid %d, ptr %p\n", lpdcb
->Id
, lpdcb
);
809 if ((ptr
= GetDeviceStruct(lpdcb
->Id
)) == NULL
) {
810 FIXME("no handle for cid = %0x!\n",lpdcb
->Id
);
814 memset(&dcb
,0,sizeof(dcb
));
815 dcb
.DCBlength
= sizeof(dcb
);
818 * according to MSDN, we should first interpret lpdcb->BaudRate as follows:
819 * 1. if the baud rate is a CBR constant, interpret it.
820 * 2. if it is greater than 57600, the baud rate is 115200
821 * 3. use the actual baudrate
822 * steps 2 and 3 are equivilent to 16550 baudrate divisor = 115200/BaudRate
823 * see http://support.microsoft.com/support/kb/articles/q108/9/28.asp
825 switch(lpdcb
->BaudRate
)
827 case CBR_110
: dcb
.BaudRate
= 110; break;
828 case CBR_300
: dcb
.BaudRate
= 300; break;
829 case CBR_600
: dcb
.BaudRate
= 600; break;
830 case CBR_1200
: dcb
.BaudRate
= 1200; break;
831 case CBR_2400
: dcb
.BaudRate
= 2400; break;
832 case CBR_4800
: dcb
.BaudRate
= 4800; break;
833 case CBR_9600
: dcb
.BaudRate
= 9600; break;
834 case CBR_14400
: dcb
.BaudRate
= 14400; break;
835 case CBR_19200
: dcb
.BaudRate
= 19200; break;
836 case CBR_38400
: dcb
.BaudRate
= 38400; break;
837 case CBR_56000
: dcb
.BaudRate
= 56000; break;
838 case CBR_128000
: dcb
.BaudRate
= 128000; break;
839 case CBR_256000
: dcb
.BaudRate
= 256000; break;
841 if(lpdcb
->BaudRate
>57600)
842 dcb
.BaudRate
= 115200;
844 dcb
.BaudRate
= lpdcb
->BaudRate
;
847 dcb
.ByteSize
=lpdcb
->ByteSize
;
848 dcb
.StopBits
=lpdcb
->StopBits
;
850 dcb
.fParity
=lpdcb
->fParity
;
851 dcb
.Parity
=lpdcb
->Parity
;
853 dcb
.fOutxCtsFlow
= lpdcb
->fOutxCtsFlow
;
855 if (lpdcb
->fDtrflow
|| lpdcb
->fRtsflow
)
856 dcb
.fRtsControl
= TRUE
;
858 if (lpdcb
->fDtrDisable
)
859 dcb
.fDtrControl
= TRUE
;
861 ptr
->evtchar
= lpdcb
->EvtChar
;
863 dcb
.fInX
= lpdcb
->fInX
;
864 dcb
.fOutX
= lpdcb
->fOutX
;
866 if (!SetCommState(ptr
->handle
,&dcb
)) {
867 ptr
->commerror
= WinError();
875 /*****************************************************************************
876 * GetCommState (USER.202)
878 INT16 WINAPI
GetCommState16(INT16 cid
, LPDCB16 lpdcb
)
880 struct DosDeviceStruct
*ptr
;
883 TRACE("cid %d, ptr %p\n", cid
, lpdcb
);
884 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
885 FIXME("no handle for cid = %0x!\n",cid
);
888 if (!GetCommState(ptr
->handle
,&dcb
)) {
889 ptr
->commerror
= WinError();
895 COMM16_DCBtoDCB16(&dcb
,lpdcb
);
897 lpdcb
->EvtChar
= ptr
->evtchar
;
903 /*****************************************************************************
904 * TransmitCommChar (USER.206)
906 INT16 WINAPI
TransmitCommChar16(INT16 cid
,CHAR chTransmit
)
908 struct DosDeviceStruct
*ptr
;
910 TRACE("cid %d, data %d \n", cid
, chTransmit
);
911 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
912 FIXME("no handle for cid = %0x!\n",cid
);
916 if (ptr
->suspended
) {
917 ptr
->commerror
= IE_HARDWARE
;
921 if (ptr
->xmit
>= 0) {
922 /* character already queued */
923 /* FIXME: which error would Windows return? */
924 ptr
->commerror
= CE_TXFULL
;
928 if (ptr
->obuf_head
== ptr
->obuf_tail
) {
929 /* transmit queue empty, try to transmit directly */
930 if(1!=COMM16_WriteFile(ptr
->handle
, &chTransmit
, 1))
932 /* didn't work, queue it */
933 ptr
->xmit
= chTransmit
;
937 /* data in queue, let this char be transmitted next */
938 ptr
->xmit
= chTransmit
;
946 /*****************************************************************************
947 * UngetCommChar (USER.212)
949 INT16 WINAPI
UngetCommChar16(INT16 cid
,CHAR chUnget
)
951 struct DosDeviceStruct
*ptr
;
953 TRACE("cid %d (char %d)\n", cid
, chUnget
);
954 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
955 FIXME("no handle for cid = %0x!\n",cid
);
959 if (ptr
->suspended
) {
960 ptr
->commerror
= IE_HARDWARE
;
965 /* character already queued */
966 /* FIXME: which error would Windows return? */
967 ptr
->commerror
= CE_RXOVER
;
971 ptr
->unget
= chUnget
;
977 /*****************************************************************************
978 * ReadComm (USER.204)
980 INT16 WINAPI
ReadComm16(INT16 cid
,LPSTR lpvBuf
,INT16 cbRead
)
983 struct DosDeviceStruct
*ptr
;
984 LPSTR orgBuf
= lpvBuf
;
986 TRACE("cid %d, ptr %p, length %d\n", cid
, lpvBuf
, cbRead
);
987 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
988 FIXME("no handle for cid = %0x!\n",cid
);
992 if (ptr
->suspended
) {
993 ptr
->commerror
= IE_HARDWARE
;
997 if(0==comm_inbuf(ptr
))
1000 /* read unget character */
1001 if (ptr
->unget
>=0) {
1002 *lpvBuf
++ = ptr
->unget
;
1009 /* read from receive buffer */
1010 while (length
< cbRead
) {
1011 status
= ((ptr
->ibuf_head
< ptr
->ibuf_tail
) ?
1012 ptr
->ibuf_size
: ptr
->ibuf_head
) - ptr
->ibuf_tail
;
1014 if ((cbRead
- length
) < status
)
1015 status
= cbRead
- length
;
1017 memcpy(lpvBuf
, ptr
->inbuf
+ ptr
->ibuf_tail
, status
);
1018 ptr
->ibuf_tail
+= status
;
1019 if (ptr
->ibuf_tail
>= ptr
->ibuf_size
)
1025 TRACE("%s\n", debugstr_an( orgBuf
, length
));
1030 /*****************************************************************************
1031 * WriteComm (USER.205)
1033 INT16 WINAPI
WriteComm16(INT16 cid
, LPSTR lpvBuf
, INT16 cbWrite
)
1036 struct DosDeviceStruct
*ptr
;
1038 TRACE("cid %d, ptr %p, length %d\n",
1039 cid
, lpvBuf
, cbWrite
);
1040 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
1041 FIXME("no handle for cid = %0x!\n",cid
);
1045 if (ptr
->suspended
) {
1046 ptr
->commerror
= IE_HARDWARE
;
1050 TRACE("%s\n", debugstr_an( lpvBuf
, cbWrite
));
1053 while (length
< cbWrite
) {
1054 if ((ptr
->obuf_head
== ptr
->obuf_tail
) && (ptr
->xmit
< 0)) {
1055 /* no data queued, try to write directly */
1056 status
= COMM16_WriteFile(ptr
->handle
, lpvBuf
, cbWrite
- length
);
1063 /* can't write directly, put into transmit buffer */
1064 status
= ((ptr
->obuf_tail
> ptr
->obuf_head
) ?
1065 (ptr
->obuf_tail
-1) : ptr
->obuf_size
) - ptr
->obuf_head
;
1067 if ((cbWrite
- length
) < status
)
1068 status
= cbWrite
- length
;
1069 memcpy(lpvBuf
, ptr
->outbuf
+ ptr
->obuf_head
, status
);
1070 ptr
->obuf_head
+= status
;
1071 if (ptr
->obuf_head
>= ptr
->obuf_size
)
1075 comm_waitwrite(ptr
);
1082 /***********************************************************************
1083 * EnableCommNotification (USER.245)
1085 BOOL16 WINAPI
EnableCommNotification16( INT16 cid
, HWND16 hwnd
,
1086 INT16 cbWriteNotify
, INT16 cbOutQueue
)
1088 struct DosDeviceStruct
*ptr
;
1090 TRACE("(%d, %x, %d, %d)\n", cid
, hwnd
, cbWriteNotify
, cbOutQueue
);
1091 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
1092 FIXME("no handle for cid = %0x!\n",cid
);
1095 ptr
->wnd
= WIN_Handle32( hwnd
);
1096 ptr
->n_read
= cbWriteNotify
;
1097 ptr
->n_write
= cbOutQueue
;