BuildCommDCB16 had a rather broken baud rate handling.
[wine] / dlls / kernel / comm.c
1 /*
2  * DEC 93 Erik Bos <erik@xs4all.nl>
3  *
4  * Copyright 1996 Marcus Meissner
5  *
6  * Mar 31, 1999. Ove Kåven <ovek@arcticnet.no>
7  * - Implemented buffers and EnableCommNotification.
8  *
9  * Apr 3, 1999.  Lawson Whitney <lawson_whitney@juno.com>
10  * - Fixed the modem control part of EscapeCommFunction16.
11  *
12  * Mar 3, 1999. Ove Kåven <ovek@arcticnet.no>
13  * - Use port indices instead of unixfds for win16
14  * - Moved things around (separated win16 and win32 routines)
15  * - Added some hints on how to implement buffers and EnableCommNotification.
16  *
17  * May 26, 1997.  Fixes and comments by Rick Richardson <rick@dgii.com> [RER]
18  * - ptr->fd wasn't getting cleared on close.
19  * - GetCommEventMask() and GetCommError() didn't do much of anything.
20  *   IMHO, they are still wrong, but they at least implement the RXCHAR
21  *   event and return I/O queue sizes, which makes the app I'm interested
22  *   in (analog devices EZKIT DSP development system) work.
23  *
24  * August 12, 1997.  Take a bash at SetCommEventMask - Lawson Whitney
25  *                                     <lawson_whitney@juno.com>
26  * July 6, 1998. Fixes and comments by Valentijn Sessink
27  *                                     <vsessink@ic.uva.nl> [V]
28  * Oktober 98, Rein Klazes [RHK]
29  * A program that wants to monitor the modem status line (RLSD/DCD) may
30  * poll the modem status register in the commMask structure. I update the bit
31  * in GetCommError, waiting for an implementation of communication events.
32  * 
33  */
34
35 #include "config.h"
36
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <termios.h>
40 #include <fcntl.h>
41 #include <string.h>
42 #ifdef HAVE_STRINGS_H
43 # include <strings.h>
44 #endif
45 #include <errno.h>
46 #include <ctype.h>
47 #include <sys/stat.h>
48 #ifdef HAVE_SYS_FILIO_H
49 # include <sys/filio.h>
50 #endif
51 #include <sys/ioctl.h>
52 #include <unistd.h>
53
54 #include "windef.h"
55 #ifdef HAVE_SYS_MODEM_H
56 # include <sys/modem.h>
57 #endif
58 #ifdef HAVE_SYS_STRTIO_H
59 # include <sys/strtio.h>
60 #endif
61 #include "heap.h"
62 #include "options.h"
63 #include "wine/port.h"
64 #include "server.h"
65 #include "winerror.h"
66 #include "services.h"
67 #include "callback.h"
68 #include "file.h"
69
70 #include "debugtools.h"
71
72 DEFAULT_DEBUG_CHANNEL(comm);
73
74 #if !defined(TIOCINQ) && defined(FIONREAD)
75 #define TIOCINQ FIONREAD
76 #endif
77
78 /* window's semi documented modem status register */
79 #define COMM_MSR_OFFSET  35
80 #define MSR_CTS  0x10
81 #define MSR_DSR  0x20
82 #define MSR_RI   0x40
83 #define MSR_RLSD 0x80
84 #define MSR_MASK (MSR_CTS|MSR_DSR|MSR_RI|MSR_RLSD)
85
86 #define FLAG_LPT 0x80
87
88 #ifdef linux
89 #define CMSPAR 0x40000000 /* stick parity */
90 #endif
91
92 #define MAX_PORTS   9
93
94 struct DosDeviceStruct {
95     char *devicename;   /* /dev/ttyS0 */
96     int fd;
97     int suspended;
98     int unget,xmit;
99     int baudrate;
100     int evtchar;
101     /* events */
102     int commerror, eventmask;
103     /* buffers */
104     char *inbuf,*outbuf;
105     unsigned ibuf_size,ibuf_head,ibuf_tail;
106     unsigned obuf_size,obuf_head,obuf_tail;
107     /* notifications */
108     int wnd, n_read, n_write;
109     HANDLE s_read, s_write;
110 };
111
112
113 static struct DosDeviceStruct COM[MAX_PORTS];
114 static struct DosDeviceStruct LPT[MAX_PORTS];
115 /* pointers to unknown(==undocumented) comm structure */ 
116 static LPCVOID *unknown[MAX_PORTS];
117 /* save terminal states */
118 static struct termios m_stat[MAX_PORTS];
119
120 /* update window's semi documented modem status register */
121 /* see knowledge base Q101417 */
122 static void COMM_MSRUpdate( UCHAR * pMsr, unsigned int mstat)
123 {
124     UCHAR tmpmsr=0;
125 #ifdef TIOCM_CTS
126     if(mstat & TIOCM_CTS) tmpmsr |= MSR_CTS;
127 #endif
128 #ifdef TIOCM_DSR
129     if(mstat & TIOCM_DSR) tmpmsr |= MSR_DSR;
130 #endif
131 #ifdef TIOCM_RI
132     if(mstat & TIOCM_RI)  tmpmsr |= MSR_RI;
133 #endif
134 #ifdef TIOCM_CAR
135     if(mstat & TIOCM_CAR) tmpmsr |= MSR_RLSD;
136 #endif
137     *pMsr = (*pMsr & ~MSR_MASK) | tmpmsr;
138 }
139
140 void COMM_Init(void)
141 {
142         int x;
143         char option[10], temp[256], *btemp;
144         struct stat st;
145
146         for (x=0; x!=MAX_PORTS; x++) {
147                 strcpy(option,"COMx");
148                 option[3] = '1' + x;
149                 option[4] = '\0';
150
151                 PROFILE_GetWineIniString( "serialports", option, "*",
152                                           temp, sizeof(temp) );
153                 if (!strcmp(temp, "*") || *temp == '\0') 
154                         COM[x].devicename = NULL;
155                 else {
156                         btemp = strchr(temp,',');
157                         if (btemp != NULL) {
158                                 *btemp++ = '\0';
159                                 COM[x].baudrate = atoi(btemp);
160                         } else {
161                                 COM[x].baudrate = -1;
162                         }
163                         stat(temp, &st);
164                         if (!S_ISCHR(st.st_mode)) 
165                                 WARN("Can't use `%s' as %s !\n", temp, option);
166                         else
167                                 if ((COM[x].devicename = malloc(strlen(temp)+1)) == NULL) 
168                                         WARN("Can't malloc for device info!\n");
169                                 else {
170                                         COM[x].fd = 0;
171                                         strcpy(COM[x].devicename, temp);
172                                 }
173                 TRACE("%s = %s\n", option, COM[x].devicename);
174                 }
175
176                 strcpy(option, "LPTx");
177                 option[3] = '1' + x;
178                 option[4] = '\0';
179
180                 PROFILE_GetWineIniString( "parallelports", option, "*",
181                                           temp, sizeof(temp) );
182                 if (!strcmp(temp, "*") || *temp == '\0')
183                         LPT[x].devicename = NULL;
184                 else {
185                         stat(temp, &st);
186                         if (!S_ISCHR(st.st_mode)) 
187                                 WARN("Can't use `%s' as %s !\n", temp, option);
188                         else 
189                                 if ((LPT[x].devicename = malloc(strlen(temp)+1)) == NULL) 
190                                         WARN("Can't malloc for device info!\n");
191                                 else {
192                                         LPT[x].fd = 0;
193                                         strcpy(LPT[x].devicename, temp);
194                                 }
195                 TRACE("%s = %s\n", option, LPT[x].devicename);
196                 }
197
198         }
199 }
200
201
202 static struct DosDeviceStruct *GetDeviceStruct(int fd)
203 {
204         if ((fd&0x7F)<=MAX_PORTS) {
205             if (!(fd&FLAG_LPT)) {
206                 if (COM[fd].fd)
207                     return &COM[fd];
208             } else {
209                 fd &= 0x7f;
210                 if (LPT[fd].fd)
211                     return &LPT[fd];
212             }
213         }
214
215         return NULL;
216 }
217
218 static int    GetCommPort_fd(int fd)
219 {
220         int x;
221         
222         for (x=0; x<MAX_PORTS; x++) {
223              if (COM[x].fd == fd)
224                  return x;
225        }
226        
227        return -1;
228
229
230 static int ValidCOMPort(int x)
231 {
232         return(x < MAX_PORTS ? (int) COM[x].devicename : 0); 
233 }
234
235 static int ValidLPTPort(int x)
236 {
237         return(x < MAX_PORTS ? (int) LPT[x].devicename : 0); 
238 }
239
240 static int WinError(void)
241 {
242         TRACE("errno = %d\n", errno);
243         switch (errno) {
244                 default:
245                         return CE_IOE;
246                 }
247 }
248
249 static unsigned comm_inbuf(struct DosDeviceStruct *ptr)
250 {
251   return ((ptr->ibuf_tail > ptr->ibuf_head) ? ptr->ibuf_size : 0)
252     + ptr->ibuf_head - ptr->ibuf_tail;
253 }
254
255 static unsigned comm_outbuf(struct DosDeviceStruct *ptr)
256 {
257   return ((ptr->obuf_tail > ptr->obuf_head) ? ptr->obuf_size : 0)
258     + ptr->obuf_head - ptr->obuf_tail;
259 }
260
261 static int COMM_WhackModem(int fd, unsigned int andy, unsigned int orrie)
262 {
263     unsigned int mstat, okay;
264     okay = ioctl(fd, TIOCMGET, &mstat);
265     if (okay) return okay;
266     if (andy) mstat &= andy;
267     mstat |= orrie;
268     return ioctl(fd, TIOCMSET, &mstat);
269 }
270         
271 static void CALLBACK comm_notification( ULONG_PTR private )
272 {
273   struct DosDeviceStruct *ptr = (struct DosDeviceStruct *)private;
274   int prev, bleft, len;
275   WORD mask = 0;
276   int cid = GetCommPort_fd(ptr->fd);
277
278   TRACE("async notification\n");
279   /* read data from comm port */
280   prev = comm_inbuf(ptr);
281   do {
282     bleft = ((ptr->ibuf_tail > ptr->ibuf_head) ? (ptr->ibuf_tail-1) : ptr->ibuf_size)
283       - ptr->ibuf_head;
284     len = read(ptr->fd, ptr->inbuf + ptr->ibuf_head, bleft?bleft:1);
285     if (len > 0) {
286       if (!bleft) {
287         ptr->commerror = CE_RXOVER;
288       } else {
289         /* check for events */
290         if ((ptr->eventmask & EV_RXFLAG) &&
291             memchr(ptr->inbuf + ptr->ibuf_head, ptr->evtchar, len)) {
292           *(WORD*)(unknown[cid]) |= EV_RXFLAG;
293           mask |= CN_EVENT;
294         }
295         if (ptr->eventmask & EV_RXCHAR) {
296           *(WORD*)(unknown[cid]) |= EV_RXCHAR;
297           mask |= CN_EVENT;
298         }
299         /* advance buffer position */
300         ptr->ibuf_head += len;
301         if (ptr->ibuf_head >= ptr->ibuf_size)
302           ptr->ibuf_head = 0;
303       }
304     }
305   } while (len > 0);
306   /* check for notification */
307   if (ptr->wnd && (ptr->n_read>0) && (prev<ptr->n_read) &&
308       (comm_inbuf(ptr)>=ptr->n_read)) {
309     /* passed the receive notification threshold */
310     mask |= CN_RECEIVE;
311   }
312
313   /* write any TransmitCommChar character */
314   if (ptr->xmit>=0) {
315     len = write(ptr->fd, &(ptr->xmit), 1);
316     if (len > 0) ptr->xmit = -1;
317   }
318   /* write from output queue */
319   prev = comm_outbuf(ptr);
320   do {
321     bleft = ((ptr->obuf_tail <= ptr->obuf_head) ? ptr->obuf_head : ptr->obuf_size)
322       - ptr->obuf_tail;
323     len = bleft ? write(ptr->fd, ptr->outbuf + ptr->obuf_tail, bleft) : 0;
324     if (len > 0) {
325       ptr->obuf_tail += len;
326       if (ptr->obuf_tail >= ptr->obuf_size)
327         ptr->obuf_tail = 0;
328       /* flag event */
329       if (ptr->obuf_tail == ptr->obuf_head) {
330         if (ptr->s_write) {
331           SERVICE_Delete( ptr->s_write );
332           ptr->s_write = INVALID_HANDLE_VALUE;
333         }
334         if (ptr->eventmask & EV_TXEMPTY) {
335           *(WORD*)(unknown[cid]) |= EV_TXEMPTY;
336           mask |= CN_EVENT;
337         }
338       }
339     }
340   } while (len > 0);
341   /* check for notification */
342   if (ptr->wnd && (ptr->n_write>0) && (prev>=ptr->n_write) &&
343       (comm_outbuf(ptr)<ptr->n_write)) {
344     /* passed the transmit notification threshold */
345     mask |= CN_TRANSMIT;
346   }
347
348   /* send notifications, if any */
349   if (ptr->wnd && mask) {
350     TRACE("notifying %04x: cid=%d, mask=%02x\n", ptr->wnd, cid, mask);
351     if (Callout.PostMessageA) Callout.PostMessageA(ptr->wnd, WM_COMMNOTIFY, cid, mask);
352   }
353 }
354
355 static void comm_waitread(struct DosDeviceStruct *ptr)
356 {
357   if (ptr->s_read != INVALID_HANDLE_VALUE) return;
358   ptr->s_read = SERVICE_AddObject( FILE_DupUnixHandle( ptr->fd,
359                                      GENERIC_READ | SYNCHRONIZE ),
360                                     comm_notification,
361                                     (ULONG_PTR)ptr );
362 }
363
364 static void comm_waitwrite(struct DosDeviceStruct *ptr)
365 {
366   if (ptr->s_write != INVALID_HANDLE_VALUE) return;
367   ptr->s_write = SERVICE_AddObject( FILE_DupUnixHandle( ptr->fd,
368                                       GENERIC_WRITE | SYNCHRONIZE ),
369                                      comm_notification,
370                                      (ULONG_PTR)ptr );
371 }
372
373 /**************************************************************************
374  *         BuildCommDCB16               (USER.213)
375  *
376  * According to the ECMA-234 (368.3) the function will return FALSE on 
377  * success, otherwise it will return -1. 
378  * IF THIS IS NOT CORRECT THE RETURNVALUE CHECK IN BuildCommDCBAndTimeoutsA
379  * NEEDS TO BE FIXED
380  */
381 BOOL16 WINAPI BuildCommDCB16(LPCSTR device, LPDCB16 lpdcb)
382 {
383         /* "COM1:96,n,8,1"      */
384         /*  012345              */
385         int port;
386         char *ptr, temp[256];
387
388         TRACE("(%s), ptr %p\n", device, lpdcb);
389
390         if (!strncasecmp(device,"COM",3)) {
391                 port = device[3] - '0';
392         
393
394                 if (port-- == 0) {
395                         ERR("BUG ! COM0 can't exist!\n");
396                         return -1;
397                 }
398
399                 if (!ValidCOMPort(port)) {
400                         FIXME("invalid COM port %d?\n",port);
401                         return -1;
402                 }
403                 
404                 memset(lpdcb, 0, sizeof(DCB16)); /* initialize */
405
406                 lpdcb->Id = port;
407                 
408                 if (!*(device+4))
409                         return 0;
410
411                 if (*(device+4) != ':')
412                         return -1;
413                 
414                 strcpy(temp,device+5);
415                 ptr = strtok(temp, ", "); 
416
417                 if (COM[port].baudrate > 0)
418                         lpdcb->BaudRate = COM[port].baudrate;
419                 else
420                 {
421                         int rate;
422                         /* DOS/Windows only compares the first two numbers
423                          * and assigns an appropriate baud rate.
424                          * You can supply 961324245, it still returns 9600 ! */
425                         if (strlen(ptr) < 2)
426                         {
427                             WARN("Unknown baudrate string '%s' !\n", ptr);
428                             return -1; /* error: less than 2 chars */
429                         }
430                         ptr[2] = '\0';
431                         rate = atoi(ptr);
432
433                         switch (rate) {
434                                 case 11:
435                                 case 30:
436                                 case 60:
437                                         rate *= 10;
438                                         break;
439                                 case 12:
440                                 case 24:
441                                 case 48:
442                                 case 96:
443                                         rate *= 100;
444                                         break;
445                                 case 19:
446                                         rate = 19200;
447                                         break;
448                                 default:
449                                         WARN("Unknown baudrate indicator %d !\n", rate);
450                                         return -1;
451                         }
452                         
453                         lpdcb->BaudRate = rate;
454                 }
455                 TRACE("baudrate (%d)\n", lpdcb->BaudRate);
456
457                 ptr = strtok(NULL, ", ");
458                 if (islower(*ptr))
459                         *ptr = toupper(*ptr);
460
461                 TRACE("parity (%c)\n", *ptr);
462                 lpdcb->fParity = TRUE;
463                 switch (*ptr) {
464                         case 'N':
465                                 lpdcb->Parity = NOPARITY;
466                                 lpdcb->fParity = FALSE;
467                                 break;                  
468                         case 'E':
469                                 lpdcb->Parity = EVENPARITY;
470                                 break;                  
471                         case 'M':
472                                 lpdcb->Parity = MARKPARITY;
473                                 break;                  
474                         case 'O':
475                                 lpdcb->Parity = ODDPARITY;
476                                 break;                  
477                         default:
478                                 WARN("Unknown parity `%c'!\n", *ptr);
479                                 return -1;
480                 }
481
482                 ptr = strtok(NULL, ", "); 
483                 TRACE("charsize (%c)\n", *ptr);
484                 lpdcb->ByteSize = *ptr - '0';
485
486                 ptr = strtok(NULL, ", ");
487                 TRACE("stopbits (%c)\n", *ptr);
488                 switch (*ptr) {
489                         case '1':
490                                 lpdcb->StopBits = ONESTOPBIT;
491                                 break;                  
492                         case '2':
493                                 lpdcb->StopBits = TWOSTOPBITS;
494                                 break;                  
495                         default:
496                                 WARN("Unknown # of stopbits `%c'!\n", *ptr);
497                                 return -1;
498                 }
499         }       
500
501         return 0;
502 }
503
504 /*****************************************************************************
505  *      OpenComm16              (USER.200)
506  */
507 INT16 WINAPI OpenComm16(LPCSTR device,UINT16 cbInQueue,UINT16 cbOutQueue)
508 {
509         int port,fd;
510
511         TRACE("%s, %d, %d\n", device, cbInQueue, cbOutQueue);
512
513         if (strlen(device) < 4)
514            return IE_BADID;
515
516         port = device[3] - '0';
517
518         if (port-- == 0)
519                 ERR("BUG ! COM0 or LPT0 don't exist !\n");
520
521         if (!strncasecmp(device,"COM",3)) {
522                 
523                 TRACE("%s = %s\n", device, COM[port].devicename);
524
525                 if (!ValidCOMPort(port))
526                         return IE_BADID;
527
528                 if (COM[port].fd)
529                         return IE_OPEN;
530
531                 fd = open(COM[port].devicename, O_RDWR | O_NONBLOCK);
532                 if (fd == -1) {
533                         ERR("Couldn't open %s ! (%s)\n", COM[port].devicename, strerror(errno));
534                         return IE_HARDWARE;
535                 } else {
536                         unknown[port] = SEGPTR_ALLOC(40);
537                         bzero(unknown[port],40);
538                         COM[port].fd = fd;
539                         COM[port].commerror = 0;
540                         COM[port].eventmask = 0;
541                         COM[port].evtchar = 0; /* FIXME: default? */
542                         /* save terminal state */
543                         tcgetattr(fd,&m_stat[port]);
544                         /* set default parameters */
545                         if(COM[port].baudrate>-1){
546                             DCB16 dcb;
547                             GetCommState16(port, &dcb);
548                             dcb.BaudRate=COM[port].baudrate;
549                             /* more defaults:
550                              * databits, parity, stopbits
551                              */
552                             SetCommState16( &dcb);
553                         }
554                         /* init priority characters */
555                         COM[port].unget = -1;
556                         COM[port].xmit = -1;
557                         /* allocate buffers */
558                         COM[port].ibuf_size = cbInQueue;
559                         COM[port].ibuf_head = COM[port].ibuf_tail = 0;
560                         COM[port].obuf_size = cbOutQueue;
561                         COM[port].obuf_head = COM[port].obuf_tail = 0;
562
563                         COM[port].inbuf = malloc(cbInQueue);
564                         if (COM[port].inbuf) {
565                           COM[port].outbuf = malloc(cbOutQueue);
566                           if (!COM[port].outbuf)
567                             free(COM[port].inbuf);
568                         } else COM[port].outbuf = NULL;
569                         if (!COM[port].outbuf) {
570                           /* not enough memory */
571                           tcsetattr(COM[port].fd,TCSANOW,&m_stat[port]);
572                           close(COM[port].fd);
573                           ERR("out of memory\n");
574                           return IE_MEMORY;
575                         }
576
577                         COM[port].s_read = INVALID_HANDLE_VALUE;
578                         COM[port].s_write = INVALID_HANDLE_VALUE;
579                         comm_waitread( &COM[port] );
580                         return port;
581                 }
582         } 
583         else 
584         if (!strncasecmp(device,"LPT",3)) {
585         
586                 if (!ValidLPTPort(port))
587                         return IE_BADID;
588
589                 if (LPT[port].fd)
590                         return IE_OPEN;
591
592                 fd = open(LPT[port].devicename, O_RDWR | O_NONBLOCK, 0);
593                 if (fd == -1) {
594                         return IE_HARDWARE;
595                 } else {
596                         LPT[port].fd = fd;
597                         LPT[port].commerror = 0;
598                         LPT[port].eventmask = 0;
599                         return port|FLAG_LPT;
600                 }
601         }
602         return 0;
603 }
604
605 /*****************************************************************************
606  *      CloseComm16             (USER.207)
607  */
608 INT16 WINAPI CloseComm16(INT16 cid)
609 {
610         struct DosDeviceStruct *ptr;
611         
612         TRACE("cid=%d\n", cid);
613         if ((ptr = GetDeviceStruct(cid)) == NULL) {
614                 FIXME("no cid=%d found!\n", cid);
615                 return -1;
616         }
617         if (!(cid&FLAG_LPT)) {
618                 /* COM port */
619                 SEGPTR_FREE(unknown[cid]); /* [LW] */
620
621                 SERVICE_Delete( COM[cid].s_write );
622                 SERVICE_Delete( COM[cid].s_read );
623                 /* free buffers */
624                 free(ptr->outbuf);
625                 free(ptr->inbuf);
626
627                 /* reset modem lines */
628                 tcsetattr(ptr->fd,TCSANOW,&m_stat[cid]);
629         }
630
631         if (close(ptr->fd) == -1) {
632                 ptr->commerror = WinError();
633                 /* FIXME: should we clear ptr->fd here? */
634                 return -1;
635         } else {
636                 ptr->commerror = 0;
637                 ptr->fd = 0;
638                 return 0;
639         }
640 }
641
642 /*****************************************************************************
643  *      SetCommBreak16          (USER.210)
644  */
645 INT16 WINAPI SetCommBreak16(INT16 cid)
646 {
647         struct DosDeviceStruct *ptr;
648
649         TRACE("cid=%d\n", cid);
650         if ((ptr = GetDeviceStruct(cid)) == NULL) {
651                 FIXME("no cid=%d found!\n", cid);
652                 return -1;
653         }
654
655         ptr->suspended = 1;
656         ptr->commerror = 0;
657         return 0;
658 }
659
660 /*****************************************************************************
661  *      ClearCommBreak16        (USER.211)
662  */
663 INT16 WINAPI ClearCommBreak16(INT16 cid)
664 {
665         struct DosDeviceStruct *ptr;
666
667         TRACE("cid=%d\n", cid);
668         if (!(ptr = GetDeviceStruct(cid))) {
669                 FIXME("no cid=%d found!\n", cid);
670                 return -1;
671         }
672         ptr->suspended = 0;
673         ptr->commerror = 0;
674         return 0;
675 }
676
677 /*****************************************************************************
678  *      EscapeCommFunction16    (USER.214)
679  */
680 LONG WINAPI EscapeCommFunction16(UINT16 cid,UINT16 nFunction)
681 {
682         int     max;
683         struct DosDeviceStruct *ptr;
684         struct termios port;
685
686         TRACE("cid=%d, function=%d\n", cid, nFunction);
687         if ((nFunction != GETMAXCOM) && (nFunction != GETMAXLPT)) {
688                 if ((ptr = GetDeviceStruct(cid)) == NULL) {
689                         FIXME("no cid=%d found!\n", cid);
690                         return -1;
691                 }
692                 if (tcgetattr(ptr->fd,&port) == -1) {
693                         TRACE("tcgetattr failed\n");
694                         ptr->commerror=WinError();      
695                         return -1;
696                 }
697         } else ptr = NULL;
698
699         switch (nFunction) {
700                 case RESETDEV:
701                         TRACE("RESETDEV\n");
702                         break;                                  
703
704                 case GETMAXCOM:
705                         TRACE("GETMAXCOM\n"); 
706                         for (max = MAX_PORTS;!COM[max].devicename;max--)
707                                 ;
708                         return max;
709                         break;
710
711                 case GETMAXLPT:
712                         TRACE("GETMAXLPT\n"); 
713                         for (max = MAX_PORTS;!LPT[max].devicename;max--)
714                                 ;
715                         return FLAG_LPT + max;
716                         break;
717
718                 case GETBASEIRQ:
719                         TRACE("GETBASEIRQ\n"); 
720                         /* FIXME: use tables */
721                         /* just fake something for now */
722                         if (cid & FLAG_LPT) {
723                                 /* LPT1: irq 7, LPT2: irq 5 */
724                                 return (cid & 0x7f) ? 5 : 7;
725                         } else {
726                                 /* COM1: irq 4, COM2: irq 3,
727                                    COM3: irq 4, COM4: irq 3 */
728                                 return 4 - (cid & 1);
729                         }
730                         break;
731
732                 case CLRDTR:
733                         TRACE("CLRDTR\n"); 
734 #ifdef TIOCM_DTR
735                         return COMM_WhackModem(ptr->fd, ~TIOCM_DTR, 0);
736 #endif
737                 case CLRRTS:
738                         TRACE("CLRRTS\n"); 
739 #ifdef TIOCM_RTS
740                         return COMM_WhackModem(ptr->fd, ~TIOCM_RTS, 0);
741 #endif
742         
743                 case SETDTR:
744                         TRACE("SETDTR\n"); 
745 #ifdef TIOCM_DTR
746                         return COMM_WhackModem(ptr->fd, 0, TIOCM_DTR);
747 #endif
748
749                 case SETRTS:
750                         TRACE("SETRTS\n"); 
751 #ifdef TIOCM_RTS                        
752                         return COMM_WhackModem(ptr->fd, 0, TIOCM_RTS);
753 #endif
754
755                 case SETXOFF:
756                         TRACE("SETXOFF\n"); 
757                         port.c_iflag |= IXOFF;
758                         break;
759
760                 case SETXON:
761                         TRACE("SETXON\n"); 
762                         port.c_iflag |= IXON;
763                         break;
764
765                 default:
766                         WARN("(cid=%d,nFunction=%d): Unknown function\n", 
767                         cid, nFunction);
768                         break;                          
769         }
770         
771         if (tcsetattr(ptr->fd, TCSADRAIN, &port) == -1) {
772                 ptr->commerror = WinError();
773                 return -1;      
774         } else {
775                 ptr->commerror = 0;
776                 return 0;
777         }
778 }
779
780 /*****************************************************************************
781  *      FlushComm16     (USER.215)
782  */
783 INT16 WINAPI FlushComm16(INT16 cid,INT16 fnQueue)
784 {
785         int queue;
786         struct DosDeviceStruct *ptr;
787
788         TRACE("cid=%d, queue=%d\n", cid, fnQueue);
789         if ((ptr = GetDeviceStruct(cid)) == NULL) {
790                 FIXME("no cid=%d found!\n", cid);
791                 return -1;
792         }
793         switch (fnQueue) {
794                 case 0:
795                   queue = TCOFLUSH;
796                   ptr->obuf_tail = ptr->obuf_head;
797                   break;
798                 case 1:
799                   queue = TCIFLUSH;
800                   ptr->ibuf_head = ptr->ibuf_tail;
801                   break;
802                 default:
803                   WARN("(cid=%d,fnQueue=%d):Unknown queue\n", 
804                             cid, fnQueue);
805                   return -1;
806                 }
807         if (tcflush(ptr->fd, queue)) {
808                 ptr->commerror = WinError();
809                 return -1;      
810         } else {
811                 ptr->commerror = 0;
812                 return 0;
813         }
814 }  
815
816 /********************************************************************
817  *      GetCommError16  (USER.203)
818  */
819 INT16 WINAPI GetCommError16(INT16 cid,LPCOMSTAT16 lpStat)
820 {
821         int             temperror;
822         struct DosDeviceStruct *ptr;
823         unsigned char *stol;
824         unsigned int mstat;
825
826         if ((ptr = GetDeviceStruct(cid)) == NULL) {
827                 FIXME("no handle for cid = %0x!\n",cid);
828                 return -1;
829         }
830         if (cid&FLAG_LPT) {
831             WARN(" cid %d not comm port\n",cid);
832             return CE_MODE;
833         }
834         stol = (unsigned char *)unknown[cid] + COMM_MSR_OFFSET;
835         ioctl(ptr->fd,TIOCMGET,&mstat);
836         COMM_MSRUpdate( stol, mstat);
837
838         if (lpStat) {
839                 lpStat->status = 0;
840
841                 lpStat->cbOutQue = comm_outbuf(ptr);
842                 lpStat->cbInQue = comm_inbuf(ptr);
843
844                 TRACE("cid %d, error %d, stat %d in %d out %d, stol %x\n",
845                              cid, ptr->commerror, lpStat->status, lpStat->cbInQue, 
846                              lpStat->cbOutQue, *stol);
847         }
848         else
849                 TRACE("cid %d, error %d, lpStat NULL stol %x\n",
850                              cid, ptr->commerror, *stol);
851
852         /* Return any errors and clear it */
853         temperror = ptr->commerror;
854         ptr->commerror = 0;
855         return(temperror);
856 }
857
858 /*****************************************************************************
859  *      SetCommEventMask16      (USER.208)
860  */
861 SEGPTR WINAPI SetCommEventMask16(INT16 cid,UINT16 fuEvtMask)
862 {
863         struct DosDeviceStruct *ptr;
864         unsigned char *stol;
865         int repid;
866         unsigned int mstat;
867
868         TRACE("cid %d,mask %d\n",cid,fuEvtMask);
869         if ((ptr = GetDeviceStruct(cid)) == NULL) {
870                 FIXME("no handle for cid = %0x!\n",cid);
871             return (SEGPTR)NULL;
872         }
873
874         ptr->eventmask = fuEvtMask;
875
876         if ((cid&FLAG_LPT) || !ValidCOMPort(cid)) {
877             WARN(" cid %d not comm port\n",cid);
878             return (SEGPTR)NULL;
879         }
880         /* it's a COM port ? -> modify flags */
881         stol = (unsigned char *)unknown[cid] + COMM_MSR_OFFSET;
882         repid = ioctl(ptr->fd,TIOCMGET,&mstat);
883         TRACE(" ioctl  %d, msr %x at %p %p\n",repid,mstat,stol,unknown[cid]);
884         COMM_MSRUpdate( stol, mstat);
885
886         TRACE(" modem dcd construct %x\n",*stol);
887         return SEGPTR_GET(unknown[cid]);
888 }
889
890 /*****************************************************************************
891  *      GetCommEventMask16      (USER.209)
892  */
893 UINT16 WINAPI GetCommEventMask16(INT16 cid,UINT16 fnEvtClear)
894 {
895         struct DosDeviceStruct *ptr;
896         WORD events;
897
898         TRACE("cid %d, mask %d\n", cid, fnEvtClear);
899         if ((ptr = GetDeviceStruct(cid)) == NULL) {
900                 FIXME("no handle for cid = %0x!\n",cid);
901             return 0;
902         }
903
904         if ((cid&FLAG_LPT) || !ValidCOMPort(cid)) {
905             WARN(" cid %d not comm port\n",cid);
906             return 0;
907         }
908
909         events = *(WORD*)(unknown[cid]) & fnEvtClear;
910         *(WORD*)(unknown[cid]) &= ~fnEvtClear;
911         return events;
912 }
913
914 /*****************************************************************************
915  *      SetCommState16  (USER.201)
916  */
917 INT16 WINAPI SetCommState16(LPDCB16 lpdcb)
918 {
919         struct termios port;
920         struct DosDeviceStruct *ptr;
921         int bytesize, stopbits;
922         int fail=0;
923
924         TRACE("cid %d, ptr %p\n", lpdcb->Id, lpdcb);
925         if ((ptr = GetDeviceStruct(lpdcb->Id)) == NULL) {
926                 FIXME("no handle for cid = %0x!\n",lpdcb->Id);
927                 return -1;
928         }
929         if (tcgetattr(ptr->fd, &port) == -1) {
930                 ptr->commerror = WinError();    
931                 return -1;
932         }
933
934         port.c_cc[VMIN] = 0;
935         port.c_cc[VTIME] = 1;
936
937 #ifdef IMAXBEL
938         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|IMAXBEL);
939 #else
940         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR);
941 #endif
942         port.c_iflag |= (IGNBRK);
943
944         port.c_oflag &= ~(OPOST);
945
946         port.c_cflag &= ~(HUPCL);
947         port.c_cflag |= CLOCAL | CREAD;
948
949         port.c_lflag &= ~(ICANON|ECHO|ISIG);
950         port.c_lflag |= NOFLSH;
951
952         TRACE("baudrate %d\n",lpdcb->BaudRate);
953 #ifdef CBAUD
954         port.c_cflag &= ~CBAUD;
955         switch (lpdcb->BaudRate) {
956                 case 110:
957                 case CBR_110:
958                         port.c_cflag |= B110;
959                         break;          
960                 case 300:
961                 case CBR_300:
962                         port.c_cflag |= B300;
963                         break;          
964                 case 600:
965                 case CBR_600:
966                         port.c_cflag |= B600;
967                         break;          
968                 case 1200:
969                 case CBR_1200:
970                         port.c_cflag |= B1200;
971                         break;          
972                 case 2400:
973                 case CBR_2400:
974                         port.c_cflag |= B2400;
975                         break;          
976                 case 4800:
977                 case CBR_4800:
978                         port.c_cflag |= B4800;
979                         break;          
980                 case 9600:
981                 case CBR_9600:
982                         port.c_cflag |= B9600;
983                         break;          
984                 case 19200:
985                 case CBR_19200:
986                         port.c_cflag |= B19200;
987                         break;          
988                 case 38400:
989                 case CBR_38400:
990                         port.c_cflag |= B38400;
991                         break;          
992 #ifdef B57600
993                 case 57600:
994                         port.c_cflag |= B57600;
995                         break;          
996 #endif
997 #ifdef B115200
998                 case 57601:
999                         port.c_cflag |= B115200;
1000                         break;          
1001 #endif
1002                 default:
1003                         ptr->commerror = IE_BAUDRATE;
1004                         fail=1;
1005         }
1006 #elif !defined(__EMX__)
1007         switch (lpdcb->BaudRate) {
1008                 case 110:
1009                 case CBR_110:
1010                         port.c_ospeed = B110;
1011                         break;
1012                 case 300:
1013                 case CBR_300:
1014                         port.c_ospeed = B300;
1015                         break;
1016                 case 600:
1017                 case CBR_600:
1018                         port.c_ospeed = B600;
1019                         break;
1020                 case 1200:
1021                 case CBR_1200:
1022                         port.c_ospeed = B1200;
1023                         break;
1024                 case 2400:
1025                 case CBR_2400:
1026                         port.c_ospeed = B2400;
1027                         break;
1028                 case 4800:
1029                 case CBR_4800:
1030                         port.c_ospeed = B4800;
1031                         break;
1032                 case 9600:
1033                 case CBR_9600:
1034                         port.c_ospeed = B9600;
1035                         break;
1036                 case 19200:
1037                 case CBR_19200:
1038                         port.c_ospeed = B19200;
1039                         break;
1040                 case 38400:
1041                 case CBR_38400:
1042                         port.c_ospeed = B38400;
1043                         break;
1044                 default:
1045                         ptr->commerror = IE_BAUDRATE;
1046                         fail=1;
1047         }
1048         port.c_ispeed = port.c_ospeed;
1049 #endif
1050         bytesize=lpdcb->ByteSize;
1051         stopbits=lpdcb->StopBits;
1052
1053         TRACE("fParity %d Parity %d\n",lpdcb->fParity, lpdcb->Parity);
1054 #ifdef CMSPAR
1055         port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
1056 #else
1057         port.c_cflag &= ~(PARENB | PARODD);
1058 #endif
1059         if (lpdcb->fParity)
1060             port.c_iflag |= INPCK;
1061         else
1062             port.c_iflag &= ~INPCK;
1063         switch (lpdcb->Parity) {
1064                 case NOPARITY:
1065                         break;
1066                 case ODDPARITY:
1067                         port.c_cflag |= (PARENB | PARODD);
1068                         break;
1069                 case EVENPARITY:
1070                         port.c_cflag |= PARENB;
1071                         break;
1072 #ifdef CMSPAR
1073                 /* Linux defines mark/space (stick) parity */
1074                 case MARKPARITY:
1075                         port.c_cflag |= (PARENB | CMSPAR);
1076                         break;
1077                 case SPACEPARITY:
1078                         port.c_cflag |= (PARENB | PARODD |  CMSPAR);
1079                         break;
1080 #else
1081                 /* try the POSIX way */
1082                 case MARKPARITY:
1083                         if( stopbits == ONESTOPBIT) {
1084                             stopbits = TWOSTOPBITS;
1085                             port.c_iflag &= ~INPCK;
1086                         } else {
1087                             ptr->commerror = IE_BYTESIZE;
1088                             fail=1;
1089                         }
1090                         break;
1091                 case SPACEPARITY:
1092                         if( bytesize < 8) {
1093                             bytesize +=1;
1094                             port.c_iflag &= ~INPCK;
1095                         } else {
1096                             ptr->commerror = IE_BYTESIZE;
1097                             fail=1;
1098                         }
1099                         break;
1100 #endif
1101                 default:
1102                         ptr->commerror = IE_BYTESIZE;
1103                         fail=1;
1104         }
1105         
1106         TRACE("bytesize %d\n",bytesize);
1107         port.c_cflag &= ~CSIZE;
1108         switch (bytesize) {
1109                 case 5:
1110                         port.c_cflag |= CS5;
1111                         break;
1112                 case 6:
1113                         port.c_cflag |= CS6;
1114                         break;
1115                 case 7:
1116                         port.c_cflag |= CS7;
1117                         break;
1118                 case 8:
1119                         port.c_cflag |= CS8;
1120                         break;
1121                 default:
1122                         ptr->commerror = IE_BYTESIZE;
1123                         fail=1;
1124         }
1125
1126         TRACE("stopbits %d\n",stopbits);
1127
1128         switch (stopbits) {
1129                 case ONESTOPBIT:
1130                                 port.c_cflag &= ~CSTOPB;
1131                                 break;
1132                 case ONE5STOPBITS: /* wil be selected if bytesize is 5 */
1133                 case TWOSTOPBITS:
1134                                 port.c_cflag |= CSTOPB;
1135                                 break;
1136                 default:
1137                         ptr->commerror = IE_BYTESIZE;
1138                         fail=1;
1139         }
1140 #ifdef CRTSCTS
1141
1142         if (lpdcb->fDtrflow || lpdcb->fRtsflow || lpdcb->fOutxCtsFlow)
1143                 port.c_cflag |= CRTSCTS;
1144
1145         if (lpdcb->fDtrDisable) 
1146                 port.c_cflag &= ~CRTSCTS;
1147 #endif  
1148         if (lpdcb->fInX)
1149                 port.c_iflag |= IXON;
1150         else
1151                 port.c_iflag &= ~IXON;
1152         if (lpdcb->fOutX)
1153                 port.c_iflag |= IXOFF;
1154         else
1155                 port.c_iflag &= ~IXOFF;
1156
1157         ptr->evtchar = lpdcb->EvtChar;
1158
1159         if(fail)
1160             return -1;
1161         
1162         if (tcsetattr(ptr->fd, TCSADRAIN, &port) == -1) {
1163                 ptr->commerror = WinError();    
1164                 return -1;
1165         } else {
1166                 ptr->commerror = 0;
1167                 return 0;
1168         }
1169 }
1170
1171 /*****************************************************************************
1172  *      GetCommState16  (USER.202)
1173  */
1174 INT16 WINAPI GetCommState16(INT16 cid, LPDCB16 lpdcb)
1175 {
1176         int speed;
1177         struct DosDeviceStruct *ptr;
1178         struct termios port;
1179
1180         TRACE("cid %d, ptr %p\n", cid, lpdcb);
1181         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1182                 FIXME("no handle for cid = %0x!\n",cid);
1183                 return -1;
1184         }
1185         if (tcgetattr(ptr->fd, &port) == -1) {
1186                 ptr->commerror = WinError();    
1187                 return -1;
1188         }
1189         lpdcb->Id = cid;
1190 #ifndef __EMX__
1191 #ifdef CBAUD
1192         speed = port.c_cflag & CBAUD;
1193 #else
1194         speed = port.c_ospeed;
1195 #endif
1196         switch(speed) {
1197                 case B110:
1198                         lpdcb->BaudRate = 110;
1199                         break;
1200                 case B300:
1201                         lpdcb->BaudRate = 300;
1202                         break;
1203                 case B600:
1204                         lpdcb->BaudRate = 600;
1205                         break;
1206                 case B1200:
1207                         lpdcb->BaudRate = 1200;
1208                         break;
1209                 case B2400:
1210                         lpdcb->BaudRate = 2400;
1211                         break;
1212                 case B4800:
1213                         lpdcb->BaudRate = 4800;
1214                         break;
1215                 case B9600:
1216                         lpdcb->BaudRate = 9600;
1217                         break;
1218                 case B19200:
1219                         lpdcb->BaudRate = 19200;
1220                         break;
1221                 case B38400:
1222                         lpdcb->BaudRate = 38400;
1223                         break;
1224 #ifdef B57600
1225                 case B57600:
1226                         lpdcb->BaudRate = 57600;
1227                         break;
1228 #endif
1229 #ifdef B115200
1230                 case B115200:
1231                         lpdcb->BaudRate = 57601;
1232                         break;
1233 #endif
1234         }
1235 #endif
1236         switch (port.c_cflag & CSIZE) {
1237                 case CS5:
1238                         lpdcb->ByteSize = 5;
1239                         break;
1240                 case CS6:
1241                         lpdcb->ByteSize = 6;
1242                         break;
1243                 case CS7:
1244                         lpdcb->ByteSize = 7;
1245                         break;
1246                 case CS8:
1247                         lpdcb->ByteSize = 8;
1248                         break;
1249         }       
1250         
1251         if(port.c_iflag & INPCK)
1252             lpdcb->fParity = TRUE;
1253         else
1254             lpdcb->fParity = FALSE;
1255 #ifdef CMSPAR
1256         switch (port.c_cflag & (PARENB | PARODD | CMSPAR))
1257 #else
1258         switch (port.c_cflag & (PARENB | PARODD))
1259 #endif
1260         {
1261                 case 0:
1262                         lpdcb->Parity = NOPARITY;
1263                         break;
1264                 case PARENB:
1265                         lpdcb->Parity = EVENPARITY;
1266                         break;
1267                 case (PARENB | PARODD):
1268                         lpdcb->Parity = ODDPARITY;              
1269                         break;
1270 #ifdef CMSPAR
1271                 case (PARENB | CMSPAR):
1272                         lpdcb->Parity = MARKPARITY;             
1273                         break;
1274                 case (PARENB | PARODD | CMSPAR):
1275                         lpdcb->Parity = SPACEPARITY;            
1276                         break;
1277 #endif
1278         }
1279
1280         if (port.c_cflag & CSTOPB)
1281             if(lpdcb->ByteSize == 5)
1282                 lpdcb->StopBits = ONE5STOPBITS;
1283             else
1284                 lpdcb->StopBits = TWOSTOPBITS;
1285         else
1286             lpdcb->StopBits = ONESTOPBIT;
1287
1288         lpdcb->RlsTimeout = 50;
1289         lpdcb->CtsTimeout = 50; 
1290         lpdcb->DsrTimeout = 50;
1291         lpdcb->fNull = 0;
1292         lpdcb->fChEvt = 0;
1293         lpdcb->fBinary = 1;
1294         lpdcb->fDtrDisable = 0;
1295
1296 #ifdef CRTSCTS
1297
1298         if (port.c_cflag & CRTSCTS) {
1299                 lpdcb->fDtrflow = 1;
1300                 lpdcb->fRtsflow = 1;
1301                 lpdcb->fOutxCtsFlow = 1;
1302                 lpdcb->fOutxDsrFlow = 1;
1303         } else 
1304 #endif
1305                 lpdcb->fDtrDisable = 1;
1306
1307         if (port.c_iflag & IXON)
1308                 lpdcb->fInX = 1;
1309         else
1310                 lpdcb->fInX = 0;
1311
1312         if (port.c_iflag & IXOFF)
1313                 lpdcb->fOutX = 1;
1314         else
1315                 lpdcb->fOutX = 0;
1316 /*
1317         lpdcb->XonChar = 
1318         lpdcb->XoffChar = 
1319  */
1320         lpdcb->XonLim = 10;
1321         lpdcb->XoffLim = 10;
1322
1323         lpdcb->EvtChar = ptr->evtchar;
1324
1325         ptr->commerror = 0;
1326         return 0;
1327 }
1328
1329 /*****************************************************************************
1330  *      TransmitCommChar16      (USER.206)
1331  */
1332 INT16 WINAPI TransmitCommChar16(INT16 cid,CHAR chTransmit)
1333 {
1334         struct DosDeviceStruct *ptr;
1335
1336         TRACE("cid %d, data %d \n", cid, chTransmit);
1337         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1338                 FIXME("no handle for cid = %0x!\n",cid);
1339                 return -1;
1340         }
1341
1342         if (ptr->suspended) {
1343                 ptr->commerror = IE_HARDWARE;
1344                 return -1;
1345         }       
1346
1347         if (ptr->xmit >= 0) {
1348           /* character already queued */
1349           /* FIXME: which error would Windows return? */
1350           ptr->commerror = CE_TXFULL;
1351           return -1;
1352         }
1353
1354         if (ptr->obuf_head == ptr->obuf_tail) {
1355           /* transmit queue empty, try to transmit directly */
1356           if (write(ptr->fd, &chTransmit, 1) == -1) {
1357             /* didn't work, queue it */
1358             ptr->xmit = chTransmit;
1359             comm_waitwrite(ptr);
1360           }
1361         } else {
1362           /* data in queue, let this char be transmitted next */
1363           ptr->xmit = chTransmit;
1364           comm_waitwrite(ptr);
1365         }
1366
1367         ptr->commerror = 0;
1368         return 0;
1369 }
1370
1371 /*****************************************************************************
1372  *      UngetCommChar16 (USER.212)
1373  */
1374 INT16 WINAPI UngetCommChar16(INT16 cid,CHAR chUnget)
1375 {
1376         struct DosDeviceStruct *ptr;
1377
1378         TRACE("cid %d (char %d)\n", cid, chUnget);
1379         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1380                 FIXME("no handle for cid = %0x!\n",cid);
1381                 return -1;
1382         }
1383
1384         if (ptr->suspended) {
1385                 ptr->commerror = IE_HARDWARE;
1386                 return -1;
1387         }       
1388
1389         if (ptr->unget>=0) {
1390           /* character already queued */
1391           /* FIXME: which error would Windows return? */
1392           ptr->commerror = CE_RXOVER;
1393           return -1;
1394         }
1395
1396         ptr->unget = chUnget;
1397
1398         ptr->commerror = 0;
1399         return 0;
1400 }
1401
1402 /*****************************************************************************
1403  *      ReadComm16      (USER.204)
1404  */
1405 INT16 WINAPI ReadComm16(INT16 cid,LPSTR lpvBuf,INT16 cbRead)
1406 {
1407         int status, length;
1408         struct DosDeviceStruct *ptr;
1409         LPSTR orgBuf = lpvBuf;
1410
1411         TRACE("cid %d, ptr %p, length %d\n", cid, lpvBuf, cbRead);
1412         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1413                 FIXME("no handle for cid = %0x!\n",cid);
1414                 return -1;
1415         }
1416
1417         if (ptr->suspended) {
1418                 ptr->commerror = IE_HARDWARE;
1419                 return -1;
1420         }       
1421
1422         /* read unget character */
1423         if (ptr->unget>=0) {
1424                 *lpvBuf++ = ptr->unget;
1425                 ptr->unget = -1;
1426
1427                 length = 1;
1428         } else
1429                 length = 0;
1430
1431         /* read from receive buffer */
1432         while (length < cbRead) {
1433           status = ((ptr->ibuf_head < ptr->ibuf_tail) ?
1434                     ptr->ibuf_size : ptr->ibuf_head) - ptr->ibuf_tail;
1435           if (!status) break;
1436           if ((cbRead - length) < status)
1437             status = cbRead - length;
1438
1439           memcpy(lpvBuf, ptr->inbuf + ptr->ibuf_tail, status);
1440           ptr->ibuf_tail += status;
1441           if (ptr->ibuf_tail >= ptr->ibuf_size)
1442             ptr->ibuf_tail = 0;
1443           lpvBuf += status;
1444           length += status;
1445         }
1446
1447         TRACE("%.*s\n", length, orgBuf);
1448         ptr->commerror = 0;
1449         return length;
1450 }
1451
1452 /*****************************************************************************
1453  *      WriteComm16     (USER.205)
1454  */
1455 INT16 WINAPI WriteComm16(INT16 cid, LPSTR lpvBuf, INT16 cbWrite)
1456 {
1457         int status, length;
1458         struct DosDeviceStruct *ptr;
1459
1460         TRACE("cid %d, ptr %p, length %d\n", 
1461                 cid, lpvBuf, cbWrite);
1462         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1463                 FIXME("no handle for cid = %0x!\n",cid);
1464                 return -1;
1465         }
1466
1467         if (ptr->suspended) {
1468                 ptr->commerror = IE_HARDWARE;
1469                 return -1;
1470         }       
1471         
1472         TRACE("%.*s\n", cbWrite, lpvBuf );
1473
1474         length = 0;
1475         while (length < cbWrite) {
1476           if ((ptr->obuf_head == ptr->obuf_tail) && (ptr->xmit < 0)) {
1477             /* no data queued, try to write directly */
1478             status = write(ptr->fd, lpvBuf, cbWrite - length);
1479             if (status > 0) {
1480               lpvBuf += status;
1481               length += status;
1482               continue;
1483             }
1484           }
1485           /* can't write directly, put into transmit buffer */
1486           status = ((ptr->obuf_tail > ptr->obuf_head) ?
1487                     (ptr->obuf_tail-1) : ptr->obuf_size) - ptr->obuf_head;
1488           if (!status) break;
1489           if ((cbWrite - length) < status)
1490             status = cbWrite - length;
1491           memcpy(lpvBuf, ptr->outbuf + ptr->obuf_head, status);
1492           ptr->obuf_head += status;
1493           if (ptr->obuf_head >= ptr->obuf_size)
1494             ptr->obuf_head = 0;
1495           lpvBuf += status;
1496           length += status;
1497           comm_waitwrite(ptr);
1498         }
1499
1500         ptr->commerror = 0;     
1501         return length;
1502 }
1503
1504 /***********************************************************************
1505  *           EnableCommNotification   (USER.245)
1506  */
1507 BOOL16 WINAPI EnableCommNotification16( INT16 cid, HWND16 hwnd,
1508                                       INT16 cbWriteNotify, INT16 cbOutQueue )
1509 {
1510         struct DosDeviceStruct *ptr;
1511
1512         TRACE("(%d, %x, %d, %d)\n", cid, hwnd, cbWriteNotify, cbOutQueue);
1513         if ((ptr = GetDeviceStruct(cid)) == NULL) {
1514                 FIXME("no handle for cid = %0x!\n",cid);
1515                 return -1;
1516         }
1517         ptr->wnd = hwnd;
1518         ptr->n_read = cbWriteNotify;
1519         ptr->n_write = cbOutQueue;
1520         return TRUE;
1521 }
1522
1523
1524 /**************************************************************************
1525  *         BuildCommDCBA                (KERNEL32.113)
1526  *
1527  *  Updates a device control block data structure with values from an
1528  *  ascii device control string.  The device control string has two forms
1529  *  normal and extended, it must be exclusively in one or the other form.
1530  *
1531  * RETURNS
1532  *
1533  *  True on success, false on an malformed control string.
1534  */
1535 BOOL WINAPI BuildCommDCBA(
1536     LPCSTR device, /* [in] The ascii device control string used to update the DCB. */
1537     LPDCB  lpdcb)  /* [out] The device control block to be updated. */
1538 {
1539         return BuildCommDCBAndTimeoutsA(device,lpdcb,NULL);
1540 }
1541
1542 /**************************************************************************
1543  *         BuildCommDCBAndTimeoutsA     (KERNEL32.114)
1544  *
1545  *  Updates a device control block data structure with values from an
1546  *  ascii device control string.  Taking time out values from a time outs
1547  *  struct if desired by the control string.
1548  *
1549  * RETURNS
1550  *
1551  *  True on success, false bad handles etc
1552  */
1553 BOOL WINAPI BuildCommDCBAndTimeoutsA(
1554     LPCSTR         device,     /* [in] The ascii device control string. */
1555     LPDCB          lpdcb,      /* [out] The device control block to be updated. */
1556     LPCOMMTIMEOUTS lptimeouts) /* [in] The time outs to use if asked to set them by the control string. */
1557 {
1558         int     port;
1559         char    *ptr,*temp;
1560
1561         TRACE("(%s,%p,%p)\n",device,lpdcb,lptimeouts);
1562
1563         if (!strncasecmp(device,"COM",3)) {
1564                 port=device[3]-'0';
1565                 if (port--==0) {
1566                         ERR("BUG! COM0 can't exist!\n");
1567                         return FALSE;
1568                 }
1569                 if (!ValidCOMPort(port))
1570                         return FALSE;
1571                 if (*(device+4)!=':')
1572                         return FALSE;
1573                 temp=(LPSTR)(device+5);
1574         } else
1575                 temp=(LPSTR)device;
1576
1577         lpdcb->DCBlength        = sizeof(DCB);
1578         if (strchr(temp,',')) { /* old style */
1579                 DCB16   dcb16;
1580                 BOOL16  ret;
1581                 char    last=temp[strlen(temp)-1];
1582
1583                 ret=BuildCommDCB16(device,&dcb16);
1584                 if (ret)
1585                         return FALSE;
1586                 lpdcb->BaudRate         = dcb16.BaudRate;
1587                 lpdcb->ByteSize         = dcb16.ByteSize;
1588                 lpdcb->fBinary          = dcb16.fBinary;
1589                 lpdcb->Parity           = dcb16.Parity;
1590                 lpdcb->fParity          = dcb16.fParity;
1591                 lpdcb->fNull            = dcb16.fNull;
1592                 lpdcb->StopBits         = dcb16.StopBits;
1593                 if (last == 'x') {
1594                         lpdcb->fInX             = TRUE;
1595                         lpdcb->fOutX            = TRUE;
1596                         lpdcb->fOutxCtsFlow     = FALSE;
1597                         lpdcb->fOutxDsrFlow     = FALSE;
1598                         lpdcb->fDtrControl      = DTR_CONTROL_ENABLE;
1599                         lpdcb->fRtsControl      = RTS_CONTROL_ENABLE;
1600                 } else if (last=='p') {
1601                         lpdcb->fInX             = FALSE;
1602                         lpdcb->fOutX            = FALSE;
1603                         lpdcb->fOutxCtsFlow     = TRUE;
1604                         lpdcb->fOutxDsrFlow     = TRUE;
1605                         lpdcb->fDtrControl      = DTR_CONTROL_HANDSHAKE;
1606                         lpdcb->fRtsControl      = RTS_CONTROL_HANDSHAKE;
1607                 } else {
1608                         lpdcb->fInX             = FALSE;
1609                         lpdcb->fOutX            = FALSE;
1610                         lpdcb->fOutxCtsFlow     = FALSE;
1611                         lpdcb->fOutxDsrFlow     = FALSE;
1612                         lpdcb->fDtrControl      = DTR_CONTROL_ENABLE;
1613                         lpdcb->fRtsControl      = RTS_CONTROL_ENABLE;
1614                 }
1615                 lpdcb->XonChar  = dcb16.XonChar;
1616                 lpdcb->XoffChar = dcb16.XoffChar;
1617                 lpdcb->ErrorChar= dcb16.PeChar;
1618                 lpdcb->fErrorChar= dcb16.fPeChar;
1619                 lpdcb->EofChar  = dcb16.EofChar;
1620                 lpdcb->EvtChar  = dcb16.EvtChar;
1621                 lpdcb->XonLim   = dcb16.XonLim;
1622                 lpdcb->XoffLim  = dcb16.XoffLim;
1623                 return TRUE;
1624         }
1625         ptr=strtok(temp," "); 
1626         while (ptr) {
1627                 DWORD   flag,x;
1628
1629                 flag=0;
1630                 if (!strncmp("baud=",ptr,5)) {
1631                         if (!sscanf(ptr+5,"%ld",&x))
1632                                 WARN("Couldn't parse %s\n",ptr);
1633                         lpdcb->BaudRate = x;
1634                         flag=1;
1635                 }
1636                 if (!strncmp("stop=",ptr,5)) {
1637                         if (!sscanf(ptr+5,"%ld",&x))
1638                                 WARN("Couldn't parse %s\n",ptr);
1639                         lpdcb->StopBits = x;
1640                         flag=1;
1641                 }
1642                 if (!strncmp("data=",ptr,5)) {
1643                         if (!sscanf(ptr+5,"%ld",&x))
1644                                 WARN("Couldn't parse %s\n",ptr);
1645                         lpdcb->ByteSize = x;
1646                         flag=1;
1647                 }
1648                 if (!strncmp("parity=",ptr,7)) {
1649                         lpdcb->fParity  = TRUE;
1650                         switch (ptr[8]) {
1651                         case 'N':case 'n':
1652                                 lpdcb->fParity  = FALSE;
1653                                 lpdcb->Parity   = NOPARITY;
1654                                 break;
1655                         case 'E':case 'e':
1656                                 lpdcb->Parity   = EVENPARITY;
1657                                 break;
1658                         case 'O':case 'o':
1659                                 lpdcb->Parity   = ODDPARITY;
1660                                 break;
1661                         case 'M':case 'm':
1662                                 lpdcb->Parity   = MARKPARITY;
1663                                 break;
1664                         }
1665                         flag=1;
1666                 }
1667                 if (!flag)
1668                         ERR("Unhandled specifier '%s', please report.\n",ptr);
1669                 ptr=strtok(NULL," ");
1670         }
1671         if (lpdcb->BaudRate==110)
1672                 lpdcb->StopBits = 2;
1673         return TRUE;
1674 }
1675
1676 /**************************************************************************
1677  *         BuildCommDCBAndTimeoutsW             (KERNEL32.115)
1678  *
1679  *  Updates a device control block data structure with values from an
1680  *  unicode device control string.  Taking time out values from a time outs
1681  *  struct if desired by the control string.
1682  *
1683  * RETURNS
1684  *
1685  *  True on success, false bad handles etc.
1686  */
1687 BOOL WINAPI BuildCommDCBAndTimeoutsW(
1688     LPCWSTR        devid,      /* [in] The unicode device control string. */
1689     LPDCB          lpdcb,      /* [out] The device control block to be updated. */
1690     LPCOMMTIMEOUTS lptimeouts) /* [in] The time outs to use if asked to set them by the control string. */
1691 {
1692         BOOL ret = FALSE;
1693         LPSTR   devidA;
1694
1695         TRACE("(%p,%p,%p)\n",devid,lpdcb,lptimeouts);
1696         devidA = HEAP_strdupWtoA( GetProcessHeap(), 0, devid );
1697         if (devidA)
1698         {
1699         ret=BuildCommDCBAndTimeoutsA(devidA,lpdcb,lptimeouts);
1700         HeapFree( GetProcessHeap(), 0, devidA );
1701         }
1702         return ret;
1703 }
1704
1705 /**************************************************************************
1706  *         BuildCommDCBW                (KERNEL32.116)
1707  *
1708  *  Updates a device control block structure with values from an
1709  *  unicode device control string.  The device control string has two forms
1710  *  normal and extended, it must be exclusively in one or the other form.
1711  *
1712  * RETURNS
1713  *
1714  *  True on success, false on an malformed control string.
1715  */
1716 BOOL WINAPI BuildCommDCBW(
1717     LPCWSTR devid, /* [in] The unicode device control string. */
1718     LPDCB   lpdcb) /* [out] The device control block to be updated. */
1719 {
1720         return BuildCommDCBAndTimeoutsW(devid,lpdcb,NULL);
1721 }
1722
1723 /* FIXME: having these global for win32 for now */
1724 int commerror=0;
1725
1726 /*****************************************************************************
1727  *      SetCommBreak            (KERNEL32.616)
1728  *
1729  *  Halts the transmission of characters to a communications device.
1730  *
1731  * RETURNS
1732  *
1733  *  True on success, and false if the communications device could not be found,
1734  *  the control is not supported.
1735  *
1736  * BUGS
1737  *
1738  *  Only TIOCSBRK and TIOCCBRK are supported. 
1739  */
1740 BOOL WINAPI SetCommBreak(
1741     HANDLE handle) /* [in] The communictions device to suspend. */
1742 {
1743 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1744         int fd,result;
1745  
1746         fd = FILE_GetUnixHandle( handle, GENERIC_READ );
1747         if(fd<0) {
1748                 TRACE("FILE_GetUnixHandle failed\n");
1749                 return FALSE;
1750         }
1751         result = ioctl(fd,TIOCSBRK,0);
1752         close(fd);
1753         if (result ==-1)
1754           {
1755                 TRACE("ioctl failed\n");
1756                 SetLastError(ERROR_NOT_SUPPORTED);
1757                 return FALSE;
1758           }
1759         return TRUE;
1760 #else
1761         FIXME("ioctl not available\n");
1762         SetLastError(ERROR_NOT_SUPPORTED);
1763         return FALSE;
1764 #endif
1765 }
1766
1767 /*****************************************************************************
1768  *      ClearCommBreak          (KERNEL32.135)
1769  *
1770  *  Resumes character transmission from a communication device.
1771  *
1772  * RETURNS
1773  *
1774  *  True on success and false if the communications device could not be found.
1775  *
1776  * BUGS
1777  *
1778  *  Only TIOCSBRK and TIOCCBRK are supported. 
1779  */
1780 BOOL WINAPI ClearCommBreak(
1781     HANDLE handle) /* [in] The halted communication device whose character transmission is to be resumed. */
1782 {
1783 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1784         int fd,result;
1785  
1786         fd = FILE_GetUnixHandle( handle, GENERIC_READ );
1787         if(fd<0) {
1788                 TRACE("FILE_GetUnixHandle failed\n");
1789                 return FALSE;
1790         }
1791         result = ioctl(fd,TIOCCBRK,0);
1792         close(fd);
1793         if (result ==-1)
1794           {
1795                 TRACE("ioctl failed\n");
1796                 SetLastError(ERROR_NOT_SUPPORTED);
1797                 return FALSE;
1798           }
1799         return TRUE;
1800 #else
1801         FIXME("ioctl not available\n");
1802         SetLastError(ERROR_NOT_SUPPORTED);
1803         return FALSE;
1804 #endif
1805 }
1806
1807 /*****************************************************************************
1808  *      EscapeCommFunction      (KERNEL32.213)
1809  *
1810  *  Directs a communication device to perform an extended function.
1811  *
1812  * RETURNS
1813  *
1814  *  True or requested data on successful completion of the command,
1815  *  false if the device is not present cannot execute the command
1816  *  or the command failed.
1817  */
1818 BOOL WINAPI EscapeCommFunction(
1819     HANDLE handle,    /* [in] The communication device to perform the extended function. */
1820     UINT   nFunction) /* [in] The extended function to be performed. */
1821 {
1822         int fd,direct=FALSE,result=FALSE;
1823         struct termios  port;
1824
1825         TRACE("handle %d, function=%d\n", handle, nFunction);
1826         fd = FILE_GetUnixHandle( handle, GENERIC_READ );
1827         if(fd<0) {
1828                 FIXME("handle %d not found.\n",handle);
1829                 return FALSE;
1830         }
1831
1832         if (tcgetattr(fd,&port) == -1) {
1833                 commerror=WinError();
1834                 close(fd);
1835                 return FALSE;
1836         }
1837
1838         switch (nFunction) {
1839                 case RESETDEV:
1840                         TRACE("\n");
1841                         break;                                  
1842
1843                 case CLRDTR:
1844                         TRACE("CLRDTR\n");
1845 #ifdef TIOCM_DTR
1846                         direct=TRUE;
1847                         result= COMM_WhackModem(fd, ~TIOCM_DTR, 0);
1848                         break;
1849 #endif
1850
1851                 case CLRRTS:
1852                         TRACE("CLRRTS\n");
1853 #ifdef TIOCM_RTS
1854                         direct=TRUE;
1855                         result= COMM_WhackModem(fd, ~TIOCM_RTS, 0);
1856                         break;
1857 #endif
1858         
1859                 case SETDTR:
1860                         TRACE("SETDTR\n");
1861 #ifdef TIOCM_DTR
1862                         direct=TRUE;
1863                         result= COMM_WhackModem(fd, 0, TIOCM_DTR);
1864                         break;
1865 #endif
1866
1867                 case SETRTS:
1868                         TRACE("SETRTS\n");
1869 #ifdef TIOCM_DTR
1870                         direct=TRUE;
1871                         result= COMM_WhackModem(fd, 0, TIOCM_RTS);
1872                         break;
1873 #endif
1874
1875                 case SETXOFF:
1876                         TRACE("SETXOFF\n");
1877                         port.c_iflag |= IXOFF;
1878                         break;
1879
1880                 case SETXON:
1881                         TRACE("SETXON\n");
1882                         port.c_iflag |= IXON;
1883                         break;
1884                 case SETBREAK:
1885                         TRACE("setbreak\n");
1886 #ifdef  TIOCSBRK
1887                         direct=TRUE;
1888                         result = ioctl(fd,TIOCSBRK,0);
1889                         break;
1890 #endif
1891                 case CLRBREAK:
1892                         TRACE("clrbreak\n");
1893 #ifdef  TIOCSBRK
1894                         direct=TRUE;
1895                         result = ioctl(fd,TIOCCBRK,0);
1896                         break;
1897 #endif
1898                 default:
1899                         WARN("(handle=%d,nFunction=%d): Unknown function\n", 
1900                         handle, nFunction);
1901                         break;                          
1902         }
1903         
1904         if (!direct)
1905           if (tcsetattr(fd, TCSADRAIN, &port) == -1) {
1906                 commerror = WinError();
1907                 close(fd);
1908                 return FALSE;   
1909           } else 
1910                 result= TRUE;
1911         else
1912           {
1913             if (result == -1)
1914               {
1915                 result= FALSE;
1916                 commerror=WinError();
1917               }
1918             else
1919               result = TRUE;
1920           }
1921         close(fd);
1922         return result;
1923 }
1924
1925 /********************************************************************
1926  *      PurgeComm        (KERNEL32.558)
1927  *
1928  *  Terminates pending operations and/or discards buffers on a
1929  *  communication resource.
1930  *
1931  * RETURNS
1932  *
1933  *  True on success and false if the communications handle is bad.
1934  */
1935 BOOL WINAPI PurgeComm(
1936     HANDLE handle, /* [in] The communication resource to be purged. */
1937     DWORD  flags)  /* [in] Flags for clear pending/buffer on input/output. */
1938 {
1939      int fd;
1940
1941      TRACE("handle %d, flags %lx\n", handle, flags);
1942
1943      fd = FILE_GetUnixHandle( handle, GENERIC_READ );
1944      if(fd<0) {
1945         FIXME("no handle %d found\n",handle);
1946         return FALSE;
1947      }
1948
1949      /*
1950      ** not exactly sure how these are different
1951      ** Perhaps if we had our own internal queues, one flushes them
1952      ** and the other flushes the kernel's buffers.
1953      */
1954      if(flags&PURGE_TXABORT)
1955          tcflush(fd,TCOFLUSH);
1956      if(flags&PURGE_RXABORT)
1957          tcflush(fd,TCIFLUSH);
1958      if(flags&PURGE_TXCLEAR)
1959          tcflush(fd,TCOFLUSH);
1960      if(flags&PURGE_RXCLEAR)
1961          tcflush(fd,TCIFLUSH);
1962      close(fd);
1963
1964      return 1;
1965 }
1966
1967 /*****************************************************************************
1968  *      ClearCommError  (KERNEL32.136)
1969  *
1970  *  Enables further I/O operations on a communications resource after
1971  *  supplying error and current status information.
1972  *
1973  * RETURNS
1974  *
1975  *  True on success, false if the communication resource handle is bad.
1976  */
1977 BOOL WINAPI ClearCommError(
1978     HANDLE    handle, /* [in] The communication resource with the error. */
1979     LPDWORD   errors, /* [out] Flags indicating error the resource experienced. */
1980     LPCOMSTAT lpStat) /* [out] The status of the communication resource. */
1981 {
1982     int fd;
1983
1984     fd=FILE_GetUnixHandle( handle, GENERIC_READ );
1985     if(0>fd) 
1986     {
1987         FIXME("no handle %d found\n",handle);
1988         return FALSE;
1989     }
1990
1991     if (lpStat) 
1992     {
1993         lpStat->status = 0;
1994
1995 #ifdef TIOCOUTQ
1996         if(ioctl(fd, TIOCOUTQ, &lpStat->cbOutQue))
1997             WARN("ioctl returned error\n");
1998 #else
1999         lpStat->cbOutQue = 0; /* FIXME: find a different way to find out */
2000 #endif
2001
2002 #ifdef TIOCINQ
2003         if(ioctl(fd, TIOCINQ, &lpStat->cbInQue))
2004             WARN("ioctl returned error\n");
2005 #endif
2006
2007         TRACE("handle %d cbInQue = %ld cbOutQue = %ld\n",
2008               handle, lpStat->cbInQue, lpStat->cbOutQue);
2009     }
2010
2011     close(fd);
2012
2013     if(errors)
2014         *errors = 0;
2015
2016     /*
2017     ** After an asynchronous write opperation, the
2018     ** app will call ClearCommError to see if the
2019     ** results are ready yet. It waits for ERROR_IO_PENDING
2020     */
2021     commerror = ERROR_IO_PENDING;
2022
2023     return TRUE;
2024 }
2025
2026 /*****************************************************************************
2027  *      SetupComm       (KERNEL32.677)
2028  *
2029  *  Called after CreateFile to hint to the communication resource to use
2030  *  specified sizes for input and output buffers rather than the default values.
2031  *
2032  * RETURNS
2033  *
2034  *  True if successful, false if the communications resource handle is bad.
2035  *
2036  * BUGS
2037  *
2038  *  Stub.
2039  */
2040 BOOL WINAPI SetupComm(
2041     HANDLE handle,  /* [in] The just created communication resource handle. */
2042     DWORD  insize,  /* [in] The suggested size of the communication resources input buffer in bytes. */
2043     DWORD  outsize) /* [in] The suggested size of the communication resources output buffer in bytes. */
2044 {
2045     int fd;
2046
2047     FIXME("insize %ld outsize %ld unimplemented stub\n", insize, outsize);
2048     fd=FILE_GetUnixHandle( handle, GENERIC_READ );
2049     if(0>fd) {
2050         FIXME("handle %d not found?\n",handle);
2051         return FALSE;
2052     }
2053     close(fd);
2054     return TRUE;
2055
2056
2057 /*****************************************************************************
2058  *      GetCommMask     (KERNEL32.284)
2059  *
2060  *  Obtain the events associated with a communication device that will cause a call
2061  *  WaitCommEvent to return.
2062  *
2063  *  RETURNS
2064  *
2065  *   True on success, fail on bad device handle etc.
2066  */
2067 BOOL WINAPI GetCommMask(
2068     HANDLE  handle,  /* [in] The communications device. */
2069     LPDWORD evtmask) /* [out] The events which cause WaitCommEvent to return. */
2070 {
2071     BOOL ret;
2072
2073     TRACE("handle %d, mask %p\n", handle, evtmask);
2074
2075     SERVER_START_REQ
2076     {
2077         struct get_serial_info_request *req = server_alloc_req( sizeof(*req), 0 );
2078         req->handle = handle;
2079         if ((ret = !server_call( REQ_GET_SERIAL_INFO )))
2080         {
2081             if (evtmask) *evtmask = req->eventmask;
2082         }
2083     }
2084     SERVER_END_REQ;
2085     return ret;
2086 }
2087
2088 /*****************************************************************************
2089  *      SetCommMask     (KERNEL32.618)
2090  *
2091  *  There be some things we need to hear about yon there communications device.
2092  *  (Set which events associated with a communication device should cause
2093  *  a call WaitCommEvent to return.)
2094  *
2095  * RETURNS
2096  *
2097  *  True on success, false on bad handle etc.
2098  */
2099 BOOL WINAPI SetCommMask(
2100     HANDLE handle,  /* [in] The communications device.  */
2101     DWORD  evtmask) /* [in] The events that to be monitored. */
2102 {
2103     BOOL ret;
2104
2105     TRACE("handle %d, mask %lx\n", handle, evtmask);
2106
2107     SERVER_START_REQ
2108     {
2109         struct set_serial_info_request *req = server_alloc_req( sizeof(*req), 0 );
2110         req->handle    = handle;
2111         req->flags     = SERIALINFO_SET_MASK;
2112         req->eventmask = evtmask;
2113         ret = !server_call( REQ_SET_SERIAL_INFO );
2114     }
2115     SERVER_END_REQ;
2116     return ret;
2117 }
2118
2119 /*****************************************************************************
2120  *      SetCommState    (KERNEL32.619)
2121  *
2122  *  Re-initializes all hardware and control settings of a communications device,
2123  *  with values from a device control block without effecting the input and output
2124  *  queues.
2125  *
2126  * RETURNS
2127  *
2128  *  True on success, false on failure eg if the XonChar is equal to the XoffChar.
2129  */
2130 BOOL WINAPI SetCommState(
2131     HANDLE handle, /* [in] The communications device. */
2132     LPDCB  lpdcb)  /* [out] The device control block. */
2133 {
2134      struct termios port;
2135      int fd, bytesize, stopbits;
2136
2137      TRACE("handle %d, ptr %p\n", handle, lpdcb);
2138      TRACE("bytesize %d baudrate %ld fParity %d Parity %d stopbits %d\n",
2139            lpdcb->ByteSize,lpdcb->BaudRate,lpdcb->fParity, lpdcb->Parity,
2140            (lpdcb->StopBits == ONESTOPBIT)?1:
2141            (lpdcb->StopBits == TWOSTOPBITS)?2:0);
2142      TRACE("%s %s\n",(lpdcb->fInX)?"IXON":"~IXON",
2143            (lpdcb->fOutX)?"IXOFF":"~IXOFF");
2144
2145      fd = FILE_GetUnixHandle( handle, GENERIC_READ );
2146      if (fd < 0)  {
2147         FIXME("no handle %d found\n",handle);
2148         return FALSE;
2149      }
2150
2151      if ((tcgetattr(fd,&port)) == -1) {
2152          int save_error = errno;
2153          commerror = WinError();
2154          close( fd );
2155          ERR("tcgetattr error '%s'\n", strerror(save_error));
2156          return FALSE;
2157      }
2158
2159         port.c_cc[VMIN] = 0;
2160         port.c_cc[VTIME] = 1;
2161
2162 #ifdef IMAXBEL
2163         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|IMAXBEL);
2164 #else
2165         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR);
2166 #endif
2167         port.c_iflag |= (IGNBRK);
2168
2169         port.c_oflag &= ~(OPOST);
2170
2171         port.c_cflag &= ~(HUPCL);
2172         port.c_cflag |= CLOCAL | CREAD;
2173
2174         port.c_lflag &= ~(ICANON|ECHO|ISIG);
2175         port.c_lflag |= NOFLSH;
2176
2177      /*
2178      ** MJM - removed default baudrate settings
2179      ** TRACE(comm,"baudrate %ld\n",lpdcb->BaudRate);
2180      */
2181 #ifdef CBAUD
2182         port.c_cflag &= ~CBAUD;
2183         switch (lpdcb->BaudRate) {
2184                 case 110:
2185                 case CBR_110:
2186                         port.c_cflag |= B110;
2187                         break;          
2188                 case 300:
2189                 case CBR_300:
2190                         port.c_cflag |= B300;
2191                         break;          
2192                 case 600:
2193                 case CBR_600:
2194                         port.c_cflag |= B600;
2195                         break;          
2196                 case 1200:
2197                 case CBR_1200:
2198                         port.c_cflag |= B1200;
2199                         break;          
2200                 case 2400:
2201                 case CBR_2400:
2202                         port.c_cflag |= B2400;
2203                         break;          
2204                 case 4800:
2205                 case CBR_4800:
2206                         port.c_cflag |= B4800;
2207                         break;          
2208                 case 9600:
2209                 case CBR_9600:
2210                         port.c_cflag |= B9600;
2211                         break;          
2212                 case 19200:
2213                 case CBR_19200:
2214                         port.c_cflag |= B19200;
2215                         break;          
2216                 case 38400:
2217                 case CBR_38400:
2218                         port.c_cflag |= B38400;
2219                         break;          
2220 #ifdef B57600
2221                 case 57600:
2222                         port.c_cflag |= B57600;
2223                         break;          
2224 #endif
2225 #ifdef B115200
2226                 case 115200:
2227                         port.c_cflag |= B115200;
2228                         break;          
2229 #endif
2230 #ifdef B230400
2231                 case 230400:
2232                         port.c_cflag |= B230400;
2233                         break;          
2234 #endif
2235 #ifdef B460800
2236                 case 460600:
2237                         port.c_cflag |= B460800;
2238                         break;          
2239 #endif
2240                 default:
2241                         commerror = IE_BAUDRATE;
2242                         close( fd );
2243                         ERR("baudrate %ld\n",lpdcb->BaudRate);
2244                         return FALSE;
2245         }
2246 #elif !defined(__EMX__)
2247         switch (lpdcb->BaudRate) {
2248                 case 110:
2249                 case CBR_110:
2250                         port.c_ospeed = B110;
2251                         break;
2252                 case 300:
2253                 case CBR_300:
2254                         port.c_ospeed = B300;
2255                         break;
2256                 case 600:
2257                 case CBR_600:
2258                         port.c_ospeed = B600;
2259                         break;
2260                 case 1200:
2261                 case CBR_1200:
2262                         port.c_ospeed = B1200;
2263                         break;
2264                 case 2400:
2265                 case CBR_2400:
2266                         port.c_ospeed = B2400;
2267                         break;
2268                 case 4800:
2269                 case CBR_4800:
2270                         port.c_ospeed = B4800;
2271                         break;
2272                 case 9600:
2273                 case CBR_9600:
2274                         port.c_ospeed = B9600;
2275                         break;
2276                 case 19200:
2277                 case CBR_19200:
2278                         port.c_ospeed = B19200;
2279                         break;
2280                 case 38400:
2281                 case CBR_38400:
2282                         port.c_ospeed = B38400;
2283                         break;
2284                 default:
2285                         commerror = IE_BAUDRATE;
2286                         close( fd );
2287                         ERR("baudrate %ld\n",lpdcb->BaudRate);
2288                         return FALSE;
2289         }
2290         port.c_ispeed = port.c_ospeed;
2291 #endif
2292         bytesize=lpdcb->ByteSize;
2293         stopbits=lpdcb->StopBits;
2294
2295 #ifdef CMSPAR
2296         port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
2297 #else
2298         port.c_cflag &= ~(PARENB | PARODD);
2299 #endif
2300         if (lpdcb->fParity)
2301             port.c_iflag |= INPCK;
2302         else
2303             port.c_iflag &= ~INPCK;
2304         switch (lpdcb->Parity) {
2305                 case NOPARITY:
2306                         break;
2307                 case ODDPARITY:
2308                         port.c_cflag |= (PARENB | PARODD);
2309                         break;
2310                 case EVENPARITY:
2311                         port.c_cflag |= PARENB;
2312                         break;
2313 #ifdef CMSPAR
2314                 /* Linux defines mark/space (stick) parity */
2315                 case MARKPARITY:
2316                         port.c_cflag |= (PARENB | CMSPAR);
2317                         break;
2318                 case SPACEPARITY:
2319                         port.c_cflag |= (PARENB | PARODD |  CMSPAR);
2320                         break;
2321 #else
2322                 /* try the POSIX way */
2323                 case MARKPARITY:
2324                         if( stopbits == ONESTOPBIT) {
2325                             stopbits = TWOSTOPBITS;
2326                             port.c_iflag &= ~INPCK;
2327                         } else {
2328                             commerror = IE_BYTESIZE;
2329                             close( fd );
2330                             ERR("Cannot set MARK Parity\n");
2331                             return FALSE;
2332                         }
2333                         break;
2334                 case SPACEPARITY:
2335                         if( bytesize < 8) {
2336                             bytesize +=1;
2337                             port.c_iflag &= ~INPCK;
2338                         } else {
2339                             commerror = IE_BYTESIZE;
2340                             close( fd );
2341                             ERR("Cannot set SPACE Parity\n");
2342                             return FALSE;
2343                         }
2344                         break;
2345 #endif
2346                default:
2347                         commerror = IE_BYTESIZE;
2348                         close( fd );
2349                         ERR("Parity\n");
2350                         return FALSE;
2351         }
2352         
2353
2354         port.c_cflag &= ~CSIZE;
2355         switch (bytesize) {
2356                 case 5:
2357                         port.c_cflag |= CS5;
2358                         break;
2359                 case 6:
2360                         port.c_cflag |= CS6;
2361                         break;
2362                 case 7:
2363                         port.c_cflag |= CS7;
2364                         break;
2365                 case 8:
2366                         port.c_cflag |= CS8;
2367                         break;
2368                 default:
2369                         commerror = IE_BYTESIZE;
2370                         close( fd );
2371                         ERR("ByteSize\n");
2372                         return FALSE;
2373         }
2374         
2375         switch (stopbits) {
2376                 case ONESTOPBIT:
2377                                 port.c_cflag &= ~CSTOPB;
2378                                 break;
2379                 case ONE5STOPBITS: /* wil be selected if bytesize is 5 */
2380                 case TWOSTOPBITS:
2381                                 port.c_cflag |= CSTOPB;
2382                                 break;
2383                 default:
2384                         commerror = IE_BYTESIZE;
2385                         close( fd );
2386                         ERR("StopBits\n");
2387                         return FALSE;
2388         }
2389 #ifdef CRTSCTS
2390         if (    lpdcb->fOutxCtsFlow                     ||
2391                 lpdcb->fDtrControl == DTR_CONTROL_ENABLE||
2392                 lpdcb->fRtsControl == RTS_CONTROL_ENABLE
2393         ) 
2394           {
2395             port.c_cflag |= CRTSCTS;
2396             TRACE("CRTSCTS\n");
2397           }
2398         
2399         if (lpdcb->fDtrControl == DTR_CONTROL_DISABLE)
2400           {
2401             port.c_cflag &= ~CRTSCTS;
2402             TRACE("~CRTSCTS\n");
2403           }
2404
2405 #endif  
2406         if (lpdcb->fInX)
2407                 port.c_iflag |= IXON;
2408         else
2409                 port.c_iflag &= ~IXON;
2410         if (lpdcb->fOutX)
2411                 port.c_iflag |= IXOFF;
2412         else
2413                 port.c_iflag &= ~IXOFF;
2414
2415         if (tcsetattr(fd,TCSANOW,&port)==-1) { /* otherwise it hangs with pending input*/
2416                 int save_error=errno;
2417                 commerror = WinError(); 
2418                 close( fd );
2419                 ERR("tcsetattr error '%s'\n", strerror(save_error));
2420                 return FALSE;
2421         } else {
2422                 commerror = 0;
2423                 close( fd );
2424                 return TRUE;
2425         }
2426 }
2427
2428
2429 /*****************************************************************************
2430  *      GetCommState    (KERNEL32.287)
2431  *
2432  *  Fills in a device control block with information from a communications device.
2433  *
2434  * RETURNS
2435  *
2436  *  True on success, false if the communication device handle is bad etc
2437  *  
2438  * BUGS
2439  *
2440  *  XonChar and XoffChar are not set.
2441  */
2442 BOOL WINAPI GetCommState(
2443     HANDLE handle, /* [in] The communications device. */
2444     LPDCB  lpdcb)  /* [out] The device control block. */
2445 {
2446      struct termios port;
2447      int fd,speed;
2448
2449      TRACE("handle %d, ptr %p\n", handle, lpdcb);
2450
2451      fd = FILE_GetUnixHandle( handle, GENERIC_READ );
2452      if (fd < 0) 
2453        {
2454          ERR("FILE_GetUnixHandle failed\n");
2455          return FALSE;
2456        }
2457      if (tcgetattr(fd, &port) == -1) {
2458                 int save_error=errno;
2459                 ERR("tcgetattr error '%s'\n", strerror(save_error));
2460                 commerror = WinError(); 
2461                 close( fd );
2462                 return FALSE;
2463         }
2464      close( fd );
2465 #ifndef __EMX__
2466 #ifdef CBAUD
2467      speed= (port.c_cflag & CBAUD);
2468 #else
2469      speed= (cfgetospeed(&port));
2470 #endif
2471      switch (speed) {
2472                 case B110:
2473                         lpdcb->BaudRate = 110;
2474                         break;
2475                 case B300:
2476                         lpdcb->BaudRate = 300;
2477                         break;
2478                 case B600:
2479                         lpdcb->BaudRate = 600;
2480                         break;
2481                 case B1200:
2482                         lpdcb->BaudRate = 1200;
2483                         break;
2484                 case B2400:
2485                         lpdcb->BaudRate = 2400;
2486                         break;
2487                 case B4800:
2488                         lpdcb->BaudRate = 4800;
2489                         break;
2490                 case B9600:
2491                         lpdcb->BaudRate = 9600;
2492                         break;
2493                 case B19200:
2494                         lpdcb->BaudRate = 19200;
2495                         break;
2496                 case B38400:
2497                         lpdcb->BaudRate = 38400;
2498                         break;
2499 #ifdef B57600
2500                 case B57600:
2501                         lpdcb->BaudRate = 57600;
2502                         break;          
2503 #endif
2504 #ifdef B115200
2505                 case B115200:
2506                         lpdcb->BaudRate = 115200;
2507                         break;          
2508 #endif
2509 #ifdef B230400
2510                 case B230400:
2511                         lpdcb->BaudRate = 230400;
2512                         break;          
2513 #endif
2514 #ifdef B460800
2515                 case B460800:
2516                         lpdcb->BaudRate = 460800;
2517                         break;          
2518 #endif
2519                 default:
2520                         ERR("unknown speed %x \n",speed);
2521         }
2522 #endif
2523         switch (port.c_cflag & CSIZE) {
2524                 case CS5:
2525                         lpdcb->ByteSize = 5;
2526                         break;
2527                 case CS6:
2528                         lpdcb->ByteSize = 6;
2529                         break;
2530                 case CS7:
2531                         lpdcb->ByteSize = 7;
2532                         break;
2533                 case CS8:
2534                         lpdcb->ByteSize = 8;
2535                         break;
2536                 default:
2537                         ERR("unknown size %x \n",port.c_cflag & CSIZE);
2538         }       
2539         
2540         if(port.c_iflag & INPCK)
2541             lpdcb->fParity = TRUE;
2542         else
2543             lpdcb->fParity = FALSE;
2544 #ifdef CMSPAR
2545         switch (port.c_cflag & (PARENB | PARODD | CMSPAR))
2546 #else
2547         switch (port.c_cflag & (PARENB | PARODD))
2548 #endif
2549         {
2550                 case 0:
2551                         lpdcb->Parity = NOPARITY;
2552                         break;
2553                 case PARENB:
2554                         lpdcb->Parity = EVENPARITY;
2555                         break;
2556                 case (PARENB | PARODD):
2557                         lpdcb->Parity = ODDPARITY;              
2558                         break;
2559 #ifdef CMSPAR
2560                 case (PARENB | CMSPAR):
2561                         lpdcb->Parity = MARKPARITY;             
2562                         break;
2563                 case (PARENB | PARODD | CMSPAR):
2564                         lpdcb->Parity = SPACEPARITY;            
2565                         break;
2566 #endif
2567         }
2568
2569         if (port.c_cflag & CSTOPB)
2570             if(lpdcb->ByteSize == 5)
2571                 lpdcb->StopBits = ONE5STOPBITS;
2572             else
2573                 lpdcb->StopBits = TWOSTOPBITS;
2574         else
2575             lpdcb->StopBits = ONESTOPBIT;
2576
2577         lpdcb->fNull = 0;
2578         lpdcb->fBinary = 1;
2579
2580 #ifdef CRTSCTS
2581
2582         if (port.c_cflag & CRTSCTS) {
2583                 lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
2584                 lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
2585                 lpdcb->fOutxCtsFlow = 1;
2586                 lpdcb->fOutxDsrFlow = 1;
2587         } else 
2588 #endif
2589         {
2590                 lpdcb->fDtrControl = DTR_CONTROL_DISABLE;
2591                 lpdcb->fRtsControl = RTS_CONTROL_DISABLE;
2592         }
2593         if (port.c_iflag & IXON)
2594                 lpdcb->fInX = 1;
2595         else
2596                 lpdcb->fInX = 0;
2597
2598         if (port.c_iflag & IXOFF)
2599                 lpdcb->fOutX = 1;
2600         else
2601                 lpdcb->fOutX = 0;
2602 /*
2603         lpdcb->XonChar = 
2604         lpdcb->XoffChar = 
2605  */
2606         lpdcb->XonLim = 10;
2607         lpdcb->XoffLim = 10;
2608
2609         commerror = 0;
2610
2611         TRACE("OK\n");
2612  
2613         TRACE("bytesize %d baudrate %ld fParity %d Parity %d stopbits %d\n",
2614               lpdcb->ByteSize,lpdcb->BaudRate,lpdcb->fParity, lpdcb->Parity,
2615               (lpdcb->StopBits == ONESTOPBIT)?1:
2616               (lpdcb->StopBits == TWOSTOPBITS)?2:0);
2617         TRACE("%s %s\n",(lpdcb->fInX)?"IXON":"~IXON",
2618               (lpdcb->fOutX)?"IXOFF":"~IXOFF");
2619 #ifdef CRTSCTS
2620         if (    lpdcb->fOutxCtsFlow                     ||
2621                 lpdcb->fDtrControl == DTR_CONTROL_ENABLE||
2622                 lpdcb->fRtsControl == RTS_CONTROL_ENABLE
2623                 ) 
2624           TRACE("CRTSCTS\n");
2625         
2626         if (lpdcb->fDtrControl == DTR_CONTROL_DISABLE)
2627           TRACE("~CRTSCTS\n");
2628         
2629 #endif  
2630         return TRUE;
2631 }
2632
2633 /*****************************************************************************
2634  *      TransmitCommChar        (KERNEL32.697)
2635  *
2636  *  Transmits a single character in front of any pending characters in the
2637  *  output buffer.  Usually used to send an interrupt character to a host.
2638  *
2639  * RETURNS
2640  *
2641  *  True if the call succeeded, false if the previous command character to the
2642  *  same device has not been sent yet the handle is bad etc.
2643  *
2644  * BUGS
2645  *
2646  *  Stub.
2647  */
2648 BOOL WINAPI TransmitCommChar(
2649     HANDLE hComm,      /* [in] The communication device in need of a command character. */
2650     CHAR   chTransmit) /* [in] The character to transmit. */
2651 {
2652         FIXME("(%x,'%c'), use win32 handle!\n",hComm,chTransmit);
2653         return TRUE;
2654 }
2655
2656 /*****************************************************************************
2657  *      GetCommTimeouts         (KERNEL32.288)
2658  *
2659  *  Obtains the request time out values for the communications device.
2660  *
2661  * RETURNS
2662  *
2663  *  True on success, false if communications device handle is bad
2664  *  or the target structure is null.
2665  */
2666 BOOL WINAPI GetCommTimeouts(
2667     HANDLE         hComm,      /* [in] The communications device. */
2668     LPCOMMTIMEOUTS lptimeouts) /* [out] The struct of request time outs. */
2669 {
2670     BOOL ret;
2671
2672     TRACE("(%x,%p)\n",hComm,lptimeouts);
2673
2674     if(!lptimeouts)
2675     {
2676         SetLastError(ERROR_INVALID_PARAMETER);
2677         return FALSE;
2678     }
2679
2680     SERVER_START_REQ
2681     {
2682         struct get_serial_info_request *req = server_alloc_req( sizeof(*req), 0 );
2683         req->handle = hComm;
2684         if ((ret = !server_call( REQ_GET_SERIAL_INFO )))
2685         {
2686             lptimeouts->ReadIntervalTimeout         = req->readinterval;
2687             lptimeouts->ReadTotalTimeoutMultiplier  = req->readmult;
2688             lptimeouts->ReadTotalTimeoutConstant    = req->readconst;
2689             lptimeouts->WriteTotalTimeoutMultiplier = req->writemult;
2690             lptimeouts->WriteTotalTimeoutConstant   = req->writeconst;
2691         }
2692     }
2693     SERVER_END_REQ;
2694     return ret;
2695 }
2696
2697 /*****************************************************************************
2698  *      SetCommTimeouts         (KERNEL32.620)
2699  *
2700  * Sets the timeouts used when reading and writing data to/from COMM ports.
2701  *
2702  * ReadIntervalTimeout 
2703  *     - converted and passes to linux kernel as c_cc[VTIME]
2704  * ReadTotalTimeoutMultiplier, ReadTotalTimeoutConstant
2705  *     - used in ReadFile to calculate GetOverlappedResult's timeout
2706  * WriteTotalTimeoutMultiplier, WriteTotalTimeoutConstant
2707  *     - used in WriteFile to calculate GetOverlappedResult's timeout
2708  *
2709  * RETURNS
2710  *
2711  *  True if the time outs were set, false otherwise.
2712  */
2713 BOOL WINAPI SetCommTimeouts(
2714     HANDLE hComm,              /* [in] handle of COMM device */
2715     LPCOMMTIMEOUTS lptimeouts) /* [in] pointer to COMMTIMEOUTS structure */
2716 {
2717     BOOL ret;
2718     int fd;
2719     struct termios tios;
2720
2721     TRACE("(%x,%p)\n",hComm,lptimeouts);
2722
2723     if(!lptimeouts)
2724     {
2725         SetLastError(ERROR_INVALID_PARAMETER);
2726         return FALSE;
2727     }
2728
2729     SERVER_START_REQ
2730     {
2731         struct set_serial_info_request *req = server_alloc_req( sizeof(*req), 0 );
2732         req->handle       = hComm;
2733         req->flags        = SERIALINFO_SET_TIMEOUTS;
2734         req->readinterval = lptimeouts->ReadIntervalTimeout ;
2735         req->readmult     = lptimeouts->ReadTotalTimeoutMultiplier ;
2736         req->readconst    = lptimeouts->ReadTotalTimeoutConstant ;
2737         req->writemult    = lptimeouts->WriteTotalTimeoutMultiplier ;
2738         req->writeconst   = lptimeouts->WriteTotalTimeoutConstant ;
2739         ret = !server_call( REQ_SET_SERIAL_INFO );
2740     }
2741     SERVER_END_REQ;
2742     if (!ret) return FALSE;
2743
2744     /* FIXME: move this stuff to the server */
2745     fd = FILE_GetUnixHandle( hComm, GENERIC_READ );
2746     if (fd < 0) {
2747        FIXME("no fd for handle = %0x!.\n",hComm);
2748        return FALSE;
2749     }
2750
2751     if (-1==tcgetattr(fd,&tios)) {
2752         FIXME("tcgetattr on fd %d failed!\n",fd);
2753         return FALSE;
2754     }
2755     /* VTIME is in 1/10 seconds */
2756     tios.c_cc[VTIME]= (lptimeouts->ReadIntervalTimeout+99)/100;
2757     if (-1==tcsetattr(fd,0,&tios)) {
2758         FIXME("tcsetattr on fd %d failed!\n",fd);
2759         return FALSE;
2760     }
2761     close(fd);
2762     return TRUE;
2763 }
2764
2765 /***********************************************************************
2766  *           GetCommModemStatus   (KERNEL32.285)
2767  *
2768  *  Obtains the four control register bits if supported by the hardware.
2769  *
2770  * RETURNS
2771  *
2772  *  True if the communications handle was good and for hardware that
2773  *  control register access, false otherwise.
2774  */
2775 BOOL WINAPI GetCommModemStatus(
2776     HANDLE  hFile,       /* [in] The communications device. */
2777     LPDWORD lpModemStat) /* [out] The control register bits. */
2778 {
2779         int fd,mstat, result=FALSE;
2780         
2781         *lpModemStat=0;
2782 #ifdef TIOCMGET
2783         fd = FILE_GetUnixHandle( hFile, GENERIC_READ );
2784         if(fd<0)
2785                 return FALSE;
2786         result = ioctl(fd, TIOCMGET, &mstat);
2787         close(fd);
2788         if (result == -1)
2789           {
2790             WARN("ioctl failed\n");
2791             return FALSE;
2792           }
2793 #ifdef TIOCM_CTS
2794         if (mstat & TIOCM_CTS)
2795             *lpModemStat |= MS_CTS_ON;
2796 #endif
2797 #ifdef TIOCM_DSR
2798         if (mstat & TIOCM_DSR)
2799           *lpModemStat |= MS_DSR_ON;
2800 #endif
2801 #ifdef TIOCM_RNG
2802         if (mstat & TIOCM_RNG)
2803           *lpModemStat |= MS_RING_ON;
2804 #endif
2805 #ifdef TIOCM_CAR
2806         /*FIXME:  Not really sure about RLSD  UB 990810*/
2807         if (mstat & TIOCM_CAR)
2808           *lpModemStat |= MS_RLSD_ON;
2809 #endif
2810         TRACE("%04x -> %s%s%s%s\n", mstat,
2811               (*lpModemStat &MS_RLSD_ON)?"MS_RLSD_ON ":"",
2812               (*lpModemStat &MS_RING_ON)?"MS_RING_ON ":"",
2813               (*lpModemStat &MS_DSR_ON)?"MS_DSR_ON ":"",
2814               (*lpModemStat &MS_CTS_ON)?"MS_CTS_ON ":"");
2815         return TRUE;
2816 #else
2817         return FALSE;
2818 #endif
2819 }
2820
2821 VOID COMM_WaitCommEventService(void **args)
2822 {
2823     LPOVERLAPPED lpOverlapped = (LPOVERLAPPED)args[0];
2824     LPDWORD buffer = (LPDWORD)args[1];
2825     DWORD events = (DWORD)args[2];
2826
2827     TRACE("overlapped %p wait complete %p <- %lx\n",lpOverlapped,buffer,events);
2828     if(buffer)
2829         *buffer = events;
2830  
2831     lpOverlapped->Internal = STATUS_SUCCESS;
2832     SetEvent( lpOverlapped->hEvent);
2833     CloseHandle(lpOverlapped->InternalHigh);
2834 }
2835
2836 /***********************************************************************
2837  *           WaitCommEvent   (KERNEL32.719)
2838  *
2839  * Wait until something interesting happens on a COMM port.
2840  * Interesting things (events) are set by calling SetCommMask before
2841  * this function is called.
2842  *
2843  * RETURNS:
2844  *   TRUE if successful
2845  *   FALSE if failure
2846  *
2847  *   The set of detected events will be written to *lpdwEventMask
2848  *   ERROR_IO_PENDING will be returned the overlapped structure was passed
2849  *
2850  * BUGS:
2851  *  Only supports EV_RXCHAR and EV_TXEMPTY
2852  */
2853 BOOL WINAPI WaitCommEvent(
2854     HANDLE hFile,              /* [in] handle of comm port to wait for */
2855     LPDWORD lpdwEvents,        /* [out] event(s) that were detected */
2856     LPOVERLAPPED lpOverlapped) /* [in/out] for Asynchronous waiting */
2857 {
2858     OVERLAPPED ov;
2859     LPOVERLAPPED lpov;
2860     int ret;
2861
2862     TRACE("(%x %p %p )\n",hFile, lpdwEvents,lpOverlapped);
2863
2864     /* if there is no overlapped structure, create our own */
2865     if(!lpOverlapped)
2866     {
2867         ov.hEvent = CreateEventA(NULL,FALSE,FALSE,NULL);
2868         lpov = &ov;
2869     }
2870     else
2871         lpov = lpOverlapped;
2872
2873     /* check that the overlapped structure has a valid event flag */
2874     if ( (lpov->hEvent==0) || (lpov->hEvent == INVALID_HANDLE_VALUE) )
2875     {
2876         ERR("Couldn't create Event flag for Overlapped structure\n");
2877         SetLastError(ERROR_INVALID_PARAMETER);
2878         return FALSE;
2879     }
2880
2881     ResetEvent(lpov->hEvent);
2882
2883     lpov->Internal = STATUS_PENDING;
2884     lpov->InternalHigh = 0;
2885     lpov->Offset = 0;
2886     lpov->OffsetHigh = 0;
2887
2888     /* start an ASYNCHRONOUS WaitCommEvent */
2889     SERVER_START_REQ
2890     {
2891         struct create_async_request *req = server_alloc_req( sizeof(*req), 0 );
2892
2893         req->file_handle = hFile;
2894         req->overlapped  = lpov;
2895         req->buffer = lpdwEvents;
2896         req->count = 0;
2897         req->func = COMM_WaitCommEventService;
2898         req->type = ASYNC_TYPE_WAIT;
2899
2900         ret=server_call( REQ_CREATE_ASYNC );
2901
2902         lpov->InternalHigh = req->ov_handle;
2903     }
2904     SERVER_END_REQ;
2905
2906     if(ret)
2907     {
2908         if(!lpOverlapped)
2909             CloseHandle(lpov->hEvent);
2910         TRACE("server call failed.\n");
2911         return FALSE;
2912     }
2913
2914     /* activate the overlapped operation */
2915     lpov->Internal = STATUS_PENDING;
2916
2917     /* wait ourselves if the caller didn't give us an overlapped struct */
2918     if(!lpOverlapped)
2919     {
2920         GetOverlappedResult(hFile, lpov, NULL, TRUE);
2921         CloseHandle(lpov->hEvent);
2922         lpov->hEvent=0;
2923     }
2924     else
2925     {
2926         /* caller wants overlapped I/O using GetOverlapped result */
2927         SetLastError(ERROR_IO_PENDING);
2928         return FALSE;
2929     }
2930
2931     return TRUE;
2932 }
2933
2934 /***********************************************************************
2935  *           GetCommProperties   (KERNEL32.286)
2936  *
2937  * This function fills in a structure with the capabilities of the 
2938  * communications port driver.
2939  *
2940  * RETURNS
2941  *
2942  *  TRUE on success, FALSE on failure
2943  *  If successful, the lpCommProp structure be filled in with
2944  *  properties of the comm port.
2945  */
2946 BOOL WINAPI GetCommProperties(
2947     HANDLE hFile,          /* [in] handle of the comm port */
2948     LPCOMMPROP lpCommProp) /* [out] pointer to struct to be filled */
2949 {
2950     FIXME("(%d %p )\n",hFile,lpCommProp);
2951     if(!lpCommProp)
2952         return FALSE;
2953
2954     /*
2955      * These values should be valid for LINUX's serial driver
2956      * FIXME: Perhaps they deserve an #ifdef LINUX
2957      */
2958     memset(lpCommProp,0,sizeof(COMMPROP));
2959     lpCommProp->wPacketLength       = 1;
2960     lpCommProp->wPacketVersion      = 1;
2961     lpCommProp->dwServiceMask       = SP_SERIALCOMM;
2962     lpCommProp->dwReserved1         = 0;
2963     lpCommProp->dwMaxTxQueue        = 4096;
2964     lpCommProp->dwMaxRxQueue        = 4096;
2965     lpCommProp->dwMaxBaud           = BAUD_115200;
2966     lpCommProp->dwProvSubType       = PST_RS232;
2967     lpCommProp->dwProvCapabilities  = PCF_DTRDSR | PCF_PARITY_CHECK | PCF_RTSCTS ;
2968     lpCommProp->dwSettableParams    = SP_BAUD | SP_DATABITS | SP_HANDSHAKING | 
2969                                       SP_PARITY | SP_PARITY_CHECK | SP_STOPBITS ;
2970     lpCommProp->dwSettableBaud      = BAUD_075 | BAUD_110 | BAUD_134_5 | BAUD_150 |
2971                 BAUD_300 | BAUD_600 | BAUD_1200 | BAUD_1800 | BAUD_2400 | BAUD_4800 |
2972                 BAUD_9600 | BAUD_19200 | BAUD_38400 | BAUD_57600 | BAUD_115200 ;
2973     lpCommProp->wSettableData       = DATABITS_5 | DATABITS_6 | DATABITS_7 | DATABITS_8 ;
2974     lpCommProp->wSettableStopParity = STOPBITS_10 | STOPBITS_15 | STOPBITS_20 | 
2975                 PARITY_NONE | PARITY_ODD |PARITY_EVEN | PARITY_MARK | PARITY_SPACE;
2976     lpCommProp->dwCurrentTxQueue    = lpCommProp->dwMaxTxQueue;
2977     lpCommProp->dwCurrentRxQueue    = lpCommProp->dwMaxRxQueue;
2978
2979     return TRUE;
2980 }
2981
2982 /***********************************************************************
2983  * FIXME:
2984  * The functionality of CommConfigDialogA, GetDefaultCommConfig and
2985  * SetDefaultCommConfig is implemented in a DLL (usually SERIALUI.DLL).
2986  * This is dependent on the type of COMM port, but since it is doubtful
2987  * anybody will get around to implementing support for fancy serial
2988  * ports in WINE, this is hardcoded for the time being.  The name of 
2989  * this DLL should be stored in and read from the system registry in 
2990  * the hive HKEY_LOCAL_MACHINE, key
2991  * System\\CurrentControlSet\\Services\\Class\\Ports\\????
2992  * where ???? is the port number... that is determined by PNP
2993  * The DLL should be loaded when the COMM port is opened, and closed 
2994  * when the COMM port is closed. - MJM 20 June 2000
2995  ***********************************************************************/
2996 static CHAR lpszSerialUI[] = "serialui.dll";
2997
2998
2999 /***********************************************************************
3000  *           CommConfigDialogA   (KERNEL32.140)
3001  *
3002  * Raises a dialog that allows the user to configure a comm port.
3003  * Fills the COMMCONFIG struct with information specified by the user.
3004  * This function should call a similar routine in the COMM driver...
3005  *
3006  * RETURNS
3007  *
3008  *  TRUE on success, FALSE on failure
3009  *  If successful, the lpCommConfig structure will contain a new
3010  *  configuration for the comm port, as specified by the user.
3011  *
3012  * BUGS
3013  *  The library with the CommConfigDialog code is never unloaded.
3014  * Perhaps this should be done when the comm port is closed?
3015  */
3016 BOOL WINAPI CommConfigDialogA(
3017     LPCSTR lpszDevice,         /* [in] name of communications device */
3018     HANDLE hWnd,               /* [in] parent window for the dialog */
3019     LPCOMMCONFIG lpCommConfig) /* [out] pointer to struct to fill */
3020 {
3021     FARPROC lpfnCommDialog;
3022     HMODULE hConfigModule;
3023     BOOL r;
3024
3025     TRACE("(%p %x %p)\n",lpszDevice, hWnd, lpCommConfig);
3026
3027     hConfigModule = LoadLibraryA(lpszSerialUI);
3028     if(!hConfigModule)
3029         return FALSE;
3030
3031     lpfnCommDialog = GetProcAddress(hConfigModule, (LPCSTR)3L);
3032
3033     if(!lpfnCommDialog)
3034         return FALSE;
3035
3036     r = lpfnCommDialog(lpszDevice,hWnd,lpCommConfig);
3037
3038     /* UnloadLibrary(hConfigModule); */
3039
3040     return r;
3041 }
3042
3043 /***********************************************************************
3044  *           CommConfigDialogW   (KERNEL32.141)
3045  *
3046  * see CommConfigDialogA for more info
3047  */
3048 BOOL WINAPI CommConfigDialogW(
3049     LPCWSTR lpszDevice,        /* [in] name of communications device */
3050     HANDLE hWnd,               /* [in] parent window for the dialog */
3051     LPCOMMCONFIG lpCommConfig) /* [out] pointer to struct to fill */
3052 {
3053     BOOL r;
3054     LPSTR lpDeviceA;
3055
3056     lpDeviceA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpszDevice );
3057     if(lpDeviceA)
3058         return FALSE;
3059     r = CommConfigDialogA(lpDeviceA,hWnd,lpCommConfig);
3060     HeapFree( GetProcessHeap(), 0, lpDeviceA );
3061     return r;
3062 }
3063
3064 /***********************************************************************
3065  *           GetCommConfig     (KERNEL32.283)
3066  *
3067  * Fill in the COMMCONFIG structure for the comm port hFile
3068  *
3069  * RETURNS
3070  *
3071  *  TRUE on success, FALSE on failure
3072  *  If successful, lpCommConfig contains the comm port configuration.
3073  *
3074  * BUGS
3075  *
3076  *  The signature is missing a the parameter for the size of the COMMCONFIG
3077  *  structure/buffer it should be
3078  *  BOOL WINAPI GetCommConfig(HANDLE hFile,LPCOMMCONFIG lpCommConfig,LPDWORD lpdwSize)
3079  */
3080 BOOL WINAPI GetCommConfig(
3081     HANDLE       hFile,        /* [in] The communications device. */
3082     LPCOMMCONFIG lpCommConfig) /* [out] The communications configuration of the device (if it fits). */
3083 #if 0 /* FIXME: Why is this "commented" out? */
3084     LPDWORD      lpdwSize)     /* [in/out] Initially the size of the configuration buffer/structure,
3085                                   afterwards the number of bytes copied to the buffer or 
3086                                   the needed size of the buffer. */
3087 #endif
3088 {
3089     BOOL r;
3090
3091     TRACE("(%x %p)\n",hFile,lpCommConfig);
3092
3093     if(lpCommConfig == NULL)
3094         return FALSE;
3095
3096     lpCommConfig->dwSize = sizeof(COMMCONFIG);
3097     lpCommConfig->wVersion = 1;
3098     lpCommConfig->wReserved = 0;
3099     r = GetCommState(hFile,&lpCommConfig->dcb);
3100     lpCommConfig->dwProviderSubType = PST_RS232;
3101     lpCommConfig->dwProviderOffset = 0;
3102     lpCommConfig->dwProviderSize = 0;
3103
3104     return r;
3105 }
3106
3107 /***********************************************************************
3108  *           SetCommConfig     (KERNEL32.617)
3109  *
3110  *  Sets the configuration of the commications device.
3111  *
3112  * RETURNS
3113  *
3114  *  True on success, false if the handle was bad is not a communications device.
3115  */
3116 BOOL WINAPI SetCommConfig(
3117     HANDLE       hFile,        /* [in] The communications device. */
3118     LPCOMMCONFIG lpCommConfig) /* [in] The desired configuration. */
3119 {
3120     TRACE("(%x %p)\n",hFile,lpCommConfig);
3121     return SetCommState(hFile,&lpCommConfig->dcb);
3122 }
3123
3124 /***********************************************************************
3125  *           SetDefaultCommConfigA   (KERNEL32.638)
3126  *
3127  *  Initializes the default configuration for the specified communication
3128  *  device. (ascii)
3129  *
3130  * RETURNS
3131  *
3132  *  True if the device was found and the defaults set, false otherwise
3133  */
3134 BOOL WINAPI SetDefaultCommConfigA(
3135     LPCSTR       lpszDevice,   /* [in] The ascii name of the device targeted for configuration. */
3136     LPCOMMCONFIG lpCommConfig, /* [in] The default configuration for the device. */
3137     DWORD        dwSize)       /* [in] The number of bytes in the configuration structure. */
3138 {
3139     FARPROC lpfnSetDefaultCommConfig;
3140     HMODULE hConfigModule;
3141     BOOL r;
3142
3143     TRACE("(%p %p %lx)\n",lpszDevice, lpCommConfig, dwSize);
3144
3145     hConfigModule = LoadLibraryA(lpszSerialUI);
3146     if(!hConfigModule)
3147         return FALSE;
3148
3149     lpfnSetDefaultCommConfig = GetProcAddress(hConfigModule, (LPCSTR)4L);
3150
3151     if(! lpfnSetDefaultCommConfig)
3152         return TRUE;
3153
3154     r = lpfnSetDefaultCommConfig(lpszDevice, lpCommConfig, dwSize);
3155
3156     /* UnloadLibrary(hConfigModule); */
3157
3158     return r;
3159 }
3160
3161
3162 /***********************************************************************
3163  *           SetDefaultCommConfigW     (KERNEL32.639)
3164  *
3165  *  Initializes the default configuration for the specified
3166  *  communication device. (unicode)
3167  *
3168  * RETURNS
3169  *
3170  */
3171 BOOL WINAPI SetDefaultCommConfigW(
3172     LPCWSTR      lpszDevice,   /* [in] The unicode name of the device targeted for configuration. */
3173     LPCOMMCONFIG lpCommConfig, /* [in] The default configuration for the device. */
3174     DWORD        dwSize)       /* [in] The number of bytes in the configuration structure. */
3175 {
3176     BOOL r;
3177     LPSTR lpDeviceA;
3178
3179     TRACE("(%s %p %lx)\n",debugstr_w(lpszDevice),lpCommConfig,dwSize);
3180
3181     lpDeviceA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpszDevice );
3182     if(lpDeviceA)
3183         return FALSE;
3184     r = SetDefaultCommConfigA(lpDeviceA,lpCommConfig,dwSize);
3185     HeapFree( GetProcessHeap(), 0, lpDeviceA );
3186     return r;
3187 }
3188
3189
3190 /***********************************************************************
3191  *           GetDefaultCommConfigA   (KERNEL32.313)
3192  *
3193  *   Acquires the default configuration of the specified communication device. (unicode)
3194  *
3195  *  RETURNS
3196  *
3197  *   True on successful reading of the default configuration,
3198  *   if the device is not found or the buffer is too small.
3199  */
3200 BOOL WINAPI GetDefaultCommConfigA(
3201     LPCSTR       lpszName, /* [in] The ascii name of the device targeted for configuration. */
3202     LPCOMMCONFIG lpCC,     /* [out] The default configuration for the device. */
3203     LPDWORD      lpdwSize) /* [in/out] Initially the size of the default configuration buffer,
3204                               afterwards the number of bytes copied to the buffer or
3205                               the needed size of the buffer. */
3206 {
3207      LPDCB lpdcb = &(lpCC->dcb);
3208      char  temp[40];
3209
3210      if (strncasecmp(lpszName,"COM",3)) {
3211         ERR("not implemented for <%s>\n", lpszName);
3212         return FALSE;
3213      }
3214
3215      if (!ValidCOMPort(lpszName[3]-'1'))
3216         return FALSE;
3217
3218      TRACE("(%s %p %ld)\n", lpszName, lpCC, *lpdwSize );
3219      if (*lpdwSize < sizeof(COMMCONFIG)) {
3220          *lpdwSize = sizeof(COMMCONFIG);
3221          return FALSE;
3222        }
3223
3224      *lpdwSize = sizeof(COMMCONFIG);
3225
3226      lpCC->dwSize = sizeof(COMMCONFIG);
3227      lpCC->wVersion = 1;
3228      lpCC->dwProviderSubType = PST_RS232;
3229      lpCC->dwProviderOffset = 0L;
3230      lpCC->dwProviderSize = 0L;
3231
3232      (void) sprintf( temp, "COM%c:38400,n,8,1", lpszName[3]);
3233      FIXME("setting %s as default\n", temp);
3234
3235      return BuildCommDCBA( temp, lpdcb);
3236 }
3237
3238 /**************************************************************************
3239  *         GetDefaultCommConfigW                (KERNEL32.314)
3240  *
3241  *   Acquires the default configuration of the specified communication device. (unicode)
3242  *
3243  *  RETURNS
3244  *
3245  *   True on successful reading of the default configuration,
3246  *   if the device is not found or the buffer is too small.
3247  */
3248 BOOL WINAPI GetDefaultCommConfigW(
3249     LPCWSTR      lpszName, /* [in] The unicode name of the device targeted for configuration. */
3250     LPCOMMCONFIG lpCC,     /* [out] The default configuration for the device. */
3251     LPDWORD      lpdwSize) /* [in/out] Initially the size of the default configuration buffer,
3252                               afterwards the number of bytes copied to the buffer or
3253                               the needed size of the buffer. */
3254 {
3255         BOOL ret = FALSE;
3256         LPSTR   lpszNameA;
3257
3258         TRACE("(%p,%p,%ld)\n",lpszName,lpCC,*lpdwSize);
3259         lpszNameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpszName );
3260         if (lpszNameA)
3261         {
3262         ret=GetDefaultCommConfigA(lpszNameA,lpCC,lpdwSize);
3263         HeapFree( GetProcessHeap(), 0, lpszNameA );
3264         }
3265         return ret;
3266 }
3267