genode/repos/os/src/drivers/input/spec/ps2/pl050/pl050.h

149 lines
3.1 KiB
C++

/*
* \brief PL050 PS/2 controller driver
* \author Norman Feske
* \date 2010-03-23
*/
/*
* Copyright (C) 2010-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 _DRIVERS__INPUT__SPEC__PS2__PL050__PL050_H_
#define _DRIVERS__INPUT__SPEC__PS2__PL050__PL050_H_
/* Genode includes */
#include <os/ring_buffer.h>
#include <base/attached_dataspace.h>
#include <io_mem_session/client.h>
/* local includes */
#include "serial_interface.h"
class Pl050
{
/*
* Device definitions
*/
enum {
/**
* Register offsets (in 32-bit words)
*/
PL050_REG_CONTROL = 0, /* control */
PL050_REG_STATUS = 1, /* status */
PL050_REG_DATA = 2, /* data */
PL050_REG_IIR = 4, /* irq control */
/**
* Bit definitions of control register
*/
PL050_CONTROL_ENABLE = (1 << 2),
PL050_CONTROL_RX_IRQ = (1 << 4),
/**
* Bit definitions of status register
*/
PL050_STATUS_RX_FULL = (1 << 4),
PL050_STATUS_TX_EMPTY = (1 << 6),
/**
* Bit definitions of interrupt control register
*/
PL050_IIR_RX_INTR = (1 << 0),
};
class _Channel : public Serial_interface,
private Genode::Ring_buffer<unsigned char, 256>
{
private:
/*
* Noncopyable
*/
_Channel(_Channel const &);
_Channel &operator = (_Channel const &);
Genode::Mutex _mutex { };
Genode::Attached_dataspace _io_mem_ds;
volatile Genode::uint32_t * _reg_base;
/**
* Return true if input is available
*/
bool _input_pending() {
return _reg_base[PL050_REG_IIR] & PL050_IIR_RX_INTR; }
public:
_Channel(Genode::Env & env,
Genode::Io_mem_dataspace_capability cap)
:
_io_mem_ds(env.rm(), cap),
_reg_base(_io_mem_ds.local_addr<Genode::uint32_t>())
{ }
/**
* Read input or wait busily until input becomes available
*/
unsigned char read() override
{
Genode::Mutex::Guard guard(_mutex);
while (empty())
if (_input_pending())
add(_reg_base[PL050_REG_DATA]);
return get();
}
void write(unsigned char value) override
{
while (!(_reg_base[PL050_REG_STATUS] & PL050_STATUS_TX_EMPTY));
_reg_base[PL050_REG_DATA] = value;
}
bool data_read_ready() override
{
return !empty() || _input_pending();
}
void enable_irq() override
{
_reg_base[PL050_REG_CONTROL] = PL050_CONTROL_RX_IRQ | PL050_CONTROL_ENABLE;
}
};
private:
_Channel _kbd;
_Channel _aux;
public:
Pl050(Genode::Env & env,
Genode::Io_mem_dataspace_capability keyb_cap,
Genode::Io_mem_dataspace_capability mouse_cap) :
_kbd(env, keyb_cap),
_aux(env, mouse_cap)
{
_kbd.enable_irq();
_aux.enable_irq();
}
/**
* Request serial keyboard interface
*/
Serial_interface &kbd_interface() { return _kbd; }
/**
* Request serial mouse interface
*/
Serial_interface &aux_interface() { return _aux; }
};
#endif /* _DRIVERS__INPUT__SPEC__PS2__PL050__PL050_H_ */