VirtualBox

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

Last change on this file since 44700 was 44700, checked in by vboxsync, 12 years ago

DevParallel.cpp: General cleanups.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 30.2 KB
Line 
1/* $Id: DevParallel.cpp 44700 2013-02-14 20:17: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-2012 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* Header Files *
23*******************************************************************************/
24#define LOG_GROUP LOG_GROUP_DEV_PARALLEL
25#include <VBox/vmm/pdmdev.h>
26#include <iprt/assert.h>
27#include <iprt/uuid.h>
28#include <iprt/string.h>
29#include <iprt/semaphore.h>
30#include <iprt/critsect.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 /** Access critical section. */
100 PDMCRITSECT CritSect;
101
102 /** Pointer to the device instance - R3 Ptr */
103 PPDMDEVINSR3 pDevInsR3;
104 /** Pointer to the device instance - R0 Ptr */
105 PPDMDEVINSR0 pDevInsR0;
106 /** Pointer to the device instance - RC Ptr */
107 PPDMDEVINSRC pDevInsRC;
108 /** Alignment. */
109 RTRCPTR Alignment0;
110 /** LUN\#0: The base interface. */
111 PDMIBASE IBase;
112 /** LUN\#0: The host device port interface. */
113 PDMIHOSTPARALLELPORT IHostParallelPort;
114 /** Pointer to the attached base driver. */
115 R3PTRTYPE(PPDMIBASE) pDrvBase;
116 /** Pointer to the attached host device. */
117 R3PTRTYPE(PPDMIHOSTPARALLELCONNECTOR) pDrvHostParallelConnector;
118 /** Flag whether the device has its RC component enabled. */
119 bool fGCEnabled;
120 /** Flag whether the device has its R0 component enabled. */
121 bool fR0Enabled;
122 /** Flag whether an EPP timeout occurred (error handling). */
123 bool fEppTimeout;
124 /** Base I/O port of the parallel port. */
125 RTIOPORT IOBase;
126 /** IRQ number assigned ot the parallel port. */
127 int iIrq;
128 /** Data register. */
129 uint8_t regData;
130 /** Status register. */
131 uint8_t regStatus;
132 /** Control register. */
133 uint8_t regControl;
134 /** EPP address register. */
135 uint8_t regEppAddr;
136 /** EPP data register. */
137 uint8_t regEppData;
138 /** More alignment. */
139 uint32_t u32Alignment;
140
141#if 0 /* Data for ECP implementation, currently unused. */
142 uint8_t reg_ecp_ecr;
143 uint8_t reg_ecp_base_plus_400h; /* has different meanings */
144 uint8_t reg_ecp_config_b;
145
146 /** The ECP FIFO implementation*/
147 uint8_t ecp_fifo[LPT_ECP_FIFO_DEPTH];
148 uint8_t abAlignemnt[2];
149 int act_fifo_pos_write;
150 int act_fifo_pos_read;
151#endif
152} PARALLELPORT, *PPARALLELPORT;
153
154#ifndef VBOX_DEVICE_STRUCT_TESTCASE
155
156#define PDMIHOSTPARALLELPORT_2_PARALLELPORT(pInstance) ( (PARALLELPORT *)((uintptr_t)(pInterface) - RT_OFFSETOF(PARALLELPORT, IHostParallelPort)) )
157#define PDMIHOSTDEVICEPORT_2_PARALLELPORT(pInstance) ( (PARALLELPORT *)((uintptr_t)(pInterface) - RT_OFFSETOF(PARALLELPORT, IHostDevicePort)) )
158#define PDMIBASE_2_PARALLELPORT(pInstance) ( (PARALLELPORT *)((uintptr_t)(pInterface) - RT_OFFSETOF(PARALLELPORT, IBase)) )
159
160
161/*******************************************************************************
162* Internal Functions *
163*******************************************************************************/
164RT_C_DECLS_BEGIN
165PDMBOTHCBDECL(int) parallelIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
166PDMBOTHCBDECL(int) parallelIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
167#if 0
168PDMBOTHCBDECL(int) parallelIOPortReadECP(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
169PDMBOTHCBDECL(int) parallelIOPortWriteECP(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
170#endif
171RT_C_DECLS_END
172
173
174#ifdef IN_RING3
175static void parallelR3IrqSet(PARALLELPORT *pThis)
176{
177 if (pThis->regControl & LPT_CONTROL_ENABLE_IRQ_VIA_ACK)
178 {
179 LogFlowFunc(("%d 1\n", pThis->iIrq));
180 PDMDevHlpISASetIrqNoWait(pThis->CTX_SUFF(pDevIns), pThis->iIrq, 1);
181 }
182}
183
184static void parallelR3IrqClear(PARALLELPORT *pThis)
185{
186 LogFlowFunc(("%d 0\n", pThis->iIrq));
187 PDMDevHlpISASetIrqNoWait(pThis->CTX_SUFF(pDevIns), pThis->iIrq, 0);
188}
189#endif
190
191#if 0
192static int parallel_ioport_write_ecp(void *opaque, uint32_t addr, uint32_t val)
193{
194 PARALLELPORT *s = (PARALLELPORT *)opaque;
195 unsigned char ch;
196
197 addr &= 7;
198 LogFlow(("parallel: write ecp addr=0x%02x val=0x%02x\n", addr, val));
199 ch = val;
200 switch (addr) {
201 default:
202 case 0:
203 if (LPT_ECP_ECR_CHIPMODE_GET_BITS(s->reg_ecp_ecr) == LPT_ECP_ECR_CHIPMODE_FIFO_TEST) {
204 s->ecp_fifo[s->act_fifo_pos_write] = ch;
205 s->act_fifo_pos_write++;
206 if (s->act_fifo_pos_write < LPT_ECP_FIFO_DEPTH) {
207 /* FIFO has some data (clear both FIFO bits) */
208 s->reg_ecp_ecr &= ~(LPT_ECP_ECR_FIFO_EMPTY | LPT_ECP_ECR_FIFO_FULL);
209 } else {
210 /* FIFO is full */
211 /* Clear FIFO empty bit */
212 s->reg_ecp_ecr &= ~LPT_ECP_ECR_FIFO_EMPTY;
213 /* Set FIFO full bit */
214 s->reg_ecp_ecr |= LPT_ECP_ECR_FIFO_FULL;
215 s->act_fifo_pos_write = 0;
216 }
217 } else {
218 s->reg_ecp_base_plus_400h = ch;
219 }
220 break;
221 case 1:
222 s->reg_ecp_config_b = ch;
223 break;
224 case 2:
225 /* If we change the mode clear FIFO */
226 if ((ch & LPT_ECP_ECR_CHIPMODE_MASK) != (s->reg_ecp_ecr & LPT_ECP_ECR_CHIPMODE_MASK)) {
227 /* reset the fifo */
228 s->act_fifo_pos_write = 0;
229 s->act_fifo_pos_read = 0;
230 /* Set FIFO empty bit */
231 s->reg_ecp_ecr |= LPT_ECP_ECR_FIFO_EMPTY;
232 /* Clear FIFO full bit */
233 s->reg_ecp_ecr &= ~LPT_ECP_ECR_FIFO_FULL;
234 }
235 /* Set new mode */
236 s->reg_ecp_ecr |= LPT_ECP_ECR_CHIPMODE_SET_BITS(LPT_ECP_ECR_CHIPMODE_GET_BITS(ch));
237 break;
238 case 3:
239 break;
240 case 4:
241 break;
242 case 5:
243 break;
244 case 6:
245 break;
246 case 7:
247 break;
248 }
249 return VINF_SUCCESS;
250}
251
252static uint32_t parallel_ioport_read_ecp(void *opaque, uint32_t addr, int *pRC)
253{
254 PARALLELPORT *s = (PARALLELPORT *)opaque;
255 uint32_t ret = ~0U;
256
257 *pRC = VINF_SUCCESS;
258
259 addr &= 7;
260 switch (addr) {
261 default:
262 case 0:
263 if (LPT_ECP_ECR_CHIPMODE_GET_BITS(s->reg_ecp_ecr) == LPT_ECP_ECR_CHIPMODE_FIFO_TEST) {
264 ret = s->ecp_fifo[s->act_fifo_pos_read];
265 s->act_fifo_pos_read++;
266 if (s->act_fifo_pos_read == LPT_ECP_FIFO_DEPTH)
267 s->act_fifo_pos_read = 0; /* end of FIFO, start at beginning */
268 if (s->act_fifo_pos_read == s->act_fifo_pos_write) {
269 /* FIFO is empty */
270 /* Set FIFO empty bit */
271 s->reg_ecp_ecr |= LPT_ECP_ECR_FIFO_EMPTY;
272 /* Clear FIFO full bit */
273 s->reg_ecp_ecr &= ~LPT_ECP_ECR_FIFO_FULL;
274 } else {
275 /* FIFO has some data (clear all FIFO bits) */
276 s->reg_ecp_ecr &= ~(LPT_ECP_ECR_FIFO_EMPTY | LPT_ECP_ECR_FIFO_FULL);
277 }
278 } else {
279 ret = s->reg_ecp_base_plus_400h;
280 }
281 break;
282 case 1:
283 ret = s->reg_ecp_config_b;
284 break;
285 case 2:
286 ret = s->reg_ecp_ecr;
287 break;
288 case 3:
289 break;
290 case 4:
291 break;
292 case 5:
293 break;
294 case 6:
295 break;
296 case 7:
297 break;
298 }
299 LogFlow(("parallel: read ecp addr=0x%02x val=0x%02x\n", addr, ret));
300 return ret;
301}
302#endif
303
304#ifdef IN_RING3
305/**
306 * @interface_methods_impl{PDMIHOSTPARALLELPORT,pfnNotifyInterrupt}
307 */
308static DECLCALLBACK(int) parallelR3NotifyInterrupt(PPDMIHOSTPARALLELPORT pInterface)
309{
310 PARALLELPORT *pThis = PDMIHOSTPARALLELPORT_2_PARALLELPORT(pInterface);
311
312 PDMCritSectEnter(&pThis->CritSect, VINF_SUCCESS);
313 parallelR3IrqSet(pThis);
314 PDMCritSectLeave(&pThis->CritSect);
315
316 return VINF_SUCCESS;
317}
318#endif /* IN_RING3 */
319
320
321/**
322 * @callback_method_impl{FNIOMIOPORTOUT}
323 */
324PDMBOTHCBDECL(int) parallelIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
325{
326 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PPARALLELPORT);
327 int rc = VINF_SUCCESS;
328
329 if (cb == 1)
330 {
331 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_R3_IOPORT_WRITE);
332 if (rc == VINF_SUCCESS)
333 {
334 uint8_t u8 = u32;
335
336 Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, u32));
337
338 Port &= 7;
339 switch (Port)
340 {
341 case 0:
342#ifndef IN_RING3
343 NOREF(u8);
344 rc = VINF_IOM_R3_IOPORT_WRITE;
345#else
346 pThis->regData = u8;
347 if (RT_LIKELY(pThis->pDrvHostParallelConnector))
348 {
349 LogFlowFunc(("Set data lines 0x%X\n", u8));
350 rc = pThis->pDrvHostParallelConnector->pfnWrite(pThis->pDrvHostParallelConnector, &u8, 1, PDM_PARALLEL_PORT_MODE_SPP);
351 AssertRC(rc);
352 }
353#endif
354 break;
355 case 1:
356 break;
357 case 2:
358 /* Set the reserved bits to one */
359 u8 |= (LPT_CONTROL_BIT6 | LPT_CONTROL_BIT7);
360 if (u8 != pThis->regControl)
361 {
362#ifndef IN_RING3
363 return VINF_IOM_R3_IOPORT_WRITE;
364#else
365 /* Set data direction. */
366 if (u8 & LPT_CONTROL_ENABLE_BIDIRECT)
367 rc = pThis->pDrvHostParallelConnector->pfnSetPortDirection(pThis->pDrvHostParallelConnector, false /* fForward */);
368 else
369 rc = pThis->pDrvHostParallelConnector->pfnSetPortDirection(pThis->pDrvHostParallelConnector, true /* fForward */);
370 AssertRC(rc);
371 u8 &= ~LPT_CONTROL_ENABLE_BIDIRECT; /* Clear bit. */
372
373 rc = pThis->pDrvHostParallelConnector->pfnWriteControl(pThis->pDrvHostParallelConnector, u8);
374 AssertRC(rc);
375 pThis->regControl = u8;
376#endif
377 }
378 break;
379 case 3:
380#ifndef IN_RING3
381 NOREF(u8);
382 rc = VINF_IOM_R3_IOPORT_WRITE;
383#else
384 pThis->regEppAddr = u8;
385 if (RT_LIKELY(pThis->pDrvHostParallelConnector))
386 {
387 LogFlowFunc(("Write EPP address 0x%X\n", u8));
388 rc = pThis->pDrvHostParallelConnector->pfnWrite(pThis->pDrvHostParallelConnector, &u8, 1, PDM_PARALLEL_PORT_MODE_EPP_ADDR);
389 AssertRC(rc);
390 }
391#endif
392 break;
393 case 4:
394#ifndef IN_RING3
395 NOREF(u8);
396 rc = VINF_IOM_R3_IOPORT_WRITE;
397#else
398 pThis->regEppData = u8;
399 if (RT_LIKELY(pThis->pDrvHostParallelConnector))
400 {
401 LogFlowFunc(("Write EPP data 0x%X\n", u8));
402 rc = pThis->pDrvHostParallelConnector->pfnWrite(pThis->pDrvHostParallelConnector, &u8, 1, PDM_PARALLEL_PORT_MODE_EPP_DATA);
403 AssertRC(rc);
404 }
405#endif
406 break;
407 case 5:
408 break;
409 case 6:
410 break;
411 case 7:
412 default:
413 break;
414 }
415 PDMCritSectLeave(&pThis->CritSect);
416 }
417 }
418 else
419 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
420
421 return rc;
422}
423
424
425/**
426 * @callback_method_impl{FNIOMIOPORTIN}
427 */
428PDMBOTHCBDECL(int) parallelIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
429{
430 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
431 int rc = VINF_SUCCESS;
432
433 if (cb == 1)
434 {
435 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_R3_IOPORT_READ);
436 if (rc == VINF_SUCCESS)
437 {
438 Port &= 7;
439 switch (Port)
440 {
441 case 0:
442 if (!(pThis->regControl & LPT_CONTROL_ENABLE_BIDIRECT))
443 *pu32 = pThis->regData;
444 else
445 {
446#ifndef IN_RING3
447 rc = VINF_IOM_R3_IOPORT_READ;
448#else
449 if (RT_LIKELY(pThis->pDrvHostParallelConnector))
450 {
451 rc = pThis->pDrvHostParallelConnector->pfnRead(pThis->pDrvHostParallelConnector, &pThis->regData,
452 1, PDM_PARALLEL_PORT_MODE_SPP);
453 Log(("Read data lines 0x%X\n", pThis->regData));
454 AssertRC(rc);
455 }
456 *pu32 = pThis->regData;
457#endif
458 }
459 break;
460 case 1:
461#ifndef IN_RING3
462 rc = VINF_IOM_R3_IOPORT_READ;
463#else
464 if (RT_LIKELY(pThis->pDrvHostParallelConnector))
465 {
466 rc = pThis->pDrvHostParallelConnector->pfnReadStatus(pThis->pDrvHostParallelConnector, &pThis->regStatus);
467 AssertRC(rc);
468 }
469 *pu32 = pThis->regStatus;
470 parallelR3IrqClear(pThis);
471#endif
472 break;
473 case 2:
474#ifndef IN_RING3
475 rc = VINF_IOM_R3_IOPORT_READ;
476#else
477 rc = pThis->pDrvHostParallelConnector->pfnReadControl(pThis->pDrvHostParallelConnector, &pThis->regControl);
478 AssertRC(rc);
479 pThis->regControl |= LPT_CONTROL_BIT6 | LPT_CONTROL_BIT7;
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 PDMCritSectLeave(&pThis->CritSect);
519 }
520 }
521 else
522 rc = VERR_IOM_IOPORT_UNUSED;
523
524 return rc;
525}
526
527#if 0
528/**
529 * @callback_method_impl{FNIOMIOPORTOUT, ECP registers.}
530 */
531PDMBOTHCBDECL(int) parallelIOPortWriteECP(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
532{
533 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
534 int rc = VINF_SUCCESS;
535
536 if (cb == 1)
537 {
538 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_R3_IOPORT_WRITE);
539 if (rc == VINF_SUCCESS)
540 {
541 Log2(("%s: ecp port %#06x val %#04x\n", __FUNCTION__, Port, u32));
542 rc = parallel_ioport_write_ecp (pThis, Port, u32);
543 PDMCritSectLeave(&pThis->CritSect);
544 }
545 }
546 else
547 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
548
549 return rc;
550}
551
552/**
553 * @callback_method_impl{FNIOMIOPORTOUT, ECP registers.}
554 */
555PDMBOTHCBDECL(int) parallelIOPortReadECP(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
556{
557 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
558 int rc = VINF_SUCCESS;
559
560 if (cb == 1)
561 {
562 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_R3_IOPORT_READ);
563 if (rc == VINF_SUCCESS)
564 {
565 *pu32 = parallel_ioport_read_ecp (pThis, Port, &rc);
566 Log2(("%s: ecp port %#06x val %#04x\n", __FUNCTION__, Port, *pu32));
567 PDMCritSectLeave(&pThis->CritSect);
568 }
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 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
585
586 SSMR3PutS32(pSSM, pThis->iIrq);
587 SSMR3PutU32(pSSM, pThis->IOBase);
588 SSMR3PutU32(pSSM, ~0); /* sanity/terminator */
589 return VINF_SSM_DONT_CALL_AGAIN;
590}
591
592
593/**
594 * @callback_method_impl{FNSSMDEVSAVEEXEC}
595 */
596static DECLCALLBACK(int) parallelR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
597{
598 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
599
600 SSMR3PutU8(pSSM, pThis->regData);
601 SSMR3PutU8(pSSM, pThis->regStatus);
602 SSMR3PutU8(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 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
615
616 AssertMsgReturn(uVersion == PARALLEL_SAVED_STATE_VERSION, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
617 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
618 if (uPass == SSM_PASS_FINAL)
619 {
620 SSMR3GetU8(pSSM, &pThis->regData);
621 SSMR3GetU8(pSSM, &pThis->regStatus);
622 SSMR3GetU8(pSSM, &pThis->regControl);
623 }
624
625 /* the config */
626 int32_t iIrq;
627 SSMR3GetS32(pSSM, &iIrq);
628 uint32_t uIoBase;
629 SSMR3GetU32(pSSM, &uIoBase);
630 uint32_t u32;
631 int rc = SSMR3GetU32(pSSM, &u32);
632 if (RT_FAILURE(rc))
633 return rc;
634 AssertMsgReturn(u32 == ~0U, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
635
636 if (pThis->iIrq != iIrq)
637 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("IRQ changed: config=%#x state=%#x"), pThis->iIrq, iIrq);
638
639 if (pThis->IOBase != uIoBase)
640 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("IOBase changed: config=%#x state=%#x"), pThis->IOBase, uIoBase);
641
642 /* not necessary... but it doesn't harm. */
643 pThis->pDevInsR3 = pDevIns;
644 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
645 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
646 return VINF_SUCCESS;
647}
648
649
650/**
651 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
652 */
653static DECLCALLBACK(void *) parallelR3QueryInterface(PPDMIBASE pInterface, const char *pszIID)
654{
655 PARALLELPORT *pThis = PDMIBASE_2_PARALLELPORT(pInterface);
656 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
657 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTPARALLELPORT, &pThis->IHostParallelPort);
658 return NULL;
659}
660
661
662/**
663 * @copydoc FNPDMDEVRELOCATE
664 */
665static DECLCALLBACK(void) parallelR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
666{
667 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
668 pThis->pDevInsRC += offDelta;
669}
670
671
672/**
673 * @interface_method_impl{PDMDEVREG,pfnDestruct}
674 */
675static DECLCALLBACK(int) parallelR3Destruct(PPDMDEVINS pDevIns)
676{
677 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
678 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
679
680 PDMR3CritSectDelete(&pThis->CritSect);
681
682 return VINF_SUCCESS;
683}
684
685
686/**
687 * @interface_method_impl{PDMDEVREG,pfnConstruct}
688 */
689static DECLCALLBACK(int) parallelR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
690{
691 int rc;
692 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT*);
693
694 Assert(iInstance < 4);
695 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
696
697 /*
698 * Init the data so parallelR3Destruct doesn't choke.
699 */
700 pThis->pDevInsR3 = pDevIns;
701 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
702 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
703
704 /* IBase */
705 pThis->IBase.pfnQueryInterface = parallelR3QueryInterface;
706
707 /* IHostParallelPort */
708 pThis->IHostParallelPort.pfnNotifyInterrupt = parallelR3NotifyInterrupt;
709
710 /* Init parallel state */
711 pThis->regData = 0;
712#if 0 /* ECP implementation not complete. */
713 pThis->reg_ecp_ecr = LPT_ECP_ECR_CHIPMODE_COMPAT | LPT_ECP_ECR_FIFO_EMPTY;
714 pThis->act_fifo_pos_read = 0;
715 pThis->act_fifo_pos_write = 0;
716#endif
717
718 /*
719 * Validate and read the configuration.
720 */
721 if (!CFGMR3AreValuesValid(pCfg, "IRQ\0" "IOBase\0" "GCEnabled\0" "R0Enabled\0"))
722 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
723 N_("Configuration error: Unknown config key"));
724
725 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fGCEnabled, false);
726 if (RT_FAILURE(rc))
727 return PDMDEV_SET_ERROR(pDevIns, rc,
728 N_("Configuration error: Failed to get the \"GCEnabled\" value"));
729
730 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, false);
731 if (RT_FAILURE(rc))
732 return PDMDEV_SET_ERROR(pDevIns, rc,
733 N_("Configuration error: Failed to get the \"R0Enabled\" value"));
734 rc = CFGMR3QueryS32Def(pCfg, "IRQ", &pThis->iIrq, 7);
735 if (RT_FAILURE(rc))
736 return PDMDEV_SET_ERROR(pDevIns, rc,
737 N_("Configuration error: Failed to get the \"IRQ\" value"));
738 rc = CFGMR3QueryU16Def(pCfg, "IOBase", &pThis->IOBase, 0x378);
739 if (RT_FAILURE(rc))
740 return PDMDEV_SET_ERROR(pDevIns, rc,
741 N_("Configuration error: Failed to get the \"IOBase\" value"));
742
743 /*
744 * Initialize critical section and event semaphore.
745 * This must of course be done before attaching drivers or anything else which can call us back..
746 */
747 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "Parallel#%u", iInstance);
748 if (RT_FAILURE(rc))
749 return rc;
750
751 /*
752 * Register the I/O ports and saved state.
753 */
754 rc = PDMDevHlpIOPortRegister(pDevIns, pThis->IOBase, 8, 0,
755 parallelIOPortWrite, parallelIOPortRead,
756 NULL, NULL, "Parallel");
757 if (RT_FAILURE(rc))
758 return rc;
759
760#if 0
761 /* register ecp registers */
762 rc = PDMDevHlpIOPortRegister(pDevIns, io_base+0x400, 8, 0,
763 parallelIOPortWriteECP, parallelIOPortReadECP,
764 NULL, NULL, "PARALLEL ECP");
765 if (RT_FAILURE(rc))
766 return rc;
767#endif
768
769 if (pThis->fGCEnabled)
770 {
771 rc = PDMDevHlpIOPortRegisterRC(pDevIns, pThis->IOBase, 8, 0, "parallelIOPortWrite",
772 "parallelIOPortRead", NULL, NULL, "Parallel");
773 if (RT_FAILURE(rc))
774 return rc;
775
776#if 0
777 rc = PDMDevHlpIOPortRegisterGC(pDevIns, io_base+0x400, 8, 0, "parallelIOPortWriteECP",
778 "parallelIOPortReadECP", NULL, NULL, "Parallel Ecp");
779 if (RT_FAILURE(rc))
780 return rc;
781#endif
782 }
783
784 if (pThis->fR0Enabled)
785 {
786 rc = PDMDevHlpIOPortRegisterR0(pDevIns, pThis->IOBase, 8, 0, "parallelIOPortWrite",
787 "parallelIOPortRead", NULL, NULL, "Parallel");
788 if (RT_FAILURE(rc))
789 return rc;
790
791#if 0
792 rc = PDMDevHlpIOPortRegisterR0(pDevIns, io_base+0x400, 8, 0, "parallelIOPortWriteECP",
793 "parallelIOPortReadECP", NULL, NULL, "Parallel Ecp");
794 if (RT_FAILURE(rc))
795 return rc;
796#endif
797 }
798
799 rc = PDMDevHlpSSMRegister3(pDevIns, PARALLEL_SAVED_STATE_VERSION, sizeof(*pThis),
800 parallelR3LiveExec, parallelR3SaveExec, parallelR3LoadExec);
801 if (RT_FAILURE(rc))
802 return rc;
803
804
805 /*
806 * Attach the parallel port driver and get the interfaces.
807 * For now no run-time changes are supported.
808 */
809 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Parallel Host");
810 if (RT_SUCCESS(rc))
811 {
812 pThis->pDrvHostParallelConnector = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIHOSTPARALLELCONNECTOR);
813 AssertMsgReturn(pThis->pDrvHostParallelConnector,
814 ("Configuration error: instance %d has no host parallel interface!\n", iInstance),
815 VERR_PDM_MISSING_INTERFACE);
816 }
817 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
818 {
819 pThis->pDrvBase = NULL;
820 pThis->pDrvHostParallelConnector = NULL;
821 LogRel(("Parallel%d: no unit\n", iInstance));
822 }
823 else
824 {
825 AssertMsgFailed(("Parallel%d: Failed to attach to host driver. rc=%Rrc\n", iInstance, rc));
826 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
827 N_("Parallel device %d cannot attach to host driver"), iInstance);
828 }
829
830 /* Set compatibility mode */
831 //pThis->pDrvHostParallelConnector->pfnSetMode(pThis->pDrvHostParallelConnector, PDM_PARALLEL_PORT_MODE_COMPAT);
832 /* Get status of control register */
833 pThis->pDrvHostParallelConnector->pfnReadControl(pThis->pDrvHostParallelConnector, &pThis->regControl);
834
835 return VINF_SUCCESS;
836}
837
838/**
839 * The device registration structure.
840 */
841const PDMDEVREG g_DeviceParallelPort =
842{
843 /* u32Version */
844 PDM_DEVREG_VERSION,
845 /* szName */
846 "parallel",
847 /* szRCMod */
848 "VBoxDDGC.gc",
849 /* szR0Mod */
850 "VBoxDDR0.r0",
851 /* pszDescription */
852 "Parallel Communication Port",
853 /* fFlags */
854 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
855 /* fClass */
856 PDM_DEVREG_CLASS_PARALLEL,
857 /* cMaxInstances */
858 1,
859 /* cbInstance */
860 sizeof(PARALLELPORT),
861 /* pfnConstruct */
862 parallelR3Construct,
863 /* pfnDestruct */
864 parallelR3Destruct,
865 /* pfnRelocate */
866 parallelR3Relocate,
867 /* pfnIOCtl */
868 NULL,
869 /* pfnPowerOn */
870 NULL,
871 /* pfnReset */
872 NULL,
873 /* pfnSuspend */
874 NULL,
875 /* pfnResume */
876 NULL,
877 /* pfnAttach */
878 NULL,
879 /* pfnDetach */
880 NULL,
881 /* pfnQueryInterface. */
882 NULL,
883 /* pfnInitComplete */
884 NULL,
885 /* pfnPowerOff */
886 NULL,
887 /* pfnSoftReset */
888 NULL,
889 /* u32VersionEnd */
890 PDM_DEVREG_VERSION
891};
892#endif /* IN_RING3 */
893
894
895#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
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