Added pow() forward.
[wine.git] / dlls / kernel / comm.c
blobb100e1d9fb8fd2730c1edcb6bfc60fec0fe8190f
1 /*
2 * DEC 93 Erik Bos <erik@xs4all.nl>
4 * Copyright 1996 Marcus Meissner
6 * Mar 31, 1999. Ove Kåven <ovek@arcticnet.no>
7 * - Implemented buffers and EnableCommNotification.
9 * Apr 3, 1999. Lawson Whitney <lawson_whitney@juno.com>
10 * - Fixed the modem control part of EscapeCommFunction16.
12 * Mar 3, 1999. Ove Kåven <ovek@arcticnet.no>
13 * - Use port indices instead of unixfds for win16
14 * - Moved things around (separated win16 and win32 routines)
15 * - Added some hints on how to implement buffers and EnableCommNotification.
17 * May 26, 1997. Fixes and comments by Rick Richardson <rick@dgii.com> [RER]
18 * - ptr->fd wasn't getting cleared on close.
19 * - GetCommEventMask() and GetCommError() didn't do much of anything.
20 * IMHO, they are still wrong, but they at least implement the RXCHAR
21 * event and return I/O queue sizes, which makes the app I'm interested
22 * in (analog devices EZKIT DSP development system) work.
24 * August 12, 1997. Take a bash at SetCommEventMask - Lawson Whitney
25 * <lawson_whitney@juno.com>
26 * July 6, 1998. Fixes and comments by Valentijn Sessink
27 * <vsessink@ic.uva.nl> [V]
28 * Oktober 98, Rein Klazes [RHK]
29 * A program that wants to monitor the modem status line (RLSD/DCD) may
30 * poll the modem status register in the commMask structure. I update the bit
31 * in GetCommError, waiting for an implementation of communication events.
35 #include "config.h"
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <termios.h>
40 #include <fcntl.h>
41 #include <string.h>
42 #ifdef HAVE_STRINGS_H
43 # include <strings.h>
44 #endif
45 #include <errno.h>
46 #include <ctype.h>
47 #include <sys/stat.h>
48 #ifdef HAVE_SYS_FILIO_H
49 # include <sys/filio.h>
50 #endif
51 #include <sys/ioctl.h>
52 #include <unistd.h>
54 #include "windef.h"
55 #ifdef HAVE_SYS_MODEM_H
56 # include <sys/modem.h>
57 #endif
58 #ifdef HAVE_SYS_STRTIO_H
59 # include <sys/strtio.h>
60 #endif
61 #include "heap.h"
62 #include "options.h"
64 #include "server.h"
65 #include "winerror.h"
66 #include "services.h"
67 #include "callback.h"
68 #include "file.h"
70 #include "debugtools.h"
72 DEFAULT_DEBUG_CHANNEL(comm);
74 #ifndef TIOCINQ
75 #define TIOCINQ FIONREAD
76 #endif
78 /* window's semi documented modem status register */
79 #define COMM_MSR_OFFSET 35
80 #define MSR_CTS 0x10
81 #define MSR_DSR 0x20
82 #define MSR_RI 0x40
83 #define MSR_RLSD 0x80
84 #define MSR_MASK (MSR_CTS|MSR_DSR|MSR_RI|MSR_RLSD)
86 #define FLAG_LPT 0x80
88 #ifdef linux
89 #define CMSPAR 0x40000000 /* stick parity */
90 #endif
92 #define MAX_PORTS 9
94 struct DosDeviceStruct {
95 char *devicename; /* /dev/cua1 */
96 int fd;
97 int suspended;
98 int unget,xmit;
99 int baudrate;
100 int evtchar;
101 /* events */
102 int commerror, eventmask;
103 /* buffers */
104 char *inbuf,*outbuf;
105 unsigned ibuf_size,ibuf_head,ibuf_tail;
106 unsigned obuf_size,obuf_head,obuf_tail;
107 /* notifications */
108 int wnd, n_read, n_write;
109 HANDLE s_read, s_write;
113 static struct DosDeviceStruct COM[MAX_PORTS];
114 static struct DosDeviceStruct LPT[MAX_PORTS];
115 /* pointers to unknown(==undocumented) comm structure */
116 static LPCVOID *unknown[MAX_PORTS];
117 /* save terminal states */
118 static struct termios m_stat[MAX_PORTS];
120 /* update window's semi documented modem status register */
121 /* see knowledge base Q101417 */
122 static void COMM_MSRUpdate( UCHAR * pMsr, unsigned int mstat)
124 UCHAR tmpmsr=0;
125 if(mstat & TIOCM_CTS) tmpmsr |= MSR_CTS;
126 if(mstat & TIOCM_DSR) tmpmsr |= MSR_DSR;
127 if(mstat & TIOCM_RI) tmpmsr |= MSR_RI;
128 if(mstat & TIOCM_CAR) tmpmsr |= MSR_RLSD;
129 *pMsr = (*pMsr & ~MSR_MASK) | tmpmsr;
132 void COMM_Init(void)
134 int x;
135 char option[10], temp[256], *btemp;
136 struct stat st;
138 for (x=0; x!=MAX_PORTS; x++) {
139 strcpy(option,"COMx");
140 option[3] = '1' + x;
141 option[4] = '\0';
143 PROFILE_GetWineIniString( "serialports", option, "*",
144 temp, sizeof(temp) );
145 if (!strcmp(temp, "*") || *temp == '\0')
146 COM[x].devicename = NULL;
147 else {
148 btemp = strchr(temp,',');
149 if (btemp != NULL) {
150 *btemp++ = '\0';
151 COM[x].baudrate = atoi(btemp);
152 } else {
153 COM[x].baudrate = -1;
155 stat(temp, &st);
156 if (!S_ISCHR(st.st_mode))
157 WARN("Can't use `%s' as %s !\n", temp, option);
158 else
159 if ((COM[x].devicename = malloc(strlen(temp)+1)) == NULL)
160 WARN("Can't malloc for device info!\n");
161 else {
162 COM[x].fd = 0;
163 strcpy(COM[x].devicename, temp);
165 TRACE("%s = %s\n", option, COM[x].devicename);
168 strcpy(option, "LPTx");
169 option[3] = '1' + x;
170 option[4] = '\0';
172 PROFILE_GetWineIniString( "parallelports", option, "*",
173 temp, sizeof(temp) );
174 if (!strcmp(temp, "*") || *temp == '\0')
175 LPT[x].devicename = NULL;
176 else {
177 stat(temp, &st);
178 if (!S_ISCHR(st.st_mode))
179 WARN("Can't use `%s' as %s !\n", temp, option);
180 else
181 if ((LPT[x].devicename = malloc(strlen(temp)+1)) == NULL)
182 WARN("Can't malloc for device info!\n");
183 else {
184 LPT[x].fd = 0;
185 strcpy(LPT[x].devicename, temp);
187 TRACE("%s = %s\n", option, LPT[x].devicename);
194 static struct DosDeviceStruct *GetDeviceStruct(int fd)
196 if ((fd&0x7F)<=MAX_PORTS) {
197 if (!(fd&FLAG_LPT)) {
198 if (COM[fd].fd)
199 return &COM[fd];
200 } else {
201 fd &= 0x7f;
202 if (LPT[fd].fd)
203 return &LPT[fd];
207 return NULL;
210 static int GetCommPort_fd(int fd)
212 int x;
214 for (x=0; x<MAX_PORTS; x++) {
215 if (COM[x].fd == fd)
216 return x;
219 return -1;
222 static int ValidCOMPort(int x)
224 return(x < MAX_PORTS ? (int) COM[x].devicename : 0);
227 static int ValidLPTPort(int x)
229 return(x < MAX_PORTS ? (int) LPT[x].devicename : 0);
232 static int WinError(void)
234 TRACE("errno = %d\n", errno);
235 switch (errno) {
236 default:
237 return CE_IOE;
241 static unsigned comm_inbuf(struct DosDeviceStruct *ptr)
243 return ((ptr->ibuf_tail > ptr->ibuf_head) ? ptr->ibuf_size : 0)
244 + ptr->ibuf_head - ptr->ibuf_tail;
247 static unsigned comm_outbuf(struct DosDeviceStruct *ptr)
249 return ((ptr->obuf_tail > ptr->obuf_head) ? ptr->obuf_size : 0)
250 + ptr->obuf_head - ptr->obuf_tail;
253 static int COMM_WhackModem(int fd, unsigned int andy, unsigned int orrie)
255 unsigned int mstat, okay;
256 okay = ioctl(fd, TIOCMGET, &mstat);
257 if (okay) return okay;
258 if (andy) mstat &= andy;
259 mstat |= orrie;
260 return ioctl(fd, TIOCMSET, &mstat);
263 static void CALLBACK comm_notification( ULONG_PTR private )
265 struct DosDeviceStruct *ptr = (struct DosDeviceStruct *)private;
266 int prev, bleft, len;
267 WORD mask = 0;
268 int cid = GetCommPort_fd(ptr->fd);
270 TRACE("async notification\n");
271 /* read data from comm port */
272 prev = comm_inbuf(ptr);
273 do {
274 bleft = ((ptr->ibuf_tail > ptr->ibuf_head) ? (ptr->ibuf_tail-1) : ptr->ibuf_size)
275 - ptr->ibuf_head;
276 len = read(ptr->fd, ptr->inbuf + ptr->ibuf_head, bleft?bleft:1);
277 if (len > 0) {
278 if (!bleft) {
279 ptr->commerror = CE_RXOVER;
280 } else {
281 /* check for events */
282 if ((ptr->eventmask & EV_RXFLAG) &&
283 memchr(ptr->inbuf + ptr->ibuf_head, ptr->evtchar, len)) {
284 *(WORD*)(unknown[cid]) |= EV_RXFLAG;
285 mask |= CN_EVENT;
287 if (ptr->eventmask & EV_RXCHAR) {
288 *(WORD*)(unknown[cid]) |= EV_RXCHAR;
289 mask |= CN_EVENT;
291 /* advance buffer position */
292 ptr->ibuf_head += len;
293 if (ptr->ibuf_head >= ptr->ibuf_size)
294 ptr->ibuf_head = 0;
297 } while (len > 0);
298 /* check for notification */
299 if (ptr->wnd && (ptr->n_read>0) && (prev<ptr->n_read) &&
300 (comm_inbuf(ptr)>=ptr->n_read)) {
301 /* passed the receive notification threshold */
302 mask |= CN_RECEIVE;
305 /* write any TransmitCommChar character */
306 if (ptr->xmit>=0) {
307 len = write(ptr->fd, &(ptr->xmit), 1);
308 if (len > 0) ptr->xmit = -1;
310 /* write from output queue */
311 prev = comm_outbuf(ptr);
312 do {
313 bleft = ((ptr->obuf_tail <= ptr->obuf_head) ? ptr->obuf_head : ptr->obuf_size)
314 - ptr->obuf_tail;
315 len = bleft ? write(ptr->fd, ptr->outbuf + ptr->obuf_tail, bleft) : 0;
316 if (len > 0) {
317 ptr->obuf_tail += len;
318 if (ptr->obuf_tail >= ptr->obuf_size)
319 ptr->obuf_tail = 0;
320 /* flag event */
321 if (ptr->obuf_tail == ptr->obuf_head) {
322 if (ptr->s_write) {
323 SERVICE_Delete( ptr->s_write );
324 ptr->s_write = INVALID_HANDLE_VALUE;
326 if (ptr->eventmask & EV_TXEMPTY) {
327 *(WORD*)(unknown[cid]) |= EV_TXEMPTY;
328 mask |= CN_EVENT;
332 } while (len > 0);
333 /* check for notification */
334 if (ptr->wnd && (ptr->n_write>0) && (prev>=ptr->n_write) &&
335 (comm_outbuf(ptr)<ptr->n_write)) {
336 /* passed the transmit notification threshold */
337 mask |= CN_TRANSMIT;
340 /* send notifications, if any */
341 if (ptr->wnd && mask) {
342 TRACE("notifying %04x: cid=%d, mask=%02x\n", ptr->wnd, cid, mask);
343 if (Callout.PostMessageA) Callout.PostMessageA(ptr->wnd, WM_COMMNOTIFY, cid, mask);
347 static void comm_waitread(struct DosDeviceStruct *ptr)
349 if (ptr->s_read != INVALID_HANDLE_VALUE) return;
350 ptr->s_read = SERVICE_AddObject( FILE_DupUnixHandle( ptr->fd,
351 GENERIC_READ | SYNCHRONIZE ),
352 comm_notification,
353 (ULONG_PTR)ptr );
356 static void comm_waitwrite(struct DosDeviceStruct *ptr)
358 if (ptr->s_write != INVALID_HANDLE_VALUE) return;
359 ptr->s_write = SERVICE_AddObject( FILE_DupUnixHandle( ptr->fd,
360 GENERIC_WRITE | SYNCHRONIZE ),
361 comm_notification,
362 (ULONG_PTR)ptr );
365 /**************************************************************************
366 * BuildCommDCB16 (USER.213)
368 * According to the ECMA-234 (368.3) the function will return FALSE on
369 * success, otherwise it will return -1.
370 * IF THIS IS NOT CORRECT THE RETURNVALUE CHECK IN BuildCommDCBAndTimeoutsA
371 * NEEDS TO BE FIXED
373 BOOL16 WINAPI BuildCommDCB16(LPCSTR device, LPDCB16 lpdcb)
375 /* "COM1:9600,n,8,1" */
376 /* 012345 */
377 int port;
378 char *ptr, temp[256];
380 TRACE("(%s), ptr %p\n", device, lpdcb);
382 if (!strncasecmp(device,"COM",3)) {
383 port = device[3] - '0';
386 if (port-- == 0) {
387 ERR("BUG ! COM0 can't exist!.\n");
388 return -1;
391 if (!ValidCOMPort(port)) {
392 FIXME("invalid COM port %d?\n",port);
393 return -1;
396 memset(lpdcb, 0, sizeof(DCB16)); /* initialize */
398 lpdcb->Id = port;
400 if (!*(device+4))
401 return 0;
403 if (*(device+4) != ':')
404 return -1;
406 strcpy(temp,device+5);
407 ptr = strtok(temp, ", ");
409 if (COM[port].baudrate > 0)
410 lpdcb->BaudRate = COM[port].baudrate;
411 else
412 lpdcb->BaudRate = atoi(ptr);
413 TRACE("baudrate (%d)\n", lpdcb->BaudRate);
415 ptr = strtok(NULL, ", ");
416 if (islower(*ptr))
417 *ptr = toupper(*ptr);
419 TRACE("parity (%c)\n", *ptr);
420 lpdcb->fParity = TRUE;
421 switch (*ptr) {
422 case 'N':
423 lpdcb->Parity = NOPARITY;
424 lpdcb->fParity = FALSE;
425 break;
426 case 'E':
427 lpdcb->Parity = EVENPARITY;
428 break;
429 case 'M':
430 lpdcb->Parity = MARKPARITY;
431 break;
432 case 'O':
433 lpdcb->Parity = ODDPARITY;
434 break;
435 default:
436 WARN("Unknown parity `%c'!\n", *ptr);
437 return -1;
440 ptr = strtok(NULL, ", ");
441 TRACE("charsize (%c)\n", *ptr);
442 lpdcb->ByteSize = *ptr - '0';
444 ptr = strtok(NULL, ", ");
445 TRACE("stopbits (%c)\n", *ptr);
446 switch (*ptr) {
447 case '1':
448 lpdcb->StopBits = ONESTOPBIT;
449 break;
450 case '2':
451 lpdcb->StopBits = TWOSTOPBITS;
452 break;
453 default:
454 WARN("Unknown # of stopbits `%c'!\n", *ptr);
455 return -1;
459 return 0;
462 /*****************************************************************************
463 * OpenComm16 (USER.200)
465 INT16 WINAPI OpenComm16(LPCSTR device,UINT16 cbInQueue,UINT16 cbOutQueue)
467 int port,fd;
469 TRACE("%s, %d, %d\n", device, cbInQueue, cbOutQueue);
471 if (strlen(device) < 4)
472 return IE_BADID;
474 port = device[3] - '0';
476 if (port-- == 0)
477 ERR("BUG ! COM0 or LPT0 don't exist !\n");
479 if (!strncasecmp(device,"COM",3)) {
481 TRACE("%s = %s\n", device, COM[port].devicename);
483 if (!ValidCOMPort(port))
484 return IE_BADID;
486 if (COM[port].fd)
487 return IE_OPEN;
489 fd = open(COM[port].devicename, O_RDWR | O_NONBLOCK);
490 if (fd == -1) {
491 ERR("Couldn't open %s ! (%s)\n", COM[port].devicename, strerror(errno));
492 return IE_HARDWARE;
493 } else {
494 unknown[port] = SEGPTR_ALLOC(40);
495 bzero(unknown[port],40);
496 COM[port].fd = fd;
497 COM[port].commerror = 0;
498 COM[port].eventmask = 0;
499 COM[port].evtchar = 0; /* FIXME: default? */
500 /* save terminal state */
501 tcgetattr(fd,&m_stat[port]);
502 /* set default parameters */
503 if(COM[port].baudrate>-1){
504 DCB16 dcb;
505 GetCommState16(port, &dcb);
506 dcb.BaudRate=COM[port].baudrate;
507 /* more defaults:
508 * databits, parity, stopbits
510 SetCommState16( &dcb);
512 /* init priority characters */
513 COM[port].unget = -1;
514 COM[port].xmit = -1;
515 /* allocate buffers */
516 COM[port].ibuf_size = cbInQueue;
517 COM[port].ibuf_head = COM[port].ibuf_tail= 0;
518 COM[port].obuf_size = cbOutQueue;
519 COM[port].obuf_head = COM[port].obuf_tail = 0;
521 COM[port].inbuf = malloc(cbInQueue);
522 if (COM[port].inbuf) {
523 COM[port].outbuf = malloc(cbOutQueue);
524 if (!COM[port].outbuf)
525 free(COM[port].inbuf);
526 } else COM[port].outbuf = NULL;
527 if (!COM[port].outbuf) {
528 /* not enough memory */
529 tcsetattr(COM[port].fd,TCSANOW,&m_stat[port]);
530 close(COM[port].fd);
531 ERR("out of memory\n");
532 return IE_MEMORY;
535 COM[port].s_read = INVALID_HANDLE_VALUE;
536 COM[port].s_write = INVALID_HANDLE_VALUE;
537 comm_waitread( &COM[port] );
538 return port;
541 else
542 if (!strncasecmp(device,"LPT",3)) {
544 if (!ValidLPTPort(port))
545 return IE_BADID;
547 if (LPT[port].fd)
548 return IE_OPEN;
550 fd = open(LPT[port].devicename, O_RDWR | O_NONBLOCK, 0);
551 if (fd == -1) {
552 return IE_HARDWARE;
553 } else {
554 LPT[port].fd = fd;
555 LPT[port].commerror = 0;
556 LPT[port].eventmask = 0;
557 return port|FLAG_LPT;
560 return 0;
563 /*****************************************************************************
564 * CloseComm16 (USER.207)
566 INT16 WINAPI CloseComm16(INT16 cid)
568 struct DosDeviceStruct *ptr;
570 TRACE("cid=%d\n", cid);
571 if ((ptr = GetDeviceStruct(cid)) == NULL) {
572 FIXME("no cid=%d found!\n", cid);
573 return -1;
575 if (!(cid&FLAG_LPT)) {
576 /* COM port */
577 SEGPTR_FREE(unknown[cid]); /* [LW] */
579 SERVICE_Delete( COM[cid].s_write );
580 SERVICE_Delete( COM[cid].s_read );
581 /* free buffers */
582 free(ptr->outbuf);
583 free(ptr->inbuf);
585 /* reset modem lines */
586 tcsetattr(ptr->fd,TCSANOW,&m_stat[cid]);
589 if (close(ptr->fd) == -1) {
590 ptr->commerror = WinError();
591 /* FIXME: should we clear ptr->fd here? */
592 return -1;
593 } else {
594 ptr->commerror = 0;
595 ptr->fd = 0;
596 return 0;
600 /*****************************************************************************
601 * SetCommBreak16 (USER.210)
603 INT16 WINAPI SetCommBreak16(INT16 cid)
605 struct DosDeviceStruct *ptr;
607 TRACE("cid=%d\n", cid);
608 if ((ptr = GetDeviceStruct(cid)) == NULL) {
609 FIXME("no cid=%d found!\n", cid);
610 return -1;
613 ptr->suspended = 1;
614 ptr->commerror = 0;
615 return 0;
618 /*****************************************************************************
619 * ClearCommBreak16 (USER.211)
621 INT16 WINAPI ClearCommBreak16(INT16 cid)
623 struct DosDeviceStruct *ptr;
625 TRACE("cid=%d\n", cid);
626 if (!(ptr = GetDeviceStruct(cid))) {
627 FIXME("no cid=%d found!\n", cid);
628 return -1;
630 ptr->suspended = 0;
631 ptr->commerror = 0;
632 return 0;
635 /*****************************************************************************
636 * EscapeCommFunction16 (USER.214)
638 LONG WINAPI EscapeCommFunction16(UINT16 cid,UINT16 nFunction)
640 int max;
641 struct DosDeviceStruct *ptr;
642 struct termios port;
644 TRACE("cid=%d, function=%d\n", cid, nFunction);
645 if ((nFunction != GETMAXCOM) && (nFunction != GETMAXLPT)) {
646 if ((ptr = GetDeviceStruct(cid)) == NULL) {
647 FIXME("no cid=%d found!\n", cid);
648 return -1;
650 if (tcgetattr(ptr->fd,&port) == -1) {
651 TRACE("tcgetattr failed\n");
652 ptr->commerror=WinError();
653 return -1;
655 } else ptr = NULL;
657 switch (nFunction) {
658 case RESETDEV:
659 TRACE("RESETDEV\n");
660 break;
662 case GETMAXCOM:
663 TRACE("GETMAXCOM\n");
664 for (max = MAX_PORTS;!COM[max].devicename;max--)
666 return max;
667 break;
669 case GETMAXLPT:
670 TRACE("GETMAXLPT\n");
671 for (max = MAX_PORTS;!LPT[max].devicename;max--)
673 return FLAG_LPT + max;
674 break;
676 case GETBASEIRQ:
677 TRACE("GETBASEIRQ\n");
678 /* FIXME: use tables */
679 /* just fake something for now */
680 if (cid & FLAG_LPT) {
681 /* LPT1: irq 7, LPT2: irq 5 */
682 return (cid & 0x7f) ? 5 : 7;
683 } else {
684 /* COM1: irq 4, COM2: irq 3,
685 COM3: irq 4, COM4: irq 3 */
686 return 4 - (cid & 1);
688 break;
690 case CLRDTR:
691 TRACE("CLRDTR\n");
692 #ifdef TIOCM_DTR
693 return COMM_WhackModem(ptr->fd, ~TIOCM_DTR, 0);
694 #endif
695 case CLRRTS:
696 TRACE("CLRRTS\n");
697 #ifdef TIOCM_RTS
698 return COMM_WhackModem(ptr->fd, ~TIOCM_RTS, 0);
699 #endif
701 case SETDTR:
702 TRACE("SETDTR\n");
703 #ifdef TIOCM_DTR
704 return COMM_WhackModem(ptr->fd, 0, TIOCM_DTR);
705 #endif
707 case SETRTS:
708 TRACE("SETRTS\n");
709 #ifdef TIOCM_RTS
710 return COMM_WhackModem(ptr->fd, 0, TIOCM_RTS);
711 #endif
713 case SETXOFF:
714 TRACE("SETXOFF\n");
715 port.c_iflag |= IXOFF;
716 break;
718 case SETXON:
719 TRACE("SETXON\n");
720 port.c_iflag |= IXON;
721 break;
723 default:
724 WARN("(cid=%d,nFunction=%d): Unknown function\n",
725 cid, nFunction);
726 break;
729 if (tcsetattr(ptr->fd, TCSADRAIN, &port) == -1) {
730 ptr->commerror = WinError();
731 return -1;
732 } else {
733 ptr->commerror = 0;
734 return 0;
738 /*****************************************************************************
739 * FlushComm16 (USER.215)
741 INT16 WINAPI FlushComm16(INT16 cid,INT16 fnQueue)
743 int queue;
744 struct DosDeviceStruct *ptr;
746 TRACE("cid=%d, queue=%d\n", cid, fnQueue);
747 if ((ptr = GetDeviceStruct(cid)) == NULL) {
748 FIXME("no cid=%d found!\n", cid);
749 return -1;
751 switch (fnQueue) {
752 case 0:
753 queue = TCOFLUSH;
754 ptr->obuf_tail = ptr->obuf_head;
755 break;
756 case 1:
757 queue = TCIFLUSH;
758 ptr->ibuf_head = ptr->ibuf_tail;
759 break;
760 default:
761 WARN("(cid=%d,fnQueue=%d):Unknown queue\n",
762 cid, fnQueue);
763 return -1;
765 if (tcflush(ptr->fd, queue)) {
766 ptr->commerror = WinError();
767 return -1;
768 } else {
769 ptr->commerror = 0;
770 return 0;
774 /********************************************************************
775 * GetCommError16 (USER.203)
777 INT16 WINAPI GetCommError16(INT16 cid,LPCOMSTAT16 lpStat)
779 int temperror;
780 struct DosDeviceStruct *ptr;
781 unsigned char *stol;
782 unsigned int mstat;
784 if ((ptr = GetDeviceStruct(cid)) == NULL) {
785 FIXME("no handle for cid = %0x!.\n",cid);
786 return -1;
788 if (cid&FLAG_LPT) {
789 WARN(" cid %d not comm port\n",cid);
790 return CE_MODE;
792 stol = (unsigned char *)unknown[cid] + COMM_MSR_OFFSET;
793 ioctl(ptr->fd,TIOCMGET,&mstat);
794 COMM_MSRUpdate( stol, mstat);
796 if (lpStat) {
797 lpStat->status = 0;
799 lpStat->cbOutQue = comm_outbuf(ptr);
800 lpStat->cbInQue = comm_inbuf(ptr);
802 TRACE("cid %d, error %d, lpStat %d %d %d stol %x\n",
803 cid, ptr->commerror, lpStat->status, lpStat->cbInQue,
804 lpStat->cbOutQue, *stol);
806 else
807 TRACE("cid %d, error %d, lpStat NULL stol %x\n",
808 cid, ptr->commerror, *stol);
810 /* Return any errors and clear it */
811 temperror = ptr->commerror;
812 ptr->commerror = 0;
813 return(temperror);
816 /*****************************************************************************
817 * SetCommEventMask16 (USER.208)
819 SEGPTR WINAPI SetCommEventMask16(INT16 cid,UINT16 fuEvtMask)
821 struct DosDeviceStruct *ptr;
822 unsigned char *stol;
823 int repid;
824 unsigned int mstat;
826 TRACE("cid %d,mask %d\n",cid,fuEvtMask);
827 if ((ptr = GetDeviceStruct(cid)) == NULL) {
828 FIXME("no handle for cid = %0x!.\n",cid);
829 return (SEGPTR)NULL;
832 ptr->eventmask = fuEvtMask;
834 if ((cid&FLAG_LPT) || !ValidCOMPort(cid)) {
835 WARN(" cid %d not comm port\n",cid);
836 return (SEGPTR)NULL;
838 /* it's a COM port ? -> modify flags */
839 stol = (unsigned char *)unknown[cid] + COMM_MSR_OFFSET;
840 repid = ioctl(ptr->fd,TIOCMGET,&mstat);
841 TRACE(" ioctl %d, msr %x at %p %p\n",repid,mstat,stol,unknown[cid]);
842 COMM_MSRUpdate( stol, mstat);
844 TRACE(" modem dcd construct %x\n",*stol);
845 return SEGPTR_GET(unknown[cid]);
848 /*****************************************************************************
849 * GetCommEventMask16 (USER.209)
851 UINT16 WINAPI GetCommEventMask16(INT16 cid,UINT16 fnEvtClear)
853 struct DosDeviceStruct *ptr;
854 WORD events;
856 TRACE("cid %d, mask %d\n", cid, fnEvtClear);
857 if ((ptr = GetDeviceStruct(cid)) == NULL) {
858 FIXME("no handle for cid = %0x!.\n",cid);
859 return 0;
862 if ((cid&FLAG_LPT) || !ValidCOMPort(cid)) {
863 WARN(" cid %d not comm port\n",cid);
864 return 0;
867 events = *(WORD*)(unknown[cid]) & fnEvtClear;
868 *(WORD*)(unknown[cid]) &= ~fnEvtClear;
869 return events;
872 /*****************************************************************************
873 * SetCommState16 (USER.201)
875 INT16 WINAPI SetCommState16(LPDCB16 lpdcb)
877 struct termios port;
878 struct DosDeviceStruct *ptr;
879 int bytesize, stopbits;
880 int fail=0;
882 TRACE("cid %d, ptr %p\n", lpdcb->Id, lpdcb);
883 if ((ptr = GetDeviceStruct(lpdcb->Id)) == NULL) {
884 FIXME("no handle for cid = %0x!.\n",lpdcb->Id);
885 return -1;
887 if (tcgetattr(ptr->fd, &port) == -1) {
888 ptr->commerror = WinError();
889 return -1;
892 port.c_cc[VMIN] = 0;
893 port.c_cc[VTIME] = 1;
895 #ifdef IMAXBEL
896 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|IMAXBEL);
897 #else
898 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR);
899 #endif
900 port.c_iflag |= (IGNBRK);
902 port.c_oflag &= ~(OPOST);
904 port.c_cflag &= ~(HUPCL);
905 port.c_cflag |= CLOCAL | CREAD;
907 port.c_lflag &= ~(ICANON|ECHO|ISIG);
908 port.c_lflag |= NOFLSH;
910 TRACE("baudrate %d\n",lpdcb->BaudRate);
911 #ifdef CBAUD
912 port.c_cflag &= ~CBAUD;
913 switch (lpdcb->BaudRate) {
914 case 110:
915 case CBR_110:
916 port.c_cflag |= B110;
917 break;
918 case 300:
919 case CBR_300:
920 port.c_cflag |= B300;
921 break;
922 case 600:
923 case CBR_600:
924 port.c_cflag |= B600;
925 break;
926 case 1200:
927 case CBR_1200:
928 port.c_cflag |= B1200;
929 break;
930 case 2400:
931 case CBR_2400:
932 port.c_cflag |= B2400;
933 break;
934 case 4800:
935 case CBR_4800:
936 port.c_cflag |= B4800;
937 break;
938 case 9600:
939 case CBR_9600:
940 port.c_cflag |= B9600;
941 break;
942 case 19200:
943 case CBR_19200:
944 port.c_cflag |= B19200;
945 break;
946 case 38400:
947 case CBR_38400:
948 port.c_cflag |= B38400;
949 break;
950 #ifdef B57600
951 case 57600:
952 port.c_cflag |= B57600;
953 break;
954 #endif
955 #ifdef B115200
956 case 57601:
957 port.c_cflag |= B115200;
958 break;
959 #endif
960 default:
961 ptr->commerror = IE_BAUDRATE;
962 fail=1;
964 #elif !defined(__EMX__)
965 switch (lpdcb->BaudRate) {
966 case 110:
967 case CBR_110:
968 port.c_ospeed = B110;
969 break;
970 case 300:
971 case CBR_300:
972 port.c_ospeed = B300;
973 break;
974 case 600:
975 case CBR_600:
976 port.c_ospeed = B600;
977 break;
978 case 1200:
979 case CBR_1200:
980 port.c_ospeed = B1200;
981 break;
982 case 2400:
983 case CBR_2400:
984 port.c_ospeed = B2400;
985 break;
986 case 4800:
987 case CBR_4800:
988 port.c_ospeed = B4800;
989 break;
990 case 9600:
991 case CBR_9600:
992 port.c_ospeed = B9600;
993 break;
994 case 19200:
995 case CBR_19200:
996 port.c_ospeed = B19200;
997 break;
998 case 38400:
999 case CBR_38400:
1000 port.c_ospeed = B38400;
1001 break;
1002 default:
1003 ptr->commerror = IE_BAUDRATE;
1004 fail=1;
1006 port.c_ispeed = port.c_ospeed;
1007 #endif
1008 bytesize=lpdcb->ByteSize;
1009 stopbits=lpdcb->StopBits;
1011 TRACE("fParity %d Parity %d\n",lpdcb->fParity, lpdcb->Parity);
1012 #ifdef CMSPAR
1013 port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
1014 #else
1015 port.c_cflag &= ~(PARENB | PARODD);
1016 #endif
1017 if (lpdcb->fParity)
1018 port.c_iflag |= INPCK;
1019 else
1020 port.c_iflag &= ~INPCK;
1021 switch (lpdcb->Parity) {
1022 case NOPARITY:
1023 break;
1024 case ODDPARITY:
1025 port.c_cflag |= (PARENB | PARODD);
1026 break;
1027 case EVENPARITY:
1028 port.c_cflag |= PARENB;
1029 break;
1030 #ifdef CMSPAR
1031 /* Linux defines mark/space (stick) parity */
1032 case MARKPARITY:
1033 port.c_cflag |= (PARENB | CMSPAR);
1034 break;
1035 case SPACEPARITY:
1036 port.c_cflag |= (PARENB | PARODD | CMSPAR);
1037 break;
1038 #else
1039 /* try the POSIX way */
1040 case MARKPARITY:
1041 if( stopbits == ONESTOPBIT) {
1042 stopbits = TWOSTOPBITS;
1043 port.c_iflag &= ~INPCK;
1044 } else {
1045 ptr->commerror = IE_BYTESIZE;
1046 fail=1;
1048 break;
1049 case SPACEPARITY:
1050 if( bytesize < 8) {
1051 bytesize +=1;
1052 port.c_iflag &= ~INPCK;
1053 } else {
1054 ptr->commerror = IE_BYTESIZE;
1055 fail=1;
1057 break;
1058 #endif
1059 default:
1060 ptr->commerror = IE_BYTESIZE;
1061 fail=1;
1064 TRACE("bytesize %d\n",bytesize);
1065 port.c_cflag &= ~CSIZE;
1066 switch (bytesize) {
1067 case 5:
1068 port.c_cflag |= CS5;
1069 break;
1070 case 6:
1071 port.c_cflag |= CS6;
1072 break;
1073 case 7:
1074 port.c_cflag |= CS7;
1075 break;
1076 case 8:
1077 port.c_cflag |= CS8;
1078 break;
1079 default:
1080 ptr->commerror = IE_BYTESIZE;
1081 fail=1;
1084 TRACE("stopbits %d\n",stopbits);
1086 switch (stopbits) {
1087 case ONESTOPBIT:
1088 port.c_cflag &= ~CSTOPB;
1089 break;
1090 case ONE5STOPBITS: /* wil be selected if bytesize is 5 */
1091 case TWOSTOPBITS:
1092 port.c_cflag |= CSTOPB;
1093 break;
1094 default:
1095 ptr->commerror = IE_BYTESIZE;
1096 fail=1;
1098 #ifdef CRTSCTS
1100 if (lpdcb->fDtrflow || lpdcb->fRtsflow || lpdcb->fOutxCtsFlow)
1101 port.c_cflag |= CRTSCTS;
1103 if (lpdcb->fDtrDisable)
1104 port.c_cflag &= ~CRTSCTS;
1105 #endif
1106 if (lpdcb->fInX)
1107 port.c_iflag |= IXON;
1108 else
1109 port.c_iflag &= ~IXON;
1110 if (lpdcb->fOutX)
1111 port.c_iflag |= IXOFF;
1112 else
1113 port.c_iflag &= ~IXOFF;
1115 ptr->evtchar = lpdcb->EvtChar;
1117 if(fail)
1118 return -1;
1120 if (tcsetattr(ptr->fd, TCSADRAIN, &port) == -1) {
1121 ptr->commerror = WinError();
1122 return -1;
1123 } else {
1124 ptr->commerror = 0;
1125 return 0;
1129 /*****************************************************************************
1130 * GetCommState16 (USER.202)
1132 INT16 WINAPI GetCommState16(INT16 cid, LPDCB16 lpdcb)
1134 int speed;
1135 struct DosDeviceStruct *ptr;
1136 struct termios port;
1138 TRACE("cid %d, ptr %p\n", cid, lpdcb);
1139 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1140 FIXME("no handle for cid = %0x!.\n",cid);
1141 return -1;
1143 if (tcgetattr(ptr->fd, &port) == -1) {
1144 ptr->commerror = WinError();
1145 return -1;
1147 lpdcb->Id = cid;
1148 #ifndef __EMX__
1149 #ifdef CBAUD
1150 speed = port.c_cflag & CBAUD;
1151 #else
1152 speed = port.c_ospeed;
1153 #endif
1154 switch(speed) {
1155 case B110:
1156 lpdcb->BaudRate = 110;
1157 break;
1158 case B300:
1159 lpdcb->BaudRate = 300;
1160 break;
1161 case B600:
1162 lpdcb->BaudRate = 600;
1163 break;
1164 case B1200:
1165 lpdcb->BaudRate = 1200;
1166 break;
1167 case B2400:
1168 lpdcb->BaudRate = 2400;
1169 break;
1170 case B4800:
1171 lpdcb->BaudRate = 4800;
1172 break;
1173 case B9600:
1174 lpdcb->BaudRate = 9600;
1175 break;
1176 case B19200:
1177 lpdcb->BaudRate = 19200;
1178 break;
1179 case B38400:
1180 lpdcb->BaudRate = 38400;
1181 break;
1182 #ifdef B57600
1183 case B57600:
1184 lpdcb->BaudRate = 57600;
1185 break;
1186 #endif
1187 #ifdef B115200
1188 case B115200:
1189 lpdcb->BaudRate = 57601;
1190 break;
1191 #endif
1193 #endif
1194 switch (port.c_cflag & CSIZE) {
1195 case CS5:
1196 lpdcb->ByteSize = 5;
1197 break;
1198 case CS6:
1199 lpdcb->ByteSize = 6;
1200 break;
1201 case CS7:
1202 lpdcb->ByteSize = 7;
1203 break;
1204 case CS8:
1205 lpdcb->ByteSize = 8;
1206 break;
1209 if(port.c_iflag & INPCK)
1210 lpdcb->fParity = TRUE;
1211 else
1212 lpdcb->fParity = FALSE;
1213 #ifdef CMSPAR
1214 switch (port.c_cflag & (PARENB | PARODD | CMSPAR))
1215 #else
1216 switch (port.c_cflag & (PARENB | PARODD))
1217 #endif
1219 case 0:
1220 lpdcb->Parity = NOPARITY;
1221 break;
1222 case PARENB:
1223 lpdcb->Parity = EVENPARITY;
1224 break;
1225 case (PARENB | PARODD):
1226 lpdcb->Parity = ODDPARITY;
1227 break;
1228 #ifdef CMSPAR
1229 case (PARENB | CMSPAR):
1230 lpdcb->Parity = MARKPARITY;
1231 break;
1232 case (PARENB | PARODD | CMSPAR):
1233 lpdcb->Parity = SPACEPARITY;
1234 break;
1235 #endif
1238 if (port.c_cflag & CSTOPB)
1239 if(lpdcb->ByteSize == 5)
1240 lpdcb->StopBits = ONE5STOPBITS;
1241 else
1242 lpdcb->StopBits = TWOSTOPBITS;
1243 else
1244 lpdcb->StopBits = ONESTOPBIT;
1246 lpdcb->RlsTimeout = 50;
1247 lpdcb->CtsTimeout = 50;
1248 lpdcb->DsrTimeout = 50;
1249 lpdcb->fNull = 0;
1250 lpdcb->fChEvt = 0;
1251 lpdcb->fBinary = 1;
1252 lpdcb->fDtrDisable = 0;
1254 #ifdef CRTSCTS
1256 if (port.c_cflag & CRTSCTS) {
1257 lpdcb->fDtrflow = 1;
1258 lpdcb->fRtsflow = 1;
1259 lpdcb->fOutxCtsFlow = 1;
1260 lpdcb->fOutxDsrFlow = 1;
1261 } else
1262 #endif
1263 lpdcb->fDtrDisable = 1;
1265 if (port.c_iflag & IXON)
1266 lpdcb->fInX = 1;
1267 else
1268 lpdcb->fInX = 0;
1270 if (port.c_iflag & IXOFF)
1271 lpdcb->fOutX = 1;
1272 else
1273 lpdcb->fOutX = 0;
1275 lpdcb->XonChar =
1276 lpdcb->XoffChar =
1278 lpdcb->XonLim = 10;
1279 lpdcb->XoffLim = 10;
1281 lpdcb->EvtChar = ptr->evtchar;
1283 ptr->commerror = 0;
1284 return 0;
1287 /*****************************************************************************
1288 * TransmitCommChar16 (USER.206)
1290 INT16 WINAPI TransmitCommChar16(INT16 cid,CHAR chTransmit)
1292 struct DosDeviceStruct *ptr;
1294 TRACE("cid %d, data %d \n", cid, chTransmit);
1295 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1296 FIXME("no handle for cid = %0x!.\n",cid);
1297 return -1;
1300 if (ptr->suspended) {
1301 ptr->commerror = IE_HARDWARE;
1302 return -1;
1305 if (ptr->xmit >= 0) {
1306 /* character already queued */
1307 /* FIXME: which error would Windows return? */
1308 ptr->commerror = CE_TXFULL;
1309 return -1;
1312 if (ptr->obuf_head == ptr->obuf_tail) {
1313 /* transmit queue empty, try to transmit directly */
1314 if (write(ptr->fd, &chTransmit, 1) == -1) {
1315 /* didn't work, queue it */
1316 ptr->xmit = chTransmit;
1317 comm_waitwrite(ptr);
1319 } else {
1320 /* data in queue, let this char be transmitted next */
1321 ptr->xmit = chTransmit;
1322 comm_waitwrite(ptr);
1325 ptr->commerror = 0;
1326 return 0;
1329 /*****************************************************************************
1330 * UngetCommChar16 (USER.212)
1332 INT16 WINAPI UngetCommChar16(INT16 cid,CHAR chUnget)
1334 struct DosDeviceStruct *ptr;
1336 TRACE("cid %d (char %d)\n", cid, chUnget);
1337 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1338 FIXME("no handle for cid = %0x!.\n",cid);
1339 return -1;
1342 if (ptr->suspended) {
1343 ptr->commerror = IE_HARDWARE;
1344 return -1;
1347 if (ptr->unget>=0) {
1348 /* character already queued */
1349 /* FIXME: which error would Windows return? */
1350 ptr->commerror = CE_RXOVER;
1351 return -1;
1354 ptr->unget = chUnget;
1356 ptr->commerror = 0;
1357 return 0;
1360 /*****************************************************************************
1361 * ReadComm16 (USER.204)
1363 INT16 WINAPI ReadComm16(INT16 cid,LPSTR lpvBuf,INT16 cbRead)
1365 int status, length;
1366 struct DosDeviceStruct *ptr;
1367 LPSTR orgBuf = lpvBuf;
1369 TRACE("cid %d, ptr %p, length %d\n", cid, lpvBuf, cbRead);
1370 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1371 FIXME("no handle for cid = %0x!.\n",cid);
1372 return -1;
1375 if (ptr->suspended) {
1376 ptr->commerror = IE_HARDWARE;
1377 return -1;
1380 /* read unget character */
1381 if (ptr->unget>=0) {
1382 *lpvBuf++ = ptr->unget;
1383 ptr->unget = -1;
1385 length = 1;
1386 } else
1387 length = 0;
1389 /* read from receive buffer */
1390 while (length < cbRead) {
1391 status = ((ptr->ibuf_head < ptr->ibuf_tail) ?
1392 ptr->ibuf_size : ptr->ibuf_head) - ptr->ibuf_tail;
1393 if (!status) break;
1394 if ((cbRead - length) < status)
1395 status = cbRead - length;
1397 memcpy(lpvBuf, ptr->inbuf + ptr->ibuf_tail, status);
1398 ptr->ibuf_tail += status;
1399 if (ptr->ibuf_tail >= ptr->ibuf_size)
1400 ptr->ibuf_tail = 0;
1401 lpvBuf += status;
1402 length += status;
1405 TRACE("%.*s\n", length, orgBuf);
1406 ptr->commerror = 0;
1407 return length;
1410 /*****************************************************************************
1411 * WriteComm16 (USER.205)
1413 INT16 WINAPI WriteComm16(INT16 cid, LPSTR lpvBuf, INT16 cbWrite)
1415 int status, length;
1416 struct DosDeviceStruct *ptr;
1418 TRACE("cid %d, ptr %p, length %d\n",
1419 cid, lpvBuf, cbWrite);
1420 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1421 FIXME("no handle for cid = %0x!.\n",cid);
1422 return -1;
1425 if (ptr->suspended) {
1426 ptr->commerror = IE_HARDWARE;
1427 return -1;
1430 TRACE("%.*s\n", cbWrite, lpvBuf );
1432 length = 0;
1433 while (length < cbWrite) {
1434 if ((ptr->obuf_head == ptr->obuf_tail) && (ptr->xmit < 0)) {
1435 /* no data queued, try to write directly */
1436 status = write(ptr->fd, lpvBuf, cbWrite - length);
1437 if (status > 0) {
1438 lpvBuf += status;
1439 length += status;
1440 continue;
1443 /* can't write directly, put into transmit buffer */
1444 status = ((ptr->obuf_tail > ptr->obuf_head) ?
1445 (ptr->obuf_tail-1) : ptr->obuf_size) - ptr->obuf_head;
1446 if (!status) break;
1447 if ((cbWrite - length) < status)
1448 status = cbWrite - length;
1449 memcpy(lpvBuf, ptr->outbuf + ptr->obuf_head, status);
1450 ptr->obuf_head += status;
1451 if (ptr->obuf_head >= ptr->obuf_size)
1452 ptr->obuf_head = 0;
1453 lpvBuf += status;
1454 length += status;
1455 comm_waitwrite(ptr);
1458 ptr->commerror = 0;
1459 return length;
1462 /***********************************************************************
1463 * EnableCommNotification16 (USER.246)
1465 BOOL16 WINAPI EnableCommNotification16( INT16 cid, HWND16 hwnd,
1466 INT16 cbWriteNotify, INT16 cbOutQueue )
1468 struct DosDeviceStruct *ptr;
1470 TRACE("(%d, %x, %d, %d)\n", cid, hwnd, cbWriteNotify, cbOutQueue);
1471 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1472 FIXME("no handle for cid = %0x!.\n",cid);
1473 return -1;
1475 ptr->wnd = hwnd;
1476 ptr->n_read = cbWriteNotify;
1477 ptr->n_write = cbOutQueue;
1478 return TRUE;
1482 /**************************************************************************
1483 * BuildCommDCBA (KERNEL32.14)
1485 BOOL WINAPI BuildCommDCBA(LPCSTR device,LPDCB lpdcb)
1487 return BuildCommDCBAndTimeoutsA(device,lpdcb,NULL);
1490 /**************************************************************************
1491 * BuildCommDCBAndTimeoutsA (KERNEL32.15)
1493 BOOL WINAPI BuildCommDCBAndTimeoutsA(LPCSTR device, LPDCB lpdcb,
1494 LPCOMMTIMEOUTS lptimeouts)
1496 int port;
1497 char *ptr,*temp;
1499 TRACE("(%s,%p,%p)\n",device,lpdcb,lptimeouts);
1501 if (!strncasecmp(device,"COM",3)) {
1502 port=device[3]-'0';
1503 if (port--==0) {
1504 ERR("BUG! COM0 can't exists!.\n");
1505 return FALSE;
1507 if (!ValidCOMPort(port))
1508 return FALSE;
1509 if (*(device+4)!=':')
1510 return FALSE;
1511 temp=(LPSTR)(device+5);
1512 } else
1513 temp=(LPSTR)device;
1515 lpdcb->DCBlength = sizeof(DCB);
1516 if (strchr(temp,',')) { /* old style */
1517 DCB16 dcb16;
1518 BOOL16 ret;
1519 char last=temp[strlen(temp)-1];
1521 ret=BuildCommDCB16(device,&dcb16);
1522 if (ret)
1523 return FALSE;
1524 lpdcb->BaudRate = dcb16.BaudRate;
1525 lpdcb->ByteSize = dcb16.ByteSize;
1526 lpdcb->fBinary = dcb16.fBinary;
1527 lpdcb->Parity = dcb16.Parity;
1528 lpdcb->fParity = dcb16.fParity;
1529 lpdcb->fNull = dcb16.fNull;
1530 lpdcb->StopBits = dcb16.StopBits;
1531 if (last == 'x') {
1532 lpdcb->fInX = TRUE;
1533 lpdcb->fOutX = TRUE;
1534 lpdcb->fOutxCtsFlow = FALSE;
1535 lpdcb->fOutxDsrFlow = FALSE;
1536 lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
1537 lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
1538 } else if (last=='p') {
1539 lpdcb->fInX = FALSE;
1540 lpdcb->fOutX = FALSE;
1541 lpdcb->fOutxCtsFlow = TRUE;
1542 lpdcb->fOutxDsrFlow = TRUE;
1543 lpdcb->fDtrControl = DTR_CONTROL_HANDSHAKE;
1544 lpdcb->fRtsControl = RTS_CONTROL_HANDSHAKE;
1545 } else {
1546 lpdcb->fInX = FALSE;
1547 lpdcb->fOutX = FALSE;
1548 lpdcb->fOutxCtsFlow = FALSE;
1549 lpdcb->fOutxDsrFlow = FALSE;
1550 lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
1551 lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
1553 lpdcb->XonChar = dcb16.XonChar;
1554 lpdcb->XoffChar = dcb16.XoffChar;
1555 lpdcb->ErrorChar= dcb16.PeChar;
1556 lpdcb->fErrorChar= dcb16.fPeChar;
1557 lpdcb->EofChar = dcb16.EofChar;
1558 lpdcb->EvtChar = dcb16.EvtChar;
1559 lpdcb->XonLim = dcb16.XonLim;
1560 lpdcb->XoffLim = dcb16.XoffLim;
1561 return TRUE;
1563 ptr=strtok(temp," ");
1564 while (ptr) {
1565 DWORD flag,x;
1567 flag=0;
1568 if (!strncmp("baud=",ptr,5)) {
1569 if (!sscanf(ptr+5,"%ld",&x))
1570 WARN("Couldn't parse %s\n",ptr);
1571 lpdcb->BaudRate = x;
1572 flag=1;
1574 if (!strncmp("stop=",ptr,5)) {
1575 if (!sscanf(ptr+5,"%ld",&x))
1576 WARN("Couldn't parse %s\n",ptr);
1577 lpdcb->StopBits = x;
1578 flag=1;
1580 if (!strncmp("data=",ptr,5)) {
1581 if (!sscanf(ptr+5,"%ld",&x))
1582 WARN("Couldn't parse %s\n",ptr);
1583 lpdcb->ByteSize = x;
1584 flag=1;
1586 if (!strncmp("parity=",ptr,7)) {
1587 lpdcb->fParity = TRUE;
1588 switch (ptr[8]) {
1589 case 'N':case 'n':
1590 lpdcb->fParity = FALSE;
1591 lpdcb->Parity = NOPARITY;
1592 break;
1593 case 'E':case 'e':
1594 lpdcb->Parity = EVENPARITY;
1595 break;
1596 case 'O':case 'o':
1597 lpdcb->Parity = ODDPARITY;
1598 break;
1599 case 'M':case 'm':
1600 lpdcb->Parity = MARKPARITY;
1601 break;
1603 flag=1;
1605 if (!flag)
1606 ERR("Unhandled specifier '%s', please report.\n",ptr);
1607 ptr=strtok(NULL," ");
1609 if (lpdcb->BaudRate==110)
1610 lpdcb->StopBits = 2;
1611 return TRUE;
1614 /**************************************************************************
1615 * BuildCommDCBAndTimeoutsW (KERNEL32.16)
1617 BOOL WINAPI BuildCommDCBAndTimeoutsW( LPCWSTR devid, LPDCB lpdcb,
1618 LPCOMMTIMEOUTS lptimeouts )
1620 LPSTR devidA;
1621 BOOL ret;
1623 TRACE("(%p,%p,%p)\n",devid,lpdcb,lptimeouts);
1624 devidA = HEAP_strdupWtoA( GetProcessHeap(), 0, devid );
1625 ret=BuildCommDCBAndTimeoutsA(devidA,lpdcb,lptimeouts);
1626 HeapFree( GetProcessHeap(), 0, devidA );
1627 return ret;
1630 /**************************************************************************
1631 * BuildCommDCBW (KERNEL32.17)
1633 BOOL WINAPI BuildCommDCBW(LPCWSTR devid,LPDCB lpdcb)
1635 return BuildCommDCBAndTimeoutsW(devid,lpdcb,NULL);
1638 /* FIXME: having these global for win32 for now */
1639 int commerror=0;
1641 /*****************************************************************************
1642 * SetCommBreak (KERNEL32.449)
1644 BOOL WINAPI SetCommBreak(HANDLE handle)
1646 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1647 int fd,result;
1649 fd = FILE_GetUnixHandle( handle, GENERIC_WRITE );
1650 if(fd<0) {
1651 TRACE("FILE_GetUnixHandle failed\n");
1652 return FALSE;
1654 result = ioctl(fd,TIOCSBRK,0);
1655 close(fd);
1656 if (result ==-1)
1658 TRACE("ioctl failed\n");
1659 SetLastError(ERROR_NOT_SUPPORTED);
1660 return FALSE;
1662 return TRUE;
1663 #else
1664 FIXME("ioctl not available\n");
1665 SetLastError(ERROR_NOT_SUPPORTED);
1666 return FALSE;
1667 #endif
1670 /*****************************************************************************
1671 * ClearCommBreak (KERNEL32.20)
1673 BOOL WINAPI ClearCommBreak(HANDLE handle)
1675 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1676 int fd,result;
1678 fd = FILE_GetUnixHandle( handle, GENERIC_WRITE );
1679 if(fd<0) {
1680 TRACE("FILE_GetUnixHandle failed\n");
1681 return FALSE;
1683 result = ioctl(fd,TIOCCBRK,0);
1684 close(fd);
1685 if (result ==-1)
1687 TRACE("ioctl failed\n");
1688 SetLastError(ERROR_NOT_SUPPORTED);
1689 return FALSE;
1691 return TRUE;
1692 #else
1693 FIXME("ioctl not available\n");
1694 SetLastError(ERROR_NOT_SUPPORTED);
1695 return FALSE;
1696 #endif
1699 /*****************************************************************************
1700 * EscapeCommFunction (KERNEL32.214)
1702 BOOL WINAPI EscapeCommFunction(HANDLE handle,UINT nFunction)
1704 int fd,direct=FALSE,result=FALSE;
1705 struct termios port;
1707 TRACE("handle %d, function=%d\n", handle, nFunction);
1708 fd = FILE_GetUnixHandle( handle, GENERIC_WRITE );
1709 if(fd<0) {
1710 FIXME("handle %d not found.\n",handle);
1711 return FALSE;
1714 if (tcgetattr(fd,&port) == -1) {
1715 commerror=WinError();
1716 close(fd);
1717 return FALSE;
1720 switch (nFunction) {
1721 case RESETDEV:
1722 TRACE("\n");
1723 break;
1725 case CLRDTR:
1726 TRACE("CLRDTR\n");
1727 #ifdef TIOCM_DTR
1728 direct=TRUE;
1729 result= COMM_WhackModem(fd, ~TIOCM_DTR, 0);
1730 break;
1731 #endif
1733 case CLRRTS:
1734 TRACE("CLRRTS\n");
1735 #ifdef TIOCM_RTS
1736 direct=TRUE;
1737 result= COMM_WhackModem(fd, ~TIOCM_RTS, 0);
1738 break;
1739 #endif
1741 case SETDTR:
1742 TRACE("SETDTR\n");
1743 #ifdef TIOCM_DTR
1744 direct=TRUE;
1745 result= COMM_WhackModem(fd, 0, TIOCM_DTR);
1746 break;
1747 #endif
1749 case SETRTS:
1750 TRACE("SETRTS\n");
1751 #ifdef TIOCM_DTR
1752 direct=TRUE;
1753 result= COMM_WhackModem(fd, 0, TIOCM_RTS);
1754 break;
1755 #endif
1757 case SETXOFF:
1758 TRACE("SETXOFF\n");
1759 port.c_iflag |= IXOFF;
1760 break;
1762 case SETXON:
1763 TRACE("SETXON\n");
1764 port.c_iflag |= IXON;
1765 break;
1766 case SETBREAK:
1767 TRACE("setbreak\n");
1768 #ifdef TIOCSBRK
1769 direct=TRUE;
1770 result = ioctl(fd,TIOCSBRK,0);
1771 break;
1772 #endif
1773 case CLRBREAK:
1774 TRACE("clrbreak\n");
1775 #ifdef TIOCSBRK
1776 direct=TRUE;
1777 result = ioctl(fd,TIOCCBRK,0);
1778 break;
1779 #endif
1780 default:
1781 WARN("(handle=%d,nFunction=%d): Unknown function\n",
1782 handle, nFunction);
1783 break;
1786 if (!direct)
1787 if (tcsetattr(fd, TCSADRAIN, &port) == -1) {
1788 commerror = WinError();
1789 close(fd);
1790 return FALSE;
1791 } else
1792 result= TRUE;
1793 else
1795 if (result == -1)
1797 result= FALSE;
1798 commerror=WinError();
1800 else
1801 result = TRUE;
1803 close(fd);
1804 return result;
1807 /********************************************************************
1808 * PurgeComm (KERNEL32.557)
1810 BOOL WINAPI PurgeComm( HANDLE handle, DWORD flags)
1812 int fd;
1814 TRACE("handle %d, flags %lx\n", handle, flags);
1816 fd = FILE_GetUnixHandle( handle, GENERIC_WRITE );
1817 if(fd<0) {
1818 FIXME("no handle %d found\n",handle);
1819 return FALSE;
1823 ** not exactly sure how these are different
1824 ** Perhaps if we had our own internal queues, one flushes them
1825 ** and the other flushes the kernel's buffers.
1827 if(flags&PURGE_TXABORT)
1828 tcflush(fd,TCOFLUSH);
1829 if(flags&PURGE_RXABORT)
1830 tcflush(fd,TCIFLUSH);
1831 if(flags&PURGE_TXCLEAR)
1832 tcflush(fd,TCOFLUSH);
1833 if(flags&PURGE_RXCLEAR)
1834 tcflush(fd,TCIFLUSH);
1835 close(fd);
1837 return 1;
1840 /*****************************************************************************
1841 * ClearCommError (KERNEL32.21)
1843 BOOL WINAPI ClearCommError(HANDLE handle,LPDWORD errors,LPCOMSTAT lpStat)
1845 int fd;
1847 fd=FILE_GetUnixHandle( handle, GENERIC_READ );
1848 if(0>fd)
1850 FIXME("no handle %d found\n",handle);
1851 return FALSE;
1854 if (lpStat)
1856 lpStat->status = 0;
1858 #ifdef TIOCOUTQ
1859 if(ioctl(fd, TIOCOUTQ, &lpStat->cbOutQue))
1860 WARN("ioctl returned error\n");
1861 #else
1862 lpStat->cbOutQue = 0; /* FIXME: find a different way to find out */
1863 #endif
1865 if(ioctl(fd, TIOCINQ, &lpStat->cbInQue))
1866 WARN("ioctl returned error\n");
1868 TRACE("handle %d cbInQue = %ld cbOutQue = %ld\n",
1869 handle, lpStat->cbInQue, lpStat->cbOutQue);
1872 close(fd);
1874 if(errors)
1875 *errors = 0;
1878 ** After an asynchronous write opperation, the
1879 ** app will call ClearCommError to see if the
1880 ** results are ready yet. It waits for ERROR_IO_PENDING
1882 commerror = ERROR_IO_PENDING;
1884 return TRUE;
1887 /*****************************************************************************
1888 * SetupComm (KERNEL32.676)
1890 BOOL WINAPI SetupComm( HANDLE handle, DWORD insize, DWORD outsize)
1892 int fd;
1894 FIXME("insize %ld outsize %ld unimplemented stub\n", insize, outsize);
1895 fd=FILE_GetUnixHandle( handle, GENERIC_WRITE );
1896 if(0>fd) {
1897 FIXME("handle %d not found?\n",handle);
1898 return FALSE;
1900 close(fd);
1901 return TRUE;
1904 /*****************************************************************************
1905 * GetCommMask (KERNEL32.156)
1907 BOOL WINAPI GetCommMask(HANDLE handle,LPDWORD evtmask)
1909 BOOL ret;
1911 TRACE("handle %d, mask %p\n", handle, evtmask);
1913 SERVER_START_REQ
1915 struct get_serial_info_request *req = server_alloc_req( sizeof(*req), 0 );
1916 req->handle = handle;
1917 if ((ret = !server_call( REQ_GET_SERIAL_INFO )))
1919 if (evtmask) *evtmask = req->eventmask;
1922 SERVER_END_REQ;
1923 return ret;
1926 /*****************************************************************************
1927 * SetCommMask (KERNEL32.451)
1929 BOOL WINAPI SetCommMask(HANDLE handle,DWORD evtmask)
1931 BOOL ret;
1933 TRACE("handle %d, mask %lx\n", handle, evtmask);
1935 SERVER_START_REQ
1937 struct set_serial_info_request *req = server_alloc_req( sizeof(*req), 0 );
1938 req->handle = handle;
1939 req->flags = SERIALINFO_SET_MASK;
1940 req->eventmask = evtmask;
1941 ret = !server_call( REQ_SET_SERIAL_INFO );
1943 SERVER_END_REQ;
1944 return ret;
1947 /*****************************************************************************
1948 * SetCommState (KERNEL32.452)
1950 BOOL WINAPI SetCommState(HANDLE handle,LPDCB lpdcb)
1952 struct termios port;
1953 int fd;
1954 int bytesize, stopbits;
1956 TRACE("handle %d, ptr %p\n", handle, lpdcb);
1957 TRACE("bytesize %d baudrate %ld fParity %d Parity %d stopbits %d\n",
1958 lpdcb->ByteSize,lpdcb->BaudRate,lpdcb->fParity, lpdcb->Parity,
1959 (lpdcb->StopBits == ONESTOPBIT)?1:
1960 (lpdcb->StopBits == TWOSTOPBITS)?2:0);
1961 TRACE("%s %s\n",(lpdcb->fInX)?"IXON":"~IXON",
1962 (lpdcb->fOutX)?"IXOFF":"~IXOFF");
1964 fd = FILE_GetUnixHandle( handle, GENERIC_WRITE );
1965 if (fd < 0) {
1966 FIXME("no handle %d found\n",handle);
1967 return FALSE;
1970 if ((tcgetattr(fd,&port)) == -1) {
1971 int save_error = errno;
1972 commerror = WinError();
1973 close( fd );
1974 ERR("tcgetattr error '%s'\n", strerror(save_error));
1975 return FALSE;
1978 port.c_cc[VMIN] = 0;
1979 port.c_cc[VTIME] = 1;
1981 #ifdef IMAXBEL
1982 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|IMAXBEL);
1983 #else
1984 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR);
1985 #endif
1986 port.c_iflag |= (IGNBRK);
1988 port.c_oflag &= ~(OPOST);
1990 port.c_cflag &= ~(HUPCL);
1991 port.c_cflag |= CLOCAL | CREAD;
1993 port.c_lflag &= ~(ICANON|ECHO|ISIG);
1994 port.c_lflag |= NOFLSH;
1997 ** MJM - removed default baudrate settings
1998 ** TRACE(comm,"baudrate %ld\n",lpdcb->BaudRate);
2000 #ifdef CBAUD
2001 port.c_cflag &= ~CBAUD;
2002 switch (lpdcb->BaudRate) {
2003 case 110:
2004 case CBR_110:
2005 port.c_cflag |= B110;
2006 break;
2007 case 300:
2008 case CBR_300:
2009 port.c_cflag |= B300;
2010 break;
2011 case 600:
2012 case CBR_600:
2013 port.c_cflag |= B600;
2014 break;
2015 case 1200:
2016 case CBR_1200:
2017 port.c_cflag |= B1200;
2018 break;
2019 case 2400:
2020 case CBR_2400:
2021 port.c_cflag |= B2400;
2022 break;
2023 case 4800:
2024 case CBR_4800:
2025 port.c_cflag |= B4800;
2026 break;
2027 case 9600:
2028 case CBR_9600:
2029 port.c_cflag |= B9600;
2030 break;
2031 case 19200:
2032 case CBR_19200:
2033 port.c_cflag |= B19200;
2034 break;
2035 case 38400:
2036 case CBR_38400:
2037 port.c_cflag |= B38400;
2038 break;
2039 #ifdef B57600
2040 case 57600:
2041 port.c_cflag |= B57600;
2042 break;
2043 #endif
2044 #ifdef B115200
2045 case 115200:
2046 port.c_cflag |= B115200;
2047 break;
2048 #endif
2049 #ifdef B230400
2050 case 230400:
2051 port.c_cflag |= B230400;
2052 break;
2053 #endif
2054 #ifdef B460800
2055 case 460600:
2056 port.c_cflag |= B460800;
2057 break;
2058 #endif
2059 default:
2060 commerror = IE_BAUDRATE;
2061 close( fd );
2062 ERR("baudrate %ld\n",lpdcb->BaudRate);
2063 return FALSE;
2065 #elif !defined(__EMX__)
2066 switch (lpdcb->BaudRate) {
2067 case 110:
2068 case CBR_110:
2069 port.c_ospeed = B110;
2070 break;
2071 case 300:
2072 case CBR_300:
2073 port.c_ospeed = B300;
2074 break;
2075 case 600:
2076 case CBR_600:
2077 port.c_ospeed = B600;
2078 break;
2079 case 1200:
2080 case CBR_1200:
2081 port.c_ospeed = B1200;
2082 break;
2083 case 2400:
2084 case CBR_2400:
2085 port.c_ospeed = B2400;
2086 break;
2087 case 4800:
2088 case CBR_4800:
2089 port.c_ospeed = B4800;
2090 break;
2091 case 9600:
2092 case CBR_9600:
2093 port.c_ospeed = B9600;
2094 break;
2095 case 19200:
2096 case CBR_19200:
2097 port.c_ospeed = B19200;
2098 break;
2099 case 38400:
2100 case CBR_38400:
2101 port.c_ospeed = B38400;
2102 break;
2103 default:
2104 commerror = IE_BAUDRATE;
2105 close( fd );
2106 ERR("baudrate %ld\n",lpdcb->BaudRate);
2107 return FALSE;
2109 port.c_ispeed = port.c_ospeed;
2110 #endif
2111 bytesize=lpdcb->ByteSize;
2112 stopbits=lpdcb->StopBits;
2114 #ifdef CMSPAR
2115 port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
2116 #else
2117 port.c_cflag &= ~(PARENB | PARODD);
2118 #endif
2119 if (lpdcb->fParity)
2120 port.c_iflag |= INPCK;
2121 else
2122 port.c_iflag &= ~INPCK;
2123 switch (lpdcb->Parity) {
2124 case NOPARITY:
2125 break;
2126 case ODDPARITY:
2127 port.c_cflag |= (PARENB | PARODD);
2128 break;
2129 case EVENPARITY:
2130 port.c_cflag |= PARENB;
2131 break;
2132 #ifdef CMSPAR
2133 /* Linux defines mark/space (stick) parity */
2134 case MARKPARITY:
2135 port.c_cflag |= (PARENB | CMSPAR);
2136 break;
2137 case SPACEPARITY:
2138 port.c_cflag |= (PARENB | PARODD | CMSPAR);
2139 break;
2140 #else
2141 /* try the POSIX way */
2142 case MARKPARITY:
2143 if( stopbits == ONESTOPBIT) {
2144 stopbits = TWOSTOPBITS;
2145 port.c_iflag &= ~INPCK;
2146 } else {
2147 commerror = IE_BYTESIZE;
2148 close( fd );
2149 ERR("Cannot set MARK Parity\n");
2150 return FALSE;
2152 break;
2153 case SPACEPARITY:
2154 if( bytesize < 8) {
2155 bytesize +=1;
2156 port.c_iflag &= ~INPCK;
2157 } else {
2158 commerror = IE_BYTESIZE;
2159 close( fd );
2160 ERR("Cannot set SPACE Parity\n");
2161 return FALSE;
2163 break;
2164 #endif
2165 default:
2166 commerror = IE_BYTESIZE;
2167 close( fd );
2168 ERR("Parity\n");
2169 return FALSE;
2173 port.c_cflag &= ~CSIZE;
2174 switch (bytesize) {
2175 case 5:
2176 port.c_cflag |= CS5;
2177 break;
2178 case 6:
2179 port.c_cflag |= CS6;
2180 break;
2181 case 7:
2182 port.c_cflag |= CS7;
2183 break;
2184 case 8:
2185 port.c_cflag |= CS8;
2186 break;
2187 default:
2188 commerror = IE_BYTESIZE;
2189 close( fd );
2190 ERR("ByteSize\n");
2191 return FALSE;
2194 switch (stopbits) {
2195 case ONESTOPBIT:
2196 port.c_cflag &= ~CSTOPB;
2197 break;
2198 case ONE5STOPBITS: /* wil be selected if bytesize is 5 */
2199 case TWOSTOPBITS:
2200 port.c_cflag |= CSTOPB;
2201 break;
2202 default:
2203 commerror = IE_BYTESIZE;
2204 close( fd );
2205 ERR("StopBits\n");
2206 return FALSE;
2208 #ifdef CRTSCTS
2209 if ( lpdcb->fOutxCtsFlow ||
2210 lpdcb->fDtrControl == DTR_CONTROL_ENABLE||
2211 lpdcb->fRtsControl == RTS_CONTROL_ENABLE
2214 port.c_cflag |= CRTSCTS;
2215 TRACE("CRTSCTS\n");
2218 if (lpdcb->fDtrControl == DTR_CONTROL_DISABLE)
2220 port.c_cflag &= ~CRTSCTS;
2221 TRACE("~CRTSCTS\n");
2224 #endif
2225 if (lpdcb->fInX)
2226 port.c_iflag |= IXON;
2227 else
2228 port.c_iflag &= ~IXON;
2229 if (lpdcb->fOutX)
2230 port.c_iflag |= IXOFF;
2231 else
2232 port.c_iflag &= ~IXOFF;
2234 if (tcsetattr(fd,TCSANOW,&port)==-1) { /* otherwise it hangs with pending input*/
2235 int save_error=errno;
2236 commerror = WinError();
2237 close( fd );
2238 ERR("tcgetattr error '%s'\n", strerror(save_error));
2239 return FALSE;
2240 } else {
2241 commerror = 0;
2242 close( fd );
2243 return TRUE;
2248 /*****************************************************************************
2249 * GetCommState (KERNEL32.159)
2251 BOOL WINAPI GetCommState(HANDLE handle, LPDCB lpdcb)
2253 struct termios port;
2254 int fd,speed;
2256 TRACE("handle %d, ptr %p\n", handle, lpdcb);
2258 fd = FILE_GetUnixHandle( handle, GENERIC_READ );
2259 if (fd < 0)
2261 ERR("FILE_GetUnixHandle failed\n");
2262 return FALSE;
2264 if (tcgetattr(fd, &port) == -1) {
2265 int save_error=errno;
2266 ERR("tcgetattr error '%s'\n", strerror(save_error));
2267 commerror = WinError();
2268 close( fd );
2269 return FALSE;
2271 close( fd );
2272 #ifndef __EMX__
2273 #ifdef CBAUD
2274 speed= (port.c_cflag & CBAUD);
2275 #else
2276 speed= (cfgetospeed(&port));
2277 #endif
2278 switch (speed) {
2279 case B110:
2280 lpdcb->BaudRate = 110;
2281 break;
2282 case B300:
2283 lpdcb->BaudRate = 300;
2284 break;
2285 case B600:
2286 lpdcb->BaudRate = 600;
2287 break;
2288 case B1200:
2289 lpdcb->BaudRate = 1200;
2290 break;
2291 case B2400:
2292 lpdcb->BaudRate = 2400;
2293 break;
2294 case B4800:
2295 lpdcb->BaudRate = 4800;
2296 break;
2297 case B9600:
2298 lpdcb->BaudRate = 9600;
2299 break;
2300 case B19200:
2301 lpdcb->BaudRate = 19200;
2302 break;
2303 case B38400:
2304 lpdcb->BaudRate = 38400;
2305 break;
2306 #ifdef B57600
2307 case B57600:
2308 lpdcb->BaudRate = 57600;
2309 break;
2310 #endif
2311 #ifdef B115200
2312 case B115200:
2313 lpdcb->BaudRate = 115200;
2314 break;
2315 #endif
2316 #ifdef B230400
2317 case B230400:
2318 lpdcb->BaudRate = 230400;
2319 break;
2320 #endif
2321 #ifdef B460800
2322 case B460800:
2323 lpdcb->BaudRate = 460800;
2324 break;
2325 #endif
2326 default:
2327 ERR("unknown speed %x \n",speed);
2329 #endif
2330 switch (port.c_cflag & CSIZE) {
2331 case CS5:
2332 lpdcb->ByteSize = 5;
2333 break;
2334 case CS6:
2335 lpdcb->ByteSize = 6;
2336 break;
2337 case CS7:
2338 lpdcb->ByteSize = 7;
2339 break;
2340 case CS8:
2341 lpdcb->ByteSize = 8;
2342 break;
2343 default:
2344 ERR("unknown size %x \n",port.c_cflag & CSIZE);
2347 if(port.c_iflag & INPCK)
2348 lpdcb->fParity = TRUE;
2349 else
2350 lpdcb->fParity = FALSE;
2351 #ifdef CMSPAR
2352 switch (port.c_cflag & (PARENB | PARODD | CMSPAR))
2353 #else
2354 switch (port.c_cflag & (PARENB | PARODD))
2355 #endif
2357 case 0:
2358 lpdcb->Parity = NOPARITY;
2359 break;
2360 case PARENB:
2361 lpdcb->Parity = EVENPARITY;
2362 break;
2363 case (PARENB | PARODD):
2364 lpdcb->Parity = ODDPARITY;
2365 break;
2366 #ifdef CMSPAR
2367 case (PARENB | CMSPAR):
2368 lpdcb->Parity = MARKPARITY;
2369 break;
2370 case (PARENB | PARODD | CMSPAR):
2371 lpdcb->Parity = SPACEPARITY;
2372 break;
2373 #endif
2376 if (port.c_cflag & CSTOPB)
2377 if(lpdcb->ByteSize == 5)
2378 lpdcb->StopBits = ONE5STOPBITS;
2379 else
2380 lpdcb->StopBits = TWOSTOPBITS;
2381 else
2382 lpdcb->StopBits = ONESTOPBIT;
2384 lpdcb->fNull = 0;
2385 lpdcb->fBinary = 1;
2387 #ifdef CRTSCTS
2389 if (port.c_cflag & CRTSCTS) {
2390 lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
2391 lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
2392 lpdcb->fOutxCtsFlow = 1;
2393 lpdcb->fOutxDsrFlow = 1;
2394 } else
2395 #endif
2397 lpdcb->fDtrControl = DTR_CONTROL_DISABLE;
2398 lpdcb->fRtsControl = RTS_CONTROL_DISABLE;
2400 if (port.c_iflag & IXON)
2401 lpdcb->fInX = 1;
2402 else
2403 lpdcb->fInX = 0;
2405 if (port.c_iflag & IXOFF)
2406 lpdcb->fOutX = 1;
2407 else
2408 lpdcb->fOutX = 0;
2410 lpdcb->XonChar =
2411 lpdcb->XoffChar =
2413 lpdcb->XonLim = 10;
2414 lpdcb->XoffLim = 10;
2416 commerror = 0;
2418 TRACE("OK\n");
2420 TRACE("bytesize %d baudrate %ld fParity %d Parity %d stopbits %d\n",
2421 lpdcb->ByteSize,lpdcb->BaudRate,lpdcb->fParity, lpdcb->Parity,
2422 (lpdcb->StopBits == ONESTOPBIT)?1:
2423 (lpdcb->StopBits == TWOSTOPBITS)?2:0);
2424 TRACE("%s %s\n",(lpdcb->fInX)?"IXON":"~IXON",
2425 (lpdcb->fOutX)?"IXOFF":"~IXOFF");
2426 #ifdef CRTSCTS
2427 if ( lpdcb->fOutxCtsFlow ||
2428 lpdcb->fDtrControl == DTR_CONTROL_ENABLE||
2429 lpdcb->fRtsControl == RTS_CONTROL_ENABLE
2431 TRACE("CRTSCTS\n");
2433 if (lpdcb->fDtrControl == DTR_CONTROL_DISABLE)
2434 TRACE("~CRTSCTS\n");
2436 #endif
2437 return TRUE;
2440 /*****************************************************************************
2441 * TransmitCommChar (KERNEL32.535)
2443 BOOL WINAPI TransmitCommChar(HANDLE hComm,CHAR chTransmit)
2445 FIXME("(%x,'%c'), use win32 handle!\n",hComm,chTransmit);
2446 return TRUE;
2449 /*****************************************************************************
2450 * GetCommTimeouts (KERNEL32.160)
2452 BOOL WINAPI GetCommTimeouts(HANDLE hComm,LPCOMMTIMEOUTS lptimeouts)
2454 BOOL ret;
2456 TRACE("(%x,%p)\n",hComm,lptimeouts);
2458 if(!lptimeouts)
2460 SetLastError(ERROR_INVALID_PARAMETER);
2461 return FALSE;
2464 SERVER_START_REQ
2466 struct get_serial_info_request *req = server_alloc_req( sizeof(*req), 0 );
2467 req->handle = hComm;
2468 if ((ret = !server_call( REQ_GET_SERIAL_INFO )))
2470 lptimeouts->ReadIntervalTimeout = req->readinterval;
2471 lptimeouts->ReadTotalTimeoutMultiplier = req->readmult;
2472 lptimeouts->ReadTotalTimeoutConstant = req->readconst;
2473 lptimeouts->WriteTotalTimeoutMultiplier = req->writemult;
2474 lptimeouts->WriteTotalTimeoutConstant = req->writeconst;
2477 SERVER_END_REQ;
2478 return ret;
2481 /*****************************************************************************
2482 * SetCommTimeouts (KERNEL32.453)
2484 * Sets the timeouts used when reading and writing data to/from COMM ports.
2486 * ReadIntervalTimeout
2487 * - converted and passes to linux kernel as c_cc[VTIME]
2488 * ReadTotalTimeoutMultiplier, ReadTotalTimeoutConstant
2489 * - used in ReadFile to calculate GetOverlappedResult's timeout
2490 * WriteTotalTimeoutMultiplier, WriteTotalTimeoutConstant
2491 * - used in WriteFile to calculate GetOverlappedResult's timeout
2493 BOOL WINAPI SetCommTimeouts(
2494 HANDLE hComm, /* [I] handle of COMM device */
2495 LPCOMMTIMEOUTS lptimeouts /* [I] pointer to COMMTIMEOUTS structure */
2497 BOOL ret;
2498 int fd;
2499 struct termios tios;
2501 TRACE("(%x,%p)\n",hComm,lptimeouts);
2503 if(!lptimeouts)
2505 SetLastError(ERROR_INVALID_PARAMETER);
2506 return FALSE;
2509 SERVER_START_REQ
2511 struct set_serial_info_request *req = server_alloc_req( sizeof(*req), 0 );
2512 req->handle = hComm;
2513 req->flags = SERIALINFO_SET_TIMEOUTS;
2514 req->readinterval = lptimeouts->ReadIntervalTimeout ;
2515 req->readmult = lptimeouts->ReadTotalTimeoutMultiplier ;
2516 req->readconst = lptimeouts->ReadTotalTimeoutConstant ;
2517 req->writemult = lptimeouts->WriteTotalTimeoutMultiplier ;
2518 req->writeconst = lptimeouts->WriteTotalTimeoutConstant ;
2519 ret = !server_call( REQ_SET_SERIAL_INFO );
2521 SERVER_END_REQ;
2522 if (!ret) return FALSE;
2524 /* FIXME: move this stuff to the server */
2525 fd = FILE_GetUnixHandle( hComm, GENERIC_WRITE );
2526 if (fd < 0) {
2527 FIXME("no fd for handle = %0x!.\n",hComm);
2528 return FALSE;
2531 if (-1==tcgetattr(fd,&tios)) {
2532 FIXME("tcgetattr on fd %d failed!\n",fd);
2533 return FALSE;
2535 /* VTIME is in 1/10 seconds */
2536 tios.c_cc[VTIME]= (lptimeouts->ReadIntervalTimeout+99)/100;
2537 if (-1==tcsetattr(fd,0,&tios)) {
2538 FIXME("tcsetattr on fd %d failed!\n",fd);
2539 return FALSE;
2541 close(fd);
2542 return TRUE;
2545 /***********************************************************************
2546 * GetCommModemStatus (KERNEL32.285)
2548 BOOL WINAPI GetCommModemStatus(HANDLE hFile,LPDWORD lpModemStat )
2550 int fd,mstat, result=FALSE;
2552 *lpModemStat=0;
2553 #ifdef TIOCMGET
2554 fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
2555 if(fd<0)
2556 return FALSE;
2557 result = ioctl(fd, TIOCMGET, &mstat);
2558 close(fd);
2559 if (result == -1)
2561 TRACE("ioctl failed\n");
2562 return FALSE;
2564 if (mstat & TIOCM_CTS)
2565 *lpModemStat |= MS_CTS_ON;
2566 if (mstat & TIOCM_DSR)
2567 *lpModemStat |= MS_DSR_ON;
2568 if (mstat & TIOCM_RNG)
2569 *lpModemStat |= MS_RING_ON;
2570 /*FIXME: Not really sure about RLSD UB 990810*/
2571 if (mstat & TIOCM_CAR)
2572 *lpModemStat |= MS_RLSD_ON;
2573 TRACE("%s%s%s%s\n",
2574 (*lpModemStat &MS_RLSD_ON)?"MS_RLSD_ON ":"",
2575 (*lpModemStat &MS_RING_ON)?"MS_RING_ON ":"",
2576 (*lpModemStat &MS_DSR_ON)?"MS_DSR_ON ":"",
2577 (*lpModemStat &MS_CTS_ON)?"MS_CTS_ON ":"");
2578 return TRUE;
2579 #else
2580 return FALSE;
2581 #endif
2584 VOID COMM_WaitCommEventService(void **args)
2586 LPOVERLAPPED lpOverlapped = (LPOVERLAPPED)args[0];
2587 LPDWORD buffer = (LPDWORD)args[1];
2588 DWORD events = (DWORD)args[2];
2590 TRACE("overlapped %p wait complete %p <- %lx\n",lpOverlapped,buffer,events);
2591 if(buffer)
2592 *buffer = events;
2594 SetEvent( lpOverlapped->hEvent);
2597 /***********************************************************************
2598 * WaitCommEvent (KERNEL32.719)
2600 * Wait until something interesting happens on a COMM port.
2601 * Interesting things (events) are set by calling SetCommMask before
2602 * this function is called.
2604 * RETURNS:
2605 * TRUE if successful
2606 * FALSE if failure
2608 * The set of detected events will be written to *lpdwEventMask
2609 * ERROR_IO_PENDING will be returned the overlapped structure was passed
2611 * BUGS:
2612 * Only supports EV_RXCHAR and EV_TXEMPTY
2614 BOOL WINAPI WaitCommEvent(
2615 HANDLE hFile, /* [I] handle of comm port to wait for */
2616 LPDWORD lpdwEvents, /* [O] event(s) that were detected */
2617 LPOVERLAPPED lpOverlapped /* [I/O] for Asynchronous waiting */
2619 OVERLAPPED ov;
2620 LPOVERLAPPED lpov;
2621 int ret;
2623 TRACE("(%x %p %p )\n",hFile, lpdwEvents,lpOverlapped);
2625 /* if there is no overlapped structure, create our own */
2626 if(!lpOverlapped)
2628 ov.hEvent = CreateEventA(NULL,FALSE,FALSE,NULL);
2629 lpov = &ov;
2631 else
2632 lpov = lpOverlapped;
2634 /* check that the overlapped structure has a valid event flag */
2635 if ( (lpov->hEvent==0) || (lpov->hEvent == INVALID_HANDLE_VALUE) )
2637 ERR("Couldn't create Event flag for Overlapped structure\n");
2638 SetLastError(ERROR_INVALID_PARAMETER);
2639 return FALSE;
2642 lpov->Internal = 0;
2643 lpov->InternalHigh = hFile;
2644 lpov->Offset = 0;
2645 lpov->OffsetHigh = 0;
2647 /* start an ASYNCHRONOUS WaitCommEvent */
2648 SERVER_START_REQ
2650 struct create_async_request *req = server_alloc_req( sizeof(*req), 0 );
2652 req->file_handle = hFile;
2653 req->overlapped = lpov;
2654 req->buffer = lpdwEvents;
2655 req->count = 0;
2656 req->func = COMM_WaitCommEventService;
2657 req->type = ASYNC_TYPE_WAIT;
2659 ret=server_call( REQ_CREATE_ASYNC );
2661 lpov->Internal = req->ov_handle;
2663 SERVER_END_REQ;
2665 if(ret)
2667 if(!lpOverlapped)
2668 CloseHandle(lpov->hEvent);
2669 TRACE("server call failed.\n");
2670 return FALSE;
2673 /* wait ourselves if the caller didn't give us an overlapped struct */
2674 if(!lpOverlapped)
2676 GetOverlappedResult(hFile, lpov, NULL, TRUE);
2677 CloseHandle(lpov->hEvent);
2678 lpov->hEvent=0;
2680 else
2682 /* caller wants overlapped I/O using GetOverlapped result */
2683 SetLastError(ERROR_IO_PENDING);
2684 return FALSE;
2687 return TRUE;
2690 /***********************************************************************
2691 * GetCommProperties (KERNEL32.286)
2693 * This function fills in a structure with the capabilities of the
2694 * communications port driver.
2696 * RETURNS
2698 * TRUE on success, FALSE on failure
2699 * If successful, the lpCommProp structure be filled in with
2700 * properties of the comm port.
2702 BOOL WINAPI GetCommProperties(
2703 HANDLE hFile, /* handle of the comm port */
2704 LPCOMMPROP lpCommProp /* pointer to struct to be filled */
2706 FIXME("(%d %p )\n",hFile,lpCommProp);
2707 if(!lpCommProp)
2708 return FALSE;
2711 * These values should be valid for LINUX's serial driver
2712 * FIXME: Perhaps they deserve an #ifdef LINUX
2714 memset(lpCommProp,0,sizeof(COMMPROP));
2715 lpCommProp->wPacketLength = 1;
2716 lpCommProp->wPacketVersion = 1;
2717 lpCommProp->dwServiceMask = SP_SERIALCOMM;
2718 lpCommProp->dwReserved1 = 0;
2719 lpCommProp->dwMaxTxQueue = 4096;
2720 lpCommProp->dwMaxRxQueue = 4096;
2721 lpCommProp->dwMaxBaud = BAUD_115200;
2722 lpCommProp->dwProvSubType = PST_RS232;
2723 lpCommProp->dwProvCapabilities = PCF_DTRDSR | PCF_PARITY_CHECK | PCF_RTSCTS ;
2724 lpCommProp->dwSettableParams = SP_BAUD | SP_DATABITS | SP_HANDSHAKING |
2725 SP_PARITY | SP_PARITY_CHECK | SP_STOPBITS ;
2726 lpCommProp->dwSettableBaud = BAUD_075 | BAUD_110 | BAUD_134_5 | BAUD_150 |
2727 BAUD_300 | BAUD_600 | BAUD_1200 | BAUD_1800 | BAUD_2400 | BAUD_4800 |
2728 BAUD_9600 | BAUD_19200 | BAUD_38400 | BAUD_57600 | BAUD_115200 ;
2729 lpCommProp->wSettableData = DATABITS_5 | DATABITS_6 | DATABITS_7 | DATABITS_8 ;
2730 lpCommProp->wSettableStopParity = STOPBITS_10 | STOPBITS_15 | STOPBITS_20 |
2731 PARITY_NONE | PARITY_ODD |PARITY_EVEN | PARITY_MARK | PARITY_SPACE;
2732 lpCommProp->dwCurrentTxQueue = lpCommProp->dwMaxTxQueue;
2733 lpCommProp->dwCurrentRxQueue = lpCommProp->dwMaxRxQueue;
2735 return TRUE;
2738 /***********************************************************************
2739 * FIXME:
2740 * The functionality of CommConfigDialogA, GetDefaultCommConfig and
2741 * SetDefaultCommConfig is implemented in a DLL (usually SERIALUI.DLL).
2742 * This is dependent on the type of COMM port, but since it is doubtful
2743 * anybody will get around to implementing support for fancy serial
2744 * ports in WINE, this is hardcoded for the time being. The name of
2745 * this DLL should be stored in and read from the system registry in
2746 * the hive HKEY_LOCAL_MACHINE, key
2747 * System\\CurrentControlSet\\Services\\Class\\Ports\\????
2748 * where ???? is the port number... that is determined by PNP
2749 * The DLL should be loaded when the COMM port is opened, and closed
2750 * when the COMM port is closed. - MJM 20 June 2000
2751 ***********************************************************************/
2752 static CHAR lpszSerialUI[] = "serialui.dll";
2755 /***********************************************************************
2756 * CommConfigDialogA (KERNEL32.140)
2758 * Raises a dialog that allows the user to configure a comm port.
2759 * Fills the COMMCONFIG struct with information specified by the user.
2760 * This function should call a similar routine in the COMM driver...
2762 * RETURNS
2764 * TRUE on success, FALSE on failure
2765 * If successful, the lpCommConfig structure will contain a new
2766 * configuration for the comm port, as specified by the user.
2768 * BUGS
2769 * The library with the CommConfigDialog code is never unloaded.
2770 * Perhaps this should be done when the comm port is closed?
2772 BOOL WINAPI CommConfigDialogA(
2773 LPCSTR lpszDevice, /* name of communications device */
2774 HANDLE hWnd, /* parent window for the dialog */
2775 LPCOMMCONFIG lpCommConfig /* pointer to struct to fill */
2777 FARPROC lpfnCommDialog;
2778 HMODULE hConfigModule;
2779 BOOL r;
2781 TRACE("(%p %x %p)\n",lpszDevice, hWnd, lpCommConfig);
2783 hConfigModule = LoadLibraryA(lpszSerialUI);
2784 if(!hConfigModule)
2785 return FALSE;
2787 lpfnCommDialog = GetProcAddress(hConfigModule, (LPCSTR)3L);
2789 if(!lpfnCommDialog)
2790 return FALSE;
2792 r = lpfnCommDialog(lpszDevice,hWnd,lpCommConfig);
2794 /* UnloadLibrary(hConfigModule); */
2796 return r;
2799 /***********************************************************************
2800 * CommConfigDialogW (KERNEL32.141)
2802 * see CommConfigDialogA for more info
2804 BOOL WINAPI CommConfigDialogW(
2805 LPCWSTR lpszDevice, /* name of communications device */
2806 HANDLE hWnd, /* parent window for the dialog */
2807 LPCOMMCONFIG lpCommConfig /* pointer to struct to fill */
2809 BOOL r;
2810 LPSTR lpDeviceA;
2812 lpDeviceA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpszDevice );
2813 if(lpDeviceA)
2814 return FALSE;
2815 r = CommConfigDialogA(lpDeviceA,hWnd,lpCommConfig);
2816 HeapFree( GetProcessHeap(), 0, lpDeviceA );
2817 return r;
2820 /***********************************************************************
2821 * GetCommConfig (KERNEL32.283)
2823 * Fill in the COMMCONFIG structure for the comm port hFile
2825 * RETURNS
2827 * TRUE on success, FALSE on failure
2828 * If successful, lpCommConfig contains the comm port configuration.
2830 BOOL WINAPI GetCommConfig(
2831 HANDLE hFile,
2832 LPCOMMCONFIG lpCommConfig
2834 BOOL r;
2836 TRACE("(%x %p)\n",hFile,lpCommConfig);
2838 if(lpCommConfig == NULL)
2839 return FALSE;
2841 lpCommConfig->dwSize = sizeof(COMMCONFIG);
2842 lpCommConfig->wVersion = 1;
2843 lpCommConfig->wReserved = 0;
2844 r = GetCommState(hFile,&lpCommConfig->dcb);
2845 lpCommConfig->dwProviderSubType = PST_RS232;
2846 lpCommConfig->dwProviderOffset = 0;
2847 lpCommConfig->dwProviderSize = 0;
2849 return r;
2852 /***********************************************************************
2853 * SetCommConfig (KERNEL32.617)
2856 BOOL WINAPI SetCommConfig(
2857 HANDLE hFile,
2858 LPCOMMCONFIG lpCommConfig
2860 BOOL r;
2862 TRACE("(%x %p)\n",hFile,lpCommConfig);
2864 r = SetCommState(hFile,&lpCommConfig->dcb);
2865 return r;
2868 /***********************************************************************
2869 * SetDefaultCommConfigA (KERNEL32.638)
2871 BOOL WINAPI SetDefaultCommConfigA(
2872 LPCSTR lpszDevice,
2873 LPCOMMCONFIG lpCommConfig,
2874 DWORD dwSize
2876 FARPROC lpfnSetDefaultCommConfig;
2877 HMODULE hConfigModule;
2878 BOOL r;
2880 TRACE("(%p %p %lx)\n",lpszDevice, lpCommConfig, dwSize);
2882 hConfigModule = LoadLibraryA(lpszSerialUI);
2883 if(!hConfigModule)
2884 return FALSE;
2886 lpfnSetDefaultCommConfig = GetProcAddress(hConfigModule, (LPCSTR)4L);
2888 if(! lpfnSetDefaultCommConfig)
2889 return TRUE;
2891 r = lpfnSetDefaultCommConfig(lpszDevice, lpCommConfig, dwSize);
2893 /* UnloadLibrary(hConfigModule); */
2895 return r;
2899 /***********************************************************************
2900 * SetDefaultCommConfigW (KERNEL32.639)
2903 BOOL WINAPI SetDefaultCommConfigW(
2904 LPCWSTR lpszDevice,
2905 LPCOMMCONFIG lpCommConfig,
2906 DWORD dwSize
2908 BOOL r;
2909 LPSTR lpDeviceA;
2911 TRACE("(%s %p %lx)\n",debugstr_w(lpszDevice),lpCommConfig,dwSize);
2913 lpDeviceA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpszDevice );
2914 if(lpDeviceA)
2915 return FALSE;
2916 r = SetDefaultCommConfigA(lpDeviceA,lpCommConfig,dwSize);
2917 HeapFree( GetProcessHeap(), 0, lpDeviceA );
2918 return r;
2922 /***********************************************************************
2923 * GetDefaultCommConfigA (KERNEL32.313)
2925 BOOL WINAPI GetDefaultCommConfigA(LPCSTR lpszName,LPCOMMCONFIG lpCC,
2926 LPDWORD lpdwSize)
2928 LPDCB lpdcb = &(lpCC->dcb);
2929 char temp[40];
2931 if (strncasecmp(lpszName,"COM",3)) {
2932 ERR("not implemented for <%s>\n", lpszName);
2933 return FALSE;
2936 if (!ValidCOMPort(lpszName[3]-'1'))
2937 return FALSE;
2939 TRACE("(%s %p %ld)\n", lpszName, lpCC, *lpdwSize );
2940 if (*lpdwSize < sizeof(COMMCONFIG)) {
2941 *lpdwSize = sizeof(COMMCONFIG);
2942 return FALSE;
2945 *lpdwSize = sizeof(COMMCONFIG);
2947 lpCC->dwSize = sizeof(COMMCONFIG);
2948 lpCC->wVersion = 1;
2949 lpCC->dwProviderSubType = PST_RS232;
2950 lpCC->dwProviderOffset = 0L;
2951 lpCC->dwProviderSize = 0L;
2953 (void) sprintf( temp, "COM%c:38400,n,8,1", lpszName[3]);
2954 FIXME("setting %s as default\n", temp);
2956 return BuildCommDCBA( temp, lpdcb);
2959 /**************************************************************************
2960 * GetDefaultCommConfigW (KERNEL32.314)
2962 BOOL WINAPI GetDefaultCommConfigW( LPCWSTR lpszName,LPCOMMCONFIG lpCC,
2963 LPDWORD lpdwSize)
2965 LPSTR lpszNameA;
2966 BOOL ret;
2968 TRACE("(%p,%p,%ld)\n",lpszName,lpCC,*lpdwSize);
2969 lpszNameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpszName );
2970 ret=GetDefaultCommConfigA(lpszNameA,lpCC,lpdwSize);
2971 HeapFree( GetProcessHeap(), 0, lpszNameA );
2972 return ret;