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.
50 #include "wine/winuser16.h"
51 #include "wine/port.h"
56 #include "debugtools.h"
58 DEFAULT_DEBUG_CHANNEL(comm);
60 /* window's semi documented modem status register */
61 #define COMM_MSR_OFFSET 35
66 #define MSR_MASK (MSR_CTS|MSR_DSR|MSR_RI|MSR_RLSD)
72 struct DosDeviceStruct {
73 char *devicename; /* /dev/ttyS0 */
80 int commerror, eventmask;
83 unsigned ibuf_size,ibuf_head,ibuf_tail;
84 unsigned obuf_size,obuf_head,obuf_tail;
88 OVERLAPPED read_ov, write_ov;
89 /* save terminal states */
91 /* pointer to unknown(==undocumented) comm structure */
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 )
105 if(!GetCommModemStatus(handle,&mstat))
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;
118 char option[10], temp[256], *btemp;
121 for (x=0; x!=MAX_PORTS; x++) {
122 strcpy(option,"COMx");
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);
137 if (!strcmp(temp, "*") || *temp == '\0')
138 COM[x].devicename = NULL;
140 btemp = strchr(temp,',');
143 COM[x].baudrate = atoi(btemp);
145 COM[x].baudrate = -1;
147 if ((COM[x].devicename = malloc(strlen(temp)+1)) == NULL)
148 WARN("Can't malloc for device info!\n");
151 strcpy(COM[x].devicename, temp);
152 TRACE("%s = %s\n", option, COM[x].devicename);
156 strcpy(option, "LPTx");
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);
171 if (!strcmp(temp, "*") || *temp == '\0')
172 LPT[x].devicename = NULL;
174 if ((LPT[x].devicename = malloc(strlen(temp)+1)) == NULL)
175 WARN("Can't malloc for device info!\n");
178 strcpy(LPT[x].devicename, temp);
179 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)
195 if (LPT[index].handle)
203 static int GetCommPort_ov(LPOVERLAPPED ov, int write)
207 for (x=0; x<MAX_PORTS; x++) {
208 if (ov == (write?&COM[x].write_ov:&COM[x].read_ov))
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);
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)
253 int cid = GetCommPort_ov(ov,0);
254 struct DosDeviceStruct *ptr;
257 ERR("async write with bad overlapped pointer\n");
262 /* read data from comm port */
263 if (status != STATUS_SUCCESS) {
264 ERR("async read failed\n");
265 COM[cid].commerror = CE_RXOVER;
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;
278 if (ptr->eventmask & EV_RXCHAR) {
279 *(WORD*)(COM[cid].unknown) |= EV_RXCHAR;
283 /* advance buffer position */
284 ptr->ibuf_head += len;
285 if (ptr->ibuf_head >= ptr->ibuf_size)
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 */
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 */
306 static VOID WINAPI COMM16_WriteComplete(DWORD status, DWORD len, LPOVERLAPPED ov)
310 int cid = GetCommPort_ov(ov,1);
311 struct DosDeviceStruct *ptr;
314 ERR("async write with bad overlapped pointer\n");
319 /* read data from comm port */
320 if (status != STATUS_SUCCESS) {
321 ERR("async write failed\n");
322 COM[cid].commerror = CE_RXOVER;
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)
333 /* write any TransmitCommChar character */
335 if(!WriteFile(ptr->handle, &(ptr->xmit), 1, &len, NULL))
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 */
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 */
362 static void comm_waitread(struct DosDeviceStruct *ptr)
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,
373 COMM16_ReadComplete);
376 static void comm_waitwrite(struct DosDeviceStruct *ptr)
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,
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;
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;
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;
428 lpdcb16->XonLim = 10;
429 lpdcb16->XoffLim = 10;
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" */
448 TRACE("(%s), ptr %p\n", device, lpdcb);
450 if (strncasecmp(device,"COM",3))
452 port = device[3] - '0';
455 ERR("BUG ! COM0 can't exist!\n");
459 if (!ValidCOMPort(port)) {
460 FIXME("invalid COM port %d?\n",port);
464 memset(lpdcb, 0, sizeof(DCB16)); /* initialize */
467 dcb.DCBlength = sizeof(DCB);
469 if (strchr(device,'=')) /* block new style */
472 if(!BuildCommDCBA(device,&dcb))
475 return COMM16_DCBtoDCB16(&dcb, lpdcb);
478 /*****************************************************************************
479 * OpenComm (USER.200)
481 INT16 WINAPI OpenComm16(LPCSTR device,UINT16 cbInQueue,UINT16 cbOutQueue)
486 TRACE("%s, %d, %d\n", device, cbInQueue, cbOutQueue);
488 if (strlen(device) < 4)
491 port = device[3] - '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))
503 if (COM[port].handle)
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));
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){
523 memcpy(&dcb,&COM[port].dcb,sizeof dcb);
524 dcb.BaudRate=COM[port].baudrate;
526 * databits, parity, stopbits
528 SetCommState16( &dcb);
530 /* init priority characters */
531 COM[port].unget = -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");
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] );
564 if (!strncasecmp(device,"LPT",3)) {
566 if (!ValidLPTPort(port))
569 if (LPT[port].handle)
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) {
577 LPT[port].handle = handle;
578 LPT[port].commerror = 0;
579 LPT[port].eventmask = 0;
580 return port|FLAG_LPT;
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);
598 if (!(cid&FLAG_LPT)) {
600 SEGPTR_FREE(COM[cid].unknown); /* [LW] */
602 CloseHandle(COM[cid].read_ov.hEvent);
603 CloseHandle(COM[cid].write_ov.hEvent);
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? */
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);
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);
659 /*****************************************************************************
660 * EscapeCommFunction (USER.214)
662 LONG WINAPI EscapeCommFunction16(UINT16 cid,UINT16 nFunction)
664 struct DosDeviceStruct *ptr;
667 TRACE("cid=%d, function=%d\n", cid, nFunction);
671 TRACE("GETMAXCOM\n");
672 for (max = MAX_PORTS;!COM[max].devicename;max--)
677 TRACE("GETMAXLPT\n");
678 for (max = MAX_PORTS;!LPT[max].devicename;max--)
680 return FLAG_LPT + max;
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;
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);
709 if(EscapeCommFunction(ptr->handle,nFunction))
712 ptr->commerror = WinError();
719 WARN("(cid=%d,nFunction=%d): Unknown function\n",
725 /*****************************************************************************
726 * FlushComm (USER.215)
728 INT16 WINAPI FlushComm16(INT16 cid,INT16 fnQueue)
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);
740 queue = PURGE_TXABORT;
741 ptr->obuf_tail = ptr->obuf_head;
744 queue = PURGE_RXABORT;
745 ptr->ibuf_head = ptr->ibuf_tail;
748 WARN("(cid=%d,fnQueue=%d):Unknown queue\n",
753 if (!PurgeComm(ptr->handle,queue)) {
754 ptr->commerror = WinError();
762 /********************************************************************
763 * GetCommError (USER.203)
765 INT16 WINAPI GetCommError16(INT16 cid,LPCOMSTAT16 lpStat)
768 struct DosDeviceStruct *ptr;
771 if ((ptr = GetDeviceStruct(cid)) == NULL) {
772 FIXME("no handle for cid = %0x!\n",cid);
776 WARN(" cid %d not comm port\n",cid);
779 stol = (unsigned char *)COM[cid].unknown + COMM_MSR_OFFSET;
780 COMM_MSRUpdate( ptr->handle, stol );
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);
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;
809 /*****************************************************************************
810 * SetCommEventMask (USER.208)
812 SEGPTR WINAPI SetCommEventMask16(INT16 cid,UINT16 fuEvtMask)
814 struct DosDeviceStruct *ptr;
817 TRACE("cid %d,mask %d\n",cid,fuEvtMask);
818 if ((ptr = GetDeviceStruct(cid)) == NULL) {
819 FIXME("no handle for cid = %0x!\n",cid);
823 ptr->eventmask = fuEvtMask;
825 if ((cid&FLAG_LPT) || !ValidCOMPort(cid)) {
826 WARN(" cid %d not comm port\n",cid);
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;
845 TRACE("cid %d, mask %d\n", cid, fnEvtClear);
846 if ((ptr = GetDeviceStruct(cid)) == NULL) {
847 FIXME("no handle for cid = %0x!\n",cid);
851 if ((cid&FLAG_LPT) || !ValidCOMPort(cid)) {
852 WARN(" cid %d not comm port\n",cid);
856 events = *(WORD*)(COM[cid].unknown) & fnEvtClear;
857 *(WORD*)(COM[cid].unknown) &= ~fnEvtClear;
861 /*****************************************************************************
862 * SetCommState (USER.201)
864 INT16 WINAPI SetCommState16(LPDCB16 lpdcb)
866 struct DosDeviceStruct *ptr;
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);
875 memset(&dcb,0,sizeof dcb);
876 dcb.DCBlength = sizeof dcb;
877 if(lpdcb->BaudRate==57601)
878 dcb.BaudRate = 115200;
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();
910 /*****************************************************************************
911 * GetCommState (USER.202)
913 INT16 WINAPI GetCommState16(INT16 cid, LPDCB16 lpdcb)
915 struct DosDeviceStruct *ptr;
918 TRACE("cid %d, ptr %p\n", cid, lpdcb);
919 if ((ptr = GetDeviceStruct(cid)) == NULL) {
920 FIXME("no handle for cid = %0x!\n",cid);
923 if (!GetCommState(ptr->handle,&dcb)) {
924 ptr->commerror = WinError();
930 COMM16_DCBtoDCB16(&dcb,lpdcb);
932 lpdcb->EvtChar = ptr->evtchar;
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);
951 if (ptr->suspended) {
952 ptr->commerror = IE_HARDWARE;
956 if (ptr->xmit >= 0) {
957 /* character already queued */
958 /* FIXME: which error would Windows return? */
959 ptr->commerror = CE_TXFULL;
963 if (ptr->obuf_head == ptr->obuf_tail) {
964 /* transmit queue empty, try to transmit directly */
966 if(!WriteFile(ptr->handle, &chTransmit, 1, &len, NULL)) {
967 /* didn't work, queue it */
968 ptr->xmit = chTransmit;
972 /* data in queue, let this char be transmitted next */
973 ptr->xmit = chTransmit;
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);
994 if (ptr->suspended) {
995 ptr->commerror = IE_HARDWARE;
1000 /* character already queued */
1001 /* FIXME: which error would Windows return? */
1002 ptr->commerror = CE_RXOVER;
1006 ptr->unget = chUnget;
1012 /*****************************************************************************
1013 * ReadComm (USER.204)
1015 INT16 WINAPI ReadComm16(INT16 cid,LPSTR lpvBuf,INT16 cbRead)
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);
1027 if (ptr->suspended) {
1028 ptr->commerror = IE_HARDWARE;
1032 /* read unget character */
1033 if (ptr->unget>=0) {
1034 *lpvBuf++ = ptr->unget;
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;
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)
1057 TRACE("%.*s\n", length, orgBuf);
1062 /*****************************************************************************
1063 * WriteComm (USER.205)
1065 INT16 WINAPI WriteComm16(INT16 cid, LPSTR lpvBuf, INT16 cbWrite)
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);
1077 if (ptr->suspended) {
1078 ptr->commerror = IE_HARDWARE;
1082 TRACE("%.*s\n", cbWrite, lpvBuf );
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))
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;
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)
1108 comm_waitwrite(ptr);
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);
1128 ptr->wnd = WIN_Handle32( hwnd );
1129 ptr->n_read = cbWriteNotify;
1130 ptr->n_write = cbOutQueue;