new 818051de2c8769029049ce3d36c6b856f47496c9
[wine/hacks.git] / dlls / ntdll / serial.c
blob6b2e7646a39d1c63e112d71c14dd2fc5744cac07
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 break;
263 #endif
265 switch (port.c_cflag & CSIZE)
267 case CS5: slc->WordLength = 5; break;
268 case CS6: slc->WordLength = 6; break;
269 case CS7: slc->WordLength = 7; break;
270 case CS8: slc->WordLength = 8; break;
271 default: ERR("unknown size %x\n", (UINT)(port.c_cflag & CSIZE));
274 if (port.c_cflag & CSTOPB)
276 if (slc->WordLength == 5)
277 slc->StopBits = ONE5STOPBITS;
278 else
279 slc->StopBits = TWOSTOPBITS;
281 else
282 slc->StopBits = ONESTOPBIT;
284 return STATUS_SUCCESS;
287 static NTSTATUS get_modem_status(int fd, DWORD* lpModemStat)
289 NTSTATUS status = STATUS_SUCCESS;
290 int mstat;
292 #ifdef TIOCMGET
293 if (ioctl(fd, TIOCMGET, &mstat) == -1)
295 WARN("ioctl failed\n");
296 status = FILE_GetNtStatus();
298 else
300 *lpModemStat = 0;
301 #ifdef TIOCM_CTS
302 if (mstat & TIOCM_CTS) *lpModemStat |= MS_CTS_ON;
303 #endif
304 #ifdef TIOCM_DSR
305 if (mstat & TIOCM_DSR) *lpModemStat |= MS_DSR_ON;
306 #endif
307 #ifdef TIOCM_RNG
308 if (mstat & TIOCM_RNG) *lpModemStat |= MS_RING_ON;
309 #endif
310 #ifdef TIOCM_CAR
311 /* FIXME: Not really sure about RLSD UB 990810 */
312 if (mstat & TIOCM_CAR) *lpModemStat |= MS_RLSD_ON;
313 #endif
314 TRACE("%04x -> %s%s%s%s\n", mstat,
315 (*lpModemStat & MS_RLSD_ON) ? "MS_RLSD_ON " : "",
316 (*lpModemStat & MS_RING_ON) ? "MS_RING_ON " : "",
317 (*lpModemStat & MS_DSR_ON) ? "MS_DSR_ON " : "",
318 (*lpModemStat & MS_CTS_ON) ? "MS_CTS_ON " : "");
320 #else
321 status = STATUS_NOT_SUPPORTED;
322 #endif
323 return status;
326 static NTSTATUS get_special_chars(int fd, SERIAL_CHARS* sc)
328 struct termios port;
330 if (tcgetattr(fd, &port) == -1)
332 ERR("tcgetattr error '%s'\n", strerror(errno));
333 return FILE_GetNtStatus();
335 sc->EofChar = port.c_cc[VEOF];
336 sc->ErrorChar = 0xFF;
337 sc->BreakChar = 0; /* FIXME */
338 sc->EventChar = 0; /* FIXME */
339 sc->XonChar = port.c_cc[VSTART];
340 sc->XoffChar = port.c_cc[VSTOP];
342 return STATUS_SUCCESS;
345 static NTSTATUS get_status(int fd, SERIAL_STATUS* ss)
347 NTSTATUS status = STATUS_SUCCESS;
349 ss->Errors = 0;
350 ss->HoldReasons = 0;
351 ss->EofReceived = FALSE;
352 ss->WaitForImmediate = FALSE;
353 #ifdef TIOCOUTQ
354 if (ioctl(fd, TIOCOUTQ, &ss->AmountInOutQueue) == -1)
356 WARN("ioctl returned error\n");
357 status = FILE_GetNtStatus();
359 #else
360 ss->AmountInOutQueue = 0; /* FIXME: find a different way to find out */
361 #endif
363 #ifdef TIOCINQ
364 if (ioctl(fd, TIOCINQ, &ss->AmountInInQueue))
366 WARN("ioctl returned error\n");
367 status = FILE_GetNtStatus();
369 #else
370 ss->AmountInInQueue = 0; /* FIXME: find a different way to find out */
371 #endif
372 return status;
375 static NTSTATUS get_timeouts(HANDLE handle, SERIAL_TIMEOUTS* st)
377 NTSTATUS status;
378 SERVER_START_REQ( get_serial_info )
380 req->handle = handle;
381 if (!(status = wine_server_call( req )))
383 st->ReadIntervalTimeout = reply->readinterval;
384 st->ReadTotalTimeoutMultiplier = reply->readmult;
385 st->ReadTotalTimeoutConstant = reply->readconst;
386 st->WriteTotalTimeoutMultiplier = reply->writemult;
387 st->WriteTotalTimeoutConstant = reply->writeconst;
390 SERVER_END_REQ;
391 return status;
394 static NTSTATUS get_wait_mask(HANDLE hDevice, DWORD* mask)
396 NTSTATUS status;
398 SERVER_START_REQ( get_serial_info )
400 req->handle = hDevice;
401 if (!(status = wine_server_call( req )))
402 *mask = reply->eventmask;
404 SERVER_END_REQ;
405 return status;
408 static NTSTATUS purge(int fd, DWORD flags)
411 ** not exactly sure how these are different
412 ** Perhaps if we had our own internal queues, one flushes them
413 ** and the other flushes the kernel's buffers.
415 if (flags & PURGE_TXABORT) tcflush(fd, TCOFLUSH);
416 if (flags & PURGE_RXABORT) tcflush(fd, TCIFLUSH);
417 if (flags & PURGE_TXCLEAR) tcflush(fd, TCOFLUSH);
418 if (flags & PURGE_RXCLEAR) tcflush(fd, TCIFLUSH);
419 return STATUS_SUCCESS;
422 static NTSTATUS set_baud_rate(int fd, const SERIAL_BAUD_RATE* sbr)
424 struct termios port;
426 if (tcgetattr(fd, &port) == -1)
428 ERR("tcgetattr error '%s'\n", strerror(errno));
429 return FILE_GetNtStatus();
432 #ifdef CBAUD
433 port.c_cflag &= ~CBAUD;
434 switch (sbr->BaudRate)
436 case 0: port.c_cflag |= B0; break;
437 case 50: port.c_cflag |= B50; break;
438 case 75: port.c_cflag |= B75; break;
439 case 110:
440 case CBR_110: port.c_cflag |= B110; break;
441 case 134: port.c_cflag |= B134; break;
442 case 150: port.c_cflag |= B150; break;
443 case 200: port.c_cflag |= B200; break;
444 case 300:
445 case CBR_300: port.c_cflag |= B300; break;
446 case 600:
447 case CBR_600: port.c_cflag |= B600; break;
448 case 1200:
449 case CBR_1200: port.c_cflag |= B1200; break;
450 case 1800: port.c_cflag |= B1800; break;
451 case 2400:
452 case CBR_2400: port.c_cflag |= B2400; break;
453 case 4800:
454 case CBR_4800: port.c_cflag |= B4800; break;
455 case 9600:
456 case CBR_9600: port.c_cflag |= B9600; break;
457 case 19200:
458 case CBR_19200: port.c_cflag |= B19200; break;
459 case 38400:
460 case CBR_38400: port.c_cflag |= B38400; break;
461 #ifdef B57600
462 case 57600: port.c_cflag |= B57600; break;
463 #endif
464 #ifdef B115200
465 case 115200: port.c_cflag |= B115200;break;
466 #endif
467 #ifdef B230400
468 case 230400: port.c_cflag |= B230400;break;
469 #endif
470 #ifdef B460800
471 case 460800: port.c_cflag |= B460800;break;
472 #endif
473 default:
474 #if defined (HAVE_LINUX_SERIAL_H) && defined (TIOCSSERIAL)
476 struct serial_struct nuts;
477 int arby;
479 ioctl(fd, TIOCGSERIAL, &nuts);
480 nuts.custom_divisor = nuts.baud_base / sbr->BaudRate;
481 if (!(nuts.custom_divisor)) nuts.custom_divisor = 1;
482 arby = nuts.baud_base / nuts.custom_divisor;
483 nuts.flags &= ~ASYNC_SPD_MASK;
484 nuts.flags |= ASYNC_SPD_CUST;
485 WARN("You (or a program acting at your behest) have specified\n"
486 "a non-standard baud rate %d. Wine will set the rate to %d,\n"
487 "which is as close as we can get by our present understanding of your\n"
488 "hardware. I hope you know what you are doing. Any disruption Wine\n"
489 "has caused to your linux system can be undone with setserial \n"
490 "(see man setserial). If you have incapacitated a Hayes type modem,\n"
491 "reset it and it will probably recover.\n", sbr->BaudRate, arby);
492 ioctl(fd, TIOCSSERIAL, &nuts);
493 port.c_cflag |= B38400;
495 break;
496 #else /* Don't have linux/serial.h or lack TIOCSSERIAL */
497 ERR("baudrate %d\n", sbr->BaudRate);
498 return STATUS_NOT_SUPPORTED;
499 #endif /* Don't have linux/serial.h or lack TIOCSSERIAL */
501 #elif !defined(__EMX__)
502 switch (sbr->BaudRate)
504 case 0: port.c_ospeed = B0; break;
505 case 50: port.c_ospeed = B50; break;
506 case 75: port.c_ospeed = B75; break;
507 case 110:
508 case CBR_110: port.c_ospeed = B110; break;
509 case 134: port.c_ospeed = B134; break;
510 case 150: port.c_ospeed = B150; break;
511 case 200: port.c_ospeed = B200; break;
512 case 300:
513 case CBR_300: port.c_ospeed = B300; break;
514 case 600:
515 case CBR_600: port.c_ospeed = B600; break;
516 case 1200:
517 case CBR_1200: port.c_ospeed = B1200; break;
518 case 1800: port.c_ospeed = B1800; break;
519 case 2400:
520 case CBR_2400: port.c_ospeed = B2400; break;
521 case 4800:
522 case CBR_4800: port.c_ospeed = B4800; break;
523 case 9600:
524 case CBR_9600: port.c_ospeed = B9600; break;
525 case 19200:
526 case CBR_19200: port.c_ospeed = B19200; break;
527 case 38400:
528 case CBR_38400: port.c_ospeed = B38400; break;
529 #ifdef B57600
530 case 57600:
531 case CBR_57600: port.c_cflag |= B57600; break;
532 #endif
533 #ifdef B115200
534 case 115200:
535 case CBR_115200: port.c_cflag |= B115200;break;
536 #endif
537 #ifdef B230400
538 case 230400: port.c_cflag |= B230400;break;
539 #endif
540 #ifdef B460800
541 case 460800: port.c_cflag |= B460800;break;
542 #endif
543 default:
544 ERR("baudrate %d\n", sbr->BaudRate);
545 return STATUS_NOT_SUPPORTED;
547 port.c_ispeed = port.c_ospeed;
548 #endif
549 if (tcsetattr(fd, TCSANOW, &port) == -1)
551 ERR("tcsetattr error '%s'\n", strerror(errno));
552 return FILE_GetNtStatus();
554 return STATUS_SUCCESS;
557 static int whack_modem(int fd, unsigned int andy, unsigned int orrie)
559 #ifdef TIOCMGET
560 unsigned int mstat, okay;
561 okay = ioctl(fd, TIOCMGET, &mstat);
562 if (okay) return okay;
563 if (andy) mstat &= andy;
564 mstat |= orrie;
565 return ioctl(fd, TIOCMSET, &mstat);
566 #else
567 return 0;
568 #endif
571 static NTSTATUS set_handflow(int fd, const SERIAL_HANDFLOW* shf)
573 struct termios port;
575 if ((shf->FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE)) ==
576 (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE))
577 return STATUS_NOT_SUPPORTED;
579 if (tcgetattr(fd, &port) == -1)
581 ERR("tcgetattr error '%s'\n", strerror(errno));
582 return FILE_GetNtStatus();
585 #ifdef CRTSCTS
586 if ((shf->ControlHandShake & SERIAL_CTS_HANDSHAKE) ||
587 (shf->FlowReplace & SERIAL_RTS_HANDSHAKE))
589 port.c_cflag |= CRTSCTS;
590 TRACE("CRTSCTS\n");
592 else
593 port.c_cflag &= ~CRTSCTS;
594 #endif
595 #ifdef TIOCM_DTR
596 if (shf->ControlHandShake & SERIAL_DTR_HANDSHAKE)
598 WARN("DSR/DTR flow control not supported\n");
599 } else if (!(shf->ControlHandShake & SERIAL_DTR_CONTROL))
600 whack_modem(fd, ~TIOCM_DTR, 0);
601 else
602 whack_modem(fd, 0, TIOCM_DTR);
603 #endif
604 #ifdef TIOCM_RTS
605 if (!(shf->ControlHandShake & SERIAL_CTS_HANDSHAKE))
607 if ((shf->FlowReplace & (SERIAL_RTS_CONTROL|SERIAL_RTS_HANDSHAKE)) == 0)
608 whack_modem(fd, ~TIOCM_RTS, 0);
609 else
610 whack_modem(fd, 0, TIOCM_RTS);
612 #endif
614 if (shf->FlowReplace & SERIAL_AUTO_RECEIVE)
615 port.c_iflag |= IXON;
616 else
617 port.c_iflag &= ~IXON;
618 if (shf->FlowReplace & SERIAL_AUTO_TRANSMIT)
619 port.c_iflag |= IXOFF;
620 else
621 port.c_iflag &= ~IXOFF;
622 if (tcsetattr(fd, TCSANOW, &port) == -1)
624 ERR("tcsetattr error '%s'\n", strerror(errno));
625 return FILE_GetNtStatus();
628 return STATUS_SUCCESS;
631 static NTSTATUS set_line_control(int fd, const SERIAL_LINE_CONTROL* slc)
633 struct termios port;
634 unsigned bytesize, stopbits;
636 if (tcgetattr(fd, &port) == -1)
638 ERR("tcgetattr error '%s'\n", strerror(errno));
639 return FILE_GetNtStatus();
642 #ifdef IMAXBEL
643 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK|IMAXBEL);
644 #else
645 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK);
646 #endif
647 port.c_iflag |= IGNBRK | INPCK;
649 port.c_oflag &= ~(OPOST);
651 port.c_cflag &= ~(HUPCL);
652 port.c_cflag |= CLOCAL | CREAD;
654 port.c_lflag &= ~(ICANON|ECHO|ISIG);
655 port.c_lflag |= NOFLSH;
657 bytesize = slc->WordLength;
658 stopbits = slc->StopBits;
660 #ifdef CMSPAR
661 port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
662 #else
663 port.c_cflag &= ~(PARENB | PARODD);
664 #endif
666 switch (slc->Parity)
668 case NOPARITY: port.c_iflag &= ~INPCK; break;
669 case ODDPARITY: port.c_cflag |= PARENB | PARODD; break;
670 case EVENPARITY: port.c_cflag |= PARENB; break;
671 #ifdef CMSPAR
672 /* Linux defines mark/space (stick) parity */
673 case MARKPARITY: port.c_cflag |= PARENB | CMSPAR; break;
674 case SPACEPARITY: port.c_cflag |= PARENB | PARODD | CMSPAR; break;
675 #else
676 /* try the POSIX way */
677 case MARKPARITY:
678 if (slc->StopBits == ONESTOPBIT)
680 stopbits = TWOSTOPBITS;
681 port.c_iflag &= ~INPCK;
683 else
685 ERR("Cannot set MARK Parity\n");
686 return STATUS_NOT_SUPPORTED;
688 break;
689 case SPACEPARITY:
690 if (slc->WordLength < 8)
692 bytesize +=1;
693 port.c_iflag &= ~INPCK;
695 else
697 ERR("Cannot set SPACE Parity\n");
698 return STATUS_NOT_SUPPORTED;
700 break;
701 #endif
702 default:
703 ERR("Parity\n");
704 return STATUS_NOT_SUPPORTED;
707 port.c_cflag &= ~CSIZE;
708 switch (bytesize)
710 case 5: port.c_cflag |= CS5; break;
711 case 6: port.c_cflag |= CS6; break;
712 case 7: port.c_cflag |= CS7; break;
713 case 8: port.c_cflag |= CS8; break;
714 default:
715 ERR("ByteSize\n");
716 return STATUS_NOT_SUPPORTED;
719 switch (stopbits)
721 case ONESTOPBIT: port.c_cflag &= ~CSTOPB; break;
722 case ONE5STOPBITS: /* will be selected if bytesize is 5 */
723 case TWOSTOPBITS: port.c_cflag |= CSTOPB; break;
724 default:
725 ERR("StopBits\n");
726 return STATUS_NOT_SUPPORTED;
728 /* otherwise it hangs with pending input*/
729 if (tcsetattr(fd, TCSANOW, &port) == -1)
731 ERR("tcsetattr error '%s'\n", strerror(errno));
732 return FILE_GetNtStatus();
734 return STATUS_SUCCESS;
737 static NTSTATUS set_queue_size(int fd, const SERIAL_QUEUE_SIZE* sqs)
739 FIXME("insize %d outsize %d unimplemented stub\n", sqs->InSize, sqs->OutSize);
740 return STATUS_SUCCESS;
743 static NTSTATUS set_special_chars(int fd, const SERIAL_CHARS* sc)
745 struct termios port;
747 if (tcgetattr(fd, &port) == -1)
749 ERR("tcgetattr error '%s'\n", strerror(errno));
750 return FILE_GetNtStatus();
753 port.c_cc[VMIN ] = 0;
754 port.c_cc[VTIME ] = 1;
756 port.c_cc[VEOF ] = sc->EofChar;
757 /* FIXME: sc->ErrorChar is not supported */
758 /* FIXME: sc->BreakChar is not supported */
759 /* FIXME: sc->EventChar is not supported */
760 port.c_cc[VSTART] = sc->XonChar;
761 port.c_cc[VSTOP ] = sc->XoffChar;
763 if (tcsetattr(fd, TCSANOW, &port) == -1)
765 ERR("tcsetattr error '%s'\n", strerror(errno));
766 return FILE_GetNtStatus();
768 return STATUS_SUCCESS;
771 static NTSTATUS set_timeouts(HANDLE handle, int fd, const SERIAL_TIMEOUTS* st)
773 NTSTATUS status;
774 struct termios port;
775 unsigned int ux_timeout;
777 SERVER_START_REQ( set_serial_info )
779 req->handle = handle;
780 req->flags = SERIALINFO_SET_TIMEOUTS;
781 req->readinterval = st->ReadIntervalTimeout ;
782 req->readmult = st->ReadTotalTimeoutMultiplier ;
783 req->readconst = st->ReadTotalTimeoutConstant ;
784 req->writemult = st->WriteTotalTimeoutMultiplier ;
785 req->writeconst = st->WriteTotalTimeoutConstant ;
786 status = wine_server_call( req );
788 SERVER_END_REQ;
789 if (status) return status;
791 if (tcgetattr(fd, &port) == -1)
793 FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
794 return FILE_GetNtStatus();
797 /* VTIME is in 1/10 seconds */
798 if (st->ReadIntervalTimeout == 0) /* 0 means no timeout */
799 ux_timeout = 0;
800 else
802 ux_timeout = (st->ReadIntervalTimeout + 99) / 100;
803 if (ux_timeout == 0)
804 ux_timeout = 1; /* must be at least some timeout */
806 port.c_cc[VTIME] = ux_timeout;
808 if (tcsetattr(fd, 0, &port) == -1)
810 FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
811 return FILE_GetNtStatus();
813 return STATUS_SUCCESS;
816 static NTSTATUS set_wait_mask(HANDLE hDevice, DWORD mask)
818 NTSTATUS status;
820 SERVER_START_REQ( set_serial_info )
822 req->handle = hDevice;
823 req->flags = SERIALINFO_SET_MASK;
824 req->eventmask = mask;
825 status = wine_server_call( req );
827 SERVER_END_REQ;
828 return status;
831 static NTSTATUS set_XOff(int fd)
833 struct termios port;
835 if (tcgetattr(fd,&port) == -1)
837 FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
838 return FILE_GetNtStatus();
842 port.c_iflag |= IXOFF;
843 if (tcsetattr(fd, TCSADRAIN, &port) == -1)
845 FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
846 return FILE_GetNtStatus();
848 return STATUS_SUCCESS;
851 static NTSTATUS set_XOn(int fd)
853 struct termios port;
855 if (tcgetattr(fd,&port) == -1)
857 FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
858 return FILE_GetNtStatus();
860 port.c_iflag |= IXON;
861 if (tcsetattr(fd, TCSADRAIN, &port) == -1)
863 FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
864 return FILE_GetNtStatus();
866 return STATUS_SUCCESS;
869 /* serial_irq_info
870 * local structure holding the irq values we need for WaitCommEvent()
872 * Stripped down from struct serial_icounter_struct, which may not be available on some systems
873 * As the modem line interrupts (cts, dsr, rng, dcd) only get updated with TIOCMIWAIT active,
874 * no need to carry them in the internal structure
877 typedef struct serial_irq_info
879 int rx , tx, frame, overrun, parity, brk, buf_overrun;
880 }serial_irq_info;
882 /***********************************************************************
883 * Data needed by the thread polling for the changing CommEvent
885 typedef struct async_commio
887 HANDLE hDevice;
888 DWORD* events;
889 HANDLE hEvent;
890 DWORD evtmask;
891 DWORD mstat;
892 serial_irq_info irq_info;
893 } async_commio;
895 /***********************************************************************
896 * Get extended interrupt count info, needed for wait_on
898 static NTSTATUS get_irq_info(int fd, serial_irq_info *irq_info)
900 #ifdef TIOCGICOUNT
901 struct serial_icounter_struct einfo;
902 if (!ioctl(fd, TIOCGICOUNT, &einfo))
904 irq_info->rx = einfo.rx;
905 irq_info->tx = einfo.tx;
906 irq_info->frame = einfo.frame;
907 irq_info->overrun = einfo.overrun;
908 irq_info->parity = einfo.parity;
909 irq_info->brk = einfo.brk;
910 irq_info->buf_overrun = einfo.buf_overrun;
911 return STATUS_SUCCESS;
913 TRACE("TIOCGICOUNT err %s\n", strerror(errno));
914 return FILE_GetNtStatus();
915 #else
916 memset(irq_info,0, sizeof(serial_irq_info));
917 return STATUS_NOT_IMPLEMENTED;
918 #endif
922 static DWORD WINAPI check_events(int fd, DWORD mask,
923 const serial_irq_info *new,
924 const serial_irq_info *old,
925 DWORD new_mstat, DWORD old_mstat)
927 DWORD ret = 0, queue;
929 TRACE("mask 0x%08x\n", mask);
930 TRACE("old->rx 0x%08x vs. new->rx 0x%08x\n", old->rx, new->rx);
931 TRACE("old->tx 0x%08x vs. new->tx 0x%08x\n", old->tx, new->tx);
932 TRACE("old->frame 0x%08x vs. new->frame 0x%08x\n", old->frame, new->frame);
933 TRACE("old->overrun 0x%08x vs. new->overrun 0x%08x\n", old->overrun, new->overrun);
934 TRACE("old->parity 0x%08x vs. new->parity 0x%08x\n", old->parity, new->parity);
935 TRACE("old->brk 0x%08x vs. new->brk 0x%08x\n", old->brk, new->brk);
936 TRACE("old->buf_overrun 0x%08x vs. new->buf_overrun 0x%08x\n", old->buf_overrun, new->buf_overrun);
938 if (old->brk != new->brk) ret |= EV_BREAK;
939 if ((old_mstat & MS_CTS_ON ) != (new_mstat & MS_CTS_ON )) ret |= EV_CTS;
940 if ((old_mstat & MS_DSR_ON ) != (new_mstat & MS_DSR_ON )) ret |= EV_DSR;
941 if ((old_mstat & MS_RING_ON) != (new_mstat & MS_RING_ON)) ret |= EV_RING;
942 if ((old_mstat & MS_RLSD_ON) != (new_mstat & MS_RLSD_ON)) ret |= EV_RLSD;
943 if (old->frame != new->frame || old->overrun != new->overrun || old->parity != new->parity) ret |= EV_ERR;
944 if (mask & EV_RXCHAR)
946 queue = 0;
947 #ifdef TIOCINQ
948 if (ioctl(fd, TIOCINQ, &queue))
949 WARN("TIOCINQ returned error\n");
950 #endif
951 if (queue)
952 ret |= EV_RXCHAR;
954 if (mask & EV_TXEMPTY)
956 queue = 0;
957 /* We really want to know when all characters have gone out of the transmitter */
958 #if defined(TIOCSERGETLSR)
959 if (ioctl(fd, TIOCSERGETLSR, &queue))
960 WARN("TIOCSERGETLSR returned error\n");
961 if (queue)
962 /* TIOCOUTQ only checks for an empty buffer */
963 #elif defined(TIOCOUTQ)
964 if (ioctl(fd, TIOCOUTQ, &queue))
965 WARN("TIOCOUTQ returned error\n");
966 if (!queue)
967 #endif
968 ret |= EV_TXEMPTY;
969 TRACE("OUTQUEUE %d, Transmitter %sempty\n",
970 queue, (ret & EV_TXEMPTY) ? "" : "not ");
972 return ret & mask;
975 /***********************************************************************
976 * wait_for_event (INTERNAL)
978 * We need to poll for what is interesting
979 * TIOCMIWAIT only checks modem status line and may not be aborted by a changing mask
982 static DWORD CALLBACK wait_for_event(LPVOID arg)
984 async_commio *commio = (async_commio*) arg;
985 int fd, needs_close;
987 if (!server_get_unix_fd( commio->hDevice, FILE_READ_DATA | FILE_WRITE_DATA, &fd, &needs_close, NULL, NULL ))
989 serial_irq_info new_irq_info;
990 DWORD new_mstat, new_evtmask;
991 LARGE_INTEGER time;
993 TRACE("device=%p fd=0x%08x mask=0x%08x buffer=%p event=%p irq_info=%p\n",
994 commio->hDevice, fd, commio->evtmask, commio->events, commio->hEvent, &commio->irq_info);
996 time.QuadPart = (ULONGLONG)10000;
997 time.QuadPart = -time.QuadPart;
998 for (;;)
1001 * TIOCMIWAIT is not adequate
1003 * FIXME:
1004 * We don't handle the EV_RXFLAG (the eventchar)
1006 NtDelayExecution(FALSE, &time);
1007 get_irq_info(fd, &new_irq_info);
1008 if (get_modem_status(fd, &new_mstat))
1009 TRACE("get_modem_status failed\n");
1010 *commio->events = check_events(fd, commio->evtmask,
1011 &new_irq_info, &commio->irq_info,
1012 new_mstat, commio->mstat);
1013 if (*commio->events) break;
1014 get_wait_mask(commio->hDevice, &new_evtmask);
1015 if (commio->evtmask != new_evtmask)
1017 *commio->events = 0;
1018 break;
1021 if (needs_close) close( fd );
1023 if (commio->hEvent) NtSetEvent(commio->hEvent, NULL);
1024 RtlFreeHeap(GetProcessHeap(), 0, commio);
1025 return 0;
1028 static NTSTATUS wait_on(HANDLE hDevice, int fd, HANDLE hEvent, DWORD* events)
1030 async_commio* commio;
1031 NTSTATUS status;
1033 if ((status = NtResetEvent(hEvent, NULL)))
1034 return status;
1036 commio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof (async_commio));
1037 if (!commio) return STATUS_NO_MEMORY;
1039 commio->hDevice = hDevice;
1040 commio->events = events;
1041 commio->hEvent = hEvent;
1042 get_wait_mask(commio->hDevice, &commio->evtmask);
1044 /* We may never return, if some capabilities miss
1045 * Return error in that case
1047 #if !defined(TIOCINQ)
1048 if (commio->evtmask & EV_RXCHAR)
1049 goto error_caps;
1050 #endif
1051 #if !(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)
1052 if (commio->evtmask & EV_TXEMPTY)
1053 goto error_caps;
1054 #endif
1055 #if !defined(TIOCMGET)
1056 if (commio->evtmask & (EV_CTS | EV_DSR| EV_RING| EV_RLSD))
1057 goto error_caps;
1058 #endif
1059 #if !defined(TIOCM_CTS)
1060 if (commio->evtmask & EV_CTS)
1061 goto error_caps;
1062 #endif
1063 #if !defined(TIOCM_DSR)
1064 if (commio->evtmask & EV_DSR)
1065 goto error_caps;
1066 #endif
1067 #if !defined(TIOCM_RNG)
1068 if (commio->evtmask & EV_RING)
1069 goto error_caps;
1070 #endif
1071 #if !defined(TIOCM_CAR)
1072 if (commio->evtmask & EV_RLSD)
1073 goto error_caps;
1074 #endif
1075 if (commio->evtmask & EV_RXFLAG)
1076 FIXME("EV_RXFLAG not handled\n");
1077 if ((status = get_irq_info(fd, &commio->irq_info)) ||
1078 (status = get_modem_status(fd, &commio->mstat)))
1079 goto out_now;
1081 /* We might have received something or the TX bufffer is delivered */
1082 *events = check_events(fd, commio->evtmask,
1083 &commio->irq_info, &commio->irq_info,
1084 commio->mstat, commio->mstat);
1085 if (*events) goto out_now;
1087 /* create the worker for the task */
1088 status = RtlQueueWorkItem(wait_for_event, commio, 0 /* FIXME */);
1089 if (status != STATUS_SUCCESS) goto out_now;
1090 return STATUS_PENDING;
1092 #if !defined(TIOCINQ) || (!(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)) || !defined(TIOCMGET) || !defined(TIOCM_CTS) ||!defined(TIOCM_DSR) || !defined(TIOCM_RNG) || !defined(TIOCM_CAR)
1093 error_caps:
1094 FIXME("Returning error because of missing capabilities\n");
1095 status = STATUS_INVALID_PARAMETER;
1096 #endif
1097 out_now:
1098 RtlFreeHeap(GetProcessHeap(), 0, commio);
1099 return status;
1102 static NTSTATUS xmit_immediate(HANDLE hDevice, int fd, const char* ptr)
1104 /* FIXME: not perfect as it should bypass the in-queue */
1105 WARN("(%p,'%c') not perfect!\n", hDevice, *ptr);
1106 if (write(fd, ptr, 1) != 1)
1107 return FILE_GetNtStatus();
1108 return STATUS_SUCCESS;
1111 /******************************************************************
1112 * COMM_DeviceIoControl
1116 static inline NTSTATUS io_control(HANDLE hDevice,
1117 HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
1118 PVOID UserApcContext,
1119 PIO_STATUS_BLOCK piosb,
1120 ULONG dwIoControlCode,
1121 LPVOID lpInBuffer, DWORD nInBufferSize,
1122 LPVOID lpOutBuffer, DWORD nOutBufferSize)
1124 DWORD sz = 0, access = FILE_READ_DATA;
1125 NTSTATUS status = STATUS_SUCCESS;
1126 int fd = -1, needs_close = 0;
1128 TRACE("%p %s %p %d %p %d %p\n",
1129 hDevice, iocode2str(dwIoControlCode), lpInBuffer, nInBufferSize,
1130 lpOutBuffer, nOutBufferSize, piosb);
1132 piosb->Information = 0;
1134 if (dwIoControlCode != IOCTL_SERIAL_GET_TIMEOUTS)
1135 if ((status = server_get_unix_fd( hDevice, access, &fd, &needs_close, NULL, NULL )))
1136 goto error;
1138 switch (dwIoControlCode)
1140 case IOCTL_SERIAL_CLR_DTR:
1141 #ifdef TIOCM_DTR
1142 if (whack_modem(fd, ~TIOCM_DTR, 0) == -1) status = FILE_GetNtStatus();
1143 #else
1144 status = STATUS_NOT_SUPPORTED;
1145 #endif
1146 break;
1147 case IOCTL_SERIAL_CLR_RTS:
1148 #ifdef TIOCM_RTS
1149 if (whack_modem(fd, ~TIOCM_RTS, 0) == -1) status = FILE_GetNtStatus();
1150 #else
1151 status = STATUS_NOT_SUPPORTED;
1152 #endif
1153 break;
1154 case IOCTL_SERIAL_GET_BAUD_RATE:
1155 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_BAUD_RATE))
1157 if (!(status = get_baud_rate(fd, (SERIAL_BAUD_RATE*)lpOutBuffer)))
1158 sz = sizeof(SERIAL_BAUD_RATE);
1160 else
1161 status = STATUS_INVALID_PARAMETER;
1162 break;
1163 case IOCTL_SERIAL_GET_CHARS:
1164 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_CHARS))
1166 if (!(status = get_special_chars(fd, (SERIAL_CHARS*)lpOutBuffer)))
1167 sz = sizeof(SERIAL_CHARS);
1169 else
1170 status = STATUS_INVALID_PARAMETER;
1171 break;
1172 case IOCTL_SERIAL_GET_COMMSTATUS:
1173 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_STATUS))
1175 if (!(status = get_status(fd, (SERIAL_STATUS*)lpOutBuffer)))
1176 sz = sizeof(SERIAL_STATUS);
1178 else status = STATUS_INVALID_PARAMETER;
1179 break;
1180 case IOCTL_SERIAL_GET_HANDFLOW:
1181 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_HANDFLOW))
1183 if (!(status = get_hand_flow(fd, (SERIAL_HANDFLOW*)lpOutBuffer)))
1184 sz = sizeof(SERIAL_HANDFLOW);
1186 else
1187 status = STATUS_INVALID_PARAMETER;
1188 break;
1189 case IOCTL_SERIAL_GET_LINE_CONTROL:
1190 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_LINE_CONTROL))
1192 if (!(status = get_line_control(fd, (SERIAL_LINE_CONTROL*)lpOutBuffer)))
1193 sz = sizeof(SERIAL_LINE_CONTROL);
1195 else
1196 status = STATUS_INVALID_PARAMETER;
1197 break;
1198 case IOCTL_SERIAL_GET_MODEMSTATUS:
1199 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1201 if (!(status = get_modem_status(fd, (DWORD*)lpOutBuffer)))
1202 sz = sizeof(DWORD);
1204 else status = STATUS_INVALID_PARAMETER;
1205 break;
1206 case IOCTL_SERIAL_GET_TIMEOUTS:
1207 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_TIMEOUTS))
1209 if (!(status = get_timeouts(hDevice, (SERIAL_TIMEOUTS*)lpOutBuffer)))
1210 sz = sizeof(SERIAL_TIMEOUTS);
1212 else
1213 status = STATUS_INVALID_PARAMETER;
1214 break;
1215 case IOCTL_SERIAL_GET_WAIT_MASK:
1216 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1218 if (!(status = get_wait_mask(hDevice, (DWORD*)lpOutBuffer)))
1219 sz = sizeof(DWORD);
1221 else
1222 status = STATUS_INVALID_PARAMETER;
1223 break;
1224 case IOCTL_SERIAL_IMMEDIATE_CHAR:
1225 if (lpInBuffer && nInBufferSize == sizeof(CHAR))
1226 status = xmit_immediate(hDevice, fd, lpInBuffer);
1227 else
1228 status = STATUS_INVALID_PARAMETER;
1229 break;
1230 case IOCTL_SERIAL_PURGE:
1231 if (lpInBuffer && nInBufferSize == sizeof(DWORD))
1232 status = purge(fd, *(DWORD*)lpInBuffer);
1233 else
1234 status = STATUS_INVALID_PARAMETER;
1235 break;
1236 case IOCTL_SERIAL_RESET_DEVICE:
1237 FIXME("Unsupported\n");
1238 break;
1239 case IOCTL_SERIAL_SET_BAUD_RATE:
1240 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_BAUD_RATE))
1241 status = set_baud_rate(fd, (const SERIAL_BAUD_RATE*)lpInBuffer);
1242 else
1243 status = STATUS_INVALID_PARAMETER;
1244 break;
1245 case IOCTL_SERIAL_SET_BREAK_OFF:
1246 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1247 if (ioctl(fd, TIOCCBRK, 0) == -1)
1249 TRACE("ioctl failed\n");
1250 status = FILE_GetNtStatus();
1252 #else
1253 FIXME("ioctl not available\n");
1254 status = STATUS_NOT_SUPPORTED;
1255 #endif
1256 break;
1257 case IOCTL_SERIAL_SET_BREAK_ON:
1258 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1259 if (ioctl(fd, TIOCSBRK, 0) == -1)
1261 TRACE("ioctl failed\n");
1262 status = FILE_GetNtStatus();
1264 #else
1265 FIXME("ioctl not available\n");
1266 status = STATUS_NOT_SUPPORTED;
1267 #endif
1268 break;
1269 case IOCTL_SERIAL_SET_CHARS:
1270 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_CHARS))
1271 status = set_special_chars(fd, (const SERIAL_CHARS*)lpInBuffer);
1272 else
1273 status = STATUS_INVALID_PARAMETER;
1274 break;
1275 case IOCTL_SERIAL_SET_DTR:
1276 #ifdef TIOCM_DTR
1277 if (whack_modem(fd, 0, TIOCM_DTR) == -1) status = FILE_GetNtStatus();
1278 #else
1279 status = STATUS_NOT_SUPPORTED;
1280 #endif
1281 break;
1282 case IOCTL_SERIAL_SET_HANDFLOW:
1283 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_HANDFLOW))
1284 status = set_handflow(fd, (const SERIAL_HANDFLOW*)lpInBuffer);
1285 else
1286 status = STATUS_INVALID_PARAMETER;
1287 break;
1288 case IOCTL_SERIAL_SET_LINE_CONTROL:
1289 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_LINE_CONTROL))
1290 status = set_line_control(fd, (const SERIAL_LINE_CONTROL*)lpInBuffer);
1291 else
1292 status = STATUS_INVALID_PARAMETER;
1293 break;
1294 case IOCTL_SERIAL_SET_QUEUE_SIZE:
1295 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_QUEUE_SIZE))
1296 status = set_queue_size(fd, (const SERIAL_QUEUE_SIZE*)lpInBuffer);
1297 else
1298 status = STATUS_INVALID_PARAMETER;
1299 break;
1300 case IOCTL_SERIAL_SET_RTS:
1301 #ifdef TIOCM_RTS
1302 if (whack_modem(fd, 0, TIOCM_RTS) == -1) status = FILE_GetNtStatus();
1303 #else
1304 status = STATUS_NOT_SUPPORTED;
1305 #endif
1306 break;
1307 case IOCTL_SERIAL_SET_TIMEOUTS:
1308 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_TIMEOUTS))
1309 status = set_timeouts(hDevice, fd, (const SERIAL_TIMEOUTS*)lpInBuffer);
1310 else
1311 status = STATUS_INVALID_PARAMETER;
1312 break;
1313 case IOCTL_SERIAL_SET_WAIT_MASK:
1314 if (lpInBuffer && nInBufferSize == sizeof(DWORD))
1316 status = set_wait_mask(hDevice, *(DWORD*)lpInBuffer);
1318 else status = STATUS_INVALID_PARAMETER;
1319 break;
1320 case IOCTL_SERIAL_SET_XOFF:
1321 status = set_XOff(fd);
1322 break;
1323 case IOCTL_SERIAL_SET_XON:
1324 status = set_XOn(fd);
1325 break;
1326 case IOCTL_SERIAL_WAIT_ON_MASK:
1327 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1329 if (!(status = wait_on(hDevice, fd, hEvent, (DWORD*)lpOutBuffer)))
1330 sz = sizeof(DWORD);
1332 else
1333 status = STATUS_INVALID_PARAMETER;
1334 break;
1335 default:
1336 FIXME("Unsupported IOCTL %x (type=%x access=%x func=%x meth=%x)\n",
1337 dwIoControlCode, dwIoControlCode >> 16, (dwIoControlCode >> 14) & 3,
1338 (dwIoControlCode >> 2) & 0xFFF, dwIoControlCode & 3);
1339 sz = 0;
1340 status = STATUS_INVALID_PARAMETER;
1341 break;
1343 if (needs_close) close( fd );
1344 error:
1345 piosb->u.Status = status;
1346 piosb->Information = sz;
1347 if (hEvent && status != STATUS_PENDING) NtSetEvent(hEvent, NULL);
1348 return status;
1351 NTSTATUS COMM_DeviceIoControl(HANDLE hDevice,
1352 HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
1353 PVOID UserApcContext,
1354 PIO_STATUS_BLOCK piosb,
1355 ULONG dwIoControlCode,
1356 LPVOID lpInBuffer, DWORD nInBufferSize,
1357 LPVOID lpOutBuffer, DWORD nOutBufferSize)
1359 NTSTATUS status;
1361 if (dwIoControlCode == IOCTL_SERIAL_WAIT_ON_MASK)
1363 HANDLE hev = hEvent;
1365 /* this is an ioctl we implement in a non blocking way if hEvent is not
1366 * null
1367 * so we have to explicitely wait if no hEvent is provided
1369 if (!hev)
1371 OBJECT_ATTRIBUTES attr;
1373 attr.Length = sizeof(attr);
1374 attr.RootDirectory = 0;
1375 attr.ObjectName = NULL;
1376 attr.Attributes = OBJ_CASE_INSENSITIVE | OBJ_OPENIF;
1377 attr.SecurityDescriptor = NULL;
1378 attr.SecurityQualityOfService = NULL;
1379 status = NtCreateEvent(&hev, EVENT_ALL_ACCESS, &attr, FALSE, FALSE);
1381 if (status) goto done;
1383 status = io_control(hDevice, hev, UserApcRoutine, UserApcContext,
1384 piosb, dwIoControlCode, lpInBuffer, nInBufferSize,
1385 lpOutBuffer, nOutBufferSize);
1386 if (hev != hEvent)
1388 if (status == STATUS_PENDING)
1390 NtWaitForSingleObject(hev, FALSE, NULL);
1391 status = STATUS_SUCCESS;
1393 NtClose(hev);
1396 else status = io_control(hDevice, hEvent, UserApcRoutine, UserApcContext,
1397 piosb, dwIoControlCode, lpInBuffer, nInBufferSize,
1398 lpOutBuffer, nOutBufferSize);
1399 done:
1400 return status;