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