DevParallel.cpp revision f5e53763b0a581b0299e98028c6c52192eb06785
956a0e3c076406b83d635174a201fd8761ee5133vboxsync/* $Id$ */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync/** @file
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * DevParallel - Parallel (Port) Device Emulation.
956a0e3c076406b83d635174a201fd8761ee5133vboxsync *
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * Contributed by: Alexander Eichner
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * Based on DevSerial.cpp
956a0e3c076406b83d635174a201fd8761ee5133vboxsync */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync/*
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * Copyright (C) 2006-2007 Oracle Corporation
956a0e3c076406b83d635174a201fd8761ee5133vboxsync *
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * available from http://www.virtualbox.org. This file is free software;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * you can redistribute it and/or modify it under the terms of the GNU
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * General Public License (GPL) as published by the Free Software
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
956a0e3c076406b83d635174a201fd8761ee5133vboxsync */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync/*******************************************************************************
956a0e3c076406b83d635174a201fd8761ee5133vboxsync* Header Files *
956a0e3c076406b83d635174a201fd8761ee5133vboxsync*******************************************************************************/
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LOG_GROUP LOG_GROUP_DEV_PARALLEL
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#include <VBox/vmm/pdmdev.h>
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#include <iprt/assert.h>
68fb2428898c55a7172e6a75a0a8d7ce259919bdvboxsync#include <iprt/uuid.h>
68fb2428898c55a7172e6a75a0a8d7ce259919bdvboxsync#include <iprt/string.h>
68fb2428898c55a7172e6a75a0a8d7ce259919bdvboxsync#include <iprt/semaphore.h>
68fb2428898c55a7172e6a75a0a8d7ce259919bdvboxsync#include <iprt/critsect.h>
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#include "VBoxDD.h"
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync/*******************************************************************************
956a0e3c076406b83d635174a201fd8761ee5133vboxsync* Defined Constants And Macros *
956a0e3c076406b83d635174a201fd8761ee5133vboxsync*******************************************************************************/
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define PARALLEL_SAVED_STATE_VERSION 1
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync/* defines for accessing the register bits */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_STATUS_BUSY 0x80
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_STATUS_ACK 0x40
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_STATUS_PAPER_OUT 0x20
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_STATUS_SELECT_IN 0x10
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_STATUS_ERROR 0x08
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_STATUS_IRQ 0x04
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_STATUS_BIT1 0x02 /* reserved (only for completeness) */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_STATUS_EPP_TIMEOUT 0x01
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_CONTROL_BIT7 0x80 /* reserved (only for completeness) */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_CONTROL_BIT6 0x40 /* reserved (only for completeness) */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_CONTROL_ENABLE_BIDIRECT 0x20
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_CONTROL_ENABLE_IRQ_VIA_ACK 0x10
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_CONTROL_SELECT_PRINTER 0x08
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_CONTROL_RESET 0x04
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_CONTROL_AUTO_LINEFEED 0x02
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_CONTROL_STROBE 0x01
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync/** mode defines for the extended control register */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_ECP_ECR_CHIPMODE_MASK 0xe0
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_ECP_ECR_CHIPMODE_GET_BITS(reg) ((reg) >> 5)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_ECP_ECR_CHIPMODE_SET_BITS(val) ((val) << 5)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_ECP_ECR_CHIPMODE_CONFIGURATION 0x07
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_ECP_ECR_CHIPMODE_FIFO_TEST 0x06
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_ECP_ECR_CHIPMODE_RESERVED 0x05
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_ECP_ECR_CHIPMODE_EPP 0x04
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_ECP_ECR_CHIPMODE_ECP_FIFO 0x03
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_ECP_ECR_CHIPMODE_PP_FIFO 0x02
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_ECP_ECR_CHIPMODE_BYTE 0x01
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_ECP_ECR_CHIPMODE_COMPAT 0x00
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync/** FIFO status bits in extended control register */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_ECP_ECR_FIFO_MASK 0x03
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_ECP_ECR_FIFO_SOME_DATA 0x00
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_ECP_ECR_FIFO_FULL 0x02
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_ECP_ECR_FIFO_EMPTY 0x01
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_ECP_CONFIGA_FIFO_WITDH_MASK 0x70
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_ECP_CONFIGA_FIFO_WIDTH_GET_BITS(reg) ((reg) >> 4)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_ECP_CONFIGA_FIFO_WIDTH_SET_BITS(val) ((val) << 4)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_ECP_CONFIGA_FIFO_WIDTH_16 0x00
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_ECP_CONFIGA_FIFO_WIDTH_32 0x20
68fb2428898c55a7172e6a75a0a8d7ce259919bdvboxsync#define LPT_ECP_CONFIGA_FIFO_WIDTH_8 0x10
68fb2428898c55a7172e6a75a0a8d7ce259919bdvboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define LPT_ECP_FIFO_DEPTH 2
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync/*******************************************************************************
956a0e3c076406b83d635174a201fd8761ee5133vboxsync* Structures and Typedefs *
956a0e3c076406b83d635174a201fd8761ee5133vboxsync*******************************************************************************/
68fb2428898c55a7172e6a75a0a8d7ce259919bdvboxsync/**
68fb2428898c55a7172e6a75a0a8d7ce259919bdvboxsync * Parallel device state.
956a0e3c076406b83d635174a201fd8761ee5133vboxsync *
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * @implements PDMIBASE
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * @implements PDMIHOSTPARALLELPORT
956a0e3c076406b83d635174a201fd8761ee5133vboxsync */
68fb2428898c55a7172e6a75a0a8d7ce259919bdvboxsynctypedef struct ParallelState
68fb2428898c55a7172e6a75a0a8d7ce259919bdvboxsync{
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /** Access critical section. */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync PDMCRITSECT CritSect;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /** Pointer to the device instance - R3 Ptr */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync PPDMDEVINSR3 pDevInsR3;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /** Pointer to the device instance - R0 Ptr */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync PPDMDEVINSR0 pDevInsR0;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /** Pointer to the device instance - RC Ptr */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync PPDMDEVINSRC pDevInsRC;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync RTRCPTR Alignment0; /**< Alignment. */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /** LUN\#0: The base interface. */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync PDMIBASE IBase;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /** LUN\#0: The host device port interface. */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync PDMIHOSTPARALLELPORT IHostParallelPort;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /** Pointer to the attached base driver. */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync R3PTRTYPE(PPDMIBASE) pDrvBase;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /** Pointer to the attached host device. */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync R3PTRTYPE(PPDMIHOSTPARALLELCONNECTOR) pDrvHostParallelConnector;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /** Unused event semaphore... */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync RTSEMEVENT ReceiveSem;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync uint8_t reg_data;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync uint8_t reg_status;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync uint8_t reg_control;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync uint8_t reg_epp_addr;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync uint8_t reg_epp_data;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync uint8_t reg_ecp_ecr;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync uint8_t reg_ecp_base_plus_400h; /* has different meanings */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync uint8_t reg_ecp_config_b;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /** The ECP FIFO implementation*/
956a0e3c076406b83d635174a201fd8761ee5133vboxsync uint8_t ecp_fifo[LPT_ECP_FIFO_DEPTH];
956a0e3c076406b83d635174a201fd8761ee5133vboxsync uint8_t abAlignemnt[2];
956a0e3c076406b83d635174a201fd8761ee5133vboxsync int act_fifo_pos_write;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync int act_fifo_pos_read;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync int irq;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync uint8_t epp_timeout;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync bool fGCEnabled;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync bool fR0Enabled;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync bool afAlignment[1];
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync uint32_t base;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync} DEVPARALLELSTATE, *PDEVPARALLELSTATE;
956a0e3c076406b83d635174a201fd8761ee5133vboxsynctypedef DEVPARALLELSTATE ParallelState;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#ifndef VBOX_DEVICE_STRUCT_TESTCASE
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define PDMIHOSTPARALLELPORT_2_PARALLELSTATE(pInstance) ( (ParallelState *)((uintptr_t)(pInterface) - RT_OFFSETOF(ParallelState, IHostParallelPort)) )
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define PDMIHOSTDEVICEPORT_2_PARALLELSTATE(pInstance) ( (ParallelState *)((uintptr_t)(pInterface) - RT_OFFSETOF(ParallelState, IHostDevicePort)) )
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#define PDMIBASE_2_PARALLELSTATE(pInstance) ( (ParallelState *)((uintptr_t)(pInterface) - RT_OFFSETOF(ParallelState, IBase)) )
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync/*******************************************************************************
956a0e3c076406b83d635174a201fd8761ee5133vboxsync* Internal Functions *
956a0e3c076406b83d635174a201fd8761ee5133vboxsync*******************************************************************************/
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncRT_C_DECLS_BEGIN
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncPDMBOTHCBDECL(int) parallelIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncPDMBOTHCBDECL(int) parallelIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#if 0
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncPDMBOTHCBDECL(int) parallelIOPortReadECP(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncPDMBOTHCBDECL(int) parallelIOPortWriteECP(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#endif
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncRT_C_DECLS_END
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#ifdef IN_RING3
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncstatic void parallel_set_irq(ParallelState *s)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync{
956a0e3c076406b83d635174a201fd8761ee5133vboxsync if (s->reg_control & LPT_CONTROL_ENABLE_IRQ_VIA_ACK)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync {
956a0e3c076406b83d635174a201fd8761ee5133vboxsync Log(("parallel_update_irq %d 1\n", s->irq));
956a0e3c076406b83d635174a201fd8761ee5133vboxsync PDMDevHlpISASetIrqNoWait(s->CTX_SUFF(pDevIns), s->irq, 1);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync }
956a0e3c076406b83d635174a201fd8761ee5133vboxsync}
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncstatic void parallel_clear_irq(ParallelState *s)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync{
956a0e3c076406b83d635174a201fd8761ee5133vboxsync Log(("parallel_update_irq %d 0\n", s->irq));
956a0e3c076406b83d635174a201fd8761ee5133vboxsync PDMDevHlpISASetIrqNoWait(s->CTX_SUFF(pDevIns), s->irq, 0);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync}
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#endif
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncstatic int parallel_ioport_write(void *opaque, uint32_t addr, uint32_t val)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync{
956a0e3c076406b83d635174a201fd8761ee5133vboxsync ParallelState *s = (ParallelState *)opaque;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync unsigned char ch;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync addr &= 7;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync LogFlow(("parallel: write addr=0x%02x val=0x%02x\n", addr, val));
956a0e3c076406b83d635174a201fd8761ee5133vboxsync ch = val;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync switch(addr) {
956a0e3c076406b83d635174a201fd8761ee5133vboxsync default:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 0:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#ifndef IN_RING3
956a0e3c076406b83d635174a201fd8761ee5133vboxsync NOREF(ch);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync return VINF_IOM_HC_IOPORT_WRITE;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#else
956a0e3c076406b83d635174a201fd8761ee5133vboxsync s->reg_data = ch;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync if (RT_LIKELY(s->pDrvHostParallelConnector))
956a0e3c076406b83d635174a201fd8761ee5133vboxsync {
956a0e3c076406b83d635174a201fd8761ee5133vboxsync Log(("parallel_io_port_write: write 0x%X\n", ch));
956a0e3c076406b83d635174a201fd8761ee5133vboxsync size_t cbWrite = 1;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync int rc = s->pDrvHostParallelConnector->pfnWrite(s->pDrvHostParallelConnector, &ch, &cbWrite);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertRC(rc);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync }
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#endif
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 1:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 2:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /* Set the reserved bits to one */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync ch |= (LPT_CONTROL_BIT6 | LPT_CONTROL_BIT7);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync if (ch != s->reg_control) {
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#ifndef IN_RING3
956a0e3c076406b83d635174a201fd8761ee5133vboxsync return VINF_IOM_HC_IOPORT_WRITE;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#else
956a0e3c076406b83d635174a201fd8761ee5133vboxsync int rc = s->pDrvHostParallelConnector->pfnWriteControl(s->pDrvHostParallelConnector, ch);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertRC(rc);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync s->reg_control = val;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#endif
956a0e3c076406b83d635174a201fd8761ee5133vboxsync }
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 3:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync s->reg_epp_addr = val;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 4:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync s->reg_epp_data = val;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 5:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 6:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 7:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync }
956a0e3c076406b83d635174a201fd8761ee5133vboxsync return VINF_SUCCESS;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync}
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncstatic uint32_t parallel_ioport_read(void *opaque, uint32_t addr, int *pRC)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync{
956a0e3c076406b83d635174a201fd8761ee5133vboxsync ParallelState *s = (ParallelState *)opaque;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync uint32_t ret = ~0U;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync *pRC = VINF_SUCCESS;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync addr &= 7;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync switch(addr) {
956a0e3c076406b83d635174a201fd8761ee5133vboxsync default:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 0:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync if (!(s->reg_control & LPT_CONTROL_ENABLE_BIDIRECT))
956a0e3c076406b83d635174a201fd8761ee5133vboxsync ret = s->reg_data;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync else
956a0e3c076406b83d635174a201fd8761ee5133vboxsync {
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#ifndef IN_RING3
956a0e3c076406b83d635174a201fd8761ee5133vboxsync *pRC = VINF_IOM_HC_IOPORT_READ;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#else
956a0e3c076406b83d635174a201fd8761ee5133vboxsync if (RT_LIKELY(s->pDrvHostParallelConnector))
956a0e3c076406b83d635174a201fd8761ee5133vboxsync {
956a0e3c076406b83d635174a201fd8761ee5133vboxsync size_t cbRead;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync int rc = s->pDrvHostParallelConnector->pfnRead(s->pDrvHostParallelConnector, &s->reg_data, &cbRead);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync Log(("parallel_io_port_read: read 0x%X\n", s->reg_data));
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertRC(rc);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync }
956a0e3c076406b83d635174a201fd8761ee5133vboxsync ret = s->reg_data;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#endif
956a0e3c076406b83d635174a201fd8761ee5133vboxsync }
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 1:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#ifndef IN_RING3
956a0e3c076406b83d635174a201fd8761ee5133vboxsync *pRC = VINF_IOM_HC_IOPORT_READ;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#else
956a0e3c076406b83d635174a201fd8761ee5133vboxsync if (RT_LIKELY(s->pDrvHostParallelConnector))
956a0e3c076406b83d635174a201fd8761ee5133vboxsync {
956a0e3c076406b83d635174a201fd8761ee5133vboxsync int rc = s->pDrvHostParallelConnector->pfnReadStatus(s->pDrvHostParallelConnector, &s->reg_status);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertRC(rc);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync }
956a0e3c076406b83d635174a201fd8761ee5133vboxsync ret = s->reg_status;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync parallel_clear_irq(s);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#endif
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 2:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync ret = s->reg_control;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 3:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync ret = s->reg_epp_addr;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 4:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync ret = s->reg_epp_data;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 5:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 6:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 7:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync }
956a0e3c076406b83d635174a201fd8761ee5133vboxsync LogFlow(("parallel: read addr=0x%02x val=0x%02x\n", addr, ret));
956a0e3c076406b83d635174a201fd8761ee5133vboxsync return ret;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync}
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#if 0
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncstatic int parallel_ioport_write_ecp(void *opaque, uint32_t addr, uint32_t val)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync{
956a0e3c076406b83d635174a201fd8761ee5133vboxsync ParallelState *s = (ParallelState *)opaque;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync unsigned char ch;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync addr &= 7;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync LogFlow(("parallel: write ecp addr=0x%02x val=0x%02x\n", addr, val));
956a0e3c076406b83d635174a201fd8761ee5133vboxsync ch = val;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync switch(addr) {
956a0e3c076406b83d635174a201fd8761ee5133vboxsync default:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 0:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync if (LPT_ECP_ECR_CHIPMODE_GET_BITS(s->reg_ecp_ecr) == LPT_ECP_ECR_CHIPMODE_FIFO_TEST) {
956a0e3c076406b83d635174a201fd8761ee5133vboxsync s->ecp_fifo[s->act_fifo_pos_write] = ch;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync s->act_fifo_pos_write++;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync if (s->act_fifo_pos_write < LPT_ECP_FIFO_DEPTH) {
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /* FIFO has some data (clear both FIFO bits) */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync s->reg_ecp_ecr &= ~(LPT_ECP_ECR_FIFO_EMPTY | LPT_ECP_ECR_FIFO_FULL);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync } else {
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /* FIFO is full */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /* Clear FIFO empty bit */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync s->reg_ecp_ecr &= ~LPT_ECP_ECR_FIFO_EMPTY;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /* Set FIFO full bit */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync s->reg_ecp_ecr |= LPT_ECP_ECR_FIFO_FULL;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync s->act_fifo_pos_write = 0;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync }
956a0e3c076406b83d635174a201fd8761ee5133vboxsync } else {
956a0e3c076406b83d635174a201fd8761ee5133vboxsync s->reg_ecp_base_plus_400h = ch;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync }
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 1:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync s->reg_ecp_config_b = ch;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 2:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /* If we change the mode clear FIFO */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync if ((ch & LPT_ECP_ECR_CHIPMODE_MASK) != (s->reg_ecp_ecr & LPT_ECP_ECR_CHIPMODE_MASK)) {
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /* reset the fifo */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync s->act_fifo_pos_write = 0;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync s->act_fifo_pos_read = 0;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /* Set FIFO empty bit */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync s->reg_ecp_ecr |= LPT_ECP_ECR_FIFO_EMPTY;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /* Clear FIFO full bit */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync s->reg_ecp_ecr &= ~LPT_ECP_ECR_FIFO_FULL;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync }
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /* Set new mode */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync s->reg_ecp_ecr |= LPT_ECP_ECR_CHIPMODE_SET_BITS(LPT_ECP_ECR_CHIPMODE_GET_BITS(ch));
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 3:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 4:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 5:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 6:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 7:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync }
956a0e3c076406b83d635174a201fd8761ee5133vboxsync return VINF_SUCCESS;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync}
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncstatic uint32_t parallel_ioport_read_ecp(void *opaque, uint32_t addr, int *pRC)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync{
956a0e3c076406b83d635174a201fd8761ee5133vboxsync ParallelState *s = (ParallelState *)opaque;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync uint32_t ret = ~0U;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync *pRC = VINF_SUCCESS;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync addr &= 7;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync switch(addr) {
956a0e3c076406b83d635174a201fd8761ee5133vboxsync default:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 0:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync if (LPT_ECP_ECR_CHIPMODE_GET_BITS(s->reg_ecp_ecr) == LPT_ECP_ECR_CHIPMODE_FIFO_TEST) {
956a0e3c076406b83d635174a201fd8761ee5133vboxsync ret = s->ecp_fifo[s->act_fifo_pos_read];
956a0e3c076406b83d635174a201fd8761ee5133vboxsync s->act_fifo_pos_read++;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync if (s->act_fifo_pos_read == LPT_ECP_FIFO_DEPTH)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync s->act_fifo_pos_read = 0; /* end of FIFO, start at beginning */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync if (s->act_fifo_pos_read == s->act_fifo_pos_write) {
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /* FIFO is empty */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /* Set FIFO empty bit */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync s->reg_ecp_ecr |= LPT_ECP_ECR_FIFO_EMPTY;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /* Clear FIFO full bit */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync s->reg_ecp_ecr &= ~LPT_ECP_ECR_FIFO_FULL;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync } else {
956a0e3c076406b83d635174a201fd8761ee5133vboxsync /* FIFO has some data (clear all FIFO bits) */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync s->reg_ecp_ecr &= ~(LPT_ECP_ECR_FIFO_EMPTY | LPT_ECP_ECR_FIFO_FULL);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync }
956a0e3c076406b83d635174a201fd8761ee5133vboxsync } else {
956a0e3c076406b83d635174a201fd8761ee5133vboxsync ret = s->reg_ecp_base_plus_400h;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync }
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 1:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync ret = s->reg_ecp_config_b;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 2:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync ret = s->reg_ecp_ecr;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 3:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 4:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 5:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 6:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync case 7:
956a0e3c076406b83d635174a201fd8761ee5133vboxsync break;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync }
956a0e3c076406b83d635174a201fd8761ee5133vboxsync LogFlow(("parallel: read ecp addr=0x%02x val=0x%02x\n", addr, ret));
956a0e3c076406b83d635174a201fd8761ee5133vboxsync return ret;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync}
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#endif
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#ifdef IN_RING3
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncstatic DECLCALLBACK(int) parallelNotifyInterrupt(PPDMIHOSTPARALLELPORT pInterface)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync{
956a0e3c076406b83d635174a201fd8761ee5133vboxsync ParallelState *pThis = PDMIHOSTPARALLELPORT_2_PARALLELSTATE(pInterface);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync PDMCritSectEnter(&pThis->CritSect, VINF_SUCCESS);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync parallel_set_irq(pThis);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync PDMCritSectLeave(&pThis->CritSect);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync return VINF_SUCCESS;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync}
956a0e3c076406b83d635174a201fd8761ee5133vboxsync#endif /* IN_RING3 */
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync/**
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * Port I/O Handler for OUT operations.
956a0e3c076406b83d635174a201fd8761ee5133vboxsync *
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * @returns VBox status code.
956a0e3c076406b83d635174a201fd8761ee5133vboxsync *
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * @param pDevIns The device instance.
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * @param pvUser User argument.
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * @param Port Port number used for the IN operation.
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * @param u32 The value to output.
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * @param cb The value size in bytes.
956a0e3c076406b83d635174a201fd8761ee5133vboxsync */
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncPDMBOTHCBDECL(int) parallelIOPortWrite(PPDMDEVINS pDevIns, void *pvUser,
956a0e3c076406b83d635174a201fd8761ee5133vboxsync RTIOPORT Port, uint32_t u32, unsigned cb)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync{
956a0e3c076406b83d635174a201fd8761ee5133vboxsync ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync int rc = VINF_SUCCESS;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync if (cb == 1)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync {
956a0e3c076406b83d635174a201fd8761ee5133vboxsync rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_WRITE);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync if (rc == VINF_SUCCESS)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync {
956a0e3c076406b83d635174a201fd8761ee5133vboxsync Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, u32));
956a0e3c076406b83d635174a201fd8761ee5133vboxsync rc = parallel_ioport_write (pThis, Port, u32);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync PDMCritSectLeave(&pThis->CritSect);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync }
956a0e3c076406b83d635174a201fd8761ee5133vboxsync }
956a0e3c076406b83d635174a201fd8761ee5133vboxsync else
956a0e3c076406b83d635174a201fd8761ee5133vboxsync AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync return rc;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync}
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync/**
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * Port I/O Handler for IN operations.
956a0e3c076406b83d635174a201fd8761ee5133vboxsync *
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * @returns VBox status code.
956a0e3c076406b83d635174a201fd8761ee5133vboxsync *
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * @param pDevIns The device instance.
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * @param pvUser User argument.
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * @param Port Port number used for the IN operation.
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * @param pu32 Where to return the read value.
956a0e3c076406b83d635174a201fd8761ee5133vboxsync * @param cb The value size in bytes.
956a0e3c076406b83d635174a201fd8761ee5133vboxsync */
956a0e3c076406b83d635174a201fd8761ee5133vboxsyncPDMBOTHCBDECL(int) parallelIOPortRead(PPDMDEVINS pDevIns, void *pvUser,
956a0e3c076406b83d635174a201fd8761ee5133vboxsync RTIOPORT Port, uint32_t *pu32, unsigned cb)
956a0e3c076406b83d635174a201fd8761ee5133vboxsync{
68fb2428898c55a7172e6a75a0a8d7ce259919bdvboxsync ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
956a0e3c076406b83d635174a201fd8761ee5133vboxsync int rc = VINF_SUCCESS;
956a0e3c076406b83d635174a201fd8761ee5133vboxsync
956a0e3c076406b83d635174a201fd8761ee5133vboxsync if (cb == 1)
{
rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_READ);
if (rc == VINF_SUCCESS)
{
*pu32 = parallel_ioport_read (pThis, Port, &rc);
Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, *pu32));
PDMCritSectLeave(&pThis->CritSect);
}
}
else
rc = VERR_IOM_IOPORT_UNUSED;
return rc;
}
#if 0
/**
* Port I/O Handler for OUT operations on ECP registers.
*
* @returns VBox status code.
*
* @param pDevIns The device instance.
* @param pvUser User argument.
* @param Port Port number used for the IN operation.
* @param u32 The value to output.
* @param cb The value size in bytes.
*/
PDMBOTHCBDECL(int) parallelIOPortWriteECP(PPDMDEVINS pDevIns, void *pvUser,
RTIOPORT Port, uint32_t u32, unsigned cb)
{
ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
int rc = VINF_SUCCESS;
if (cb == 1)
{
rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_WRITE);
if (rc == VINF_SUCCESS)
{
Log2(("%s: ecp port %#06x val %#04x\n", __FUNCTION__, Port, u32));
rc = parallel_ioport_write_ecp (pThis, Port, u32);
PDMCritSectLeave(&pThis->CritSect);
}
}
else
AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
return rc;
}
/**
* Port I/O Handler for IN operations on ECP registers.
*
* @returns VBox status code.
*
* @param pDevIns The device instance.
* @param pvUser User argument.
* @param Port Port number used for the IN operation.
* @param u32 The value to output.
* @param cb The value size in bytes.
*/
PDMBOTHCBDECL(int) parallelIOPortReadECP(PPDMDEVINS pDevIns, void *pvUser,
RTIOPORT Port, uint32_t *pu32, unsigned cb)
{
ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
int rc = VINF_SUCCESS;
if (cb == 1)
{
rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_READ);
if (rc == VINF_SUCCESS)
{
*pu32 = parallel_ioport_read_ecp (pThis, Port, &rc);
Log2(("%s: ecp port %#06x val %#04x\n", __FUNCTION__, Port, *pu32));
PDMCritSectLeave(&pThis->CritSect);
}
}
else
rc = VERR_IOM_IOPORT_UNUSED;
return rc;
}
#endif
#ifdef IN_RING3
/**
* @copydoc FNSSMDEVLIVEEXEC
*/
static DECLCALLBACK(int) parallelLiveExec(PPDMDEVINS pDevIns,
PSSMHANDLE pSSM,
uint32_t uPass)
{
ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
SSMR3PutS32(pSSM, pThis->irq);
SSMR3PutU32(pSSM, pThis->base);
SSMR3PutU32(pSSM, ~0); /* sanity/terminator */
return VINF_SSM_DONT_CALL_AGAIN;
}
/**
* @copydoc FNSSMDEVSAVEEXEC
*/
static DECLCALLBACK(int) parallelSaveExec(PPDMDEVINS pDevIns,
PSSMHANDLE pSSM)
{
ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
SSMR3PutU8(pSSM, pThis->reg_data);
SSMR3PutU8(pSSM, pThis->reg_status);
SSMR3PutU8(pSSM, pThis->reg_control);
parallelLiveExec(pDevIns, pSSM, 0);
return VINF_SUCCESS;
}
/**
* @copydoc FNSSMDEVLOADEXEC
*/
static DECLCALLBACK(int) parallelLoadExec(PPDMDEVINS pDevIns,
PSSMHANDLE pSSM,
uint32_t uVersion,
uint32_t uPass)
{
ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
AssertMsgReturn(uVersion == PARALLEL_SAVED_STATE_VERSION, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
if (uPass == SSM_PASS_FINAL)
{
SSMR3GetU8(pSSM, &pThis->reg_data);
SSMR3GetU8(pSSM, &pThis->reg_status);
SSMR3GetU8(pSSM, &pThis->reg_control);
}
/* the config */
int32_t iIrq;
SSMR3GetS32(pSSM, &iIrq);
uint32_t uIoBase;
SSMR3GetU32(pSSM, &uIoBase);
uint32_t u32;
int rc = SSMR3GetU32(pSSM, &u32);
if (RT_FAILURE(rc))
return rc;
AssertMsgReturn(u32 == ~0U, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
if (pThis->irq != iIrq)
return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("IRQ changed: config=%#x state=%#x"), pThis->irq, iIrq);
if (pThis->base != uIoBase)
return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("IOBase changed: config=%#x state=%#x"), pThis->base, uIoBase);
/* not necessary... but it doesn't harm. */
pThis->pDevInsR3 = pDevIns;
pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
return VINF_SUCCESS;
}
/**
* @copydoc FNPDMDEVRELOCATE
*/
static DECLCALLBACK(void) parallelRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
{
ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
pThis->pDevInsRC += offDelta;
}
/**
* @interface_method_impl{PDMIBASE,pfnQueryInterface}
*/
static DECLCALLBACK(void *) parallelQueryInterface(PPDMIBASE pInterface, const char *pszIID)
{
ParallelState *pThis = PDMIBASE_2_PARALLELSTATE(pInterface);
PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTPARALLELPORT, &pThis->IHostParallelPort);
return NULL;
}
/**
* Destruct a device instance.
*
* Most VM resources are freed by the VM. This callback is provided so that any non-VM
* resources can be freed correctly.
*
* @returns VBox status.
* @param pDevIns The device instance data.
*/
static DECLCALLBACK(int) parallelDestruct(PPDMDEVINS pDevIns)
{
ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
PDMR3CritSectDelete(&pThis->CritSect);
RTSemEventDestroy(pThis->ReceiveSem);
return VINF_SUCCESS;
}
/**
* @interface_method_impl{PDMDEVREG,pfnConstruct}
*/
static DECLCALLBACK(int) parallelConstruct(PPDMDEVINS pDevIns,
int iInstance,
PCFGMNODE pCfg)
{
int rc;
ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState*);
Assert(iInstance < 4);
PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
/*
* Init the data so parallelDestruct doesn't choke.
*/
pThis->pDevInsR3 = pDevIns;
pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
pThis->ReceiveSem = NIL_RTSEMEVENT;
/* IBase */
pThis->IBase.pfnQueryInterface = parallelQueryInterface;
/* IHostParallelPort */
pThis->IHostParallelPort.pfnNotifyInterrupt = parallelNotifyInterrupt;
/* Init parallel state */
pThis->reg_data = 0;
pThis->reg_ecp_ecr = LPT_ECP_ECR_CHIPMODE_COMPAT | LPT_ECP_ECR_FIFO_EMPTY;
pThis->act_fifo_pos_read = 0;
pThis->act_fifo_pos_write = 0;
/*
* Validate and read the configuration.
*/
if (!CFGMR3AreValuesValid(pCfg, "IRQ\0" "IOBase\0" "GCEnabled\0" "R0Enabled\0"))
return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
N_("Configuration error: Unknown config key"));
rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fGCEnabled, true);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to get the \"GCEnabled\" value"));
rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, true);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to get the \"R0Enabled\" value"));
uint8_t irq_lvl;
rc = CFGMR3QueryU8Def(pCfg, "IRQ", &irq_lvl, 7);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to get the \"IRQ\" value"));
uint16_t io_base;
rc = CFGMR3QueryU16Def(pCfg, "IOBase", &io_base, 0x378);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Failed to get the \"IOBase\" value"));
Log(("parallelConstruct instance %d iobase=%04x irq=%d\n", iInstance, io_base, irq_lvl));
pThis->irq = irq_lvl;
pThis->base = io_base;
/*
* Initialize critical section and event semaphore.
* This must of course be done before attaching drivers or anything else which can call us back..
*/
rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "Parallel#%d", iInstance);
if (RT_FAILURE(rc))
return rc;
rc = RTSemEventCreate(&pThis->ReceiveSem);
if (RT_FAILURE(rc))
return rc;
/*
* Register the I/O ports and saved state.
*/
rc = PDMDevHlpIOPortRegister(pDevIns, io_base, 8, 0,
parallelIOPortWrite, parallelIOPortRead,
NULL, NULL, "PARALLEL");
if (RT_FAILURE(rc))
return rc;
#if 0
/* register ecp registers */
rc = PDMDevHlpIOPortRegister(pDevIns, io_base+0x400, 8, 0,
parallelIOPortWriteECP, parallelIOPortReadECP,
NULL, NULL, "PARALLEL ECP");
if (RT_FAILURE(rc))
return rc;
#endif
if (pThis->fGCEnabled)
{
rc = PDMDevHlpIOPortRegisterRC(pDevIns, io_base, 8, 0, "parallelIOPortWrite",
"parallelIOPortRead", NULL, NULL, "Parallel");
if (RT_FAILURE(rc))
return rc;
#if 0
rc = PDMDevHlpIOPortRegisterGC(pDevIns, io_base+0x400, 8, 0, "parallelIOPortWriteECP",
"parallelIOPortReadECP", NULL, NULL, "Parallel Ecp");
if (RT_FAILURE(rc))
return rc;
#endif
}
if (pThis->fR0Enabled)
{
rc = PDMDevHlpIOPortRegisterR0(pDevIns, io_base, 8, 0, "parallelIOPortWrite",
"parallelIOPortRead", NULL, NULL, "Parallel");
if (RT_FAILURE(rc))
return rc;
#if 0
rc = PDMDevHlpIOPortRegisterR0(pDevIns, io_base+0x400, 8, 0, "parallelIOPortWriteECP",
"parallelIOPortReadECP", NULL, NULL, "Parallel Ecp");
if (RT_FAILURE(rc))
return rc;
#endif
}
rc = PDMDevHlpSSMRegister3(pDevIns, PARALLEL_SAVED_STATE_VERSION, sizeof(*pThis),
parallelLiveExec, parallelSaveExec, parallelLoadExec);
if (RT_FAILURE(rc))
return rc;
/*
* Attach the parallel port driver and get the interfaces.
* For now no run-time changes are supported.
*/
rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Parallel Host");
if (RT_SUCCESS(rc))
{
pThis->pDrvHostParallelConnector = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIHOSTPARALLELCONNECTOR);
AssertMsgReturn(pThis->pDrvHostParallelConnector,
("Configuration error: instance %d has no host parallel interface!\n", iInstance),
VERR_PDM_MISSING_INTERFACE);
/** @todo provide read notification interface!!!! */
}
else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
{
pThis->pDrvBase = NULL;
pThis->pDrvHostParallelConnector = NULL;
LogRel(("Parallel%d: no unit\n", iInstance));
}
else
{
AssertMsgFailed(("Parallel%d: Failed to attach to host driver. rc=%Rrc\n", iInstance, rc));
return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
N_("Parallel device %d cannot attach to host driver"), iInstance);
}
/* Set compatibility mode */
pThis->pDrvHostParallelConnector->pfnSetMode(pThis->pDrvHostParallelConnector, PDM_PARALLEL_PORT_MODE_COMPAT);
/* Get status of control register */
pThis->pDrvHostParallelConnector->pfnReadControl(pThis->pDrvHostParallelConnector, &pThis->reg_control);
return VINF_SUCCESS;
}
/**
* The device registration structure.
*/
const PDMDEVREG g_DeviceParallelPort =
{
/* u32Version */
PDM_DEVREG_VERSION,
/* szName */
"parallel",
/* szRCMod */
"VBoxDDGC.gc",
/* szR0Mod */
"VBoxDDR0.r0",
/* pszDescription */
"Parallel Communication Port",
/* fFlags */
PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
/* fClass */
PDM_DEVREG_CLASS_PARALLEL,
/* cMaxInstances */
1,
/* cbInstance */
sizeof(ParallelState),
/* pfnConstruct */
parallelConstruct,
/* pfnDestruct */
parallelDestruct,
/* pfnRelocate */
parallelRelocate,
/* pfnIOCtl */
NULL,
/* pfnPowerOn */
NULL,
/* pfnReset */
NULL,
/* pfnSuspend */
NULL,
/* pfnResume */
NULL,
/* pfnAttach */
NULL,
/* pfnDetach */
NULL,
/* pfnQueryInterface. */
NULL,
/* pfnInitComplete */
NULL,
/* pfnPowerOff */
NULL,
/* pfnSoftReset */
NULL,
/* u32VersionEnd */
PDM_DEVREG_VERSION
};
#endif /* IN_RING3 */
#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */