Release 0.6
[wine/multimedia.git] / misc / comm.c
blobc0db9d590ff5fa15f6424f6d35b81d84e12ee5f4
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 #ifdef __NetBSD__
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;
30 struct DosDeviceStruct COM[MAX_PORTS];
31 struct DosDeviceStruct LPT[MAX_PORTS];
33 void Comm_DeInit(void);
35 void Comm_Init(void)
37 int x, serial = 0, parallel = 0;
38 char option[10], temp[256], *ptr;
39 struct stat st;
41 for (x=0; x!=MAX_PORTS; x++) {
42 strcpy(option,"COMx");
43 option[3] = '0' + x;
44 option[4] = '\0';
46 GetPrivateProfileString("serialports", option, "*", temp, sizeof(temp), WINE_INI);
47 if (!strcmp(temp, "*") || *temp == '\0')
48 COM[serial].devicename = NULL;
49 else {
50 stat(temp, &st);
51 if (!S_ISCHR(st.st_mode))
52 fprintf(stderr,"comm: can 't use `%s' as COM%d !\n", temp, x);
53 else
54 if ((ptr = malloc(strlen(temp)+1)) == NULL)
55 fprintf(stderr,"comm: can't malloc for device info!\n");
56 else {
57 COM[serial].fd = 0;
58 COM[serial].devicename = ptr;
59 strcpy(COM[serial++].devicename, temp);
63 strcpy(option, "LPTx");
64 option[3] = '0' + x;
65 option[4] = '\0';
67 GetPrivateProfileString("parallelports", option, "*", temp, sizeof(temp), WINE_INI);
68 if (!strcmp(temp, "*") || *temp == '\0')
69 LPT[parallel].devicename = NULL;
70 else {
71 stat(temp, &st);
72 if (!S_ISCHR(st.st_mode))
73 fprintf(stderr,"comm: can 't use `%s' as LPT%d !\n", temp, x);
74 else
75 if ((ptr = malloc(strlen(temp)+1)) == NULL)
76 fprintf(stderr,"comm: can't malloc for device info!\n");
77 else {
78 LPT[serial].fd = 0;
79 LPT[serial].devicename = ptr;
80 strcpy(LPT[serial++].devicename, temp);
85 atexit(Comm_DeInit);
87 #ifdef DEBUG_COMM
88 for (x=0; x!=MAX_PORTS; x++) {
89 if (COM[x].devicename)
90 fprintf(stderr, "comm: COM%d = %s\n", x, COM[x].devicename);
91 if (LPT[x].devicename)
92 fprintf(stderr, "comm: LPT%d = %s\n", x, LPT[x].devicename);
94 #endif
97 void Comm_DeInit(void)
99 int x;
101 for (x=0; x!=MAX_PORTS; x++) {
103 if (COM[x].devicename) {
104 if (COM[x].fd)
105 close(COM[x].fd);
106 fprintf(stderr, "comm: COM%d = %s\n",x,COM[x].devicename);
107 free(COM[x].devicename);
109 if (LPT[x].devicename) {
110 if (LPT[x].fd)
111 close(LPT[x].fd);
112 fprintf(stderr, "comm: LPT%d = %s\n",x,LPT[x].devicename);
113 free(LPT[x].devicename);
118 struct DosDeviceStruct *GetDeviceStruct(int fd)
120 int x;
122 for (x=0; x!=MAX_PORTS; x++) {
123 if (COM[x].fd == fd)
124 return &COM[x];
125 if (LPT[x].fd == fd)
126 return &LPT[x];
129 return NULL;
132 int ValidCOMPort(int x)
134 return(x < MAX_PORTS ? (int) COM[x].devicename : 0);
137 int ValidLPTPort(int x)
139 return(x < MAX_PORTS ? (int) LPT[x].devicename : 0);
142 int WinError(void)
144 perror("comm");
145 switch (errno) {
146 default:
147 return CE_IOE;
151 int BuildCommDCB(LPSTR device, DCB FAR *lpdcb)
153 /* "COM1:9600,n,8,1" */
154 /* 012345 */
156 int port;
157 char *ptr, *ptr2, temp[256],temp2[10];
159 #ifdef DEBUG_COMM
160 fprintf(stderr,"BuildCommDCB: (%s), ptr %d\n", device, lpdcb);
161 #endif
162 commerror = 0;
164 if (!strncmp(device,"COM",3)) {
165 port = device[3] - '0';
167 if (!ValidCOMPort(port)) {
168 commerror = IE_BADID;
169 return -1;
172 if (!COM[port].fd) {
173 commerror = IE_NOPEN;
174 return -1;
176 lpdcb->Id = COM[port].fd;
178 if (!*(device+4))
179 return 0;
181 if (*(device+4) != ':')
182 return -1;
184 strcpy(temp,device+5);
185 ptr = strtok(temp, ",");
187 fprintf(stderr,"BuildCommDCB: baudrate (%s)\n", ptr);
188 lpdcb->BaudRate = atoi(ptr);
190 ptr = strtok(NULL, ",");
191 if (islower(*ptr))
192 *ptr = toupper(*ptr);
194 fprintf(stderr,"BuildCommDCB: parity (%c)\n", *ptr);
195 switch (*ptr) {
196 case 'N':
197 lpdcb->Parity = NOPARITY;
198 lpdcb->fParity = 0;
199 break;
201 lpdcb->fParity = 1;
203 case 'E':
204 lpdcb->Parity = EVENPARITY;
205 break;
206 case 'M':
207 lpdcb->Parity = MARKPARITY;
208 break;
209 case 'O':
210 lpdcb->Parity = ODDPARITY;
211 break;
212 default:
213 fprintf(stderr,"comm: unknown parity `%c'!\n", *ptr);
214 return -1;
217 ptr = strtok(NULL, ",");
218 fprintf(stderr, "BuildCommDCB: charsize (%c)\n", *ptr);
219 lpdcb->ByteSize = *ptr - '0';
221 ptr = strtok(NULL, ",");
222 fprintf(stderr, "BuildCommDCB: stopbits (%c)\n", *ptr);
223 switch (*ptr) {
224 case '1':
225 lpdcb->StopBits = ONESTOPBIT;
226 break;
227 case '2':
228 lpdcb->StopBits = TWOSTOPBITS;
229 break;
230 default:
231 fprintf(stderr,"comm: unknown # of stopbits `%c'!\n", *ptr);
232 return -1;
236 return 0;
239 int OpenComm(LPSTR device, UINT cbInQueue, UINT cbOutQueue)
241 int port, fd;
243 #ifdef DEBUG_COMM
244 fprintf(stderr,"OpenComm: %s, %d, %d\n", device, cbInQueue, cbOutQueue);
245 #endif
247 commerror = 0;
249 if (!strncmp(device,"COM",3)) {
250 port = device[3] - '0';
252 if (!ValidCOMPort(port)) {
253 commerror = IE_BADID;
254 return -1;
256 if (COM[port].fd) {
257 commerror = IE_OPEN;
258 return -1;
261 fd = open(COM[port].devicename, O_RDWR | O_NONBLOCK, 0);
262 if (fd == -1) {
263 commerror = WinError();
264 return -1;
265 } else {
266 COM[port].fd = fd;
267 return fd;
270 else
271 if (!strncmp(device,"LPT",3)) {
272 port = device[3] - '0';
274 if (!ValidLPTPort(port)) {
275 commerror = IE_BADID;
276 return -1;
278 if (LPT[port].fd) {
279 commerror = IE_OPEN;
280 return -1;
283 fd = open(LPT[port].devicename, O_RDWR | O_NONBLOCK, 0);
284 if (fd == -1) {
285 commerror = WinError();
286 return -1;
287 } else {
288 LPT[port].fd = fd;
289 return fd;
292 return 0;
295 int CloseComm(int fd)
297 int status;
299 #ifdef DEBUG_COMM
300 fprintf(stderr,"CloseComm: fd %d\n", fd);
301 #endif
303 if (close(fd) == -1) {
304 commerror = WinError();
305 return -1;
306 } else {
307 commerror = 0;
308 return 0;
312 int SetCommBreak(int fd)
314 struct DosDeviceStruct *ptr;
316 #ifdef DEBUG_COMM
317 fprintf(stderr,"SetCommBreak: fd: %d\n", fd);
318 #endif
320 if ((ptr = GetDeviceStruct(fd)) == NULL) {
321 commerror = IE_BADID;
322 return -1;
325 ptr->suspended = 1;
326 commerror = 0;
327 return 0;
330 int ClearCommBreak(int fd)
332 struct DosDeviceStruct *ptr;
334 #ifdef DEBUG_COMM
335 fprintf(stderr,"ClearCommBreak: fd: %d\n", fd);
336 #endif
338 if ((ptr = GetDeviceStruct(fd)) == NULL) {
339 commerror = IE_BADID;
340 return -1;
343 ptr->suspended = 0;
344 commerror = 0;
345 return 0;
348 LONG EscapeCommFunction(int fd, int nFunction)
350 int max;
351 struct termios port;
353 #ifdef DEBUG_COMM
354 fprintf(stderr,"EscapeCommFunction fd: %d, function: %d\n", fd, nFunction);
355 #endif
357 if (tcgetattr(fd, &port) == -1) {
358 commerror = WinError();
359 return -1;
362 switch (nFunction) {
363 case RESETDEV:
364 break;
366 case GETMAXCOM:
367 for (max = 0;COM[max].devicename;max++)
369 return max;
370 break;
372 case GETMAXLPT:
373 for (max = 0;LPT[max].devicename;max++)
375 return 0x80 + max;
376 break;
378 case CLRDTR:
379 port.c_cflag &= TIOCM_DTR;
380 break;
382 case CLRRTS:
383 port.c_cflag &= TIOCM_RTS;
384 break;
386 case SETDTR:
387 port.c_cflag |= CRTSCTS;
388 break;
390 case SETRTS:
391 port.c_cflag |= CRTSCTS;
392 break;
394 case SETXOFF:
395 port.c_iflag |= IXOFF;
396 break;
398 case SETXON:
399 port.c_iflag |= IXON;
400 break;
402 default:
403 fprintf(stderr,"EscapeCommFunction fd: %d, unknown function: %d\n", fd, nFunction);
404 break;
407 if (tcsetattr(fd, TCSADRAIN, &port) == -1) {
408 commerror = WinError();
409 return -1;
410 } else {
411 commerror = 0;
412 return 0;
416 int FlushComm(int fd, int fnQueue)
418 int queue;
420 #ifdef DEBUG_COMM
421 fprintf(stderr,"FlushComm fd: %d, queue: %d\n", fd, fnQueue);
422 #endif
424 switch (fnQueue) {
425 case 0:
426 queue = TCOFLUSH;
427 break;
428 case 1:
429 queue = TCIFLUSH;
430 break;
431 default:
432 fprintf(stderr,"FlushComm fd: %d, UNKNOWN queue: %d\n", fd, fnQueue);
433 return -1;
436 if (tcflush(fd, fnQueue)) {
437 commerror = WinError();
438 return -1;
439 } else {
440 commerror = 0;
441 return 0;
445 int GetCommError(int fd, COMSTAT FAR *lpStat)
447 #ifdef DEBUG_COMM
448 fprintf(stderr,"GetCommError: fd %d (current error %d)\n", fd, commerror);
449 #endif
451 return(commerror);
454 UINT FAR* SetCommEventMask(int fd, UINT fuEvtMask)
456 #ifdef DEBUG_COMM
457 fprintf(stderr,"SetCommEventMask: fd %d, mask %d\n", fd, fuEvtMask);
458 #endif
460 eventmask |= fuEvtMask;
461 return (UINT *)&eventmask;
464 UINT GetCommEventMask(int fd, int fnEvtClear)
466 #ifdef DEBUG_COMM
467 fprintf(stderr,"GetCommEventMask: fd %d, mask %d\n", fd, fnEvtClear);
468 #endif
469 eventmask &= ~fnEvtClear;
470 return eventmask;
473 int SetCommState(DCB FAR *lpdcb)
475 struct termios port;
477 #ifdef DEBUG_COMM
478 fprintf(stderr,"SetCommState: fd %d, ptr %d\n", lpdcb->Id, lpdcb);
479 #endif
481 if (tcgetattr(lpdcb->Id, &port) == -1) {
482 commerror = WinError();
483 return -1;
485 cfmakeraw(&port);
486 port.c_cc[VMIN] = 0;
487 port.c_cc[VTIME] = 0;
489 fprintf(stderr,"SetCommState: baudrate %d\n",lpdcb->BaudRate);
490 #ifdef CBAUD
491 port.c_cflag &= ~CBAUD;
492 switch (lpdcb->BaudRate) {
493 case 110:
494 case CBR_110:
495 port.c_cflag |= B110;
496 break;
497 case 300:
498 case CBR_300:
499 port.c_cflag |= B300;
500 break;
501 case 600:
502 case CBR_600:
503 port.c_cflag |= B600;
504 break;
505 case 1200:
506 case CBR_1200:
507 port.c_cflag |= B1200;
508 break;
509 case 2400:
510 case CBR_2400:
511 port.c_cflag |= B2400;
512 break;
513 case 4800:
514 case CBR_4800:
515 port.c_cflag |= B4800;
516 break;
517 case 9600:
518 case CBR_9600:
519 port.c_cflag |= B9600;
520 break;
521 case 19200:
522 case CBR_19200:
523 port.c_cflag |= B19200;
524 break;
525 case 38400:
526 case CBR_38400:
527 port.c_cflag |= B38400;
528 break;
529 default:
530 commerror = IE_BAUDRATE;
531 return -1;
533 #else
534 switch (lpdcb->BaudRate) {
535 case 110:
536 case CBR_110:
537 port.c_ospeed = B110;
538 break;
539 case 300:
540 case CBR_300:
541 port.c_ospeed = B300;
542 break;
543 case 600:
544 case CBR_600:
545 port.c_ospeed = B600;
546 break;
547 case 1200:
548 case CBR_1200:
549 port.c_ospeed = B1200;
550 break;
551 case 2400:
552 case CBR_2400:
553 port.c_ospeed = B2400;
554 break;
555 case 4800:
556 case CBR_4800:
557 port.c_ospeed = B4800;
558 break;
559 case 9600:
560 case CBR_9600:
561 port.c_ospeed = B9600;
562 break;
563 case 19200:
564 case CBR_19200:
565 port.c_ospeed = B19200;
566 break;
567 case 38400:
568 case CBR_38400:
569 port.c_ospeed = B38400;
570 break;
571 default:
572 commerror = IE_BAUDRATE;
573 return -1;
575 port.c_ispeed = port.c_ospeed;
576 #endif
577 fprintf(stderr,"SetCommState: bytesize %d\n",lpdcb->ByteSize);
578 port.c_cflag &= ~CSIZE;
579 switch (lpdcb->ByteSize) {
580 case 5:
581 port.c_cflag |= CS5;
582 break;
583 case 6:
584 port.c_cflag |= CS6;
585 break;
586 case 7:
587 port.c_cflag |= CS7;
588 break;
589 case 8:
590 port.c_cflag |= CS8;
591 break;
592 default:
593 commerror = IE_BYTESIZE;
594 return -1;
597 fprintf(stderr,"SetCommState: parity %d\n",lpdcb->Parity);
598 port.c_cflag &= ~(PARENB | PARODD);
599 if (lpdcb->fParity)
600 switch (lpdcb->Parity) {
601 case NOPARITY:
602 port.c_iflag &= ~INPCK;
603 break;
604 case ODDPARITY:
605 port.c_cflag |= (PARENB | PARODD);
606 port.c_iflag |= INPCK;
607 break;
608 case EVENPARITY:
609 port.c_cflag |= PARENB;
610 port.c_iflag |= INPCK;
611 break;
612 default:
613 commerror = IE_BYTESIZE;
614 return -1;
618 fprintf(stderr,"SetCommState: stopbits %d\n",lpdcb->StopBits);
619 switch (lpdcb->StopBits) {
620 case ONESTOPBIT:
621 port.c_cflag &= ~CSTOPB;
622 break;
623 case TWOSTOPBITS:
624 port.c_cflag |= CSTOPB;
625 break;
626 default:
627 commerror = IE_BYTESIZE;
628 return -1;
631 if (lpdcb->fDtrflow || lpdcb->fRtsflow || lpdcb->fOutxCtsFlow)
632 port.c_cflag |= CRTSCTS;
634 if (lpdcb->fDtrDisable)
635 port.c_cflag &= ~CRTSCTS;
637 if (lpdcb->fInX)
638 port.c_iflag |= IXON;
639 if (lpdcb->fOutX)
640 port.c_iflag |= IXOFF;
642 if (tcsetattr(lpdcb->Id, TCSADRAIN, &port) == -1) {
643 commerror = WinError();
644 return -1;
645 } else {
646 commerror = 0;
647 return 0;
651 int GetCommState(int fd, DCB FAR *lpdcb)
653 struct termios port;
655 #ifdef DEBUG_COMM
656 fprintf(stderr,"GetCommState: fd %d, ptr %d\n", fd, lpdcb);
657 #endif
659 if (tcgetattr(fd, &port) == -1) {
660 commerror = WinError();
661 return -1;
664 lpdcb->Id = fd;
666 #ifdef CBAUD
667 switch (port.c_cflag & CBAUD) {
668 #else
669 switch (port.c_ospeed) {
670 #endif
671 case B110:
672 lpdcb->BaudRate = 110;
673 break;
674 case B300:
675 lpdcb->BaudRate = 300;
676 break;
677 case B600:
678 lpdcb->BaudRate = 600;
679 break;
680 case B1200:
681 lpdcb->BaudRate = 1200;
682 break;
683 case B2400:
684 lpdcb->BaudRate = 2400;
685 break;
686 case B4800:
687 lpdcb->BaudRate = 4800;
688 break;
689 case B9600:
690 lpdcb->BaudRate = 9600;
691 break;
692 case B19200:
693 lpdcb->BaudRate = 19200;
694 break;
695 case B38400:
696 lpdcb->BaudRate = 38400;
697 break;
700 switch (port.c_cflag & CSIZE) {
701 case CS5:
702 lpdcb->ByteSize = 5;
703 break;
704 case CS6:
705 lpdcb->ByteSize = 6;
706 break;
707 case CS7:
708 lpdcb->ByteSize = 7;
709 break;
710 case CS8:
711 lpdcb->ByteSize = 8;
712 break;
715 switch (port.c_cflag & ~(PARENB | PARODD)) {
716 case 0:
717 lpdcb->fParity = NOPARITY;
718 break;
719 case PARENB:
720 lpdcb->fParity = EVENPARITY;
721 break;
722 case (PARENB | PARODD):
723 lpdcb->fParity = ODDPARITY;
724 break;
727 if (port.c_cflag & CSTOPB)
728 lpdcb->StopBits = TWOSTOPBITS;
729 else
730 lpdcb->StopBits = ONESTOPBIT;
732 lpdcb->RlsTimeout = 50;
733 lpdcb->CtsTimeout = 50;
734 lpdcb->DsrTimeout = 50;
735 lpdcb->fNull = 0;
736 lpdcb->fChEvt = 0;
737 lpdcb->fBinary = 1;
739 lpdcb->fDtrDisable = 0;
740 if (port.c_cflag & CRTSCTS) {
741 lpdcb->fDtrflow = 1;
742 lpdcb->fRtsflow = 1;
743 lpdcb->fOutxCtsFlow = 1;
744 lpdcb->fOutxDsrFlow = 1;
745 } else
746 lpdcb->fDtrDisable = 1;
748 if (port.c_iflag & IXON)
749 lpdcb->fInX = 1;
750 else
751 lpdcb->fInX = 0;
753 if (port.c_iflag & IXOFF)
754 lpdcb->fOutX = 1;
755 else
756 lpdcb->fOutX = 0;
758 lpdcb->XonChar =
759 lpdcb->XoffChar =
761 lpdcb->XonLim = 10;
762 lpdcb->XoffLim = 10;
764 commerror = 0;
765 return 0;
768 int TransmitCommChar(int fd, char chTransmit)
770 struct DosDeviceStruct *ptr;
772 #ifdef DEBUG_COMM
773 fprintf(stderr,"TransmitCommChar: fd %d, data %d \n", fd, chTransmit);
774 #endif
776 if ((ptr = GetDeviceStruct(fd)) == NULL) {
777 commerror = IE_BADID;
778 return -1;
781 if (ptr->suspended) {
782 commerror = IE_HARDWARE;
783 return -1;
786 if (write(fd, (void *) &chTransmit, 1) == -1) {
787 commerror = WinError();
788 return -1;
789 } else {
790 commerror = 0;
791 return 0;
795 int UngetCommChar(int fd, char chUnget)
797 struct DosDeviceStruct *ptr;
799 #ifdef DEBUG_COMM
800 fprintf(stderr,"UngetCommChar: fd %d (char %d)\n", fd, chUnget);
801 #endif
802 fprintf(stderr,"NOT implemented!\n");
804 if ((ptr = GetDeviceStruct(fd)) == NULL) {
805 commerror = IE_BADID;
806 return -1;
809 if (ptr->suspended) {
810 commerror = IE_HARDWARE;
811 return -1;
814 commerror = 0;
815 return 0;
818 int ReadComm(int fd, LPSTR lpvBuf, int cbRead)
820 struct DosDeviceStruct *ptr;
821 #ifdef DEBUG_COMM
822 fprintf(stderr,"ReadComm: fd %d, ptr %d, length %d\n", fd, lpvBuf, cbRead);
823 #endif
824 if ((ptr = GetDeviceStruct(fd)) == NULL) {
825 commerror = IE_BADID;
826 return -1;
829 if (ptr->suspended) {
830 commerror = IE_HARDWARE;
831 return -1;
834 if (read(fd, (void *) lpvBuf, cbRead) == -1) {
835 commerror = WinError();
836 return -1;
837 } else {
838 commerror = 0;
839 return 0;
843 int WriteComm(int fd, LPSTR lpvBuf, int cbWrite)
845 int x;
846 struct DosDeviceStruct *ptr;
848 #ifdef DEBUG_COMM
849 fprintf(stderr,"WriteComm: fd %d, ptr %d, length %d\n", fd, lpvBuf, cbWrite);
850 #endif
852 if ((ptr = GetDeviceStruct(fd)) == NULL) {
853 commerror = IE_BADID;
854 return -1;
857 if (ptr->suspended) {
858 commerror = IE_HARDWARE;
859 return -1;
862 for (x=0; x != cbWrite ; x++)
863 fprintf(stderr,"%c", *(lpvBuf + x) );
865 if (write(fd, (void *) lpvBuf, cbWrite) == -1) {
866 commerror = WinError();
867 return -1;
868 } else {
869 commerror = 0;
870 return 0;