1 /* Main file for COMM support
3 * DEC 93 Erik Bos <erik@xs4all.nl>
4 * Copyright 1996 Marcus Meissner
5 * Copyright 2005 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"
46 #ifdef HAVE_SYS_STAT_H
47 # include <sys/stat.h>
49 #include <sys/types.h>
50 #ifdef HAVE_SYS_FILIO_H
51 # include <sys/filio.h>
53 #ifdef HAVE_SYS_IOCTL_H
54 #include <sys/ioctl.h>
56 #ifdef HAVE_SYS_POLL_H
57 # include <sys/poll.h>
59 #ifdef HAVE_SYS_MODEM_H
60 # include <sys/modem.h>
62 #ifdef HAVE_SYS_STRTIO_H
63 # include <sys/strtio.h>
66 #define NONAMELESSUNION
67 #define NONAMELESSSTRUCT
69 #define WIN32_NO_STATUS
73 #include "ddk/ntddser.h"
74 #include "ntdll_misc.h"
75 #include "wine/server.h"
76 #include "wine/library.h"
77 #include "wine/debug.h"
79 #ifdef HAVE_LINUX_SERIAL_H
80 #include <linux/serial.h>
83 WINE_DEFAULT_DEBUG_CHANNEL(comm);
85 static const char* iocode2str(DWORD ioc)
89 #define X(x) case (x): return #x;
90 X(IOCTL_SERIAL_CLEAR_STATS);
91 X(IOCTL_SERIAL_CLR_DTR);
92 X(IOCTL_SERIAL_CLR_RTS);
93 X(IOCTL_SERIAL_CONFIG_SIZE);
94 X(IOCTL_SERIAL_GET_BAUD_RATE);
95 X(IOCTL_SERIAL_GET_CHARS);
96 X(IOCTL_SERIAL_GET_COMMSTATUS);
97 X(IOCTL_SERIAL_GET_DTRRTS);
98 X(IOCTL_SERIAL_GET_HANDFLOW);
99 X(IOCTL_SERIAL_GET_LINE_CONTROL);
100 X(IOCTL_SERIAL_GET_MODEM_CONTROL);
101 X(IOCTL_SERIAL_GET_MODEMSTATUS);
102 X(IOCTL_SERIAL_GET_PROPERTIES);
103 X(IOCTL_SERIAL_GET_STATS);
104 X(IOCTL_SERIAL_GET_TIMEOUTS);
105 X(IOCTL_SERIAL_GET_WAIT_MASK);
106 X(IOCTL_SERIAL_IMMEDIATE_CHAR);
107 X(IOCTL_SERIAL_LSRMST_INSERT);
108 X(IOCTL_SERIAL_PURGE);
109 X(IOCTL_SERIAL_RESET_DEVICE);
110 X(IOCTL_SERIAL_SET_BAUD_RATE);
111 X(IOCTL_SERIAL_SET_BREAK_ON);
112 X(IOCTL_SERIAL_SET_BREAK_OFF);
113 X(IOCTL_SERIAL_SET_CHARS);
114 X(IOCTL_SERIAL_SET_DTR);
115 X(IOCTL_SERIAL_SET_FIFO_CONTROL);
116 X(IOCTL_SERIAL_SET_HANDFLOW);
117 X(IOCTL_SERIAL_SET_LINE_CONTROL);
118 X(IOCTL_SERIAL_SET_MODEM_CONTROL);
119 X(IOCTL_SERIAL_SET_QUEUE_SIZE);
120 X(IOCTL_SERIAL_SET_RTS);
121 X(IOCTL_SERIAL_SET_TIMEOUTS);
122 X(IOCTL_SERIAL_SET_WAIT_MASK);
123 X(IOCTL_SERIAL_SET_XOFF);
124 X(IOCTL_SERIAL_SET_XON);
125 X(IOCTL_SERIAL_WAIT_ON_MASK);
126 X(IOCTL_SERIAL_XOFF_COUNTER);
128 default: { static char tmp[32]; sprintf(tmp, "IOCTL_SERIAL_%ld\n", ioc); return tmp; }
132 static NTSTATUS get_baud_rate(int fd, SERIAL_BAUD_RATE* sbr)
137 if (tcgetattr(fd, &port) == -1)
139 ERR("tcgetattr error '%s'\n", strerror(errno));
140 return FILE_GetNtStatus();
144 speed = port.c_cflag & CBAUD;
146 speed = cfgetospeed(&port);
150 case B0: sbr->BaudRate = 0; break;
151 case B50: sbr->BaudRate = 50; break;
152 case B75: sbr->BaudRate = 75; break;
153 case B110: sbr->BaudRate = 110; break;
154 case B134: sbr->BaudRate = 134; break;
155 case B150: sbr->BaudRate = 150; break;
156 case B200: sbr->BaudRate = 200; break;
157 case B300: sbr->BaudRate = 300; break;
158 case B600: sbr->BaudRate = 600; break;
159 case B1200: sbr->BaudRate = 1200; break;
160 case B1800: sbr->BaudRate = 1800; break;
161 case B2400: sbr->BaudRate = 2400; break;
162 case B4800: sbr->BaudRate = 4800; break;
163 case B9600: sbr->BaudRate = 9600; break;
164 case B19200: sbr->BaudRate = 19200; break;
165 case B38400: sbr->BaudRate = 38400; break;
167 case B57600: sbr->BaudRate = 57600; break;
170 case B115200: sbr->BaudRate = 115200; break;
173 case B230400: sbr->BaudRate = 230400; break;
176 case B460800: sbr->BaudRate = 460800; break;
179 ERR("unknown speed %x\n", speed);
180 return STATUS_INVALID_PARAMETER;
183 return STATUS_INVALID_PARAMETER;
185 return STATUS_SUCCESS;
188 static NTSTATUS get_hand_flow(int fd, SERIAL_HANDFLOW* shf)
193 if (tcgetattr(fd, &port) == -1)
195 ERR("tcgetattr error '%s'\n", strerror(errno));
196 return FILE_GetNtStatus();
199 if (ioctl(fd, TIOCMGET, &stat) == -1)
201 WARN("ioctl error '%s'\n", strerror(errno));
202 stat = DTR_CONTROL_ENABLE | RTS_CONTROL_ENABLE;
205 /* termios does not support DTR/DSR flow control */
206 shf->ControlHandShake = 0;
207 shf->FlowReplace = 0;
209 if (stat & TIOCM_DTR)
211 shf->ControlHandShake |= SERIAL_DTR_CONTROL;
213 if (port.c_cflag & CRTSCTS)
215 shf->ControlHandShake |= SERIAL_DTR_CONTROL | SERIAL_DTR_HANDSHAKE;
216 shf->ControlHandShake |= SERIAL_CTS_HANDSHAKE;
222 if (stat & TIOCM_RTS)
224 shf->ControlHandShake |= SERIAL_RTS_CONTROL;
226 if (port.c_iflag & IXON)
227 shf->FlowReplace |= SERIAL_AUTO_RECEIVE;
228 if (port.c_iflag & IXOFF)
229 shf->FlowReplace |= SERIAL_AUTO_TRANSMIT;
233 return STATUS_SUCCESS;
236 static NTSTATUS get_line_control(int fd, SERIAL_LINE_CONTROL* slc)
240 if (tcgetattr(fd, &port) == -1)
242 ERR("tcgetattr error '%s'\n", strerror(errno));
243 return FILE_GetNtStatus();
247 switch (port.c_cflag & (PARENB | PARODD | CMSPAR))
249 switch (port.c_cflag & (PARENB | PARODD))
252 case 0: slc->Parity = NOPARITY; break;
253 case PARENB: slc->Parity = EVENPARITY; break;
254 case PARENB|PARODD: slc->Parity = ODDPARITY; break;
256 case PARENB|CMSPAR: slc->Parity = MARKPARITY; break;
257 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 %ld. 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 #endif /* Don't have linux/serial.h or lack TIOCSSERIAL */
493 ERR("baudrate %ld\n", sbr->BaudRate);
494 return STATUS_NOT_SUPPORTED;
496 #elif !defined(__EMX__)
497 switch (sbr->BaudRate)
499 case 0: port.c_ospeed = B0; break;
500 case 50: port.c_ospeed = B50; break;
501 case 75: port.c_ospeed = B75; break;
503 case CBR_110: port.c_ospeed = B110; break;
504 case 134: port.c_ospeed = B134; break;
505 case 150: port.c_ospeed = B150; break;
506 case 200: port.c_ospeed = B200; break;
508 case CBR_300: port.c_ospeed = B300; break;
510 case CBR_600: port.c_ospeed = B600; break;
512 case CBR_1200: port.c_ospeed = B1200; break;
513 case 1800: port.c_ospeed = B1800; break;
515 case CBR_2400: port.c_ospeed = B2400; break;
517 case CBR_4800: port.c_ospeed = B4800; break;
519 case CBR_9600: port.c_ospeed = B9600; break;
521 case CBR_19200: port.c_ospeed = B19200; break;
523 case CBR_38400: port.c_ospeed = B38400; break;
526 case CBR_57600: port.c_cflag |= B57600; break;
530 case CBR_115200: port.c_cflag |= B115200;break;
533 case 230400: port.c_cflag |= B230400;break;
536 case 460800: port.c_cflag |= B460800;break;
539 ERR("baudrate %ld\n", sbr->BaudRate);
540 return STATUS_NOT_SUPPORTED;
542 port.c_ispeed = port.c_ospeed;
544 if (tcsetattr(fd, TCSANOW, &port) == -1)
546 ERR("tcsetattr error '%s'\n", strerror(errno));
547 return FILE_GetNtStatus();
549 return STATUS_SUCCESS;
552 static int whack_modem(int fd, unsigned int andy, unsigned int orrie)
555 unsigned int mstat, okay;
556 okay = ioctl(fd, TIOCMGET, &mstat);
557 if (okay) return okay;
558 if (andy) mstat &= andy;
560 return ioctl(fd, TIOCMSET, &mstat);
566 static NTSTATUS set_handflow(int fd, const SERIAL_HANDFLOW* shf)
570 if ((shf->FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE)) ==
571 (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE))
572 return STATUS_NOT_SUPPORTED;
574 if (tcgetattr(fd, &port) == -1)
576 ERR("tcgetattr error '%s'\n", strerror(errno));
577 return FILE_GetNtStatus();
581 if ((shf->ControlHandShake & SERIAL_CTS_HANDSHAKE) ||
582 (shf->FlowReplace & SERIAL_RTS_HANDSHAKE))
584 port.c_cflag |= CRTSCTS;
588 port.c_cflag &= ~CRTSCTS;
591 if (shf->ControlHandShake & SERIAL_DTR_HANDSHAKE)
593 WARN("DSR/DTR flow control not supported\n");
594 } else if (shf->ControlHandShake & SERIAL_DTR_CONTROL)
595 whack_modem(fd, ~TIOCM_DTR, 0);
597 whack_modem(fd, 0, TIOCM_DTR);
600 if (!(shf->ControlHandShake & SERIAL_DSR_HANDSHAKE))
602 if ((shf->FlowReplace & (SERIAL_RTS_CONTROL|SERIAL_RTS_HANDSHAKE)) == 0)
603 whack_modem(fd, ~TIOCM_RTS, 0);
605 whack_modem(fd, 0, TIOCM_RTS);
609 if (shf->FlowReplace & SERIAL_AUTO_RECEIVE)
610 port.c_iflag |= IXON;
612 port.c_iflag &= ~IXON;
613 if (shf->FlowReplace & SERIAL_AUTO_TRANSMIT)
614 port.c_iflag |= IXOFF;
616 port.c_iflag &= ~IXOFF;
617 if (tcsetattr(fd, TCSANOW, &port) == -1)
619 ERR("tcsetattr error '%s'\n", strerror(errno));
620 return FILE_GetNtStatus();
623 return STATUS_SUCCESS;
626 static NTSTATUS set_line_control(int fd, const SERIAL_LINE_CONTROL* slc)
629 unsigned bytesize, stopbits;
631 if (tcgetattr(fd, &port) == -1)
633 ERR("tcgetattr error '%s'\n", strerror(errno));
634 return FILE_GetNtStatus();
638 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK|IMAXBEL);
640 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK);
642 port.c_iflag |= IGNBRK | INPCK;
644 port.c_oflag &= ~(OPOST);
646 port.c_cflag &= ~(HUPCL);
647 port.c_cflag |= CLOCAL | CREAD;
649 port.c_lflag &= ~(ICANON|ECHO|ISIG);
650 port.c_lflag |= NOFLSH;
652 bytesize = slc->WordLength;
653 stopbits = slc->StopBits;
656 port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
658 port.c_cflag &= ~(PARENB | PARODD);
663 case NOPARITY: port.c_iflag &= ~INPCK; break;
664 case ODDPARITY: port.c_cflag |= PARENB | PARODD; break;
665 case EVENPARITY: port.c_cflag |= PARENB; break;
667 /* Linux defines mark/space (stick) parity */
668 case MARKPARITY: port.c_cflag |= PARENB | CMSPAR; break;
669 case SPACEPARITY: port.c_cflag |= PARENB | PARODD | CMSPAR; break;
671 /* try the POSIX way */
673 if (slc->StopBits == ONESTOPBIT)
675 stopbits = TWOSTOPBITS;
676 port.c_iflag &= ~INPCK;
680 ERR("Cannot set MARK Parity\n");
681 return STATUS_NOT_SUPPORTED;
685 if (slc->WordLength < 8)
688 port.c_iflag &= ~INPCK;
692 ERR("Cannot set SPACE Parity\n");
693 return STATUS_NOT_SUPPORTED;
699 return STATUS_NOT_SUPPORTED;
702 port.c_cflag &= ~CSIZE;
705 case 5: port.c_cflag |= CS5; break;
706 case 6: port.c_cflag |= CS6; break;
707 case 7: port.c_cflag |= CS7; break;
708 case 8: port.c_cflag |= CS8; break;
711 return STATUS_NOT_SUPPORTED;
716 case ONESTOPBIT: port.c_cflag &= ~CSTOPB; break;
717 case ONE5STOPBITS: /* will be selected if bytesize is 5 */
718 case TWOSTOPBITS: port.c_cflag |= CSTOPB; break;
721 return STATUS_NOT_SUPPORTED;
723 /* otherwise it hangs with pending input*/
724 if (tcsetattr(fd, TCSANOW, &port) == -1)
726 ERR("tcsetattr error '%s'\n", strerror(errno));
727 return FILE_GetNtStatus();
729 return STATUS_SUCCESS;
732 static NTSTATUS set_queue_size(int fd, const SERIAL_QUEUE_SIZE* sqs)
734 FIXME("insize %ld outsize %ld unimplemented stub\n", sqs->InSize, sqs->OutSize);
735 return STATUS_SUCCESS;
738 static NTSTATUS set_special_chars(int fd, const SERIAL_CHARS* sc)
742 if (tcgetattr(fd, &port) == -1)
744 ERR("tcgetattr error '%s'\n", strerror(errno));
745 return FILE_GetNtStatus();
748 port.c_cc[VMIN ] = 0;
749 port.c_cc[VTIME ] = 1;
751 port.c_cc[VEOF ] = sc->EofChar;
752 /* FIXME: sc->ErrorChar is not supported */
753 /* FIXME: sc->BreakChar is not supported */
754 /* FIXME: sc->EventChar is not supported */
755 port.c_cc[VSTART] = sc->XonChar;
756 port.c_cc[VSTOP ] = sc->XoffChar;
758 if (tcsetattr(fd, TCSANOW, &port) == -1)
760 ERR("tcsetattr error '%s'\n", strerror(errno));
761 return FILE_GetNtStatus();
763 return STATUS_SUCCESS;
766 static NTSTATUS set_timeouts(HANDLE handle, int fd, const SERIAL_TIMEOUTS* st)
770 unsigned int ux_timeout;
772 SERVER_START_REQ( set_serial_info )
774 req->handle = handle;
775 req->flags = SERIALINFO_SET_TIMEOUTS;
776 req->readinterval = st->ReadIntervalTimeout ;
777 req->readmult = st->ReadTotalTimeoutMultiplier ;
778 req->readconst = st->ReadTotalTimeoutConstant ;
779 req->writemult = st->WriteTotalTimeoutMultiplier ;
780 req->writeconst = st->WriteTotalTimeoutConstant ;
781 status = wine_server_call( req );
784 if (status) return status;
786 if (tcgetattr(fd, &port) == -1)
788 FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
789 return FILE_GetNtStatus();
792 /* VTIME is in 1/10 seconds */
793 if (st->ReadIntervalTimeout == 0) /* 0 means no timeout */
797 ux_timeout = (st->ReadIntervalTimeout + 99) / 100;
799 ux_timeout = 1; /* must be at least some timeout */
801 port.c_cc[VTIME] = ux_timeout;
803 if (tcsetattr(fd, 0, &port) == -1)
805 FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
806 return FILE_GetNtStatus();
808 return STATUS_SUCCESS;
811 static NTSTATUS set_wait_mask(HANDLE hDevice, DWORD mask)
815 SERVER_START_REQ( set_serial_info )
817 req->handle = hDevice;
818 req->flags = SERIALINFO_SET_MASK;
819 req->eventmask = mask;
820 status = wine_server_call( req );
826 static NTSTATUS set_XOff(int fd)
830 if (tcgetattr(fd,&port) == -1)
832 FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
833 return FILE_GetNtStatus();
837 port.c_iflag |= IXOFF;
838 if (tcsetattr(fd, TCSADRAIN, &port) == -1)
840 FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
841 return FILE_GetNtStatus();
843 return STATUS_SUCCESS;
846 static NTSTATUS set_XOn(int fd)
850 if (tcgetattr(fd,&port) == -1)
852 FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
853 return FILE_GetNtStatus();
855 port.c_iflag |= IXON;
856 if (tcsetattr(fd, TCSADRAIN, &port) == -1)
858 FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
859 return FILE_GetNtStatus();
861 return STATUS_SUCCESS;
864 static NTSTATUS xmit_immediate(HANDLE hDevice, int fd, char* ptr)
866 /* FIXME: not perfect as it should bypass the in-queue */
867 WARN("(%p,'%c') not perfect!\n", hDevice, *ptr);
868 if (write(fd, ptr, 1) != 1)
869 return FILE_GetNtStatus();
870 return STATUS_SUCCESS;
873 /******************************************************************
874 * COMM_DeviceIoControl
878 NTSTATUS COMM_DeviceIoControl(HANDLE hDevice,
879 HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
880 PVOID UserApcContext,
881 PIO_STATUS_BLOCK piosb,
882 ULONG dwIoControlCode,
883 LPVOID lpInBuffer, DWORD nInBufferSize,
884 LPVOID lpOutBuffer, DWORD nOutBufferSize)
886 DWORD sz = 0, access = FILE_READ_DATA;
887 NTSTATUS status = STATUS_SUCCESS;
890 TRACE("%p %s %p %ld %p %ld %p\n",
891 hDevice, iocode2str(dwIoControlCode), lpInBuffer, nInBufferSize,
892 lpOutBuffer, nOutBufferSize, piosb);
894 piosb->Information = 0;
896 if (dwIoControlCode != IOCTL_SERIAL_GET_TIMEOUTS)
897 if ((status = wine_server_handle_to_fd( hDevice, access, &fd, NULL )))
900 switch (dwIoControlCode)
902 case IOCTL_SERIAL_CLR_DTR:
904 if (whack_modem(fd, ~TIOCM_DTR, 0) == -1) status = FILE_GetNtStatus();
906 status = STATUS_NOT_SUPPORTED;
909 case IOCTL_SERIAL_CLR_RTS:
911 if (whack_modem(fd, ~TIOCM_RTS, 0) == -1) status = FILE_GetNtStatus();
913 status = STATUS_NOT_SUPPORTED;
916 case IOCTL_SERIAL_GET_BAUD_RATE:
917 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_BAUD_RATE))
919 if (!(status = get_baud_rate(fd, (SERIAL_BAUD_RATE*)lpOutBuffer)))
920 sz = sizeof(SERIAL_BAUD_RATE);
923 status = STATUS_INVALID_PARAMETER;
925 case IOCTL_SERIAL_GET_CHARS:
926 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_CHARS))
928 if (!(status = get_special_chars(fd, (SERIAL_CHARS*)lpOutBuffer)))
929 sz = sizeof(SERIAL_CHARS);
932 status = STATUS_INVALID_PARAMETER;
934 case IOCTL_SERIAL_GET_COMMSTATUS:
935 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_STATUS))
937 if (!(status = get_status(fd, (SERIAL_STATUS*)lpOutBuffer)))
938 sz = sizeof(SERIAL_STATUS);
940 else status = STATUS_INVALID_PARAMETER;
942 case IOCTL_SERIAL_GET_HANDFLOW:
943 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_HANDFLOW))
945 if (!(status = get_hand_flow(fd, (SERIAL_HANDFLOW*)lpOutBuffer)))
946 sz = sizeof(SERIAL_HANDFLOW);
949 status = STATUS_INVALID_PARAMETER;
951 case IOCTL_SERIAL_GET_LINE_CONTROL:
952 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_LINE_CONTROL))
954 if (!(status = get_line_control(fd, (SERIAL_LINE_CONTROL*)lpOutBuffer)))
955 sz = sizeof(SERIAL_LINE_CONTROL);
958 status = STATUS_INVALID_PARAMETER;
960 case IOCTL_SERIAL_GET_MODEMSTATUS:
961 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
963 if (!(status = get_modem_status(fd, (DWORD*)lpOutBuffer)))
966 else status = STATUS_INVALID_PARAMETER;
968 case IOCTL_SERIAL_GET_TIMEOUTS:
969 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_TIMEOUTS))
971 if (!(status = get_timeouts(hDevice, (SERIAL_TIMEOUTS*)lpOutBuffer)))
972 sz = sizeof(SERIAL_TIMEOUTS);
975 status = STATUS_INVALID_PARAMETER;
977 case IOCTL_SERIAL_GET_WAIT_MASK:
978 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
980 if (!(status = get_wait_mask(hDevice, (DWORD*)lpOutBuffer)))
984 status = STATUS_INVALID_PARAMETER;
986 case IOCTL_SERIAL_IMMEDIATE_CHAR:
987 if (lpInBuffer && nInBufferSize == sizeof(CHAR))
988 status = xmit_immediate(hDevice, fd, lpInBuffer);
990 status = STATUS_INVALID_PARAMETER;
992 case IOCTL_SERIAL_PURGE:
993 if (lpInBuffer && nInBufferSize == sizeof(DWORD))
994 status = purge(fd, *(DWORD*)lpInBuffer);
996 status = STATUS_INVALID_PARAMETER;
998 case IOCTL_SERIAL_RESET_DEVICE:
999 FIXME("Unsupported\n");
1001 case IOCTL_SERIAL_SET_BAUD_RATE:
1002 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_BAUD_RATE))
1003 status = set_baud_rate(fd, (const SERIAL_BAUD_RATE*)lpInBuffer);
1005 status = STATUS_INVALID_PARAMETER;
1007 case IOCTL_SERIAL_SET_BREAK_OFF:
1008 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1009 if (ioctl(fd, TIOCCBRK, 0) == -1)
1011 TRACE("ioctl failed\n");
1012 status = FILE_GetNtStatus();
1015 FIXME("ioctl not available\n");
1016 status = STATUS_NOT_SUPPORTED;
1019 case IOCTL_SERIAL_SET_BREAK_ON:
1020 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1021 if (ioctl(fd, TIOCSBRK, 0) == -1)
1023 TRACE("ioctl failed\n");
1024 status = FILE_GetNtStatus();
1027 FIXME("ioctl not available\n");
1028 status = STATUS_NOT_SUPPORTED;
1031 case IOCTL_SERIAL_SET_CHARS:
1032 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_CHARS))
1033 status = set_special_chars(fd, (const SERIAL_CHARS*)lpInBuffer);
1035 status = STATUS_INVALID_PARAMETER;
1037 case IOCTL_SERIAL_SET_DTR:
1039 if (whack_modem(fd, 0, TIOCM_DTR) == -1) status = FILE_GetNtStatus();
1041 status = STATUS_NOT_SUPPORTED;
1044 case IOCTL_SERIAL_SET_HANDFLOW:
1045 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_HANDFLOW))
1046 status = set_handflow(fd, (const SERIAL_HANDFLOW*)lpInBuffer);
1048 status = STATUS_INVALID_PARAMETER;
1050 case IOCTL_SERIAL_SET_LINE_CONTROL:
1051 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_LINE_CONTROL))
1052 status = set_line_control(fd, (const SERIAL_LINE_CONTROL*)lpInBuffer);
1054 status = STATUS_INVALID_PARAMETER;
1056 case IOCTL_SERIAL_SET_QUEUE_SIZE:
1057 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_QUEUE_SIZE))
1058 status = set_queue_size(fd, (const SERIAL_QUEUE_SIZE*)lpInBuffer);
1060 status = STATUS_INVALID_PARAMETER;
1062 case IOCTL_SERIAL_SET_RTS:
1064 if (whack_modem(fd, 0, TIOCM_RTS) == -1) status = FILE_GetNtStatus();
1066 status = STATUS_NOT_SUPPORTED;
1069 case IOCTL_SERIAL_SET_TIMEOUTS:
1070 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_TIMEOUTS))
1071 status = set_timeouts(hDevice, fd, (const SERIAL_TIMEOUTS*)lpInBuffer);
1073 status = STATUS_INVALID_PARAMETER;
1075 case IOCTL_SERIAL_SET_WAIT_MASK:
1076 if (lpInBuffer && nInBufferSize == sizeof(DWORD))
1078 status = set_wait_mask(hDevice, *(DWORD*)lpInBuffer);
1080 else status = STATUS_INVALID_PARAMETER;
1082 case IOCTL_SERIAL_SET_XOFF:
1083 status = set_XOff(fd);
1085 case IOCTL_SERIAL_SET_XON:
1086 status = set_XOn(fd);
1089 FIXME("Unsupported IOCTL %lx (type=%lx access=%lx func=%lx meth=%lx)\n",
1090 dwIoControlCode, dwIoControlCode >> 16, (dwIoControlCode >> 14) & 3,
1091 (dwIoControlCode >> 2) & 0xFFF, dwIoControlCode & 3);
1093 status = STATUS_INVALID_PARAMETER;
1096 if (fd != -1) wine_server_release_fd( hDevice, fd );
1098 piosb->u.Status = status;
1099 piosb->Information = sz;
1100 if (hEvent) NtSetEvent(hEvent, NULL);