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.
48 #ifdef HAVE_SYS_FILIO_H
49 # include <sys/filio.h>
51 #include <sys/ioctl.h>
55 #ifdef HAVE_SYS_MODEM_H
56 # include <sys/modem.h>
58 #ifdef HAVE_SYS_STRTIO_H
59 # include <sys/strtio.h>
63 #include "wine/port.h"
70 #include "debugtools.h"
72 DEFAULT_DEBUG_CHANNEL(comm);
74 #if !defined(TIOCINQ) && defined(FIONREAD)
75 #define TIOCINQ FIONREAD
78 /* window's semi documented modem status register */
79 #define COMM_MSR_OFFSET 35
84 #define MSR_MASK (MSR_CTS|MSR_DSR|MSR_RI|MSR_RLSD)
89 #define CMSPAR 0x40000000 /* stick parity */
94 struct DosDeviceStruct {
95 char *devicename; /* /dev/cua1 */
102 int commerror, eventmask;
105 unsigned ibuf_size,ibuf_head,ibuf_tail;
106 unsigned obuf_size,obuf_head,obuf_tail;
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)
126 if(mstat & TIOCM_CTS) tmpmsr |= MSR_CTS;
129 if(mstat & TIOCM_DSR) tmpmsr |= MSR_DSR;
132 if(mstat & TIOCM_RI) tmpmsr |= MSR_RI;
135 if(mstat & TIOCM_CAR) tmpmsr |= MSR_RLSD;
137 *pMsr = (*pMsr & ~MSR_MASK) | tmpmsr;
143 char option[10], temp[256], *btemp;
146 for (x=0; x!=MAX_PORTS; x++) {
147 strcpy(option,"COMx");
151 PROFILE_GetWineIniString( "serialports", option, "*",
152 temp, sizeof(temp) );
153 if (!strcmp(temp, "*") || *temp == '\0')
154 COM[x].devicename = NULL;
156 btemp = strchr(temp,',');
159 COM[x].baudrate = atoi(btemp);
161 COM[x].baudrate = -1;
164 if (!S_ISCHR(st.st_mode))
165 WARN("Can't use `%s' as %s !\n", temp, option);
167 if ((COM[x].devicename = malloc(strlen(temp)+1)) == NULL)
168 WARN("Can't malloc for device info!\n");
171 strcpy(COM[x].devicename, temp);
173 TRACE("%s = %s\n", option, COM[x].devicename);
176 strcpy(option, "LPTx");
180 PROFILE_GetWineIniString( "parallelports", option, "*",
181 temp, sizeof(temp) );
182 if (!strcmp(temp, "*") || *temp == '\0')
183 LPT[x].devicename = NULL;
186 if (!S_ISCHR(st.st_mode))
187 WARN("Can't use `%s' as %s !\n", temp, option);
189 if ((LPT[x].devicename = malloc(strlen(temp)+1)) == NULL)
190 WARN("Can't malloc for device info!\n");
193 strcpy(LPT[x].devicename, temp);
195 TRACE("%s = %s\n", option, LPT[x].devicename);
202 static struct DosDeviceStruct *GetDeviceStruct(int fd)
204 if ((fd&0x7F)<=MAX_PORTS) {
205 if (!(fd&FLAG_LPT)) {
218 static int GetCommPort_fd(int fd)
222 for (x=0; x<MAX_PORTS; x++) {
230 static int ValidCOMPort(int x)
232 return(x < MAX_PORTS ? (int) COM[x].devicename : 0);
235 static int ValidLPTPort(int x)
237 return(x < MAX_PORTS ? (int) LPT[x].devicename : 0);
240 static int WinError(void)
242 TRACE("errno = %d\n", errno);
249 static unsigned comm_inbuf(struct DosDeviceStruct *ptr)
251 return ((ptr->ibuf_tail > ptr->ibuf_head) ? ptr->ibuf_size : 0)
252 + ptr->ibuf_head - ptr->ibuf_tail;
255 static unsigned comm_outbuf(struct DosDeviceStruct *ptr)
257 return ((ptr->obuf_tail > ptr->obuf_head) ? ptr->obuf_size : 0)
258 + ptr->obuf_head - ptr->obuf_tail;
261 static int COMM_WhackModem(int fd, unsigned int andy, unsigned int orrie)
263 unsigned int mstat, okay;
264 okay = ioctl(fd, TIOCMGET, &mstat);
265 if (okay) return okay;
266 if (andy) mstat &= andy;
268 return ioctl(fd, TIOCMSET, &mstat);
271 static void CALLBACK comm_notification( ULONG_PTR private )
273 struct DosDeviceStruct *ptr = (struct DosDeviceStruct *)private;
274 int prev, bleft, len;
276 int cid = GetCommPort_fd(ptr->fd);
278 TRACE("async notification\n");
279 /* read data from comm port */
280 prev = comm_inbuf(ptr);
282 bleft = ((ptr->ibuf_tail > ptr->ibuf_head) ? (ptr->ibuf_tail-1) : ptr->ibuf_size)
284 len = read(ptr->fd, ptr->inbuf + ptr->ibuf_head, bleft?bleft:1);
287 ptr->commerror = CE_RXOVER;
289 /* check for events */
290 if ((ptr->eventmask & EV_RXFLAG) &&
291 memchr(ptr->inbuf + ptr->ibuf_head, ptr->evtchar, len)) {
292 *(WORD*)(unknown[cid]) |= EV_RXFLAG;
295 if (ptr->eventmask & EV_RXCHAR) {
296 *(WORD*)(unknown[cid]) |= EV_RXCHAR;
299 /* advance buffer position */
300 ptr->ibuf_head += len;
301 if (ptr->ibuf_head >= ptr->ibuf_size)
306 /* check for notification */
307 if (ptr->wnd && (ptr->n_read>0) && (prev<ptr->n_read) &&
308 (comm_inbuf(ptr)>=ptr->n_read)) {
309 /* passed the receive notification threshold */
313 /* write any TransmitCommChar character */
315 len = write(ptr->fd, &(ptr->xmit), 1);
316 if (len > 0) ptr->xmit = -1;
318 /* write from output queue */
319 prev = comm_outbuf(ptr);
321 bleft = ((ptr->obuf_tail <= ptr->obuf_head) ? ptr->obuf_head : ptr->obuf_size)
323 len = bleft ? write(ptr->fd, ptr->outbuf + ptr->obuf_tail, bleft) : 0;
325 ptr->obuf_tail += len;
326 if (ptr->obuf_tail >= ptr->obuf_size)
329 if (ptr->obuf_tail == ptr->obuf_head) {
331 SERVICE_Delete( ptr->s_write );
332 ptr->s_write = INVALID_HANDLE_VALUE;
334 if (ptr->eventmask & EV_TXEMPTY) {
335 *(WORD*)(unknown[cid]) |= EV_TXEMPTY;
341 /* check for notification */
342 if (ptr->wnd && (ptr->n_write>0) && (prev>=ptr->n_write) &&
343 (comm_outbuf(ptr)<ptr->n_write)) {
344 /* passed the transmit notification threshold */
348 /* send notifications, if any */
349 if (ptr->wnd && mask) {
350 TRACE("notifying %04x: cid=%d, mask=%02x\n", ptr->wnd, cid, mask);
351 if (Callout.PostMessageA) Callout.PostMessageA(ptr->wnd, WM_COMMNOTIFY, cid, mask);
355 static void comm_waitread(struct DosDeviceStruct *ptr)
357 if (ptr->s_read != INVALID_HANDLE_VALUE) return;
358 ptr->s_read = SERVICE_AddObject( FILE_DupUnixHandle( ptr->fd,
359 GENERIC_READ | SYNCHRONIZE ),
364 static void comm_waitwrite(struct DosDeviceStruct *ptr)
366 if (ptr->s_write != INVALID_HANDLE_VALUE) return;
367 ptr->s_write = SERVICE_AddObject( FILE_DupUnixHandle( ptr->fd,
368 GENERIC_WRITE | SYNCHRONIZE ),
373 /**************************************************************************
374 * BuildCommDCB16 (USER.213)
376 * According to the ECMA-234 (368.3) the function will return FALSE on
377 * success, otherwise it will return -1.
378 * IF THIS IS NOT CORRECT THE RETURNVALUE CHECK IN BuildCommDCBAndTimeoutsA
381 BOOL16 WINAPI BuildCommDCB16(LPCSTR device, LPDCB16 lpdcb)
383 /* "COM1:9600,n,8,1" */
386 char *ptr, temp[256];
388 TRACE("(%s), ptr %p\n", device, lpdcb);
390 if (!strncasecmp(device,"COM",3)) {
391 port = device[3] - '0';
395 ERR("BUG ! COM0 can't exist!.\n");
399 if (!ValidCOMPort(port)) {
400 FIXME("invalid COM port %d?\n",port);
404 memset(lpdcb, 0, sizeof(DCB16)); /* initialize */
411 if (*(device+4) != ':')
414 strcpy(temp,device+5);
415 ptr = strtok(temp, ", ");
417 if (COM[port].baudrate > 0)
418 lpdcb->BaudRate = COM[port].baudrate;
420 lpdcb->BaudRate = atoi(ptr);
421 TRACE("baudrate (%d)\n", lpdcb->BaudRate);
423 ptr = strtok(NULL, ", ");
425 *ptr = toupper(*ptr);
427 TRACE("parity (%c)\n", *ptr);
428 lpdcb->fParity = TRUE;
431 lpdcb->Parity = NOPARITY;
432 lpdcb->fParity = FALSE;
435 lpdcb->Parity = EVENPARITY;
438 lpdcb->Parity = MARKPARITY;
441 lpdcb->Parity = ODDPARITY;
444 WARN("Unknown parity `%c'!\n", *ptr);
448 ptr = strtok(NULL, ", ");
449 TRACE("charsize (%c)\n", *ptr);
450 lpdcb->ByteSize = *ptr - '0';
452 ptr = strtok(NULL, ", ");
453 TRACE("stopbits (%c)\n", *ptr);
456 lpdcb->StopBits = ONESTOPBIT;
459 lpdcb->StopBits = TWOSTOPBITS;
462 WARN("Unknown # of stopbits `%c'!\n", *ptr);
470 /*****************************************************************************
471 * OpenComm16 (USER.200)
473 INT16 WINAPI OpenComm16(LPCSTR device,UINT16 cbInQueue,UINT16 cbOutQueue)
477 TRACE("%s, %d, %d\n", device, cbInQueue, cbOutQueue);
479 if (strlen(device) < 4)
482 port = device[3] - '0';
485 ERR("BUG ! COM0 or LPT0 don't exist !\n");
487 if (!strncasecmp(device,"COM",3)) {
489 TRACE("%s = %s\n", device, COM[port].devicename);
491 if (!ValidCOMPort(port))
497 fd = open(COM[port].devicename, O_RDWR | O_NONBLOCK);
499 ERR("Couldn't open %s ! (%s)\n", COM[port].devicename, strerror(errno));
502 unknown[port] = SEGPTR_ALLOC(40);
503 bzero(unknown[port],40);
505 COM[port].commerror = 0;
506 COM[port].eventmask = 0;
507 COM[port].evtchar = 0; /* FIXME: default? */
508 /* save terminal state */
509 tcgetattr(fd,&m_stat[port]);
510 /* set default parameters */
511 if(COM[port].baudrate>-1){
513 GetCommState16(port, &dcb);
514 dcb.BaudRate=COM[port].baudrate;
516 * databits, parity, stopbits
518 SetCommState16( &dcb);
520 /* init priority characters */
521 COM[port].unget = -1;
523 /* allocate buffers */
524 COM[port].ibuf_size = cbInQueue;
525 COM[port].ibuf_head = COM[port].ibuf_tail= 0;
526 COM[port].obuf_size = cbOutQueue;
527 COM[port].obuf_head = COM[port].obuf_tail = 0;
529 COM[port].inbuf = malloc(cbInQueue);
530 if (COM[port].inbuf) {
531 COM[port].outbuf = malloc(cbOutQueue);
532 if (!COM[port].outbuf)
533 free(COM[port].inbuf);
534 } else COM[port].outbuf = NULL;
535 if (!COM[port].outbuf) {
536 /* not enough memory */
537 tcsetattr(COM[port].fd,TCSANOW,&m_stat[port]);
539 ERR("out of memory\n");
543 COM[port].s_read = INVALID_HANDLE_VALUE;
544 COM[port].s_write = INVALID_HANDLE_VALUE;
545 comm_waitread( &COM[port] );
550 if (!strncasecmp(device,"LPT",3)) {
552 if (!ValidLPTPort(port))
558 fd = open(LPT[port].devicename, O_RDWR | O_NONBLOCK, 0);
563 LPT[port].commerror = 0;
564 LPT[port].eventmask = 0;
565 return port|FLAG_LPT;
571 /*****************************************************************************
572 * CloseComm16 (USER.207)
574 INT16 WINAPI CloseComm16(INT16 cid)
576 struct DosDeviceStruct *ptr;
578 TRACE("cid=%d\n", cid);
579 if ((ptr = GetDeviceStruct(cid)) == NULL) {
580 FIXME("no cid=%d found!\n", cid);
583 if (!(cid&FLAG_LPT)) {
585 SEGPTR_FREE(unknown[cid]); /* [LW] */
587 SERVICE_Delete( COM[cid].s_write );
588 SERVICE_Delete( COM[cid].s_read );
593 /* reset modem lines */
594 tcsetattr(ptr->fd,TCSANOW,&m_stat[cid]);
597 if (close(ptr->fd) == -1) {
598 ptr->commerror = WinError();
599 /* FIXME: should we clear ptr->fd here? */
608 /*****************************************************************************
609 * SetCommBreak16 (USER.210)
611 INT16 WINAPI SetCommBreak16(INT16 cid)
613 struct DosDeviceStruct *ptr;
615 TRACE("cid=%d\n", cid);
616 if ((ptr = GetDeviceStruct(cid)) == NULL) {
617 FIXME("no cid=%d found!\n", cid);
626 /*****************************************************************************
627 * ClearCommBreak16 (USER.211)
629 INT16 WINAPI ClearCommBreak16(INT16 cid)
631 struct DosDeviceStruct *ptr;
633 TRACE("cid=%d\n", cid);
634 if (!(ptr = GetDeviceStruct(cid))) {
635 FIXME("no cid=%d found!\n", cid);
643 /*****************************************************************************
644 * EscapeCommFunction16 (USER.214)
646 LONG WINAPI EscapeCommFunction16(UINT16 cid,UINT16 nFunction)
649 struct DosDeviceStruct *ptr;
652 TRACE("cid=%d, function=%d\n", cid, nFunction);
653 if ((nFunction != GETMAXCOM) && (nFunction != GETMAXLPT)) {
654 if ((ptr = GetDeviceStruct(cid)) == NULL) {
655 FIXME("no cid=%d found!\n", cid);
658 if (tcgetattr(ptr->fd,&port) == -1) {
659 TRACE("tcgetattr failed\n");
660 ptr->commerror=WinError();
671 TRACE("GETMAXCOM\n");
672 for (max = MAX_PORTS;!COM[max].devicename;max--)
678 TRACE("GETMAXLPT\n");
679 for (max = MAX_PORTS;!LPT[max].devicename;max--)
681 return FLAG_LPT + max;
685 TRACE("GETBASEIRQ\n");
686 /* FIXME: use tables */
687 /* just fake something for now */
688 if (cid & FLAG_LPT) {
689 /* LPT1: irq 7, LPT2: irq 5 */
690 return (cid & 0x7f) ? 5 : 7;
692 /* COM1: irq 4, COM2: irq 3,
693 COM3: irq 4, COM4: irq 3 */
694 return 4 - (cid & 1);
701 return COMM_WhackModem(ptr->fd, ~TIOCM_DTR, 0);
706 return COMM_WhackModem(ptr->fd, ~TIOCM_RTS, 0);
712 return COMM_WhackModem(ptr->fd, 0, TIOCM_DTR);
718 return COMM_WhackModem(ptr->fd, 0, TIOCM_RTS);
723 port.c_iflag |= IXOFF;
728 port.c_iflag |= IXON;
732 WARN("(cid=%d,nFunction=%d): Unknown function\n",
737 if (tcsetattr(ptr->fd, TCSADRAIN, &port) == -1) {
738 ptr->commerror = WinError();
746 /*****************************************************************************
747 * FlushComm16 (USER.215)
749 INT16 WINAPI FlushComm16(INT16 cid,INT16 fnQueue)
752 struct DosDeviceStruct *ptr;
754 TRACE("cid=%d, queue=%d\n", cid, fnQueue);
755 if ((ptr = GetDeviceStruct(cid)) == NULL) {
756 FIXME("no cid=%d found!\n", cid);
762 ptr->obuf_tail = ptr->obuf_head;
766 ptr->ibuf_head = ptr->ibuf_tail;
769 WARN("(cid=%d,fnQueue=%d):Unknown queue\n",
773 if (tcflush(ptr->fd, queue)) {
774 ptr->commerror = WinError();
782 /********************************************************************
783 * GetCommError16 (USER.203)
785 INT16 WINAPI GetCommError16(INT16 cid,LPCOMSTAT16 lpStat)
788 struct DosDeviceStruct *ptr;
792 if ((ptr = GetDeviceStruct(cid)) == NULL) {
793 FIXME("no handle for cid = %0x!.\n",cid);
797 WARN(" cid %d not comm port\n",cid);
800 stol = (unsigned char *)unknown[cid] + COMM_MSR_OFFSET;
801 ioctl(ptr->fd,TIOCMGET,&mstat);
802 COMM_MSRUpdate( stol, mstat);
807 lpStat->cbOutQue = comm_outbuf(ptr);
808 lpStat->cbInQue = comm_inbuf(ptr);
810 TRACE("cid %d, error %d, lpStat %d %d %d stol %x\n",
811 cid, ptr->commerror, lpStat->status, lpStat->cbInQue,
812 lpStat->cbOutQue, *stol);
815 TRACE("cid %d, error %d, lpStat NULL stol %x\n",
816 cid, ptr->commerror, *stol);
818 /* Return any errors and clear it */
819 temperror = ptr->commerror;
824 /*****************************************************************************
825 * SetCommEventMask16 (USER.208)
827 SEGPTR WINAPI SetCommEventMask16(INT16 cid,UINT16 fuEvtMask)
829 struct DosDeviceStruct *ptr;
834 TRACE("cid %d,mask %d\n",cid,fuEvtMask);
835 if ((ptr = GetDeviceStruct(cid)) == NULL) {
836 FIXME("no handle for cid = %0x!.\n",cid);
840 ptr->eventmask = fuEvtMask;
842 if ((cid&FLAG_LPT) || !ValidCOMPort(cid)) {
843 WARN(" cid %d not comm port\n",cid);
846 /* it's a COM port ? -> modify flags */
847 stol = (unsigned char *)unknown[cid] + COMM_MSR_OFFSET;
848 repid = ioctl(ptr->fd,TIOCMGET,&mstat);
849 TRACE(" ioctl %d, msr %x at %p %p\n",repid,mstat,stol,unknown[cid]);
850 COMM_MSRUpdate( stol, mstat);
852 TRACE(" modem dcd construct %x\n",*stol);
853 return SEGPTR_GET(unknown[cid]);
856 /*****************************************************************************
857 * GetCommEventMask16 (USER.209)
859 UINT16 WINAPI GetCommEventMask16(INT16 cid,UINT16 fnEvtClear)
861 struct DosDeviceStruct *ptr;
864 TRACE("cid %d, mask %d\n", cid, fnEvtClear);
865 if ((ptr = GetDeviceStruct(cid)) == NULL) {
866 FIXME("no handle for cid = %0x!.\n",cid);
870 if ((cid&FLAG_LPT) || !ValidCOMPort(cid)) {
871 WARN(" cid %d not comm port\n",cid);
875 events = *(WORD*)(unknown[cid]) & fnEvtClear;
876 *(WORD*)(unknown[cid]) &= ~fnEvtClear;
880 /*****************************************************************************
881 * SetCommState16 (USER.201)
883 INT16 WINAPI SetCommState16(LPDCB16 lpdcb)
886 struct DosDeviceStruct *ptr;
887 int bytesize, stopbits;
890 TRACE("cid %d, ptr %p\n", lpdcb->Id, lpdcb);
891 if ((ptr = GetDeviceStruct(lpdcb->Id)) == NULL) {
892 FIXME("no handle for cid = %0x!.\n",lpdcb->Id);
895 if (tcgetattr(ptr->fd, &port) == -1) {
896 ptr->commerror = WinError();
901 port.c_cc[VTIME] = 1;
904 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|IMAXBEL);
906 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR);
908 port.c_iflag |= (IGNBRK);
910 port.c_oflag &= ~(OPOST);
912 port.c_cflag &= ~(HUPCL);
913 port.c_cflag |= CLOCAL | CREAD;
915 port.c_lflag &= ~(ICANON|ECHO|ISIG);
916 port.c_lflag |= NOFLSH;
918 TRACE("baudrate %d\n",lpdcb->BaudRate);
920 port.c_cflag &= ~CBAUD;
921 switch (lpdcb->BaudRate) {
924 port.c_cflag |= B110;
928 port.c_cflag |= B300;
932 port.c_cflag |= B600;
936 port.c_cflag |= B1200;
940 port.c_cflag |= B2400;
944 port.c_cflag |= B4800;
948 port.c_cflag |= B9600;
952 port.c_cflag |= B19200;
956 port.c_cflag |= B38400;
960 port.c_cflag |= B57600;
965 port.c_cflag |= B115200;
969 ptr->commerror = IE_BAUDRATE;
972 #elif !defined(__EMX__)
973 switch (lpdcb->BaudRate) {
976 port.c_ospeed = B110;
980 port.c_ospeed = B300;
984 port.c_ospeed = B600;
988 port.c_ospeed = B1200;
992 port.c_ospeed = B2400;
996 port.c_ospeed = B4800;
1000 port.c_ospeed = B9600;
1004 port.c_ospeed = B19200;
1008 port.c_ospeed = B38400;
1011 ptr->commerror = IE_BAUDRATE;
1014 port.c_ispeed = port.c_ospeed;
1016 bytesize=lpdcb->ByteSize;
1017 stopbits=lpdcb->StopBits;
1019 TRACE("fParity %d Parity %d\n",lpdcb->fParity, lpdcb->Parity);
1021 port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
1023 port.c_cflag &= ~(PARENB | PARODD);
1026 port.c_iflag |= INPCK;
1028 port.c_iflag &= ~INPCK;
1029 switch (lpdcb->Parity) {
1033 port.c_cflag |= (PARENB | PARODD);
1036 port.c_cflag |= PARENB;
1039 /* Linux defines mark/space (stick) parity */
1041 port.c_cflag |= (PARENB | CMSPAR);
1044 port.c_cflag |= (PARENB | PARODD | CMSPAR);
1047 /* try the POSIX way */
1049 if( stopbits == ONESTOPBIT) {
1050 stopbits = TWOSTOPBITS;
1051 port.c_iflag &= ~INPCK;
1053 ptr->commerror = IE_BYTESIZE;
1060 port.c_iflag &= ~INPCK;
1062 ptr->commerror = IE_BYTESIZE;
1068 ptr->commerror = IE_BYTESIZE;
1072 TRACE("bytesize %d\n",bytesize);
1073 port.c_cflag &= ~CSIZE;
1076 port.c_cflag |= CS5;
1079 port.c_cflag |= CS6;
1082 port.c_cflag |= CS7;
1085 port.c_cflag |= CS8;
1088 ptr->commerror = IE_BYTESIZE;
1092 TRACE("stopbits %d\n",stopbits);
1096 port.c_cflag &= ~CSTOPB;
1098 case ONE5STOPBITS: /* wil be selected if bytesize is 5 */
1100 port.c_cflag |= CSTOPB;
1103 ptr->commerror = IE_BYTESIZE;
1108 if (lpdcb->fDtrflow || lpdcb->fRtsflow || lpdcb->fOutxCtsFlow)
1109 port.c_cflag |= CRTSCTS;
1111 if (lpdcb->fDtrDisable)
1112 port.c_cflag &= ~CRTSCTS;
1115 port.c_iflag |= IXON;
1117 port.c_iflag &= ~IXON;
1119 port.c_iflag |= IXOFF;
1121 port.c_iflag &= ~IXOFF;
1123 ptr->evtchar = lpdcb->EvtChar;
1128 if (tcsetattr(ptr->fd, TCSADRAIN, &port) == -1) {
1129 ptr->commerror = WinError();
1137 /*****************************************************************************
1138 * GetCommState16 (USER.202)
1140 INT16 WINAPI GetCommState16(INT16 cid, LPDCB16 lpdcb)
1143 struct DosDeviceStruct *ptr;
1144 struct termios port;
1146 TRACE("cid %d, ptr %p\n", cid, lpdcb);
1147 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1148 FIXME("no handle for cid = %0x!.\n",cid);
1151 if (tcgetattr(ptr->fd, &port) == -1) {
1152 ptr->commerror = WinError();
1158 speed = port.c_cflag & CBAUD;
1160 speed = port.c_ospeed;
1164 lpdcb->BaudRate = 110;
1167 lpdcb->BaudRate = 300;
1170 lpdcb->BaudRate = 600;
1173 lpdcb->BaudRate = 1200;
1176 lpdcb->BaudRate = 2400;
1179 lpdcb->BaudRate = 4800;
1182 lpdcb->BaudRate = 9600;
1185 lpdcb->BaudRate = 19200;
1188 lpdcb->BaudRate = 38400;
1192 lpdcb->BaudRate = 57600;
1197 lpdcb->BaudRate = 57601;
1202 switch (port.c_cflag & CSIZE) {
1204 lpdcb->ByteSize = 5;
1207 lpdcb->ByteSize = 6;
1210 lpdcb->ByteSize = 7;
1213 lpdcb->ByteSize = 8;
1217 if(port.c_iflag & INPCK)
1218 lpdcb->fParity = TRUE;
1220 lpdcb->fParity = FALSE;
1222 switch (port.c_cflag & (PARENB | PARODD | CMSPAR))
1224 switch (port.c_cflag & (PARENB | PARODD))
1228 lpdcb->Parity = NOPARITY;
1231 lpdcb->Parity = EVENPARITY;
1233 case (PARENB | PARODD):
1234 lpdcb->Parity = ODDPARITY;
1237 case (PARENB | CMSPAR):
1238 lpdcb->Parity = MARKPARITY;
1240 case (PARENB | PARODD | CMSPAR):
1241 lpdcb->Parity = SPACEPARITY;
1246 if (port.c_cflag & CSTOPB)
1247 if(lpdcb->ByteSize == 5)
1248 lpdcb->StopBits = ONE5STOPBITS;
1250 lpdcb->StopBits = TWOSTOPBITS;
1252 lpdcb->StopBits = ONESTOPBIT;
1254 lpdcb->RlsTimeout = 50;
1255 lpdcb->CtsTimeout = 50;
1256 lpdcb->DsrTimeout = 50;
1260 lpdcb->fDtrDisable = 0;
1264 if (port.c_cflag & CRTSCTS) {
1265 lpdcb->fDtrflow = 1;
1266 lpdcb->fRtsflow = 1;
1267 lpdcb->fOutxCtsFlow = 1;
1268 lpdcb->fOutxDsrFlow = 1;
1271 lpdcb->fDtrDisable = 1;
1273 if (port.c_iflag & IXON)
1278 if (port.c_iflag & IXOFF)
1287 lpdcb->XoffLim = 10;
1289 lpdcb->EvtChar = ptr->evtchar;
1295 /*****************************************************************************
1296 * TransmitCommChar16 (USER.206)
1298 INT16 WINAPI TransmitCommChar16(INT16 cid,CHAR chTransmit)
1300 struct DosDeviceStruct *ptr;
1302 TRACE("cid %d, data %d \n", cid, chTransmit);
1303 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1304 FIXME("no handle for cid = %0x!.\n",cid);
1308 if (ptr->suspended) {
1309 ptr->commerror = IE_HARDWARE;
1313 if (ptr->xmit >= 0) {
1314 /* character already queued */
1315 /* FIXME: which error would Windows return? */
1316 ptr->commerror = CE_TXFULL;
1320 if (ptr->obuf_head == ptr->obuf_tail) {
1321 /* transmit queue empty, try to transmit directly */
1322 if (write(ptr->fd, &chTransmit, 1) == -1) {
1323 /* didn't work, queue it */
1324 ptr->xmit = chTransmit;
1325 comm_waitwrite(ptr);
1328 /* data in queue, let this char be transmitted next */
1329 ptr->xmit = chTransmit;
1330 comm_waitwrite(ptr);
1337 /*****************************************************************************
1338 * UngetCommChar16 (USER.212)
1340 INT16 WINAPI UngetCommChar16(INT16 cid,CHAR chUnget)
1342 struct DosDeviceStruct *ptr;
1344 TRACE("cid %d (char %d)\n", cid, chUnget);
1345 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1346 FIXME("no handle for cid = %0x!.\n",cid);
1350 if (ptr->suspended) {
1351 ptr->commerror = IE_HARDWARE;
1355 if (ptr->unget>=0) {
1356 /* character already queued */
1357 /* FIXME: which error would Windows return? */
1358 ptr->commerror = CE_RXOVER;
1362 ptr->unget = chUnget;
1368 /*****************************************************************************
1369 * ReadComm16 (USER.204)
1371 INT16 WINAPI ReadComm16(INT16 cid,LPSTR lpvBuf,INT16 cbRead)
1374 struct DosDeviceStruct *ptr;
1375 LPSTR orgBuf = lpvBuf;
1377 TRACE("cid %d, ptr %p, length %d\n", cid, lpvBuf, cbRead);
1378 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1379 FIXME("no handle for cid = %0x!.\n",cid);
1383 if (ptr->suspended) {
1384 ptr->commerror = IE_HARDWARE;
1388 /* read unget character */
1389 if (ptr->unget>=0) {
1390 *lpvBuf++ = ptr->unget;
1397 /* read from receive buffer */
1398 while (length < cbRead) {
1399 status = ((ptr->ibuf_head < ptr->ibuf_tail) ?
1400 ptr->ibuf_size : ptr->ibuf_head) - ptr->ibuf_tail;
1402 if ((cbRead - length) < status)
1403 status = cbRead - length;
1405 memcpy(lpvBuf, ptr->inbuf + ptr->ibuf_tail, status);
1406 ptr->ibuf_tail += status;
1407 if (ptr->ibuf_tail >= ptr->ibuf_size)
1413 TRACE("%.*s\n", length, orgBuf);
1418 /*****************************************************************************
1419 * WriteComm16 (USER.205)
1421 INT16 WINAPI WriteComm16(INT16 cid, LPSTR lpvBuf, INT16 cbWrite)
1424 struct DosDeviceStruct *ptr;
1426 TRACE("cid %d, ptr %p, length %d\n",
1427 cid, lpvBuf, cbWrite);
1428 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1429 FIXME("no handle for cid = %0x!.\n",cid);
1433 if (ptr->suspended) {
1434 ptr->commerror = IE_HARDWARE;
1438 TRACE("%.*s\n", cbWrite, lpvBuf );
1441 while (length < cbWrite) {
1442 if ((ptr->obuf_head == ptr->obuf_tail) && (ptr->xmit < 0)) {
1443 /* no data queued, try to write directly */
1444 status = write(ptr->fd, lpvBuf, cbWrite - length);
1451 /* can't write directly, put into transmit buffer */
1452 status = ((ptr->obuf_tail > ptr->obuf_head) ?
1453 (ptr->obuf_tail-1) : ptr->obuf_size) - ptr->obuf_head;
1455 if ((cbWrite - length) < status)
1456 status = cbWrite - length;
1457 memcpy(lpvBuf, ptr->outbuf + ptr->obuf_head, status);
1458 ptr->obuf_head += status;
1459 if (ptr->obuf_head >= ptr->obuf_size)
1463 comm_waitwrite(ptr);
1470 /***********************************************************************
1471 * EnableCommNotification16 (USER.246)
1473 BOOL16 WINAPI EnableCommNotification16( INT16 cid, HWND16 hwnd,
1474 INT16 cbWriteNotify, INT16 cbOutQueue )
1476 struct DosDeviceStruct *ptr;
1478 TRACE("(%d, %x, %d, %d)\n", cid, hwnd, cbWriteNotify, cbOutQueue);
1479 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1480 FIXME("no handle for cid = %0x!.\n",cid);
1484 ptr->n_read = cbWriteNotify;
1485 ptr->n_write = cbOutQueue;
1490 /**************************************************************************
1491 * BuildCommDCBA (KERNEL32.14)
1493 BOOL WINAPI BuildCommDCBA(LPCSTR device,LPDCB lpdcb)
1495 return BuildCommDCBAndTimeoutsA(device,lpdcb,NULL);
1498 /**************************************************************************
1499 * BuildCommDCBAndTimeoutsA (KERNEL32.15)
1501 BOOL WINAPI BuildCommDCBAndTimeoutsA(LPCSTR device, LPDCB lpdcb,
1502 LPCOMMTIMEOUTS lptimeouts)
1507 TRACE("(%s,%p,%p)\n",device,lpdcb,lptimeouts);
1509 if (!strncasecmp(device,"COM",3)) {
1512 ERR("BUG! COM0 can't exists!.\n");
1515 if (!ValidCOMPort(port))
1517 if (*(device+4)!=':')
1519 temp=(LPSTR)(device+5);
1523 lpdcb->DCBlength = sizeof(DCB);
1524 if (strchr(temp,',')) { /* old style */
1527 char last=temp[strlen(temp)-1];
1529 ret=BuildCommDCB16(device,&dcb16);
1532 lpdcb->BaudRate = dcb16.BaudRate;
1533 lpdcb->ByteSize = dcb16.ByteSize;
1534 lpdcb->fBinary = dcb16.fBinary;
1535 lpdcb->Parity = dcb16.Parity;
1536 lpdcb->fParity = dcb16.fParity;
1537 lpdcb->fNull = dcb16.fNull;
1538 lpdcb->StopBits = dcb16.StopBits;
1541 lpdcb->fOutX = TRUE;
1542 lpdcb->fOutxCtsFlow = FALSE;
1543 lpdcb->fOutxDsrFlow = FALSE;
1544 lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
1545 lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
1546 } else if (last=='p') {
1547 lpdcb->fInX = FALSE;
1548 lpdcb->fOutX = FALSE;
1549 lpdcb->fOutxCtsFlow = TRUE;
1550 lpdcb->fOutxDsrFlow = TRUE;
1551 lpdcb->fDtrControl = DTR_CONTROL_HANDSHAKE;
1552 lpdcb->fRtsControl = RTS_CONTROL_HANDSHAKE;
1554 lpdcb->fInX = FALSE;
1555 lpdcb->fOutX = FALSE;
1556 lpdcb->fOutxCtsFlow = FALSE;
1557 lpdcb->fOutxDsrFlow = FALSE;
1558 lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
1559 lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
1561 lpdcb->XonChar = dcb16.XonChar;
1562 lpdcb->XoffChar = dcb16.XoffChar;
1563 lpdcb->ErrorChar= dcb16.PeChar;
1564 lpdcb->fErrorChar= dcb16.fPeChar;
1565 lpdcb->EofChar = dcb16.EofChar;
1566 lpdcb->EvtChar = dcb16.EvtChar;
1567 lpdcb->XonLim = dcb16.XonLim;
1568 lpdcb->XoffLim = dcb16.XoffLim;
1571 ptr=strtok(temp," ");
1576 if (!strncmp("baud=",ptr,5)) {
1577 if (!sscanf(ptr+5,"%ld",&x))
1578 WARN("Couldn't parse %s\n",ptr);
1579 lpdcb->BaudRate = x;
1582 if (!strncmp("stop=",ptr,5)) {
1583 if (!sscanf(ptr+5,"%ld",&x))
1584 WARN("Couldn't parse %s\n",ptr);
1585 lpdcb->StopBits = x;
1588 if (!strncmp("data=",ptr,5)) {
1589 if (!sscanf(ptr+5,"%ld",&x))
1590 WARN("Couldn't parse %s\n",ptr);
1591 lpdcb->ByteSize = x;
1594 if (!strncmp("parity=",ptr,7)) {
1595 lpdcb->fParity = TRUE;
1598 lpdcb->fParity = FALSE;
1599 lpdcb->Parity = NOPARITY;
1602 lpdcb->Parity = EVENPARITY;
1605 lpdcb->Parity = ODDPARITY;
1608 lpdcb->Parity = MARKPARITY;
1614 ERR("Unhandled specifier '%s', please report.\n",ptr);
1615 ptr=strtok(NULL," ");
1617 if (lpdcb->BaudRate==110)
1618 lpdcb->StopBits = 2;
1622 /**************************************************************************
1623 * BuildCommDCBAndTimeoutsW (KERNEL32.16)
1625 BOOL WINAPI BuildCommDCBAndTimeoutsW( LPCWSTR devid, LPDCB lpdcb,
1626 LPCOMMTIMEOUTS lptimeouts )
1631 TRACE("(%p,%p,%p)\n",devid,lpdcb,lptimeouts);
1632 devidA = HEAP_strdupWtoA( GetProcessHeap(), 0, devid );
1633 ret=BuildCommDCBAndTimeoutsA(devidA,lpdcb,lptimeouts);
1634 HeapFree( GetProcessHeap(), 0, devidA );
1638 /**************************************************************************
1639 * BuildCommDCBW (KERNEL32.17)
1641 BOOL WINAPI BuildCommDCBW(LPCWSTR devid,LPDCB lpdcb)
1643 return BuildCommDCBAndTimeoutsW(devid,lpdcb,NULL);
1646 /* FIXME: having these global for win32 for now */
1649 /*****************************************************************************
1650 * SetCommBreak (KERNEL32.449)
1652 BOOL WINAPI SetCommBreak(HANDLE handle)
1654 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1657 fd = FILE_GetUnixHandle( handle, GENERIC_WRITE );
1659 TRACE("FILE_GetUnixHandle failed\n");
1662 result = ioctl(fd,TIOCSBRK,0);
1666 TRACE("ioctl failed\n");
1667 SetLastError(ERROR_NOT_SUPPORTED);
1672 FIXME("ioctl not available\n");
1673 SetLastError(ERROR_NOT_SUPPORTED);
1678 /*****************************************************************************
1679 * ClearCommBreak (KERNEL32.20)
1681 BOOL WINAPI ClearCommBreak(HANDLE handle)
1683 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
1686 fd = FILE_GetUnixHandle( handle, GENERIC_WRITE );
1688 TRACE("FILE_GetUnixHandle failed\n");
1691 result = ioctl(fd,TIOCCBRK,0);
1695 TRACE("ioctl failed\n");
1696 SetLastError(ERROR_NOT_SUPPORTED);
1701 FIXME("ioctl not available\n");
1702 SetLastError(ERROR_NOT_SUPPORTED);
1707 /*****************************************************************************
1708 * EscapeCommFunction (KERNEL32.214)
1710 BOOL WINAPI EscapeCommFunction(HANDLE handle,UINT nFunction)
1712 int fd,direct=FALSE,result=FALSE;
1713 struct termios port;
1715 TRACE("handle %d, function=%d\n", handle, nFunction);
1716 fd = FILE_GetUnixHandle( handle, GENERIC_WRITE );
1718 FIXME("handle %d not found.\n",handle);
1722 if (tcgetattr(fd,&port) == -1) {
1723 commerror=WinError();
1728 switch (nFunction) {
1737 result= COMM_WhackModem(fd, ~TIOCM_DTR, 0);
1745 result= COMM_WhackModem(fd, ~TIOCM_RTS, 0);
1753 result= COMM_WhackModem(fd, 0, TIOCM_DTR);
1761 result= COMM_WhackModem(fd, 0, TIOCM_RTS);
1767 port.c_iflag |= IXOFF;
1772 port.c_iflag |= IXON;
1775 TRACE("setbreak\n");
1778 result = ioctl(fd,TIOCSBRK,0);
1782 TRACE("clrbreak\n");
1785 result = ioctl(fd,TIOCCBRK,0);
1789 WARN("(handle=%d,nFunction=%d): Unknown function\n",
1795 if (tcsetattr(fd, TCSADRAIN, &port) == -1) {
1796 commerror = WinError();
1806 commerror=WinError();
1815 /********************************************************************
1816 * PurgeComm (KERNEL32.557)
1818 BOOL WINAPI PurgeComm( HANDLE handle, DWORD flags)
1822 TRACE("handle %d, flags %lx\n", handle, flags);
1824 fd = FILE_GetUnixHandle( handle, GENERIC_WRITE );
1826 FIXME("no handle %d found\n",handle);
1831 ** not exactly sure how these are different
1832 ** Perhaps if we had our own internal queues, one flushes them
1833 ** and the other flushes the kernel's buffers.
1835 if(flags&PURGE_TXABORT)
1836 tcflush(fd,TCOFLUSH);
1837 if(flags&PURGE_RXABORT)
1838 tcflush(fd,TCIFLUSH);
1839 if(flags&PURGE_TXCLEAR)
1840 tcflush(fd,TCOFLUSH);
1841 if(flags&PURGE_RXCLEAR)
1842 tcflush(fd,TCIFLUSH);
1848 /*****************************************************************************
1849 * ClearCommError (KERNEL32.21)
1851 BOOL WINAPI ClearCommError(HANDLE handle,LPDWORD errors,LPCOMSTAT lpStat)
1855 fd=FILE_GetUnixHandle( handle, GENERIC_READ );
1858 FIXME("no handle %d found\n",handle);
1867 if(ioctl(fd, TIOCOUTQ, &lpStat->cbOutQue))
1868 WARN("ioctl returned error\n");
1870 lpStat->cbOutQue = 0; /* FIXME: find a different way to find out */
1874 if(ioctl(fd, TIOCINQ, &lpStat->cbInQue))
1875 WARN("ioctl returned error\n");
1878 TRACE("handle %d cbInQue = %ld cbOutQue = %ld\n",
1879 handle, lpStat->cbInQue, lpStat->cbOutQue);
1888 ** After an asynchronous write opperation, the
1889 ** app will call ClearCommError to see if the
1890 ** results are ready yet. It waits for ERROR_IO_PENDING
1892 commerror = ERROR_IO_PENDING;
1897 /*****************************************************************************
1898 * SetupComm (KERNEL32.676)
1900 BOOL WINAPI SetupComm( HANDLE handle, DWORD insize, DWORD outsize)
1904 FIXME("insize %ld outsize %ld unimplemented stub\n", insize, outsize);
1905 fd=FILE_GetUnixHandle( handle, GENERIC_WRITE );
1907 FIXME("handle %d not found?\n",handle);
1914 /*****************************************************************************
1915 * GetCommMask (KERNEL32.156)
1917 BOOL WINAPI GetCommMask(HANDLE handle,LPDWORD evtmask)
1921 TRACE("handle %d, mask %p\n", handle, evtmask);
1925 struct get_serial_info_request *req = server_alloc_req( sizeof(*req), 0 );
1926 req->handle = handle;
1927 if ((ret = !server_call( REQ_GET_SERIAL_INFO )))
1929 if (evtmask) *evtmask = req->eventmask;
1936 /*****************************************************************************
1937 * SetCommMask (KERNEL32.451)
1939 BOOL WINAPI SetCommMask(HANDLE handle,DWORD evtmask)
1943 TRACE("handle %d, mask %lx\n", handle, evtmask);
1947 struct set_serial_info_request *req = server_alloc_req( sizeof(*req), 0 );
1948 req->handle = handle;
1949 req->flags = SERIALINFO_SET_MASK;
1950 req->eventmask = evtmask;
1951 ret = !server_call( REQ_SET_SERIAL_INFO );
1957 /*****************************************************************************
1958 * SetCommState (KERNEL32.452)
1960 BOOL WINAPI SetCommState(HANDLE handle,LPDCB lpdcb)
1962 struct termios port;
1964 int bytesize, stopbits;
1966 TRACE("handle %d, ptr %p\n", handle, lpdcb);
1967 TRACE("bytesize %d baudrate %ld fParity %d Parity %d stopbits %d\n",
1968 lpdcb->ByteSize,lpdcb->BaudRate,lpdcb->fParity, lpdcb->Parity,
1969 (lpdcb->StopBits == ONESTOPBIT)?1:
1970 (lpdcb->StopBits == TWOSTOPBITS)?2:0);
1971 TRACE("%s %s\n",(lpdcb->fInX)?"IXON":"~IXON",
1972 (lpdcb->fOutX)?"IXOFF":"~IXOFF");
1974 fd = FILE_GetUnixHandle( handle, GENERIC_WRITE );
1976 FIXME("no handle %d found\n",handle);
1980 if ((tcgetattr(fd,&port)) == -1) {
1981 int save_error = errno;
1982 commerror = WinError();
1984 ERR("tcgetattr error '%s'\n", strerror(save_error));
1988 port.c_cc[VMIN] = 0;
1989 port.c_cc[VTIME] = 1;
1992 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|IMAXBEL);
1994 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR);
1996 port.c_iflag |= (IGNBRK);
1998 port.c_oflag &= ~(OPOST);
2000 port.c_cflag &= ~(HUPCL);
2001 port.c_cflag |= CLOCAL | CREAD;
2003 port.c_lflag &= ~(ICANON|ECHO|ISIG);
2004 port.c_lflag |= NOFLSH;
2007 ** MJM - removed default baudrate settings
2008 ** TRACE(comm,"baudrate %ld\n",lpdcb->BaudRate);
2011 port.c_cflag &= ~CBAUD;
2012 switch (lpdcb->BaudRate) {
2015 port.c_cflag |= B110;
2019 port.c_cflag |= B300;
2023 port.c_cflag |= B600;
2027 port.c_cflag |= B1200;
2031 port.c_cflag |= B2400;
2035 port.c_cflag |= B4800;
2039 port.c_cflag |= B9600;
2043 port.c_cflag |= B19200;
2047 port.c_cflag |= B38400;
2051 port.c_cflag |= B57600;
2056 port.c_cflag |= B115200;
2061 port.c_cflag |= B230400;
2066 port.c_cflag |= B460800;
2070 commerror = IE_BAUDRATE;
2072 ERR("baudrate %ld\n",lpdcb->BaudRate);
2075 #elif !defined(__EMX__)
2076 switch (lpdcb->BaudRate) {
2079 port.c_ospeed = B110;
2083 port.c_ospeed = B300;
2087 port.c_ospeed = B600;
2091 port.c_ospeed = B1200;
2095 port.c_ospeed = B2400;
2099 port.c_ospeed = B4800;
2103 port.c_ospeed = B9600;
2107 port.c_ospeed = B19200;
2111 port.c_ospeed = B38400;
2114 commerror = IE_BAUDRATE;
2116 ERR("baudrate %ld\n",lpdcb->BaudRate);
2119 port.c_ispeed = port.c_ospeed;
2121 bytesize=lpdcb->ByteSize;
2122 stopbits=lpdcb->StopBits;
2125 port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
2127 port.c_cflag &= ~(PARENB | PARODD);
2130 port.c_iflag |= INPCK;
2132 port.c_iflag &= ~INPCK;
2133 switch (lpdcb->Parity) {
2137 port.c_cflag |= (PARENB | PARODD);
2140 port.c_cflag |= PARENB;
2143 /* Linux defines mark/space (stick) parity */
2145 port.c_cflag |= (PARENB | CMSPAR);
2148 port.c_cflag |= (PARENB | PARODD | CMSPAR);
2151 /* try the POSIX way */
2153 if( stopbits == ONESTOPBIT) {
2154 stopbits = TWOSTOPBITS;
2155 port.c_iflag &= ~INPCK;
2157 commerror = IE_BYTESIZE;
2159 ERR("Cannot set MARK Parity\n");
2166 port.c_iflag &= ~INPCK;
2168 commerror = IE_BYTESIZE;
2170 ERR("Cannot set SPACE Parity\n");
2176 commerror = IE_BYTESIZE;
2183 port.c_cflag &= ~CSIZE;
2186 port.c_cflag |= CS5;
2189 port.c_cflag |= CS6;
2192 port.c_cflag |= CS7;
2195 port.c_cflag |= CS8;
2198 commerror = IE_BYTESIZE;
2206 port.c_cflag &= ~CSTOPB;
2208 case ONE5STOPBITS: /* wil be selected if bytesize is 5 */
2210 port.c_cflag |= CSTOPB;
2213 commerror = IE_BYTESIZE;
2219 if ( lpdcb->fOutxCtsFlow ||
2220 lpdcb->fDtrControl == DTR_CONTROL_ENABLE||
2221 lpdcb->fRtsControl == RTS_CONTROL_ENABLE
2224 port.c_cflag |= CRTSCTS;
2228 if (lpdcb->fDtrControl == DTR_CONTROL_DISABLE)
2230 port.c_cflag &= ~CRTSCTS;
2231 TRACE("~CRTSCTS\n");
2236 port.c_iflag |= IXON;
2238 port.c_iflag &= ~IXON;
2240 port.c_iflag |= IXOFF;
2242 port.c_iflag &= ~IXOFF;
2244 if (tcsetattr(fd,TCSANOW,&port)==-1) { /* otherwise it hangs with pending input*/
2245 int save_error=errno;
2246 commerror = WinError();
2248 ERR("tcgetattr error '%s'\n", strerror(save_error));
2258 /*****************************************************************************
2259 * GetCommState (KERNEL32.159)
2261 BOOL WINAPI GetCommState(HANDLE handle, LPDCB lpdcb)
2263 struct termios port;
2266 TRACE("handle %d, ptr %p\n", handle, lpdcb);
2268 fd = FILE_GetUnixHandle( handle, GENERIC_READ );
2271 ERR("FILE_GetUnixHandle failed\n");
2274 if (tcgetattr(fd, &port) == -1) {
2275 int save_error=errno;
2276 ERR("tcgetattr error '%s'\n", strerror(save_error));
2277 commerror = WinError();
2284 speed= (port.c_cflag & CBAUD);
2286 speed= (cfgetospeed(&port));
2290 lpdcb->BaudRate = 110;
2293 lpdcb->BaudRate = 300;
2296 lpdcb->BaudRate = 600;
2299 lpdcb->BaudRate = 1200;
2302 lpdcb->BaudRate = 2400;
2305 lpdcb->BaudRate = 4800;
2308 lpdcb->BaudRate = 9600;
2311 lpdcb->BaudRate = 19200;
2314 lpdcb->BaudRate = 38400;
2318 lpdcb->BaudRate = 57600;
2323 lpdcb->BaudRate = 115200;
2328 lpdcb->BaudRate = 230400;
2333 lpdcb->BaudRate = 460800;
2337 ERR("unknown speed %x \n",speed);
2340 switch (port.c_cflag & CSIZE) {
2342 lpdcb->ByteSize = 5;
2345 lpdcb->ByteSize = 6;
2348 lpdcb->ByteSize = 7;
2351 lpdcb->ByteSize = 8;
2354 ERR("unknown size %x \n",port.c_cflag & CSIZE);
2357 if(port.c_iflag & INPCK)
2358 lpdcb->fParity = TRUE;
2360 lpdcb->fParity = FALSE;
2362 switch (port.c_cflag & (PARENB | PARODD | CMSPAR))
2364 switch (port.c_cflag & (PARENB | PARODD))
2368 lpdcb->Parity = NOPARITY;
2371 lpdcb->Parity = EVENPARITY;
2373 case (PARENB | PARODD):
2374 lpdcb->Parity = ODDPARITY;
2377 case (PARENB | CMSPAR):
2378 lpdcb->Parity = MARKPARITY;
2380 case (PARENB | PARODD | CMSPAR):
2381 lpdcb->Parity = SPACEPARITY;
2386 if (port.c_cflag & CSTOPB)
2387 if(lpdcb->ByteSize == 5)
2388 lpdcb->StopBits = ONE5STOPBITS;
2390 lpdcb->StopBits = TWOSTOPBITS;
2392 lpdcb->StopBits = ONESTOPBIT;
2399 if (port.c_cflag & CRTSCTS) {
2400 lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
2401 lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
2402 lpdcb->fOutxCtsFlow = 1;
2403 lpdcb->fOutxDsrFlow = 1;
2407 lpdcb->fDtrControl = DTR_CONTROL_DISABLE;
2408 lpdcb->fRtsControl = RTS_CONTROL_DISABLE;
2410 if (port.c_iflag & IXON)
2415 if (port.c_iflag & IXOFF)
2424 lpdcb->XoffLim = 10;
2430 TRACE("bytesize %d baudrate %ld fParity %d Parity %d stopbits %d\n",
2431 lpdcb->ByteSize,lpdcb->BaudRate,lpdcb->fParity, lpdcb->Parity,
2432 (lpdcb->StopBits == ONESTOPBIT)?1:
2433 (lpdcb->StopBits == TWOSTOPBITS)?2:0);
2434 TRACE("%s %s\n",(lpdcb->fInX)?"IXON":"~IXON",
2435 (lpdcb->fOutX)?"IXOFF":"~IXOFF");
2437 if ( lpdcb->fOutxCtsFlow ||
2438 lpdcb->fDtrControl == DTR_CONTROL_ENABLE||
2439 lpdcb->fRtsControl == RTS_CONTROL_ENABLE
2443 if (lpdcb->fDtrControl == DTR_CONTROL_DISABLE)
2444 TRACE("~CRTSCTS\n");
2450 /*****************************************************************************
2451 * TransmitCommChar (KERNEL32.535)
2453 BOOL WINAPI TransmitCommChar(HANDLE hComm,CHAR chTransmit)
2455 FIXME("(%x,'%c'), use win32 handle!\n",hComm,chTransmit);
2459 /*****************************************************************************
2460 * GetCommTimeouts (KERNEL32.160)
2462 BOOL WINAPI GetCommTimeouts(HANDLE hComm,LPCOMMTIMEOUTS lptimeouts)
2466 TRACE("(%x,%p)\n",hComm,lptimeouts);
2470 SetLastError(ERROR_INVALID_PARAMETER);
2476 struct get_serial_info_request *req = server_alloc_req( sizeof(*req), 0 );
2477 req->handle = hComm;
2478 if ((ret = !server_call( REQ_GET_SERIAL_INFO )))
2480 lptimeouts->ReadIntervalTimeout = req->readinterval;
2481 lptimeouts->ReadTotalTimeoutMultiplier = req->readmult;
2482 lptimeouts->ReadTotalTimeoutConstant = req->readconst;
2483 lptimeouts->WriteTotalTimeoutMultiplier = req->writemult;
2484 lptimeouts->WriteTotalTimeoutConstant = req->writeconst;
2491 /*****************************************************************************
2492 * SetCommTimeouts (KERNEL32.453)
2494 * Sets the timeouts used when reading and writing data to/from COMM ports.
2496 * ReadIntervalTimeout
2497 * - converted and passes to linux kernel as c_cc[VTIME]
2498 * ReadTotalTimeoutMultiplier, ReadTotalTimeoutConstant
2499 * - used in ReadFile to calculate GetOverlappedResult's timeout
2500 * WriteTotalTimeoutMultiplier, WriteTotalTimeoutConstant
2501 * - used in WriteFile to calculate GetOverlappedResult's timeout
2503 BOOL WINAPI SetCommTimeouts(
2504 HANDLE hComm, /* [I] handle of COMM device */
2505 LPCOMMTIMEOUTS lptimeouts /* [I] pointer to COMMTIMEOUTS structure */
2509 struct termios tios;
2511 TRACE("(%x,%p)\n",hComm,lptimeouts);
2515 SetLastError(ERROR_INVALID_PARAMETER);
2521 struct set_serial_info_request *req = server_alloc_req( sizeof(*req), 0 );
2522 req->handle = hComm;
2523 req->flags = SERIALINFO_SET_TIMEOUTS;
2524 req->readinterval = lptimeouts->ReadIntervalTimeout ;
2525 req->readmult = lptimeouts->ReadTotalTimeoutMultiplier ;
2526 req->readconst = lptimeouts->ReadTotalTimeoutConstant ;
2527 req->writemult = lptimeouts->WriteTotalTimeoutMultiplier ;
2528 req->writeconst = lptimeouts->WriteTotalTimeoutConstant ;
2529 ret = !server_call( REQ_SET_SERIAL_INFO );
2532 if (!ret) return FALSE;
2534 /* FIXME: move this stuff to the server */
2535 fd = FILE_GetUnixHandle( hComm, GENERIC_WRITE );
2537 FIXME("no fd for handle = %0x!.\n",hComm);
2541 if (-1==tcgetattr(fd,&tios)) {
2542 FIXME("tcgetattr on fd %d failed!\n",fd);
2545 /* VTIME is in 1/10 seconds */
2546 tios.c_cc[VTIME]= (lptimeouts->ReadIntervalTimeout+99)/100;
2547 if (-1==tcsetattr(fd,0,&tios)) {
2548 FIXME("tcsetattr on fd %d failed!\n",fd);
2555 /***********************************************************************
2556 * GetCommModemStatus (KERNEL32.285)
2558 BOOL WINAPI GetCommModemStatus(HANDLE hFile,LPDWORD lpModemStat )
2560 int fd,mstat, result=FALSE;
2564 fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
2567 result = ioctl(fd, TIOCMGET, &mstat);
2571 TRACE("ioctl failed\n");
2575 if (mstat & TIOCM_CTS)
2576 *lpModemStat |= MS_CTS_ON;
2579 if (mstat & TIOCM_DSR)
2580 *lpModemStat |= MS_DSR_ON;
2583 if (mstat & TIOCM_RNG)
2584 *lpModemStat |= MS_RING_ON;
2587 /*FIXME: Not really sure about RLSD UB 990810*/
2588 if (mstat & TIOCM_CAR)
2589 *lpModemStat |= MS_RLSD_ON;
2592 (*lpModemStat &MS_RLSD_ON)?"MS_RLSD_ON ":"",
2593 (*lpModemStat &MS_RING_ON)?"MS_RING_ON ":"",
2594 (*lpModemStat &MS_DSR_ON)?"MS_DSR_ON ":"",
2595 (*lpModemStat &MS_CTS_ON)?"MS_CTS_ON ":"");
2602 VOID COMM_WaitCommEventService(void **args)
2604 LPOVERLAPPED lpOverlapped = (LPOVERLAPPED)args[0];
2605 LPDWORD buffer = (LPDWORD)args[1];
2606 DWORD events = (DWORD)args[2];
2608 TRACE("overlapped %p wait complete %p <- %lx\n",lpOverlapped,buffer,events);
2612 SetEvent( lpOverlapped->hEvent);
2615 /***********************************************************************
2616 * WaitCommEvent (KERNEL32.719)
2618 * Wait until something interesting happens on a COMM port.
2619 * Interesting things (events) are set by calling SetCommMask before
2620 * this function is called.
2623 * TRUE if successful
2626 * The set of detected events will be written to *lpdwEventMask
2627 * ERROR_IO_PENDING will be returned the overlapped structure was passed
2630 * Only supports EV_RXCHAR and EV_TXEMPTY
2632 BOOL WINAPI WaitCommEvent(
2633 HANDLE hFile, /* [I] handle of comm port to wait for */
2634 LPDWORD lpdwEvents, /* [O] event(s) that were detected */
2635 LPOVERLAPPED lpOverlapped /* [I/O] for Asynchronous waiting */
2641 TRACE("(%x %p %p )\n",hFile, lpdwEvents,lpOverlapped);
2643 /* if there is no overlapped structure, create our own */
2646 ov.hEvent = CreateEventA(NULL,FALSE,FALSE,NULL);
2650 lpov = lpOverlapped;
2652 /* check that the overlapped structure has a valid event flag */
2653 if ( (lpov->hEvent==0) || (lpov->hEvent == INVALID_HANDLE_VALUE) )
2655 ERR("Couldn't create Event flag for Overlapped structure\n");
2656 SetLastError(ERROR_INVALID_PARAMETER);
2661 lpov->InternalHigh = hFile;
2663 lpov->OffsetHigh = 0;
2665 /* start an ASYNCHRONOUS WaitCommEvent */
2668 struct create_async_request *req = server_alloc_req( sizeof(*req), 0 );
2670 req->file_handle = hFile;
2671 req->overlapped = lpov;
2672 req->buffer = lpdwEvents;
2674 req->func = COMM_WaitCommEventService;
2675 req->type = ASYNC_TYPE_WAIT;
2677 ret=server_call( REQ_CREATE_ASYNC );
2679 lpov->Internal = req->ov_handle;
2686 CloseHandle(lpov->hEvent);
2687 TRACE("server call failed.\n");
2691 /* wait ourselves if the caller didn't give us an overlapped struct */
2694 GetOverlappedResult(hFile, lpov, NULL, TRUE);
2695 CloseHandle(lpov->hEvent);
2700 /* caller wants overlapped I/O using GetOverlapped result */
2701 SetLastError(ERROR_IO_PENDING);
2708 /***********************************************************************
2709 * GetCommProperties (KERNEL32.286)
2711 * This function fills in a structure with the capabilities of the
2712 * communications port driver.
2716 * TRUE on success, FALSE on failure
2717 * If successful, the lpCommProp structure be filled in with
2718 * properties of the comm port.
2720 BOOL WINAPI GetCommProperties(
2721 HANDLE hFile, /* handle of the comm port */
2722 LPCOMMPROP lpCommProp /* pointer to struct to be filled */
2724 FIXME("(%d %p )\n",hFile,lpCommProp);
2729 * These values should be valid for LINUX's serial driver
2730 * FIXME: Perhaps they deserve an #ifdef LINUX
2732 memset(lpCommProp,0,sizeof(COMMPROP));
2733 lpCommProp->wPacketLength = 1;
2734 lpCommProp->wPacketVersion = 1;
2735 lpCommProp->dwServiceMask = SP_SERIALCOMM;
2736 lpCommProp->dwReserved1 = 0;
2737 lpCommProp->dwMaxTxQueue = 4096;
2738 lpCommProp->dwMaxRxQueue = 4096;
2739 lpCommProp->dwMaxBaud = BAUD_115200;
2740 lpCommProp->dwProvSubType = PST_RS232;
2741 lpCommProp->dwProvCapabilities = PCF_DTRDSR | PCF_PARITY_CHECK | PCF_RTSCTS ;
2742 lpCommProp->dwSettableParams = SP_BAUD | SP_DATABITS | SP_HANDSHAKING |
2743 SP_PARITY | SP_PARITY_CHECK | SP_STOPBITS ;
2744 lpCommProp->dwSettableBaud = BAUD_075 | BAUD_110 | BAUD_134_5 | BAUD_150 |
2745 BAUD_300 | BAUD_600 | BAUD_1200 | BAUD_1800 | BAUD_2400 | BAUD_4800 |
2746 BAUD_9600 | BAUD_19200 | BAUD_38400 | BAUD_57600 | BAUD_115200 ;
2747 lpCommProp->wSettableData = DATABITS_5 | DATABITS_6 | DATABITS_7 | DATABITS_8 ;
2748 lpCommProp->wSettableStopParity = STOPBITS_10 | STOPBITS_15 | STOPBITS_20 |
2749 PARITY_NONE | PARITY_ODD |PARITY_EVEN | PARITY_MARK | PARITY_SPACE;
2750 lpCommProp->dwCurrentTxQueue = lpCommProp->dwMaxTxQueue;
2751 lpCommProp->dwCurrentRxQueue = lpCommProp->dwMaxRxQueue;
2756 /***********************************************************************
2758 * The functionality of CommConfigDialogA, GetDefaultCommConfig and
2759 * SetDefaultCommConfig is implemented in a DLL (usually SERIALUI.DLL).
2760 * This is dependent on the type of COMM port, but since it is doubtful
2761 * anybody will get around to implementing support for fancy serial
2762 * ports in WINE, this is hardcoded for the time being. The name of
2763 * this DLL should be stored in and read from the system registry in
2764 * the hive HKEY_LOCAL_MACHINE, key
2765 * System\\CurrentControlSet\\Services\\Class\\Ports\\????
2766 * where ???? is the port number... that is determined by PNP
2767 * The DLL should be loaded when the COMM port is opened, and closed
2768 * when the COMM port is closed. - MJM 20 June 2000
2769 ***********************************************************************/
2770 static CHAR lpszSerialUI[] = "serialui.dll";
2773 /***********************************************************************
2774 * CommConfigDialogA (KERNEL32.140)
2776 * Raises a dialog that allows the user to configure a comm port.
2777 * Fills the COMMCONFIG struct with information specified by the user.
2778 * This function should call a similar routine in the COMM driver...
2782 * TRUE on success, FALSE on failure
2783 * If successful, the lpCommConfig structure will contain a new
2784 * configuration for the comm port, as specified by the user.
2787 * The library with the CommConfigDialog code is never unloaded.
2788 * Perhaps this should be done when the comm port is closed?
2790 BOOL WINAPI CommConfigDialogA(
2791 LPCSTR lpszDevice, /* name of communications device */
2792 HANDLE hWnd, /* parent window for the dialog */
2793 LPCOMMCONFIG lpCommConfig /* pointer to struct to fill */
2795 FARPROC lpfnCommDialog;
2796 HMODULE hConfigModule;
2799 TRACE("(%p %x %p)\n",lpszDevice, hWnd, lpCommConfig);
2801 hConfigModule = LoadLibraryA(lpszSerialUI);
2805 lpfnCommDialog = GetProcAddress(hConfigModule, (LPCSTR)3L);
2810 r = lpfnCommDialog(lpszDevice,hWnd,lpCommConfig);
2812 /* UnloadLibrary(hConfigModule); */
2817 /***********************************************************************
2818 * CommConfigDialogW (KERNEL32.141)
2820 * see CommConfigDialogA for more info
2822 BOOL WINAPI CommConfigDialogW(
2823 LPCWSTR lpszDevice, /* name of communications device */
2824 HANDLE hWnd, /* parent window for the dialog */
2825 LPCOMMCONFIG lpCommConfig /* pointer to struct to fill */
2830 lpDeviceA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpszDevice );
2833 r = CommConfigDialogA(lpDeviceA,hWnd,lpCommConfig);
2834 HeapFree( GetProcessHeap(), 0, lpDeviceA );
2838 /***********************************************************************
2839 * GetCommConfig (KERNEL32.283)
2841 * Fill in the COMMCONFIG structure for the comm port hFile
2845 * TRUE on success, FALSE on failure
2846 * If successful, lpCommConfig contains the comm port configuration.
2848 BOOL WINAPI GetCommConfig(
2850 LPCOMMCONFIG lpCommConfig
2854 TRACE("(%x %p)\n",hFile,lpCommConfig);
2856 if(lpCommConfig == NULL)
2859 lpCommConfig->dwSize = sizeof(COMMCONFIG);
2860 lpCommConfig->wVersion = 1;
2861 lpCommConfig->wReserved = 0;
2862 r = GetCommState(hFile,&lpCommConfig->dcb);
2863 lpCommConfig->dwProviderSubType = PST_RS232;
2864 lpCommConfig->dwProviderOffset = 0;
2865 lpCommConfig->dwProviderSize = 0;
2870 /***********************************************************************
2871 * SetCommConfig (KERNEL32.617)
2874 BOOL WINAPI SetCommConfig(
2876 LPCOMMCONFIG lpCommConfig
2880 TRACE("(%x %p)\n",hFile,lpCommConfig);
2882 r = SetCommState(hFile,&lpCommConfig->dcb);
2886 /***********************************************************************
2887 * SetDefaultCommConfigA (KERNEL32.638)
2889 BOOL WINAPI SetDefaultCommConfigA(
2891 LPCOMMCONFIG lpCommConfig,
2894 FARPROC lpfnSetDefaultCommConfig;
2895 HMODULE hConfigModule;
2898 TRACE("(%p %p %lx)\n",lpszDevice, lpCommConfig, dwSize);
2900 hConfigModule = LoadLibraryA(lpszSerialUI);
2904 lpfnSetDefaultCommConfig = GetProcAddress(hConfigModule, (LPCSTR)4L);
2906 if(! lpfnSetDefaultCommConfig)
2909 r = lpfnSetDefaultCommConfig(lpszDevice, lpCommConfig, dwSize);
2911 /* UnloadLibrary(hConfigModule); */
2917 /***********************************************************************
2918 * SetDefaultCommConfigW (KERNEL32.639)
2921 BOOL WINAPI SetDefaultCommConfigW(
2923 LPCOMMCONFIG lpCommConfig,
2929 TRACE("(%s %p %lx)\n",debugstr_w(lpszDevice),lpCommConfig,dwSize);
2931 lpDeviceA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpszDevice );
2934 r = SetDefaultCommConfigA(lpDeviceA,lpCommConfig,dwSize);
2935 HeapFree( GetProcessHeap(), 0, lpDeviceA );
2940 /***********************************************************************
2941 * GetDefaultCommConfigA (KERNEL32.313)
2943 BOOL WINAPI GetDefaultCommConfigA(LPCSTR lpszName,LPCOMMCONFIG lpCC,
2946 LPDCB lpdcb = &(lpCC->dcb);
2949 if (strncasecmp(lpszName,"COM",3)) {
2950 ERR("not implemented for <%s>\n", lpszName);
2954 if (!ValidCOMPort(lpszName[3]-'1'))
2957 TRACE("(%s %p %ld)\n", lpszName, lpCC, *lpdwSize );
2958 if (*lpdwSize < sizeof(COMMCONFIG)) {
2959 *lpdwSize = sizeof(COMMCONFIG);
2963 *lpdwSize = sizeof(COMMCONFIG);
2965 lpCC->dwSize = sizeof(COMMCONFIG);
2967 lpCC->dwProviderSubType = PST_RS232;
2968 lpCC->dwProviderOffset = 0L;
2969 lpCC->dwProviderSize = 0L;
2971 (void) sprintf( temp, "COM%c:38400,n,8,1", lpszName[3]);
2972 FIXME("setting %s as default\n", temp);
2974 return BuildCommDCBA( temp, lpdcb);
2977 /**************************************************************************
2978 * GetDefaultCommConfigW (KERNEL32.314)
2980 BOOL WINAPI GetDefaultCommConfigW( LPCWSTR lpszName,LPCOMMCONFIG lpCC,
2986 TRACE("(%p,%p,%ld)\n",lpszName,lpCC,*lpdwSize);
2987 lpszNameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpszName );
2988 ret=GetDefaultCommConfigA(lpszNameA,lpCC,lpdwSize);
2989 HeapFree( GetProcessHeap(), 0, lpszNameA );