2015-07-09 09:03:11 +00:00
|
|
|
/*
|
2017-04-28 13:27:26 +00:00
|
|
|
* \brief UART driver for the x86 PC
|
2015-07-09 09:03:11 +00:00
|
|
|
* \author Norman Feske
|
|
|
|
* \author Alexander Boettcher
|
|
|
|
* \date 2009-12-28
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2017-02-20 12:23:52 +00:00
|
|
|
* Copyright (C) 2009-2017 Genode Labs GmbH
|
2015-07-09 09:03:11 +00:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
2017-02-20 12:23:52 +00:00
|
|
|
* under the terms of the GNU Affero General Public License version 3.
|
2015-07-09 09:03:11 +00:00
|
|
|
*/
|
|
|
|
|
2017-04-28 13:27:26 +00:00
|
|
|
#ifndef _INCLUDE__DRIVERS__UART__X86_PC_H_
|
|
|
|
#define _INCLUDE__DRIVERS__UART__X86_PC_H_
|
2015-07-09 09:03:11 +00:00
|
|
|
|
|
|
|
/* Genode includes */
|
|
|
|
#include <base/stdint.h>
|
|
|
|
|
2017-04-28 13:27:26 +00:00
|
|
|
namespace Genode { class X86_uart; }
|
2015-07-09 09:03:11 +00:00
|
|
|
|
2017-04-28 13:27:26 +00:00
|
|
|
class Genode::X86_uart
|
2015-07-09 09:03:11 +00:00
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
|
|
|
uint16_t _port;
|
|
|
|
|
|
|
|
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:
|
|
|
|
|
2017-04-28 13:27:26 +00:00
|
|
|
X86_uart(addr_t const port, unsigned const clock,
|
|
|
|
unsigned const baud_rate)
|
2015-07-09 09:03:11 +00:00
|
|
|
: _port(port)
|
|
|
|
{
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize serial port
|
|
|
|
*
|
|
|
|
* Based on 'init_serial' of L4ka::Pistachio's 'kdb/platform/pc99/io.cc'
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (!port)
|
|
|
|
return;
|
|
|
|
|
|
|
|
const unsigned
|
|
|
|
IER = port + 1,
|
|
|
|
EIR = port + 2,
|
|
|
|
LCR = port + 3,
|
|
|
|
MCR = port + 4,
|
|
|
|
LSR = port + 5,
|
|
|
|
MSR = port + 6,
|
|
|
|
DLLO = port + 0,
|
|
|
|
DLHI = port + 1;
|
|
|
|
|
|
|
|
_outb(LCR, 0x80); /* select bank 1 */
|
|
|
|
for (volatile int i = 10000000; i--; );
|
|
|
|
_outb(DLLO, (115200/baud_rate) >> 0);
|
|
|
|
_outb(DLHI, (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 */
|
|
|
|
Genode::uint8_t ready = STATUS_THR_EMPTY;
|
|
|
|
while ((_inb(_port + COMPORT_STATUS_OFFSET) & ready) != ready);
|
|
|
|
|
|
|
|
/* output character */
|
|
|
|
_outb(_port + COMPORT_DATA_OFFSET, c);
|
|
|
|
}
|
|
|
|
};
|
2015-09-03 12:55:05 +00:00
|
|
|
|
2017-04-28 13:27:26 +00:00
|
|
|
#endif /* _INCLUDE__DRIVERS__UART__X86_PC_H_ */
|