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