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