VirtualBox

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

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

DevParallel: verify config on load.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 29.7 KB
Line 
1/* $Id: DevParallel.cpp 23989 2009-10-22 14:42:12Z 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*******************************************************************************/
155RT_C_DECLS_BEGIN
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
162RT_C_DECLS_END
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 * @copydoc FNSSMDEVLIVEEXEC
564 */
565static DECLCALLBACK(int) parallelLiveExec(PPDMDEVINS pDevIns,
566 PSSMHANDLE pSSMHandle,
567 uint32_t uPass)
568{
569 ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
570
571 SSMR3PutS32(pSSMHandle, pThis->irq);
572 SSMR3PutU32(pSSMHandle, pThis->base);
573 SSMR3PutU32(pSSMHandle, ~0); /* sanity/terminator */
574 return VINF_SSM_DONT_CALL_AGAIN;
575}
576
577/**
578 * @copydoc FNSSMDEVSAVEEXEC
579 */
580static DECLCALLBACK(int) parallelSaveExec(PPDMDEVINS pDevIns,
581 PSSMHANDLE pSSMHandle)
582{
583 ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
584
585 SSMR3PutU8(pSSMHandle, pThis->reg_data);
586 SSMR3PutU8(pSSMHandle, pThis->reg_status);
587 SSMR3PutU8(pSSMHandle, pThis->reg_control);
588
589 parallelLiveExec(pDevIns, pSSMHandle, 0);
590 return VINF_SUCCESS;
591}
592
593/**
594 * @copydoc FNSSMDEVLOADEXEC
595 */
596static DECLCALLBACK(int) parallelLoadExec(PPDMDEVINS pDevIns,
597 PSSMHANDLE pSSMHandle,
598 uint32_t uVersion,
599 uint32_t uPass)
600{
601 ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
602
603 AssertMsgReturn(uVersion == PARALLEL_SAVED_STATE_VERSION, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
604 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
605 if (uPass == SSM_PASS_FINAL)
606 {
607 SSMR3GetU8(pSSMHandle, &pThis->reg_data);
608 SSMR3GetU8(pSSMHandle, &pThis->reg_status);
609 SSMR3GetU8(pSSMHandle, &pThis->reg_control);
610 }
611
612 /* the config */
613 int32_t iIrq;
614 SSMR3GetS32(pSSMHandle, &iIrq);
615 uint32_t uIoBase;
616 SSMR3GetU32(pSSMHandle, &uIoBase);
617 uint32_t u32;
618 int rc = SSMR3GetU32(pSSMHandle, &u32);
619 if (RT_FAILURE(rc))
620 return rc;
621 AssertMsgReturn(u32 == ~0U, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
622
623 if (pThis->irq != iIrq)
624 {
625 LogRel(("Parallel: IRQ changed: config=%#x state=%#x\n", pThis->irq, iIrq));
626 return VERR_SSM_LOAD_CONFIG_MISMATCH;
627 }
628
629 if (pThis->base != uIoBase)
630 {
631 LogRel(("Parallel: IOBase changed: config=%#x state=%#x\n", pThis->base, uIoBase));
632 return VERR_SSM_LOAD_CONFIG_MISMATCH;
633 }
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/** @copyfrom PIBASE::pfnqueryInterface */
653static DECLCALLBACK(void *) parallelQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
654{
655 ParallelState *pThis = PDMIBASE_2_PARALLELSTATE(pInterface);
656 switch (enmInterface)
657 {
658 case PDMINTERFACE_BASE:
659 return &pThis->IBase;
660 case PDMINTERFACE_HOST_PARALLEL_PORT:
661 return &pThis->IHostParallelPort;
662 default:
663 return NULL;
664 }
665}
666
667/**
668 * Destruct a device instance.
669 *
670 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
671 * resources can be freed correctly.
672 *
673 * @returns VBox status.
674 * @param pDevIns The device instance data.
675 */
676static DECLCALLBACK(int) parallelDestruct(PPDMDEVINS pDevIns)
677{
678 ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState *);
679
680 PDMR3CritSectDelete(&pThis->CritSect);
681 RTSemEventDestroy(pThis->ReceiveSem);
682
683 return VINF_SUCCESS;
684}
685
686
687/**
688 * Construct a device instance for a VM.
689 *
690 * @returns VBox status.
691 * @param pDevIns The device instance data.
692 * If the registration structure is needed, pDevIns->pDevReg points to it.
693 * @param iInstance Instance number. Use this to figure out which registers and such to use.
694 * The device number is also found in pDevIns->iInstance, but since it's
695 * likely to be freqently used PDM passes it as parameter.
696 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
697 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
698 * iInstance it's expected to be used a bit in this function.
699 */
700static DECLCALLBACK(int) parallelConstruct(PPDMDEVINS pDevIns,
701 int iInstance,
702 PCFGMNODE pCfgHandle)
703{
704 int rc;
705 ParallelState *pThis = PDMINS_2_DATA(pDevIns, ParallelState*);
706
707 Assert(iInstance < 4);
708
709 /*
710 * Init the data so parallelDestruct doesn't choke.
711 */
712 pThis->pDevInsR3 = pDevIns;
713 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
714 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
715 pThis->ReceiveSem = NIL_RTSEMEVENT;
716
717 /* IBase */
718 pThis->IBase.pfnQueryInterface = parallelQueryInterface;
719
720 /* IHostParallelPort */
721 pThis->IHostParallelPort.pfnNotifyInterrupt = parallelNotifyInterrupt;
722
723 /* Init parallel state */
724 pThis->reg_data = 0;
725 pThis->reg_ecp_ecr = LPT_ECP_ECR_CHIPMODE_COMPAT | LPT_ECP_ECR_FIFO_EMPTY;
726 pThis->act_fifo_pos_read = 0;
727 pThis->act_fifo_pos_write = 0;
728
729 /*
730 * Validate and read the configuration.
731 */
732 if (!CFGMR3AreValuesValid(pCfgHandle, "IRQ\0" "IOBase\0" "GCEnabled\0" "R0Enabled\0"))
733 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
734 N_("Configuration error: Unknown config key"));
735
736 rc = CFGMR3QueryBoolDef(pCfgHandle, "GCEnabled", &pThis->fGCEnabled, true);
737 if (RT_FAILURE(rc))
738 return PDMDEV_SET_ERROR(pDevIns, rc,
739 N_("Configuration error: Failed to get the \"GCEnabled\" value"));
740
741 rc = CFGMR3QueryBoolDef(pCfgHandle, "R0Enabled", &pThis->fR0Enabled, true);
742 if (RT_FAILURE(rc))
743 return PDMDEV_SET_ERROR(pDevIns, rc,
744 N_("Configuration error: Failed to get the \"R0Enabled\" value"));
745
746 uint8_t irq_lvl;
747 rc = CFGMR3QueryU8Def(pCfgHandle, "IRQ", &irq_lvl, 7);
748 if (RT_FAILURE(rc))
749 return PDMDEV_SET_ERROR(pDevIns, rc,
750 N_("Configuration error: Failed to get the \"IRQ\" value"));
751
752 uint16_t io_base;
753 rc = CFGMR3QueryU16Def(pCfgHandle, "IOBase", &io_base, 0x378);
754 if (RT_FAILURE(rc))
755 return PDMDEV_SET_ERROR(pDevIns, rc,
756 N_("Configuration error: Failed to get the \"IOBase\" value"));
757
758 Log(("parallelConstruct instance %d iobase=%04x irq=%d\n", iInstance, io_base, irq_lvl));
759
760 pThis->irq = irq_lvl;
761 pThis->base = io_base;
762
763 /*
764 * Initialize critical section and event semaphore.
765 * This must of course be done before attaching drivers or anything else which can call us back..
766 */
767 char szName[24];
768 RTStrPrintf(szName, sizeof(szName), "Parallel#%d", iInstance);
769 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, szName);
770 if (RT_FAILURE(rc))
771 return rc;
772
773 rc = RTSemEventCreate(&pThis->ReceiveSem);
774 if (RT_FAILURE(rc))
775 return rc;
776
777 /*
778 * Register the I/O ports and saved state.
779 */
780 rc = PDMDevHlpIOPortRegister(pDevIns, io_base, 8, 0,
781 parallelIOPortWrite, parallelIOPortRead,
782 NULL, NULL, "PARALLEL");
783 if (RT_FAILURE(rc))
784 return rc;
785
786#if 0
787 /* register ecp registers */
788 rc = PDMDevHlpIOPortRegister(pDevIns, io_base+0x400, 8, 0,
789 parallelIOPortWriteECP, parallelIOPortReadECP,
790 NULL, NULL, "PARALLEL ECP");
791 if (RT_FAILURE(rc))
792 return rc;
793#endif
794
795 if (pThis->fGCEnabled)
796 {
797 rc = PDMDevHlpIOPortRegisterGC(pDevIns, io_base, 8, 0, "parallelIOPortWrite",
798 "parallelIOPortRead", NULL, NULL, "Parallel");
799 if (RT_FAILURE(rc))
800 return rc;
801
802#if 0
803 rc = PDMDevHlpIOPortRegisterGC(pDevIns, io_base+0x400, 8, 0, "parallelIOPortWriteECP",
804 "parallelIOPortReadECP", NULL, NULL, "Parallel Ecp");
805 if (RT_FAILURE(rc))
806 return rc;
807#endif
808 }
809
810 if (pThis->fR0Enabled)
811 {
812 rc = PDMDevHlpIOPortRegisterR0(pDevIns, io_base, 8, 0, "parallelIOPortWrite",
813 "parallelIOPortRead", NULL, NULL, "Parallel");
814 if (RT_FAILURE(rc))
815 return rc;
816
817#if 0
818 rc = PDMDevHlpIOPortRegisterR0(pDevIns, io_base+0x400, 8, 0, "parallelIOPortWriteECP",
819 "parallelIOPortReadECP", NULL, NULL, "Parallel Ecp");
820 if (RT_FAILURE(rc))
821 return rc;
822#endif
823 }
824
825 rc = PDMDevHlpSSMRegister3(pDevIns, PARALLEL_SAVED_STATE_VERSION, sizeof(*pThis),
826 parallelLiveExec, parallelSaveExec, parallelLoadExec);
827 if (RT_FAILURE(rc))
828 return rc;
829
830
831 /*
832 * Attach the parallel port driver and get the interfaces.
833 * For now no run-time changes are supported.
834 */
835 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Parallel Host");
836 if (RT_SUCCESS(rc))
837 {
838 pThis->pDrvHostParallelConnector = (PDMIHOSTPARALLELCONNECTOR *)pThis->pDrvBase->pfnQueryInterface(pThis->pDrvBase,
839 PDMINTERFACE_HOST_PARALLEL_CONNECTOR);
840 if (!pThis->pDrvHostParallelConnector)
841 {
842 AssertMsgFailed(("Configuration error: instance %d has no host parallel interface!\n", iInstance));
843 return VERR_PDM_MISSING_INTERFACE;
844 }
845 /** @todo provide read notification interface!!!! */
846 }
847 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
848 {
849 pThis->pDrvBase = NULL;
850 pThis->pDrvHostParallelConnector = NULL;
851 LogRel(("Parallel%d: no unit\n", iInstance));
852 }
853 else
854 {
855 AssertMsgFailed(("Parallel%d: Failed to attach to host driver. rc=%Rrc\n", iInstance, rc));
856 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
857 N_("Parallel device %d cannot attach to host driver"), iInstance);
858 }
859
860 /* Set compatibility mode */
861 pThis->pDrvHostParallelConnector->pfnSetMode(pThis->pDrvHostParallelConnector, PDM_PARALLEL_PORT_MODE_COMPAT);
862 /* Get status of control register */
863 pThis->pDrvHostParallelConnector->pfnReadControl(pThis->pDrvHostParallelConnector, &pThis->reg_control);
864
865 return VINF_SUCCESS;
866}
867
868/**
869 * The device registration structure.
870 */
871const PDMDEVREG g_DeviceParallelPort =
872{
873 /* u32Version */
874 PDM_DEVREG_VERSION,
875 /* szDeviceName */
876 "parallel",
877 /* szRCMod */
878 "VBoxDDGC.gc",
879 /* szR0Mod */
880 "VBoxDDR0.r0",
881 /* pszDescription */
882 "Parallel Communication Port",
883 /* fFlags */
884 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
885 /* fClass */
886 PDM_DEVREG_CLASS_PARALLEL,
887 /* cMaxInstances */
888 1,
889 /* cbInstance */
890 sizeof(ParallelState),
891 /* pfnConstruct */
892 parallelConstruct,
893 /* pfnDestruct */
894 parallelDestruct,
895 /* pfnRelocate */
896 parallelRelocate,
897 /* pfnIOCtl */
898 NULL,
899 /* pfnPowerOn */
900 NULL,
901 /* pfnReset */
902 NULL,
903 /* pfnSuspend */
904 NULL,
905 /* pfnResume */
906 NULL,
907 /* pfnAttach */
908 NULL,
909 /* pfnDetach */
910 NULL,
911 /* pfnQueryInterface. */
912 NULL,
913 /* pfnInitComplete */
914 NULL,
915 /* pfnPowerOff */
916 NULL,
917 /* pfnSoftReset */
918 NULL,
919 /* u32VersionEnd */
920 PDM_DEVREG_VERSION
921};
922#endif /* IN_RING3 */
923
924
925#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