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