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