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.
68 #include "wine/winuser16.h"
69 #include "wine/port.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 BOOL
get_com_device_name( int port
, char *devicename
, DWORD size
, int *baudrate
)
134 char temp
[256], *btemp
;
136 if (port
>= MAX_PORTS
) return FALSE
;
138 if (!RegOpenKeyA(HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config\\serialports", &hkey
))
140 DWORD type
, count
= sizeof(temp
);
143 sprintf( value
, "COM%d", port
+1 );
144 RegQueryValueExA(hkey
, value
, 0, &type
, temp
, &count
);
147 if (!temp
[0]) return FALSE
;
149 btemp
= strchr(temp
,',');
153 if (baudrate
) *baudrate
= atoi(btemp
);
155 else if (baudrate
) *baudrate
= -1;
156 if (devicename
) lstrcpynA( devicename
, temp
, size
);
160 static BOOL
get_lpt_device_name( int port
, char *devicename
, DWORD size
)
165 if (port
>= MAX_PORTS
) return FALSE
;
167 if (!RegOpenKeyA(HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config\\parallelports", &hkey
))
169 DWORD type
, count
= sizeof(temp
);
172 sprintf( value
, "LPT%d", port
+1 );
173 RegQueryValueExA(hkey
, value
, 0, &type
, temp
, &count
);
176 if (!temp
[0]) return FALSE
;
178 if (devicename
) lstrcpynA( devicename
, temp
, size
);
183 static struct DosDeviceStruct
*GetDeviceStruct(int index
)
185 if ((index
&0x7F)<=MAX_PORTS
) {
186 if (!(index
&FLAG_LPT
)) {
187 if (COM
[index
].handle
)
191 if (LPT
[index
].handle
)
199 static int GetCommPort_ov(LPOVERLAPPED ov
, int write
)
203 for (x
=0; x
<MAX_PORTS
; x
++) {
204 if (ov
== (write
?&COM
[x
].write_ov
:&COM
[x
].read_ov
))
211 inline static int ValidCOMPort(int x
)
213 return get_com_device_name( x
, NULL
, 0, NULL
);
216 inline static int ValidLPTPort(int x
)
218 return get_lpt_device_name( x
, NULL
, 0 );
221 static int WinError(void)
223 TRACE("errno = %d\n", errno
);
230 static unsigned comm_inbuf(struct DosDeviceStruct
*ptr
)
232 return ((ptr
->ibuf_tail
> ptr
->ibuf_head
) ? ptr
->ibuf_size
: 0)
233 + ptr
->ibuf_head
- ptr
->ibuf_tail
;
236 static unsigned comm_outbuf(struct DosDeviceStruct
*ptr
)
238 return ((ptr
->obuf_tail
> ptr
->obuf_head
) ? ptr
->obuf_size
: 0)
239 + ptr
->obuf_head
- ptr
->obuf_tail
;
242 static void comm_waitread(struct DosDeviceStruct
*ptr
);
243 static void comm_waitwrite(struct DosDeviceStruct
*ptr
);
245 static VOID WINAPI
COMM16_ReadComplete(DWORD status
, DWORD len
, LPOVERLAPPED ov
)
249 int cid
= GetCommPort_ov(ov
,0);
250 struct DosDeviceStruct
*ptr
;
253 ERR("async write with bad overlapped pointer\n");
258 /* we get cancelled when CloseComm is called */
259 if (status
==STATUS_CANCELLED
)
261 TRACE("Cancelled\n");
265 /* read data from comm port */
266 if (status
!= STATUS_SUCCESS
) {
267 ERR("async read failed %08lx\n",status
);
268 COM
[cid
].commerror
= CE_RXOVER
;
271 TRACE("async read completed %ld bytes\n",len
);
273 prev
= comm_inbuf(ptr
);
275 /* check for events */
276 if ((ptr
->eventmask
& EV_RXFLAG
) &&
277 memchr(ptr
->inbuf
+ ptr
->ibuf_head
, ptr
->evtchar
, len
)) {
278 *(WORD
*)(COM
[cid
].unknown
) |= EV_RXFLAG
;
281 if (ptr
->eventmask
& EV_RXCHAR
) {
282 *(WORD
*)(COM
[cid
].unknown
) |= EV_RXCHAR
;
286 /* advance buffer position */
287 ptr
->ibuf_head
+= len
;
288 if (ptr
->ibuf_head
>= ptr
->ibuf_size
)
291 /* check for notification */
292 if (ptr
->wnd
&& (ptr
->n_read
>0) && (prev
<ptr
->n_read
) &&
293 (comm_inbuf(ptr
)>=ptr
->n_read
)) {
294 /* passed the receive notification threshold */
298 /* send notifications, if any */
299 if (ptr
->wnd
&& mask
) {
300 TRACE("notifying %p: cid=%d, mask=%02x\n", ptr
->wnd
, cid
, mask
);
301 PostMessageA(ptr
->wnd
, WM_COMMNOTIFY
, cid
, mask
);
304 /* on real windows, this could cause problems, since it is recursive */
305 /* restart the receive */
309 /* this is meant to work like write() */
310 static INT
COMM16_WriteFile(HANDLE hComm
, LPCVOID buffer
, DWORD len
)
315 ZeroMemory(&ov
,sizeof(ov
));
316 ov
.hEvent
= CreateEventA(NULL
,0,0,NULL
);
317 if(ov
.hEvent
==INVALID_HANDLE_VALUE
)
320 if(!WriteFile(hComm
,buffer
,len
,&count
,&ov
))
322 if(GetLastError()==ERROR_IO_PENDING
)
324 GetOverlappedResult(hComm
,&ov
,&count
,TRUE
);
327 CloseHandle(ov
.hEvent
);
332 static VOID WINAPI
COMM16_WriteComplete(DWORD status
, DWORD len
, LPOVERLAPPED ov
)
336 int cid
= GetCommPort_ov(ov
,1);
337 struct DosDeviceStruct
*ptr
;
340 ERR("async write with bad overlapped pointer\n");
345 /* read data from comm port */
346 if (status
!= STATUS_SUCCESS
) {
347 ERR("async write failed\n");
348 COM
[cid
].commerror
= CE_RXOVER
;
351 TRACE("async write completed %ld bytes\n",len
);
353 /* update the buffer pointers */
354 prev
= comm_outbuf(&COM
[cid
]);
355 ptr
->obuf_tail
+= len
;
356 if (ptr
->obuf_tail
>= ptr
->obuf_size
)
359 /* write any TransmitCommChar character */
361 len
= COMM16_WriteFile(ptr
->handle
, &(ptr
->xmit
), 1);
362 if (len
> 0) ptr
->xmit
= -1;
365 /* write from output queue */
366 bleft
= ((ptr
->obuf_tail
<= ptr
->obuf_head
) ?
367 ptr
->obuf_head
: ptr
->obuf_size
) - ptr
->obuf_tail
;
369 /* check for notification */
370 if (ptr
->wnd
&& (ptr
->n_write
>0) && (prev
>=ptr
->n_write
) &&
371 (comm_outbuf(ptr
)<ptr
->n_write
)) {
372 /* passed the transmit notification threshold */
376 /* send notifications, if any */
377 if (ptr
->wnd
&& mask
) {
378 TRACE("notifying %p: cid=%d, mask=%02x\n", ptr
->wnd
, cid
, mask
);
379 PostMessageA(ptr
->wnd
, WM_COMMNOTIFY
, cid
, mask
);
382 /* start again if necessary */
387 static void comm_waitread(struct DosDeviceStruct
*ptr
)
392 /* FIXME: get timeouts working properly so we can read bleft bytes */
393 bleft
= ((ptr
->ibuf_tail
> ptr
->ibuf_head
) ?
394 (ptr
->ibuf_tail
-1) : ptr
->ibuf_size
) - ptr
->ibuf_head
;
396 /* find out how many bytes are left in the buffer */
397 if(ClearCommError(ptr
->handle
,NULL
,&stat
))
398 bleft
= (bleft
<stat
.cbInQue
) ? bleft
: stat
.cbInQue
;
402 /* always read at least one byte */
406 ReadFileEx(ptr
->handle
,
407 ptr
->inbuf
+ ptr
->ibuf_head
,
410 COMM16_ReadComplete
);
413 static void comm_waitwrite(struct DosDeviceStruct
*ptr
)
417 bleft
= ((ptr
->obuf_tail
<= ptr
->obuf_head
) ?
418 ptr
->obuf_head
: ptr
->obuf_size
) - ptr
->obuf_tail
;
419 WriteFileEx(ptr
->handle
,
420 ptr
->outbuf
+ ptr
->obuf_tail
,
423 COMM16_WriteComplete
);
426 /*****************************************************************************
427 * COMM16_DCBtoDCB16 (Internal)
429 INT16
COMM16_DCBtoDCB16(LPDCB lpdcb
, LPDCB16 lpdcb16
)
431 if(lpdcb
->BaudRate
<0x10000)
432 lpdcb16
->BaudRate
= lpdcb
->BaudRate
;
433 else if(lpdcb
->BaudRate
==115200)
434 lpdcb16
->BaudRate
= 57601;
436 WARN("Baud rate can't be converted\n");
437 lpdcb16
->BaudRate
= 57601;
439 lpdcb16
->ByteSize
= lpdcb
->ByteSize
;
440 lpdcb16
->fParity
= lpdcb
->fParity
;
441 lpdcb16
->Parity
= lpdcb
->Parity
;
442 lpdcb16
->StopBits
= lpdcb
->StopBits
;
444 lpdcb16
->RlsTimeout
= 50;
445 lpdcb16
->CtsTimeout
= 50;
446 lpdcb16
->DsrTimeout
= 50;
449 lpdcb16
->fBinary
= 1;
451 lpdcb16
->fDtrflow
= (lpdcb
->fDtrControl
==DTR_CONTROL_HANDSHAKE
);
452 lpdcb16
->fRtsflow
= (lpdcb
->fRtsControl
==RTS_CONTROL_HANDSHAKE
);
453 lpdcb16
->fOutxCtsFlow
= lpdcb
->fOutxCtsFlow
;
454 lpdcb16
->fOutxDsrFlow
= lpdcb
->fOutxDsrFlow
;
455 lpdcb16
->fDtrDisable
= (lpdcb
->fDtrControl
==DTR_CONTROL_DISABLE
);
457 lpdcb16
->fInX
= lpdcb
->fInX
;
459 lpdcb16
->fOutX
= lpdcb
->fOutX
;
464 lpdcb16
->XonLim
= 10;
465 lpdcb16
->XoffLim
= 10;
471 /**************************************************************************
472 * BuildCommDCB (USER.213)
474 * According to the ECMA-234 (368.3) the function will return FALSE on
475 * success, otherwise it will return -1.
477 INT16 WINAPI
BuildCommDCB16(LPCSTR device
, LPDCB16 lpdcb
)
479 /* "COM1:96,n,8,1" */
484 TRACE("(%s), ptr %p\n", device
, lpdcb
);
486 if (strncasecmp(device
,"COM",3))
488 port
= device
[3] - '0';
491 ERR("BUG ! COM0 can't exist!\n");
495 if (!ValidCOMPort(port
)) {
496 FIXME("invalid COM port %d?\n",port
);
500 memset(lpdcb
, 0, sizeof(DCB16
)); /* initialize */
503 dcb
.DCBlength
= sizeof(DCB
);
505 if (strchr(device
,'=')) /* block new style */
508 if(!BuildCommDCBA(device
,&dcb
))
511 return COMM16_DCBtoDCB16(&dcb
, lpdcb
);
514 /*****************************************************************************
515 * OpenComm (USER.200)
517 INT16 WINAPI
OpenComm16(LPCSTR device
,UINT16 cbInQueue
,UINT16 cbOutQueue
)
522 TRACE("%s, %d, %d\n", device
, cbInQueue
, cbOutQueue
);
524 if (strlen(device
) < 4)
527 port
= device
[3] - '0';
530 ERR("BUG ! COM0 or LPT0 don't exist !\n");
532 if (!strncasecmp(device
,"COM",3))
537 if (!get_com_device_name( port
, devicename
, sizeof(devicename
), &baudrate
))
540 TRACE("%s = %s\n", device
, devicename
);
542 if (COM
[port
].handle
)
545 handle
= CreateFileA(device
, GENERIC_READ
|GENERIC_WRITE
,
546 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, CREATE_ALWAYS
,
547 FILE_FLAG_OVERLAPPED
|FILE_FLAG_NO_BUFFERING
, 0 );
548 if (handle
== INVALID_HANDLE_VALUE
) {
549 ERR("Couldn't open %s ! (%s)\n", devicename
, strerror(errno
));
552 memset(COM
[port
].unknown
, 0, sizeof(COM
[port
].unknown
));
553 COM
[port
].seg_unknown
= 0;
554 COM
[port
].handle
= handle
;
555 COM
[port
].commerror
= 0;
556 COM
[port
].eventmask
= 0;
557 COM
[port
].evtchar
= 0; /* FIXME: default? */
558 /* save terminal state */
559 GetCommState16(port
,&COM
[port
].dcb
);
560 /* set default parameters */
563 memcpy(&dcb
,&COM
[port
].dcb
,sizeof(dcb
));
564 dcb
.BaudRate
=baudrate
;
566 * databits, parity, stopbits
568 SetCommState16( &dcb
);
570 /* init priority characters */
571 COM
[port
].unget
= -1;
573 /* allocate buffers */
574 COM
[port
].ibuf_size
= cbInQueue
;
575 COM
[port
].ibuf_head
= COM
[port
].ibuf_tail
= 0;
576 COM
[port
].obuf_size
= cbOutQueue
;
577 COM
[port
].obuf_head
= COM
[port
].obuf_tail
= 0;
579 COM
[port
].inbuf
= malloc(cbInQueue
);
580 if (COM
[port
].inbuf
) {
581 COM
[port
].outbuf
= malloc(cbOutQueue
);
582 if (!COM
[port
].outbuf
)
583 free(COM
[port
].inbuf
);
584 } else COM
[port
].outbuf
= NULL
;
585 if (!COM
[port
].outbuf
) {
586 /* not enough memory */
587 SetCommState16(&COM
[port
].dcb
);
588 CloseHandle(COM
[port
].handle
);
589 ERR("out of memory\n");
593 ZeroMemory(&COM
[port
].read_ov
,sizeof (OVERLAPPED
));
594 ZeroMemory(&COM
[port
].write_ov
,sizeof (OVERLAPPED
));
596 comm_waitread( &COM
[port
] );
597 USER16_AlertableWait
++;
603 if (!strncasecmp(device
,"LPT",3)) {
605 if (!ValidLPTPort(port
))
608 if (LPT
[port
].handle
)
611 handle
= CreateFileA(device
, GENERIC_READ
|GENERIC_WRITE
,
612 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, CREATE_ALWAYS
, 0, 0 );
613 if (handle
== INVALID_HANDLE_VALUE
) {
616 LPT
[port
].handle
= handle
;
617 LPT
[port
].commerror
= 0;
618 LPT
[port
].eventmask
= 0;
619 return port
|FLAG_LPT
;
625 /*****************************************************************************
626 * CloseComm (USER.207)
628 INT16 WINAPI
CloseComm16(INT16 cid
)
630 struct DosDeviceStruct
*ptr
;
632 TRACE("cid=%d\n", cid
);
633 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
634 FIXME("no cid=%d found!\n", cid
);
637 if (!(cid
&FLAG_LPT
)) {
639 UnMapLS( COM
[cid
].seg_unknown
);
640 USER16_AlertableWait
--;
641 CancelIo(ptr
->handle
);
647 /* reset modem lines */
648 SetCommState16(&COM
[cid
].dcb
);
651 if (!CloseHandle(ptr
->handle
)) {
652 ptr
->commerror
= WinError();
653 /* FIXME: should we clear ptr->handle here? */
662 /*****************************************************************************
663 * SetCommBreak (USER.210)
665 INT16 WINAPI
SetCommBreak16(INT16 cid
)
667 struct DosDeviceStruct
*ptr
;
669 TRACE("cid=%d\n", cid
);
670 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
671 FIXME("no cid=%d found!\n", cid
);
680 /*****************************************************************************
681 * ClearCommBreak (USER.211)
683 INT16 WINAPI
ClearCommBreak16(INT16 cid
)
685 struct DosDeviceStruct
*ptr
;
687 TRACE("cid=%d\n", cid
);
688 if (!(ptr
= GetDeviceStruct(cid
))) {
689 FIXME("no cid=%d found!\n", cid
);
697 /*****************************************************************************
698 * EscapeCommFunction (USER.214)
700 LONG WINAPI
EscapeCommFunction16(UINT16 cid
,UINT16 nFunction
)
702 struct DosDeviceStruct
*ptr
;
705 TRACE("cid=%d, function=%d\n", cid
, nFunction
);
709 TRACE("GETMAXCOM\n");
710 for (max
= MAX_PORTS
;!ValidCOMPort(max
);max
--)
715 TRACE("GETMAXLPT\n");
716 for (max
= MAX_PORTS
;!ValidLPTPort(max
);max
--)
718 return FLAG_LPT
+ max
;
721 TRACE("GETBASEIRQ\n");
722 /* FIXME: use tables */
723 /* just fake something for now */
724 if (cid
& FLAG_LPT
) {
725 /* LPT1: irq 7, LPT2: irq 5 */
726 return (cid
& 0x7f) ? 5 : 7;
728 /* COM1: irq 4, COM2: irq 3,
729 COM3: irq 4, COM4: irq 3 */
730 return 4 - (cid
& 1);
734 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
735 FIXME("no cid=%d found!\n", cid
);
747 if(EscapeCommFunction(ptr
->handle
,nFunction
))
750 ptr
->commerror
= WinError();
757 WARN("(cid=%d,nFunction=%d): Unknown function\n",
763 /*****************************************************************************
764 * FlushComm (USER.215)
766 INT16 WINAPI
FlushComm16(INT16 cid
,INT16 fnQueue
)
769 struct DosDeviceStruct
*ptr
;
771 TRACE("cid=%d, queue=%d\n", cid
, fnQueue
);
772 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
773 FIXME("no cid=%d found!\n", cid
);
778 queue
= PURGE_TXABORT
;
779 ptr
->obuf_tail
= ptr
->obuf_head
;
782 queue
= PURGE_RXABORT
;
783 ptr
->ibuf_head
= ptr
->ibuf_tail
;
786 WARN("(cid=%d,fnQueue=%d):Unknown queue\n",
791 if (!PurgeComm(ptr
->handle
,queue
)) {
792 ptr
->commerror
= WinError();
800 /********************************************************************
801 * GetCommError (USER.203)
803 INT16 WINAPI
GetCommError16(INT16 cid
,LPCOMSTAT16 lpStat
)
806 struct DosDeviceStruct
*ptr
;
809 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
810 FIXME("no handle for cid = %0x!\n",cid
);
814 WARN(" cid %d not comm port\n",cid
);
817 stol
= (unsigned char *)COM
[cid
].unknown
+ COMM_MSR_OFFSET
;
818 COMM_MSRUpdate( ptr
->handle
, stol
);
825 lpStat
->cbOutQue
= comm_outbuf(ptr
);
826 lpStat
->cbInQue
= comm_inbuf(ptr
);
828 TRACE("cid %d, error %d, stat %d in %d out %d, stol %x\n",
829 cid
, ptr
->commerror
, lpStat
->status
, lpStat
->cbInQue
,
830 lpStat
->cbOutQue
, *stol
);
833 TRACE("cid %d, error %d, lpStat NULL stol %x\n",
834 cid
, ptr
->commerror
, *stol
);
836 /* Return any errors and clear it */
837 temperror
= ptr
->commerror
;
842 /*****************************************************************************
843 * SetCommEventMask (USER.208)
845 SEGPTR WINAPI
SetCommEventMask16(INT16 cid
,UINT16 fuEvtMask
)
847 struct DosDeviceStruct
*ptr
;
850 TRACE("cid %d,mask %d\n",cid
,fuEvtMask
);
851 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
852 FIXME("no handle for cid = %0x!\n",cid
);
856 ptr
->eventmask
= fuEvtMask
;
858 if ((cid
&FLAG_LPT
) || !ValidCOMPort(cid
)) {
859 WARN(" cid %d not comm port\n",cid
);
862 /* it's a COM port ? -> modify flags */
863 stol
= (unsigned char *)COM
[cid
].unknown
+ COMM_MSR_OFFSET
;
864 COMM_MSRUpdate( ptr
->handle
, stol
);
866 TRACE(" modem dcd construct %x\n",*stol
);
867 if (!COM
[cid
].seg_unknown
) COM
[cid
].seg_unknown
= MapLS( COM
[cid
].unknown
);
868 return COM
[cid
].seg_unknown
;
871 /*****************************************************************************
872 * GetCommEventMask (USER.209)
874 UINT16 WINAPI
GetCommEventMask16(INT16 cid
,UINT16 fnEvtClear
)
876 struct DosDeviceStruct
*ptr
;
879 TRACE("cid %d, mask %d\n", cid
, fnEvtClear
);
880 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
881 FIXME("no handle for cid = %0x!\n",cid
);
885 if ((cid
&FLAG_LPT
) || !ValidCOMPort(cid
)) {
886 WARN(" cid %d not comm port\n",cid
);
890 events
= *(WORD
*)(COM
[cid
].unknown
) & fnEvtClear
;
891 *(WORD
*)(COM
[cid
].unknown
) &= ~fnEvtClear
;
895 /*****************************************************************************
896 * SetCommState (USER.201)
898 INT16 WINAPI
SetCommState16(LPDCB16 lpdcb
)
900 struct DosDeviceStruct
*ptr
;
903 TRACE("cid %d, ptr %p\n", lpdcb
->Id
, lpdcb
);
904 if ((ptr
= GetDeviceStruct(lpdcb
->Id
)) == NULL
) {
905 FIXME("no handle for cid = %0x!\n",lpdcb
->Id
);
909 memset(&dcb
,0,sizeof(dcb
));
910 dcb
.DCBlength
= sizeof(dcb
);
913 * according to MSDN, we should first interpret lpdcb->BaudRate as follows:
914 * 1. if the baud rate is a CBR constant, interpret it.
915 * 2. if it is greater than 57600, the baud rate is 115200
916 * 3. use the actual baudrate
917 * steps 2 and 3 are equivilent to 16550 baudrate divisor = 115200/BaudRate
918 * see http://support.microsoft.com/support/kb/articles/q108/9/28.asp
920 switch(lpdcb
->BaudRate
)
922 case CBR_110
: dcb
.BaudRate
= 110; break;
923 case CBR_300
: dcb
.BaudRate
= 300; break;
924 case CBR_600
: dcb
.BaudRate
= 600; break;
925 case CBR_1200
: dcb
.BaudRate
= 1200; break;
926 case CBR_2400
: dcb
.BaudRate
= 2400; break;
927 case CBR_4800
: dcb
.BaudRate
= 4800; break;
928 case CBR_9600
: dcb
.BaudRate
= 9600; break;
929 case CBR_14400
: dcb
.BaudRate
= 14400; break;
930 case CBR_19200
: dcb
.BaudRate
= 19200; break;
931 case CBR_38400
: dcb
.BaudRate
= 38400; break;
932 case CBR_56000
: dcb
.BaudRate
= 56000; break;
933 case CBR_128000
: dcb
.BaudRate
= 128000; break;
934 case CBR_256000
: dcb
.BaudRate
= 256000; break;
936 if(lpdcb
->BaudRate
>57600)
937 dcb
.BaudRate
= 115200;
939 dcb
.BaudRate
= lpdcb
->BaudRate
;
942 dcb
.ByteSize
=lpdcb
->ByteSize
;
943 dcb
.StopBits
=lpdcb
->StopBits
;
945 dcb
.fParity
=lpdcb
->fParity
;
946 dcb
.Parity
=lpdcb
->Parity
;
948 dcb
.fOutxCtsFlow
= lpdcb
->fOutxCtsFlow
;
950 if (lpdcb
->fDtrflow
|| lpdcb
->fRtsflow
)
951 dcb
.fRtsControl
= TRUE
;
953 if (lpdcb
->fDtrDisable
)
954 dcb
.fDtrControl
= TRUE
;
956 ptr
->evtchar
= lpdcb
->EvtChar
;
958 dcb
.fInX
= lpdcb
->fInX
;
959 dcb
.fOutX
= lpdcb
->fOutX
;
961 if (!SetCommState(ptr
->handle
,&dcb
)) {
962 ptr
->commerror
= WinError();
970 /*****************************************************************************
971 * GetCommState (USER.202)
973 INT16 WINAPI
GetCommState16(INT16 cid
, LPDCB16 lpdcb
)
975 struct DosDeviceStruct
*ptr
;
978 TRACE("cid %d, ptr %p\n", cid
, lpdcb
);
979 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
980 FIXME("no handle for cid = %0x!\n",cid
);
983 if (!GetCommState(ptr
->handle
,&dcb
)) {
984 ptr
->commerror
= WinError();
990 COMM16_DCBtoDCB16(&dcb
,lpdcb
);
992 lpdcb
->EvtChar
= ptr
->evtchar
;
998 /*****************************************************************************
999 * TransmitCommChar (USER.206)
1001 INT16 WINAPI
TransmitCommChar16(INT16 cid
,CHAR chTransmit
)
1003 struct DosDeviceStruct
*ptr
;
1005 TRACE("cid %d, data %d \n", cid
, chTransmit
);
1006 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
1007 FIXME("no handle for cid = %0x!\n",cid
);
1011 if (ptr
->suspended
) {
1012 ptr
->commerror
= IE_HARDWARE
;
1016 if (ptr
->xmit
>= 0) {
1017 /* character already queued */
1018 /* FIXME: which error would Windows return? */
1019 ptr
->commerror
= CE_TXFULL
;
1023 if (ptr
->obuf_head
== ptr
->obuf_tail
) {
1024 /* transmit queue empty, try to transmit directly */
1025 if(1!=COMM16_WriteFile(ptr
->handle
, &chTransmit
, 1))
1027 /* didn't work, queue it */
1028 ptr
->xmit
= chTransmit
;
1029 comm_waitwrite(ptr
);
1032 /* data in queue, let this char be transmitted next */
1033 ptr
->xmit
= chTransmit
;
1034 comm_waitwrite(ptr
);
1041 /*****************************************************************************
1042 * UngetCommChar (USER.212)
1044 INT16 WINAPI
UngetCommChar16(INT16 cid
,CHAR chUnget
)
1046 struct DosDeviceStruct
*ptr
;
1048 TRACE("cid %d (char %d)\n", cid
, chUnget
);
1049 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
1050 FIXME("no handle for cid = %0x!\n",cid
);
1054 if (ptr
->suspended
) {
1055 ptr
->commerror
= IE_HARDWARE
;
1059 if (ptr
->unget
>=0) {
1060 /* character already queued */
1061 /* FIXME: which error would Windows return? */
1062 ptr
->commerror
= CE_RXOVER
;
1066 ptr
->unget
= chUnget
;
1072 /*****************************************************************************
1073 * ReadComm (USER.204)
1075 INT16 WINAPI
ReadComm16(INT16 cid
,LPSTR lpvBuf
,INT16 cbRead
)
1078 struct DosDeviceStruct
*ptr
;
1079 LPSTR orgBuf
= lpvBuf
;
1081 TRACE("cid %d, ptr %p, length %d\n", cid
, lpvBuf
, cbRead
);
1082 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
1083 FIXME("no handle for cid = %0x!\n",cid
);
1087 if (ptr
->suspended
) {
1088 ptr
->commerror
= IE_HARDWARE
;
1092 if(0==comm_inbuf(ptr
))
1095 /* read unget character */
1096 if (ptr
->unget
>=0) {
1097 *lpvBuf
++ = ptr
->unget
;
1104 /* read from receive buffer */
1105 while (length
< cbRead
) {
1106 status
= ((ptr
->ibuf_head
< ptr
->ibuf_tail
) ?
1107 ptr
->ibuf_size
: ptr
->ibuf_head
) - ptr
->ibuf_tail
;
1109 if ((cbRead
- length
) < status
)
1110 status
= cbRead
- length
;
1112 memcpy(lpvBuf
, ptr
->inbuf
+ ptr
->ibuf_tail
, status
);
1113 ptr
->ibuf_tail
+= status
;
1114 if (ptr
->ibuf_tail
>= ptr
->ibuf_size
)
1120 TRACE("%s\n", debugstr_an( orgBuf
, length
));
1125 /*****************************************************************************
1126 * WriteComm (USER.205)
1128 INT16 WINAPI
WriteComm16(INT16 cid
, LPSTR lpvBuf
, INT16 cbWrite
)
1131 struct DosDeviceStruct
*ptr
;
1133 TRACE("cid %d, ptr %p, length %d\n",
1134 cid
, lpvBuf
, cbWrite
);
1135 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
1136 FIXME("no handle for cid = %0x!\n",cid
);
1140 if (ptr
->suspended
) {
1141 ptr
->commerror
= IE_HARDWARE
;
1145 TRACE("%s\n", debugstr_an( lpvBuf
, cbWrite
));
1148 while (length
< cbWrite
) {
1149 if ((ptr
->obuf_head
== ptr
->obuf_tail
) && (ptr
->xmit
< 0)) {
1150 /* no data queued, try to write directly */
1151 status
= COMM16_WriteFile(ptr
->handle
, lpvBuf
, cbWrite
- length
);
1158 /* can't write directly, put into transmit buffer */
1159 status
= ((ptr
->obuf_tail
> ptr
->obuf_head
) ?
1160 (ptr
->obuf_tail
-1) : ptr
->obuf_size
) - ptr
->obuf_head
;
1162 if ((cbWrite
- length
) < status
)
1163 status
= cbWrite
- length
;
1164 memcpy(lpvBuf
, ptr
->outbuf
+ ptr
->obuf_head
, status
);
1165 ptr
->obuf_head
+= status
;
1166 if (ptr
->obuf_head
>= ptr
->obuf_size
)
1170 comm_waitwrite(ptr
);
1177 /***********************************************************************
1178 * EnableCommNotification (USER.245)
1180 BOOL16 WINAPI
EnableCommNotification16( INT16 cid
, HWND16 hwnd
,
1181 INT16 cbWriteNotify
, INT16 cbOutQueue
)
1183 struct DosDeviceStruct
*ptr
;
1185 TRACE("(%d, %x, %d, %d)\n", cid
, hwnd
, cbWriteNotify
, cbOutQueue
);
1186 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
1187 FIXME("no handle for cid = %0x!\n",cid
);
1190 ptr
->wnd
= WIN_Handle32( hwnd
);
1191 ptr
->n_read
= cbWriteNotify
;
1192 ptr
->n_write
= cbOutQueue
;