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