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