ntdll/kernel32: GetCommState & IOCTL_SERIAL_GET_HANDFLOW
[wine/testsucceed.git] / dlls / ntdll / serial.c
blob65eafd2dca992422864501985addd843bcae9b27
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
22 #include "config.h"
23 #include "wine/port.h"
25 #include <errno.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30 #ifdef HAVE_STRINGS_H
31 # include <strings.h>
32 #endif
33 #ifdef HAVE_TERMIOS_H
34 #include <termios.h>
35 #endif
36 #ifdef HAVE_IO_H
37 # include <io.h>
38 #endif
39 #ifdef HAVE_UNISTD_H
40 # include <unistd.h>
41 #endif
42 #ifdef HAVE_TERMIOS_H
43 #include <termios.h>
44 #endif
45 #include <fcntl.h>
46 #ifdef HAVE_SYS_STAT_H
47 # include <sys/stat.h>
48 #endif
49 #include <sys/types.h>
50 #ifdef HAVE_SYS_FILIO_H
51 # include <sys/filio.h>
52 #endif
53 #ifdef HAVE_SYS_IOCTL_H
54 #include <sys/ioctl.h>
55 #endif
56 #ifdef HAVE_SYS_POLL_H
57 # include <sys/poll.h>
58 #endif
59 #ifdef HAVE_SYS_MODEM_H
60 # include <sys/modem.h>
61 #endif
62 #ifdef HAVE_SYS_STRTIO_H
63 # include <sys/strtio.h>
64 #endif
66 #define NONAMELESSUNION
67 #define NONAMELESSSTRUCT
68 #include "ntstatus.h"
69 #define WIN32_NO_STATUS
70 #include "windef.h"
71 #include "winternl.h"
72 #include "winioctl.h"
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>
81 #endif
83 WINE_DEFAULT_DEBUG_CHANNEL(comm);
85 static const char* iocode2str(DWORD ioc)
87 switch (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);
127 #undef X
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)
134 struct termios port;
135 int speed;
137 if (tcgetattr(fd, &port) == -1)
139 ERR("tcgetattr error '%s'\n", strerror(errno));
140 return FILE_GetNtStatus();
142 #ifndef __EMX__
143 #ifdef CBAUD
144 speed = port.c_cflag & CBAUD;
145 #else
146 speed = cfgetospeed(&port);
147 #endif
148 switch (speed)
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;
166 #ifdef B57600
167 case B57600: sbr->BaudRate = 57600; break;
168 #endif
169 #ifdef B115200
170 case B115200: sbr->BaudRate = 115200; break;
171 #endif
172 #ifdef B230400
173 case B230400: sbr->BaudRate = 230400; break;
174 #endif
175 #ifdef B460800
176 case B460800: sbr->BaudRate = 460800; break;
177 #endif
178 default:
179 ERR("unknown speed %x\n", speed);
180 return STATUS_INVALID_PARAMETER;
182 #else
183 return STATUS_INVALID_PARAMETER;
184 #endif
185 return STATUS_SUCCESS;
188 static NTSTATUS get_hand_flow(int fd, SERIAL_HANDFLOW* shf)
190 int stat;
191 struct termios port;
193 if (tcgetattr(fd, &port) == -1)
195 ERR("tcgetattr error '%s'\n", strerror(errno));
196 return FILE_GetNtStatus();
198 #ifdef TIOCMGET
199 if (ioctl(fd, TIOCMGET, &stat) == -1)
201 WARN("ioctl error '%s'\n", strerror(errno));
202 stat = DTR_CONTROL_ENABLE | RTS_CONTROL_ENABLE;
204 #endif
205 /* termios does not support DTR/DSR flow control */
206 shf->ControlHandShake = 0;
207 shf->FlowReplace = 0;
208 #ifdef TIOCM_DTR
209 if (stat & TIOCM_DTR)
210 #endif
211 shf->ControlHandShake |= SERIAL_DTR_CONTROL;
212 #ifdef CRTSCTS
213 if (port.c_cflag & CRTSCTS)
215 shf->ControlHandShake |= SERIAL_DTR_CONTROL | SERIAL_DTR_HANDSHAKE;
216 shf->ControlHandShake |= SERIAL_CTS_HANDSHAKE;
218 else
219 #endif
221 #ifdef TIOCM_RTS
222 if (stat & TIOCM_RTS)
223 #endif
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;
231 shf->XonLimit = 10;
232 shf->XoffLimit = 10;
233 return STATUS_SUCCESS;
236 static NTSTATUS get_line_control(int fd, SERIAL_LINE_CONTROL* slc)
238 struct termios port;
240 if (tcgetattr(fd, &port) == -1)
242 ERR("tcgetattr error '%s'\n", strerror(errno));
243 return FILE_GetNtStatus();
246 #ifdef CMSPAR
247 switch (port.c_cflag & (PARENB | PARODD | CMSPAR))
248 #else
249 switch (port.c_cflag & (PARENB | PARODD))
250 #endif
252 case 0: slc->Parity = NOPARITY; break;
253 case PARENB: slc->Parity = EVENPARITY; break;
254 case PARENB|PARODD: slc->Parity = ODDPARITY; break;
255 #ifdef CMSPAR
256 case PARENB|CMSPAR: slc->Parity = MARKPARITY; break;
257 case PARENB|PARODD|CMSPAR: slc->Parity = SPACEPARITY; break;
258 break;
259 #endif
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;
274 else
275 slc->StopBits = TWOSTOPBITS;
277 else
278 slc->StopBits = ONESTOPBIT;
280 return STATUS_SUCCESS;
283 static NTSTATUS get_modem_status(int fd, DWORD* lpModemStat)
285 NTSTATUS status = STATUS_SUCCESS;
286 int mstat;
288 #ifdef TIOCMGET
289 if (ioctl(fd, TIOCMGET, &mstat) == -1)
291 WARN("ioctl failed\n");
292 status = FILE_GetNtStatus();
294 else
296 *lpModemStat = 0;
297 #ifdef TIOCM_CTS
298 if (mstat & TIOCM_CTS) *lpModemStat |= MS_CTS_ON;
299 #endif
300 #ifdef TIOCM_DSR
301 if (mstat & TIOCM_DSR) *lpModemStat |= MS_DSR_ON;
302 #endif
303 #ifdef TIOCM_RNG
304 if (mstat & TIOCM_RNG) *lpModemStat |= MS_RING_ON;
305 #endif
306 #ifdef TIOCM_CAR
307 /* FIXME: Not really sure about RLSD UB 990810 */
308 if (mstat & TIOCM_CAR) *lpModemStat |= MS_RLSD_ON;
309 #endif
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 " : "");
316 #else
317 status = STATUS_NOT_SUPPORTED;
318 #endif
319 return status;
322 static NTSTATUS get_status(int fd, SERIAL_STATUS* ss)
324 NTSTATUS status = STATUS_SUCCESS;
326 ss->Errors = 0;
327 ss->HoldReasons = 0;
328 ss->EofReceived = FALSE;
329 ss->WaitForImmediate = FALSE;
330 #ifdef TIOCOUTQ
331 if (ioctl(fd, TIOCOUTQ, &ss->AmountInOutQueue) == -1)
333 WARN("ioctl returned error\n");
334 status = FILE_GetNtStatus();
336 #else
337 ss->AmountInOutQueue = 0; /* FIXME: find a different way to find out */
338 #endif
340 #ifdef TIOCINQ
341 if (ioctl(fd, TIOCINQ, &ss->AmountInInQueue))
343 WARN("ioctl returned error\n");
344 status = FILE_GetNtStatus();
346 #else
347 ss->AmountInInQueue = 0; /* FIXME: find a different way to find out */
348 #endif
349 return status;
352 static NTSTATUS get_wait_mask(HANDLE hDevice, DWORD* mask)
354 NTSTATUS status;
356 SERVER_START_REQ( get_serial_info )
358 req->handle = hDevice;
359 if (!(status = wine_server_call( req )))
360 *mask = reply->eventmask;
362 SERVER_END_REQ;
363 return status;
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)
382 struct termios port;
384 if (tcgetattr(fd, &port) == -1)
386 ERR("tcgetattr error '%s'\n", strerror(errno));
387 return FILE_GetNtStatus();
390 #ifdef CBAUD
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;
397 case 110:
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;
402 case 300:
403 case CBR_300: port.c_cflag |= B300; break;
404 case 600:
405 case CBR_600: port.c_cflag |= B600; break;
406 case 1200:
407 case CBR_1200: port.c_cflag |= B1200; break;
408 case 1800: port.c_cflag |= B1800; break;
409 case 2400:
410 case CBR_2400: port.c_cflag |= B2400; break;
411 case 4800:
412 case CBR_4800: port.c_cflag |= B4800; break;
413 case 9600:
414 case CBR_9600: port.c_cflag |= B9600; break;
415 case 19200:
416 case CBR_19200: port.c_cflag |= B19200; break;
417 case 38400:
418 case CBR_38400: port.c_cflag |= B38400; break;
419 #ifdef B57600
420 case 57600: port.c_cflag |= B57600; break;
421 #endif
422 #ifdef B115200
423 case 115200: port.c_cflag |= B115200;break;
424 #endif
425 #ifdef B230400
426 case 230400: port.c_cflag |= B230400;break;
427 #endif
428 #ifdef B460800
429 case 460800: port.c_cflag |= B460800;break;
430 #endif
431 default:
432 #if defined (HAVE_LINUX_SERIAL_H) && defined (TIOCSSERIAL)
434 struct serial_struct nuts;
435 int arby;
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;
453 break;
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;
464 case 110:
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;
469 case 300:
470 case CBR_300: port.c_ospeed = B300; break;
471 case 600:
472 case CBR_600: port.c_ospeed = B600; break;
473 case 1200:
474 case CBR_1200: port.c_ospeed = B1200; break;
475 case 1800: port.c_ospeed = B1800; break;
476 case 2400:
477 case CBR_2400: port.c_ospeed = B2400; break;
478 case 4800:
479 case CBR_4800: port.c_ospeed = B4800; break;
480 case 9600:
481 case CBR_9600: port.c_ospeed = B9600; break;
482 case 19200:
483 case CBR_19200: port.c_ospeed = B19200; break;
484 case 38400:
485 case CBR_38400: port.c_ospeed = B38400; break;
486 #ifdef B57600
487 case 57600:
488 case CBR_57600: port.c_cflag |= B57600; break;
489 #endif
490 #ifdef B115200
491 case 115200:
492 case CBR_115200: port.c_cflag |= B115200;break;
493 #endif
494 #ifdef B230400
495 case 230400: port.c_cflag |= B230400;break;
496 #endif
497 #ifdef B460800
498 case 460800: port.c_cflag |= B460800;break;
499 #endif
500 default:
501 ERR("baudrate %ld\n", sbr->BaudRate);
502 return STATUS_NOT_SUPPORTED;
504 port.c_ispeed = port.c_ospeed;
505 #endif
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)
516 #ifdef TIOCMGET
517 unsigned int mstat, okay;
518 okay = ioctl(fd, TIOCMGET, &mstat);
519 if (okay) return okay;
520 if (andy) mstat &= andy;
521 mstat |= orrie;
522 return ioctl(fd, TIOCMSET, &mstat);
523 #else
524 return 0;
525 #endif
528 static NTSTATUS set_handflow(int fd, const SERIAL_HANDFLOW* shf)
530 struct termios port;
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();
542 #ifdef CRTSCTS
543 if ((shf->ControlHandShake & SERIAL_CTS_HANDSHAKE) ||
544 (shf->FlowReplace & SERIAL_RTS_HANDSHAKE))
546 port.c_cflag |= CRTSCTS;
547 TRACE("CRTSCTS\n");
549 else
550 port.c_cflag &= ~CRTSCTS;
551 #endif
552 #ifdef TIOCM_DTR
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);
558 else
559 whack_modem(fd, 0, TIOCM_DTR);
560 #endif
561 #ifdef TIOCM_RTS
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);
566 else
567 whack_modem(fd, 0, TIOCM_RTS);
569 #endif
571 if (shf->FlowReplace & SERIAL_AUTO_RECEIVE)
572 port.c_iflag |= IXON;
573 else
574 port.c_iflag &= ~IXON;
575 if (shf->FlowReplace & SERIAL_AUTO_TRANSMIT)
576 port.c_iflag |= IXOFF;
577 else
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)
590 struct termios port;
591 unsigned bytesize, stopbits;
593 if (tcgetattr(fd, &port) == -1)
595 ERR("tcgetattr error '%s'\n", strerror(errno));
596 return FILE_GetNtStatus();
599 #ifdef IMAXBEL
600 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK|IMAXBEL);
601 #else
602 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK);
603 #endif
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;
617 #ifdef CMSPAR
618 port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
619 #else
620 port.c_cflag &= ~(PARENB | PARODD);
621 #endif
623 switch (slc->Parity)
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;
628 #ifdef CMSPAR
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;
632 #else
633 /* try the POSIX way */
634 case MARKPARITY:
635 if (slc->StopBits == ONESTOPBIT)
637 stopbits = TWOSTOPBITS;
638 port.c_iflag &= ~INPCK;
640 else
642 ERR("Cannot set MARK Parity\n");
643 return STATUS_NOT_SUPPORTED;
645 break;
646 case SPACEPARITY:
647 if (slc->WordLength < 8)
649 bytesize +=1;
650 port.c_iflag &= ~INPCK;
652 else
654 ERR("Cannot set SPACE Parity\n");
655 return STATUS_NOT_SUPPORTED;
657 break;
658 #endif
659 default:
660 ERR("Parity\n");
661 return STATUS_NOT_SUPPORTED;
664 port.c_cflag &= ~CSIZE;
665 switch (bytesize)
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;
671 default:
672 ERR("ByteSize\n");
673 return STATUS_NOT_SUPPORTED;
676 switch (stopbits)
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;
681 default:
682 ERR("StopBits\n");
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)
696 struct termios port;
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)
724 NTSTATUS status;
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 );
733 SERVER_END_REQ;
734 return status;
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;
761 int fd;
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);
779 else
780 status = STATUS_INVALID_PARAMETER;
781 break;
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;
789 break;
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);
796 else
797 status = STATUS_INVALID_PARAMETER;
798 break;
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);
805 else
806 status = STATUS_INVALID_PARAMETER;
807 break;
808 case IOCTL_SERIAL_GET_MODEMSTATUS:
809 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
811 if (!(status = get_modem_status(fd, (DWORD*)lpOutBuffer)))
812 sz = sizeof(DWORD);
814 else status = STATUS_INVALID_PARAMETER;
815 break;
816 case IOCTL_SERIAL_GET_WAIT_MASK:
817 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
819 if (!(status = get_wait_mask(hDevice, (DWORD*)lpOutBuffer)))
820 sz = sizeof(DWORD);
822 else
823 status = STATUS_INVALID_PARAMETER;
824 break;
825 case IOCTL_SERIAL_IMMEDIATE_CHAR:
826 if (lpInBuffer && nInBufferSize == sizeof(CHAR))
827 status = xmit_immediate(hDevice, fd, lpInBuffer);
828 else
829 status = STATUS_INVALID_PARAMETER;
830 break;
831 case IOCTL_SERIAL_PURGE:
832 if (lpInBuffer && nInBufferSize == sizeof(DWORD))
833 status = purge(fd, *(DWORD*)lpInBuffer);
834 else
835 status = STATUS_INVALID_PARAMETER;
836 break;
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);
840 else
841 status = STATUS_INVALID_PARAMETER;
842 break;
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();
850 #else
851 FIXME("ioctl not available\n");
852 status = STATUS_NOT_SUPPORTED;
853 #endif
854 break;
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();
862 #else
863 FIXME("ioctl not available\n");
864 status = STATUS_NOT_SUPPORTED;
865 #endif
866 break;
867 case IOCTL_SERIAL_SET_CHARS:
868 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_CHARS))
869 status = set_special_chars(fd, (const SERIAL_CHARS*)lpInBuffer);
870 else
871 status = STATUS_INVALID_PARAMETER;
872 break;
873 case IOCTL_SERIAL_SET_HANDFLOW:
874 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_HANDFLOW))
875 status = set_handflow(fd, (const SERIAL_HANDFLOW*)lpInBuffer);
876 else
877 status = STATUS_INVALID_PARAMETER;
878 break;
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);
882 else
883 status = STATUS_INVALID_PARAMETER;
884 break;
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;
891 break;
892 default:
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);
896 sz = 0;
897 status = STATUS_INVALID_PARAMETER;
898 break;
900 wine_server_release_fd( hDevice, fd );
901 error:
902 piosb->u.Status = status;
903 piosb->Information = sz;
904 if (hEvent) NtSetEvent(hEvent, NULL);
905 return status;