msctf: Spelling fix.
[wine.git] / dlls / user.exe16 / comm.c
bloba9141dbed88bc0e29fb2a9418f00c639835f4a22
1 /*
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
22 * History:
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.
53 #include "config.h"
54 #include "wine/port.h"
56 #include <stdlib.h>
57 #include <stdarg.h>
58 #include <stdio.h>
59 #include <string.h>
60 #include <errno.h>
61 #include <ctype.h>
63 #include "windef.h"
64 #include "winbase.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
74 #define MSR_CTS 0x10
75 #define MSR_DSR 0x20
76 #define MSR_RI 0x40
77 #define MSR_RLSD 0x80
78 #define MSR_MASK (MSR_CTS|MSR_DSR|MSR_RI|MSR_RLSD)
80 #define FLAG_LPT 0x80
82 #define MAX_PORTS 9
84 struct DosDeviceStruct {
85 HANDLE handle;
86 BOOL suspended;
87 int unget,xmit;
88 int evtchar;
89 /* events */
90 int commerror, eventmask;
91 /* buffers */
92 char *inbuf,*outbuf;
93 unsigned ibuf_size,ibuf_head,ibuf_tail;
94 unsigned obuf_size,obuf_head,obuf_tail;
95 /* notifications */
96 HWND wnd;
97 int n_read, n_write;
98 OVERLAPPED read_ov, write_ov;
99 /* save terminal states */
100 DCB16 dcb;
101 /* pointer to unknown(==undocumented) comm structure */
102 SEGPTR seg_unknown;
103 BYTE unknown[40];
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 )
113 UCHAR tmpmsr=0;
114 DWORD mstat=0;
116 if(!GetCommModemStatus(handle,&mstat))
117 return;
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)
131 return &COM[index];
132 } else {
133 index &= 0x7f;
134 if (LPT[index].handle)
135 return &LPT[index];
139 return NULL;
142 static int GetCommPort_ov(const OVERLAPPED *ov, int write)
144 int x;
146 for (x=0; x<MAX_PORTS; x++) {
147 if (ov == (write?&COM[x].write_ov:&COM[x].read_ov))
148 return x;
151 return -1;
154 static int WinError(void)
156 TRACE("errno = %d\n", errno);
157 switch (errno) {
158 default:
159 return CE_IOE;
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)
180 int prev;
181 WORD mask = 0;
182 int cid = GetCommPort_ov(ov,0);
183 struct DosDeviceStruct *ptr;
185 if(cid<0) {
186 ERR("async write with bad overlapped pointer\n");
187 return;
189 ptr = &COM[cid];
191 /* we get cancelled when CloseComm is called */
192 if (dwErrorCode==ERROR_OPERATION_ABORTED)
194 TRACE("Cancelled\n");
195 return;
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;
202 return;
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;
212 mask |= CN_EVENT;
214 if (ptr->eventmask & EV_RXCHAR) {
215 *(WORD*)(COM[cid].unknown) |= EV_RXCHAR;
216 mask |= CN_EVENT;
219 /* advance buffer position */
220 ptr->ibuf_head += len;
221 if (ptr->ibuf_head >= ptr->ibuf_size)
222 ptr->ibuf_head = 0;
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 */
228 mask |= CN_RECEIVE;
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 */
239 comm_waitread(ptr);
242 /* this is meant to work like write() */
243 static INT COMM16_WriteFile(HANDLE hComm, LPCVOID buffer, DWORD len)
245 OVERLAPPED ov;
246 DWORD count= -1;
248 ZeroMemory(&ov,sizeof(ov));
249 ov.hEvent = CreateEventW(NULL,0,0,NULL);
250 if(ov.hEvent==INVALID_HANDLE_VALUE)
251 return -1;
253 if(!WriteFile(hComm,buffer,len,&count,&ov))
255 if(GetLastError()==ERROR_IO_PENDING)
257 GetOverlappedResult(hComm,&ov,&count,TRUE);
260 CloseHandle(ov.hEvent);
262 return count;
265 static VOID WINAPI COMM16_WriteComplete(DWORD dwErrorCode, DWORD len, LPOVERLAPPED ov)
267 int prev, bleft;
268 WORD mask = 0;
269 int cid = GetCommPort_ov(ov,1);
270 struct DosDeviceStruct *ptr;
272 if(cid<0) {
273 ERR("async write with bad overlapped pointer\n");
274 return;
276 ptr = &COM[cid];
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;
282 return;
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)
290 ptr->obuf_tail = 0;
292 /* write any TransmitCommChar character */
293 if (ptr->xmit>=0) {
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 */
306 mask |= CN_TRANSMIT;
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 */
316 if(bleft)
317 comm_waitwrite(ptr);
320 static void comm_waitread(struct DosDeviceStruct *ptr)
322 unsigned int bleft;
323 COMSTAT stat;
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;
332 else
333 bleft = 1;
335 /* always read at least one byte */
336 if(bleft==0)
337 bleft++;
339 ReadFileEx(ptr->handle,
340 ptr->inbuf + ptr->ibuf_head,
341 bleft,
342 &ptr->read_ov,
343 COMM16_ReadComplete);
346 static void comm_waitwrite(struct DosDeviceStruct *ptr)
348 int bleft;
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,
354 bleft,
355 &ptr->write_ov,
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;
368 else {
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;
380 lpdcb16->fNull = 0;
381 lpdcb16->fChEvt = 0;
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;
394 lpdcb16->XonChar =
395 lpdcb16->XoffChar =
397 lpdcb16->XonLim = 10;
398 lpdcb16->XoffLim = 10;
400 return 0;
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" */
413 /* 012345 */
414 int port;
415 DCB dcb;
417 TRACE("(%s), ptr %p\n", device, lpdcb);
419 if (strncasecmp(device,"COM",3))
420 return -1;
421 port = device[3] - '0';
423 if (port-- == 0) {
424 ERR("BUG ! COM0 can't exist!\n");
425 return -1;
428 memset(lpdcb, 0, sizeof(DCB16)); /* initialize */
430 lpdcb->Id = port;
431 dcb.DCBlength = sizeof(DCB);
433 if (strchr(device,'=')) /* block new style */
434 return -1;
436 if(!BuildCommDCBA(device,&dcb))
437 return -1;
439 return COMM16_DCBtoDCB16(&dcb, lpdcb);
442 /*****************************************************************************
443 * OpenComm (USER.200)
445 INT16 WINAPI OpenComm16(LPCSTR device,UINT16 cbInQueue,UINT16 cbOutQueue)
447 int port;
448 HANDLE handle;
450 TRACE("%s, %d, %d\n", device, cbInQueue, cbOutQueue);
452 if (strlen(device) < 4)
453 return IE_BADID;
455 port = device[3] - '0';
457 if (port-- == 0)
458 ERR("BUG ! COM0 or LPT0 don't exist !\n");
460 if (!strncasecmp(device,"COM",3))
462 if (COM[port].handle)
463 return IE_OPEN;
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) {
469 return IE_HARDWARE;
470 } else {
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;
481 COM[port].xmit = -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");
498 return IE_MEMORY;
501 ZeroMemory(&COM[port].read_ov,sizeof (OVERLAPPED));
502 ZeroMemory(&COM[port].write_ov,sizeof (OVERLAPPED));
504 comm_waitread( &COM[port] );
505 USER16_AlertableWait++;
507 return port;
510 else
511 if (!strncasecmp(device,"LPT",3)) {
513 if (LPT[port].handle)
514 return IE_OPEN;
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) {
519 return IE_HARDWARE;
520 } else {
521 LPT[port].handle = handle;
522 LPT[port].commerror = 0;
523 LPT[port].eventmask = 0;
524 return port|FLAG_LPT;
527 return IE_BADID;
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);
540 return -1;
542 if (!(cid&FLAG_LPT)) {
543 /* COM port */
544 UnMapLS( COM[cid].seg_unknown );
545 USER16_AlertableWait--;
546 CancelIo(ptr->handle);
548 /* free buffers */
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? */
559 return -1;
560 } else {
561 ptr->commerror = 0;
562 ptr->handle = 0;
563 return 0;
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);
577 return -1;
580 ptr->suspended = TRUE;
581 ptr->commerror = 0;
582 return 0;
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);
595 return -1;
597 ptr->suspended = FALSE;
598 ptr->commerror = 0;
599 return 0;
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);
611 switch(nFunction) {
612 case GETMAXCOM:
613 TRACE("GETMAXCOM\n");
614 return 4; /* FIXME */
616 case GETMAXLPT:
617 TRACE("GETMAXLPT\n");
618 return FLAG_LPT + 3; /* FIXME */
620 case GETBASEIRQ:
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;
627 } else {
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);
636 return -1;
639 switch (nFunction) {
640 case RESETDEV:
641 case CLRDTR:
642 case CLRRTS:
643 case SETDTR:
644 case SETRTS:
645 case SETXOFF:
646 case SETXON:
647 if(EscapeCommFunction(ptr->handle,nFunction))
648 return 0;
649 else {
650 ptr->commerror = WinError();
651 return -1;
654 case CLRBREAK:
655 case SETBREAK:
656 default:
657 WARN("(cid=%d,nFunction=%d): Unknown function\n",
658 cid, nFunction);
660 return -1;
663 /*****************************************************************************
664 * FlushComm (USER.215)
666 INT16 WINAPI FlushComm16(INT16 cid,INT16 fnQueue)
668 DWORD queue;
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);
674 return -1;
676 switch (fnQueue) {
677 case 0:
678 queue = PURGE_TXABORT;
679 ptr->obuf_tail = ptr->obuf_head;
680 break;
681 case 1:
682 queue = PURGE_RXABORT;
683 ptr->ibuf_head = ptr->ibuf_tail;
684 break;
685 default:
686 WARN("(cid=%d,fnQueue=%d):Unknown queue\n",
687 cid, fnQueue);
688 return -1;
691 if (!PurgeComm(ptr->handle,queue)) {
692 ptr->commerror = WinError();
693 return -1;
694 } else {
695 ptr->commerror = 0;
696 return 0;
700 /********************************************************************
701 * GetCommError (USER.203)
703 INT16 WINAPI GetCommError16(INT16 cid,LPCOMSTAT16 lpStat)
705 int temperror;
706 struct DosDeviceStruct *ptr;
707 unsigned char *stol;
709 if ((ptr = GetDeviceStruct(cid)) == NULL) {
710 FIXME("no handle for cid = %0x!\n",cid);
711 return -1;
713 if (cid&FLAG_LPT) {
714 WARN(" cid %d not comm port\n",cid);
715 return CE_MODE;
717 stol = (unsigned char *)COM[cid].unknown + COMM_MSR_OFFSET;
718 COMM_MSRUpdate( ptr->handle, stol );
720 if (lpStat) {
721 lpStat->status = 0;
723 if (comm_inbuf(ptr) == 0)
724 SleepEx(1,TRUE);
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);
733 else
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;
739 ptr->commerror = 0;
740 return(temperror);
743 /*****************************************************************************
744 * SetCommEventMask (USER.208)
746 SEGPTR WINAPI SetCommEventMask16(INT16 cid,UINT16 fuEvtMask)
748 struct DosDeviceStruct *ptr;
749 unsigned char *stol;
751 TRACE("cid %d,mask %d\n",cid,fuEvtMask);
752 if ((ptr = GetDeviceStruct(cid)) == NULL) {
753 FIXME("no handle for cid = %0x!\n",cid);
754 return 0;
757 ptr->eventmask = fuEvtMask;
759 if (cid&FLAG_LPT) {
760 WARN(" cid %d not comm port\n",cid);
761 return 0;
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;
778 WORD events;
780 TRACE("cid %d, mask %d\n", cid, fnEvtClear);
781 if ((ptr = GetDeviceStruct(cid)) == NULL) {
782 FIXME("no handle for cid = %0x!\n",cid);
783 return 0;
786 if (cid&FLAG_LPT) {
787 WARN(" cid %d not comm port\n",cid);
788 return 0;
791 events = *(WORD*)(COM[cid].unknown) & fnEvtClear;
792 *(WORD*)(COM[cid].unknown) &= ~fnEvtClear;
793 return events;
796 /*****************************************************************************
797 * SetCommState (USER.201)
799 INT16 WINAPI SetCommState16(LPDCB16 lpdcb)
801 struct DosDeviceStruct *ptr;
802 DCB dcb;
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);
807 return -1;
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;
835 default:
836 if(lpdcb->BaudRate>57600)
837 dcb.BaudRate = 115200;
838 else
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();
863 return -1;
864 } else {
865 ptr->commerror = 0;
866 return 0;
870 /*****************************************************************************
871 * GetCommState (USER.202)
873 INT16 WINAPI GetCommState16(INT16 cid, LPDCB16 lpdcb)
875 struct DosDeviceStruct *ptr;
876 DCB dcb;
878 TRACE("cid %d, ptr %p\n", cid, lpdcb);
879 if ((ptr = GetDeviceStruct(cid)) == NULL) {
880 FIXME("no handle for cid = %0x!\n",cid);
881 return -1;
883 if (!GetCommState(ptr->handle,&dcb)) {
884 ptr->commerror = WinError();
885 return -1;
888 lpdcb->Id = cid;
890 COMM16_DCBtoDCB16(&dcb,lpdcb);
892 lpdcb->EvtChar = ptr->evtchar;
894 ptr->commerror = 0;
895 return 0;
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);
908 return -1;
911 if (ptr->suspended) {
912 ptr->commerror = IE_HARDWARE;
913 return -1;
916 if (ptr->xmit >= 0) {
917 /* character already queued */
918 /* FIXME: which error would Windows return? */
919 ptr->commerror = CE_TXFULL;
920 return -1;
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;
929 comm_waitwrite(ptr);
931 } else {
932 /* data in queue, let this char be transmitted next */
933 ptr->xmit = chTransmit;
934 comm_waitwrite(ptr);
937 ptr->commerror = 0;
938 return 0;
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);
951 return -1;
954 if (ptr->suspended) {
955 ptr->commerror = IE_HARDWARE;
956 return -1;
959 if (ptr->unget>=0) {
960 /* character already queued */
961 /* FIXME: which error would Windows return? */
962 ptr->commerror = CE_RXOVER;
963 return -1;
966 ptr->unget = chUnget;
968 ptr->commerror = 0;
969 return 0;
972 /*****************************************************************************
973 * ReadComm (USER.204)
975 INT16 WINAPI ReadComm16(INT16 cid,LPSTR lpvBuf,INT16 cbRead)
977 int status, length;
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);
984 return -1;
987 if (ptr->suspended) {
988 ptr->commerror = IE_HARDWARE;
989 return -1;
992 if(0==comm_inbuf(ptr))
993 SleepEx(1,TRUE);
995 /* read unget character */
996 if (ptr->unget>=0) {
997 *lpvBuf++ = ptr->unget;
998 ptr->unget = -1;
1000 length = 1;
1001 } else
1002 length = 0;
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;
1008 if (!status) break;
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)
1015 ptr->ibuf_tail = 0;
1016 lpvBuf += status;
1017 length += status;
1020 TRACE("%s\n", debugstr_an( orgBuf, length ));
1021 ptr->commerror = 0;
1022 return length;
1025 /*****************************************************************************
1026 * WriteComm (USER.205)
1028 INT16 WINAPI WriteComm16(INT16 cid, LPSTR lpvBuf, INT16 cbWrite)
1030 int status, length;
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);
1037 return -1;
1040 if (ptr->suspended) {
1041 ptr->commerror = IE_HARDWARE;
1042 return -1;
1045 TRACE("%s\n", debugstr_an( lpvBuf, cbWrite ));
1047 length = 0;
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);
1052 if (status > 0) {
1053 lpvBuf += status;
1054 length += status;
1055 continue;
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;
1061 if (!status) break;
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)
1067 ptr->obuf_head = 0;
1068 lpvBuf += status;
1069 length += status;
1070 comm_waitwrite(ptr);
1073 ptr->commerror = 0;
1074 return length;
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);
1088 return -1;
1090 ptr->wnd = WIN_Handle32( hwnd );
1091 ptr->n_read = cbWriteNotify;
1092 ptr->n_write = cbOutQueue;
1093 return TRUE;