aboutsummaryrefslogtreecommitdiffstats
path: root/xen/include/xen/serial.h
blob: f38c9b7f54d87ed099eb22829d46d6aebce71b6b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
/******************************************************************************
 * serial.h
 * 
 * Framework for serial device drivers.
 * 
 * Copyright (c) 2003-2008, K A Fraser
 */

#ifndef __XEN_SERIAL_H__
#define __XEN_SERIAL_H__

#include <xen/init.h>
#include <xen/spinlock.h>

struct cpu_user_regs;

/* Register a character-receive hook on the specified COM port. */
typedef void (*serial_rx_fn)(char, struct cpu_user_regs *);
void serial_set_rx_handler(int handle, serial_rx_fn fn);

/* Number of characters we buffer for a polling receiver. */
#define serial_rxbufsz 32

/* Number of characters we buffer for an interrupt-driven transmitter. */
extern unsigned int serial_txbufsz;

struct uart_driver;

enum serial_port_state {
    serial_unused,
    serial_parsed,
    serial_initialized
};

struct vuart_info {
    paddr_t base_addr;          /* Base address of the UART */
    unsigned long size;         /* Size of the memory region */
    unsigned long data_off;     /* Data register offset */
    unsigned long status_off;   /* Status register offset */
    unsigned long status;       /* Ready status value */
};

struct serial_port {
    /* Uart-driver parameters. */
    struct uart_driver *driver;
    void               *uart;
    enum serial_port_state state;
    /* Transmit data buffer (interrupt-driven uart). */
    char               *txbuf;
    unsigned int        txbufp, txbufc;
    bool_t              tx_quench;
    int                 tx_log_everything;
    /* Force synchronous transmit. */
    int                 sync;
    /* Receiver callback functions (asynchronous receivers). */
    serial_rx_fn        rx_lo, rx_hi, rx;
    /* Receive data buffer (polling receivers). */
    char                rxbuf[serial_rxbufsz];
    unsigned int        rxbufp, rxbufc;
    /* Serial I/O is concurrency-safe. */
    spinlock_t          rx_lock, tx_lock;
};

struct uart_driver {
    /* Driver initialisation (pre- and post-IRQ subsystem setup). */
    void (*init_preirq)(struct serial_port *);
    void (*init_postirq)(struct serial_port *);
    /* Hook to clean up after Xen bootstrap (before domain 0 runs). */
    void (*endboot)(struct serial_port *);
    /* Driver suspend/resume. */
    void (*suspend)(struct serial_port *);
    void (*resume)(struct serial_port *);
    /* Return number of characters the port can hold for transmit,
     * or -EIO if port is inaccesible */
    int (*tx_ready)(struct serial_port *);
    /* Put a character onto the serial line. */
    void (*putc)(struct serial_port *, char);
    /* Flush accumulated characters. */
    void (*flush)(struct serial_port *);
    /* Get a character from the serial line: returns 0 if none available. */
    int  (*getc)(struct serial_port *, char *);
    /* Get IRQ number for this port's serial line: returns -1 if none. */
    int  (*irq)(struct serial_port *);
    /* Get IRQ device node for this port's serial line: returns NULL if none. */
    const struct dt_irq *(*dt_irq_get)(struct serial_port *);
    /* Get serial information */
    const struct vuart_info *(*vuart_info)(struct serial_port *);
};

/* 'Serial handles' are composed from the following fields. */
#define SERHND_IDX      (3<<0) /* COM1, COM2, DBGP, DTUART?               */
# define SERHND_COM1    (0<<0)
# define SERHND_COM2    (1<<0)
# define SERHND_DBGP    (2<<0)
# define SERHND_DTUART  (0<<0) /* Steal SERHND_COM1 value */
#define SERHND_HI       (1<<2) /* Mux/demux each transferred char by MSB. */
#define SERHND_LO       (1<<3) /* Ditto, except that the MSB is cleared.  */
#define SERHND_COOKED   (1<<4) /* Newline/carriage-return translation?    */

/* Two-stage initialisation (before/after IRQ-subsystem initialisation). */
void serial_init_preirq(void);
void serial_init_postirq(void);

/* Clean-up hook before domain 0 runs. */
void serial_endboot(void);

/* Takes a config string and creates a numeric handle on the COM port. */
int serial_parse_handle(char *conf);

/* Transmit a single character via the specified COM port. */
void serial_putc(int handle, char c);

/* Transmit a NULL-terminated string via the specified COM port. */
void serial_puts(int handle, const char *s);

/*
 * An alternative to registering a character-receive hook. This function
 * will not return until a character is available. It can safely be
 * called with interrupts disabled.
 */
char serial_getc(int handle);

/* Forcibly prevent serial lockup when the system is in a bad way. */
/* (NB. This also forces an implicit serial_start_sync()). */
void serial_force_unlock(int handle);

/* Start/end a synchronous region (temporarily disable interrupt-driven tx). */
void serial_start_sync(int handle);
void serial_end_sync(int handle);

/* Start/end a region where we will wait rather than drop characters. */
void serial_start_log_everything(int handle);
void serial_end_log_everything(int handle);

/* Return irq number for specified serial port (identified by index). */
int serial_irq(int idx);

/* Return irq device node for specified serial port (identified by index). */
const struct dt_irq *serial_dt_irq(int idx);

/* Retrieve basic UART information to emulate it (base address, size...) */
const struct vuart_info* serial_vuart_info(int idx);

/* Serial suspend/resume. */
void serial_suspend(void);
void serial_resume(void);

/*
 * Initialisation and helper functions for uart drivers.
 */
/* Register a uart on serial port @idx (e.g., @idx==0 is COM1). */
void serial_register_uart(int idx, struct uart_driver *driver, void *uart);
/* Place the serial port into asynchronous transmit mode. */
void serial_async_transmit(struct serial_port *port);
/* Process work in interrupt context. */
void serial_rx_interrupt(struct serial_port *port, struct cpu_user_regs *regs);
void serial_tx_interrupt(struct serial_port *port, struct cpu_user_regs *regs);

/*
 * Initialisers for individual uart drivers.
 */
/* NB. Any default value can be 0 if it is unknown and must be specified. */
struct ns16550_defaults {
    int baud;      /* default baud rate; BAUD_AUTO == pre-configured */
    int data_bits; /* default data bits (5, 6, 7 or 8) */
    int parity;    /* default parity (n, o, e, m or s) */
    int stop_bits; /* default stop bits (1 or 2) */
    int irq;       /* default irq */
    unsigned long io_base; /* default io_base address */
};
void ns16550_init(int index, struct ns16550_defaults *defaults);
void ehci_dbgp_init(void);

void __init dt_uart_init(void);

struct physdev_dbgp_op;
int dbgp_op(const struct physdev_dbgp_op *);

/* Baud rate was pre-configured before invoking the UART driver. */
#define BAUD_AUTO (-1)

#endif /* __XEN_SERIAL_H__ */

/*
 * Local variables:
 * mode: C
 * c-file-style: "BSD"
 * c-basic-offset: 4
 * tab-width: 4
 * indent-tabs-mode: nil
 * End:
 */