Release 980913
[wine/wine-kai.git] / misc / comm.c
blobf0bcc0f8c496aabc4ba9d795c0ec5bc03739fe8c
1 /*
2 * DEC 93 Erik Bos <erik@xs4all.nl>
4 * Copyright 1996 Marcus Meissner
5 * FIXME: use HFILEs instead of unixfds
6 * the win32 functions here get HFILEs already.
8 * May 26, 1997. Fixes and comments by Rick Richardson <rick@dgii.com> [RER]
9 * - ptr->fd wasn't getting cleared on close.
10 * - GetCommEventMask() and GetCommError() didn't do much of anything.
11 * IMHO, they are still wrong, but they at least implement the RXCHAR
12 * event and return I/O queue sizes, which makes the app I'm interested
13 * in (analog devices EZKIT DSP development system) work.
15 * August 12, 1997. Take a bash at SetCommEventMask - Lawson Whitney
16 * <lawson_whitney@juno.com>
17 * July 6, 1998. Fixes and comments by Valentijn Sessink
18 * <vsessink@ic.uva.nl> [V]
19 * I only quick-fixed an error for the output buffers. The thing is this: if a
20 * WinApp starts using serial ports, it calls OpenComm, asking it to open two
21 * buffers, cbInQueue and cbOutQueue size, to hold data to/from the serial
22 * ports. Wine OpenComm only returns "OK". Now the kernel buffer size for
23 * serial communication is only 4096 bytes large. Error: (App asks for
24 * a 104,000 bytes size buffer, Wine returns "OK", App asks "How many char's
25 * are in the buffer", Wine returns "4000" and App thinks "OK, another
26 * 100,000 chars left, good!")
27 * The solution below is a bad but working quickfix for the transmit buffer:
28 * the cbInQueue is saved in a variable; when the program asks how many chars
29 * there are in the buffer, GetCommError returns # in buffer PLUS
30 * the additional (cbOutQeueu - 4096), which leaves the application thinking
31 * "wow, almost full".
32 * Sorry for the rather chatty explanation - but I think comm.c needs to be
33 * redefined with real working buffers make it work; maybe these comments are
34 * of help.
37 #include "config.h"
39 #include <stdlib.h>
40 #include <termios.h>
41 #include <fcntl.h>
42 #include <string.h>
43 #ifdef HAVE_STRINGS_H
44 # include <strings.h>
45 #endif
46 #include <errno.h>
47 #include <ctype.h>
48 #include <sys/stat.h>
49 #ifdef HAVE_SYS_FILIO_H
50 # include <sys/filio.h>
51 #endif
52 #include <sys/ioctl.h>
53 #include <unistd.h>
55 #include "windows.h"
56 #include "comm.h"
57 #ifdef HAVE_SYS_MODEM_H
58 # include <sys/modem.h>
59 #endif
60 #ifdef HAVE_SYS_STRTIO_H
61 # include <sys/strtio.h>
62 #endif
63 #include "heap.h"
64 #include "options.h"
65 #include "debug.h"
67 #ifndef TIOCINQ
68 #define TIOCINQ FIONREAD
69 #endif
70 #define msr 35 /* offset in unknown structure commMask */
72 * [RER] These are globals are wrong. They should be in DosDeviceStruct
73 * on a per port basis.
75 int commerror = 0, eventmask = 0;
78 * [V] If above globals are wrong, the one below will be wrong as well. It
79 * should probably be in the DosDeviceStruct on per port basis too.
81 int iGlobalOutQueueFiller;
83 #define SERIAL_XMIT_SIZE 4096
85 struct DosDeviceStruct COM[MAX_PORTS];
86 struct DosDeviceStruct LPT[MAX_PORTS];
87 LPCVOID *unknown[MAX_PORTS];
89 void COMM_Init(void)
91 int x;
92 char option[10], temp[256], *btemp;
93 struct stat st;
95 for (x=0; x!=MAX_PORTS; x++) {
96 strcpy(option,"COMx");
97 option[3] = '1' + x;
98 option[4] = '\0';
100 PROFILE_GetWineIniString( "serialports", option, "*",
101 temp, sizeof(temp) );
102 if (!strcmp(temp, "*") || *temp == '\0')
103 COM[x].devicename = NULL;
104 else {
105 btemp = strchr(temp,',');
106 if (btemp != NULL) {
107 *btemp++ = '\0';
108 COM[x].baudrate = atoi(btemp);
109 } else {
110 COM[x].baudrate = -1;
112 stat(temp, &st);
113 if (!S_ISCHR(st.st_mode))
114 WARN(comm,"Can't use `%s' as %s !\n", temp, option);
115 else
116 if ((COM[x].devicename = malloc(strlen(temp)+1)) == NULL)
117 WARN(comm,"Can't malloc for device info!\n");
118 else {
119 COM[x].fd = 0;
120 strcpy(COM[x].devicename, temp);
122 TRACE(comm, "%s = %s\n", option, COM[x].devicename);
125 strcpy(option, "LPTx");
126 option[3] = '1' + x;
127 option[4] = '\0';
129 PROFILE_GetWineIniString( "parallelports", option, "*",
130 temp, sizeof(temp) );
131 if (!strcmp(temp, "*") || *temp == '\0')
132 LPT[x].devicename = NULL;
133 else {
134 stat(temp, &st);
135 if (!S_ISCHR(st.st_mode))
136 WARN(comm,"Can't use `%s' as %s !\n", temp, option);
137 else
138 if ((LPT[x].devicename = malloc(strlen(temp)+1)) == NULL)
139 WARN(comm,"Can't malloc for device info!\n");
140 else {
141 LPT[x].fd = 0;
142 strcpy(LPT[x].devicename, temp);
144 TRACE(comm, "%s = %s\n", option, LPT[x].devicename);
151 struct DosDeviceStruct *GetDeviceStruct(int fd)
153 int x;
155 for (x=0; x!=MAX_PORTS; x++) {
156 if (COM[x].fd == fd)
157 return &COM[x];
158 if (LPT[x].fd == fd)
159 return &LPT[x];
162 return NULL;
165 int GetCommPort(int fd)
167 int x;
169 for (x=0; x<MAX_PORTS; x++) {
170 if (COM[x].fd == fd)
171 return x;
174 return -1;
177 int ValidCOMPort(int x)
179 return(x < MAX_PORTS ? (int) COM[x].devicename : 0);
182 int ValidLPTPort(int x)
184 return(x < MAX_PORTS ? (int) LPT[x].devicename : 0);
187 int WinError(void)
189 TRACE(comm, "errno = %d\n", errno);
190 switch (errno) {
191 default:
192 return CE_IOE;
196 /**************************************************************************
197 * BuildCommDCB (USER.213)
199 BOOL16 WINAPI BuildCommDCB16(LPCSTR device, LPDCB16 lpdcb)
201 /* "COM1:9600,n,8,1" */
202 /* 012345 */
203 int port;
204 char *ptr, temp[256];
206 TRACE(comm, "(%s), ptr %p\n", device, lpdcb);
207 commerror = 0;
209 if (!lstrncmpi32A(device,"COM",3)) {
210 port = device[3] - '0';
213 if (port-- == 0) {
214 ERR(comm, "BUG ! COM0 can't exists!.\n");
215 commerror = IE_BADID;
218 if (!ValidCOMPort(port)) {
219 commerror = IE_BADID;
220 return -1;
223 memset(lpdcb, 0, sizeof(DCB16)); /* initialize */
225 if (!COM[port].fd) {
226 OpenComm(device, 0, 0);
228 lpdcb->Id = COM[port].fd;
230 if (!*(device+4))
231 return 0;
233 if (*(device+4) != ':')
234 return -1;
236 strcpy(temp,device+5);
237 ptr = strtok(temp, ", ");
239 if (COM[port].baudrate > 0)
240 lpdcb->BaudRate = COM[port].baudrate;
241 else
242 lpdcb->BaudRate = atoi(ptr);
243 TRACE(comm,"baudrate (%d)\n", lpdcb->BaudRate);
245 ptr = strtok(NULL, ", ");
246 if (islower(*ptr))
247 *ptr = toupper(*ptr);
249 TRACE(comm,"parity (%c)\n", *ptr);
250 lpdcb->fParity = 1;
251 switch (*ptr) {
252 case 'N':
253 lpdcb->Parity = NOPARITY;
254 lpdcb->fParity = 0;
255 break;
256 case 'E':
257 lpdcb->Parity = EVENPARITY;
258 break;
259 case 'M':
260 lpdcb->Parity = MARKPARITY;
261 break;
262 case 'O':
263 lpdcb->Parity = ODDPARITY;
264 break;
265 default:
266 WARN(comm,"Unknown parity `%c'!\n", *ptr);
267 return -1;
270 ptr = strtok(NULL, ", ");
271 TRACE(comm, "charsize (%c)\n", *ptr);
272 lpdcb->ByteSize = *ptr - '0';
274 ptr = strtok(NULL, ", ");
275 TRACE(comm, "stopbits (%c)\n", *ptr);
276 switch (*ptr) {
277 case '1':
278 lpdcb->StopBits = ONESTOPBIT;
279 break;
280 case '2':
281 lpdcb->StopBits = TWOSTOPBITS;
282 break;
283 default:
284 WARN(comm,"Unknown # of stopbits `%c'!\n", *ptr);
285 return -1;
289 return 0;
292 /**************************************************************************
293 * BuildCommDCBA (KERNEL32.14)
295 BOOL32 WINAPI BuildCommDCB32A(LPCSTR device,LPDCB32 lpdcb)
297 return BuildCommDCBAndTimeouts32A(device,lpdcb,NULL);
300 /**************************************************************************
301 * BuildCommDCBAndTimeoutsA (KERNEL32.15)
303 BOOL32 WINAPI BuildCommDCBAndTimeouts32A(LPCSTR device, LPDCB32 lpdcb,
304 LPCOMMTIMEOUTS lptimeouts)
306 int port;
307 char *ptr,*temp;
309 TRACE(comm,"(%s,%p,%p)\n",device,lpdcb,lptimeouts);
310 commerror = 0;
312 if (!lstrncmpi32A(device,"COM",3)) {
313 port=device[3]-'0';
314 if (port--==0) {
315 ERR(comm,"BUG! COM0 can't exists!.\n");
316 return FALSE;
318 if (!ValidCOMPort(port))
319 return FALSE;
320 if (*(device+4)!=':')
321 return FALSE;
322 temp=(LPSTR)(device+5);
323 } else
324 temp=(LPSTR)device;
326 memset(lpdcb, 0, sizeof(DCB32)); /* initialize */
328 lpdcb->DCBlength = sizeof(DCB32);
329 if (strchr(temp,',')) { /* old style */
330 DCB16 dcb16;
331 BOOL16 ret;
332 char last=temp[strlen(temp)-1];
334 ret=BuildCommDCB16(device,&dcb16);
335 if (!ret)
336 return FALSE;
337 lpdcb->BaudRate = dcb16.BaudRate;
338 lpdcb->ByteSize = dcb16.ByteSize;
339 lpdcb->fBinary = dcb16.fBinary;
340 lpdcb->Parity = dcb16.Parity;
341 lpdcb->fParity = dcb16.fParity;
342 lpdcb->fNull = dcb16.fNull;
343 lpdcb->StopBits = dcb16.StopBits;
344 if (last == 'x') {
345 lpdcb->fInX = TRUE;
346 lpdcb->fOutX = TRUE;
347 lpdcb->fOutxCtsFlow = FALSE;
348 lpdcb->fOutxDsrFlow = FALSE;
349 lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
350 lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
351 } else if (last=='p') {
352 lpdcb->fInX = FALSE;
353 lpdcb->fOutX = FALSE;
354 lpdcb->fOutxCtsFlow = TRUE;
355 lpdcb->fOutxDsrFlow = TRUE;
356 lpdcb->fDtrControl = DTR_CONTROL_HANDSHAKE;
357 lpdcb->fRtsControl = RTS_CONTROL_HANDSHAKE;
358 } else {
359 lpdcb->fInX = FALSE;
360 lpdcb->fOutX = FALSE;
361 lpdcb->fOutxCtsFlow = FALSE;
362 lpdcb->fOutxDsrFlow = FALSE;
363 lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
364 lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
366 lpdcb->XonChar = dcb16.XonChar;
367 lpdcb->XoffChar = dcb16.XoffChar;
368 lpdcb->ErrorChar= dcb16.PeChar;
369 lpdcb->fErrorChar= dcb16.fPeChar;
370 lpdcb->EofChar = dcb16.EofChar;
371 lpdcb->EvtChar = dcb16.EvtChar;
372 lpdcb->XonLim = dcb16.XonLim;
373 lpdcb->XoffLim = dcb16.XoffLim;
374 return TRUE;
376 ptr=strtok(temp," ");
377 while (ptr) {
378 DWORD flag,x;
380 flag=0;
381 if (!strncmp("baud=",ptr,5)) {
382 if (!sscanf(ptr+5,"%ld",&x))
383 WARN(comm,"Couldn't parse %s\n",ptr);
384 lpdcb->BaudRate = x;
385 flag=1;
387 if (!strncmp("stop=",ptr,5)) {
388 if (!sscanf(ptr+5,"%ld",&x))
389 WARN(comm,"Couldn't parse %s\n",ptr);
390 lpdcb->StopBits = x;
391 flag=1;
393 if (!strncmp("data=",ptr,5)) {
394 if (!sscanf(ptr+5,"%ld",&x))
395 WARN(comm,"Couldn't parse %s\n",ptr);
396 lpdcb->ByteSize = x;
397 flag=1;
399 if (!strncmp("parity=",ptr,7)) {
400 lpdcb->fParity = TRUE;
401 switch (ptr[8]) {
402 case 'N':case 'n':
403 lpdcb->fParity = FALSE;
404 lpdcb->Parity = NOPARITY;
405 break;
406 case 'E':case 'e':
407 lpdcb->Parity = EVENPARITY;
408 break;
409 case 'O':case 'o':
410 lpdcb->Parity = ODDPARITY;
411 break;
412 case 'M':case 'm':
413 lpdcb->Parity = MARKPARITY;
414 break;
416 flag=1;
418 if (!flag)
419 ERR(comm,"Unhandled specifier '%s', please report.\n",ptr);
420 ptr=strtok(NULL," ");
422 if (lpdcb->BaudRate==110)
423 lpdcb->StopBits = 2;
424 return TRUE;
427 /**************************************************************************
428 * BuildCommDCBAndTimeoutsW (KERNEL32.16)
430 BOOL32 WINAPI BuildCommDCBAndTimeouts32W( LPCWSTR devid, LPDCB32 lpdcb,
431 LPCOMMTIMEOUTS lptimeouts )
433 LPSTR devidA;
434 BOOL32 ret;
436 TRACE(comm,"(%p,%p,%p)\n",devid,lpdcb,lptimeouts);
437 devidA = HEAP_strdupWtoA( GetProcessHeap(), 0, devid );
438 ret=BuildCommDCBAndTimeouts32A(devidA,lpdcb,lptimeouts);
439 HeapFree( GetProcessHeap(), 0, devidA );
440 return ret;
443 /**************************************************************************
444 * BuildCommDCBW (KERNEL32.17)
446 BOOL32 WINAPI BuildCommDCB32W(LPCWSTR devid,LPDCB32 lpdcb)
448 return BuildCommDCBAndTimeouts32W(devid,lpdcb,NULL);
451 /*****************************************************************************
452 * OpenComm (USER.200)
454 INT16 WINAPI OpenComm(LPCSTR device,UINT16 cbInQueue,UINT16 cbOutQueue)
456 int port,fd;
458 TRACE(comm, "%s, %d, %d\n", device, cbInQueue, cbOutQueue);
459 commerror = 0;
461 if (!lstrncmpi32A(device,"COM",3)) {
462 port = device[3] - '0';
464 if (port-- == 0) {
465 ERR(comm, "BUG ! COM0 doesn't exist !\n");
466 commerror = IE_BADID;
469 /* to help GetCommError return left buffsize [V] */
470 iGlobalOutQueueFiller = (cbOutQueue - SERIAL_XMIT_SIZE);
471 if (iGlobalOutQueueFiller < 0) iGlobalOutQueueFiller = 0;
473 TRACE(comm, "%s = %s\n", device, COM[port].devicename);
475 if (!ValidCOMPort(port)) {
476 commerror = IE_BADID;
477 return -1;
479 if (COM[port].fd) {
480 return COM[port].fd;
483 fd = open(COM[port].devicename, O_RDWR | O_NONBLOCK);
484 if (fd == -1) {
485 commerror = WinError();
486 return -1;
487 } else {
488 unknown[port] = SEGPTR_ALLOC(40);
489 bzero(unknown[port],40);
490 COM[port].fd = fd;
491 return fd;
494 else
495 if (!lstrncmpi32A(device,"LPT",3)) {
496 port = device[3] - '0';
498 if (!ValidLPTPort(port)) {
499 commerror = IE_BADID;
500 return -1;
502 if (LPT[port].fd) {
503 commerror = IE_OPEN;
504 return -1;
507 fd = open(LPT[port].devicename, O_RDWR | O_NONBLOCK, 0);
508 if (fd == -1) {
509 commerror = WinError();
510 return -1;
511 } else {
512 LPT[port].fd = fd;
513 return fd;
516 return 0;
519 /*****************************************************************************
520 * CloseComm (USER.207)
522 INT16 WINAPI CloseComm(INT16 fd)
524 int port;
525 TRACE(comm,"fd %d\n", fd);
526 if ((port = GetCommPort(fd)) !=-1) { /* [LW] */
527 SEGPTR_FREE(unknown[port]);
528 COM[port].fd = 0; /* my adaptation of RER's fix */
529 } else {
530 commerror = IE_BADID;
531 return -1;
534 if (close(fd) == -1) {
535 commerror = WinError();
536 return -1;
537 } else {
538 commerror = 0;
539 return 0;
543 /*****************************************************************************
544 * SetCommBreak (USER.210)
546 INT16 WINAPI SetCommBreak16(INT16 fd)
548 struct DosDeviceStruct *ptr;
550 TRACE(comm,"fd=%d\n", fd);
551 if ((ptr = GetDeviceStruct(fd)) == NULL) {
552 commerror = IE_BADID;
553 return -1;
556 ptr->suspended = 1;
557 commerror = 0;
558 return 0;
561 /*****************************************************************************
562 * SetCommBreak (KERNEL32.449)
564 BOOL32 WINAPI SetCommBreak32(INT32 fd)
567 struct DosDeviceStruct *ptr;
569 TRACE(comm,"fd=%d\n", fd);
570 if ((ptr = GetDeviceStruct(fd)) == NULL) {
571 commerror = IE_BADID;
572 return FALSE;
575 ptr->suspended = 1;
576 commerror = 0;
577 return TRUE;
580 /*****************************************************************************
581 * ClearCommBreak (USER.211)
583 INT16 WINAPI ClearCommBreak16(INT16 fd)
585 struct DosDeviceStruct *ptr;
587 TRACE(comm,"fd=%d\n", fd);
588 if ((ptr = GetDeviceStruct(fd)) == NULL) {
589 commerror = IE_BADID;
590 return -1;
593 ptr->suspended = 0;
594 commerror = 0;
595 return 0;
598 /*****************************************************************************
599 * ClearCommBreak (KERNEL32.20)
601 BOOL32 WINAPI ClearCommBreak32(INT32 fd)
603 struct DosDeviceStruct *ptr;
605 TRACE(comm,"fd=%d\n", fd);
606 if ((ptr = GetDeviceStruct(fd)) == NULL) {
607 commerror = IE_BADID;
608 return FALSE;
611 ptr->suspended = 0;
612 commerror = 0;
613 return TRUE;
616 /*****************************************************************************
617 * EscapeCommFunction (USER.214)
619 LONG WINAPI EscapeCommFunction16(UINT16 fd,UINT16 nFunction)
621 int max;
622 struct termios port;
624 TRACE(comm,"fd=%d, function=%d\n", fd, nFunction);
625 if (tcgetattr(fd,&port) == -1) {
626 commerror=WinError();
627 return -1;
630 switch (nFunction) {
631 case RESETDEV:
632 break;
634 case GETMAXCOM:
635 for (max = MAX_PORTS;!COM[max].devicename;max--)
637 return max;
638 break;
640 case GETMAXLPT:
641 for (max = MAX_PORTS;!LPT[max].devicename;max--)
643 return 0x80 + max;
644 break;
646 #ifdef TIOCM_DTR
647 case CLRDTR:
648 port.c_cflag &= TIOCM_DTR;
649 break;
650 #endif
652 #ifdef TIOCM_RTS
653 case CLRRTS:
654 port.c_cflag &= TIOCM_RTS;
655 break;
656 #endif
658 #ifdef CRTSCTS
659 case SETDTR:
660 port.c_cflag |= CRTSCTS;
661 break;
663 case SETRTS:
664 port.c_cflag |= CRTSCTS;
665 break;
666 #endif
668 case SETXOFF:
669 port.c_iflag |= IXOFF;
670 break;
672 case SETXON:
673 port.c_iflag |= IXON;
674 break;
676 default:
677 WARN(comm,"(fd=%d,nFunction=%d): Unknown function\n",
678 fd, nFunction);
679 break;
682 if (tcsetattr(fd, TCSADRAIN, &port) == -1) {
683 commerror = WinError();
684 return -1;
685 } else {
686 commerror = 0;
687 return 0;
691 /*****************************************************************************
692 * EscapeCommFunction (KERNEL32.214)
694 BOOL32 WINAPI EscapeCommFunction32(INT32 fd,UINT32 nFunction)
696 struct termios port;
697 struct DosDeviceStruct *ptr;
699 TRACE(comm,"fd=%d, function=%d\n", fd, nFunction);
700 if (tcgetattr(fd,&port) == -1) {
701 commerror=WinError();
702 return FALSE;
704 if ((ptr = GetDeviceStruct(fd)) == NULL) {
705 commerror = IE_BADID;
706 return FALSE;
709 switch (nFunction) {
710 case RESETDEV:
711 break;
713 #ifdef TIOCM_DTR
714 case CLRDTR:
715 port.c_cflag &= TIOCM_DTR;
716 break;
717 #endif
719 #ifdef TIOCM_RTS
720 case CLRRTS:
721 port.c_cflag &= TIOCM_RTS;
722 break;
723 #endif
725 #ifdef CRTSCTS
726 case SETDTR:
727 port.c_cflag |= CRTSCTS;
728 break;
730 case SETRTS:
731 port.c_cflag |= CRTSCTS;
732 break;
733 #endif
735 case SETXOFF:
736 port.c_iflag |= IXOFF;
737 break;
739 case SETXON:
740 port.c_iflag |= IXON;
741 break;
742 case SETBREAK:
743 ptr->suspended = 1;
744 break;
745 case CLRBREAK:
746 ptr->suspended = 0;
747 break;
748 default:
749 WARN(comm,"(fd=%d,nFunction=%d): Unknown function\n",
750 fd, nFunction);
751 break;
754 if (tcsetattr(fd, TCSADRAIN, &port) == -1) {
755 commerror = WinError();
756 return FALSE;
757 } else {
758 commerror = 0;
759 return TRUE;
763 /*****************************************************************************
764 * FlushComm (USER.215)
766 INT16 WINAPI FlushComm(INT16 fd,INT16 fnQueue)
768 int queue;
770 TRACE(comm,"fd=%d, queue=%d\n", fd, fnQueue);
771 switch (fnQueue) {
772 case 0: queue = TCOFLUSH;
773 break;
774 case 1: queue = TCIFLUSH;
775 break;
776 default:WARN(comm,"(fd=%d,fnQueue=%d):Unknown queue\n",
777 fd, fnQueue);
778 return -1;
780 if (tcflush(fd, queue)) {
781 commerror = WinError();
782 return -1;
783 } else {
784 commerror = 0;
785 return 0;
789 /********************************************************************
790 * PurgeComm (KERNEL32.557)
792 BOOL32 WINAPI PurgeComm( HANDLE32 hFile, DWORD flags)
794 FIXME(comm, "(%08x %08lx) unimplemented stub\n",
795 hFile, flags);
796 return 0;
799 /********************************************************************
800 * GetCommError (USER.203)
802 INT16 WINAPI GetCommError(INT16 fd,LPCOMSTAT lpStat)
804 int temperror;
805 unsigned long cnt;
806 int rc;
808 if (lpStat) {
809 lpStat->status = 0;
811 rc = ioctl(fd, TIOCOUTQ, &cnt);
812 if (rc) WARN(comm, "Error !\n");
813 lpStat->cbOutQue = cnt + iGlobalOutQueueFiller;
815 rc = ioctl(fd, TIOCINQ, &cnt);
816 if (rc) WARN(comm, "Error !\n");
817 lpStat->cbInQue = cnt;
819 TRACE(comm, "fd %d, error %d, lpStat %d %d %d\n",
820 fd, commerror, lpStat->status, lpStat->cbInQue,
821 lpStat->cbOutQue);
823 else
824 TRACE(comm, "fd %d, error %d, lpStat NULL\n",
825 fd, commerror);
828 * [RER] I have no idea what the following is trying to accomplish.
829 * [RER] It is certainly not what the reference manual suggests.
831 temperror = commerror;
832 commerror = 0;
833 return(temperror);
836 /*****************************************************************************
837 * ClearCommError (KERNEL32.21)
839 BOOL32 WINAPI ClearCommError(INT32 fd,LPDWORD errors,LPCOMSTAT lpStat)
841 int temperror;
843 TRACE(comm, "fd %d (current error %d)\n",
844 fd, commerror);
845 temperror = commerror;
846 commerror = 0;
847 return TRUE;
850 /*****************************************************************************
851 * SetCommEventMask (USER.208)
853 SEGPTR WINAPI SetCommEventMask(INT16 fd,UINT16 fuEvtMask)
855 unsigned char *stol;
856 int act;
857 int repid;
858 unsigned int mstat;
859 TRACE(comm,"fd %d,mask %d\n",fd,fuEvtMask);
860 eventmask |= fuEvtMask;
861 if ((act = GetCommPort(fd)) == -1) {
862 WARN(comm," fd %d not comm port\n",act);
863 return NULL;}
864 stol = (unsigned char *)unknown[act];
865 stol += msr;
866 repid = ioctl(fd,TIOCMGET,&mstat);
867 TRACE(comm, " ioctl %d, msr %x at %p %p\n",repid,mstat,stol,unknown[act]);
868 if ((mstat&TIOCM_CAR)) {*stol |= 0x80;}
869 else {*stol &=0x7f;}
870 TRACE(comm," modem dcd construct %x\n",*stol);
871 return SEGPTR_GET(unknown[act]);
874 /*****************************************************************************
875 * GetCommEventMask (USER.209)
877 UINT16 WINAPI GetCommEventMask(INT16 fd,UINT16 fnEvtClear)
879 int events = 0;
881 TRACE(comm, "fd %d, mask %d\n", fd, fnEvtClear);
884 * Determine if any characters are available
886 if (fnEvtClear & EV_RXCHAR)
888 int rc;
889 unsigned long cnt;
891 rc = ioctl(fd, TIOCINQ, &cnt);
892 if (cnt) events |= EV_RXCHAR;
894 TRACE(comm, "rxchar %ld\n", cnt);
898 * There are other events that need to be checked for
900 /* TODO */
902 TRACE(comm, "return events %d\n", events);
903 return events;
906 * [RER] The following was gibberish
908 #if 0
909 tempmask = eventmask;
910 eventmask &= ~fnEvtClear;
911 return eventmask;
912 #endif
915 /*****************************************************************************
916 * SetupComm (KERNEL32.676)
918 BOOL32 WINAPI SetupComm( HANDLE32 hFile, DWORD insize, DWORD outsize)
920 FIXME(comm, "insize %ld outsize %ld unimplemented stub\n", insize, outsize);
921 return FALSE;
924 /*****************************************************************************
925 * GetCommMask (KERNEL32.156)
927 BOOL32 WINAPI GetCommMask(INT32 fd,LPDWORD evtmask)
929 TRACE(comm, "fd %d, mask %p\n", fd, evtmask);
930 *evtmask = eventmask;
931 return TRUE;
934 /*****************************************************************************
935 * SetCommMask (KERNEL32.451)
937 BOOL32 WINAPI SetCommMask(INT32 fd,DWORD evtmask)
939 TRACE(comm, "fd %d, mask %lx\n", fd, evtmask);
940 eventmask = evtmask;
941 return TRUE;
944 /*****************************************************************************
945 * SetCommState16 (USER.201)
947 INT16 WINAPI SetCommState16(LPDCB16 lpdcb)
949 struct termios port;
950 struct DosDeviceStruct *ptr;
952 TRACE(comm, "fd %d, ptr %p\n", lpdcb->Id, lpdcb);
953 if (tcgetattr(lpdcb->Id, &port) == -1) {
954 commerror = WinError();
955 return -1;
958 port.c_cc[VMIN] = 0;
959 port.c_cc[VTIME] = 1;
961 #ifdef IMAXBEL
962 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|IMAXBEL);
963 #else
964 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR);
965 #endif
966 port.c_iflag |= (IGNBRK);
968 port.c_oflag &= ~(OPOST);
970 port.c_cflag &= ~(HUPCL);
971 port.c_cflag |= CLOCAL | CREAD;
973 port.c_lflag &= ~(ICANON|ECHO|ISIG);
974 port.c_lflag |= NOFLSH;
976 if ((ptr = GetDeviceStruct(lpdcb->Id)) == NULL) {
977 commerror = IE_BADID;
978 return -1;
980 if (ptr->baudrate > 0)
981 lpdcb->BaudRate = ptr->baudrate;
982 TRACE(comm,"baudrate %d\n",lpdcb->BaudRate);
983 #ifdef CBAUD
984 port.c_cflag &= ~CBAUD;
985 switch (lpdcb->BaudRate) {
986 case 110:
987 case CBR_110:
988 port.c_cflag |= B110;
989 break;
990 case 300:
991 case CBR_300:
992 port.c_cflag |= B300;
993 break;
994 case 600:
995 case CBR_600:
996 port.c_cflag |= B600;
997 break;
998 case 1200:
999 case CBR_1200:
1000 port.c_cflag |= B1200;
1001 break;
1002 case 2400:
1003 case CBR_2400:
1004 port.c_cflag |= B2400;
1005 break;
1006 case 4800:
1007 case CBR_4800:
1008 port.c_cflag |= B4800;
1009 break;
1010 case 9600:
1011 case CBR_9600:
1012 port.c_cflag |= B9600;
1013 break;
1014 case 19200:
1015 case CBR_19200:
1016 port.c_cflag |= B19200;
1017 break;
1018 case 38400:
1019 case CBR_38400:
1020 port.c_cflag |= B38400;
1021 break;
1022 case 57600:
1023 port.c_cflag |= B57600;
1024 break;
1025 case 57601:
1026 port.c_cflag |= B115200;
1027 break;
1028 default:
1029 commerror = IE_BAUDRATE;
1030 return -1;
1032 #elif !defined(__EMX__)
1033 switch (lpdcb->BaudRate) {
1034 case 110:
1035 case CBR_110:
1036 port.c_ospeed = B110;
1037 break;
1038 case 300:
1039 case CBR_300:
1040 port.c_ospeed = B300;
1041 break;
1042 case 600:
1043 case CBR_600:
1044 port.c_ospeed = B600;
1045 break;
1046 case 1200:
1047 case CBR_1200:
1048 port.c_ospeed = B1200;
1049 break;
1050 case 2400:
1051 case CBR_2400:
1052 port.c_ospeed = B2400;
1053 break;
1054 case 4800:
1055 case CBR_4800:
1056 port.c_ospeed = B4800;
1057 break;
1058 case 9600:
1059 case CBR_9600:
1060 port.c_ospeed = B9600;
1061 break;
1062 case 19200:
1063 case CBR_19200:
1064 port.c_ospeed = B19200;
1065 break;
1066 case 38400:
1067 case CBR_38400:
1068 port.c_ospeed = B38400;
1069 break;
1070 default:
1071 commerror = IE_BAUDRATE;
1072 return -1;
1074 port.c_ispeed = port.c_ospeed;
1075 #endif
1076 TRACE(comm,"bytesize %d\n",lpdcb->ByteSize);
1077 port.c_cflag &= ~CSIZE;
1078 switch (lpdcb->ByteSize) {
1079 case 5:
1080 port.c_cflag |= CS5;
1081 break;
1082 case 6:
1083 port.c_cflag |= CS6;
1084 break;
1085 case 7:
1086 port.c_cflag |= CS7;
1087 break;
1088 case 8:
1089 port.c_cflag |= CS8;
1090 break;
1091 default:
1092 commerror = IE_BYTESIZE;
1093 return -1;
1096 TRACE(comm,"parity %d\n",lpdcb->Parity);
1097 port.c_cflag &= ~(PARENB | PARODD);
1098 if (lpdcb->fParity)
1099 switch (lpdcb->Parity) {
1100 case NOPARITY:
1101 port.c_iflag &= ~INPCK;
1102 break;
1103 case ODDPARITY:
1104 port.c_cflag |= (PARENB | PARODD);
1105 port.c_iflag |= INPCK;
1106 break;
1107 case EVENPARITY:
1108 port.c_cflag |= PARENB;
1109 port.c_iflag |= INPCK;
1110 break;
1111 default:
1112 commerror = IE_BYTESIZE;
1113 return -1;
1117 TRACE(comm,"stopbits %d\n",lpdcb->StopBits);
1119 switch (lpdcb->StopBits) {
1120 case ONESTOPBIT:
1121 port.c_cflag &= ~CSTOPB;
1122 break;
1123 case TWOSTOPBITS:
1124 port.c_cflag |= CSTOPB;
1125 break;
1126 default:
1127 commerror = IE_BYTESIZE;
1128 return -1;
1130 #ifdef CRTSCTS
1132 if (lpdcb->fDtrflow || lpdcb->fRtsflow || lpdcb->fOutxCtsFlow)
1133 port.c_cflag |= CRTSCTS;
1135 if (lpdcb->fDtrDisable)
1136 port.c_cflag &= ~CRTSCTS;
1137 #endif
1138 if (lpdcb->fInX)
1139 port.c_iflag |= IXON;
1140 else
1141 port.c_iflag &= ~IXON;
1142 if (lpdcb->fOutX)
1143 port.c_iflag |= IXOFF;
1144 else
1145 port.c_iflag &= ~IXOFF;
1147 if (tcsetattr(lpdcb->Id, TCSADRAIN, &port) == -1) {
1148 commerror = WinError();
1149 return FALSE;
1150 } else {
1151 commerror = 0;
1152 return 0;
1156 /*****************************************************************************
1157 * SetCommState32 (KERNEL32.452)
1159 BOOL32 WINAPI SetCommState32(INT32 fd,LPDCB32 lpdcb)
1161 struct termios port;
1162 struct DosDeviceStruct *ptr;
1164 TRACE(comm,"fd %d, ptr %p\n",fd,lpdcb);
1165 if (tcgetattr(fd,&port) == -1) {
1166 commerror = WinError();
1167 return FALSE;
1170 port.c_cc[VMIN] = 0;
1171 port.c_cc[VTIME] = 1;
1173 #ifdef IMAXBEL
1174 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|IMAXBEL);
1175 #else
1176 port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR);
1177 #endif
1178 port.c_iflag |= (IGNBRK);
1180 port.c_oflag &= ~(OPOST);
1182 port.c_cflag &= ~(HUPCL);
1183 port.c_cflag |= CLOCAL | CREAD;
1185 port.c_lflag &= ~(ICANON|ECHO|ISIG);
1186 port.c_lflag |= NOFLSH;
1188 if ((ptr = GetDeviceStruct(fd)) == NULL) {
1189 commerror = IE_BADID;
1190 return FALSE;
1192 if (ptr->baudrate > 0)
1193 lpdcb->BaudRate = ptr->baudrate;
1194 TRACE(comm,"baudrate %ld\n",lpdcb->BaudRate);
1195 #ifdef CBAUD
1196 port.c_cflag &= ~CBAUD;
1197 switch (lpdcb->BaudRate) {
1198 case 110:
1199 case CBR_110:
1200 port.c_cflag |= B110;
1201 break;
1202 case 300:
1203 case CBR_300:
1204 port.c_cflag |= B300;
1205 break;
1206 case 600:
1207 case CBR_600:
1208 port.c_cflag |= B600;
1209 break;
1210 case 1200:
1211 case CBR_1200:
1212 port.c_cflag |= B1200;
1213 break;
1214 case 2400:
1215 case CBR_2400:
1216 port.c_cflag |= B2400;
1217 break;
1218 case 4800:
1219 case CBR_4800:
1220 port.c_cflag |= B4800;
1221 break;
1222 case 9600:
1223 case CBR_9600:
1224 port.c_cflag |= B9600;
1225 break;
1226 case 19200:
1227 case CBR_19200:
1228 port.c_cflag |= B19200;
1229 break;
1230 case 38400:
1231 case CBR_38400:
1232 port.c_cflag |= B38400;
1233 break;
1234 default:
1235 commerror = IE_BAUDRATE;
1236 return FALSE;
1238 #elif !defined(__EMX__)
1239 switch (lpdcb->BaudRate) {
1240 case 110:
1241 case CBR_110:
1242 port.c_ospeed = B110;
1243 break;
1244 case 300:
1245 case CBR_300:
1246 port.c_ospeed = B300;
1247 break;
1248 case 600:
1249 case CBR_600:
1250 port.c_ospeed = B600;
1251 break;
1252 case 1200:
1253 case CBR_1200:
1254 port.c_ospeed = B1200;
1255 break;
1256 case 2400:
1257 case CBR_2400:
1258 port.c_ospeed = B2400;
1259 break;
1260 case 4800:
1261 case CBR_4800:
1262 port.c_ospeed = B4800;
1263 break;
1264 case 9600:
1265 case CBR_9600:
1266 port.c_ospeed = B9600;
1267 break;
1268 case 19200:
1269 case CBR_19200:
1270 port.c_ospeed = B19200;
1271 break;
1272 case 38400:
1273 case CBR_38400:
1274 port.c_ospeed = B38400;
1275 break;
1276 default:
1277 commerror = IE_BAUDRATE;
1278 return FALSE;
1280 port.c_ispeed = port.c_ospeed;
1281 #endif
1282 TRACE(comm,"bytesize %d\n",lpdcb->ByteSize);
1283 port.c_cflag &= ~CSIZE;
1284 switch (lpdcb->ByteSize) {
1285 case 5:
1286 port.c_cflag |= CS5;
1287 break;
1288 case 6:
1289 port.c_cflag |= CS6;
1290 break;
1291 case 7:
1292 port.c_cflag |= CS7;
1293 break;
1294 case 8:
1295 port.c_cflag |= CS8;
1296 break;
1297 default:
1298 commerror = IE_BYTESIZE;
1299 return FALSE;
1302 TRACE(comm,"parity %d\n",lpdcb->Parity);
1303 port.c_cflag &= ~(PARENB | PARODD);
1304 if (lpdcb->fParity)
1305 switch (lpdcb->Parity) {
1306 case NOPARITY:
1307 port.c_iflag &= ~INPCK;
1308 break;
1309 case ODDPARITY:
1310 port.c_cflag |= (PARENB | PARODD);
1311 port.c_iflag |= INPCK;
1312 break;
1313 case EVENPARITY:
1314 port.c_cflag |= PARENB;
1315 port.c_iflag |= INPCK;
1316 break;
1317 default:
1318 commerror = IE_BYTESIZE;
1319 return FALSE;
1323 TRACE(comm,"stopbits %d\n",lpdcb->StopBits);
1324 switch (lpdcb->StopBits) {
1325 case ONESTOPBIT:
1326 port.c_cflag &= ~CSTOPB;
1327 break;
1328 case TWOSTOPBITS:
1329 port.c_cflag |= CSTOPB;
1330 break;
1331 default:
1332 commerror = IE_BYTESIZE;
1333 return FALSE;
1335 #ifdef CRTSCTS
1336 if ( lpdcb->fOutxCtsFlow ||
1337 lpdcb->fDtrControl == DTR_CONTROL_ENABLE||
1338 lpdcb->fRtsControl == RTS_CONTROL_ENABLE
1340 port.c_cflag |= CRTSCTS;
1341 if (lpdcb->fDtrControl == DTR_CONTROL_DISABLE)
1342 port.c_cflag &= ~CRTSCTS;
1344 #endif
1345 if (lpdcb->fInX)
1346 port.c_iflag |= IXON;
1347 else
1348 port.c_iflag &= ~IXON;
1349 if (lpdcb->fOutX)
1350 port.c_iflag |= IXOFF;
1351 else
1352 port.c_iflag &= ~IXOFF;
1354 if (tcsetattr(fd,TCSADRAIN,&port)==-1) {
1355 commerror = WinError();
1356 return FALSE;
1357 } else {
1358 commerror = 0;
1359 return TRUE;
1364 /*****************************************************************************
1365 * GetCommState (USER.202)
1367 INT16 WINAPI GetCommState16(INT16 fd, LPDCB16 lpdcb)
1369 struct termios port;
1371 TRACE(comm,"fd %d, ptr %p\n", fd, lpdcb);
1372 if (tcgetattr(fd, &port) == -1) {
1373 commerror = WinError();
1374 return -1;
1376 lpdcb->Id = fd;
1377 #ifndef __EMX__
1378 #ifdef CBAUD
1379 switch (port.c_cflag & CBAUD) {
1380 #else
1381 switch (port.c_ospeed) {
1382 #endif
1383 case B110:
1384 lpdcb->BaudRate = 110;
1385 break;
1386 case B300:
1387 lpdcb->BaudRate = 300;
1388 break;
1389 case B600:
1390 lpdcb->BaudRate = 600;
1391 break;
1392 case B1200:
1393 lpdcb->BaudRate = 1200;
1394 break;
1395 case B2400:
1396 lpdcb->BaudRate = 2400;
1397 break;
1398 case B4800:
1399 lpdcb->BaudRate = 4800;
1400 break;
1401 case B9600:
1402 lpdcb->BaudRate = 9600;
1403 break;
1404 case B19200:
1405 lpdcb->BaudRate = 19200;
1406 break;
1407 case B38400:
1408 lpdcb->BaudRate = 38400;
1409 break;
1410 case B57600:
1411 lpdcb->BaudRate = 57600;
1412 break;
1413 case B115200:
1414 lpdcb->BaudRate = 57601;
1415 break;
1417 #endif
1418 switch (port.c_cflag & CSIZE) {
1419 case CS5:
1420 lpdcb->ByteSize = 5;
1421 break;
1422 case CS6:
1423 lpdcb->ByteSize = 6;
1424 break;
1425 case CS7:
1426 lpdcb->ByteSize = 7;
1427 break;
1428 case CS8:
1429 lpdcb->ByteSize = 8;
1430 break;
1433 switch (port.c_cflag & ~(PARENB | PARODD)) {
1434 case 0:
1435 lpdcb->fParity = NOPARITY;
1436 break;
1437 case PARENB:
1438 lpdcb->fParity = EVENPARITY;
1439 break;
1440 case (PARENB | PARODD):
1441 lpdcb->fParity = ODDPARITY;
1442 break;
1445 if (port.c_cflag & CSTOPB)
1446 lpdcb->StopBits = TWOSTOPBITS;
1447 else
1448 lpdcb->StopBits = ONESTOPBIT;
1450 lpdcb->RlsTimeout = 50;
1451 lpdcb->CtsTimeout = 50;
1452 lpdcb->DsrTimeout = 50;
1453 lpdcb->fNull = 0;
1454 lpdcb->fChEvt = 0;
1455 lpdcb->fBinary = 1;
1456 lpdcb->fDtrDisable = 0;
1458 #ifdef CRTSCTS
1460 if (port.c_cflag & CRTSCTS) {
1461 lpdcb->fDtrflow = 1;
1462 lpdcb->fRtsflow = 1;
1463 lpdcb->fOutxCtsFlow = 1;
1464 lpdcb->fOutxDsrFlow = 1;
1465 } else
1466 #endif
1467 lpdcb->fDtrDisable = 1;
1469 if (port.c_iflag & IXON)
1470 lpdcb->fInX = 1;
1471 else
1472 lpdcb->fInX = 0;
1474 if (port.c_iflag & IXOFF)
1475 lpdcb->fOutX = 1;
1476 else
1477 lpdcb->fOutX = 0;
1479 lpdcb->XonChar =
1480 lpdcb->XoffChar =
1482 lpdcb->XonLim = 10;
1483 lpdcb->XoffLim = 10;
1485 commerror = 0;
1486 return 0;
1489 /*****************************************************************************
1490 * GetCommState (KERNEL32.159)
1492 BOOL32 WINAPI GetCommState32(INT32 fd, LPDCB32 lpdcb)
1494 struct termios port;
1496 TRACE(comm,"fd %d, ptr %p\n", fd, lpdcb);
1497 if (GetDeviceStruct(fd) == NULL) return FALSE;
1498 if (tcgetattr(fd, &port) == -1) {
1499 commerror = WinError();
1500 return FALSE;
1502 #ifndef __EMX__
1503 #ifdef CBAUD
1504 switch (port.c_cflag & CBAUD) {
1505 #else
1506 switch (port.c_ospeed) {
1507 #endif
1508 case B110:
1509 lpdcb->BaudRate = 110;
1510 break;
1511 case B300:
1512 lpdcb->BaudRate = 300;
1513 break;
1514 case B600:
1515 lpdcb->BaudRate = 600;
1516 break;
1517 case B1200:
1518 lpdcb->BaudRate = 1200;
1519 break;
1520 case B2400:
1521 lpdcb->BaudRate = 2400;
1522 break;
1523 case B4800:
1524 lpdcb->BaudRate = 4800;
1525 break;
1526 case B9600:
1527 lpdcb->BaudRate = 9600;
1528 break;
1529 case B19200:
1530 lpdcb->BaudRate = 19200;
1531 break;
1532 case B38400:
1533 lpdcb->BaudRate = 38400;
1534 break;
1536 #endif
1537 switch (port.c_cflag & CSIZE) {
1538 case CS5:
1539 lpdcb->ByteSize = 5;
1540 break;
1541 case CS6:
1542 lpdcb->ByteSize = 6;
1543 break;
1544 case CS7:
1545 lpdcb->ByteSize = 7;
1546 break;
1547 case CS8:
1548 lpdcb->ByteSize = 8;
1549 break;
1552 switch (port.c_cflag & ~(PARENB | PARODD)) {
1553 case 0:
1554 lpdcb->fParity = NOPARITY;
1555 break;
1556 case PARENB:
1557 lpdcb->fParity = EVENPARITY;
1558 break;
1559 case (PARENB | PARODD):
1560 lpdcb->fParity = ODDPARITY;
1561 break;
1564 if (port.c_cflag & CSTOPB)
1565 lpdcb->StopBits = TWOSTOPBITS;
1566 else
1567 lpdcb->StopBits = ONESTOPBIT;
1569 lpdcb->fNull = 0;
1570 lpdcb->fBinary = 1;
1572 #ifdef CRTSCTS
1574 if (port.c_cflag & CRTSCTS) {
1575 lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
1576 lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
1577 lpdcb->fOutxCtsFlow = 1;
1578 lpdcb->fOutxDsrFlow = 1;
1579 } else
1580 #endif
1582 lpdcb->fDtrControl = DTR_CONTROL_DISABLE;
1583 lpdcb->fRtsControl = RTS_CONTROL_DISABLE;
1585 if (port.c_iflag & IXON)
1586 lpdcb->fInX = 1;
1587 else
1588 lpdcb->fInX = 0;
1590 if (port.c_iflag & IXOFF)
1591 lpdcb->fOutX = 1;
1592 else
1593 lpdcb->fOutX = 0;
1595 lpdcb->XonChar =
1596 lpdcb->XoffChar =
1598 lpdcb->XonLim = 10;
1599 lpdcb->XoffLim = 10;
1601 commerror = 0;
1602 return TRUE;
1605 /*****************************************************************************
1606 * TransmitCommChar (USER.206)
1608 INT16 WINAPI TransmitCommChar16(INT16 fd,CHAR chTransmit)
1610 struct DosDeviceStruct *ptr;
1612 TRACE(comm, "fd %d, data %d \n", fd, chTransmit);
1613 if ((ptr = GetDeviceStruct(fd)) == NULL) {
1614 commerror = IE_BADID;
1615 return -1;
1618 if (ptr->suspended) {
1619 commerror = IE_HARDWARE;
1620 return -1;
1623 if (write(fd, (void *) &chTransmit, 1) == -1) {
1624 commerror = WinError();
1625 return -1;
1626 } else {
1627 commerror = 0;
1628 return 0;
1632 /*****************************************************************************
1633 * TransmitCommChar (KERNEL32.535)
1635 BOOL32 WINAPI TransmitCommChar32(INT32 fd,CHAR chTransmit)
1637 struct DosDeviceStruct *ptr;
1639 TRACE(comm,"(%d,'%c')\n",fd,chTransmit);
1640 if ((ptr = GetDeviceStruct(fd)) == NULL) {
1641 commerror = IE_BADID;
1642 return FALSE;
1645 if (ptr->suspended) {
1646 commerror = IE_HARDWARE;
1647 return FALSE;
1649 if (write(fd, (void *) &chTransmit, 1) == -1) {
1650 commerror = WinError();
1651 return FALSE;
1652 } else {
1653 commerror = 0;
1654 return TRUE;
1658 /*****************************************************************************
1659 * UngetCommChar (USER.212)
1661 INT16 WINAPI UngetCommChar(INT16 fd,CHAR chUnget)
1663 struct DosDeviceStruct *ptr;
1665 TRACE(comm,"fd %d (char %d)\n", fd, chUnget);
1666 if ((ptr = GetDeviceStruct(fd)) == NULL) {
1667 commerror = IE_BADID;
1668 return -1;
1671 if (ptr->suspended) {
1672 commerror = IE_HARDWARE;
1673 return -1;
1676 ptr->unget = 1;
1677 ptr->unget_byte = chUnget;
1678 commerror = 0;
1679 return 0;
1682 /*****************************************************************************
1683 * ReadComm (USER.204)
1685 INT16 WINAPI ReadComm(INT16 fd,LPSTR lpvBuf,INT16 cbRead)
1687 int status, length;
1688 struct DosDeviceStruct *ptr;
1690 TRACE(comm, "fd %d, ptr %p, length %d\n", fd, lpvBuf, cbRead);
1691 if ((ptr = GetDeviceStruct(fd)) == NULL) {
1692 commerror = IE_BADID;
1693 return -1;
1696 if (ptr->suspended) {
1697 commerror = IE_HARDWARE;
1698 return -1;
1701 if (ptr->unget) {
1702 *lpvBuf = ptr->unget_byte;
1703 lpvBuf++;
1704 ptr->unget = 0;
1706 length = 1;
1707 } else
1708 length = 0;
1710 status = read(fd, (void *) lpvBuf, cbRead);
1712 if (status == -1) {
1713 if (errno != EAGAIN) {
1714 commerror = WinError();
1715 return -1 - length;
1716 } else {
1717 commerror = 0;
1718 return length;
1720 } else {
1721 TRACE(comm,"%*s\n", length+status, lpvBuf);
1722 commerror = 0;
1723 return length + status;
1727 /*****************************************************************************
1728 * WriteComm (USER.205)
1730 INT16 WINAPI WriteComm(INT16 fd, LPSTR lpvBuf, INT16 cbWrite)
1732 int length;
1733 struct DosDeviceStruct *ptr;
1735 TRACE(comm,"fd %d, ptr %p, length %d\n",
1736 fd, lpvBuf, cbWrite);
1737 if ((ptr = GetDeviceStruct(fd)) == NULL) {
1738 commerror = IE_BADID;
1739 return -1;
1742 if (ptr->suspended) {
1743 commerror = IE_HARDWARE;
1744 return -1;
1747 TRACE(comm,"%*s\n", cbWrite, lpvBuf );
1748 length = write(fd, (void *) lpvBuf, cbWrite);
1750 if (length == -1) {
1751 commerror = WinError();
1752 return -1;
1753 } else {
1754 commerror = 0;
1755 return length;
1760 /*****************************************************************************
1761 * GetCommTimeouts (KERNEL32.160)
1763 BOOL32 WINAPI GetCommTimeouts(INT32 fd,LPCOMMTIMEOUTS lptimeouts)
1765 FIXME(comm,"(%x,%p):stub.\n",fd,lptimeouts);
1766 return TRUE;
1769 /*****************************************************************************
1770 * SetCommTimeouts (KERNEL32.453)
1772 BOOL32 WINAPI SetCommTimeouts(INT32 fd,LPCOMMTIMEOUTS lptimeouts) {
1773 FIXME(comm,"(%x,%p):stub.\n",fd,lptimeouts);
1774 return TRUE;
1777 /***********************************************************************
1778 * EnableCommNotification (USER.246)
1780 BOOL16 WINAPI EnableCommNotification( INT16 fd, HWND16 hwnd,
1781 INT16 cbWriteNotify, INT16 cbOutQueue )
1783 FIXME(comm, "(%d, %x, %d, %d):stub.\n", fd, hwnd, cbWriteNotify, cbOutQueue);
1784 return TRUE;