blob: 4ea27417f52f1b8d54fbce48e83c3061dec80a2a [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <threads.h>
#include <magenta/types.h>
// clang-format off
/* UART state flags. */
#define UART_INTERRUPT_ENABLE_NONE 0
#define UART_INTERRUPT_ENABLE_RDA (1u << 0)
#define UART_INTERRUPT_ENABLE_THR_EMPTY (1u << 1)
#define UART_INTERRUPT_ID_NONE (1u << 0)
#define UART_INTERRUPT_ID_THR_EMPTY (1u << 1)
#define UART_INTERRUPT_ID_RDA (1u << 2)
#define UART_LINE_CONTROL_DIV_LATCH (1u << 7)
#define UART_LINE_STATUS_DATA_READY (1u << 0)
#define UART_LINE_STATUS_EMPTY (1u << 5)
#define UART_LINE_STATUS_IDLE (1u << 6)
#define UART_LINE_STATUS_THR_EMPTY (UART_LINE_STATUS_IDLE | UART_LINE_STATUS_EMPTY)
/* Interrupt vectors. */
#define X86_INT_UART 4u
/* UART configuration constants. */
#define UART_BUFFER_SIZE 512u
// clang-format on
__BEGIN_CDECLS
typedef struct io_apic io_apic_t;
typedef struct mx_packet_guest_io mx_packet_guest_io_t;
typedef struct mx_vcpu_io mx_vcpu_io_t;
/* Stores the state of a UART. */
typedef struct uart {
mtx_t mutex;
// IO APIC for use with interrupt redirects.
const io_apic_t* io_apic;
// Transmit holding register (THR).
uint8_t tx_buffer[UART_BUFFER_SIZE];
uint16_t tx_offset;
// Notify output thread that guest has output buffered.
cnd_t tx_cnd;
// Receive buffer register (RBR).
uint8_t rx_buffer;
// Notify input thread that guest is ready for input.
cnd_t rx_cnd;
// Interrupt enable register (IER).
uint8_t interrupt_enable;
// Interrupt ID register (IIR).
uint8_t interrupt_id;
// Line control register (LCR).
uint8_t line_control;
// Line status register (LSR).
uint8_t line_status;
// Raise an interrupt.
mx_status_t (*raise_interrupt)(mx_handle_t vcpu, uint32_t vector);
} uart_t;
void uart_init(uart_t* uart, const io_apic_t* io_apic);
mx_status_t uart_read(uart_t* uart, uint16_t port, mx_vcpu_io_t* vcpu_io);
mx_status_t uart_write(uart_t* uart, const mx_packet_guest_io_t* io);
/* Start asynchronous handling of UART. */
mx_status_t uart_async(uart_t* uart, mx_handle_t guest);
__END_CDECLS