winspool/tests: Use 0xdeadbeef as magic value.
[wine.git] / dlls / ntdll / serial.c
blobe66353160d1481d6a7e4bf0e7a955fedf50e34fb
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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_special_chars(int fd, SERIAL_CHARS* sc)
324 struct termios port;
326 if (tcgetattr(fd, &port) == -1)
328 ERR("tcgetattr error '%s'\n", strerror(errno));
329 return FILE_GetNtStatus();
331 sc->EofChar = port.c_cc[VEOF];
332 sc->ErrorChar = 0xFF;
333 sc->BreakChar = 0; /* FIXME */
334 sc->EventChar = 0; /* FIXME */
335 sc->XonChar = port.c_cc[VSTART];
336 sc->XoffChar = port.c_cc[VSTOP];
338 return STATUS_SUCCESS;
341 static NTSTATUS get_status(int fd, SERIAL_STATUS* ss)
343 NTSTATUS status = STATUS_SUCCESS;
345 ss->Errors = 0;
346 ss->HoldReasons = 0;
347 ss->EofReceived = FALSE;
348 ss->WaitForImmediate = FALSE;
349 #ifdef TIOCOUTQ
350 if (ioctl(fd, TIOCOUTQ, &ss->AmountInOutQueue) == -1)
352 WARN("ioctl returned error\n");
353 status = FILE_GetNtStatus();
355 #else
356 ss->AmountInOutQueue = 0; /* FIXME: find a different way to find out */
357 #endif
359 #ifdef TIOCINQ
360 if (ioctl(fd, TIOCINQ, &ss->AmountInInQueue))
362 WARN("ioctl returned error\n");
363 status = FILE_GetNtStatus();
365 #else
366 ss->AmountInInQueue = 0; /* FIXME: find a different way to find out */
367 #endif
368 return status;
371 static NTSTATUS get_timeouts(HANDLE handle, SERIAL_TIMEOUTS* st)
373 NTSTATUS status;
374 SERVER_START_REQ( get_serial_info )
376 req->handle = handle;
377 if (!(status = wine_server_call( req )))
379 st->ReadIntervalTimeout = reply->readinterval;
380 st->ReadTotalTimeoutMultiplier = reply->readmult;
381 st->ReadTotalTimeoutConstant = reply->readconst;
382 st->WriteTotalTimeoutMultiplier = reply->writemult;
383 st->WriteTotalTimeoutConstant = reply->writeconst;
386 SERVER_END_REQ;
387 return status;
390 static NTSTATUS get_wait_mask(HANDLE hDevice, DWORD* mask)
392 NTSTATUS status;
394 SERVER_START_REQ( get_serial_info )
396 req->handle = hDevice;
397 if (!(status = wine_server_call( req )))
398 *mask = reply->eventmask;
400 SERVER_END_REQ;
401 return status;
404 static NTSTATUS purge(int fd, DWORD flags)
407 ** not exactly sure how these are different
408 ** Perhaps if we had our own internal queues, one flushes them
409 ** and the other flushes the kernel's buffers.
411 if (flags & PURGE_TXABORT) tcflush(fd, TCOFLUSH);
412 if (flags & PURGE_RXABORT) tcflush(fd, TCIFLUSH);
413 if (flags & PURGE_TXCLEAR) tcflush(fd, TCOFLUSH);
414 if (flags & PURGE_RXCLEAR) tcflush(fd, TCIFLUSH);
415 return STATUS_SUCCESS;
418 static NTSTATUS set_baud_rate(int fd, const SERIAL_BAUD_RATE* sbr)
420 struct termios port;
422 if (tcgetattr(fd, &port) == -1)
424 ERR("tcgetattr error '%s'\n", strerror(errno));
425 return FILE_GetNtStatus();
428 #ifdef CBAUD
429 port.c_cflag &= ~CBAUD;
430 switch (sbr->BaudRate)
432 case 0: port.c_cflag |= B0; break;
433 case 50: port.c_cflag |= B50; break;
434 case 75: port.c_cflag |= B75; break;
435 case 110:
436 case CBR_110: port.c_cflag |= B110; break;
437 case 134: port.c_cflag |= B134; break;
438 case 150: port.c_cflag |= B150; break;
439 case 200: port.c_cflag |= B200; break;
440 case 300:
441 case CBR_300: port.c_cflag |= B300; break;
442 case 600:
443 case CBR_600: port.c_cflag |= B600; break;
444 case 1200:
445 case CBR_1200: port.c_cflag |= B1200; break;
446 case 1800: port.c_cflag |= B1800; break;
447 case 2400:
448 case CBR_2400: port.c_cflag |= B2400; break;
449 case 4800:
450 case CBR_4800: port.c_cflag |= B4800; break;
451 case 9600:
452 case CBR_9600: port.c_cflag |= B9600; break;
453 case 19200:
454 case CBR_19200: port.c_cflag |= B19200; break;
455 case 38400:
456 case CBR_38400: port.c_cflag |= B38400; break;
457 #ifdef B57600
458 case 57600: port.c_cflag |= B57600; break;
459 #endif
460 #ifdef B115200
461 case 115200: port.c_cflag |= B115200;break;
462 #endif
463 #ifdef B230400
464 case 230400: port.c_cflag |= B230400;break;
465 #endif
466 #ifdef B460800
467 case 460800: port.c_cflag |= B460800;break;
468 #endif
469 default:
470 #if defined (HAVE_LINUX_SERIAL_H) && defined (TIOCSSERIAL)
472 struct serial_struct nuts;
473 int arby;
475 ioctl(fd, TIOCGSERIAL, &nuts);
476 nuts.custom_divisor = nuts.baud_base / sbr->BaudRate;
477 if (!(nuts.custom_divisor)) nuts.custom_divisor = 1;
478 arby = nuts.baud_base / nuts.custom_divisor;
479 nuts.flags &= ~ASYNC_SPD_MASK;
480 nuts.flags |= ASYNC_SPD_CUST;
481 WARN("You (or a program acting at your behest) have specified\n"
482 "a non-standard baud rate %ld. Wine will set the rate to %d,\n"
483 "which is as close as we can get by our present understanding of your\n"
484 "hardware. I hope you know what you are doing. Any disruption Wine\n"
485 "has caused to your linux system can be undone with setserial \n"
486 "(see man setserial). If you have incapacitated a Hayes type modem,\n"
487 "reset it and it will probably recover.\n", sbr->BaudRate, arby);
488 ioctl(fd, TIOCSSERIAL, &nuts);
489 port.c_cflag |= B38400;
491 break;
492 #endif /* Don't have linux/serial.h or lack TIOCSSERIAL */
493 ERR("baudrate %ld\n", sbr->BaudRate);
494 return STATUS_NOT_SUPPORTED;
496 #elif !defined(__EMX__)
497 switch (sbr->BaudRate)
499 case 0: port.c_ospeed = B0; break;
500 case 50: port.c_ospeed = B50; break;
501 case 75: port.c_ospeed = B75; break;
502 case 110:
503 case CBR_110: port.c_ospeed = B110; break;
504 case 134: port.c_ospeed = B134; break;
505 case 150: port.c_ospeed = B150; break;
506 case 200: port.c_ospeed = B200; break;
507 case 300:
508 case CBR_300: port.c_ospeed = B300; break;
509 case 600:
510 case CBR_600: port.c_ospeed = B600; break;
511 case 1200:
512 case CBR_1200: port.c_ospeed = B1200; break;
513 case 1800: port.c_ospeed = B1800; break;
514 case 2400:
515 case CBR_2400: port.c_ospeed = B2400; break;
516 case 4800:
517 case CBR_4800: port.c_ospeed = B4800; break;
518 case 9600:
519 case CBR_9600: port.c_ospeed = B9600; break;
520 case 19200:
521 case CBR_19200: port.c_ospeed = B19200; break;
522 case 38400:
523 case CBR_38400: port.c_ospeed = B38400; break;
524 #ifdef B57600
525 case 57600:
526 case CBR_57600: port.c_cflag |= B57600; break;
527 #endif
528 #ifdef B115200
529 case 115200:
530 case CBR_115200: port.c_cflag |= B115200;break;
531 #endif
532 #ifdef B230400
533 case 230400: port.c_cflag |= B230400;break;
534 #endif
535 #ifdef B460800
536 case 460800: port.c_cflag |= B460800;break;
537 #endif
538 default:
539 ERR("baudrate %ld\n", sbr->BaudRate);
540 return STATUS_NOT_SUPPORTED;
542 port.c_ispeed = port.c_ospeed;
543 #endif
544 if (tcsetattr(fd, TCSANOW, &port) == -1)
546 ERR("tcsetattr error '%s'\n", strerror(errno));
547 return FILE_GetNtStatus();
549 return STATUS_SUCCESS;
552 static int whack_modem(int fd, unsigned int andy, unsigned int orrie)
554 #ifdef TIOCMGET
555 unsigned int mstat, okay;
556 okay = ioctl(fd, TIOCMGET, &mstat);
557 if (okay) return okay;
558 if (andy) mstat &= andy;
559 mstat |= orrie;
560 return ioctl(fd, TIOCMSET, &mstat);
561 #else
562 return 0;
563 #endif
566 static NTSTATUS set_handflow(int fd, const SERIAL_HANDFLOW* shf)
568 struct termios port;
570 if ((shf->FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE)) ==
571 (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE))
572 return STATUS_NOT_SUPPORTED;
574 if (tcgetattr(fd, &port) == -1)
576 ERR("tcgetattr error '%s'\n", strerror(errno));
577 return FILE_GetNtStatus();
580 #ifdef CRTSCTS
581 if ((shf->ControlHandShake & SERIAL_CTS_HANDSHAKE) ||
582 (shf->FlowReplace & SERIAL_RTS_HANDSHAKE))
584 port.c_cflag |= CRTSCTS;
585 TRACE("CRTSCTS\n");
587 else
588 port.c_cflag &= ~CRTSCTS;
589 #endif
590 #ifdef TIOCM_DTR
591 if (shf->ControlHandShake & SERIAL_DTR_HANDSHAKE)
593 WARN("DSR/DTR flow control not supported\n");
594 } else if (shf->ControlHandShake & SERIAL_DTR_CONTROL)
595 whack_modem(fd, ~TIOCM_DTR, 0);
596 else
597 whack_modem(fd, 0, TIOCM_DTR);
598 #endif
599 #ifdef TIOCM_RTS
600 if (!(shf->ControlHandShake & SERIAL_DSR_HANDSHAKE))
602 if ((shf->FlowReplace & (SERIAL_RTS_CONTROL|SERIAL_RTS_HANDSHAKE)) == 0)
603 whack_modem(fd, ~TIOCM_RTS, 0);
604 else
605 whack_modem(fd, 0, TIOCM_RTS);
607 #endif
609 if (shf->FlowReplace & SERIAL_AUTO_RECEIVE)
610 port.c_iflag |= IXON;
611 else
612 port.c_iflag &= ~IXON;
613 if (shf->FlowReplace & SERIAL_AUTO_TRANSMIT)
614 port.c_iflag |= IXOFF;
615 else
616 port.c_iflag &= ~IXOFF;
617 if (tcsetattr(fd, TCSANOW, &port) == -1)
619 ERR("tcsetattr error '%s'\n", strerror(errno));
620 return FILE_GetNtStatus();
623 return STATUS_SUCCESS;
626 static NTSTATUS set_line_control(int fd, const SERIAL_LINE_CONTROL* slc)
628 struct termios port;
629 unsigned bytesize, stopbits;
631 if (tcgetattr(fd, &port) == -1)
633 ERR("tcgetattr error '%s'\n", strerror(errno));
634 return FILE_GetNtStatus();
637 #ifdef IMAXBEL
638 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK|IMAXBEL);
639 #else
640 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK);
641 #endif
642 port.c_iflag |= IGNBRK | INPCK;
644 port.c_oflag &= ~(OPOST);
646 port.c_cflag &= ~(HUPCL);
647 port.c_cflag |= CLOCAL | CREAD;
649 port.c_lflag &= ~(ICANON|ECHO|ISIG);
650 port.c_lflag |= NOFLSH;
652 bytesize = slc->WordLength;
653 stopbits = slc->StopBits;
655 #ifdef CMSPAR
656 port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
657 #else
658 port.c_cflag &= ~(PARENB | PARODD);
659 #endif
661 switch (slc->Parity)
663 case NOPARITY: port.c_iflag &= ~INPCK; break;
664 case ODDPARITY: port.c_cflag |= PARENB | PARODD; break;
665 case EVENPARITY: port.c_cflag |= PARENB; break;
666 #ifdef CMSPAR
667 /* Linux defines mark/space (stick) parity */
668 case MARKPARITY: port.c_cflag |= PARENB | CMSPAR; break;
669 case SPACEPARITY: port.c_cflag |= PARENB | PARODD | CMSPAR; break;
670 #else
671 /* try the POSIX way */
672 case MARKPARITY:
673 if (slc->StopBits == ONESTOPBIT)
675 stopbits = TWOSTOPBITS;
676 port.c_iflag &= ~INPCK;
678 else
680 ERR("Cannot set MARK Parity\n");
681 return STATUS_NOT_SUPPORTED;
683 break;
684 case SPACEPARITY:
685 if (slc->WordLength < 8)
687 bytesize +=1;
688 port.c_iflag &= ~INPCK;
690 else
692 ERR("Cannot set SPACE Parity\n");
693 return STATUS_NOT_SUPPORTED;
695 break;
696 #endif
697 default:
698 ERR("Parity\n");
699 return STATUS_NOT_SUPPORTED;
702 port.c_cflag &= ~CSIZE;
703 switch (bytesize)
705 case 5: port.c_cflag |= CS5; break;
706 case 6: port.c_cflag |= CS6; break;
707 case 7: port.c_cflag |= CS7; break;
708 case 8: port.c_cflag |= CS8; break;
709 default:
710 ERR("ByteSize\n");
711 return STATUS_NOT_SUPPORTED;
714 switch (stopbits)
716 case ONESTOPBIT: port.c_cflag &= ~CSTOPB; break;
717 case ONE5STOPBITS: /* will be selected if bytesize is 5 */
718 case TWOSTOPBITS: port.c_cflag |= CSTOPB; break;
719 default:
720 ERR("StopBits\n");
721 return STATUS_NOT_SUPPORTED;
723 /* otherwise it hangs with pending input*/
724 if (tcsetattr(fd, TCSANOW, &port) == -1)
726 ERR("tcsetattr error '%s'\n", strerror(errno));
727 return FILE_GetNtStatus();
729 return STATUS_SUCCESS;
732 static NTSTATUS set_queue_size(int fd, const SERIAL_QUEUE_SIZE* sqs)
734 FIXME("insize %ld outsize %ld unimplemented stub\n", sqs->InSize, sqs->OutSize);
735 return STATUS_SUCCESS;
738 static NTSTATUS set_special_chars(int fd, const SERIAL_CHARS* sc)
740 struct termios port;
742 if (tcgetattr(fd, &port) == -1)
744 ERR("tcgetattr error '%s'\n", strerror(errno));
745 return FILE_GetNtStatus();
748 port.c_cc[VMIN ] = 0;
749 port.c_cc[VTIME ] = 1;
751 port.c_cc[VEOF ] = sc->EofChar;
752 /* FIXME: sc->ErrorChar is not supported */
753 /* FIXME: sc->BreakChar is not supported */
754 /* FIXME: sc->EventChar is not supported */
755 port.c_cc[VSTART] = sc->XonChar;
756 port.c_cc[VSTOP ] = sc->XoffChar;
758 if (tcsetattr(fd, TCSANOW, &port) == -1)
760 ERR("tcsetattr error '%s'\n", strerror(errno));
761 return FILE_GetNtStatus();
763 return STATUS_SUCCESS;
766 static NTSTATUS set_timeouts(HANDLE handle, int fd, const SERIAL_TIMEOUTS* st)
768 NTSTATUS status;
769 struct termios port;
770 unsigned int ux_timeout;
772 SERVER_START_REQ( set_serial_info )
774 req->handle = handle;
775 req->flags = SERIALINFO_SET_TIMEOUTS;
776 req->readinterval = st->ReadIntervalTimeout ;
777 req->readmult = st->ReadTotalTimeoutMultiplier ;
778 req->readconst = st->ReadTotalTimeoutConstant ;
779 req->writemult = st->WriteTotalTimeoutMultiplier ;
780 req->writeconst = st->WriteTotalTimeoutConstant ;
781 status = wine_server_call( req );
783 SERVER_END_REQ;
784 if (status) return status;
786 if (tcgetattr(fd, &port) == -1)
788 FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
789 return FILE_GetNtStatus();
792 /* VTIME is in 1/10 seconds */
793 if (st->ReadIntervalTimeout == 0) /* 0 means no timeout */
794 ux_timeout = 0;
795 else
797 ux_timeout = (st->ReadIntervalTimeout + 99) / 100;
798 if (ux_timeout == 0)
799 ux_timeout = 1; /* must be at least some timeout */
801 port.c_cc[VTIME] = ux_timeout;
803 if (tcsetattr(fd, 0, &port) == -1)
805 FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
806 return FILE_GetNtStatus();
808 return STATUS_SUCCESS;
811 static NTSTATUS set_wait_mask(HANDLE hDevice, DWORD mask)
813 NTSTATUS status;
815 SERVER_START_REQ( set_serial_info )
817 req->handle = hDevice;
818 req->flags = SERIALINFO_SET_MASK;
819 req->eventmask = mask;
820 status = wine_server_call( req );
822 SERVER_END_REQ;
823 return status;
826 static NTSTATUS set_XOff(int fd)
828 struct termios port;
830 if (tcgetattr(fd,&port) == -1)
832 FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
833 return FILE_GetNtStatus();
837 port.c_iflag |= IXOFF;
838 if (tcsetattr(fd, TCSADRAIN, &port) == -1)
840 FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
841 return FILE_GetNtStatus();
843 return STATUS_SUCCESS;
846 static NTSTATUS set_XOn(int fd)
848 struct termios port;
850 if (tcgetattr(fd,&port) == -1)
852 FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
853 return FILE_GetNtStatus();
855 port.c_iflag |= IXON;
856 if (tcsetattr(fd, TCSADRAIN, &port) == -1)
858 FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
859 return FILE_GetNtStatus();
861 return STATUS_SUCCESS;
864 static NTSTATUS xmit_immediate(HANDLE hDevice, int fd, char* ptr)
866 /* FIXME: not perfect as it should bypass the in-queue */
867 WARN("(%p,'%c') not perfect!\n", hDevice, *ptr);
868 if (write(fd, ptr, 1) != 1)
869 return FILE_GetNtStatus();
870 return STATUS_SUCCESS;
873 /******************************************************************
874 * COMM_DeviceIoControl
878 NTSTATUS COMM_DeviceIoControl(HANDLE hDevice,
879 HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
880 PVOID UserApcContext,
881 PIO_STATUS_BLOCK piosb,
882 ULONG dwIoControlCode,
883 LPVOID lpInBuffer, DWORD nInBufferSize,
884 LPVOID lpOutBuffer, DWORD nOutBufferSize)
886 DWORD sz = 0, access = FILE_READ_DATA;
887 NTSTATUS status = STATUS_SUCCESS;
888 int fd = -1;
890 TRACE("%p %s %p %ld %p %ld %p\n",
891 hDevice, iocode2str(dwIoControlCode), lpInBuffer, nInBufferSize,
892 lpOutBuffer, nOutBufferSize, piosb);
894 piosb->Information = 0;
896 if (dwIoControlCode != IOCTL_SERIAL_GET_TIMEOUTS)
897 if ((status = wine_server_handle_to_fd( hDevice, access, &fd, NULL )))
898 goto error;
900 switch (dwIoControlCode)
902 case IOCTL_SERIAL_CLR_DTR:
903 #ifdef TIOCM_DTR
904 if (whack_modem(fd, ~TIOCM_DTR, 0) == -1) status = FILE_GetNtStatus();
905 #else
906 status = STATUS_NOT_SUPPORTED;
907 #endif
908 break;
909 case IOCTL_SERIAL_CLR_RTS:
910 #ifdef TIOCM_RTS
911 if (whack_modem(fd, ~TIOCM_RTS, 0) == -1) status = FILE_GetNtStatus();
912 #else
913 status = STATUS_NOT_SUPPORTED;
914 #endif
915 break;
916 case IOCTL_SERIAL_GET_BAUD_RATE:
917 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_BAUD_RATE))
919 if (!(status = get_baud_rate(fd, (SERIAL_BAUD_RATE*)lpOutBuffer)))
920 sz = sizeof(SERIAL_BAUD_RATE);
922 else
923 status = STATUS_INVALID_PARAMETER;
924 break;
925 case IOCTL_SERIAL_GET_CHARS:
926 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_CHARS))
928 if (!(status = get_special_chars(fd, (SERIAL_CHARS*)lpOutBuffer)))
929 sz = sizeof(SERIAL_CHARS);
931 else
932 status = STATUS_INVALID_PARAMETER;
933 break;
934 case IOCTL_SERIAL_GET_COMMSTATUS:
935 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_STATUS))
937 if (!(status = get_status(fd, (SERIAL_STATUS*)lpOutBuffer)))
938 sz = sizeof(SERIAL_STATUS);
940 else status = STATUS_INVALID_PARAMETER;
941 break;
942 case IOCTL_SERIAL_GET_HANDFLOW:
943 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_HANDFLOW))
945 if (!(status = get_hand_flow(fd, (SERIAL_HANDFLOW*)lpOutBuffer)))
946 sz = sizeof(SERIAL_HANDFLOW);
948 else
949 status = STATUS_INVALID_PARAMETER;
950 break;
951 case IOCTL_SERIAL_GET_LINE_CONTROL:
952 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_LINE_CONTROL))
954 if (!(status = get_line_control(fd, (SERIAL_LINE_CONTROL*)lpOutBuffer)))
955 sz = sizeof(SERIAL_LINE_CONTROL);
957 else
958 status = STATUS_INVALID_PARAMETER;
959 break;
960 case IOCTL_SERIAL_GET_MODEMSTATUS:
961 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
963 if (!(status = get_modem_status(fd, (DWORD*)lpOutBuffer)))
964 sz = sizeof(DWORD);
966 else status = STATUS_INVALID_PARAMETER;
967 break;
968 case IOCTL_SERIAL_GET_TIMEOUTS:
969 if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_TIMEOUTS))
971 if (!(status = get_timeouts(hDevice, (SERIAL_TIMEOUTS*)lpOutBuffer)))
972 sz = sizeof(SERIAL_TIMEOUTS);
974 else
975 status = STATUS_INVALID_PARAMETER;
976 break;
977 case IOCTL_SERIAL_GET_WAIT_MASK:
978 if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
980 if (!(status = get_wait_mask(hDevice, (DWORD*)lpOutBuffer)))
981 sz = sizeof(DWORD);
983 else
984 status = STATUS_INVALID_PARAMETER;
985 break;
986 case IOCTL_SERIAL_IMMEDIATE_CHAR:
987 if (lpInBuffer && nInBufferSize == sizeof(CHAR))
988 status = xmit_immediate(hDevice, fd, lpInBuffer);
989 else
990 status = STATUS_INVALID_PARAMETER;
991 break;
992 case IOCTL_SERIAL_PURGE:
993 if (lpInBuffer && nInBufferSize == sizeof(DWORD))
994 status = purge(fd, *(DWORD*)lpInBuffer);
995 else
996 status = STATUS_INVALID_PARAMETER;
997 break;
998 case IOCTL_SERIAL_RESET_DEVICE:
999 FIXME("Unsupported\n");
1000 break;
1001 case IOCTL_SERIAL_SET_BAUD_RATE:
1002 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_BAUD_RATE))
1003 status = set_baud_rate(fd, (const SERIAL_BAUD_RATE*)lpInBuffer);
1004 else
1005 status = STATUS_INVALID_PARAMETER;
1006 break;
1007 case IOCTL_SERIAL_SET_BREAK_OFF:
1008 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1009 if (ioctl(fd, TIOCCBRK, 0) == -1)
1011 TRACE("ioctl failed\n");
1012 status = FILE_GetNtStatus();
1014 #else
1015 FIXME("ioctl not available\n");
1016 status = STATUS_NOT_SUPPORTED;
1017 #endif
1018 break;
1019 case IOCTL_SERIAL_SET_BREAK_ON:
1020 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1021 if (ioctl(fd, TIOCSBRK, 0) == -1)
1023 TRACE("ioctl failed\n");
1024 status = FILE_GetNtStatus();
1026 #else
1027 FIXME("ioctl not available\n");
1028 status = STATUS_NOT_SUPPORTED;
1029 #endif
1030 break;
1031 case IOCTL_SERIAL_SET_CHARS:
1032 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_CHARS))
1033 status = set_special_chars(fd, (const SERIAL_CHARS*)lpInBuffer);
1034 else
1035 status = STATUS_INVALID_PARAMETER;
1036 break;
1037 case IOCTL_SERIAL_SET_DTR:
1038 #ifdef TIOCM_DTR
1039 if (whack_modem(fd, 0, TIOCM_DTR) == -1) status = FILE_GetNtStatus();
1040 #else
1041 status = STATUS_NOT_SUPPORTED;
1042 #endif
1043 break;
1044 case IOCTL_SERIAL_SET_HANDFLOW:
1045 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_HANDFLOW))
1046 status = set_handflow(fd, (const SERIAL_HANDFLOW*)lpInBuffer);
1047 else
1048 status = STATUS_INVALID_PARAMETER;
1049 break;
1050 case IOCTL_SERIAL_SET_LINE_CONTROL:
1051 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_LINE_CONTROL))
1052 status = set_line_control(fd, (const SERIAL_LINE_CONTROL*)lpInBuffer);
1053 else
1054 status = STATUS_INVALID_PARAMETER;
1055 break;
1056 case IOCTL_SERIAL_SET_QUEUE_SIZE:
1057 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_QUEUE_SIZE))
1058 status = set_queue_size(fd, (const SERIAL_QUEUE_SIZE*)lpInBuffer);
1059 else
1060 status = STATUS_INVALID_PARAMETER;
1061 break;
1062 case IOCTL_SERIAL_SET_RTS:
1063 #ifdef TIOCM_RTS
1064 if (whack_modem(fd, 0, TIOCM_RTS) == -1) status = FILE_GetNtStatus();
1065 #else
1066 status = STATUS_NOT_SUPPORTED;
1067 #endif
1068 break;
1069 case IOCTL_SERIAL_SET_TIMEOUTS:
1070 if (lpInBuffer && nInBufferSize == sizeof(SERIAL_TIMEOUTS))
1071 status = set_timeouts(hDevice, fd, (const SERIAL_TIMEOUTS*)lpInBuffer);
1072 else
1073 status = STATUS_INVALID_PARAMETER;
1074 break;
1075 case IOCTL_SERIAL_SET_WAIT_MASK:
1076 if (lpInBuffer && nInBufferSize == sizeof(DWORD))
1078 status = set_wait_mask(hDevice, *(DWORD*)lpInBuffer);
1080 else status = STATUS_INVALID_PARAMETER;
1081 break;
1082 case IOCTL_SERIAL_SET_XOFF:
1083 status = set_XOff(fd);
1084 break;
1085 case IOCTL_SERIAL_SET_XON:
1086 status = set_XOn(fd);
1087 break;
1088 default:
1089 FIXME("Unsupported IOCTL %lx (type=%lx access=%lx func=%lx meth=%lx)\n",
1090 dwIoControlCode, dwIoControlCode >> 16, (dwIoControlCode >> 14) & 3,
1091 (dwIoControlCode >> 2) & 0xFFF, dwIoControlCode & 3);
1092 sz = 0;
1093 status = STATUS_INVALID_PARAMETER;
1094 break;
1096 if (fd != -1) wine_server_release_fd( hDevice, fd );
1097 error:
1098 piosb->u.Status = status;
1099 piosb->Information = sz;
1100 if (hEvent) NtSetEvent(hEvent, NULL);
1101 return status;