VirtualBox

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

Last change on this file since 37808 was 37466, checked in by vboxsync, 14 years ago

VMM,Devices: Automatically use a per-device lock instead of the giant IOM lock. With exception of the PIC, APIC, IOAPIC and PCI buses which are all using the PDM crit sect, there should be no calls between devices. So, this change should be relatively safe.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 28.5 KB
Line 
1/* $Id: DevParallel.cpp 37466 2011-06-15 12:44:16Z 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/vmm/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 "VBoxDD.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#%u", 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