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