Hi,
sorry for sending a wrong version of tha patch. The correct version ist
attached.
Kind regards,
Alexander Eichner
Am Donnerstag, den 16.08.2007, 16:34 +0200 schrieb Alexander Eichner:
> 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
> _______________________________________________
> vbox-dev mailing list
> [email protected]
> http://vbox.innotek.de/mailman/listinfo/vbox-dev
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_WINDOWS)
+ /* 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((HANDLE)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