Skip to content

Commit 80d0d2c

Browse files
committed
serial: uart_native_pty: ASYNC TX support
Add support for transmitting using the asynchronous API. The asynchronous portion is simulated through the system workqueue. Signed-off-by: Jordan Yates <[email protected]>
1 parent 6e29a33 commit 80d0d2c

File tree

2 files changed

+91
-0
lines changed

2 files changed

+91
-0
lines changed

drivers/serial/Kconfig.native_pty

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ config UART_NATIVE_PTY
66
default y
77
depends on (DT_HAS_ZEPHYR_NATIVE_PTY_UART_ENABLED || DT_HAS_ZEPHYR_NATIVE_POSIX_UART_ENABLED)
88
select SERIAL_HAS_DRIVER
9+
select SERIAL_SUPPORT_ASYNC
910
help
1011
This enables a PTY based UART driver for the POSIX ARCH with up to 2 UARTs.
1112
For the first UART port, the driver can be configured

drivers/serial/uart_native_pty.c

+90
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,38 @@ struct native_pty_status {
4848
char *auto_attach_cmd; /* If auto_attach, which command to launch the terminal emulator */
4949
bool wait_pts; /* Hold writes to the uart/pts until a client is connected/ready */
5050
bool cmd_request_stdinout; /* User requested to connect this UART to the stdin/out */
51+
#ifdef CONFIG_UART_ASYNC_API
52+
struct {
53+
const struct device *dev;
54+
struct k_work_delayable tx_done;
55+
uart_callback_t user_callback;
56+
void *user_data;
57+
const uint8_t *tx_buf;
58+
size_t tx_len;
59+
} async;
60+
#endif /* CONFIG_UART_ASYNC_API */
5161
};
5262

5363
static void np_uart_poll_out(const struct device *dev, unsigned char out_char);
5464
static int np_uart_poll_in(const struct device *dev, unsigned char *p_char);
5565
static int np_uart_init(const struct device *dev);
5666

67+
#ifdef CONFIG_UART_ASYNC_API
68+
static void np_uart_tx_done_work(struct k_work *work);
69+
static int np_uart_callback_set(const struct device *dev, uart_callback_t callback,
70+
void *user_data);
71+
static int np_uart_tx(const struct device *dev, const uint8_t *buf, size_t len, int32_t timeout);
72+
static int np_uart_tx_abort(const struct device *dev);
73+
#endif /* CONFIG_UART_ASYNC_API */
74+
5775
static DEVICE_API(uart, np_uart_driver_api) = {
5876
.poll_out = np_uart_poll_out,
5977
.poll_in = np_uart_poll_in,
78+
#ifdef CONFIG_UART_ASYNC_API
79+
.callback_set = np_uart_callback_set,
80+
.tx = np_uart_tx,
81+
.tx_abort = np_uart_tx_abort,
82+
#endif /* CONFIG_UART_ASYNC_API */
6083
};
6184

6285
#define NATIVE_PTY_INSTANCE(inst) \
@@ -119,6 +142,11 @@ static int np_uart_init(const struct device *dev)
119142
d->out_fd = tty_fn;
120143
}
121144

145+
#ifdef CONFIG_UART_ASYNC_API
146+
k_work_init_delayable(&d->async.tx_done, np_uart_tx_done_work);
147+
d->async.dev = dev;
148+
#endif
149+
122150
return 0;
123151
}
124152

@@ -207,6 +235,68 @@ static int np_uart_poll_in(const struct device *dev, unsigned char *p_char)
207235
}
208236
}
209237

238+
#ifdef CONFIG_UART_ASYNC_API
239+
240+
static int np_uart_callback_set(const struct device *dev, uart_callback_t callback, void *user_data)
241+
{
242+
struct native_pty_status *data = dev->data;
243+
244+
data->async.user_callback = callback;
245+
data->async.user_data = user_data;
246+
247+
return 0;
248+
}
249+
250+
static void np_uart_tx_done_work(struct k_work *work)
251+
{
252+
struct k_work_delayable *dwork = k_work_delayable_from_work(work);
253+
struct native_pty_status *data =
254+
CONTAINER_OF(dwork, struct native_pty_status, async.tx_done);
255+
struct uart_event evt;
256+
unsigned int key = irq_lock();
257+
258+
evt.type = UART_TX_DONE;
259+
evt.data.tx.buf = data->async.tx_buf;
260+
evt.data.tx.len = data->async.tx_len;
261+
262+
(void)nsi_host_write(data->out_fd, evt.data.tx.buf, evt.data.tx.len);
263+
264+
data->async.tx_buf = NULL;
265+
266+
if (data->async.user_callback) {
267+
data->async.user_callback(data->async.dev, &evt, data->async.user_data);
268+
}
269+
irq_unlock(key);
270+
}
271+
272+
static int np_uart_tx(const struct device *dev, const uint8_t *buf, size_t len, int32_t timeout)
273+
{
274+
struct native_pty_status *data = dev->data;
275+
276+
if (data->async.tx_buf) {
277+
/* Port is busy */
278+
return -EBUSY;
279+
}
280+
data->async.tx_buf = buf;
281+
data->async.tx_len = len;
282+
283+
/* Run the callback on the next tick to give the caller time to use the return value */
284+
k_work_reschedule(&data->async.tx_done, K_TICKS(1));
285+
return 0;
286+
}
287+
288+
static int np_uart_tx_abort(const struct device *dev)
289+
{
290+
struct native_pty_status *data = dev->data;
291+
struct k_work_sync sync;
292+
293+
/* Cancel the callback */
294+
return k_work_cancel_delayable_sync(&data->async.tx_done, &sync) ? 0 : -EFAULT;
295+
}
296+
297+
#endif /* CONFIG_UART_ASYNC_API */
298+
299+
210300
#define NATIVE_PTY_SET_AUTO_ATTACH_CMD(inst, cmd) \
211301
native_pty_status_##inst.auto_attach_cmd = cmd;
212302
#define NATIVE_PTY_SET_AUTO_ATTACH(inst, value) \

0 commit comments

Comments
 (0)