server: Add support for 64-bits client/server
[wine/wine64.git] / dlls / ntdll / serial.c
blobdc16cc51ffe96f41035cbc4bc124936a9d2fc3c7
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_NOT_SUPPORTED;
291 int mstat;
293 *lpModemStat = 0;
294 #ifdef TIOCMGET
295 if (!ioctl(fd, TIOCMGET, &mstat))
297 #ifdef TIOCM_CTS
298 if (mstat & TIOCM_CTS) *lpModemStat |= MS_CTS_ON;
299 #endif
300 #ifdef TIOCM_DSR
301 if (mstat & TIOCM_DSR) *lpModemStat |= MS_DSR_ON;
302 #endif
303 #ifdef TIOCM_RNG
304 if (mstat & TIOCM_RNG) *lpModemStat |= MS_RING_ON;
305 #endif
306 #ifdef TIOCM_CAR
307 /* FIXME: Not really sure about RLSD UB 990810 */
308 if (mstat & TIOCM_CAR) *lpModemStat |= MS_RLSD_ON;
309 #endif
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();
319 #endif
320 return status;
323 static NTSTATUS get_special_chars(int fd, SERIAL_CHARS* sc)
325 struct termios port;
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;
346 ss->Errors = 0;
347 ss->HoldReasons = 0;
348 ss->EofReceived = FALSE;
349 ss->WaitForImmediate = FALSE;
350 #ifdef TIOCOUTQ
351 if (ioctl(fd, TIOCOUTQ, &ss->AmountInOutQueue) == -1)
353 WARN("ioctl returned error\n");
354 status = FILE_GetNtStatus();
356 #else
357 ss->AmountInOutQueue = 0; /* FIXME: find a different way to find out */
358 #endif
360 #ifdef TIOCINQ
361 if (ioctl(fd, TIOCINQ, &ss->AmountInInQueue))
363 WARN("ioctl returned error\n");
364 status = FILE_GetNtStatus();
366 #else
367 ss->AmountInInQueue = 0; /* FIXME: find a different way to find out */
368 #endif
369 return status;
372 static NTSTATUS get_timeouts(HANDLE handle, SERIAL_TIMEOUTS* st)
374 NTSTATUS status;
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;
387 SERVER_END_REQ;
388 return status;
391 static NTSTATUS get_wait_mask(HANDLE hDevice, DWORD* mask)
393 NTSTATUS status;
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;
401 SERVER_END_REQ;
402 return status;
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)
421 struct termios port;
423 if (tcgetattr(fd, &port) == -1)
425 ERR("tcgetattr error '%s'\n", strerror(errno));
426 return FILE_GetNtStatus();
429 #ifdef CBAUD
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;
436 case 110:
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;
441 case 300:
442 case CBR_300: port.c_cflag |= B300; break;
443 case 600:
444 case CBR_600: port.c_cflag |= B600; break;
445 case 1200:
446 case CBR_1200: port.c_cflag |= B1200; break;
447 case 1800: port.c_cflag |= B1800; break;
448 case 2400:
449 case CBR_2400: port.c_cflag |= B2400; break;
450 case 4800:
451 case CBR_4800: port.c_cflag |= B4800; break;
452 case 9600:
453 case CBR_9600: port.c_cflag |= B9600; break;
454 case 19200:
455 case CBR_19200: port.c_cflag |= B19200; break;
456 case 38400:
457 case CBR_38400: port.c_cflag |= B38400; break;
458 #ifdef B57600
459 case 57600: port.c_cflag |= B57600; break;
460 #endif
461 #ifdef B115200
462 case 115200: port.c_cflag |= B115200;break;
463 #endif
464 #ifdef B230400
465 case 230400: port.c_cflag |= B230400;break;
466 #endif
467 #ifdef B460800
468 case 460800: port.c_cflag |= B460800;break;
469 #endif
470 default:
471 #if defined (HAVE_LINUX_SERIAL_H) && defined (TIOCSSERIAL)
473 struct serial_struct nuts;
474 int arby;
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;
492 break;
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;
504 case 110:
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;
509 case 300:
510 case CBR_300: port.c_ospeed = B300; break;
511 case 600:
512 case CBR_600: port.c_ospeed = B600; break;
513 case 1200:
514 case CBR_1200: port.c_ospeed = B1200; break;
515 case 1800: port.c_ospeed = B1800; break;
516 case 2400:
517 case CBR_2400: port.c_ospeed = B2400; break;
518 case 4800:
519 case CBR_4800: port.c_ospeed = B4800; break;
520 case 9600:
521 case CBR_9600: port.c_ospeed = B9600; break;
522 case 19200:
523 case CBR_19200: port.c_ospeed = B19200; break;
524 case 38400:
525 case CBR_38400: port.c_ospeed = B38400; break;
526 #ifdef B57600
527 case 57600:
528 case CBR_57600: port.c_cflag |= B57600; break;
529 #endif
530 #ifdef B115200
531 case 115200:
532 case CBR_115200: port.c_cflag |= B115200;break;
533 #endif
534 #ifdef B230400
535 case 230400: port.c_cflag |= B230400;break;
536 #endif
537 #ifdef B460800
538 case 460800: port.c_cflag |= B460800;break;
539 #endif
540 default:
541 ERR("baudrate %d\n", sbr->BaudRate);
542 return STATUS_NOT_SUPPORTED;
544 port.c_ispeed = port.c_ospeed;
545 #endif
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)
556 #ifdef TIOCMGET
557 unsigned int mstat, okay;
558 okay = ioctl(fd, TIOCMGET, &mstat);
559 if (okay) return okay;
560 if (andy) mstat &= andy;
561 mstat |= orrie;
562 return ioctl(fd, TIOCMSET, &mstat);
563 #else
564 return 0;
565 #endif
568 static NTSTATUS set_handflow(int fd, const SERIAL_HANDFLOW* shf)
570 struct termios port;
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();
582 #ifdef CRTSCTS
583 if ((shf->ControlHandShake & SERIAL_CTS_HANDSHAKE) ||
584 (shf->FlowReplace & SERIAL_RTS_HANDSHAKE))
586 port.c_cflag |= CRTSCTS;
587 TRACE("CRTSCTS\n");
589 else
590 port.c_cflag &= ~CRTSCTS;
591 #endif
592 #ifdef TIOCM_DTR
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);
598 else
599 whack_modem(fd, 0, TIOCM_DTR);
600 #endif
601 #ifdef TIOCM_RTS
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);
606 else
607 whack_modem(fd, 0, TIOCM_RTS);
609 #endif
611 if (shf->FlowReplace & SERIAL_AUTO_RECEIVE)
612 port.c_iflag |= IXOFF;
613 else
614 port.c_iflag &= ~IXOFF;
615 if (shf->FlowReplace & SERIAL_AUTO_TRANSMIT)
616 port.c_iflag |= IXON;
617 else
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)
630 struct termios port;
631 unsigned bytesize, stopbits;
633 if (tcgetattr(fd, &port) == -1)
635 ERR("tcgetattr error '%s'\n", strerror(errno));
636 return FILE_GetNtStatus();
639 #ifdef IMAXBEL
640 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK|IMAXBEL);
641 #else
642 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK);
643 #endif
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;
657 #ifdef CMSPAR
658 port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
659 #else
660 port.c_cflag &= ~(PARENB | PARODD);
661 #endif
663 /* make sure that reads don't block */
664 port.c_cc[VMIN] = 0;
665 port.c_cc[VTIME] = 0;
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[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)
771 NTSTATUS status;
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 );
784 SERVER_END_REQ;
785 return status;
788 static NTSTATUS set_wait_mask(HANDLE hDevice, DWORD mask)
790 NTSTATUS status;
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 );
799 SERVER_END_REQ;
800 return status;
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;
827 /* serial_irq_info
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;
838 }serial_irq_info;
840 /***********************************************************************
841 * Data needed by the thread polling for the changing CommEvent
843 typedef struct async_commio
845 HANDLE hDevice;
846 DWORD* events;
847 HANDLE hEvent;
848 DWORD evtmask;
849 DWORD mstat;
850 serial_irq_info irq_info;
851 } async_commio;
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;
859 #ifdef TIOCGICOUNT
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();
874 #endif
875 memset(irq_info,0, sizeof(serial_irq_info));
876 return status;
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)
904 queue = 0;
905 #ifdef TIOCINQ
906 if (ioctl(fd, TIOCINQ, &queue))
907 WARN("TIOCINQ returned error\n");
908 #endif
909 if (queue)
910 ret |= EV_RXCHAR;
912 if (mask & EV_TXEMPTY)
914 queue = 0;
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");
919 if (queue)
920 /* TIOCOUTQ only checks for an empty buffer */
921 #elif defined(TIOCOUTQ)
922 if (ioctl(fd, TIOCOUTQ, &queue))
923 WARN("TIOCOUTQ returned error\n");
924 if (!queue)
925 #endif
926 ret |= EV_TXEMPTY;
927 TRACE("OUTQUEUE %d, Transmitter %sempty\n",
928 queue, (ret & EV_TXEMPTY) ? "" : "not ");
930 return ret & mask;
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;
943 int fd, needs_close;
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;
949 LARGE_INTEGER time;
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;
956 for (;;)
959 * TIOCMIWAIT is not adequate
961 * FIXME:
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)
975 *commio->events = 0;
976 break;
979 if (needs_close) close( fd );
981 if (commio->hEvent) NtSetEvent(commio->hEvent, NULL);
982 RtlFreeHeap(GetProcessHeap(), 0, commio);
983 return 0;
986 static NTSTATUS wait_on(HANDLE hDevice, int fd, HANDLE hEvent, DWORD* events)
988 async_commio* commio;
989 NTSTATUS status;
991 if ((status = NtResetEvent(hEvent, NULL)))
992 return status;
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)
1007 goto error_caps;
1008 #endif
1009 #if !(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)
1010 if (commio->evtmask & EV_TXEMPTY)
1011 goto error_caps;
1012 #endif
1013 #if !defined(TIOCMGET)
1014 if (commio->evtmask & (EV_CTS | EV_DSR| EV_RING| EV_RLSD))
1015 goto error_caps;
1016 #endif
1017 #if !defined(TIOCM_CTS)
1018 if (commio->evtmask & EV_CTS)
1019 goto error_caps;
1020 #endif
1021 #if !defined(TIOCM_DSR)
1022 if (commio->evtmask & EV_DSR)
1023 goto error_caps;
1024 #endif
1025 #if !defined(TIOCM_RNG)
1026 if (commio->evtmask & EV_RING)
1027 goto error_caps;
1028 #endif
1029 #if !defined(TIOCM_CAR)
1030 if (commio->evtmask & EV_RLSD)
1031 goto error_caps;
1032 #endif
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)))
1038 goto out_now;
1040 if ((status = get_modem_status(fd, &commio->mstat)) &&
1041 (commio->evtmask & (EV_CTS | EV_DSR| EV_RING| EV_RLSD)))
1042 goto out_now;
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);
1048 if (*events)
1050 status = STATUS_SUCCESS;
1051 goto out_now;
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)
1060 error_caps:
1061 FIXME("Returning error because of missing capabilities\n");
1062 status = STATUS_INVALID_PARAMETER;
1063 #endif
1064 out_now:
1065 RtlFreeHeap(GetProcessHeap(), 0, commio);
1066 return status;
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 )))
1104 goto error;
1106 switch (dwIoControlCode)
1108 case IOCTL_SERIAL_CLR_DTR:
1109 #ifdef TIOCM_DTR
1110 if (whack_modem(fd, ~TIOCM_DTR, 0) == -1) status = FILE_GetNtStatus();
1111 #else
1112 status = STATUS_NOT_SUPPORTED;
1113 #endif
1114 break;
1115 case IOCTL_SERIAL_CLR_RTS:
1116 #ifdef TIOCM_RTS
1117 if (whack_modem(fd, ~TIOCM_RTS, 0) == -1) status = FILE_GetNtStatus();
1118 #else
1119 status = STATUS_NOT_SUPPORTED;
1120 #endif
1121 break;
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);
1128 else
1129 status = STATUS_INVALID_PARAMETER;
1130 break;
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);
1137 else
1138 status = STATUS_INVALID_PARAMETER;
1139 break;
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;
1147 break;
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);
1154 else
1155 status = STATUS_INVALID_PARAMETER;
1156 break;
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);
1163 else
1164 status = STATUS_INVALID_PARAMETER;
1165 break;
1166 case IOCTL_SERIAL_GET_MODEMSTATUS:
1167 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1169 if (!(status = get_modem_status(fd, (DWORD*)lpOutBuffer)))
1170 sz = sizeof(DWORD);
1172 else status = STATUS_INVALID_PARAMETER;
1173 break;
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);
1180 else
1181 status = STATUS_INVALID_PARAMETER;
1182 break;
1183 case IOCTL_SERIAL_GET_WAIT_MASK:
1184 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1186 if (!(status = get_wait_mask(hDevice, (DWORD*)lpOutBuffer)))
1187 sz = sizeof(DWORD);
1189 else
1190 status = STATUS_INVALID_PARAMETER;
1191 break;
1192 case IOCTL_SERIAL_IMMEDIATE_CHAR:
1193 if (lpInBuffer && nInBufferSize == sizeof(CHAR))
1194 status = xmit_immediate(hDevice, fd, lpInBuffer);
1195 else
1196 status = STATUS_INVALID_PARAMETER;
1197 break;
1198 case IOCTL_SERIAL_PURGE:
1199 if (lpInBuffer && nInBufferSize == sizeof(DWORD))
1200 status = purge(fd, *(DWORD*)lpInBuffer);
1201 else
1202 status = STATUS_INVALID_PARAMETER;
1203 break;
1204 case IOCTL_SERIAL_RESET_DEVICE:
1205 FIXME("Unsupported\n");
1206 break;
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);
1210 else
1211 status = STATUS_INVALID_PARAMETER;
1212 break;
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();
1220 #else
1221 FIXME("ioctl not available\n");
1222 status = STATUS_NOT_SUPPORTED;
1223 #endif
1224 break;
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();
1232 #else
1233 FIXME("ioctl not available\n");
1234 status = STATUS_NOT_SUPPORTED;
1235 #endif
1236 break;
1237 case IOCTL_SERIAL_SET_CHARS:
1238 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_CHARS))
1239 status = set_special_chars(fd, (const SERIAL_CHARS*)lpInBuffer);
1240 else
1241 status = STATUS_INVALID_PARAMETER;
1242 break;
1243 case IOCTL_SERIAL_SET_DTR:
1244 #ifdef TIOCM_DTR
1245 if (whack_modem(fd, 0, TIOCM_DTR) == -1) status = FILE_GetNtStatus();
1246 #else
1247 status = STATUS_NOT_SUPPORTED;
1248 #endif
1249 break;
1250 case IOCTL_SERIAL_SET_HANDFLOW:
1251 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_HANDFLOW))
1252 status = set_handflow(fd, (const SERIAL_HANDFLOW*)lpInBuffer);
1253 else
1254 status = STATUS_INVALID_PARAMETER;
1255 break;
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);
1259 else
1260 status = STATUS_INVALID_PARAMETER;
1261 break;
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);
1265 else
1266 status = STATUS_INVALID_PARAMETER;
1267 break;
1268 case IOCTL_SERIAL_SET_RTS:
1269 #ifdef TIOCM_RTS
1270 if (whack_modem(fd, 0, TIOCM_RTS) == -1) status = FILE_GetNtStatus();
1271 #else
1272 status = STATUS_NOT_SUPPORTED;
1273 #endif
1274 break;
1275 case IOCTL_SERIAL_SET_TIMEOUTS:
1276 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_TIMEOUTS))
1277 status = set_timeouts(hDevice, (const SERIAL_TIMEOUTS*)lpInBuffer);
1278 else
1279 status = STATUS_INVALID_PARAMETER;
1280 break;
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;
1287 break;
1288 case IOCTL_SERIAL_SET_XOFF:
1289 status = set_XOff(fd);
1290 break;
1291 case IOCTL_SERIAL_SET_XON:
1292 status = set_XOn(fd);
1293 break;
1294 case IOCTL_SERIAL_WAIT_ON_MASK:
1295 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1297 if (!(status = wait_on(hDevice, fd, hEvent, (DWORD*)lpOutBuffer)))
1298 sz = sizeof(DWORD);
1300 else
1301 status = STATUS_INVALID_PARAMETER;
1302 break;
1303 default:
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);
1307 sz = 0;
1308 status = STATUS_INVALID_PARAMETER;
1309 break;
1311 if (needs_close) close( fd );
1312 error:
1313 piosb->u.Status = status;
1314 piosb->Information = sz;
1315 if (hEvent && status != STATUS_PENDING) NtSetEvent(hEvent, NULL);
1316 return status;
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)
1327 NTSTATUS status;
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
1334 * null
1335 * so we have to explicitly wait if no hEvent is provided
1337 if (!hev)
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);
1354 if (hev != hEvent)
1356 if (status == STATUS_PENDING)
1358 NtWaitForSingleObject(hev, FALSE, NULL);
1359 status = STATUS_SUCCESS;
1361 NtClose(hev);
1364 else status = io_control(hDevice, hEvent, UserApcRoutine, UserApcContext,
1365 piosb, dwIoControlCode, lpInBuffer, nInBufferSize,
1366 lpOutBuffer, nOutBufferSize);
1367 done:
1368 return status;