Fixed memory overwrite bug.
[wine/testsucceed.git] / misc / comm.c
blob4cee53494a43ea45e6e4987b3966a191c661086a
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 * Apr 3, 1999. Lawson Whitney <lawson_whitney@juno.com>
10 * - Fixed the modem control part of EscapeCommFunction16.
12 * Mar 3, 1999. Ove Kåven <ovek@arcticnet.no>
13 * - Use port indices instead of unixfds for win16
14 * - Moved things around (separated win16 and win32 routines)
15 * - Added some hints on how to implement buffers and EnableCommNotification.
17 * May 26, 1997. Fixes and comments by Rick Richardson <rick@dgii.com> [RER]
18 * - ptr->fd wasn't getting cleared on close.
19 * - GetCommEventMask() and GetCommError() didn't do much of anything.
20 * IMHO, they are still wrong, but they at least implement the RXCHAR
21 * event and return I/O queue sizes, which makes the app I'm interested
22 * in (analog devices EZKIT DSP development system) work.
24 * August 12, 1997. Take a bash at SetCommEventMask - Lawson Whitney
25 * <lawson_whitney@juno.com>
26 * July 6, 1998. Fixes and comments by Valentijn Sessink
27 * <vsessink@ic.uva.nl> [V]
28 * Oktober 98, Rein Klazes [RHK]
29 * A program that wants to monitor the modem status line (RLSD/DCD) may
30 * poll the modem status register in the commMask structure. I update the bit
31 * in GetCommError, waiting for an implementation of communication events.
35 #include "config.h"
37 #include <stdlib.h>
38 #include <termios.h>
39 #include <fcntl.h>
40 #include <string.h>
41 #ifdef HAVE_STRINGS_H
42 # include <strings.h>
43 #endif
44 #include <errno.h>
45 #include <ctype.h>
46 #include <sys/stat.h>
47 #ifdef HAVE_SYS_FILIO_H
48 # include <sys/filio.h>
49 #endif
50 #include <sys/ioctl.h>
51 #include <unistd.h>
53 #include "wine/winuser16.h"
54 #include "comm.h"
55 #ifdef HAVE_SYS_MODEM_H
56 # include <sys/modem.h>
57 #endif
58 #ifdef HAVE_SYS_STRTIO_H
59 # include <sys/strtio.h>
60 #endif
61 #include "heap.h"
62 #include "options.h"
64 #include "server.h"
65 #include "process.h"
66 #include "winerror.h"
67 #include "services.h"
68 #include "file.h"
70 #include "debugtools.h"
72 DEFAULT_DEBUG_CHANNEL(comm)
74 #ifndef TIOCINQ
75 #define TIOCINQ FIONREAD
76 #endif
77 #define COMM_MSR_OFFSET 35 /* see knowledge base Q101417 */
78 #define FLAG_LPT 0x80
80 struct DosDeviceStruct COM[MAX_PORTS];
81 struct DosDeviceStruct LPT[MAX_PORTS];
82 /* pointers to unknown(==undocumented) comm structure */
83 LPCVOID *unknown[MAX_PORTS];
84 /* save terminal states */
85 static struct termios m_stat[MAX_PORTS];
87 void COMM_Init(void)
89 int x;
90 char option[10], temp[256], *btemp;
91 struct stat st;
93 for (x=0; x!=MAX_PORTS; x++) {
94 strcpy(option,"COMx");
95 option[3] = '1' + x;
96 option[4] = '\0';
98 PROFILE_GetWineIniString( "serialports", option, "*",
99 temp, sizeof(temp) );
100 if (!strcmp(temp, "*") || *temp == '\0')
101 COM[x].devicename = NULL;
102 else {
103 btemp = strchr(temp,',');
104 if (btemp != NULL) {
105 *btemp++ = '\0';
106 COM[x].baudrate = atoi(btemp);
107 } else {
108 COM[x].baudrate = -1;
110 stat(temp, &st);
111 if (!S_ISCHR(st.st_mode))
112 WARN("Can't use `%s' as %s !\n", temp, option);
113 else
114 if ((COM[x].devicename = malloc(strlen(temp)+1)) == NULL)
115 WARN("Can't malloc for device info!\n");
116 else {
117 COM[x].fd = 0;
118 strcpy(COM[x].devicename, temp);
120 TRACE("%s = %s\n", option, COM[x].devicename);
123 strcpy(option, "LPTx");
124 option[3] = '1' + x;
125 option[4] = '\0';
127 PROFILE_GetWineIniString( "parallelports", option, "*",
128 temp, sizeof(temp) );
129 if (!strcmp(temp, "*") || *temp == '\0')
130 LPT[x].devicename = NULL;
131 else {
132 stat(temp, &st);
133 if (!S_ISCHR(st.st_mode))
134 WARN("Can't use `%s' as %s !\n", temp, option);
135 else
136 if ((LPT[x].devicename = malloc(strlen(temp)+1)) == NULL)
137 WARN("Can't malloc for device info!\n");
138 else {
139 LPT[x].fd = 0;
140 strcpy(LPT[x].devicename, temp);
142 TRACE("%s = %s\n", option, LPT[x].devicename);
149 static struct DosDeviceStruct *GetDeviceStruct(int fd)
151 if ((fd&0x7F)<=MAX_PORTS) {
152 if (!(fd&FLAG_LPT)) {
153 if (COM[fd].fd)
154 return &COM[fd];
155 } else {
156 fd &= 0x7f;
157 if (LPT[fd].fd)
158 return &LPT[fd];
162 return NULL;
165 static int GetCommPort_fd(int fd)
167 int x;
169 for (x=0; x<MAX_PORTS; x++) {
170 if (COM[x].fd == fd)
171 return x;
174 return -1;
177 static int ValidCOMPort(int x)
179 return(x < MAX_PORTS ? (int) COM[x].devicename : 0);
182 static int ValidLPTPort(int x)
184 return(x < MAX_PORTS ? (int) LPT[x].devicename : 0);
187 static int WinError(void)
189 TRACE("errno = %d\n", errno);
190 switch (errno) {
191 default:
192 return CE_IOE;
196 static unsigned comm_inbuf(struct DosDeviceStruct *ptr)
198 return ((ptr->ibuf_tail > ptr->ibuf_head) ? ptr->ibuf_size : 0)
199 + ptr->ibuf_head - ptr->ibuf_tail;
202 static unsigned comm_outbuf(struct DosDeviceStruct *ptr)
204 return ((ptr->obuf_tail > ptr->obuf_head) ? ptr->obuf_size : 0)
205 + ptr->obuf_head - ptr->obuf_tail;
208 static int COMM_WhackModem(int fd, unsigned int andy, unsigned int orrie)
210 unsigned int mstat, okay;
211 okay = ioctl(fd, TIOCMGET, &mstat);
212 if (okay) return okay;
213 if (andy) mstat &= andy;
214 mstat |= orrie;
215 return ioctl(fd, TIOCMSET, &mstat);
218 static void CALLBACK comm_notification( ULONG_PTR private )
220 struct DosDeviceStruct *ptr = (struct DosDeviceStruct *)private;
221 int prev, bleft, len;
222 WORD mask = 0;
223 int cid = GetCommPort_fd(ptr->fd);
225 TRACE("async notification\n");
226 /* read data from comm port */
227 prev = comm_inbuf(ptr);
228 do {
229 bleft = ((ptr->ibuf_tail > ptr->ibuf_head) ? (ptr->ibuf_tail-1) : ptr->ibuf_size)
230 - ptr->ibuf_head;
231 len = read(ptr->fd, ptr->inbuf + ptr->ibuf_head, bleft?bleft:1);
232 if (len > 0) {
233 if (!bleft) {
234 ptr->commerror = CE_RXOVER;
235 } else {
236 /* check for events */
237 if ((ptr->eventmask & EV_RXFLAG) &&
238 memchr(ptr->inbuf + ptr->ibuf_head, ptr->evtchar, len)) {
239 *(WORD*)(unknown[cid]) |= EV_RXFLAG;
240 mask |= CN_EVENT;
242 if (ptr->eventmask & EV_RXCHAR) {
243 *(WORD*)(unknown[cid]) |= EV_RXCHAR;
244 mask |= CN_EVENT;
246 /* advance buffer position */
247 ptr->ibuf_head += len;
248 if (ptr->ibuf_head >= ptr->ibuf_size)
249 ptr->ibuf_head = 0;
252 } while (len > 0);
253 /* check for notification */
254 if (ptr->wnd && (ptr->n_read>0) && (prev<ptr->n_read) &&
255 (comm_inbuf(ptr)>=ptr->n_read)) {
256 /* passed the receive notification threshold */
257 mask |= CN_RECEIVE;
260 /* write any TransmitCommChar character */
261 if (ptr->xmit>=0) {
262 len = write(ptr->fd, &(ptr->xmit), 1);
263 if (len > 0) ptr->xmit = -1;
265 /* write from output queue */
266 prev = comm_outbuf(ptr);
267 do {
268 bleft = ((ptr->obuf_tail <= ptr->obuf_head) ? ptr->obuf_head : ptr->obuf_size)
269 - ptr->obuf_tail;
270 len = bleft ? write(ptr->fd, ptr->outbuf + ptr->obuf_tail, bleft) : 0;
271 if (len > 0) {
272 ptr->obuf_tail += len;
273 if (ptr->obuf_tail >= ptr->obuf_size)
274 ptr->obuf_tail = 0;
275 /* flag event */
276 if (ptr->obuf_tail == ptr->obuf_head) {
277 if (ptr->s_write) {
278 SERVICE_Delete( ptr->s_write );
279 ptr->s_write = INVALID_HANDLE_VALUE;
281 if (ptr->eventmask & EV_TXEMPTY) {
282 *(WORD*)(unknown[cid]) |= EV_TXEMPTY;
283 mask |= CN_EVENT;
287 } while (len > 0);
288 /* check for notification */
289 if (ptr->wnd && (ptr->n_write>0) && (prev>=ptr->n_write) &&
290 (comm_outbuf(ptr)<ptr->n_write)) {
291 /* passed the transmit notification threshold */
292 mask |= CN_TRANSMIT;
295 /* send notifications, if any */
296 if (ptr->wnd && mask) {
297 TRACE("notifying %04x: cid=%d, mask=%02x\n", ptr->wnd, cid, mask);
298 PostMessage16(ptr->wnd, WM_COMMNOTIFY, cid, mask);
302 static void comm_waitread(struct DosDeviceStruct *ptr)
304 if (ptr->s_read != INVALID_HANDLE_VALUE) return;
305 ptr->s_read = SERVICE_AddObject( FILE_DupUnixHandle( ptr->fd,
306 GENERIC_READ | SYNCHRONIZE ),
307 comm_notification,
308 (ULONG_PTR)ptr );
311 static void comm_waitwrite(struct DosDeviceStruct *ptr)
313 if (ptr->s_write != INVALID_HANDLE_VALUE) return;
314 ptr->s_write = SERVICE_AddObject( FILE_DupUnixHandle( ptr->fd,
315 GENERIC_WRITE | SYNCHRONIZE ),
316 comm_notification,
317 (ULONG_PTR)ptr );
320 /**************************************************************************
321 * BuildCommDCB (USER.213)
323 BOOL16 WINAPI BuildCommDCB16(LPCSTR device, LPDCB16 lpdcb)
325 /* "COM1:9600,n,8,1" */
326 /* 012345 */
327 int port;
328 char *ptr, temp[256];
330 TRACE("(%s), ptr %p\n", device, lpdcb);
332 if (!lstrncmpiA(device,"COM",3)) {
333 port = device[3] - '0';
336 if (port-- == 0) {
337 ERR("BUG ! COM0 can't exist!.\n");
338 return -1;
341 if (!ValidCOMPort(port)) {
342 FIXME("invalid COM port %d?\n",port);
343 return -1;
346 memset(lpdcb, 0, sizeof(DCB16)); /* initialize */
348 lpdcb->Id = port;
350 if (!*(device+4))
351 return 0;
353 if (*(device+4) != ':')
354 return -1;
356 strcpy(temp,device+5);
357 ptr = strtok(temp, ", ");
359 if (COM[port].baudrate > 0)
360 lpdcb->BaudRate = COM[port].baudrate;
361 else
362 lpdcb->BaudRate = atoi(ptr);
363 TRACE("baudrate (%d)\n", lpdcb->BaudRate);
365 ptr = strtok(NULL, ", ");
366 if (islower(*ptr))
367 *ptr = toupper(*ptr);
369 TRACE("parity (%c)\n", *ptr);
370 lpdcb->fParity = TRUE;
371 switch (*ptr) {
372 case 'N':
373 lpdcb->Parity = NOPARITY;
374 lpdcb->fParity = FALSE;
375 break;
376 case 'E':
377 lpdcb->Parity = EVENPARITY;
378 break;
379 case 'M':
380 lpdcb->Parity = MARKPARITY;
381 break;
382 case 'O':
383 lpdcb->Parity = ODDPARITY;
384 break;
385 default:
386 WARN("Unknown parity `%c'!\n", *ptr);
387 return -1;
390 ptr = strtok(NULL, ", ");
391 TRACE("charsize (%c)\n", *ptr);
392 lpdcb->ByteSize = *ptr - '0';
394 ptr = strtok(NULL, ", ");
395 TRACE("stopbits (%c)\n", *ptr);
396 switch (*ptr) {
397 case '1':
398 lpdcb->StopBits = ONESTOPBIT;
399 break;
400 case '2':
401 lpdcb->StopBits = TWOSTOPBITS;
402 break;
403 default:
404 WARN("Unknown # of stopbits `%c'!\n", *ptr);
405 return -1;
409 return 0;
412 /*****************************************************************************
413 * OpenComm (USER.200)
415 INT16 WINAPI OpenComm16(LPCSTR device,UINT16 cbInQueue,UINT16 cbOutQueue)
417 int port,fd;
419 TRACE("%s, %d, %d\n", device, cbInQueue, cbOutQueue);
421 if (strlen(device) < 4)
422 return IE_BADID;
424 port = device[3] - '0';
426 if (port-- == 0)
427 ERR("BUG ! COM0 or LPT0 don't exist !\n");
429 if (!lstrncmpiA(device,"COM",3)) {
431 TRACE("%s = %s\n", device, COM[port].devicename);
433 if (!ValidCOMPort(port))
434 return IE_BADID;
436 if (COM[port].fd)
437 return IE_OPEN;
439 fd = open(COM[port].devicename, O_RDWR | O_NONBLOCK);
440 if (fd == -1) {
441 ERR("error=%d\n", errno);
442 return IE_HARDWARE;
443 } else {
444 unknown[port] = SEGPTR_ALLOC(40);
445 bzero(unknown[port],40);
446 COM[port].fd = fd;
447 COM[port].commerror = 0;
448 COM[port].eventmask = 0;
449 COM[port].evtchar = 0; /* FIXME: default? */
450 /* save terminal state */
451 tcgetattr(fd,&m_stat[port]);
452 /* set default parameters */
453 if(COM[port].baudrate>-1){
454 DCB16 dcb;
455 GetCommState16(port, &dcb);
456 dcb.BaudRate=COM[port].baudrate;
457 /* more defaults:
458 * databits, parity, stopbits
460 SetCommState16( &dcb);
462 /* init priority characters */
463 COM[port].unget = -1;
464 COM[port].xmit = -1;
465 /* allocate buffers */
466 COM[port].ibuf_size = cbInQueue;
467 COM[port].ibuf_head = COM[port].ibuf_tail= 0;
468 COM[port].obuf_size = cbOutQueue;
469 COM[port].obuf_head = COM[port].obuf_tail = 0;
471 COM[port].inbuf = malloc(cbInQueue);
472 if (COM[port].inbuf) {
473 COM[port].outbuf = malloc(cbOutQueue);
474 if (!COM[port].outbuf)
475 free(COM[port].inbuf);
476 } else COM[port].outbuf = NULL;
477 if (!COM[port].outbuf) {
478 /* not enough memory */
479 tcsetattr(COM[port].fd,TCSANOW,&m_stat[port]);
480 close(COM[port].fd);
481 ERR("out of memory");
482 return IE_MEMORY;
485 COM[port].s_read = INVALID_HANDLE_VALUE;
486 COM[port].s_write = INVALID_HANDLE_VALUE;
487 comm_waitread( &COM[port] );
488 return port;
491 else
492 if (!lstrncmpiA(device,"LPT",3)) {
494 if (!ValidLPTPort(port))
495 return IE_BADID;
497 if (LPT[port].fd)
498 return IE_OPEN;
500 fd = open(LPT[port].devicename, O_RDWR | O_NONBLOCK, 0);
501 if (fd == -1) {
502 return IE_HARDWARE;
503 } else {
504 LPT[port].fd = fd;
505 LPT[port].commerror = 0;
506 LPT[port].eventmask = 0;
507 return port|FLAG_LPT;
510 return 0;
513 /*****************************************************************************
514 * CloseComm (USER.207)
516 INT16 WINAPI CloseComm16(INT16 cid)
518 struct DosDeviceStruct *ptr;
520 TRACE("cid=%d\n", cid);
521 if ((ptr = GetDeviceStruct(cid)) == NULL) {
522 FIXME("no cid=%d found!\n", cid);
523 return -1;
525 if (!(cid&FLAG_LPT)) {
526 /* COM port */
527 SEGPTR_FREE(unknown[cid]); /* [LW] */
529 SERVICE_Delete( COM[cid].s_write );
530 SERVICE_Delete( COM[cid].s_read );
531 /* free buffers */
532 free(ptr->outbuf);
533 free(ptr->inbuf);
535 /* reset modem lines */
536 tcsetattr(ptr->fd,TCSANOW,&m_stat[cid]);
539 if (close(ptr->fd) == -1) {
540 ptr->commerror = WinError();
541 /* FIXME: should we clear ptr->fd here? */
542 return -1;
543 } else {
544 ptr->commerror = 0;
545 ptr->fd = 0;
546 return 0;
550 /*****************************************************************************
551 * SetCommBreak (USER.210)
553 INT16 WINAPI SetCommBreak16(INT16 cid)
555 struct DosDeviceStruct *ptr;
557 TRACE("cid=%d\n", cid);
558 if ((ptr = GetDeviceStruct(cid)) == NULL) {
559 FIXME("no cid=%d found!\n", cid);
560 return -1;
563 ptr->suspended = 1;
564 ptr->commerror = 0;
565 return 0;
568 /*****************************************************************************
569 * ClearCommBreak (USER.211)
571 INT16 WINAPI ClearCommBreak16(INT16 cid)
573 struct DosDeviceStruct *ptr;
575 TRACE("cid=%d\n", cid);
576 if (!(ptr = GetDeviceStruct(cid))) {
577 FIXME("no cid=%d found!\n", cid);
578 return -1;
580 ptr->suspended = 0;
581 ptr->commerror = 0;
582 return 0;
585 /*****************************************************************************
586 * EscapeCommFunction (USER.214)
588 LONG WINAPI EscapeCommFunction16(UINT16 cid,UINT16 nFunction)
590 int max;
591 struct DosDeviceStruct *ptr;
592 struct termios port;
594 TRACE("cid=%d, function=%d\n", cid, nFunction);
595 if ((nFunction != GETMAXCOM) && (nFunction != GETMAXLPT)) {
596 if ((ptr = GetDeviceStruct(cid)) == NULL) {
597 FIXME("no cid=%d found!\n", cid);
598 return -1;
600 if (tcgetattr(ptr->fd,&port) == -1) {
601 TRACE("tcgetattr failed\n");
602 ptr->commerror=WinError();
603 return -1;
605 } else ptr = NULL;
607 switch (nFunction) {
608 case RESETDEV:
609 TRACE("RESETDEV\n");
610 break;
612 case GETMAXCOM:
613 TRACE("GETMAXCOM\n");
614 for (max = MAX_PORTS;!COM[max].devicename;max--)
616 return max;
617 break;
619 case GETMAXLPT:
620 TRACE("GETMAXLPT\n");
621 for (max = MAX_PORTS;!LPT[max].devicename;max--)
623 return FLAG_LPT + max;
624 break;
626 case GETBASEIRQ:
627 TRACE("GETBASEIRQ\n");
628 /* FIXME: use tables */
629 /* just fake something for now */
630 if (cid & FLAG_LPT) {
631 /* LPT1: irq 7, LPT2: irq 5 */
632 return (cid & 0x7f) ? 5 : 7;
633 } else {
634 /* COM1: irq 4, COM2: irq 3,
635 COM3: irq 4, COM4: irq 3 */
636 return 4 - (cid & 1);
638 break;
640 case CLRDTR:
641 TRACE("CLRDTR\n");
642 #ifdef TIOCM_DTR
643 return COMM_WhackModem(ptr->fd, ~TIOCM_DTR, 0);
644 #endif
645 case CLRRTS:
646 TRACE("CLRRTS\n");
647 #ifdef TIOCM_RTS
648 return COMM_WhackModem(ptr->fd, ~TIOCM_RTS, 0);
649 #endif
651 case SETDTR:
652 TRACE("SETDTR\n");
653 #ifdef TIOCM_DTR
654 return COMM_WhackModem(ptr->fd, 0, TIOCM_DTR);
655 #endif
657 case SETRTS:
658 TRACE("SETRTS\n");
659 #ifdef TIOCM_RTS
660 return COMM_WhackModem(ptr->fd, 0, TIOCM_RTS);
661 #endif
663 case SETXOFF:
664 TRACE("SETXOFF\n");
665 port.c_iflag |= IXOFF;
666 break;
668 case SETXON:
669 TRACE("SETXON\n");
670 port.c_iflag |= IXON;
671 break;
673 default:
674 WARN("(cid=%d,nFunction=%d): Unknown function\n",
675 cid, nFunction);
676 break;
679 if (tcsetattr(ptr->fd, TCSADRAIN, &port) == -1) {
680 ptr->commerror = WinError();
681 return -1;
682 } else {
683 ptr->commerror = 0;
684 return 0;
688 /*****************************************************************************
689 * FlushComm (USER.215)
691 INT16 WINAPI FlushComm16(INT16 cid,INT16 fnQueue)
693 int queue;
694 struct DosDeviceStruct *ptr;
696 TRACE("cid=%d, queue=%d\n", cid, fnQueue);
697 if ((ptr = GetDeviceStruct(cid)) == NULL) {
698 FIXME("no cid=%d found!\n", cid);
699 return -1;
701 switch (fnQueue) {
702 case 0:
703 queue = TCOFLUSH;
704 ptr->obuf_tail = ptr->obuf_head;
705 break;
706 case 1:
707 queue = TCIFLUSH;
708 ptr->ibuf_head = ptr->ibuf_tail;
709 break;
710 default:
711 WARN("(cid=%d,fnQueue=%d):Unknown queue\n",
712 cid, fnQueue);
713 return -1;
715 if (tcflush(ptr->fd, queue)) {
716 ptr->commerror = WinError();
717 return -1;
718 } else {
719 ptr->commerror = 0;
720 return 0;
724 /********************************************************************
725 * GetCommError (USER.203)
727 INT16 WINAPI GetCommError16(INT16 cid,LPCOMSTAT16 lpStat)
729 int temperror;
730 struct DosDeviceStruct *ptr;
731 unsigned char *stol;
732 unsigned int mstat;
734 if ((ptr = GetDeviceStruct(cid)) == NULL) {
735 FIXME("no handle for cid = %0x!.\n",cid);
736 return -1;
738 if (cid&FLAG_LPT) {
739 WARN(" cid %d not comm port\n",cid);
740 return CE_MODE;
742 stol = (unsigned char *)unknown[cid] + COMM_MSR_OFFSET;
743 ioctl(ptr->fd,TIOCMGET,&mstat);
744 if( mstat&TIOCM_CAR )
745 *stol |= 0x80;
746 else
747 *stol &=0x7f;
749 if (lpStat) {
750 lpStat->status = 0;
752 lpStat->cbOutQue = comm_outbuf(ptr);
753 lpStat->cbInQue = comm_inbuf(ptr);
755 TRACE("cid %d, error %d, lpStat %d %d %d stol %x\n",
756 cid, ptr->commerror, lpStat->status, lpStat->cbInQue,
757 lpStat->cbOutQue, *stol);
759 else
760 TRACE("cid %d, error %d, lpStat NULL stol %x\n",
761 cid, ptr->commerror, *stol);
763 /* Return any errors and clear it */
764 temperror = ptr->commerror;
765 ptr->commerror = 0;
766 return(temperror);
769 /*****************************************************************************
770 * SetCommEventMask (USER.208)
772 SEGPTR WINAPI SetCommEventMask16(INT16 cid,UINT16 fuEvtMask)
774 struct DosDeviceStruct *ptr;
775 unsigned char *stol;
776 int repid;
777 unsigned int mstat;
779 TRACE("cid %d,mask %d\n",cid,fuEvtMask);
780 if ((ptr = GetDeviceStruct(cid)) == NULL) {
781 FIXME("no handle for cid = %0x!.\n",cid);
782 return (SEGPTR)NULL;
785 ptr->eventmask = fuEvtMask;
787 if ((cid&FLAG_LPT) || !ValidCOMPort(cid)) {
788 WARN(" cid %d not comm port\n",cid);
789 return (SEGPTR)NULL;
791 /* it's a COM port ? -> modify flags */
792 stol = (unsigned char *)unknown[cid] + COMM_MSR_OFFSET;
793 repid = ioctl(ptr->fd,TIOCMGET,&mstat);
794 TRACE(" ioctl %d, msr %x at %p %p\n",repid,mstat,stol,unknown[cid]);
795 if ((mstat&TIOCM_CAR))
796 *stol |= 0x80;
797 else
798 *stol &=0x7f;
800 TRACE(" modem dcd construct %x\n",*stol);
801 return SEGPTR_GET(unknown[cid]);
804 /*****************************************************************************
805 * GetCommEventMask (USER.209)
807 UINT16 WINAPI GetCommEventMask16(INT16 cid,UINT16 fnEvtClear)
809 struct DosDeviceStruct *ptr;
810 WORD events;
812 TRACE("cid %d, mask %d\n", cid, fnEvtClear);
813 if ((ptr = GetDeviceStruct(cid)) == NULL) {
814 FIXME("no handle for cid = %0x!.\n",cid);
815 return 0;
818 if ((cid&FLAG_LPT) || !ValidCOMPort(cid)) {
819 WARN(" cid %d not comm port\n",cid);
820 return 0;
823 events = *(WORD*)(unknown[cid]) & fnEvtClear;
824 *(WORD*)(unknown[cid]) &= ~fnEvtClear;
825 return events;
828 /*****************************************************************************
829 * SetCommState16 (USER.201)
831 INT16 WINAPI SetCommState16(LPDCB16 lpdcb)
833 struct termios port;
834 struct DosDeviceStruct *ptr;
836 TRACE("cid %d, ptr %p\n", lpdcb->Id, lpdcb);
837 if ((ptr = GetDeviceStruct(lpdcb->Id)) == NULL) {
838 FIXME("no handle for cid = %0x!.\n",lpdcb->Id);
839 return -1;
841 if (tcgetattr(ptr->fd, &port) == -1) {
842 ptr->commerror = WinError();
843 return -1;
846 port.c_cc[VMIN] = 0;
847 port.c_cc[VTIME] = 1;
849 #ifdef IMAXBEL
850 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|IMAXBEL);
851 #else
852 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR);
853 #endif
854 port.c_iflag |= (IGNBRK);
856 port.c_oflag &= ~(OPOST);
858 port.c_cflag &= ~(HUPCL);
859 port.c_cflag |= CLOCAL | CREAD;
861 port.c_lflag &= ~(ICANON|ECHO|ISIG);
862 port.c_lflag |= NOFLSH;
864 TRACE("baudrate %d\n",lpdcb->BaudRate);
865 #ifdef CBAUD
866 port.c_cflag &= ~CBAUD;
867 switch (lpdcb->BaudRate) {
868 case 110:
869 case CBR_110:
870 port.c_cflag |= B110;
871 break;
872 case 300:
873 case CBR_300:
874 port.c_cflag |= B300;
875 break;
876 case 600:
877 case CBR_600:
878 port.c_cflag |= B600;
879 break;
880 case 1200:
881 case CBR_1200:
882 port.c_cflag |= B1200;
883 break;
884 case 2400:
885 case CBR_2400:
886 port.c_cflag |= B2400;
887 break;
888 case 4800:
889 case CBR_4800:
890 port.c_cflag |= B4800;
891 break;
892 case 9600:
893 case CBR_9600:
894 port.c_cflag |= B9600;
895 break;
896 case 19200:
897 case CBR_19200:
898 port.c_cflag |= B19200;
899 break;
900 case 38400:
901 case CBR_38400:
902 port.c_cflag |= B38400;
903 break;
904 #ifdef B57600
905 case 57600:
906 port.c_cflag |= B57600;
907 break;
908 #endif
909 #ifdef B115200
910 case 57601:
911 port.c_cflag |= B115200;
912 break;
913 #endif
914 default:
915 ptr->commerror = IE_BAUDRATE;
916 return -1;
918 #elif !defined(__EMX__)
919 switch (lpdcb->BaudRate) {
920 case 110:
921 case CBR_110:
922 port.c_ospeed = B110;
923 break;
924 case 300:
925 case CBR_300:
926 port.c_ospeed = B300;
927 break;
928 case 600:
929 case CBR_600:
930 port.c_ospeed = B600;
931 break;
932 case 1200:
933 case CBR_1200:
934 port.c_ospeed = B1200;
935 break;
936 case 2400:
937 case CBR_2400:
938 port.c_ospeed = B2400;
939 break;
940 case 4800:
941 case CBR_4800:
942 port.c_ospeed = B4800;
943 break;
944 case 9600:
945 case CBR_9600:
946 port.c_ospeed = B9600;
947 break;
948 case 19200:
949 case CBR_19200:
950 port.c_ospeed = B19200;
951 break;
952 case 38400:
953 case CBR_38400:
954 port.c_ospeed = B38400;
955 break;
956 default:
957 ptr->commerror = IE_BAUDRATE;
958 return -1;
960 port.c_ispeed = port.c_ospeed;
961 #endif
962 TRACE("bytesize %d\n",lpdcb->ByteSize);
963 port.c_cflag &= ~CSIZE;
964 switch (lpdcb->ByteSize) {
965 case 5:
966 port.c_cflag |= CS5;
967 break;
968 case 6:
969 port.c_cflag |= CS6;
970 break;
971 case 7:
972 port.c_cflag |= CS7;
973 break;
974 case 8:
975 port.c_cflag |= CS8;
976 break;
977 default:
978 ptr->commerror = IE_BYTESIZE;
979 return -1;
982 TRACE("fParity %d Parity %d\n",lpdcb->fParity, lpdcb->Parity);
983 port.c_cflag &= ~(PARENB | PARODD);
984 if (lpdcb->fParity)
985 port.c_iflag |= INPCK;
986 else
987 port.c_iflag &= ~INPCK;
988 switch (lpdcb->Parity) {
989 case NOPARITY:
990 break;
991 case ODDPARITY:
992 port.c_cflag |= (PARENB | PARODD);
993 break;
994 case EVENPARITY:
995 port.c_cflag |= PARENB;
996 break;
997 default:
998 ptr->commerror = IE_BYTESIZE;
999 return -1;
1003 TRACE("stopbits %d\n",lpdcb->StopBits);
1005 switch (lpdcb->StopBits) {
1006 case ONESTOPBIT:
1007 port.c_cflag &= ~CSTOPB;
1008 break;
1009 case TWOSTOPBITS:
1010 port.c_cflag |= CSTOPB;
1011 break;
1012 default:
1013 ptr->commerror = IE_BYTESIZE;
1014 return -1;
1016 #ifdef CRTSCTS
1018 if (lpdcb->fDtrflow || lpdcb->fRtsflow || lpdcb->fOutxCtsFlow)
1019 port.c_cflag |= CRTSCTS;
1021 if (lpdcb->fDtrDisable)
1022 port.c_cflag &= ~CRTSCTS;
1023 #endif
1024 if (lpdcb->fInX)
1025 port.c_iflag |= IXON;
1026 else
1027 port.c_iflag &= ~IXON;
1028 if (lpdcb->fOutX)
1029 port.c_iflag |= IXOFF;
1030 else
1031 port.c_iflag &= ~IXOFF;
1033 ptr->evtchar = lpdcb->EvtChar;
1035 if (tcsetattr(ptr->fd, TCSADRAIN, &port) == -1) {
1036 ptr->commerror = WinError();
1037 return FALSE;
1038 } else {
1039 ptr->commerror = 0;
1040 return 0;
1044 /*****************************************************************************
1045 * GetCommState (USER.202)
1047 INT16 WINAPI GetCommState16(INT16 cid, LPDCB16 lpdcb)
1049 int speed;
1050 struct DosDeviceStruct *ptr;
1051 struct termios port;
1053 TRACE("cid %d, ptr %p\n", cid, lpdcb);
1054 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1055 FIXME("no handle for cid = %0x!.\n",cid);
1056 return -1;
1058 if (tcgetattr(ptr->fd, &port) == -1) {
1059 ptr->commerror = WinError();
1060 return -1;
1062 lpdcb->Id = cid;
1063 #ifndef __EMX__
1064 #ifdef CBAUD
1065 speed = port.c_cflag & CBAUD;
1066 #else
1067 speed = port.c_ospeed;
1068 #endif
1069 switch(speed) {
1070 case B110:
1071 lpdcb->BaudRate = 110;
1072 break;
1073 case B300:
1074 lpdcb->BaudRate = 300;
1075 break;
1076 case B600:
1077 lpdcb->BaudRate = 600;
1078 break;
1079 case B1200:
1080 lpdcb->BaudRate = 1200;
1081 break;
1082 case B2400:
1083 lpdcb->BaudRate = 2400;
1084 break;
1085 case B4800:
1086 lpdcb->BaudRate = 4800;
1087 break;
1088 case B9600:
1089 lpdcb->BaudRate = 9600;
1090 break;
1091 case B19200:
1092 lpdcb->BaudRate = 19200;
1093 break;
1094 case B38400:
1095 lpdcb->BaudRate = 38400;
1096 break;
1097 #ifdef B57600
1098 case B57600:
1099 lpdcb->BaudRate = 57600;
1100 break;
1101 #endif
1102 #ifdef B115200
1103 case B115200:
1104 lpdcb->BaudRate = 57601;
1105 break;
1106 #endif
1108 #endif
1109 switch (port.c_cflag & CSIZE) {
1110 case CS5:
1111 lpdcb->ByteSize = 5;
1112 break;
1113 case CS6:
1114 lpdcb->ByteSize = 6;
1115 break;
1116 case CS7:
1117 lpdcb->ByteSize = 7;
1118 break;
1119 case CS8:
1120 lpdcb->ByteSize = 8;
1121 break;
1124 if(port.c_iflag & INPCK)
1125 lpdcb->fParity = TRUE;
1126 else
1127 lpdcb->fParity = FALSE;
1128 switch (port.c_cflag & (PARENB | PARODD)) {
1129 case 0:
1130 lpdcb->Parity = NOPARITY;
1131 break;
1132 case PARENB:
1133 lpdcb->Parity = EVENPARITY;
1134 break;
1135 case (PARENB | PARODD):
1136 lpdcb->Parity = ODDPARITY;
1137 break;
1140 if (port.c_cflag & CSTOPB)
1141 lpdcb->StopBits = TWOSTOPBITS;
1142 else
1143 lpdcb->StopBits = ONESTOPBIT;
1145 lpdcb->RlsTimeout = 50;
1146 lpdcb->CtsTimeout = 50;
1147 lpdcb->DsrTimeout = 50;
1148 lpdcb->fNull = 0;
1149 lpdcb->fChEvt = 0;
1150 lpdcb->fBinary = 1;
1151 lpdcb->fDtrDisable = 0;
1153 #ifdef CRTSCTS
1155 if (port.c_cflag & CRTSCTS) {
1156 lpdcb->fDtrflow = 1;
1157 lpdcb->fRtsflow = 1;
1158 lpdcb->fOutxCtsFlow = 1;
1159 lpdcb->fOutxDsrFlow = 1;
1160 } else
1161 #endif
1162 lpdcb->fDtrDisable = 1;
1164 if (port.c_iflag & IXON)
1165 lpdcb->fInX = 1;
1166 else
1167 lpdcb->fInX = 0;
1169 if (port.c_iflag & IXOFF)
1170 lpdcb->fOutX = 1;
1171 else
1172 lpdcb->fOutX = 0;
1174 lpdcb->XonChar =
1175 lpdcb->XoffChar =
1177 lpdcb->XonLim = 10;
1178 lpdcb->XoffLim = 10;
1180 lpdcb->EvtChar = ptr->evtchar;
1182 ptr->commerror = 0;
1183 return 0;
1186 /*****************************************************************************
1187 * TransmitCommChar (USER.206)
1189 INT16 WINAPI TransmitCommChar16(INT16 cid,CHAR chTransmit)
1191 struct DosDeviceStruct *ptr;
1193 TRACE("cid %d, data %d \n", cid, chTransmit);
1194 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1195 FIXME("no handle for cid = %0x!.\n",cid);
1196 return -1;
1199 if (ptr->suspended) {
1200 ptr->commerror = IE_HARDWARE;
1201 return -1;
1204 if (ptr->xmit >= 0) {
1205 /* character already queued */
1206 /* FIXME: which error would Windows return? */
1207 ptr->commerror = CE_TXFULL;
1208 return -1;
1211 if (ptr->obuf_head == ptr->obuf_tail) {
1212 /* transmit queue empty, try to transmit directly */
1213 if (write(ptr->fd, &chTransmit, 1) == -1) {
1214 /* didn't work, queue it */
1215 ptr->xmit = chTransmit;
1216 comm_waitwrite(ptr);
1218 } else {
1219 /* data in queue, let this char be transmitted next */
1220 ptr->xmit = chTransmit;
1221 comm_waitwrite(ptr);
1224 ptr->commerror = 0;
1225 return 0;
1228 /*****************************************************************************
1229 * UngetCommChar (USER.212)
1231 INT16 WINAPI UngetCommChar16(INT16 cid,CHAR chUnget)
1233 struct DosDeviceStruct *ptr;
1235 TRACE("cid %d (char %d)\n", cid, chUnget);
1236 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1237 FIXME("no handle for cid = %0x!.\n",cid);
1238 return -1;
1241 if (ptr->suspended) {
1242 ptr->commerror = IE_HARDWARE;
1243 return -1;
1246 if (ptr->unget>=0) {
1247 /* character already queued */
1248 /* FIXME: which error would Windows return? */
1249 ptr->commerror = CE_RXOVER;
1250 return -1;
1253 ptr->unget = chUnget;
1255 ptr->commerror = 0;
1256 return 0;
1259 /*****************************************************************************
1260 * ReadComm (USER.204)
1262 INT16 WINAPI ReadComm16(INT16 cid,LPSTR lpvBuf,INT16 cbRead)
1264 int status, length;
1265 struct DosDeviceStruct *ptr;
1266 LPSTR orgBuf = lpvBuf;
1268 TRACE("cid %d, ptr %p, length %d\n", cid, lpvBuf, cbRead);
1269 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1270 FIXME("no handle for cid = %0x!.\n",cid);
1271 return -1;
1274 if (ptr->suspended) {
1275 ptr->commerror = IE_HARDWARE;
1276 return -1;
1279 /* read unget character */
1280 if (ptr->unget>=0) {
1281 *lpvBuf++ = ptr->unget;
1282 ptr->unget = -1;
1284 length = 1;
1285 } else
1286 length = 0;
1288 /* read from receive buffer */
1289 while (length < cbRead) {
1290 status = ((ptr->ibuf_head < ptr->ibuf_tail) ?
1291 ptr->ibuf_size : ptr->ibuf_head) - ptr->ibuf_tail;
1292 if (!status) break;
1293 if ((cbRead - length) < status)
1294 status = cbRead - length;
1296 memcpy(lpvBuf, ptr->inbuf + ptr->ibuf_tail, status);
1297 ptr->ibuf_tail += status;
1298 if (ptr->ibuf_tail >= ptr->ibuf_size)
1299 ptr->ibuf_tail = 0;
1300 lpvBuf += status;
1301 length += status;
1304 TRACE("%.*s\n", length, orgBuf);
1305 ptr->commerror = 0;
1306 return length;
1309 /*****************************************************************************
1310 * WriteComm (USER.205)
1312 INT16 WINAPI WriteComm16(INT16 cid, LPSTR lpvBuf, INT16 cbWrite)
1314 int status, length;
1315 struct DosDeviceStruct *ptr;
1317 TRACE("cid %d, ptr %p, length %d\n",
1318 cid, lpvBuf, cbWrite);
1319 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1320 FIXME("no handle for cid = %0x!.\n",cid);
1321 return -1;
1324 if (ptr->suspended) {
1325 ptr->commerror = IE_HARDWARE;
1326 return -1;
1329 TRACE("%.*s\n", cbWrite, lpvBuf );
1331 length = 0;
1332 while (length < cbWrite) {
1333 if ((ptr->obuf_head == ptr->obuf_tail) && (ptr->xmit < 0)) {
1334 /* no data queued, try to write directly */
1335 status = write(ptr->fd, lpvBuf, cbWrite - length);
1336 if (status > 0) {
1337 lpvBuf += status;
1338 length += status;
1339 continue;
1342 /* can't write directly, put into transmit buffer */
1343 status = ((ptr->obuf_tail > ptr->obuf_head) ?
1344 (ptr->obuf_tail-1) : ptr->obuf_size) - ptr->obuf_head;
1345 if (!status) break;
1346 if ((cbWrite - length) < status)
1347 status = cbWrite - length;
1348 memcpy(lpvBuf, ptr->outbuf + ptr->obuf_head, status);
1349 ptr->obuf_head += status;
1350 if (ptr->obuf_head >= ptr->obuf_size)
1351 ptr->obuf_head = 0;
1352 lpvBuf += status;
1353 length += status;
1354 comm_waitwrite(ptr);
1357 ptr->commerror = 0;
1358 return length;
1361 /***********************************************************************
1362 * EnableCommNotification (USER.246)
1364 BOOL16 WINAPI EnableCommNotification16( INT16 cid, HWND16 hwnd,
1365 INT16 cbWriteNotify, INT16 cbOutQueue )
1367 struct DosDeviceStruct *ptr;
1369 TRACE("(%d, %x, %d, %d)\n", cid, hwnd, cbWriteNotify, cbOutQueue);
1370 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1371 FIXME("no handle for cid = %0x!.\n",cid);
1372 ptr->commerror = IE_BADID;
1373 return -1;
1375 ptr->wnd = hwnd;
1376 ptr->n_read = cbWriteNotify;
1377 ptr->n_write = cbOutQueue;
1378 return TRUE;
1382 /**************************************************************************
1383 * BuildCommDCBA (KERNEL32.14)
1385 BOOL WINAPI BuildCommDCBA(LPCSTR device,LPDCB lpdcb)
1387 return BuildCommDCBAndTimeoutsA(device,lpdcb,NULL);
1390 /**************************************************************************
1391 * BuildCommDCBAndTimeoutsA (KERNEL32.15)
1393 BOOL WINAPI BuildCommDCBAndTimeoutsA(LPCSTR device, LPDCB lpdcb,
1394 LPCOMMTIMEOUTS lptimeouts)
1396 int port;
1397 char *ptr,*temp;
1399 TRACE("(%s,%p,%p)\n",device,lpdcb,lptimeouts);
1401 if (!lstrncmpiA(device,"COM",3)) {
1402 port=device[3]-'0';
1403 if (port--==0) {
1404 ERR("BUG! COM0 can't exists!.\n");
1405 return FALSE;
1407 if (!ValidCOMPort(port))
1408 return FALSE;
1409 if (*(device+4)!=':')
1410 return FALSE;
1411 temp=(LPSTR)(device+5);
1412 } else
1413 temp=(LPSTR)device;
1415 memset(lpdcb, 0, sizeof(DCB)); /* initialize */
1417 lpdcb->DCBlength = sizeof(DCB);
1418 if (strchr(temp,',')) { /* old style */
1419 DCB16 dcb16;
1420 BOOL16 ret;
1421 char last=temp[strlen(temp)-1];
1423 ret=BuildCommDCB16(device,&dcb16);
1424 if (!ret)
1425 return FALSE;
1426 lpdcb->BaudRate = dcb16.BaudRate;
1427 lpdcb->ByteSize = dcb16.ByteSize;
1428 lpdcb->fBinary = dcb16.fBinary;
1429 lpdcb->Parity = dcb16.Parity;
1430 lpdcb->fParity = dcb16.fParity;
1431 lpdcb->fNull = dcb16.fNull;
1432 lpdcb->StopBits = dcb16.StopBits;
1433 if (last == 'x') {
1434 lpdcb->fInX = TRUE;
1435 lpdcb->fOutX = TRUE;
1436 lpdcb->fOutxCtsFlow = FALSE;
1437 lpdcb->fOutxDsrFlow = FALSE;
1438 lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
1439 lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
1440 } else if (last=='p') {
1441 lpdcb->fInX = FALSE;
1442 lpdcb->fOutX = FALSE;
1443 lpdcb->fOutxCtsFlow = TRUE;
1444 lpdcb->fOutxDsrFlow = TRUE;
1445 lpdcb->fDtrControl = DTR_CONTROL_HANDSHAKE;
1446 lpdcb->fRtsControl = RTS_CONTROL_HANDSHAKE;
1447 } else {
1448 lpdcb->fInX = FALSE;
1449 lpdcb->fOutX = FALSE;
1450 lpdcb->fOutxCtsFlow = FALSE;
1451 lpdcb->fOutxDsrFlow = FALSE;
1452 lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
1453 lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
1455 lpdcb->XonChar = dcb16.XonChar;
1456 lpdcb->XoffChar = dcb16.XoffChar;
1457 lpdcb->ErrorChar= dcb16.PeChar;
1458 lpdcb->fErrorChar= dcb16.fPeChar;
1459 lpdcb->EofChar = dcb16.EofChar;
1460 lpdcb->EvtChar = dcb16.EvtChar;
1461 lpdcb->XonLim = dcb16.XonLim;
1462 lpdcb->XoffLim = dcb16.XoffLim;
1463 return TRUE;
1465 ptr=strtok(temp," ");
1466 while (ptr) {
1467 DWORD flag,x;
1469 flag=0;
1470 if (!strncmp("baud=",ptr,5)) {
1471 if (!sscanf(ptr+5,"%ld",&x))
1472 WARN("Couldn't parse %s\n",ptr);
1473 lpdcb->BaudRate = x;
1474 flag=1;
1476 if (!strncmp("stop=",ptr,5)) {
1477 if (!sscanf(ptr+5,"%ld",&x))
1478 WARN("Couldn't parse %s\n",ptr);
1479 lpdcb->StopBits = x;
1480 flag=1;
1482 if (!strncmp("data=",ptr,5)) {
1483 if (!sscanf(ptr+5,"%ld",&x))
1484 WARN("Couldn't parse %s\n",ptr);
1485 lpdcb->ByteSize = x;
1486 flag=1;
1488 if (!strncmp("parity=",ptr,7)) {
1489 lpdcb->fParity = TRUE;
1490 switch (ptr[8]) {
1491 case 'N':case 'n':
1492 lpdcb->fParity = FALSE;
1493 lpdcb->Parity = NOPARITY;
1494 break;
1495 case 'E':case 'e':
1496 lpdcb->Parity = EVENPARITY;
1497 break;
1498 case 'O':case 'o':
1499 lpdcb->Parity = ODDPARITY;
1500 break;
1501 case 'M':case 'm':
1502 lpdcb->Parity = MARKPARITY;
1503 break;
1505 flag=1;
1507 if (!flag)
1508 ERR("Unhandled specifier '%s', please report.\n",ptr);
1509 ptr=strtok(NULL," ");
1511 if (lpdcb->BaudRate==110)
1512 lpdcb->StopBits = 2;
1513 return TRUE;
1516 /**************************************************************************
1517 * BuildCommDCBAndTimeoutsW (KERNEL32.16)
1519 BOOL WINAPI BuildCommDCBAndTimeoutsW( LPCWSTR devid, LPDCB lpdcb,
1520 LPCOMMTIMEOUTS lptimeouts )
1522 LPSTR devidA;
1523 BOOL ret;
1525 TRACE("(%p,%p,%p)\n",devid,lpdcb,lptimeouts);
1526 devidA = HEAP_strdupWtoA( GetProcessHeap(), 0, devid );
1527 ret=BuildCommDCBAndTimeoutsA(devidA,lpdcb,lptimeouts);
1528 HeapFree( GetProcessHeap(), 0, devidA );
1529 return ret;
1532 /**************************************************************************
1533 * BuildCommDCBW (KERNEL32.17)
1535 BOOL WINAPI BuildCommDCBW(LPCWSTR devid,LPDCB lpdcb)
1537 return BuildCommDCBAndTimeoutsW(devid,lpdcb,NULL);
1540 /*****************************************************************************
1541 * COMM_GetReadFd
1542 * Returns a file descriptor for reading.
1543 * Make sure to close the handle afterwards!
1545 static int COMM_GetReadFd( HANDLE handle)
1547 int fd;
1548 struct get_read_fd_request *req = get_req_buffer();
1549 req->handle = handle;
1550 server_call_fd( REQ_GET_READ_FD, -1, &fd );
1551 return fd;
1554 /*****************************************************************************
1555 * COMM_GetWriteFd
1556 * Returns a file descriptor for writing.
1557 * Make sure to close the handle afterwards!
1559 static int COMM_GetWriteFd( HANDLE handle)
1561 int fd = -1;
1562 struct get_write_fd_request *req = get_req_buffer();
1563 req->handle = handle;
1564 server_call_fd( REQ_GET_WRITE_FD, -1, &fd );
1565 return fd;
1568 /* FIXME: having these global for win32 for now */
1569 int commerror=0,eventmask=0;
1571 /*****************************************************************************
1572 * SetCommBreak (KERNEL32.449)
1574 BOOL WINAPI SetCommBreak(HANDLE handle)
1576 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1577 int fd,result;
1579 fd = COMM_GetWriteFd(handle);
1580 if(fd<0) {
1581 TRACE("COMM_GetWriteFd failed\n");
1582 return FALSE;
1584 result = ioctl(fd,TIOCSBRK,0);
1585 close(fd);
1586 if (result ==-1)
1588 TRACE("ioctl failed\n");
1589 SetLastError(ERROR_NOT_SUPPORTED);
1590 return FALSE;
1592 return TRUE;
1593 #else
1594 FIXME("ioctl not available\n");
1595 SetLastError(ERROR_NOT_SUPPORTED);
1596 return FALSE;
1597 #endif
1600 /*****************************************************************************
1601 * ClearCommBreak (KERNEL32.20)
1603 BOOL WINAPI ClearCommBreak(HANDLE handle)
1605 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1606 int fd,result;
1608 fd = COMM_GetWriteFd(handle);
1609 if(fd<0) {
1610 TRACE("COMM_GetWriteFd failed\n");
1611 return FALSE;
1613 result = ioctl(fd,TIOCCBRK,0);
1614 close(fd);
1615 if (result ==-1)
1617 TRACE("ioctl failed\n");
1618 SetLastError(ERROR_NOT_SUPPORTED);
1619 return FALSE;
1621 return TRUE;
1622 #else
1623 FIXME("ioctl not available\n");
1624 SetLastError(ERROR_NOT_SUPPORTED);
1625 return FALSE;
1626 #endif
1629 /*****************************************************************************
1630 * EscapeCommFunction (KERNEL32.214)
1632 BOOL WINAPI EscapeCommFunction(HANDLE handle,UINT nFunction)
1634 int fd,direct=FALSE,result=FALSE;
1635 struct termios port;
1637 TRACE("handle %d, function=%d\n", handle, nFunction);
1638 fd = COMM_GetWriteFd(handle);
1639 if(fd<0) {
1640 FIXME("handle %d not found.\n",handle);
1641 return FALSE;
1644 if (tcgetattr(fd,&port) == -1) {
1645 commerror=WinError();
1646 close(fd);
1647 return FALSE;
1650 switch (nFunction) {
1651 case RESETDEV:
1652 TRACE("\n");
1653 break;
1655 case CLRDTR:
1656 TRACE("CLRDTR\n");
1657 #ifdef TIOCM_DTR
1658 direct=TRUE;
1659 result= COMM_WhackModem(fd, ~TIOCM_DTR, 0);
1660 break;
1661 #endif
1663 case CLRRTS:
1664 TRACE("CLRRTS\n");
1665 #ifdef TIOCM_RTS
1666 direct=TRUE;
1667 result= COMM_WhackModem(fd, ~TIOCM_RTS, 0);
1668 break;
1669 #endif
1671 case SETDTR:
1672 TRACE("SETDTR\n");
1673 #ifdef TIOCM_DTR
1674 direct=TRUE;
1675 result= COMM_WhackModem(fd, 0, TIOCM_DTR);
1676 break;
1677 #endif
1679 case SETRTS:
1680 TRACE("SETRTS\n");
1681 #ifdef TIOCM_DTR
1682 direct=TRUE;
1683 result= COMM_WhackModem(fd, 0, TIOCM_RTS);
1684 break;
1685 #endif
1687 case SETXOFF:
1688 TRACE("SETXOFF\n");
1689 port.c_iflag |= IXOFF;
1690 break;
1692 case SETXON:
1693 TRACE("SETXON\n");
1694 port.c_iflag |= IXON;
1695 break;
1696 case SETBREAK:
1697 TRACE("setbreak\n");
1698 #ifdef TIOCSBRK
1699 direct=TRUE;
1700 result = ioctl(fd,TIOCSBRK,0);
1701 break;
1702 #endif
1703 case CLRBREAK:
1704 TRACE("clrbreak\n");
1705 #ifdef TIOCSBRK
1706 direct=TRUE;
1707 result = ioctl(fd,TIOCCBRK,0);
1708 break;
1709 #endif
1710 default:
1711 WARN("(handle=%d,nFunction=%d): Unknown function\n",
1712 handle, nFunction);
1713 break;
1716 if (!direct)
1717 if (tcsetattr(fd, TCSADRAIN, &port) == -1) {
1718 commerror = WinError();
1719 close(fd);
1720 return FALSE;
1721 } else
1722 result= TRUE;
1723 else
1725 if (result == -1)
1727 result= FALSE;
1728 commerror=WinError();
1730 else
1731 result = TRUE;
1733 close(fd);
1734 return result;
1737 /********************************************************************
1738 * PurgeComm (KERNEL32.557)
1740 BOOL WINAPI PurgeComm( HANDLE handle, DWORD flags)
1742 int fd;
1744 TRACE("handle %d, flags %lx\n", handle, flags);
1746 fd = COMM_GetWriteFd(handle);
1747 if(fd<0) {
1748 FIXME("no handle %d found\n",handle);
1749 return FALSE;
1753 ** not exactly sure how these are different
1754 ** Perhaps if we had our own internal queues, one flushes them
1755 ** and the other flushes the kernel's buffers.
1757 if(flags&PURGE_TXABORT)
1758 tcflush(fd,TCOFLUSH);
1759 if(flags&PURGE_RXABORT)
1760 tcflush(fd,TCIFLUSH);
1761 if(flags&PURGE_TXCLEAR)
1762 tcflush(fd,TCOFLUSH);
1763 if(flags&PURGE_RXCLEAR)
1764 tcflush(fd,TCIFLUSH);
1765 close(fd);
1767 return 1;
1770 /*****************************************************************************
1771 * ClearCommError (KERNEL32.21)
1773 BOOL WINAPI ClearCommError(INT handle,LPDWORD errors,LPCOMSTAT lpStat)
1775 int fd;
1777 fd=COMM_GetReadFd(handle);
1778 if(0>fd)
1780 FIXME("no handle %d found\n",handle);
1781 return FALSE;
1784 if (lpStat)
1786 lpStat->status = 0;
1788 #ifdef TIOCOUTQ
1789 if(ioctl(fd, TIOCOUTQ, &lpStat->cbOutQue))
1790 WARN("ioctl returned error\n");
1791 #else
1792 lpStat->cbOutQue = 0; /* FIXME: find a different way to find out */
1793 #endif
1795 if(ioctl(fd, TIOCINQ, &lpStat->cbInQue))
1796 WARN("ioctl returned error\n");
1798 TRACE("handle %d cbInQue = %ld cbOutQue = %ld\n",
1799 handle, lpStat->cbInQue, lpStat->cbOutQue);
1802 close(fd);
1804 if(errors)
1805 *errors = 0;
1808 ** After an asynchronous write opperation, the
1809 ** app will call ClearCommError to see if the
1810 ** results are ready yet. It waits for ERROR_IO_PENDING
1812 commerror = ERROR_IO_PENDING;
1814 return TRUE;
1817 /*****************************************************************************
1818 * SetupComm (KERNEL32.676)
1820 BOOL WINAPI SetupComm( HANDLE handle, DWORD insize, DWORD outsize)
1822 int fd;
1824 FIXME("insize %ld outsize %ld unimplemented stub\n", insize, outsize);
1825 fd=COMM_GetWriteFd(handle);
1826 if(0>fd) {
1827 FIXME("handle %d not found?\n",handle);
1828 return FALSE;
1830 close(fd);
1831 return TRUE;
1834 /*****************************************************************************
1835 * GetCommMask (KERNEL32.156)
1837 BOOL WINAPI GetCommMask(HANDLE handle,LPDWORD evtmask)
1839 int fd;
1841 TRACE("handle %d, mask %p\n", handle, evtmask);
1842 if(0>(fd=COMM_GetReadFd(handle)))
1844 FIXME("no handle %d found\n",handle);
1845 return FALSE;
1847 close(fd);
1848 *evtmask = eventmask;
1849 TRACE("%s%s%s%s%s%s%s%s%s\n",
1850 (eventmask&EV_BREAK)?"EV_BREAK":"",
1851 (eventmask&EV_CTS)?"EV_CTS":"",
1852 (eventmask&EV_DSR)?"EV_DSR":"",
1853 (eventmask&EV_ERR)?"EV_ERR":"",
1854 (eventmask&EV_RING)?"EV_RING":"",
1855 (eventmask&EV_RLSD)?"EV_RLSD":"",
1856 (eventmask&EV_RXCHAR)?"EV_RXCHAR":"",
1857 (eventmask&EV_RXFLAG)?"EV_RXFLAG":"",
1858 (eventmask&EV_TXEMPTY)?"EV_TXEMPTY":"");
1860 return TRUE;
1863 /*****************************************************************************
1864 * SetCommMask (KERNEL32.451)
1866 BOOL WINAPI SetCommMask(INT handle,DWORD evtmask)
1868 int fd;
1870 TRACE("handle %d, mask %lx\n", handle, evtmask);
1871 TRACE("%s%s%s%s%s%s%s%s%s\n",
1872 (evtmask&EV_BREAK)?"EV_BREAK":"",
1873 (evtmask&EV_CTS)?"EV_CTS":"",
1874 (evtmask&EV_DSR)?"EV_DSR":"",
1875 (evtmask&EV_ERR)?"EV_ERR":"",
1876 (evtmask&EV_RING)?"EV_RING":"",
1877 (evtmask&EV_RLSD)?"EV_RLSD":"",
1878 (evtmask&EV_RXCHAR)?"EV_RXCHAR":"",
1879 (evtmask&EV_RXFLAG)?"EV_RXFLAG":"",
1880 (evtmask&EV_TXEMPTY)?"EV_TXEMPTY":"");
1882 if(0>(fd=COMM_GetWriteFd(handle))) {
1883 FIXME("no handle %d found\n",handle);
1884 return FALSE;
1886 close(fd);
1887 eventmask = evtmask;
1888 return TRUE;
1891 /*****************************************************************************
1892 * SetCommState (KERNEL32.452)
1894 BOOL WINAPI SetCommState(INT handle,LPDCB lpdcb)
1896 struct termios port;
1897 int fd;
1899 TRACE("handle %d, ptr %p\n", handle, lpdcb);
1900 TRACE("bytesize %d baudrate %ld fParity %d Parity %d stopbits %d\n",
1901 lpdcb->ByteSize,lpdcb->BaudRate,lpdcb->fParity, lpdcb->Parity,
1902 (lpdcb->StopBits == ONESTOPBIT)?1:
1903 (lpdcb->StopBits == TWOSTOPBITS)?2:0);
1904 TRACE("%s %s\n",(lpdcb->fInX)?"IXON":"~IXON",
1905 (lpdcb->fOutX)?"IXOFF":"~IXOFF");
1907 if ((fd = COMM_GetWriteFd(handle)) < 0) {
1908 FIXME("no handle %d found\n",handle);
1909 return FALSE;
1912 if ((tcgetattr(fd,&port)) == -1) {
1913 int save_error = errno;
1914 commerror = WinError();
1915 close( fd );
1916 #ifdef HAVE_STRERROR
1917 ERR("tcgetattr error '%s'\n", strerror(save_error));
1918 #else
1919 ERR("tcgetattr error %d\n", save_error);
1920 #endif
1921 return FALSE;
1924 port.c_cc[VMIN] = 0;
1925 port.c_cc[VTIME] = 1;
1927 #ifdef IMAXBEL
1928 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|IMAXBEL);
1929 #else
1930 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR);
1931 #endif
1932 port.c_iflag |= (IGNBRK);
1934 port.c_oflag &= ~(OPOST);
1936 port.c_cflag &= ~(HUPCL);
1937 port.c_cflag |= CLOCAL | CREAD;
1939 port.c_lflag &= ~(ICANON|ECHO|ISIG);
1940 port.c_lflag |= NOFLSH;
1943 ** MJM - removed default baudrate settings
1944 ** TRACE(comm,"baudrate %ld\n",lpdcb->BaudRate);
1946 #ifdef CBAUD
1947 port.c_cflag &= ~CBAUD;
1948 switch (lpdcb->BaudRate) {
1949 case 110:
1950 case CBR_110:
1951 port.c_cflag |= B110;
1952 break;
1953 case 300:
1954 case CBR_300:
1955 port.c_cflag |= B300;
1956 break;
1957 case 600:
1958 case CBR_600:
1959 port.c_cflag |= B600;
1960 break;
1961 case 1200:
1962 case CBR_1200:
1963 port.c_cflag |= B1200;
1964 break;
1965 case 2400:
1966 case CBR_2400:
1967 port.c_cflag |= B2400;
1968 break;
1969 case 4800:
1970 case CBR_4800:
1971 port.c_cflag |= B4800;
1972 break;
1973 case 9600:
1974 case CBR_9600:
1975 port.c_cflag |= B9600;
1976 break;
1977 case 19200:
1978 case CBR_19200:
1979 port.c_cflag |= B19200;
1980 break;
1981 case 38400:
1982 case CBR_38400:
1983 port.c_cflag |= B38400;
1984 break;
1985 #ifdef B57600
1986 case 57600:
1987 port.c_cflag |= B57600;
1988 break;
1989 #endif
1990 #ifdef B115200
1991 case 115200:
1992 port.c_cflag |= B115200;
1993 break;
1994 #endif
1995 #ifdef B230400
1996 case 230400:
1997 port.c_cflag |= B230400;
1998 break;
1999 #endif
2000 #ifdef B460800
2001 case 460600:
2002 port.c_cflag |= B460800;
2003 break;
2004 #endif
2005 default:
2006 commerror = IE_BAUDRATE;
2007 close( fd );
2008 ERR("baudrate %ld\n",lpdcb->BaudRate);
2009 return FALSE;
2011 #elif !defined(__EMX__)
2012 switch (lpdcb->BaudRate) {
2013 case 110:
2014 case CBR_110:
2015 port.c_ospeed = B110;
2016 break;
2017 case 300:
2018 case CBR_300:
2019 port.c_ospeed = B300;
2020 break;
2021 case 600:
2022 case CBR_600:
2023 port.c_ospeed = B600;
2024 break;
2025 case 1200:
2026 case CBR_1200:
2027 port.c_ospeed = B1200;
2028 break;
2029 case 2400:
2030 case CBR_2400:
2031 port.c_ospeed = B2400;
2032 break;
2033 case 4800:
2034 case CBR_4800:
2035 port.c_ospeed = B4800;
2036 break;
2037 case 9600:
2038 case CBR_9600:
2039 port.c_ospeed = B9600;
2040 break;
2041 case 19200:
2042 case CBR_19200:
2043 port.c_ospeed = B19200;
2044 break;
2045 case 38400:
2046 case CBR_38400:
2047 port.c_ospeed = B38400;
2048 break;
2049 default:
2050 commerror = IE_BAUDRATE;
2051 close( fd );
2052 ERR("baudrate %d \n",lpdcb->BaudRate);
2053 return FALSE;
2055 port.c_ispeed = port.c_ospeed;
2056 #endif
2057 port.c_cflag &= ~CSIZE;
2058 switch (lpdcb->ByteSize) {
2059 case 5:
2060 port.c_cflag |= CS5;
2061 break;
2062 case 6:
2063 port.c_cflag |= CS6;
2064 break;
2065 case 7:
2066 port.c_cflag |= CS7;
2067 break;
2068 case 8:
2069 port.c_cflag |= CS8;
2070 break;
2071 default:
2072 commerror = IE_BYTESIZE;
2073 close( fd );
2074 ERR("ByteSize\n");
2075 return FALSE;
2078 port.c_cflag &= ~(PARENB | PARODD);
2079 if (lpdcb->fParity)
2080 port.c_iflag |= INPCK;
2081 else
2082 port.c_iflag &= ~INPCK;
2083 switch (lpdcb->Parity) {
2084 case NOPARITY:
2085 break;
2086 case ODDPARITY:
2087 port.c_cflag |= (PARENB | PARODD);
2088 break;
2089 case EVENPARITY:
2090 port.c_cflag |= PARENB;
2091 break;
2092 default:
2093 commerror = IE_BYTESIZE;
2094 close( fd );
2095 ERR("Parity\n");
2096 return FALSE;
2100 switch (lpdcb->StopBits) {
2101 case ONESTOPBIT:
2102 port.c_cflag &= ~CSTOPB;
2103 break;
2104 case TWOSTOPBITS:
2105 port.c_cflag |= CSTOPB;
2106 break;
2107 default:
2108 commerror = IE_BYTESIZE;
2109 close( fd );
2110 ERR("StopBits\n");
2111 return FALSE;
2113 #ifdef CRTSCTS
2114 if ( lpdcb->fOutxCtsFlow ||
2115 lpdcb->fDtrControl == DTR_CONTROL_ENABLE||
2116 lpdcb->fRtsControl == RTS_CONTROL_ENABLE
2119 port.c_cflag |= CRTSCTS;
2120 TRACE("CRTSCTS\n");
2123 if (lpdcb->fDtrControl == DTR_CONTROL_DISABLE)
2125 port.c_cflag &= ~CRTSCTS;
2126 TRACE("~CRTSCTS\n");
2129 #endif
2130 if (lpdcb->fInX)
2131 port.c_iflag |= IXON;
2132 else
2133 port.c_iflag &= ~IXON;
2134 if (lpdcb->fOutX)
2135 port.c_iflag |= IXOFF;
2136 else
2137 port.c_iflag &= ~IXOFF;
2139 if (tcsetattr(fd,TCSANOW,&port)==-1) { /* otherwise it hangs with pending input*/
2140 int save_error=errno;
2141 commerror = WinError();
2142 close( fd );
2143 #ifdef HAVE_STRERROR
2144 ERR("tcgetattr error '%s'\n", strerror(save_error));
2145 #else
2146 ERR("tcgetattr error %d\n", save_error);
2147 #endif
2148 return FALSE;
2149 } else {
2150 commerror = 0;
2151 close( fd );
2152 return TRUE;
2157 /*****************************************************************************
2158 * GetCommState (KERNEL32.159)
2160 BOOL WINAPI GetCommState(INT handle, LPDCB lpdcb)
2162 struct termios port;
2163 int fd,speed;
2165 TRACE("handle %d, ptr %p\n", handle, lpdcb);
2167 if ((fd = COMM_GetReadFd(handle)) < 0)
2169 ERR("can't get COMM_GetReadFd\n");
2170 return FALSE;
2172 if (tcgetattr(fd, &port) == -1) {
2173 int save_error=errno;
2174 #ifdef HAVE_STRERROR
2175 ERR("tcgetattr error '%s'\n", strerror(save_error));
2176 #else
2177 ERR("tcgetattr error %d\n", save_error);
2178 #endif
2179 commerror = WinError();
2180 close( fd );
2181 return FALSE;
2183 close( fd );
2184 #ifndef __EMX__
2185 #ifdef CBAUD
2186 speed= (port.c_cflag & CBAUD);
2187 #else
2188 speed= (cfgetospeed(&port));
2189 #endif
2190 switch (speed) {
2191 case B110:
2192 lpdcb->BaudRate = 110;
2193 break;
2194 case B300:
2195 lpdcb->BaudRate = 300;
2196 break;
2197 case B600:
2198 lpdcb->BaudRate = 600;
2199 break;
2200 case B1200:
2201 lpdcb->BaudRate = 1200;
2202 break;
2203 case B2400:
2204 lpdcb->BaudRate = 2400;
2205 break;
2206 case B4800:
2207 lpdcb->BaudRate = 4800;
2208 break;
2209 case B9600:
2210 lpdcb->BaudRate = 9600;
2211 break;
2212 case B19200:
2213 lpdcb->BaudRate = 19200;
2214 break;
2215 case B38400:
2216 lpdcb->BaudRate = 38400;
2217 break;
2218 #ifdef B57600
2219 case B57600:
2220 lpdcb->BaudRate = 57600;
2221 break;
2222 #endif
2223 #ifdef B115200
2224 case B115200:
2225 lpdcb->BaudRate = 115200;
2226 break;
2227 #endif
2228 #ifdef B230400
2229 case B230400:
2230 lpdcb->BaudRate = 230400;
2231 break;
2232 #endif
2233 #ifdef B460800
2234 case B460800:
2235 lpdcb->BaudRate = 460800;
2236 break;
2237 #endif
2238 default:
2239 ERR("unknown speed %x \n",speed);
2241 #endif
2242 switch (port.c_cflag & CSIZE) {
2243 case CS5:
2244 lpdcb->ByteSize = 5;
2245 break;
2246 case CS6:
2247 lpdcb->ByteSize = 6;
2248 break;
2249 case CS7:
2250 lpdcb->ByteSize = 7;
2251 break;
2252 case CS8:
2253 lpdcb->ByteSize = 8;
2254 break;
2255 default:
2256 ERR("unknown size %x \n",port.c_cflag & CSIZE);
2259 if(port.c_iflag & INPCK)
2260 lpdcb->fParity = TRUE;
2261 else
2262 lpdcb->fParity = FALSE;
2263 switch (port.c_cflag & (PARENB | PARODD)) {
2264 case 0:
2265 lpdcb->Parity = NOPARITY;
2266 break;
2267 case PARENB:
2268 lpdcb->Parity = EVENPARITY;
2269 break;
2270 case (PARENB | PARODD):
2271 lpdcb->Parity = ODDPARITY;
2272 break;
2275 if (port.c_cflag & CSTOPB)
2276 lpdcb->StopBits = TWOSTOPBITS;
2277 else
2278 lpdcb->StopBits = ONESTOPBIT;
2280 lpdcb->fNull = 0;
2281 lpdcb->fBinary = 1;
2283 #ifdef CRTSCTS
2285 if (port.c_cflag & CRTSCTS) {
2286 lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
2287 lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
2288 lpdcb->fOutxCtsFlow = 1;
2289 lpdcb->fOutxDsrFlow = 1;
2290 } else
2291 #endif
2293 lpdcb->fDtrControl = DTR_CONTROL_DISABLE;
2294 lpdcb->fRtsControl = RTS_CONTROL_DISABLE;
2296 if (port.c_iflag & IXON)
2297 lpdcb->fInX = 1;
2298 else
2299 lpdcb->fInX = 0;
2301 if (port.c_iflag & IXOFF)
2302 lpdcb->fOutX = 1;
2303 else
2304 lpdcb->fOutX = 0;
2306 lpdcb->XonChar =
2307 lpdcb->XoffChar =
2309 lpdcb->XonLim = 10;
2310 lpdcb->XoffLim = 10;
2312 commerror = 0;
2314 TRACE("OK\n");
2316 TRACE("bytesize %d baudrate %ld fParity %d Parity %d stopbits %d\n",
2317 lpdcb->ByteSize,lpdcb->BaudRate,lpdcb->fParity, lpdcb->Parity,
2318 (lpdcb->StopBits == ONESTOPBIT)?1:
2319 (lpdcb->StopBits == TWOSTOPBITS)?2:0);
2320 TRACE("%s %s\n",(lpdcb->fInX)?"IXON":"~IXON",
2321 (lpdcb->fOutX)?"IXOFF":"~IXOFF");
2322 #ifdef CRTSCTS
2323 if ( lpdcb->fOutxCtsFlow ||
2324 lpdcb->fDtrControl == DTR_CONTROL_ENABLE||
2325 lpdcb->fRtsControl == RTS_CONTROL_ENABLE
2327 TRACE("CRTSCTS\n");
2329 if (lpdcb->fDtrControl == DTR_CONTROL_DISABLE)
2330 TRACE("~CRTSCTS\n");
2332 #endif
2333 return TRUE;
2336 /*****************************************************************************
2337 * TransmitCommChar (KERNEL32.535)
2339 BOOL WINAPI TransmitCommChar(INT cid,CHAR chTransmit)
2341 struct DosDeviceStruct *ptr;
2343 FIXME("(%d,'%c'), use win32 handle!\n",cid,chTransmit);
2344 if ((ptr = GetDeviceStruct(cid)) == NULL)
2345 FIXME("no handle for cid = %0x!.\n",cid);
2346 return FALSE;
2348 if (ptr->suspended) {
2349 ptr->commerror = IE_HARDWARE;
2350 return FALSE;
2352 if (write(ptr->fd, (void *) &chTransmit, 1) == -1) {
2353 ptr->commerror = WinError();
2354 return FALSE;
2355 } else {
2356 ptr->commerror = 0;
2357 return TRUE;
2361 /*****************************************************************************
2362 * GetCommTimeouts (KERNEL32.160)
2364 BOOL WINAPI GetCommTimeouts(HANDLE hcom,LPCOMMTIMEOUTS lptimeouts)
2366 FIXME("(%x,%p):stub.\n",hcom,lptimeouts);
2367 return TRUE;
2370 /*****************************************************************************
2371 * SetCommTimeouts (KERNEL32.453)
2373 BOOL WINAPI SetCommTimeouts(HANDLE hcom,LPCOMMTIMEOUTS lptimeouts) {
2374 struct DosDeviceStruct *ptr;
2375 struct termios tios;
2376 int fd;
2378 FIXME("(%x,%p):stub.\n",hcom,lptimeouts);
2380 if ((ptr = GetDeviceStruct(hcom)) == NULL) {
2381 FIXME("no handle for cid = %0x!.\n",hcom);
2382 return FALSE;
2386 fd = COMM_GetWriteFd(hcom);
2387 if (fd < 0) {
2388 FIXME("no fd for cid = %0x!.\n",hcom);
2389 return FALSE;
2393 FIXME("ReadIntervalTimeout %ld\n",lptimeouts->ReadIntervalTimeout);
2394 FIXME("ReadTotalTimeoutMultiplier %ld\n",lptimeouts->ReadTotalTimeoutMultiplier);
2395 FIXME("ReadTotalTimeoutConstant %ld\n",lptimeouts->ReadTotalTimeoutConstant);
2396 FIXME("WriteTotalTimeoutMultiplier %ld\n",lptimeouts->WriteTotalTimeoutMultiplier);
2397 FIXME("WriteTotalTimeoutConstant %ld\n",lptimeouts->WriteTotalTimeoutConstant);
2400 if (-1==tcgetattr(fd,&tios)) {
2401 FIXME("tcgetattr on fd %d failed!\n",fd);
2402 return FALSE;
2404 /* VTIME is in 1/10 seconds */
2405 tios.c_cc[VTIME]= (lptimeouts->ReadIntervalTimeout+99)/100;
2406 if (-1==tcsetattr(fd,0,&tios)) {
2407 FIXME("tcsetattr on fd %d failed!\n",fd);
2408 return FALSE;
2410 return TRUE;
2413 /***********************************************************************
2414 * GetCommModemStatus (KERNEL32.285)
2416 BOOL WINAPI GetCommModemStatus(HANDLE hFile,LPDWORD lpModemStat )
2418 int fd,mstat, result=FALSE;
2420 *lpModemStat=0;
2421 #ifdef TIOCMGET
2422 fd = COMM_GetWriteFd(hFile);
2423 if(fd<0)
2424 return FALSE;
2425 result = ioctl(fd, TIOCMGET, &mstat);
2426 close(fd);
2427 if (result == -1)
2429 TRACE("ioctl failed\n");
2430 return FALSE;
2432 if (mstat & TIOCM_CTS)
2433 *lpModemStat |= MS_CTS_ON;
2434 if (mstat & TIOCM_DSR)
2435 *lpModemStat |= MS_DSR_ON;
2436 if (mstat & TIOCM_RNG)
2437 *lpModemStat |= MS_RING_ON;
2438 /*FIXME: Not really sure about RLSD UB 990810*/
2439 if (mstat & TIOCM_CAR)
2440 *lpModemStat |= MS_RLSD_ON;
2441 TRACE("%s%s%s%s\n",
2442 (*lpModemStat &MS_RLSD_ON)?"MS_RLSD_ON ":"",
2443 (*lpModemStat &MS_RING_ON)?"MS_RING_ON ":"",
2444 (*lpModemStat &MS_DSR_ON)?"MS_DSR_ON ":"",
2445 (*lpModemStat &MS_CTS_ON)?"MS_CTS_ON ":"");
2446 return TRUE;
2447 #else
2448 return FALSE;
2449 #endif
2451 /***********************************************************************
2452 * WaitCommEvent (KERNEL32.719)
2454 BOOL WINAPI WaitCommEvent(HANDLE hFile,LPDWORD eventmask ,LPOVERLAPPED overlapped)
2456 FIXME("(%d %p %p )\n",hFile, eventmask,overlapped);
2457 return TRUE;
2460 /***********************************************************************
2461 * GetCommProperties (KERNEL32.???)
2463 BOOL WINAPI GetCommProperties(HANDLE hFile, LPDCB *dcb)
2465 FIXME("(%d %p )\n",hFile,dcb);
2466 return TRUE;
2469 /***********************************************************************
2470 * SetCommProperties (KERNEL32.???)
2472 BOOL WINAPI SetCommProperties(HANDLE hFile, LPDCB dcb)
2474 FIXME("(%d %p )\n",hFile,dcb);
2475 return TRUE;