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