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