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