Release 960405
[wine] / misc / comm.c
1 /*
2  * DEC 93 Erik Bos <erik@xs4all.nl>
3  */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <termios.h>
8 #include <fcntl.h>
9 #include <string.h>
10 #include <errno.h>
11 #include <ctype.h>
12 #include <sys/stat.h>
13 #if defined(__NetBSD__) || defined(__FreeBSD__)
14 #include <errno.h>
15 #include <sys/ioctl.h>
16 #endif
17 #include <unistd.h>
18
19 #include "windows.h"
20 #include "comm.h"
21 #include "options.h"
22 #include "stddebug.h"
23 /* #define DEBUG_COMM */
24 /* #undef  DEBUG_COMM */
25 #include "debug.h"
26
27 int commerror = 0, eventmask = 0;
28
29 struct DosDeviceStruct COM[MAX_PORTS];
30 struct DosDeviceStruct LPT[MAX_PORTS];
31
32 void COMM_Init(void)
33 {
34         int x;
35         char option[10], temp[256], *btemp;
36         struct stat st;
37
38         for (x=0; x!=MAX_PORTS; x++) {
39                 strcpy(option,"COMx");
40                 option[3] = '1' + x;
41                 option[4] = '\0';
42
43                 PROFILE_GetWineIniString( "serialports", option, "*",
44                                           temp, sizeof(temp) );
45                 if (!strcmp(temp, "*") || *temp == '\0') 
46                         COM[x].devicename = NULL;
47                 else {
48                         btemp = strchr(temp,',');
49                         if (btemp != NULL) {
50                                 *btemp++ = '\0';
51                                 COM[x].baudrate = atoi(btemp);
52                         } else {
53                                 COM[x].baudrate = -1;
54                         }
55                         stat(temp, &st);
56                         if (!S_ISCHR(st.st_mode)) 
57                                 fprintf(stderr,"comm: can't use `%s' as %s !\n", temp, option);
58                         else
59                                 if ((COM[x].devicename = malloc(strlen(temp)+1)) == NULL) 
60                                         fprintf(stderr,"comm: can't malloc for device info!\n");
61                                 else {
62                                         COM[x].fd = 0;
63                                         strcpy(COM[x].devicename, temp);
64                                 }
65                 dprintf_comm(stddeb,
66                         "Comm_Init: %s = %s\n", option, COM[x].devicename);
67                 }
68
69                 strcpy(option, "LPTx");
70                 option[3] = '1' + x;
71                 option[4] = '\0';
72
73                 PROFILE_GetWineIniString( "parallelports", option, "*",
74                                           temp, sizeof(temp) );
75                 if (!strcmp(temp, "*") || *temp == '\0')
76                         LPT[x].devicename = NULL;
77                 else {
78                         stat(temp, &st);
79                         if (!S_ISCHR(st.st_mode)) 
80                                 fprintf(stderr,"comm: can't use `%s' as %s !\n", temp, option);
81                         else 
82                                 if ((LPT[x].devicename = malloc(strlen(temp)+1)) == NULL) 
83                                         fprintf(stderr,"comm: can't malloc for device info!\n");
84                                 else {
85                                         LPT[x].fd = 0;
86                                         strcpy(LPT[x].devicename, temp);
87                                 }
88                 dprintf_comm(stddeb,
89                         "Comm_Init: %s = %s\n", option, LPT[x].devicename);
90                 }
91
92         }
93 }
94
95
96 struct DosDeviceStruct *GetDeviceStruct(int fd)
97 {
98         int x;
99         
100         for (x=0; x!=MAX_PORTS; x++) {
101             if (COM[x].fd == fd)
102                 return &COM[x];
103             if (LPT[x].fd == fd)
104                 return &LPT[x];
105         }
106
107         return NULL;
108 }
109
110 int ValidCOMPort(int x)
111 {
112         return(x < MAX_PORTS ? (int) COM[x].devicename : 0); 
113 }
114
115 int ValidLPTPort(int x)
116 {
117         return(x < MAX_PORTS ? (int) LPT[x].devicename : 0); 
118 }
119
120 int WinError(void)
121 {
122         dprintf_comm(stddeb, "WinError: errno = %d\n", errno);
123         switch (errno) {
124                 default:
125                         return CE_IOE;
126                 }
127 }
128
129 BOOL BuildCommDCB(LPCSTR device, LPDCB lpdcb)
130 {
131         /* "COM1:9600,n,8,1"    */
132         /*  012345              */
133
134         int port;
135         char *ptr, temp[256];
136
137         dprintf_comm(stddeb,
138                 "BuildCommDCB: (%s), ptr %p\n", device, lpdcb);
139         commerror = 0;
140
141         if (!lstrncmpi(device,"COM",3)) {
142                 port = device[3] - '0';
143         
144
145                 if (port-- == 0) {
146                         fprintf(stderr, "comm: BUG ! COM0 can't exists!.\n");
147                         commerror = IE_BADID;
148                 }
149
150                 if (!ValidCOMPort(port)) {
151                         commerror = IE_BADID;
152                         return -1;
153                 }
154                 
155                 if (!COM[port].fd) {
156                     OpenComm(device, 0, 0);
157                 }
158                 lpdcb->Id = COM[port].fd;
159                 
160                 if (!*(device+4))
161                         return 0;
162
163                 if (*(device+4) != ':')
164                         return -1;
165                 
166                 strcpy(temp,device+5);
167                 ptr = strtok(temp, ","); 
168
169                 if (COM[port].baudrate > 0)
170                         lpdcb->BaudRate = COM[port].baudrate;
171                 else
172                         lpdcb->BaudRate = atoi(ptr);
173                 dprintf_comm(stddeb,"BuildCommDCB: baudrate (%d)\n", lpdcb->BaudRate);
174
175                 ptr = strtok(NULL, ",");
176                 if (islower(*ptr))
177                         *ptr = toupper(*ptr);
178
179                 dprintf_comm(stddeb,"BuildCommDCB: parity (%c)\n", *ptr);
180                 switch (*ptr) {
181                         case 'N':
182                                 lpdcb->Parity = NOPARITY;
183                                 lpdcb->fParity = 0;
184                                 break;                  
185                         
186                         lpdcb->fParity = 1;
187                         
188                         case 'E':
189                                 lpdcb->Parity = EVENPARITY;
190                                 break;                  
191                         case 'M':
192                                 lpdcb->Parity = MARKPARITY;
193                                 break;                  
194                         case 'O':
195                                 lpdcb->Parity = ODDPARITY;
196                                 break;                  
197                         default:
198                                 fprintf(stderr,"comm: unknown parity `%c'!\n", *ptr);
199                                 return -1;
200                 }
201
202                 ptr = strtok(NULL, ","); 
203                 dprintf_comm(stddeb, "BuildCommDCB: charsize (%c)\n", *ptr);
204                 lpdcb->ByteSize = *ptr - '0';
205
206                 ptr = strtok(NULL, ",");
207                 dprintf_comm(stddeb, "BuildCommDCB: stopbits (%c)\n", *ptr);
208                 switch (*ptr) {
209                         case '1':
210                                 lpdcb->StopBits = ONESTOPBIT;
211                                 break;                  
212                         case '2':
213                                 lpdcb->StopBits = TWOSTOPBITS;
214                                 break;                  
215                         default:
216                                 fprintf(stderr,"comm: unknown # of stopbits `%c'!\n", *ptr);
217                                 return -1;
218                 }
219         }       
220
221         return 0;
222 }
223
224 int OpenComm(LPCSTR device, UINT cbInQueue, UINT cbOutQueue)
225 {
226         int port, fd;
227
228         dprintf_comm(stddeb,
229                 "OpenComm: %s, %d, %d\n", device, cbInQueue, cbOutQueue);
230         commerror = 0;
231
232         if (!lstrncmpi(device,"COM",3)) {
233                 port = device[3] - '0';
234
235                 if (port-- == 0) {
236                         fprintf(stderr, "comm: BUG ! COM0 doesn't exists!.\n");
237                         commerror = IE_BADID;
238                 }
239
240                 dprintf_comm(stddeb,
241                        "OpenComm: %s = %s\n", device, COM[port].devicename);
242
243                 if (!ValidCOMPort(port)) {
244                         commerror = IE_BADID;
245                         return -1;
246                 }
247                 if (COM[port].fd) {
248                         return COM[port].fd;
249                 }
250
251                 fd = open(COM[port].devicename, O_RDWR | O_NONBLOCK);
252                 if (fd == -1) {
253                         commerror = WinError();
254                         return -1;
255                 } else {
256                         COM[port].fd = fd;      
257                         return fd;
258                 }
259         } 
260         else 
261         if (!lstrncmpi(device,"LPT",3)) {
262                 port = device[3] - '0';
263         
264                 if (!ValidLPTPort(port)) {
265                         commerror = IE_BADID;
266                         return -1;
267                 }               
268                 if (LPT[port].fd) {
269                         commerror = IE_OPEN;
270                         return -1;
271                 }
272
273                 fd = open(LPT[port].devicename, O_RDWR | O_NONBLOCK, 0);
274                 if (fd == -1) {
275                         commerror = WinError();
276                         return -1;      
277                 } else {
278                         LPT[port].fd = fd;
279                         return fd;
280                 }
281         }
282         return 0;
283 }
284
285 int CloseComm(int fd)
286 {
287         dprintf_comm(stddeb,"CloseComm: fd %d\n", fd);
288         if (close(fd) == -1) {
289                 commerror = WinError();
290                 return -1;
291         } else {
292                 commerror = 0;
293                 return 0;
294         }
295 }
296
297 int SetCommBreak(int fd)
298 {
299         struct DosDeviceStruct *ptr;
300
301         dprintf_comm(stddeb,"SetCommBreak: fd: %d\n", fd);
302         if ((ptr = GetDeviceStruct(fd)) == NULL) {
303                 commerror = IE_BADID;
304                 return -1;
305         }
306
307         ptr->suspended = 1;
308         commerror = 0;
309         return 0;
310 }
311
312 int ClearCommBreak(int fd)
313 {
314         struct DosDeviceStruct *ptr;
315
316         dprintf_comm(stddeb,"ClearCommBreak: fd: %d\n", fd);
317         if ((ptr = GetDeviceStruct(fd)) == NULL) {
318                 commerror = IE_BADID;
319                 return -1;
320         }
321
322         ptr->suspended = 0;
323         commerror = 0;
324         return 0;
325 }
326
327 LONG EscapeCommFunction(int fd, int nFunction)
328 {
329         int max;
330         struct termios port;
331
332         dprintf_comm(stddeb,
333                 "EscapeCommFunction fd: %d, function: %d\n", fd, nFunction);
334         if (tcgetattr(fd, &port) == -1) {
335                 commerror = WinError(); 
336                 return -1;
337         }
338
339         switch (nFunction) {
340                 case RESETDEV:
341                         break;                                  
342
343                 case GETMAXCOM:
344                         for (max = MAX_PORTS;!COM[max].devicename;max--)
345                                 ;               
346                         return max;
347                         break;
348
349                 case GETMAXLPT:
350                         for (max = MAX_PORTS;!LPT[max].devicename;max--)
351                                 ;               
352                         return 0x80 + max;
353                         break;
354
355 #ifdef TIOCM_DTR
356                 case CLRDTR:
357                         port.c_cflag &= TIOCM_DTR;
358                         break;
359 #endif
360
361 #ifdef TIOCM_RTS
362                 case CLRRTS:
363                         port.c_cflag &= TIOCM_RTS;
364                         break;
365 #endif
366         
367 #ifdef CRTSCTS
368                 case SETDTR:
369                         port.c_cflag |= CRTSCTS;
370                         break;
371
372                 case SETRTS:
373                         port.c_cflag |= CRTSCTS;
374                         break;
375 #endif
376
377                 case SETXOFF:
378                         port.c_iflag |= IXOFF;
379                         break;
380
381                 case SETXON:
382                         port.c_iflag |= IXON;
383                         break;
384
385                 default:
386                         fprintf(stderr,
387                         "EscapeCommFunction fd: %d, unknown function: %d\n", 
388                         fd, nFunction);
389                         break;                          
390         }
391         
392         if (tcsetattr(fd, TCSADRAIN, &port) == -1) {
393                 commerror = WinError();
394                 return -1;      
395         } else {
396                 commerror = 0;
397                 return 0;
398         }
399 }
400
401 int FlushComm(int fd, int fnQueue)
402 {
403         int queue;
404
405         dprintf_comm(stddeb,"FlushComm fd: %d, queue: %d\n", fd, fnQueue);
406         switch (fnQueue) {
407                 case 0:
408                         queue = TCOFLUSH;
409                         break;
410                 case 1:
411                         queue = TCIFLUSH;
412                         break;
413                 default:
414                         fprintf(stderr,
415                                 "FlushComm fd: %d, UNKNOWN queue: %d\n", 
416                                 fd, fnQueue);
417                         return -1;
418                 }
419         
420         if (tcflush(fd, fnQueue)) {
421                 commerror = WinError();
422                 return -1;      
423         } else {
424                 commerror = 0;
425                 return 0;
426         }
427 }  
428
429 int GetCommError(int fd, COMSTAT FAR *lpStat)
430 {
431         int temperror;
432
433         dprintf_comm(stddeb,
434                 "GetCommError: fd %d (current error %d)\n", fd, commerror);
435         temperror = commerror;
436         commerror = 0;
437         return(temperror);
438 }
439
440 UINT FAR* SetCommEventMask(int fd, UINT fuEvtMask)
441 {
442         dprintf_comm(stddeb,
443                 "SetCommEventMask: fd %d, mask %d\n", fd, fuEvtMask);
444         eventmask |= fuEvtMask;
445         return (UINT *)&eventmask;
446 }
447
448 UINT GetCommEventMask(int fd, int fnEvtClear)
449 {
450         dprintf_comm(stddeb,
451                 "GetCommEventMask: fd %d, mask %d\n", fd, fnEvtClear);
452         eventmask &= ~fnEvtClear;
453         return eventmask;
454 }
455
456 int SetCommState(DCB FAR *lpdcb)
457 {
458         struct termios port;
459         struct DosDeviceStruct *ptr;
460
461         dprintf_comm(stddeb,
462                 "SetCommState: fd %d, ptr %p\n", lpdcb->Id, lpdcb);
463         if (tcgetattr(lpdcb->Id, &port) == -1) {
464                 commerror = WinError(); 
465                 return -1;
466         }
467
468         port.c_cc[VMIN] = 0;
469         port.c_cc[VTIME] = 1;
470
471 #ifdef IMAXBEL
472         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|IMAXBEL);
473 #else
474         port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR);
475 #endif
476         port.c_iflag |= (IGNBRK);
477
478         port.c_oflag &= ~(OPOST);
479
480         port.c_cflag &= ~(HUPCL);
481         port.c_cflag |= CLOCAL | CREAD;
482
483         port.c_lflag &= ~(ICANON|ECHO|ISIG);
484         port.c_lflag |= NOFLSH;
485
486         if ((ptr = GetDeviceStruct(lpdcb->Id)) == NULL) {
487                 commerror = IE_BADID;
488                 return -1;
489         }
490         if (ptr->baudrate > 0)
491                 lpdcb->BaudRate = ptr->baudrate;
492         dprintf_comm(stddeb,"SetCommState: baudrate %d\n",lpdcb->BaudRate);
493 #ifdef CBAUD
494         port.c_cflag &= ~CBAUD;
495         switch (lpdcb->BaudRate) {
496                 case 110:
497                 case CBR_110:
498                         port.c_cflag |= B110;
499                         break;          
500                 case 300:
501                 case CBR_300:
502                         port.c_cflag |= B300;
503                         break;          
504                 case 600:
505                 case CBR_600:
506                         port.c_cflag |= B600;
507                         break;          
508                 case 1200:
509                 case CBR_1200:
510                         port.c_cflag |= B1200;
511                         break;          
512                 case 2400:
513                 case CBR_2400:
514                         port.c_cflag |= B2400;
515                         break;          
516                 case 4800:
517                 case CBR_4800:
518                         port.c_cflag |= B4800;
519                         break;          
520                 case 9600:
521                 case CBR_9600:
522                         port.c_cflag |= B9600;
523                         break;          
524                 case 19200:
525                 case CBR_19200:
526                         port.c_cflag |= B19200;
527                         break;          
528                 case 38400:
529                 case CBR_38400:
530                         port.c_cflag |= B38400;
531                         break;          
532                 default:
533                         commerror = IE_BAUDRATE;
534                         return -1;
535         }
536 #else
537         switch (lpdcb->BaudRate) {
538                 case 110:
539                 case CBR_110:
540                         port.c_ospeed = B110;
541                         break;
542                 case 300:
543                 case CBR_300:
544                         port.c_ospeed = B300;
545                         break;
546                 case 600:
547                 case CBR_600:
548                         port.c_ospeed = B600;
549                         break;
550                 case 1200:
551                 case CBR_1200:
552                         port.c_ospeed = B1200;
553                         break;
554                 case 2400:
555                 case CBR_2400:
556                         port.c_ospeed = B2400;
557                         break;
558                 case 4800:
559                 case CBR_4800:
560                         port.c_ospeed = B4800;
561                         break;
562                 case 9600:
563                 case CBR_9600:
564                         port.c_ospeed = B9600;
565                         break;
566                 case 19200:
567                 case CBR_19200:
568                         port.c_ospeed = B19200;
569                         break;
570                 case 38400:
571                 case CBR_38400:
572                         port.c_ospeed = B38400;
573                         break;
574                 default:
575                         commerror = IE_BAUDRATE;
576                         return -1;
577         }
578         port.c_ispeed = port.c_ospeed;
579 #endif
580         dprintf_comm(stddeb,"SetCommState: bytesize %d\n",lpdcb->ByteSize);
581         port.c_cflag &= ~CSIZE;
582         switch (lpdcb->ByteSize) {
583                 case 5:
584                         port.c_cflag |= CS5;
585                         break;
586                 case 6:
587                         port.c_cflag |= CS6;
588                         break;
589                 case 7:
590                         port.c_cflag |= CS7;
591                         break;
592                 case 8:
593                         port.c_cflag |= CS8;
594                         break;
595                 default:
596                         commerror = IE_BYTESIZE;
597                         return -1;
598         }
599
600         dprintf_comm(stddeb,"SetCommState: parity %d\n",lpdcb->Parity);
601         port.c_cflag &= ~(PARENB | PARODD);
602         if (lpdcb->fParity)
603                 switch (lpdcb->Parity) {
604                         case NOPARITY:
605                                 port.c_iflag &= ~INPCK;
606                                 break;
607                         case ODDPARITY:
608                                 port.c_cflag |= (PARENB | PARODD);
609                                 port.c_iflag |= INPCK;
610                                 break;
611                         case EVENPARITY:
612                                 port.c_cflag |= PARENB;
613                                 port.c_iflag |= INPCK;
614                                 break;
615                         default:
616                                 commerror = IE_BYTESIZE;
617                                 return -1;
618                 }
619         
620
621         dprintf_comm(stddeb,"SetCommState: stopbits %d\n",lpdcb->StopBits);
622         switch (lpdcb->StopBits) {
623                 case ONESTOPBIT:
624                                 port.c_cflag &= ~CSTOPB;
625                                 break;
626                 case TWOSTOPBITS:
627                                 port.c_cflag |= CSTOPB;
628                                 break;
629                 default:
630                         commerror = IE_BYTESIZE;
631                         return -1;
632         }
633 #ifdef CRTSCTS
634
635         if (lpdcb->fDtrflow || lpdcb->fRtsflow || lpdcb->fOutxCtsFlow)
636                 port.c_cflag |= CRTSCTS;
637
638         if (lpdcb->fDtrDisable) 
639                 port.c_cflag &= ~CRTSCTS;
640 #endif  
641         if (lpdcb->fInX)
642                 port.c_iflag |= IXON;
643         if (lpdcb->fOutX)
644                 port.c_iflag |= IXOFF;
645
646         if (tcsetattr(lpdcb->Id, TCSADRAIN, &port) == -1) {
647                 commerror = WinError(); 
648                 return -1;
649         } else {
650                 commerror = 0;
651                 return 0;
652         }
653 }
654
655 int GetCommState(int fd, DCB FAR *lpdcb)
656 {
657         struct termios port;
658
659         dprintf_comm(stddeb,"GetCommState: fd %d, ptr %p\n", fd, lpdcb);
660         if (tcgetattr(fd, &port) == -1) {
661                 commerror = WinError(); 
662                 return -1;
663         }
664
665         lpdcb->Id = fd;
666
667 #ifdef CBAUD
668         switch (port.c_cflag & CBAUD) {
669 #else
670         switch (port.c_ospeed) {
671 #endif
672                 case B110:
673                         lpdcb->BaudRate = 110;
674                         break;
675                 case B300:
676                         lpdcb->BaudRate = 300;
677                         break;
678                 case B600:
679                         lpdcb->BaudRate = 600;
680                         break;
681                 case B1200:
682                         lpdcb->BaudRate = 1200;
683                         break;
684                 case B2400:
685                         lpdcb->BaudRate = 2400;
686                         break;
687                 case B4800:
688                         lpdcb->BaudRate = 4800;
689                         break;
690                 case B9600:
691                         lpdcb->BaudRate = 9600;
692                         break;
693                 case B19200:
694                         lpdcb->BaudRate = 19200;
695                         break;
696                 case B38400:
697                         lpdcb->BaudRate = 38400;
698                         break;
699         }
700
701         switch (port.c_cflag & CSIZE) {
702                 case CS5:
703                         lpdcb->ByteSize = 5;
704                         break;
705                 case CS6:
706                         lpdcb->ByteSize = 6;
707                         break;
708                 case CS7:
709                         lpdcb->ByteSize = 7;
710                         break;
711                 case CS8:
712                         lpdcb->ByteSize = 8;
713                         break;
714         }       
715         
716         switch (port.c_cflag & ~(PARENB | PARODD)) {
717                 case 0:
718                         lpdcb->fParity = NOPARITY;
719                         break;
720                 case PARENB:
721                         lpdcb->fParity = EVENPARITY;
722                         break;
723                 case (PARENB | PARODD):
724                         lpdcb->fParity = ODDPARITY;             
725                         break;
726         }
727
728         if (port.c_cflag & CSTOPB)
729                 lpdcb->StopBits = TWOSTOPBITS;
730         else
731                 lpdcb->StopBits = ONESTOPBIT;
732
733         lpdcb->RlsTimeout = 50;
734         lpdcb->CtsTimeout = 50; 
735         lpdcb->DsrTimeout = 50;
736         lpdcb->fNull = 0;
737         lpdcb->fChEvt = 0;
738         lpdcb->fBinary = 1;
739         lpdcb->fDtrDisable = 0;
740
741 #ifdef CRTSCTS
742
743         if (port.c_cflag & CRTSCTS) {
744                 lpdcb->fDtrflow = 1;
745                 lpdcb->fRtsflow = 1;
746                 lpdcb->fOutxCtsFlow = 1;
747                 lpdcb->fOutxDsrFlow = 1;
748         } else 
749 #endif
750                 lpdcb->fDtrDisable = 1;
751
752         if (port.c_iflag & IXON)
753                 lpdcb->fInX = 1;
754         else
755                 lpdcb->fInX = 0;
756
757         if (port.c_iflag & IXOFF)
758                 lpdcb->fOutX = 1;
759         else
760                 lpdcb->fOutX = 0;
761 /*
762         lpdcb->XonChar = 
763         lpdcb->XoffChar = 
764  */
765         lpdcb->XonLim = 10;
766         lpdcb->XoffLim = 10;
767
768         commerror = 0;
769         return 0;
770 }
771
772 int TransmitCommChar(int fd, char chTransmit)
773 {
774         struct DosDeviceStruct *ptr;
775
776         dprintf_comm(stddeb,
777                 "TransmitCommChar: fd %d, data %d \n", fd, chTransmit);
778         if ((ptr = GetDeviceStruct(fd)) == NULL) {
779                 commerror = IE_BADID;
780                 return -1;
781         }
782
783         if (ptr->suspended) {
784                 commerror = IE_HARDWARE;
785                 return -1;
786         }       
787
788         if (write(fd, (void *) &chTransmit, 1) == -1) {
789                 commerror = WinError();
790                 return -1;      
791         }  else {
792                 commerror = 0;
793                 return 0;
794         }
795 }
796
797 int UngetCommChar(int fd, char chUnget)
798 {
799         struct DosDeviceStruct *ptr;
800
801         dprintf_comm(stddeb,"UngetCommChar: fd %d (char %d)\n", fd, chUnget);
802         if ((ptr = GetDeviceStruct(fd)) == NULL) {
803                 commerror = IE_BADID;
804                 return -1;
805         }
806
807         if (ptr->suspended) {
808                 commerror = IE_HARDWARE;
809                 return -1;
810         }       
811
812         ptr->unget = 1;
813         ptr->unget_byte = chUnget;
814         
815         commerror = 0;
816         return 0;
817 }
818
819 int ReadComm(int fd, LPSTR lpvBuf, int cbRead)
820 {
821         int status, length;
822         struct DosDeviceStruct *ptr;
823
824         dprintf_comm(stddeb,
825             "ReadComm: fd %d, ptr %p, length %d\n", fd, lpvBuf, cbRead);
826         if ((ptr = GetDeviceStruct(fd)) == NULL) {
827                 commerror = IE_BADID;
828                 return -1;
829         }
830
831         if (ptr->suspended) {
832                 commerror = IE_HARDWARE;
833                 return -1;
834         }       
835
836         if (ptr->unget) {
837                 *lpvBuf = ptr->unget_byte;
838                 lpvBuf++;
839                 ptr->unget = 0;
840
841                 length = 1;
842         } else
843                 length = 0;
844
845         status = read(fd, (void *) lpvBuf, cbRead);
846
847         if (status == -1) {
848                 if (errno != EAGAIN) {
849                        commerror = WinError();
850                        return -1 - length;
851                 } else {
852                         commerror = 0;
853                         return length;
854                 }
855         } else {
856                 commerror = 0;
857                 return length + status;
858         }
859 }
860
861 int WriteComm(int fd, LPSTR lpvBuf, int cbWrite)
862 {
863         int x, length;
864         struct DosDeviceStruct *ptr;
865
866         dprintf_comm(stddeb,"WriteComm: fd %d, ptr %p, length %d\n", 
867                 fd, lpvBuf, cbWrite);
868         if ((ptr = GetDeviceStruct(fd)) == NULL) {
869                 commerror = IE_BADID;
870                 return -1;
871         }
872
873         if (ptr->suspended) {
874                 commerror = IE_HARDWARE;
875                 return -1;
876         }       
877         
878         for (x=0; x != cbWrite ; x++)
879         dprintf_comm(stddeb,"%c", *(lpvBuf + x) );
880
881         length = write(fd, (void *) lpvBuf, cbWrite);
882         
883         if (length == -1) {
884                 commerror = WinError();
885                 return -1;      
886         } else {
887                 commerror = 0;  
888                 return length;
889         }
890 }