VirtualBox

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

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

PDMIBASE refactoring; use UUID as interface IDs.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 29.6 KB
Line 
1/* $Id: DevParallel.cpp 25966 2010-01-22 11:15:43Z 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 if (RTUuidCompare2Strs(pszIID, PDMIBASE_IID) == 0)
659 return &pThis->IBase;
660 if (RTUuidCompare2Strs(pszIID, PDMINTERFACE_HOST_PARALLEL_PORT) == 0)
661 return &pThis->IHostParallelPort;
662 return NULL;
663}
664
665/**
666 * Destruct a device instance.
667 *
668 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
669 * resources can be freed correctly.
670 *
671 * @returns VBox status.
672 * @param pDevIns The device instance data.
673 */
674static DECLCALLBACK(int) parallelDestruct(PPDMDEVINS pDevIns)
675{
676 ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
677
678 PDMR3CritSectDelete(&pThis->CritSect);
679 RTSemEventDestroy(pThis->ReceiveSem);
680
681 return VINF_SUCCESS;
682}
683
684
685/**
686 * Construct a device instance for a VM.
687 *
688 * @returns VBox status.
689 * @param pDevIns The device instance data.
690 * If the registration structure is needed, pDevIns->pDevReg points to it.
691 * @param iInstance Instance number. Use this to figure out which registers and such to use.
692 * The device number is also found in pDevIns->iInstance, but since it's
693 * likely to be freqently used PDM passes it as parameter.
694 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
695 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
696 * iInstance it's expected to be used a bit in this function.
697 */
698static DECLCALLBACK(int) parallelConstruct(PPDMDEVINS pDevIns,
699 int iInstance,
700 PCFGMNODE pCfgHandle)
701{
702 int rc;
703 ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState*);
704
705 Assert(iInstance < 4);
706
707 /*
708 * Init the data so parallelDestruct doesn't choke.
709 */
710 pThis->pDevInsR3 = pDevIns;
711 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
712 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
713 pThis->ReceiveSem = NIL_RTSEMEVENT;
714
715 /* IBase */
716 pThis->IBase.pfnQueryInterface = parallelQueryInterface;
717
718 /* IHostParallelPort */
719 pThis->IHostParallelPort.pfnNotifyInterrupt = parallelNotifyInterrupt;
720
721 /* Init parallel state */
722 pThis->reg_data = 0;
723 pThis->reg_ecp_ecr = LPT_ECP_ECR_CHIPMODE_COMPAT | LPT_ECP_ECR_FIFO_EMPTY;
724 pThis->act_fifo_pos_read = 0;
725 pThis->act_fifo_pos_write = 0;
726
727 /*
728 * Validate and read the configuration.
729 */
730 if (!CFGMR3AreValuesValid(pCfgHandle, "IRQ\0" "IOBase\0" "GCEnabled\0" "R0Enabled\0"))
731 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
732 N_("Configuration error: Unknown config key"));
733
734 rc = CFGMR3QueryBoolDef(pCfgHandle, "GCEnabled", &pThis->fGCEnabled, true);
735 if (RT_FAILURE(rc))
736 return PDMDEV_SET_ERROR(pDevIns, rc,
737 N_("Configuration error: Failed to get the \"GCEnabled\" value"));
738
739 rc = CFGMR3QueryBoolDef(pCfgHandle, "R0Enabled", &pThis->fR0Enabled, true);
740 if (RT_FAILURE(rc))
741 return PDMDEV_SET_ERROR(pDevIns, rc,
742 N_("Configuration error: Failed to get the \"R0Enabled\" value"));
743
744 uint8_t irq_lvl;
745 rc = CFGMR3QueryU8Def(pCfgHandle, "IRQ", &irq_lvl, 7);
746 if (RT_FAILURE(rc))
747 return PDMDEV_SET_ERROR(pDevIns, rc,
748 N_("Configuration error: Failed to get the \"IRQ\" value"));
749
750 uint16_t io_base;
751 rc = CFGMR3QueryU16Def(pCfgHandle, "IOBase", &io_base, 0x378);
752 if (RT_FAILURE(rc))
753 return PDMDEV_SET_ERROR(pDevIns, rc,
754 N_("Configuration error: Failed to get the \"IOBase\" value"));
755
756 Log(("parallelConstruct instance %d iobase=%04x irq=%d\n", iInstance, io_base, irq_lvl));
757
758 pThis->irq = irq_lvl;
759 pThis->base = io_base;
760
761 /*
762 * Initialize critical section and event semaphore.
763 * This must of course be done before attaching drivers or anything else which can call us back..
764 */
765 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "Parallel#%d", iInstance);
766 if (RT_FAILURE(rc))
767 return rc;
768
769 rc = RTSemEventCreate(&pThis->ReceiveSem);
770 if (RT_FAILURE(rc))
771 return rc;
772
773 /*
774 * Register the I/O ports and saved state.
775 */
776 rc = PDMDevHlpIOPortRegister(pDevIns, io_base, 8, 0,
777 parallelIOPortWrite, parallelIOPortRead,
778 NULL, NULL, "PARALLEL");
779 if (RT_FAILURE(rc))
780 return rc;
781
782#if 0
783 /* register ecp registers */
784 rc = PDMDevHlpIOPortRegister(pDevIns, io_base+0x400, 8, 0,
785 parallelIOPortWriteECP, parallelIOPortReadECP,
786 NULL, NULL, "PARALLEL ECP");
787 if (RT_FAILURE(rc))
788 return rc;
789#endif
790
791 if (pThis->fGCEnabled)
792 {
793 rc = PDMDevHlpIOPortRegisterGC(pDevIns, io_base, 8, 0, "parallelIOPortWrite",
794 "parallelIOPortRead", NULL, NULL, "Parallel");
795 if (RT_FAILURE(rc))
796 return rc;
797
798#if 0
799 rc = PDMDevHlpIOPortRegisterGC(pDevIns, io_base+0x400, 8, 0, "parallelIOPortWriteECP",
800 "parallelIOPortReadECP", NULL, NULL, "Parallel Ecp");
801 if (RT_FAILURE(rc))
802 return rc;
803#endif
804 }
805
806 if (pThis->fR0Enabled)
807 {
808 rc = PDMDevHlpIOPortRegisterR0(pDevIns, io_base, 8, 0, "parallelIOPortWrite",
809 "parallelIOPortRead", NULL, NULL, "Parallel");
810 if (RT_FAILURE(rc))
811 return rc;
812
813#if 0
814 rc = PDMDevHlpIOPortRegisterR0(pDevIns, io_base+0x400, 8, 0, "parallelIOPortWriteECP",
815 "parallelIOPortReadECP", NULL, NULL, "Parallel Ecp");
816 if (RT_FAILURE(rc))
817 return rc;
818#endif
819 }
820
821 rc = PDMDevHlpSSMRegister3(pDevIns, PARALLEL_SAVED_STATE_VERSION, sizeof(*pThis),
822 parallelLiveExec, parallelSaveExec, parallelLoadExec);
823 if (RT_FAILURE(rc))
824 return rc;
825
826
827 /*
828 * Attach the parallel port driver and get the interfaces.
829 * For now no run-time changes are supported.
830 */
831 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Parallel Host");
832 if (RT_SUCCESS(rc))
833 {
834 pThis->pDrvHostParallelConnector = (PDMIHOSTPARALLELCONNECTOR *)pThis->pDrvBase->pfnQueryInterface(pThis->pDrvBase,
835 PDMINTERFACE_HOST_PARALLEL_CONNECTOR);
836 if (!pThis->pDrvHostParallelConnector)
837 {
838 AssertMsgFailed(("Configuration error: instance %d has no host parallel interface!\n", iInstance));
839 return VERR_PDM_MISSING_INTERFACE;
840 }
841 /** @todo provide read notification interface!!!! */
842 }
843 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
844 {
845 pThis->pDrvBase = NULL;
846 pThis->pDrvHostParallelConnector = NULL;
847 LogRel(("Parallel%d: no unit\n", iInstance));
848 }
849 else
850 {
851 AssertMsgFailed(("Parallel%d: Failed to attach to host driver. rc=%Rrc\n", iInstance, rc));
852 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
853 N_("Parallel device %d cannot attach to host driver"), iInstance);
854 }
855
856 /* Set compatibility mode */
857 pThis->pDrvHostParallelConnector->pfnSetMode(pThis->pDrvHostParallelConnector, PDM_PARALLEL_PORT_MODE_COMPAT);
858 /* Get status of control register */
859 pThis->pDrvHostParallelConnector->pfnReadControl(pThis->pDrvHostParallelConnector, &pThis->reg_control);
860
861 return VINF_SUCCESS;
862}
863
864/**
865 * The device registration structure.
866 */
867const PDMDEVREG g_DeviceParallelPort =
868{
869 /* u32Version */
870 PDM_DEVREG_VERSION,
871 /* szDeviceName */
872 "parallel",
873 /* szRCMod */
874 "VBoxDDGC.gc",
875 /* szR0Mod */
876 "VBoxDDR0.r0",
877 /* pszDescription */
878 "Parallel Communication Port",
879 /* fFlags */
880 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
881 /* fClass */
882 PDM_DEVREG_CLASS_PARALLEL,
883 /* cMaxInstances */
884 1,
885 /* cbInstance */
886 sizeof(ParallelState),
887 /* pfnConstruct */
888 parallelConstruct,
889 /* pfnDestruct */
890 parallelDestruct,
891 /* pfnRelocate */
892 parallelRelocate,
893 /* pfnIOCtl */
894 NULL,
895 /* pfnPowerOn */
896 NULL,
897 /* pfnReset */
898 NULL,
899 /* pfnSuspend */
900 NULL,
901 /* pfnResume */
902 NULL,
903 /* pfnAttach */
904 NULL,
905 /* pfnDetach */
906 NULL,
907 /* pfnQueryInterface. */
908 NULL,
909 /* pfnInitComplete */
910 NULL,
911 /* pfnPowerOff */
912 NULL,
913 /* pfnSoftReset */
914 NULL,
915 /* u32VersionEnd */
916 PDM_DEVREG_VERSION
917};
918#endif /* IN_RING3 */
919
920
921#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