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