VirtualBox

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

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

Automated rebranding to Oracle copyright/license strings via filemuncher

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