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