VirtualBox

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

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

Converted serial card to PCI device

  • Property svn:eol-style set to native
File size: 24.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
64#include "Builtins.h"
65#include "../vl_vbox.h"
66
67#define VBOX_SERIAL_PCI
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#endif /* VBOX */
76
77#ifndef VBOX
78#include "vl.h"
79#endif /* !VBOX */
80
81//#define DEBUG_SERIAL
82
83#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
84
85#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */
86#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */
87#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */
88#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */
89
90#define UART_IIR_NO_INT 0x01 /* No interrupts pending */
91#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */
92
93#define UART_IIR_MSI 0x00 /* Modem status interrupt */
94#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */
95#define UART_IIR_RDI 0x04 /* Receiver data interrupt */
96#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */
97
98/*
99 * These are the definitions for the Modem Control Register
100 */
101#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
102#define UART_MCR_OUT2 0x08 /* Out2 complement */
103#define UART_MCR_OUT1 0x04 /* Out1 complement */
104#define UART_MCR_RTS 0x02 /* RTS complement */
105#define UART_MCR_DTR 0x01 /* DTR complement */
106
107/*
108 * These are the definitions for the Modem Status Register
109 */
110#define UART_MSR_DCD 0x80 /* Data Carrier Detect */
111#define UART_MSR_RI 0x40 /* Ring Indicator */
112#define UART_MSR_DSR 0x20 /* Data Set Ready */
113#define UART_MSR_CTS 0x10 /* Clear to Send */
114#define UART_MSR_DDCD 0x08 /* Delta DCD */
115#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */
116#define UART_MSR_DDSR 0x02 /* Delta DSR */
117#define UART_MSR_DCTS 0x01 /* Delta CTS */
118#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */
119
120#define UART_LSR_TEMT 0x40 /* Transmitter empty */
121#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
122#define UART_LSR_BI 0x10 /* Break interrupt indicator */
123#define UART_LSR_FE 0x08 /* Frame error indicator */
124#define UART_LSR_PE 0x04 /* Parity error indicator */
125#define UART_LSR_OE 0x02 /* Overrun error indicator */
126#define UART_LSR_DR 0x01 /* Receiver data ready */
127
128struct SerialState {
129 uint16_t divider;
130 uint8_t rbr; /* receive register */
131 uint8_t ier;
132 uint8_t iir; /* read only */
133 uint8_t lcr;
134 uint8_t mcr;
135 uint8_t lsr; /* read only */
136 uint8_t msr; /* read only */
137 uint8_t scr;
138 /* NOTE: this hidden state is necessary for tx irq generation as
139 it can be reset while reading iir */
140 int thr_ipending;
141#ifndef VBOX
142 SetIRQFunc *set_irq;
143 void *irq_opaque;
144#endif /* !VBOX */
145 int irq;
146#ifdef VBOX
147#ifdef VBOX_SERIAL_PCI
148 PCIDEVICE dev;
149#endif /* VBOX_SERIAL_PCI */
150 /* Be careful with pointers in the structure; load just gets the whole structure from the saved state */
151 PPDMDEVINS pDevIns;
152#if 0
153 PDMICHAR pDevChar;
154#endif
155#else /* !VBOX */
156 CharDriverState *chr;
157#endif /* !VBOX */
158 int last_break_enable;
159 target_ulong base;
160#ifndef VBOX
161 int it_shift;
162#endif /* !VBOX */
163};
164
165#ifdef VBOX
166#ifdef VBOX_SERIAL_PCI
167#define PCIDEV_2_SERIALSTATE(pPciDev) ( (SerialState *)((uintptr_t)(pPciDev) - RT_OFFSETOF(SerialState, dev)) )
168#endif /* VBOX_SERIAL_PCI */
169#endif /* VBOX */
170
171static void serial_update_irq(SerialState *s)
172{
173 if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) {
174 s->iir = UART_IIR_RDI;
175 } else if (s->thr_ipending && (s->ier & UART_IER_THRI)) {
176 s->iir = UART_IIR_THRI;
177 } else {
178 s->iir = UART_IIR_NO_INT;
179 }
180 if (s->iir != UART_IIR_NO_INT) {
181#ifdef VBOX
182 s->pDevIns->pDevHlp->pfnISASetIrq (s->pDevIns, s->irq, 1);
183#else /* !VBOX */
184 s->set_irq(s->irq_opaque, s->irq, 1);
185#endif /* !VBOX */
186 } else {
187#ifdef VBOX
188 s->pDevIns->pDevHlp->pfnISASetIrq (s->pDevIns, s->irq, 0);
189#else /* !VBOX */
190 s->set_irq(s->irq_opaque, s->irq, 0);
191#endif /* !VBOX */
192 }
193}
194
195static void serial_update_parameters(SerialState *s)
196{
197 int speed, parity, data_bits, stop_bits;
198 QEMUSerialSetParams ssp;
199
200 if (s->lcr & 0x08) {
201 if (s->lcr & 0x10)
202 parity = 'E';
203 else
204 parity = 'O';
205 } else {
206 parity = 'N';
207 }
208 if (s->lcr & 0x04)
209 stop_bits = 2;
210 else
211 stop_bits = 1;
212 data_bits = (s->lcr & 0x03) + 5;
213 if (s->divider == 0)
214 return;
215 speed = 115200 / s->divider;
216 ssp.speed = speed;
217 ssp.parity = parity;
218 ssp.data_bits = data_bits;
219 ssp.stop_bits = stop_bits;
220#ifndef VBOX
221 qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
222#endif /* !VBOX */
223#if 0
224 printf("speed=%d parity=%c data=%d stop=%d\n",
225 speed, parity, data_bits, stop_bits);
226#endif
227}
228
229static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
230{
231 SerialState *s = opaque;
232 unsigned char ch;
233
234 addr &= 7;
235#ifdef DEBUG_SERIAL
236 printf("serial: write addr=0x%02x val=0x%02x\n", addr, val);
237#endif
238 switch(addr) {
239 default:
240 case 0:
241 if (s->lcr & UART_LCR_DLAB) {
242 s->divider = (s->divider & 0xff00) | val;
243 serial_update_parameters(s);
244 } else {
245 s->thr_ipending = 0;
246 s->lsr &= ~UART_LSR_THRE;
247 serial_update_irq(s);
248 ch = val;
249#ifdef VBOX
250#if 0
251 if (s->pDrvChar)
252 {
253 int rc = s->pDrvChar->pfnWrite(s->pDrvChar, &ch, 1);
254 AssertRC(rc);
255 }
256#endif
257#else /* !VBOX */
258 qemu_chr_write(s->chr, &ch, 1);
259#endif /* !VBOX */
260 s->thr_ipending = 1;
261 s->lsr |= UART_LSR_THRE;
262 s->lsr |= UART_LSR_TEMT;
263 serial_update_irq(s);
264 }
265 break;
266 case 1:
267 if (s->lcr & UART_LCR_DLAB) {
268 s->divider = (s->divider & 0x00ff) | (val << 8);
269 serial_update_parameters(s);
270 } else {
271 s->ier = val & 0x0f;
272 if (s->lsr & UART_LSR_THRE) {
273 s->thr_ipending = 1;
274 }
275 serial_update_irq(s);
276 }
277 break;
278 case 2:
279 break;
280 case 3:
281 {
282 int break_enable;
283 s->lcr = val;
284 serial_update_parameters(s);
285 break_enable = (val >> 6) & 1;
286 if (break_enable != s->last_break_enable) {
287 s->last_break_enable = break_enable;
288#ifndef VBOX
289 qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
290 &break_enable);
291#endif /* !VBOX */
292 }
293 }
294 break;
295 case 4:
296 s->mcr = val & 0x1f;
297 break;
298 case 5:
299 break;
300 case 6:
301 break;
302 case 7:
303 s->scr = val;
304 break;
305 }
306}
307
308static uint32_t serial_ioport_read(void *opaque, uint32_t addr)
309{
310 SerialState *s = opaque;
311 uint32_t ret;
312
313 addr &= 7;
314 switch(addr) {
315 default:
316 case 0:
317 if (s->lcr & UART_LCR_DLAB) {
318 ret = s->divider & 0xff;
319 } else {
320 ret = s->rbr;
321 s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
322 serial_update_irq(s);
323 }
324 break;
325 case 1:
326 if (s->lcr & UART_LCR_DLAB) {
327 ret = (s->divider >> 8) & 0xff;
328 } else {
329 ret = s->ier;
330 }
331 break;
332 case 2:
333 ret = s->iir;
334 /* reset THR pending bit */
335 if ((ret & 0x7) == UART_IIR_THRI)
336 s->thr_ipending = 0;
337 serial_update_irq(s);
338 break;
339 case 3:
340 ret = s->lcr;
341 break;
342 case 4:
343 ret = s->mcr;
344 break;
345 case 5:
346 ret = s->lsr;
347 break;
348 case 6:
349 if (s->mcr & UART_MCR_LOOP) {
350 /* in loopback, the modem output pins are connected to the
351 inputs */
352 ret = (s->mcr & 0x0c) << 4;
353 ret |= (s->mcr & 0x02) << 3;
354 ret |= (s->mcr & 0x01) << 5;
355 } else {
356 ret = s->msr;
357 }
358 break;
359 case 7:
360 ret = s->scr;
361 break;
362 }
363#ifdef DEBUG_SERIAL
364 printf("serial: read addr=0x%02x val=0x%02x\n", addr, ret);
365#endif
366 return ret;
367}
368
369#ifdef VBOX
370/* Provide non-blocking functions to receive data from the host system. */
371
372#else /* !VBOX */
373static int serial_can_receive(SerialState *s)
374{
375 return !(s->lsr & UART_LSR_DR);
376}
377
378static void serial_receive_byte(SerialState *s, int ch)
379{
380 s->rbr = ch;
381 s->lsr |= UART_LSR_DR;
382 serial_update_irq(s);
383}
384
385static void serial_receive_break(SerialState *s)
386{
387 s->rbr = 0;
388 s->lsr |= UART_LSR_BI | UART_LSR_DR;
389 serial_update_irq(s);
390}
391
392static int serial_can_receive1(void *opaque)
393{
394 SerialState *s = opaque;
395 return serial_can_receive(s);
396}
397
398static void serial_receive1(void *opaque, const uint8_t *buf, int size)
399{
400 SerialState *s = opaque;
401 serial_receive_byte(s, buf[0]);
402}
403
404static void serial_event(void *opaque, int event)
405{
406 SerialState *s = opaque;
407 if (event == CHR_EVENT_BREAK)
408 serial_receive_break(s);
409}
410
411static void serial_save(QEMUFile *f, void *opaque)
412{
413 SerialState *s = opaque;
414
415 qemu_put_be16s(f,&s->divider);
416 qemu_put_8s(f,&s->rbr);
417 qemu_put_8s(f,&s->ier);
418 qemu_put_8s(f,&s->iir);
419 qemu_put_8s(f,&s->lcr);
420 qemu_put_8s(f,&s->mcr);
421 qemu_put_8s(f,&s->lsr);
422 qemu_put_8s(f,&s->msr);
423 qemu_put_8s(f,&s->scr);
424}
425
426static int serial_load(QEMUFile *f, void *opaque, int version_id)
427{
428 SerialState *s = opaque;
429
430 if(version_id > 2)
431 return -EINVAL;
432
433 if (version_id >= 2)
434 qemu_get_be16s(f, &s->divider);
435 else
436 s->divider = qemu_get_byte(f);
437 qemu_get_8s(f,&s->rbr);
438 qemu_get_8s(f,&s->ier);
439 qemu_get_8s(f,&s->iir);
440 qemu_get_8s(f,&s->lcr);
441 qemu_get_8s(f,&s->mcr);
442 qemu_get_8s(f,&s->lsr);
443 qemu_get_8s(f,&s->msr);
444 qemu_get_8s(f,&s->scr);
445
446 return 0;
447}
448
449/* If fd is zero, it means that the serial device uses the console */
450SerialState *serial_init(SetIRQFunc *set_irq, void *opaque,
451 int base, int irq, CharDriverState *chr)
452{
453 SerialState *s;
454
455 s = qemu_mallocz(sizeof(SerialState));
456 if (!s)
457 return NULL;
458 s->set_irq = set_irq;
459 s->irq_opaque = opaque;
460 s->irq = irq;
461 s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
462 s->iir = UART_IIR_NO_INT;
463 s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
464
465 register_savevm("serial", base, 2, serial_save, serial_load, s);
466
467 register_ioport_write(base, 8, 1, serial_ioport_write, s);
468 register_ioport_read(base, 8, 1, serial_ioport_read, s);
469 s->chr = chr;
470 qemu_chr_add_read_handler(chr, serial_can_receive1, serial_receive1, s);
471 qemu_chr_add_event_handler(chr, serial_event);
472 return s;
473}
474
475/* Memory mapped interface */
476static uint32_t serial_mm_readb (void *opaque, target_phys_addr_t addr)
477{
478 SerialState *s = opaque;
479
480 return serial_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFF;
481}
482
483static void serial_mm_writeb (void *opaque,
484 target_phys_addr_t addr, uint32_t value)
485{
486 SerialState *s = opaque;
487
488 serial_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFF);
489}
490
491static uint32_t serial_mm_readw (void *opaque, target_phys_addr_t addr)
492{
493 SerialState *s = opaque;
494
495 return serial_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFFFF;
496}
497
498static void serial_mm_writew (void *opaque,
499 target_phys_addr_t addr, uint32_t value)
500{
501 SerialState *s = opaque;
502
503 serial_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFFFF);
504}
505
506static uint32_t serial_mm_readl (void *opaque, target_phys_addr_t addr)
507{
508 SerialState *s = opaque;
509
510 return serial_ioport_read(s, (addr - s->base) >> s->it_shift);
511}
512
513static void serial_mm_writel (void *opaque,
514 target_phys_addr_t addr, uint32_t value)
515{
516 SerialState *s = opaque;
517
518 serial_ioport_write(s, (addr - s->base) >> s->it_shift, value);
519}
520
521static CPUReadMemoryFunc *serial_mm_read[] = {
522 &serial_mm_readb,
523 &serial_mm_readw,
524 &serial_mm_readl,
525};
526
527static CPUWriteMemoryFunc *serial_mm_write[] = {
528 &serial_mm_writeb,
529 &serial_mm_writew,
530 &serial_mm_writel,
531};
532
533SerialState *serial_mm_init (SetIRQFunc *set_irq, void *opaque,
534 target_ulong base, int it_shift,
535 int irq, CharDriverState *chr)
536{
537 SerialState *s;
538 int s_io_memory;
539
540 s = qemu_mallocz(sizeof(SerialState));
541 if (!s)
542 return NULL;
543 s->set_irq = set_irq;
544 s->irq_opaque = opaque;
545 s->irq = irq;
546 s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
547 s->iir = UART_IIR_NO_INT;
548 s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
549 s->base = base;
550 s->it_shift = it_shift;
551
552 register_savevm("serial", base, 2, serial_save, serial_load, s);
553
554 s_io_memory = cpu_register_io_memory(0, serial_mm_read,
555 serial_mm_write, s);
556 cpu_register_physical_memory(base, 8 << it_shift, s_io_memory);
557 s->chr = chr;
558 qemu_chr_add_read_handler(chr, serial_can_receive1, serial_receive1, s);
559 qemu_chr_add_event_handler(chr, serial_event);
560 return s;
561}
562#endif
563
564#ifdef VBOX
565static DECLCALLBACK(int) serial_io_write (PPDMDEVINS pDevIns,
566 void *pvUser,
567 RTIOPORT Port,
568 uint32_t u32,
569 unsigned cb)
570{
571 if (cb == 1) {
572 Log(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, u32));
573 serial_ioport_write (pvUser, Port, u32);
574 }
575 else {
576 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
577 }
578 return VINF_SUCCESS;
579}
580
581static DECLCALLBACK(int) serial_io_read (PPDMDEVINS pDevIns,
582 void *pvUser,
583 RTIOPORT Port,
584 uint32_t *pu32,
585 unsigned cb)
586{
587 if (cb == 1) {
588 Log(("%s: port %#06x\n", __FUNCTION__, Port));
589 *pu32 = serial_ioport_read (pvUser, Port);
590 Log(("%s: port %#06x val %#04x\n", __FUNCTION__, Port, *pu32));
591 return VINF_SUCCESS;
592 }
593 else {
594 return VERR_IOM_IOPORT_UNUSED;
595 }
596}
597
598static DECLCALLBACK(int) serialSaveExec(PPDMDEVINS pDevIns,
599 PSSMHANDLE pSSMHandle)
600{
601 SerialState *s = PDMINS2DATA (pDevIns, SerialState *);
602 SSMR3PutU16(pSSMHandle, s->divider);
603 SSMR3PutU8(pSSMHandle, s->rbr);
604 SSMR3PutU8(pSSMHandle, s->ier);
605 SSMR3PutU8(pSSMHandle, s->lcr);
606 SSMR3PutU8(pSSMHandle, s->mcr);
607 SSMR3PutU8(pSSMHandle, s->lsr);
608 SSMR3PutU8(pSSMHandle, s->msr);
609 SSMR3PutU8(pSSMHandle, s->scr);
610 SSMR3PutU32(pSSMHandle, s->thr_ipending);
611 SSMR3PutU32(pSSMHandle, s->irq);
612 SSMR3PutU32(pSSMHandle, s->last_break_enable);
613 SSMR3PutU32(pSSMHandle, s->base);
614 return SSMR3PutU32(pSSMHandle, ~0); /* sanity/terminator */
615}
616
617static DECLCALLBACK(int) serialLoadExec(PPDMDEVINS pDevIns,
618 PSSMHANDLE pSSMHandle,
619 uint32_t u32Version)
620{
621 int rc;
622 uint32_t u32;
623 SerialState *s = PDMINS2DATA (pDevIns, SerialState *);
624
625 if (u32Version != SERIAL_SAVED_STATE_VERSION) {
626 AssertMsgFailed(("u32Version=%d\n", u32Version));
627 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
628 }
629
630 SSMR3GetU16(pSSMHandle, &s->divider);
631 SSMR3GetU8(pSSMHandle, &s->rbr);
632 SSMR3GetU8(pSSMHandle, &s->ier);
633 SSMR3GetU8(pSSMHandle, &s->lcr);
634 SSMR3GetU8(pSSMHandle, &s->mcr);
635 SSMR3GetU8(pSSMHandle, &s->lsr);
636 SSMR3GetU8(pSSMHandle, &s->msr);
637 SSMR3GetU8(pSSMHandle, &s->scr);
638 SSMR3GetU32(pSSMHandle, &s->thr_ipending);
639 SSMR3GetU32(pSSMHandle, &s->irq);
640 SSMR3GetU32(pSSMHandle, &s->last_break_enable);
641 SSMR3GetU32(pSSMHandle, &s->base);
642
643 rc = SSMR3GetU32(pSSMHandle, &u32);
644 if (VBOX_FAILURE(rc))
645 return rc;
646
647 if (u32 != ~0U) {
648 AssertMsgFailed(("u32=%#x expected ~0\n", u32));
649 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
650 }
651 /* Be careful with pointers in the structure; they are not preserved
652 * in the saved state. */
653 s->pDevIns = pDevIns;
654 return VINF_SUCCESS;
655}
656
657#ifdef VBOX_SERIAL_PCI
658
659static DECLCALLBACK(int) serialIOPortRegionMap(PPCIDEVICE pPciDev, /* unsigned */ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
660{
661 SerialState *pData = PCIDEV_2_SERIALSTATE(pPciDev);
662 int rc = VINF_SUCCESS;
663
664 Assert(enmType == PCI_ADDRESS_SPACE_IO);
665 Assert(iRegion == 0);
666 Assert(cb == 8);
667 AssertMsg(RT_ALIGN(GCPhysAddress, 8) == GCPhysAddress, ("Expected 8 byte alignment. GCPhysAddress=%#x\n", GCPhysAddress));
668
669 pData->base = (RTIOPORT)GCPhysAddress;
670
671 /*
672 * Register our port IO handlers.
673 */
674 rc = pPciDev->pDevIns->pDevHlp->pfnIOPortRegister(pPciDev->pDevIns, (RTIOPORT)GCPhysAddress, 8, (void *)pData,
675 serial_io_write, serial_io_read, NULL, NULL, "SERIAL");
676 AssertRC(rc);
677 return rc;
678}
679
680#endif /* VBOX_SERIAL_PCI */
681
682/**
683 * Construct a device instance for a VM.
684 *
685 * @returns VBox status.
686 * @param pDevIns The device instance data.
687 * If the registration structure is needed, pDevIns->pDevReg points to it.
688 * @param iInstance Instance number. Use this to figure out which registers and such to use.
689 * The device number is also found in pDevIns->iInstance, but since it's
690 * likely to be freqently used PDM passes it as parameter.
691 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
692 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
693 * iInstance it's expected to be used a bit in this function.
694 */
695static DECLCALLBACK(int) serialConstruct(PPDMDEVINS pDevIns,
696 int iInstance,
697 PCFGMNODE pCfgHandle)
698{
699 int rc;
700 SerialState *s = PDMINS2DATA(pDevIns, SerialState*);
701 uint16_t io_base;
702 uint8_t irq_lvl;
703
704 Assert(iInstance < 2);
705
706 s->pDevIns = pDevIns;
707 /*
708 * Validate configuration.
709 */
710 if (!CFGMR3AreValuesValid(pCfgHandle, "IRQ\0IOBase\0")) {
711 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
712 }
713
714
715/** @todo r=bird: Check for VERR_CFGM_VALUE_NOT_FOUND and provide sensible defaults.
716 * Also do AssertMsgFailed(("Configuration error:....)) in the failure cases of CFGMR3Query*()
717 * and CFGR3AreValuesValid() like we're doing in the other devices. */
718 rc = CFGMR3QueryU8 (pCfgHandle, "IRQ", &irq_lvl);
719 if (VBOX_FAILURE (rc)) {
720 return rc;
721 }
722
723 rc = CFGMR3QueryU16 (pCfgHandle, "IOBase", &io_base);
724 if (VBOX_FAILURE (rc)) {
725 return rc;
726 }
727
728 Log(("serialConstruct instance %d iobase=%04x irq=%d\n", iInstance, io_base, irq_lvl));
729
730 s->irq = irq_lvl;
731 s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
732 s->iir = UART_IIR_NO_INT;
733 s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
734#ifdef VBOX_SERIAL_PCI
735 s->base = -1;
736 s->dev.config[0x00] = 0xee; /* Vendor: ??? */
737 s->dev.config[0x01] = 0x80;
738 s->dev.config[0x02] = 0x01; /* Device: ??? */
739 s->dev.config[0x03] = 0x01;
740 s->dev.config[0x04] = PCI_COMMAND_IOACCESS;
741 s->dev.config[0x09] = 0x01; /* Programming interface: 16450 */
742 s->dev.config[0x0a] = 0x00; /* Subclass: Serial controller */
743 s->dev.config[0x0b] = 0x07; /* Class: Communication controller */
744 s->dev.config[0x0e] = 0x00; /* Header type: standard */
745 s->dev.config[0x3c] = irq_lvl; /* preconfigure IRQ number (0 = autoconfig)*/
746 s->dev.config[0x3d] = 1; /* interrupt pin 0 */
747 rc = pDevIns->pDevHlp->pfnPCIRegister(pDevIns, &s->dev);
748 if (VBOX_FAILURE(rc))
749 return rc;
750 /*
751 * Register the PCI I/O ports.
752 */
753 rc = pDevIns->pDevHlp->pfnPCIIORegionRegister(pDevIns, 0, 8, PCI_ADDRESS_SPACE_IO, serialIOPortRegionMap);
754 if (VBOX_FAILURE(rc))
755 return rc;
756#else /* !VBOX_SERIAL_PCI */
757 s->base = io_base;
758 rc = pDevIns->pDevHlp->pfnIOPortRegister (
759 pDevIns,
760 io_base,
761 8,
762 s,
763 serial_io_write,
764 serial_io_read,
765 NULL, NULL,
766 "SERIAL"
767 );
768 if (VBOX_FAILURE (rc)) {
769 return rc;
770 }
771#endif /* !VBOX_SERIAL_PCI */
772
773 rc = pDevIns->pDevHlp->pfnSSMRegister (
774 pDevIns, /* pDevIns */
775 pDevIns->pDevReg->szDeviceName, /* pszName */
776 iInstance, /* u32Instance */
777 SERIAL_SAVED_STATE_VERSION, /* u32Version */
778 sizeof (*s), /* cbGuess */
779 NULL, /* pfnSavePrep */
780 serialSaveExec, /* pfnSaveExec */
781 NULL, /* pfnSaveDone */
782 NULL, /* pfnLoadPrep */
783 serialLoadExec, /* pfnLoadExec */
784 NULL /* pfnLoadDone */
785 );
786 if (VBOX_FAILURE(rc))
787 return rc;
788
789 return VINF_SUCCESS;
790}
791
792/**
793 * The device registration structure.
794 */
795const PDMDEVREG g_DeviceSerialPort =
796{
797 /* u32Version */
798 PDM_DEVREG_VERSION,
799 /* szDeviceName */
800 "serial",
801 /* szGCMod */
802 "",
803 /* szR0Mod */
804 "",
805 /* pszDescription */
806 "Serial Communication Port",
807 /* fFlags */
808 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT,
809 /* fClass */
810 PDM_DEVREG_CLASS_SERIAL_PORT,
811 /* cMaxInstances */
812 1,
813 /* cbInstance */
814 sizeof(SerialState),
815 /* pfnConstruct */
816 serialConstruct,
817 /* pfnDestruct */
818 NULL,
819 /* pfnRelocate */
820 NULL,
821 /* pfnIOCtl */
822 NULL,
823 /* pfnPowerOn */
824 NULL,
825 /* pfnReset */
826 NULL,
827 /* pfnSuspend */
828 NULL,
829 /* pfnResume */
830 NULL,
831 /* pfnAttach */
832 NULL,
833 /* pfnDetach */
834 NULL,
835 /* pfnQueryInterface. */
836 NULL
837};
838#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