From 002ea7cfc4b936aa8a6334cd1397df5865589b91 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Wed, 20 Feb 2013 22:06:49 +0100 Subject: [PATCH] uart_drv: Mechanism for detecting terminal size --- os/src/drivers/uart/README | 6 +- os/src/drivers/uart/i8250/main.cc | 2 +- os/src/drivers/uart/uart_component.h | 83 +++++++++++++++++++++++++--- 3 files changed, 81 insertions(+), 10 deletions(-) diff --git a/os/src/drivers/uart/README b/os/src/drivers/uart/README index b04c20fb2..64178dea8 100644 --- a/os/src/drivers/uart/README +++ b/os/src/drivers/uart/README @@ -15,8 +15,12 @@ via Genode's config mechanism. assumed to be used by the kernel and, therefore, left untouched. ! - ! + ! ! ! ! + 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. diff --git a/os/src/drivers/uart/i8250/main.cc b/os/src/drivers/uart/i8250/main.cc index 03dd6660a..7f87873b0 100644 --- a/os/src/drivers/uart/i8250/main.cc +++ b/os/src/drivers/uart/i8250/main.cc @@ -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; diff --git a/os/src/drivers/uart/uart_component.h b/os/src/drivers/uart/uart_component.h index d073989db..38be48075 100644 --- a/os/src/drivers/uart/uart_component.h +++ b/os/src/drivers/uart/uart_component.h @@ -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");