Release 940201
[wine/multimedia.git] / misc / comm.c
blobd9f53444973065182be82f81525facead93c5bc3
1 /*
2 * DEC 93 Erik Bos (erik@trashcan.hacktic.nl)
3 */
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <termios.h>
8 #include <fcntl.h>
9 #include <string.h>
10 #include <sys/stat.h>
11 #if defined(__NetBSD__) || defined(__FreeBSD__)
12 #include <errno.h>
13 #include <sys/ioctl.h>
14 #endif
15 #include "wine.h"
16 #include "windows.h"
18 #define DEBUG_COMM
20 #define MAX_PORTS 16
22 int commerror = 0, eventmask = 0;
24 struct DosDeviceStruct {
25 char *devicename; /* /dev/cua1 */
26 int fd;
27 int suspended;
28 int unget;
29 int unget_byte;
32 struct DosDeviceStruct COM[MAX_PORTS];
33 struct DosDeviceStruct LPT[MAX_PORTS];
35 void Comm_DeInit(void);
37 void Comm_Init(void)
39 int x, serial = 0, parallel = 0;
40 char option[10], temp[256], *ptr;
41 struct stat st;
43 for (x=0; x!=MAX_PORTS; x++) {
44 strcpy(option,"COMx");
45 option[3] = '0' + x;
46 option[4] = '\0';
48 GetPrivateProfileString("serialports", option, "*", temp, sizeof(temp), WINE_INI);
49 if (!strcmp(temp, "*") || *temp == '\0')
50 COM[serial].devicename = NULL;
51 else {
52 stat(temp, &st);
53 if (!S_ISCHR(st.st_mode))
54 fprintf(stderr,"comm: can 't use `%s' as COM%d !\n", temp, x);
55 else
56 if ((ptr = malloc(strlen(temp)+1)) == NULL)
57 fprintf(stderr,"comm: can't malloc for device info!\n");
58 else {
59 COM[serial].fd = 0;
60 COM[serial].devicename = ptr;
61 strcpy(COM[serial++].devicename, temp);
65 strcpy(option, "LPTx");
66 option[3] = '0' + x;
67 option[4] = '\0';
69 GetPrivateProfileString("parallelports", option, "*", temp, sizeof(temp), WINE_INI);
70 if (!strcmp(temp, "*") || *temp == '\0')
71 LPT[parallel].devicename = NULL;
72 else {
73 stat(temp, &st);
74 if (!S_ISCHR(st.st_mode))
75 fprintf(stderr,"comm: can 't use `%s' as LPT%d !\n", temp, x);
76 else
77 if ((ptr = malloc(strlen(temp)+1)) == NULL)
78 fprintf(stderr,"comm: can't malloc for device info!\n");
79 else {
80 LPT[serial].fd = 0;
81 LPT[serial].devicename = ptr;
82 strcpy(LPT[serial++].devicename, temp);
87 atexit(Comm_DeInit);
90 void Comm_DeInit(void)
92 int x;
94 for (x=0; x!=MAX_PORTS; x++) {
96 if (COM[x].devicename) {
97 if (COM[x].fd)
98 close(COM[x].fd);
99 free(COM[x].devicename);
101 if (LPT[x].devicename) {
102 if (LPT[x].fd)
103 close(LPT[x].fd);
104 free(LPT[x].devicename);
109 struct DosDeviceStruct *GetDeviceStruct(int fd)
111 int x;
113 for (x=0; x!=MAX_PORTS; x++) {
114 if (COM[x].fd == fd)
115 return &COM[x];
116 if (LPT[x].fd == fd)
117 return &LPT[x];
120 return NULL;
123 int ValidCOMPort(int x)
125 return(x < MAX_PORTS ? (int) COM[x].devicename : 0);
128 int ValidLPTPort(int x)
130 return(x < MAX_PORTS ? (int) LPT[x].devicename : 0);
133 int WinError(void)
135 perror("comm");
136 switch (errno) {
137 default:
138 return CE_IOE;
142 int BuildCommDCB(LPSTR device, DCB FAR *lpdcb)
144 /* "COM1:9600,n,8,1" */
145 /* 012345 */
147 int port;
148 char *ptr, *ptr2, temp[256],temp2[10];
150 #ifdef DEBUG_COMM
151 fprintf(stderr,"BuildCommDCB: (%s), ptr %d\n", device, lpdcb);
152 #endif
153 commerror = 0;
155 if (!strncmp(device,"COM",3)) {
156 port = device[3] - '0';
158 if (!ValidCOMPort(port)) {
159 commerror = IE_BADID;
160 return -1;
163 if (!COM[port].fd) {
164 commerror = IE_NOPEN;
165 return -1;
167 lpdcb->Id = COM[port].fd;
169 if (!*(device+4))
170 return 0;
172 if (*(device+4) != ':')
173 return -1;
175 strcpy(temp,device+5);
176 ptr = strtok(temp, ",");
178 fprintf(stderr,"BuildCommDCB: baudrate (%s)\n", ptr);
179 lpdcb->BaudRate = atoi(ptr);
181 ptr = strtok(NULL, ",");
182 if (islower(*ptr))
183 *ptr = toupper(*ptr);
185 fprintf(stderr,"BuildCommDCB: parity (%c)\n", *ptr);
186 switch (*ptr) {
187 case 'N':
188 lpdcb->Parity = NOPARITY;
189 lpdcb->fParity = 0;
190 break;
192 lpdcb->fParity = 1;
194 case 'E':
195 lpdcb->Parity = EVENPARITY;
196 break;
197 case 'M':
198 lpdcb->Parity = MARKPARITY;
199 break;
200 case 'O':
201 lpdcb->Parity = ODDPARITY;
202 break;
203 default:
204 fprintf(stderr,"comm: unknown parity `%c'!\n", *ptr);
205 return -1;
208 ptr = strtok(NULL, ",");
209 fprintf(stderr, "BuildCommDCB: charsize (%c)\n", *ptr);
210 lpdcb->ByteSize = *ptr - '0';
212 ptr = strtok(NULL, ",");
213 fprintf(stderr, "BuildCommDCB: stopbits (%c)\n", *ptr);
214 switch (*ptr) {
215 case '1':
216 lpdcb->StopBits = ONESTOPBIT;
217 break;
218 case '2':
219 lpdcb->StopBits = TWOSTOPBITS;
220 break;
221 default:
222 fprintf(stderr,"comm: unknown # of stopbits `%c'!\n", *ptr);
223 return -1;
227 return 0;
230 int OpenComm(LPSTR device, UINT cbInQueue, UINT cbOutQueue)
232 int port, fd;
234 #ifdef DEBUG_COMM
235 fprintf(stderr,"OpenComm: %s, %d, %d\n", device, cbInQueue, cbOutQueue);
236 #endif
238 commerror = 0;
240 if (!strncmp(device,"COM",3)) {
241 port = device[3] - '0';
243 if (!ValidCOMPort(port)) {
244 commerror = IE_BADID;
245 return -1;
247 if (COM[port].fd) {
248 commerror = IE_OPEN;
249 return -1;
252 fd = open(COM[port].devicename, O_RDWR | O_NONBLOCK, 0);
253 if (fd == -1) {
254 commerror = WinError();
255 return -1;
256 } else {
257 COM[port].fd = fd;
258 return fd;
261 else
262 if (!strncmp(device,"LPT",3)) {
263 port = device[3] - '0';
265 if (!ValidLPTPort(port)) {
266 commerror = IE_BADID;
267 return -1;
269 if (LPT[port].fd) {
270 commerror = IE_OPEN;
271 return -1;
274 fd = open(LPT[port].devicename, O_RDWR | O_NONBLOCK, 0);
275 if (fd == -1) {
276 commerror = WinError();
277 return -1;
278 } else {
279 LPT[port].fd = fd;
280 return fd;
283 return 0;
286 int CloseComm(int fd)
288 int status;
290 #ifdef DEBUG_COMM
291 fprintf(stderr,"CloseComm: fd %d\n", fd);
292 #endif
294 if (close(fd) == -1) {
295 commerror = WinError();
296 return -1;
297 } else {
298 commerror = 0;
299 return 0;
303 int SetCommBreak(int fd)
305 struct DosDeviceStruct *ptr;
307 #ifdef DEBUG_COMM
308 fprintf(stderr,"SetCommBreak: fd: %d\n", fd);
309 #endif
311 if ((ptr = GetDeviceStruct(fd)) == NULL) {
312 commerror = IE_BADID;
313 return -1;
316 ptr->suspended = 1;
317 commerror = 0;
318 return 0;
321 int ClearCommBreak(int fd)
323 struct DosDeviceStruct *ptr;
325 #ifdef DEBUG_COMM
326 fprintf(stderr,"ClearCommBreak: fd: %d\n", fd);
327 #endif
329 if ((ptr = GetDeviceStruct(fd)) == NULL) {
330 commerror = IE_BADID;
331 return -1;
334 ptr->suspended = 0;
335 commerror = 0;
336 return 0;
339 LONG EscapeCommFunction(int fd, int nFunction)
341 int max;
342 struct termios port;
344 #ifdef DEBUG_COMM
345 fprintf(stderr,"EscapeCommFunction fd: %d, function: %d\n", fd, nFunction);
346 #endif
348 if (tcgetattr(fd, &port) == -1) {
349 commerror = WinError();
350 return -1;
353 switch (nFunction) {
354 case RESETDEV:
355 break;
357 case GETMAXCOM:
358 for (max = 0;COM[max].devicename;max++)
360 return max;
361 break;
363 case GETMAXLPT:
364 for (max = 0;LPT[max].devicename;max++)
366 return 0x80 + max;
367 break;
369 case CLRDTR:
370 port.c_cflag &= TIOCM_DTR;
371 break;
373 case CLRRTS:
374 port.c_cflag &= TIOCM_RTS;
375 break;
377 case SETDTR:
378 port.c_cflag |= CRTSCTS;
379 break;
381 case SETRTS:
382 port.c_cflag |= CRTSCTS;
383 break;
385 case SETXOFF:
386 port.c_iflag |= IXOFF;
387 break;
389 case SETXON:
390 port.c_iflag |= IXON;
391 break;
393 default:
394 fprintf(stderr,"EscapeCommFunction fd: %d, unknown function: %d\n", fd, nFunction);
395 break;
398 if (tcsetattr(fd, TCSADRAIN, &port) == -1) {
399 commerror = WinError();
400 return -1;
401 } else {
402 commerror = 0;
403 return 0;
407 int FlushComm(int fd, int fnQueue)
409 int queue;
411 #ifdef DEBUG_COMM
412 fprintf(stderr,"FlushComm fd: %d, queue: %d\n", fd, fnQueue);
413 #endif
415 switch (fnQueue) {
416 case 0:
417 queue = TCOFLUSH;
418 break;
419 case 1:
420 queue = TCIFLUSH;
421 break;
422 default:
423 fprintf(stderr,"FlushComm fd: %d, UNKNOWN queue: %d\n", fd, fnQueue);
424 return -1;
427 if (tcflush(fd, fnQueue)) {
428 commerror = WinError();
429 return -1;
430 } else {
431 commerror = 0;
432 return 0;
436 int GetCommError(int fd, COMSTAT FAR *lpStat)
438 #ifdef DEBUG_COMM
439 fprintf(stderr,"GetCommError: fd %d (current error %d)\n", fd, commerror);
440 #endif
442 return(commerror);
445 UINT FAR* SetCommEventMask(int fd, UINT fuEvtMask)
447 #ifdef DEBUG_COMM
448 fprintf(stderr,"SetCommEventMask: fd %d, mask %d\n", fd, fuEvtMask);
449 #endif
451 eventmask |= fuEvtMask;
452 return (UINT *)&eventmask;
455 UINT GetCommEventMask(int fd, int fnEvtClear)
457 #ifdef DEBUG_COMM
458 fprintf(stderr,"GetCommEventMask: fd %d, mask %d\n", fd, fnEvtClear);
459 #endif
460 eventmask &= ~fnEvtClear;
461 return eventmask;
464 int SetCommState(DCB FAR *lpdcb)
466 struct termios port;
468 #ifdef DEBUG_COMM
469 fprintf(stderr,"SetCommState: fd %d, ptr %d\n", lpdcb->Id, lpdcb);
470 #endif
472 if (tcgetattr(lpdcb->Id, &port) == -1) {
473 commerror = WinError();
474 return -1;
476 cfmakeraw(&port);
477 port.c_cc[VMIN] = 0;
478 port.c_cc[VTIME] = 0;
480 fprintf(stderr,"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;
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;
566 port.c_ispeed = port.c_ospeed;
567 #endif
568 fprintf(stderr,"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;
588 fprintf(stderr,"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;
609 fprintf(stderr,"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;
622 if (lpdcb->fDtrflow || lpdcb->fRtsflow || lpdcb->fOutxCtsFlow)
623 port.c_cflag |= CRTSCTS;
625 if (lpdcb->fDtrDisable)
626 port.c_cflag &= ~CRTSCTS;
628 if (lpdcb->fInX)
629 port.c_iflag |= IXON;
630 if (lpdcb->fOutX)
631 port.c_iflag |= IXOFF;
633 if (tcsetattr(lpdcb->Id, TCSADRAIN, &port) == -1) {
634 commerror = WinError();
635 return -1;
636 } else {
637 commerror = 0;
638 return 0;
642 int GetCommState(int fd, DCB FAR *lpdcb)
644 struct termios port;
646 #ifdef DEBUG_COMM
647 fprintf(stderr,"GetCommState: fd %d, ptr %d\n", fd, lpdcb);
648 #endif
650 if (tcgetattr(fd, &port) == -1) {
651 commerror = WinError();
652 return -1;
655 lpdcb->Id = fd;
657 #ifdef CBAUD
658 switch (port.c_cflag & CBAUD) {
659 #else
660 switch (port.c_ospeed) {
661 #endif
662 case B110:
663 lpdcb->BaudRate = 110;
664 break;
665 case B300:
666 lpdcb->BaudRate = 300;
667 break;
668 case B600:
669 lpdcb->BaudRate = 600;
670 break;
671 case B1200:
672 lpdcb->BaudRate = 1200;
673 break;
674 case B2400:
675 lpdcb->BaudRate = 2400;
676 break;
677 case B4800:
678 lpdcb->BaudRate = 4800;
679 break;
680 case B9600:
681 lpdcb->BaudRate = 9600;
682 break;
683 case B19200:
684 lpdcb->BaudRate = 19200;
685 break;
686 case B38400:
687 lpdcb->BaudRate = 38400;
688 break;
691 switch (port.c_cflag & CSIZE) {
692 case CS5:
693 lpdcb->ByteSize = 5;
694 break;
695 case CS6:
696 lpdcb->ByteSize = 6;
697 break;
698 case CS7:
699 lpdcb->ByteSize = 7;
700 break;
701 case CS8:
702 lpdcb->ByteSize = 8;
703 break;
706 switch (port.c_cflag & ~(PARENB | PARODD)) {
707 case 0:
708 lpdcb->fParity = NOPARITY;
709 break;
710 case PARENB:
711 lpdcb->fParity = EVENPARITY;
712 break;
713 case (PARENB | PARODD):
714 lpdcb->fParity = ODDPARITY;
715 break;
718 if (port.c_cflag & CSTOPB)
719 lpdcb->StopBits = TWOSTOPBITS;
720 else
721 lpdcb->StopBits = ONESTOPBIT;
723 lpdcb->RlsTimeout = 50;
724 lpdcb->CtsTimeout = 50;
725 lpdcb->DsrTimeout = 50;
726 lpdcb->fNull = 0;
727 lpdcb->fChEvt = 0;
728 lpdcb->fBinary = 1;
730 lpdcb->fDtrDisable = 0;
731 if (port.c_cflag & CRTSCTS) {
732 lpdcb->fDtrflow = 1;
733 lpdcb->fRtsflow = 1;
734 lpdcb->fOutxCtsFlow = 1;
735 lpdcb->fOutxDsrFlow = 1;
736 } else
737 lpdcb->fDtrDisable = 1;
739 if (port.c_iflag & IXON)
740 lpdcb->fInX = 1;
741 else
742 lpdcb->fInX = 0;
744 if (port.c_iflag & IXOFF)
745 lpdcb->fOutX = 1;
746 else
747 lpdcb->fOutX = 0;
749 lpdcb->XonChar =
750 lpdcb->XoffChar =
752 lpdcb->XonLim = 10;
753 lpdcb->XoffLim = 10;
755 commerror = 0;
756 return 0;
759 int TransmitCommChar(int fd, char chTransmit)
761 struct DosDeviceStruct *ptr;
763 #ifdef DEBUG_COMM
764 fprintf(stderr,"TransmitCommChar: fd %d, data %d \n", fd, chTransmit);
765 #endif
767 if ((ptr = GetDeviceStruct(fd)) == NULL) {
768 commerror = IE_BADID;
769 return -1;
772 if (ptr->suspended) {
773 commerror = IE_HARDWARE;
774 return -1;
777 if (write(fd, (void *) &chTransmit, 1) == -1) {
778 commerror = WinError();
779 return -1;
780 } else {
781 commerror = 0;
782 return 0;
786 int UngetCommChar(int fd, char chUnget)
788 struct DosDeviceStruct *ptr;
790 #ifdef DEBUG_COMM
791 fprintf(stderr,"UngetCommChar: fd %d (char %d)\n", fd, chUnget);
792 #endif
794 if ((ptr = GetDeviceStruct(fd)) == NULL) {
795 commerror = IE_BADID;
796 return -1;
799 if (ptr->suspended) {
800 commerror = IE_HARDWARE;
801 return -1;
804 ptr->unget = 1;
805 ptr->unget_byte = chUnget;
807 commerror = 0;
808 return 0;
811 int ReadComm(int fd, LPSTR lpvBuf, int cbRead)
813 int status, length;
814 struct DosDeviceStruct *ptr;
816 #ifdef DEBUG_COMM
817 fprintf(stderr,"ReadComm: fd %d, ptr %d, length %d\n", fd, lpvBuf, cbRead);
818 #endif
820 if ((ptr = GetDeviceStruct(fd)) == NULL) {
821 commerror = IE_BADID;
822 return -1;
825 if (ptr->suspended) {
826 commerror = IE_HARDWARE;
827 return -1;
830 if (ptr->unget) {
831 *lpvBuf = ptr->unget_byte;
832 lpvBuf++;
833 ptr->unget = 0;
835 length = 1;
836 } else
837 length = 0;
839 status = read(fd, (void *) lpvBuf, cbRead);
841 if (status == -1) {
842 commerror = WinError();
843 return -1 - length;
844 } else {
845 commerror = 0;
846 return length + status;
850 int WriteComm(int fd, LPSTR lpvBuf, int cbWrite)
852 int x, length;
853 struct DosDeviceStruct *ptr;
855 #ifdef DEBUG_COMM
856 fprintf(stderr,"WriteComm: fd %d, ptr %d, length %d\n", fd, lpvBuf, cbWrite);
857 #endif
859 if ((ptr = GetDeviceStruct(fd)) == NULL) {
860 commerror = IE_BADID;
861 return -1;
864 if (ptr->suspended) {
865 commerror = IE_HARDWARE;
866 return -1;
869 #ifdef DEBUG_COMM
870 for (x=0; x != cbWrite ; x++)
871 fprintf(stderr,"%c", *(lpvBuf + x) );
872 #endif
874 length = write(fd, (void *) lpvBuf, cbWrite);
876 if (length == -1) {
877 commerror = WinError();
878 return -1;
879 } else {
880 commerror = 0;
881 return length;