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