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_NOT_SUPPORTED;
295 if (!ioctl(fd, TIOCMGET, &mstat))
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 " : "");
315 return STATUS_SUCCESS;
317 WARN("ioctl failed\n");
318 status = FILE_GetNtStatus();
323 static NTSTATUS get_special_chars(int fd, SERIAL_CHARS* sc)
327 if (tcgetattr(fd, &port) == -1)
329 ERR("tcgetattr error '%s'\n", strerror(errno));
330 return FILE_GetNtStatus();
332 sc->EofChar = port.c_cc[VEOF];
333 sc->ErrorChar = 0xFF;
334 sc->BreakChar = 0; /* FIXME */
335 sc->EventChar = 0; /* FIXME */
336 sc->XonChar = port.c_cc[VSTART];
337 sc->XoffChar = port.c_cc[VSTOP];
339 return STATUS_SUCCESS;
342 static NTSTATUS get_status(int fd, SERIAL_STATUS* ss)
344 NTSTATUS status = STATUS_SUCCESS;
348 ss->EofReceived = FALSE;
349 ss->WaitForImmediate = FALSE;
351 if (ioctl(fd, TIOCOUTQ, &ss->AmountInOutQueue) == -1)
353 WARN("ioctl returned error\n");
354 status = FILE_GetNtStatus();
357 ss->AmountInOutQueue = 0; /* FIXME: find a different way to find out */
361 if (ioctl(fd, TIOCINQ, &ss->AmountInInQueue))
363 WARN("ioctl returned error\n");
364 status = FILE_GetNtStatus();
367 ss->AmountInInQueue = 0; /* FIXME: find a different way to find out */
372 static NTSTATUS get_timeouts(HANDLE handle, SERIAL_TIMEOUTS* st)
375 SERVER_START_REQ( get_serial_info )
377 req->handle = handle;
378 if (!(status = wine_server_call( req )))
380 st->ReadIntervalTimeout = reply->readinterval;
381 st->ReadTotalTimeoutMultiplier = reply->readmult;
382 st->ReadTotalTimeoutConstant = reply->readconst;
383 st->WriteTotalTimeoutMultiplier = reply->writemult;
384 st->WriteTotalTimeoutConstant = reply->writeconst;
391 static NTSTATUS get_wait_mask(HANDLE hDevice, DWORD* mask)
395 SERVER_START_REQ( get_serial_info )
397 req->handle = hDevice;
398 if (!(status = wine_server_call( req )))
399 *mask = reply->eventmask;
405 static NTSTATUS purge(int fd, DWORD flags)
408 ** not exactly sure how these are different
409 ** Perhaps if we had our own internal queues, one flushes them
410 ** and the other flushes the kernel's buffers.
412 if (flags & PURGE_TXABORT) tcflush(fd, TCOFLUSH);
413 if (flags & PURGE_RXABORT) tcflush(fd, TCIFLUSH);
414 if (flags & PURGE_TXCLEAR) tcflush(fd, TCOFLUSH);
415 if (flags & PURGE_RXCLEAR) tcflush(fd, TCIFLUSH);
416 return STATUS_SUCCESS;
419 static NTSTATUS set_baud_rate(int fd, const SERIAL_BAUD_RATE* sbr)
423 if (tcgetattr(fd, &port) == -1)
425 ERR("tcgetattr error '%s'\n", strerror(errno));
426 return FILE_GetNtStatus();
430 port.c_cflag &= ~CBAUD;
431 switch (sbr->BaudRate)
433 case 0: port.c_cflag |= B0; break;
434 case 50: port.c_cflag |= B50; break;
435 case 75: port.c_cflag |= B75; break;
437 case CBR_110: port.c_cflag |= B110; break;
438 case 134: port.c_cflag |= B134; break;
439 case 150: port.c_cflag |= B150; break;
440 case 200: port.c_cflag |= B200; break;
442 case CBR_300: port.c_cflag |= B300; break;
444 case CBR_600: port.c_cflag |= B600; break;
446 case CBR_1200: port.c_cflag |= B1200; break;
447 case 1800: port.c_cflag |= B1800; break;
449 case CBR_2400: port.c_cflag |= B2400; break;
451 case CBR_4800: port.c_cflag |= B4800; break;
453 case CBR_9600: port.c_cflag |= B9600; break;
455 case CBR_19200: port.c_cflag |= B19200; break;
457 case CBR_38400: port.c_cflag |= B38400; break;
459 case 57600: port.c_cflag |= B57600; break;
462 case 115200: port.c_cflag |= B115200;break;
465 case 230400: port.c_cflag |= B230400;break;
468 case 460800: port.c_cflag |= B460800;break;
471 #if defined (HAVE_LINUX_SERIAL_H) && defined (TIOCSSERIAL)
473 struct serial_struct nuts;
476 ioctl(fd, TIOCGSERIAL, &nuts);
477 nuts.custom_divisor = nuts.baud_base / sbr->BaudRate;
478 if (!(nuts.custom_divisor)) nuts.custom_divisor = 1;
479 arby = nuts.baud_base / nuts.custom_divisor;
480 nuts.flags &= ~ASYNC_SPD_MASK;
481 nuts.flags |= ASYNC_SPD_CUST;
482 WARN("You (or a program acting at your behest) have specified\n"
483 "a non-standard baud rate %d. Wine will set the rate to %d,\n"
484 "which is as close as we can get by our present understanding of your\n"
485 "hardware. I hope you know what you are doing. Any disruption Wine\n"
486 "has caused to your linux system can be undone with setserial \n"
487 "(see man setserial). If you have incapacitated a Hayes type modem,\n"
488 "reset it and it will probably recover.\n", sbr->BaudRate, arby);
489 ioctl(fd, TIOCSSERIAL, &nuts);
490 port.c_cflag |= B38400;
493 #else /* Don't have linux/serial.h or lack TIOCSSERIAL */
494 ERR("baudrate %d\n", sbr->BaudRate);
495 return STATUS_NOT_SUPPORTED;
496 #endif /* Don't have linux/serial.h or lack TIOCSSERIAL */
498 #elif !defined(__EMX__)
499 switch (sbr->BaudRate)
501 case 0: port.c_ospeed = B0; break;
502 case 50: port.c_ospeed = B50; break;
503 case 75: port.c_ospeed = B75; break;
505 case CBR_110: port.c_ospeed = B110; break;
506 case 134: port.c_ospeed = B134; break;
507 case 150: port.c_ospeed = B150; break;
508 case 200: port.c_ospeed = B200; break;
510 case CBR_300: port.c_ospeed = B300; break;
512 case CBR_600: port.c_ospeed = B600; break;
514 case CBR_1200: port.c_ospeed = B1200; break;
515 case 1800: port.c_ospeed = B1800; break;
517 case CBR_2400: port.c_ospeed = B2400; break;
519 case CBR_4800: port.c_ospeed = B4800; break;
521 case CBR_9600: port.c_ospeed = B9600; break;
523 case CBR_19200: port.c_ospeed = B19200; break;
525 case CBR_38400: port.c_ospeed = B38400; break;
528 case CBR_57600: port.c_cflag |= B57600; break;
532 case CBR_115200: port.c_cflag |= B115200;break;
535 case 230400: port.c_cflag |= B230400;break;
538 case 460800: port.c_cflag |= B460800;break;
541 ERR("baudrate %d\n", sbr->BaudRate);
542 return STATUS_NOT_SUPPORTED;
544 port.c_ispeed = port.c_ospeed;
546 if (tcsetattr(fd, TCSANOW, &port) == -1)
548 ERR("tcsetattr error '%s'\n", strerror(errno));
549 return FILE_GetNtStatus();
551 return STATUS_SUCCESS;
554 static int whack_modem(int fd, unsigned int andy, unsigned int orrie)
557 unsigned int mstat, okay;
558 okay = ioctl(fd, TIOCMGET, &mstat);
559 if (okay) return okay;
560 if (andy) mstat &= andy;
562 return ioctl(fd, TIOCMSET, &mstat);
568 static NTSTATUS set_handflow(int fd, const SERIAL_HANDFLOW* shf)
572 if ((shf->FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE)) ==
573 (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE))
574 return STATUS_NOT_SUPPORTED;
576 if (tcgetattr(fd, &port) == -1)
578 ERR("tcgetattr error '%s'\n", strerror(errno));
579 return FILE_GetNtStatus();
583 if ((shf->ControlHandShake & SERIAL_CTS_HANDSHAKE) ||
584 (shf->FlowReplace & SERIAL_RTS_HANDSHAKE))
586 port.c_cflag |= CRTSCTS;
590 port.c_cflag &= ~CRTSCTS;
593 if (shf->ControlHandShake & SERIAL_DTR_HANDSHAKE)
595 WARN("DSR/DTR flow control not supported\n");
596 } else if (!(shf->ControlHandShake & SERIAL_DTR_CONTROL))
597 whack_modem(fd, ~TIOCM_DTR, 0);
599 whack_modem(fd, 0, TIOCM_DTR);
602 if (!(shf->ControlHandShake & SERIAL_CTS_HANDSHAKE))
604 if ((shf->FlowReplace & (SERIAL_RTS_CONTROL|SERIAL_RTS_HANDSHAKE)) == 0)
605 whack_modem(fd, ~TIOCM_RTS, 0);
607 whack_modem(fd, 0, TIOCM_RTS);
611 if (shf->FlowReplace & SERIAL_AUTO_RECEIVE)
612 port.c_iflag |= IXOFF;
614 port.c_iflag &= ~IXOFF;
615 if (shf->FlowReplace & SERIAL_AUTO_TRANSMIT)
616 port.c_iflag |= IXON;
618 port.c_iflag &= ~IXON;
619 if (tcsetattr(fd, TCSANOW, &port) == -1)
621 ERR("tcsetattr error '%s'\n", strerror(errno));
622 return FILE_GetNtStatus();
625 return STATUS_SUCCESS;
628 static NTSTATUS set_line_control(int fd, const SERIAL_LINE_CONTROL* slc)
631 unsigned bytesize, stopbits;
633 if (tcgetattr(fd, &port) == -1)
635 ERR("tcgetattr error '%s'\n", strerror(errno));
636 return FILE_GetNtStatus();
640 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK|IMAXBEL);
642 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK);
644 port.c_iflag |= IGNBRK | INPCK;
646 port.c_oflag &= ~(OPOST);
648 port.c_cflag &= ~(HUPCL);
649 port.c_cflag |= CLOCAL | CREAD;
651 port.c_lflag &= ~(ICANON|ECHO|ISIG);
652 port.c_lflag |= NOFLSH;
654 bytesize = slc->WordLength;
655 stopbits = slc->StopBits;
658 port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
660 port.c_cflag &= ~(PARENB | PARODD);
663 /* make sure that reads don't block */
665 port.c_cc[VTIME] = 0;
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[VEOF ] = sc->EofChar;
755 /* FIXME: sc->ErrorChar is not supported */
756 /* FIXME: sc->BreakChar is not supported */
757 /* FIXME: sc->EventChar is not supported */
758 port.c_cc[VSTART] = sc->XonChar;
759 port.c_cc[VSTOP ] = sc->XoffChar;
761 if (tcsetattr(fd, TCSANOW, &port) == -1)
763 ERR("tcsetattr error '%s'\n", strerror(errno));
764 return FILE_GetNtStatus();
766 return STATUS_SUCCESS;
769 static NTSTATUS set_timeouts(HANDLE handle, const SERIAL_TIMEOUTS* st)
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 );
788 static NTSTATUS set_wait_mask(HANDLE hDevice, DWORD mask)
792 SERVER_START_REQ( set_serial_info )
794 req->handle = hDevice;
795 req->flags = SERIALINFO_SET_MASK;
796 req->eventmask = mask;
797 status = wine_server_call( req );
803 static NTSTATUS set_XOff(int fd)
807 if (tcgetattr(fd,&port) == -1)
809 FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
810 return FILE_GetNtStatus();
814 port.c_iflag |= IXOFF;
815 if (tcsetattr(fd, TCSADRAIN, &port) == -1)
817 FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
818 return FILE_GetNtStatus();
820 return STATUS_SUCCESS;
823 static NTSTATUS set_XOn(int fd)
827 if (tcgetattr(fd,&port) == -1)
829 FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
830 return FILE_GetNtStatus();
832 port.c_iflag |= IXON;
833 if (tcsetattr(fd, TCSADRAIN, &port) == -1)
835 FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
836 return FILE_GetNtStatus();
838 return STATUS_SUCCESS;
842 * local structure holding the irq values we need for WaitCommEvent()
844 * Stripped down from struct serial_icounter_struct, which may not be available on some systems
845 * As the modem line interrupts (cts, dsr, rng, dcd) only get updated with TIOCMIWAIT active,
846 * no need to carry them in the internal structure
849 typedef struct serial_irq_info
851 int rx , tx, frame, overrun, parity, brk, buf_overrun;
854 /***********************************************************************
855 * Data needed by the thread polling for the changing CommEvent
857 typedef struct async_commio
864 serial_irq_info irq_info;
867 /***********************************************************************
868 * Get extended interrupt count info, needed for wait_on
870 static NTSTATUS get_irq_info(int fd, serial_irq_info *irq_info)
872 NTSTATUS status = STATUS_NOT_IMPLEMENTED;
874 struct serial_icounter_struct einfo;
875 if (!ioctl(fd, TIOCGICOUNT, &einfo))
877 irq_info->rx = einfo.rx;
878 irq_info->tx = einfo.tx;
879 irq_info->frame = einfo.frame;
880 irq_info->overrun = einfo.overrun;
881 irq_info->parity = einfo.parity;
882 irq_info->brk = einfo.brk;
883 irq_info->buf_overrun = einfo.buf_overrun;
884 return STATUS_SUCCESS;
886 TRACE("TIOCGICOUNT err %s\n", strerror(errno));
887 status = FILE_GetNtStatus();
889 memset(irq_info,0, sizeof(serial_irq_info));
894 static DWORD WINAPI check_events(int fd, DWORD mask,
895 const serial_irq_info *new,
896 const serial_irq_info *old,
897 DWORD new_mstat, DWORD old_mstat)
899 DWORD ret = 0, queue;
901 TRACE("mask 0x%08x\n", mask);
902 TRACE("old->rx 0x%08x vs. new->rx 0x%08x\n", old->rx, new->rx);
903 TRACE("old->tx 0x%08x vs. new->tx 0x%08x\n", old->tx, new->tx);
904 TRACE("old->frame 0x%08x vs. new->frame 0x%08x\n", old->frame, new->frame);
905 TRACE("old->overrun 0x%08x vs. new->overrun 0x%08x\n", old->overrun, new->overrun);
906 TRACE("old->parity 0x%08x vs. new->parity 0x%08x\n", old->parity, new->parity);
907 TRACE("old->brk 0x%08x vs. new->brk 0x%08x\n", old->brk, new->brk);
908 TRACE("old->buf_overrun 0x%08x vs. new->buf_overrun 0x%08x\n", old->buf_overrun, new->buf_overrun);
910 if (old->brk != new->brk) ret |= EV_BREAK;
911 if ((old_mstat & MS_CTS_ON ) != (new_mstat & MS_CTS_ON )) ret |= EV_CTS;
912 if ((old_mstat & MS_DSR_ON ) != (new_mstat & MS_DSR_ON )) ret |= EV_DSR;
913 if ((old_mstat & MS_RING_ON) != (new_mstat & MS_RING_ON)) ret |= EV_RING;
914 if ((old_mstat & MS_RLSD_ON) != (new_mstat & MS_RLSD_ON)) ret |= EV_RLSD;
915 if (old->frame != new->frame || old->overrun != new->overrun || old->parity != new->parity) ret |= EV_ERR;
916 if (mask & EV_RXCHAR)
920 if (ioctl(fd, TIOCINQ, &queue))
921 WARN("TIOCINQ returned error\n");
926 if (mask & EV_TXEMPTY)
929 /* We really want to know when all characters have gone out of the transmitter */
930 #if defined(TIOCSERGETLSR)
931 if (ioctl(fd, TIOCSERGETLSR, &queue))
932 WARN("TIOCSERGETLSR returned error\n");
934 /* TIOCOUTQ only checks for an empty buffer */
935 #elif defined(TIOCOUTQ)
936 if (ioctl(fd, TIOCOUTQ, &queue))
937 WARN("TIOCOUTQ returned error\n");
941 TRACE("OUTQUEUE %d, Transmitter %sempty\n",
942 queue, (ret & EV_TXEMPTY) ? "" : "not ");
947 /***********************************************************************
948 * wait_for_event (INTERNAL)
950 * We need to poll for what is interesting
951 * TIOCMIWAIT only checks modem status line and may not be aborted by a changing mask
954 static DWORD CALLBACK wait_for_event(LPVOID arg)
956 async_commio *commio = (async_commio*) arg;
959 if (!server_get_unix_fd( commio->hDevice, FILE_READ_DATA | FILE_WRITE_DATA, &fd, &needs_close, NULL, NULL ))
961 serial_irq_info new_irq_info;
962 DWORD new_mstat, new_evtmask;
965 TRACE("device=%p fd=0x%08x mask=0x%08x buffer=%p event=%p irq_info=%p\n",
966 commio->hDevice, fd, commio->evtmask, commio->events, commio->hEvent, &commio->irq_info);
968 time.QuadPart = (ULONGLONG)10000;
969 time.QuadPart = -time.QuadPart;
973 * TIOCMIWAIT is not adequate
976 * We don't handle the EV_RXFLAG (the eventchar)
978 NtDelayExecution(FALSE, &time);
979 get_irq_info(fd, &new_irq_info);
980 if (get_modem_status(fd, &new_mstat))
981 TRACE("get_modem_status failed\n");
982 *commio->events = check_events(fd, commio->evtmask,
983 &new_irq_info, &commio->irq_info,
984 new_mstat, commio->mstat);
985 if (*commio->events) break;
986 get_wait_mask(commio->hDevice, &new_evtmask);
987 if (commio->evtmask != new_evtmask)
993 if (needs_close) close( fd );
995 if (commio->hEvent) NtSetEvent(commio->hEvent, NULL);
996 RtlFreeHeap(GetProcessHeap(), 0, commio);
1000 static NTSTATUS wait_on(HANDLE hDevice, int fd, HANDLE hEvent, DWORD* events)
1002 async_commio* commio;
1005 if ((status = NtResetEvent(hEvent, NULL)))
1008 commio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof (async_commio));
1009 if (!commio) return STATUS_NO_MEMORY;
1011 commio->hDevice = hDevice;
1012 commio->events = events;
1013 commio->hEvent = hEvent;
1014 get_wait_mask(commio->hDevice, &commio->evtmask);
1016 /* We may never return, if some capabilities miss
1017 * Return error in that case
1019 #if !defined(TIOCINQ)
1020 if (commio->evtmask & EV_RXCHAR)
1023 #if !(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)
1024 if (commio->evtmask & EV_TXEMPTY)
1027 #if !defined(TIOCMGET)
1028 if (commio->evtmask & (EV_CTS | EV_DSR| EV_RING| EV_RLSD))
1031 #if !defined(TIOCM_CTS)
1032 if (commio->evtmask & EV_CTS)
1035 #if !defined(TIOCM_DSR)
1036 if (commio->evtmask & EV_DSR)
1039 #if !defined(TIOCM_RNG)
1040 if (commio->evtmask & EV_RING)
1043 #if !defined(TIOCM_CAR)
1044 if (commio->evtmask & EV_RLSD)
1047 if (commio->evtmask & EV_RXFLAG)
1048 FIXME("EV_RXFLAG not handled\n");
1050 if ((status = get_irq_info(fd, &commio->irq_info)) &&
1051 (commio->evtmask & (EV_BREAK | EV_ERR)))
1054 if ((status = get_modem_status(fd, &commio->mstat)) &&
1055 (commio->evtmask & (EV_CTS | EV_DSR| EV_RING| EV_RLSD)))
1058 /* We might have received something or the TX buffer is delivered */
1059 *events = check_events(fd, commio->evtmask,
1060 &commio->irq_info, &commio->irq_info,
1061 commio->mstat, commio->mstat);
1064 status = STATUS_SUCCESS;
1068 /* create the worker for the task */
1069 status = RtlQueueWorkItem(wait_for_event, commio, 0 /* FIXME */);
1070 if (status != STATUS_SUCCESS) goto out_now;
1071 return STATUS_PENDING;
1073 #if !defined(TIOCINQ) || (!(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)) || !defined(TIOCMGET) || !defined(TIOCM_CTS) ||!defined(TIOCM_DSR) || !defined(TIOCM_RNG) || !defined(TIOCM_CAR)
1075 FIXME("Returning error because of missing capabilities\n");
1076 status = STATUS_INVALID_PARAMETER;
1079 RtlFreeHeap(GetProcessHeap(), 0, commio);
1083 static NTSTATUS xmit_immediate(HANDLE hDevice, int fd, const char* ptr)
1085 /* FIXME: not perfect as it should bypass the in-queue */
1086 WARN("(%p,'%c') not perfect!\n", hDevice, *ptr);
1087 if (write(fd, ptr, 1) != 1)
1088 return FILE_GetNtStatus();
1089 return STATUS_SUCCESS;
1092 /******************************************************************
1093 * COMM_DeviceIoControl
1097 static inline NTSTATUS io_control(HANDLE hDevice,
1098 HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
1099 PVOID UserApcContext,
1100 PIO_STATUS_BLOCK piosb,
1101 ULONG dwIoControlCode,
1102 LPVOID lpInBuffer, DWORD nInBufferSize,
1103 LPVOID lpOutBuffer, DWORD nOutBufferSize)
1105 DWORD sz = 0, access = FILE_READ_DATA;
1106 NTSTATUS status = STATUS_SUCCESS;
1107 int fd = -1, needs_close = 0;
1109 TRACE("%p %s %p %d %p %d %p\n",
1110 hDevice, iocode2str(dwIoControlCode), lpInBuffer, nInBufferSize,
1111 lpOutBuffer, nOutBufferSize, piosb);
1113 piosb->Information = 0;
1115 if (dwIoControlCode != IOCTL_SERIAL_GET_TIMEOUTS &&
1116 dwIoControlCode != IOCTL_SERIAL_SET_TIMEOUTS)
1117 if ((status = server_get_unix_fd( hDevice, access, &fd, &needs_close, NULL, NULL )))
1120 switch (dwIoControlCode)
1122 case IOCTL_SERIAL_CLR_DTR:
1124 if (whack_modem(fd, ~TIOCM_DTR, 0) == -1) status = FILE_GetNtStatus();
1126 status = STATUS_NOT_SUPPORTED;
1129 case IOCTL_SERIAL_CLR_RTS:
1131 if (whack_modem(fd, ~TIOCM_RTS, 0) == -1) status = FILE_GetNtStatus();
1133 status = STATUS_NOT_SUPPORTED;
1136 case IOCTL_SERIAL_GET_BAUD_RATE:
1137 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_BAUD_RATE))
1139 if (!(status = get_baud_rate(fd, (SERIAL_BAUD_RATE*)lpOutBuffer)))
1140 sz = sizeof(SERIAL_BAUD_RATE);
1143 status = STATUS_INVALID_PARAMETER;
1145 case IOCTL_SERIAL_GET_CHARS:
1146 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_CHARS))
1148 if (!(status = get_special_chars(fd, (SERIAL_CHARS*)lpOutBuffer)))
1149 sz = sizeof(SERIAL_CHARS);
1152 status = STATUS_INVALID_PARAMETER;
1154 case IOCTL_SERIAL_GET_COMMSTATUS:
1155 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_STATUS))
1157 if (!(status = get_status(fd, (SERIAL_STATUS*)lpOutBuffer)))
1158 sz = sizeof(SERIAL_STATUS);
1160 else status = STATUS_INVALID_PARAMETER;
1162 case IOCTL_SERIAL_GET_HANDFLOW:
1163 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_HANDFLOW))
1165 if (!(status = get_hand_flow(fd, (SERIAL_HANDFLOW*)lpOutBuffer)))
1166 sz = sizeof(SERIAL_HANDFLOW);
1169 status = STATUS_INVALID_PARAMETER;
1171 case IOCTL_SERIAL_GET_LINE_CONTROL:
1172 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_LINE_CONTROL))
1174 if (!(status = get_line_control(fd, (SERIAL_LINE_CONTROL*)lpOutBuffer)))
1175 sz = sizeof(SERIAL_LINE_CONTROL);
1178 status = STATUS_INVALID_PARAMETER;
1180 case IOCTL_SERIAL_GET_MODEMSTATUS:
1181 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1183 if (!(status = get_modem_status(fd, (DWORD*)lpOutBuffer)))
1186 else status = STATUS_INVALID_PARAMETER;
1188 case IOCTL_SERIAL_GET_TIMEOUTS:
1189 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_TIMEOUTS))
1191 if (!(status = get_timeouts(hDevice, (SERIAL_TIMEOUTS*)lpOutBuffer)))
1192 sz = sizeof(SERIAL_TIMEOUTS);
1195 status = STATUS_INVALID_PARAMETER;
1197 case IOCTL_SERIAL_GET_WAIT_MASK:
1198 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1200 if (!(status = get_wait_mask(hDevice, (DWORD*)lpOutBuffer)))
1204 status = STATUS_INVALID_PARAMETER;
1206 case IOCTL_SERIAL_IMMEDIATE_CHAR:
1207 if (lpInBuffer && nInBufferSize == sizeof(CHAR))
1208 status = xmit_immediate(hDevice, fd, lpInBuffer);
1210 status = STATUS_INVALID_PARAMETER;
1212 case IOCTL_SERIAL_PURGE:
1213 if (lpInBuffer && nInBufferSize == sizeof(DWORD))
1214 status = purge(fd, *(DWORD*)lpInBuffer);
1216 status = STATUS_INVALID_PARAMETER;
1218 case IOCTL_SERIAL_RESET_DEVICE:
1219 FIXME("Unsupported\n");
1221 case IOCTL_SERIAL_SET_BAUD_RATE:
1222 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_BAUD_RATE))
1223 status = set_baud_rate(fd, (const SERIAL_BAUD_RATE*)lpInBuffer);
1225 status = STATUS_INVALID_PARAMETER;
1227 case IOCTL_SERIAL_SET_BREAK_OFF:
1228 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1229 if (ioctl(fd, TIOCCBRK, 0) == -1)
1231 TRACE("ioctl failed\n");
1232 status = FILE_GetNtStatus();
1235 FIXME("ioctl not available\n");
1236 status = STATUS_NOT_SUPPORTED;
1239 case IOCTL_SERIAL_SET_BREAK_ON:
1240 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1241 if (ioctl(fd, TIOCSBRK, 0) == -1)
1243 TRACE("ioctl failed\n");
1244 status = FILE_GetNtStatus();
1247 FIXME("ioctl not available\n");
1248 status = STATUS_NOT_SUPPORTED;
1251 case IOCTL_SERIAL_SET_CHARS:
1252 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_CHARS))
1253 status = set_special_chars(fd, (const SERIAL_CHARS*)lpInBuffer);
1255 status = STATUS_INVALID_PARAMETER;
1257 case IOCTL_SERIAL_SET_DTR:
1259 if (whack_modem(fd, 0, TIOCM_DTR) == -1) status = FILE_GetNtStatus();
1261 status = STATUS_NOT_SUPPORTED;
1264 case IOCTL_SERIAL_SET_HANDFLOW:
1265 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_HANDFLOW))
1266 status = set_handflow(fd, (const SERIAL_HANDFLOW*)lpInBuffer);
1268 status = STATUS_INVALID_PARAMETER;
1270 case IOCTL_SERIAL_SET_LINE_CONTROL:
1271 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_LINE_CONTROL))
1272 status = set_line_control(fd, (const SERIAL_LINE_CONTROL*)lpInBuffer);
1274 status = STATUS_INVALID_PARAMETER;
1276 case IOCTL_SERIAL_SET_QUEUE_SIZE:
1277 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_QUEUE_SIZE))
1278 status = set_queue_size(fd, (const SERIAL_QUEUE_SIZE*)lpInBuffer);
1280 status = STATUS_INVALID_PARAMETER;
1282 case IOCTL_SERIAL_SET_RTS:
1284 if (whack_modem(fd, 0, TIOCM_RTS) == -1) status = FILE_GetNtStatus();
1286 status = STATUS_NOT_SUPPORTED;
1289 case IOCTL_SERIAL_SET_TIMEOUTS:
1290 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_TIMEOUTS))
1291 status = set_timeouts(hDevice, (const SERIAL_TIMEOUTS*)lpInBuffer);
1293 status = STATUS_INVALID_PARAMETER;
1295 case IOCTL_SERIAL_SET_WAIT_MASK:
1296 if (lpInBuffer && nInBufferSize == sizeof(DWORD))
1298 status = set_wait_mask(hDevice, *(DWORD*)lpInBuffer);
1300 else status = STATUS_INVALID_PARAMETER;
1302 case IOCTL_SERIAL_SET_XOFF:
1303 status = set_XOff(fd);
1305 case IOCTL_SERIAL_SET_XON:
1306 status = set_XOn(fd);
1308 case IOCTL_SERIAL_WAIT_ON_MASK:
1309 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1311 if (!(status = wait_on(hDevice, fd, hEvent, (DWORD*)lpOutBuffer)))
1315 status = STATUS_INVALID_PARAMETER;
1318 FIXME("Unsupported IOCTL %x (type=%x access=%x func=%x meth=%x)\n",
1319 dwIoControlCode, dwIoControlCode >> 16, (dwIoControlCode >> 14) & 3,
1320 (dwIoControlCode >> 2) & 0xFFF, dwIoControlCode & 3);
1322 status = STATUS_INVALID_PARAMETER;
1325 if (needs_close) close( fd );
1327 piosb->u.Status = status;
1328 piosb->Information = sz;
1329 if (hEvent && status != STATUS_PENDING) NtSetEvent(hEvent, NULL);
1333 NTSTATUS COMM_DeviceIoControl(HANDLE hDevice,
1334 HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
1335 PVOID UserApcContext,
1336 PIO_STATUS_BLOCK piosb,
1337 ULONG dwIoControlCode,
1338 LPVOID lpInBuffer, DWORD nInBufferSize,
1339 LPVOID lpOutBuffer, DWORD nOutBufferSize)
1343 if (dwIoControlCode == IOCTL_SERIAL_WAIT_ON_MASK)
1345 HANDLE hev = hEvent;
1347 /* this is an ioctl we implement in a non blocking way if hEvent is not
1349 * so we have to explicitly wait if no hEvent is provided
1353 OBJECT_ATTRIBUTES attr;
1355 attr.Length = sizeof(attr);
1356 attr.RootDirectory = 0;
1357 attr.ObjectName = NULL;
1358 attr.Attributes = OBJ_CASE_INSENSITIVE | OBJ_OPENIF;
1359 attr.SecurityDescriptor = NULL;
1360 attr.SecurityQualityOfService = NULL;
1361 status = NtCreateEvent(&hev, EVENT_ALL_ACCESS, &attr, FALSE, FALSE);
1363 if (status) goto done;
1365 status = io_control(hDevice, hev, UserApcRoutine, UserApcContext,
1366 piosb, dwIoControlCode, lpInBuffer, nInBufferSize,
1367 lpOutBuffer, nOutBufferSize);
1370 if (status == STATUS_PENDING)
1372 NtWaitForSingleObject(hev, FALSE, NULL);
1373 status = STATUS_SUCCESS;
1378 else status = io_control(hDevice, hEvent, UserApcRoutine, UserApcContext,
1379 piosb, dwIoControlCode, lpInBuffer, nInBufferSize,
1380 lpOutBuffer, nOutBufferSize);