Moved __ASM_GLOBAL_FUNC macros and interlocked functions to port.[ch]
[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         FIXME("(%x,'%c'), stub ! Use win32 handle!\n",hComm,chTransmit);
1439         return TRUE;
1440 }
1441
1442 /*****************************************************************************
1443  *      GetCommTimeouts         (KERNEL32.@)
1444  *
1445  *  Obtains the request timeout values for the communications device.
1446  *
1447  * RETURNS
1448  *
1449  *  True on success, false if communications device handle is bad
1450  *  or the target structure is null.
1451  */
1452 BOOL WINAPI GetCommTimeouts(
1453     HANDLE         hComm,      /* [in] The communications device. */
1454     LPCOMMTIMEOUTS lptimeouts) /* [out] The struct of request timeouts. */
1455 {
1456     BOOL ret;
1457
1458     TRACE("(%x,%p)\n",hComm,lptimeouts);
1459
1460     if(!lptimeouts)
1461     {
1462         SetLastError(ERROR_INVALID_PARAMETER);
1463         return FALSE;
1464     }
1465
1466     SERVER_START_REQ( get_serial_info )
1467     {
1468         req->handle = hComm;
1469         if ((ret = !wine_server_call_err( req )))
1470         {
1471             lptimeouts->ReadIntervalTimeout         = reply->readinterval;
1472             lptimeouts->ReadTotalTimeoutMultiplier  = reply->readmult;
1473             lptimeouts->ReadTotalTimeoutConstant    = reply->readconst;
1474             lptimeouts->WriteTotalTimeoutMultiplier = reply->writemult;
1475             lptimeouts->WriteTotalTimeoutConstant   = reply->writeconst;
1476         }
1477     }
1478     SERVER_END_REQ;
1479     return ret;
1480 }
1481
1482 /*****************************************************************************
1483  *      SetCommTimeouts         (KERNEL32.@)
1484  *
1485  * Sets the timeouts used when reading and writing data to/from COMM ports.
1486  *
1487  * ReadIntervalTimeout 
1488  *     - converted and passes to linux kernel as c_cc[VTIME]
1489  * ReadTotalTimeoutMultiplier, ReadTotalTimeoutConstant
1490  *     - used in ReadFile to calculate GetOverlappedResult's timeout
1491  * WriteTotalTimeoutMultiplier, WriteTotalTimeoutConstant
1492  *     - used in WriteFile to calculate GetOverlappedResult's timeout
1493  *
1494  * RETURNS
1495  *
1496  *  True if the timeouts were set, false otherwise.
1497  */
1498 BOOL WINAPI SetCommTimeouts(
1499     HANDLE hComm,              /* [in] handle of COMM device */
1500     LPCOMMTIMEOUTS lptimeouts) /* [in] pointer to COMMTIMEOUTS structure */
1501 {
1502     BOOL ret;
1503     int fd;
1504     struct termios tios;
1505
1506     TRACE("(%x,%p)\n",hComm,lptimeouts);
1507
1508     if(!lptimeouts)
1509     {
1510         SetLastError(ERROR_INVALID_PARAMETER);
1511         return FALSE;
1512     }
1513
1514     SERVER_START_REQ( set_serial_info )
1515     {
1516         req->handle       = hComm;
1517         req->flags        = SERIALINFO_SET_TIMEOUTS;
1518         req->readinterval = lptimeouts->ReadIntervalTimeout ;
1519         req->readmult     = lptimeouts->ReadTotalTimeoutMultiplier ;
1520         req->readconst    = lptimeouts->ReadTotalTimeoutConstant ;
1521         req->writemult    = lptimeouts->WriteTotalTimeoutMultiplier ;
1522         req->writeconst   = lptimeouts->WriteTotalTimeoutConstant ;
1523         ret = !wine_server_call_err( req );
1524     }
1525     SERVER_END_REQ;
1526     if (!ret) return FALSE;
1527
1528     /* FIXME: move this stuff to the server */
1529     fd = FILE_GetUnixHandle( hComm, GENERIC_READ );
1530     if (fd < 0) {
1531        FIXME("no fd for handle = %0x!.\n",hComm);
1532        return FALSE;
1533     }
1534
1535     if (-1==tcgetattr(fd,&tios)) {
1536         FIXME("tcgetattr on fd %d failed!\n",fd);
1537         return FALSE;
1538     }
1539
1540     /* VTIME is in 1/10 seconds */
1541         {
1542                 unsigned int ux_timeout;
1543
1544                 if(lptimeouts->ReadIntervalTimeout == 0) /* 0 means no timeout */
1545                 {
1546                         ux_timeout = 0;
1547                 }
1548                 else
1549                 {
1550                         ux_timeout = (lptimeouts->ReadIntervalTimeout+99)/100;
1551                         if(ux_timeout == 0)
1552                         {
1553                                 ux_timeout = 1; /* must be at least some timeout */
1554                         }
1555                 }
1556                 tios.c_cc[VTIME] = ux_timeout;
1557         }
1558
1559     if (-1==tcsetattr(fd,0,&tios)) {
1560         FIXME("tcsetattr on fd %d failed!\n",fd);
1561         return FALSE;
1562     }
1563     close(fd);
1564     return TRUE;
1565 }
1566
1567 /***********************************************************************
1568  *           GetCommModemStatus   (KERNEL32.@)
1569  *
1570  *  Obtains the four control register bits if supported by the hardware.
1571  *
1572  * RETURNS
1573  *
1574  *  True if the communications handle was good and for hardware that
1575  *  control register access, false otherwise.
1576  */
1577 BOOL WINAPI GetCommModemStatus(
1578     HANDLE  hFile,       /* [in] The communications device. */
1579     LPDWORD lpModemStat) /* [out] The control register bits. */
1580 {
1581         int fd,mstat, result=FALSE;
1582         
1583         *lpModemStat=0;
1584 #ifdef TIOCMGET
1585         fd = FILE_GetUnixHandle( hFile, GENERIC_READ );
1586         if(fd<0)
1587                 return FALSE;
1588         result = ioctl(fd, TIOCMGET, &mstat);
1589         close(fd);
1590         if (result == -1)
1591           {
1592             WARN("ioctl failed\n");
1593             return FALSE;
1594           }
1595 #ifdef TIOCM_CTS
1596         if (mstat & TIOCM_CTS)
1597             *lpModemStat |= MS_CTS_ON;
1598 #endif
1599 #ifdef TIOCM_DSR
1600         if (mstat & TIOCM_DSR)
1601           *lpModemStat |= MS_DSR_ON;
1602 #endif
1603 #ifdef TIOCM_RNG
1604         if (mstat & TIOCM_RNG)
1605           *lpModemStat |= MS_RING_ON;
1606 #endif
1607 #ifdef TIOCM_CAR
1608         /*FIXME:  Not really sure about RLSD  UB 990810*/
1609         if (mstat & TIOCM_CAR)
1610           *lpModemStat |= MS_RLSD_ON;
1611 #endif
1612         TRACE("%04x -> %s%s%s%s\n", mstat,
1613               (*lpModemStat &MS_RLSD_ON)?"MS_RLSD_ON ":"",
1614               (*lpModemStat &MS_RING_ON)?"MS_RING_ON ":"",
1615               (*lpModemStat &MS_DSR_ON)?"MS_DSR_ON ":"",
1616               (*lpModemStat &MS_CTS_ON)?"MS_CTS_ON ":"");
1617         return TRUE;
1618 #else
1619         return FALSE;
1620 #endif
1621 }
1622
1623 /***********************************************************************
1624  *             COMM_WaitCommEventService      (INTERNAL)
1625  *
1626  *  This function is called while the client is waiting on the
1627  *  server, so we can't make any server calls here.
1628  */
1629 static void COMM_WaitCommEventService(async_private *ovp)
1630 {
1631     async_commio *commio = (async_commio*) ovp;
1632     LPOVERLAPPED lpOverlapped = commio->lpOverlapped;
1633
1634     TRACE("overlapped %p\n",lpOverlapped);
1635
1636     /* FIXME: detect other events */
1637     *commio->buffer = EV_RXCHAR;
1638  
1639     lpOverlapped->Internal = STATUS_SUCCESS;
1640 }
1641
1642
1643 /***********************************************************************
1644  *             COMM_WaitCommEvent         (INTERNAL)
1645  *
1646  *  This function must have an lpOverlapped.
1647  */
1648 static BOOL COMM_WaitCommEvent(
1649     HANDLE hFile,              /* [in] handle of comm port to wait for */
1650     LPDWORD lpdwEvents,        /* [out] event(s) that were detected */
1651     LPOVERLAPPED lpOverlapped) /* [in/out] for Asynchronous waiting */
1652 {
1653     int fd;
1654     async_commio *ovp;
1655
1656     if(!lpOverlapped)
1657     {
1658         SetLastError(ERROR_INVALID_PARAMETER);
1659         return FALSE;
1660     }
1661
1662     if(NtResetEvent(lpOverlapped->hEvent,NULL))
1663         return FALSE;
1664
1665     fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
1666     if(fd<0)
1667         return FALSE;
1668
1669     ovp = (async_commio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_commio));
1670     if(!ovp)
1671     {
1672         close(fd);
1673         return FALSE;
1674     }
1675
1676     ovp->async.ops = &commio_async_ops;
1677     ovp->async.handle = hFile;
1678     ovp->async.fd = fd;
1679     ovp->async.type = ASYNC_TYPE_WAIT;
1680     ovp->async.func = COMM_WaitCommEventService;
1681     ovp->async.event = lpOverlapped->hEvent;
1682     ovp->lpOverlapped = lpOverlapped;
1683     ovp->buffer = (char *)lpdwEvents;
1684
1685     lpOverlapped->InternalHigh = 0;
1686     lpOverlapped->Offset = 0;
1687     lpOverlapped->OffsetHigh = 0;
1688
1689     if ( !register_new_async (&ovp->async) )
1690         SetLastError( ERROR_IO_PENDING );
1691
1692     return FALSE;
1693 }
1694
1695 /***********************************************************************
1696  *           WaitCommEvent   (KERNEL32.@)
1697  *
1698  * Wait until something interesting happens on a COMM port.
1699  * Interesting things (events) are set by calling SetCommMask before
1700  * this function is called.
1701  *
1702  * RETURNS:
1703  *   TRUE if successful
1704  *   FALSE if failure
1705  *
1706  *   The set of detected events will be written to *lpdwEventMask
1707  *   ERROR_IO_PENDING will be returned the overlapped structure was passed
1708  *
1709  * BUGS:
1710  *  Only supports EV_RXCHAR and EV_TXEMPTY
1711  */
1712 BOOL WINAPI WaitCommEvent(
1713     HANDLE hFile,              /* [in] handle of comm port to wait for */
1714     LPDWORD lpdwEvents,        /* [out] event(s) that were detected */
1715     LPOVERLAPPED lpOverlapped) /* [in/out] for Asynchronous waiting */
1716 {
1717     OVERLAPPED ov;
1718     int ret;
1719
1720     TRACE("(%x %p %p )\n",hFile, lpdwEvents,lpOverlapped);
1721
1722     if(lpOverlapped)
1723         return COMM_WaitCommEvent(hFile, lpdwEvents, lpOverlapped);
1724
1725     /* if there is no overlapped structure, create our own */
1726     ov.hEvent = CreateEventA(NULL,FALSE,FALSE,NULL);
1727
1728     COMM_WaitCommEvent(hFile, lpdwEvents, &ov);
1729
1730     if(GetLastError()!=STATUS_PENDING)
1731     {
1732         CloseHandle(ov.hEvent);
1733         return FALSE;
1734     }
1735
1736     /* wait for the overlapped to complete */
1737     ret = GetOverlappedResult(hFile, &ov, NULL, TRUE);
1738     CloseHandle(ov.hEvent);
1739
1740     return ret;
1741 }
1742   
1743 /***********************************************************************
1744  *           GetCommProperties   (KERNEL32.@)
1745  *
1746  * This function fills in a structure with the capabilities of the 
1747  * communications port driver.
1748  *
1749  * RETURNS
1750  *
1751  *  TRUE on success, FALSE on failure
1752  *  If successful, the lpCommProp structure be filled in with
1753  *  properties of the comm port.
1754  */
1755 BOOL WINAPI GetCommProperties(
1756     HANDLE hFile,          /* [in] handle of the comm port */
1757     LPCOMMPROP lpCommProp) /* [out] pointer to struct to be filled */
1758 {
1759     FIXME("(%d %p )\n",hFile,lpCommProp);
1760     if(!lpCommProp)
1761         return FALSE;
1762
1763     /*
1764      * These values should be valid for LINUX's serial driver
1765      * FIXME: Perhaps they deserve an #ifdef LINUX
1766      */
1767     memset(lpCommProp,0,sizeof(COMMPROP));
1768     lpCommProp->wPacketLength       = 1;
1769     lpCommProp->wPacketVersion      = 1;
1770     lpCommProp->dwServiceMask       = SP_SERIALCOMM;
1771     lpCommProp->dwReserved1         = 0;
1772     lpCommProp->dwMaxTxQueue        = 4096;
1773     lpCommProp->dwMaxRxQueue        = 4096;
1774     lpCommProp->dwMaxBaud           = BAUD_115200;
1775     lpCommProp->dwProvSubType       = PST_RS232;
1776     lpCommProp->dwProvCapabilities  = PCF_DTRDSR | PCF_PARITY_CHECK | PCF_RTSCTS ;
1777     lpCommProp->dwSettableParams    = SP_BAUD | SP_DATABITS | SP_HANDSHAKING | 
1778                                       SP_PARITY | SP_PARITY_CHECK | SP_STOPBITS ;
1779     lpCommProp->dwSettableBaud      = BAUD_075 | BAUD_110 | BAUD_134_5 | BAUD_150 |
1780                 BAUD_300 | BAUD_600 | BAUD_1200 | BAUD_1800 | BAUD_2400 | BAUD_4800 |
1781                 BAUD_9600 | BAUD_19200 | BAUD_38400 | BAUD_57600 | BAUD_115200 ;
1782     lpCommProp->wSettableData       = DATABITS_5 | DATABITS_6 | DATABITS_7 | DATABITS_8 ;
1783     lpCommProp->wSettableStopParity = STOPBITS_10 | STOPBITS_15 | STOPBITS_20 | 
1784                 PARITY_NONE | PARITY_ODD |PARITY_EVEN | PARITY_MARK | PARITY_SPACE;
1785     lpCommProp->dwCurrentTxQueue    = lpCommProp->dwMaxTxQueue;
1786     lpCommProp->dwCurrentRxQueue    = lpCommProp->dwMaxRxQueue;
1787
1788     return TRUE;
1789 }
1790
1791 /***********************************************************************
1792  * FIXME:
1793  * The functionality of CommConfigDialogA, GetDefaultCommConfig and
1794  * SetDefaultCommConfig is implemented in a DLL (usually SERIALUI.DLL).
1795  * This is dependent on the type of COMM port, but since it is doubtful
1796  * anybody will get around to implementing support for fancy serial
1797  * ports in WINE, this is hardcoded for the time being.  The name of 
1798  * this DLL should be stored in and read from the system registry in 
1799  * the hive HKEY_LOCAL_MACHINE, key
1800  * System\\CurrentControlSet\\Services\\Class\\Ports\\????
1801  * where ???? is the port number... that is determined by PNP
1802  * The DLL should be loaded when the COMM port is opened, and closed 
1803  * when the COMM port is closed. - MJM 20 June 2000
1804  ***********************************************************************/
1805 static CHAR lpszSerialUI[] = "serialui.dll";
1806
1807
1808 /***********************************************************************
1809  *           CommConfigDialogA   (KERNEL32.@)
1810  *
1811  * Raises a dialog that allows the user to configure a comm port.
1812  * Fills the COMMCONFIG struct with information specified by the user.
1813  * This function should call a similar routine in the COMM driver...
1814  *
1815  * RETURNS
1816  *
1817  *  TRUE on success, FALSE on failure
1818  *  If successful, the lpCommConfig structure will contain a new
1819  *  configuration for the comm port, as specified by the user.
1820  *
1821  * BUGS
1822  *  The library with the CommConfigDialog code is never unloaded.
1823  * Perhaps this should be done when the comm port is closed?
1824  */
1825 BOOL WINAPI CommConfigDialogA(
1826     LPCSTR lpszDevice,         /* [in] name of communications device */
1827     HANDLE hWnd,               /* [in] parent window for the dialog */
1828     LPCOMMCONFIG lpCommConfig) /* [out] pointer to struct to fill */
1829 {
1830     FARPROC lpfnCommDialog;
1831     HMODULE hConfigModule;
1832     BOOL r;
1833
1834     TRACE("(%p %x %p)\n",lpszDevice, hWnd, lpCommConfig);
1835
1836     hConfigModule = LoadLibraryA(lpszSerialUI);
1837     if(!hConfigModule)
1838         return FALSE;
1839
1840     lpfnCommDialog = GetProcAddress(hConfigModule, (LPCSTR)3L);
1841
1842     if(!lpfnCommDialog)
1843         return FALSE;
1844
1845     r = lpfnCommDialog(lpszDevice,hWnd,lpCommConfig);
1846
1847     /* UnloadLibrary(hConfigModule); */
1848
1849     return r;
1850 }
1851
1852 /***********************************************************************
1853  *           CommConfigDialogW   (KERNEL32.@)
1854  *
1855  * see CommConfigDialogA for more info
1856  */
1857 BOOL WINAPI CommConfigDialogW(
1858     LPCWSTR lpszDevice,        /* [in] name of communications device */
1859     HANDLE hWnd,               /* [in] parent window for the dialog */
1860     LPCOMMCONFIG lpCommConfig) /* [out] pointer to struct to fill */
1861 {
1862     BOOL r;
1863     LPSTR lpDeviceA;
1864
1865     lpDeviceA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpszDevice );
1866     if(lpDeviceA)
1867         return FALSE;
1868     r = CommConfigDialogA(lpDeviceA,hWnd,lpCommConfig);
1869     HeapFree( GetProcessHeap(), 0, lpDeviceA );
1870     return r;
1871 }
1872
1873 /***********************************************************************
1874  *           GetCommConfig     (KERNEL32.@)
1875  *
1876  * Fill in the COMMCONFIG structure for the comm port hFile
1877  *
1878  * RETURNS
1879  *
1880  *  TRUE on success, FALSE on failure
1881  *  If successful, lpCommConfig contains the comm port configuration.
1882  *
1883  * BUGS
1884  *
1885  */
1886 BOOL WINAPI GetCommConfig(
1887     HANDLE       hFile,        /* [in] The communications device. */
1888     LPCOMMCONFIG lpCommConfig, /* [out] The communications configuration of the device (if it fits). */
1889     LPDWORD      lpdwSize)     /* [in/out] Initially the size of the configuration buffer/structure,
1890                                   afterwards the number of bytes copied to the buffer or 
1891                                   the needed size of the buffer. */
1892 {
1893     BOOL r;
1894
1895     TRACE("(%x %p)\n",hFile,lpCommConfig);
1896
1897     if(lpCommConfig == NULL)
1898         return FALSE;
1899
1900     r = *lpdwSize < sizeof(COMMCONFIG);
1901     *lpdwSize = sizeof(COMMCONFIG);
1902     if(!r)   
1903         return FALSE;
1904
1905     lpCommConfig->dwSize = sizeof(COMMCONFIG);
1906     lpCommConfig->wVersion = 1;
1907     lpCommConfig->wReserved = 0;
1908     r = GetCommState(hFile,&lpCommConfig->dcb);
1909     lpCommConfig->dwProviderSubType = PST_RS232;
1910     lpCommConfig->dwProviderOffset = 0;
1911     lpCommConfig->dwProviderSize = 0;
1912
1913     return r;
1914 }
1915
1916 /***********************************************************************
1917  *           SetCommConfig     (KERNEL32.@)
1918  *
1919  *  Sets the configuration of the communications device.
1920  *
1921  * RETURNS
1922  *
1923  *  True on success, false if the handle was bad is not a communications device.
1924  */
1925 BOOL WINAPI SetCommConfig(
1926     HANDLE       hFile,         /* [in] The communications device. */
1927     LPCOMMCONFIG lpCommConfig,  /* [in] The desired configuration. */
1928     DWORD dwSize)               /* [in] size of the lpCommConfig struct */
1929 {
1930     TRACE("(%x %p)\n",hFile,lpCommConfig);
1931     return SetCommState(hFile,&lpCommConfig->dcb);
1932 }
1933
1934 /***********************************************************************
1935  *           SetDefaultCommConfigA   (KERNEL32.@)
1936  *
1937  *  Initializes the default configuration for the specified communication
1938  *  device. (ascii)
1939  *
1940  * RETURNS
1941  *
1942  *  True if the device was found and the defaults set, false otherwise
1943  */
1944 BOOL WINAPI SetDefaultCommConfigA(
1945     LPCSTR       lpszDevice,   /* [in] The ascii name of the device targeted for configuration. */
1946     LPCOMMCONFIG lpCommConfig, /* [in] The default configuration for the device. */
1947     DWORD        dwSize)       /* [in] The number of bytes in the configuration structure. */
1948 {
1949     FARPROC lpfnSetDefaultCommConfig;
1950     HMODULE hConfigModule;
1951     BOOL r;
1952
1953     TRACE("(%p %p %lx)\n",lpszDevice, lpCommConfig, dwSize);
1954
1955     hConfigModule = LoadLibraryA(lpszSerialUI);
1956     if(!hConfigModule)
1957         return FALSE;
1958
1959     lpfnSetDefaultCommConfig = GetProcAddress(hConfigModule, (LPCSTR)4L);
1960
1961     if(! lpfnSetDefaultCommConfig)
1962         return TRUE;
1963
1964     r = lpfnSetDefaultCommConfig(lpszDevice, lpCommConfig, dwSize);
1965
1966     /* UnloadLibrary(hConfigModule); */
1967
1968     return r;
1969 }
1970
1971
1972 /***********************************************************************
1973  *           SetDefaultCommConfigW     (KERNEL32.@)
1974  *
1975  *  Initializes the default configuration for the specified
1976  *  communication device. (unicode)
1977  *
1978  * RETURNS
1979  *
1980  */
1981 BOOL WINAPI SetDefaultCommConfigW(
1982     LPCWSTR      lpszDevice,   /* [in] The unicode name of the device targeted for configuration. */
1983     LPCOMMCONFIG lpCommConfig, /* [in] The default configuration for the device. */
1984     DWORD        dwSize)       /* [in] The number of bytes in the configuration structure. */
1985 {
1986     BOOL r;
1987     LPSTR lpDeviceA;
1988
1989     TRACE("(%s %p %lx)\n",debugstr_w(lpszDevice),lpCommConfig,dwSize);
1990
1991     lpDeviceA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpszDevice );
1992     if(lpDeviceA)
1993         return FALSE;
1994     r = SetDefaultCommConfigA(lpDeviceA,lpCommConfig,dwSize);
1995     HeapFree( GetProcessHeap(), 0, lpDeviceA );
1996     return r;
1997 }
1998
1999
2000 /***********************************************************************
2001  *           GetDefaultCommConfigA   (KERNEL32.@)
2002  *
2003  *   Acquires the default configuration of the specified communication device. (unicode)
2004  *
2005  *  RETURNS
2006  *
2007  *   True on successful reading of the default configuration,
2008  *   if the device is not found or the buffer is too small.
2009  */
2010 BOOL WINAPI GetDefaultCommConfigA(
2011     LPCSTR       lpszName, /* [in] The ascii name of the device targeted for configuration. */
2012     LPCOMMCONFIG lpCC,     /* [out] The default configuration for the device. */
2013     LPDWORD      lpdwSize) /* [in/out] Initially the size of the default configuration buffer,
2014                               afterwards the number of bytes copied to the buffer or
2015                               the needed size of the buffer. */
2016 {
2017      LPDCB lpdcb = &(lpCC->dcb);
2018      char  temp[40];
2019
2020      if (strncasecmp(lpszName,"COM",3)) {
2021         ERR("not implemented for <%s>\n", lpszName);
2022         return FALSE;
2023      }
2024
2025      TRACE("(%s %p %ld)\n", lpszName, lpCC, *lpdwSize );
2026      if (*lpdwSize < sizeof(COMMCONFIG)) {
2027          *lpdwSize = sizeof(COMMCONFIG);
2028          return FALSE;
2029        }
2030
2031      *lpdwSize = sizeof(COMMCONFIG);
2032
2033      lpCC->dwSize = sizeof(COMMCONFIG);
2034      lpCC->wVersion = 1;
2035      lpCC->dwProviderSubType = PST_RS232;
2036      lpCC->dwProviderOffset = 0L;
2037      lpCC->dwProviderSize = 0L;
2038
2039      sprintf( temp, "COM%c:38400,n,8,1", lpszName[3]);
2040      FIXME("setting %s as default\n", temp);
2041
2042      return BuildCommDCBA( temp, lpdcb);
2043 }
2044
2045 /**************************************************************************
2046  *         GetDefaultCommConfigW                (KERNEL32.@)
2047  *
2048  *   Acquires the default configuration of the specified communication device. (unicode)
2049  *
2050  *  RETURNS
2051  *
2052  *   True on successful reading of the default configuration,
2053  *   if the device is not found or the buffer is too small.
2054  */
2055 BOOL WINAPI GetDefaultCommConfigW(
2056     LPCWSTR      lpszName, /* [in] The unicode name of the device targeted for configuration. */
2057     LPCOMMCONFIG lpCC,     /* [out] The default configuration for the device. */
2058     LPDWORD      lpdwSize) /* [in/out] Initially the size of the default configuration buffer,
2059                               afterwards the number of bytes copied to the buffer or
2060                               the needed size of the buffer. */
2061 {
2062         BOOL ret = FALSE;
2063         LPSTR   lpszNameA;
2064
2065         TRACE("(%p,%p,%ld)\n",lpszName,lpCC,*lpdwSize);
2066         lpszNameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpszName );
2067         if (lpszNameA)
2068         {
2069         ret=GetDefaultCommConfigA(lpszNameA,lpCC,lpdwSize);
2070         HeapFree( GetProcessHeap(), 0, lpszNameA );
2071         }
2072         return ret;
2073 }
2074