user: Fix LB_GETTEXT unmapping for A<->W.
[wine/multimedia.git] / dlls / user / comm16.c
blobc2366e458a0b69fb8a25038c73b33aada3780977
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 "wingdi.h"
66 #include "wine/winuser16.h"
67 #include "win.h"
68 #include "user_private.h"
70 #include "wine/debug.h"
72 WINE_DEFAULT_DEBUG_CHANNEL(comm);
74 /* window's semi documented modem status register */
75 #define COMM_MSR_OFFSET 35
76 #define MSR_CTS 0x10
77 #define MSR_DSR 0x20
78 #define MSR_RI 0x40
79 #define MSR_RLSD 0x80
80 #define MSR_MASK (MSR_CTS|MSR_DSR|MSR_RI|MSR_RLSD)
82 #define FLAG_LPT 0x80
84 #define MAX_PORTS 9
86 struct DosDeviceStruct {
87 HANDLE handle;
88 int suspended;
89 int unget,xmit;
90 int evtchar;
91 /* events */
92 int commerror, eventmask;
93 /* buffers */
94 char *inbuf,*outbuf;
95 unsigned ibuf_size,ibuf_head,ibuf_tail;
96 unsigned obuf_size,obuf_head,obuf_tail;
97 /* notifications */
98 HWND wnd;
99 int n_read, n_write;
100 OVERLAPPED read_ov, write_ov;
101 /* save terminal states */
102 DCB16 dcb;
103 /* pointer to unknown(==undocumented) comm structure */
104 SEGPTR seg_unknown;
105 BYTE unknown[40];
108 static struct DosDeviceStruct COM[MAX_PORTS];
109 static struct DosDeviceStruct LPT[MAX_PORTS];
111 /* update window's semi documented modem status register */
112 /* see knowledge base Q101417 */
113 static void COMM_MSRUpdate( HANDLE handle, UCHAR * pMsr )
115 UCHAR tmpmsr=0;
116 DWORD mstat=0;
118 if(!GetCommModemStatus(handle,&mstat))
119 return;
121 if(mstat & MS_CTS_ON) tmpmsr |= MSR_CTS;
122 if(mstat & MS_DSR_ON) tmpmsr |= MSR_DSR;
123 if(mstat & MS_RING_ON) tmpmsr |= MSR_RI;
124 if(mstat & MS_RLSD_ON) tmpmsr |= MSR_RLSD;
125 *pMsr = (*pMsr & ~MSR_MASK) | tmpmsr;
128 static struct DosDeviceStruct *GetDeviceStruct(int index)
130 if ((index&0x7F)<=MAX_PORTS) {
131 if (!(index&FLAG_LPT)) {
132 if (COM[index].handle)
133 return &COM[index];
134 } else {
135 index &= 0x7f;
136 if (LPT[index].handle)
137 return &LPT[index];
141 return NULL;
144 static int GetCommPort_ov(LPOVERLAPPED ov, int write)
146 int x;
148 for (x=0; x<MAX_PORTS; x++) {
149 if (ov == (write?&COM[x].write_ov:&COM[x].read_ov))
150 return x;
153 return -1;
156 static int WinError(void)
158 TRACE("errno = %d\n", errno);
159 switch (errno) {
160 default:
161 return CE_IOE;
165 static unsigned comm_inbuf(struct DosDeviceStruct *ptr)
167 return ((ptr->ibuf_tail > ptr->ibuf_head) ? ptr->ibuf_size : 0)
168 + ptr->ibuf_head - ptr->ibuf_tail;
171 static unsigned comm_outbuf(struct DosDeviceStruct *ptr)
173 return ((ptr->obuf_tail > ptr->obuf_head) ? ptr->obuf_size : 0)
174 + ptr->obuf_head - ptr->obuf_tail;
177 static void comm_waitread(struct DosDeviceStruct *ptr);
178 static void comm_waitwrite(struct DosDeviceStruct *ptr);
180 static VOID WINAPI COMM16_ReadComplete(DWORD dwErrorCode, DWORD len, LPOVERLAPPED ov)
182 int prev;
183 WORD mask = 0;
184 int cid = GetCommPort_ov(ov,0);
185 struct DosDeviceStruct *ptr;
187 if(cid<0) {
188 ERR("async write with bad overlapped pointer\n");
189 return;
191 ptr = &COM[cid];
193 /* we get cancelled when CloseComm is called */
194 if (dwErrorCode==ERROR_OPERATION_ABORTED)
196 TRACE("Cancelled\n");
197 return;
200 /* read data from comm port */
201 if (dwErrorCode != NO_ERROR) {
202 ERR("async read failed, error %ld\n",dwErrorCode);
203 COM[cid].commerror = CE_RXOVER;
204 return;
206 TRACE("async read completed %ld bytes\n",len);
208 prev = comm_inbuf(ptr);
210 /* check for events */
211 if ((ptr->eventmask & EV_RXFLAG) &&
212 memchr(ptr->inbuf + ptr->ibuf_head, ptr->evtchar, len)) {
213 *(WORD*)(COM[cid].unknown) |= EV_RXFLAG;
214 mask |= CN_EVENT;
216 if (ptr->eventmask & EV_RXCHAR) {
217 *(WORD*)(COM[cid].unknown) |= EV_RXCHAR;
218 mask |= CN_EVENT;
221 /* advance buffer position */
222 ptr->ibuf_head += len;
223 if (ptr->ibuf_head >= ptr->ibuf_size)
224 ptr->ibuf_head = 0;
226 /* check for notification */
227 if (ptr->wnd && (ptr->n_read>0) && (prev<ptr->n_read) &&
228 (comm_inbuf(ptr)>=ptr->n_read)) {
229 /* passed the receive notification threshold */
230 mask |= CN_RECEIVE;
233 /* send notifications, if any */
234 if (ptr->wnd && mask) {
235 TRACE("notifying %p: cid=%d, mask=%02x\n", ptr->wnd, cid, mask);
236 PostMessageA(ptr->wnd, WM_COMMNOTIFY, cid, mask);
239 /* on real windows, this could cause problems, since it is recursive */
240 /* restart the receive */
241 comm_waitread(ptr);
244 /* this is meant to work like write() */
245 static INT COMM16_WriteFile(HANDLE hComm, LPCVOID buffer, DWORD len)
247 OVERLAPPED ov;
248 DWORD count= -1;
250 ZeroMemory(&ov,sizeof(ov));
251 ov.hEvent = CreateEventW(NULL,0,0,NULL);
252 if(ov.hEvent==INVALID_HANDLE_VALUE)
253 return -1;
255 if(!WriteFile(hComm,buffer,len,&count,&ov))
257 if(GetLastError()==ERROR_IO_PENDING)
259 GetOverlappedResult(hComm,&ov,&count,TRUE);
262 CloseHandle(ov.hEvent);
264 return count;
267 static VOID WINAPI COMM16_WriteComplete(DWORD dwErrorCode, DWORD len, LPOVERLAPPED ov)
269 int prev, bleft;
270 WORD mask = 0;
271 int cid = GetCommPort_ov(ov,1);
272 struct DosDeviceStruct *ptr;
274 if(cid<0) {
275 ERR("async write with bad overlapped pointer\n");
276 return;
278 ptr = &COM[cid];
280 /* read data from comm port */
281 if (dwErrorCode != NO_ERROR) {
282 ERR("async write failed, error %ld\n",dwErrorCode);
283 COM[cid].commerror = CE_RXOVER;
284 return;
286 TRACE("async write completed %ld bytes\n",len);
288 /* update the buffer pointers */
289 prev = comm_outbuf(&COM[cid]);
290 ptr->obuf_tail += len;
291 if (ptr->obuf_tail >= ptr->obuf_size)
292 ptr->obuf_tail = 0;
294 /* write any TransmitCommChar character */
295 if (ptr->xmit>=0) {
296 len = COMM16_WriteFile(ptr->handle, &(ptr->xmit), 1);
297 if (len > 0) ptr->xmit = -1;
300 /* write from output queue */
301 bleft = ((ptr->obuf_tail <= ptr->obuf_head) ?
302 ptr->obuf_head : ptr->obuf_size) - ptr->obuf_tail;
304 /* check for notification */
305 if (ptr->wnd && (ptr->n_write>0) && (prev>=ptr->n_write) &&
306 (comm_outbuf(ptr)<ptr->n_write)) {
307 /* passed the transmit notification threshold */
308 mask |= CN_TRANSMIT;
311 /* send notifications, if any */
312 if (ptr->wnd && mask) {
313 TRACE("notifying %p: cid=%d, mask=%02x\n", ptr->wnd, cid, mask);
314 PostMessageA(ptr->wnd, WM_COMMNOTIFY, cid, mask);
317 /* start again if necessary */
318 if(bleft)
319 comm_waitwrite(ptr);
322 static void comm_waitread(struct DosDeviceStruct *ptr)
324 unsigned int bleft;
325 COMSTAT stat;
327 /* FIXME: get timeouts working properly so we can read bleft bytes */
328 bleft = ((ptr->ibuf_tail > ptr->ibuf_head) ?
329 (ptr->ibuf_tail-1) : ptr->ibuf_size) - ptr->ibuf_head;
331 /* find out how many bytes are left in the buffer */
332 if(ClearCommError(ptr->handle,NULL,&stat))
333 bleft = (bleft<stat.cbInQue) ? bleft : stat.cbInQue;
334 else
335 bleft = 1;
337 /* always read at least one byte */
338 if(bleft==0)
339 bleft++;
341 ReadFileEx(ptr->handle,
342 ptr->inbuf + ptr->ibuf_head,
343 bleft,
344 &ptr->read_ov,
345 COMM16_ReadComplete);
348 static void comm_waitwrite(struct DosDeviceStruct *ptr)
350 int bleft;
352 bleft = ((ptr->obuf_tail <= ptr->obuf_head) ?
353 ptr->obuf_head : ptr->obuf_size) - ptr->obuf_tail;
354 WriteFileEx(ptr->handle,
355 ptr->outbuf + ptr->obuf_tail,
356 bleft,
357 &ptr->write_ov,
358 COMM16_WriteComplete);
361 /*****************************************************************************
362 * COMM16_DCBtoDCB16 (Internal)
364 INT16 COMM16_DCBtoDCB16(LPDCB lpdcb, LPDCB16 lpdcb16)
366 if(lpdcb->BaudRate<0x10000)
367 lpdcb16->BaudRate = lpdcb->BaudRate;
368 else if(lpdcb->BaudRate==115200)
369 lpdcb16->BaudRate = 57601;
370 else {
371 WARN("Baud rate can't be converted\n");
372 lpdcb16->BaudRate = 57601;
374 lpdcb16->ByteSize = lpdcb->ByteSize;
375 lpdcb16->fParity = lpdcb->fParity;
376 lpdcb16->Parity = lpdcb->Parity;
377 lpdcb16->StopBits = lpdcb->StopBits;
379 lpdcb16->RlsTimeout = 50;
380 lpdcb16->CtsTimeout = 50;
381 lpdcb16->DsrTimeout = 50;
382 lpdcb16->fNull = 0;
383 lpdcb16->fChEvt = 0;
384 lpdcb16->fBinary = 1;
386 lpdcb16->fDtrflow = (lpdcb->fDtrControl==DTR_CONTROL_HANDSHAKE);
387 lpdcb16->fRtsflow = (lpdcb->fRtsControl==RTS_CONTROL_HANDSHAKE);
388 lpdcb16->fOutxCtsFlow = lpdcb->fOutxCtsFlow;
389 lpdcb16->fOutxDsrFlow = lpdcb->fOutxDsrFlow;
390 lpdcb16->fDtrDisable = (lpdcb->fDtrControl==DTR_CONTROL_DISABLE);
392 lpdcb16->fInX = lpdcb->fInX;
394 lpdcb16->fOutX = lpdcb->fOutX;
396 lpdcb16->XonChar =
397 lpdcb16->XoffChar =
399 lpdcb16->XonLim = 10;
400 lpdcb16->XoffLim = 10;
402 return 0;
406 /**************************************************************************
407 * BuildCommDCB (USER.213)
409 * According to the ECMA-234 (368.3) the function will return FALSE on
410 * success, otherwise it will return -1.
412 INT16 WINAPI BuildCommDCB16(LPCSTR device, LPDCB16 lpdcb)
414 /* "COM1:96,n,8,1" */
415 /* 012345 */
416 int port;
417 DCB dcb;
419 TRACE("(%s), ptr %p\n", device, lpdcb);
421 if (strncasecmp(device,"COM",3))
422 return -1;
423 port = device[3] - '0';
425 if (port-- == 0) {
426 ERR("BUG ! COM0 can't exist!\n");
427 return -1;
430 memset(lpdcb, 0, sizeof(DCB16)); /* initialize */
432 lpdcb->Id = port;
433 dcb.DCBlength = sizeof(DCB);
435 if (strchr(device,'=')) /* block new style */
436 return -1;
438 if(!BuildCommDCBA(device,&dcb))
439 return -1;
441 return COMM16_DCBtoDCB16(&dcb, lpdcb);
444 /*****************************************************************************
445 * OpenComm (USER.200)
447 INT16 WINAPI OpenComm16(LPCSTR device,UINT16 cbInQueue,UINT16 cbOutQueue)
449 int port;
450 HANDLE handle;
452 TRACE("%s, %d, %d\n", device, cbInQueue, cbOutQueue);
454 if (strlen(device) < 4)
455 return IE_BADID;
457 port = device[3] - '0';
459 if (port-- == 0)
460 ERR("BUG ! COM0 or LPT0 don't exist !\n");
462 if (!strncasecmp(device,"COM",3))
464 if (COM[port].handle)
465 return IE_OPEN;
467 handle = CreateFileA(device, GENERIC_READ|GENERIC_WRITE,
468 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
469 FILE_FLAG_OVERLAPPED|FILE_FLAG_NO_BUFFERING, 0 );
470 if (handle == INVALID_HANDLE_VALUE) {
471 return IE_HARDWARE;
472 } else {
473 memset(COM[port].unknown, 0, sizeof(COM[port].unknown));
474 COM[port].seg_unknown = 0;
475 COM[port].handle = handle;
476 COM[port].commerror = 0;
477 COM[port].eventmask = 0;
478 COM[port].evtchar = 0; /* FIXME: default? */
479 /* save terminal state */
480 GetCommState16(port,&COM[port].dcb);
481 /* init priority characters */
482 COM[port].unget = -1;
483 COM[port].xmit = -1;
484 /* allocate buffers */
485 COM[port].ibuf_size = cbInQueue;
486 COM[port].ibuf_head = COM[port].ibuf_tail = 0;
487 COM[port].obuf_size = cbOutQueue;
488 COM[port].obuf_head = COM[port].obuf_tail = 0;
490 COM[port].inbuf = HeapAlloc(GetProcessHeap(), 0, cbInQueue);
491 if (COM[port].inbuf) {
492 COM[port].outbuf = HeapAlloc( GetProcessHeap(), 0, cbOutQueue);
493 if (!COM[port].outbuf)
494 HeapFree( GetProcessHeap(), 0, COM[port].inbuf);
495 } else COM[port].outbuf = NULL;
496 if (!COM[port].outbuf) {
497 /* not enough memory */
498 CloseHandle(COM[port].handle);
499 ERR("out of memory\n");
500 return IE_MEMORY;
503 ZeroMemory(&COM[port].read_ov,sizeof (OVERLAPPED));
504 ZeroMemory(&COM[port].write_ov,sizeof (OVERLAPPED));
506 comm_waitread( &COM[port] );
507 USER16_AlertableWait++;
509 return port;
512 else
513 if (!strncasecmp(device,"LPT",3)) {
515 if (LPT[port].handle)
516 return IE_OPEN;
518 handle = CreateFileA(device, GENERIC_READ|GENERIC_WRITE,
519 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0 );
520 if (handle == INVALID_HANDLE_VALUE) {
521 return IE_HARDWARE;
522 } else {
523 LPT[port].handle = handle;
524 LPT[port].commerror = 0;
525 LPT[port].eventmask = 0;
526 return port|FLAG_LPT;
529 return IE_BADID;
532 /*****************************************************************************
533 * CloseComm (USER.207)
535 INT16 WINAPI CloseComm16(INT16 cid)
537 struct DosDeviceStruct *ptr;
539 TRACE("cid=%d\n", cid);
540 if ((ptr = GetDeviceStruct(cid)) == NULL) {
541 FIXME("no cid=%d found!\n", cid);
542 return -1;
544 if (!(cid&FLAG_LPT)) {
545 /* COM port */
546 UnMapLS( COM[cid].seg_unknown );
547 USER16_AlertableWait--;
548 CancelIo(ptr->handle);
550 /* free buffers */
551 HeapFree( GetProcessHeap(), 0, ptr->outbuf);
552 HeapFree( GetProcessHeap(), 0, ptr->inbuf);
554 /* reset modem lines */
555 SetCommState16(&COM[cid].dcb);
558 if (!CloseHandle(ptr->handle)) {
559 ptr->commerror = WinError();
560 /* FIXME: should we clear ptr->handle here? */
561 return -1;
562 } else {
563 ptr->commerror = 0;
564 ptr->handle = 0;
565 return 0;
569 /*****************************************************************************
570 * SetCommBreak (USER.210)
572 INT16 WINAPI SetCommBreak16(INT16 cid)
574 struct DosDeviceStruct *ptr;
576 TRACE("cid=%d\n", cid);
577 if ((ptr = GetDeviceStruct(cid)) == NULL) {
578 FIXME("no cid=%d found!\n", cid);
579 return -1;
582 ptr->suspended = 1;
583 ptr->commerror = 0;
584 return 0;
587 /*****************************************************************************
588 * ClearCommBreak (USER.211)
590 INT16 WINAPI ClearCommBreak16(INT16 cid)
592 struct DosDeviceStruct *ptr;
594 TRACE("cid=%d\n", cid);
595 if (!(ptr = GetDeviceStruct(cid))) {
596 FIXME("no cid=%d found!\n", cid);
597 return -1;
599 ptr->suspended = 0;
600 ptr->commerror = 0;
601 return 0;
604 /*****************************************************************************
605 * EscapeCommFunction (USER.214)
607 LONG WINAPI EscapeCommFunction16(UINT16 cid,UINT16 nFunction)
609 struct DosDeviceStruct *ptr;
611 TRACE("cid=%d, function=%d\n", cid, nFunction);
613 switch(nFunction) {
614 case GETMAXCOM:
615 TRACE("GETMAXCOM\n");
616 return 4; /* FIXME */
618 case GETMAXLPT:
619 TRACE("GETMAXLPT\n");
620 return FLAG_LPT + 3; /* FIXME */
622 case GETBASEIRQ:
623 TRACE("GETBASEIRQ\n");
624 /* FIXME: use tables */
625 /* just fake something for now */
626 if (cid & FLAG_LPT) {
627 /* LPT1: irq 7, LPT2: irq 5 */
628 return (cid & 0x7f) ? 5 : 7;
629 } else {
630 /* COM1: irq 4, COM2: irq 3,
631 COM3: irq 4, COM4: irq 3 */
632 return 4 - (cid & 1);
636 if ((ptr = GetDeviceStruct(cid)) == NULL) {
637 FIXME("no cid=%d found!\n", cid);
638 return -1;
641 switch (nFunction) {
642 case RESETDEV:
643 case CLRDTR:
644 case CLRRTS:
645 case SETDTR:
646 case SETRTS:
647 case SETXOFF:
648 case SETXON:
649 if(EscapeCommFunction(ptr->handle,nFunction))
650 return 0;
651 else {
652 ptr->commerror = WinError();
653 return -1;
656 case CLRBREAK:
657 case SETBREAK:
658 default:
659 WARN("(cid=%d,nFunction=%d): Unknown function\n",
660 cid, nFunction);
662 return -1;
665 /*****************************************************************************
666 * FlushComm (USER.215)
668 INT16 WINAPI FlushComm16(INT16 cid,INT16 fnQueue)
670 DWORD queue;
671 struct DosDeviceStruct *ptr;
673 TRACE("cid=%d, queue=%d\n", cid, fnQueue);
674 if ((ptr = GetDeviceStruct(cid)) == NULL) {
675 FIXME("no cid=%d found!\n", cid);
676 return -1;
678 switch (fnQueue) {
679 case 0:
680 queue = PURGE_TXABORT;
681 ptr->obuf_tail = ptr->obuf_head;
682 break;
683 case 1:
684 queue = PURGE_RXABORT;
685 ptr->ibuf_head = ptr->ibuf_tail;
686 break;
687 default:
688 WARN("(cid=%d,fnQueue=%d):Unknown queue\n",
689 cid, fnQueue);
690 return -1;
693 if (!PurgeComm(ptr->handle,queue)) {
694 ptr->commerror = WinError();
695 return -1;
696 } else {
697 ptr->commerror = 0;
698 return 0;
702 /********************************************************************
703 * GetCommError (USER.203)
705 INT16 WINAPI GetCommError16(INT16 cid,LPCOMSTAT16 lpStat)
707 int temperror;
708 struct DosDeviceStruct *ptr;
709 unsigned char *stol;
711 if ((ptr = GetDeviceStruct(cid)) == NULL) {
712 FIXME("no handle for cid = %0x!\n",cid);
713 return -1;
715 if (cid&FLAG_LPT) {
716 WARN(" cid %d not comm port\n",cid);
717 return CE_MODE;
719 stol = (unsigned char *)COM[cid].unknown + COMM_MSR_OFFSET;
720 COMM_MSRUpdate( ptr->handle, stol );
722 if (lpStat) {
723 lpStat->status = 0;
725 SleepEx(1,TRUE);
727 lpStat->cbOutQue = comm_outbuf(ptr);
728 lpStat->cbInQue = comm_inbuf(ptr);
730 TRACE("cid %d, error %d, stat %d in %d out %d, stol %x\n",
731 cid, ptr->commerror, lpStat->status, lpStat->cbInQue,
732 lpStat->cbOutQue, *stol);
734 else
735 TRACE("cid %d, error %d, lpStat NULL stol %x\n",
736 cid, ptr->commerror, *stol);
738 /* Return any errors and clear it */
739 temperror = ptr->commerror;
740 ptr->commerror = 0;
741 return(temperror);
744 /*****************************************************************************
745 * SetCommEventMask (USER.208)
747 SEGPTR WINAPI SetCommEventMask16(INT16 cid,UINT16 fuEvtMask)
749 struct DosDeviceStruct *ptr;
750 unsigned char *stol;
752 TRACE("cid %d,mask %d\n",cid,fuEvtMask);
753 if ((ptr = GetDeviceStruct(cid)) == NULL) {
754 FIXME("no handle for cid = %0x!\n",cid);
755 return (SEGPTR)NULL;
758 ptr->eventmask = fuEvtMask;
760 if (cid&FLAG_LPT) {
761 WARN(" cid %d not comm port\n",cid);
762 return (SEGPTR)NULL;
764 /* it's a COM port ? -> modify flags */
765 stol = (unsigned char *)COM[cid].unknown + COMM_MSR_OFFSET;
766 COMM_MSRUpdate( ptr->handle, stol );
768 TRACE(" modem dcd construct %x\n",*stol);
769 if (!COM[cid].seg_unknown) COM[cid].seg_unknown = MapLS( COM[cid].unknown );
770 return COM[cid].seg_unknown;
773 /*****************************************************************************
774 * GetCommEventMask (USER.209)
776 UINT16 WINAPI GetCommEventMask16(INT16 cid,UINT16 fnEvtClear)
778 struct DosDeviceStruct *ptr;
779 WORD events;
781 TRACE("cid %d, mask %d\n", cid, fnEvtClear);
782 if ((ptr = GetDeviceStruct(cid)) == NULL) {
783 FIXME("no handle for cid = %0x!\n",cid);
784 return 0;
787 if (cid&FLAG_LPT) {
788 WARN(" cid %d not comm port\n",cid);
789 return 0;
792 events = *(WORD*)(COM[cid].unknown) & fnEvtClear;
793 *(WORD*)(COM[cid].unknown) &= ~fnEvtClear;
794 return events;
797 /*****************************************************************************
798 * SetCommState (USER.201)
800 INT16 WINAPI SetCommState16(LPDCB16 lpdcb)
802 struct DosDeviceStruct *ptr;
803 DCB dcb;
805 TRACE("cid %d, ptr %p\n", lpdcb->Id, lpdcb);
806 if ((ptr = GetDeviceStruct(lpdcb->Id)) == NULL) {
807 FIXME("no handle for cid = %0x!\n",lpdcb->Id);
808 return -1;
811 memset(&dcb,0,sizeof(dcb));
812 dcb.DCBlength = sizeof(dcb);
815 * according to MSDN, we should first interpret lpdcb->BaudRate as follows:
816 * 1. if the baud rate is a CBR constant, interpret it.
817 * 2. if it is greater than 57600, the baud rate is 115200
818 * 3. use the actual baudrate
819 * steps 2 and 3 are equivilent to 16550 baudrate divisor = 115200/BaudRate
820 * see http://support.microsoft.com/support/kb/articles/q108/9/28.asp
822 switch(lpdcb->BaudRate)
824 case CBR_110: dcb.BaudRate = 110; break;
825 case CBR_300: dcb.BaudRate = 300; break;
826 case CBR_600: dcb.BaudRate = 600; break;
827 case CBR_1200: dcb.BaudRate = 1200; break;
828 case CBR_2400: dcb.BaudRate = 2400; break;
829 case CBR_4800: dcb.BaudRate = 4800; break;
830 case CBR_9600: dcb.BaudRate = 9600; break;
831 case CBR_14400: dcb.BaudRate = 14400; break;
832 case CBR_19200: dcb.BaudRate = 19200; break;
833 case CBR_38400: dcb.BaudRate = 38400; break;
834 case CBR_56000: dcb.BaudRate = 56000; break;
835 case CBR_128000: dcb.BaudRate = 128000; break;
836 case CBR_256000: dcb.BaudRate = 256000; break;
837 default:
838 if(lpdcb->BaudRate>57600)
839 dcb.BaudRate = 115200;
840 else
841 dcb.BaudRate = lpdcb->BaudRate;
844 dcb.ByteSize=lpdcb->ByteSize;
845 dcb.StopBits=lpdcb->StopBits;
847 dcb.fParity=lpdcb->fParity;
848 dcb.Parity=lpdcb->Parity;
850 dcb.fOutxCtsFlow = lpdcb->fOutxCtsFlow;
852 if (lpdcb->fDtrflow || lpdcb->fRtsflow)
853 dcb.fRtsControl = TRUE;
855 if (lpdcb->fDtrDisable)
856 dcb.fDtrControl = TRUE;
858 ptr->evtchar = lpdcb->EvtChar;
860 dcb.fInX = lpdcb->fInX;
861 dcb.fOutX = lpdcb->fOutX;
863 if (!SetCommState(ptr->handle,&dcb)) {
864 ptr->commerror = WinError();
865 return -1;
866 } else {
867 ptr->commerror = 0;
868 return 0;
872 /*****************************************************************************
873 * GetCommState (USER.202)
875 INT16 WINAPI GetCommState16(INT16 cid, LPDCB16 lpdcb)
877 struct DosDeviceStruct *ptr;
878 DCB dcb;
880 TRACE("cid %d, ptr %p\n", cid, lpdcb);
881 if ((ptr = GetDeviceStruct(cid)) == NULL) {
882 FIXME("no handle for cid = %0x!\n",cid);
883 return -1;
885 if (!GetCommState(ptr->handle,&dcb)) {
886 ptr->commerror = WinError();
887 return -1;
890 lpdcb->Id = cid;
892 COMM16_DCBtoDCB16(&dcb,lpdcb);
894 lpdcb->EvtChar = ptr->evtchar;
896 ptr->commerror = 0;
897 return 0;
900 /*****************************************************************************
901 * TransmitCommChar (USER.206)
903 INT16 WINAPI TransmitCommChar16(INT16 cid,CHAR chTransmit)
905 struct DosDeviceStruct *ptr;
907 TRACE("cid %d, data %d\n", cid, chTransmit);
908 if ((ptr = GetDeviceStruct(cid)) == NULL) {
909 FIXME("no handle for cid = %0x!\n",cid);
910 return -1;
913 if (ptr->suspended) {
914 ptr->commerror = IE_HARDWARE;
915 return -1;
918 if (ptr->xmit >= 0) {
919 /* character already queued */
920 /* FIXME: which error would Windows return? */
921 ptr->commerror = CE_TXFULL;
922 return -1;
925 if (ptr->obuf_head == ptr->obuf_tail) {
926 /* transmit queue empty, try to transmit directly */
927 if(1!=COMM16_WriteFile(ptr->handle, &chTransmit, 1))
929 /* didn't work, queue it */
930 ptr->xmit = chTransmit;
931 comm_waitwrite(ptr);
933 } else {
934 /* data in queue, let this char be transmitted next */
935 ptr->xmit = chTransmit;
936 comm_waitwrite(ptr);
939 ptr->commerror = 0;
940 return 0;
943 /*****************************************************************************
944 * UngetCommChar (USER.212)
946 INT16 WINAPI UngetCommChar16(INT16 cid,CHAR chUnget)
948 struct DosDeviceStruct *ptr;
950 TRACE("cid %d (char %d)\n", cid, chUnget);
951 if ((ptr = GetDeviceStruct(cid)) == NULL) {
952 FIXME("no handle for cid = %0x!\n",cid);
953 return -1;
956 if (ptr->suspended) {
957 ptr->commerror = IE_HARDWARE;
958 return -1;
961 if (ptr->unget>=0) {
962 /* character already queued */
963 /* FIXME: which error would Windows return? */
964 ptr->commerror = CE_RXOVER;
965 return -1;
968 ptr->unget = chUnget;
970 ptr->commerror = 0;
971 return 0;
974 /*****************************************************************************
975 * ReadComm (USER.204)
977 INT16 WINAPI ReadComm16(INT16 cid,LPSTR lpvBuf,INT16 cbRead)
979 int status, length;
980 struct DosDeviceStruct *ptr;
981 LPSTR orgBuf = lpvBuf;
983 TRACE("cid %d, ptr %p, length %d\n", cid, lpvBuf, cbRead);
984 if ((ptr = GetDeviceStruct(cid)) == NULL) {
985 FIXME("no handle for cid = %0x!\n",cid);
986 return -1;
989 if (ptr->suspended) {
990 ptr->commerror = IE_HARDWARE;
991 return -1;
994 if(0==comm_inbuf(ptr))
995 SleepEx(1,TRUE);
997 /* read unget character */
998 if (ptr->unget>=0) {
999 *lpvBuf++ = ptr->unget;
1000 ptr->unget = -1;
1002 length = 1;
1003 } else
1004 length = 0;
1006 /* read from receive buffer */
1007 while (length < cbRead) {
1008 status = ((ptr->ibuf_head < ptr->ibuf_tail) ?
1009 ptr->ibuf_size : ptr->ibuf_head) - ptr->ibuf_tail;
1010 if (!status) break;
1011 if ((cbRead - length) < status)
1012 status = cbRead - length;
1014 memcpy(lpvBuf, ptr->inbuf + ptr->ibuf_tail, status);
1015 ptr->ibuf_tail += status;
1016 if (ptr->ibuf_tail >= ptr->ibuf_size)
1017 ptr->ibuf_tail = 0;
1018 lpvBuf += status;
1019 length += status;
1022 TRACE("%s\n", debugstr_an( orgBuf, length ));
1023 ptr->commerror = 0;
1024 return length;
1027 /*****************************************************************************
1028 * WriteComm (USER.205)
1030 INT16 WINAPI WriteComm16(INT16 cid, LPSTR lpvBuf, INT16 cbWrite)
1032 int status, length;
1033 struct DosDeviceStruct *ptr;
1035 TRACE("cid %d, ptr %p, length %d\n",
1036 cid, lpvBuf, cbWrite);
1037 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1038 FIXME("no handle for cid = %0x!\n",cid);
1039 return -1;
1042 if (ptr->suspended) {
1043 ptr->commerror = IE_HARDWARE;
1044 return -1;
1047 TRACE("%s\n", debugstr_an( lpvBuf, cbWrite ));
1049 length = 0;
1050 while (length < cbWrite) {
1051 if ((ptr->obuf_head == ptr->obuf_tail) && (ptr->xmit < 0)) {
1052 /* no data queued, try to write directly */
1053 status = COMM16_WriteFile(ptr->handle, lpvBuf, cbWrite - length);
1054 if (status > 0) {
1055 lpvBuf += status;
1056 length += status;
1057 continue;
1060 /* can't write directly, put into transmit buffer */
1061 status = ((ptr->obuf_tail > ptr->obuf_head) ?
1062 (ptr->obuf_tail-1) : ptr->obuf_size) - ptr->obuf_head;
1063 if (!status) break;
1064 if ((cbWrite - length) < status)
1065 status = cbWrite - length;
1066 memcpy(lpvBuf, ptr->outbuf + ptr->obuf_head, status);
1067 ptr->obuf_head += status;
1068 if (ptr->obuf_head >= ptr->obuf_size)
1069 ptr->obuf_head = 0;
1070 lpvBuf += status;
1071 length += status;
1072 comm_waitwrite(ptr);
1075 ptr->commerror = 0;
1076 return length;
1079 /***********************************************************************
1080 * EnableCommNotification (USER.245)
1082 BOOL16 WINAPI EnableCommNotification16( INT16 cid, HWND16 hwnd,
1083 INT16 cbWriteNotify, INT16 cbOutQueue )
1085 struct DosDeviceStruct *ptr;
1087 TRACE("(%d, %x, %d, %d)\n", cid, hwnd, cbWriteNotify, cbOutQueue);
1088 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1089 FIXME("no handle for cid = %0x!\n",cid);
1090 return -1;
1092 ptr->wnd = WIN_Handle32( hwnd );
1093 ptr->n_read = cbWriteNotify;
1094 ptr->n_write = cbOutQueue;
1095 return TRUE;