ntdll/tests: Do GetModuleHandle only once and add a few skip's.
[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,2006 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 #if !defined(TIOCINQ) && defined(FIONREAD)
84 #define TIOCINQ FIONREAD
85 #endif
86
87 WINE_DEFAULT_DEBUG_CHANNEL(comm);
88
89 static const char* iocode2str(DWORD ioc)
90 {
91     switch (ioc)
92     {
93 #define X(x)    case (x): return #x;
94         X(IOCTL_SERIAL_CLEAR_STATS);
95         X(IOCTL_SERIAL_CLR_DTR);
96         X(IOCTL_SERIAL_CLR_RTS);
97         X(IOCTL_SERIAL_CONFIG_SIZE);
98         X(IOCTL_SERIAL_GET_BAUD_RATE);
99         X(IOCTL_SERIAL_GET_CHARS);
100         X(IOCTL_SERIAL_GET_COMMSTATUS);
101         X(IOCTL_SERIAL_GET_DTRRTS);
102         X(IOCTL_SERIAL_GET_HANDFLOW);
103         X(IOCTL_SERIAL_GET_LINE_CONTROL);
104         X(IOCTL_SERIAL_GET_MODEM_CONTROL);
105         X(IOCTL_SERIAL_GET_MODEMSTATUS);
106         X(IOCTL_SERIAL_GET_PROPERTIES);
107         X(IOCTL_SERIAL_GET_STATS);
108         X(IOCTL_SERIAL_GET_TIMEOUTS);
109         X(IOCTL_SERIAL_GET_WAIT_MASK);
110         X(IOCTL_SERIAL_IMMEDIATE_CHAR);
111         X(IOCTL_SERIAL_LSRMST_INSERT);
112         X(IOCTL_SERIAL_PURGE);
113         X(IOCTL_SERIAL_RESET_DEVICE);
114         X(IOCTL_SERIAL_SET_BAUD_RATE);
115         X(IOCTL_SERIAL_SET_BREAK_ON);
116         X(IOCTL_SERIAL_SET_BREAK_OFF);
117         X(IOCTL_SERIAL_SET_CHARS);
118         X(IOCTL_SERIAL_SET_DTR);
119         X(IOCTL_SERIAL_SET_FIFO_CONTROL);
120         X(IOCTL_SERIAL_SET_HANDFLOW);
121         X(IOCTL_SERIAL_SET_LINE_CONTROL);
122         X(IOCTL_SERIAL_SET_MODEM_CONTROL);
123         X(IOCTL_SERIAL_SET_QUEUE_SIZE);
124         X(IOCTL_SERIAL_SET_RTS);
125         X(IOCTL_SERIAL_SET_TIMEOUTS);
126         X(IOCTL_SERIAL_SET_WAIT_MASK);
127         X(IOCTL_SERIAL_SET_XOFF);
128         X(IOCTL_SERIAL_SET_XON);
129         X(IOCTL_SERIAL_WAIT_ON_MASK);
130         X(IOCTL_SERIAL_XOFF_COUNTER);
131 #undef X
132     default: { static char tmp[32]; sprintf(tmp, "IOCTL_SERIAL_%d\n", ioc); return tmp; }
133     }
134 }
135
136 static NTSTATUS get_baud_rate(int fd, SERIAL_BAUD_RATE* sbr)
137 {
138     struct termios port;
139     int speed;
140     
141     if (tcgetattr(fd, &port) == -1)
142     {
143         ERR("tcgetattr error '%s'\n", strerror(errno));
144         return FILE_GetNtStatus();
145     }
146 #ifndef __EMX__
147 #ifdef CBAUD
148     speed = port.c_cflag & CBAUD;
149 #else
150     speed = cfgetospeed(&port);
151 #endif
152     switch (speed)
153     {
154     case B0:            sbr->BaudRate = 0;      break;
155     case B50:           sbr->BaudRate = 50;     break;
156     case B75:           sbr->BaudRate = 75;     break;
157     case B110:          sbr->BaudRate = 110;    break;
158     case B134:          sbr->BaudRate = 134;    break;
159     case B150:          sbr->BaudRate = 150;    break;
160     case B200:          sbr->BaudRate = 200;    break;
161     case B300:          sbr->BaudRate = 300;    break;
162     case B600:          sbr->BaudRate = 600;    break;
163     case B1200:         sbr->BaudRate = 1200;   break;
164     case B1800:         sbr->BaudRate = 1800;   break;
165     case B2400:         sbr->BaudRate = 2400;   break;
166     case B4800:         sbr->BaudRate = 4800;   break;
167     case B9600:         sbr->BaudRate = 9600;   break;
168     case B19200:        sbr->BaudRate = 19200;  break;
169     case B38400:        sbr->BaudRate = 38400;  break;
170 #ifdef B57600
171     case B57600:        sbr->BaudRate = 57600;  break;
172 #endif
173 #ifdef B115200
174     case B115200:       sbr->BaudRate = 115200; break;
175 #endif
176 #ifdef B230400
177     case B230400:       sbr->BaudRate = 230400; break;
178 #endif
179 #ifdef B460800
180     case B460800:       sbr->BaudRate = 460800; break;
181 #endif
182     default:
183         ERR("unknown speed %x\n", speed);
184         return STATUS_INVALID_PARAMETER;
185     }
186 #else
187     return STATUS_INVALID_PARAMETER;
188 #endif
189     return STATUS_SUCCESS;
190 }
191
192 static NTSTATUS get_hand_flow(int fd, SERIAL_HANDFLOW* shf)
193 {
194     int stat;
195     struct termios port;
196     
197     if (tcgetattr(fd, &port) == -1)
198     {
199         ERR("tcgetattr error '%s'\n", strerror(errno));
200         return FILE_GetNtStatus();
201     }
202 #ifdef TIOCMGET
203     if (ioctl(fd, TIOCMGET, &stat) == -1)
204     {
205         WARN("ioctl error '%s'\n", strerror(errno));
206         stat = DTR_CONTROL_ENABLE | RTS_CONTROL_ENABLE;
207     }
208 #endif
209     /* termios does not support DTR/DSR flow control */
210     shf->ControlHandShake = 0;
211     shf->FlowReplace = 0;
212 #ifdef TIOCM_DTR
213     if (stat & TIOCM_DTR)
214 #endif
215         shf->ControlHandShake |= SERIAL_DTR_CONTROL;
216 #ifdef CRTSCTS
217     if (port.c_cflag & CRTSCTS)
218     {
219         shf->ControlHandShake |= SERIAL_DTR_CONTROL | SERIAL_DTR_HANDSHAKE;
220         shf->ControlHandShake |= SERIAL_CTS_HANDSHAKE;
221     }
222     else
223 #endif
224     {
225 #ifdef TIOCM_RTS
226         if (stat & TIOCM_RTS)
227 #endif
228             shf->ControlHandShake |= SERIAL_RTS_CONTROL;
229     }
230     if (port.c_iflag & IXON)
231         shf->FlowReplace |= SERIAL_AUTO_RECEIVE;
232     if (port.c_iflag & IXOFF)
233         shf->FlowReplace |= SERIAL_AUTO_TRANSMIT;
234
235     shf->XonLimit = 10;
236     shf->XoffLimit = 10;
237     return STATUS_SUCCESS;
238 }
239
240 static NTSTATUS get_line_control(int fd, SERIAL_LINE_CONTROL* slc)
241 {
242     struct termios port;
243     
244     if (tcgetattr(fd, &port) == -1)
245     {
246         ERR("tcgetattr error '%s'\n", strerror(errno));
247         return FILE_GetNtStatus();
248     }
249     
250 #ifdef CMSPAR
251     switch (port.c_cflag & (PARENB | PARODD | CMSPAR))
252 #else
253     switch (port.c_cflag & (PARENB | PARODD))
254 #endif
255     {
256     case 0:                     slc->Parity = NOPARITY;         break;
257     case PARENB:                slc->Parity = EVENPARITY;       break;
258     case PARENB|PARODD:         slc->Parity = ODDPARITY;        break;
259 #ifdef CMSPAR
260     case PARENB|CMSPAR:         slc->Parity = MARKPARITY;       break;
261     case PARENB|PARODD|CMSPAR:  slc->Parity = SPACEPARITY;      break;
262 #endif
263     }
264     switch (port.c_cflag & CSIZE)
265     {
266     case CS5:   slc->WordLength = 5;    break;
267     case CS6:   slc->WordLength = 6;    break;
268     case CS7:   slc->WordLength = 7;    break;
269     case CS8:   slc->WordLength = 8;    break;
270     default: ERR("unknown size %x\n", (UINT)(port.c_cflag & CSIZE));
271     }
272     
273     if (port.c_cflag & CSTOPB)
274     {
275         if (slc->WordLength == 5)
276             slc->StopBits = ONE5STOPBITS;
277         else
278             slc->StopBits = TWOSTOPBITS;
279     }
280     else
281         slc->StopBits = ONESTOPBIT;
282
283     return STATUS_SUCCESS;
284 }
285
286 static NTSTATUS get_modem_status(int fd, DWORD* lpModemStat)
287 {
288     NTSTATUS    status = STATUS_SUCCESS;
289     int         mstat;
290
291 #ifdef TIOCMGET
292     if (ioctl(fd, TIOCMGET, &mstat) == -1)
293     {
294         WARN("ioctl failed\n");
295         status = FILE_GetNtStatus();
296     }
297     else
298     {
299         *lpModemStat = 0;
300 #ifdef TIOCM_CTS
301         if (mstat & TIOCM_CTS)  *lpModemStat |= MS_CTS_ON;
302 #endif
303 #ifdef TIOCM_DSR
304         if (mstat & TIOCM_DSR)  *lpModemStat |= MS_DSR_ON;
305 #endif
306 #ifdef TIOCM_RNG
307         if (mstat & TIOCM_RNG)  *lpModemStat |= MS_RING_ON;
308 #endif
309 #ifdef TIOCM_CAR
310         /* FIXME: Not really sure about RLSD UB 990810 */
311         if (mstat & TIOCM_CAR)  *lpModemStat |= MS_RLSD_ON;
312 #endif
313         TRACE("%04x -> %s%s%s%s\n", mstat,
314               (*lpModemStat & MS_RLSD_ON) ? "MS_RLSD_ON " : "",
315               (*lpModemStat & MS_RING_ON) ? "MS_RING_ON " : "",
316               (*lpModemStat & MS_DSR_ON)  ? "MS_DSR_ON  " : "",
317               (*lpModemStat & MS_CTS_ON)  ? "MS_CTS_ON  " : "");
318     }
319 #else
320     status = STATUS_NOT_SUPPORTED;
321 #endif
322     return status;
323 }
324
325 static NTSTATUS get_special_chars(int fd, SERIAL_CHARS* sc)
326 {
327     struct termios port;
328     
329     if (tcgetattr(fd, &port) == -1)
330     {
331         ERR("tcgetattr error '%s'\n", strerror(errno));
332         return FILE_GetNtStatus();
333     }
334     sc->EofChar   = port.c_cc[VEOF];
335     sc->ErrorChar = 0xFF;
336     sc->BreakChar = 0; /* FIXME */
337     sc->EventChar = 0; /* FIXME */
338     sc->XonChar   = port.c_cc[VSTART];
339     sc->XoffChar  = port.c_cc[VSTOP];
340
341     return STATUS_SUCCESS;
342 }
343
344 static NTSTATUS get_status(int fd, SERIAL_STATUS* ss)
345 {
346     NTSTATUS    status = STATUS_SUCCESS;
347
348     ss->Errors = 0;
349     ss->HoldReasons = 0;
350     ss->EofReceived = FALSE;
351     ss->WaitForImmediate = FALSE;
352 #ifdef TIOCOUTQ
353     if (ioctl(fd, TIOCOUTQ, &ss->AmountInOutQueue) == -1)
354     {
355         WARN("ioctl returned error\n");
356         status = FILE_GetNtStatus();
357     }
358 #else
359     ss->AmountInOutQueue = 0; /* FIXME: find a different way to find out */
360 #endif
361
362 #ifdef TIOCINQ
363     if (ioctl(fd, TIOCINQ, &ss->AmountInInQueue))
364     {
365         WARN("ioctl returned error\n");
366         status = FILE_GetNtStatus();
367     }
368 #else
369     ss->AmountInInQueue = 0; /* FIXME: find a different way to find out */
370 #endif
371     return status;
372 }
373
374 static NTSTATUS get_timeouts(HANDLE handle, SERIAL_TIMEOUTS* st)
375 {
376     NTSTATUS    status;
377     SERVER_START_REQ( get_serial_info )
378     {
379         req->handle = handle;
380         if (!(status = wine_server_call( req )))
381         {
382             st->ReadIntervalTimeout         = reply->readinterval;
383             st->ReadTotalTimeoutMultiplier  = reply->readmult;
384             st->ReadTotalTimeoutConstant    = reply->readconst;
385             st->WriteTotalTimeoutMultiplier = reply->writemult;
386             st->WriteTotalTimeoutConstant   = reply->writeconst;
387         }
388     }
389     SERVER_END_REQ;
390     return status;
391 }
392
393 static NTSTATUS get_wait_mask(HANDLE hDevice, DWORD* mask)
394 {
395     NTSTATUS    status;
396
397     SERVER_START_REQ( get_serial_info )
398     {
399         req->handle = hDevice;
400         if (!(status = wine_server_call( req )))
401             *mask = reply->eventmask;
402     }
403     SERVER_END_REQ;
404     return status;
405 }
406
407 static NTSTATUS purge(int fd, DWORD flags)
408 {
409     /*
410     ** not exactly sure how these are different
411     ** Perhaps if we had our own internal queues, one flushes them
412     ** and the other flushes the kernel's buffers.
413     */
414     if (flags & PURGE_TXABORT) tcflush(fd, TCOFLUSH);
415     if (flags & PURGE_RXABORT) tcflush(fd, TCIFLUSH);
416     if (flags & PURGE_TXCLEAR) tcflush(fd, TCOFLUSH);
417     if (flags & PURGE_RXCLEAR) tcflush(fd, TCIFLUSH);
418     return STATUS_SUCCESS;
419 }
420
421 static NTSTATUS set_baud_rate(int fd, const SERIAL_BAUD_RATE* sbr)
422 {
423     struct termios port;
424
425     if (tcgetattr(fd, &port) == -1)
426     {
427         ERR("tcgetattr error '%s'\n", strerror(errno));
428         return FILE_GetNtStatus();
429     }
430
431 #ifdef CBAUD
432     port.c_cflag &= ~CBAUD;
433     switch (sbr->BaudRate)
434     {
435     case 0:             port.c_cflag |= B0;     break;
436     case 50:            port.c_cflag |= B50;    break;
437     case 75:            port.c_cflag |= B75;    break;
438     case 110:   
439     case CBR_110:       port.c_cflag |= B110;   break;
440     case 134:           port.c_cflag |= B134;   break;
441     case 150:           port.c_cflag |= B150;   break;
442     case 200:           port.c_cflag |= B200;   break;
443     case 300:           
444     case CBR_300:       port.c_cflag |= B300;   break;
445     case 600:
446     case CBR_600:       port.c_cflag |= B600;   break;
447     case 1200:
448     case CBR_1200:      port.c_cflag |= B1200;  break;
449     case 1800:          port.c_cflag |= B1800;  break;
450     case 2400:
451     case CBR_2400:      port.c_cflag |= B2400;  break;
452     case 4800:
453     case CBR_4800:      port.c_cflag |= B4800;  break;
454     case 9600:
455     case CBR_9600:      port.c_cflag |= B9600;  break;
456     case 19200:
457     case CBR_19200:     port.c_cflag |= B19200; break;
458     case 38400:
459     case CBR_38400:     port.c_cflag |= B38400; break;
460 #ifdef B57600
461     case 57600:         port.c_cflag |= B57600; break;
462 #endif
463 #ifdef B115200
464     case 115200:        port.c_cflag |= B115200;break;
465 #endif
466 #ifdef B230400
467     case 230400:        port.c_cflag |= B230400;break;
468 #endif
469 #ifdef B460800
470     case 460800:        port.c_cflag |= B460800;break;
471 #endif
472     default:
473 #if defined (HAVE_LINUX_SERIAL_H) && defined (TIOCSSERIAL)
474         {
475             struct serial_struct nuts;
476             int arby;
477         
478             ioctl(fd, TIOCGSERIAL, &nuts);
479             nuts.custom_divisor = nuts.baud_base / sbr->BaudRate;
480             if (!(nuts.custom_divisor)) nuts.custom_divisor = 1;
481             arby = nuts.baud_base / nuts.custom_divisor;
482             nuts.flags &= ~ASYNC_SPD_MASK;
483             nuts.flags |= ASYNC_SPD_CUST;
484             WARN("You (or a program acting at your behest) have specified\n"
485                  "a non-standard baud rate %d.  Wine will set the rate to %d,\n"
486                  "which is as close as we can get by our present understanding of your\n"
487                  "hardware. I hope you know what you are doing.  Any disruption Wine\n"
488                  "has caused to your linux system can be undone with setserial \n"
489                  "(see man setserial). If you have incapacitated a Hayes type modem,\n"
490                  "reset it and it will probably recover.\n", sbr->BaudRate, arby);
491             ioctl(fd, TIOCSSERIAL, &nuts);
492             port.c_cflag |= B38400;
493         }
494         break;
495 #else     /* Don't have linux/serial.h or lack TIOCSSERIAL */
496         ERR("baudrate %d\n", sbr->BaudRate);
497         return STATUS_NOT_SUPPORTED;
498 #endif    /* Don't have linux/serial.h or lack TIOCSSERIAL */
499     }
500 #elif !defined(__EMX__)
501     switch (sbr->BaudRate)
502     {
503     case 0:             port.c_ospeed = B0;     break;
504     case 50:            port.c_ospeed = B50;    break;
505     case 75:            port.c_ospeed = B75;    break;
506     case 110:
507     case CBR_110:       port.c_ospeed = B110;   break;
508     case 134:           port.c_ospeed = B134;   break;
509     case 150:           port.c_ospeed = B150;   break;
510     case 200:           port.c_ospeed = B200;   break;
511     case 300:
512     case CBR_300:       port.c_ospeed = B300;   break;
513     case 600:
514     case CBR_600:       port.c_ospeed = B600;   break;
515     case 1200:
516     case CBR_1200:      port.c_ospeed = B1200;  break;
517     case 1800:          port.c_ospeed = B1800;  break;
518     case 2400:
519     case CBR_2400:      port.c_ospeed = B2400;  break;
520     case 4800:
521     case CBR_4800:      port.c_ospeed = B4800;  break;
522     case 9600:
523     case CBR_9600:      port.c_ospeed = B9600;  break;
524     case 19200:
525     case CBR_19200:     port.c_ospeed = B19200; break;
526     case 38400:
527     case CBR_38400:     port.c_ospeed = B38400; break;
528 #ifdef B57600
529     case 57600:
530     case CBR_57600:     port.c_cflag |= B57600; break;
531 #endif
532 #ifdef B115200
533     case 115200:
534     case CBR_115200:    port.c_cflag |= B115200;break;
535 #endif
536 #ifdef B230400
537     case 230400:        port.c_cflag |= B230400;break;
538 #endif
539 #ifdef B460800
540     case 460800:        port.c_cflag |= B460800;break;
541 #endif
542     default:
543         ERR("baudrate %d\n", sbr->BaudRate);
544         return STATUS_NOT_SUPPORTED;
545     }
546     port.c_ispeed = port.c_ospeed;
547 #endif
548     if (tcsetattr(fd, TCSANOW, &port) == -1)
549     {
550         ERR("tcsetattr error '%s'\n", strerror(errno));
551         return FILE_GetNtStatus();
552     }
553     return STATUS_SUCCESS;
554 }
555
556 static int whack_modem(int fd, unsigned int andy, unsigned int orrie)
557 {
558 #ifdef TIOCMGET
559     unsigned int mstat, okay;
560     okay = ioctl(fd, TIOCMGET, &mstat);
561     if (okay) return okay;
562     if (andy) mstat &= andy;
563     mstat |= orrie;
564     return ioctl(fd, TIOCMSET, &mstat);
565 #else
566     return 0;
567 #endif
568 }
569
570 static NTSTATUS set_handflow(int fd, const SERIAL_HANDFLOW* shf)
571 {
572     struct termios port;
573
574     if ((shf->FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE)) == 
575         (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE))
576         return STATUS_NOT_SUPPORTED;
577
578     if (tcgetattr(fd, &port) == -1)
579     {
580         ERR("tcgetattr error '%s'\n", strerror(errno));
581         return FILE_GetNtStatus();
582     }
583     
584 #ifdef CRTSCTS
585     if ((shf->ControlHandShake & SERIAL_CTS_HANDSHAKE) ||
586         (shf->FlowReplace & SERIAL_RTS_HANDSHAKE))
587     {
588         port.c_cflag |= CRTSCTS;
589         TRACE("CRTSCTS\n");
590     }
591     else
592         port.c_cflag &= ~CRTSCTS;
593 #endif
594 #ifdef TIOCM_DTR
595     if (shf->ControlHandShake & SERIAL_DTR_HANDSHAKE)
596     {
597         WARN("DSR/DTR flow control not supported\n");
598     } else if (!(shf->ControlHandShake & SERIAL_DTR_CONTROL))
599         whack_modem(fd, ~TIOCM_DTR, 0);
600     else
601         whack_modem(fd, 0, TIOCM_DTR);
602 #endif
603 #ifdef TIOCM_RTS
604     if (!(shf->ControlHandShake & SERIAL_CTS_HANDSHAKE))
605     {
606         if ((shf->FlowReplace & (SERIAL_RTS_CONTROL|SERIAL_RTS_HANDSHAKE)) == 0)
607             whack_modem(fd, ~TIOCM_RTS, 0);
608         else    
609             whack_modem(fd, 0, TIOCM_RTS);
610     }
611 #endif
612
613     if (shf->FlowReplace & SERIAL_AUTO_RECEIVE)
614         port.c_iflag |= IXON;
615     else
616         port.c_iflag &= ~IXON;
617     if (shf->FlowReplace & SERIAL_AUTO_TRANSMIT)
618         port.c_iflag |= IXOFF;
619     else
620         port.c_iflag &= ~IXOFF;
621     if (tcsetattr(fd, TCSANOW, &port) == -1)
622     {
623         ERR("tcsetattr error '%s'\n", strerror(errno));
624         return FILE_GetNtStatus();
625     }
626
627     return STATUS_SUCCESS;
628 }
629
630 static NTSTATUS set_line_control(int fd, const SERIAL_LINE_CONTROL* slc)
631 {
632     struct termios port;
633     unsigned bytesize, stopbits;
634     
635     if (tcgetattr(fd, &port) == -1)
636     {
637         ERR("tcgetattr error '%s'\n", strerror(errno));
638         return FILE_GetNtStatus();
639     }
640     
641 #ifdef IMAXBEL
642     port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK|IMAXBEL);
643 #else
644     port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK);
645 #endif
646     port.c_iflag |= IGNBRK | INPCK;
647     
648     port.c_oflag &= ~(OPOST);
649     
650     port.c_cflag &= ~(HUPCL);
651     port.c_cflag |= CLOCAL | CREAD;
652     
653     port.c_lflag &= ~(ICANON|ECHO|ISIG);
654     port.c_lflag |= NOFLSH;
655     
656     bytesize = slc->WordLength;
657     stopbits = slc->StopBits;
658     
659 #ifdef CMSPAR
660     port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
661 #else
662     port.c_cflag &= ~(PARENB | PARODD);
663 #endif
664
665     switch (slc->Parity)
666     {
667     case NOPARITY:      port.c_iflag &= ~INPCK;                         break;
668     case ODDPARITY:     port.c_cflag |= PARENB | PARODD;                break;
669     case EVENPARITY:    port.c_cflag |= PARENB;                         break;
670 #ifdef CMSPAR
671         /* Linux defines mark/space (stick) parity */
672     case MARKPARITY:    port.c_cflag |= PARENB | CMSPAR;                break;
673     case SPACEPARITY:   port.c_cflag |= PARENB | PARODD |  CMSPAR;      break;
674 #else
675         /* try the POSIX way */
676     case MARKPARITY:
677         if (slc->StopBits == ONESTOPBIT)
678         {
679             stopbits = TWOSTOPBITS;
680             port.c_iflag &= ~INPCK;
681         }
682         else
683         {
684             ERR("Cannot set MARK Parity\n");
685             return STATUS_NOT_SUPPORTED;
686         }
687         break;
688     case SPACEPARITY:
689         if (slc->WordLength < 8)
690         {
691             bytesize +=1;
692             port.c_iflag &= ~INPCK;
693         }
694         else
695         {
696             ERR("Cannot set SPACE Parity\n");
697             return STATUS_NOT_SUPPORTED;
698         }
699         break;
700 #endif
701     default:
702         ERR("Parity\n");
703         return STATUS_NOT_SUPPORTED;
704     }
705     
706     port.c_cflag &= ~CSIZE;
707     switch (bytesize)
708     {
709     case 5:     port.c_cflag |= CS5;    break;
710     case 6:     port.c_cflag |= CS6;    break;
711     case 7:     port.c_cflag |= CS7;    break;
712     case 8:     port.c_cflag |= CS8;    break;
713     default:
714         ERR("ByteSize\n");
715         return STATUS_NOT_SUPPORTED;
716     }
717     
718     switch (stopbits)
719     {
720     case ONESTOPBIT:    port.c_cflag &= ~CSTOPB;        break;
721     case ONE5STOPBITS: /* will be selected if bytesize is 5 */
722     case TWOSTOPBITS:   port.c_cflag |= CSTOPB;         break;
723     default:
724         ERR("StopBits\n");
725         return STATUS_NOT_SUPPORTED;
726     }
727     /* otherwise it hangs with pending input*/
728     if (tcsetattr(fd, TCSANOW, &port) == -1)
729     {
730         ERR("tcsetattr error '%s'\n", strerror(errno));
731         return FILE_GetNtStatus();
732     }
733     return STATUS_SUCCESS;
734 }
735
736 static NTSTATUS set_queue_size(int fd, const SERIAL_QUEUE_SIZE* sqs)
737 {
738     FIXME("insize %d outsize %d unimplemented stub\n", sqs->InSize, sqs->OutSize);
739     return STATUS_SUCCESS;
740 }
741
742 static NTSTATUS set_special_chars(int fd, const SERIAL_CHARS* sc)
743 {
744     struct termios port;
745     
746     if (tcgetattr(fd, &port) == -1)
747     {
748         ERR("tcgetattr error '%s'\n", strerror(errno));
749         return FILE_GetNtStatus();
750     }
751     
752     port.c_cc[VMIN  ] = 0;
753     port.c_cc[VTIME ] = 1;
754     
755     port.c_cc[VEOF  ] = sc->EofChar;
756     /* FIXME: sc->ErrorChar is not supported */
757     /* FIXME: sc->BreakChar is not supported */
758     /* FIXME: sc->EventChar is not supported */
759     port.c_cc[VSTART] = sc->XonChar;
760     port.c_cc[VSTOP ] = sc->XoffChar;
761     
762     if (tcsetattr(fd, TCSANOW, &port) == -1)
763     {
764         ERR("tcsetattr error '%s'\n", strerror(errno));
765         return FILE_GetNtStatus();
766     }
767     return STATUS_SUCCESS;
768 }
769
770 static NTSTATUS set_timeouts(HANDLE handle, int fd, const SERIAL_TIMEOUTS* st)
771 {
772     NTSTATUS            status;
773     struct termios      port;
774     unsigned int        ux_timeout;
775
776     SERVER_START_REQ( set_serial_info )
777     {
778         req->handle       = handle;
779         req->flags        = SERIALINFO_SET_TIMEOUTS;
780         req->readinterval = st->ReadIntervalTimeout ;
781         req->readmult     = st->ReadTotalTimeoutMultiplier ;
782         req->readconst    = st->ReadTotalTimeoutConstant ;
783         req->writemult    = st->WriteTotalTimeoutMultiplier ;
784         req->writeconst   = st->WriteTotalTimeoutConstant ;
785         status = wine_server_call( req );
786     }
787     SERVER_END_REQ;
788     if (status) return status;
789
790     if (tcgetattr(fd, &port) == -1)
791     {
792         FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
793         return FILE_GetNtStatus();
794     }
795
796     /* VTIME is in 1/10 seconds */
797     if (st->ReadIntervalTimeout == 0) /* 0 means no timeout */
798         ux_timeout = 0;
799     else
800     {
801         ux_timeout = (st->ReadIntervalTimeout + 99) / 100;
802         if (ux_timeout == 0)
803             ux_timeout = 1; /* must be at least some timeout */
804     }
805     port.c_cc[VTIME] = ux_timeout;
806
807     if (tcsetattr(fd, 0, &port) == -1)
808     {
809         FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
810         return FILE_GetNtStatus();
811     }
812     return STATUS_SUCCESS;
813 }
814
815 static NTSTATUS set_wait_mask(HANDLE hDevice, DWORD mask)
816 {
817     NTSTATUS status;
818
819     SERVER_START_REQ( set_serial_info )
820     {
821         req->handle    = hDevice;
822         req->flags     = SERIALINFO_SET_MASK;
823         req->eventmask = mask;
824         status = wine_server_call( req );
825     }
826     SERVER_END_REQ;
827     return status;
828 }
829
830 static NTSTATUS set_XOff(int fd)
831 {
832     struct termios      port;
833
834     if (tcgetattr(fd,&port) == -1)
835     {
836         FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
837         return FILE_GetNtStatus();
838
839
840     }
841     port.c_iflag |= IXOFF;
842     if (tcsetattr(fd, TCSADRAIN, &port) == -1)
843     {
844         FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
845         return FILE_GetNtStatus();
846     }
847     return STATUS_SUCCESS;
848 }
849
850 static NTSTATUS set_XOn(int fd)
851 {
852     struct termios      port;
853
854     if (tcgetattr(fd,&port) == -1)
855     {
856         FIXME("tcgetattr on fd %d failed (%s)!\n", fd, strerror(errno));
857         return FILE_GetNtStatus();
858     }
859     port.c_iflag |= IXON;
860     if (tcsetattr(fd, TCSADRAIN, &port) == -1)
861     {
862         FIXME("tcsetattr on fd %d failed (%s)!\n", fd, strerror(errno));
863         return FILE_GetNtStatus();
864     }
865     return STATUS_SUCCESS;
866 }
867
868 /*             serial_irq_info
869  * local structure holding the irq values we need for WaitCommEvent()
870  *
871  * Stripped down from struct serial_icounter_struct, which may not be available on some systems
872  * As the modem line interrupts (cts, dsr, rng, dcd) only get updated with TIOCMIWAIT active,
873  * no need to carry them in the internal structure
874  *
875  */
876 typedef struct serial_irq_info
877 {
878     int rx , tx, frame, overrun, parity, brk, buf_overrun;
879 }serial_irq_info;
880
881 /***********************************************************************
882  * Data needed by the thread polling for the changing CommEvent
883  */
884 typedef struct async_commio
885 {
886     HANDLE              hDevice;
887     DWORD*              events;
888     HANDLE              hEvent;
889     DWORD               evtmask;
890     DWORD               mstat;
891     serial_irq_info     irq_info;
892 } async_commio;
893
894 /***********************************************************************
895  *   Get extended interrupt count info, needed for wait_on
896  */
897 static NTSTATUS get_irq_info(int fd, serial_irq_info *irq_info)
898 {
899 #ifdef TIOCGICOUNT
900     struct serial_icounter_struct einfo;
901     if (!ioctl(fd, TIOCGICOUNT, &einfo))
902     {
903         irq_info->rx          = einfo.rx;
904         irq_info->tx          = einfo.tx;
905         irq_info->frame       = einfo.frame;
906         irq_info->overrun     = einfo.overrun;
907         irq_info->parity      = einfo.parity;
908         irq_info->brk         = einfo.brk;
909         irq_info->buf_overrun = einfo.buf_overrun;
910         return STATUS_SUCCESS;
911     }
912     TRACE("TIOCGICOUNT err %s\n", strerror(errno));
913     return FILE_GetNtStatus();
914 #else
915     memset(irq_info,0, sizeof(serial_irq_info));
916     return STATUS_NOT_IMPLEMENTED;
917 #endif
918 }
919
920
921 static DWORD WINAPI check_events(int fd, DWORD mask, 
922                                  const serial_irq_info *new, 
923                                  const serial_irq_info *old,
924                                  DWORD new_mstat, DWORD old_mstat)
925 {
926     DWORD ret = 0, queue;
927
928     TRACE("mask 0x%08x\n", mask);
929     TRACE("old->rx          0x%08x vs. new->rx          0x%08x\n", old->rx, new->rx);
930     TRACE("old->tx          0x%08x vs. new->tx          0x%08x\n", old->tx, new->tx);
931     TRACE("old->frame       0x%08x vs. new->frame       0x%08x\n", old->frame, new->frame);
932     TRACE("old->overrun     0x%08x vs. new->overrun     0x%08x\n", old->overrun, new->overrun);
933     TRACE("old->parity      0x%08x vs. new->parity      0x%08x\n", old->parity, new->parity);
934     TRACE("old->brk         0x%08x vs. new->brk         0x%08x\n", old->brk, new->brk);
935     TRACE("old->buf_overrun 0x%08x vs. new->buf_overrun 0x%08x\n", old->buf_overrun, new->buf_overrun);
936
937     if (old->brk != new->brk) ret |= EV_BREAK;
938     if ((old_mstat & MS_CTS_ON ) != (new_mstat & MS_CTS_ON )) ret |= EV_CTS;
939     if ((old_mstat & MS_DSR_ON ) != (new_mstat & MS_DSR_ON )) ret |= EV_DSR;
940     if ((old_mstat & MS_RING_ON) != (new_mstat & MS_RING_ON)) ret |= EV_RING;
941     if ((old_mstat & MS_RLSD_ON) != (new_mstat & MS_RLSD_ON)) ret |= EV_RLSD;
942     if (old->frame != new->frame || old->overrun != new->overrun || old->parity != new->parity) ret |= EV_ERR;
943     if (mask & EV_RXCHAR)
944     {
945         queue = 0;
946 #ifdef TIOCINQ
947         if (ioctl(fd, TIOCINQ, &queue))
948             WARN("TIOCINQ returned error\n");
949 #endif
950         if (queue)
951             ret |= EV_RXCHAR;
952     }
953     if (mask & EV_TXEMPTY)
954     {
955         queue = 0;
956 /* We really want to know when all characters have gone out of the transmitter */
957 #if defined(TIOCSERGETLSR) 
958         if (ioctl(fd, TIOCSERGETLSR, &queue))
959             WARN("TIOCSERGETLSR returned error\n");
960         if (queue)
961 /* TIOCOUTQ only checks for an empty buffer */
962 #elif defined(TIOCOUTQ)
963         if (ioctl(fd, TIOCOUTQ, &queue))
964             WARN("TIOCOUTQ returned error\n");
965         if (!queue)
966 #endif
967            ret |= EV_TXEMPTY;
968         TRACE("OUTQUEUE %d, Transmitter %sempty\n",
969               queue, (ret & EV_TXEMPTY) ? "" : "not ");
970     }
971     return ret & mask;
972 }
973
974 /***********************************************************************
975  *             wait_for_event      (INTERNAL)
976  *
977  *  We need to poll for what is interesting
978  *  TIOCMIWAIT only checks modem status line and may not be aborted by a changing mask
979  *
980  */
981 static DWORD CALLBACK wait_for_event(LPVOID arg)
982 {
983     async_commio *commio = (async_commio*) arg;
984     int fd, needs_close;
985
986     if (!server_get_unix_fd( commio->hDevice, FILE_READ_DATA | FILE_WRITE_DATA, &fd, &needs_close, NULL, NULL ))
987     {
988         serial_irq_info new_irq_info;
989         DWORD new_mstat, new_evtmask;
990         LARGE_INTEGER time;
991         
992         TRACE("device=%p fd=0x%08x mask=0x%08x buffer=%p event=%p irq_info=%p\n", 
993               commio->hDevice, fd, commio->evtmask, commio->events, commio->hEvent, &commio->irq_info);
994
995         time.QuadPart = (ULONGLONG)10000;
996         time.QuadPart = -time.QuadPart;
997         for (;;)
998         {
999             /*
1000              * TIOCMIWAIT is not adequate
1001              *
1002              * FIXME:
1003              * We don't handle the EV_RXFLAG (the eventchar)
1004              */
1005             NtDelayExecution(FALSE, &time);
1006             get_irq_info(fd, &new_irq_info);
1007             if (get_modem_status(fd, &new_mstat))
1008                 TRACE("get_modem_status failed\n");
1009             *commio->events = check_events(fd, commio->evtmask,
1010                                            &new_irq_info, &commio->irq_info,
1011                                            new_mstat, commio->mstat);
1012             if (*commio->events) break;
1013             get_wait_mask(commio->hDevice, &new_evtmask);
1014             if (commio->evtmask != new_evtmask)
1015             {
1016                 *commio->events = 0;
1017                 break;
1018             }
1019         }
1020         if (needs_close) close( fd );
1021     }
1022     if (commio->hEvent) NtSetEvent(commio->hEvent, NULL);
1023     RtlFreeHeap(GetProcessHeap(), 0, commio);
1024     return 0;
1025 }
1026
1027 static NTSTATUS wait_on(HANDLE hDevice, int fd, HANDLE hEvent, DWORD* events)
1028 {
1029     async_commio*       commio;
1030     NTSTATUS            status;
1031
1032     if ((status = NtResetEvent(hEvent, NULL)))
1033         return status;
1034
1035     commio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof (async_commio));
1036     if (!commio) return STATUS_NO_MEMORY;
1037
1038     commio->hDevice = hDevice;
1039     commio->events  = events;
1040     commio->hEvent  = hEvent;
1041     get_wait_mask(commio->hDevice, &commio->evtmask);
1042
1043 /* We may never return, if some capabilities miss
1044  * Return error in that case
1045  */
1046 #if !defined(TIOCINQ)
1047     if (commio->evtmask & EV_RXCHAR)
1048         goto error_caps;
1049 #endif
1050 #if !(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)
1051     if (commio->evtmask & EV_TXEMPTY)
1052         goto error_caps;
1053 #endif
1054 #if !defined(TIOCMGET)
1055     if (commio->evtmask & (EV_CTS | EV_DSR| EV_RING| EV_RLSD))
1056         goto error_caps;
1057 #endif
1058 #if !defined(TIOCM_CTS)
1059     if (commio->evtmask & EV_CTS)
1060         goto error_caps;
1061 #endif
1062 #if !defined(TIOCM_DSR)
1063     if (commio->evtmask & EV_DSR)
1064         goto error_caps;
1065 #endif
1066 #if !defined(TIOCM_RNG)
1067     if (commio->evtmask & EV_RING)
1068         goto error_caps;
1069 #endif
1070 #if !defined(TIOCM_CAR)
1071     if (commio->evtmask & EV_RLSD)
1072         goto error_caps;
1073 #endif
1074     if (commio->evtmask & EV_RXFLAG)
1075         FIXME("EV_RXFLAG not handled\n");
1076     if ((status = get_irq_info(fd, &commio->irq_info)) ||
1077         (status = get_modem_status(fd, &commio->mstat)))
1078         goto out_now;
1079
1080     /* We might have received something or the TX bufffer is delivered */
1081     *events = check_events(fd, commio->evtmask,
1082                                &commio->irq_info, &commio->irq_info,
1083                                commio->mstat, commio->mstat);
1084     if (*events) goto out_now;
1085
1086     /* create the worker for the task */
1087     status = RtlQueueWorkItem(wait_for_event, commio, 0 /* FIXME */);
1088     if (status != STATUS_SUCCESS) goto out_now;
1089     return STATUS_PENDING;
1090
1091 #if !defined(TIOCINQ) || (!(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)) || !defined(TIOCMGET) || !defined(TIOCM_CTS) ||!defined(TIOCM_DSR) || !defined(TIOCM_RNG) || !defined(TIOCM_CAR)
1092 error_caps:
1093     FIXME("Returning error because of missing capabilities\n");
1094     status = STATUS_INVALID_PARAMETER;
1095 #endif
1096 out_now:
1097     RtlFreeHeap(GetProcessHeap(), 0, commio);
1098     return status;
1099 }
1100
1101 static NTSTATUS xmit_immediate(HANDLE hDevice, int fd, const char* ptr)
1102 {
1103     /* FIXME: not perfect as it should bypass the in-queue */
1104     WARN("(%p,'%c') not perfect!\n", hDevice, *ptr);
1105     if (write(fd, ptr, 1) != 1)
1106         return FILE_GetNtStatus();
1107     return STATUS_SUCCESS;
1108 }
1109
1110 /******************************************************************
1111  *              COMM_DeviceIoControl
1112  *
1113  *
1114  */
1115 static inline NTSTATUS io_control(HANDLE hDevice, 
1116                                   HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
1117                                   PVOID UserApcContext, 
1118                                   PIO_STATUS_BLOCK piosb, 
1119                                   ULONG dwIoControlCode,
1120                                   LPVOID lpInBuffer, DWORD nInBufferSize,
1121                                   LPVOID lpOutBuffer, DWORD nOutBufferSize)
1122 {
1123     DWORD       sz = 0, access = FILE_READ_DATA;
1124     NTSTATUS    status = STATUS_SUCCESS;
1125     int         fd = -1, needs_close = 0;
1126
1127     TRACE("%p %s %p %d %p %d %p\n",
1128           hDevice, iocode2str(dwIoControlCode), lpInBuffer, nInBufferSize,
1129           lpOutBuffer, nOutBufferSize, piosb);
1130
1131     piosb->Information = 0;
1132
1133     if (dwIoControlCode != IOCTL_SERIAL_GET_TIMEOUTS)
1134         if ((status = server_get_unix_fd( hDevice, access, &fd, &needs_close, NULL, NULL )))
1135             goto error;
1136
1137     switch (dwIoControlCode)
1138     {
1139     case IOCTL_SERIAL_CLR_DTR:
1140 #ifdef TIOCM_DTR
1141         if (whack_modem(fd, ~TIOCM_DTR, 0) == -1) status = FILE_GetNtStatus();
1142 #else
1143         status = STATUS_NOT_SUPPORTED;
1144 #endif
1145         break;
1146     case IOCTL_SERIAL_CLR_RTS:
1147 #ifdef TIOCM_RTS
1148         if (whack_modem(fd, ~TIOCM_RTS, 0) == -1) status = FILE_GetNtStatus();
1149 #else
1150         status = STATUS_NOT_SUPPORTED;
1151 #endif
1152         break;
1153     case IOCTL_SERIAL_GET_BAUD_RATE:
1154         if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_BAUD_RATE))
1155         {
1156             if (!(status = get_baud_rate(fd, (SERIAL_BAUD_RATE*)lpOutBuffer)))
1157                 sz = sizeof(SERIAL_BAUD_RATE);
1158         }
1159         else
1160             status = STATUS_INVALID_PARAMETER;
1161         break;
1162     case IOCTL_SERIAL_GET_CHARS:
1163         if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_CHARS))
1164         {
1165             if (!(status = get_special_chars(fd, (SERIAL_CHARS*)lpOutBuffer)))
1166                 sz = sizeof(SERIAL_CHARS);
1167         }
1168         else
1169             status = STATUS_INVALID_PARAMETER;
1170         break;
1171      case IOCTL_SERIAL_GET_COMMSTATUS:
1172         if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_STATUS))
1173         {
1174             if (!(status = get_status(fd, (SERIAL_STATUS*)lpOutBuffer)))
1175                 sz = sizeof(SERIAL_STATUS);
1176         }
1177         else status = STATUS_INVALID_PARAMETER;
1178         break;
1179     case IOCTL_SERIAL_GET_HANDFLOW:
1180         if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_HANDFLOW))
1181         {
1182             if (!(status = get_hand_flow(fd, (SERIAL_HANDFLOW*)lpOutBuffer)))
1183                 sz = sizeof(SERIAL_HANDFLOW);
1184         }
1185         else
1186             status = STATUS_INVALID_PARAMETER;
1187         break;
1188     case IOCTL_SERIAL_GET_LINE_CONTROL:
1189         if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_LINE_CONTROL))
1190         {
1191             if (!(status = get_line_control(fd, (SERIAL_LINE_CONTROL*)lpOutBuffer)))
1192                 sz = sizeof(SERIAL_LINE_CONTROL);
1193         }
1194         else
1195             status = STATUS_INVALID_PARAMETER;
1196         break;
1197     case IOCTL_SERIAL_GET_MODEMSTATUS:
1198         if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1199         {
1200             if (!(status = get_modem_status(fd, (DWORD*)lpOutBuffer)))
1201                 sz = sizeof(DWORD);
1202         }
1203         else status = STATUS_INVALID_PARAMETER;
1204         break;
1205     case IOCTL_SERIAL_GET_TIMEOUTS:
1206         if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_TIMEOUTS))
1207         {
1208             if (!(status = get_timeouts(hDevice, (SERIAL_TIMEOUTS*)lpOutBuffer)))
1209                 sz = sizeof(SERIAL_TIMEOUTS);
1210         }
1211         else
1212             status = STATUS_INVALID_PARAMETER;
1213         break;
1214     case IOCTL_SERIAL_GET_WAIT_MASK:
1215         if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1216         {
1217             if (!(status = get_wait_mask(hDevice, (DWORD*)lpOutBuffer)))
1218                 sz = sizeof(DWORD);
1219         }
1220         else
1221             status = STATUS_INVALID_PARAMETER;
1222         break;
1223     case IOCTL_SERIAL_IMMEDIATE_CHAR:
1224         if (lpInBuffer && nInBufferSize == sizeof(CHAR))
1225             status = xmit_immediate(hDevice, fd, lpInBuffer);
1226         else
1227             status = STATUS_INVALID_PARAMETER;
1228         break;
1229     case IOCTL_SERIAL_PURGE:
1230         if (lpInBuffer && nInBufferSize == sizeof(DWORD))
1231             status = purge(fd, *(DWORD*)lpInBuffer);
1232         else
1233             status = STATUS_INVALID_PARAMETER;
1234         break;
1235     case IOCTL_SERIAL_RESET_DEVICE:
1236         FIXME("Unsupported\n");
1237         break;
1238     case IOCTL_SERIAL_SET_BAUD_RATE:
1239         if (lpInBuffer && nInBufferSize == sizeof(SERIAL_BAUD_RATE))
1240             status = set_baud_rate(fd, (const SERIAL_BAUD_RATE*)lpInBuffer);
1241         else
1242             status = STATUS_INVALID_PARAMETER;
1243         break;
1244     case IOCTL_SERIAL_SET_BREAK_OFF:
1245 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1246         if (ioctl(fd, TIOCCBRK, 0) == -1)
1247         {
1248             TRACE("ioctl failed\n");
1249             status = FILE_GetNtStatus();
1250         }
1251 #else
1252         FIXME("ioctl not available\n");
1253         status = STATUS_NOT_SUPPORTED;
1254 #endif
1255         break;
1256     case IOCTL_SERIAL_SET_BREAK_ON:
1257 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1258         if (ioctl(fd, TIOCSBRK, 0) == -1)
1259         {
1260             TRACE("ioctl failed\n");
1261             status = FILE_GetNtStatus();
1262         }
1263 #else
1264         FIXME("ioctl not available\n");
1265         status = STATUS_NOT_SUPPORTED;
1266 #endif
1267         break;
1268     case IOCTL_SERIAL_SET_CHARS:
1269         if (lpInBuffer && nInBufferSize == sizeof(SERIAL_CHARS))
1270             status = set_special_chars(fd, (const SERIAL_CHARS*)lpInBuffer);
1271         else
1272             status = STATUS_INVALID_PARAMETER;
1273         break;
1274     case IOCTL_SERIAL_SET_DTR:
1275 #ifdef TIOCM_DTR
1276         if (whack_modem(fd, 0, TIOCM_DTR) == -1) status = FILE_GetNtStatus();
1277 #else
1278         status = STATUS_NOT_SUPPORTED;
1279 #endif
1280         break;
1281     case IOCTL_SERIAL_SET_HANDFLOW:
1282         if (lpInBuffer && nInBufferSize == sizeof(SERIAL_HANDFLOW))
1283             status = set_handflow(fd, (const SERIAL_HANDFLOW*)lpInBuffer);
1284         else
1285             status = STATUS_INVALID_PARAMETER;
1286         break;
1287     case IOCTL_SERIAL_SET_LINE_CONTROL:
1288         if (lpInBuffer && nInBufferSize == sizeof(SERIAL_LINE_CONTROL))
1289             status = set_line_control(fd, (const SERIAL_LINE_CONTROL*)lpInBuffer);
1290         else
1291             status = STATUS_INVALID_PARAMETER;
1292         break;
1293     case IOCTL_SERIAL_SET_QUEUE_SIZE:
1294         if (lpInBuffer && nInBufferSize == sizeof(SERIAL_QUEUE_SIZE))
1295             status = set_queue_size(fd, (const SERIAL_QUEUE_SIZE*)lpInBuffer);
1296         else
1297             status = STATUS_INVALID_PARAMETER;
1298         break;
1299     case IOCTL_SERIAL_SET_RTS:
1300 #ifdef TIOCM_RTS
1301         if (whack_modem(fd, 0, TIOCM_RTS) == -1) status = FILE_GetNtStatus();
1302 #else
1303         status = STATUS_NOT_SUPPORTED;
1304 #endif
1305         break;
1306     case IOCTL_SERIAL_SET_TIMEOUTS:
1307         if (lpInBuffer && nInBufferSize == sizeof(SERIAL_TIMEOUTS))
1308             status = set_timeouts(hDevice, fd, (const SERIAL_TIMEOUTS*)lpInBuffer);
1309         else
1310             status = STATUS_INVALID_PARAMETER;
1311         break;
1312     case IOCTL_SERIAL_SET_WAIT_MASK:
1313         if (lpInBuffer && nInBufferSize == sizeof(DWORD))
1314         {
1315             status = set_wait_mask(hDevice, *(DWORD*)lpInBuffer);
1316         }
1317         else status = STATUS_INVALID_PARAMETER;
1318         break;
1319     case IOCTL_SERIAL_SET_XOFF:
1320         status = set_XOff(fd);
1321         break;
1322     case IOCTL_SERIAL_SET_XON:
1323         status = set_XOn(fd);
1324         break;
1325     case IOCTL_SERIAL_WAIT_ON_MASK:
1326         if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1327         {
1328             if (!(status = wait_on(hDevice, fd, hEvent, (DWORD*)lpOutBuffer)))
1329                 sz = sizeof(DWORD);
1330         }
1331         else
1332             status = STATUS_INVALID_PARAMETER;
1333         break;
1334     default:
1335         FIXME("Unsupported IOCTL %x (type=%x access=%x func=%x meth=%x)\n", 
1336               dwIoControlCode, dwIoControlCode >> 16, (dwIoControlCode >> 14) & 3,
1337               (dwIoControlCode >> 2) & 0xFFF, dwIoControlCode & 3);
1338         sz = 0;
1339         status = STATUS_INVALID_PARAMETER;
1340         break;
1341     }
1342     if (needs_close) close( fd );
1343  error:
1344     piosb->u.Status = status;
1345     piosb->Information = sz;
1346     if (hEvent && status != STATUS_PENDING) NtSetEvent(hEvent, NULL);
1347     return status;
1348 }
1349
1350 NTSTATUS COMM_DeviceIoControl(HANDLE hDevice, 
1351                               HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
1352                               PVOID UserApcContext, 
1353                               PIO_STATUS_BLOCK piosb, 
1354                               ULONG dwIoControlCode,
1355                               LPVOID lpInBuffer, DWORD nInBufferSize,
1356                               LPVOID lpOutBuffer, DWORD nOutBufferSize)
1357 {
1358     NTSTATUS    status;
1359
1360     if (dwIoControlCode == IOCTL_SERIAL_WAIT_ON_MASK)
1361     {
1362         HANDLE          hev = hEvent;
1363
1364         /* this is an ioctl we implement in a non blocking way if hEvent is not
1365          * null
1366          * so we have to explicitely wait if no hEvent is provided
1367          */
1368         if (!hev)
1369         {
1370             OBJECT_ATTRIBUTES   attr;
1371             
1372             attr.Length                   = sizeof(attr);
1373             attr.RootDirectory            = 0;
1374             attr.ObjectName               = NULL;
1375             attr.Attributes               = OBJ_CASE_INSENSITIVE | OBJ_OPENIF;
1376             attr.SecurityDescriptor       = NULL;
1377             attr.SecurityQualityOfService = NULL;
1378             status = NtCreateEvent(&hev, EVENT_ALL_ACCESS, &attr, FALSE, FALSE);
1379
1380             if (status) goto done;
1381         }
1382         status = io_control(hDevice, hev, UserApcRoutine, UserApcContext,
1383                             piosb, dwIoControlCode, lpInBuffer, nInBufferSize,
1384                             lpOutBuffer, nOutBufferSize);
1385         if (hev != hEvent)
1386         {
1387             if (status == STATUS_PENDING)
1388             {
1389                 NtWaitForSingleObject(hev, FALSE, NULL);
1390                 status = STATUS_SUCCESS;
1391             }
1392             NtClose(hev);
1393         }
1394     }
1395     else status = io_control(hDevice, hEvent, UserApcRoutine, UserApcContext,
1396                              piosb, dwIoControlCode, lpInBuffer, nInBufferSize,
1397                              lpOutBuffer, nOutBufferSize);
1398 done:
1399     return status;
1400 }