MMSYSTEM_GetIData() now dies when no iData is present
[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         struct DosDeviceStruct *ptr;
1017         struct termios port;
1018
1019         TRACE("cid %d, ptr %p\n", cid, lpdcb);
1020         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1021                 return -1;
1022         }
1023         if (tcgetattr(ptr->fd, &port) == -1) {
1024                 ptr->commerror = WinError();    
1025                 return -1;
1026         }
1027         lpdcb->Id = cid;
1028 #ifndef __EMX__
1029 #ifdef CBAUD
1030         switch (port.c_cflag & CBAUD) {
1031 #else
1032         switch (port.c_ospeed) {
1033 #endif
1034                 case B110:
1035                         lpdcb->BaudRate = 110;
1036                         break;
1037                 case B300:
1038                         lpdcb->BaudRate = 300;
1039                         break;
1040                 case B600:
1041                         lpdcb->BaudRate = 600;
1042                         break;
1043                 case B1200:
1044                         lpdcb->BaudRate = 1200;
1045                         break;
1046                 case B2400:
1047                         lpdcb->BaudRate = 2400;
1048                         break;
1049                 case B4800:
1050                         lpdcb->BaudRate = 4800;
1051                         break;
1052                 case B9600:
1053                         lpdcb->BaudRate = 9600;
1054                         break;
1055                 case B19200:
1056                         lpdcb->BaudRate = 19200;
1057                         break;
1058                 case B38400:
1059                         lpdcb->BaudRate = 38400;
1060                         break;
1061 #ifdef B57600
1062                 case B57600:
1063                         lpdcb->BaudRate = 57600;
1064                         break;
1065 #endif
1066 #ifdef B115200
1067                 case B115200:
1068                         lpdcb->BaudRate = 57601;
1069                         break;
1070 #endif
1071         }
1072 #endif
1073         switch (port.c_cflag & CSIZE) {
1074                 case CS5:
1075                         lpdcb->ByteSize = 5;
1076                         break;
1077                 case CS6:
1078                         lpdcb->ByteSize = 6;
1079                         break;
1080                 case CS7:
1081                         lpdcb->ByteSize = 7;
1082                         break;
1083                 case CS8:
1084                         lpdcb->ByteSize = 8;
1085                         break;
1086         }       
1087         
1088         if(port.c_iflag & INPCK)
1089             lpdcb->fParity = TRUE;
1090         else
1091             lpdcb->fParity = FALSE;
1092         switch (port.c_cflag & (PARENB | PARODD)) {
1093                 case 0:
1094                         lpdcb->Parity = NOPARITY;
1095                         break;
1096                 case PARENB:
1097                         lpdcb->Parity = EVENPARITY;
1098                         break;
1099                 case (PARENB | PARODD):
1100                         lpdcb->Parity = ODDPARITY;              
1101                         break;
1102         }
1103
1104         if (port.c_cflag & CSTOPB)
1105                 lpdcb->StopBits = TWOSTOPBITS;
1106         else
1107                 lpdcb->StopBits = ONESTOPBIT;
1108
1109         lpdcb->RlsTimeout = 50;
1110         lpdcb->CtsTimeout = 50; 
1111         lpdcb->DsrTimeout = 50;
1112         lpdcb->fNull = 0;
1113         lpdcb->fChEvt = 0;
1114         lpdcb->fBinary = 1;
1115         lpdcb->fDtrDisable = 0;
1116
1117 #ifdef CRTSCTS
1118
1119         if (port.c_cflag & CRTSCTS) {
1120                 lpdcb->fDtrflow = 1;
1121                 lpdcb->fRtsflow = 1;
1122                 lpdcb->fOutxCtsFlow = 1;
1123                 lpdcb->fOutxDsrFlow = 1;
1124         } else 
1125 #endif
1126                 lpdcb->fDtrDisable = 1;
1127
1128         if (port.c_iflag & IXON)
1129                 lpdcb->fInX = 1;
1130         else
1131                 lpdcb->fInX = 0;
1132
1133         if (port.c_iflag & IXOFF)
1134                 lpdcb->fOutX = 1;
1135         else
1136                 lpdcb->fOutX = 0;
1137 /*
1138         lpdcb->XonChar = 
1139         lpdcb->XoffChar = 
1140  */
1141         lpdcb->XonLim = 10;
1142         lpdcb->XoffLim = 10;
1143
1144         lpdcb->EvtChar = ptr->evtchar;
1145
1146         ptr->commerror = 0;
1147         return 0;
1148 }
1149
1150 /*****************************************************************************
1151  *      TransmitCommChar        (USER.206)
1152  */
1153 INT16 WINAPI TransmitCommChar16(INT16 cid,CHAR chTransmit)
1154 {
1155         struct DosDeviceStruct *ptr;
1156
1157         TRACE("cid %d, data %d \n", cid, chTransmit);
1158         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1159                 return -1;
1160         }
1161
1162         if (ptr->suspended) {
1163                 ptr->commerror = IE_HARDWARE;
1164                 return -1;
1165         }       
1166
1167         if (ptr->xmit >= 0) {
1168           /* character already queued */
1169           /* FIXME: which error would Windows return? */
1170           ptr->commerror = CE_TXFULL;
1171           return -1;
1172         }
1173
1174         if (ptr->obuf_head == ptr->obuf_tail) {
1175           /* transmit queue empty, try to transmit directly */
1176           if (write(ptr->fd, &chTransmit, 1) == -1) {
1177             /* didn't work, queue it */
1178             ptr->xmit = chTransmit;
1179           }
1180         } else {
1181           /* data in queue, let this char be transmitted next */
1182           ptr->xmit = chTransmit;
1183         }
1184
1185         ptr->commerror = 0;
1186         return 0;
1187 }
1188
1189 /*****************************************************************************
1190  *      UngetCommChar   (USER.212)
1191  */
1192 INT16 WINAPI UngetCommChar16(INT16 cid,CHAR chUnget)
1193 {
1194         struct DosDeviceStruct *ptr;
1195
1196         TRACE("cid %d (char %d)\n", cid, chUnget);
1197         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1198                 return -1;
1199         }
1200
1201         if (ptr->suspended) {
1202                 ptr->commerror = IE_HARDWARE;
1203                 return -1;
1204         }       
1205
1206         if (ptr->unget>=0) {
1207           /* character already queued */
1208           /* FIXME: which error would Windows return? */
1209           ptr->commerror = CE_RXOVER;
1210           return -1;
1211         }
1212
1213         ptr->unget = chUnget;
1214
1215         ptr->commerror = 0;
1216         return 0;
1217 }
1218
1219 /*****************************************************************************
1220  *      ReadComm        (USER.204)
1221  */
1222 INT16 WINAPI ReadComm16(INT16 cid,LPSTR lpvBuf,INT16 cbRead)
1223 {
1224         int status, length;
1225         struct DosDeviceStruct *ptr;
1226         LPSTR orgBuf = lpvBuf;
1227
1228         TRACE("cid %d, ptr %p, length %d\n", cid, lpvBuf, cbRead);
1229         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1230                 return -1;
1231         }
1232
1233         if (ptr->suspended) {
1234                 ptr->commerror = IE_HARDWARE;
1235                 return -1;
1236         }       
1237
1238         /* read unget character */
1239         if (ptr->unget>=0) {
1240                 *lpvBuf++ = ptr->unget;
1241                 ptr->unget = -1;
1242
1243                 length = 1;
1244         } else
1245                 length = 0;
1246
1247         /* read from receive buffer */
1248         while (length < cbRead) {
1249           status = ((ptr->ibuf_head < ptr->ibuf_tail) ?
1250                     ptr->ibuf_size : ptr->ibuf_head) - ptr->ibuf_tail;
1251           if (!status) break;
1252           if ((cbRead - length) < status)
1253             status = cbRead - length;
1254
1255           memcpy(lpvBuf, ptr->inbuf + ptr->ibuf_tail, status);
1256           ptr->ibuf_tail += status;
1257           if (ptr->ibuf_tail >= ptr->ibuf_size)
1258             ptr->ibuf_tail = 0;
1259           lpvBuf += status;
1260           length += status;
1261         }
1262
1263         TRACE("%.*s\n", length, orgBuf);
1264         ptr->commerror = 0;
1265         return length;
1266 }
1267
1268 /*****************************************************************************
1269  *      WriteComm       (USER.205)
1270  */
1271 INT16 WINAPI WriteComm16(INT16 cid, LPSTR lpvBuf, INT16 cbWrite)
1272 {
1273         int status, length;
1274         struct DosDeviceStruct *ptr;
1275
1276         TRACE("cid %d, ptr %p, length %d\n", 
1277                 cid, lpvBuf, cbWrite);
1278         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1279                 return -1;
1280         }
1281
1282         if (ptr->suspended) {
1283                 ptr->commerror = IE_HARDWARE;
1284                 return -1;
1285         }       
1286         
1287         TRACE("%.*s\n", cbWrite, lpvBuf );
1288
1289         length = 0;
1290         while (length < cbWrite) {
1291           if ((ptr->obuf_head == ptr->obuf_tail) && (ptr->xmit < 0)) {
1292             /* no data queued, try to write directly */
1293             status = write(ptr->fd, lpvBuf, cbWrite - length);
1294             if (status > 0) {
1295               lpvBuf += status;
1296               length += status;
1297               continue;
1298             }
1299           }
1300           /* can't write directly, put into transmit buffer */
1301           status = ((ptr->obuf_tail > ptr->obuf_head) ?
1302                     (ptr->obuf_tail-1) : ptr->obuf_size) - ptr->obuf_head;
1303           if (!status) break;
1304           if ((cbWrite - length) < status)
1305             status = cbWrite - length;
1306           memcpy(lpvBuf, ptr->outbuf + ptr->obuf_head, status);
1307           ptr->obuf_head += status;
1308           if (ptr->obuf_head >= ptr->obuf_size)
1309             ptr->obuf_head = 0;
1310           lpvBuf += status;
1311           length += status;
1312         }
1313
1314         ptr->commerror = 0;     
1315         return length;
1316 }
1317
1318 /***********************************************************************
1319  *           EnableCommNotification   (USER.246)
1320  */
1321 BOOL16 WINAPI EnableCommNotification16( INT16 cid, HWND16 hwnd,
1322                                       INT16 cbWriteNotify, INT16 cbOutQueue )
1323 {
1324         struct DosDeviceStruct *ptr;
1325
1326         TRACE("(%d, %x, %d, %d)\n", cid, hwnd, cbWriteNotify, cbOutQueue);
1327         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1328                 ptr->commerror = IE_BADID;
1329                 return -1;
1330         }
1331         ptr->wnd = hwnd;
1332         ptr->n_read = cbWriteNotify;
1333         ptr->n_write = cbOutQueue;
1334         return TRUE;
1335 }
1336
1337
1338 /**************************************************************************
1339  *         BuildCommDCBA                (KERNEL32.14)
1340  */
1341 BOOL WINAPI BuildCommDCBA(LPCSTR device,LPDCB lpdcb)
1342 {
1343         return BuildCommDCBAndTimeoutsA(device,lpdcb,NULL);
1344 }
1345
1346 /**************************************************************************
1347  *         BuildCommDCBAndTimeoutsA     (KERNEL32.15)
1348  */
1349 BOOL WINAPI BuildCommDCBAndTimeoutsA(LPCSTR device, LPDCB lpdcb,
1350                                          LPCOMMTIMEOUTS lptimeouts)
1351 {
1352         int     port;
1353         char    *ptr,*temp;
1354
1355         TRACE("(%s,%p,%p)\n",device,lpdcb,lptimeouts);
1356
1357         if (!lstrncmpiA(device,"COM",3)) {
1358                 port=device[3]-'0';
1359                 if (port--==0) {
1360                         ERR("BUG! COM0 can't exists!.\n");
1361                         return FALSE;
1362                 }
1363                 if (!ValidCOMPort(port))
1364                         return FALSE;
1365                 if (*(device+4)!=':')
1366                         return FALSE;
1367                 temp=(LPSTR)(device+5);
1368         } else
1369                 temp=(LPSTR)device;
1370
1371         memset(lpdcb, 0, sizeof(DCB)); /* initialize */
1372
1373         lpdcb->DCBlength        = sizeof(DCB);
1374         if (strchr(temp,',')) { /* old style */
1375                 DCB16   dcb16;
1376                 BOOL16  ret;
1377                 char    last=temp[strlen(temp)-1];
1378
1379                 ret=BuildCommDCB16(device,&dcb16);
1380                 if (!ret)
1381                         return FALSE;
1382                 lpdcb->BaudRate         = dcb16.BaudRate;
1383                 lpdcb->ByteSize         = dcb16.ByteSize;
1384                 lpdcb->fBinary          = dcb16.fBinary;
1385                 lpdcb->Parity           = dcb16.Parity;
1386                 lpdcb->fParity          = dcb16.fParity;
1387                 lpdcb->fNull            = dcb16.fNull;
1388                 lpdcb->StopBits         = dcb16.StopBits;
1389                 if (last == 'x') {
1390                         lpdcb->fInX             = TRUE;
1391                         lpdcb->fOutX            = TRUE;
1392                         lpdcb->fOutxCtsFlow     = FALSE;
1393                         lpdcb->fOutxDsrFlow     = FALSE;
1394                         lpdcb->fDtrControl      = DTR_CONTROL_ENABLE;
1395                         lpdcb->fRtsControl      = RTS_CONTROL_ENABLE;
1396                 } else if (last=='p') {
1397                         lpdcb->fInX             = FALSE;
1398                         lpdcb->fOutX            = FALSE;
1399                         lpdcb->fOutxCtsFlow     = TRUE;
1400                         lpdcb->fOutxDsrFlow     = TRUE;
1401                         lpdcb->fDtrControl      = DTR_CONTROL_HANDSHAKE;
1402                         lpdcb->fRtsControl      = RTS_CONTROL_HANDSHAKE;
1403                 } else {
1404                         lpdcb->fInX             = FALSE;
1405                         lpdcb->fOutX            = FALSE;
1406                         lpdcb->fOutxCtsFlow     = FALSE;
1407                         lpdcb->fOutxDsrFlow     = FALSE;
1408                         lpdcb->fDtrControl      = DTR_CONTROL_ENABLE;
1409                         lpdcb->fRtsControl      = RTS_CONTROL_ENABLE;
1410                 }
1411                 lpdcb->XonChar  = dcb16.XonChar;
1412                 lpdcb->XoffChar = dcb16.XoffChar;
1413                 lpdcb->ErrorChar= dcb16.PeChar;
1414                 lpdcb->fErrorChar= dcb16.fPeChar;
1415                 lpdcb->EofChar  = dcb16.EofChar;
1416                 lpdcb->EvtChar  = dcb16.EvtChar;
1417                 lpdcb->XonLim   = dcb16.XonLim;
1418                 lpdcb->XoffLim  = dcb16.XoffLim;
1419                 return TRUE;
1420         }
1421         ptr=strtok(temp," "); 
1422         while (ptr) {
1423                 DWORD   flag,x;
1424
1425                 flag=0;
1426                 if (!strncmp("baud=",ptr,5)) {
1427                         if (!sscanf(ptr+5,"%ld",&x))
1428                                 WARN("Couldn't parse %s\n",ptr);
1429                         lpdcb->BaudRate = x;
1430                         flag=1;
1431                 }
1432                 if (!strncmp("stop=",ptr,5)) {
1433                         if (!sscanf(ptr+5,"%ld",&x))
1434                                 WARN("Couldn't parse %s\n",ptr);
1435                         lpdcb->StopBits = x;
1436                         flag=1;
1437                 }
1438                 if (!strncmp("data=",ptr,5)) {
1439                         if (!sscanf(ptr+5,"%ld",&x))
1440                                 WARN("Couldn't parse %s\n",ptr);
1441                         lpdcb->ByteSize = x;
1442                         flag=1;
1443                 }
1444                 if (!strncmp("parity=",ptr,7)) {
1445                         lpdcb->fParity  = TRUE;
1446                         switch (ptr[8]) {
1447                         case 'N':case 'n':
1448                                 lpdcb->fParity  = FALSE;
1449                                 lpdcb->Parity   = NOPARITY;
1450                                 break;
1451                         case 'E':case 'e':
1452                                 lpdcb->Parity   = EVENPARITY;
1453                                 break;
1454                         case 'O':case 'o':
1455                                 lpdcb->Parity   = ODDPARITY;
1456                                 break;
1457                         case 'M':case 'm':
1458                                 lpdcb->Parity   = MARKPARITY;
1459                                 break;
1460                         }
1461                         flag=1;
1462                 }
1463                 if (!flag)
1464                         ERR("Unhandled specifier '%s', please report.\n",ptr);
1465                 ptr=strtok(NULL," ");
1466         }
1467         if (lpdcb->BaudRate==110)
1468                 lpdcb->StopBits = 2;
1469         return TRUE;
1470 }
1471
1472 /**************************************************************************
1473  *         BuildCommDCBAndTimeoutsW             (KERNEL32.16)
1474  */
1475 BOOL WINAPI BuildCommDCBAndTimeoutsW( LPCWSTR devid, LPDCB lpdcb,
1476                                           LPCOMMTIMEOUTS lptimeouts )
1477 {
1478         LPSTR   devidA;
1479         BOOL    ret;
1480
1481         TRACE("(%p,%p,%p)\n",devid,lpdcb,lptimeouts);
1482         devidA = HEAP_strdupWtoA( GetProcessHeap(), 0, devid );
1483         ret=BuildCommDCBAndTimeoutsA(devidA,lpdcb,lptimeouts);
1484         HeapFree( GetProcessHeap(), 0, devidA );
1485         return ret;
1486 }
1487
1488 /**************************************************************************
1489  *         BuildCommDCBW                (KERNEL32.17)
1490  */
1491 BOOL WINAPI BuildCommDCBW(LPCWSTR devid,LPDCB lpdcb)
1492 {
1493         return BuildCommDCBAndTimeoutsW(devid,lpdcb,NULL);
1494 }
1495
1496 /*****************************************************************************
1497  *      COMM_GetReadFd
1498  *  Returns a file descriptor for reading.
1499  *  Make sure to close the handle afterwards!
1500  */
1501 static int COMM_GetReadFd( HANDLE handle)
1502 {
1503     int fd;
1504     struct get_read_fd_request *req = get_req_buffer();
1505     req->handle = handle;
1506     server_call_fd( REQ_GET_READ_FD, -1, &fd );
1507     return fd;
1508 }
1509
1510 /*****************************************************************************
1511  *      COMM_GetWriteFd
1512  *  Returns a file descriptor for writing.
1513  *  Make sure to close the handle afterwards!
1514  */
1515 static int COMM_GetWriteFd( HANDLE handle)
1516 {
1517     int fd;
1518     struct get_write_fd_request *req = get_req_buffer();
1519     req->handle = handle;
1520     server_call_fd( REQ_GET_WRITE_FD, -1, &fd );
1521     return fd;
1522 }
1523
1524 /* FIXME: having these global for win32 for now */
1525 int commerror=0,eventmask=0;
1526
1527 /*****************************************************************************
1528  *      SetCommBreak            (KERNEL32.449)
1529  */
1530 BOOL WINAPI SetCommBreak(HANDLE handle)
1531 {
1532 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1533         int fd,result;
1534  
1535         fd = COMM_GetWriteFd(handle);
1536         if(fd<0) {
1537                 TRACE("COMM_GetWriteFd failed\n");
1538                 return FALSE;
1539         }
1540         result = ioctl(fd,TIOCSBRK,0);
1541         close(fd);
1542         if (result ==-1)
1543           {
1544                 TRACE("ioctl failed\n");
1545                 SetLastError(ERROR_NOT_SUPPORTED);
1546                 return FALSE;
1547           }
1548         return TRUE;
1549 #else
1550         FIXME("ioctl not available\n");
1551         SetLastError(ERROR_NOT_SUPPORTED);
1552         return FALSE;
1553 #endif
1554 }
1555
1556 /*****************************************************************************
1557  *      ClearCommBreak          (KERNEL32.20)
1558  */
1559 BOOL WINAPI ClearCommBreak(HANDLE handle)
1560 {
1561 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1562         int fd,result;
1563  
1564         fd = COMM_GetWriteFd(handle);
1565         if(fd<0) {
1566                 TRACE("COMM_GetWriteFd failed\n");
1567                 return FALSE;
1568         }
1569         result = ioctl(fd,TIOCCBRK,0);
1570         close(fd);
1571         if (result ==-1)
1572           {
1573                 TRACE("ioctl failed\n");
1574                 SetLastError(ERROR_NOT_SUPPORTED);
1575                 return FALSE;
1576           }
1577         return TRUE;
1578 #else
1579         FIXME("ioctl not available\n");
1580         SetLastError(ERROR_NOT_SUPPORTED);
1581         return FALSE;
1582 #endif
1583 }
1584
1585 /*****************************************************************************
1586  *      EscapeCommFunction      (KERNEL32.214)
1587  */
1588 BOOL WINAPI EscapeCommFunction(HANDLE handle,UINT nFunction)
1589 {
1590         int fd,direct=FALSE,result=FALSE;
1591         struct termios  port;
1592
1593         TRACE("handle %d, function=%d\n", handle, nFunction);
1594         fd = COMM_GetWriteFd(handle);
1595         if(fd<0)
1596                 return FALSE;
1597
1598         if (tcgetattr(fd,&port) == -1) {
1599                 commerror=WinError();
1600                 close(fd);
1601                 return FALSE;
1602         }
1603
1604         switch (nFunction) {
1605                 case RESETDEV:
1606                         TRACE("\n");
1607                         break;                                  
1608
1609                 case CLRDTR:
1610                         TRACE("CLRDTR\n");
1611 #ifdef TIOCM_DTR
1612                         direct=TRUE;
1613                         result= COMM_WhackModem(fd, ~TIOCM_DTR, 0);
1614                         break;
1615 #endif
1616
1617                 case CLRRTS:
1618                         TRACE("CLRRTS\n");
1619 #ifdef TIOCM_RTS
1620                         direct=TRUE;
1621                         result= COMM_WhackModem(fd, ~TIOCM_RTS, 0);
1622                         break;
1623 #endif
1624         
1625                 case SETDTR:
1626                         TRACE("SETDTR\n");
1627 #ifdef TIOCM_DTR
1628                         direct=TRUE;
1629                         result= COMM_WhackModem(fd, 0, TIOCM_DTR);
1630                         break;
1631 #endif
1632
1633                 case SETRTS:
1634                         TRACE("SETRTS\n");
1635 #ifdef TIOCM_DTR
1636                         direct=TRUE;
1637                         result= COMM_WhackModem(fd, 0, TIOCM_RTS);
1638                         break;
1639 #endif
1640
1641                 case SETXOFF:
1642                         TRACE("SETXOFF\n");
1643                         port.c_iflag |= IXOFF;
1644                         break;
1645
1646                 case SETXON:
1647                         TRACE("SETXON\n");
1648                         port.c_iflag |= IXON;
1649                         break;
1650                 case SETBREAK:
1651                         TRACE("setbreak\n");
1652 #ifdef  TIOCSBRK
1653                         direct=TRUE;
1654                         result = ioctl(fd,TIOCSBRK,0);
1655                         break;
1656 #endif
1657                 case CLRBREAK:
1658                         TRACE("clrbreak\n");
1659 #ifdef  TIOCSBRK
1660                         direct=TRUE;
1661                         result = ioctl(fd,TIOCCBRK,0);
1662                         break;
1663 #endif
1664                 default:
1665                         WARN("(handle=%d,nFunction=%d): Unknown function\n", 
1666                         handle, nFunction);
1667                         break;                          
1668         }
1669         
1670         if (!direct)
1671           if (tcsetattr(fd, TCSADRAIN, &port) == -1) {
1672                 commerror = WinError();
1673                 close(fd);
1674                 return FALSE;   
1675           } else 
1676                 result= TRUE;
1677         else
1678           {
1679             if (result == -1)
1680               {
1681                 result= FALSE;
1682                 commerror=WinError();
1683               }
1684             else
1685               result = TRUE;
1686           }
1687         close(fd);
1688         return result;
1689 }
1690
1691 /********************************************************************
1692  *      PurgeComm        (KERNEL32.557)
1693  */
1694 BOOL WINAPI PurgeComm( HANDLE handle, DWORD flags) 
1695 {
1696      int fd;
1697
1698      TRACE("handle %d, flags %lx\n", handle, flags);
1699
1700      fd = COMM_GetWriteFd(handle);
1701      if(fd<0)
1702          return FALSE;
1703
1704      /*
1705      ** not exactly sure how these are different
1706      ** Perhaps if we had our own internal queues, one flushes them
1707      ** and the other flushes the kernel's buffers.
1708      */
1709      if(flags&PURGE_TXABORT)
1710      {
1711          tcflush(fd,TCOFLUSH);
1712      }
1713      if(flags&PURGE_RXABORT)
1714      {
1715          tcflush(fd,TCIFLUSH);
1716      }
1717      if(flags&PURGE_TXCLEAR)
1718      {
1719          tcflush(fd,TCOFLUSH);
1720      }
1721      if(flags&PURGE_RXCLEAR)
1722      {
1723          tcflush(fd,TCIFLUSH);
1724      }
1725      close(fd);
1726
1727      return 1;
1728 }
1729
1730 /*****************************************************************************
1731  *      ClearCommError  (KERNEL32.21)
1732  */
1733 BOOL WINAPI ClearCommError(INT handle,LPDWORD errors,LPCOMSTAT lpStat)
1734 {
1735     int fd;
1736
1737     fd=COMM_GetReadFd(handle);
1738     if(0>fd) 
1739     {
1740         return FALSE;
1741     }
1742
1743     if (lpStat) 
1744     {
1745         lpStat->status = 0;
1746
1747         if(ioctl(fd, TIOCOUTQ, &lpStat->cbOutQue))
1748             WARN("ioctl returned error\n");
1749
1750         if(ioctl(fd, TIOCINQ, &lpStat->cbInQue))
1751             WARN("ioctl returned error\n");
1752
1753         TRACE("handle %d cbInQue = %ld cbOutQue = %ld\n",
1754               handle, lpStat->cbInQue, lpStat->cbOutQue);
1755     }
1756
1757     close(fd);
1758
1759     if(errors)
1760         *errors = 0;
1761
1762     /*
1763     ** After an asynchronous write opperation, the
1764     ** app will call ClearCommError to see if the
1765     ** results are ready yet. It waits for ERROR_IO_PENDING
1766     */
1767     commerror = ERROR_IO_PENDING;
1768
1769     return TRUE;
1770 }
1771
1772 /*****************************************************************************
1773  *      SetupComm       (KERNEL32.676)
1774  */
1775 BOOL WINAPI SetupComm( HANDLE handle, DWORD insize, DWORD outsize)
1776 {
1777     int fd;
1778
1779     FIXME("insize %ld outsize %ld unimplemented stub\n", insize, outsize);
1780     fd=COMM_GetWriteFd(handle);
1781     if(0>fd)
1782     {
1783         return FALSE;
1784     }
1785     close(fd);
1786     return TRUE;
1787
1788
1789 /*****************************************************************************
1790  *      GetCommMask     (KERNEL32.156)
1791  */
1792 BOOL WINAPI GetCommMask(HANDLE handle,LPDWORD evtmask)
1793 {
1794     int fd;
1795
1796     TRACE("handle %d, mask %p\n", handle, evtmask);
1797     if(0>(fd=COMM_GetReadFd(handle))) 
1798     {
1799         return FALSE;
1800     }
1801     close(fd);
1802     *evtmask = eventmask;
1803     TRACE("%s%s%s%s%s%s%s%s%s\n",
1804           (eventmask&EV_BREAK)?"EV_BREAK":"",
1805           (eventmask&EV_CTS)?"EV_CTS":"",
1806           (eventmask&EV_DSR)?"EV_DSR":"",
1807           (eventmask&EV_ERR)?"EV_ERR":"",
1808           (eventmask&EV_RING)?"EV_RING":"",
1809           (eventmask&EV_RLSD)?"EV_RLSD":"",
1810           (eventmask&EV_RXCHAR)?"EV_RXCHAR":"",
1811           (eventmask&EV_RXFLAG)?"EV_RXFLAG":"",
1812           (eventmask&EV_TXEMPTY)?"EV_TXEMPTY":"");
1813           
1814     return TRUE;
1815 }
1816
1817 /*****************************************************************************
1818  *      SetCommMask     (KERNEL32.451)
1819  */
1820 BOOL WINAPI SetCommMask(INT handle,DWORD evtmask)
1821 {
1822     int fd;
1823
1824     TRACE("handle %d, mask %lx\n", handle, evtmask);
1825     TRACE("%s%s%s%s%s%s%s%s%s\n",
1826           (evtmask&EV_BREAK)?"EV_BREAK":"",
1827           (evtmask&EV_CTS)?"EV_CTS":"",
1828           (evtmask&EV_DSR)?"EV_DSR":"",
1829           (evtmask&EV_ERR)?"EV_ERR":"",
1830           (evtmask&EV_RING)?"EV_RING":"",
1831           (evtmask&EV_RLSD)?"EV_RLSD":"",
1832           (evtmask&EV_RXCHAR)?"EV_RXCHAR":"",
1833           (evtmask&EV_RXFLAG)?"EV_RXFLAG":"",
1834           (evtmask&EV_TXEMPTY)?"EV_TXEMPTY":"");
1835           
1836     if(0>(fd=COMM_GetWriteFd(handle))) {
1837         return FALSE;
1838     }
1839     close(fd);
1840     eventmask = evtmask;
1841     return TRUE;
1842 }
1843
1844 /*****************************************************************************
1845  *      SetCommState    (KERNEL32.452)
1846  */
1847 BOOL WINAPI SetCommState(INT handle,LPDCB lpdcb)
1848 {
1849      struct termios port;
1850      int fd;
1851
1852      TRACE("handle %d, ptr %p\n", handle, lpdcb);
1853      TRACE("bytesize %d baudrate %ld fParity %d Parity %d stopbits %d\n",
1854            lpdcb->ByteSize,lpdcb->BaudRate,lpdcb->fParity, lpdcb->Parity,
1855            (lpdcb->StopBits == ONESTOPBIT)?1:
1856            (lpdcb->StopBits == TWOSTOPBITS)?2:0);
1857      TRACE("%s %s\n",(lpdcb->fInX)?"IXON":"~IXON",
1858            (lpdcb->fOutX)?"IXOFF":"~IXOFF");
1859
1860      if ((fd = COMM_GetWriteFd(handle)) < 0) return FALSE;
1861
1862      if ((tcgetattr(fd,&port)) == -1) {
1863          int save_error = errno;
1864          commerror = WinError();
1865          close( fd );
1866 #ifdef HAVE_STRERROR
1867          ERR("tcgetattr error '%s'\n", strerror(save_error));
1868 #else
1869          ERR("tcgetattr error %d\n", save_error);
1870 #endif
1871          return FALSE;
1872      }
1873
1874         port.c_cc[VMIN] = 0;
1875         port.c_cc[VTIME] = 1;
1876
1877 #ifdef IMAXBEL
1878         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|IMAXBEL);
1879 #else
1880         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR);
1881 #endif
1882         port.c_iflag |= (IGNBRK);
1883
1884         port.c_oflag &= ~(OPOST);
1885
1886         port.c_cflag &= ~(HUPCL);
1887         port.c_cflag |= CLOCAL | CREAD;
1888
1889         port.c_lflag &= ~(ICANON|ECHO|ISIG);
1890         port.c_lflag |= NOFLSH;
1891
1892      /*
1893      ** MJM - removed default baudrate settings
1894      ** TRACE(comm,"baudrate %ld\n",lpdcb->BaudRate);
1895      */
1896 #ifdef CBAUD
1897         port.c_cflag &= ~CBAUD;
1898         switch (lpdcb->BaudRate) {
1899                 case 110:
1900                 case CBR_110:
1901                         port.c_cflag |= B110;
1902                         break;          
1903                 case 300:
1904                 case CBR_300:
1905                         port.c_cflag |= B300;
1906                         break;          
1907                 case 600:
1908                 case CBR_600:
1909                         port.c_cflag |= B600;
1910                         break;          
1911                 case 1200:
1912                 case CBR_1200:
1913                         port.c_cflag |= B1200;
1914                         break;          
1915                 case 2400:
1916                 case CBR_2400:
1917                         port.c_cflag |= B2400;
1918                         break;          
1919                 case 4800:
1920                 case CBR_4800:
1921                         port.c_cflag |= B4800;
1922                         break;          
1923                 case 9600:
1924                 case CBR_9600:
1925                         port.c_cflag |= B9600;
1926                         break;          
1927                 case 19200:
1928                 case CBR_19200:
1929                         port.c_cflag |= B19200;
1930                         break;          
1931                 case 38400:
1932                 case CBR_38400:
1933                         port.c_cflag |= B38400;
1934                         break;          
1935 #ifdef B57600
1936                 case 57600:
1937                         port.c_cflag |= B57600;
1938                         break;          
1939 #endif
1940 #ifdef B115200
1941                 case 115200:
1942                         port.c_cflag |= B115200;
1943                         break;          
1944 #endif
1945 #ifdef B230400
1946                 case 230400:
1947                         port.c_cflag |= B230400;
1948                         break;          
1949 #endif
1950 #ifdef B460800
1951                 case 460600:
1952                         port.c_cflag |= B460800;
1953                         break;          
1954 #endif
1955                 default:
1956                         commerror = IE_BAUDRATE;
1957                         close( fd );
1958                         ERR("baudrate %ld\n",lpdcb->BaudRate);
1959                         return FALSE;
1960         }
1961 #elif !defined(__EMX__)
1962         switch (lpdcb->BaudRate) {
1963                 case 110:
1964                 case CBR_110:
1965                         port.c_ospeed = B110;
1966                         break;
1967                 case 300:
1968                 case CBR_300:
1969                         port.c_ospeed = B300;
1970                         break;
1971                 case 600:
1972                 case CBR_600:
1973                         port.c_ospeed = B600;
1974                         break;
1975                 case 1200:
1976                 case CBR_1200:
1977                         port.c_ospeed = B1200;
1978                         break;
1979                 case 2400:
1980                 case CBR_2400:
1981                         port.c_ospeed = B2400;
1982                         break;
1983                 case 4800:
1984                 case CBR_4800:
1985                         port.c_ospeed = B4800;
1986                         break;
1987                 case 9600:
1988                 case CBR_9600:
1989                         port.c_ospeed = B9600;
1990                         break;
1991                 case 19200:
1992                 case CBR_19200:
1993                         port.c_ospeed = B19200;
1994                         break;
1995                 case 38400:
1996                 case CBR_38400:
1997                         port.c_ospeed = B38400;
1998                         break;
1999                 default:
2000                         commerror = IE_BAUDRATE;
2001                         close( fd );
2002                         ERR("baudrate %d \n",lpdcb->BaudRate);
2003                         return FALSE;
2004         }
2005         port.c_ispeed = port.c_ospeed;
2006 #endif
2007         port.c_cflag &= ~CSIZE;
2008         switch (lpdcb->ByteSize) {
2009                 case 5:
2010                         port.c_cflag |= CS5;
2011                         break;
2012                 case 6:
2013                         port.c_cflag |= CS6;
2014                         break;
2015                 case 7:
2016                         port.c_cflag |= CS7;
2017                         break;
2018                 case 8:
2019                         port.c_cflag |= CS8;
2020                         break;
2021                 default:
2022                         commerror = IE_BYTESIZE;
2023                         close( fd );
2024                         ERR("ByteSize\n");
2025                         return FALSE;
2026         }
2027
2028         port.c_cflag &= ~(PARENB | PARODD);
2029         if (lpdcb->fParity)
2030             port.c_iflag |= INPCK;
2031         else
2032             port.c_iflag &= ~INPCK;
2033         switch (lpdcb->Parity) {
2034                 case NOPARITY:
2035                         break;
2036                 case ODDPARITY:
2037                         port.c_cflag |= (PARENB | PARODD);
2038                         break;
2039                 case EVENPARITY:
2040                         port.c_cflag |= PARENB;
2041                         break;
2042                 default:
2043                         commerror = IE_BYTESIZE;
2044                         close( fd );
2045                         ERR("Parity\n");
2046                         return FALSE;
2047         }
2048         
2049
2050         switch (lpdcb->StopBits) {
2051                 case ONESTOPBIT:
2052                                 port.c_cflag &= ~CSTOPB;
2053                                 break;
2054                 case TWOSTOPBITS:
2055                                 port.c_cflag |= CSTOPB;
2056                                 break;
2057                 default:
2058                         commerror = IE_BYTESIZE;
2059                         close( fd );
2060                         ERR("StopBits\n");
2061                         return FALSE;
2062         }
2063 #ifdef CRTSCTS
2064         if (    lpdcb->fOutxCtsFlow                     ||
2065                 lpdcb->fDtrControl == DTR_CONTROL_ENABLE||
2066                 lpdcb->fRtsControl == RTS_CONTROL_ENABLE
2067         ) 
2068           {
2069             port.c_cflag |= CRTSCTS;
2070             TRACE("CRTSCTS\n");
2071           }
2072         
2073         if (lpdcb->fDtrControl == DTR_CONTROL_DISABLE)
2074           {
2075             port.c_cflag &= ~CRTSCTS;
2076             TRACE("~CRTSCTS\n");
2077           }
2078
2079 #endif  
2080         if (lpdcb->fInX)
2081                 port.c_iflag |= IXON;
2082         else
2083                 port.c_iflag &= ~IXON;
2084         if (lpdcb->fOutX)
2085                 port.c_iflag |= IXOFF;
2086         else
2087                 port.c_iflag &= ~IXOFF;
2088
2089         if (tcsetattr(fd,TCSANOW,&port)==-1) { /* otherwise it hangs with pending input*/
2090                 int save_error=errno;
2091                 commerror = WinError(); 
2092                 close( fd );
2093 #ifdef HAVE_STRERROR
2094                 ERR("tcgetattr error '%s'\n", strerror(save_error));
2095 #else
2096                 ERR("tcgetattr error %d\n", save_error);
2097 #endif
2098                 return FALSE;
2099         } else {
2100                 commerror = 0;
2101                 close( fd );
2102                 return TRUE;
2103         }
2104 }
2105
2106
2107 /*****************************************************************************
2108  *      GetCommState    (KERNEL32.159)
2109  */
2110 BOOL WINAPI GetCommState(INT handle, LPDCB lpdcb)
2111 {
2112      struct termios port;
2113      int fd,speed;
2114
2115      TRACE("handle %d, ptr %p\n", handle, lpdcb);
2116
2117      if ((fd = COMM_GetReadFd(handle)) < 0) 
2118        {
2119          ERR("can't get COMM_GetReadFd\n");
2120          return FALSE;
2121        }
2122      if (tcgetattr(fd, &port) == -1) {
2123                 int save_error=errno;
2124 #ifdef HAVE_STRERROR
2125                 ERR("tcgetattr error '%s'\n", strerror(save_error));
2126 #else
2127                 ERR("tcgetattr error %d\n", save_error);
2128 #endif
2129                 commerror = WinError(); 
2130                 close( fd );
2131                 return FALSE;
2132         }
2133      close( fd );
2134 #ifndef __EMX__
2135 #ifdef CBAUD
2136      speed= (port.c_cflag & CBAUD);
2137 #else
2138      speed= (cfgetospeed(&port));
2139 #endif
2140      switch (speed) {
2141                 case B110:
2142                         lpdcb->BaudRate = 110;
2143                         break;
2144                 case B300:
2145                         lpdcb->BaudRate = 300;
2146                         break;
2147                 case B600:
2148                         lpdcb->BaudRate = 600;
2149                         break;
2150                 case B1200:
2151                         lpdcb->BaudRate = 1200;
2152                         break;
2153                 case B2400:
2154                         lpdcb->BaudRate = 2400;
2155                         break;
2156                 case B4800:
2157                         lpdcb->BaudRate = 4800;
2158                         break;
2159                 case B9600:
2160                         lpdcb->BaudRate = 9600;
2161                         break;
2162                 case B19200:
2163                         lpdcb->BaudRate = 19200;
2164                         break;
2165                 case B38400:
2166                         lpdcb->BaudRate = 38400;
2167                         break;
2168 #ifdef B57600
2169                 case B57600:
2170                         lpdcb->BaudRate = 57600;
2171                         break;          
2172 #endif
2173 #ifdef B115200
2174                 case B115200:
2175                         lpdcb->BaudRate = 115200;
2176                         break;          
2177 #endif
2178 #ifdef B230400
2179                 case B230400:
2180                         lpdcb->BaudRate = 230400;
2181                         break;          
2182 #endif
2183 #ifdef B460800
2184                 case B460800:
2185                         lpdcb->BaudRate = 460800;
2186                         break;          
2187 #endif
2188                 default:
2189                         ERR("unknown speed %x \n",speed);
2190         }
2191 #endif
2192         switch (port.c_cflag & CSIZE) {
2193                 case CS5:
2194                         lpdcb->ByteSize = 5;
2195                         break;
2196                 case CS6:
2197                         lpdcb->ByteSize = 6;
2198                         break;
2199                 case CS7:
2200                         lpdcb->ByteSize = 7;
2201                         break;
2202                 case CS8:
2203                         lpdcb->ByteSize = 8;
2204                         break;
2205                 default:
2206                         ERR("unknown size %x \n",port.c_cflag & CSIZE);
2207         }       
2208         
2209         if(port.c_iflag & INPCK)
2210             lpdcb->fParity = TRUE;
2211         else
2212             lpdcb->fParity = FALSE;
2213         switch (port.c_cflag & (PARENB | PARODD)) {
2214                 case 0:
2215                         lpdcb->Parity = NOPARITY;
2216                         break;
2217                 case PARENB:
2218                         lpdcb->Parity = EVENPARITY;
2219                         break;
2220                 case (PARENB | PARODD):
2221                         lpdcb->Parity = ODDPARITY;              
2222                         break;
2223         }
2224
2225         if (port.c_cflag & CSTOPB)
2226                 lpdcb->StopBits = TWOSTOPBITS;
2227         else
2228                 lpdcb->StopBits = ONESTOPBIT;
2229
2230         lpdcb->fNull = 0;
2231         lpdcb->fBinary = 1;
2232
2233 #ifdef CRTSCTS
2234
2235         if (port.c_cflag & CRTSCTS) {
2236                 lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
2237                 lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
2238                 lpdcb->fOutxCtsFlow = 1;
2239                 lpdcb->fOutxDsrFlow = 1;
2240         } else 
2241 #endif
2242         {
2243                 lpdcb->fDtrControl = DTR_CONTROL_DISABLE;
2244                 lpdcb->fRtsControl = RTS_CONTROL_DISABLE;
2245         }
2246         if (port.c_iflag & IXON)
2247                 lpdcb->fInX = 1;
2248         else
2249                 lpdcb->fInX = 0;
2250
2251         if (port.c_iflag & IXOFF)
2252                 lpdcb->fOutX = 1;
2253         else
2254                 lpdcb->fOutX = 0;
2255 /*
2256         lpdcb->XonChar = 
2257         lpdcb->XoffChar = 
2258  */
2259         lpdcb->XonLim = 10;
2260         lpdcb->XoffLim = 10;
2261
2262         commerror = 0;
2263
2264         TRACE("OK\n");
2265  
2266         TRACE("bytesize %d baudrate %ld fParity %d Parity %d stopbits %d\n",
2267               lpdcb->ByteSize,lpdcb->BaudRate,lpdcb->fParity, lpdcb->Parity,
2268               (lpdcb->StopBits == ONESTOPBIT)?1:
2269               (lpdcb->StopBits == TWOSTOPBITS)?2:0);
2270         TRACE("%s %s\n",(lpdcb->fInX)?"IXON":"~IXON",
2271               (lpdcb->fOutX)?"IXOFF":"~IXOFF");
2272 #ifdef CRTSCTS
2273         if (    lpdcb->fOutxCtsFlow                     ||
2274                 lpdcb->fDtrControl == DTR_CONTROL_ENABLE||
2275                 lpdcb->fRtsControl == RTS_CONTROL_ENABLE
2276                 ) 
2277           TRACE("CRTSCTS\n");
2278         
2279         if (lpdcb->fDtrControl == DTR_CONTROL_DISABLE)
2280           TRACE("~CRTSCTS\n");
2281         
2282 #endif  
2283         return TRUE;
2284 }
2285
2286 /*****************************************************************************
2287  *      TransmitCommChar        (KERNEL32.535)
2288  */
2289 BOOL WINAPI TransmitCommChar(INT cid,CHAR chTransmit)
2290 {
2291         struct DosDeviceStruct *ptr;
2292
2293         FIXME("(%d,'%c'), use win32 handle!\n",cid,chTransmit);
2294         if ((ptr = GetDeviceStruct(cid)) == NULL) {
2295                 return FALSE;
2296         }
2297
2298         if (ptr->suspended) {
2299                 ptr->commerror = IE_HARDWARE;
2300                 return FALSE;
2301         }
2302         if (write(ptr->fd, (void *) &chTransmit, 1) == -1) {
2303                 ptr->commerror = WinError();
2304                 return FALSE;
2305         }  else {
2306                 ptr->commerror = 0;
2307                 return TRUE;
2308         }
2309 }
2310
2311 /*****************************************************************************
2312  *      GetCommTimeouts         (KERNEL32.160)
2313  */
2314 BOOL WINAPI GetCommTimeouts(INT cid,LPCOMMTIMEOUTS lptimeouts)
2315 {
2316         FIXME("(%x,%p):stub.\n",cid,lptimeouts);
2317         return TRUE;
2318 }
2319
2320 /*****************************************************************************
2321  *      SetCommTimeouts         (KERNEL32.453)
2322  */
2323 BOOL WINAPI SetCommTimeouts(INT cid,LPCOMMTIMEOUTS lptimeouts) {
2324         FIXME("(%x,%p):stub.\n",cid,lptimeouts);
2325         TRACE("ReadIntervalTimeout %ld\n",lptimeouts->ReadIntervalTimeout);
2326         TRACE("ReadTotalTimeoutMultiplier %ld\n",
2327               lptimeouts->ReadTotalTimeoutMultiplier);
2328         TRACE("ReadTotalTimeoutConstant %ld\n",
2329               lptimeouts->ReadTotalTimeoutConstant);
2330         TRACE("WriteTotalTimeoutMultiplier %ld\n",
2331               lptimeouts->WriteTotalTimeoutMultiplier);
2332         TRACE("WriteTotalTimeoutConstant %ld\n",
2333               lptimeouts->WriteTotalTimeoutConstant);
2334         return TRUE;
2335 }
2336
2337 /***********************************************************************
2338  *           GetCommModemStatus   (KERNEL32.285)
2339  */
2340 BOOL WINAPI GetCommModemStatus(HANDLE hFile,LPDWORD lpModemStat )
2341 {
2342         int fd,mstat, result=FALSE;
2343         
2344         *lpModemStat=0;
2345 #ifdef TIOCMGET
2346         fd = COMM_GetWriteFd(hFile);
2347         if(fd<0)
2348                 return FALSE;
2349         result = ioctl(fd, TIOCMGET, &mstat);
2350         close(fd);
2351         if (result == -1)
2352           {
2353             TRACE("ioctl failed\n");
2354             return FALSE;
2355           }
2356         if (mstat & TIOCM_CTS)
2357             *lpModemStat |= MS_CTS_ON;
2358         if (mstat & TIOCM_DSR)
2359           *lpModemStat |= MS_DSR_ON;
2360         if (mstat & TIOCM_RNG)
2361           *lpModemStat |= MS_RING_ON;
2362         /*FIXME:  Not really sure about RLSD  UB 990810*/
2363         if (mstat & TIOCM_CAR)
2364           *lpModemStat |= MS_RLSD_ON;
2365         TRACE("%s%s%s%s\n",
2366               (*lpModemStat &MS_RLSD_ON)?"MS_RLSD_ON ":"",
2367               (*lpModemStat &MS_RING_ON)?"MS_RING_ON ":"",
2368               (*lpModemStat &MS_DSR_ON)?"MS_DSR_ON ":"",
2369               (*lpModemStat &MS_CTS_ON)?"MS_CTS_ON ":"");
2370         return TRUE;
2371 #else
2372         return FALSE;
2373 #endif
2374 }
2375 /***********************************************************************
2376  *           WaitCommEvent   (KERNEL32.719)
2377  */
2378 BOOL WINAPI WaitCommEvent(HANDLE hFile,LPDWORD eventmask ,LPOVERLAPPED overlapped)
2379 {
2380         FIXME("(%d %p %p )\n",hFile, eventmask,overlapped);
2381         return TRUE;
2382 }
2383
2384 /***********************************************************************
2385  *           GetCommProperties   (KERNEL32.???)
2386  */
2387 BOOL WINAPI GetCommProperties(HANDLE hFile, LPDCB *dcb)
2388 {
2389     FIXME("(%d %p )\n",hFile,dcb);
2390     return TRUE;
2391 }
2392
2393 /***********************************************************************
2394  *           SetCommProperties   (KERNEL32.???)
2395  */
2396 BOOL WINAPI SetCommProperties(HANDLE hFile, LPDCB dcb)
2397 {
2398     FIXME("(%d %p )\n",hFile,dcb);
2399     return TRUE;
2400 }
2401