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
23 #include "wine/port.h"
46 #ifdef HAVE_SYS_STAT_H
47 # include <sys/stat.h>
49 #include <sys/types.h>
50 #ifdef HAVE_SYS_FILIO_H
51 # include <sys/filio.h>
53 #ifdef HAVE_SYS_IOCTL_H
54 #include <sys/ioctl.h>
56 #ifdef HAVE_SYS_POLL_H
57 # include <sys/poll.h>
59 #ifdef HAVE_SYS_MODEM_H
60 # include <sys/modem.h>
62 #ifdef HAVE_SYS_STRTIO_H
63 # include <sys/strtio.h>
66 #define NONAMELESSUNION
67 #define NONAMELESSSTRUCT
69 #define WIN32_NO_STATUS
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>
83 #if !defined(TIOCINQ) && defined(FIONREAD)
84 #define TIOCINQ FIONREAD
87 WINE_DEFAULT_DEBUG_CHANNEL(comm
);
89 static const char* iocode2str(DWORD 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
);
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
)
141 if (tcgetattr(fd
, &port
) == -1)
143 ERR("tcgetattr error '%s'\n", strerror(errno
));
144 return FILE_GetNtStatus();
148 speed
= port
.c_cflag
& CBAUD
;
150 speed
= cfgetospeed(&port
);
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;
171 case B57600
: sbr
->BaudRate
= 57600; break;
174 case B115200
: sbr
->BaudRate
= 115200; break;
177 case B230400
: sbr
->BaudRate
= 230400; break;
180 case B460800
: sbr
->BaudRate
= 460800; break;
183 ERR("unknown speed %x\n", speed
);
184 return STATUS_INVALID_PARAMETER
;
187 return STATUS_INVALID_PARAMETER
;
189 return STATUS_SUCCESS
;
192 static NTSTATUS
get_hand_flow(int fd
, SERIAL_HANDFLOW
* shf
)
197 if (tcgetattr(fd
, &port
) == -1)
199 ERR("tcgetattr error '%s'\n", strerror(errno
));
200 return FILE_GetNtStatus();
203 if (ioctl(fd
, TIOCMGET
, &stat
) == -1)
205 WARN("ioctl error '%s'\n", strerror(errno
));
206 stat
= DTR_CONTROL_ENABLE
| RTS_CONTROL_ENABLE
;
209 /* termios does not support DTR/DSR flow control */
210 shf
->ControlHandShake
= 0;
211 shf
->FlowReplace
= 0;
213 if (stat
& TIOCM_DTR
)
215 shf
->ControlHandShake
|= SERIAL_DTR_CONTROL
;
217 if (port
.c_cflag
& CRTSCTS
)
219 shf
->ControlHandShake
|= SERIAL_DTR_CONTROL
| SERIAL_DTR_HANDSHAKE
;
220 shf
->ControlHandShake
|= SERIAL_CTS_HANDSHAKE
;
226 if (stat
& TIOCM_RTS
)
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
;
237 return STATUS_SUCCESS
;
240 static NTSTATUS
get_line_control(int fd
, SERIAL_LINE_CONTROL
* slc
)
244 if (tcgetattr(fd
, &port
) == -1)
246 ERR("tcgetattr error '%s'\n", strerror(errno
));
247 return FILE_GetNtStatus();
251 switch (port
.c_cflag
& (PARENB
| PARODD
| CMSPAR
))
253 switch (port
.c_cflag
& (PARENB
| PARODD
))
256 case 0: slc
->Parity
= NOPARITY
; break;
257 case PARENB
: slc
->Parity
= EVENPARITY
; break;
258 case PARENB
|PARODD
: slc
->Parity
= ODDPARITY
; break;
260 case PARENB
|CMSPAR
: slc
->Parity
= MARKPARITY
; break;
261 case PARENB
|PARODD
|CMSPAR
: slc
->Parity
= SPACEPARITY
; break;
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
;
279 slc
->StopBits
= TWOSTOPBITS
;
282 slc
->StopBits
= ONESTOPBIT
;
284 return STATUS_SUCCESS
;
287 static NTSTATUS
get_modem_status(int fd
, DWORD
* lpModemStat
)
289 NTSTATUS status
= STATUS_SUCCESS
;
293 if (ioctl(fd
, TIOCMGET
, &mstat
) == -1)
295 WARN("ioctl failed\n");
296 status
= FILE_GetNtStatus();
302 if (mstat
& TIOCM_CTS
) *lpModemStat
|= MS_CTS_ON
;
305 if (mstat
& TIOCM_DSR
) *lpModemStat
|= MS_DSR_ON
;
308 if (mstat
& TIOCM_RNG
) *lpModemStat
|= MS_RING_ON
;
311 /* FIXME: Not really sure about RLSD UB 990810 */
312 if (mstat
& TIOCM_CAR
) *lpModemStat
|= MS_RLSD_ON
;
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 " : "");
321 status
= STATUS_NOT_SUPPORTED
;
326 static NTSTATUS
get_special_chars(int fd
, SERIAL_CHARS
* sc
)
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
;
351 ss
->EofReceived
= FALSE
;
352 ss
->WaitForImmediate
= FALSE
;
354 if (ioctl(fd
, TIOCOUTQ
, &ss
->AmountInOutQueue
) == -1)
356 WARN("ioctl returned error\n");
357 status
= FILE_GetNtStatus();
360 ss
->AmountInOutQueue
= 0; /* FIXME: find a different way to find out */
364 if (ioctl(fd
, TIOCINQ
, &ss
->AmountInInQueue
))
366 WARN("ioctl returned error\n");
367 status
= FILE_GetNtStatus();
370 ss
->AmountInInQueue
= 0; /* FIXME: find a different way to find out */
375 static NTSTATUS
get_timeouts(HANDLE handle
, SERIAL_TIMEOUTS
* st
)
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
;
394 static NTSTATUS
get_wait_mask(HANDLE hDevice
, DWORD
* mask
)
398 SERVER_START_REQ( get_serial_info
)
400 req
->handle
= hDevice
;
401 if (!(status
= wine_server_call( req
)))
402 *mask
= reply
->eventmask
;
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
)
426 if (tcgetattr(fd
, &port
) == -1)
428 ERR("tcgetattr error '%s'\n", strerror(errno
));
429 return FILE_GetNtStatus();
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;
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;
445 case CBR_300
: port
.c_cflag
|= B300
; break;
447 case CBR_600
: port
.c_cflag
|= B600
; break;
449 case CBR_1200
: port
.c_cflag
|= B1200
; break;
450 case 1800: port
.c_cflag
|= B1800
; break;
452 case CBR_2400
: port
.c_cflag
|= B2400
; break;
454 case CBR_4800
: port
.c_cflag
|= B4800
; break;
456 case CBR_9600
: port
.c_cflag
|= B9600
; break;
458 case CBR_19200
: port
.c_cflag
|= B19200
; break;
460 case CBR_38400
: port
.c_cflag
|= B38400
; break;
462 case 57600: port
.c_cflag
|= B57600
; break;
465 case 115200: port
.c_cflag
|= B115200
;break;
468 case 230400: port
.c_cflag
|= B230400
;break;
471 case 460800: port
.c_cflag
|= B460800
;break;
474 #if defined (HAVE_LINUX_SERIAL_H) && defined (TIOCSSERIAL)
476 struct serial_struct nuts
;
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
;
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;
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;
513 case CBR_300
: port
.c_ospeed
= B300
; break;
515 case CBR_600
: port
.c_ospeed
= B600
; break;
517 case CBR_1200
: port
.c_ospeed
= B1200
; break;
518 case 1800: port
.c_ospeed
= B1800
; break;
520 case CBR_2400
: port
.c_ospeed
= B2400
; break;
522 case CBR_4800
: port
.c_ospeed
= B4800
; break;
524 case CBR_9600
: port
.c_ospeed
= B9600
; break;
526 case CBR_19200
: port
.c_ospeed
= B19200
; break;
528 case CBR_38400
: port
.c_ospeed
= B38400
; break;
531 case CBR_57600
: port
.c_cflag
|= B57600
; break;
535 case CBR_115200
: port
.c_cflag
|= B115200
;break;
538 case 230400: port
.c_cflag
|= B230400
;break;
541 case 460800: port
.c_cflag
|= B460800
;break;
544 ERR("baudrate %d\n", sbr
->BaudRate
);
545 return STATUS_NOT_SUPPORTED
;
547 port
.c_ispeed
= port
.c_ospeed
;
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
)
560 unsigned int mstat
, okay
;
561 okay
= ioctl(fd
, TIOCMGET
, &mstat
);
562 if (okay
) return okay
;
563 if (andy
) mstat
&= andy
;
565 return ioctl(fd
, TIOCMSET
, &mstat
);
571 static NTSTATUS
set_handflow(int fd
, const SERIAL_HANDFLOW
* shf
)
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();
586 if ((shf
->ControlHandShake
& SERIAL_CTS_HANDSHAKE
) ||
587 (shf
->FlowReplace
& SERIAL_RTS_HANDSHAKE
))
589 port
.c_cflag
|= CRTSCTS
;
593 port
.c_cflag
&= ~CRTSCTS
;
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);
602 whack_modem(fd
, 0, TIOCM_DTR
);
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);
610 whack_modem(fd
, 0, TIOCM_RTS
);
614 if (shf
->FlowReplace
& SERIAL_AUTO_RECEIVE
)
615 port
.c_iflag
|= IXON
;
617 port
.c_iflag
&= ~IXON
;
618 if (shf
->FlowReplace
& SERIAL_AUTO_TRANSMIT
)
619 port
.c_iflag
|= IXOFF
;
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
)
634 unsigned bytesize
, stopbits
;
636 if (tcgetattr(fd
, &port
) == -1)
638 ERR("tcgetattr error '%s'\n", strerror(errno
));
639 return FILE_GetNtStatus();
643 port
.c_iflag
&= ~(ISTRIP
|BRKINT
|IGNCR
|ICRNL
|INLCR
|PARMRK
|IMAXBEL
);
645 port
.c_iflag
&= ~(ISTRIP
|BRKINT
|IGNCR
|ICRNL
|INLCR
|PARMRK
);
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
;
661 port
.c_cflag
&= ~(PARENB
| PARODD
| CMSPAR
);
663 port
.c_cflag
&= ~(PARENB
| PARODD
);
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;
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;
676 /* try the POSIX way */
678 if (slc
->StopBits
== ONESTOPBIT
)
680 stopbits
= TWOSTOPBITS
;
681 port
.c_iflag
&= ~INPCK
;
685 ERR("Cannot set MARK Parity\n");
686 return STATUS_NOT_SUPPORTED
;
690 if (slc
->WordLength
< 8)
693 port
.c_iflag
&= ~INPCK
;
697 ERR("Cannot set SPACE Parity\n");
698 return STATUS_NOT_SUPPORTED
;
704 return STATUS_NOT_SUPPORTED
;
707 port
.c_cflag
&= ~CSIZE
;
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;
716 return STATUS_NOT_SUPPORTED
;
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;
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
)
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
)
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
);
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 */
802 ux_timeout
= (st
->ReadIntervalTimeout
+ 99) / 100;
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
)
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
);
831 static NTSTATUS
set_XOff(int fd
)
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
)
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
;
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
;
882 /***********************************************************************
883 * Data needed by the thread polling for the changing CommEvent
885 typedef struct async_commio
892 serial_irq_info irq_info
;
895 /***********************************************************************
896 * Get extended interrupt count info, needed for wait_on
898 static NTSTATUS
get_irq_info(int fd
, serial_irq_info
*irq_info
)
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();
916 memset(irq_info
,0, sizeof(serial_irq_info
));
917 return STATUS_NOT_IMPLEMENTED
;
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
)
948 if (ioctl(fd
, TIOCINQ
, &queue
))
949 WARN("TIOCINQ returned error\n");
954 if (mask
& EV_TXEMPTY
)
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");
962 /* TIOCOUTQ only checks for an empty buffer */
963 #elif defined(TIOCOUTQ)
964 if (ioctl(fd
, TIOCOUTQ
, &queue
))
965 WARN("TIOCOUTQ returned error\n");
969 TRACE("OUTQUEUE %d, Transmitter %sempty\n",
970 queue
, (ret
& EV_TXEMPTY
) ? "" : "not ");
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
;
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
;
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
;
1001 * TIOCMIWAIT is not adequate
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;
1021 if (needs_close
) close( fd
);
1023 if (commio
->hEvent
) NtSetEvent(commio
->hEvent
, NULL
);
1024 RtlFreeHeap(GetProcessHeap(), 0, commio
);
1028 static NTSTATUS
wait_on(HANDLE hDevice
, int fd
, HANDLE hEvent
, DWORD
* events
)
1030 async_commio
* commio
;
1033 if ((status
= NtResetEvent(hEvent
, NULL
)))
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
)
1051 #if !(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)
1052 if (commio
->evtmask
& EV_TXEMPTY
)
1055 #if !defined(TIOCMGET)
1056 if (commio
->evtmask
& (EV_CTS
| EV_DSR
| EV_RING
| EV_RLSD
))
1059 #if !defined(TIOCM_CTS)
1060 if (commio
->evtmask
& EV_CTS
)
1063 #if !defined(TIOCM_DSR)
1064 if (commio
->evtmask
& EV_DSR
)
1067 #if !defined(TIOCM_RNG)
1068 if (commio
->evtmask
& EV_RING
)
1071 #if !defined(TIOCM_CAR)
1072 if (commio
->evtmask
& EV_RLSD
)
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
)))
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)
1094 FIXME("Returning error because of missing capabilities\n");
1095 status
= STATUS_INVALID_PARAMETER
;
1098 RtlFreeHeap(GetProcessHeap(), 0, commio
);
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
)))
1138 switch (dwIoControlCode
)
1140 case IOCTL_SERIAL_CLR_DTR
:
1142 if (whack_modem(fd
, ~TIOCM_DTR
, 0) == -1) status
= FILE_GetNtStatus();
1144 status
= STATUS_NOT_SUPPORTED
;
1147 case IOCTL_SERIAL_CLR_RTS
:
1149 if (whack_modem(fd
, ~TIOCM_RTS
, 0) == -1) status
= FILE_GetNtStatus();
1151 status
= STATUS_NOT_SUPPORTED
;
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
);
1161 status
= STATUS_INVALID_PARAMETER
;
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
);
1170 status
= STATUS_INVALID_PARAMETER
;
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
;
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
);
1187 status
= STATUS_INVALID_PARAMETER
;
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
);
1196 status
= STATUS_INVALID_PARAMETER
;
1198 case IOCTL_SERIAL_GET_MODEMSTATUS
:
1199 if (lpOutBuffer
&& nOutBufferSize
== sizeof(DWORD
))
1201 if (!(status
= get_modem_status(fd
, (DWORD
*)lpOutBuffer
)))
1204 else status
= STATUS_INVALID_PARAMETER
;
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
);
1213 status
= STATUS_INVALID_PARAMETER
;
1215 case IOCTL_SERIAL_GET_WAIT_MASK
:
1216 if (lpOutBuffer
&& nOutBufferSize
== sizeof(DWORD
))
1218 if (!(status
= get_wait_mask(hDevice
, (DWORD
*)lpOutBuffer
)))
1222 status
= STATUS_INVALID_PARAMETER
;
1224 case IOCTL_SERIAL_IMMEDIATE_CHAR
:
1225 if (lpInBuffer
&& nInBufferSize
== sizeof(CHAR
))
1226 status
= xmit_immediate(hDevice
, fd
, lpInBuffer
);
1228 status
= STATUS_INVALID_PARAMETER
;
1230 case IOCTL_SERIAL_PURGE
:
1231 if (lpInBuffer
&& nInBufferSize
== sizeof(DWORD
))
1232 status
= purge(fd
, *(DWORD
*)lpInBuffer
);
1234 status
= STATUS_INVALID_PARAMETER
;
1236 case IOCTL_SERIAL_RESET_DEVICE
:
1237 FIXME("Unsupported\n");
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
);
1243 status
= STATUS_INVALID_PARAMETER
;
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();
1253 FIXME("ioctl not available\n");
1254 status
= STATUS_NOT_SUPPORTED
;
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();
1265 FIXME("ioctl not available\n");
1266 status
= STATUS_NOT_SUPPORTED
;
1269 case IOCTL_SERIAL_SET_CHARS
:
1270 if (lpInBuffer
&& nInBufferSize
== sizeof(SERIAL_CHARS
))
1271 status
= set_special_chars(fd
, (const SERIAL_CHARS
*)lpInBuffer
);
1273 status
= STATUS_INVALID_PARAMETER
;
1275 case IOCTL_SERIAL_SET_DTR
:
1277 if (whack_modem(fd
, 0, TIOCM_DTR
) == -1) status
= FILE_GetNtStatus();
1279 status
= STATUS_NOT_SUPPORTED
;
1282 case IOCTL_SERIAL_SET_HANDFLOW
:
1283 if (lpInBuffer
&& nInBufferSize
== sizeof(SERIAL_HANDFLOW
))
1284 status
= set_handflow(fd
, (const SERIAL_HANDFLOW
*)lpInBuffer
);
1286 status
= STATUS_INVALID_PARAMETER
;
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
);
1292 status
= STATUS_INVALID_PARAMETER
;
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
);
1298 status
= STATUS_INVALID_PARAMETER
;
1300 case IOCTL_SERIAL_SET_RTS
:
1302 if (whack_modem(fd
, 0, TIOCM_RTS
) == -1) status
= FILE_GetNtStatus();
1304 status
= STATUS_NOT_SUPPORTED
;
1307 case IOCTL_SERIAL_SET_TIMEOUTS
:
1308 if (lpInBuffer
&& nInBufferSize
== sizeof(SERIAL_TIMEOUTS
))
1309 status
= set_timeouts(hDevice
, fd
, (const SERIAL_TIMEOUTS
*)lpInBuffer
);
1311 status
= STATUS_INVALID_PARAMETER
;
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
;
1320 case IOCTL_SERIAL_SET_XOFF
:
1321 status
= set_XOff(fd
);
1323 case IOCTL_SERIAL_SET_XON
:
1324 status
= set_XOn(fd
);
1326 case IOCTL_SERIAL_WAIT_ON_MASK
:
1327 if (lpOutBuffer
&& nOutBufferSize
== sizeof(DWORD
))
1329 if (!(status
= wait_on(hDevice
, fd
, hEvent
, (DWORD
*)lpOutBuffer
)))
1333 status
= STATUS_INVALID_PARAMETER
;
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);
1340 status
= STATUS_INVALID_PARAMETER
;
1343 if (needs_close
) close( fd
);
1345 piosb
->u
.Status
= status
;
1346 piosb
->Information
= sz
;
1347 if (hEvent
&& status
!= STATUS_PENDING
) NtSetEvent(hEvent
, NULL
);
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
)
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
1367 * so we have to explicitely wait if no hEvent is provided
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
);
1388 if (status
== STATUS_PENDING
)
1390 NtWaitForSingleObject(hev
, FALSE
, NULL
);
1391 status
= STATUS_SUCCESS
;
1396 else status
= io_control(hDevice
, hEvent
, UserApcRoutine
, UserApcContext
,
1397 piosb
, dwIoControlCode
, lpInBuffer
, nInBufferSize
,
1398 lpOutBuffer
, nOutBufferSize
);