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