Added DebugBreak.
[wine] / misc / comm.c
1  /*
2  * DEC 93 Erik Bos <erik@xs4all.nl>
3  *
4  * Copyright 1996 Marcus Meissner
5  *
6  * Mar 31, 1999. Ove Kåven <ovek@arcticnet.no>
7  * - Implemented buffers and EnableCommNotification.
8  *
9  * Apr 3, 1999.  Lawson Whitney <lawson_whitney@juno.com>
10  * - Fixed the modem control part of EscapeCommFunction16.
11  *
12  * Mar 3, 1999. Ove Kåven <ovek@arcticnet.no>
13  * - Use port indices instead of unixfds for win16
14  * - Moved things around (separated win16 and win32 routines)
15  * - Added some hints on how to implement buffers and EnableCommNotification.
16  *
17  * May 26, 1997.  Fixes and comments by Rick Richardson <rick@dgii.com> [RER]
18  * - ptr->fd wasn't getting cleared on close.
19  * - GetCommEventMask() and GetCommError() didn't do much of anything.
20  *   IMHO, they are still wrong, but they at least implement the RXCHAR
21  *   event and return I/O queue sizes, which makes the app I'm interested
22  *   in (analog devices EZKIT DSP development system) work.
23  *
24  * August 12, 1997.  Take a bash at SetCommEventMask - Lawson Whitney
25  *                                     <lawson_whitney@juno.com>
26  * July 6, 1998. Fixes and comments by Valentijn Sessink
27  *                                     <vsessink@ic.uva.nl> [V]
28  * Oktober 98, Rein Klazes [RHK]
29  * A program that wants to monitor the modem status line (RLSD/DCD) may
30  * poll the modem status register in the commMask structure. I update the bit
31  * in GetCommError, waiting for an implementation of communication events.
32  * 
33  */
34
35 #include "config.h"
36
37 #include <stdlib.h>
38 #include <termios.h>
39 #include <fcntl.h>
40 #include <string.h>
41 #ifdef HAVE_STRINGS_H
42 # include <strings.h>
43 #endif
44 #include <errno.h>
45 #include <ctype.h>
46 #include <sys/stat.h>
47 #ifdef HAVE_SYS_FILIO_H
48 # include <sys/filio.h>
49 #endif
50 #include <sys/ioctl.h>
51 #include <unistd.h>
52
53 #include "wine/winuser16.h"
54 #include "comm.h"
55 #ifdef HAVE_SYS_MODEM_H
56 # include <sys/modem.h>
57 #endif
58 #ifdef HAVE_SYS_STRTIO_H
59 # include <sys/strtio.h>
60 #endif
61 #include "heap.h"
62 #include "options.h"
63
64 #include "server/request.h"
65 #include "server.h"
66 #include "process.h"
67 #include "winerror.h"
68 #include "async.h"
69
70 #include "debug.h"
71
72 DEFAULT_DEBUG_CHANNEL(comm)
73
74 #ifndef TIOCINQ
75 #define TIOCINQ FIONREAD
76 #endif
77 #define COMM_MSR_OFFSET  35       /* see knowledge base Q101417 */
78 #define FLAG_LPT 0x80
79
80 struct DosDeviceStruct COM[MAX_PORTS];
81 struct DosDeviceStruct LPT[MAX_PORTS];
82 /* pointers to unknown(==undocumented) comm structure */ 
83 LPCVOID *unknown[MAX_PORTS];
84 /* save terminal states */
85 static struct termios m_stat[MAX_PORTS];
86
87 void COMM_Init(void)
88 {
89         int x;
90         char option[10], temp[256], *btemp;
91         struct stat st;
92
93         for (x=0; x!=MAX_PORTS; x++) {
94                 strcpy(option,"COMx");
95                 option[3] = '1' + x;
96                 option[4] = '\0';
97
98                 PROFILE_GetWineIniString( "serialports", option, "*",
99                                           temp, sizeof(temp) );
100                 if (!strcmp(temp, "*") || *temp == '\0') 
101                         COM[x].devicename = NULL;
102                 else {
103                         btemp = strchr(temp,',');
104                         if (btemp != NULL) {
105                                 *btemp++ = '\0';
106                                 COM[x].baudrate = atoi(btemp);
107                         } else {
108                                 COM[x].baudrate = -1;
109                         }
110                         stat(temp, &st);
111                         if (!S_ISCHR(st.st_mode)) 
112                                 WARN(comm,"Can't use `%s' as %s !\n", temp, option);
113                         else
114                                 if ((COM[x].devicename = malloc(strlen(temp)+1)) == NULL) 
115                                         WARN(comm,"Can't malloc for device info!\n");
116                                 else {
117                                         COM[x].fd = 0;
118                                         strcpy(COM[x].devicename, temp);
119                                 }
120                 TRACE(comm, "%s = %s\n", option, COM[x].devicename);
121                 }
122
123                 strcpy(option, "LPTx");
124                 option[3] = '1' + x;
125                 option[4] = '\0';
126
127                 PROFILE_GetWineIniString( "parallelports", option, "*",
128                                           temp, sizeof(temp) );
129                 if (!strcmp(temp, "*") || *temp == '\0')
130                         LPT[x].devicename = NULL;
131                 else {
132                         stat(temp, &st);
133                         if (!S_ISCHR(st.st_mode)) 
134                                 WARN(comm,"Can't use `%s' as %s !\n", temp, option);
135                         else 
136                                 if ((LPT[x].devicename = malloc(strlen(temp)+1)) == NULL) 
137                                         WARN(comm,"Can't malloc for device info!\n");
138                                 else {
139                                         LPT[x].fd = 0;
140                                         strcpy(LPT[x].devicename, temp);
141                                 }
142                 TRACE(comm, "%s = %s\n", option, LPT[x].devicename);
143                 }
144
145         }
146 }
147
148
149 struct DosDeviceStruct *GetDeviceStruct_fd(int fd)
150 {
151         int x;
152
153         for (x=0; x!=MAX_PORTS; x++) {
154             if (COM[x].fd == fd)
155                 return &COM[x];
156             if (LPT[x].fd == fd)
157                 return &LPT[x];
158         }
159
160         return NULL;
161 }
162
163 struct DosDeviceStruct *GetDeviceStruct(int fd)
164 {
165         if ((fd&0x7F)<=MAX_PORTS) {
166             if (!(fd&FLAG_LPT)) {
167                 if (COM[fd].fd)
168                     return &COM[fd];
169             } else {
170                 if (LPT[fd].fd)
171                     return &LPT[fd];
172             }
173         }
174
175         return NULL;
176 }
177
178 int    GetCommPort_fd(int fd)
179 {
180         int x;
181         
182         for (x=0; x<MAX_PORTS; x++) {
183              if (COM[x].fd == fd)
184                  return x;
185        }
186        
187        return -1;
188
189
190 int ValidCOMPort(int x)
191 {
192         return(x < MAX_PORTS ? (int) COM[x].devicename : 0); 
193 }
194
195 int ValidLPTPort(int x)
196 {
197         return(x < MAX_PORTS ? (int) LPT[x].devicename : 0); 
198 }
199
200 int WinError(void)
201 {
202         TRACE(comm, "errno = %d\n", errno);
203         switch (errno) {
204                 default:
205                         return CE_IOE;
206                 }
207 }
208
209 static unsigned comm_inbuf(struct DosDeviceStruct *ptr)
210 {
211   return ((ptr->ibuf_tail > ptr->ibuf_head) ? ptr->ibuf_size : 0)
212     + ptr->ibuf_head - ptr->ibuf_tail;
213 }
214
215 static unsigned comm_outbuf(struct DosDeviceStruct *ptr)
216 {
217   return ((ptr->obuf_tail > ptr->obuf_head) ? ptr->obuf_size : 0)
218     + ptr->obuf_head - ptr->obuf_tail;
219 }
220
221 static int COMM_WhackModem(int fd, unsigned int andy, unsigned int orrie)
222 {
223     unsigned int mstat, okay;
224     okay = ioctl(fd, TIOCMGET, &mstat);
225     if (okay) return okay;
226     if (andy) mstat &= andy;
227     mstat |= orrie;
228     return ioctl(fd, TIOCMSET, &mstat);
229 }
230         
231 static void comm_notification(int fd,void*private)
232 {
233   struct DosDeviceStruct *ptr = (struct DosDeviceStruct *)private;
234   int prev, bleft, len;
235   WORD mask = 0;
236   int cid = GetCommPort_fd(fd);
237
238   TRACE(comm, "async notification\n");
239   /* read data from comm port */
240   prev = comm_inbuf(ptr);
241   do {
242     bleft = ((ptr->ibuf_tail > ptr->ibuf_head) ? (ptr->ibuf_tail-1) : ptr->ibuf_size)
243       - ptr->ibuf_head;
244     len = read(fd, ptr->inbuf + ptr->ibuf_head, bleft?bleft:1);
245     if (len > 0) {
246       if (!bleft) {
247         ptr->commerror = CE_RXOVER;
248       } else {
249         /* check for events */
250         if ((ptr->eventmask & EV_RXFLAG) &&
251             memchr(ptr->inbuf + ptr->ibuf_head, ptr->evtchar, bleft)) {
252           *(WORD*)(unknown[cid]) |= EV_RXFLAG;
253           mask |= CN_EVENT;
254         }
255         if (ptr->eventmask & EV_RXCHAR) {
256           *(WORD*)(unknown[cid]) |= EV_RXCHAR;
257           mask |= CN_EVENT;
258         }
259         /* advance buffer position */
260         ptr->ibuf_head += len;
261         if (ptr->ibuf_head >= ptr->ibuf_size)
262           ptr->ibuf_head = 0;
263       }
264     }
265   } while (len > 0);
266   /* check for notification */
267   if (ptr->wnd && (ptr->n_read>0) && (prev<ptr->n_read) &&
268       (comm_inbuf(ptr)>=ptr->n_read)) {
269     /* passed the receive notification threshold */
270     mask |= CN_RECEIVE;
271   }
272
273   /* write any TransmitCommChar character */
274   if (ptr->xmit>=0) {
275     len = write(fd, &(ptr->xmit), 1);
276     if (len > 0) ptr->xmit = -1;
277   }
278   /* write from output queue */
279   prev = comm_outbuf(ptr);
280   do {
281     bleft = ((ptr->obuf_tail <= ptr->obuf_head) ? ptr->obuf_head : ptr->obuf_size)
282       - ptr->obuf_tail;
283     len = bleft ? write(fd, ptr->outbuf + ptr->obuf_tail, bleft) : 0;
284     if (len > 0) {
285       ptr->obuf_tail += len;
286       if (ptr->obuf_tail >= ptr->obuf_size)
287         ptr->obuf_tail = 0;
288       /* flag event */
289       if ((ptr->obuf_tail == ptr->obuf_head) && (ptr->eventmask & EV_TXEMPTY)) {
290         *(WORD*)(unknown[cid]) |= EV_TXEMPTY;
291         mask |= CN_EVENT;
292       }
293     }
294   } while (len > 0);
295   /* check for notification */
296   if (ptr->wnd && (ptr->n_write>0) && (prev>=ptr->n_write) &&
297       (comm_outbuf(ptr)<ptr->n_write)) {
298     /* passed the transmit notification threshold */
299     mask |= CN_TRANSMIT;
300   }
301
302   /* send notifications, if any */
303   if (ptr->wnd && mask) {
304     TRACE(comm, "notifying %04x: cid=%d, mask=%02x\n", ptr->wnd, cid, mask);
305     PostMessage16(ptr->wnd, WM_COMMNOTIFY, cid, mask);
306   }
307 }
308
309 /**************************************************************************
310  *         BuildCommDCB         (USER.213)
311  */
312 BOOL16 WINAPI BuildCommDCB16(LPCSTR device, LPDCB16 lpdcb)
313 {
314         /* "COM1:9600,n,8,1"    */
315         /*  012345              */
316         int port;
317         char *ptr, temp[256];
318
319         TRACE(comm, "(%s), ptr %p\n", device, lpdcb);
320
321         if (!lstrncmpiA(device,"COM",3)) {
322                 port = device[3] - '0';
323         
324
325                 if (port-- == 0) {
326                         ERR(comm, "BUG ! COM0 can't exist!.\n");
327                         return -1;
328                 }
329
330                 if (!ValidCOMPort(port)) {
331                         return -1;
332                 }
333                 
334                 memset(lpdcb, 0, sizeof(DCB16)); /* initialize */
335
336                 lpdcb->Id = port;
337                 
338                 if (!*(device+4))
339                         return 0;
340
341                 if (*(device+4) != ':')
342                         return -1;
343                 
344                 strcpy(temp,device+5);
345                 ptr = strtok(temp, ", "); 
346
347                 if (COM[port].baudrate > 0)
348                         lpdcb->BaudRate = COM[port].baudrate;
349                 else
350                         lpdcb->BaudRate = atoi(ptr);
351                 TRACE(comm,"baudrate (%d)\n", lpdcb->BaudRate);
352
353                 ptr = strtok(NULL, ", ");
354                 if (islower(*ptr))
355                         *ptr = toupper(*ptr);
356
357                 TRACE(comm,"parity (%c)\n", *ptr);
358                 lpdcb->fParity = TRUE;
359                 switch (*ptr) {
360                         case 'N':
361                                 lpdcb->Parity = NOPARITY;
362                                 lpdcb->fParity = FALSE;
363                                 break;                  
364                         case 'E':
365                                 lpdcb->Parity = EVENPARITY;
366                                 break;                  
367                         case 'M':
368                                 lpdcb->Parity = MARKPARITY;
369                                 break;                  
370                         case 'O':
371                                 lpdcb->Parity = ODDPARITY;
372                                 break;                  
373                         default:
374                                 WARN(comm,"Unknown parity `%c'!\n", *ptr);
375                                 return -1;
376                 }
377
378                 ptr = strtok(NULL, ", "); 
379                 TRACE(comm, "charsize (%c)\n", *ptr);
380                 lpdcb->ByteSize = *ptr - '0';
381
382                 ptr = strtok(NULL, ", ");
383                 TRACE(comm, "stopbits (%c)\n", *ptr);
384                 switch (*ptr) {
385                         case '1':
386                                 lpdcb->StopBits = ONESTOPBIT;
387                                 break;                  
388                         case '2':
389                                 lpdcb->StopBits = TWOSTOPBITS;
390                                 break;                  
391                         default:
392                                 WARN(comm,"Unknown # of stopbits `%c'!\n", *ptr);
393                                 return -1;
394                 }
395         }       
396
397         return 0;
398 }
399
400 /*****************************************************************************
401  *      OpenComm                (USER.200)
402  */
403 INT16 WINAPI OpenComm16(LPCSTR device,UINT16 cbInQueue,UINT16 cbOutQueue)
404 {
405         int port,fd;
406
407         TRACE(comm, "%s, %d, %d\n", device, cbInQueue, cbOutQueue);
408
409                 port = device[3] - '0';
410
411         if (port-- == 0)
412                 ERR(comm, "BUG ! COM0 or LPT0 don't exist !\n");
413
414         if (!lstrncmpiA(device,"COM",3)) {
415                 
416                 TRACE(comm, "%s = %s\n", device, COM[port].devicename);
417
418                 if (!ValidCOMPort(port))
419                         return IE_BADID;
420
421                 if (COM[port].fd)
422                         return IE_OPEN;
423
424                 fd = open(COM[port].devicename, O_RDWR | O_NONBLOCK);
425                 if (fd == -1) {
426                         ERR(comm, "error=%d\n", errno);
427                         return IE_HARDWARE;
428                 } else {
429                         unknown[port] = SEGPTR_ALLOC(40);
430                         bzero(unknown[port],40);
431                         COM[port].fd = fd;
432                         COM[port].commerror = 0;
433                         COM[port].eventmask = 0;
434                         COM[port].evtchar = 0; /* FIXME: default? */
435                         /* save terminal state */
436                         tcgetattr(fd,&m_stat[port]);
437                         /* set default parameters */
438                         if(COM[port].baudrate>-1){
439                             DCB16 dcb;
440                             GetCommState16(port, &dcb);
441                             dcb.BaudRate=COM[port].baudrate;
442                             /* more defaults:
443                              * databits, parity, stopbits
444                              */
445                             SetCommState16( &dcb);
446                         }
447                         /* init priority characters */
448                         COM[port].unget = -1;
449                         COM[port].xmit = -1;
450                         /* allocate buffers */
451                         COM[port].ibuf_size = cbInQueue;
452                         COM[port].ibuf_head = COM[port].ibuf_tail= 0;
453                         COM[port].obuf_size = cbOutQueue;
454                         COM[port].obuf_head = COM[port].obuf_tail = 0;
455
456                         COM[port].inbuf = malloc(cbInQueue);
457                         if (COM[port].inbuf) {
458                           COM[port].outbuf = malloc(cbOutQueue);
459                           if (!COM[port].outbuf)
460                             free(COM[port].inbuf);
461                         } else COM[port].outbuf = NULL;
462                         if (!COM[port].outbuf) {
463                           /* not enough memory */
464                           tcsetattr(COM[port].fd,TCSANOW,&m_stat[port]);
465                           close(COM[port].fd);
466                           ERR(comm, "out of memory");
467                           return IE_MEMORY;
468                         }
469
470                         /* enable async notifications */
471                         ASYNC_RegisterFD(COM[port].fd,comm_notification,&COM[port]);
472                         /* bootstrap notifications, just in case */
473                         comm_notification(COM[port].fd,&COM[port]);
474                         return port;
475                 }
476         } 
477         else 
478         if (!lstrncmpiA(device,"LPT",3)) {
479         
480                 if (!ValidLPTPort(port))
481                         return IE_BADID;
482
483                 if (LPT[port].fd)
484                         return IE_OPEN;
485
486                 fd = open(LPT[port].devicename, O_RDWR | O_NONBLOCK, 0);
487                 if (fd == -1) {
488                         return IE_HARDWARE;
489                 } else {
490                         LPT[port].fd = fd;
491                         LPT[port].commerror = 0;
492                         LPT[port].eventmask = 0;
493                         return port|FLAG_LPT;
494                 }
495         }
496         return 0;
497 }
498
499 /*****************************************************************************
500  *      CloseComm               (USER.207)
501  */
502 INT16 WINAPI CloseComm16(INT16 cid)
503 {
504         struct DosDeviceStruct *ptr;
505         
506         TRACE(comm,"cid=%d\n", cid);
507         if ((ptr = GetDeviceStruct(cid)) == NULL) {
508                 return -1;
509         }
510         if (!(cid&FLAG_LPT)) {
511                 /* COM port */
512                 SEGPTR_FREE(unknown[cid]); /* [LW] */
513
514                 /* disable async notifications */
515                 ASYNC_UnregisterFD(COM[cid].fd,comm_notification);
516                 /* free buffers */
517                 free(ptr->outbuf);
518                 free(ptr->inbuf);
519
520                 /* reset modem lines */
521                 tcsetattr(ptr->fd,TCSANOW,&m_stat[cid]);
522         }
523
524         if (close(ptr->fd) == -1) {
525                 ptr->commerror = WinError();
526                 /* FIXME: should we clear ptr->fd here? */
527                 return -1;
528         } else {
529                 ptr->commerror = 0;
530                 ptr->fd = 0;
531                 return 0;
532         }
533 }
534
535 /*****************************************************************************
536  *      SetCommBreak            (USER.210)
537  */
538 INT16 WINAPI SetCommBreak16(INT16 cid)
539 {
540         struct DosDeviceStruct *ptr;
541
542         TRACE(comm,"cid=%d\n", cid);
543         if ((ptr = GetDeviceStruct(cid)) == NULL) {
544                 return -1;
545         }
546
547         ptr->suspended = 1;
548         ptr->commerror = 0;
549         return 0;
550 }
551
552 /*****************************************************************************
553  *      ClearCommBreak          (USER.211)
554  */
555 INT16 WINAPI ClearCommBreak16(INT16 cid)
556 {
557         struct DosDeviceStruct *ptr;
558
559         TRACE(comm,"cid=%d\n", cid);
560         if ((ptr = GetDeviceStruct(cid)) == NULL) {
561                 return -1;
562         }
563
564         ptr->suspended = 0;
565         ptr->commerror = 0;
566         return 0;
567 }
568
569 /*****************************************************************************
570  *      EscapeCommFunction      (USER.214)
571  */
572 LONG WINAPI EscapeCommFunction16(UINT16 cid,UINT16 nFunction)
573 {
574         int     max;
575         struct DosDeviceStruct *ptr;
576         struct termios port;
577
578         TRACE(comm,"cid=%d, function=%d\n", cid, nFunction);
579         if ((ptr = GetDeviceStruct(cid)) == NULL) {
580                 return -1;
581         }
582         if (tcgetattr(ptr->fd,&port) == -1) {
583                 ptr->commerror=WinError();      
584                 return -1;
585         }
586
587         switch (nFunction) {
588                 case RESETDEV:
589                         break;                                  
590
591                 case GETMAXCOM:
592                         for (max = MAX_PORTS;!COM[max].devicename;max--)
593                                 ;
594                         return max;
595                         break;
596
597                 case GETMAXLPT:
598                         for (max = MAX_PORTS;!LPT[max].devicename;max--)
599                                 ;
600                         return FLAG_LPT + max;
601                         break;
602
603 #ifdef TIOCM_DTR
604                 case CLRDTR:
605                         return COMM_WhackModem(ptr->fd, ~TIOCM_DTR, 0);
606 #endif
607 #ifdef TIOCM_RTS
608                 case CLRRTS:
609                         return COMM_WhackModem(ptr->fd, ~TIOCM_RTS, 0);
610 #endif
611         
612 #ifdef TIOCM_DTR
613                 case SETDTR:
614                         return COMM_WhackModem(ptr->fd, 0, TIOCM_DTR);
615 #endif
616
617 #ifdef TIOCM_RTS                        
618                 case SETRTS:
619                         return COMM_WhackModem(ptr->fd, 0, TIOCM_RTS);
620 #endif
621
622                 case SETXOFF:
623                         port.c_iflag |= IXOFF;
624                         break;
625
626                 case SETXON:
627                         port.c_iflag |= IXON;
628                         break;
629
630                 default:
631                         WARN(comm,"(cid=%d,nFunction=%d): Unknown function\n", 
632                         cid, nFunction);
633                         break;                          
634         }
635         
636         if (tcsetattr(ptr->fd, TCSADRAIN, &port) == -1) {
637                 ptr->commerror = WinError();
638                 return -1;      
639         } else {
640                 ptr->commerror = 0;
641                 return 0;
642         }
643 }
644
645 /*****************************************************************************
646  *      FlushComm       (USER.215)
647  */
648 INT16 WINAPI FlushComm16(INT16 cid,INT16 fnQueue)
649 {
650         int queue;
651         struct DosDeviceStruct *ptr;
652
653         TRACE(comm,"cid=%d, queue=%d\n", cid, fnQueue);
654         if ((ptr = GetDeviceStruct(cid)) == NULL) {
655                 return -1;
656         }
657         switch (fnQueue) {
658                 case 0:
659                   queue = TCOFLUSH;
660                   ptr->obuf_tail = ptr->obuf_head;
661                   break;
662                 case 1:
663                   queue = TCIFLUSH;
664                   ptr->ibuf_head = ptr->ibuf_tail;
665                   break;
666                 default:
667                   WARN(comm,"(cid=%d,fnQueue=%d):Unknown queue\n", 
668                             cid, fnQueue);
669                   return -1;
670                 }
671         if (tcflush(ptr->fd, queue)) {
672                 ptr->commerror = WinError();
673                 return -1;      
674         } else {
675                 ptr->commerror = 0;
676                 return 0;
677         }
678 }  
679
680 /********************************************************************
681  *      GetCommError    (USER.203)
682  */
683 INT16 WINAPI GetCommError16(INT16 cid,LPCOMSTAT16 lpStat)
684 {
685         int             temperror;
686         struct DosDeviceStruct *ptr;
687         unsigned char *stol;
688         unsigned int mstat;
689
690         if ((ptr = GetDeviceStruct(cid)) == NULL) {
691                 return -1;
692         }
693         if (cid&FLAG_LPT) {
694             WARN(comm," cid %d not comm port\n",cid);
695             return CE_MODE;
696         }
697         stol = (unsigned char *)unknown[cid] + COMM_MSR_OFFSET;
698         ioctl(ptr->fd,TIOCMGET,&mstat);
699         if( mstat&TIOCM_CAR ) 
700             *stol |= 0x80;
701         else 
702             *stol &=0x7f;
703
704         if (lpStat) {
705                 lpStat->status = 0;
706
707                 lpStat->cbOutQue = comm_outbuf(ptr);
708                 lpStat->cbInQue = comm_inbuf(ptr);
709
710                 TRACE(comm, "cid %d, error %d, lpStat %d %d %d stol %x\n",
711                              cid, ptr->commerror, lpStat->status, lpStat->cbInQue, 
712                              lpStat->cbOutQue, *stol);
713         }
714         else
715                 TRACE(comm, "cid %d, error %d, lpStat NULL stol %x\n",
716                              cid, ptr->commerror, *stol);
717
718         /* Return any errors and clear it */
719         temperror = ptr->commerror;
720         ptr->commerror = 0;
721         return(temperror);
722 }
723
724 /*****************************************************************************
725  *      SetCommEventMask        (USER.208)
726  */
727 SEGPTR WINAPI SetCommEventMask16(INT16 cid,UINT16 fuEvtMask)
728 {
729         struct DosDeviceStruct *ptr;
730         unsigned char *stol;
731         int repid;
732         unsigned int mstat;
733
734         TRACE(comm,"cid %d,mask %d\n",cid,fuEvtMask);
735         if ((ptr = GetDeviceStruct(cid)) == NULL)
736             return (SEGPTR)NULL;
737
738         ptr->eventmask = fuEvtMask;
739
740         if ((cid&FLAG_LPT) || !ValidCOMPort(cid)) {
741             WARN(comm," cid %d not comm port\n",cid);
742             return (SEGPTR)NULL;
743         }
744         /* it's a COM port ? -> modify flags */
745         stol = (unsigned char *)unknown[cid] + COMM_MSR_OFFSET;
746         repid = ioctl(ptr->fd,TIOCMGET,&mstat);
747         TRACE(comm, " ioctl  %d, msr %x at %p %p\n",repid,mstat,stol,unknown[cid]);
748         if ((mstat&TIOCM_CAR))
749             *stol |= 0x80;
750         else
751             *stol &=0x7f;
752
753         TRACE(comm," modem dcd construct %x\n",*stol);
754         return SEGPTR_GET(unknown[cid]);
755 }
756
757 /*****************************************************************************
758  *      GetCommEventMask        (USER.209)
759  */
760 UINT16 WINAPI GetCommEventMask16(INT16 cid,UINT16 fnEvtClear)
761 {
762         struct DosDeviceStruct *ptr;
763         WORD events;
764
765         TRACE(comm, "cid %d, mask %d\n", cid, fnEvtClear);
766         if ((ptr = GetDeviceStruct(cid)) == NULL)
767             return 0;
768
769         if ((cid&FLAG_LPT) || !ValidCOMPort(cid)) {
770             WARN(comm," cid %d not comm port\n",cid);
771             return 0;
772         }
773
774         events = *(WORD*)(unknown[cid]) & fnEvtClear;
775         *(WORD*)(unknown[cid]) &= ~fnEvtClear;
776         return events;
777 }
778
779 /*****************************************************************************
780  *      SetCommState16  (USER.201)
781  */
782 INT16 WINAPI SetCommState16(LPDCB16 lpdcb)
783 {
784         struct termios port;
785         struct DosDeviceStruct *ptr;
786
787         TRACE(comm, "cid %d, ptr %p\n", lpdcb->Id, lpdcb);
788         if ((ptr = GetDeviceStruct(lpdcb->Id)) == NULL) {
789                 return -1;
790         }
791         if (tcgetattr(ptr->fd, &port) == -1) {
792                 ptr->commerror = WinError();    
793                 return -1;
794         }
795
796         port.c_cc[VMIN] = 0;
797         port.c_cc[VTIME] = 1;
798
799 #ifdef IMAXBEL
800         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|IMAXBEL);
801 #else
802         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR);
803 #endif
804         port.c_iflag |= (IGNBRK);
805
806         port.c_oflag &= ~(OPOST);
807
808         port.c_cflag &= ~(HUPCL);
809         port.c_cflag |= CLOCAL | CREAD;
810
811         port.c_lflag &= ~(ICANON|ECHO|ISIG);
812         port.c_lflag |= NOFLSH;
813
814         TRACE(comm,"baudrate %d\n",lpdcb->BaudRate);
815 #ifdef CBAUD
816         port.c_cflag &= ~CBAUD;
817         switch (lpdcb->BaudRate) {
818                 case 110:
819                 case CBR_110:
820                         port.c_cflag |= B110;
821                         break;          
822                 case 300:
823                 case CBR_300:
824                         port.c_cflag |= B300;
825                         break;          
826                 case 600:
827                 case CBR_600:
828                         port.c_cflag |= B600;
829                         break;          
830                 case 1200:
831                 case CBR_1200:
832                         port.c_cflag |= B1200;
833                         break;          
834                 case 2400:
835                 case CBR_2400:
836                         port.c_cflag |= B2400;
837                         break;          
838                 case 4800:
839                 case CBR_4800:
840                         port.c_cflag |= B4800;
841                         break;          
842                 case 9600:
843                 case CBR_9600:
844                         port.c_cflag |= B9600;
845                         break;          
846                 case 19200:
847                 case CBR_19200:
848                         port.c_cflag |= B19200;
849                         break;          
850                 case 38400:
851                 case CBR_38400:
852                         port.c_cflag |= B38400;
853                         break;          
854 #ifdef B57600
855                 case 57600:
856                         port.c_cflag |= B57600;
857                         break;          
858 #endif
859 #ifdef B115200
860                 case 57601:
861                         port.c_cflag |= B115200;
862                         break;          
863 #endif
864                 default:
865                         ptr->commerror = IE_BAUDRATE;
866                         return -1;
867         }
868 #elif !defined(__EMX__)
869         switch (lpdcb->BaudRate) {
870                 case 110:
871                 case CBR_110:
872                         port.c_ospeed = B110;
873                         break;
874                 case 300:
875                 case CBR_300:
876                         port.c_ospeed = B300;
877                         break;
878                 case 600:
879                 case CBR_600:
880                         port.c_ospeed = B600;
881                         break;
882                 case 1200:
883                 case CBR_1200:
884                         port.c_ospeed = B1200;
885                         break;
886                 case 2400:
887                 case CBR_2400:
888                         port.c_ospeed = B2400;
889                         break;
890                 case 4800:
891                 case CBR_4800:
892                         port.c_ospeed = B4800;
893                         break;
894                 case 9600:
895                 case CBR_9600:
896                         port.c_ospeed = B9600;
897                         break;
898                 case 19200:
899                 case CBR_19200:
900                         port.c_ospeed = B19200;
901                         break;
902                 case 38400:
903                 case CBR_38400:
904                         port.c_ospeed = B38400;
905                         break;
906                 default:
907                         ptr->commerror = IE_BAUDRATE;
908                         return -1;
909         }
910         port.c_ispeed = port.c_ospeed;
911 #endif
912         TRACE(comm,"bytesize %d\n",lpdcb->ByteSize);
913         port.c_cflag &= ~CSIZE;
914         switch (lpdcb->ByteSize) {
915                 case 5:
916                         port.c_cflag |= CS5;
917                         break;
918                 case 6:
919                         port.c_cflag |= CS6;
920                         break;
921                 case 7:
922                         port.c_cflag |= CS7;
923                         break;
924                 case 8:
925                         port.c_cflag |= CS8;
926                         break;
927                 default:
928                         ptr->commerror = IE_BYTESIZE;
929                         return -1;
930         }
931
932         TRACE(comm,"fParity %d Parity %d\n",lpdcb->fParity, lpdcb->Parity);
933         port.c_cflag &= ~(PARENB | PARODD);
934         if (lpdcb->fParity)
935             port.c_iflag |= INPCK;
936         else
937             port.c_iflag &= ~INPCK;
938         switch (lpdcb->Parity) {
939                 case NOPARITY:
940                         break;
941                 case ODDPARITY:
942                         port.c_cflag |= (PARENB | PARODD);
943                         break;
944                 case EVENPARITY:
945                         port.c_cflag |= PARENB;
946                         break;
947                 default:
948                         ptr->commerror = IE_BYTESIZE;
949                         return -1;
950         }
951         
952
953         TRACE(comm,"stopbits %d\n",lpdcb->StopBits);
954
955         switch (lpdcb->StopBits) {
956                 case ONESTOPBIT:
957                                 port.c_cflag &= ~CSTOPB;
958                                 break;
959                 case TWOSTOPBITS:
960                                 port.c_cflag |= CSTOPB;
961                                 break;
962                 default:
963                         ptr->commerror = IE_BYTESIZE;
964                         return -1;
965         }
966 #ifdef CRTSCTS
967
968         if (lpdcb->fDtrflow || lpdcb->fRtsflow || lpdcb->fOutxCtsFlow)
969                 port.c_cflag |= CRTSCTS;
970
971         if (lpdcb->fDtrDisable) 
972                 port.c_cflag &= ~CRTSCTS;
973 #endif  
974         if (lpdcb->fInX)
975                 port.c_iflag |= IXON;
976         else
977                 port.c_iflag &= ~IXON;
978         if (lpdcb->fOutX)
979                 port.c_iflag |= IXOFF;
980         else
981                 port.c_iflag &= ~IXOFF;
982
983         ptr->evtchar = lpdcb->EvtChar;
984
985         if (tcsetattr(ptr->fd, TCSADRAIN, &port) == -1) {
986                 ptr->commerror = WinError();    
987                 return FALSE;
988         } else {
989                 ptr->commerror = 0;
990                 return 0;
991         }
992 }
993
994 /*****************************************************************************
995  *      GetCommState    (USER.202)
996  */
997 INT16 WINAPI GetCommState16(INT16 cid, LPDCB16 lpdcb)
998 {
999         struct DosDeviceStruct *ptr;
1000         struct termios port;
1001
1002         TRACE(comm,"cid %d, ptr %p\n", cid, lpdcb);
1003         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1004                 return -1;
1005         }
1006         if (tcgetattr(ptr->fd, &port) == -1) {
1007                 ptr->commerror = WinError();    
1008                 return -1;
1009         }
1010         lpdcb->Id = cid;
1011 #ifndef __EMX__
1012 #ifdef CBAUD
1013         switch (port.c_cflag & CBAUD) {
1014 #else
1015         switch (port.c_ospeed) {
1016 #endif
1017                 case B110:
1018                         lpdcb->BaudRate = 110;
1019                         break;
1020                 case B300:
1021                         lpdcb->BaudRate = 300;
1022                         break;
1023                 case B600:
1024                         lpdcb->BaudRate = 600;
1025                         break;
1026                 case B1200:
1027                         lpdcb->BaudRate = 1200;
1028                         break;
1029                 case B2400:
1030                         lpdcb->BaudRate = 2400;
1031                         break;
1032                 case B4800:
1033                         lpdcb->BaudRate = 4800;
1034                         break;
1035                 case B9600:
1036                         lpdcb->BaudRate = 9600;
1037                         break;
1038                 case B19200:
1039                         lpdcb->BaudRate = 19200;
1040                         break;
1041                 case B38400:
1042                         lpdcb->BaudRate = 38400;
1043                         break;
1044 #ifdef B57600
1045                 case B57600:
1046                         lpdcb->BaudRate = 57600;
1047                         break;
1048 #endif
1049 #ifdef B115200
1050                 case B115200:
1051                         lpdcb->BaudRate = 57601;
1052                         break;
1053 #endif
1054         }
1055 #endif
1056         switch (port.c_cflag & CSIZE) {
1057                 case CS5:
1058                         lpdcb->ByteSize = 5;
1059                         break;
1060                 case CS6:
1061                         lpdcb->ByteSize = 6;
1062                         break;
1063                 case CS7:
1064                         lpdcb->ByteSize = 7;
1065                         break;
1066                 case CS8:
1067                         lpdcb->ByteSize = 8;
1068                         break;
1069         }       
1070         
1071         if(port.c_iflag & INPCK)
1072             lpdcb->fParity = TRUE;
1073         else
1074             lpdcb->fParity = FALSE;
1075         switch (port.c_cflag & (PARENB | PARODD)) {
1076                 case 0:
1077                         lpdcb->Parity = NOPARITY;
1078                         break;
1079                 case PARENB:
1080                         lpdcb->Parity = EVENPARITY;
1081                         break;
1082                 case (PARENB | PARODD):
1083                         lpdcb->Parity = ODDPARITY;              
1084                         break;
1085         }
1086
1087         if (port.c_cflag & CSTOPB)
1088                 lpdcb->StopBits = TWOSTOPBITS;
1089         else
1090                 lpdcb->StopBits = ONESTOPBIT;
1091
1092         lpdcb->RlsTimeout = 50;
1093         lpdcb->CtsTimeout = 50; 
1094         lpdcb->DsrTimeout = 50;
1095         lpdcb->fNull = 0;
1096         lpdcb->fChEvt = 0;
1097         lpdcb->fBinary = 1;
1098         lpdcb->fDtrDisable = 0;
1099
1100 #ifdef CRTSCTS
1101
1102         if (port.c_cflag & CRTSCTS) {
1103                 lpdcb->fDtrflow = 1;
1104                 lpdcb->fRtsflow = 1;
1105                 lpdcb->fOutxCtsFlow = 1;
1106                 lpdcb->fOutxDsrFlow = 1;
1107         } else 
1108 #endif
1109                 lpdcb->fDtrDisable = 1;
1110
1111         if (port.c_iflag & IXON)
1112                 lpdcb->fInX = 1;
1113         else
1114                 lpdcb->fInX = 0;
1115
1116         if (port.c_iflag & IXOFF)
1117                 lpdcb->fOutX = 1;
1118         else
1119                 lpdcb->fOutX = 0;
1120 /*
1121         lpdcb->XonChar = 
1122         lpdcb->XoffChar = 
1123  */
1124         lpdcb->XonLim = 10;
1125         lpdcb->XoffLim = 10;
1126
1127         lpdcb->EvtChar = ptr->evtchar;
1128
1129         ptr->commerror = 0;
1130         return 0;
1131 }
1132
1133 /*****************************************************************************
1134  *      TransmitCommChar        (USER.206)
1135  */
1136 INT16 WINAPI TransmitCommChar16(INT16 cid,CHAR chTransmit)
1137 {
1138         struct DosDeviceStruct *ptr;
1139
1140         TRACE(comm, "cid %d, data %d \n", cid, chTransmit);
1141         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1142                 return -1;
1143         }
1144
1145         if (ptr->suspended) {
1146                 ptr->commerror = IE_HARDWARE;
1147                 return -1;
1148         }       
1149
1150         if (ptr->xmit >= 0) {
1151           /* character already queued */
1152           /* FIXME: which error would Windows return? */
1153           ptr->commerror = CE_TXFULL;
1154           return -1;
1155         }
1156
1157         if (ptr->obuf_head == ptr->obuf_tail) {
1158           /* transmit queue empty, try to transmit directly */
1159           if (write(ptr->fd, &chTransmit, 1) == -1) {
1160             /* didn't work, queue it */
1161             ptr->xmit = chTransmit;
1162           }
1163         } else {
1164           /* data in queue, let this char be transmitted next */
1165           ptr->xmit = chTransmit;
1166         }
1167
1168         ptr->commerror = 0;
1169         return 0;
1170 }
1171
1172 /*****************************************************************************
1173  *      UngetCommChar   (USER.212)
1174  */
1175 INT16 WINAPI UngetCommChar16(INT16 cid,CHAR chUnget)
1176 {
1177         struct DosDeviceStruct *ptr;
1178
1179         TRACE(comm,"cid %d (char %d)\n", cid, chUnget);
1180         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1181                 return -1;
1182         }
1183
1184         if (ptr->suspended) {
1185                 ptr->commerror = IE_HARDWARE;
1186                 return -1;
1187         }       
1188
1189         if (ptr->unget>=0) {
1190           /* character already queued */
1191           /* FIXME: which error would Windows return? */
1192           ptr->commerror = CE_RXOVER;
1193           return -1;
1194         }
1195
1196         ptr->unget = chUnget;
1197
1198         ptr->commerror = 0;
1199         return 0;
1200 }
1201
1202 /*****************************************************************************
1203  *      ReadComm        (USER.204)
1204  */
1205 INT16 WINAPI ReadComm16(INT16 cid,LPSTR lpvBuf,INT16 cbRead)
1206 {
1207         int status, length;
1208         struct DosDeviceStruct *ptr;
1209         LPSTR orgBuf = lpvBuf;
1210
1211         TRACE(comm, "cid %d, ptr %p, length %d\n", cid, lpvBuf, cbRead);
1212         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1213                 return -1;
1214         }
1215
1216         if (ptr->suspended) {
1217                 ptr->commerror = IE_HARDWARE;
1218                 return -1;
1219         }       
1220
1221         /* read unget character */
1222         if (ptr->unget>=0) {
1223                 *lpvBuf++ = ptr->unget;
1224                 ptr->unget = -1;
1225
1226                 length = 1;
1227         } else
1228                 length = 0;
1229
1230         /* read from receive buffer */
1231         while (length < cbRead) {
1232           status = ((ptr->ibuf_head < ptr->ibuf_tail) ?
1233                     ptr->ibuf_size : ptr->ibuf_head) - ptr->ibuf_tail;
1234           if (!status) break;
1235           if ((cbRead - length) < status)
1236             status = cbRead - length;
1237
1238           memcpy(lpvBuf, ptr->inbuf + ptr->ibuf_tail, status);
1239           ptr->ibuf_tail += status;
1240           if (ptr->ibuf_tail >= ptr->ibuf_size)
1241             ptr->ibuf_tail = 0;
1242           lpvBuf += status;
1243           length += status;
1244         }
1245
1246         TRACE(comm,"%.*s\n", length, orgBuf);
1247         ptr->commerror = 0;
1248         return length;
1249 }
1250
1251 /*****************************************************************************
1252  *      WriteComm       (USER.205)
1253  */
1254 INT16 WINAPI WriteComm16(INT16 cid, LPSTR lpvBuf, INT16 cbWrite)
1255 {
1256         int status, length;
1257         struct DosDeviceStruct *ptr;
1258
1259         TRACE(comm,"cid %d, ptr %p, length %d\n", 
1260                 cid, lpvBuf, cbWrite);
1261         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1262                 return -1;
1263         }
1264
1265         if (ptr->suspended) {
1266                 ptr->commerror = IE_HARDWARE;
1267                 return -1;
1268         }       
1269         
1270         TRACE(comm,"%.*s\n", cbWrite, lpvBuf );
1271
1272         length = 0;
1273         while (length < cbWrite) {
1274           if ((ptr->obuf_head == ptr->obuf_tail) && (ptr->xmit < 0)) {
1275             /* no data queued, try to write directly */
1276             status = write(ptr->fd, lpvBuf, cbWrite - length);
1277             if (status > 0) {
1278               lpvBuf += status;
1279               length += status;
1280               continue;
1281             }
1282           }
1283           /* can't write directly, put into transmit buffer */
1284           status = ((ptr->obuf_tail > ptr->obuf_head) ?
1285                     (ptr->obuf_tail-1) : ptr->obuf_size) - ptr->obuf_head;
1286           if (!status) break;
1287           if ((cbWrite - length) < status)
1288             status = cbWrite - length;
1289           memcpy(lpvBuf, ptr->outbuf + ptr->obuf_head, status);
1290           ptr->obuf_head += status;
1291           if (ptr->obuf_head >= ptr->obuf_size)
1292             ptr->obuf_head = 0;
1293           lpvBuf += status;
1294           length += status;
1295         }
1296
1297         ptr->commerror = 0;     
1298         return length;
1299 }
1300
1301 /***********************************************************************
1302  *           EnableCommNotification   (USER.246)
1303  */
1304 BOOL16 WINAPI EnableCommNotification16( INT16 cid, HWND16 hwnd,
1305                                       INT16 cbWriteNotify, INT16 cbOutQueue )
1306 {
1307         struct DosDeviceStruct *ptr;
1308
1309         TRACE(comm, "(%d, %x, %d, %d)\n", cid, hwnd, cbWriteNotify, cbOutQueue);
1310         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1311                 ptr->commerror = IE_BADID;
1312                 return -1;
1313         }
1314         ptr->wnd = hwnd;
1315         ptr->n_read = cbWriteNotify;
1316         ptr->n_write = cbOutQueue;
1317         return TRUE;
1318 }
1319
1320
1321 /**************************************************************************
1322  *         BuildCommDCBA                (KERNEL32.14)
1323  */
1324 BOOL WINAPI BuildCommDCBA(LPCSTR device,LPDCB lpdcb)
1325 {
1326         return BuildCommDCBAndTimeoutsA(device,lpdcb,NULL);
1327 }
1328
1329 /**************************************************************************
1330  *         BuildCommDCBAndTimeoutsA     (KERNEL32.15)
1331  */
1332 BOOL WINAPI BuildCommDCBAndTimeoutsA(LPCSTR device, LPDCB lpdcb,
1333                                          LPCOMMTIMEOUTS lptimeouts)
1334 {
1335         int     port;
1336         char    *ptr,*temp;
1337
1338         TRACE(comm,"(%s,%p,%p)\n",device,lpdcb,lptimeouts);
1339
1340         if (!lstrncmpiA(device,"COM",3)) {
1341                 port=device[3]-'0';
1342                 if (port--==0) {
1343                         ERR(comm,"BUG! COM0 can't exists!.\n");
1344                         return FALSE;
1345                 }
1346                 if (!ValidCOMPort(port))
1347                         return FALSE;
1348                 if (*(device+4)!=':')
1349                         return FALSE;
1350                 temp=(LPSTR)(device+5);
1351         } else
1352                 temp=(LPSTR)device;
1353
1354         memset(lpdcb, 0, sizeof(DCB)); /* initialize */
1355
1356         lpdcb->DCBlength        = sizeof(DCB);
1357         if (strchr(temp,',')) { /* old style */
1358                 DCB16   dcb16;
1359                 BOOL16  ret;
1360                 char    last=temp[strlen(temp)-1];
1361
1362                 ret=BuildCommDCB16(device,&dcb16);
1363                 if (!ret)
1364                         return FALSE;
1365                 lpdcb->BaudRate         = dcb16.BaudRate;
1366                 lpdcb->ByteSize         = dcb16.ByteSize;
1367                 lpdcb->fBinary          = dcb16.fBinary;
1368                 lpdcb->Parity           = dcb16.Parity;
1369                 lpdcb->fParity          = dcb16.fParity;
1370                 lpdcb->fNull            = dcb16.fNull;
1371                 lpdcb->StopBits         = dcb16.StopBits;
1372                 if (last == 'x') {
1373                         lpdcb->fInX             = TRUE;
1374                         lpdcb->fOutX            = TRUE;
1375                         lpdcb->fOutxCtsFlow     = FALSE;
1376                         lpdcb->fOutxDsrFlow     = FALSE;
1377                         lpdcb->fDtrControl      = DTR_CONTROL_ENABLE;
1378                         lpdcb->fRtsControl      = RTS_CONTROL_ENABLE;
1379                 } else if (last=='p') {
1380                         lpdcb->fInX             = FALSE;
1381                         lpdcb->fOutX            = FALSE;
1382                         lpdcb->fOutxCtsFlow     = TRUE;
1383                         lpdcb->fOutxDsrFlow     = TRUE;
1384                         lpdcb->fDtrControl      = DTR_CONTROL_HANDSHAKE;
1385                         lpdcb->fRtsControl      = RTS_CONTROL_HANDSHAKE;
1386                 } else {
1387                         lpdcb->fInX             = FALSE;
1388                         lpdcb->fOutX            = FALSE;
1389                         lpdcb->fOutxCtsFlow     = FALSE;
1390                         lpdcb->fOutxDsrFlow     = FALSE;
1391                         lpdcb->fDtrControl      = DTR_CONTROL_ENABLE;
1392                         lpdcb->fRtsControl      = RTS_CONTROL_ENABLE;
1393                 }
1394                 lpdcb->XonChar  = dcb16.XonChar;
1395                 lpdcb->XoffChar = dcb16.XoffChar;
1396                 lpdcb->ErrorChar= dcb16.PeChar;
1397                 lpdcb->fErrorChar= dcb16.fPeChar;
1398                 lpdcb->EofChar  = dcb16.EofChar;
1399                 lpdcb->EvtChar  = dcb16.EvtChar;
1400                 lpdcb->XonLim   = dcb16.XonLim;
1401                 lpdcb->XoffLim  = dcb16.XoffLim;
1402                 return TRUE;
1403         }
1404         ptr=strtok(temp," "); 
1405         while (ptr) {
1406                 DWORD   flag,x;
1407
1408                 flag=0;
1409                 if (!strncmp("baud=",ptr,5)) {
1410                         if (!sscanf(ptr+5,"%ld",&x))
1411                                 WARN(comm,"Couldn't parse %s\n",ptr);
1412                         lpdcb->BaudRate = x;
1413                         flag=1;
1414                 }
1415                 if (!strncmp("stop=",ptr,5)) {
1416                         if (!sscanf(ptr+5,"%ld",&x))
1417                                 WARN(comm,"Couldn't parse %s\n",ptr);
1418                         lpdcb->StopBits = x;
1419                         flag=1;
1420                 }
1421                 if (!strncmp("data=",ptr,5)) {
1422                         if (!sscanf(ptr+5,"%ld",&x))
1423                                 WARN(comm,"Couldn't parse %s\n",ptr);
1424                         lpdcb->ByteSize = x;
1425                         flag=1;
1426                 }
1427                 if (!strncmp("parity=",ptr,7)) {
1428                         lpdcb->fParity  = TRUE;
1429                         switch (ptr[8]) {
1430                         case 'N':case 'n':
1431                                 lpdcb->fParity  = FALSE;
1432                                 lpdcb->Parity   = NOPARITY;
1433                                 break;
1434                         case 'E':case 'e':
1435                                 lpdcb->Parity   = EVENPARITY;
1436                                 break;
1437                         case 'O':case 'o':
1438                                 lpdcb->Parity   = ODDPARITY;
1439                                 break;
1440                         case 'M':case 'm':
1441                                 lpdcb->Parity   = MARKPARITY;
1442                                 break;
1443                         }
1444                         flag=1;
1445                 }
1446                 if (!flag)
1447                         ERR(comm,"Unhandled specifier '%s', please report.\n",ptr);
1448                 ptr=strtok(NULL," ");
1449         }
1450         if (lpdcb->BaudRate==110)
1451                 lpdcb->StopBits = 2;
1452         return TRUE;
1453 }
1454
1455 /**************************************************************************
1456  *         BuildCommDCBAndTimeoutsW             (KERNEL32.16)
1457  */
1458 BOOL WINAPI BuildCommDCBAndTimeoutsW( LPCWSTR devid, LPDCB lpdcb,
1459                                           LPCOMMTIMEOUTS lptimeouts )
1460 {
1461         LPSTR   devidA;
1462         BOOL    ret;
1463
1464         TRACE(comm,"(%p,%p,%p)\n",devid,lpdcb,lptimeouts);
1465         devidA = HEAP_strdupWtoA( GetProcessHeap(), 0, devid );
1466         ret=BuildCommDCBAndTimeoutsA(devidA,lpdcb,lptimeouts);
1467         HeapFree( GetProcessHeap(), 0, devidA );
1468         return ret;
1469 }
1470
1471 /**************************************************************************
1472  *         BuildCommDCBW                (KERNEL32.17)
1473  */
1474 BOOL WINAPI BuildCommDCBW(LPCWSTR devid,LPDCB lpdcb)
1475 {
1476         return BuildCommDCBAndTimeoutsW(devid,lpdcb,NULL);
1477 }
1478
1479 /*****************************************************************************
1480  *      COMM_Handle2fd
1481  *  returns a file descriptor for reading from or writing to
1482  *  mode is GENERIC_READ or GENERIC_WRITE. Make sure to close
1483  *  the handle afterwards!
1484  */
1485 int COMM_Handle2fd(HANDLE handle, int mode) {
1486     struct get_read_fd_request r_req;
1487     struct get_write_fd_request w_req;
1488     int fd;
1489
1490     w_req.handle = r_req.handle = handle;
1491
1492     switch(mode) {
1493     case GENERIC_WRITE:
1494         CLIENT_SendRequest( REQ_GET_WRITE_FD, -1, 1, &w_req, sizeof(w_req) );
1495         break;
1496     case GENERIC_READ:
1497         CLIENT_SendRequest( REQ_GET_READ_FD, -1, 1, &r_req, sizeof(r_req) );
1498         break;
1499     default:
1500         ERR(comm,"COMM_Handle2fd: Don't know what type of fd is required.\n");
1501         return -1;
1502     }
1503     CLIENT_WaitReply( NULL, &fd, 0 );
1504
1505     return fd;
1506 }
1507
1508 /* FIXME: having these global for win32 for now */
1509 int commerror=0,eventmask=0;
1510
1511 /*****************************************************************************
1512  *      SetCommBreak            (KERNEL32.449)
1513  */
1514 BOOL WINAPI SetCommBreak(HANDLE handle)
1515 {
1516         FIXME(comm,"handle %d, stub!\n", handle);
1517         return TRUE;
1518 }
1519
1520 /*****************************************************************************
1521  *      ClearCommBreak          (KERNEL32.20)
1522  */
1523 BOOL WINAPI ClearCommBreak(HANDLE handle)
1524 {
1525         FIXME(comm,"handle %d, stub!\n", handle);
1526         return TRUE;
1527 }
1528
1529 /*****************************************************************************
1530  *      EscapeCommFunction      (KERNEL32.214)
1531  */
1532 BOOL WINAPI EscapeCommFunction(HANDLE handle,UINT nFunction)
1533 {
1534         int fd;
1535         struct termios  port;
1536
1537         TRACE(comm,"handle %d, function=%d\n", handle, nFunction);
1538         fd = COMM_Handle2fd(handle, GENERIC_WRITE);
1539         if(fd<0)
1540                 return FALSE;
1541
1542         if (tcgetattr(fd,&port) == -1) {
1543                 commerror=WinError();
1544                 close(fd);
1545                 return FALSE;
1546         }
1547
1548         switch (nFunction) {
1549                 case RESETDEV:
1550                         break;                                  
1551
1552 #ifdef TIOCM_DTR
1553                 case CLRDTR:
1554                         port.c_cflag &= TIOCM_DTR;
1555                         break;
1556 #endif
1557
1558 #ifdef TIOCM_RTS
1559                 case CLRRTS:
1560                         port.c_cflag &= TIOCM_RTS;
1561                         break;
1562 #endif
1563         
1564 #ifdef CRTSCTS
1565                 case SETDTR:
1566                         port.c_cflag |= CRTSCTS;
1567                         break;
1568
1569                 case SETRTS:
1570                         port.c_cflag |= CRTSCTS;
1571                         break;
1572 #endif
1573
1574                 case SETXOFF:
1575                         port.c_iflag |= IXOFF;
1576                         break;
1577
1578                 case SETXON:
1579                         port.c_iflag |= IXON;
1580                         break;
1581                 case SETBREAK:
1582                         FIXME(comm,"setbreak, stub\n");
1583 /*                      ptr->suspended = 1; */
1584                         break;
1585                 case CLRBREAK:
1586                         FIXME(comm,"clrbreak, stub\n");
1587 /*                      ptr->suspended = 0; */
1588                         break;
1589                 default:
1590                         WARN(comm,"(handle=%d,nFunction=%d): Unknown function\n", 
1591                         handle, nFunction);
1592                         break;                          
1593         }
1594         
1595         if (tcsetattr(fd, TCSADRAIN, &port) == -1) {
1596                 commerror = WinError();
1597                 close(fd);
1598                 return FALSE;   
1599         } else {
1600                 commerror = 0;
1601                 close(fd);
1602                 return TRUE;
1603         }
1604 }
1605
1606 /********************************************************************
1607  *      PurgeComm        (KERNEL32.557)
1608  */
1609 BOOL WINAPI PurgeComm( HANDLE handle, DWORD flags) 
1610 {
1611      int fd;
1612
1613      TRACE(comm,"handle %d, flags %lx\n", handle, flags);
1614
1615      fd = COMM_Handle2fd(handle, GENERIC_WRITE);
1616      if(fd<0)
1617          return FALSE;
1618
1619      /*
1620      ** not exactly sure how these are different
1621      ** Perhaps if we had our own internal queues, one flushes them
1622      ** and the other flushes the kernel's buffers.
1623      */
1624      if(flags&PURGE_TXABORT)
1625      {
1626          tcflush(fd,TCOFLUSH);
1627      }
1628      if(flags&PURGE_RXABORT)
1629      {
1630          tcflush(fd,TCIFLUSH);
1631      }
1632      if(flags&PURGE_TXCLEAR)
1633      {
1634          tcflush(fd,TCOFLUSH);
1635      }
1636      if(flags&PURGE_RXCLEAR)
1637      {
1638          tcflush(fd,TCIFLUSH);
1639      }
1640      close(fd);
1641
1642      return 1;
1643 }
1644
1645 /*****************************************************************************
1646  *      ClearCommError  (KERNEL32.21)
1647  */
1648 BOOL WINAPI ClearCommError(INT handle,LPDWORD errors,LPCOMSTAT lpStat)
1649 {
1650     int fd;
1651
1652     fd=COMM_Handle2fd(handle,GENERIC_READ);
1653     if(0>fd) 
1654     {
1655         return FALSE;
1656     }
1657
1658     if (lpStat) 
1659     {
1660         lpStat->status = 0;
1661
1662         if(ioctl(fd, TIOCOUTQ, &lpStat->cbOutQue))
1663             WARN(comm, "ioctl returned error\n");
1664
1665         if(ioctl(fd, TIOCINQ, &lpStat->cbInQue))
1666             WARN(comm, "ioctl returned error\n");
1667     }
1668
1669     close(fd);
1670
1671     TRACE(comm,"handle %d cbInQue = %ld cbOutQue = %ld\n",
1672                 handle,
1673                 lpStat->cbInQue,
1674                 lpStat->cbOutQue);
1675
1676     if(errors)
1677         *errors = 0;
1678
1679     /*
1680     ** After an asynchronous write opperation, the
1681     ** app will call ClearCommError to see if the
1682     ** results are ready yet. It waits for ERROR_IO_PENDING
1683     */
1684     commerror = ERROR_IO_PENDING;
1685
1686     return TRUE;
1687 }
1688
1689 /*****************************************************************************
1690  *      SetupComm       (KERNEL32.676)
1691  */
1692 BOOL WINAPI SetupComm( HANDLE handle, DWORD insize, DWORD outsize)
1693 {
1694     int fd;
1695
1696     FIXME(comm, "insize %ld outsize %ld unimplemented stub\n", insize, outsize);
1697     fd=COMM_Handle2fd(handle,GENERIC_WRITE);
1698     if(0>fd)
1699     {
1700         return FALSE;
1701     }
1702     close(fd);
1703     return TRUE;
1704
1705
1706 /*****************************************************************************
1707  *      GetCommMask     (KERNEL32.156)
1708  */
1709 BOOL WINAPI GetCommMask(HANDLE handle,LPDWORD evtmask)
1710 {
1711     int fd;
1712
1713     TRACE(comm, "handle %d, mask %p\n", handle, evtmask);
1714     if(0>(fd=COMM_Handle2fd(handle,GENERIC_READ))) 
1715     {
1716         return FALSE;
1717     }
1718     close(fd);
1719     *evtmask = eventmask;
1720     return TRUE;
1721 }
1722
1723 /*****************************************************************************
1724  *      SetCommMask     (KERNEL32.451)
1725  */
1726 BOOL WINAPI SetCommMask(INT handle,DWORD evtmask)
1727 {
1728     int fd;
1729
1730     TRACE(comm, "handle %d, mask %lx\n", handle, evtmask);
1731     if(0>(fd=COMM_Handle2fd(handle,GENERIC_WRITE))) {
1732         return FALSE;
1733     }
1734     close(fd);
1735     eventmask = evtmask;
1736     return TRUE;
1737 }
1738
1739 /*****************************************************************************
1740  *      SetCommState    (KERNEL32.452)
1741  */
1742 BOOL WINAPI SetCommState(INT handle,LPDCB lpdcb)
1743 {
1744      struct termios port;
1745      int fd;
1746      struct get_write_fd_request req;
1747
1748      TRACE(comm,"handle %d, ptr %p\n", handle, lpdcb);
1749
1750      req.handle = handle;
1751      CLIENT_SendRequest( REQ_GET_WRITE_FD, -1, 1, &req, sizeof(req) );
1752      CLIENT_WaitReply( NULL, &fd, 0 );
1753
1754      if(fd<0)
1755          return FALSE;
1756
1757      if (tcgetattr(fd,&port) == -1) {
1758          commerror = WinError();        
1759          return FALSE;
1760      }
1761
1762         port.c_cc[VMIN] = 0;
1763         port.c_cc[VTIME] = 1;
1764
1765 #ifdef IMAXBEL
1766         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|IMAXBEL);
1767 #else
1768         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR);
1769 #endif
1770         port.c_iflag |= (IGNBRK);
1771
1772         port.c_oflag &= ~(OPOST);
1773
1774         port.c_cflag &= ~(HUPCL);
1775         port.c_cflag |= CLOCAL | CREAD;
1776
1777         port.c_lflag &= ~(ICANON|ECHO|ISIG);
1778         port.c_lflag |= NOFLSH;
1779
1780      /*
1781      ** MJM - removed default baudrate settings
1782      ** TRACE(comm,"baudrate %ld\n",lpdcb->BaudRate);
1783      */
1784 #ifdef CBAUD
1785         port.c_cflag &= ~CBAUD;
1786         switch (lpdcb->BaudRate) {
1787                 case 110:
1788                 case CBR_110:
1789                         port.c_cflag |= B110;
1790                         break;          
1791                 case 300:
1792                 case CBR_300:
1793                         port.c_cflag |= B300;
1794                         break;          
1795                 case 600:
1796                 case CBR_600:
1797                         port.c_cflag |= B600;
1798                         break;          
1799                 case 1200:
1800                 case CBR_1200:
1801                         port.c_cflag |= B1200;
1802                         break;          
1803                 case 2400:
1804                 case CBR_2400:
1805                         port.c_cflag |= B2400;
1806                         break;          
1807                 case 4800:
1808                 case CBR_4800:
1809                         port.c_cflag |= B4800;
1810                         break;          
1811                 case 9600:
1812                 case CBR_9600:
1813                         port.c_cflag |= B9600;
1814                         break;          
1815                 case 19200:
1816                 case CBR_19200:
1817                         port.c_cflag |= B19200;
1818                         break;          
1819                 case 38400:
1820                 case CBR_38400:
1821                         port.c_cflag |= B38400;
1822                         break;          
1823                 default:
1824                         commerror = IE_BAUDRATE;
1825                         return FALSE;
1826         }
1827 #elif !defined(__EMX__)
1828         switch (lpdcb->BaudRate) {
1829                 case 110:
1830                 case CBR_110:
1831                         port.c_ospeed = B110;
1832                         break;
1833                 case 300:
1834                 case CBR_300:
1835                         port.c_ospeed = B300;
1836                         break;
1837                 case 600:
1838                 case CBR_600:
1839                         port.c_ospeed = B600;
1840                         break;
1841                 case 1200:
1842                 case CBR_1200:
1843                         port.c_ospeed = B1200;
1844                         break;
1845                 case 2400:
1846                 case CBR_2400:
1847                         port.c_ospeed = B2400;
1848                         break;
1849                 case 4800:
1850                 case CBR_4800:
1851                         port.c_ospeed = B4800;
1852                         break;
1853                 case 9600:
1854                 case CBR_9600:
1855                         port.c_ospeed = B9600;
1856                         break;
1857                 case 19200:
1858                 case CBR_19200:
1859                         port.c_ospeed = B19200;
1860                         break;
1861                 case 38400:
1862                 case CBR_38400:
1863                         port.c_ospeed = B38400;
1864                         break;
1865                 default:
1866                         commerror = IE_BAUDRATE;
1867                         return FALSE;
1868         }
1869         port.c_ispeed = port.c_ospeed;
1870 #endif
1871         TRACE(comm,"bytesize %d\n",lpdcb->ByteSize);
1872         port.c_cflag &= ~CSIZE;
1873         switch (lpdcb->ByteSize) {
1874                 case 5:
1875                         port.c_cflag |= CS5;
1876                         break;
1877                 case 6:
1878                         port.c_cflag |= CS6;
1879                         break;
1880                 case 7:
1881                         port.c_cflag |= CS7;
1882                         break;
1883                 case 8:
1884                         port.c_cflag |= CS8;
1885                         break;
1886                 default:
1887                         commerror = IE_BYTESIZE;
1888                         return FALSE;
1889         }
1890
1891         TRACE(comm,"fParity %d Parity %d\n",lpdcb->fParity, lpdcb->Parity);
1892         port.c_cflag &= ~(PARENB | PARODD);
1893         if (lpdcb->fParity)
1894             port.c_iflag |= INPCK;
1895         else
1896             port.c_iflag &= ~INPCK;
1897         switch (lpdcb->Parity) {
1898                 case NOPARITY:
1899                         break;
1900                 case ODDPARITY:
1901                         port.c_cflag |= (PARENB | PARODD);
1902                         break;
1903                 case EVENPARITY:
1904                         port.c_cflag |= PARENB;
1905                         break;
1906                 default:
1907                         commerror = IE_BYTESIZE;
1908                         return FALSE;
1909         }
1910         
1911
1912         TRACE(comm,"stopbits %d\n",lpdcb->StopBits);
1913         switch (lpdcb->StopBits) {
1914                 case ONESTOPBIT:
1915                                 port.c_cflag &= ~CSTOPB;
1916                                 break;
1917                 case TWOSTOPBITS:
1918                                 port.c_cflag |= CSTOPB;
1919                                 break;
1920                 default:
1921                         commerror = IE_BYTESIZE;
1922                         return FALSE;
1923         }
1924 #ifdef CRTSCTS
1925         if (    lpdcb->fOutxCtsFlow                     ||
1926                 lpdcb->fDtrControl == DTR_CONTROL_ENABLE||
1927                 lpdcb->fRtsControl == RTS_CONTROL_ENABLE
1928         )
1929                 port.c_cflag |= CRTSCTS;
1930         if (lpdcb->fDtrControl == DTR_CONTROL_DISABLE)
1931                 port.c_cflag &= ~CRTSCTS;
1932
1933 #endif  
1934         if (lpdcb->fInX)
1935                 port.c_iflag |= IXON;
1936         else
1937                 port.c_iflag &= ~IXON;
1938         if (lpdcb->fOutX)
1939                 port.c_iflag |= IXOFF;
1940         else
1941                 port.c_iflag &= ~IXOFF;
1942
1943         if (tcsetattr(fd,TCSADRAIN,&port)==-1) {
1944                 commerror = WinError(); 
1945                 return FALSE;
1946         } else {
1947                 commerror = 0;
1948                 return TRUE;
1949         }
1950 }
1951
1952
1953 /*****************************************************************************
1954  *      GetCommState    (KERNEL32.159)
1955  */
1956 BOOL WINAPI GetCommState(INT handle, LPDCB lpdcb)
1957 {
1958      struct termios port;
1959      int fd;
1960      struct get_read_fd_request req;
1961
1962      TRACE(comm,"handle %d, ptr %p\n", handle, lpdcb);
1963      req.handle = handle;
1964      CLIENT_SendRequest( REQ_GET_READ_FD, -1, 1, &req, sizeof(req) );
1965      CLIENT_WaitReply( NULL, &fd, 0 );
1966
1967      if(fd<0)
1968          return FALSE;
1969
1970      if (tcgetattr(fd, &port) == -1) {
1971         TRACE(comm,"tcgetattr(%d, ...) returned -1",fd);
1972                 commerror = WinError(); 
1973                 return FALSE;
1974         }
1975 #ifndef __EMX__
1976 #ifdef CBAUD
1977         switch (port.c_cflag & CBAUD) {
1978 #else
1979         switch (port.c_ospeed) {
1980 #endif
1981                 case B110:
1982                         lpdcb->BaudRate = 110;
1983                         break;
1984                 case B300:
1985                         lpdcb->BaudRate = 300;
1986                         break;
1987                 case B600:
1988                         lpdcb->BaudRate = 600;
1989                         break;
1990                 case B1200:
1991                         lpdcb->BaudRate = 1200;
1992                         break;
1993                 case B2400:
1994                         lpdcb->BaudRate = 2400;
1995                         break;
1996                 case B4800:
1997                         lpdcb->BaudRate = 4800;
1998                         break;
1999                 case B9600:
2000                         lpdcb->BaudRate = 9600;
2001                         break;
2002                 case B19200:
2003                         lpdcb->BaudRate = 19200;
2004                         break;
2005                 case B38400:
2006                         lpdcb->BaudRate = 38400;
2007                         break;
2008         }
2009 #endif
2010         switch (port.c_cflag & CSIZE) {
2011                 case CS5:
2012                         lpdcb->ByteSize = 5;
2013                         break;
2014                 case CS6:
2015                         lpdcb->ByteSize = 6;
2016                         break;
2017                 case CS7:
2018                         lpdcb->ByteSize = 7;
2019                         break;
2020                 case CS8:
2021                         lpdcb->ByteSize = 8;
2022                         break;
2023         }       
2024         
2025         if(port.c_iflag & INPCK)
2026             lpdcb->fParity = TRUE;
2027         else
2028             lpdcb->fParity = FALSE;
2029         switch (port.c_cflag & (PARENB | PARODD)) {
2030                 case 0:
2031                         lpdcb->Parity = NOPARITY;
2032                         break;
2033                 case PARENB:
2034                         lpdcb->Parity = EVENPARITY;
2035                         break;
2036                 case (PARENB | PARODD):
2037                         lpdcb->Parity = ODDPARITY;              
2038                         break;
2039         }
2040
2041         if (port.c_cflag & CSTOPB)
2042                 lpdcb->StopBits = TWOSTOPBITS;
2043         else
2044                 lpdcb->StopBits = ONESTOPBIT;
2045
2046         lpdcb->fNull = 0;
2047         lpdcb->fBinary = 1;
2048
2049 #ifdef CRTSCTS
2050
2051         if (port.c_cflag & CRTSCTS) {
2052                 lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
2053                 lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
2054                 lpdcb->fOutxCtsFlow = 1;
2055                 lpdcb->fOutxDsrFlow = 1;
2056         } else 
2057 #endif
2058         {
2059                 lpdcb->fDtrControl = DTR_CONTROL_DISABLE;
2060                 lpdcb->fRtsControl = RTS_CONTROL_DISABLE;
2061         }
2062         if (port.c_iflag & IXON)
2063                 lpdcb->fInX = 1;
2064         else
2065                 lpdcb->fInX = 0;
2066
2067         if (port.c_iflag & IXOFF)
2068                 lpdcb->fOutX = 1;
2069         else
2070                 lpdcb->fOutX = 0;
2071 /*
2072         lpdcb->XonChar = 
2073         lpdcb->XoffChar = 
2074  */
2075         lpdcb->XonLim = 10;
2076         lpdcb->XoffLim = 10;
2077
2078         commerror = 0;
2079
2080      TRACE(comm,"OK\n");
2081  
2082         return TRUE;
2083 }
2084
2085 /*****************************************************************************
2086  *      TransmitCommChar        (KERNEL32.535)
2087  */
2088 BOOL WINAPI TransmitCommChar(INT cid,CHAR chTransmit)
2089 {
2090         struct DosDeviceStruct *ptr;
2091
2092         FIXME(comm,"(%d,'%c'), use win32 handle!\n",cid,chTransmit);
2093         if ((ptr = GetDeviceStruct(cid)) == NULL) {
2094                 return FALSE;
2095         }
2096
2097         if (ptr->suspended) {
2098                 ptr->commerror = IE_HARDWARE;
2099                 return FALSE;
2100         }
2101         if (write(ptr->fd, (void *) &chTransmit, 1) == -1) {
2102                 ptr->commerror = WinError();
2103                 return FALSE;
2104         }  else {
2105                 ptr->commerror = 0;
2106                 return TRUE;
2107         }
2108 }
2109
2110 /*****************************************************************************
2111  *      GetCommTimeouts         (KERNEL32.160)
2112  */
2113 BOOL WINAPI GetCommTimeouts(INT cid,LPCOMMTIMEOUTS lptimeouts)
2114 {
2115         FIXME(comm,"(%x,%p):stub.\n",cid,lptimeouts);
2116         return TRUE;
2117 }
2118
2119 /*****************************************************************************
2120  *      SetCommTimeouts         (KERNEL32.453)
2121  */
2122 BOOL WINAPI SetCommTimeouts(INT cid,LPCOMMTIMEOUTS lptimeouts) {
2123         FIXME(comm,"(%x,%p):stub.\n",cid,lptimeouts);
2124         return TRUE;
2125 }
2126
2127 /***********************************************************************
2128  *           GetCommModemStatus   (KERNEL32.285)
2129  */
2130 BOOL WINAPI GetCommModemStatus(HANDLE hFile,LPDWORD lpModemStat )
2131 {
2132         FIXME(comm, "(%d %p)\n",hFile,lpModemStat );
2133         return TRUE;
2134 }
2135 /***********************************************************************
2136  *           WaitCommEvent   (KERNEL32.719)
2137  */
2138 BOOL WINAPI WaitCommEvent(HANDLE hFile,LPDWORD eventmask ,LPOVERLAPPED overlapped)
2139 {
2140         FIXME(comm, "(%d %p %p )\n",hFile, eventmask,overlapped);
2141         return TRUE;
2142 }
2143
2144 /***********************************************************************
2145  *           GetCommProperties   (KERNEL32.???)
2146  */
2147 BOOL WINAPI GetCommProperties(HANDLE hFile, LPDCB *dcb)
2148 {
2149     FIXME(comm, "(%d %p )\n",hFile,dcb);
2150     return TRUE;
2151 }
2152
2153 /***********************************************************************
2154  *           SetCommProperties   (KERNEL32.???)
2155  */
2156 BOOL WINAPI SetCommProperties(HANDLE hFile, LPDCB dcb)
2157 {
2158     FIXME(comm, "(%d %p )\n",hFile,dcb);
2159     return TRUE;
2160 }
2161