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