Allow the file names and paths for the registry files (user.reg and
[wine] / misc / comm.c
1  /*
2  * DEC 93 Erik Bos <erik@xs4all.nl>
3  *
4  * Copyright 1996 Marcus Meissner
5  * FIXME: use HFILEs instead of unixfds
6  *        the win32 functions here get HFILEs already.
7  *
8  * May 26, 1997.  Fixes and comments by Rick Richardson <rick@dgii.com> [RER]
9  * - ptr->fd wasn't getting cleared on close.
10  * - GetCommEventMask() and GetCommError() didn't do much of anything.
11  *   IMHO, they are still wrong, but they at least implement the RXCHAR
12  *   event and return I/O queue sizes, which makes the app I'm interested
13  *   in (analog devices EZKIT DSP development system) work.
14  *
15  * August 12, 1997.  Take a bash at SetCommEventMask - Lawson Whitney
16  *                                     <lawson_whitney@juno.com>
17  * July 6, 1998. Fixes and comments by Valentijn Sessink
18  *                                     <vsessink@ic.uva.nl> [V]
19  *  I only quick-fixed an error for the output buffers. The thing is this: if a
20  * WinApp starts using serial ports, it calls OpenComm, asking it to open two
21  * buffers, cbInQueue and cbOutQueue size, to hold data to/from the serial
22  * ports. Wine OpenComm only returns "OK". Now the kernel buffer size for
23  * serial communication is only 4096 bytes large. Error: (App asks for
24  * a 104,000 bytes size buffer, Wine returns "OK", App asks "How many char's
25  * are in the buffer", Wine returns "4000" and App thinks "OK, another
26  * 100,000 chars left, good!")
27  * The solution below is a bad but working quickfix for the transmit buffer:
28  * the cbInQueue is saved in a variable; when the program asks how many chars
29  * there are in the buffer, GetCommError returns # in buffer PLUS
30  * the additional (cbOutQeueu - 4096), which leaves the application thinking
31  * "wow, almost full".
32  * Sorry for the rather chatty explanation - but I think comm.c needs to be
33  * redefined with real working buffers make it work; maybe these comments are
34  * of help.
35  * Oktober 98, Rein Klazes [RHK]
36  * A program that wants to monitor the modem status line (RLSD/DCD) may
37  * poll the modem status register in the commMask structure. I update the bit
38  * in GetCommError, waiting for an implementation of communication events.
39  * 
40  */
41
42 #include "config.h"
43
44 #include <stdlib.h>
45 #include <termios.h>
46 #include <fcntl.h>
47 #include <string.h>
48 #ifdef HAVE_STRINGS_H
49 # include <strings.h>
50 #endif
51 #include <errno.h>
52 #include <ctype.h>
53 #include <sys/stat.h>
54 #ifdef HAVE_SYS_FILIO_H
55 # include <sys/filio.h>
56 #endif
57 #include <sys/ioctl.h>
58 #include <unistd.h>
59
60 #include "wine/winuser16.h"
61 #include "comm.h"
62 #ifdef HAVE_SYS_MODEM_H
63 # include <sys/modem.h>
64 #endif
65 #ifdef HAVE_SYS_STRTIO_H
66 # include <sys/strtio.h>
67 #endif
68 #include "heap.h"
69 #include "options.h"
70 #include "debug.h"
71
72 #include "server/request.h"
73 #include "server.h"
74 #include "process.h"
75 #include "winerror.h"
76
77 #ifndef TIOCINQ
78 #define TIOCINQ FIONREAD
79 #endif
80 #define COMM_MSR_OFFSET  35       /* see knowledge base Q101417 */
81 /*
82  * [RER] These are globals are wrong.  They should be in DosDeviceStruct
83  * on a per port basis.
84  */
85 int commerror = 0, eventmask = 0;
86
87 /*
88  * [V] If above globals are wrong, the one below will be wrong as well. It
89  * should probably be in the DosDeviceStruct on per port basis too.
90 */
91 int iGlobalOutQueueFiller;
92
93 #define SERIAL_XMIT_SIZE 4096
94
95 struct DosDeviceStruct COM[MAX_PORTS];
96 struct DosDeviceStruct LPT[MAX_PORTS];
97 /* pointers to unknown(==undocumented) comm structure */ 
98 LPCVOID *unknown[MAX_PORTS];
99 /* save terminal states */
100 static struct termios m_stat[MAX_PORTS];
101
102 void COMM_Init(void)
103 {
104         int x;
105         char option[10], temp[256], *btemp;
106         struct stat st;
107
108         for (x=0; x!=MAX_PORTS; x++) {
109                 strcpy(option,"COMx");
110                 option[3] = '1' + x;
111                 option[4] = '\0';
112
113                 PROFILE_GetWineIniString( "serialports", option, "*",
114                                           temp, sizeof(temp) );
115                 if (!strcmp(temp, "*") || *temp == '\0') 
116                         COM[x].devicename = NULL;
117                 else {
118                         btemp = strchr(temp,',');
119                         if (btemp != NULL) {
120                                 *btemp++ = '\0';
121                                 COM[x].baudrate = atoi(btemp);
122                         } else {
123                                 COM[x].baudrate = -1;
124                         }
125                         stat(temp, &st);
126                         if (!S_ISCHR(st.st_mode)) 
127                                 WARN(comm,"Can't use `%s' as %s !\n", temp, option);
128                         else
129                                 if ((COM[x].devicename = malloc(strlen(temp)+1)) == NULL) 
130                                         WARN(comm,"Can't malloc for device info!\n");
131                                 else {
132                                         COM[x].fd = 0;
133                                         strcpy(COM[x].devicename, temp);
134                                 }
135                 TRACE(comm, "%s = %s\n", option, COM[x].devicename);
136                 }
137
138                 strcpy(option, "LPTx");
139                 option[3] = '1' + x;
140                 option[4] = '\0';
141
142                 PROFILE_GetWineIniString( "parallelports", option, "*",
143                                           temp, sizeof(temp) );
144                 if (!strcmp(temp, "*") || *temp == '\0')
145                         LPT[x].devicename = NULL;
146                 else {
147                         stat(temp, &st);
148                         if (!S_ISCHR(st.st_mode)) 
149                                 WARN(comm,"Can't use `%s' as %s !\n", temp, option);
150                         else 
151                                 if ((LPT[x].devicename = malloc(strlen(temp)+1)) == NULL) 
152                                         WARN(comm,"Can't malloc for device info!\n");
153                                 else {
154                                         LPT[x].fd = 0;
155                                         strcpy(LPT[x].devicename, temp);
156                                 }
157                 TRACE(comm, "%s = %s\n", option, LPT[x].devicename);
158                 }
159
160         }
161 }
162
163
164 struct DosDeviceStruct *GetDeviceStruct(int fd)
165 {
166         int x;
167         
168         for (x=0; x!=MAX_PORTS; x++) {
169             if (COM[x].fd == fd)
170                 return &COM[x];
171             if (LPT[x].fd == fd)
172                 return &LPT[x];
173         }
174
175         return NULL;
176 }
177
178 int    GetCommPort(int fd)
179 {
180         int x;
181         
182         for (x=0; x<MAX_PORTS; x++) {
183              if (COM[x].fd == fd)
184                  return x;
185        }
186        
187        return -1;
188
189
190 int ValidCOMPort(int x)
191 {
192         return(x < MAX_PORTS ? (int) COM[x].devicename : 0); 
193 }
194
195 int ValidLPTPort(int x)
196 {
197         return(x < MAX_PORTS ? (int) LPT[x].devicename : 0); 
198 }
199
200 int WinError(void)
201 {
202         TRACE(comm, "errno = %d\n", errno);
203         switch (errno) {
204                 default:
205                         return CE_IOE;
206                 }
207 }
208
209 /**************************************************************************
210  *         BuildCommDCB         (USER.213)
211  */
212 BOOL16 WINAPI BuildCommDCB16(LPCSTR device, LPDCB16 lpdcb)
213 {
214         /* "COM1:9600,n,8,1"    */
215         /*  012345              */
216         int port;
217         char *ptr, temp[256];
218
219         TRACE(comm, "(%s), ptr %p\n", device, lpdcb);
220         commerror = 0;
221
222         if (!lstrncmpiA(device,"COM",3)) {
223                 port = device[3] - '0';
224         
225
226                 if (port-- == 0) {
227                         ERR(comm, "BUG ! COM0 can't exists!.\n");
228                         commerror = IE_BADID;
229                 }
230
231                 if (!ValidCOMPort(port)) {
232                         commerror = IE_BADID;
233                         return -1;
234                 }
235                 
236                 memset(lpdcb, 0, sizeof(DCB16)); /* initialize */
237
238                 if (!COM[port].fd) {
239                     OpenComm16(device, 0, 0);
240                 }
241                 lpdcb->Id = COM[port].fd;
242                 
243                 if (!*(device+4))
244                         return 0;
245
246                 if (*(device+4) != ':')
247                         return -1;
248                 
249                 strcpy(temp,device+5);
250                 ptr = strtok(temp, ", "); 
251
252                 if (COM[port].baudrate > 0)
253                         lpdcb->BaudRate = COM[port].baudrate;
254                 else
255                         lpdcb->BaudRate = atoi(ptr);
256                 TRACE(comm,"baudrate (%d)\n", lpdcb->BaudRate);
257
258                 ptr = strtok(NULL, ", ");
259                 if (islower(*ptr))
260                         *ptr = toupper(*ptr);
261
262                 TRACE(comm,"parity (%c)\n", *ptr);
263                 lpdcb->fParity = TRUE;
264                 switch (*ptr) {
265                         case 'N':
266                                 lpdcb->Parity = NOPARITY;
267                                 lpdcb->fParity = FALSE;
268                                 break;                  
269                         case 'E':
270                                 lpdcb->Parity = EVENPARITY;
271                                 break;                  
272                         case 'M':
273                                 lpdcb->Parity = MARKPARITY;
274                                 break;                  
275                         case 'O':
276                                 lpdcb->Parity = ODDPARITY;
277                                 break;                  
278                         default:
279                                 WARN(comm,"Unknown parity `%c'!\n", *ptr);
280                                 return -1;
281                 }
282
283                 ptr = strtok(NULL, ", "); 
284                 TRACE(comm, "charsize (%c)\n", *ptr);
285                 lpdcb->ByteSize = *ptr - '0';
286
287                 ptr = strtok(NULL, ", ");
288                 TRACE(comm, "stopbits (%c)\n", *ptr);
289                 switch (*ptr) {
290                         case '1':
291                                 lpdcb->StopBits = ONESTOPBIT;
292                                 break;                  
293                         case '2':
294                                 lpdcb->StopBits = TWOSTOPBITS;
295                                 break;                  
296                         default:
297                                 WARN(comm,"Unknown # of stopbits `%c'!\n", *ptr);
298                                 return -1;
299                 }
300         }       
301
302         return 0;
303 }
304
305 /**************************************************************************
306  *         BuildCommDCBA                (KERNEL32.14)
307  */
308 BOOL WINAPI BuildCommDCBA(LPCSTR device,LPDCB lpdcb)
309 {
310         return BuildCommDCBAndTimeoutsA(device,lpdcb,NULL);
311 }
312
313 /**************************************************************************
314  *         BuildCommDCBAndTimeoutsA     (KERNEL32.15)
315  */
316 BOOL WINAPI BuildCommDCBAndTimeoutsA(LPCSTR device, LPDCB lpdcb,
317                                          LPCOMMTIMEOUTS lptimeouts)
318 {
319         int     port;
320         char    *ptr,*temp;
321
322         TRACE(comm,"(%s,%p,%p)\n",device,lpdcb,lptimeouts);
323         commerror = 0;
324
325         if (!lstrncmpiA(device,"COM",3)) {
326                 port=device[3]-'0';
327                 if (port--==0) {
328                         ERR(comm,"BUG! COM0 can't exists!.\n");
329                         return FALSE;
330                 }
331                 if (!ValidCOMPort(port))
332                         return FALSE;
333                 if (*(device+4)!=':')
334                         return FALSE;
335                 temp=(LPSTR)(device+5);
336         } else
337                 temp=(LPSTR)device;
338
339         memset(lpdcb, 0, sizeof(DCB)); /* initialize */
340
341         lpdcb->DCBlength        = sizeof(DCB);
342         if (strchr(temp,',')) { /* old style */
343                 DCB16   dcb16;
344                 BOOL16  ret;
345                 char    last=temp[strlen(temp)-1];
346
347                 ret=BuildCommDCB16(device,&dcb16);
348                 if (!ret)
349                         return FALSE;
350                 lpdcb->BaudRate         = dcb16.BaudRate;
351                 lpdcb->ByteSize         = dcb16.ByteSize;
352                 lpdcb->fBinary          = dcb16.fBinary;
353                 lpdcb->Parity           = dcb16.Parity;
354                 lpdcb->fParity          = dcb16.fParity;
355                 lpdcb->fNull            = dcb16.fNull;
356                 lpdcb->StopBits         = dcb16.StopBits;
357                 if (last == 'x') {
358                         lpdcb->fInX             = TRUE;
359                         lpdcb->fOutX            = TRUE;
360                         lpdcb->fOutxCtsFlow     = FALSE;
361                         lpdcb->fOutxDsrFlow     = FALSE;
362                         lpdcb->fDtrControl      = DTR_CONTROL_ENABLE;
363                         lpdcb->fRtsControl      = RTS_CONTROL_ENABLE;
364                 } else if (last=='p') {
365                         lpdcb->fInX             = FALSE;
366                         lpdcb->fOutX            = FALSE;
367                         lpdcb->fOutxCtsFlow     = TRUE;
368                         lpdcb->fOutxDsrFlow     = TRUE;
369                         lpdcb->fDtrControl      = DTR_CONTROL_HANDSHAKE;
370                         lpdcb->fRtsControl      = RTS_CONTROL_HANDSHAKE;
371                 } else {
372                         lpdcb->fInX             = FALSE;
373                         lpdcb->fOutX            = FALSE;
374                         lpdcb->fOutxCtsFlow     = FALSE;
375                         lpdcb->fOutxDsrFlow     = FALSE;
376                         lpdcb->fDtrControl      = DTR_CONTROL_ENABLE;
377                         lpdcb->fRtsControl      = RTS_CONTROL_ENABLE;
378                 }
379                 lpdcb->XonChar  = dcb16.XonChar;
380                 lpdcb->XoffChar = dcb16.XoffChar;
381                 lpdcb->ErrorChar= dcb16.PeChar;
382                 lpdcb->fErrorChar= dcb16.fPeChar;
383                 lpdcb->EofChar  = dcb16.EofChar;
384                 lpdcb->EvtChar  = dcb16.EvtChar;
385                 lpdcb->XonLim   = dcb16.XonLim;
386                 lpdcb->XoffLim  = dcb16.XoffLim;
387                 return TRUE;
388         }
389         ptr=strtok(temp," "); 
390         while (ptr) {
391                 DWORD   flag,x;
392
393                 flag=0;
394                 if (!strncmp("baud=",ptr,5)) {
395                         if (!sscanf(ptr+5,"%ld",&x))
396                                 WARN(comm,"Couldn't parse %s\n",ptr);
397                         lpdcb->BaudRate = x;
398                         flag=1;
399                 }
400                 if (!strncmp("stop=",ptr,5)) {
401                         if (!sscanf(ptr+5,"%ld",&x))
402                                 WARN(comm,"Couldn't parse %s\n",ptr);
403                         lpdcb->StopBits = x;
404                         flag=1;
405                 }
406                 if (!strncmp("data=",ptr,5)) {
407                         if (!sscanf(ptr+5,"%ld",&x))
408                                 WARN(comm,"Couldn't parse %s\n",ptr);
409                         lpdcb->ByteSize = x;
410                         flag=1;
411                 }
412                 if (!strncmp("parity=",ptr,7)) {
413                         lpdcb->fParity  = TRUE;
414                         switch (ptr[8]) {
415                         case 'N':case 'n':
416                                 lpdcb->fParity  = FALSE;
417                                 lpdcb->Parity   = NOPARITY;
418                                 break;
419                         case 'E':case 'e':
420                                 lpdcb->Parity   = EVENPARITY;
421                                 break;
422                         case 'O':case 'o':
423                                 lpdcb->Parity   = ODDPARITY;
424                                 break;
425                         case 'M':case 'm':
426                                 lpdcb->Parity   = MARKPARITY;
427                                 break;
428                         }
429                         flag=1;
430                 }
431                 if (!flag)
432                         ERR(comm,"Unhandled specifier '%s', please report.\n",ptr);
433                 ptr=strtok(NULL," ");
434         }
435         if (lpdcb->BaudRate==110)
436                 lpdcb->StopBits = 2;
437         return TRUE;
438 }
439
440 /**************************************************************************
441  *         BuildCommDCBAndTimeoutsW             (KERNEL32.16)
442  */
443 BOOL WINAPI BuildCommDCBAndTimeoutsW( LPCWSTR devid, LPDCB lpdcb,
444                                           LPCOMMTIMEOUTS lptimeouts )
445 {
446         LPSTR   devidA;
447         BOOL    ret;
448
449         TRACE(comm,"(%p,%p,%p)\n",devid,lpdcb,lptimeouts);
450         devidA = HEAP_strdupWtoA( GetProcessHeap(), 0, devid );
451         ret=BuildCommDCBAndTimeoutsA(devidA,lpdcb,lptimeouts);
452         HeapFree( GetProcessHeap(), 0, devidA );
453         return ret;
454 }
455
456 /**************************************************************************
457  *         BuildCommDCBW                (KERNEL32.17)
458  */
459 BOOL WINAPI BuildCommDCBW(LPCWSTR devid,LPDCB lpdcb)
460 {
461         return BuildCommDCBAndTimeoutsW(devid,lpdcb,NULL);
462 }
463
464 /*****************************************************************************
465  *      OpenComm                (USER.200)
466  */
467 INT16 WINAPI OpenComm16(LPCSTR device,UINT16 cbInQueue,UINT16 cbOutQueue)
468 {
469         int port,fd;
470
471         TRACE(comm, "%s, %d, %d\n", device, cbInQueue, cbOutQueue);
472         commerror = 0;
473
474         if (!lstrncmpiA(device,"COM",3)) {
475                 port = device[3] - '0';
476
477                 if (port-- == 0) {
478                         ERR(comm, "BUG ! COM0 doesn't exist !\n");
479                         commerror = IE_BADID;
480                 }
481                 
482                 /* to help GetCommError return left buffsize [V] */
483                 iGlobalOutQueueFiller = (cbOutQueue - SERIAL_XMIT_SIZE);
484                 if (iGlobalOutQueueFiller < 0) iGlobalOutQueueFiller = 0;
485
486                 TRACE(comm, "%s = %s\n", device, COM[port].devicename);
487
488                 if (!ValidCOMPort(port)) {
489                         commerror = IE_BADID;
490                         return -1;
491                 }
492                 if (COM[port].fd) {
493                         return COM[port].fd;
494                 }
495
496                 fd = open(COM[port].devicename, O_RDWR | O_NONBLOCK);
497                 if (fd == -1) {
498                         commerror = WinError();
499                         return -1;
500                 } else {
501                         unknown[port] = SEGPTR_ALLOC(40);
502                         bzero(unknown[port],40);
503                         COM[port].fd = fd;      
504                         /* save terminal state */
505                         tcgetattr(fd,&m_stat[port]);
506                         return fd;
507                 }
508         } 
509         else 
510         if (!lstrncmpiA(device,"LPT",3)) {
511                 port = device[3] - '0';
512         
513                 if (!ValidLPTPort(port)) {
514                         commerror = IE_BADID;
515                         return -1;
516                 }               
517                 if (LPT[port].fd) {
518                         commerror = IE_OPEN;
519                         return -1;
520                 }
521
522                 fd = open(LPT[port].devicename, O_RDWR | O_NONBLOCK, 0);
523                 if (fd == -1) {
524                         commerror = WinError();
525                         return -1;      
526                 } else {
527                         LPT[port].fd = fd;
528                         return fd;
529                 }
530         }
531         return 0;
532 }
533
534 /*****************************************************************************
535  *      CloseComm               (USER.207)
536  */
537 INT16 WINAPI CloseComm16(INT16 fd)
538 {
539         int port;
540         
541         TRACE(comm,"fd %d\n", fd);
542         if ((port = GetCommPort(fd)) !=-1) {  /* [LW]       */
543                 SEGPTR_FREE(unknown[port]); 
544                 COM[port].fd = 0;       /*  my adaptation of RER's fix   */  
545         }  else {               
546                 commerror = IE_BADID;
547                 return -1;
548         }
549
550         /* reset modem lines */
551         tcsetattr(fd,TCSANOW,&m_stat[port]);
552
553         if (close(fd) == -1) {
554                 commerror = WinError();
555                 return -1;
556         } else {
557                 commerror = 0;
558                 return 0;
559         }
560 }
561
562 /*****************************************************************************
563  *      SetCommBreak            (USER.210)
564  */
565 INT16 WINAPI SetCommBreak16(INT16 fd)
566 {
567         struct DosDeviceStruct *ptr;
568
569         TRACE(comm,"fd=%d\n", fd);
570         if ((ptr = GetDeviceStruct(fd)) == NULL) {
571                 commerror = IE_BADID;
572                 return -1;
573         }
574
575         ptr->suspended = 1;
576         commerror = 0;
577         return 0;
578 }
579
580 /*****************************************************************************
581  *      SetCommBreak            (KERNEL32.449)
582  */
583 BOOL WINAPI SetCommBreak(INT fd)
584 {
585
586         struct DosDeviceStruct *ptr;
587
588         TRACE(comm,"fd=%d\n", fd);
589         if ((ptr = GetDeviceStruct(fd)) == NULL) {
590                 commerror = IE_BADID;
591                 return FALSE;
592         }
593
594         ptr->suspended = 1;
595         commerror = 0;
596         return TRUE;
597 }
598
599 /*****************************************************************************
600  *      ClearCommBreak          (USER.211)
601  */
602 INT16 WINAPI ClearCommBreak16(INT16 fd)
603 {
604         struct DosDeviceStruct *ptr;
605
606         TRACE(comm,"fd=%d\n", fd);
607         if ((ptr = GetDeviceStruct(fd)) == NULL) {
608                 commerror = IE_BADID;
609                 return -1;
610         }
611
612         ptr->suspended = 0;
613         commerror = 0;
614         return 0;
615 }
616
617 /*****************************************************************************
618  *      ClearCommBreak          (KERNEL32.20)
619  */
620 BOOL WINAPI ClearCommBreak(INT fd)
621 {
622         struct DosDeviceStruct *ptr;
623
624         TRACE(comm,"fd=%d\n", fd);
625         if ((ptr = GetDeviceStruct(fd)) == NULL) {
626                 commerror = IE_BADID;
627                 return FALSE;
628         }
629
630         ptr->suspended = 0;
631         commerror = 0;
632         return TRUE;
633 }
634
635 /*****************************************************************************
636  *      EscapeCommFunction      (USER.214)
637  */
638 LONG WINAPI EscapeCommFunction16(UINT16 fd,UINT16 nFunction)
639 {
640         int     max;
641         struct termios port;
642
643         TRACE(comm,"fd=%d, function=%d\n", fd, nFunction);
644         if (tcgetattr(fd,&port) == -1) {
645                 commerror=WinError();   
646                 return -1;
647         }
648
649         switch (nFunction) {
650                 case RESETDEV:
651                         break;                                  
652
653                 case GETMAXCOM:
654                         for (max = MAX_PORTS;!COM[max].devicename;max--)
655                                 ;
656                         return max;
657                         break;
658
659                 case GETMAXLPT:
660                         for (max = MAX_PORTS;!LPT[max].devicename;max--)
661                                 ;
662                         return 0x80 + max;
663                         break;
664
665 #ifdef TIOCM_DTR
666                 case CLRDTR:
667                         port.c_cflag &= TIOCM_DTR;
668                         break;
669 #endif
670
671 #ifdef TIOCM_RTS
672                 case CLRRTS:
673                         port.c_cflag &= TIOCM_RTS;
674                         break;
675 #endif
676         
677 #ifdef CRTSCTS
678                 case SETDTR:
679                         port.c_cflag |= CRTSCTS;
680                         break;
681
682                 case SETRTS:
683                         port.c_cflag |= CRTSCTS;
684                         break;
685 #endif
686
687                 case SETXOFF:
688                         port.c_iflag |= IXOFF;
689                         break;
690
691                 case SETXON:
692                         port.c_iflag |= IXON;
693                         break;
694
695                 default:
696                         WARN(comm,"(fd=%d,nFunction=%d): Unknown function\n", 
697                         fd, nFunction);
698                         break;                          
699         }
700         
701         if (tcsetattr(fd, TCSADRAIN, &port) == -1) {
702                 commerror = WinError();
703                 return -1;      
704         } else {
705                 commerror = 0;
706                 return 0;
707         }
708 }
709
710 /*****************************************************************************
711  *      EscapeCommFunction      (KERNEL32.214)
712  */
713 BOOL WINAPI EscapeCommFunction(INT fd,UINT nFunction)
714 {
715         struct termios  port;
716         struct DosDeviceStruct *ptr;
717
718         TRACE(comm,"fd=%d, function=%d\n", fd, nFunction);
719         if (tcgetattr(fd,&port) == -1) {
720                 commerror=WinError();   
721                 return FALSE;
722         }
723         if ((ptr = GetDeviceStruct(fd)) == NULL) {
724                 commerror = IE_BADID;
725                 return FALSE;
726         }
727
728         switch (nFunction) {
729                 case RESETDEV:
730                         break;                                  
731
732 #ifdef TIOCM_DTR
733                 case CLRDTR:
734                         port.c_cflag &= TIOCM_DTR;
735                         break;
736 #endif
737
738 #ifdef TIOCM_RTS
739                 case CLRRTS:
740                         port.c_cflag &= TIOCM_RTS;
741                         break;
742 #endif
743         
744 #ifdef CRTSCTS
745                 case SETDTR:
746                         port.c_cflag |= CRTSCTS;
747                         break;
748
749                 case SETRTS:
750                         port.c_cflag |= CRTSCTS;
751                         break;
752 #endif
753
754                 case SETXOFF:
755                         port.c_iflag |= IXOFF;
756                         break;
757
758                 case SETXON:
759                         port.c_iflag |= IXON;
760                         break;
761                 case SETBREAK:
762                         ptr->suspended = 1;
763                         break;
764                 case CLRBREAK:
765                         ptr->suspended = 0;
766                         break;
767                 default:
768                         WARN(comm,"(fd=%d,nFunction=%d): Unknown function\n", 
769                         fd, nFunction);
770                         break;                          
771         }
772         
773         if (tcsetattr(fd, TCSADRAIN, &port) == -1) {
774                 commerror = WinError();
775                 return FALSE;   
776         } else {
777                 commerror = 0;
778                 return TRUE;
779         }
780 }
781
782 /*****************************************************************************
783  *      FlushComm       (USER.215)
784  */
785 INT16 WINAPI FlushComm16(INT16 fd,INT16 fnQueue)
786 {
787         int queue;
788
789         TRACE(comm,"fd=%d, queue=%d\n", fd, fnQueue);
790         switch (fnQueue) {
791                 case 0: queue = TCOFLUSH;
792                         break;
793                 case 1: queue = TCIFLUSH;
794                         break;
795                 default:WARN(comm,"(fd=%d,fnQueue=%d):Unknown queue\n", 
796                                 fd, fnQueue);
797                         return -1;
798                 }
799         if (tcflush(fd, queue)) {
800                 commerror = WinError();
801                 return -1;      
802         } else {
803                 commerror = 0;
804                 return 0;
805         }
806 }  
807
808 /********************************************************************
809  *      PurgeComm        (KERNEL32.557)
810  */
811 BOOL WINAPI PurgeComm( HANDLE handle, DWORD flags) 
812 {
813      int fd;
814      struct get_write_fd_request req;
815
816      TRACE(comm,"handle %d, flags %lx\n", handle, flags);
817
818      req.handle = handle;
819      CLIENT_SendRequest( REQ_GET_WRITE_FD, -1, 1, &req, sizeof(req) );
820      CLIENT_WaitReply( NULL, &fd, 0 );
821
822      if(fd<0)
823          return FALSE;
824
825      /*
826      ** not exactly sure how these are different
827      ** Perhaps if we had our own internal queues, one flushes them
828      ** and the other flushes the kernel's buffers.
829      */
830      if(flags&PURGE_TXABORT)
831      {
832          tcflush(fd,TCOFLUSH);
833      }
834      if(flags&PURGE_RXABORT)
835      {
836          tcflush(fd,TCIFLUSH);
837      }
838      if(flags&PURGE_TXCLEAR)
839      {
840          tcflush(fd,TCOFLUSH);
841      }
842      if(flags&PURGE_RXCLEAR)
843      {
844          tcflush(fd,TCIFLUSH);
845      }
846
847      return 1;
848 }
849
850 /********************************************************************
851  *      GetCommError    (USER.203)
852  */
853 INT16 WINAPI GetCommError16(INT16 fd,LPCOMSTAT16 lpStat)
854 {
855         int             temperror;
856         unsigned long   cnt;
857         int             rc;
858         
859         unsigned char *stol;
860         int act;
861         unsigned int mstat;
862         if ((act = GetCommPort(fd)) == -1) {
863             WARN(comm," fd %d not comm port\n",fd);
864             return CE_MODE;
865         }
866         stol = (unsigned char *)unknown[act] + COMM_MSR_OFFSET;
867         ioctl(fd,TIOCMGET,&mstat);
868         if( mstat&TIOCM_CAR ) 
869             *stol |= 0x80;
870         else 
871             *stol &=0x7f;
872
873         if (lpStat) {
874                 lpStat->status = 0;
875
876                 rc = ioctl(fd, TIOCOUTQ, &cnt);
877                 if (rc) WARN(comm, "Error !\n");
878                 lpStat->cbOutQue = cnt + iGlobalOutQueueFiller;
879
880                 rc = ioctl(fd, TIOCINQ, &cnt);
881                 if (rc) WARN(comm, "Error !\n");
882                 lpStat->cbInQue = cnt;
883
884                 TRACE(comm, "fd %d, error %d, lpStat %d %d %d stol %x\n",
885                              fd, commerror, lpStat->status, lpStat->cbInQue, 
886                              lpStat->cbOutQue, *stol);
887         }
888         else
889                 TRACE(comm, "fd %d, error %d, lpStat NULL stol %x\n",
890                              fd, commerror, *stol);
891
892         /*
893          * [RER] I have no idea what the following is trying to accomplish.
894          * [RER] It is certainly not what the reference manual suggests.
895          */
896         temperror = commerror;
897         commerror = 0;
898         return(temperror);
899 }
900
901 /*****************************************************************************
902  *      COMM_Handle2fd
903  *  returns a file descriptor for reading from or writing to
904  *  mode is GENERIC_READ or GENERIC_WRITE. Make sure to close
905  *  the handle afterwards!
906  */
907 int COMM_Handle2fd(HANDLE handle, int mode) {
908     struct get_read_fd_request r_req;
909     struct get_write_fd_request w_req;
910     int fd;
911
912     w_req.handle = r_req.handle = handle;
913
914     switch(mode) {
915     case GENERIC_WRITE:
916         CLIENT_SendRequest( REQ_GET_WRITE_FD, -1, 1, &w_req, sizeof(w_req) );
917         break;
918     case GENERIC_READ:
919         CLIENT_SendRequest( REQ_GET_READ_FD, -1, 1, &r_req, sizeof(r_req) );
920         break;
921     default:
922         ERR(comm,"COMM_Handle2fd: Don't know what type of fd is required.\n");
923         return -1;
924     }
925     CLIENT_WaitReply( NULL, &fd, 0 );
926
927     return fd;
928 }
929
930 /*****************************************************************************
931  *      ClearCommError  (KERNEL32.21)
932  */
933 BOOL WINAPI ClearCommError(INT handle,LPDWORD errors,LPCOMSTAT lpStat)
934 {
935     int fd;
936
937     fd=COMM_Handle2fd(handle,GENERIC_READ);
938     if(0>fd) 
939     {
940         return FALSE;
941     }
942
943     if (lpStat) 
944     {
945         lpStat->status = 0;
946
947         if(ioctl(fd, TIOCOUTQ, &lpStat->cbOutQue))
948             WARN(comm, "ioctl returned error\n");
949
950         if(ioctl(fd, TIOCINQ, &lpStat->cbInQue))
951             WARN(comm, "ioctl returned error\n");
952     }
953
954     close(fd);
955
956     TRACE(comm,"handle %d cbInQue = %ld cbOutQue = %ld\n",
957                 handle,
958                 lpStat->cbInQue,
959                 lpStat->cbOutQue);
960
961     if(errors)
962         *errors = 0;
963
964     /*
965     ** After an asynchronous write opperation, the
966     ** app will call ClearCommError to see if the
967     ** results are ready yet. It waits for ERROR_IO_PENDING
968     */
969     commerror = ERROR_IO_PENDING;
970
971     return TRUE;
972 }
973
974 /*****************************************************************************
975  *      SetCommEventMask        (USER.208)
976  */
977 SEGPTR WINAPI SetCommEventMask16(INT16 fd,UINT16 fuEvtMask)
978 {
979         unsigned char *stol;
980         int act;
981         int repid;
982         unsigned int mstat;
983         TRACE(comm,"fd %d,mask %d\n",fd,fuEvtMask);
984         eventmask |= fuEvtMask;
985         if ((act = GetCommPort(fd)) == -1) {
986             WARN(comm," fd %d not comm port\n",act);
987             return SEGPTR_GET(NULL);
988         }
989         stol = (unsigned char *)unknown[act];
990         stol += COMM_MSR_OFFSET;    
991         repid = ioctl(fd,TIOCMGET,&mstat);
992         TRACE(comm, " ioctl  %d, msr %x at %p %p\n",repid,mstat,stol,unknown[act]);
993         if ((mstat&TIOCM_CAR)) {*stol |= 0x80;}
994              else {*stol &=0x7f;}
995         TRACE(comm," modem dcd construct %x\n",*stol);
996         return SEGPTR_GET(unknown[act]);        
997 }
998
999 /*****************************************************************************
1000  *      GetCommEventMask        (USER.209)
1001  */
1002 UINT16 WINAPI GetCommEventMask16(INT16 fd,UINT16 fnEvtClear)
1003 {
1004         int     events = 0;
1005
1006         TRACE(comm, "fd %d, mask %d\n", fd, fnEvtClear);
1007
1008         /*
1009          *      Determine if any characters are available
1010          */
1011         if (fnEvtClear & EV_RXCHAR)
1012         {
1013                 int             rc;
1014                 unsigned long   cnt;
1015
1016                 rc = ioctl(fd, TIOCINQ, &cnt);
1017                 if (cnt) events |= EV_RXCHAR;
1018
1019                 TRACE(comm, "rxchar %ld\n", cnt);
1020         }
1021
1022         /*
1023          *      There are other events that need to be checked for
1024          */
1025         /* TODO */
1026
1027         TRACE(comm, "return events %d\n", events);
1028         return events;
1029
1030         /*
1031          * [RER] The following was gibberish
1032          */
1033 #if 0
1034         tempmask = eventmask;
1035         eventmask &= ~fnEvtClear;
1036         return eventmask;
1037 #endif
1038 }
1039
1040 /*****************************************************************************
1041  *      SetupComm       (KERNEL32.676)
1042  */
1043 BOOL WINAPI SetupComm( HANDLE handle, DWORD insize, DWORD outsize)
1044 {
1045     int fd;
1046
1047     FIXME(comm, "insize %ld outsize %ld unimplemented stub\n", insize, outsize);
1048     fd=COMM_Handle2fd(handle,GENERIC_WRITE);
1049     if(0>fd)
1050     {
1051         return FALSE;
1052     }
1053     close(fd);
1054     return TRUE;
1055
1056
1057 /*****************************************************************************
1058  *      GetCommMask     (KERNEL32.156)
1059  */
1060 BOOL WINAPI GetCommMask(HANDLE handle,LPDWORD evtmask)
1061 {
1062     int fd;
1063
1064     TRACE(comm, "handle %d, mask %p\n", handle, evtmask);
1065     if(0>(fd=COMM_Handle2fd(handle,GENERIC_READ))) 
1066     {
1067         return FALSE;
1068     }
1069     close(fd);
1070     *evtmask = eventmask;
1071     return TRUE;
1072 }
1073
1074 /*****************************************************************************
1075  *      SetCommMask     (KERNEL32.451)
1076  */
1077 BOOL WINAPI SetCommMask(INT handle,DWORD evtmask)
1078 {
1079     int fd;
1080
1081     TRACE(comm, "handle %d, mask %lx\n", handle, evtmask);
1082     if(0>(fd=COMM_Handle2fd(handle,GENERIC_WRITE))) {
1083         return FALSE;
1084     }
1085     close(fd);
1086     eventmask = evtmask;
1087     return TRUE;
1088 }
1089
1090 /*****************************************************************************
1091  *      SetCommState16  (USER.201)
1092  */
1093 INT16 WINAPI SetCommState16(LPDCB16 lpdcb)
1094 {
1095         struct termios port;
1096         struct DosDeviceStruct *ptr;
1097
1098         TRACE(comm, "fd %d, ptr %p\n", lpdcb->Id, lpdcb);
1099         if (tcgetattr(lpdcb->Id, &port) == -1) {
1100                 commerror = WinError(); 
1101                 return -1;
1102         }
1103
1104         port.c_cc[VMIN] = 0;
1105         port.c_cc[VTIME] = 1;
1106
1107 #ifdef IMAXBEL
1108         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|IMAXBEL);
1109 #else
1110         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR);
1111 #endif
1112         port.c_iflag |= (IGNBRK);
1113
1114         port.c_oflag &= ~(OPOST);
1115
1116         port.c_cflag &= ~(HUPCL);
1117         port.c_cflag |= CLOCAL | CREAD;
1118
1119         port.c_lflag &= ~(ICANON|ECHO|ISIG);
1120         port.c_lflag |= NOFLSH;
1121
1122         if ((ptr = GetDeviceStruct(lpdcb->Id)) == NULL) {
1123                 commerror = IE_BADID;
1124                 return -1;
1125         }
1126         if (ptr->baudrate > 0)
1127                 lpdcb->BaudRate = ptr->baudrate;
1128         TRACE(comm,"baudrate %d\n",lpdcb->BaudRate);
1129 #ifdef CBAUD
1130         port.c_cflag &= ~CBAUD;
1131         switch (lpdcb->BaudRate) {
1132                 case 110:
1133                 case CBR_110:
1134                         port.c_cflag |= B110;
1135                         break;          
1136                 case 300:
1137                 case CBR_300:
1138                         port.c_cflag |= B300;
1139                         break;          
1140                 case 600:
1141                 case CBR_600:
1142                         port.c_cflag |= B600;
1143                         break;          
1144                 case 1200:
1145                 case CBR_1200:
1146                         port.c_cflag |= B1200;
1147                         break;          
1148                 case 2400:
1149                 case CBR_2400:
1150                         port.c_cflag |= B2400;
1151                         break;          
1152                 case 4800:
1153                 case CBR_4800:
1154                         port.c_cflag |= B4800;
1155                         break;          
1156                 case 9600:
1157                 case CBR_9600:
1158                         port.c_cflag |= B9600;
1159                         break;          
1160                 case 19200:
1161                 case CBR_19200:
1162                         port.c_cflag |= B19200;
1163                         break;          
1164                 case 38400:
1165                 case CBR_38400:
1166                         port.c_cflag |= B38400;
1167                         break;          
1168 #ifdef B57600
1169                 case 57600:
1170                         port.c_cflag |= B57600;
1171                         break;          
1172 #endif
1173 #ifdef B115200
1174                 case 57601:
1175                         port.c_cflag |= B115200;
1176                         break;          
1177 #endif
1178                 default:
1179                         commerror = IE_BAUDRATE;
1180                         return -1;
1181         }
1182 #elif !defined(__EMX__)
1183         switch (lpdcb->BaudRate) {
1184                 case 110:
1185                 case CBR_110:
1186                         port.c_ospeed = B110;
1187                         break;
1188                 case 300:
1189                 case CBR_300:
1190                         port.c_ospeed = B300;
1191                         break;
1192                 case 600:
1193                 case CBR_600:
1194                         port.c_ospeed = B600;
1195                         break;
1196                 case 1200:
1197                 case CBR_1200:
1198                         port.c_ospeed = B1200;
1199                         break;
1200                 case 2400:
1201                 case CBR_2400:
1202                         port.c_ospeed = B2400;
1203                         break;
1204                 case 4800:
1205                 case CBR_4800:
1206                         port.c_ospeed = B4800;
1207                         break;
1208                 case 9600:
1209                 case CBR_9600:
1210                         port.c_ospeed = B9600;
1211                         break;
1212                 case 19200:
1213                 case CBR_19200:
1214                         port.c_ospeed = B19200;
1215                         break;
1216                 case 38400:
1217                 case CBR_38400:
1218                         port.c_ospeed = B38400;
1219                         break;
1220                 default:
1221                         commerror = IE_BAUDRATE;
1222                         return -1;
1223         }
1224         port.c_ispeed = port.c_ospeed;
1225 #endif
1226         TRACE(comm,"bytesize %d\n",lpdcb->ByteSize);
1227         port.c_cflag &= ~CSIZE;
1228         switch (lpdcb->ByteSize) {
1229                 case 5:
1230                         port.c_cflag |= CS5;
1231                         break;
1232                 case 6:
1233                         port.c_cflag |= CS6;
1234                         break;
1235                 case 7:
1236                         port.c_cflag |= CS7;
1237                         break;
1238                 case 8:
1239                         port.c_cflag |= CS8;
1240                         break;
1241                 default:
1242                         commerror = IE_BYTESIZE;
1243                         return -1;
1244         }
1245
1246         TRACE(comm,"parity %d\n",lpdcb->Parity);
1247         port.c_cflag &= ~(PARENB | PARODD);
1248         if (lpdcb->fParity)
1249                 switch (lpdcb->Parity) {
1250                         case NOPARITY:
1251                                 port.c_iflag &= ~INPCK;
1252                                 break;
1253                         case ODDPARITY:
1254                                 port.c_cflag |= (PARENB | PARODD);
1255                                 port.c_iflag |= INPCK;
1256                                 break;
1257                         case EVENPARITY:
1258                                 port.c_cflag |= PARENB;
1259                                 port.c_iflag |= INPCK;
1260                                 break;
1261                         default:
1262                                 commerror = IE_BYTESIZE;
1263                                 return -1;
1264                 }
1265         
1266
1267         TRACE(comm,"stopbits %d\n",lpdcb->StopBits);
1268
1269         switch (lpdcb->StopBits) {
1270                 case ONESTOPBIT:
1271                                 port.c_cflag &= ~CSTOPB;
1272                                 break;
1273                 case TWOSTOPBITS:
1274                                 port.c_cflag |= CSTOPB;
1275                                 break;
1276                 default:
1277                         commerror = IE_BYTESIZE;
1278                         return -1;
1279         }
1280 #ifdef CRTSCTS
1281
1282         if (lpdcb->fDtrflow || lpdcb->fRtsflow || lpdcb->fOutxCtsFlow)
1283                 port.c_cflag |= CRTSCTS;
1284
1285         if (lpdcb->fDtrDisable) 
1286                 port.c_cflag &= ~CRTSCTS;
1287 #endif  
1288         if (lpdcb->fInX)
1289                 port.c_iflag |= IXON;
1290         else
1291                 port.c_iflag &= ~IXON;
1292         if (lpdcb->fOutX)
1293                 port.c_iflag |= IXOFF;
1294         else
1295                 port.c_iflag &= ~IXOFF;
1296
1297         if (tcsetattr(lpdcb->Id, TCSADRAIN, &port) == -1) {
1298                 commerror = WinError(); 
1299                 return FALSE;
1300         } else {
1301                 commerror = 0;
1302                 return 0;
1303         }
1304 }
1305
1306 /*****************************************************************************
1307  *      SetCommState    (KERNEL32.452)
1308  */
1309 BOOL WINAPI SetCommState(INT handle,LPDCB lpdcb)
1310 {
1311      struct termios port;
1312      int fd;
1313      struct get_write_fd_request req;
1314
1315      TRACE(comm,"handle %d, ptr %p\n", handle, lpdcb);
1316
1317      req.handle = handle;
1318      CLIENT_SendRequest( REQ_GET_WRITE_FD, -1, 1, &req, sizeof(req) );
1319      CLIENT_WaitReply( NULL, &fd, 0 );
1320
1321      if(fd<0)
1322          return FALSE;
1323
1324      if (tcgetattr(fd,&port) == -1) {
1325          commerror = WinError();        
1326          return FALSE;
1327      }
1328
1329         port.c_cc[VMIN] = 0;
1330         port.c_cc[VTIME] = 1;
1331
1332 #ifdef IMAXBEL
1333         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|IMAXBEL);
1334 #else
1335         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR);
1336 #endif
1337         port.c_iflag |= (IGNBRK);
1338
1339         port.c_oflag &= ~(OPOST);
1340
1341         port.c_cflag &= ~(HUPCL);
1342         port.c_cflag |= CLOCAL | CREAD;
1343
1344         port.c_lflag &= ~(ICANON|ECHO|ISIG);
1345         port.c_lflag |= NOFLSH;
1346
1347      /*
1348      ** MJM - removed default baudrate settings
1349      ** TRACE(comm,"baudrate %ld\n",lpdcb->BaudRate);
1350      */
1351 #ifdef CBAUD
1352         port.c_cflag &= ~CBAUD;
1353         switch (lpdcb->BaudRate) {
1354                 case 110:
1355                 case CBR_110:
1356                         port.c_cflag |= B110;
1357                         break;          
1358                 case 300:
1359                 case CBR_300:
1360                         port.c_cflag |= B300;
1361                         break;          
1362                 case 600:
1363                 case CBR_600:
1364                         port.c_cflag |= B600;
1365                         break;          
1366                 case 1200:
1367                 case CBR_1200:
1368                         port.c_cflag |= B1200;
1369                         break;          
1370                 case 2400:
1371                 case CBR_2400:
1372                         port.c_cflag |= B2400;
1373                         break;          
1374                 case 4800:
1375                 case CBR_4800:
1376                         port.c_cflag |= B4800;
1377                         break;          
1378                 case 9600:
1379                 case CBR_9600:
1380                         port.c_cflag |= B9600;
1381                         break;          
1382                 case 19200:
1383                 case CBR_19200:
1384                         port.c_cflag |= B19200;
1385                         break;          
1386                 case 38400:
1387                 case CBR_38400:
1388                         port.c_cflag |= B38400;
1389                         break;          
1390                 default:
1391                         commerror = IE_BAUDRATE;
1392                         return FALSE;
1393         }
1394 #elif !defined(__EMX__)
1395         switch (lpdcb->BaudRate) {
1396                 case 110:
1397                 case CBR_110:
1398                         port.c_ospeed = B110;
1399                         break;
1400                 case 300:
1401                 case CBR_300:
1402                         port.c_ospeed = B300;
1403                         break;
1404                 case 600:
1405                 case CBR_600:
1406                         port.c_ospeed = B600;
1407                         break;
1408                 case 1200:
1409                 case CBR_1200:
1410                         port.c_ospeed = B1200;
1411                         break;
1412                 case 2400:
1413                 case CBR_2400:
1414                         port.c_ospeed = B2400;
1415                         break;
1416                 case 4800:
1417                 case CBR_4800:
1418                         port.c_ospeed = B4800;
1419                         break;
1420                 case 9600:
1421                 case CBR_9600:
1422                         port.c_ospeed = B9600;
1423                         break;
1424                 case 19200:
1425                 case CBR_19200:
1426                         port.c_ospeed = B19200;
1427                         break;
1428                 case 38400:
1429                 case CBR_38400:
1430                         port.c_ospeed = B38400;
1431                         break;
1432                 default:
1433                         commerror = IE_BAUDRATE;
1434                         return FALSE;
1435         }
1436         port.c_ispeed = port.c_ospeed;
1437 #endif
1438         TRACE(comm,"bytesize %d\n",lpdcb->ByteSize);
1439         port.c_cflag &= ~CSIZE;
1440         switch (lpdcb->ByteSize) {
1441                 case 5:
1442                         port.c_cflag |= CS5;
1443                         break;
1444                 case 6:
1445                         port.c_cflag |= CS6;
1446                         break;
1447                 case 7:
1448                         port.c_cflag |= CS7;
1449                         break;
1450                 case 8:
1451                         port.c_cflag |= CS8;
1452                         break;
1453                 default:
1454                         commerror = IE_BYTESIZE;
1455                         return FALSE;
1456         }
1457
1458         TRACE(comm,"parity %d\n",lpdcb->Parity);
1459         port.c_cflag &= ~(PARENB | PARODD);
1460         if (lpdcb->fParity)
1461                 switch (lpdcb->Parity) {
1462                         case NOPARITY:
1463                                 port.c_iflag &= ~INPCK;
1464                                 break;
1465                         case ODDPARITY:
1466                                 port.c_cflag |= (PARENB | PARODD);
1467                                 port.c_iflag |= INPCK;
1468                                 break;
1469                         case EVENPARITY:
1470                                 port.c_cflag |= PARENB;
1471                                 port.c_iflag |= INPCK;
1472                                 break;
1473                         default:
1474                                 commerror = IE_BYTESIZE;
1475                                 return FALSE;
1476                 }
1477         
1478
1479         TRACE(comm,"stopbits %d\n",lpdcb->StopBits);
1480         switch (lpdcb->StopBits) {
1481                 case ONESTOPBIT:
1482                                 port.c_cflag &= ~CSTOPB;
1483                                 break;
1484                 case TWOSTOPBITS:
1485                                 port.c_cflag |= CSTOPB;
1486                                 break;
1487                 default:
1488                         commerror = IE_BYTESIZE;
1489                         return FALSE;
1490         }
1491 #ifdef CRTSCTS
1492         if (    lpdcb->fOutxCtsFlow                     ||
1493                 lpdcb->fDtrControl == DTR_CONTROL_ENABLE||
1494                 lpdcb->fRtsControl == RTS_CONTROL_ENABLE
1495         )
1496                 port.c_cflag |= CRTSCTS;
1497         if (lpdcb->fDtrControl == DTR_CONTROL_DISABLE)
1498                 port.c_cflag &= ~CRTSCTS;
1499
1500 #endif  
1501         if (lpdcb->fInX)
1502                 port.c_iflag |= IXON;
1503         else
1504                 port.c_iflag &= ~IXON;
1505         if (lpdcb->fOutX)
1506                 port.c_iflag |= IXOFF;
1507         else
1508                 port.c_iflag &= ~IXOFF;
1509
1510         if (tcsetattr(fd,TCSADRAIN,&port)==-1) {
1511                 commerror = WinError(); 
1512                 return FALSE;
1513         } else {
1514                 commerror = 0;
1515                 return TRUE;
1516         }
1517 }
1518
1519
1520 /*****************************************************************************
1521  *      GetCommState    (USER.202)
1522  */
1523 INT16 WINAPI GetCommState16(INT16 fd, LPDCB16 lpdcb)
1524 {
1525         struct termios port;
1526
1527         TRACE(comm,"fd %d, ptr %p\n", fd, lpdcb);
1528         if (tcgetattr(fd, &port) == -1) {
1529                 commerror = WinError(); 
1530                 return -1;
1531         }
1532         lpdcb->Id = fd;
1533 #ifndef __EMX__
1534 #ifdef CBAUD
1535         switch (port.c_cflag & CBAUD) {
1536 #else
1537         switch (port.c_ospeed) {
1538 #endif
1539                 case B110:
1540                         lpdcb->BaudRate = 110;
1541                         break;
1542                 case B300:
1543                         lpdcb->BaudRate = 300;
1544                         break;
1545                 case B600:
1546                         lpdcb->BaudRate = 600;
1547                         break;
1548                 case B1200:
1549                         lpdcb->BaudRate = 1200;
1550                         break;
1551                 case B2400:
1552                         lpdcb->BaudRate = 2400;
1553                         break;
1554                 case B4800:
1555                         lpdcb->BaudRate = 4800;
1556                         break;
1557                 case B9600:
1558                         lpdcb->BaudRate = 9600;
1559                         break;
1560                 case B19200:
1561                         lpdcb->BaudRate = 19200;
1562                         break;
1563                 case B38400:
1564                         lpdcb->BaudRate = 38400;
1565                         break;
1566 #ifdef B57600
1567                 case B57600:
1568                         lpdcb->BaudRate = 57600;
1569                         break;
1570 #endif
1571 #ifdef B115200
1572                 case B115200:
1573                         lpdcb->BaudRate = 57601;
1574                         break;
1575 #endif
1576         }
1577 #endif
1578         switch (port.c_cflag & CSIZE) {
1579                 case CS5:
1580                         lpdcb->ByteSize = 5;
1581                         break;
1582                 case CS6:
1583                         lpdcb->ByteSize = 6;
1584                         break;
1585                 case CS7:
1586                         lpdcb->ByteSize = 7;
1587                         break;
1588                 case CS8:
1589                         lpdcb->ByteSize = 8;
1590                         break;
1591         }       
1592         
1593         switch (port.c_cflag & (PARENB | PARODD)) {
1594                 case 0:
1595                         lpdcb->fParity = FALSE;
1596                         lpdcb->Parity = NOPARITY;
1597                         break;
1598                 case PARENB:
1599                         lpdcb->fParity = TRUE;
1600                         lpdcb->Parity = EVENPARITY;
1601                         break;
1602                 case (PARENB | PARODD):
1603                         lpdcb->fParity = TRUE;          
1604                         lpdcb->Parity = ODDPARITY;              
1605                         break;
1606         }
1607
1608         if (port.c_cflag & CSTOPB)
1609                 lpdcb->StopBits = TWOSTOPBITS;
1610         else
1611                 lpdcb->StopBits = ONESTOPBIT;
1612
1613         lpdcb->RlsTimeout = 50;
1614         lpdcb->CtsTimeout = 50; 
1615         lpdcb->DsrTimeout = 50;
1616         lpdcb->fNull = 0;
1617         lpdcb->fChEvt = 0;
1618         lpdcb->fBinary = 1;
1619         lpdcb->fDtrDisable = 0;
1620
1621 #ifdef CRTSCTS
1622
1623         if (port.c_cflag & CRTSCTS) {
1624                 lpdcb->fDtrflow = 1;
1625                 lpdcb->fRtsflow = 1;
1626                 lpdcb->fOutxCtsFlow = 1;
1627                 lpdcb->fOutxDsrFlow = 1;
1628         } else 
1629 #endif
1630                 lpdcb->fDtrDisable = 1;
1631
1632         if (port.c_iflag & IXON)
1633                 lpdcb->fInX = 1;
1634         else
1635                 lpdcb->fInX = 0;
1636
1637         if (port.c_iflag & IXOFF)
1638                 lpdcb->fOutX = 1;
1639         else
1640                 lpdcb->fOutX = 0;
1641 /*
1642         lpdcb->XonChar = 
1643         lpdcb->XoffChar = 
1644  */
1645         lpdcb->XonLim = 10;
1646         lpdcb->XoffLim = 10;
1647
1648         commerror = 0;
1649         return 0;
1650 }
1651
1652 /*****************************************************************************
1653  *      GetCommState    (KERNEL32.159)
1654  */
1655 BOOL WINAPI GetCommState(INT handle, LPDCB lpdcb)
1656 {
1657      struct termios port;
1658      int fd;
1659      struct get_read_fd_request req;
1660
1661      TRACE(comm,"handle %d, ptr %p\n", handle, lpdcb);
1662      req.handle = handle;
1663      CLIENT_SendRequest( REQ_GET_READ_FD, -1, 1, &req, sizeof(req) );
1664      CLIENT_WaitReply( NULL, &fd, 0 );
1665
1666      if(fd<0)
1667          return FALSE;
1668
1669      if (tcgetattr(fd, &port) == -1) {
1670         TRACE(comm,"tcgetattr(%d, ...) returned -1",fd);
1671                 commerror = WinError(); 
1672                 return FALSE;
1673         }
1674 #ifndef __EMX__
1675 #ifdef CBAUD
1676         switch (port.c_cflag & CBAUD) {
1677 #else
1678         switch (port.c_ospeed) {
1679 #endif
1680                 case B110:
1681                         lpdcb->BaudRate = 110;
1682                         break;
1683                 case B300:
1684                         lpdcb->BaudRate = 300;
1685                         break;
1686                 case B600:
1687                         lpdcb->BaudRate = 600;
1688                         break;
1689                 case B1200:
1690                         lpdcb->BaudRate = 1200;
1691                         break;
1692                 case B2400:
1693                         lpdcb->BaudRate = 2400;
1694                         break;
1695                 case B4800:
1696                         lpdcb->BaudRate = 4800;
1697                         break;
1698                 case B9600:
1699                         lpdcb->BaudRate = 9600;
1700                         break;
1701                 case B19200:
1702                         lpdcb->BaudRate = 19200;
1703                         break;
1704                 case B38400:
1705                         lpdcb->BaudRate = 38400;
1706                         break;
1707         }
1708 #endif
1709         switch (port.c_cflag & CSIZE) {
1710                 case CS5:
1711                         lpdcb->ByteSize = 5;
1712                         break;
1713                 case CS6:
1714                         lpdcb->ByteSize = 6;
1715                         break;
1716                 case CS7:
1717                         lpdcb->ByteSize = 7;
1718                         break;
1719                 case CS8:
1720                         lpdcb->ByteSize = 8;
1721                         break;
1722         }       
1723         
1724         switch (port.c_cflag & (PARENB | PARODD)) {
1725                 case 0:
1726                         lpdcb->fParity = FALSE;
1727                         lpdcb->Parity = NOPARITY;
1728                         break;
1729                 case PARENB:
1730                         lpdcb->fParity = TRUE;
1731                         lpdcb->Parity = EVENPARITY;
1732                         break;
1733                 case (PARENB | PARODD):
1734                         lpdcb->fParity = TRUE;          
1735                         lpdcb->Parity = ODDPARITY;              
1736                         break;
1737         }
1738
1739         if (port.c_cflag & CSTOPB)
1740                 lpdcb->StopBits = TWOSTOPBITS;
1741         else
1742                 lpdcb->StopBits = ONESTOPBIT;
1743
1744         lpdcb->fNull = 0;
1745         lpdcb->fBinary = 1;
1746
1747 #ifdef CRTSCTS
1748
1749         if (port.c_cflag & CRTSCTS) {
1750                 lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
1751                 lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
1752                 lpdcb->fOutxCtsFlow = 1;
1753                 lpdcb->fOutxDsrFlow = 1;
1754         } else 
1755 #endif
1756         {
1757                 lpdcb->fDtrControl = DTR_CONTROL_DISABLE;
1758                 lpdcb->fRtsControl = RTS_CONTROL_DISABLE;
1759         }
1760         if (port.c_iflag & IXON)
1761                 lpdcb->fInX = 1;
1762         else
1763                 lpdcb->fInX = 0;
1764
1765         if (port.c_iflag & IXOFF)
1766                 lpdcb->fOutX = 1;
1767         else
1768                 lpdcb->fOutX = 0;
1769 /*
1770         lpdcb->XonChar = 
1771         lpdcb->XoffChar = 
1772  */
1773         lpdcb->XonLim = 10;
1774         lpdcb->XoffLim = 10;
1775
1776         commerror = 0;
1777
1778      TRACE(comm,"OK\n");
1779  
1780         return TRUE;
1781 }
1782
1783 /*****************************************************************************
1784  *      TransmitCommChar        (USER.206)
1785  */
1786 INT16 WINAPI TransmitCommChar16(INT16 fd,CHAR chTransmit)
1787 {
1788         struct DosDeviceStruct *ptr;
1789
1790         TRACE(comm, "fd %d, data %d \n", fd, chTransmit);
1791         if ((ptr = GetDeviceStruct(fd)) == NULL) {
1792                 commerror = IE_BADID;
1793                 return -1;
1794         }
1795
1796         if (ptr->suspended) {
1797                 commerror = IE_HARDWARE;
1798                 return -1;
1799         }       
1800
1801         if (write(fd, (void *) &chTransmit, 1) == -1) {
1802                 commerror = WinError();
1803                 return -1;      
1804         }  else {
1805                 commerror = 0;
1806                 return 0;
1807         }
1808 }
1809
1810 /*****************************************************************************
1811  *      TransmitCommChar        (KERNEL32.535)
1812  */
1813 BOOL WINAPI TransmitCommChar(INT fd,CHAR chTransmit)
1814 {
1815         struct DosDeviceStruct *ptr;
1816
1817         TRACE(comm,"(%d,'%c')\n",fd,chTransmit);
1818         if ((ptr = GetDeviceStruct(fd)) == NULL) {
1819                 commerror = IE_BADID;
1820                 return FALSE;
1821         }
1822
1823         if (ptr->suspended) {
1824                 commerror = IE_HARDWARE;
1825                 return FALSE;
1826         }
1827         if (write(fd, (void *) &chTransmit, 1) == -1) {
1828                 commerror = WinError();
1829                 return FALSE;
1830         }  else {
1831                 commerror = 0;
1832                 return TRUE;
1833         }
1834 }
1835
1836 /*****************************************************************************
1837  *      UngetCommChar   (USER.212)
1838  */
1839 INT16 WINAPI UngetCommChar16(INT16 fd,CHAR chUnget)
1840 {
1841         struct DosDeviceStruct *ptr;
1842
1843         TRACE(comm,"fd %d (char %d)\n", fd, chUnget);
1844         if ((ptr = GetDeviceStruct(fd)) == NULL) {
1845                 commerror = IE_BADID;
1846                 return -1;
1847         }
1848
1849         if (ptr->suspended) {
1850                 commerror = IE_HARDWARE;
1851                 return -1;
1852         }       
1853
1854         ptr->unget = 1;
1855         ptr->unget_byte = chUnget;
1856         commerror = 0;
1857         return 0;
1858 }
1859
1860 /*****************************************************************************
1861  *      ReadComm        (USER.204)
1862  */
1863 INT16 WINAPI ReadComm16(INT16 fd,LPSTR lpvBuf,INT16 cbRead)
1864 {
1865         int status, length;
1866         struct DosDeviceStruct *ptr;
1867
1868         TRACE(comm, "fd %d, ptr %p, length %d\n", fd, lpvBuf, cbRead);
1869         if ((ptr = GetDeviceStruct(fd)) == NULL) {
1870                 commerror = IE_BADID;
1871                 return -1;
1872         }
1873
1874         if (ptr->suspended) {
1875                 commerror = IE_HARDWARE;
1876                 return -1;
1877         }       
1878
1879         if (ptr->unget) {
1880                 *lpvBuf = ptr->unget_byte;
1881                 lpvBuf++;
1882                 ptr->unget = 0;
1883
1884                 length = 1;
1885         } else
1886                 length = 0;
1887
1888         status = read(fd, (void *) lpvBuf, cbRead);
1889
1890         if (status == -1) {
1891                 if (errno != EAGAIN) {
1892                        commerror = WinError();
1893                        return -1 - length;
1894                 } else {
1895                         commerror = 0;
1896                         return length;
1897                 }
1898         } else {
1899                 TRACE(comm,"%.*s\n", length+status, lpvBuf);
1900                 commerror = 0;
1901                 return length + status;
1902         }
1903 }
1904
1905 /*****************************************************************************
1906  *      WriteComm       (USER.205)
1907  */
1908 INT16 WINAPI WriteComm16(INT16 fd, LPSTR lpvBuf, INT16 cbWrite)
1909 {
1910         int length;
1911         struct DosDeviceStruct *ptr;
1912
1913         TRACE(comm,"fd %d, ptr %p, length %d\n", 
1914                 fd, lpvBuf, cbWrite);
1915         if ((ptr = GetDeviceStruct(fd)) == NULL) {
1916                 commerror = IE_BADID;
1917                 return -1;
1918         }
1919
1920         if (ptr->suspended) {
1921                 commerror = IE_HARDWARE;
1922                 return -1;
1923         }       
1924         
1925         TRACE(comm,"%.*s\n", cbWrite, lpvBuf );
1926         length = write(fd, (void *) lpvBuf, cbWrite);
1927         
1928         if (length == -1) {
1929                 commerror = WinError();
1930                 return -1;      
1931         } else {
1932                 commerror = 0;  
1933                 return length;
1934         }
1935 }
1936
1937
1938 /*****************************************************************************
1939  *      GetCommTimeouts         (KERNEL32.160)
1940  */
1941 BOOL WINAPI GetCommTimeouts(INT fd,LPCOMMTIMEOUTS lptimeouts)
1942 {
1943         FIXME(comm,"(%x,%p):stub.\n",fd,lptimeouts);
1944         return TRUE;
1945 }
1946
1947 /*****************************************************************************
1948  *      SetCommTimeouts         (KERNEL32.453)
1949  */
1950 BOOL WINAPI SetCommTimeouts(INT fd,LPCOMMTIMEOUTS lptimeouts) {
1951         FIXME(comm,"(%x,%p):stub.\n",fd,lptimeouts);
1952         return TRUE;
1953 }
1954
1955 /***********************************************************************
1956  *           EnableCommNotification   (USER.246)
1957  */
1958 BOOL16 WINAPI EnableCommNotification16( INT16 fd, HWND16 hwnd,
1959                                       INT16 cbWriteNotify, INT16 cbOutQueue )
1960 {
1961         FIXME(comm, "(%d, %x, %d, %d):stub.\n", fd, hwnd, cbWriteNotify, cbOutQueue);
1962         return TRUE;
1963 }
1964
1965 /***********************************************************************
1966  *           GetCommModemStatus   (KERNEL32.285)
1967  */
1968 BOOL WINAPI GetCommModemStatus(HANDLE hFile,LPDWORD lpModemStat )
1969 {
1970         FIXME(comm, "(%d %p)\n",hFile,lpModemStat );
1971         return TRUE;
1972 }
1973 /***********************************************************************
1974  *           WaitCommEvent   (KERNEL32.719)
1975  */
1976 BOOL WINAPI WaitCommEvent(HANDLE hFile,LPDWORD eventmask ,LPOVERLAPPED overlapped)
1977 {
1978         FIXME(comm, "(%d %p %p )\n",hFile, eventmask,overlapped);
1979         return TRUE;
1980 }
1981
1982 /***********************************************************************
1983  *           GetCommProperties   (KERNEL32.???)
1984  */
1985 BOOL WINAPI GetCommProperties(HANDLE hFile, LPDCB *dcb)
1986 {
1987     FIXME(comm, "(%d %p )\n",hFile,dcb);
1988     return TRUE;
1989 }
1990
1991 /***********************************************************************
1992  *           SetCommProperties   (KERNEL32.???)
1993  */
1994 BOOL WINAPI SetCommProperties(HANDLE hFile, LPDCB dcb)
1995 {
1996     FIXME(comm, "(%d %p )\n",hFile,dcb);
1997     return TRUE;
1998 }
1999