kernel32/tests: Add a few more tests, fix some failures on Windows.
[wine/wine-kai.git] / dlls / ntdll / serial.c
blobbdb47e49003d38cf70d42828d687d71ed2122f9d
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 = 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 = 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 = 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 = hDevice;
795 req->flags = SERIALINFO_SET_MASK;
796 req->eventmask = mask;
797 status = wine_server_call( req );
799 SERVER_END_REQ;
800 return status;
803 static NTSTATUS set_XOff(int fd)
805 struct termios port;
807 if (tcgetattr(fd,&port) == -1)
809 FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
810 return FILE_GetNtStatus();
814 port.c_iflag |= IXOFF;
815 if (tcsetattr(fd, TCSADRAIN, &port) == -1)
817 FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
818 return FILE_GetNtStatus();
820 return STATUS_SUCCESS;
823 static NTSTATUS set_XOn(int fd)
825 struct termios port;
827 if (tcgetattr(fd,&port) == -1)
829 FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
830 return FILE_GetNtStatus();
832 port.c_iflag |= IXON;
833 if (tcsetattr(fd, TCSADRAIN, &port) == -1)
835 FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
836 return FILE_GetNtStatus();
838 return STATUS_SUCCESS;
841 /* serial_irq_info
842 * local structure holding the irq values we need for WaitCommEvent()
844 * Stripped down from struct serial_icounter_struct, which may not be available on some systems
845 * As the modem line interrupts (cts, dsr, rng, dcd) only get updated with TIOCMIWAIT active,
846 * no need to carry them in the internal structure
849 typedef struct serial_irq_info
851 int rx , tx, frame, overrun, parity, brk, buf_overrun;
852 }serial_irq_info;
854 /***********************************************************************
855 * Data needed by the thread polling for the changing CommEvent
857 typedef struct async_commio
859 HANDLE hDevice;
860 DWORD* events;
861 HANDLE hEvent;
862 DWORD evtmask;
863 DWORD mstat;
864 serial_irq_info irq_info;
865 } async_commio;
867 /***********************************************************************
868 * Get extended interrupt count info, needed for wait_on
870 static NTSTATUS get_irq_info(int fd, serial_irq_info *irq_info)
872 NTSTATUS status = STATUS_NOT_IMPLEMENTED;
873 #ifdef TIOCGICOUNT
874 struct serial_icounter_struct einfo;
875 if (!ioctl(fd, TIOCGICOUNT, &einfo))
877 irq_info->rx = einfo.rx;
878 irq_info->tx = einfo.tx;
879 irq_info->frame = einfo.frame;
880 irq_info->overrun = einfo.overrun;
881 irq_info->parity = einfo.parity;
882 irq_info->brk = einfo.brk;
883 irq_info->buf_overrun = einfo.buf_overrun;
884 return STATUS_SUCCESS;
886 TRACE("TIOCGICOUNT err %s\n", strerror(errno));
887 status = FILE_GetNtStatus();
888 #endif
889 memset(irq_info,0, sizeof(serial_irq_info));
890 return status;
894 static DWORD WINAPI check_events(int fd, DWORD mask,
895 const serial_irq_info *new,
896 const serial_irq_info *old,
897 DWORD new_mstat, DWORD old_mstat)
899 DWORD ret = 0, queue;
901 TRACE("mask 0x%08x\n", mask);
902 TRACE("old->rx 0x%08x vs. new->rx 0x%08x\n", old->rx, new->rx);
903 TRACE("old->tx 0x%08x vs. new->tx 0x%08x\n", old->tx, new->tx);
904 TRACE("old->frame 0x%08x vs. new->frame 0x%08x\n", old->frame, new->frame);
905 TRACE("old->overrun 0x%08x vs. new->overrun 0x%08x\n", old->overrun, new->overrun);
906 TRACE("old->parity 0x%08x vs. new->parity 0x%08x\n", old->parity, new->parity);
907 TRACE("old->brk 0x%08x vs. new->brk 0x%08x\n", old->brk, new->brk);
908 TRACE("old->buf_overrun 0x%08x vs. new->buf_overrun 0x%08x\n", old->buf_overrun, new->buf_overrun);
910 if (old->brk != new->brk) ret |= EV_BREAK;
911 if ((old_mstat & MS_CTS_ON ) != (new_mstat & MS_CTS_ON )) ret |= EV_CTS;
912 if ((old_mstat & MS_DSR_ON ) != (new_mstat & MS_DSR_ON )) ret |= EV_DSR;
913 if ((old_mstat & MS_RING_ON) != (new_mstat & MS_RING_ON)) ret |= EV_RING;
914 if ((old_mstat & MS_RLSD_ON) != (new_mstat & MS_RLSD_ON)) ret |= EV_RLSD;
915 if (old->frame != new->frame || old->overrun != new->overrun || old->parity != new->parity) ret |= EV_ERR;
916 if (mask & EV_RXCHAR)
918 queue = 0;
919 #ifdef TIOCINQ
920 if (ioctl(fd, TIOCINQ, &queue))
921 WARN("TIOCINQ returned error\n");
922 #endif
923 if (queue)
924 ret |= EV_RXCHAR;
926 if (mask & EV_TXEMPTY)
928 queue = 0;
929 /* We really want to know when all characters have gone out of the transmitter */
930 #if defined(TIOCSERGETLSR)
931 if (ioctl(fd, TIOCSERGETLSR, &queue))
932 WARN("TIOCSERGETLSR returned error\n");
933 if (queue)
934 /* TIOCOUTQ only checks for an empty buffer */
935 #elif defined(TIOCOUTQ)
936 if (ioctl(fd, TIOCOUTQ, &queue))
937 WARN("TIOCOUTQ returned error\n");
938 if (!queue)
939 #endif
940 ret |= EV_TXEMPTY;
941 TRACE("OUTQUEUE %d, Transmitter %sempty\n",
942 queue, (ret & EV_TXEMPTY) ? "" : "not ");
944 return ret & mask;
947 /***********************************************************************
948 * wait_for_event (INTERNAL)
950 * We need to poll for what is interesting
951 * TIOCMIWAIT only checks modem status line and may not be aborted by a changing mask
954 static DWORD CALLBACK wait_for_event(LPVOID arg)
956 async_commio *commio = (async_commio*) arg;
957 int fd, needs_close;
959 if (!server_get_unix_fd( commio->hDevice, FILE_READ_DATA | FILE_WRITE_DATA, &fd, &needs_close, NULL, NULL ))
961 serial_irq_info new_irq_info;
962 DWORD new_mstat, new_evtmask;
963 LARGE_INTEGER time;
965 TRACE("device=%p fd=0x%08x mask=0x%08x buffer=%p event=%p irq_info=%p\n",
966 commio->hDevice, fd, commio->evtmask, commio->events, commio->hEvent, &commio->irq_info);
968 time.QuadPart = (ULONGLONG)10000;
969 time.QuadPart = -time.QuadPart;
970 for (;;)
973 * TIOCMIWAIT is not adequate
975 * FIXME:
976 * We don't handle the EV_RXFLAG (the eventchar)
978 NtDelayExecution(FALSE, &time);
979 get_irq_info(fd, &new_irq_info);
980 if (get_modem_status(fd, &new_mstat))
981 TRACE("get_modem_status failed\n");
982 *commio->events = check_events(fd, commio->evtmask,
983 &new_irq_info, &commio->irq_info,
984 new_mstat, commio->mstat);
985 if (*commio->events) break;
986 get_wait_mask(commio->hDevice, &new_evtmask);
987 if (commio->evtmask != new_evtmask)
989 *commio->events = 0;
990 break;
993 if (needs_close) close( fd );
995 if (commio->hEvent) NtSetEvent(commio->hEvent, NULL);
996 RtlFreeHeap(GetProcessHeap(), 0, commio);
997 return 0;
1000 static NTSTATUS wait_on(HANDLE hDevice, int fd, HANDLE hEvent, DWORD* events)
1002 async_commio* commio;
1003 NTSTATUS status;
1005 if ((status = NtResetEvent(hEvent, NULL)))
1006 return status;
1008 commio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof (async_commio));
1009 if (!commio) return STATUS_NO_MEMORY;
1011 commio->hDevice = hDevice;
1012 commio->events = events;
1013 commio->hEvent = hEvent;
1014 get_wait_mask(commio->hDevice, &commio->evtmask);
1016 /* We may never return, if some capabilities miss
1017 * Return error in that case
1019 #if !defined(TIOCINQ)
1020 if (commio->evtmask & EV_RXCHAR)
1021 goto error_caps;
1022 #endif
1023 #if !(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)
1024 if (commio->evtmask & EV_TXEMPTY)
1025 goto error_caps;
1026 #endif
1027 #if !defined(TIOCMGET)
1028 if (commio->evtmask & (EV_CTS | EV_DSR| EV_RING| EV_RLSD))
1029 goto error_caps;
1030 #endif
1031 #if !defined(TIOCM_CTS)
1032 if (commio->evtmask & EV_CTS)
1033 goto error_caps;
1034 #endif
1035 #if !defined(TIOCM_DSR)
1036 if (commio->evtmask & EV_DSR)
1037 goto error_caps;
1038 #endif
1039 #if !defined(TIOCM_RNG)
1040 if (commio->evtmask & EV_RING)
1041 goto error_caps;
1042 #endif
1043 #if !defined(TIOCM_CAR)
1044 if (commio->evtmask & EV_RLSD)
1045 goto error_caps;
1046 #endif
1047 if (commio->evtmask & EV_RXFLAG)
1048 FIXME("EV_RXFLAG not handled\n");
1050 if ((status = get_irq_info(fd, &commio->irq_info)) &&
1051 (commio->evtmask & (EV_BREAK | EV_ERR)))
1052 goto out_now;
1054 if ((status = get_modem_status(fd, &commio->mstat)) &&
1055 (commio->evtmask & (EV_CTS | EV_DSR| EV_RING| EV_RLSD)))
1056 goto out_now;
1058 /* We might have received something or the TX buffer is delivered */
1059 *events = check_events(fd, commio->evtmask,
1060 &commio->irq_info, &commio->irq_info,
1061 commio->mstat, commio->mstat);
1062 if (*events)
1064 status = STATUS_SUCCESS;
1065 goto out_now;
1068 /* create the worker for the task */
1069 status = RtlQueueWorkItem(wait_for_event, commio, 0 /* FIXME */);
1070 if (status != STATUS_SUCCESS) goto out_now;
1071 return STATUS_PENDING;
1073 #if !defined(TIOCINQ) || (!(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)) || !defined(TIOCMGET) || !defined(TIOCM_CTS) ||!defined(TIOCM_DSR) || !defined(TIOCM_RNG) || !defined(TIOCM_CAR)
1074 error_caps:
1075 FIXME("Returning error because of missing capabilities\n");
1076 status = STATUS_INVALID_PARAMETER;
1077 #endif
1078 out_now:
1079 RtlFreeHeap(GetProcessHeap(), 0, commio);
1080 return status;
1083 static NTSTATUS xmit_immediate(HANDLE hDevice, int fd, const char* ptr)
1085 /* FIXME: not perfect as it should bypass the in-queue */
1086 WARN("(%p,'%c') not perfect!\n", hDevice, *ptr);
1087 if (write(fd, ptr, 1) != 1)
1088 return FILE_GetNtStatus();
1089 return STATUS_SUCCESS;
1092 /******************************************************************
1093 * COMM_DeviceIoControl
1097 static inline NTSTATUS io_control(HANDLE hDevice,
1098 HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
1099 PVOID UserApcContext,
1100 PIO_STATUS_BLOCK piosb,
1101 ULONG dwIoControlCode,
1102 LPVOID lpInBuffer, DWORD nInBufferSize,
1103 LPVOID lpOutBuffer, DWORD nOutBufferSize)
1105 DWORD sz = 0, access = FILE_READ_DATA;
1106 NTSTATUS status = STATUS_SUCCESS;
1107 int fd = -1, needs_close = 0;
1109 TRACE("%p %s %p %d %p %d %p\n",
1110 hDevice, iocode2str(dwIoControlCode), lpInBuffer, nInBufferSize,
1111 lpOutBuffer, nOutBufferSize, piosb);
1113 piosb->Information = 0;
1115 if (dwIoControlCode != IOCTL_SERIAL_GET_TIMEOUTS &&
1116 dwIoControlCode != IOCTL_SERIAL_SET_TIMEOUTS)
1117 if ((status = server_get_unix_fd( hDevice, access, &fd, &needs_close, NULL, NULL )))
1118 goto error;
1120 switch (dwIoControlCode)
1122 case IOCTL_SERIAL_CLR_DTR:
1123 #ifdef TIOCM_DTR
1124 if (whack_modem(fd, ~TIOCM_DTR, 0) == -1) status = FILE_GetNtStatus();
1125 #else
1126 status = STATUS_NOT_SUPPORTED;
1127 #endif
1128 break;
1129 case IOCTL_SERIAL_CLR_RTS:
1130 #ifdef TIOCM_RTS
1131 if (whack_modem(fd, ~TIOCM_RTS, 0) == -1) status = FILE_GetNtStatus();
1132 #else
1133 status = STATUS_NOT_SUPPORTED;
1134 #endif
1135 break;
1136 case IOCTL_SERIAL_GET_BAUD_RATE:
1137 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_BAUD_RATE))
1139 if (!(status = get_baud_rate(fd, (SERIAL_BAUD_RATE*)lpOutBuffer)))
1140 sz = sizeof(SERIAL_BAUD_RATE);
1142 else
1143 status = STATUS_INVALID_PARAMETER;
1144 break;
1145 case IOCTL_SERIAL_GET_CHARS:
1146 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_CHARS))
1148 if (!(status = get_special_chars(fd, (SERIAL_CHARS*)lpOutBuffer)))
1149 sz = sizeof(SERIAL_CHARS);
1151 else
1152 status = STATUS_INVALID_PARAMETER;
1153 break;
1154 case IOCTL_SERIAL_GET_COMMSTATUS:
1155 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_STATUS))
1157 if (!(status = get_status(fd, (SERIAL_STATUS*)lpOutBuffer)))
1158 sz = sizeof(SERIAL_STATUS);
1160 else status = STATUS_INVALID_PARAMETER;
1161 break;
1162 case IOCTL_SERIAL_GET_HANDFLOW:
1163 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_HANDFLOW))
1165 if (!(status = get_hand_flow(fd, (SERIAL_HANDFLOW*)lpOutBuffer)))
1166 sz = sizeof(SERIAL_HANDFLOW);
1168 else
1169 status = STATUS_INVALID_PARAMETER;
1170 break;
1171 case IOCTL_SERIAL_GET_LINE_CONTROL:
1172 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_LINE_CONTROL))
1174 if (!(status = get_line_control(fd, (SERIAL_LINE_CONTROL*)lpOutBuffer)))
1175 sz = sizeof(SERIAL_LINE_CONTROL);
1177 else
1178 status = STATUS_INVALID_PARAMETER;
1179 break;
1180 case IOCTL_SERIAL_GET_MODEMSTATUS:
1181 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1183 if (!(status = get_modem_status(fd, (DWORD*)lpOutBuffer)))
1184 sz = sizeof(DWORD);
1186 else status = STATUS_INVALID_PARAMETER;
1187 break;
1188 case IOCTL_SERIAL_GET_TIMEOUTS:
1189 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_TIMEOUTS))
1191 if (!(status = get_timeouts(hDevice, (SERIAL_TIMEOUTS*)lpOutBuffer)))
1192 sz = sizeof(SERIAL_TIMEOUTS);
1194 else
1195 status = STATUS_INVALID_PARAMETER;
1196 break;
1197 case IOCTL_SERIAL_GET_WAIT_MASK:
1198 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1200 if (!(status = get_wait_mask(hDevice, (DWORD*)lpOutBuffer)))
1201 sz = sizeof(DWORD);
1203 else
1204 status = STATUS_INVALID_PARAMETER;
1205 break;
1206 case IOCTL_SERIAL_IMMEDIATE_CHAR:
1207 if (lpInBuffer && nInBufferSize == sizeof(CHAR))
1208 status = xmit_immediate(hDevice, fd, lpInBuffer);
1209 else
1210 status = STATUS_INVALID_PARAMETER;
1211 break;
1212 case IOCTL_SERIAL_PURGE:
1213 if (lpInBuffer && nInBufferSize == sizeof(DWORD))
1214 status = purge(fd, *(DWORD*)lpInBuffer);
1215 else
1216 status = STATUS_INVALID_PARAMETER;
1217 break;
1218 case IOCTL_SERIAL_RESET_DEVICE:
1219 FIXME("Unsupported\n");
1220 break;
1221 case IOCTL_SERIAL_SET_BAUD_RATE:
1222 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_BAUD_RATE))
1223 status = set_baud_rate(fd, (const SERIAL_BAUD_RATE*)lpInBuffer);
1224 else
1225 status = STATUS_INVALID_PARAMETER;
1226 break;
1227 case IOCTL_SERIAL_SET_BREAK_OFF:
1228 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1229 if (ioctl(fd, TIOCCBRK, 0) == -1)
1231 TRACE("ioctl failed\n");
1232 status = FILE_GetNtStatus();
1234 #else
1235 FIXME("ioctl not available\n");
1236 status = STATUS_NOT_SUPPORTED;
1237 #endif
1238 break;
1239 case IOCTL_SERIAL_SET_BREAK_ON:
1240 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1241 if (ioctl(fd, TIOCSBRK, 0) == -1)
1243 TRACE("ioctl failed\n");
1244 status = FILE_GetNtStatus();
1246 #else
1247 FIXME("ioctl not available\n");
1248 status = STATUS_NOT_SUPPORTED;
1249 #endif
1250 break;
1251 case IOCTL_SERIAL_SET_CHARS:
1252 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_CHARS))
1253 status = set_special_chars(fd, (const SERIAL_CHARS*)lpInBuffer);
1254 else
1255 status = STATUS_INVALID_PARAMETER;
1256 break;
1257 case IOCTL_SERIAL_SET_DTR:
1258 #ifdef TIOCM_DTR
1259 if (whack_modem(fd, 0, TIOCM_DTR) == -1) status = FILE_GetNtStatus();
1260 #else
1261 status = STATUS_NOT_SUPPORTED;
1262 #endif
1263 break;
1264 case IOCTL_SERIAL_SET_HANDFLOW:
1265 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_HANDFLOW))
1266 status = set_handflow(fd, (const SERIAL_HANDFLOW*)lpInBuffer);
1267 else
1268 status = STATUS_INVALID_PARAMETER;
1269 break;
1270 case IOCTL_SERIAL_SET_LINE_CONTROL:
1271 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_LINE_CONTROL))
1272 status = set_line_control(fd, (const SERIAL_LINE_CONTROL*)lpInBuffer);
1273 else
1274 status = STATUS_INVALID_PARAMETER;
1275 break;
1276 case IOCTL_SERIAL_SET_QUEUE_SIZE:
1277 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_QUEUE_SIZE))
1278 status = set_queue_size(fd, (const SERIAL_QUEUE_SIZE*)lpInBuffer);
1279 else
1280 status = STATUS_INVALID_PARAMETER;
1281 break;
1282 case IOCTL_SERIAL_SET_RTS:
1283 #ifdef TIOCM_RTS
1284 if (whack_modem(fd, 0, TIOCM_RTS) == -1) status = FILE_GetNtStatus();
1285 #else
1286 status = STATUS_NOT_SUPPORTED;
1287 #endif
1288 break;
1289 case IOCTL_SERIAL_SET_TIMEOUTS:
1290 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_TIMEOUTS))
1291 status = set_timeouts(hDevice, (const SERIAL_TIMEOUTS*)lpInBuffer);
1292 else
1293 status = STATUS_INVALID_PARAMETER;
1294 break;
1295 case IOCTL_SERIAL_SET_WAIT_MASK:
1296 if (lpInBuffer && nInBufferSize == sizeof(DWORD))
1298 status = set_wait_mask(hDevice, *(DWORD*)lpInBuffer);
1300 else status = STATUS_INVALID_PARAMETER;
1301 break;
1302 case IOCTL_SERIAL_SET_XOFF:
1303 status = set_XOff(fd);
1304 break;
1305 case IOCTL_SERIAL_SET_XON:
1306 status = set_XOn(fd);
1307 break;
1308 case IOCTL_SERIAL_WAIT_ON_MASK:
1309 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1311 if (!(status = wait_on(hDevice, fd, hEvent, (DWORD*)lpOutBuffer)))
1312 sz = sizeof(DWORD);
1314 else
1315 status = STATUS_INVALID_PARAMETER;
1316 break;
1317 default:
1318 FIXME("Unsupported IOCTL %x (type=%x access=%x func=%x meth=%x)\n",
1319 dwIoControlCode, dwIoControlCode >> 16, (dwIoControlCode >> 14) & 3,
1320 (dwIoControlCode >> 2) & 0xFFF, dwIoControlCode & 3);
1321 sz = 0;
1322 status = STATUS_INVALID_PARAMETER;
1323 break;
1325 if (needs_close) close( fd );
1326 error:
1327 piosb->u.Status = status;
1328 piosb->Information = sz;
1329 if (hEvent && status != STATUS_PENDING) NtSetEvent(hEvent, NULL);
1330 return status;
1333 NTSTATUS COMM_DeviceIoControl(HANDLE hDevice,
1334 HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
1335 PVOID UserApcContext,
1336 PIO_STATUS_BLOCK piosb,
1337 ULONG dwIoControlCode,
1338 LPVOID lpInBuffer, DWORD nInBufferSize,
1339 LPVOID lpOutBuffer, DWORD nOutBufferSize)
1341 NTSTATUS status;
1343 if (dwIoControlCode == IOCTL_SERIAL_WAIT_ON_MASK)
1345 HANDLE hev = hEvent;
1347 /* this is an ioctl we implement in a non blocking way if hEvent is not
1348 * null
1349 * so we have to explicitly wait if no hEvent is provided
1351 if (!hev)
1353 OBJECT_ATTRIBUTES attr;
1355 attr.Length = sizeof(attr);
1356 attr.RootDirectory = 0;
1357 attr.ObjectName = NULL;
1358 attr.Attributes = OBJ_CASE_INSENSITIVE | OBJ_OPENIF;
1359 attr.SecurityDescriptor = NULL;
1360 attr.SecurityQualityOfService = NULL;
1361 status = NtCreateEvent(&hev, EVENT_ALL_ACCESS, &attr, FALSE, FALSE);
1363 if (status) goto done;
1365 status = io_control(hDevice, hev, UserApcRoutine, UserApcContext,
1366 piosb, dwIoControlCode, lpInBuffer, nInBufferSize,
1367 lpOutBuffer, nOutBufferSize);
1368 if (hev != hEvent)
1370 if (status == STATUS_PENDING)
1372 NtWaitForSingleObject(hev, FALSE, NULL);
1373 status = STATUS_SUCCESS;
1375 NtClose(hev);
1378 else status = io_control(hDevice, hEvent, UserApcRoutine, UserApcContext,
1379 piosb, dwIoControlCode, lpInBuffer, nInBufferSize,
1380 lpOutBuffer, nOutBufferSize);
1381 done:
1382 return status;