1 /* Main file for COMM support
3 * DEC 93 Erik Bos <erik@xs4all.nl>
4 * Copyright 1996 Marcus Meissner
5 * Copyright 2005,2006 Eric Pouech
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "wine/port.h"
43 #ifdef HAVE_SYS_STAT_H
44 # include <sys/stat.h>
46 #include <sys/types.h>
47 #ifdef HAVE_SYS_FILIO_H
48 # include <sys/filio.h>
50 #ifdef HAVE_SYS_IOCTL_H
51 #include <sys/ioctl.h>
53 #ifdef HAVE_SYS_POLL_H
54 # include <sys/poll.h>
56 #ifdef HAVE_SYS_MODEM_H
57 # include <sys/modem.h>
59 #ifdef HAVE_SYS_STRTIO_H
60 # include <sys/strtio.h>
63 #define NONAMELESSUNION
64 #define NONAMELESSSTRUCT
66 #define WIN32_NO_STATUS
70 #include "ddk/ntddser.h"
71 #include "ntdll_misc.h"
72 #include "wine/server.h"
73 #include "wine/library.h"
74 #include "wine/debug.h"
76 #ifdef HAVE_LINUX_SERIAL_H
77 #include <linux/serial.h>
80 #if !defined(TIOCINQ) && defined(FIONREAD)
81 #define TIOCINQ FIONREAD
84 WINE_DEFAULT_DEBUG_CHANNEL(comm);
86 static const char* iocode2str(DWORD ioc)
90 #define X(x) case (x): return #x;
91 X(IOCTL_SERIAL_CLEAR_STATS);
92 X(IOCTL_SERIAL_CLR_DTR);
93 X(IOCTL_SERIAL_CLR_RTS);
94 X(IOCTL_SERIAL_CONFIG_SIZE);
95 X(IOCTL_SERIAL_GET_BAUD_RATE);
96 X(IOCTL_SERIAL_GET_CHARS);
97 X(IOCTL_SERIAL_GET_COMMSTATUS);
98 X(IOCTL_SERIAL_GET_DTRRTS);
99 X(IOCTL_SERIAL_GET_HANDFLOW);
100 X(IOCTL_SERIAL_GET_LINE_CONTROL);
101 X(IOCTL_SERIAL_GET_MODEM_CONTROL);
102 X(IOCTL_SERIAL_GET_MODEMSTATUS);
103 X(IOCTL_SERIAL_GET_PROPERTIES);
104 X(IOCTL_SERIAL_GET_STATS);
105 X(IOCTL_SERIAL_GET_TIMEOUTS);
106 X(IOCTL_SERIAL_GET_WAIT_MASK);
107 X(IOCTL_SERIAL_IMMEDIATE_CHAR);
108 X(IOCTL_SERIAL_LSRMST_INSERT);
109 X(IOCTL_SERIAL_PURGE);
110 X(IOCTL_SERIAL_RESET_DEVICE);
111 X(IOCTL_SERIAL_SET_BAUD_RATE);
112 X(IOCTL_SERIAL_SET_BREAK_ON);
113 X(IOCTL_SERIAL_SET_BREAK_OFF);
114 X(IOCTL_SERIAL_SET_CHARS);
115 X(IOCTL_SERIAL_SET_DTR);
116 X(IOCTL_SERIAL_SET_FIFO_CONTROL);
117 X(IOCTL_SERIAL_SET_HANDFLOW);
118 X(IOCTL_SERIAL_SET_LINE_CONTROL);
119 X(IOCTL_SERIAL_SET_MODEM_CONTROL);
120 X(IOCTL_SERIAL_SET_QUEUE_SIZE);
121 X(IOCTL_SERIAL_SET_RTS);
122 X(IOCTL_SERIAL_SET_TIMEOUTS);
123 X(IOCTL_SERIAL_SET_WAIT_MASK);
124 X(IOCTL_SERIAL_SET_XOFF);
125 X(IOCTL_SERIAL_SET_XON);
126 X(IOCTL_SERIAL_WAIT_ON_MASK);
127 X(IOCTL_SERIAL_XOFF_COUNTER);
129 default: { static char tmp[32]; sprintf(tmp, "IOCTL_SERIAL_%d\n", ioc); return tmp; }
133 static NTSTATUS get_baud_rate(int fd, SERIAL_BAUD_RATE* sbr)
138 if (tcgetattr(fd, &port) == -1)
140 ERR("tcgetattr error '%s'\n", strerror(errno));
141 return FILE_GetNtStatus();
145 speed = port.c_cflag & CBAUD;
147 speed = cfgetospeed(&port);
151 case B0: sbr->BaudRate = 0; break;
152 case B50: sbr->BaudRate = 50; break;
153 case B75: sbr->BaudRate = 75; break;
154 case B110: sbr->BaudRate = 110; break;
155 case B134: sbr->BaudRate = 134; break;
156 case B150: sbr->BaudRate = 150; break;
157 case B200: sbr->BaudRate = 200; break;
158 case B300: sbr->BaudRate = 300; break;
159 case B600: sbr->BaudRate = 600; break;
160 case B1200: sbr->BaudRate = 1200; break;
161 case B1800: sbr->BaudRate = 1800; break;
162 case B2400: sbr->BaudRate = 2400; break;
163 case B4800: sbr->BaudRate = 4800; break;
164 case B9600: sbr->BaudRate = 9600; break;
165 case B19200: sbr->BaudRate = 19200; break;
166 case B38400: sbr->BaudRate = 38400; break;
168 case B57600: sbr->BaudRate = 57600; break;
171 case B115200: sbr->BaudRate = 115200; break;
174 case B230400: sbr->BaudRate = 230400; break;
177 case B460800: sbr->BaudRate = 460800; break;
180 ERR("unknown speed %x\n", speed);
181 return STATUS_INVALID_PARAMETER;
184 return STATUS_INVALID_PARAMETER;
186 return STATUS_SUCCESS;
189 static NTSTATUS get_hand_flow(int fd, SERIAL_HANDFLOW* shf)
194 if (tcgetattr(fd, &port) == -1)
196 ERR("tcgetattr error '%s'\n", strerror(errno));
197 return FILE_GetNtStatus();
199 /* termios does not support DTR/DSR flow control */
200 shf->ControlHandShake = 0;
201 shf->FlowReplace = 0;
203 if (ioctl(fd, TIOCMGET, &stat) == -1)
205 WARN("ioctl error '%s'\n", strerror(errno));
206 shf->ControlHandShake |= SERIAL_DTR_CONTROL;
207 shf->FlowReplace |= SERIAL_RTS_CONTROL;
210 WARN("Setting DTR/RTS to enabled by default\n");
211 shf->ControlHandShake |= SERIAL_DTR_CONTROL;
212 shf->FlowReplace |= SERIAL_RTS_CONTROL;
215 if (stat & TIOCM_DTR)
217 shf->ControlHandShake |= SERIAL_DTR_CONTROL;
219 if (port.c_cflag & CRTSCTS)
221 shf->FlowReplace |= SERIAL_RTS_CONTROL;
222 shf->ControlHandShake |= SERIAL_CTS_HANDSHAKE;
228 if (stat & TIOCM_RTS)
230 shf->FlowReplace |= SERIAL_RTS_CONTROL;
232 if (port.c_iflag & IXOFF)
233 shf->FlowReplace |= SERIAL_AUTO_RECEIVE;
234 if (port.c_iflag & IXON)
235 shf->FlowReplace |= SERIAL_AUTO_TRANSMIT;
239 return STATUS_SUCCESS;
242 static NTSTATUS get_line_control(int fd, SERIAL_LINE_CONTROL* slc)
246 if (tcgetattr(fd, &port) == -1)
248 ERR("tcgetattr error '%s'\n", strerror(errno));
249 return FILE_GetNtStatus();
253 switch (port.c_cflag & (PARENB | PARODD | CMSPAR))
255 switch (port.c_cflag & (PARENB | PARODD))
258 case 0: slc->Parity = NOPARITY; break;
259 case PARENB: slc->Parity = EVENPARITY; break;
260 case PARENB|PARODD: slc->Parity = ODDPARITY; break;
262 case PARENB|CMSPAR: slc->Parity = MARKPARITY; break;
263 case PARENB|PARODD|CMSPAR: slc->Parity = SPACEPARITY; break;
266 switch (port.c_cflag & CSIZE)
268 case CS5: slc->WordLength = 5; break;
269 case CS6: slc->WordLength = 6; break;
270 case CS7: slc->WordLength = 7; break;
271 case CS8: slc->WordLength = 8; break;
272 default: ERR("unknown size %x\n", (UINT)(port.c_cflag & CSIZE));
275 if (port.c_cflag & CSTOPB)
277 if (slc->WordLength == 5)
278 slc->StopBits = ONE5STOPBITS;
280 slc->StopBits = TWOSTOPBITS;
283 slc->StopBits = ONESTOPBIT;
285 return STATUS_SUCCESS;
288 static NTSTATUS get_modem_status(int fd, DWORD* lpModemStat)
290 NTSTATUS status = STATUS_SUCCESS;
294 if (ioctl(fd, TIOCMGET, &mstat) == -1)
296 WARN("ioctl failed\n");
297 status = FILE_GetNtStatus();
303 if (mstat & TIOCM_CTS) *lpModemStat |= MS_CTS_ON;
306 if (mstat & TIOCM_DSR) *lpModemStat |= MS_DSR_ON;
309 if (mstat & TIOCM_RNG) *lpModemStat |= MS_RING_ON;
312 /* FIXME: Not really sure about RLSD UB 990810 */
313 if (mstat & TIOCM_CAR) *lpModemStat |= MS_RLSD_ON;
315 TRACE("%04x -> %s%s%s%s\n", mstat,
316 (*lpModemStat & MS_RLSD_ON) ? "MS_RLSD_ON " : "",
317 (*lpModemStat & MS_RING_ON) ? "MS_RING_ON " : "",
318 (*lpModemStat & MS_DSR_ON) ? "MS_DSR_ON " : "",
319 (*lpModemStat & MS_CTS_ON) ? "MS_CTS_ON " : "");
322 status = STATUS_NOT_SUPPORTED;
327 static NTSTATUS get_special_chars(int fd, SERIAL_CHARS* sc)
331 if (tcgetattr(fd, &port) == -1)
333 ERR("tcgetattr error '%s'\n", strerror(errno));
334 return FILE_GetNtStatus();
336 sc->EofChar = port.c_cc[VEOF];
337 sc->ErrorChar = 0xFF;
338 sc->BreakChar = 0; /* FIXME */
339 sc->EventChar = 0; /* FIXME */
340 sc->XonChar = port.c_cc[VSTART];
341 sc->XoffChar = port.c_cc[VSTOP];
343 return STATUS_SUCCESS;
346 static NTSTATUS get_status(int fd, SERIAL_STATUS* ss)
348 NTSTATUS status = STATUS_SUCCESS;
352 ss->EofReceived = FALSE;
353 ss->WaitForImmediate = FALSE;
355 if (ioctl(fd, TIOCOUTQ, &ss->AmountInOutQueue) == -1)
357 WARN("ioctl returned error\n");
358 status = FILE_GetNtStatus();
361 ss->AmountInOutQueue = 0; /* FIXME: find a different way to find out */
365 if (ioctl(fd, TIOCINQ, &ss->AmountInInQueue))
367 WARN("ioctl returned error\n");
368 status = FILE_GetNtStatus();
371 ss->AmountInInQueue = 0; /* FIXME: find a different way to find out */
376 static NTSTATUS get_timeouts(HANDLE handle, SERIAL_TIMEOUTS* st)
379 SERVER_START_REQ( get_serial_info )
381 req->handle = handle;
382 if (!(status = wine_server_call( req )))
384 st->ReadIntervalTimeout = reply->readinterval;
385 st->ReadTotalTimeoutMultiplier = reply->readmult;
386 st->ReadTotalTimeoutConstant = reply->readconst;
387 st->WriteTotalTimeoutMultiplier = reply->writemult;
388 st->WriteTotalTimeoutConstant = reply->writeconst;
395 static NTSTATUS get_wait_mask(HANDLE hDevice, DWORD* mask)
399 SERVER_START_REQ( get_serial_info )
401 req->handle = hDevice;
402 if (!(status = wine_server_call( req )))
403 *mask = reply->eventmask;
409 static NTSTATUS purge(int fd, DWORD flags)
412 ** not exactly sure how these are different
413 ** Perhaps if we had our own internal queues, one flushes them
414 ** and the other flushes the kernel's buffers.
416 if (flags & PURGE_TXABORT) tcflush(fd, TCOFLUSH);
417 if (flags & PURGE_RXABORT) tcflush(fd, TCIFLUSH);
418 if (flags & PURGE_TXCLEAR) tcflush(fd, TCOFLUSH);
419 if (flags & PURGE_RXCLEAR) tcflush(fd, TCIFLUSH);
420 return STATUS_SUCCESS;
423 static NTSTATUS set_baud_rate(int fd, const SERIAL_BAUD_RATE* sbr)
427 if (tcgetattr(fd, &port) == -1)
429 ERR("tcgetattr error '%s'\n", strerror(errno));
430 return FILE_GetNtStatus();
434 port.c_cflag &= ~CBAUD;
435 switch (sbr->BaudRate)
437 case 0: port.c_cflag |= B0; break;
438 case 50: port.c_cflag |= B50; break;
439 case 75: port.c_cflag |= B75; break;
441 case CBR_110: port.c_cflag |= B110; break;
442 case 134: port.c_cflag |= B134; break;
443 case 150: port.c_cflag |= B150; break;
444 case 200: port.c_cflag |= B200; break;
446 case CBR_300: port.c_cflag |= B300; break;
448 case CBR_600: port.c_cflag |= B600; break;
450 case CBR_1200: port.c_cflag |= B1200; break;
451 case 1800: port.c_cflag |= B1800; break;
453 case CBR_2400: port.c_cflag |= B2400; break;
455 case CBR_4800: port.c_cflag |= B4800; break;
457 case CBR_9600: port.c_cflag |= B9600; break;
459 case CBR_19200: port.c_cflag |= B19200; break;
461 case CBR_38400: port.c_cflag |= B38400; break;
463 case 57600: port.c_cflag |= B57600; break;
466 case 115200: port.c_cflag |= B115200;break;
469 case 230400: port.c_cflag |= B230400;break;
472 case 460800: port.c_cflag |= B460800;break;
475 #if defined (HAVE_LINUX_SERIAL_H) && defined (TIOCSSERIAL)
477 struct serial_struct nuts;
480 ioctl(fd, TIOCGSERIAL, &nuts);
481 nuts.custom_divisor = nuts.baud_base / sbr->BaudRate;
482 if (!(nuts.custom_divisor)) nuts.custom_divisor = 1;
483 arby = nuts.baud_base / nuts.custom_divisor;
484 nuts.flags &= ~ASYNC_SPD_MASK;
485 nuts.flags |= ASYNC_SPD_CUST;
486 WARN("You (or a program acting at your behest) have specified\n"
487 "a non-standard baud rate %d. Wine will set the rate to %d,\n"
488 "which is as close as we can get by our present understanding of your\n"
489 "hardware. I hope you know what you are doing. Any disruption Wine\n"
490 "has caused to your linux system can be undone with setserial \n"
491 "(see man setserial). If you have incapacitated a Hayes type modem,\n"
492 "reset it and it will probably recover.\n", sbr->BaudRate, arby);
493 ioctl(fd, TIOCSSERIAL, &nuts);
494 port.c_cflag |= B38400;
497 #else /* Don't have linux/serial.h or lack TIOCSSERIAL */
498 ERR("baudrate %d\n", sbr->BaudRate);
499 return STATUS_NOT_SUPPORTED;
500 #endif /* Don't have linux/serial.h or lack TIOCSSERIAL */
502 #elif !defined(__EMX__)
503 switch (sbr->BaudRate)
505 case 0: port.c_ospeed = B0; break;
506 case 50: port.c_ospeed = B50; break;
507 case 75: port.c_ospeed = B75; break;
509 case CBR_110: port.c_ospeed = B110; break;
510 case 134: port.c_ospeed = B134; break;
511 case 150: port.c_ospeed = B150; break;
512 case 200: port.c_ospeed = B200; break;
514 case CBR_300: port.c_ospeed = B300; break;
516 case CBR_600: port.c_ospeed = B600; break;
518 case CBR_1200: port.c_ospeed = B1200; break;
519 case 1800: port.c_ospeed = B1800; break;
521 case CBR_2400: port.c_ospeed = B2400; break;
523 case CBR_4800: port.c_ospeed = B4800; break;
525 case CBR_9600: port.c_ospeed = B9600; break;
527 case CBR_19200: port.c_ospeed = B19200; break;
529 case CBR_38400: port.c_ospeed = B38400; break;
532 case CBR_57600: port.c_cflag |= B57600; break;
536 case CBR_115200: port.c_cflag |= B115200;break;
539 case 230400: port.c_cflag |= B230400;break;
542 case 460800: port.c_cflag |= B460800;break;
545 ERR("baudrate %d\n", sbr->BaudRate);
546 return STATUS_NOT_SUPPORTED;
548 port.c_ispeed = port.c_ospeed;
550 if (tcsetattr(fd, TCSANOW, &port) == -1)
552 ERR("tcsetattr error '%s'\n", strerror(errno));
553 return FILE_GetNtStatus();
555 return STATUS_SUCCESS;
558 static int whack_modem(int fd, unsigned int andy, unsigned int orrie)
561 unsigned int mstat, okay;
562 okay = ioctl(fd, TIOCMGET, &mstat);
563 if (okay) return okay;
564 if (andy) mstat &= andy;
566 return ioctl(fd, TIOCMSET, &mstat);
572 static NTSTATUS set_handflow(int fd, const SERIAL_HANDFLOW* shf)
576 if ((shf->FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE)) ==
577 (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE))
578 return STATUS_NOT_SUPPORTED;
580 if (tcgetattr(fd, &port) == -1)
582 ERR("tcgetattr error '%s'\n", strerror(errno));
583 return FILE_GetNtStatus();
587 if ((shf->ControlHandShake & SERIAL_CTS_HANDSHAKE) ||
588 (shf->FlowReplace & SERIAL_RTS_HANDSHAKE))
590 port.c_cflag |= CRTSCTS;
594 port.c_cflag &= ~CRTSCTS;
597 if (shf->ControlHandShake & SERIAL_DTR_HANDSHAKE)
599 WARN("DSR/DTR flow control not supported\n");
600 } else if (!(shf->ControlHandShake & SERIAL_DTR_CONTROL))
601 whack_modem(fd, ~TIOCM_DTR, 0);
603 whack_modem(fd, 0, TIOCM_DTR);
606 if (!(shf->ControlHandShake & SERIAL_CTS_HANDSHAKE))
608 if ((shf->FlowReplace & (SERIAL_RTS_CONTROL|SERIAL_RTS_HANDSHAKE)) == 0)
609 whack_modem(fd, ~TIOCM_RTS, 0);
611 whack_modem(fd, 0, TIOCM_RTS);
615 if (shf->FlowReplace & SERIAL_AUTO_RECEIVE)
616 port.c_iflag |= IXOFF;
618 port.c_iflag &= ~IXOFF;
619 if (shf->FlowReplace & SERIAL_AUTO_TRANSMIT)
620 port.c_iflag |= IXON;
622 port.c_iflag &= ~IXON;
623 if (tcsetattr(fd, TCSANOW, &port) == -1)
625 ERR("tcsetattr error '%s'\n", strerror(errno));
626 return FILE_GetNtStatus();
629 return STATUS_SUCCESS;
632 static NTSTATUS set_line_control(int fd, const SERIAL_LINE_CONTROL* slc)
635 unsigned bytesize, stopbits;
637 if (tcgetattr(fd, &port) == -1)
639 ERR("tcgetattr error '%s'\n", strerror(errno));
640 return FILE_GetNtStatus();
644 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK|IMAXBEL);
646 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK);
648 port.c_iflag |= IGNBRK | INPCK;
650 port.c_oflag &= ~(OPOST);
652 port.c_cflag &= ~(HUPCL);
653 port.c_cflag |= CLOCAL | CREAD;
655 port.c_lflag &= ~(ICANON|ECHO|ISIG);
656 port.c_lflag |= NOFLSH;
658 bytesize = slc->WordLength;
659 stopbits = slc->StopBits;
662 port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
664 port.c_cflag &= ~(PARENB | PARODD);
669 case NOPARITY: port.c_iflag &= ~INPCK; break;
670 case ODDPARITY: port.c_cflag |= PARENB | PARODD; break;
671 case EVENPARITY: port.c_cflag |= PARENB; break;
673 /* Linux defines mark/space (stick) parity */
674 case MARKPARITY: port.c_cflag |= PARENB | CMSPAR; break;
675 case SPACEPARITY: port.c_cflag |= PARENB | PARODD | CMSPAR; break;
677 /* try the POSIX way */
679 if (slc->StopBits == ONESTOPBIT)
681 stopbits = TWOSTOPBITS;
682 port.c_iflag &= ~INPCK;
686 ERR("Cannot set MARK Parity\n");
687 return STATUS_NOT_SUPPORTED;
691 if (slc->WordLength < 8)
694 port.c_iflag &= ~INPCK;
698 ERR("Cannot set SPACE Parity\n");
699 return STATUS_NOT_SUPPORTED;
705 return STATUS_NOT_SUPPORTED;
708 port.c_cflag &= ~CSIZE;
711 case 5: port.c_cflag |= CS5; break;
712 case 6: port.c_cflag |= CS6; break;
713 case 7: port.c_cflag |= CS7; break;
714 case 8: port.c_cflag |= CS8; break;
717 return STATUS_NOT_SUPPORTED;
722 case ONESTOPBIT: port.c_cflag &= ~CSTOPB; break;
723 case ONE5STOPBITS: /* will be selected if bytesize is 5 */
724 case TWOSTOPBITS: port.c_cflag |= CSTOPB; break;
727 return STATUS_NOT_SUPPORTED;
729 /* otherwise it hangs with pending input*/
730 if (tcsetattr(fd, TCSANOW, &port) == -1)
732 ERR("tcsetattr error '%s'\n", strerror(errno));
733 return FILE_GetNtStatus();
735 return STATUS_SUCCESS;
738 static NTSTATUS set_queue_size(int fd, const SERIAL_QUEUE_SIZE* sqs)
740 FIXME("insize %d outsize %d unimplemented stub\n", sqs->InSize, sqs->OutSize);
741 return STATUS_SUCCESS;
744 static NTSTATUS set_special_chars(int fd, const SERIAL_CHARS* sc)
748 if (tcgetattr(fd, &port) == -1)
750 ERR("tcgetattr error '%s'\n", strerror(errno));
751 return FILE_GetNtStatus();
754 port.c_cc[VMIN ] = 0;
755 port.c_cc[VTIME ] = 1;
757 port.c_cc[VEOF ] = sc->EofChar;
758 /* FIXME: sc->ErrorChar is not supported */
759 /* FIXME: sc->BreakChar is not supported */
760 /* FIXME: sc->EventChar is not supported */
761 port.c_cc[VSTART] = sc->XonChar;
762 port.c_cc[VSTOP ] = sc->XoffChar;
764 if (tcsetattr(fd, TCSANOW, &port) == -1)
766 ERR("tcsetattr error '%s'\n", strerror(errno));
767 return FILE_GetNtStatus();
769 return STATUS_SUCCESS;
772 static NTSTATUS set_timeouts(HANDLE handle, int fd, const SERIAL_TIMEOUTS* st)
776 unsigned int ux_timeout;
778 SERVER_START_REQ( set_serial_info )
780 req->handle = handle;
781 req->flags = SERIALINFO_SET_TIMEOUTS;
782 req->readinterval = st->ReadIntervalTimeout ;
783 req->readmult = st->ReadTotalTimeoutMultiplier ;
784 req->readconst = st->ReadTotalTimeoutConstant ;
785 req->writemult = st->WriteTotalTimeoutMultiplier ;
786 req->writeconst = st->WriteTotalTimeoutConstant ;
787 status = wine_server_call( req );
790 if (status) return status;
792 if (tcgetattr(fd, &port) == -1)
794 FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
795 return FILE_GetNtStatus();
798 /* VTIME is in 1/10 seconds */
799 if (st->ReadIntervalTimeout == 0) /* 0 means no timeout */
803 ux_timeout = (st->ReadIntervalTimeout + 99) / 100;
805 ux_timeout = 1; /* must be at least some timeout */
807 port.c_cc[VTIME] = ux_timeout;
809 if (tcsetattr(fd, 0, &port) == -1)
811 FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
812 return FILE_GetNtStatus();
814 return STATUS_SUCCESS;
817 static NTSTATUS set_wait_mask(HANDLE hDevice, DWORD mask)
821 SERVER_START_REQ( set_serial_info )
823 req->handle = hDevice;
824 req->flags = SERIALINFO_SET_MASK;
825 req->eventmask = mask;
826 status = wine_server_call( req );
832 static NTSTATUS set_XOff(int fd)
836 if (tcgetattr(fd,&port) == -1)
838 FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
839 return FILE_GetNtStatus();
843 port.c_iflag |= IXOFF;
844 if (tcsetattr(fd, TCSADRAIN, &port) == -1)
846 FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
847 return FILE_GetNtStatus();
849 return STATUS_SUCCESS;
852 static NTSTATUS set_XOn(int fd)
856 if (tcgetattr(fd,&port) == -1)
858 FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
859 return FILE_GetNtStatus();
861 port.c_iflag |= IXON;
862 if (tcsetattr(fd, TCSADRAIN, &port) == -1)
864 FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
865 return FILE_GetNtStatus();
867 return STATUS_SUCCESS;
871 * local structure holding the irq values we need for WaitCommEvent()
873 * Stripped down from struct serial_icounter_struct, which may not be available on some systems
874 * As the modem line interrupts (cts, dsr, rng, dcd) only get updated with TIOCMIWAIT active,
875 * no need to carry them in the internal structure
878 typedef struct serial_irq_info
880 int rx , tx, frame, overrun, parity, brk, buf_overrun;
883 /***********************************************************************
884 * Data needed by the thread polling for the changing CommEvent
886 typedef struct async_commio
893 serial_irq_info irq_info;
896 /***********************************************************************
897 * Get extended interrupt count info, needed for wait_on
899 static NTSTATUS get_irq_info(int fd, serial_irq_info *irq_info)
902 struct serial_icounter_struct einfo;
903 if (!ioctl(fd, TIOCGICOUNT, &einfo))
905 irq_info->rx = einfo.rx;
906 irq_info->tx = einfo.tx;
907 irq_info->frame = einfo.frame;
908 irq_info->overrun = einfo.overrun;
909 irq_info->parity = einfo.parity;
910 irq_info->brk = einfo.brk;
911 irq_info->buf_overrun = einfo.buf_overrun;
912 return STATUS_SUCCESS;
914 TRACE("TIOCGICOUNT err %s\n", strerror(errno));
915 return FILE_GetNtStatus();
917 memset(irq_info,0, sizeof(serial_irq_info));
918 return STATUS_NOT_IMPLEMENTED;
923 static DWORD WINAPI check_events(int fd, DWORD mask,
924 const serial_irq_info *new,
925 const serial_irq_info *old,
926 DWORD new_mstat, DWORD old_mstat)
928 DWORD ret = 0, queue;
930 TRACE("mask 0x%08x\n", mask);
931 TRACE("old->rx 0x%08x vs. new->rx 0x%08x\n", old->rx, new->rx);
932 TRACE("old->tx 0x%08x vs. new->tx 0x%08x\n", old->tx, new->tx);
933 TRACE("old->frame 0x%08x vs. new->frame 0x%08x\n", old->frame, new->frame);
934 TRACE("old->overrun 0x%08x vs. new->overrun 0x%08x\n", old->overrun, new->overrun);
935 TRACE("old->parity 0x%08x vs. new->parity 0x%08x\n", old->parity, new->parity);
936 TRACE("old->brk 0x%08x vs. new->brk 0x%08x\n", old->brk, new->brk);
937 TRACE("old->buf_overrun 0x%08x vs. new->buf_overrun 0x%08x\n", old->buf_overrun, new->buf_overrun);
939 if (old->brk != new->brk) ret |= EV_BREAK;
940 if ((old_mstat & MS_CTS_ON ) != (new_mstat & MS_CTS_ON )) ret |= EV_CTS;
941 if ((old_mstat & MS_DSR_ON ) != (new_mstat & MS_DSR_ON )) ret |= EV_DSR;
942 if ((old_mstat & MS_RING_ON) != (new_mstat & MS_RING_ON)) ret |= EV_RING;
943 if ((old_mstat & MS_RLSD_ON) != (new_mstat & MS_RLSD_ON)) ret |= EV_RLSD;
944 if (old->frame != new->frame || old->overrun != new->overrun || old->parity != new->parity) ret |= EV_ERR;
945 if (mask & EV_RXCHAR)
949 if (ioctl(fd, TIOCINQ, &queue))
950 WARN("TIOCINQ returned error\n");
955 if (mask & EV_TXEMPTY)
958 /* We really want to know when all characters have gone out of the transmitter */
959 #if defined(TIOCSERGETLSR)
960 if (ioctl(fd, TIOCSERGETLSR, &queue))
961 WARN("TIOCSERGETLSR returned error\n");
963 /* TIOCOUTQ only checks for an empty buffer */
964 #elif defined(TIOCOUTQ)
965 if (ioctl(fd, TIOCOUTQ, &queue))
966 WARN("TIOCOUTQ returned error\n");
970 TRACE("OUTQUEUE %d, Transmitter %sempty\n",
971 queue, (ret & EV_TXEMPTY) ? "" : "not ");
976 /***********************************************************************
977 * wait_for_event (INTERNAL)
979 * We need to poll for what is interesting
980 * TIOCMIWAIT only checks modem status line and may not be aborted by a changing mask
983 static DWORD CALLBACK wait_for_event(LPVOID arg)
985 async_commio *commio = (async_commio*) arg;
988 if (!server_get_unix_fd( commio->hDevice, FILE_READ_DATA | FILE_WRITE_DATA, &fd, &needs_close, NULL, NULL ))
990 serial_irq_info new_irq_info;
991 DWORD new_mstat, new_evtmask;
994 TRACE("device=%p fd=0x%08x mask=0x%08x buffer=%p event=%p irq_info=%p\n",
995 commio->hDevice, fd, commio->evtmask, commio->events, commio->hEvent, &commio->irq_info);
997 time.QuadPart = (ULONGLONG)10000;
998 time.QuadPart = -time.QuadPart;
1002 * TIOCMIWAIT is not adequate
1005 * We don't handle the EV_RXFLAG (the eventchar)
1007 NtDelayExecution(FALSE, &time);
1008 get_irq_info(fd, &new_irq_info);
1009 if (get_modem_status(fd, &new_mstat))
1010 TRACE("get_modem_status failed\n");
1011 *commio->events = check_events(fd, commio->evtmask,
1012 &new_irq_info, &commio->irq_info,
1013 new_mstat, commio->mstat);
1014 if (*commio->events) break;
1015 get_wait_mask(commio->hDevice, &new_evtmask);
1016 if (commio->evtmask != new_evtmask)
1018 *commio->events = 0;
1022 if (needs_close) close( fd );
1024 if (commio->hEvent) NtSetEvent(commio->hEvent, NULL);
1025 RtlFreeHeap(GetProcessHeap(), 0, commio);
1029 static NTSTATUS wait_on(HANDLE hDevice, int fd, HANDLE hEvent, DWORD* events)
1031 async_commio* commio;
1034 if ((status = NtResetEvent(hEvent, NULL)))
1037 commio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof (async_commio));
1038 if (!commio) return STATUS_NO_MEMORY;
1040 commio->hDevice = hDevice;
1041 commio->events = events;
1042 commio->hEvent = hEvent;
1043 get_wait_mask(commio->hDevice, &commio->evtmask);
1045 /* We may never return, if some capabilities miss
1046 * Return error in that case
1048 #if !defined(TIOCINQ)
1049 if (commio->evtmask & EV_RXCHAR)
1052 #if !(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)
1053 if (commio->evtmask & EV_TXEMPTY)
1056 #if !defined(TIOCMGET)
1057 if (commio->evtmask & (EV_CTS | EV_DSR| EV_RING| EV_RLSD))
1060 #if !defined(TIOCM_CTS)
1061 if (commio->evtmask & EV_CTS)
1064 #if !defined(TIOCM_DSR)
1065 if (commio->evtmask & EV_DSR)
1068 #if !defined(TIOCM_RNG)
1069 if (commio->evtmask & EV_RING)
1072 #if !defined(TIOCM_CAR)
1073 if (commio->evtmask & EV_RLSD)
1076 if (commio->evtmask & EV_RXFLAG)
1077 FIXME("EV_RXFLAG not handled\n");
1078 if ((status = get_irq_info(fd, &commio->irq_info)) ||
1079 (status = get_modem_status(fd, &commio->mstat)))
1082 /* We might have received something or the TX bufffer is delivered */
1083 *events = check_events(fd, commio->evtmask,
1084 &commio->irq_info, &commio->irq_info,
1085 commio->mstat, commio->mstat);
1086 if (*events) goto out_now;
1088 /* create the worker for the task */
1089 status = RtlQueueWorkItem(wait_for_event, commio, 0 /* FIXME */);
1090 if (status != STATUS_SUCCESS) goto out_now;
1091 return STATUS_PENDING;
1093 #if !defined(TIOCINQ) || (!(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)) || !defined(TIOCMGET) || !defined(TIOCM_CTS) ||!defined(TIOCM_DSR) || !defined(TIOCM_RNG) || !defined(TIOCM_CAR)
1095 FIXME("Returning error because of missing capabilities\n");
1096 status = STATUS_INVALID_PARAMETER;
1099 RtlFreeHeap(GetProcessHeap(), 0, commio);
1103 static NTSTATUS xmit_immediate(HANDLE hDevice, int fd, const char* ptr)
1105 /* FIXME: not perfect as it should bypass the in-queue */
1106 WARN("(%p,'%c') not perfect!\n", hDevice, *ptr);
1107 if (write(fd, ptr, 1) != 1)
1108 return FILE_GetNtStatus();
1109 return STATUS_SUCCESS;
1112 /******************************************************************
1113 * COMM_DeviceIoControl
1117 static inline NTSTATUS io_control(HANDLE hDevice,
1118 HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
1119 PVOID UserApcContext,
1120 PIO_STATUS_BLOCK piosb,
1121 ULONG dwIoControlCode,
1122 LPVOID lpInBuffer, DWORD nInBufferSize,
1123 LPVOID lpOutBuffer, DWORD nOutBufferSize)
1125 DWORD sz = 0, access = FILE_READ_DATA;
1126 NTSTATUS status = STATUS_SUCCESS;
1127 int fd = -1, needs_close = 0;
1129 TRACE("%p %s %p %d %p %d %p\n",
1130 hDevice, iocode2str(dwIoControlCode), lpInBuffer, nInBufferSize,
1131 lpOutBuffer, nOutBufferSize, piosb);
1133 piosb->Information = 0;
1135 if (dwIoControlCode != IOCTL_SERIAL_GET_TIMEOUTS)
1136 if ((status = server_get_unix_fd( hDevice, access, &fd, &needs_close, NULL, NULL )))
1139 switch (dwIoControlCode)
1141 case IOCTL_SERIAL_CLR_DTR:
1143 if (whack_modem(fd, ~TIOCM_DTR, 0) == -1) status = FILE_GetNtStatus();
1145 status = STATUS_NOT_SUPPORTED;
1148 case IOCTL_SERIAL_CLR_RTS:
1150 if (whack_modem(fd, ~TIOCM_RTS, 0) == -1) status = FILE_GetNtStatus();
1152 status = STATUS_NOT_SUPPORTED;
1155 case IOCTL_SERIAL_GET_BAUD_RATE:
1156 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_BAUD_RATE))
1158 if (!(status = get_baud_rate(fd, (SERIAL_BAUD_RATE*)lpOutBuffer)))
1159 sz = sizeof(SERIAL_BAUD_RATE);
1162 status = STATUS_INVALID_PARAMETER;
1164 case IOCTL_SERIAL_GET_CHARS:
1165 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_CHARS))
1167 if (!(status = get_special_chars(fd, (SERIAL_CHARS*)lpOutBuffer)))
1168 sz = sizeof(SERIAL_CHARS);
1171 status = STATUS_INVALID_PARAMETER;
1173 case IOCTL_SERIAL_GET_COMMSTATUS:
1174 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_STATUS))
1176 if (!(status = get_status(fd, (SERIAL_STATUS*)lpOutBuffer)))
1177 sz = sizeof(SERIAL_STATUS);
1179 else status = STATUS_INVALID_PARAMETER;
1181 case IOCTL_SERIAL_GET_HANDFLOW:
1182 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_HANDFLOW))
1184 if (!(status = get_hand_flow(fd, (SERIAL_HANDFLOW*)lpOutBuffer)))
1185 sz = sizeof(SERIAL_HANDFLOW);
1188 status = STATUS_INVALID_PARAMETER;
1190 case IOCTL_SERIAL_GET_LINE_CONTROL:
1191 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_LINE_CONTROL))
1193 if (!(status = get_line_control(fd, (SERIAL_LINE_CONTROL*)lpOutBuffer)))
1194 sz = sizeof(SERIAL_LINE_CONTROL);
1197 status = STATUS_INVALID_PARAMETER;
1199 case IOCTL_SERIAL_GET_MODEMSTATUS:
1200 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1202 if (!(status = get_modem_status(fd, (DWORD*)lpOutBuffer)))
1205 else status = STATUS_INVALID_PARAMETER;
1207 case IOCTL_SERIAL_GET_TIMEOUTS:
1208 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_TIMEOUTS))
1210 if (!(status = get_timeouts(hDevice, (SERIAL_TIMEOUTS*)lpOutBuffer)))
1211 sz = sizeof(SERIAL_TIMEOUTS);
1214 status = STATUS_INVALID_PARAMETER;
1216 case IOCTL_SERIAL_GET_WAIT_MASK:
1217 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1219 if (!(status = get_wait_mask(hDevice, (DWORD*)lpOutBuffer)))
1223 status = STATUS_INVALID_PARAMETER;
1225 case IOCTL_SERIAL_IMMEDIATE_CHAR:
1226 if (lpInBuffer && nInBufferSize == sizeof(CHAR))
1227 status = xmit_immediate(hDevice, fd, lpInBuffer);
1229 status = STATUS_INVALID_PARAMETER;
1231 case IOCTL_SERIAL_PURGE:
1232 if (lpInBuffer && nInBufferSize == sizeof(DWORD))
1233 status = purge(fd, *(DWORD*)lpInBuffer);
1235 status = STATUS_INVALID_PARAMETER;
1237 case IOCTL_SERIAL_RESET_DEVICE:
1238 FIXME("Unsupported\n");
1240 case IOCTL_SERIAL_SET_BAUD_RATE:
1241 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_BAUD_RATE))
1242 status = set_baud_rate(fd, (const SERIAL_BAUD_RATE*)lpInBuffer);
1244 status = STATUS_INVALID_PARAMETER;
1246 case IOCTL_SERIAL_SET_BREAK_OFF:
1247 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1248 if (ioctl(fd, TIOCCBRK, 0) == -1)
1250 TRACE("ioctl failed\n");
1251 status = FILE_GetNtStatus();
1254 FIXME("ioctl not available\n");
1255 status = STATUS_NOT_SUPPORTED;
1258 case IOCTL_SERIAL_SET_BREAK_ON:
1259 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1260 if (ioctl(fd, TIOCSBRK, 0) == -1)
1262 TRACE("ioctl failed\n");
1263 status = FILE_GetNtStatus();
1266 FIXME("ioctl not available\n");
1267 status = STATUS_NOT_SUPPORTED;
1270 case IOCTL_SERIAL_SET_CHARS:
1271 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_CHARS))
1272 status = set_special_chars(fd, (const SERIAL_CHARS*)lpInBuffer);
1274 status = STATUS_INVALID_PARAMETER;
1276 case IOCTL_SERIAL_SET_DTR:
1278 if (whack_modem(fd, 0, TIOCM_DTR) == -1) status = FILE_GetNtStatus();
1280 status = STATUS_NOT_SUPPORTED;
1283 case IOCTL_SERIAL_SET_HANDFLOW:
1284 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_HANDFLOW))
1285 status = set_handflow(fd, (const SERIAL_HANDFLOW*)lpInBuffer);
1287 status = STATUS_INVALID_PARAMETER;
1289 case IOCTL_SERIAL_SET_LINE_CONTROL:
1290 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_LINE_CONTROL))
1291 status = set_line_control(fd, (const SERIAL_LINE_CONTROL*)lpInBuffer);
1293 status = STATUS_INVALID_PARAMETER;
1295 case IOCTL_SERIAL_SET_QUEUE_SIZE:
1296 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_QUEUE_SIZE))
1297 status = set_queue_size(fd, (const SERIAL_QUEUE_SIZE*)lpInBuffer);
1299 status = STATUS_INVALID_PARAMETER;
1301 case IOCTL_SERIAL_SET_RTS:
1303 if (whack_modem(fd, 0, TIOCM_RTS) == -1) status = FILE_GetNtStatus();
1305 status = STATUS_NOT_SUPPORTED;
1308 case IOCTL_SERIAL_SET_TIMEOUTS:
1309 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_TIMEOUTS))
1310 status = set_timeouts(hDevice, fd, (const SERIAL_TIMEOUTS*)lpInBuffer);
1312 status = STATUS_INVALID_PARAMETER;
1314 case IOCTL_SERIAL_SET_WAIT_MASK:
1315 if (lpInBuffer && nInBufferSize == sizeof(DWORD))
1317 status = set_wait_mask(hDevice, *(DWORD*)lpInBuffer);
1319 else status = STATUS_INVALID_PARAMETER;
1321 case IOCTL_SERIAL_SET_XOFF:
1322 status = set_XOff(fd);
1324 case IOCTL_SERIAL_SET_XON:
1325 status = set_XOn(fd);
1327 case IOCTL_SERIAL_WAIT_ON_MASK:
1328 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1330 if (!(status = wait_on(hDevice, fd, hEvent, (DWORD*)lpOutBuffer)))
1334 status = STATUS_INVALID_PARAMETER;
1337 FIXME("Unsupported IOCTL %x (type=%x access=%x func=%x meth=%x)\n",
1338 dwIoControlCode, dwIoControlCode >> 16, (dwIoControlCode >> 14) & 3,
1339 (dwIoControlCode >> 2) & 0xFFF, dwIoControlCode & 3);
1341 status = STATUS_INVALID_PARAMETER;
1344 if (needs_close) close( fd );
1346 piosb->u.Status = status;
1347 piosb->Information = sz;
1348 if (hEvent && status != STATUS_PENDING) NtSetEvent(hEvent, NULL);
1352 NTSTATUS COMM_DeviceIoControl(HANDLE hDevice,
1353 HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
1354 PVOID UserApcContext,
1355 PIO_STATUS_BLOCK piosb,
1356 ULONG dwIoControlCode,
1357 LPVOID lpInBuffer, DWORD nInBufferSize,
1358 LPVOID lpOutBuffer, DWORD nOutBufferSize)
1362 if (dwIoControlCode == IOCTL_SERIAL_WAIT_ON_MASK)
1364 HANDLE hev = hEvent;
1366 /* this is an ioctl we implement in a non blocking way if hEvent is not
1368 * so we have to explicitly wait if no hEvent is provided
1372 OBJECT_ATTRIBUTES attr;
1374 attr.Length = sizeof(attr);
1375 attr.RootDirectory = 0;
1376 attr.ObjectName = NULL;
1377 attr.Attributes = OBJ_CASE_INSENSITIVE | OBJ_OPENIF;
1378 attr.SecurityDescriptor = NULL;
1379 attr.SecurityQualityOfService = NULL;
1380 status = NtCreateEvent(&hev, EVENT_ALL_ACCESS, &attr, FALSE, FALSE);
1382 if (status) goto done;
1384 status = io_control(hDevice, hev, UserApcRoutine, UserApcContext,
1385 piosb, dwIoControlCode, lpInBuffer, nInBufferSize,
1386 lpOutBuffer, nOutBufferSize);
1389 if (status == STATUS_PENDING)
1391 NtWaitForSingleObject(hev, FALSE, NULL);
1392 status = STATUS_SUCCESS;
1397 else status = io_control(hDevice, hEvent, UserApcRoutine, UserApcContext,
1398 piosb, dwIoControlCode, lpInBuffer, nInBufferSize,
1399 lpOutBuffer, nOutBufferSize);