Made DOSVM_GetTimer survive EAGAIN errors...
[wine.git] / misc / comm.c
blob940d005545b7ab6f68360e1c54c277651c2f812b
1 /*
2 * DEC 93 Erik Bos <erik@xs4all.nl>
4 * Copyright 1996 Marcus Meissner
6 * Mar 31, 1999. Ove Kåven <ovek@arcticnet.no>
7 * - Implemented buffers and EnableCommNotification.
9 * Mar 3, 1999. Ove Kåven <ovek@arcticnet.no>
10 * - Use port indices instead of unixfds for win16
11 * - Moved things around (separated win16 and win32 routines)
12 * - Added some hints on how to implement buffers and EnableCommNotification.
14 * May 26, 1997. Fixes and comments by Rick Richardson <rick@dgii.com> [RER]
15 * - ptr->fd wasn't getting cleared on close.
16 * - GetCommEventMask() and GetCommError() didn't do much of anything.
17 * IMHO, they are still wrong, but they at least implement the RXCHAR
18 * event and return I/O queue sizes, which makes the app I'm interested
19 * in (analog devices EZKIT DSP development system) work.
21 * August 12, 1997. Take a bash at SetCommEventMask - Lawson Whitney
22 * <lawson_whitney@juno.com>
23 * July 6, 1998. Fixes and comments by Valentijn Sessink
24 * <vsessink@ic.uva.nl> [V]
25 * Oktober 98, Rein Klazes [RHK]
26 * A program that wants to monitor the modem status line (RLSD/DCD) may
27 * poll the modem status register in the commMask structure. I update the bit
28 * in GetCommError, waiting for an implementation of communication events.
32 #include "config.h"
34 #include <stdlib.h>
35 #include <termios.h>
36 #include <fcntl.h>
37 #include <string.h>
38 #ifdef HAVE_STRINGS_H
39 # include <strings.h>
40 #endif
41 #include <errno.h>
42 #include <ctype.h>
43 #include <sys/stat.h>
44 #ifdef HAVE_SYS_FILIO_H
45 # include <sys/filio.h>
46 #endif
47 #include <sys/ioctl.h>
48 #include <unistd.h>
50 #include "wine/winuser16.h"
51 #include "comm.h"
52 #ifdef HAVE_SYS_MODEM_H
53 # include <sys/modem.h>
54 #endif
55 #ifdef HAVE_SYS_STRTIO_H
56 # include <sys/strtio.h>
57 #endif
58 #include "heap.h"
59 #include "options.h"
61 #include "server/request.h"
62 #include "server.h"
63 #include "process.h"
64 #include "winerror.h"
65 #include "async.h"
67 #include "debug.h"
69 #ifndef TIOCINQ
70 #define TIOCINQ FIONREAD
71 #endif
72 #define COMM_MSR_OFFSET 35 /* see knowledge base Q101417 */
74 struct DosDeviceStruct COM[MAX_PORTS];
75 struct DosDeviceStruct LPT[MAX_PORTS];
76 /* pointers to unknown(==undocumented) comm structure */
77 LPCVOID *unknown[MAX_PORTS];
78 /* save terminal states */
79 static struct termios m_stat[MAX_PORTS];
81 void COMM_Init(void)
83 int x;
84 char option[10], temp[256], *btemp;
85 struct stat st;
87 for (x=0; x!=MAX_PORTS; x++) {
88 strcpy(option,"COMx");
89 option[3] = '1' + x;
90 option[4] = '\0';
92 PROFILE_GetWineIniString( "serialports", option, "*",
93 temp, sizeof(temp) );
94 if (!strcmp(temp, "*") || *temp == '\0')
95 COM[x].devicename = NULL;
96 else {
97 btemp = strchr(temp,',');
98 if (btemp != NULL) {
99 *btemp++ = '\0';
100 COM[x].baudrate = atoi(btemp);
101 } else {
102 COM[x].baudrate = -1;
104 stat(temp, &st);
105 if (!S_ISCHR(st.st_mode))
106 WARN(comm,"Can't use `%s' as %s !\n", temp, option);
107 else
108 if ((COM[x].devicename = malloc(strlen(temp)+1)) == NULL)
109 WARN(comm,"Can't malloc for device info!\n");
110 else {
111 COM[x].fd = 0;
112 strcpy(COM[x].devicename, temp);
114 TRACE(comm, "%s = %s\n", option, COM[x].devicename);
117 strcpy(option, "LPTx");
118 option[3] = '1' + x;
119 option[4] = '\0';
121 PROFILE_GetWineIniString( "parallelports", option, "*",
122 temp, sizeof(temp) );
123 if (!strcmp(temp, "*") || *temp == '\0')
124 LPT[x].devicename = NULL;
125 else {
126 stat(temp, &st);
127 if (!S_ISCHR(st.st_mode))
128 WARN(comm,"Can't use `%s' as %s !\n", temp, option);
129 else
130 if ((LPT[x].devicename = malloc(strlen(temp)+1)) == NULL)
131 WARN(comm,"Can't malloc for device info!\n");
132 else {
133 LPT[x].fd = 0;
134 strcpy(LPT[x].devicename, temp);
136 TRACE(comm, "%s = %s\n", option, LPT[x].devicename);
143 struct DosDeviceStruct *GetDeviceStruct_fd(int fd)
145 int x;
147 for (x=0; x!=MAX_PORTS; x++) {
148 if (COM[x].fd == fd)
149 return &COM[x];
150 if (LPT[x].fd == fd)
151 return &LPT[x];
154 return NULL;
157 struct DosDeviceStruct *GetDeviceStruct(int fd)
159 if ((fd&0x7F)<=MAX_PORTS) {
160 if (!(fd&0x80)) {
161 if (COM[fd].fd)
162 return &COM[fd];
163 } else {
164 if (LPT[fd].fd)
165 return &LPT[fd];
169 return NULL;
172 int GetCommPort_fd(int fd)
174 int x;
176 for (x=0; x<MAX_PORTS; x++) {
177 if (COM[x].fd == fd)
178 return x;
181 return -1;
184 int ValidCOMPort(int x)
186 return(x < MAX_PORTS ? (int) COM[x].devicename : 0);
189 int ValidLPTPort(int x)
191 return(x < MAX_PORTS ? (int) LPT[x].devicename : 0);
194 int WinError(void)
196 TRACE(comm, "errno = %d\n", errno);
197 switch (errno) {
198 default:
199 return CE_IOE;
203 static unsigned comm_inbuf(struct DosDeviceStruct *ptr)
205 return ((ptr->ibuf_tail > ptr->ibuf_head) ? ptr->ibuf_size : 0)
206 + ptr->ibuf_head - ptr->ibuf_tail;
209 static unsigned comm_outbuf(struct DosDeviceStruct *ptr)
211 return ((ptr->obuf_tail > ptr->obuf_head) ? ptr->obuf_size : 0)
212 + ptr->obuf_head - ptr->obuf_tail;
215 static void comm_notification(int fd,void*private)
217 struct DosDeviceStruct *ptr = (struct DosDeviceStruct *)private;
218 int prev, bleft, len;
219 WORD mask = 0;
220 int cid = GetCommPort_fd(fd);
222 /* read data from comm port */
223 prev = comm_inbuf(ptr);
224 do {
225 bleft = ((ptr->ibuf_tail > ptr->ibuf_head) ? (ptr->ibuf_tail-1) : ptr->ibuf_size)
226 - ptr->ibuf_head;
227 len = read(fd, ptr->inbuf + ptr->ibuf_head, bleft?bleft:1);
228 if (len > 0) {
229 if (!bleft) {
230 ptr->commerror = CE_RXOVER;
231 } else {
232 ptr->ibuf_head += len;
233 if (ptr->ibuf_head >= ptr->ibuf_size)
234 ptr->ibuf_head = 0;
235 /* flag event */
236 if (ptr->eventmask & EV_RXCHAR)
237 *(WORD*)(unknown[cid]) |= EV_RXCHAR;
238 /* FIXME: check for event character (EV_RXFLAG) */
241 } while (len > 0);
242 /* check for notification */
243 if (ptr->wnd && (ptr->n_read>0) && (prev<ptr->n_read) &&
244 (comm_inbuf(ptr)>=ptr->n_read)) {
245 /* passed the receive notification threshold */
246 mask |= CN_RECEIVE;
249 /* write any TransmitCommChar character */
250 if (ptr->xmit>=0) {
251 len = write(fd, &(ptr->xmit), 1);
252 if (len > 0) ptr->xmit = -1;
254 /* write from output queue */
255 prev = comm_outbuf(ptr);
256 do {
257 bleft = ((ptr->obuf_tail < ptr->obuf_head) ? ptr->obuf_head : ptr->obuf_size)
258 - ptr->obuf_tail;
259 len = bleft ? write(fd, ptr->outbuf + ptr->obuf_tail, bleft) : 0;
260 if (len > 0) {
261 ptr->obuf_tail += len;
262 if (ptr->obuf_tail >= ptr->obuf_size)
263 ptr->obuf_tail = 0;
264 /* flag event */
265 if ((ptr->obuf_tail == ptr->obuf_head) && (ptr->eventmask & EV_TXEMPTY))
266 *(WORD*)(unknown[cid]) |= EV_TXEMPTY;
268 } while (len > 0);
269 /* check for notification */
270 if (ptr->wnd && (ptr->n_write>0) && (prev>=ptr->n_write) &&
271 (comm_outbuf(ptr)<ptr->n_write)) {
272 /* passed the transmit notification threshold */
273 mask |= CN_TRANSMIT;
276 /* send notifications, if any */
277 if (ptr->wnd && mask) {
278 PostMessage16(ptr->wnd, WM_COMMNOTIFY, cid, mask);
282 /**************************************************************************
283 * BuildCommDCB (USER.213)
285 BOOL16 WINAPI BuildCommDCB16(LPCSTR device, LPDCB16 lpdcb)
287 /* "COM1:9600,n,8,1" */
288 /* 012345 */
289 int port;
290 char *ptr, temp[256];
292 TRACE(comm, "(%s), ptr %p\n", device, lpdcb);
294 if (!lstrncmpiA(device,"COM",3)) {
295 port = device[3] - '0';
298 if (port-- == 0) {
299 ERR(comm, "BUG ! COM0 can't exist!.\n");
300 return -1;
303 if (!ValidCOMPort(port)) {
304 return -1;
307 memset(lpdcb, 0, sizeof(DCB16)); /* initialize */
309 lpdcb->Id = port;
311 if (!*(device+4))
312 return 0;
314 if (*(device+4) != ':')
315 return -1;
317 strcpy(temp,device+5);
318 ptr = strtok(temp, ", ");
320 if (COM[port].baudrate > 0)
321 lpdcb->BaudRate = COM[port].baudrate;
322 else
323 lpdcb->BaudRate = atoi(ptr);
324 TRACE(comm,"baudrate (%d)\n", lpdcb->BaudRate);
326 ptr = strtok(NULL, ", ");
327 if (islower(*ptr))
328 *ptr = toupper(*ptr);
330 TRACE(comm,"parity (%c)\n", *ptr);
331 lpdcb->fParity = TRUE;
332 switch (*ptr) {
333 case 'N':
334 lpdcb->Parity = NOPARITY;
335 lpdcb->fParity = FALSE;
336 break;
337 case 'E':
338 lpdcb->Parity = EVENPARITY;
339 break;
340 case 'M':
341 lpdcb->Parity = MARKPARITY;
342 break;
343 case 'O':
344 lpdcb->Parity = ODDPARITY;
345 break;
346 default:
347 WARN(comm,"Unknown parity `%c'!\n", *ptr);
348 return -1;
351 ptr = strtok(NULL, ", ");
352 TRACE(comm, "charsize (%c)\n", *ptr);
353 lpdcb->ByteSize = *ptr - '0';
355 ptr = strtok(NULL, ", ");
356 TRACE(comm, "stopbits (%c)\n", *ptr);
357 switch (*ptr) {
358 case '1':
359 lpdcb->StopBits = ONESTOPBIT;
360 break;
361 case '2':
362 lpdcb->StopBits = TWOSTOPBITS;
363 break;
364 default:
365 WARN(comm,"Unknown # of stopbits `%c'!\n", *ptr);
366 return -1;
370 return 0;
373 /*****************************************************************************
374 * OpenComm (USER.200)
376 INT16 WINAPI OpenComm16(LPCSTR device,UINT16 cbInQueue,UINT16 cbOutQueue)
378 int port,fd;
380 TRACE(comm, "%s, %d, %d\n", device, cbInQueue, cbOutQueue);
382 if (!lstrncmpiA(device,"COM",3)) {
383 port = device[3] - '0';
385 if (port-- == 0) {
386 ERR(comm, "BUG ! COM0 doesn't exist !\n");
389 TRACE(comm, "%s = %s\n", device, COM[port].devicename);
391 if (!ValidCOMPort(port)) {
392 return IE_BADID;
394 if (COM[port].fd) {
395 return IE_OPEN;
398 fd = open(COM[port].devicename, O_RDWR | O_NONBLOCK);
399 if (fd == -1) {
400 return WinError();
401 } else {
402 unknown[port] = SEGPTR_ALLOC(40);
403 bzero(unknown[port],40);
404 COM[port].fd = fd;
405 COM[port].commerror = 0;
406 COM[port].eventmask = 0;
407 /* save terminal state */
408 tcgetattr(fd,&m_stat[port]);
409 /* set default parameters */
410 if(COM[port].baudrate>-1){
411 DCB16 dcb;
412 GetCommState16(port, &dcb);
413 dcb.BaudRate=COM[port].baudrate;
414 /* more defaults:
415 * databits, parity, stopbits
417 SetCommState16( &dcb);
419 /* init priority characters */
420 COM[port].unget = -1;
421 COM[port].xmit = -1;
422 /* allocate buffers */
423 COM[port].ibuf_size = cbInQueue;
424 COM[port].ibuf_head = COM[port].ibuf_tail= 0;
425 COM[port].obuf_size = cbOutQueue;
426 COM[port].obuf_head = COM[port].obuf_tail = 0;
428 COM[port].inbuf = malloc(cbInQueue);
429 if (COM[port].inbuf) {
430 COM[port].outbuf = malloc(cbOutQueue);
431 if (!COM[port].outbuf)
432 free(COM[port].inbuf);
433 } else COM[port].outbuf = NULL;
434 if (!COM[port].outbuf) {
435 /* not enough memory */
436 tcsetattr(COM[port].fd,TCSANOW,&m_stat[port]);
437 close(COM[port].fd);
438 return IE_MEMORY;
441 /* enable async notifications */
442 ASYNC_RegisterFD(COM[port].fd,comm_notification,&COM[port]);
443 return port;
446 else
447 if (!lstrncmpiA(device,"LPT",3)) {
448 port = device[3] - '0';
450 if (port-- == 0) {
451 ERR(comm, "BUG ! LPT0 doesn't exist !\n");
454 if (!ValidLPTPort(port)) {
455 return IE_BADID;
457 if (LPT[port].fd) {
458 return IE_OPEN;
461 fd = open(LPT[port].devicename, O_RDWR | O_NONBLOCK, 0);
462 if (fd == -1) {
463 return WinError();
464 } else {
465 LPT[port].fd = fd;
466 LPT[port].commerror = 0;
467 LPT[port].eventmask = 0;
468 return port|0x80;
471 return 0;
474 /*****************************************************************************
475 * CloseComm (USER.207)
477 INT16 WINAPI CloseComm16(INT16 cid)
479 struct DosDeviceStruct *ptr;
481 TRACE(comm,"cid=%d\n", cid);
482 if ((ptr = GetDeviceStruct(cid)) == NULL) {
483 return -1;
485 if (!(cid&0x80)) {
486 /* COM port */
487 SEGPTR_FREE(unknown[cid]); /* [LW] */
489 /* disable async notifications */
490 ASYNC_UnregisterFD(COM[cid].fd,comm_notification);
491 /* free buffers */
492 free(ptr->outbuf);
493 free(ptr->inbuf);
495 /* reset modem lines */
496 tcsetattr(ptr->fd,TCSANOW,&m_stat[cid]);
499 if (close(ptr->fd) == -1) {
500 ptr->commerror = WinError();
501 /* FIXME: should we clear ptr->fd here? */
502 return -1;
503 } else {
504 ptr->commerror = 0;
505 ptr->fd = 0;
506 return 0;
510 /*****************************************************************************
511 * SetCommBreak (USER.210)
513 INT16 WINAPI SetCommBreak16(INT16 cid)
515 struct DosDeviceStruct *ptr;
517 TRACE(comm,"cid=%d\n", cid);
518 if ((ptr = GetDeviceStruct(cid)) == NULL) {
519 return -1;
522 ptr->suspended = 1;
523 ptr->commerror = 0;
524 return 0;
527 /*****************************************************************************
528 * ClearCommBreak (USER.211)
530 INT16 WINAPI ClearCommBreak16(INT16 cid)
532 struct DosDeviceStruct *ptr;
534 TRACE(comm,"cid=%d\n", cid);
535 if ((ptr = GetDeviceStruct(cid)) == NULL) {
536 return -1;
539 ptr->suspended = 0;
540 ptr->commerror = 0;
541 return 0;
544 /*****************************************************************************
545 * EscapeCommFunction (USER.214)
547 LONG WINAPI EscapeCommFunction16(UINT16 cid,UINT16 nFunction)
549 int max;
550 struct DosDeviceStruct *ptr;
551 struct termios port;
553 TRACE(comm,"cid=%d, function=%d\n", cid, nFunction);
554 if ((ptr = GetDeviceStruct(cid)) == NULL) {
555 return -1;
557 if (tcgetattr(ptr->fd,&port) == -1) {
558 ptr->commerror=WinError();
559 return -1;
562 switch (nFunction) {
563 case RESETDEV:
564 break;
566 case GETMAXCOM:
567 for (max = MAX_PORTS;!COM[max].devicename;max--)
569 return max;
570 break;
572 case GETMAXLPT:
573 for (max = MAX_PORTS;!LPT[max].devicename;max--)
575 return 0x80 + max;
576 break;
578 #ifdef TIOCM_DTR
579 case CLRDTR:
580 port.c_cflag &= TIOCM_DTR;
581 break;
582 #endif
584 #ifdef TIOCM_RTS
585 case CLRRTS:
586 port.c_cflag &= TIOCM_RTS;
587 break;
588 #endif
590 #ifdef CRTSCTS
591 case SETDTR:
592 port.c_cflag |= CRTSCTS;
593 break;
595 case SETRTS:
596 port.c_cflag |= CRTSCTS;
597 break;
598 #endif
600 case SETXOFF:
601 port.c_iflag |= IXOFF;
602 break;
604 case SETXON:
605 port.c_iflag |= IXON;
606 break;
608 default:
609 WARN(comm,"(cid=%d,nFunction=%d): Unknown function\n",
610 cid, nFunction);
611 break;
614 if (tcsetattr(ptr->fd, TCSADRAIN, &port) == -1) {
615 ptr->commerror = WinError();
616 return -1;
617 } else {
618 ptr->commerror = 0;
619 return 0;
623 /*****************************************************************************
624 * FlushComm (USER.215)
626 INT16 WINAPI FlushComm16(INT16 cid,INT16 fnQueue)
628 int queue;
629 struct DosDeviceStruct *ptr;
631 TRACE(comm,"cid=%d, queue=%d\n", cid, fnQueue);
632 if ((ptr = GetDeviceStruct(cid)) == NULL) {
633 return -1;
635 switch (fnQueue) {
636 case 0:
637 queue = TCOFLUSH;
638 ptr->obuf_tail = ptr->obuf_head;
639 break;
640 case 1:
641 queue = TCIFLUSH;
642 ptr->ibuf_head = ptr->ibuf_tail;
643 break;
644 default:
645 WARN(comm,"(cid=%d,fnQueue=%d):Unknown queue\n",
646 cid, fnQueue);
647 return -1;
649 if (tcflush(ptr->fd, queue)) {
650 ptr->commerror = WinError();
651 return -1;
652 } else {
653 ptr->commerror = 0;
654 return 0;
658 /********************************************************************
659 * GetCommError (USER.203)
661 INT16 WINAPI GetCommError16(INT16 cid,LPCOMSTAT16 lpStat)
663 int temperror;
664 struct DosDeviceStruct *ptr;
665 unsigned char *stol;
666 unsigned int mstat;
668 if ((ptr = GetDeviceStruct(cid)) == NULL) {
669 return -1;
671 if (cid&0x80) {
672 WARN(comm," cid %d not comm port\n",cid);
673 return CE_MODE;
675 stol = (unsigned char *)unknown[cid] + COMM_MSR_OFFSET;
676 ioctl(ptr->fd,TIOCMGET,&mstat);
677 if( mstat&TIOCM_CAR )
678 *stol |= 0x80;
679 else
680 *stol &=0x7f;
682 if (lpStat) {
683 lpStat->status = 0;
685 lpStat->cbOutQue = comm_outbuf(ptr);
686 lpStat->cbInQue = comm_inbuf(ptr);
688 TRACE(comm, "cid %d, error %d, lpStat %d %d %d stol %x\n",
689 cid, ptr->commerror, lpStat->status, lpStat->cbInQue,
690 lpStat->cbOutQue, *stol);
692 else
693 TRACE(comm, "cid %d, error %d, lpStat NULL stol %x\n",
694 cid, ptr->commerror, *stol);
696 /* Return any errors and clear it */
697 temperror = ptr->commerror;
698 ptr->commerror = 0;
699 return(temperror);
702 /*****************************************************************************
703 * SetCommEventMask (USER.208)
705 SEGPTR WINAPI SetCommEventMask16(INT16 cid,UINT16 fuEvtMask)
707 struct DosDeviceStruct *ptr;
708 unsigned char *stol;
709 int repid;
710 unsigned int mstat;
712 TRACE(comm,"cid %d,mask %d\n",cid,fuEvtMask);
713 if ((ptr = GetDeviceStruct(cid)) == NULL) {
714 return -1;
716 ptr->eventmask = fuEvtMask;
717 if (cid&0x80) {
718 WARN(comm," cid %d not comm port\n",cid);
719 return SEGPTR_GET(NULL);
721 stol = (unsigned char *)unknown[cid] + COMM_MSR_OFFSET;
722 repid = ioctl(ptr->fd,TIOCMGET,&mstat);
723 TRACE(comm, " ioctl %d, msr %x at %p %p\n",repid,mstat,stol,unknown[cid]);
724 if ((mstat&TIOCM_CAR)) {*stol |= 0x80;}
725 else {*stol &=0x7f;}
726 TRACE(comm," modem dcd construct %x\n",*stol);
727 return SEGPTR_GET(unknown[cid]);
730 /*****************************************************************************
731 * GetCommEventMask (USER.209)
733 UINT16 WINAPI GetCommEventMask16(INT16 cid,UINT16 fnEvtClear)
735 struct DosDeviceStruct *ptr;
736 WORD events;
738 TRACE(comm, "cid %d, mask %d\n", cid, fnEvtClear);
739 if ((ptr = GetDeviceStruct(cid)) == NULL) {
740 return -1;
742 if (cid&0x80) {
743 WARN(comm," cid %d not comm port\n",cid);
744 return 0;
747 events = *(WORD*)(unknown[cid]) & fnEvtClear;
748 *(WORD*)(unknown[cid]) &= ~fnEvtClear;
749 return events;
752 /*****************************************************************************
753 * SetCommState16 (USER.201)
755 INT16 WINAPI SetCommState16(LPDCB16 lpdcb)
757 struct termios port;
758 struct DosDeviceStruct *ptr;
760 TRACE(comm, "cid %d, ptr %p\n", lpdcb->Id, lpdcb);
761 if ((ptr = GetDeviceStruct(lpdcb->Id)) == NULL) {
762 return -1;
764 if (tcgetattr(ptr->fd, &port) == -1) {
765 ptr->commerror = WinError();
766 return -1;
769 port.c_cc[VMIN] = 0;
770 port.c_cc[VTIME] = 1;
772 #ifdef IMAXBEL
773 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|IMAXBEL);
774 #else
775 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR);
776 #endif
777 port.c_iflag |= (IGNBRK);
779 port.c_oflag &= ~(OPOST);
781 port.c_cflag &= ~(HUPCL);
782 port.c_cflag |= CLOCAL | CREAD;
784 port.c_lflag &= ~(ICANON|ECHO|ISIG);
785 port.c_lflag |= NOFLSH;
787 TRACE(comm,"baudrate %d\n",lpdcb->BaudRate);
788 #ifdef CBAUD
789 port.c_cflag &= ~CBAUD;
790 switch (lpdcb->BaudRate) {
791 case 110:
792 case CBR_110:
793 port.c_cflag |= B110;
794 break;
795 case 300:
796 case CBR_300:
797 port.c_cflag |= B300;
798 break;
799 case 600:
800 case CBR_600:
801 port.c_cflag |= B600;
802 break;
803 case 1200:
804 case CBR_1200:
805 port.c_cflag |= B1200;
806 break;
807 case 2400:
808 case CBR_2400:
809 port.c_cflag |= B2400;
810 break;
811 case 4800:
812 case CBR_4800:
813 port.c_cflag |= B4800;
814 break;
815 case 9600:
816 case CBR_9600:
817 port.c_cflag |= B9600;
818 break;
819 case 19200:
820 case CBR_19200:
821 port.c_cflag |= B19200;
822 break;
823 case 38400:
824 case CBR_38400:
825 port.c_cflag |= B38400;
826 break;
827 #ifdef B57600
828 case 57600:
829 port.c_cflag |= B57600;
830 break;
831 #endif
832 #ifdef B115200
833 case 57601:
834 port.c_cflag |= B115200;
835 break;
836 #endif
837 default:
838 ptr->commerror = IE_BAUDRATE;
839 return -1;
841 #elif !defined(__EMX__)
842 switch (lpdcb->BaudRate) {
843 case 110:
844 case CBR_110:
845 port.c_ospeed = B110;
846 break;
847 case 300:
848 case CBR_300:
849 port.c_ospeed = B300;
850 break;
851 case 600:
852 case CBR_600:
853 port.c_ospeed = B600;
854 break;
855 case 1200:
856 case CBR_1200:
857 port.c_ospeed = B1200;
858 break;
859 case 2400:
860 case CBR_2400:
861 port.c_ospeed = B2400;
862 break;
863 case 4800:
864 case CBR_4800:
865 port.c_ospeed = B4800;
866 break;
867 case 9600:
868 case CBR_9600:
869 port.c_ospeed = B9600;
870 break;
871 case 19200:
872 case CBR_19200:
873 port.c_ospeed = B19200;
874 break;
875 case 38400:
876 case CBR_38400:
877 port.c_ospeed = B38400;
878 break;
879 default:
880 ptr->commerror = IE_BAUDRATE;
881 return -1;
883 port.c_ispeed = port.c_ospeed;
884 #endif
885 TRACE(comm,"bytesize %d\n",lpdcb->ByteSize);
886 port.c_cflag &= ~CSIZE;
887 switch (lpdcb->ByteSize) {
888 case 5:
889 port.c_cflag |= CS5;
890 break;
891 case 6:
892 port.c_cflag |= CS6;
893 break;
894 case 7:
895 port.c_cflag |= CS7;
896 break;
897 case 8:
898 port.c_cflag |= CS8;
899 break;
900 default:
901 ptr->commerror = IE_BYTESIZE;
902 return -1;
905 TRACE(comm,"fParity %d Parity %d\n",lpdcb->fParity, lpdcb->Parity);
906 port.c_cflag &= ~(PARENB | PARODD);
907 if (lpdcb->fParity)
908 port.c_iflag |= INPCK;
909 else
910 port.c_iflag &= ~INPCK;
911 switch (lpdcb->Parity) {
912 case NOPARITY:
913 break;
914 case ODDPARITY:
915 port.c_cflag |= (PARENB | PARODD);
916 break;
917 case EVENPARITY:
918 port.c_cflag |= PARENB;
919 break;
920 default:
921 ptr->commerror = IE_BYTESIZE;
922 return -1;
926 TRACE(comm,"stopbits %d\n",lpdcb->StopBits);
928 switch (lpdcb->StopBits) {
929 case ONESTOPBIT:
930 port.c_cflag &= ~CSTOPB;
931 break;
932 case TWOSTOPBITS:
933 port.c_cflag |= CSTOPB;
934 break;
935 default:
936 ptr->commerror = IE_BYTESIZE;
937 return -1;
939 #ifdef CRTSCTS
941 if (lpdcb->fDtrflow || lpdcb->fRtsflow || lpdcb->fOutxCtsFlow)
942 port.c_cflag |= CRTSCTS;
944 if (lpdcb->fDtrDisable)
945 port.c_cflag &= ~CRTSCTS;
946 #endif
947 if (lpdcb->fInX)
948 port.c_iflag |= IXON;
949 else
950 port.c_iflag &= ~IXON;
951 if (lpdcb->fOutX)
952 port.c_iflag |= IXOFF;
953 else
954 port.c_iflag &= ~IXOFF;
956 if (tcsetattr(ptr->fd, TCSADRAIN, &port) == -1) {
957 ptr->commerror = WinError();
958 return FALSE;
959 } else {
960 ptr->commerror = 0;
961 return 0;
965 /*****************************************************************************
966 * GetCommState (USER.202)
968 INT16 WINAPI GetCommState16(INT16 cid, LPDCB16 lpdcb)
970 struct DosDeviceStruct *ptr;
971 struct termios port;
973 TRACE(comm,"cid %d, ptr %p\n", cid, lpdcb);
974 if ((ptr = GetDeviceStruct(cid)) == NULL) {
975 return -1;
977 if (tcgetattr(ptr->fd, &port) == -1) {
978 ptr->commerror = WinError();
979 return -1;
981 lpdcb->Id = cid;
982 #ifndef __EMX__
983 #ifdef CBAUD
984 switch (port.c_cflag & CBAUD) {
985 #else
986 switch (port.c_ospeed) {
987 #endif
988 case B110:
989 lpdcb->BaudRate = 110;
990 break;
991 case B300:
992 lpdcb->BaudRate = 300;
993 break;
994 case B600:
995 lpdcb->BaudRate = 600;
996 break;
997 case B1200:
998 lpdcb->BaudRate = 1200;
999 break;
1000 case B2400:
1001 lpdcb->BaudRate = 2400;
1002 break;
1003 case B4800:
1004 lpdcb->BaudRate = 4800;
1005 break;
1006 case B9600:
1007 lpdcb->BaudRate = 9600;
1008 break;
1009 case B19200:
1010 lpdcb->BaudRate = 19200;
1011 break;
1012 case B38400:
1013 lpdcb->BaudRate = 38400;
1014 break;
1015 #ifdef B57600
1016 case B57600:
1017 lpdcb->BaudRate = 57600;
1018 break;
1019 #endif
1020 #ifdef B115200
1021 case B115200:
1022 lpdcb->BaudRate = 57601;
1023 break;
1024 #endif
1026 #endif
1027 switch (port.c_cflag & CSIZE) {
1028 case CS5:
1029 lpdcb->ByteSize = 5;
1030 break;
1031 case CS6:
1032 lpdcb->ByteSize = 6;
1033 break;
1034 case CS7:
1035 lpdcb->ByteSize = 7;
1036 break;
1037 case CS8:
1038 lpdcb->ByteSize = 8;
1039 break;
1042 if(port.c_iflag & INPCK)
1043 lpdcb->fParity = TRUE;
1044 else
1045 lpdcb->fParity = FALSE;
1046 switch (port.c_cflag & (PARENB | PARODD)) {
1047 case 0:
1048 lpdcb->Parity = NOPARITY;
1049 break;
1050 case PARENB:
1051 lpdcb->Parity = EVENPARITY;
1052 break;
1053 case (PARENB | PARODD):
1054 lpdcb->Parity = ODDPARITY;
1055 break;
1058 if (port.c_cflag & CSTOPB)
1059 lpdcb->StopBits = TWOSTOPBITS;
1060 else
1061 lpdcb->StopBits = ONESTOPBIT;
1063 lpdcb->RlsTimeout = 50;
1064 lpdcb->CtsTimeout = 50;
1065 lpdcb->DsrTimeout = 50;
1066 lpdcb->fNull = 0;
1067 lpdcb->fChEvt = 0;
1068 lpdcb->fBinary = 1;
1069 lpdcb->fDtrDisable = 0;
1071 #ifdef CRTSCTS
1073 if (port.c_cflag & CRTSCTS) {
1074 lpdcb->fDtrflow = 1;
1075 lpdcb->fRtsflow = 1;
1076 lpdcb->fOutxCtsFlow = 1;
1077 lpdcb->fOutxDsrFlow = 1;
1078 } else
1079 #endif
1080 lpdcb->fDtrDisable = 1;
1082 if (port.c_iflag & IXON)
1083 lpdcb->fInX = 1;
1084 else
1085 lpdcb->fInX = 0;
1087 if (port.c_iflag & IXOFF)
1088 lpdcb->fOutX = 1;
1089 else
1090 lpdcb->fOutX = 0;
1092 lpdcb->XonChar =
1093 lpdcb->XoffChar =
1095 lpdcb->XonLim = 10;
1096 lpdcb->XoffLim = 10;
1098 ptr->commerror = 0;
1099 return 0;
1102 /*****************************************************************************
1103 * TransmitCommChar (USER.206)
1105 INT16 WINAPI TransmitCommChar16(INT16 cid,CHAR chTransmit)
1107 struct DosDeviceStruct *ptr;
1109 TRACE(comm, "cid %d, data %d \n", cid, chTransmit);
1110 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1111 return -1;
1114 if (ptr->suspended) {
1115 ptr->commerror = IE_HARDWARE;
1116 return -1;
1119 if (ptr->xmit >= 0) {
1120 /* character already queued */
1121 /* FIXME: which error would Windows return? */
1122 ptr->commerror = CE_TXFULL;
1123 return -1;
1126 if (ptr->obuf_head == ptr->obuf_tail) {
1127 /* transmit queue empty, try to transmit directly */
1128 if (write(ptr->fd, &chTransmit, 1) == -1) {
1129 /* didn't work, queue it */
1130 ptr->xmit = chTransmit;
1132 } else {
1133 /* data in queue, let this char be transmitted next */
1134 ptr->xmit = chTransmit;
1137 ptr->commerror = 0;
1138 return 0;
1141 /*****************************************************************************
1142 * UngetCommChar (USER.212)
1144 INT16 WINAPI UngetCommChar16(INT16 cid,CHAR chUnget)
1146 struct DosDeviceStruct *ptr;
1148 TRACE(comm,"cid %d (char %d)\n", cid, chUnget);
1149 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1150 return -1;
1153 if (ptr->suspended) {
1154 ptr->commerror = IE_HARDWARE;
1155 return -1;
1158 if (ptr->unget>=0) {
1159 /* character already queued */
1160 /* FIXME: which error would Windows return? */
1161 ptr->commerror = CE_RXOVER;
1162 return -1;
1165 ptr->unget = chUnget;
1167 ptr->commerror = 0;
1168 return 0;
1171 /*****************************************************************************
1172 * ReadComm (USER.204)
1174 INT16 WINAPI ReadComm16(INT16 cid,LPSTR lpvBuf,INT16 cbRead)
1176 int status, length;
1177 struct DosDeviceStruct *ptr;
1178 LPSTR orgBuf = lpvBuf;
1180 TRACE(comm, "cid %d, ptr %p, length %d\n", cid, lpvBuf, cbRead);
1181 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1182 return -1;
1185 if (ptr->suspended) {
1186 ptr->commerror = IE_HARDWARE;
1187 return -1;
1190 /* read unget character */
1191 if (ptr->unget>=0) {
1192 *lpvBuf++ = ptr->unget;
1193 ptr->unget = -1;
1195 length = 1;
1196 } else
1197 length = 0;
1199 /* read from receive buffer */
1200 while (length < cbRead) {
1201 status = ((ptr->ibuf_head < ptr->ibuf_tail) ?
1202 ptr->ibuf_size : ptr->ibuf_head) - ptr->ibuf_tail;
1203 if (!status) break;
1204 if ((cbRead - length) < status)
1205 status = cbRead - length;
1207 memcpy(lpvBuf, ptr->inbuf + ptr->ibuf_tail, status);
1208 ptr->ibuf_tail += status;
1209 if (ptr->ibuf_tail >= ptr->ibuf_size)
1210 ptr->ibuf_tail = 0;
1211 lpvBuf += status;
1212 length += status;
1215 TRACE(comm,"%.*s\n", length, orgBuf);
1216 ptr->commerror = 0;
1217 return length;
1220 /*****************************************************************************
1221 * WriteComm (USER.205)
1223 INT16 WINAPI WriteComm16(INT16 cid, LPSTR lpvBuf, INT16 cbWrite)
1225 int status, length;
1226 struct DosDeviceStruct *ptr;
1228 TRACE(comm,"cid %d, ptr %p, length %d\n",
1229 cid, lpvBuf, cbWrite);
1230 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1231 return -1;
1234 if (ptr->suspended) {
1235 ptr->commerror = IE_HARDWARE;
1236 return -1;
1239 TRACE(comm,"%.*s\n", cbWrite, lpvBuf );
1241 length = 0;
1242 while (length < cbWrite) {
1243 if ((ptr->obuf_head == ptr->obuf_tail) && (ptr->xmit < 0)) {
1244 /* no data queued, try to write directly */
1245 status = write(ptr->fd, lpvBuf, cbWrite - length);
1246 if (status > 0) {
1247 lpvBuf += status;
1248 length += status;
1249 continue;
1252 /* can't write directly, put into transmit buffer */
1253 status = ((ptr->obuf_tail > ptr->obuf_head) ?
1254 (ptr->obuf_tail-1) : ptr->obuf_size) - ptr->obuf_head;
1255 if (!status) break;
1256 if ((cbWrite - length) < status)
1257 status = cbWrite - length;
1258 memcpy(lpvBuf, ptr->outbuf + ptr->obuf_head, status);
1259 ptr->obuf_head += status;
1260 if (ptr->obuf_head >= ptr->obuf_size)
1261 ptr->obuf_head = 0;
1262 lpvBuf += status;
1263 length += status;
1266 ptr->commerror = 0;
1267 return length;
1270 /***********************************************************************
1271 * EnableCommNotification (USER.246)
1273 BOOL16 WINAPI EnableCommNotification16( INT16 cid, HWND16 hwnd,
1274 INT16 cbWriteNotify, INT16 cbOutQueue )
1276 struct DosDeviceStruct *ptr;
1278 TRACE(comm, "(%d, %x, %d, %d)\n", cid, hwnd, cbWriteNotify, cbOutQueue);
1279 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1280 ptr->commerror = IE_BADID;
1281 return -1;
1283 ptr->wnd = hwnd;
1284 ptr->n_read = cbWriteNotify;
1285 ptr->n_write = cbOutQueue;
1286 return TRUE;
1290 /**************************************************************************
1291 * BuildCommDCBA (KERNEL32.14)
1293 BOOL WINAPI BuildCommDCBA(LPCSTR device,LPDCB lpdcb)
1295 return BuildCommDCBAndTimeoutsA(device,lpdcb,NULL);
1298 /**************************************************************************
1299 * BuildCommDCBAndTimeoutsA (KERNEL32.15)
1301 BOOL WINAPI BuildCommDCBAndTimeoutsA(LPCSTR device, LPDCB lpdcb,
1302 LPCOMMTIMEOUTS lptimeouts)
1304 int port;
1305 char *ptr,*temp;
1307 TRACE(comm,"(%s,%p,%p)\n",device,lpdcb,lptimeouts);
1309 if (!lstrncmpiA(device,"COM",3)) {
1310 port=device[3]-'0';
1311 if (port--==0) {
1312 ERR(comm,"BUG! COM0 can't exists!.\n");
1313 return FALSE;
1315 if (!ValidCOMPort(port))
1316 return FALSE;
1317 if (*(device+4)!=':')
1318 return FALSE;
1319 temp=(LPSTR)(device+5);
1320 } else
1321 temp=(LPSTR)device;
1323 memset(lpdcb, 0, sizeof(DCB)); /* initialize */
1325 lpdcb->DCBlength = sizeof(DCB);
1326 if (strchr(temp,',')) { /* old style */
1327 DCB16 dcb16;
1328 BOOL16 ret;
1329 char last=temp[strlen(temp)-1];
1331 ret=BuildCommDCB16(device,&dcb16);
1332 if (!ret)
1333 return FALSE;
1334 lpdcb->BaudRate = dcb16.BaudRate;
1335 lpdcb->ByteSize = dcb16.ByteSize;
1336 lpdcb->fBinary = dcb16.fBinary;
1337 lpdcb->Parity = dcb16.Parity;
1338 lpdcb->fParity = dcb16.fParity;
1339 lpdcb->fNull = dcb16.fNull;
1340 lpdcb->StopBits = dcb16.StopBits;
1341 if (last == 'x') {
1342 lpdcb->fInX = TRUE;
1343 lpdcb->fOutX = TRUE;
1344 lpdcb->fOutxCtsFlow = FALSE;
1345 lpdcb->fOutxDsrFlow = FALSE;
1346 lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
1347 lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
1348 } else if (last=='p') {
1349 lpdcb->fInX = FALSE;
1350 lpdcb->fOutX = FALSE;
1351 lpdcb->fOutxCtsFlow = TRUE;
1352 lpdcb->fOutxDsrFlow = TRUE;
1353 lpdcb->fDtrControl = DTR_CONTROL_HANDSHAKE;
1354 lpdcb->fRtsControl = RTS_CONTROL_HANDSHAKE;
1355 } else {
1356 lpdcb->fInX = FALSE;
1357 lpdcb->fOutX = FALSE;
1358 lpdcb->fOutxCtsFlow = FALSE;
1359 lpdcb->fOutxDsrFlow = FALSE;
1360 lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
1361 lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
1363 lpdcb->XonChar = dcb16.XonChar;
1364 lpdcb->XoffChar = dcb16.XoffChar;
1365 lpdcb->ErrorChar= dcb16.PeChar;
1366 lpdcb->fErrorChar= dcb16.fPeChar;
1367 lpdcb->EofChar = dcb16.EofChar;
1368 lpdcb->EvtChar = dcb16.EvtChar;
1369 lpdcb->XonLim = dcb16.XonLim;
1370 lpdcb->XoffLim = dcb16.XoffLim;
1371 return TRUE;
1373 ptr=strtok(temp," ");
1374 while (ptr) {
1375 DWORD flag,x;
1377 flag=0;
1378 if (!strncmp("baud=",ptr,5)) {
1379 if (!sscanf(ptr+5,"%ld",&x))
1380 WARN(comm,"Couldn't parse %s\n",ptr);
1381 lpdcb->BaudRate = x;
1382 flag=1;
1384 if (!strncmp("stop=",ptr,5)) {
1385 if (!sscanf(ptr+5,"%ld",&x))
1386 WARN(comm,"Couldn't parse %s\n",ptr);
1387 lpdcb->StopBits = x;
1388 flag=1;
1390 if (!strncmp("data=",ptr,5)) {
1391 if (!sscanf(ptr+5,"%ld",&x))
1392 WARN(comm,"Couldn't parse %s\n",ptr);
1393 lpdcb->ByteSize = x;
1394 flag=1;
1396 if (!strncmp("parity=",ptr,7)) {
1397 lpdcb->fParity = TRUE;
1398 switch (ptr[8]) {
1399 case 'N':case 'n':
1400 lpdcb->fParity = FALSE;
1401 lpdcb->Parity = NOPARITY;
1402 break;
1403 case 'E':case 'e':
1404 lpdcb->Parity = EVENPARITY;
1405 break;
1406 case 'O':case 'o':
1407 lpdcb->Parity = ODDPARITY;
1408 break;
1409 case 'M':case 'm':
1410 lpdcb->Parity = MARKPARITY;
1411 break;
1413 flag=1;
1415 if (!flag)
1416 ERR(comm,"Unhandled specifier '%s', please report.\n",ptr);
1417 ptr=strtok(NULL," ");
1419 if (lpdcb->BaudRate==110)
1420 lpdcb->StopBits = 2;
1421 return TRUE;
1424 /**************************************************************************
1425 * BuildCommDCBAndTimeoutsW (KERNEL32.16)
1427 BOOL WINAPI BuildCommDCBAndTimeoutsW( LPCWSTR devid, LPDCB lpdcb,
1428 LPCOMMTIMEOUTS lptimeouts )
1430 LPSTR devidA;
1431 BOOL ret;
1433 TRACE(comm,"(%p,%p,%p)\n",devid,lpdcb,lptimeouts);
1434 devidA = HEAP_strdupWtoA( GetProcessHeap(), 0, devid );
1435 ret=BuildCommDCBAndTimeoutsA(devidA,lpdcb,lptimeouts);
1436 HeapFree( GetProcessHeap(), 0, devidA );
1437 return ret;
1440 /**************************************************************************
1441 * BuildCommDCBW (KERNEL32.17)
1443 BOOL WINAPI BuildCommDCBW(LPCWSTR devid,LPDCB lpdcb)
1445 return BuildCommDCBAndTimeoutsW(devid,lpdcb,NULL);
1448 /*****************************************************************************
1449 * COMM_Handle2fd
1450 * returns a file descriptor for reading from or writing to
1451 * mode is GENERIC_READ or GENERIC_WRITE. Make sure to close
1452 * the handle afterwards!
1454 int COMM_Handle2fd(HANDLE handle, int mode) {
1455 struct get_read_fd_request r_req;
1456 struct get_write_fd_request w_req;
1457 int fd;
1459 w_req.handle = r_req.handle = handle;
1461 switch(mode) {
1462 case GENERIC_WRITE:
1463 CLIENT_SendRequest( REQ_GET_WRITE_FD, -1, 1, &w_req, sizeof(w_req) );
1464 break;
1465 case GENERIC_READ:
1466 CLIENT_SendRequest( REQ_GET_READ_FD, -1, 1, &r_req, sizeof(r_req) );
1467 break;
1468 default:
1469 ERR(comm,"COMM_Handle2fd: Don't know what type of fd is required.\n");
1470 return -1;
1472 CLIENT_WaitReply( NULL, &fd, 0 );
1474 return fd;
1477 /* FIXME: having these global for win32 for now */
1478 int commerror=0,eventmask=0;
1480 /*****************************************************************************
1481 * SetCommBreak (KERNEL32.449)
1483 BOOL WINAPI SetCommBreak(HANDLE handle)
1485 FIXME(comm,"handle %d, stub!\n", handle);
1486 return TRUE;
1489 /*****************************************************************************
1490 * ClearCommBreak (KERNEL32.20)
1492 BOOL WINAPI ClearCommBreak(HANDLE handle)
1494 FIXME(comm,"handle %d, stub!\n", handle);
1495 return TRUE;
1498 /*****************************************************************************
1499 * EscapeCommFunction (KERNEL32.214)
1501 BOOL WINAPI EscapeCommFunction(HANDLE handle,UINT nFunction)
1503 int fd;
1504 struct termios port;
1506 TRACE(comm,"handle %d, function=%d\n", handle, nFunction);
1507 fd = COMM_Handle2fd(handle, GENERIC_WRITE);
1508 if(fd<0)
1509 return FALSE;
1511 if (tcgetattr(fd,&port) == -1) {
1512 commerror=WinError();
1513 close(fd);
1514 return FALSE;
1517 switch (nFunction) {
1518 case RESETDEV:
1519 break;
1521 #ifdef TIOCM_DTR
1522 case CLRDTR:
1523 port.c_cflag &= TIOCM_DTR;
1524 break;
1525 #endif
1527 #ifdef TIOCM_RTS
1528 case CLRRTS:
1529 port.c_cflag &= TIOCM_RTS;
1530 break;
1531 #endif
1533 #ifdef CRTSCTS
1534 case SETDTR:
1535 port.c_cflag |= CRTSCTS;
1536 break;
1538 case SETRTS:
1539 port.c_cflag |= CRTSCTS;
1540 break;
1541 #endif
1543 case SETXOFF:
1544 port.c_iflag |= IXOFF;
1545 break;
1547 case SETXON:
1548 port.c_iflag |= IXON;
1549 break;
1550 case SETBREAK:
1551 FIXME(comm,"setbreak, stub\n");
1552 /* ptr->suspended = 1; */
1553 break;
1554 case CLRBREAK:
1555 FIXME(comm,"clrbreak, stub\n");
1556 /* ptr->suspended = 0; */
1557 break;
1558 default:
1559 WARN(comm,"(handle=%d,nFunction=%d): Unknown function\n",
1560 handle, nFunction);
1561 break;
1564 if (tcsetattr(fd, TCSADRAIN, &port) == -1) {
1565 commerror = WinError();
1566 close(fd);
1567 return FALSE;
1568 } else {
1569 commerror = 0;
1570 close(fd);
1571 return TRUE;
1575 /********************************************************************
1576 * PurgeComm (KERNEL32.557)
1578 BOOL WINAPI PurgeComm( HANDLE handle, DWORD flags)
1580 int fd;
1582 TRACE(comm,"handle %d, flags %lx\n", handle, flags);
1584 fd = COMM_Handle2fd(handle, GENERIC_WRITE);
1585 if(fd<0)
1586 return FALSE;
1589 ** not exactly sure how these are different
1590 ** Perhaps if we had our own internal queues, one flushes them
1591 ** and the other flushes the kernel's buffers.
1593 if(flags&PURGE_TXABORT)
1595 tcflush(fd,TCOFLUSH);
1597 if(flags&PURGE_RXABORT)
1599 tcflush(fd,TCIFLUSH);
1601 if(flags&PURGE_TXCLEAR)
1603 tcflush(fd,TCOFLUSH);
1605 if(flags&PURGE_RXCLEAR)
1607 tcflush(fd,TCIFLUSH);
1609 close(fd);
1611 return 1;
1614 /*****************************************************************************
1615 * ClearCommError (KERNEL32.21)
1617 BOOL WINAPI ClearCommError(INT handle,LPDWORD errors,LPCOMSTAT lpStat)
1619 int fd;
1621 fd=COMM_Handle2fd(handle,GENERIC_READ);
1622 if(0>fd)
1624 return FALSE;
1627 if (lpStat)
1629 lpStat->status = 0;
1631 if(ioctl(fd, TIOCOUTQ, &lpStat->cbOutQue))
1632 WARN(comm, "ioctl returned error\n");
1634 if(ioctl(fd, TIOCINQ, &lpStat->cbInQue))
1635 WARN(comm, "ioctl returned error\n");
1638 close(fd);
1640 TRACE(comm,"handle %d cbInQue = %ld cbOutQue = %ld\n",
1641 handle,
1642 lpStat->cbInQue,
1643 lpStat->cbOutQue);
1645 if(errors)
1646 *errors = 0;
1649 ** After an asynchronous write opperation, the
1650 ** app will call ClearCommError to see if the
1651 ** results are ready yet. It waits for ERROR_IO_PENDING
1653 commerror = ERROR_IO_PENDING;
1655 return TRUE;
1658 /*****************************************************************************
1659 * SetupComm (KERNEL32.676)
1661 BOOL WINAPI SetupComm( HANDLE handle, DWORD insize, DWORD outsize)
1663 int fd;
1665 FIXME(comm, "insize %ld outsize %ld unimplemented stub\n", insize, outsize);
1666 fd=COMM_Handle2fd(handle,GENERIC_WRITE);
1667 if(0>fd)
1669 return FALSE;
1671 close(fd);
1672 return TRUE;
1675 /*****************************************************************************
1676 * GetCommMask (KERNEL32.156)
1678 BOOL WINAPI GetCommMask(HANDLE handle,LPDWORD evtmask)
1680 int fd;
1682 TRACE(comm, "handle %d, mask %p\n", handle, evtmask);
1683 if(0>(fd=COMM_Handle2fd(handle,GENERIC_READ)))
1685 return FALSE;
1687 close(fd);
1688 *evtmask = eventmask;
1689 return TRUE;
1692 /*****************************************************************************
1693 * SetCommMask (KERNEL32.451)
1695 BOOL WINAPI SetCommMask(INT handle,DWORD evtmask)
1697 int fd;
1699 TRACE(comm, "handle %d, mask %lx\n", handle, evtmask);
1700 if(0>(fd=COMM_Handle2fd(handle,GENERIC_WRITE))) {
1701 return FALSE;
1703 close(fd);
1704 eventmask = evtmask;
1705 return TRUE;
1708 /*****************************************************************************
1709 * SetCommState (KERNEL32.452)
1711 BOOL WINAPI SetCommState(INT handle,LPDCB lpdcb)
1713 struct termios port;
1714 int fd;
1715 struct get_write_fd_request req;
1717 TRACE(comm,"handle %d, ptr %p\n", handle, lpdcb);
1719 req.handle = handle;
1720 CLIENT_SendRequest( REQ_GET_WRITE_FD, -1, 1, &req, sizeof(req) );
1721 CLIENT_WaitReply( NULL, &fd, 0 );
1723 if(fd<0)
1724 return FALSE;
1726 if (tcgetattr(fd,&port) == -1) {
1727 commerror = WinError();
1728 return FALSE;
1731 port.c_cc[VMIN] = 0;
1732 port.c_cc[VTIME] = 1;
1734 #ifdef IMAXBEL
1735 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|IMAXBEL);
1736 #else
1737 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR);
1738 #endif
1739 port.c_iflag |= (IGNBRK);
1741 port.c_oflag &= ~(OPOST);
1743 port.c_cflag &= ~(HUPCL);
1744 port.c_cflag |= CLOCAL | CREAD;
1746 port.c_lflag &= ~(ICANON|ECHO|ISIG);
1747 port.c_lflag |= NOFLSH;
1750 ** MJM - removed default baudrate settings
1751 ** TRACE(comm,"baudrate %ld\n",lpdcb->BaudRate);
1753 #ifdef CBAUD
1754 port.c_cflag &= ~CBAUD;
1755 switch (lpdcb->BaudRate) {
1756 case 110:
1757 case CBR_110:
1758 port.c_cflag |= B110;
1759 break;
1760 case 300:
1761 case CBR_300:
1762 port.c_cflag |= B300;
1763 break;
1764 case 600:
1765 case CBR_600:
1766 port.c_cflag |= B600;
1767 break;
1768 case 1200:
1769 case CBR_1200:
1770 port.c_cflag |= B1200;
1771 break;
1772 case 2400:
1773 case CBR_2400:
1774 port.c_cflag |= B2400;
1775 break;
1776 case 4800:
1777 case CBR_4800:
1778 port.c_cflag |= B4800;
1779 break;
1780 case 9600:
1781 case CBR_9600:
1782 port.c_cflag |= B9600;
1783 break;
1784 case 19200:
1785 case CBR_19200:
1786 port.c_cflag |= B19200;
1787 break;
1788 case 38400:
1789 case CBR_38400:
1790 port.c_cflag |= B38400;
1791 break;
1792 default:
1793 commerror = IE_BAUDRATE;
1794 return FALSE;
1796 #elif !defined(__EMX__)
1797 switch (lpdcb->BaudRate) {
1798 case 110:
1799 case CBR_110:
1800 port.c_ospeed = B110;
1801 break;
1802 case 300:
1803 case CBR_300:
1804 port.c_ospeed = B300;
1805 break;
1806 case 600:
1807 case CBR_600:
1808 port.c_ospeed = B600;
1809 break;
1810 case 1200:
1811 case CBR_1200:
1812 port.c_ospeed = B1200;
1813 break;
1814 case 2400:
1815 case CBR_2400:
1816 port.c_ospeed = B2400;
1817 break;
1818 case 4800:
1819 case CBR_4800:
1820 port.c_ospeed = B4800;
1821 break;
1822 case 9600:
1823 case CBR_9600:
1824 port.c_ospeed = B9600;
1825 break;
1826 case 19200:
1827 case CBR_19200:
1828 port.c_ospeed = B19200;
1829 break;
1830 case 38400:
1831 case CBR_38400:
1832 port.c_ospeed = B38400;
1833 break;
1834 default:
1835 commerror = IE_BAUDRATE;
1836 return FALSE;
1838 port.c_ispeed = port.c_ospeed;
1839 #endif
1840 TRACE(comm,"bytesize %d\n",lpdcb->ByteSize);
1841 port.c_cflag &= ~CSIZE;
1842 switch (lpdcb->ByteSize) {
1843 case 5:
1844 port.c_cflag |= CS5;
1845 break;
1846 case 6:
1847 port.c_cflag |= CS6;
1848 break;
1849 case 7:
1850 port.c_cflag |= CS7;
1851 break;
1852 case 8:
1853 port.c_cflag |= CS8;
1854 break;
1855 default:
1856 commerror = IE_BYTESIZE;
1857 return FALSE;
1860 TRACE(comm,"fParity %d Parity %d\n",lpdcb->fParity, lpdcb->Parity);
1861 port.c_cflag &= ~(PARENB | PARODD);
1862 if (lpdcb->fParity)
1863 port.c_iflag |= INPCK;
1864 else
1865 port.c_iflag &= ~INPCK;
1866 switch (lpdcb->Parity) {
1867 case NOPARITY:
1868 break;
1869 case ODDPARITY:
1870 port.c_cflag |= (PARENB | PARODD);
1871 break;
1872 case EVENPARITY:
1873 port.c_cflag |= PARENB;
1874 break;
1875 default:
1876 commerror = IE_BYTESIZE;
1877 return FALSE;
1881 TRACE(comm,"stopbits %d\n",lpdcb->StopBits);
1882 switch (lpdcb->StopBits) {
1883 case ONESTOPBIT:
1884 port.c_cflag &= ~CSTOPB;
1885 break;
1886 case TWOSTOPBITS:
1887 port.c_cflag |= CSTOPB;
1888 break;
1889 default:
1890 commerror = IE_BYTESIZE;
1891 return FALSE;
1893 #ifdef CRTSCTS
1894 if ( lpdcb->fOutxCtsFlow ||
1895 lpdcb->fDtrControl == DTR_CONTROL_ENABLE||
1896 lpdcb->fRtsControl == RTS_CONTROL_ENABLE
1898 port.c_cflag |= CRTSCTS;
1899 if (lpdcb->fDtrControl == DTR_CONTROL_DISABLE)
1900 port.c_cflag &= ~CRTSCTS;
1902 #endif
1903 if (lpdcb->fInX)
1904 port.c_iflag |= IXON;
1905 else
1906 port.c_iflag &= ~IXON;
1907 if (lpdcb->fOutX)
1908 port.c_iflag |= IXOFF;
1909 else
1910 port.c_iflag &= ~IXOFF;
1912 if (tcsetattr(fd,TCSADRAIN,&port)==-1) {
1913 commerror = WinError();
1914 return FALSE;
1915 } else {
1916 commerror = 0;
1917 return TRUE;
1922 /*****************************************************************************
1923 * GetCommState (KERNEL32.159)
1925 BOOL WINAPI GetCommState(INT handle, LPDCB lpdcb)
1927 struct termios port;
1928 int fd;
1929 struct get_read_fd_request req;
1931 TRACE(comm,"handle %d, ptr %p\n", handle, lpdcb);
1932 req.handle = handle;
1933 CLIENT_SendRequest( REQ_GET_READ_FD, -1, 1, &req, sizeof(req) );
1934 CLIENT_WaitReply( NULL, &fd, 0 );
1936 if(fd<0)
1937 return FALSE;
1939 if (tcgetattr(fd, &port) == -1) {
1940 TRACE(comm,"tcgetattr(%d, ...) returned -1",fd);
1941 commerror = WinError();
1942 return FALSE;
1944 #ifndef __EMX__
1945 #ifdef CBAUD
1946 switch (port.c_cflag & CBAUD) {
1947 #else
1948 switch (port.c_ospeed) {
1949 #endif
1950 case B110:
1951 lpdcb->BaudRate = 110;
1952 break;
1953 case B300:
1954 lpdcb->BaudRate = 300;
1955 break;
1956 case B600:
1957 lpdcb->BaudRate = 600;
1958 break;
1959 case B1200:
1960 lpdcb->BaudRate = 1200;
1961 break;
1962 case B2400:
1963 lpdcb->BaudRate = 2400;
1964 break;
1965 case B4800:
1966 lpdcb->BaudRate = 4800;
1967 break;
1968 case B9600:
1969 lpdcb->BaudRate = 9600;
1970 break;
1971 case B19200:
1972 lpdcb->BaudRate = 19200;
1973 break;
1974 case B38400:
1975 lpdcb->BaudRate = 38400;
1976 break;
1978 #endif
1979 switch (port.c_cflag & CSIZE) {
1980 case CS5:
1981 lpdcb->ByteSize = 5;
1982 break;
1983 case CS6:
1984 lpdcb->ByteSize = 6;
1985 break;
1986 case CS7:
1987 lpdcb->ByteSize = 7;
1988 break;
1989 case CS8:
1990 lpdcb->ByteSize = 8;
1991 break;
1994 if(port.c_iflag & INPCK)
1995 lpdcb->fParity = TRUE;
1996 else
1997 lpdcb->fParity = FALSE;
1998 switch (port.c_cflag & (PARENB | PARODD)) {
1999 case 0:
2000 lpdcb->Parity = NOPARITY;
2001 break;
2002 case PARENB:
2003 lpdcb->Parity = EVENPARITY;
2004 break;
2005 case (PARENB | PARODD):
2006 lpdcb->Parity = ODDPARITY;
2007 break;
2010 if (port.c_cflag & CSTOPB)
2011 lpdcb->StopBits = TWOSTOPBITS;
2012 else
2013 lpdcb->StopBits = ONESTOPBIT;
2015 lpdcb->fNull = 0;
2016 lpdcb->fBinary = 1;
2018 #ifdef CRTSCTS
2020 if (port.c_cflag & CRTSCTS) {
2021 lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
2022 lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
2023 lpdcb->fOutxCtsFlow = 1;
2024 lpdcb->fOutxDsrFlow = 1;
2025 } else
2026 #endif
2028 lpdcb->fDtrControl = DTR_CONTROL_DISABLE;
2029 lpdcb->fRtsControl = RTS_CONTROL_DISABLE;
2031 if (port.c_iflag & IXON)
2032 lpdcb->fInX = 1;
2033 else
2034 lpdcb->fInX = 0;
2036 if (port.c_iflag & IXOFF)
2037 lpdcb->fOutX = 1;
2038 else
2039 lpdcb->fOutX = 0;
2041 lpdcb->XonChar =
2042 lpdcb->XoffChar =
2044 lpdcb->XonLim = 10;
2045 lpdcb->XoffLim = 10;
2047 commerror = 0;
2049 TRACE(comm,"OK\n");
2051 return TRUE;
2054 /*****************************************************************************
2055 * TransmitCommChar (KERNEL32.535)
2057 BOOL WINAPI TransmitCommChar(INT cid,CHAR chTransmit)
2059 struct DosDeviceStruct *ptr;
2061 FIXME(comm,"(%d,'%c'), use win32 handle!\n",cid,chTransmit);
2062 if ((ptr = GetDeviceStruct(cid)) == NULL) {
2063 return FALSE;
2066 if (ptr->suspended) {
2067 ptr->commerror = IE_HARDWARE;
2068 return FALSE;
2070 if (write(ptr->fd, (void *) &chTransmit, 1) == -1) {
2071 ptr->commerror = WinError();
2072 return FALSE;
2073 } else {
2074 ptr->commerror = 0;
2075 return TRUE;
2079 /*****************************************************************************
2080 * GetCommTimeouts (KERNEL32.160)
2082 BOOL WINAPI GetCommTimeouts(INT cid,LPCOMMTIMEOUTS lptimeouts)
2084 FIXME(comm,"(%x,%p):stub.\n",cid,lptimeouts);
2085 return TRUE;
2088 /*****************************************************************************
2089 * SetCommTimeouts (KERNEL32.453)
2091 BOOL WINAPI SetCommTimeouts(INT cid,LPCOMMTIMEOUTS lptimeouts) {
2092 FIXME(comm,"(%x,%p):stub.\n",cid,lptimeouts);
2093 return TRUE;
2096 /***********************************************************************
2097 * GetCommModemStatus (KERNEL32.285)
2099 BOOL WINAPI GetCommModemStatus(HANDLE hFile,LPDWORD lpModemStat )
2101 FIXME(comm, "(%d %p)\n",hFile,lpModemStat );
2102 return TRUE;
2104 /***********************************************************************
2105 * WaitCommEvent (KERNEL32.719)
2107 BOOL WINAPI WaitCommEvent(HANDLE hFile,LPDWORD eventmask ,LPOVERLAPPED overlapped)
2109 FIXME(comm, "(%d %p %p )\n",hFile, eventmask,overlapped);
2110 return TRUE;
2113 /***********************************************************************
2114 * GetCommProperties (KERNEL32.???)
2116 BOOL WINAPI GetCommProperties(HANDLE hFile, LPDCB *dcb)
2118 FIXME(comm, "(%d %p )\n",hFile,dcb);
2119 return TRUE;
2122 /***********************************************************************
2123 * SetCommProperties (KERNEL32.???)
2125 BOOL WINAPI SetCommProperties(HANDLE hFile, LPDCB dcb)
2127 FIXME(comm, "(%d %p )\n",hFile,dcb);
2128 return TRUE;