VirtualBox

source: vbox/trunk/src/VBox/Devices/Parallel/DevParallel.cpp

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 29.8 KB
Line 
1/* $Id: DevParallel.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * DevParallel - Parallel (Port) Device Emulation.
4 *
5 * Contributed by: Alexander Eichner
6 * Based on DevSerial.cpp
7 */
8
9/*
10 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
11 *
12 * This file is part of VirtualBox base platform packages, as
13 * available from https://www.virtualbox.org.
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation, in version 3 of the
18 * License.
19 *
20 * This program is distributed in the hope that it will be useful, but
21 * WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, see <https://www.gnu.org/licenses>.
27 *
28 * SPDX-License-Identifier: GPL-3.0-only
29 */
30
31
32/*********************************************************************************************************************************
33* Header Files *
34*********************************************************************************************************************************/
35#define LOG_GROUP LOG_GROUP_DEV_PARALLEL
36#include <VBox/vmm/pdmdev.h>
37#include <VBox/AssertGuest.h>
38#include <iprt/assert.h>
39#include <iprt/uuid.h>
40#include <iprt/string.h>
41#include <iprt/semaphore.h>
42
43#include "VBoxDD.h"
44
45
46/*********************************************************************************************************************************
47* Defined Constants And Macros *
48*********************************************************************************************************************************/
49#define PARALLEL_SAVED_STATE_VERSION 1
50
51/* defines for accessing the register bits */
52#define LPT_STATUS_BUSY 0x80
53#define LPT_STATUS_ACK 0x40
54#define LPT_STATUS_PAPER_OUT 0x20
55#define LPT_STATUS_SELECT_IN 0x10
56#define LPT_STATUS_ERROR 0x08
57#define LPT_STATUS_IRQ 0x04
58#define LPT_STATUS_BIT1 0x02 /* reserved (only for completeness) */
59#define LPT_STATUS_EPP_TIMEOUT 0x01
60
61#define LPT_CONTROL_BIT7 0x80 /* reserved (only for completeness) */
62#define LPT_CONTROL_BIT6 0x40 /* reserved (only for completeness) */
63#define LPT_CONTROL_ENABLE_BIDIRECT 0x20
64#define LPT_CONTROL_ENABLE_IRQ_VIA_ACK 0x10
65#define LPT_CONTROL_SELECT_PRINTER 0x08
66#define LPT_CONTROL_RESET 0x04
67#define LPT_CONTROL_AUTO_LINEFEED 0x02
68#define LPT_CONTROL_STROBE 0x01
69
70/** mode defines for the extended control register */
71#define LPT_ECP_ECR_CHIPMODE_MASK 0xe0
72#define LPT_ECP_ECR_CHIPMODE_GET_BITS(reg) ((reg) >> 5)
73#define LPT_ECP_ECR_CHIPMODE_SET_BITS(val) ((val) << 5)
74#define LPT_ECP_ECR_CHIPMODE_CONFIGURATION 0x07
75#define LPT_ECP_ECR_CHIPMODE_FIFO_TEST 0x06
76#define LPT_ECP_ECR_CHIPMODE_RESERVED 0x05
77#define LPT_ECP_ECR_CHIPMODE_EPP 0x04
78#define LPT_ECP_ECR_CHIPMODE_ECP_FIFO 0x03
79#define LPT_ECP_ECR_CHIPMODE_PP_FIFO 0x02
80#define LPT_ECP_ECR_CHIPMODE_BYTE 0x01
81#define LPT_ECP_ECR_CHIPMODE_COMPAT 0x00
82
83/** FIFO status bits in extended control register */
84#define LPT_ECP_ECR_FIFO_MASK 0x03
85#define LPT_ECP_ECR_FIFO_SOME_DATA 0x00
86#define LPT_ECP_ECR_FIFO_FULL 0x02
87#define LPT_ECP_ECR_FIFO_EMPTY 0x01
88
89#define LPT_ECP_CONFIGA_FIFO_WITDH_MASK 0x70
90#define LPT_ECP_CONFIGA_FIFO_WIDTH_GET_BITS(reg) ((reg) >> 4)
91#define LPT_ECP_CONFIGA_FIFO_WIDTH_SET_BITS(val) ((val) << 4)
92#define LPT_ECP_CONFIGA_FIFO_WIDTH_16 0x00
93#define LPT_ECP_CONFIGA_FIFO_WIDTH_32 0x20
94#define LPT_ECP_CONFIGA_FIFO_WIDTH_8 0x10
95
96#define LPT_ECP_FIFO_DEPTH 2
97
98
99/*********************************************************************************************************************************
100* Structures and Typedefs *
101*********************************************************************************************************************************/
102/**
103 * The shared parallel device state.
104 */
105typedef struct PARALLELPORT
106{
107 /** Flag whether an EPP timeout occurred (error handling). */
108 bool fEppTimeout;
109 bool fAlignment1;
110 /** Base I/O port of the parallel port. */
111 RTIOPORT IOBase;
112 /** IRQ number assigned ot the parallel port. */
113 int32_t iIrq;
114 /** Data register. */
115 uint8_t regData;
116 /** Status register. */
117 uint8_t regStatus;
118 /** Control register. */
119 uint8_t regControl;
120 /** EPP address register. */
121 uint8_t regEppAddr;
122 /** EPP data register. */
123 uint8_t regEppData;
124 /** More alignment. */
125 uint8_t abAlignment2[3];
126
127#if 0 /* Data for ECP implementation, currently unused. */
128 uint8_t reg_ecp_ecr;
129 uint8_t reg_ecp_base_plus_400h; /* has different meanings */
130 uint8_t reg_ecp_config_b;
131
132 /** The ECP FIFO implementation*/
133 uint8_t ecp_fifo[LPT_ECP_FIFO_DEPTH];
134 uint8_t abAlignemnt[3];
135 int32_t act_fifo_pos_write;
136 int32_t act_fifo_pos_read;
137#endif
138 /** Handle to the regular I/O ports. */
139 IOMIOPORTHANDLE hIoPorts;
140 /** Handle to the ECP I/O ports. */
141 IOMIOPORTHANDLE hIoPortsEcp;
142} PARALLELPORT;
143/** Pointer to the shared parallel device state. */
144typedef PARALLELPORT *PPARALLELPORT;
145
146
147/**
148 * The parallel device state for ring-3.
149 *
150 * @implements PDMIBASE
151 * @implements PDMIHOSTPARALLELPORT
152 */
153typedef struct PARALLELPORTR3
154{
155 /** Pointer to the device instance.
156 * @note Only for getting our bearings when arriving here via an interface
157 * method. */
158 PPDMDEVINSR3 pDevIns;
159 /** LUN\#0: The base interface. */
160 PDMIBASE IBase;
161 /** LUN\#0: The host device port interface. */
162 PDMIHOSTPARALLELPORT IHostParallelPort;
163 /** Pointer to the attached base driver. */
164 R3PTRTYPE(PPDMIBASE) pDrvBase;
165 /** Pointer to the attached host device. */
166 R3PTRTYPE(PPDMIHOSTPARALLELCONNECTOR) pDrvHostParallelConnector;
167} PARALLELPORTR3;
168/** Pointer to the parallel device state for ring-3. */
169typedef PARALLELPORTR3 *PPARALLELPORTR3;
170
171
172#ifndef VBOX_DEVICE_STRUCT_TESTCASE /* Rest of file, does not count wrt indentation. */
173
174#ifdef IN_RING3
175
176static void parallelR3IrqSet(PPDMDEVINS pDevIns, PARALLELPORT *pThis)
177{
178 if (pThis->regControl & LPT_CONTROL_ENABLE_IRQ_VIA_ACK)
179 {
180 LogFlowFunc(("%d 1\n", pThis->iIrq));
181 PDMDevHlpISASetIrqNoWait(pDevIns, pThis->iIrq, 1);
182 }
183}
184
185static void parallelR3IrqClear(PPDMDEVINS pDevIns, PARALLELPORT *pThis)
186{
187 LogFlowFunc(("%d 0\n", pThis->iIrq));
188 PDMDevHlpISASetIrqNoWait(pDevIns, pThis->iIrq, 0);
189}
190
191#endif /* IN_RING3 */
192
193#if 0
194static int parallel_ioport_write_ecp(void *opaque, uint32_t addr, uint32_t val)
195{
196 PARALLELPORT *s = (PARALLELPORT *)opaque;
197 unsigned char ch;
198
199 addr &= 7;
200 LogFlow(("parallel: write ecp addr=0x%02x val=0x%02x\n", addr, val));
201 ch = val;
202 switch (addr) {
203 default:
204 case 0:
205 if (LPT_ECP_ECR_CHIPMODE_GET_BITS(s->reg_ecp_ecr) == LPT_ECP_ECR_CHIPMODE_FIFO_TEST) {
206 s->ecp_fifo[s->act_fifo_pos_write] = ch;
207 s->act_fifo_pos_write++;
208 if (s->act_fifo_pos_write < LPT_ECP_FIFO_DEPTH) {
209 /* FIFO has some data (clear both FIFO bits) */
210 s->reg_ecp_ecr &= ~(LPT_ECP_ECR_FIFO_EMPTY | LPT_ECP_ECR_FIFO_FULL);
211 } else {
212 /* FIFO is full */
213 /* Clear FIFO empty bit */
214 s->reg_ecp_ecr &= ~LPT_ECP_ECR_FIFO_EMPTY;
215 /* Set FIFO full bit */
216 s->reg_ecp_ecr |= LPT_ECP_ECR_FIFO_FULL;
217 s->act_fifo_pos_write = 0;
218 }
219 } else {
220 s->reg_ecp_base_plus_400h = ch;
221 }
222 break;
223 case 1:
224 s->reg_ecp_config_b = ch;
225 break;
226 case 2:
227 /* If we change the mode clear FIFO */
228 if ((ch & LPT_ECP_ECR_CHIPMODE_MASK) != (s->reg_ecp_ecr & LPT_ECP_ECR_CHIPMODE_MASK)) {
229 /* reset the fifo */
230 s->act_fifo_pos_write = 0;
231 s->act_fifo_pos_read = 0;
232 /* Set FIFO empty bit */
233 s->reg_ecp_ecr |= LPT_ECP_ECR_FIFO_EMPTY;
234 /* Clear FIFO full bit */
235 s->reg_ecp_ecr &= ~LPT_ECP_ECR_FIFO_FULL;
236 }
237 /* Set new mode */
238 s->reg_ecp_ecr |= LPT_ECP_ECR_CHIPMODE_SET_BITS(LPT_ECP_ECR_CHIPMODE_GET_BITS(ch));
239 break;
240 case 3:
241 break;
242 case 4:
243 break;
244 case 5:
245 break;
246 case 6:
247 break;
248 case 7:
249 break;
250 }
251 return VINF_SUCCESS;
252}
253
254static uint32_t parallel_ioport_read_ecp(void *opaque, uint32_t addr, int *pRC)
255{
256 PARALLELPORT *s = (PARALLELPORT *)opaque;
257 uint32_t ret = ~0U;
258
259 *pRC = VINF_SUCCESS;
260
261 addr &= 7;
262 switch (addr) {
263 default:
264 case 0:
265 if (LPT_ECP_ECR_CHIPMODE_GET_BITS(s->reg_ecp_ecr) == LPT_ECP_ECR_CHIPMODE_FIFO_TEST) {
266 ret = s->ecp_fifo[s->act_fifo_pos_read];
267 s->act_fifo_pos_read++;
268 if (s->act_fifo_pos_read == LPT_ECP_FIFO_DEPTH)
269 s->act_fifo_pos_read = 0; /* end of FIFO, start at beginning */
270 if (s->act_fifo_pos_read == s->act_fifo_pos_write) {
271 /* FIFO is empty */
272 /* Set FIFO empty bit */
273 s->reg_ecp_ecr |= LPT_ECP_ECR_FIFO_EMPTY;
274 /* Clear FIFO full bit */
275 s->reg_ecp_ecr &= ~LPT_ECP_ECR_FIFO_FULL;
276 } else {
277 /* FIFO has some data (clear all FIFO bits) */
278 s->reg_ecp_ecr &= ~(LPT_ECP_ECR_FIFO_EMPTY | LPT_ECP_ECR_FIFO_FULL);
279 }
280 } else {
281 ret = s->reg_ecp_base_plus_400h;
282 }
283 break;
284 case 1:
285 ret = s->reg_ecp_config_b;
286 break;
287 case 2:
288 ret = s->reg_ecp_ecr;
289 break;
290 case 3:
291 break;
292 case 4:
293 break;
294 case 5:
295 break;
296 case 6:
297 break;
298 case 7:
299 break;
300 }
301 LogFlow(("parallel: read ecp addr=0x%02x val=0x%02x\n", addr, ret));
302 return ret;
303}
304#endif
305
306#ifdef IN_RING3
307/**
308 * @interface_method_impl{PDMIHOSTPARALLELPORT,pfnNotifyInterrupt}
309 */
310static DECLCALLBACK(int) parallelR3NotifyInterrupt(PPDMIHOSTPARALLELPORT pInterface)
311{
312 PPARALLELPORTR3 pThisCC = RT_FROM_MEMBER(pInterface, PARALLELPORTR3, IHostParallelPort);
313 PPDMDEVINS pDevIns = pThisCC->pDevIns;
314 PPARALLELPORT pThis = PDMDEVINS_2_DATA(pDevIns, PPARALLELPORT);
315
316 int rc = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VINF_SUCCESS);
317 AssertRCReturn(rc, rc);
318
319 parallelR3IrqSet(pDevIns, pThis);
320
321 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
322
323 return VINF_SUCCESS;
324}
325#endif /* IN_RING3 */
326
327
328/**
329 * @callback_method_impl{FNIOMIOPORTNEWOUT}
330 */
331static DECLCALLBACK(VBOXSTRICTRC)
332parallelIoPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
333{
334 PPARALLELPORT pThis = PDMDEVINS_2_DATA(pDevIns, PPARALLELPORT);
335#ifdef IN_RING3
336 PPARALLELPORTR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PPARALLELPORTR3);
337#endif
338 VBOXSTRICTRC rc = VINF_SUCCESS;
339 RT_NOREF_PV(pvUser);
340
341 if (cb == 1)
342 {
343 uint8_t u8 = u32;
344
345 Log2(("%s: Port=%#06x+%x val %#04x\n", __FUNCTION__, pThis->IOBase, offPort, u32));
346
347 offPort &= 7;
348 switch (offPort)
349 {
350 case 0:
351#ifndef IN_RING3
352 NOREF(u8);
353 rc = VINF_IOM_R3_IOPORT_WRITE;
354#else
355 pThis->regData = u8;
356 if (RT_LIKELY(pThisCC->pDrvHostParallelConnector))
357 {
358 LogFlowFunc(("Set data lines 0x%X\n", u8));
359 rc = pThisCC->pDrvHostParallelConnector->pfnWrite(pThisCC->pDrvHostParallelConnector, &u8, 1, PDM_PARALLEL_PORT_MODE_SPP);
360 AssertRC(VBOXSTRICTRC_VAL(rc));
361 }
362#endif
363 break;
364 case 1:
365 break;
366 case 2:
367 /* Set the reserved bits to one */
368 u8 |= (LPT_CONTROL_BIT6 | LPT_CONTROL_BIT7);
369 if (u8 != pThis->regControl)
370 {
371#ifndef IN_RING3
372 return VINF_IOM_R3_IOPORT_WRITE;
373#else
374 if (RT_LIKELY(pThisCC->pDrvHostParallelConnector))
375 {
376 /* Set data direction. */
377 if (u8 & LPT_CONTROL_ENABLE_BIDIRECT)
378 rc = pThisCC->pDrvHostParallelConnector->pfnSetPortDirection(pThisCC->pDrvHostParallelConnector, false /* fForward */);
379 else
380 rc = pThisCC->pDrvHostParallelConnector->pfnSetPortDirection(pThisCC->pDrvHostParallelConnector, true /* fForward */);
381 AssertRC(VBOXSTRICTRC_VAL(rc));
382
383 u8 &= ~LPT_CONTROL_ENABLE_BIDIRECT; /* Clear bit. */
384
385 rc = pThisCC->pDrvHostParallelConnector->pfnWriteControl(pThisCC->pDrvHostParallelConnector, u8);
386 AssertRC(VBOXSTRICTRC_VAL(rc));
387 }
388 else
389 u8 &= ~LPT_CONTROL_ENABLE_BIDIRECT; /* Clear bit. */
390
391 pThis->regControl = u8;
392#endif
393 }
394 break;
395 case 3:
396#ifndef IN_RING3
397 NOREF(u8);
398 rc = VINF_IOM_R3_IOPORT_WRITE;
399#else
400 pThis->regEppAddr = u8;
401 if (RT_LIKELY(pThisCC->pDrvHostParallelConnector))
402 {
403 LogFlowFunc(("Write EPP address 0x%X\n", u8));
404 rc = pThisCC->pDrvHostParallelConnector->pfnWrite(pThisCC->pDrvHostParallelConnector, &u8, 1, PDM_PARALLEL_PORT_MODE_EPP_ADDR);
405 AssertRC(VBOXSTRICTRC_VAL(rc));
406 }
407#endif
408 break;
409 case 4:
410#ifndef IN_RING3
411 NOREF(u8);
412 rc = VINF_IOM_R3_IOPORT_WRITE;
413#else
414 pThis->regEppData = u8;
415 if (RT_LIKELY(pThisCC->pDrvHostParallelConnector))
416 {
417 LogFlowFunc(("Write EPP data 0x%X\n", u8));
418 rc = pThisCC->pDrvHostParallelConnector->pfnWrite(pThisCC->pDrvHostParallelConnector, &u8, 1, PDM_PARALLEL_PORT_MODE_EPP_DATA);
419 AssertRC(VBOXSTRICTRC_VAL(rc));
420 }
421#endif
422 break;
423 case 5:
424 break;
425 case 6:
426 break;
427 case 7:
428 default:
429 break;
430 }
431 }
432 else
433 ASSERT_GUEST_MSG_FAILED(("Port=%#x+%x cb=%d u32=%#x\n", pThis->IOBase, offPort, cb, u32));
434
435 return rc;
436}
437
438
439/**
440 * @callback_method_impl{FNIOMIOPORTNEWIN}
441 */
442static DECLCALLBACK(VBOXSTRICTRC)
443parallelIoPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
444{
445 PPARALLELPORT pThis = PDMDEVINS_2_DATA(pDevIns, PPARALLELPORT);
446#ifdef IN_RING3
447 PPARALLELPORTR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PPARALLELPORTR3);
448#endif
449 VBOXSTRICTRC rc = VINF_SUCCESS;
450 RT_NOREF_PV(pvUser);
451
452 if (cb == 1)
453 {
454 offPort &= 7;
455 switch (offPort)
456 {
457 case 0:
458 if (!(pThis->regControl & LPT_CONTROL_ENABLE_BIDIRECT))
459 *pu32 = pThis->regData;
460 else
461 {
462#ifndef IN_RING3
463 rc = VINF_IOM_R3_IOPORT_READ;
464#else
465 if (RT_LIKELY(pThisCC->pDrvHostParallelConnector))
466 {
467 rc = pThisCC->pDrvHostParallelConnector->pfnRead(pThisCC->pDrvHostParallelConnector, &pThis->regData,
468 1, PDM_PARALLEL_PORT_MODE_SPP);
469 Log(("Read data lines 0x%X\n", pThis->regData));
470 AssertRC(VBOXSTRICTRC_VAL(rc));
471 }
472 *pu32 = pThis->regData;
473#endif
474 }
475 break;
476 case 1:
477#ifndef IN_RING3
478 rc = VINF_IOM_R3_IOPORT_READ;
479#else
480 if (RT_LIKELY(pThisCC->pDrvHostParallelConnector))
481 {
482 rc = pThisCC->pDrvHostParallelConnector->pfnReadStatus(pThisCC->pDrvHostParallelConnector, &pThis->regStatus);
483 AssertRC(VBOXSTRICTRC_VAL(rc));
484 }
485 *pu32 = pThis->regStatus;
486 parallelR3IrqClear(pDevIns, pThis);
487#endif
488 break;
489 case 2:
490#ifndef IN_RING3
491 rc = VINF_IOM_R3_IOPORT_READ;
492#else
493 if (RT_LIKELY(pThisCC->pDrvHostParallelConnector))
494 {
495 rc = pThisCC->pDrvHostParallelConnector->pfnReadControl(pThisCC->pDrvHostParallelConnector, &pThis->regControl);
496 AssertRC(VBOXSTRICTRC_VAL(rc));
497 pThis->regControl |= LPT_CONTROL_BIT6 | LPT_CONTROL_BIT7;
498 }
499
500 *pu32 = pThis->regControl;
501#endif
502 break;
503 case 3:
504#ifndef IN_RING3
505 rc = VINF_IOM_R3_IOPORT_READ;
506#else
507 if (RT_LIKELY(pThisCC->pDrvHostParallelConnector))
508 {
509 rc = pThisCC->pDrvHostParallelConnector->pfnRead(pThisCC->pDrvHostParallelConnector, &pThis->regEppAddr,
510 1, PDM_PARALLEL_PORT_MODE_EPP_ADDR);
511 Log(("Read EPP address 0x%X\n", pThis->regEppAddr));
512 AssertRC(VBOXSTRICTRC_VAL(rc));
513 }
514 *pu32 = pThis->regEppAddr;
515#endif
516 break;
517 case 4:
518#ifndef IN_RING3
519 rc = VINF_IOM_R3_IOPORT_READ;
520#else
521 if (RT_LIKELY(pThisCC->pDrvHostParallelConnector))
522 {
523 rc = pThisCC->pDrvHostParallelConnector->pfnRead(pThisCC->pDrvHostParallelConnector, &pThis->regEppData,
524 1, PDM_PARALLEL_PORT_MODE_EPP_DATA);
525 Log(("Read EPP data 0x%X\n", pThis->regEppData));
526 AssertRC(VBOXSTRICTRC_VAL(rc));
527 }
528 *pu32 = pThis->regEppData;
529#endif
530 break;
531 case 5:
532 break;
533 case 6:
534 break;
535 case 7:
536 break;
537 }
538 }
539 else
540 rc = VERR_IOM_IOPORT_UNUSED;
541
542 return rc;
543}
544
545#if 0
546/**
547 * @callback_method_impl{FNIOMIOPORTNEWOUT, ECP registers.}
548 */
549static DECLCALLBACK(VBOXSTRICTRC)
550parallelIoPortWriteECP(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
551{
552 PPARALLELPORT pThis = PDMDEVINS_2_DATA(pDevIns, PPARALLELPORT);
553 VBOXSTRICTRC rc = VINF_SUCCESS;
554
555 if (cb == 1)
556 {
557 Log2(("%s: ecp port %#06x+%x val %#04x\n", __FUNCTION__, pThis->IOBase + 0x400, offPort, u32));
558 rc = parallel_ioport_write_ecp(pThis, Port, u32);
559 }
560 else
561 ASSERT_GUEST_MSG_FAILED(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
562
563 return rc;
564}
565
566/**
567 * @callback_method_impl{FNIOMIOPORTNEWOUT, ECP registers.}
568 */
569static DECLCALLBACK(VBOXSTRICTRC)
570parallelIoPortReadECP(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
571{
572 PPARALLELPORT pThis = PDMDEVINS_2_DATA(pDevIns, PPARALLELPORT);
573 VBOXSTRICTRC rc = VINF_SUCCESS;
574
575 if (cb == 1)
576 {
577 *pu32 = parallel_ioport_read_ecp(pThis, Port, &rc);
578 Log2(("%s: ecp port %#06x+%x val %#04x\n", __FUNCTION__, pThis->IOBase + 0x400, offPort, *pu32));
579 }
580 else
581 rc = VERR_IOM_IOPORT_UNUSED;
582
583 return rc;
584}
585#endif
586
587#ifdef IN_RING3
588
589/**
590 * @callback_method_impl{FNSSMDEVLIVEEXEC}
591 */
592static DECLCALLBACK(int) parallelR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
593{
594 PPARALLELPORT pThis = PDMDEVINS_2_DATA(pDevIns, PPARALLELPORT);
595 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
596 RT_NOREF(uPass);
597
598 pHlp->pfnSSMPutS32(pSSM, pThis->iIrq);
599 pHlp->pfnSSMPutU32(pSSM, pThis->IOBase);
600 pHlp->pfnSSMPutU32(pSSM, UINT32_MAX); /* sanity/terminator */
601 return VINF_SSM_DONT_CALL_AGAIN;
602}
603
604
605/**
606 * @callback_method_impl{FNSSMDEVSAVEEXEC}
607 */
608static DECLCALLBACK(int) parallelR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
609{
610 PPARALLELPORT pThis = PDMDEVINS_2_DATA(pDevIns, PPARALLELPORT);
611 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
612
613 pHlp->pfnSSMPutU8(pSSM, pThis->regData);
614 pHlp->pfnSSMPutU8(pSSM, pThis->regStatus);
615 pHlp->pfnSSMPutU8(pSSM, pThis->regControl);
616
617 parallelR3LiveExec(pDevIns, pSSM, 0);
618 return VINF_SUCCESS;
619}
620
621
622/**
623 * @callback_method_impl{FNSSMDEVLOADEXEC}
624 */
625static DECLCALLBACK(int) parallelR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
626{
627 PPARALLELPORT pThis = PDMDEVINS_2_DATA(pDevIns, PPARALLELPORT);
628 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
629
630 AssertMsgReturn(uVersion == PARALLEL_SAVED_STATE_VERSION, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
631 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
632 if (uPass == SSM_PASS_FINAL)
633 {
634 pHlp->pfnSSMGetU8(pSSM, &pThis->regData);
635 pHlp->pfnSSMGetU8(pSSM, &pThis->regStatus);
636 pHlp->pfnSSMGetU8(pSSM, &pThis->regControl);
637 }
638
639 /* the config */
640 int32_t iIrq;
641 pHlp->pfnSSMGetS32(pSSM, &iIrq);
642 uint32_t uIoBase;
643 pHlp->pfnSSMGetU32(pSSM, &uIoBase);
644 uint32_t u32;
645 int rc = pHlp->pfnSSMGetU32(pSSM, &u32);
646 AssertRCReturn(rc, rc);
647 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
648
649 if (pThis->iIrq != iIrq)
650 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("IRQ changed: config=%#x state=%#x"), pThis->iIrq, iIrq);
651
652 if (pThis->IOBase != uIoBase)
653 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("IOBase changed: config=%#x state=%#x"), pThis->IOBase, uIoBase);
654
655 return VINF_SUCCESS;
656}
657
658
659/**
660 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
661 */
662static DECLCALLBACK(void *) parallelR3QueryInterface(PPDMIBASE pInterface, const char *pszIID)
663{
664 PPARALLELPORTR3 pThisCC = RT_FROM_MEMBER(pInterface, PARALLELPORTR3, IBase);
665 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->IBase);
666 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTPARALLELPORT, &pThisCC->IHostParallelPort);
667 return NULL;
668}
669
670
671/**
672 * @interface_method_impl{PDMDEVREG,pfnConstruct}
673 */
674static DECLCALLBACK(int) parallelR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
675{
676 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
677 PPARALLELPORT pThis = PDMDEVINS_2_DATA(pDevIns, PPARALLELPORT);
678 PPARALLELPORTR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PPARALLELPORTR3);
679 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
680 int rc;
681
682 Assert(iInstance < 4);
683
684 /*
685 * Init the data.
686 */
687 pThisCC->pDevIns = pDevIns;
688
689 /* IBase */
690 pThisCC->IBase.pfnQueryInterface = parallelR3QueryInterface;
691
692 /* IHostParallelPort */
693 pThisCC->IHostParallelPort.pfnNotifyInterrupt = parallelR3NotifyInterrupt;
694
695 /* Init parallel state */
696 pThis->regData = 0;
697#if 0 /* ECP implementation not complete. */
698 pThis->reg_ecp_ecr = LPT_ECP_ECR_CHIPMODE_COMPAT | LPT_ECP_ECR_FIFO_EMPTY;
699 pThis->act_fifo_pos_read = 0;
700 pThis->act_fifo_pos_write = 0;
701#endif
702
703 /*
704 * Validate and read the configuration.
705 */
706 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "IRQ|IOBase", "");
707
708 rc = pHlp->pfnCFGMQueryS32Def(pCfg, "IRQ", &pThis->iIrq, 7);
709 if (RT_FAILURE(rc))
710 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"IRQ\" value"));
711
712 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "IOBase", &pThis->IOBase, 0x378);
713 if (RT_FAILURE(rc))
714 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"IOBase\" value"));
715
716 int cPorts = (pThis->IOBase == 0x3BC) ? 4 : 8;
717 /*
718 * Register the I/O ports and saved state.
719 */
720 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, pThis->IOBase, cPorts, parallelIoPortWrite, parallelIoPortRead,
721 "Parallel", NULL /*paExtDesc*/, &pThis->hIoPorts);
722 AssertRCReturn(rc, rc);
723
724#if 0
725 /* register ecp registers */
726 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, pThis->IOBase + 0x400, 8, parallelIoPortWriteECP, parallelIoPortReadECP,
727 "Parallel ECP", NULL /*paExtDesc*/, &pThis->hIoPortsEcp);
728 AssertRCReturn(rc, rc);
729#endif
730
731
732 rc = PDMDevHlpSSMRegister3(pDevIns, PARALLEL_SAVED_STATE_VERSION, sizeof(*pThis),
733 parallelR3LiveExec, parallelR3SaveExec, parallelR3LoadExec);
734 AssertRCReturn(rc, rc);
735
736
737 /*
738 * Attach the parallel port driver and get the interfaces.
739 * For now no run-time changes are supported.
740 */
741 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThisCC->IBase, &pThisCC->pDrvBase, "Parallel Host");
742 if (RT_SUCCESS(rc))
743 {
744 pThisCC->pDrvHostParallelConnector = PDMIBASE_QUERY_INTERFACE(pThisCC->pDrvBase, PDMIHOSTPARALLELCONNECTOR);
745
746 /* Set compatibility mode */
747 //pThisCC->pDrvHostParallelConnector->pfnSetMode(pThisCC->pDrvHostParallelConnector, PDM_PARALLEL_PORT_MODE_COMPAT);
748 /* Get status of control register */
749 pThisCC->pDrvHostParallelConnector->pfnReadControl(pThisCC->pDrvHostParallelConnector, &pThis->regControl);
750
751 AssertMsgReturn(pThisCC->pDrvHostParallelConnector,
752 ("Configuration error: instance %d has no host parallel interface!\n", iInstance),
753 VERR_PDM_MISSING_INTERFACE);
754 }
755 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
756 {
757 pThisCC->pDrvBase = NULL;
758 pThisCC->pDrvHostParallelConnector = NULL;
759 LogRel(("Parallel%d: no unit\n", iInstance));
760 }
761 else
762 AssertMsgFailedReturn(("Parallel%d: Failed to attach to host driver. rc=%Rrc\n", iInstance, rc),
763 PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
764 N_("Parallel device %d cannot attach to host driver"), iInstance));
765
766 return VINF_SUCCESS;
767}
768
769#else /* !IN_RING3 */
770
771/**
772 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
773 */
774static DECLCALLBACK(int) parallelRZConstruct(PPDMDEVINS pDevIns)
775{
776 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
777 PPARALLELPORT pThis = PDMDEVINS_2_DATA(pDevIns, PPARALLELPORT);
778
779 int rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPorts, parallelIoPortWrite, parallelIoPortRead, NULL /*pvUser*/);
780 AssertRCReturn(rc, rc);
781
782# if 0
783 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortsEcp, parallelIoPortWriteECP, parallelIoPortReadECP, NULL /*pvUser*/);
784 AssertRCReturn(rc, rc);
785# endif
786
787 return VINF_SUCCESS;
788}
789
790#endif /* !IN_RING3 */
791
792/**
793 * The device registration structure.
794 */
795const PDMDEVREG g_DeviceParallelPort =
796{
797 /* .u32Version = */ PDM_DEVREG_VERSION,
798 /* .uReserved0 = */ 0,
799 /* .szName = */ "parallel",
800 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
801 /* .fClass = */ PDM_DEVREG_CLASS_PARALLEL,
802 /* .cMaxInstances = */ 2,
803 /* .uSharedVersion = */ 42,
804 /* .cbInstanceShared = */ sizeof(PARALLELPORT),
805 /* .cbInstanceCC = */ CTX_EXPR(sizeof(PARALLELPORTR3), 0, 0),
806 /* .cbInstanceRC = */ 0,
807 /* .cMaxPciDevices = */ 0,
808 /* .cMaxMsixVectors = */ 0,
809 /* .pszDescription = */ "Parallel Communication Port",
810#if defined(IN_RING3)
811 /* .pszRCMod = */ "VBoxDDRC.rc",
812 /* .pszR0Mod = */ "VBoxDDR0.r0",
813 /* .pfnConstruct = */ parallelR3Construct,
814 /* .pfnDestruct = */ NULL,
815 /* .pfnRelocate = */ NULL,
816 /* .pfnMemSetup = */ NULL,
817 /* .pfnPowerOn = */ NULL,
818 /* .pfnReset = */ NULL,
819 /* .pfnSuspend = */ NULL,
820 /* .pfnResume = */ NULL,
821 /* .pfnAttach = */ NULL,
822 /* .pfnDetach = */ NULL,
823 /* .pfnQueryInterface = */ NULL,
824 /* .pfnInitComplete = */ NULL,
825 /* .pfnPowerOff = */ NULL,
826 /* .pfnSoftReset = */ NULL,
827 /* .pfnReserved0 = */ NULL,
828 /* .pfnReserved1 = */ NULL,
829 /* .pfnReserved2 = */ NULL,
830 /* .pfnReserved3 = */ NULL,
831 /* .pfnReserved4 = */ NULL,
832 /* .pfnReserved5 = */ NULL,
833 /* .pfnReserved6 = */ NULL,
834 /* .pfnReserved7 = */ NULL,
835#elif defined(IN_RING0)
836 /* .pfnEarlyConstruct = */ NULL,
837 /* .pfnConstruct = */ parallelRZConstruct,
838 /* .pfnDestruct = */ NULL,
839 /* .pfnFinalDestruct = */ NULL,
840 /* .pfnRequest = */ NULL,
841 /* .pfnReserved0 = */ NULL,
842 /* .pfnReserved1 = */ NULL,
843 /* .pfnReserved2 = */ NULL,
844 /* .pfnReserved3 = */ NULL,
845 /* .pfnReserved4 = */ NULL,
846 /* .pfnReserved5 = */ NULL,
847 /* .pfnReserved6 = */ NULL,
848 /* .pfnReserved7 = */ NULL,
849#elif defined(IN_RC)
850 /* .pfnConstruct = */ parallelRZConstruct,
851 /* .pfnReserved0 = */ NULL,
852 /* .pfnReserved1 = */ NULL,
853 /* .pfnReserved2 = */ NULL,
854 /* .pfnReserved3 = */ NULL,
855 /* .pfnReserved4 = */ NULL,
856 /* .pfnReserved5 = */ NULL,
857 /* .pfnReserved6 = */ NULL,
858 /* .pfnReserved7 = */ NULL,
859#else
860# error "Not in IN_RING3, IN_RING0 or IN_RC!"
861#endif
862 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
863};
864
865#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
866
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use