ntdll/kernel32: EscapeCommFunction & associated IOCTLs
[wine] / dlls / ntdll / serial.c
1 /* Main file for COMM support
2  *
3  * DEC 93 Erik Bos <erik@xs4all.nl>
4  * Copyright 1996 Marcus Meissner
5  * Copyright 2005 Eric Pouech
6  *
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.
11  *
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.
16  *
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
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
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
65
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"
78
79 #ifdef HAVE_LINUX_SERIAL_H
80 #include <linux/serial.h>
81 #endif
82
83 WINE_DEFAULT_DEBUG_CHANNEL(comm);
84
85 static const char* iocode2str(DWORD ioc)
86 {
87     switch (ioc)
88     {
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; }
129     }
130 }
131
132 static NTSTATUS get_baud_rate(int fd, SERIAL_BAUD_RATE* sbr)
133 {
134     struct termios port;
135     int speed;
136     
137     if (tcgetattr(fd, &port) == -1)
138     {
139         ERR("tcgetattr error '%s'\n", strerror(errno));
140         return FILE_GetNtStatus();
141     }
142 #ifndef __EMX__
143 #ifdef CBAUD
144     speed = port.c_cflag & CBAUD;
145 #else
146     speed = cfgetospeed(&port);
147 #endif
148     switch (speed)
149     {
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;
181     }
182 #else
183     return STATUS_INVALID_PARAMETER;
184 #endif
185     return STATUS_SUCCESS;
186 }
187
188 static NTSTATUS get_hand_flow(int fd, SERIAL_HANDFLOW* shf)
189 {
190     int stat;
191     struct termios port;
192     
193     if (tcgetattr(fd, &port) == -1)
194     {
195         ERR("tcgetattr error '%s'\n", strerror(errno));
196         return FILE_GetNtStatus();
197     }
198 #ifdef TIOCMGET
199     if (ioctl(fd, TIOCMGET, &stat) == -1)
200     {
201         WARN("ioctl error '%s'\n", strerror(errno));
202         stat = DTR_CONTROL_ENABLE | RTS_CONTROL_ENABLE;
203     }
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)
214     {
215         shf->ControlHandShake |= SERIAL_DTR_CONTROL | SERIAL_DTR_HANDSHAKE;
216         shf->ControlHandShake |= SERIAL_CTS_HANDSHAKE;
217     }
218     else
219 #endif
220     {
221 #ifdef TIOCM_RTS
222         if (stat & TIOCM_RTS)
223 #endif
224             shf->ControlHandShake |= SERIAL_RTS_CONTROL;
225     }
226     if (port.c_iflag & IXON)
227         shf->FlowReplace |= SERIAL_AUTO_RECEIVE;
228     if (port.c_iflag & IXOFF)
229         shf->FlowReplace |= SERIAL_AUTO_TRANSMIT;
230
231     shf->XonLimit = 10;
232     shf->XoffLimit = 10;
233     return STATUS_SUCCESS;
234 }
235
236 static NTSTATUS get_line_control(int fd, SERIAL_LINE_CONTROL* slc)
237 {
238     struct termios port;
239     
240     if (tcgetattr(fd, &port) == -1)
241     {
242         ERR("tcgetattr error '%s'\n", strerror(errno));
243         return FILE_GetNtStatus();
244     }
245     
246 #ifdef CMSPAR
247     switch (port.c_cflag & (PARENB | PARODD | CMSPAR))
248 #else
249     switch (port.c_cflag & (PARENB | PARODD))
250 #endif
251     {
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
260     }
261     switch (port.c_cflag & CSIZE)
262     {
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);
268     }
269     
270     if (port.c_cflag & CSTOPB)
271     {
272         if (slc->WordLength == 5)
273             slc->StopBits = ONE5STOPBITS;
274         else
275             slc->StopBits = TWOSTOPBITS;
276     }
277     else
278         slc->StopBits = ONESTOPBIT;
279
280     return STATUS_SUCCESS;
281 }
282
283 static NTSTATUS get_modem_status(int fd, DWORD* lpModemStat)
284 {
285     NTSTATUS    status = STATUS_SUCCESS;
286     int         mstat;
287
288 #ifdef TIOCMGET
289     if (ioctl(fd, TIOCMGET, &mstat) == -1)
290     {
291         WARN("ioctl failed\n");
292         status = FILE_GetNtStatus();
293     }
294     else
295     {
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  " : "");
315     }
316 #else
317     status = STATUS_NOT_SUPPORTED;
318 #endif
319     return status;
320 }
321
322 static NTSTATUS get_special_chars(int fd, SERIAL_CHARS* sc)
323 {
324     struct termios port;
325     
326     if (tcgetattr(fd, &port) == -1)
327     {
328         ERR("tcgetattr error '%s'\n", strerror(errno));
329         return FILE_GetNtStatus();
330     }
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];
337
338     return STATUS_SUCCESS;
339 }
340
341 static NTSTATUS get_status(int fd, SERIAL_STATUS* ss)
342 {
343     NTSTATUS    status = STATUS_SUCCESS;
344
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)
351     {
352         WARN("ioctl returned error\n");
353         status = FILE_GetNtStatus();
354     }
355 #else
356     ss->AmountInOutQueue = 0; /* FIXME: find a different way to find out */
357 #endif
358
359 #ifdef TIOCINQ
360     if (ioctl(fd, TIOCINQ, &ss->AmountInInQueue))
361     {
362         WARN("ioctl returned error\n");
363         status = FILE_GetNtStatus();
364     }
365 #else
366     ss->AmountInInQueue = 0; /* FIXME: find a different way to find out */
367 #endif
368     return status;
369 }
370
371 static NTSTATUS get_timeouts(HANDLE handle, SERIAL_TIMEOUTS* st)
372 {
373     NTSTATUS    status;
374     SERVER_START_REQ( get_serial_info )
375     {
376         req->handle = handle;
377         if (!(status = wine_server_call( req )))
378         {
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;
384         }
385     }
386     SERVER_END_REQ;
387     return status;
388 }
389
390 static NTSTATUS get_wait_mask(HANDLE hDevice, DWORD* mask)
391 {
392     NTSTATUS    status;
393
394     SERVER_START_REQ( get_serial_info )
395     {
396         req->handle = hDevice;
397         if (!(status = wine_server_call( req )))
398             *mask = reply->eventmask;
399     }
400     SERVER_END_REQ;
401     return status;
402 }
403
404 static NTSTATUS purge(int fd, DWORD flags)
405 {
406     /*
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.
410     */
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;
416 }
417
418 static NTSTATUS set_baud_rate(int fd, const SERIAL_BAUD_RATE* sbr)
419 {
420     struct termios port;
421
422     if (tcgetattr(fd, &port) == -1)
423     {
424         ERR("tcgetattr error '%s'\n", strerror(errno));
425         return FILE_GetNtStatus();
426     }
427
428 #ifdef CBAUD
429     port.c_cflag &= ~CBAUD;
430     switch (sbr->BaudRate)
431     {
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)
471         {
472             struct serial_struct nuts;
473             int arby;
474         
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;
490         }
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;
495     }
496 #elif !defined(__EMX__)
497     switch (sbr->BaudRate)
498     {
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;
541     }
542     port.c_ispeed = port.c_ospeed;
543 #endif
544     if (tcsetattr(fd, TCSANOW, &port) == -1)
545     {
546         ERR("tcsetattr error '%s'\n", strerror(errno));
547         return FILE_GetNtStatus();
548     }
549     return STATUS_SUCCESS;
550 }
551
552 static int whack_modem(int fd, unsigned int andy, unsigned int orrie)
553 {
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
564 }
565
566 static NTSTATUS set_handflow(int fd, const SERIAL_HANDFLOW* shf)
567 {
568     struct termios port;
569
570     if ((shf->FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE)) == 
571         (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE))
572         return STATUS_NOT_SUPPORTED;
573
574     if (tcgetattr(fd, &port) == -1)
575     {
576         ERR("tcgetattr error '%s'\n", strerror(errno));
577         return FILE_GetNtStatus();
578     }
579     
580 #ifdef CRTSCTS
581     if ((shf->ControlHandShake & SERIAL_CTS_HANDSHAKE) ||
582         (shf->FlowReplace & SERIAL_RTS_HANDSHAKE))
583     {
584         port.c_cflag |= CRTSCTS;
585         TRACE("CRTSCTS\n");
586     }
587     else
588         port.c_cflag &= ~CRTSCTS;
589 #endif
590 #ifdef TIOCM_DTR
591     if (shf->ControlHandShake & SERIAL_DTR_HANDSHAKE)
592     {
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))
601     {
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);
606     }
607 #endif
608
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)
618     {
619         ERR("tcsetattr error '%s'\n", strerror(errno));
620         return FILE_GetNtStatus();
621     }
622
623     return STATUS_SUCCESS;
624 }
625
626 static NTSTATUS set_line_control(int fd, const SERIAL_LINE_CONTROL* slc)
627 {
628     struct termios port;
629     unsigned bytesize, stopbits;
630     
631     if (tcgetattr(fd, &port) == -1)
632     {
633         ERR("tcgetattr error '%s'\n", strerror(errno));
634         return FILE_GetNtStatus();
635     }
636     
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;
643     
644     port.c_oflag &= ~(OPOST);
645     
646     port.c_cflag &= ~(HUPCL);
647     port.c_cflag |= CLOCAL | CREAD;
648     
649     port.c_lflag &= ~(ICANON|ECHO|ISIG);
650     port.c_lflag |= NOFLSH;
651     
652     bytesize = slc->WordLength;
653     stopbits = slc->StopBits;
654     
655 #ifdef CMSPAR
656     port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
657 #else
658     port.c_cflag &= ~(PARENB | PARODD);
659 #endif
660
661     switch (slc->Parity)
662     {
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)
674         {
675             stopbits = TWOSTOPBITS;
676             port.c_iflag &= ~INPCK;
677         }
678         else
679         {
680             ERR("Cannot set MARK Parity\n");
681             return STATUS_NOT_SUPPORTED;
682         }
683         break;
684     case SPACEPARITY:
685         if (slc->WordLength < 8)
686         {
687             bytesize +=1;
688             port.c_iflag &= ~INPCK;
689         }
690         else
691         {
692             ERR("Cannot set SPACE Parity\n");
693             return STATUS_NOT_SUPPORTED;
694         }
695         break;
696 #endif
697     default:
698         ERR("Parity\n");
699         return STATUS_NOT_SUPPORTED;
700     }
701     
702     port.c_cflag &= ~CSIZE;
703     switch (bytesize)
704     {
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;
712     }
713     
714     switch (stopbits)
715     {
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;
722     }
723     /* otherwise it hangs with pending input*/
724     if (tcsetattr(fd, TCSANOW, &port) == -1)
725     {
726         ERR("tcsetattr error '%s'\n", strerror(errno));
727         return FILE_GetNtStatus();
728     }
729     return STATUS_SUCCESS;
730 }
731
732 static NTSTATUS set_queue_size(int fd, const SERIAL_QUEUE_SIZE* sqs)
733 {
734     FIXME("insize %ld outsize %ld unimplemented stub\n", sqs->InSize, sqs->OutSize);
735     return STATUS_SUCCESS;
736 }
737
738 static NTSTATUS set_special_chars(int fd, const SERIAL_CHARS* sc)
739 {
740     struct termios port;
741     
742     if (tcgetattr(fd, &port) == -1)
743     {
744         ERR("tcgetattr error '%s'\n", strerror(errno));
745         return FILE_GetNtStatus();
746     }
747     
748     port.c_cc[VMIN  ] = 0;
749     port.c_cc[VTIME ] = 1;
750     
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;
757     
758     if (tcsetattr(fd, TCSANOW, &port) == -1)
759     {
760         ERR("tcsetattr error '%s'\n", strerror(errno));
761         return FILE_GetNtStatus();
762     }
763     return STATUS_SUCCESS;
764 }
765
766 static NTSTATUS set_timeouts(HANDLE handle, int fd, const SERIAL_TIMEOUTS* st)
767 {
768     NTSTATUS            status;
769     struct termios      port;
770     unsigned int        ux_timeout;
771
772     SERVER_START_REQ( set_serial_info )
773     {
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 );
782     }
783     SERVER_END_REQ;
784     if (status) return status;
785
786     if (tcgetattr(fd, &port) == -1)
787     {
788         FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
789         return FILE_GetNtStatus();
790     }
791
792     /* VTIME is in 1/10 seconds */
793     if (st->ReadIntervalTimeout == 0) /* 0 means no timeout */
794         ux_timeout = 0;
795     else
796     {
797         ux_timeout = (st->ReadIntervalTimeout + 99) / 100;
798         if (ux_timeout == 0)
799             ux_timeout = 1; /* must be at least some timeout */
800     }
801     port.c_cc[VTIME] = ux_timeout;
802
803     if (tcsetattr(fd, 0, &port) == -1)
804     {
805         FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
806         return FILE_GetNtStatus();
807     }
808     return STATUS_SUCCESS;
809 }
810
811 static NTSTATUS set_wait_mask(HANDLE hDevice, DWORD mask)
812 {
813     NTSTATUS status;
814
815     SERVER_START_REQ( set_serial_info )
816     {
817         req->handle    = hDevice;
818         req->flags     = SERIALINFO_SET_MASK;
819         req->eventmask = mask;
820         status = wine_server_call( req );
821     }
822     SERVER_END_REQ;
823     return status;
824 }
825
826 static NTSTATUS set_XOff(int fd)
827 {
828     struct termios      port;
829
830     if (tcgetattr(fd,&port) == -1)
831     {
832         FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
833         return FILE_GetNtStatus();
834
835
836     }
837     port.c_iflag |= IXOFF;
838     if (tcsetattr(fd, TCSADRAIN, &port) == -1)
839     {
840         FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
841         return FILE_GetNtStatus();
842     }
843     return STATUS_SUCCESS;
844 }
845
846 static NTSTATUS set_XOn(int fd)
847 {
848     struct termios      port;
849
850     if (tcgetattr(fd,&port) == -1)
851     {
852         FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
853         return FILE_GetNtStatus();
854     }
855     port.c_iflag |= IXON;
856     if (tcsetattr(fd, TCSADRAIN, &port) == -1)
857     {
858         FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
859         return FILE_GetNtStatus();
860     }
861     return STATUS_SUCCESS;
862 }
863
864 static NTSTATUS xmit_immediate(HANDLE hDevice, int fd, char* ptr)
865 {
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;
871 }
872
873 /******************************************************************
874  *              COMM_DeviceIoControl
875  *
876  *
877  */
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)
885 {
886     DWORD       sz = 0, access = FILE_READ_DATA;
887     NTSTATUS    status = STATUS_SUCCESS;
888     int         fd = -1;
889
890     TRACE("%p %s %p %ld %p %ld %p\n",
891           hDevice, iocode2str(dwIoControlCode), lpInBuffer, nInBufferSize,
892           lpOutBuffer, nOutBufferSize, piosb);
893
894     piosb->Information = 0;
895
896     if (dwIoControlCode != IOCTL_SERIAL_GET_TIMEOUTS)
897         if ((status = wine_server_handle_to_fd( hDevice, access, &fd, NULL )))
898             goto error;
899
900     switch (dwIoControlCode)
901     {
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))
918         {
919             if (!(status = get_baud_rate(fd, (SERIAL_BAUD_RATE*)lpOutBuffer)))
920                 sz = sizeof(SERIAL_BAUD_RATE);
921         }
922         else
923             status = STATUS_INVALID_PARAMETER;
924         break;
925     case IOCTL_SERIAL_GET_CHARS:
926         if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_CHARS))
927         {
928             if (!(status = get_special_chars(fd, (SERIAL_CHARS*)lpOutBuffer)))
929                 sz = sizeof(SERIAL_CHARS);
930         }
931         else
932             status = STATUS_INVALID_PARAMETER;
933         break;
934      case IOCTL_SERIAL_GET_COMMSTATUS:
935         if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_STATUS))
936         {
937             if (!(status = get_status(fd, (SERIAL_STATUS*)lpOutBuffer)))
938                 sz = sizeof(SERIAL_STATUS);
939         }
940         else status = STATUS_INVALID_PARAMETER;
941         break;
942     case IOCTL_SERIAL_GET_HANDFLOW:
943         if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_HANDFLOW))
944         {
945             if (!(status = get_hand_flow(fd, (SERIAL_HANDFLOW*)lpOutBuffer)))
946                 sz = sizeof(SERIAL_HANDFLOW);
947         }
948         else
949             status = STATUS_INVALID_PARAMETER;
950         break;
951     case IOCTL_SERIAL_GET_LINE_CONTROL:
952         if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_LINE_CONTROL))
953         {
954             if (!(status = get_line_control(fd, (SERIAL_LINE_CONTROL*)lpOutBuffer)))
955                 sz = sizeof(SERIAL_LINE_CONTROL);
956         }
957         else
958             status = STATUS_INVALID_PARAMETER;
959         break;
960     case IOCTL_SERIAL_GET_MODEMSTATUS:
961         if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
962         {
963             if (!(status = get_modem_status(fd, (DWORD*)lpOutBuffer)))
964                 sz = sizeof(DWORD);
965         }
966         else status = STATUS_INVALID_PARAMETER;
967         break;
968     case IOCTL_SERIAL_GET_TIMEOUTS:
969         if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_TIMEOUTS))
970         {
971             if (!(status = get_timeouts(hDevice, (SERIAL_TIMEOUTS*)lpInBuffer)))
972                 sz = sizeof(SERIAL_TIMEOUTS);
973         }
974         else
975             status = STATUS_INVALID_PARAMETER;
976         break;
977     case IOCTL_SERIAL_GET_WAIT_MASK:
978         if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
979         {
980             if (!(status = get_wait_mask(hDevice, (DWORD*)lpOutBuffer)))
981                 sz = sizeof(DWORD);
982         }
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)
1010         {
1011             TRACE("ioctl failed\n");
1012             status = FILE_GetNtStatus();
1013         }
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)
1022         {
1023             TRACE("ioctl failed\n");
1024             status = FILE_GetNtStatus();
1025         }
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))
1077         {
1078             status = set_wait_mask(hDevice, *(DWORD*)lpInBuffer);
1079         }
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;
1095     }
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;
1102 }