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