VirtualBox

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

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

First go at a serial port device with I/O hooked to named pipe/local
socket. Doesn't support mounting/unmounting at runtime yet.

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