urlmon: Call IBindStatusCallback_OnStopBinding only if this actually is the last...
[wine.git] / dlls / ntdll / serial.c
blobbd6f9cad39fe50f9ab1be111eabba8c47b27b31e
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 #ifdef HAVE_TERMIOS_H
43 #include <termios.h>
44 #endif
45 #include <fcntl.h>
46 #ifdef HAVE_SYS_STAT_H
47 # include <sys/stat.h>
48 #endif
49 #include <sys/types.h>
50 #ifdef HAVE_SYS_FILIO_H
51 # include <sys/filio.h>
52 #endif
53 #ifdef HAVE_SYS_IOCTL_H
54 #include <sys/ioctl.h>
55 #endif
56 #ifdef HAVE_SYS_POLL_H
57 # include <sys/poll.h>
58 #endif
59 #ifdef HAVE_SYS_MODEM_H
60 # include <sys/modem.h>
61 #endif
62 #ifdef HAVE_SYS_STRTIO_H
63 # include <sys/strtio.h>
64 #endif
66 #define NONAMELESSUNION
67 #define NONAMELESSSTRUCT
68 #include "ntstatus.h"
69 #define WIN32_NO_STATUS
70 #include "windef.h"
71 #include "winternl.h"
72 #include "winioctl.h"
73 #include "ddk/ntddser.h"
74 #include "ntdll_misc.h"
75 #include "wine/server.h"
76 #include "wine/library.h"
77 #include "wine/debug.h"
79 #ifdef HAVE_LINUX_SERIAL_H
80 #include <linux/serial.h>
81 #endif
83 #if !defined(TIOCINQ) && defined(FIONREAD)
84 #define TIOCINQ FIONREAD
85 #endif
87 WINE_DEFAULT_DEBUG_CHANNEL(comm);
89 static const char* iocode2str(DWORD ioc)
91 switch (ioc)
93 #define X(x) case (x): return #x;
94 X(IOCTL_SERIAL_CLEAR_STATS);
95 X(IOCTL_SERIAL_CLR_DTR);
96 X(IOCTL_SERIAL_CLR_RTS);
97 X(IOCTL_SERIAL_CONFIG_SIZE);
98 X(IOCTL_SERIAL_GET_BAUD_RATE);
99 X(IOCTL_SERIAL_GET_CHARS);
100 X(IOCTL_SERIAL_GET_COMMSTATUS);
101 X(IOCTL_SERIAL_GET_DTRRTS);
102 X(IOCTL_SERIAL_GET_HANDFLOW);
103 X(IOCTL_SERIAL_GET_LINE_CONTROL);
104 X(IOCTL_SERIAL_GET_MODEM_CONTROL);
105 X(IOCTL_SERIAL_GET_MODEMSTATUS);
106 X(IOCTL_SERIAL_GET_PROPERTIES);
107 X(IOCTL_SERIAL_GET_STATS);
108 X(IOCTL_SERIAL_GET_TIMEOUTS);
109 X(IOCTL_SERIAL_GET_WAIT_MASK);
110 X(IOCTL_SERIAL_IMMEDIATE_CHAR);
111 X(IOCTL_SERIAL_LSRMST_INSERT);
112 X(IOCTL_SERIAL_PURGE);
113 X(IOCTL_SERIAL_RESET_DEVICE);
114 X(IOCTL_SERIAL_SET_BAUD_RATE);
115 X(IOCTL_SERIAL_SET_BREAK_ON);
116 X(IOCTL_SERIAL_SET_BREAK_OFF);
117 X(IOCTL_SERIAL_SET_CHARS);
118 X(IOCTL_SERIAL_SET_DTR);
119 X(IOCTL_SERIAL_SET_FIFO_CONTROL);
120 X(IOCTL_SERIAL_SET_HANDFLOW);
121 X(IOCTL_SERIAL_SET_LINE_CONTROL);
122 X(IOCTL_SERIAL_SET_MODEM_CONTROL);
123 X(IOCTL_SERIAL_SET_QUEUE_SIZE);
124 X(IOCTL_SERIAL_SET_RTS);
125 X(IOCTL_SERIAL_SET_TIMEOUTS);
126 X(IOCTL_SERIAL_SET_WAIT_MASK);
127 X(IOCTL_SERIAL_SET_XOFF);
128 X(IOCTL_SERIAL_SET_XON);
129 X(IOCTL_SERIAL_WAIT_ON_MASK);
130 X(IOCTL_SERIAL_XOFF_COUNTER);
131 #undef X
132 default: { static char tmp[32]; sprintf(tmp, "IOCTL_SERIAL_%d\n", ioc); return tmp; }
136 static NTSTATUS get_baud_rate(int fd, SERIAL_BAUD_RATE* sbr)
138 struct termios port;
139 int speed;
141 if (tcgetattr(fd, &port) == -1)
143 ERR("tcgetattr error '%s'\n", strerror(errno));
144 return FILE_GetNtStatus();
146 #ifndef __EMX__
147 #ifdef CBAUD
148 speed = port.c_cflag & CBAUD;
149 #else
150 speed = cfgetospeed(&port);
151 #endif
152 switch (speed)
154 case B0: sbr->BaudRate = 0; break;
155 case B50: sbr->BaudRate = 50; break;
156 case B75: sbr->BaudRate = 75; break;
157 case B110: sbr->BaudRate = 110; break;
158 case B134: sbr->BaudRate = 134; break;
159 case B150: sbr->BaudRate = 150; break;
160 case B200: sbr->BaudRate = 200; break;
161 case B300: sbr->BaudRate = 300; break;
162 case B600: sbr->BaudRate = 600; break;
163 case B1200: sbr->BaudRate = 1200; break;
164 case B1800: sbr->BaudRate = 1800; break;
165 case B2400: sbr->BaudRate = 2400; break;
166 case B4800: sbr->BaudRate = 4800; break;
167 case B9600: sbr->BaudRate = 9600; break;
168 case B19200: sbr->BaudRate = 19200; break;
169 case B38400: sbr->BaudRate = 38400; break;
170 #ifdef B57600
171 case B57600: sbr->BaudRate = 57600; break;
172 #endif
173 #ifdef B115200
174 case B115200: sbr->BaudRate = 115200; break;
175 #endif
176 #ifdef B230400
177 case B230400: sbr->BaudRate = 230400; break;
178 #endif
179 #ifdef B460800
180 case B460800: sbr->BaudRate = 460800; break;
181 #endif
182 default:
183 ERR("unknown speed %x\n", speed);
184 return STATUS_INVALID_PARAMETER;
186 #else
187 return STATUS_INVALID_PARAMETER;
188 #endif
189 return STATUS_SUCCESS;
192 static NTSTATUS get_hand_flow(int fd, SERIAL_HANDFLOW* shf)
194 int stat;
195 struct termios port;
197 if (tcgetattr(fd, &port) == -1)
199 ERR("tcgetattr error '%s'\n", strerror(errno));
200 return FILE_GetNtStatus();
202 #ifdef TIOCMGET
203 if (ioctl(fd, TIOCMGET, &stat) == -1)
205 WARN("ioctl error '%s'\n", strerror(errno));
206 stat = DTR_CONTROL_ENABLE | RTS_CONTROL_ENABLE;
208 #endif
209 /* termios does not support DTR/DSR flow control */
210 shf->ControlHandShake = 0;
211 shf->FlowReplace = 0;
212 #ifdef TIOCM_DTR
213 if (stat & TIOCM_DTR)
214 #endif
215 shf->ControlHandShake |= SERIAL_DTR_CONTROL;
216 #ifdef CRTSCTS
217 if (port.c_cflag & CRTSCTS)
219 shf->ControlHandShake |= SERIAL_DTR_CONTROL | SERIAL_DTR_HANDSHAKE;
220 shf->ControlHandShake |= SERIAL_CTS_HANDSHAKE;
222 else
223 #endif
225 #ifdef TIOCM_RTS
226 if (stat & TIOCM_RTS)
227 #endif
228 shf->ControlHandShake |= SERIAL_RTS_CONTROL;
230 if (port.c_iflag & IXON)
231 shf->FlowReplace |= SERIAL_AUTO_RECEIVE;
232 if (port.c_iflag & IXOFF)
233 shf->FlowReplace |= SERIAL_AUTO_TRANSMIT;
235 shf->XonLimit = 10;
236 shf->XoffLimit = 10;
237 return STATUS_SUCCESS;
240 static NTSTATUS get_line_control(int fd, SERIAL_LINE_CONTROL* slc)
242 struct termios port;
244 if (tcgetattr(fd, &port) == -1)
246 ERR("tcgetattr error '%s'\n", strerror(errno));
247 return FILE_GetNtStatus();
250 #ifdef CMSPAR
251 switch (port.c_cflag & (PARENB | PARODD | CMSPAR))
252 #else
253 switch (port.c_cflag & (PARENB | PARODD))
254 #endif
256 case 0: slc->Parity = NOPARITY; break;
257 case PARENB: slc->Parity = EVENPARITY; break;
258 case PARENB|PARODD: slc->Parity = ODDPARITY; break;
259 #ifdef CMSPAR
260 case PARENB|CMSPAR: slc->Parity = MARKPARITY; break;
261 case PARENB|PARODD|CMSPAR: slc->Parity = SPACEPARITY; break;
262 #endif
264 switch (port.c_cflag & CSIZE)
266 case CS5: slc->WordLength = 5; break;
267 case CS6: slc->WordLength = 6; break;
268 case CS7: slc->WordLength = 7; break;
269 case CS8: slc->WordLength = 8; break;
270 default: ERR("unknown size %x\n", (UINT)(port.c_cflag & CSIZE));
273 if (port.c_cflag & CSTOPB)
275 if (slc->WordLength == 5)
276 slc->StopBits = ONE5STOPBITS;
277 else
278 slc->StopBits = TWOSTOPBITS;
280 else
281 slc->StopBits = ONESTOPBIT;
283 return STATUS_SUCCESS;
286 static NTSTATUS get_modem_status(int fd, DWORD* lpModemStat)
288 NTSTATUS status = STATUS_SUCCESS;
289 int mstat;
291 #ifdef TIOCMGET
292 if (ioctl(fd, TIOCMGET, &mstat) == -1)
294 WARN("ioctl failed\n");
295 status = FILE_GetNtStatus();
297 else
299 *lpModemStat = 0;
300 #ifdef TIOCM_CTS
301 if (mstat & TIOCM_CTS) *lpModemStat |= MS_CTS_ON;
302 #endif
303 #ifdef TIOCM_DSR
304 if (mstat & TIOCM_DSR) *lpModemStat |= MS_DSR_ON;
305 #endif
306 #ifdef TIOCM_RNG
307 if (mstat & TIOCM_RNG) *lpModemStat |= MS_RING_ON;
308 #endif
309 #ifdef TIOCM_CAR
310 /* FIXME: Not really sure about RLSD UB 990810 */
311 if (mstat & TIOCM_CAR) *lpModemStat |= MS_RLSD_ON;
312 #endif
313 TRACE("%04x -> %s%s%s%s\n", mstat,
314 (*lpModemStat & MS_RLSD_ON) ? "MS_RLSD_ON " : "",
315 (*lpModemStat & MS_RING_ON) ? "MS_RING_ON " : "",
316 (*lpModemStat & MS_DSR_ON) ? "MS_DSR_ON " : "",
317 (*lpModemStat & MS_CTS_ON) ? "MS_CTS_ON " : "");
319 #else
320 status = STATUS_NOT_SUPPORTED;
321 #endif
322 return status;
325 static NTSTATUS get_special_chars(int fd, SERIAL_CHARS* sc)
327 struct termios port;
329 if (tcgetattr(fd, &port) == -1)
331 ERR("tcgetattr error '%s'\n", strerror(errno));
332 return FILE_GetNtStatus();
334 sc->EofChar = port.c_cc[VEOF];
335 sc->ErrorChar = 0xFF;
336 sc->BreakChar = 0; /* FIXME */
337 sc->EventChar = 0; /* FIXME */
338 sc->XonChar = port.c_cc[VSTART];
339 sc->XoffChar = port.c_cc[VSTOP];
341 return STATUS_SUCCESS;
344 static NTSTATUS get_status(int fd, SERIAL_STATUS* ss)
346 NTSTATUS status = STATUS_SUCCESS;
348 ss->Errors = 0;
349 ss->HoldReasons = 0;
350 ss->EofReceived = FALSE;
351 ss->WaitForImmediate = FALSE;
352 #ifdef TIOCOUTQ
353 if (ioctl(fd, TIOCOUTQ, &ss->AmountInOutQueue) == -1)
355 WARN("ioctl returned error\n");
356 status = FILE_GetNtStatus();
358 #else
359 ss->AmountInOutQueue = 0; /* FIXME: find a different way to find out */
360 #endif
362 #ifdef TIOCINQ
363 if (ioctl(fd, TIOCINQ, &ss->AmountInInQueue))
365 WARN("ioctl returned error\n");
366 status = FILE_GetNtStatus();
368 #else
369 ss->AmountInInQueue = 0; /* FIXME: find a different way to find out */
370 #endif
371 return status;
374 static NTSTATUS get_timeouts(HANDLE handle, SERIAL_TIMEOUTS* st)
376 NTSTATUS status;
377 SERVER_START_REQ( get_serial_info )
379 req->handle = handle;
380 if (!(status = wine_server_call( req )))
382 st->ReadIntervalTimeout = reply->readinterval;
383 st->ReadTotalTimeoutMultiplier = reply->readmult;
384 st->ReadTotalTimeoutConstant = reply->readconst;
385 st->WriteTotalTimeoutMultiplier = reply->writemult;
386 st->WriteTotalTimeoutConstant = reply->writeconst;
389 SERVER_END_REQ;
390 return status;
393 static NTSTATUS get_wait_mask(HANDLE hDevice, DWORD* mask)
395 NTSTATUS status;
397 SERVER_START_REQ( get_serial_info )
399 req->handle = hDevice;
400 if (!(status = wine_server_call( req )))
401 *mask = reply->eventmask;
403 SERVER_END_REQ;
404 return status;
407 static NTSTATUS purge(int fd, DWORD flags)
410 ** not exactly sure how these are different
411 ** Perhaps if we had our own internal queues, one flushes them
412 ** and the other flushes the kernel's buffers.
414 if (flags & PURGE_TXABORT) tcflush(fd, TCOFLUSH);
415 if (flags & PURGE_RXABORT) tcflush(fd, TCIFLUSH);
416 if (flags & PURGE_TXCLEAR) tcflush(fd, TCOFLUSH);
417 if (flags & PURGE_RXCLEAR) tcflush(fd, TCIFLUSH);
418 return STATUS_SUCCESS;
421 static NTSTATUS set_baud_rate(int fd, const SERIAL_BAUD_RATE* sbr)
423 struct termios port;
425 if (tcgetattr(fd, &port) == -1)
427 ERR("tcgetattr error '%s'\n", strerror(errno));
428 return FILE_GetNtStatus();
431 #ifdef CBAUD
432 port.c_cflag &= ~CBAUD;
433 switch (sbr->BaudRate)
435 case 0: port.c_cflag |= B0; break;
436 case 50: port.c_cflag |= B50; break;
437 case 75: port.c_cflag |= B75; break;
438 case 110:
439 case CBR_110: port.c_cflag |= B110; break;
440 case 134: port.c_cflag |= B134; break;
441 case 150: port.c_cflag |= B150; break;
442 case 200: port.c_cflag |= B200; break;
443 case 300:
444 case CBR_300: port.c_cflag |= B300; break;
445 case 600:
446 case CBR_600: port.c_cflag |= B600; break;
447 case 1200:
448 case CBR_1200: port.c_cflag |= B1200; break;
449 case 1800: port.c_cflag |= B1800; break;
450 case 2400:
451 case CBR_2400: port.c_cflag |= B2400; break;
452 case 4800:
453 case CBR_4800: port.c_cflag |= B4800; break;
454 case 9600:
455 case CBR_9600: port.c_cflag |= B9600; break;
456 case 19200:
457 case CBR_19200: port.c_cflag |= B19200; break;
458 case 38400:
459 case CBR_38400: port.c_cflag |= B38400; break;
460 #ifdef B57600
461 case 57600: port.c_cflag |= B57600; break;
462 #endif
463 #ifdef B115200
464 case 115200: port.c_cflag |= B115200;break;
465 #endif
466 #ifdef B230400
467 case 230400: port.c_cflag |= B230400;break;
468 #endif
469 #ifdef B460800
470 case 460800: port.c_cflag |= B460800;break;
471 #endif
472 default:
473 #if defined (HAVE_LINUX_SERIAL_H) && defined (TIOCSSERIAL)
475 struct serial_struct nuts;
476 int arby;
478 ioctl(fd, TIOCGSERIAL, &nuts);
479 nuts.custom_divisor = nuts.baud_base / sbr->BaudRate;
480 if (!(nuts.custom_divisor)) nuts.custom_divisor = 1;
481 arby = nuts.baud_base / nuts.custom_divisor;
482 nuts.flags &= ~ASYNC_SPD_MASK;
483 nuts.flags |= ASYNC_SPD_CUST;
484 WARN("You (or a program acting at your behest) have specified\n"
485 "a non-standard baud rate %d. Wine will set the rate to %d,\n"
486 "which is as close as we can get by our present understanding of your\n"
487 "hardware. I hope you know what you are doing. Any disruption Wine\n"
488 "has caused to your linux system can be undone with setserial \n"
489 "(see man setserial). If you have incapacitated a Hayes type modem,\n"
490 "reset it and it will probably recover.\n", sbr->BaudRate, arby);
491 ioctl(fd, TIOCSSERIAL, &nuts);
492 port.c_cflag |= B38400;
494 break;
495 #else /* Don't have linux/serial.h or lack TIOCSSERIAL */
496 ERR("baudrate %d\n", sbr->BaudRate);
497 return STATUS_NOT_SUPPORTED;
498 #endif /* Don't have linux/serial.h or lack TIOCSSERIAL */
500 #elif !defined(__EMX__)
501 switch (sbr->BaudRate)
503 case 0: port.c_ospeed = B0; break;
504 case 50: port.c_ospeed = B50; break;
505 case 75: port.c_ospeed = B75; break;
506 case 110:
507 case CBR_110: port.c_ospeed = B110; break;
508 case 134: port.c_ospeed = B134; break;
509 case 150: port.c_ospeed = B150; break;
510 case 200: port.c_ospeed = B200; break;
511 case 300:
512 case CBR_300: port.c_ospeed = B300; break;
513 case 600:
514 case CBR_600: port.c_ospeed = B600; break;
515 case 1200:
516 case CBR_1200: port.c_ospeed = B1200; break;
517 case 1800: port.c_ospeed = B1800; break;
518 case 2400:
519 case CBR_2400: port.c_ospeed = B2400; break;
520 case 4800:
521 case CBR_4800: port.c_ospeed = B4800; break;
522 case 9600:
523 case CBR_9600: port.c_ospeed = B9600; break;
524 case 19200:
525 case CBR_19200: port.c_ospeed = B19200; break;
526 case 38400:
527 case CBR_38400: port.c_ospeed = B38400; break;
528 #ifdef B57600
529 case 57600:
530 case CBR_57600: port.c_cflag |= B57600; break;
531 #endif
532 #ifdef B115200
533 case 115200:
534 case CBR_115200: port.c_cflag |= B115200;break;
535 #endif
536 #ifdef B230400
537 case 230400: port.c_cflag |= B230400;break;
538 #endif
539 #ifdef B460800
540 case 460800: port.c_cflag |= B460800;break;
541 #endif
542 default:
543 ERR("baudrate %d\n", sbr->BaudRate);
544 return STATUS_NOT_SUPPORTED;
546 port.c_ispeed = port.c_ospeed;
547 #endif
548 if (tcsetattr(fd, TCSANOW, &port) == -1)
550 ERR("tcsetattr error '%s'\n", strerror(errno));
551 return FILE_GetNtStatus();
553 return STATUS_SUCCESS;
556 static int whack_modem(int fd, unsigned int andy, unsigned int orrie)
558 #ifdef TIOCMGET
559 unsigned int mstat, okay;
560 okay = ioctl(fd, TIOCMGET, &mstat);
561 if (okay) return okay;
562 if (andy) mstat &= andy;
563 mstat |= orrie;
564 return ioctl(fd, TIOCMSET, &mstat);
565 #else
566 return 0;
567 #endif
570 static NTSTATUS set_handflow(int fd, const SERIAL_HANDFLOW* shf)
572 struct termios port;
574 if ((shf->FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE)) ==
575 (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE))
576 return STATUS_NOT_SUPPORTED;
578 if (tcgetattr(fd, &port) == -1)
580 ERR("tcgetattr error '%s'\n", strerror(errno));
581 return FILE_GetNtStatus();
584 #ifdef CRTSCTS
585 if ((shf->ControlHandShake & SERIAL_CTS_HANDSHAKE) ||
586 (shf->FlowReplace & SERIAL_RTS_HANDSHAKE))
588 port.c_cflag |= CRTSCTS;
589 TRACE("CRTSCTS\n");
591 else
592 port.c_cflag &= ~CRTSCTS;
593 #endif
594 #ifdef TIOCM_DTR
595 if (shf->ControlHandShake & SERIAL_DTR_HANDSHAKE)
597 WARN("DSR/DTR flow control not supported\n");
598 } else if (!(shf->ControlHandShake & SERIAL_DTR_CONTROL))
599 whack_modem(fd, ~TIOCM_DTR, 0);
600 else
601 whack_modem(fd, 0, TIOCM_DTR);
602 #endif
603 #ifdef TIOCM_RTS
604 if (!(shf->ControlHandShake & SERIAL_CTS_HANDSHAKE))
606 if ((shf->FlowReplace & (SERIAL_RTS_CONTROL|SERIAL_RTS_HANDSHAKE)) == 0)
607 whack_modem(fd, ~TIOCM_RTS, 0);
608 else
609 whack_modem(fd, 0, TIOCM_RTS);
611 #endif
613 if (shf->FlowReplace & SERIAL_AUTO_RECEIVE)
614 port.c_iflag |= IXON;
615 else
616 port.c_iflag &= ~IXON;
617 if (shf->FlowReplace & SERIAL_AUTO_TRANSMIT)
618 port.c_iflag |= IXOFF;
619 else
620 port.c_iflag &= ~IXOFF;
621 if (tcsetattr(fd, TCSANOW, &port) == -1)
623 ERR("tcsetattr error '%s'\n", strerror(errno));
624 return FILE_GetNtStatus();
627 return STATUS_SUCCESS;
630 static NTSTATUS set_line_control(int fd, const SERIAL_LINE_CONTROL* slc)
632 struct termios port;
633 unsigned bytesize, stopbits;
635 if (tcgetattr(fd, &port) == -1)
637 ERR("tcgetattr error '%s'\n", strerror(errno));
638 return FILE_GetNtStatus();
641 #ifdef IMAXBEL
642 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK|IMAXBEL);
643 #else
644 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK);
645 #endif
646 port.c_iflag |= IGNBRK | INPCK;
648 port.c_oflag &= ~(OPOST);
650 port.c_cflag &= ~(HUPCL);
651 port.c_cflag |= CLOCAL | CREAD;
653 port.c_lflag &= ~(ICANON|ECHO|ISIG);
654 port.c_lflag |= NOFLSH;
656 bytesize = slc->WordLength;
657 stopbits = slc->StopBits;
659 #ifdef CMSPAR
660 port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
661 #else
662 port.c_cflag &= ~(PARENB | PARODD);
663 #endif
665 switch (slc->Parity)
667 case NOPARITY: port.c_iflag &= ~INPCK; break;
668 case ODDPARITY: port.c_cflag |= PARENB | PARODD; break;
669 case EVENPARITY: port.c_cflag |= PARENB; break;
670 #ifdef CMSPAR
671 /* Linux defines mark/space (stick) parity */
672 case MARKPARITY: port.c_cflag |= PARENB | CMSPAR; break;
673 case SPACEPARITY: port.c_cflag |= PARENB | PARODD | CMSPAR; break;
674 #else
675 /* try the POSIX way */
676 case MARKPARITY:
677 if (slc->StopBits == ONESTOPBIT)
679 stopbits = TWOSTOPBITS;
680 port.c_iflag &= ~INPCK;
682 else
684 ERR("Cannot set MARK Parity\n");
685 return STATUS_NOT_SUPPORTED;
687 break;
688 case SPACEPARITY:
689 if (slc->WordLength < 8)
691 bytesize +=1;
692 port.c_iflag &= ~INPCK;
694 else
696 ERR("Cannot set SPACE Parity\n");
697 return STATUS_NOT_SUPPORTED;
699 break;
700 #endif
701 default:
702 ERR("Parity\n");
703 return STATUS_NOT_SUPPORTED;
706 port.c_cflag &= ~CSIZE;
707 switch (bytesize)
709 case 5: port.c_cflag |= CS5; break;
710 case 6: port.c_cflag |= CS6; break;
711 case 7: port.c_cflag |= CS7; break;
712 case 8: port.c_cflag |= CS8; break;
713 default:
714 ERR("ByteSize\n");
715 return STATUS_NOT_SUPPORTED;
718 switch (stopbits)
720 case ONESTOPBIT: port.c_cflag &= ~CSTOPB; break;
721 case ONE5STOPBITS: /* will be selected if bytesize is 5 */
722 case TWOSTOPBITS: port.c_cflag |= CSTOPB; break;
723 default:
724 ERR("StopBits\n");
725 return STATUS_NOT_SUPPORTED;
727 /* otherwise it hangs with pending input*/
728 if (tcsetattr(fd, TCSANOW, &port) == -1)
730 ERR("tcsetattr error '%s'\n", strerror(errno));
731 return FILE_GetNtStatus();
733 return STATUS_SUCCESS;
736 static NTSTATUS set_queue_size(int fd, const SERIAL_QUEUE_SIZE* sqs)
738 FIXME("insize %d outsize %d unimplemented stub\n", sqs->InSize, sqs->OutSize);
739 return STATUS_SUCCESS;
742 static NTSTATUS set_special_chars(int fd, const SERIAL_CHARS* sc)
744 struct termios port;
746 if (tcgetattr(fd, &port) == -1)
748 ERR("tcgetattr error '%s'\n", strerror(errno));
749 return FILE_GetNtStatus();
752 port.c_cc[VMIN ] = 0;
753 port.c_cc[VTIME ] = 1;
755 port.c_cc[VEOF ] = sc->EofChar;
756 /* FIXME: sc->ErrorChar is not supported */
757 /* FIXME: sc->BreakChar is not supported */
758 /* FIXME: sc->EventChar is not supported */
759 port.c_cc[VSTART] = sc->XonChar;
760 port.c_cc[VSTOP ] = sc->XoffChar;
762 if (tcsetattr(fd, TCSANOW, &port) == -1)
764 ERR("tcsetattr error '%s'\n", strerror(errno));
765 return FILE_GetNtStatus();
767 return STATUS_SUCCESS;
770 static NTSTATUS set_timeouts(HANDLE handle, int fd, const SERIAL_TIMEOUTS* st)
772 NTSTATUS status;
773 struct termios port;
774 unsigned int ux_timeout;
776 SERVER_START_REQ( set_serial_info )
778 req->handle = handle;
779 req->flags = SERIALINFO_SET_TIMEOUTS;
780 req->readinterval = st->ReadIntervalTimeout ;
781 req->readmult = st->ReadTotalTimeoutMultiplier ;
782 req->readconst = st->ReadTotalTimeoutConstant ;
783 req->writemult = st->WriteTotalTimeoutMultiplier ;
784 req->writeconst = st->WriteTotalTimeoutConstant ;
785 status = wine_server_call( req );
787 SERVER_END_REQ;
788 if (status) return status;
790 if (tcgetattr(fd, &port) == -1)
792 FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
793 return FILE_GetNtStatus();
796 /* VTIME is in 1/10 seconds */
797 if (st->ReadIntervalTimeout == 0) /* 0 means no timeout */
798 ux_timeout = 0;
799 else
801 ux_timeout = (st->ReadIntervalTimeout + 99) / 100;
802 if (ux_timeout == 0)
803 ux_timeout = 1; /* must be at least some timeout */
805 port.c_cc[VTIME] = ux_timeout;
807 if (tcsetattr(fd, 0, &port) == -1)
809 FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
810 return FILE_GetNtStatus();
812 return STATUS_SUCCESS;
815 static NTSTATUS set_wait_mask(HANDLE hDevice, DWORD mask)
817 NTSTATUS status;
819 SERVER_START_REQ( set_serial_info )
821 req->handle = hDevice;
822 req->flags = SERIALINFO_SET_MASK;
823 req->eventmask = mask;
824 status = wine_server_call( req );
826 SERVER_END_REQ;
827 return status;
830 static NTSTATUS set_XOff(int fd)
832 struct termios port;
834 if (tcgetattr(fd,&port) == -1)
836 FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
837 return FILE_GetNtStatus();
841 port.c_iflag |= IXOFF;
842 if (tcsetattr(fd, TCSADRAIN, &port) == -1)
844 FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
845 return FILE_GetNtStatus();
847 return STATUS_SUCCESS;
850 static NTSTATUS set_XOn(int fd)
852 struct termios port;
854 if (tcgetattr(fd,&port) == -1)
856 FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
857 return FILE_GetNtStatus();
859 port.c_iflag |= IXON;
860 if (tcsetattr(fd, TCSADRAIN, &port) == -1)
862 FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
863 return FILE_GetNtStatus();
865 return STATUS_SUCCESS;
868 /* serial_irq_info
869 * local structure holding the irq values we need for WaitCommEvent()
871 * Stripped down from struct serial_icounter_struct, which may not be available on some systems
872 * As the modem line interrupts (cts, dsr, rng, dcd) only get updated with TIOCMIWAIT active,
873 * no need to carry them in the internal structure
876 typedef struct serial_irq_info
878 int rx , tx, frame, overrun, parity, brk, buf_overrun;
879 }serial_irq_info;
881 /***********************************************************************
882 * Data needed by the thread polling for the changing CommEvent
884 typedef struct async_commio
886 HANDLE hDevice;
887 DWORD* events;
888 HANDLE hEvent;
889 DWORD evtmask;
890 DWORD mstat;
891 serial_irq_info irq_info;
892 } async_commio;
894 /***********************************************************************
895 * Get extended interrupt count info, needed for wait_on
897 static NTSTATUS get_irq_info(int fd, serial_irq_info *irq_info)
899 #ifdef TIOCGICOUNT
900 struct serial_icounter_struct einfo;
901 if (!ioctl(fd, TIOCGICOUNT, &einfo))
903 irq_info->rx = einfo.rx;
904 irq_info->tx = einfo.tx;
905 irq_info->frame = einfo.frame;
906 irq_info->overrun = einfo.overrun;
907 irq_info->parity = einfo.parity;
908 irq_info->brk = einfo.brk;
909 irq_info->buf_overrun = einfo.buf_overrun;
910 return STATUS_SUCCESS;
912 TRACE("TIOCGICOUNT err %s\n", strerror(errno));
913 return FILE_GetNtStatus();
914 #else
915 memset(irq_info,0, sizeof(serial_irq_info));
916 return STATUS_NOT_IMPLEMENTED;
917 #endif
921 static DWORD WINAPI check_events(int fd, DWORD mask,
922 const serial_irq_info *new,
923 const serial_irq_info *old,
924 DWORD new_mstat, DWORD old_mstat)
926 DWORD ret = 0, queue;
928 TRACE("mask 0x%08x\n", mask);
929 TRACE("old->rx 0x%08x vs. new->rx 0x%08x\n", old->rx, new->rx);
930 TRACE("old->tx 0x%08x vs. new->tx 0x%08x\n", old->tx, new->tx);
931 TRACE("old->frame 0x%08x vs. new->frame 0x%08x\n", old->frame, new->frame);
932 TRACE("old->overrun 0x%08x vs. new->overrun 0x%08x\n", old->overrun, new->overrun);
933 TRACE("old->parity 0x%08x vs. new->parity 0x%08x\n", old->parity, new->parity);
934 TRACE("old->brk 0x%08x vs. new->brk 0x%08x\n", old->brk, new->brk);
935 TRACE("old->buf_overrun 0x%08x vs. new->buf_overrun 0x%08x\n", old->buf_overrun, new->buf_overrun);
937 if (old->brk != new->brk) ret |= EV_BREAK;
938 if ((old_mstat & MS_CTS_ON ) != (new_mstat & MS_CTS_ON )) ret |= EV_CTS;
939 if ((old_mstat & MS_DSR_ON ) != (new_mstat & MS_DSR_ON )) ret |= EV_DSR;
940 if ((old_mstat & MS_RING_ON) != (new_mstat & MS_RING_ON)) ret |= EV_RING;
941 if ((old_mstat & MS_RLSD_ON) != (new_mstat & MS_RLSD_ON)) ret |= EV_RLSD;
942 if (old->frame != new->frame || old->overrun != new->overrun || old->parity != new->parity) ret |= EV_ERR;
943 if (mask & EV_RXCHAR)
945 queue = 0;
946 #ifdef TIOCINQ
947 if (ioctl(fd, TIOCINQ, &queue))
948 WARN("TIOCINQ returned error\n");
949 #endif
950 if (queue)
951 ret |= EV_RXCHAR;
953 if (mask & EV_TXEMPTY)
955 queue = 0;
956 /* We really want to know when all characters have gone out of the transmitter */
957 #if defined(TIOCSERGETLSR)
958 if (ioctl(fd, TIOCSERGETLSR, &queue))
959 WARN("TIOCSERGETLSR returned error\n");
960 if (queue)
961 /* TIOCOUTQ only checks for an empty buffer */
962 #elif defined(TIOCOUTQ)
963 if (ioctl(fd, TIOCOUTQ, &queue))
964 WARN("TIOCOUTQ returned error\n");
965 if (!queue)
966 #endif
967 ret |= EV_TXEMPTY;
968 TRACE("OUTQUEUE %d, Transmitter %sempty\n",
969 queue, (ret & EV_TXEMPTY) ? "" : "not ");
971 return ret & mask;
974 /***********************************************************************
975 * wait_for_event (INTERNAL)
977 * We need to poll for what is interesting
978 * TIOCMIWAIT only checks modem status line and may not be aborted by a changing mask
981 static DWORD CALLBACK wait_for_event(LPVOID arg)
983 async_commio *commio = (async_commio*) arg;
984 int fd, needs_close;
986 if (!server_get_unix_fd( commio->hDevice, FILE_READ_DATA | FILE_WRITE_DATA, &fd, &needs_close, NULL, NULL ))
988 serial_irq_info new_irq_info;
989 DWORD new_mstat, new_evtmask;
990 LARGE_INTEGER time;
992 TRACE("device=%p fd=0x%08x mask=0x%08x buffer=%p event=%p irq_info=%p\n",
993 commio->hDevice, fd, commio->evtmask, commio->events, commio->hEvent, &commio->irq_info);
995 time.QuadPart = (ULONGLONG)10000;
996 time.QuadPart = -time.QuadPart;
997 for (;;)
1000 * TIOCMIWAIT is not adequate
1002 * FIXME:
1003 * We don't handle the EV_RXFLAG (the eventchar)
1005 NtDelayExecution(FALSE, &time);
1006 get_irq_info(fd, &new_irq_info);
1007 if (get_modem_status(fd, &new_mstat))
1008 TRACE("get_modem_status failed\n");
1009 *commio->events = check_events(fd, commio->evtmask,
1010 &new_irq_info, &commio->irq_info,
1011 new_mstat, commio->mstat);
1012 if (*commio->events) break;
1013 get_wait_mask(commio->hDevice, &new_evtmask);
1014 if (commio->evtmask != new_evtmask)
1016 *commio->events = 0;
1017 break;
1020 if (needs_close) close( fd );
1022 if (commio->hEvent) NtSetEvent(commio->hEvent, NULL);
1023 RtlFreeHeap(GetProcessHeap(), 0, commio);
1024 return 0;
1027 static NTSTATUS wait_on(HANDLE hDevice, int fd, HANDLE hEvent, DWORD* events)
1029 async_commio* commio;
1030 NTSTATUS status;
1032 if ((status = NtResetEvent(hEvent, NULL)))
1033 return status;
1035 commio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof (async_commio));
1036 if (!commio) return STATUS_NO_MEMORY;
1038 commio->hDevice = hDevice;
1039 commio->events = events;
1040 commio->hEvent = hEvent;
1041 get_wait_mask(commio->hDevice, &commio->evtmask);
1043 /* We may never return, if some capabilities miss
1044 * Return error in that case
1046 #if !defined(TIOCINQ)
1047 if (commio->evtmask & EV_RXCHAR)
1048 goto error_caps;
1049 #endif
1050 #if !(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)
1051 if (commio->evtmask & EV_TXEMPTY)
1052 goto error_caps;
1053 #endif
1054 #if !defined(TIOCMGET)
1055 if (commio->evtmask & (EV_CTS | EV_DSR| EV_RING| EV_RLSD))
1056 goto error_caps;
1057 #endif
1058 #if !defined(TIOCM_CTS)
1059 if (commio->evtmask & EV_CTS)
1060 goto error_caps;
1061 #endif
1062 #if !defined(TIOCM_DSR)
1063 if (commio->evtmask & EV_DSR)
1064 goto error_caps;
1065 #endif
1066 #if !defined(TIOCM_RNG)
1067 if (commio->evtmask & EV_RING)
1068 goto error_caps;
1069 #endif
1070 #if !defined(TIOCM_CAR)
1071 if (commio->evtmask & EV_RLSD)
1072 goto error_caps;
1073 #endif
1074 if (commio->evtmask & EV_RXFLAG)
1075 FIXME("EV_RXFLAG not handled\n");
1076 if ((status = get_irq_info(fd, &commio->irq_info)) ||
1077 (status = get_modem_status(fd, &commio->mstat)))
1078 goto out_now;
1080 /* We might have received something or the TX bufffer is delivered */
1081 *events = check_events(fd, commio->evtmask,
1082 &commio->irq_info, &commio->irq_info,
1083 commio->mstat, commio->mstat);
1084 if (*events) goto out_now;
1086 /* create the worker for the task */
1087 status = RtlQueueWorkItem(wait_for_event, commio, 0 /* FIXME */);
1088 if (status != STATUS_SUCCESS) goto out_now;
1089 return STATUS_PENDING;
1091 #if !defined(TIOCINQ) || (!(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)) || !defined(TIOCMGET) || !defined(TIOCM_CTS) ||!defined(TIOCM_DSR) || !defined(TIOCM_RNG) || !defined(TIOCM_CAR)
1092 error_caps:
1093 FIXME("Returning error because of missing capabilities\n");
1094 status = STATUS_INVALID_PARAMETER;
1095 #endif
1096 out_now:
1097 RtlFreeHeap(GetProcessHeap(), 0, commio);
1098 return status;
1101 static NTSTATUS xmit_immediate(HANDLE hDevice, int fd, const char* ptr)
1103 /* FIXME: not perfect as it should bypass the in-queue */
1104 WARN("(%p,'%c') not perfect!\n", hDevice, *ptr);
1105 if (write(fd, ptr, 1) != 1)
1106 return FILE_GetNtStatus();
1107 return STATUS_SUCCESS;
1110 /******************************************************************
1111 * COMM_DeviceIoControl
1115 static inline NTSTATUS io_control(HANDLE hDevice,
1116 HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
1117 PVOID UserApcContext,
1118 PIO_STATUS_BLOCK piosb,
1119 ULONG dwIoControlCode,
1120 LPVOID lpInBuffer, DWORD nInBufferSize,
1121 LPVOID lpOutBuffer, DWORD nOutBufferSize)
1123 DWORD sz = 0, access = FILE_READ_DATA;
1124 NTSTATUS status = STATUS_SUCCESS;
1125 int fd = -1, needs_close = 0;
1127 TRACE("%p %s %p %d %p %d %p\n",
1128 hDevice, iocode2str(dwIoControlCode), lpInBuffer, nInBufferSize,
1129 lpOutBuffer, nOutBufferSize, piosb);
1131 piosb->Information = 0;
1133 if (dwIoControlCode != IOCTL_SERIAL_GET_TIMEOUTS)
1134 if ((status = server_get_unix_fd( hDevice, access, &fd, &needs_close, NULL, NULL )))
1135 goto error;
1137 switch (dwIoControlCode)
1139 case IOCTL_SERIAL_CLR_DTR:
1140 #ifdef TIOCM_DTR
1141 if (whack_modem(fd, ~TIOCM_DTR, 0) == -1) status = FILE_GetNtStatus();
1142 #else
1143 status = STATUS_NOT_SUPPORTED;
1144 #endif
1145 break;
1146 case IOCTL_SERIAL_CLR_RTS:
1147 #ifdef TIOCM_RTS
1148 if (whack_modem(fd, ~TIOCM_RTS, 0) == -1) status = FILE_GetNtStatus();
1149 #else
1150 status = STATUS_NOT_SUPPORTED;
1151 #endif
1152 break;
1153 case IOCTL_SERIAL_GET_BAUD_RATE:
1154 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_BAUD_RATE))
1156 if (!(status = get_baud_rate(fd, (SERIAL_BAUD_RATE*)lpOutBuffer)))
1157 sz = sizeof(SERIAL_BAUD_RATE);
1159 else
1160 status = STATUS_INVALID_PARAMETER;
1161 break;
1162 case IOCTL_SERIAL_GET_CHARS:
1163 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_CHARS))
1165 if (!(status = get_special_chars(fd, (SERIAL_CHARS*)lpOutBuffer)))
1166 sz = sizeof(SERIAL_CHARS);
1168 else
1169 status = STATUS_INVALID_PARAMETER;
1170 break;
1171 case IOCTL_SERIAL_GET_COMMSTATUS:
1172 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_STATUS))
1174 if (!(status = get_status(fd, (SERIAL_STATUS*)lpOutBuffer)))
1175 sz = sizeof(SERIAL_STATUS);
1177 else status = STATUS_INVALID_PARAMETER;
1178 break;
1179 case IOCTL_SERIAL_GET_HANDFLOW:
1180 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_HANDFLOW))
1182 if (!(status = get_hand_flow(fd, (SERIAL_HANDFLOW*)lpOutBuffer)))
1183 sz = sizeof(SERIAL_HANDFLOW);
1185 else
1186 status = STATUS_INVALID_PARAMETER;
1187 break;
1188 case IOCTL_SERIAL_GET_LINE_CONTROL:
1189 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_LINE_CONTROL))
1191 if (!(status = get_line_control(fd, (SERIAL_LINE_CONTROL*)lpOutBuffer)))
1192 sz = sizeof(SERIAL_LINE_CONTROL);
1194 else
1195 status = STATUS_INVALID_PARAMETER;
1196 break;
1197 case IOCTL_SERIAL_GET_MODEMSTATUS:
1198 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1200 if (!(status = get_modem_status(fd, (DWORD*)lpOutBuffer)))
1201 sz = sizeof(DWORD);
1203 else status = STATUS_INVALID_PARAMETER;
1204 break;
1205 case IOCTL_SERIAL_GET_TIMEOUTS:
1206 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_TIMEOUTS))
1208 if (!(status = get_timeouts(hDevice, (SERIAL_TIMEOUTS*)lpOutBuffer)))
1209 sz = sizeof(SERIAL_TIMEOUTS);
1211 else
1212 status = STATUS_INVALID_PARAMETER;
1213 break;
1214 case IOCTL_SERIAL_GET_WAIT_MASK:
1215 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1217 if (!(status = get_wait_mask(hDevice, (DWORD*)lpOutBuffer)))
1218 sz = sizeof(DWORD);
1220 else
1221 status = STATUS_INVALID_PARAMETER;
1222 break;
1223 case IOCTL_SERIAL_IMMEDIATE_CHAR:
1224 if (lpInBuffer && nInBufferSize == sizeof(CHAR))
1225 status = xmit_immediate(hDevice, fd, lpInBuffer);
1226 else
1227 status = STATUS_INVALID_PARAMETER;
1228 break;
1229 case IOCTL_SERIAL_PURGE:
1230 if (lpInBuffer && nInBufferSize == sizeof(DWORD))
1231 status = purge(fd, *(DWORD*)lpInBuffer);
1232 else
1233 status = STATUS_INVALID_PARAMETER;
1234 break;
1235 case IOCTL_SERIAL_RESET_DEVICE:
1236 FIXME("Unsupported\n");
1237 break;
1238 case IOCTL_SERIAL_SET_BAUD_RATE:
1239 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_BAUD_RATE))
1240 status = set_baud_rate(fd, (const SERIAL_BAUD_RATE*)lpInBuffer);
1241 else
1242 status = STATUS_INVALID_PARAMETER;
1243 break;
1244 case IOCTL_SERIAL_SET_BREAK_OFF:
1245 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1246 if (ioctl(fd, TIOCCBRK, 0) == -1)
1248 TRACE("ioctl failed\n");
1249 status = FILE_GetNtStatus();
1251 #else
1252 FIXME("ioctl not available\n");
1253 status = STATUS_NOT_SUPPORTED;
1254 #endif
1255 break;
1256 case IOCTL_SERIAL_SET_BREAK_ON:
1257 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1258 if (ioctl(fd, TIOCSBRK, 0) == -1)
1260 TRACE("ioctl failed\n");
1261 status = FILE_GetNtStatus();
1263 #else
1264 FIXME("ioctl not available\n");
1265 status = STATUS_NOT_SUPPORTED;
1266 #endif
1267 break;
1268 case IOCTL_SERIAL_SET_CHARS:
1269 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_CHARS))
1270 status = set_special_chars(fd, (const SERIAL_CHARS*)lpInBuffer);
1271 else
1272 status = STATUS_INVALID_PARAMETER;
1273 break;
1274 case IOCTL_SERIAL_SET_DTR:
1275 #ifdef TIOCM_DTR
1276 if (whack_modem(fd, 0, TIOCM_DTR) == -1) status = FILE_GetNtStatus();
1277 #else
1278 status = STATUS_NOT_SUPPORTED;
1279 #endif
1280 break;
1281 case IOCTL_SERIAL_SET_HANDFLOW:
1282 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_HANDFLOW))
1283 status = set_handflow(fd, (const SERIAL_HANDFLOW*)lpInBuffer);
1284 else
1285 status = STATUS_INVALID_PARAMETER;
1286 break;
1287 case IOCTL_SERIAL_SET_LINE_CONTROL:
1288 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_LINE_CONTROL))
1289 status = set_line_control(fd, (const SERIAL_LINE_CONTROL*)lpInBuffer);
1290 else
1291 status = STATUS_INVALID_PARAMETER;
1292 break;
1293 case IOCTL_SERIAL_SET_QUEUE_SIZE:
1294 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_QUEUE_SIZE))
1295 status = set_queue_size(fd, (const SERIAL_QUEUE_SIZE*)lpInBuffer);
1296 else
1297 status = STATUS_INVALID_PARAMETER;
1298 break;
1299 case IOCTL_SERIAL_SET_RTS:
1300 #ifdef TIOCM_RTS
1301 if (whack_modem(fd, 0, TIOCM_RTS) == -1) status = FILE_GetNtStatus();
1302 #else
1303 status = STATUS_NOT_SUPPORTED;
1304 #endif
1305 break;
1306 case IOCTL_SERIAL_SET_TIMEOUTS:
1307 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_TIMEOUTS))
1308 status = set_timeouts(hDevice, fd, (const SERIAL_TIMEOUTS*)lpInBuffer);
1309 else
1310 status = STATUS_INVALID_PARAMETER;
1311 break;
1312 case IOCTL_SERIAL_SET_WAIT_MASK:
1313 if (lpInBuffer && nInBufferSize == sizeof(DWORD))
1315 status = set_wait_mask(hDevice, *(DWORD*)lpInBuffer);
1317 else status = STATUS_INVALID_PARAMETER;
1318 break;
1319 case IOCTL_SERIAL_SET_XOFF:
1320 status = set_XOff(fd);
1321 break;
1322 case IOCTL_SERIAL_SET_XON:
1323 status = set_XOn(fd);
1324 break;
1325 case IOCTL_SERIAL_WAIT_ON_MASK:
1326 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1328 if (!(status = wait_on(hDevice, fd, hEvent, (DWORD*)lpOutBuffer)))
1329 sz = sizeof(DWORD);
1331 else
1332 status = STATUS_INVALID_PARAMETER;
1333 break;
1334 default:
1335 FIXME("Unsupported IOCTL %x (type=%x access=%x func=%x meth=%x)\n",
1336 dwIoControlCode, dwIoControlCode >> 16, (dwIoControlCode >> 14) & 3,
1337 (dwIoControlCode >> 2) & 0xFFF, dwIoControlCode & 3);
1338 sz = 0;
1339 status = STATUS_INVALID_PARAMETER;
1340 break;
1342 if (needs_close) close( fd );
1343 error:
1344 piosb->u.Status = status;
1345 piosb->Information = sz;
1346 if (hEvent && status != STATUS_PENDING) NtSetEvent(hEvent, NULL);
1347 return status;
1350 NTSTATUS COMM_DeviceIoControl(HANDLE hDevice,
1351 HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
1352 PVOID UserApcContext,
1353 PIO_STATUS_BLOCK piosb,
1354 ULONG dwIoControlCode,
1355 LPVOID lpInBuffer, DWORD nInBufferSize,
1356 LPVOID lpOutBuffer, DWORD nOutBufferSize)
1358 NTSTATUS status;
1360 if (dwIoControlCode == IOCTL_SERIAL_WAIT_ON_MASK)
1362 HANDLE hev = hEvent;
1364 /* this is an ioctl we implement in a non blocking way if hEvent is not
1365 * null
1366 * so we have to explicitely wait if no hEvent is provided
1368 if (!hev)
1370 OBJECT_ATTRIBUTES attr;
1372 attr.Length = sizeof(attr);
1373 attr.RootDirectory = 0;
1374 attr.ObjectName = NULL;
1375 attr.Attributes = OBJ_CASE_INSENSITIVE | OBJ_OPENIF;
1376 attr.SecurityDescriptor = NULL;
1377 attr.SecurityQualityOfService = NULL;
1378 status = NtCreateEvent(&hev, EVENT_ALL_ACCESS, &attr, FALSE, FALSE);
1380 if (status) goto done;
1382 status = io_control(hDevice, hev, UserApcRoutine, UserApcContext,
1383 piosb, dwIoControlCode, lpInBuffer, nInBufferSize,
1384 lpOutBuffer, nOutBufferSize);
1385 if (hev != hEvent)
1387 if (status == STATUS_PENDING)
1389 NtWaitForSingleObject(hev, FALSE, NULL);
1390 status = STATUS_SUCCESS;
1392 NtClose(hev);
1395 else status = io_control(hDevice, hEvent, UserApcRoutine, UserApcContext,
1396 piosb, dwIoControlCode, lpInBuffer, nInBufferSize,
1397 lpOutBuffer, nOutBufferSize);
1398 done:
1399 return status;