base: move x86 uart driver from nova to base
So it can be reused by base-hw-x86 instead of re-writing it. Fixes #1403
This commit is contained in:
parent
bc827787f4
commit
0b019d0508
|
@ -5,142 +5,30 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2012-2013 Genode Labs GmbH
|
* Copyright (C) 2012-2015 Genode Labs GmbH
|
||||||
*
|
*
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU General Public License version 2.
|
* under the terms of the GNU General Public License version 2.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _SERIAL_H_
|
#pragma once
|
||||||
#define _SERIAL_H_
|
|
||||||
|
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <base/stdint.h>
|
#include <drivers/uart/x86_uart_base.h>
|
||||||
|
|
||||||
|
namespace Genode { class Serial; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read byte from I/O port
|
* Serial output driver for core
|
||||||
*/
|
*/
|
||||||
inline Genode::uint8_t inb(Genode::uint16_t port)
|
class Genode::Serial : public X86_uart_base
|
||||||
{
|
{
|
||||||
Genode::uint8_t res;
|
private:
|
||||||
asm volatile ("inb %%dx, %0" :"=a"(res) :"Nd"(port));
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
enum { IO_PORT = 0x3f8, CLOCK_UNUSED = 0 };
|
||||||
|
|
||||||
/**
|
public:
|
||||||
* Write byte to I/O port
|
|
||||||
*/
|
|
||||||
inline void outb(Genode::uint16_t port, Genode::uint8_t val)
|
|
||||||
{
|
|
||||||
asm volatile ("outb %b0, %w1" : : "a" (val), "Nd" (port));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Serial(unsigned baud_rate)
|
||||||
/**
|
: X86_uart_base(IO_PORT, CLOCK_UNUSED, baud_rate) { }
|
||||||
* Definitions of PC serial ports
|
|
||||||
*/
|
|
||||||
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 */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize serial port
|
|
||||||
*
|
|
||||||
* Based on 'init_serial' of L4ka::Pistachio's 'kdb/platform/pc99/io.cc'
|
|
||||||
*/
|
|
||||||
static void init_comport(Genode::uint16_t port, unsigned baud)
|
|
||||||
{
|
|
||||||
if (!port)
|
|
||||||
return;
|
|
||||||
|
|
||||||
unsigned const ier = port + 1;
|
|
||||||
unsigned const eir = port + 2;
|
|
||||||
unsigned const lcr = port + 3;
|
|
||||||
unsigned const mcr = port + 4;
|
|
||||||
unsigned const lsr = port + 5;
|
|
||||||
unsigned const msr = port + 6;
|
|
||||||
unsigned const dllo = port + 0;
|
|
||||||
unsigned const dlhi = port + 1;
|
|
||||||
|
|
||||||
outb(lcr, 0x80); /* select bank 1 */
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Output character to serial port
|
|
||||||
*/
|
|
||||||
inline void serial_out_char(Genode::uint16_t comport, Genode::uint8_t c)
|
|
||||||
{
|
|
||||||
/* wait until serial port is ready */
|
|
||||||
Genode::uint8_t ready = STATUS_THR_EMPTY;
|
|
||||||
while ((inb(comport + COMPORT_STATUS_OFFSET) & ready) != ready);
|
|
||||||
|
|
||||||
/* output character */
|
|
||||||
outb(comport + COMPORT_DATA_OFFSET, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
namespace Genode {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serial output driver for core
|
|
||||||
*/
|
|
||||||
class Serial
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
uint16_t _comport;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
void put_char(char c)
|
|
||||||
{
|
|
||||||
if (!_comport)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (c == '\n')
|
|
||||||
serial_out_char(_comport, '\r');
|
|
||||||
serial_out_char(_comport, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* XXX: The 'baud_rate' argument is ignored for now.
|
|
||||||
*/
|
|
||||||
Serial(unsigned) : _comport(0x3f8)
|
|
||||||
{
|
|
||||||
init_comport(_comport, 115200);
|
|
||||||
}
|
|
||||||
|
|
||||||
Serial(const char *s) : _comport(0x3f8)
|
|
||||||
{
|
|
||||||
init_comport(_comport, 115200);
|
|
||||||
|
|
||||||
while (*s)
|
|
||||||
put_char(*s++);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* _SERIAL_H_ */
|
|
||||||
|
|
|
@ -6,149 +6,63 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2013 Genode Labs GmbH
|
* Copyright (C) 2009-2015 Genode Labs GmbH
|
||||||
*
|
*
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU General Public License version 2.
|
* under the terms of the GNU General Public License version 2.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Genode includes */
|
#pragma once
|
||||||
#include <base/stdint.h>
|
|
||||||
#include <base/console.h>
|
#include <base/console.h>
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <drivers/uart/x86_uart_base.h>
|
||||||
|
|
||||||
/**
|
namespace Genode { class Core_console; }
|
||||||
* Read byte from I/O port
|
|
||||||
*/
|
class Genode::Core_console : public X86_uart_base, public Console
|
||||||
inline Genode::uint8_t inb(Genode::uint16_t port)
|
|
||||||
{
|
{
|
||||||
Genode::uint8_t res;
|
private:
|
||||||
asm volatile ("inb %%dx, %0" :"=a"(res) :"Nd"(port));
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
addr_t _port()
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Read BDA (Bios Data Area) to obtain I/O ports of COM
|
||||||
|
* interfaces. The page must be mapped by the platform code !
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
enum {
|
||||||
* Write byte to I/O port
|
MAP_ADDR_BDA = 0x1000,
|
||||||
*/
|
|
||||||
inline void outb(Genode::uint16_t port, Genode::uint8_t val)
|
|
||||||
{
|
|
||||||
asm volatile ("outb %b0, %w1" : : "a" (val), "Nd" (port));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
BDA_SERIAL_BASE_COM1 = 0x400,
|
||||||
|
BDA_EQUIPMENT_WORD = 0x410,
|
||||||
|
BDA_EQUIPMENT_SERIAL_COUNT_MASK = 0x7,
|
||||||
|
BDA_EQUIPMENT_SERIAL_COUNT_SHIFT = 9,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
char * map_bda = reinterpret_cast<char *>(MAP_ADDR_BDA);
|
||||||
* Definitions of PC serial ports
|
uint16_t serial_count = *reinterpret_cast<uint16_t *>(map_bda + BDA_EQUIPMENT_WORD);
|
||||||
*/
|
serial_count >>= BDA_EQUIPMENT_SERIAL_COUNT_SHIFT;
|
||||||
enum {
|
serial_count &= BDA_EQUIPMENT_SERIAL_COUNT_MASK;
|
||||||
MAP_ADDR_BDA = 0x1000,
|
|
||||||
|
if (serial_count > 0)
|
||||||
|
return *reinterpret_cast<uint16_t *>(map_bda + BDA_SERIAL_BASE_COM1);
|
||||||
|
|
||||||
BDA_SERIAL_BASE_COM1 = 0x400,
|
return 0;
|
||||||
BDA_EQUIPMENT_WORD = 0x410,
|
}
|
||||||
BDA_EQUIPMENT_SERIAL_COUNT_MASK = 0x7,
|
|
||||||
BDA_EQUIPMENT_SERIAL_COUNT_SHIFT = 9,
|
|
||||||
|
|
||||||
COMPORT_DATA_OFFSET = 0,
|
enum { CLOCK = 0, BAUDRATE = 115200 };
|
||||||
COMPORT_STATUS_OFFSET = 5,
|
|
||||||
|
|
||||||
STATUS_THR_EMPTY = 0x20, /* transmitter hold register empty */
|
void _out_char(char c)
|
||||||
STATUS_DHR_EMPTY = 0x40, /* data hold register empty - data completely sent */
|
{
|
||||||
|
if (c == '\n')
|
||||||
|
put_char('\r');
|
||||||
|
|
||||||
|
put_char(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Core_console() : X86_uart_base(_port(), CLOCK, BAUDRATE) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize serial port
|
|
||||||
*
|
|
||||||
* Based on 'init_serial' of L4ka::Pistachio's 'kdb/platform/pc99/io.cc'
|
|
||||||
*/
|
|
||||||
static void init_comport(Genode::uint16_t port, unsigned baud)
|
|
||||||
{
|
|
||||||
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) >> 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Output character to serial port
|
|
||||||
*/
|
|
||||||
inline void serial_out_char(Genode::uint16_t comport, Genode::uint8_t c)
|
|
||||||
{
|
|
||||||
/* wait until serial port is ready */
|
|
||||||
Genode::uint8_t ready = STATUS_THR_EMPTY;
|
|
||||||
while ((inb(comport + COMPORT_STATUS_OFFSET) & ready) != ready);
|
|
||||||
|
|
||||||
/* output character */
|
|
||||||
outb(comport + COMPORT_DATA_OFFSET, c);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
namespace Genode {
|
|
||||||
|
|
||||||
class Core_console : public Console
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
uint16_t _comport;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
void _out_char(char c)
|
|
||||||
{
|
|
||||||
if (!_comport)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (c == '\n')
|
|
||||||
serial_out_char(_comport, '\r');
|
|
||||||
serial_out_char(_comport, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Core_console() : _comport(0)
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Read BDA (Bios Data Area) to obtain I/O ports of COM
|
|
||||||
* interfaces. The page must be mapped by the platform code !
|
|
||||||
*/
|
|
||||||
char * map_bda = reinterpret_cast<char *>(MAP_ADDR_BDA);
|
|
||||||
uint16_t serial_count = *reinterpret_cast<uint16_t *>(map_bda + BDA_EQUIPMENT_WORD);
|
|
||||||
serial_count >>= BDA_EQUIPMENT_SERIAL_COUNT_SHIFT;
|
|
||||||
serial_count &= BDA_EQUIPMENT_SERIAL_COUNT_MASK;
|
|
||||||
|
|
||||||
if (serial_count > 0)
|
|
||||||
_comport = *reinterpret_cast<uint16_t *>(
|
|
||||||
map_bda + BDA_SERIAL_BASE_COM1);
|
|
||||||
|
|
||||||
init_comport(_comport, 115200);
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
111
repos/base/include/drivers/uart/x86_uart_base.h
Normal file
111
repos/base/include/drivers/uart/x86_uart_base.h
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
/*
|
||||||
|
* \brief Console backend for NOVA
|
||||||
|
* \author Norman Feske
|
||||||
|
* \author Alexander Boettcher
|
||||||
|
* \date 2009-12-28
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2013 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <base/stdint.h>
|
||||||
|
|
||||||
|
namespace Genode { class X86_uart_base; }
|
||||||
|
|
||||||
|
class Genode::X86_uart_base
|
||||||
|
{
|
||||||
|
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:
|
||||||
|
|
||||||
|
X86_uart_base(addr_t const port, unsigned const clock,
|
||||||
|
unsigned const baud_rate)
|
||||||
|
: _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);
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user