VirtualBox

source: vbox/trunk/src/VBox/Devices/Serial/serial.c@ 1712

Last change on this file since 1712 was 1712, checked in by vboxsync, 18 years ago

Cleaned up a bit.

  • Property svn:eol-style set to native
File size: 23.5 KB
Line 
1/** @file
2 *
3 * VBox serial device:
4 * Serial communication port driver
5 */
6
7/*
8 * Copyright (C) 2006 InnoTek Systemberatung GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * If you received this file as part of a commercial VirtualBox
19 * distribution, then only the terms of your commercial VirtualBox
20 * license agreement apply instead of the previous paragraph.
21 *
22 * --------------------------------------------------------------------
23 *
24 * This code is based on:
25 *
26 * QEMU 16450 UART emulation
27 *
28 * Copyright (c) 2003-2004 Fabrice Bellard
29 *
30 * Permission is hereby granted, free of charge, to any person obtaining a copy
31 * of this software and associated documentation files (the "Software"), to deal
32 * in the Software without restriction, including without limitation the rights
33 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
34 * copies of the Software, and to permit persons to whom the Software is
35 * furnished to do so, subject to the following conditions:
36 *
37 * The above copyright notice and this permission notice shall be included in
38 * all copies or substantial portions of the Software.
39 *
40 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
43 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
44 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
45 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
46 * THE SOFTWARE.
47 *
48 */
49
50
51/*******************************************************************************
52* Header Files *
53*******************************************************************************/
54#define LOG_GROUP LOG_GROUP_DEV_SERIAL
55#include <VBox/pdm.h>
56#include <VBox/err.h>
57
58#include <VBox/log.h>
59#include <iprt/assert.h>
60#include <iprt/uuid.h>
61#include <iprt/string.h>
62#include <iprt/semaphore.h>
63
64#include "Builtins.h"
65#include "../vl_vbox.h"
66
67#undef VBOX_SERIAL_PCI /* The PCI variant has lots of problems: wrong IRQ line and wrong IO base assigned. */
68
69#ifdef VBOX_SERIAL_PCI
70#include <VBox/pci.h>
71#endif /* VBOX_SERIAL_PCI */
72
73#define SERIAL_SAVED_STATE_VERSION 2
74
75#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
76
77#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */
78#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */
79#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */
80#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */
81
82#define UART_IIR_NO_INT 0x01 /* No interrupts pending */
83#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */
84
85#define UART_IIR_MSI 0x00 /* Modem status interrupt */
86#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */
87#define UART_IIR_RDI 0x04 /* Receiver data interrupt */
88#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */
89
90/*
91 * These are the definitions for the Modem Control Register
92 */
93#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
94#define UART_MCR_OUT2 0x08 /* Out2 complement */
95#define UART_MCR_OUT1 0x04 /* Out1 complement */
96#define UART_MCR_RTS 0x02 /* RTS complement */
97#define UART_MCR_DTR 0x01 /* DTR complement */
98
99/*
100 * These are the definitions for the Modem Status Register
101 */
102#define UART_MSR_DCD 0x80 /* Data Carrier Detect */
103#define UART_MSR_RI 0x40 /* Ring Indicator */
104#define UART_MSR_DSR 0x20 /* Data Set Ready */
105#define UART_MSR_CTS 0x10 /* Clear to Send */
106#define UART_MSR_DDCD 0x08 /* Delta DCD */
107#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */
108#define UART_MSR_DDSR 0x02 /* Delta DSR */
109#define UART_MSR_DCTS 0x01 /* Delta CTS */
110#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */
111
112#define UART_LSR_TEMT 0x40 /* Transmitter empty */
113#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
114#define UART_LSR_BI 0x10 /* Break interrupt indicator */
115#define UART_LSR_FE 0x08 /* Frame error indicator */
116#define UART_LSR_PE 0x04 /* Parity error indicator */
117#define UART_LSR_OE 0x02 /* Overrun error indicator */
118#define UART_LSR_DR 0x01 /* Receiver data ready */
119
120struct SerialState {
121 uint16_t divider;
122 uint8_t rbr; /* receive register */
123 uint8_t ier;
124 uint8_t iir; /* read only */
125 uint8_t lcr;
126 uint8_t mcr;
127 uint8_t lsr; /* read only */
128 uint8_t msr; /* read only */
129 uint8_t scr;
130 /* NOTE: this hidden state is necessary for tx irq generation as
131 it can be reset while reading iir */
132 int thr_ipending;
133 int irq;
134
135 bool fGCEnabled;
136 bool fR0Enabled;
137
138#ifdef VBOX_SERIAL_PCI
139 PCIDEVICE dev;
140#endif /* VBOX_SERIAL_PCI */
141 /** Pointer to the device instance. */
142 GCPTRTYPE(PPDMDEVINS) pDevInsGC;
143 /** Pointer to the device instance. */
144 HCPTRTYPE(PPDMDEVINS) pDevInsHC;
145 /** The base interface. */
146 PDMIBASE IBase;
147 /** The character port interface. */
148 PDMICHARPORT ICharPort;
149 /** Pointer to the attached base driver. */
150 HCPTRTYPE(PPDMIBASE) pDrvBase;
151 /** Pointer to the attached character driver. */
152 PPDMICHAR pDrvChar;
153
154 RTSEMEVENT ReceiveSem;
155 int last_break_enable;
156 target_ulong base;
157};
158
159#ifdef VBOX_SERIAL_PCI
160#define PCIDEV_2_SERIALSTATE(pPciDev) ( (SerialState *)((uintptr_t)(pPciDev) - RT_OFFSETOF(SerialState, dev)) )
161#endif /* VBOX_SERIAL_PCI */
162#define PDMIBASE_2_SERIALSTATE(pInstance) ( (SerialState *)((uintptr_t)(pInterface) - RT_OFFSETOF(SerialState, IBase)) )
163#define PDMICHARPORT_2_SERIALSTATE(pInstance) ( (SerialState *)((uintptr_t)(pInterface) - RT_OFFSETOF(SerialState, ICharPort)) )
164
165static void serial_update_irq(SerialState *s)
166{
167 if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) {
168 s->iir = UART_IIR_RDI;
169 } else if (s->thr_ipending && (s->ier & UART_IER_THRI)) {
170 s->iir = UART_IIR_THRI;
171 } else {
172 s->iir = UART_IIR_NO_INT;
173 }
174 if (s->iir != UART_IIR_NO_INT) {
175#ifdef VBOX_SERIAL_PCI
176 PDMDevHlpPCISetIrqNoWait(CTXSUFF(s->pDevIns), 0, 1);
177#else /* !VBOX_SERIAL_PCI */
178 PDMDevHlpISASetIrqNoWait(CTXSUFF(s->pDevIns), s->irq, 1);
179#endif /* !VBOX_SERIAL_PCI */
180 } else {
181#ifdef VBOX_SERIAL_PCI
182 PDMDevHlpPCISetIrqNoWait(CTXSUFF(s->pDevIns), 0, 0);
183#else /* !VBOX_SERIAL_PCI */
184 PDMDevHlpISASetIrqNoWait(CTXSUFF(s->pDevIns), s->irq, 0);
185#endif /* !VBOX_SERIAL_PCI */
186 }
187}
188
189static void serial_update_parameters(SerialState *s)
190{
191 int speed, parity, data_bits, stop_bits;
192 QEMUSerialSetParams ssp;
193
194 if (s->lcr & 0x08) {
195 if (s->lcr & 0x10)
196 parity = 'E';
197 else
198 parity = 'O';
199 } else {
200 parity = 'N';
201 }
202 if (s->lcr & 0x04)
203 stop_bits = 2;
204 else
205 stop_bits = 1;
206 data_bits = (s->lcr & 0x03) + 5;
207 if (s->divider == 0)
208 return;
209 speed = 115200 / s->divider;
210 ssp.speed = speed;
211 ssp.parity = parity;
212 ssp.data_bits = data_bits;
213 ssp.stop_bits = stop_bits;
214 Log(("speed=%d parity=%c data=%d stop=%d\n", speed, parity, data_bits, stop_bits));
215}
216
217static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
218{
219 SerialState *s = opaque;
220 unsigned char ch;
221
222 addr &= 7;
223 LogFlow(("serial: write addr=0x%02x val=0x%02x\n", addr, val));
224 switch(addr) {
225 default:
226 case 0:
227 if (s->lcr & UART_LCR_DLAB) {
228 s->divider = (s->divider & 0xff00) | val;
229 serial_update_parameters(s);
230 } else {
231 s->thr_ipending = 0;
232 s->lsr &= ~UART_LSR_THRE;
233 serial_update_irq(s);
234 ch = val;
235 /** @todo implement backpressure for writing (don't set interrupt
236 * bits/line until the character is actually written). This way
237 * EMT wouldn't block for writes taking longer than normal. */
238 if (s->pDrvChar)
239 {
240 int rc = s->pDrvChar->pfnWrite(s->pDrvChar, &ch, 1);
241 AssertRC(rc);
242 }
243 s->thr_ipending = 1;
244 s->lsr |= UART_LSR_THRE;
245 s->lsr |= UART_LSR_TEMT;
246 serial_update_irq(s);
247 }
248 break;
249 case 1:
250 if (s->lcr & UART_LCR_DLAB) {
251 s->divider = (s->divider & 0x00ff) | (val << 8);
252 serial_update_parameters(s);
253 } else {
254 s->ier = val & 0x0f;
255 if (s->lsr & UART_LSR_THRE) {
256 s->thr_ipending = 1;
257 }
258 serial_update_irq(s);
259 }
260 break;
261 case 2:
262 break;
263 case 3:
264 {
265 int break_enable;
266 s->lcr = val;
267 serial_update_parameters(s);
268 break_enable = (val >> 6) & 1;
269 if (break_enable != s->last_break_enable) {
270 s->last_break_enable = break_enable;
271 }
272 }
273 break;
274 case 4:
275 s->mcr = val & 0x1f;
276 break;
277 case 5:
278 break;
279 case 6:
280 break;
281 case 7:
282 s->scr = val;
283 break;
284 }
285}
286
287static uint32_t serial_ioport_read(void *opaque, uint32_t addr)
288{
289 SerialState *s = opaque;
290 uint32_t ret;
291
292 addr &= 7;
293 switch(addr) {
294 default:
295 case 0:
296 if (s->lcr & UART_LCR_DLAB) {
297 ret = s->divider & 0xff;
298 } else {
299 ret = s->rbr;
300 s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
301 serial_update_irq(s);
302 {
303 int rc = RTSemEventSignal(s->ReceiveSem);
304 AssertRC(rc);
305 }
306 }
307 break;
308 case 1:
309 if (s->lcr & UART_LCR_DLAB) {
310 ret = (s->divider >> 8) & 0xff;
311 } else {
312 ret = s->ier;
313 }
314 break;
315 case 2:
316 ret = s->iir;
317 /* reset THR pending bit */
318 if ((ret & 0x7) == UART_IIR_THRI)
319 s->thr_ipending = 0;
320 serial_update_irq(s);
321 break;
322 case 3:
323 ret = s->lcr;
324 break;
325 case 4:
326 ret = s->mcr;
327 break;
328 case 5:
329 ret = s->lsr;
330 break;
331 case 6:
332 if (s->mcr & UART_MCR_LOOP) {
333 /* in loopback, the modem output pins are connected to the
334 inputs */
335 ret = (s->mcr & 0x0c) << 4;
336 ret |= (s->mcr & 0x02) << 3;
337 ret |= (s->mcr & 0x01) << 5;
338 } else {
339 ret = s->msr;
340 }
341 break;
342 case 7:
343 ret = s->scr;
344 break;
345 }
346 LogFlow(("serial: read addr=0x%02x val=0x%02x\n", addr, ret));
347 return ret;
348}
349
350static DECLCALLBACK(int) serialNotifyRead(PPDMICHARPORT pInterface, const void *pvBuf, size_t *pcbRead)
351{
352 SerialState *s = PDMICHARPORT_2_SERIALSTATE(pInterface);
353 int rc;
354
355 Assert(*pcbRead != 0);
356 rc = RTSemEventWait(s->ReceiveSem, 250);
357 if (VBOX_FAILURE(rc))
358 return rc;
359 Assert(!(s->lsr & UART_LSR_DR));
360 s->rbr = *(const char *)pvBuf;
361 s->lsr |= UART_LSR_DR;
362 serial_update_irq(s);
363 *pcbRead = 1;
364 return VINF_SUCCESS;
365}
366
367static DECLCALLBACK(int) serial_io_write (PPDMDEVINS pDevIns,
368 void *pvUser,
369 RTIOPORT Port,
370 uint32_t u32,
371 unsigned cb)
372{
373 if (cb == 1) {
374 Log(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, u32));
375 serial_ioport_write (pvUser, Port, u32);
376 }
377 else {
378 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
379 }
380 return VINF_SUCCESS;
381}
382
383static DECLCALLBACK(int) serial_io_read (PPDMDEVINS pDevIns,
384 void *pvUser,
385 RTIOPORT Port,
386 uint32_t *pu32,
387 unsigned cb)
388{
389 if (cb == 1) {
390 Log(("%s: port %#06x\n", __FUNCTION__, Port));
391 *pu32 = serial_ioport_read (pvUser, Port);
392 Log(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, *pu32));
393 return VINF_SUCCESS;
394 }
395 else {
396 return VERR_IOM_IOPORT_UNUSED;
397 }
398}
399
400static DECLCALLBACK(int) serialSaveExec(PPDMDEVINS pDevIns,
401 PSSMHANDLE pSSMHandle)
402{
403 SerialState *s = PDMINS2DATA (pDevIns, SerialState *);
404 SSMR3PutU16(pSSMHandle, s->divider);
405 SSMR3PutU8(pSSMHandle, s->rbr);
406 SSMR3PutU8(pSSMHandle, s->ier);
407 SSMR3PutU8(pSSMHandle, s->lcr);
408 SSMR3PutU8(pSSMHandle, s->mcr);
409 SSMR3PutU8(pSSMHandle, s->lsr);
410 SSMR3PutU8(pSSMHandle, s->msr);
411 SSMR3PutU8(pSSMHandle, s->scr);
412 SSMR3PutS32(pSSMHandle, s->thr_ipending);
413 SSMR3PutS32(pSSMHandle, s->irq);
414 SSMR3PutS32(pSSMHandle, s->last_break_enable);
415 SSMR3PutU32(pSSMHandle, s->base);
416 return SSMR3PutU32(pSSMHandle, ~0); /* sanity/terminator */
417}
418
419static DECLCALLBACK(int) serialLoadExec(PPDMDEVINS pDevIns,
420 PSSMHANDLE pSSMHandle,
421 uint32_t u32Version)
422{
423 int rc;
424 uint32_t u32;
425 SerialState *s = PDMINS2DATA (pDevIns, SerialState *);
426
427 if (u32Version != SERIAL_SAVED_STATE_VERSION) {
428 AssertMsgFailed(("u32Version=%d\n", u32Version));
429 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
430 }
431
432 SSMR3GetU16(pSSMHandle, &s->divider);
433 SSMR3GetU8(pSSMHandle, &s->rbr);
434 SSMR3GetU8(pSSMHandle, &s->ier);
435 SSMR3GetU8(pSSMHandle, &s->lcr);
436 SSMR3GetU8(pSSMHandle, &s->mcr);
437 SSMR3GetU8(pSSMHandle, &s->lsr);
438 SSMR3GetU8(pSSMHandle, &s->msr);
439 SSMR3GetU8(pSSMHandle, &s->scr);
440 SSMR3GetS32(pSSMHandle, &s->thr_ipending);
441 SSMR3GetS32(pSSMHandle, &s->irq);
442 SSMR3GetS32(pSSMHandle, &s->last_break_enable);
443 SSMR3GetU32(pSSMHandle, &s->base);
444
445 rc = SSMR3GetU32(pSSMHandle, &u32);
446 if (VBOX_FAILURE(rc))
447 return rc;
448
449 if (u32 != ~0U) {
450 AssertMsgFailed(("u32=%#x expected ~0\n", u32));
451 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
452 }
453 /* Be careful with pointers in the structure; they are not preserved
454 * in the saved state. */
455
456 if (s->lsr & UART_LSR_DR)
457 {
458 int rc = RTSemEventSignal(s->ReceiveSem);
459 AssertRC(rc);
460 }
461 s->pDevInsHC = pDevIns;
462 s->pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
463 return VINF_SUCCESS;
464}
465
466#ifdef VBOX_SERIAL_PCI
467
468static DECLCALLBACK(int) serialIOPortRegionMap(PPCIDEVICE pPciDev, /* unsigned */ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
469{
470 SerialState *pData = PCIDEV_2_SERIALSTATE(pPciDev);
471 int rc = VINF_SUCCESS;
472
473 Assert(enmType == PCI_ADDRESS_SPACE_IO);
474 Assert(iRegion == 0);
475 Assert(cb == 8);
476 AssertMsg(RT_ALIGN(GCPhysAddress, 8) == GCPhysAddress, ("Expected 8 byte alignment. GCPhysAddress=%#x\n", GCPhysAddress));
477
478 pData->base = (RTIOPORT)GCPhysAddress;
479 LogRel(("Serial#%d: mapping I/O at %#06x\n", pData->pDevIns->iInstance, pData->base));
480
481 /*
482 * Register our port IO handlers.
483 */
484 rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns, (RTIOPORT)GCPhysAddress, 8, (void *)pData,
485 serial_io_write, serial_io_read, NULL, NULL, "SERIAL");
486 AssertRC(rc);
487 return rc;
488}
489
490#endif /* VBOX_SERIAL_PCI */
491
492
493/** @copyfrom PIBASE::pfnqueryInterface */
494static DECLCALLBACK(void *) serialQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
495{
496 SerialState *pData = PDMIBASE_2_SERIALSTATE(pInterface);
497 switch (enmInterface)
498 {
499 case PDMINTERFACE_BASE:
500 return &pData->IBase;
501 case PDMINTERFACE_CHAR_PORT:
502 return &pData->ICharPort;
503 default:
504 return NULL;
505 }
506}
507
508
509/**
510 * Construct a device instance for a VM.
511 *
512 * @returns VBox status.
513 * @param pDevIns The device instance data.
514 * If the registration structure is needed, pDevIns->pDevReg points to it.
515 * @param iInstance Instance number. Use this to figure out which registers and such to use.
516 * The device number is also found in pDevIns->iInstance, but since it's
517 * likely to be freqently used PDM passes it as parameter.
518 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
519 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
520 * iInstance it's expected to be used a bit in this function.
521 */
522static DECLCALLBACK(int) serialConstruct(PPDMDEVINS pDevIns,
523 int iInstance,
524 PCFGMNODE pCfgHandle)
525{
526 int rc;
527 SerialState *pData = PDMINS2DATA(pDevIns, SerialState*);
528 uint16_t io_base;
529 uint8_t irq_lvl;
530
531 Assert(iInstance < 4);
532
533 pData->pDevInsHC = pDevIns;
534 pData->pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
535
536 /*
537 * Validate configuration.
538 */
539 if (!CFGMR3AreValuesValid(pCfgHandle, "IRQ\0IOBase\0")) {
540 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
541 }
542
543 rc = CFGMR3QueryBool(pCfgHandle, "GCEnabled", &pData->fGCEnabled);
544 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
545 pData->fGCEnabled = true;
546 else if (VBOX_FAILURE(rc))
547 return PDMDEV_SET_ERROR(pDevIns, rc,
548 N_("Configuration error: Failed to get the \"GCEnabled\" value"));
549
550 rc = CFGMR3QueryBool(pCfgHandle, "R0Enabled", &pData->fR0Enabled);
551 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
552 pData->fR0Enabled = true;
553 else if (VBOX_FAILURE(rc))
554 return PDMDEV_SET_ERROR(pDevIns, rc,
555 N_("Configuration error: Failed to get the \"R0Enabled\" value"));
556
557 /* IBase */
558 pData->IBase.pfnQueryInterface = serialQueryInterface;
559
560 /* ICharPort */
561 pData->ICharPort.pfnNotifyRead = serialNotifyRead;
562
563 rc = RTSemEventCreate(&pData->ReceiveSem);
564 AssertRC(rc);
565
566/** @todo r=bird: Check for VERR_CFGM_VALUE_NOT_FOUND and provide sensible defaults.
567 * Also do AssertMsgFailed(("Configuration error:....)) in the failure cases of CFGMR3Query*()
568 * and CFGR3AreValuesValid() like we're doing in the other devices. */
569 rc = CFGMR3QueryU8 (pCfgHandle, "IRQ", &irq_lvl);
570 if (VBOX_FAILURE (rc)) {
571 return rc;
572 }
573
574 rc = CFGMR3QueryU16 (pCfgHandle, "IOBase", &io_base);
575 if (VBOX_FAILURE (rc)) {
576 return rc;
577 }
578
579 Log(("serialConstruct instance %d iobase=%04x irq=%d\n", iInstance, io_base, irq_lvl));
580
581 pData->irq = irq_lvl;
582 pData->lsr = UART_LSR_TEMT | UART_LSR_THRE;
583 pData->iir = UART_IIR_NO_INT;
584 pData->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
585#ifdef VBOX_SERIAL_PCI
586 pData->base = -1;
587 pData->dev.config[0x00] = 0xee; /* Vendor: ??? */
588 pData->dev.config[0x01] = 0x80;
589 pData->dev.config[0x02] = 0x01; /* Device: ??? */
590 pData->dev.config[0x03] = 0x01;
591 pData->dev.config[0x04] = PCI_COMMAND_IOACCESS;
592 pData->dev.config[0x09] = 0x01; /* Programming interface: 16450 */
593 pData->dev.config[0x0a] = 0x00; /* Subclass: Serial controller */
594 pData->dev.config[0x0b] = 0x07; /* Class: Communication controller */
595 pData->dev.config[0x0e] = 0x00; /* Header type: standard */
596 pData->dev.config[0x3c] = irq_lvl; /* preconfigure IRQ number (0 = autoconfig)*/
597 pData->dev.config[0x3d] = 1; /* interrupt pin 0 */
598 rc = PDMDevHlpPCIRegister(pDevIns, &pData->dev);
599 if (VBOX_FAILURE(rc))
600 return rc;
601 /*
602 * Register the PCI I/O ports.
603 */
604 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 8, PCI_ADDRESS_SPACE_IO, serialIOPortRegionMap);
605 if (VBOX_FAILURE(rc))
606 return rc;
607#else /* !VBOX_SERIAL_PCI */
608 pData->base = io_base;
609 rc = PDMDevHlpIOPortRegister(pDevIns, io_base, 8, pData,
610 serial_io_write, serial_io_read,
611 NULL, NULL, "SERIAL");
612 if (VBOX_FAILURE (rc)) {
613 return rc;
614 }
615#endif /* !VBOX_SERIAL_PCI */
616
617 /* Attach the char driver and get the interfaces. For now no run-time
618 * changes are supported. */
619 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pData->IBase, &pData->pDrvBase, "Serial Char");
620 if (VBOX_SUCCESS(rc))
621 {
622 pData->pDrvChar = (PDMICHAR *)pData->pDrvBase->pfnQueryInterface(pData->pDrvBase, PDMINTERFACE_CHAR);
623 if (!pData->pDrvChar)
624 {
625 AssertMsgFailed(("Configuration error: instance %d has no char interface!\n", iInstance));
626 return VERR_PDM_MISSING_INTERFACE;
627 }
628 /** @todo provide read notification interface!!!! */
629 }
630 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
631 {
632 pData->pDrvBase = NULL;
633 pData->pDrvChar = NULL;
634 LogRel(("Serial%d: no unit\n", iInstance));
635 }
636 else
637 {
638 AssertMsgFailed(("Serial%d: Failed to attach to char driver. rc=%Vrc\n", iInstance, rc));
639 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
640 N_("Serial device %d cannot attach to char driver\n"), iInstance);
641 }
642
643 rc = PDMDevHlpSSMRegister (
644 pDevIns, /* pDevIns */
645 pDevIns->pDevReg->szDeviceName, /* pszName */
646 iInstance, /* u32Instance */
647 SERIAL_SAVED_STATE_VERSION, /* u32Version */
648 sizeof (*pData), /* cbGuess */
649 NULL, /* pfnSavePrep */
650 serialSaveExec, /* pfnSaveExec */
651 NULL, /* pfnSaveDone */
652 NULL, /* pfnLoadPrep */
653 serialLoadExec, /* pfnLoadExec */
654 NULL /* pfnLoadDone */
655 );
656 if (VBOX_FAILURE(rc))
657 return rc;
658
659 return VINF_SUCCESS;
660}
661
662/**
663 * The device registration structure.
664 */
665const PDMDEVREG g_DeviceSerialPort =
666{
667 /* u32Version */
668 PDM_DEVREG_VERSION,
669 /* szDeviceName */
670 "serial",
671 /* szGCMod */
672 "VBoxDDGC.gc",
673 /* szR0Mod */
674 "VBoxDDR0.r0",
675 /* pszDescription */
676 "Serial Communication Port",
677 /* fFlags */
678 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GC | PDM_DEVREG_FLAGS_R0,
679 /* fClass */
680 PDM_DEVREG_CLASS_SERIAL,
681 /* cMaxInstances */
682 1,
683 /* cbInstance */
684 sizeof(SerialState),
685 /* pfnConstruct */
686 serialConstruct,
687 /* pfnDestruct */
688 NULL,
689 /* pfnRelocate */
690 NULL,
691 /* pfnIOCtl */
692 NULL,
693 /* pfnPowerOn */
694 NULL,
695 /* pfnReset */
696 NULL,
697 /* pfnSuspend */
698 NULL,
699 /* pfnResume */
700 NULL,
701 /* pfnAttach */
702 NULL,
703 /* pfnDetach */
704 NULL,
705 /* pfnQueryInterface. */
706 NULL
707};
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette