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