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"
43 #ifdef HAVE_SYS_STAT_H
44 # include <sys/stat.h>
46 #include <sys/types.h>
47 #ifdef HAVE_SYS_FILIO_H
48 # include <sys/filio.h>
50 #ifdef HAVE_SYS_IOCTL_H
51 #include <sys/ioctl.h>
53 #ifdef HAVE_SYS_POLL_H
54 # include <sys/poll.h>
56 #ifdef HAVE_SYS_MODEM_H
57 # include <sys/modem.h>
59 #ifdef HAVE_SYS_STRTIO_H
60 # include <sys/strtio.h>
63 #define NONAMELESSUNION
64 #define NONAMELESSSTRUCT
66 #define WIN32_NO_STATUS
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>
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();
202 /* termios does not support DTR/DSR flow control */
203 shf
->ControlHandShake
= 0;
204 shf
->FlowReplace
= 0;
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
;
213 WARN("Setting DTR/RTS to enabled by default\n");
214 shf
->ControlHandShake
|= SERIAL_DTR_CONTROL
;
215 shf
->FlowReplace
|= SERIAL_RTS_CONTROL
;
218 if (stat
& TIOCM_DTR
)
220 shf
->ControlHandShake
|= SERIAL_DTR_CONTROL
;
222 if (port
.c_cflag
& CRTSCTS
)
224 shf
->FlowReplace
|= SERIAL_RTS_CONTROL
;
225 shf
->ControlHandShake
|= SERIAL_CTS_HANDSHAKE
;
231 if (stat
& TIOCM_RTS
)
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
;
242 return STATUS_SUCCESS
;
245 static NTSTATUS
get_line_control(int fd
, SERIAL_LINE_CONTROL
* slc
)
249 if (tcgetattr(fd
, &port
) == -1)
251 ERR("tcgetattr error '%s'\n", strerror(errno
));
252 return FILE_GetNtStatus();
256 switch (port
.c_cflag
& (PARENB
| PARODD
| CMSPAR
))
258 switch (port
.c_cflag
& (PARENB
| PARODD
))
261 case 0: slc
->Parity
= NOPARITY
; break;
262 case PARENB
: slc
->Parity
= EVENPARITY
; break;
263 case PARENB
|PARODD
: slc
->Parity
= ODDPARITY
; break;
265 case PARENB
|CMSPAR
: slc
->Parity
= MARKPARITY
; break;
266 case PARENB
|PARODD
|CMSPAR
: slc
->Parity
= SPACEPARITY
; break;
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
;
283 slc
->StopBits
= TWOSTOPBITS
;
286 slc
->StopBits
= ONESTOPBIT
;
288 return STATUS_SUCCESS
;
291 static NTSTATUS
get_modem_status(int fd
, DWORD
* lpModemStat
)
293 NTSTATUS status
= STATUS_NOT_SUPPORTED
;
298 if (!ioctl(fd
, TIOCMGET
, &mstat
))
301 if (mstat
& TIOCM_CTS
) *lpModemStat
|= MS_CTS_ON
;
304 if (mstat
& TIOCM_DSR
) *lpModemStat
|= MS_DSR_ON
;
307 if (mstat
& TIOCM_RNG
) *lpModemStat
|= MS_RING_ON
;
310 /* FIXME: Not really sure about RLSD UB 990810 */
311 if (mstat
& TIOCM_CAR
) *lpModemStat
|= MS_RLSD_ON
;
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();
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
= 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
;
394 static NTSTATUS
get_wait_mask(HANDLE hDevice
, DWORD
* mask
)
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
;
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
|= IXOFF
;
617 port
.c_iflag
&= ~IXOFF
;
618 if (shf
->FlowReplace
& SERIAL_AUTO_TRANSMIT
)
619 port
.c_iflag
|= IXON
;
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
)
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
);
666 /* make sure that reads don't block */
668 port
.c_cc
[VTIME
] = 0;
672 case NOPARITY
: port
.c_iflag
&= ~INPCK
; break;
673 case ODDPARITY
: port
.c_cflag
|= PARENB
| PARODD
; break;
674 case EVENPARITY
: port
.c_cflag
|= PARENB
; break;
676 /* Linux defines mark/space (stick) parity */
677 case MARKPARITY
: port
.c_cflag
|= PARENB
| CMSPAR
; break;
678 case SPACEPARITY
: port
.c_cflag
|= PARENB
| PARODD
| CMSPAR
; break;
680 /* try the POSIX way */
682 if (slc
->StopBits
== ONESTOPBIT
)
684 stopbits
= TWOSTOPBITS
;
685 port
.c_iflag
&= ~INPCK
;
689 ERR("Cannot set MARK Parity\n");
690 return STATUS_NOT_SUPPORTED
;
694 if (slc
->WordLength
< 8)
697 port
.c_iflag
&= ~INPCK
;
701 ERR("Cannot set SPACE Parity\n");
702 return STATUS_NOT_SUPPORTED
;
708 return STATUS_NOT_SUPPORTED
;
711 port
.c_cflag
&= ~CSIZE
;
714 case 5: port
.c_cflag
|= CS5
; break;
715 case 6: port
.c_cflag
|= CS6
; break;
716 case 7: port
.c_cflag
|= CS7
; break;
717 case 8: port
.c_cflag
|= CS8
; break;
720 return STATUS_NOT_SUPPORTED
;
725 case ONESTOPBIT
: port
.c_cflag
&= ~CSTOPB
; break;
726 case ONE5STOPBITS
: /* will be selected if bytesize is 5 */
727 case TWOSTOPBITS
: port
.c_cflag
|= CSTOPB
; break;
730 return STATUS_NOT_SUPPORTED
;
732 /* otherwise it hangs with pending input*/
733 if (tcsetattr(fd
, TCSANOW
, &port
) == -1)
735 ERR("tcsetattr error '%s'\n", strerror(errno
));
736 return FILE_GetNtStatus();
738 return STATUS_SUCCESS
;
741 static NTSTATUS
set_queue_size(int fd
, const SERIAL_QUEUE_SIZE
* sqs
)
743 FIXME("insize %d outsize %d unimplemented stub\n", sqs
->InSize
, sqs
->OutSize
);
744 return STATUS_SUCCESS
;
747 static NTSTATUS
set_special_chars(int fd
, const SERIAL_CHARS
* sc
)
751 if (tcgetattr(fd
, &port
) == -1)
753 ERR("tcgetattr error '%s'\n", strerror(errno
));
754 return FILE_GetNtStatus();
757 port
.c_cc
[VEOF
] = sc
->EofChar
;
758 /* FIXME: sc->ErrorChar is not supported */
759 /* FIXME: sc->BreakChar is not supported */
760 /* FIXME: sc->EventChar is not supported */
761 port
.c_cc
[VSTART
] = sc
->XonChar
;
762 port
.c_cc
[VSTOP
] = sc
->XoffChar
;
764 if (tcsetattr(fd
, TCSANOW
, &port
) == -1)
766 ERR("tcsetattr error '%s'\n", strerror(errno
));
767 return FILE_GetNtStatus();
769 return STATUS_SUCCESS
;
772 static NTSTATUS
set_timeouts(HANDLE handle
, const SERIAL_TIMEOUTS
* st
)
776 SERVER_START_REQ( set_serial_info
)
778 req
->handle
= wine_server_obj_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
);
791 static NTSTATUS
set_wait_mask(HANDLE hDevice
, DWORD mask
)
795 SERVER_START_REQ( set_serial_info
)
797 req
->handle
= wine_server_obj_handle( hDevice
);
798 req
->flags
= SERIALINFO_SET_MASK
;
799 req
->eventmask
= mask
;
800 status
= wine_server_call( req
);
807 * does not change IXOFF but simulates that IXOFF has been received:
809 static NTSTATUS
set_XOff(int fd
)
811 if (tcflow(fd
, TCOOFF
))
813 return FILE_GetNtStatus();
815 return STATUS_SUCCESS
;
819 * does not change IXON but simulates that IXON has been received:
821 static NTSTATUS
set_XOn(int fd
)
823 if (tcflow(fd
, TCOON
))
825 return FILE_GetNtStatus();
827 return STATUS_SUCCESS
;
831 * local structure holding the irq values we need for WaitCommEvent()
833 * Stripped down from struct serial_icounter_struct, which may not be available on some systems
834 * As the modem line interrupts (cts, dsr, rng, dcd) only get updated with TIOCMIWAIT active,
835 * no need to carry them in the internal structure
838 typedef struct serial_irq_info
840 int rx
, tx
, frame
, overrun
, parity
, brk
, buf_overrun
;
843 /***********************************************************************
844 * Data needed by the thread polling for the changing CommEvent
846 typedef struct async_commio
853 serial_irq_info irq_info
;
856 /***********************************************************************
857 * Get extended interrupt count info, needed for wait_on
859 static NTSTATUS
get_irq_info(int fd
, serial_irq_info
*irq_info
)
861 NTSTATUS status
= STATUS_NOT_IMPLEMENTED
;
863 struct serial_icounter_struct einfo
;
864 if (!ioctl(fd
, TIOCGICOUNT
, &einfo
))
866 irq_info
->rx
= einfo
.rx
;
867 irq_info
->tx
= einfo
.tx
;
868 irq_info
->frame
= einfo
.frame
;
869 irq_info
->overrun
= einfo
.overrun
;
870 irq_info
->parity
= einfo
.parity
;
871 irq_info
->brk
= einfo
.brk
;
872 irq_info
->buf_overrun
= einfo
.buf_overrun
;
873 return STATUS_SUCCESS
;
875 TRACE("TIOCGICOUNT err %s\n", strerror(errno
));
876 status
= FILE_GetNtStatus();
878 memset(irq_info
,0, sizeof(serial_irq_info
));
883 static DWORD
check_events(int fd
, DWORD mask
,
884 const serial_irq_info
*new,
885 const serial_irq_info
*old
,
886 DWORD new_mstat
, DWORD old_mstat
)
888 DWORD ret
= 0, queue
;
890 TRACE("mask 0x%08x\n", mask
);
891 TRACE("old->rx 0x%08x vs. new->rx 0x%08x\n", old
->rx
, new->rx
);
892 TRACE("old->tx 0x%08x vs. new->tx 0x%08x\n", old
->tx
, new->tx
);
893 TRACE("old->frame 0x%08x vs. new->frame 0x%08x\n", old
->frame
, new->frame
);
894 TRACE("old->overrun 0x%08x vs. new->overrun 0x%08x\n", old
->overrun
, new->overrun
);
895 TRACE("old->parity 0x%08x vs. new->parity 0x%08x\n", old
->parity
, new->parity
);
896 TRACE("old->brk 0x%08x vs. new->brk 0x%08x\n", old
->brk
, new->brk
);
897 TRACE("old->buf_overrun 0x%08x vs. new->buf_overrun 0x%08x\n", old
->buf_overrun
, new->buf_overrun
);
899 if (old
->brk
!= new->brk
) ret
|= EV_BREAK
;
900 if ((old_mstat
& MS_CTS_ON
) != (new_mstat
& MS_CTS_ON
)) ret
|= EV_CTS
;
901 if ((old_mstat
& MS_DSR_ON
) != (new_mstat
& MS_DSR_ON
)) ret
|= EV_DSR
;
902 if ((old_mstat
& MS_RING_ON
) != (new_mstat
& MS_RING_ON
)) ret
|= EV_RING
;
903 if ((old_mstat
& MS_RLSD_ON
) != (new_mstat
& MS_RLSD_ON
)) ret
|= EV_RLSD
;
904 if (old
->frame
!= new->frame
|| old
->overrun
!= new->overrun
|| old
->parity
!= new->parity
) ret
|= EV_ERR
;
905 if (mask
& EV_RXCHAR
)
909 if (ioctl(fd
, TIOCINQ
, &queue
))
910 WARN("TIOCINQ returned error\n");
915 if (mask
& EV_TXEMPTY
)
918 /* We really want to know when all characters have gone out of the transmitter */
919 #if defined(TIOCSERGETLSR)
920 if (ioctl(fd
, TIOCSERGETLSR
, &queue
))
921 WARN("TIOCSERGETLSR returned error\n");
923 /* TIOCOUTQ only checks for an empty buffer */
924 #elif defined(TIOCOUTQ)
925 if (ioctl(fd
, TIOCOUTQ
, &queue
))
926 WARN("TIOCOUTQ returned error\n");
930 TRACE("OUTQUEUE %d, Transmitter %sempty\n",
931 queue
, (ret
& EV_TXEMPTY
) ? "" : "not ");
936 /***********************************************************************
937 * wait_for_event (INTERNAL)
939 * We need to poll for what is interesting
940 * TIOCMIWAIT only checks modem status line and may not be aborted by a changing mask
943 static DWORD CALLBACK
wait_for_event(LPVOID arg
)
945 async_commio
*commio
= (async_commio
*) arg
;
948 if (!server_get_unix_fd( commio
->hDevice
, FILE_READ_DATA
| FILE_WRITE_DATA
, &fd
, &needs_close
, NULL
, NULL
))
950 serial_irq_info new_irq_info
;
951 DWORD new_mstat
, new_evtmask
;
954 TRACE("device=%p fd=0x%08x mask=0x%08x buffer=%p event=%p irq_info=%p\n",
955 commio
->hDevice
, fd
, commio
->evtmask
, commio
->events
, commio
->hEvent
, &commio
->irq_info
);
957 time
.QuadPart
= (ULONGLONG
)10000;
958 time
.QuadPart
= -time
.QuadPart
;
962 * TIOCMIWAIT is not adequate
965 * We don't handle the EV_RXFLAG (the eventchar)
967 NtDelayExecution(FALSE
, &time
);
968 get_irq_info(fd
, &new_irq_info
);
969 if (get_modem_status(fd
, &new_mstat
))
970 TRACE("get_modem_status failed\n");
971 *commio
->events
= check_events(fd
, commio
->evtmask
,
972 &new_irq_info
, &commio
->irq_info
,
973 new_mstat
, commio
->mstat
);
974 if (*commio
->events
) break;
975 get_wait_mask(commio
->hDevice
, &new_evtmask
);
976 if (commio
->evtmask
!= new_evtmask
)
982 if (needs_close
) close( fd
);
984 if (commio
->hEvent
) NtSetEvent(commio
->hEvent
, NULL
);
985 RtlFreeHeap(GetProcessHeap(), 0, commio
);
989 static NTSTATUS
wait_on(HANDLE hDevice
, int fd
, HANDLE hEvent
, DWORD
* events
)
991 async_commio
* commio
;
994 if ((status
= NtResetEvent(hEvent
, NULL
)))
997 commio
= RtlAllocateHeap(GetProcessHeap(), 0, sizeof (async_commio
));
998 if (!commio
) return STATUS_NO_MEMORY
;
1000 commio
->hDevice
= hDevice
;
1001 commio
->events
= events
;
1002 commio
->hEvent
= hEvent
;
1003 get_wait_mask(commio
->hDevice
, &commio
->evtmask
);
1005 /* We may never return, if some capabilities miss
1006 * Return error in that case
1008 #if !defined(TIOCINQ)
1009 if (commio
->evtmask
& EV_RXCHAR
)
1012 #if !(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)
1013 if (commio
->evtmask
& EV_TXEMPTY
)
1016 #if !defined(TIOCMGET)
1017 if (commio
->evtmask
& (EV_CTS
| EV_DSR
| EV_RING
| EV_RLSD
))
1020 #if !defined(TIOCM_CTS)
1021 if (commio
->evtmask
& EV_CTS
)
1024 #if !defined(TIOCM_DSR)
1025 if (commio
->evtmask
& EV_DSR
)
1028 #if !defined(TIOCM_RNG)
1029 if (commio
->evtmask
& EV_RING
)
1032 #if !defined(TIOCM_CAR)
1033 if (commio
->evtmask
& EV_RLSD
)
1036 if (commio
->evtmask
& EV_RXFLAG
)
1037 FIXME("EV_RXFLAG not handled\n");
1039 if ((status
= get_irq_info(fd
, &commio
->irq_info
)) &&
1040 (commio
->evtmask
& (EV_BREAK
| EV_ERR
)))
1043 if ((status
= get_modem_status(fd
, &commio
->mstat
)) &&
1044 (commio
->evtmask
& (EV_CTS
| EV_DSR
| EV_RING
| EV_RLSD
)))
1047 /* We might have received something or the TX buffer is delivered */
1048 *events
= check_events(fd
, commio
->evtmask
,
1049 &commio
->irq_info
, &commio
->irq_info
,
1050 commio
->mstat
, commio
->mstat
);
1053 status
= STATUS_SUCCESS
;
1057 /* create the worker for the task */
1058 status
= RtlQueueWorkItem(wait_for_event
, commio
, 0 /* FIXME */);
1059 if (status
!= STATUS_SUCCESS
) goto out_now
;
1060 return STATUS_PENDING
;
1062 #if !defined(TIOCINQ) || (!(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)) || !defined(TIOCMGET) || !defined(TIOCM_CTS) ||!defined(TIOCM_DSR) || !defined(TIOCM_RNG) || !defined(TIOCM_CAR)
1064 FIXME("Returning error because of missing capabilities\n");
1065 status
= STATUS_INVALID_PARAMETER
;
1068 RtlFreeHeap(GetProcessHeap(), 0, commio
);
1072 static NTSTATUS
xmit_immediate(HANDLE hDevice
, int fd
, const char* ptr
)
1074 /* FIXME: not perfect as it should bypass the in-queue */
1075 WARN("(%p,'%c') not perfect!\n", hDevice
, *ptr
);
1076 if (write(fd
, ptr
, 1) != 1)
1077 return FILE_GetNtStatus();
1078 return STATUS_SUCCESS
;
1081 /******************************************************************
1082 * COMM_DeviceIoControl
1086 static inline NTSTATUS
io_control(HANDLE hDevice
,
1087 HANDLE hEvent
, PIO_APC_ROUTINE UserApcRoutine
,
1088 PVOID UserApcContext
,
1089 PIO_STATUS_BLOCK piosb
,
1090 ULONG dwIoControlCode
,
1091 LPVOID lpInBuffer
, DWORD nInBufferSize
,
1092 LPVOID lpOutBuffer
, DWORD nOutBufferSize
)
1094 DWORD sz
= 0, access
= FILE_READ_DATA
;
1095 NTSTATUS status
= STATUS_SUCCESS
;
1096 int fd
= -1, needs_close
= 0;
1098 TRACE("%p %s %p %d %p %d %p\n",
1099 hDevice
, iocode2str(dwIoControlCode
), lpInBuffer
, nInBufferSize
,
1100 lpOutBuffer
, nOutBufferSize
, piosb
);
1102 piosb
->Information
= 0;
1104 if (dwIoControlCode
!= IOCTL_SERIAL_GET_TIMEOUTS
&&
1105 dwIoControlCode
!= IOCTL_SERIAL_SET_TIMEOUTS
)
1106 if ((status
= server_get_unix_fd( hDevice
, access
, &fd
, &needs_close
, NULL
, NULL
)))
1109 switch (dwIoControlCode
)
1111 case IOCTL_SERIAL_CLR_DTR
:
1113 if (whack_modem(fd
, ~TIOCM_DTR
, 0) == -1) status
= FILE_GetNtStatus();
1115 status
= STATUS_NOT_SUPPORTED
;
1118 case IOCTL_SERIAL_CLR_RTS
:
1120 if (whack_modem(fd
, ~TIOCM_RTS
, 0) == -1) status
= FILE_GetNtStatus();
1122 status
= STATUS_NOT_SUPPORTED
;
1125 case IOCTL_SERIAL_GET_BAUD_RATE
:
1126 if (lpOutBuffer
&& nOutBufferSize
== sizeof(SERIAL_BAUD_RATE
))
1128 if (!(status
= get_baud_rate(fd
, (SERIAL_BAUD_RATE
*)lpOutBuffer
)))
1129 sz
= sizeof(SERIAL_BAUD_RATE
);
1132 status
= STATUS_INVALID_PARAMETER
;
1134 case IOCTL_SERIAL_GET_CHARS
:
1135 if (lpOutBuffer
&& nOutBufferSize
== sizeof(SERIAL_CHARS
))
1137 if (!(status
= get_special_chars(fd
, (SERIAL_CHARS
*)lpOutBuffer
)))
1138 sz
= sizeof(SERIAL_CHARS
);
1141 status
= STATUS_INVALID_PARAMETER
;
1143 case IOCTL_SERIAL_GET_COMMSTATUS
:
1144 if (lpOutBuffer
&& nOutBufferSize
== sizeof(SERIAL_STATUS
))
1146 if (!(status
= get_status(fd
, (SERIAL_STATUS
*)lpOutBuffer
)))
1147 sz
= sizeof(SERIAL_STATUS
);
1149 else status
= STATUS_INVALID_PARAMETER
;
1151 case IOCTL_SERIAL_GET_HANDFLOW
:
1152 if (lpOutBuffer
&& nOutBufferSize
== sizeof(SERIAL_HANDFLOW
))
1154 if (!(status
= get_hand_flow(fd
, (SERIAL_HANDFLOW
*)lpOutBuffer
)))
1155 sz
= sizeof(SERIAL_HANDFLOW
);
1158 status
= STATUS_INVALID_PARAMETER
;
1160 case IOCTL_SERIAL_GET_LINE_CONTROL
:
1161 if (lpOutBuffer
&& nOutBufferSize
== sizeof(SERIAL_LINE_CONTROL
))
1163 if (!(status
= get_line_control(fd
, (SERIAL_LINE_CONTROL
*)lpOutBuffer
)))
1164 sz
= sizeof(SERIAL_LINE_CONTROL
);
1167 status
= STATUS_INVALID_PARAMETER
;
1169 case IOCTL_SERIAL_GET_MODEMSTATUS
:
1170 if (lpOutBuffer
&& nOutBufferSize
== sizeof(DWORD
))
1172 if (!(status
= get_modem_status(fd
, (DWORD
*)lpOutBuffer
)))
1175 else status
= STATUS_INVALID_PARAMETER
;
1177 case IOCTL_SERIAL_GET_TIMEOUTS
:
1178 if (lpOutBuffer
&& nOutBufferSize
== sizeof(SERIAL_TIMEOUTS
))
1180 if (!(status
= get_timeouts(hDevice
, (SERIAL_TIMEOUTS
*)lpOutBuffer
)))
1181 sz
= sizeof(SERIAL_TIMEOUTS
);
1184 status
= STATUS_INVALID_PARAMETER
;
1186 case IOCTL_SERIAL_GET_WAIT_MASK
:
1187 if (lpOutBuffer
&& nOutBufferSize
== sizeof(DWORD
))
1189 if (!(status
= get_wait_mask(hDevice
, (DWORD
*)lpOutBuffer
)))
1193 status
= STATUS_INVALID_PARAMETER
;
1195 case IOCTL_SERIAL_IMMEDIATE_CHAR
:
1196 if (lpInBuffer
&& nInBufferSize
== sizeof(CHAR
))
1197 status
= xmit_immediate(hDevice
, fd
, lpInBuffer
);
1199 status
= STATUS_INVALID_PARAMETER
;
1201 case IOCTL_SERIAL_PURGE
:
1202 if (lpInBuffer
&& nInBufferSize
== sizeof(DWORD
))
1203 status
= purge(fd
, *(DWORD
*)lpInBuffer
);
1205 status
= STATUS_INVALID_PARAMETER
;
1207 case IOCTL_SERIAL_RESET_DEVICE
:
1208 FIXME("Unsupported\n");
1210 case IOCTL_SERIAL_SET_BAUD_RATE
:
1211 if (lpInBuffer
&& nInBufferSize
== sizeof(SERIAL_BAUD_RATE
))
1212 status
= set_baud_rate(fd
, (const SERIAL_BAUD_RATE
*)lpInBuffer
);
1214 status
= STATUS_INVALID_PARAMETER
;
1216 case IOCTL_SERIAL_SET_BREAK_OFF
:
1217 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1218 if (ioctl(fd
, TIOCCBRK
, 0) == -1)
1220 TRACE("ioctl failed\n");
1221 status
= FILE_GetNtStatus();
1224 FIXME("ioctl not available\n");
1225 status
= STATUS_NOT_SUPPORTED
;
1228 case IOCTL_SERIAL_SET_BREAK_ON
:
1229 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1230 if (ioctl(fd
, TIOCSBRK
, 0) == -1)
1232 TRACE("ioctl failed\n");
1233 status
= FILE_GetNtStatus();
1236 FIXME("ioctl not available\n");
1237 status
= STATUS_NOT_SUPPORTED
;
1240 case IOCTL_SERIAL_SET_CHARS
:
1241 if (lpInBuffer
&& nInBufferSize
== sizeof(SERIAL_CHARS
))
1242 status
= set_special_chars(fd
, (const SERIAL_CHARS
*)lpInBuffer
);
1244 status
= STATUS_INVALID_PARAMETER
;
1246 case IOCTL_SERIAL_SET_DTR
:
1248 if (whack_modem(fd
, 0, TIOCM_DTR
) == -1) status
= FILE_GetNtStatus();
1250 status
= STATUS_NOT_SUPPORTED
;
1253 case IOCTL_SERIAL_SET_HANDFLOW
:
1254 if (lpInBuffer
&& nInBufferSize
== sizeof(SERIAL_HANDFLOW
))
1255 status
= set_handflow(fd
, (const SERIAL_HANDFLOW
*)lpInBuffer
);
1257 status
= STATUS_INVALID_PARAMETER
;
1259 case IOCTL_SERIAL_SET_LINE_CONTROL
:
1260 if (lpInBuffer
&& nInBufferSize
== sizeof(SERIAL_LINE_CONTROL
))
1261 status
= set_line_control(fd
, (const SERIAL_LINE_CONTROL
*)lpInBuffer
);
1263 status
= STATUS_INVALID_PARAMETER
;
1265 case IOCTL_SERIAL_SET_QUEUE_SIZE
:
1266 if (lpInBuffer
&& nInBufferSize
== sizeof(SERIAL_QUEUE_SIZE
))
1267 status
= set_queue_size(fd
, (const SERIAL_QUEUE_SIZE
*)lpInBuffer
);
1269 status
= STATUS_INVALID_PARAMETER
;
1271 case IOCTL_SERIAL_SET_RTS
:
1273 if (whack_modem(fd
, 0, TIOCM_RTS
) == -1) status
= FILE_GetNtStatus();
1275 status
= STATUS_NOT_SUPPORTED
;
1278 case IOCTL_SERIAL_SET_TIMEOUTS
:
1279 if (lpInBuffer
&& nInBufferSize
== sizeof(SERIAL_TIMEOUTS
))
1280 status
= set_timeouts(hDevice
, (const SERIAL_TIMEOUTS
*)lpInBuffer
);
1282 status
= STATUS_INVALID_PARAMETER
;
1284 case IOCTL_SERIAL_SET_WAIT_MASK
:
1285 if (lpInBuffer
&& nInBufferSize
== sizeof(DWORD
))
1287 status
= set_wait_mask(hDevice
, *(DWORD
*)lpInBuffer
);
1289 else status
= STATUS_INVALID_PARAMETER
;
1291 case IOCTL_SERIAL_SET_XOFF
:
1292 status
= set_XOff(fd
);
1294 case IOCTL_SERIAL_SET_XON
:
1295 status
= set_XOn(fd
);
1297 case IOCTL_SERIAL_WAIT_ON_MASK
:
1298 if (lpOutBuffer
&& nOutBufferSize
== sizeof(DWORD
))
1300 if (!(status
= wait_on(hDevice
, fd
, hEvent
, (DWORD
*)lpOutBuffer
)))
1304 status
= STATUS_INVALID_PARAMETER
;
1307 FIXME("Unsupported IOCTL %x (type=%x access=%x func=%x meth=%x)\n",
1308 dwIoControlCode
, dwIoControlCode
>> 16, (dwIoControlCode
>> 14) & 3,
1309 (dwIoControlCode
>> 2) & 0xFFF, dwIoControlCode
& 3);
1311 status
= STATUS_INVALID_PARAMETER
;
1314 if (needs_close
) close( fd
);
1316 piosb
->u
.Status
= status
;
1317 piosb
->Information
= sz
;
1318 if (hEvent
&& status
!= STATUS_PENDING
) NtSetEvent(hEvent
, NULL
);
1322 NTSTATUS
COMM_DeviceIoControl(HANDLE hDevice
,
1323 HANDLE hEvent
, PIO_APC_ROUTINE UserApcRoutine
,
1324 PVOID UserApcContext
,
1325 PIO_STATUS_BLOCK piosb
,
1326 ULONG dwIoControlCode
,
1327 LPVOID lpInBuffer
, DWORD nInBufferSize
,
1328 LPVOID lpOutBuffer
, DWORD nOutBufferSize
)
1332 if (dwIoControlCode
== IOCTL_SERIAL_WAIT_ON_MASK
)
1334 HANDLE hev
= hEvent
;
1336 /* this is an ioctl we implement in a non blocking way if hEvent is not
1338 * so we have to explicitly wait if no hEvent is provided
1342 OBJECT_ATTRIBUTES attr
;
1344 attr
.Length
= sizeof(attr
);
1345 attr
.RootDirectory
= 0;
1346 attr
.ObjectName
= NULL
;
1347 attr
.Attributes
= OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
;
1348 attr
.SecurityDescriptor
= NULL
;
1349 attr
.SecurityQualityOfService
= NULL
;
1350 status
= NtCreateEvent(&hev
, EVENT_ALL_ACCESS
, &attr
, FALSE
, FALSE
);
1352 if (status
) goto done
;
1354 status
= io_control(hDevice
, hev
, UserApcRoutine
, UserApcContext
,
1355 piosb
, dwIoControlCode
, lpInBuffer
, nInBufferSize
,
1356 lpOutBuffer
, nOutBufferSize
);
1359 if (status
== STATUS_PENDING
)
1361 NtWaitForSingleObject(hev
, FALSE
, NULL
);
1362 status
= STATUS_SUCCESS
;
1367 else status
= io_control(hDevice
, hEvent
, UserApcRoutine
, UserApcContext
,
1368 piosb
, dwIoControlCode
, lpInBuffer
, nInBufferSize
,
1369 lpOutBuffer
, nOutBufferSize
);