VirtualBox

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

Last change on this file since 12649 was 11284, checked in by vboxsync, 16 years ago

Devices: %Vrc -> %Rrc (just preferred, not mandatory (yet))

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 29.6 KB
Line 
1/* $Id: DevParallel.cpp 11284 2008-08-08 22:32:08Z 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 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
21 * Clara, CA 95054 USA or visit http://www.sun.com if you need
22 * additional information or have any questions.
23 */
24
25/*******************************************************************************
26* Header Files *
27*******************************************************************************/
28#define LOG_GROUP LOG_GROUP_DEV_PARALLEL
29#include <VBox/pdmdev.h>
30#include <iprt/assert.h>
31#include <iprt/uuid.h>
32#include <iprt/string.h>
33#include <iprt/semaphore.h>
34#include <iprt/critsect.h>
35
36#include "../Builtins.h"
37
38
39/*******************************************************************************
40* Defined Constants And Macros *
41*******************************************************************************/
42#define PARALLEL_SAVED_STATE_VERSION 1
43
44/* defines for accessing the register bits */
45#define LPT_STATUS_BUSY 0x80
46#define LPT_STATUS_ACK 0x40
47#define LPT_STATUS_PAPER_OUT 0x20
48#define LPT_STATUS_SELECT_IN 0x10
49#define LPT_STATUS_ERROR 0x08
50#define LPT_STATUS_IRQ 0x04
51#define LPT_STATUS_BIT1 0x02 /* reserved (only for completeness) */
52#define LPT_STATUS_EPP_TIMEOUT 0x01
53
54#define LPT_CONTROL_BIT7 0x80 /* reserved (only for completeness) */
55#define LPT_CONTROL_BIT6 0x40 /* reserved (only for completeness) */
56#define LPT_CONTROL_ENABLE_BIDIRECT 0x20
57#define LPT_CONTROL_ENABLE_IRQ_VIA_ACK 0x10
58#define LPT_CONTROL_SELECT_PRINTER 0x08
59#define LPT_CONTROL_RESET 0x04
60#define LPT_CONTROL_AUTO_LINEFEED 0x02
61#define LPT_CONTROL_STROBE 0x01
62
63/** mode defines for the extended control register */
64#define LPT_ECP_ECR_CHIPMODE_MASK 0xe0
65#define LPT_ECP_ECR_CHIPMODE_GET_BITS(reg) ((reg) >> 5)
66#define LPT_ECP_ECR_CHIPMODE_SET_BITS(val) ((val) << 5)
67#define LPT_ECP_ECR_CHIPMODE_CONFIGURATION 0x07
68#define LPT_ECP_ECR_CHIPMODE_FIFO_TEST 0x06
69#define LPT_ECP_ECR_CHIPMODE_RESERVED 0x05
70#define LPT_ECP_ECR_CHIPMODE_EPP 0x04
71#define LPT_ECP_ECR_CHIPMODE_ECP_FIFO 0x03
72#define LPT_ECP_ECR_CHIPMODE_PP_FIFO 0x02
73#define LPT_ECP_ECR_CHIPMODE_BYTE 0x01
74#define LPT_ECP_ECR_CHIPMODE_COMPAT 0x00
75
76/** FIFO status bits in extended control register */
77#define LPT_ECP_ECR_FIFO_MASK 0x03
78#define LPT_ECP_ECR_FIFO_SOME_DATA 0x00
79#define LPT_ECP_ECR_FIFO_FULL 0x02
80#define LPT_ECP_ECR_FIFO_EMPTY 0x01
81
82#define LPT_ECP_CONFIGA_FIFO_WITDH_MASK 0x70
83#define LPT_ECP_CONFIGA_FIFO_WIDTH_GET_BITS(reg) ((reg) >> 4)
84#define LPT_ECP_CONFIGA_FIFO_WIDTH_SET_BITS(val) ((val) << 4)
85#define LPT_ECP_CONFIGA_FIFO_WIDTH_16 0x00
86#define LPT_ECP_CONFIGA_FIFO_WIDTH_32 0x20
87#define LPT_ECP_CONFIGA_FIFO_WIDTH_8 0x10
88
89#define LPT_ECP_FIFO_DEPTH 2
90
91
92/*******************************************************************************
93* Structures and Typedefs *
94*******************************************************************************/
95typedef struct ParallelState
96{
97 /** Access critical section. */
98 PDMCRITSECT CritSect;
99
100 /** Pointer to the device instance - R3 Ptr */
101 PPDMDEVINSR3 pDevInsR3;
102 /** Pointer to the device instance - R0 Ptr */
103 PPDMDEVINSR0 pDevInsR0;
104 /** Pointer to the device instance - RC Ptr */
105 PPDMDEVINSRC pDevInsRC;
106 RTRCPTR Alignment0; /**< Alignment. */
107 /** The base interface. */
108 PDMIBASE IBase;
109 /** The host device port interface. */
110 PDMIHOSTPARALLELPORT IHostParallelPort;
111 /** Pointer to the attached base driver. */
112 R3PTRTYPE(PPDMIBASE) pDrvBase;
113 /** Pointer to the attached host device. */
114 R3PTRTYPE(PPDMIHOSTPARALLELCONNECTOR) pDrvHostParallelConnector;
115 /** Unused event semaphore... */
116 RTSEMEVENT ReceiveSem;
117
118 uint8_t reg_data;
119 uint8_t reg_status;
120 uint8_t reg_control;
121 uint8_t reg_epp_addr;
122 uint8_t reg_epp_data;
123 uint8_t reg_ecp_ecr;
124 uint8_t reg_ecp_base_plus_400h; /* has different meanings */
125 uint8_t reg_ecp_config_b;
126
127 /** The ECP FIFO implementation*/
128 uint8_t ecp_fifo[LPT_ECP_FIFO_DEPTH];
129 uint8_t abAlignemnt[2];
130 int act_fifo_pos_write;
131 int act_fifo_pos_read;
132
133 int irq;
134 uint8_t epp_timeout;
135
136 bool fGCEnabled;
137 bool fR0Enabled;
138 bool afAlignment[1];
139
140 uint32_t base;
141
142} DEVPARALLELSTATE, *PDEVPARALLELSTATE;
143typedef DEVPARALLELSTATE ParallelState;
144
145#ifndef VBOX_DEVICE_STRUCT_TESTCASE
146
147#define PDMIHOSTPARALLELPORT_2_PARALLELSTATE(pInstance) ( (ParallelState *)((uintptr_t)(pInterface) - RT_OFFSETOF(ParallelState, IHostParallelPort)) )
148#define PDMIHOSTDEVICEPORT_2_PARALLELSTATE(pInstance) ( (ParallelState *)((uintptr_t)(pInterface) - RT_OFFSETOF(ParallelState, IHostDevicePort)) )
149#define PDMIBASE_2_PARALLELSTATE(pInstance) ( (ParallelState *)((uintptr_t)(pInterface) - RT_OFFSETOF(ParallelState, IBase)) )
150
151
152/*******************************************************************************
153* Internal Functions *
154*******************************************************************************/
155__BEGIN_DECLS
156PDMBOTHCBDECL(int) parallelIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
157PDMBOTHCBDECL(int) parallelIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
158#if 0
159PDMBOTHCBDECL(int) parallelIOPortReadECP(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
160PDMBOTHCBDECL(int) parallelIOPortWriteECP(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
161#endif
162__END_DECLS
163
164
165#ifdef IN_RING3
166static void parallel_set_irq(ParallelState *s)
167{
168 if (s->reg_control & LPT_CONTROL_ENABLE_IRQ_VIA_ACK)
169 {
170 Log(("parallel_update_irq %d 1\n", s->irq));
171 PDMDevHlpISASetIrqNoWait(s->CTX_SUFF(pDevIns), s->irq, 1);
172 }
173}
174
175static void parallel_clear_irq(ParallelState *s)
176{
177 Log(("parallel_update_irq %d 0\n", s->irq));
178 PDMDevHlpISASetIrqNoWait(s->CTX_SUFF(pDevIns), s->irq, 0);
179}
180#endif
181
182static int parallel_ioport_write(void *opaque, uint32_t addr, uint32_t val)
183{
184 ParallelState *s = (ParallelState *)opaque;
185 unsigned char ch;
186
187 addr &= 7;
188 LogFlow(("parallel: write addr=0x%02x val=0x%02x\n", addr, val));
189 ch = val;
190
191 switch(addr) {
192 default:
193 case 0:
194#ifndef IN_RING3
195 NOREF(ch);
196 return VINF_IOM_HC_IOPORT_WRITE;
197#else
198 s->reg_data = ch;
199 if (RT_LIKELY(s->pDrvHostParallelConnector))
200 {
201 Log(("parallel_io_port_write: write 0x%X\n", ch));
202 size_t cbWrite = 1;
203 int rc = s->pDrvHostParallelConnector->pfnWrite(s->pDrvHostParallelConnector, &ch, &cbWrite);
204 AssertRC(rc);
205 }
206#endif
207 break;
208 case 1:
209 break;
210 case 2:
211 /* Set the reserved bits to one */
212 ch |= (LPT_CONTROL_BIT6 | LPT_CONTROL_BIT7);
213 if (ch != s->reg_control) {
214#ifndef IN_RING3
215 return VINF_IOM_HC_IOPORT_WRITE;
216#else
217 int rc = s->pDrvHostParallelConnector->pfnWriteControl(s->pDrvHostParallelConnector, ch);
218 AssertRC(rc);
219 s->reg_control = val;
220#endif
221 }
222 break;
223 case 3:
224 s->reg_epp_addr = val;
225 break;
226 case 4:
227 s->reg_epp_data = val;
228 break;
229 case 5:
230 break;
231 case 6:
232 break;
233 case 7:
234 break;
235 }
236 return VINF_SUCCESS;
237}
238
239static uint32_t parallel_ioport_read(void *opaque, uint32_t addr, int *pRC)
240{
241 ParallelState *s = (ParallelState *)opaque;
242 uint32_t ret = ~0U;
243
244 *pRC = VINF_SUCCESS;
245
246 addr &= 7;
247 switch(addr) {
248 default:
249 case 0:
250 if (!(s->reg_control & LPT_CONTROL_ENABLE_BIDIRECT))
251 ret = s->reg_data;
252 else
253 {
254#ifndef IN_RING3
255 *pRC = VINF_IOM_HC_IOPORT_READ;
256#else
257 if (RT_LIKELY(s->pDrvHostParallelConnector))
258 {
259 size_t cbRead;
260 int rc = s->pDrvHostParallelConnector->pfnRead(s->pDrvHostParallelConnector, &s->reg_data, &cbRead);
261 Log(("parallel_io_port_read: read 0x%X\n", s->reg_data));
262 AssertRC(rc);
263 }
264 ret = s->reg_data;
265#endif
266 }
267 break;
268 case 1:
269#ifndef IN_RING3
270 *pRC = VINF_IOM_HC_IOPORT_READ;
271#else
272 if (RT_LIKELY(s->pDrvHostParallelConnector))
273 {
274 int rc = s->pDrvHostParallelConnector->pfnReadStatus(s->pDrvHostParallelConnector, &s->reg_status);
275 AssertRC(rc);
276 }
277 ret = s->reg_status;
278 parallel_clear_irq(s);
279#endif
280 break;
281 case 2:
282 ret = s->reg_control;
283 break;
284 case 3:
285 ret = s->reg_epp_addr;
286 break;
287 case 4:
288 ret = s->reg_epp_data;
289 break;
290 case 5:
291 break;
292 case 6:
293 break;
294 case 7:
295 break;
296 }
297 LogFlow(("parallel: read addr=0x%02x val=0x%02x\n", addr, ret));
298 return ret;
299}
300
301#if 0
302static int parallel_ioport_write_ecp(void *opaque, uint32_t addr, uint32_t val)
303{
304 ParallelState *s = (ParallelState *)opaque;
305 unsigned char ch;
306
307 addr &= 7;
308 LogFlow(("parallel: write ecp addr=0x%02x val=0x%02x\n", addr, val));
309 ch = val;
310 switch(addr) {
311 default:
312 case 0:
313 if (LPT_ECP_ECR_CHIPMODE_GET_BITS(s->reg_ecp_ecr) == LPT_ECP_ECR_CHIPMODE_FIFO_TEST) {
314 s->ecp_fifo[s->act_fifo_pos_write] = ch;
315 s->act_fifo_pos_write++;
316 if (s->act_fifo_pos_write < LPT_ECP_FIFO_DEPTH) {
317 /* FIFO has some data (clear both FIFO bits) */
318 s->reg_ecp_ecr &= ~(LPT_ECP_ECR_FIFO_EMPTY | LPT_ECP_ECR_FIFO_FULL);
319 } else {
320 /* FIFO is full */
321 /* Clear FIFO empty bit */
322 s->reg_ecp_ecr &= ~LPT_ECP_ECR_FIFO_EMPTY;
323 /* Set FIFO full bit */
324 s->reg_ecp_ecr |= LPT_ECP_ECR_FIFO_FULL;
325 s->act_fifo_pos_write = 0;
326 }
327 } else {
328 s->reg_ecp_base_plus_400h = ch;
329 }
330 break;
331 case 1:
332 s->reg_ecp_config_b = ch;
333 break;
334 case 2:
335 /* If we change the mode clear FIFO */
336 if ((ch & LPT_ECP_ECR_CHIPMODE_MASK) != (s->reg_ecp_ecr & LPT_ECP_ECR_CHIPMODE_MASK)) {
337 /* reset the fifo */
338 s->act_fifo_pos_write = 0;
339 s->act_fifo_pos_read = 0;
340 /* Set FIFO empty bit */
341 s->reg_ecp_ecr |= LPT_ECP_ECR_FIFO_EMPTY;
342 /* Clear FIFO full bit */
343 s->reg_ecp_ecr &= ~LPT_ECP_ECR_FIFO_FULL;
344 }
345 /* Set new mode */
346 s->reg_ecp_ecr |= LPT_ECP_ECR_CHIPMODE_SET_BITS(LPT_ECP_ECR_CHIPMODE_GET_BITS(ch));
347 break;
348 case 3:
349 break;
350 case 4:
351 break;
352 case 5:
353 break;
354 case 6:
355 break;
356 case 7:
357 break;
358 }
359 return VINF_SUCCESS;
360}
361
362static uint32_t parallel_ioport_read_ecp(void *opaque, uint32_t addr, int *pRC)
363{
364 ParallelState *s = (ParallelState *)opaque;
365 uint32_t ret = ~0U;
366
367 *pRC = VINF_SUCCESS;
368
369 addr &= 7;
370 switch(addr) {
371 default:
372 case 0:
373 if (LPT_ECP_ECR_CHIPMODE_GET_BITS(s->reg_ecp_ecr) == LPT_ECP_ECR_CHIPMODE_FIFO_TEST) {
374 ret = s->ecp_fifo[s->act_fifo_pos_read];
375 s->act_fifo_pos_read++;
376 if (s->act_fifo_pos_read == LPT_ECP_FIFO_DEPTH)
377 s->act_fifo_pos_read = 0; /* end of FIFO, start at beginning */
378 if (s->act_fifo_pos_read == s->act_fifo_pos_write) {
379 /* FIFO is empty */
380 /* Set FIFO empty bit */
381 s->reg_ecp_ecr |= LPT_ECP_ECR_FIFO_EMPTY;
382 /* Clear FIFO full bit */
383 s->reg_ecp_ecr &= ~LPT_ECP_ECR_FIFO_FULL;
384 } else {
385 /* FIFO has some data (clear all FIFO bits) */
386 s->reg_ecp_ecr &= ~(LPT_ECP_ECR_FIFO_EMPTY | LPT_ECP_ECR_FIFO_FULL);
387 }
388 } else {
389 ret = s->reg_ecp_base_plus_400h;
390 }
391 break;
392 case 1:
393 ret = s->reg_ecp_config_b;
394 break;
395 case 2:
396 ret = s->reg_ecp_ecr;
397 break;
398 case 3:
399 break;
400 case 4:
401 break;
402 case 5:
403 break;
404 case 6:
405 break;
406 case 7:
407 break;
408 }
409 LogFlow(("parallel: read ecp addr=0x%02x val=0x%02x\n", addr, ret));
410 return ret;
411}
412#endif
413
414#ifdef IN_RING3
415static DECLCALLBACK(int) parallelNotifyInterrupt(PPDMIHOSTPARALLELPORT pInterface)
416{
417 ParallelState *pThis = PDMIHOSTPARALLELPORT_2_PARALLELSTATE(pInterface);
418
419 PDMCritSectEnter(&pThis->CritSect, VINF_SUCCESS);
420 parallel_set_irq(pThis);
421 PDMCritSectLeave(&pThis->CritSect);
422
423 return VINF_SUCCESS;
424}
425#endif /* IN_RING3 */
426
427/**
428 * Port I/O Handler for OUT operations.
429 *
430 * @returns VBox status code.
431 *
432 * @param pDevIns The device instance.
433 * @param pvUser User argument.
434 * @param Port Port number used for the IN operation.
435 * @param u32 The value to output.
436 * @param cb The value size in bytes.
437 */
438PDMBOTHCBDECL(int) parallelIOPortWrite(PPDMDEVINS pDevIns, void *pvUser,
439 RTIOPORT Port, uint32_t u32, unsigned cb)
440{
441 ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
442 int rc = VINF_SUCCESS;
443
444 if (cb == 1)
445 {
446 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_WRITE);
447 if (rc == VINF_SUCCESS)
448 {
449 Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, u32));
450 rc = parallel_ioport_write (pThis, Port, u32);
451 PDMCritSectLeave(&pThis->CritSect);
452 }
453 }
454 else
455 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
456
457 return rc;
458}
459
460/**
461 * Port I/O Handler for IN operations.
462 *
463 * @returns VBox status code.
464 *
465 * @param pDevIns The device instance.
466 * @param pvUser User argument.
467 * @param Port Port number used for the IN operation.
468 * @param u32 The value to output.
469 * @param cb The value size in bytes.
470 */
471PDMBOTHCBDECL(int) parallelIOPortRead(PPDMDEVINS pDevIns, void *pvUser,
472 RTIOPORT Port, uint32_t *pu32, unsigned cb)
473{
474 ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
475 int rc = VINF_SUCCESS;
476
477 if (cb == 1)
478 {
479 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_READ);
480 if (rc == VINF_SUCCESS)
481 {
482 *pu32 = parallel_ioport_read (pThis, Port, &rc);
483 Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, *pu32));
484 PDMCritSectLeave(&pThis->CritSect);
485 }
486 }
487 else
488 rc = VERR_IOM_IOPORT_UNUSED;
489
490 return rc;
491}
492
493#if 0
494/**
495 * Port I/O Handler for OUT operations on ECP registers.
496 *
497 * @returns VBox status code.
498 *
499 * @param pDevIns The device instance.
500 * @param pvUser User argument.
501 * @param Port Port number used for the IN operation.
502 * @param u32 The value to output.
503 * @param cb The value size in bytes.
504 */
505PDMBOTHCBDECL(int) parallelIOPortWriteECP(PPDMDEVINS pDevIns, void *pvUser,
506 RTIOPORT Port, uint32_t u32, unsigned cb)
507{
508 ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
509 int rc = VINF_SUCCESS;
510
511 if (cb == 1)
512 {
513 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_WRITE);
514 if (rc == VINF_SUCCESS)
515 {
516 Log2(("%s: ecp port %#06x val %#04x\n", __FUNCTION__, Port, u32));
517 rc = parallel_ioport_write_ecp (pThis, Port, u32);
518 PDMCritSectLeave(&pThis->CritSect);
519 }
520 }
521 else
522 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
523
524 return rc;
525}
526
527/**
528 * Port I/O Handler for IN operations on ECP registers.
529 *
530 * @returns VBox status code.
531 *
532 * @param pDevIns The device instance.
533 * @param pvUser User argument.
534 * @param Port Port number used for the IN operation.
535 * @param u32 The value to output.
536 * @param cb The value size in bytes.
537 */
538PDMBOTHCBDECL(int) parallelIOPortReadECP(PPDMDEVINS pDevIns, void *pvUser,
539 RTIOPORT Port, uint32_t *pu32, unsigned cb)
540{
541 ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
542 int rc = VINF_SUCCESS;
543
544 if (cb == 1)
545 {
546 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_READ);
547 if (rc == VINF_SUCCESS)
548 {
549 *pu32 = parallel_ioport_read_ecp (pThis, Port, &rc);
550 Log2(("%s: ecp port %#06x val %#04x\n", __FUNCTION__, Port, *pu32));
551 PDMCritSectLeave(&pThis->CritSect);
552 }
553 }
554 else
555 rc = VERR_IOM_IOPORT_UNUSED;
556
557 return rc;
558}
559#endif
560
561#ifdef IN_RING3
562/**
563 * Saves a state of the serial port device.
564 *
565 * @returns VBox status code.
566 * @param pDevIns The device instance.
567 * @param pSSMHandle The handle to save the state to.
568 */
569static DECLCALLBACK(int) parallelSaveExec(PPDMDEVINS pDevIns,
570 PSSMHANDLE pSSMHandle)
571{
572 ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
573
574 SSMR3PutU8(pSSMHandle, pThis->reg_data);
575 SSMR3PutU8(pSSMHandle, pThis->reg_status);
576 SSMR3PutU8(pSSMHandle, pThis->reg_control);
577 SSMR3PutS32(pSSMHandle, pThis->irq);
578 SSMR3PutU32(pSSMHandle, pThis->base);
579
580 return SSMR3PutU32(pSSMHandle, ~0); /* sanity/terminator */
581}
582
583/**
584 * Loads a saved serial port device state.
585 *
586 * @returns VBox status code.
587 * @param pDevIns The device instance.
588 * @param pSSMHandle The handle to the saved state.
589 * @param u32Version The data unit version number.
590 */
591static DECLCALLBACK(int) parallelLoadExec(PPDMDEVINS pDevIns,
592 PSSMHANDLE pSSMHandle,
593 uint32_t u32Version)
594{
595 int rc;
596 uint32_t u32;
597 ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
598
599 if (u32Version != PARALLEL_SAVED_STATE_VERSION)
600 {
601 AssertLogRelMsgFailed(("u32Version=%d\n", u32Version));
602 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
603 }
604
605 SSMR3GetU8(pSSMHandle, &pThis->reg_data);
606 SSMR3GetU8(pSSMHandle, &pThis->reg_status);
607 SSMR3GetU8(pSSMHandle, &pThis->reg_control);
608 SSMR3GetS32(pSSMHandle, &pThis->irq);
609 SSMR3GetU32(pSSMHandle, &pThis->base);
610
611 rc = SSMR3GetU32(pSSMHandle, &u32);
612 if (RT_FAILURE(rc))
613 return rc;
614
615 if (u32 != ~0U)
616 {
617 AssertLogRelMsgFailed(("u32=%#x expected ~0\n", u32));
618 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
619 }
620
621 /* not necessary... but it doesn't harm. */
622 pThis->pDevInsR3 = pDevIns;
623 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
624 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
625 return VINF_SUCCESS;
626}
627
628
629/**
630 * @copydoc FNPDMDEVRELOCATE
631 */
632static DECLCALLBACK(void) parallelRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
633{
634 ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
635 pThis->pDevInsRC += offDelta;
636}
637
638/** @copyfrom PIBASE::pfnqueryInterface */
639static DECLCALLBACK(void *) parallelQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
640{
641 ParallelState *pThis = PDMIBASE_2_PARALLELSTATE(pInterface);
642 switch (enmInterface)
643 {
644 case PDMINTERFACE_BASE:
645 return &pThis->IBase;
646 case PDMINTERFACE_HOST_PARALLEL_PORT:
647 return &pThis->IHostParallelPort;
648 default:
649 return NULL;
650 }
651}
652
653/**
654 * Destruct a device instance.
655 *
656 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
657 * resources can be freed correctly.
658 *
659 * @returns VBox status.
660 * @param pDevIns The device instance data.
661 */
662static DECLCALLBACK(int) parallelDestruct(PPDMDEVINS pDevIns)
663{
664 ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
665
666 PDMR3CritSectDelete(&pThis->CritSect);
667 RTSemEventDestroy(pThis->ReceiveSem);
668
669 return VINF_SUCCESS;
670}
671
672
673/**
674 * Construct a device instance for a VM.
675 *
676 * @returns VBox status.
677 * @param pDevIns The device instance data.
678 * If the registration structure is needed, pDevIns->pDevReg points to it.
679 * @param iInstance Instance number. Use this to figure out which registers and such to use.
680 * The device number is also found in pDevIns->iInstance, but since it's
681 * likely to be freqently used PDM passes it as parameter.
682 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
683 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
684 * iInstance it's expected to be used a bit in this function.
685 */
686static DECLCALLBACK(int) parallelConstruct(PPDMDEVINS pDevIns,
687 int iInstance,
688 PCFGMNODE pCfgHandle)
689{
690 int rc;
691 ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState*);
692
693 Assert(iInstance < 4);
694
695 /*
696 * Init the data so parallelDestruct doesn't choke.
697 */
698 pThis->pDevInsR3 = pDevIns;
699 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
700 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
701 pThis->ReceiveSem = NIL_RTSEMEVENT;
702
703 /* IBase */
704 pThis->IBase.pfnQueryInterface = parallelQueryInterface;
705
706 /* IHostParallelPort */
707 pThis->IHostParallelPort.pfnNotifyInterrupt = parallelNotifyInterrupt;
708
709 /* Init parallel state */
710 pThis->reg_data = 0;
711 pThis->reg_ecp_ecr = LPT_ECP_ECR_CHIPMODE_COMPAT | LPT_ECP_ECR_FIFO_EMPTY;
712 pThis->act_fifo_pos_read = 0;
713 pThis->act_fifo_pos_write = 0;
714
715 /*
716 * Validate and read the configuration.
717 */
718 if (!CFGMR3AreValuesValid(pCfgHandle, "IRQ\0" "IOBase\0" "GCEnabled\0" "R0Enabled\0"))
719 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
720 N_("Configuration error: Unknown config key"));
721
722 rc = CFGMR3QueryBoolDef(pCfgHandle, "GCEnabled", &pThis->fGCEnabled, true);
723 if (RT_FAILURE(rc))
724 return PDMDEV_SET_ERROR(pDevIns, rc,
725 N_("Configuration error: Failed to get the \"GCEnabled\" value"));
726
727 rc = CFGMR3QueryBoolDef(pCfgHandle, "R0Enabled", &pThis->fR0Enabled, true);
728 if (RT_FAILURE(rc))
729 return PDMDEV_SET_ERROR(pDevIns, rc,
730 N_("Configuration error: Failed to get the \"R0Enabled\" value"));
731
732 uint8_t irq_lvl;
733 rc = CFGMR3QueryU8Def(pCfgHandle, "IRQ", &irq_lvl, 7);
734 if (RT_FAILURE(rc))
735 return PDMDEV_SET_ERROR(pDevIns, rc,
736 N_("Configuration error: Failed to get the \"IRQ\" value"));
737
738 uint16_t io_base;
739 rc = CFGMR3QueryU16Def(pCfgHandle, "IOBase", &io_base, 0x378);
740 if (RT_FAILURE(rc))
741 return PDMDEV_SET_ERROR(pDevIns, rc,
742 N_("Configuration error: Failed to get the \"IOBase\" value"));
743
744 Log(("parallelConstruct instance %d iobase=%04x irq=%d\n", iInstance, io_base, irq_lvl));
745
746 pThis->irq = irq_lvl;
747 pThis->base = io_base;
748
749 /*
750 * Initialize critical section and event semaphore.
751 * This must of course be done before attaching drivers or anything else which can call us back..
752 */
753 char szName[24];
754 RTStrPrintf(szName, sizeof(szName), "Parallel#%d", iInstance);
755 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, szName);
756 if (RT_FAILURE(rc))
757 return rc;
758
759 rc = RTSemEventCreate(&pThis->ReceiveSem);
760 if (RT_FAILURE(rc))
761 return rc;
762
763 /*
764 * Register the I/O ports and saved state.
765 */
766 rc = PDMDevHlpIOPortRegister(pDevIns, io_base, 8, 0,
767 parallelIOPortWrite, parallelIOPortRead,
768 NULL, NULL, "PARALLEL");
769 if (RT_FAILURE(rc))
770 return rc;
771
772#if 0
773 /* register ecp registers */
774 rc = PDMDevHlpIOPortRegister(pDevIns, io_base+0x400, 8, 0,
775 parallelIOPortWriteECP, parallelIOPortReadECP,
776 NULL, NULL, "PARALLEL ECP");
777 if (RT_FAILURE(rc))
778 return rc;
779#endif
780
781 if (pThis->fGCEnabled)
782 {
783 rc = PDMDevHlpIOPortRegisterGC(pDevIns, io_base, 8, 0, "parallelIOPortWrite",
784 "parallelIOPortRead", NULL, NULL, "Parallel");
785 if (RT_FAILURE(rc))
786 return rc;
787
788#if 0
789 rc = PDMDevHlpIOPortRegisterGC(pDevIns, io_base+0x400, 8, 0, "parallelIOPortWriteECP",
790 "parallelIOPortReadECP", NULL, NULL, "Parallel Ecp");
791 if (RT_FAILURE(rc))
792 return rc;
793#endif
794 }
795
796 if (pThis->fR0Enabled)
797 {
798 rc = PDMDevHlpIOPortRegisterR0(pDevIns, io_base, 8, 0, "parallelIOPortWrite",
799 "parallelIOPortRead", NULL, NULL, "Parallel");
800 if (RT_FAILURE(rc))
801 return rc;
802
803#if 0
804 rc = PDMDevHlpIOPortRegisterR0(pDevIns, io_base+0x400, 8, 0, "parallelIOPortWriteECP",
805 "parallelIOPortReadECP", NULL, NULL, "Parallel Ecp");
806 if (RT_FAILURE(rc))
807 return rc;
808#endif
809 }
810
811 rc = PDMDevHlpSSMRegister(
812 pDevIns, /* pDevIns */
813 pDevIns->pDevReg->szDeviceName, /* pszName */
814 iInstance, /* u32Instance */
815 PARALLEL_SAVED_STATE_VERSION, /* u32Version */
816 sizeof (*pThis), /* cbGuess */
817 NULL, /* pfnSavePrep */
818 parallelSaveExec, /* pfnSaveExec */
819 NULL, /* pfnSaveDone */
820 NULL, /* pfnLoadPrep */
821 parallelLoadExec, /* pfnLoadExec */
822 NULL /* pfnLoadDone */
823 );
824 if (RT_FAILURE(rc))
825 return rc;
826
827
828 /*
829 * Attach the parallel port driver and get the interfaces.
830 * For now no run-time changes are supported.
831 */
832 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Parallel Host");
833 if (RT_SUCCESS(rc))
834 {
835 pThis->pDrvHostParallelConnector = (PDMIHOSTPARALLELCONNECTOR *)pThis->pDrvBase->pfnQueryInterface(pThis->pDrvBase,
836 PDMINTERFACE_HOST_PARALLEL_CONNECTOR);
837 if (!pThis->pDrvHostParallelConnector)
838 {
839 AssertMsgFailed(("Configuration error: instance %d has no host parallel interface!\n", iInstance));
840 return VERR_PDM_MISSING_INTERFACE;
841 }
842 /** @todo provide read notification interface!!!! */
843 }
844 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
845 {
846 pThis->pDrvBase = NULL;
847 pThis->pDrvHostParallelConnector = NULL;
848 LogRel(("Parallel%d: no unit\n", iInstance));
849 }
850 else
851 {
852 AssertMsgFailed(("Parallel%d: Failed to attach to host driver. rc=%Rrc\n", iInstance, rc));
853 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
854 N_("Parallel device %d cannot attach to host driver"), iInstance);
855 }
856
857 /* Set compatibility mode */
858 pThis->pDrvHostParallelConnector->pfnSetMode(pThis->pDrvHostParallelConnector, PDM_PARALLEL_PORT_MODE_COMPAT);
859 /* Get status of control register */
860 pThis->pDrvHostParallelConnector->pfnReadControl(pThis->pDrvHostParallelConnector, &pThis->reg_control);
861
862 return VINF_SUCCESS;
863}
864
865/**
866 * The device registration structure.
867 */
868const PDMDEVREG g_DeviceParallelPort =
869{
870 /* u32Version */
871 PDM_DEVREG_VERSION,
872 /* szDeviceName */
873 "parallel",
874 /* szGCMod */
875 "VBoxDDGC.gc",
876 /* szR0Mod */
877 "VBoxDDR0.r0",
878 /* pszDescription */
879 "Parallel Communication Port",
880 /* fFlags */
881 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GC | PDM_DEVREG_FLAGS_R0,
882 /* fClass */
883 PDM_DEVREG_CLASS_PARALLEL,
884 /* cMaxInstances */
885 1,
886 /* cbInstance */
887 sizeof(ParallelState),
888 /* pfnConstruct */
889 parallelConstruct,
890 /* pfnDestruct */
891 parallelDestruct,
892 /* pfnRelocate */
893 parallelRelocate,
894 /* pfnIOCtl */
895 NULL,
896 /* pfnPowerOn */
897 NULL,
898 /* pfnReset */
899 NULL,
900 /* pfnSuspend */
901 NULL,
902 /* pfnResume */
903 NULL,
904 /* pfnAttach */
905 NULL,
906 /* pfnDetach */
907 NULL,
908 /* pfnQueryInterface. */
909 NULL
910};
911#endif /* IN_RING3 */
912
913
914#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use