Cosmetics.
[wine] / dlls / kernel / 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 <stdio.h>
39 #include <termios.h>
40 #include <fcntl.h>
41 #include <string.h>
42 #ifdef HAVE_STRINGS_H
43 # include <strings.h>
44 #endif
45 #include <errno.h>
46 #include <ctype.h>
47 #include <sys/stat.h>
48 #ifdef HAVE_SYS_FILIO_H
49 # include <sys/filio.h>
50 #endif
51 #include <sys/ioctl.h>
52 #include <unistd.h>
53
54 #include "windef.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 #include "wine/port.h"
64 #include "server.h"
65 #include "winerror.h"
66 #include "services.h"
67 #include "callback.h"
68 #include "file.h"
69
70 #include "debugtools.h"
71
72 DEFAULT_DEBUG_CHANNEL(comm);
73
74 #if !defined(TIOCINQ) && defined(FIONREAD)
75 #define TIOCINQ FIONREAD
76 #endif
77
78 /* window's semi documented modem status register */
79 #define COMM_MSR_OFFSET  35
80 #define MSR_CTS  0x10
81 #define MSR_DSR  0x20
82 #define MSR_RI   0x40
83 #define MSR_RLSD 0x80
84 #define MSR_MASK (MSR_CTS|MSR_DSR|MSR_RI|MSR_RLSD)
85
86 #define FLAG_LPT 0x80
87
88 #ifdef linux
89 #define CMSPAR 0x40000000 /* stick parity */
90 #endif
91
92 #define MAX_PORTS   9
93
94 struct DosDeviceStruct {
95     char *devicename;   /* /dev/ttyS0 */
96     int fd;
97     int suspended;
98     int unget,xmit;
99     int baudrate;
100     int evtchar;
101     /* events */
102     int commerror, eventmask;
103     /* buffers */
104     char *inbuf,*outbuf;
105     unsigned ibuf_size,ibuf_head,ibuf_tail;
106     unsigned obuf_size,obuf_head,obuf_tail;
107     /* notifications */
108     int wnd, n_read, n_write;
109     HANDLE s_read, s_write;
110 };
111
112
113 static struct DosDeviceStruct COM[MAX_PORTS];
114 static struct DosDeviceStruct LPT[MAX_PORTS];
115 /* pointers to unknown(==undocumented) comm structure */ 
116 static LPCVOID *unknown[MAX_PORTS];
117 /* save terminal states */
118 static struct termios m_stat[MAX_PORTS];
119
120 /* update window's semi documented modem status register */
121 /* see knowledge base Q101417 */
122 static void COMM_MSRUpdate( UCHAR * pMsr, unsigned int mstat)
123 {
124     UCHAR tmpmsr=0;
125 #ifdef TIOCM_CTS
126     if(mstat & TIOCM_CTS) tmpmsr |= MSR_CTS;
127 #endif
128 #ifdef TIOCM_DSR
129     if(mstat & TIOCM_DSR) tmpmsr |= MSR_DSR;
130 #endif
131 #ifdef TIOCM_RI
132     if(mstat & TIOCM_RI)  tmpmsr |= MSR_RI;
133 #endif
134 #ifdef TIOCM_CAR
135     if(mstat & TIOCM_CAR) tmpmsr |= MSR_RLSD;
136 #endif
137     *pMsr = (*pMsr & ~MSR_MASK) | tmpmsr;
138 }
139
140 void COMM_Init(void)
141 {
142         int x;
143         char option[10], temp[256], *btemp;
144         struct stat st;
145
146         for (x=0; x!=MAX_PORTS; x++) {
147                 strcpy(option,"COMx");
148                 option[3] = '1' + x;
149                 option[4] = '\0';
150
151                 PROFILE_GetWineIniString( "serialports", option, "*",
152                                           temp, sizeof(temp) );
153                 if (!strcmp(temp, "*") || *temp == '\0') 
154                         COM[x].devicename = NULL;
155                 else {
156                         btemp = strchr(temp,',');
157                         if (btemp != NULL) {
158                                 *btemp++ = '\0';
159                                 COM[x].baudrate = atoi(btemp);
160                         } else {
161                                 COM[x].baudrate = -1;
162                         }
163                         stat(temp, &st);
164                         if (!S_ISCHR(st.st_mode)) 
165                                 WARN("Can't use `%s' as %s !\n", temp, option);
166                         else
167                                 if ((COM[x].devicename = malloc(strlen(temp)+1)) == NULL) 
168                                         WARN("Can't malloc for device info!\n");
169                                 else {
170                                         COM[x].fd = 0;
171                                         strcpy(COM[x].devicename, temp);
172                                 }
173                 TRACE("%s = %s\n", option, COM[x].devicename);
174                 }
175
176                 strcpy(option, "LPTx");
177                 option[3] = '1' + x;
178                 option[4] = '\0';
179
180                 PROFILE_GetWineIniString( "parallelports", option, "*",
181                                           temp, sizeof(temp) );
182                 if (!strcmp(temp, "*") || *temp == '\0')
183                         LPT[x].devicename = NULL;
184                 else {
185                         stat(temp, &st);
186                         if (!S_ISCHR(st.st_mode)) 
187                                 WARN("Can't use `%s' as %s !\n", temp, option);
188                         else 
189                                 if ((LPT[x].devicename = malloc(strlen(temp)+1)) == NULL) 
190                                         WARN("Can't malloc for device info!\n");
191                                 else {
192                                         LPT[x].fd = 0;
193                                         strcpy(LPT[x].devicename, temp);
194                                 }
195                 TRACE("%s = %s\n", option, LPT[x].devicename);
196                 }
197
198         }
199 }
200
201
202 static struct DosDeviceStruct *GetDeviceStruct(int fd)
203 {
204         if ((fd&0x7F)<=MAX_PORTS) {
205             if (!(fd&FLAG_LPT)) {
206                 if (COM[fd].fd)
207                     return &COM[fd];
208             } else {
209                 fd &= 0x7f;
210                 if (LPT[fd].fd)
211                     return &LPT[fd];
212             }
213         }
214
215         return NULL;
216 }
217
218 static int    GetCommPort_fd(int fd)
219 {
220         int x;
221         
222         for (x=0; x<MAX_PORTS; x++) {
223              if (COM[x].fd == fd)
224                  return x;
225        }
226        
227        return -1;
228
229
230 static int ValidCOMPort(int x)
231 {
232         return(x < MAX_PORTS ? (int) COM[x].devicename : 0); 
233 }
234
235 static int ValidLPTPort(int x)
236 {
237         return(x < MAX_PORTS ? (int) LPT[x].devicename : 0); 
238 }
239
240 static int WinError(void)
241 {
242         TRACE("errno = %d\n", errno);
243         switch (errno) {
244                 default:
245                         return CE_IOE;
246                 }
247 }
248
249 static unsigned comm_inbuf(struct DosDeviceStruct *ptr)
250 {
251   return ((ptr->ibuf_tail > ptr->ibuf_head) ? ptr->ibuf_size : 0)
252     + ptr->ibuf_head - ptr->ibuf_tail;
253 }
254
255 static unsigned comm_outbuf(struct DosDeviceStruct *ptr)
256 {
257   return ((ptr->obuf_tail > ptr->obuf_head) ? ptr->obuf_size : 0)
258     + ptr->obuf_head - ptr->obuf_tail;
259 }
260
261 static int COMM_WhackModem(int fd, unsigned int andy, unsigned int orrie)
262 {
263     unsigned int mstat, okay;
264     okay = ioctl(fd, TIOCMGET, &mstat);
265     if (okay) return okay;
266     if (andy) mstat &= andy;
267     mstat |= orrie;
268     return ioctl(fd, TIOCMSET, &mstat);
269 }
270         
271 static void CALLBACK comm_notification( ULONG_PTR private )
272 {
273   struct DosDeviceStruct *ptr = (struct DosDeviceStruct *)private;
274   int prev, bleft, len;
275   WORD mask = 0;
276   int cid = GetCommPort_fd(ptr->fd);
277
278   TRACE("async notification\n");
279   /* read data from comm port */
280   prev = comm_inbuf(ptr);
281   do {
282     bleft = ((ptr->ibuf_tail > ptr->ibuf_head) ? (ptr->ibuf_tail-1) : ptr->ibuf_size)
283       - ptr->ibuf_head;
284     len = read(ptr->fd, ptr->inbuf + ptr->ibuf_head, bleft?bleft:1);
285     if (len > 0) {
286       if (!bleft) {
287         ptr->commerror = CE_RXOVER;
288       } else {
289         /* check for events */
290         if ((ptr->eventmask & EV_RXFLAG) &&
291             memchr(ptr->inbuf + ptr->ibuf_head, ptr->evtchar, len)) {
292           *(WORD*)(unknown[cid]) |= EV_RXFLAG;
293           mask |= CN_EVENT;
294         }
295         if (ptr->eventmask & EV_RXCHAR) {
296           *(WORD*)(unknown[cid]) |= EV_RXCHAR;
297           mask |= CN_EVENT;
298         }
299         /* advance buffer position */
300         ptr->ibuf_head += len;
301         if (ptr->ibuf_head >= ptr->ibuf_size)
302           ptr->ibuf_head = 0;
303       }
304     }
305   } while (len > 0);
306   /* check for notification */
307   if (ptr->wnd && (ptr->n_read>0) && (prev<ptr->n_read) &&
308       (comm_inbuf(ptr)>=ptr->n_read)) {
309     /* passed the receive notification threshold */
310     mask |= CN_RECEIVE;
311   }
312
313   /* write any TransmitCommChar character */
314   if (ptr->xmit>=0) {
315     len = write(ptr->fd, &(ptr->xmit), 1);
316     if (len > 0) ptr->xmit = -1;
317   }
318   /* write from output queue */
319   prev = comm_outbuf(ptr);
320   do {
321     bleft = ((ptr->obuf_tail <= ptr->obuf_head) ? ptr->obuf_head : ptr->obuf_size)
322       - ptr->obuf_tail;
323     len = bleft ? write(ptr->fd, ptr->outbuf + ptr->obuf_tail, bleft) : 0;
324     if (len > 0) {
325       ptr->obuf_tail += len;
326       if (ptr->obuf_tail >= ptr->obuf_size)
327         ptr->obuf_tail = 0;
328       /* flag event */
329       if (ptr->obuf_tail == ptr->obuf_head) {
330         if (ptr->s_write) {
331           SERVICE_Delete( ptr->s_write );
332           ptr->s_write = INVALID_HANDLE_VALUE;
333         }
334         if (ptr->eventmask & EV_TXEMPTY) {
335           *(WORD*)(unknown[cid]) |= EV_TXEMPTY;
336           mask |= CN_EVENT;
337         }
338       }
339     }
340   } while (len > 0);
341   /* check for notification */
342   if (ptr->wnd && (ptr->n_write>0) && (prev>=ptr->n_write) &&
343       (comm_outbuf(ptr)<ptr->n_write)) {
344     /* passed the transmit notification threshold */
345     mask |= CN_TRANSMIT;
346   }
347
348   /* send notifications, if any */
349   if (ptr->wnd && mask) {
350     TRACE("notifying %04x: cid=%d, mask=%02x\n", ptr->wnd, cid, mask);
351     if (Callout.PostMessageA) Callout.PostMessageA(ptr->wnd, WM_COMMNOTIFY, cid, mask);
352   }
353 }
354
355 static void comm_waitread(struct DosDeviceStruct *ptr)
356 {
357   if (ptr->s_read != INVALID_HANDLE_VALUE) return;
358   ptr->s_read = SERVICE_AddObject( FILE_DupUnixHandle( ptr->fd,
359                                      GENERIC_READ | SYNCHRONIZE ),
360                                     comm_notification,
361                                     (ULONG_PTR)ptr );
362 }
363
364 static void comm_waitwrite(struct DosDeviceStruct *ptr)
365 {
366   if (ptr->s_write != INVALID_HANDLE_VALUE) return;
367   ptr->s_write = SERVICE_AddObject( FILE_DupUnixHandle( ptr->fd,
368                                       GENERIC_WRITE | SYNCHRONIZE ),
369                                      comm_notification,
370                                      (ULONG_PTR)ptr );
371 }
372
373 /**************************************************************************
374  *         BuildCommDCB16               (USER.213)
375  *
376  * According to the ECMA-234 (368.3) the function will return FALSE on 
377  * success, otherwise it will return -1. 
378  * IF THIS IS NOT CORRECT THE RETURNVALUE CHECK IN BuildCommDCBAndTimeoutsA
379  * NEEDS TO BE FIXED
380  */
381 BOOL16 WINAPI BuildCommDCB16(LPCSTR device, LPDCB16 lpdcb)
382 {
383         /* "COM1:9600,n,8,1"    */
384         /*  012345              */
385         int port;
386         char *ptr, temp[256];
387
388         TRACE("(%s), ptr %p\n", device, lpdcb);
389
390         if (!strncasecmp(device,"COM",3)) {
391                 port = device[3] - '0';
392         
393
394                 if (port-- == 0) {
395                         ERR("BUG ! COM0 can't exist!\n");
396                         return -1;
397                 }
398
399                 if (!ValidCOMPort(port)) {
400                         FIXME("invalid COM port %d?\n",port);
401                         return -1;
402                 }
403                 
404                 memset(lpdcb, 0, sizeof(DCB16)); /* initialize */
405
406                 lpdcb->Id = port;
407                 
408                 if (!*(device+4))
409                         return 0;
410
411                 if (*(device+4) != ':')
412                         return -1;
413                 
414                 strcpy(temp,device+5);
415                 ptr = strtok(temp, ", "); 
416
417                 if (COM[port].baudrate > 0)
418                         lpdcb->BaudRate = COM[port].baudrate;
419                 else
420                         lpdcb->BaudRate = atoi(ptr);
421                 TRACE("baudrate (%d)\n", lpdcb->BaudRate);
422
423                 ptr = strtok(NULL, ", ");
424                 if (islower(*ptr))
425                         *ptr = toupper(*ptr);
426
427                 TRACE("parity (%c)\n", *ptr);
428                 lpdcb->fParity = TRUE;
429                 switch (*ptr) {
430                         case 'N':
431                                 lpdcb->Parity = NOPARITY;
432                                 lpdcb->fParity = FALSE;
433                                 break;                  
434                         case 'E':
435                                 lpdcb->Parity = EVENPARITY;
436                                 break;                  
437                         case 'M':
438                                 lpdcb->Parity = MARKPARITY;
439                                 break;                  
440                         case 'O':
441                                 lpdcb->Parity = ODDPARITY;
442                                 break;                  
443                         default:
444                                 WARN("Unknown parity `%c'!\n", *ptr);
445                                 return -1;
446                 }
447
448                 ptr = strtok(NULL, ", "); 
449                 TRACE("charsize (%c)\n", *ptr);
450                 lpdcb->ByteSize = *ptr - '0';
451
452                 ptr = strtok(NULL, ", ");
453                 TRACE("stopbits (%c)\n", *ptr);
454                 switch (*ptr) {
455                         case '1':
456                                 lpdcb->StopBits = ONESTOPBIT;
457                                 break;                  
458                         case '2':
459                                 lpdcb->StopBits = TWOSTOPBITS;
460                                 break;                  
461                         default:
462                                 WARN("Unknown # of stopbits `%c'!\n", *ptr);
463                                 return -1;
464                 }
465         }       
466
467         return 0;
468 }
469
470 /*****************************************************************************
471  *      OpenComm16              (USER.200)
472  */
473 INT16 WINAPI OpenComm16(LPCSTR device,UINT16 cbInQueue,UINT16 cbOutQueue)
474 {
475         int port,fd;
476
477         TRACE("%s, %d, %d\n", device, cbInQueue, cbOutQueue);
478
479         if (strlen(device) < 4)
480            return IE_BADID;
481
482         port = device[3] - '0';
483
484         if (port-- == 0)
485                 ERR("BUG ! COM0 or LPT0 don't exist !\n");
486
487         if (!strncasecmp(device,"COM",3)) {
488                 
489                 TRACE("%s = %s\n", device, COM[port].devicename);
490
491                 if (!ValidCOMPort(port))
492                         return IE_BADID;
493
494                 if (COM[port].fd)
495                         return IE_OPEN;
496
497                 fd = open(COM[port].devicename, O_RDWR | O_NONBLOCK);
498                 if (fd == -1) {
499                         ERR("Couldn't open %s ! (%s)\n", COM[port].devicename, strerror(errno));
500                         return IE_HARDWARE;
501                 } else {
502                         unknown[port] = SEGPTR_ALLOC(40);
503                         bzero(unknown[port],40);
504                         COM[port].fd = fd;
505                         COM[port].commerror = 0;
506                         COM[port].eventmask = 0;
507                         COM[port].evtchar = 0; /* FIXME: default? */
508                         /* save terminal state */
509                         tcgetattr(fd,&m_stat[port]);
510                         /* set default parameters */
511                         if(COM[port].baudrate>-1){
512                             DCB16 dcb;
513                             GetCommState16(port, &dcb);
514                             dcb.BaudRate=COM[port].baudrate;
515                             /* more defaults:
516                              * databits, parity, stopbits
517                              */
518                             SetCommState16( &dcb);
519                         }
520                         /* init priority characters */
521                         COM[port].unget = -1;
522                         COM[port].xmit = -1;
523                         /* allocate buffers */
524                         COM[port].ibuf_size = cbInQueue;
525                         COM[port].ibuf_head = COM[port].ibuf_tail = 0;
526                         COM[port].obuf_size = cbOutQueue;
527                         COM[port].obuf_head = COM[port].obuf_tail = 0;
528
529                         COM[port].inbuf = malloc(cbInQueue);
530                         if (COM[port].inbuf) {
531                           COM[port].outbuf = malloc(cbOutQueue);
532                           if (!COM[port].outbuf)
533                             free(COM[port].inbuf);
534                         } else COM[port].outbuf = NULL;
535                         if (!COM[port].outbuf) {
536                           /* not enough memory */
537                           tcsetattr(COM[port].fd,TCSANOW,&m_stat[port]);
538                           close(COM[port].fd);
539                           ERR("out of memory\n");
540                           return IE_MEMORY;
541                         }
542
543                         COM[port].s_read = INVALID_HANDLE_VALUE;
544                         COM[port].s_write = INVALID_HANDLE_VALUE;
545                         comm_waitread( &COM[port] );
546                         return port;
547                 }
548         } 
549         else 
550         if (!strncasecmp(device,"LPT",3)) {
551         
552                 if (!ValidLPTPort(port))
553                         return IE_BADID;
554
555                 if (LPT[port].fd)
556                         return IE_OPEN;
557
558                 fd = open(LPT[port].devicename, O_RDWR | O_NONBLOCK, 0);
559                 if (fd == -1) {
560                         return IE_HARDWARE;
561                 } else {
562                         LPT[port].fd = fd;
563                         LPT[port].commerror = 0;
564                         LPT[port].eventmask = 0;
565                         return port|FLAG_LPT;
566                 }
567         }
568         return 0;
569 }
570
571 /*****************************************************************************
572  *      CloseComm16             (USER.207)
573  */
574 INT16 WINAPI CloseComm16(INT16 cid)
575 {
576         struct DosDeviceStruct *ptr;
577         
578         TRACE("cid=%d\n", cid);
579         if ((ptr = GetDeviceStruct(cid)) == NULL) {
580                 FIXME("no cid=%d found!\n", cid);
581                 return -1;
582         }
583         if (!(cid&FLAG_LPT)) {
584                 /* COM port */
585                 SEGPTR_FREE(unknown[cid]); /* [LW] */
586
587                 SERVICE_Delete( COM[cid].s_write );
588                 SERVICE_Delete( COM[cid].s_read );
589                 /* free buffers */
590                 free(ptr->outbuf);
591                 free(ptr->inbuf);
592
593                 /* reset modem lines */
594                 tcsetattr(ptr->fd,TCSANOW,&m_stat[cid]);
595         }
596
597         if (close(ptr->fd) == -1) {
598                 ptr->commerror = WinError();
599                 /* FIXME: should we clear ptr->fd here? */
600                 return -1;
601         } else {
602                 ptr->commerror = 0;
603                 ptr->fd = 0;
604                 return 0;
605         }
606 }
607
608 /*****************************************************************************
609  *      SetCommBreak16          (USER.210)
610  */
611 INT16 WINAPI SetCommBreak16(INT16 cid)
612 {
613         struct DosDeviceStruct *ptr;
614
615         TRACE("cid=%d\n", cid);
616         if ((ptr = GetDeviceStruct(cid)) == NULL) {
617                 FIXME("no cid=%d found!\n", cid);
618                 return -1;
619         }
620
621         ptr->suspended = 1;
622         ptr->commerror = 0;
623         return 0;
624 }
625
626 /*****************************************************************************
627  *      ClearCommBreak16        (USER.211)
628  */
629 INT16 WINAPI ClearCommBreak16(INT16 cid)
630 {
631         struct DosDeviceStruct *ptr;
632
633         TRACE("cid=%d\n", cid);
634         if (!(ptr = GetDeviceStruct(cid))) {
635                 FIXME("no cid=%d found!\n", cid);
636                 return -1;
637         }
638         ptr->suspended = 0;
639         ptr->commerror = 0;
640         return 0;
641 }
642
643 /*****************************************************************************
644  *      EscapeCommFunction16    (USER.214)
645  */
646 LONG WINAPI EscapeCommFunction16(UINT16 cid,UINT16 nFunction)
647 {
648         int     max;
649         struct DosDeviceStruct *ptr;
650         struct termios port;
651
652         TRACE("cid=%d, function=%d\n", cid, nFunction);
653         if ((nFunction != GETMAXCOM) && (nFunction != GETMAXLPT)) {
654                 if ((ptr = GetDeviceStruct(cid)) == NULL) {
655                         FIXME("no cid=%d found!\n", cid);
656                         return -1;
657                 }
658                 if (tcgetattr(ptr->fd,&port) == -1) {
659                         TRACE("tcgetattr failed\n");
660                         ptr->commerror=WinError();      
661                         return -1;
662                 }
663         } else ptr = NULL;
664
665         switch (nFunction) {
666                 case RESETDEV:
667                         TRACE("RESETDEV\n");
668                         break;                                  
669
670                 case GETMAXCOM:
671                         TRACE("GETMAXCOM\n"); 
672                         for (max = MAX_PORTS;!COM[max].devicename;max--)
673                                 ;
674                         return max;
675                         break;
676
677                 case GETMAXLPT:
678                         TRACE("GETMAXLPT\n"); 
679                         for (max = MAX_PORTS;!LPT[max].devicename;max--)
680                                 ;
681                         return FLAG_LPT + max;
682                         break;
683
684                 case GETBASEIRQ:
685                         TRACE("GETBASEIRQ\n"); 
686                         /* FIXME: use tables */
687                         /* just fake something for now */
688                         if (cid & FLAG_LPT) {
689                                 /* LPT1: irq 7, LPT2: irq 5 */
690                                 return (cid & 0x7f) ? 5 : 7;
691                         } else {
692                                 /* COM1: irq 4, COM2: irq 3,
693                                    COM3: irq 4, COM4: irq 3 */
694                                 return 4 - (cid & 1);
695                         }
696                         break;
697
698                 case CLRDTR:
699                         TRACE("CLRDTR\n"); 
700 #ifdef TIOCM_DTR
701                         return COMM_WhackModem(ptr->fd, ~TIOCM_DTR, 0);
702 #endif
703                 case CLRRTS:
704                         TRACE("CLRRTS\n"); 
705 #ifdef TIOCM_RTS
706                         return COMM_WhackModem(ptr->fd, ~TIOCM_RTS, 0);
707 #endif
708         
709                 case SETDTR:
710                         TRACE("SETDTR\n"); 
711 #ifdef TIOCM_DTR
712                         return COMM_WhackModem(ptr->fd, 0, TIOCM_DTR);
713 #endif
714
715                 case SETRTS:
716                         TRACE("SETRTS\n"); 
717 #ifdef TIOCM_RTS                        
718                         return COMM_WhackModem(ptr->fd, 0, TIOCM_RTS);
719 #endif
720
721                 case SETXOFF:
722                         TRACE("SETXOFF\n"); 
723                         port.c_iflag |= IXOFF;
724                         break;
725
726                 case SETXON:
727                         TRACE("SETXON\n"); 
728                         port.c_iflag |= IXON;
729                         break;
730
731                 default:
732                         WARN("(cid=%d,nFunction=%d): Unknown function\n", 
733                         cid, nFunction);
734                         break;                          
735         }
736         
737         if (tcsetattr(ptr->fd, TCSADRAIN, &port) == -1) {
738                 ptr->commerror = WinError();
739                 return -1;      
740         } else {
741                 ptr->commerror = 0;
742                 return 0;
743         }
744 }
745
746 /*****************************************************************************
747  *      FlushComm16     (USER.215)
748  */
749 INT16 WINAPI FlushComm16(INT16 cid,INT16 fnQueue)
750 {
751         int queue;
752         struct DosDeviceStruct *ptr;
753
754         TRACE("cid=%d, queue=%d\n", cid, fnQueue);
755         if ((ptr = GetDeviceStruct(cid)) == NULL) {
756                 FIXME("no cid=%d found!\n", cid);
757                 return -1;
758         }
759         switch (fnQueue) {
760                 case 0:
761                   queue = TCOFLUSH;
762                   ptr->obuf_tail = ptr->obuf_head;
763                   break;
764                 case 1:
765                   queue = TCIFLUSH;
766                   ptr->ibuf_head = ptr->ibuf_tail;
767                   break;
768                 default:
769                   WARN("(cid=%d,fnQueue=%d):Unknown queue\n", 
770                             cid, fnQueue);
771                   return -1;
772                 }
773         if (tcflush(ptr->fd, queue)) {
774                 ptr->commerror = WinError();
775                 return -1;      
776         } else {
777                 ptr->commerror = 0;
778                 return 0;
779         }
780 }  
781
782 /********************************************************************
783  *      GetCommError16  (USER.203)
784  */
785 INT16 WINAPI GetCommError16(INT16 cid,LPCOMSTAT16 lpStat)
786 {
787         int             temperror;
788         struct DosDeviceStruct *ptr;
789         unsigned char *stol;
790         unsigned int mstat;
791
792         if ((ptr = GetDeviceStruct(cid)) == NULL) {
793                 FIXME("no handle for cid = %0x!\n",cid);
794                 return -1;
795         }
796         if (cid&FLAG_LPT) {
797             WARN(" cid %d not comm port\n",cid);
798             return CE_MODE;
799         }
800         stol = (unsigned char *)unknown[cid] + COMM_MSR_OFFSET;
801         ioctl(ptr->fd,TIOCMGET,&mstat);
802         COMM_MSRUpdate( stol, mstat);
803
804         if (lpStat) {
805                 lpStat->status = 0;
806
807                 lpStat->cbOutQue = comm_outbuf(ptr);
808                 lpStat->cbInQue = comm_inbuf(ptr);
809
810                 TRACE("cid %d, error %d, stat %d in %d out %d, stol %x\n",
811                              cid, ptr->commerror, lpStat->status, lpStat->cbInQue, 
812                              lpStat->cbOutQue, *stol);
813         }
814         else
815                 TRACE("cid %d, error %d, lpStat NULL stol %x\n",
816                              cid, ptr->commerror, *stol);
817
818         /* Return any errors and clear it */
819         temperror = ptr->commerror;
820         ptr->commerror = 0;
821         return(temperror);
822 }
823
824 /*****************************************************************************
825  *      SetCommEventMask16      (USER.208)
826  */
827 SEGPTR WINAPI SetCommEventMask16(INT16 cid,UINT16 fuEvtMask)
828 {
829         struct DosDeviceStruct *ptr;
830         unsigned char *stol;
831         int repid;
832         unsigned int mstat;
833
834         TRACE("cid %d,mask %d\n",cid,fuEvtMask);
835         if ((ptr = GetDeviceStruct(cid)) == NULL) {
836                 FIXME("no handle for cid = %0x!\n",cid);
837             return (SEGPTR)NULL;
838         }
839
840         ptr->eventmask = fuEvtMask;
841
842         if ((cid&FLAG_LPT) || !ValidCOMPort(cid)) {
843             WARN(" cid %d not comm port\n",cid);
844             return (SEGPTR)NULL;
845         }
846         /* it's a COM port ? -> modify flags */
847         stol = (unsigned char *)unknown[cid] + COMM_MSR_OFFSET;
848         repid = ioctl(ptr->fd,TIOCMGET,&mstat);
849         TRACE(" ioctl  %d, msr %x at %p %p\n",repid,mstat,stol,unknown[cid]);
850         COMM_MSRUpdate( stol, mstat);
851
852         TRACE(" modem dcd construct %x\n",*stol);
853         return SEGPTR_GET(unknown[cid]);
854 }
855
856 /*****************************************************************************
857  *      GetCommEventMask16      (USER.209)
858  */
859 UINT16 WINAPI GetCommEventMask16(INT16 cid,UINT16 fnEvtClear)
860 {
861         struct DosDeviceStruct *ptr;
862         WORD events;
863
864         TRACE("cid %d, mask %d\n", cid, fnEvtClear);
865         if ((ptr = GetDeviceStruct(cid)) == NULL) {
866                 FIXME("no handle for cid = %0x!\n",cid);
867             return 0;
868         }
869
870         if ((cid&FLAG_LPT) || !ValidCOMPort(cid)) {
871             WARN(" cid %d not comm port\n",cid);
872             return 0;
873         }
874
875         events = *(WORD*)(unknown[cid]) & fnEvtClear;
876         *(WORD*)(unknown[cid]) &= ~fnEvtClear;
877         return events;
878 }
879
880 /*****************************************************************************
881  *      SetCommState16  (USER.201)
882  */
883 INT16 WINAPI SetCommState16(LPDCB16 lpdcb)
884 {
885         struct termios port;
886         struct DosDeviceStruct *ptr;
887         int bytesize, stopbits;
888         int fail=0;
889
890         TRACE("cid %d, ptr %p\n", lpdcb->Id, lpdcb);
891         if ((ptr = GetDeviceStruct(lpdcb->Id)) == NULL) {
892                 FIXME("no handle for cid = %0x!\n",lpdcb->Id);
893                 return -1;
894         }
895         if (tcgetattr(ptr->fd, &port) == -1) {
896                 ptr->commerror = WinError();    
897                 return -1;
898         }
899
900         port.c_cc[VMIN] = 0;
901         port.c_cc[VTIME] = 1;
902
903 #ifdef IMAXBEL
904         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|IMAXBEL);
905 #else
906         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR);
907 #endif
908         port.c_iflag |= (IGNBRK);
909
910         port.c_oflag &= ~(OPOST);
911
912         port.c_cflag &= ~(HUPCL);
913         port.c_cflag |= CLOCAL | CREAD;
914
915         port.c_lflag &= ~(ICANON|ECHO|ISIG);
916         port.c_lflag |= NOFLSH;
917
918         TRACE("baudrate %d\n",lpdcb->BaudRate);
919 #ifdef CBAUD
920         port.c_cflag &= ~CBAUD;
921         switch (lpdcb->BaudRate) {
922                 case 110:
923                 case CBR_110:
924                         port.c_cflag |= B110;
925                         break;          
926                 case 300:
927                 case CBR_300:
928                         port.c_cflag |= B300;
929                         break;          
930                 case 600:
931                 case CBR_600:
932                         port.c_cflag |= B600;
933                         break;          
934                 case 1200:
935                 case CBR_1200:
936                         port.c_cflag |= B1200;
937                         break;          
938                 case 2400:
939                 case CBR_2400:
940                         port.c_cflag |= B2400;
941                         break;          
942                 case 4800:
943                 case CBR_4800:
944                         port.c_cflag |= B4800;
945                         break;          
946                 case 9600:
947                 case CBR_9600:
948                         port.c_cflag |= B9600;
949                         break;          
950                 case 19200:
951                 case CBR_19200:
952                         port.c_cflag |= B19200;
953                         break;          
954                 case 38400:
955                 case CBR_38400:
956                         port.c_cflag |= B38400;
957                         break;          
958 #ifdef B57600
959                 case 57600:
960                         port.c_cflag |= B57600;
961                         break;          
962 #endif
963 #ifdef B115200
964                 case 57601:
965                         port.c_cflag |= B115200;
966                         break;          
967 #endif
968                 default:
969                         ptr->commerror = IE_BAUDRATE;
970                         fail=1;
971         }
972 #elif !defined(__EMX__)
973         switch (lpdcb->BaudRate) {
974                 case 110:
975                 case CBR_110:
976                         port.c_ospeed = B110;
977                         break;
978                 case 300:
979                 case CBR_300:
980                         port.c_ospeed = B300;
981                         break;
982                 case 600:
983                 case CBR_600:
984                         port.c_ospeed = B600;
985                         break;
986                 case 1200:
987                 case CBR_1200:
988                         port.c_ospeed = B1200;
989                         break;
990                 case 2400:
991                 case CBR_2400:
992                         port.c_ospeed = B2400;
993                         break;
994                 case 4800:
995                 case CBR_4800:
996                         port.c_ospeed = B4800;
997                         break;
998                 case 9600:
999                 case CBR_9600:
1000                         port.c_ospeed = B9600;
1001                         break;
1002                 case 19200:
1003                 case CBR_19200:
1004                         port.c_ospeed = B19200;
1005                         break;
1006                 case 38400:
1007                 case CBR_38400:
1008                         port.c_ospeed = B38400;
1009                         break;
1010                 default:
1011                         ptr->commerror = IE_BAUDRATE;
1012                         fail=1;
1013         }
1014         port.c_ispeed = port.c_ospeed;
1015 #endif
1016         bytesize=lpdcb->ByteSize;
1017         stopbits=lpdcb->StopBits;
1018
1019         TRACE("fParity %d Parity %d\n",lpdcb->fParity, lpdcb->Parity);
1020 #ifdef CMSPAR
1021         port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
1022 #else
1023         port.c_cflag &= ~(PARENB | PARODD);
1024 #endif
1025         if (lpdcb->fParity)
1026             port.c_iflag |= INPCK;
1027         else
1028             port.c_iflag &= ~INPCK;
1029         switch (lpdcb->Parity) {
1030                 case NOPARITY:
1031                         break;
1032                 case ODDPARITY:
1033                         port.c_cflag |= (PARENB | PARODD);
1034                         break;
1035                 case EVENPARITY:
1036                         port.c_cflag |= PARENB;
1037                         break;
1038 #ifdef CMSPAR
1039                 /* Linux defines mark/space (stick) parity */
1040                 case MARKPARITY:
1041                         port.c_cflag |= (PARENB | CMSPAR);
1042                         break;
1043                 case SPACEPARITY:
1044                         port.c_cflag |= (PARENB | PARODD |  CMSPAR);
1045                         break;
1046 #else
1047                 /* try the POSIX way */
1048                 case MARKPARITY:
1049                         if( stopbits == ONESTOPBIT) {
1050                             stopbits = TWOSTOPBITS;
1051                             port.c_iflag &= ~INPCK;
1052                         } else {
1053                             ptr->commerror = IE_BYTESIZE;
1054                             fail=1;
1055                         }
1056                         break;
1057                 case SPACEPARITY:
1058                         if( bytesize < 8) {
1059                             bytesize +=1;
1060                             port.c_iflag &= ~INPCK;
1061                         } else {
1062                             ptr->commerror = IE_BYTESIZE;
1063                             fail=1;
1064                         }
1065                         break;
1066 #endif
1067                 default:
1068                         ptr->commerror = IE_BYTESIZE;
1069                         fail=1;
1070         }
1071         
1072         TRACE("bytesize %d\n",bytesize);
1073         port.c_cflag &= ~CSIZE;
1074         switch (bytesize) {
1075                 case 5:
1076                         port.c_cflag |= CS5;
1077                         break;
1078                 case 6:
1079                         port.c_cflag |= CS6;
1080                         break;
1081                 case 7:
1082                         port.c_cflag |= CS7;
1083                         break;
1084                 case 8:
1085                         port.c_cflag |= CS8;
1086                         break;
1087                 default:
1088                         ptr->commerror = IE_BYTESIZE;
1089                         fail=1;
1090         }
1091
1092         TRACE("stopbits %d\n",stopbits);
1093
1094         switch (stopbits) {
1095                 case ONESTOPBIT:
1096                                 port.c_cflag &= ~CSTOPB;
1097                                 break;
1098                 case ONE5STOPBITS: /* wil be selected if bytesize is 5 */
1099                 case TWOSTOPBITS:
1100                                 port.c_cflag |= CSTOPB;
1101                                 break;
1102                 default:
1103                         ptr->commerror = IE_BYTESIZE;
1104                         fail=1;
1105         }
1106 #ifdef CRTSCTS
1107
1108         if (lpdcb->fDtrflow || lpdcb->fRtsflow || lpdcb->fOutxCtsFlow)
1109                 port.c_cflag |= CRTSCTS;
1110
1111         if (lpdcb->fDtrDisable) 
1112                 port.c_cflag &= ~CRTSCTS;
1113 #endif  
1114         if (lpdcb->fInX)
1115                 port.c_iflag |= IXON;
1116         else
1117                 port.c_iflag &= ~IXON;
1118         if (lpdcb->fOutX)
1119                 port.c_iflag |= IXOFF;
1120         else
1121                 port.c_iflag &= ~IXOFF;
1122
1123         ptr->evtchar = lpdcb->EvtChar;
1124
1125         if(fail)
1126             return -1;
1127         
1128         if (tcsetattr(ptr->fd, TCSADRAIN, &port) == -1) {
1129                 ptr->commerror = WinError();    
1130                 return -1;
1131         } else {
1132                 ptr->commerror = 0;
1133                 return 0;
1134         }
1135 }
1136
1137 /*****************************************************************************
1138  *      GetCommState16  (USER.202)
1139  */
1140 INT16 WINAPI GetCommState16(INT16 cid, LPDCB16 lpdcb)
1141 {
1142         int speed;
1143         struct DosDeviceStruct *ptr;
1144         struct termios port;
1145
1146         TRACE("cid %d, ptr %p\n", cid, lpdcb);
1147         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1148                 FIXME("no handle for cid = %0x!\n",cid);
1149                 return -1;
1150         }
1151         if (tcgetattr(ptr->fd, &port) == -1) {
1152                 ptr->commerror = WinError();    
1153                 return -1;
1154         }
1155         lpdcb->Id = cid;
1156 #ifndef __EMX__
1157 #ifdef CBAUD
1158         speed = port.c_cflag & CBAUD;
1159 #else
1160         speed = port.c_ospeed;
1161 #endif
1162         switch(speed) {
1163                 case B110:
1164                         lpdcb->BaudRate = 110;
1165                         break;
1166                 case B300:
1167                         lpdcb->BaudRate = 300;
1168                         break;
1169                 case B600:
1170                         lpdcb->BaudRate = 600;
1171                         break;
1172                 case B1200:
1173                         lpdcb->BaudRate = 1200;
1174                         break;
1175                 case B2400:
1176                         lpdcb->BaudRate = 2400;
1177                         break;
1178                 case B4800:
1179                         lpdcb->BaudRate = 4800;
1180                         break;
1181                 case B9600:
1182                         lpdcb->BaudRate = 9600;
1183                         break;
1184                 case B19200:
1185                         lpdcb->BaudRate = 19200;
1186                         break;
1187                 case B38400:
1188                         lpdcb->BaudRate = 38400;
1189                         break;
1190 #ifdef B57600
1191                 case B57600:
1192                         lpdcb->BaudRate = 57600;
1193                         break;
1194 #endif
1195 #ifdef B115200
1196                 case B115200:
1197                         lpdcb->BaudRate = 57601;
1198                         break;
1199 #endif
1200         }
1201 #endif
1202         switch (port.c_cflag & CSIZE) {
1203                 case CS5:
1204                         lpdcb->ByteSize = 5;
1205                         break;
1206                 case CS6:
1207                         lpdcb->ByteSize = 6;
1208                         break;
1209                 case CS7:
1210                         lpdcb->ByteSize = 7;
1211                         break;
1212                 case CS8:
1213                         lpdcb->ByteSize = 8;
1214                         break;
1215         }       
1216         
1217         if(port.c_iflag & INPCK)
1218             lpdcb->fParity = TRUE;
1219         else
1220             lpdcb->fParity = FALSE;
1221 #ifdef CMSPAR
1222         switch (port.c_cflag & (PARENB | PARODD | CMSPAR))
1223 #else
1224         switch (port.c_cflag & (PARENB | PARODD))
1225 #endif
1226         {
1227                 case 0:
1228                         lpdcb->Parity = NOPARITY;
1229                         break;
1230                 case PARENB:
1231                         lpdcb->Parity = EVENPARITY;
1232                         break;
1233                 case (PARENB | PARODD):
1234                         lpdcb->Parity = ODDPARITY;              
1235                         break;
1236 #ifdef CMSPAR
1237                 case (PARENB | CMSPAR):
1238                         lpdcb->Parity = MARKPARITY;             
1239                         break;
1240                 case (PARENB | PARODD | CMSPAR):
1241                         lpdcb->Parity = SPACEPARITY;            
1242                         break;
1243 #endif
1244         }
1245
1246         if (port.c_cflag & CSTOPB)
1247             if(lpdcb->ByteSize == 5)
1248                 lpdcb->StopBits = ONE5STOPBITS;
1249             else
1250                 lpdcb->StopBits = TWOSTOPBITS;
1251         else
1252             lpdcb->StopBits = ONESTOPBIT;
1253
1254         lpdcb->RlsTimeout = 50;
1255         lpdcb->CtsTimeout = 50; 
1256         lpdcb->DsrTimeout = 50;
1257         lpdcb->fNull = 0;
1258         lpdcb->fChEvt = 0;
1259         lpdcb->fBinary = 1;
1260         lpdcb->fDtrDisable = 0;
1261
1262 #ifdef CRTSCTS
1263
1264         if (port.c_cflag & CRTSCTS) {
1265                 lpdcb->fDtrflow = 1;
1266                 lpdcb->fRtsflow = 1;
1267                 lpdcb->fOutxCtsFlow = 1;
1268                 lpdcb->fOutxDsrFlow = 1;
1269         } else 
1270 #endif
1271                 lpdcb->fDtrDisable = 1;
1272
1273         if (port.c_iflag & IXON)
1274                 lpdcb->fInX = 1;
1275         else
1276                 lpdcb->fInX = 0;
1277
1278         if (port.c_iflag & IXOFF)
1279                 lpdcb->fOutX = 1;
1280         else
1281                 lpdcb->fOutX = 0;
1282 /*
1283         lpdcb->XonChar = 
1284         lpdcb->XoffChar = 
1285  */
1286         lpdcb->XonLim = 10;
1287         lpdcb->XoffLim = 10;
1288
1289         lpdcb->EvtChar = ptr->evtchar;
1290
1291         ptr->commerror = 0;
1292         return 0;
1293 }
1294
1295 /*****************************************************************************
1296  *      TransmitCommChar16      (USER.206)
1297  */
1298 INT16 WINAPI TransmitCommChar16(INT16 cid,CHAR chTransmit)
1299 {
1300         struct DosDeviceStruct *ptr;
1301
1302         TRACE("cid %d, data %d \n", cid, chTransmit);
1303         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1304                 FIXME("no handle for cid = %0x!\n",cid);
1305                 return -1;
1306         }
1307
1308         if (ptr->suspended) {
1309                 ptr->commerror = IE_HARDWARE;
1310                 return -1;
1311         }       
1312
1313         if (ptr->xmit >= 0) {
1314           /* character already queued */
1315           /* FIXME: which error would Windows return? */
1316           ptr->commerror = CE_TXFULL;
1317           return -1;
1318         }
1319
1320         if (ptr->obuf_head == ptr->obuf_tail) {
1321           /* transmit queue empty, try to transmit directly */
1322           if (write(ptr->fd, &chTransmit, 1) == -1) {
1323             /* didn't work, queue it */
1324             ptr->xmit = chTransmit;
1325             comm_waitwrite(ptr);
1326           }
1327         } else {
1328           /* data in queue, let this char be transmitted next */
1329           ptr->xmit = chTransmit;
1330           comm_waitwrite(ptr);
1331         }
1332
1333         ptr->commerror = 0;
1334         return 0;
1335 }
1336
1337 /*****************************************************************************
1338  *      UngetCommChar16 (USER.212)
1339  */
1340 INT16 WINAPI UngetCommChar16(INT16 cid,CHAR chUnget)
1341 {
1342         struct DosDeviceStruct *ptr;
1343
1344         TRACE("cid %d (char %d)\n", cid, chUnget);
1345         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1346                 FIXME("no handle for cid = %0x!\n",cid);
1347                 return -1;
1348         }
1349
1350         if (ptr->suspended) {
1351                 ptr->commerror = IE_HARDWARE;
1352                 return -1;
1353         }       
1354
1355         if (ptr->unget>=0) {
1356           /* character already queued */
1357           /* FIXME: which error would Windows return? */
1358           ptr->commerror = CE_RXOVER;
1359           return -1;
1360         }
1361
1362         ptr->unget = chUnget;
1363
1364         ptr->commerror = 0;
1365         return 0;
1366 }
1367
1368 /*****************************************************************************
1369  *      ReadComm16      (USER.204)
1370  */
1371 INT16 WINAPI ReadComm16(INT16 cid,LPSTR lpvBuf,INT16 cbRead)
1372 {
1373         int status, length;
1374         struct DosDeviceStruct *ptr;
1375         LPSTR orgBuf = lpvBuf;
1376
1377         TRACE("cid %d, ptr %p, length %d\n", cid, lpvBuf, cbRead);
1378         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1379                 FIXME("no handle for cid = %0x!\n",cid);
1380                 return -1;
1381         }
1382
1383         if (ptr->suspended) {
1384                 ptr->commerror = IE_HARDWARE;
1385                 return -1;
1386         }       
1387
1388         /* read unget character */
1389         if (ptr->unget>=0) {
1390                 *lpvBuf++ = ptr->unget;
1391                 ptr->unget = -1;
1392
1393                 length = 1;
1394         } else
1395                 length = 0;
1396
1397         /* read from receive buffer */
1398         while (length < cbRead) {
1399           status = ((ptr->ibuf_head < ptr->ibuf_tail) ?
1400                     ptr->ibuf_size : ptr->ibuf_head) - ptr->ibuf_tail;
1401           if (!status) break;
1402           if ((cbRead - length) < status)
1403             status = cbRead - length;
1404
1405           memcpy(lpvBuf, ptr->inbuf + ptr->ibuf_tail, status);
1406           ptr->ibuf_tail += status;
1407           if (ptr->ibuf_tail >= ptr->ibuf_size)
1408             ptr->ibuf_tail = 0;
1409           lpvBuf += status;
1410           length += status;
1411         }
1412
1413         TRACE("%.*s\n", length, orgBuf);
1414         ptr->commerror = 0;
1415         return length;
1416 }
1417
1418 /*****************************************************************************
1419  *      WriteComm16     (USER.205)
1420  */
1421 INT16 WINAPI WriteComm16(INT16 cid, LPSTR lpvBuf, INT16 cbWrite)
1422 {
1423         int status, length;
1424         struct DosDeviceStruct *ptr;
1425
1426         TRACE("cid %d, ptr %p, length %d\n", 
1427                 cid, lpvBuf, cbWrite);
1428         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1429                 FIXME("no handle for cid = %0x!\n",cid);
1430                 return -1;
1431         }
1432
1433         if (ptr->suspended) {
1434                 ptr->commerror = IE_HARDWARE;
1435                 return -1;
1436         }       
1437         
1438         TRACE("%.*s\n", cbWrite, lpvBuf );
1439
1440         length = 0;
1441         while (length < cbWrite) {
1442           if ((ptr->obuf_head == ptr->obuf_tail) && (ptr->xmit < 0)) {
1443             /* no data queued, try to write directly */
1444             status = write(ptr->fd, lpvBuf, cbWrite - length);
1445             if (status > 0) {
1446               lpvBuf += status;
1447               length += status;
1448               continue;
1449             }
1450           }
1451           /* can't write directly, put into transmit buffer */
1452           status = ((ptr->obuf_tail > ptr->obuf_head) ?
1453                     (ptr->obuf_tail-1) : ptr->obuf_size) - ptr->obuf_head;
1454           if (!status) break;
1455           if ((cbWrite - length) < status)
1456             status = cbWrite - length;
1457           memcpy(lpvBuf, ptr->outbuf + ptr->obuf_head, status);
1458           ptr->obuf_head += status;
1459           if (ptr->obuf_head >= ptr->obuf_size)
1460             ptr->obuf_head = 0;
1461           lpvBuf += status;
1462           length += status;
1463           comm_waitwrite(ptr);
1464         }
1465
1466         ptr->commerror = 0;     
1467         return length;
1468 }
1469
1470 /***********************************************************************
1471  *           EnableCommNotification   (USER.245)
1472  */
1473 BOOL16 WINAPI EnableCommNotification16( INT16 cid, HWND16 hwnd,
1474                                       INT16 cbWriteNotify, INT16 cbOutQueue )
1475 {
1476         struct DosDeviceStruct *ptr;
1477
1478         TRACE("(%d, %x, %d, %d)\n", cid, hwnd, cbWriteNotify, cbOutQueue);
1479         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1480                 FIXME("no handle for cid = %0x!\n",cid);
1481                 return -1;
1482         }
1483         ptr->wnd = hwnd;
1484         ptr->n_read = cbWriteNotify;
1485         ptr->n_write = cbOutQueue;
1486         return TRUE;
1487 }
1488
1489
1490 /**************************************************************************
1491  *         BuildCommDCBA                (KERNEL32.113)
1492  *
1493  *  Updates a device control block data structure with values from an
1494  *  ascii device control string.  The device control string has two forms
1495  *  normal and extended, it must be exclusively in one or the other form.
1496  *
1497  * RETURNS
1498  *
1499  *  True on success, false on an malformed control string.
1500  */
1501 BOOL WINAPI BuildCommDCBA(
1502     LPCSTR device, /* [in] The ascii device control string used to update the DCB. */
1503     LPDCB  lpdcb)  /* [out] The device control block to be updated. */
1504 {
1505         return BuildCommDCBAndTimeoutsA(device,lpdcb,NULL);
1506 }
1507
1508 /**************************************************************************
1509  *         BuildCommDCBAndTimeoutsA     (KERNEL32.114)
1510  *
1511  *  Updates a device control block data structure with values from an
1512  *  ascii device control string.  Taking time out values from a time outs
1513  *  struct if desired by the control string.
1514  *
1515  * RETURNS
1516  *
1517  *  True on success, false bad handles etc
1518  */
1519 BOOL WINAPI BuildCommDCBAndTimeoutsA(
1520     LPCSTR         device,     /* [in] The ascii device control string. */
1521     LPDCB          lpdcb,      /* [out] The device control block to be updated. */
1522     LPCOMMTIMEOUTS lptimeouts) /* [in] The time outs to use if asked to set them by the control string. */
1523 {
1524         int     port;
1525         char    *ptr,*temp;
1526
1527         TRACE("(%s,%p,%p)\n",device,lpdcb,lptimeouts);
1528
1529         if (!strncasecmp(device,"COM",3)) {
1530                 port=device[3]-'0';
1531                 if (port--==0) {
1532                         ERR("BUG! COM0 can't exist!\n");
1533                         return FALSE;
1534                 }
1535                 if (!ValidCOMPort(port))
1536                         return FALSE;
1537                 if (*(device+4)!=':')
1538                         return FALSE;
1539                 temp=(LPSTR)(device+5);
1540         } else
1541                 temp=(LPSTR)device;
1542
1543         lpdcb->DCBlength        = sizeof(DCB);
1544         if (strchr(temp,',')) { /* old style */
1545                 DCB16   dcb16;
1546                 BOOL16  ret;
1547                 char    last=temp[strlen(temp)-1];
1548
1549                 ret=BuildCommDCB16(device,&dcb16);
1550                 if (ret)
1551                         return FALSE;
1552                 lpdcb->BaudRate         = dcb16.BaudRate;
1553                 lpdcb->ByteSize         = dcb16.ByteSize;
1554                 lpdcb->fBinary          = dcb16.fBinary;
1555                 lpdcb->Parity           = dcb16.Parity;
1556                 lpdcb->fParity          = dcb16.fParity;
1557                 lpdcb->fNull            = dcb16.fNull;
1558                 lpdcb->StopBits         = dcb16.StopBits;
1559                 if (last == 'x') {
1560                         lpdcb->fInX             = TRUE;
1561                         lpdcb->fOutX            = TRUE;
1562                         lpdcb->fOutxCtsFlow     = FALSE;
1563                         lpdcb->fOutxDsrFlow     = FALSE;
1564                         lpdcb->fDtrControl      = DTR_CONTROL_ENABLE;
1565                         lpdcb->fRtsControl      = RTS_CONTROL_ENABLE;
1566                 } else if (last=='p') {
1567                         lpdcb->fInX             = FALSE;
1568                         lpdcb->fOutX            = FALSE;
1569                         lpdcb->fOutxCtsFlow     = TRUE;
1570                         lpdcb->fOutxDsrFlow     = TRUE;
1571                         lpdcb->fDtrControl      = DTR_CONTROL_HANDSHAKE;
1572                         lpdcb->fRtsControl      = RTS_CONTROL_HANDSHAKE;
1573                 } else {
1574                         lpdcb->fInX             = FALSE;
1575                         lpdcb->fOutX            = FALSE;
1576                         lpdcb->fOutxCtsFlow     = FALSE;
1577                         lpdcb->fOutxDsrFlow     = FALSE;
1578                         lpdcb->fDtrControl      = DTR_CONTROL_ENABLE;
1579                         lpdcb->fRtsControl      = RTS_CONTROL_ENABLE;
1580                 }
1581                 lpdcb->XonChar  = dcb16.XonChar;
1582                 lpdcb->XoffChar = dcb16.XoffChar;
1583                 lpdcb->ErrorChar= dcb16.PeChar;
1584                 lpdcb->fErrorChar= dcb16.fPeChar;
1585                 lpdcb->EofChar  = dcb16.EofChar;
1586                 lpdcb->EvtChar  = dcb16.EvtChar;
1587                 lpdcb->XonLim   = dcb16.XonLim;
1588                 lpdcb->XoffLim  = dcb16.XoffLim;
1589                 return TRUE;
1590         }
1591         ptr=strtok(temp," "); 
1592         while (ptr) {
1593                 DWORD   flag,x;
1594
1595                 flag=0;
1596                 if (!strncmp("baud=",ptr,5)) {
1597                         if (!sscanf(ptr+5,"%ld",&x))
1598                                 WARN("Couldn't parse %s\n",ptr);
1599                         lpdcb->BaudRate = x;
1600                         flag=1;
1601                 }
1602                 if (!strncmp("stop=",ptr,5)) {
1603                         if (!sscanf(ptr+5,"%ld",&x))
1604                                 WARN("Couldn't parse %s\n",ptr);
1605                         lpdcb->StopBits = x;
1606                         flag=1;
1607                 }
1608                 if (!strncmp("data=",ptr,5)) {
1609                         if (!sscanf(ptr+5,"%ld",&x))
1610                                 WARN("Couldn't parse %s\n",ptr);
1611                         lpdcb->ByteSize = x;
1612                         flag=1;
1613                 }
1614                 if (!strncmp("parity=",ptr,7)) {
1615                         lpdcb->fParity  = TRUE;
1616                         switch (ptr[8]) {
1617                         case 'N':case 'n':
1618                                 lpdcb->fParity  = FALSE;
1619                                 lpdcb->Parity   = NOPARITY;
1620                                 break;
1621                         case 'E':case 'e':
1622                                 lpdcb->Parity   = EVENPARITY;
1623                                 break;
1624                         case 'O':case 'o':
1625                                 lpdcb->Parity   = ODDPARITY;
1626                                 break;
1627                         case 'M':case 'm':
1628                                 lpdcb->Parity   = MARKPARITY;
1629                                 break;
1630                         }
1631                         flag=1;
1632                 }
1633                 if (!flag)
1634                         ERR("Unhandled specifier '%s', please report.\n",ptr);
1635                 ptr=strtok(NULL," ");
1636         }
1637         if (lpdcb->BaudRate==110)
1638                 lpdcb->StopBits = 2;
1639         return TRUE;
1640 }
1641
1642 /**************************************************************************
1643  *         BuildCommDCBAndTimeoutsW             (KERNEL32.115)
1644  *
1645  *  Updates a device control block data structure with values from an
1646  *  unicode device control string.  Taking time out values from a time outs
1647  *  struct if desired by the control string.
1648  *
1649  * RETURNS
1650  *
1651  *  True on success, false bad handles etc.
1652  */
1653 BOOL WINAPI BuildCommDCBAndTimeoutsW(
1654     LPCWSTR        devid,      /* [in] The unicode device control string. */
1655     LPDCB          lpdcb,      /* [out] The device control block to be updated. */
1656     LPCOMMTIMEOUTS lptimeouts) /* [in] The time outs to use if asked to set them by the control string. */
1657 {
1658         BOOL ret = FALSE;
1659         LPSTR   devidA;
1660
1661         TRACE("(%p,%p,%p)\n",devid,lpdcb,lptimeouts);
1662         devidA = HEAP_strdupWtoA( GetProcessHeap(), 0, devid );
1663         if (devidA)
1664         {
1665         ret=BuildCommDCBAndTimeoutsA(devidA,lpdcb,lptimeouts);
1666         HeapFree( GetProcessHeap(), 0, devidA );
1667         }
1668         return ret;
1669 }
1670
1671 /**************************************************************************
1672  *         BuildCommDCBW                (KERNEL32.116)
1673  *
1674  *  Updates a device control block structure with values from an
1675  *  unicode device control string.  The device control string has two forms
1676  *  normal and extended, it must be exclusively in one or the other form.
1677  *
1678  * RETURNS
1679  *
1680  *  True on success, false on an malformed control string.
1681  */
1682 BOOL WINAPI BuildCommDCBW(
1683     LPCWSTR devid, /* [in] The unicode device control string. */
1684     LPDCB   lpdcb) /* [out] The device control block to be updated. */
1685 {
1686         return BuildCommDCBAndTimeoutsW(devid,lpdcb,NULL);
1687 }
1688
1689 /* FIXME: having these global for win32 for now */
1690 int commerror=0;
1691
1692 /*****************************************************************************
1693  *      SetCommBreak            (KERNEL32.616)
1694  *
1695  *  Halts the transmission of characters to a communications device.
1696  *
1697  * RETURNS
1698  *
1699  *  True on success, and false if the communications device could not be found,
1700  *  the control is not supported.
1701  *
1702  * BUGS
1703  *
1704  *  Only TIOCSBRK and TIOCCBRK are supported. 
1705  */
1706 BOOL WINAPI SetCommBreak(
1707     HANDLE handle) /* [in] The communictions device to suspend. */
1708 {
1709 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1710         int fd,result;
1711  
1712         fd = FILE_GetUnixHandle( handle, GENERIC_READ );
1713         if(fd<0) {
1714                 TRACE("FILE_GetUnixHandle failed\n");
1715                 return FALSE;
1716         }
1717         result = ioctl(fd,TIOCSBRK,0);
1718         close(fd);
1719         if (result ==-1)
1720           {
1721                 TRACE("ioctl failed\n");
1722                 SetLastError(ERROR_NOT_SUPPORTED);
1723                 return FALSE;
1724           }
1725         return TRUE;
1726 #else
1727         FIXME("ioctl not available\n");
1728         SetLastError(ERROR_NOT_SUPPORTED);
1729         return FALSE;
1730 #endif
1731 }
1732
1733 /*****************************************************************************
1734  *      ClearCommBreak          (KERNEL32.135)
1735  *
1736  *  Resumes character transmission from a communication device.
1737  *
1738  * RETURNS
1739  *
1740  *  True on success and false if the communications device could not be found.
1741  *
1742  * BUGS
1743  *
1744  *  Only TIOCSBRK and TIOCCBRK are supported. 
1745  */
1746 BOOL WINAPI ClearCommBreak(
1747     HANDLE handle) /* [in] The halted communication device whose character transmission is to be resumed. */
1748 {
1749 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1750         int fd,result;
1751  
1752         fd = FILE_GetUnixHandle( handle, GENERIC_READ );
1753         if(fd<0) {
1754                 TRACE("FILE_GetUnixHandle failed\n");
1755                 return FALSE;
1756         }
1757         result = ioctl(fd,TIOCCBRK,0);
1758         close(fd);
1759         if (result ==-1)
1760           {
1761                 TRACE("ioctl failed\n");
1762                 SetLastError(ERROR_NOT_SUPPORTED);
1763                 return FALSE;
1764           }
1765         return TRUE;
1766 #else
1767         FIXME("ioctl not available\n");
1768         SetLastError(ERROR_NOT_SUPPORTED);
1769         return FALSE;
1770 #endif
1771 }
1772
1773 /*****************************************************************************
1774  *      EscapeCommFunction      (KERNEL32.213)
1775  *
1776  *  Directs a communication device to perform an extended function.
1777  *
1778  * RETURNS
1779  *
1780  *  True or requested data on successful completion of the command,
1781  *  false if the device is not present cannot execute the command
1782  *  or the command failed.
1783  */
1784 BOOL WINAPI EscapeCommFunction(
1785     HANDLE handle,    /* [in] The communication device to perform the extended function. */
1786     UINT   nFunction) /* [in] The extended function to be performed. */
1787 {
1788         int fd,direct=FALSE,result=FALSE;
1789         struct termios  port;
1790
1791         TRACE("handle %d, function=%d\n", handle, nFunction);
1792         fd = FILE_GetUnixHandle( handle, GENERIC_READ );
1793         if(fd<0) {
1794                 FIXME("handle %d not found.\n",handle);
1795                 return FALSE;
1796         }
1797
1798         if (tcgetattr(fd,&port) == -1) {
1799                 commerror=WinError();
1800                 close(fd);
1801                 return FALSE;
1802         }
1803
1804         switch (nFunction) {
1805                 case RESETDEV:
1806                         TRACE("\n");
1807                         break;                                  
1808
1809                 case CLRDTR:
1810                         TRACE("CLRDTR\n");
1811 #ifdef TIOCM_DTR
1812                         direct=TRUE;
1813                         result= COMM_WhackModem(fd, ~TIOCM_DTR, 0);
1814                         break;
1815 #endif
1816
1817                 case CLRRTS:
1818                         TRACE("CLRRTS\n");
1819 #ifdef TIOCM_RTS
1820                         direct=TRUE;
1821                         result= COMM_WhackModem(fd, ~TIOCM_RTS, 0);
1822                         break;
1823 #endif
1824         
1825                 case SETDTR:
1826                         TRACE("SETDTR\n");
1827 #ifdef TIOCM_DTR
1828                         direct=TRUE;
1829                         result= COMM_WhackModem(fd, 0, TIOCM_DTR);
1830                         break;
1831 #endif
1832
1833                 case SETRTS:
1834                         TRACE("SETRTS\n");
1835 #ifdef TIOCM_DTR
1836                         direct=TRUE;
1837                         result= COMM_WhackModem(fd, 0, TIOCM_RTS);
1838                         break;
1839 #endif
1840
1841                 case SETXOFF:
1842                         TRACE("SETXOFF\n");
1843                         port.c_iflag |= IXOFF;
1844                         break;
1845
1846                 case SETXON:
1847                         TRACE("SETXON\n");
1848                         port.c_iflag |= IXON;
1849                         break;
1850                 case SETBREAK:
1851                         TRACE("setbreak\n");
1852 #ifdef  TIOCSBRK
1853                         direct=TRUE;
1854                         result = ioctl(fd,TIOCSBRK,0);
1855                         break;
1856 #endif
1857                 case CLRBREAK:
1858                         TRACE("clrbreak\n");
1859 #ifdef  TIOCSBRK
1860                         direct=TRUE;
1861                         result = ioctl(fd,TIOCCBRK,0);
1862                         break;
1863 #endif
1864                 default:
1865                         WARN("(handle=%d,nFunction=%d): Unknown function\n", 
1866                         handle, nFunction);
1867                         break;                          
1868         }
1869         
1870         if (!direct)
1871           if (tcsetattr(fd, TCSADRAIN, &port) == -1) {
1872                 commerror = WinError();
1873                 close(fd);
1874                 return FALSE;   
1875           } else 
1876                 result= TRUE;
1877         else
1878           {
1879             if (result == -1)
1880               {
1881                 result= FALSE;
1882                 commerror=WinError();
1883               }
1884             else
1885               result = TRUE;
1886           }
1887         close(fd);
1888         return result;
1889 }
1890
1891 /********************************************************************
1892  *      PurgeComm        (KERNEL32.558)
1893  *
1894  *  Terminates pending operations and/or discards buffers on a
1895  *  communication resource.
1896  *
1897  * RETURNS
1898  *
1899  *  True on success and false if the communications handle is bad.
1900  */
1901 BOOL WINAPI PurgeComm(
1902     HANDLE handle, /* [in] The communication resource to be purged. */
1903     DWORD  flags)  /* [in] Flags for clear pending/buffer on input/output. */
1904 {
1905      int fd;
1906
1907      TRACE("handle %d, flags %lx\n", handle, flags);
1908
1909      fd = FILE_GetUnixHandle( handle, GENERIC_READ );
1910      if(fd<0) {
1911         FIXME("no handle %d found\n",handle);
1912         return FALSE;
1913      }
1914
1915      /*
1916      ** not exactly sure how these are different
1917      ** Perhaps if we had our own internal queues, one flushes them
1918      ** and the other flushes the kernel's buffers.
1919      */
1920      if(flags&PURGE_TXABORT)
1921          tcflush(fd,TCOFLUSH);
1922      if(flags&PURGE_RXABORT)
1923          tcflush(fd,TCIFLUSH);
1924      if(flags&PURGE_TXCLEAR)
1925          tcflush(fd,TCOFLUSH);
1926      if(flags&PURGE_RXCLEAR)
1927          tcflush(fd,TCIFLUSH);
1928      close(fd);
1929
1930      return 1;
1931 }
1932
1933 /*****************************************************************************
1934  *      ClearCommError  (KERNEL32.136)
1935  *
1936  *  Enables further I/O operations on a communications resource after
1937  *  supplying error and current status information.
1938  *
1939  * RETURNS
1940  *
1941  *  True on success, false if the communication resource handle is bad.
1942  */
1943 BOOL WINAPI ClearCommError(
1944     HANDLE    handle, /* [in] The communication resource with the error. */
1945     LPDWORD   errors, /* [out] Flags indicating error the resource experienced. */
1946     LPCOMSTAT lpStat) /* [out] The status of the communication resource. */
1947 {
1948     int fd;
1949
1950     fd=FILE_GetUnixHandle( handle, GENERIC_READ );
1951     if(0>fd) 
1952     {
1953         FIXME("no handle %d found\n",handle);
1954         return FALSE;
1955     }
1956
1957     if (lpStat) 
1958     {
1959         lpStat->status = 0;
1960
1961 #ifdef TIOCOUTQ
1962         if(ioctl(fd, TIOCOUTQ, &lpStat->cbOutQue))
1963             WARN("ioctl returned error\n");
1964 #else
1965         lpStat->cbOutQue = 0; /* FIXME: find a different way to find out */
1966 #endif
1967
1968 #ifdef TIOCINQ
1969         if(ioctl(fd, TIOCINQ, &lpStat->cbInQue))
1970             WARN("ioctl returned error\n");
1971 #endif
1972
1973         TRACE("handle %d cbInQue = %ld cbOutQue = %ld\n",
1974               handle, lpStat->cbInQue, lpStat->cbOutQue);
1975     }
1976
1977     close(fd);
1978
1979     if(errors)
1980         *errors = 0;
1981
1982     /*
1983     ** After an asynchronous write opperation, the
1984     ** app will call ClearCommError to see if the
1985     ** results are ready yet. It waits for ERROR_IO_PENDING
1986     */
1987     commerror = ERROR_IO_PENDING;
1988
1989     return TRUE;
1990 }
1991
1992 /*****************************************************************************
1993  *      SetupComm       (KERNEL32.677)
1994  *
1995  *  Called after CreateFile to hint to the communication resource to use
1996  *  specified sizes for input and output buffers rather than the default values.
1997  *
1998  * RETURNS
1999  *
2000  *  True if successful, false if the communications resource handle is bad.
2001  *
2002  * BUGS
2003  *
2004  *  Stub.
2005  */
2006 BOOL WINAPI SetupComm(
2007     HANDLE handle,  /* [in] The just created communication resource handle. */
2008     DWORD  insize,  /* [in] The suggested size of the communication resources input buffer in bytes. */
2009     DWORD  outsize) /* [in] The suggested size of the communication resources output buffer in bytes. */
2010 {
2011     int fd;
2012
2013     FIXME("insize %ld outsize %ld unimplemented stub\n", insize, outsize);
2014     fd=FILE_GetUnixHandle( handle, GENERIC_READ );
2015     if(0>fd) {
2016         FIXME("handle %d not found?\n",handle);
2017         return FALSE;
2018     }
2019     close(fd);
2020     return TRUE;
2021
2022
2023 /*****************************************************************************
2024  *      GetCommMask     (KERNEL32.284)
2025  *
2026  *  Obtain the events associated with a communication device that will cause a call
2027  *  WaitCommEvent to return.
2028  *
2029  *  RETURNS
2030  *
2031  *   True on success, fail on bad device handle etc.
2032  */
2033 BOOL WINAPI GetCommMask(
2034     HANDLE  handle,  /* [in] The communications device. */
2035     LPDWORD evtmask) /* [out] The events which cause WaitCommEvent to return. */
2036 {
2037     BOOL ret;
2038
2039     TRACE("handle %d, mask %p\n", handle, evtmask);
2040
2041     SERVER_START_REQ
2042     {
2043         struct get_serial_info_request *req = server_alloc_req( sizeof(*req), 0 );
2044         req->handle = handle;
2045         if ((ret = !server_call( REQ_GET_SERIAL_INFO )))
2046         {
2047             if (evtmask) *evtmask = req->eventmask;
2048         }
2049     }
2050     SERVER_END_REQ;
2051     return ret;
2052 }
2053
2054 /*****************************************************************************
2055  *      SetCommMask     (KERNEL32.618)
2056  *
2057  *  There be some things we need to hear about yon there communications device.
2058  *  (Set which events associated with a communication device should cause
2059  *  a call WaitCommEvent to return.)
2060  *
2061  * RETURNS
2062  *
2063  *  True on success, false on bad handle etc.
2064  */
2065 BOOL WINAPI SetCommMask(
2066     HANDLE handle,  /* [in] The communications device.  */
2067     DWORD  evtmask) /* [in] The events that to be monitored. */
2068 {
2069     BOOL ret;
2070
2071     TRACE("handle %d, mask %lx\n", handle, evtmask);
2072
2073     SERVER_START_REQ
2074     {
2075         struct set_serial_info_request *req = server_alloc_req( sizeof(*req), 0 );
2076         req->handle    = handle;
2077         req->flags     = SERIALINFO_SET_MASK;
2078         req->eventmask = evtmask;
2079         ret = !server_call( REQ_SET_SERIAL_INFO );
2080     }
2081     SERVER_END_REQ;
2082     return ret;
2083 }
2084
2085 /*****************************************************************************
2086  *      SetCommState    (KERNEL32.619)
2087  *
2088  *  Re-initializes all hardware and control settings of a communications device,
2089  *  with values from a device control block without effecting the input and output
2090  *  queues.
2091  *
2092  * RETURNS
2093  *
2094  *  True on success, false on failure eg if the XonChar is equal to the XoffChar.
2095  */
2096 BOOL WINAPI SetCommState(
2097     HANDLE handle, /* [in] The communications device. */
2098     LPDCB  lpdcb)  /* [out] The device control block. */
2099 {
2100      struct termios port;
2101      int fd, bytesize, stopbits;
2102
2103      TRACE("handle %d, ptr %p\n", handle, lpdcb);
2104      TRACE("bytesize %d baudrate %ld fParity %d Parity %d stopbits %d\n",
2105            lpdcb->ByteSize,lpdcb->BaudRate,lpdcb->fParity, lpdcb->Parity,
2106            (lpdcb->StopBits == ONESTOPBIT)?1:
2107            (lpdcb->StopBits == TWOSTOPBITS)?2:0);
2108      TRACE("%s %s\n",(lpdcb->fInX)?"IXON":"~IXON",
2109            (lpdcb->fOutX)?"IXOFF":"~IXOFF");
2110
2111      fd = FILE_GetUnixHandle( handle, GENERIC_READ );
2112      if (fd < 0)  {
2113         FIXME("no handle %d found\n",handle);
2114         return FALSE;
2115      }
2116
2117      if ((tcgetattr(fd,&port)) == -1) {
2118          int save_error = errno;
2119          commerror = WinError();
2120          close( fd );
2121          ERR("tcgetattr error '%s'\n", strerror(save_error));
2122          return FALSE;
2123      }
2124
2125         port.c_cc[VMIN] = 0;
2126         port.c_cc[VTIME] = 1;
2127
2128 #ifdef IMAXBEL
2129         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|IMAXBEL);
2130 #else
2131         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR);
2132 #endif
2133         port.c_iflag |= (IGNBRK);
2134
2135         port.c_oflag &= ~(OPOST);
2136
2137         port.c_cflag &= ~(HUPCL);
2138         port.c_cflag |= CLOCAL | CREAD;
2139
2140         port.c_lflag &= ~(ICANON|ECHO|ISIG);
2141         port.c_lflag |= NOFLSH;
2142
2143      /*
2144      ** MJM - removed default baudrate settings
2145      ** TRACE(comm,"baudrate %ld\n",lpdcb->BaudRate);
2146      */
2147 #ifdef CBAUD
2148         port.c_cflag &= ~CBAUD;
2149         switch (lpdcb->BaudRate) {
2150                 case 110:
2151                 case CBR_110:
2152                         port.c_cflag |= B110;
2153                         break;          
2154                 case 300:
2155                 case CBR_300:
2156                         port.c_cflag |= B300;
2157                         break;          
2158                 case 600:
2159                 case CBR_600:
2160                         port.c_cflag |= B600;
2161                         break;          
2162                 case 1200:
2163                 case CBR_1200:
2164                         port.c_cflag |= B1200;
2165                         break;          
2166                 case 2400:
2167                 case CBR_2400:
2168                         port.c_cflag |= B2400;
2169                         break;          
2170                 case 4800:
2171                 case CBR_4800:
2172                         port.c_cflag |= B4800;
2173                         break;          
2174                 case 9600:
2175                 case CBR_9600:
2176                         port.c_cflag |= B9600;
2177                         break;          
2178                 case 19200:
2179                 case CBR_19200:
2180                         port.c_cflag |= B19200;
2181                         break;          
2182                 case 38400:
2183                 case CBR_38400:
2184                         port.c_cflag |= B38400;
2185                         break;          
2186 #ifdef B57600
2187                 case 57600:
2188                         port.c_cflag |= B57600;
2189                         break;          
2190 #endif
2191 #ifdef B115200
2192                 case 115200:
2193                         port.c_cflag |= B115200;
2194                         break;          
2195 #endif
2196 #ifdef B230400
2197                 case 230400:
2198                         port.c_cflag |= B230400;
2199                         break;          
2200 #endif
2201 #ifdef B460800
2202                 case 460600:
2203                         port.c_cflag |= B460800;
2204                         break;          
2205 #endif
2206                 default:
2207                         commerror = IE_BAUDRATE;
2208                         close( fd );
2209                         ERR("baudrate %ld\n",lpdcb->BaudRate);
2210                         return FALSE;
2211         }
2212 #elif !defined(__EMX__)
2213         switch (lpdcb->BaudRate) {
2214                 case 110:
2215                 case CBR_110:
2216                         port.c_ospeed = B110;
2217                         break;
2218                 case 300:
2219                 case CBR_300:
2220                         port.c_ospeed = B300;
2221                         break;
2222                 case 600:
2223                 case CBR_600:
2224                         port.c_ospeed = B600;
2225                         break;
2226                 case 1200:
2227                 case CBR_1200:
2228                         port.c_ospeed = B1200;
2229                         break;
2230                 case 2400:
2231                 case CBR_2400:
2232                         port.c_ospeed = B2400;
2233                         break;
2234                 case 4800:
2235                 case CBR_4800:
2236                         port.c_ospeed = B4800;
2237                         break;
2238                 case 9600:
2239                 case CBR_9600:
2240                         port.c_ospeed = B9600;
2241                         break;
2242                 case 19200:
2243                 case CBR_19200:
2244                         port.c_ospeed = B19200;
2245                         break;
2246                 case 38400:
2247                 case CBR_38400:
2248                         port.c_ospeed = B38400;
2249                         break;
2250                 default:
2251                         commerror = IE_BAUDRATE;
2252                         close( fd );
2253                         ERR("baudrate %ld\n",lpdcb->BaudRate);
2254                         return FALSE;
2255         }
2256         port.c_ispeed = port.c_ospeed;
2257 #endif
2258         bytesize=lpdcb->ByteSize;
2259         stopbits=lpdcb->StopBits;
2260
2261 #ifdef CMSPAR
2262         port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
2263 #else
2264         port.c_cflag &= ~(PARENB | PARODD);
2265 #endif
2266         if (lpdcb->fParity)
2267             port.c_iflag |= INPCK;
2268         else
2269             port.c_iflag &= ~INPCK;
2270         switch (lpdcb->Parity) {
2271                 case NOPARITY:
2272                         break;
2273                 case ODDPARITY:
2274                         port.c_cflag |= (PARENB | PARODD);
2275                         break;
2276                 case EVENPARITY:
2277                         port.c_cflag |= PARENB;
2278                         break;
2279 #ifdef CMSPAR
2280                 /* Linux defines mark/space (stick) parity */
2281                 case MARKPARITY:
2282                         port.c_cflag |= (PARENB | CMSPAR);
2283                         break;
2284                 case SPACEPARITY:
2285                         port.c_cflag |= (PARENB | PARODD |  CMSPAR);
2286                         break;
2287 #else
2288                 /* try the POSIX way */
2289                 case MARKPARITY:
2290                         if( stopbits == ONESTOPBIT) {
2291                             stopbits = TWOSTOPBITS;
2292                             port.c_iflag &= ~INPCK;
2293                         } else {
2294                             commerror = IE_BYTESIZE;
2295                             close( fd );
2296                             ERR("Cannot set MARK Parity\n");
2297                             return FALSE;
2298                         }
2299                         break;
2300                 case SPACEPARITY:
2301                         if( bytesize < 8) {
2302                             bytesize +=1;
2303                             port.c_iflag &= ~INPCK;
2304                         } else {
2305                             commerror = IE_BYTESIZE;
2306                             close( fd );
2307                             ERR("Cannot set SPACE Parity\n");
2308                             return FALSE;
2309                         }
2310                         break;
2311 #endif
2312                default:
2313                         commerror = IE_BYTESIZE;
2314                         close( fd );
2315                         ERR("Parity\n");
2316                         return FALSE;
2317         }
2318         
2319
2320         port.c_cflag &= ~CSIZE;
2321         switch (bytesize) {
2322                 case 5:
2323                         port.c_cflag |= CS5;
2324                         break;
2325                 case 6:
2326                         port.c_cflag |= CS6;
2327                         break;
2328                 case 7:
2329                         port.c_cflag |= CS7;
2330                         break;
2331                 case 8:
2332                         port.c_cflag |= CS8;
2333                         break;
2334                 default:
2335                         commerror = IE_BYTESIZE;
2336                         close( fd );
2337                         ERR("ByteSize\n");
2338                         return FALSE;
2339         }
2340         
2341         switch (stopbits) {
2342                 case ONESTOPBIT:
2343                                 port.c_cflag &= ~CSTOPB;
2344                                 break;
2345                 case ONE5STOPBITS: /* wil be selected if bytesize is 5 */
2346                 case TWOSTOPBITS:
2347                                 port.c_cflag |= CSTOPB;
2348                                 break;
2349                 default:
2350                         commerror = IE_BYTESIZE;
2351                         close( fd );
2352                         ERR("StopBits\n");
2353                         return FALSE;
2354         }
2355 #ifdef CRTSCTS
2356         if (    lpdcb->fOutxCtsFlow                     ||
2357                 lpdcb->fDtrControl == DTR_CONTROL_ENABLE||
2358                 lpdcb->fRtsControl == RTS_CONTROL_ENABLE
2359         ) 
2360           {
2361             port.c_cflag |= CRTSCTS;
2362             TRACE("CRTSCTS\n");
2363           }
2364         
2365         if (lpdcb->fDtrControl == DTR_CONTROL_DISABLE)
2366           {
2367             port.c_cflag &= ~CRTSCTS;
2368             TRACE("~CRTSCTS\n");
2369           }
2370
2371 #endif  
2372         if (lpdcb->fInX)
2373                 port.c_iflag |= IXON;
2374         else
2375                 port.c_iflag &= ~IXON;
2376         if (lpdcb->fOutX)
2377                 port.c_iflag |= IXOFF;
2378         else
2379                 port.c_iflag &= ~IXOFF;
2380
2381         if (tcsetattr(fd,TCSANOW,&port)==-1) { /* otherwise it hangs with pending input*/
2382                 int save_error=errno;
2383                 commerror = WinError(); 
2384                 close( fd );
2385                 ERR("tcsetattr error '%s'\n", strerror(save_error));
2386                 return FALSE;
2387         } else {
2388                 commerror = 0;
2389                 close( fd );
2390                 return TRUE;
2391         }
2392 }
2393
2394
2395 /*****************************************************************************
2396  *      GetCommState    (KERNEL32.287)
2397  *
2398  *  Fills in a device control block with information from a communications device.
2399  *
2400  * RETURNS
2401  *
2402  *  True on success, false if the communication device handle is bad etc
2403  *  
2404  * BUGS
2405  *
2406  *  XonChar and XoffChar are not set.
2407  */
2408 BOOL WINAPI GetCommState(
2409     HANDLE handle, /* [in] The communications device. */
2410     LPDCB  lpdcb)  /* [out] The device control block. */
2411 {
2412      struct termios port;
2413      int fd,speed;
2414
2415      TRACE("handle %d, ptr %p\n", handle, lpdcb);
2416
2417      fd = FILE_GetUnixHandle( handle, GENERIC_READ );
2418      if (fd < 0) 
2419        {
2420          ERR("FILE_GetUnixHandle failed\n");
2421          return FALSE;
2422        }
2423      if (tcgetattr(fd, &port) == -1) {
2424                 int save_error=errno;
2425                 ERR("tcgetattr error '%s'\n", strerror(save_error));
2426                 commerror = WinError(); 
2427                 close( fd );
2428                 return FALSE;
2429         }
2430      close( fd );
2431 #ifndef __EMX__
2432 #ifdef CBAUD
2433      speed= (port.c_cflag & CBAUD);
2434 #else
2435      speed= (cfgetospeed(&port));
2436 #endif
2437      switch (speed) {
2438                 case B110:
2439                         lpdcb->BaudRate = 110;
2440                         break;
2441                 case B300:
2442                         lpdcb->BaudRate = 300;
2443                         break;
2444                 case B600:
2445                         lpdcb->BaudRate = 600;
2446                         break;
2447                 case B1200:
2448                         lpdcb->BaudRate = 1200;
2449                         break;
2450                 case B2400:
2451                         lpdcb->BaudRate = 2400;
2452                         break;
2453                 case B4800:
2454                         lpdcb->BaudRate = 4800;
2455                         break;
2456                 case B9600:
2457                         lpdcb->BaudRate = 9600;
2458                         break;
2459                 case B19200:
2460                         lpdcb->BaudRate = 19200;
2461                         break;
2462                 case B38400:
2463                         lpdcb->BaudRate = 38400;
2464                         break;
2465 #ifdef B57600
2466                 case B57600:
2467                         lpdcb->BaudRate = 57600;
2468                         break;          
2469 #endif
2470 #ifdef B115200
2471                 case B115200:
2472                         lpdcb->BaudRate = 115200;
2473                         break;          
2474 #endif
2475 #ifdef B230400
2476                 case B230400:
2477                         lpdcb->BaudRate = 230400;
2478                         break;          
2479 #endif
2480 #ifdef B460800
2481                 case B460800:
2482                         lpdcb->BaudRate = 460800;
2483                         break;          
2484 #endif
2485                 default:
2486                         ERR("unknown speed %x \n",speed);
2487         }
2488 #endif
2489         switch (port.c_cflag & CSIZE) {
2490                 case CS5:
2491                         lpdcb->ByteSize = 5;
2492                         break;
2493                 case CS6:
2494                         lpdcb->ByteSize = 6;
2495                         break;
2496                 case CS7:
2497                         lpdcb->ByteSize = 7;
2498                         break;
2499                 case CS8:
2500                         lpdcb->ByteSize = 8;
2501                         break;
2502                 default:
2503                         ERR("unknown size %x \n",port.c_cflag & CSIZE);
2504         }       
2505         
2506         if(port.c_iflag & INPCK)
2507             lpdcb->fParity = TRUE;
2508         else
2509             lpdcb->fParity = FALSE;
2510 #ifdef CMSPAR
2511         switch (port.c_cflag & (PARENB | PARODD | CMSPAR))
2512 #else
2513         switch (port.c_cflag & (PARENB | PARODD))
2514 #endif
2515         {
2516                 case 0:
2517                         lpdcb->Parity = NOPARITY;
2518                         break;
2519                 case PARENB:
2520                         lpdcb->Parity = EVENPARITY;
2521                         break;
2522                 case (PARENB | PARODD):
2523                         lpdcb->Parity = ODDPARITY;              
2524                         break;
2525 #ifdef CMSPAR
2526                 case (PARENB | CMSPAR):
2527                         lpdcb->Parity = MARKPARITY;             
2528                         break;
2529                 case (PARENB | PARODD | CMSPAR):
2530                         lpdcb->Parity = SPACEPARITY;            
2531                         break;
2532 #endif
2533         }
2534
2535         if (port.c_cflag & CSTOPB)
2536             if(lpdcb->ByteSize == 5)
2537                 lpdcb->StopBits = ONE5STOPBITS;
2538             else
2539                 lpdcb->StopBits = TWOSTOPBITS;
2540         else
2541             lpdcb->StopBits = ONESTOPBIT;
2542
2543         lpdcb->fNull = 0;
2544         lpdcb->fBinary = 1;
2545
2546 #ifdef CRTSCTS
2547
2548         if (port.c_cflag & CRTSCTS) {
2549                 lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
2550                 lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
2551                 lpdcb->fOutxCtsFlow = 1;
2552                 lpdcb->fOutxDsrFlow = 1;
2553         } else 
2554 #endif
2555         {
2556                 lpdcb->fDtrControl = DTR_CONTROL_DISABLE;
2557                 lpdcb->fRtsControl = RTS_CONTROL_DISABLE;
2558         }
2559         if (port.c_iflag & IXON)
2560                 lpdcb->fInX = 1;
2561         else
2562                 lpdcb->fInX = 0;
2563
2564         if (port.c_iflag & IXOFF)
2565                 lpdcb->fOutX = 1;
2566         else
2567                 lpdcb->fOutX = 0;
2568 /*
2569         lpdcb->XonChar = 
2570         lpdcb->XoffChar = 
2571  */
2572         lpdcb->XonLim = 10;
2573         lpdcb->XoffLim = 10;
2574
2575         commerror = 0;
2576
2577         TRACE("OK\n");
2578  
2579         TRACE("bytesize %d baudrate %ld fParity %d Parity %d stopbits %d\n",
2580               lpdcb->ByteSize,lpdcb->BaudRate,lpdcb->fParity, lpdcb->Parity,
2581               (lpdcb->StopBits == ONESTOPBIT)?1:
2582               (lpdcb->StopBits == TWOSTOPBITS)?2:0);
2583         TRACE("%s %s\n",(lpdcb->fInX)?"IXON":"~IXON",
2584               (lpdcb->fOutX)?"IXOFF":"~IXOFF");
2585 #ifdef CRTSCTS
2586         if (    lpdcb->fOutxCtsFlow                     ||
2587                 lpdcb->fDtrControl == DTR_CONTROL_ENABLE||
2588                 lpdcb->fRtsControl == RTS_CONTROL_ENABLE
2589                 ) 
2590           TRACE("CRTSCTS\n");
2591         
2592         if (lpdcb->fDtrControl == DTR_CONTROL_DISABLE)
2593           TRACE("~CRTSCTS\n");
2594         
2595 #endif  
2596         return TRUE;
2597 }
2598
2599 /*****************************************************************************
2600  *      TransmitCommChar        (KERNEL32.697)
2601  *
2602  *  Transmits a single character in front of any pending characters in the
2603  *  output buffer.  Usually used to send an interrupt character to a host.
2604  *
2605  * RETURNS
2606  *
2607  *  True if the call succeeded, false if the previous command character to the
2608  *  same device has not been sent yet the handle is bad etc.
2609  *
2610  * BUGS
2611  *
2612  *  Stub.
2613  */
2614 BOOL WINAPI TransmitCommChar(
2615     HANDLE hComm,      /* [in] The communication device in need of a command character. */
2616     CHAR   chTransmit) /* [in] The character to transmit. */
2617 {
2618         FIXME("(%x,'%c'), use win32 handle!\n",hComm,chTransmit);
2619         return TRUE;
2620 }
2621
2622 /*****************************************************************************
2623  *      GetCommTimeouts         (KERNEL32.288)
2624  *
2625  *  Obtains the request time out values for the communications device.
2626  *
2627  * RETURNS
2628  *
2629  *  True on success, false if communications device handle is bad
2630  *  or the target structure is null.
2631  */
2632 BOOL WINAPI GetCommTimeouts(
2633     HANDLE         hComm,      /* [in] The communications device. */
2634     LPCOMMTIMEOUTS lptimeouts) /* [out] The struct of request time outs. */
2635 {
2636     BOOL ret;
2637
2638     TRACE("(%x,%p)\n",hComm,lptimeouts);
2639
2640     if(!lptimeouts)
2641     {
2642         SetLastError(ERROR_INVALID_PARAMETER);
2643         return FALSE;
2644     }
2645
2646     SERVER_START_REQ
2647     {
2648         struct get_serial_info_request *req = server_alloc_req( sizeof(*req), 0 );
2649         req->handle = hComm;
2650         if ((ret = !server_call( REQ_GET_SERIAL_INFO )))
2651         {
2652             lptimeouts->ReadIntervalTimeout         = req->readinterval;
2653             lptimeouts->ReadTotalTimeoutMultiplier  = req->readmult;
2654             lptimeouts->ReadTotalTimeoutConstant    = req->readconst;
2655             lptimeouts->WriteTotalTimeoutMultiplier = req->writemult;
2656             lptimeouts->WriteTotalTimeoutConstant   = req->writeconst;
2657         }
2658     }
2659     SERVER_END_REQ;
2660     return ret;
2661 }
2662
2663 /*****************************************************************************
2664  *      SetCommTimeouts         (KERNEL32.620)
2665  *
2666  * Sets the timeouts used when reading and writing data to/from COMM ports.
2667  *
2668  * ReadIntervalTimeout 
2669  *     - converted and passes to linux kernel as c_cc[VTIME]
2670  * ReadTotalTimeoutMultiplier, ReadTotalTimeoutConstant
2671  *     - used in ReadFile to calculate GetOverlappedResult's timeout
2672  * WriteTotalTimeoutMultiplier, WriteTotalTimeoutConstant
2673  *     - used in WriteFile to calculate GetOverlappedResult's timeout
2674  *
2675  * RETURNS
2676  *
2677  *  True if the time outs were set, false otherwise.
2678  */
2679 BOOL WINAPI SetCommTimeouts(
2680     HANDLE hComm,              /* [in] handle of COMM device */
2681     LPCOMMTIMEOUTS lptimeouts) /* [in] pointer to COMMTIMEOUTS structure */
2682 {
2683     BOOL ret;
2684     int fd;
2685     struct termios tios;
2686
2687     TRACE("(%x,%p)\n",hComm,lptimeouts);
2688
2689     if(!lptimeouts)
2690     {
2691         SetLastError(ERROR_INVALID_PARAMETER);
2692         return FALSE;
2693     }
2694
2695     SERVER_START_REQ
2696     {
2697         struct set_serial_info_request *req = server_alloc_req( sizeof(*req), 0 );
2698         req->handle       = hComm;
2699         req->flags        = SERIALINFO_SET_TIMEOUTS;
2700         req->readinterval = lptimeouts->ReadIntervalTimeout ;
2701         req->readmult     = lptimeouts->ReadTotalTimeoutMultiplier ;
2702         req->readconst    = lptimeouts->ReadTotalTimeoutConstant ;
2703         req->writemult    = lptimeouts->WriteTotalTimeoutMultiplier ;
2704         req->writeconst   = lptimeouts->WriteTotalTimeoutConstant ;
2705         ret = !server_call( REQ_SET_SERIAL_INFO );
2706     }
2707     SERVER_END_REQ;
2708     if (!ret) return FALSE;
2709
2710     /* FIXME: move this stuff to the server */
2711     fd = FILE_GetUnixHandle( hComm, GENERIC_READ );
2712     if (fd < 0) {
2713        FIXME("no fd for handle = %0x!.\n",hComm);
2714        return FALSE;
2715     }
2716
2717     if (-1==tcgetattr(fd,&tios)) {
2718         FIXME("tcgetattr on fd %d failed!\n",fd);
2719         return FALSE;
2720     }
2721     /* VTIME is in 1/10 seconds */
2722     tios.c_cc[VTIME]= (lptimeouts->ReadIntervalTimeout+99)/100;
2723     if (-1==tcsetattr(fd,0,&tios)) {
2724         FIXME("tcsetattr on fd %d failed!\n",fd);
2725         return FALSE;
2726     }
2727     close(fd);
2728     return TRUE;
2729 }
2730
2731 /***********************************************************************
2732  *           GetCommModemStatus   (KERNEL32.285)
2733  *
2734  *  Obtains the four control register bits if supported by the hardware.
2735  *
2736  * RETURNS
2737  *
2738  *  True if the communications handle was good and for hardware that
2739  *  control register access, false otherwise.
2740  */
2741 BOOL WINAPI GetCommModemStatus(
2742     HANDLE  hFile,       /* [in] The communications device. */
2743     LPDWORD lpModemStat) /* [out] The control register bits. */
2744 {
2745         int fd,mstat, result=FALSE;
2746         
2747         *lpModemStat=0;
2748 #ifdef TIOCMGET
2749         fd = FILE_GetUnixHandle( hFile, GENERIC_READ );
2750         if(fd<0)
2751                 return FALSE;
2752         result = ioctl(fd, TIOCMGET, &mstat);
2753         close(fd);
2754         if (result == -1)
2755           {
2756             WARN("ioctl failed\n");
2757             return FALSE;
2758           }
2759 #ifdef TIOCM_CTS
2760         if (mstat & TIOCM_CTS)
2761             *lpModemStat |= MS_CTS_ON;
2762 #endif
2763 #ifdef TIOCM_DSR
2764         if (mstat & TIOCM_DSR)
2765           *lpModemStat |= MS_DSR_ON;
2766 #endif
2767 #ifdef TIOCM_RNG
2768         if (mstat & TIOCM_RNG)
2769           *lpModemStat |= MS_RING_ON;
2770 #endif
2771 #ifdef TIOCM_CAR
2772         /*FIXME:  Not really sure about RLSD  UB 990810*/
2773         if (mstat & TIOCM_CAR)
2774           *lpModemStat |= MS_RLSD_ON;
2775 #endif
2776         TRACE("%04x -> %s%s%s%s\n", mstat,
2777               (*lpModemStat &MS_RLSD_ON)?"MS_RLSD_ON ":"",
2778               (*lpModemStat &MS_RING_ON)?"MS_RING_ON ":"",
2779               (*lpModemStat &MS_DSR_ON)?"MS_DSR_ON ":"",
2780               (*lpModemStat &MS_CTS_ON)?"MS_CTS_ON ":"");
2781         return TRUE;
2782 #else
2783         return FALSE;
2784 #endif
2785 }
2786
2787 VOID COMM_WaitCommEventService(void **args)
2788 {
2789     LPOVERLAPPED lpOverlapped = (LPOVERLAPPED)args[0];
2790     LPDWORD buffer = (LPDWORD)args[1];
2791     DWORD events = (DWORD)args[2];
2792
2793     TRACE("overlapped %p wait complete %p <- %lx\n",lpOverlapped,buffer,events);
2794     if(buffer)
2795         *buffer = events;
2796  
2797     lpOverlapped->Internal = STATUS_SUCCESS;
2798     SetEvent( lpOverlapped->hEvent);
2799     CloseHandle(lpOverlapped->InternalHigh);
2800 }
2801
2802 /***********************************************************************
2803  *           WaitCommEvent   (KERNEL32.719)
2804  *
2805  * Wait until something interesting happens on a COMM port.
2806  * Interesting things (events) are set by calling SetCommMask before
2807  * this function is called.
2808  *
2809  * RETURNS:
2810  *   TRUE if successful
2811  *   FALSE if failure
2812  *
2813  *   The set of detected events will be written to *lpdwEventMask
2814  *   ERROR_IO_PENDING will be returned the overlapped structure was passed
2815  *
2816  * BUGS:
2817  *  Only supports EV_RXCHAR and EV_TXEMPTY
2818  */
2819 BOOL WINAPI WaitCommEvent(
2820     HANDLE hFile,              /* [in] handle of comm port to wait for */
2821     LPDWORD lpdwEvents,        /* [out] event(s) that were detected */
2822     LPOVERLAPPED lpOverlapped) /* [in/out] for Asynchronous waiting */
2823 {
2824     OVERLAPPED ov;
2825     LPOVERLAPPED lpov;
2826     int ret;
2827
2828     TRACE("(%x %p %p )\n",hFile, lpdwEvents,lpOverlapped);
2829
2830     /* if there is no overlapped structure, create our own */
2831     if(!lpOverlapped)
2832     {
2833         ov.hEvent = CreateEventA(NULL,FALSE,FALSE,NULL);
2834         lpov = &ov;
2835     }
2836     else
2837         lpov = lpOverlapped;
2838
2839     /* check that the overlapped structure has a valid event flag */
2840     if ( (lpov->hEvent==0) || (lpov->hEvent == INVALID_HANDLE_VALUE) )
2841     {
2842         ERR("Couldn't create Event flag for Overlapped structure\n");
2843         SetLastError(ERROR_INVALID_PARAMETER);
2844         return FALSE;
2845     }
2846
2847     ResetEvent(lpov->hEvent);
2848
2849     lpov->Internal = STATUS_PENDING;
2850     lpov->InternalHigh = 0;
2851     lpov->Offset = 0;
2852     lpov->OffsetHigh = 0;
2853
2854     /* start an ASYNCHRONOUS WaitCommEvent */
2855     SERVER_START_REQ
2856     {
2857         struct create_async_request *req = server_alloc_req( sizeof(*req), 0 );
2858
2859         req->file_handle = hFile;
2860         req->overlapped  = lpov;
2861         req->buffer = lpdwEvents;
2862         req->count = 0;
2863         req->func = COMM_WaitCommEventService;
2864         req->type = ASYNC_TYPE_WAIT;
2865
2866         ret=server_call( REQ_CREATE_ASYNC );
2867
2868         lpov->InternalHigh = req->ov_handle;
2869     }
2870     SERVER_END_REQ;
2871
2872     if(ret)
2873     {
2874         if(!lpOverlapped)
2875             CloseHandle(lpov->hEvent);
2876         TRACE("server call failed.\n");
2877         return FALSE;
2878     }
2879
2880     /* activate the overlapped operation */
2881     lpov->Internal = STATUS_PENDING;
2882
2883     /* wait ourselves if the caller didn't give us an overlapped struct */
2884     if(!lpOverlapped)
2885     {
2886         GetOverlappedResult(hFile, lpov, NULL, TRUE);
2887         CloseHandle(lpov->hEvent);
2888         lpov->hEvent=0;
2889     }
2890     else
2891     {
2892         /* caller wants overlapped I/O using GetOverlapped result */
2893         SetLastError(ERROR_IO_PENDING);
2894         return FALSE;
2895     }
2896
2897     return TRUE;
2898 }
2899
2900 /***********************************************************************
2901  *           GetCommProperties   (KERNEL32.286)
2902  *
2903  * This function fills in a structure with the capabilities of the 
2904  * communications port driver.
2905  *
2906  * RETURNS
2907  *
2908  *  TRUE on success, FALSE on failure
2909  *  If successful, the lpCommProp structure be filled in with
2910  *  properties of the comm port.
2911  */
2912 BOOL WINAPI GetCommProperties(
2913     HANDLE hFile,          /* [in] handle of the comm port */
2914     LPCOMMPROP lpCommProp) /* [out] pointer to struct to be filled */
2915 {
2916     FIXME("(%d %p )\n",hFile,lpCommProp);
2917     if(!lpCommProp)
2918         return FALSE;
2919
2920     /*
2921      * These values should be valid for LINUX's serial driver
2922      * FIXME: Perhaps they deserve an #ifdef LINUX
2923      */
2924     memset(lpCommProp,0,sizeof(COMMPROP));
2925     lpCommProp->wPacketLength       = 1;
2926     lpCommProp->wPacketVersion      = 1;
2927     lpCommProp->dwServiceMask       = SP_SERIALCOMM;
2928     lpCommProp->dwReserved1         = 0;
2929     lpCommProp->dwMaxTxQueue        = 4096;
2930     lpCommProp->dwMaxRxQueue        = 4096;
2931     lpCommProp->dwMaxBaud           = BAUD_115200;
2932     lpCommProp->dwProvSubType       = PST_RS232;
2933     lpCommProp->dwProvCapabilities  = PCF_DTRDSR | PCF_PARITY_CHECK | PCF_RTSCTS ;
2934     lpCommProp->dwSettableParams    = SP_BAUD | SP_DATABITS | SP_HANDSHAKING | 
2935                                       SP_PARITY | SP_PARITY_CHECK | SP_STOPBITS ;
2936     lpCommProp->dwSettableBaud      = BAUD_075 | BAUD_110 | BAUD_134_5 | BAUD_150 |
2937                 BAUD_300 | BAUD_600 | BAUD_1200 | BAUD_1800 | BAUD_2400 | BAUD_4800 |
2938                 BAUD_9600 | BAUD_19200 | BAUD_38400 | BAUD_57600 | BAUD_115200 ;
2939     lpCommProp->wSettableData       = DATABITS_5 | DATABITS_6 | DATABITS_7 | DATABITS_8 ;
2940     lpCommProp->wSettableStopParity = STOPBITS_10 | STOPBITS_15 | STOPBITS_20 | 
2941                 PARITY_NONE | PARITY_ODD |PARITY_EVEN | PARITY_MARK | PARITY_SPACE;
2942     lpCommProp->dwCurrentTxQueue    = lpCommProp->dwMaxTxQueue;
2943     lpCommProp->dwCurrentRxQueue    = lpCommProp->dwMaxRxQueue;
2944
2945     return TRUE;
2946 }
2947
2948 /***********************************************************************
2949  * FIXME:
2950  * The functionality of CommConfigDialogA, GetDefaultCommConfig and
2951  * SetDefaultCommConfig is implemented in a DLL (usually SERIALUI.DLL).
2952  * This is dependent on the type of COMM port, but since it is doubtful
2953  * anybody will get around to implementing support for fancy serial
2954  * ports in WINE, this is hardcoded for the time being.  The name of 
2955  * this DLL should be stored in and read from the system registry in 
2956  * the hive HKEY_LOCAL_MACHINE, key
2957  * System\\CurrentControlSet\\Services\\Class\\Ports\\????
2958  * where ???? is the port number... that is determined by PNP
2959  * The DLL should be loaded when the COMM port is opened, and closed 
2960  * when the COMM port is closed. - MJM 20 June 2000
2961  ***********************************************************************/
2962 static CHAR lpszSerialUI[] = "serialui.dll";
2963
2964
2965 /***********************************************************************
2966  *           CommConfigDialogA   (KERNEL32.140)
2967  *
2968  * Raises a dialog that allows the user to configure a comm port.
2969  * Fills the COMMCONFIG struct with information specified by the user.
2970  * This function should call a similar routine in the COMM driver...
2971  *
2972  * RETURNS
2973  *
2974  *  TRUE on success, FALSE on failure
2975  *  If successful, the lpCommConfig structure will contain a new
2976  *  configuration for the comm port, as specified by the user.
2977  *
2978  * BUGS
2979  *  The library with the CommConfigDialog code is never unloaded.
2980  * Perhaps this should be done when the comm port is closed?
2981  */
2982 BOOL WINAPI CommConfigDialogA(
2983     LPCSTR lpszDevice,         /* [in] name of communications device */
2984     HANDLE hWnd,               /* [in] parent window for the dialog */
2985     LPCOMMCONFIG lpCommConfig) /* [out] pointer to struct to fill */
2986 {
2987     FARPROC lpfnCommDialog;
2988     HMODULE hConfigModule;
2989     BOOL r;
2990
2991     TRACE("(%p %x %p)\n",lpszDevice, hWnd, lpCommConfig);
2992
2993     hConfigModule = LoadLibraryA(lpszSerialUI);
2994     if(!hConfigModule)
2995         return FALSE;
2996
2997     lpfnCommDialog = GetProcAddress(hConfigModule, (LPCSTR)3L);
2998
2999     if(!lpfnCommDialog)
3000         return FALSE;
3001
3002     r = lpfnCommDialog(lpszDevice,hWnd,lpCommConfig);
3003
3004     /* UnloadLibrary(hConfigModule); */
3005
3006     return r;
3007 }
3008
3009 /***********************************************************************
3010  *           CommConfigDialogW   (KERNEL32.141)
3011  *
3012  * see CommConfigDialogA for more info
3013  */
3014 BOOL WINAPI CommConfigDialogW(
3015     LPCWSTR lpszDevice,        /* [in] name of communications device */
3016     HANDLE hWnd,               /* [in] parent window for the dialog */
3017     LPCOMMCONFIG lpCommConfig) /* [out] pointer to struct to fill */
3018 {
3019     BOOL r;
3020     LPSTR lpDeviceA;
3021
3022     lpDeviceA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpszDevice );
3023     if(lpDeviceA)
3024         return FALSE;
3025     r = CommConfigDialogA(lpDeviceA,hWnd,lpCommConfig);
3026     HeapFree( GetProcessHeap(), 0, lpDeviceA );
3027     return r;
3028 }
3029
3030 /***********************************************************************
3031  *           GetCommConfig     (KERNEL32.283)
3032  *
3033  * Fill in the COMMCONFIG structure for the comm port hFile
3034  *
3035  * RETURNS
3036  *
3037  *  TRUE on success, FALSE on failure
3038  *  If successful, lpCommConfig contains the comm port configuration.
3039  *
3040  * BUGS
3041  *
3042  *  The signature is missing a the parameter for the size of the COMMCONFIG
3043  *  structure/buffer it should be
3044  *  BOOL WINAPI GetCommConfig(HANDLE hFile,LPCOMMCONFIG lpCommConfig,LPDWORD lpdwSize)
3045  */
3046 BOOL WINAPI GetCommConfig(
3047     HANDLE       hFile,        /* [in] The communications device. */
3048     LPCOMMCONFIG lpCommConfig) /* [out] The communications configuration of the device (if it fits). */
3049 #if 0 /* FIXME: Why is this "commented" out? */
3050     LPDWORD      lpdwSize)     /* [in/out] Initially the size of the configuration buffer/structure,
3051                                   afterwards the number of bytes copied to the buffer or 
3052                                   the needed size of the buffer. */
3053 #endif
3054 {
3055     BOOL r;
3056
3057     TRACE("(%x %p)\n",hFile,lpCommConfig);
3058
3059     if(lpCommConfig == NULL)
3060         return FALSE;
3061
3062     lpCommConfig->dwSize = sizeof(COMMCONFIG);
3063     lpCommConfig->wVersion = 1;
3064     lpCommConfig->wReserved = 0;
3065     r = GetCommState(hFile,&lpCommConfig->dcb);
3066     lpCommConfig->dwProviderSubType = PST_RS232;
3067     lpCommConfig->dwProviderOffset = 0;
3068     lpCommConfig->dwProviderSize = 0;
3069
3070     return r;
3071 }
3072
3073 /***********************************************************************
3074  *           SetCommConfig     (KERNEL32.617)
3075  *
3076  *  Sets the configuration of the commications device.
3077  *
3078  * RETURNS
3079  *
3080  *  True on success, false if the handle was bad is not a communications device.
3081  */
3082 BOOL WINAPI SetCommConfig(
3083     HANDLE       hFile,        /* [in] The communications device. */
3084     LPCOMMCONFIG lpCommConfig) /* [in] The desired configuration. */
3085 {
3086     TRACE("(%x %p)\n",hFile,lpCommConfig);
3087     return SetCommState(hFile,&lpCommConfig->dcb);
3088 }
3089
3090 /***********************************************************************
3091  *           SetDefaultCommConfigA   (KERNEL32.638)
3092  *
3093  *  Initializes the default configuration for the specified communication
3094  *  device. (ascii)
3095  *
3096  * RETURNS
3097  *
3098  *  True if the device was found and the defaults set, false otherwise
3099  */
3100 BOOL WINAPI SetDefaultCommConfigA(
3101     LPCSTR       lpszDevice,   /* [in] The ascii name of the device targeted for configuration. */
3102     LPCOMMCONFIG lpCommConfig, /* [in] The default configuration for the device. */
3103     DWORD        dwSize)       /* [in] The number of bytes in the configuration structure. */
3104 {
3105     FARPROC lpfnSetDefaultCommConfig;
3106     HMODULE hConfigModule;
3107     BOOL r;
3108
3109     TRACE("(%p %p %lx)\n",lpszDevice, lpCommConfig, dwSize);
3110
3111     hConfigModule = LoadLibraryA(lpszSerialUI);
3112     if(!hConfigModule)
3113         return FALSE;
3114
3115     lpfnSetDefaultCommConfig = GetProcAddress(hConfigModule, (LPCSTR)4L);
3116
3117     if(! lpfnSetDefaultCommConfig)
3118         return TRUE;
3119
3120     r = lpfnSetDefaultCommConfig(lpszDevice, lpCommConfig, dwSize);
3121
3122     /* UnloadLibrary(hConfigModule); */
3123
3124     return r;
3125 }
3126
3127
3128 /***********************************************************************
3129  *           SetDefaultCommConfigW     (KERNEL32.639)
3130  *
3131  *  Initializes the default configuration for the specified
3132  *  communication device. (unicode)
3133  *
3134  * RETURNS
3135  *
3136  */
3137 BOOL WINAPI SetDefaultCommConfigW(
3138     LPCWSTR      lpszDevice,   /* [in] The unicode name of the device targeted for configuration. */
3139     LPCOMMCONFIG lpCommConfig, /* [in] The default configuration for the device. */
3140     DWORD        dwSize)       /* [in] The number of bytes in the configuration structure. */
3141 {
3142     BOOL r;
3143     LPSTR lpDeviceA;
3144
3145     TRACE("(%s %p %lx)\n",debugstr_w(lpszDevice),lpCommConfig,dwSize);
3146
3147     lpDeviceA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpszDevice );
3148     if(lpDeviceA)
3149         return FALSE;
3150     r = SetDefaultCommConfigA(lpDeviceA,lpCommConfig,dwSize);
3151     HeapFree( GetProcessHeap(), 0, lpDeviceA );
3152     return r;
3153 }
3154
3155
3156 /***********************************************************************
3157  *           GetDefaultCommConfigA   (KERNEL32.313)
3158  *
3159  *   Acquires the default configuration of the specified communication device. (unicode)
3160  *
3161  *  RETURNS
3162  *
3163  *   True on successful reading of the default configuration,
3164  *   if the device is not found or the buffer is too small.
3165  */
3166 BOOL WINAPI GetDefaultCommConfigA(
3167     LPCSTR       lpszName, /* [in] The ascii name of the device targeted for configuration. */
3168     LPCOMMCONFIG lpCC,     /* [out] The default configuration for the device. */
3169     LPDWORD      lpdwSize) /* [in/out] Initially the size of the default configuration buffer,
3170                               afterwards the number of bytes copied to the buffer or
3171                               the needed size of the buffer. */
3172 {
3173      LPDCB lpdcb = &(lpCC->dcb);
3174      char  temp[40];
3175
3176      if (strncasecmp(lpszName,"COM",3)) {
3177         ERR("not implemented for <%s>\n", lpszName);
3178         return FALSE;
3179      }
3180
3181      if (!ValidCOMPort(lpszName[3]-'1'))
3182         return FALSE;
3183
3184      TRACE("(%s %p %ld)\n", lpszName, lpCC, *lpdwSize );
3185      if (*lpdwSize < sizeof(COMMCONFIG)) {
3186          *lpdwSize = sizeof(COMMCONFIG);
3187          return FALSE;
3188        }
3189
3190      *lpdwSize = sizeof(COMMCONFIG);
3191
3192      lpCC->dwSize = sizeof(COMMCONFIG);
3193      lpCC->wVersion = 1;
3194      lpCC->dwProviderSubType = PST_RS232;
3195      lpCC->dwProviderOffset = 0L;
3196      lpCC->dwProviderSize = 0L;
3197
3198      (void) sprintf( temp, "COM%c:38400,n,8,1", lpszName[3]);
3199      FIXME("setting %s as default\n", temp);
3200
3201      return BuildCommDCBA( temp, lpdcb);
3202 }
3203
3204 /**************************************************************************
3205  *         GetDefaultCommConfigW                (KERNEL32.314)
3206  *
3207  *   Acquires the default configuration of the specified communication device. (unicode)
3208  *
3209  *  RETURNS
3210  *
3211  *   True on successful reading of the default configuration,
3212  *   if the device is not found or the buffer is too small.
3213  */
3214 BOOL WINAPI GetDefaultCommConfigW(
3215     LPCWSTR      lpszName, /* [in] The unicode name of the device targeted for configuration. */
3216     LPCOMMCONFIG lpCC,     /* [out] The default configuration for the device. */
3217     LPDWORD      lpdwSize) /* [in/out] Initially the size of the default configuration buffer,
3218                               afterwards the number of bytes copied to the buffer or
3219                               the needed size of the buffer. */
3220 {
3221         BOOL ret = FALSE;
3222         LPSTR   lpszNameA;
3223
3224         TRACE("(%p,%p,%ld)\n",lpszName,lpCC,*lpdwSize);
3225         lpszNameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpszName );
3226         if (lpszNameA)
3227         {
3228         ret=GetDefaultCommConfigA(lpszNameA,lpCC,lpdwSize);
3229         HeapFree( GetProcessHeap(), 0, lpszNameA );
3230         }
3231         return ret;
3232 }
3233