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