janitorial: Remove remaining NULL checks before free() (found by Smatch).
[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_%ld\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         break;
263 #endif
264     }
265     switch (port.c_cflag & CSIZE)
266     {
267     case CS5:   slc->WordLength = 5;    break;
268     case CS6:   slc->WordLength = 6;    break;
269     case CS7:   slc->WordLength = 7;    break;
270     case CS8:   slc->WordLength = 8;    break;
271     default: ERR("unknown size %x\n", (UINT)(port.c_cflag & CSIZE));
272     }
273     
274     if (port.c_cflag & CSTOPB)
275     {
276         if (slc->WordLength == 5)
277             slc->StopBits = ONE5STOPBITS;
278         else
279             slc->StopBits = TWOSTOPBITS;
280     }
281     else
282         slc->StopBits = ONESTOPBIT;
283
284     return STATUS_SUCCESS;
285 }
286
287 static NTSTATUS get_modem_status(int fd, DWORD* lpModemStat)
288 {
289     NTSTATUS    status = STATUS_SUCCESS;
290     int         mstat;
291
292 #ifdef TIOCMGET
293     if (ioctl(fd, TIOCMGET, &mstat) == -1)
294     {
295         WARN("ioctl failed\n");
296         status = FILE_GetNtStatus();
297     }
298     else
299     {
300         *lpModemStat = 0;
301 #ifdef TIOCM_CTS
302         if (mstat & TIOCM_CTS)  *lpModemStat |= MS_CTS_ON;
303 #endif
304 #ifdef TIOCM_DSR
305         if (mstat & TIOCM_DSR)  *lpModemStat |= MS_DSR_ON;
306 #endif
307 #ifdef TIOCM_RNG
308         if (mstat & TIOCM_RNG)  *lpModemStat |= MS_RING_ON;
309 #endif
310 #ifdef TIOCM_CAR
311         /* FIXME: Not really sure about RLSD UB 990810 */
312         if (mstat & TIOCM_CAR)  *lpModemStat |= MS_RLSD_ON;
313 #endif
314         TRACE("%04x -> %s%s%s%s\n", mstat,
315               (*lpModemStat & MS_RLSD_ON) ? "MS_RLSD_ON " : "",
316               (*lpModemStat & MS_RING_ON) ? "MS_RING_ON " : "",
317               (*lpModemStat & MS_DSR_ON)  ? "MS_DSR_ON  " : "",
318               (*lpModemStat & MS_CTS_ON)  ? "MS_CTS_ON  " : "");
319     }
320 #else
321     status = STATUS_NOT_SUPPORTED;
322 #endif
323     return status;
324 }
325
326 static NTSTATUS get_special_chars(int fd, SERIAL_CHARS* sc)
327 {
328     struct termios port;
329     
330     if (tcgetattr(fd, &port) == -1)
331     {
332         ERR("tcgetattr error '%s'\n", strerror(errno));
333         return FILE_GetNtStatus();
334     }
335     sc->EofChar   = port.c_cc[VEOF];
336     sc->ErrorChar = 0xFF;
337     sc->BreakChar = 0; /* FIXME */
338     sc->EventChar = 0; /* FIXME */
339     sc->XonChar   = port.c_cc[VSTART];
340     sc->XoffChar  = port.c_cc[VSTOP];
341
342     return STATUS_SUCCESS;
343 }
344
345 static NTSTATUS get_status(int fd, SERIAL_STATUS* ss)
346 {
347     NTSTATUS    status = STATUS_SUCCESS;
348
349     ss->Errors = 0;
350     ss->HoldReasons = 0;
351     ss->EofReceived = FALSE;
352     ss->WaitForImmediate = FALSE;
353 #ifdef TIOCOUTQ
354     if (ioctl(fd, TIOCOUTQ, &ss->AmountInOutQueue) == -1)
355     {
356         WARN("ioctl returned error\n");
357         status = FILE_GetNtStatus();
358     }
359 #else
360     ss->AmountInOutQueue = 0; /* FIXME: find a different way to find out */
361 #endif
362
363 #ifdef TIOCINQ
364     if (ioctl(fd, TIOCINQ, &ss->AmountInInQueue))
365     {
366         WARN("ioctl returned error\n");
367         status = FILE_GetNtStatus();
368     }
369 #else
370     ss->AmountInInQueue = 0; /* FIXME: find a different way to find out */
371 #endif
372     return status;
373 }
374
375 static NTSTATUS get_timeouts(HANDLE handle, SERIAL_TIMEOUTS* st)
376 {
377     NTSTATUS    status;
378     SERVER_START_REQ( get_serial_info )
379     {
380         req->handle = handle;
381         if (!(status = wine_server_call( req )))
382         {
383             st->ReadIntervalTimeout         = reply->readinterval;
384             st->ReadTotalTimeoutMultiplier  = reply->readmult;
385             st->ReadTotalTimeoutConstant    = reply->readconst;
386             st->WriteTotalTimeoutMultiplier = reply->writemult;
387             st->WriteTotalTimeoutConstant   = reply->writeconst;
388         }
389     }
390     SERVER_END_REQ;
391     return status;
392 }
393
394 static NTSTATUS get_wait_mask(HANDLE hDevice, DWORD* mask)
395 {
396     NTSTATUS    status;
397
398     SERVER_START_REQ( get_serial_info )
399     {
400         req->handle = hDevice;
401         if (!(status = wine_server_call( req )))
402             *mask = reply->eventmask;
403     }
404     SERVER_END_REQ;
405     return status;
406 }
407
408 static NTSTATUS purge(int fd, DWORD flags)
409 {
410     /*
411     ** not exactly sure how these are different
412     ** Perhaps if we had our own internal queues, one flushes them
413     ** and the other flushes the kernel's buffers.
414     */
415     if (flags & PURGE_TXABORT) tcflush(fd, TCOFLUSH);
416     if (flags & PURGE_RXABORT) tcflush(fd, TCIFLUSH);
417     if (flags & PURGE_TXCLEAR) tcflush(fd, TCOFLUSH);
418     if (flags & PURGE_RXCLEAR) tcflush(fd, TCIFLUSH);
419     return STATUS_SUCCESS;
420 }
421
422 static NTSTATUS set_baud_rate(int fd, const SERIAL_BAUD_RATE* sbr)
423 {
424     struct termios port;
425
426     if (tcgetattr(fd, &port) == -1)
427     {
428         ERR("tcgetattr error '%s'\n", strerror(errno));
429         return FILE_GetNtStatus();
430     }
431
432 #ifdef CBAUD
433     port.c_cflag &= ~CBAUD;
434     switch (sbr->BaudRate)
435     {
436     case 0:             port.c_cflag |= B0;     break;
437     case 50:            port.c_cflag |= B50;    break;
438     case 75:            port.c_cflag |= B75;    break;
439     case 110:   
440     case CBR_110:       port.c_cflag |= B110;   break;
441     case 134:           port.c_cflag |= B134;   break;
442     case 150:           port.c_cflag |= B150;   break;
443     case 200:           port.c_cflag |= B200;   break;
444     case 300:           
445     case CBR_300:       port.c_cflag |= B300;   break;
446     case 600:
447     case CBR_600:       port.c_cflag |= B600;   break;
448     case 1200:
449     case CBR_1200:      port.c_cflag |= B1200;  break;
450     case 1800:          port.c_cflag |= B1800;  break;
451     case 2400:
452     case CBR_2400:      port.c_cflag |= B2400;  break;
453     case 4800:
454     case CBR_4800:      port.c_cflag |= B4800;  break;
455     case 9600:
456     case CBR_9600:      port.c_cflag |= B9600;  break;
457     case 19200:
458     case CBR_19200:     port.c_cflag |= B19200; break;
459     case 38400:
460     case CBR_38400:     port.c_cflag |= B38400; break;
461 #ifdef B57600
462     case 57600:         port.c_cflag |= B57600; break;
463 #endif
464 #ifdef B115200
465     case 115200:        port.c_cflag |= B115200;break;
466 #endif
467 #ifdef B230400
468     case 230400:        port.c_cflag |= B230400;break;
469 #endif
470 #ifdef B460800
471     case 460800:        port.c_cflag |= B460800;break;
472 #endif
473     default:
474 #if defined (HAVE_LINUX_SERIAL_H) && defined (TIOCSSERIAL)
475         {
476             struct serial_struct nuts;
477             int arby;
478         
479             ioctl(fd, TIOCGSERIAL, &nuts);
480             nuts.custom_divisor = nuts.baud_base / sbr->BaudRate;
481             if (!(nuts.custom_divisor)) nuts.custom_divisor = 1;
482             arby = nuts.baud_base / nuts.custom_divisor;
483             nuts.flags &= ~ASYNC_SPD_MASK;
484             nuts.flags |= ASYNC_SPD_CUST;
485             WARN("You (or a program acting at your behest) have specified\n"
486                  "a non-standard baud rate %ld.  Wine will set the rate to %d,\n"
487                  "which is as close as we can get by our present understanding of your\n"
488                  "hardware. I hope you know what you are doing.  Any disruption Wine\n"
489                  "has caused to your linux system can be undone with setserial \n"
490                  "(see man setserial). If you have incapacitated a Hayes type modem,\n"
491                  "reset it and it will probably recover.\n", sbr->BaudRate, arby);
492             ioctl(fd, TIOCSSERIAL, &nuts);
493             port.c_cflag |= B38400;
494         }
495         break;
496 #endif    /* Don't have linux/serial.h or lack TIOCSSERIAL */
497         ERR("baudrate %ld\n", sbr->BaudRate);
498         return STATUS_NOT_SUPPORTED;
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 %ld\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_DSR_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 %ld outsize %ld 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 #endif
915     memset(irq_info,0, sizeof(serial_irq_info));
916     return STATUS_NOT_IMPLEMENTED;
917 }
918
919
920 static DWORD WINAPI check_events(int fd, DWORD mask, 
921                                  const serial_irq_info *new, 
922                                  const serial_irq_info *old,
923                                  DWORD new_mstat, DWORD old_mstat)
924 {
925     DWORD ret = 0, queue;
926
927     TRACE("mask 0x%08lx\n", mask);
928     TRACE("old->rx          0x%08x vs. new->rx          0x%08x\n", old->rx, new->rx);
929     TRACE("old->tx          0x%08x vs. new->tx          0x%08x\n", old->tx, new->tx);
930     TRACE("old->frame       0x%08x vs. new->frame       0x%08x\n", old->frame, new->frame);
931     TRACE("old->overrun     0x%08x vs. new->overrun     0x%08x\n", old->overrun, new->overrun);
932     TRACE("old->parity      0x%08x vs. new->parity      0x%08x\n", old->parity, new->parity);
933     TRACE("old->brk         0x%08x vs. new->brk         0x%08x\n", old->brk, new->brk);
934     TRACE("old->buf_overrun 0x%08x vs. new->buf_overrun 0x%08x\n", old->buf_overrun, new->buf_overrun);
935
936     if (old->brk != new->brk) ret |= EV_BREAK;
937     if ((old_mstat & MS_CTS_ON ) != (new_mstat & MS_CTS_ON )) ret |= EV_CTS;
938     if ((old_mstat & MS_DSR_ON ) != (new_mstat & MS_DSR_ON )) ret |= EV_DSR;
939     if ((old_mstat & MS_RING_ON) != (new_mstat & MS_RING_ON)) ret |= EV_RING;
940     if ((old_mstat & MS_RLSD_ON) != (new_mstat & MS_RLSD_ON)) ret |= EV_RLSD;
941     if (old->frame != new->frame || old->overrun != new->overrun || old->parity != new->parity) ret |= EV_ERR;
942     if (mask & EV_RXCHAR)
943     {
944         queue = 0;
945 #ifdef TIOCINQ
946         if (ioctl(fd, TIOCINQ, &queue))
947             WARN("TIOCINQ returned error\n");
948 #endif
949         if (queue)
950             ret |= EV_RXCHAR;
951     }
952     if (mask & EV_TXEMPTY)
953     {
954         queue = 0;
955 /* We really want to know when all characters have gone out of the transmitter */
956 #if defined(TIOCSERGETLSR) 
957         if (ioctl(fd, TIOCSERGETLSR, &queue))
958             WARN("TIOCSERGETLSR returned error\n");
959         if (queue)
960 /* TIOCOUTQ only checks for an empty buffer */
961 #elif defined(TIOCOUTQ)
962         if (ioctl(fd, TIOCOUTQ, &queue))
963             WARN("TIOCOUTQ returned error\n");
964         if (!queue)
965 #endif
966            ret |= EV_TXEMPTY;
967         TRACE("OUTQUEUE %ld, Transmitter %sempty\n",
968               queue, (ret & EV_TXEMPTY) ? "" : "not ");
969     }
970     return ret & mask;
971 }
972
973 /***********************************************************************
974  *             wait_for_event      (INTERNAL)
975  *
976  *  We need to poll for what is interesting
977  *  TIOCMIWAIT only checks modem status line and may not be aborted by a changing mask
978  *
979  */
980 static DWORD CALLBACK wait_for_event(LPVOID arg)
981 {
982     async_commio *commio = (async_commio*) arg;
983     int fd;
984
985     if (wine_server_handle_to_fd( commio->hDevice, FILE_READ_DATA | FILE_WRITE_DATA, &fd, NULL ))
986     {
987         fd = -1;
988     }
989     else
990     {
991         serial_irq_info new_irq_info;
992         DWORD new_mstat, new_evtmask;
993         LARGE_INTEGER time;
994         
995         TRACE("device=%p fd=0x%08x mask=0x%08lx buffer=%p event=%p irq_info=%p\n", 
996               commio->hDevice, fd, commio->evtmask, commio->events, commio->hEvent, &commio->irq_info);
997
998         time.QuadPart = (ULONGLONG)10000;
999         time.QuadPart = -time.QuadPart;
1000         for (;;)
1001         {
1002             /*
1003              * TIOCMIWAIT is not adequate
1004              *
1005              * FIXME:
1006              * We don't handle the EV_RXFLAG (the eventchar)
1007              */
1008             NtDelayExecution(FALSE, &time);
1009             get_irq_info(fd, &new_irq_info);
1010             if (get_modem_status(fd, &new_mstat))
1011                 TRACE("get_modem_status failed\n");
1012             *commio->events = check_events(fd, commio->evtmask,
1013                                            &new_irq_info, &commio->irq_info,
1014                                            new_mstat, commio->mstat);
1015             if (*commio->events) break;
1016             get_wait_mask(commio->hDevice, &new_evtmask);
1017             if (commio->evtmask != new_evtmask)
1018             {
1019                 *commio->events = 0;
1020                 break;
1021             }
1022         }
1023     }
1024     if (commio->hEvent != INVALID_HANDLE_VALUE)
1025         NtSetEvent(commio->hEvent, NULL);
1026     if (fd != -1) wine_server_release_fd( commio->hDevice, fd );
1027     RtlFreeHeap(GetProcessHeap(), 0, commio);
1028     return 0;
1029 }
1030
1031 static NTSTATUS wait_on(HANDLE hDevice, int fd, HANDLE hEvent, DWORD* events)
1032 {
1033     async_commio*       commio;
1034     NTSTATUS            status;
1035
1036     if ((status = NtResetEvent(hEvent, NULL)))
1037         return status;
1038
1039     commio = RtlAllocateHeap(GetProcessHeap(), 0, sizeof (async_commio));
1040     if (!commio) return STATUS_NO_MEMORY;
1041
1042     commio->hDevice = hDevice;
1043     commio->events  = events;
1044     commio->hEvent  = hEvent;
1045     get_wait_mask(commio->hDevice, &commio->evtmask);
1046
1047 /* We may never return, if some capabilities miss
1048  * Return error in that case
1049  */
1050 #if !defined(TIOCINQ)
1051     if (commio->evtmask & EV_RXCHAR)
1052         goto error_caps;
1053 #endif
1054 #if !(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)
1055     if (commio->evtmask & EV_TXEMPTY)
1056         goto error_caps;
1057 #endif
1058 #if !defined(TIOCMGET)
1059     if (commio->evtmask & (EV_CTS | EV_DSR| EV_RING| EV_RLSD))
1060         goto error_caps;
1061 #endif
1062 #if !defined(TIOCM_CTS)
1063     if (commio->evtmask & EV_CTS)
1064         goto error_caps;
1065 #endif
1066 #if !defined(TIOCM_DSR)
1067     if (commio->evtmask & EV_DSR)
1068         goto error_caps;
1069 #endif
1070 #if !defined(TIOCM_RNG)
1071     if (commio->evtmask & EV_RING)
1072         goto error_caps;
1073 #endif
1074 #if !defined(TIOCM_CAR)
1075     if (commio->evtmask & EV_RLSD)
1076         goto error_caps;
1077 #endif
1078     if (commio->evtmask & EV_RXFLAG)
1079         FIXME("EV_RXFLAG not handled\n");
1080     if ((status = get_irq_info(fd, &commio->irq_info)) ||
1081         (status = get_modem_status(fd, &commio->mstat)))
1082         goto out_now;
1083
1084     /* We might have received something or the TX bufffer is delivered */
1085     *events = check_events(fd, commio->evtmask,
1086                                &commio->irq_info, &commio->irq_info,
1087                                commio->mstat, commio->mstat);
1088     if (*events) goto out_now;
1089
1090     /* create the worker for the task */
1091     status = RtlQueueWorkItem(wait_for_event, commio, 0 /* FIXME */);
1092     if (status != STATUS_SUCCESS) goto out_now;
1093     return STATUS_PENDING;
1094
1095 #if !defined(TIOCINQ) || (!(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)) || !defined(TIOCMGET) || !defined(TIOCM_CTS) ||!defined(TIOCM_DSR) || !defined(TIOCM_RNG) || !defined(TIOCM_CAR)
1096 error_caps:
1097     FIXME("Returning error because of missing capabilities\n");
1098     status = STATUS_INVALID_PARAMETER;
1099 #endif
1100 out_now:
1101     RtlFreeHeap(GetProcessHeap(), 0, commio);
1102     return status;
1103 }
1104
1105 static NTSTATUS xmit_immediate(HANDLE hDevice, int fd, char* ptr)
1106 {
1107     /* FIXME: not perfect as it should bypass the in-queue */
1108     WARN("(%p,'%c') not perfect!\n", hDevice, *ptr);
1109     if (write(fd, ptr, 1) != 1)
1110         return FILE_GetNtStatus();
1111     return STATUS_SUCCESS;
1112 }
1113
1114 /******************************************************************
1115  *              COMM_DeviceIoControl
1116  *
1117  *
1118  */
1119 static inline NTSTATUS io_control(HANDLE hDevice, 
1120                                   HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
1121                                   PVOID UserApcContext, 
1122                                   PIO_STATUS_BLOCK piosb, 
1123                                   ULONG dwIoControlCode,
1124                                   LPVOID lpInBuffer, DWORD nInBufferSize,
1125                                   LPVOID lpOutBuffer, DWORD nOutBufferSize)
1126 {
1127     DWORD       sz = 0, access = FILE_READ_DATA;
1128     NTSTATUS    status = STATUS_SUCCESS;
1129     int         fd = -1;
1130
1131     TRACE("%p %s %p %ld %p %ld %p\n",
1132           hDevice, iocode2str(dwIoControlCode), lpInBuffer, nInBufferSize,
1133           lpOutBuffer, nOutBufferSize, piosb);
1134
1135     piosb->Information = 0;
1136
1137     if (dwIoControlCode != IOCTL_SERIAL_GET_TIMEOUTS)
1138         if ((status = wine_server_handle_to_fd( hDevice, access, &fd, NULL )))
1139             goto error;
1140
1141     switch (dwIoControlCode)
1142     {
1143     case IOCTL_SERIAL_CLR_DTR:
1144 #ifdef TIOCM_DTR
1145         if (whack_modem(fd, ~TIOCM_DTR, 0) == -1) status = FILE_GetNtStatus();
1146 #else
1147         status = STATUS_NOT_SUPPORTED;
1148 #endif
1149         break;
1150     case IOCTL_SERIAL_CLR_RTS:
1151 #ifdef TIOCM_RTS
1152         if (whack_modem(fd, ~TIOCM_RTS, 0) == -1) status = FILE_GetNtStatus();
1153 #else
1154         status = STATUS_NOT_SUPPORTED;
1155 #endif
1156         break;
1157     case IOCTL_SERIAL_GET_BAUD_RATE:
1158         if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_BAUD_RATE))
1159         {
1160             if (!(status = get_baud_rate(fd, (SERIAL_BAUD_RATE*)lpOutBuffer)))
1161                 sz = sizeof(SERIAL_BAUD_RATE);
1162         }
1163         else
1164             status = STATUS_INVALID_PARAMETER;
1165         break;
1166     case IOCTL_SERIAL_GET_CHARS:
1167         if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_CHARS))
1168         {
1169             if (!(status = get_special_chars(fd, (SERIAL_CHARS*)lpOutBuffer)))
1170                 sz = sizeof(SERIAL_CHARS);
1171         }
1172         else
1173             status = STATUS_INVALID_PARAMETER;
1174         break;
1175      case IOCTL_SERIAL_GET_COMMSTATUS:
1176         if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_STATUS))
1177         {
1178             if (!(status = get_status(fd, (SERIAL_STATUS*)lpOutBuffer)))
1179                 sz = sizeof(SERIAL_STATUS);
1180         }
1181         else status = STATUS_INVALID_PARAMETER;
1182         break;
1183     case IOCTL_SERIAL_GET_HANDFLOW:
1184         if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_HANDFLOW))
1185         {
1186             if (!(status = get_hand_flow(fd, (SERIAL_HANDFLOW*)lpOutBuffer)))
1187                 sz = sizeof(SERIAL_HANDFLOW);
1188         }
1189         else
1190             status = STATUS_INVALID_PARAMETER;
1191         break;
1192     case IOCTL_SERIAL_GET_LINE_CONTROL:
1193         if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_LINE_CONTROL))
1194         {
1195             if (!(status = get_line_control(fd, (SERIAL_LINE_CONTROL*)lpOutBuffer)))
1196                 sz = sizeof(SERIAL_LINE_CONTROL);
1197         }
1198         else
1199             status = STATUS_INVALID_PARAMETER;
1200         break;
1201     case IOCTL_SERIAL_GET_MODEMSTATUS:
1202         if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1203         {
1204             if (!(status = get_modem_status(fd, (DWORD*)lpOutBuffer)))
1205                 sz = sizeof(DWORD);
1206         }
1207         else status = STATUS_INVALID_PARAMETER;
1208         break;
1209     case IOCTL_SERIAL_GET_TIMEOUTS:
1210         if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_TIMEOUTS))
1211         {
1212             if (!(status = get_timeouts(hDevice, (SERIAL_TIMEOUTS*)lpOutBuffer)))
1213                 sz = sizeof(SERIAL_TIMEOUTS);
1214         }
1215         else
1216             status = STATUS_INVALID_PARAMETER;
1217         break;
1218     case IOCTL_SERIAL_GET_WAIT_MASK:
1219         if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1220         {
1221             if (!(status = get_wait_mask(hDevice, (DWORD*)lpOutBuffer)))
1222                 sz = sizeof(DWORD);
1223         }
1224         else
1225             status = STATUS_INVALID_PARAMETER;
1226         break;
1227     case IOCTL_SERIAL_IMMEDIATE_CHAR:
1228         if (lpInBuffer && nInBufferSize == sizeof(CHAR))
1229             status = xmit_immediate(hDevice, fd, lpInBuffer);
1230         else
1231             status = STATUS_INVALID_PARAMETER;
1232         break;
1233     case IOCTL_SERIAL_PURGE:
1234         if (lpInBuffer && nInBufferSize == sizeof(DWORD))
1235             status = purge(fd, *(DWORD*)lpInBuffer);
1236         else
1237             status = STATUS_INVALID_PARAMETER;
1238         break;
1239     case IOCTL_SERIAL_RESET_DEVICE:
1240         FIXME("Unsupported\n");
1241         break;
1242     case IOCTL_SERIAL_SET_BAUD_RATE:
1243         if (lpInBuffer && nInBufferSize == sizeof(SERIAL_BAUD_RATE))
1244             status = set_baud_rate(fd, (const SERIAL_BAUD_RATE*)lpInBuffer);
1245         else
1246             status = STATUS_INVALID_PARAMETER;
1247         break;
1248     case IOCTL_SERIAL_SET_BREAK_OFF:
1249 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1250         if (ioctl(fd, TIOCCBRK, 0) == -1)
1251         {
1252             TRACE("ioctl failed\n");
1253             status = FILE_GetNtStatus();
1254         }
1255 #else
1256         FIXME("ioctl not available\n");
1257         status = STATUS_NOT_SUPPORTED;
1258 #endif
1259         break;
1260     case IOCTL_SERIAL_SET_BREAK_ON:
1261 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1262         if (ioctl(fd, TIOCSBRK, 0) == -1)
1263         {
1264             TRACE("ioctl failed\n");
1265             status = FILE_GetNtStatus();
1266         }
1267 #else
1268         FIXME("ioctl not available\n");
1269         status = STATUS_NOT_SUPPORTED;
1270 #endif
1271         break;
1272     case IOCTL_SERIAL_SET_CHARS:
1273         if (lpInBuffer && nInBufferSize == sizeof(SERIAL_CHARS))
1274             status = set_special_chars(fd, (const SERIAL_CHARS*)lpInBuffer);
1275         else
1276             status = STATUS_INVALID_PARAMETER;
1277         break;
1278     case IOCTL_SERIAL_SET_DTR:
1279 #ifdef TIOCM_DTR
1280         if (whack_modem(fd, 0, TIOCM_DTR) == -1) status = FILE_GetNtStatus();
1281 #else
1282         status = STATUS_NOT_SUPPORTED;
1283 #endif
1284         break;
1285     case IOCTL_SERIAL_SET_HANDFLOW:
1286         if (lpInBuffer && nInBufferSize == sizeof(SERIAL_HANDFLOW))
1287             status = set_handflow(fd, (const SERIAL_HANDFLOW*)lpInBuffer);
1288         else
1289             status = STATUS_INVALID_PARAMETER;
1290         break;
1291     case IOCTL_SERIAL_SET_LINE_CONTROL:
1292         if (lpInBuffer && nInBufferSize == sizeof(SERIAL_LINE_CONTROL))
1293             status = set_line_control(fd, (const SERIAL_LINE_CONTROL*)lpInBuffer);
1294         else
1295             status = STATUS_INVALID_PARAMETER;
1296         break;
1297     case IOCTL_SERIAL_SET_QUEUE_SIZE:
1298         if (lpInBuffer && nInBufferSize == sizeof(SERIAL_QUEUE_SIZE))
1299             status = set_queue_size(fd, (const SERIAL_QUEUE_SIZE*)lpInBuffer);
1300         else
1301             status = STATUS_INVALID_PARAMETER;
1302         break;
1303     case IOCTL_SERIAL_SET_RTS:
1304 #ifdef TIOCM_RTS
1305         if (whack_modem(fd, 0, TIOCM_RTS) == -1) status = FILE_GetNtStatus();
1306 #else
1307         status = STATUS_NOT_SUPPORTED;
1308 #endif
1309         break;
1310     case IOCTL_SERIAL_SET_TIMEOUTS:
1311         if (lpInBuffer && nInBufferSize == sizeof(SERIAL_TIMEOUTS))
1312             status = set_timeouts(hDevice, fd, (const SERIAL_TIMEOUTS*)lpInBuffer);
1313         else
1314             status = STATUS_INVALID_PARAMETER;
1315         break;
1316     case IOCTL_SERIAL_SET_WAIT_MASK:
1317         if (lpInBuffer && nInBufferSize == sizeof(DWORD))
1318         {
1319             status = set_wait_mask(hDevice, *(DWORD*)lpInBuffer);
1320         }
1321         else status = STATUS_INVALID_PARAMETER;
1322         break;
1323     case IOCTL_SERIAL_SET_XOFF:
1324         status = set_XOff(fd);
1325         break;
1326     case IOCTL_SERIAL_SET_XON:
1327         status = set_XOn(fd);
1328         break;
1329     case IOCTL_SERIAL_WAIT_ON_MASK:
1330         if (lpOutBuffer && nOutBufferSize == sizeof(DWORD))
1331         {
1332             if (!(status = wait_on(hDevice, fd, hEvent, (DWORD*)lpOutBuffer)))
1333                 sz = sizeof(DWORD);
1334         }
1335         else
1336             status = STATUS_INVALID_PARAMETER;
1337         break;
1338     default:
1339         FIXME("Unsupported IOCTL %lx (type=%lx access=%lx func=%lx meth=%lx)\n", 
1340               dwIoControlCode, dwIoControlCode >> 16, (dwIoControlCode >> 14) & 3,
1341               (dwIoControlCode >> 2) & 0xFFF, dwIoControlCode & 3);
1342         sz = 0;
1343         status = STATUS_INVALID_PARAMETER;
1344         break;
1345     }
1346     if (fd != -1) wine_server_release_fd( hDevice, fd );
1347  error:
1348     piosb->u.Status = status;
1349     piosb->Information = sz;
1350     if (hEvent && status != STATUS_PENDING) NtSetEvent(hEvent, NULL);
1351     return status;
1352 }
1353
1354 NTSTATUS COMM_DeviceIoControl(HANDLE hDevice, 
1355                               HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine,
1356                               PVOID UserApcContext, 
1357                               PIO_STATUS_BLOCK piosb, 
1358                               ULONG dwIoControlCode,
1359                               LPVOID lpInBuffer, DWORD nInBufferSize,
1360                               LPVOID lpOutBuffer, DWORD nOutBufferSize)
1361 {
1362     NTSTATUS    status;
1363
1364     if (dwIoControlCode == IOCTL_SERIAL_WAIT_ON_MASK)
1365     {
1366         HANDLE          hev = hEvent;
1367
1368         /* this is an ioctl we implement in a non blocking way if hEvent is not
1369          * null
1370          * so we have to explicitely wait if no hEvent is provided
1371          */
1372         if (!hev)
1373         {
1374             OBJECT_ATTRIBUTES   attr;
1375             
1376             attr.Length                   = sizeof(attr);
1377             attr.RootDirectory            = 0;
1378             attr.ObjectName               = NULL;
1379             attr.Attributes               = OBJ_CASE_INSENSITIVE | OBJ_OPENIF;
1380             attr.SecurityDescriptor       = NULL;
1381             attr.SecurityQualityOfService = NULL;
1382             status = NtCreateEvent(&hev, EVENT_ALL_ACCESS, &attr, FALSE, FALSE);
1383
1384             if (status) goto done;
1385         }
1386         status = io_control(hDevice, hev, UserApcRoutine, UserApcContext,
1387                             piosb, dwIoControlCode, lpInBuffer, nInBufferSize,
1388                             lpOutBuffer, nOutBufferSize);
1389         if (hev != hEvent)
1390         {
1391             if (status == STATUS_PENDING)
1392             {
1393                 NtWaitForSingleObject(hev, FALSE, NULL);
1394                 status = STATUS_SUCCESS;
1395             }
1396             NtClose(hev);
1397         }
1398     }
1399     else status = io_control(hDevice, hEvent, UserApcRoutine, UserApcContext,
1400                              piosb, dwIoControlCode, lpInBuffer, nInBufferSize,
1401                              lpOutBuffer, nOutBufferSize);
1402 done:
1403     return status;
1404 }