VirtualBox

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

Last change on this file since 26165 was 26165, checked in by vboxsync, 15 years ago

PDM: s/szDeviceName/szName/g - PDMDEVREG & PDMUSBREG.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 28.8 KB
Line 
1/* $Id: DevParallel.cpp 26165 2010-02-02 19:50:31Z 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*******************************************************************************/
95/**
96 * Parallel device state.
97 *
98 * @implements PDMIBASE
99 * @implements PDMIHOSTPARALLELPORT
100 */
101typedef struct ParallelState
102{
103 /** Access critical section. */
104 PDMCRITSECT CritSect;
105
106 /** Pointer to the device instance - R3 Ptr */
107 PPDMDEVINSR3 pDevInsR3;
108 /** Pointer to the device instance - R0 Ptr */
109 PPDMDEVINSR0 pDevInsR0;
110 /** Pointer to the device instance - RC Ptr */
111 PPDMDEVINSRC pDevInsRC;
112 RTRCPTR Alignment0; /**< Alignment. */
113 /** LUN\#0: The base interface. */
114 PDMIBASE IBase;
115 /** LUN\#0: The host device port interface. */
116 PDMIHOSTPARALLELPORT IHostParallelPort;
117 /** Pointer to the attached base driver. */
118 R3PTRTYPE(PPDMIBASE) pDrvBase;
119 /** Pointer to the attached host device. */
120 R3PTRTYPE(PPDMIHOSTPARALLELCONNECTOR) pDrvHostParallelConnector;
121 /** Unused event semaphore... */
122 RTSEMEVENT ReceiveSem;
123
124 uint8_t reg_data;
125 uint8_t reg_status;
126 uint8_t reg_control;
127 uint8_t reg_epp_addr;
128 uint8_t reg_epp_data;
129 uint8_t reg_ecp_ecr;
130 uint8_t reg_ecp_base_plus_400h; /* has different meanings */
131 uint8_t reg_ecp_config_b;
132
133 /** The ECP FIFO implementation*/
134 uint8_t ecp_fifo[LPT_ECP_FIFO_DEPTH];
135 uint8_t abAlignemnt[2];
136 int act_fifo_pos_write;
137 int act_fifo_pos_read;
138
139 int irq;
140 uint8_t epp_timeout;
141
142 bool fGCEnabled;
143 bool fR0Enabled;
144 bool afAlignment[1];
145
146 uint32_t base;
147
148} DEVPARALLELSTATE, *PDEVPARALLELSTATE;
149typedef DEVPARALLELSTATE ParallelState;
150
151#ifndef VBOX_DEVICE_STRUCT_TESTCASE
152
153#define PDMIHOSTPARALLELPORT_2_PARALLELSTATE(pInstance) ( (ParallelState *)((uintptr_t)(pInterface) - RT_OFFSETOF(ParallelState, IHostParallelPort)) )
154#define PDMIHOSTDEVICEPORT_2_PARALLELSTATE(pInstance) ( (ParallelState *)((uintptr_t)(pInterface) - RT_OFFSETOF(ParallelState, IHostDevicePort)) )
155#define PDMIBASE_2_PARALLELSTATE(pInstance) ( (ParallelState *)((uintptr_t)(pInterface) - RT_OFFSETOF(ParallelState, IBase)) )
156
157
158/*******************************************************************************
159* Internal Functions *
160*******************************************************************************/
161RT_C_DECLS_BEGIN
162PDMBOTHCBDECL(int) parallelIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
163PDMBOTHCBDECL(int) parallelIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
164#if 0
165PDMBOTHCBDECL(int) parallelIOPortReadECP(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
166PDMBOTHCBDECL(int) parallelIOPortWriteECP(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
167#endif
168RT_C_DECLS_END
169
170
171#ifdef IN_RING3
172static void parallel_set_irq(ParallelState *s)
173{
174 if (s->reg_control & LPT_CONTROL_ENABLE_IRQ_VIA_ACK)
175 {
176 Log(("parallel_update_irq %d 1\n", s->irq));
177 PDMDevHlpISASetIrqNoWait(s->CTX_SUFF(pDevIns), s->irq, 1);
178 }
179}
180
181static void parallel_clear_irq(ParallelState *s)
182{
183 Log(("parallel_update_irq %d 0\n", s->irq));
184 PDMDevHlpISASetIrqNoWait(s->CTX_SUFF(pDevIns), s->irq, 0);
185}
186#endif
187
188static int parallel_ioport_write(void *opaque, uint32_t addr, uint32_t val)
189{
190 ParallelState *s = (ParallelState *)opaque;
191 unsigned char ch;
192
193 addr &= 7;
194 LogFlow(("parallel: write addr=0x%02x val=0x%02x\n", addr, val));
195 ch = val;
196
197 switch(addr) {
198 default:
199 case 0:
200#ifndef IN_RING3
201 NOREF(ch);
202 return VINF_IOM_HC_IOPORT_WRITE;
203#else
204 s->reg_data = ch;
205 if (RT_LIKELY(s->pDrvHostParallelConnector))
206 {
207 Log(("parallel_io_port_write: write 0x%X\n", ch));
208 size_t cbWrite = 1;
209 int rc = s->pDrvHostParallelConnector->pfnWrite(s->pDrvHostParallelConnector, &ch, &cbWrite);
210 AssertRC(rc);
211 }
212#endif
213 break;
214 case 1:
215 break;
216 case 2:
217 /* Set the reserved bits to one */
218 ch |= (LPT_CONTROL_BIT6 | LPT_CONTROL_BIT7);
219 if (ch != s->reg_control) {
220#ifndef IN_RING3
221 return VINF_IOM_HC_IOPORT_WRITE;
222#else
223 int rc = s->pDrvHostParallelConnector->pfnWriteControl(s->pDrvHostParallelConnector, ch);
224 AssertRC(rc);
225 s->reg_control = val;
226#endif
227 }
228 break;
229 case 3:
230 s->reg_epp_addr = val;
231 break;
232 case 4:
233 s->reg_epp_data = val;
234 break;
235 case 5:
236 break;
237 case 6:
238 break;
239 case 7:
240 break;
241 }
242 return VINF_SUCCESS;
243}
244
245static uint32_t parallel_ioport_read(void *opaque, uint32_t addr, int *pRC)
246{
247 ParallelState *s = (ParallelState *)opaque;
248 uint32_t ret = ~0U;
249
250 *pRC = VINF_SUCCESS;
251
252 addr &= 7;
253 switch(addr) {
254 default:
255 case 0:
256 if (!(s->reg_control & LPT_CONTROL_ENABLE_BIDIRECT))
257 ret = s->reg_data;
258 else
259 {
260#ifndef IN_RING3
261 *pRC = VINF_IOM_HC_IOPORT_READ;
262#else
263 if (RT_LIKELY(s->pDrvHostParallelConnector))
264 {
265 size_t cbRead;
266 int rc = s->pDrvHostParallelConnector->pfnRead(s->pDrvHostParallelConnector, &s->reg_data, &cbRead);
267 Log(("parallel_io_port_read: read 0x%X\n", s->reg_data));
268 AssertRC(rc);
269 }
270 ret = s->reg_data;
271#endif
272 }
273 break;
274 case 1:
275#ifndef IN_RING3
276 *pRC = VINF_IOM_HC_IOPORT_READ;
277#else
278 if (RT_LIKELY(s->pDrvHostParallelConnector))
279 {
280 int rc = s->pDrvHostParallelConnector->pfnReadStatus(s->pDrvHostParallelConnector, &s->reg_status);
281 AssertRC(rc);
282 }
283 ret = s->reg_status;
284 parallel_clear_irq(s);
285#endif
286 break;
287 case 2:
288 ret = s->reg_control;
289 break;
290 case 3:
291 ret = s->reg_epp_addr;
292 break;
293 case 4:
294 ret = s->reg_epp_data;
295 break;
296 case 5:
297 break;
298 case 6:
299 break;
300 case 7:
301 break;
302 }
303 LogFlow(("parallel: read addr=0x%02x val=0x%02x\n", addr, ret));
304 return ret;
305}
306
307#if 0
308static int parallel_ioport_write_ecp(void *opaque, uint32_t addr, uint32_t val)
309{
310 ParallelState *s = (ParallelState *)opaque;
311 unsigned char ch;
312
313 addr &= 7;
314 LogFlow(("parallel: write ecp addr=0x%02x val=0x%02x\n", addr, val));
315 ch = val;
316 switch(addr) {
317 default:
318 case 0:
319 if (LPT_ECP_ECR_CHIPMODE_GET_BITS(s->reg_ecp_ecr) == LPT_ECP_ECR_CHIPMODE_FIFO_TEST) {
320 s->ecp_fifo[s->act_fifo_pos_write] = ch;
321 s->act_fifo_pos_write++;
322 if (s->act_fifo_pos_write < LPT_ECP_FIFO_DEPTH) {
323 /* FIFO has some data (clear both FIFO bits) */
324 s->reg_ecp_ecr &= ~(LPT_ECP_ECR_FIFO_EMPTY | LPT_ECP_ECR_FIFO_FULL);
325 } else {
326 /* FIFO is full */
327 /* Clear FIFO empty bit */
328 s->reg_ecp_ecr &= ~LPT_ECP_ECR_FIFO_EMPTY;
329 /* Set FIFO full bit */
330 s->reg_ecp_ecr |= LPT_ECP_ECR_FIFO_FULL;
331 s->act_fifo_pos_write = 0;
332 }
333 } else {
334 s->reg_ecp_base_plus_400h = ch;
335 }
336 break;
337 case 1:
338 s->reg_ecp_config_b = ch;
339 break;
340 case 2:
341 /* If we change the mode clear FIFO */
342 if ((ch & LPT_ECP_ECR_CHIPMODE_MASK) != (s->reg_ecp_ecr & LPT_ECP_ECR_CHIPMODE_MASK)) {
343 /* reset the fifo */
344 s->act_fifo_pos_write = 0;
345 s->act_fifo_pos_read = 0;
346 /* Set FIFO empty bit */
347 s->reg_ecp_ecr |= LPT_ECP_ECR_FIFO_EMPTY;
348 /* Clear FIFO full bit */
349 s->reg_ecp_ecr &= ~LPT_ECP_ECR_FIFO_FULL;
350 }
351 /* Set new mode */
352 s->reg_ecp_ecr |= LPT_ECP_ECR_CHIPMODE_SET_BITS(LPT_ECP_ECR_CHIPMODE_GET_BITS(ch));
353 break;
354 case 3:
355 break;
356 case 4:
357 break;
358 case 5:
359 break;
360 case 6:
361 break;
362 case 7:
363 break;
364 }
365 return VINF_SUCCESS;
366}
367
368static uint32_t parallel_ioport_read_ecp(void *opaque, uint32_t addr, int *pRC)
369{
370 ParallelState *s = (ParallelState *)opaque;
371 uint32_t ret = ~0U;
372
373 *pRC = VINF_SUCCESS;
374
375 addr &= 7;
376 switch(addr) {
377 default:
378 case 0:
379 if (LPT_ECP_ECR_CHIPMODE_GET_BITS(s->reg_ecp_ecr) == LPT_ECP_ECR_CHIPMODE_FIFO_TEST) {
380 ret = s->ecp_fifo[s->act_fifo_pos_read];
381 s->act_fifo_pos_read++;
382 if (s->act_fifo_pos_read == LPT_ECP_FIFO_DEPTH)
383 s->act_fifo_pos_read = 0; /* end of FIFO, start at beginning */
384 if (s->act_fifo_pos_read == s->act_fifo_pos_write) {
385 /* FIFO is empty */
386 /* Set FIFO empty bit */
387 s->reg_ecp_ecr |= LPT_ECP_ECR_FIFO_EMPTY;
388 /* Clear FIFO full bit */
389 s->reg_ecp_ecr &= ~LPT_ECP_ECR_FIFO_FULL;
390 } else {
391 /* FIFO has some data (clear all FIFO bits) */
392 s->reg_ecp_ecr &= ~(LPT_ECP_ECR_FIFO_EMPTY | LPT_ECP_ECR_FIFO_FULL);
393 }
394 } else {
395 ret = s->reg_ecp_base_plus_400h;
396 }
397 break;
398 case 1:
399 ret = s->reg_ecp_config_b;
400 break;
401 case 2:
402 ret = s->reg_ecp_ecr;
403 break;
404 case 3:
405 break;
406 case 4:
407 break;
408 case 5:
409 break;
410 case 6:
411 break;
412 case 7:
413 break;
414 }
415 LogFlow(("parallel: read ecp addr=0x%02x val=0x%02x\n", addr, ret));
416 return ret;
417}
418#endif
419
420#ifdef IN_RING3
421static DECLCALLBACK(int) parallelNotifyInterrupt(PPDMIHOSTPARALLELPORT pInterface)
422{
423 ParallelState *pThis = PDMIHOSTPARALLELPORT_2_PARALLELSTATE(pInterface);
424
425 PDMCritSectEnter(&pThis->CritSect, VINF_SUCCESS);
426 parallel_set_irq(pThis);
427 PDMCritSectLeave(&pThis->CritSect);
428
429 return VINF_SUCCESS;
430}
431#endif /* IN_RING3 */
432
433/**
434 * Port I/O Handler for OUT operations.
435 *
436 * @returns VBox status code.
437 *
438 * @param pDevIns The device instance.
439 * @param pvUser User argument.
440 * @param Port Port number used for the IN operation.
441 * @param u32 The value to output.
442 * @param cb The value size in bytes.
443 */
444PDMBOTHCBDECL(int) parallelIOPortWrite(PPDMDEVINS pDevIns, void *pvUser,
445 RTIOPORT Port, uint32_t u32, unsigned cb)
446{
447 ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
448 int rc = VINF_SUCCESS;
449
450 if (cb == 1)
451 {
452 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_WRITE);
453 if (rc == VINF_SUCCESS)
454 {
455 Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, u32));
456 rc = parallel_ioport_write (pThis, Port, u32);
457 PDMCritSectLeave(&pThis->CritSect);
458 }
459 }
460 else
461 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
462
463 return rc;
464}
465
466/**
467 * Port I/O Handler for IN operations.
468 *
469 * @returns VBox status code.
470 *
471 * @param pDevIns The device instance.
472 * @param pvUser User argument.
473 * @param Port Port number used for the IN operation.
474 * @param pu32 Where to return the read value.
475 * @param cb The value size in bytes.
476 */
477PDMBOTHCBDECL(int) parallelIOPortRead(PPDMDEVINS pDevIns, void *pvUser,
478 RTIOPORT Port, uint32_t *pu32, unsigned cb)
479{
480 ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
481 int rc = VINF_SUCCESS;
482
483 if (cb == 1)
484 {
485 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_READ);
486 if (rc == VINF_SUCCESS)
487 {
488 *pu32 = parallel_ioport_read (pThis, Port, &rc);
489 Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, *pu32));
490 PDMCritSectLeave(&pThis->CritSect);
491 }
492 }
493 else
494 rc = VERR_IOM_IOPORT_UNUSED;
495
496 return rc;
497}
498
499#if 0
500/**
501 * Port I/O Handler for OUT operations on ECP registers.
502 *
503 * @returns VBox status code.
504 *
505 * @param pDevIns The device instance.
506 * @param pvUser User argument.
507 * @param Port Port number used for the IN operation.
508 * @param u32 The value to output.
509 * @param cb The value size in bytes.
510 */
511PDMBOTHCBDECL(int) parallelIOPortWriteECP(PPDMDEVINS pDevIns, void *pvUser,
512 RTIOPORT Port, uint32_t u32, unsigned cb)
513{
514 ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
515 int rc = VINF_SUCCESS;
516
517 if (cb == 1)
518 {
519 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_WRITE);
520 if (rc == VINF_SUCCESS)
521 {
522 Log2(("%s: ecp port %#06x val %#04x\n", __FUNCTION__, Port, u32));
523 rc = parallel_ioport_write_ecp (pThis, Port, u32);
524 PDMCritSectLeave(&pThis->CritSect);
525 }
526 }
527 else
528 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
529
530 return rc;
531}
532
533/**
534 * Port I/O Handler for IN operations on ECP registers.
535 *
536 * @returns VBox status code.
537 *
538 * @param pDevIns The device instance.
539 * @param pvUser User argument.
540 * @param Port Port number used for the IN operation.
541 * @param u32 The value to output.
542 * @param cb The value size in bytes.
543 */
544PDMBOTHCBDECL(int) parallelIOPortReadECP(PPDMDEVINS pDevIns, void *pvUser,
545 RTIOPORT Port, uint32_t *pu32, unsigned cb)
546{
547 ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
548 int rc = VINF_SUCCESS;
549
550 if (cb == 1)
551 {
552 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_READ);
553 if (rc == VINF_SUCCESS)
554 {
555 *pu32 = parallel_ioport_read_ecp (pThis, Port, &rc);
556 Log2(("%s: ecp port %#06x val %#04x\n", __FUNCTION__, Port, *pu32));
557 PDMCritSectLeave(&pThis->CritSect);
558 }
559 }
560 else
561 rc = VERR_IOM_IOPORT_UNUSED;
562
563 return rc;
564}
565#endif
566
567#ifdef IN_RING3
568/**
569 * @copydoc FNSSMDEVLIVEEXEC
570 */
571static DECLCALLBACK(int) parallelLiveExec(PPDMDEVINS pDevIns,
572 PSSMHANDLE pSSM,
573 uint32_t uPass)
574{
575 ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
576
577 SSMR3PutS32(pSSM, pThis->irq);
578 SSMR3PutU32(pSSM, pThis->base);
579 SSMR3PutU32(pSSM, ~0); /* sanity/terminator */
580 return VINF_SSM_DONT_CALL_AGAIN;
581}
582
583/**
584 * @copydoc FNSSMDEVSAVEEXEC
585 */
586static DECLCALLBACK(int) parallelSaveExec(PPDMDEVINS pDevIns,
587 PSSMHANDLE pSSM)
588{
589 ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
590
591 SSMR3PutU8(pSSM, pThis->reg_data);
592 SSMR3PutU8(pSSM, pThis->reg_status);
593 SSMR3PutU8(pSSM, pThis->reg_control);
594
595 parallelLiveExec(pDevIns, pSSM, 0);
596 return VINF_SUCCESS;
597}
598
599/**
600 * @copydoc FNSSMDEVLOADEXEC
601 */
602static DECLCALLBACK(int) parallelLoadExec(PPDMDEVINS pDevIns,
603 PSSMHANDLE pSSM,
604 uint32_t uVersion,
605 uint32_t uPass)
606{
607 ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
608
609 AssertMsgReturn(uVersion == PARALLEL_SAVED_STATE_VERSION, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
610 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
611 if (uPass == SSM_PASS_FINAL)
612 {
613 SSMR3GetU8(pSSM, &pThis->reg_data);
614 SSMR3GetU8(pSSM, &pThis->reg_status);
615 SSMR3GetU8(pSSM, &pThis->reg_control);
616 }
617
618 /* the config */
619 int32_t iIrq;
620 SSMR3GetS32(pSSM, &iIrq);
621 uint32_t uIoBase;
622 SSMR3GetU32(pSSM, &uIoBase);
623 uint32_t u32;
624 int rc = SSMR3GetU32(pSSM, &u32);
625 if (RT_FAILURE(rc))
626 return rc;
627 AssertMsgReturn(u32 == ~0U, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
628
629 if (pThis->irq != iIrq)
630 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("IRQ changed: config=%#x state=%#x"), pThis->irq, iIrq);
631
632 if (pThis->base != uIoBase)
633 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("IOBase changed: config=%#x state=%#x"), pThis->base, uIoBase);
634
635 /* not necessary... but it doesn't harm. */
636 pThis->pDevInsR3 = pDevIns;
637 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
638 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
639 return VINF_SUCCESS;
640}
641
642
643/**
644 * @copydoc FNPDMDEVRELOCATE
645 */
646static DECLCALLBACK(void) parallelRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
647{
648 ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
649 pThis->pDevInsRC += offDelta;
650}
651
652/**
653 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
654 */
655static DECLCALLBACK(void *) parallelQueryInterface(PPDMIBASE pInterface, const char *pszIID)
656{
657 ParallelState *pThis = PDMIBASE_2_PARALLELSTATE(pInterface);
658 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
659 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTPARALLELPORT, &pThis->IHostParallelPort);
660 return NULL;
661}
662
663/**
664 * Destruct a device instance.
665 *
666 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
667 * resources can be freed correctly.
668 *
669 * @returns VBox status.
670 * @param pDevIns The device instance data.
671 */
672static DECLCALLBACK(int) parallelDestruct(PPDMDEVINS pDevIns)
673{
674 ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
675 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
676
677 PDMR3CritSectDelete(&pThis->CritSect);
678 RTSemEventDestroy(pThis->ReceiveSem);
679
680 return VINF_SUCCESS;
681}
682
683
684/**
685 * @interface_method_impl{PDMDEVREG,pfnConstruct}
686 */
687static DECLCALLBACK(int) parallelConstruct(PPDMDEVINS pDevIns,
688 int iInstance,
689 PCFGMNODE pCfgHandle)
690{
691 int rc;
692 ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState*);
693
694 Assert(iInstance < 4);
695 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
696
697 /*
698 * Init the data so parallelDestruct doesn't choke.
699 */
700 pThis->pDevInsR3 = pDevIns;
701 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
702 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
703 pThis->ReceiveSem = NIL_RTSEMEVENT;
704
705 /* IBase */
706 pThis->IBase.pfnQueryInterface = parallelQueryInterface;
707
708 /* IHostParallelPort */
709 pThis->IHostParallelPort.pfnNotifyInterrupt = parallelNotifyInterrupt;
710
711 /* Init parallel state */
712 pThis->reg_data = 0;
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
717 /*
718 * Validate and read the configuration.
719 */
720 if (!CFGMR3AreValuesValid(pCfgHandle, "IRQ\0" "IOBase\0" "GCEnabled\0" "R0Enabled\0"))
721 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
722 N_("Configuration error: Unknown config key"));
723
724 rc = CFGMR3QueryBoolDef(pCfgHandle, "GCEnabled", &pThis->fGCEnabled, true);
725 if (RT_FAILURE(rc))
726 return PDMDEV_SET_ERROR(pDevIns, rc,
727 N_("Configuration error: Failed to get the \"GCEnabled\" value"));
728
729 rc = CFGMR3QueryBoolDef(pCfgHandle, "R0Enabled", &pThis->fR0Enabled, true);
730 if (RT_FAILURE(rc))
731 return PDMDEV_SET_ERROR(pDevIns, rc,
732 N_("Configuration error: Failed to get the \"R0Enabled\" value"));
733
734 uint8_t irq_lvl;
735 rc = CFGMR3QueryU8Def(pCfgHandle, "IRQ", &irq_lvl, 7);
736 if (RT_FAILURE(rc))
737 return PDMDEV_SET_ERROR(pDevIns, rc,
738 N_("Configuration error: Failed to get the \"IRQ\" value"));
739
740 uint16_t io_base;
741 rc = CFGMR3QueryU16Def(pCfgHandle, "IOBase", &io_base, 0x378);
742 if (RT_FAILURE(rc))
743 return PDMDEV_SET_ERROR(pDevIns, rc,
744 N_("Configuration error: Failed to get the \"IOBase\" value"));
745
746 Log(("parallelConstruct instance %d iobase=%04x irq=%d\n", iInstance, io_base, irq_lvl));
747
748 pThis->irq = irq_lvl;
749 pThis->base = io_base;
750
751 /*
752 * Initialize critical section and event semaphore.
753 * This must of course be done before attaching drivers or anything else which can call us back..
754 */
755 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "Parallel#%d", iInstance);
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 = PDMDevHlpIOPortRegisterRC(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 = PDMDevHlpSSMRegister3(pDevIns, PARALLEL_SAVED_STATE_VERSION, sizeof(*pThis),
812 parallelLiveExec, parallelSaveExec, parallelLoadExec);
813 if (RT_FAILURE(rc))
814 return rc;
815
816
817 /*
818 * Attach the parallel port driver and get the interfaces.
819 * For now no run-time changes are supported.
820 */
821 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Parallel Host");
822 if (RT_SUCCESS(rc))
823 {
824 pThis->pDrvHostParallelConnector = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIHOSTPARALLELCONNECTOR);
825 AssertMsgReturn(pThis->pDrvHostParallelConnector,
826 ("Configuration error: instance %d has no host parallel interface!\n", iInstance),
827 VERR_PDM_MISSING_INTERFACE);
828 /** @todo provide read notification interface!!!! */
829 }
830 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
831 {
832 pThis->pDrvBase = NULL;
833 pThis->pDrvHostParallelConnector = NULL;
834 LogRel(("Parallel%d: no unit\n", iInstance));
835 }
836 else
837 {
838 AssertMsgFailed(("Parallel%d: Failed to attach to host driver. rc=%Rrc\n", iInstance, rc));
839 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
840 N_("Parallel device %d cannot attach to host driver"), iInstance);
841 }
842
843 /* Set compatibility mode */
844 pThis->pDrvHostParallelConnector->pfnSetMode(pThis->pDrvHostParallelConnector, PDM_PARALLEL_PORT_MODE_COMPAT);
845 /* Get status of control register */
846 pThis->pDrvHostParallelConnector->pfnReadControl(pThis->pDrvHostParallelConnector, &pThis->reg_control);
847
848 return VINF_SUCCESS;
849}
850
851/**
852 * The device registration structure.
853 */
854const PDMDEVREG g_DeviceParallelPort =
855{
856 /* u32Version */
857 PDM_DEVREG_VERSION,
858 /* szName */
859 "parallel",
860 /* szRCMod */
861 "VBoxDDGC.gc",
862 /* szR0Mod */
863 "VBoxDDR0.r0",
864 /* pszDescription */
865 "Parallel Communication Port",
866 /* fFlags */
867 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
868 /* fClass */
869 PDM_DEVREG_CLASS_PARALLEL,
870 /* cMaxInstances */
871 1,
872 /* cbInstance */
873 sizeof(ParallelState),
874 /* pfnConstruct */
875 parallelConstruct,
876 /* pfnDestruct */
877 parallelDestruct,
878 /* pfnRelocate */
879 parallelRelocate,
880 /* pfnIOCtl */
881 NULL,
882 /* pfnPowerOn */
883 NULL,
884 /* pfnReset */
885 NULL,
886 /* pfnSuspend */
887 NULL,
888 /* pfnResume */
889 NULL,
890 /* pfnAttach */
891 NULL,
892 /* pfnDetach */
893 NULL,
894 /* pfnQueryInterface. */
895 NULL,
896 /* pfnInitComplete */
897 NULL,
898 /* pfnPowerOff */
899 NULL,
900 /* pfnSoftReset */
901 NULL,
902 /* u32VersionEnd */
903 PDM_DEVREG_VERSION
904};
905#endif /* IN_RING3 */
906
907
908#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