mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-21 17:42:40 +00:00
exynos_fb: use new base APIs
In addition to that we now busy wait, i.e. poll, for interrupts instead of using the IRQ session. That is fine because interrupts were only used while configuring the HDMI over I2C and are not used while normal operation. Issue #1987.
This commit is contained in:
parent
834e47d2cf
commit
ce3170f3f7
@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Genode Labs GmbH
|
||||
* Copyright (C) 2013-2017 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.
|
||||
@ -34,35 +34,11 @@ class Timer_delayer : public Mmio::Delayer, public Timer::Connection
|
||||
** Delayer **
|
||||
*************/
|
||||
|
||||
Timer_delayer(Genode::Env &env) : Timer::Connection(env) { }
|
||||
|
||||
void usleep(unsigned us) { Timer::Connection::usleep(us); }
|
||||
};
|
||||
|
||||
/**
|
||||
* Singleton delayer for MMIO polling
|
||||
*/
|
||||
static Mmio::Delayer * delayer()
|
||||
{
|
||||
static Timer_delayer s;
|
||||
return &s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Singleton regulator for HDMI clocks
|
||||
*/
|
||||
static Regulator::Connection * hdmi_clock()
|
||||
{
|
||||
static Regulator::Connection s(Regulator::CLK_HDMI);
|
||||
return &s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Singleton regulator for HDMI clocks
|
||||
*/
|
||||
static Regulator::Connection * hdmi_power()
|
||||
{
|
||||
static Regulator::Connection s(Regulator::PWR_HDMI);
|
||||
return &s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends and receives data via I2C protocol as master or slave
|
||||
@ -113,18 +89,22 @@ class I2c_interface : public Attached_mmio
|
||||
TX_DELAY_US = 1,
|
||||
};
|
||||
|
||||
Irq_connection _irq;
|
||||
Genode::Signal_receiver _irq_rec;
|
||||
Genode::Signal_context _irq_ctx;
|
||||
Irq_connection _irq;
|
||||
|
||||
Mmio::Delayer &_delayer;
|
||||
|
||||
/**
|
||||
* Wait until the IRQ signal was received
|
||||
*/
|
||||
void _wait_for_irq()
|
||||
{
|
||||
_irq_rec.wait_for_signal();
|
||||
|
||||
_irq.ack_irq();
|
||||
/*
|
||||
* Instead of using the signal from the IRQ session we
|
||||
* busy wait and poll at max 2048 times.
|
||||
*/
|
||||
if (wait_for<Con::Irq_pending>(1, _delayer, 2048, 500)) {
|
||||
_irq.ack_irq();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -156,7 +136,7 @@ class I2c_interface : public Attached_mmio
|
||||
Start_msg::access_t start = 0;
|
||||
Start_msg::Addr::set(start, slave);
|
||||
Start_msg::Rx::set(start, !tx);
|
||||
if (!wait_for<Stat::Busy>(0, *delayer())) {
|
||||
if (!wait_for<Stat::Busy>(0, _delayer)) {
|
||||
error("I2C to busy to do transfer");
|
||||
return -1;
|
||||
}
|
||||
@ -172,7 +152,7 @@ class I2c_interface : public Attached_mmio
|
||||
Stat::Mode::set(stat, tx ? MASTER_TX : MASTER_RX);
|
||||
write<Stat>(stat);
|
||||
write<Ds>(start);
|
||||
delayer()->usleep(TX_DELAY_US);
|
||||
_delayer.usleep(TX_DELAY_US);
|
||||
|
||||
/* end start-op transfer */
|
||||
write<Con>(con);
|
||||
@ -190,7 +170,7 @@ class I2c_interface : public Attached_mmio
|
||||
{
|
||||
for (unsigned i = 0; i < 3; i++) {
|
||||
if (read<Con::Irq_pending>() && !read<Stat::Last_bit>()) return 1;
|
||||
delayer()->usleep(TX_DELAY_US);
|
||||
_delayer.usleep(TX_DELAY_US);
|
||||
}
|
||||
error("I2C ack not received");
|
||||
return 0;
|
||||
@ -217,9 +197,11 @@ class I2c_interface : public Attached_mmio
|
||||
* \param base physical MMIO base
|
||||
* \param irq interrupt name
|
||||
*/
|
||||
I2c_interface(addr_t base, unsigned irq)
|
||||
I2c_interface(Genode::Env &env, addr_t base, unsigned irq,
|
||||
Mmio::Delayer &delayer)
|
||||
:
|
||||
Attached_mmio(base, 0x10000), _irq(irq)
|
||||
Attached_mmio(env, base, 0x10000), _irq(env, irq),
|
||||
_delayer(delayer)
|
||||
{
|
||||
/* FIXME: is this a correct slave address? */
|
||||
write<Add::Slave_addr>(0);
|
||||
@ -238,11 +220,10 @@ class I2c_interface : public Attached_mmio
|
||||
Lc::Filter_en::set(lc, 1);
|
||||
write<Lc>(lc);
|
||||
|
||||
_irq.sigh(_irq_rec.manage(&_irq_ctx));
|
||||
_irq.ack_irq();
|
||||
}
|
||||
|
||||
~I2c_interface() { _irq_rec.dissolve(&_irq_ctx); }
|
||||
~I2c_interface() { }
|
||||
|
||||
/**
|
||||
* Transmit an I2C message as master
|
||||
@ -265,7 +246,7 @@ class I2c_interface : public Attached_mmio
|
||||
if (!_ack_received()) return -1;
|
||||
if (off == msg_size) break;
|
||||
write<Ds>(msg[off]);
|
||||
delayer()->usleep(TX_DELAY_US);
|
||||
_delayer.usleep(TX_DELAY_US);
|
||||
|
||||
/* finish last byte and prepare for next one */
|
||||
off++;
|
||||
@ -278,48 +259,6 @@ class I2c_interface : public Attached_mmio
|
||||
_stop_m_transfer();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive an I2C message as master
|
||||
*
|
||||
* \param slave I2C address of targeted slave
|
||||
* \param buf base of receive buffer
|
||||
* \param buf_size size of receive buffer (= transfer size)
|
||||
*
|
||||
* \retval 0 succeeded
|
||||
* \retval -1 failed
|
||||
*/
|
||||
int m_receive(uint8_t slave, uint8_t * buf, size_t buf_size)
|
||||
{
|
||||
/* check receive buffer and initialize message transfer */
|
||||
if (!buf_size) {
|
||||
error("zero-sized receive buffer");
|
||||
return -1;
|
||||
}
|
||||
if (_start_m_transfer(slave, 0)) return -1;
|
||||
write<Con::Irq_pending>(0);
|
||||
size_t off = 0;
|
||||
bool last_byte = 0;
|
||||
while (1)
|
||||
{
|
||||
/* receive next message byte */
|
||||
_wait_for_irq();
|
||||
if (_arbitration_error()) return -1;
|
||||
buf[off] = read<Ds>();
|
||||
off++;
|
||||
|
||||
/* acknowledge receipt or leave if buffer is full */
|
||||
if (last_byte) break;
|
||||
if (off == buf_size - 1) {
|
||||
write<Con::Ack_en>(0);
|
||||
last_byte = 1;
|
||||
}
|
||||
write<Con::Irq_pending>(0);
|
||||
}
|
||||
/* end message transfer */
|
||||
_stop_m_transfer();
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -417,7 +356,8 @@ class Video_mixer : public Attached_mmio
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Video_mixer() : Attached_mmio(Genode::Board_base::MIXER_BASE, 0x10000) { }
|
||||
Video_mixer(Genode::Env &env)
|
||||
: Attached_mmio(env, Genode::Board_base::MIXER_BASE, 0x10000) { }
|
||||
|
||||
/**
|
||||
* Initialize mixer for displaying one graphical input fullscreen
|
||||
@ -430,8 +370,8 @@ class Video_mixer : public Attached_mmio
|
||||
* \retval 0 succeeded
|
||||
* \retval -1 failed
|
||||
*/
|
||||
int init_mxr(addr_t const fb_phys, size_t const fb_width,
|
||||
size_t const fb_height, Format const fb_format)
|
||||
int init(addr_t const fb_phys, size_t const fb_width,
|
||||
size_t const fb_height, Format const fb_format)
|
||||
{
|
||||
using namespace Framebuffer;
|
||||
|
||||
@ -552,14 +492,6 @@ class Video_mixer : public Attached_mmio
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return singleton of device instance
|
||||
*/
|
||||
static Video_mixer * video_mixer()
|
||||
{
|
||||
static Video_mixer s;
|
||||
return &s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dedicated I2C interface for communicating with HDMI PHY controller
|
||||
@ -573,13 +505,18 @@ class I2c_hdmi : public I2c_interface
|
||||
HDMI_PHY_SLAVE = 0x38,
|
||||
};
|
||||
|
||||
Mmio::Delayer &_delayer;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
I2c_hdmi()
|
||||
: I2c_interface(Genode::Board_base::I2C_BASE, Genode::Board_base::I2C_HDMI_IRQ) { }
|
||||
I2c_hdmi(Genode::Env &env, Mmio::Delayer &delayer)
|
||||
: I2c_interface(env, Genode::Board_base::I2C_BASE,
|
||||
Genode::Board_base::I2C_HDMI_IRQ, delayer),
|
||||
_delayer(delayer)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Stop HDMI PHY from operating
|
||||
@ -629,7 +566,7 @@ class I2c_hdmi : public I2c_interface
|
||||
if (m_transmit(HDMI_PHY_SLAVE, cfg, cfg_size)) { return -1; }
|
||||
|
||||
/* ensure that configuration is applied */
|
||||
delayer()->usleep(10000);
|
||||
_delayer.usleep(10000);
|
||||
|
||||
/* start hdmi phy */
|
||||
static uint8_t start[] = { 0x1f, 0x80 };
|
||||
@ -956,13 +893,17 @@ class Hdmi : public Attached_mmio
|
||||
|
||||
I2c_hdmi _i2c_hdmi;
|
||||
|
||||
Mmio::Delayer &_delayer;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Hdmi()
|
||||
: Attached_mmio(Genode::Board_base::HDMI_BASE, 0xa0000), _i2c_hdmi() { }
|
||||
Hdmi(Genode::Env &env, Mmio::Delayer &delayer)
|
||||
: Attached_mmio(env, Genode::Board_base::HDMI_BASE, 0xa0000),
|
||||
_i2c_hdmi(env, delayer), _delayer(delayer)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Initialize HDMI controller for video output only
|
||||
@ -973,7 +914,7 @@ class Hdmi : public Attached_mmio
|
||||
* \retval 0 succeeded
|
||||
* \retval -1 failed
|
||||
*/
|
||||
int init_hdmi(unsigned scr_width, unsigned scr_height)
|
||||
int init(unsigned scr_width, unsigned scr_height)
|
||||
{
|
||||
/* choose appropriate output mode and parameters */
|
||||
enum Aspect_ratio { _16_9 };
|
||||
@ -995,16 +936,16 @@ class Hdmi : public Attached_mmio
|
||||
write<Phy_con_0::Pwr_off>(0);
|
||||
if (_i2c_hdmi.stop_hdmi_phy()) return -1;
|
||||
write<Phy_rstout::Reset>(1);
|
||||
delayer()->usleep(10000);
|
||||
_delayer.usleep(10000);
|
||||
write<Phy_rstout::Reset>(0);
|
||||
delayer()->usleep(10000);
|
||||
_delayer.usleep(10000);
|
||||
if (_i2c_hdmi.setup_and_start_hdmi_phy(pixel_clk)) return -1;
|
||||
|
||||
/* reset HDMI CORE */
|
||||
write<Core_rstout::Reset>(0);
|
||||
delayer()->usleep(10000);
|
||||
_delayer.usleep(10000);
|
||||
write<Core_rstout::Reset>(1);
|
||||
delayer()->usleep(10000);
|
||||
_delayer.usleep(10000);
|
||||
|
||||
/* common config */
|
||||
write<Intc_con_0::En_global>(0);
|
||||
@ -1093,7 +1034,7 @@ class Hdmi : public Attached_mmio
|
||||
return -1;
|
||||
}
|
||||
/* wait for PHY PLLs to get steady */
|
||||
if (!wait_for<Phy_status_0::Phy_ready>(1, *delayer(), 10)) {
|
||||
if (!wait_for<Phy_status_0::Phy_ready>(1, _delayer, 10)) {
|
||||
error("HDMI PHY not ready");
|
||||
return -1;
|
||||
}
|
||||
@ -1115,39 +1056,32 @@ class Hdmi : public Attached_mmio
|
||||
** Framebuffer::Driver **
|
||||
*************************/
|
||||
|
||||
int Framebuffer::Driver::init_drv(size_t width, size_t height, Format format,
|
||||
Output output, addr_t fb_phys)
|
||||
int Framebuffer::Driver::init(size_t width, size_t height, Format format,
|
||||
addr_t fb_phys)
|
||||
{
|
||||
_fb_width = width;
|
||||
_fb_height = height;
|
||||
_fb_format = format;
|
||||
|
||||
/* set-up targeted output */
|
||||
switch (output) {
|
||||
case OUTPUT_HDMI:
|
||||
if (_init_hdmi(fb_phys)) { return -1; }
|
||||
return 0;
|
||||
default:
|
||||
error("output not supported");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
static Timer_delayer delayer(_env);
|
||||
|
||||
|
||||
int Framebuffer::Driver::_init_hdmi(addr_t fb_phys)
|
||||
{
|
||||
/* feed in power and clocks */
|
||||
hdmi_clock()->state(1);
|
||||
hdmi_power()->state(1);
|
||||
static Regulator::Connection hdmi_clock(_env, Regulator::CLK_HDMI);
|
||||
hdmi_clock.state(1);
|
||||
static Regulator::Connection hdmi_power(_env, Regulator::PWR_HDMI);
|
||||
hdmi_power.state(1);
|
||||
|
||||
int err;
|
||||
|
||||
/* set-up video mixer to feed HDMI */
|
||||
int err;
|
||||
err = video_mixer()->init_mxr(fb_phys, _fb_width, _fb_height, _fb_format);
|
||||
static Video_mixer video_mixer(_env);
|
||||
err = video_mixer.init(fb_phys, _fb_width, _fb_height, _fb_format);
|
||||
if (err) { return -1; }
|
||||
|
||||
/* set-up HDMI to feed connected device */
|
||||
static Hdmi hdmi;
|
||||
err = hdmi.init_hdmi(_fb_width, _fb_height);
|
||||
static Hdmi hdmi(_env, delayer);
|
||||
err = hdmi.init(_fb_width, _fb_height);
|
||||
if (err) { return -1; }
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Genode Labs GmbH
|
||||
* Copyright (C) 2013-2017 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.
|
||||
@ -15,9 +15,9 @@
|
||||
#define _DRIVER_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/component.h>
|
||||
#include <base/stdint.h>
|
||||
#include <base/log.h>
|
||||
#include <os/server.h>
|
||||
|
||||
namespace Framebuffer
|
||||
{
|
||||
@ -38,27 +38,20 @@ class Framebuffer::Driver
|
||||
|
||||
private:
|
||||
|
||||
Genode::Env &_env;
|
||||
|
||||
size_t _fb_width;
|
||||
size_t _fb_height;
|
||||
Format _fb_format;
|
||||
|
||||
/**
|
||||
* Driver-initialization backend for output HDMI
|
||||
*
|
||||
* \param fb_phys physical base of framebuffer
|
||||
*
|
||||
* \retval -1 failed
|
||||
* \retval 0 succeeded
|
||||
*/
|
||||
int _init_hdmi(addr_t fb_phys);
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Driver()
|
||||
Driver(Genode::Env &env)
|
||||
:
|
||||
_env(env),
|
||||
_fb_width(0),
|
||||
_fb_height(0),
|
||||
_fb_format(FORMAT_RGB565)
|
||||
@ -99,19 +92,17 @@ class Framebuffer::Driver
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize driver
|
||||
* Initialize driver for HDMI output
|
||||
*
|
||||
* \param width width of screen and framebuffer in pixel
|
||||
* \param height height of screen and framebuffer in pixel
|
||||
* \param format pixel format of framebuffer
|
||||
* \param output selected output device
|
||||
* \param fb_phys physical base of framebuffer
|
||||
*
|
||||
* \retval -1 failed
|
||||
* \retval 0 succeeded
|
||||
*/
|
||||
int init_drv(size_t width, size_t height, Format format,
|
||||
Output output, addr_t fb_phys);
|
||||
int init(size_t width, size_t height, Format format, addr_t fb_phys);
|
||||
};
|
||||
|
||||
#endif /* _DRIVER_H_ */
|
||||
|
@ -5,22 +5,21 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Genode Labs GmbH
|
||||
* Copyright (C) 2013-2017 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.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/attached_rom_dataspace.h>
|
||||
#include <base/component.h>
|
||||
#include <framebuffer_session/framebuffer_session.h>
|
||||
#include <cap_session/connection.h>
|
||||
#include <timer_session/connection.h>
|
||||
#include <dataspace/client.h>
|
||||
#include <base/log.h>
|
||||
#include <base/sleep.h>
|
||||
#include <os/config.h>
|
||||
#include <os/static_root.h>
|
||||
#include <os/server.h>
|
||||
#include <util/string.h>
|
||||
|
||||
/* local includes */
|
||||
#include <driver.h>
|
||||
@ -33,6 +32,7 @@ namespace Framebuffer
|
||||
* Framebuffer session backend
|
||||
*/
|
||||
class Session_component;
|
||||
struct Main;
|
||||
};
|
||||
|
||||
class Framebuffer::Session_component
|
||||
@ -41,13 +41,15 @@ class Framebuffer::Session_component
|
||||
{
|
||||
private:
|
||||
|
||||
size_t _width;
|
||||
size_t _height;
|
||||
Genode::Env &_env;
|
||||
|
||||
unsigned _width;
|
||||
unsigned _height;
|
||||
Driver::Format _format;
|
||||
size_t _size;
|
||||
Dataspace_capability _ds;
|
||||
addr_t _phys_base;
|
||||
Timer::Connection _timer;
|
||||
Timer::Connection _timer { _env };
|
||||
|
||||
/**
|
||||
* Convert Driver::Format to Framebuffer::Mode::Format
|
||||
@ -70,17 +72,18 @@ class Framebuffer::Session_component
|
||||
* \param height height of framebuffer in pixel
|
||||
* \param output targeted output device
|
||||
*/
|
||||
Session_component(Driver &driver, size_t width, size_t height,
|
||||
Driver::Output output)
|
||||
Session_component(Genode::Env &env, Driver &driver,
|
||||
unsigned width, unsigned height)
|
||||
:
|
||||
_env(env),
|
||||
_width(width),
|
||||
_height(height),
|
||||
_format(Driver::FORMAT_RGB565),
|
||||
_size(driver.buffer_size(width, height, _format)),
|
||||
_ds(env()->ram_session()->alloc(_size, WRITE_COMBINED)),
|
||||
_ds(_env.ram().alloc(_size, WRITE_COMBINED)),
|
||||
_phys_base(Dataspace_client(_ds).phys_addr())
|
||||
{
|
||||
if (driver.init_drv(width, height, _format, output, _phys_base)) {
|
||||
if (driver.init(width, height, _format, _phys_base)) {
|
||||
error("could not initialize display");
|
||||
struct Could_not_initialize_display : Exception { };
|
||||
throw Could_not_initialize_display();
|
||||
@ -110,52 +113,35 @@ class Framebuffer::Session_component
|
||||
};
|
||||
|
||||
|
||||
static unsigned config_dimension(Genode::Xml_node node, char const *attr,
|
||||
unsigned default_value)
|
||||
{
|
||||
return node.attribute_value(attr, default_value);
|
||||
}
|
||||
|
||||
|
||||
struct Main
|
||||
{
|
||||
Server::Entrypoint &ep;
|
||||
Framebuffer::Driver driver;
|
||||
Genode::Env &_env;
|
||||
Genode::Entrypoint &_ep;
|
||||
|
||||
Main(Server::Entrypoint &ep)
|
||||
: ep(ep), driver()
|
||||
Genode::Attached_rom_dataspace _config { _env, "config" };
|
||||
|
||||
Framebuffer::Driver _driver { _env };
|
||||
|
||||
Framebuffer::Session_component _fb_session { _env, _driver,
|
||||
config_dimension(_config.xml(), "width", 1920),
|
||||
config_dimension(_config.xml(), "height", 1080)
|
||||
};
|
||||
|
||||
Genode::Static_root<Framebuffer::Session> _fb_root { _ep.manage(_fb_session) };
|
||||
|
||||
Main(Genode::Env &env) : _env(env), _ep(_env.ep())
|
||||
{
|
||||
using namespace Framebuffer;
|
||||
|
||||
/* default config */
|
||||
size_t width = 1920;
|
||||
size_t height = 1080;
|
||||
Driver::Output output = Driver::OUTPUT_HDMI;
|
||||
|
||||
/* try to read custom user config */
|
||||
try {
|
||||
char out[5] = { 0 };
|
||||
Genode::Xml_node config_node = Genode::config()->xml_node();
|
||||
config_node.attribute("width").value(&width);
|
||||
config_node.attribute("height").value(&height);
|
||||
config_node.attribute("output").value(out, sizeof(out));
|
||||
if (!Genode::strcmp(out, "LCD")) {
|
||||
output = Driver::OUTPUT_LCD;
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
log("using default configuration: HDMI@", width, "x", height);
|
||||
}
|
||||
|
||||
/* let entrypoint serve the framebuffer session and root interfaces */
|
||||
static Session_component fb_session(driver, width, height, output);
|
||||
static Static_root<Framebuffer::Session> fb_root(ep.manage(fb_session));
|
||||
|
||||
/* announce service and relax */
|
||||
env()->parent()->announce(ep.manage(fb_root));
|
||||
_env.parent().announce(_ep.manage(_fb_root));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/************
|
||||
** Server **
|
||||
************/
|
||||
|
||||
namespace Server {
|
||||
char const *name() { return "fb_drv_ep"; }
|
||||
size_t stack_size() { return 16*1024*sizeof(long); }
|
||||
void construct(Entrypoint &ep) { static Main server(ep); }
|
||||
}
|
||||
void Component::construct(Genode::Env &env) { static Main main(env); }
|
||||
|
@ -1,5 +1,5 @@
|
||||
TARGET = fb_drv
|
||||
REQUIRES = exynos
|
||||
SRC_CC += main.cc driver.cc
|
||||
LIBS += base config server
|
||||
LIBS += base
|
||||
INC_DIR += $(PRG_DIR)
|
||||
|
Loading…
x
Reference in New Issue
Block a user