VirtualBox

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

最後變更 在這個檔案從28399是 28399,由 vboxsync 提交於 15 年 前

DevSerial: disabled r59817 as it causes regressions

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 33.7 KB
 
1/* $Id: DevSerial.cpp 28399 2010-04-16 08:50:37Z vboxsync $ */
2/** @file
3 * DevSerial - 16450 UART emulation.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/*
23 * This code is based on:
24 *
25 * QEMU 16450 UART emulation
26 *
27 * Copyright (c) 2003-2004 Fabrice Bellard
28 *
29 * Permission is hereby granted, free of charge, to any person obtaining a copy
30 * of this software and associated documentation files (the "Software"), to deal
31 * in the Software without restriction, including without limitation the rights
32 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
33 * copies of the Software, and to permit persons to whom the Software is
34 * furnished to do so, subject to the following conditions:
35 *
36 * The above copyright notice and this permission notice shall be included in
37 * all copies or substantial portions of the Software.
38 *
39 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
42 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
45 * THE SOFTWARE.
46 *
47 */
48
49/*******************************************************************************
50* Header Files *
51*******************************************************************************/
52#define LOG_GROUP LOG_GROUP_DEV_SERIAL
53#include <VBox/pdmdev.h>
54#include <iprt/assert.h>
55#include <iprt/uuid.h>
56#include <iprt/string.h>
57#include <iprt/semaphore.h>
58#include <iprt/critsect.h>
59
60#include "../Builtins.h"
61
62#undef VBOX_SERIAL_PCI /* The PCI variant has lots of problems: wrong IRQ line and wrong IO base assigned. */
63
64#ifdef VBOX_SERIAL_PCI
65# include <VBox/pci.h>
66#endif /* VBOX_SERIAL_PCI */
67
68
69/*******************************************************************************
70* Defined Constants And Macros *
71*******************************************************************************/
72#define SERIAL_SAVED_STATE_VERSION 3
73
74#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
75
76#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */
77#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */
78#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */
79#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */
80
81#define UART_IIR_NO_INT 0x01 /* No interrupts pending */
82#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */
83
84#define UART_IIR_MSI 0x00 /* Modem status interrupt */
85#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */
86#define UART_IIR_RDI 0x04 /* Receiver data interrupt */
87#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */
88
89/*
90 * These are the definitions for the Modem Control Register
91 */
92#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
93#define UART_MCR_OUT2 0x08 /* Out2 complement */
94#define UART_MCR_OUT1 0x04 /* Out1 complement */
95#define UART_MCR_RTS 0x02 /* RTS complement */
96#define UART_MCR_DTR 0x01 /* DTR complement */
97
98/*
99 * These are the definitions for the Modem Status Register
100 */
101#define UART_MSR_DCD 0x80 /* Data Carrier Detect */
102#define UART_MSR_RI 0x40 /* Ring Indicator */
103#define UART_MSR_DSR 0x20 /* Data Set Ready */
104#define UART_MSR_CTS 0x10 /* Clear to Send */
105#define UART_MSR_DDCD 0x08 /* Delta DCD */
106#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */
107#define UART_MSR_DDSR 0x02 /* Delta DSR */
108#define UART_MSR_DCTS 0x01 /* Delta CTS */
109#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */
110
111#define UART_LSR_TEMT 0x40 /* Transmitter empty */
112#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
113#define UART_LSR_BI 0x10 /* Break interrupt indicator */
114#define UART_LSR_FE 0x08 /* Frame error indicator */
115#define UART_LSR_PE 0x04 /* Parity error indicator */
116#define UART_LSR_OE 0x02 /* Overrun error indicator */
117#define UART_LSR_DR 0x01 /* Receiver data ready */
118
119
120/*******************************************************************************
121* Structures and Typedefs *
122*******************************************************************************/
123/**
124 * Serial device.
125 *
126 * @implements PDMIBASE
127 * @implements PDMICHARPORT
128 */
129struct SerialState
130{
131 /** Access critical section. */
132 PDMCRITSECT CritSect;
133
134 /** Pointer to the device instance - R3 Ptr. */
135 PPDMDEVINSR3 pDevInsR3;
136 /** Pointer to the device instance - R0 Ptr. */
137 PPDMDEVINSR0 pDevInsR0;
138 /** Pointer to the device instance - RC Ptr. */
139 PPDMDEVINSRC pDevInsRC;
140 RTRCPTR Alignment0; /**< Alignment. */
141 /** LUN\#0: The base interface. */
142 PDMIBASE IBase;
143 /** LUN\#0: The character port interface. */
144 PDMICHARPORT ICharPort;
145 /** Pointer to the attached base driver. */
146 R3PTRTYPE(PPDMIBASE) pDrvBase;
147 /** Pointer to the attached character driver. */
148 R3PTRTYPE(PPDMICHARCONNECTOR) pDrvChar;
149
150 uint16_t divider;
151 uint16_t auAlignment[3];
152 uint8_t rbr; /* receive register */
153 uint8_t ier;
154 uint8_t iir; /* read only */
155 uint8_t lcr;
156 uint8_t mcr;
157 uint8_t lsr; /* read only */
158 uint8_t msr; /* read only */
159 uint8_t scr;
160 /* NOTE: this hidden state is necessary for tx irq generation as
161 it can be reset while reading iir */
162 int thr_ipending;
163 int irq;
164 bool msr_changed;
165
166 bool fGCEnabled;
167 bool fR0Enabled;
168 bool fYieldOnLSRRead;
169 bool afAlignment[4];
170
171 RTSEMEVENT ReceiveSem;
172 int last_break_enable;
173 uint32_t base;
174
175#ifdef VBOX_SERIAL_PCI
176 PCIDEVICE dev;
177#endif /* VBOX_SERIAL_PCI */
178};
179
180#ifndef VBOX_DEVICE_STRUCT_TESTCASE
181
182
183#ifdef VBOX_SERIAL_PCI
184#define PCIDEV_2_SERIALSTATE(pPciDev) ( (SerialState *)((uintptr_t)(pPciDev) - RT_OFFSETOF(SerialState, dev)) )
185#endif /* VBOX_SERIAL_PCI */
186#define PDMIBASE_2_SERIALSTATE(pInstance) ( (SerialState *)((uintptr_t)(pInterface) - RT_OFFSETOF(SerialState, IBase)) )
187#define PDMICHARPORT_2_SERIALSTATE(pInstance) ( (SerialState *)((uintptr_t)(pInterface) - RT_OFFSETOF(SerialState, ICharPort)) )
188
189
190/*******************************************************************************
191* Internal Functions *
192*******************************************************************************/
193RT_C_DECLS_BEGIN
194PDMBOTHCBDECL(int) serialIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
195PDMBOTHCBDECL(int) serialIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
196RT_C_DECLS_END
197
198#ifdef IN_RING3
199
200static void serial_update_irq(SerialState *s)
201{
202 if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) {
203 s->iir = UART_IIR_RDI;
204 } else if (s->thr_ipending && (s->ier & UART_IER_THRI)) {
205 s->iir = UART_IIR_THRI;
206 } else if (s->msr_changed && (s->ier & UART_IER_RLSI)) {
207 s->iir = UART_IIR_RLSI;
208 } else if (s->lsr & UART_LSR_BI) {
209 s->iir = 0; /* No special status bit */
210 } else {
211 s->iir = UART_IIR_NO_INT;
212 }
213 if (s->iir != UART_IIR_NO_INT) {
214 Log(("serial_update_irq %d 1\n", s->irq));
215# ifdef VBOX_SERIAL_PCI
216 PDMDevHlpPCISetIrqNoWait(s->CTX_SUFF(pDevIns), 0, 1);
217# else /* !VBOX_SERIAL_PCI */
218 PDMDevHlpISASetIrqNoWait(s->CTX_SUFF(pDevIns), s->irq, 1);
219# endif /* !VBOX_SERIAL_PCI */
220 } else {
221 Log(("serial_update_irq %d 0\n", s->irq));
222# ifdef VBOX_SERIAL_PCI
223 PDMDevHlpPCISetIrqNoWait(s->CTX_SUFF(pDevIns), 0, 0);
224# else /* !VBOX_SERIAL_PCI */
225 PDMDevHlpISASetIrqNoWait(s->CTX_SUFF(pDevIns), s->irq, 0);
226# endif /* !VBOX_SERIAL_PCI */
227 }
228}
229
230static void serial_update_parameters(SerialState *s)
231{
232 int speed, parity, data_bits, stop_bits;
233
234 if (s->lcr & 0x08) {
235 if (s->lcr & 0x10)
236 parity = 'E';
237 else
238 parity = 'O';
239 } else {
240 parity = 'N';
241 }
242 if (s->lcr & 0x04)
243 stop_bits = 2;
244 else
245 stop_bits = 1;
246 data_bits = (s->lcr & 0x03) + 5;
247 if (s->divider == 0)
248 return;
249 speed = 115200 / s->divider;
250 Log(("speed=%d parity=%c data=%d stop=%d\n", speed, parity, data_bits, stop_bits));
251 if (RT_LIKELY(s->pDrvChar))
252 s->pDrvChar->pfnSetParameters(s->pDrvChar, speed, parity, data_bits, stop_bits);
253}
254
255#endif /* IN_RING3 */
256
257static int serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
258{
259 SerialState *s = (SerialState *)opaque;
260 unsigned char ch;
261
262 addr &= 7;
263 LogFlow(("serial: write addr=0x%02x val=0x%02x\n", addr, val));
264
265#ifndef IN_RING3
266 NOREF(ch);
267 NOREF(s);
268 return VINF_IOM_HC_IOPORT_WRITE;
269#else
270 switch(addr) {
271 default:
272 case 0:
273 if (s->lcr & UART_LCR_DLAB) {
274 s->divider = (s->divider & 0xff00) | val;
275 serial_update_parameters(s);
276#if 0 /* disabled because this causes regressions */
277 } else if (s->lsr & UART_LSR_THRE) {
278 s->thr_ipending = 0;
279 ch = val;
280 if (RT_LIKELY(s->pDrvChar))
281 {
282 Log(("serial_ioport_write: write 0x%X\n", ch));
283 int rc = s->pDrvChar->pfnWrite(s->pDrvChar, &ch, 1);
284 AssertRC(rc);
285 }
286 s->thr_ipending = 1;
287 serial_update_irq(s);
288 } else
289 Log(("serial: THR not EMPTY!\n"));
290#else
291 } else {
292 s->thr_ipending = 0;
293 s->lsr &= ~UART_LSR_THRE;
294 serial_update_irq(s);
295 ch = val;
296 if (RT_LIKELY(s->pDrvChar))
297 {
298 Log(("serial_ioport_write: write 0x%X\n", ch));
299 int rc = s->pDrvChar->pfnWrite(s->pDrvChar, &ch, 1);
300 AssertRC(rc);
301 }
302 s->thr_ipending = 1;
303 s->lsr |= UART_LSR_THRE;
304 s->lsr |= UART_LSR_TEMT;
305 serial_update_irq(s);
306 }
307#endif
308 break;
309 case 1:
310 if (s->lcr & UART_LCR_DLAB) {
311 s->divider = (s->divider & 0x00ff) | (val << 8);
312 serial_update_parameters(s);
313 } else {
314 s->ier = val & 0x0f;
315 if (s->lsr & UART_LSR_THRE) {
316 s->thr_ipending = 1;
317 }
318 serial_update_irq(s);
319 }
320 break;
321 case 2:
322 break;
323 case 3:
324 {
325 int break_enable;
326 if (s->lcr != val)
327 {
328 s->lcr = val;
329 serial_update_parameters(s);
330 }
331 break_enable = (val >> 6) & 1;
332 if (break_enable != s->last_break_enable) {
333 s->last_break_enable = break_enable;
334 if (RT_LIKELY(s->pDrvChar))
335 {
336 Log(("serial_ioport_write: Set break %d\n", break_enable));
337 int rc = s->pDrvChar->pfnSetBreak(s->pDrvChar, !!break_enable);
338 AssertRC(rc);
339 }
340 }
341 }
342 break;
343 case 4:
344 s->mcr = val & 0x1f;
345 if (RT_LIKELY(s->pDrvChar))
346 {
347 int rc = s->pDrvChar->pfnSetModemLines(s->pDrvChar, !!(s->mcr & UART_MCR_RTS), !!(s->mcr & UART_MCR_DTR));
348 AssertRC(rc);
349 }
350 break;
351 case 5:
352 break;
353 case 6:
354 break;
355 case 7:
356 s->scr = val;
357 break;
358 }
359 return VINF_SUCCESS;
360#endif
361}
362
363static uint32_t serial_ioport_read(void *opaque, uint32_t addr, int *pRC)
364{
365 SerialState *s = (SerialState *)opaque;
366 uint32_t ret = ~0U;
367
368 *pRC = VINF_SUCCESS;
369
370 addr &= 7;
371 switch(addr) {
372 default:
373 case 0:
374 if (s->lcr & UART_LCR_DLAB) {
375 ret = s->divider & 0xff;
376 } else {
377#ifndef IN_RING3
378 *pRC = VINF_IOM_HC_IOPORT_READ;
379#else
380 Log(("serial_io_port_read: read 0x%X\n", s->rbr));
381 ret = s->rbr;
382 s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
383 serial_update_irq(s);
384 {
385 int rc = RTSemEventSignal(s->ReceiveSem);
386 AssertRC(rc);
387 }
388#endif
389 }
390 break;
391 case 1:
392 if (s->lcr & UART_LCR_DLAB) {
393 ret = (s->divider >> 8) & 0xff;
394 } else {
395 ret = s->ier;
396 }
397 break;
398 case 2:
399#ifndef IN_RING3
400 *pRC = VINF_IOM_HC_IOPORT_READ;
401#else
402 ret = s->iir;
403 /* reset THR pending bit */
404 if ((ret & 0x7) == UART_IIR_THRI)
405 s->thr_ipending = 0;
406 /* reset msr changed bit */
407 s->msr_changed = false;
408 serial_update_irq(s);
409#endif
410 break;
411 case 3:
412 ret = s->lcr;
413 break;
414 case 4:
415 ret = s->mcr;
416 break;
417 case 5:
418 if ((s->lsr & UART_LSR_DR) == 0 && s->fYieldOnLSRRead)
419 {
420 /* No data available and yielding is enabled, so yield in ring3. */
421#ifndef IN_RING3
422 *pRC = VINF_IOM_HC_IOPORT_READ;
423 break;
424#else
425 RTThreadYield ();
426#endif
427 }
428 ret = s->lsr;
429 break;
430 case 6:
431 if (s->mcr & UART_MCR_LOOP) {
432 /* in loopback, the modem output pins are connected to the
433 inputs */
434 ret = (s->mcr & 0x0c) << 4;
435 ret |= (s->mcr & 0x02) << 3;
436 ret |= (s->mcr & 0x01) << 5;
437 } else {
438 ret = s->msr;
439 /* Reset delta bits. */
440 s->msr &= ~UART_MSR_ANY_DELTA;
441 }
442 break;
443 case 7:
444 ret = s->scr;
445 break;
446 }
447 LogFlow(("serial: read addr=0x%02x val=0x%02x\n", addr, ret));
448 return ret;
449}
450
451#ifdef IN_RING3
452
453static DECLCALLBACK(int) serialNotifyRead(PPDMICHARPORT pInterface, const void *pvBuf, size_t *pcbRead)
454{
455 SerialState *pThis = PDMICHARPORT_2_SERIALSTATE(pInterface);
456 int rc;
457
458 Assert(*pcbRead != 0);
459
460 PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);
461 if (pThis->lsr & UART_LSR_DR)
462 {
463 /* If a character is still in the read queue, then wait for it to be emptied. */
464 PDMCritSectLeave(&pThis->CritSect);
465 rc = RTSemEventWait(pThis->ReceiveSem, 250);
466 if (RT_FAILURE(rc))
467 return rc;
468
469 PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);
470 }
471
472 if (!(pThis->lsr & UART_LSR_DR))
473 {
474 pThis->rbr = *(const char *)pvBuf;
475 pThis->lsr |= UART_LSR_DR;
476 serial_update_irq(pThis);
477 *pcbRead = 1;
478 rc = VINF_SUCCESS;
479 }
480 else
481 rc = VERR_TIMEOUT;
482
483 PDMCritSectLeave(&pThis->CritSect);
484
485 return rc;
486}
487
488static DECLCALLBACK(int) serialNotifyStatusLinesChanged(PPDMICHARPORT pInterface, uint32_t newStatusLines)
489{
490 SerialState *pThis = PDMICHARPORT_2_SERIALSTATE(pInterface);
491 uint8_t newMsr = 0;
492
493 Log(("%s: pInterface=%p newStatusLines=%u\n", __FUNCTION__, pInterface, newStatusLines));
494
495 PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);
496
497 /* Set new states. */
498 if (newStatusLines & PDMICHARPORT_STATUS_LINES_DCD)
499 newMsr |= UART_MSR_DCD;
500 if (newStatusLines & PDMICHARPORT_STATUS_LINES_RI)
501 newMsr |= UART_MSR_RI;
502 if (newStatusLines & PDMICHARPORT_STATUS_LINES_DSR)
503 newMsr |= UART_MSR_DSR;
504 if (newStatusLines & PDMICHARPORT_STATUS_LINES_CTS)
505 newMsr |= UART_MSR_CTS;
506
507 /* Compare the old and the new states and set the delta bits accordingly. */
508 if ((newMsr & UART_MSR_DCD) != (pThis->msr & UART_MSR_DCD))
509 newMsr |= UART_MSR_DDCD;
510 if ((newMsr & UART_MSR_RI) == 1 && (pThis->msr & UART_MSR_RI) == 0)
511 newMsr |= UART_MSR_TERI;
512 if ((newMsr & UART_MSR_DSR) != (pThis->msr & UART_MSR_DSR))
513 newMsr |= UART_MSR_DDSR;
514 if ((newMsr & UART_MSR_CTS) != (pThis->msr & UART_MSR_CTS))
515 newMsr |= UART_MSR_DCTS;
516
517 pThis->msr = newMsr;
518 pThis->msr_changed = true;
519 serial_update_irq(pThis);
520
521 PDMCritSectLeave(&pThis->CritSect);
522
523 return VINF_SUCCESS;
524}
525
526static DECLCALLBACK(int) serialNotifyBufferFull(PPDMICHARPORT pInterface, bool fFull)
527{
528 SerialState *pThis = PDMICHARPORT_2_SERIALSTATE(pInterface);
529 PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);
530 if (fFull)
531 {
532 pThis->lsr &= ~UART_LSR_THRE;
533 }
534 else
535 {
536 pThis->thr_ipending = 1;
537 pThis->lsr |= UART_LSR_THRE;
538 pThis->lsr |= UART_LSR_TEMT;
539 }
540 serial_update_irq(pThis);
541 PDMCritSectLeave(&pThis->CritSect);
542 return VINF_SUCCESS;
543}
544
545static DECLCALLBACK(int) serialNotifyBreak(PPDMICHARPORT pInterface)
546{
547 SerialState *pThis = PDMICHARPORT_2_SERIALSTATE(pInterface);
548
549 Log(("%s: pInterface=%p\n", __FUNCTION__, pInterface));
550
551 PDMCritSectEnter(&pThis->CritSect, VERR_PERMISSION_DENIED);
552
553 pThis->lsr |= UART_LSR_BI;
554 serial_update_irq(pThis);
555
556 PDMCritSectLeave(&pThis->CritSect);
557
558 return VINF_SUCCESS;
559}
560
561#endif /* IN_RING3 */
562
563/**
564 * Port I/O Handler for OUT operations.
565 *
566 * @returns VBox status code.
567 *
568 * @param pDevIns The device instance.
569 * @param pvUser User argument.
570 * @param Port Port number used for the IN operation.
571 * @param u32 The value to output.
572 * @param cb The value size in bytes.
573 */
574PDMBOTHCBDECL(int) serialIOPortWrite(PPDMDEVINS pDevIns, void *pvUser,
575 RTIOPORT Port, uint32_t u32, unsigned cb)
576{
577 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
578 int rc = VINF_SUCCESS;
579
580 if (cb == 1)
581 {
582 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_WRITE);
583 if (rc == VINF_SUCCESS)
584 {
585 Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, u32));
586 rc = serial_ioport_write(pThis, Port, u32);
587 PDMCritSectLeave(&pThis->CritSect);
588 }
589 }
590 else
591 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
592
593 return rc;
594}
595
596/**
597 * Port I/O Handler for IN operations.
598 *
599 * @returns VBox status code.
600 *
601 * @param pDevIns The device instance.
602 * @param pvUser User argument.
603 * @param Port Port number used for the IN operation.
604 * @param u32 The value to output.
605 * @param cb The value size in bytes.
606 */
607PDMBOTHCBDECL(int) serialIOPortRead(PPDMDEVINS pDevIns, void *pvUser,
608 RTIOPORT Port, uint32_t *pu32, unsigned cb)
609{
610 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
611 int rc = VINF_SUCCESS;
612
613 if (cb == 1)
614 {
615 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_READ);
616 if (rc == VINF_SUCCESS)
617 {
618 *pu32 = serial_ioport_read(pThis, Port, &rc);
619 Log2(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, *pu32));
620 PDMCritSectLeave(&pThis->CritSect);
621 }
622 }
623 else
624 rc = VERR_IOM_IOPORT_UNUSED;
625
626 return rc;
627}
628
629#ifdef IN_RING3
630
631/**
632 * @copydoc FNSSMDEVLIVEEXEC
633 */
634static DECLCALLBACK(int) serialLiveExec(PPDMDEVINS pDevIns,
635 PSSMHANDLE pSSM,
636 uint32_t uPass)
637{
638 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
639 SSMR3PutS32(pSSM, pThis->irq);
640 SSMR3PutU32(pSSM, pThis->base);
641 return VINF_SSM_DONT_CALL_AGAIN;
642}
643
644/**
645 * @copydoc FNSSMDEVSAVEEXEC
646 */
647static DECLCALLBACK(int) serialSaveExec(PPDMDEVINS pDevIns,
648 PSSMHANDLE pSSM)
649{
650 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
651
652 SSMR3PutU16(pSSM, pThis->divider);
653 SSMR3PutU8(pSSM, pThis->rbr);
654 SSMR3PutU8(pSSM, pThis->ier);
655 SSMR3PutU8(pSSM, pThis->lcr);
656 SSMR3PutU8(pSSM, pThis->mcr);
657 SSMR3PutU8(pSSM, pThis->lsr);
658 SSMR3PutU8(pSSM, pThis->msr);
659 SSMR3PutU8(pSSM, pThis->scr);
660 SSMR3PutS32(pSSM, pThis->thr_ipending);
661 SSMR3PutS32(pSSM, pThis->irq);
662 SSMR3PutS32(pSSM, pThis->last_break_enable);
663 SSMR3PutU32(pSSM, pThis->base);
664 SSMR3PutBool(pSSM, pThis->msr_changed);
665 return SSMR3PutU32(pSSM, ~0); /* sanity/terminator */
666}
667
668/**
669 * @copydoc FNSSMDEVLOADEXEC
670 */
671static DECLCALLBACK(int) serialLoadExec(PPDMDEVINS pDevIns,
672 PSSMHANDLE pSSM,
673 uint32_t uVersion,
674 uint32_t uPass)
675{
676 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
677
678 AssertMsgReturn(uVersion == SERIAL_SAVED_STATE_VERSION, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
679
680 if (uPass == SSM_PASS_FINAL)
681 {
682 SSMR3GetU16(pSSM, &pThis->divider);
683 SSMR3GetU8(pSSM, &pThis->rbr);
684 SSMR3GetU8(pSSM, &pThis->ier);
685 SSMR3GetU8(pSSM, &pThis->lcr);
686 SSMR3GetU8(pSSM, &pThis->mcr);
687 SSMR3GetU8(pSSM, &pThis->lsr);
688 SSMR3GetU8(pSSM, &pThis->msr);
689 SSMR3GetU8(pSSM, &pThis->scr);
690 SSMR3GetS32(pSSM, &pThis->thr_ipending);
691 }
692
693 int32_t iIrq;
694 SSMR3GetS32(pSSM, &iIrq);
695
696 if (uPass == SSM_PASS_FINAL)
697 SSMR3GetS32(pSSM, &pThis->last_break_enable);
698
699 uint32_t IOBase;
700 int rc = SSMR3GetU32(pSSM, &IOBase);
701 AssertRCReturn(rc, rc);
702
703 if ( pThis->irq != iIrq
704 || pThis->base != IOBase)
705 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - saved irq=%#x iobase=%#x; configured irq=%#x iobase=%#x"),
706 iIrq, IOBase, pThis->irq, pThis->base);
707
708 if (uPass == SSM_PASS_FINAL)
709 {
710 SSMR3GetBool(pSSM, &pThis->msr_changed);
711
712 uint32_t u32;
713 rc = SSMR3GetU32(pSSM, &u32);
714 if (RT_FAILURE(rc))
715 return rc;
716 AssertMsgReturn(u32 == ~0U, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
717
718 if (pThis->lsr & UART_LSR_DR)
719 {
720 rc = RTSemEventSignal(pThis->ReceiveSem);
721 AssertRC(rc);
722 }
723
724 /* this isn't strictly necessary but cannot hurt... */
725 pThis->pDevInsR3 = pDevIns;
726 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
727 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
728 }
729
730 return VINF_SUCCESS;
731}
732
733
734/**
735 * @copydoc FNPDMDEVRELOCATE
736 */
737static DECLCALLBACK(void) serialRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
738{
739 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
740 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
741}
742
743#ifdef VBOX_SERIAL_PCI
744
745static DECLCALLBACK(int) serialIOPortRegionMap(PPCIDEVICE pPciDev, /* unsigned */ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
746{
747 SerialState *pThis = PCIDEV_2_SERIALSTATE(pPciDev);
748 int rc = VINF_SUCCESS;
749
750 Assert(enmType == PCI_ADDRESS_SPACE_IO);
751 Assert(iRegion == 0);
752 Assert(cb == 8);
753 AssertMsg(RT_ALIGN(GCPhysAddress, 8) == GCPhysAddress, ("Expected 8 byte alignment. GCPhysAddress=%#x\n", GCPhysAddress));
754
755 pThis->base = (RTIOPORT)GCPhysAddress;
756 LogRel(("Serial#%d: mapping I/O at %#06x\n", pThis->pDevIns->iInstance, pThis->base));
757
758 /*
759 * Register our port IO handlers.
760 */
761 rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns, (RTIOPORT)GCPhysAddress, 8, (void *)pThis,
762 serial_io_write, serial_io_read, NULL, NULL, "SERIAL");
763 AssertRC(rc);
764 return rc;
765}
766
767#endif /* VBOX_SERIAL_PCI */
768
769/**
770 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
771 */
772static DECLCALLBACK(void *) serialQueryInterface(PPDMIBASE pInterface, const char *pszIID)
773{
774 SerialState *pThis = PDMIBASE_2_SERIALSTATE(pInterface);
775 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
776 PDMIBASE_RETURN_INTERFACE(pszIID, PDMICHARPORT, &pThis->ICharPort);
777 return NULL;
778}
779
780/**
781 * Destruct a device instance.
782 *
783 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
784 * resources can be freed correctly.
785 *
786 * @returns VBox status.
787 * @param pDevIns The device instance data.
788 */
789static DECLCALLBACK(int) serialDestruct(PPDMDEVINS pDevIns)
790{
791 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState *);
792 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
793
794 RTSemEventDestroy(pThis->ReceiveSem);
795 pThis->ReceiveSem = NIL_RTSEMEVENT;
796
797 PDMR3CritSectDelete(&pThis->CritSect);
798 return VINF_SUCCESS;
799}
800
801
802/**
803 * @interface_method_impl{PDMDEVREG,pfnConstruct}
804 */
805static DECLCALLBACK(int) serialConstruct(PPDMDEVINS pDevIns,
806 int iInstance,
807 PCFGMNODE pCfg)
808{
809 int rc;
810 SerialState *pThis = PDMINS_2_DATA(pDevIns, SerialState*);
811 uint16_t io_base;
812 uint8_t irq_lvl;
813
814 Assert(iInstance < 4);
815 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
816
817 /*
818 * Initialize the instance data.
819 * (Do this early or the destructor might choke on something!)
820 */
821 pThis->pDevInsR3 = pDevIns;
822 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
823 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
824
825 pThis->lsr = UART_LSR_TEMT | UART_LSR_THRE;
826 pThis->iir = UART_IIR_NO_INT;
827 pThis->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
828
829 /* IBase */
830 pThis->IBase.pfnQueryInterface = serialQueryInterface;
831
832 /* ICharPort */
833 pThis->ICharPort.pfnNotifyRead = serialNotifyRead;
834 pThis->ICharPort.pfnNotifyStatusLinesChanged = serialNotifyStatusLinesChanged;
835 pThis->ICharPort.pfnNotifyBufferFull = serialNotifyBufferFull;
836 pThis->ICharPort.pfnNotifyBreak = serialNotifyBreak;
837
838#ifdef VBOX_SERIAL_PCI
839 /* the PCI device */
840 pThis->dev.config[0x00] = 0xee; /* Vendor: ??? */
841 pThis->dev.config[0x01] = 0x80;
842 pThis->dev.config[0x02] = 0x01; /* Device: ??? */
843 pThis->dev.config[0x03] = 0x01;
844 pThis->dev.config[0x04] = PCI_COMMAND_IOACCESS;
845 pThis->dev.config[0x09] = 0x01; /* Programming interface: 16450 */
846 pThis->dev.config[0x0a] = 0x00; /* Subclass: Serial controller */
847 pThis->dev.config[0x0b] = 0x07; /* Class: Communication controller */
848 pThis->dev.config[0x0e] = 0x00; /* Header type: standard */
849 pThis->dev.config[0x3c] = irq_lvl; /* preconfigure IRQ number (0 = autoconfig)*/
850 pThis->dev.config[0x3d] = 1; /* interrupt pin 0 */
851#endif /* VBOX_SERIAL_PCI */
852
853 /*
854 * Validate and read the configuration.
855 */
856 if (!CFGMR3AreValuesValid(pCfg, "IRQ\0" "IOBase\0" "GCEnabled\0" "R0Enabled\0" "YieldOnLSRRead\0"))
857 {
858 AssertMsgFailed(("serialConstruct Invalid configuration values\n"));
859 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
860 }
861
862 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &pThis->fGCEnabled, true);
863 if (RT_FAILURE(rc))
864 return PDMDEV_SET_ERROR(pDevIns, rc,
865 N_("Configuration error: Failed to get the \"GCEnabled\" value"));
866
867 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, true);
868 if (RT_FAILURE(rc))
869 return PDMDEV_SET_ERROR(pDevIns, rc,
870 N_("Configuration error: Failed to get the \"R0Enabled\" value"));
871
872 rc = CFGMR3QueryBoolDef(pCfg, "YieldOnLSRRead", &pThis->fYieldOnLSRRead, false);
873 if (RT_FAILURE(rc))
874 return PDMDEV_SET_ERROR(pDevIns, rc,
875 N_("Configuration error: Failed to get the \"YieldOnLSRRead\" value"));
876
877 rc = CFGMR3QueryU8(pCfg, "IRQ", &irq_lvl);
878 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
879 {
880 /* Provide sensible defaults. */
881 if (iInstance == 0)
882 irq_lvl = 4;
883 else if (iInstance == 1)
884 irq_lvl = 3;
885 else
886 AssertReleaseFailed(); /* irq_lvl is undefined. */
887 }
888 else if (RT_FAILURE(rc))
889 return PDMDEV_SET_ERROR(pDevIns, rc,
890 N_("Configuration error: Failed to get the \"IRQ\" value"));
891
892 rc = CFGMR3QueryU16(pCfg, "IOBase", &io_base);
893 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
894 {
895 if (iInstance == 0)
896 io_base = 0x3f8;
897 else if (iInstance == 1)
898 io_base = 0x2f8;
899 else
900 AssertReleaseFailed(); /* io_base is undefined */
901 }
902 else if (RT_FAILURE(rc))
903 return PDMDEV_SET_ERROR(pDevIns, rc,
904 N_("Configuration error: Failed to get the \"IOBase\" value"));
905
906 Log(("DevSerial: instance %d iobase=%04x irq=%d\n", iInstance, io_base, irq_lvl));
907
908 pThis->irq = irq_lvl;
909#ifdef VBOX_SERIAL_PCI
910 pThis->base = -1;
911#else
912 pThis->base = io_base;
913#endif
914
915 /*
916 * Initialize critical section and the semaphore.
917 * This must of course be done before attaching drivers or anything else which can call us back..
918 */
919 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "Serial#%d", iInstance);
920 if (RT_FAILURE(rc))
921 return rc;
922
923 rc = RTSemEventCreate(&pThis->ReceiveSem);
924 AssertRC(rc);
925
926#ifdef VBOX_SERIAL_PCI
927 /*
928 * Register the PCI Device and region.
929 */
930 rc = PDMDevHlpPCIRegister(pDevIns, &pThis->dev);
931 if (RT_FAILURE(rc))
932 return rc;
933 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 8, PCI_ADDRESS_SPACE_IO, serialIOPortRegionMap);
934 if (RT_FAILURE(rc))
935 return rc;
936
937#else /* !VBOX_SERIAL_PCI */
938 /*
939 * Register the I/O ports.
940 */
941 pThis->base = io_base;
942 rc = PDMDevHlpIOPortRegister(pDevIns, io_base, 8, 0,
943 serialIOPortWrite, serialIOPortRead,
944 NULL, NULL, "SERIAL");
945 if (RT_FAILURE(rc))
946 return rc;
947
948 if (pThis->fGCEnabled)
949 {
950 rc = PDMDevHlpIOPortRegisterRC(pDevIns, io_base, 8, 0, "serialIOPortWrite",
951 "serialIOPortRead", NULL, NULL, "Serial");
952 if (RT_FAILURE(rc))
953 return rc;
954 }
955
956
957 if (pThis->fR0Enabled)
958 {
959 rc = PDMDevHlpIOPortRegisterR0(pDevIns, io_base, 8, 0, "serialIOPortWrite",
960 "serialIOPortRead", NULL, NULL, "Serial");
961 if (RT_FAILURE(rc))
962 return rc;
963 }
964#endif /* !VBOX_SERIAL_PCI */
965
966 /*
967 * Saved state.
968 */
969 rc = PDMDevHlpSSMRegister3(pDevIns, SERIAL_SAVED_STATE_VERSION, sizeof (*pThis),
970 serialLiveExec, serialSaveExec, serialLoadExec);
971 if (RT_FAILURE(rc))
972 return rc;
973
974 /*
975 * Attach the char driver and get the interfaces.
976 * For now no run-time changes are supported.
977 */
978 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Serial Char");
979 if (RT_SUCCESS(rc))
980 {
981 pThis->pDrvChar = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMICHARCONNECTOR);
982 if (!pThis->pDrvChar)
983 {
984 AssertLogRelMsgFailed(("Configuration error: instance %d has no char interface!\n", iInstance));
985 return VERR_PDM_MISSING_INTERFACE;
986 }
987 /** @todo provide read notification interface!!!! */
988 }
989 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
990 {
991 pThis->pDrvBase = NULL;
992 pThis->pDrvChar = NULL;
993 LogRel(("Serial%d: no unit\n", iInstance));
994 }
995 else
996 {
997 AssertLogRelMsgFailed(("Serial%d: Failed to attach to char driver. rc=%Rrc\n", iInstance, rc));
998 /* Don't call VMSetError here as we assume that the driver already set an appropriate error */
999 return rc;
1000 }
1001
1002 return VINF_SUCCESS;
1003}
1004
1005
1006/**
1007 * The device registration structure.
1008 */
1009const PDMDEVREG g_DeviceSerialPort =
1010{
1011 /* u32Version */
1012 PDM_DEVREG_VERSION,
1013 /* szName */
1014 "serial",
1015 /* szRCMod */
1016 "VBoxDDGC.gc",
1017 /* szR0Mod */
1018 "VBoxDDR0.r0",
1019 /* pszDescription */
1020 "Serial Communication Port",
1021 /* fFlags */
1022 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
1023 /* fClass */
1024 PDM_DEVREG_CLASS_SERIAL,
1025 /* cMaxInstances */
1026 UINT32_MAX,
1027 /* cbInstance */
1028 sizeof(SerialState),
1029 /* pfnConstruct */
1030 serialConstruct,
1031 /* pfnDestruct */
1032 serialDestruct,
1033 /* pfnRelocate */
1034 serialRelocate,
1035 /* pfnIOCtl */
1036 NULL,
1037 /* pfnPowerOn */
1038 NULL,
1039 /* pfnReset */
1040 NULL,
1041 /* pfnSuspend */
1042 NULL,
1043 /* pfnResume */
1044 NULL,
1045 /* pfnAttach */
1046 NULL,
1047 /* pfnDetach */
1048 NULL,
1049 /* pfnQueryInterface. */
1050 NULL,
1051 /* pfnInitComplete */
1052 NULL,
1053 /* pfnPowerOff */
1054 NULL,
1055 /* pfnSoftReset */
1056 NULL,
1057 /* u32VersionEnd */
1058 PDM_DEVREG_VERSION
1059};
1060#endif /* IN_RING3 */
1061
1062
1063#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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