quartz: Fix checking for duration.
[wine/wine64.git] / dlls / ntdll / serial.c
blobc54d70696e6a565fdc7373c11262b6ae3caea81d
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
22 #include "config.h"
23 #include "wine/port.h"
25 #include <errno.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30 #ifdef HAVE_STRINGS_H
31 # include <strings.h>
32 #endif
33 #ifdef HAVE_TERMIOS_H
34 #include <termios.h>
35 #endif
36 #ifdef HAVE_IO_H
37 # include <io.h>
38 #endif
39 #ifdef HAVE_UNISTD_H
40 # include <unistd.h>
41 #endif
42 #include <fcntl.h>
43 #ifdef HAVE_SYS_STAT_H
44 # include <sys/stat.h>
45 #endif
46 #include <sys/types.h>
47 #ifdef HAVE_SYS_FILIO_H
48 # include <sys/filio.h>
49 #endif
50 #ifdef HAVE_SYS_IOCTL_H
51 #include <sys/ioctl.h>
52 #endif
53 #ifdef HAVE_SYS_POLL_H
54 # include <sys/poll.h>
55 #endif
56 #ifdef HAVE_SYS_MODEM_H
57 # include <sys/modem.h>
58 #endif
59 #ifdef HAVE_SYS_STRTIO_H
60 # include <sys/strtio.h>
61 #endif
63 #define NONAMELESSUNION
64 #define NONAMELESSSTRUCT
65 #include "ntstatus.h"
66 #define WIN32_NO_STATUS
67 #include "windef.h"
68 #include "winternl.h"
69 #include "winioctl.h"
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>
78 #endif
80 #if !defined(TIOCINQ) && defined(FIONREAD)
81 #define TIOCINQ FIONREAD
82 #endif
84 WINE_DEFAULT_DEBUG_CHANNEL(comm);
86 static const char* iocode2str(DWORD ioc)
88 switch (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);
128 #undef X
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)
135 struct termios port;
136 int speed;
138 if (tcgetattr(fd, &port) == -1)
140 ERR("tcgetattr error '%s'\n", strerror(errno));
141 return FILE_GetNtStatus();
143 #ifndef __EMX__
144 #ifdef CBAUD
145 speed = port.c_cflag & CBAUD;
146 #else
147 speed = cfgetospeed(&port);
148 #endif
149 switch (speed)
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;
167 #ifdef B57600
168 case B57600: sbr->BaudRate = 57600; break;
169 #endif
170 #ifdef B115200
171 case B115200: sbr->BaudRate = 115200; break;
172 #endif
173 #ifdef B230400
174 case B230400: sbr->BaudRate = 230400; break;
175 #endif
176 #ifdef B460800
177 case B460800: sbr->BaudRate = 460800; break;
178 #endif
179 default:
180 ERR("unknown speed %x\n", speed);
181 return STATUS_INVALID_PARAMETER;
183 #else
184 return STATUS_INVALID_PARAMETER;
185 #endif
186 return STATUS_SUCCESS;
189 static NTSTATUS get_hand_flow(int fd, SERIAL_HANDFLOW* shf)
191 int stat = 0;
192 struct termios port;
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;
202 #ifdef TIOCMGET
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;
209 #else
210 WARN("Setting DTR/RTS to enabled by default\n");
211 shf->ControlHandShake |= SERIAL_DTR_CONTROL;
212 shf->FlowReplace |= SERIAL_RTS_CONTROL;
213 #endif
214 #ifdef TIOCM_DTR
215 if (stat & TIOCM_DTR)
216 #endif
217 shf->ControlHandShake |= SERIAL_DTR_CONTROL;
218 #ifdef CRTSCTS
219 if (port.c_cflag & CRTSCTS)
221 shf->FlowReplace |= SERIAL_RTS_CONTROL;
222 shf->ControlHandShake |= SERIAL_CTS_HANDSHAKE;
224 else
225 #endif
227 #ifdef TIOCM_RTS
228 if (stat & TIOCM_RTS)
229 #endif
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;
237 shf->XonLimit = 10;
238 shf->XoffLimit = 10;
239 return STATUS_SUCCESS;
242 static NTSTATUS get_line_control(int fd, SERIAL_LINE_CONTROL* slc)
244 struct termios port;
246 if (tcgetattr(fd, &port) == -1)
248 ERR("tcgetattr error '%s'\n", strerror(errno));
249 return FILE_GetNtStatus();
252 #ifdef CMSPAR
253 switch (port.c_cflag & (PARENB | PARODD | CMSPAR))
254 #else
255 switch (port.c_cflag & (PARENB | PARODD))
256 #endif
258 case 0: slc->Parity = NOPARITY; break;
259 case PARENB: slc->Parity = EVENPARITY; break;
260 case PARENB|PARODD: slc->Parity = ODDPARITY; break;
261 #ifdef CMSPAR
262 case PARENB|CMSPAR: slc->Parity = MARKPARITY; break;
263 case PARENB|PARODD|CMSPAR: slc->Parity = SPACEPARITY; break;
264 #endif
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;
279 else
280 slc->StopBits = TWOSTOPBITS;
282 else
283 slc->StopBits = ONESTOPBIT;
285 return STATUS_SUCCESS;
288 static NTSTATUS get_modem_status(int fd, DWORD* lpModemStat)
290 NTSTATUS status = STATUS_SUCCESS;
291 int mstat;
293 #ifdef TIOCMGET
294 if (ioctl(fd, TIOCMGET, &mstat) == -1)
296 WARN("ioctl failed\n");
297 status = FILE_GetNtStatus();
299 else
301 *lpModemStat = 0;
302 #ifdef TIOCM_CTS
303 if (mstat & TIOCM_CTS) *lpModemStat |= MS_CTS_ON;
304 #endif
305 #ifdef TIOCM_DSR
306 if (mstat & TIOCM_DSR) *lpModemStat |= MS_DSR_ON;
307 #endif
308 #ifdef TIOCM_RNG
309 if (mstat & TIOCM_RNG) *lpModemStat |= MS_RING_ON;
310 #endif
311 #ifdef TIOCM_CAR
312 /* FIXME: Not really sure about RLSD UB 990810 */
313 if (mstat & TIOCM_CAR) *lpModemStat |= MS_RLSD_ON;
314 #endif
315 TRACE("%04x -> %s%s%s%s\n", mstat,
316 (*lpModemStat & MS_RLSD_ON) ? "MS_RLSD_ON " : "",
317 (*lpModemStat & MS_RING_ON) ? "MS_RING_ON " : "",
318 (*lpModemStat & MS_DSR_ON) ? "MS_DSR_ON " : "",
319 (*lpModemStat & MS_CTS_ON) ? "MS_CTS_ON " : "");
321 #else
322 status = STATUS_NOT_SUPPORTED;
323 #endif
324 return status;
327 static NTSTATUS get_special_chars(int fd, SERIAL_CHARS* sc)
329 struct termios port;
331 if (tcgetattr(fd, &port) == -1)
333 ERR("tcgetattr error '%s'\n", strerror(errno));
334 return FILE_GetNtStatus();
336 sc->EofChar = port.c_cc[VEOF];
337 sc->ErrorChar = 0xFF;
338 sc->BreakChar = 0; /* FIXME */
339 sc->EventChar = 0; /* FIXME */
340 sc->XonChar = port.c_cc[VSTART];
341 sc->XoffChar = port.c_cc[VSTOP];
343 return STATUS_SUCCESS;
346 static NTSTATUS get_status(int fd, SERIAL_STATUS* ss)
348 NTSTATUS status = STATUS_SUCCESS;
350 ss->Errors = 0;
351 ss->HoldReasons = 0;
352 ss->EofReceived = FALSE;
353 ss->WaitForImmediate = FALSE;
354 #ifdef TIOCOUTQ
355 if (ioctl(fd, TIOCOUTQ, &ss->AmountInOutQueue) == -1)
357 WARN("ioctl returned error\n");
358 status = FILE_GetNtStatus();
360 #else
361 ss->AmountInOutQueue = 0; /* FIXME: find a different way to find out */
362 #endif
364 #ifdef TIOCINQ
365 if (ioctl(fd, TIOCINQ, &ss->AmountInInQueue))
367 WARN("ioctl returned error\n");
368 status = FILE_GetNtStatus();
370 #else
371 ss->AmountInInQueue = 0; /* FIXME: find a different way to find out */
372 #endif
373 return status;
376 static NTSTATUS get_timeouts(HANDLE handle, SERIAL_TIMEOUTS* st)
378 NTSTATUS status;
379 SERVER_START_REQ( get_serial_info )
381 req->handle = handle;
382 if (!(status = wine_server_call( req )))
384 st->ReadIntervalTimeout = reply->readinterval;
385 st->ReadTotalTimeoutMultiplier = reply->readmult;
386 st->ReadTotalTimeoutConstant = reply->readconst;
387 st->WriteTotalTimeoutMultiplier = reply->writemult;
388 st->WriteTotalTimeoutConstant = reply->writeconst;
391 SERVER_END_REQ;
392 return status;
395 static NTSTATUS get_wait_mask(HANDLE hDevice, DWORD* mask)
397 NTSTATUS status;
399 SERVER_START_REQ( get_serial_info )
401 req->handle = hDevice;
402 if (!(status = wine_server_call( req )))
403 *mask = reply->eventmask;
405 SERVER_END_REQ;
406 return status;
409 static NTSTATUS purge(int fd, DWORD flags)
412 ** not exactly sure how these are different
413 ** Perhaps if we had our own internal queues, one flushes them
414 ** and the other flushes the kernel's buffers.
416 if (flags & PURGE_TXABORT) tcflush(fd, TCOFLUSH);
417 if (flags & PURGE_RXABORT) tcflush(fd, TCIFLUSH);
418 if (flags & PURGE_TXCLEAR) tcflush(fd, TCOFLUSH);
419 if (flags & PURGE_RXCLEAR) tcflush(fd, TCIFLUSH);
420 return STATUS_SUCCESS;
423 static NTSTATUS set_baud_rate(int fd, const SERIAL_BAUD_RATE* sbr)
425 struct termios port;
427 if (tcgetattr(fd, &port) == -1)
429 ERR("tcgetattr error '%s'\n", strerror(errno));
430 return FILE_GetNtStatus();
433 #ifdef CBAUD
434 port.c_cflag &= ~CBAUD;
435 switch (sbr->BaudRate)
437 case 0: port.c_cflag |= B0; break;
438 case 50: port.c_cflag |= B50; break;
439 case 75: port.c_cflag |= B75; break;
440 case 110:
441 case CBR_110: port.c_cflag |= B110; break;
442 case 134: port.c_cflag |= B134; break;
443 case 150: port.c_cflag |= B150; break;
444 case 200: port.c_cflag |= B200; break;
445 case 300:
446 case CBR_300: port.c_cflag |= B300; break;
447 case 600:
448 case CBR_600: port.c_cflag |= B600; break;
449 case 1200:
450 case CBR_1200: port.c_cflag |= B1200; break;
451 case 1800: port.c_cflag |= B1800; break;
452 case 2400:
453 case CBR_2400: port.c_cflag |= B2400; break;
454 case 4800:
455 case CBR_4800: port.c_cflag |= B4800; break;
456 case 9600:
457 case CBR_9600: port.c_cflag |= B9600; break;
458 case 19200:
459 case CBR_19200: port.c_cflag |= B19200; break;
460 case 38400:
461 case CBR_38400: port.c_cflag |= B38400; break;
462 #ifdef B57600
463 case 57600: port.c_cflag |= B57600; break;
464 #endif
465 #ifdef B115200
466 case 115200: port.c_cflag |= B115200;break;
467 #endif
468 #ifdef B230400
469 case 230400: port.c_cflag |= B230400;break;
470 #endif
471 #ifdef B460800
472 case 460800: port.c_cflag |= B460800;break;
473 #endif
474 default:
475 #if defined (HAVE_LINUX_SERIAL_H) && defined (TIOCSSERIAL)
477 struct serial_struct nuts;
478 int arby;
480 ioctl(fd, TIOCGSERIAL, &nuts);
481 nuts.custom_divisor = nuts.baud_base / sbr->BaudRate;
482 if (!(nuts.custom_divisor)) nuts.custom_divisor = 1;
483 arby = nuts.baud_base / nuts.custom_divisor;
484 nuts.flags &= ~ASYNC_SPD_MASK;
485 nuts.flags |= ASYNC_SPD_CUST;
486 WARN("You (or a program acting at your behest) have specified\n"
487 "a non-standard baud rate %d. Wine will set the rate to %d,\n"
488 "which is as close as we can get by our present understanding of your\n"
489 "hardware. I hope you know what you are doing. Any disruption Wine\n"
490 "has caused to your linux system can be undone with setserial \n"
491 "(see man setserial). If you have incapacitated a Hayes type modem,\n"
492 "reset it and it will probably recover.\n", sbr->BaudRate, arby);
493 ioctl(fd, TIOCSSERIAL, &nuts);
494 port.c_cflag |= B38400;
496 break;
497 #else /* Don't have linux/serial.h or lack TIOCSSERIAL */
498 ERR("baudrate %d\n", sbr->BaudRate);
499 return STATUS_NOT_SUPPORTED;
500 #endif /* Don't have linux/serial.h or lack TIOCSSERIAL */
502 #elif !defined(__EMX__)
503 switch (sbr->BaudRate)
505 case 0: port.c_ospeed = B0; break;
506 case 50: port.c_ospeed = B50; break;
507 case 75: port.c_ospeed = B75; break;
508 case 110:
509 case CBR_110: port.c_ospeed = B110; break;
510 case 134: port.c_ospeed = B134; break;
511 case 150: port.c_ospeed = B150; break;
512 case 200: port.c_ospeed = B200; break;
513 case 300:
514 case CBR_300: port.c_ospeed = B300; break;
515 case 600:
516 case CBR_600: port.c_ospeed = B600; break;
517 case 1200:
518 case CBR_1200: port.c_ospeed = B1200; break;
519 case 1800: port.c_ospeed = B1800; break;
520 case 2400:
521 case CBR_2400: port.c_ospeed = B2400; break;
522 case 4800:
523 case CBR_4800: port.c_ospeed = B4800; break;
524 case 9600:
525 case CBR_9600: port.c_ospeed = B9600; break;
526 case 19200:
527 case CBR_19200: port.c_ospeed = B19200; break;
528 case 38400:
529 case CBR_38400: port.c_ospeed = B38400; break;
530 #ifdef B57600
531 case 57600:
532 case CBR_57600: port.c_cflag |= B57600; break;
533 #endif
534 #ifdef B115200
535 case 115200:
536 case CBR_115200: port.c_cflag |= B115200;break;
537 #endif
538 #ifdef B230400
539 case 230400: port.c_cflag |= B230400;break;
540 #endif
541 #ifdef B460800
542 case 460800: port.c_cflag |= B460800;break;
543 #endif
544 default:
545 ERR("baudrate %d\n", sbr->BaudRate);
546 return STATUS_NOT_SUPPORTED;
548 port.c_ispeed = port.c_ospeed;
549 #endif
550 if (tcsetattr(fd, TCSANOW, &port) == -1)
552 ERR("tcsetattr error '%s'\n", strerror(errno));
553 return FILE_GetNtStatus();
555 return STATUS_SUCCESS;
558 static int whack_modem(int fd, unsigned int andy, unsigned int orrie)
560 #ifdef TIOCMGET
561 unsigned int mstat, okay;
562 okay = ioctl(fd, TIOCMGET, &mstat);
563 if (okay) return okay;
564 if (andy) mstat &= andy;
565 mstat |= orrie;
566 return ioctl(fd, TIOCMSET, &mstat);
567 #else
568 return 0;
569 #endif
572 static NTSTATUS set_handflow(int fd, const SERIAL_HANDFLOW* shf)
574 struct termios port;
576 if ((shf->FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE)) ==
577 (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE))
578 return STATUS_NOT_SUPPORTED;
580 if (tcgetattr(fd, &port) == -1)
582 ERR("tcgetattr error '%s'\n", strerror(errno));
583 return FILE_GetNtStatus();
586 #ifdef CRTSCTS
587 if ((shf->ControlHandShake & SERIAL_CTS_HANDSHAKE) ||
588 (shf->FlowReplace & SERIAL_RTS_HANDSHAKE))
590 port.c_cflag |= CRTSCTS;
591 TRACE("CRTSCTS\n");
593 else
594 port.c_cflag &= ~CRTSCTS;
595 #endif
596 #ifdef TIOCM_DTR
597 if (shf->ControlHandShake & SERIAL_DTR_HANDSHAKE)
599 WARN("DSR/DTR flow control not supported\n");
600 } else if (!(shf->ControlHandShake & SERIAL_DTR_CONTROL))
601 whack_modem(fd, ~TIOCM_DTR, 0);
602 else
603 whack_modem(fd, 0, TIOCM_DTR);
604 #endif
605 #ifdef TIOCM_RTS
606 if (!(shf->ControlHandShake & SERIAL_CTS_HANDSHAKE))
608 if ((shf->FlowReplace & (SERIAL_RTS_CONTROL|SERIAL_RTS_HANDSHAKE)) == 0)
609 whack_modem(fd, ~TIOCM_RTS, 0);
610 else
611 whack_modem(fd, 0, TIOCM_RTS);
613 #endif
615 if (shf->FlowReplace & SERIAL_AUTO_RECEIVE)
616 port.c_iflag |= IXOFF;
617 else
618 port.c_iflag &= ~IXOFF;
619 if (shf->FlowReplace & SERIAL_AUTO_TRANSMIT)
620 port.c_iflag |= IXON;
621 else
622 port.c_iflag &= ~IXON;
623 if (tcsetattr(fd, TCSANOW, &port) == -1)
625 ERR("tcsetattr error '%s'\n", strerror(errno));
626 return FILE_GetNtStatus();
629 return STATUS_SUCCESS;
632 static NTSTATUS set_line_control(int fd, const SERIAL_LINE_CONTROL* slc)
634 struct termios port;
635 unsigned bytesize, stopbits;
637 if (tcgetattr(fd, &port) == -1)
639 ERR("tcgetattr error '%s'\n", strerror(errno));
640 return FILE_GetNtStatus();
643 #ifdef IMAXBEL
644 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK|IMAXBEL);
645 #else
646 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK);
647 #endif
648 port.c_iflag |= IGNBRK | INPCK;
650 port.c_oflag &= ~(OPOST);
652 port.c_cflag &= ~(HUPCL);
653 port.c_cflag |= CLOCAL | CREAD;
655 port.c_lflag &= ~(ICANON|ECHO|ISIG);
656 port.c_lflag |= NOFLSH;
658 bytesize = slc->WordLength;
659 stopbits = slc->StopBits;
661 #ifdef CMSPAR
662 port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
663 #else
664 port.c_cflag &= ~(PARENB | PARODD);
665 #endif
667 switch (slc->Parity)
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;
672 #ifdef CMSPAR
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;
676 #else
677 /* try the POSIX way */
678 case MARKPARITY:
679 if (slc->StopBits == ONESTOPBIT)
681 stopbits = TWOSTOPBITS;
682 port.c_iflag &= ~INPCK;
684 else
686 ERR("Cannot set MARK Parity\n");
687 return STATUS_NOT_SUPPORTED;
689 break;
690 case SPACEPARITY:
691 if (slc->WordLength < 8)
693 bytesize +=1;
694 port.c_iflag &= ~INPCK;
696 else
698 ERR("Cannot set SPACE Parity\n");
699 return STATUS_NOT_SUPPORTED;
701 break;
702 #endif
703 default:
704 ERR("Parity\n");
705 return STATUS_NOT_SUPPORTED;
708 port.c_cflag &= ~CSIZE;
709 switch (bytesize)
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;
715 default:
716 ERR("ByteSize\n");
717 return STATUS_NOT_SUPPORTED;
720 switch (stopbits)
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;
725 default:
726 ERR("StopBits\n");
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)
746 struct termios port;
748 if (tcgetattr(fd, &port) == -1)
750 ERR("tcgetattr error '%s'\n", strerror(errno));
751 return FILE_GetNtStatus();
754 port.c_cc[VMIN ] = 0;
755 port.c_cc[VTIME ] = 1;
757 port.c_cc[VEOF ] = sc->EofChar;
758 /* FIXME: sc->ErrorChar is not supported */
759 /* FIXME: sc->BreakChar is not supported */
760 /* FIXME: sc->EventChar is not supported */
761 port.c_cc[VSTART] = sc->XonChar;
762 port.c_cc[VSTOP ] = sc->XoffChar;
764 if (tcsetattr(fd, TCSANOW, &port) == -1)
766 ERR("tcsetattr error '%s'\n", strerror(errno));
767 return FILE_GetNtStatus();
769 return STATUS_SUCCESS;
772 static NTSTATUS set_timeouts(HANDLE handle, int fd, const SERIAL_TIMEOUTS* st)
774 NTSTATUS status;
775 struct termios port;
776 unsigned int ux_timeout;
778 SERVER_START_REQ( set_serial_info )
780 req->handle = handle;
781 req->flags = SERIALINFO_SET_TIMEOUTS;
782 req->readinterval = st->ReadIntervalTimeout ;
783 req->readmult = st->ReadTotalTimeoutMultiplier ;
784 req->readconst = st->ReadTotalTimeoutConstant ;
785 req->writemult = st->WriteTotalTimeoutMultiplier ;
786 req->writeconst = st->WriteTotalTimeoutConstant ;
787 status = wine_server_call( req );
789 SERVER_END_REQ;
790 if (status) return status;
792 if (tcgetattr(fd, &port) == -1)
794 FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
795 return FILE_GetNtStatus();
798 /* VTIME is in 1/10 seconds */
799 if (st->ReadIntervalTimeout == 0) /* 0 means no timeout */
800 ux_timeout = 0;
801 else
803 ux_timeout = (st->ReadIntervalTimeout + 99) / 100;
804 if (ux_timeout == 0)
805 ux_timeout = 1; /* must be at least some timeout */
807 port.c_cc[VTIME] = ux_timeout;
809 if (tcsetattr(fd, 0, &port) == -1)
811 FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
812 return FILE_GetNtStatus();
814 return STATUS_SUCCESS;
817 static NTSTATUS set_wait_mask(HANDLE hDevice, DWORD mask)
819 NTSTATUS status;
821 SERVER_START_REQ( set_serial_info )
823 req->handle = hDevice;
824 req->flags = SERIALINFO_SET_MASK;
825 req->eventmask = mask;
826 status = wine_server_call( req );
828 SERVER_END_REQ;
829 return status;
832 static NTSTATUS set_XOff(int fd)
834 struct termios port;
836 if (tcgetattr(fd,&port) == -1)
838 FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
839 return FILE_GetNtStatus();
843 port.c_iflag |= IXOFF;
844 if (tcsetattr(fd, TCSADRAIN, &port) == -1)
846 FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
847 return FILE_GetNtStatus();
849 return STATUS_SUCCESS;
852 static NTSTATUS set_XOn(int fd)
854 struct termios port;
856 if (tcgetattr(fd,&port) == -1)
858 FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
859 return FILE_GetNtStatus();
861 port.c_iflag |= IXON;
862 if (tcsetattr(fd, TCSADRAIN, &port) == -1)
864 FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
865 return FILE_GetNtStatus();
867 return STATUS_SUCCESS;
870 /* serial_irq_info
871 * local structure holding the irq values we need for WaitCommEvent()
873 * Stripped down from struct serial_icounter_struct, which may not be available on some systems
874 * As the modem line interrupts (cts, dsr, rng, dcd) only get updated with TIOCMIWAIT active,
875 * no need to carry them in the internal structure
878 typedef struct serial_irq_info
880 int rx , tx, frame, overrun, parity, brk, buf_overrun;
881 }serial_irq_info;
883 /***********************************************************************
884 * Data needed by the thread polling for the changing CommEvent
886 typedef struct async_commio
888 HANDLE hDevice;
889 DWORD* events;
890 HANDLE hEvent;
891 DWORD evtmask;
892 DWORD mstat;
893 serial_irq_info irq_info;
894 } async_commio;
896 /***********************************************************************
897 * Get extended interrupt count info, needed for wait_on
899 static NTSTATUS get_irq_info(int fd, serial_irq_info *irq_info)
901 #ifdef TIOCGICOUNT
902 struct serial_icounter_struct einfo;
903 if (!ioctl(fd, TIOCGICOUNT, &einfo))
905 irq_info->rx = einfo.rx;
906 irq_info->tx = einfo.tx;
907 irq_info->frame = einfo.frame;
908 irq_info->overrun = einfo.overrun;
909 irq_info->parity = einfo.parity;
910 irq_info->brk = einfo.brk;
911 irq_info->buf_overrun = einfo.buf_overrun;
912 return STATUS_SUCCESS;
914 TRACE("TIOCGICOUNT err %s\n", strerror(errno));
915 return FILE_GetNtStatus();
916 #else
917 memset(irq_info,0, sizeof(serial_irq_info));
918 return STATUS_NOT_IMPLEMENTED;
919 #endif
923 static DWORD WINAPI check_events(int fd, DWORD mask,
924 const serial_irq_info *new,
925 const serial_irq_info *old,
926 DWORD new_mstat, DWORD old_mstat)
928 DWORD ret = 0, queue;
930 TRACE("mask 0x%08x\n", mask);
931 TRACE("old->rx 0x%08x vs. new->rx 0x%08x\n", old->rx, new->rx);
932 TRACE("old->tx 0x%08x vs. new->tx 0x%08x\n", old->tx, new->tx);
933 TRACE("old->frame 0x%08x vs. new->frame 0x%08x\n", old->frame, new->frame);
934 TRACE("old->overrun 0x%08x vs. new->overrun 0x%08x\n", old->overrun, new->overrun);
935 TRACE("old->parity 0x%08x vs. new->parity 0x%08x\n", old->parity, new->parity);
936 TRACE("old->brk 0x%08x vs. new->brk 0x%08x\n", old->brk, new->brk);
937 TRACE("old->buf_overrun 0x%08x vs. new->buf_overrun 0x%08x\n", old->buf_overrun, new->buf_overrun);
939 if (old->brk != new->brk) ret |= EV_BREAK;
940 if ((old_mstat & MS_CTS_ON ) != (new_mstat & MS_CTS_ON )) ret |= EV_CTS;
941 if ((old_mstat & MS_DSR_ON ) != (new_mstat & MS_DSR_ON )) ret |= EV_DSR;
942 if ((old_mstat & MS_RING_ON) != (new_mstat & MS_RING_ON)) ret |= EV_RING;
943 if ((old_mstat & MS_RLSD_ON) != (new_mstat & MS_RLSD_ON)) ret |= EV_RLSD;
944 if (old->frame != new->frame || old->overrun != new->overrun || old->parity != new->parity) ret |= EV_ERR;
945 if (mask & EV_RXCHAR)
947 queue = 0;
948 #ifdef TIOCINQ
949 if (ioctl(fd, TIOCINQ, &queue))
950 WARN("TIOCINQ returned error\n");
951 #endif
952 if (queue)
953 ret |= EV_RXCHAR;
955 if (mask & EV_TXEMPTY)
957 queue = 0;
958 /* We really want to know when all characters have gone out of the transmitter */
959 #if defined(TIOCSERGETLSR)
960 if (ioctl(fd, TIOCSERGETLSR, &queue))
961 WARN("TIOCSERGETLSR returned error\n");
962 if (queue)
963 /* TIOCOUTQ only checks for an empty buffer */
964 #elif defined(TIOCOUTQ)
965 if (ioctl(fd, TIOCOUTQ, &queue))
966 WARN("TIOCOUTQ returned error\n");
967 if (!queue)
968 #endif
969 ret |= EV_TXEMPTY;
970 TRACE("OUTQUEUE %d, Transmitter %sempty\n",
971 queue, (ret & EV_TXEMPTY) ? "" : "not ");
973 return ret & mask;
976 /***********************************************************************
977 * wait_for_event (INTERNAL)
979 * We need to poll for what is interesting
980 * TIOCMIWAIT only checks modem status line and may not be aborted by a changing mask
983 static DWORD CALLBACK wait_for_event(LPVOID arg)
985 async_commio *commio = (async_commio*) arg;
986 int fd, needs_close;
988 if (!server_get_unix_fd( commio->hDevice, FILE_READ_DATA | FILE_WRITE_DATA, &fd, &needs_close, NULL, NULL ))
990 serial_irq_info new_irq_info;
991 DWORD new_mstat, new_evtmask;
992 LARGE_INTEGER time;
994 TRACE("device=%p fd=0x%08x mask=0x%08x buffer=%p event=%p irq_info=%p\n",
995 commio->hDevice, fd, commio->evtmask, commio->events, commio->hEvent, &commio->irq_info);
997 time.QuadPart = (ULONGLONG)10000;
998 time.QuadPart = -time.QuadPart;
999 for (;;)
1002 * TIOCMIWAIT is not adequate
1004 * FIXME:
1005 * We don't handle the EV_RXFLAG (the eventchar)
1007 NtDelayExecution(FALSE, &time);
1008 get_irq_info(fd, &new_irq_info);
1009 if (get_modem_status(fd, &new_mstat))
1010 TRACE("get_modem_status failed\n");
1011 *commio->events = check_events(fd, commio->evtmask,
1012 &new_irq_info, &commio->irq_info,
1013 new_mstat, commio->mstat);
1014 if (*commio->events) break;
1015 get_wait_mask(commio->hDevice, &new_evtmask);
1016 if (commio->evtmask != new_evtmask)
1018 *commio->events = 0;
1019 break;
1022 if (needs_close) close( fd );
1024 if (commio->hEvent) NtSetEvent(commio->hEvent, NULL);
1025 RtlFreeHeap(GetProcessHeap(), 0, commio);
1026 return 0;
1029 static NTSTATUS wait_on(HANDLE hDevice, int fd, HANDLE hEvent, DWORD* events)
1031 async_commio* commio;
1032 NTSTATUS status;
1034 if ((status = NtResetEvent(hEvent, NULL)))
1035 return status;
1037 commio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof (async_commio));
1038 if (!commio) return STATUS_NO_MEMORY;
1040 commio->hDevice = hDevice;
1041 commio->events = events;
1042 commio->hEvent = hEvent;
1043 get_wait_mask(commio->hDevice, &commio->evtmask);
1045 /* We may never return, if some capabilities miss
1046 * Return error in that case
1048 #if !defined(TIOCINQ)
1049 if (commio->evtmask & EV_RXCHAR)
1050 goto error_caps;
1051 #endif
1052 #if !(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)
1053 if (commio->evtmask & EV_TXEMPTY)
1054 goto error_caps;
1055 #endif
1056 #if !defined(TIOCMGET)
1057 if (commio->evtmask & (EV_CTS | EV_DSR| EV_RING| EV_RLSD))
1058 goto error_caps;
1059 #endif
1060 #if !defined(TIOCM_CTS)
1061 if (commio->evtmask & EV_CTS)
1062 goto error_caps;
1063 #endif
1064 #if !defined(TIOCM_DSR)
1065 if (commio->evtmask & EV_DSR)
1066 goto error_caps;
1067 #endif
1068 #if !defined(TIOCM_RNG)
1069 if (commio->evtmask & EV_RING)
1070 goto error_caps;
1071 #endif
1072 #if !defined(TIOCM_CAR)
1073 if (commio->evtmask & EV_RLSD)
1074 goto error_caps;
1075 #endif
1076 if (commio->evtmask & EV_RXFLAG)
1077 FIXME("EV_RXFLAG not handled\n");
1078 if ((status = get_irq_info(fd, &commio->irq_info)) ||
1079 (status = get_modem_status(fd, &commio->mstat)))
1080 goto out_now;
1082 /* We might have received something or the TX bufffer is delivered */
1083 *events = check_events(fd, commio->evtmask,
1084 &commio->irq_info, &commio->irq_info,
1085 commio->mstat, commio->mstat);
1086 if (*events) goto out_now;
1088 /* create the worker for the task */
1089 status = RtlQueueWorkItem(wait_for_event, commio, 0 /* FIXME */);
1090 if (status != STATUS_SUCCESS) goto out_now;
1091 return STATUS_PENDING;
1093 #if !defined(TIOCINQ) || (!(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)) || !defined(TIOCMGET) || !defined(TIOCM_CTS) ||!defined(TIOCM_DSR) || !defined(TIOCM_RNG) || !defined(TIOCM_CAR)
1094 error_caps:
1095 FIXME("Returning error because of missing capabilities\n");
1096 status = STATUS_INVALID_PARAMETER;
1097 #endif
1098 out_now:
1099 RtlFreeHeap(GetProcessHeap(), 0, commio);
1100 return status;
1103 static NTSTATUS xmit_immediate(HANDLE hDevice, int fd, const char* ptr)
1105 /* FIXME: not perfect as it should bypass the in-queue */
1106 WARN("(%p,'%c') not perfect!\n", hDevice, *ptr);
1107 if (write(fd, ptr, 1) != 1)
1108 return FILE_GetNtStatus();
1109 return STATUS_SUCCESS;
1112 /******************************************************************
1113 * COMM_DeviceIoControl
1117 static inline NTSTATUS io_control(HANDLE hDevice,
1118 HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
1119 PVOID UserApcContext,
1120 PIO_STATUS_BLOCK piosb,
1121 ULONG dwIoControlCode,
1122 LPVOID lpInBuffer, DWORD nInBufferSize,
1123 LPVOID lpOutBuffer, DWORD nOutBufferSize)
1125 DWORD sz = 0, access = FILE_READ_DATA;
1126 NTSTATUS status = STATUS_SUCCESS;
1127 int fd = -1, needs_close = 0;
1129 TRACE("%p %s %p %d %p %d %p\n",
1130 hDevice, iocode2str(dwIoControlCode), lpInBuffer, nInBufferSize,
1131 lpOutBuffer, nOutBufferSize, piosb);
1133 piosb->Information = 0;
1135 if (dwIoControlCode != IOCTL_SERIAL_GET_TIMEOUTS)
1136 if ((status = server_get_unix_fd( hDevice, access, &fd, &needs_close, NULL, NULL )))
1137 goto error;
1139 switch (dwIoControlCode)
1141 case IOCTL_SERIAL_CLR_DTR:
1142 #ifdef TIOCM_DTR
1143 if (whack_modem(fd, ~TIOCM_DTR, 0) == -1) status = FILE_GetNtStatus();
1144 #else
1145 status = STATUS_NOT_SUPPORTED;
1146 #endif
1147 break;
1148 case IOCTL_SERIAL_CLR_RTS:
1149 #ifdef TIOCM_RTS
1150 if (whack_modem(fd, ~TIOCM_RTS, 0) == -1) status = FILE_GetNtStatus();
1151 #else
1152 status = STATUS_NOT_SUPPORTED;
1153 #endif
1154 break;
1155 case IOCTL_SERIAL_GET_BAUD_RATE:
1156 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_BAUD_RATE))
1158 if (!(status = get_baud_rate(fd, (SERIAL_BAUD_RATE*)lpOutBuffer)))
1159 sz = sizeof(SERIAL_BAUD_RATE);
1161 else
1162 status = STATUS_INVALID_PARAMETER;
1163 break;
1164 case IOCTL_SERIAL_GET_CHARS:
1165 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_CHARS))
1167 if (!(status = get_special_chars(fd, (SERIAL_CHARS*)lpOutBuffer)))
1168 sz = sizeof(SERIAL_CHARS);
1170 else
1171 status = STATUS_INVALID_PARAMETER;
1172 break;
1173 case IOCTL_SERIAL_GET_COMMSTATUS:
1174 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_STATUS))
1176 if (!(status = get_status(fd, (SERIAL_STATUS*)lpOutBuffer)))
1177 sz = sizeof(SERIAL_STATUS);
1179 else status = STATUS_INVALID_PARAMETER;
1180 break;
1181 case IOCTL_SERIAL_GET_HANDFLOW:
1182 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_HANDFLOW))
1184 if (!(status = get_hand_flow(fd, (SERIAL_HANDFLOW*)lpOutBuffer)))
1185 sz = sizeof(SERIAL_HANDFLOW);
1187 else
1188 status = STATUS_INVALID_PARAMETER;
1189 break;
1190 case IOCTL_SERIAL_GET_LINE_CONTROL:
1191 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_LINE_CONTROL))
1193 if (!(status = get_line_control(fd, (SERIAL_LINE_CONTROL*)lpOutBuffer)))
1194 sz = sizeof(SERIAL_LINE_CONTROL);
1196 else
1197 status = STATUS_INVALID_PARAMETER;
1198 break;
1199 case IOCTL_SERIAL_GET_MODEMSTATUS:
1200 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1202 if (!(status = get_modem_status(fd, (DWORD*)lpOutBuffer)))
1203 sz = sizeof(DWORD);
1205 else status = STATUS_INVALID_PARAMETER;
1206 break;
1207 case IOCTL_SERIAL_GET_TIMEOUTS:
1208 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_TIMEOUTS))
1210 if (!(status = get_timeouts(hDevice, (SERIAL_TIMEOUTS*)lpOutBuffer)))
1211 sz = sizeof(SERIAL_TIMEOUTS);
1213 else
1214 status = STATUS_INVALID_PARAMETER;
1215 break;
1216 case IOCTL_SERIAL_GET_WAIT_MASK:
1217 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1219 if (!(status = get_wait_mask(hDevice, (DWORD*)lpOutBuffer)))
1220 sz = sizeof(DWORD);
1222 else
1223 status = STATUS_INVALID_PARAMETER;
1224 break;
1225 case IOCTL_SERIAL_IMMEDIATE_CHAR:
1226 if (lpInBuffer && nInBufferSize == sizeof(CHAR))
1227 status = xmit_immediate(hDevice, fd, lpInBuffer);
1228 else
1229 status = STATUS_INVALID_PARAMETER;
1230 break;
1231 case IOCTL_SERIAL_PURGE:
1232 if (lpInBuffer && nInBufferSize == sizeof(DWORD))
1233 status = purge(fd, *(DWORD*)lpInBuffer);
1234 else
1235 status = STATUS_INVALID_PARAMETER;
1236 break;
1237 case IOCTL_SERIAL_RESET_DEVICE:
1238 FIXME("Unsupported\n");
1239 break;
1240 case IOCTL_SERIAL_SET_BAUD_RATE:
1241 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_BAUD_RATE))
1242 status = set_baud_rate(fd, (const SERIAL_BAUD_RATE*)lpInBuffer);
1243 else
1244 status = STATUS_INVALID_PARAMETER;
1245 break;
1246 case IOCTL_SERIAL_SET_BREAK_OFF:
1247 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1248 if (ioctl(fd, TIOCCBRK, 0) == -1)
1250 TRACE("ioctl failed\n");
1251 status = FILE_GetNtStatus();
1253 #else
1254 FIXME("ioctl not available\n");
1255 status = STATUS_NOT_SUPPORTED;
1256 #endif
1257 break;
1258 case IOCTL_SERIAL_SET_BREAK_ON:
1259 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1260 if (ioctl(fd, TIOCSBRK, 0) == -1)
1262 TRACE("ioctl failed\n");
1263 status = FILE_GetNtStatus();
1265 #else
1266 FIXME("ioctl not available\n");
1267 status = STATUS_NOT_SUPPORTED;
1268 #endif
1269 break;
1270 case IOCTL_SERIAL_SET_CHARS:
1271 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_CHARS))
1272 status = set_special_chars(fd, (const SERIAL_CHARS*)lpInBuffer);
1273 else
1274 status = STATUS_INVALID_PARAMETER;
1275 break;
1276 case IOCTL_SERIAL_SET_DTR:
1277 #ifdef TIOCM_DTR
1278 if (whack_modem(fd, 0, TIOCM_DTR) == -1) status = FILE_GetNtStatus();
1279 #else
1280 status = STATUS_NOT_SUPPORTED;
1281 #endif
1282 break;
1283 case IOCTL_SERIAL_SET_HANDFLOW:
1284 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_HANDFLOW))
1285 status = set_handflow(fd, (const SERIAL_HANDFLOW*)lpInBuffer);
1286 else
1287 status = STATUS_INVALID_PARAMETER;
1288 break;
1289 case IOCTL_SERIAL_SET_LINE_CONTROL:
1290 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_LINE_CONTROL))
1291 status = set_line_control(fd, (const SERIAL_LINE_CONTROL*)lpInBuffer);
1292 else
1293 status = STATUS_INVALID_PARAMETER;
1294 break;
1295 case IOCTL_SERIAL_SET_QUEUE_SIZE:
1296 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_QUEUE_SIZE))
1297 status = set_queue_size(fd, (const SERIAL_QUEUE_SIZE*)lpInBuffer);
1298 else
1299 status = STATUS_INVALID_PARAMETER;
1300 break;
1301 case IOCTL_SERIAL_SET_RTS:
1302 #ifdef TIOCM_RTS
1303 if (whack_modem(fd, 0, TIOCM_RTS) == -1) status = FILE_GetNtStatus();
1304 #else
1305 status = STATUS_NOT_SUPPORTED;
1306 #endif
1307 break;
1308 case IOCTL_SERIAL_SET_TIMEOUTS:
1309 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_TIMEOUTS))
1310 status = set_timeouts(hDevice, fd, (const SERIAL_TIMEOUTS*)lpInBuffer);
1311 else
1312 status = STATUS_INVALID_PARAMETER;
1313 break;
1314 case IOCTL_SERIAL_SET_WAIT_MASK:
1315 if (lpInBuffer && nInBufferSize == sizeof(DWORD))
1317 status = set_wait_mask(hDevice, *(DWORD*)lpInBuffer);
1319 else status = STATUS_INVALID_PARAMETER;
1320 break;
1321 case IOCTL_SERIAL_SET_XOFF:
1322 status = set_XOff(fd);
1323 break;
1324 case IOCTL_SERIAL_SET_XON:
1325 status = set_XOn(fd);
1326 break;
1327 case IOCTL_SERIAL_WAIT_ON_MASK:
1328 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1330 if (!(status = wait_on(hDevice, fd, hEvent, (DWORD*)lpOutBuffer)))
1331 sz = sizeof(DWORD);
1333 else
1334 status = STATUS_INVALID_PARAMETER;
1335 break;
1336 default:
1337 FIXME("Unsupported IOCTL %x (type=%x access=%x func=%x meth=%x)\n",
1338 dwIoControlCode, dwIoControlCode >> 16, (dwIoControlCode >> 14) & 3,
1339 (dwIoControlCode >> 2) & 0xFFF, dwIoControlCode & 3);
1340 sz = 0;
1341 status = STATUS_INVALID_PARAMETER;
1342 break;
1344 if (needs_close) close( fd );
1345 error:
1346 piosb->u.Status = status;
1347 piosb->Information = sz;
1348 if (hEvent && status != STATUS_PENDING) NtSetEvent(hEvent, NULL);
1349 return status;
1352 NTSTATUS COMM_DeviceIoControl(HANDLE hDevice,
1353 HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
1354 PVOID UserApcContext,
1355 PIO_STATUS_BLOCK piosb,
1356 ULONG dwIoControlCode,
1357 LPVOID lpInBuffer, DWORD nInBufferSize,
1358 LPVOID lpOutBuffer, DWORD nOutBufferSize)
1360 NTSTATUS status;
1362 if (dwIoControlCode == IOCTL_SERIAL_WAIT_ON_MASK)
1364 HANDLE hev = hEvent;
1366 /* this is an ioctl we implement in a non blocking way if hEvent is not
1367 * null
1368 * so we have to explicitly wait if no hEvent is provided
1370 if (!hev)
1372 OBJECT_ATTRIBUTES attr;
1374 attr.Length = sizeof(attr);
1375 attr.RootDirectory = 0;
1376 attr.ObjectName = NULL;
1377 attr.Attributes = OBJ_CASE_INSENSITIVE | OBJ_OPENIF;
1378 attr.SecurityDescriptor = NULL;
1379 attr.SecurityQualityOfService = NULL;
1380 status = NtCreateEvent(&hev, EVENT_ALL_ACCESS, &attr, FALSE, FALSE);
1382 if (status) goto done;
1384 status = io_control(hDevice, hev, UserApcRoutine, UserApcContext,
1385 piosb, dwIoControlCode, lpInBuffer, nInBufferSize,
1386 lpOutBuffer, nOutBufferSize);
1387 if (hev != hEvent)
1389 if (status == STATUS_PENDING)
1391 NtWaitForSingleObject(hev, FALSE, NULL);
1392 status = STATUS_SUCCESS;
1394 NtClose(hev);
1397 else status = io_control(hDevice, hEvent, UserApcRoutine, UserApcContext,
1398 piosb, dwIoControlCode, lpInBuffer, nInBufferSize,
1399 lpOutBuffer, nOutBufferSize);
1400 done:
1401 return status;