VirtualBox

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

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

Copyright year updates by scm.

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

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