Skip to content

Commit df1e6f5

Browse files
tpamborhenrikbrixandersen
authored andcommitted
serial: uart_native_pty: IRQ support
Add support for the interrupt-driven API. Interrupts are emulated using a polling thread. Signed-off-by: Tim Pambor <tim.pambor@codewrights.de>
1 parent 00cee2c commit df1e6f5

File tree

5 files changed

+309
-61
lines changed

5 files changed

+309
-61
lines changed

boards/native/native_sim/doc/index.rst

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -564,8 +564,7 @@ program ends, one could do:
564564
565565
$ zephyr.exe --uart_attach_uart_cmd='ln -s %s /tmp/somename' ; rm /tmp/somename
566566
567-
This driver supports poll mode or async mode with :kconfig:option:`CONFIG_UART_ASYNC_API`.
568-
Interrupt mode is not supported.
567+
This driver supports poll mode, interrupt mode and async mode.
569568
Neither runtime configuration or line control are supported.
570569

571570
.. _native_tty_uart:

drivers/serial/Kconfig.native_pty

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ config UART_NATIVE_PTY
77
depends on (DT_HAS_ZEPHYR_NATIVE_PTY_UART_ENABLED || DT_HAS_ZEPHYR_NATIVE_POSIX_UART_ENABLED)
88
select SERIAL_HAS_DRIVER
99
select SERIAL_SUPPORT_ASYNC
10+
select SERIAL_SUPPORT_INTERRUPT
1011
help
1112
This enables a PTY based UART driver for the POSIX ARCH with up to 2 UARTs.
1213
For the first UART port, the driver can be configured

drivers/serial/uart_native_pty.c

Lines changed: 239 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ struct native_pty_status {
4343
int out_fd; /* File descriptor used for output */
4444
int in_fd; /* File descriptor used for input */
4545
bool on_stdinout; /* This UART is connected to a PTY and not STDIN/OUT */
46+
bool stdin_disconnected;
4647

4748
bool auto_attach; /* For PTY, attach a terminal emulator automatically */
4849
char *auto_attach_cmd; /* If auto_attach, which command to launch the terminal emulator */
@@ -64,6 +65,18 @@ struct native_pty_status {
6465
K_KERNEL_STACK_MEMBER(rx_stack, CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE);
6566
} async;
6667
#endif /* CONFIG_UART_ASYNC_API */
68+
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
69+
struct {
70+
bool tx_enabled;
71+
bool rx_enabled;
72+
uart_irq_callback_user_data_t callback;
73+
void *cb_data;
74+
/* Instance-specific IRQ emulation thread. */
75+
struct k_thread poll_thread;
76+
/* Stack for IRQ emulation thread */
77+
K_KERNEL_STACK_MEMBER(poll_stack, CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE);
78+
} irq;
79+
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
6780
};
6881

6982
static void np_uart_poll_out(const struct device *dev, unsigned char out_char);
@@ -81,6 +94,22 @@ static int np_uart_rx_enable(const struct device *dev, uint8_t *buf, size_t len,
8194
static int np_uart_rx_disable(const struct device *dev);
8295
#endif /* CONFIG_UART_ASYNC_API */
8396

97+
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
98+
static int np_uart_fifo_fill(const struct device *dev, const uint8_t *tx_data, int size);
99+
static int np_uart_fifo_read(const struct device *dev, uint8_t *rx_data, const int size);
100+
static void np_uart_irq_tx_enable(const struct device *dev);
101+
static void np_uart_irq_tx_disable(const struct device *dev);
102+
static int np_uart_irq_tx_ready(const struct device *dev);
103+
static int np_uart_irq_tx_complete(const struct device *dev);
104+
static void np_uart_irq_rx_enable(const struct device *dev);
105+
static void np_uart_irq_rx_disable(const struct device *dev);
106+
static int np_uart_irq_rx_ready(const struct device *dev);
107+
static int np_uart_irq_is_pending(const struct device *dev);
108+
static int np_uart_irq_update(const struct device *dev);
109+
static void np_uart_irq_callback_set(const struct device *dev, uart_irq_callback_user_data_t cb,
110+
void *cb_data);
111+
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
112+
84113
static DEVICE_API(uart, np_uart_driver_api) = {
85114
.poll_out = np_uart_poll_out,
86115
.poll_in = np_uart_poll_in,
@@ -92,6 +121,20 @@ static DEVICE_API(uart, np_uart_driver_api) = {
92121
.rx_enable = np_uart_rx_enable,
93122
.rx_disable = np_uart_rx_disable,
94123
#endif /* CONFIG_UART_ASYNC_API */
124+
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
125+
.fifo_fill = np_uart_fifo_fill,
126+
.fifo_read = np_uart_fifo_read,
127+
.irq_tx_enable = np_uart_irq_tx_enable,
128+
.irq_tx_disable = np_uart_irq_tx_disable,
129+
.irq_tx_ready = np_uart_irq_tx_ready,
130+
.irq_tx_complete = np_uart_irq_tx_complete,
131+
.irq_rx_enable = np_uart_irq_rx_enable,
132+
.irq_rx_disable = np_uart_irq_rx_disable,
133+
.irq_rx_ready = np_uart_irq_rx_ready,
134+
.irq_is_pending = np_uart_irq_is_pending,
135+
.irq_update = np_uart_irq_update,
136+
.irq_callback_set = np_uart_irq_callback_set,
137+
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
95138
};
96139

97140
#define NATIVE_PTY_INSTANCE(inst) \
@@ -192,61 +235,49 @@ static void np_uart_poll_out(const struct device *dev, unsigned char out_char)
192235
}
193236

194237
/**
195-
* @brief Poll the device for input.
238+
* @brief Poll the device for up to len input characters
196239
*
197240
* @param dev UART device structure.
198241
* @param p_char Pointer to character.
199242
*
200-
* @retval 0 If a character arrived and was stored in p_char
243+
* @retval > 0 If a character arrived and was stored in p_char
244+
* @retval == 0 If a character arrived but len was 0
201245
* @retval -1 If no character was available to read
202246
*/
203-
static int np_uart_stdin_poll_in(const struct device *dev, unsigned char *p_char)
247+
static int np_uart_poll_in_n(const struct device *dev, unsigned char *p_char, int len)
204248
{
205-
int in_f = ((struct native_pty_status *)dev->data)->in_fd;
206-
static bool disconnected;
207-
int rc;
249+
int rc = -1;
250+
struct native_pty_status *data = (struct native_pty_status *)dev->data;
251+
int in_f = data->in_fd;
208252

209-
if (disconnected == true) {
253+
if (data->stdin_disconnected) {
210254
return -1;
211255
}
212256

213-
rc = np_uart_stdin_poll_in_bottom(in_f, p_char, 1);
214-
if (rc == -2) {
215-
disconnected = true;
257+
if (data->on_stdinout) {
258+
rc = np_uart_stdin_poll_in_bottom(in_f, p_char, len);
259+
260+
if (rc == -2) {
261+
data->stdin_disconnected = true;
262+
return -1;
263+
}
264+
} else {
265+
rc = np_uart_pty_poll_in_bottom(in_f, p_char, len);
216266
}
217-
return rc == 1 ? 0 : -1;
267+
268+
return rc;
218269
}
219270

220-
/**
221-
* @brief Poll the device for input.
222-
*
223-
* @param dev UART device structure.
224-
* @param p_char Pointer to character.
225-
*
226-
* @retval 0 If a character arrived and was stored in p_char
227-
* @retval -1 If no character was available to read
228-
*/
229-
static int np_uart_pty_poll_in(const struct device *dev, unsigned char *p_char)
271+
static int np_uart_poll_in(const struct device *dev, unsigned char *p_char)
230272
{
231-
int n = -1;
232-
int in_f = ((struct native_pty_status *)dev->data)->in_fd;
273+
int ret = np_uart_poll_in_n(dev, p_char, 1);
233274

234-
n = nsi_host_read(in_f, p_char, 1);
235-
if (n == -1) {
275+
if (ret == -1) {
236276
return -1;
237277
}
238278
return 0;
239279
}
240280

241-
static int np_uart_poll_in(const struct device *dev, unsigned char *p_char)
242-
{
243-
if (((struct native_pty_status *)dev->data)->on_stdinout) {
244-
return np_uart_stdin_poll_in(dev, p_char);
245-
} else {
246-
return np_uart_pty_poll_in(dev, p_char);
247-
}
248-
}
249-
250281
#ifdef CONFIG_UART_ASYNC_API
251282

252283
static int np_uart_callback_set(const struct device *dev, uart_callback_t callback, void *user_data)
@@ -337,8 +368,7 @@ static void native_pty_uart_async_poll_function(void *arg1, void *arg2, void *ar
337368
ARG_UNUSED(arg3);
338369

339370
while (data->async.rx_len) {
340-
rc = np_uart_stdin_poll_in_bottom(data->in_fd, data->async.rx_buf,
341-
data->async.rx_len);
371+
rc = np_uart_poll_in_n(dev, data->async.rx_buf, data->async.rx_len);
342372
if (rc > 0) {
343373
/* Data received */
344374
evt.type = UART_RX_RDY;
@@ -403,6 +433,179 @@ static int np_uart_rx_disable(const struct device *dev)
403433

404434
#endif /* CONFIG_UART_ASYNC_API */
405435

436+
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
437+
static void np_uart_irq_handler(const struct device *dev)
438+
{
439+
struct native_pty_status *data = dev->data;
440+
441+
if (data->irq.callback) {
442+
data->irq.callback(dev, data->irq.cb_data);
443+
} else {
444+
WARN("No callback!\n");
445+
}
446+
}
447+
448+
/*
449+
* Emulate uart interrupts using a polling thread
450+
*/
451+
static void np_uart_irq_thread(void *arg1, void *arg2, void *arg3)
452+
{
453+
ARG_UNUSED(arg2);
454+
ARG_UNUSED(arg3);
455+
456+
struct device *dev = (struct device *)arg1;
457+
struct native_pty_status *data = dev->data;
458+
459+
while (1) {
460+
if (data->irq.rx_enabled) {
461+
int ret = np_uart_poll_in_n(dev, NULL, 0);
462+
463+
if (ret == 0) {
464+
np_uart_irq_handler(dev);
465+
} else if (ret == -1) {
466+
k_sleep(K_MSEC(1));
467+
} else {
468+
WARN("Poll returned error %d\n", ret);
469+
}
470+
}
471+
if (data->irq.tx_enabled) {
472+
np_uart_irq_handler(dev);
473+
}
474+
if (!data->irq.tx_enabled && !data->irq.rx_enabled) {
475+
break; /* No IRQs enabled, exit the thread */
476+
}
477+
}
478+
}
479+
480+
static void np_uart_irq_thread_start(const struct device *dev)
481+
{
482+
struct native_pty_status *data = dev->data;
483+
484+
/* Create a thread which will wait for data - replacement for IRQ */
485+
k_thread_create(&data->irq.poll_thread, data->irq.poll_stack,
486+
K_KERNEL_STACK_SIZEOF(data->irq.poll_stack),
487+
np_uart_irq_thread,
488+
(void *)dev, NULL, NULL,
489+
K_HIGHEST_THREAD_PRIO, 0, K_NO_WAIT);
490+
}
491+
492+
static void np_uart_irq_thread_stop(const struct device *dev)
493+
{
494+
struct native_pty_status *data = dev->data;
495+
496+
/* Wait for IRQ thread to terminate */
497+
k_thread_join(&data->irq.poll_thread, K_FOREVER);
498+
}
499+
500+
static int np_uart_fifo_fill(const struct device *dev, const uint8_t *tx_data, int size)
501+
{
502+
for (int i = 0; i < size; i++) {
503+
np_uart_poll_out(dev, tx_data[i]);
504+
}
505+
506+
return size;
507+
}
508+
509+
static int np_uart_fifo_read(const struct device *dev, uint8_t *rx_data, const int size)
510+
{
511+
return np_uart_poll_in_n(dev, rx_data, size);
512+
}
513+
514+
static int np_uart_irq_tx_ready(const struct device *dev)
515+
{
516+
struct native_pty_status *data = dev->data;
517+
518+
return data->irq.tx_enabled ? 1 : 0;
519+
}
520+
521+
static int np_uart_irq_tx_complete(const struct device *dev)
522+
{
523+
ARG_UNUSED(dev);
524+
525+
return 1;
526+
}
527+
528+
static void np_uart_irq_tx_enable(const struct device *dev)
529+
{
530+
struct native_pty_status *data = dev->data;
531+
532+
bool start_thread = !data->irq.rx_enabled && !data->irq.tx_enabled;
533+
534+
data->irq.tx_enabled = true;
535+
536+
if (start_thread) {
537+
np_uart_irq_thread_start(dev);
538+
}
539+
}
540+
541+
static void np_uart_irq_tx_disable(const struct device *dev)
542+
{
543+
struct native_pty_status *data = dev->data;
544+
545+
data->irq.tx_enabled = false;
546+
547+
if (!data->irq.rx_enabled && !data->irq.tx_enabled) {
548+
np_uart_irq_thread_stop(dev);
549+
}
550+
}
551+
552+
static void np_uart_irq_rx_enable(const struct device *dev)
553+
{
554+
struct native_pty_status *data = dev->data;
555+
556+
bool start_thread = !data->irq.rx_enabled && !data->irq.tx_enabled;
557+
558+
data->irq.rx_enabled = true;
559+
560+
if (start_thread) {
561+
np_uart_irq_thread_start(dev);
562+
}
563+
}
564+
565+
static void np_uart_irq_rx_disable(const struct device *dev)
566+
{
567+
struct native_pty_status *data = dev->data;
568+
569+
data->irq.rx_enabled = false;
570+
571+
if (!data->irq.rx_enabled && !data->irq.tx_enabled) {
572+
np_uart_irq_thread_stop(dev);
573+
}
574+
}
575+
576+
static int np_uart_irq_rx_ready(const struct device *dev)
577+
{
578+
struct native_pty_status *data = dev->data;
579+
580+
if (data->irq.rx_enabled && np_uart_poll_in_n(dev, NULL, 0) == 0) {
581+
return 1;
582+
}
583+
return 0;
584+
}
585+
586+
static int np_uart_irq_is_pending(const struct device *dev)
587+
{
588+
return np_uart_irq_rx_ready(dev) ||
589+
np_uart_irq_tx_ready(dev);
590+
}
591+
592+
static int np_uart_irq_update(const struct device *dev)
593+
{
594+
ARG_UNUSED(dev);
595+
596+
return 1;
597+
}
598+
599+
static void np_uart_irq_callback_set(const struct device *dev, uart_irq_callback_user_data_t cb,
600+
void *cb_data)
601+
{
602+
struct native_pty_status *data = dev->data;
603+
604+
data->irq.callback = cb;
605+
data->irq.cb_data = cb_data;
606+
}
607+
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
608+
406609

407610
#define NATIVE_PTY_SET_AUTO_ATTACH_CMD(inst, cmd) \
408611
native_pty_status_##inst.auto_attach_cmd = cmd;

0 commit comments

Comments
 (0)