From e4ca13ea823cff305a850a7ac604acd29054f3f0 Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Tue, 24 Jul 2001 20:49:41 +0000 Subject: [PATCH] Move 16-bit COMM code to USER dll. --- dlls/kernel/comm.c | 1069 ----------------------------------- dlls/kernel/kernel_main.c | 4 - dlls/user/Makefile.in | 1 + dlls/user/comm16.c | 1112 +++++++++++++++++++++++++++++++++++++ dlls/user/user_main.c | 5 + 5 files changed, 1118 insertions(+), 1073 deletions(-) create mode 100644 dlls/user/comm16.c diff --git a/dlls/kernel/comm.c b/dlls/kernel/comm.c index ec345000396..50d716553f6 100644 --- a/dlls/kernel/comm.c +++ b/dlls/kernel/comm.c @@ -60,14 +60,10 @@ #include "windef.h" #include "winbase.h" -#include "wingdi.h" -#include "winuser.h" #include "heap.h" -#include "options.h" #include "wine/port.h" #include "wine/server.h" #include "winerror.h" -#include "callback.h" #include "file.h" #include "debugtools.h" @@ -78,165 +74,6 @@ DEFAULT_DEBUG_CHANNEL(comm); #define TIOCINQ FIONREAD #endif -/* window's semi documented modem status register */ -#define COMM_MSR_OFFSET 35 -#define MSR_CTS 0x10 -#define MSR_DSR 0x20 -#define MSR_RI 0x40 -#define MSR_RLSD 0x80 -#define MSR_MASK (MSR_CTS|MSR_DSR|MSR_RI|MSR_RLSD) - -#define FLAG_LPT 0x80 - -#ifdef linux -#define CMSPAR 0x40000000 /* stick parity */ -#endif - -#define MAX_PORTS 9 - -struct DosDeviceStruct { - char *devicename; /* /dev/ttyS0 */ - HANDLE handle; - int suspended; - int unget,xmit; - int baudrate; - int evtchar; - /* events */ - int commerror, eventmask; - /* buffers */ - char *inbuf,*outbuf; - unsigned ibuf_size,ibuf_head,ibuf_tail; - unsigned obuf_size,obuf_head,obuf_tail; - /* notifications */ - int wnd, n_read, n_write; - OVERLAPPED read_ov, write_ov; - /* save terminal states */ - DCB16 dcb; - /* pointer to unknown(==undocumented) comm structure */ - LPCVOID *unknown; -}; - - -static struct DosDeviceStruct COM[MAX_PORTS]; -static struct DosDeviceStruct LPT[MAX_PORTS]; - -/* update window's semi documented modem status register */ -/* see knowledge base Q101417 */ -static void COMM_MSRUpdate( HANDLE handle, UCHAR * pMsr ) -{ - UCHAR tmpmsr=0; - DWORD mstat=0; - - if(!GetCommModemStatus(handle,&mstat)) - return; - - if(mstat & MS_CTS_ON) tmpmsr |= MSR_CTS; - if(mstat & MS_DSR_ON) tmpmsr |= MSR_DSR; - if(mstat & MS_RING_ON) tmpmsr |= MSR_RI; - if(mstat & MS_RLSD_ON) tmpmsr |= MSR_RLSD; - *pMsr = (*pMsr & ~MSR_MASK) | tmpmsr; -} - -void COMM_Init(void) -{ - int x; - char option[10], temp[256], *btemp; - struct stat st; - - for (x=0; x!=MAX_PORTS; x++) { - strcpy(option,"COMx"); - option[3] = '1' + x; - option[4] = '\0'; - - PROFILE_GetWineIniString( "serialports", option, "*", - temp, sizeof(temp) ); - if (!strcmp(temp, "*") || *temp == '\0') - COM[x].devicename = NULL; - else { - btemp = strchr(temp,','); - if (btemp != NULL) { - *btemp++ = '\0'; - COM[x].baudrate = atoi(btemp); - } else { - COM[x].baudrate = -1; - } - stat(temp, &st); - if (!S_ISCHR(st.st_mode)) - WARN("Can't use `%s' as %s !\n", temp, option); - else - if ((COM[x].devicename = malloc(strlen(temp)+1)) == NULL) - WARN("Can't malloc for device info!\n"); - else { - COM[x].handle = 0; - strcpy(COM[x].devicename, temp); - } - TRACE("%s = %s\n", option, COM[x].devicename); - } - - strcpy(option, "LPTx"); - option[3] = '1' + x; - option[4] = '\0'; - - PROFILE_GetWineIniString( "parallelports", option, "*", - temp, sizeof(temp) ); - if (!strcmp(temp, "*") || *temp == '\0') - LPT[x].devicename = NULL; - else { - stat(temp, &st); - if (!S_ISCHR(st.st_mode)) - WARN("Can't use `%s' as %s !\n", temp, option); - else - if ((LPT[x].devicename = malloc(strlen(temp)+1)) == NULL) - WARN("Can't malloc for device info!\n"); - else { - LPT[x].handle = 0; - strcpy(LPT[x].devicename, temp); - } - TRACE("%s = %s\n", option, LPT[x].devicename); - } - - } -} - - -static struct DosDeviceStruct *GetDeviceStruct(int index) -{ - if ((index&0x7F)<=MAX_PORTS) { - if (!(index&FLAG_LPT)) { - if (COM[index].handle) - return &COM[index]; - } else { - index &= 0x7f; - if (LPT[index].handle) - return &LPT[index]; - } - } - - return NULL; -} - -static int GetCommPort_ov(LPOVERLAPPED ov, int write) -{ - int x; - - for (x=0; xibuf_tail > ptr->ibuf_head) ? ptr->ibuf_size : 0) - + ptr->ibuf_head - ptr->ibuf_tail; -} - -static unsigned comm_outbuf(struct DosDeviceStruct *ptr) -{ - return ((ptr->obuf_tail > ptr->obuf_head) ? ptr->obuf_size : 0) - + ptr->obuf_head - ptr->obuf_tail; -} - static int COMM_WhackModem(int fd, unsigned int andy, unsigned int orrie) { unsigned int mstat, okay; @@ -268,895 +93,6 @@ static int COMM_WhackModem(int fd, unsigned int andy, unsigned int orrie) return ioctl(fd, TIOCMSET, &mstat); } -static void comm_waitread(struct DosDeviceStruct *ptr); -static void comm_waitwrite(struct DosDeviceStruct *ptr); - -static VOID WINAPI COMM16_ReadComplete(DWORD status, DWORD len, LPOVERLAPPED ov) -{ - int prev ; - WORD mask = 0; - int cid = GetCommPort_ov(ov,0); - struct DosDeviceStruct *ptr; - - if(cid<0) { - ERR("async write with bad overlapped pointer\n"); - return; - } - ptr = &COM[cid]; - - /* read data from comm port */ - if (status != STATUS_SUCCESS) { - ERR("async read failed\n"); - COM[cid].commerror = CE_RXOVER; - return; - } - TRACE("async read completed %ld bytes\n",len); - - prev = comm_inbuf(ptr); - - /* check for events */ - if ((ptr->eventmask & EV_RXFLAG) && - memchr(ptr->inbuf + ptr->ibuf_head, ptr->evtchar, len)) { - *(WORD*)(COM[cid].unknown) |= EV_RXFLAG; - mask |= CN_EVENT; - } - if (ptr->eventmask & EV_RXCHAR) { - *(WORD*)(COM[cid].unknown) |= EV_RXCHAR; - mask |= CN_EVENT; - } - - /* advance buffer position */ - ptr->ibuf_head += len; - if (ptr->ibuf_head >= ptr->ibuf_size) - ptr->ibuf_head = 0; - - /* check for notification */ - if (ptr->wnd && (ptr->n_read>0) && (prevn_read) && - (comm_inbuf(ptr)>=ptr->n_read)) { - /* passed the receive notification threshold */ - mask |= CN_RECEIVE; - } - - /* send notifications, if any */ - if (ptr->wnd && mask) { - TRACE("notifying %04x: cid=%d, mask=%02x\n", ptr->wnd, cid, mask); - if (Callout.PostMessageA) Callout.PostMessageA(ptr->wnd, WM_COMMNOTIFY, cid, mask); - } - - /* on real windows, this could cause problems, since it is recursive */ - /* restart the receive */ - comm_waitread(ptr); -} - -static VOID WINAPI COMM16_WriteComplete(DWORD status, DWORD len, LPOVERLAPPED ov) -{ - int prev, bleft; - WORD mask = 0; - int cid = GetCommPort_ov(ov,1); - struct DosDeviceStruct *ptr; - - if(cid<0) { - ERR("async write with bad overlapped pointer\n"); - return; - } - ptr = &COM[cid]; - - /* read data from comm port */ - if (status != STATUS_SUCCESS) { - ERR("async write failed\n"); - COM[cid].commerror = CE_RXOVER; - return; - } - TRACE("async write completed %ld bytes\n",len); - - /* update the buffer pointers */ - prev = comm_outbuf(&COM[cid]); - ptr->obuf_tail += len; - if (ptr->obuf_tail >= ptr->obuf_size) - ptr->obuf_tail = 0; - - /* write any TransmitCommChar character */ - if (ptr->xmit>=0) { - if(!WriteFile(ptr->handle, &(ptr->xmit), 1, &len, NULL)) - len = -1; - if (len > 0) ptr->xmit = -1; - } - - /* write from output queue */ - bleft = ((ptr->obuf_tail <= ptr->obuf_head) ? - ptr->obuf_head : ptr->obuf_size) - ptr->obuf_tail; - - /* check for notification */ - if (ptr->wnd && (ptr->n_write>0) && (prev>=ptr->n_write) && - (comm_outbuf(ptr)n_write)) { - /* passed the transmit notification threshold */ - mask |= CN_TRANSMIT; - } - - /* send notifications, if any */ - if (ptr->wnd && mask) { - TRACE("notifying %04x: cid=%d, mask=%02x\n", ptr->wnd, cid, mask); - if (Callout.PostMessageA) Callout.PostMessageA(ptr->wnd, WM_COMMNOTIFY, cid, mask); - } - - /* start again if necessary */ - if(bleft) - comm_waitwrite(ptr); -} - -static void comm_waitread(struct DosDeviceStruct *ptr) -{ - int bleft; - - bleft = ((ptr->ibuf_tail > ptr->ibuf_head) ? - (ptr->ibuf_tail-1) : ptr->ibuf_size) - ptr->ibuf_head; - /* FIXME: get timeouts working properly so we can read bleft bytes */ - ReadFileEx(ptr->handle, - ptr->inbuf + ptr->ibuf_head, - 1, - &ptr->read_ov, - COMM16_ReadComplete); -} - -static void comm_waitwrite(struct DosDeviceStruct *ptr) -{ - int bleft; - - bleft = ((ptr->obuf_tail <= ptr->obuf_head) ? - ptr->obuf_head : ptr->obuf_size) - ptr->obuf_tail; - WriteFileEx(ptr->handle, - ptr->outbuf + ptr->obuf_tail, - bleft, - &ptr->write_ov, - COMM16_WriteComplete); -} - -/***************************************************************************** - * COMM16_DCBtoDCB16 (Internal) - */ -INT16 COMM16_DCBtoDCB16(LPDCB lpdcb, LPDCB16 lpdcb16) -{ - if(lpdcb->BaudRate<0x10000) - lpdcb16->BaudRate = lpdcb->BaudRate; - else if(lpdcb->BaudRate==115200) - lpdcb16->BaudRate = 57601; - else { - WARN("Baud rate can't be converted\n"); - lpdcb16->BaudRate = 57601; - } - lpdcb16->ByteSize = lpdcb->ByteSize; - lpdcb16->fParity = lpdcb->fParity; - lpdcb16->Parity = lpdcb->Parity; - lpdcb16->StopBits = lpdcb->StopBits; - - lpdcb16->RlsTimeout = 50; - lpdcb16->CtsTimeout = 50; - lpdcb16->DsrTimeout = 50; - lpdcb16->fNull = 0; - lpdcb16->fChEvt = 0; - lpdcb16->fBinary = 1; - lpdcb16->fDtrDisable = 0; - - lpdcb16->fDtrflow = (lpdcb->fDtrControl==DTR_CONTROL_ENABLE); - lpdcb16->fRtsflow = (lpdcb->fRtsControl==RTS_CONTROL_ENABLE); - lpdcb16->fOutxCtsFlow = lpdcb->fOutxCtsFlow; - lpdcb16->fOutxDsrFlow = lpdcb->fOutxDsrFlow; - lpdcb16->fDtrDisable = (lpdcb->fDtrControl==DTR_CONTROL_DISABLE); - - lpdcb16->fInX = lpdcb->fInX; - - lpdcb16->fOutX = lpdcb->fOutX; -/* - lpdcb16->XonChar = - lpdcb16->XoffChar = - */ - lpdcb16->XonLim = 10; - lpdcb16->XoffLim = 10; - - return 0; -} - - -/************************************************************************** - * BuildCommDCB (USER.213) - * - * According to the ECMA-234 (368.3) the function will return FALSE on - * success, otherwise it will return -1. - */ -INT16 WINAPI BuildCommDCB16(LPCSTR device, LPDCB16 lpdcb) -{ - /* "COM1:96,n,8,1" */ - /* 012345 */ - int port; - DCB dcb; - - TRACE("(%s), ptr %p\n", device, lpdcb); - - if (strncasecmp(device,"COM",3)) - return -1; - port = device[3] - '0'; - - if (port-- == 0) { - ERR("BUG ! COM0 can't exist!\n"); - return -1; - } - - if (!ValidCOMPort(port)) { - FIXME("invalid COM port %d?\n",port); - return -1; - } - - memset(lpdcb, 0, sizeof(DCB16)); /* initialize */ - - lpdcb->Id = port; - dcb.DCBlength = sizeof(DCB); - - if (strchr(device,'=')) /* block new style */ - return -1; - - if(!BuildCommDCBA(device,&dcb)) - return -1; - - return COMM16_DCBtoDCB16(&dcb, lpdcb); - } - -/***************************************************************************** - * OpenComm (USER.200) - */ -INT16 WINAPI OpenComm16(LPCSTR device,UINT16 cbInQueue,UINT16 cbOutQueue) -{ - int port; - HANDLE handle; - - TRACE("%s, %d, %d\n", device, cbInQueue, cbOutQueue); - - if (strlen(device) < 4) - return IE_BADID; - - port = device[3] - '0'; - - if (port-- == 0) - ERR("BUG ! COM0 or LPT0 don't exist !\n"); - - if (!strncasecmp(device,"COM",3)) { - - TRACE("%s = %s\n", device, COM[port].devicename); - - if (!ValidCOMPort(port)) - return IE_BADID; - - if (COM[port].handle) - return IE_OPEN; - - handle = CreateFileA(device, GENERIC_READ|GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0 ); - if (handle == INVALID_HANDLE_VALUE) { - ERR("Couldn't open %s ! (%s)\n", COM[port].devicename, strerror(errno)); - return IE_HARDWARE; - } else { - COM[port].unknown = SEGPTR_ALLOC(40); - memset(COM[port].unknown, 0, 40); - COM[port].handle = handle; - COM[port].commerror = 0; - COM[port].eventmask = 0; - COM[port].evtchar = 0; /* FIXME: default? */ - /* save terminal state */ - GetCommState16(port,&COM[port].dcb); - /* set default parameters */ - if(COM[port].baudrate>-1){ - DCB16 dcb; - memcpy(&dcb,&COM[port].dcb,sizeof dcb); - dcb.BaudRate=COM[port].baudrate; - /* more defaults: - * databits, parity, stopbits - */ - SetCommState16( &dcb); - } - /* init priority characters */ - COM[port].unget = -1; - COM[port].xmit = -1; - /* allocate buffers */ - COM[port].ibuf_size = cbInQueue; - COM[port].ibuf_head = COM[port].ibuf_tail = 0; - COM[port].obuf_size = cbOutQueue; - COM[port].obuf_head = COM[port].obuf_tail = 0; - - COM[port].inbuf = malloc(cbInQueue); - if (COM[port].inbuf) { - COM[port].outbuf = malloc(cbOutQueue); - if (!COM[port].outbuf) - free(COM[port].inbuf); - } else COM[port].outbuf = NULL; - if (!COM[port].outbuf) { - /* not enough memory */ - SetCommState16(&COM[port].dcb); - CloseHandle(COM[port].handle); - ERR("out of memory\n"); - return IE_MEMORY; - } - - ZeroMemory(&COM[port].read_ov,sizeof (OVERLAPPED)); - ZeroMemory(&COM[port].write_ov,sizeof (OVERLAPPED)); - COM[port].read_ov.hEvent = CreateEventA(NULL,0,0,NULL); - COM[port].write_ov.hEvent = CreateEventA(NULL,0,0,NULL); - - comm_waitread( &COM[port] ); - - return port; - } - } - else - if (!strncasecmp(device,"LPT",3)) { - - if (!ValidLPTPort(port)) - return IE_BADID; - - if (LPT[port].handle) - return IE_OPEN; - - handle = CreateFileA(device, GENERIC_READ|GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0 ); - if (handle == INVALID_HANDLE_VALUE) { - return IE_HARDWARE; - } else { - LPT[port].handle = handle; - LPT[port].commerror = 0; - LPT[port].eventmask = 0; - return port|FLAG_LPT; - } - } - return IE_BADID; -} - -/***************************************************************************** - * CloseComm (USER.207) - */ -INT16 WINAPI CloseComm16(INT16 cid) -{ - struct DosDeviceStruct *ptr; - - TRACE("cid=%d\n", cid); - if ((ptr = GetDeviceStruct(cid)) == NULL) { - FIXME("no cid=%d found!\n", cid); - return -1; - } - if (!(cid&FLAG_LPT)) { - /* COM port */ - SEGPTR_FREE(COM[cid].unknown); /* [LW] */ - - CloseHandle(COM[cid].read_ov.hEvent); - CloseHandle(COM[cid].write_ov.hEvent); - - /* free buffers */ - free(ptr->outbuf); - free(ptr->inbuf); - - /* reset modem lines */ - SetCommState16(&COM[cid].dcb); - } - - if (!CloseHandle(ptr->handle)) { - ptr->commerror = WinError(); - /* FIXME: should we clear ptr->handle here? */ - return -1; - } else { - ptr->commerror = 0; - ptr->handle = 0; - return 0; - } -} - -/***************************************************************************** - * SetCommBreak (USER.210) - */ -INT16 WINAPI SetCommBreak16(INT16 cid) -{ - struct DosDeviceStruct *ptr; - - TRACE("cid=%d\n", cid); - if ((ptr = GetDeviceStruct(cid)) == NULL) { - FIXME("no cid=%d found!\n", cid); - return -1; - } - - ptr->suspended = 1; - ptr->commerror = 0; - return 0; -} - -/***************************************************************************** - * ClearCommBreak (USER.211) - */ -INT16 WINAPI ClearCommBreak16(INT16 cid) -{ - struct DosDeviceStruct *ptr; - - TRACE("cid=%d\n", cid); - if (!(ptr = GetDeviceStruct(cid))) { - FIXME("no cid=%d found!\n", cid); - return -1; - } - ptr->suspended = 0; - ptr->commerror = 0; - return 0; -} - -/***************************************************************************** - * EscapeCommFunction (USER.214) - */ -LONG WINAPI EscapeCommFunction16(UINT16 cid,UINT16 nFunction) -{ - struct DosDeviceStruct *ptr; - int max; - - TRACE("cid=%d, function=%d\n", cid, nFunction); - - switch(nFunction) { - case GETMAXCOM: - TRACE("GETMAXCOM\n"); - for (max = MAX_PORTS;!COM[max].devicename;max--) - ; - return max; - - case GETMAXLPT: - TRACE("GETMAXLPT\n"); - for (max = MAX_PORTS;!LPT[max].devicename;max--) - ; - return FLAG_LPT + max; - - case GETBASEIRQ: - TRACE("GETBASEIRQ\n"); - /* FIXME: use tables */ - /* just fake something for now */ - if (cid & FLAG_LPT) { - /* LPT1: irq 7, LPT2: irq 5 */ - return (cid & 0x7f) ? 5 : 7; - } else { - /* COM1: irq 4, COM2: irq 3, - COM3: irq 4, COM4: irq 3 */ - return 4 - (cid & 1); - } - } - - if ((ptr = GetDeviceStruct(cid)) == NULL) { - FIXME("no cid=%d found!\n", cid); - return -1; - } - - switch (nFunction) { - case RESETDEV: - case CLRDTR: - case CLRRTS: - case SETDTR: - case SETRTS: - case SETXOFF: - case SETXON: - if(EscapeCommFunction(ptr->handle,nFunction)) - return 0; - else { - ptr->commerror = WinError(); - return -1; - } - - case CLRBREAK: - case SETBREAK: - default: - WARN("(cid=%d,nFunction=%d): Unknown function\n", - cid, nFunction); - } - return -1; -} - -/***************************************************************************** - * FlushComm (USER.215) - */ -INT16 WINAPI FlushComm16(INT16 cid,INT16 fnQueue) -{ - DWORD queue; - struct DosDeviceStruct *ptr; - - TRACE("cid=%d, queue=%d\n", cid, fnQueue); - if ((ptr = GetDeviceStruct(cid)) == NULL) { - FIXME("no cid=%d found!\n", cid); - return -1; - } - switch (fnQueue) { - case 0: - queue = PURGE_TXABORT; - ptr->obuf_tail = ptr->obuf_head; - break; - case 1: - queue = PURGE_RXABORT; - ptr->ibuf_head = ptr->ibuf_tail; - break; - default: - WARN("(cid=%d,fnQueue=%d):Unknown queue\n", - cid, fnQueue); - return -1; - } - - if (!PurgeComm(ptr->handle,queue)) { - ptr->commerror = WinError(); - return -1; - } else { - ptr->commerror = 0; - return 0; - } -} - -/******************************************************************** - * GetCommError (USER.203) - */ -INT16 WINAPI GetCommError16(INT16 cid,LPCOMSTAT16 lpStat) -{ - int temperror; - struct DosDeviceStruct *ptr; - unsigned char *stol; - - if ((ptr = GetDeviceStruct(cid)) == NULL) { - FIXME("no handle for cid = %0x!\n",cid); - return -1; - } - if (cid&FLAG_LPT) { - WARN(" cid %d not comm port\n",cid); - return CE_MODE; - } - stol = (unsigned char *)COM[cid].unknown + COMM_MSR_OFFSET; - COMM_MSRUpdate( ptr->handle, stol ); - - if (lpStat) { - HANDLE rw_events[2]; - - lpStat->status = 0; - - rw_events[0] = COM[cid].read_ov.hEvent; - rw_events[1] = COM[cid].write_ov.hEvent; - - WaitForMultipleObjectsEx(2,&rw_events[0],FALSE,1,TRUE); - - lpStat->cbOutQue = comm_outbuf(ptr); - lpStat->cbInQue = comm_inbuf(ptr); - - TRACE("cid %d, error %d, stat %d in %d out %d, stol %x\n", - cid, ptr->commerror, lpStat->status, lpStat->cbInQue, - lpStat->cbOutQue, *stol); - } - else - TRACE("cid %d, error %d, lpStat NULL stol %x\n", - cid, ptr->commerror, *stol); - - /* Return any errors and clear it */ - temperror = ptr->commerror; - ptr->commerror = 0; - return(temperror); -} - -/***************************************************************************** - * SetCommEventMask (USER.208) - */ -SEGPTR WINAPI SetCommEventMask16(INT16 cid,UINT16 fuEvtMask) -{ - struct DosDeviceStruct *ptr; - unsigned char *stol; - - TRACE("cid %d,mask %d\n",cid,fuEvtMask); - if ((ptr = GetDeviceStruct(cid)) == NULL) { - FIXME("no handle for cid = %0x!\n",cid); - return (SEGPTR)NULL; - } - - ptr->eventmask = fuEvtMask; - - if ((cid&FLAG_LPT) || !ValidCOMPort(cid)) { - WARN(" cid %d not comm port\n",cid); - return (SEGPTR)NULL; - } - /* it's a COM port ? -> modify flags */ - stol = (unsigned char *)COM[cid].unknown + COMM_MSR_OFFSET; - COMM_MSRUpdate( ptr->handle, stol ); - - TRACE(" modem dcd construct %x\n",*stol); - return SEGPTR_GET(COM[cid].unknown); -} - -/***************************************************************************** - * GetCommEventMask (USER.209) - */ -UINT16 WINAPI GetCommEventMask16(INT16 cid,UINT16 fnEvtClear) -{ - struct DosDeviceStruct *ptr; - WORD events; - - TRACE("cid %d, mask %d\n", cid, fnEvtClear); - if ((ptr = GetDeviceStruct(cid)) == NULL) { - FIXME("no handle for cid = %0x!\n",cid); - return 0; - } - - if ((cid&FLAG_LPT) || !ValidCOMPort(cid)) { - WARN(" cid %d not comm port\n",cid); - return 0; - } - - events = *(WORD*)(COM[cid].unknown) & fnEvtClear; - *(WORD*)(COM[cid].unknown) &= ~fnEvtClear; - return events; -} - -/***************************************************************************** - * SetCommState (USER.201) - */ -INT16 WINAPI SetCommState16(LPDCB16 lpdcb) -{ - struct DosDeviceStruct *ptr; - DCB dcb; - - TRACE("cid %d, ptr %p\n", lpdcb->Id, lpdcb); - if ((ptr = GetDeviceStruct(lpdcb->Id)) == NULL) { - FIXME("no handle for cid = %0x!\n",lpdcb->Id); - return -1; - } - - memset(&dcb,0,sizeof dcb); - dcb.DCBlength = sizeof dcb; - if(lpdcb->BaudRate==57601) - dcb.BaudRate = 115200; - else - dcb.BaudRate = lpdcb->BaudRate; - - dcb.ByteSize=lpdcb->ByteSize; - dcb.StopBits=lpdcb->StopBits; - - dcb.fParity=lpdcb->fParity; - dcb.Parity=lpdcb->Parity; - - dcb.fOutxCtsFlow = lpdcb->fOutxCtsFlow; - - if (lpdcb->fDtrflow || lpdcb->fRtsflow) - dcb.fRtsControl = TRUE; - - if (lpdcb->fDtrDisable) - dcb.fDtrControl = TRUE; - - ptr->evtchar = lpdcb->EvtChar; - - dcb.fInX = lpdcb->fInX; - dcb.fOutX = lpdcb->fOutX; - - if (!SetCommState(ptr->handle,&dcb)) { - ptr->commerror = WinError(); - return -1; - } else { - ptr->commerror = 0; - return 0; - } -} - -/***************************************************************************** - * GetCommState (USER.202) - */ -INT16 WINAPI GetCommState16(INT16 cid, LPDCB16 lpdcb) -{ - struct DosDeviceStruct *ptr; - DCB dcb; - - TRACE("cid %d, ptr %p\n", cid, lpdcb); - if ((ptr = GetDeviceStruct(cid)) == NULL) { - FIXME("no handle for cid = %0x!\n",cid); - return -1; - } - if (!GetCommState(ptr->handle,&dcb)) { - ptr->commerror = WinError(); - return -1; - } - - lpdcb->Id = cid; - - COMM16_DCBtoDCB16(&dcb,lpdcb); - - lpdcb->EvtChar = ptr->evtchar; - - ptr->commerror = 0; - return 0; -} - -/***************************************************************************** - * TransmitCommChar (USER.206) - */ -INT16 WINAPI TransmitCommChar16(INT16 cid,CHAR chTransmit) -{ - struct DosDeviceStruct *ptr; - - TRACE("cid %d, data %d \n", cid, chTransmit); - if ((ptr = GetDeviceStruct(cid)) == NULL) { - FIXME("no handle for cid = %0x!\n",cid); - return -1; - } - - if (ptr->suspended) { - ptr->commerror = IE_HARDWARE; - return -1; - } - - if (ptr->xmit >= 0) { - /* character already queued */ - /* FIXME: which error would Windows return? */ - ptr->commerror = CE_TXFULL; - return -1; - } - - if (ptr->obuf_head == ptr->obuf_tail) { - /* transmit queue empty, try to transmit directly */ - DWORD len; - if(!WriteFile(ptr->handle, &chTransmit, 1, &len, NULL)) { - /* didn't work, queue it */ - ptr->xmit = chTransmit; - comm_waitwrite(ptr); - } - } else { - /* data in queue, let this char be transmitted next */ - ptr->xmit = chTransmit; - comm_waitwrite(ptr); - } - - ptr->commerror = 0; - return 0; -} - -/***************************************************************************** - * UngetCommChar (USER.212) - */ -INT16 WINAPI UngetCommChar16(INT16 cid,CHAR chUnget) -{ - struct DosDeviceStruct *ptr; - - TRACE("cid %d (char %d)\n", cid, chUnget); - if ((ptr = GetDeviceStruct(cid)) == NULL) { - FIXME("no handle for cid = %0x!\n",cid); - return -1; - } - - if (ptr->suspended) { - ptr->commerror = IE_HARDWARE; - return -1; - } - - if (ptr->unget>=0) { - /* character already queued */ - /* FIXME: which error would Windows return? */ - ptr->commerror = CE_RXOVER; - return -1; - } - - ptr->unget = chUnget; - - ptr->commerror = 0; - return 0; -} - -/***************************************************************************** - * ReadComm (USER.204) - */ -INT16 WINAPI ReadComm16(INT16 cid,LPSTR lpvBuf,INT16 cbRead) -{ - int status, length; - struct DosDeviceStruct *ptr; - LPSTR orgBuf = lpvBuf; - - TRACE("cid %d, ptr %p, length %d\n", cid, lpvBuf, cbRead); - if ((ptr = GetDeviceStruct(cid)) == NULL) { - FIXME("no handle for cid = %0x!\n",cid); - return -1; - } - - if (ptr->suspended) { - ptr->commerror = IE_HARDWARE; - return -1; - } - - /* read unget character */ - if (ptr->unget>=0) { - *lpvBuf++ = ptr->unget; - ptr->unget = -1; - - length = 1; - } else - length = 0; - - /* read from receive buffer */ - while (length < cbRead) { - status = ((ptr->ibuf_head < ptr->ibuf_tail) ? - ptr->ibuf_size : ptr->ibuf_head) - ptr->ibuf_tail; - if (!status) break; - if ((cbRead - length) < status) - status = cbRead - length; - - memcpy(lpvBuf, ptr->inbuf + ptr->ibuf_tail, status); - ptr->ibuf_tail += status; - if (ptr->ibuf_tail >= ptr->ibuf_size) - ptr->ibuf_tail = 0; - lpvBuf += status; - length += status; - } - - TRACE("%.*s\n", length, orgBuf); - ptr->commerror = 0; - return length; -} - -/***************************************************************************** - * WriteComm (USER.205) - */ -INT16 WINAPI WriteComm16(INT16 cid, LPSTR lpvBuf, INT16 cbWrite) -{ - int status, length; - struct DosDeviceStruct *ptr; - - TRACE("cid %d, ptr %p, length %d\n", - cid, lpvBuf, cbWrite); - if ((ptr = GetDeviceStruct(cid)) == NULL) { - FIXME("no handle for cid = %0x!\n",cid); - return -1; - } - - if (ptr->suspended) { - ptr->commerror = IE_HARDWARE; - return -1; - } - - TRACE("%.*s\n", cbWrite, lpvBuf ); - - length = 0; - while (length < cbWrite) { - if ((ptr->obuf_head == ptr->obuf_tail) && (ptr->xmit < 0)) { - /* no data queued, try to write directly */ - if(!WriteFile(ptr->handle, lpvBuf, cbWrite - length, (LPDWORD)&status, NULL)) - status = -1; - if (status > 0) { - lpvBuf += status; - length += status; - continue; - } - } - /* can't write directly, put into transmit buffer */ - status = ((ptr->obuf_tail > ptr->obuf_head) ? - (ptr->obuf_tail-1) : ptr->obuf_size) - ptr->obuf_head; - if (!status) break; - if ((cbWrite - length) < status) - status = cbWrite - length; - memcpy(lpvBuf, ptr->outbuf + ptr->obuf_head, status); - ptr->obuf_head += status; - if (ptr->obuf_head >= ptr->obuf_size) - ptr->obuf_head = 0; - lpvBuf += status; - length += status; - comm_waitwrite(ptr); - } - - ptr->commerror = 0; - return length; -} - -/*********************************************************************** - * EnableCommNotification (USER.245) - */ -BOOL16 WINAPI EnableCommNotification16( INT16 cid, HWND16 hwnd, - INT16 cbWriteNotify, INT16 cbOutQueue ) -{ - struct DosDeviceStruct *ptr; - - TRACE("(%d, %x, %d, %d)\n", cid, hwnd, cbWriteNotify, cbOutQueue); - if ((ptr = GetDeviceStruct(cid)) == NULL) { - FIXME("no handle for cid = %0x!\n",cid); - return -1; - } - ptr->wnd = hwnd; - ptr->n_read = cbWriteNotify; - ptr->n_write = cbOutQueue; - return TRUE; -} - - /*********************************************************************** * COMM_BuildOldCommDCB (Internal) * @@ -1333,8 +269,6 @@ BOOL WINAPI BuildCommDCBAndTimeoutsA( ERR("BUG! COM0 can't exist!\n"); return FALSE; } - if (!ValidCOMPort(port)) - return FALSE; if (*(device+4)!=':') return FALSE; temp=(LPSTR)(device+5); @@ -2988,9 +1922,6 @@ BOOL WINAPI GetDefaultCommConfigA( return FALSE; } - if (!ValidCOMPort(lpszName[3]-'1')) - return FALSE; - TRACE("(%s %p %ld)\n", lpszName, lpCC, *lpdwSize ); if (*lpdwSize < sizeof(COMMCONFIG)) { *lpdwSize = sizeof(COMMCONFIG); diff --git a/dlls/kernel/kernel_main.c b/dlls/kernel/kernel_main.c index 382f185540e..229dcc08089 100644 --- a/dlls/kernel/kernel_main.c +++ b/dlls/kernel/kernel_main.c @@ -20,7 +20,6 @@ extern void CODEPAGE_Init(void); extern BOOL RELAY_Init(void); extern BOOL THUNK_Init(void); -extern void COMM_Init(void); /*********************************************************************** @@ -77,9 +76,6 @@ static BOOL process_attach(void) /* Force loading of some dlls */ if (LoadLibrary16( "system" ) < 32) return FALSE; - /* Initialize communications */ - COMM_Init(); - /* Read DOS config.sys */ if (!DOSCONF_ReadConfig()) return FALSE; diff --git a/dlls/user/Makefile.in b/dlls/user/Makefile.in index 21701698d9b..eb6f038a50c 100644 --- a/dlls/user/Makefile.in +++ b/dlls/user/Makefile.in @@ -10,6 +10,7 @@ IMPORTS = gdi32 kernel32 ntdll C_SRCS = \ bidi16.c \ cache.c \ + comm16.c \ dde/client.c \ dde/ddeml16.c \ dde/misc.c \ diff --git a/dlls/user/comm16.c b/dlls/user/comm16.c new file mode 100644 index 00000000000..f2da71bcccb --- /dev/null +++ b/dlls/user/comm16.c @@ -0,0 +1,1112 @@ +/* + * DEC 93 Erik Bos + * + * Copyright 1996 Marcus Meissner + * + * Copyright 2001 Mike McCormack + * + * Mar 31, 1999. Ove Kåven + * - Implemented buffers and EnableCommNotification. + * + * Apr 3, 1999. Lawson Whitney + * - Fixed the modem control part of EscapeCommFunction16. + * + * Mar 3, 1999. Ove Kåven + * - Use port indices instead of unixfds for win16 + * - Moved things around (separated win16 and win32 routines) + * - Added some hints on how to implement buffers and EnableCommNotification. + * + * May 26, 1997. Fixes and comments by Rick Richardson [RER] + * - ptr->fd wasn't getting cleared on close. + * - GetCommEventMask() and GetCommError() didn't do much of anything. + * IMHO, they are still wrong, but they at least implement the RXCHAR + * event and return I/O queue sizes, which makes the app I'm interested + * in (analog devices EZKIT DSP development system) work. + * + * August 12, 1997. Take a bash at SetCommEventMask - Lawson Whitney + * + * July 6, 1998. Fixes and comments by Valentijn Sessink + * [V] + * Oktober 98, Rein Klazes [RHK] + * A program that wants to monitor the modem status line (RLSD/DCD) may + * poll the modem status register in the commMask structure. I update the bit + * in GetCommError, waiting for an implementation of communication events. + * + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "wine/winuser16.h" +#include "wine/port.h" +#include "heap.h" +#include "options.h" +#include "winerror.h" + +#include "debugtools.h" + +DEFAULT_DEBUG_CHANNEL(comm); + +/* window's semi documented modem status register */ +#define COMM_MSR_OFFSET 35 +#define MSR_CTS 0x10 +#define MSR_DSR 0x20 +#define MSR_RI 0x40 +#define MSR_RLSD 0x80 +#define MSR_MASK (MSR_CTS|MSR_DSR|MSR_RI|MSR_RLSD) + +#define FLAG_LPT 0x80 + +#define MAX_PORTS 9 + +struct DosDeviceStruct { + char *devicename; /* /dev/ttyS0 */ + HANDLE handle; + int suspended; + int unget,xmit; + int baudrate; + int evtchar; + /* events */ + int commerror, eventmask; + /* buffers */ + char *inbuf,*outbuf; + unsigned ibuf_size,ibuf_head,ibuf_tail; + unsigned obuf_size,obuf_head,obuf_tail; + /* notifications */ + int wnd, n_read, n_write; + OVERLAPPED read_ov, write_ov; + /* save terminal states */ + DCB16 dcb; + /* pointer to unknown(==undocumented) comm structure */ + LPCVOID *unknown; +}; + +static struct DosDeviceStruct COM[MAX_PORTS]; +static struct DosDeviceStruct LPT[MAX_PORTS]; + +/* update window's semi documented modem status register */ +/* see knowledge base Q101417 */ +static void COMM_MSRUpdate( HANDLE handle, UCHAR * pMsr ) +{ + UCHAR tmpmsr=0; + DWORD mstat=0; + + if(!GetCommModemStatus(handle,&mstat)) + return; + + if(mstat & MS_CTS_ON) tmpmsr |= MSR_CTS; + if(mstat & MS_DSR_ON) tmpmsr |= MSR_DSR; + if(mstat & MS_RING_ON) tmpmsr |= MSR_RI; + if(mstat & MS_RLSD_ON) tmpmsr |= MSR_RLSD; + *pMsr = (*pMsr & ~MSR_MASK) | tmpmsr; +} + +void COMM_Init(void) +{ + int x; + char option[10], temp[256], *btemp; + + for (x=0; x!=MAX_PORTS; x++) { + strcpy(option,"COMx"); + option[3] = '1' + x; + option[4] = '\0'; + + PROFILE_GetWineIniString( "serialports", option, "*", + temp, sizeof(temp) ); + if (!strcmp(temp, "*") || *temp == '\0') + COM[x].devicename = NULL; + else { + btemp = strchr(temp,','); + if (btemp != NULL) { + *btemp++ = '\0'; + COM[x].baudrate = atoi(btemp); + } else { + COM[x].baudrate = -1; + } + if ((COM[x].devicename = malloc(strlen(temp)+1)) == NULL) + WARN("Can't malloc for device info!\n"); + else { + COM[x].handle = 0; + strcpy(COM[x].devicename, temp); + } + TRACE("%s = %s\n", option, COM[x].devicename); + } + + strcpy(option, "LPTx"); + option[3] = '1' + x; + option[4] = '\0'; + + PROFILE_GetWineIniString( "parallelports", option, "*", + temp, sizeof(temp) ); + if (!strcmp(temp, "*") || *temp == '\0') + LPT[x].devicename = NULL; + else { + if ((LPT[x].devicename = malloc(strlen(temp)+1)) == NULL) + WARN("Can't malloc for device info!\n"); + else { + LPT[x].handle = 0; + strcpy(LPT[x].devicename, temp); + } + TRACE("%s = %s\n", option, LPT[x].devicename); + } + + } +} + + +static struct DosDeviceStruct *GetDeviceStruct(int index) +{ + if ((index&0x7F)<=MAX_PORTS) { + if (!(index&FLAG_LPT)) { + if (COM[index].handle) + return &COM[index]; + } else { + index &= 0x7f; + if (LPT[index].handle) + return &LPT[index]; + } + } + + return NULL; +} + +static int GetCommPort_ov(LPOVERLAPPED ov, int write) +{ + int x; + + for (x=0; xibuf_tail > ptr->ibuf_head) ? ptr->ibuf_size : 0) + + ptr->ibuf_head - ptr->ibuf_tail; +} + +static unsigned comm_outbuf(struct DosDeviceStruct *ptr) +{ + return ((ptr->obuf_tail > ptr->obuf_head) ? ptr->obuf_size : 0) + + ptr->obuf_head - ptr->obuf_tail; +} + +static void comm_waitread(struct DosDeviceStruct *ptr); +static void comm_waitwrite(struct DosDeviceStruct *ptr); + +static VOID WINAPI COMM16_ReadComplete(DWORD status, DWORD len, LPOVERLAPPED ov) +{ + int prev ; + WORD mask = 0; + int cid = GetCommPort_ov(ov,0); + struct DosDeviceStruct *ptr; + + if(cid<0) { + ERR("async write with bad overlapped pointer\n"); + return; + } + ptr = &COM[cid]; + + /* read data from comm port */ + if (status != STATUS_SUCCESS) { + ERR("async read failed\n"); + COM[cid].commerror = CE_RXOVER; + return; + } + TRACE("async read completed %ld bytes\n",len); + + prev = comm_inbuf(ptr); + + /* check for events */ + if ((ptr->eventmask & EV_RXFLAG) && + memchr(ptr->inbuf + ptr->ibuf_head, ptr->evtchar, len)) { + *(WORD*)(COM[cid].unknown) |= EV_RXFLAG; + mask |= CN_EVENT; + } + if (ptr->eventmask & EV_RXCHAR) { + *(WORD*)(COM[cid].unknown) |= EV_RXCHAR; + mask |= CN_EVENT; + } + + /* advance buffer position */ + ptr->ibuf_head += len; + if (ptr->ibuf_head >= ptr->ibuf_size) + ptr->ibuf_head = 0; + + /* check for notification */ + if (ptr->wnd && (ptr->n_read>0) && (prevn_read) && + (comm_inbuf(ptr)>=ptr->n_read)) { + /* passed the receive notification threshold */ + mask |= CN_RECEIVE; + } + + /* send notifications, if any */ + if (ptr->wnd && mask) { + TRACE("notifying %04x: cid=%d, mask=%02x\n", ptr->wnd, cid, mask); + PostMessageA(ptr->wnd, WM_COMMNOTIFY, cid, mask); + } + + /* on real windows, this could cause problems, since it is recursive */ + /* restart the receive */ + comm_waitread(ptr); +} + +static VOID WINAPI COMM16_WriteComplete(DWORD status, DWORD len, LPOVERLAPPED ov) +{ + int prev, bleft; + WORD mask = 0; + int cid = GetCommPort_ov(ov,1); + struct DosDeviceStruct *ptr; + + if(cid<0) { + ERR("async write with bad overlapped pointer\n"); + return; + } + ptr = &COM[cid]; + + /* read data from comm port */ + if (status != STATUS_SUCCESS) { + ERR("async write failed\n"); + COM[cid].commerror = CE_RXOVER; + return; + } + TRACE("async write completed %ld bytes\n",len); + + /* update the buffer pointers */ + prev = comm_outbuf(&COM[cid]); + ptr->obuf_tail += len; + if (ptr->obuf_tail >= ptr->obuf_size) + ptr->obuf_tail = 0; + + /* write any TransmitCommChar character */ + if (ptr->xmit>=0) { + if(!WriteFile(ptr->handle, &(ptr->xmit), 1, &len, NULL)) + len = -1; + if (len > 0) ptr->xmit = -1; + } + + /* write from output queue */ + bleft = ((ptr->obuf_tail <= ptr->obuf_head) ? + ptr->obuf_head : ptr->obuf_size) - ptr->obuf_tail; + + /* check for notification */ + if (ptr->wnd && (ptr->n_write>0) && (prev>=ptr->n_write) && + (comm_outbuf(ptr)n_write)) { + /* passed the transmit notification threshold */ + mask |= CN_TRANSMIT; + } + + /* send notifications, if any */ + if (ptr->wnd && mask) { + TRACE("notifying %04x: cid=%d, mask=%02x\n", ptr->wnd, cid, mask); + PostMessageA(ptr->wnd, WM_COMMNOTIFY, cid, mask); + } + + /* start again if necessary */ + if(bleft) + comm_waitwrite(ptr); +} + +static void comm_waitread(struct DosDeviceStruct *ptr) +{ + int bleft; + + bleft = ((ptr->ibuf_tail > ptr->ibuf_head) ? + (ptr->ibuf_tail-1) : ptr->ibuf_size) - ptr->ibuf_head; + /* FIXME: get timeouts working properly so we can read bleft bytes */ + ReadFileEx(ptr->handle, + ptr->inbuf + ptr->ibuf_head, + 1, + &ptr->read_ov, + COMM16_ReadComplete); +} + +static void comm_waitwrite(struct DosDeviceStruct *ptr) +{ + int bleft; + + bleft = ((ptr->obuf_tail <= ptr->obuf_head) ? + ptr->obuf_head : ptr->obuf_size) - ptr->obuf_tail; + WriteFileEx(ptr->handle, + ptr->outbuf + ptr->obuf_tail, + bleft, + &ptr->write_ov, + COMM16_WriteComplete); +} + +/***************************************************************************** + * COMM16_DCBtoDCB16 (Internal) + */ +INT16 COMM16_DCBtoDCB16(LPDCB lpdcb, LPDCB16 lpdcb16) +{ + if(lpdcb->BaudRate<0x10000) + lpdcb16->BaudRate = lpdcb->BaudRate; + else if(lpdcb->BaudRate==115200) + lpdcb16->BaudRate = 57601; + else { + WARN("Baud rate can't be converted\n"); + lpdcb16->BaudRate = 57601; + } + lpdcb16->ByteSize = lpdcb->ByteSize; + lpdcb16->fParity = lpdcb->fParity; + lpdcb16->Parity = lpdcb->Parity; + lpdcb16->StopBits = lpdcb->StopBits; + + lpdcb16->RlsTimeout = 50; + lpdcb16->CtsTimeout = 50; + lpdcb16->DsrTimeout = 50; + lpdcb16->fNull = 0; + lpdcb16->fChEvt = 0; + lpdcb16->fBinary = 1; + lpdcb16->fDtrDisable = 0; + + lpdcb16->fDtrflow = (lpdcb->fDtrControl==DTR_CONTROL_ENABLE); + lpdcb16->fRtsflow = (lpdcb->fRtsControl==RTS_CONTROL_ENABLE); + lpdcb16->fOutxCtsFlow = lpdcb->fOutxCtsFlow; + lpdcb16->fOutxDsrFlow = lpdcb->fOutxDsrFlow; + lpdcb16->fDtrDisable = (lpdcb->fDtrControl==DTR_CONTROL_DISABLE); + + lpdcb16->fInX = lpdcb->fInX; + + lpdcb16->fOutX = lpdcb->fOutX; +/* + lpdcb16->XonChar = + lpdcb16->XoffChar = + */ + lpdcb16->XonLim = 10; + lpdcb16->XoffLim = 10; + + return 0; +} + + +/************************************************************************** + * BuildCommDCB (USER.213) + * + * According to the ECMA-234 (368.3) the function will return FALSE on + * success, otherwise it will return -1. + */ +INT16 WINAPI BuildCommDCB16(LPCSTR device, LPDCB16 lpdcb) +{ + /* "COM1:96,n,8,1" */ + /* 012345 */ + int port; + DCB dcb; + + TRACE("(%s), ptr %p\n", device, lpdcb); + + if (strncasecmp(device,"COM",3)) + return -1; + port = device[3] - '0'; + + if (port-- == 0) { + ERR("BUG ! COM0 can't exist!\n"); + return -1; + } + + if (!ValidCOMPort(port)) { + FIXME("invalid COM port %d?\n",port); + return -1; + } + + memset(lpdcb, 0, sizeof(DCB16)); /* initialize */ + + lpdcb->Id = port; + dcb.DCBlength = sizeof(DCB); + + if (strchr(device,'=')) /* block new style */ + return -1; + + if(!BuildCommDCBA(device,&dcb)) + return -1; + + return COMM16_DCBtoDCB16(&dcb, lpdcb); +} + +/***************************************************************************** + * OpenComm (USER.200) + */ +INT16 WINAPI OpenComm16(LPCSTR device,UINT16 cbInQueue,UINT16 cbOutQueue) +{ + int port; + HANDLE handle; + + TRACE("%s, %d, %d\n", device, cbInQueue, cbOutQueue); + + if (strlen(device) < 4) + return IE_BADID; + + port = device[3] - '0'; + + if (port-- == 0) + ERR("BUG ! COM0 or LPT0 don't exist !\n"); + + if (!strncasecmp(device,"COM",3)) { + + TRACE("%s = %s\n", device, COM[port].devicename); + + if (!ValidCOMPort(port)) + return IE_BADID; + + if (COM[port].handle) + return IE_OPEN; + + handle = CreateFileA(device, GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0 ); + if (handle == INVALID_HANDLE_VALUE) { + ERR("Couldn't open %s ! (%s)\n", COM[port].devicename, strerror(errno)); + return IE_HARDWARE; + } else { + COM[port].unknown = SEGPTR_ALLOC(40); + memset(COM[port].unknown, 0, 40); + COM[port].handle = handle; + COM[port].commerror = 0; + COM[port].eventmask = 0; + COM[port].evtchar = 0; /* FIXME: default? */ + /* save terminal state */ + GetCommState16(port,&COM[port].dcb); + /* set default parameters */ + if(COM[port].baudrate>-1){ + DCB16 dcb; + memcpy(&dcb,&COM[port].dcb,sizeof dcb); + dcb.BaudRate=COM[port].baudrate; + /* more defaults: + * databits, parity, stopbits + */ + SetCommState16( &dcb); + } + /* init priority characters */ + COM[port].unget = -1; + COM[port].xmit = -1; + /* allocate buffers */ + COM[port].ibuf_size = cbInQueue; + COM[port].ibuf_head = COM[port].ibuf_tail = 0; + COM[port].obuf_size = cbOutQueue; + COM[port].obuf_head = COM[port].obuf_tail = 0; + + COM[port].inbuf = malloc(cbInQueue); + if (COM[port].inbuf) { + COM[port].outbuf = malloc(cbOutQueue); + if (!COM[port].outbuf) + free(COM[port].inbuf); + } else COM[port].outbuf = NULL; + if (!COM[port].outbuf) { + /* not enough memory */ + SetCommState16(&COM[port].dcb); + CloseHandle(COM[port].handle); + ERR("out of memory\n"); + return IE_MEMORY; + } + + ZeroMemory(&COM[port].read_ov,sizeof (OVERLAPPED)); + ZeroMemory(&COM[port].write_ov,sizeof (OVERLAPPED)); + COM[port].read_ov.hEvent = CreateEventA(NULL,0,0,NULL); + COM[port].write_ov.hEvent = CreateEventA(NULL,0,0,NULL); + + comm_waitread( &COM[port] ); + + return port; + } + } + else + if (!strncasecmp(device,"LPT",3)) { + + if (!ValidLPTPort(port)) + return IE_BADID; + + if (LPT[port].handle) + return IE_OPEN; + + handle = CreateFileA(device, GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0 ); + if (handle == INVALID_HANDLE_VALUE) { + return IE_HARDWARE; + } else { + LPT[port].handle = handle; + LPT[port].commerror = 0; + LPT[port].eventmask = 0; + return port|FLAG_LPT; + } + } + return IE_BADID; +} + +/***************************************************************************** + * CloseComm (USER.207) + */ +INT16 WINAPI CloseComm16(INT16 cid) +{ + struct DosDeviceStruct *ptr; + + TRACE("cid=%d\n", cid); + if ((ptr = GetDeviceStruct(cid)) == NULL) { + FIXME("no cid=%d found!\n", cid); + return -1; + } + if (!(cid&FLAG_LPT)) { + /* COM port */ + SEGPTR_FREE(COM[cid].unknown); /* [LW] */ + + CloseHandle(COM[cid].read_ov.hEvent); + CloseHandle(COM[cid].write_ov.hEvent); + + /* free buffers */ + free(ptr->outbuf); + free(ptr->inbuf); + + /* reset modem lines */ + SetCommState16(&COM[cid].dcb); + } + + if (!CloseHandle(ptr->handle)) { + ptr->commerror = WinError(); + /* FIXME: should we clear ptr->handle here? */ + return -1; + } else { + ptr->commerror = 0; + ptr->handle = 0; + return 0; + } +} + +/***************************************************************************** + * SetCommBreak (USER.210) + */ +INT16 WINAPI SetCommBreak16(INT16 cid) +{ + struct DosDeviceStruct *ptr; + + TRACE("cid=%d\n", cid); + if ((ptr = GetDeviceStruct(cid)) == NULL) { + FIXME("no cid=%d found!\n", cid); + return -1; + } + + ptr->suspended = 1; + ptr->commerror = 0; + return 0; +} + +/***************************************************************************** + * ClearCommBreak (USER.211) + */ +INT16 WINAPI ClearCommBreak16(INT16 cid) +{ + struct DosDeviceStruct *ptr; + + TRACE("cid=%d\n", cid); + if (!(ptr = GetDeviceStruct(cid))) { + FIXME("no cid=%d found!\n", cid); + return -1; + } + ptr->suspended = 0; + ptr->commerror = 0; + return 0; +} + +/***************************************************************************** + * EscapeCommFunction (USER.214) + */ +LONG WINAPI EscapeCommFunction16(UINT16 cid,UINT16 nFunction) +{ + struct DosDeviceStruct *ptr; + int max; + + TRACE("cid=%d, function=%d\n", cid, nFunction); + + switch(nFunction) { + case GETMAXCOM: + TRACE("GETMAXCOM\n"); + for (max = MAX_PORTS;!COM[max].devicename;max--) + ; + return max; + + case GETMAXLPT: + TRACE("GETMAXLPT\n"); + for (max = MAX_PORTS;!LPT[max].devicename;max--) + ; + return FLAG_LPT + max; + + case GETBASEIRQ: + TRACE("GETBASEIRQ\n"); + /* FIXME: use tables */ + /* just fake something for now */ + if (cid & FLAG_LPT) { + /* LPT1: irq 7, LPT2: irq 5 */ + return (cid & 0x7f) ? 5 : 7; + } else { + /* COM1: irq 4, COM2: irq 3, + COM3: irq 4, COM4: irq 3 */ + return 4 - (cid & 1); + } + } + + if ((ptr = GetDeviceStruct(cid)) == NULL) { + FIXME("no cid=%d found!\n", cid); + return -1; + } + + switch (nFunction) { + case RESETDEV: + case CLRDTR: + case CLRRTS: + case SETDTR: + case SETRTS: + case SETXOFF: + case SETXON: + if(EscapeCommFunction(ptr->handle,nFunction)) + return 0; + else { + ptr->commerror = WinError(); + return -1; + } + + case CLRBREAK: + case SETBREAK: + default: + WARN("(cid=%d,nFunction=%d): Unknown function\n", + cid, nFunction); + } + return -1; +} + +/***************************************************************************** + * FlushComm (USER.215) + */ +INT16 WINAPI FlushComm16(INT16 cid,INT16 fnQueue) +{ + DWORD queue; + struct DosDeviceStruct *ptr; + + TRACE("cid=%d, queue=%d\n", cid, fnQueue); + if ((ptr = GetDeviceStruct(cid)) == NULL) { + FIXME("no cid=%d found!\n", cid); + return -1; + } + switch (fnQueue) { + case 0: + queue = PURGE_TXABORT; + ptr->obuf_tail = ptr->obuf_head; + break; + case 1: + queue = PURGE_RXABORT; + ptr->ibuf_head = ptr->ibuf_tail; + break; + default: + WARN("(cid=%d,fnQueue=%d):Unknown queue\n", + cid, fnQueue); + return -1; + } + + if (!PurgeComm(ptr->handle,queue)) { + ptr->commerror = WinError(); + return -1; + } else { + ptr->commerror = 0; + return 0; + } +} + +/******************************************************************** + * GetCommError (USER.203) + */ +INT16 WINAPI GetCommError16(INT16 cid,LPCOMSTAT16 lpStat) +{ + int temperror; + struct DosDeviceStruct *ptr; + unsigned char *stol; + + if ((ptr = GetDeviceStruct(cid)) == NULL) { + FIXME("no handle for cid = %0x!\n",cid); + return -1; + } + if (cid&FLAG_LPT) { + WARN(" cid %d not comm port\n",cid); + return CE_MODE; + } + stol = (unsigned char *)COM[cid].unknown + COMM_MSR_OFFSET; + COMM_MSRUpdate( ptr->handle, stol ); + + if (lpStat) { + HANDLE rw_events[2]; + + lpStat->status = 0; + + rw_events[0] = COM[cid].read_ov.hEvent; + rw_events[1] = COM[cid].write_ov.hEvent; + + WaitForMultipleObjectsEx(2,&rw_events[0],FALSE,1,TRUE); + + lpStat->cbOutQue = comm_outbuf(ptr); + lpStat->cbInQue = comm_inbuf(ptr); + + TRACE("cid %d, error %d, stat %d in %d out %d, stol %x\n", + cid, ptr->commerror, lpStat->status, lpStat->cbInQue, + lpStat->cbOutQue, *stol); + } + else + TRACE("cid %d, error %d, lpStat NULL stol %x\n", + cid, ptr->commerror, *stol); + + /* Return any errors and clear it */ + temperror = ptr->commerror; + ptr->commerror = 0; + return(temperror); +} + +/***************************************************************************** + * SetCommEventMask (USER.208) + */ +SEGPTR WINAPI SetCommEventMask16(INT16 cid,UINT16 fuEvtMask) +{ + struct DosDeviceStruct *ptr; + unsigned char *stol; + + TRACE("cid %d,mask %d\n",cid,fuEvtMask); + if ((ptr = GetDeviceStruct(cid)) == NULL) { + FIXME("no handle for cid = %0x!\n",cid); + return (SEGPTR)NULL; + } + + ptr->eventmask = fuEvtMask; + + if ((cid&FLAG_LPT) || !ValidCOMPort(cid)) { + WARN(" cid %d not comm port\n",cid); + return (SEGPTR)NULL; + } + /* it's a COM port ? -> modify flags */ + stol = (unsigned char *)COM[cid].unknown + COMM_MSR_OFFSET; + COMM_MSRUpdate( ptr->handle, stol ); + + TRACE(" modem dcd construct %x\n",*stol); + return SEGPTR_GET(COM[cid].unknown); +} + +/***************************************************************************** + * GetCommEventMask (USER.209) + */ +UINT16 WINAPI GetCommEventMask16(INT16 cid,UINT16 fnEvtClear) +{ + struct DosDeviceStruct *ptr; + WORD events; + + TRACE("cid %d, mask %d\n", cid, fnEvtClear); + if ((ptr = GetDeviceStruct(cid)) == NULL) { + FIXME("no handle for cid = %0x!\n",cid); + return 0; + } + + if ((cid&FLAG_LPT) || !ValidCOMPort(cid)) { + WARN(" cid %d not comm port\n",cid); + return 0; + } + + events = *(WORD*)(COM[cid].unknown) & fnEvtClear; + *(WORD*)(COM[cid].unknown) &= ~fnEvtClear; + return events; +} + +/***************************************************************************** + * SetCommState (USER.201) + */ +INT16 WINAPI SetCommState16(LPDCB16 lpdcb) +{ + struct DosDeviceStruct *ptr; + DCB dcb; + + TRACE("cid %d, ptr %p\n", lpdcb->Id, lpdcb); + if ((ptr = GetDeviceStruct(lpdcb->Id)) == NULL) { + FIXME("no handle for cid = %0x!\n",lpdcb->Id); + return -1; + } + + memset(&dcb,0,sizeof dcb); + dcb.DCBlength = sizeof dcb; + if(lpdcb->BaudRate==57601) + dcb.BaudRate = 115200; + else + dcb.BaudRate = lpdcb->BaudRate; + + dcb.ByteSize=lpdcb->ByteSize; + dcb.StopBits=lpdcb->StopBits; + + dcb.fParity=lpdcb->fParity; + dcb.Parity=lpdcb->Parity; + + dcb.fOutxCtsFlow = lpdcb->fOutxCtsFlow; + + if (lpdcb->fDtrflow || lpdcb->fRtsflow) + dcb.fRtsControl = TRUE; + + if (lpdcb->fDtrDisable) + dcb.fDtrControl = TRUE; + + ptr->evtchar = lpdcb->EvtChar; + + dcb.fInX = lpdcb->fInX; + dcb.fOutX = lpdcb->fOutX; + + if (!SetCommState(ptr->handle,&dcb)) { + ptr->commerror = WinError(); + return -1; + } else { + ptr->commerror = 0; + return 0; + } +} + +/***************************************************************************** + * GetCommState (USER.202) + */ +INT16 WINAPI GetCommState16(INT16 cid, LPDCB16 lpdcb) +{ + struct DosDeviceStruct *ptr; + DCB dcb; + + TRACE("cid %d, ptr %p\n", cid, lpdcb); + if ((ptr = GetDeviceStruct(cid)) == NULL) { + FIXME("no handle for cid = %0x!\n",cid); + return -1; + } + if (!GetCommState(ptr->handle,&dcb)) { + ptr->commerror = WinError(); + return -1; + } + + lpdcb->Id = cid; + + COMM16_DCBtoDCB16(&dcb,lpdcb); + + lpdcb->EvtChar = ptr->evtchar; + + ptr->commerror = 0; + return 0; +} + +/***************************************************************************** + * TransmitCommChar (USER.206) + */ +INT16 WINAPI TransmitCommChar16(INT16 cid,CHAR chTransmit) +{ + struct DosDeviceStruct *ptr; + + TRACE("cid %d, data %d \n", cid, chTransmit); + if ((ptr = GetDeviceStruct(cid)) == NULL) { + FIXME("no handle for cid = %0x!\n",cid); + return -1; + } + + if (ptr->suspended) { + ptr->commerror = IE_HARDWARE; + return -1; + } + + if (ptr->xmit >= 0) { + /* character already queued */ + /* FIXME: which error would Windows return? */ + ptr->commerror = CE_TXFULL; + return -1; + } + + if (ptr->obuf_head == ptr->obuf_tail) { + /* transmit queue empty, try to transmit directly */ + DWORD len; + if(!WriteFile(ptr->handle, &chTransmit, 1, &len, NULL)) { + /* didn't work, queue it */ + ptr->xmit = chTransmit; + comm_waitwrite(ptr); + } + } else { + /* data in queue, let this char be transmitted next */ + ptr->xmit = chTransmit; + comm_waitwrite(ptr); + } + + ptr->commerror = 0; + return 0; +} + +/***************************************************************************** + * UngetCommChar (USER.212) + */ +INT16 WINAPI UngetCommChar16(INT16 cid,CHAR chUnget) +{ + struct DosDeviceStruct *ptr; + + TRACE("cid %d (char %d)\n", cid, chUnget); + if ((ptr = GetDeviceStruct(cid)) == NULL) { + FIXME("no handle for cid = %0x!\n",cid); + return -1; + } + + if (ptr->suspended) { + ptr->commerror = IE_HARDWARE; + return -1; + } + + if (ptr->unget>=0) { + /* character already queued */ + /* FIXME: which error would Windows return? */ + ptr->commerror = CE_RXOVER; + return -1; + } + + ptr->unget = chUnget; + + ptr->commerror = 0; + return 0; +} + +/***************************************************************************** + * ReadComm (USER.204) + */ +INT16 WINAPI ReadComm16(INT16 cid,LPSTR lpvBuf,INT16 cbRead) +{ + int status, length; + struct DosDeviceStruct *ptr; + LPSTR orgBuf = lpvBuf; + + TRACE("cid %d, ptr %p, length %d\n", cid, lpvBuf, cbRead); + if ((ptr = GetDeviceStruct(cid)) == NULL) { + FIXME("no handle for cid = %0x!\n",cid); + return -1; + } + + if (ptr->suspended) { + ptr->commerror = IE_HARDWARE; + return -1; + } + + /* read unget character */ + if (ptr->unget>=0) { + *lpvBuf++ = ptr->unget; + ptr->unget = -1; + + length = 1; + } else + length = 0; + + /* read from receive buffer */ + while (length < cbRead) { + status = ((ptr->ibuf_head < ptr->ibuf_tail) ? + ptr->ibuf_size : ptr->ibuf_head) - ptr->ibuf_tail; + if (!status) break; + if ((cbRead - length) < status) + status = cbRead - length; + + memcpy(lpvBuf, ptr->inbuf + ptr->ibuf_tail, status); + ptr->ibuf_tail += status; + if (ptr->ibuf_tail >= ptr->ibuf_size) + ptr->ibuf_tail = 0; + lpvBuf += status; + length += status; + } + + TRACE("%.*s\n", length, orgBuf); + ptr->commerror = 0; + return length; +} + +/***************************************************************************** + * WriteComm (USER.205) + */ +INT16 WINAPI WriteComm16(INT16 cid, LPSTR lpvBuf, INT16 cbWrite) +{ + int status, length; + struct DosDeviceStruct *ptr; + + TRACE("cid %d, ptr %p, length %d\n", + cid, lpvBuf, cbWrite); + if ((ptr = GetDeviceStruct(cid)) == NULL) { + FIXME("no handle for cid = %0x!\n",cid); + return -1; + } + + if (ptr->suspended) { + ptr->commerror = IE_HARDWARE; + return -1; + } + + TRACE("%.*s\n", cbWrite, lpvBuf ); + + length = 0; + while (length < cbWrite) { + if ((ptr->obuf_head == ptr->obuf_tail) && (ptr->xmit < 0)) { + /* no data queued, try to write directly */ + if(!WriteFile(ptr->handle, lpvBuf, cbWrite - length, (LPDWORD)&status, NULL)) + status = -1; + if (status > 0) { + lpvBuf += status; + length += status; + continue; + } + } + /* can't write directly, put into transmit buffer */ + status = ((ptr->obuf_tail > ptr->obuf_head) ? + (ptr->obuf_tail-1) : ptr->obuf_size) - ptr->obuf_head; + if (!status) break; + if ((cbWrite - length) < status) + status = cbWrite - length; + memcpy(lpvBuf, ptr->outbuf + ptr->obuf_head, status); + ptr->obuf_head += status; + if (ptr->obuf_head >= ptr->obuf_size) + ptr->obuf_head = 0; + lpvBuf += status; + length += status; + comm_waitwrite(ptr); + } + + ptr->commerror = 0; + return length; +} + +/*********************************************************************** + * EnableCommNotification (USER.245) + */ +BOOL16 WINAPI EnableCommNotification16( INT16 cid, HWND16 hwnd, + INT16 cbWriteNotify, INT16 cbOutQueue ) +{ + struct DosDeviceStruct *ptr; + + TRACE("(%d, %x, %d, %d)\n", cid, hwnd, cbWriteNotify, cbOutQueue); + if ((ptr = GetDeviceStruct(cid)) == NULL) { + FIXME("no handle for cid = %0x!\n",cid); + return -1; + } + ptr->wnd = hwnd; + ptr->n_read = cbWriteNotify; + ptr->n_write = cbOutQueue; + return TRUE; +} + diff --git a/dlls/user/user_main.c b/dlls/user/user_main.c index 66f816420cb..e0b48b65550 100644 --- a/dlls/user/user_main.c +++ b/dlls/user/user_main.c @@ -35,6 +35,8 @@ WORD USER_HeapSel = 0; /* USER heap selector */ static HMODULE graphics_driver; +extern void COMM_Init(void); + #define GET_USER_FUNC(name) USER_Driver.p##name = (void*)GetProcAddress( graphics_driver, #name ) /* load the graphics driver */ @@ -246,6 +248,9 @@ static BOOL process_attach(void) /* Initialize mouse driver */ MOUSE_Enable( mouse_event ); + /* Initialize 16-bit serial communications */ + COMM_Init(); + return TRUE; }