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"
55 #include "debugtools.h"
57 DEFAULT_DEBUG_CHANNEL(comm);
59 /* window's semi documented modem status register */
60 #define COMM_MSR_OFFSET 35
65 #define MSR_MASK (MSR_CTS|MSR_DSR|MSR_RI|MSR_RLSD)
71 struct DosDeviceStruct {
72 char *devicename; /* /dev/ttyS0 */
79 int commerror, eventmask;
82 unsigned ibuf_size,ibuf_head,ibuf_tail;
83 unsigned obuf_size,obuf_head,obuf_tail;
87 OVERLAPPED read_ov, write_ov;
88 /* save terminal states */
90 /* 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 /* we get cancelled when CloseComm is called */
263 if (status==STATUS_CANCELLED)
265 TRACE("Cancelled\n");
269 /* read data from comm port */
270 if (status != STATUS_SUCCESS) {
271 ERR("async read failed %08lx\n",status);
272 COM[cid].commerror = CE_RXOVER;
275 TRACE("async read completed %ld bytes\n",len);
277 prev = comm_inbuf(ptr);
279 /* check for events */
280 if ((ptr->eventmask & EV_RXFLAG) &&
281 memchr(ptr->inbuf + ptr->ibuf_head, ptr->evtchar, len)) {
282 *(WORD*)(COM[cid].unknown) |= EV_RXFLAG;
285 if (ptr->eventmask & EV_RXCHAR) {
286 *(WORD*)(COM[cid].unknown) |= EV_RXCHAR;
290 /* advance buffer position */
291 ptr->ibuf_head += len;
292 if (ptr->ibuf_head >= ptr->ibuf_size)
295 /* check for notification */
296 if (ptr->wnd && (ptr->n_read>0) && (prev<ptr->n_read) &&
297 (comm_inbuf(ptr)>=ptr->n_read)) {
298 /* passed the receive notification threshold */
302 /* send notifications, if any */
303 if (ptr->wnd && mask) {
304 TRACE("notifying %04x: cid=%d, mask=%02x\n", ptr->wnd, cid, mask);
305 PostMessageA(ptr->wnd, WM_COMMNOTIFY, cid, mask);
308 /* on real windows, this could cause problems, since it is recursive */
309 /* restart the receive */
313 /* this is meant to work like write() */
314 static INT COMM16_WriteFile(HANDLE hComm, LPCVOID buffer, DWORD len)
319 ZeroMemory(&ov,sizeof ov);
320 ov.hEvent = CreateEventA(NULL,0,0,NULL);
321 if(ov.hEvent==INVALID_HANDLE_VALUE)
324 if(!WriteFile(hComm,buffer,len,&count,&ov))
326 if(GetLastError()==ERROR_IO_PENDING)
328 GetOverlappedResult(hComm,&ov,&count,TRUE);
331 CloseHandle(ov.hEvent);
336 static VOID WINAPI COMM16_WriteComplete(DWORD status, DWORD len, LPOVERLAPPED ov)
340 int cid = GetCommPort_ov(ov,1);
341 struct DosDeviceStruct *ptr;
344 ERR("async write with bad overlapped pointer\n");
349 /* read data from comm port */
350 if (status != STATUS_SUCCESS) {
351 ERR("async write failed\n");
352 COM[cid].commerror = CE_RXOVER;
355 TRACE("async write completed %ld bytes\n",len);
357 /* update the buffer pointers */
358 prev = comm_outbuf(&COM[cid]);
359 ptr->obuf_tail += len;
360 if (ptr->obuf_tail >= ptr->obuf_size)
363 /* write any TransmitCommChar character */
365 len = COMM16_WriteFile(ptr->handle, &(ptr->xmit), 1);
366 if (len > 0) ptr->xmit = -1;
369 /* write from output queue */
370 bleft = ((ptr->obuf_tail <= ptr->obuf_head) ?
371 ptr->obuf_head : ptr->obuf_size) - ptr->obuf_tail;
373 /* check for notification */
374 if (ptr->wnd && (ptr->n_write>0) && (prev>=ptr->n_write) &&
375 (comm_outbuf(ptr)<ptr->n_write)) {
376 /* passed the transmit notification threshold */
380 /* send notifications, if any */
381 if (ptr->wnd && mask) {
382 TRACE("notifying %04x: cid=%d, mask=%02x\n", ptr->wnd, cid, mask);
383 PostMessageA(ptr->wnd, WM_COMMNOTIFY, cid, mask);
386 /* start again if necessary */
391 static void comm_waitread(struct DosDeviceStruct *ptr)
396 /* FIXME: get timeouts working properly so we can read bleft bytes */
397 bleft = ((ptr->ibuf_tail > ptr->ibuf_head) ?
398 (ptr->ibuf_tail-1) : ptr->ibuf_size) - ptr->ibuf_head;
400 /* find out how many bytes are left in the buffer */
401 if(ClearCommError(ptr->handle,NULL,&stat))
402 bleft = (bleft<stat.cbInQue) ? bleft : stat.cbInQue;
406 /* always read at least one byte */
410 ReadFileEx(ptr->handle,
411 ptr->inbuf + ptr->ibuf_head,
414 COMM16_ReadComplete);
417 static void comm_waitwrite(struct DosDeviceStruct *ptr)
421 bleft = ((ptr->obuf_tail <= ptr->obuf_head) ?
422 ptr->obuf_head : ptr->obuf_size) - ptr->obuf_tail;
423 WriteFileEx(ptr->handle,
424 ptr->outbuf + ptr->obuf_tail,
427 COMM16_WriteComplete);
430 /*****************************************************************************
431 * COMM16_DCBtoDCB16 (Internal)
433 INT16 COMM16_DCBtoDCB16(LPDCB lpdcb, LPDCB16 lpdcb16)
435 if(lpdcb->BaudRate<0x10000)
436 lpdcb16->BaudRate = lpdcb->BaudRate;
437 else if(lpdcb->BaudRate==115200)
438 lpdcb16->BaudRate = 57601;
440 WARN("Baud rate can't be converted\n");
441 lpdcb16->BaudRate = 57601;
443 lpdcb16->ByteSize = lpdcb->ByteSize;
444 lpdcb16->fParity = lpdcb->fParity;
445 lpdcb16->Parity = lpdcb->Parity;
446 lpdcb16->StopBits = lpdcb->StopBits;
448 lpdcb16->RlsTimeout = 50;
449 lpdcb16->CtsTimeout = 50;
450 lpdcb16->DsrTimeout = 50;
453 lpdcb16->fBinary = 1;
455 lpdcb16->fDtrflow = (lpdcb->fDtrControl==DTR_CONTROL_HANDSHAKE);
456 lpdcb16->fRtsflow = (lpdcb->fRtsControl==RTS_CONTROL_HANDSHAKE);
457 lpdcb16->fOutxCtsFlow = lpdcb->fOutxCtsFlow;
458 lpdcb16->fOutxDsrFlow = lpdcb->fOutxDsrFlow;
459 lpdcb16->fDtrDisable = (lpdcb->fDtrControl==DTR_CONTROL_DISABLE);
461 lpdcb16->fInX = lpdcb->fInX;
463 lpdcb16->fOutX = lpdcb->fOutX;
468 lpdcb16->XonLim = 10;
469 lpdcb16->XoffLim = 10;
475 /**************************************************************************
476 * BuildCommDCB (USER.213)
478 * According to the ECMA-234 (368.3) the function will return FALSE on
479 * success, otherwise it will return -1.
481 INT16 WINAPI BuildCommDCB16(LPCSTR device, LPDCB16 lpdcb)
483 /* "COM1:96,n,8,1" */
488 TRACE("(%s), ptr %p\n", device, lpdcb);
490 if (strncasecmp(device,"COM",3))
492 port = device[3] - '0';
495 ERR("BUG ! COM0 can't exist!\n");
499 if (!ValidCOMPort(port)) {
500 FIXME("invalid COM port %d?\n",port);
504 memset(lpdcb, 0, sizeof(DCB16)); /* initialize */
507 dcb.DCBlength = sizeof(DCB);
509 if (strchr(device,'=')) /* block new style */
512 if(!BuildCommDCBA(device,&dcb))
515 return COMM16_DCBtoDCB16(&dcb, lpdcb);
518 /*****************************************************************************
519 * OpenComm (USER.200)
521 INT16 WINAPI OpenComm16(LPCSTR device,UINT16 cbInQueue,UINT16 cbOutQueue)
526 TRACE("%s, %d, %d\n", device, cbInQueue, cbOutQueue);
528 if (strlen(device) < 4)
531 port = device[3] - '0';
534 ERR("BUG ! COM0 or LPT0 don't exist !\n");
536 if (!strncasecmp(device,"COM",3)) {
538 TRACE("%s = %s\n", device, COM[port].devicename);
540 if (!ValidCOMPort(port))
543 if (COM[port].handle)
546 handle = CreateFileA(device, GENERIC_READ|GENERIC_WRITE,
547 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
548 FILE_FLAG_OVERLAPPED|FILE_FLAG_NO_BUFFERING, 0 );
549 if (handle == INVALID_HANDLE_VALUE) {
550 ERR("Couldn't open %s ! (%s)\n", COM[port].devicename, strerror(errno));
553 memset(COM[port].unknown, 0, sizeof(COM[port].unknown));
554 COM[port].seg_unknown = 0;
555 COM[port].handle = handle;
556 COM[port].commerror = 0;
557 COM[port].eventmask = 0;
558 COM[port].evtchar = 0; /* FIXME: default? */
559 /* save terminal state */
560 GetCommState16(port,&COM[port].dcb);
561 /* set default parameters */
562 if(COM[port].baudrate>-1){
564 memcpy(&dcb,&COM[port].dcb,sizeof dcb);
565 dcb.BaudRate=COM[port].baudrate;
567 * databits, parity, stopbits
569 SetCommState16( &dcb);
571 /* init priority characters */
572 COM[port].unget = -1;
574 /* allocate buffers */
575 COM[port].ibuf_size = cbInQueue;
576 COM[port].ibuf_head = COM[port].ibuf_tail = 0;
577 COM[port].obuf_size = cbOutQueue;
578 COM[port].obuf_head = COM[port].obuf_tail = 0;
580 COM[port].inbuf = malloc(cbInQueue);
581 if (COM[port].inbuf) {
582 COM[port].outbuf = malloc(cbOutQueue);
583 if (!COM[port].outbuf)
584 free(COM[port].inbuf);
585 } else COM[port].outbuf = NULL;
586 if (!COM[port].outbuf) {
587 /* not enough memory */
588 SetCommState16(&COM[port].dcb);
589 CloseHandle(COM[port].handle);
590 ERR("out of memory\n");
594 ZeroMemory(&COM[port].read_ov,sizeof (OVERLAPPED));
595 ZeroMemory(&COM[port].write_ov,sizeof (OVERLAPPED));
597 comm_waitread( &COM[port] );
598 USER16_AlertableWait++;
604 if (!strncasecmp(device,"LPT",3)) {
606 if (!ValidLPTPort(port))
609 if (LPT[port].handle)
612 handle = CreateFileA(device, GENERIC_READ|GENERIC_WRITE,
613 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0 );
614 if (handle == INVALID_HANDLE_VALUE) {
617 LPT[port].handle = handle;
618 LPT[port].commerror = 0;
619 LPT[port].eventmask = 0;
620 return port|FLAG_LPT;
626 /*****************************************************************************
627 * CloseComm (USER.207)
629 INT16 WINAPI CloseComm16(INT16 cid)
631 struct DosDeviceStruct *ptr;
633 TRACE("cid=%d\n", cid);
634 if ((ptr = GetDeviceStruct(cid)) == NULL) {
635 FIXME("no cid=%d found!\n", cid);
638 if (!(cid&FLAG_LPT)) {
640 UnMapLS( COM[cid].seg_unknown );
641 USER16_AlertableWait--;
642 CancelIo(ptr->handle);
648 /* reset modem lines */
649 SetCommState16(&COM[cid].dcb);
652 if (!CloseHandle(ptr->handle)) {
653 ptr->commerror = WinError();
654 /* FIXME: should we clear ptr->handle here? */
663 /*****************************************************************************
664 * SetCommBreak (USER.210)
666 INT16 WINAPI SetCommBreak16(INT16 cid)
668 struct DosDeviceStruct *ptr;
670 TRACE("cid=%d\n", cid);
671 if ((ptr = GetDeviceStruct(cid)) == NULL) {
672 FIXME("no cid=%d found!\n", cid);
681 /*****************************************************************************
682 * ClearCommBreak (USER.211)
684 INT16 WINAPI ClearCommBreak16(INT16 cid)
686 struct DosDeviceStruct *ptr;
688 TRACE("cid=%d\n", cid);
689 if (!(ptr = GetDeviceStruct(cid))) {
690 FIXME("no cid=%d found!\n", cid);
698 /*****************************************************************************
699 * EscapeCommFunction (USER.214)
701 LONG WINAPI EscapeCommFunction16(UINT16 cid,UINT16 nFunction)
703 struct DosDeviceStruct *ptr;
706 TRACE("cid=%d, function=%d\n", cid, nFunction);
710 TRACE("GETMAXCOM\n");
711 for (max = MAX_PORTS;!COM[max].devicename;max--)
716 TRACE("GETMAXLPT\n");
717 for (max = MAX_PORTS;!LPT[max].devicename;max--)
719 return FLAG_LPT + max;
722 TRACE("GETBASEIRQ\n");
723 /* FIXME: use tables */
724 /* just fake something for now */
725 if (cid & FLAG_LPT) {
726 /* LPT1: irq 7, LPT2: irq 5 */
727 return (cid & 0x7f) ? 5 : 7;
729 /* COM1: irq 4, COM2: irq 3,
730 COM3: irq 4, COM4: irq 3 */
731 return 4 - (cid & 1);
735 if ((ptr = GetDeviceStruct(cid)) == NULL) {
736 FIXME("no cid=%d found!\n", cid);
748 if(EscapeCommFunction(ptr->handle,nFunction))
751 ptr->commerror = WinError();
758 WARN("(cid=%d,nFunction=%d): Unknown function\n",
764 /*****************************************************************************
765 * FlushComm (USER.215)
767 INT16 WINAPI FlushComm16(INT16 cid,INT16 fnQueue)
770 struct DosDeviceStruct *ptr;
772 TRACE("cid=%d, queue=%d\n", cid, fnQueue);
773 if ((ptr = GetDeviceStruct(cid)) == NULL) {
774 FIXME("no cid=%d found!\n", cid);
779 queue = PURGE_TXABORT;
780 ptr->obuf_tail = ptr->obuf_head;
783 queue = PURGE_RXABORT;
784 ptr->ibuf_head = ptr->ibuf_tail;
787 WARN("(cid=%d,fnQueue=%d):Unknown queue\n",
792 if (!PurgeComm(ptr->handle,queue)) {
793 ptr->commerror = WinError();
801 /********************************************************************
802 * GetCommError (USER.203)
804 INT16 WINAPI GetCommError16(INT16 cid,LPCOMSTAT16 lpStat)
807 struct DosDeviceStruct *ptr;
810 if ((ptr = GetDeviceStruct(cid)) == NULL) {
811 FIXME("no handle for cid = %0x!\n",cid);
815 WARN(" cid %d not comm port\n",cid);
818 stol = (unsigned char *)COM[cid].unknown + COMM_MSR_OFFSET;
819 COMM_MSRUpdate( ptr->handle, stol );
824 WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
826 lpStat->cbOutQue = comm_outbuf(ptr);
827 lpStat->cbInQue = comm_inbuf(ptr);
829 TRACE("cid %d, error %d, stat %d in %d out %d, stol %x\n",
830 cid, ptr->commerror, lpStat->status, lpStat->cbInQue,
831 lpStat->cbOutQue, *stol);
834 TRACE("cid %d, error %d, lpStat NULL stol %x\n",
835 cid, ptr->commerror, *stol);
837 /* Return any errors and clear it */
838 temperror = ptr->commerror;
843 /*****************************************************************************
844 * SetCommEventMask (USER.208)
846 SEGPTR WINAPI SetCommEventMask16(INT16 cid,UINT16 fuEvtMask)
848 struct DosDeviceStruct *ptr;
851 TRACE("cid %d,mask %d\n",cid,fuEvtMask);
852 if ((ptr = GetDeviceStruct(cid)) == NULL) {
853 FIXME("no handle for cid = %0x!\n",cid);
857 ptr->eventmask = fuEvtMask;
859 if ((cid&FLAG_LPT) || !ValidCOMPort(cid)) {
860 WARN(" cid %d not comm port\n",cid);
863 /* it's a COM port ? -> modify flags */
864 stol = (unsigned char *)COM[cid].unknown + COMM_MSR_OFFSET;
865 COMM_MSRUpdate( ptr->handle, stol );
867 TRACE(" modem dcd construct %x\n",*stol);
868 if (!COM[cid].seg_unknown) COM[cid].seg_unknown = MapLS( COM[cid].unknown );
869 return COM[cid].seg_unknown;
872 /*****************************************************************************
873 * GetCommEventMask (USER.209)
875 UINT16 WINAPI GetCommEventMask16(INT16 cid,UINT16 fnEvtClear)
877 struct DosDeviceStruct *ptr;
880 TRACE("cid %d, mask %d\n", cid, fnEvtClear);
881 if ((ptr = GetDeviceStruct(cid)) == NULL) {
882 FIXME("no handle for cid = %0x!\n",cid);
886 if ((cid&FLAG_LPT) || !ValidCOMPort(cid)) {
887 WARN(" cid %d not comm port\n",cid);
891 events = *(WORD*)(COM[cid].unknown) & fnEvtClear;
892 *(WORD*)(COM[cid].unknown) &= ~fnEvtClear;
896 /*****************************************************************************
897 * SetCommState (USER.201)
899 INT16 WINAPI SetCommState16(LPDCB16 lpdcb)
901 struct DosDeviceStruct *ptr;
904 TRACE("cid %d, ptr %p\n", lpdcb->Id, lpdcb);
905 if ((ptr = GetDeviceStruct(lpdcb->Id)) == NULL) {
906 FIXME("no handle for cid = %0x!\n",lpdcb->Id);
910 memset(&dcb,0,sizeof dcb);
911 dcb.DCBlength = sizeof dcb;
914 * according to MSDN, we should first interpret lpdcb->BaudRate as follows:
915 * 1. if the baud rate is a CBR constant, interpret it.
916 * 2. if it is greater than 57600, the baud rate is 115200
917 * 3. use the actual baudrate
918 * steps 2 and 3 are equivilent to 16550 baudrate divisor = 115200/BaudRate
919 * see http://support.microsoft.com/support/kb/articles/q108/9/28.asp
921 switch(lpdcb->BaudRate)
923 case CBR_110: dcb.BaudRate = 110; break;
924 case CBR_300: dcb.BaudRate = 300; break;
925 case CBR_600: dcb.BaudRate = 600; break;
926 case CBR_1200: dcb.BaudRate = 1200; break;
927 case CBR_2400: dcb.BaudRate = 2400; break;
928 case CBR_4800: dcb.BaudRate = 4800; break;
929 case CBR_9600: dcb.BaudRate = 9600; break;
930 case CBR_14400: dcb.BaudRate = 14400; break;
931 case CBR_19200: dcb.BaudRate = 19200; break;
932 case CBR_38400: dcb.BaudRate = 38400; break;
933 case CBR_56000: dcb.BaudRate = 56000; break;
934 case CBR_128000: dcb.BaudRate = 128000; break;
935 case CBR_256000: dcb.BaudRate = 256000; break;
937 if(lpdcb->BaudRate>57600)
938 dcb.BaudRate = 115200;
940 dcb.BaudRate = lpdcb->BaudRate;
943 dcb.ByteSize=lpdcb->ByteSize;
944 dcb.StopBits=lpdcb->StopBits;
946 dcb.fParity=lpdcb->fParity;
947 dcb.Parity=lpdcb->Parity;
949 dcb.fOutxCtsFlow = lpdcb->fOutxCtsFlow;
951 if (lpdcb->fDtrflow || lpdcb->fRtsflow)
952 dcb.fRtsControl = TRUE;
954 if (lpdcb->fDtrDisable)
955 dcb.fDtrControl = TRUE;
957 ptr->evtchar = lpdcb->EvtChar;
959 dcb.fInX = lpdcb->fInX;
960 dcb.fOutX = lpdcb->fOutX;
962 if (!SetCommState(ptr->handle,&dcb)) {
963 ptr->commerror = WinError();
971 /*****************************************************************************
972 * GetCommState (USER.202)
974 INT16 WINAPI GetCommState16(INT16 cid, LPDCB16 lpdcb)
976 struct DosDeviceStruct *ptr;
979 TRACE("cid %d, ptr %p\n", cid, lpdcb);
980 if ((ptr = GetDeviceStruct(cid)) == NULL) {
981 FIXME("no handle for cid = %0x!\n",cid);
984 if (!GetCommState(ptr->handle,&dcb)) {
985 ptr->commerror = WinError();
991 COMM16_DCBtoDCB16(&dcb,lpdcb);
993 lpdcb->EvtChar = ptr->evtchar;
999 /*****************************************************************************
1000 * TransmitCommChar (USER.206)
1002 INT16 WINAPI TransmitCommChar16(INT16 cid,CHAR chTransmit)
1004 struct DosDeviceStruct *ptr;
1006 TRACE("cid %d, data %d \n", cid, chTransmit);
1007 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1008 FIXME("no handle for cid = %0x!\n",cid);
1012 if (ptr->suspended) {
1013 ptr->commerror = IE_HARDWARE;
1017 if (ptr->xmit >= 0) {
1018 /* character already queued */
1019 /* FIXME: which error would Windows return? */
1020 ptr->commerror = CE_TXFULL;
1024 if (ptr->obuf_head == ptr->obuf_tail) {
1025 /* transmit queue empty, try to transmit directly */
1026 if(1!=COMM16_WriteFile(ptr->handle, &chTransmit, 1))
1028 /* didn't work, queue it */
1029 ptr->xmit = chTransmit;
1030 comm_waitwrite(ptr);
1033 /* data in queue, let this char be transmitted next */
1034 ptr->xmit = chTransmit;
1035 comm_waitwrite(ptr);
1042 /*****************************************************************************
1043 * UngetCommChar (USER.212)
1045 INT16 WINAPI UngetCommChar16(INT16 cid,CHAR chUnget)
1047 struct DosDeviceStruct *ptr;
1049 TRACE("cid %d (char %d)\n", cid, chUnget);
1050 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1051 FIXME("no handle for cid = %0x!\n",cid);
1055 if (ptr->suspended) {
1056 ptr->commerror = IE_HARDWARE;
1060 if (ptr->unget>=0) {
1061 /* character already queued */
1062 /* FIXME: which error would Windows return? */
1063 ptr->commerror = CE_RXOVER;
1067 ptr->unget = chUnget;
1073 /*****************************************************************************
1074 * ReadComm (USER.204)
1076 INT16 WINAPI ReadComm16(INT16 cid,LPSTR lpvBuf,INT16 cbRead)
1079 struct DosDeviceStruct *ptr;
1080 LPSTR orgBuf = lpvBuf;
1082 TRACE("cid %d, ptr %p, length %d\n", cid, lpvBuf, cbRead);
1083 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1084 FIXME("no handle for cid = %0x!\n",cid);
1088 if (ptr->suspended) {
1089 ptr->commerror = IE_HARDWARE;
1093 if(0==comm_inbuf(ptr))
1094 WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE);
1096 /* read unget character */
1097 if (ptr->unget>=0) {
1098 *lpvBuf++ = ptr->unget;
1105 /* read from receive buffer */
1106 while (length < cbRead) {
1107 status = ((ptr->ibuf_head < ptr->ibuf_tail) ?
1108 ptr->ibuf_size : ptr->ibuf_head) - ptr->ibuf_tail;
1110 if ((cbRead - length) < status)
1111 status = cbRead - length;
1113 memcpy(lpvBuf, ptr->inbuf + ptr->ibuf_tail, status);
1114 ptr->ibuf_tail += status;
1115 if (ptr->ibuf_tail >= ptr->ibuf_size)
1121 TRACE("%s\n", debugstr_an( orgBuf, length ));
1126 /*****************************************************************************
1127 * WriteComm (USER.205)
1129 INT16 WINAPI WriteComm16(INT16 cid, LPSTR lpvBuf, INT16 cbWrite)
1132 struct DosDeviceStruct *ptr;
1134 TRACE("cid %d, ptr %p, length %d\n",
1135 cid, lpvBuf, cbWrite);
1136 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1137 FIXME("no handle for cid = %0x!\n",cid);
1141 if (ptr->suspended) {
1142 ptr->commerror = IE_HARDWARE;
1146 TRACE("%s\n", debugstr_an( lpvBuf, cbWrite ));
1149 while (length < cbWrite) {
1150 if ((ptr->obuf_head == ptr->obuf_tail) && (ptr->xmit < 0)) {
1151 /* no data queued, try to write directly */
1152 status = COMM16_WriteFile(ptr->handle, lpvBuf, cbWrite - length);
1159 /* can't write directly, put into transmit buffer */
1160 status = ((ptr->obuf_tail > ptr->obuf_head) ?
1161 (ptr->obuf_tail-1) : ptr->obuf_size) - ptr->obuf_head;
1163 if ((cbWrite - length) < status)
1164 status = cbWrite - length;
1165 memcpy(lpvBuf, ptr->outbuf + ptr->obuf_head, status);
1166 ptr->obuf_head += status;
1167 if (ptr->obuf_head >= ptr->obuf_size)
1171 comm_waitwrite(ptr);
1178 /***********************************************************************
1179 * EnableCommNotification (USER.245)
1181 BOOL16 WINAPI EnableCommNotification16( INT16 cid, HWND16 hwnd,
1182 INT16 cbWriteNotify, INT16 cbOutQueue )
1184 struct DosDeviceStruct *ptr;
1186 TRACE("(%d, %x, %d, %d)\n", cid, hwnd, cbWriteNotify, cbOutQueue);
1187 if ((ptr = GetDeviceStruct(cid)) == NULL) {
1188 FIXME("no handle for cid = %0x!\n",cid);
1191 ptr->wnd = WIN_Handle32( hwnd );
1192 ptr->n_read = cbWriteNotify;
1193 ptr->n_write = cbOutQueue;