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