VirtualBox

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

Last change on this file since 82120 was 82120, checked in by vboxsync, 5 years ago

DevParallel: CFGM & SSM via devhlp. bugref:9218

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette