Use V_* macros.
[wine/wine64.git] / dlls / user / comm16.c
blob45a831f2292b50b183fd6e29713ce04b943cd600
1 /*
2 * DEC 93 Erik Bos <erik@xs4all.nl>
4 * Copyright 1996 Marcus Meissner
6 * Copyright 2001 Mike McCormack
8 * Mar 31, 1999. Ove Kåven <ovek@arcticnet.no>
9 * - Implemented buffers and EnableCommNotification.
11 * Apr 3, 1999. Lawson Whitney <lawson_whitney@juno.com>
12 * - Fixed the modem control part of EscapeCommFunction16.
14 * Mar 3, 1999. Ove Kåven <ovek@arcticnet.no>
15 * - Use port indices instead of unixfds for win16
16 * - Moved things around (separated win16 and win32 routines)
17 * - Added some hints on how to implement buffers and EnableCommNotification.
19 * May 26, 1997. Fixes and comments by Rick Richardson <rick@dgii.com> [RER]
20 * - ptr->fd wasn't getting cleared on close.
21 * - GetCommEventMask() and GetCommError() didn't do much of anything.
22 * IMHO, they are still wrong, but they at least implement the RXCHAR
23 * event and return I/O queue sizes, which makes the app I'm interested
24 * in (analog devices EZKIT DSP development system) work.
26 * August 12, 1997. Take a bash at SetCommEventMask - Lawson Whitney
27 * <lawson_whitney@juno.com>
28 * July 6, 1998. Fixes and comments by Valentijn Sessink
29 * <vsessink@ic.uva.nl> [V]
30 * Oktober 98, Rein Klazes [RHK]
31 * A program that wants to monitor the modem status line (RLSD/DCD) may
32 * poll the modem status register in the commMask structure. I update the bit
33 * in GetCommError, waiting for an implementation of communication events.
37 #include "config.h"
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <errno.h>
43 #include <ctype.h>
45 #include "windef.h"
46 #include "winbase.h"
47 #include "wingdi.h"
48 #include "winreg.h"
49 #include "winuser.h"
50 #include "wine/winuser16.h"
51 #include "wine/port.h"
52 #include "heap.h"
53 #include "winerror.h"
55 #include "debugtools.h"
57 DEFAULT_DEBUG_CHANNEL(comm);
59 /* window's semi documented modem status register */
60 #define COMM_MSR_OFFSET 35
61 #define MSR_CTS 0x10
62 #define MSR_DSR 0x20
63 #define MSR_RI 0x40
64 #define MSR_RLSD 0x80
65 #define MSR_MASK (MSR_CTS|MSR_DSR|MSR_RI|MSR_RLSD)
67 #define FLAG_LPT 0x80
69 #define MAX_PORTS 9
71 struct DosDeviceStruct {
72 char *devicename; /* /dev/ttyS0 */
73 HANDLE handle;
74 int suspended;
75 int unget,xmit;
76 int baudrate;
77 int evtchar;
78 /* events */
79 int commerror, eventmask;
80 /* buffers */
81 char *inbuf,*outbuf;
82 unsigned ibuf_size,ibuf_head,ibuf_tail;
83 unsigned obuf_size,obuf_head,obuf_tail;
84 /* notifications */
85 int wnd, n_read, n_write;
86 OVERLAPPED read_ov, write_ov;
87 /* save terminal states */
88 DCB16 dcb;
89 /* pointer to unknown(==undocumented) comm structure */
90 LPCVOID *unknown;
93 static struct DosDeviceStruct COM[MAX_PORTS];
94 static struct DosDeviceStruct LPT[MAX_PORTS];
96 /* update window's semi documented modem status register */
97 /* see knowledge base Q101417 */
98 static void COMM_MSRUpdate( HANDLE handle, UCHAR * pMsr )
100 UCHAR tmpmsr=0;
101 DWORD mstat=0;
103 if(!GetCommModemStatus(handle,&mstat))
104 return;
106 if(mstat & MS_CTS_ON) tmpmsr |= MSR_CTS;
107 if(mstat & MS_DSR_ON) tmpmsr |= MSR_DSR;
108 if(mstat & MS_RING_ON) tmpmsr |= MSR_RI;
109 if(mstat & MS_RLSD_ON) tmpmsr |= MSR_RLSD;
110 *pMsr = (*pMsr & ~MSR_MASK) | tmpmsr;
113 void COMM_Init(void)
115 int x;
116 char option[10], temp[256], *btemp;
117 HKEY hkey;
119 for (x=0; x!=MAX_PORTS; x++) {
120 strcpy(option,"COMx");
121 option[3] = '1' + x;
122 option[4] = '\0';
124 /* default value */
125 strcpy(temp, "*");
127 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\serialports", &hkey))
129 DWORD type, count = sizeof(temp);
131 RegQueryValueExA(hkey, option, 0, &type, temp, &count);
132 RegCloseKey(hkey);
135 if (!strcmp(temp, "*") || *temp == '\0')
136 COM[x].devicename = NULL;
137 else {
138 btemp = strchr(temp,',');
139 if (btemp != NULL) {
140 *btemp++ = '\0';
141 COM[x].baudrate = atoi(btemp);
142 } else {
143 COM[x].baudrate = -1;
145 if ((COM[x].devicename = malloc(strlen(temp)+1)) == NULL)
146 WARN("Can't malloc for device info!\n");
147 else {
148 COM[x].handle = 0;
149 strcpy(COM[x].devicename, temp);
151 TRACE("%s = %s\n", option, COM[x].devicename);
154 strcpy(option, "LPTx");
155 option[3] = '1' + x;
156 option[4] = '\0';
158 /* default value */
159 strcpy(temp, "*");
161 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\parallelports", &hkey))
163 DWORD type, count = sizeof(temp);
165 RegQueryValueExA(hkey, option, 0, &type, temp, &count);
166 RegCloseKey(hkey);
169 if (!strcmp(temp, "*") || *temp == '\0')
170 LPT[x].devicename = NULL;
171 else {
172 if ((LPT[x].devicename = malloc(strlen(temp)+1)) == NULL)
173 WARN("Can't malloc for device info!\n");
174 else {
175 LPT[x].handle = 0;
176 strcpy(LPT[x].devicename, temp);
178 TRACE("%s = %s\n", option, LPT[x].devicename);
185 static struct DosDeviceStruct *GetDeviceStruct(int index)
187 if ((index&0x7F)<=MAX_PORTS) {
188 if (!(index&FLAG_LPT)) {
189 if (COM[index].handle)
190 return &COM[index];
191 } else {
192 index &= 0x7f;
193 if (LPT[index].handle)
194 return &LPT[index];
198 return NULL;
201 static int GetCommPort_ov(LPOVERLAPPED ov, int write)
203 int x;
205 for (x=0; x<MAX_PORTS; x++) {
206 if (ov == (write?&COM[x].write_ov:&COM[x].read_ov))
207 return x;
210 return -1;
213 static int ValidCOMPort(int x)
215 return(x < MAX_PORTS ? (int) COM[x].devicename : 0);
218 static int ValidLPTPort(int x)
220 return(x < MAX_PORTS ? (int) LPT[x].devicename : 0);
223 static int WinError(void)
225 TRACE("errno = %d\n", errno);
226 switch (errno) {
227 default:
228 return CE_IOE;
232 static unsigned comm_inbuf(struct DosDeviceStruct *ptr)
234 return ((ptr->ibuf_tail > ptr->ibuf_head) ? ptr->ibuf_size : 0)
235 + ptr->ibuf_head - ptr->ibuf_tail;
238 static unsigned comm_outbuf(struct DosDeviceStruct *ptr)
240 return ((ptr->obuf_tail > ptr->obuf_head) ? ptr->obuf_size : 0)
241 + ptr->obuf_head - ptr->obuf_tail;
244 static void comm_waitread(struct DosDeviceStruct *ptr);
245 static void comm_waitwrite(struct DosDeviceStruct *ptr);
247 static VOID WINAPI COMM16_ReadComplete(DWORD status, DWORD len, LPOVERLAPPED ov)
249 int prev ;
250 WORD mask = 0;
251 int cid = GetCommPort_ov(ov,0);
252 struct DosDeviceStruct *ptr;
254 if(cid<0) {
255 ERR("async write with bad overlapped pointer\n");
256 return;
258 ptr = &COM[cid];
260 /* read data from comm port */
261 if (status != STATUS_SUCCESS) {
262 ERR("async read failed\n");
263 COM[cid].commerror = CE_RXOVER;
264 return;
266 TRACE("async read completed %ld bytes\n",len);
268 prev = comm_inbuf(ptr);
270 /* check for events */
271 if ((ptr->eventmask & EV_RXFLAG) &&
272 memchr(ptr->inbuf + ptr->ibuf_head, ptr->evtchar, len)) {
273 *(WORD*)(COM[cid].unknown) |= EV_RXFLAG;
274 mask |= CN_EVENT;
276 if (ptr->eventmask & EV_RXCHAR) {
277 *(WORD*)(COM[cid].unknown) |= EV_RXCHAR;
278 mask |= CN_EVENT;
281 /* advance buffer position */
282 ptr->ibuf_head += len;
283 if (ptr->ibuf_head >= ptr->ibuf_size)
284 ptr->ibuf_head = 0;
286 /* check for notification */
287 if (ptr->wnd && (ptr->n_read>0) && (prev<ptr->n_read) &&
288 (comm_inbuf(ptr)>=ptr->n_read)) {
289 /* passed the receive notification threshold */
290 mask |= CN_RECEIVE;
293 /* send notifications, if any */
294 if (ptr->wnd && mask) {
295 TRACE("notifying %04x: cid=%d, mask=%02x\n", ptr->wnd, cid, mask);
296 PostMessageA(ptr->wnd, WM_COMMNOTIFY, cid, mask);
299 /* on real windows, this could cause problems, since it is recursive */
300 /* restart the receive */
301 comm_waitread(ptr);
304 static VOID WINAPI COMM16_WriteComplete(DWORD status, DWORD len, LPOVERLAPPED ov)
306 int prev, bleft;
307 WORD mask = 0;
308 int cid = GetCommPort_ov(ov,1);
309 struct DosDeviceStruct *ptr;
311 if(cid<0) {
312 ERR("async write with bad overlapped pointer\n");
313 return;
315 ptr = &COM[cid];
317 /* read data from comm port */
318 if (status != STATUS_SUCCESS) {
319 ERR("async write failed\n");
320 COM[cid].commerror = CE_RXOVER;
321 return;
323 TRACE("async write completed %ld bytes\n",len);
325 /* update the buffer pointers */
326 prev = comm_outbuf(&COM[cid]);
327 ptr->obuf_tail += len;
328 if (ptr->obuf_tail >= ptr->obuf_size)
329 ptr->obuf_tail = 0;
331 /* write any TransmitCommChar character */
332 if (ptr->xmit>=0) {
333 if(!WriteFile(ptr->handle, &(ptr->xmit), 1, &len, NULL))
334 len = -1;
335 if (len > 0) ptr->xmit = -1;
338 /* write from output queue */
339 bleft = ((ptr->obuf_tail <= ptr->obuf_head) ?
340 ptr->obuf_head : ptr->obuf_size) - ptr->obuf_tail;
342 /* check for notification */
343 if (ptr->wnd && (ptr->n_write>0) && (prev>=ptr->n_write) &&
344 (comm_outbuf(ptr)<ptr->n_write)) {
345 /* passed the transmit notification threshold */
346 mask |= CN_TRANSMIT;
349 /* send notifications, if any */
350 if (ptr->wnd && mask) {
351 TRACE("notifying %04x: cid=%d, mask=%02x\n", ptr->wnd, cid, mask);
352 PostMessageA(ptr->wnd, WM_COMMNOTIFY, cid, mask);
355 /* start again if necessary */
356 if(bleft)
357 comm_waitwrite(ptr);
360 static void comm_waitread(struct DosDeviceStruct *ptr)
362 int bleft;
364 bleft = ((ptr->ibuf_tail > ptr->ibuf_head) ?
365 (ptr->ibuf_tail-1) : ptr->ibuf_size) - ptr->ibuf_head;
366 /* FIXME: get timeouts working properly so we can read bleft bytes */
367 ReadFileEx(ptr->handle,
368 ptr->inbuf + ptr->ibuf_head,
370 &ptr->read_ov,
371 COMM16_ReadComplete);
374 static void comm_waitwrite(struct DosDeviceStruct *ptr)
376 int bleft;
378 bleft = ((ptr->obuf_tail <= ptr->obuf_head) ?
379 ptr->obuf_head : ptr->obuf_size) - ptr->obuf_tail;
380 WriteFileEx(ptr->handle,
381 ptr->outbuf + ptr->obuf_tail,
382 bleft,
383 &ptr->write_ov,
384 COMM16_WriteComplete);
387 /*****************************************************************************
388 * COMM16_DCBtoDCB16 (Internal)
390 INT16 COMM16_DCBtoDCB16(LPDCB lpdcb, LPDCB16 lpdcb16)
392 if(lpdcb->BaudRate<0x10000)
393 lpdcb16->BaudRate = lpdcb->BaudRate;
394 else if(lpdcb->BaudRate==115200)
395 lpdcb16->BaudRate = 57601;
396 else {
397 WARN("Baud rate can't be converted\n");
398 lpdcb16->BaudRate = 57601;
400 lpdcb16->ByteSize = lpdcb->ByteSize;
401 lpdcb16->fParity = lpdcb->fParity;
402 lpdcb16->Parity = lpdcb->Parity;
403 lpdcb16->StopBits = lpdcb->StopBits;
405 lpdcb16->RlsTimeout = 50;
406 lpdcb16->CtsTimeout = 50;
407 lpdcb16->DsrTimeout = 50;
408 lpdcb16->fNull = 0;
409 lpdcb16->fChEvt = 0;
410 lpdcb16->fBinary = 1;
411 lpdcb16->fDtrDisable = 0;
413 lpdcb16->fDtrflow = (lpdcb->fDtrControl==DTR_CONTROL_ENABLE);
414 lpdcb16->fRtsflow = (lpdcb->fRtsControl==RTS_CONTROL_ENABLE);
415 lpdcb16->fOutxCtsFlow = lpdcb->fOutxCtsFlow;
416 lpdcb16->fOutxDsrFlow = lpdcb->fOutxDsrFlow;
417 lpdcb16->fDtrDisable = (lpdcb->fDtrControl==DTR_CONTROL_DISABLE);
419 lpdcb16->fInX = lpdcb->fInX;
421 lpdcb16->fOutX = lpdcb->fOutX;
423 lpdcb16->XonChar =
424 lpdcb16->XoffChar =
426 lpdcb16->XonLim = 10;
427 lpdcb16->XoffLim = 10;
429 return 0;
433 /**************************************************************************
434 * BuildCommDCB (USER.213)
436 * According to the ECMA-234 (368.3) the function will return FALSE on
437 * success, otherwise it will return -1.
439 INT16 WINAPI BuildCommDCB16(LPCSTR device, LPDCB16 lpdcb)
441 /* "COM1:96,n,8,1" */
442 /* 012345 */
443 int port;
444 DCB dcb;
446 TRACE("(%s), ptr %p\n", device, lpdcb);
448 if (strncasecmp(device,"COM",3))
449 return -1;
450 port = device[3] - '0';
452 if (port-- == 0) {
453 ERR("BUG ! COM0 can't exist!\n");
454 return -1;
457 if (!ValidCOMPort(port)) {
458 FIXME("invalid COM port %d?\n",port);
459 return -1;
462 memset(lpdcb, 0, sizeof(DCB16)); /* initialize */
464 lpdcb->Id = port;
465 dcb.DCBlength = sizeof(DCB);
467 if (strchr(device,'=')) /* block new style */
468 return -1;
470 if(!BuildCommDCBA(device,&dcb))
471 return -1;
473 return COMM16_DCBtoDCB16(&dcb, lpdcb);
476 /*****************************************************************************
477 * OpenComm (USER.200)
479 INT16 WINAPI OpenComm16(LPCSTR device,UINT16 cbInQueue,UINT16 cbOutQueue)
481 int port;
482 HANDLE handle;
484 TRACE("%s, %d, %d\n", device, cbInQueue, cbOutQueue);
486 if (strlen(device) < 4)
487 return IE_BADID;
489 port = device[3] - '0';
491 if (port-- == 0)
492 ERR("BUG ! COM0 or LPT0 don't exist !\n");
494 if (!strncasecmp(device,"COM",3)) {
496 TRACE("%s = %s\n", device, COM[port].devicename);
498 if (!ValidCOMPort(port))
499 return IE_BADID;
501 if (COM[port].handle)
502 return IE_OPEN;
504 handle = CreateFileA(device, GENERIC_READ|GENERIC_WRITE,
505 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0 );
506 if (handle == INVALID_HANDLE_VALUE) {
507 ERR("Couldn't open %s ! (%s)\n", COM[port].devicename, strerror(errno));
508 return IE_HARDWARE;
509 } else {
510 COM[port].unknown = SEGPTR_ALLOC(40);
511 memset(COM[port].unknown, 0, 40);
512 COM[port].handle = handle;
513 COM[port].commerror = 0;
514 COM[port].eventmask = 0;
515 COM[port].evtchar = 0; /* FIXME: default? */
516 /* save terminal state */
517 GetCommState16(port,&COM[port].dcb);
518 /* set default parameters */
519 if(COM[port].baudrate>-1){
520 DCB16 dcb;
521 memcpy(&dcb,&COM[port].dcb,sizeof dcb);
522 dcb.BaudRate=COM[port].baudrate;
523 /* more defaults:
524 * databits, parity, stopbits
526 SetCommState16( &dcb);
528 /* init priority characters */
529 COM[port].unget = -1;
530 COM[port].xmit = -1;
531 /* allocate buffers */
532 COM[port].ibuf_size = cbInQueue;
533 COM[port].ibuf_head = COM[port].ibuf_tail = 0;
534 COM[port].obuf_size = cbOutQueue;
535 COM[port].obuf_head = COM[port].obuf_tail = 0;
537 COM[port].inbuf = malloc(cbInQueue);
538 if (COM[port].inbuf) {
539 COM[port].outbuf = malloc(cbOutQueue);
540 if (!COM[port].outbuf)
541 free(COM[port].inbuf);
542 } else COM[port].outbuf = NULL;
543 if (!COM[port].outbuf) {
544 /* not enough memory */
545 SetCommState16(&COM[port].dcb);
546 CloseHandle(COM[port].handle);
547 ERR("out of memory\n");
548 return IE_MEMORY;
551 ZeroMemory(&COM[port].read_ov,sizeof (OVERLAPPED));
552 ZeroMemory(&COM[port].write_ov,sizeof (OVERLAPPED));
553 COM[port].read_ov.hEvent = CreateEventA(NULL,0,0,NULL);
554 COM[port].write_ov.hEvent = CreateEventA(NULL,0,0,NULL);
556 comm_waitread( &COM[port] );
558 return port;
561 else
562 if (!strncasecmp(device,"LPT",3)) {
564 if (!ValidLPTPort(port))
565 return IE_BADID;
567 if (LPT[port].handle)
568 return IE_OPEN;
570 handle = CreateFileA(device, GENERIC_READ|GENERIC_WRITE,
571 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0 );
572 if (handle == INVALID_HANDLE_VALUE) {
573 return IE_HARDWARE;
574 } else {
575 LPT[port].handle = handle;
576 LPT[port].commerror = 0;
577 LPT[port].eventmask = 0;
578 return port|FLAG_LPT;
581 return IE_BADID;
584 /*****************************************************************************
585 * CloseComm (USER.207)
587 INT16 WINAPI CloseComm16(INT16 cid)
589 struct DosDeviceStruct *ptr;
591 TRACE("cid=%d\n", cid);
592 if ((ptr = GetDeviceStruct(cid)) == NULL) {
593 FIXME("no cid=%d found!\n", cid);
594 return -1;
596 if (!(cid&FLAG_LPT)) {
597 /* COM port */
598 SEGPTR_FREE(COM[cid].unknown); /* [LW] */
600 CloseHandle(COM[cid].read_ov.hEvent);
601 CloseHandle(COM[cid].write_ov.hEvent);
603 /* free buffers */
604 free(ptr->outbuf);
605 free(ptr->inbuf);
607 /* reset modem lines */
608 SetCommState16(&COM[cid].dcb);
611 if (!CloseHandle(ptr->handle)) {
612 ptr->commerror = WinError();
613 /* FIXME: should we clear ptr->handle here? */
614 return -1;
615 } else {
616 ptr->commerror = 0;
617 ptr->handle = 0;
618 return 0;
622 /*****************************************************************************
623 * SetCommBreak (USER.210)
625 INT16 WINAPI SetCommBreak16(INT16 cid)
627 struct DosDeviceStruct *ptr;
629 TRACE("cid=%d\n", cid);
630 if ((ptr = GetDeviceStruct(cid)) == NULL) {
631 FIXME("no cid=%d found!\n", cid);
632 return -1;
635 ptr->suspended = 1;
636 ptr->commerror = 0;
637 return 0;
640 /*****************************************************************************
641 * ClearCommBreak (USER.211)
643 INT16 WINAPI ClearCommBreak16(INT16 cid)
645 struct DosDeviceStruct *ptr;
647 TRACE("cid=%d\n", cid);
648 if (!(ptr = GetDeviceStruct(cid))) {
649 FIXME("no cid=%d found!\n", cid);
650 return -1;
652 ptr->suspended = 0;
653 ptr->commerror = 0;
654 return 0;
657 /*****************************************************************************
658 * EscapeCommFunction (USER.214)
660 LONG WINAPI EscapeCommFunction16(UINT16 cid,UINT16 nFunction)
662 struct DosDeviceStruct *ptr;
663 int max;
665 TRACE("cid=%d, function=%d\n", cid, nFunction);
667 switch(nFunction) {
668 case GETMAXCOM:
669 TRACE("GETMAXCOM\n");
670 for (max = MAX_PORTS;!COM[max].devicename;max--)
672 return max;
674 case GETMAXLPT:
675 TRACE("GETMAXLPT\n");
676 for (max = MAX_PORTS;!LPT[max].devicename;max--)
678 return FLAG_LPT + max;
680 case GETBASEIRQ:
681 TRACE("GETBASEIRQ\n");
682 /* FIXME: use tables */
683 /* just fake something for now */
684 if (cid & FLAG_LPT) {
685 /* LPT1: irq 7, LPT2: irq 5 */
686 return (cid & 0x7f) ? 5 : 7;
687 } else {
688 /* COM1: irq 4, COM2: irq 3,
689 COM3: irq 4, COM4: irq 3 */
690 return 4 - (cid & 1);
694 if ((ptr = GetDeviceStruct(cid)) == NULL) {
695 FIXME("no cid=%d found!\n", cid);
696 return -1;
699 switch (nFunction) {
700 case RESETDEV:
701 case CLRDTR:
702 case CLRRTS:
703 case SETDTR:
704 case SETRTS:
705 case SETXOFF:
706 case SETXON:
707 if(EscapeCommFunction(ptr->handle,nFunction))
708 return 0;
709 else {
710 ptr->commerror = WinError();
711 return -1;
714 case CLRBREAK:
715 case SETBREAK:
716 default:
717 WARN("(cid=%d,nFunction=%d): Unknown function\n",
718 cid, nFunction);
720 return -1;
723 /*****************************************************************************
724 * FlushComm (USER.215)
726 INT16 WINAPI FlushComm16(INT16 cid,INT16 fnQueue)
728 DWORD queue;
729 struct DosDeviceStruct *ptr;
731 TRACE("cid=%d, queue=%d\n", cid, fnQueue);
732 if ((ptr = GetDeviceStruct(cid)) == NULL) {
733 FIXME("no cid=%d found!\n", cid);
734 return -1;
736 switch (fnQueue) {
737 case 0:
738 queue = PURGE_TXABORT;
739 ptr->obuf_tail = ptr->obuf_head;
740 break;
741 case 1:
742 queue = PURGE_RXABORT;
743 ptr->ibuf_head = ptr->ibuf_tail;
744 break;
745 default:
746 WARN("(cid=%d,fnQueue=%d):Unknown queue\n",
747 cid, fnQueue);
748 return -1;
751 if (!PurgeComm(ptr->handle,queue)) {
752 ptr->commerror = WinError();
753 return -1;
754 } else {
755 ptr->commerror = 0;
756 return 0;
760 /********************************************************************
761 * GetCommError (USER.203)
763 INT16 WINAPI GetCommError16(INT16 cid,LPCOMSTAT16 lpStat)
765 int temperror;
766 struct DosDeviceStruct *ptr;
767 unsigned char *stol;
769 if ((ptr = GetDeviceStruct(cid)) == NULL) {
770 FIXME("no handle for cid = %0x!\n",cid);
771 return -1;
773 if (cid&FLAG_LPT) {
774 WARN(" cid %d not comm port\n",cid);
775 return CE_MODE;
777 stol = (unsigned char *)COM[cid].unknown + COMM_MSR_OFFSET;
778 COMM_MSRUpdate( ptr->handle, stol );
780 if (lpStat) {
781 HANDLE rw_events[2];
783 lpStat->status = 0;
785 rw_events[0] = COM[cid].read_ov.hEvent;
786 rw_events[1] = COM[cid].write_ov.hEvent;
788 WaitForMultipleObjectsEx(2,&rw_events[0],FALSE,1,TRUE);
790 lpStat->cbOutQue = comm_outbuf(ptr);
791 lpStat->cbInQue = comm_inbuf(ptr);
793 TRACE("cid %d, error %d, stat %d in %d out %d, stol %x\n",
794 cid, ptr->commerror, lpStat->status, lpStat->cbInQue,
795 lpStat->cbOutQue, *stol);
797 else
798 TRACE("cid %d, error %d, lpStat NULL stol %x\n",
799 cid, ptr->commerror, *stol);
801 /* Return any errors and clear it */
802 temperror = ptr->commerror;
803 ptr->commerror = 0;
804 return(temperror);
807 /*****************************************************************************
808 * SetCommEventMask (USER.208)
810 SEGPTR WINAPI SetCommEventMask16(INT16 cid,UINT16 fuEvtMask)
812 struct DosDeviceStruct *ptr;
813 unsigned char *stol;
815 TRACE("cid %d,mask %d\n",cid,fuEvtMask);
816 if ((ptr = GetDeviceStruct(cid)) == NULL) {
817 FIXME("no handle for cid = %0x!\n",cid);
818 return (SEGPTR)NULL;
821 ptr->eventmask = fuEvtMask;
823 if ((cid&FLAG_LPT) || !ValidCOMPort(cid)) {
824 WARN(" cid %d not comm port\n",cid);
825 return (SEGPTR)NULL;
827 /* it's a COM port ? -> modify flags */
828 stol = (unsigned char *)COM[cid].unknown + COMM_MSR_OFFSET;
829 COMM_MSRUpdate( ptr->handle, stol );
831 TRACE(" modem dcd construct %x\n",*stol);
832 return SEGPTR_GET(COM[cid].unknown);
835 /*****************************************************************************
836 * GetCommEventMask (USER.209)
838 UINT16 WINAPI GetCommEventMask16(INT16 cid,UINT16 fnEvtClear)
840 struct DosDeviceStruct *ptr;
841 WORD events;
843 TRACE("cid %d, mask %d\n", cid, fnEvtClear);
844 if ((ptr = GetDeviceStruct(cid)) == NULL) {
845 FIXME("no handle for cid = %0x!\n",cid);
846 return 0;
849 if ((cid&FLAG_LPT) || !ValidCOMPort(cid)) {
850 WARN(" cid %d not comm port\n",cid);
851 return 0;
854 events = *(WORD*)(COM[cid].unknown) & fnEvtClear;
855 *(WORD*)(COM[cid].unknown) &= ~fnEvtClear;
856 return events;
859 /*****************************************************************************
860 * SetCommState (USER.201)
862 INT16 WINAPI SetCommState16(LPDCB16 lpdcb)
864 struct DosDeviceStruct *ptr;
865 DCB dcb;
867 TRACE("cid %d, ptr %p\n", lpdcb->Id, lpdcb);
868 if ((ptr = GetDeviceStruct(lpdcb->Id)) == NULL) {
869 FIXME("no handle for cid = %0x!\n",lpdcb->Id);
870 return -1;
873 memset(&dcb,0,sizeof dcb);
874 dcb.DCBlength = sizeof dcb;
875 if(lpdcb->BaudRate==57601)
876 dcb.BaudRate = 115200;
877 else
878 dcb.BaudRate = lpdcb->BaudRate;
880 dcb.ByteSize=lpdcb->ByteSize;
881 dcb.StopBits=lpdcb->StopBits;
883 dcb.fParity=lpdcb->fParity;
884 dcb.Parity=lpdcb->Parity;
886 dcb.fOutxCtsFlow = lpdcb->fOutxCtsFlow;
888 if (lpdcb->fDtrflow || lpdcb->fRtsflow)
889 dcb.fRtsControl = TRUE;
891 if (lpdcb->fDtrDisable)
892 dcb.fDtrControl = TRUE;
894 ptr->evtchar = lpdcb->EvtChar;
896 dcb.fInX = lpdcb->fInX;
897 dcb.fOutX = lpdcb->fOutX;
899 if (!SetCommState(ptr->handle,&dcb)) {
900 ptr->commerror = WinError();
901 return -1;
902 } else {
903 ptr->commerror = 0;
904 return 0;
908 /*****************************************************************************
909 * GetCommState (USER.202)
911 INT16 WINAPI GetCommState16(INT16 cid, LPDCB16 lpdcb)
913 struct DosDeviceStruct *ptr;
914 DCB dcb;
916 TRACE("cid %d, ptr %p\n", cid, lpdcb);
917 if ((ptr = GetDeviceStruct(cid)) == NULL) {
918 FIXME("no handle for cid = %0x!\n",cid);
919 return -1;
921 if (!GetCommState(ptr->handle,&dcb)) {
922 ptr->commerror = WinError();
923 return -1;
926 lpdcb->Id = cid;
928 COMM16_DCBtoDCB16(&dcb,lpdcb);
930 lpdcb->EvtChar = ptr->evtchar;
932 ptr->commerror = 0;
933 return 0;
936 /*****************************************************************************
937 * TransmitCommChar (USER.206)
939 INT16 WINAPI TransmitCommChar16(INT16 cid,CHAR chTransmit)
941 struct DosDeviceStruct *ptr;
943 TRACE("cid %d, data %d \n", cid, chTransmit);
944 if ((ptr = GetDeviceStruct(cid)) == NULL) {
945 FIXME("no handle for cid = %0x!\n",cid);
946 return -1;
949 if (ptr->suspended) {
950 ptr->commerror = IE_HARDWARE;
951 return -1;
954 if (ptr->xmit >= 0) {
955 /* character already queued */
956 /* FIXME: which error would Windows return? */
957 ptr->commerror = CE_TXFULL;
958 return -1;
961 if (ptr->obuf_head == ptr->obuf_tail) {
962 /* transmit queue empty, try to transmit directly */
963 DWORD len;
964 if(!WriteFile(ptr->handle, &chTransmit, 1, &len, NULL)) {
965 /* didn't work, queue it */
966 ptr->xmit = chTransmit;
967 comm_waitwrite(ptr);
969 } else {
970 /* data in queue, let this char be transmitted next */
971 ptr->xmit = chTransmit;
972 comm_waitwrite(ptr);
975 ptr->commerror = 0;
976 return 0;
979 /*****************************************************************************
980 * UngetCommChar (USER.212)
982 INT16 WINAPI UngetCommChar16(INT16 cid,CHAR chUnget)
984 struct DosDeviceStruct *ptr;
986 TRACE("cid %d (char %d)\n", cid, chUnget);
987 if ((ptr = GetDeviceStruct(cid)) == NULL) {
988 FIXME("no handle for cid = %0x!\n",cid);
989 return -1;
992 if (ptr->suspended) {
993 ptr->commerror = IE_HARDWARE;
994 return -1;
997 if (ptr->unget>=0) {
998 /* character already queued */
999 /* FIXME: which error would Windows return? */
1000 ptr->commerror = CE_RXOVER;
1001 return -1;
1004 ptr->unget = chUnget;
1006 ptr->commerror = 0;
1007 return 0;
1010 /*****************************************************************************
1011 * ReadComm (USER.204)
1013 INT16 WINAPI ReadComm16(INT16 cid,LPSTR lpvBuf,INT16 cbRead)
1015 int status, length;
1016 struct DosDeviceStruct *ptr;
1017 LPSTR orgBuf = lpvBuf;
1019 TRACE("cid %d, ptr %p, length %d\n", cid, lpvBuf, cbRead);
1020 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1021 FIXME("no handle for cid = %0x!\n",cid);
1022 return -1;
1025 if (ptr->suspended) {
1026 ptr->commerror = IE_HARDWARE;
1027 return -1;
1030 /* read unget character */
1031 if (ptr->unget>=0) {
1032 *lpvBuf++ = ptr->unget;
1033 ptr->unget = -1;
1035 length = 1;
1036 } else
1037 length = 0;
1039 /* read from receive buffer */
1040 while (length < cbRead) {
1041 status = ((ptr->ibuf_head < ptr->ibuf_tail) ?
1042 ptr->ibuf_size : ptr->ibuf_head) - ptr->ibuf_tail;
1043 if (!status) break;
1044 if ((cbRead - length) < status)
1045 status = cbRead - length;
1047 memcpy(lpvBuf, ptr->inbuf + ptr->ibuf_tail, status);
1048 ptr->ibuf_tail += status;
1049 if (ptr->ibuf_tail >= ptr->ibuf_size)
1050 ptr->ibuf_tail = 0;
1051 lpvBuf += status;
1052 length += status;
1055 TRACE("%.*s\n", length, orgBuf);
1056 ptr->commerror = 0;
1057 return length;
1060 /*****************************************************************************
1061 * WriteComm (USER.205)
1063 INT16 WINAPI WriteComm16(INT16 cid, LPSTR lpvBuf, INT16 cbWrite)
1065 int status, length;
1066 struct DosDeviceStruct *ptr;
1068 TRACE("cid %d, ptr %p, length %d\n",
1069 cid, lpvBuf, cbWrite);
1070 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1071 FIXME("no handle for cid = %0x!\n",cid);
1072 return -1;
1075 if (ptr->suspended) {
1076 ptr->commerror = IE_HARDWARE;
1077 return -1;
1080 TRACE("%.*s\n", cbWrite, lpvBuf );
1082 length = 0;
1083 while (length < cbWrite) {
1084 if ((ptr->obuf_head == ptr->obuf_tail) && (ptr->xmit < 0)) {
1085 /* no data queued, try to write directly */
1086 if(!WriteFile(ptr->handle, lpvBuf, cbWrite - length, (LPDWORD)&status, NULL))
1087 status = -1;
1088 if (status > 0) {
1089 lpvBuf += status;
1090 length += status;
1091 continue;
1094 /* can't write directly, put into transmit buffer */
1095 status = ((ptr->obuf_tail > ptr->obuf_head) ?
1096 (ptr->obuf_tail-1) : ptr->obuf_size) - ptr->obuf_head;
1097 if (!status) break;
1098 if ((cbWrite - length) < status)
1099 status = cbWrite - length;
1100 memcpy(lpvBuf, ptr->outbuf + ptr->obuf_head, status);
1101 ptr->obuf_head += status;
1102 if (ptr->obuf_head >= ptr->obuf_size)
1103 ptr->obuf_head = 0;
1104 lpvBuf += status;
1105 length += status;
1106 comm_waitwrite(ptr);
1109 ptr->commerror = 0;
1110 return length;
1113 /***********************************************************************
1114 * EnableCommNotification (USER.245)
1116 BOOL16 WINAPI EnableCommNotification16( INT16 cid, HWND16 hwnd,
1117 INT16 cbWriteNotify, INT16 cbOutQueue )
1119 struct DosDeviceStruct *ptr;
1121 TRACE("(%d, %x, %d, %d)\n", cid, hwnd, cbWriteNotify, cbOutQueue);
1122 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1123 FIXME("no handle for cid = %0x!\n",cid);
1124 return -1;
1126 ptr->wnd = hwnd;
1127 ptr->n_read = cbWriteNotify;
1128 ptr->n_write = cbOutQueue;
1129 return TRUE;