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.
66 #include "wine/winuser16.h"
67 #include "wine/port.h"
71 #include "wine/debug.h"
73 WINE_DEFAULT_DEBUG_CHANNEL(comm
);
75 /* window's semi documented modem status register */
76 #define COMM_MSR_OFFSET 35
81 #define MSR_MASK (MSR_CTS|MSR_DSR|MSR_RI|MSR_RLSD)
87 struct DosDeviceStruct
{
88 char *devicename
; /* /dev/ttyS0 */
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
;
134 char option
[10], temp
[256], *btemp
;
137 for (x
=0; x
!=MAX_PORTS
; x
++) {
138 strcpy(option
,"COMx");
145 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config\\serialports", &hkey
))
147 DWORD type
, count
= sizeof(temp
);
149 RegQueryValueExA(hkey
, option
, 0, &type
, temp
, &count
);
153 if (!strcmp(temp
, "*") || *temp
== '\0')
154 COM
[x
].devicename
= NULL
;
156 btemp
= strchr(temp
,',');
159 COM
[x
].baudrate
= atoi(btemp
);
161 COM
[x
].baudrate
= -1;
163 if ((COM
[x
].devicename
= malloc(strlen(temp
)+1)) == NULL
)
164 WARN("Can't malloc for device info!\n");
167 strcpy(COM
[x
].devicename
, temp
);
168 TRACE("%s = %s\n", option
, COM
[x
].devicename
);
172 strcpy(option
, "LPTx");
179 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config\\parallelports", &hkey
))
181 DWORD type
, count
= sizeof(temp
);
183 RegQueryValueExA(hkey
, option
, 0, &type
, temp
, &count
);
187 if (!strcmp(temp
, "*") || *temp
== '\0')
188 LPT
[x
].devicename
= NULL
;
190 if ((LPT
[x
].devicename
= malloc(strlen(temp
)+1)) == NULL
)
191 WARN("Can't malloc for device info!\n");
194 strcpy(LPT
[x
].devicename
, temp
);
195 TRACE("%s = %s\n", option
, LPT
[x
].devicename
);
203 static struct DosDeviceStruct
*GetDeviceStruct(int index
)
205 if ((index
&0x7F)<=MAX_PORTS
) {
206 if (!(index
&FLAG_LPT
)) {
207 if (COM
[index
].handle
)
211 if (LPT
[index
].handle
)
219 static int GetCommPort_ov(LPOVERLAPPED ov
, int write
)
223 for (x
=0; x
<MAX_PORTS
; x
++) {
224 if (ov
== (write
?&COM
[x
].write_ov
:&COM
[x
].read_ov
))
231 static int ValidCOMPort(int x
)
233 return(x
< MAX_PORTS
? (int) COM
[x
].devicename
: 0);
236 static int ValidLPTPort(int x
)
238 return(x
< MAX_PORTS
? (int) LPT
[x
].devicename
: 0);
241 static int WinError(void)
243 TRACE("errno = %d\n", errno
);
250 static unsigned comm_inbuf(struct DosDeviceStruct
*ptr
)
252 return ((ptr
->ibuf_tail
> ptr
->ibuf_head
) ? ptr
->ibuf_size
: 0)
253 + ptr
->ibuf_head
- ptr
->ibuf_tail
;
256 static unsigned comm_outbuf(struct DosDeviceStruct
*ptr
)
258 return ((ptr
->obuf_tail
> ptr
->obuf_head
) ? ptr
->obuf_size
: 0)
259 + ptr
->obuf_head
- ptr
->obuf_tail
;
262 static void comm_waitread(struct DosDeviceStruct
*ptr
);
263 static void comm_waitwrite(struct DosDeviceStruct
*ptr
);
265 static VOID WINAPI
COMM16_ReadComplete(DWORD status
, DWORD len
, LPOVERLAPPED ov
)
269 int cid
= GetCommPort_ov(ov
,0);
270 struct DosDeviceStruct
*ptr
;
273 ERR("async write with bad overlapped pointer\n");
278 /* we get cancelled when CloseComm is called */
279 if (status
==STATUS_CANCELLED
)
281 TRACE("Cancelled\n");
285 /* read data from comm port */
286 if (status
!= STATUS_SUCCESS
) {
287 ERR("async read failed %08lx\n",status
);
288 COM
[cid
].commerror
= CE_RXOVER
;
291 TRACE("async read completed %ld bytes\n",len
);
293 prev
= comm_inbuf(ptr
);
295 /* check for events */
296 if ((ptr
->eventmask
& EV_RXFLAG
) &&
297 memchr(ptr
->inbuf
+ ptr
->ibuf_head
, ptr
->evtchar
, len
)) {
298 *(WORD
*)(COM
[cid
].unknown
) |= EV_RXFLAG
;
301 if (ptr
->eventmask
& EV_RXCHAR
) {
302 *(WORD
*)(COM
[cid
].unknown
) |= EV_RXCHAR
;
306 /* advance buffer position */
307 ptr
->ibuf_head
+= len
;
308 if (ptr
->ibuf_head
>= ptr
->ibuf_size
)
311 /* check for notification */
312 if (ptr
->wnd
&& (ptr
->n_read
>0) && (prev
<ptr
->n_read
) &&
313 (comm_inbuf(ptr
)>=ptr
->n_read
)) {
314 /* passed the receive notification threshold */
318 /* send notifications, if any */
319 if (ptr
->wnd
&& mask
) {
320 TRACE("notifying %04x: cid=%d, mask=%02x\n", ptr
->wnd
, cid
, mask
);
321 PostMessageA(ptr
->wnd
, WM_COMMNOTIFY
, cid
, mask
);
324 /* on real windows, this could cause problems, since it is recursive */
325 /* restart the receive */
329 /* this is meant to work like write() */
330 static INT
COMM16_WriteFile(HANDLE hComm
, LPCVOID buffer
, DWORD len
)
335 ZeroMemory(&ov
,sizeof ov
);
336 ov
.hEvent
= CreateEventA(NULL
,0,0,NULL
);
337 if(ov
.hEvent
==INVALID_HANDLE_VALUE
)
340 if(!WriteFile(hComm
,buffer
,len
,&count
,&ov
))
342 if(GetLastError()==ERROR_IO_PENDING
)
344 GetOverlappedResult(hComm
,&ov
,&count
,TRUE
);
347 CloseHandle(ov
.hEvent
);
352 static VOID WINAPI
COMM16_WriteComplete(DWORD status
, DWORD len
, LPOVERLAPPED ov
)
356 int cid
= GetCommPort_ov(ov
,1);
357 struct DosDeviceStruct
*ptr
;
360 ERR("async write with bad overlapped pointer\n");
365 /* read data from comm port */
366 if (status
!= STATUS_SUCCESS
) {
367 ERR("async write failed\n");
368 COM
[cid
].commerror
= CE_RXOVER
;
371 TRACE("async write completed %ld bytes\n",len
);
373 /* update the buffer pointers */
374 prev
= comm_outbuf(&COM
[cid
]);
375 ptr
->obuf_tail
+= len
;
376 if (ptr
->obuf_tail
>= ptr
->obuf_size
)
379 /* write any TransmitCommChar character */
381 len
= COMM16_WriteFile(ptr
->handle
, &(ptr
->xmit
), 1);
382 if (len
> 0) ptr
->xmit
= -1;
385 /* write from output queue */
386 bleft
= ((ptr
->obuf_tail
<= ptr
->obuf_head
) ?
387 ptr
->obuf_head
: ptr
->obuf_size
) - ptr
->obuf_tail
;
389 /* check for notification */
390 if (ptr
->wnd
&& (ptr
->n_write
>0) && (prev
>=ptr
->n_write
) &&
391 (comm_outbuf(ptr
)<ptr
->n_write
)) {
392 /* passed the transmit notification threshold */
396 /* send notifications, if any */
397 if (ptr
->wnd
&& mask
) {
398 TRACE("notifying %04x: cid=%d, mask=%02x\n", ptr
->wnd
, cid
, mask
);
399 PostMessageA(ptr
->wnd
, WM_COMMNOTIFY
, cid
, mask
);
402 /* start again if necessary */
407 static void comm_waitread(struct DosDeviceStruct
*ptr
)
412 /* FIXME: get timeouts working properly so we can read bleft bytes */
413 bleft
= ((ptr
->ibuf_tail
> ptr
->ibuf_head
) ?
414 (ptr
->ibuf_tail
-1) : ptr
->ibuf_size
) - ptr
->ibuf_head
;
416 /* find out how many bytes are left in the buffer */
417 if(ClearCommError(ptr
->handle
,NULL
,&stat
))
418 bleft
= (bleft
<stat
.cbInQue
) ? bleft
: stat
.cbInQue
;
422 /* always read at least one byte */
426 ReadFileEx(ptr
->handle
,
427 ptr
->inbuf
+ ptr
->ibuf_head
,
430 COMM16_ReadComplete
);
433 static void comm_waitwrite(struct DosDeviceStruct
*ptr
)
437 bleft
= ((ptr
->obuf_tail
<= ptr
->obuf_head
) ?
438 ptr
->obuf_head
: ptr
->obuf_size
) - ptr
->obuf_tail
;
439 WriteFileEx(ptr
->handle
,
440 ptr
->outbuf
+ ptr
->obuf_tail
,
443 COMM16_WriteComplete
);
446 /*****************************************************************************
447 * COMM16_DCBtoDCB16 (Internal)
449 INT16
COMM16_DCBtoDCB16(LPDCB lpdcb
, LPDCB16 lpdcb16
)
451 if(lpdcb
->BaudRate
<0x10000)
452 lpdcb16
->BaudRate
= lpdcb
->BaudRate
;
453 else if(lpdcb
->BaudRate
==115200)
454 lpdcb16
->BaudRate
= 57601;
456 WARN("Baud rate can't be converted\n");
457 lpdcb16
->BaudRate
= 57601;
459 lpdcb16
->ByteSize
= lpdcb
->ByteSize
;
460 lpdcb16
->fParity
= lpdcb
->fParity
;
461 lpdcb16
->Parity
= lpdcb
->Parity
;
462 lpdcb16
->StopBits
= lpdcb
->StopBits
;
464 lpdcb16
->RlsTimeout
= 50;
465 lpdcb16
->CtsTimeout
= 50;
466 lpdcb16
->DsrTimeout
= 50;
469 lpdcb16
->fBinary
= 1;
471 lpdcb16
->fDtrflow
= (lpdcb
->fDtrControl
==DTR_CONTROL_HANDSHAKE
);
472 lpdcb16
->fRtsflow
= (lpdcb
->fRtsControl
==RTS_CONTROL_HANDSHAKE
);
473 lpdcb16
->fOutxCtsFlow
= lpdcb
->fOutxCtsFlow
;
474 lpdcb16
->fOutxDsrFlow
= lpdcb
->fOutxDsrFlow
;
475 lpdcb16
->fDtrDisable
= (lpdcb
->fDtrControl
==DTR_CONTROL_DISABLE
);
477 lpdcb16
->fInX
= lpdcb
->fInX
;
479 lpdcb16
->fOutX
= lpdcb
->fOutX
;
484 lpdcb16
->XonLim
= 10;
485 lpdcb16
->XoffLim
= 10;
491 /**************************************************************************
492 * BuildCommDCB (USER.213)
494 * According to the ECMA-234 (368.3) the function will return FALSE on
495 * success, otherwise it will return -1.
497 INT16 WINAPI
BuildCommDCB16(LPCSTR device
, LPDCB16 lpdcb
)
499 /* "COM1:96,n,8,1" */
504 TRACE("(%s), ptr %p\n", device
, lpdcb
);
506 if (strncasecmp(device
,"COM",3))
508 port
= device
[3] - '0';
511 ERR("BUG ! COM0 can't exist!\n");
515 if (!ValidCOMPort(port
)) {
516 FIXME("invalid COM port %d?\n",port
);
520 memset(lpdcb
, 0, sizeof(DCB16
)); /* initialize */
523 dcb
.DCBlength
= sizeof(DCB
);
525 if (strchr(device
,'=')) /* block new style */
528 if(!BuildCommDCBA(device
,&dcb
))
531 return COMM16_DCBtoDCB16(&dcb
, lpdcb
);
534 /*****************************************************************************
535 * OpenComm (USER.200)
537 INT16 WINAPI
OpenComm16(LPCSTR device
,UINT16 cbInQueue
,UINT16 cbOutQueue
)
542 TRACE("%s, %d, %d\n", device
, cbInQueue
, cbOutQueue
);
544 if (strlen(device
) < 4)
547 port
= device
[3] - '0';
550 ERR("BUG ! COM0 or LPT0 don't exist !\n");
552 if (!strncasecmp(device
,"COM",3)) {
554 TRACE("%s = %s\n", device
, COM
[port
].devicename
);
556 if (!ValidCOMPort(port
))
559 if (COM
[port
].handle
)
562 handle
= CreateFileA(device
, GENERIC_READ
|GENERIC_WRITE
,
563 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, CREATE_ALWAYS
,
564 FILE_FLAG_OVERLAPPED
|FILE_FLAG_NO_BUFFERING
, 0 );
565 if (handle
== INVALID_HANDLE_VALUE
) {
566 ERR("Couldn't open %s ! (%s)\n", COM
[port
].devicename
, strerror(errno
));
569 memset(COM
[port
].unknown
, 0, sizeof(COM
[port
].unknown
));
570 COM
[port
].seg_unknown
= 0;
571 COM
[port
].handle
= handle
;
572 COM
[port
].commerror
= 0;
573 COM
[port
].eventmask
= 0;
574 COM
[port
].evtchar
= 0; /* FIXME: default? */
575 /* save terminal state */
576 GetCommState16(port
,&COM
[port
].dcb
);
577 /* set default parameters */
578 if(COM
[port
].baudrate
>-1){
580 memcpy(&dcb
,&COM
[port
].dcb
,sizeof dcb
);
581 dcb
.BaudRate
=COM
[port
].baudrate
;
583 * databits, parity, stopbits
585 SetCommState16( &dcb
);
587 /* init priority characters */
588 COM
[port
].unget
= -1;
590 /* allocate buffers */
591 COM
[port
].ibuf_size
= cbInQueue
;
592 COM
[port
].ibuf_head
= COM
[port
].ibuf_tail
= 0;
593 COM
[port
].obuf_size
= cbOutQueue
;
594 COM
[port
].obuf_head
= COM
[port
].obuf_tail
= 0;
596 COM
[port
].inbuf
= malloc(cbInQueue
);
597 if (COM
[port
].inbuf
) {
598 COM
[port
].outbuf
= malloc(cbOutQueue
);
599 if (!COM
[port
].outbuf
)
600 free(COM
[port
].inbuf
);
601 } else COM
[port
].outbuf
= NULL
;
602 if (!COM
[port
].outbuf
) {
603 /* not enough memory */
604 SetCommState16(&COM
[port
].dcb
);
605 CloseHandle(COM
[port
].handle
);
606 ERR("out of memory\n");
610 ZeroMemory(&COM
[port
].read_ov
,sizeof (OVERLAPPED
));
611 ZeroMemory(&COM
[port
].write_ov
,sizeof (OVERLAPPED
));
613 comm_waitread( &COM
[port
] );
614 USER16_AlertableWait
++;
620 if (!strncasecmp(device
,"LPT",3)) {
622 if (!ValidLPTPort(port
))
625 if (LPT
[port
].handle
)
628 handle
= CreateFileA(device
, GENERIC_READ
|GENERIC_WRITE
,
629 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
, CREATE_ALWAYS
, 0, 0 );
630 if (handle
== INVALID_HANDLE_VALUE
) {
633 LPT
[port
].handle
= handle
;
634 LPT
[port
].commerror
= 0;
635 LPT
[port
].eventmask
= 0;
636 return port
|FLAG_LPT
;
642 /*****************************************************************************
643 * CloseComm (USER.207)
645 INT16 WINAPI
CloseComm16(INT16 cid
)
647 struct DosDeviceStruct
*ptr
;
649 TRACE("cid=%d\n", cid
);
650 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
651 FIXME("no cid=%d found!\n", cid
);
654 if (!(cid
&FLAG_LPT
)) {
656 UnMapLS( COM
[cid
].seg_unknown
);
657 USER16_AlertableWait
--;
658 CancelIo(ptr
->handle
);
664 /* reset modem lines */
665 SetCommState16(&COM
[cid
].dcb
);
668 if (!CloseHandle(ptr
->handle
)) {
669 ptr
->commerror
= WinError();
670 /* FIXME: should we clear ptr->handle here? */
679 /*****************************************************************************
680 * SetCommBreak (USER.210)
682 INT16 WINAPI
SetCommBreak16(INT16 cid
)
684 struct DosDeviceStruct
*ptr
;
686 TRACE("cid=%d\n", cid
);
687 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
688 FIXME("no cid=%d found!\n", cid
);
697 /*****************************************************************************
698 * ClearCommBreak (USER.211)
700 INT16 WINAPI
ClearCommBreak16(INT16 cid
)
702 struct DosDeviceStruct
*ptr
;
704 TRACE("cid=%d\n", cid
);
705 if (!(ptr
= GetDeviceStruct(cid
))) {
706 FIXME("no cid=%d found!\n", cid
);
714 /*****************************************************************************
715 * EscapeCommFunction (USER.214)
717 LONG WINAPI
EscapeCommFunction16(UINT16 cid
,UINT16 nFunction
)
719 struct DosDeviceStruct
*ptr
;
722 TRACE("cid=%d, function=%d\n", cid
, nFunction
);
726 TRACE("GETMAXCOM\n");
727 for (max
= MAX_PORTS
;!COM
[max
].devicename
;max
--)
732 TRACE("GETMAXLPT\n");
733 for (max
= MAX_PORTS
;!LPT
[max
].devicename
;max
--)
735 return FLAG_LPT
+ max
;
738 TRACE("GETBASEIRQ\n");
739 /* FIXME: use tables */
740 /* just fake something for now */
741 if (cid
& FLAG_LPT
) {
742 /* LPT1: irq 7, LPT2: irq 5 */
743 return (cid
& 0x7f) ? 5 : 7;
745 /* COM1: irq 4, COM2: irq 3,
746 COM3: irq 4, COM4: irq 3 */
747 return 4 - (cid
& 1);
751 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
752 FIXME("no cid=%d found!\n", cid
);
764 if(EscapeCommFunction(ptr
->handle
,nFunction
))
767 ptr
->commerror
= WinError();
774 WARN("(cid=%d,nFunction=%d): Unknown function\n",
780 /*****************************************************************************
781 * FlushComm (USER.215)
783 INT16 WINAPI
FlushComm16(INT16 cid
,INT16 fnQueue
)
786 struct DosDeviceStruct
*ptr
;
788 TRACE("cid=%d, queue=%d\n", cid
, fnQueue
);
789 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
790 FIXME("no cid=%d found!\n", cid
);
795 queue
= PURGE_TXABORT
;
796 ptr
->obuf_tail
= ptr
->obuf_head
;
799 queue
= PURGE_RXABORT
;
800 ptr
->ibuf_head
= ptr
->ibuf_tail
;
803 WARN("(cid=%d,fnQueue=%d):Unknown queue\n",
808 if (!PurgeComm(ptr
->handle
,queue
)) {
809 ptr
->commerror
= WinError();
817 /********************************************************************
818 * GetCommError (USER.203)
820 INT16 WINAPI
GetCommError16(INT16 cid
,LPCOMSTAT16 lpStat
)
823 struct DosDeviceStruct
*ptr
;
826 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
827 FIXME("no handle for cid = %0x!\n",cid
);
831 WARN(" cid %d not comm port\n",cid
);
834 stol
= (unsigned char *)COM
[cid
].unknown
+ COMM_MSR_OFFSET
;
835 COMM_MSRUpdate( ptr
->handle
, stol
);
840 WaitForMultipleObjectsEx(0,NULL
,FALSE
,1,TRUE
);
842 lpStat
->cbOutQue
= comm_outbuf(ptr
);
843 lpStat
->cbInQue
= comm_inbuf(ptr
);
845 TRACE("cid %d, error %d, stat %d in %d out %d, stol %x\n",
846 cid
, ptr
->commerror
, lpStat
->status
, lpStat
->cbInQue
,
847 lpStat
->cbOutQue
, *stol
);
850 TRACE("cid %d, error %d, lpStat NULL stol %x\n",
851 cid
, ptr
->commerror
, *stol
);
853 /* Return any errors and clear it */
854 temperror
= ptr
->commerror
;
859 /*****************************************************************************
860 * SetCommEventMask (USER.208)
862 SEGPTR WINAPI
SetCommEventMask16(INT16 cid
,UINT16 fuEvtMask
)
864 struct DosDeviceStruct
*ptr
;
867 TRACE("cid %d,mask %d\n",cid
,fuEvtMask
);
868 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
869 FIXME("no handle for cid = %0x!\n",cid
);
873 ptr
->eventmask
= fuEvtMask
;
875 if ((cid
&FLAG_LPT
) || !ValidCOMPort(cid
)) {
876 WARN(" cid %d not comm port\n",cid
);
879 /* it's a COM port ? -> modify flags */
880 stol
= (unsigned char *)COM
[cid
].unknown
+ COMM_MSR_OFFSET
;
881 COMM_MSRUpdate( ptr
->handle
, stol
);
883 TRACE(" modem dcd construct %x\n",*stol
);
884 if (!COM
[cid
].seg_unknown
) COM
[cid
].seg_unknown
= MapLS( COM
[cid
].unknown
);
885 return COM
[cid
].seg_unknown
;
888 /*****************************************************************************
889 * GetCommEventMask (USER.209)
891 UINT16 WINAPI
GetCommEventMask16(INT16 cid
,UINT16 fnEvtClear
)
893 struct DosDeviceStruct
*ptr
;
896 TRACE("cid %d, mask %d\n", cid
, fnEvtClear
);
897 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
898 FIXME("no handle for cid = %0x!\n",cid
);
902 if ((cid
&FLAG_LPT
) || !ValidCOMPort(cid
)) {
903 WARN(" cid %d not comm port\n",cid
);
907 events
= *(WORD
*)(COM
[cid
].unknown
) & fnEvtClear
;
908 *(WORD
*)(COM
[cid
].unknown
) &= ~fnEvtClear
;
912 /*****************************************************************************
913 * SetCommState (USER.201)
915 INT16 WINAPI
SetCommState16(LPDCB16 lpdcb
)
917 struct DosDeviceStruct
*ptr
;
920 TRACE("cid %d, ptr %p\n", lpdcb
->Id
, lpdcb
);
921 if ((ptr
= GetDeviceStruct(lpdcb
->Id
)) == NULL
) {
922 FIXME("no handle for cid = %0x!\n",lpdcb
->Id
);
926 memset(&dcb
,0,sizeof dcb
);
927 dcb
.DCBlength
= sizeof dcb
;
930 * according to MSDN, we should first interpret lpdcb->BaudRate as follows:
931 * 1. if the baud rate is a CBR constant, interpret it.
932 * 2. if it is greater than 57600, the baud rate is 115200
933 * 3. use the actual baudrate
934 * steps 2 and 3 are equivilent to 16550 baudrate divisor = 115200/BaudRate
935 * see http://support.microsoft.com/support/kb/articles/q108/9/28.asp
937 switch(lpdcb
->BaudRate
)
939 case CBR_110
: dcb
.BaudRate
= 110; break;
940 case CBR_300
: dcb
.BaudRate
= 300; break;
941 case CBR_600
: dcb
.BaudRate
= 600; break;
942 case CBR_1200
: dcb
.BaudRate
= 1200; break;
943 case CBR_2400
: dcb
.BaudRate
= 2400; break;
944 case CBR_4800
: dcb
.BaudRate
= 4800; break;
945 case CBR_9600
: dcb
.BaudRate
= 9600; break;
946 case CBR_14400
: dcb
.BaudRate
= 14400; break;
947 case CBR_19200
: dcb
.BaudRate
= 19200; break;
948 case CBR_38400
: dcb
.BaudRate
= 38400; break;
949 case CBR_56000
: dcb
.BaudRate
= 56000; break;
950 case CBR_128000
: dcb
.BaudRate
= 128000; break;
951 case CBR_256000
: dcb
.BaudRate
= 256000; break;
953 if(lpdcb
->BaudRate
>57600)
954 dcb
.BaudRate
= 115200;
956 dcb
.BaudRate
= lpdcb
->BaudRate
;
959 dcb
.ByteSize
=lpdcb
->ByteSize
;
960 dcb
.StopBits
=lpdcb
->StopBits
;
962 dcb
.fParity
=lpdcb
->fParity
;
963 dcb
.Parity
=lpdcb
->Parity
;
965 dcb
.fOutxCtsFlow
= lpdcb
->fOutxCtsFlow
;
967 if (lpdcb
->fDtrflow
|| lpdcb
->fRtsflow
)
968 dcb
.fRtsControl
= TRUE
;
970 if (lpdcb
->fDtrDisable
)
971 dcb
.fDtrControl
= TRUE
;
973 ptr
->evtchar
= lpdcb
->EvtChar
;
975 dcb
.fInX
= lpdcb
->fInX
;
976 dcb
.fOutX
= lpdcb
->fOutX
;
978 if (!SetCommState(ptr
->handle
,&dcb
)) {
979 ptr
->commerror
= WinError();
987 /*****************************************************************************
988 * GetCommState (USER.202)
990 INT16 WINAPI
GetCommState16(INT16 cid
, LPDCB16 lpdcb
)
992 struct DosDeviceStruct
*ptr
;
995 TRACE("cid %d, ptr %p\n", cid
, lpdcb
);
996 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
997 FIXME("no handle for cid = %0x!\n",cid
);
1000 if (!GetCommState(ptr
->handle
,&dcb
)) {
1001 ptr
->commerror
= WinError();
1007 COMM16_DCBtoDCB16(&dcb
,lpdcb
);
1009 lpdcb
->EvtChar
= ptr
->evtchar
;
1015 /*****************************************************************************
1016 * TransmitCommChar (USER.206)
1018 INT16 WINAPI
TransmitCommChar16(INT16 cid
,CHAR chTransmit
)
1020 struct DosDeviceStruct
*ptr
;
1022 TRACE("cid %d, data %d \n", cid
, chTransmit
);
1023 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
1024 FIXME("no handle for cid = %0x!\n",cid
);
1028 if (ptr
->suspended
) {
1029 ptr
->commerror
= IE_HARDWARE
;
1033 if (ptr
->xmit
>= 0) {
1034 /* character already queued */
1035 /* FIXME: which error would Windows return? */
1036 ptr
->commerror
= CE_TXFULL
;
1040 if (ptr
->obuf_head
== ptr
->obuf_tail
) {
1041 /* transmit queue empty, try to transmit directly */
1042 if(1!=COMM16_WriteFile(ptr
->handle
, &chTransmit
, 1))
1044 /* didn't work, queue it */
1045 ptr
->xmit
= chTransmit
;
1046 comm_waitwrite(ptr
);
1049 /* data in queue, let this char be transmitted next */
1050 ptr
->xmit
= chTransmit
;
1051 comm_waitwrite(ptr
);
1058 /*****************************************************************************
1059 * UngetCommChar (USER.212)
1061 INT16 WINAPI
UngetCommChar16(INT16 cid
,CHAR chUnget
)
1063 struct DosDeviceStruct
*ptr
;
1065 TRACE("cid %d (char %d)\n", cid
, chUnget
);
1066 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
1067 FIXME("no handle for cid = %0x!\n",cid
);
1071 if (ptr
->suspended
) {
1072 ptr
->commerror
= IE_HARDWARE
;
1076 if (ptr
->unget
>=0) {
1077 /* character already queued */
1078 /* FIXME: which error would Windows return? */
1079 ptr
->commerror
= CE_RXOVER
;
1083 ptr
->unget
= chUnget
;
1089 /*****************************************************************************
1090 * ReadComm (USER.204)
1092 INT16 WINAPI
ReadComm16(INT16 cid
,LPSTR lpvBuf
,INT16 cbRead
)
1095 struct DosDeviceStruct
*ptr
;
1096 LPSTR orgBuf
= lpvBuf
;
1098 TRACE("cid %d, ptr %p, length %d\n", cid
, lpvBuf
, cbRead
);
1099 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
1100 FIXME("no handle for cid = %0x!\n",cid
);
1104 if (ptr
->suspended
) {
1105 ptr
->commerror
= IE_HARDWARE
;
1109 if(0==comm_inbuf(ptr
))
1110 WaitForMultipleObjectsEx(0,NULL
,FALSE
,1,TRUE
);
1112 /* read unget character */
1113 if (ptr
->unget
>=0) {
1114 *lpvBuf
++ = ptr
->unget
;
1121 /* read from receive buffer */
1122 while (length
< cbRead
) {
1123 status
= ((ptr
->ibuf_head
< ptr
->ibuf_tail
) ?
1124 ptr
->ibuf_size
: ptr
->ibuf_head
) - ptr
->ibuf_tail
;
1126 if ((cbRead
- length
) < status
)
1127 status
= cbRead
- length
;
1129 memcpy(lpvBuf
, ptr
->inbuf
+ ptr
->ibuf_tail
, status
);
1130 ptr
->ibuf_tail
+= status
;
1131 if (ptr
->ibuf_tail
>= ptr
->ibuf_size
)
1137 TRACE("%s\n", debugstr_an( orgBuf
, length
));
1142 /*****************************************************************************
1143 * WriteComm (USER.205)
1145 INT16 WINAPI
WriteComm16(INT16 cid
, LPSTR lpvBuf
, INT16 cbWrite
)
1148 struct DosDeviceStruct
*ptr
;
1150 TRACE("cid %d, ptr %p, length %d\n",
1151 cid
, lpvBuf
, cbWrite
);
1152 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
1153 FIXME("no handle for cid = %0x!\n",cid
);
1157 if (ptr
->suspended
) {
1158 ptr
->commerror
= IE_HARDWARE
;
1162 TRACE("%s\n", debugstr_an( lpvBuf
, cbWrite
));
1165 while (length
< cbWrite
) {
1166 if ((ptr
->obuf_head
== ptr
->obuf_tail
) && (ptr
->xmit
< 0)) {
1167 /* no data queued, try to write directly */
1168 status
= COMM16_WriteFile(ptr
->handle
, lpvBuf
, cbWrite
- length
);
1175 /* can't write directly, put into transmit buffer */
1176 status
= ((ptr
->obuf_tail
> ptr
->obuf_head
) ?
1177 (ptr
->obuf_tail
-1) : ptr
->obuf_size
) - ptr
->obuf_head
;
1179 if ((cbWrite
- length
) < status
)
1180 status
= cbWrite
- length
;
1181 memcpy(lpvBuf
, ptr
->outbuf
+ ptr
->obuf_head
, status
);
1182 ptr
->obuf_head
+= status
;
1183 if (ptr
->obuf_head
>= ptr
->obuf_size
)
1187 comm_waitwrite(ptr
);
1194 /***********************************************************************
1195 * EnableCommNotification (USER.245)
1197 BOOL16 WINAPI
EnableCommNotification16( INT16 cid
, HWND16 hwnd
,
1198 INT16 cbWriteNotify
, INT16 cbOutQueue
)
1200 struct DosDeviceStruct
*ptr
;
1202 TRACE("(%d, %x, %d, %d)\n", cid
, hwnd
, cbWriteNotify
, cbOutQueue
);
1203 if ((ptr
= GetDeviceStruct(cid
)) == NULL
) {
1204 FIXME("no handle for cid = %0x!\n",cid
);
1207 ptr
->wnd
= WIN_Handle32( hwnd
);
1208 ptr
->n_read
= cbWriteNotify
;
1209 ptr
->n_write
= cbOutQueue
;