VirtualBox

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

Last change on this file since 57979 was 57979, checked in by vboxsync, 10 years ago

Parallel ports: Several fixes for multiple parallel ports. Make the second parallel port visible to the guest through ACPI if enabled (and don't expose the first port if it is not enabled), increase the maximum instanbce count to 2 and make it possible to enable a parallel port without having it connected to a host device to make it behave like it is not connected to anything.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 29.3 KB
Line 
1/* $Id: DevParallel.cpp 57979 2015-10-01 08:25:21Z 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-2015 Oracle Corporation
11 *
12 * This file is part of VirtualBox Open Source Edition (OSE), as
13 * available from http://www.215389.xyz. 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 * 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 Alignment0;
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 the device has its RC component enabled. */
116 bool fGCEnabled;
117 /** Flag whether the device has its R0 component enabled. */
118 bool fR0Enabled;
119 /** Flag whether an EPP timeout occurred (error handling). */
120 bool fEppTimeout;
121 /** Base I/O port of the parallel port. */
122 RTIOPORT IOBase;
123 /** IRQ number assigned ot the parallel port. */
124 int iIrq;
125 /** Data register. */
126 uint8_t regData;
127 /** Status register. */
128 uint8_t regStatus;
129 /** Control register. */
130 uint8_t regControl;
131 /** EPP address register. */
132 uint8_t regEppAddr;
133 /** EPP data register. */
134 uint8_t regEppData;
135 /** More alignment. */
136 uint32_t u32Alignment;
137
138#if 0 /* Data for ECP implementation, currently unused. */
139 uint8_t reg_ecp_ecr;
140 uint8_t reg_ecp_base_plus_400h; /* has different meanings */
141 uint8_t reg_ecp_config_b;
142
143 /** The ECP FIFO implementation*/
144 uint8_t ecp_fifo[LPT_ECP_FIFO_DEPTH];
145 uint8_t abAlignemnt[2];
146 int act_fifo_pos_write;
147 int act_fifo_pos_read;
148#endif
149} PARALLELPORT, *PPARALLELPORT;
150
151#ifndef VBOX_DEVICE_STRUCT_TESTCASE
152
153#define PDMIHOSTPARALLELPORT_2_PARALLELPORT(pInstance) ( (PARALLELPORT *)((uintptr_t)(pInterface) - RT_OFFSETOF(PARALLELPORT, IHostParallelPort)) )
154#define PDMIHOSTDEVICEPORT_2_PARALLELPORT(pInstance) ( (PARALLELPORT *)((uintptr_t)(pInterface) - RT_OFFSETOF(PARALLELPORT, IHostDevicePort)) )
155#define PDMIBASE_2_PARALLELPORT(pInstance) ( (PARALLELPORT *)((uintptr_t)(pInterface) - RT_OFFSETOF(PARALLELPORT, IBase)) )
156
157
158/*********************************************************************************************************************************
159* Internal Functions *
160*********************************************************************************************************************************/
161RT_C_DECLS_BEGIN
162PDMBOTHCBDECL(int) parallelIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
163PDMBOTHCBDECL(int) parallelIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
164#if 0
165PDMBOTHCBDECL(int) parallelIOPortReadECP(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
166PDMBOTHCBDECL(int) parallelIOPortWriteECP(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
167#endif
168RT_C_DECLS_END
169
170
171#ifdef IN_RING3
172static void parallelR3IrqSet(PARALLELPORT *pThis)
173{
174 if (pThis->regControl & LPT_CONTROL_ENABLE_IRQ_VIA_ACK)
175 {
176 LogFlowFunc(("%d 1\n", pThis->iIrq));
177 PDMDevHlpISASetIrqNoWait(pThis->CTX_SUFF(pDevIns), pThis->iIrq, 1);
178 }
179}
180
181static void parallelR3IrqClear(PARALLELPORT *pThis)
182{
183 LogFlowFunc(("%d 0\n", pThis->iIrq));
184 PDMDevHlpISASetIrqNoWait(pThis->CTX_SUFF(pDevIns), pThis->iIrq, 0);
185}
186#endif
187
188#if 0
189static int parallel_ioport_write_ecp(void *opaque, uint32_t addr, uint32_t val)
190{
191 PARALLELPORT *s = (PARALLELPORT *)opaque;
192 unsigned char ch;
193
194 addr &= 7;
195 LogFlow(("parallel: write ecp addr=0x%02x val=0x%02x\n", addr, val));
196 ch = val;
197 switch (addr) {
198 default:
199 case 0:
200 if (LPT_ECP_ECR_CHIPMODE_GET_BITS(s->reg_ecp_ecr) == LPT_ECP_ECR_CHIPMODE_FIFO_TEST) {
201 s->ecp_fifo[s->act_fifo_pos_write] = ch;
202 s->act_fifo_pos_write++;
203 if (s->act_fifo_pos_write < LPT_ECP_FIFO_DEPTH) {
204 /* FIFO has some data (clear both FIFO bits) */
205 s->reg_ecp_ecr &= ~(LPT_ECP_ECR_FIFO_EMPTY | LPT_ECP_ECR_FIFO_FULL);
206 } else {
207 /* FIFO is full */
208 /* Clear FIFO empty bit */
209 s->reg_ecp_ecr &= ~LPT_ECP_ECR_FIFO_EMPTY;
210 /* Set FIFO full bit */
211 s->reg_ecp_ecr |= LPT_ECP_ECR_FIFO_FULL;
212 s->act_fifo_pos_write = 0;
213 }
214 } else {
215 s->reg_ecp_base_plus_400h = ch;
216 }
217 break;
218 case 1:
219 s->reg_ecp_config_b = ch;
220 break;
221 case 2:
222 /* If we change the mode clear FIFO */
223 if ((ch & LPT_ECP_ECR_CHIPMODE_MASK) != (s->reg_ecp_ecr & LPT_ECP_ECR_CHIPMODE_MASK)) {
224 /* reset the fifo */
225 s->act_fifo_pos_write = 0;
226 s->act_fifo_pos_read = 0;
227 /* Set FIFO empty bit */
228 s->reg_ecp_ecr |= LPT_ECP_ECR_FIFO_EMPTY;
229 /* Clear FIFO full bit */
230 s->reg_ecp_ecr &= ~LPT_ECP_ECR_FIFO_FULL;
231 }
232 /* Set new mode */
233 s->reg_ecp_ecr |= LPT_ECP_ECR_CHIPMODE_SET_BITS(LPT_ECP_ECR_CHIPMODE_GET_BITS(ch));
234 break;
235 case 3:
236 break;
237 case 4:
238 break;
239 case 5:
240 break;
241 case 6:
242 break;
243 case 7:
244 break;
245 }
246 return VINF_SUCCESS;
247}
248
249static uint32_t parallel_ioport_read_ecp(void *opaque, uint32_t addr, int *pRC)
250{
251 PARALLELPORT *s = (PARALLELPORT *)opaque;
252 uint32_t ret = ~0U;
253
254 *pRC = VINF_SUCCESS;
255
256 addr &= 7;
257 switch (addr) {
258 default:
259 case 0:
260 if (LPT_ECP_ECR_CHIPMODE_GET_BITS(s->reg_ecp_ecr) == LPT_ECP_ECR_CHIPMODE_FIFO_TEST) {
261 ret = s->ecp_fifo[s->act_fifo_pos_read];
262 s->act_fifo_pos_read++;
263 if (s->act_fifo_pos_read == LPT_ECP_FIFO_DEPTH)
264 s->act_fifo_pos_read = 0; /* end of FIFO, start at beginning */
265 if (s->act_fifo_pos_read == s->act_fifo_pos_write) {
266 /* FIFO is empty */
267 /* Set FIFO empty bit */
268 s->reg_ecp_ecr |= LPT_ECP_ECR_FIFO_EMPTY;
269 /* Clear FIFO full bit */
270 s->reg_ecp_ecr &= ~LPT_ECP_ECR_FIFO_FULL;
271 } else {
272 /* FIFO has some data (clear all FIFO bits) */
273 s->reg_ecp_ecr &= ~(LPT_ECP_ECR_FIFO_EMPTY | LPT_ECP_ECR_FIFO_FULL);
274 }
275 } else {
276 ret = s->reg_ecp_base_plus_400h;
277 }
278 break;
279 case 1:
280 ret = s->reg_ecp_config_b;
281 break;
282 case 2:
283 ret = s->reg_ecp_ecr;
284 break;
285 case 3:
286 break;
287 case 4:
288 break;
289 case 5:
290 break;
291 case 6:
292 break;
293 case 7:
294 break;
295 }
296 LogFlow(("parallel: read ecp addr=0x%02x val=0x%02x\n", addr, ret));
297 return ret;
298}
299#endif
300
301#ifdef IN_RING3
302/**
303 * @interface_methods_impl{PDMIHOSTPARALLELPORT,pfnNotifyInterrupt}
304 */
305static DECLCALLBACK(int) parallelR3NotifyInterrupt(PPDMIHOSTPARALLELPORT pInterface)
306{
307 PARALLELPORT *pThis = PDMIHOSTPARALLELPORT_2_PARALLELPORT(pInterface);
308
309 PDMCritSectEnter(pThis->pDevInsR3->pCritSectRoR3, VINF_SUCCESS);
310 parallelR3IrqSet(pThis);
311 PDMCritSectLeave(pThis->pDevInsR3->pCritSectRoR3);
312
313 return VINF_SUCCESS;
314}
315#endif /* IN_RING3 */
316
317
318/**
319 * @callback_method_impl{FNIOMIOPORTOUT}
320 */
321PDMBOTHCBDECL(int) parallelIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
322{
323 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PPARALLELPORT);
324 int rc = VINF_SUCCESS;
325
326 if (cb == 1)
327 {
328 uint8_t u8 = u32;
329
330 Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, u32));
331
332 Port &= 7;
333 switch (Port)
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", Port, cb, u32));
419
420 return rc;
421}
422
423
424/**
425 * @callback_method_impl{FNIOMIOPORTIN}
426 */
427PDMBOTHCBDECL(int) parallelIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
428{
429 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
430 int rc = VINF_SUCCESS;
431
432 if (cb == 1)
433 {
434 Port &= 7;
435 switch (Port)
436 {
437 case 0:
438 if (!(pThis->regControl & LPT_CONTROL_ENABLE_BIDIRECT))
439 *pu32 = pThis->regData;
440 else
441 {
442#ifndef IN_RING3
443 rc = VINF_IOM_R3_IOPORT_READ;
444#else
445 if (RT_LIKELY(pThis->pDrvHostParallelConnector))
446 {
447 rc = pThis->pDrvHostParallelConnector->pfnRead(pThis->pDrvHostParallelConnector, &pThis->regData,
448 1, PDM_PARALLEL_PORT_MODE_SPP);
449 Log(("Read data lines 0x%X\n", pThis->regData));
450 AssertRC(rc);
451 }
452 *pu32 = pThis->regData;
453#endif
454 }
455 break;
456 case 1:
457#ifndef IN_RING3
458 rc = VINF_IOM_R3_IOPORT_READ;
459#else
460 if (RT_LIKELY(pThis->pDrvHostParallelConnector))
461 {
462 rc = pThis->pDrvHostParallelConnector->pfnReadStatus(pThis->pDrvHostParallelConnector, &pThis->regStatus);
463 AssertRC(rc);
464 }
465 *pu32 = pThis->regStatus;
466 parallelR3IrqClear(pThis);
467#endif
468 break;
469 case 2:
470#ifndef IN_RING3
471 rc = VINF_IOM_R3_IOPORT_READ;
472#else
473 if (RT_LIKELY(pThis->pDrvHostParallelConnector))
474 {
475 rc = pThis->pDrvHostParallelConnector->pfnReadControl(pThis->pDrvHostParallelConnector, &pThis->regControl);
476 AssertRC(rc);
477 pThis->regControl |= LPT_CONTROL_BIT6 | LPT_CONTROL_BIT7;
478 }
479
480 *pu32 = pThis->regControl;
481#endif
482 break;
483 case 3:
484#ifndef IN_RING3
485 rc = VINF_IOM_R3_IOPORT_READ;
486#else
487 if (RT_LIKELY(pThis->pDrvHostParallelConnector))
488 {
489 rc = pThis->pDrvHostParallelConnector->pfnRead(pThis->pDrvHostParallelConnector, &pThis->regEppAddr,
490 1, PDM_PARALLEL_PORT_MODE_EPP_ADDR);
491 Log(("Read EPP address 0x%X\n", pThis->regEppAddr));
492 AssertRC(rc);
493 }
494 *pu32 = pThis->regEppAddr;
495#endif
496 break;
497 case 4:
498#ifndef IN_RING3
499 rc = VINF_IOM_R3_IOPORT_READ;
500#else
501 if (RT_LIKELY(pThis->pDrvHostParallelConnector))
502 {
503 rc = pThis->pDrvHostParallelConnector->pfnRead(pThis->pDrvHostParallelConnector, &pThis->regEppData,
504 1, PDM_PARALLEL_PORT_MODE_EPP_DATA);
505 Log(("Read EPP data 0x%X\n", pThis->regEppData));
506 AssertRC(rc);
507 }
508 *pu32 = pThis->regEppData;
509#endif
510 break;
511 case 5:
512 break;
513 case 6:
514 break;
515 case 7:
516 break;
517 }
518 }
519 else
520 rc = VERR_IOM_IOPORT_UNUSED;
521
522 return rc;
523}
524
525#if 0
526/**
527 * @callback_method_impl{FNIOMIOPORTOUT, ECP registers.}
528 */
529PDMBOTHCBDECL(int) parallelIOPortWriteECP(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
530{
531 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
532 int rc = VINF_SUCCESS;
533
534 if (cb == 1)
535 {
536 Log2(("%s: ecp port %#06x val %#04x\n", __FUNCTION__, Port, u32));
537 rc = parallel_ioport_write_ecp (pThis, Port, u32);
538 }
539 else
540 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
541
542 return rc;
543}
544
545/**
546 * @callback_method_impl{FNIOMIOPORTOUT, ECP registers.}
547 */
548PDMBOTHCBDECL(int) parallelIOPortReadECP(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
549{
550 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
551 int rc = VINF_SUCCESS;
552
553 if (cb == 1)
554 {
555 *pu32 = parallel_ioport_read_ecp (pThis, Port, &rc);
556 Log2(("%s: ecp port %#06x val %#04x\n", __FUNCTION__, Port, *pu32));
557 }
558 else
559 rc = VERR_IOM_IOPORT_UNUSED;
560
561 return rc;
562}
563#endif
564
565#ifdef IN_RING3
566
567/**
568 * @callback_method_impl{FNSSMDEVLIVEEXEC}
569 */
570static DECLCALLBACK(int) parallelR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
571{
572 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
573
574 SSMR3PutS32(pSSM, pThis->iIrq);
575 SSMR3PutU32(pSSM, pThis->IOBase);
576 SSMR3PutU32(pSSM, ~0); /* sanity/terminator */
577 return VINF_SSM_DONT_CALL_AGAIN;
578}
579
580
581/**
582 * @callback_method_impl{FNSSMDEVSAVEEXEC}
583 */
584static DECLCALLBACK(int) parallelR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
585{
586 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
587
588 SSMR3PutU8(pSSM, pThis->regData);
589 SSMR3PutU8(pSSM, pThis->regStatus);
590 SSMR3PutU8(pSSM, pThis->regControl);
591
592 parallelR3LiveExec(pDevIns, pSSM, 0);
593 return VINF_SUCCESS;
594}
595
596
597/**
598 * @callback_method_impl{FNSSMDEVLOADEXEC}
599 */
600static DECLCALLBACK(int) parallelR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
601{
602 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
603
604 AssertMsgReturn(uVersion == PARALLEL_SAVED_STATE_VERSION, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
605 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
606 if (uPass == SSM_PASS_FINAL)
607 {
608 SSMR3GetU8(pSSM, &pThis->regData);
609 SSMR3GetU8(pSSM, &pThis->regStatus);
610 SSMR3GetU8(pSSM, &pThis->regControl);
611 }
612
613 /* the config */
614 int32_t iIrq;
615 SSMR3GetS32(pSSM, &iIrq);
616 uint32_t uIoBase;
617 SSMR3GetU32(pSSM, &uIoBase);
618 uint32_t u32;
619 int rc = SSMR3GetU32(pSSM, &u32);
620 if (RT_FAILURE(rc))
621 return rc;
622 AssertMsgReturn(u32 == ~0U, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
623
624 if (pThis->iIrq != iIrq)
625 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("IRQ changed: config=%#x state=%#x"), pThis->iIrq, iIrq);
626
627 if (pThis->IOBase != uIoBase)
628 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("IOBase changed: config=%#x state=%#x"), pThis->IOBase, uIoBase);
629
630 /* not necessary... but it doesn't harm. */
631 pThis->pDevInsR3 = pDevIns;
632 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
633 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
634 return VINF_SUCCESS;
635}
636
637
638/**
639 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
640 */
641static DECLCALLBACK(void *) parallelR3QueryInterface(PPDMIBASE pInterface, const char *pszIID)
642{
643 PARALLELPORT *pThis = PDMIBASE_2_PARALLELPORT(pInterface);
644 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
645 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTPARALLELPORT, &pThis->IHostParallelPort);
646 return NULL;
647}
648
649
650/**
651 * @copydoc FNPDMDEVRELOCATE
652 */
653static DECLCALLBACK(void) parallelR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
654{
655 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
656 pThis->pDevInsRC += offDelta;
657}
658
659
660/**
661 * @interface_method_impl{PDMDEVREG,pfnConstruct}
662 */
663static DECLCALLBACK(int) parallelR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
664{
665 int rc;
666 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT*);
667
668 Assert(iInstance < 4);
669 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
670
671 /*
672 * Init the data.
673 */
674 pThis->pDevInsR3 = pDevIns;
675 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
676 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
677
678 /* IBase */
679 pThis->IBase.pfnQueryInterface = parallelR3QueryInterface;
680
681 /* IHostParallelPort */
682 pThis->IHostParallelPort.pfnNotifyInterrupt = parallelR3NotifyInterrupt;
683
684 /* Init parallel state */
685 pThis->regData = 0;
686#if 0 /* ECP implementation not complete. */
687 pThis->reg_ecp_ecr = LPT_ECP_ECR_CHIPMODE_COMPAT | LPT_ECP_ECR_FIFO_EMPTY;
688 pThis->act_fifo_pos_read = 0;
689 pThis->act_fifo_pos_write = 0;
690#endif
691
692 /*
693 * Validate and read the configuration.
694 */
695 if (!CFGMR3AreValuesValid(pCfg, "IRQ\0" "IOBase\0" "GCEnabled\0" "R0Enabled\0"))
696 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
697 N_("Configuration error: Unknown config key"));
698
699 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fGCEnabled, false);
700 if (RT_FAILURE(rc))
701 return PDMDEV_SET_ERROR(pDevIns, rc,
702 N_("Configuration error: Failed to get the \"GCEnabled\" value"));
703
704 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, false);
705 if (RT_FAILURE(rc))
706 return PDMDEV_SET_ERROR(pDevIns, rc,
707 N_("Configuration error: Failed to get the \"R0Enabled\" value"));
708 rc = CFGMR3QueryS32Def(pCfg, "IRQ", &pThis->iIrq, 7);
709 if (RT_FAILURE(rc))
710 return PDMDEV_SET_ERROR(pDevIns, rc,
711 N_("Configuration error: Failed to get the \"IRQ\" value"));
712 rc = CFGMR3QueryU16Def(pCfg, "IOBase", &pThis->IOBase, 0x378);
713 if (RT_FAILURE(rc))
714 return PDMDEV_SET_ERROR(pDevIns, rc,
715 N_("Configuration error: Failed to get the \"IOBase\" value"));
716
717 /*
718 * Register the I/O ports and saved state.
719 */
720 rc = PDMDevHlpIOPortRegister(pDevIns, pThis->IOBase, 8, 0,
721 parallelIOPortWrite, parallelIOPortRead,
722 NULL, NULL, "Parallel");
723 if (RT_FAILURE(rc))
724 return rc;
725
726#if 0
727 /* register ecp registers */
728 rc = PDMDevHlpIOPortRegister(pDevIns, io_base+0x400, 8, 0,
729 parallelIOPortWriteECP, parallelIOPortReadECP,
730 NULL, NULL, "PARALLEL ECP");
731 if (RT_FAILURE(rc))
732 return rc;
733#endif
734
735 if (pThis->fGCEnabled)
736 {
737 rc = PDMDevHlpIOPortRegisterRC(pDevIns, pThis->IOBase, 8, 0, "parallelIOPortWrite",
738 "parallelIOPortRead", NULL, NULL, "Parallel");
739 if (RT_FAILURE(rc))
740 return rc;
741
742#if 0
743 rc = PDMDevHlpIOPortRegisterGC(pDevIns, io_base+0x400, 8, 0, "parallelIOPortWriteECP",
744 "parallelIOPortReadECP", NULL, NULL, "Parallel Ecp");
745 if (RT_FAILURE(rc))
746 return rc;
747#endif
748 }
749
750 if (pThis->fR0Enabled)
751 {
752 rc = PDMDevHlpIOPortRegisterR0(pDevIns, pThis->IOBase, 8, 0, "parallelIOPortWrite",
753 "parallelIOPortRead", NULL, NULL, "Parallel");
754 if (RT_FAILURE(rc))
755 return rc;
756
757#if 0
758 rc = PDMDevHlpIOPortRegisterR0(pDevIns, io_base+0x400, 8, 0, "parallelIOPortWriteECP",
759 "parallelIOPortReadECP", NULL, NULL, "Parallel Ecp");
760 if (RT_FAILURE(rc))
761 return rc;
762#endif
763 }
764
765 rc = PDMDevHlpSSMRegister3(pDevIns, PARALLEL_SAVED_STATE_VERSION, sizeof(*pThis),
766 parallelR3LiveExec, parallelR3SaveExec, parallelR3LoadExec);
767 if (RT_FAILURE(rc))
768 return rc;
769
770
771 /*
772 * Attach the parallel port driver and get the interfaces.
773 * For now no run-time changes are supported.
774 */
775 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Parallel Host");
776 if (RT_SUCCESS(rc))
777 {
778 pThis->pDrvHostParallelConnector = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIHOSTPARALLELCONNECTOR);
779
780 /* Set compatibility mode */
781 //pThis->pDrvHostParallelConnector->pfnSetMode(pThis->pDrvHostParallelConnector, PDM_PARALLEL_PORT_MODE_COMPAT);
782 /* Get status of control register */
783 pThis->pDrvHostParallelConnector->pfnReadControl(pThis->pDrvHostParallelConnector, &pThis->regControl);
784
785 AssertMsgReturn(pThis->pDrvHostParallelConnector,
786 ("Configuration error: instance %d has no host parallel interface!\n", iInstance),
787 VERR_PDM_MISSING_INTERFACE);
788 }
789 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
790 {
791 pThis->pDrvBase = NULL;
792 pThis->pDrvHostParallelConnector = NULL;
793 LogRel(("Parallel%d: no unit\n", iInstance));
794 }
795 else
796 {
797 AssertMsgFailed(("Parallel%d: Failed to attach to host driver. rc=%Rrc\n", iInstance, rc));
798 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
799 N_("Parallel device %d cannot attach to host driver"), iInstance);
800 }
801
802 return VINF_SUCCESS;
803}
804
805/**
806 * The device registration structure.
807 */
808const PDMDEVREG g_DeviceParallelPort =
809{
810 /* u32Version */
811 PDM_DEVREG_VERSION,
812 /* szName */
813 "parallel",
814 /* szRCMod */
815 "VBoxDDRC.rc",
816 /* szR0Mod */
817 "VBoxDDR0.r0",
818 /* pszDescription */
819 "Parallel Communication Port",
820 /* fFlags */
821 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
822 /* fClass */
823 PDM_DEVREG_CLASS_PARALLEL,
824 /* cMaxInstances */
825 2,
826 /* cbInstance */
827 sizeof(PARALLELPORT),
828 /* pfnConstruct */
829 parallelR3Construct,
830 /* pfnDestruct */
831 NULL,
832 /* pfnRelocate */
833 parallelR3Relocate,
834 /* pfnMemSetup */
835 NULL,
836 /* pfnPowerOn */
837 NULL,
838 /* pfnReset */
839 NULL,
840 /* pfnSuspend */
841 NULL,
842 /* pfnResume */
843 NULL,
844 /* pfnAttach */
845 NULL,
846 /* pfnDetach */
847 NULL,
848 /* pfnQueryInterface. */
849 NULL,
850 /* pfnInitComplete */
851 NULL,
852 /* pfnPowerOff */
853 NULL,
854 /* pfnSoftReset */
855 NULL,
856 /* u32VersionEnd */
857 PDM_DEVREG_VERSION
858};
859#endif /* IN_RING3 */
860
861
862#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
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