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