Release 970629
[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
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <termios.h>
19 #include <fcntl.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <ctype.h>
23 #include <sys/stat.h>
24 #if defined(__NetBSD__) || defined(__FreeBSD__)
25 #include <sys/filio.h>
26 #endif
27 #include <sys/ioctl.h>
28 #include <unistd.h>
29
30 #include "windows.h"
31 #include "comm.h"
32 #include "heap.h"
33 #include "options.h"
34 #include "stddebug.h"
35 #include "debug.h"
36 #include "handle32.h"
37
38 #ifndef TIOCINQ
39 #define TIOCINQ FIONREAD
40 #endif
41
42 /*
43  * [RER] These are globals are wrong.  They should be in DosDeviceStruct
44  * on a per port basis.
45  */
46 int commerror = 0, eventmask = 0;
47
48 struct DosDeviceStruct COM[MAX_PORTS];
49 struct DosDeviceStruct LPT[MAX_PORTS];
50
51 void COMM_Init(void)
52 {
53         int x;
54         char option[10], temp[256], *btemp;
55         struct stat st;
56
57         for (x=0; x!=MAX_PORTS; x++) {
58                 strcpy(option,"COMx");
59                 option[3] = '1' + x;
60                 option[4] = '\0';
61
62                 PROFILE_GetWineIniString( "serialports", option, "*",
63                                           temp, sizeof(temp) );
64                 if (!strcmp(temp, "*") || *temp == '\0') 
65                         COM[x].devicename = NULL;
66                 else {
67                         btemp = strchr(temp,',');
68                         if (btemp != NULL) {
69                                 *btemp++ = '\0';
70                                 COM[x].baudrate = atoi(btemp);
71                         } else {
72                                 COM[x].baudrate = -1;
73                         }
74                         stat(temp, &st);
75                         if (!S_ISCHR(st.st_mode)) 
76                                 fprintf(stderr,"comm: can't use `%s' as %s !\n", temp, option);
77                         else
78                                 if ((COM[x].devicename = malloc(strlen(temp)+1)) == NULL) 
79                                         fprintf(stderr,"comm: can't malloc for device info!\n");
80                                 else {
81                                         COM[x].fd = 0;
82                                         strcpy(COM[x].devicename, temp);
83                                 }
84                 dprintf_comm(stddeb,
85                         "Comm_Init: %s = %s\n", option, COM[x].devicename);
86                 }
87
88                 strcpy(option, "LPTx");
89                 option[3] = '1' + x;
90                 option[4] = '\0';
91
92                 PROFILE_GetWineIniString( "parallelports", option, "*",
93                                           temp, sizeof(temp) );
94                 if (!strcmp(temp, "*") || *temp == '\0')
95                         LPT[x].devicename = NULL;
96                 else {
97                         stat(temp, &st);
98                         if (!S_ISCHR(st.st_mode)) 
99                                 fprintf(stderr,"comm: can't use `%s' as %s !\n", temp, option);
100                         else 
101                                 if ((LPT[x].devicename = malloc(strlen(temp)+1)) == NULL) 
102                                         fprintf(stderr,"comm: can't malloc for device info!\n");
103                                 else {
104                                         LPT[x].fd = 0;
105                                         strcpy(LPT[x].devicename, temp);
106                                 }
107                 dprintf_comm(stddeb,
108                         "Comm_Init: %s = %s\n", option, LPT[x].devicename);
109                 }
110
111         }
112 }
113
114
115 struct DosDeviceStruct *GetDeviceStruct(int fd)
116 {
117         int x;
118         
119         for (x=0; x!=MAX_PORTS; x++) {
120             if (COM[x].fd == fd)
121                 return &COM[x];
122             if (LPT[x].fd == fd)
123                 return &LPT[x];
124         }
125
126         return NULL;
127 }
128
129 int ValidCOMPort(int x)
130 {
131         return(x < MAX_PORTS ? (int) COM[x].devicename : 0); 
132 }
133
134 int ValidLPTPort(int x)
135 {
136         return(x < MAX_PORTS ? (int) LPT[x].devicename : 0); 
137 }
138
139 int WinError(void)
140 {
141         dprintf_comm(stddeb, "WinError: errno = %d\n", errno);
142         switch (errno) {
143                 default:
144                         return CE_IOE;
145                 }
146 }
147
148 /**************************************************************************
149  *         BuildCommDCB         (USER.213)
150  */
151 BOOL16 BuildCommDCB16(LPCSTR device, LPDCB16 lpdcb)
152 {
153         /* "COM1:9600,n,8,1"    */
154         /*  012345              */
155         int port;
156         char *ptr, temp[256];
157
158         dprintf_comm(stddeb,
159                 "BuildCommDCB: (%s), ptr %p\n", device, lpdcb);
160         commerror = 0;
161
162         if (!lstrncmpi32A(device,"COM",3)) {
163                 port = device[3] - '0';
164         
165
166                 if (port-- == 0) {
167                         fprintf(stderr, "comm: BUG ! COM0 can't exists!.\n");
168                         commerror = IE_BADID;
169                 }
170
171                 if (!ValidCOMPort(port)) {
172                         commerror = IE_BADID;
173                         return -1;
174                 }
175                 
176                 if (!COM[port].fd) {
177                     OpenComm(device, 0, 0);
178                 }
179                 lpdcb->Id = COM[port].fd;
180                 
181                 if (!*(device+4))
182                         return 0;
183
184                 if (*(device+4) != ':')
185                         return -1;
186                 
187                 strcpy(temp,device+5);
188                 ptr = strtok(temp, ", "); 
189
190                 if (COM[port].baudrate > 0)
191                         lpdcb->BaudRate = COM[port].baudrate;
192                 else
193                         lpdcb->BaudRate = atoi(ptr);
194                 dprintf_comm(stddeb,"BuildCommDCB: baudrate (%d)\n", lpdcb->BaudRate);
195
196                 ptr = strtok(NULL, ", ");
197                 if (islower(*ptr))
198                         *ptr = toupper(*ptr);
199
200                 dprintf_comm(stddeb,"BuildCommDCB: parity (%c)\n", *ptr);
201                 lpdcb->fParity = 1;
202                 switch (*ptr) {
203                         case 'N':
204                                 lpdcb->Parity = NOPARITY;
205                                 lpdcb->fParity = 0;
206                                 break;                  
207                         case 'E':
208                                 lpdcb->Parity = EVENPARITY;
209                                 break;                  
210                         case 'M':
211                                 lpdcb->Parity = MARKPARITY;
212                                 break;                  
213                         case 'O':
214                                 lpdcb->Parity = ODDPARITY;
215                                 break;                  
216                         default:
217                                 fprintf(stderr,"comm: unknown parity `%c'!\n", *ptr);
218                                 return -1;
219                 }
220
221                 ptr = strtok(NULL, ", "); 
222                 dprintf_comm(stddeb, "BuildCommDCB: charsize (%c)\n", *ptr);
223                 lpdcb->ByteSize = *ptr - '0';
224
225                 ptr = strtok(NULL, ", ");
226                 dprintf_comm(stddeb, "BuildCommDCB: stopbits (%c)\n", *ptr);
227                 switch (*ptr) {
228                         case '1':
229                                 lpdcb->StopBits = ONESTOPBIT;
230                                 break;                  
231                         case '2':
232                                 lpdcb->StopBits = TWOSTOPBITS;
233                                 break;                  
234                         default:
235                                 fprintf(stderr,"comm: unknown # of stopbits `%c'!\n", *ptr);
236                                 return -1;
237                 }
238         }       
239
240         return 0;
241 }
242
243 /**************************************************************************
244  *         BuildCommDCBA                (KERNEL32.14)
245  */
246 BOOL32 BuildCommDCB32A(LPCSTR device,LPDCB32 lpdcb) {
247         return BuildCommDCBAndTimeouts32A(device,lpdcb,NULL);
248 }
249
250 /**************************************************************************
251  *         BuildCommDCBAndTimeoutsA     (KERNEL32.15)
252  */
253 BOOL32 BuildCommDCBAndTimeouts32A(LPCSTR device, LPDCB32 lpdcb,LPCOMMTIMEOUTS lptimeouts) {
254         int     port;
255         char    *ptr,*temp;
256
257         dprintf_comm(stddeb,"BuildCommDCBAndTimeouts32A(%s,%p,%p)\n",device,lpdcb,lptimeouts);
258         commerror = 0;
259
260         if (!lstrncmpi32A(device,"COM",3)) {
261                 port=device[3]-'0';
262                 if (port--==0) {
263                         fprintf(stderr,"comm:BUG! COM0 can't exists!.\n");
264                         return FALSE;
265                 }
266                 if (!ValidCOMPort(port))
267                         return FALSE;
268                 if (*(device+4)!=':')
269                         return FALSE;
270                 temp=(LPSTR)(device+5);
271         } else
272                 temp=(LPSTR)device;
273         lpdcb->DCBlength        = sizeof(DCB32);
274         if (strchr(temp,',')) { /* old style */
275                 DCB16   dcb16;
276                 BOOL16  ret;
277                 char    last=temp[strlen(temp)-1];
278
279                 ret=BuildCommDCB16(device,&dcb16);
280                 if (!ret)
281                         return FALSE;
282                 lpdcb->BaudRate         = dcb16.BaudRate;
283                 lpdcb->ByteSize         = dcb16.ByteSize;
284                 lpdcb->fBinary          = dcb16.fBinary;
285                 lpdcb->Parity           = dcb16.Parity;
286                 lpdcb->fParity          = dcb16.fParity;
287                 lpdcb->fNull            = dcb16.fNull;
288                 lpdcb->StopBits         = dcb16.StopBits;
289                 if (last == 'x') {
290                         lpdcb->fInX             = TRUE;
291                         lpdcb->fOutX            = TRUE;
292                         lpdcb->fOutxCtsFlow     = FALSE;
293                         lpdcb->fOutxDsrFlow     = FALSE;
294                         lpdcb->fDtrControl      = DTR_CONTROL_ENABLE;
295                         lpdcb->fRtsControl      = RTS_CONTROL_ENABLE;
296                 } else if (last=='p') {
297                         lpdcb->fInX             = FALSE;
298                         lpdcb->fOutX            = FALSE;
299                         lpdcb->fOutxCtsFlow     = TRUE;
300                         lpdcb->fOutxDsrFlow     = TRUE;
301                         lpdcb->fDtrControl      = DTR_CONTROL_HANDSHAKE;
302                         lpdcb->fRtsControl      = RTS_CONTROL_HANDSHAKE;
303                 } else {
304                         lpdcb->fInX             = FALSE;
305                         lpdcb->fOutX            = FALSE;
306                         lpdcb->fOutxCtsFlow     = FALSE;
307                         lpdcb->fOutxDsrFlow     = FALSE;
308                         lpdcb->fDtrControl      = DTR_CONTROL_ENABLE;
309                         lpdcb->fRtsControl      = RTS_CONTROL_ENABLE;
310                 }
311                 lpdcb->XonChar  = dcb16.XonChar;
312                 lpdcb->XoffChar = dcb16.XoffChar;
313                 lpdcb->ErrorChar= dcb16.PeChar;
314                 lpdcb->fErrorChar= dcb16.fPeChar;
315                 lpdcb->EofChar  = dcb16.EofChar;
316                 lpdcb->EvtChar  = dcb16.EvtChar;
317                 lpdcb->XonLim   = dcb16.XonLim;
318                 lpdcb->XoffLim  = dcb16.XoffLim;
319                 return TRUE;
320         }
321         ptr=strtok(temp," "); 
322         while (ptr) {
323                 DWORD   flag,x;
324
325                 flag=0;
326                 if (!strncmp("baud=",ptr,5)) {
327                         if (!sscanf(ptr+5,"%ld",&x))
328                                 fprintf(stderr,"BuildCommDCB32A:Couldn't parse %s\n",ptr);
329                         lpdcb->BaudRate = x;
330                         flag=1;
331                 }
332                 if (!strncmp("stop=",ptr,5)) {
333                         if (!sscanf(ptr+5,"%ld",&x))
334                                 fprintf(stderr,"BuildCommDCB32A:Couldn't parse %s\n",ptr);
335                         lpdcb->StopBits = x;
336                         flag=1;
337                 }
338                 if (!strncmp("data=",ptr,5)) {
339                         if (!sscanf(ptr+5,"%ld",&x))
340                                 fprintf(stderr,"BuildCommDCB32A:Couldn't parse %s\n",ptr);
341                         lpdcb->ByteSize = x;
342                         flag=1;
343                 }
344                 if (!strncmp("parity=",ptr,7)) {
345                         lpdcb->fParity  = TRUE;
346                         switch (ptr[8]) {
347                         case 'N':case 'n':
348                                 lpdcb->fParity  = FALSE;
349                                 lpdcb->Parity   = NOPARITY;
350                                 break;
351                         case 'E':case 'e':
352                                 lpdcb->Parity   = EVENPARITY;
353                                 break;
354                         case 'O':case 'o':
355                                 lpdcb->Parity   = ODDPARITY;
356                                 break;
357                         case 'M':case 'm':
358                                 lpdcb->Parity   = MARKPARITY;
359                                 break;
360                         }
361                         flag=1;
362                 }
363                 if (!flag)
364                         fprintf(stderr,"BuildCommDCB32A: Unhandled specifier '%s', please report.\n",ptr);
365                 ptr=strtok(NULL," ");
366         }
367         if (lpdcb->BaudRate==110)
368                 lpdcb->StopBits = 2;
369         return TRUE;
370 }
371
372 /**************************************************************************
373  *         BuildCommDCBAndTimeoutsW             (KERNEL32.16)
374  */
375 BOOL32 BuildCommDCBAndTimeouts32W(
376         LPCWSTR devid,LPDCB32 lpdcb,LPCOMMTIMEOUTS lptimeouts
377 ) {
378         LPSTR   devidA;
379         BOOL32  ret;
380
381         dprintf_comm(stddeb,"BuildCommDCBAndTimeouts32W(%p,%p,%p)\n",devid,lpdcb,lptimeouts);
382         devidA = HEAP_strdupWtoA( GetProcessHeap(), 0, devid );
383         ret=BuildCommDCBAndTimeouts32A(devidA,lpdcb,lptimeouts);
384         HeapFree( GetProcessHeap(), 0, devidA );
385         return ret;
386 }
387
388 /**************************************************************************
389  *         BuildCommDCBW                (KERNEL32.17)
390  */
391 BOOL32 BuildCommDCB32W(LPCWSTR devid,LPDCB32 lpdcb) {
392         return BuildCommDCBAndTimeouts32W(devid,lpdcb,NULL);
393 }
394
395 /*****************************************************************************
396  *      OpenComm                (USER.200)
397  */
398 INT16 OpenComm(LPCSTR device,UINT16 cbInQueue,UINT16 cbOutQueue)
399 {
400         int port,fd;
401
402         dprintf_comm(stddeb,
403                 "OpenComm: %s, %d, %d\n", device, cbInQueue, cbOutQueue);
404         commerror = 0;
405
406         if (!lstrncmpi32A(device,"COM",3)) {
407                 port = device[3] - '0';
408
409                 if (port-- == 0) {
410                         fprintf(stderr, "comm: BUG ! COM0 doesn't exists!.\n");
411                         commerror = IE_BADID;
412                 }
413
414                 dprintf_comm(stddeb,
415                        "OpenComm: %s = %s\n", device, COM[port].devicename);
416
417                 if (!ValidCOMPort(port)) {
418                         commerror = IE_BADID;
419                         return -1;
420                 }
421                 if (COM[port].fd) {
422                         return COM[port].fd;
423                 }
424
425                 fd = open(COM[port].devicename, O_RDWR | O_NONBLOCK);
426                 if (fd == -1) {
427                         commerror = WinError();
428                         return -1;
429                 } else {
430                         COM[port].fd = fd;      
431                         return fd;
432                 }
433         } 
434         else 
435         if (!lstrncmpi32A(device,"LPT",3)) {
436                 port = device[3] - '0';
437         
438                 if (!ValidLPTPort(port)) {
439                         commerror = IE_BADID;
440                         return -1;
441                 }               
442                 if (LPT[port].fd) {
443                         commerror = IE_OPEN;
444                         return -1;
445                 }
446
447                 fd = open(LPT[port].devicename, O_RDWR | O_NONBLOCK, 0);
448                 if (fd == -1) {
449                         commerror = WinError();
450                         return -1;      
451                 } else {
452                         LPT[port].fd = fd;
453                         return fd;
454                 }
455         }
456         return 0;
457 }
458
459 /*****************************************************************************
460  *      CloseComm               (USER.207)
461  */
462 INT16 CloseComm(INT16 fd)
463 {
464         struct DosDeviceStruct *ptr;
465
466         dprintf_comm(stddeb,"CloseComm: fd %d\n", fd);
467         if ((ptr = GetDeviceStruct(fd)) == NULL) {
468                 commerror = IE_BADID;
469                 return -1;
470         }
471
472         ptr->fd = 0;    /* [RER] Really, -1 would be a better value */
473
474         if (close(fd) == -1) {
475                 commerror = WinError();
476                 return -1;
477         } else {
478                 commerror = 0;
479                 return 0;
480         }
481 }
482
483 /*****************************************************************************
484  *      SetCommBreak            (USER.210)
485  */
486 INT16 SetCommBreak16(INT16 fd)
487 {
488         struct DosDeviceStruct *ptr;
489
490         dprintf_comm(stddeb,"SetCommBreak: fd: %d\n", fd);
491         if ((ptr = GetDeviceStruct(fd)) == NULL) {
492                 commerror = IE_BADID;
493                 return -1;
494         }
495
496         ptr->suspended = 1;
497         commerror = 0;
498         return 0;
499 }
500
501 /*****************************************************************************
502  *      SetCommBreak            (KERNEL32.449)
503  */
504 BOOL32 SetCommBreak32(INT32 fd)
505 {
506
507         struct DosDeviceStruct *ptr;
508
509         dprintf_comm(stddeb,"SetCommBreak: fd: %d\n", fd);
510         if ((ptr = GetDeviceStruct(fd)) == NULL) {
511                 commerror = IE_BADID;
512                 return FALSE;
513         }
514
515         ptr->suspended = 1;
516         commerror = 0;
517         return TRUE;
518 }
519
520 /*****************************************************************************
521  *      ClearCommBreak          (USER.211)
522  */
523 INT16 ClearCommBreak16(INT16 fd)
524 {
525         struct DosDeviceStruct *ptr;
526
527         dprintf_comm(stddeb,"ClearCommBreak: fd: %d\n", fd);
528         if ((ptr = GetDeviceStruct(fd)) == NULL) {
529                 commerror = IE_BADID;
530                 return -1;
531         }
532
533         ptr->suspended = 0;
534         commerror = 0;
535         return 0;
536 }
537
538 /*****************************************************************************
539  *      ClearCommBreak          (KERNEL32.20)
540  */
541 BOOL32 ClearCommBreak32(INT32 fd)
542 {
543         struct DosDeviceStruct *ptr;
544
545         dprintf_comm(stddeb,"ClearCommBreak: fd: %d\n", fd);
546         if ((ptr = GetDeviceStruct(fd)) == NULL) {
547                 commerror = IE_BADID;
548                 return FALSE;
549         }
550
551         ptr->suspended = 0;
552         commerror = 0;
553         return TRUE;
554 }
555
556 /*****************************************************************************
557  *      EscapeCommFunction      (USER.214)
558  */
559 LONG EscapeCommFunction16(UINT16 fd,UINT16 nFunction)
560 {
561         int     max;
562         struct termios port;
563
564         dprintf_comm(stddeb,"EscapeCommFunction fd: %d, function: %d\n", fd, nFunction);
565         if (tcgetattr(fd,&port) == -1) {
566                 commerror=WinError();   
567                 return -1;
568         }
569
570         switch (nFunction) {
571                 case RESETDEV:
572                         break;                                  
573
574                 case GETMAXCOM:
575                         for (max = MAX_PORTS;!COM[max].devicename;max--)
576                                 ;
577                         return max;
578                         break;
579
580                 case GETMAXLPT:
581                         for (max = MAX_PORTS;!LPT[max].devicename;max--)
582                                 ;
583                         return 0x80 + max;
584                         break;
585
586 #ifdef TIOCM_DTR
587                 case CLRDTR:
588                         port.c_cflag &= TIOCM_DTR;
589                         break;
590 #endif
591
592 #ifdef TIOCM_RTS
593                 case CLRRTS:
594                         port.c_cflag &= TIOCM_RTS;
595                         break;
596 #endif
597         
598 #ifdef CRTSCTS
599                 case SETDTR:
600                         port.c_cflag |= CRTSCTS;
601                         break;
602
603                 case SETRTS:
604                         port.c_cflag |= CRTSCTS;
605                         break;
606 #endif
607
608                 case SETXOFF:
609                         port.c_iflag |= IXOFF;
610                         break;
611
612                 case SETXON:
613                         port.c_iflag |= IXON;
614                         break;
615
616                 default:
617                         fprintf(stderr,
618                         "EscapeCommFunction fd: %d, unknown function: %d\n", 
619                         fd, nFunction);
620                         break;                          
621         }
622         
623         if (tcsetattr(fd, TCSADRAIN, &port) == -1) {
624                 commerror = WinError();
625                 return -1;      
626         } else {
627                 commerror = 0;
628                 return 0;
629         }
630 }
631
632 /*****************************************************************************
633  *      EscapeCommFunction      (KERNEL32.214)
634  */
635 BOOL32 EscapeCommFunction32(INT32 fd,UINT32 nFunction)
636 {
637         struct termios  port;
638         struct DosDeviceStruct *ptr;
639
640         dprintf_comm(stddeb,"EscapeCommFunction fd: %d, function: %d\n", fd, nFunction);
641         if (tcgetattr(fd,&port) == -1) {
642                 commerror=WinError();   
643                 return FALSE;
644         }
645         if ((ptr = GetDeviceStruct(fd)) == NULL) {
646                 commerror = IE_BADID;
647                 return FALSE;
648         }
649
650         switch (nFunction) {
651                 case RESETDEV:
652                         break;                                  
653
654 #ifdef TIOCM_DTR
655                 case CLRDTR:
656                         port.c_cflag &= TIOCM_DTR;
657                         break;
658 #endif
659
660 #ifdef TIOCM_RTS
661                 case CLRRTS:
662                         port.c_cflag &= TIOCM_RTS;
663                         break;
664 #endif
665         
666 #ifdef CRTSCTS
667                 case SETDTR:
668                         port.c_cflag |= CRTSCTS;
669                         break;
670
671                 case SETRTS:
672                         port.c_cflag |= CRTSCTS;
673                         break;
674 #endif
675
676                 case SETXOFF:
677                         port.c_iflag |= IXOFF;
678                         break;
679
680                 case SETXON:
681                         port.c_iflag |= IXON;
682                         break;
683                 case SETBREAK:
684                         ptr->suspended = 1;
685                         break;
686                 case CLRBREAK:
687                         ptr->suspended = 0;
688                         break;
689                 default:
690                         fprintf(stderr,
691                         "EscapeCommFunction32 fd: %d, unknown function: %d\n", 
692                         fd, nFunction);
693                         break;                          
694         }
695         
696         if (tcsetattr(fd, TCSADRAIN, &port) == -1) {
697                 commerror = WinError();
698                 return FALSE;   
699         } else {
700                 commerror = 0;
701                 return TRUE;
702         }
703 }
704
705 /*****************************************************************************
706  *      FlushComm       (USER.215)
707  */
708 INT16 FlushComm(INT16 fd,INT16 fnQueue)
709 {
710         int queue;
711
712         dprintf_comm(stddeb,"FlushComm fd: %d, queue: %d\n", fd, fnQueue);
713         switch (fnQueue) {
714                 case 0: queue = TCOFLUSH;
715                         break;
716                 case 1: queue = TCIFLUSH;
717                         break;
718                 default:fprintf(stderr,
719                                 "FlushComm fd: %d, UNKNOWN queue: %d\n", 
720                                 fd, fnQueue);
721                         return -1;
722                 }
723         if (tcflush(fd, fnQueue)) {
724                 commerror = WinError();
725                 return -1;      
726         } else {
727                 commerror = 0;
728                 return 0;
729         }
730 }  
731
732 /*****************************************************************************
733  *      GetCommError    (USER.203)
734  */
735 INT16 GetCommError(INT16 fd,LPCOMSTAT lpStat)
736 {
737         int             temperror;
738         unsigned long   cnt;
739         int             rc;
740
741         lpStat->status = 0;
742
743         rc = ioctl(fd, TIOCOUTQ, &cnt);
744         lpStat->cbOutQue = cnt;
745
746         rc = ioctl(fd, TIOCINQ, &cnt);
747         lpStat->cbInQue = cnt;
748
749         dprintf_comm(stddeb,
750                 "GetCommError: fd %d, error %d, lpStat %d %d %d\n",
751                 fd, commerror,
752                 lpStat->status, lpStat->cbInQue, lpStat->cbOutQue);
753         /*
754          * [RER] I have no idea what the following is trying to accomplish.
755          * [RER] It is certainly not what the reference manual suggests.
756          */
757         temperror = commerror;
758         commerror = 0;
759         return(temperror);
760 }
761
762 /*****************************************************************************
763  *      ClearCommError  (KERNEL32.21)
764  */
765 BOOL32 ClearCommError(INT32 fd,LPDWORD errors,LPCOMSTAT lpStat)
766 {
767         int temperror;
768
769         dprintf_comm(stddeb,
770                 "ClearCommError: fd %d (current error %d)\n", fd, commerror);
771         temperror = commerror;
772         commerror = 0;
773         return TRUE;
774 }
775
776 /*****************************************************************************
777  *      SetCommEventMask        (USER.208)
778  */
779 UINT16  *SetCommEventMask(INT16 fd,UINT16 fuEvtMask)
780 {
781         dprintf_comm(stddeb,"SetCommEventMask:fd %d,mask %d\n",fd,fuEvtMask);
782         eventmask |= fuEvtMask;
783         return (UINT16 *)&eventmask;    /* FIXME, should be SEGPTR */
784 }
785
786 /*****************************************************************************
787  *      GetCommEventMask        (USER.209)
788  */
789 UINT16 GetCommEventMask(INT16 fd,UINT16 fnEvtClear)
790 {
791         int     events = 0;
792
793         dprintf_comm(stddeb,
794                 "GetCommEventMask: fd %d, mask %d\n", fd, fnEvtClear);
795
796         /*
797          *      Determine if any characters are available
798          */
799         if (fnEvtClear & EV_RXCHAR)
800         {
801                 int             rc;
802                 unsigned long   cnt;
803
804                 rc = ioctl(fd, TIOCINQ, &cnt);
805                 if (cnt) events |= EV_RXCHAR;
806
807                 dprintf_comm(stddeb,
808                         "GetCommEventMask: rxchar %ld\n", cnt);
809         }
810
811         /*
812          *      There are other events that need to be checked for
813          */
814         /* TODO */
815
816         dprintf_comm(stddeb,
817                 "GetCommEventMask: return events %d\n", events);
818         return events;
819
820         /*
821          * [RER] The following was gibberish
822          */
823 #if 0
824         tempmask = eventmask;
825         eventmask &= ~fnEvtClear;
826         return eventmask;
827 #endif
828 }
829
830 /*****************************************************************************
831  *      GetCommMask     (KERNEL32.156)
832  */
833 BOOL32 GetCommMask(INT32 fd,LPDWORD evtmask)
834 {
835         dprintf_comm(stddeb,
836                 "GetCommMask: fd %d, mask %p\n", fd, evtmask);
837         *evtmask = eventmask;
838         return TRUE;
839 }
840
841 /*****************************************************************************
842  *      SetCommMask     (KERNEL32.451)
843  */
844 BOOL32 SetCommMask(INT32 fd,DWORD evtmask)
845 {
846         dprintf_comm(stddeb,
847                 "SetCommMask: fd %d, mask %lx\n", fd, evtmask);
848         eventmask = evtmask;
849         return TRUE;
850 }
851
852 /*****************************************************************************
853  *      SetCommState16  (USER.201)
854  */
855 INT16 SetCommState16(LPDCB16 lpdcb)
856 {
857         struct termios port;
858         struct DosDeviceStruct *ptr;
859
860         dprintf_comm(stddeb,
861                 "SetCommState: fd %d, ptr %p\n", lpdcb->Id, lpdcb);
862         if (tcgetattr(lpdcb->Id, &port) == -1) {
863                 commerror = WinError(); 
864                 return -1;
865         }
866
867         port.c_cc[VMIN] = 0;
868         port.c_cc[VTIME] = 1;
869
870 #ifdef IMAXBEL
871         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|IMAXBEL);
872 #else
873         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR);
874 #endif
875         port.c_iflag |= (IGNBRK);
876
877         port.c_oflag &= ~(OPOST);
878
879         port.c_cflag &= ~(HUPCL);
880         port.c_cflag |= CLOCAL | CREAD;
881
882         port.c_lflag &= ~(ICANON|ECHO|ISIG);
883         port.c_lflag |= NOFLSH;
884
885         if ((ptr = GetDeviceStruct(lpdcb->Id)) == NULL) {
886                 commerror = IE_BADID;
887                 return -1;
888         }
889         if (ptr->baudrate > 0)
890                 lpdcb->BaudRate = ptr->baudrate;
891         dprintf_comm(stddeb,"SetCommState: baudrate %d\n",lpdcb->BaudRate);
892 #ifdef CBAUD
893         port.c_cflag &= ~CBAUD;
894         switch (lpdcb->BaudRate) {
895                 case 110:
896                 case CBR_110:
897                         port.c_cflag |= B110;
898                         break;          
899                 case 300:
900                 case CBR_300:
901                         port.c_cflag |= B300;
902                         break;          
903                 case 600:
904                 case CBR_600:
905                         port.c_cflag |= B600;
906                         break;          
907                 case 1200:
908                 case CBR_1200:
909                         port.c_cflag |= B1200;
910                         break;          
911                 case 2400:
912                 case CBR_2400:
913                         port.c_cflag |= B2400;
914                         break;          
915                 case 4800:
916                 case CBR_4800:
917                         port.c_cflag |= B4800;
918                         break;          
919                 case 9600:
920                 case CBR_9600:
921                         port.c_cflag |= B9600;
922                         break;          
923                 case 19200:
924                 case CBR_19200:
925                         port.c_cflag |= B19200;
926                         break;          
927                 case 38400:
928                 case CBR_38400:
929                         port.c_cflag |= B38400;
930                         break;          
931                 default:
932                         commerror = IE_BAUDRATE;
933                         return -1;
934         }
935 #elif !defined(__EMX__)
936         switch (lpdcb->BaudRate) {
937                 case 110:
938                 case CBR_110:
939                         port.c_ospeed = B110;
940                         break;
941                 case 300:
942                 case CBR_300:
943                         port.c_ospeed = B300;
944                         break;
945                 case 600:
946                 case CBR_600:
947                         port.c_ospeed = B600;
948                         break;
949                 case 1200:
950                 case CBR_1200:
951                         port.c_ospeed = B1200;
952                         break;
953                 case 2400:
954                 case CBR_2400:
955                         port.c_ospeed = B2400;
956                         break;
957                 case 4800:
958                 case CBR_4800:
959                         port.c_ospeed = B4800;
960                         break;
961                 case 9600:
962                 case CBR_9600:
963                         port.c_ospeed = B9600;
964                         break;
965                 case 19200:
966                 case CBR_19200:
967                         port.c_ospeed = B19200;
968                         break;
969                 case 38400:
970                 case CBR_38400:
971                         port.c_ospeed = B38400;
972                         break;
973                 default:
974                         commerror = IE_BAUDRATE;
975                         return -1;
976         }
977         port.c_ispeed = port.c_ospeed;
978 #endif
979         dprintf_comm(stddeb,"SetCommState: bytesize %d\n",lpdcb->ByteSize);
980         port.c_cflag &= ~CSIZE;
981         switch (lpdcb->ByteSize) {
982                 case 5:
983                         port.c_cflag |= CS5;
984                         break;
985                 case 6:
986                         port.c_cflag |= CS6;
987                         break;
988                 case 7:
989                         port.c_cflag |= CS7;
990                         break;
991                 case 8:
992                         port.c_cflag |= CS8;
993                         break;
994                 default:
995                         commerror = IE_BYTESIZE;
996                         return -1;
997         }
998
999         dprintf_comm(stddeb,"SetCommState: parity %d\n",lpdcb->Parity);
1000         port.c_cflag &= ~(PARENB | PARODD);
1001         if (lpdcb->fParity)
1002                 switch (lpdcb->Parity) {
1003                         case NOPARITY:
1004                                 port.c_iflag &= ~INPCK;
1005                                 break;
1006                         case ODDPARITY:
1007                                 port.c_cflag |= (PARENB | PARODD);
1008                                 port.c_iflag |= INPCK;
1009                                 break;
1010                         case EVENPARITY:
1011                                 port.c_cflag |= PARENB;
1012                                 port.c_iflag |= INPCK;
1013                                 break;
1014                         default:
1015                                 commerror = IE_BYTESIZE;
1016                                 return -1;
1017                 }
1018         
1019
1020         dprintf_comm(stddeb,"SetCommState: stopbits %d\n",lpdcb->StopBits);
1021         switch (lpdcb->StopBits) {
1022                 case ONESTOPBIT:
1023                                 port.c_cflag &= ~CSTOPB;
1024                                 break;
1025                 case TWOSTOPBITS:
1026                                 port.c_cflag |= CSTOPB;
1027                                 break;
1028                 default:
1029                         commerror = IE_BYTESIZE;
1030                         return -1;
1031         }
1032 #ifdef CRTSCTS
1033
1034         if (lpdcb->fDtrflow || lpdcb->fRtsflow || lpdcb->fOutxCtsFlow)
1035                 port.c_cflag |= CRTSCTS;
1036
1037         if (lpdcb->fDtrDisable) 
1038                 port.c_cflag &= ~CRTSCTS;
1039 #endif  
1040         if (lpdcb->fInX)
1041                 port.c_iflag |= IXON;
1042         if (lpdcb->fOutX)
1043                 port.c_iflag |= IXOFF;
1044
1045         if (tcsetattr(lpdcb->Id, TCSADRAIN, &port) == -1) {
1046                 commerror = WinError(); 
1047                 return -1;
1048         } else {
1049                 commerror = 0;
1050                 return 0;
1051         }
1052 }
1053
1054 /*****************************************************************************
1055  *      SetCommState32  (KERNEL32.452)
1056  */
1057 BOOL32 SetCommState32(INT32 fd,LPDCB32 lpdcb)
1058 {
1059         struct termios port;
1060         struct DosDeviceStruct *ptr;
1061
1062         dprintf_comm(stddeb,"SetCommState: fd %d, ptr %p\n",fd,lpdcb);
1063         if (tcgetattr(fd,&port) == -1) {
1064                 commerror = WinError(); 
1065                 return FALSE;
1066         }
1067
1068         port.c_cc[VMIN] = 0;
1069         port.c_cc[VTIME] = 1;
1070
1071 #ifdef IMAXBEL
1072         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|IMAXBEL);
1073 #else
1074         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR);
1075 #endif
1076         port.c_iflag |= (IGNBRK);
1077
1078         port.c_oflag &= ~(OPOST);
1079
1080         port.c_cflag &= ~(HUPCL);
1081         port.c_cflag |= CLOCAL | CREAD;
1082
1083         port.c_lflag &= ~(ICANON|ECHO|ISIG);
1084         port.c_lflag |= NOFLSH;
1085
1086         if ((ptr = GetDeviceStruct(fd)) == NULL) {
1087                 commerror = IE_BADID;
1088                 return FALSE;
1089         }
1090         if (ptr->baudrate > 0)
1091                 lpdcb->BaudRate = ptr->baudrate;
1092         dprintf_comm(stddeb,"SetCommState: baudrate %ld\n",lpdcb->BaudRate);
1093 #ifdef CBAUD
1094         port.c_cflag &= ~CBAUD;
1095         switch (lpdcb->BaudRate) {
1096                 case 110:
1097                 case CBR_110:
1098                         port.c_cflag |= B110;
1099                         break;          
1100                 case 300:
1101                 case CBR_300:
1102                         port.c_cflag |= B300;
1103                         break;          
1104                 case 600:
1105                 case CBR_600:
1106                         port.c_cflag |= B600;
1107                         break;          
1108                 case 1200:
1109                 case CBR_1200:
1110                         port.c_cflag |= B1200;
1111                         break;          
1112                 case 2400:
1113                 case CBR_2400:
1114                         port.c_cflag |= B2400;
1115                         break;          
1116                 case 4800:
1117                 case CBR_4800:
1118                         port.c_cflag |= B4800;
1119                         break;          
1120                 case 9600:
1121                 case CBR_9600:
1122                         port.c_cflag |= B9600;
1123                         break;          
1124                 case 19200:
1125                 case CBR_19200:
1126                         port.c_cflag |= B19200;
1127                         break;          
1128                 case 38400:
1129                 case CBR_38400:
1130                         port.c_cflag |= B38400;
1131                         break;          
1132                 default:
1133                         commerror = IE_BAUDRATE;
1134                         return FALSE;
1135         }
1136 #elif !defined(__EMX__)
1137         switch (lpdcb->BaudRate) {
1138                 case 110:
1139                 case CBR_110:
1140                         port.c_ospeed = B110;
1141                         break;
1142                 case 300:
1143                 case CBR_300:
1144                         port.c_ospeed = B300;
1145                         break;
1146                 case 600:
1147                 case CBR_600:
1148                         port.c_ospeed = B600;
1149                         break;
1150                 case 1200:
1151                 case CBR_1200:
1152                         port.c_ospeed = B1200;
1153                         break;
1154                 case 2400:
1155                 case CBR_2400:
1156                         port.c_ospeed = B2400;
1157                         break;
1158                 case 4800:
1159                 case CBR_4800:
1160                         port.c_ospeed = B4800;
1161                         break;
1162                 case 9600:
1163                 case CBR_9600:
1164                         port.c_ospeed = B9600;
1165                         break;
1166                 case 19200:
1167                 case CBR_19200:
1168                         port.c_ospeed = B19200;
1169                         break;
1170                 case 38400:
1171                 case CBR_38400:
1172                         port.c_ospeed = B38400;
1173                         break;
1174                 default:
1175                         commerror = IE_BAUDRATE;
1176                         return FALSE;
1177         }
1178         port.c_ispeed = port.c_ospeed;
1179 #endif
1180         dprintf_comm(stddeb,"SetCommState: bytesize %d\n",lpdcb->ByteSize);
1181         port.c_cflag &= ~CSIZE;
1182         switch (lpdcb->ByteSize) {
1183                 case 5:
1184                         port.c_cflag |= CS5;
1185                         break;
1186                 case 6:
1187                         port.c_cflag |= CS6;
1188                         break;
1189                 case 7:
1190                         port.c_cflag |= CS7;
1191                         break;
1192                 case 8:
1193                         port.c_cflag |= CS8;
1194                         break;
1195                 default:
1196                         commerror = IE_BYTESIZE;
1197                         return FALSE;
1198         }
1199
1200         dprintf_comm(stddeb,"SetCommState: parity %d\n",lpdcb->Parity);
1201         port.c_cflag &= ~(PARENB | PARODD);
1202         if (lpdcb->fParity)
1203                 switch (lpdcb->Parity) {
1204                         case NOPARITY:
1205                                 port.c_iflag &= ~INPCK;
1206                                 break;
1207                         case ODDPARITY:
1208                                 port.c_cflag |= (PARENB | PARODD);
1209                                 port.c_iflag |= INPCK;
1210                                 break;
1211                         case EVENPARITY:
1212                                 port.c_cflag |= PARENB;
1213                                 port.c_iflag |= INPCK;
1214                                 break;
1215                         default:
1216                                 commerror = IE_BYTESIZE;
1217                                 return FALSE;
1218                 }
1219         
1220
1221         dprintf_comm(stddeb,"SetCommState: stopbits %d\n",lpdcb->StopBits);
1222         switch (lpdcb->StopBits) {
1223                 case ONESTOPBIT:
1224                                 port.c_cflag &= ~CSTOPB;
1225                                 break;
1226                 case TWOSTOPBITS:
1227                                 port.c_cflag |= CSTOPB;
1228                                 break;
1229                 default:
1230                         commerror = IE_BYTESIZE;
1231                         return FALSE;
1232         }
1233 #ifdef CRTSCTS
1234         if (    lpdcb->fOutxCtsFlow                     ||
1235                 lpdcb->fDtrControl == DTR_CONTROL_ENABLE||
1236                 lpdcb->fRtsControl == RTS_CONTROL_ENABLE
1237         )
1238                 port.c_cflag |= CRTSCTS;
1239         if (lpdcb->fDtrControl == DTR_CONTROL_DISABLE)
1240                 port.c_cflag &= ~CRTSCTS;
1241
1242 #endif  
1243         if (lpdcb->fInX)
1244                 port.c_iflag |= IXON;
1245         if (lpdcb->fOutX)
1246                 port.c_iflag |= IXOFF;
1247
1248         if (tcsetattr(fd,TCSADRAIN,&port)==-1) {
1249                 commerror = WinError(); 
1250                 return FALSE;
1251         } else {
1252                 commerror = 0;
1253                 return TRUE;
1254         }
1255 }
1256
1257
1258 /*****************************************************************************
1259  *      GetCommState    (USER.202)
1260  */
1261 INT16 GetCommState16(INT16 fd, LPDCB16 lpdcb)
1262 {
1263         struct termios port;
1264
1265         dprintf_comm(stddeb,"GetCommState: fd %d, ptr %p\n", fd, lpdcb);
1266         if (tcgetattr(fd, &port) == -1) {
1267                 commerror = WinError(); 
1268                 return -1;
1269         }
1270         lpdcb->Id = fd;
1271 #ifndef __EMX__
1272 #ifdef CBAUD
1273         switch (port.c_cflag & CBAUD) {
1274 #else
1275         switch (port.c_ospeed) {
1276 #endif
1277                 case B110:
1278                         lpdcb->BaudRate = 110;
1279                         break;
1280                 case B300:
1281                         lpdcb->BaudRate = 300;
1282                         break;
1283                 case B600:
1284                         lpdcb->BaudRate = 600;
1285                         break;
1286                 case B1200:
1287                         lpdcb->BaudRate = 1200;
1288                         break;
1289                 case B2400:
1290                         lpdcb->BaudRate = 2400;
1291                         break;
1292                 case B4800:
1293                         lpdcb->BaudRate = 4800;
1294                         break;
1295                 case B9600:
1296                         lpdcb->BaudRate = 9600;
1297                         break;
1298                 case B19200:
1299                         lpdcb->BaudRate = 19200;
1300                         break;
1301                 case B38400:
1302                         lpdcb->BaudRate = 38400;
1303                         break;
1304         }
1305 #endif
1306         switch (port.c_cflag & CSIZE) {
1307                 case CS5:
1308                         lpdcb->ByteSize = 5;
1309                         break;
1310                 case CS6:
1311                         lpdcb->ByteSize = 6;
1312                         break;
1313                 case CS7:
1314                         lpdcb->ByteSize = 7;
1315                         break;
1316                 case CS8:
1317                         lpdcb->ByteSize = 8;
1318                         break;
1319         }       
1320         
1321         switch (port.c_cflag & ~(PARENB | PARODD)) {
1322                 case 0:
1323                         lpdcb->fParity = NOPARITY;
1324                         break;
1325                 case PARENB:
1326                         lpdcb->fParity = EVENPARITY;
1327                         break;
1328                 case (PARENB | PARODD):
1329                         lpdcb->fParity = ODDPARITY;             
1330                         break;
1331         }
1332
1333         if (port.c_cflag & CSTOPB)
1334                 lpdcb->StopBits = TWOSTOPBITS;
1335         else
1336                 lpdcb->StopBits = ONESTOPBIT;
1337
1338         lpdcb->RlsTimeout = 50;
1339         lpdcb->CtsTimeout = 50; 
1340         lpdcb->DsrTimeout = 50;
1341         lpdcb->fNull = 0;
1342         lpdcb->fChEvt = 0;
1343         lpdcb->fBinary = 1;
1344         lpdcb->fDtrDisable = 0;
1345
1346 #ifdef CRTSCTS
1347
1348         if (port.c_cflag & CRTSCTS) {
1349                 lpdcb->fDtrflow = 1;
1350                 lpdcb->fRtsflow = 1;
1351                 lpdcb->fOutxCtsFlow = 1;
1352                 lpdcb->fOutxDsrFlow = 1;
1353         } else 
1354 #endif
1355                 lpdcb->fDtrDisable = 1;
1356
1357         if (port.c_iflag & IXON)
1358                 lpdcb->fInX = 1;
1359         else
1360                 lpdcb->fInX = 0;
1361
1362         if (port.c_iflag & IXOFF)
1363                 lpdcb->fOutX = 1;
1364         else
1365                 lpdcb->fOutX = 0;
1366 /*
1367         lpdcb->XonChar = 
1368         lpdcb->XoffChar = 
1369  */
1370         lpdcb->XonLim = 10;
1371         lpdcb->XoffLim = 10;
1372
1373         commerror = 0;
1374         return 0;
1375 }
1376
1377 /*****************************************************************************
1378  *      GetCommState    (KERNEL32.159)
1379  */
1380 BOOL32 GetCommState32(INT32 fd, LPDCB32 lpdcb)
1381 {
1382         struct termios  port;
1383
1384
1385         dprintf_comm(stddeb,"GetCommState32: fd %d, ptr %p\n", fd, lpdcb);
1386         if (tcgetattr(fd, &port) == -1) {
1387                 commerror = WinError(); 
1388                 return FALSE;
1389         }
1390 #ifndef __EMX__
1391 #ifdef CBAUD
1392         switch (port.c_cflag & CBAUD) {
1393 #else
1394         switch (port.c_ospeed) {
1395 #endif
1396                 case B110:
1397                         lpdcb->BaudRate = 110;
1398                         break;
1399                 case B300:
1400                         lpdcb->BaudRate = 300;
1401                         break;
1402                 case B600:
1403                         lpdcb->BaudRate = 600;
1404                         break;
1405                 case B1200:
1406                         lpdcb->BaudRate = 1200;
1407                         break;
1408                 case B2400:
1409                         lpdcb->BaudRate = 2400;
1410                         break;
1411                 case B4800:
1412                         lpdcb->BaudRate = 4800;
1413                         break;
1414                 case B9600:
1415                         lpdcb->BaudRate = 9600;
1416                         break;
1417                 case B19200:
1418                         lpdcb->BaudRate = 19200;
1419                         break;
1420                 case B38400:
1421                         lpdcb->BaudRate = 38400;
1422                         break;
1423         }
1424 #endif
1425         switch (port.c_cflag & CSIZE) {
1426                 case CS5:
1427                         lpdcb->ByteSize = 5;
1428                         break;
1429                 case CS6:
1430                         lpdcb->ByteSize = 6;
1431                         break;
1432                 case CS7:
1433                         lpdcb->ByteSize = 7;
1434                         break;
1435                 case CS8:
1436                         lpdcb->ByteSize = 8;
1437                         break;
1438         }       
1439         
1440         switch (port.c_cflag & ~(PARENB | PARODD)) {
1441                 case 0:
1442                         lpdcb->fParity = NOPARITY;
1443                         break;
1444                 case PARENB:
1445                         lpdcb->fParity = EVENPARITY;
1446                         break;
1447                 case (PARENB | PARODD):
1448                         lpdcb->fParity = ODDPARITY;             
1449                         break;
1450         }
1451
1452         if (port.c_cflag & CSTOPB)
1453                 lpdcb->StopBits = TWOSTOPBITS;
1454         else
1455                 lpdcb->StopBits = ONESTOPBIT;
1456
1457         lpdcb->fNull = 0;
1458         lpdcb->fBinary = 1;
1459
1460 #ifdef CRTSCTS
1461
1462         if (port.c_cflag & CRTSCTS) {
1463                 lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
1464                 lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
1465                 lpdcb->fOutxCtsFlow = 1;
1466                 lpdcb->fOutxDsrFlow = 1;
1467         } else 
1468 #endif
1469         {
1470                 lpdcb->fDtrControl = DTR_CONTROL_DISABLE;
1471                 lpdcb->fRtsControl = RTS_CONTROL_DISABLE;
1472         }
1473         if (port.c_iflag & IXON)
1474                 lpdcb->fInX = 1;
1475         else
1476                 lpdcb->fInX = 0;
1477
1478         if (port.c_iflag & IXOFF)
1479                 lpdcb->fOutX = 1;
1480         else
1481                 lpdcb->fOutX = 0;
1482 /*
1483         lpdcb->XonChar = 
1484         lpdcb->XoffChar = 
1485  */
1486         lpdcb->XonLim = 10;
1487         lpdcb->XoffLim = 10;
1488
1489         commerror = 0;
1490         return TRUE;
1491 }
1492
1493 /*****************************************************************************
1494  *      TransmitCommChar        (USER.206)
1495  */
1496 INT16 TransmitCommChar16(INT16 fd,CHAR chTransmit)
1497 {
1498         struct DosDeviceStruct *ptr;
1499
1500         dprintf_comm(stddeb,
1501                 "TransmitCommChar: fd %d, data %d \n", fd, chTransmit);
1502         if ((ptr = GetDeviceStruct(fd)) == NULL) {
1503                 commerror = IE_BADID;
1504                 return -1;
1505         }
1506
1507         if (ptr->suspended) {
1508                 commerror = IE_HARDWARE;
1509                 return -1;
1510         }       
1511
1512         if (write(fd, (void *) &chTransmit, 1) == -1) {
1513                 commerror = WinError();
1514                 return -1;      
1515         }  else {
1516                 commerror = 0;
1517                 return 0;
1518         }
1519 }
1520
1521 /*****************************************************************************
1522  *      TransmitCommChar        (KERNEL32.535)
1523  */
1524 BOOL32 TransmitCommChar32(INT32 fd,CHAR chTransmit)
1525 {
1526         struct DosDeviceStruct *ptr;
1527
1528         dprintf_comm(stddeb,"TransmitCommChar32(%d,'%c')\n",fd,chTransmit);
1529         if ((ptr = GetDeviceStruct(fd)) == NULL) {
1530                 commerror = IE_BADID;
1531                 return FALSE;
1532         }
1533
1534         if (ptr->suspended) {
1535                 commerror = IE_HARDWARE;
1536                 return FALSE;
1537         }
1538         if (write(fd, (void *) &chTransmit, 1) == -1) {
1539                 commerror = WinError();
1540                 return FALSE;
1541         }  else {
1542                 commerror = 0;
1543                 return TRUE;
1544         }
1545 }
1546
1547 /*****************************************************************************
1548  *      UngetCommChar   (USER.212)
1549  */
1550 INT16 UngetCommChar(INT16 fd,CHAR chUnget)
1551 {
1552         struct DosDeviceStruct *ptr;
1553
1554         dprintf_comm(stddeb,"UngetCommChar: fd %d (char %d)\n", fd, chUnget);
1555         if ((ptr = GetDeviceStruct(fd)) == NULL) {
1556                 commerror = IE_BADID;
1557                 return -1;
1558         }
1559
1560         if (ptr->suspended) {
1561                 commerror = IE_HARDWARE;
1562                 return -1;
1563         }       
1564
1565         ptr->unget = 1;
1566         ptr->unget_byte = chUnget;
1567         commerror = 0;
1568         return 0;
1569 }
1570
1571 /*****************************************************************************
1572  *      ReadComm        (USER.204)
1573  */
1574 INT16 ReadComm(INT16 fd,LPSTR lpvBuf,INT16 cbRead)
1575 {
1576         int status, length;
1577         struct DosDeviceStruct *ptr;
1578
1579         dprintf_comm(stddeb,
1580             "ReadComm: fd %d, ptr %p, length %d\n", fd, lpvBuf, cbRead);
1581         if ((ptr = GetDeviceStruct(fd)) == NULL) {
1582                 commerror = IE_BADID;
1583                 return -1;
1584         }
1585
1586         if (ptr->suspended) {
1587                 commerror = IE_HARDWARE;
1588                 return -1;
1589         }       
1590
1591         if (ptr->unget) {
1592                 *lpvBuf = ptr->unget_byte;
1593                 lpvBuf++;
1594                 ptr->unget = 0;
1595
1596                 length = 1;
1597         } else
1598                 length = 0;
1599
1600         status = read(fd, (void *) lpvBuf, cbRead);
1601
1602         if (status == -1) {
1603                 if (errno != EAGAIN) {
1604                        commerror = WinError();
1605                        return -1 - length;
1606                 } else {
1607                         commerror = 0;
1608                         return length;
1609                 }
1610         } else {
1611                 commerror = 0;
1612                 return length + status;
1613         }
1614 }
1615
1616 /*****************************************************************************
1617  *      WriteComm       (USER.205)
1618  */
1619 INT16 WriteComm(INT16 fd, LPSTR lpvBuf, INT16 cbWrite)
1620 {
1621         int x, length;
1622         struct DosDeviceStruct *ptr;
1623
1624         dprintf_comm(stddeb,"WriteComm: fd %d, ptr %p, length %d\n", 
1625                 fd, lpvBuf, cbWrite);
1626         if ((ptr = GetDeviceStruct(fd)) == NULL) {
1627                 commerror = IE_BADID;
1628                 return -1;
1629         }
1630
1631         if (ptr->suspended) {
1632                 commerror = IE_HARDWARE;
1633                 return -1;
1634         }       
1635         
1636         for (x=0; x != cbWrite ; x++)
1637         dprintf_comm(stddeb,"%c", *(lpvBuf + x) );
1638
1639         length = write(fd, (void *) lpvBuf, cbWrite);
1640         
1641         if (length == -1) {
1642                 commerror = WinError();
1643                 return -1;      
1644         } else {
1645                 commerror = 0;  
1646                 return length;
1647         }
1648 }
1649
1650
1651 /*****************************************************************************
1652  *      GetCommTimeouts         (KERNEL32.160)
1653  */
1654 BOOL32 GetCommTimeouts(INT32 fd,LPCOMMTIMEOUTS lptimeouts) {
1655         dprintf_comm(stddeb,"GetCommTimeouts(%x,%p), empty stub.\n",
1656                 fd,lptimeouts
1657         );
1658         return TRUE;
1659 }
1660
1661 /*****************************************************************************
1662  *      SetCommTimeouts         (KERNEL32.453)
1663  */
1664 BOOL32 SetCommTimeouts(INT32 fd,LPCOMMTIMEOUTS lptimeouts) {
1665         dprintf_comm(stddeb,"SetCommTimeouts(%x,%p), empty stub.\n",
1666                 fd,lptimeouts
1667         );
1668         return TRUE;
1669 }