Make sure that HWND comparisons are always done with full 32-bit
[wine/multimedia.git] / dlls / user / comm16.c
bloba07b5726c515bb93561cc248424361b9ebf89ef4
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 "win.h"
54 #include "winerror.h"
56 #include "debugtools.h"
58 DEFAULT_DEBUG_CHANNEL(comm);
60 /* window's semi documented modem status register */
61 #define COMM_MSR_OFFSET 35
62 #define MSR_CTS 0x10
63 #define MSR_DSR 0x20
64 #define MSR_RI 0x40
65 #define MSR_RLSD 0x80
66 #define MSR_MASK (MSR_CTS|MSR_DSR|MSR_RI|MSR_RLSD)
68 #define FLAG_LPT 0x80
70 #define MAX_PORTS 9
72 struct DosDeviceStruct {
73 char *devicename; /* /dev/ttyS0 */
74 HANDLE handle;
75 int suspended;
76 int unget,xmit;
77 int baudrate;
78 int evtchar;
79 /* events */
80 int commerror, eventmask;
81 /* buffers */
82 char *inbuf,*outbuf;
83 unsigned ibuf_size,ibuf_head,ibuf_tail;
84 unsigned obuf_size,obuf_head,obuf_tail;
85 /* notifications */
86 HWND wnd;
87 int n_read, n_write;
88 OVERLAPPED read_ov, write_ov;
89 /* save terminal states */
90 DCB16 dcb;
91 /* pointer to unknown(==undocumented) comm structure */
92 LPCVOID *unknown;
95 static struct DosDeviceStruct COM[MAX_PORTS];
96 static struct DosDeviceStruct LPT[MAX_PORTS];
98 /* update window's semi documented modem status register */
99 /* see knowledge base Q101417 */
100 static void COMM_MSRUpdate( HANDLE handle, UCHAR * pMsr )
102 UCHAR tmpmsr=0;
103 DWORD mstat=0;
105 if(!GetCommModemStatus(handle,&mstat))
106 return;
108 if(mstat & MS_CTS_ON) tmpmsr |= MSR_CTS;
109 if(mstat & MS_DSR_ON) tmpmsr |= MSR_DSR;
110 if(mstat & MS_RING_ON) tmpmsr |= MSR_RI;
111 if(mstat & MS_RLSD_ON) tmpmsr |= MSR_RLSD;
112 *pMsr = (*pMsr & ~MSR_MASK) | tmpmsr;
115 void COMM_Init(void)
117 int x;
118 char option[10], temp[256], *btemp;
119 HKEY hkey;
121 for (x=0; x!=MAX_PORTS; x++) {
122 strcpy(option,"COMx");
123 option[3] = '1' + x;
124 option[4] = '\0';
126 /* default value */
127 strcpy(temp, "*");
129 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\serialports", &hkey))
131 DWORD type, count = sizeof(temp);
133 RegQueryValueExA(hkey, option, 0, &type, temp, &count);
134 RegCloseKey(hkey);
137 if (!strcmp(temp, "*") || *temp == '\0')
138 COM[x].devicename = NULL;
139 else {
140 btemp = strchr(temp,',');
141 if (btemp != NULL) {
142 *btemp++ = '\0';
143 COM[x].baudrate = atoi(btemp);
144 } else {
145 COM[x].baudrate = -1;
147 if ((COM[x].devicename = malloc(strlen(temp)+1)) == NULL)
148 WARN("Can't malloc for device info!\n");
149 else {
150 COM[x].handle = 0;
151 strcpy(COM[x].devicename, temp);
153 TRACE("%s = %s\n", option, COM[x].devicename);
156 strcpy(option, "LPTx");
157 option[3] = '1' + x;
158 option[4] = '\0';
160 /* default value */
161 strcpy(temp, "*");
163 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\parallelports", &hkey))
165 DWORD type, count = sizeof(temp);
167 RegQueryValueExA(hkey, option, 0, &type, temp, &count);
168 RegCloseKey(hkey);
171 if (!strcmp(temp, "*") || *temp == '\0')
172 LPT[x].devicename = NULL;
173 else {
174 if ((LPT[x].devicename = malloc(strlen(temp)+1)) == NULL)
175 WARN("Can't malloc for device info!\n");
176 else {
177 LPT[x].handle = 0;
178 strcpy(LPT[x].devicename, temp);
180 TRACE("%s = %s\n", option, LPT[x].devicename);
187 static struct DosDeviceStruct *GetDeviceStruct(int index)
189 if ((index&0x7F)<=MAX_PORTS) {
190 if (!(index&FLAG_LPT)) {
191 if (COM[index].handle)
192 return &COM[index];
193 } else {
194 index &= 0x7f;
195 if (LPT[index].handle)
196 return &LPT[index];
200 return NULL;
203 static int GetCommPort_ov(LPOVERLAPPED ov, int write)
205 int x;
207 for (x=0; x<MAX_PORTS; x++) {
208 if (ov == (write?&COM[x].write_ov:&COM[x].read_ov))
209 return x;
212 return -1;
215 static int ValidCOMPort(int x)
217 return(x < MAX_PORTS ? (int) COM[x].devicename : 0);
220 static int ValidLPTPort(int x)
222 return(x < MAX_PORTS ? (int) LPT[x].devicename : 0);
225 static int WinError(void)
227 TRACE("errno = %d\n", errno);
228 switch (errno) {
229 default:
230 return CE_IOE;
234 static unsigned comm_inbuf(struct DosDeviceStruct *ptr)
236 return ((ptr->ibuf_tail > ptr->ibuf_head) ? ptr->ibuf_size : 0)
237 + ptr->ibuf_head - ptr->ibuf_tail;
240 static unsigned comm_outbuf(struct DosDeviceStruct *ptr)
242 return ((ptr->obuf_tail > ptr->obuf_head) ? ptr->obuf_size : 0)
243 + ptr->obuf_head - ptr->obuf_tail;
246 static void comm_waitread(struct DosDeviceStruct *ptr);
247 static void comm_waitwrite(struct DosDeviceStruct *ptr);
249 static VOID WINAPI COMM16_ReadComplete(DWORD status, DWORD len, LPOVERLAPPED ov)
251 int prev ;
252 WORD mask = 0;
253 int cid = GetCommPort_ov(ov,0);
254 struct DosDeviceStruct *ptr;
256 if(cid<0) {
257 ERR("async write with bad overlapped pointer\n");
258 return;
260 ptr = &COM[cid];
262 /* read data from comm port */
263 if (status != STATUS_SUCCESS) {
264 ERR("async read failed\n");
265 COM[cid].commerror = CE_RXOVER;
266 return;
268 TRACE("async read completed %ld bytes\n",len);
270 prev = comm_inbuf(ptr);
272 /* check for events */
273 if ((ptr->eventmask & EV_RXFLAG) &&
274 memchr(ptr->inbuf + ptr->ibuf_head, ptr->evtchar, len)) {
275 *(WORD*)(COM[cid].unknown) |= EV_RXFLAG;
276 mask |= CN_EVENT;
278 if (ptr->eventmask & EV_RXCHAR) {
279 *(WORD*)(COM[cid].unknown) |= EV_RXCHAR;
280 mask |= CN_EVENT;
283 /* advance buffer position */
284 ptr->ibuf_head += len;
285 if (ptr->ibuf_head >= ptr->ibuf_size)
286 ptr->ibuf_head = 0;
288 /* check for notification */
289 if (ptr->wnd && (ptr->n_read>0) && (prev<ptr->n_read) &&
290 (comm_inbuf(ptr)>=ptr->n_read)) {
291 /* passed the receive notification threshold */
292 mask |= CN_RECEIVE;
295 /* send notifications, if any */
296 if (ptr->wnd && mask) {
297 TRACE("notifying %04x: cid=%d, mask=%02x\n", ptr->wnd, cid, mask);
298 PostMessageA(ptr->wnd, WM_COMMNOTIFY, cid, mask);
301 /* on real windows, this could cause problems, since it is recursive */
302 /* restart the receive */
303 comm_waitread(ptr);
306 static VOID WINAPI COMM16_WriteComplete(DWORD status, DWORD len, LPOVERLAPPED ov)
308 int prev, bleft;
309 WORD mask = 0;
310 int cid = GetCommPort_ov(ov,1);
311 struct DosDeviceStruct *ptr;
313 if(cid<0) {
314 ERR("async write with bad overlapped pointer\n");
315 return;
317 ptr = &COM[cid];
319 /* read data from comm port */
320 if (status != STATUS_SUCCESS) {
321 ERR("async write failed\n");
322 COM[cid].commerror = CE_RXOVER;
323 return;
325 TRACE("async write completed %ld bytes\n",len);
327 /* update the buffer pointers */
328 prev = comm_outbuf(&COM[cid]);
329 ptr->obuf_tail += len;
330 if (ptr->obuf_tail >= ptr->obuf_size)
331 ptr->obuf_tail = 0;
333 /* write any TransmitCommChar character */
334 if (ptr->xmit>=0) {
335 if(!WriteFile(ptr->handle, &(ptr->xmit), 1, &len, NULL))
336 len = -1;
337 if (len > 0) ptr->xmit = -1;
340 /* write from output queue */
341 bleft = ((ptr->obuf_tail <= ptr->obuf_head) ?
342 ptr->obuf_head : ptr->obuf_size) - ptr->obuf_tail;
344 /* check for notification */
345 if (ptr->wnd && (ptr->n_write>0) && (prev>=ptr->n_write) &&
346 (comm_outbuf(ptr)<ptr->n_write)) {
347 /* passed the transmit notification threshold */
348 mask |= CN_TRANSMIT;
351 /* send notifications, if any */
352 if (ptr->wnd && mask) {
353 TRACE("notifying %04x: cid=%d, mask=%02x\n", ptr->wnd, cid, mask);
354 PostMessageA(ptr->wnd, WM_COMMNOTIFY, cid, mask);
357 /* start again if necessary */
358 if(bleft)
359 comm_waitwrite(ptr);
362 static void comm_waitread(struct DosDeviceStruct *ptr)
364 int bleft;
366 bleft = ((ptr->ibuf_tail > ptr->ibuf_head) ?
367 (ptr->ibuf_tail-1) : ptr->ibuf_size) - ptr->ibuf_head;
368 /* FIXME: get timeouts working properly so we can read bleft bytes */
369 ReadFileEx(ptr->handle,
370 ptr->inbuf + ptr->ibuf_head,
372 &ptr->read_ov,
373 COMM16_ReadComplete);
376 static void comm_waitwrite(struct DosDeviceStruct *ptr)
378 int bleft;
380 bleft = ((ptr->obuf_tail <= ptr->obuf_head) ?
381 ptr->obuf_head : ptr->obuf_size) - ptr->obuf_tail;
382 WriteFileEx(ptr->handle,
383 ptr->outbuf + ptr->obuf_tail,
384 bleft,
385 &ptr->write_ov,
386 COMM16_WriteComplete);
389 /*****************************************************************************
390 * COMM16_DCBtoDCB16 (Internal)
392 INT16 COMM16_DCBtoDCB16(LPDCB lpdcb, LPDCB16 lpdcb16)
394 if(lpdcb->BaudRate<0x10000)
395 lpdcb16->BaudRate = lpdcb->BaudRate;
396 else if(lpdcb->BaudRate==115200)
397 lpdcb16->BaudRate = 57601;
398 else {
399 WARN("Baud rate can't be converted\n");
400 lpdcb16->BaudRate = 57601;
402 lpdcb16->ByteSize = lpdcb->ByteSize;
403 lpdcb16->fParity = lpdcb->fParity;
404 lpdcb16->Parity = lpdcb->Parity;
405 lpdcb16->StopBits = lpdcb->StopBits;
407 lpdcb16->RlsTimeout = 50;
408 lpdcb16->CtsTimeout = 50;
409 lpdcb16->DsrTimeout = 50;
410 lpdcb16->fNull = 0;
411 lpdcb16->fChEvt = 0;
412 lpdcb16->fBinary = 1;
413 lpdcb16->fDtrDisable = 0;
415 lpdcb16->fDtrflow = (lpdcb->fDtrControl==DTR_CONTROL_ENABLE);
416 lpdcb16->fRtsflow = (lpdcb->fRtsControl==RTS_CONTROL_ENABLE);
417 lpdcb16->fOutxCtsFlow = lpdcb->fOutxCtsFlow;
418 lpdcb16->fOutxDsrFlow = lpdcb->fOutxDsrFlow;
419 lpdcb16->fDtrDisable = (lpdcb->fDtrControl==DTR_CONTROL_DISABLE);
421 lpdcb16->fInX = lpdcb->fInX;
423 lpdcb16->fOutX = lpdcb->fOutX;
425 lpdcb16->XonChar =
426 lpdcb16->XoffChar =
428 lpdcb16->XonLim = 10;
429 lpdcb16->XoffLim = 10;
431 return 0;
435 /**************************************************************************
436 * BuildCommDCB (USER.213)
438 * According to the ECMA-234 (368.3) the function will return FALSE on
439 * success, otherwise it will return -1.
441 INT16 WINAPI BuildCommDCB16(LPCSTR device, LPDCB16 lpdcb)
443 /* "COM1:96,n,8,1" */
444 /* 012345 */
445 int port;
446 DCB dcb;
448 TRACE("(%s), ptr %p\n", device, lpdcb);
450 if (strncasecmp(device,"COM",3))
451 return -1;
452 port = device[3] - '0';
454 if (port-- == 0) {
455 ERR("BUG ! COM0 can't exist!\n");
456 return -1;
459 if (!ValidCOMPort(port)) {
460 FIXME("invalid COM port %d?\n",port);
461 return -1;
464 memset(lpdcb, 0, sizeof(DCB16)); /* initialize */
466 lpdcb->Id = port;
467 dcb.DCBlength = sizeof(DCB);
469 if (strchr(device,'=')) /* block new style */
470 return -1;
472 if(!BuildCommDCBA(device,&dcb))
473 return -1;
475 return COMM16_DCBtoDCB16(&dcb, lpdcb);
478 /*****************************************************************************
479 * OpenComm (USER.200)
481 INT16 WINAPI OpenComm16(LPCSTR device,UINT16 cbInQueue,UINT16 cbOutQueue)
483 int port;
484 HANDLE handle;
486 TRACE("%s, %d, %d\n", device, cbInQueue, cbOutQueue);
488 if (strlen(device) < 4)
489 return IE_BADID;
491 port = device[3] - '0';
493 if (port-- == 0)
494 ERR("BUG ! COM0 or LPT0 don't exist !\n");
496 if (!strncasecmp(device,"COM",3)) {
498 TRACE("%s = %s\n", device, COM[port].devicename);
500 if (!ValidCOMPort(port))
501 return IE_BADID;
503 if (COM[port].handle)
504 return IE_OPEN;
506 handle = CreateFileA(device, GENERIC_READ|GENERIC_WRITE,
507 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0 );
508 if (handle == INVALID_HANDLE_VALUE) {
509 ERR("Couldn't open %s ! (%s)\n", COM[port].devicename, strerror(errno));
510 return IE_HARDWARE;
511 } else {
512 COM[port].unknown = SEGPTR_ALLOC(40);
513 memset(COM[port].unknown, 0, 40);
514 COM[port].handle = handle;
515 COM[port].commerror = 0;
516 COM[port].eventmask = 0;
517 COM[port].evtchar = 0; /* FIXME: default? */
518 /* save terminal state */
519 GetCommState16(port,&COM[port].dcb);
520 /* set default parameters */
521 if(COM[port].baudrate>-1){
522 DCB16 dcb;
523 memcpy(&dcb,&COM[port].dcb,sizeof dcb);
524 dcb.BaudRate=COM[port].baudrate;
525 /* more defaults:
526 * databits, parity, stopbits
528 SetCommState16( &dcb);
530 /* init priority characters */
531 COM[port].unget = -1;
532 COM[port].xmit = -1;
533 /* allocate buffers */
534 COM[port].ibuf_size = cbInQueue;
535 COM[port].ibuf_head = COM[port].ibuf_tail = 0;
536 COM[port].obuf_size = cbOutQueue;
537 COM[port].obuf_head = COM[port].obuf_tail = 0;
539 COM[port].inbuf = malloc(cbInQueue);
540 if (COM[port].inbuf) {
541 COM[port].outbuf = malloc(cbOutQueue);
542 if (!COM[port].outbuf)
543 free(COM[port].inbuf);
544 } else COM[port].outbuf = NULL;
545 if (!COM[port].outbuf) {
546 /* not enough memory */
547 SetCommState16(&COM[port].dcb);
548 CloseHandle(COM[port].handle);
549 ERR("out of memory\n");
550 return IE_MEMORY;
553 ZeroMemory(&COM[port].read_ov,sizeof (OVERLAPPED));
554 ZeroMemory(&COM[port].write_ov,sizeof (OVERLAPPED));
555 COM[port].read_ov.hEvent = CreateEventA(NULL,0,0,NULL);
556 COM[port].write_ov.hEvent = CreateEventA(NULL,0,0,NULL);
558 comm_waitread( &COM[port] );
560 return port;
563 else
564 if (!strncasecmp(device,"LPT",3)) {
566 if (!ValidLPTPort(port))
567 return IE_BADID;
569 if (LPT[port].handle)
570 return IE_OPEN;
572 handle = CreateFileA(device, GENERIC_READ|GENERIC_WRITE,
573 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0 );
574 if (handle == INVALID_HANDLE_VALUE) {
575 return IE_HARDWARE;
576 } else {
577 LPT[port].handle = handle;
578 LPT[port].commerror = 0;
579 LPT[port].eventmask = 0;
580 return port|FLAG_LPT;
583 return IE_BADID;
586 /*****************************************************************************
587 * CloseComm (USER.207)
589 INT16 WINAPI CloseComm16(INT16 cid)
591 struct DosDeviceStruct *ptr;
593 TRACE("cid=%d\n", cid);
594 if ((ptr = GetDeviceStruct(cid)) == NULL) {
595 FIXME("no cid=%d found!\n", cid);
596 return -1;
598 if (!(cid&FLAG_LPT)) {
599 /* COM port */
600 SEGPTR_FREE(COM[cid].unknown); /* [LW] */
602 CloseHandle(COM[cid].read_ov.hEvent);
603 CloseHandle(COM[cid].write_ov.hEvent);
605 /* free buffers */
606 free(ptr->outbuf);
607 free(ptr->inbuf);
609 /* reset modem lines */
610 SetCommState16(&COM[cid].dcb);
613 if (!CloseHandle(ptr->handle)) {
614 ptr->commerror = WinError();
615 /* FIXME: should we clear ptr->handle here? */
616 return -1;
617 } else {
618 ptr->commerror = 0;
619 ptr->handle = 0;
620 return 0;
624 /*****************************************************************************
625 * SetCommBreak (USER.210)
627 INT16 WINAPI SetCommBreak16(INT16 cid)
629 struct DosDeviceStruct *ptr;
631 TRACE("cid=%d\n", cid);
632 if ((ptr = GetDeviceStruct(cid)) == NULL) {
633 FIXME("no cid=%d found!\n", cid);
634 return -1;
637 ptr->suspended = 1;
638 ptr->commerror = 0;
639 return 0;
642 /*****************************************************************************
643 * ClearCommBreak (USER.211)
645 INT16 WINAPI ClearCommBreak16(INT16 cid)
647 struct DosDeviceStruct *ptr;
649 TRACE("cid=%d\n", cid);
650 if (!(ptr = GetDeviceStruct(cid))) {
651 FIXME("no cid=%d found!\n", cid);
652 return -1;
654 ptr->suspended = 0;
655 ptr->commerror = 0;
656 return 0;
659 /*****************************************************************************
660 * EscapeCommFunction (USER.214)
662 LONG WINAPI EscapeCommFunction16(UINT16 cid,UINT16 nFunction)
664 struct DosDeviceStruct *ptr;
665 int max;
667 TRACE("cid=%d, function=%d\n", cid, nFunction);
669 switch(nFunction) {
670 case GETMAXCOM:
671 TRACE("GETMAXCOM\n");
672 for (max = MAX_PORTS;!COM[max].devicename;max--)
674 return max;
676 case GETMAXLPT:
677 TRACE("GETMAXLPT\n");
678 for (max = MAX_PORTS;!LPT[max].devicename;max--)
680 return FLAG_LPT + max;
682 case GETBASEIRQ:
683 TRACE("GETBASEIRQ\n");
684 /* FIXME: use tables */
685 /* just fake something for now */
686 if (cid & FLAG_LPT) {
687 /* LPT1: irq 7, LPT2: irq 5 */
688 return (cid & 0x7f) ? 5 : 7;
689 } else {
690 /* COM1: irq 4, COM2: irq 3,
691 COM3: irq 4, COM4: irq 3 */
692 return 4 - (cid & 1);
696 if ((ptr = GetDeviceStruct(cid)) == NULL) {
697 FIXME("no cid=%d found!\n", cid);
698 return -1;
701 switch (nFunction) {
702 case RESETDEV:
703 case CLRDTR:
704 case CLRRTS:
705 case SETDTR:
706 case SETRTS:
707 case SETXOFF:
708 case SETXON:
709 if(EscapeCommFunction(ptr->handle,nFunction))
710 return 0;
711 else {
712 ptr->commerror = WinError();
713 return -1;
716 case CLRBREAK:
717 case SETBREAK:
718 default:
719 WARN("(cid=%d,nFunction=%d): Unknown function\n",
720 cid, nFunction);
722 return -1;
725 /*****************************************************************************
726 * FlushComm (USER.215)
728 INT16 WINAPI FlushComm16(INT16 cid,INT16 fnQueue)
730 DWORD queue;
731 struct DosDeviceStruct *ptr;
733 TRACE("cid=%d, queue=%d\n", cid, fnQueue);
734 if ((ptr = GetDeviceStruct(cid)) == NULL) {
735 FIXME("no cid=%d found!\n", cid);
736 return -1;
738 switch (fnQueue) {
739 case 0:
740 queue = PURGE_TXABORT;
741 ptr->obuf_tail = ptr->obuf_head;
742 break;
743 case 1:
744 queue = PURGE_RXABORT;
745 ptr->ibuf_head = ptr->ibuf_tail;
746 break;
747 default:
748 WARN("(cid=%d,fnQueue=%d):Unknown queue\n",
749 cid, fnQueue);
750 return -1;
753 if (!PurgeComm(ptr->handle,queue)) {
754 ptr->commerror = WinError();
755 return -1;
756 } else {
757 ptr->commerror = 0;
758 return 0;
762 /********************************************************************
763 * GetCommError (USER.203)
765 INT16 WINAPI GetCommError16(INT16 cid,LPCOMSTAT16 lpStat)
767 int temperror;
768 struct DosDeviceStruct *ptr;
769 unsigned char *stol;
771 if ((ptr = GetDeviceStruct(cid)) == NULL) {
772 FIXME("no handle for cid = %0x!\n",cid);
773 return -1;
775 if (cid&FLAG_LPT) {
776 WARN(" cid %d not comm port\n",cid);
777 return CE_MODE;
779 stol = (unsigned char *)COM[cid].unknown + COMM_MSR_OFFSET;
780 COMM_MSRUpdate( ptr->handle, stol );
782 if (lpStat) {
783 HANDLE rw_events[2];
785 lpStat->status = 0;
787 rw_events[0] = COM[cid].read_ov.hEvent;
788 rw_events[1] = COM[cid].write_ov.hEvent;
790 WaitForMultipleObjectsEx(2,&rw_events[0],FALSE,1,TRUE);
792 lpStat->cbOutQue = comm_outbuf(ptr);
793 lpStat->cbInQue = comm_inbuf(ptr);
795 TRACE("cid %d, error %d, stat %d in %d out %d, stol %x\n",
796 cid, ptr->commerror, lpStat->status, lpStat->cbInQue,
797 lpStat->cbOutQue, *stol);
799 else
800 TRACE("cid %d, error %d, lpStat NULL stol %x\n",
801 cid, ptr->commerror, *stol);
803 /* Return any errors and clear it */
804 temperror = ptr->commerror;
805 ptr->commerror = 0;
806 return(temperror);
809 /*****************************************************************************
810 * SetCommEventMask (USER.208)
812 SEGPTR WINAPI SetCommEventMask16(INT16 cid,UINT16 fuEvtMask)
814 struct DosDeviceStruct *ptr;
815 unsigned char *stol;
817 TRACE("cid %d,mask %d\n",cid,fuEvtMask);
818 if ((ptr = GetDeviceStruct(cid)) == NULL) {
819 FIXME("no handle for cid = %0x!\n",cid);
820 return (SEGPTR)NULL;
823 ptr->eventmask = fuEvtMask;
825 if ((cid&FLAG_LPT) || !ValidCOMPort(cid)) {
826 WARN(" cid %d not comm port\n",cid);
827 return (SEGPTR)NULL;
829 /* it's a COM port ? -> modify flags */
830 stol = (unsigned char *)COM[cid].unknown + COMM_MSR_OFFSET;
831 COMM_MSRUpdate( ptr->handle, stol );
833 TRACE(" modem dcd construct %x\n",*stol);
834 return SEGPTR_GET(COM[cid].unknown);
837 /*****************************************************************************
838 * GetCommEventMask (USER.209)
840 UINT16 WINAPI GetCommEventMask16(INT16 cid,UINT16 fnEvtClear)
842 struct DosDeviceStruct *ptr;
843 WORD events;
845 TRACE("cid %d, mask %d\n", cid, fnEvtClear);
846 if ((ptr = GetDeviceStruct(cid)) == NULL) {
847 FIXME("no handle for cid = %0x!\n",cid);
848 return 0;
851 if ((cid&FLAG_LPT) || !ValidCOMPort(cid)) {
852 WARN(" cid %d not comm port\n",cid);
853 return 0;
856 events = *(WORD*)(COM[cid].unknown) & fnEvtClear;
857 *(WORD*)(COM[cid].unknown) &= ~fnEvtClear;
858 return events;
861 /*****************************************************************************
862 * SetCommState (USER.201)
864 INT16 WINAPI SetCommState16(LPDCB16 lpdcb)
866 struct DosDeviceStruct *ptr;
867 DCB dcb;
869 TRACE("cid %d, ptr %p\n", lpdcb->Id, lpdcb);
870 if ((ptr = GetDeviceStruct(lpdcb->Id)) == NULL) {
871 FIXME("no handle for cid = %0x!\n",lpdcb->Id);
872 return -1;
875 memset(&dcb,0,sizeof dcb);
876 dcb.DCBlength = sizeof dcb;
877 if(lpdcb->BaudRate==57601)
878 dcb.BaudRate = 115200;
879 else
880 dcb.BaudRate = lpdcb->BaudRate;
882 dcb.ByteSize=lpdcb->ByteSize;
883 dcb.StopBits=lpdcb->StopBits;
885 dcb.fParity=lpdcb->fParity;
886 dcb.Parity=lpdcb->Parity;
888 dcb.fOutxCtsFlow = lpdcb->fOutxCtsFlow;
890 if (lpdcb->fDtrflow || lpdcb->fRtsflow)
891 dcb.fRtsControl = TRUE;
893 if (lpdcb->fDtrDisable)
894 dcb.fDtrControl = TRUE;
896 ptr->evtchar = lpdcb->EvtChar;
898 dcb.fInX = lpdcb->fInX;
899 dcb.fOutX = lpdcb->fOutX;
901 if (!SetCommState(ptr->handle,&dcb)) {
902 ptr->commerror = WinError();
903 return -1;
904 } else {
905 ptr->commerror = 0;
906 return 0;
910 /*****************************************************************************
911 * GetCommState (USER.202)
913 INT16 WINAPI GetCommState16(INT16 cid, LPDCB16 lpdcb)
915 struct DosDeviceStruct *ptr;
916 DCB dcb;
918 TRACE("cid %d, ptr %p\n", cid, lpdcb);
919 if ((ptr = GetDeviceStruct(cid)) == NULL) {
920 FIXME("no handle for cid = %0x!\n",cid);
921 return -1;
923 if (!GetCommState(ptr->handle,&dcb)) {
924 ptr->commerror = WinError();
925 return -1;
928 lpdcb->Id = cid;
930 COMM16_DCBtoDCB16(&dcb,lpdcb);
932 lpdcb->EvtChar = ptr->evtchar;
934 ptr->commerror = 0;
935 return 0;
938 /*****************************************************************************
939 * TransmitCommChar (USER.206)
941 INT16 WINAPI TransmitCommChar16(INT16 cid,CHAR chTransmit)
943 struct DosDeviceStruct *ptr;
945 TRACE("cid %d, data %d \n", cid, chTransmit);
946 if ((ptr = GetDeviceStruct(cid)) == NULL) {
947 FIXME("no handle for cid = %0x!\n",cid);
948 return -1;
951 if (ptr->suspended) {
952 ptr->commerror = IE_HARDWARE;
953 return -1;
956 if (ptr->xmit >= 0) {
957 /* character already queued */
958 /* FIXME: which error would Windows return? */
959 ptr->commerror = CE_TXFULL;
960 return -1;
963 if (ptr->obuf_head == ptr->obuf_tail) {
964 /* transmit queue empty, try to transmit directly */
965 DWORD len;
966 if(!WriteFile(ptr->handle, &chTransmit, 1, &len, NULL)) {
967 /* didn't work, queue it */
968 ptr->xmit = chTransmit;
969 comm_waitwrite(ptr);
971 } else {
972 /* data in queue, let this char be transmitted next */
973 ptr->xmit = chTransmit;
974 comm_waitwrite(ptr);
977 ptr->commerror = 0;
978 return 0;
981 /*****************************************************************************
982 * UngetCommChar (USER.212)
984 INT16 WINAPI UngetCommChar16(INT16 cid,CHAR chUnget)
986 struct DosDeviceStruct *ptr;
988 TRACE("cid %d (char %d)\n", cid, chUnget);
989 if ((ptr = GetDeviceStruct(cid)) == NULL) {
990 FIXME("no handle for cid = %0x!\n",cid);
991 return -1;
994 if (ptr->suspended) {
995 ptr->commerror = IE_HARDWARE;
996 return -1;
999 if (ptr->unget>=0) {
1000 /* character already queued */
1001 /* FIXME: which error would Windows return? */
1002 ptr->commerror = CE_RXOVER;
1003 return -1;
1006 ptr->unget = chUnget;
1008 ptr->commerror = 0;
1009 return 0;
1012 /*****************************************************************************
1013 * ReadComm (USER.204)
1015 INT16 WINAPI ReadComm16(INT16 cid,LPSTR lpvBuf,INT16 cbRead)
1017 int status, length;
1018 struct DosDeviceStruct *ptr;
1019 LPSTR orgBuf = lpvBuf;
1021 TRACE("cid %d, ptr %p, length %d\n", cid, lpvBuf, cbRead);
1022 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1023 FIXME("no handle for cid = %0x!\n",cid);
1024 return -1;
1027 if (ptr->suspended) {
1028 ptr->commerror = IE_HARDWARE;
1029 return -1;
1032 /* read unget character */
1033 if (ptr->unget>=0) {
1034 *lpvBuf++ = ptr->unget;
1035 ptr->unget = -1;
1037 length = 1;
1038 } else
1039 length = 0;
1041 /* read from receive buffer */
1042 while (length < cbRead) {
1043 status = ((ptr->ibuf_head < ptr->ibuf_tail) ?
1044 ptr->ibuf_size : ptr->ibuf_head) - ptr->ibuf_tail;
1045 if (!status) break;
1046 if ((cbRead - length) < status)
1047 status = cbRead - length;
1049 memcpy(lpvBuf, ptr->inbuf + ptr->ibuf_tail, status);
1050 ptr->ibuf_tail += status;
1051 if (ptr->ibuf_tail >= ptr->ibuf_size)
1052 ptr->ibuf_tail = 0;
1053 lpvBuf += status;
1054 length += status;
1057 TRACE("%.*s\n", length, orgBuf);
1058 ptr->commerror = 0;
1059 return length;
1062 /*****************************************************************************
1063 * WriteComm (USER.205)
1065 INT16 WINAPI WriteComm16(INT16 cid, LPSTR lpvBuf, INT16 cbWrite)
1067 int status, length;
1068 struct DosDeviceStruct *ptr;
1070 TRACE("cid %d, ptr %p, length %d\n",
1071 cid, lpvBuf, cbWrite);
1072 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1073 FIXME("no handle for cid = %0x!\n",cid);
1074 return -1;
1077 if (ptr->suspended) {
1078 ptr->commerror = IE_HARDWARE;
1079 return -1;
1082 TRACE("%.*s\n", cbWrite, lpvBuf );
1084 length = 0;
1085 while (length < cbWrite) {
1086 if ((ptr->obuf_head == ptr->obuf_tail) && (ptr->xmit < 0)) {
1087 /* no data queued, try to write directly */
1088 if(!WriteFile(ptr->handle, lpvBuf, cbWrite - length, (LPDWORD)&status, NULL))
1089 status = -1;
1090 if (status > 0) {
1091 lpvBuf += status;
1092 length += status;
1093 continue;
1096 /* can't write directly, put into transmit buffer */
1097 status = ((ptr->obuf_tail > ptr->obuf_head) ?
1098 (ptr->obuf_tail-1) : ptr->obuf_size) - ptr->obuf_head;
1099 if (!status) break;
1100 if ((cbWrite - length) < status)
1101 status = cbWrite - length;
1102 memcpy(lpvBuf, ptr->outbuf + ptr->obuf_head, status);
1103 ptr->obuf_head += status;
1104 if (ptr->obuf_head >= ptr->obuf_size)
1105 ptr->obuf_head = 0;
1106 lpvBuf += status;
1107 length += status;
1108 comm_waitwrite(ptr);
1111 ptr->commerror = 0;
1112 return length;
1115 /***********************************************************************
1116 * EnableCommNotification (USER.245)
1118 BOOL16 WINAPI EnableCommNotification16( INT16 cid, HWND16 hwnd,
1119 INT16 cbWriteNotify, INT16 cbOutQueue )
1121 struct DosDeviceStruct *ptr;
1123 TRACE("(%d, %x, %d, %d)\n", cid, hwnd, cbWriteNotify, cbOutQueue);
1124 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1125 FIXME("no handle for cid = %0x!\n",cid);
1126 return -1;
1128 ptr->wnd = WIN_Handle32( hwnd );
1129 ptr->n_read = cbWriteNotify;
1130 ptr->n_write = cbOutQueue;
1131 return TRUE;