/* * \brief UART driver for the x86 PC * \author Norman Feske * \author Alexander Boettcher * \date 2009-12-28 */ /* * Copyright (C) 2009-2017 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU Affero General Public License version 3. */ #ifndef _INCLUDE__DRIVERS__UART__X86_PC_H_ #define _INCLUDE__DRIVERS__UART__X86_PC_H_ /* Genode includes */ #include #include namespace Genode { class X86_uart; } class Genode::X86_uart { private: uint16_t const _port; unsigned const _baud_rate; enum { COMPORT_DATA_OFFSET = 0, COMPORT_STATUS_OFFSET = 5, STATUS_THR_EMPTY = 0x20, /* transmitter hold register empty */ STATUS_DHR_EMPTY = 0x40, /* data hold register empty - data completely sent */ }; /** * Read byte from I/O port */ uint8_t _inb(uint16_t port) { uint8_t res; asm volatile ("inb %%dx, %0" :"=a"(res) :"Nd"(port)); return res; } /** * Write byte to I/O port */ void _outb(uint16_t port, uint8_t val) { asm volatile ("outb %b0, %w1" : : "a" (val), "Nd" (port)); } public: X86_uart(uint16_t const port, unsigned /* clock */, unsigned const baud_rate) : _port(port), _baud_rate(baud_rate) { init(); } void init() { /** * Initialize serial port * * Based on 'init_serial' of L4ka::Pistachio's 'kdb/platform/pc99/io.cc' */ if (!_port) return; uint16_t const IER = (uint16_t)(_port + 1), EIR = (uint16_t)(_port + 2), LCR = (uint16_t)(_port + 3), MCR = (uint16_t)(_port + 4), LSR = (uint16_t)(_port + 5), MSR = (uint16_t)(_port + 6), DLLO = (uint16_t)(_port + 0), DLHI = (uint16_t)(_port + 1); _outb(LCR, 0x80); /* select bank 1 */ for (int i = 10000000; i; --i) memory_barrier(); _outb(DLLO, (uint8_t)((115200/_baud_rate) >> 0)); _outb(DLHI, (uint8_t)((115200/_baud_rate) >> 8)); _outb(LCR, 0x03); /* set 8,N,1 */ _outb(IER, 0x00); /* disable interrupts */ _outb(EIR, 0x07); /* enable FIFOs */ _outb(MCR, 0x0b); /* force data terminal ready */ _outb(IER, 0x01); /* enable RX interrupts */ _inb(IER); _inb(EIR); _inb(LCR); _inb(MCR); _inb(LSR); _inb(MSR); } void put_char(char const c) { if (!_port) return; /* wait until serial port is ready */ uint8_t ready = STATUS_THR_EMPTY; while ((_inb((uint16_t)(_port + COMPORT_STATUS_OFFSET)) & ready) != ready); /* output character */ _outb(_port + COMPORT_DATA_OFFSET, c); } }; #endif /* _INCLUDE__DRIVERS__UART__X86_PC_H_ */