1 /* Main file for COMM support
3 * DEC 93 Erik Bos <erik@xs4all.nl>
4 * Copyright 1996 Marcus Meissner
5 * Copyright 2005 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 WINE_DEFAULT_DEBUG_CHANNEL(comm
);
85 static const char* iocode2str(DWORD ioc
)
89 #define X(x) case (x): return #x;
90 X(IOCTL_SERIAL_CLEAR_STATS
);
91 X(IOCTL_SERIAL_CLR_DTR
);
92 X(IOCTL_SERIAL_CLR_RTS
);
93 X(IOCTL_SERIAL_CONFIG_SIZE
);
94 X(IOCTL_SERIAL_GET_BAUD_RATE
);
95 X(IOCTL_SERIAL_GET_CHARS
);
96 X(IOCTL_SERIAL_GET_COMMSTATUS
);
97 X(IOCTL_SERIAL_GET_DTRRTS
);
98 X(IOCTL_SERIAL_GET_HANDFLOW
);
99 X(IOCTL_SERIAL_GET_LINE_CONTROL
);
100 X(IOCTL_SERIAL_GET_MODEM_CONTROL
);
101 X(IOCTL_SERIAL_GET_MODEMSTATUS
);
102 X(IOCTL_SERIAL_GET_PROPERTIES
);
103 X(IOCTL_SERIAL_GET_STATS
);
104 X(IOCTL_SERIAL_GET_TIMEOUTS
);
105 X(IOCTL_SERIAL_GET_WAIT_MASK
);
106 X(IOCTL_SERIAL_IMMEDIATE_CHAR
);
107 X(IOCTL_SERIAL_LSRMST_INSERT
);
108 X(IOCTL_SERIAL_PURGE
);
109 X(IOCTL_SERIAL_RESET_DEVICE
);
110 X(IOCTL_SERIAL_SET_BAUD_RATE
);
111 X(IOCTL_SERIAL_SET_BREAK_ON
);
112 X(IOCTL_SERIAL_SET_BREAK_OFF
);
113 X(IOCTL_SERIAL_SET_CHARS
);
114 X(IOCTL_SERIAL_SET_DTR
);
115 X(IOCTL_SERIAL_SET_FIFO_CONTROL
);
116 X(IOCTL_SERIAL_SET_HANDFLOW
);
117 X(IOCTL_SERIAL_SET_LINE_CONTROL
);
118 X(IOCTL_SERIAL_SET_MODEM_CONTROL
);
119 X(IOCTL_SERIAL_SET_QUEUE_SIZE
);
120 X(IOCTL_SERIAL_SET_RTS
);
121 X(IOCTL_SERIAL_SET_TIMEOUTS
);
122 X(IOCTL_SERIAL_SET_WAIT_MASK
);
123 X(IOCTL_SERIAL_SET_XOFF
);
124 X(IOCTL_SERIAL_SET_XON
);
125 X(IOCTL_SERIAL_WAIT_ON_MASK
);
126 X(IOCTL_SERIAL_XOFF_COUNTER
);
128 default: { static char tmp
[32]; sprintf(tmp
, "IOCTL_SERIAL_%ld\n", ioc
); return tmp
; }
132 static NTSTATUS
get_baud_rate(int fd
, SERIAL_BAUD_RATE
* sbr
)
137 if (tcgetattr(fd
, &port
) == -1)
139 ERR("tcgetattr error '%s'\n", strerror(errno
));
140 return FILE_GetNtStatus();
144 speed
= port
.c_cflag
& CBAUD
;
146 speed
= cfgetospeed(&port
);
150 case B0
: sbr
->BaudRate
= 0; break;
151 case B50
: sbr
->BaudRate
= 50; break;
152 case B75
: sbr
->BaudRate
= 75; break;
153 case B110
: sbr
->BaudRate
= 110; break;
154 case B134
: sbr
->BaudRate
= 134; break;
155 case B150
: sbr
->BaudRate
= 150; break;
156 case B200
: sbr
->BaudRate
= 200; break;
157 case B300
: sbr
->BaudRate
= 300; break;
158 case B600
: sbr
->BaudRate
= 600; break;
159 case B1200
: sbr
->BaudRate
= 1200; break;
160 case B1800
: sbr
->BaudRate
= 1800; break;
161 case B2400
: sbr
->BaudRate
= 2400; break;
162 case B4800
: sbr
->BaudRate
= 4800; break;
163 case B9600
: sbr
->BaudRate
= 9600; break;
164 case B19200
: sbr
->BaudRate
= 19200; break;
165 case B38400
: sbr
->BaudRate
= 38400; break;
167 case B57600
: sbr
->BaudRate
= 57600; break;
170 case B115200
: sbr
->BaudRate
= 115200; break;
173 case B230400
: sbr
->BaudRate
= 230400; break;
176 case B460800
: sbr
->BaudRate
= 460800; break;
179 ERR("unknown speed %x\n", speed
);
180 return STATUS_INVALID_PARAMETER
;
183 return STATUS_INVALID_PARAMETER
;
185 return STATUS_SUCCESS
;
188 static NTSTATUS
get_hand_flow(int fd
, SERIAL_HANDFLOW
* shf
)
193 if (tcgetattr(fd
, &port
) == -1)
195 ERR("tcgetattr error '%s'\n", strerror(errno
));
196 return FILE_GetNtStatus();
199 if (ioctl(fd
, TIOCMGET
, &stat
) == -1)
201 WARN("ioctl error '%s'\n", strerror(errno
));
202 stat
= DTR_CONTROL_ENABLE
| RTS_CONTROL_ENABLE
;
205 /* termios does not support DTR/DSR flow control */
206 shf
->ControlHandShake
= 0;
207 shf
->FlowReplace
= 0;
209 if (stat
& TIOCM_DTR
)
211 shf
->ControlHandShake
|= SERIAL_DTR_CONTROL
;
213 if (port
.c_cflag
& CRTSCTS
)
215 shf
->ControlHandShake
|= SERIAL_DTR_CONTROL
| SERIAL_DTR_HANDSHAKE
;
216 shf
->ControlHandShake
|= SERIAL_CTS_HANDSHAKE
;
222 if (stat
& TIOCM_RTS
)
224 shf
->ControlHandShake
|= SERIAL_RTS_CONTROL
;
226 if (port
.c_iflag
& IXON
)
227 shf
->FlowReplace
|= SERIAL_AUTO_RECEIVE
;
228 if (port
.c_iflag
& IXOFF
)
229 shf
->FlowReplace
|= SERIAL_AUTO_TRANSMIT
;
233 return STATUS_SUCCESS
;
236 static NTSTATUS
get_line_control(int fd
, SERIAL_LINE_CONTROL
* slc
)
240 if (tcgetattr(fd
, &port
) == -1)
242 ERR("tcgetattr error '%s'\n", strerror(errno
));
243 return FILE_GetNtStatus();
247 switch (port
.c_cflag
& (PARENB
| PARODD
| CMSPAR
))
249 switch (port
.c_cflag
& (PARENB
| PARODD
))
252 case 0: slc
->Parity
= NOPARITY
; break;
253 case PARENB
: slc
->Parity
= EVENPARITY
; break;
254 case PARENB
|PARODD
: slc
->Parity
= ODDPARITY
; break;
256 case PARENB
|CMSPAR
: slc
->Parity
= MARKPARITY
; break;
257 case PARENB
|PARODD
|CMSPAR
: slc
->Parity
= SPACEPARITY
; break;
261 switch (port
.c_cflag
& CSIZE
)
263 case CS5
: slc
->WordLength
= 5; break;
264 case CS6
: slc
->WordLength
= 6; break;
265 case CS7
: slc
->WordLength
= 7; break;
266 case CS8
: slc
->WordLength
= 8; break;
267 default: ERR("unknown size %x\n", port
.c_cflag
& CSIZE
);
270 if (port
.c_cflag
& CSTOPB
)
272 if (slc
->WordLength
== 5)
273 slc
->StopBits
= ONE5STOPBITS
;
275 slc
->StopBits
= TWOSTOPBITS
;
278 slc
->StopBits
= ONESTOPBIT
;
280 return STATUS_SUCCESS
;
283 static NTSTATUS
get_modem_status(int fd
, DWORD
* lpModemStat
)
285 NTSTATUS status
= STATUS_SUCCESS
;
289 if (ioctl(fd
, TIOCMGET
, &mstat
) == -1)
291 WARN("ioctl failed\n");
292 status
= FILE_GetNtStatus();
298 if (mstat
& TIOCM_CTS
) *lpModemStat
|= MS_CTS_ON
;
301 if (mstat
& TIOCM_DSR
) *lpModemStat
|= MS_DSR_ON
;
304 if (mstat
& TIOCM_RNG
) *lpModemStat
|= MS_RING_ON
;
307 /* FIXME: Not really sure about RLSD UB 990810 */
308 if (mstat
& TIOCM_CAR
) *lpModemStat
|= MS_RLSD_ON
;
310 TRACE("%04x -> %s%s%s%s\n", mstat
,
311 (*lpModemStat
& MS_RLSD_ON
) ? "MS_RLSD_ON " : "",
312 (*lpModemStat
& MS_RING_ON
) ? "MS_RING_ON " : "",
313 (*lpModemStat
& MS_DSR_ON
) ? "MS_DSR_ON " : "",
314 (*lpModemStat
& MS_CTS_ON
) ? "MS_CTS_ON " : "");
317 status
= STATUS_NOT_SUPPORTED
;
322 static NTSTATUS
get_status(int fd
, SERIAL_STATUS
* ss
)
324 NTSTATUS status
= STATUS_SUCCESS
;
328 ss
->EofReceived
= FALSE
;
329 ss
->WaitForImmediate
= FALSE
;
331 if (ioctl(fd
, TIOCOUTQ
, &ss
->AmountInOutQueue
) == -1)
333 WARN("ioctl returned error\n");
334 status
= FILE_GetNtStatus();
337 ss
->AmountInOutQueue
= 0; /* FIXME: find a different way to find out */
341 if (ioctl(fd
, TIOCINQ
, &ss
->AmountInInQueue
))
343 WARN("ioctl returned error\n");
344 status
= FILE_GetNtStatus();
347 ss
->AmountInInQueue
= 0; /* FIXME: find a different way to find out */
352 static NTSTATUS
get_wait_mask(HANDLE hDevice
, DWORD
* mask
)
356 SERVER_START_REQ( get_serial_info
)
358 req
->handle
= hDevice
;
359 if (!(status
= wine_server_call( req
)))
360 *mask
= reply
->eventmask
;
366 static NTSTATUS
purge(int fd
, DWORD flags
)
369 ** not exactly sure how these are different
370 ** Perhaps if we had our own internal queues, one flushes them
371 ** and the other flushes the kernel's buffers.
373 if (flags
& PURGE_TXABORT
) tcflush(fd
, TCOFLUSH
);
374 if (flags
& PURGE_RXABORT
) tcflush(fd
, TCIFLUSH
);
375 if (flags
& PURGE_TXCLEAR
) tcflush(fd
, TCOFLUSH
);
376 if (flags
& PURGE_RXCLEAR
) tcflush(fd
, TCIFLUSH
);
377 return STATUS_SUCCESS
;
380 static NTSTATUS
set_baud_rate(int fd
, const SERIAL_BAUD_RATE
* sbr
)
384 if (tcgetattr(fd
, &port
) == -1)
386 ERR("tcgetattr error '%s'\n", strerror(errno
));
387 return FILE_GetNtStatus();
391 port
.c_cflag
&= ~CBAUD
;
392 switch (sbr
->BaudRate
)
394 case 0: port
.c_cflag
|= B0
; break;
395 case 50: port
.c_cflag
|= B50
; break;
396 case 75: port
.c_cflag
|= B75
; break;
398 case CBR_110
: port
.c_cflag
|= B110
; break;
399 case 134: port
.c_cflag
|= B134
; break;
400 case 150: port
.c_cflag
|= B150
; break;
401 case 200: port
.c_cflag
|= B200
; break;
403 case CBR_300
: port
.c_cflag
|= B300
; break;
405 case CBR_600
: port
.c_cflag
|= B600
; break;
407 case CBR_1200
: port
.c_cflag
|= B1200
; break;
408 case 1800: port
.c_cflag
|= B1800
; break;
410 case CBR_2400
: port
.c_cflag
|= B2400
; break;
412 case CBR_4800
: port
.c_cflag
|= B4800
; break;
414 case CBR_9600
: port
.c_cflag
|= B9600
; break;
416 case CBR_19200
: port
.c_cflag
|= B19200
; break;
418 case CBR_38400
: port
.c_cflag
|= B38400
; break;
420 case 57600: port
.c_cflag
|= B57600
; break;
423 case 115200: port
.c_cflag
|= B115200
;break;
426 case 230400: port
.c_cflag
|= B230400
;break;
429 case 460800: port
.c_cflag
|= B460800
;break;
432 #if defined (HAVE_LINUX_SERIAL_H) && defined (TIOCSSERIAL)
434 struct serial_struct nuts
;
437 ioctl(fd
, TIOCGSERIAL
, &nuts
);
438 nuts
.custom_divisor
= nuts
.baud_base
/ sbr
->BaudRate
;
439 if (!(nuts
.custom_divisor
)) nuts
.custom_divisor
= 1;
440 arby
= nuts
.baud_base
/ nuts
.custom_divisor
;
441 nuts
.flags
&= ~ASYNC_SPD_MASK
;
442 nuts
.flags
|= ASYNC_SPD_CUST
;
443 WARN("You (or a program acting at your behest) have specified\n"
444 "a non-standard baud rate %ld. Wine will set the rate to %d,\n"
445 "which is as close as we can get by our present understanding of your\n"
446 "hardware. I hope you know what you are doing. Any disruption Wine\n"
447 "has caused to your linux system can be undone with setserial \n"
448 "(see man setserial). If you have incapacitated a Hayes type modem,\n"
449 "reset it and it will probably recover.\n", sbr
->BaudRate
, arby
);
450 ioctl(fd
, TIOCSSERIAL
, &nuts
);
451 port
.c_cflag
|= B38400
;
454 #endif /* Don't have linux/serial.h or lack TIOCSSERIAL */
455 ERR("baudrate %ld\n", sbr
->BaudRate
);
456 return STATUS_NOT_SUPPORTED
;
458 #elif !defined(__EMX__)
459 switch (sbr
->BaudRate
)
461 case 0: port
.c_ospeed
= B0
; break;
462 case 50: port
.c_ospeed
= B50
; break;
463 case 75: port
.c_ospeed
= B75
; break;
465 case CBR_110
: port
.c_ospeed
= B110
; break;
466 case 134: port
.c_ospeed
= B134
; break;
467 case 150: port
.c_ospeed
= B150
; break;
468 case 200: port
.c_ospeed
= B200
; break;
470 case CBR_300
: port
.c_ospeed
= B300
; break;
472 case CBR_600
: port
.c_ospeed
= B600
; break;
474 case CBR_1200
: port
.c_ospeed
= B1200
; break;
475 case 1800: port
.c_ospeed
= B1800
; break;
477 case CBR_2400
: port
.c_ospeed
= B2400
; break;
479 case CBR_4800
: port
.c_ospeed
= B4800
; break;
481 case CBR_9600
: port
.c_ospeed
= B9600
; break;
483 case CBR_19200
: port
.c_ospeed
= B19200
; break;
485 case CBR_38400
: port
.c_ospeed
= B38400
; break;
488 case CBR_57600
: port
.c_cflag
|= B57600
; break;
492 case CBR_115200
: port
.c_cflag
|= B115200
;break;
495 case 230400: port
.c_cflag
|= B230400
;break;
498 case 460800: port
.c_cflag
|= B460800
;break;
501 ERR("baudrate %ld\n", sbr
->BaudRate
);
502 return STATUS_NOT_SUPPORTED
;
504 port
.c_ispeed
= port
.c_ospeed
;
506 if (tcsetattr(fd
, TCSANOW
, &port
) == -1)
508 ERR("tcsetattr error '%s'\n", strerror(errno
));
509 return FILE_GetNtStatus();
511 return STATUS_SUCCESS
;
514 static int whack_modem(int fd
, unsigned int andy
, unsigned int orrie
)
517 unsigned int mstat
, okay
;
518 okay
= ioctl(fd
, TIOCMGET
, &mstat
);
519 if (okay
) return okay
;
520 if (andy
) mstat
&= andy
;
522 return ioctl(fd
, TIOCMSET
, &mstat
);
528 static NTSTATUS
set_handflow(int fd
, const SERIAL_HANDFLOW
* shf
)
532 if ((shf
->FlowReplace
& (SERIAL_RTS_CONTROL
| SERIAL_RTS_HANDSHAKE
)) ==
533 (SERIAL_RTS_CONTROL
| SERIAL_RTS_HANDSHAKE
))
534 return STATUS_NOT_SUPPORTED
;
536 if (tcgetattr(fd
, &port
) == -1)
538 ERR("tcgetattr error '%s'\n", strerror(errno
));
539 return FILE_GetNtStatus();
543 if ((shf
->ControlHandShake
& SERIAL_CTS_HANDSHAKE
) ||
544 (shf
->FlowReplace
& SERIAL_RTS_HANDSHAKE
))
546 port
.c_cflag
|= CRTSCTS
;
550 port
.c_cflag
&= ~CRTSCTS
;
553 if (shf
->ControlHandShake
& SERIAL_DTR_HANDSHAKE
)
555 WARN("DSR/DTR flow control not supported\n");
556 } else if (shf
->ControlHandShake
& SERIAL_DTR_CONTROL
)
557 whack_modem(fd
, ~TIOCM_DTR
, 0);
559 whack_modem(fd
, 0, TIOCM_DTR
);
562 if (!(shf
->ControlHandShake
& SERIAL_DSR_HANDSHAKE
))
564 if ((shf
->FlowReplace
& (SERIAL_RTS_CONTROL
|SERIAL_RTS_HANDSHAKE
)) == 0)
565 whack_modem(fd
, ~TIOCM_RTS
, 0);
567 whack_modem(fd
, 0, TIOCM_RTS
);
571 if (shf
->FlowReplace
& SERIAL_AUTO_RECEIVE
)
572 port
.c_iflag
|= IXON
;
574 port
.c_iflag
&= ~IXON
;
575 if (shf
->FlowReplace
& SERIAL_AUTO_TRANSMIT
)
576 port
.c_iflag
|= IXOFF
;
578 port
.c_iflag
&= ~IXOFF
;
579 if (tcsetattr(fd
, TCSANOW
, &port
) == -1)
581 ERR("tcsetattr error '%s'\n", strerror(errno
));
582 return FILE_GetNtStatus();
585 return STATUS_SUCCESS
;
588 static NTSTATUS
set_line_control(int fd
, const SERIAL_LINE_CONTROL
* slc
)
591 unsigned bytesize
, stopbits
;
593 if (tcgetattr(fd
, &port
) == -1)
595 ERR("tcgetattr error '%s'\n", strerror(errno
));
596 return FILE_GetNtStatus();
600 port
.c_iflag
&= ~(ISTRIP
|BRKINT
|IGNCR
|ICRNL
|INLCR
|PARMRK
|IMAXBEL
);
602 port
.c_iflag
&= ~(ISTRIP
|BRKINT
|IGNCR
|ICRNL
|INLCR
|PARMRK
);
604 port
.c_iflag
|= IGNBRK
| INPCK
;
606 port
.c_oflag
&= ~(OPOST
);
608 port
.c_cflag
&= ~(HUPCL
);
609 port
.c_cflag
|= CLOCAL
| CREAD
;
611 port
.c_lflag
&= ~(ICANON
|ECHO
|ISIG
);
612 port
.c_lflag
|= NOFLSH
;
614 bytesize
= slc
->WordLength
;
615 stopbits
= slc
->StopBits
;
618 port
.c_cflag
&= ~(PARENB
| PARODD
| CMSPAR
);
620 port
.c_cflag
&= ~(PARENB
| PARODD
);
625 case NOPARITY
: port
.c_iflag
&= ~INPCK
; break;
626 case ODDPARITY
: port
.c_cflag
|= PARENB
| PARODD
; break;
627 case EVENPARITY
: port
.c_cflag
|= PARENB
; break;
629 /* Linux defines mark/space (stick) parity */
630 case MARKPARITY
: port
.c_cflag
|= PARENB
| CMSPAR
; break;
631 case SPACEPARITY
: port
.c_cflag
|= PARENB
| PARODD
| CMSPAR
; break;
633 /* try the POSIX way */
635 if (slc
->StopBits
== ONESTOPBIT
)
637 stopbits
= TWOSTOPBITS
;
638 port
.c_iflag
&= ~INPCK
;
642 ERR("Cannot set MARK Parity\n");
643 return STATUS_NOT_SUPPORTED
;
647 if (slc
->WordLength
< 8)
650 port
.c_iflag
&= ~INPCK
;
654 ERR("Cannot set SPACE Parity\n");
655 return STATUS_NOT_SUPPORTED
;
661 return STATUS_NOT_SUPPORTED
;
664 port
.c_cflag
&= ~CSIZE
;
667 case 5: port
.c_cflag
|= CS5
; break;
668 case 6: port
.c_cflag
|= CS6
; break;
669 case 7: port
.c_cflag
|= CS7
; break;
670 case 8: port
.c_cflag
|= CS8
; break;
673 return STATUS_NOT_SUPPORTED
;
678 case ONESTOPBIT
: port
.c_cflag
&= ~CSTOPB
; break;
679 case ONE5STOPBITS
: /* will be selected if bytesize is 5 */
680 case TWOSTOPBITS
: port
.c_cflag
|= CSTOPB
; break;
683 return STATUS_NOT_SUPPORTED
;
685 /* otherwise it hangs with pending input*/
686 if (tcsetattr(fd
, TCSANOW
, &port
) == -1)
688 ERR("tcsetattr error '%s'\n", strerror(errno
));
689 return FILE_GetNtStatus();
691 return STATUS_SUCCESS
;
694 static NTSTATUS
set_special_chars(int fd
, const SERIAL_CHARS
* sc
)
698 if (tcgetattr(fd
, &port
) == -1)
700 ERR("tcgetattr error '%s'\n", strerror(errno
));
701 return FILE_GetNtStatus();
704 port
.c_cc
[VMIN
] = 0;
705 port
.c_cc
[VTIME
] = 1;
707 port
.c_cc
[VEOF
] = sc
->EofChar
;
708 /* FIXME: sc->ErrorChar is not supported */
709 /* FIXME: sc->BreakChar is not supported */
710 /* FIXME: sc->EventChar is not supported */
711 port
.c_cc
[VSTART
] = sc
->XonChar
;
712 port
.c_cc
[VSTOP
] = sc
->XoffChar
;
714 if (tcsetattr(fd
, TCSANOW
, &port
) == -1)
716 ERR("tcsetattr error '%s'\n", strerror(errno
));
717 return FILE_GetNtStatus();
719 return STATUS_SUCCESS
;
722 static NTSTATUS
set_wait_mask(HANDLE hDevice
, DWORD mask
)
726 SERVER_START_REQ( set_serial_info
)
728 req
->handle
= hDevice
;
729 req
->flags
= SERIALINFO_SET_MASK
;
730 req
->eventmask
= mask
;
731 status
= wine_server_call( req
);
737 static NTSTATUS
xmit_immediate(HANDLE hDevice
, int fd
, char* ptr
)
739 /* FIXME: not perfect as it should bypass the in-queue */
740 WARN("(%p,'%c') not perfect!\n", hDevice
, *ptr
);
741 if (write(fd
, ptr
, 1) != 1)
742 return FILE_GetNtStatus();
743 return STATUS_SUCCESS
;
746 /******************************************************************
747 * COMM_DeviceIoControl
751 NTSTATUS
COMM_DeviceIoControl(HANDLE hDevice
,
752 HANDLE hEvent
, PIO_APC_ROUTINE UserApcRoutine
,
753 PVOID UserApcContext
,
754 PIO_STATUS_BLOCK piosb
,
755 ULONG dwIoControlCode
,
756 LPVOID lpInBuffer
, DWORD nInBufferSize
,
757 LPVOID lpOutBuffer
, DWORD nOutBufferSize
)
759 DWORD sz
= 0, access
= FILE_READ_DATA
;
760 NTSTATUS status
= STATUS_SUCCESS
;
763 TRACE("%p %s %p %ld %p %ld %p\n",
764 hDevice
, iocode2str(dwIoControlCode
), lpInBuffer
, nInBufferSize
,
765 lpOutBuffer
, nOutBufferSize
, piosb
);
767 piosb
->Information
= 0;
769 if ((status
= wine_server_handle_to_fd( hDevice
, access
, &fd
, NULL
))) goto error
;
771 switch (dwIoControlCode
)
773 case IOCTL_SERIAL_GET_BAUD_RATE
:
774 if (lpOutBuffer
&& nOutBufferSize
== sizeof(SERIAL_BAUD_RATE
))
776 if (!(status
= get_baud_rate(fd
, (SERIAL_BAUD_RATE
*)lpOutBuffer
)))
777 sz
= sizeof(SERIAL_BAUD_RATE
);
780 status
= STATUS_INVALID_PARAMETER
;
782 case IOCTL_SERIAL_GET_COMMSTATUS
:
783 if (lpOutBuffer
&& nOutBufferSize
== sizeof(SERIAL_STATUS
))
785 if (!(status
= get_status(fd
, (SERIAL_STATUS
*)lpOutBuffer
)))
786 sz
= sizeof(SERIAL_STATUS
);
788 else status
= STATUS_INVALID_PARAMETER
;
790 case IOCTL_SERIAL_GET_HANDFLOW
:
791 if (lpOutBuffer
&& nOutBufferSize
== sizeof(SERIAL_HANDFLOW
))
793 if (!(status
= get_hand_flow(fd
, (SERIAL_HANDFLOW
*)lpOutBuffer
)))
794 sz
= sizeof(SERIAL_HANDFLOW
);
797 status
= STATUS_INVALID_PARAMETER
;
799 case IOCTL_SERIAL_GET_LINE_CONTROL
:
800 if (lpOutBuffer
&& nOutBufferSize
== sizeof(SERIAL_LINE_CONTROL
))
802 if (!(status
= get_line_control(fd
, (SERIAL_LINE_CONTROL
*)lpOutBuffer
)))
803 sz
= sizeof(SERIAL_LINE_CONTROL
);
806 status
= STATUS_INVALID_PARAMETER
;
808 case IOCTL_SERIAL_GET_MODEMSTATUS
:
809 if (lpOutBuffer
&& nOutBufferSize
== sizeof(DWORD
))
811 if (!(status
= get_modem_status(fd
, (DWORD
*)lpOutBuffer
)))
814 else status
= STATUS_INVALID_PARAMETER
;
816 case IOCTL_SERIAL_GET_WAIT_MASK
:
817 if (lpOutBuffer
&& nOutBufferSize
== sizeof(DWORD
))
819 if (!(status
= get_wait_mask(hDevice
, (DWORD
*)lpOutBuffer
)))
823 status
= STATUS_INVALID_PARAMETER
;
825 case IOCTL_SERIAL_IMMEDIATE_CHAR
:
826 if (lpInBuffer
&& nInBufferSize
== sizeof(CHAR
))
827 status
= xmit_immediate(hDevice
, fd
, lpInBuffer
);
829 status
= STATUS_INVALID_PARAMETER
;
831 case IOCTL_SERIAL_PURGE
:
832 if (lpInBuffer
&& nInBufferSize
== sizeof(DWORD
))
833 status
= purge(fd
, *(DWORD
*)lpInBuffer
);
835 status
= STATUS_INVALID_PARAMETER
;
837 case IOCTL_SERIAL_SET_BAUD_RATE
:
838 if (lpInBuffer
&& nInBufferSize
== sizeof(SERIAL_BAUD_RATE
))
839 status
= set_baud_rate(fd
, (const SERIAL_BAUD_RATE
*)lpInBuffer
);
841 status
= STATUS_INVALID_PARAMETER
;
843 case IOCTL_SERIAL_SET_BREAK_OFF
:
844 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
845 if (ioctl(fd
, TIOCCBRK
, 0) == -1)
847 TRACE("ioctl failed\n");
848 status
= FILE_GetNtStatus();
851 FIXME("ioctl not available\n");
852 status
= STATUS_NOT_SUPPORTED
;
855 case IOCTL_SERIAL_SET_BREAK_ON
:
856 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
857 if (ioctl(fd
, TIOCSBRK
, 0) == -1)
859 TRACE("ioctl failed\n");
860 status
= FILE_GetNtStatus();
863 FIXME("ioctl not available\n");
864 status
= STATUS_NOT_SUPPORTED
;
867 case IOCTL_SERIAL_SET_CHARS
:
868 if (lpInBuffer
&& nInBufferSize
== sizeof(SERIAL_CHARS
))
869 status
= set_special_chars(fd
, (const SERIAL_CHARS
*)lpInBuffer
);
871 status
= STATUS_INVALID_PARAMETER
;
873 case IOCTL_SERIAL_SET_HANDFLOW
:
874 if (lpInBuffer
&& nInBufferSize
== sizeof(SERIAL_HANDFLOW
))
875 status
= set_handflow(fd
, (const SERIAL_HANDFLOW
*)lpInBuffer
);
877 status
= STATUS_INVALID_PARAMETER
;
879 case IOCTL_SERIAL_SET_LINE_CONTROL
:
880 if (lpInBuffer
&& nInBufferSize
== sizeof(SERIAL_LINE_CONTROL
))
881 status
= set_line_control(fd
, (const SERIAL_LINE_CONTROL
*)lpInBuffer
);
883 status
= STATUS_INVALID_PARAMETER
;
885 case IOCTL_SERIAL_SET_WAIT_MASK
:
886 if (lpInBuffer
&& nInBufferSize
== sizeof(DWORD
))
888 status
= set_wait_mask(hDevice
, *(DWORD
*)lpInBuffer
);
890 else status
= STATUS_INVALID_PARAMETER
;
893 FIXME("Unsupported IOCTL %lx (type=%lx access=%lx func=%lx meth=%lx)\n",
894 dwIoControlCode
, dwIoControlCode
>> 16, (dwIoControlCode
>> 14) & 3,
895 (dwIoControlCode
>> 2) & 0xFFF, dwIoControlCode
& 3);
897 status
= STATUS_INVALID_PARAMETER
;
900 wine_server_release_fd( hDevice
, fd
);
902 piosb
->u
.Status
= status
;
903 piosb
->Information
= sz
;
904 if (hEvent
) NtSetEvent(hEvent
, NULL
);