- Implement RtlLocalTimeToSystemTime and RtlSystemTimeToLocalTime.
[wine] / dlls / kernel / comm.c
1 /*
2  * DEC 93 Erik Bos <erik@xs4all.nl>
3  *
4  * Copyright 1996 Marcus Meissner
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * History:
21  *
22  * Apr 3, 1999.  Lawson Whitney <lawson_whitney@juno.com>
23  * - Fixed the modem control part of EscapeCommFunction16.
24  *
25  * Mar 31, 1999. Ove Kåven <ovek@arcticnet.no>
26  * - Implemented buffers and EnableCommNotification.
27  *
28  * Mar 3, 1999. Ove Kåven <ovek@arcticnet.no>
29  * - Use port indices instead of unixfds for win16
30  * - Moved things around (separated win16 and win32 routines)
31  * - Added some hints on how to implement buffers and EnableCommNotification.
32  *
33  * Oktober 98, Rein Klazes [RHK]
34  * A program that wants to monitor the modem status line (RLSD/DCD) may
35  * poll the modem status register in the commMask structure. I update the bit
36  * in GetCommError, waiting for an implementation of communication events.
37  *
38  * July 6, 1998. Fixes and comments by Valentijn Sessink
39  *                                     <vsessink@ic.uva.nl> [V]
40  *
41  * August 12, 1997.  Take a bash at SetCommEventMask - Lawson Whitney
42  *                                     <lawson_whitney@juno.com>
43  *
44  * May 26, 1997.  Fixes and comments by Rick Richardson <rick@dgii.com> [RER]
45  * - ptr->fd wasn't getting cleared on close.
46  * - GetCommEventMask() and GetCommError() didn't do much of anything.
47  *   IMHO, they are still wrong, but they at least implement the RXCHAR
48  *   event and return I/O queue sizes, which makes the app I'm interested
49  *   in (analog devices EZKIT DSP development system) work.
50  */
51
52 #include "config.h"
53 #include "wine/port.h"
54
55 #include <stdlib.h>
56 #include <stdio.h>
57 #ifdef HAVE_TERMIOS_H
58 #include <termios.h>
59 #endif
60 #include <fcntl.h>
61 #include <string.h>
62 #ifdef HAVE_STRINGS_H
63 # include <strings.h>
64 #endif
65 #include <errno.h>
66 #include <ctype.h>
67 #include <sys/stat.h>
68 #ifdef HAVE_SYS_FILIO_H
69 # include <sys/filio.h>
70 #endif
71 #ifdef HAVE_SYS_IOCTL_H
72 #include <sys/ioctl.h>
73 #endif
74 #ifdef HAVE_UNISTD_H
75 # include <unistd.h>
76 #endif
77 #ifdef HAVE_SYS_POLL_H
78 # include <sys/poll.h>
79 #endif
80 #ifdef HAVE_SYS_MODEM_H
81 # include <sys/modem.h>
82 #endif
83 #ifdef HAVE_SYS_STRTIO_H
84 # include <sys/strtio.h>
85 #endif
86
87 #include "winbase.h"
88 #include "winerror.h"
89
90 #include "wine/server.h"
91 #include "async.h"
92 #include "file.h"
93 #include "heap.h"
94
95 #include "wine/debug.h"
96
97 #ifdef HAVE_LINUX_SERIAL_H
98 #include <linux/serial.h>
99 #endif
100
101 WINE_DEFAULT_DEBUG_CHANNEL(comm);
102
103 /***********************************************************************
104  * Asynchronous I/O for asynchronous wait requests                     *
105  */
106
107 static DWORD commio_get_async_status (const async_private *ovp);
108 static DWORD commio_get_async_count (const async_private *ovp);
109 static void commio_set_async_status (async_private *ovp, const DWORD status);
110 static void commio_async_cleanup  (async_private *ovp);
111
112 static async_ops commio_async_ops =
113 {
114     commio_get_async_status,       /* get_status */
115     commio_set_async_status,       /* set_status */
116     commio_get_async_count,        /* get_count */
117     NULL,                          /* call_completion */
118     commio_async_cleanup           /* cleanup */
119 };
120
121 typedef struct async_commio
122 {
123     struct async_private             async;
124     LPOVERLAPPED                     lpOverlapped;
125     char                             *buffer;
126 } async_commio;
127
128 static DWORD commio_get_async_status (const struct async_private *ovp)
129 {
130     return ((async_commio*) ovp)->lpOverlapped->Internal;
131 }
132
133 static void commio_set_async_status (async_private *ovp, const DWORD status)
134 {
135     ((async_commio*) ovp)->lpOverlapped->Internal = status;
136 }
137
138 static DWORD commio_get_async_count (const struct async_private *ovp)
139 {
140     return 0;
141 }
142
143 static void commio_async_cleanup  (async_private *ovp)
144 {
145     HeapFree(GetProcessHeap(), 0, ovp );
146 }
147
148 /***********************************************************************/
149
150 #if !defined(TIOCINQ) && defined(FIONREAD)
151 #define TIOCINQ FIONREAD
152 #endif
153
154 static int COMM_WhackModem(int fd, unsigned int andy, unsigned int orrie)
155 {
156 #ifdef TIOCMGET
157     unsigned int mstat, okay;
158     okay = ioctl(fd, TIOCMGET, &mstat);
159     if (okay) return okay;
160     if (andy) mstat &= andy;
161     mstat |= orrie;
162     return ioctl(fd, TIOCMSET, &mstat);
163 #else
164     return 0;
165 #endif
166 }
167
168 /***********************************************************************
169  *           COMM_BuildOldCommDCB   (Internal)
170  *
171  *  Build a DCB using the old style settings string eg: "COMx:96,n,8,1"
172  *  We ignore the COM port index, since we can support more than 4 ports.
173  */
174 BOOL WINAPI COMM_BuildOldCommDCB(LPCSTR device, LPDCB lpdcb)
175 {
176         /* "COM1:96,n,8,1"      */
177         /*  012345              */
178         char *ptr, temp[256], last;
179         int rate;
180
181         TRACE("(%s), ptr %p\n", device, lpdcb);
182
183         /* Some applications call this function with "9600,n,8,1"
184          * not sending the "COM1:" parameter at left of string */
185         if (!strncasecmp(device,"COM",3))
186         {
187             if (!device[3]) return FALSE;
188             if (device[4] != ':' && device[4] != ' ') return FALSE;
189             strcpy(temp,device+5);
190         }
191         else strcpy(temp,device);
192
193         last=temp[strlen(temp)-1];
194         ptr = strtok(temp, ", ");
195
196         /* DOS/Windows only compares the first two numbers
197          * and assigns an appropriate baud rate.
198          * You can supply 961324245, it still returns 9600 ! */
199         if (strlen(ptr) < 2)
200         {
201                 WARN("Unknown baudrate string '%s' !\n", ptr);
202                 return FALSE; /* error: less than 2 chars */
203         }
204         ptr[2] = '\0';
205         rate = atoi(ptr);
206
207         switch (rate) {
208         case 11:
209         case 30:
210         case 60:
211                 rate *= 10;
212                 break;
213         case 12:
214         case 24:
215         case 48:
216         case 96:
217                 rate *= 100;
218                 break;
219         case 19:
220                 rate = 19200;
221                 break;
222         default:
223                 WARN("Unknown baudrate indicator %d !\n", rate);
224                 return FALSE;
225         }
226
227         lpdcb->BaudRate = rate;
228         TRACE("baudrate (%ld)\n", lpdcb->BaudRate);
229
230         ptr = strtok(NULL, ", ");
231         if (islower(*ptr))
232                 *ptr = toupper(*ptr);
233
234         TRACE("parity (%c)\n", *ptr);
235         lpdcb->fParity = TRUE;
236         switch (*ptr) {
237         case 'N':
238                 lpdcb->Parity = NOPARITY;
239                 lpdcb->fParity = FALSE;
240                 break;
241         case 'E':
242                 lpdcb->Parity = EVENPARITY;
243                 break;
244         case 'M':
245                 lpdcb->Parity = MARKPARITY;
246                 break;
247         case 'O':
248                 lpdcb->Parity = ODDPARITY;
249                 break;
250         case 'S':
251                 lpdcb->Parity = SPACEPARITY;
252                 break;
253         default:
254                 WARN("Unknown parity `%c'!\n", *ptr);
255                 return FALSE;
256         }
257
258         ptr = strtok(NULL, ", ");
259         TRACE("charsize (%c)\n", *ptr);
260         lpdcb->ByteSize = *ptr - '0';
261
262         ptr = strtok(NULL, ", ");
263         TRACE("stopbits (%c)\n", *ptr);
264         switch (*ptr) {
265         case '1':
266                 lpdcb->StopBits = ONESTOPBIT;
267                 break;
268         case '2':
269                 lpdcb->StopBits = TWOSTOPBITS;
270                 break;
271         default:
272                 WARN("Unknown # of stopbits `%c'!\n", *ptr);
273                 return FALSE;
274         }
275
276         if (last == 'x') {
277                 lpdcb->fInX             = TRUE;
278                 lpdcb->fOutX            = TRUE;
279                 lpdcb->fOutxCtsFlow     = FALSE;
280                 lpdcb->fOutxDsrFlow     = FALSE;
281                 lpdcb->fDtrControl      = DTR_CONTROL_ENABLE;
282                 lpdcb->fRtsControl      = RTS_CONTROL_ENABLE;
283         } else if (last=='p') {
284                 lpdcb->fInX             = FALSE;
285                 lpdcb->fOutX            = FALSE;
286                 lpdcb->fOutxCtsFlow     = TRUE;
287                 lpdcb->fOutxDsrFlow     = FALSE;
288                 lpdcb->fDtrControl      = DTR_CONTROL_ENABLE;
289                 lpdcb->fRtsControl      = RTS_CONTROL_HANDSHAKE;
290         } else {
291                 lpdcb->fInX             = FALSE;
292                 lpdcb->fOutX            = FALSE;
293                 lpdcb->fOutxCtsFlow     = FALSE;
294                 lpdcb->fOutxDsrFlow     = FALSE;
295                 lpdcb->fDtrControl      = DTR_CONTROL_ENABLE;
296                 lpdcb->fRtsControl      = RTS_CONTROL_ENABLE;
297         }
298
299         return TRUE;
300 }
301
302 /**************************************************************************
303  *         BuildCommDCBA                (KERNEL32.@)
304  *
305  *  Updates a device control block data structure with values from an
306  *  ascii device control string.  The device control string has two forms
307  *  normal and extended, it must be exclusively in one or the other form.
308  *
309  * RETURNS
310  *
311  *  True on success, false on a malformed control string.
312  */
313 BOOL WINAPI BuildCommDCBA(
314     LPCSTR device, /* [in] The ascii device control string used to update the DCB. */
315     LPDCB  lpdcb)  /* [out] The device control block to be updated. */
316 {
317         return BuildCommDCBAndTimeoutsA(device,lpdcb,NULL);
318 }
319
320 /**************************************************************************
321  *         BuildCommDCBAndTimeoutsA     (KERNEL32.@)
322  *
323  *  Updates a device control block data structure with values from an
324  *  ascii device control string.  Taking timeout values from a timeouts
325  *  struct if desired by the control string.
326  *
327  * RETURNS
328  *
329  *  True on success, false bad handles etc
330  */
331 BOOL WINAPI BuildCommDCBAndTimeoutsA(
332     LPCSTR         device,     /* [in] The ascii device control string. */
333     LPDCB          lpdcb,      /* [out] The device control block to be updated. */
334     LPCOMMTIMEOUTS lptimeouts) /* [in] The timeouts to use if asked to set them by the control string. */
335 {
336         int     port;
337         char    *ptr,*temp;
338
339         TRACE("(%s,%p,%p)\n",device,lpdcb,lptimeouts);
340
341         if (!strncasecmp(device,"COM",3)) {
342                 port=device[3]-'0';
343                 if (port--==0) {
344                         ERR("BUG! COM0 can't exist!\n");
345                         return FALSE;
346                 }
347                 if ((*(device+4)!=':') && (*(device+4)!=' '))
348                         return FALSE;
349                 temp=(LPSTR)(device+5);
350         } else
351                 temp=(LPSTR)device;
352
353         memset(lpdcb,0,sizeof (DCB));
354         lpdcb->DCBlength        = sizeof(DCB);
355         if (strchr(temp,',')) { /* old style */
356
357                 return COMM_BuildOldCommDCB(device,lpdcb);
358         }
359         ptr=strtok(temp," ");
360         while (ptr) {
361                 DWORD   flag,x;
362
363                 flag=0;
364                 if (!strncasecmp("baud=",ptr,5)) {
365                         if (!sscanf(ptr+5,"%ld",&x))
366                                 WARN("Couldn't parse %s\n",ptr);
367                         lpdcb->BaudRate = x;
368                         flag=1;
369                 }
370                 if (!strncasecmp("stop=",ptr,5)) {
371                         if (!sscanf(ptr+5,"%ld",&x))
372                                 WARN("Couldn't parse %s\n",ptr);
373                         lpdcb->StopBits = x;
374                         flag=1;
375                 }
376                 if (!strncasecmp("data=",ptr,5)) {
377                         if (!sscanf(ptr+5,"%ld",&x))
378                                 WARN("Couldn't parse %s\n",ptr);
379                         lpdcb->ByteSize = x;
380                         flag=1;
381                 }
382                 if (!strncasecmp("parity=",ptr,7)) {
383                         lpdcb->fParity  = TRUE;
384                         switch (ptr[7]) {
385                         case 'N':case 'n':
386                                 lpdcb->fParity  = FALSE;
387                                 lpdcb->Parity   = NOPARITY;
388                                 break;
389                         case 'E':case 'e':
390                                 lpdcb->Parity   = EVENPARITY;
391                                 break;
392                         case 'O':case 'o':
393                                 lpdcb->Parity   = ODDPARITY;
394                                 break;
395                         case 'M':case 'm':
396                                 lpdcb->Parity   = MARKPARITY;
397                                 break;
398                         case 'S':case 's':
399                                 lpdcb->Parity   = SPACEPARITY;
400                                 break;
401                         }
402                         flag=1;
403                 }
404                 if (!flag)
405                         ERR("Unhandled specifier '%s', please report.\n",ptr);
406                 ptr=strtok(NULL," ");
407         }
408         if (lpdcb->BaudRate==110)
409                 lpdcb->StopBits = 2;
410         return TRUE;
411 }
412
413 /**************************************************************************
414  *         BuildCommDCBAndTimeoutsW             (KERNEL32.@)
415  *
416  *  Updates a device control block data structure with values from an
417  *  unicode device control string.  Taking timeout values from a timeouts
418  *  struct if desired by the control string.
419  *
420  * RETURNS
421  *
422  *  True on success, false bad handles etc.
423  */
424 BOOL WINAPI BuildCommDCBAndTimeoutsW(
425     LPCWSTR        devid,      /* [in] The unicode device control string. */
426     LPDCB          lpdcb,      /* [out] The device control block to be updated. */
427     LPCOMMTIMEOUTS lptimeouts) /* [in] The timeouts to use if asked to set them by the control string. */
428 {
429         BOOL ret = FALSE;
430         LPSTR   devidA;
431
432         TRACE("(%p,%p,%p)\n",devid,lpdcb,lptimeouts);
433         devidA = HEAP_strdupWtoA( GetProcessHeap(), 0, devid );
434         if (devidA)
435         {
436         ret=BuildCommDCBAndTimeoutsA(devidA,lpdcb,lptimeouts);
437         HeapFree( GetProcessHeap(), 0, devidA );
438         }
439         return ret;
440 }
441
442 /**************************************************************************
443  *         BuildCommDCBW                (KERNEL32.@)
444  *
445  *  Updates a device control block structure with values from an
446  *  unicode device control string.  The device control string has two forms
447  *  normal and extended, it must be exclusively in one or the other form.
448  *
449  * RETURNS
450  *
451  *  True on success, false on an malformed control string.
452  */
453 BOOL WINAPI BuildCommDCBW(
454     LPCWSTR devid, /* [in] The unicode device control string. */
455     LPDCB   lpdcb) /* [out] The device control block to be updated. */
456 {
457         return BuildCommDCBAndTimeoutsW(devid,lpdcb,NULL);
458 }
459
460 static BOOL COMM_SetCommError(HANDLE handle, DWORD error)
461 {
462     DWORD ret;
463
464     SERVER_START_REQ( set_serial_info )
465     {
466         req->handle = handle;
467         req->flags = SERIALINFO_SET_ERROR;
468         req->commerror = error;
469         ret = !wine_server_call_err( req );
470     }
471     SERVER_END_REQ;
472     return ret;
473 }
474
475 static BOOL COMM_GetCommError(HANDLE handle, LPDWORD lperror)
476 {
477     DWORD ret;
478
479     if(!lperror)
480         return FALSE;
481
482     SERVER_START_REQ( get_serial_info )
483     {
484         req->handle = handle;
485         ret = !wine_server_call_err( req );
486         *lperror = reply->commerror;
487     }
488     SERVER_END_REQ;
489
490     return ret;
491 }
492
493 /*****************************************************************************
494  *      SetCommBreak            (KERNEL32.@)
495  *
496  *  Halts the transmission of characters to a communications device.
497  *
498  * RETURNS
499  *
500  *  True on success, and false if the communications device could not be found,
501  *  the control is not supported.
502  *
503  * BUGS
504  *
505  *  Only TIOCSBRK and TIOCCBRK are supported.
506  */
507 BOOL WINAPI SetCommBreak(
508     HANDLE handle) /* [in] The communictions device to suspend. */
509 {
510 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
511         int fd,result;
512
513         fd = FILE_GetUnixHandle( handle, GENERIC_READ );
514         if(fd<0) {
515                 TRACE("FILE_GetUnixHandle failed\n");
516                 return FALSE;
517         }
518         result = ioctl(fd,TIOCSBRK,0);
519         close(fd);
520         if (result ==-1)
521           {
522                 TRACE("ioctl failed\n");
523                 SetLastError(ERROR_NOT_SUPPORTED);
524                 return FALSE;
525           }
526         return TRUE;
527 #else
528         FIXME("ioctl not available\n");
529         SetLastError(ERROR_NOT_SUPPORTED);
530         return FALSE;
531 #endif
532 }
533
534 /*****************************************************************************
535  *      ClearCommBreak          (KERNEL32.@)
536  *
537  *  Resumes character transmission from a communication device.
538  *
539  * RETURNS
540  *
541  *  True on success and false if the communications device could not be found.
542  *
543  * BUGS
544  *
545  *  Only TIOCSBRK and TIOCCBRK are supported.
546  */
547 BOOL WINAPI ClearCommBreak(
548     HANDLE handle) /* [in] The halted communication device whose character transmission is to be resumed. */
549 {
550 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
551         int fd,result;
552
553         fd = FILE_GetUnixHandle( handle, GENERIC_READ );
554         if(fd<0) {
555                 TRACE("FILE_GetUnixHandle failed\n");
556                 return FALSE;
557         }
558         result = ioctl(fd,TIOCCBRK,0);
559         close(fd);
560         if (result ==-1)
561           {
562                 TRACE("ioctl failed\n");
563                 SetLastError(ERROR_NOT_SUPPORTED);
564                 return FALSE;
565           }
566         return TRUE;
567 #else
568         FIXME("ioctl not available\n");
569         SetLastError(ERROR_NOT_SUPPORTED);
570         return FALSE;
571 #endif
572 }
573
574 /*****************************************************************************
575  *      EscapeCommFunction      (KERNEL32.@)
576  *
577  *  Directs a communication device to perform an extended function.
578  *
579  * RETURNS
580  *
581  *  True or requested data on successful completion of the command,
582  *  false if the device is not present cannot execute the command
583  *  or the command failed.
584  */
585 BOOL WINAPI EscapeCommFunction(
586     HANDLE handle,    /* [in] The communication device to perform the extended function. */
587     UINT   nFunction) /* [in] The extended function to be performed. */
588 {
589         int fd,direct=FALSE,result=FALSE;
590         struct termios  port;
591
592         TRACE("handle %p, function=%d\n", handle, nFunction);
593         fd = FILE_GetUnixHandle( handle, GENERIC_READ );
594         if(fd<0) {
595                 FIXME("handle %p not found.\n",handle);
596                 return FALSE;
597         }
598
599         if (tcgetattr(fd,&port) == -1) {
600                 COMM_SetCommError(handle,CE_IOE);
601                 close(fd);
602                 return FALSE;
603         }
604
605         switch (nFunction) {
606                 case RESETDEV:
607                         TRACE("\n");
608                         break;
609
610                 case CLRDTR:
611                         TRACE("CLRDTR\n");
612 #ifdef TIOCM_DTR
613                         direct=TRUE;
614                         result= COMM_WhackModem(fd, ~TIOCM_DTR, 0);
615                         break;
616 #endif
617
618                 case CLRRTS:
619                         TRACE("CLRRTS\n");
620 #ifdef TIOCM_RTS
621                         direct=TRUE;
622                         result= COMM_WhackModem(fd, ~TIOCM_RTS, 0);
623                         break;
624 #endif
625
626                 case SETDTR:
627                         TRACE("SETDTR\n");
628 #ifdef TIOCM_DTR
629                         direct=TRUE;
630                         result= COMM_WhackModem(fd, 0, TIOCM_DTR);
631                         break;
632 #endif
633
634                 case SETRTS:
635                         TRACE("SETRTS\n");
636 #ifdef TIOCM_RTS
637                         direct=TRUE;
638                         result= COMM_WhackModem(fd, 0, TIOCM_RTS);
639                         break;
640 #endif
641
642                 case SETXOFF:
643                         TRACE("SETXOFF\n");
644                         port.c_iflag |= IXOFF;
645                         break;
646
647                 case SETXON:
648                         TRACE("SETXON\n");
649                         port.c_iflag |= IXON;
650                         break;
651                 case SETBREAK:
652                         TRACE("setbreak\n");
653 #ifdef  TIOCSBRK
654                         direct=TRUE;
655                         result = ioctl(fd,TIOCSBRK,0);
656                         break;
657 #endif
658                 case CLRBREAK:
659                         TRACE("clrbreak\n");
660 #ifdef  TIOCSBRK
661                         direct=TRUE;
662                         result = ioctl(fd,TIOCCBRK,0);
663                         break;
664 #endif
665                 default:
666                         WARN("(handle=%p,nFunction=%d): Unknown function\n",
667                         handle, nFunction);
668                         break;
669         }
670
671         if (!direct)
672           if (tcsetattr(fd, TCSADRAIN, &port) == -1) {
673                 close(fd);
674                 COMM_SetCommError(handle,CE_IOE);
675                 return FALSE;
676           } else
677                 result= TRUE;
678         else
679           {
680             if (result == -1)
681               {
682                 result= FALSE;
683                 COMM_SetCommError(handle,CE_IOE);
684               }
685             else
686               result = TRUE;
687           }
688         close(fd);
689         return result;
690 }
691
692 /********************************************************************
693  *      PurgeComm        (KERNEL32.@)
694  *
695  *  Terminates pending operations and/or discards buffers on a
696  *  communication resource.
697  *
698  * RETURNS
699  *
700  *  True on success and false if the communications handle is bad.
701  */
702 BOOL WINAPI PurgeComm(
703     HANDLE handle, /* [in] The communication resource to be purged. */
704     DWORD  flags)  /* [in] Flags for clear pending/buffer on input/output. */
705 {
706      int fd;
707
708      TRACE("handle %p, flags %lx\n", handle, flags);
709
710      fd = FILE_GetUnixHandle( handle, GENERIC_READ );
711      if(fd<0) {
712         FIXME("no handle %p found\n",handle);
713         return FALSE;
714      }
715
716      /*
717      ** not exactly sure how these are different
718      ** Perhaps if we had our own internal queues, one flushes them
719      ** and the other flushes the kernel's buffers.
720      */
721      if(flags&PURGE_TXABORT)
722          tcflush(fd,TCOFLUSH);
723      if(flags&PURGE_RXABORT)
724          tcflush(fd,TCIFLUSH);
725      if(flags&PURGE_TXCLEAR)
726          tcflush(fd,TCOFLUSH);
727      if(flags&PURGE_RXCLEAR)
728          tcflush(fd,TCIFLUSH);
729      close(fd);
730
731      return 1;
732 }
733
734 /*****************************************************************************
735  *      ClearCommError  (KERNEL32.@)
736  *
737  *  Enables further I/O operations on a communications resource after
738  *  supplying error and current status information.
739  *
740  * RETURNS
741  *
742  *  True on success, false if the communication resource handle is bad.
743  */
744 BOOL WINAPI ClearCommError(
745     HANDLE    handle, /* [in] The communication resource with the error. */
746     LPDWORD   errors, /* [out] Flags indicating error the resource experienced. */
747     LPCOMSTAT lpStat) /* [out] The status of the communication resource. */
748 {
749     int fd;
750
751     fd=FILE_GetUnixHandle( handle, GENERIC_READ );
752     if(0>fd)
753     {
754         FIXME("no handle %p found\n",handle);
755         return FALSE;
756     }
757
758     if (lpStat)
759     {
760         lpStat->fCtsHold = 0;
761         lpStat->fDsrHold = 0;
762         lpStat->fRlsdHold = 0;
763         lpStat->fXoffHold = 0;
764         lpStat->fXoffSent = 0;
765         lpStat->fEof = 0;
766         lpStat->fTxim = 0;
767         lpStat->fReserved = 0;
768
769 #ifdef TIOCOUTQ
770         if(ioctl(fd, TIOCOUTQ, &lpStat->cbOutQue))
771             WARN("ioctl returned error\n");
772 #else
773         lpStat->cbOutQue = 0; /* FIXME: find a different way to find out */
774 #endif
775
776 #ifdef TIOCINQ
777         if(ioctl(fd, TIOCINQ, &lpStat->cbInQue))
778             WARN("ioctl returned error\n");
779 #endif
780
781         TRACE("handle %p cbInQue = %ld cbOutQue = %ld\n",
782               handle, lpStat->cbInQue, lpStat->cbOutQue);
783     }
784
785     close(fd);
786
787     COMM_GetCommError(handle, errors);
788     COMM_SetCommError(handle, 0);
789
790     return TRUE;
791 }
792
793 /*****************************************************************************
794  *      SetupComm       (KERNEL32.@)
795  *
796  *  Called after CreateFile to hint to the communication resource to use
797  *  specified sizes for input and output buffers rather than the default values.
798  *
799  * RETURNS
800  *
801  *  True if successful, false if the communications resource handle is bad.
802  *
803  * BUGS
804  *
805  *  Stub.
806  */
807 BOOL WINAPI SetupComm(
808     HANDLE handle,  /* [in] The just created communication resource handle. */
809     DWORD  insize,  /* [in] The suggested size of the communication resources input buffer in bytes. */
810     DWORD  outsize) /* [in] The suggested size of the communication resources output buffer in bytes. */
811 {
812     int fd;
813
814     FIXME("insize %ld outsize %ld unimplemented stub\n", insize, outsize);
815     fd=FILE_GetUnixHandle( handle, GENERIC_READ );
816     if(0>fd) {
817         FIXME("handle %p not found?\n",handle);
818         return FALSE;
819     }
820     close(fd);
821     return TRUE;
822 }
823
824 /*****************************************************************************
825  *      GetCommMask     (KERNEL32.@)
826  *
827  *  Obtain the events associated with a communication device that will cause
828  *  a call WaitCommEvent to return.
829  *
830  *  RETURNS
831  *
832  *   True on success, fail on bad device handle etc.
833  */
834 BOOL WINAPI GetCommMask(
835     HANDLE  handle,  /* [in] The communications device. */
836     LPDWORD evtmask) /* [out] The events which cause WaitCommEvent to return. */
837 {
838     BOOL ret;
839
840     TRACE("handle %p, mask %p\n", handle, evtmask);
841
842     SERVER_START_REQ( get_serial_info )
843     {
844         req->handle = handle;
845         if ((ret = !wine_server_call_err( req )))
846         {
847             if (evtmask) *evtmask = reply->eventmask;
848         }
849     }
850     SERVER_END_REQ;
851     return ret;
852 }
853
854 /*****************************************************************************
855  *      SetCommMask     (KERNEL32.@)
856  *
857  *  There be some things we need to hear about yon there communications device.
858  *  (Set which events associated with a communication device should cause
859  *  a call WaitCommEvent to return.)
860  *
861  * RETURNS
862  *
863  *  True on success, false on bad handle etc.
864  */
865 BOOL WINAPI SetCommMask(
866     HANDLE handle,  /* [in] The communications device.  */
867     DWORD  evtmask) /* [in] The events that are to be monitored. */
868 {
869     BOOL ret;
870
871     TRACE("handle %p, mask %lx\n", handle, evtmask);
872
873     SERVER_START_REQ( set_serial_info )
874     {
875         req->handle    = handle;
876         req->flags     = SERIALINFO_SET_MASK;
877         req->eventmask = evtmask;
878         ret = !wine_server_call_err( req );
879     }
880     SERVER_END_REQ;
881     return ret;
882 }
883
884 /*****************************************************************************
885  *      SetCommState    (KERNEL32.@)
886  *
887  *  Re-initializes all hardware and control settings of a communications device,
888  *  with values from a device control block without effecting the input and output
889  *  queues.
890  *
891  * RETURNS
892  *
893  *  True on success, false on failure eg if the XonChar is equal to the XoffChar.
894  */
895 BOOL WINAPI SetCommState(
896     HANDLE handle, /* [in] The communications device. */
897     LPDCB  lpdcb)  /* [out] The device control block. */
898 {
899      struct termios port;
900      int fd, bytesize, stopbits;
901
902      TRACE("handle %p, ptr %p\n", handle, lpdcb);
903      TRACE("bytesize %d baudrate %ld fParity %d Parity %d stopbits %d\n",
904            lpdcb->ByteSize,lpdcb->BaudRate,lpdcb->fParity, lpdcb->Parity,
905            (lpdcb->StopBits == ONESTOPBIT)?1:
906            (lpdcb->StopBits == TWOSTOPBITS)?2:0);
907      TRACE("%s %s\n",(lpdcb->fInX)?"IXON":"~IXON",
908            (lpdcb->fOutX)?"IXOFF":"~IXOFF");
909
910      fd = FILE_GetUnixHandle( handle, GENERIC_READ );
911      if (fd < 0)  {
912         FIXME("no handle %p found\n",handle);
913         return FALSE;
914      }
915
916      if ((tcgetattr(fd,&port)) == -1) {
917          int save_error = errno;
918          COMM_SetCommError(handle,CE_IOE);
919          close( fd );
920          ERR("tcgetattr error '%s'\n", strerror(save_error));
921          return FALSE;
922      }
923
924         port.c_cc[VMIN] = 0;
925         port.c_cc[VTIME] = 1;
926
927 #ifdef IMAXBEL
928         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|IMAXBEL);
929 #else
930         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR);
931 #endif
932         port.c_iflag |= (IGNBRK);
933
934         port.c_oflag &= ~(OPOST);
935
936         port.c_cflag &= ~(HUPCL);
937         port.c_cflag |= CLOCAL | CREAD;
938
939         port.c_lflag &= ~(ICANON|ECHO|ISIG);
940         port.c_lflag |= NOFLSH;
941
942 #ifdef CBAUD
943         port.c_cflag &= ~CBAUD;
944         switch (lpdcb->BaudRate) {
945                 case 110:
946                 case CBR_110:
947                         port.c_cflag |= B110;
948                         break;
949                 case 300:
950                 case CBR_300:
951                         port.c_cflag |= B300;
952                         break;
953                 case 600:
954                 case CBR_600:
955                         port.c_cflag |= B600;
956                         break;
957                 case 1200:
958                 case CBR_1200:
959                         port.c_cflag |= B1200;
960                         break;
961                 case 2400:
962                 case CBR_2400:
963                         port.c_cflag |= B2400;
964                         break;
965                 case 4800:
966                 case CBR_4800:
967                         port.c_cflag |= B4800;
968                         break;
969                 case 9600:
970                 case CBR_9600:
971                         port.c_cflag |= B9600;
972                         break;
973                 case 19200:
974                 case CBR_19200:
975                         port.c_cflag |= B19200;
976                         break;
977                 case 38400:
978                 case CBR_38400:
979                         port.c_cflag |= B38400;
980                         break;
981 #ifdef B57600
982                 case 57600:
983                         port.c_cflag |= B57600;
984                         break;
985 #endif
986 #ifdef B115200
987                 case 115200:
988                         port.c_cflag |= B115200;
989                         break;
990 #endif
991 #ifdef B230400
992                 case 230400:
993                         port.c_cflag |= B230400;
994                         break;
995 #endif
996 #ifdef B460800
997                 case 460800:
998                         port.c_cflag |= B460800;
999                         break;
1000 #endif
1001                 default:
1002 #if defined (HAVE_LINUX_SERIAL_H) && defined (TIOCSSERIAL)
1003                         {   struct serial_struct nuts;
1004                             int arby;
1005                             ioctl(fd, TIOCGSERIAL, &nuts);
1006                             nuts.custom_divisor = nuts.baud_base / lpdcb->BaudRate;
1007                             if (!(nuts.custom_divisor)) nuts.custom_divisor = 1;
1008                             arby = nuts.baud_base / nuts.custom_divisor;
1009                             nuts.flags &= ~ASYNC_SPD_MASK;
1010                             nuts.flags |= ASYNC_SPD_CUST;
1011                             WARN("You (or a program acting at your behest) have specified\n"
1012                                  "a non-standard baud rate %ld.  Wine will set the rate to %d,\n"
1013                                  "which is as close as we can get by our present understanding of your\n"
1014                                  "hardware. I hope you know what you are doing.  Any disruption Wine\n"
1015                                  "has caused to your linux system can be undone with setserial \n"
1016                                  "(see man setserial). If you have incapacitated a Hayes type modem,\n"
1017                                  "reset it and it will probably recover.\n", lpdcb->BaudRate, arby);
1018                             ioctl(fd, TIOCSSERIAL, &nuts);
1019                             port.c_cflag |= B38400;
1020                         }
1021                         break;
1022 #endif    /* Don't have linux/serial.h or lack TIOCSSERIAL */
1023
1024
1025                         COMM_SetCommError(handle,IE_BAUDRATE);
1026                         close( fd );
1027                         ERR("baudrate %ld\n",lpdcb->BaudRate);
1028                         return FALSE;
1029         }
1030 #elif !defined(__EMX__)
1031         switch (lpdcb->BaudRate) {
1032                 case 110:
1033                 case CBR_110:
1034                         port.c_ospeed = B110;
1035                         break;
1036                 case 300:
1037                 case CBR_300:
1038                         port.c_ospeed = B300;
1039                         break;
1040                 case 600:
1041                 case CBR_600:
1042                         port.c_ospeed = B600;
1043                         break;
1044                 case 1200:
1045                 case CBR_1200:
1046                         port.c_ospeed = B1200;
1047                         break;
1048                 case 2400:
1049                 case CBR_2400:
1050                         port.c_ospeed = B2400;
1051                         break;
1052                 case 4800:
1053                 case CBR_4800:
1054                         port.c_ospeed = B4800;
1055                         break;
1056                 case 9600:
1057                 case CBR_9600:
1058                         port.c_ospeed = B9600;
1059                         break;
1060                 case 19200:
1061                 case CBR_19200:
1062                         port.c_ospeed = B19200;
1063                         break;
1064                 case 38400:
1065                 case CBR_38400:
1066                         port.c_ospeed = B38400;
1067                         break;
1068 #ifdef B57600
1069                 case 57600:
1070                 case CBR_57600:
1071                         port.c_cflag |= B57600;
1072                         break;
1073 #endif
1074 #ifdef B115200
1075                 case 115200:
1076                 case CBR_115200:
1077                         port.c_cflag |= B115200;
1078                         break;
1079 #endif
1080 #ifdef B230400
1081                 case 230400:
1082                         port.c_cflag |= B230400;
1083                         break;
1084 #endif
1085 #ifdef B460800
1086                 case 460800:
1087                         port.c_cflag |= B460800;
1088                         break;
1089 #endif
1090                 default:
1091                         COMM_SetCommError(handle,IE_BAUDRATE);
1092                         close( fd );
1093                         ERR("baudrate %ld\n",lpdcb->BaudRate);
1094                         return FALSE;
1095         }
1096         port.c_ispeed = port.c_ospeed;
1097 #endif
1098         bytesize=lpdcb->ByteSize;
1099         stopbits=lpdcb->StopBits;
1100
1101 #ifdef CMSPAR
1102         port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
1103 #else
1104         port.c_cflag &= ~(PARENB | PARODD);
1105 #endif
1106         if (lpdcb->fParity)
1107             port.c_iflag |= INPCK;
1108         else
1109             port.c_iflag &= ~INPCK;
1110         switch (lpdcb->Parity) {
1111                 case NOPARITY:
1112                         break;
1113                 case ODDPARITY:
1114                         port.c_cflag |= (PARENB | PARODD);
1115                         break;
1116                 case EVENPARITY:
1117                         port.c_cflag |= PARENB;
1118                         break;
1119 #ifdef CMSPAR
1120                 /* Linux defines mark/space (stick) parity */
1121                 case MARKPARITY:
1122                         port.c_cflag |= (PARENB | CMSPAR);
1123                         break;
1124                 case SPACEPARITY:
1125                         port.c_cflag |= (PARENB | PARODD |  CMSPAR);
1126                         break;
1127 #else
1128                 /* try the POSIX way */
1129                 case MARKPARITY:
1130                         if( stopbits == ONESTOPBIT) {
1131                             stopbits = TWOSTOPBITS;
1132                             port.c_iflag &= ~INPCK;
1133                         } else {
1134                             COMM_SetCommError(handle,IE_BYTESIZE);
1135                             close( fd );
1136                             ERR("Cannot set MARK Parity\n");
1137                             return FALSE;
1138                         }
1139                         break;
1140                 case SPACEPARITY:
1141                         if( bytesize < 8) {
1142                             bytesize +=1;
1143                             port.c_iflag &= ~INPCK;
1144                         } else {
1145                             COMM_SetCommError(handle,IE_BYTESIZE);
1146                             close( fd );
1147                             ERR("Cannot set SPACE Parity\n");
1148                             return FALSE;
1149                         }
1150                         break;
1151 #endif
1152                default:
1153                         COMM_SetCommError(handle,IE_BYTESIZE);
1154                         close( fd );
1155                         ERR("Parity\n");
1156                         return FALSE;
1157         }
1158
1159
1160         port.c_cflag &= ~CSIZE;
1161         switch (bytesize) {
1162                 case 5:
1163                         port.c_cflag |= CS5;
1164                         break;
1165                 case 6:
1166                         port.c_cflag |= CS6;
1167                         break;
1168                 case 7:
1169                         port.c_cflag |= CS7;
1170                         break;
1171                 case 8:
1172                         port.c_cflag |= CS8;
1173                         break;
1174                 default:
1175                         COMM_SetCommError(handle,IE_BYTESIZE);
1176                         close( fd );
1177                         ERR("ByteSize\n");
1178                         return FALSE;
1179         }
1180
1181         switch (stopbits) {
1182                 case ONESTOPBIT:
1183                                 port.c_cflag &= ~CSTOPB;
1184                                 break;
1185                 case ONE5STOPBITS: /* wil be selected if bytesize is 5 */
1186                 case TWOSTOPBITS:
1187                                 port.c_cflag |= CSTOPB;
1188                                 break;
1189                 default:
1190                         COMM_SetCommError(handle,IE_BYTESIZE);
1191                         close( fd );
1192                         ERR("StopBits\n");
1193                         return FALSE;
1194         }
1195 #ifdef CRTSCTS
1196         if (    lpdcb->fOutxCtsFlow                     ||
1197                 lpdcb->fRtsControl == RTS_CONTROL_HANDSHAKE
1198         )
1199           {
1200             port.c_cflag |= CRTSCTS;
1201             TRACE("CRTSCTS\n");
1202           }
1203 #endif
1204
1205         if (lpdcb->fDtrControl == DTR_CONTROL_HANDSHAKE)
1206           {
1207              WARN("DSR/DTR flow control not supported\n");
1208           }
1209
1210         if (lpdcb->fInX)
1211                 port.c_iflag |= IXON;
1212         else
1213                 port.c_iflag &= ~IXON;
1214         if (lpdcb->fOutX)
1215                 port.c_iflag |= IXOFF;
1216         else
1217                 port.c_iflag &= ~IXOFF;
1218
1219         if (tcsetattr(fd,TCSANOW,&port)==-1) { /* otherwise it hangs with pending input*/
1220                 int save_error=errno;
1221                 COMM_SetCommError(handle,CE_IOE);
1222                 close( fd );
1223                 ERR("tcsetattr error '%s'\n", strerror(save_error));
1224                 return FALSE;
1225         } else {
1226                 COMM_SetCommError(handle,0);
1227                 close( fd );
1228                 return TRUE;
1229         }
1230 }
1231
1232
1233 /*****************************************************************************
1234  *      GetCommState    (KERNEL32.@)
1235  *
1236  *  Fills in a device control block with information from a communications device.
1237  *
1238  * RETURNS
1239  *
1240  *  True on success, false if the communication device handle is bad etc
1241  *
1242  * BUGS
1243  *
1244  *  XonChar and XoffChar are not set.
1245  */
1246 BOOL WINAPI GetCommState(
1247     HANDLE handle, /* [in] The communications device. */
1248     LPDCB  lpdcb)  /* [out] The device control block. */
1249 {
1250      struct termios port;
1251      int fd,speed;
1252
1253      TRACE("handle %p, ptr %p\n", handle, lpdcb);
1254
1255      fd = FILE_GetUnixHandle( handle, GENERIC_READ );
1256      if (fd < 0)
1257        {
1258          ERR("FILE_GetUnixHandle failed\n");
1259          return FALSE;
1260        }
1261      if (tcgetattr(fd, &port) == -1) {
1262                 int save_error=errno;
1263                 ERR("tcgetattr error '%s'\n", strerror(save_error));
1264                 COMM_SetCommError(handle,CE_IOE);
1265                 close( fd );
1266                 return FALSE;
1267         }
1268      close( fd );
1269 #ifndef __EMX__
1270 #ifdef CBAUD
1271      speed= (port.c_cflag & CBAUD);
1272 #else
1273      speed= (cfgetospeed(&port));
1274 #endif
1275      switch (speed) {
1276                 case B110:
1277                         lpdcb->BaudRate = 110;
1278                         break;
1279                 case B300:
1280                         lpdcb->BaudRate = 300;
1281                         break;
1282                 case B600:
1283                         lpdcb->BaudRate = 600;
1284                         break;
1285                 case B1200:
1286                         lpdcb->BaudRate = 1200;
1287                         break;
1288                 case B2400:
1289                         lpdcb->BaudRate = 2400;
1290                         break;
1291                 case B4800:
1292                         lpdcb->BaudRate = 4800;
1293                         break;
1294                 case B9600:
1295                         lpdcb->BaudRate = 9600;
1296                         break;
1297                 case B19200:
1298                         lpdcb->BaudRate = 19200;
1299                         break;
1300                 case B38400:
1301                         lpdcb->BaudRate = 38400;
1302                         break;
1303 #ifdef B57600
1304                 case B57600:
1305                         lpdcb->BaudRate = 57600;
1306                         break;
1307 #endif
1308 #ifdef B115200
1309                 case B115200:
1310                         lpdcb->BaudRate = 115200;
1311                         break;
1312 #endif
1313 #ifdef B230400
1314                 case B230400:
1315                         lpdcb->BaudRate = 230400;
1316                         break;
1317 #endif
1318 #ifdef B460800
1319                 case B460800:
1320                         lpdcb->BaudRate = 460800;
1321                         break;
1322 #endif
1323                 default:
1324                         ERR("unknown speed %x \n",speed);
1325         }
1326 #endif
1327         switch (port.c_cflag & CSIZE) {
1328                 case CS5:
1329                         lpdcb->ByteSize = 5;
1330                         break;
1331                 case CS6:
1332                         lpdcb->ByteSize = 6;
1333                         break;
1334                 case CS7:
1335                         lpdcb->ByteSize = 7;
1336                         break;
1337                 case CS8:
1338                         lpdcb->ByteSize = 8;
1339                         break;
1340                 default:
1341                         ERR("unknown size %x \n",port.c_cflag & CSIZE);
1342         }
1343
1344         if(port.c_iflag & INPCK)
1345             lpdcb->fParity = TRUE;
1346         else
1347             lpdcb->fParity = FALSE;
1348 #ifdef CMSPAR
1349         switch (port.c_cflag & (PARENB | PARODD | CMSPAR))
1350 #else
1351         switch (port.c_cflag & (PARENB | PARODD))
1352 #endif
1353         {
1354                 case 0:
1355                         lpdcb->Parity = NOPARITY;
1356                         break;
1357                 case PARENB:
1358                         lpdcb->Parity = EVENPARITY;
1359                         break;
1360                 case (PARENB | PARODD):
1361                         lpdcb->Parity = ODDPARITY;
1362                         break;
1363 #ifdef CMSPAR
1364                 case (PARENB | CMSPAR):
1365                         lpdcb->Parity = MARKPARITY;
1366                         break;
1367                 case (PARENB | PARODD | CMSPAR):
1368                         lpdcb->Parity = SPACEPARITY;
1369                         break;
1370 #endif
1371         }
1372
1373         if (port.c_cflag & CSTOPB)
1374             if(lpdcb->ByteSize == 5)
1375                 lpdcb->StopBits = ONE5STOPBITS;
1376             else
1377                 lpdcb->StopBits = TWOSTOPBITS;
1378         else
1379             lpdcb->StopBits = ONESTOPBIT;
1380
1381         lpdcb->fNull = 0;
1382         lpdcb->fBinary = 1;
1383
1384         /* termios does not support DTR/DSR flow control */
1385         lpdcb->fOutxDsrFlow = 0;
1386         lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
1387
1388 #ifdef CRTSCTS
1389
1390         if (port.c_cflag & CRTSCTS) {
1391                 lpdcb->fRtsControl = RTS_CONTROL_HANDSHAKE;
1392                 lpdcb->fOutxCtsFlow = 1;
1393         } else
1394 #endif
1395         {
1396                 lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
1397                 lpdcb->fOutxCtsFlow = 0;
1398         }
1399         if (port.c_iflag & IXON)
1400                 lpdcb->fInX = 1;
1401         else
1402                 lpdcb->fInX = 0;
1403
1404         if (port.c_iflag & IXOFF)
1405                 lpdcb->fOutX = 1;
1406         else
1407                 lpdcb->fOutX = 0;
1408 /*
1409         lpdcb->XonChar =
1410         lpdcb->XoffChar =
1411  */
1412         lpdcb->XonLim = 10;
1413         lpdcb->XoffLim = 10;
1414
1415         COMM_SetCommError(handle,0);
1416
1417         TRACE("OK\n");
1418
1419         TRACE("bytesize %d baudrate %ld fParity %d Parity %d stopbits %d\n",
1420               lpdcb->ByteSize,lpdcb->BaudRate,lpdcb->fParity, lpdcb->Parity,
1421               (lpdcb->StopBits == ONESTOPBIT)?1:
1422               (lpdcb->StopBits == TWOSTOPBITS)?2:0);
1423         TRACE("%s %s\n",(lpdcb->fInX)?"IXON":"~IXON",
1424               (lpdcb->fOutX)?"IXOFF":"~IXOFF");
1425 #ifdef CRTSCTS
1426         if (    lpdcb->fOutxCtsFlow                     ||
1427                 lpdcb->fRtsControl == RTS_CONTROL_HANDSHAKE
1428                 )
1429           TRACE("CRTSCTS\n");
1430         else
1431
1432           TRACE("~CRTSCTS\n");
1433
1434 #endif
1435         return TRUE;
1436 }
1437
1438 /*****************************************************************************
1439  *      TransmitCommChar        (KERNEL32.@)
1440  *
1441  *  Transmits a single character in front of any pending characters in the
1442  *  output buffer.  Usually used to send an interrupt character to a host.
1443  *
1444  * RETURNS
1445  *
1446  *  True if the call succeeded, false if the previous command character to the
1447  *  same device has not been sent yet the handle is bad etc.
1448  *
1449  * BUGS
1450  *
1451  *  Stub.
1452  */
1453 BOOL WINAPI TransmitCommChar(
1454     HANDLE hComm,      /* [in] The communication device in need of a command character. */
1455     CHAR   chTransmit) /* [in] The character to transmit. */
1456 {
1457     BOOL r = FALSE;
1458     int fd;
1459
1460     WARN("(%p,'%c') not perfect!\n",hComm,chTransmit);
1461
1462     fd = FILE_GetUnixHandle( hComm, GENERIC_READ );
1463     if ( fd < 0 )
1464         SetLastError ( ERROR_INVALID_PARAMETER );
1465     else
1466     {
1467         r = (1 == write(fd, &chTransmit, 1));
1468         close(fd);
1469     }
1470
1471     return r;
1472 }
1473
1474
1475 /*****************************************************************************
1476  *      GetCommTimeouts         (KERNEL32.@)
1477  *
1478  *  Obtains the request timeout values for the communications device.
1479  *
1480  * RETURNS
1481  *
1482  *  True on success, false if communications device handle is bad
1483  *  or the target structure is null.
1484  */
1485 BOOL WINAPI GetCommTimeouts(
1486     HANDLE         hComm,      /* [in] The communications device. */
1487     LPCOMMTIMEOUTS lptimeouts) /* [out] The struct of request timeouts. */
1488 {
1489     BOOL ret;
1490
1491     TRACE("(%p,%p)\n",hComm,lptimeouts);
1492
1493     if(!lptimeouts)
1494     {
1495         SetLastError(ERROR_INVALID_PARAMETER);
1496         return FALSE;
1497     }
1498
1499     SERVER_START_REQ( get_serial_info )
1500     {
1501         req->handle = hComm;
1502         if ((ret = !wine_server_call_err( req )))
1503         {
1504             lptimeouts->ReadIntervalTimeout         = reply->readinterval;
1505             lptimeouts->ReadTotalTimeoutMultiplier  = reply->readmult;
1506             lptimeouts->ReadTotalTimeoutConstant    = reply->readconst;
1507             lptimeouts->WriteTotalTimeoutMultiplier = reply->writemult;
1508             lptimeouts->WriteTotalTimeoutConstant   = reply->writeconst;
1509         }
1510     }
1511     SERVER_END_REQ;
1512     return ret;
1513 }
1514
1515 /*****************************************************************************
1516  *      SetCommTimeouts         (KERNEL32.@)
1517  *
1518  * Sets the timeouts used when reading and writing data to/from COMM ports.
1519  *
1520  * ReadIntervalTimeout
1521  *     - converted and passes to linux kernel as c_cc[VTIME]
1522  * ReadTotalTimeoutMultiplier, ReadTotalTimeoutConstant
1523  *     - used in ReadFile to calculate GetOverlappedResult's timeout
1524  * WriteTotalTimeoutMultiplier, WriteTotalTimeoutConstant
1525  *     - used in WriteFile to calculate GetOverlappedResult's timeout
1526  *
1527  * RETURNS
1528  *
1529  *  True if the timeouts were set, false otherwise.
1530  */
1531 BOOL WINAPI SetCommTimeouts(
1532     HANDLE hComm,              /* [in] handle of COMM device */
1533     LPCOMMTIMEOUTS lptimeouts) /* [in] pointer to COMMTIMEOUTS structure */
1534 {
1535     BOOL ret;
1536     int fd;
1537     struct termios tios;
1538
1539     TRACE("(%p,%p)\n",hComm,lptimeouts);
1540
1541     if(!lptimeouts)
1542     {
1543         SetLastError(ERROR_INVALID_PARAMETER);
1544         return FALSE;
1545     }
1546
1547     SERVER_START_REQ( set_serial_info )
1548     {
1549         req->handle       = hComm;
1550         req->flags        = SERIALINFO_SET_TIMEOUTS;
1551         req->readinterval = lptimeouts->ReadIntervalTimeout ;
1552         req->readmult     = lptimeouts->ReadTotalTimeoutMultiplier ;
1553         req->readconst    = lptimeouts->ReadTotalTimeoutConstant ;
1554         req->writemult    = lptimeouts->WriteTotalTimeoutMultiplier ;
1555         req->writeconst   = lptimeouts->WriteTotalTimeoutConstant ;
1556         ret = !wine_server_call_err( req );
1557     }
1558     SERVER_END_REQ;
1559     if (!ret) return FALSE;
1560
1561     /* FIXME: move this stuff to the server */
1562     fd = FILE_GetUnixHandle( hComm, GENERIC_READ );
1563     if (fd < 0) {
1564        FIXME("no fd for handle = %p!.\n",hComm);
1565        return FALSE;
1566     }
1567
1568     if (-1==tcgetattr(fd,&tios)) {
1569         FIXME("tcgetattr on fd %d failed!\n",fd);
1570         return FALSE;
1571     }
1572
1573     /* VTIME is in 1/10 seconds */
1574         {
1575                 unsigned int ux_timeout;
1576
1577                 if(lptimeouts->ReadIntervalTimeout == 0) /* 0 means no timeout */
1578                 {
1579                         ux_timeout = 0;
1580                 }
1581                 else
1582                 {
1583                         ux_timeout = (lptimeouts->ReadIntervalTimeout+99)/100;
1584                         if(ux_timeout == 0)
1585                         {
1586                                 ux_timeout = 1; /* must be at least some timeout */
1587                         }
1588                 }
1589                 tios.c_cc[VTIME] = ux_timeout;
1590         }
1591
1592     if (-1==tcsetattr(fd,0,&tios)) {
1593         FIXME("tcsetattr on fd %d failed!\n",fd);
1594         return FALSE;
1595     }
1596     close(fd);
1597     return TRUE;
1598 }
1599
1600 /***********************************************************************
1601  *           GetCommModemStatus   (KERNEL32.@)
1602  *
1603  *  Obtains the four control register bits if supported by the hardware.
1604  *
1605  * RETURNS
1606  *
1607  *  True if the communications handle was good and for hardware that
1608  *  control register access, false otherwise.
1609  */
1610 BOOL WINAPI GetCommModemStatus(
1611     HANDLE  hFile,       /* [in] The communications device. */
1612     LPDWORD lpModemStat) /* [out] The control register bits. */
1613 {
1614         int fd,mstat, result=FALSE;
1615
1616         *lpModemStat=0;
1617 #ifdef TIOCMGET
1618         fd = FILE_GetUnixHandle( hFile, GENERIC_READ );
1619         if(fd<0)
1620                 return FALSE;
1621         result = ioctl(fd, TIOCMGET, &mstat);
1622         close(fd);
1623         if (result == -1)
1624           {
1625             WARN("ioctl failed\n");
1626             return FALSE;
1627           }
1628 #ifdef TIOCM_CTS
1629         if (mstat & TIOCM_CTS)
1630             *lpModemStat |= MS_CTS_ON;
1631 #endif
1632 #ifdef TIOCM_DSR
1633         if (mstat & TIOCM_DSR)
1634           *lpModemStat |= MS_DSR_ON;
1635 #endif
1636 #ifdef TIOCM_RNG
1637         if (mstat & TIOCM_RNG)
1638           *lpModemStat |= MS_RING_ON;
1639 #endif
1640 #ifdef TIOCM_CAR
1641         /*FIXME:  Not really sure about RLSD  UB 990810*/
1642         if (mstat & TIOCM_CAR)
1643           *lpModemStat |= MS_RLSD_ON;
1644 #endif
1645         TRACE("%04x -> %s%s%s%s\n", mstat,
1646               (*lpModemStat &MS_RLSD_ON)?"MS_RLSD_ON ":"",
1647               (*lpModemStat &MS_RING_ON)?"MS_RING_ON ":"",
1648               (*lpModemStat &MS_DSR_ON)?"MS_DSR_ON ":"",
1649               (*lpModemStat &MS_CTS_ON)?"MS_CTS_ON ":"");
1650         return TRUE;
1651 #else
1652         return FALSE;
1653 #endif
1654 }
1655
1656 /***********************************************************************
1657  *             COMM_WaitCommEventService      (INTERNAL)
1658  *
1659  *  This function is called while the client is waiting on the
1660  *  server, so we can't make any server calls here.
1661  */
1662 static void COMM_WaitCommEventService(async_private *ovp)
1663 {
1664     async_commio *commio = (async_commio*) ovp;
1665     LPOVERLAPPED lpOverlapped = commio->lpOverlapped;
1666
1667     TRACE("overlapped %p\n",lpOverlapped);
1668
1669     /* FIXME: detect other events */
1670     *commio->buffer = EV_RXCHAR;
1671
1672     lpOverlapped->Internal = STATUS_SUCCESS;
1673 }
1674
1675
1676 /***********************************************************************
1677  *             COMM_WaitCommEvent         (INTERNAL)
1678  *
1679  *  This function must have an lpOverlapped.
1680  */
1681 static BOOL COMM_WaitCommEvent(
1682     HANDLE hFile,              /* [in] handle of comm port to wait for */
1683     LPDWORD lpdwEvents,        /* [out] event(s) that were detected */
1684     LPOVERLAPPED lpOverlapped) /* [in/out] for Asynchronous waiting */
1685 {
1686     int fd;
1687     async_commio *ovp;
1688
1689     if(!lpOverlapped)
1690     {
1691         SetLastError(ERROR_INVALID_PARAMETER);
1692         return FALSE;
1693     }
1694
1695     if(NtResetEvent(lpOverlapped->hEvent,NULL))
1696         return FALSE;
1697
1698     fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
1699     if(fd<0)
1700         return FALSE;
1701
1702     ovp = (async_commio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_commio));
1703     if(!ovp)
1704     {
1705         close(fd);
1706         return FALSE;
1707     }
1708
1709     ovp->async.ops = &commio_async_ops;
1710     ovp->async.handle = hFile;
1711     ovp->async.fd = fd;
1712     ovp->async.type = ASYNC_TYPE_WAIT;
1713     ovp->async.func = COMM_WaitCommEventService;
1714     ovp->async.event = lpOverlapped->hEvent;
1715     ovp->lpOverlapped = lpOverlapped;
1716     ovp->buffer = (char *)lpdwEvents;
1717
1718     lpOverlapped->InternalHigh = 0;
1719     lpOverlapped->Offset = 0;
1720     lpOverlapped->OffsetHigh = 0;
1721
1722     if ( !register_new_async (&ovp->async) )
1723         SetLastError( ERROR_IO_PENDING );
1724
1725     return FALSE;
1726 }
1727
1728 /***********************************************************************
1729  *           WaitCommEvent   (KERNEL32.@)
1730  *
1731  * Wait until something interesting happens on a COMM port.
1732  * Interesting things (events) are set by calling SetCommMask before
1733  * this function is called.
1734  *
1735  * RETURNS:
1736  *   TRUE if successful
1737  *   FALSE if failure
1738  *
1739  *   The set of detected events will be written to *lpdwEventMask
1740  *   ERROR_IO_PENDING will be returned the overlapped structure was passed
1741  *
1742  * BUGS:
1743  *  Only supports EV_RXCHAR and EV_TXEMPTY
1744  */
1745 BOOL WINAPI WaitCommEvent(
1746     HANDLE hFile,              /* [in] handle of comm port to wait for */
1747     LPDWORD lpdwEvents,        /* [out] event(s) that were detected */
1748     LPOVERLAPPED lpOverlapped) /* [in/out] for Asynchronous waiting */
1749 {
1750     OVERLAPPED ov;
1751     int ret;
1752
1753     TRACE("(%p %p %p )\n",hFile, lpdwEvents,lpOverlapped);
1754
1755     if(lpOverlapped)
1756         return COMM_WaitCommEvent(hFile, lpdwEvents, lpOverlapped);
1757
1758     /* if there is no overlapped structure, create our own */
1759     ov.hEvent = CreateEventA(NULL,FALSE,FALSE,NULL);
1760
1761     COMM_WaitCommEvent(hFile, lpdwEvents, &ov);
1762
1763     if(GetLastError()!=STATUS_PENDING)
1764     {
1765         CloseHandle(ov.hEvent);
1766         return FALSE;
1767     }
1768
1769     /* wait for the overlapped to complete */
1770     ret = GetOverlappedResult(hFile, &ov, NULL, TRUE);
1771     CloseHandle(ov.hEvent);
1772
1773     return ret;
1774 }
1775
1776 /***********************************************************************
1777  *           GetCommProperties   (KERNEL32.@)
1778  *
1779  * This function fills in a structure with the capabilities of the
1780  * communications port driver.
1781  *
1782  * RETURNS
1783  *
1784  *  TRUE on success, FALSE on failure
1785  *  If successful, the lpCommProp structure be filled in with
1786  *  properties of the comm port.
1787  */
1788 BOOL WINAPI GetCommProperties(
1789     HANDLE hFile,          /* [in] handle of the comm port */
1790     LPCOMMPROP lpCommProp) /* [out] pointer to struct to be filled */
1791 {
1792     FIXME("(%p %p )\n",hFile,lpCommProp);
1793     if(!lpCommProp)
1794         return FALSE;
1795
1796     /*
1797      * These values should be valid for LINUX's serial driver
1798      * FIXME: Perhaps they deserve an #ifdef LINUX
1799      */
1800     memset(lpCommProp,0,sizeof(COMMPROP));
1801     lpCommProp->wPacketLength       = 1;
1802     lpCommProp->wPacketVersion      = 1;
1803     lpCommProp->dwServiceMask       = SP_SERIALCOMM;
1804     lpCommProp->dwReserved1         = 0;
1805     lpCommProp->dwMaxTxQueue        = 4096;
1806     lpCommProp->dwMaxRxQueue        = 4096;
1807     lpCommProp->dwMaxBaud           = BAUD_115200;
1808     lpCommProp->dwProvSubType       = PST_RS232;
1809     lpCommProp->dwProvCapabilities  = PCF_DTRDSR | PCF_PARITY_CHECK | PCF_RTSCTS | PCF_TOTALTIMEOUTS;
1810     lpCommProp->dwSettableParams    = SP_BAUD | SP_DATABITS | SP_HANDSHAKING |
1811                                       SP_PARITY | SP_PARITY_CHECK | SP_STOPBITS ;
1812     lpCommProp->dwSettableBaud      = BAUD_075 | BAUD_110 | BAUD_134_5 | BAUD_150 |
1813                 BAUD_300 | BAUD_600 | BAUD_1200 | BAUD_1800 | BAUD_2400 | BAUD_4800 |
1814                 BAUD_9600 | BAUD_19200 | BAUD_38400 | BAUD_57600 | BAUD_115200 ;
1815     lpCommProp->wSettableData       = DATABITS_5 | DATABITS_6 | DATABITS_7 | DATABITS_8 ;
1816     lpCommProp->wSettableStopParity = STOPBITS_10 | STOPBITS_15 | STOPBITS_20 |
1817                 PARITY_NONE | PARITY_ODD |PARITY_EVEN | PARITY_MARK | PARITY_SPACE;
1818     lpCommProp->dwCurrentTxQueue    = lpCommProp->dwMaxTxQueue;
1819     lpCommProp->dwCurrentRxQueue    = lpCommProp->dwMaxRxQueue;
1820
1821     return TRUE;
1822 }
1823
1824 /***********************************************************************
1825  * FIXME:
1826  * The functionality of CommConfigDialogA, GetDefaultCommConfig and
1827  * SetDefaultCommConfig is implemented in a DLL (usually SERIALUI.DLL).
1828  * This is dependent on the type of COMM port, but since it is doubtful
1829  * anybody will get around to implementing support for fancy serial
1830  * ports in WINE, this is hardcoded for the time being.  The name of
1831  * this DLL should be stored in and read from the system registry in
1832  * the hive HKEY_LOCAL_MACHINE, key
1833  * System\\CurrentControlSet\\Services\\Class\\Ports\\????
1834  * where ???? is the port number... that is determined by PNP
1835  * The DLL should be loaded when the COMM port is opened, and closed
1836  * when the COMM port is closed. - MJM 20 June 2000
1837  ***********************************************************************/
1838 static CHAR lpszSerialUI[] = "serialui.dll";
1839
1840
1841 /***********************************************************************
1842  *           CommConfigDialogA   (KERNEL32.@)
1843  *
1844  * Raises a dialog that allows the user to configure a comm port.
1845  * Fills the COMMCONFIG struct with information specified by the user.
1846  * This function should call a similar routine in the COMM driver...
1847  *
1848  * RETURNS
1849  *
1850  *  TRUE on success, FALSE on failure
1851  *  If successful, the lpCommConfig structure will contain a new
1852  *  configuration for the comm port, as specified by the user.
1853  *
1854  * BUGS
1855  *  The library with the CommConfigDialog code is never unloaded.
1856  * Perhaps this should be done when the comm port is closed?
1857  */
1858 BOOL WINAPI CommConfigDialogA(
1859     LPCSTR lpszDevice,         /* [in] name of communications device */
1860     HANDLE hWnd,               /* [in] parent window for the dialog */
1861     LPCOMMCONFIG lpCommConfig) /* [out] pointer to struct to fill */
1862 {
1863     FARPROC lpfnCommDialog;
1864     HMODULE hConfigModule;
1865     BOOL r;
1866
1867     TRACE("(%p %p %p)\n",lpszDevice, hWnd, lpCommConfig);
1868
1869     hConfigModule = LoadLibraryA(lpszSerialUI);
1870     if(!hConfigModule)
1871         return FALSE;
1872
1873     lpfnCommDialog = GetProcAddress(hConfigModule, (LPCSTR)3L);
1874
1875     if(!lpfnCommDialog)
1876         return FALSE;
1877
1878     r = lpfnCommDialog(lpszDevice,hWnd,lpCommConfig);
1879
1880     /* UnloadLibrary(hConfigModule); */
1881
1882     return r;
1883 }
1884
1885 /***********************************************************************
1886  *           CommConfigDialogW   (KERNEL32.@)
1887  *
1888  * see CommConfigDialogA for more info
1889  */
1890 BOOL WINAPI CommConfigDialogW(
1891     LPCWSTR lpszDevice,        /* [in] name of communications device */
1892     HANDLE hWnd,               /* [in] parent window for the dialog */
1893     LPCOMMCONFIG lpCommConfig) /* [out] pointer to struct to fill */
1894 {
1895     BOOL r;
1896     LPSTR lpDeviceA;
1897
1898     lpDeviceA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpszDevice );
1899     if(lpDeviceA)
1900         return FALSE;
1901     r = CommConfigDialogA(lpDeviceA,hWnd,lpCommConfig);
1902     HeapFree( GetProcessHeap(), 0, lpDeviceA );
1903     return r;
1904 }
1905
1906 /***********************************************************************
1907  *           GetCommConfig     (KERNEL32.@)
1908  *
1909  * Fill in the COMMCONFIG structure for the comm port hFile
1910  *
1911  * RETURNS
1912  *
1913  *  TRUE on success, FALSE on failure
1914  *  If successful, lpCommConfig contains the comm port configuration.
1915  *
1916  * BUGS
1917  *
1918  */
1919 BOOL WINAPI GetCommConfig(
1920     HANDLE       hFile,        /* [in] The communications device. */
1921     LPCOMMCONFIG lpCommConfig, /* [out] The communications configuration of the device (if it fits). */
1922     LPDWORD      lpdwSize)     /* [in/out] Initially the size of the configuration buffer/structure,
1923                                   afterwards the number of bytes copied to the buffer or
1924                                   the needed size of the buffer. */
1925 {
1926     BOOL r;
1927
1928     TRACE("(%p %p)\n",hFile,lpCommConfig);
1929
1930     if(lpCommConfig == NULL)
1931         return FALSE;
1932
1933     r = *lpdwSize < sizeof(COMMCONFIG);
1934     *lpdwSize = sizeof(COMMCONFIG);
1935     if(!r)
1936         return FALSE;
1937
1938     lpCommConfig->dwSize = sizeof(COMMCONFIG);
1939     lpCommConfig->wVersion = 1;
1940     lpCommConfig->wReserved = 0;
1941     r = GetCommState(hFile,&lpCommConfig->dcb);
1942     lpCommConfig->dwProviderSubType = PST_RS232;
1943     lpCommConfig->dwProviderOffset = 0;
1944     lpCommConfig->dwProviderSize = 0;
1945
1946     return r;
1947 }
1948
1949 /***********************************************************************
1950  *           SetCommConfig     (KERNEL32.@)
1951  *
1952  *  Sets the configuration of the communications device.
1953  *
1954  * RETURNS
1955  *
1956  *  True on success, false if the handle was bad is not a communications device.
1957  */
1958 BOOL WINAPI SetCommConfig(
1959     HANDLE       hFile,         /* [in] The communications device. */
1960     LPCOMMCONFIG lpCommConfig,  /* [in] The desired configuration. */
1961     DWORD dwSize)               /* [in] size of the lpCommConfig struct */
1962 {
1963     TRACE("(%p %p)\n",hFile,lpCommConfig);
1964     return SetCommState(hFile,&lpCommConfig->dcb);
1965 }
1966
1967 /***********************************************************************
1968  *           SetDefaultCommConfigA   (KERNEL32.@)
1969  *
1970  *  Initializes the default configuration for the specified communication
1971  *  device. (ascii)
1972  *
1973  * RETURNS
1974  *
1975  *  True if the device was found and the defaults set, false otherwise
1976  */
1977 BOOL WINAPI SetDefaultCommConfigA(
1978     LPCSTR       lpszDevice,   /* [in] The ascii name of the device targeted for configuration. */
1979     LPCOMMCONFIG lpCommConfig, /* [in] The default configuration for the device. */
1980     DWORD        dwSize)       /* [in] The number of bytes in the configuration structure. */
1981 {
1982     FARPROC lpfnSetDefaultCommConfig;
1983     HMODULE hConfigModule;
1984     BOOL r;
1985
1986     TRACE("(%p %p %lx)\n",lpszDevice, lpCommConfig, dwSize);
1987
1988     hConfigModule = LoadLibraryA(lpszSerialUI);
1989     if(!hConfigModule)
1990         return FALSE;
1991
1992     lpfnSetDefaultCommConfig = GetProcAddress(hConfigModule, (LPCSTR)4L);
1993
1994     if(! lpfnSetDefaultCommConfig)
1995         return TRUE;
1996
1997     r = lpfnSetDefaultCommConfig(lpszDevice, lpCommConfig, dwSize);
1998
1999     /* UnloadLibrary(hConfigModule); */
2000
2001     return r;
2002 }
2003
2004
2005 /***********************************************************************
2006  *           SetDefaultCommConfigW     (KERNEL32.@)
2007  *
2008  *  Initializes the default configuration for the specified
2009  *  communication device. (unicode)
2010  *
2011  * RETURNS
2012  *
2013  */
2014 BOOL WINAPI SetDefaultCommConfigW(
2015     LPCWSTR      lpszDevice,   /* [in] The unicode name of the device targeted for configuration. */
2016     LPCOMMCONFIG lpCommConfig, /* [in] The default configuration for the device. */
2017     DWORD        dwSize)       /* [in] The number of bytes in the configuration structure. */
2018 {
2019     BOOL r;
2020     LPSTR lpDeviceA;
2021
2022     TRACE("(%s %p %lx)\n",debugstr_w(lpszDevice),lpCommConfig,dwSize);
2023
2024     lpDeviceA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpszDevice );
2025     if(lpDeviceA)
2026         return FALSE;
2027     r = SetDefaultCommConfigA(lpDeviceA,lpCommConfig,dwSize);
2028     HeapFree( GetProcessHeap(), 0, lpDeviceA );
2029     return r;
2030 }
2031
2032
2033 /***********************************************************************
2034  *           GetDefaultCommConfigA   (KERNEL32.@)
2035  *
2036  *   Acquires the default configuration of the specified communication device. (unicode)
2037  *
2038  *  RETURNS
2039  *
2040  *   True on successful reading of the default configuration,
2041  *   if the device is not found or the buffer is too small.
2042  */
2043 BOOL WINAPI GetDefaultCommConfigA(
2044     LPCSTR       lpszName, /* [in] The ascii name of the device targeted for configuration. */
2045     LPCOMMCONFIG lpCC,     /* [out] The default configuration for the device. */
2046     LPDWORD      lpdwSize) /* [in/out] Initially the size of the default configuration buffer,
2047                               afterwards the number of bytes copied to the buffer or
2048                               the needed size of the buffer. */
2049 {
2050      LPDCB lpdcb = &(lpCC->dcb);
2051      char  temp[40];
2052
2053      if (strncasecmp(lpszName,"COM",3)) {
2054         ERR("not implemented for <%s>\n", lpszName);
2055         return FALSE;
2056      }
2057
2058      TRACE("(%s %p %ld)\n", lpszName, lpCC, *lpdwSize );
2059      if (*lpdwSize < sizeof(COMMCONFIG)) {
2060          *lpdwSize = sizeof(COMMCONFIG);
2061          return FALSE;
2062        }
2063
2064      *lpdwSize = sizeof(COMMCONFIG);
2065
2066      lpCC->dwSize = sizeof(COMMCONFIG);
2067      lpCC->wVersion = 1;
2068      lpCC->dwProviderSubType = PST_RS232;
2069      lpCC->dwProviderOffset = 0L;
2070      lpCC->dwProviderSize = 0L;
2071
2072      sprintf( temp, "COM%c:38400,n,8,1", lpszName[3]);
2073      FIXME("setting %s as default\n", temp);
2074
2075      return BuildCommDCBA( temp, lpdcb);
2076 }
2077
2078 /**************************************************************************
2079  *         GetDefaultCommConfigW                (KERNEL32.@)
2080  *
2081  *   Acquires the default configuration of the specified communication device. (unicode)
2082  *
2083  *  RETURNS
2084  *
2085  *   True on successful reading of the default configuration,
2086  *   if the device is not found or the buffer is too small.
2087  */
2088 BOOL WINAPI GetDefaultCommConfigW(
2089     LPCWSTR      lpszName, /* [in] The unicode name of the device targeted for configuration. */
2090     LPCOMMCONFIG lpCC,     /* [out] The default configuration for the device. */
2091     LPDWORD      lpdwSize) /* [in/out] Initially the size of the default configuration buffer,
2092                               afterwards the number of bytes copied to the buffer or
2093                               the needed size of the buffer. */
2094 {
2095         BOOL ret = FALSE;
2096         LPSTR   lpszNameA;
2097
2098         TRACE("(%p,%p,%ld)\n",lpszName,lpCC,*lpdwSize);
2099         lpszNameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpszName );
2100         if (lpszNameA)
2101         {
2102         ret=GetDefaultCommConfigA(lpszNameA,lpCC,lpdwSize);
2103         HeapFree( GetProcessHeap(), 0, lpszNameA );
2104         }
2105         return ret;
2106 }