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