Hi,
the attached patch improves the code of the host serial driver.
The code now uses IPRT functions where possible and adds error handling
in case the driver can not open the serial port.
The patch hopefully adds support for serial ports on Windows host OS but
i couldn't check if it works because I'm not able to compile the whole
VirtualBox tree on Windows. I only checked that it compiles without an
error.
At last the driver has it's own log group now.
Kind regards,
Alexander Eichner
Index: include/VBox/log.h
===================================================================
--- include/VBox/log.h (Revision 4144)
+++ include/VBox/log.h (Arbeitskopie)
@@ -134,6 +134,8 @@
LOG_GROUP_DRV_HOST_HDD,
/** Host Parallel Driver group */
LOG_GROUP_DRV_HOST_PARALLEL,
+ /** Host Serial Driver Group */
+ LOG_GROUP_DRV_HOST_SERIAL,
/** The internal networking transport driver group. */
LOG_GROUP_DRV_INTNET,
/** iSCSI Initiator driver group. */
@@ -323,6 +325,7 @@
"DRV_HOST_FLOPPY", \
"DRV_HOST_HDD", \
"DRV_HOST_PARALLEL", \
+ "DRV_HOST_SERIAL", \
"DRV_INTNET", \
"DRV_ISCSI", \
"DRV_ISCSI_TRANSPORT_TCP", \
Index: src/VBox/Devices/Serial/DrvHostSerial.cpp
===================================================================
--- src/VBox/Devices/Serial/DrvHostSerial.cpp (Revision 4144)
+++ src/VBox/Devices/Serial/DrvHostSerial.cpp (Arbeitskopie)
@@ -27,7 +27,7 @@
/*******************************************************************************
* Header Files *
*******************************************************************************/
-#define LOG_GROUP LOG_GROUP_DRV_CHAR
+#define LOG_GROUP LOG_GROUP_DRV_HOST_SERIAL
#include <VBox/pdm.h>
#include <VBox/err.h>
@@ -35,14 +35,18 @@
#include <iprt/asm.h>
#include <iprt/assert.h>
#include <iprt/stream.h>
-#include <iprt/semaphore.h>
+#include <iprt/semaphore.h>
+#include <iprt/file.h>
+#include <iprt/alloc.h>
#ifdef RT_OS_LINUX
-#include <termios.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <string.h>
-#include <unistd.h>
+# include <termios.h>
+# include <sys/types.h>
+# include <fcntl.h>
+# include <string.h>
+# include <unistd.h>
+#elif defined(RT_OS_WINDOWS)
+# include <windows.h>
#endif
#include "Builtins.h"
@@ -79,7 +83,7 @@
/** the device path */
char *pszDevicePath;
/** the device handle */
- int DeviceFile;
+ RTFILE DeviceFile;
/** Internal send FIFO queue */
uint8_t aSendQueue[CHAR_MAX_SEND_QUEUE];
@@ -148,16 +152,21 @@
static DECLCALLBACK(int) drvHostSerialSetParameters(PPDMICHAR pInterface, int speed, int parity, int data_bits, int stop_bits)
{
- PDRVHOSTSERIAL pData = PDMICHAR_2_DRVHOSTSERIAL(pInterface);
- struct termios termiosSetup;
+ PDRVHOSTSERIAL pData = PDMICHAR_2_DRVHOSTSERIAL(pInterface);
+#ifdef RT_OS_LINUX
+ struct termios *termiosSetup;
int baud_rate;
+#elif defined(RT_OS_WINDOWS)
+ LPDCB comSetup;
+#endif
LogFlow(("%s: speed=%d parity=%c data_bits=%d stop_bits=%d\n", __FUNCTION__, speed, parity, data_bits, stop_bits));
+
+#ifdef RT_OS_LINUX
+ termiosSetup = (struct termios *)RTMemTmpAllocZ(sizeof(struct termios));
- memset(&termiosSetup, 0, sizeof(termiosSetup));
-
/* Enable receiver */
- termiosSetup.c_cflag |= (CLOCAL | CREAD);
+ termiosSetup->c_cflag |= (CLOCAL | CREAD);
switch (speed) {
case 50:
@@ -215,15 +224,15 @@
baud_rate = B9600;
}
- cfsetispeed(&termiosSetup, baud_rate);
- cfsetospeed(&termiosSetup, baud_rate);
+ cfsetispeed(termiosSetup, baud_rate);
+ cfsetospeed(termiosSetup, baud_rate);
switch (parity) {
case 'E':
- termiosSetup.c_cflag |= PARENB;
+ termiosSetup->c_cflag |= PARENB;
break;
case 'O':
- termiosSetup.c_cflag |= (PARENB | PARODD);
+ termiosSetup->c_cflag |= (PARENB | PARODD);
break;
case 'N':
break;
@@ -233,16 +242,16 @@
switch (data_bits) {
case 5:
- termiosSetup.c_cflag |= CS5;
+ termiosSetup->c_cflag |= CS5;
break;
case 6:
- termiosSetup.c_cflag |= CS6;
+ termiosSetup->c_cflag |= CS6;
break;
case 7:
- termiosSetup.c_cflag |= CS7;
+ termiosSetup->c_cflag |= CS7;
break;
case 8:
- termiosSetup.c_cflag |= CS8;
+ termiosSetup->c_cflag |= CS8;
break;
default:
break;
@@ -250,15 +259,115 @@
switch (stop_bits) {
case 2:
- termiosSetup.c_cflag |= CSTOPB;
+ termiosSetup->c_cflag |= CSTOPB;
default:
break;
}
/* set serial port to raw input */
- termiosSetup.c_lflag = ~(ICANON | ECHO | ECHOE | ISIG);
+ termiosSetup->c_lflag = ~(ICANON | ECHO | ECHOE | ISIG);
- tcsetattr(pData->DeviceFile, TCSANOW, &termiosSetup);
+ tcsetattr(pData->DeviceFile, TCSANOW, termiosSetup);
+ RTMemFree(termiosSetup);
+#elif defined(RT_OS_WINDOWS)
+ comSetup = (LPDCB)RTMemTmpAllocZ(sizeof(DCB));
+
+ comSetup->DCBLength = sizeof(DCB);
+
+ switch (speed) {
+ case 110:
+ comSetup->BaudRate = CBR_110;
+ break;
+ case 300:
+ comSetup->BaudRate = CBR_300;
+ break;
+ case 600:
+ comSetup->BaudRate = CBR_600;
+ break;
+ case 1200:
+ comSetup->BaudRate = CBR_1200;
+ break;
+ case 2400:
+ comSetup->BaudRate = CBR_2400;
+ break;
+ case 4800:
+ comSetup->BaudRate = CBR_4800;
+ break;
+ case 9600:
+ comSetup->BaudRate = CBR_9600;
+ break;
+ case 14400:
+ comSetup->BaudRate = CBR_14400;
+ break;
+ case 19200:
+ comSetup->BaudRate = CBR_19200;
+ break;
+ case 38400:
+ comSetup->BaudRate = CBR_38400;
+ break;
+ case 57600:
+ comSetup->BaudRate = CBR_57600;
+ break;
+ case 115200:
+ comSetup->BaudRate = CBR_115200;
+ break;
+ default:
+ comSetup->BaudRate = CBR_9600;
+ }
+
+ comSetup->fBinary = TRUE;
+ comSetup->fOutxCtsFlow = FALSE;
+ comSetup->fOutxDsrFlow = FALSE;
+ comSetup->fDtrControl = DTR_CONTROL_DISABLE;
+ comSetup->fDsrSensitivity = FALSE;
+ comSetup->fTXContinueOnXoff = TRUE;
+ comSetup->fOutX = FALSE;
+ comSetup->fInX = FALSE;
+ comSetup->fErrorChar = FALSE;
+ comSetup->fNull = FALSE;
+ comSetup->fRtsControl = RTS_CONTROL_DISABLE;
+ comSetup->fAbortOnError = FALSE;
+ comSetup->wReserved = 0;
+ comSetup->XonLim = 5;
+ comSetup->XoffLim = 5;
+ comSetup->ByteSize = data_bits;
+
+ switch (parity) {
+ case 'E':
+ comSetup->Parity = EVENPARITY;
+ break;
+ case 'O':
+ comSetup->Parity = ODDPARITY;
+ break;
+ case 'N':
+ comSetup->Parity = NOPARITY;
+ break;
+ default:
+ break;
+ }
+
+ switch (stop_bits) {
+ case 1:
+ comSetup->StopBits = ONESTOPBIT;
+ break;
+ case 2:
+ comSetup->StopBits = TWOSTOPBITS;
+ break;
+ default:
+ break;
+ }
+
+ comSetup->XonChar = 0;
+ comSetup->XoffChar = 0;
+ comSetup->ErrorChar = 0;
+ comSetup->EofChar = 0;
+ comSetup->EvtChar = 0;
+
+ SetCommState((HANDLE)pData->DeviceFile, comSetup);
+ RTMemFree(comSetup);
+#endif
+
+ return VINF_SUCCESS;
}
/* -=-=-=-=- receive thread -=-=-=-=- */
@@ -289,14 +398,14 @@
{
size_t cbProcessed = 1;
- rc = write(pData->DeviceFile, &pData->aSendQueue[pData->iSendQueueTail], cbProcessed);
- if (rc > 0)
+ rc = RTFileWrite(pData->DeviceFile, &pData->aSendQueue[pData->iSendQueueTail], cbProcessed, NULL);
+ if (VBOX_SUCCESS(rc))
{
Assert(cbProcessed);
pData->iSendQueueTail++;
pData->iSendQueueTail &= CHAR_MAX_SEND_QUEUE_MASK;
}
- else if (rc < 0)
+ else if (VBOX_FAILURE(rc))
{
LogFlow(("Write failed with %Vrc; skipping\n", rc));
break;
@@ -326,7 +435,7 @@
{
PDRVHOSTSERIAL pData = (PDRVHOSTSERIAL)pvUser;
char aBuffer[256], *pBuffer;
- size_t cbRemaining, cbProcessed;
+ size_t cbRemaining, cbProcessed, cbRead;
int rc;
cbRemaining = 0;
@@ -335,15 +444,15 @@
{
if (!cbRemaining)
{
- /* Get block of data from stream driver. */
+ /* Get block of data from serial device. */
cbRemaining = sizeof(aBuffer);
- rc = read(pData->DeviceFile, aBuffer, cbRemaining);
- if (rc < 0)
+ rc = RTFileRead(pData->DeviceFile, aBuffer, cbRemaining, &cbRead);
+ if (VBOX_FAILURE(rc))
{
LogFlow(("Read failed with %Vrc\n", rc));
break;
} else {
- cbRemaining = rc;
+ cbRemaining = cbRead;
}
pBuffer = aBuffer;
}
@@ -423,32 +532,68 @@
/*
* Open the device
*/
- pData->DeviceFile = open(pData->pszDevicePath, O_RDWR | O_NONBLOCK);
- if (pData->DeviceFile < 0) {
-
+ rc = RTFileOpen(&pData->DeviceFile, pData->pszDevicePath, RTFILE_O_OPEN | RTFILE_O_READWRITE);
+
+ if (VBOX_FAILURE(rc)) {
+ pData->DeviceFile = NIL_RTFILE;
+ AssertMsgFailed(("Could not open host device %s, rc=%Vrc\n", pData->pszDevicePath, rc));
+ switch (rc) {
+ case VERR_ACCESS_DENIED:
+ return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
+#ifdef RT_OS_LINUX
+ N_("Cannot open host device '%s' for read/write access. Check the permissions "
+ "of that device ('/bin/ls -l %s'): Most probably you need to be member "
+ "of the device group. Make sure that you logout/login after changing "
+ "the group settings of the current user"),
+#else
+ N_("Cannot open host device '%s' for read/write access. Check the permissions "
+ "of that device"),
+#endif
+ pData->pszDevicePath, pData->pszDevicePath);
+ default:
+ return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
+ N_("Failed to open host device '%s'"),
+ pData->pszDevicePath);
+ }
}
+
+ /* Set to non blocking I/O */
+#ifdef RT_OS_LINUX
+ fcntl(pData->DeviceFile, F_SETFL, O_NONBLOCK);
+#elif defined(RT_OS_WINDOS)
+ /* Set the COMMTIMEOUTS to get non blocking I/O */
+ COMMTIMEOUTS comTimeout;
+
+ comTimeout.ReadIntervalTimeout = MAXDWORD;
+ comTimeout.ReadTotalTimeoutMultiplier = 0;
+ comTimeout.ReadTotalTimeoutConstant = 0;
+ comTimeout.WriteTotalTimeoutMultiplier = 0;
+ comTimeout.WriteTotalTimeoutConstant = 0;
+
+ SetCommTimeouts(pData->DeviceFile, &comTimeout);
+#endif
/*
* Get the ICharPort interface of the above driver/device.
*/
pData->pDrvCharPort = (PPDMICHARPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_CHAR_PORT);
if (!pData->pDrvCharPort)
- return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE, RT_SRC_POS, N_("Char#%d has no char port interface above"), pDrvIns->iInstance);
+ return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE, RT_SRC_POS, N_("HostSerial#%d has no char port interface above"), pDrvIns->iInstance);
- rc = RTThreadCreate(&pData->ReceiveThread, drvHostSerialReceiveLoop, (void *)pData, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "Char Receive");
+ rc = RTThreadCreate(&pData->ReceiveThread, drvHostSerialReceiveLoop, (void *)pData, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "Serial Receive");
if (VBOX_FAILURE(rc))
- return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("Char#%d cannot create receive thread"), pDrvIns->iInstance);
+ return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create receive thread"), pDrvIns->iInstance);
rc = RTSemEventCreate(&pData->SendSem);
AssertRC(rc);
- rc = RTThreadCreate(&pData->SendThread, drvHostSerialSendLoop, (void *)pData, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "Char Send");
+ rc = RTThreadCreate(&pData->SendThread, drvHostSerialSendLoop, (void *)pData, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "Serial Send");
if (VBOX_FAILURE(rc))
- return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("Char#%d cannot create send thread"), pDrvIns->iInstance);
+ return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostSerial#%d cannot create send thread"), pDrvIns->iInstance);
- PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes written", "/Devices/Char%d/Written", pDrvIns->iInstance);
- PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes read", "/Devices/Char%d/Read", pDrvIns->iInstance);
+ PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatBytesWritten, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes written", "/Devices/HostSerial%d/Written", pDrvIns->iInstance);
+ PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatBytesRead, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, "Nr of bytes read", "/Devices/HostSerial%d/Read", pDrvIns->iInstance);
return VINF_SUCCESS;
}
@@ -473,7 +618,7 @@
{
RTThreadWait(pData->ReceiveThread, 1000, NULL);
if (pData->ReceiveThread != NIL_RTTHREAD)
- LogRel(("Char%d: receive thread did not terminate\n", pDrvIns->iInstance));
+ LogRel(("HostSerial%d: receive thread did not terminate\n", pDrvIns->iInstance));
}
/* Empty the send queue */
@@ -487,7 +632,7 @@
{
RTThreadWait(pData->SendThread, 1000, NULL);
if (pData->SendThread != NIL_RTTHREAD)
- LogRel(("Char%d: send thread did not terminate\n", pDrvIns->iInstance));
+ LogRel(("HostSerial%d: send thread did not terminate\n", pDrvIns->iInstance));
}
}
Index: src/VBox/Devices/Makefile.kmk
===================================================================
--- src/VBox/Devices/Makefile.kmk (Revision 4144)
+++ src/VBox/Devices/Makefile.kmk (Arbeitskopie)
@@ -441,7 +441,8 @@
Drivers_SOURCES.win = \
Network/DrvTAPWin32.cpp \
- Audio/dsoundaudio.c
+ Audio/dsoundaudio.c \
+ Serial/DrvHostSerial.cpp
# -- features --
_______________________________________________
vbox-dev mailing list
[email protected]
http://vbox.innotek.de/mailman/listinfo/vbox-dev