DrvHostParallel.cpp revision cba6719bd64ec749967bbe931230452664109857
45e9809aff7304721fddb95654901b32195c9c7avboxsync/* $Id$ */
45e9809aff7304721fddb95654901b32195c9c7avboxsync/** @file
45e9809aff7304721fddb95654901b32195c9c7avboxsync * VirtualBox Host Parallel Port Driver.
45e9809aff7304721fddb95654901b32195c9c7avboxsync *
45e9809aff7304721fddb95654901b32195c9c7avboxsync * Contributed by: Alexander Eichner
45e9809aff7304721fddb95654901b32195c9c7avboxsync */
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync/*
45e9809aff7304721fddb95654901b32195c9c7avboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
45e9809aff7304721fddb95654901b32195c9c7avboxsync *
45e9809aff7304721fddb95654901b32195c9c7avboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
45e9809aff7304721fddb95654901b32195c9c7avboxsync * available from http://www.virtualbox.org. This file is free software;
45e9809aff7304721fddb95654901b32195c9c7avboxsync * you can redistribute it and/or modify it under the terms of the GNU
45e9809aff7304721fddb95654901b32195c9c7avboxsync * General Public License (GPL) as published by the Free Software
45e9809aff7304721fddb95654901b32195c9c7avboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
45e9809aff7304721fddb95654901b32195c9c7avboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
45e9809aff7304721fddb95654901b32195c9c7avboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
45e9809aff7304721fddb95654901b32195c9c7avboxsync *
45e9809aff7304721fddb95654901b32195c9c7avboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
45e9809aff7304721fddb95654901b32195c9c7avboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
45e9809aff7304721fddb95654901b32195c9c7avboxsync * additional information or have any questions.
45e9809aff7304721fddb95654901b32195c9c7avboxsync */
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync/*******************************************************************************
45e9809aff7304721fddb95654901b32195c9c7avboxsync* Header Files *
45e9809aff7304721fddb95654901b32195c9c7avboxsync*******************************************************************************/
45e9809aff7304721fddb95654901b32195c9c7avboxsync#define LOG_GROUP LOG_GROUP_DRV_HOST_PARALLEL
45e9809aff7304721fddb95654901b32195c9c7avboxsync#include <VBox/pdmdrv.h>
45e9809aff7304721fddb95654901b32195c9c7avboxsync#include <VBox/pdmthread.h>
45e9809aff7304721fddb95654901b32195c9c7avboxsync#include <iprt/asm.h>
45e9809aff7304721fddb95654901b32195c9c7avboxsync#include <iprt/assert.h>
45e9809aff7304721fddb95654901b32195c9c7avboxsync#include <iprt/stream.h>
45e9809aff7304721fddb95654901b32195c9c7avboxsync#include <iprt/semaphore.h>
45e9809aff7304721fddb95654901b32195c9c7avboxsync#include <iprt/file.h>
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync#ifdef RT_OS_LINUX
45e9809aff7304721fddb95654901b32195c9c7avboxsync# include <sys/ioctl.h>
45e9809aff7304721fddb95654901b32195c9c7avboxsync# include <sys/types.h>
45e9809aff7304721fddb95654901b32195c9c7avboxsync# include <sys/stat.h>
45e9809aff7304721fddb95654901b32195c9c7avboxsync# include <sys/poll.h>
45e9809aff7304721fddb95654901b32195c9c7avboxsync# include <fcntl.h>
45e9809aff7304721fddb95654901b32195c9c7avboxsync# include <unistd.h>
45e9809aff7304721fddb95654901b32195c9c7avboxsync# include <linux/ppdev.h>
45e9809aff7304721fddb95654901b32195c9c7avboxsync# include <linux/parport.h>
45e9809aff7304721fddb95654901b32195c9c7avboxsync# include <errno.h>
45e9809aff7304721fddb95654901b32195c9c7avboxsync#endif
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync#include "Builtins.h"
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync/*******************************************************************************
45e9809aff7304721fddb95654901b32195c9c7avboxsync* Structures and Typedefs *
45e9809aff7304721fddb95654901b32195c9c7avboxsync*******************************************************************************/
45e9809aff7304721fddb95654901b32195c9c7avboxsync/**
45e9809aff7304721fddb95654901b32195c9c7avboxsync * Host parallel port driver instance data.
45e9809aff7304721fddb95654901b32195c9c7avboxsync */
45e9809aff7304721fddb95654901b32195c9c7avboxsynctypedef struct DRVHOSTPARALLEL
45e9809aff7304721fddb95654901b32195c9c7avboxsync{
45e9809aff7304721fddb95654901b32195c9c7avboxsync /** Pointer to the driver instance structure. */
45e9809aff7304721fddb95654901b32195c9c7avboxsync PPDMDRVINS pDrvIns;
45e9809aff7304721fddb95654901b32195c9c7avboxsync /** Pointer to the char port interface of the driver/device above us. */
45e9809aff7304721fddb95654901b32195c9c7avboxsync PPDMIHOSTPARALLELPORT pDrvHostParallelPort;
45e9809aff7304721fddb95654901b32195c9c7avboxsync /** Our host device interface. */
45e9809aff7304721fddb95654901b32195c9c7avboxsync PDMIHOSTPARALLELCONNECTOR IHostParallelConnector;
45e9809aff7304721fddb95654901b32195c9c7avboxsync /** Our host device port interface. */
45e9809aff7304721fddb95654901b32195c9c7avboxsync PDMIHOSTPARALLELPORT IHostParallelPort;
45e9809aff7304721fddb95654901b32195c9c7avboxsync /** Device Path */
45e9809aff7304721fddb95654901b32195c9c7avboxsync char *pszDevicePath;
45e9809aff7304721fddb95654901b32195c9c7avboxsync /** Device Handle */
45e9809aff7304721fddb95654901b32195c9c7avboxsync RTFILE FileDevice;
45e9809aff7304721fddb95654901b32195c9c7avboxsync /** Thread waiting for interrupts. */
45e9809aff7304721fddb95654901b32195c9c7avboxsync PPDMTHREAD pMonitorThread;
45e9809aff7304721fddb95654901b32195c9c7avboxsync /** Wakeup pipe read end. */
45e9809aff7304721fddb95654901b32195c9c7avboxsync RTFILE WakeupPipeR;
45e9809aff7304721fddb95654901b32195c9c7avboxsync /** Wakeup pipe write end. */
45e9809aff7304721fddb95654901b32195c9c7avboxsync RTFILE WakeupPipeW;
45e9809aff7304721fddb95654901b32195c9c7avboxsync} DRVHOSTPARALLEL, *PDRVHOSTPARALLEL;
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync/** Converts a pointer to DRVHOSTPARALLEL::IHostDeviceConnector to a PDRHOSTPARALLEL. */
45e9809aff7304721fddb95654901b32195c9c7avboxsync#define PDMIHOSTPARALLELCONNECTOR_2_DRVHOSTPARALLEL(pInterface) ( (PDRVHOSTPARALLEL)((uintptr_t)pInterface - RT_OFFSETOF(DRVHOSTPARALLEL, IHostParallelConnector)) )
45e9809aff7304721fddb95654901b32195c9c7avboxsync/** Converts a pointer to DRVHOSTPARALLEL::IHostDevicePort to a PDRHOSTPARALLEL. */
45e9809aff7304721fddb95654901b32195c9c7avboxsync#define PDMIHOSTPARALLELPORT_2_DRVHOSTPARALLEL(pInterface) ( (PDRVHOSTPARALLEL)((uintptr_t)pInterface - RT_OFFSETOF(DRVHOSTPARALLEL, IHostParallelPort)) )
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync/* -=-=-=-=- IBase -=-=-=-=- */
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync/**
45e9809aff7304721fddb95654901b32195c9c7avboxsync * Queries an interface to the driver.
45e9809aff7304721fddb95654901b32195c9c7avboxsync *
45e9809aff7304721fddb95654901b32195c9c7avboxsync * @returns Pointer to interface.
45e9809aff7304721fddb95654901b32195c9c7avboxsync * @returns NULL if the interface was not supported by the driver.
45e9809aff7304721fddb95654901b32195c9c7avboxsync * @param pInterface Pointer to this interface structure.
45e9809aff7304721fddb95654901b32195c9c7avboxsync * @param enmInterface The requested interface identification.
45e9809aff7304721fddb95654901b32195c9c7avboxsync */
45e9809aff7304721fddb95654901b32195c9c7avboxsyncstatic DECLCALLBACK(void *) drvHostParallelQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
45e9809aff7304721fddb95654901b32195c9c7avboxsync{
45e9809aff7304721fddb95654901b32195c9c7avboxsync PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
45e9809aff7304721fddb95654901b32195c9c7avboxsync PDRVHOSTPARALLEL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPARALLEL);
45e9809aff7304721fddb95654901b32195c9c7avboxsync switch (enmInterface)
45e9809aff7304721fddb95654901b32195c9c7avboxsync {
45e9809aff7304721fddb95654901b32195c9c7avboxsync case PDMINTERFACE_BASE:
45e9809aff7304721fddb95654901b32195c9c7avboxsync return &pDrvIns->IBase;
45e9809aff7304721fddb95654901b32195c9c7avboxsync case PDMINTERFACE_HOST_PARALLEL_CONNECTOR:
45e9809aff7304721fddb95654901b32195c9c7avboxsync return &pThis->IHostParallelConnector;
45e9809aff7304721fddb95654901b32195c9c7avboxsync default:
45e9809aff7304721fddb95654901b32195c9c7avboxsync return NULL;
45e9809aff7304721fddb95654901b32195c9c7avboxsync }
45e9809aff7304721fddb95654901b32195c9c7avboxsync}
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync/* -=-=-=-=- IHostDeviceConnector -=-=-=-=- */
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync/** @copydoc PDMICHAR::pfnWrite */
45e9809aff7304721fddb95654901b32195c9c7avboxsyncstatic DECLCALLBACK(int) drvHostParallelWrite(PPDMIHOSTPARALLELCONNECTOR pInterface, const void *pvBuf, size_t *cbWrite)
45e9809aff7304721fddb95654901b32195c9c7avboxsync{
45e9809aff7304721fddb95654901b32195c9c7avboxsync PDRVHOSTPARALLEL pThis = PDMIHOSTPARALLELCONNECTOR_2_DRVHOSTPARALLEL(pInterface);
45e9809aff7304721fddb95654901b32195c9c7avboxsync const unsigned char *pBuffer = (const unsigned char *)pvBuf;
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync LogFlow(("%s: pvBuf=%#p cbWrite=%d\n", __FUNCTION__, pvBuf, *cbWrite));
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync ioctl(pThis->FileDevice, PPWDATA, pBuffer);
45e9809aff7304721fddb95654901b32195c9c7avboxsync *cbWrite = 1;
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync return VINF_SUCCESS;
45e9809aff7304721fddb95654901b32195c9c7avboxsync}
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsyncstatic DECLCALLBACK(int) drvHostParallelRead(PPDMIHOSTPARALLELCONNECTOR pInterface, void *pvBuf, size_t *cbRead)
45e9809aff7304721fddb95654901b32195c9c7avboxsync{
45e9809aff7304721fddb95654901b32195c9c7avboxsync PDRVHOSTPARALLEL pThis = PDMIHOSTPARALLELCONNECTOR_2_DRVHOSTPARALLEL(pInterface);
45e9809aff7304721fddb95654901b32195c9c7avboxsync unsigned char *pBuffer = (unsigned char *)pvBuf;
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync LogFlow(("%s: pvBuf=%#p cbRead=%d\n", __FUNCTION__, pvBuf, cbRead));
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync ioctl(pThis->FileDevice, PPRDATA, pBuffer);
45e9809aff7304721fddb95654901b32195c9c7avboxsync *cbRead = 1;
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync return VINF_SUCCESS;
45e9809aff7304721fddb95654901b32195c9c7avboxsync}
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsyncstatic DECLCALLBACK(int) drvHostParallelSetMode(PPDMIHOSTPARALLELCONNECTOR pInterface, PDMPARALLELPORTMODE enmMode)
45e9809aff7304721fddb95654901b32195c9c7avboxsync{
45e9809aff7304721fddb95654901b32195c9c7avboxsync PDRVHOSTPARALLEL pThis = PDMIHOSTPARALLELCONNECTOR_2_DRVHOSTPARALLEL(pInterface);
45e9809aff7304721fddb95654901b32195c9c7avboxsync int ppdev_mode;
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync LogFlow(("%s: mode=%d\n", __FUNCTION__, enmMode));
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync switch (enmMode) {
45e9809aff7304721fddb95654901b32195c9c7avboxsync case PDM_PARALLEL_PORT_MODE_COMPAT:
45e9809aff7304721fddb95654901b32195c9c7avboxsync ppdev_mode = IEEE1284_MODE_COMPAT;
45e9809aff7304721fddb95654901b32195c9c7avboxsync break;
45e9809aff7304721fddb95654901b32195c9c7avboxsync case PDM_PARALLEL_PORT_MODE_EPP:
45e9809aff7304721fddb95654901b32195c9c7avboxsync ppdev_mode = IEEE1284_MODE_EPP;
45e9809aff7304721fddb95654901b32195c9c7avboxsync break;
45e9809aff7304721fddb95654901b32195c9c7avboxsync case PDM_PARALLEL_PORT_MODE_ECP:
45e9809aff7304721fddb95654901b32195c9c7avboxsync //ppdev_mode = IEEE1284_MODE_ECP;
45e9809aff7304721fddb95654901b32195c9c7avboxsync break;
45e9809aff7304721fddb95654901b32195c9c7avboxsync }
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync ioctl(pThis->FileDevice, PPSETMODE, &ppdev_mode);
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync return VINF_SUCCESS;
45e9809aff7304721fddb95654901b32195c9c7avboxsync}
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsyncstatic DECLCALLBACK(int) drvHostParallelWriteControl(PPDMIHOSTPARALLELCONNECTOR pInterface, uint8_t fReg)
45e9809aff7304721fddb95654901b32195c9c7avboxsync{
45e9809aff7304721fddb95654901b32195c9c7avboxsync PDRVHOSTPARALLEL pThis = PDMIHOSTPARALLELCONNECTOR_2_DRVHOSTPARALLEL(pInterface);
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync LogFlow(("%s: fReg=%d\n", __FUNCTION__, fReg));
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync ioctl(pThis->FileDevice, PPWCONTROL, &fReg);
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync return VINF_SUCCESS;
45e9809aff7304721fddb95654901b32195c9c7avboxsync}
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsyncstatic DECLCALLBACK(int) drvHostParallelReadControl(PPDMIHOSTPARALLELCONNECTOR pInterface, uint8_t *pfReg)
45e9809aff7304721fddb95654901b32195c9c7avboxsync{
45e9809aff7304721fddb95654901b32195c9c7avboxsync PDRVHOSTPARALLEL pThis = PDMIHOSTPARALLELCONNECTOR_2_DRVHOSTPARALLEL(pInterface);
45e9809aff7304721fddb95654901b32195c9c7avboxsync uint8_t fReg;
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync ioctl(pThis->FileDevice, PPRCONTROL, &fReg);
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync LogFlow(("%s: fReg=%d\n", __FUNCTION__, fReg));
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync *pfReg = fReg;
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync return VINF_SUCCESS;
45e9809aff7304721fddb95654901b32195c9c7avboxsync}
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsyncstatic DECLCALLBACK(int) drvHostParallelReadStatus(PPDMIHOSTPARALLELCONNECTOR pInterface, uint8_t *pfReg)
45e9809aff7304721fddb95654901b32195c9c7avboxsync{
45e9809aff7304721fddb95654901b32195c9c7avboxsync PDRVHOSTPARALLEL pThis = PDMIHOSTPARALLELCONNECTOR_2_DRVHOSTPARALLEL(pInterface);
45e9809aff7304721fddb95654901b32195c9c7avboxsync uint8_t fReg;
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync ioctl(pThis->FileDevice, PPRSTATUS, &fReg);
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync LogFlow(("%s: fReg=%d\n", __FUNCTION__, fReg));
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync *pfReg = fReg;
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync return VINF_SUCCESS;
45e9809aff7304721fddb95654901b32195c9c7avboxsync}
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsyncstatic DECLCALLBACK(int) drvHostParallelMonitorThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
45e9809aff7304721fddb95654901b32195c9c7avboxsync{
45e9809aff7304721fddb95654901b32195c9c7avboxsync PDRVHOSTPARALLEL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPARALLEL);
45e9809aff7304721fddb95654901b32195c9c7avboxsync struct pollfd aFDs[2];
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync /*
45e9809aff7304721fddb95654901b32195c9c7avboxsync * We can wait for interrupts using poll on linux hosts.
45e9809aff7304721fddb95654901b32195c9c7avboxsync */
45e9809aff7304721fddb95654901b32195c9c7avboxsync while (pThread->enmState == PDMTHREADSTATE_RUNNING)
45e9809aff7304721fddb95654901b32195c9c7avboxsync {
45e9809aff7304721fddb95654901b32195c9c7avboxsync int rc;
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync aFDs[0].fd = pThis->FileDevice;
45e9809aff7304721fddb95654901b32195c9c7avboxsync aFDs[0].events = POLLIN;
45e9809aff7304721fddb95654901b32195c9c7avboxsync aFDs[0].revents = 0;
45e9809aff7304721fddb95654901b32195c9c7avboxsync aFDs[1].fd = pThis->WakeupPipeR;
45e9809aff7304721fddb95654901b32195c9c7avboxsync aFDs[1].events = POLLIN | POLLERR | POLLHUP;
45e9809aff7304721fddb95654901b32195c9c7avboxsync aFDs[1].revents = 0;
45e9809aff7304721fddb95654901b32195c9c7avboxsync rc = poll(aFDs, RT_ELEMENTS(aFDs), -1);
45e9809aff7304721fddb95654901b32195c9c7avboxsync if (rc < 0)
45e9809aff7304721fddb95654901b32195c9c7avboxsync {
45e9809aff7304721fddb95654901b32195c9c7avboxsync AssertMsgFailed(("poll failed with rc=%d\n", RTErrConvertFromErrno(errno)));
45e9809aff7304721fddb95654901b32195c9c7avboxsync return RTErrConvertFromErrno(errno);
45e9809aff7304721fddb95654901b32195c9c7avboxsync }
45e9809aff7304721fddb95654901b32195c9c7avboxsync
45e9809aff7304721fddb95654901b32195c9c7avboxsync if (pThread->enmState != PDMTHREADSTATE_RUNNING)
45e9809aff7304721fddb95654901b32195c9c7avboxsync break;
45e9809aff7304721fddb95654901b32195c9c7avboxsync if (rc > 0 && aFDs[1].revents)
45e9809aff7304721fddb95654901b32195c9c7avboxsync {
45e9809aff7304721fddb95654901b32195c9c7avboxsync if (aFDs[1].revents & (POLLHUP | POLLERR | POLLNVAL))
45e9809aff7304721fddb95654901b32195c9c7avboxsync break;
45e9809aff7304721fddb95654901b32195c9c7avboxsync /* notification to terminate -- drain the pipe */
45e9809aff7304721fddb95654901b32195c9c7avboxsync char ch;
45e9809aff7304721fddb95654901b32195c9c7avboxsync size_t cbRead;
RTFileRead(pThis->WakeupPipeR, &ch, 1, &cbRead);
continue;
}
/* Interrupt occurred. */
rc = pThis->pDrvHostParallelPort->pfnNotifyInterrupt(pThis->pDrvHostParallelPort);
AssertRC(rc);
}
return VINF_SUCCESS;
}
/**
* Unblock the monitor thread so it can respond to a state change.
*
* @returns a VBox status code.
* @param pDrvIns The driver instance.
* @param pThread The send thread.
*/
static DECLCALLBACK(int) drvHostParallelWakeupMonitorThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
{
PDRVHOSTPARALLEL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPARALLEL);
return RTFileWrite(pThis->WakeupPipeW, "", 1, NULL);
}
/**
* Construct a host parallel driver instance.
*
* @copydoc FNPDMDRVCONSTRUCT
*/
static DECLCALLBACK(int) drvHostParallelConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle, uint32_t fFlags)
{
PDRVHOSTPARALLEL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPARALLEL);
LogFlow(("%s: iInstance=%d\n", __FUNCTION__, pDrvIns->iInstance));
/*
* Validate the config.
*/
if (!CFGMR3AreValuesValid(pCfgHandle, "DevicePath\0"))
return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES,
N_("Unknown host parallel configuration option, only supports DevicePath"));
/*
* Init basic data members and interfaces.
*/
/* IBase. */
pDrvIns->IBase.pfnQueryInterface = drvHostParallelQueryInterface;
/* IHostParallelConnector. */
pThis->IHostParallelConnector.pfnWrite = drvHostParallelWrite;
pThis->IHostParallelConnector.pfnRead = drvHostParallelRead;
pThis->IHostParallelConnector.pfnSetMode = drvHostParallelSetMode;
pThis->IHostParallelConnector.pfnWriteControl = drvHostParallelWriteControl;
pThis->IHostParallelConnector.pfnReadControl = drvHostParallelReadControl;
pThis->IHostParallelConnector.pfnReadStatus = drvHostParallelReadStatus;
/*
* Query configuration.
*/
/* Device */
int rc = CFGMR3QueryStringAlloc(pCfgHandle, "DevicePath", &pThis->pszDevicePath);
if (RT_FAILURE(rc))
{
AssertMsgFailed(("Configuration error: query for \"DevicePath\" string returned %Rra.\n", rc));
return rc;
}
/*
* Open the device
*/
rc = RTFileOpen(&pThis->FileDevice, pThis->pszDevicePath, RTFILE_O_OPEN | RTFILE_O_READWRITE);
if (RT_FAILURE(rc))
return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("Parallel#%d could not open '%s'"),
pDrvIns->iInstance, pThis->pszDevicePath);
/*
* Try to get exclusive access to parallel port
*/
rc = ioctl(pThis->FileDevice, PPEXCL);
if (rc < 0)
return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS,
N_("Parallel#%d could not get exclusive access for parallel port '%s'"
"Be sure that no other process or driver accesses this port"),
pDrvIns->iInstance, pThis->pszDevicePath);
/*
* Claim the parallel port
*/
rc = ioctl(pThis->FileDevice, PPCLAIM);
if (rc < 0)
return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS,
N_("Parallel#%d could not claim parallel port '%s'"
"Be sure that no other process or driver accesses this port"),
pDrvIns->iInstance, pThis->pszDevicePath);
/*
* Get the IHostParallelPort interface of the above driver/device.
*/
pThis->pDrvHostParallelPort = (PPDMIHOSTPARALLELPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_HOST_PARALLEL_PORT);
if (!pThis->pDrvHostParallelPort)
return PDMDrvHlpVMSetError(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE, RT_SRC_POS, N_("Parallel#%d has no parallel port interface above"),
pDrvIns->iInstance);
/*
* Create wakeup pipe.
*/
int aFDs[2];
if (pipe(aFDs) != 0)
{
int rc = RTErrConvertFromErrno(errno);
AssertRC(rc);
return rc;
}
pThis->WakeupPipeR = aFDs[0];
pThis->WakeupPipeW = aFDs[1];
/*
* Start waiting for interrupts.
*/
rc = PDMDrvHlpPDMThreadCreate(pDrvIns, &pThis->pMonitorThread, pThis, drvHostParallelMonitorThread, drvHostParallelWakeupMonitorThread, 0,
RTTHREADTYPE_IO, "ParMon");
if (RT_FAILURE(rc))
return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("HostParallel#%d cannot create monitor thread"), pDrvIns->iInstance);
return VINF_SUCCESS;
}
/**
* Destruct a host parallel driver instance.
*
* Most VM resources are freed by the VM. This callback is provided so that
* any non-VM resources can be freed correctly.
*
* @param pDrvIns The driver instance data.
*/
static DECLCALLBACK(void) drvHostParallelDestruct(PPDMDRVINS pDrvIns)
{
PDRVHOSTPARALLEL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPARALLEL);
LogFlow(("%s: iInstance=%d\n", __FUNCTION__, pDrvIns->iInstance));
ioctl(pThis->FileDevice, PPRELEASE);
if (pThis->WakeupPipeW != NIL_RTFILE)
{
int rc = RTFileClose(pThis->WakeupPipeW);
AssertRC(rc);
pThis->WakeupPipeW = NIL_RTFILE;
}
if (pThis->WakeupPipeR != NIL_RTFILE)
{
int rc = RTFileClose(pThis->WakeupPipeR);
AssertRC(rc);
pThis->WakeupPipeR = NIL_RTFILE;
}
if (pThis->FileDevice != NIL_RTFILE)
{
int rc = RTFileClose(pThis->FileDevice);
AssertRC(rc);
pThis->FileDevice = NIL_RTFILE;
}
}
/**
* Char driver registration record.
*/
const PDMDRVREG g_DrvHostParallel =
{
/* u32Version */
PDM_DRVREG_VERSION,
/* szDriverName */
"HostParallel",
/* pszDescription */
"Parallel host driver.",
/* fFlags */
PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
/* fClass. */
PDM_DRVREG_CLASS_CHAR,
/* cMaxInstances */
~0,
/* cbInstance */
sizeof(DRVHOSTPARALLEL),
/* pfnConstruct */
drvHostParallelConstruct,
/* pfnDestruct */
drvHostParallelDestruct,
/* pfnIOCtl */
NULL,
/* pfnPowerOn */
NULL,
/* pfnReset */
NULL,
/* pfnSuspend */
NULL,
/* pfnResume */
NULL,
/* pfnAttach */
NULL,
/* pfnDetach */
NULL,
/* pfnPowerOff */
NULL,
/* pfnSoftReset */
NULL,
/* u32EndVersion */
PDM_DRVREG_VERSION
};