uart_drv: Mechanism for detecting terminal size

This commit is contained in:
Norman Feske 2013-02-20 22:06:49 +01:00
parent 79d5f9c565
commit 002ea7cfc4
3 changed files with 81 additions and 10 deletions

View File

@ -15,8 +15,12 @@ via Genode's config mechanism.
assumed to be used by the kernel and, therefore, left untouched.
! <config>
! <policy label="test-uart1" uart="1" />
! <policy label="test-uart1" uart="1" detect_size="yes" />
! <policy label="test-uart2" uart="2" />
! <policy label="test-uartx" uart="1" />
! </config>
If the 'detect_size' attribute is set to "yes", the UART driver will
try to detect the terminal size of the connected remote terminal using
a protocol of escape sequences. If not specified, the UART driver will
report a size of (0, 0) to the terminal-session client.

View File

@ -84,7 +84,7 @@ int main(int argc, char **argv)
if (!uart) {
uart = new (env()->heap())
I8250(io_port_base(index), irq_number(index),
baudrate, callback);
baudrate, callback);
/* update 'created' table */
created[index] = uart;

View File

@ -60,17 +60,79 @@ namespace Uart {
Uart::Driver_factory &_driver_factory;
Uart::Driver &_driver;
Size _size;
unsigned char _poll_char()
{
while (!_driver.char_avail());
return _driver.get_char();
}
void _put_string(char const *s)
{
for (; *s; s++)
_driver.put_char(*s);
}
/**
* Read ASCII number from UART
*
* \return character that terminates the sequence of digits
*/
unsigned char _read_number(unsigned &result)
{
result = 0;
for (;;) {
unsigned char c = _poll_char();
if (!is_digit(c))
return c;
result = result*10 + digit(c);
}
}
/**
* Try to detect the size of the terminal
*/
Size _detect_size()
{
/* set cursor position to the max */
_put_string("\033[1;199r\033[199;199H");
/* flush incoming characters */
for (; _driver.char_avail(); _driver.get_char());
/* request cursor coordinates */
_put_string("\033[6n");
unsigned width = 0, height = 0;
if (_poll_char() == 27
&& _poll_char() == '['
&& _read_number(height) == ';'
&& _read_number(width) == 'R') {
PINF("detected terminal size %dx%d", width, height);
return Size(width, height);
}
return Size(0, 0);
}
public:
/**
* Constructor
*/
Session_component(Uart::Driver_factory &driver_factory,
unsigned index, unsigned baudrate)
unsigned index, unsigned baudrate, bool detect_size)
:
_io_buffer(Genode::env()->ram_session(), IO_BUFFER_SIZE),
_driver_factory(driver_factory),
_driver(*_driver_factory.create(index, baudrate, _char_avail_callback))
_driver(*_driver_factory.create(index, baudrate, _char_avail_callback)),
_size(detect_size ? _detect_size() : Size(0, 0))
{ }
@ -88,7 +150,7 @@ namespace Uart {
** Terminal session interface **
********************************/
Size size() { return Size(0, 0); }
Size size() { return _size; }
bool avail() { return _driver.char_avail(); }
@ -158,16 +220,21 @@ namespace Uart {
try {
Session_policy policy(args);
unsigned uart_index = 0;
policy.attribute("uart").value(&uart_index);
unsigned index = 0;
policy.attribute("uart").value(&index);
unsigned uart_baudrate = 0;
unsigned baudrate = 0;
try {
policy.attribute("baudrate").value(&uart_baudrate);
policy.attribute("baudrate").value(&baudrate);
} catch (Xml_node::Nonexistent_attribute) { }
bool detect_size = false;
try {
detect_size = policy.attribute("detect_size").has_value("yes");
} catch (Xml_node::Nonexistent_attribute) { }
return new (md_alloc())
Session_component(_driver_factory, uart_index, uart_baudrate);
Session_component(_driver_factory, index, baudrate, detect_size);
} catch (Xml_node::Nonexistent_attribute) {
PERR("Missing \"uart\" attribute in policy definition");