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