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