Implemented NtCreatelFile using the new symlink scheme.
[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      BOOL ret;
1088
1089      TRACE("handle %p, ptr %p\n", handle, lpdcb);
1090      TRACE("bytesize %d baudrate %ld fParity %d Parity %d stopbits %d\n",
1091            lpdcb->ByteSize,lpdcb->BaudRate,lpdcb->fParity, lpdcb->Parity,
1092            (lpdcb->StopBits == ONESTOPBIT)?1:
1093            (lpdcb->StopBits == TWOSTOPBITS)?2:0);
1094      TRACE("%s %s\n",(lpdcb->fInX)?"IXON":"~IXON",
1095            (lpdcb->fOutX)?"IXOFF":"~IXOFF");
1096      TRACE("fOutxCtsFlow %d fRtsControl %d\n", lpdcb->fOutxCtsFlow,
1097              lpdcb->fRtsControl);
1098      TRACE("fOutxDsrFlow %d fDtrControl%d\n", lpdcb->fOutxDsrFlow,
1099              lpdcb->fDtrControl);
1100              
1101
1102      fd = get_comm_fd( handle, GENERIC_READ );
1103      if (fd < 0) return FALSE;
1104
1105      if ((tcgetattr(fd,&port)) == -1) {
1106          int save_error = errno;
1107          COMM_SetCommError(handle,CE_IOE);
1108          release_comm_fd( handle, fd );
1109          ERR("tcgetattr error '%s'\n", strerror(save_error));
1110          return FALSE;
1111      }
1112
1113         port.c_cc[VMIN] = 0;
1114         port.c_cc[VTIME] = 1;
1115
1116 #ifdef IMAXBEL
1117         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|IMAXBEL);
1118 #else
1119         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR);
1120 #endif
1121         port.c_iflag |= (IGNBRK);
1122
1123         port.c_oflag &= ~(OPOST);
1124
1125         port.c_cflag &= ~(HUPCL);
1126         port.c_cflag |= CLOCAL | CREAD;
1127
1128         port.c_lflag &= ~(ICANON|ECHO|ISIG);
1129         port.c_lflag |= NOFLSH;
1130
1131 #ifdef CBAUD
1132         port.c_cflag &= ~CBAUD;
1133         switch (lpdcb->BaudRate) {
1134                 case 110:
1135                 case CBR_110:
1136                         port.c_cflag |= B110;
1137                         break;
1138                 case 300:
1139                 case CBR_300:
1140                         port.c_cflag |= B300;
1141                         break;
1142                 case 600:
1143                 case CBR_600:
1144                         port.c_cflag |= B600;
1145                         break;
1146                 case 1200:
1147                 case CBR_1200:
1148                         port.c_cflag |= B1200;
1149                         break;
1150                 case 2400:
1151                 case CBR_2400:
1152                         port.c_cflag |= B2400;
1153                         break;
1154                 case 4800:
1155                 case CBR_4800:
1156                         port.c_cflag |= B4800;
1157                         break;
1158                 case 9600:
1159                 case CBR_9600:
1160                         port.c_cflag |= B9600;
1161                         break;
1162                 case 19200:
1163                 case CBR_19200:
1164                         port.c_cflag |= B19200;
1165                         break;
1166                 case 38400:
1167                 case CBR_38400:
1168                         port.c_cflag |= B38400;
1169                         break;
1170 #ifdef B57600
1171                 case 57600:
1172                         port.c_cflag |= B57600;
1173                         break;
1174 #endif
1175 #ifdef B115200
1176                 case 115200:
1177                         port.c_cflag |= B115200;
1178                         break;
1179 #endif
1180 #ifdef B230400
1181                 case 230400:
1182                         port.c_cflag |= B230400;
1183                         break;
1184 #endif
1185 #ifdef B460800
1186                 case 460800:
1187                         port.c_cflag |= B460800;
1188                         break;
1189 #endif
1190                 default:
1191 #if defined (HAVE_LINUX_SERIAL_H) && defined (TIOCSSERIAL)
1192                         {   struct serial_struct nuts;
1193                             int arby;
1194                             ioctl(fd, TIOCGSERIAL, &nuts);
1195                             nuts.custom_divisor = nuts.baud_base / lpdcb->BaudRate;
1196                             if (!(nuts.custom_divisor)) nuts.custom_divisor = 1;
1197                             arby = nuts.baud_base / nuts.custom_divisor;
1198                             nuts.flags &= ~ASYNC_SPD_MASK;
1199                             nuts.flags |= ASYNC_SPD_CUST;
1200                             WARN("You (or a program acting at your behest) have specified\n"
1201                                  "a non-standard baud rate %ld.  Wine will set the rate to %d,\n"
1202                                  "which is as close as we can get by our present understanding of your\n"
1203                                  "hardware. I hope you know what you are doing.  Any disruption Wine\n"
1204                                  "has caused to your linux system can be undone with setserial \n"
1205                                  "(see man setserial). If you have incapacitated a Hayes type modem,\n"
1206                                  "reset it and it will probably recover.\n", lpdcb->BaudRate, arby);
1207                             ioctl(fd, TIOCSSERIAL, &nuts);
1208                             port.c_cflag |= B38400;
1209                         }
1210                         break;
1211 #endif    /* Don't have linux/serial.h or lack TIOCSSERIAL */
1212
1213
1214                         COMM_SetCommError(handle,IE_BAUDRATE);
1215                         release_comm_fd( handle, fd );
1216                         ERR("baudrate %ld\n",lpdcb->BaudRate);
1217                         return FALSE;
1218         }
1219 #elif !defined(__EMX__)
1220         switch (lpdcb->BaudRate) {
1221                 case 110:
1222                 case CBR_110:
1223                         port.c_ospeed = B110;
1224                         break;
1225                 case 300:
1226                 case CBR_300:
1227                         port.c_ospeed = B300;
1228                         break;
1229                 case 600:
1230                 case CBR_600:
1231                         port.c_ospeed = B600;
1232                         break;
1233                 case 1200:
1234                 case CBR_1200:
1235                         port.c_ospeed = B1200;
1236                         break;
1237                 case 2400:
1238                 case CBR_2400:
1239                         port.c_ospeed = B2400;
1240                         break;
1241                 case 4800:
1242                 case CBR_4800:
1243                         port.c_ospeed = B4800;
1244                         break;
1245                 case 9600:
1246                 case CBR_9600:
1247                         port.c_ospeed = B9600;
1248                         break;
1249                 case 19200:
1250                 case CBR_19200:
1251                         port.c_ospeed = B19200;
1252                         break;
1253                 case 38400:
1254                 case CBR_38400:
1255                         port.c_ospeed = B38400;
1256                         break;
1257 #ifdef B57600
1258                 case 57600:
1259                 case CBR_57600:
1260                         port.c_cflag |= B57600;
1261                         break;
1262 #endif
1263 #ifdef B115200
1264                 case 115200:
1265                 case CBR_115200:
1266                         port.c_cflag |= B115200;
1267                         break;
1268 #endif
1269 #ifdef B230400
1270                 case 230400:
1271                         port.c_cflag |= B230400;
1272                         break;
1273 #endif
1274 #ifdef B460800
1275                 case 460800:
1276                         port.c_cflag |= B460800;
1277                         break;
1278 #endif
1279                 default:
1280                         COMM_SetCommError(handle,IE_BAUDRATE);
1281                         release_comm_fd( handle, fd );
1282                         ERR("baudrate %ld\n",lpdcb->BaudRate);
1283                         return FALSE;
1284         }
1285         port.c_ispeed = port.c_ospeed;
1286 #endif
1287         bytesize=lpdcb->ByteSize;
1288         stopbits=lpdcb->StopBits;
1289
1290 #ifdef CMSPAR
1291         port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
1292 #else
1293         port.c_cflag &= ~(PARENB | PARODD);
1294 #endif
1295         if (lpdcb->fParity)
1296             port.c_iflag |= INPCK;
1297         else
1298             port.c_iflag &= ~INPCK;
1299         switch (lpdcb->Parity) {
1300                 case NOPARITY:
1301                         break;
1302                 case ODDPARITY:
1303                         port.c_cflag |= (PARENB | PARODD);
1304                         break;
1305                 case EVENPARITY:
1306                         port.c_cflag |= PARENB;
1307                         break;
1308 #ifdef CMSPAR
1309                 /* Linux defines mark/space (stick) parity */
1310                 case MARKPARITY:
1311                         port.c_cflag |= (PARENB | CMSPAR);
1312                         break;
1313                 case SPACEPARITY:
1314                         port.c_cflag |= (PARENB | PARODD |  CMSPAR);
1315                         break;
1316 #else
1317                 /* try the POSIX way */
1318                 case MARKPARITY:
1319                         if( stopbits == ONESTOPBIT) {
1320                             stopbits = TWOSTOPBITS;
1321                             port.c_iflag &= ~INPCK;
1322                         } else {
1323                             COMM_SetCommError(handle,IE_BYTESIZE);
1324                             release_comm_fd( handle, fd );
1325                             ERR("Cannot set MARK Parity\n");
1326                             return FALSE;
1327                         }
1328                         break;
1329                 case SPACEPARITY:
1330                         if( bytesize < 8) {
1331                             bytesize +=1;
1332                             port.c_iflag &= ~INPCK;
1333                         } else {
1334                             COMM_SetCommError(handle,IE_BYTESIZE);
1335                             release_comm_fd( handle, fd );
1336                             ERR("Cannot set SPACE Parity\n");
1337                             return FALSE;
1338                         }
1339                         break;
1340 #endif
1341                default:
1342                         COMM_SetCommError(handle,IE_BYTESIZE);
1343                         release_comm_fd( handle, fd );
1344                         ERR("Parity\n");
1345                         return FALSE;
1346         }
1347
1348
1349         port.c_cflag &= ~CSIZE;
1350         switch (bytesize) {
1351                 case 5:
1352                         port.c_cflag |= CS5;
1353                         break;
1354                 case 6:
1355                         port.c_cflag |= CS6;
1356                         break;
1357                 case 7:
1358                         port.c_cflag |= CS7;
1359                         break;
1360                 case 8:
1361                         port.c_cflag |= CS8;
1362                         break;
1363                 default:
1364                         COMM_SetCommError(handle,IE_BYTESIZE);
1365                         release_comm_fd( handle, fd );
1366                         ERR("ByteSize\n");
1367                         return FALSE;
1368         }
1369
1370         switch (stopbits) {
1371                 case ONESTOPBIT:
1372                                 port.c_cflag &= ~CSTOPB;
1373                                 break;
1374                 case ONE5STOPBITS: /* wil be selected if bytesize is 5 */
1375                 case TWOSTOPBITS:
1376                                 port.c_cflag |= CSTOPB;
1377                                 break;
1378                 default:
1379                         COMM_SetCommError(handle,IE_BYTESIZE);
1380                         release_comm_fd( handle, fd );
1381                         ERR("StopBits\n");
1382                         return FALSE;
1383         }
1384 #ifdef CRTSCTS
1385         if (    lpdcb->fOutxCtsFlow                     ||
1386                 lpdcb->fRtsControl == RTS_CONTROL_HANDSHAKE
1387         )
1388           {
1389             port.c_cflag |= CRTSCTS;
1390             TRACE("CRTSCTS\n");
1391           }
1392 #endif
1393
1394         if (lpdcb->fInX)
1395                 port.c_iflag |= IXON;
1396         else
1397                 port.c_iflag &= ~IXON;
1398         if (lpdcb->fOutX)
1399                 port.c_iflag |= IXOFF;
1400         else
1401                 port.c_iflag &= ~IXOFF;
1402
1403         if (tcsetattr(fd,TCSANOW,&port)==-1) { /* otherwise it hangs with pending input*/
1404                 ERR("tcsetattr error '%s'\n", strerror(errno));
1405                 COMM_SetCommError(handle,CE_IOE);
1406                 ret = FALSE;
1407         } else {
1408                 COMM_SetCommError(handle,0);
1409                 ret = TRUE;
1410         }
1411
1412         /* note: change DTR/RTS lines after setting the comm attributes,
1413          * so flow control does not interfere. */
1414 #ifdef TIOCM_DTR
1415         if (lpdcb->fDtrControl == DTR_CONTROL_HANDSHAKE)
1416         {
1417              WARN("DSR/DTR flow control not supported\n");
1418         } else if(lpdcb->fDtrControl == DTR_CONTROL_DISABLE)
1419             COMM_WhackModem(fd, ~TIOCM_DTR, 0);
1420         else    
1421             COMM_WhackModem(fd, 0, TIOCM_DTR);
1422 #endif
1423 #ifdef TIOCM_RTS
1424         if(!lpdcb->fOutxCtsFlow )
1425         {
1426             if(lpdcb->fRtsControl == RTS_CONTROL_DISABLE)
1427                 COMM_WhackModem(fd, ~TIOCM_RTS, 0);
1428             else    
1429                 COMM_WhackModem(fd, 0, TIOCM_RTS);
1430         }
1431 #endif
1432         if(lpdcb->fRtsControl == RTS_CONTROL_TOGGLE)
1433             FIXME("RTS_CONTROL_TOGGLE is not supported.\n");
1434         release_comm_fd( handle, fd );
1435         return ret;
1436
1437 }
1438
1439
1440 /*****************************************************************************
1441  *      GetCommState    (KERNEL32.@)
1442  *
1443  *  Fills in a device control block with information from a communications device.
1444  *
1445  * RETURNS
1446  *
1447  *  True on success, false if the communication device handle is bad etc
1448  *
1449  * BUGS
1450  *
1451  *  XonChar and XoffChar are not set.
1452  */
1453 BOOL WINAPI GetCommState(
1454     HANDLE handle, /* [in] The communications device. */
1455     LPDCB  lpdcb)  /* [out] The device control block. */
1456 {
1457      struct termios port;
1458      int fd,speed;
1459      int stat = DTR_CONTROL_ENABLE | RTS_CONTROL_ENABLE;
1460
1461      TRACE("handle %p, ptr %p\n", handle, lpdcb);
1462
1463      fd = get_comm_fd( handle, GENERIC_READ );
1464      if (fd < 0) return FALSE;
1465      if (tcgetattr(fd, &port) == -1
1466 #ifdef TIOCMGET
1467              || ioctl(fd, TIOCMGET, &stat) == -1
1468 #endif
1469              ) {
1470                 int save_error=errno;
1471                 ERR("tcgetattr or ioctl error '%s'\n", strerror(save_error));
1472                 COMM_SetCommError(handle,CE_IOE);
1473                 release_comm_fd( handle, fd );
1474                 return FALSE;
1475         }
1476      release_comm_fd( handle, fd );
1477 #ifndef __EMX__
1478 #ifdef CBAUD
1479      speed= (port.c_cflag & CBAUD);
1480 #else
1481      speed= (cfgetospeed(&port));
1482 #endif
1483      switch (speed) {
1484                 case B110:
1485                         lpdcb->BaudRate = 110;
1486                         break;
1487                 case B300:
1488                         lpdcb->BaudRate = 300;
1489                         break;
1490                 case B600:
1491                         lpdcb->BaudRate = 600;
1492                         break;
1493                 case B1200:
1494                         lpdcb->BaudRate = 1200;
1495                         break;
1496                 case B2400:
1497                         lpdcb->BaudRate = 2400;
1498                         break;
1499                 case B4800:
1500                         lpdcb->BaudRate = 4800;
1501                         break;
1502                 case B9600:
1503                         lpdcb->BaudRate = 9600;
1504                         break;
1505                 case B19200:
1506                         lpdcb->BaudRate = 19200;
1507                         break;
1508                 case B38400:
1509                         lpdcb->BaudRate = 38400;
1510                         break;
1511 #ifdef B57600
1512                 case B57600:
1513                         lpdcb->BaudRate = 57600;
1514                         break;
1515 #endif
1516 #ifdef B115200
1517                 case B115200:
1518                         lpdcb->BaudRate = 115200;
1519                         break;
1520 #endif
1521 #ifdef B230400
1522                 case B230400:
1523                         lpdcb->BaudRate = 230400;
1524                         break;
1525 #endif
1526 #ifdef B460800
1527                 case B460800:
1528                         lpdcb->BaudRate = 460800;
1529                         break;
1530 #endif
1531                 default:
1532                         ERR("unknown speed %x \n",speed);
1533         }
1534 #endif
1535         switch (port.c_cflag & CSIZE) {
1536                 case CS5:
1537                         lpdcb->ByteSize = 5;
1538                         break;
1539                 case CS6:
1540                         lpdcb->ByteSize = 6;
1541                         break;
1542                 case CS7:
1543                         lpdcb->ByteSize = 7;
1544                         break;
1545                 case CS8:
1546                         lpdcb->ByteSize = 8;
1547                         break;
1548                 default:
1549                         ERR("unknown size %x \n",port.c_cflag & CSIZE);
1550         }
1551
1552         if(port.c_iflag & INPCK)
1553             lpdcb->fParity = TRUE;
1554         else
1555             lpdcb->fParity = FALSE;
1556 #ifdef CMSPAR
1557         switch (port.c_cflag & (PARENB | PARODD | CMSPAR))
1558 #else
1559         switch (port.c_cflag & (PARENB | PARODD))
1560 #endif
1561         {
1562                 case 0:
1563                         lpdcb->Parity = NOPARITY;
1564                         break;
1565                 case PARENB:
1566                         lpdcb->Parity = EVENPARITY;
1567                         break;
1568                 case (PARENB | PARODD):
1569                         lpdcb->Parity = ODDPARITY;
1570                         break;
1571 #ifdef CMSPAR
1572                 case (PARENB | CMSPAR):
1573                         lpdcb->Parity = MARKPARITY;
1574                         break;
1575                 case (PARENB | PARODD | CMSPAR):
1576                         lpdcb->Parity = SPACEPARITY;
1577                         break;
1578 #endif
1579         }
1580
1581         if (port.c_cflag & CSTOPB)
1582             if(lpdcb->ByteSize == 5)
1583                 lpdcb->StopBits = ONE5STOPBITS;
1584             else
1585                 lpdcb->StopBits = TWOSTOPBITS;
1586         else
1587             lpdcb->StopBits = ONESTOPBIT;
1588
1589         lpdcb->fNull = 0;
1590         lpdcb->fBinary = 1;
1591
1592         /* termios does not support DTR/DSR flow control */
1593         lpdcb->fOutxDsrFlow = 0;
1594         lpdcb->fDtrControl =
1595 #ifdef TIOCM_DTR
1596             !(stat & TIOCM_DTR) ?  DTR_CONTROL_DISABLE:
1597 #endif
1598                 DTR_CONTROL_ENABLE  ;
1599
1600 #ifdef CRTSCTS
1601
1602         if (port.c_cflag & CRTSCTS) {
1603                 lpdcb->fRtsControl = RTS_CONTROL_HANDSHAKE;
1604                 lpdcb->fOutxCtsFlow = 1;
1605         } else
1606 #endif
1607         {
1608                 lpdcb->fRtsControl = 
1609 #ifdef TIOCM_RTS
1610                     !(stat & TIOCM_RTS) ?  RTS_CONTROL_DISABLE :
1611 #endif
1612                     RTS_CONTROL_ENABLE ;
1613                 lpdcb->fOutxCtsFlow = 0;
1614         }
1615         if (port.c_iflag & IXON)
1616                 lpdcb->fInX = 1;
1617         else
1618                 lpdcb->fInX = 0;
1619
1620         if (port.c_iflag & IXOFF)
1621                 lpdcb->fOutX = 1;
1622         else
1623                 lpdcb->fOutX = 0;
1624 /*
1625         lpdcb->XonChar =
1626         lpdcb->XoffChar =
1627  */
1628         lpdcb->XonLim = 10;
1629         lpdcb->XoffLim = 10;
1630
1631         COMM_SetCommError(handle,0);
1632
1633         TRACE("OK\n");
1634
1635         TRACE("bytesize %d baudrate %ld fParity %d Parity %d stopbits %d\n",
1636               lpdcb->ByteSize,lpdcb->BaudRate,lpdcb->fParity, lpdcb->Parity,
1637               (lpdcb->StopBits == ONESTOPBIT)?1:
1638               (lpdcb->StopBits == TWOSTOPBITS)?2:0);
1639         TRACE("%s %s\n",(lpdcb->fInX)?"IXON":"~IXON",
1640               (lpdcb->fOutX)?"IXOFF":"~IXOFF");
1641          TRACE("fOutxCtsFlow %d fRtsControl %d\n", lpdcb->fOutxCtsFlow,
1642                  lpdcb->fRtsControl);
1643          TRACE("fOutxDsrFlow %d fDtrControl%d\n", lpdcb->fOutxDsrFlow,
1644                  lpdcb->fDtrControl);
1645 #ifdef CRTSCTS
1646         if (    lpdcb->fOutxCtsFlow                     ||
1647                 lpdcb->fRtsControl == RTS_CONTROL_HANDSHAKE
1648                 )
1649           TRACE("CRTSCTS\n");
1650         else
1651
1652           TRACE("~CRTSCTS\n");
1653 #endif
1654         return TRUE;
1655 }
1656
1657 /*****************************************************************************
1658  *      TransmitCommChar        (KERNEL32.@)
1659  *
1660  *  Transmits a single character in front of any pending characters in the
1661  *  output buffer.  Usually used to send an interrupt character to a host.
1662  *
1663  * RETURNS
1664  *
1665  *  True if the call succeeded, false if the previous command character to the
1666  *  same device has not been sent yet the handle is bad etc.
1667  *
1668  * BUGS
1669  *
1670  *  Stub.
1671  */
1672 BOOL WINAPI TransmitCommChar(
1673     HANDLE hComm,      /* [in] The communication device in need of a command character. */
1674     CHAR   chTransmit) /* [in] The character to transmit. */
1675 {
1676     WARN("(%p,'%c') not perfect!\n",hComm,chTransmit);
1677
1678     return WriteFile( hComm, &chTransmit, 1, NULL, NULL );
1679 }
1680
1681
1682 /*****************************************************************************
1683  *      GetCommTimeouts         (KERNEL32.@)
1684  *
1685  *  Obtains the request timeout values for the communications device.
1686  *
1687  * RETURNS
1688  *
1689  *  True on success, false if communications device handle is bad
1690  *  or the target structure is null.
1691  */
1692 BOOL WINAPI GetCommTimeouts(
1693     HANDLE         hComm,      /* [in] The communications device. */
1694     LPCOMMTIMEOUTS lptimeouts) /* [out] The struct of request timeouts. */
1695 {
1696     BOOL ret;
1697
1698     TRACE("(%p,%p)\n",hComm,lptimeouts);
1699
1700     if(!lptimeouts)
1701     {
1702         SetLastError(ERROR_INVALID_PARAMETER);
1703         return FALSE;
1704     }
1705
1706     SERVER_START_REQ( get_serial_info )
1707     {
1708         req->handle = hComm;
1709         if ((ret = !wine_server_call_err( req )))
1710         {
1711             lptimeouts->ReadIntervalTimeout         = reply->readinterval;
1712             lptimeouts->ReadTotalTimeoutMultiplier  = reply->readmult;
1713             lptimeouts->ReadTotalTimeoutConstant    = reply->readconst;
1714             lptimeouts->WriteTotalTimeoutMultiplier = reply->writemult;
1715             lptimeouts->WriteTotalTimeoutConstant   = reply->writeconst;
1716         }
1717     }
1718     SERVER_END_REQ;
1719     return ret;
1720 }
1721
1722 /*****************************************************************************
1723  *      SetCommTimeouts         (KERNEL32.@)
1724  *
1725  * Sets the timeouts used when reading and writing data to/from COMM ports.
1726  *
1727  * ReadIntervalTimeout
1728  *     - converted and passes to linux kernel as c_cc[VTIME]
1729  * ReadTotalTimeoutMultiplier, ReadTotalTimeoutConstant
1730  *     - used in ReadFile to calculate GetOverlappedResult's timeout
1731  * WriteTotalTimeoutMultiplier, WriteTotalTimeoutConstant
1732  *     - used in WriteFile to calculate GetOverlappedResult's timeout
1733  *
1734  * RETURNS
1735  *
1736  *  True if the timeouts were set, false otherwise.
1737  */
1738 BOOL WINAPI SetCommTimeouts(
1739     HANDLE hComm,              /* [in] handle of COMM device */
1740     LPCOMMTIMEOUTS lptimeouts) /* [in] pointer to COMMTIMEOUTS structure */
1741 {
1742     BOOL ret;
1743     int fd;
1744     struct termios tios;
1745
1746     TRACE("(%p,%p)\n",hComm,lptimeouts);
1747
1748     if(!lptimeouts)
1749     {
1750         SetLastError(ERROR_INVALID_PARAMETER);
1751         return FALSE;
1752     }
1753
1754     SERVER_START_REQ( set_serial_info )
1755     {
1756         req->handle       = hComm;
1757         req->flags        = SERIALINFO_SET_TIMEOUTS;
1758         req->readinterval = lptimeouts->ReadIntervalTimeout ;
1759         req->readmult     = lptimeouts->ReadTotalTimeoutMultiplier ;
1760         req->readconst    = lptimeouts->ReadTotalTimeoutConstant ;
1761         req->writemult    = lptimeouts->WriteTotalTimeoutMultiplier ;
1762         req->writeconst   = lptimeouts->WriteTotalTimeoutConstant ;
1763         ret = !wine_server_call_err( req );
1764     }
1765     SERVER_END_REQ;
1766     if (!ret) return FALSE;
1767
1768     /* FIXME: move this stuff to the server */
1769     fd = get_comm_fd( hComm, GENERIC_READ );
1770     if (fd < 0) return FALSE;
1771
1772     if (-1==tcgetattr(fd,&tios)) {
1773         FIXME("tcgetattr on fd %d failed!\n",fd);
1774         release_comm_fd( hComm, fd );
1775         return FALSE;
1776     }
1777
1778     /* VTIME is in 1/10 seconds */
1779         {
1780                 unsigned int ux_timeout;
1781
1782                 if(lptimeouts->ReadIntervalTimeout == 0) /* 0 means no timeout */
1783                 {
1784                         ux_timeout = 0;
1785                 }
1786                 else
1787                 {
1788                         ux_timeout = (lptimeouts->ReadIntervalTimeout+99)/100;
1789                         if(ux_timeout == 0)
1790                         {
1791                                 ux_timeout = 1; /* must be at least some timeout */
1792                         }
1793                 }
1794                 tios.c_cc[VTIME] = ux_timeout;
1795         }
1796
1797     if (-1==tcsetattr(fd,0,&tios)) {
1798         FIXME("tcsetattr on fd %d failed!\n",fd);
1799         release_comm_fd( hComm, fd );
1800         return FALSE;
1801     }
1802     release_comm_fd( hComm, fd );
1803     return TRUE;
1804 }
1805
1806 /***********************************************************************
1807  *           GetCommModemStatus   (KERNEL32.@)
1808  *
1809  *  Obtains the four control register bits if supported by the hardware.
1810  *
1811  * RETURNS
1812  *
1813  *  True if the communications handle was good and for hardware that
1814  *  control register access, false otherwise.
1815  */
1816 BOOL WINAPI GetCommModemStatus(
1817     HANDLE  hFile,       /* [in] The communications device. */
1818     LPDWORD lpModemStat) /* [out] The control register bits. */
1819 {
1820         int fd,mstat, result=FALSE;
1821
1822         *lpModemStat=0;
1823 #ifdef TIOCMGET
1824         fd = get_comm_fd( hFile, GENERIC_READ );
1825         if(fd<0)
1826                 return FALSE;
1827         result = ioctl(fd, TIOCMGET, &mstat);
1828         release_comm_fd( hFile, fd );
1829         if (result == -1)
1830           {
1831             WARN("ioctl failed\n");
1832             return FALSE;
1833           }
1834 #ifdef TIOCM_CTS
1835         if (mstat & TIOCM_CTS)
1836             *lpModemStat |= MS_CTS_ON;
1837 #endif
1838 #ifdef TIOCM_DSR
1839         if (mstat & TIOCM_DSR)
1840           *lpModemStat |= MS_DSR_ON;
1841 #endif
1842 #ifdef TIOCM_RNG
1843         if (mstat & TIOCM_RNG)
1844           *lpModemStat |= MS_RING_ON;
1845 #endif
1846 #ifdef TIOCM_CAR
1847         /*FIXME:  Not really sure about RLSD  UB 990810*/
1848         if (mstat & TIOCM_CAR)
1849           *lpModemStat |= MS_RLSD_ON;
1850 #endif
1851         TRACE("%04x -> %s%s%s%s\n", mstat,
1852               (*lpModemStat &MS_RLSD_ON)?"MS_RLSD_ON ":"",
1853               (*lpModemStat &MS_RING_ON)?"MS_RING_ON ":"",
1854               (*lpModemStat &MS_DSR_ON)?"MS_DSR_ON ":"",
1855               (*lpModemStat &MS_CTS_ON)?"MS_CTS_ON ":"");
1856         return TRUE;
1857 #else
1858         return FALSE;
1859 #endif
1860 }
1861
1862 /***********************************************************************
1863  *             COMM_WaitCommEventService      (INTERNAL)
1864  *
1865  *  This function is called while the client is waiting on the
1866  *  server, so we can't make any server calls here.
1867  */
1868 static void COMM_WaitCommEventService(async_private *ovp)
1869 {
1870     async_commio *commio = (async_commio*) ovp;
1871     IO_STATUS_BLOCK* iosb = commio->async.iosb;
1872
1873     TRACE("iosb %p\n",iosb);
1874
1875     /* FIXME: detect other events */
1876     *commio->buffer = EV_RXCHAR;
1877
1878     iosb->u.Status = STATUS_SUCCESS;
1879 }
1880
1881
1882 /***********************************************************************
1883  *             COMM_WaitCommEvent         (INTERNAL)
1884  *
1885  *  This function must have an lpOverlapped.
1886  */
1887 static BOOL COMM_WaitCommEvent(
1888     HANDLE hFile,              /* [in] handle of comm port to wait for */
1889     LPDWORD lpdwEvents,        /* [out] event(s) that were detected */
1890     LPOVERLAPPED lpOverlapped) /* [in/out] for Asynchronous waiting */
1891 {
1892     int fd;
1893     async_commio *ovp;
1894
1895     if(!lpOverlapped)
1896     {
1897         SetLastError(ERROR_INVALID_PARAMETER);
1898         return FALSE;
1899     }
1900
1901     if(NtResetEvent(lpOverlapped->hEvent,NULL))
1902         return FALSE;
1903
1904     fd = get_comm_fd( hFile, GENERIC_WRITE );
1905     if(fd<0)
1906         return FALSE;
1907
1908     ovp = (async_commio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_commio));
1909     if(!ovp)
1910     {
1911         release_comm_fd( hFile, fd );
1912         return FALSE;
1913     }
1914
1915     ovp->async.ops = &commio_async_ops;
1916     ovp->async.handle = hFile;
1917     ovp->async.fd = fd;  /* FIXME */
1918     ovp->async.type = ASYNC_TYPE_WAIT;
1919     ovp->async.func = COMM_WaitCommEventService;
1920     ovp->async.event = lpOverlapped->hEvent;
1921     ovp->async.iosb = (IO_STATUS_BLOCK*)lpOverlapped;
1922     ovp->buffer = (char *)lpdwEvents;
1923
1924     lpOverlapped->InternalHigh = 0;
1925     lpOverlapped->Offset = 0;
1926     lpOverlapped->OffsetHigh = 0;
1927
1928     if ( !register_new_async (&ovp->async) )
1929         SetLastError( ERROR_IO_PENDING );
1930
1931     return FALSE;
1932 }
1933
1934 /***********************************************************************
1935  *           WaitCommEvent   (KERNEL32.@)
1936  *
1937  * Wait until something interesting happens on a COMM port.
1938  * Interesting things (events) are set by calling SetCommMask before
1939  * this function is called.
1940  *
1941  * RETURNS:
1942  *   TRUE if successful
1943  *   FALSE if failure
1944  *
1945  *   The set of detected events will be written to *lpdwEventMask
1946  *   ERROR_IO_PENDING will be returned the overlapped structure was passed
1947  *
1948  * BUGS:
1949  *  Only supports EV_RXCHAR and EV_TXEMPTY
1950  */
1951 BOOL WINAPI WaitCommEvent(
1952     HANDLE hFile,              /* [in] handle of comm port to wait for */
1953     LPDWORD lpdwEvents,        /* [out] event(s) that were detected */
1954     LPOVERLAPPED lpOverlapped) /* [in/out] for Asynchronous waiting */
1955 {
1956     OVERLAPPED ov;
1957     int ret;
1958
1959     TRACE("(%p %p %p )\n",hFile, lpdwEvents,lpOverlapped);
1960
1961     if(lpOverlapped)
1962         return COMM_WaitCommEvent(hFile, lpdwEvents, lpOverlapped);
1963
1964     /* if there is no overlapped structure, create our own */
1965     ov.hEvent = CreateEventA(NULL,FALSE,FALSE,NULL);
1966
1967     COMM_WaitCommEvent(hFile, lpdwEvents, &ov);
1968
1969     /* wait for the overlapped to complete */
1970     ret = GetOverlappedResult(hFile, &ov, NULL, TRUE);
1971     CloseHandle(ov.hEvent);
1972
1973     return ret;
1974 }
1975
1976 /***********************************************************************
1977  *           GetCommProperties   (KERNEL32.@)
1978  *
1979  * This function fills in a structure with the capabilities of the
1980  * communications port driver.
1981  *
1982  * RETURNS
1983  *
1984  *  TRUE on success, FALSE on failure
1985  *  If successful, the lpCommProp structure be filled in with
1986  *  properties of the comm port.
1987  */
1988 BOOL WINAPI GetCommProperties(
1989     HANDLE hFile,          /* [in] handle of the comm port */
1990     LPCOMMPROP lpCommProp) /* [out] pointer to struct to be filled */
1991 {
1992     FIXME("(%p %p )\n",hFile,lpCommProp);
1993     if(!lpCommProp)
1994         return FALSE;
1995
1996     /*
1997      * These values should be valid for LINUX's serial driver
1998      * FIXME: Perhaps they deserve an #ifdef LINUX
1999      */
2000     memset(lpCommProp,0,sizeof(COMMPROP));
2001     lpCommProp->wPacketLength       = 1;
2002     lpCommProp->wPacketVersion      = 1;
2003     lpCommProp->dwServiceMask       = SP_SERIALCOMM;
2004     lpCommProp->dwReserved1         = 0;
2005     lpCommProp->dwMaxTxQueue        = 4096;
2006     lpCommProp->dwMaxRxQueue        = 4096;
2007     lpCommProp->dwMaxBaud           = BAUD_115200;
2008     lpCommProp->dwProvSubType       = PST_RS232;
2009     lpCommProp->dwProvCapabilities  = PCF_DTRDSR | PCF_PARITY_CHECK | PCF_RTSCTS | PCF_TOTALTIMEOUTS;
2010     lpCommProp->dwSettableParams    = SP_BAUD | SP_DATABITS | SP_HANDSHAKING |
2011                                       SP_PARITY | SP_PARITY_CHECK | SP_STOPBITS ;
2012     lpCommProp->dwSettableBaud      = BAUD_075 | BAUD_110 | BAUD_134_5 | BAUD_150 |
2013                 BAUD_300 | BAUD_600 | BAUD_1200 | BAUD_1800 | BAUD_2400 | BAUD_4800 |
2014                 BAUD_9600 | BAUD_19200 | BAUD_38400 | BAUD_57600 | BAUD_115200 ;
2015     lpCommProp->wSettableData       = DATABITS_5 | DATABITS_6 | DATABITS_7 | DATABITS_8 ;
2016     lpCommProp->wSettableStopParity = STOPBITS_10 | STOPBITS_15 | STOPBITS_20 |
2017                 PARITY_NONE | PARITY_ODD |PARITY_EVEN | PARITY_MARK | PARITY_SPACE;
2018     lpCommProp->dwCurrentTxQueue    = lpCommProp->dwMaxTxQueue;
2019     lpCommProp->dwCurrentRxQueue    = lpCommProp->dwMaxRxQueue;
2020
2021     return TRUE;
2022 }
2023
2024 /***********************************************************************
2025  * FIXME:
2026  * The functionality of CommConfigDialogA, GetDefaultCommConfig and
2027  * SetDefaultCommConfig is implemented in a DLL (usually SERIALUI.DLL).
2028  * This is dependent on the type of COMM port, but since it is doubtful
2029  * anybody will get around to implementing support for fancy serial
2030  * ports in WINE, this is hardcoded for the time being.  The name of
2031  * this DLL should be stored in and read from the system registry in
2032  * the hive HKEY_LOCAL_MACHINE, key
2033  * System\\CurrentControlSet\\Services\\Class\\Ports\\????
2034  * where ???? is the port number... that is determined by PNP
2035  * The DLL should be loaded when the COMM port is opened, and closed
2036  * when the COMM port is closed. - MJM 20 June 2000
2037  ***********************************************************************/
2038 static CHAR lpszSerialUI[] = "serialui.dll";
2039
2040
2041 /***********************************************************************
2042  *           CommConfigDialogA   (KERNEL32.@)
2043  *
2044  * Raises a dialog that allows the user to configure a comm port.
2045  * Fills the COMMCONFIG struct with information specified by the user.
2046  * This function should call a similar routine in the COMM driver...
2047  *
2048  * RETURNS
2049  *
2050  *  TRUE on success, FALSE on failure
2051  *  If successful, the lpCommConfig structure will contain a new
2052  *  configuration for the comm port, as specified by the user.
2053  *
2054  * BUGS
2055  *  The library with the CommConfigDialog code is never unloaded.
2056  * Perhaps this should be done when the comm port is closed?
2057  */
2058 BOOL WINAPI CommConfigDialogA(
2059     LPCSTR lpszDevice,         /* [in] name of communications device */
2060     HANDLE hWnd,               /* [in] parent window for the dialog */
2061     LPCOMMCONFIG lpCommConfig) /* [out] pointer to struct to fill */
2062 {
2063     FARPROC lpfnCommDialog;
2064     HMODULE hConfigModule;
2065     BOOL r;
2066
2067     TRACE("(%p %p %p)\n",lpszDevice, hWnd, lpCommConfig);
2068
2069     hConfigModule = LoadLibraryA(lpszSerialUI);
2070     if(!hConfigModule)
2071         return FALSE;
2072
2073     lpfnCommDialog = GetProcAddress(hConfigModule, (LPCSTR)3L);
2074
2075     if(!lpfnCommDialog)
2076         return FALSE;
2077
2078     r = lpfnCommDialog(lpszDevice,hWnd,lpCommConfig);
2079
2080     /* UnloadLibrary(hConfigModule); */
2081
2082     return r;
2083 }
2084
2085 /***********************************************************************
2086  *           CommConfigDialogW   (KERNEL32.@)
2087  *
2088  * see CommConfigDialogA for more info
2089  */
2090 BOOL WINAPI CommConfigDialogW(
2091     LPCWSTR lpszDevice,        /* [in] name of communications device */
2092     HANDLE hWnd,               /* [in] parent window for the dialog */
2093     LPCOMMCONFIG lpCommConfig) /* [out] pointer to struct to fill */
2094 {
2095     BOOL r;
2096     LPSTR lpDeviceA;
2097
2098     lpDeviceA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpszDevice );
2099     if(lpDeviceA)
2100         return FALSE;
2101     r = CommConfigDialogA(lpDeviceA,hWnd,lpCommConfig);
2102     HeapFree( GetProcessHeap(), 0, lpDeviceA );
2103     return r;
2104 }
2105
2106 /***********************************************************************
2107  *           GetCommConfig     (KERNEL32.@)
2108  *
2109  * Fill in the COMMCONFIG structure for the comm port hFile
2110  *
2111  * RETURNS
2112  *
2113  *  TRUE on success, FALSE on failure
2114  *  If successful, lpCommConfig contains the comm port configuration.
2115  *
2116  * BUGS
2117  *
2118  */
2119 BOOL WINAPI GetCommConfig(
2120     HANDLE       hFile,        /* [in] The communications device. */
2121     LPCOMMCONFIG lpCommConfig, /* [out] The communications configuration of the device (if it fits). */
2122     LPDWORD      lpdwSize)     /* [in/out] Initially the size of the configuration buffer/structure,
2123                                   afterwards the number of bytes copied to the buffer or
2124                                   the needed size of the buffer. */
2125 {
2126     BOOL r;
2127
2128     TRACE("(%p %p)\n",hFile,lpCommConfig);
2129
2130     if(lpCommConfig == NULL)
2131         return FALSE;
2132     r = *lpdwSize < sizeof(COMMCONFIG); /* TRUE if not enough space */
2133     *lpdwSize = sizeof(COMMCONFIG);
2134     if(r)
2135         return FALSE;
2136
2137     lpCommConfig->dwSize = sizeof(COMMCONFIG);
2138     lpCommConfig->wVersion = 1;
2139     lpCommConfig->wReserved = 0;
2140     r = GetCommState(hFile,&lpCommConfig->dcb);
2141     lpCommConfig->dwProviderSubType = PST_RS232;
2142     lpCommConfig->dwProviderOffset = 0;
2143     lpCommConfig->dwProviderSize = 0;
2144
2145     return r;
2146 }
2147
2148 /***********************************************************************
2149  *           SetCommConfig     (KERNEL32.@)
2150  *
2151  *  Sets the configuration of the communications device.
2152  *
2153  * RETURNS
2154  *
2155  *  True on success, false if the handle was bad is not a communications device.
2156  */
2157 BOOL WINAPI SetCommConfig(
2158     HANDLE       hFile,         /* [in] The communications device. */
2159     LPCOMMCONFIG lpCommConfig,  /* [in] The desired configuration. */
2160     DWORD dwSize)               /* [in] size of the lpCommConfig struct */
2161 {
2162     TRACE("(%p %p)\n",hFile,lpCommConfig);
2163     return SetCommState(hFile,&lpCommConfig->dcb);
2164 }
2165
2166 /***********************************************************************
2167  *           SetDefaultCommConfigA   (KERNEL32.@)
2168  *
2169  *  Initializes the default configuration for the specified communication
2170  *  device. (ascii)
2171  *
2172  * RETURNS
2173  *
2174  *  True if the device was found and the defaults set, false otherwise
2175  */
2176 BOOL WINAPI SetDefaultCommConfigA(
2177     LPCSTR       lpszDevice,   /* [in] The ascii name of the device targeted for configuration. */
2178     LPCOMMCONFIG lpCommConfig, /* [in] The default configuration for the device. */
2179     DWORD        dwSize)       /* [in] The number of bytes in the configuration structure. */
2180 {
2181     FARPROC lpfnSetDefaultCommConfig;
2182     HMODULE hConfigModule;
2183     BOOL r;
2184
2185     TRACE("(%p %p %lx)\n",lpszDevice, lpCommConfig, dwSize);
2186
2187     hConfigModule = LoadLibraryA(lpszSerialUI);
2188     if(!hConfigModule)
2189         return FALSE;
2190
2191     lpfnSetDefaultCommConfig = GetProcAddress(hConfigModule, (LPCSTR)4L);
2192
2193     if(! lpfnSetDefaultCommConfig)
2194         return TRUE;
2195
2196     r = lpfnSetDefaultCommConfig(lpszDevice, lpCommConfig, dwSize);
2197
2198     /* UnloadLibrary(hConfigModule); */
2199
2200     return r;
2201 }
2202
2203
2204 /***********************************************************************
2205  *           SetDefaultCommConfigW     (KERNEL32.@)
2206  *
2207  *  Initializes the default configuration for the specified
2208  *  communication device. (unicode)
2209  *
2210  * RETURNS
2211  *
2212  */
2213 BOOL WINAPI SetDefaultCommConfigW(
2214     LPCWSTR      lpszDevice,   /* [in] The unicode name of the device targeted for configuration. */
2215     LPCOMMCONFIG lpCommConfig, /* [in] The default configuration for the device. */
2216     DWORD        dwSize)       /* [in] The number of bytes in the configuration structure. */
2217 {
2218     BOOL r;
2219     LPSTR lpDeviceA;
2220
2221     TRACE("(%s %p %lx)\n",debugstr_w(lpszDevice),lpCommConfig,dwSize);
2222
2223     lpDeviceA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpszDevice );
2224     if(lpDeviceA)
2225         return FALSE;
2226     r = SetDefaultCommConfigA(lpDeviceA,lpCommConfig,dwSize);
2227     HeapFree( GetProcessHeap(), 0, lpDeviceA );
2228     return r;
2229 }
2230
2231
2232 /***********************************************************************
2233  *           GetDefaultCommConfigW   (KERNEL32.@)
2234  *
2235  *   Acquires the default configuration of the specified communication device. (unicode)
2236  *
2237  *  RETURNS
2238  *
2239  *   True on successful reading of the default configuration,
2240  *   if the device is not found or the buffer is too small.
2241  */
2242 BOOL WINAPI GetDefaultCommConfigW(
2243     LPCWSTR      lpszName, /* [in] The unicode name of the device targeted for configuration. */
2244     LPCOMMCONFIG lpCC,     /* [out] The default configuration for the device. */
2245     LPDWORD      lpdwSize) /* [in/out] Initially the size of the default configuration buffer,
2246                               afterwards the number of bytes copied to the buffer or
2247                               the needed size of the buffer. */
2248 {
2249      LPDCB lpdcb = &(lpCC->dcb);
2250      WCHAR temp[40];
2251      const WCHAR comW[] = {'C','O','M',0};
2252      const WCHAR formatW[] = {'C','O','M','%','c',':','3','8','4','0','0',',','n',',','8',',','1',0};
2253
2254      if (strncmpiW(lpszName,comW,3)) {
2255         ERR("not implemented for <%s>\n", debugstr_w(lpszName));
2256         return FALSE;
2257      }
2258
2259      TRACE("(%s %p %ld)\n", debugstr_w(lpszName), lpCC, *lpdwSize );
2260      if (*lpdwSize < sizeof(COMMCONFIG)) {
2261          *lpdwSize = sizeof(COMMCONFIG);
2262          return FALSE;
2263        }
2264
2265      *lpdwSize = sizeof(COMMCONFIG);
2266
2267      lpCC->dwSize = sizeof(COMMCONFIG);
2268      lpCC->wVersion = 1;
2269      lpCC->dwProviderSubType = PST_RS232;
2270      lpCC->dwProviderOffset = 0L;
2271      lpCC->dwProviderSize = 0L;
2272
2273      sprintfW( temp, formatW, lpszName[3]);
2274      FIXME("setting %s as default\n", debugstr_w(temp));
2275
2276      return BuildCommDCBW( temp, lpdcb);
2277 }
2278
2279 /**************************************************************************
2280  *         GetDefaultCommConfigA                (KERNEL32.@)
2281  *
2282  *   Acquires the default configuration of the specified communication device. (ascii)
2283  *
2284  *  RETURNS
2285  *
2286  *   True on successful reading of the default configuration,
2287  *   if the device is not found or the buffer is too small.
2288  */
2289 BOOL WINAPI GetDefaultCommConfigA(
2290     LPCSTR       lpszName, /* [in] The ascii name of the device targeted for configuration. */
2291     LPCOMMCONFIG lpCC,     /* [out] The default configuration for the device. */
2292     LPDWORD      lpdwSize) /* [in/out] Initially the size of the default configuration buffer,
2293                               afterwards the number of bytes copied to the buffer or
2294                               the needed size of the buffer. */
2295 {
2296         BOOL ret = FALSE;
2297         UNICODE_STRING lpszNameW;
2298
2299         TRACE("(%s,%p,%ld)\n",lpszName,lpCC,*lpdwSize);
2300         if(lpszName) RtlCreateUnicodeStringFromAsciiz(&lpszNameW,lpszName);
2301         else lpszNameW.Buffer = NULL;
2302
2303         if(lpszNameW.Buffer) ret = GetDefaultCommConfigW(lpszNameW.Buffer,lpCC,lpdwSize);
2304
2305         RtlFreeUnicodeString(&lpszNameW);
2306         return ret;
2307 }