VirtualBox

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

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

Devices/Parallel: Added more debug statements for enhanced logging.. Need to give debug build to user for debugging. Will revert the changes soon.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 32.0 KB
Line 
1/* $Id: DevParallel.cpp 43383 2012-09-21 08:12:41Z 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 LogFlow(("Read Status \n"));
478 if (RT_LIKELY(pThis->pDrvHostParallelConnector))
479 {
480 LogFlow(("Call to Read Status \n"));
481 rc = pThis->pDrvHostParallelConnector->pfnReadStatus(pThis->pDrvHostParallelConnector, &pThis->regStatus);
482 AssertRC(rc);
483 }
484 *pu32 = pThis->regStatus;
485
486 LogFlow(("Call to parallel IRQ . Status=%d\n", *pu32));
487 parallelIrqClear(pThis);
488#endif
489 break;
490 case 2:
491#ifndef IN_RING3
492 rc = VINF_IOM_R3_IOPORT_READ;
493#else
494 rc = pThis->pDrvHostParallelConnector->pfnReadControl(pThis->pDrvHostParallelConnector, &pThis->regControl);
495 AssertRC(rc);
496 pThis->regControl |= LPT_CONTROL_BIT6 | LPT_CONTROL_BIT7;
497 *pu32 = pThis->regControl;
498#endif
499 break;
500 case 3:
501#ifndef IN_RING3
502 rc = VINF_IOM_R3_IOPORT_READ;
503#else
504 if (RT_LIKELY(pThis->pDrvHostParallelConnector))
505 {
506 rc = pThis->pDrvHostParallelConnector->pfnRead(pThis->pDrvHostParallelConnector, &pThis->regEppAddr,
507 1, PDM_PARALLEL_PORT_MODE_EPP_ADDR);
508 Log(("Read EPP address 0x%X\n", pThis->regEppAddr));
509 AssertRC(rc);
510 }
511 *pu32 = pThis->regEppAddr;
512#endif
513 break;
514 case 4:
515#ifndef IN_RING3
516 rc = VINF_IOM_R3_IOPORT_READ;
517#else
518 if (RT_LIKELY(pThis->pDrvHostParallelConnector))
519 {
520 rc = pThis->pDrvHostParallelConnector->pfnRead(pThis->pDrvHostParallelConnector, &pThis->regEppData,
521 1, PDM_PARALLEL_PORT_MODE_EPP_DATA);
522 Log(("Read EPP data 0x%X\n", pThis->regEppData));
523 AssertRC(rc);
524 }
525 *pu32 = pThis->regEppData;
526#endif
527 break;
528 case 5:
529 break;
530 case 6:
531 break;
532 case 7:
533 break;
534 }
535 PDMCritSectLeave(&pThis->CritSect);
536 }
537 }
538 else
539 rc = VERR_IOM_IOPORT_UNUSED;
540
541 return rc;
542}
543
544#if 0
545/**
546 * Port I/O Handler for OUT operations on ECP registers.
547 *
548 * @returns VBox status code.
549 *
550 * @param pDevIns The device instance.
551 * @param pvUser User argument.
552 * @param Port Port number used for the IN operation.
553 * @param u32 The value to output.
554 * @param cb The value size in bytes.
555 */
556PDMBOTHCBDECL(int) parallelIOPortWriteECP(PPDMDEVINS pDevIns, void *pvUser,
557 RTIOPORT Port, uint32_t u32, unsigned cb)
558{
559 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
560 int rc = VINF_SUCCESS;
561
562 if (cb == 1)
563 {
564 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_R3_IOPORT_WRITE);
565 if (rc == VINF_SUCCESS)
566 {
567 Log2(("%s: ecp port %#06x val %#04x\n", __FUNCTION__, Port, u32));
568 rc = parallel_ioport_write_ecp (pThis, Port, u32);
569 PDMCritSectLeave(&pThis->CritSect);
570 }
571 }
572 else
573 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
574
575 return rc;
576}
577
578/**
579 * Port I/O Handler for IN operations on ECP registers.
580 *
581 * @returns VBox status code.
582 *
583 * @param pDevIns The device instance.
584 * @param pvUser User argument.
585 * @param Port Port number used for the IN operation.
586 * @param u32 The value to output.
587 * @param cb The value size in bytes.
588 */
589PDMBOTHCBDECL(int) parallelIOPortReadECP(PPDMDEVINS pDevIns, void *pvUser,
590 RTIOPORT Port, uint32_t *pu32, unsigned cb)
591{
592 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
593 int rc = VINF_SUCCESS;
594
595 if (cb == 1)
596 {
597 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_R3_IOPORT_READ);
598 if (rc == VINF_SUCCESS)
599 {
600 *pu32 = parallel_ioport_read_ecp (pThis, Port, &rc);
601 Log2(("%s: ecp port %#06x val %#04x\n", __FUNCTION__, Port, *pu32));
602 PDMCritSectLeave(&pThis->CritSect);
603 }
604 }
605 else
606 rc = VERR_IOM_IOPORT_UNUSED;
607
608 return rc;
609}
610#endif
611
612#ifdef IN_RING3
613/**
614 * @copydoc FNSSMDEVLIVEEXEC
615 */
616static DECLCALLBACK(int) parallelLiveExec(PPDMDEVINS pDevIns,
617 PSSMHANDLE pSSM,
618 uint32_t uPass)
619{
620 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
621
622 SSMR3PutS32(pSSM, pThis->iIrq);
623 SSMR3PutU32(pSSM, pThis->IOBase);
624 SSMR3PutU32(pSSM, ~0); /* sanity/terminator */
625 return VINF_SSM_DONT_CALL_AGAIN;
626}
627
628/**
629 * @copydoc FNSSMDEVSAVEEXEC
630 */
631static DECLCALLBACK(int) parallelSaveExec(PPDMDEVINS pDevIns,
632 PSSMHANDLE pSSM)
633{
634 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
635
636 SSMR3PutU8(pSSM, pThis->regData);
637 SSMR3PutU8(pSSM, pThis->regStatus);
638 SSMR3PutU8(pSSM, pThis->regControl);
639
640 parallelLiveExec(pDevIns, pSSM, 0);
641 return VINF_SUCCESS;
642}
643
644/**
645 * @copydoc FNSSMDEVLOADEXEC
646 */
647static DECLCALLBACK(int) parallelLoadExec(PPDMDEVINS pDevIns,
648 PSSMHANDLE pSSM,
649 uint32_t uVersion,
650 uint32_t uPass)
651{
652 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
653
654 AssertMsgReturn(uVersion == PARALLEL_SAVED_STATE_VERSION, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
655 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
656 if (uPass == SSM_PASS_FINAL)
657 {
658 SSMR3GetU8(pSSM, &pThis->regData);
659 SSMR3GetU8(pSSM, &pThis->regStatus);
660 SSMR3GetU8(pSSM, &pThis->regControl);
661 }
662
663 /* the config */
664 int32_t iIrq;
665 SSMR3GetS32(pSSM, &iIrq);
666 uint32_t uIoBase;
667 SSMR3GetU32(pSSM, &uIoBase);
668 uint32_t u32;
669 int rc = SSMR3GetU32(pSSM, &u32);
670 if (RT_FAILURE(rc))
671 return rc;
672 AssertMsgReturn(u32 == ~0U, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
673
674 if (pThis->iIrq != iIrq)
675 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("IRQ changed: config=%#x state=%#x"), pThis->iIrq, iIrq);
676
677 if (pThis->IOBase != uIoBase)
678 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("IOBase changed: config=%#x state=%#x"), pThis->IOBase, uIoBase);
679
680 /* not necessary... but it doesn't harm. */
681 pThis->pDevInsR3 = pDevIns;
682 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
683 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
684 return VINF_SUCCESS;
685}
686
687
688/**
689 * @copydoc FNPDMDEVRELOCATE
690 */
691static DECLCALLBACK(void) parallelRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
692{
693 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
694 pThis->pDevInsRC += offDelta;
695}
696
697/**
698 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
699 */
700static DECLCALLBACK(void *) parallelQueryInterface(PPDMIBASE pInterface, const char *pszIID)
701{
702 PARALLELPORT *pThis = PDMIBASE_2_PARALLELPORT(pInterface);
703 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
704 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTPARALLELPORT, &pThis->IHostParallelPort);
705 return NULL;
706}
707
708/**
709 * Destruct a device instance.
710 *
711 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
712 * resources can be freed correctly.
713 *
714 * @returns VBox status.
715 * @param pDevIns The device instance data.
716 */
717static DECLCALLBACK(int) parallelDestruct(PPDMDEVINS pDevIns)
718{
719 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT *);
720 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
721
722 PDMR3CritSectDelete(&pThis->CritSect);
723
724 return VINF_SUCCESS;
725}
726
727
728/**
729 * @interface_method_impl{PDMDEVREG,pfnConstruct}
730 */
731static DECLCALLBACK(int) parallelConstruct(PPDMDEVINS pDevIns,
732 int iInstance,
733 PCFGMNODE pCfg)
734{
735 int rc;
736 PARALLELPORT *pThis = PDMINS_2_DATA(pDevIns, PARALLELPORT*);
737
738 Assert(iInstance < 4);
739 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
740
741 /*
742 * Init the data so parallelDestruct doesn't choke.
743 */
744 pThis->pDevInsR3 = pDevIns;
745 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
746 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
747
748 /* IBase */
749 pThis->IBase.pfnQueryInterface = parallelQueryInterface;
750
751 /* IHostParallelPort */
752 pThis->IHostParallelPort.pfnNotifyInterrupt = parallelNotifyInterrupt;
753
754 /* Init parallel state */
755 pThis->regData = 0;
756#if 0 /* ECP implementation not complete. */
757 pThis->reg_ecp_ecr = LPT_ECP_ECR_CHIPMODE_COMPAT | LPT_ECP_ECR_FIFO_EMPTY;
758 pThis->act_fifo_pos_read = 0;
759 pThis->act_fifo_pos_write = 0;
760#endif
761
762 /*
763 * Validate and read the configuration.
764 */
765 if (!CFGMR3AreValuesValid(pCfg, "IRQ\0" "IOBase\0" "GCEnabled\0" "R0Enabled\0"))
766 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
767 N_("Configuration error: Unknown config key"));
768
769 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fGCEnabled, false);
770 if (RT_FAILURE(rc))
771 return PDMDEV_SET_ERROR(pDevIns, rc,
772 N_("Configuration error: Failed to get the \"GCEnabled\" value"));
773
774 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, false);
775 if (RT_FAILURE(rc))
776 return PDMDEV_SET_ERROR(pDevIns, rc,
777 N_("Configuration error: Failed to get the \"R0Enabled\" value"));
778 rc = CFGMR3QueryS32Def(pCfg, "IRQ", &pThis->iIrq, 7);
779 if (RT_FAILURE(rc))
780 return PDMDEV_SET_ERROR(pDevIns, rc,
781 N_("Configuration error: Failed to get the \"IRQ\" value"));
782 rc = CFGMR3QueryU16Def(pCfg, "IOBase", &pThis->IOBase, 0x378);
783 if (RT_FAILURE(rc))
784 return PDMDEV_SET_ERROR(pDevIns, rc,
785 N_("Configuration error: Failed to get the \"IOBase\" value"));
786
787 /*
788 * Initialize critical section and event semaphore.
789 * This must of course be done before attaching drivers or anything else which can call us back..
790 */
791 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "Parallel#%u", iInstance);
792 if (RT_FAILURE(rc))
793 return rc;
794
795 /*
796 * Register the I/O ports and saved state.
797 */
798 rc = PDMDevHlpIOPortRegister(pDevIns, pThis->IOBase, 8, 0,
799 parallelIOPortWrite, parallelIOPortRead,
800 NULL, NULL, "Parallel");
801 if (RT_FAILURE(rc))
802 return rc;
803
804#if 0
805 /* register ecp registers */
806 rc = PDMDevHlpIOPortRegister(pDevIns, io_base+0x400, 8, 0,
807 parallelIOPortWriteECP, parallelIOPortReadECP,
808 NULL, NULL, "PARALLEL ECP");
809 if (RT_FAILURE(rc))
810 return rc;
811#endif
812
813 if (pThis->fGCEnabled)
814 {
815 rc = PDMDevHlpIOPortRegisterRC(pDevIns, pThis->IOBase, 8, 0, "parallelIOPortWrite",
816 "parallelIOPortRead", NULL, NULL, "Parallel");
817 if (RT_FAILURE(rc))
818 return rc;
819
820#if 0
821 rc = PDMDevHlpIOPortRegisterGC(pDevIns, io_base+0x400, 8, 0, "parallelIOPortWriteECP",
822 "parallelIOPortReadECP", NULL, NULL, "Parallel Ecp");
823 if (RT_FAILURE(rc))
824 return rc;
825#endif
826 }
827
828 if (pThis->fR0Enabled)
829 {
830 rc = PDMDevHlpIOPortRegisterR0(pDevIns, pThis->IOBase, 8, 0, "parallelIOPortWrite",
831 "parallelIOPortRead", NULL, NULL, "Parallel");
832 if (RT_FAILURE(rc))
833 return rc;
834
835#if 0
836 rc = PDMDevHlpIOPortRegisterR0(pDevIns, io_base+0x400, 8, 0, "parallelIOPortWriteECP",
837 "parallelIOPortReadECP", NULL, NULL, "Parallel Ecp");
838 if (RT_FAILURE(rc))
839 return rc;
840#endif
841 }
842
843 rc = PDMDevHlpSSMRegister3(pDevIns, PARALLEL_SAVED_STATE_VERSION, sizeof(*pThis),
844 parallelLiveExec, parallelSaveExec, parallelLoadExec);
845 if (RT_FAILURE(rc))
846 return rc;
847
848
849 /*
850 * Attach the parallel port driver and get the interfaces.
851 * For now no run-time changes are supported.
852 */
853 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Parallel Host");
854 if (RT_SUCCESS(rc))
855 {
856 pThis->pDrvHostParallelConnector = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIHOSTPARALLELCONNECTOR);
857 AssertMsgReturn(pThis->pDrvHostParallelConnector,
858 ("Configuration error: instance %d has no host parallel interface!\n", iInstance),
859 VERR_PDM_MISSING_INTERFACE);
860 }
861 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
862 {
863 pThis->pDrvBase = NULL;
864 pThis->pDrvHostParallelConnector = NULL;
865 LogRel(("Parallel%d: no unit\n", iInstance));
866 }
867 else
868 {
869 AssertMsgFailed(("Parallel%d: Failed to attach to host driver. rc=%Rrc\n", iInstance, rc));
870 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
871 N_("Parallel device %d cannot attach to host driver"), iInstance);
872 }
873
874 /* Set compatibility mode */
875 //pThis->pDrvHostParallelConnector->pfnSetMode(pThis->pDrvHostParallelConnector, PDM_PARALLEL_PORT_MODE_COMPAT);
876 /* Get status of control register */
877 pThis->pDrvHostParallelConnector->pfnReadControl(pThis->pDrvHostParallelConnector, &pThis->regControl);
878
879 return VINF_SUCCESS;
880}
881
882/**
883 * The device registration structure.
884 */
885const PDMDEVREG g_DeviceParallelPort =
886{
887 /* u32Version */
888 PDM_DEVREG_VERSION,
889 /* szName */
890 "parallel",
891 /* szRCMod */
892 "VBoxDDGC.gc",
893 /* szR0Mod */
894 "VBoxDDR0.r0",
895 /* pszDescription */
896 "Parallel Communication Port",
897 /* fFlags */
898 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
899 /* fClass */
900 PDM_DEVREG_CLASS_PARALLEL,
901 /* cMaxInstances */
902 1,
903 /* cbInstance */
904 sizeof(PARALLELPORT),
905 /* pfnConstruct */
906 parallelConstruct,
907 /* pfnDestruct */
908 parallelDestruct,
909 /* pfnRelocate */
910 parallelRelocate,
911 /* pfnIOCtl */
912 NULL,
913 /* pfnPowerOn */
914 NULL,
915 /* pfnReset */
916 NULL,
917 /* pfnSuspend */
918 NULL,
919 /* pfnResume */
920 NULL,
921 /* pfnAttach */
922 NULL,
923 /* pfnDetach */
924 NULL,
925 /* pfnQueryInterface. */
926 NULL,
927 /* pfnInitComplete */
928 NULL,
929 /* pfnPowerOff */
930 NULL,
931 /* pfnSoftReset */
932 NULL,
933 /* u32VersionEnd */
934 PDM_DEVREG_VERSION
935};
936#endif /* IN_RING3 */
937
938
939#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