Removed some unnecessary includes.
[wine] / dlls / kernel / 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 #ifdef HAVE_SYS_MODEM_H
56 # include <sys/modem.h>
57 #endif
58 #ifdef HAVE_SYS_STRTIO_H
59 # include <sys/strtio.h>
60 #endif
61 #include "heap.h"
62 #include "options.h"
63 #include "wine/port.h"
64 #include "server.h"
65 #include "winerror.h"
66 #include "services.h"
67 #include "callback.h"
68 #include "file.h"
69
70 #include "debugtools.h"
71
72 DEFAULT_DEBUG_CHANNEL(comm);
73
74 #if !defined(TIOCINQ) && defined(FIONREAD)
75 #define TIOCINQ FIONREAD
76 #endif
77
78 /* window's semi documented modem status register */
79 #define COMM_MSR_OFFSET  35
80 #define MSR_CTS  0x10
81 #define MSR_DSR  0x20
82 #define MSR_RI   0x40
83 #define MSR_RLSD 0x80
84 #define MSR_MASK (MSR_CTS|MSR_DSR|MSR_RI|MSR_RLSD)
85
86 #define FLAG_LPT 0x80
87
88 #ifdef linux
89 #define CMSPAR 0x40000000 /* stick parity */
90 #endif
91
92 #define MAX_PORTS   9
93
94 struct DosDeviceStruct {
95     char *devicename;   /* /dev/cua1 */
96     int fd;
97     int suspended;
98     int unget,xmit;
99     int baudrate;
100     int evtchar;
101     /* events */
102     int commerror, eventmask;
103     /* buffers */
104     char *inbuf,*outbuf;
105     unsigned ibuf_size,ibuf_head,ibuf_tail;
106     unsigned obuf_size,obuf_head,obuf_tail;
107     /* notifications */
108     int wnd, n_read, n_write;
109     HANDLE s_read, s_write;
110 };
111
112
113 static struct DosDeviceStruct COM[MAX_PORTS];
114 static struct DosDeviceStruct LPT[MAX_PORTS];
115 /* pointers to unknown(==undocumented) comm structure */ 
116 static LPCVOID *unknown[MAX_PORTS];
117 /* save terminal states */
118 static struct termios m_stat[MAX_PORTS];
119
120 /* update window's semi documented modem status register */
121 /* see knowledge base Q101417 */
122 static void COMM_MSRUpdate( UCHAR * pMsr, unsigned int mstat)
123 {
124     UCHAR tmpmsr=0;
125 #ifdef TIOCM_CTS
126     if(mstat & TIOCM_CTS) tmpmsr |= MSR_CTS;
127 #endif
128 #ifdef TIOCM_DSR
129     if(mstat & TIOCM_DSR) tmpmsr |= MSR_DSR;
130 #endif
131 #ifdef TIOCM_RI
132     if(mstat & TIOCM_RI)  tmpmsr |= MSR_RI;
133 #endif
134 #ifdef TIOCM_CAR
135     if(mstat & TIOCM_CAR) tmpmsr |= MSR_RLSD;
136 #endif
137     *pMsr = (*pMsr & ~MSR_MASK) | tmpmsr;
138 }
139
140 void COMM_Init(void)
141 {
142         int x;
143         char option[10], temp[256], *btemp;
144         struct stat st;
145
146         for (x=0; x!=MAX_PORTS; x++) {
147                 strcpy(option,"COMx");
148                 option[3] = '1' + x;
149                 option[4] = '\0';
150
151                 PROFILE_GetWineIniString( "serialports", option, "*",
152                                           temp, sizeof(temp) );
153                 if (!strcmp(temp, "*") || *temp == '\0') 
154                         COM[x].devicename = NULL;
155                 else {
156                         btemp = strchr(temp,',');
157                         if (btemp != NULL) {
158                                 *btemp++ = '\0';
159                                 COM[x].baudrate = atoi(btemp);
160                         } else {
161                                 COM[x].baudrate = -1;
162                         }
163                         stat(temp, &st);
164                         if (!S_ISCHR(st.st_mode)) 
165                                 WARN("Can't use `%s' as %s !\n", temp, option);
166                         else
167                                 if ((COM[x].devicename = malloc(strlen(temp)+1)) == NULL) 
168                                         WARN("Can't malloc for device info!\n");
169                                 else {
170                                         COM[x].fd = 0;
171                                         strcpy(COM[x].devicename, temp);
172                                 }
173                 TRACE("%s = %s\n", option, COM[x].devicename);
174                 }
175
176                 strcpy(option, "LPTx");
177                 option[3] = '1' + x;
178                 option[4] = '\0';
179
180                 PROFILE_GetWineIniString( "parallelports", option, "*",
181                                           temp, sizeof(temp) );
182                 if (!strcmp(temp, "*") || *temp == '\0')
183                         LPT[x].devicename = NULL;
184                 else {
185                         stat(temp, &st);
186                         if (!S_ISCHR(st.st_mode)) 
187                                 WARN("Can't use `%s' as %s !\n", temp, option);
188                         else 
189                                 if ((LPT[x].devicename = malloc(strlen(temp)+1)) == NULL) 
190                                         WARN("Can't malloc for device info!\n");
191                                 else {
192                                         LPT[x].fd = 0;
193                                         strcpy(LPT[x].devicename, temp);
194                                 }
195                 TRACE("%s = %s\n", option, LPT[x].devicename);
196                 }
197
198         }
199 }
200
201
202 static struct DosDeviceStruct *GetDeviceStruct(int fd)
203 {
204         if ((fd&0x7F)<=MAX_PORTS) {
205             if (!(fd&FLAG_LPT)) {
206                 if (COM[fd].fd)
207                     return &COM[fd];
208             } else {
209                 fd &= 0x7f;
210                 if (LPT[fd].fd)
211                     return &LPT[fd];
212             }
213         }
214
215         return NULL;
216 }
217
218 static int    GetCommPort_fd(int fd)
219 {
220         int x;
221         
222         for (x=0; x<MAX_PORTS; x++) {
223              if (COM[x].fd == fd)
224                  return x;
225        }
226        
227        return -1;
228
229
230 static int ValidCOMPort(int x)
231 {
232         return(x < MAX_PORTS ? (int) COM[x].devicename : 0); 
233 }
234
235 static int ValidLPTPort(int x)
236 {
237         return(x < MAX_PORTS ? (int) LPT[x].devicename : 0); 
238 }
239
240 static int WinError(void)
241 {
242         TRACE("errno = %d\n", errno);
243         switch (errno) {
244                 default:
245                         return CE_IOE;
246                 }
247 }
248
249 static unsigned comm_inbuf(struct DosDeviceStruct *ptr)
250 {
251   return ((ptr->ibuf_tail > ptr->ibuf_head) ? ptr->ibuf_size : 0)
252     + ptr->ibuf_head - ptr->ibuf_tail;
253 }
254
255 static unsigned comm_outbuf(struct DosDeviceStruct *ptr)
256 {
257   return ((ptr->obuf_tail > ptr->obuf_head) ? ptr->obuf_size : 0)
258     + ptr->obuf_head - ptr->obuf_tail;
259 }
260
261 static int COMM_WhackModem(int fd, unsigned int andy, unsigned int orrie)
262 {
263     unsigned int mstat, okay;
264     okay = ioctl(fd, TIOCMGET, &mstat);
265     if (okay) return okay;
266     if (andy) mstat &= andy;
267     mstat |= orrie;
268     return ioctl(fd, TIOCMSET, &mstat);
269 }
270         
271 static void CALLBACK comm_notification( ULONG_PTR private )
272 {
273   struct DosDeviceStruct *ptr = (struct DosDeviceStruct *)private;
274   int prev, bleft, len;
275   WORD mask = 0;
276   int cid = GetCommPort_fd(ptr->fd);
277
278   TRACE("async notification\n");
279   /* read data from comm port */
280   prev = comm_inbuf(ptr);
281   do {
282     bleft = ((ptr->ibuf_tail > ptr->ibuf_head) ? (ptr->ibuf_tail-1) : ptr->ibuf_size)
283       - ptr->ibuf_head;
284     len = read(ptr->fd, ptr->inbuf + ptr->ibuf_head, bleft?bleft:1);
285     if (len > 0) {
286       if (!bleft) {
287         ptr->commerror = CE_RXOVER;
288       } else {
289         /* check for events */
290         if ((ptr->eventmask & EV_RXFLAG) &&
291             memchr(ptr->inbuf + ptr->ibuf_head, ptr->evtchar, len)) {
292           *(WORD*)(unknown[cid]) |= EV_RXFLAG;
293           mask |= CN_EVENT;
294         }
295         if (ptr->eventmask & EV_RXCHAR) {
296           *(WORD*)(unknown[cid]) |= EV_RXCHAR;
297           mask |= CN_EVENT;
298         }
299         /* advance buffer position */
300         ptr->ibuf_head += len;
301         if (ptr->ibuf_head >= ptr->ibuf_size)
302           ptr->ibuf_head = 0;
303       }
304     }
305   } while (len > 0);
306   /* check for notification */
307   if (ptr->wnd && (ptr->n_read>0) && (prev<ptr->n_read) &&
308       (comm_inbuf(ptr)>=ptr->n_read)) {
309     /* passed the receive notification threshold */
310     mask |= CN_RECEIVE;
311   }
312
313   /* write any TransmitCommChar character */
314   if (ptr->xmit>=0) {
315     len = write(ptr->fd, &(ptr->xmit), 1);
316     if (len > 0) ptr->xmit = -1;
317   }
318   /* write from output queue */
319   prev = comm_outbuf(ptr);
320   do {
321     bleft = ((ptr->obuf_tail <= ptr->obuf_head) ? ptr->obuf_head : ptr->obuf_size)
322       - ptr->obuf_tail;
323     len = bleft ? write(ptr->fd, ptr->outbuf + ptr->obuf_tail, bleft) : 0;
324     if (len > 0) {
325       ptr->obuf_tail += len;
326       if (ptr->obuf_tail >= ptr->obuf_size)
327         ptr->obuf_tail = 0;
328       /* flag event */
329       if (ptr->obuf_tail == ptr->obuf_head) {
330         if (ptr->s_write) {
331           SERVICE_Delete( ptr->s_write );
332           ptr->s_write = INVALID_HANDLE_VALUE;
333         }
334         if (ptr->eventmask & EV_TXEMPTY) {
335           *(WORD*)(unknown[cid]) |= EV_TXEMPTY;
336           mask |= CN_EVENT;
337         }
338       }
339     }
340   } while (len > 0);
341   /* check for notification */
342   if (ptr->wnd && (ptr->n_write>0) && (prev>=ptr->n_write) &&
343       (comm_outbuf(ptr)<ptr->n_write)) {
344     /* passed the transmit notification threshold */
345     mask |= CN_TRANSMIT;
346   }
347
348   /* send notifications, if any */
349   if (ptr->wnd && mask) {
350     TRACE("notifying %04x: cid=%d, mask=%02x\n", ptr->wnd, cid, mask);
351     if (Callout.PostMessageA) Callout.PostMessageA(ptr->wnd, WM_COMMNOTIFY, cid, mask);
352   }
353 }
354
355 static void comm_waitread(struct DosDeviceStruct *ptr)
356 {
357   if (ptr->s_read != INVALID_HANDLE_VALUE) return;
358   ptr->s_read = SERVICE_AddObject( FILE_DupUnixHandle( ptr->fd,
359                                      GENERIC_READ | SYNCHRONIZE ),
360                                     comm_notification,
361                                     (ULONG_PTR)ptr );
362 }
363
364 static void comm_waitwrite(struct DosDeviceStruct *ptr)
365 {
366   if (ptr->s_write != INVALID_HANDLE_VALUE) return;
367   ptr->s_write = SERVICE_AddObject( FILE_DupUnixHandle( ptr->fd,
368                                       GENERIC_WRITE | SYNCHRONIZE ),
369                                      comm_notification,
370                                      (ULONG_PTR)ptr );
371 }
372
373 /**************************************************************************
374  *         BuildCommDCB16               (USER.213)
375  *
376  * According to the ECMA-234 (368.3) the function will return FALSE on 
377  * success, otherwise it will return -1. 
378  * IF THIS IS NOT CORRECT THE RETURNVALUE CHECK IN BuildCommDCBAndTimeoutsA
379  * NEEDS TO BE FIXED
380  */
381 BOOL16 WINAPI BuildCommDCB16(LPCSTR device, LPDCB16 lpdcb)
382 {
383         /* "COM1:9600,n,8,1"    */
384         /*  012345              */
385         int port;
386         char *ptr, temp[256];
387
388         TRACE("(%s), ptr %p\n", device, lpdcb);
389
390         if (!strncasecmp(device,"COM",3)) {
391                 port = device[3] - '0';
392         
393
394                 if (port-- == 0) {
395                         ERR("BUG ! COM0 can't exist!.\n");
396                         return -1;
397                 }
398
399                 if (!ValidCOMPort(port)) {
400                         FIXME("invalid COM port %d?\n",port);
401                         return -1;
402                 }
403                 
404                 memset(lpdcb, 0, sizeof(DCB16)); /* initialize */
405
406                 lpdcb->Id = port;
407                 
408                 if (!*(device+4))
409                         return 0;
410
411                 if (*(device+4) != ':')
412                         return -1;
413                 
414                 strcpy(temp,device+5);
415                 ptr = strtok(temp, ", "); 
416
417                 if (COM[port].baudrate > 0)
418                         lpdcb->BaudRate = COM[port].baudrate;
419                 else
420                         lpdcb->BaudRate = atoi(ptr);
421                 TRACE("baudrate (%d)\n", lpdcb->BaudRate);
422
423                 ptr = strtok(NULL, ", ");
424                 if (islower(*ptr))
425                         *ptr = toupper(*ptr);
426
427                 TRACE("parity (%c)\n", *ptr);
428                 lpdcb->fParity = TRUE;
429                 switch (*ptr) {
430                         case 'N':
431                                 lpdcb->Parity = NOPARITY;
432                                 lpdcb->fParity = FALSE;
433                                 break;                  
434                         case 'E':
435                                 lpdcb->Parity = EVENPARITY;
436                                 break;                  
437                         case 'M':
438                                 lpdcb->Parity = MARKPARITY;
439                                 break;                  
440                         case 'O':
441                                 lpdcb->Parity = ODDPARITY;
442                                 break;                  
443                         default:
444                                 WARN("Unknown parity `%c'!\n", *ptr);
445                                 return -1;
446                 }
447
448                 ptr = strtok(NULL, ", "); 
449                 TRACE("charsize (%c)\n", *ptr);
450                 lpdcb->ByteSize = *ptr - '0';
451
452                 ptr = strtok(NULL, ", ");
453                 TRACE("stopbits (%c)\n", *ptr);
454                 switch (*ptr) {
455                         case '1':
456                                 lpdcb->StopBits = ONESTOPBIT;
457                                 break;                  
458                         case '2':
459                                 lpdcb->StopBits = TWOSTOPBITS;
460                                 break;                  
461                         default:
462                                 WARN("Unknown # of stopbits `%c'!\n", *ptr);
463                                 return -1;
464                 }
465         }       
466
467         return 0;
468 }
469
470 /*****************************************************************************
471  *      OpenComm16              (USER.200)
472  */
473 INT16 WINAPI OpenComm16(LPCSTR device,UINT16 cbInQueue,UINT16 cbOutQueue)
474 {
475         int port,fd;
476
477         TRACE("%s, %d, %d\n", device, cbInQueue, cbOutQueue);
478
479         if (strlen(device) < 4)
480            return IE_BADID;
481
482         port = device[3] - '0';
483
484         if (port-- == 0)
485                 ERR("BUG ! COM0 or LPT0 don't exist !\n");
486
487         if (!strncasecmp(device,"COM",3)) {
488                 
489                 TRACE("%s = %s\n", device, COM[port].devicename);
490
491                 if (!ValidCOMPort(port))
492                         return IE_BADID;
493
494                 if (COM[port].fd)
495                         return IE_OPEN;
496
497                 fd = open(COM[port].devicename, O_RDWR | O_NONBLOCK);
498                 if (fd == -1) {
499                         ERR("Couldn't open %s ! (%s)\n", COM[port].devicename, strerror(errno));
500                         return IE_HARDWARE;
501                 } else {
502                         unknown[port] = SEGPTR_ALLOC(40);
503                         bzero(unknown[port],40);
504                         COM[port].fd = fd;
505                         COM[port].commerror = 0;
506                         COM[port].eventmask = 0;
507                         COM[port].evtchar = 0; /* FIXME: default? */
508                         /* save terminal state */
509                         tcgetattr(fd,&m_stat[port]);
510                         /* set default parameters */
511                         if(COM[port].baudrate>-1){
512                             DCB16 dcb;
513                             GetCommState16(port, &dcb);
514                             dcb.BaudRate=COM[port].baudrate;
515                             /* more defaults:
516                              * databits, parity, stopbits
517                              */
518                             SetCommState16( &dcb);
519                         }
520                         /* init priority characters */
521                         COM[port].unget = -1;
522                         COM[port].xmit = -1;
523                         /* allocate buffers */
524                         COM[port].ibuf_size = cbInQueue;
525                         COM[port].ibuf_head = COM[port].ibuf_tail= 0;
526                         COM[port].obuf_size = cbOutQueue;
527                         COM[port].obuf_head = COM[port].obuf_tail = 0;
528
529                         COM[port].inbuf = malloc(cbInQueue);
530                         if (COM[port].inbuf) {
531                           COM[port].outbuf = malloc(cbOutQueue);
532                           if (!COM[port].outbuf)
533                             free(COM[port].inbuf);
534                         } else COM[port].outbuf = NULL;
535                         if (!COM[port].outbuf) {
536                           /* not enough memory */
537                           tcsetattr(COM[port].fd,TCSANOW,&m_stat[port]);
538                           close(COM[port].fd);
539                           ERR("out of memory\n");
540                           return IE_MEMORY;
541                         }
542
543                         COM[port].s_read = INVALID_HANDLE_VALUE;
544                         COM[port].s_write = INVALID_HANDLE_VALUE;
545                         comm_waitread( &COM[port] );
546                         return port;
547                 }
548         } 
549         else 
550         if (!strncasecmp(device,"LPT",3)) {
551         
552                 if (!ValidLPTPort(port))
553                         return IE_BADID;
554
555                 if (LPT[port].fd)
556                         return IE_OPEN;
557
558                 fd = open(LPT[port].devicename, O_RDWR | O_NONBLOCK, 0);
559                 if (fd == -1) {
560                         return IE_HARDWARE;
561                 } else {
562                         LPT[port].fd = fd;
563                         LPT[port].commerror = 0;
564                         LPT[port].eventmask = 0;
565                         return port|FLAG_LPT;
566                 }
567         }
568         return 0;
569 }
570
571 /*****************************************************************************
572  *      CloseComm16             (USER.207)
573  */
574 INT16 WINAPI CloseComm16(INT16 cid)
575 {
576         struct DosDeviceStruct *ptr;
577         
578         TRACE("cid=%d\n", cid);
579         if ((ptr = GetDeviceStruct(cid)) == NULL) {
580                 FIXME("no cid=%d found!\n", cid);
581                 return -1;
582         }
583         if (!(cid&FLAG_LPT)) {
584                 /* COM port */
585                 SEGPTR_FREE(unknown[cid]); /* [LW] */
586
587                 SERVICE_Delete( COM[cid].s_write );
588                 SERVICE_Delete( COM[cid].s_read );
589                 /* free buffers */
590                 free(ptr->outbuf);
591                 free(ptr->inbuf);
592
593                 /* reset modem lines */
594                 tcsetattr(ptr->fd,TCSANOW,&m_stat[cid]);
595         }
596
597         if (close(ptr->fd) == -1) {
598                 ptr->commerror = WinError();
599                 /* FIXME: should we clear ptr->fd here? */
600                 return -1;
601         } else {
602                 ptr->commerror = 0;
603                 ptr->fd = 0;
604                 return 0;
605         }
606 }
607
608 /*****************************************************************************
609  *      SetCommBreak16          (USER.210)
610  */
611 INT16 WINAPI SetCommBreak16(INT16 cid)
612 {
613         struct DosDeviceStruct *ptr;
614
615         TRACE("cid=%d\n", cid);
616         if ((ptr = GetDeviceStruct(cid)) == NULL) {
617                 FIXME("no cid=%d found!\n", cid);
618                 return -1;
619         }
620
621         ptr->suspended = 1;
622         ptr->commerror = 0;
623         return 0;
624 }
625
626 /*****************************************************************************
627  *      ClearCommBreak16        (USER.211)
628  */
629 INT16 WINAPI ClearCommBreak16(INT16 cid)
630 {
631         struct DosDeviceStruct *ptr;
632
633         TRACE("cid=%d\n", cid);
634         if (!(ptr = GetDeviceStruct(cid))) {
635                 FIXME("no cid=%d found!\n", cid);
636                 return -1;
637         }
638         ptr->suspended = 0;
639         ptr->commerror = 0;
640         return 0;
641 }
642
643 /*****************************************************************************
644  *      EscapeCommFunction16    (USER.214)
645  */
646 LONG WINAPI EscapeCommFunction16(UINT16 cid,UINT16 nFunction)
647 {
648         int     max;
649         struct DosDeviceStruct *ptr;
650         struct termios port;
651
652         TRACE("cid=%d, function=%d\n", cid, nFunction);
653         if ((nFunction != GETMAXCOM) && (nFunction != GETMAXLPT)) {
654                 if ((ptr = GetDeviceStruct(cid)) == NULL) {
655                         FIXME("no cid=%d found!\n", cid);
656                         return -1;
657                 }
658                 if (tcgetattr(ptr->fd,&port) == -1) {
659                         TRACE("tcgetattr failed\n");
660                         ptr->commerror=WinError();      
661                         return -1;
662                 }
663         } else ptr = NULL;
664
665         switch (nFunction) {
666                 case RESETDEV:
667                         TRACE("RESETDEV\n");
668                         break;                                  
669
670                 case GETMAXCOM:
671                         TRACE("GETMAXCOM\n"); 
672                         for (max = MAX_PORTS;!COM[max].devicename;max--)
673                                 ;
674                         return max;
675                         break;
676
677                 case GETMAXLPT:
678                         TRACE("GETMAXLPT\n"); 
679                         for (max = MAX_PORTS;!LPT[max].devicename;max--)
680                                 ;
681                         return FLAG_LPT + max;
682                         break;
683
684                 case GETBASEIRQ:
685                         TRACE("GETBASEIRQ\n"); 
686                         /* FIXME: use tables */
687                         /* just fake something for now */
688                         if (cid & FLAG_LPT) {
689                                 /* LPT1: irq 7, LPT2: irq 5 */
690                                 return (cid & 0x7f) ? 5 : 7;
691                         } else {
692                                 /* COM1: irq 4, COM2: irq 3,
693                                    COM3: irq 4, COM4: irq 3 */
694                                 return 4 - (cid & 1);
695                         }
696                         break;
697
698                 case CLRDTR:
699                         TRACE("CLRDTR\n"); 
700 #ifdef TIOCM_DTR
701                         return COMM_WhackModem(ptr->fd, ~TIOCM_DTR, 0);
702 #endif
703                 case CLRRTS:
704                         TRACE("CLRRTS\n"); 
705 #ifdef TIOCM_RTS
706                         return COMM_WhackModem(ptr->fd, ~TIOCM_RTS, 0);
707 #endif
708         
709                 case SETDTR:
710                         TRACE("SETDTR\n"); 
711 #ifdef TIOCM_DTR
712                         return COMM_WhackModem(ptr->fd, 0, TIOCM_DTR);
713 #endif
714
715                 case SETRTS:
716                         TRACE("SETRTS\n"); 
717 #ifdef TIOCM_RTS                        
718                         return COMM_WhackModem(ptr->fd, 0, TIOCM_RTS);
719 #endif
720
721                 case SETXOFF:
722                         TRACE("SETXOFF\n"); 
723                         port.c_iflag |= IXOFF;
724                         break;
725
726                 case SETXON:
727                         TRACE("SETXON\n"); 
728                         port.c_iflag |= IXON;
729                         break;
730
731                 default:
732                         WARN("(cid=%d,nFunction=%d): Unknown function\n", 
733                         cid, nFunction);
734                         break;                          
735         }
736         
737         if (tcsetattr(ptr->fd, TCSADRAIN, &port) == -1) {
738                 ptr->commerror = WinError();
739                 return -1;      
740         } else {
741                 ptr->commerror = 0;
742                 return 0;
743         }
744 }
745
746 /*****************************************************************************
747  *      FlushComm16     (USER.215)
748  */
749 INT16 WINAPI FlushComm16(INT16 cid,INT16 fnQueue)
750 {
751         int queue;
752         struct DosDeviceStruct *ptr;
753
754         TRACE("cid=%d, queue=%d\n", cid, fnQueue);
755         if ((ptr = GetDeviceStruct(cid)) == NULL) {
756                 FIXME("no cid=%d found!\n", cid);
757                 return -1;
758         }
759         switch (fnQueue) {
760                 case 0:
761                   queue = TCOFLUSH;
762                   ptr->obuf_tail = ptr->obuf_head;
763                   break;
764                 case 1:
765                   queue = TCIFLUSH;
766                   ptr->ibuf_head = ptr->ibuf_tail;
767                   break;
768                 default:
769                   WARN("(cid=%d,fnQueue=%d):Unknown queue\n", 
770                             cid, fnQueue);
771                   return -1;
772                 }
773         if (tcflush(ptr->fd, queue)) {
774                 ptr->commerror = WinError();
775                 return -1;      
776         } else {
777                 ptr->commerror = 0;
778                 return 0;
779         }
780 }  
781
782 /********************************************************************
783  *      GetCommError16  (USER.203)
784  */
785 INT16 WINAPI GetCommError16(INT16 cid,LPCOMSTAT16 lpStat)
786 {
787         int             temperror;
788         struct DosDeviceStruct *ptr;
789         unsigned char *stol;
790         unsigned int mstat;
791
792         if ((ptr = GetDeviceStruct(cid)) == NULL) {
793                 FIXME("no handle for cid = %0x!.\n",cid);
794                 return -1;
795         }
796         if (cid&FLAG_LPT) {
797             WARN(" cid %d not comm port\n",cid);
798             return CE_MODE;
799         }
800         stol = (unsigned char *)unknown[cid] + COMM_MSR_OFFSET;
801         ioctl(ptr->fd,TIOCMGET,&mstat);
802         COMM_MSRUpdate( stol, mstat);
803
804         if (lpStat) {
805                 lpStat->status = 0;
806
807                 lpStat->cbOutQue = comm_outbuf(ptr);
808                 lpStat->cbInQue = comm_inbuf(ptr);
809
810                 TRACE("cid %d, error %d, lpStat %d %d %d stol %x\n",
811                              cid, ptr->commerror, lpStat->status, lpStat->cbInQue, 
812                              lpStat->cbOutQue, *stol);
813         }
814         else
815                 TRACE("cid %d, error %d, lpStat NULL stol %x\n",
816                              cid, ptr->commerror, *stol);
817
818         /* Return any errors and clear it */
819         temperror = ptr->commerror;
820         ptr->commerror = 0;
821         return(temperror);
822 }
823
824 /*****************************************************************************
825  *      SetCommEventMask16      (USER.208)
826  */
827 SEGPTR WINAPI SetCommEventMask16(INT16 cid,UINT16 fuEvtMask)
828 {
829         struct DosDeviceStruct *ptr;
830         unsigned char *stol;
831         int repid;
832         unsigned int mstat;
833
834         TRACE("cid %d,mask %d\n",cid,fuEvtMask);
835         if ((ptr = GetDeviceStruct(cid)) == NULL) {
836                 FIXME("no handle for cid = %0x!.\n",cid);
837             return (SEGPTR)NULL;
838         }
839
840         ptr->eventmask = fuEvtMask;
841
842         if ((cid&FLAG_LPT) || !ValidCOMPort(cid)) {
843             WARN(" cid %d not comm port\n",cid);
844             return (SEGPTR)NULL;
845         }
846         /* it's a COM port ? -> modify flags */
847         stol = (unsigned char *)unknown[cid] + COMM_MSR_OFFSET;
848         repid = ioctl(ptr->fd,TIOCMGET,&mstat);
849         TRACE(" ioctl  %d, msr %x at %p %p\n",repid,mstat,stol,unknown[cid]);
850         COMM_MSRUpdate( stol, mstat);
851
852         TRACE(" modem dcd construct %x\n",*stol);
853         return SEGPTR_GET(unknown[cid]);
854 }
855
856 /*****************************************************************************
857  *      GetCommEventMask16      (USER.209)
858  */
859 UINT16 WINAPI GetCommEventMask16(INT16 cid,UINT16 fnEvtClear)
860 {
861         struct DosDeviceStruct *ptr;
862         WORD events;
863
864         TRACE("cid %d, mask %d\n", cid, fnEvtClear);
865         if ((ptr = GetDeviceStruct(cid)) == NULL) {
866                 FIXME("no handle for cid = %0x!.\n",cid);
867             return 0;
868         }
869
870         if ((cid&FLAG_LPT) || !ValidCOMPort(cid)) {
871             WARN(" cid %d not comm port\n",cid);
872             return 0;
873         }
874
875         events = *(WORD*)(unknown[cid]) & fnEvtClear;
876         *(WORD*)(unknown[cid]) &= ~fnEvtClear;
877         return events;
878 }
879
880 /*****************************************************************************
881  *      SetCommState16  (USER.201)
882  */
883 INT16 WINAPI SetCommState16(LPDCB16 lpdcb)
884 {
885         struct termios port;
886         struct DosDeviceStruct *ptr;
887         int bytesize, stopbits;
888         int fail=0;
889
890         TRACE("cid %d, ptr %p\n", lpdcb->Id, lpdcb);
891         if ((ptr = GetDeviceStruct(lpdcb->Id)) == NULL) {
892                 FIXME("no handle for cid = %0x!.\n",lpdcb->Id);
893                 return -1;
894         }
895         if (tcgetattr(ptr->fd, &port) == -1) {
896                 ptr->commerror = WinError();    
897                 return -1;
898         }
899
900         port.c_cc[VMIN] = 0;
901         port.c_cc[VTIME] = 1;
902
903 #ifdef IMAXBEL
904         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|IMAXBEL);
905 #else
906         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR);
907 #endif
908         port.c_iflag |= (IGNBRK);
909
910         port.c_oflag &= ~(OPOST);
911
912         port.c_cflag &= ~(HUPCL);
913         port.c_cflag |= CLOCAL | CREAD;
914
915         port.c_lflag &= ~(ICANON|ECHO|ISIG);
916         port.c_lflag |= NOFLSH;
917
918         TRACE("baudrate %d\n",lpdcb->BaudRate);
919 #ifdef CBAUD
920         port.c_cflag &= ~CBAUD;
921         switch (lpdcb->BaudRate) {
922                 case 110:
923                 case CBR_110:
924                         port.c_cflag |= B110;
925                         break;          
926                 case 300:
927                 case CBR_300:
928                         port.c_cflag |= B300;
929                         break;          
930                 case 600:
931                 case CBR_600:
932                         port.c_cflag |= B600;
933                         break;          
934                 case 1200:
935                 case CBR_1200:
936                         port.c_cflag |= B1200;
937                         break;          
938                 case 2400:
939                 case CBR_2400:
940                         port.c_cflag |= B2400;
941                         break;          
942                 case 4800:
943                 case CBR_4800:
944                         port.c_cflag |= B4800;
945                         break;          
946                 case 9600:
947                 case CBR_9600:
948                         port.c_cflag |= B9600;
949                         break;          
950                 case 19200:
951                 case CBR_19200:
952                         port.c_cflag |= B19200;
953                         break;          
954                 case 38400:
955                 case CBR_38400:
956                         port.c_cflag |= B38400;
957                         break;          
958 #ifdef B57600
959                 case 57600:
960                         port.c_cflag |= B57600;
961                         break;          
962 #endif
963 #ifdef B115200
964                 case 57601:
965                         port.c_cflag |= B115200;
966                         break;          
967 #endif
968                 default:
969                         ptr->commerror = IE_BAUDRATE;
970                         fail=1;
971         }
972 #elif !defined(__EMX__)
973         switch (lpdcb->BaudRate) {
974                 case 110:
975                 case CBR_110:
976                         port.c_ospeed = B110;
977                         break;
978                 case 300:
979                 case CBR_300:
980                         port.c_ospeed = B300;
981                         break;
982                 case 600:
983                 case CBR_600:
984                         port.c_ospeed = B600;
985                         break;
986                 case 1200:
987                 case CBR_1200:
988                         port.c_ospeed = B1200;
989                         break;
990                 case 2400:
991                 case CBR_2400:
992                         port.c_ospeed = B2400;
993                         break;
994                 case 4800:
995                 case CBR_4800:
996                         port.c_ospeed = B4800;
997                         break;
998                 case 9600:
999                 case CBR_9600:
1000                         port.c_ospeed = B9600;
1001                         break;
1002                 case 19200:
1003                 case CBR_19200:
1004                         port.c_ospeed = B19200;
1005                         break;
1006                 case 38400:
1007                 case CBR_38400:
1008                         port.c_ospeed = B38400;
1009                         break;
1010                 default:
1011                         ptr->commerror = IE_BAUDRATE;
1012                         fail=1;
1013         }
1014         port.c_ispeed = port.c_ospeed;
1015 #endif
1016         bytesize=lpdcb->ByteSize;
1017         stopbits=lpdcb->StopBits;
1018
1019         TRACE("fParity %d Parity %d\n",lpdcb->fParity, lpdcb->Parity);
1020 #ifdef CMSPAR
1021         port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
1022 #else
1023         port.c_cflag &= ~(PARENB | PARODD);
1024 #endif
1025         if (lpdcb->fParity)
1026             port.c_iflag |= INPCK;
1027         else
1028             port.c_iflag &= ~INPCK;
1029         switch (lpdcb->Parity) {
1030                 case NOPARITY:
1031                         break;
1032                 case ODDPARITY:
1033                         port.c_cflag |= (PARENB | PARODD);
1034                         break;
1035                 case EVENPARITY:
1036                         port.c_cflag |= PARENB;
1037                         break;
1038 #ifdef CMSPAR
1039                 /* Linux defines mark/space (stick) parity */
1040                 case MARKPARITY:
1041                         port.c_cflag |= (PARENB | CMSPAR);
1042                         break;
1043                 case SPACEPARITY:
1044                         port.c_cflag |= (PARENB | PARODD |  CMSPAR);
1045                         break;
1046 #else
1047                 /* try the POSIX way */
1048                 case MARKPARITY:
1049                         if( stopbits == ONESTOPBIT) {
1050                             stopbits = TWOSTOPBITS;
1051                             port.c_iflag &= ~INPCK;
1052                         } else {
1053                             ptr->commerror = IE_BYTESIZE;
1054                             fail=1;
1055                         }
1056                         break;
1057                 case SPACEPARITY:
1058                         if( bytesize < 8) {
1059                             bytesize +=1;
1060                             port.c_iflag &= ~INPCK;
1061                         } else {
1062                             ptr->commerror = IE_BYTESIZE;
1063                             fail=1;
1064                         }
1065                         break;
1066 #endif
1067                 default:
1068                         ptr->commerror = IE_BYTESIZE;
1069                         fail=1;
1070         }
1071         
1072         TRACE("bytesize %d\n",bytesize);
1073         port.c_cflag &= ~CSIZE;
1074         switch (bytesize) {
1075                 case 5:
1076                         port.c_cflag |= CS5;
1077                         break;
1078                 case 6:
1079                         port.c_cflag |= CS6;
1080                         break;
1081                 case 7:
1082                         port.c_cflag |= CS7;
1083                         break;
1084                 case 8:
1085                         port.c_cflag |= CS8;
1086                         break;
1087                 default:
1088                         ptr->commerror = IE_BYTESIZE;
1089                         fail=1;
1090         }
1091
1092         TRACE("stopbits %d\n",stopbits);
1093
1094         switch (stopbits) {
1095                 case ONESTOPBIT:
1096                                 port.c_cflag &= ~CSTOPB;
1097                                 break;
1098                 case ONE5STOPBITS: /* wil be selected if bytesize is 5 */
1099                 case TWOSTOPBITS:
1100                                 port.c_cflag |= CSTOPB;
1101                                 break;
1102                 default:
1103                         ptr->commerror = IE_BYTESIZE;
1104                         fail=1;
1105         }
1106 #ifdef CRTSCTS
1107
1108         if (lpdcb->fDtrflow || lpdcb->fRtsflow || lpdcb->fOutxCtsFlow)
1109                 port.c_cflag |= CRTSCTS;
1110
1111         if (lpdcb->fDtrDisable) 
1112                 port.c_cflag &= ~CRTSCTS;
1113 #endif  
1114         if (lpdcb->fInX)
1115                 port.c_iflag |= IXON;
1116         else
1117                 port.c_iflag &= ~IXON;
1118         if (lpdcb->fOutX)
1119                 port.c_iflag |= IXOFF;
1120         else
1121                 port.c_iflag &= ~IXOFF;
1122
1123         ptr->evtchar = lpdcb->EvtChar;
1124
1125         if(fail)
1126             return -1;
1127         
1128         if (tcsetattr(ptr->fd, TCSADRAIN, &port) == -1) {
1129                 ptr->commerror = WinError();    
1130                 return -1;
1131         } else {
1132                 ptr->commerror = 0;
1133                 return 0;
1134         }
1135 }
1136
1137 /*****************************************************************************
1138  *      GetCommState16  (USER.202)
1139  */
1140 INT16 WINAPI GetCommState16(INT16 cid, LPDCB16 lpdcb)
1141 {
1142         int speed;
1143         struct DosDeviceStruct *ptr;
1144         struct termios port;
1145
1146         TRACE("cid %d, ptr %p\n", cid, lpdcb);
1147         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1148                 FIXME("no handle for cid = %0x!.\n",cid);
1149                 return -1;
1150         }
1151         if (tcgetattr(ptr->fd, &port) == -1) {
1152                 ptr->commerror = WinError();    
1153                 return -1;
1154         }
1155         lpdcb->Id = cid;
1156 #ifndef __EMX__
1157 #ifdef CBAUD
1158         speed = port.c_cflag & CBAUD;
1159 #else
1160         speed = port.c_ospeed;
1161 #endif
1162         switch(speed) {
1163                 case B110:
1164                         lpdcb->BaudRate = 110;
1165                         break;
1166                 case B300:
1167                         lpdcb->BaudRate = 300;
1168                         break;
1169                 case B600:
1170                         lpdcb->BaudRate = 600;
1171                         break;
1172                 case B1200:
1173                         lpdcb->BaudRate = 1200;
1174                         break;
1175                 case B2400:
1176                         lpdcb->BaudRate = 2400;
1177                         break;
1178                 case B4800:
1179                         lpdcb->BaudRate = 4800;
1180                         break;
1181                 case B9600:
1182                         lpdcb->BaudRate = 9600;
1183                         break;
1184                 case B19200:
1185                         lpdcb->BaudRate = 19200;
1186                         break;
1187                 case B38400:
1188                         lpdcb->BaudRate = 38400;
1189                         break;
1190 #ifdef B57600
1191                 case B57600:
1192                         lpdcb->BaudRate = 57600;
1193                         break;
1194 #endif
1195 #ifdef B115200
1196                 case B115200:
1197                         lpdcb->BaudRate = 57601;
1198                         break;
1199 #endif
1200         }
1201 #endif
1202         switch (port.c_cflag & CSIZE) {
1203                 case CS5:
1204                         lpdcb->ByteSize = 5;
1205                         break;
1206                 case CS6:
1207                         lpdcb->ByteSize = 6;
1208                         break;
1209                 case CS7:
1210                         lpdcb->ByteSize = 7;
1211                         break;
1212                 case CS8:
1213                         lpdcb->ByteSize = 8;
1214                         break;
1215         }       
1216         
1217         if(port.c_iflag & INPCK)
1218             lpdcb->fParity = TRUE;
1219         else
1220             lpdcb->fParity = FALSE;
1221 #ifdef CMSPAR
1222         switch (port.c_cflag & (PARENB | PARODD | CMSPAR))
1223 #else
1224         switch (port.c_cflag & (PARENB | PARODD))
1225 #endif
1226         {
1227                 case 0:
1228                         lpdcb->Parity = NOPARITY;
1229                         break;
1230                 case PARENB:
1231                         lpdcb->Parity = EVENPARITY;
1232                         break;
1233                 case (PARENB | PARODD):
1234                         lpdcb->Parity = ODDPARITY;              
1235                         break;
1236 #ifdef CMSPAR
1237                 case (PARENB | CMSPAR):
1238                         lpdcb->Parity = MARKPARITY;             
1239                         break;
1240                 case (PARENB | PARODD | CMSPAR):
1241                         lpdcb->Parity = SPACEPARITY;            
1242                         break;
1243 #endif
1244         }
1245
1246         if (port.c_cflag & CSTOPB)
1247             if(lpdcb->ByteSize == 5)
1248                 lpdcb->StopBits = ONE5STOPBITS;
1249             else
1250                 lpdcb->StopBits = TWOSTOPBITS;
1251         else
1252             lpdcb->StopBits = ONESTOPBIT;
1253
1254         lpdcb->RlsTimeout = 50;
1255         lpdcb->CtsTimeout = 50; 
1256         lpdcb->DsrTimeout = 50;
1257         lpdcb->fNull = 0;
1258         lpdcb->fChEvt = 0;
1259         lpdcb->fBinary = 1;
1260         lpdcb->fDtrDisable = 0;
1261
1262 #ifdef CRTSCTS
1263
1264         if (port.c_cflag & CRTSCTS) {
1265                 lpdcb->fDtrflow = 1;
1266                 lpdcb->fRtsflow = 1;
1267                 lpdcb->fOutxCtsFlow = 1;
1268                 lpdcb->fOutxDsrFlow = 1;
1269         } else 
1270 #endif
1271                 lpdcb->fDtrDisable = 1;
1272
1273         if (port.c_iflag & IXON)
1274                 lpdcb->fInX = 1;
1275         else
1276                 lpdcb->fInX = 0;
1277
1278         if (port.c_iflag & IXOFF)
1279                 lpdcb->fOutX = 1;
1280         else
1281                 lpdcb->fOutX = 0;
1282 /*
1283         lpdcb->XonChar = 
1284         lpdcb->XoffChar = 
1285  */
1286         lpdcb->XonLim = 10;
1287         lpdcb->XoffLim = 10;
1288
1289         lpdcb->EvtChar = ptr->evtchar;
1290
1291         ptr->commerror = 0;
1292         return 0;
1293 }
1294
1295 /*****************************************************************************
1296  *      TransmitCommChar16      (USER.206)
1297  */
1298 INT16 WINAPI TransmitCommChar16(INT16 cid,CHAR chTransmit)
1299 {
1300         struct DosDeviceStruct *ptr;
1301
1302         TRACE("cid %d, data %d \n", cid, chTransmit);
1303         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1304                 FIXME("no handle for cid = %0x!.\n",cid);
1305                 return -1;
1306         }
1307
1308         if (ptr->suspended) {
1309                 ptr->commerror = IE_HARDWARE;
1310                 return -1;
1311         }       
1312
1313         if (ptr->xmit >= 0) {
1314           /* character already queued */
1315           /* FIXME: which error would Windows return? */
1316           ptr->commerror = CE_TXFULL;
1317           return -1;
1318         }
1319
1320         if (ptr->obuf_head == ptr->obuf_tail) {
1321           /* transmit queue empty, try to transmit directly */
1322           if (write(ptr->fd, &chTransmit, 1) == -1) {
1323             /* didn't work, queue it */
1324             ptr->xmit = chTransmit;
1325             comm_waitwrite(ptr);
1326           }
1327         } else {
1328           /* data in queue, let this char be transmitted next */
1329           ptr->xmit = chTransmit;
1330           comm_waitwrite(ptr);
1331         }
1332
1333         ptr->commerror = 0;
1334         return 0;
1335 }
1336
1337 /*****************************************************************************
1338  *      UngetCommChar16 (USER.212)
1339  */
1340 INT16 WINAPI UngetCommChar16(INT16 cid,CHAR chUnget)
1341 {
1342         struct DosDeviceStruct *ptr;
1343
1344         TRACE("cid %d (char %d)\n", cid, chUnget);
1345         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1346                 FIXME("no handle for cid = %0x!.\n",cid);
1347                 return -1;
1348         }
1349
1350         if (ptr->suspended) {
1351                 ptr->commerror = IE_HARDWARE;
1352                 return -1;
1353         }       
1354
1355         if (ptr->unget>=0) {
1356           /* character already queued */
1357           /* FIXME: which error would Windows return? */
1358           ptr->commerror = CE_RXOVER;
1359           return -1;
1360         }
1361
1362         ptr->unget = chUnget;
1363
1364         ptr->commerror = 0;
1365         return 0;
1366 }
1367
1368 /*****************************************************************************
1369  *      ReadComm16      (USER.204)
1370  */
1371 INT16 WINAPI ReadComm16(INT16 cid,LPSTR lpvBuf,INT16 cbRead)
1372 {
1373         int status, length;
1374         struct DosDeviceStruct *ptr;
1375         LPSTR orgBuf = lpvBuf;
1376
1377         TRACE("cid %d, ptr %p, length %d\n", cid, lpvBuf, cbRead);
1378         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1379                 FIXME("no handle for cid = %0x!.\n",cid);
1380                 return -1;
1381         }
1382
1383         if (ptr->suspended) {
1384                 ptr->commerror = IE_HARDWARE;
1385                 return -1;
1386         }       
1387
1388         /* read unget character */
1389         if (ptr->unget>=0) {
1390                 *lpvBuf++ = ptr->unget;
1391                 ptr->unget = -1;
1392
1393                 length = 1;
1394         } else
1395                 length = 0;
1396
1397         /* read from receive buffer */
1398         while (length < cbRead) {
1399           status = ((ptr->ibuf_head < ptr->ibuf_tail) ?
1400                     ptr->ibuf_size : ptr->ibuf_head) - ptr->ibuf_tail;
1401           if (!status) break;
1402           if ((cbRead - length) < status)
1403             status = cbRead - length;
1404
1405           memcpy(lpvBuf, ptr->inbuf + ptr->ibuf_tail, status);
1406           ptr->ibuf_tail += status;
1407           if (ptr->ibuf_tail >= ptr->ibuf_size)
1408             ptr->ibuf_tail = 0;
1409           lpvBuf += status;
1410           length += status;
1411         }
1412
1413         TRACE("%.*s\n", length, orgBuf);
1414         ptr->commerror = 0;
1415         return length;
1416 }
1417
1418 /*****************************************************************************
1419  *      WriteComm16     (USER.205)
1420  */
1421 INT16 WINAPI WriteComm16(INT16 cid, LPSTR lpvBuf, INT16 cbWrite)
1422 {
1423         int status, length;
1424         struct DosDeviceStruct *ptr;
1425
1426         TRACE("cid %d, ptr %p, length %d\n", 
1427                 cid, lpvBuf, cbWrite);
1428         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1429                 FIXME("no handle for cid = %0x!.\n",cid);
1430                 return -1;
1431         }
1432
1433         if (ptr->suspended) {
1434                 ptr->commerror = IE_HARDWARE;
1435                 return -1;
1436         }       
1437         
1438         TRACE("%.*s\n", cbWrite, lpvBuf );
1439
1440         length = 0;
1441         while (length < cbWrite) {
1442           if ((ptr->obuf_head == ptr->obuf_tail) && (ptr->xmit < 0)) {
1443             /* no data queued, try to write directly */
1444             status = write(ptr->fd, lpvBuf, cbWrite - length);
1445             if (status > 0) {
1446               lpvBuf += status;
1447               length += status;
1448               continue;
1449             }
1450           }
1451           /* can't write directly, put into transmit buffer */
1452           status = ((ptr->obuf_tail > ptr->obuf_head) ?
1453                     (ptr->obuf_tail-1) : ptr->obuf_size) - ptr->obuf_head;
1454           if (!status) break;
1455           if ((cbWrite - length) < status)
1456             status = cbWrite - length;
1457           memcpy(lpvBuf, ptr->outbuf + ptr->obuf_head, status);
1458           ptr->obuf_head += status;
1459           if (ptr->obuf_head >= ptr->obuf_size)
1460             ptr->obuf_head = 0;
1461           lpvBuf += status;
1462           length += status;
1463           comm_waitwrite(ptr);
1464         }
1465
1466         ptr->commerror = 0;     
1467         return length;
1468 }
1469
1470 /***********************************************************************
1471  *           EnableCommNotification16   (USER.246)
1472  */
1473 BOOL16 WINAPI EnableCommNotification16( INT16 cid, HWND16 hwnd,
1474                                       INT16 cbWriteNotify, INT16 cbOutQueue )
1475 {
1476         struct DosDeviceStruct *ptr;
1477
1478         TRACE("(%d, %x, %d, %d)\n", cid, hwnd, cbWriteNotify, cbOutQueue);
1479         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1480                 FIXME("no handle for cid = %0x!.\n",cid);
1481                 return -1;
1482         }
1483         ptr->wnd = hwnd;
1484         ptr->n_read = cbWriteNotify;
1485         ptr->n_write = cbOutQueue;
1486         return TRUE;
1487 }
1488
1489
1490 /**************************************************************************
1491  *         BuildCommDCBA                (KERNEL32.14)
1492  */
1493 BOOL WINAPI BuildCommDCBA(LPCSTR device,LPDCB lpdcb)
1494 {
1495         return BuildCommDCBAndTimeoutsA(device,lpdcb,NULL);
1496 }
1497
1498 /**************************************************************************
1499  *         BuildCommDCBAndTimeoutsA     (KERNEL32.15)
1500  */
1501 BOOL WINAPI BuildCommDCBAndTimeoutsA(LPCSTR device, LPDCB lpdcb,
1502                                          LPCOMMTIMEOUTS lptimeouts)
1503 {
1504         int     port;
1505         char    *ptr,*temp;
1506
1507         TRACE("(%s,%p,%p)\n",device,lpdcb,lptimeouts);
1508
1509         if (!strncasecmp(device,"COM",3)) {
1510                 port=device[3]-'0';
1511                 if (port--==0) {
1512                         ERR("BUG! COM0 can't exists!.\n");
1513                         return FALSE;
1514                 }
1515                 if (!ValidCOMPort(port))
1516                         return FALSE;
1517                 if (*(device+4)!=':')
1518                         return FALSE;
1519                 temp=(LPSTR)(device+5);
1520         } else
1521                 temp=(LPSTR)device;
1522
1523         lpdcb->DCBlength        = sizeof(DCB);
1524         if (strchr(temp,',')) { /* old style */
1525                 DCB16   dcb16;
1526                 BOOL16  ret;
1527                 char    last=temp[strlen(temp)-1];
1528
1529                 ret=BuildCommDCB16(device,&dcb16);
1530                 if (ret)
1531                         return FALSE;
1532                 lpdcb->BaudRate         = dcb16.BaudRate;
1533                 lpdcb->ByteSize         = dcb16.ByteSize;
1534                 lpdcb->fBinary          = dcb16.fBinary;
1535                 lpdcb->Parity           = dcb16.Parity;
1536                 lpdcb->fParity          = dcb16.fParity;
1537                 lpdcb->fNull            = dcb16.fNull;
1538                 lpdcb->StopBits         = dcb16.StopBits;
1539                 if (last == 'x') {
1540                         lpdcb->fInX             = TRUE;
1541                         lpdcb->fOutX            = TRUE;
1542                         lpdcb->fOutxCtsFlow     = FALSE;
1543                         lpdcb->fOutxDsrFlow     = FALSE;
1544                         lpdcb->fDtrControl      = DTR_CONTROL_ENABLE;
1545                         lpdcb->fRtsControl      = RTS_CONTROL_ENABLE;
1546                 } else if (last=='p') {
1547                         lpdcb->fInX             = FALSE;
1548                         lpdcb->fOutX            = FALSE;
1549                         lpdcb->fOutxCtsFlow     = TRUE;
1550                         lpdcb->fOutxDsrFlow     = TRUE;
1551                         lpdcb->fDtrControl      = DTR_CONTROL_HANDSHAKE;
1552                         lpdcb->fRtsControl      = RTS_CONTROL_HANDSHAKE;
1553                 } else {
1554                         lpdcb->fInX             = FALSE;
1555                         lpdcb->fOutX            = FALSE;
1556                         lpdcb->fOutxCtsFlow     = FALSE;
1557                         lpdcb->fOutxDsrFlow     = FALSE;
1558                         lpdcb->fDtrControl      = DTR_CONTROL_ENABLE;
1559                         lpdcb->fRtsControl      = RTS_CONTROL_ENABLE;
1560                 }
1561                 lpdcb->XonChar  = dcb16.XonChar;
1562                 lpdcb->XoffChar = dcb16.XoffChar;
1563                 lpdcb->ErrorChar= dcb16.PeChar;
1564                 lpdcb->fErrorChar= dcb16.fPeChar;
1565                 lpdcb->EofChar  = dcb16.EofChar;
1566                 lpdcb->EvtChar  = dcb16.EvtChar;
1567                 lpdcb->XonLim   = dcb16.XonLim;
1568                 lpdcb->XoffLim  = dcb16.XoffLim;
1569                 return TRUE;
1570         }
1571         ptr=strtok(temp," "); 
1572         while (ptr) {
1573                 DWORD   flag,x;
1574
1575                 flag=0;
1576                 if (!strncmp("baud=",ptr,5)) {
1577                         if (!sscanf(ptr+5,"%ld",&x))
1578                                 WARN("Couldn't parse %s\n",ptr);
1579                         lpdcb->BaudRate = x;
1580                         flag=1;
1581                 }
1582                 if (!strncmp("stop=",ptr,5)) {
1583                         if (!sscanf(ptr+5,"%ld",&x))
1584                                 WARN("Couldn't parse %s\n",ptr);
1585                         lpdcb->StopBits = x;
1586                         flag=1;
1587                 }
1588                 if (!strncmp("data=",ptr,5)) {
1589                         if (!sscanf(ptr+5,"%ld",&x))
1590                                 WARN("Couldn't parse %s\n",ptr);
1591                         lpdcb->ByteSize = x;
1592                         flag=1;
1593                 }
1594                 if (!strncmp("parity=",ptr,7)) {
1595                         lpdcb->fParity  = TRUE;
1596                         switch (ptr[8]) {
1597                         case 'N':case 'n':
1598                                 lpdcb->fParity  = FALSE;
1599                                 lpdcb->Parity   = NOPARITY;
1600                                 break;
1601                         case 'E':case 'e':
1602                                 lpdcb->Parity   = EVENPARITY;
1603                                 break;
1604                         case 'O':case 'o':
1605                                 lpdcb->Parity   = ODDPARITY;
1606                                 break;
1607                         case 'M':case 'm':
1608                                 lpdcb->Parity   = MARKPARITY;
1609                                 break;
1610                         }
1611                         flag=1;
1612                 }
1613                 if (!flag)
1614                         ERR("Unhandled specifier '%s', please report.\n",ptr);
1615                 ptr=strtok(NULL," ");
1616         }
1617         if (lpdcb->BaudRate==110)
1618                 lpdcb->StopBits = 2;
1619         return TRUE;
1620 }
1621
1622 /**************************************************************************
1623  *         BuildCommDCBAndTimeoutsW             (KERNEL32.16)
1624  */
1625 BOOL WINAPI BuildCommDCBAndTimeoutsW( LPCWSTR devid, LPDCB lpdcb,
1626                                           LPCOMMTIMEOUTS lptimeouts )
1627 {
1628         LPSTR   devidA;
1629         BOOL    ret;
1630
1631         TRACE("(%p,%p,%p)\n",devid,lpdcb,lptimeouts);
1632         devidA = HEAP_strdupWtoA( GetProcessHeap(), 0, devid );
1633         ret=BuildCommDCBAndTimeoutsA(devidA,lpdcb,lptimeouts);
1634         HeapFree( GetProcessHeap(), 0, devidA );
1635         return ret;
1636 }
1637
1638 /**************************************************************************
1639  *         BuildCommDCBW                (KERNEL32.17)
1640  */
1641 BOOL WINAPI BuildCommDCBW(LPCWSTR devid,LPDCB lpdcb)
1642 {
1643         return BuildCommDCBAndTimeoutsW(devid,lpdcb,NULL);
1644 }
1645
1646 /* FIXME: having these global for win32 for now */
1647 int commerror=0;
1648
1649 /*****************************************************************************
1650  *      SetCommBreak            (KERNEL32.449)
1651  */
1652 BOOL WINAPI SetCommBreak(HANDLE handle)
1653 {
1654 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1655         int fd,result;
1656  
1657         fd = FILE_GetUnixHandle( handle, GENERIC_WRITE );
1658         if(fd<0) {
1659                 TRACE("FILE_GetUnixHandle failed\n");
1660                 return FALSE;
1661         }
1662         result = ioctl(fd,TIOCSBRK,0);
1663         close(fd);
1664         if (result ==-1)
1665           {
1666                 TRACE("ioctl failed\n");
1667                 SetLastError(ERROR_NOT_SUPPORTED);
1668                 return FALSE;
1669           }
1670         return TRUE;
1671 #else
1672         FIXME("ioctl not available\n");
1673         SetLastError(ERROR_NOT_SUPPORTED);
1674         return FALSE;
1675 #endif
1676 }
1677
1678 /*****************************************************************************
1679  *      ClearCommBreak          (KERNEL32.20)
1680  */
1681 BOOL WINAPI ClearCommBreak(HANDLE handle)
1682 {
1683 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1684         int fd,result;
1685  
1686         fd = FILE_GetUnixHandle( handle, GENERIC_WRITE );
1687         if(fd<0) {
1688                 TRACE("FILE_GetUnixHandle failed\n");
1689                 return FALSE;
1690         }
1691         result = ioctl(fd,TIOCCBRK,0);
1692         close(fd);
1693         if (result ==-1)
1694           {
1695                 TRACE("ioctl failed\n");
1696                 SetLastError(ERROR_NOT_SUPPORTED);
1697                 return FALSE;
1698           }
1699         return TRUE;
1700 #else
1701         FIXME("ioctl not available\n");
1702         SetLastError(ERROR_NOT_SUPPORTED);
1703         return FALSE;
1704 #endif
1705 }
1706
1707 /*****************************************************************************
1708  *      EscapeCommFunction      (KERNEL32.214)
1709  */
1710 BOOL WINAPI EscapeCommFunction(HANDLE handle,UINT nFunction)
1711 {
1712         int fd,direct=FALSE,result=FALSE;
1713         struct termios  port;
1714
1715         TRACE("handle %d, function=%d\n", handle, nFunction);
1716         fd = FILE_GetUnixHandle( handle, GENERIC_WRITE );
1717         if(fd<0) {
1718                 FIXME("handle %d not found.\n",handle);
1719                 return FALSE;
1720         }
1721
1722         if (tcgetattr(fd,&port) == -1) {
1723                 commerror=WinError();
1724                 close(fd);
1725                 return FALSE;
1726         }
1727
1728         switch (nFunction) {
1729                 case RESETDEV:
1730                         TRACE("\n");
1731                         break;                                  
1732
1733                 case CLRDTR:
1734                         TRACE("CLRDTR\n");
1735 #ifdef TIOCM_DTR
1736                         direct=TRUE;
1737                         result= COMM_WhackModem(fd, ~TIOCM_DTR, 0);
1738                         break;
1739 #endif
1740
1741                 case CLRRTS:
1742                         TRACE("CLRRTS\n");
1743 #ifdef TIOCM_RTS
1744                         direct=TRUE;
1745                         result= COMM_WhackModem(fd, ~TIOCM_RTS, 0);
1746                         break;
1747 #endif
1748         
1749                 case SETDTR:
1750                         TRACE("SETDTR\n");
1751 #ifdef TIOCM_DTR
1752                         direct=TRUE;
1753                         result= COMM_WhackModem(fd, 0, TIOCM_DTR);
1754                         break;
1755 #endif
1756
1757                 case SETRTS:
1758                         TRACE("SETRTS\n");
1759 #ifdef TIOCM_DTR
1760                         direct=TRUE;
1761                         result= COMM_WhackModem(fd, 0, TIOCM_RTS);
1762                         break;
1763 #endif
1764
1765                 case SETXOFF:
1766                         TRACE("SETXOFF\n");
1767                         port.c_iflag |= IXOFF;
1768                         break;
1769
1770                 case SETXON:
1771                         TRACE("SETXON\n");
1772                         port.c_iflag |= IXON;
1773                         break;
1774                 case SETBREAK:
1775                         TRACE("setbreak\n");
1776 #ifdef  TIOCSBRK
1777                         direct=TRUE;
1778                         result = ioctl(fd,TIOCSBRK,0);
1779                         break;
1780 #endif
1781                 case CLRBREAK:
1782                         TRACE("clrbreak\n");
1783 #ifdef  TIOCSBRK
1784                         direct=TRUE;
1785                         result = ioctl(fd,TIOCCBRK,0);
1786                         break;
1787 #endif
1788                 default:
1789                         WARN("(handle=%d,nFunction=%d): Unknown function\n", 
1790                         handle, nFunction);
1791                         break;                          
1792         }
1793         
1794         if (!direct)
1795           if (tcsetattr(fd, TCSADRAIN, &port) == -1) {
1796                 commerror = WinError();
1797                 close(fd);
1798                 return FALSE;   
1799           } else 
1800                 result= TRUE;
1801         else
1802           {
1803             if (result == -1)
1804               {
1805                 result= FALSE;
1806                 commerror=WinError();
1807               }
1808             else
1809               result = TRUE;
1810           }
1811         close(fd);
1812         return result;
1813 }
1814
1815 /********************************************************************
1816  *      PurgeComm        (KERNEL32.557)
1817  */
1818 BOOL WINAPI PurgeComm( HANDLE handle, DWORD flags) 
1819 {
1820      int fd;
1821
1822      TRACE("handle %d, flags %lx\n", handle, flags);
1823
1824      fd = FILE_GetUnixHandle( handle, GENERIC_WRITE );
1825      if(fd<0) {
1826         FIXME("no handle %d found\n",handle);
1827         return FALSE;
1828      }
1829
1830      /*
1831      ** not exactly sure how these are different
1832      ** Perhaps if we had our own internal queues, one flushes them
1833      ** and the other flushes the kernel's buffers.
1834      */
1835      if(flags&PURGE_TXABORT)
1836          tcflush(fd,TCOFLUSH);
1837      if(flags&PURGE_RXABORT)
1838          tcflush(fd,TCIFLUSH);
1839      if(flags&PURGE_TXCLEAR)
1840          tcflush(fd,TCOFLUSH);
1841      if(flags&PURGE_RXCLEAR)
1842          tcflush(fd,TCIFLUSH);
1843      close(fd);
1844
1845      return 1;
1846 }
1847
1848 /*****************************************************************************
1849  *      ClearCommError  (KERNEL32.21)
1850  */
1851 BOOL WINAPI ClearCommError(HANDLE handle,LPDWORD errors,LPCOMSTAT lpStat)
1852 {
1853     int fd;
1854
1855     fd=FILE_GetUnixHandle( handle, GENERIC_READ );
1856     if(0>fd) 
1857     {
1858         FIXME("no handle %d found\n",handle);
1859         return FALSE;
1860     }
1861
1862     if (lpStat) 
1863     {
1864         lpStat->status = 0;
1865
1866 #ifdef TIOCOUTQ
1867         if(ioctl(fd, TIOCOUTQ, &lpStat->cbOutQue))
1868             WARN("ioctl returned error\n");
1869 #else
1870         lpStat->cbOutQue = 0; /* FIXME: find a different way to find out */
1871 #endif
1872
1873 #ifdef TIOCINQ
1874         if(ioctl(fd, TIOCINQ, &lpStat->cbInQue))
1875             WARN("ioctl returned error\n");
1876 #endif
1877
1878         TRACE("handle %d cbInQue = %ld cbOutQue = %ld\n",
1879               handle, lpStat->cbInQue, lpStat->cbOutQue);
1880     }
1881
1882     close(fd);
1883
1884     if(errors)
1885         *errors = 0;
1886
1887     /*
1888     ** After an asynchronous write opperation, the
1889     ** app will call ClearCommError to see if the
1890     ** results are ready yet. It waits for ERROR_IO_PENDING
1891     */
1892     commerror = ERROR_IO_PENDING;
1893
1894     return TRUE;
1895 }
1896
1897 /*****************************************************************************
1898  *      SetupComm       (KERNEL32.676)
1899  */
1900 BOOL WINAPI SetupComm( HANDLE handle, DWORD insize, DWORD outsize)
1901 {
1902     int fd;
1903
1904     FIXME("insize %ld outsize %ld unimplemented stub\n", insize, outsize);
1905     fd=FILE_GetUnixHandle( handle, GENERIC_WRITE );
1906     if(0>fd) {
1907         FIXME("handle %d not found?\n",handle);
1908         return FALSE;
1909     }
1910     close(fd);
1911     return TRUE;
1912
1913
1914 /*****************************************************************************
1915  *      GetCommMask     (KERNEL32.156)
1916  */
1917 BOOL WINAPI GetCommMask(HANDLE handle,LPDWORD evtmask)
1918 {
1919     BOOL ret;
1920
1921     TRACE("handle %d, mask %p\n", handle, evtmask);
1922
1923     SERVER_START_REQ
1924     {
1925         struct get_serial_info_request *req = server_alloc_req( sizeof(*req), 0 );
1926         req->handle = handle;
1927         if ((ret = !server_call( REQ_GET_SERIAL_INFO )))
1928         {
1929             if (evtmask) *evtmask = req->eventmask;
1930         }
1931     }
1932     SERVER_END_REQ;
1933     return ret;
1934 }
1935
1936 /*****************************************************************************
1937  *      SetCommMask     (KERNEL32.451)
1938  */
1939 BOOL WINAPI SetCommMask(HANDLE handle,DWORD evtmask)
1940 {
1941     BOOL ret;
1942
1943     TRACE("handle %d, mask %lx\n", handle, evtmask);
1944
1945     SERVER_START_REQ
1946     {
1947         struct set_serial_info_request *req = server_alloc_req( sizeof(*req), 0 );
1948         req->handle    = handle;
1949         req->flags     = SERIALINFO_SET_MASK;
1950         req->eventmask = evtmask;
1951         ret = !server_call( REQ_SET_SERIAL_INFO );
1952     }
1953     SERVER_END_REQ;
1954     return ret;
1955 }
1956
1957 /*****************************************************************************
1958  *      SetCommState    (KERNEL32.452)
1959  */
1960 BOOL WINAPI SetCommState(HANDLE handle,LPDCB lpdcb)
1961 {
1962      struct termios port;
1963      int fd;
1964      int bytesize, stopbits;
1965
1966      TRACE("handle %d, ptr %p\n", handle, lpdcb);
1967      TRACE("bytesize %d baudrate %ld fParity %d Parity %d stopbits %d\n",
1968            lpdcb->ByteSize,lpdcb->BaudRate,lpdcb->fParity, lpdcb->Parity,
1969            (lpdcb->StopBits == ONESTOPBIT)?1:
1970            (lpdcb->StopBits == TWOSTOPBITS)?2:0);
1971      TRACE("%s %s\n",(lpdcb->fInX)?"IXON":"~IXON",
1972            (lpdcb->fOutX)?"IXOFF":"~IXOFF");
1973
1974      fd = FILE_GetUnixHandle( handle, GENERIC_WRITE );
1975      if (fd < 0)  {
1976         FIXME("no handle %d found\n",handle);
1977         return FALSE;
1978      }
1979
1980      if ((tcgetattr(fd,&port)) == -1) {
1981          int save_error = errno;
1982          commerror = WinError();
1983          close( fd );
1984          ERR("tcgetattr error '%s'\n", strerror(save_error));
1985          return FALSE;
1986      }
1987
1988         port.c_cc[VMIN] = 0;
1989         port.c_cc[VTIME] = 1;
1990
1991 #ifdef IMAXBEL
1992         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|IMAXBEL);
1993 #else
1994         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR);
1995 #endif
1996         port.c_iflag |= (IGNBRK);
1997
1998         port.c_oflag &= ~(OPOST);
1999
2000         port.c_cflag &= ~(HUPCL);
2001         port.c_cflag |= CLOCAL | CREAD;
2002
2003         port.c_lflag &= ~(ICANON|ECHO|ISIG);
2004         port.c_lflag |= NOFLSH;
2005
2006      /*
2007      ** MJM - removed default baudrate settings
2008      ** TRACE(comm,"baudrate %ld\n",lpdcb->BaudRate);
2009      */
2010 #ifdef CBAUD
2011         port.c_cflag &= ~CBAUD;
2012         switch (lpdcb->BaudRate) {
2013                 case 110:
2014                 case CBR_110:
2015                         port.c_cflag |= B110;
2016                         break;          
2017                 case 300:
2018                 case CBR_300:
2019                         port.c_cflag |= B300;
2020                         break;          
2021                 case 600:
2022                 case CBR_600:
2023                         port.c_cflag |= B600;
2024                         break;          
2025                 case 1200:
2026                 case CBR_1200:
2027                         port.c_cflag |= B1200;
2028                         break;          
2029                 case 2400:
2030                 case CBR_2400:
2031                         port.c_cflag |= B2400;
2032                         break;          
2033                 case 4800:
2034                 case CBR_4800:
2035                         port.c_cflag |= B4800;
2036                         break;          
2037                 case 9600:
2038                 case CBR_9600:
2039                         port.c_cflag |= B9600;
2040                         break;          
2041                 case 19200:
2042                 case CBR_19200:
2043                         port.c_cflag |= B19200;
2044                         break;          
2045                 case 38400:
2046                 case CBR_38400:
2047                         port.c_cflag |= B38400;
2048                         break;          
2049 #ifdef B57600
2050                 case 57600:
2051                         port.c_cflag |= B57600;
2052                         break;          
2053 #endif
2054 #ifdef B115200
2055                 case 115200:
2056                         port.c_cflag |= B115200;
2057                         break;          
2058 #endif
2059 #ifdef B230400
2060                 case 230400:
2061                         port.c_cflag |= B230400;
2062                         break;          
2063 #endif
2064 #ifdef B460800
2065                 case 460600:
2066                         port.c_cflag |= B460800;
2067                         break;          
2068 #endif
2069                 default:
2070                         commerror = IE_BAUDRATE;
2071                         close( fd );
2072                         ERR("baudrate %ld\n",lpdcb->BaudRate);
2073                         return FALSE;
2074         }
2075 #elif !defined(__EMX__)
2076         switch (lpdcb->BaudRate) {
2077                 case 110:
2078                 case CBR_110:
2079                         port.c_ospeed = B110;
2080                         break;
2081                 case 300:
2082                 case CBR_300:
2083                         port.c_ospeed = B300;
2084                         break;
2085                 case 600:
2086                 case CBR_600:
2087                         port.c_ospeed = B600;
2088                         break;
2089                 case 1200:
2090                 case CBR_1200:
2091                         port.c_ospeed = B1200;
2092                         break;
2093                 case 2400:
2094                 case CBR_2400:
2095                         port.c_ospeed = B2400;
2096                         break;
2097                 case 4800:
2098                 case CBR_4800:
2099                         port.c_ospeed = B4800;
2100                         break;
2101                 case 9600:
2102                 case CBR_9600:
2103                         port.c_ospeed = B9600;
2104                         break;
2105                 case 19200:
2106                 case CBR_19200:
2107                         port.c_ospeed = B19200;
2108                         break;
2109                 case 38400:
2110                 case CBR_38400:
2111                         port.c_ospeed = B38400;
2112                         break;
2113                 default:
2114                         commerror = IE_BAUDRATE;
2115                         close( fd );
2116                         ERR("baudrate %ld\n",lpdcb->BaudRate);
2117                         return FALSE;
2118         }
2119         port.c_ispeed = port.c_ospeed;
2120 #endif
2121         bytesize=lpdcb->ByteSize;
2122         stopbits=lpdcb->StopBits;
2123
2124 #ifdef CMSPAR
2125         port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
2126 #else
2127         port.c_cflag &= ~(PARENB | PARODD);
2128 #endif
2129         if (lpdcb->fParity)
2130             port.c_iflag |= INPCK;
2131         else
2132             port.c_iflag &= ~INPCK;
2133         switch (lpdcb->Parity) {
2134                 case NOPARITY:
2135                         break;
2136                 case ODDPARITY:
2137                         port.c_cflag |= (PARENB | PARODD);
2138                         break;
2139                 case EVENPARITY:
2140                         port.c_cflag |= PARENB;
2141                         break;
2142 #ifdef CMSPAR
2143                 /* Linux defines mark/space (stick) parity */
2144                 case MARKPARITY:
2145                         port.c_cflag |= (PARENB | CMSPAR);
2146                         break;
2147                 case SPACEPARITY:
2148                         port.c_cflag |= (PARENB | PARODD |  CMSPAR);
2149                         break;
2150 #else
2151                 /* try the POSIX way */
2152                 case MARKPARITY:
2153                         if( stopbits == ONESTOPBIT) {
2154                             stopbits = TWOSTOPBITS;
2155                             port.c_iflag &= ~INPCK;
2156                         } else {
2157                             commerror = IE_BYTESIZE;
2158                             close( fd );
2159                             ERR("Cannot set MARK Parity\n");
2160                             return FALSE;
2161                         }
2162                         break;
2163                 case SPACEPARITY:
2164                         if( bytesize < 8) {
2165                             bytesize +=1;
2166                             port.c_iflag &= ~INPCK;
2167                         } else {
2168                             commerror = IE_BYTESIZE;
2169                             close( fd );
2170                             ERR("Cannot set SPACE Parity\n");
2171                             return FALSE;
2172                         }
2173                         break;
2174 #endif
2175                default:
2176                         commerror = IE_BYTESIZE;
2177                         close( fd );
2178                         ERR("Parity\n");
2179                         return FALSE;
2180         }
2181         
2182
2183         port.c_cflag &= ~CSIZE;
2184         switch (bytesize) {
2185                 case 5:
2186                         port.c_cflag |= CS5;
2187                         break;
2188                 case 6:
2189                         port.c_cflag |= CS6;
2190                         break;
2191                 case 7:
2192                         port.c_cflag |= CS7;
2193                         break;
2194                 case 8:
2195                         port.c_cflag |= CS8;
2196                         break;
2197                 default:
2198                         commerror = IE_BYTESIZE;
2199                         close( fd );
2200                         ERR("ByteSize\n");
2201                         return FALSE;
2202         }
2203         
2204         switch (stopbits) {
2205                 case ONESTOPBIT:
2206                                 port.c_cflag &= ~CSTOPB;
2207                                 break;
2208                 case ONE5STOPBITS: /* wil be selected if bytesize is 5 */
2209                 case TWOSTOPBITS:
2210                                 port.c_cflag |= CSTOPB;
2211                                 break;
2212                 default:
2213                         commerror = IE_BYTESIZE;
2214                         close( fd );
2215                         ERR("StopBits\n");
2216                         return FALSE;
2217         }
2218 #ifdef CRTSCTS
2219         if (    lpdcb->fOutxCtsFlow                     ||
2220                 lpdcb->fDtrControl == DTR_CONTROL_ENABLE||
2221                 lpdcb->fRtsControl == RTS_CONTROL_ENABLE
2222         ) 
2223           {
2224             port.c_cflag |= CRTSCTS;
2225             TRACE("CRTSCTS\n");
2226           }
2227         
2228         if (lpdcb->fDtrControl == DTR_CONTROL_DISABLE)
2229           {
2230             port.c_cflag &= ~CRTSCTS;
2231             TRACE("~CRTSCTS\n");
2232           }
2233
2234 #endif  
2235         if (lpdcb->fInX)
2236                 port.c_iflag |= IXON;
2237         else
2238                 port.c_iflag &= ~IXON;
2239         if (lpdcb->fOutX)
2240                 port.c_iflag |= IXOFF;
2241         else
2242                 port.c_iflag &= ~IXOFF;
2243
2244         if (tcsetattr(fd,TCSANOW,&port)==-1) { /* otherwise it hangs with pending input*/
2245                 int save_error=errno;
2246                 commerror = WinError(); 
2247                 close( fd );
2248                 ERR("tcgetattr error '%s'\n", strerror(save_error));
2249                 return FALSE;
2250         } else {
2251                 commerror = 0;
2252                 close( fd );
2253                 return TRUE;
2254         }
2255 }
2256
2257
2258 /*****************************************************************************
2259  *      GetCommState    (KERNEL32.159)
2260  */
2261 BOOL WINAPI GetCommState(HANDLE handle, LPDCB lpdcb)
2262 {
2263      struct termios port;
2264      int fd,speed;
2265
2266      TRACE("handle %d, ptr %p\n", handle, lpdcb);
2267
2268      fd = FILE_GetUnixHandle( handle, GENERIC_READ );
2269      if (fd < 0) 
2270        {
2271          ERR("FILE_GetUnixHandle failed\n");
2272          return FALSE;
2273        }
2274      if (tcgetattr(fd, &port) == -1) {
2275                 int save_error=errno;
2276                 ERR("tcgetattr error '%s'\n", strerror(save_error));
2277                 commerror = WinError(); 
2278                 close( fd );
2279                 return FALSE;
2280         }
2281      close( fd );
2282 #ifndef __EMX__
2283 #ifdef CBAUD
2284      speed= (port.c_cflag & CBAUD);
2285 #else
2286      speed= (cfgetospeed(&port));
2287 #endif
2288      switch (speed) {
2289                 case B110:
2290                         lpdcb->BaudRate = 110;
2291                         break;
2292                 case B300:
2293                         lpdcb->BaudRate = 300;
2294                         break;
2295                 case B600:
2296                         lpdcb->BaudRate = 600;
2297                         break;
2298                 case B1200:
2299                         lpdcb->BaudRate = 1200;
2300                         break;
2301                 case B2400:
2302                         lpdcb->BaudRate = 2400;
2303                         break;
2304                 case B4800:
2305                         lpdcb->BaudRate = 4800;
2306                         break;
2307                 case B9600:
2308                         lpdcb->BaudRate = 9600;
2309                         break;
2310                 case B19200:
2311                         lpdcb->BaudRate = 19200;
2312                         break;
2313                 case B38400:
2314                         lpdcb->BaudRate = 38400;
2315                         break;
2316 #ifdef B57600
2317                 case B57600:
2318                         lpdcb->BaudRate = 57600;
2319                         break;          
2320 #endif
2321 #ifdef B115200
2322                 case B115200:
2323                         lpdcb->BaudRate = 115200;
2324                         break;          
2325 #endif
2326 #ifdef B230400
2327                 case B230400:
2328                         lpdcb->BaudRate = 230400;
2329                         break;          
2330 #endif
2331 #ifdef B460800
2332                 case B460800:
2333                         lpdcb->BaudRate = 460800;
2334                         break;          
2335 #endif
2336                 default:
2337                         ERR("unknown speed %x \n",speed);
2338         }
2339 #endif
2340         switch (port.c_cflag & CSIZE) {
2341                 case CS5:
2342                         lpdcb->ByteSize = 5;
2343                         break;
2344                 case CS6:
2345                         lpdcb->ByteSize = 6;
2346                         break;
2347                 case CS7:
2348                         lpdcb->ByteSize = 7;
2349                         break;
2350                 case CS8:
2351                         lpdcb->ByteSize = 8;
2352                         break;
2353                 default:
2354                         ERR("unknown size %x \n",port.c_cflag & CSIZE);
2355         }       
2356         
2357         if(port.c_iflag & INPCK)
2358             lpdcb->fParity = TRUE;
2359         else
2360             lpdcb->fParity = FALSE;
2361 #ifdef CMSPAR
2362         switch (port.c_cflag & (PARENB | PARODD | CMSPAR))
2363 #else
2364         switch (port.c_cflag & (PARENB | PARODD))
2365 #endif
2366         {
2367                 case 0:
2368                         lpdcb->Parity = NOPARITY;
2369                         break;
2370                 case PARENB:
2371                         lpdcb->Parity = EVENPARITY;
2372                         break;
2373                 case (PARENB | PARODD):
2374                         lpdcb->Parity = ODDPARITY;              
2375                         break;
2376 #ifdef CMSPAR
2377                 case (PARENB | CMSPAR):
2378                         lpdcb->Parity = MARKPARITY;             
2379                         break;
2380                 case (PARENB | PARODD | CMSPAR):
2381                         lpdcb->Parity = SPACEPARITY;            
2382                         break;
2383 #endif
2384         }
2385
2386         if (port.c_cflag & CSTOPB)
2387             if(lpdcb->ByteSize == 5)
2388                 lpdcb->StopBits = ONE5STOPBITS;
2389             else
2390                 lpdcb->StopBits = TWOSTOPBITS;
2391         else
2392             lpdcb->StopBits = ONESTOPBIT;
2393
2394         lpdcb->fNull = 0;
2395         lpdcb->fBinary = 1;
2396
2397 #ifdef CRTSCTS
2398
2399         if (port.c_cflag & CRTSCTS) {
2400                 lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
2401                 lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
2402                 lpdcb->fOutxCtsFlow = 1;
2403                 lpdcb->fOutxDsrFlow = 1;
2404         } else 
2405 #endif
2406         {
2407                 lpdcb->fDtrControl = DTR_CONTROL_DISABLE;
2408                 lpdcb->fRtsControl = RTS_CONTROL_DISABLE;
2409         }
2410         if (port.c_iflag & IXON)
2411                 lpdcb->fInX = 1;
2412         else
2413                 lpdcb->fInX = 0;
2414
2415         if (port.c_iflag & IXOFF)
2416                 lpdcb->fOutX = 1;
2417         else
2418                 lpdcb->fOutX = 0;
2419 /*
2420         lpdcb->XonChar = 
2421         lpdcb->XoffChar = 
2422  */
2423         lpdcb->XonLim = 10;
2424         lpdcb->XoffLim = 10;
2425
2426         commerror = 0;
2427
2428         TRACE("OK\n");
2429  
2430         TRACE("bytesize %d baudrate %ld fParity %d Parity %d stopbits %d\n",
2431               lpdcb->ByteSize,lpdcb->BaudRate,lpdcb->fParity, lpdcb->Parity,
2432               (lpdcb->StopBits == ONESTOPBIT)?1:
2433               (lpdcb->StopBits == TWOSTOPBITS)?2:0);
2434         TRACE("%s %s\n",(lpdcb->fInX)?"IXON":"~IXON",
2435               (lpdcb->fOutX)?"IXOFF":"~IXOFF");
2436 #ifdef CRTSCTS
2437         if (    lpdcb->fOutxCtsFlow                     ||
2438                 lpdcb->fDtrControl == DTR_CONTROL_ENABLE||
2439                 lpdcb->fRtsControl == RTS_CONTROL_ENABLE
2440                 ) 
2441           TRACE("CRTSCTS\n");
2442         
2443         if (lpdcb->fDtrControl == DTR_CONTROL_DISABLE)
2444           TRACE("~CRTSCTS\n");
2445         
2446 #endif  
2447         return TRUE;
2448 }
2449
2450 /*****************************************************************************
2451  *      TransmitCommChar        (KERNEL32.535)
2452  */
2453 BOOL WINAPI TransmitCommChar(HANDLE hComm,CHAR chTransmit)
2454 {
2455         FIXME("(%x,'%c'), use win32 handle!\n",hComm,chTransmit);
2456         return TRUE;
2457 }
2458
2459 /*****************************************************************************
2460  *      GetCommTimeouts         (KERNEL32.160)
2461  */
2462 BOOL WINAPI GetCommTimeouts(HANDLE hComm,LPCOMMTIMEOUTS lptimeouts)
2463 {
2464     BOOL ret;
2465
2466     TRACE("(%x,%p)\n",hComm,lptimeouts);
2467
2468     if(!lptimeouts)
2469     {
2470         SetLastError(ERROR_INVALID_PARAMETER);
2471         return FALSE;
2472     }
2473
2474     SERVER_START_REQ
2475     {
2476         struct get_serial_info_request *req = server_alloc_req( sizeof(*req), 0 );
2477         req->handle = hComm;
2478         if ((ret = !server_call( REQ_GET_SERIAL_INFO )))
2479         {
2480             lptimeouts->ReadIntervalTimeout         = req->readinterval;
2481             lptimeouts->ReadTotalTimeoutMultiplier  = req->readmult;
2482             lptimeouts->ReadTotalTimeoutConstant    = req->readconst;
2483             lptimeouts->WriteTotalTimeoutMultiplier = req->writemult;
2484             lptimeouts->WriteTotalTimeoutConstant   = req->writeconst;
2485         }
2486     }
2487     SERVER_END_REQ;
2488     return ret;
2489 }
2490
2491 /*****************************************************************************
2492  *      SetCommTimeouts         (KERNEL32.453)
2493  *
2494  * Sets the timeouts used when reading and writing data to/from COMM ports.
2495  *
2496  * ReadIntervalTimeout 
2497  *     - converted and passes to linux kernel as c_cc[VTIME]
2498  * ReadTotalTimeoutMultiplier, ReadTotalTimeoutConstant
2499  *     - used in ReadFile to calculate GetOverlappedResult's timeout
2500  * WriteTotalTimeoutMultiplier, WriteTotalTimeoutConstant
2501  *     - used in WriteFile to calculate GetOverlappedResult's timeout
2502  */
2503 BOOL WINAPI SetCommTimeouts(
2504     HANDLE hComm,              /* [I] handle of COMM device */
2505     LPCOMMTIMEOUTS lptimeouts /* [I] pointer to COMMTIMEOUTS structure */
2506 ) {
2507     BOOL ret;
2508     int fd;
2509     struct termios tios;
2510
2511     TRACE("(%x,%p)\n",hComm,lptimeouts);
2512
2513     if(!lptimeouts)
2514     {
2515         SetLastError(ERROR_INVALID_PARAMETER);
2516         return FALSE;
2517     }
2518
2519     SERVER_START_REQ
2520     {
2521         struct set_serial_info_request *req = server_alloc_req( sizeof(*req), 0 );
2522         req->handle       = hComm;
2523         req->flags        = SERIALINFO_SET_TIMEOUTS;
2524         req->readinterval = lptimeouts->ReadIntervalTimeout ;
2525         req->readmult     = lptimeouts->ReadTotalTimeoutMultiplier ;
2526         req->readconst    = lptimeouts->ReadTotalTimeoutConstant ;
2527         req->writemult    = lptimeouts->WriteTotalTimeoutMultiplier ;
2528         req->writeconst   = lptimeouts->WriteTotalTimeoutConstant ;
2529         ret = !server_call( REQ_SET_SERIAL_INFO );
2530     }
2531     SERVER_END_REQ;
2532     if (!ret) return FALSE;
2533
2534     /* FIXME: move this stuff to the server */
2535     fd = FILE_GetUnixHandle( hComm, GENERIC_WRITE );
2536     if (fd < 0) {
2537        FIXME("no fd for handle = %0x!.\n",hComm);
2538        return FALSE;
2539     }
2540
2541     if (-1==tcgetattr(fd,&tios)) {
2542         FIXME("tcgetattr on fd %d failed!\n",fd);
2543         return FALSE;
2544     }
2545     /* VTIME is in 1/10 seconds */
2546     tios.c_cc[VTIME]= (lptimeouts->ReadIntervalTimeout+99)/100;
2547     if (-1==tcsetattr(fd,0,&tios)) {
2548         FIXME("tcsetattr on fd %d failed!\n",fd);
2549         return FALSE;
2550     }
2551     close(fd);
2552     return TRUE;
2553 }
2554
2555 /***********************************************************************
2556  *           GetCommModemStatus   (KERNEL32.285)
2557  */
2558 BOOL WINAPI GetCommModemStatus(HANDLE hFile,LPDWORD lpModemStat )
2559 {
2560         int fd,mstat, result=FALSE;
2561         
2562         *lpModemStat=0;
2563 #ifdef TIOCMGET
2564         fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
2565         if(fd<0)
2566                 return FALSE;
2567         result = ioctl(fd, TIOCMGET, &mstat);
2568         close(fd);
2569         if (result == -1)
2570           {
2571             TRACE("ioctl failed\n");
2572             return FALSE;
2573           }
2574 #ifdef TIOCM_CTS
2575         if (mstat & TIOCM_CTS)
2576             *lpModemStat |= MS_CTS_ON;
2577 #endif
2578 #ifdef TIOCM_DSR
2579         if (mstat & TIOCM_DSR)
2580           *lpModemStat |= MS_DSR_ON;
2581 #endif
2582 #ifdef TIOCM_RNG
2583         if (mstat & TIOCM_RNG)
2584           *lpModemStat |= MS_RING_ON;
2585 #endif
2586 #ifdef TIOCM_CAR
2587         /*FIXME:  Not really sure about RLSD  UB 990810*/
2588         if (mstat & TIOCM_CAR)
2589           *lpModemStat |= MS_RLSD_ON;
2590 #endif
2591         TRACE("%s%s%s%s\n",
2592               (*lpModemStat &MS_RLSD_ON)?"MS_RLSD_ON ":"",
2593               (*lpModemStat &MS_RING_ON)?"MS_RING_ON ":"",
2594               (*lpModemStat &MS_DSR_ON)?"MS_DSR_ON ":"",
2595               (*lpModemStat &MS_CTS_ON)?"MS_CTS_ON ":"");
2596         return TRUE;
2597 #else
2598         return FALSE;
2599 #endif
2600 }
2601
2602 VOID COMM_WaitCommEventService(void **args)
2603 {
2604     LPOVERLAPPED lpOverlapped = (LPOVERLAPPED)args[0];
2605     LPDWORD buffer = (LPDWORD)args[1];
2606     DWORD events = (DWORD)args[2];
2607
2608     TRACE("overlapped %p wait complete %p <- %lx\n",lpOverlapped,buffer,events);
2609     if(buffer)
2610         *buffer = events;
2611  
2612     SetEvent( lpOverlapped->hEvent);
2613 }
2614
2615 /***********************************************************************
2616  *           WaitCommEvent   (KERNEL32.719)
2617  *
2618  * Wait until something interesting happens on a COMM port.
2619  * Interesting things (events) are set by calling SetCommMask before
2620  * this function is called.
2621  *
2622  * RETURNS:
2623  *   TRUE if successful
2624  *   FALSE if failure
2625  *
2626  *   The set of detected events will be written to *lpdwEventMask
2627  *   ERROR_IO_PENDING will be returned the overlapped structure was passed
2628  *
2629  * BUGS:
2630  *  Only supports EV_RXCHAR and EV_TXEMPTY
2631  */
2632 BOOL WINAPI WaitCommEvent(
2633     HANDLE hFile,             /* [I] handle of comm port to wait for */
2634     LPDWORD lpdwEvents,       /* [O] event(s) that were detected */
2635     LPOVERLAPPED lpOverlapped /* [I/O] for Asynchronous waiting */
2636 ) {
2637     OVERLAPPED ov;
2638     LPOVERLAPPED lpov;
2639     int ret;
2640
2641     TRACE("(%x %p %p )\n",hFile, lpdwEvents,lpOverlapped);
2642
2643     /* if there is no overlapped structure, create our own */
2644     if(!lpOverlapped)
2645     {
2646         ov.hEvent = CreateEventA(NULL,FALSE,FALSE,NULL);
2647         lpov = &ov;
2648     }
2649     else
2650         lpov = lpOverlapped;
2651
2652     /* check that the overlapped structure has a valid event flag */
2653     if ( (lpov->hEvent==0) || (lpov->hEvent == INVALID_HANDLE_VALUE) )
2654 {
2655         ERR("Couldn't create Event flag for Overlapped structure\n");
2656         SetLastError(ERROR_INVALID_PARAMETER);
2657         return FALSE;
2658     }
2659
2660     lpov->Internal = 0;
2661     lpov->InternalHigh = hFile;
2662     lpov->Offset = 0;
2663     lpov->OffsetHigh = 0;
2664
2665     /* start an ASYNCHRONOUS WaitCommEvent */
2666     SERVER_START_REQ
2667     {
2668         struct create_async_request *req = server_alloc_req( sizeof(*req), 0 );
2669
2670         req->file_handle = hFile;
2671         req->overlapped  = lpov;
2672         req->buffer = lpdwEvents;
2673         req->count = 0;
2674         req->func = COMM_WaitCommEventService;
2675         req->type = ASYNC_TYPE_WAIT;
2676
2677         ret=server_call( REQ_CREATE_ASYNC );
2678
2679         lpov->Internal = req->ov_handle;
2680     }
2681     SERVER_END_REQ;
2682
2683     if(ret)
2684     {
2685         if(!lpOverlapped)
2686             CloseHandle(lpov->hEvent);
2687         TRACE("server call failed.\n");
2688         return FALSE;
2689     }
2690
2691     /* wait ourselves if the caller didn't give us an overlapped struct */
2692     if(!lpOverlapped)
2693     {
2694         GetOverlappedResult(hFile, lpov, NULL, TRUE);
2695         CloseHandle(lpov->hEvent);
2696         lpov->hEvent=0;
2697     }
2698     else
2699     {
2700         /* caller wants overlapped I/O using GetOverlapped result */
2701         SetLastError(ERROR_IO_PENDING);
2702         return FALSE;
2703     }
2704
2705     return TRUE;
2706 }
2707
2708 /***********************************************************************
2709  *           GetCommProperties   (KERNEL32.286)
2710  *
2711  * This function fills in a structure with the capabilities of the 
2712  * communications port driver.
2713  *
2714  * RETURNS
2715  *
2716  *  TRUE on success, FALSE on failure
2717  *  If successful, the lpCommProp structure be filled in with
2718  *  properties of the comm port.
2719  */
2720 BOOL WINAPI GetCommProperties(
2721         HANDLE hFile,          /* handle of the comm port */
2722         LPCOMMPROP lpCommProp /* pointer to struct to be filled */
2723 ) {
2724     FIXME("(%d %p )\n",hFile,lpCommProp);
2725     if(!lpCommProp)
2726         return FALSE;
2727
2728     /*
2729      * These values should be valid for LINUX's serial driver
2730      * FIXME: Perhaps they deserve an #ifdef LINUX
2731      */
2732     memset(lpCommProp,0,sizeof(COMMPROP));
2733     lpCommProp->wPacketLength       = 1;
2734     lpCommProp->wPacketVersion      = 1;
2735     lpCommProp->dwServiceMask       = SP_SERIALCOMM;
2736     lpCommProp->dwReserved1         = 0;
2737     lpCommProp->dwMaxTxQueue        = 4096;
2738     lpCommProp->dwMaxRxQueue        = 4096;
2739     lpCommProp->dwMaxBaud           = BAUD_115200;
2740     lpCommProp->dwProvSubType       = PST_RS232;
2741     lpCommProp->dwProvCapabilities  = PCF_DTRDSR | PCF_PARITY_CHECK | PCF_RTSCTS ;
2742     lpCommProp->dwSettableParams    = SP_BAUD | SP_DATABITS | SP_HANDSHAKING | 
2743                                       SP_PARITY | SP_PARITY_CHECK | SP_STOPBITS ;
2744     lpCommProp->dwSettableBaud      = BAUD_075 | BAUD_110 | BAUD_134_5 | BAUD_150 |
2745                 BAUD_300 | BAUD_600 | BAUD_1200 | BAUD_1800 | BAUD_2400 | BAUD_4800 |
2746                 BAUD_9600 | BAUD_19200 | BAUD_38400 | BAUD_57600 | BAUD_115200 ;
2747     lpCommProp->wSettableData       = DATABITS_5 | DATABITS_6 | DATABITS_7 | DATABITS_8 ;
2748     lpCommProp->wSettableStopParity = STOPBITS_10 | STOPBITS_15 | STOPBITS_20 | 
2749                 PARITY_NONE | PARITY_ODD |PARITY_EVEN | PARITY_MARK | PARITY_SPACE;
2750     lpCommProp->dwCurrentTxQueue    = lpCommProp->dwMaxTxQueue;
2751     lpCommProp->dwCurrentRxQueue    = lpCommProp->dwMaxRxQueue;
2752
2753     return TRUE;
2754 }
2755
2756 /***********************************************************************
2757  * FIXME:
2758  * The functionality of CommConfigDialogA, GetDefaultCommConfig and
2759  * SetDefaultCommConfig is implemented in a DLL (usually SERIALUI.DLL).
2760  * This is dependent on the type of COMM port, but since it is doubtful
2761  * anybody will get around to implementing support for fancy serial
2762  * ports in WINE, this is hardcoded for the time being.  The name of 
2763  * this DLL should be stored in and read from the system registry in 
2764  * the hive HKEY_LOCAL_MACHINE, key
2765  * System\\CurrentControlSet\\Services\\Class\\Ports\\????
2766  * where ???? is the port number... that is determined by PNP
2767  * The DLL should be loaded when the COMM port is opened, and closed 
2768  * when the COMM port is closed. - MJM 20 June 2000
2769  ***********************************************************************/
2770 static CHAR lpszSerialUI[] = "serialui.dll";
2771
2772
2773 /***********************************************************************
2774  *           CommConfigDialogA   (KERNEL32.140)
2775  *
2776  * Raises a dialog that allows the user to configure a comm port.
2777  * Fills the COMMCONFIG struct with information specified by the user.
2778  * This function should call a similar routine in the COMM driver...
2779  *
2780  * RETURNS
2781  *
2782  *  TRUE on success, FALSE on failure
2783  *  If successful, the lpCommConfig structure will contain a new
2784  *  configuration for the comm port, as specified by the user.
2785  *
2786  * BUGS
2787  *  The library with the CommConfigDialog code is never unloaded.
2788  * Perhaps this should be done when the comm port is closed?
2789  */
2790 BOOL WINAPI CommConfigDialogA(
2791         LPCSTR lpszDevice,         /* name of communications device */
2792         HANDLE hWnd,               /* parent window for the dialog */
2793         LPCOMMCONFIG lpCommConfig  /* pointer to struct to fill */
2794 ) {
2795     FARPROC lpfnCommDialog;
2796     HMODULE hConfigModule;
2797     BOOL r;
2798
2799     TRACE("(%p %x %p)\n",lpszDevice, hWnd, lpCommConfig);
2800
2801     hConfigModule = LoadLibraryA(lpszSerialUI);
2802     if(!hConfigModule)
2803         return FALSE;
2804
2805     lpfnCommDialog = GetProcAddress(hConfigModule, (LPCSTR)3L);
2806
2807     if(!lpfnCommDialog)
2808         return FALSE;
2809
2810     r = lpfnCommDialog(lpszDevice,hWnd,lpCommConfig);
2811
2812     /* UnloadLibrary(hConfigModule); */
2813
2814     return r;
2815 }
2816
2817 /***********************************************************************
2818  *           CommConfigDialogW   (KERNEL32.141)
2819  *
2820  * see CommConfigDialogA for more info
2821  */
2822 BOOL WINAPI CommConfigDialogW(
2823         LPCWSTR lpszDevice,        /* name of communications device */
2824         HANDLE hWnd,               /* parent window for the dialog */
2825         LPCOMMCONFIG lpCommConfig  /* pointer to struct to fill */
2826 ) {
2827     BOOL r;
2828     LPSTR lpDeviceA;
2829
2830     lpDeviceA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpszDevice );
2831     if(lpDeviceA)
2832         return FALSE;
2833     r = CommConfigDialogA(lpDeviceA,hWnd,lpCommConfig);
2834     HeapFree( GetProcessHeap(), 0, lpDeviceA );
2835     return r;
2836 }
2837
2838 /***********************************************************************
2839  *           GetCommConfig     (KERNEL32.283)
2840  *
2841  * Fill in the COMMCONFIG structure for the comm port hFile
2842  *
2843  * RETURNS
2844  *
2845  *  TRUE on success, FALSE on failure
2846  *  If successful, lpCommConfig contains the comm port configuration.
2847  */
2848 BOOL WINAPI GetCommConfig(
2849         HANDLE hFile,
2850         LPCOMMCONFIG lpCommConfig
2851 ) {
2852     BOOL r;
2853
2854     TRACE("(%x %p)\n",hFile,lpCommConfig);
2855
2856     if(lpCommConfig == NULL)
2857         return FALSE;
2858
2859     lpCommConfig->dwSize = sizeof(COMMCONFIG);
2860     lpCommConfig->wVersion = 1;
2861     lpCommConfig->wReserved = 0;
2862     r = GetCommState(hFile,&lpCommConfig->dcb);
2863     lpCommConfig->dwProviderSubType = PST_RS232;
2864     lpCommConfig->dwProviderOffset = 0;
2865     lpCommConfig->dwProviderSize = 0;
2866
2867     return r;
2868 }
2869
2870 /***********************************************************************
2871  *           SetCommConfig     (KERNEL32.617)
2872  *
2873  */
2874 BOOL WINAPI SetCommConfig(
2875         HANDLE hFile,
2876         LPCOMMCONFIG lpCommConfig
2877 ) {
2878     BOOL r;
2879
2880     TRACE("(%x %p)\n",hFile,lpCommConfig);
2881     
2882     r = SetCommState(hFile,&lpCommConfig->dcb);
2883     return r;
2884 }
2885
2886 /***********************************************************************
2887  *           SetDefaultCommConfigA   (KERNEL32.638)
2888  */
2889 BOOL WINAPI SetDefaultCommConfigA(
2890         LPCSTR lpszDevice, 
2891         LPCOMMCONFIG lpCommConfig,
2892         DWORD dwSize
2893 ) {
2894     FARPROC lpfnSetDefaultCommConfig;
2895     HMODULE hConfigModule;
2896     BOOL r;
2897
2898     TRACE("(%p %p %lx)\n",lpszDevice, lpCommConfig, dwSize);
2899
2900     hConfigModule = LoadLibraryA(lpszSerialUI);
2901     if(!hConfigModule)
2902         return FALSE;
2903
2904     lpfnSetDefaultCommConfig = GetProcAddress(hConfigModule, (LPCSTR)4L);
2905
2906     if(! lpfnSetDefaultCommConfig)
2907         return TRUE;
2908
2909     r = lpfnSetDefaultCommConfig(lpszDevice, lpCommConfig, dwSize);
2910
2911     /* UnloadLibrary(hConfigModule); */
2912
2913     return r;
2914 }
2915
2916
2917 /***********************************************************************
2918  *           SetDefaultCommConfigW     (KERNEL32.639)
2919  *
2920  */
2921 BOOL WINAPI SetDefaultCommConfigW(
2922         LPCWSTR lpszDevice, 
2923         LPCOMMCONFIG lpCommConfig,
2924         DWORD dwSize
2925 ) {
2926     BOOL r;
2927     LPSTR lpDeviceA;
2928
2929     TRACE("(%s %p %lx)\n",debugstr_w(lpszDevice),lpCommConfig,dwSize);
2930
2931     lpDeviceA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpszDevice );
2932     if(lpDeviceA)
2933         return FALSE;
2934     r = SetDefaultCommConfigA(lpDeviceA,lpCommConfig,dwSize);
2935     HeapFree( GetProcessHeap(), 0, lpDeviceA );
2936     return r;
2937 }
2938
2939
2940 /***********************************************************************
2941  *           GetDefaultCommConfigA   (KERNEL32.313)
2942  */
2943 BOOL WINAPI GetDefaultCommConfigA(LPCSTR lpszName,LPCOMMCONFIG lpCC,
2944                                       LPDWORD lpdwSize)
2945 {    
2946      LPDCB lpdcb = &(lpCC->dcb);
2947      char  temp[40];
2948
2949      if (strncasecmp(lpszName,"COM",3)) {
2950         ERR("not implemented for <%s>\n", lpszName);
2951         return FALSE;
2952      }
2953
2954      if (!ValidCOMPort(lpszName[3]-'1'))
2955         return FALSE;
2956
2957      TRACE("(%s %p %ld)\n", lpszName, lpCC, *lpdwSize );
2958      if (*lpdwSize < sizeof(COMMCONFIG)) {
2959          *lpdwSize = sizeof(COMMCONFIG);
2960          return FALSE;
2961        }
2962
2963      *lpdwSize = sizeof(COMMCONFIG);
2964
2965      lpCC->dwSize = sizeof(COMMCONFIG);
2966      lpCC->wVersion = 1;
2967      lpCC->dwProviderSubType = PST_RS232;
2968      lpCC->dwProviderOffset = 0L;
2969      lpCC->dwProviderSize = 0L;
2970
2971      (void) sprintf( temp, "COM%c:38400,n,8,1", lpszName[3]);
2972      FIXME("setting %s as default\n", temp);
2973
2974      return BuildCommDCBA( temp, lpdcb);
2975 }
2976
2977 /**************************************************************************
2978  *         GetDefaultCommConfigW                (KERNEL32.314)
2979  */
2980 BOOL WINAPI GetDefaultCommConfigW( LPCWSTR lpszName,LPCOMMCONFIG lpCC,
2981                                       LPDWORD lpdwSize)
2982 {
2983         LPSTR   lpszNameA;
2984         BOOL    ret;
2985
2986         TRACE("(%p,%p,%ld)\n",lpszName,lpCC,*lpdwSize);
2987         lpszNameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpszName );
2988         ret=GetDefaultCommConfigA(lpszNameA,lpCC,lpdwSize);
2989         HeapFree( GetProcessHeap(), 0, lpszNameA );
2990         return ret;
2991 }
2992