mirror of
https://git.rtems.org/rtems-libbsd/
synced 2025-10-14 05:11:15 +08:00
Add poll() and select() support for Termios
This commit is contained in:
@@ -188,6 +188,15 @@ extern "C" {
|
||||
#define RTEMS_BSD_CFGDECL_TELNETD
|
||||
#endif /* RTEMS_BSD_CONFIG_SERVICE_TELNETD */
|
||||
|
||||
/*
|
||||
* Termios
|
||||
*/
|
||||
#if defined(RTEMS_BSD_CONFIG_TERMIOS_KQUEUE_AND_POLL)
|
||||
#define RTEMS_BSD_CFGDECL_TERMIOS_KQUEUE_AND_POLL SYSINIT_REFERENCE(termioskqueuepoll)
|
||||
#else
|
||||
#define RTEMS_BSD_CFGDECL_TERMIOS_KQUEUE_AND_POLL
|
||||
#endif /* RTEMS_BSD_CONFIG_TERMIOS_KQUEUE_AND_POLL */
|
||||
|
||||
/*
|
||||
* Configure the system.
|
||||
*/
|
||||
@@ -230,6 +239,8 @@ extern "C" {
|
||||
RTEMS_BSD_CFGDECL_TELNETD;
|
||||
RTEMS_BSD_CFGDECL_TELNETD_STACK_SIZE;
|
||||
RTEMS_BSD_CFGDECL_FTPD;
|
||||
|
||||
RTEMS_BSD_CFGDECL_TERMIOS_KQUEUE_AND_POLL;
|
||||
#endif /* RTEMS_BSD_CONFIG_INIT */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
283
rtemsbsd/rtems/rtems-kernel-termioskqueuepoll.c
Normal file
283
rtemsbsd/rtems/rtems-kernel-termioskqueuepoll.c
Normal file
@@ -0,0 +1,283 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup rtems_bsd_rtems
|
||||
*
|
||||
* @brief TODO.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 embedded brains GmbH.
|
||||
* All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <machine/rtems-bsd-kernel-space.h>
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/pcpu.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/selinfo.h>
|
||||
|
||||
#include <rtems/termiostypes.h>
|
||||
#include <rtems/irq-extension.h>
|
||||
|
||||
SYSINIT_REFERENCE(irqs);
|
||||
|
||||
typedef struct {
|
||||
rtems_termios_tty *tty;
|
||||
struct selinfo sel;
|
||||
rtems_interrupt_server_request request;
|
||||
} termios_selinfo;
|
||||
|
||||
static bool
|
||||
termios_is_eol(const rtems_termios_tty *tty, char c)
|
||||
{
|
||||
|
||||
return (c == '\n' || c == tty->termios.c_cc[VEOF] ||
|
||||
c == tty->termios.c_cc[VEOL] ||
|
||||
c == tty->termios.c_cc[VEOL2]);
|
||||
}
|
||||
|
||||
static bool
|
||||
termios_can_read(rtems_termios_tty *tty)
|
||||
{
|
||||
rtems_termios_device_context *ctx;
|
||||
rtems_interrupt_lock_context lock_context;
|
||||
unsigned int i;
|
||||
unsigned int size;
|
||||
unsigned int raw_content_size;
|
||||
bool can;
|
||||
|
||||
if (tty->handler.mode == TERMIOS_POLLED) {
|
||||
return (true);
|
||||
}
|
||||
|
||||
if (tty->cindex != tty->ccount) {
|
||||
return (true);
|
||||
}
|
||||
|
||||
ctx = tty->device_context;
|
||||
rtems_termios_device_lock_acquire(ctx, &lock_context);
|
||||
i = tty->rawInBuf.Head;
|
||||
size = tty->rawInBuf.Size;
|
||||
raw_content_size = (tty->rawInBuf.Tail - i) % size;
|
||||
|
||||
if ((tty->termios.c_lflag & ICANON) != 0) {
|
||||
unsigned int todo = raw_content_size;
|
||||
|
||||
/*
|
||||
* FIXME: What to do in case of a raw input buffer overflow?
|
||||
* For now, indicated that we can read. However, this has
|
||||
* problems in case an erase takes place.
|
||||
*/
|
||||
can = raw_content_size == (size - 1);
|
||||
|
||||
while (todo > 0 && !can) {
|
||||
char c;
|
||||
|
||||
i = (i + 1) % size;
|
||||
c = tty->rawInBuf.theBuf[i];
|
||||
can = termios_is_eol(tty, c);
|
||||
--todo;
|
||||
}
|
||||
} else {
|
||||
cc_t vmin = tty->termios.c_cc[VMIN];
|
||||
|
||||
if (vmin == 0) {
|
||||
vmin = 1;
|
||||
}
|
||||
|
||||
can = raw_content_size >= vmin;
|
||||
}
|
||||
|
||||
if (!can) {
|
||||
tty->tty_rcvwakeup = false;
|
||||
}
|
||||
|
||||
rtems_termios_device_lock_release(ctx, &lock_context);
|
||||
return (can);
|
||||
}
|
||||
|
||||
static bool
|
||||
termios_can_write(const rtems_termios_tty *tty)
|
||||
{
|
||||
rtems_termios_device_context *ctx;
|
||||
rtems_interrupt_lock_context lock_context;
|
||||
bool can;
|
||||
|
||||
if (tty->handler.mode == TERMIOS_POLLED) {
|
||||
return (true);
|
||||
}
|
||||
|
||||
ctx = tty->device_context;
|
||||
rtems_termios_device_lock_acquire(ctx, &lock_context);
|
||||
can = ((tty->rawOutBuf.Tail - tty->rawOutBuf.Head - 1) %
|
||||
tty->rawOutBuf.Size) > 0;
|
||||
rtems_termios_device_lock_release(ctx, &lock_context);
|
||||
return (can);
|
||||
}
|
||||
|
||||
static void
|
||||
termios_receive_wakeup(void *arg)
|
||||
{
|
||||
termios_selinfo *ts;
|
||||
rtems_termios_tty *tty;
|
||||
rtems_status_code sc;
|
||||
|
||||
ts = arg;
|
||||
tty = ts->tty;
|
||||
|
||||
sc = rtems_semaphore_obtain(tty->isem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||
BSD_ASSERT(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
selwakeup(&ts->sel);
|
||||
|
||||
sc = rtems_semaphore_release(tty->isem);
|
||||
BSD_ASSERT(sc == RTEMS_SUCCESSFUL);
|
||||
}
|
||||
|
||||
static void
|
||||
termios_transmit_wakeup(void *arg)
|
||||
{
|
||||
termios_selinfo *ts;
|
||||
rtems_termios_tty *tty;
|
||||
rtems_status_code sc;
|
||||
|
||||
ts = arg;
|
||||
tty = ts->tty;
|
||||
|
||||
sc = rtems_semaphore_obtain(tty->osem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||
BSD_ASSERT(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
selwakeup(&ts->sel);
|
||||
|
||||
sc = rtems_semaphore_release(tty->osem);
|
||||
BSD_ASSERT(sc == RTEMS_SUCCESSFUL);
|
||||
}
|
||||
|
||||
static void
|
||||
termios_wakeup(struct termios *term, void *arg)
|
||||
{
|
||||
termios_selinfo *ts = arg;
|
||||
|
||||
rtems_interrupt_server_request_submit(RTEMS_ID_NONE, &ts->request);
|
||||
}
|
||||
|
||||
static struct selinfo *
|
||||
termios_get_selinfo(rtems_termios_tty *tty, struct ttywakeup *wk,
|
||||
rtems_interrupt_handler handler)
|
||||
{
|
||||
termios_selinfo *ts = wk->sw_arg;
|
||||
|
||||
if (ts == NULL) {
|
||||
BSD_ASSERT(wk->sw_pfn == NULL);
|
||||
ts = malloc(sizeof(*ts), M_TEMP, M_WAITOK | M_ZERO);
|
||||
ts->tty = tty;
|
||||
rtems_interrupt_server_request_initialize(&ts->request,
|
||||
handler, ts);
|
||||
wk->sw_arg = ts;
|
||||
wk->sw_pfn = termios_wakeup;
|
||||
} else {
|
||||
BSD_ASSERT(wk->sw_pfn == termios_wakeup);
|
||||
}
|
||||
|
||||
return (&ts->sel);
|
||||
}
|
||||
|
||||
int
|
||||
rtems_termios_kqfilter(rtems_libio_t *iop, struct knote *kn)
|
||||
{
|
||||
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
int
|
||||
rtems_termios_poll(rtems_libio_t *iop, int events)
|
||||
{
|
||||
struct thread *td = rtems_bsd_get_curthread_or_wait_forever();
|
||||
struct selinfo *sel;
|
||||
rtems_termios_tty *tty;
|
||||
rtems_status_code sc;
|
||||
int revents;
|
||||
|
||||
revents = 0;
|
||||
tty = iop->data1;
|
||||
|
||||
if ((events & (POLLIN | POLLRDNORM)) != 0) {
|
||||
sel = termios_get_selinfo(tty, &tty->tty_rcv,
|
||||
termios_receive_wakeup);
|
||||
|
||||
sc = rtems_semaphore_obtain(tty->isem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||
BSD_ASSERT(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
if (termios_can_read(tty)) {
|
||||
revents |= events & (POLLIN | POLLRDNORM);
|
||||
} else {
|
||||
selrecord(td, sel);
|
||||
}
|
||||
|
||||
sc = rtems_semaphore_release(tty->isem);
|
||||
BSD_ASSERT(sc == RTEMS_SUCCESSFUL);
|
||||
}
|
||||
|
||||
if ((events & (POLLOUT | POLLWRNORM)) != 0) {
|
||||
sel = termios_get_selinfo(tty, &tty->tty_snd,
|
||||
termios_transmit_wakeup);
|
||||
|
||||
sc = rtems_semaphore_obtain(tty->osem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||
BSD_ASSERT(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
if (termios_can_write(tty)) {
|
||||
revents |= events & (POLLOUT | POLLWRNORM);
|
||||
} else {
|
||||
selrecord(td, sel);
|
||||
}
|
||||
|
||||
sc = rtems_semaphore_release(tty->osem);
|
||||
BSD_ASSERT(sc == RTEMS_SUCCESSFUL);
|
||||
}
|
||||
|
||||
return (revents);
|
||||
}
|
||||
|
||||
static void
|
||||
termioskqueuepoll_sysinit(void)
|
||||
{
|
||||
|
||||
/* Do nothing */
|
||||
}
|
||||
|
||||
SYSINIT(termioskqueuepoll, SI_SUB_TUNABLES, SI_ORDER_ANY,
|
||||
termioskqueuepoll_sysinit, NULL);
|
Reference in New Issue
Block a user