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 = wine_server_obj_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 = wine_server_obj_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 = wine_server_obj_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 = wine_server_obj_handle( hDevice );
795 req->flags = SERIALINFO_SET_MASK;
796 req->eventmask = mask;
797 status = wine_server_call( req );
804 * does not change IXOFF but simulates that IXOFF has been received:
806 static NTSTATUS set_XOff(int fd)
808 if (tcflow(fd, TCOOFF))
810 return FILE_GetNtStatus();
812 return STATUS_SUCCESS;
816 * does not change IXON but simulates that IXON has been received:
818 static NTSTATUS set_XOn(int fd)
820 if (tcflow(fd, TCOON))
822 return FILE_GetNtStatus();
824 return STATUS_SUCCESS;
828 * local structure holding the irq values we need for WaitCommEvent()
830 * Stripped down from struct serial_icounter_struct, which may not be available on some systems
831 * As the modem line interrupts (cts, dsr, rng, dcd) only get updated with TIOCMIWAIT active,
832 * no need to carry them in the internal structure
835 typedef struct serial_irq_info
837 int rx , tx, frame, overrun, parity, brk, buf_overrun;
840 /***********************************************************************
841 * Data needed by the thread polling for the changing CommEvent
843 typedef struct async_commio
850 serial_irq_info irq_info;
853 /***********************************************************************
854 * Get extended interrupt count info, needed for wait_on
856 static NTSTATUS get_irq_info(int fd, serial_irq_info *irq_info)
858 NTSTATUS status = STATUS_NOT_IMPLEMENTED;
860 struct serial_icounter_struct einfo;
861 if (!ioctl(fd, TIOCGICOUNT, &einfo))
863 irq_info->rx = einfo.rx;
864 irq_info->tx = einfo.tx;
865 irq_info->frame = einfo.frame;
866 irq_info->overrun = einfo.overrun;
867 irq_info->parity = einfo.parity;
868 irq_info->brk = einfo.brk;
869 irq_info->buf_overrun = einfo.buf_overrun;
870 return STATUS_SUCCESS;
872 TRACE("TIOCGICOUNT err %s\n", strerror(errno));
873 status = FILE_GetNtStatus();
875 memset(irq_info,0, sizeof(serial_irq_info));
880 static DWORD check_events(int fd, DWORD mask,
881 const serial_irq_info *new,
882 const serial_irq_info *old,
883 DWORD new_mstat, DWORD old_mstat)
885 DWORD ret = 0, queue;
887 TRACE("mask 0x%08x\n", mask);
888 TRACE("old->rx 0x%08x vs. new->rx 0x%08x\n", old->rx, new->rx);
889 TRACE("old->tx 0x%08x vs. new->tx 0x%08x\n", old->tx, new->tx);
890 TRACE("old->frame 0x%08x vs. new->frame 0x%08x\n", old->frame, new->frame);
891 TRACE("old->overrun 0x%08x vs. new->overrun 0x%08x\n", old->overrun, new->overrun);
892 TRACE("old->parity 0x%08x vs. new->parity 0x%08x\n", old->parity, new->parity);
893 TRACE("old->brk 0x%08x vs. new->brk 0x%08x\n", old->brk, new->brk);
894 TRACE("old->buf_overrun 0x%08x vs. new->buf_overrun 0x%08x\n", old->buf_overrun, new->buf_overrun);
896 if (old->brk != new->brk) ret |= EV_BREAK;
897 if ((old_mstat & MS_CTS_ON ) != (new_mstat & MS_CTS_ON )) ret |= EV_CTS;
898 if ((old_mstat & MS_DSR_ON ) != (new_mstat & MS_DSR_ON )) ret |= EV_DSR;
899 if ((old_mstat & MS_RING_ON) != (new_mstat & MS_RING_ON)) ret |= EV_RING;
900 if ((old_mstat & MS_RLSD_ON) != (new_mstat & MS_RLSD_ON)) ret |= EV_RLSD;
901 if (old->frame != new->frame || old->overrun != new->overrun || old->parity != new->parity) ret |= EV_ERR;
902 if (mask & EV_RXCHAR)
906 if (ioctl(fd, TIOCINQ, &queue))
907 WARN("TIOCINQ returned error\n");
912 if (mask & EV_TXEMPTY)
915 /* We really want to know when all characters have gone out of the transmitter */
916 #if defined(TIOCSERGETLSR)
917 if (ioctl(fd, TIOCSERGETLSR, &queue))
918 WARN("TIOCSERGETLSR returned error\n");
920 /* TIOCOUTQ only checks for an empty buffer */
921 #elif defined(TIOCOUTQ)
922 if (ioctl(fd, TIOCOUTQ, &queue))
923 WARN("TIOCOUTQ returned error\n");
927 TRACE("OUTQUEUE %d, Transmitter %sempty\n",
928 queue, (ret & EV_TXEMPTY) ? "" : "not ");
933 /***********************************************************************
934 * wait_for_event (INTERNAL)
936 * We need to poll for what is interesting
937 * TIOCMIWAIT only checks modem status line and may not be aborted by a changing mask
940 static DWORD CALLBACK wait_for_event(LPVOID arg)
942 async_commio *commio = (async_commio*) arg;
945 if (!server_get_unix_fd( commio->hDevice, FILE_READ_DATA | FILE_WRITE_DATA, &fd, &needs_close, NULL, NULL ))
947 serial_irq_info new_irq_info;
948 DWORD new_mstat, new_evtmask;
951 TRACE("device=%p fd=0x%08x mask=0x%08x buffer=%p event=%p irq_info=%p\n",
952 commio->hDevice, fd, commio->evtmask, commio->events, commio->hEvent, &commio->irq_info);
954 time.QuadPart = (ULONGLONG)10000;
955 time.QuadPart = -time.QuadPart;
959 * TIOCMIWAIT is not adequate
962 * We don't handle the EV_RXFLAG (the eventchar)
964 NtDelayExecution(FALSE, &time);
965 get_irq_info(fd, &new_irq_info);
966 if (get_modem_status(fd, &new_mstat))
967 TRACE("get_modem_status failed\n");
968 *commio->events = check_events(fd, commio->evtmask,
969 &new_irq_info, &commio->irq_info,
970 new_mstat, commio->mstat);
971 if (*commio->events) break;
972 get_wait_mask(commio->hDevice, &new_evtmask);
973 if (commio->evtmask != new_evtmask)
979 if (needs_close) close( fd );
981 if (commio->hEvent) NtSetEvent(commio->hEvent, NULL);
982 RtlFreeHeap(GetProcessHeap(), 0, commio);
986 static NTSTATUS wait_on(HANDLE hDevice, int fd, HANDLE hEvent, DWORD* events)
988 async_commio* commio;
991 if ((status = NtResetEvent(hEvent, NULL)))
994 commio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof (async_commio));
995 if (!commio) return STATUS_NO_MEMORY;
997 commio->hDevice = hDevice;
998 commio->events = events;
999 commio->hEvent = hEvent;
1000 get_wait_mask(commio->hDevice, &commio->evtmask);
1002 /* We may never return, if some capabilities miss
1003 * Return error in that case
1005 #if !defined(TIOCINQ)
1006 if (commio->evtmask & EV_RXCHAR)
1009 #if !(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)
1010 if (commio->evtmask & EV_TXEMPTY)
1013 #if !defined(TIOCMGET)
1014 if (commio->evtmask & (EV_CTS | EV_DSR| EV_RING| EV_RLSD))
1017 #if !defined(TIOCM_CTS)
1018 if (commio->evtmask & EV_CTS)
1021 #if !defined(TIOCM_DSR)
1022 if (commio->evtmask & EV_DSR)
1025 #if !defined(TIOCM_RNG)
1026 if (commio->evtmask & EV_RING)
1029 #if !defined(TIOCM_CAR)
1030 if (commio->evtmask & EV_RLSD)
1033 if (commio->evtmask & EV_RXFLAG)
1034 FIXME("EV_RXFLAG not handled\n");
1036 if ((status = get_irq_info(fd, &commio->irq_info)) &&
1037 (commio->evtmask & (EV_BREAK | EV_ERR)))
1040 if ((status = get_modem_status(fd, &commio->mstat)) &&
1041 (commio->evtmask & (EV_CTS | EV_DSR| EV_RING| EV_RLSD)))
1044 /* We might have received something or the TX buffer is delivered */
1045 *events = check_events(fd, commio->evtmask,
1046 &commio->irq_info, &commio->irq_info,
1047 commio->mstat, commio->mstat);
1050 status = STATUS_SUCCESS;
1054 /* create the worker for the task */
1055 status = RtlQueueWorkItem(wait_for_event, commio, 0 /* FIXME */);
1056 if (status != STATUS_SUCCESS) goto out_now;
1057 return STATUS_PENDING;
1059 #if !defined(TIOCINQ) || (!(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)) || !defined(TIOCMGET) || !defined(TIOCM_CTS) ||!defined(TIOCM_DSR) || !defined(TIOCM_RNG) || !defined(TIOCM_CAR)
1061 FIXME("Returning error because of missing capabilities\n");
1062 status = STATUS_INVALID_PARAMETER;
1065 RtlFreeHeap(GetProcessHeap(), 0, commio);
1069 static NTSTATUS xmit_immediate(HANDLE hDevice, int fd, const char* ptr)
1071 /* FIXME: not perfect as it should bypass the in-queue */
1072 WARN("(%p,'%c') not perfect!\n", hDevice, *ptr);
1073 if (write(fd, ptr, 1) != 1)
1074 return FILE_GetNtStatus();
1075 return STATUS_SUCCESS;
1078 /******************************************************************
1079 * COMM_DeviceIoControl
1083 static inline NTSTATUS io_control(HANDLE hDevice,
1084 HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
1085 PVOID UserApcContext,
1086 PIO_STATUS_BLOCK piosb,
1087 ULONG dwIoControlCode,
1088 LPVOID lpInBuffer, DWORD nInBufferSize,
1089 LPVOID lpOutBuffer, DWORD nOutBufferSize)
1091 DWORD sz = 0, access = FILE_READ_DATA;
1092 NTSTATUS status = STATUS_SUCCESS;
1093 int fd = -1, needs_close = 0;
1095 TRACE("%p %s %p %d %p %d %p\n",
1096 hDevice, iocode2str(dwIoControlCode), lpInBuffer, nInBufferSize,
1097 lpOutBuffer, nOutBufferSize, piosb);
1099 piosb->Information = 0;
1101 if (dwIoControlCode != IOCTL_SERIAL_GET_TIMEOUTS &&
1102 dwIoControlCode != IOCTL_SERIAL_SET_TIMEOUTS)
1103 if ((status = server_get_unix_fd( hDevice, access, &fd, &needs_close, NULL, NULL )))
1106 switch (dwIoControlCode)
1108 case IOCTL_SERIAL_CLR_DTR:
1110 if (whack_modem(fd, ~TIOCM_DTR, 0) == -1) status = FILE_GetNtStatus();
1112 status = STATUS_NOT_SUPPORTED;
1115 case IOCTL_SERIAL_CLR_RTS:
1117 if (whack_modem(fd, ~TIOCM_RTS, 0) == -1) status = FILE_GetNtStatus();
1119 status = STATUS_NOT_SUPPORTED;
1122 case IOCTL_SERIAL_GET_BAUD_RATE:
1123 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_BAUD_RATE))
1125 if (!(status = get_baud_rate(fd, (SERIAL_BAUD_RATE*)lpOutBuffer)))
1126 sz = sizeof(SERIAL_BAUD_RATE);
1129 status = STATUS_INVALID_PARAMETER;
1131 case IOCTL_SERIAL_GET_CHARS:
1132 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_CHARS))
1134 if (!(status = get_special_chars(fd, (SERIAL_CHARS*)lpOutBuffer)))
1135 sz = sizeof(SERIAL_CHARS);
1138 status = STATUS_INVALID_PARAMETER;
1140 case IOCTL_SERIAL_GET_COMMSTATUS:
1141 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_STATUS))
1143 if (!(status = get_status(fd, (SERIAL_STATUS*)lpOutBuffer)))
1144 sz = sizeof(SERIAL_STATUS);
1146 else status = STATUS_INVALID_PARAMETER;
1148 case IOCTL_SERIAL_GET_HANDFLOW:
1149 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_HANDFLOW))
1151 if (!(status = get_hand_flow(fd, (SERIAL_HANDFLOW*)lpOutBuffer)))
1152 sz = sizeof(SERIAL_HANDFLOW);
1155 status = STATUS_INVALID_PARAMETER;
1157 case IOCTL_SERIAL_GET_LINE_CONTROL:
1158 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_LINE_CONTROL))
1160 if (!(status = get_line_control(fd, (SERIAL_LINE_CONTROL*)lpOutBuffer)))
1161 sz = sizeof(SERIAL_LINE_CONTROL);
1164 status = STATUS_INVALID_PARAMETER;
1166 case IOCTL_SERIAL_GET_MODEMSTATUS:
1167 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1169 if (!(status = get_modem_status(fd, (DWORD*)lpOutBuffer)))
1172 else status = STATUS_INVALID_PARAMETER;
1174 case IOCTL_SERIAL_GET_TIMEOUTS:
1175 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_TIMEOUTS))
1177 if (!(status = get_timeouts(hDevice, (SERIAL_TIMEOUTS*)lpOutBuffer)))
1178 sz = sizeof(SERIAL_TIMEOUTS);
1181 status = STATUS_INVALID_PARAMETER;
1183 case IOCTL_SERIAL_GET_WAIT_MASK:
1184 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1186 if (!(status = get_wait_mask(hDevice, (DWORD*)lpOutBuffer)))
1190 status = STATUS_INVALID_PARAMETER;
1192 case IOCTL_SERIAL_IMMEDIATE_CHAR:
1193 if (lpInBuffer && nInBufferSize == sizeof(CHAR))
1194 status = xmit_immediate(hDevice, fd, lpInBuffer);
1196 status = STATUS_INVALID_PARAMETER;
1198 case IOCTL_SERIAL_PURGE:
1199 if (lpInBuffer && nInBufferSize == sizeof(DWORD))
1200 status = purge(fd, *(DWORD*)lpInBuffer);
1202 status = STATUS_INVALID_PARAMETER;
1204 case IOCTL_SERIAL_RESET_DEVICE:
1205 FIXME("Unsupported\n");
1207 case IOCTL_SERIAL_SET_BAUD_RATE:
1208 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_BAUD_RATE))
1209 status = set_baud_rate(fd, (const SERIAL_BAUD_RATE*)lpInBuffer);
1211 status = STATUS_INVALID_PARAMETER;
1213 case IOCTL_SERIAL_SET_BREAK_OFF:
1214 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1215 if (ioctl(fd, TIOCCBRK, 0) == -1)
1217 TRACE("ioctl failed\n");
1218 status = FILE_GetNtStatus();
1221 FIXME("ioctl not available\n");
1222 status = STATUS_NOT_SUPPORTED;
1225 case IOCTL_SERIAL_SET_BREAK_ON:
1226 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1227 if (ioctl(fd, TIOCSBRK, 0) == -1)
1229 TRACE("ioctl failed\n");
1230 status = FILE_GetNtStatus();
1233 FIXME("ioctl not available\n");
1234 status = STATUS_NOT_SUPPORTED;
1237 case IOCTL_SERIAL_SET_CHARS:
1238 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_CHARS))
1239 status = set_special_chars(fd, (const SERIAL_CHARS*)lpInBuffer);
1241 status = STATUS_INVALID_PARAMETER;
1243 case IOCTL_SERIAL_SET_DTR:
1245 if (whack_modem(fd, 0, TIOCM_DTR) == -1) status = FILE_GetNtStatus();
1247 status = STATUS_NOT_SUPPORTED;
1250 case IOCTL_SERIAL_SET_HANDFLOW:
1251 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_HANDFLOW))
1252 status = set_handflow(fd, (const SERIAL_HANDFLOW*)lpInBuffer);
1254 status = STATUS_INVALID_PARAMETER;
1256 case IOCTL_SERIAL_SET_LINE_CONTROL:
1257 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_LINE_CONTROL))
1258 status = set_line_control(fd, (const SERIAL_LINE_CONTROL*)lpInBuffer);
1260 status = STATUS_INVALID_PARAMETER;
1262 case IOCTL_SERIAL_SET_QUEUE_SIZE:
1263 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_QUEUE_SIZE))
1264 status = set_queue_size(fd, (const SERIAL_QUEUE_SIZE*)lpInBuffer);
1266 status = STATUS_INVALID_PARAMETER;
1268 case IOCTL_SERIAL_SET_RTS:
1270 if (whack_modem(fd, 0, TIOCM_RTS) == -1) status = FILE_GetNtStatus();
1272 status = STATUS_NOT_SUPPORTED;
1275 case IOCTL_SERIAL_SET_TIMEOUTS:
1276 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_TIMEOUTS))
1277 status = set_timeouts(hDevice, (const SERIAL_TIMEOUTS*)lpInBuffer);
1279 status = STATUS_INVALID_PARAMETER;
1281 case IOCTL_SERIAL_SET_WAIT_MASK:
1282 if (lpInBuffer && nInBufferSize == sizeof(DWORD))
1284 status = set_wait_mask(hDevice, *(DWORD*)lpInBuffer);
1286 else status = STATUS_INVALID_PARAMETER;
1288 case IOCTL_SERIAL_SET_XOFF:
1289 status = set_XOff(fd);
1291 case IOCTL_SERIAL_SET_XON:
1292 status = set_XOn(fd);
1294 case IOCTL_SERIAL_WAIT_ON_MASK:
1295 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1297 if (!(status = wait_on(hDevice, fd, hEvent, (DWORD*)lpOutBuffer)))
1301 status = STATUS_INVALID_PARAMETER;
1304 FIXME("Unsupported IOCTL %x (type=%x access=%x func=%x meth=%x)\n",
1305 dwIoControlCode, dwIoControlCode >> 16, (dwIoControlCode >> 14) & 3,
1306 (dwIoControlCode >> 2) & 0xFFF, dwIoControlCode & 3);
1308 status = STATUS_INVALID_PARAMETER;
1311 if (needs_close) close( fd );
1313 piosb->u.Status = status;
1314 piosb->Information = sz;
1315 if (hEvent && status != STATUS_PENDING) NtSetEvent(hEvent, NULL);
1319 NTSTATUS COMM_DeviceIoControl(HANDLE hDevice,
1320 HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
1321 PVOID UserApcContext,
1322 PIO_STATUS_BLOCK piosb,
1323 ULONG dwIoControlCode,
1324 LPVOID lpInBuffer, DWORD nInBufferSize,
1325 LPVOID lpOutBuffer, DWORD nOutBufferSize)
1329 if (dwIoControlCode == IOCTL_SERIAL_WAIT_ON_MASK)
1331 HANDLE hev = hEvent;
1333 /* this is an ioctl we implement in a non blocking way if hEvent is not
1335 * so we have to explicitly wait if no hEvent is provided
1339 OBJECT_ATTRIBUTES attr;
1341 attr.Length = sizeof(attr);
1342 attr.RootDirectory = 0;
1343 attr.ObjectName = NULL;
1344 attr.Attributes = OBJ_CASE_INSENSITIVE | OBJ_OPENIF;
1345 attr.SecurityDescriptor = NULL;
1346 attr.SecurityQualityOfService = NULL;
1347 status = NtCreateEvent(&hev, EVENT_ALL_ACCESS, &attr, FALSE, FALSE);
1349 if (status) goto done;
1351 status = io_control(hDevice, hev, UserApcRoutine, UserApcContext,
1352 piosb, dwIoControlCode, lpInBuffer, nInBufferSize,
1353 lpOutBuffer, nOutBufferSize);
1356 if (status == STATUS_PENDING)
1358 NtWaitForSingleObject(hev, FALSE, NULL);
1359 status = STATUS_SUCCESS;
1364 else status = io_control(hDevice, hEvent, UserApcRoutine, UserApcContext,
1365 piosb, dwIoControlCode, lpInBuffer, nInBufferSize,
1366 lpOutBuffer, nOutBufferSize);