shell32: In ParseDisplayName make use of shdocvw if the display name is not a drive...
[wine/hacks.git] / dlls / ntdll / serial.c
blobc8d3b29a8918a555754e6be2d612f1c101af6b38
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 #ifdef HAVE_ASM_TYPES_H
78 #include <asm/types.h>
79 #endif
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 = 0;
195 struct termios port;
197 if (tcgetattr(fd, &port) == -1)
199 ERR("tcgetattr error '%s'\n", strerror(errno));
200 return FILE_GetNtStatus();
202 /* termios does not support DTR/DSR flow control */
203 shf->ControlHandShake = 0;
204 shf->FlowReplace = 0;
205 #ifdef TIOCMGET
206 if (ioctl(fd, TIOCMGET, &stat) == -1)
208 WARN("ioctl error '%s'\n", strerror(errno));
209 shf->ControlHandShake |= SERIAL_DTR_CONTROL;
210 shf->FlowReplace |= SERIAL_RTS_CONTROL;
212 #else
213 WARN("Setting DTR/RTS to enabled by default\n");
214 shf->ControlHandShake |= SERIAL_DTR_CONTROL;
215 shf->FlowReplace |= SERIAL_RTS_CONTROL;
216 #endif
217 #ifdef TIOCM_DTR
218 if (stat & TIOCM_DTR)
219 #endif
220 shf->ControlHandShake |= SERIAL_DTR_CONTROL;
221 #ifdef CRTSCTS
222 if (port.c_cflag & CRTSCTS)
224 shf->FlowReplace |= SERIAL_RTS_CONTROL;
225 shf->ControlHandShake |= SERIAL_CTS_HANDSHAKE;
227 else
228 #endif
230 #ifdef TIOCM_RTS
231 if (stat & TIOCM_RTS)
232 #endif
233 shf->FlowReplace |= SERIAL_RTS_CONTROL;
235 if (port.c_iflag & IXOFF)
236 shf->FlowReplace |= SERIAL_AUTO_RECEIVE;
237 if (port.c_iflag & IXON)
238 shf->FlowReplace |= SERIAL_AUTO_TRANSMIT;
240 shf->XonLimit = 10;
241 shf->XoffLimit = 10;
242 return STATUS_SUCCESS;
245 static NTSTATUS get_line_control(int fd, SERIAL_LINE_CONTROL* slc)
247 struct termios port;
249 if (tcgetattr(fd, &port) == -1)
251 ERR("tcgetattr error '%s'\n", strerror(errno));
252 return FILE_GetNtStatus();
255 #ifdef CMSPAR
256 switch (port.c_cflag & (PARENB | PARODD | CMSPAR))
257 #else
258 switch (port.c_cflag & (PARENB | PARODD))
259 #endif
261 case 0: slc->Parity = NOPARITY; break;
262 case PARENB: slc->Parity = EVENPARITY; break;
263 case PARENB|PARODD: slc->Parity = ODDPARITY; break;
264 #ifdef CMSPAR
265 case PARENB|CMSPAR: slc->Parity = MARKPARITY; break;
266 case PARENB|PARODD|CMSPAR: slc->Parity = SPACEPARITY; break;
267 #endif
269 switch (port.c_cflag & CSIZE)
271 case CS5: slc->WordLength = 5; break;
272 case CS6: slc->WordLength = 6; break;
273 case CS7: slc->WordLength = 7; break;
274 case CS8: slc->WordLength = 8; break;
275 default: ERR("unknown size %x\n", (UINT)(port.c_cflag & CSIZE));
278 if (port.c_cflag & CSTOPB)
280 if (slc->WordLength == 5)
281 slc->StopBits = ONE5STOPBITS;
282 else
283 slc->StopBits = TWOSTOPBITS;
285 else
286 slc->StopBits = ONESTOPBIT;
288 return STATUS_SUCCESS;
291 static NTSTATUS get_modem_status(int fd, DWORD* lpModemStat)
293 NTSTATUS status = STATUS_NOT_SUPPORTED;
294 int mstat;
296 *lpModemStat = 0;
297 #ifdef TIOCMGET
298 if (!ioctl(fd, TIOCMGET, &mstat))
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 " : "");
318 return STATUS_SUCCESS;
320 WARN("ioctl failed\n");
321 status = FILE_GetNtStatus();
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 = wine_server_obj_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 = wine_server_obj_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 |= IXOFF;
616 else
617 port.c_iflag &= ~IXOFF;
618 if (shf->FlowReplace & SERIAL_AUTO_TRANSMIT)
619 port.c_iflag |= IXON;
620 else
621 port.c_iflag &= ~IXON;
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;
655 * on FreeBSD, turning off ICANON does not disable IEXTEN,
656 * so we must turn it off explicitly. No harm done on Linux.
658 port.c_lflag &= ~(ICANON|ECHO|ISIG|IEXTEN);
659 port.c_lflag |= NOFLSH;
661 bytesize = slc->WordLength;
662 stopbits = slc->StopBits;
664 #ifdef CMSPAR
665 port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
666 #else
667 port.c_cflag &= ~(PARENB | PARODD);
668 #endif
670 /* make sure that reads don't block */
671 port.c_cc[VMIN] = 0;
672 port.c_cc[VTIME] = 0;
674 switch (slc->Parity)
676 case NOPARITY: port.c_iflag &= ~INPCK; break;
677 case ODDPARITY: port.c_cflag |= PARENB | PARODD; break;
678 case EVENPARITY: port.c_cflag |= PARENB; break;
679 #ifdef CMSPAR
680 /* Linux defines mark/space (stick) parity */
681 case MARKPARITY: port.c_cflag |= PARENB | CMSPAR; break;
682 case SPACEPARITY: port.c_cflag |= PARENB | PARODD | CMSPAR; break;
683 #else
684 /* try the POSIX way */
685 case MARKPARITY:
686 if (slc->StopBits == ONESTOPBIT)
688 stopbits = TWOSTOPBITS;
689 port.c_iflag &= ~INPCK;
691 else
693 ERR("Cannot set MARK Parity\n");
694 return STATUS_NOT_SUPPORTED;
696 break;
697 case SPACEPARITY:
698 if (slc->WordLength < 8)
700 bytesize +=1;
701 port.c_iflag &= ~INPCK;
703 else
705 ERR("Cannot set SPACE Parity\n");
706 return STATUS_NOT_SUPPORTED;
708 break;
709 #endif
710 default:
711 ERR("Parity\n");
712 return STATUS_NOT_SUPPORTED;
715 port.c_cflag &= ~CSIZE;
716 switch (bytesize)
718 case 5: port.c_cflag |= CS5; break;
719 case 6: port.c_cflag |= CS6; break;
720 case 7: port.c_cflag |= CS7; break;
721 case 8: port.c_cflag |= CS8; break;
722 default:
723 ERR("ByteSize\n");
724 return STATUS_NOT_SUPPORTED;
727 switch (stopbits)
729 case ONESTOPBIT: port.c_cflag &= ~CSTOPB; break;
730 case ONE5STOPBITS: /* will be selected if bytesize is 5 */
731 case TWOSTOPBITS: port.c_cflag |= CSTOPB; break;
732 default:
733 ERR("StopBits\n");
734 return STATUS_NOT_SUPPORTED;
736 /* otherwise it hangs with pending input*/
737 if (tcsetattr(fd, TCSANOW, &port) == -1)
739 ERR("tcsetattr error '%s'\n", strerror(errno));
740 return FILE_GetNtStatus();
742 return STATUS_SUCCESS;
745 static NTSTATUS set_queue_size(int fd, const SERIAL_QUEUE_SIZE* sqs)
747 FIXME("insize %d outsize %d unimplemented stub\n", sqs->InSize, sqs->OutSize);
748 return STATUS_SUCCESS;
751 static NTSTATUS set_special_chars(int fd, const SERIAL_CHARS* sc)
753 struct termios port;
755 if (tcgetattr(fd, &port) == -1)
757 ERR("tcgetattr error '%s'\n", strerror(errno));
758 return FILE_GetNtStatus();
761 port.c_cc[VEOF ] = sc->EofChar;
762 /* FIXME: sc->ErrorChar is not supported */
763 /* FIXME: sc->BreakChar is not supported */
764 /* FIXME: sc->EventChar is not supported */
765 port.c_cc[VSTART] = sc->XonChar;
766 port.c_cc[VSTOP ] = sc->XoffChar;
768 if (tcsetattr(fd, TCSANOW, &port) == -1)
770 ERR("tcsetattr error '%s'\n", strerror(errno));
771 return FILE_GetNtStatus();
773 return STATUS_SUCCESS;
776 static NTSTATUS set_timeouts(HANDLE handle, const SERIAL_TIMEOUTS* st)
778 NTSTATUS status;
780 SERVER_START_REQ( set_serial_info )
782 req->handle = wine_server_obj_handle( handle );
783 req->flags = SERIALINFO_SET_TIMEOUTS;
784 req->readinterval = st->ReadIntervalTimeout ;
785 req->readmult = st->ReadTotalTimeoutMultiplier ;
786 req->readconst = st->ReadTotalTimeoutConstant ;
787 req->writemult = st->WriteTotalTimeoutMultiplier ;
788 req->writeconst = st->WriteTotalTimeoutConstant ;
789 status = wine_server_call( req );
791 SERVER_END_REQ;
792 return status;
795 static NTSTATUS set_wait_mask(HANDLE hDevice, DWORD mask)
797 NTSTATUS status;
799 SERVER_START_REQ( set_serial_info )
801 req->handle = wine_server_obj_handle( hDevice );
802 req->flags = SERIALINFO_SET_MASK;
803 req->eventmask = mask;
804 status = wine_server_call( req );
806 SERVER_END_REQ;
807 return status;
811 * does not change IXOFF but simulates that IXOFF has been received:
813 static NTSTATUS set_XOff(int fd)
815 if (tcflow(fd, TCOOFF))
817 return FILE_GetNtStatus();
819 return STATUS_SUCCESS;
823 * does not change IXON but simulates that IXON has been received:
825 static NTSTATUS set_XOn(int fd)
827 if (tcflow(fd, TCOON))
829 return FILE_GetNtStatus();
831 return STATUS_SUCCESS;
834 /* serial_irq_info
835 * local structure holding the irq values we need for WaitCommEvent()
837 * Stripped down from struct serial_icounter_struct, which may not be available on some systems
838 * As the modem line interrupts (cts, dsr, rng, dcd) only get updated with TIOCMIWAIT active,
839 * no need to carry them in the internal structure
842 typedef struct serial_irq_info
844 int rx , tx, frame, overrun, parity, brk, buf_overrun;
845 }serial_irq_info;
847 /***********************************************************************
848 * Data needed by the thread polling for the changing CommEvent
850 typedef struct async_commio
852 HANDLE hDevice;
853 DWORD* events;
854 HANDLE hEvent;
855 DWORD evtmask;
856 DWORD mstat;
857 serial_irq_info irq_info;
858 } async_commio;
860 /***********************************************************************
861 * Get extended interrupt count info, needed for wait_on
863 static NTSTATUS get_irq_info(int fd, serial_irq_info *irq_info)
865 NTSTATUS status = STATUS_NOT_IMPLEMENTED;
866 #ifdef TIOCGICOUNT
867 struct serial_icounter_struct einfo;
868 if (!ioctl(fd, TIOCGICOUNT, &einfo))
870 irq_info->rx = einfo.rx;
871 irq_info->tx = einfo.tx;
872 irq_info->frame = einfo.frame;
873 irq_info->overrun = einfo.overrun;
874 irq_info->parity = einfo.parity;
875 irq_info->brk = einfo.brk;
876 irq_info->buf_overrun = einfo.buf_overrun;
877 return STATUS_SUCCESS;
879 TRACE("TIOCGICOUNT err %s\n", strerror(errno));
880 status = FILE_GetNtStatus();
881 #endif
882 memset(irq_info,0, sizeof(serial_irq_info));
883 return status;
887 static DWORD check_events(int fd, DWORD mask,
888 const serial_irq_info *new,
889 const serial_irq_info *old,
890 DWORD new_mstat, DWORD old_mstat)
892 DWORD ret = 0, queue;
894 TRACE("mask 0x%08x\n", mask);
895 TRACE("old->rx 0x%08x vs. new->rx 0x%08x\n", old->rx, new->rx);
896 TRACE("old->tx 0x%08x vs. new->tx 0x%08x\n", old->tx, new->tx);
897 TRACE("old->frame 0x%08x vs. new->frame 0x%08x\n", old->frame, new->frame);
898 TRACE("old->overrun 0x%08x vs. new->overrun 0x%08x\n", old->overrun, new->overrun);
899 TRACE("old->parity 0x%08x vs. new->parity 0x%08x\n", old->parity, new->parity);
900 TRACE("old->brk 0x%08x vs. new->brk 0x%08x\n", old->brk, new->brk);
901 TRACE("old->buf_overrun 0x%08x vs. new->buf_overrun 0x%08x\n", old->buf_overrun, new->buf_overrun);
903 if (old->brk != new->brk) ret |= EV_BREAK;
904 if ((old_mstat & MS_CTS_ON ) != (new_mstat & MS_CTS_ON )) ret |= EV_CTS;
905 if ((old_mstat & MS_DSR_ON ) != (new_mstat & MS_DSR_ON )) ret |= EV_DSR;
906 if ((old_mstat & MS_RING_ON) != (new_mstat & MS_RING_ON)) ret |= EV_RING;
907 if ((old_mstat & MS_RLSD_ON) != (new_mstat & MS_RLSD_ON)) ret |= EV_RLSD;
908 if (old->frame != new->frame || old->overrun != new->overrun || old->parity != new->parity) ret |= EV_ERR;
909 if (mask & EV_RXCHAR)
911 queue = 0;
912 #ifdef TIOCINQ
913 if (ioctl(fd, TIOCINQ, &queue))
914 WARN("TIOCINQ returned error\n");
915 #endif
916 if (queue)
917 ret |= EV_RXCHAR;
919 if (mask & EV_TXEMPTY)
921 queue = 0;
922 /* We really want to know when all characters have gone out of the transmitter */
923 #if defined(TIOCSERGETLSR)
924 if (ioctl(fd, TIOCSERGETLSR, &queue))
925 WARN("TIOCSERGETLSR returned error\n");
926 if (queue)
927 /* TIOCOUTQ only checks for an empty buffer */
928 #elif defined(TIOCOUTQ)
929 if (ioctl(fd, TIOCOUTQ, &queue))
930 WARN("TIOCOUTQ returned error\n");
931 if (!queue)
932 #endif
933 ret |= EV_TXEMPTY;
934 TRACE("OUTQUEUE %d, Transmitter %sempty\n",
935 queue, (ret & EV_TXEMPTY) ? "" : "not ");
937 return ret & mask;
940 /***********************************************************************
941 * wait_for_event (INTERNAL)
943 * We need to poll for what is interesting
944 * TIOCMIWAIT only checks modem status line and may not be aborted by a changing mask
947 static DWORD CALLBACK wait_for_event(LPVOID arg)
949 async_commio *commio = (async_commio*) arg;
950 int fd, needs_close;
952 if (!server_get_unix_fd( commio->hDevice, FILE_READ_DATA | FILE_WRITE_DATA, &fd, &needs_close, NULL, NULL ))
954 serial_irq_info new_irq_info;
955 DWORD new_mstat, new_evtmask;
956 LARGE_INTEGER time;
958 TRACE("device=%p fd=0x%08x mask=0x%08x buffer=%p event=%p irq_info=%p\n",
959 commio->hDevice, fd, commio->evtmask, commio->events, commio->hEvent, &commio->irq_info);
961 time.QuadPart = (ULONGLONG)10000;
962 time.QuadPart = -time.QuadPart;
963 for (;;)
966 * TIOCMIWAIT is not adequate
968 * FIXME:
969 * We don't handle the EV_RXFLAG (the eventchar)
971 NtDelayExecution(FALSE, &time);
972 get_irq_info(fd, &new_irq_info);
973 if (get_modem_status(fd, &new_mstat))
974 TRACE("get_modem_status failed\n");
975 *commio->events = check_events(fd, commio->evtmask,
976 &new_irq_info, &commio->irq_info,
977 new_mstat, commio->mstat);
978 if (*commio->events) break;
979 get_wait_mask(commio->hDevice, &new_evtmask);
980 if (commio->evtmask != new_evtmask)
982 *commio->events = 0;
983 break;
986 if (needs_close) close( fd );
988 if (commio->hEvent) NtSetEvent(commio->hEvent, NULL);
989 RtlFreeHeap(GetProcessHeap(), 0, commio);
990 return 0;
993 static NTSTATUS wait_on(HANDLE hDevice, int fd, HANDLE hEvent, DWORD* events)
995 async_commio* commio;
996 NTSTATUS status;
998 if ((status = NtResetEvent(hEvent, NULL)))
999 return status;
1001 commio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof (async_commio));
1002 if (!commio) return STATUS_NO_MEMORY;
1004 commio->hDevice = hDevice;
1005 commio->events = events;
1006 commio->hEvent = hEvent;
1007 get_wait_mask(commio->hDevice, &commio->evtmask);
1009 /* We may never return, if some capabilities miss
1010 * Return error in that case
1012 #if !defined(TIOCINQ)
1013 if (commio->evtmask & EV_RXCHAR)
1014 goto error_caps;
1015 #endif
1016 #if !(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)
1017 if (commio->evtmask & EV_TXEMPTY)
1018 goto error_caps;
1019 #endif
1020 #if !defined(TIOCMGET)
1021 if (commio->evtmask & (EV_CTS | EV_DSR| EV_RING| EV_RLSD))
1022 goto error_caps;
1023 #endif
1024 #if !defined(TIOCM_CTS)
1025 if (commio->evtmask & EV_CTS)
1026 goto error_caps;
1027 #endif
1028 #if !defined(TIOCM_DSR)
1029 if (commio->evtmask & EV_DSR)
1030 goto error_caps;
1031 #endif
1032 #if !defined(TIOCM_RNG)
1033 if (commio->evtmask & EV_RING)
1034 goto error_caps;
1035 #endif
1036 #if !defined(TIOCM_CAR)
1037 if (commio->evtmask & EV_RLSD)
1038 goto error_caps;
1039 #endif
1040 if (commio->evtmask & EV_RXFLAG)
1041 FIXME("EV_RXFLAG not handled\n");
1043 if ((status = get_irq_info(fd, &commio->irq_info)) &&
1044 (commio->evtmask & (EV_BREAK | EV_ERR)))
1045 goto out_now;
1047 if ((status = get_modem_status(fd, &commio->mstat)) &&
1048 (commio->evtmask & (EV_CTS | EV_DSR| EV_RING| EV_RLSD)))
1049 goto out_now;
1051 /* We might have received something or the TX buffer is delivered */
1052 *events = check_events(fd, commio->evtmask,
1053 &commio->irq_info, &commio->irq_info,
1054 commio->mstat, commio->mstat);
1055 if (*events)
1057 status = STATUS_SUCCESS;
1058 goto out_now;
1061 /* create the worker for the task */
1062 status = RtlQueueWorkItem(wait_for_event, commio, 0 /* FIXME */);
1063 if (status != STATUS_SUCCESS) goto out_now;
1064 return STATUS_PENDING;
1066 #if !defined(TIOCINQ) || (!(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)) || !defined(TIOCMGET) || !defined(TIOCM_CTS) ||!defined(TIOCM_DSR) || !defined(TIOCM_RNG) || !defined(TIOCM_CAR)
1067 error_caps:
1068 FIXME("Returning error because of missing capabilities\n");
1069 status = STATUS_INVALID_PARAMETER;
1070 #endif
1071 out_now:
1072 RtlFreeHeap(GetProcessHeap(), 0, commio);
1073 return status;
1076 static NTSTATUS xmit_immediate(HANDLE hDevice, int fd, const char* ptr)
1078 /* FIXME: not perfect as it should bypass the in-queue */
1079 WARN("(%p,'%c') not perfect!\n", hDevice, *ptr);
1080 if (write(fd, ptr, 1) != 1)
1081 return FILE_GetNtStatus();
1082 return STATUS_SUCCESS;
1085 /******************************************************************
1086 * COMM_DeviceIoControl
1090 static inline NTSTATUS io_control(HANDLE hDevice,
1091 HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
1092 PVOID UserApcContext,
1093 PIO_STATUS_BLOCK piosb,
1094 ULONG dwIoControlCode,
1095 LPVOID lpInBuffer, DWORD nInBufferSize,
1096 LPVOID lpOutBuffer, DWORD nOutBufferSize)
1098 DWORD sz = 0, access = FILE_READ_DATA;
1099 NTSTATUS status = STATUS_SUCCESS;
1100 int fd = -1, needs_close = 0;
1102 TRACE("%p %s %p %d %p %d %p\n",
1103 hDevice, iocode2str(dwIoControlCode), lpInBuffer, nInBufferSize,
1104 lpOutBuffer, nOutBufferSize, piosb);
1106 piosb->Information = 0;
1108 if (dwIoControlCode != IOCTL_SERIAL_GET_TIMEOUTS &&
1109 dwIoControlCode != IOCTL_SERIAL_SET_TIMEOUTS)
1110 if ((status = server_get_unix_fd( hDevice, access, &fd, &needs_close, NULL, NULL )))
1111 goto error;
1113 switch (dwIoControlCode)
1115 case IOCTL_SERIAL_CLR_DTR:
1116 #ifdef TIOCM_DTR
1117 if (whack_modem(fd, ~TIOCM_DTR, 0) == -1) status = FILE_GetNtStatus();
1118 #else
1119 status = STATUS_NOT_SUPPORTED;
1120 #endif
1121 break;
1122 case IOCTL_SERIAL_CLR_RTS:
1123 #ifdef TIOCM_RTS
1124 if (whack_modem(fd, ~TIOCM_RTS, 0) == -1) status = FILE_GetNtStatus();
1125 #else
1126 status = STATUS_NOT_SUPPORTED;
1127 #endif
1128 break;
1129 case IOCTL_SERIAL_GET_BAUD_RATE:
1130 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_BAUD_RATE))
1132 if (!(status = get_baud_rate(fd, (SERIAL_BAUD_RATE*)lpOutBuffer)))
1133 sz = sizeof(SERIAL_BAUD_RATE);
1135 else
1136 status = STATUS_INVALID_PARAMETER;
1137 break;
1138 case IOCTL_SERIAL_GET_CHARS:
1139 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_CHARS))
1141 if (!(status = get_special_chars(fd, (SERIAL_CHARS*)lpOutBuffer)))
1142 sz = sizeof(SERIAL_CHARS);
1144 else
1145 status = STATUS_INVALID_PARAMETER;
1146 break;
1147 case IOCTL_SERIAL_GET_COMMSTATUS:
1148 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_STATUS))
1150 if (!(status = get_status(fd, (SERIAL_STATUS*)lpOutBuffer)))
1151 sz = sizeof(SERIAL_STATUS);
1153 else status = STATUS_INVALID_PARAMETER;
1154 break;
1155 case IOCTL_SERIAL_GET_HANDFLOW:
1156 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_HANDFLOW))
1158 if (!(status = get_hand_flow(fd, (SERIAL_HANDFLOW*)lpOutBuffer)))
1159 sz = sizeof(SERIAL_HANDFLOW);
1161 else
1162 status = STATUS_INVALID_PARAMETER;
1163 break;
1164 case IOCTL_SERIAL_GET_LINE_CONTROL:
1165 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_LINE_CONTROL))
1167 if (!(status = get_line_control(fd, (SERIAL_LINE_CONTROL*)lpOutBuffer)))
1168 sz = sizeof(SERIAL_LINE_CONTROL);
1170 else
1171 status = STATUS_INVALID_PARAMETER;
1172 break;
1173 case IOCTL_SERIAL_GET_MODEMSTATUS:
1174 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1176 if (!(status = get_modem_status(fd, (DWORD*)lpOutBuffer)))
1177 sz = sizeof(DWORD);
1179 else status = STATUS_INVALID_PARAMETER;
1180 break;
1181 case IOCTL_SERIAL_GET_TIMEOUTS:
1182 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_TIMEOUTS))
1184 if (!(status = get_timeouts(hDevice, (SERIAL_TIMEOUTS*)lpOutBuffer)))
1185 sz = sizeof(SERIAL_TIMEOUTS);
1187 else
1188 status = STATUS_INVALID_PARAMETER;
1189 break;
1190 case IOCTL_SERIAL_GET_WAIT_MASK:
1191 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1193 if (!(status = get_wait_mask(hDevice, (DWORD*)lpOutBuffer)))
1194 sz = sizeof(DWORD);
1196 else
1197 status = STATUS_INVALID_PARAMETER;
1198 break;
1199 case IOCTL_SERIAL_IMMEDIATE_CHAR:
1200 if (lpInBuffer && nInBufferSize == sizeof(CHAR))
1201 status = xmit_immediate(hDevice, fd, lpInBuffer);
1202 else
1203 status = STATUS_INVALID_PARAMETER;
1204 break;
1205 case IOCTL_SERIAL_PURGE:
1206 if (lpInBuffer && nInBufferSize == sizeof(DWORD))
1207 status = purge(fd, *(DWORD*)lpInBuffer);
1208 else
1209 status = STATUS_INVALID_PARAMETER;
1210 break;
1211 case IOCTL_SERIAL_RESET_DEVICE:
1212 FIXME("Unsupported\n");
1213 break;
1214 case IOCTL_SERIAL_SET_BAUD_RATE:
1215 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_BAUD_RATE))
1216 status = set_baud_rate(fd, (const SERIAL_BAUD_RATE*)lpInBuffer);
1217 else
1218 status = STATUS_INVALID_PARAMETER;
1219 break;
1220 case IOCTL_SERIAL_SET_BREAK_OFF:
1221 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1222 if (ioctl(fd, TIOCCBRK, 0) == -1)
1224 TRACE("ioctl failed\n");
1225 status = FILE_GetNtStatus();
1227 #else
1228 FIXME("ioctl not available\n");
1229 status = STATUS_NOT_SUPPORTED;
1230 #endif
1231 break;
1232 case IOCTL_SERIAL_SET_BREAK_ON:
1233 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1234 if (ioctl(fd, TIOCSBRK, 0) == -1)
1236 TRACE("ioctl failed\n");
1237 status = FILE_GetNtStatus();
1239 #else
1240 FIXME("ioctl not available\n");
1241 status = STATUS_NOT_SUPPORTED;
1242 #endif
1243 break;
1244 case IOCTL_SERIAL_SET_CHARS:
1245 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_CHARS))
1246 status = set_special_chars(fd, (const SERIAL_CHARS*)lpInBuffer);
1247 else
1248 status = STATUS_INVALID_PARAMETER;
1249 break;
1250 case IOCTL_SERIAL_SET_DTR:
1251 #ifdef TIOCM_DTR
1252 if (whack_modem(fd, 0, TIOCM_DTR) == -1) status = FILE_GetNtStatus();
1253 #else
1254 status = STATUS_NOT_SUPPORTED;
1255 #endif
1256 break;
1257 case IOCTL_SERIAL_SET_HANDFLOW:
1258 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_HANDFLOW))
1259 status = set_handflow(fd, (const SERIAL_HANDFLOW*)lpInBuffer);
1260 else
1261 status = STATUS_INVALID_PARAMETER;
1262 break;
1263 case IOCTL_SERIAL_SET_LINE_CONTROL:
1264 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_LINE_CONTROL))
1265 status = set_line_control(fd, (const SERIAL_LINE_CONTROL*)lpInBuffer);
1266 else
1267 status = STATUS_INVALID_PARAMETER;
1268 break;
1269 case IOCTL_SERIAL_SET_QUEUE_SIZE:
1270 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_QUEUE_SIZE))
1271 status = set_queue_size(fd, (const SERIAL_QUEUE_SIZE*)lpInBuffer);
1272 else
1273 status = STATUS_INVALID_PARAMETER;
1274 break;
1275 case IOCTL_SERIAL_SET_RTS:
1276 #ifdef TIOCM_RTS
1277 if (whack_modem(fd, 0, TIOCM_RTS) == -1) status = FILE_GetNtStatus();
1278 #else
1279 status = STATUS_NOT_SUPPORTED;
1280 #endif
1281 break;
1282 case IOCTL_SERIAL_SET_TIMEOUTS:
1283 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_TIMEOUTS))
1284 status = set_timeouts(hDevice, (const SERIAL_TIMEOUTS*)lpInBuffer);
1285 else
1286 status = STATUS_INVALID_PARAMETER;
1287 break;
1288 case IOCTL_SERIAL_SET_WAIT_MASK:
1289 if (lpInBuffer && nInBufferSize == sizeof(DWORD))
1291 status = set_wait_mask(hDevice, *(DWORD*)lpInBuffer);
1293 else status = STATUS_INVALID_PARAMETER;
1294 break;
1295 case IOCTL_SERIAL_SET_XOFF:
1296 status = set_XOff(fd);
1297 break;
1298 case IOCTL_SERIAL_SET_XON:
1299 status = set_XOn(fd);
1300 break;
1301 case IOCTL_SERIAL_WAIT_ON_MASK:
1302 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1304 if (!(status = wait_on(hDevice, fd, hEvent, (DWORD*)lpOutBuffer)))
1305 sz = sizeof(DWORD);
1307 else
1308 status = STATUS_INVALID_PARAMETER;
1309 break;
1310 default:
1311 FIXME("Unsupported IOCTL %x (type=%x access=%x func=%x meth=%x)\n",
1312 dwIoControlCode, dwIoControlCode >> 16, (dwIoControlCode >> 14) & 3,
1313 (dwIoControlCode >> 2) & 0xFFF, dwIoControlCode & 3);
1314 sz = 0;
1315 status = STATUS_INVALID_PARAMETER;
1316 break;
1318 if (needs_close) close( fd );
1319 error:
1320 piosb->u.Status = status;
1321 piosb->Information = sz;
1322 if (hEvent && status != STATUS_PENDING) NtSetEvent(hEvent, NULL);
1323 return status;
1326 NTSTATUS COMM_DeviceIoControl(HANDLE hDevice,
1327 HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
1328 PVOID UserApcContext,
1329 PIO_STATUS_BLOCK piosb,
1330 ULONG dwIoControlCode,
1331 LPVOID lpInBuffer, DWORD nInBufferSize,
1332 LPVOID lpOutBuffer, DWORD nOutBufferSize)
1334 NTSTATUS status;
1336 if (dwIoControlCode == IOCTL_SERIAL_WAIT_ON_MASK)
1338 HANDLE hev = hEvent;
1340 /* this is an ioctl we implement in a non blocking way if hEvent is not
1341 * null
1342 * so we have to explicitly wait if no hEvent is provided
1344 if (!hev)
1346 OBJECT_ATTRIBUTES attr;
1348 attr.Length = sizeof(attr);
1349 attr.RootDirectory = 0;
1350 attr.ObjectName = NULL;
1351 attr.Attributes = OBJ_CASE_INSENSITIVE | OBJ_OPENIF;
1352 attr.SecurityDescriptor = NULL;
1353 attr.SecurityQualityOfService = NULL;
1354 status = NtCreateEvent(&hev, EVENT_ALL_ACCESS, &attr, FALSE, FALSE);
1356 if (status) goto done;
1358 status = io_control(hDevice, hev, UserApcRoutine, UserApcContext,
1359 piosb, dwIoControlCode, lpInBuffer, nInBufferSize,
1360 lpOutBuffer, nOutBufferSize);
1361 if (hev != hEvent)
1363 if (status == STATUS_PENDING)
1365 NtWaitForSingleObject(hev, FALSE, NULL);
1366 status = STATUS_SUCCESS;
1368 NtClose(hev);
1371 else status = io_control(hDevice, hEvent, UserApcRoutine, UserApcContext,
1372 piosb, dwIoControlCode, lpInBuffer, nInBufferSize,
1373 lpOutBuffer, nOutBufferSize);
1374 done:
1375 return status;