/* $Id$ */
/** @file
* DevParallel - Parallel (Port) Device Emulation.
*
* Contributed by: Alexander Eichner
* Based on DevSerial.cpp
*/
/*
* Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include <iprt/semaphore.h>
#include "VBoxDD.h"
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/* defines for accessing the register bits */
/** mode defines for the extended control register */
/** FIFO status bits in extended control register */
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* Parallel device state.
*
* @implements PDMIBASE
* @implements PDMIHOSTPARALLELPORT
*/
typedef struct PARALLELPORT
{
/** Pointer to the device instance - R3 Ptr */
/** Pointer to the device instance - R0 Ptr */
/** Pointer to the device instance - RC Ptr */
/** Alignment. */
/** LUN\#0: The base interface. */
/** LUN\#0: The host device port interface. */
/** Pointer to the attached base driver. */
/** Pointer to the attached host device. */
/** Flag whether the device has its RC component enabled. */
bool fGCEnabled;
/** Flag whether the device has its R0 component enabled. */
bool fR0Enabled;
/** Flag whether an EPP timeout occurred (error handling). */
bool fEppTimeout;
/** Base I/O port of the parallel port. */
/** IRQ number assigned ot the parallel port. */
int iIrq;
/** Data register. */
/** Status register. */
/** Control register. */
/** EPP address register. */
/** EPP data register. */
/** More alignment. */
#if 0 /* Data for ECP implementation, currently unused. */
/** The ECP FIFO implementation*/
int act_fifo_pos_write;
int act_fifo_pos_read;
#endif
#ifndef VBOX_DEVICE_STRUCT_TESTCASE
#define PDMIHOSTPARALLELPORT_2_PARALLELPORT(pInstance) ( (PARALLELPORT *)((uintptr_t)(pInterface) - RT_OFFSETOF(PARALLELPORT, IHostParallelPort)) )
#define PDMIHOSTDEVICEPORT_2_PARALLELPORT(pInstance) ( (PARALLELPORT *)((uintptr_t)(pInterface) - RT_OFFSETOF(PARALLELPORT, IHostDevicePort)) )
#define PDMIBASE_2_PARALLELPORT(pInstance) ( (PARALLELPORT *)((uintptr_t)(pInterface) - RT_OFFSETOF(PARALLELPORT, IBase)) )
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
PDMBOTHCBDECL(int) parallelIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
PDMBOTHCBDECL(int) parallelIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
#if 0
PDMBOTHCBDECL(int) parallelIOPortReadECP(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
PDMBOTHCBDECL(int) parallelIOPortWriteECP(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
#endif
#ifdef IN_RING3
{
{
}
}
{
}
#endif
#if 0
{
unsigned char ch;
addr &= 7;
switch (addr) {
default:
case 0:
s->act_fifo_pos_write++;
if (s->act_fifo_pos_write < LPT_ECP_FIFO_DEPTH) {
/* FIFO has some data (clear both FIFO bits) */
} else {
/* FIFO is full */
/* Clear FIFO empty bit */
s->reg_ecp_ecr &= ~LPT_ECP_ECR_FIFO_EMPTY;
/* Set FIFO full bit */
s->reg_ecp_ecr |= LPT_ECP_ECR_FIFO_FULL;
s->act_fifo_pos_write = 0;
}
} else {
s->reg_ecp_base_plus_400h = ch;
}
break;
case 1:
s->reg_ecp_config_b = ch;
break;
case 2:
/* If we change the mode clear FIFO */
/* reset the fifo */
s->act_fifo_pos_write = 0;
s->act_fifo_pos_read = 0;
/* Set FIFO empty bit */
/* Clear FIFO full bit */
s->reg_ecp_ecr &= ~LPT_ECP_ECR_FIFO_FULL;
}
/* Set new mode */
break;
case 3:
break;
case 4:
break;
case 5:
break;
case 6:
break;
case 7:
break;
}
return VINF_SUCCESS;
}
{
*pRC = VINF_SUCCESS;
addr &= 7;
switch (addr) {
default:
case 0:
s->act_fifo_pos_read++;
if (s->act_fifo_pos_read == LPT_ECP_FIFO_DEPTH)
s->act_fifo_pos_read = 0; /* end of FIFO, start at beginning */
if (s->act_fifo_pos_read == s->act_fifo_pos_write) {
/* FIFO is empty */
/* Set FIFO empty bit */
/* Clear FIFO full bit */
s->reg_ecp_ecr &= ~LPT_ECP_ECR_FIFO_FULL;
} else {
/* FIFO has some data (clear all FIFO bits) */
}
} else {
ret = s->reg_ecp_base_plus_400h;
}
break;
case 1:
ret = s->reg_ecp_config_b;
break;
case 2:
ret = s->reg_ecp_ecr;
break;
case 3:
break;
case 4:
break;
case 5:
break;
case 6:
break;
case 7:
break;
}
return ret;
}
#endif
#ifdef IN_RING3
/**
* @interface_methods_impl{PDMIHOSTPARALLELPORT,pfnNotifyInterrupt}
*/
{
return VINF_SUCCESS;
}
#endif /* IN_RING3 */
/**
* @callback_method_impl{FNIOMIOPORTOUT}
*/
PDMBOTHCBDECL(int) parallelIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
{
if (cb == 1)
{
Port &= 7;
switch (Port)
{
case 0:
#ifndef IN_RING3
#else
{
rc = pThis->pDrvHostParallelConnector->pfnWrite(pThis->pDrvHostParallelConnector, &u8, 1, PDM_PARALLEL_PORT_MODE_SPP);
}
#endif
break;
case 1:
break;
case 2:
/* Set the reserved bits to one */
{
#ifndef IN_RING3
return VINF_IOM_R3_IOPORT_WRITE;
#else
/* Set data direction. */
if (u8 & LPT_CONTROL_ENABLE_BIDIRECT)
rc = pThis->pDrvHostParallelConnector->pfnSetPortDirection(pThis->pDrvHostParallelConnector, false /* fForward */);
else
rc = pThis->pDrvHostParallelConnector->pfnSetPortDirection(pThis->pDrvHostParallelConnector, true /* fForward */);
#endif
}
break;
case 3:
#ifndef IN_RING3
#else
{
rc = pThis->pDrvHostParallelConnector->pfnWrite(pThis->pDrvHostParallelConnector, &u8, 1, PDM_PARALLEL_PORT_MODE_EPP_ADDR);
}
#endif
break;
case 4:
#ifndef IN_RING3
#else
{
rc = pThis->pDrvHostParallelConnector->pfnWrite(pThis->pDrvHostParallelConnector, &u8, 1, PDM_PARALLEL_PORT_MODE_EPP_DATA);
}
#endif
break;
case 5:
break;
case 6:
break;
case 7:
default:
break;
}
}
else
return rc;
}
/**
* @callback_method_impl{FNIOMIOPORTIN}
*/
PDMBOTHCBDECL(int) parallelIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
{
if (cb == 1)
{
Port &= 7;
switch (Port)
{
case 0:
else
{
#ifndef IN_RING3
#else
{
}
#endif
}
break;
case 1:
#ifndef IN_RING3
#else
{
rc = pThis->pDrvHostParallelConnector->pfnReadStatus(pThis->pDrvHostParallelConnector, &pThis->regStatus);
}
#endif
break;
case 2:
#ifndef IN_RING3
#else
rc = pThis->pDrvHostParallelConnector->pfnReadControl(pThis->pDrvHostParallelConnector, &pThis->regControl);
#endif
break;
case 3:
#ifndef IN_RING3
#else
{
rc = pThis->pDrvHostParallelConnector->pfnRead(pThis->pDrvHostParallelConnector, &pThis->regEppAddr,
}
#endif
break;
case 4:
#ifndef IN_RING3
#else
{
rc = pThis->pDrvHostParallelConnector->pfnRead(pThis->pDrvHostParallelConnector, &pThis->regEppData,
}
#endif
break;
case 5:
break;
case 6:
break;
case 7:
break;
}
}
else
return rc;
}
#if 0
/**
* @callback_method_impl{FNIOMIOPORTOUT, ECP registers.}
*/
PDMBOTHCBDECL(int) parallelIOPortWriteECP(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
{
int rc = VINF_SUCCESS;
if (cb == 1)
{
}
else
return rc;
}
/**
* @callback_method_impl{FNIOMIOPORTOUT, ECP registers.}
*/
PDMBOTHCBDECL(int) parallelIOPortReadECP(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
{
int rc = VINF_SUCCESS;
if (cb == 1)
{
}
else
return rc;
}
#endif
#ifdef IN_RING3
/**
* @callback_method_impl{FNSSMDEVLIVEEXEC}
*/
{
return VINF_SSM_DONT_CALL_AGAIN;
}
/**
* @callback_method_impl{FNSSMDEVSAVEEXEC}
*/
{
return VINF_SUCCESS;
}
/**
* @callback_method_impl{FNSSMDEVLOADEXEC}
*/
static DECLCALLBACK(int) parallelR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
{
AssertMsgReturn(uVersion == PARALLEL_SAVED_STATE_VERSION, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
if (uPass == SSM_PASS_FINAL)
{
}
/* the config */
if (RT_FAILURE(rc))
return rc;
return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("IRQ changed: config=%#x state=%#x"), pThis->iIrq, iIrq);
return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("IOBase changed: config=%#x state=%#x"), pThis->IOBase, uIoBase);
/* not necessary... but it doesn't harm. */
return VINF_SUCCESS;
}
/**
* @interface_method_impl{PDMIBASE,pfnQueryInterface}
*/
{
return NULL;
}
/**
* @copydoc FNPDMDEVRELOCATE
*/
{
}
/**
* @interface_method_impl{PDMDEVREG,pfnConstruct}
*/
{
int rc;
/*
* Init the data.
*/
/* IBase */
/* IHostParallelPort */
/* Init parallel state */
#if 0 /* ECP implementation not complete. */
pThis->act_fifo_pos_read = 0;
pThis->act_fifo_pos_write = 0;
#endif
/*
* Validate and read the configuration.
*/
N_("Configuration error: Unknown config key"));
if (RT_FAILURE(rc))
N_("Configuration error: Failed to get the \"GCEnabled\" value"));
if (RT_FAILURE(rc))
N_("Configuration error: Failed to get the \"R0Enabled\" value"));
if (RT_FAILURE(rc))
N_("Configuration error: Failed to get the \"IRQ\" value"));
if (RT_FAILURE(rc))
N_("Configuration error: Failed to get the \"IOBase\" value"));
/*
* Register the I/O ports and saved state.
*/
if (RT_FAILURE(rc))
return rc;
#if 0
/* register ecp registers */
if (RT_FAILURE(rc))
return rc;
#endif
if (pThis->fGCEnabled)
{
if (RT_FAILURE(rc))
return rc;
#if 0
if (RT_FAILURE(rc))
return rc;
#endif
}
if (pThis->fR0Enabled)
{
if (RT_FAILURE(rc))
return rc;
#if 0
if (RT_FAILURE(rc))
return rc;
#endif
}
if (RT_FAILURE(rc))
return rc;
/*
* Attach the parallel port driver and get the interfaces.
* For now no run-time changes are supported.
*/
if (RT_SUCCESS(rc))
{
pThis->pDrvHostParallelConnector = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIHOSTPARALLELCONNECTOR);
("Configuration error: instance %d has no host parallel interface!\n", iInstance),
}
else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
{
}
else
{
}
/* Set compatibility mode */
//pThis->pDrvHostParallelConnector->pfnSetMode(pThis->pDrvHostParallelConnector, PDM_PARALLEL_PORT_MODE_COMPAT);
/* Get status of control register */
pThis->pDrvHostParallelConnector->pfnReadControl(pThis->pDrvHostParallelConnector, &pThis->regControl);
return VINF_SUCCESS;
}
/**
* The device registration structure.
*/
const PDMDEVREG g_DeviceParallelPort =
{
/* u32Version */
/* szName */
"parallel",
/* szRCMod */
"VBoxDDGC.gc",
/* szR0Mod */
"VBoxDDR0.r0",
/* pszDescription */
"Parallel Communication Port",
/* fFlags */
/* fClass */
/* cMaxInstances */
1,
/* cbInstance */
sizeof(PARALLELPORT),
/* pfnConstruct */
/* pfnDestruct */
NULL,
/* pfnRelocate */
/* pfnMemSetup */
NULL,
/* pfnPowerOn */
NULL,
/* pfnReset */
NULL,
/* pfnSuspend */
NULL,
/* pfnResume */
NULL,
/* pfnAttach */
NULL,
/* pfnDetach */
NULL,
/* pfnQueryInterface. */
NULL,
/* pfnInitComplete */
NULL,
/* pfnPowerOff */
NULL,
/* pfnSoftReset */
NULL,
/* u32VersionEnd */
};
#endif /* IN_RING3 */
#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */