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