VirtualBox

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

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

Corrected a bunch of HC and GC uses in status codes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 31.8 KB
Line 
1/* $Id: DevParallel.cpp 40280 2012-02-28 19:47:00Z 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-2007 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 parallelIrqSet(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 parallelIrqClear(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
305static DECLCALLBACK(int) parallelNotifyInterrupt(PPDMIHOSTPARALLELPORT pInterface)
306{
307 PARALLELPORT *pThis = PDMIHOSTPARALLELPORT_2_PARALLELPORT(pInterface);
308
309 PDMCritSectEnter(&pThis->CritSect, VINF_SUCCESS);
310 parallelIrqSet(pThis);
311 PDMCritSectLeave(&pThis->CritSect);
312
313 return VINF_SUCCESS;
314}
315#endif /* IN_RING3 */
316
317/**
318 * Port I/O Handler for OUT operations.
319 *
320 * @returns VBox status code.
321 *
322 * @param pDevIns The device instance.
323 * @param pvUser User argument.
324 * @param Port Port number used for the IN operation.
325 * @param u32 The value to output.
326 * @param cb The value size in bytes.
327 */
328PDMBOTHCBDECL(int) parallelIOPortWrite(PPDMDEVINS pDevIns, void *pvUser,
329 RTIOPORT Port, uint32_t u32, unsigned cb)
330{
331 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PPARALLELPORT);
332 int rc = VINF_SUCCESS;
333
334 if (cb == 1)
335 {
336 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_R3_IOPORT_WRITE);
337 if (rc == VINF_SUCCESS)
338 {
339 uint8_t u8 = u32;
340
341 Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, u32));
342
343 Port &= 7;
344 switch(Port)
345 {
346 case 0:
347#ifndef IN_RING3
348 NOREF(u8);
349 rc = VINF_IOM_R3_IOPORT_WRITE;
350#else
351 pThis->regData = u8;
352 if (RT_LIKELY(pThis->pDrvHostParallelConnector))
353 {
354 LogFlowFunc(("Set data lines 0x%X\n", u8));
355 rc = pThis->pDrvHostParallelConnector->pfnWrite(pThis->pDrvHostParallelConnector, &u8, 1, PDM_PARALLEL_PORT_MODE_SPP);
356 AssertRC(rc);
357 }
358#endif
359 break;
360 case 1:
361 break;
362 case 2:
363 /* Set the reserved bits to one */
364 u8 |= (LPT_CONTROL_BIT6 | LPT_CONTROL_BIT7);
365 if (u8 != pThis->regControl)
366 {
367#ifndef IN_RING3
368 return VINF_IOM_R3_IOPORT_WRITE;
369#else
370 /* Set data direction. */
371 if (u8 & LPT_CONTROL_ENABLE_BIDIRECT)
372 rc = pThis->pDrvHostParallelConnector->pfnSetPortDirection(pThis->pDrvHostParallelConnector, false /* fForward */);
373 else
374 rc = pThis->pDrvHostParallelConnector->pfnSetPortDirection(pThis->pDrvHostParallelConnector, true /* fForward */);
375 AssertRC(rc);
376 u8 &= ~LPT_CONTROL_ENABLE_BIDIRECT; /* Clear bit. */
377
378 rc = pThis->pDrvHostParallelConnector->pfnWriteControl(pThis->pDrvHostParallelConnector, u8);
379 AssertRC(rc);
380 pThis->regControl = u8;
381#endif
382 }
383 break;
384 case 3:
385#ifndef IN_RING3
386 NOREF(u8);
387 rc = VINF_IOM_R3_IOPORT_WRITE;
388#else
389 pThis->regEppAddr = u8;
390 if (RT_LIKELY(pThis->pDrvHostParallelConnector))
391 {
392 LogFlowFunc(("Write EPP address 0x%X\n", u8));
393 rc = pThis->pDrvHostParallelConnector->pfnWrite(pThis->pDrvHostParallelConnector, &u8, 1, PDM_PARALLEL_PORT_MODE_EPP_ADDR);
394 AssertRC(rc);
395 }
396#endif
397 break;
398 case 4:
399#ifndef IN_RING3
400 NOREF(u8);
401 rc = VINF_IOM_R3_IOPORT_WRITE;
402#else
403 pThis->regEppData = u8;
404 if (RT_LIKELY(pThis->pDrvHostParallelConnector))
405 {
406 LogFlowFunc(("Write EPP data 0x%X\n", u8));
407 rc = pThis->pDrvHostParallelConnector->pfnWrite(pThis->pDrvHostParallelConnector, &u8, 1, PDM_PARALLEL_PORT_MODE_EPP_DATA);
408 AssertRC(rc);
409 }
410#endif
411 break;
412 case 5:
413 break;
414 case 6:
415 break;
416 case 7:
417 default:
418 break;
419 }
420 PDMCritSectLeave(&pThis->CritSect);
421 }
422 }
423 else
424 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
425
426 return rc;
427}
428
429/**
430 * Port I/O Handler for IN operations.
431 *
432 * @returns VBox status code.
433 *
434 * @param pDevIns The device instance.
435 * @param pvUser User argument.
436 * @param Port Port number used for the IN operation.
437 * @param pu32 Where to return the read value.
438 * @param cb The value size in bytes.
439 */
440PDMBOTHCBDECL(int) parallelIOPortRead(PPDMDEVINS pDevIns, void *pvUser,
441 RTIOPORT Port, uint32_t *pu32, unsigned cb)
442{
443 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
444 int rc = VINF_SUCCESS;
445
446 if (cb == 1)
447 {
448 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_R3_IOPORT_READ);
449 if (rc == VINF_SUCCESS)
450 {
451 Port &= 7;
452 switch(Port)
453 {
454 case 0:
455 if (!(pThis->regControl & LPT_CONTROL_ENABLE_BIDIRECT))
456 *pu32 = pThis->regData;
457 else
458 {
459#ifndef IN_RING3
460 rc = VINF_IOM_R3_IOPORT_READ;
461#else
462 if (RT_LIKELY(pThis->pDrvHostParallelConnector))
463 {
464 rc = pThis->pDrvHostParallelConnector->pfnRead(pThis->pDrvHostParallelConnector, &pThis->regData,
465 1, PDM_PARALLEL_PORT_MODE_SPP);
466 Log(("Read data lines 0x%X\n", pThis->regData));
467 AssertRC(rc);
468 }
469 *pu32 = pThis->regData;
470#endif
471 }
472 break;
473 case 1:
474#ifndef IN_RING3
475 rc = VINF_IOM_R3_IOPORT_READ;
476#else
477 if (RT_LIKELY(pThis->pDrvHostParallelConnector))
478 {
479 rc = pThis->pDrvHostParallelConnector->pfnReadStatus(pThis->pDrvHostParallelConnector, &pThis->regStatus);
480 AssertRC(rc);
481 }
482 *pu32 = pThis->regStatus;
483 parallelIrqClear(pThis);
484#endif
485 break;
486 case 2:
487#ifndef IN_RING3
488 rc = VINF_IOM_R3_IOPORT_READ;
489#else
490 rc = pThis->pDrvHostParallelConnector->pfnReadControl(pThis->pDrvHostParallelConnector, &pThis->regControl);
491 AssertRC(rc);
492 pThis->regControl |= LPT_CONTROL_BIT6 | LPT_CONTROL_BIT7;
493 *pu32 = pThis->regControl;
494#endif
495 break;
496 case 3:
497#ifndef IN_RING3
498 rc = VINF_IOM_R3_IOPORT_READ;
499#else
500 if (RT_LIKELY(pThis->pDrvHostParallelConnector))
501 {
502 rc = pThis->pDrvHostParallelConnector->pfnRead(pThis->pDrvHostParallelConnector, &pThis->regEppAddr,
503 1, PDM_PARALLEL_PORT_MODE_EPP_ADDR);
504 Log(("Read EPP address 0x%X\n", pThis->regEppAddr));
505 AssertRC(rc);
506 }
507 *pu32 = pThis->regEppAddr;
508#endif
509 break;
510 case 4:
511#ifndef IN_RING3
512 rc = VINF_IOM_R3_IOPORT_READ;
513#else
514 if (RT_LIKELY(pThis->pDrvHostParallelConnector))
515 {
516 rc = pThis->pDrvHostParallelConnector->pfnRead(pThis->pDrvHostParallelConnector, &pThis->regEppData,
517 1, PDM_PARALLEL_PORT_MODE_EPP_DATA);
518 Log(("Read EPP data 0x%X\n", pThis->regEppData));
519 AssertRC(rc);
520 }
521 *pu32 = pThis->regEppData;
522#endif
523 break;
524 case 5:
525 break;
526 case 6:
527 break;
528 case 7:
529 break;
530 }
531 PDMCritSectLeave(&pThis->CritSect);
532 }
533 }
534 else
535 rc = VERR_IOM_IOPORT_UNUSED;
536
537 return rc;
538}
539
540#if 0
541/**
542 * Port I/O Handler for OUT operations on ECP registers.
543 *
544 * @returns VBox status code.
545 *
546 * @param pDevIns The device instance.
547 * @param pvUser User argument.
548 * @param Port Port number used for the IN operation.
549 * @param u32 The value to output.
550 * @param cb The value size in bytes.
551 */
552PDMBOTHCBDECL(int) parallelIOPortWriteECP(PPDMDEVINS pDevIns, void *pvUser,
553 RTIOPORT Port, uint32_t u32, unsigned cb)
554{
555 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
556 int rc = VINF_SUCCESS;
557
558 if (cb == 1)
559 {
560 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_R3_IOPORT_WRITE);
561 if (rc == VINF_SUCCESS)
562 {
563 Log2(("%s: ecp port %#06x val %#04x\n", __FUNCTION__, Port, u32));
564 rc = parallel_ioport_write_ecp (pThis, Port, u32);
565 PDMCritSectLeave(&pThis->CritSect);
566 }
567 }
568 else
569 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
570
571 return rc;
572}
573
574/**
575 * Port I/O Handler for IN operations on ECP registers.
576 *
577 * @returns VBox status code.
578 *
579 * @param pDevIns The device instance.
580 * @param pvUser User argument.
581 * @param Port Port number used for the IN operation.
582 * @param u32 The value to output.
583 * @param cb The value size in bytes.
584 */
585PDMBOTHCBDECL(int) parallelIOPortReadECP(PPDMDEVINS pDevIns, void *pvUser,
586 RTIOPORT Port, uint32_t *pu32, unsigned cb)
587{
588 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
589 int rc = VINF_SUCCESS;
590
591 if (cb == 1)
592 {
593 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_R3_IOPORT_READ);
594 if (rc == VINF_SUCCESS)
595 {
596 *pu32 = parallel_ioport_read_ecp (pThis, Port, &rc);
597 Log2(("%s: ecp port %#06x val %#04x\n", __FUNCTION__, Port, *pu32));
598 PDMCritSectLeave(&pThis->CritSect);
599 }
600 }
601 else
602 rc = VERR_IOM_IOPORT_UNUSED;
603
604 return rc;
605}
606#endif
607
608#ifdef IN_RING3
609/**
610 * @copydoc FNSSMDEVLIVEEXEC
611 */
612static DECLCALLBACK(int) parallelLiveExec(PPDMDEVINS pDevIns,
613 PSSMHANDLE pSSM,
614 uint32_t uPass)
615{
616 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
617
618 SSMR3PutS32(pSSM, pThis->iIrq);
619 SSMR3PutU32(pSSM, pThis->IOBase);
620 SSMR3PutU32(pSSM, ~0); /* sanity/terminator */
621 return VINF_SSM_DONT_CALL_AGAIN;
622}
623
624/**
625 * @copydoc FNSSMDEVSAVEEXEC
626 */
627static DECLCALLBACK(int) parallelSaveExec(PPDMDEVINS pDevIns,
628 PSSMHANDLE pSSM)
629{
630 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
631
632 SSMR3PutU8(pSSM, pThis->regData);
633 SSMR3PutU8(pSSM, pThis->regStatus);
634 SSMR3PutU8(pSSM, pThis->regControl);
635
636 parallelLiveExec(pDevIns, pSSM, 0);
637 return VINF_SUCCESS;
638}
639
640/**
641 * @copydoc FNSSMDEVLOADEXEC
642 */
643static DECLCALLBACK(int) parallelLoadExec(PPDMDEVINS pDevIns,
644 PSSMHANDLE pSSM,
645 uint32_t uVersion,
646 uint32_t uPass)
647{
648 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
649
650 AssertMsgReturn(uVersion == PARALLEL_SAVED_STATE_VERSION, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
651 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
652 if (uPass == SSM_PASS_FINAL)
653 {
654 SSMR3GetU8(pSSM, &pThis->regData);
655 SSMR3GetU8(pSSM, &pThis->regStatus);
656 SSMR3GetU8(pSSM, &pThis->regControl);
657 }
658
659 /* the config */
660 int32_t iIrq;
661 SSMR3GetS32(pSSM, &iIrq);
662 uint32_t uIoBase;
663 SSMR3GetU32(pSSM, &uIoBase);
664 uint32_t u32;
665 int rc = SSMR3GetU32(pSSM, &u32);
666 if (RT_FAILURE(rc))
667 return rc;
668 AssertMsgReturn(u32 == ~0U, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
669
670 if (pThis->iIrq != iIrq)
671 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("IRQ changed: config=%#x state=%#x"), pThis->iIrq, iIrq);
672
673 if (pThis->IOBase != uIoBase)
674 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("IOBase changed: config=%#x state=%#x"), pThis->IOBase, uIoBase);
675
676 /* not necessary... but it doesn't harm. */
677 pThis->pDevInsR3 = pDevIns;
678 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
679 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
680 return VINF_SUCCESS;
681}
682
683
684/**
685 * @copydoc FNPDMDEVRELOCATE
686 */
687static DECLCALLBACK(void) parallelRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
688{
689 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
690 pThis->pDevInsRC += offDelta;
691}
692
693/**
694 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
695 */
696static DECLCALLBACK(void *) parallelQueryInterface(PPDMIBASE pInterface, const char *pszIID)
697{
698 PARALLELPORT *pThis = PDMIBASE_2_PARALLELPORT(pInterface);
699 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
700 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTPARALLELPORT, &pThis->IHostParallelPort);
701 return NULL;
702}
703
704/**
705 * Destruct a device instance.
706 *
707 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
708 * resources can be freed correctly.
709 *
710 * @returns VBox status.
711 * @param pDevIns The device instance data.
712 */
713static DECLCALLBACK(int) parallelDestruct(PPDMDEVINS pDevIns)
714{
715 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
716 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
717
718 PDMR3CritSectDelete(&pThis->CritSect);
719
720 return VINF_SUCCESS;
721}
722
723
724/**
725 * @interface_method_impl{PDMDEVREG,pfnConstruct}
726 */
727static DECLCALLBACK(int) parallelConstruct(PPDMDEVINS pDevIns,
728 int iInstance,
729 PCFGMNODE pCfg)
730{
731 int rc;
732 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT*);
733
734 Assert(iInstance < 4);
735 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
736
737 /*
738 * Init the data so parallelDestruct doesn't choke.
739 */
740 pThis->pDevInsR3 = pDevIns;
741 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
742 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
743
744 /* IBase */
745 pThis->IBase.pfnQueryInterface = parallelQueryInterface;
746
747 /* IHostParallelPort */
748 pThis->IHostParallelPort.pfnNotifyInterrupt = parallelNotifyInterrupt;
749
750 /* Init parallel state */
751 pThis->regData = 0;
752#if 0 /* ECP implementation not complete. */
753 pThis->reg_ecp_ecr = LPT_ECP_ECR_CHIPMODE_COMPAT | LPT_ECP_ECR_FIFO_EMPTY;
754 pThis->act_fifo_pos_read = 0;
755 pThis->act_fifo_pos_write = 0;
756#endif
757
758 /*
759 * Validate and read the configuration.
760 */
761 if (!CFGMR3AreValuesValid(pCfg, "IRQ\0" "IOBase\0" "GCEnabled\0" "R0Enabled\0"))
762 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
763 N_("Configuration error: Unknown config key"));
764
765 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fGCEnabled, false);
766 if (RT_FAILURE(rc))
767 return PDMDEV_SET_ERROR(pDevIns, rc,
768 N_("Configuration error: Failed to get the \"GCEnabled\" value"));
769
770 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, false);
771 if (RT_FAILURE(rc))
772 return PDMDEV_SET_ERROR(pDevIns, rc,
773 N_("Configuration error: Failed to get the \"R0Enabled\" value"));
774 rc = CFGMR3QueryS32Def(pCfg, "IRQ", &pThis->iIrq, 7);
775 if (RT_FAILURE(rc))
776 return PDMDEV_SET_ERROR(pDevIns, rc,
777 N_("Configuration error: Failed to get the \"IRQ\" value"));
778 rc = CFGMR3QueryU16Def(pCfg, "IOBase", &pThis->IOBase, 0x378);
779 if (RT_FAILURE(rc))
780 return PDMDEV_SET_ERROR(pDevIns, rc,
781 N_("Configuration error: Failed to get the \"IOBase\" value"));
782
783 /*
784 * Initialize critical section and event semaphore.
785 * This must of course be done before attaching drivers or anything else which can call us back..
786 */
787 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "Parallel#%u", iInstance);
788 if (RT_FAILURE(rc))
789 return rc;
790
791 /*
792 * Register the I/O ports and saved state.
793 */
794 rc = PDMDevHlpIOPortRegister(pDevIns, pThis->IOBase, 8, 0,
795 parallelIOPortWrite, parallelIOPortRead,
796 NULL, NULL, "Parallel");
797 if (RT_FAILURE(rc))
798 return rc;
799
800#if 0
801 /* register ecp registers */
802 rc = PDMDevHlpIOPortRegister(pDevIns, io_base+0x400, 8, 0,
803 parallelIOPortWriteECP, parallelIOPortReadECP,
804 NULL, NULL, "PARALLEL ECP");
805 if (RT_FAILURE(rc))
806 return rc;
807#endif
808
809 if (pThis->fGCEnabled)
810 {
811 rc = PDMDevHlpIOPortRegisterRC(pDevIns, pThis->IOBase, 8, 0, "parallelIOPortWrite",
812 "parallelIOPortRead", NULL, NULL, "Parallel");
813 if (RT_FAILURE(rc))
814 return rc;
815
816#if 0
817 rc = PDMDevHlpIOPortRegisterGC(pDevIns, io_base+0x400, 8, 0, "parallelIOPortWriteECP",
818 "parallelIOPortReadECP", NULL, NULL, "Parallel Ecp");
819 if (RT_FAILURE(rc))
820 return rc;
821#endif
822 }
823
824 if (pThis->fR0Enabled)
825 {
826 rc = PDMDevHlpIOPortRegisterR0(pDevIns, pThis->IOBase, 8, 0, "parallelIOPortWrite",
827 "parallelIOPortRead", NULL, NULL, "Parallel");
828 if (RT_FAILURE(rc))
829 return rc;
830
831#if 0
832 rc = PDMDevHlpIOPortRegisterR0(pDevIns, io_base+0x400, 8, 0, "parallelIOPortWriteECP",
833 "parallelIOPortReadECP", NULL, NULL, "Parallel Ecp");
834 if (RT_FAILURE(rc))
835 return rc;
836#endif
837 }
838
839 rc = PDMDevHlpSSMRegister3(pDevIns, PARALLEL_SAVED_STATE_VERSION, sizeof(*pThis),
840 parallelLiveExec, parallelSaveExec, parallelLoadExec);
841 if (RT_FAILURE(rc))
842 return rc;
843
844
845 /*
846 * Attach the parallel port driver and get the interfaces.
847 * For now no run-time changes are supported.
848 */
849 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Parallel Host");
850 if (RT_SUCCESS(rc))
851 {
852 pThis->pDrvHostParallelConnector = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIHOSTPARALLELCONNECTOR);
853 AssertMsgReturn(pThis->pDrvHostParallelConnector,
854 ("Configuration error: instance %d has no host parallel interface!\n", iInstance),
855 VERR_PDM_MISSING_INTERFACE);
856 }
857 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
858 {
859 pThis->pDrvBase = NULL;
860 pThis->pDrvHostParallelConnector = NULL;
861 LogRel(("Parallel%d: no unit\n", iInstance));
862 }
863 else
864 {
865 AssertMsgFailed(("Parallel%d: Failed to attach to host driver. rc=%Rrc\n", iInstance, rc));
866 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
867 N_("Parallel device %d cannot attach to host driver"), iInstance);
868 }
869
870 /* Set compatibility mode */
871 //pThis->pDrvHostParallelConnector->pfnSetMode(pThis->pDrvHostParallelConnector, PDM_PARALLEL_PORT_MODE_COMPAT);
872 /* Get status of control register */
873 pThis->pDrvHostParallelConnector->pfnReadControl(pThis->pDrvHostParallelConnector, &pThis->regControl);
874
875 return VINF_SUCCESS;
876}
877
878/**
879 * The device registration structure.
880 */
881const PDMDEVREG g_DeviceParallelPort =
882{
883 /* u32Version */
884 PDM_DEVREG_VERSION,
885 /* szName */
886 "parallel",
887 /* szRCMod */
888 "VBoxDDGC.gc",
889 /* szR0Mod */
890 "VBoxDDR0.r0",
891 /* pszDescription */
892 "Parallel Communication Port",
893 /* fFlags */
894 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
895 /* fClass */
896 PDM_DEVREG_CLASS_PARALLEL,
897 /* cMaxInstances */
898 1,
899 /* cbInstance */
900 sizeof(PARALLELPORT),
901 /* pfnConstruct */
902 parallelConstruct,
903 /* pfnDestruct */
904 parallelDestruct,
905 /* pfnRelocate */
906 parallelRelocate,
907 /* pfnIOCtl */
908 NULL,
909 /* pfnPowerOn */
910 NULL,
911 /* pfnReset */
912 NULL,
913 /* pfnSuspend */
914 NULL,
915 /* pfnResume */
916 NULL,
917 /* pfnAttach */
918 NULL,
919 /* pfnDetach */
920 NULL,
921 /* pfnQueryInterface. */
922 NULL,
923 /* pfnInitComplete */
924 NULL,
925 /* pfnPowerOff */
926 NULL,
927 /* pfnSoftReset */
928 NULL,
929 /* u32VersionEnd */
930 PDM_DEVREG_VERSION
931};
932#endif /* IN_RING3 */
933
934
935#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use