genode/os/src/drivers/uart/i8250/i8250.h
Norman Feske 5b4edeb031 Introduce 'Uart::Session' interface
The new 'Uart::Session' interface is an extension of the
'Terminal::Session' interface that allows for configuring UART-specific
parameters, i.e., the baud rate.
2012-11-07 13:43:09 +01:00

143 lines
2.8 KiB
C++

/*
* \brief i8250 UART driver
* \author Norman Feske
* \date 2011-09-12
*/
/*
* Copyright (C) 2011-2012 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _I8250_H_
#define _I8250_H_
/* Genode includes */
#include <base/env.h>
#include <base/lock.h>
#include <base/printf.h>
#include <os/irq_activation.h>
#include <io_port_session/connection.h>
/* local includes */
#include "uart_driver.h"
class I8250 : public Uart::Driver, public Genode::Irq_handler
{
private:
unsigned _port_base;
Genode::Io_port_connection _io_port;
/**
* Register offsets relative to '_port_base'
*/
enum Reg {
TRB = 0, /* transmit/receive buffer */
IER = 1,
EIR = 2,
LCR = 3,
MCR = 4,
LSR = 5, /* line status register */
MSR = 6,
DLLO = 0,
DLHI = 1,
};
/**
* Read byte from i8250 register
*/
template <Reg REG>
char _inb() { return _io_port.inb(_port_base + REG); }
/**
* Write byte to i8250 register
*/
template <Reg REG>
void _outb(char value) { _io_port.outb(_port_base + REG, value); }
/**
* Initialize UART
*
* Based on 'init_serial' of L4ka::Pistachio's 'kdb/platform/pc99/io.cc'
*/
void _init_comport(unsigned baud)
{
_outb<LCR>(0x80); /* select bank 1 */
for (volatile int i = 10000000; i--; );
_outb<DLLO>((115200/baud) >> 0);
_outb<DLHI>((115200/baud) >> 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>();
}
Uart::Char_avail_callback &_char_avail_callback;
enum { IRQ_STACK_SIZE = 4096 };
Genode::Irq_activation _irq_activation;
public:
/**
* Constructor
*/
I8250(unsigned port_base, int irq_number, unsigned baud,
Uart::Char_avail_callback &callback)
:
_port_base(port_base),
_io_port(port_base, 0xf),
_char_avail_callback(callback),
_irq_activation(irq_number, *this, IRQ_STACK_SIZE)
{
_init_comport(baud);
}
/***************************
** IRQ handler interface **
***************************/
void handle_irq(int irq_number)
{
/* inform client about the availability of data */
_char_avail_callback();
}
/***************************
** UART driver interface **
***************************/
void put_char(char c)
{
/* wait until serial port is ready */
while (!(_inb<LSR>() & 0x60));
/* output character */
_outb<TRB>(c);
}
bool char_avail()
{
return _inb<LSR>() & 1;
}
char get_char()
{
return _inb<TRB>();
}
};
#endif /* _I8250_H_ */