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();
200 if (ioctl(fd, TIOCMGET, &stat) == -1)
202 WARN("ioctl error '%s'\n", strerror(errno));
203 stat = DTR_CONTROL_ENABLE | RTS_CONTROL_ENABLE;
206 /* termios does not support DTR/DSR flow control */
207 shf->ControlHandShake = 0;
208 shf->FlowReplace = 0;
210 if (stat & TIOCM_DTR)
212 shf->ControlHandShake |= SERIAL_DTR_CONTROL;
214 if (port.c_cflag & CRTSCTS)
216 shf->ControlHandShake |= SERIAL_DTR_CONTROL | SERIAL_DTR_HANDSHAKE;
217 shf->ControlHandShake |= SERIAL_CTS_HANDSHAKE;
223 if (stat & TIOCM_RTS)
225 shf->ControlHandShake |= SERIAL_RTS_CONTROL;
227 if (port.c_iflag & IXOFF)
228 shf->FlowReplace |= SERIAL_AUTO_RECEIVE;
229 if (port.c_iflag & IXON)
230 shf->FlowReplace |= SERIAL_AUTO_TRANSMIT;
234 return STATUS_SUCCESS;
237 static NTSTATUS get_line_control(int fd, SERIAL_LINE_CONTROL* slc)
241 if (tcgetattr(fd, &port) == -1)
243 ERR("tcgetattr error '%s'\n", strerror(errno));
244 return FILE_GetNtStatus();
248 switch (port.c_cflag & (PARENB | PARODD | CMSPAR))
250 switch (port.c_cflag & (PARENB | PARODD))
253 case 0: slc->Parity = NOPARITY; break;
254 case PARENB: slc->Parity = EVENPARITY; break;
255 case PARENB|PARODD: slc->Parity = ODDPARITY; break;
257 case PARENB|CMSPAR: slc->Parity = MARKPARITY; break;
258 case PARENB|PARODD|CMSPAR: slc->Parity = SPACEPARITY; break;
261 switch (port.c_cflag & CSIZE)
263 case CS5: slc->WordLength = 5; break;
264 case CS6: slc->WordLength = 6; break;
265 case CS7: slc->WordLength = 7; break;
266 case CS8: slc->WordLength = 8; break;
267 default: ERR("unknown size %x\n", (UINT)(port.c_cflag & CSIZE));
270 if (port.c_cflag & CSTOPB)
272 if (slc->WordLength == 5)
273 slc->StopBits = ONE5STOPBITS;
275 slc->StopBits = TWOSTOPBITS;
278 slc->StopBits = ONESTOPBIT;
280 return STATUS_SUCCESS;
283 static NTSTATUS get_modem_status(int fd, DWORD* lpModemStat)
285 NTSTATUS status = STATUS_SUCCESS;
289 if (ioctl(fd, TIOCMGET, &mstat) == -1)
291 WARN("ioctl failed\n");
292 status = FILE_GetNtStatus();
298 if (mstat & TIOCM_CTS) *lpModemStat |= MS_CTS_ON;
301 if (mstat & TIOCM_DSR) *lpModemStat |= MS_DSR_ON;
304 if (mstat & TIOCM_RNG) *lpModemStat |= MS_RING_ON;
307 /* FIXME: Not really sure about RLSD UB 990810 */
308 if (mstat & TIOCM_CAR) *lpModemStat |= MS_RLSD_ON;
310 TRACE("%04x -> %s%s%s%s\n", mstat,
311 (*lpModemStat & MS_RLSD_ON) ? "MS_RLSD_ON " : "",
312 (*lpModemStat & MS_RING_ON) ? "MS_RING_ON " : "",
313 (*lpModemStat & MS_DSR_ON) ? "MS_DSR_ON " : "",
314 (*lpModemStat & MS_CTS_ON) ? "MS_CTS_ON " : "");
317 status = STATUS_NOT_SUPPORTED;
322 static NTSTATUS get_special_chars(int fd, SERIAL_CHARS* sc)
326 if (tcgetattr(fd, &port) == -1)
328 ERR("tcgetattr error '%s'\n", strerror(errno));
329 return FILE_GetNtStatus();
331 sc->EofChar = port.c_cc[VEOF];
332 sc->ErrorChar = 0xFF;
333 sc->BreakChar = 0; /* FIXME */
334 sc->EventChar = 0; /* FIXME */
335 sc->XonChar = port.c_cc[VSTART];
336 sc->XoffChar = port.c_cc[VSTOP];
338 return STATUS_SUCCESS;
341 static NTSTATUS get_status(int fd, SERIAL_STATUS* ss)
343 NTSTATUS status = STATUS_SUCCESS;
347 ss->EofReceived = FALSE;
348 ss->WaitForImmediate = FALSE;
350 if (ioctl(fd, TIOCOUTQ, &ss->AmountInOutQueue) == -1)
352 WARN("ioctl returned error\n");
353 status = FILE_GetNtStatus();
356 ss->AmountInOutQueue = 0; /* FIXME: find a different way to find out */
360 if (ioctl(fd, TIOCINQ, &ss->AmountInInQueue))
362 WARN("ioctl returned error\n");
363 status = FILE_GetNtStatus();
366 ss->AmountInInQueue = 0; /* FIXME: find a different way to find out */
371 static NTSTATUS get_timeouts(HANDLE handle, SERIAL_TIMEOUTS* st)
374 SERVER_START_REQ( get_serial_info )
376 req->handle = handle;
377 if (!(status = wine_server_call( req )))
379 st->ReadIntervalTimeout = reply->readinterval;
380 st->ReadTotalTimeoutMultiplier = reply->readmult;
381 st->ReadTotalTimeoutConstant = reply->readconst;
382 st->WriteTotalTimeoutMultiplier = reply->writemult;
383 st->WriteTotalTimeoutConstant = reply->writeconst;
390 static NTSTATUS get_wait_mask(HANDLE hDevice, DWORD* mask)
394 SERVER_START_REQ( get_serial_info )
396 req->handle = hDevice;
397 if (!(status = wine_server_call( req )))
398 *mask = reply->eventmask;
404 static NTSTATUS purge(int fd, DWORD flags)
407 ** not exactly sure how these are different
408 ** Perhaps if we had our own internal queues, one flushes them
409 ** and the other flushes the kernel's buffers.
411 if (flags & PURGE_TXABORT) tcflush(fd, TCOFLUSH);
412 if (flags & PURGE_RXABORT) tcflush(fd, TCIFLUSH);
413 if (flags & PURGE_TXCLEAR) tcflush(fd, TCOFLUSH);
414 if (flags & PURGE_RXCLEAR) tcflush(fd, TCIFLUSH);
415 return STATUS_SUCCESS;
418 static NTSTATUS set_baud_rate(int fd, const SERIAL_BAUD_RATE* sbr)
422 if (tcgetattr(fd, &port) == -1)
424 ERR("tcgetattr error '%s'\n", strerror(errno));
425 return FILE_GetNtStatus();
429 port.c_cflag &= ~CBAUD;
430 switch (sbr->BaudRate)
432 case 0: port.c_cflag |= B0; break;
433 case 50: port.c_cflag |= B50; break;
434 case 75: port.c_cflag |= B75; break;
436 case CBR_110: port.c_cflag |= B110; break;
437 case 134: port.c_cflag |= B134; break;
438 case 150: port.c_cflag |= B150; break;
439 case 200: port.c_cflag |= B200; break;
441 case CBR_300: port.c_cflag |= B300; break;
443 case CBR_600: port.c_cflag |= B600; break;
445 case CBR_1200: port.c_cflag |= B1200; break;
446 case 1800: port.c_cflag |= B1800; break;
448 case CBR_2400: port.c_cflag |= B2400; break;
450 case CBR_4800: port.c_cflag |= B4800; break;
452 case CBR_9600: port.c_cflag |= B9600; break;
454 case CBR_19200: port.c_cflag |= B19200; break;
456 case CBR_38400: port.c_cflag |= B38400; break;
458 case 57600: port.c_cflag |= B57600; break;
461 case 115200: port.c_cflag |= B115200;break;
464 case 230400: port.c_cflag |= B230400;break;
467 case 460800: port.c_cflag |= B460800;break;
470 #if defined (HAVE_LINUX_SERIAL_H) && defined (TIOCSSERIAL)
472 struct serial_struct nuts;
475 ioctl(fd, TIOCGSERIAL, &nuts);
476 nuts.custom_divisor = nuts.baud_base / sbr->BaudRate;
477 if (!(nuts.custom_divisor)) nuts.custom_divisor = 1;
478 arby = nuts.baud_base / nuts.custom_divisor;
479 nuts.flags &= ~ASYNC_SPD_MASK;
480 nuts.flags |= ASYNC_SPD_CUST;
481 WARN("You (or a program acting at your behest) have specified\n"
482 "a non-standard baud rate %d. Wine will set the rate to %d,\n"
483 "which is as close as we can get by our present understanding of your\n"
484 "hardware. I hope you know what you are doing. Any disruption Wine\n"
485 "has caused to your linux system can be undone with setserial \n"
486 "(see man setserial). If you have incapacitated a Hayes type modem,\n"
487 "reset it and it will probably recover.\n", sbr->BaudRate, arby);
488 ioctl(fd, TIOCSSERIAL, &nuts);
489 port.c_cflag |= B38400;
492 #else /* Don't have linux/serial.h or lack TIOCSSERIAL */
493 ERR("baudrate %d\n", sbr->BaudRate);
494 return STATUS_NOT_SUPPORTED;
495 #endif /* Don't have linux/serial.h or lack TIOCSSERIAL */
497 #elif !defined(__EMX__)
498 switch (sbr->BaudRate)
500 case 0: port.c_ospeed = B0; break;
501 case 50: port.c_ospeed = B50; break;
502 case 75: port.c_ospeed = B75; break;
504 case CBR_110: port.c_ospeed = B110; break;
505 case 134: port.c_ospeed = B134; break;
506 case 150: port.c_ospeed = B150; break;
507 case 200: port.c_ospeed = B200; break;
509 case CBR_300: port.c_ospeed = B300; break;
511 case CBR_600: port.c_ospeed = B600; break;
513 case CBR_1200: port.c_ospeed = B1200; break;
514 case 1800: port.c_ospeed = B1800; break;
516 case CBR_2400: port.c_ospeed = B2400; break;
518 case CBR_4800: port.c_ospeed = B4800; break;
520 case CBR_9600: port.c_ospeed = B9600; break;
522 case CBR_19200: port.c_ospeed = B19200; break;
524 case CBR_38400: port.c_ospeed = B38400; break;
527 case CBR_57600: port.c_cflag |= B57600; break;
531 case CBR_115200: port.c_cflag |= B115200;break;
534 case 230400: port.c_cflag |= B230400;break;
537 case 460800: port.c_cflag |= B460800;break;
540 ERR("baudrate %d\n", sbr->BaudRate);
541 return STATUS_NOT_SUPPORTED;
543 port.c_ispeed = port.c_ospeed;
545 if (tcsetattr(fd, TCSANOW, &port) == -1)
547 ERR("tcsetattr error '%s'\n", strerror(errno));
548 return FILE_GetNtStatus();
550 return STATUS_SUCCESS;
553 static int whack_modem(int fd, unsigned int andy, unsigned int orrie)
556 unsigned int mstat, okay;
557 okay = ioctl(fd, TIOCMGET, &mstat);
558 if (okay) return okay;
559 if (andy) mstat &= andy;
561 return ioctl(fd, TIOCMSET, &mstat);
567 static NTSTATUS set_handflow(int fd, const SERIAL_HANDFLOW* shf)
571 if ((shf->FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE)) ==
572 (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE))
573 return STATUS_NOT_SUPPORTED;
575 if (tcgetattr(fd, &port) == -1)
577 ERR("tcgetattr error '%s'\n", strerror(errno));
578 return FILE_GetNtStatus();
582 if ((shf->ControlHandShake & SERIAL_CTS_HANDSHAKE) ||
583 (shf->FlowReplace & SERIAL_RTS_HANDSHAKE))
585 port.c_cflag |= CRTSCTS;
589 port.c_cflag &= ~CRTSCTS;
592 if (shf->ControlHandShake & SERIAL_DTR_HANDSHAKE)
594 WARN("DSR/DTR flow control not supported\n");
595 } else if (!(shf->ControlHandShake & SERIAL_DTR_CONTROL))
596 whack_modem(fd, ~TIOCM_DTR, 0);
598 whack_modem(fd, 0, TIOCM_DTR);
601 if (!(shf->ControlHandShake & SERIAL_CTS_HANDSHAKE))
603 if ((shf->FlowReplace & (SERIAL_RTS_CONTROL|SERIAL_RTS_HANDSHAKE)) == 0)
604 whack_modem(fd, ~TIOCM_RTS, 0);
606 whack_modem(fd, 0, TIOCM_RTS);
610 if (shf->FlowReplace & SERIAL_AUTO_RECEIVE)
611 port.c_iflag |= IXOFF;
613 port.c_iflag &= ~IXOFF;
614 if (shf->FlowReplace & SERIAL_AUTO_TRANSMIT)
615 port.c_iflag |= IXON;
617 port.c_iflag &= ~IXON;
618 if (tcsetattr(fd, TCSANOW, &port) == -1)
620 ERR("tcsetattr error '%s'\n", strerror(errno));
621 return FILE_GetNtStatus();
624 return STATUS_SUCCESS;
627 static NTSTATUS set_line_control(int fd, const SERIAL_LINE_CONTROL* slc)
630 unsigned bytesize, stopbits;
632 if (tcgetattr(fd, &port) == -1)
634 ERR("tcgetattr error '%s'\n", strerror(errno));
635 return FILE_GetNtStatus();
639 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK|IMAXBEL);
641 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK);
643 port.c_iflag |= IGNBRK | INPCK;
645 port.c_oflag &= ~(OPOST);
647 port.c_cflag &= ~(HUPCL);
648 port.c_cflag |= CLOCAL | CREAD;
650 port.c_lflag &= ~(ICANON|ECHO|ISIG);
651 port.c_lflag |= NOFLSH;
653 bytesize = slc->WordLength;
654 stopbits = slc->StopBits;
657 port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
659 port.c_cflag &= ~(PARENB | PARODD);
664 case NOPARITY: port.c_iflag &= ~INPCK; break;
665 case ODDPARITY: port.c_cflag |= PARENB | PARODD; break;
666 case EVENPARITY: port.c_cflag |= PARENB; break;
668 /* Linux defines mark/space (stick) parity */
669 case MARKPARITY: port.c_cflag |= PARENB | CMSPAR; break;
670 case SPACEPARITY: port.c_cflag |= PARENB | PARODD | CMSPAR; break;
672 /* try the POSIX way */
674 if (slc->StopBits == ONESTOPBIT)
676 stopbits = TWOSTOPBITS;
677 port.c_iflag &= ~INPCK;
681 ERR("Cannot set MARK Parity\n");
682 return STATUS_NOT_SUPPORTED;
686 if (slc->WordLength < 8)
689 port.c_iflag &= ~INPCK;
693 ERR("Cannot set SPACE Parity\n");
694 return STATUS_NOT_SUPPORTED;
700 return STATUS_NOT_SUPPORTED;
703 port.c_cflag &= ~CSIZE;
706 case 5: port.c_cflag |= CS5; break;
707 case 6: port.c_cflag |= CS6; break;
708 case 7: port.c_cflag |= CS7; break;
709 case 8: port.c_cflag |= CS8; break;
712 return STATUS_NOT_SUPPORTED;
717 case ONESTOPBIT: port.c_cflag &= ~CSTOPB; break;
718 case ONE5STOPBITS: /* will be selected if bytesize is 5 */
719 case TWOSTOPBITS: port.c_cflag |= CSTOPB; break;
722 return STATUS_NOT_SUPPORTED;
724 /* otherwise it hangs with pending input*/
725 if (tcsetattr(fd, TCSANOW, &port) == -1)
727 ERR("tcsetattr error '%s'\n", strerror(errno));
728 return FILE_GetNtStatus();
730 return STATUS_SUCCESS;
733 static NTSTATUS set_queue_size(int fd, const SERIAL_QUEUE_SIZE* sqs)
735 FIXME("insize %d outsize %d unimplemented stub\n", sqs->InSize, sqs->OutSize);
736 return STATUS_SUCCESS;
739 static NTSTATUS set_special_chars(int fd, const SERIAL_CHARS* sc)
743 if (tcgetattr(fd, &port) == -1)
745 ERR("tcgetattr error '%s'\n", strerror(errno));
746 return FILE_GetNtStatus();
749 port.c_cc[VMIN ] = 0;
750 port.c_cc[VTIME ] = 1;
752 port.c_cc[VEOF ] = sc->EofChar;
753 /* FIXME: sc->ErrorChar is not supported */
754 /* FIXME: sc->BreakChar is not supported */
755 /* FIXME: sc->EventChar is not supported */
756 port.c_cc[VSTART] = sc->XonChar;
757 port.c_cc[VSTOP ] = sc->XoffChar;
759 if (tcsetattr(fd, TCSANOW, &port) == -1)
761 ERR("tcsetattr error '%s'\n", strerror(errno));
762 return FILE_GetNtStatus();
764 return STATUS_SUCCESS;
767 static NTSTATUS set_timeouts(HANDLE handle, int fd, const SERIAL_TIMEOUTS* st)
771 unsigned int ux_timeout;
773 SERVER_START_REQ( set_serial_info )
775 req->handle = handle;
776 req->flags = SERIALINFO_SET_TIMEOUTS;
777 req->readinterval = st->ReadIntervalTimeout ;
778 req->readmult = st->ReadTotalTimeoutMultiplier ;
779 req->readconst = st->ReadTotalTimeoutConstant ;
780 req->writemult = st->WriteTotalTimeoutMultiplier ;
781 req->writeconst = st->WriteTotalTimeoutConstant ;
782 status = wine_server_call( req );
785 if (status) return status;
787 if (tcgetattr(fd, &port) == -1)
789 FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
790 return FILE_GetNtStatus();
793 /* VTIME is in 1/10 seconds */
794 if (st->ReadIntervalTimeout == 0) /* 0 means no timeout */
798 ux_timeout = (st->ReadIntervalTimeout + 99) / 100;
800 ux_timeout = 1; /* must be at least some timeout */
802 port.c_cc[VTIME] = ux_timeout;
804 if (tcsetattr(fd, 0, &port) == -1)
806 FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
807 return FILE_GetNtStatus();
809 return STATUS_SUCCESS;
812 static NTSTATUS set_wait_mask(HANDLE hDevice, DWORD mask)
816 SERVER_START_REQ( set_serial_info )
818 req->handle = hDevice;
819 req->flags = SERIALINFO_SET_MASK;
820 req->eventmask = mask;
821 status = wine_server_call( req );
827 static NTSTATUS set_XOff(int fd)
831 if (tcgetattr(fd,&port) == -1)
833 FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
834 return FILE_GetNtStatus();
838 port.c_iflag |= IXOFF;
839 if (tcsetattr(fd, TCSADRAIN, &port) == -1)
841 FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
842 return FILE_GetNtStatus();
844 return STATUS_SUCCESS;
847 static NTSTATUS set_XOn(int fd)
851 if (tcgetattr(fd,&port) == -1)
853 FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
854 return FILE_GetNtStatus();
856 port.c_iflag |= IXON;
857 if (tcsetattr(fd, TCSADRAIN, &port) == -1)
859 FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
860 return FILE_GetNtStatus();
862 return STATUS_SUCCESS;
866 * local structure holding the irq values we need for WaitCommEvent()
868 * Stripped down from struct serial_icounter_struct, which may not be available on some systems
869 * As the modem line interrupts (cts, dsr, rng, dcd) only get updated with TIOCMIWAIT active,
870 * no need to carry them in the internal structure
873 typedef struct serial_irq_info
875 int rx , tx, frame, overrun, parity, brk, buf_overrun;
878 /***********************************************************************
879 * Data needed by the thread polling for the changing CommEvent
881 typedef struct async_commio
888 serial_irq_info irq_info;
891 /***********************************************************************
892 * Get extended interrupt count info, needed for wait_on
894 static NTSTATUS get_irq_info(int fd, serial_irq_info *irq_info)
897 struct serial_icounter_struct einfo;
898 if (!ioctl(fd, TIOCGICOUNT, &einfo))
900 irq_info->rx = einfo.rx;
901 irq_info->tx = einfo.tx;
902 irq_info->frame = einfo.frame;
903 irq_info->overrun = einfo.overrun;
904 irq_info->parity = einfo.parity;
905 irq_info->brk = einfo.brk;
906 irq_info->buf_overrun = einfo.buf_overrun;
907 return STATUS_SUCCESS;
909 TRACE("TIOCGICOUNT err %s\n", strerror(errno));
910 return FILE_GetNtStatus();
912 memset(irq_info,0, sizeof(serial_irq_info));
913 return STATUS_NOT_IMPLEMENTED;
918 static DWORD WINAPI check_events(int fd, DWORD mask,
919 const serial_irq_info *new,
920 const serial_irq_info *old,
921 DWORD new_mstat, DWORD old_mstat)
923 DWORD ret = 0, queue;
925 TRACE("mask 0x%08x\n", mask);
926 TRACE("old->rx 0x%08x vs. new->rx 0x%08x\n", old->rx, new->rx);
927 TRACE("old->tx 0x%08x vs. new->tx 0x%08x\n", old->tx, new->tx);
928 TRACE("old->frame 0x%08x vs. new->frame 0x%08x\n", old->frame, new->frame);
929 TRACE("old->overrun 0x%08x vs. new->overrun 0x%08x\n", old->overrun, new->overrun);
930 TRACE("old->parity 0x%08x vs. new->parity 0x%08x\n", old->parity, new->parity);
931 TRACE("old->brk 0x%08x vs. new->brk 0x%08x\n", old->brk, new->brk);
932 TRACE("old->buf_overrun 0x%08x vs. new->buf_overrun 0x%08x\n", old->buf_overrun, new->buf_overrun);
934 if (old->brk != new->brk) ret |= EV_BREAK;
935 if ((old_mstat & MS_CTS_ON ) != (new_mstat & MS_CTS_ON )) ret |= EV_CTS;
936 if ((old_mstat & MS_DSR_ON ) != (new_mstat & MS_DSR_ON )) ret |= EV_DSR;
937 if ((old_mstat & MS_RING_ON) != (new_mstat & MS_RING_ON)) ret |= EV_RING;
938 if ((old_mstat & MS_RLSD_ON) != (new_mstat & MS_RLSD_ON)) ret |= EV_RLSD;
939 if (old->frame != new->frame || old->overrun != new->overrun || old->parity != new->parity) ret |= EV_ERR;
940 if (mask & EV_RXCHAR)
944 if (ioctl(fd, TIOCINQ, &queue))
945 WARN("TIOCINQ returned error\n");
950 if (mask & EV_TXEMPTY)
953 /* We really want to know when all characters have gone out of the transmitter */
954 #if defined(TIOCSERGETLSR)
955 if (ioctl(fd, TIOCSERGETLSR, &queue))
956 WARN("TIOCSERGETLSR returned error\n");
958 /* TIOCOUTQ only checks for an empty buffer */
959 #elif defined(TIOCOUTQ)
960 if (ioctl(fd, TIOCOUTQ, &queue))
961 WARN("TIOCOUTQ returned error\n");
965 TRACE("OUTQUEUE %d, Transmitter %sempty\n",
966 queue, (ret & EV_TXEMPTY) ? "" : "not ");
971 /***********************************************************************
972 * wait_for_event (INTERNAL)
974 * We need to poll for what is interesting
975 * TIOCMIWAIT only checks modem status line and may not be aborted by a changing mask
978 static DWORD CALLBACK wait_for_event(LPVOID arg)
980 async_commio *commio = (async_commio*) arg;
983 if (!server_get_unix_fd( commio->hDevice, FILE_READ_DATA | FILE_WRITE_DATA, &fd, &needs_close, NULL, NULL ))
985 serial_irq_info new_irq_info;
986 DWORD new_mstat, new_evtmask;
989 TRACE("device=%p fd=0x%08x mask=0x%08x buffer=%p event=%p irq_info=%p\n",
990 commio->hDevice, fd, commio->evtmask, commio->events, commio->hEvent, &commio->irq_info);
992 time.QuadPart = (ULONGLONG)10000;
993 time.QuadPart = -time.QuadPart;
997 * TIOCMIWAIT is not adequate
1000 * We don't handle the EV_RXFLAG (the eventchar)
1002 NtDelayExecution(FALSE, &time);
1003 get_irq_info(fd, &new_irq_info);
1004 if (get_modem_status(fd, &new_mstat))
1005 TRACE("get_modem_status failed\n");
1006 *commio->events = check_events(fd, commio->evtmask,
1007 &new_irq_info, &commio->irq_info,
1008 new_mstat, commio->mstat);
1009 if (*commio->events) break;
1010 get_wait_mask(commio->hDevice, &new_evtmask);
1011 if (commio->evtmask != new_evtmask)
1013 *commio->events = 0;
1017 if (needs_close) close( fd );
1019 if (commio->hEvent) NtSetEvent(commio->hEvent, NULL);
1020 RtlFreeHeap(GetProcessHeap(), 0, commio);
1024 static NTSTATUS wait_on(HANDLE hDevice, int fd, HANDLE hEvent, DWORD* events)
1026 async_commio* commio;
1029 if ((status = NtResetEvent(hEvent, NULL)))
1032 commio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof (async_commio));
1033 if (!commio) return STATUS_NO_MEMORY;
1035 commio->hDevice = hDevice;
1036 commio->events = events;
1037 commio->hEvent = hEvent;
1038 get_wait_mask(commio->hDevice, &commio->evtmask);
1040 /* We may never return, if some capabilities miss
1041 * Return error in that case
1043 #if !defined(TIOCINQ)
1044 if (commio->evtmask & EV_RXCHAR)
1047 #if !(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)
1048 if (commio->evtmask & EV_TXEMPTY)
1051 #if !defined(TIOCMGET)
1052 if (commio->evtmask & (EV_CTS | EV_DSR| EV_RING| EV_RLSD))
1055 #if !defined(TIOCM_CTS)
1056 if (commio->evtmask & EV_CTS)
1059 #if !defined(TIOCM_DSR)
1060 if (commio->evtmask & EV_DSR)
1063 #if !defined(TIOCM_RNG)
1064 if (commio->evtmask & EV_RING)
1067 #if !defined(TIOCM_CAR)
1068 if (commio->evtmask & EV_RLSD)
1071 if (commio->evtmask & EV_RXFLAG)
1072 FIXME("EV_RXFLAG not handled\n");
1073 if ((status = get_irq_info(fd, &commio->irq_info)) ||
1074 (status = get_modem_status(fd, &commio->mstat)))
1077 /* We might have received something or the TX bufffer is delivered */
1078 *events = check_events(fd, commio->evtmask,
1079 &commio->irq_info, &commio->irq_info,
1080 commio->mstat, commio->mstat);
1081 if (*events) goto out_now;
1083 /* create the worker for the task */
1084 status = RtlQueueWorkItem(wait_for_event, commio, 0 /* FIXME */);
1085 if (status != STATUS_SUCCESS) goto out_now;
1086 return STATUS_PENDING;
1088 #if !defined(TIOCINQ) || (!(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)) || !defined(TIOCMGET) || !defined(TIOCM_CTS) ||!defined(TIOCM_DSR) || !defined(TIOCM_RNG) || !defined(TIOCM_CAR)
1090 FIXME("Returning error because of missing capabilities\n");
1091 status = STATUS_INVALID_PARAMETER;
1094 RtlFreeHeap(GetProcessHeap(), 0, commio);
1098 static NTSTATUS xmit_immediate(HANDLE hDevice, int fd, const char* ptr)
1100 /* FIXME: not perfect as it should bypass the in-queue */
1101 WARN("(%p,'%c') not perfect!\n", hDevice, *ptr);
1102 if (write(fd, ptr, 1) != 1)
1103 return FILE_GetNtStatus();
1104 return STATUS_SUCCESS;
1107 /******************************************************************
1108 * COMM_DeviceIoControl
1112 static inline NTSTATUS io_control(HANDLE hDevice,
1113 HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
1114 PVOID UserApcContext,
1115 PIO_STATUS_BLOCK piosb,
1116 ULONG dwIoControlCode,
1117 LPVOID lpInBuffer, DWORD nInBufferSize,
1118 LPVOID lpOutBuffer, DWORD nOutBufferSize)
1120 DWORD sz = 0, access = FILE_READ_DATA;
1121 NTSTATUS status = STATUS_SUCCESS;
1122 int fd = -1, needs_close = 0;
1124 TRACE("%p %s %p %d %p %d %p\n",
1125 hDevice, iocode2str(dwIoControlCode), lpInBuffer, nInBufferSize,
1126 lpOutBuffer, nOutBufferSize, piosb);
1128 piosb->Information = 0;
1130 if (dwIoControlCode != IOCTL_SERIAL_GET_TIMEOUTS)
1131 if ((status = server_get_unix_fd( hDevice, access, &fd, &needs_close, NULL, NULL )))
1134 switch (dwIoControlCode)
1136 case IOCTL_SERIAL_CLR_DTR:
1138 if (whack_modem(fd, ~TIOCM_DTR, 0) == -1) status = FILE_GetNtStatus();
1140 status = STATUS_NOT_SUPPORTED;
1143 case IOCTL_SERIAL_CLR_RTS:
1145 if (whack_modem(fd, ~TIOCM_RTS, 0) == -1) status = FILE_GetNtStatus();
1147 status = STATUS_NOT_SUPPORTED;
1150 case IOCTL_SERIAL_GET_BAUD_RATE:
1151 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_BAUD_RATE))
1153 if (!(status = get_baud_rate(fd, (SERIAL_BAUD_RATE*)lpOutBuffer)))
1154 sz = sizeof(SERIAL_BAUD_RATE);
1157 status = STATUS_INVALID_PARAMETER;
1159 case IOCTL_SERIAL_GET_CHARS:
1160 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_CHARS))
1162 if (!(status = get_special_chars(fd, (SERIAL_CHARS*)lpOutBuffer)))
1163 sz = sizeof(SERIAL_CHARS);
1166 status = STATUS_INVALID_PARAMETER;
1168 case IOCTL_SERIAL_GET_COMMSTATUS:
1169 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_STATUS))
1171 if (!(status = get_status(fd, (SERIAL_STATUS*)lpOutBuffer)))
1172 sz = sizeof(SERIAL_STATUS);
1174 else status = STATUS_INVALID_PARAMETER;
1176 case IOCTL_SERIAL_GET_HANDFLOW:
1177 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_HANDFLOW))
1179 if (!(status = get_hand_flow(fd, (SERIAL_HANDFLOW*)lpOutBuffer)))
1180 sz = sizeof(SERIAL_HANDFLOW);
1183 status = STATUS_INVALID_PARAMETER;
1185 case IOCTL_SERIAL_GET_LINE_CONTROL:
1186 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_LINE_CONTROL))
1188 if (!(status = get_line_control(fd, (SERIAL_LINE_CONTROL*)lpOutBuffer)))
1189 sz = sizeof(SERIAL_LINE_CONTROL);
1192 status = STATUS_INVALID_PARAMETER;
1194 case IOCTL_SERIAL_GET_MODEMSTATUS:
1195 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1197 if (!(status = get_modem_status(fd, (DWORD*)lpOutBuffer)))
1200 else status = STATUS_INVALID_PARAMETER;
1202 case IOCTL_SERIAL_GET_TIMEOUTS:
1203 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_TIMEOUTS))
1205 if (!(status = get_timeouts(hDevice, (SERIAL_TIMEOUTS*)lpOutBuffer)))
1206 sz = sizeof(SERIAL_TIMEOUTS);
1209 status = STATUS_INVALID_PARAMETER;
1211 case IOCTL_SERIAL_GET_WAIT_MASK:
1212 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1214 if (!(status = get_wait_mask(hDevice, (DWORD*)lpOutBuffer)))
1218 status = STATUS_INVALID_PARAMETER;
1220 case IOCTL_SERIAL_IMMEDIATE_CHAR:
1221 if (lpInBuffer && nInBufferSize == sizeof(CHAR))
1222 status = xmit_immediate(hDevice, fd, lpInBuffer);
1224 status = STATUS_INVALID_PARAMETER;
1226 case IOCTL_SERIAL_PURGE:
1227 if (lpInBuffer && nInBufferSize == sizeof(DWORD))
1228 status = purge(fd, *(DWORD*)lpInBuffer);
1230 status = STATUS_INVALID_PARAMETER;
1232 case IOCTL_SERIAL_RESET_DEVICE:
1233 FIXME("Unsupported\n");
1235 case IOCTL_SERIAL_SET_BAUD_RATE:
1236 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_BAUD_RATE))
1237 status = set_baud_rate(fd, (const SERIAL_BAUD_RATE*)lpInBuffer);
1239 status = STATUS_INVALID_PARAMETER;
1241 case IOCTL_SERIAL_SET_BREAK_OFF:
1242 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1243 if (ioctl(fd, TIOCCBRK, 0) == -1)
1245 TRACE("ioctl failed\n");
1246 status = FILE_GetNtStatus();
1249 FIXME("ioctl not available\n");
1250 status = STATUS_NOT_SUPPORTED;
1253 case IOCTL_SERIAL_SET_BREAK_ON:
1254 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1255 if (ioctl(fd, TIOCSBRK, 0) == -1)
1257 TRACE("ioctl failed\n");
1258 status = FILE_GetNtStatus();
1261 FIXME("ioctl not available\n");
1262 status = STATUS_NOT_SUPPORTED;
1265 case IOCTL_SERIAL_SET_CHARS:
1266 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_CHARS))
1267 status = set_special_chars(fd, (const SERIAL_CHARS*)lpInBuffer);
1269 status = STATUS_INVALID_PARAMETER;
1271 case IOCTL_SERIAL_SET_DTR:
1273 if (whack_modem(fd, 0, TIOCM_DTR) == -1) status = FILE_GetNtStatus();
1275 status = STATUS_NOT_SUPPORTED;
1278 case IOCTL_SERIAL_SET_HANDFLOW:
1279 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_HANDFLOW))
1280 status = set_handflow(fd, (const SERIAL_HANDFLOW*)lpInBuffer);
1282 status = STATUS_INVALID_PARAMETER;
1284 case IOCTL_SERIAL_SET_LINE_CONTROL:
1285 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_LINE_CONTROL))
1286 status = set_line_control(fd, (const SERIAL_LINE_CONTROL*)lpInBuffer);
1288 status = STATUS_INVALID_PARAMETER;
1290 case IOCTL_SERIAL_SET_QUEUE_SIZE:
1291 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_QUEUE_SIZE))
1292 status = set_queue_size(fd, (const SERIAL_QUEUE_SIZE*)lpInBuffer);
1294 status = STATUS_INVALID_PARAMETER;
1296 case IOCTL_SERIAL_SET_RTS:
1298 if (whack_modem(fd, 0, TIOCM_RTS) == -1) status = FILE_GetNtStatus();
1300 status = STATUS_NOT_SUPPORTED;
1303 case IOCTL_SERIAL_SET_TIMEOUTS:
1304 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_TIMEOUTS))
1305 status = set_timeouts(hDevice, fd, (const SERIAL_TIMEOUTS*)lpInBuffer);
1307 status = STATUS_INVALID_PARAMETER;
1309 case IOCTL_SERIAL_SET_WAIT_MASK:
1310 if (lpInBuffer && nInBufferSize == sizeof(DWORD))
1312 status = set_wait_mask(hDevice, *(DWORD*)lpInBuffer);
1314 else status = STATUS_INVALID_PARAMETER;
1316 case IOCTL_SERIAL_SET_XOFF:
1317 status = set_XOff(fd);
1319 case IOCTL_SERIAL_SET_XON:
1320 status = set_XOn(fd);
1322 case IOCTL_SERIAL_WAIT_ON_MASK:
1323 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1325 if (!(status = wait_on(hDevice, fd, hEvent, (DWORD*)lpOutBuffer)))
1329 status = STATUS_INVALID_PARAMETER;
1332 FIXME("Unsupported IOCTL %x (type=%x access=%x func=%x meth=%x)\n",
1333 dwIoControlCode, dwIoControlCode >> 16, (dwIoControlCode >> 14) & 3,
1334 (dwIoControlCode >> 2) & 0xFFF, dwIoControlCode & 3);
1336 status = STATUS_INVALID_PARAMETER;
1339 if (needs_close) close( fd );
1341 piosb->u.Status = status;
1342 piosb->Information = sz;
1343 if (hEvent && status != STATUS_PENDING) NtSetEvent(hEvent, NULL);
1347 NTSTATUS COMM_DeviceIoControl(HANDLE hDevice,
1348 HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
1349 PVOID UserApcContext,
1350 PIO_STATUS_BLOCK piosb,
1351 ULONG dwIoControlCode,
1352 LPVOID lpInBuffer, DWORD nInBufferSize,
1353 LPVOID lpOutBuffer, DWORD nOutBufferSize)
1357 if (dwIoControlCode == IOCTL_SERIAL_WAIT_ON_MASK)
1359 HANDLE hev = hEvent;
1361 /* this is an ioctl we implement in a non blocking way if hEvent is not
1363 * so we have to explicitely wait if no hEvent is provided
1367 OBJECT_ATTRIBUTES attr;
1369 attr.Length = sizeof(attr);
1370 attr.RootDirectory = 0;
1371 attr.ObjectName = NULL;
1372 attr.Attributes = OBJ_CASE_INSENSITIVE | OBJ_OPENIF;
1373 attr.SecurityDescriptor = NULL;
1374 attr.SecurityQualityOfService = NULL;
1375 status = NtCreateEvent(&hev, EVENT_ALL_ACCESS, &attr, FALSE, FALSE);
1377 if (status) goto done;
1379 status = io_control(hDevice, hev, UserApcRoutine, UserApcContext,
1380 piosb, dwIoControlCode, lpInBuffer, nInBufferSize,
1381 lpOutBuffer, nOutBufferSize);
1384 if (status == STATUS_PENDING)
1386 NtWaitForSingleObject(hev, FALSE, NULL);
1387 status = STATUS_SUCCESS;
1392 else status = io_control(hDevice, hEvent, UserApcRoutine, UserApcContext,
1393 piosb, dwIoControlCode, lpInBuffer, nInBufferSize,
1394 lpOutBuffer, nOutBufferSize);