L4Re Operating System Framework
Interface and Usage Documentation
Loading...
Searching...
No Matches
uart_base.h
1/*
2 * Copyright (C) 2009-2012 Technische Universität Dresden.
3 * Copyright (C) 2023-2025 Kernkonzept GmbH.
4 * Author(s): Adam Lackorzynski <adam@os.inf.tu-dresden.de>
5 *
6 * License: see LICENSE.spdx (in this directory or the directories above)
7 */
8#pragma once
9
10#include <stddef.h>
11#include <l4/drivers/io_regblock.h>
12#include <l4/sys/types.h>
13
14#include <l4/drivers/device.h>
15#include "poll_timeout_counter.h"
16
17namespace L4 {
18
22class Uart : public Dev_obj
23{
24protected:
25 unsigned _mode;
26 unsigned _rate;
27 Io_register_block const *_regs;
28
29public:
30 void *operator new (size_t, void *p) { return p; }
31
32public:
33 typedef unsigned Transfer_mode;
34 typedef unsigned Baud_rate;
35
36 Uart()
37 : _mode(~0U), _rate(~0U)
38 {}
39
47 virtual bool reg_shift(unsigned char *shift __attribute__((unused))) const
48 { return false; }
49
57 virtual bool startup(Io_register_block const *regs) = 0;
58
59 virtual ~Uart() {}
60
64 virtual void shutdown() = 0;
65
77 virtual bool change_mode(Transfer_mode m, Baud_rate r) = 0;
78
89 virtual int write(char const *s, unsigned long count,
90 bool blocking = true) const = 0;
91
97 Transfer_mode mode() const { return _mode; }
98
104 Baud_rate rate() const { return _rate; }
105
106#ifndef UART_WITHOUT_INPUT
107
115 virtual bool enable_rx_irq(bool = true) { return false; }
116
120 virtual void irq_ack() {}
121
128 virtual int char_avail() const = 0;
129
138 virtual int get_char(bool blocking = true) const = 0;
139
140#endif // !UART_WITHOUT_INPUT
141
142protected:
154 template <typename Uart_driver, bool Timeout_guard = true>
155 int generic_write(char const *s, unsigned long count,
156 bool blocking = true) const
157 {
158 auto *self = static_cast<Uart_driver const*>(this);
159
160 unsigned long c;
161 for (c = 0; c < count; ++c)
162 {
163 if (!blocking && !self->tx_avail())
164 break;
165
166 if constexpr (Timeout_guard)
167 {
168 Poll_timeout_counter i(3000000);
169 while (i.test(!self->tx_avail()))
170 ;
171 }
172 else
173 {
174 while (!self->tx_avail())
175 ;
176 }
177
178 self->out_char(*s++);
179 }
180
181 if (blocking)
182 self->wait_tx_done();
183
184 return c;
185 }
186};
187
188} // namespace L4
189
190/*
191 * Instantiate a UART, given the memory.
192 */
193static inline
194L4::Uart *
195l4re_dev_uart_create_by_dt_compatible(const char *dt_compatible,
196 void *obj_buf, unsigned obj_buf_size,
197 unsigned freq)
198{
199 L4::Dev_obj *dev = l4re_dev_create_by_dt_compatible(dt_compatible,
200 obj_buf, obj_buf_size,
201 freq);
202 return static_cast<L4::Uart *>(dev);
203}
204
205/*
206 * Instantiate a UART a single time, use an internal static buffer.
207 */
208static inline
209L4::Uart *
210l4re_dev_uart_create_by_dt_compatible_once(const char *dt_compatible, unsigned freq)
211{
212 static bool once_done = false;
213
214 if (once_done)
215 return nullptr;
216
217 static char __attribute__((aligned(sizeof(long) * 2))) obj_buf[64];
218 L4::Uart *uart
219 = l4re_dev_uart_create_by_dt_compatible(dt_compatible,
220 obj_buf, sizeof(obj_buf),
221 freq);
222 if (uart)
223 once_done = true;
224
225 return uart;
226}
227
228#define l4re_register_device_uart(Device_class, instance_name, \
229 device_dt_ids, pci_ids) \
230 static const struct l4re_device_ids __dev_spec_##instance_name \
231 = { .dt = device_dt_ids, .pcidev = pci_ids }; \
232 l4re_register_device(L4::Uart, Device_class, instance_name, \
233 __dev_spec_##instance_name)
234
235#define l4re_register_device_uart_dt(Device_class, instance_name, dt_ids) \
236 l4re_register_device_uart(Device_class, instance_name, dt_ids, nullptr)
237
238#define l4re_register_device_uart_pci(Device_class, instance_name, pci_ids) \
239 l4re_register_device_uart(Device_class, instance_name, nullptr, pci_ids)
240
Evaluate an expression for a maximum number of times.
bool test(bool expression=true)
Evaluate the expression for a maximum number of times.
Uart driver abstraction.
Definition uart_base.h:23
virtual void irq_ack()
Acknowledge a received interrupt.
Definition uart_base.h:120
virtual int write(char const *s, unsigned long count, bool blocking=true) const =0
Transmit a number of characters.
int generic_write(char const *s, unsigned long count, bool blocking=true) const
Internal function transmitting each character one-after-another and finally waiting that the transmis...
Definition uart_base.h:155
virtual void shutdown()=0
Terminate the UART driver.
Baud_rate rate() const
Return the baud rate.
Definition uart_base.h:104
virtual int char_avail() const =0
Check if there is at least one character available for reading from the UART.
virtual bool reg_shift(unsigned char *shift)) const
Provide the reg_shift value for the UART's registers.
Definition uart_base.h:47
virtual bool change_mode(Transfer_mode m, Baud_rate r)=0
Set certain parameters of the UART.
virtual bool startup(Io_register_block const *regs)=0
Start the UART driver.
virtual bool enable_rx_irq(bool=true)
Enable the receive IRQ.
Definition uart_base.h:115
virtual int get_char(bool blocking=true) const =0
Read a character from the UART.
Transfer_mode mode() const
Return the transfer mode.
Definition uart_base.h:97
Common L4 ABI Data Types.
L4 low-level kernel interface.