VirtualBox

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

Last change on this file since 91968 was 90445, checked in by vboxsync, 3 years ago

Dev*: Check PDMDevHlpCritSectEnter return status better. bugref:6695

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 29.5 KB
Line 
1/* $Id: DevParallel.cpp 90445 2021-07-30 22:18:24Z 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 int rc = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VINF_SUCCESS);
307 AssertRCReturn(rc, rc);
308
309 parallelR3IrqSet(pDevIns, pThis);
310
311 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
312
313 return VINF_SUCCESS;
314}
315#endif /* IN_RING3 */
316
317
318/**
319 * @callback_method_impl{FNIOMIOPORTNEWOUT}
320 */
321static DECLCALLBACK(VBOXSTRICTRC)
322parallelIoPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
323{
324 PPARALLELPORT pThis = PDMDEVINS_2_DATA(pDevIns, PPARALLELPORT);
325#ifdef IN_RING3
326 PPARALLELPORTR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PPARALLELPORTR3);
327#endif
328 VBOXSTRICTRC rc = VINF_SUCCESS;
329 RT_NOREF_PV(pvUser);
330
331 if (cb == 1)
332 {
333 uint8_t u8 = u32;
334
335 Log2(("%s: Port=%#06x+%x val %#04x\n", __FUNCTION__, pThis->IOBase, offPort, u32));
336
337 offPort &= 7;
338 switch (offPort)
339 {
340 case 0:
341#ifndef IN_RING3
342 NOREF(u8);
343 rc = VINF_IOM_R3_IOPORT_WRITE;
344#else
345 pThis->regData = u8;
346 if (RT_LIKELY(pThisCC->pDrvHostParallelConnector))
347 {
348 LogFlowFunc(("Set data lines 0x%X\n", u8));
349 rc = pThisCC->pDrvHostParallelConnector->pfnWrite(pThisCC->pDrvHostParallelConnector, &u8, 1, PDM_PARALLEL_PORT_MODE_SPP);
350 AssertRC(VBOXSTRICTRC_VAL(rc));
351 }
352#endif
353 break;
354 case 1:
355 break;
356 case 2:
357 /* Set the reserved bits to one */
358 u8 |= (LPT_CONTROL_BIT6 | LPT_CONTROL_BIT7);
359 if (u8 != pThis->regControl)
360 {
361#ifndef IN_RING3
362 return VINF_IOM_R3_IOPORT_WRITE;
363#else
364 if (RT_LIKELY(pThisCC->pDrvHostParallelConnector))
365 {
366 /* Set data direction. */
367 if (u8 & LPT_CONTROL_ENABLE_BIDIRECT)
368 rc = pThisCC->pDrvHostParallelConnector->pfnSetPortDirection(pThisCC->pDrvHostParallelConnector, false /* fForward */);
369 else
370 rc = pThisCC->pDrvHostParallelConnector->pfnSetPortDirection(pThisCC->pDrvHostParallelConnector, true /* fForward */);
371 AssertRC(VBOXSTRICTRC_VAL(rc));
372
373 u8 &= ~LPT_CONTROL_ENABLE_BIDIRECT; /* Clear bit. */
374
375 rc = pThisCC->pDrvHostParallelConnector->pfnWriteControl(pThisCC->pDrvHostParallelConnector, u8);
376 AssertRC(VBOXSTRICTRC_VAL(rc));
377 }
378 else
379 u8 &= ~LPT_CONTROL_ENABLE_BIDIRECT; /* Clear bit. */
380
381 pThis->regControl = u8;
382#endif
383 }
384 break;
385 case 3:
386#ifndef IN_RING3
387 NOREF(u8);
388 rc = VINF_IOM_R3_IOPORT_WRITE;
389#else
390 pThis->regEppAddr = u8;
391 if (RT_LIKELY(pThisCC->pDrvHostParallelConnector))
392 {
393 LogFlowFunc(("Write EPP address 0x%X\n", u8));
394 rc = pThisCC->pDrvHostParallelConnector->pfnWrite(pThisCC->pDrvHostParallelConnector, &u8, 1, PDM_PARALLEL_PORT_MODE_EPP_ADDR);
395 AssertRC(VBOXSTRICTRC_VAL(rc));
396 }
397#endif
398 break;
399 case 4:
400#ifndef IN_RING3
401 NOREF(u8);
402 rc = VINF_IOM_R3_IOPORT_WRITE;
403#else
404 pThis->regEppData = u8;
405 if (RT_LIKELY(pThisCC->pDrvHostParallelConnector))
406 {
407 LogFlowFunc(("Write EPP data 0x%X\n", u8));
408 rc = pThisCC->pDrvHostParallelConnector->pfnWrite(pThisCC->pDrvHostParallelConnector, &u8, 1, PDM_PARALLEL_PORT_MODE_EPP_DATA);
409 AssertRC(VBOXSTRICTRC_VAL(rc));
410 }
411#endif
412 break;
413 case 5:
414 break;
415 case 6:
416 break;
417 case 7:
418 default:
419 break;
420 }
421 }
422 else
423 ASSERT_GUEST_MSG_FAILED(("Port=%#x+%x cb=%d u32=%#x\n", pThis->IOBase, offPort, cb, u32));
424
425 return rc;
426}
427
428
429/**
430 * @callback_method_impl{FNIOMIOPORTNEWIN}
431 */
432static DECLCALLBACK(VBOXSTRICTRC)
433parallelIoPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
434{
435 PPARALLELPORT pThis = PDMDEVINS_2_DATA(pDevIns, PPARALLELPORT);
436#ifdef IN_RING3
437 PPARALLELPORTR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PPARALLELPORTR3);
438#endif
439 VBOXSTRICTRC rc = VINF_SUCCESS;
440 RT_NOREF_PV(pvUser);
441
442 if (cb == 1)
443 {
444 offPort &= 7;
445 switch (offPort)
446 {
447 case 0:
448 if (!(pThis->regControl & LPT_CONTROL_ENABLE_BIDIRECT))
449 *pu32 = pThis->regData;
450 else
451 {
452#ifndef IN_RING3
453 rc = VINF_IOM_R3_IOPORT_READ;
454#else
455 if (RT_LIKELY(pThisCC->pDrvHostParallelConnector))
456 {
457 rc = pThisCC->pDrvHostParallelConnector->pfnRead(pThisCC->pDrvHostParallelConnector, &pThis->regData,
458 1, PDM_PARALLEL_PORT_MODE_SPP);
459 Log(("Read data lines 0x%X\n", pThis->regData));
460 AssertRC(VBOXSTRICTRC_VAL(rc));
461 }
462 *pu32 = pThis->regData;
463#endif
464 }
465 break;
466 case 1:
467#ifndef IN_RING3
468 rc = VINF_IOM_R3_IOPORT_READ;
469#else
470 if (RT_LIKELY(pThisCC->pDrvHostParallelConnector))
471 {
472 rc = pThisCC->pDrvHostParallelConnector->pfnReadStatus(pThisCC->pDrvHostParallelConnector, &pThis->regStatus);
473 AssertRC(VBOXSTRICTRC_VAL(rc));
474 }
475 *pu32 = pThis->regStatus;
476 parallelR3IrqClear(pDevIns, pThis);
477#endif
478 break;
479 case 2:
480#ifndef IN_RING3
481 rc = VINF_IOM_R3_IOPORT_READ;
482#else
483 if (RT_LIKELY(pThisCC->pDrvHostParallelConnector))
484 {
485 rc = pThisCC->pDrvHostParallelConnector->pfnReadControl(pThisCC->pDrvHostParallelConnector, &pThis->regControl);
486 AssertRC(VBOXSTRICTRC_VAL(rc));
487 pThis->regControl |= LPT_CONTROL_BIT6 | LPT_CONTROL_BIT7;
488 }
489
490 *pu32 = pThis->regControl;
491#endif
492 break;
493 case 3:
494#ifndef IN_RING3
495 rc = VINF_IOM_R3_IOPORT_READ;
496#else
497 if (RT_LIKELY(pThisCC->pDrvHostParallelConnector))
498 {
499 rc = pThisCC->pDrvHostParallelConnector->pfnRead(pThisCC->pDrvHostParallelConnector, &pThis->regEppAddr,
500 1, PDM_PARALLEL_PORT_MODE_EPP_ADDR);
501 Log(("Read EPP address 0x%X\n", pThis->regEppAddr));
502 AssertRC(VBOXSTRICTRC_VAL(rc));
503 }
504 *pu32 = pThis->regEppAddr;
505#endif
506 break;
507 case 4:
508#ifndef IN_RING3
509 rc = VINF_IOM_R3_IOPORT_READ;
510#else
511 if (RT_LIKELY(pThisCC->pDrvHostParallelConnector))
512 {
513 rc = pThisCC->pDrvHostParallelConnector->pfnRead(pThisCC->pDrvHostParallelConnector, &pThis->regEppData,
514 1, PDM_PARALLEL_PORT_MODE_EPP_DATA);
515 Log(("Read EPP data 0x%X\n", pThis->regEppData));
516 AssertRC(VBOXSTRICTRC_VAL(rc));
517 }
518 *pu32 = pThis->regEppData;
519#endif
520 break;
521 case 5:
522 break;
523 case 6:
524 break;
525 case 7:
526 break;
527 }
528 }
529 else
530 rc = VERR_IOM_IOPORT_UNUSED;
531
532 return rc;
533}
534
535#if 0
536/**
537 * @callback_method_impl{FNIOMIOPORTNEWOUT, ECP registers.}
538 */
539static DECLCALLBACK(VBOXSTRICTRC)
540parallelIoPortWriteECP(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
541{
542 PPARALLELPORT pThis = PDMDEVINS_2_DATA(pDevIns, PPARALLELPORT);
543 VBOXSTRICTRC rc = VINF_SUCCESS;
544
545 if (cb == 1)
546 {
547 Log2(("%s: ecp port %#06x+%x val %#04x\n", __FUNCTION__, pThis->IOBase + 0x400, offPort, u32));
548 rc = parallel_ioport_write_ecp(pThis, Port, u32);
549 }
550 else
551 ASSERT_GUEST_MSG_FAILED(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
552
553 return rc;
554}
555
556/**
557 * @callback_method_impl{FNIOMIOPORTNEWOUT, ECP registers.}
558 */
559static DECLCALLBACK(VBOXSTRICTRC)
560parallelIoPortReadECP(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
561{
562 PPARALLELPORT pThis = PDMDEVINS_2_DATA(pDevIns, PPARALLELPORT);
563 VBOXSTRICTRC rc = VINF_SUCCESS;
564
565 if (cb == 1)
566 {
567 *pu32 = parallel_ioport_read_ecp(pThis, Port, &rc);
568 Log2(("%s: ecp port %#06x+%x val %#04x\n", __FUNCTION__, pThis->IOBase + 0x400, offPort, *pu32));
569 }
570 else
571 rc = VERR_IOM_IOPORT_UNUSED;
572
573 return rc;
574}
575#endif
576
577#ifdef IN_RING3
578
579/**
580 * @callback_method_impl{FNSSMDEVLIVEEXEC}
581 */
582static DECLCALLBACK(int) parallelR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
583{
584 PPARALLELPORT pThis = PDMDEVINS_2_DATA(pDevIns, PPARALLELPORT);
585 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
586 RT_NOREF(uPass);
587
588 pHlp->pfnSSMPutS32(pSSM, pThis->iIrq);
589 pHlp->pfnSSMPutU32(pSSM, pThis->IOBase);
590 pHlp->pfnSSMPutU32(pSSM, UINT32_MAX); /* sanity/terminator */
591 return VINF_SSM_DONT_CALL_AGAIN;
592}
593
594
595/**
596 * @callback_method_impl{FNSSMDEVSAVEEXEC}
597 */
598static DECLCALLBACK(int) parallelR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
599{
600 PPARALLELPORT pThis = PDMDEVINS_2_DATA(pDevIns, PPARALLELPORT);
601 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
602
603 pHlp->pfnSSMPutU8(pSSM, pThis->regData);
604 pHlp->pfnSSMPutU8(pSSM, pThis->regStatus);
605 pHlp->pfnSSMPutU8(pSSM, pThis->regControl);
606
607 parallelR3LiveExec(pDevIns, pSSM, 0);
608 return VINF_SUCCESS;
609}
610
611
612/**
613 * @callback_method_impl{FNSSMDEVLOADEXEC}
614 */
615static DECLCALLBACK(int) parallelR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
616{
617 PPARALLELPORT pThis = PDMDEVINS_2_DATA(pDevIns, PPARALLELPORT);
618 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
619
620 AssertMsgReturn(uVersion == PARALLEL_SAVED_STATE_VERSION, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
621 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
622 if (uPass == SSM_PASS_FINAL)
623 {
624 pHlp->pfnSSMGetU8(pSSM, &pThis->regData);
625 pHlp->pfnSSMGetU8(pSSM, &pThis->regStatus);
626 pHlp->pfnSSMGetU8(pSSM, &pThis->regControl);
627 }
628
629 /* the config */
630 int32_t iIrq;
631 pHlp->pfnSSMGetS32(pSSM, &iIrq);
632 uint32_t uIoBase;
633 pHlp->pfnSSMGetU32(pSSM, &uIoBase);
634 uint32_t u32;
635 int rc = pHlp->pfnSSMGetU32(pSSM, &u32);
636 AssertRCReturn(rc, rc);
637 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
638
639 if (pThis->iIrq != iIrq)
640 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("IRQ changed: config=%#x state=%#x"), pThis->iIrq, iIrq);
641
642 if (pThis->IOBase != uIoBase)
643 return pHlp->pfnSSMSetCfgError(pSSM, RT_SRC_POS, N_("IOBase changed: config=%#x state=%#x"), pThis->IOBase, uIoBase);
644
645 return VINF_SUCCESS;
646}
647
648
649/**
650 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
651 */
652static DECLCALLBACK(void *) parallelR3QueryInterface(PPDMIBASE pInterface, const char *pszIID)
653{
654 PPARALLELPORTR3 pThisCC = RT_FROM_MEMBER(pInterface, PARALLELPORTR3, IBase);
655 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->IBase);
656 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTPARALLELPORT, &pThisCC->IHostParallelPort);
657 return NULL;
658}
659
660
661/**
662 * @interface_method_impl{PDMDEVREG,pfnConstruct}
663 */
664static DECLCALLBACK(int) parallelR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
665{
666 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
667 PPARALLELPORT pThis = PDMDEVINS_2_DATA(pDevIns, PPARALLELPORT);
668 PPARALLELPORTR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PPARALLELPORTR3);
669 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
670 int rc;
671
672 Assert(iInstance < 4);
673
674 /*
675 * Init the data.
676 */
677 pThisCC->pDevIns = pDevIns;
678
679 /* IBase */
680 pThisCC->IBase.pfnQueryInterface = parallelR3QueryInterface;
681
682 /* IHostParallelPort */
683 pThisCC->IHostParallelPort.pfnNotifyInterrupt = parallelR3NotifyInterrupt;
684
685 /* Init parallel state */
686 pThis->regData = 0;
687#if 0 /* ECP implementation not complete. */
688 pThis->reg_ecp_ecr = LPT_ECP_ECR_CHIPMODE_COMPAT | LPT_ECP_ECR_FIFO_EMPTY;
689 pThis->act_fifo_pos_read = 0;
690 pThis->act_fifo_pos_write = 0;
691#endif
692
693 /*
694 * Validate and read the configuration.
695 */
696 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "IRQ|IOBase", "");
697
698 rc = pHlp->pfnCFGMQueryS32Def(pCfg, "IRQ", &pThis->iIrq, 7);
699 if (RT_FAILURE(rc))
700 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"IRQ\" value"));
701
702 rc = pHlp->pfnCFGMQueryU16Def(pCfg, "IOBase", &pThis->IOBase, 0x378);
703 if (RT_FAILURE(rc))
704 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"IOBase\" value"));
705
706 int cPorts = (pThis->IOBase == 0x3BC) ? 4 : 8;
707 /*
708 * Register the I/O ports and saved state.
709 */
710 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, pThis->IOBase, cPorts, parallelIoPortWrite, parallelIoPortRead,
711 "Parallel", NULL /*paExtDesc*/, &pThis->hIoPorts);
712 AssertRCReturn(rc, rc);
713
714#if 0
715 /* register ecp registers */
716 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, pThis->IOBase + 0x400, 8, parallelIoPortWriteECP, parallelIoPortReadECP,
717 "Parallel ECP", NULL /*paExtDesc*/, &pThis->hIoPortsEcp);
718 AssertRCReturn(rc, rc);
719#endif
720
721
722 rc = PDMDevHlpSSMRegister3(pDevIns, PARALLEL_SAVED_STATE_VERSION, sizeof(*pThis),
723 parallelR3LiveExec, parallelR3SaveExec, parallelR3LoadExec);
724 AssertRCReturn(rc, rc);
725
726
727 /*
728 * Attach the parallel port driver and get the interfaces.
729 * For now no run-time changes are supported.
730 */
731 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThisCC->IBase, &pThisCC->pDrvBase, "Parallel Host");
732 if (RT_SUCCESS(rc))
733 {
734 pThisCC->pDrvHostParallelConnector = PDMIBASE_QUERY_INTERFACE(pThisCC->pDrvBase, PDMIHOSTPARALLELCONNECTOR);
735
736 /* Set compatibility mode */
737 //pThisCC->pDrvHostParallelConnector->pfnSetMode(pThisCC->pDrvHostParallelConnector, PDM_PARALLEL_PORT_MODE_COMPAT);
738 /* Get status of control register */
739 pThisCC->pDrvHostParallelConnector->pfnReadControl(pThisCC->pDrvHostParallelConnector, &pThis->regControl);
740
741 AssertMsgReturn(pThisCC->pDrvHostParallelConnector,
742 ("Configuration error: instance %d has no host parallel interface!\n", iInstance),
743 VERR_PDM_MISSING_INTERFACE);
744 }
745 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
746 {
747 pThisCC->pDrvBase = NULL;
748 pThisCC->pDrvHostParallelConnector = NULL;
749 LogRel(("Parallel%d: no unit\n", iInstance));
750 }
751 else
752 AssertMsgFailedReturn(("Parallel%d: Failed to attach to host driver. rc=%Rrc\n", iInstance, rc),
753 PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
754 N_("Parallel device %d cannot attach to host driver"), iInstance));
755
756 return VINF_SUCCESS;
757}
758
759#else /* !IN_RING3 */
760
761/**
762 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
763 */
764static DECLCALLBACK(int) parallelRZConstruct(PPDMDEVINS pDevIns)
765{
766 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
767 PPARALLELPORT pThis = PDMDEVINS_2_DATA(pDevIns, PPARALLELPORT);
768
769 int rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPorts, parallelIoPortWrite, parallelIoPortRead, NULL /*pvUser*/);
770 AssertRCReturn(rc, rc);
771
772# if 0
773 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pThis->hIoPortsEcp, parallelIoPortWriteECP, parallelIoPortReadECP, NULL /*pvUser*/);
774 AssertRCReturn(rc, rc);
775# endif
776
777 return VINF_SUCCESS;
778}
779
780#endif /* !IN_RING3 */
781
782/**
783 * The device registration structure.
784 */
785const PDMDEVREG g_DeviceParallelPort =
786{
787 /* .u32Version = */ PDM_DEVREG_VERSION,
788 /* .uReserved0 = */ 0,
789 /* .szName = */ "parallel",
790 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
791 /* .fClass = */ PDM_DEVREG_CLASS_PARALLEL,
792 /* .cMaxInstances = */ 2,
793 /* .uSharedVersion = */ 42,
794 /* .cbInstanceShared = */ sizeof(PARALLELPORT),
795 /* .cbInstanceCC = */ CTX_EXPR(sizeof(PARALLELPORTR3), 0, 0),
796 /* .cbInstanceRC = */ 0,
797 /* .cMaxPciDevices = */ 0,
798 /* .cMaxMsixVectors = */ 0,
799 /* .pszDescription = */ "Parallel Communication Port",
800#if defined(IN_RING3)
801 /* .pszRCMod = */ "VBoxDDRC.rc",
802 /* .pszR0Mod = */ "VBoxDDR0.r0",
803 /* .pfnConstruct = */ parallelR3Construct,
804 /* .pfnDestruct = */ NULL,
805 /* .pfnRelocate = */ NULL,
806 /* .pfnMemSetup = */ NULL,
807 /* .pfnPowerOn = */ NULL,
808 /* .pfnReset = */ NULL,
809 /* .pfnSuspend = */ NULL,
810 /* .pfnResume = */ NULL,
811 /* .pfnAttach = */ NULL,
812 /* .pfnDetach = */ NULL,
813 /* .pfnQueryInterface = */ NULL,
814 /* .pfnInitComplete = */ NULL,
815 /* .pfnPowerOff = */ NULL,
816 /* .pfnSoftReset = */ NULL,
817 /* .pfnReserved0 = */ NULL,
818 /* .pfnReserved1 = */ NULL,
819 /* .pfnReserved2 = */ NULL,
820 /* .pfnReserved3 = */ NULL,
821 /* .pfnReserved4 = */ NULL,
822 /* .pfnReserved5 = */ NULL,
823 /* .pfnReserved6 = */ NULL,
824 /* .pfnReserved7 = */ NULL,
825#elif defined(IN_RING0)
826 /* .pfnEarlyConstruct = */ NULL,
827 /* .pfnConstruct = */ parallelRZConstruct,
828 /* .pfnDestruct = */ NULL,
829 /* .pfnFinalDestruct = */ NULL,
830 /* .pfnRequest = */ NULL,
831 /* .pfnReserved0 = */ NULL,
832 /* .pfnReserved1 = */ NULL,
833 /* .pfnReserved2 = */ NULL,
834 /* .pfnReserved3 = */ NULL,
835 /* .pfnReserved4 = */ NULL,
836 /* .pfnReserved5 = */ NULL,
837 /* .pfnReserved6 = */ NULL,
838 /* .pfnReserved7 = */ NULL,
839#elif defined(IN_RC)
840 /* .pfnConstruct = */ parallelRZConstruct,
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#else
850# error "Not in IN_RING3, IN_RING0 or IN_RC!"
851#endif
852 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
853};
854
855#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
856
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