VirtualBox

source: vbox/trunk/src/VBox/Devices/Serial/DevSerial.cpp@ 2402

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

Comment cleanup.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.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#include <iprt/critsect.h>
64
65#include "Builtins.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{
122 /** Access critical section. */
123 PDMCRITSECT CritSect;
124
125 /** Pointer to the device instance. */
126 HCPTRTYPE(PPDMDEVINS) pDevInsHC;
127 /** Pointer to the device instance. */
128 GCPTRTYPE(PPDMDEVINS) pDevInsGC;
129#if HC_ARCH_BITS == 64 && GC_ARCH_BITS != 64
130 RTGCPTR Alignment0;
131#endif
132 /** The base interface. */
133 HCPTRTYPE(PDMIBASE) IBase;
134 /** The character port interface. */
135 HCPTRTYPE(PDMICHARPORT) ICharPort;
136 /** Pointer to the attached base driver. */
137 HCPTRTYPE(PPDMIBASE) pDrvBase;
138 /** Pointer to the attached character driver. */
139 HCPTRTYPE(PPDMICHAR) pDrvChar;
140
141 uint16_t divider;
142 uint16_t auAlignment[3];
143 uint8_t rbr; /* receive register */
144 uint8_t ier;
145 uint8_t iir; /* read only */
146 uint8_t lcr;
147 uint8_t mcr;
148 uint8_t lsr; /* read only */
149 uint8_t msr; /* read only */
150 uint8_t scr;
151 /* NOTE: this hidden state is necessary for tx irq generation as
152 it can be reset while reading iir */
153 int thr_ipending;
154 int irq;
155
156 bool fGCEnabled;
157 bool fR0Enabled;
158 bool afAlignment[6];
159
160 RTSEMEVENT ReceiveSem;
161 int last_break_enable;
162 uint32_t base;
163
164#ifdef VBOX_SERIAL_PCI
165 PCIDEVICE dev;
166#endif /* VBOX_SERIAL_PCI */
167};
168
169#ifndef VBOX_DEVICE_STRUCT_TESTCASE
170
171
172#ifdef VBOX_SERIAL_PCI
173#define PCIDEV_2_SERIALSTATE(pPciDev) ( (SerialState *)((uintptr_t)(pPciDev) - RT_OFFSETOF(SerialState, dev)) )
174#endif /* VBOX_SERIAL_PCI */
175#define PDMIBASE_2_SERIALSTATE(pInstance) ( (SerialState *)((uintptr_t)(pInterface) - RT_OFFSETOF(SerialState, IBase)) )
176#define PDMICHARPORT_2_SERIALSTATE(pInstance) ( (SerialState *)((uintptr_t)(pInterface) - RT_OFFSETOF(SerialState, ICharPort)) )
177
178
179__BEGIN_DECLS
180PDMBOTHCBDECL(int) serialIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
181PDMBOTHCBDECL(int) serialIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
182__END_DECLS
183
184
185static void serial_update_irq(SerialState *s)
186{
187 if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) {
188 s->iir = UART_IIR_RDI;
189 } else if (s->thr_ipending && (s->ier & UART_IER_THRI)) {
190 s->iir = UART_IIR_THRI;
191 } else {
192 s->iir = UART_IIR_NO_INT;
193 }
194 if (s->iir != UART_IIR_NO_INT) {
195 Log(("serial_update_irq %d 1\n", s->irq));
196#ifdef VBOX_SERIAL_PCI
197 PDMDevHlpPCISetIrqNoWait(CTXSUFF(s->pDevIns), 0, 1);
198#else /* !VBOX_SERIAL_PCI */
199 PDMDevHlpISASetIrqNoWait(CTXSUFF(s->pDevIns), s->irq, 1);
200#endif /* !VBOX_SERIAL_PCI */
201 } else {
202 Log(("serial_update_irq %d 0\n", s->irq));
203#ifdef VBOX_SERIAL_PCI
204 PDMDevHlpPCISetIrqNoWait(CTXSUFF(s->pDevIns), 0, 0);
205#else /* !VBOX_SERIAL_PCI */
206 PDMDevHlpISASetIrqNoWait(CTXSUFF(s->pDevIns), s->irq, 0);
207#endif /* !VBOX_SERIAL_PCI */
208 }
209}
210
211static void serial_update_parameters(SerialState *s)
212{
213 int speed, parity, data_bits, stop_bits;
214
215 if (s->lcr & 0x08) {
216 if (s->lcr & 0x10)
217 parity = 'E';
218 else
219 parity = 'O';
220 } else {
221 parity = 'N';
222 }
223 if (s->lcr & 0x04)
224 stop_bits = 2;
225 else
226 stop_bits = 1;
227 data_bits = (s->lcr & 0x03) + 5;
228 if (s->divider == 0)
229 return;
230 speed = 115200 / s->divider;
231 Log(("speed=%d parity=%c data=%d stop=%d\n", speed, parity, data_bits, stop_bits));
232}
233
234static int serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
235{
236 SerialState *s = (SerialState *)opaque;
237 unsigned char ch;
238
239 addr &= 7;
240 LogFlow(("serial: write addr=0x%02x val=0x%02x\n", addr, val));
241 switch(addr) {
242 default:
243 case 0:
244 if (s->lcr & UART_LCR_DLAB) {
245 s->divider = (s->divider & 0xff00) | val;
246 serial_update_parameters(s);
247 } else {
248#ifndef IN_RING3
249 NOREF(ch);
250 return VINF_IOM_HC_IOPORT_WRITE;
251#else
252 s->thr_ipending = 0;
253 s->lsr &= ~UART_LSR_THRE;
254 serial_update_irq(s);
255 ch = val;
256 if (RT_LIKELY(s->pDrvChar))
257 {
258 Log(("serial_io_port_write: write 0x%X\n", ch));
259 int rc = s->pDrvChar->pfnWrite(s->pDrvChar, &ch, 1);
260 AssertRC(rc);
261 }
262 s->thr_ipending = 1;
263 s->lsr |= UART_LSR_THRE;
264 s->lsr |= UART_LSR_TEMT;
265 serial_update_irq(s);
266#endif
267 }
268 break;
269 case 1:
270 if (s->lcr & UART_LCR_DLAB) {
271 s->divider = (s->divider & 0x00ff) | (val << 8);
272 serial_update_parameters(s);
273 } else {
274 s->ier = val & 0x0f;
275 if (s->lsr & UART_LSR_THRE) {
276 s->thr_ipending = 1;
277 }
278 serial_update_irq(s);
279 }
280 break;
281 case 2:
282 break;
283 case 3:
284 {
285 int break_enable;
286 s->lcr = val;
287 serial_update_parameters(s);
288 break_enable = (val >> 6) & 1;
289 if (break_enable != s->last_break_enable) {
290 s->last_break_enable = break_enable;
291 }
292 }
293 break;
294 case 4:
295 s->mcr = val & 0x1f;
296 break;
297 case 5:
298 break;
299 case 6:
300 break;
301 case 7:
302 s->scr = val;
303 break;
304 }
305 return VINF_SUCCESS;
306}
307
308static uint32_t serial_ioport_read(void *opaque, uint32_t addr, int *pRC)
309{
310 SerialState *s = (SerialState *)opaque;
311 uint32_t ret = ~0U;
312
313 *pRC = VINF_SUCCESS;
314
315 addr &= 7;
316 switch(addr) {
317 default:
318 case 0:
319 if (s->lcr & UART_LCR_DLAB) {
320 ret = s->divider & 0xff;
321 } else {
322#ifndef IN_RING3
323 *pRC = VINF_IOM_HC_IOPORT_READ;
324#else
325 Log(("serial_io_port_read: read 0x%X\n", s->rbr));
326 ret = s->rbr;
327 s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
328 serial_update_irq(s);
329 {
330 int rc = RTSemEventSignal(s->ReceiveSem);
331 AssertRC(rc);
332 }
333#endif
334 }
335 break;
336 case 1:
337 if (s->lcr & UART_LCR_DLAB) {
338 ret = (s->divider >> 8) & 0xff;
339 } else {
340 ret = s->ier;
341 }
342 break;
343 case 2:
344 ret = s->iir;
345 /* reset THR pending bit */
346 if ((ret & 0x7) == UART_IIR_THRI)
347 s->thr_ipending = 0;
348 serial_update_irq(s);
349 break;
350 case 3:
351 ret = s->lcr;
352 break;
353 case 4:
354 ret = s->mcr;
355 break;
356 case 5:
357 ret = s->lsr;
358 break;
359 case 6:
360 if (s->mcr & UART_MCR_LOOP) {
361 /* in loopback, the modem output pins are connected to the
362 inputs */
363 ret = (s->mcr & 0x0c) << 4;
364 ret |= (s->mcr & 0x02) << 3;
365 ret |= (s->mcr & 0x01) << 5;
366 } else {
367 ret = s->msr;
368 }
369 break;
370 case 7:
371 ret = s->scr;
372 break;
373 }
374 LogFlow(("serial: read addr=0x%02x val=0x%02x\n", addr, ret));
375 return ret;
376}
377
378#ifdef IN_RING3
379static DECLCALLBACK(int) serialNotifyRead(PPDMICHARPORT pInterface, const void *pvBuf, size_t *pcbRead)
380{
381 SerialState *pData = PDMICHARPORT_2_SERIALSTATE(pInterface);
382 int rc;
383
384 Assert(*pcbRead != 0);
385
386 PDMCritSectEnter(&pData->CritSect, VERR_PERMISSION_DENIED);
387 if (pData->lsr & UART_LSR_DR)
388 {
389 /* If a character is still in the read queue, then wait for it to be emptied. */
390 PDMCritSectLeave(&pData->CritSect);
391 rc = RTSemEventWait(pData->ReceiveSem, 250);
392 if (VBOX_FAILURE(rc))
393 return rc;
394
395 PDMCritSectEnter(&pData->CritSect, VERR_PERMISSION_DENIED);
396 }
397
398 if (!(pData->lsr & UART_LSR_DR))
399 {
400 pData->rbr = *(const char *)pvBuf;
401 pData->lsr |= UART_LSR_DR;
402 serial_update_irq(pData);
403 *pcbRead = 1;
404 rc = VINF_SUCCESS;
405 }
406 else
407 rc = VERR_TIMEOUT;
408
409 PDMCritSectLeave(&pData->CritSect);
410
411 return rc;
412}
413#endif /* IN_RING3 */
414
415/**
416 * Port I/O Handler for OUT operations.
417 *
418 * @returns VBox status code.
419 *
420 * @param pDevIns The device instance.
421 * @param pvUser User argument.
422 * @param Port Port number used for the IN operation.
423 * @param u32 The value to output.
424 * @param cb The value size in bytes.
425 */
426PDMBOTHCBDECL(int) serialIOPortWrite(PPDMDEVINS pDevIns, void *pvUser,
427 RTIOPORT Port, uint32_t u32, unsigned cb)
428{
429 SerialState *pData = PDMINS2DATA(pDevIns, SerialState *);
430 int rc = VINF_SUCCESS;
431
432 if (cb == 1)
433 {
434 rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_IOPORT_WRITE);
435 if (rc == VINF_SUCCESS)
436 {
437 Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, u32));
438 rc = serial_ioport_write (pData, Port, u32);
439 PDMCritSectLeave(&pData->CritSect);
440 }
441 }
442 else
443 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
444
445 return rc;
446}
447
448/**
449 * Port I/O Handler for IN operations.
450 *
451 * @returns VBox status code.
452 *
453 * @param pDevIns The device instance.
454 * @param pvUser User argument.
455 * @param Port Port number used for the IN operation.
456 * @param u32 The value to output.
457 * @param cb The value size in bytes.
458 */
459PDMBOTHCBDECL(int) serialIOPortRead(PPDMDEVINS pDevIns, void *pvUser,
460 RTIOPORT Port, uint32_t *pu32, unsigned cb)
461{
462 SerialState *pData = PDMINS2DATA(pDevIns, SerialState *);
463 int rc = VINF_SUCCESS;
464
465 if (cb == 1)
466 {
467 rc = PDMCritSectEnter(&pData->CritSect, VINF_IOM_HC_IOPORT_READ);
468 if (rc == VINF_SUCCESS)
469 {
470 *pu32 = serial_ioport_read (pData, Port, &rc);
471 Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, *pu32));
472 PDMCritSectLeave(&pData->CritSect);
473 }
474 }
475 else
476 rc = VERR_IOM_IOPORT_UNUSED;
477
478 return rc;
479}
480
481#ifdef IN_RING3
482/**
483 * Saves a state of the serial port device.
484 *
485 * @returns VBox status code.
486 * @param pDevIns The device instance.
487 * @param pSSMHandle The handle to save the state to.
488 */
489static DECLCALLBACK(int) serialSaveExec(PPDMDEVINS pDevIns,
490 PSSMHANDLE pSSMHandle)
491{
492 SerialState *pData = PDMINS2DATA(pDevIns, SerialState *);
493
494 SSMR3PutU16(pSSMHandle, pData->divider);
495 SSMR3PutU8(pSSMHandle, pData->rbr);
496 SSMR3PutU8(pSSMHandle, pData->ier);
497 SSMR3PutU8(pSSMHandle, pData->lcr);
498 SSMR3PutU8(pSSMHandle, pData->mcr);
499 SSMR3PutU8(pSSMHandle, pData->lsr);
500 SSMR3PutU8(pSSMHandle, pData->msr);
501 SSMR3PutU8(pSSMHandle, pData->scr);
502 SSMR3PutS32(pSSMHandle, pData->thr_ipending);
503 SSMR3PutS32(pSSMHandle, pData->irq);
504 SSMR3PutS32(pSSMHandle, pData->last_break_enable);
505 SSMR3PutU32(pSSMHandle, pData->base);
506 return SSMR3PutU32(pSSMHandle, ~0); /* sanity/terminator */
507}
508
509/**
510 * Loads a saved serial port device state.
511 *
512 * @returns VBox status code.
513 * @param pDevIns The device instance.
514 * @param pSSMHandle The handle to the saved state.
515 * @param u32Version The data unit version number.
516 */
517static DECLCALLBACK(int) serialLoadExec(PPDMDEVINS pDevIns,
518 PSSMHANDLE pSSMHandle,
519 uint32_t u32Version)
520{
521 int rc;
522 uint32_t u32;
523 SerialState *pData = PDMINS2DATA(pDevIns, SerialState *);
524
525 if (u32Version != SERIAL_SAVED_STATE_VERSION)
526 {
527 AssertMsgFailed(("u32Version=%d\n", u32Version));
528 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
529 }
530
531 SSMR3GetU16(pSSMHandle, &pData->divider);
532 SSMR3GetU8(pSSMHandle, &pData->rbr);
533 SSMR3GetU8(pSSMHandle, &pData->ier);
534 SSMR3GetU8(pSSMHandle, &pData->lcr);
535 SSMR3GetU8(pSSMHandle, &pData->mcr);
536 SSMR3GetU8(pSSMHandle, &pData->lsr);
537 SSMR3GetU8(pSSMHandle, &pData->msr);
538 SSMR3GetU8(pSSMHandle, &pData->scr);
539 SSMR3GetS32(pSSMHandle, &pData->thr_ipending);
540 SSMR3GetS32(pSSMHandle, &pData->irq);
541 SSMR3GetS32(pSSMHandle, &pData->last_break_enable);
542 SSMR3GetU32(pSSMHandle, &pData->base);
543
544 rc = SSMR3GetU32(pSSMHandle, &u32);
545 if (VBOX_FAILURE(rc))
546 return rc;
547
548 if (u32 != ~0U)
549 {
550 AssertMsgFailed(("u32=%#x expected ~0\n", u32));
551 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
552 }
553 /* Be careful with pointers in the structure; they are not preserved
554 * in the saved state. */
555
556 if (pData->lsr & UART_LSR_DR)
557 {
558 int rc = RTSemEventSignal(pData->ReceiveSem);
559 AssertRC(rc);
560 }
561 pData->pDevInsHC = pDevIns;
562 pData->pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
563 return VINF_SUCCESS;
564}
565
566
567/**
568 * @copydoc FNPDMDEVRELOCATE
569 */
570static DECLCALLBACK(void) serialRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
571{
572 SerialState *pData = PDMINS2DATA(pDevIns, SerialState *);
573 pData->pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
574}
575
576#ifdef VBOX_SERIAL_PCI
577
578static DECLCALLBACK(int) serialIOPortRegionMap(PPCIDEVICE pPciDev, /* unsigned */ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
579{
580 SerialState *pData = PCIDEV_2_SERIALSTATE(pPciDev);
581 int rc = VINF_SUCCESS;
582
583 Assert(enmType == PCI_ADDRESS_SPACE_IO);
584 Assert(iRegion == 0);
585 Assert(cb == 8);
586 AssertMsg(RT_ALIGN(GCPhysAddress, 8) == GCPhysAddress, ("Expected 8 byte alignment. GCPhysAddress=%#x\n", GCPhysAddress));
587
588 pData->base = (RTIOPORT)GCPhysAddress;
589 LogRel(("Serial#%d: mapping I/O at %#06x\n", pData->pDevIns->iInstance, pData->base));
590
591 /*
592 * Register our port IO handlers.
593 */
594 rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns, (RTIOPORT)GCPhysAddress, 8, (void *)pData,
595 serial_io_write, serial_io_read, NULL, NULL, "SERIAL");
596 AssertRC(rc);
597 return rc;
598}
599
600#endif /* VBOX_SERIAL_PCI */
601
602
603/** @copyfrom PIBASE::pfnqueryInterface */
604static DECLCALLBACK(void *) serialQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
605{
606 SerialState *pData = PDMIBASE_2_SERIALSTATE(pInterface);
607 switch (enmInterface)
608 {
609 case PDMINTERFACE_BASE:
610 return &pData->IBase;
611 case PDMINTERFACE_CHAR_PORT:
612 return &pData->ICharPort;
613 default:
614 return NULL;
615 }
616}
617
618/**
619 * Destruct a device instance.
620 *
621 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
622 * resources can be freed correctly.
623 *
624 * @returns VBox status.
625 * @param pDevIns The device instance data.
626 */
627static DECLCALLBACK(int) serialDestruct(PPDMDEVINS pDevIns)
628{
629 SerialState *pData = PDMINS2DATA(pDevIns, SerialState *);
630
631 RTSemEventDestroy(pData->ReceiveSem);
632 pData->ReceiveSem = NIL_RTSEMEVENT;
633
634 PDMR3CritSectDelete(&pData->CritSect);
635 return VINF_SUCCESS;
636}
637
638
639/**
640 * Construct a device instance for a VM.
641 *
642 * @returns VBox status.
643 * @param pDevIns The device instance data.
644 * If the registration structure is needed, pDevIns->pDevReg points to it.
645 * @param iInstance Instance number. Use this to figure out which registers and such to use.
646 * The device number is also found in pDevIns->iInstance, but since it's
647 * likely to be freqently used PDM passes it as parameter.
648 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
649 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
650 * iInstance it's expected to be used a bit in this function.
651 */
652static DECLCALLBACK(int) serialConstruct(PPDMDEVINS pDevIns,
653 int iInstance,
654 PCFGMNODE pCfgHandle)
655{
656 int rc;
657 SerialState *pData = PDMINS2DATA(pDevIns, SerialState*);
658 uint16_t io_base;
659 uint8_t irq_lvl;
660
661 Assert(iInstance < 4);
662
663 pData->pDevInsHC = pDevIns;
664 pData->pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
665
666 /*
667 * Validate configuration.
668 */
669 if (!CFGMR3AreValuesValid(pCfgHandle, "IRQ\0IOBase\0"))
670 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
671
672 rc = CFGMR3QueryBool(pCfgHandle, "GCEnabled", &pData->fGCEnabled);
673 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
674 pData->fGCEnabled = true;
675 else if (VBOX_FAILURE(rc))
676 return PDMDEV_SET_ERROR(pDevIns, rc,
677 N_("Configuration error: Failed to get the \"GCEnabled\" value"));
678
679 rc = CFGMR3QueryBool(pCfgHandle, "R0Enabled", &pData->fR0Enabled);
680 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
681 pData->fR0Enabled = true;
682 else if (VBOX_FAILURE(rc))
683 return PDMDEV_SET_ERROR(pDevIns, rc,
684 N_("Configuration error: Failed to get the \"R0Enabled\" value"));
685
686 /* IBase */
687 pData->IBase.pfnQueryInterface = serialQueryInterface;
688
689 /* ICharPort */
690 pData->ICharPort.pfnNotifyRead = serialNotifyRead;
691
692 rc = RTSemEventCreate(&pData->ReceiveSem);
693 AssertRC(rc);
694
695 /*
696 * Initialize critical section.
697 * This must of course be done before attaching drivers or anything else which can call us back..
698 */
699 char szName[24];
700 RTStrPrintf(szName, sizeof(szName), "Serial#%d", iInstance);
701 rc = PDMDevHlpCritSectInit(pDevIns, &pData->CritSect, szName);
702 if (VBOX_FAILURE(rc))
703 return rc;
704
705/** @todo r=bird: Check for VERR_CFGM_VALUE_NOT_FOUND and provide sensible defaults.
706 * Also do AssertMsgFailed(("Configuration error:....)) in the failure cases of CFGMR3Query*()
707 * and CFGR3AreValuesValid() like we're doing in the other devices. */
708 rc = CFGMR3QueryU8 (pCfgHandle, "IRQ", &irq_lvl);
709 if (VBOX_FAILURE (rc))
710 return rc;
711
712 rc = CFGMR3QueryU16 (pCfgHandle, "IOBase", &io_base);
713 if (VBOX_FAILURE (rc))
714 return rc;
715
716 Log(("serialConstruct instance %d iobase=%04x irq=%d\n", iInstance, io_base, irq_lvl));
717
718 pData->irq = irq_lvl;
719 pData->lsr = UART_LSR_TEMT | UART_LSR_THRE;
720 pData->iir = UART_IIR_NO_INT;
721 pData->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
722#ifdef VBOX_SERIAL_PCI
723 pData->base = -1;
724 pData->dev.config[0x00] = 0xee; /* Vendor: ??? */
725 pData->dev.config[0x01] = 0x80;
726 pData->dev.config[0x02] = 0x01; /* Device: ??? */
727 pData->dev.config[0x03] = 0x01;
728 pData->dev.config[0x04] = PCI_COMMAND_IOACCESS;
729 pData->dev.config[0x09] = 0x01; /* Programming interface: 16450 */
730 pData->dev.config[0x0a] = 0x00; /* Subclass: Serial controller */
731 pData->dev.config[0x0b] = 0x07; /* Class: Communication controller */
732 pData->dev.config[0x0e] = 0x00; /* Header type: standard */
733 pData->dev.config[0x3c] = irq_lvl; /* preconfigure IRQ number (0 = autoconfig)*/
734 pData->dev.config[0x3d] = 1; /* interrupt pin 0 */
735 rc = PDMDevHlpPCIRegister(pDevIns, &pData->dev);
736 if (VBOX_FAILURE(rc))
737 return rc;
738 /*
739 * Register the PCI I/O ports.
740 */
741 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 8, PCI_ADDRESS_SPACE_IO, serialIOPortRegionMap);
742 if (VBOX_FAILURE(rc))
743 return rc;
744#else /* !VBOX_SERIAL_PCI */
745 pData->base = io_base;
746 rc = PDMDevHlpIOPortRegister(pDevIns, io_base, 8, 0,
747 serialIOPortWrite, serialIOPortRead,
748 NULL, NULL, "SERIAL");
749 if (VBOX_FAILURE (rc))
750 return rc;
751
752 if (pData->fGCEnabled)
753 rc = PDMDevHlpIOPortRegisterGC(pDevIns, io_base, 8, 0, "serialIOPortWrite",
754 "serialIOPortRead", NULL, NULL, "Serial");
755
756 if (pData->fR0Enabled)
757 rc = PDMDevHlpIOPortRegisterR0(pDevIns, io_base, 8, 0, "serialIOPortWrite",
758 "serialIOPortRead", NULL, NULL, "Serial");
759
760#endif /* !VBOX_SERIAL_PCI */
761
762 /* Attach the char driver and get the interfaces. For now no run-time
763 * changes are supported. */
764 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pData->IBase, &pData->pDrvBase, "Serial Char");
765 if (VBOX_SUCCESS(rc))
766 {
767 pData->pDrvChar = (PDMICHAR *)pData->pDrvBase->pfnQueryInterface(pData->pDrvBase, PDMINTERFACE_CHAR);
768 if (!pData->pDrvChar)
769 {
770 AssertMsgFailed(("Configuration error: instance %d has no char interface!\n", iInstance));
771 return VERR_PDM_MISSING_INTERFACE;
772 }
773 /** @todo provide read notification interface!!!! */
774 }
775 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
776 {
777 pData->pDrvBase = NULL;
778 pData->pDrvChar = NULL;
779 LogRel(("Serial%d: no unit\n", iInstance));
780 }
781 else
782 {
783 AssertMsgFailed(("Serial%d: Failed to attach to char driver. rc=%Vrc\n", iInstance, rc));
784 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
785 N_("Serial device %d cannot attach to char driver\n"), iInstance);
786 }
787
788 rc = PDMDevHlpSSMRegister (
789 pDevIns, /* pDevIns */
790 pDevIns->pDevReg->szDeviceName, /* pszName */
791 iInstance, /* u32Instance */
792 SERIAL_SAVED_STATE_VERSION, /* u32Version */
793 sizeof (*pData), /* cbGuess */
794 NULL, /* pfnSavePrep */
795 serialSaveExec, /* pfnSaveExec */
796 NULL, /* pfnSaveDone */
797 NULL, /* pfnLoadPrep */
798 serialLoadExec, /* pfnLoadExec */
799 NULL /* pfnLoadDone */
800 );
801 if (VBOX_FAILURE(rc))
802 return rc;
803
804 return VINF_SUCCESS;
805}
806
807/**
808 * The device registration structure.
809 */
810const PDMDEVREG g_DeviceSerialPort =
811{
812 /* u32Version */
813 PDM_DEVREG_VERSION,
814 /* szDeviceName */
815 "serial",
816 /* szGCMod */
817 "VBoxDDGC.gc",
818 /* szR0Mod */
819 "VBoxDDR0.r0",
820 /* pszDescription */
821 "Serial Communication Port",
822 /* fFlags */
823 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GC | PDM_DEVREG_FLAGS_R0,
824 /* fClass */
825 PDM_DEVREG_CLASS_SERIAL,
826 /* cMaxInstances */
827 1,
828 /* cbInstance */
829 sizeof(SerialState),
830 /* pfnConstruct */
831 serialConstruct,
832 /* pfnDestruct */
833 serialDestruct,
834 /* pfnRelocate */
835 serialRelocate,
836 /* pfnIOCtl */
837 NULL,
838 /* pfnPowerOn */
839 NULL,
840 /* pfnReset */
841 NULL,
842 /* pfnSuspend */
843 NULL,
844 /* pfnResume */
845 NULL,
846 /* pfnAttach */
847 NULL,
848 /* pfnDetach */
849 NULL,
850 /* pfnQueryInterface. */
851 NULL
852};
853#endif /* IN_RING3 */
854
855
856#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