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_%ld\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 %ld. 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 #endif /* Don't have linux/serial.h or lack TIOCSSERIAL */
497 ERR("baudrate %ld\n", sbr
->BaudRate
);
498 return STATUS_NOT_SUPPORTED
;
500 #elif !defined(__EMX__)
501 switch (sbr
->BaudRate
)
503 case 0: port
.c_ospeed
= B0
; break;
504 case 50: port
.c_ospeed
= B50
; break;
505 case 75: port
.c_ospeed
= B75
; break;
507 case CBR_110
: port
.c_ospeed
= B110
; break;
508 case 134: port
.c_ospeed
= B134
; break;
509 case 150: port
.c_ospeed
= B150
; break;
510 case 200: port
.c_ospeed
= B200
; break;
512 case CBR_300
: port
.c_ospeed
= B300
; break;
514 case CBR_600
: port
.c_ospeed
= B600
; break;
516 case CBR_1200
: port
.c_ospeed
= B1200
; break;
517 case 1800: port
.c_ospeed
= B1800
; break;
519 case CBR_2400
: port
.c_ospeed
= B2400
; break;
521 case CBR_4800
: port
.c_ospeed
= B4800
; break;
523 case CBR_9600
: port
.c_ospeed
= B9600
; break;
525 case CBR_19200
: port
.c_ospeed
= B19200
; break;
527 case CBR_38400
: port
.c_ospeed
= B38400
; break;
530 case CBR_57600
: port
.c_cflag
|= B57600
; break;
534 case CBR_115200
: port
.c_cflag
|= B115200
;break;
537 case 230400: port
.c_cflag
|= B230400
;break;
540 case 460800: port
.c_cflag
|= B460800
;break;
543 ERR("baudrate %ld\n", sbr
->BaudRate
);
544 return STATUS_NOT_SUPPORTED
;
546 port
.c_ispeed
= port
.c_ospeed
;
548 if (tcsetattr(fd
, TCSANOW
, &port
) == -1)
550 ERR("tcsetattr error '%s'\n", strerror(errno
));
551 return FILE_GetNtStatus();
553 return STATUS_SUCCESS
;
556 static int whack_modem(int fd
, unsigned int andy
, unsigned int orrie
)
559 unsigned int mstat
, okay
;
560 okay
= ioctl(fd
, TIOCMGET
, &mstat
);
561 if (okay
) return okay
;
562 if (andy
) mstat
&= andy
;
564 return ioctl(fd
, TIOCMSET
, &mstat
);
570 static NTSTATUS
set_handflow(int fd
, const SERIAL_HANDFLOW
* shf
)
574 if ((shf
->FlowReplace
& (SERIAL_RTS_CONTROL
| SERIAL_RTS_HANDSHAKE
)) ==
575 (SERIAL_RTS_CONTROL
| SERIAL_RTS_HANDSHAKE
))
576 return STATUS_NOT_SUPPORTED
;
578 if (tcgetattr(fd
, &port
) == -1)
580 ERR("tcgetattr error '%s'\n", strerror(errno
));
581 return FILE_GetNtStatus();
585 if ((shf
->ControlHandShake
& SERIAL_CTS_HANDSHAKE
) ||
586 (shf
->FlowReplace
& SERIAL_RTS_HANDSHAKE
))
588 port
.c_cflag
|= CRTSCTS
;
592 port
.c_cflag
&= ~CRTSCTS
;
595 if (shf
->ControlHandShake
& SERIAL_DTR_HANDSHAKE
)
597 WARN("DSR/DTR flow control not supported\n");
598 } else if (shf
->ControlHandShake
& SERIAL_DTR_CONTROL
)
599 whack_modem(fd
, ~TIOCM_DTR
, 0);
601 whack_modem(fd
, 0, TIOCM_DTR
);
604 if (!(shf
->ControlHandShake
& SERIAL_DSR_HANDSHAKE
))
606 if ((shf
->FlowReplace
& (SERIAL_RTS_CONTROL
|SERIAL_RTS_HANDSHAKE
)) == 0)
607 whack_modem(fd
, ~TIOCM_RTS
, 0);
609 whack_modem(fd
, 0, TIOCM_RTS
);
613 if (shf
->FlowReplace
& SERIAL_AUTO_RECEIVE
)
614 port
.c_iflag
|= IXON
;
616 port
.c_iflag
&= ~IXON
;
617 if (shf
->FlowReplace
& SERIAL_AUTO_TRANSMIT
)
618 port
.c_iflag
|= IXOFF
;
620 port
.c_iflag
&= ~IXOFF
;
621 if (tcsetattr(fd
, TCSANOW
, &port
) == -1)
623 ERR("tcsetattr error '%s'\n", strerror(errno
));
624 return FILE_GetNtStatus();
627 return STATUS_SUCCESS
;
630 static NTSTATUS
set_line_control(int fd
, const SERIAL_LINE_CONTROL
* slc
)
633 unsigned bytesize
, stopbits
;
635 if (tcgetattr(fd
, &port
) == -1)
637 ERR("tcgetattr error '%s'\n", strerror(errno
));
638 return FILE_GetNtStatus();
642 port
.c_iflag
&= ~(ISTRIP
|BRKINT
|IGNCR
|ICRNL
|INLCR
|PARMRK
|IMAXBEL
);
644 port
.c_iflag
&= ~(ISTRIP
|BRKINT
|IGNCR
|ICRNL
|INLCR
|PARMRK
);
646 port
.c_iflag
|= IGNBRK
| INPCK
;
648 port
.c_oflag
&= ~(OPOST
);
650 port
.c_cflag
&= ~(HUPCL
);
651 port
.c_cflag
|= CLOCAL
| CREAD
;
653 port
.c_lflag
&= ~(ICANON
|ECHO
|ISIG
);
654 port
.c_lflag
|= NOFLSH
;
656 bytesize
= slc
->WordLength
;
657 stopbits
= slc
->StopBits
;
660 port
.c_cflag
&= ~(PARENB
| PARODD
| CMSPAR
);
662 port
.c_cflag
&= ~(PARENB
| PARODD
);
667 case NOPARITY
: port
.c_iflag
&= ~INPCK
; break;
668 case ODDPARITY
: port
.c_cflag
|= PARENB
| PARODD
; break;
669 case EVENPARITY
: port
.c_cflag
|= PARENB
; break;
671 /* Linux defines mark/space (stick) parity */
672 case MARKPARITY
: port
.c_cflag
|= PARENB
| CMSPAR
; break;
673 case SPACEPARITY
: port
.c_cflag
|= PARENB
| PARODD
| CMSPAR
; break;
675 /* try the POSIX way */
677 if (slc
->StopBits
== ONESTOPBIT
)
679 stopbits
= TWOSTOPBITS
;
680 port
.c_iflag
&= ~INPCK
;
684 ERR("Cannot set MARK Parity\n");
685 return STATUS_NOT_SUPPORTED
;
689 if (slc
->WordLength
< 8)
692 port
.c_iflag
&= ~INPCK
;
696 ERR("Cannot set SPACE Parity\n");
697 return STATUS_NOT_SUPPORTED
;
703 return STATUS_NOT_SUPPORTED
;
706 port
.c_cflag
&= ~CSIZE
;
709 case 5: port
.c_cflag
|= CS5
; break;
710 case 6: port
.c_cflag
|= CS6
; break;
711 case 7: port
.c_cflag
|= CS7
; break;
712 case 8: port
.c_cflag
|= CS8
; break;
715 return STATUS_NOT_SUPPORTED
;
720 case ONESTOPBIT
: port
.c_cflag
&= ~CSTOPB
; break;
721 case ONE5STOPBITS
: /* will be selected if bytesize is 5 */
722 case TWOSTOPBITS
: port
.c_cflag
|= CSTOPB
; break;
725 return STATUS_NOT_SUPPORTED
;
727 /* otherwise it hangs with pending input*/
728 if (tcsetattr(fd
, TCSANOW
, &port
) == -1)
730 ERR("tcsetattr error '%s'\n", strerror(errno
));
731 return FILE_GetNtStatus();
733 return STATUS_SUCCESS
;
736 static NTSTATUS
set_queue_size(int fd
, const SERIAL_QUEUE_SIZE
* sqs
)
738 FIXME("insize %ld outsize %ld unimplemented stub\n", sqs
->InSize
, sqs
->OutSize
);
739 return STATUS_SUCCESS
;
742 static NTSTATUS
set_special_chars(int fd
, const SERIAL_CHARS
* sc
)
746 if (tcgetattr(fd
, &port
) == -1)
748 ERR("tcgetattr error '%s'\n", strerror(errno
));
749 return FILE_GetNtStatus();
752 port
.c_cc
[VMIN
] = 0;
753 port
.c_cc
[VTIME
] = 1;
755 port
.c_cc
[VEOF
] = sc
->EofChar
;
756 /* FIXME: sc->ErrorChar is not supported */
757 /* FIXME: sc->BreakChar is not supported */
758 /* FIXME: sc->EventChar is not supported */
759 port
.c_cc
[VSTART
] = sc
->XonChar
;
760 port
.c_cc
[VSTOP
] = sc
->XoffChar
;
762 if (tcsetattr(fd
, TCSANOW
, &port
) == -1)
764 ERR("tcsetattr error '%s'\n", strerror(errno
));
765 return FILE_GetNtStatus();
767 return STATUS_SUCCESS
;
770 static NTSTATUS
set_timeouts(HANDLE handle
, int fd
, const SERIAL_TIMEOUTS
* st
)
774 unsigned int ux_timeout
;
776 SERVER_START_REQ( set_serial_info
)
778 req
->handle
= handle
;
779 req
->flags
= SERIALINFO_SET_TIMEOUTS
;
780 req
->readinterval
= st
->ReadIntervalTimeout
;
781 req
->readmult
= st
->ReadTotalTimeoutMultiplier
;
782 req
->readconst
= st
->ReadTotalTimeoutConstant
;
783 req
->writemult
= st
->WriteTotalTimeoutMultiplier
;
784 req
->writeconst
= st
->WriteTotalTimeoutConstant
;
785 status
= wine_server_call( req
);
788 if (status
) return status
;
790 if (tcgetattr(fd
, &port
) == -1)
792 FIXME("tcgetattr on fd %d failed (%s)!\n", fd
, strerror(errno
));
793 return FILE_GetNtStatus();
796 /* VTIME is in 1/10 seconds */
797 if (st
->ReadIntervalTimeout
== 0) /* 0 means no timeout */
801 ux_timeout
= (st
->ReadIntervalTimeout
+ 99) / 100;
803 ux_timeout
= 1; /* must be at least some timeout */
805 port
.c_cc
[VTIME
] = ux_timeout
;
807 if (tcsetattr(fd
, 0, &port
) == -1)
809 FIXME("tcsetattr on fd %d failed (%s)!\n", fd
, strerror(errno
));
810 return FILE_GetNtStatus();
812 return STATUS_SUCCESS
;
815 static NTSTATUS
set_wait_mask(HANDLE hDevice
, DWORD mask
)
819 SERVER_START_REQ( set_serial_info
)
821 req
->handle
= hDevice
;
822 req
->flags
= SERIALINFO_SET_MASK
;
823 req
->eventmask
= mask
;
824 status
= wine_server_call( req
);
830 static NTSTATUS
set_XOff(int fd
)
834 if (tcgetattr(fd
,&port
) == -1)
836 FIXME("tcgetattr on fd %d failed (%s)!\n", fd
, strerror(errno
));
837 return FILE_GetNtStatus();
841 port
.c_iflag
|= IXOFF
;
842 if (tcsetattr(fd
, TCSADRAIN
, &port
) == -1)
844 FIXME("tcsetattr on fd %d failed (%s)!\n", fd
, strerror(errno
));
845 return FILE_GetNtStatus();
847 return STATUS_SUCCESS
;
850 static NTSTATUS
set_XOn(int fd
)
854 if (tcgetattr(fd
,&port
) == -1)
856 FIXME("tcgetattr on fd %d failed (%s)!\n", fd
, strerror(errno
));
857 return FILE_GetNtStatus();
859 port
.c_iflag
|= IXON
;
860 if (tcsetattr(fd
, TCSADRAIN
, &port
) == -1)
862 FIXME("tcsetattr on fd %d failed (%s)!\n", fd
, strerror(errno
));
863 return FILE_GetNtStatus();
865 return STATUS_SUCCESS
;
869 * local structure holding the irq values we need for WaitCommEvent()
871 * Stripped down from struct serial_icounter_struct, which may not be available on some systems
872 * As the modem line interrupts (cts, dsr, rng, dcd) only get updated with TIOCMIWAIT active,
873 * no need to carry them in the internal structure
876 typedef struct serial_irq_info
878 int rx
, tx
, frame
, overrun
, parity
, brk
, buf_overrun
;
881 /***********************************************************************
882 * Data needed by the thread polling for the changing CommEvent
884 typedef struct async_commio
891 serial_irq_info irq_info
;
894 /***********************************************************************
895 * Get extended interrupt count info, needed for wait_on
897 static NTSTATUS
get_irq_info(int fd
, serial_irq_info
*irq_info
)
900 struct serial_icounter_struct einfo
;
901 if (!ioctl(fd
, TIOCGICOUNT
, &einfo
))
903 irq_info
->rx
= einfo
.rx
;
904 irq_info
->tx
= einfo
.tx
;
905 irq_info
->frame
= einfo
.frame
;
906 irq_info
->overrun
= einfo
.overrun
;
907 irq_info
->parity
= einfo
.parity
;
908 irq_info
->brk
= einfo
.brk
;
909 irq_info
->buf_overrun
= einfo
.buf_overrun
;
910 return STATUS_SUCCESS
;
912 TRACE("TIOCGICOUNT err %s\n", strerror(errno
));
913 return FILE_GetNtStatus();
915 memset(irq_info
,0, sizeof(serial_irq_info
));
916 return STATUS_NOT_IMPLEMENTED
;
920 static DWORD WINAPI
check_events(int fd
, DWORD mask
,
921 const serial_irq_info
*new,
922 const serial_irq_info
*old
,
923 DWORD new_mstat
, DWORD old_mstat
)
925 DWORD ret
= 0, queue
;
927 TRACE("mask 0x%08lx\n", mask
);
928 TRACE("old->rx 0x%08x vs. new->rx 0x%08x\n", old
->rx
, new->rx
);
929 TRACE("old->tx 0x%08x vs. new->tx 0x%08x\n", old
->tx
, new->tx
);
930 TRACE("old->frame 0x%08x vs. new->frame 0x%08x\n", old
->frame
, new->frame
);
931 TRACE("old->overrun 0x%08x vs. new->overrun 0x%08x\n", old
->overrun
, new->overrun
);
932 TRACE("old->parity 0x%08x vs. new->parity 0x%08x\n", old
->parity
, new->parity
);
933 TRACE("old->brk 0x%08x vs. new->brk 0x%08x\n", old
->brk
, new->brk
);
934 TRACE("old->buf_overrun 0x%08x vs. new->buf_overrun 0x%08x\n", old
->buf_overrun
, new->buf_overrun
);
936 if (old
->brk
!= new->brk
) ret
|= EV_BREAK
;
937 if ((old_mstat
& MS_CTS_ON
) != (new_mstat
& MS_CTS_ON
)) ret
|= EV_CTS
;
938 if ((old_mstat
& MS_DSR_ON
) != (new_mstat
& MS_DSR_ON
)) ret
|= EV_DSR
;
939 if ((old_mstat
& MS_RING_ON
) != (new_mstat
& MS_RING_ON
)) ret
|= EV_RING
;
940 if ((old_mstat
& MS_RLSD_ON
) != (new_mstat
& MS_RLSD_ON
)) ret
|= EV_RLSD
;
941 if (old
->frame
!= new->frame
|| old
->overrun
!= new->overrun
|| old
->parity
!= new->parity
) ret
|= EV_ERR
;
942 if (mask
& EV_RXCHAR
)
946 if (ioctl(fd
, TIOCINQ
, &queue
))
947 WARN("TIOCINQ returned error\n");
952 if (mask
& EV_TXEMPTY
)
955 /* We really want to know when all characters have gone out of the transmitter */
956 #if defined(TIOCSERGETLSR)
957 if (ioctl(fd
, TIOCSERGETLSR
, &queue
))
958 WARN("TIOCSERGETLSR returned error\n");
960 /* TIOCOUTQ only checks for an empty buffer */
961 #elif defined(TIOCOUTQ)
962 if (ioctl(fd
, TIOCOUTQ
, &queue
))
963 WARN("TIOCOUTQ returned error\n");
967 TRACE("OUTQUEUE %ld, Transmitter %sempty\n",
968 queue
, (ret
& EV_TXEMPTY
) ? "" : "not ");
973 /***********************************************************************
974 * wait_for_event (INTERNAL)
976 * We need to poll for what is interesting
977 * TIOCMIWAIT only checks modem status line and may not be aborted by a changing mask
980 static DWORD CALLBACK
wait_for_event(LPVOID arg
)
982 async_commio
*commio
= (async_commio
*) arg
;
985 if (wine_server_handle_to_fd( commio
->hDevice
, FILE_READ_DATA
| FILE_WRITE_DATA
, &fd
, NULL
))
991 serial_irq_info new_irq_info
;
992 DWORD new_mstat
, new_evtmask
;
995 TRACE("device=%p fd=0x%08x mask=0x%08lx buffer=%p event=%p irq_info=%p\n",
996 commio
->hDevice
, fd
, commio
->evtmask
, commio
->events
, commio
->hEvent
, &commio
->irq_info
);
998 time
.QuadPart
= (ULONGLONG
)10000;
999 time
.QuadPart
= -time
.QuadPart
;
1003 * TIOCMIWAIT is not adequate
1006 * We don't handle the EV_RXFLAG (the eventchar)
1008 NtDelayExecution(FALSE
, &time
);
1009 get_irq_info(fd
, &new_irq_info
);
1010 if (get_modem_status(fd
, &new_mstat
))
1011 TRACE("get_modem_status failed\n");
1012 *commio
->events
= check_events(fd
, commio
->evtmask
,
1013 &new_irq_info
, &commio
->irq_info
,
1014 new_mstat
, commio
->mstat
);
1015 if (*commio
->events
) break;
1016 get_wait_mask(commio
->hDevice
, &new_evtmask
);
1017 if (commio
->evtmask
!= new_evtmask
)
1019 *commio
->events
= 0;
1024 if (commio
->hEvent
!= INVALID_HANDLE_VALUE
)
1025 NtSetEvent(commio
->hEvent
, NULL
);
1026 if (fd
!= -1) wine_server_release_fd( commio
->hDevice
, fd
);
1027 RtlFreeHeap(GetProcessHeap(), 0, commio
);
1031 static NTSTATUS
wait_on(HANDLE hDevice
, int fd
, HANDLE hEvent
, DWORD
* events
)
1033 async_commio
* commio
;
1036 if ((status
= NtResetEvent(hEvent
, NULL
)))
1039 commio
= RtlAllocateHeap(GetProcessHeap(), 0, sizeof (async_commio
));
1040 if (!commio
) return STATUS_NO_MEMORY
;
1042 commio
->hDevice
= hDevice
;
1043 commio
->events
= events
;
1044 commio
->hEvent
= hEvent
;
1045 get_wait_mask(commio
->hDevice
, &commio
->evtmask
);
1047 /* We may never return, if some capabilities miss
1048 * Return error in that case
1050 #if !defined(TIOCINQ)
1051 if (commio
->evtmask
& EV_RXCHAR
)
1054 #if !(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)
1055 if (commio
->evtmask
& EV_TXEMPTY
)
1058 #if !defined(TIOCMGET)
1059 if (commio
->evtmask
& (EV_CTS
| EV_DSR
| EV_RING
| EV_RLSD
))
1062 #if !defined(TIOCM_CTS)
1063 if (commio
->evtmask
& EV_CTS
)
1066 #if !defined(TIOCM_DSR)
1067 if (commio
->evtmask
& EV_DSR
)
1070 #if !defined(TIOCM_RNG)
1071 if (commio
->evtmask
& EV_RING
)
1074 #if !defined(TIOCM_CAR)
1075 if (commio
->evtmask
& EV_RLSD
)
1078 if (commio
->evtmask
& EV_RXFLAG
)
1079 FIXME("EV_RXFLAG not handled\n");
1080 if ((status
= get_irq_info(fd
, &commio
->irq_info
)) ||
1081 (status
= get_modem_status(fd
, &commio
->mstat
)))
1084 /* We might have received something or the TX bufffer is delivered */
1085 *events
= check_events(fd
, commio
->evtmask
,
1086 &commio
->irq_info
, &commio
->irq_info
,
1087 commio
->mstat
, commio
->mstat
);
1088 if (*events
) goto out_now
;
1090 /* create the worker for the task */
1091 status
= RtlQueueWorkItem(wait_for_event
, commio
, 0 /* FIXME */);
1092 if (status
!= STATUS_SUCCESS
) goto out_now
;
1093 return STATUS_PENDING
;
1095 #if !defined(TIOCINQ) || (!(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)) || !defined(TIOCMGET) || !defined(TIOCM_CTS) ||!defined(TIOCM_DSR) || !defined(TIOCM_RNG) || !defined(TIOCM_CAR)
1097 FIXME("Returning error because of missing capabilities\n");
1098 status
= STATUS_INVALID_PARAMETER
;
1101 RtlFreeHeap(GetProcessHeap(), 0, commio
);
1105 static NTSTATUS
xmit_immediate(HANDLE hDevice
, int fd
, char* ptr
)
1107 /* FIXME: not perfect as it should bypass the in-queue */
1108 WARN("(%p,'%c') not perfect!\n", hDevice
, *ptr
);
1109 if (write(fd
, ptr
, 1) != 1)
1110 return FILE_GetNtStatus();
1111 return STATUS_SUCCESS
;
1114 /******************************************************************
1115 * COMM_DeviceIoControl
1119 static inline NTSTATUS
io_control(HANDLE hDevice
,
1120 HANDLE hEvent
, PIO_APC_ROUTINE UserApcRoutine
,
1121 PVOID UserApcContext
,
1122 PIO_STATUS_BLOCK piosb
,
1123 ULONG dwIoControlCode
,
1124 LPVOID lpInBuffer
, DWORD nInBufferSize
,
1125 LPVOID lpOutBuffer
, DWORD nOutBufferSize
)
1127 DWORD sz
= 0, access
= FILE_READ_DATA
;
1128 NTSTATUS status
= STATUS_SUCCESS
;
1131 TRACE("%p %s %p %ld %p %ld %p\n",
1132 hDevice
, iocode2str(dwIoControlCode
), lpInBuffer
, nInBufferSize
,
1133 lpOutBuffer
, nOutBufferSize
, piosb
);
1135 piosb
->Information
= 0;
1137 if (dwIoControlCode
!= IOCTL_SERIAL_GET_TIMEOUTS
)
1138 if ((status
= wine_server_handle_to_fd( hDevice
, access
, &fd
, NULL
)))
1141 switch (dwIoControlCode
)
1143 case IOCTL_SERIAL_CLR_DTR
:
1145 if (whack_modem(fd
, ~TIOCM_DTR
, 0) == -1) status
= FILE_GetNtStatus();
1147 status
= STATUS_NOT_SUPPORTED
;
1150 case IOCTL_SERIAL_CLR_RTS
:
1152 if (whack_modem(fd
, ~TIOCM_RTS
, 0) == -1) status
= FILE_GetNtStatus();
1154 status
= STATUS_NOT_SUPPORTED
;
1157 case IOCTL_SERIAL_GET_BAUD_RATE
:
1158 if (lpOutBuffer
&& nOutBufferSize
== sizeof(SERIAL_BAUD_RATE
))
1160 if (!(status
= get_baud_rate(fd
, (SERIAL_BAUD_RATE
*)lpOutBuffer
)))
1161 sz
= sizeof(SERIAL_BAUD_RATE
);
1164 status
= STATUS_INVALID_PARAMETER
;
1166 case IOCTL_SERIAL_GET_CHARS
:
1167 if (lpOutBuffer
&& nOutBufferSize
== sizeof(SERIAL_CHARS
))
1169 if (!(status
= get_special_chars(fd
, (SERIAL_CHARS
*)lpOutBuffer
)))
1170 sz
= sizeof(SERIAL_CHARS
);
1173 status
= STATUS_INVALID_PARAMETER
;
1175 case IOCTL_SERIAL_GET_COMMSTATUS
:
1176 if (lpOutBuffer
&& nOutBufferSize
== sizeof(SERIAL_STATUS
))
1178 if (!(status
= get_status(fd
, (SERIAL_STATUS
*)lpOutBuffer
)))
1179 sz
= sizeof(SERIAL_STATUS
);
1181 else status
= STATUS_INVALID_PARAMETER
;
1183 case IOCTL_SERIAL_GET_HANDFLOW
:
1184 if (lpOutBuffer
&& nOutBufferSize
== sizeof(SERIAL_HANDFLOW
))
1186 if (!(status
= get_hand_flow(fd
, (SERIAL_HANDFLOW
*)lpOutBuffer
)))
1187 sz
= sizeof(SERIAL_HANDFLOW
);
1190 status
= STATUS_INVALID_PARAMETER
;
1192 case IOCTL_SERIAL_GET_LINE_CONTROL
:
1193 if (lpOutBuffer
&& nOutBufferSize
== sizeof(SERIAL_LINE_CONTROL
))
1195 if (!(status
= get_line_control(fd
, (SERIAL_LINE_CONTROL
*)lpOutBuffer
)))
1196 sz
= sizeof(SERIAL_LINE_CONTROL
);
1199 status
= STATUS_INVALID_PARAMETER
;
1201 case IOCTL_SERIAL_GET_MODEMSTATUS
:
1202 if (lpOutBuffer
&& nOutBufferSize
== sizeof(DWORD
))
1204 if (!(status
= get_modem_status(fd
, (DWORD
*)lpOutBuffer
)))
1207 else status
= STATUS_INVALID_PARAMETER
;
1209 case IOCTL_SERIAL_GET_TIMEOUTS
:
1210 if (lpOutBuffer
&& nOutBufferSize
== sizeof(SERIAL_TIMEOUTS
))
1212 if (!(status
= get_timeouts(hDevice
, (SERIAL_TIMEOUTS
*)lpOutBuffer
)))
1213 sz
= sizeof(SERIAL_TIMEOUTS
);
1216 status
= STATUS_INVALID_PARAMETER
;
1218 case IOCTL_SERIAL_GET_WAIT_MASK
:
1219 if (lpOutBuffer
&& nOutBufferSize
== sizeof(DWORD
))
1221 if (!(status
= get_wait_mask(hDevice
, (DWORD
*)lpOutBuffer
)))
1225 status
= STATUS_INVALID_PARAMETER
;
1227 case IOCTL_SERIAL_IMMEDIATE_CHAR
:
1228 if (lpInBuffer
&& nInBufferSize
== sizeof(CHAR
))
1229 status
= xmit_immediate(hDevice
, fd
, lpInBuffer
);
1231 status
= STATUS_INVALID_PARAMETER
;
1233 case IOCTL_SERIAL_PURGE
:
1234 if (lpInBuffer
&& nInBufferSize
== sizeof(DWORD
))
1235 status
= purge(fd
, *(DWORD
*)lpInBuffer
);
1237 status
= STATUS_INVALID_PARAMETER
;
1239 case IOCTL_SERIAL_RESET_DEVICE
:
1240 FIXME("Unsupported\n");
1242 case IOCTL_SERIAL_SET_BAUD_RATE
:
1243 if (lpInBuffer
&& nInBufferSize
== sizeof(SERIAL_BAUD_RATE
))
1244 status
= set_baud_rate(fd
, (const SERIAL_BAUD_RATE
*)lpInBuffer
);
1246 status
= STATUS_INVALID_PARAMETER
;
1248 case IOCTL_SERIAL_SET_BREAK_OFF
:
1249 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1250 if (ioctl(fd
, TIOCCBRK
, 0) == -1)
1252 TRACE("ioctl failed\n");
1253 status
= FILE_GetNtStatus();
1256 FIXME("ioctl not available\n");
1257 status
= STATUS_NOT_SUPPORTED
;
1260 case IOCTL_SERIAL_SET_BREAK_ON
:
1261 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1262 if (ioctl(fd
, TIOCSBRK
, 0) == -1)
1264 TRACE("ioctl failed\n");
1265 status
= FILE_GetNtStatus();
1268 FIXME("ioctl not available\n");
1269 status
= STATUS_NOT_SUPPORTED
;
1272 case IOCTL_SERIAL_SET_CHARS
:
1273 if (lpInBuffer
&& nInBufferSize
== sizeof(SERIAL_CHARS
))
1274 status
= set_special_chars(fd
, (const SERIAL_CHARS
*)lpInBuffer
);
1276 status
= STATUS_INVALID_PARAMETER
;
1278 case IOCTL_SERIAL_SET_DTR
:
1280 if (whack_modem(fd
, 0, TIOCM_DTR
) == -1) status
= FILE_GetNtStatus();
1282 status
= STATUS_NOT_SUPPORTED
;
1285 case IOCTL_SERIAL_SET_HANDFLOW
:
1286 if (lpInBuffer
&& nInBufferSize
== sizeof(SERIAL_HANDFLOW
))
1287 status
= set_handflow(fd
, (const SERIAL_HANDFLOW
*)lpInBuffer
);
1289 status
= STATUS_INVALID_PARAMETER
;
1291 case IOCTL_SERIAL_SET_LINE_CONTROL
:
1292 if (lpInBuffer
&& nInBufferSize
== sizeof(SERIAL_LINE_CONTROL
))
1293 status
= set_line_control(fd
, (const SERIAL_LINE_CONTROL
*)lpInBuffer
);
1295 status
= STATUS_INVALID_PARAMETER
;
1297 case IOCTL_SERIAL_SET_QUEUE_SIZE
:
1298 if (lpInBuffer
&& nInBufferSize
== sizeof(SERIAL_QUEUE_SIZE
))
1299 status
= set_queue_size(fd
, (const SERIAL_QUEUE_SIZE
*)lpInBuffer
);
1301 status
= STATUS_INVALID_PARAMETER
;
1303 case IOCTL_SERIAL_SET_RTS
:
1305 if (whack_modem(fd
, 0, TIOCM_RTS
) == -1) status
= FILE_GetNtStatus();
1307 status
= STATUS_NOT_SUPPORTED
;
1310 case IOCTL_SERIAL_SET_TIMEOUTS
:
1311 if (lpInBuffer
&& nInBufferSize
== sizeof(SERIAL_TIMEOUTS
))
1312 status
= set_timeouts(hDevice
, fd
, (const SERIAL_TIMEOUTS
*)lpInBuffer
);
1314 status
= STATUS_INVALID_PARAMETER
;
1316 case IOCTL_SERIAL_SET_WAIT_MASK
:
1317 if (lpInBuffer
&& nInBufferSize
== sizeof(DWORD
))
1319 status
= set_wait_mask(hDevice
, *(DWORD
*)lpInBuffer
);
1321 else status
= STATUS_INVALID_PARAMETER
;
1323 case IOCTL_SERIAL_SET_XOFF
:
1324 status
= set_XOff(fd
);
1326 case IOCTL_SERIAL_SET_XON
:
1327 status
= set_XOn(fd
);
1329 case IOCTL_SERIAL_WAIT_ON_MASK
:
1330 if (lpOutBuffer
&& nOutBufferSize
== sizeof(DWORD
))
1332 if (!(status
= wait_on(hDevice
, fd
, hEvent
, (DWORD
*)lpOutBuffer
)))
1336 status
= STATUS_INVALID_PARAMETER
;
1339 FIXME("Unsupported IOCTL %lx (type=%lx access=%lx func=%lx meth=%lx)\n",
1340 dwIoControlCode
, dwIoControlCode
>> 16, (dwIoControlCode
>> 14) & 3,
1341 (dwIoControlCode
>> 2) & 0xFFF, dwIoControlCode
& 3);
1343 status
= STATUS_INVALID_PARAMETER
;
1346 if (fd
!= -1) wine_server_release_fd( hDevice
, fd
);
1348 piosb
->u
.Status
= status
;
1349 piosb
->Information
= sz
;
1350 if (hEvent
&& status
!= STATUS_PENDING
) NtSetEvent(hEvent
, NULL
);
1354 NTSTATUS
COMM_DeviceIoControl(HANDLE hDevice
,
1355 HANDLE hEvent
, PIO_APC_ROUTINE UserApcRoutine
,
1356 PVOID UserApcContext
,
1357 PIO_STATUS_BLOCK piosb
,
1358 ULONG dwIoControlCode
,
1359 LPVOID lpInBuffer
, DWORD nInBufferSize
,
1360 LPVOID lpOutBuffer
, DWORD nOutBufferSize
)
1364 if (dwIoControlCode
== IOCTL_SERIAL_WAIT_ON_MASK
)
1366 HANDLE hev
= hEvent
;
1368 /* this is an ioctl we implement in a non blocking way if hEvent is not
1370 * so we have to explicitely wait if no hEvent is provided
1374 OBJECT_ATTRIBUTES attr
;
1376 attr
.Length
= sizeof(attr
);
1377 attr
.RootDirectory
= 0;
1378 attr
.ObjectName
= NULL
;
1379 attr
.Attributes
= OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
;
1380 attr
.SecurityDescriptor
= NULL
;
1381 attr
.SecurityQualityOfService
= NULL
;
1382 status
= NtCreateEvent(&hev
, EVENT_ALL_ACCESS
, &attr
, FALSE
, FALSE
);
1384 if (status
) goto done
;
1386 status
= io_control(hDevice
, hev
, UserApcRoutine
, UserApcContext
,
1387 piosb
, dwIoControlCode
, lpInBuffer
, nInBufferSize
,
1388 lpOutBuffer
, nOutBufferSize
);
1391 if (status
== STATUS_PENDING
)
1393 NtWaitForSingleObject(hev
, FALSE
, NULL
);
1394 status
= STATUS_SUCCESS
;
1399 else status
= io_control(hDevice
, hEvent
, UserApcRoutine
, UserApcContext
,
1400 piosb
, dwIoControlCode
, lpInBuffer
, nInBufferSize
,
1401 lpOutBuffer
, nOutBufferSize
);