dinput: Use bitwise NOT not logical NOT.
[wine/wine-kai.git] / dlls / ntdll / serial.c
blob1b05b6e17441bbbbd53661a9298d07eb1e10442d
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;
192 struct termios port;
194 if (tcgetattr(fd, &port) == -1)
196 ERR("tcgetattr error '%s'\n", strerror(errno));
197 return FILE_GetNtStatus();
199 #ifdef TIOCMGET
200 if (ioctl(fd, TIOCMGET, &stat) == -1)
202 WARN("ioctl error '%s'\n", strerror(errno));
203 stat = DTR_CONTROL_ENABLE | RTS_CONTROL_ENABLE;
205 #endif
206 /* termios does not support DTR/DSR flow control */
207 shf->ControlHandShake = 0;
208 shf->FlowReplace = 0;
209 #ifdef TIOCM_DTR
210 if (stat & TIOCM_DTR)
211 #endif
212 shf->ControlHandShake |= SERIAL_DTR_CONTROL;
213 #ifdef CRTSCTS
214 if (port.c_cflag & CRTSCTS)
216 shf->ControlHandShake |= SERIAL_DTR_CONTROL | SERIAL_DTR_HANDSHAKE;
217 shf->ControlHandShake |= SERIAL_CTS_HANDSHAKE;
219 else
220 #endif
222 #ifdef TIOCM_RTS
223 if (stat & TIOCM_RTS)
224 #endif
225 shf->ControlHandShake |= SERIAL_RTS_CONTROL;
227 if (port.c_iflag & IXOFF)
228 shf->FlowReplace |= SERIAL_AUTO_RECEIVE;
229 if (port.c_iflag & IXON)
230 shf->FlowReplace |= SERIAL_AUTO_TRANSMIT;
232 shf->XonLimit = 10;
233 shf->XoffLimit = 10;
234 return STATUS_SUCCESS;
237 static NTSTATUS get_line_control(int fd, SERIAL_LINE_CONTROL* slc)
239 struct termios port;
241 if (tcgetattr(fd, &port) == -1)
243 ERR("tcgetattr error '%s'\n", strerror(errno));
244 return FILE_GetNtStatus();
247 #ifdef CMSPAR
248 switch (port.c_cflag & (PARENB | PARODD | CMSPAR))
249 #else
250 switch (port.c_cflag & (PARENB | PARODD))
251 #endif
253 case 0: slc->Parity = NOPARITY; break;
254 case PARENB: slc->Parity = EVENPARITY; break;
255 case PARENB|PARODD: slc->Parity = ODDPARITY; break;
256 #ifdef CMSPAR
257 case PARENB|CMSPAR: slc->Parity = MARKPARITY; break;
258 case PARENB|PARODD|CMSPAR: slc->Parity = SPACEPARITY; break;
259 #endif
261 switch (port.c_cflag & CSIZE)
263 case CS5: slc->WordLength = 5; break;
264 case CS6: slc->WordLength = 6; break;
265 case CS7: slc->WordLength = 7; break;
266 case CS8: slc->WordLength = 8; break;
267 default: ERR("unknown size %x\n", (UINT)(port.c_cflag & CSIZE));
270 if (port.c_cflag & CSTOPB)
272 if (slc->WordLength == 5)
273 slc->StopBits = ONE5STOPBITS;
274 else
275 slc->StopBits = TWOSTOPBITS;
277 else
278 slc->StopBits = ONESTOPBIT;
280 return STATUS_SUCCESS;
283 static NTSTATUS get_modem_status(int fd, DWORD* lpModemStat)
285 NTSTATUS status = STATUS_SUCCESS;
286 int mstat;
288 #ifdef TIOCMGET
289 if (ioctl(fd, TIOCMGET, &mstat) == -1)
291 WARN("ioctl failed\n");
292 status = FILE_GetNtStatus();
294 else
296 *lpModemStat = 0;
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 " : "");
316 #else
317 status = STATUS_NOT_SUPPORTED;
318 #endif
319 return status;
322 static NTSTATUS get_special_chars(int fd, SERIAL_CHARS* sc)
324 struct termios port;
326 if (tcgetattr(fd, &port) == -1)
328 ERR("tcgetattr error '%s'\n", strerror(errno));
329 return FILE_GetNtStatus();
331 sc->EofChar = port.c_cc[VEOF];
332 sc->ErrorChar = 0xFF;
333 sc->BreakChar = 0; /* FIXME */
334 sc->EventChar = 0; /* FIXME */
335 sc->XonChar = port.c_cc[VSTART];
336 sc->XoffChar = port.c_cc[VSTOP];
338 return STATUS_SUCCESS;
341 static NTSTATUS get_status(int fd, SERIAL_STATUS* ss)
343 NTSTATUS status = STATUS_SUCCESS;
345 ss->Errors = 0;
346 ss->HoldReasons = 0;
347 ss->EofReceived = FALSE;
348 ss->WaitForImmediate = FALSE;
349 #ifdef TIOCOUTQ
350 if (ioctl(fd, TIOCOUTQ, &ss->AmountInOutQueue) == -1)
352 WARN("ioctl returned error\n");
353 status = FILE_GetNtStatus();
355 #else
356 ss->AmountInOutQueue = 0; /* FIXME: find a different way to find out */
357 #endif
359 #ifdef TIOCINQ
360 if (ioctl(fd, TIOCINQ, &ss->AmountInInQueue))
362 WARN("ioctl returned error\n");
363 status = FILE_GetNtStatus();
365 #else
366 ss->AmountInInQueue = 0; /* FIXME: find a different way to find out */
367 #endif
368 return status;
371 static NTSTATUS get_timeouts(HANDLE handle, SERIAL_TIMEOUTS* st)
373 NTSTATUS status;
374 SERVER_START_REQ( get_serial_info )
376 req->handle = handle;
377 if (!(status = wine_server_call( req )))
379 st->ReadIntervalTimeout = reply->readinterval;
380 st->ReadTotalTimeoutMultiplier = reply->readmult;
381 st->ReadTotalTimeoutConstant = reply->readconst;
382 st->WriteTotalTimeoutMultiplier = reply->writemult;
383 st->WriteTotalTimeoutConstant = reply->writeconst;
386 SERVER_END_REQ;
387 return status;
390 static NTSTATUS get_wait_mask(HANDLE hDevice, DWORD* mask)
392 NTSTATUS status;
394 SERVER_START_REQ( get_serial_info )
396 req->handle = hDevice;
397 if (!(status = wine_server_call( req )))
398 *mask = reply->eventmask;
400 SERVER_END_REQ;
401 return status;
404 static NTSTATUS purge(int fd, DWORD flags)
407 ** not exactly sure how these are different
408 ** Perhaps if we had our own internal queues, one flushes them
409 ** and the other flushes the kernel's buffers.
411 if (flags & PURGE_TXABORT) tcflush(fd, TCOFLUSH);
412 if (flags & PURGE_RXABORT) tcflush(fd, TCIFLUSH);
413 if (flags & PURGE_TXCLEAR) tcflush(fd, TCOFLUSH);
414 if (flags & PURGE_RXCLEAR) tcflush(fd, TCIFLUSH);
415 return STATUS_SUCCESS;
418 static NTSTATUS set_baud_rate(int fd, const SERIAL_BAUD_RATE* sbr)
420 struct termios port;
422 if (tcgetattr(fd, &port) == -1)
424 ERR("tcgetattr error '%s'\n", strerror(errno));
425 return FILE_GetNtStatus();
428 #ifdef CBAUD
429 port.c_cflag &= ~CBAUD;
430 switch (sbr->BaudRate)
432 case 0: port.c_cflag |= B0; break;
433 case 50: port.c_cflag |= B50; break;
434 case 75: port.c_cflag |= B75; break;
435 case 110:
436 case CBR_110: port.c_cflag |= B110; break;
437 case 134: port.c_cflag |= B134; break;
438 case 150: port.c_cflag |= B150; break;
439 case 200: port.c_cflag |= B200; break;
440 case 300:
441 case CBR_300: port.c_cflag |= B300; break;
442 case 600:
443 case CBR_600: port.c_cflag |= B600; break;
444 case 1200:
445 case CBR_1200: port.c_cflag |= B1200; break;
446 case 1800: port.c_cflag |= B1800; break;
447 case 2400:
448 case CBR_2400: port.c_cflag |= B2400; break;
449 case 4800:
450 case CBR_4800: port.c_cflag |= B4800; break;
451 case 9600:
452 case CBR_9600: port.c_cflag |= B9600; break;
453 case 19200:
454 case CBR_19200: port.c_cflag |= B19200; break;
455 case 38400:
456 case CBR_38400: port.c_cflag |= B38400; break;
457 #ifdef B57600
458 case 57600: port.c_cflag |= B57600; break;
459 #endif
460 #ifdef B115200
461 case 115200: port.c_cflag |= B115200;break;
462 #endif
463 #ifdef B230400
464 case 230400: port.c_cflag |= B230400;break;
465 #endif
466 #ifdef B460800
467 case 460800: port.c_cflag |= B460800;break;
468 #endif
469 default:
470 #if defined (HAVE_LINUX_SERIAL_H) && defined (TIOCSSERIAL)
472 struct serial_struct nuts;
473 int arby;
475 ioctl(fd, TIOCGSERIAL, &nuts);
476 nuts.custom_divisor = nuts.baud_base / sbr->BaudRate;
477 if (!(nuts.custom_divisor)) nuts.custom_divisor = 1;
478 arby = nuts.baud_base / nuts.custom_divisor;
479 nuts.flags &= ~ASYNC_SPD_MASK;
480 nuts.flags |= ASYNC_SPD_CUST;
481 WARN("You (or a program acting at your behest) have specified\n"
482 "a non-standard baud rate %d. Wine will set the rate to %d,\n"
483 "which is as close as we can get by our present understanding of your\n"
484 "hardware. I hope you know what you are doing. Any disruption Wine\n"
485 "has caused to your linux system can be undone with setserial \n"
486 "(see man setserial). If you have incapacitated a Hayes type modem,\n"
487 "reset it and it will probably recover.\n", sbr->BaudRate, arby);
488 ioctl(fd, TIOCSSERIAL, &nuts);
489 port.c_cflag |= B38400;
491 break;
492 #else /* Don't have linux/serial.h or lack TIOCSSERIAL */
493 ERR("baudrate %d\n", sbr->BaudRate);
494 return STATUS_NOT_SUPPORTED;
495 #endif /* Don't have linux/serial.h or lack TIOCSSERIAL */
497 #elif !defined(__EMX__)
498 switch (sbr->BaudRate)
500 case 0: port.c_ospeed = B0; break;
501 case 50: port.c_ospeed = B50; break;
502 case 75: port.c_ospeed = B75; break;
503 case 110:
504 case CBR_110: port.c_ospeed = B110; break;
505 case 134: port.c_ospeed = B134; break;
506 case 150: port.c_ospeed = B150; break;
507 case 200: port.c_ospeed = B200; break;
508 case 300:
509 case CBR_300: port.c_ospeed = B300; break;
510 case 600:
511 case CBR_600: port.c_ospeed = B600; break;
512 case 1200:
513 case CBR_1200: port.c_ospeed = B1200; break;
514 case 1800: port.c_ospeed = B1800; break;
515 case 2400:
516 case CBR_2400: port.c_ospeed = B2400; break;
517 case 4800:
518 case CBR_4800: port.c_ospeed = B4800; break;
519 case 9600:
520 case CBR_9600: port.c_ospeed = B9600; break;
521 case 19200:
522 case CBR_19200: port.c_ospeed = B19200; break;
523 case 38400:
524 case CBR_38400: port.c_ospeed = B38400; break;
525 #ifdef B57600
526 case 57600:
527 case CBR_57600: port.c_cflag |= B57600; break;
528 #endif
529 #ifdef B115200
530 case 115200:
531 case CBR_115200: port.c_cflag |= B115200;break;
532 #endif
533 #ifdef B230400
534 case 230400: port.c_cflag |= B230400;break;
535 #endif
536 #ifdef B460800
537 case 460800: port.c_cflag |= B460800;break;
538 #endif
539 default:
540 ERR("baudrate %d\n", sbr->BaudRate);
541 return STATUS_NOT_SUPPORTED;
543 port.c_ispeed = port.c_ospeed;
544 #endif
545 if (tcsetattr(fd, TCSANOW, &port) == -1)
547 ERR("tcsetattr error '%s'\n", strerror(errno));
548 return FILE_GetNtStatus();
550 return STATUS_SUCCESS;
553 static int whack_modem(int fd, unsigned int andy, unsigned int orrie)
555 #ifdef TIOCMGET
556 unsigned int mstat, okay;
557 okay = ioctl(fd, TIOCMGET, &mstat);
558 if (okay) return okay;
559 if (andy) mstat &= andy;
560 mstat |= orrie;
561 return ioctl(fd, TIOCMSET, &mstat);
562 #else
563 return 0;
564 #endif
567 static NTSTATUS set_handflow(int fd, const SERIAL_HANDFLOW* shf)
569 struct termios port;
571 if ((shf->FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE)) ==
572 (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE))
573 return STATUS_NOT_SUPPORTED;
575 if (tcgetattr(fd, &port) == -1)
577 ERR("tcgetattr error '%s'\n", strerror(errno));
578 return FILE_GetNtStatus();
581 #ifdef CRTSCTS
582 if ((shf->ControlHandShake & SERIAL_CTS_HANDSHAKE) ||
583 (shf->FlowReplace & SERIAL_RTS_HANDSHAKE))
585 port.c_cflag |= CRTSCTS;
586 TRACE("CRTSCTS\n");
588 else
589 port.c_cflag &= ~CRTSCTS;
590 #endif
591 #ifdef TIOCM_DTR
592 if (shf->ControlHandShake & SERIAL_DTR_HANDSHAKE)
594 WARN("DSR/DTR flow control not supported\n");
595 } else if (!(shf->ControlHandShake & SERIAL_DTR_CONTROL))
596 whack_modem(fd, ~TIOCM_DTR, 0);
597 else
598 whack_modem(fd, 0, TIOCM_DTR);
599 #endif
600 #ifdef TIOCM_RTS
601 if (!(shf->ControlHandShake & SERIAL_CTS_HANDSHAKE))
603 if ((shf->FlowReplace & (SERIAL_RTS_CONTROL|SERIAL_RTS_HANDSHAKE)) == 0)
604 whack_modem(fd, ~TIOCM_RTS, 0);
605 else
606 whack_modem(fd, 0, TIOCM_RTS);
608 #endif
610 if (shf->FlowReplace & SERIAL_AUTO_RECEIVE)
611 port.c_iflag |= IXOFF;
612 else
613 port.c_iflag &= ~IXOFF;
614 if (shf->FlowReplace & SERIAL_AUTO_TRANSMIT)
615 port.c_iflag |= IXON;
616 else
617 port.c_iflag &= ~IXON;
618 if (tcsetattr(fd, TCSANOW, &port) == -1)
620 ERR("tcsetattr error '%s'\n", strerror(errno));
621 return FILE_GetNtStatus();
624 return STATUS_SUCCESS;
627 static NTSTATUS set_line_control(int fd, const SERIAL_LINE_CONTROL* slc)
629 struct termios port;
630 unsigned bytesize, stopbits;
632 if (tcgetattr(fd, &port) == -1)
634 ERR("tcgetattr error '%s'\n", strerror(errno));
635 return FILE_GetNtStatus();
638 #ifdef IMAXBEL
639 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK|IMAXBEL);
640 #else
641 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK);
642 #endif
643 port.c_iflag |= IGNBRK | INPCK;
645 port.c_oflag &= ~(OPOST);
647 port.c_cflag &= ~(HUPCL);
648 port.c_cflag |= CLOCAL | CREAD;
650 port.c_lflag &= ~(ICANON|ECHO|ISIG);
651 port.c_lflag |= NOFLSH;
653 bytesize = slc->WordLength;
654 stopbits = slc->StopBits;
656 #ifdef CMSPAR
657 port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
658 #else
659 port.c_cflag &= ~(PARENB | PARODD);
660 #endif
662 switch (slc->Parity)
664 case NOPARITY: port.c_iflag &= ~INPCK; break;
665 case ODDPARITY: port.c_cflag |= PARENB | PARODD; break;
666 case EVENPARITY: port.c_cflag |= PARENB; break;
667 #ifdef CMSPAR
668 /* Linux defines mark/space (stick) parity */
669 case MARKPARITY: port.c_cflag |= PARENB | CMSPAR; break;
670 case SPACEPARITY: port.c_cflag |= PARENB | PARODD | CMSPAR; break;
671 #else
672 /* try the POSIX way */
673 case MARKPARITY:
674 if (slc->StopBits == ONESTOPBIT)
676 stopbits = TWOSTOPBITS;
677 port.c_iflag &= ~INPCK;
679 else
681 ERR("Cannot set MARK Parity\n");
682 return STATUS_NOT_SUPPORTED;
684 break;
685 case SPACEPARITY:
686 if (slc->WordLength < 8)
688 bytesize +=1;
689 port.c_iflag &= ~INPCK;
691 else
693 ERR("Cannot set SPACE Parity\n");
694 return STATUS_NOT_SUPPORTED;
696 break;
697 #endif
698 default:
699 ERR("Parity\n");
700 return STATUS_NOT_SUPPORTED;
703 port.c_cflag &= ~CSIZE;
704 switch (bytesize)
706 case 5: port.c_cflag |= CS5; break;
707 case 6: port.c_cflag |= CS6; break;
708 case 7: port.c_cflag |= CS7; break;
709 case 8: port.c_cflag |= CS8; break;
710 default:
711 ERR("ByteSize\n");
712 return STATUS_NOT_SUPPORTED;
715 switch (stopbits)
717 case ONESTOPBIT: port.c_cflag &= ~CSTOPB; break;
718 case ONE5STOPBITS: /* will be selected if bytesize is 5 */
719 case TWOSTOPBITS: port.c_cflag |= CSTOPB; break;
720 default:
721 ERR("StopBits\n");
722 return STATUS_NOT_SUPPORTED;
724 /* otherwise it hangs with pending input*/
725 if (tcsetattr(fd, TCSANOW, &port) == -1)
727 ERR("tcsetattr error '%s'\n", strerror(errno));
728 return FILE_GetNtStatus();
730 return STATUS_SUCCESS;
733 static NTSTATUS set_queue_size(int fd, const SERIAL_QUEUE_SIZE* sqs)
735 FIXME("insize %d outsize %d unimplemented stub\n", sqs->InSize, sqs->OutSize);
736 return STATUS_SUCCESS;
739 static NTSTATUS set_special_chars(int fd, const SERIAL_CHARS* sc)
741 struct termios port;
743 if (tcgetattr(fd, &port) == -1)
745 ERR("tcgetattr error '%s'\n", strerror(errno));
746 return FILE_GetNtStatus();
749 port.c_cc[VMIN ] = 0;
750 port.c_cc[VTIME ] = 1;
752 port.c_cc[VEOF ] = sc->EofChar;
753 /* FIXME: sc->ErrorChar is not supported */
754 /* FIXME: sc->BreakChar is not supported */
755 /* FIXME: sc->EventChar is not supported */
756 port.c_cc[VSTART] = sc->XonChar;
757 port.c_cc[VSTOP ] = sc->XoffChar;
759 if (tcsetattr(fd, TCSANOW, &port) == -1)
761 ERR("tcsetattr error '%s'\n", strerror(errno));
762 return FILE_GetNtStatus();
764 return STATUS_SUCCESS;
767 static NTSTATUS set_timeouts(HANDLE handle, int fd, const SERIAL_TIMEOUTS* st)
769 NTSTATUS status;
770 struct termios port;
771 unsigned int ux_timeout;
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 if (status) return status;
787 if (tcgetattr(fd, &port) == -1)
789 FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
790 return FILE_GetNtStatus();
793 /* VTIME is in 1/10 seconds */
794 if (st->ReadIntervalTimeout == 0) /* 0 means no timeout */
795 ux_timeout = 0;
796 else
798 ux_timeout = (st->ReadIntervalTimeout + 99) / 100;
799 if (ux_timeout == 0)
800 ux_timeout = 1; /* must be at least some timeout */
802 port.c_cc[VTIME] = ux_timeout;
804 if (tcsetattr(fd, 0, &port) == -1)
806 FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
807 return FILE_GetNtStatus();
809 return STATUS_SUCCESS;
812 static NTSTATUS set_wait_mask(HANDLE hDevice, DWORD mask)
814 NTSTATUS status;
816 SERVER_START_REQ( set_serial_info )
818 req->handle = hDevice;
819 req->flags = SERIALINFO_SET_MASK;
820 req->eventmask = mask;
821 status = wine_server_call( req );
823 SERVER_END_REQ;
824 return status;
827 static NTSTATUS set_XOff(int fd)
829 struct termios port;
831 if (tcgetattr(fd,&port) == -1)
833 FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
834 return FILE_GetNtStatus();
838 port.c_iflag |= IXOFF;
839 if (tcsetattr(fd, TCSADRAIN, &port) == -1)
841 FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
842 return FILE_GetNtStatus();
844 return STATUS_SUCCESS;
847 static NTSTATUS set_XOn(int fd)
849 struct termios port;
851 if (tcgetattr(fd,&port) == -1)
853 FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
854 return FILE_GetNtStatus();
856 port.c_iflag |= IXON;
857 if (tcsetattr(fd, TCSADRAIN, &port) == -1)
859 FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
860 return FILE_GetNtStatus();
862 return STATUS_SUCCESS;
865 /* serial_irq_info
866 * local structure holding the irq values we need for WaitCommEvent()
868 * Stripped down from struct serial_icounter_struct, which may not be available on some systems
869 * As the modem line interrupts (cts, dsr, rng, dcd) only get updated with TIOCMIWAIT active,
870 * no need to carry them in the internal structure
873 typedef struct serial_irq_info
875 int rx , tx, frame, overrun, parity, brk, buf_overrun;
876 }serial_irq_info;
878 /***********************************************************************
879 * Data needed by the thread polling for the changing CommEvent
881 typedef struct async_commio
883 HANDLE hDevice;
884 DWORD* events;
885 HANDLE hEvent;
886 DWORD evtmask;
887 DWORD mstat;
888 serial_irq_info irq_info;
889 } async_commio;
891 /***********************************************************************
892 * Get extended interrupt count info, needed for wait_on
894 static NTSTATUS get_irq_info(int fd, serial_irq_info *irq_info)
896 #ifdef TIOCGICOUNT
897 struct serial_icounter_struct einfo;
898 if (!ioctl(fd, TIOCGICOUNT, &einfo))
900 irq_info->rx = einfo.rx;
901 irq_info->tx = einfo.tx;
902 irq_info->frame = einfo.frame;
903 irq_info->overrun = einfo.overrun;
904 irq_info->parity = einfo.parity;
905 irq_info->brk = einfo.brk;
906 irq_info->buf_overrun = einfo.buf_overrun;
907 return STATUS_SUCCESS;
909 TRACE("TIOCGICOUNT err %s\n", strerror(errno));
910 return FILE_GetNtStatus();
911 #else
912 memset(irq_info,0, sizeof(serial_irq_info));
913 return STATUS_NOT_IMPLEMENTED;
914 #endif
918 static DWORD WINAPI check_events(int fd, DWORD mask,
919 const serial_irq_info *new,
920 const serial_irq_info *old,
921 DWORD new_mstat, DWORD old_mstat)
923 DWORD ret = 0, queue;
925 TRACE("mask 0x%08x\n", mask);
926 TRACE("old->rx 0x%08x vs. new->rx 0x%08x\n", old->rx, new->rx);
927 TRACE("old->tx 0x%08x vs. new->tx 0x%08x\n", old->tx, new->tx);
928 TRACE("old->frame 0x%08x vs. new->frame 0x%08x\n", old->frame, new->frame);
929 TRACE("old->overrun 0x%08x vs. new->overrun 0x%08x\n", old->overrun, new->overrun);
930 TRACE("old->parity 0x%08x vs. new->parity 0x%08x\n", old->parity, new->parity);
931 TRACE("old->brk 0x%08x vs. new->brk 0x%08x\n", old->brk, new->brk);
932 TRACE("old->buf_overrun 0x%08x vs. new->buf_overrun 0x%08x\n", old->buf_overrun, new->buf_overrun);
934 if (old->brk != new->brk) ret |= EV_BREAK;
935 if ((old_mstat & MS_CTS_ON ) != (new_mstat & MS_CTS_ON )) ret |= EV_CTS;
936 if ((old_mstat & MS_DSR_ON ) != (new_mstat & MS_DSR_ON )) ret |= EV_DSR;
937 if ((old_mstat & MS_RING_ON) != (new_mstat & MS_RING_ON)) ret |= EV_RING;
938 if ((old_mstat & MS_RLSD_ON) != (new_mstat & MS_RLSD_ON)) ret |= EV_RLSD;
939 if (old->frame != new->frame || old->overrun != new->overrun || old->parity != new->parity) ret |= EV_ERR;
940 if (mask & EV_RXCHAR)
942 queue = 0;
943 #ifdef TIOCINQ
944 if (ioctl(fd, TIOCINQ, &queue))
945 WARN("TIOCINQ returned error\n");
946 #endif
947 if (queue)
948 ret |= EV_RXCHAR;
950 if (mask & EV_TXEMPTY)
952 queue = 0;
953 /* We really want to know when all characters have gone out of the transmitter */
954 #if defined(TIOCSERGETLSR)
955 if (ioctl(fd, TIOCSERGETLSR, &queue))
956 WARN("TIOCSERGETLSR returned error\n");
957 if (queue)
958 /* TIOCOUTQ only checks for an empty buffer */
959 #elif defined(TIOCOUTQ)
960 if (ioctl(fd, TIOCOUTQ, &queue))
961 WARN("TIOCOUTQ returned error\n");
962 if (!queue)
963 #endif
964 ret |= EV_TXEMPTY;
965 TRACE("OUTQUEUE %d, Transmitter %sempty\n",
966 queue, (ret & EV_TXEMPTY) ? "" : "not ");
968 return ret & mask;
971 /***********************************************************************
972 * wait_for_event (INTERNAL)
974 * We need to poll for what is interesting
975 * TIOCMIWAIT only checks modem status line and may not be aborted by a changing mask
978 static DWORD CALLBACK wait_for_event(LPVOID arg)
980 async_commio *commio = (async_commio*) arg;
981 int fd, needs_close;
983 if (!server_get_unix_fd( commio->hDevice, FILE_READ_DATA | FILE_WRITE_DATA, &fd, &needs_close, NULL, NULL ))
985 serial_irq_info new_irq_info;
986 DWORD new_mstat, new_evtmask;
987 LARGE_INTEGER time;
989 TRACE("device=%p fd=0x%08x mask=0x%08x buffer=%p event=%p irq_info=%p\n",
990 commio->hDevice, fd, commio->evtmask, commio->events, commio->hEvent, &commio->irq_info);
992 time.QuadPart = (ULONGLONG)10000;
993 time.QuadPart = -time.QuadPart;
994 for (;;)
997 * TIOCMIWAIT is not adequate
999 * FIXME:
1000 * We don't handle the EV_RXFLAG (the eventchar)
1002 NtDelayExecution(FALSE, &time);
1003 get_irq_info(fd, &new_irq_info);
1004 if (get_modem_status(fd, &new_mstat))
1005 TRACE("get_modem_status failed\n");
1006 *commio->events = check_events(fd, commio->evtmask,
1007 &new_irq_info, &commio->irq_info,
1008 new_mstat, commio->mstat);
1009 if (*commio->events) break;
1010 get_wait_mask(commio->hDevice, &new_evtmask);
1011 if (commio->evtmask != new_evtmask)
1013 *commio->events = 0;
1014 break;
1017 if (needs_close) close( fd );
1019 if (commio->hEvent) NtSetEvent(commio->hEvent, NULL);
1020 RtlFreeHeap(GetProcessHeap(), 0, commio);
1021 return 0;
1024 static NTSTATUS wait_on(HANDLE hDevice, int fd, HANDLE hEvent, DWORD* events)
1026 async_commio* commio;
1027 NTSTATUS status;
1029 if ((status = NtResetEvent(hEvent, NULL)))
1030 return status;
1032 commio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof (async_commio));
1033 if (!commio) return STATUS_NO_MEMORY;
1035 commio->hDevice = hDevice;
1036 commio->events = events;
1037 commio->hEvent = hEvent;
1038 get_wait_mask(commio->hDevice, &commio->evtmask);
1040 /* We may never return, if some capabilities miss
1041 * Return error in that case
1043 #if !defined(TIOCINQ)
1044 if (commio->evtmask & EV_RXCHAR)
1045 goto error_caps;
1046 #endif
1047 #if !(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)
1048 if (commio->evtmask & EV_TXEMPTY)
1049 goto error_caps;
1050 #endif
1051 #if !defined(TIOCMGET)
1052 if (commio->evtmask & (EV_CTS | EV_DSR| EV_RING| EV_RLSD))
1053 goto error_caps;
1054 #endif
1055 #if !defined(TIOCM_CTS)
1056 if (commio->evtmask & EV_CTS)
1057 goto error_caps;
1058 #endif
1059 #if !defined(TIOCM_DSR)
1060 if (commio->evtmask & EV_DSR)
1061 goto error_caps;
1062 #endif
1063 #if !defined(TIOCM_RNG)
1064 if (commio->evtmask & EV_RING)
1065 goto error_caps;
1066 #endif
1067 #if !defined(TIOCM_CAR)
1068 if (commio->evtmask & EV_RLSD)
1069 goto error_caps;
1070 #endif
1071 if (commio->evtmask & EV_RXFLAG)
1072 FIXME("EV_RXFLAG not handled\n");
1073 if ((status = get_irq_info(fd, &commio->irq_info)) ||
1074 (status = get_modem_status(fd, &commio->mstat)))
1075 goto out_now;
1077 /* We might have received something or the TX bufffer is delivered */
1078 *events = check_events(fd, commio->evtmask,
1079 &commio->irq_info, &commio->irq_info,
1080 commio->mstat, commio->mstat);
1081 if (*events) goto out_now;
1083 /* create the worker for the task */
1084 status = RtlQueueWorkItem(wait_for_event, commio, 0 /* FIXME */);
1085 if (status != STATUS_SUCCESS) goto out_now;
1086 return STATUS_PENDING;
1088 #if !defined(TIOCINQ) || (!(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)) || !defined(TIOCMGET) || !defined(TIOCM_CTS) ||!defined(TIOCM_DSR) || !defined(TIOCM_RNG) || !defined(TIOCM_CAR)
1089 error_caps:
1090 FIXME("Returning error because of missing capabilities\n");
1091 status = STATUS_INVALID_PARAMETER;
1092 #endif
1093 out_now:
1094 RtlFreeHeap(GetProcessHeap(), 0, commio);
1095 return status;
1098 static NTSTATUS xmit_immediate(HANDLE hDevice, int fd, const char* ptr)
1100 /* FIXME: not perfect as it should bypass the in-queue */
1101 WARN("(%p,'%c') not perfect!\n", hDevice, *ptr);
1102 if (write(fd, ptr, 1) != 1)
1103 return FILE_GetNtStatus();
1104 return STATUS_SUCCESS;
1107 /******************************************************************
1108 * COMM_DeviceIoControl
1112 static inline NTSTATUS io_control(HANDLE hDevice,
1113 HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
1114 PVOID UserApcContext,
1115 PIO_STATUS_BLOCK piosb,
1116 ULONG dwIoControlCode,
1117 LPVOID lpInBuffer, DWORD nInBufferSize,
1118 LPVOID lpOutBuffer, DWORD nOutBufferSize)
1120 DWORD sz = 0, access = FILE_READ_DATA;
1121 NTSTATUS status = STATUS_SUCCESS;
1122 int fd = -1, needs_close = 0;
1124 TRACE("%p %s %p %d %p %d %p\n",
1125 hDevice, iocode2str(dwIoControlCode), lpInBuffer, nInBufferSize,
1126 lpOutBuffer, nOutBufferSize, piosb);
1128 piosb->Information = 0;
1130 if (dwIoControlCode != IOCTL_SERIAL_GET_TIMEOUTS)
1131 if ((status = server_get_unix_fd( hDevice, access, &fd, &needs_close, NULL, NULL )))
1132 goto error;
1134 switch (dwIoControlCode)
1136 case IOCTL_SERIAL_CLR_DTR:
1137 #ifdef TIOCM_DTR
1138 if (whack_modem(fd, ~TIOCM_DTR, 0) == -1) status = FILE_GetNtStatus();
1139 #else
1140 status = STATUS_NOT_SUPPORTED;
1141 #endif
1142 break;
1143 case IOCTL_SERIAL_CLR_RTS:
1144 #ifdef TIOCM_RTS
1145 if (whack_modem(fd, ~TIOCM_RTS, 0) == -1) status = FILE_GetNtStatus();
1146 #else
1147 status = STATUS_NOT_SUPPORTED;
1148 #endif
1149 break;
1150 case IOCTL_SERIAL_GET_BAUD_RATE:
1151 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_BAUD_RATE))
1153 if (!(status = get_baud_rate(fd, (SERIAL_BAUD_RATE*)lpOutBuffer)))
1154 sz = sizeof(SERIAL_BAUD_RATE);
1156 else
1157 status = STATUS_INVALID_PARAMETER;
1158 break;
1159 case IOCTL_SERIAL_GET_CHARS:
1160 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_CHARS))
1162 if (!(status = get_special_chars(fd, (SERIAL_CHARS*)lpOutBuffer)))
1163 sz = sizeof(SERIAL_CHARS);
1165 else
1166 status = STATUS_INVALID_PARAMETER;
1167 break;
1168 case IOCTL_SERIAL_GET_COMMSTATUS:
1169 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_STATUS))
1171 if (!(status = get_status(fd, (SERIAL_STATUS*)lpOutBuffer)))
1172 sz = sizeof(SERIAL_STATUS);
1174 else status = STATUS_INVALID_PARAMETER;
1175 break;
1176 case IOCTL_SERIAL_GET_HANDFLOW:
1177 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_HANDFLOW))
1179 if (!(status = get_hand_flow(fd, (SERIAL_HANDFLOW*)lpOutBuffer)))
1180 sz = sizeof(SERIAL_HANDFLOW);
1182 else
1183 status = STATUS_INVALID_PARAMETER;
1184 break;
1185 case IOCTL_SERIAL_GET_LINE_CONTROL:
1186 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_LINE_CONTROL))
1188 if (!(status = get_line_control(fd, (SERIAL_LINE_CONTROL*)lpOutBuffer)))
1189 sz = sizeof(SERIAL_LINE_CONTROL);
1191 else
1192 status = STATUS_INVALID_PARAMETER;
1193 break;
1194 case IOCTL_SERIAL_GET_MODEMSTATUS:
1195 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1197 if (!(status = get_modem_status(fd, (DWORD*)lpOutBuffer)))
1198 sz = sizeof(DWORD);
1200 else status = STATUS_INVALID_PARAMETER;
1201 break;
1202 case IOCTL_SERIAL_GET_TIMEOUTS:
1203 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_TIMEOUTS))
1205 if (!(status = get_timeouts(hDevice, (SERIAL_TIMEOUTS*)lpOutBuffer)))
1206 sz = sizeof(SERIAL_TIMEOUTS);
1208 else
1209 status = STATUS_INVALID_PARAMETER;
1210 break;
1211 case IOCTL_SERIAL_GET_WAIT_MASK:
1212 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1214 if (!(status = get_wait_mask(hDevice, (DWORD*)lpOutBuffer)))
1215 sz = sizeof(DWORD);
1217 else
1218 status = STATUS_INVALID_PARAMETER;
1219 break;
1220 case IOCTL_SERIAL_IMMEDIATE_CHAR:
1221 if (lpInBuffer && nInBufferSize == sizeof(CHAR))
1222 status = xmit_immediate(hDevice, fd, lpInBuffer);
1223 else
1224 status = STATUS_INVALID_PARAMETER;
1225 break;
1226 case IOCTL_SERIAL_PURGE:
1227 if (lpInBuffer && nInBufferSize == sizeof(DWORD))
1228 status = purge(fd, *(DWORD*)lpInBuffer);
1229 else
1230 status = STATUS_INVALID_PARAMETER;
1231 break;
1232 case IOCTL_SERIAL_RESET_DEVICE:
1233 FIXME("Unsupported\n");
1234 break;
1235 case IOCTL_SERIAL_SET_BAUD_RATE:
1236 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_BAUD_RATE))
1237 status = set_baud_rate(fd, (const SERIAL_BAUD_RATE*)lpInBuffer);
1238 else
1239 status = STATUS_INVALID_PARAMETER;
1240 break;
1241 case IOCTL_SERIAL_SET_BREAK_OFF:
1242 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1243 if (ioctl(fd, TIOCCBRK, 0) == -1)
1245 TRACE("ioctl failed\n");
1246 status = FILE_GetNtStatus();
1248 #else
1249 FIXME("ioctl not available\n");
1250 status = STATUS_NOT_SUPPORTED;
1251 #endif
1252 break;
1253 case IOCTL_SERIAL_SET_BREAK_ON:
1254 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1255 if (ioctl(fd, TIOCSBRK, 0) == -1)
1257 TRACE("ioctl failed\n");
1258 status = FILE_GetNtStatus();
1260 #else
1261 FIXME("ioctl not available\n");
1262 status = STATUS_NOT_SUPPORTED;
1263 #endif
1264 break;
1265 case IOCTL_SERIAL_SET_CHARS:
1266 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_CHARS))
1267 status = set_special_chars(fd, (const SERIAL_CHARS*)lpInBuffer);
1268 else
1269 status = STATUS_INVALID_PARAMETER;
1270 break;
1271 case IOCTL_SERIAL_SET_DTR:
1272 #ifdef TIOCM_DTR
1273 if (whack_modem(fd, 0, TIOCM_DTR) == -1) status = FILE_GetNtStatus();
1274 #else
1275 status = STATUS_NOT_SUPPORTED;
1276 #endif
1277 break;
1278 case IOCTL_SERIAL_SET_HANDFLOW:
1279 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_HANDFLOW))
1280 status = set_handflow(fd, (const SERIAL_HANDFLOW*)lpInBuffer);
1281 else
1282 status = STATUS_INVALID_PARAMETER;
1283 break;
1284 case IOCTL_SERIAL_SET_LINE_CONTROL:
1285 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_LINE_CONTROL))
1286 status = set_line_control(fd, (const SERIAL_LINE_CONTROL*)lpInBuffer);
1287 else
1288 status = STATUS_INVALID_PARAMETER;
1289 break;
1290 case IOCTL_SERIAL_SET_QUEUE_SIZE:
1291 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_QUEUE_SIZE))
1292 status = set_queue_size(fd, (const SERIAL_QUEUE_SIZE*)lpInBuffer);
1293 else
1294 status = STATUS_INVALID_PARAMETER;
1295 break;
1296 case IOCTL_SERIAL_SET_RTS:
1297 #ifdef TIOCM_RTS
1298 if (whack_modem(fd, 0, TIOCM_RTS) == -1) status = FILE_GetNtStatus();
1299 #else
1300 status = STATUS_NOT_SUPPORTED;
1301 #endif
1302 break;
1303 case IOCTL_SERIAL_SET_TIMEOUTS:
1304 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_TIMEOUTS))
1305 status = set_timeouts(hDevice, fd, (const SERIAL_TIMEOUTS*)lpInBuffer);
1306 else
1307 status = STATUS_INVALID_PARAMETER;
1308 break;
1309 case IOCTL_SERIAL_SET_WAIT_MASK:
1310 if (lpInBuffer && nInBufferSize == sizeof(DWORD))
1312 status = set_wait_mask(hDevice, *(DWORD*)lpInBuffer);
1314 else status = STATUS_INVALID_PARAMETER;
1315 break;
1316 case IOCTL_SERIAL_SET_XOFF:
1317 status = set_XOff(fd);
1318 break;
1319 case IOCTL_SERIAL_SET_XON:
1320 status = set_XOn(fd);
1321 break;
1322 case IOCTL_SERIAL_WAIT_ON_MASK:
1323 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1325 if (!(status = wait_on(hDevice, fd, hEvent, (DWORD*)lpOutBuffer)))
1326 sz = sizeof(DWORD);
1328 else
1329 status = STATUS_INVALID_PARAMETER;
1330 break;
1331 default:
1332 FIXME("Unsupported IOCTL %x (type=%x access=%x func=%x meth=%x)\n",
1333 dwIoControlCode, dwIoControlCode >> 16, (dwIoControlCode >> 14) & 3,
1334 (dwIoControlCode >> 2) & 0xFFF, dwIoControlCode & 3);
1335 sz = 0;
1336 status = STATUS_INVALID_PARAMETER;
1337 break;
1339 if (needs_close) close( fd );
1340 error:
1341 piosb->u.Status = status;
1342 piosb->Information = sz;
1343 if (hEvent && status != STATUS_PENDING) NtSetEvent(hEvent, NULL);
1344 return status;
1347 NTSTATUS COMM_DeviceIoControl(HANDLE hDevice,
1348 HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
1349 PVOID UserApcContext,
1350 PIO_STATUS_BLOCK piosb,
1351 ULONG dwIoControlCode,
1352 LPVOID lpInBuffer, DWORD nInBufferSize,
1353 LPVOID lpOutBuffer, DWORD nOutBufferSize)
1355 NTSTATUS status;
1357 if (dwIoControlCode == IOCTL_SERIAL_WAIT_ON_MASK)
1359 HANDLE hev = hEvent;
1361 /* this is an ioctl we implement in a non blocking way if hEvent is not
1362 * null
1363 * so we have to explicitely wait if no hEvent is provided
1365 if (!hev)
1367 OBJECT_ATTRIBUTES attr;
1369 attr.Length = sizeof(attr);
1370 attr.RootDirectory = 0;
1371 attr.ObjectName = NULL;
1372 attr.Attributes = OBJ_CASE_INSENSITIVE | OBJ_OPENIF;
1373 attr.SecurityDescriptor = NULL;
1374 attr.SecurityQualityOfService = NULL;
1375 status = NtCreateEvent(&hev, EVENT_ALL_ACCESS, &attr, FALSE, FALSE);
1377 if (status) goto done;
1379 status = io_control(hDevice, hev, UserApcRoutine, UserApcContext,
1380 piosb, dwIoControlCode, lpInBuffer, nInBufferSize,
1381 lpOutBuffer, nOutBufferSize);
1382 if (hev != hEvent)
1384 if (status == STATUS_PENDING)
1386 NtWaitForSingleObject(hev, FALSE, NULL);
1387 status = STATUS_SUCCESS;
1389 NtClose(hev);
1392 else status = io_control(hDevice, hEvent, UserApcRoutine, UserApcContext,
1393 piosb, dwIoControlCode, lpInBuffer, nInBufferSize,
1394 lpOutBuffer, nOutBufferSize);
1395 done:
1396 return status;