genode/ports/src/noux/terminal_io_channel.h

139 lines
3.3 KiB
C
Raw Normal View History

2011-12-22 16:19:25 +01:00
/*
* \brief I/O channel targeting Genode's terminal interface
* \author Norman Feske
* \date 2011-10-21
*/
/*
2012-01-03 15:35:05 +01:00
* Copyright (C) 2011-2012 Genode Labs GmbH
2011-12-22 16:19:25 +01:00
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _NOUX__TERMINAL_IO_CHANNEL_H_
#define _NOUX__TERMINAL_IO_CHANNEL_H_
/* Genode includes */
#include <util/string.h>
#include <base/printf.h>
#include <terminal_session/connection.h>
/* Noux includes */
#include <io_channel.h>
#include <noux_session/sysio.h>
namespace Noux {
struct Terminal_io_channel : Io_channel, Signal_dispatcher
{
Terminal::Session &terminal;
Genode::Signal_receiver &sig_rec;
2011-12-22 16:19:25 +01:00
enum Type { STDIN, STDOUT, STDERR } type;
Terminal_io_channel(Terminal::Session &terminal, Type type,
Genode::Signal_receiver &sig_rec)
: terminal(terminal), sig_rec(sig_rec), type(type)
2011-12-22 16:19:25 +01:00
{
/*
* Enable wake up STDIN channel on the presence of new input
*
* By registering our I/O channel as signal handler, the Noux
* main loop will be unblocked on the arrival of new input.
* It will check if the received signal belongs to an I/O channel
* and invokes the 'handle_signal' function of the I/O channel.
*
* This gives us the opportunity to handle the unblocking of
* blocking system calls such as 'select'.
*/
if (type == STDIN) {
terminal.read_avail_sigh(sig_rec.manage(this));
}
}
~Terminal_io_channel() { sig_rec.dissolve(this); }
bool write(Sysio *sysio, size_t &count)
2011-12-22 16:19:25 +01:00
{
terminal.write(sysio->write_in.chunk, sysio->write_in.count);
count = sysio->write_in.count;
2011-12-22 16:19:25 +01:00
return true;
}
bool read(Sysio *sysio)
{
if (type != STDIN) {
PERR("attempt to read from terminal output channel");
return false;
}
Genode::size_t const max_count =
Genode::min(sysio->read_in.count,
sizeof(sysio->read_out.chunk));
sysio->read_out.count =
terminal.read(sysio->read_out.chunk, max_count);
2011-12-22 16:19:25 +01:00
return true;
}
bool fstat(Sysio *sysio)
{
/*
* Supply stat values such that libc is happy. I.e., the libc
* is checking for the file descriptor 1 being a character
* device.
*/
sysio->fstat_out.st.mode = Sysio::STAT_MODE_CHARDEV;
return true;
}
bool check_unblock(bool rd, bool wr, bool ex) const
{
/* never block for writing */
if (wr) return true;
2011-12-22 16:19:25 +01:00
/*
* Unblock I/O channel if the terminal has new user input. Channels
* otther than STDIN will never unblock.
*/
return (rd && (type == STDIN) && terminal.avail());
}
bool ioctl(Sysio *sysio)
{
switch (sysio->ioctl_in.request) {
case Sysio::Ioctl_in::OP_TIOCGWINSZ:
{
Terminal::Session::Size size = terminal.size();
sysio->ioctl_out.tiocgwinsz.rows = size.lines();
sysio->ioctl_out.tiocgwinsz.columns = size.columns();
PDBG("OP_TIOCGWINSZ requested");
return true;
}
default:
PDBG("invalid ioctl request %d", sysio->ioctl_in.request);
return false;
};
}
/*********************************
** Signal_dispatcher interface **
*********************************/
/**
* Called by Noux main loop on the occurrence of new STDIN input
*/
void dispatch()
{
Io_channel::invoke_all_notifiers();
}
};
}
#endif /* _NOUX__TERMINAL_IO_CHANNEL_H_ */