DevParallel.cpp revision 4fbca3751fe239da5934c23a783c3422618336e8
c74832c7184337c330041742d88e6dacaa07b378vboxsync/* $Id$ */
c74832c7184337c330041742d88e6dacaa07b378vboxsync/** @file
c74832c7184337c330041742d88e6dacaa07b378vboxsync * VirtualBox Parallel Device Emulation.
d192cc72774b02a0df2fdd46350d418236ac09aevboxsync *
d192cc72774b02a0df2fdd46350d418236ac09aevboxsync * Contributed by: Alexander Eichner
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync/*
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Copyright (C) 2006-2007 innotek GmbH
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
c74832c7184337c330041742d88e6dacaa07b378vboxsync * available from http://www.virtualbox.org. This file is free software;
c74832c7184337c330041742d88e6dacaa07b378vboxsync * you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License (GPL) as published by the Free Software
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync/* based on DevSerial.cpp */
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync/*******************************************************************************
c74832c7184337c330041742d88e6dacaa07b378vboxsync* Header Files *
c74832c7184337c330041742d88e6dacaa07b378vboxsync*******************************************************************************/
c74832c7184337c330041742d88e6dacaa07b378vboxsync#define LOG_GROUP LOG_GROUP_DEV_PARALLEL
da957c069c2a3c582fe265ff88170ce4c42b499dvboxsync#include <VBox/pdmdev.h>
c74832c7184337c330041742d88e6dacaa07b378vboxsync#include <iprt/assert.h>
c74832c7184337c330041742d88e6dacaa07b378vboxsync#include <iprt/uuid.h>
c74832c7184337c330041742d88e6dacaa07b378vboxsync#include <iprt/string.h>
c74832c7184337c330041742d88e6dacaa07b378vboxsync#include <iprt/semaphore.h>
c74832c7184337c330041742d88e6dacaa07b378vboxsync#include <iprt/critsect.h>
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync#include "Builtins.h"
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync#define PARALLEL_SAVED_STATE_VERSION 1
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync/* defines for accessing the register bits */
c74832c7184337c330041742d88e6dacaa07b378vboxsync#define LPT_STATUS_BUSY 0x80
c74832c7184337c330041742d88e6dacaa07b378vboxsync#define LPT_STATUS_ACK 0x40
c74832c7184337c330041742d88e6dacaa07b378vboxsync#define LPT_STATUS_PAPER_OUT 0x20
c74832c7184337c330041742d88e6dacaa07b378vboxsync#define LPT_STATUS_SELECT_IN 0x10
c74832c7184337c330041742d88e6dacaa07b378vboxsync#define LPT_STATUS_ERROR 0x08
c74832c7184337c330041742d88e6dacaa07b378vboxsync#define LPT_STATUS_IRQ 0x04
c74832c7184337c330041742d88e6dacaa07b378vboxsync#define LPT_STATUS_BIT1 0x02 /* reserved (only for completeness) */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define LPT_STATUS_EPP_TIMEOUT 0x01
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync#define LPT_CONTROL_BIT7 0x80 /* reserved (only for completeness) */
c74832c7184337c330041742d88e6dacaa07b378vboxsync#define LPT_CONTROL_BIT6 0x40 /* reserved (only for completeness) */
c74832c7184337c330041742d88e6dacaa07b378vboxsync#define LPT_CONTROL_ENABLE_BIDIRECT 0x20
c74832c7184337c330041742d88e6dacaa07b378vboxsync#define LPT_CONTROL_ENABLE_IRQ_VIA_ACK 0x10
c74832c7184337c330041742d88e6dacaa07b378vboxsync#define LPT_CONTROL_SELECT_PRINTER 0x08
c74832c7184337c330041742d88e6dacaa07b378vboxsync#define LPT_CONTROL_RESET 0x04
c74832c7184337c330041742d88e6dacaa07b378vboxsync#define LPT_CONTROL_AUTO_LINEFEED 0x02
c74832c7184337c330041742d88e6dacaa07b378vboxsync#define LPT_CONTROL_STROBE 0x01
c74832c7184337c330041742d88e6dacaa07b378vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync/** mode defines for the extended control register */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define LPT_ECP_ECR_CHIPMODE_MASK 0xe0
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define LPT_ECP_ECR_CHIPMODE_GET_BITS(reg) ((reg) >> 5)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define LPT_ECP_ECR_CHIPMODE_SET_BITS(val) ((val) << 5)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define LPT_ECP_ECR_CHIPMODE_CONFIGURATION 0x07
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define LPT_ECP_ECR_CHIPMODE_FIFO_TEST 0x06
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define LPT_ECP_ECR_CHIPMODE_RESERVED 0x05
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define LPT_ECP_ECR_CHIPMODE_EPP 0x04
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define LPT_ECP_ECR_CHIPMODE_ECP_FIFO 0x03
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define LPT_ECP_ECR_CHIPMODE_PP_FIFO 0x02
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define LPT_ECP_ECR_CHIPMODE_BYTE 0x01
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define LPT_ECP_ECR_CHIPMODE_COMPAT 0x00
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync/** FIFO status bits in extended control register */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define LPT_ECP_ECR_FIFO_MASK 0x03
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define LPT_ECP_ECR_FIFO_SOME_DATA 0x00
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define LPT_ECP_ECR_FIFO_FULL 0x02
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define LPT_ECP_ECR_FIFO_EMPTY 0x01
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define LPT_ECP_CONFIGA_FIFO_WITDH_MASK 0x70
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define LPT_ECP_CONFIGA_FIFO_WIDTH_GET_BITS(reg) ((reg) >> 4)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define LPT_ECP_CONFIGA_FIFO_WIDTH_SET_BITS(val) ((val) << 4)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define LPT_ECP_CONFIGA_FIFO_WIDTH_16 0x00
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define LPT_ECP_CONFIGA_FIFO_WIDTH_32 0x20
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define LPT_ECP_CONFIGA_FIFO_WIDTH_8 0x10
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define LPT_ECP_FIFO_DEPTH 2
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsynctypedef struct ParallelState
c74832c7184337c330041742d88e6dacaa07b378vboxsync{
c74832c7184337c330041742d88e6dacaa07b378vboxsync /** Access critical section. */
c74832c7184337c330041742d88e6dacaa07b378vboxsync PDMCRITSECT CritSect;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync /** Pointer to the device instance. */
0c34933fc8f84dd5183d1897881bbc7683d24541vboxsync R3R0PTRTYPE(PPDMDEVINS) pDevInsHC;
c74832c7184337c330041742d88e6dacaa07b378vboxsync /** Pointer to the device instance. */
c74832c7184337c330041742d88e6dacaa07b378vboxsync GCPTRTYPE(PPDMDEVINS) pDevInsGC;
c74832c7184337c330041742d88e6dacaa07b378vboxsync#if HC_ARCH_BITS == 64 && GC_ARCH_BITS != 64
c74832c7184337c330041742d88e6dacaa07b378vboxsync RTGCPTR Alignment0;
c74832c7184337c330041742d88e6dacaa07b378vboxsync#endif
c74832c7184337c330041742d88e6dacaa07b378vboxsync /** The base interface. */
0c34933fc8f84dd5183d1897881bbc7683d24541vboxsync R3PTRTYPE(PDMIBASE) IBase;
c74832c7184337c330041742d88e6dacaa07b378vboxsync /** The host device port interface. */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync R3PTRTYPE(PDMIHOSTPARALLELPORT) IHostParallelPort;
c74832c7184337c330041742d88e6dacaa07b378vboxsync /** Pointer to the attached base driver. */
0c34933fc8f84dd5183d1897881bbc7683d24541vboxsync R3PTRTYPE(PPDMIBASE) pDrvBase;
c74832c7184337c330041742d88e6dacaa07b378vboxsync /** Pointer to the attached host device. */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync R3PTRTYPE(PPDMIHOSTPARALLELCONNECTOR) pDrvHostParallelConnector;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync uint8_t reg_data;
c74832c7184337c330041742d88e6dacaa07b378vboxsync uint8_t reg_status;
c74832c7184337c330041742d88e6dacaa07b378vboxsync uint8_t reg_control;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync uint8_t reg_epp_addr;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync uint8_t reg_epp_data;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync uint8_t reg_ecp_ecr;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync uint8_t reg_ecp_base_plus_400h; /* has different meanings */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync uint8_t reg_ecp_config_b;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /** The ECP FIFO implementation*/
4fbca3751fe239da5934c23a783c3422618336e8vboxsync uint8_t ecp_fifo[LPT_ECP_FIFO_DEPTH];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync int act_fifo_pos_write;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync int act_fifo_pos_read;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync int irq;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync uint8_t epp_timeout;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync bool fGCEnabled;
c74832c7184337c330041742d88e6dacaa07b378vboxsync bool fR0Enabled;
c74832c7184337c330041742d88e6dacaa07b378vboxsync bool afAlignment[6];
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync RTSEMEVENT ReceiveSem;
c74832c7184337c330041742d88e6dacaa07b378vboxsync uint32_t base;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync} DEVPARALLELSTATE, *PDEVPARALLELSTATE;
c74832c7184337c330041742d88e6dacaa07b378vboxsynctypedef DEVPARALLELSTATE ParallelState;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync#ifndef VBOX_DEVICE_STRUCT_TESTCASE
c74832c7184337c330041742d88e6dacaa07b378vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define PDMIHOSTPARALLELPORT_2_PARALLELSTATE(pInstance) ( (ParallelState *)((uintptr_t)(pInterface) - RT_OFFSETOF(ParallelState, IHostParallelPort)) )
c74832c7184337c330041742d88e6dacaa07b378vboxsync#define PDMIHOSTDEVICEPORT_2_PARALLELSTATE(pInstance) ( (ParallelState *)((uintptr_t)(pInterface) - RT_OFFSETOF(ParallelState, IHostDevicePort)) )
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define PDMIBASE_2_PARALLELSTATE(pInstance) ( (ParallelState *)((uintptr_t)(pInterface) - RT_OFFSETOF(ParallelState, IBase)) )
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync__BEGIN_DECLS
c74832c7184337c330041742d88e6dacaa07b378vboxsyncPDMBOTHCBDECL(int) parallelIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
c74832c7184337c330041742d88e6dacaa07b378vboxsyncPDMBOTHCBDECL(int) parallelIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#if 0
4fbca3751fe239da5934c23a783c3422618336e8vboxsyncPDMBOTHCBDECL(int) parallelIOPortReadECP(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
4fbca3751fe239da5934c23a783c3422618336e8vboxsyncPDMBOTHCBDECL(int) parallelIOPortWriteECP(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#endif
c74832c7184337c330041742d88e6dacaa07b378vboxsync__END_DECLS
c74832c7184337c330041742d88e6dacaa07b378vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsyncstatic void parallel_set_irq(ParallelState *s)
c74832c7184337c330041742d88e6dacaa07b378vboxsync{
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (s->reg_control & LPT_CONTROL_ENABLE_IRQ_VIA_ACK)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync {
c74832c7184337c330041742d88e6dacaa07b378vboxsync Log(("parallel_update_irq %d 1\n", s->irq));
c74832c7184337c330041742d88e6dacaa07b378vboxsync PDMDevHlpISASetIrqNoWait(CTXSUFF(s->pDevIns), s->irq, 1);
c74832c7184337c330041742d88e6dacaa07b378vboxsync }
c74832c7184337c330041742d88e6dacaa07b378vboxsync}
c74832c7184337c330041742d88e6dacaa07b378vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsyncstatic void parallel_clear_irq(ParallelState *s)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync{
4fbca3751fe239da5934c23a783c3422618336e8vboxsync Log(("parallel_update_irq %d 0\n", s->irq));
4fbca3751fe239da5934c23a783c3422618336e8vboxsync PDMDevHlpISASetIrqNoWait(CTXSUFF(s->pDevIns), s->irq, 0);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync}
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsyncstatic int parallel_ioport_write(void *opaque, uint32_t addr, uint32_t val)
c74832c7184337c330041742d88e6dacaa07b378vboxsync{
c74832c7184337c330041742d88e6dacaa07b378vboxsync ParallelState *s = (ParallelState *)opaque;
c74832c7184337c330041742d88e6dacaa07b378vboxsync unsigned char ch;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync addr &= 7;
c74832c7184337c330041742d88e6dacaa07b378vboxsync LogFlow(("parallel: write addr=0x%02x val=0x%02x\n", addr, val));
4fbca3751fe239da5934c23a783c3422618336e8vboxsync ch = val;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync switch(addr) {
c74832c7184337c330041742d88e6dacaa07b378vboxsync default:
c74832c7184337c330041742d88e6dacaa07b378vboxsync case 0:
c74832c7184337c330041742d88e6dacaa07b378vboxsync#ifndef IN_RING3
c74832c7184337c330041742d88e6dacaa07b378vboxsync NOREF(ch);
c74832c7184337c330041742d88e6dacaa07b378vboxsync return VINF_IOM_HC_IOPORT_WRITE;
c74832c7184337c330041742d88e6dacaa07b378vboxsync#else
c74832c7184337c330041742d88e6dacaa07b378vboxsync s->reg_data = ch;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (RT_LIKELY(s->pDrvHostParallelConnector))
c74832c7184337c330041742d88e6dacaa07b378vboxsync {
c74832c7184337c330041742d88e6dacaa07b378vboxsync Log(("parallel_io_port_write: write 0x%X\n", ch));
c74832c7184337c330041742d88e6dacaa07b378vboxsync size_t cbWrite = 1;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync int rc = s->pDrvHostParallelConnector->pfnWrite(s->pDrvHostParallelConnector, &ch, &cbWrite);
c74832c7184337c330041742d88e6dacaa07b378vboxsync AssertRC(rc);
c74832c7184337c330041742d88e6dacaa07b378vboxsync }
c74832c7184337c330041742d88e6dacaa07b378vboxsync#endif
c74832c7184337c330041742d88e6dacaa07b378vboxsync break;
c74832c7184337c330041742d88e6dacaa07b378vboxsync case 1:
c74832c7184337c330041742d88e6dacaa07b378vboxsync break;
c74832c7184337c330041742d88e6dacaa07b378vboxsync case 2:
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /** Set the reserved bits to one */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync ch |= (LPT_CONTROL_BIT6 | LPT_CONTROL_BIT7);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (ch != s->reg_control) {
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#ifndef IN_RING3
4fbca3751fe239da5934c23a783c3422618336e8vboxsync NOREF(ch);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync return VINF_IOM_HC_IOPORT_WRITE;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#else
4fbca3751fe239da5934c23a783c3422618336e8vboxsync int rc = s->pDrvHostParallelConnector->pfnWriteControl(s->pDrvHostParallelConnector, ch);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync AssertRC(rc);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync s->reg_control = val;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#endif
4fbca3751fe239da5934c23a783c3422618336e8vboxsync }
c74832c7184337c330041742d88e6dacaa07b378vboxsync break;
c74832c7184337c330041742d88e6dacaa07b378vboxsync case 3:
4fbca3751fe239da5934c23a783c3422618336e8vboxsync s->reg_epp_addr = val;
c74832c7184337c330041742d88e6dacaa07b378vboxsync break;
c74832c7184337c330041742d88e6dacaa07b378vboxsync case 4:
4fbca3751fe239da5934c23a783c3422618336e8vboxsync s->reg_epp_data = val;
c74832c7184337c330041742d88e6dacaa07b378vboxsync break;
c74832c7184337c330041742d88e6dacaa07b378vboxsync case 5:
c74832c7184337c330041742d88e6dacaa07b378vboxsync break;
c74832c7184337c330041742d88e6dacaa07b378vboxsync case 6:
c74832c7184337c330041742d88e6dacaa07b378vboxsync break;
c74832c7184337c330041742d88e6dacaa07b378vboxsync case 7:
c74832c7184337c330041742d88e6dacaa07b378vboxsync break;
c74832c7184337c330041742d88e6dacaa07b378vboxsync }
c74832c7184337c330041742d88e6dacaa07b378vboxsync return VINF_SUCCESS;
c74832c7184337c330041742d88e6dacaa07b378vboxsync}
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsyncstatic uint32_t parallel_ioport_read(void *opaque, uint32_t addr, int *pRC)
c74832c7184337c330041742d88e6dacaa07b378vboxsync{
c74832c7184337c330041742d88e6dacaa07b378vboxsync ParallelState *s = (ParallelState *)opaque;
c74832c7184337c330041742d88e6dacaa07b378vboxsync uint32_t ret = ~0U;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync *pRC = VINF_SUCCESS;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync addr &= 7;
c74832c7184337c330041742d88e6dacaa07b378vboxsync switch(addr) {
c74832c7184337c330041742d88e6dacaa07b378vboxsync default:
c74832c7184337c330041742d88e6dacaa07b378vboxsync case 0:
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (!(s->reg_control & LPT_CONTROL_ENABLE_BIDIRECT))
4fbca3751fe239da5934c23a783c3422618336e8vboxsync ret = s->reg_data;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync else
4fbca3751fe239da5934c23a783c3422618336e8vboxsync {
c74832c7184337c330041742d88e6dacaa07b378vboxsync#ifndef IN_RING3
c74832c7184337c330041742d88e6dacaa07b378vboxsync *pRC = VINF_IOM_HC_IOPORT_READ;
c74832c7184337c330041742d88e6dacaa07b378vboxsync#else
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (RT_LIKELY(s->pDrvHostParallelConnector))
c74832c7184337c330041742d88e6dacaa07b378vboxsync {
c74832c7184337c330041742d88e6dacaa07b378vboxsync size_t cbRead;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync int rc = s->pDrvHostParallelConnector->pfnRead(s->pDrvHostParallelConnector, &s->reg_data, &cbRead);
c74832c7184337c330041742d88e6dacaa07b378vboxsync Log(("parallel_io_port_read: read 0x%X\n", s->reg_data));
c74832c7184337c330041742d88e6dacaa07b378vboxsync AssertRC(rc);
c74832c7184337c330041742d88e6dacaa07b378vboxsync }
c74832c7184337c330041742d88e6dacaa07b378vboxsync ret = s->reg_data;
c74832c7184337c330041742d88e6dacaa07b378vboxsync#endif
4fbca3751fe239da5934c23a783c3422618336e8vboxsync }
c74832c7184337c330041742d88e6dacaa07b378vboxsync break;
c74832c7184337c330041742d88e6dacaa07b378vboxsync case 1:
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#ifndef IN_RING3
4fbca3751fe239da5934c23a783c3422618336e8vboxsync *pRC = VINF_IOM_HC_IOPORT_READ;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#else
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (RT_LIKELY(s->pDrvHostParallelConnector))
4fbca3751fe239da5934c23a783c3422618336e8vboxsync {
4fbca3751fe239da5934c23a783c3422618336e8vboxsync int rc = s->pDrvHostParallelConnector->pfnReadStatus(s->pDrvHostParallelConnector, &s->reg_status);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync AssertRC(rc);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync }
c74832c7184337c330041742d88e6dacaa07b378vboxsync ret = s->reg_status;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync parallel_clear_irq(s);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#endif
c74832c7184337c330041742d88e6dacaa07b378vboxsync break;
c74832c7184337c330041742d88e6dacaa07b378vboxsync case 2:
c74832c7184337c330041742d88e6dacaa07b378vboxsync ret = s->reg_control;
c74832c7184337c330041742d88e6dacaa07b378vboxsync break;
c74832c7184337c330041742d88e6dacaa07b378vboxsync case 3:
4fbca3751fe239da5934c23a783c3422618336e8vboxsync ret = s->reg_epp_addr;
c74832c7184337c330041742d88e6dacaa07b378vboxsync break;
c74832c7184337c330041742d88e6dacaa07b378vboxsync case 4:
4fbca3751fe239da5934c23a783c3422618336e8vboxsync ret = s->reg_epp_data;
c74832c7184337c330041742d88e6dacaa07b378vboxsync break;
c74832c7184337c330041742d88e6dacaa07b378vboxsync case 5:
c74832c7184337c330041742d88e6dacaa07b378vboxsync break;
c74832c7184337c330041742d88e6dacaa07b378vboxsync case 6:
c74832c7184337c330041742d88e6dacaa07b378vboxsync break;
c74832c7184337c330041742d88e6dacaa07b378vboxsync case 7:
c74832c7184337c330041742d88e6dacaa07b378vboxsync break;
c74832c7184337c330041742d88e6dacaa07b378vboxsync }
c74832c7184337c330041742d88e6dacaa07b378vboxsync LogFlow(("parallel: read addr=0x%02x val=0x%02x\n", addr, ret));
c74832c7184337c330041742d88e6dacaa07b378vboxsync return ret;
c74832c7184337c330041742d88e6dacaa07b378vboxsync}
c74832c7184337c330041742d88e6dacaa07b378vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#if 0
4fbca3751fe239da5934c23a783c3422618336e8vboxsyncstatic int parallel_ioport_write_ecp(void *opaque, uint32_t addr, uint32_t val)
c74832c7184337c330041742d88e6dacaa07b378vboxsync{
4fbca3751fe239da5934c23a783c3422618336e8vboxsync ParallelState *s = (ParallelState *)opaque;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync unsigned char ch;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync addr &= 7;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync LogFlow(("parallel: write ecp addr=0x%02x val=0x%02x\n", addr, val));
4fbca3751fe239da5934c23a783c3422618336e8vboxsync ch = val;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync switch(addr) {
4fbca3751fe239da5934c23a783c3422618336e8vboxsync default:
4fbca3751fe239da5934c23a783c3422618336e8vboxsync case 0:
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (LPT_ECP_ECR_CHIPMODE_GET_BITS(s->reg_ecp_ecr) == LPT_ECP_ECR_CHIPMODE_FIFO_TEST) {
4fbca3751fe239da5934c23a783c3422618336e8vboxsync s->ecp_fifo[s->act_fifo_pos_write] = ch;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync s->act_fifo_pos_write++;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (s->act_fifo_pos_write < LPT_ECP_FIFO_DEPTH) {
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /** FIFO has some data (clear both FIFO bits) */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync s->reg_ecp_ecr &= ~(LPT_ECP_ECR_FIFO_EMPTY | LPT_ECP_ECR_FIFO_FULL);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync } else {
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /** FIFO is full */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /** Clear FIFO empty bit */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync s->reg_ecp_ecr &= ~LPT_ECP_ECR_FIFO_EMPTY;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /** Set FIFO full bit */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync s->reg_ecp_ecr |= LPT_ECP_ECR_FIFO_FULL;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync s->act_fifo_pos_write = 0;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync }
4fbca3751fe239da5934c23a783c3422618336e8vboxsync } else {
4fbca3751fe239da5934c23a783c3422618336e8vboxsync s->reg_ecp_base_plus_400h = ch;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync }
4fbca3751fe239da5934c23a783c3422618336e8vboxsync break;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync case 1:
4fbca3751fe239da5934c23a783c3422618336e8vboxsync s->reg_ecp_config_b = ch;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync break;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync case 2:
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /** If we change the mode clear FIFO */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if ((ch & LPT_ECP_ECR_CHIPMODE_MASK) != (s->reg_ecp_ecr & LPT_ECP_ECR_CHIPMODE_MASK)) {
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /** reset the fifo */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync s->act_fifo_pos_write = 0;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync s->act_fifo_pos_read = 0;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /** Set FIFO empty bit */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync s->reg_ecp_ecr |= LPT_ECP_ECR_FIFO_EMPTY;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /** Clear FIFO full bit */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync s->reg_ecp_ecr &= ~LPT_ECP_ECR_FIFO_FULL;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync }
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /** Set new mode */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync s->reg_ecp_ecr |= LPT_ECP_ECR_CHIPMODE_SET_BITS(LPT_ECP_ECR_CHIPMODE_GET_BITS(ch));
4fbca3751fe239da5934c23a783c3422618336e8vboxsync break;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync case 3:
4fbca3751fe239da5934c23a783c3422618336e8vboxsync break;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync case 4:
4fbca3751fe239da5934c23a783c3422618336e8vboxsync break;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync case 5:
4fbca3751fe239da5934c23a783c3422618336e8vboxsync break;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync case 6:
4fbca3751fe239da5934c23a783c3422618336e8vboxsync break;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync case 7:
4fbca3751fe239da5934c23a783c3422618336e8vboxsync break;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync }
c74832c7184337c330041742d88e6dacaa07b378vboxsync return VINF_SUCCESS;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync}
c74832c7184337c330041742d88e6dacaa07b378vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsyncstatic uint32_t parallel_ioport_read_ecp(void *opaque, uint32_t addr, int *pRC)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync{
4fbca3751fe239da5934c23a783c3422618336e8vboxsync ParallelState *s = (ParallelState *)opaque;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync uint32_t ret = ~0U;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync *pRC = VINF_SUCCESS;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync addr &= 7;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync switch(addr) {
4fbca3751fe239da5934c23a783c3422618336e8vboxsync default:
4fbca3751fe239da5934c23a783c3422618336e8vboxsync case 0:
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (LPT_ECP_ECR_CHIPMODE_GET_BITS(s->reg_ecp_ecr) == LPT_ECP_ECR_CHIPMODE_FIFO_TEST) {
4fbca3751fe239da5934c23a783c3422618336e8vboxsync ret = s->ecp_fifo[s->act_fifo_pos_read];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync s->act_fifo_pos_read++;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (s->act_fifo_pos_read == LPT_ECP_FIFO_DEPTH)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync s->act_fifo_pos_read = 0; /** end of FIFO, start at beginning */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (s->act_fifo_pos_read == s->act_fifo_pos_write) {
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /** FIFO is empty */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /** Set FIFO empty bit */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync s->reg_ecp_ecr |= LPT_ECP_ECR_FIFO_EMPTY;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /** Clear FIFO full bit */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync s->reg_ecp_ecr &= ~LPT_ECP_ECR_FIFO_FULL;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync } else {
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /** FIFO has some data (clear all FIFO bits) */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync s->reg_ecp_ecr &= ~(LPT_ECP_ECR_FIFO_EMPTY | LPT_ECP_ECR_FIFO_FULL);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync }
4fbca3751fe239da5934c23a783c3422618336e8vboxsync } else {
4fbca3751fe239da5934c23a783c3422618336e8vboxsync ret = s->reg_ecp_base_plus_400h;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync }
4fbca3751fe239da5934c23a783c3422618336e8vboxsync break;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync case 1:
4fbca3751fe239da5934c23a783c3422618336e8vboxsync ret = s->reg_ecp_config_b;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync break;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync case 2:
4fbca3751fe239da5934c23a783c3422618336e8vboxsync ret = s->reg_ecp_ecr;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync break;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync case 3:
4fbca3751fe239da5934c23a783c3422618336e8vboxsync break;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync case 4:
4fbca3751fe239da5934c23a783c3422618336e8vboxsync break;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync case 5:
4fbca3751fe239da5934c23a783c3422618336e8vboxsync break;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync case 6:
4fbca3751fe239da5934c23a783c3422618336e8vboxsync break;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync case 7:
4fbca3751fe239da5934c23a783c3422618336e8vboxsync break;
c74832c7184337c330041742d88e6dacaa07b378vboxsync }
4fbca3751fe239da5934c23a783c3422618336e8vboxsync LogFlow(("parallel: read ecp addr=0x%02x val=0x%02x\n", addr, ret));
4fbca3751fe239da5934c23a783c3422618336e8vboxsync return ret;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync}
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#endif
c74832c7184337c330041742d88e6dacaa07b378vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#ifdef IN_RING3
4fbca3751fe239da5934c23a783c3422618336e8vboxsyncstatic DECLCALLBACK(int) parallelNotifyInterrupt(PPDMIHOSTPARALLELPORT pInterface)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync{
4fbca3751fe239da5934c23a783c3422618336e8vboxsync ParallelState *pData = PDMIHOSTPARALLELPORT_2_PARALLELSTATE(pInterface);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync PDMCritSectEnter(&pData->CritSect, VINF_SUCCESS);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync parallel_set_irq(pData);
c74832c7184337c330041742d88e6dacaa07b378vboxsync PDMCritSectLeave(&pData->CritSect);
c74832c7184337c330041742d88e6dacaa07b378vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync return VINF_SUCCESS;
c74832c7184337c330041742d88e6dacaa07b378vboxsync}
c74832c7184337c330041742d88e6dacaa07b378vboxsync#endif /* IN_RING3 */
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync/**
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Port I/O Handler for OUT operations.
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @returns VBox status code.
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param pDevIns The device instance.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param pvUser User argument.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param Port Port number used for the IN operation.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param u32 The value to output.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param cb The value size in bytes.
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsyncPDMBOTHCBDECL(int) parallelIOPortWrite(PPDMDEVINS pDevIns, void *pvUser,
c74832c7184337c330041742d88e6dacaa07b378vboxsync RTIOPORT Port, uint32_t u32, unsigned cb)
c74832c7184337c330041742d88e6dacaa07b378vboxsync{
c74832c7184337c330041742d88e6dacaa07b378vboxsync ParallelState *pData = PDMINS2DATA(pDevIns, ParallelState *);
c74832c7184337c330041742d88e6dacaa07b378vboxsync int rc = VINF_SUCCESS;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync if (cb == 1)
c74832c7184337c330041742d88e6dacaa07b378vboxsync {
c74832c7184337c330041742d88e6dacaa07b378vboxsync rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_IOPORT_WRITE);
c74832c7184337c330041742d88e6dacaa07b378vboxsync if (rc == VINF_SUCCESS)
c74832c7184337c330041742d88e6dacaa07b378vboxsync {
c74832c7184337c330041742d88e6dacaa07b378vboxsync Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, u32));
c74832c7184337c330041742d88e6dacaa07b378vboxsync rc = parallel_ioport_write (pData, Port, u32);
c74832c7184337c330041742d88e6dacaa07b378vboxsync PDMCritSectLeave(&pData->CritSect);
c74832c7184337c330041742d88e6dacaa07b378vboxsync }
c74832c7184337c330041742d88e6dacaa07b378vboxsync }
c74832c7184337c330041742d88e6dacaa07b378vboxsync else
c74832c7184337c330041742d88e6dacaa07b378vboxsync AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync return rc;
c74832c7184337c330041742d88e6dacaa07b378vboxsync}
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync/**
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Port I/O Handler for IN operations.
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @returns VBox status code.
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param pDevIns The device instance.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param pvUser User argument.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param Port Port number used for the IN operation.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param u32 The value to output.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param cb The value size in bytes.
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsyncPDMBOTHCBDECL(int) parallelIOPortRead(PPDMDEVINS pDevIns, void *pvUser,
c74832c7184337c330041742d88e6dacaa07b378vboxsync RTIOPORT Port, uint32_t *pu32, unsigned cb)
c74832c7184337c330041742d88e6dacaa07b378vboxsync{
c74832c7184337c330041742d88e6dacaa07b378vboxsync ParallelState *pData = PDMINS2DATA(pDevIns, ParallelState *);
c74832c7184337c330041742d88e6dacaa07b378vboxsync int rc = VINF_SUCCESS;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync if (cb == 1)
c74832c7184337c330041742d88e6dacaa07b378vboxsync {
c74832c7184337c330041742d88e6dacaa07b378vboxsync rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_IOPORT_READ);
c74832c7184337c330041742d88e6dacaa07b378vboxsync if (rc == VINF_SUCCESS)
c74832c7184337c330041742d88e6dacaa07b378vboxsync {
c74832c7184337c330041742d88e6dacaa07b378vboxsync *pu32 = parallel_ioport_read (pData, Port, &rc);
c74832c7184337c330041742d88e6dacaa07b378vboxsync Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, *pu32));
c74832c7184337c330041742d88e6dacaa07b378vboxsync PDMCritSectLeave(&pData->CritSect);
c74832c7184337c330041742d88e6dacaa07b378vboxsync }
c74832c7184337c330041742d88e6dacaa07b378vboxsync }
c74832c7184337c330041742d88e6dacaa07b378vboxsync else
c74832c7184337c330041742d88e6dacaa07b378vboxsync rc = VERR_IOM_IOPORT_UNUSED;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync return rc;
c74832c7184337c330041742d88e6dacaa07b378vboxsync}
c74832c7184337c330041742d88e6dacaa07b378vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#if 0
4fbca3751fe239da5934c23a783c3422618336e8vboxsync/**
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * Port I/O Handler for OUT operations on ECP registers.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync *
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @returns VBox status code.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync *
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @param pDevIns The device instance.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @param pvUser User argument.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @param Port Port number used for the IN operation.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @param u32 The value to output.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @param cb The value size in bytes.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync */
4fbca3751fe239da5934c23a783c3422618336e8vboxsyncPDMBOTHCBDECL(int) parallelIOPortWriteECP(PPDMDEVINS pDevIns, void *pvUser,
4fbca3751fe239da5934c23a783c3422618336e8vboxsync RTIOPORT Port, uint32_t u32, unsigned cb)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync{
4fbca3751fe239da5934c23a783c3422618336e8vboxsync ParallelState *pData = PDMINS2DATA(pDevIns, ParallelState *);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync int rc = VINF_SUCCESS;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (cb == 1)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync {
4fbca3751fe239da5934c23a783c3422618336e8vboxsync rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_IOPORT_WRITE);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (rc == VINF_SUCCESS)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync {
4fbca3751fe239da5934c23a783c3422618336e8vboxsync Log2(("%s: ecp port %#06x val %#04x\n", __FUNCTION__, Port, u32));
4fbca3751fe239da5934c23a783c3422618336e8vboxsync rc = parallel_ioport_write_ecp (pData, Port, u32);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync PDMCritSectLeave(&pData->CritSect);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync }
4fbca3751fe239da5934c23a783c3422618336e8vboxsync }
4fbca3751fe239da5934c23a783c3422618336e8vboxsync else
4fbca3751fe239da5934c23a783c3422618336e8vboxsync AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync return rc;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync}
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync/**
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * Port I/O Handler for IN operations on ECP registers.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync *
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @returns VBox status code.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync *
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @param pDevIns The device instance.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @param pvUser User argument.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @param Port Port number used for the IN operation.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @param u32 The value to output.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @param cb The value size in bytes.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync */
4fbca3751fe239da5934c23a783c3422618336e8vboxsyncPDMBOTHCBDECL(int) parallelIOPortReadECP(PPDMDEVINS pDevIns, void *pvUser,
4fbca3751fe239da5934c23a783c3422618336e8vboxsync RTIOPORT Port, uint32_t *pu32, unsigned cb)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync{
4fbca3751fe239da5934c23a783c3422618336e8vboxsync ParallelState *pData = PDMINS2DATA(pDevIns, ParallelState *);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync int rc = VINF_SUCCESS;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (cb == 1)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync {
4fbca3751fe239da5934c23a783c3422618336e8vboxsync rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_IOPORT_READ);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (rc == VINF_SUCCESS)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync {
4fbca3751fe239da5934c23a783c3422618336e8vboxsync *pu32 = parallel_ioport_read_ecp (pData, Port, &rc);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync Log2(("%s: ecp port %#06x val %#04x\n", __FUNCTION__, Port, *pu32));
4fbca3751fe239da5934c23a783c3422618336e8vboxsync PDMCritSectLeave(&pData->CritSect);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync }
4fbca3751fe239da5934c23a783c3422618336e8vboxsync }
4fbca3751fe239da5934c23a783c3422618336e8vboxsync else
4fbca3751fe239da5934c23a783c3422618336e8vboxsync rc = VERR_IOM_IOPORT_UNUSED;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync return rc;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync}
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#endif
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync#ifdef IN_RING3
c74832c7184337c330041742d88e6dacaa07b378vboxsync/**
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Saves a state of the serial port device.
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @returns VBox status code.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param pDevIns The device instance.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param pSSMHandle The handle to save the state to.
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsyncstatic DECLCALLBACK(int) parallelSaveExec(PPDMDEVINS pDevIns,
c74832c7184337c330041742d88e6dacaa07b378vboxsync PSSMHANDLE pSSMHandle)
c74832c7184337c330041742d88e6dacaa07b378vboxsync{
c74832c7184337c330041742d88e6dacaa07b378vboxsync ParallelState *pData = PDMINS2DATA(pDevIns, ParallelState *);
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync SSMR3PutU8(pSSMHandle, pData->reg_data);
c74832c7184337c330041742d88e6dacaa07b378vboxsync SSMR3PutU8(pSSMHandle, pData->reg_status);
c74832c7184337c330041742d88e6dacaa07b378vboxsync SSMR3PutU8(pSSMHandle, pData->reg_control);
c74832c7184337c330041742d88e6dacaa07b378vboxsync SSMR3PutS32(pSSMHandle, pData->irq);
c74832c7184337c330041742d88e6dacaa07b378vboxsync SSMR3PutU32(pSSMHandle, pData->base);
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync return SSMR3PutU32(pSSMHandle, ~0); /* sanity/terminator */
c74832c7184337c330041742d88e6dacaa07b378vboxsync}
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync/**
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Loads a saved serial port device state.
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @returns VBox status code.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param pDevIns The device instance.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param pSSMHandle The handle to the saved state.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param u32Version The data unit version number.
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsyncstatic DECLCALLBACK(int) parallelLoadExec(PPDMDEVINS pDevIns,
c74832c7184337c330041742d88e6dacaa07b378vboxsync PSSMHANDLE pSSMHandle,
c74832c7184337c330041742d88e6dacaa07b378vboxsync uint32_t u32Version)
c74832c7184337c330041742d88e6dacaa07b378vboxsync{
c74832c7184337c330041742d88e6dacaa07b378vboxsync int rc;
c74832c7184337c330041742d88e6dacaa07b378vboxsync uint32_t u32;
c74832c7184337c330041742d88e6dacaa07b378vboxsync ParallelState *pData = PDMINS2DATA(pDevIns, ParallelState *);
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync if (u32Version != PARALLEL_SAVED_STATE_VERSION)
c74832c7184337c330041742d88e6dacaa07b378vboxsync {
c74832c7184337c330041742d88e6dacaa07b378vboxsync AssertMsgFailed(("u32Version=%d\n", u32Version));
c74832c7184337c330041742d88e6dacaa07b378vboxsync return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
c74832c7184337c330041742d88e6dacaa07b378vboxsync }
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync SSMR3GetU8(pSSMHandle, &pData->reg_data);
c74832c7184337c330041742d88e6dacaa07b378vboxsync SSMR3GetU8(pSSMHandle, &pData->reg_status);
c74832c7184337c330041742d88e6dacaa07b378vboxsync SSMR3GetU8(pSSMHandle, &pData->reg_control);
c74832c7184337c330041742d88e6dacaa07b378vboxsync SSMR3GetS32(pSSMHandle, &pData->irq);
c74832c7184337c330041742d88e6dacaa07b378vboxsync SSMR3GetU32(pSSMHandle, &pData->base);
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync rc = SSMR3GetU32(pSSMHandle, &u32);
c74832c7184337c330041742d88e6dacaa07b378vboxsync if (VBOX_FAILURE(rc))
c74832c7184337c330041742d88e6dacaa07b378vboxsync return rc;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync if (u32 != ~0U)
c74832c7184337c330041742d88e6dacaa07b378vboxsync {
c74832c7184337c330041742d88e6dacaa07b378vboxsync AssertMsgFailed(("u32=%#x expected ~0\n", u32));
c74832c7184337c330041742d88e6dacaa07b378vboxsync return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
c74832c7184337c330041742d88e6dacaa07b378vboxsync }
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync pData->pDevInsHC = pDevIns;
c74832c7184337c330041742d88e6dacaa07b378vboxsync pData->pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
c74832c7184337c330041742d88e6dacaa07b378vboxsync return VINF_SUCCESS;
c74832c7184337c330041742d88e6dacaa07b378vboxsync}
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync/**
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @copydoc FNPDMDEVRELOCATE
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsyncstatic DECLCALLBACK(void) parallelRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
c74832c7184337c330041742d88e6dacaa07b378vboxsync{
c74832c7184337c330041742d88e6dacaa07b378vboxsync ParallelState *pData = PDMINS2DATA(pDevIns, ParallelState *);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync pData->pDevInsGC += offDelta;
c74832c7184337c330041742d88e6dacaa07b378vboxsync}
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync/** @copyfrom PIBASE::pfnqueryInterface */
c74832c7184337c330041742d88e6dacaa07b378vboxsyncstatic DECLCALLBACK(void *) parallelQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
c74832c7184337c330041742d88e6dacaa07b378vboxsync{
c74832c7184337c330041742d88e6dacaa07b378vboxsync ParallelState *pData = PDMIBASE_2_PARALLELSTATE(pInterface);
c74832c7184337c330041742d88e6dacaa07b378vboxsync switch (enmInterface)
c74832c7184337c330041742d88e6dacaa07b378vboxsync {
c74832c7184337c330041742d88e6dacaa07b378vboxsync case PDMINTERFACE_BASE:
c74832c7184337c330041742d88e6dacaa07b378vboxsync return &pData->IBase;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync case PDMINTERFACE_HOST_PARALLEL_PORT:
4fbca3751fe239da5934c23a783c3422618336e8vboxsync return &pData->IHostParallelPort;
c74832c7184337c330041742d88e6dacaa07b378vboxsync default:
c74832c7184337c330041742d88e6dacaa07b378vboxsync return NULL;
c74832c7184337c330041742d88e6dacaa07b378vboxsync }
c74832c7184337c330041742d88e6dacaa07b378vboxsync}
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync/**
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Destruct a device instance.
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Most VM resources are freed by the VM. This callback is provided so that any non-VM
c74832c7184337c330041742d88e6dacaa07b378vboxsync * resources can be freed correctly.
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @returns VBox status.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param pDevIns The device instance data.
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsyncstatic DECLCALLBACK(int) parallelDestruct(PPDMDEVINS pDevIns)
c74832c7184337c330041742d88e6dacaa07b378vboxsync{
c74832c7184337c330041742d88e6dacaa07b378vboxsync ParallelState *pData = PDMINS2DATA(pDevIns, ParallelState *);
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync PDMR3CritSectDelete(&pData->CritSect);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync return VINF_SUCCESS;
c74832c7184337c330041742d88e6dacaa07b378vboxsync}
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync/**
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Construct a device instance for a VM.
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @returns VBox status.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param pDevIns The device instance data.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * If the registration structure is needed, pDevIns->pDevReg points to it.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param iInstance Instance number. Use this to figure out which registers and such to use.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * The device number is also found in pDevIns->iInstance, but since it's
c74832c7184337c330041742d88e6dacaa07b378vboxsync * likely to be freqently used PDM passes it as parameter.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
c74832c7184337c330041742d88e6dacaa07b378vboxsync * of the device instance. It's also found in pDevIns->pCfgHandle, but like
c74832c7184337c330041742d88e6dacaa07b378vboxsync * iInstance it's expected to be used a bit in this function.
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsyncstatic DECLCALLBACK(int) parallelConstruct(PPDMDEVINS pDevIns,
c74832c7184337c330041742d88e6dacaa07b378vboxsync int iInstance,
c74832c7184337c330041742d88e6dacaa07b378vboxsync PCFGMNODE pCfgHandle)
c74832c7184337c330041742d88e6dacaa07b378vboxsync{
c74832c7184337c330041742d88e6dacaa07b378vboxsync int rc;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync ParallelState *pData = PDMINS2DATA(pDevIns, ParallelState*);
c74832c7184337c330041742d88e6dacaa07b378vboxsync uint16_t io_base;
c74832c7184337c330041742d88e6dacaa07b378vboxsync uint8_t irq_lvl;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync Assert(iInstance < 4);
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync pData->pDevInsHC = pDevIns;
c74832c7184337c330041742d88e6dacaa07b378vboxsync pData->pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync /*
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Validate configuration.
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsync if (!CFGMR3AreValuesValid(pCfgHandle, "IRQ\0IOBase\0"))
4fbca3751fe239da5934c23a783c3422618336e8vboxsync return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
4fbca3751fe239da5934c23a783c3422618336e8vboxsync N_("Configuration error: Unknown config key"));
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync rc = CFGMR3QueryBool(pCfgHandle, "GCEnabled", &pData->fGCEnabled);
c74832c7184337c330041742d88e6dacaa07b378vboxsync if (rc == VERR_CFGM_VALUE_NOT_FOUND)
c74832c7184337c330041742d88e6dacaa07b378vboxsync pData->fGCEnabled = true;
c74832c7184337c330041742d88e6dacaa07b378vboxsync else if (VBOX_FAILURE(rc))
c74832c7184337c330041742d88e6dacaa07b378vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
c74832c7184337c330041742d88e6dacaa07b378vboxsync N_("Configuration error: Failed to get the \"GCEnabled\" value"));
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync rc = CFGMR3QueryBool(pCfgHandle, "R0Enabled", &pData->fR0Enabled);
c74832c7184337c330041742d88e6dacaa07b378vboxsync if (rc == VERR_CFGM_VALUE_NOT_FOUND)
c74832c7184337c330041742d88e6dacaa07b378vboxsync pData->fR0Enabled = true;
c74832c7184337c330041742d88e6dacaa07b378vboxsync else if (VBOX_FAILURE(rc))
c74832c7184337c330041742d88e6dacaa07b378vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
c74832c7184337c330041742d88e6dacaa07b378vboxsync N_("Configuration error: Failed to get the \"R0Enabled\" value"));
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* IBase */
c74832c7184337c330041742d88e6dacaa07b378vboxsync pData->IBase.pfnQueryInterface = parallelQueryInterface;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /* IHostParallelPort */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync pData->IHostParallelPort.pfnNotifyInterrupt = parallelNotifyInterrupt;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync rc = RTSemEventCreate(&pData->ReceiveSem);
c74832c7184337c330041742d88e6dacaa07b378vboxsync AssertRC(rc);
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync /*
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Initialize critical section.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * This must of course be done before attaching drivers or anything else which can call us back..
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsync char szName[24];
c74832c7184337c330041742d88e6dacaa07b378vboxsync RTStrPrintf(szName, sizeof(szName), "Parallel#%d", iInstance);
c74832c7184337c330041742d88e6dacaa07b378vboxsync rc = PDMDevHlpCritSectInit(pDevIns, &pData->CritSect, szName);
c74832c7184337c330041742d88e6dacaa07b378vboxsync if (VBOX_FAILURE(rc))
c74832c7184337c330041742d88e6dacaa07b378vboxsync return rc;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync rc = CFGMR3QueryU8(pCfgHandle, "IRQ", &irq_lvl);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (rc == VERR_CFGM_VALUE_NOT_FOUND)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync irq_lvl = 7;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync else if (VBOX_FAILURE(rc))
4fbca3751fe239da5934c23a783c3422618336e8vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
4fbca3751fe239da5934c23a783c3422618336e8vboxsync N_("Configuration error: Failed to get the \"IRQ\" value"));
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync rc = CFGMR3QueryU16(pCfgHandle, "IOBase", &io_base);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (rc == VERR_CFGM_VALUE_NOT_FOUND)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync io_base = 0x378;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync else if (VBOX_FAILURE(rc))
4fbca3751fe239da5934c23a783c3422618336e8vboxsync return PDMDEV_SET_ERROR(pDevIns, rc,
4fbca3751fe239da5934c23a783c3422618336e8vboxsync N_("Configuration error: Failed to get the \"IOBase\" value"));
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync Log(("parallelConstruct instance %d iobase=%04x irq=%d\n", iInstance, io_base, irq_lvl));
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync pData->irq = irq_lvl;
c74832c7184337c330041742d88e6dacaa07b378vboxsync pData->base = io_base;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /* Init parallel state */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync pData->reg_data = 0;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync pData->reg_ecp_ecr = LPT_ECP_ECR_CHIPMODE_COMPAT | LPT_ECP_ECR_FIFO_EMPTY;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync pData->act_fifo_pos_read = 0;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync pData->act_fifo_pos_write = 0;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync rc = PDMDevHlpIOPortRegister(pDevIns, io_base, 8, 0,
c74832c7184337c330041742d88e6dacaa07b378vboxsync parallelIOPortWrite, parallelIOPortRead,
c74832c7184337c330041742d88e6dacaa07b378vboxsync NULL, NULL, "PARALLEL");
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (VBOX_FAILURE(rc))
c74832c7184337c330041742d88e6dacaa07b378vboxsync return rc;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#if 0
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /* register ecp registers */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync rc = PDMDevHlpIOPortRegister(pDevIns, io_base+0x400, 8, 0,
4fbca3751fe239da5934c23a783c3422618336e8vboxsync parallelIOPortWriteECP, parallelIOPortReadECP,
4fbca3751fe239da5934c23a783c3422618336e8vboxsync NULL, NULL, "PARALLEL ECP");
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (VBOX_FAILURE(rc))
4fbca3751fe239da5934c23a783c3422618336e8vboxsync return rc;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#endif
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync if (pData->fGCEnabled)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync {
c74832c7184337c330041742d88e6dacaa07b378vboxsync rc = PDMDevHlpIOPortRegisterGC(pDevIns, io_base, 8, 0, "parallelIOPortWrite",
c74832c7184337c330041742d88e6dacaa07b378vboxsync "parallelIOPortRead", NULL, NULL, "Parallel");
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (VBOX_FAILURE(rc))
4fbca3751fe239da5934c23a783c3422618336e8vboxsync return rc;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#if 0
4fbca3751fe239da5934c23a783c3422618336e8vboxsync rc = PDMDevHlpIOPortRegisterGC(pDevIns, io_base+0x400, 8, 0, "parallelIOPortWriteECP",
4fbca3751fe239da5934c23a783c3422618336e8vboxsync "parallelIOPortReadECP", NULL, NULL, "Parallel Ecp");
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (VBOX_FAILURE(rc))
4fbca3751fe239da5934c23a783c3422618336e8vboxsync return rc;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#endif
4fbca3751fe239da5934c23a783c3422618336e8vboxsync }
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync if (pData->fR0Enabled)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync {
c74832c7184337c330041742d88e6dacaa07b378vboxsync rc = PDMDevHlpIOPortRegisterR0(pDevIns, io_base, 8, 0, "parallelIOPortWrite",
c74832c7184337c330041742d88e6dacaa07b378vboxsync "parallelIOPortRead", NULL, NULL, "Parallel");
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (VBOX_FAILURE(rc))
4fbca3751fe239da5934c23a783c3422618336e8vboxsync return rc;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#if 0
4fbca3751fe239da5934c23a783c3422618336e8vboxsync rc = PDMDevHlpIOPortRegisterR0(pDevIns, io_base+0x400, 8, 0, "parallelIOPortWriteECP",
4fbca3751fe239da5934c23a783c3422618336e8vboxsync "parallelIOPortReadECP", NULL, NULL, "Parallel Ecp");
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (VBOX_FAILURE(rc))
4fbca3751fe239da5934c23a783c3422618336e8vboxsync return rc;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#endif
4fbca3751fe239da5934c23a783c3422618336e8vboxsync }
c74832c7184337c330041742d88e6dacaa07b378vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /* Attach the parallel port driver and get the interfaces. For now no run-time
c74832c7184337c330041742d88e6dacaa07b378vboxsync * changes are supported. */
c74832c7184337c330041742d88e6dacaa07b378vboxsync rc = PDMDevHlpDriverAttach(pDevIns, 0, &pData->IBase, &pData->pDrvBase, "Parallel Host");
c74832c7184337c330041742d88e6dacaa07b378vboxsync if (VBOX_SUCCESS(rc))
c74832c7184337c330041742d88e6dacaa07b378vboxsync {
4fbca3751fe239da5934c23a783c3422618336e8vboxsync pData->pDrvHostParallelConnector = (PDMIHOSTPARALLELCONNECTOR *)pData->pDrvBase->pfnQueryInterface(pData->pDrvBase,
4fbca3751fe239da5934c23a783c3422618336e8vboxsync PDMINTERFACE_HOST_PARALLEL_CONNECTOR);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (!pData->pDrvHostParallelConnector)
c74832c7184337c330041742d88e6dacaa07b378vboxsync {
4fbca3751fe239da5934c23a783c3422618336e8vboxsync AssertMsgFailed(("Configuration error: instance %d has no host parallel interface!\n", iInstance));
c74832c7184337c330041742d88e6dacaa07b378vboxsync return VERR_PDM_MISSING_INTERFACE;
c74832c7184337c330041742d88e6dacaa07b378vboxsync }
c74832c7184337c330041742d88e6dacaa07b378vboxsync /** @todo provide read notification interface!!!! */
c74832c7184337c330041742d88e6dacaa07b378vboxsync }
c74832c7184337c330041742d88e6dacaa07b378vboxsync else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
c74832c7184337c330041742d88e6dacaa07b378vboxsync {
c74832c7184337c330041742d88e6dacaa07b378vboxsync pData->pDrvBase = NULL;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync pData->pDrvHostParallelConnector = NULL;
c74832c7184337c330041742d88e6dacaa07b378vboxsync LogRel(("Parallel%d: no unit\n", iInstance));
c74832c7184337c330041742d88e6dacaa07b378vboxsync }
c74832c7184337c330041742d88e6dacaa07b378vboxsync else
c74832c7184337c330041742d88e6dacaa07b378vboxsync {
c74832c7184337c330041742d88e6dacaa07b378vboxsync AssertMsgFailed(("Parallel%d: Failed to attach to host driver. rc=%Vrc\n", iInstance, rc));
c74832c7184337c330041742d88e6dacaa07b378vboxsync return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
c74832c7184337c330041742d88e6dacaa07b378vboxsync N_("Parallel device %d cannot attach to host driver\n"), iInstance);
c74832c7184337c330041742d88e6dacaa07b378vboxsync }
c74832c7184337c330041742d88e6dacaa07b378vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /** Set compatibility mode */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync pData->pDrvHostParallelConnector->pfnSetMode(pData->pDrvHostParallelConnector, PDM_PARALLEL_PORT_MODE_COMPAT);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /** Get status of control register */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync pData->pDrvHostParallelConnector->pfnReadControl(pData->pDrvHostParallelConnector, &pData->reg_control);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync rc = PDMDevHlpSSMRegister(
c74832c7184337c330041742d88e6dacaa07b378vboxsync pDevIns, /* pDevIns */
c74832c7184337c330041742d88e6dacaa07b378vboxsync pDevIns->pDevReg->szDeviceName, /* pszName */
c74832c7184337c330041742d88e6dacaa07b378vboxsync iInstance, /* u32Instance */
c74832c7184337c330041742d88e6dacaa07b378vboxsync PARALLEL_SAVED_STATE_VERSION, /* u32Version */
c74832c7184337c330041742d88e6dacaa07b378vboxsync sizeof (*pData), /* cbGuess */
c74832c7184337c330041742d88e6dacaa07b378vboxsync NULL, /* pfnSavePrep */
c74832c7184337c330041742d88e6dacaa07b378vboxsync parallelSaveExec, /* pfnSaveExec */
c74832c7184337c330041742d88e6dacaa07b378vboxsync NULL, /* pfnSaveDone */
c74832c7184337c330041742d88e6dacaa07b378vboxsync NULL, /* pfnLoadPrep */
c74832c7184337c330041742d88e6dacaa07b378vboxsync parallelLoadExec, /* pfnLoadExec */
c74832c7184337c330041742d88e6dacaa07b378vboxsync NULL /* pfnLoadDone */
c74832c7184337c330041742d88e6dacaa07b378vboxsync );
c74832c7184337c330041742d88e6dacaa07b378vboxsync if (VBOX_FAILURE(rc))
c74832c7184337c330041742d88e6dacaa07b378vboxsync return rc;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync return VINF_SUCCESS;
c74832c7184337c330041742d88e6dacaa07b378vboxsync}
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync/**
c74832c7184337c330041742d88e6dacaa07b378vboxsync * The device registration structure.
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsyncconst PDMDEVREG g_DeviceParallelPort =
c74832c7184337c330041742d88e6dacaa07b378vboxsync{
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* u32Version */
c74832c7184337c330041742d88e6dacaa07b378vboxsync PDM_DEVREG_VERSION,
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* szDeviceName */
c74832c7184337c330041742d88e6dacaa07b378vboxsync "parallel",
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* szGCMod */
c74832c7184337c330041742d88e6dacaa07b378vboxsync "VBoxDDGC.gc",
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* szR0Mod */
c74832c7184337c330041742d88e6dacaa07b378vboxsync "VBoxDDR0.r0",
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* pszDescription */
c74832c7184337c330041742d88e6dacaa07b378vboxsync "Parallel Communication Port",
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* fFlags */
c74832c7184337c330041742d88e6dacaa07b378vboxsync PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GC | PDM_DEVREG_FLAGS_R0,
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* fClass */
c74832c7184337c330041742d88e6dacaa07b378vboxsync PDM_DEVREG_CLASS_PARALLEL,
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* cMaxInstances */
c74832c7184337c330041742d88e6dacaa07b378vboxsync 1,
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* cbInstance */
c74832c7184337c330041742d88e6dacaa07b378vboxsync sizeof(ParallelState),
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* pfnConstruct */
c74832c7184337c330041742d88e6dacaa07b378vboxsync parallelConstruct,
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* pfnDestruct */
c74832c7184337c330041742d88e6dacaa07b378vboxsync parallelDestruct,
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* pfnRelocate */
c74832c7184337c330041742d88e6dacaa07b378vboxsync parallelRelocate,
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* pfnIOCtl */
c74832c7184337c330041742d88e6dacaa07b378vboxsync NULL,
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* pfnPowerOn */
c74832c7184337c330041742d88e6dacaa07b378vboxsync NULL,
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* pfnReset */
c74832c7184337c330041742d88e6dacaa07b378vboxsync NULL,
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* pfnSuspend */
c74832c7184337c330041742d88e6dacaa07b378vboxsync NULL,
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* pfnResume */
c74832c7184337c330041742d88e6dacaa07b378vboxsync NULL,
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* pfnAttach */
c74832c7184337c330041742d88e6dacaa07b378vboxsync NULL,
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* pfnDetach */
c74832c7184337c330041742d88e6dacaa07b378vboxsync NULL,
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* pfnQueryInterface. */
c74832c7184337c330041742d88e6dacaa07b378vboxsync NULL
c74832c7184337c330041742d88e6dacaa07b378vboxsync};
c74832c7184337c330041742d88e6dacaa07b378vboxsync#endif /* IN_RING3 */
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */