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