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