DevParallel.cpp revision 43747b1f0bc8302a238fb35e55857a5e9aa1933d
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * DevParallel - Parallel (Port) Device Emulation.
d192cc72774b02a0df2fdd46350d418236ac09aevboxsync * Contributed by: Alexander Eichner
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * Copyright (C) 2006-2007 Oracle Corporation
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* Header Files *
c74832c7184337c330041742d88e6dacaa07b378vboxsync*******************************************************************************/
a6e58d30b4d856cf924fda15cd743fed386fff93vboxsync/*******************************************************************************
a6e58d30b4d856cf924fda15cd743fed386fff93vboxsync* Defined Constants And Macros *
a6e58d30b4d856cf924fda15cd743fed386fff93vboxsync*******************************************************************************/
c74832c7184337c330041742d88e6dacaa07b378vboxsync/* defines for accessing the register bits */
c74832c7184337c330041742d88e6dacaa07b378vboxsync#define LPT_STATUS_BIT1 0x02 /* reserved (only for completeness) */
c74832c7184337c330041742d88e6dacaa07b378vboxsync#define LPT_CONTROL_BIT7 0x80 /* reserved (only for completeness) */
c74832c7184337c330041742d88e6dacaa07b378vboxsync#define LPT_CONTROL_BIT6 0x40 /* reserved (only for completeness) */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync/** mode defines for the extended control register */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define LPT_ECP_ECR_CHIPMODE_GET_BITS(reg) ((reg) >> 5)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define LPT_ECP_ECR_CHIPMODE_SET_BITS(val) ((val) << 5)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync/** FIFO status bits in extended control register */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define LPT_ECP_CONFIGA_FIFO_WIDTH_GET_BITS(reg) ((reg) >> 4)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define LPT_ECP_CONFIGA_FIFO_WIDTH_SET_BITS(val) ((val) << 4)
a6e58d30b4d856cf924fda15cd743fed386fff93vboxsync/*******************************************************************************
a6e58d30b4d856cf924fda15cd743fed386fff93vboxsync* Structures and Typedefs *
a6e58d30b4d856cf924fda15cd743fed386fff93vboxsync*******************************************************************************/
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * Parallel device state.
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * @implements PDMIBASE
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * @implements PDMIHOSTPARALLELPORT
c74832c7184337c330041742d88e6dacaa07b378vboxsync /** Access critical section. */
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync /** Pointer to the device instance - R3 Ptr */
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync /** Pointer to the device instance - R0 Ptr */
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync /** Pointer to the device instance - RC Ptr */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync /** LUN\#0: The base interface. */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync /** LUN\#0: The host device port interface. */
c74832c7184337c330041742d88e6dacaa07b378vboxsync /** Pointer to the attached base driver. */
c74832c7184337c330041742d88e6dacaa07b378vboxsync /** Pointer to the attached host device. */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync R3PTRTYPE(PPDMIHOSTPARALLELCONNECTOR) pDrvHostParallelConnector;
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync /** Unused event semaphore... */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync uint8_t reg_ecp_base_plus_400h; /* has different meanings */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /** The ECP FIFO implementation*/
a6e58d30b4d856cf924fda15cd743fed386fff93vboxsync#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)) )
a6e58d30b4d856cf924fda15cd743fed386fff93vboxsync#define PDMIBASE_2_PARALLELSTATE(pInstance) ( (ParallelState *)((uintptr_t)(pInterface) - RT_OFFSETOF(ParallelState, IBase)) )
a6e58d30b4d856cf924fda15cd743fed386fff93vboxsync/*******************************************************************************
a6e58d30b4d856cf924fda15cd743fed386fff93vboxsync* Internal Functions *
a6e58d30b4d856cf924fda15cd743fed386fff93vboxsync*******************************************************************************/
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);
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 if (s->reg_control & LPT_CONTROL_ENABLE_IRQ_VIA_ACK)
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync PDMDevHlpISASetIrqNoWait(s->CTX_SUFF(pDevIns), s->irq, 1);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync PDMDevHlpISASetIrqNoWait(s->CTX_SUFF(pDevIns), s->irq, 0);
c74832c7184337c330041742d88e6dacaa07b378vboxsyncstatic int parallel_ioport_write(void *opaque, uint32_t addr, uint32_t val)
c74832c7184337c330041742d88e6dacaa07b378vboxsync unsigned char ch;
c74832c7184337c330041742d88e6dacaa07b378vboxsync LogFlow(("parallel: write addr=0x%02x val=0x%02x\n", addr, val));
4fbca3751fe239da5934c23a783c3422618336e8vboxsync int rc = s->pDrvHostParallelConnector->pfnWrite(s->pDrvHostParallelConnector, &ch, &cbWrite);
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync /* Set the reserved bits to one */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync int rc = s->pDrvHostParallelConnector->pfnWriteControl(s->pDrvHostParallelConnector, ch);
c74832c7184337c330041742d88e6dacaa07b378vboxsyncstatic uint32_t parallel_ioport_read(void *opaque, uint32_t addr, int *pRC)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (!(s->reg_control & LPT_CONTROL_ENABLE_BIDIRECT))
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));
4fbca3751fe239da5934c23a783c3422618336e8vboxsync int rc = s->pDrvHostParallelConnector->pfnReadStatus(s->pDrvHostParallelConnector, &s->reg_status);
c74832c7184337c330041742d88e6dacaa07b378vboxsync LogFlow(("parallel: read addr=0x%02x val=0x%02x\n", addr, ret));
4fbca3751fe239da5934c23a783c3422618336e8vboxsyncstatic int parallel_ioport_write_ecp(void *opaque, uint32_t addr, uint32_t val)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync unsigned char ch;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync LogFlow(("parallel: write ecp addr=0x%02x val=0x%02x\n", addr, val));
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (LPT_ECP_ECR_CHIPMODE_GET_BITS(s->reg_ecp_ecr) == LPT_ECP_ECR_CHIPMODE_FIFO_TEST) {
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync /* FIFO has some data (clear both FIFO bits) */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync s->reg_ecp_ecr &= ~(LPT_ECP_ECR_FIFO_EMPTY | LPT_ECP_ECR_FIFO_FULL);
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync /* FIFO is full */
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync /* Clear FIFO empty bit */
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync /* Set FIFO full bit */
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync /* If we change the mode clear FIFO */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if ((ch & LPT_ECP_ECR_CHIPMODE_MASK) != (s->reg_ecp_ecr & LPT_ECP_ECR_CHIPMODE_MASK)) {
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync /* reset the fifo */
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync /* Set FIFO empty bit */
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync /* Clear FIFO full bit */
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync /* Set new mode */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync s->reg_ecp_ecr |= LPT_ECP_ECR_CHIPMODE_SET_BITS(LPT_ECP_ECR_CHIPMODE_GET_BITS(ch));
4fbca3751fe239da5934c23a783c3422618336e8vboxsyncstatic uint32_t parallel_ioport_read_ecp(void *opaque, uint32_t addr, int *pRC)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (LPT_ECP_ECR_CHIPMODE_GET_BITS(s->reg_ecp_ecr) == LPT_ECP_ECR_CHIPMODE_FIFO_TEST) {
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync s->act_fifo_pos_read = 0; /* end of FIFO, start at beginning */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (s->act_fifo_pos_read == s->act_fifo_pos_write) {
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync /* FIFO is empty */
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync /* Set FIFO empty bit */
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync /* Clear FIFO full bit */
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync /* FIFO has some data (clear all FIFO bits) */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync s->reg_ecp_ecr &= ~(LPT_ECP_ECR_FIFO_EMPTY | LPT_ECP_ECR_FIFO_FULL);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync LogFlow(("parallel: read ecp addr=0x%02x val=0x%02x\n", addr, ret));
4fbca3751fe239da5934c23a783c3422618336e8vboxsyncstatic DECLCALLBACK(int) parallelNotifyInterrupt(PPDMIHOSTPARALLELPORT pInterface)
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync ParallelState *pThis = PDMIHOSTPARALLELPORT_2_PARALLELSTATE(pInterface);
c74832c7184337c330041742d88e6dacaa07b378vboxsync#endif /* IN_RING3 */
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Port I/O Handler for OUT operations.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @returns VBox status code.
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.
c74832c7184337c330041742d88e6dacaa07b378vboxsyncPDMBOTHCBDECL(int) parallelIOPortWrite(PPDMDEVINS pDevIns, void *pvUser,
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_WRITE);
c74832c7184337c330041742d88e6dacaa07b378vboxsync Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, u32));
c74832c7184337c330041742d88e6dacaa07b378vboxsync AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Port I/O Handler for IN operations.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @returns VBox status code.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param pDevIns The device instance.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param pvUser User argument.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param Port Port number used for the IN operation.
d59a43b735abea2db17caa9b5661d2f5118f0e02vboxsync * @param pu32 Where to return the read value.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param cb The value size in bytes.
c74832c7184337c330041742d88e6dacaa07b378vboxsyncPDMBOTHCBDECL(int) parallelIOPortRead(PPDMDEVINS pDevIns, void *pvUser,
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_READ);
c74832c7184337c330041742d88e6dacaa07b378vboxsync Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, *pu32));
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * Port I/O Handler for OUT operations on ECP registers.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @returns VBox status code.
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.
4fbca3751fe239da5934c23a783c3422618336e8vboxsyncPDMBOTHCBDECL(int) parallelIOPortWriteECP(PPDMDEVINS pDevIns, void *pvUser,
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_WRITE);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync Log2(("%s: ecp port %#06x val %#04x\n", __FUNCTION__, Port, u32));
4fbca3751fe239da5934c23a783c3422618336e8vboxsync AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * Port I/O Handler for IN operations on ECP registers.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @returns VBox status code.
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.
4fbca3751fe239da5934c23a783c3422618336e8vboxsyncPDMBOTHCBDECL(int) parallelIOPortReadECP(PPDMDEVINS pDevIns, void *pvUser,
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_READ);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync *pu32 = parallel_ioport_read_ecp (pThis, Port, &rc);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync Log2(("%s: ecp port %#06x val %#04x\n", __FUNCTION__, Port, *pu32));
6b98f92a0c2c5dd90d8496ee553e5763c4debd49vboxsync * @copydoc FNSSMDEVLIVEEXEC
6b98f92a0c2c5dd90d8496ee553e5763c4debd49vboxsyncstatic DECLCALLBACK(int) parallelLiveExec(PPDMDEVINS pDevIns,
6b98f92a0c2c5dd90d8496ee553e5763c4debd49vboxsync ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
6b98f92a0c2c5dd90d8496ee553e5763c4debd49vboxsync * @copydoc FNSSMDEVSAVEEXEC
c74832c7184337c330041742d88e6dacaa07b378vboxsyncstatic DECLCALLBACK(int) parallelSaveExec(PPDMDEVINS pDevIns,
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
6b98f92a0c2c5dd90d8496ee553e5763c4debd49vboxsync * @copydoc FNSSMDEVLOADEXEC
c74832c7184337c330041742d88e6dacaa07b378vboxsyncstatic DECLCALLBACK(int) parallelLoadExec(PPDMDEVINS pDevIns,
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
b5d837811bf21f30a31748bbbcb28ee562bb2355vboxsync AssertMsgReturn(uVersion == PARALLEL_SAVED_STATE_VERSION, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
6b98f92a0c2c5dd90d8496ee553e5763c4debd49vboxsync /* the config */
b5d837811bf21f30a31748bbbcb28ee562bb2355vboxsync AssertMsgReturn(u32 == ~0U, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
e7925b345f17e5bd9f0c1cf3540b7d8573ec274fvboxsync return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("IRQ changed: config=%#x state=%#x"), pThis->irq, iIrq);
e7925b345f17e5bd9f0c1cf3540b7d8573ec274fvboxsync return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("IOBase changed: config=%#x state=%#x"), pThis->base, uIoBase);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync /* not necessary... but it doesn't harm. */
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @copydoc FNPDMDEVRELOCATE
c74832c7184337c330041742d88e6dacaa07b378vboxsyncstatic DECLCALLBACK(void) parallelRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * @interface_method_impl{PDMIBASE,pfnQueryInterface}
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsyncstatic DECLCALLBACK(void *) parallelQueryInterface(PPDMIBASE pInterface, const char *pszIID)
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync ParallelState *pThis = PDMIBASE_2_PARALLELSTATE(pInterface);
a39ea3668b7019c23a68936259545f9b71bce1aavboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
0db6a029780d9f9b347500e117320a8d5661efe5vboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTPARALLELPORT, &pThis->IHostParallelPort);
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Destruct a device instance.
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 * @returns VBox status.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param pDevIns The device instance data.
c74832c7184337c330041742d88e6dacaa07b378vboxsyncstatic DECLCALLBACK(int) parallelDestruct(PPDMDEVINS pDevIns)
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
cad8876b46f9e366c4a1007a40c27ca1df078950vboxsync * @interface_method_impl{PDMDEVREG,pfnConstruct}
c74832c7184337c330041742d88e6dacaa07b378vboxsyncstatic DECLCALLBACK(int) parallelConstruct(PPDMDEVINS pDevIns,
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState*);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * Init the data so parallelDestruct doesn't choke.
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* IBase */
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync pThis->IBase.pfnQueryInterface = parallelQueryInterface;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /* IHostParallelPort */
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync pThis->IHostParallelPort.pfnNotifyInterrupt = parallelNotifyInterrupt;
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync /* Init parallel state */
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync pThis->reg_ecp_ecr = LPT_ECP_ECR_CHIPMODE_COMPAT | LPT_ECP_ECR_FIFO_EMPTY;
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * Validate and read the configuration.
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync if (!CFGMR3AreValuesValid(pCfg, "IRQ\0" "IOBase\0" "GCEnabled\0" "R0Enabled\0"))
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fGCEnabled, true);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync N_("Configuration error: Failed to get the \"GCEnabled\" value"));
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, true);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync N_("Configuration error: Failed to get the \"R0Enabled\" value"));
4fbca3751fe239da5934c23a783c3422618336e8vboxsync N_("Configuration error: Failed to get the \"IRQ\" value"));
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync rc = CFGMR3QueryU16Def(pCfg, "IOBase", &io_base, 0x378);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync N_("Configuration error: Failed to get the \"IOBase\" value"));
c74832c7184337c330041742d88e6dacaa07b378vboxsync Log(("parallelConstruct instance %d iobase=%04x irq=%d\n", iInstance, io_base, irq_lvl));
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * Initialize critical section and event semaphore.
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * This must of course be done before attaching drivers or anything else which can call us back..
3e9c5c3e44de15c28695c7b570bc2551639187e3vboxsync rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "Parallel#%d", iInstance);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * Register the I/O ports and saved state.
c74832c7184337c330041742d88e6dacaa07b378vboxsync rc = PDMDevHlpIOPortRegister(pDevIns, io_base, 8, 0,
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /* register ecp registers */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync rc = PDMDevHlpIOPortRegister(pDevIns, io_base+0x400, 8, 0,
8b90eb0585fa16024709ca374c69f1eb5d5a5a7cvboxsync rc = PDMDevHlpIOPortRegisterRC(pDevIns, io_base, 8, 0, "parallelIOPortWrite",
4fbca3751fe239da5934c23a783c3422618336e8vboxsync rc = PDMDevHlpIOPortRegisterGC(pDevIns, io_base+0x400, 8, 0, "parallelIOPortWriteECP",
4fbca3751fe239da5934c23a783c3422618336e8vboxsync "parallelIOPortReadECP", NULL, NULL, "Parallel Ecp");
c74832c7184337c330041742d88e6dacaa07b378vboxsync rc = PDMDevHlpIOPortRegisterR0(pDevIns, io_base, 8, 0, "parallelIOPortWrite",
4fbca3751fe239da5934c23a783c3422618336e8vboxsync rc = PDMDevHlpIOPortRegisterR0(pDevIns, io_base+0x400, 8, 0, "parallelIOPortWriteECP",
4fbca3751fe239da5934c23a783c3422618336e8vboxsync "parallelIOPortReadECP", NULL, NULL, "Parallel Ecp");
6b98f92a0c2c5dd90d8496ee553e5763c4debd49vboxsync rc = PDMDevHlpSSMRegister3(pDevIns, PARALLEL_SAVED_STATE_VERSION, sizeof(*pThis),
6b98f92a0c2c5dd90d8496ee553e5763c4debd49vboxsync parallelLiveExec, parallelSaveExec, parallelLoadExec);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * Attach the parallel port driver and get the interfaces.
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * For now no run-time changes are supported.
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Parallel Host");
0db6a029780d9f9b347500e117320a8d5661efe5vboxsync pThis->pDrvHostParallelConnector = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIHOSTPARALLELCONNECTOR);
0db6a029780d9f9b347500e117320a8d5661efe5vboxsync ("Configuration error: instance %d has no host parallel interface!\n", iInstance),
c74832c7184337c330041742d88e6dacaa07b378vboxsync /** @todo provide read notification interface!!!! */
fe813b3594039ba864493438e78ee0e7132bc445vboxsync AssertMsgFailed(("Parallel%d: Failed to attach to host driver. rc=%Rrc\n", iInstance, rc));
c74832c7184337c330041742d88e6dacaa07b378vboxsync return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
a40c05ca69e15a5efdd0796ef52e26ec0b1bc4d2vboxsync N_("Parallel device %d cannot attach to host driver"), iInstance);
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync /* Set compatibility mode */
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync pThis->pDrvHostParallelConnector->pfnSetMode(pThis->pDrvHostParallelConnector, PDM_PARALLEL_PORT_MODE_COMPAT);
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync /* Get status of control register */
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync pThis->pDrvHostParallelConnector->pfnReadControl(pThis->pDrvHostParallelConnector, &pThis->reg_control);
c74832c7184337c330041742d88e6dacaa07b378vboxsync * The device registration structure.
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* u32Version */
2c8ee291fb75c4a6f05df160f5d67f4e9ef1cabcvboxsync /* szName */
c74832c7184337c330041742d88e6dacaa07b378vboxsync "parallel",
f01175bdcb5e36a1a89fca88f45d7ee7fb034ed6vboxsync /* szRCMod */
c74832c7184337c330041742d88e6dacaa07b378vboxsync "VBoxDDGC.gc",
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* szR0Mod */
c74832c7184337c330041742d88e6dacaa07b378vboxsync "VBoxDDR0.r0",
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* pszDescription */
c74832c7184337c330041742d88e6dacaa07b378vboxsync "Parallel Communication Port",
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* fFlags */
3cf2cf6eea0401233eece976db8cf31909f1f955vboxsync PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* fClass */
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* cMaxInstances */
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* cbInstance */
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* pfnConstruct */
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* pfnDestruct */
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* pfnRelocate */
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* pfnIOCtl */
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* pfnPowerOn */
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* pfnReset */
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* pfnSuspend */
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* pfnResume */
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* pfnAttach */
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* pfnDetach */
c74832c7184337c330041742d88e6dacaa07b378vboxsync /* pfnQueryInterface. */
f01175bdcb5e36a1a89fca88f45d7ee7fb034ed6vboxsync /* pfnInitComplete */
f01175bdcb5e36a1a89fca88f45d7ee7fb034ed6vboxsync /* pfnPowerOff */
f01175bdcb5e36a1a89fca88f45d7ee7fb034ed6vboxsync /* pfnSoftReset */
f01175bdcb5e36a1a89fca88f45d7ee7fb034ed6vboxsync /* u32VersionEnd */
c74832c7184337c330041742d88e6dacaa07b378vboxsync#endif /* IN_RING3 */
c74832c7184337c330041742d88e6dacaa07b378vboxsync#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */