Check that we have statfs before using it.
[wine.git] / dlls / user / comm16.c
blobf22245c00b72d52febaaeb4a877230edb9b3cc7b
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"
55 #include <stdlib.h>
56 #include <stdarg.h>
57 #include <stdio.h>
58 #include <string.h>
59 #include <errno.h>
60 #include <ctype.h>
62 #include "ntstatus.h"
63 #include "windef.h"
64 #include "winbase.h"
65 #include "wingdi.h"
66 #include "winreg.h"
67 #include "winuser.h"
68 #include "wine/winuser16.h"
69 #include "wine/port.h"
70 #include "win.h"
71 #include "winerror.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
79 #define MSR_CTS 0x10
80 #define MSR_DSR 0x20
81 #define MSR_RI 0x40
82 #define MSR_RLSD 0x80
83 #define MSR_MASK (MSR_CTS|MSR_DSR|MSR_RI|MSR_RLSD)
85 #define FLAG_LPT 0x80
87 #define MAX_PORTS 9
89 struct DosDeviceStruct {
90 HANDLE handle;
91 int suspended;
92 int unget,xmit;
93 int evtchar;
94 /* events */
95 int commerror, eventmask;
96 /* buffers */
97 char *inbuf,*outbuf;
98 unsigned ibuf_size,ibuf_head,ibuf_tail;
99 unsigned obuf_size,obuf_head,obuf_tail;
100 /* notifications */
101 HWND wnd;
102 int n_read, n_write;
103 OVERLAPPED read_ov, write_ov;
104 /* save terminal states */
105 DCB16 dcb;
106 /* pointer to unknown(==undocumented) comm structure */
107 SEGPTR seg_unknown;
108 BYTE unknown[40];
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 )
118 UCHAR tmpmsr=0;
119 DWORD mstat=0;
121 if(!GetCommModemStatus(handle,&mstat))
122 return;
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 )
133 HKEY hkey;
134 char temp[256], *btemp;
136 if (port >= MAX_PORTS) return FALSE;
137 temp[0] = 0;
138 if (!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\serialports", &hkey))
140 DWORD type, count = sizeof(temp);
141 char value[8];
143 sprintf( value, "COM%d", port+1 );
144 RegQueryValueExA(hkey, value, 0, &type, temp, &count);
145 RegCloseKey(hkey);
147 if (!temp[0]) return FALSE;
149 btemp = strchr(temp,',');
150 if (btemp != NULL)
152 *btemp++ = '\0';
153 if (baudrate) *baudrate = atoi(btemp);
155 else if (baudrate) *baudrate = -1;
156 if (devicename) lstrcpynA( devicename, temp, size );
157 return TRUE;
160 static BOOL get_lpt_device_name( int port, char *devicename, DWORD size )
162 HKEY hkey;
163 char temp[256];
165 if (port >= MAX_PORTS) return FALSE;
166 temp[0] = 0;
167 if (!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\parallelports", &hkey))
169 DWORD type, count = sizeof(temp);
170 char value[8];
172 sprintf( value, "LPT%d", port+1 );
173 RegQueryValueExA(hkey, value, 0, &type, temp, &count);
174 RegCloseKey(hkey);
176 if (!temp[0]) return FALSE;
178 if (devicename) lstrcpynA( devicename, temp, size );
179 return TRUE;
183 static struct DosDeviceStruct *GetDeviceStruct(int index)
185 if ((index&0x7F)<=MAX_PORTS) {
186 if (!(index&FLAG_LPT)) {
187 if (COM[index].handle)
188 return &COM[index];
189 } else {
190 index &= 0x7f;
191 if (LPT[index].handle)
192 return &LPT[index];
196 return NULL;
199 static int GetCommPort_ov(LPOVERLAPPED ov, int write)
201 int x;
203 for (x=0; x<MAX_PORTS; x++) {
204 if (ov == (write?&COM[x].write_ov:&COM[x].read_ov))
205 return x;
208 return -1;
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);
224 switch (errno) {
225 default:
226 return CE_IOE;
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)
247 int prev ;
248 WORD mask = 0;
249 int cid = GetCommPort_ov(ov,0);
250 struct DosDeviceStruct *ptr;
252 if(cid<0) {
253 ERR("async write with bad overlapped pointer\n");
254 return;
256 ptr = &COM[cid];
258 /* we get cancelled when CloseComm is called */
259 if (status==STATUS_CANCELLED)
261 TRACE("Cancelled\n");
262 return;
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;
269 return;
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;
279 mask |= CN_EVENT;
281 if (ptr->eventmask & EV_RXCHAR) {
282 *(WORD*)(COM[cid].unknown) |= EV_RXCHAR;
283 mask |= CN_EVENT;
286 /* advance buffer position */
287 ptr->ibuf_head += len;
288 if (ptr->ibuf_head >= ptr->ibuf_size)
289 ptr->ibuf_head = 0;
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 */
295 mask |= CN_RECEIVE;
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 */
306 comm_waitread(ptr);
309 /* this is meant to work like write() */
310 static INT COMM16_WriteFile(HANDLE hComm, LPCVOID buffer, DWORD len)
312 OVERLAPPED ov;
313 DWORD count= -1;
315 ZeroMemory(&ov,sizeof(ov));
316 ov.hEvent = CreateEventA(NULL,0,0,NULL);
317 if(ov.hEvent==INVALID_HANDLE_VALUE)
318 return -1;
320 if(!WriteFile(hComm,buffer,len,&count,&ov))
322 if(GetLastError()==ERROR_IO_PENDING)
324 GetOverlappedResult(hComm,&ov,&count,TRUE);
327 CloseHandle(ov.hEvent);
329 return count;
332 static VOID WINAPI COMM16_WriteComplete(DWORD status, DWORD len, LPOVERLAPPED ov)
334 int prev, bleft;
335 WORD mask = 0;
336 int cid = GetCommPort_ov(ov,1);
337 struct DosDeviceStruct *ptr;
339 if(cid<0) {
340 ERR("async write with bad overlapped pointer\n");
341 return;
343 ptr = &COM[cid];
345 /* read data from comm port */
346 if (status != STATUS_SUCCESS) {
347 ERR("async write failed\n");
348 COM[cid].commerror = CE_RXOVER;
349 return;
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)
357 ptr->obuf_tail = 0;
359 /* write any TransmitCommChar character */
360 if (ptr->xmit>=0) {
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 */
373 mask |= CN_TRANSMIT;
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 */
383 if(bleft)
384 comm_waitwrite(ptr);
387 static void comm_waitread(struct DosDeviceStruct *ptr)
389 int bleft;
390 COMSTAT stat;
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;
399 else
400 bleft = 1;
402 /* always read at least one byte */
403 if(bleft==0)
404 bleft++;
406 ReadFileEx(ptr->handle,
407 ptr->inbuf + ptr->ibuf_head,
408 bleft,
409 &ptr->read_ov,
410 COMM16_ReadComplete);
413 static void comm_waitwrite(struct DosDeviceStruct *ptr)
415 int bleft;
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,
421 bleft,
422 &ptr->write_ov,
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;
435 else {
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;
447 lpdcb16->fNull = 0;
448 lpdcb16->fChEvt = 0;
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;
461 lpdcb16->XonChar =
462 lpdcb16->XoffChar =
464 lpdcb16->XonLim = 10;
465 lpdcb16->XoffLim = 10;
467 return 0;
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" */
480 /* 012345 */
481 int port;
482 DCB dcb;
484 TRACE("(%s), ptr %p\n", device, lpdcb);
486 if (strncasecmp(device,"COM",3))
487 return -1;
488 port = device[3] - '0';
490 if (port-- == 0) {
491 ERR("BUG ! COM0 can't exist!\n");
492 return -1;
495 if (!ValidCOMPort(port)) {
496 FIXME("invalid COM port %d?\n",port);
497 return -1;
500 memset(lpdcb, 0, sizeof(DCB16)); /* initialize */
502 lpdcb->Id = port;
503 dcb.DCBlength = sizeof(DCB);
505 if (strchr(device,'=')) /* block new style */
506 return -1;
508 if(!BuildCommDCBA(device,&dcb))
509 return -1;
511 return COMM16_DCBtoDCB16(&dcb, lpdcb);
514 /*****************************************************************************
515 * OpenComm (USER.200)
517 INT16 WINAPI OpenComm16(LPCSTR device,UINT16 cbInQueue,UINT16 cbOutQueue)
519 int port;
520 HANDLE handle;
522 TRACE("%s, %d, %d\n", device, cbInQueue, cbOutQueue);
524 if (strlen(device) < 4)
525 return IE_BADID;
527 port = device[3] - '0';
529 if (port-- == 0)
530 ERR("BUG ! COM0 or LPT0 don't exist !\n");
532 if (!strncasecmp(device,"COM",3))
534 char devicename[32];
535 int baudrate;
537 if (!get_com_device_name( port, devicename, sizeof(devicename), &baudrate ))
538 return IE_BADID;
540 TRACE("%s = %s\n", device, devicename);
542 if (COM[port].handle)
543 return IE_OPEN;
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));
550 return IE_HARDWARE;
551 } else {
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 */
561 if(baudrate>-1){
562 DCB16 dcb;
563 memcpy(&dcb,&COM[port].dcb,sizeof(dcb));
564 dcb.BaudRate=baudrate;
565 /* more defaults:
566 * databits, parity, stopbits
568 SetCommState16( &dcb);
570 /* init priority characters */
571 COM[port].unget = -1;
572 COM[port].xmit = -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");
590 return IE_MEMORY;
593 ZeroMemory(&COM[port].read_ov,sizeof (OVERLAPPED));
594 ZeroMemory(&COM[port].write_ov,sizeof (OVERLAPPED));
596 comm_waitread( &COM[port] );
597 USER16_AlertableWait++;
599 return port;
602 else
603 if (!strncasecmp(device,"LPT",3)) {
605 if (!ValidLPTPort(port))
606 return IE_BADID;
608 if (LPT[port].handle)
609 return IE_OPEN;
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) {
614 return IE_HARDWARE;
615 } else {
616 LPT[port].handle = handle;
617 LPT[port].commerror = 0;
618 LPT[port].eventmask = 0;
619 return port|FLAG_LPT;
622 return IE_BADID;
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);
635 return -1;
637 if (!(cid&FLAG_LPT)) {
638 /* COM port */
639 UnMapLS( COM[cid].seg_unknown );
640 USER16_AlertableWait--;
641 CancelIo(ptr->handle);
643 /* free buffers */
644 free(ptr->outbuf);
645 free(ptr->inbuf);
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? */
654 return -1;
655 } else {
656 ptr->commerror = 0;
657 ptr->handle = 0;
658 return 0;
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);
672 return -1;
675 ptr->suspended = 1;
676 ptr->commerror = 0;
677 return 0;
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);
690 return -1;
692 ptr->suspended = 0;
693 ptr->commerror = 0;
694 return 0;
697 /*****************************************************************************
698 * EscapeCommFunction (USER.214)
700 LONG WINAPI EscapeCommFunction16(UINT16 cid,UINT16 nFunction)
702 struct DosDeviceStruct *ptr;
703 int max;
705 TRACE("cid=%d, function=%d\n", cid, nFunction);
707 switch(nFunction) {
708 case GETMAXCOM:
709 TRACE("GETMAXCOM\n");
710 for (max = MAX_PORTS;!ValidCOMPort(max);max--)
712 return max;
714 case GETMAXLPT:
715 TRACE("GETMAXLPT\n");
716 for (max = MAX_PORTS;!ValidLPTPort(max);max--)
718 return FLAG_LPT + max;
720 case GETBASEIRQ:
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;
727 } else {
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);
736 return -1;
739 switch (nFunction) {
740 case RESETDEV:
741 case CLRDTR:
742 case CLRRTS:
743 case SETDTR:
744 case SETRTS:
745 case SETXOFF:
746 case SETXON:
747 if(EscapeCommFunction(ptr->handle,nFunction))
748 return 0;
749 else {
750 ptr->commerror = WinError();
751 return -1;
754 case CLRBREAK:
755 case SETBREAK:
756 default:
757 WARN("(cid=%d,nFunction=%d): Unknown function\n",
758 cid, nFunction);
760 return -1;
763 /*****************************************************************************
764 * FlushComm (USER.215)
766 INT16 WINAPI FlushComm16(INT16 cid,INT16 fnQueue)
768 DWORD queue;
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);
774 return -1;
776 switch (fnQueue) {
777 case 0:
778 queue = PURGE_TXABORT;
779 ptr->obuf_tail = ptr->obuf_head;
780 break;
781 case 1:
782 queue = PURGE_RXABORT;
783 ptr->ibuf_head = ptr->ibuf_tail;
784 break;
785 default:
786 WARN("(cid=%d,fnQueue=%d):Unknown queue\n",
787 cid, fnQueue);
788 return -1;
791 if (!PurgeComm(ptr->handle,queue)) {
792 ptr->commerror = WinError();
793 return -1;
794 } else {
795 ptr->commerror = 0;
796 return 0;
800 /********************************************************************
801 * GetCommError (USER.203)
803 INT16 WINAPI GetCommError16(INT16 cid,LPCOMSTAT16 lpStat)
805 int temperror;
806 struct DosDeviceStruct *ptr;
807 unsigned char *stol;
809 if ((ptr = GetDeviceStruct(cid)) == NULL) {
810 FIXME("no handle for cid = %0x!\n",cid);
811 return -1;
813 if (cid&FLAG_LPT) {
814 WARN(" cid %d not comm port\n",cid);
815 return CE_MODE;
817 stol = (unsigned char *)COM[cid].unknown + COMM_MSR_OFFSET;
818 COMM_MSRUpdate( ptr->handle, stol );
820 if (lpStat) {
821 lpStat->status = 0;
823 SleepEx(1,TRUE);
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);
832 else
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;
838 ptr->commerror = 0;
839 return(temperror);
842 /*****************************************************************************
843 * SetCommEventMask (USER.208)
845 SEGPTR WINAPI SetCommEventMask16(INT16 cid,UINT16 fuEvtMask)
847 struct DosDeviceStruct *ptr;
848 unsigned char *stol;
850 TRACE("cid %d,mask %d\n",cid,fuEvtMask);
851 if ((ptr = GetDeviceStruct(cid)) == NULL) {
852 FIXME("no handle for cid = %0x!\n",cid);
853 return (SEGPTR)NULL;
856 ptr->eventmask = fuEvtMask;
858 if ((cid&FLAG_LPT) || !ValidCOMPort(cid)) {
859 WARN(" cid %d not comm port\n",cid);
860 return (SEGPTR)NULL;
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;
877 WORD events;
879 TRACE("cid %d, mask %d\n", cid, fnEvtClear);
880 if ((ptr = GetDeviceStruct(cid)) == NULL) {
881 FIXME("no handle for cid = %0x!\n",cid);
882 return 0;
885 if ((cid&FLAG_LPT) || !ValidCOMPort(cid)) {
886 WARN(" cid %d not comm port\n",cid);
887 return 0;
890 events = *(WORD*)(COM[cid].unknown) & fnEvtClear;
891 *(WORD*)(COM[cid].unknown) &= ~fnEvtClear;
892 return events;
895 /*****************************************************************************
896 * SetCommState (USER.201)
898 INT16 WINAPI SetCommState16(LPDCB16 lpdcb)
900 struct DosDeviceStruct *ptr;
901 DCB dcb;
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);
906 return -1;
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;
935 default:
936 if(lpdcb->BaudRate>57600)
937 dcb.BaudRate = 115200;
938 else
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();
963 return -1;
964 } else {
965 ptr->commerror = 0;
966 return 0;
970 /*****************************************************************************
971 * GetCommState (USER.202)
973 INT16 WINAPI GetCommState16(INT16 cid, LPDCB16 lpdcb)
975 struct DosDeviceStruct *ptr;
976 DCB dcb;
978 TRACE("cid %d, ptr %p\n", cid, lpdcb);
979 if ((ptr = GetDeviceStruct(cid)) == NULL) {
980 FIXME("no handle for cid = %0x!\n",cid);
981 return -1;
983 if (!GetCommState(ptr->handle,&dcb)) {
984 ptr->commerror = WinError();
985 return -1;
988 lpdcb->Id = cid;
990 COMM16_DCBtoDCB16(&dcb,lpdcb);
992 lpdcb->EvtChar = ptr->evtchar;
994 ptr->commerror = 0;
995 return 0;
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);
1008 return -1;
1011 if (ptr->suspended) {
1012 ptr->commerror = IE_HARDWARE;
1013 return -1;
1016 if (ptr->xmit >= 0) {
1017 /* character already queued */
1018 /* FIXME: which error would Windows return? */
1019 ptr->commerror = CE_TXFULL;
1020 return -1;
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);
1031 } else {
1032 /* data in queue, let this char be transmitted next */
1033 ptr->xmit = chTransmit;
1034 comm_waitwrite(ptr);
1037 ptr->commerror = 0;
1038 return 0;
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);
1051 return -1;
1054 if (ptr->suspended) {
1055 ptr->commerror = IE_HARDWARE;
1056 return -1;
1059 if (ptr->unget>=0) {
1060 /* character already queued */
1061 /* FIXME: which error would Windows return? */
1062 ptr->commerror = CE_RXOVER;
1063 return -1;
1066 ptr->unget = chUnget;
1068 ptr->commerror = 0;
1069 return 0;
1072 /*****************************************************************************
1073 * ReadComm (USER.204)
1075 INT16 WINAPI ReadComm16(INT16 cid,LPSTR lpvBuf,INT16 cbRead)
1077 int status, length;
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);
1084 return -1;
1087 if (ptr->suspended) {
1088 ptr->commerror = IE_HARDWARE;
1089 return -1;
1092 if(0==comm_inbuf(ptr))
1093 SleepEx(1,TRUE);
1095 /* read unget character */
1096 if (ptr->unget>=0) {
1097 *lpvBuf++ = ptr->unget;
1098 ptr->unget = -1;
1100 length = 1;
1101 } else
1102 length = 0;
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;
1108 if (!status) break;
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)
1115 ptr->ibuf_tail = 0;
1116 lpvBuf += status;
1117 length += status;
1120 TRACE("%s\n", debugstr_an( orgBuf, length ));
1121 ptr->commerror = 0;
1122 return length;
1125 /*****************************************************************************
1126 * WriteComm (USER.205)
1128 INT16 WINAPI WriteComm16(INT16 cid, LPSTR lpvBuf, INT16 cbWrite)
1130 int status, length;
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);
1137 return -1;
1140 if (ptr->suspended) {
1141 ptr->commerror = IE_HARDWARE;
1142 return -1;
1145 TRACE("%s\n", debugstr_an( lpvBuf, cbWrite ));
1147 length = 0;
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);
1152 if (status > 0) {
1153 lpvBuf += status;
1154 length += status;
1155 continue;
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;
1161 if (!status) break;
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)
1167 ptr->obuf_head = 0;
1168 lpvBuf += status;
1169 length += status;
1170 comm_waitwrite(ptr);
1173 ptr->commerror = 0;
1174 return length;
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);
1188 return -1;
1190 ptr->wnd = WIN_Handle32( hwnd );
1191 ptr->n_read = cbWriteNotify;
1192 ptr->n_write = cbOutQueue;
1193 return TRUE;