dde_bsd: update audio driver to OpenBSD 6.6

Besides updating to a newer version the update adds the AC97 ICH driver
and addresses shortcomings with the OpenBSD emulation environment:

* Fix 'delay(9)' implementation - it now properly uses 'us' as unit,
  which results on faster initialization of the drivers.

* Fix LOG output that got lost during commit f23579532 and bring over
  the printf implementation from dde_linux for more structured
  printing.

* As said the driver now recognizes the AUICH devices. So far it was
  only tested with the device model in VirtualBox where it produces
  stuttering audio, investigating the cause is still ongoing.

Fixes #3641.
This commit is contained in:
Josef Söntgen 2019-10-16 11:57:44 +02:00 committed by Christian Helmuth
parent 9bd3d2aa5c
commit 9d7a58f6a7
16 changed files with 569 additions and 105 deletions

View File

@ -3,10 +3,11 @@ This repository contains device drivers ported from OpenBSD.
Audio
#####
The audio driver is ported from OpenBSD 5.7 and includes support for
Intel HD Audio as well as for Ensoniq AudioPCI (ES1370) compatible
The audio driver is ported from OpenBSD 6.6 and includes support for
Intel HD Audio, ICH as well as for Ensoniq AudioPCI (ES1370) compatible
soundcards. The HDA driver works on real hardware and Virtualbox
whereas the ES1370 driver is only used in Qemu.
whereas the ES1370 driver is only used in Qemu. The ICH driver is only
tested in Virtualbox where it produces audible artifacts.
Usage

View File

@ -1,16 +1,17 @@
./sys/dev/audio.c
./sys/dev/audio_if.h
./sys/dev/pci/azalia.c
./sys/dev/pci/azalia.h
./sys/dev/pci/azalia_codec.c
./sys/dev/pci/eap.c
./sys/dev/pci/eapreg.h
./sys/dev/pci/pcidevs.h
./sys/dev/pci/pcidevs_data.h
./sys/dev/mulaw.c
./sys/dev/mulaw.h
./sys/dev/ic/ac97.c
./sys/dev/ic/ac97.h
./sys/sys/audioio.h
./sys/sys/device.h
./sys/sys/queue.h
sys/dev/audio.c
sys/dev/audio_if.h
sys/dev/pci/auich.c
sys/dev/pci/azalia.c
sys/dev/pci/azalia.h
sys/dev/pci/azalia_codec.c
sys/dev/pci/eap.c
sys/dev/pci/eapreg.h
sys/dev/pci/pcidevs.h
sys/dev/pci/pcidevs_data.h
sys/dev/mulaw.c
sys/dev/mulaw.h
sys/dev/ic/ac97.c
sys/dev/ic/ac97.h
sys/sys/audioio.h
sys/sys/device.h
sys/sys/queue.h

View File

@ -29,9 +29,11 @@ CC_OPT += -D_KERNEL
CC_C_OPT += -Wno-maybe-uninitialized
# enable when debugging
# CC_OPT += -DAUDIO_DEBUG
# CC_OPT += -DAZALIA_DEBUG
# CC_OPT += -DDIAGNOSTIC
#CC_OPT += -DAUDIO_DEBUG
#CC_OPT += -DAC97_DEBUG
#CC_OPT += -DAUICH_DEBUG
#CC_OPT += -DAZALIA_DEBUG
#CC_OPT += -DDIAGNOSTIC
# audio interface
SRC_C += dev/audio.c
@ -42,6 +44,9 @@ SRC_C += dev/ic/ac97.c
# HDA driver
SRC_C += dev/pci/azalia.c dev/pci/azalia_codec.c
# ICH driver
SRC_C += dev/pci/auich.c
# ES1370
SRC_C += dev/pci/eap.c

View File

@ -1,8 +1,6 @@
diff --git a/dev/pci/azalia.c b/dev/pci/azalia.c
index b126ef6..f73c238 100644
--- a/dev/pci/azalia.c
+++ b/dev/pci/azalia.c
@@ -492,7 +492,7 @@ azalia_pci_attach(struct device *parent, struct device *self, void *aux)
@@ -492,7 +492,7 @@
azalia_t *sc;
struct pci_attach_args *pa;
pcireg_t v;
@ -11,7 +9,7 @@ index b126ef6..f73c238 100644
pci_intr_handle_t ih;
const char *interrupt_str;
@@ -518,12 +518,18 @@ azalia_pci_attach(struct device *parent, struct device *self, void *aux)
@@ -518,12 +518,18 @@
azalia_configure_pci(sc);
@ -34,5 +32,24 @@ index b126ef6..f73c238 100644
+ // azalia_pci_write(sc->pc, sc->tag, ICH_PCI_MMC, reg);
+ // }
/* interrupt */
if (pci_intr_map_msi(pa, &ih) && pci_intr_map(pa, &ih)) {
/* disable MSI for AMD Summit Ridge/Raven Ridge HD Audio */
if (PCI_VENDOR(sc->pciid) == PCI_VENDOR_AMD) {
@@ -3973,6 +3979,10 @@
azalia_set_blksz(void *v, int mode,
struct audio_params *p, struct audio_params *r, unsigned int blksz)
{
+ // XXX using mult leads to a blksz of 416 in case of a
+ // requested blksz of 441 which in return results in distored
+ // playback.
+#if 0
int mult;
/* must be multiple of 128 bytes */
@@ -3981,6 +3991,7 @@
blksz -= blksz % mult;
if (blksz == 0)
blksz = mult;
+#endif
return blksz;
}

View File

@ -1 +1 @@
789276c39e114f0e0ca304a892fe92705da1b50e
823dbe660265cdb53067d515c7dc1a623297c468

View File

@ -3,15 +3,15 @@ VERSION := 1
DOWNLOADS := audio.archive
#
# Audio drivers from OpenBSD 5.9
# Audio drivers from OpenBSD 6.6
#
SRC_DIR_AUDIO := src/lib/audio
VERSION_AUDIO := 5.9
VERSION_AUDIO := 6.6
BASE_URL := https://ftp.halifax.rwth-aachen.de/pub/OpenBSD
URL(audio) := $(BASE_URL)/$(VERSION_AUDIO)/sys.tar.gz
SHA(audio) := 868775750a405c252d1ba78df69d6ebb101ccb26e776d5407a087ec030970baa
SHA(audio) := a1b19665989c02a2017a639d47a042f4fe7f584b6298727e982a5536020b832d
DIR(audio) := $(SRC_DIR_AUDIO)
TAR_OPT(audio) := --strip-components=2 --files-from $(REP_DIR)/audio.list
TAR_OPT(audio) := --strip-components=1 --files-from $(REP_DIR)/audio.list
HASH_INPUT += $(REP_DIR)/audio.list
#

View File

@ -14,6 +14,7 @@ MIRROR_FROM_PORT_DIR := $(addprefix src/lib/audio/, \
dev/pci/azalia.h \
dev/pci/eapreg.h \
dev/pci/azalia.c \
dev/pci/auich.c \
dev/mulaw.h \
dev/audio_if.h \
dev/mulaw.c \

View File

@ -68,12 +68,20 @@ append_if $use_mixer config {
</route>
</start>}
append_if [have_spec linux] config {
<start name="audio_drv" ld="no">}
append_if [expr ![have_spec linux]] config {
<start name="audio_drv">}
append config {
<start name="audio_drv">
<binary name="} [audio_drv_binary] {"/>
<resource name="RAM" quantum="8M"/>
<provides> <service name="Audio_out"/> </provides>
<config />
<!--
The proper ALSA device might need to be configured, e.g.
<config alsa_device="hw:CARD=Schiit,DEV=0"/>
when using Linux.
-->
<config/>
</start>
<start name="test-audio_out">
<resource name="RAM" quantum="4M"/>

View File

@ -179,7 +179,9 @@ class Audio_out::Out
_data_avail_dispatcher(env.ep(), *this, &Audio_out::Out::_handle_data_avail),
_notify_dispatcher(env.ep(), *this, &Audio_out::Out::_handle_notify)
{
/* play a silence packet to get the driver running */
/* play a silence packets to get the driver running */
// XXX replace by explicit call to audio_start
_play_silence();
_play_silence();
}

View File

@ -31,6 +31,8 @@ extern struct cfdriver azalia_cd;
extern struct cfattach azalia_ca;
extern struct cfdriver eap_cd;
extern struct cfattach eap_ca;
extern struct cfdriver auich_cd;
extern struct cfattach auich_ca;
/* original value */
@ -42,6 +44,7 @@ struct cfdata cfdata[] = {
{&audio_ca, &audio_cd, 0, 0, 0, 0, pv+0, 0, 0},
{&azalia_ca, &azalia_cd, 0, 0, 0, 0, pv+1, 0, 0},
{&eap_ca, &eap_cd, 0, 0, 0, 0, pv+1, 0, 0},
{&auich_ca, &auich_cd, 0, 0, 0, 0, pv+1, 0, 0},
};
@ -100,10 +103,13 @@ int probe_cfdata(struct pci_attach_args *pa)
struct device *dev = (struct device *) malloc(ca->ca_devsize,
M_DEVBUF, M_NOWAIT|M_ZERO);
dev->dv_cfdata = cf;
snprintf(dev->dv_xname, sizeof(dev->dv_xname), "%s%d", cd->cd_name,
dev->dv_unit);
printf("%s at %s\n", dev->dv_xname, pci_bus.dv_xname);
ca->ca_attach(&pci_bus, dev, pa);
return 1;
}
}
@ -128,6 +134,8 @@ struct device *config_found_sm(struct device *parent, void *aux, cfprint_t print
dev->dv_unit);
printf("%s at %s\n", dev->dv_xname, parent->dv_xname);
dev->dv_cfdata = cf;
ca->ca_attach(parent, dev, aux);
audio_cd.cd_ndevs = 1;
@ -148,3 +156,15 @@ struct device *device_lookup(struct cfdriver *cd, int unit)
return audio_cd.cd_devs[unit];
}
/*****************
** sys/ucred.h **
*****************/
int suser(struct proc *p)
{
(void)p;
/* we always have special user powers */
return 0;
};

View File

@ -32,7 +32,7 @@
extern struct cfdriver audio_cd;
static dev_t const adev = 0x80; /* audio0 (minor nr 128) */
static dev_t const adev = 0x00; /* audio0 (minor nr 0) */
static dev_t const mdev = 0x10; /* mixer0 (minor nr 16) */
static bool adev_usuable = false;
@ -53,41 +53,23 @@ static bool drv_loaded()
** Dump audio configuration **
******************************/
#define DUMP_INFO(field) \
Genode::log("--- " #field " information ---"); \
Genode::log("sample_rate: ", (unsigned)ai.field.sample_rate); \
Genode::log("channels: ", (unsigned)ai.field.channels); \
Genode::log("precision: ", (unsigned)ai.field.precision); \
Genode::log("bps: ", (unsigned)ai.field.bps); \
Genode::log("encoding: ", (unsigned)ai.field.encoding); \
Genode::log("buffer_size: ", (unsigned)ai.field.buffer_size); \
Genode::log("block_size: ", (unsigned)ai.field.block_size); \
Genode::log("samples: ", (unsigned)ai.field.samples); \
Genode::log("pause: ", (unsigned)ai.field.pause); \
Genode::log("active: ", (unsigned)ai.field.active)
static void dump_pinfo()
static void dump_info()
{
struct audio_info ai;
if (audioioctl(adev, AUDIO_GETINFO, (char*)&ai, 0, 0)) {
struct audio_swpar ap;
AUDIO_INITPAR(&ap);
if (audioioctl(adev, AUDIO_GETPAR, (char*)&ap, 0, 0)) {
Genode::error("could not gather play information");
return;
}
DUMP_INFO(play);
}
static void dump_rinfo()
{
struct audio_info ai;
if (audioioctl(adev, AUDIO_GETINFO, (char*)&ai, 0, 0)) {
Genode::error("could not gather play information");
return;
}
DUMP_INFO(record);
Genode::log("Audio information:");
Genode::log(" sample_rate: ", (unsigned)ap.rate);
Genode::log(" playback channels: ", (unsigned)ap.pchan);
Genode::log(" record channels: ", (unsigned)ap.rchan);
Genode::log(" num blocks: ", (unsigned)ap.nblks);
Genode::log(" block size: ", (unsigned)ap.round);
}
@ -374,36 +356,39 @@ static void configure_mixer(Genode::Env &env, Mixer &mixer, Genode::Xml_node con
static bool configure_audio_device(Genode::Env &env, dev_t dev, Genode::Xml_node config)
{
struct audio_info ai;
struct audio_swpar ap;
int err = audioioctl(adev, AUDIO_GETINFO, (char*)&ai, 0, 0);
AUDIO_INITPAR(&ap);
int err = audioioctl(adev, AUDIO_GETPAR, (char*)&ap, 0, 0);
if (err)
return false;
using namespace Audio;
/* configure the device according to our Audio_out session settings */
ai.play.sample_rate = Audio_out::SAMPLE_RATE;
ai.play.channels = Audio_out::MAX_CHANNELS;
ai.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
ai.play.block_size = Audio_out::MAX_CHANNELS * sizeof(short) * Audio_out::PERIOD;
/* Configure the device according to our Audio_in session settings
*
* We use Audio_out::MAX_CHANNELS here because the backend provides us
* with two channels that we will mix to one in the front end for now.
/*
* Configure the device according to our Audio_out session parameters.
* Only set the relevant parameters and let the audio(4) subsystem
* figure out the rest.
*/
ai.record.sample_rate = Audio_in::SAMPLE_RATE;
ai.record.channels = Audio_out::MAX_CHANNELS;
ai.record.encoding = AUDIO_ENCODING_SLINEAR_LE;
ai.record.block_size = Audio_out::MAX_CHANNELS * sizeof(short) * Audio_in::PERIOD;
ap.rate = Audio_out::SAMPLE_RATE;
ap.pchan = Audio_out::MAX_CHANNELS;
ap.sig = 1;
ap.bits = 16;
ap.bps = (ap.bits / 8);
ap.round = Audio_out::PERIOD;
/*
* Use 2 blocks, the one that is currently played and the one
* that will be filled in.
*/
ap.nblks = 2;
/*
* For recording use two channels that we will mix to one in the
* front end.
*/
ap.rchan = 2;
err = audioioctl(adev, AUDIO_SETINFO, (char*)&ai, 0, 0);
if (err)
return false;
int fullduplex = 1;
err = audioioctl(adev, AUDIO_SETFD, (char*)&fullduplex, 0, 0);
err = audioioctl(adev, AUDIO_SETPAR, (char*)&ap, 0, 0);
if (err)
return false;
@ -415,8 +400,7 @@ static bool configure_audio_device(Genode::Env &env, dev_t dev, Genode::Xml_node
bool const verbose = config.attribute_value<bool>("verbose", false);
if (verbose) dump_pinfo();
if (verbose) dump_rinfo();
if (verbose) dump_info();
if (verbose) dump_mixer(mixer);
configure_mixer(env, mixer, config);

View File

@ -62,6 +62,7 @@ DUMMY(0, timeout_add_msec)
DUMMY(0, timeout_del)
DUMMY(0, timeout_set)
DUMMY(0, tsleep)
DUMMY(0, tsleep_nsec)
DUMMY(0, vdevgone)
DUMMY(0, device_unref)

View File

@ -47,6 +47,7 @@ typedef unsigned int uint;
typedef signed short int16_t;
typedef signed int int32_t;
typedef signed long long int64_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
@ -70,6 +71,7 @@ typedef signed long long off_t;
enum {
EIO = 5,
ENXIO = 6,
EBADF = 9,
ENOMEM = 12,
EACCES = 13,
EBUSY = 16,
@ -100,6 +102,7 @@ enum {
M_WAITOK = 0x01,
M_NOWAIT = 0x02,
M_ZERO = 0x08,
M_TEMP = 0x10,
/* types of memory */
M_DEVBUF = 2,
};
@ -120,6 +123,8 @@ enum {
PCATCH = 0x100,
};
#define PAGE_SIZE (1 << 12)
#ifdef __cplusplus
#define NULL 0
#else
@ -128,6 +133,8 @@ enum {
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
#define offsetof(s, e) __builtin_offsetof(s, e)
/******************
** sys/kernel.h **
@ -153,6 +160,13 @@ extern int hz;
struct proc { };
/*****************
** sys/ucred.h **
*****************/
int suser(struct proc *p);
/****************
** sys/task.h **
****************/
@ -281,6 +295,8 @@ void mtx_leave(struct mutex *);
** sys/systm.h **
*****************/
#define INFSLP __UINT64_MAX__
extern int nchrdev;
int enodev(void);
@ -296,6 +312,7 @@ void *memset(void *, int, size_t);
void wakeup(const volatile void*);
int tsleep(const volatile void *, int, const char *, int);
int tsleep_nsec(const volatile void *, int, const char *, uint64_t);
int msleep(const volatile void *, struct mutex *, int, const char*, int);
int uiomove(void *, int, struct uio *);
@ -549,6 +566,7 @@ enum {
BUS_DMA_WAITOK = 0x0000,
BUS_DMA_NOWAIT = 0x0001,
BUS_DMA_COHERENT = 0x0004,
BUS_DMA_NOCACHE = 0x0800,
};
@ -615,6 +633,8 @@ enum {
** dev/pci/pcivar.h **
**********************/
#define PCI_FLAGS_MSI_ENABLED 0x20
/* actually from pci_machdep.h */
typedef void *pci_chipset_tag_t;
typedef uint32_t pcitag_t;
@ -625,6 +645,7 @@ struct pci_attach_args
{
bus_dma_tag_t pa_dmat;
pci_chipset_tag_t pa_pc;
int pa_flags;
pcitag_t pa_tag;
pcireg_t pa_id;
pcireg_t pa_class;
@ -676,9 +697,24 @@ int timeout_del(struct timeout *);
** sys/endian.h **
******************/
#define LITTLE_ENDIAN 1234
#define BYTE_ORDER LITTLE_ENDIAN
#define htole32(x) ((uint32_t)(x))
/****************
** sys/time.h **
****************/
struct timeval
{
int64_t tv_sec;
long tv_usec;
};
void microuptime(struct timeval *);
#include <extern_c_end.h>
#endif /* _BSD_EMUL_H_ */

View File

@ -133,7 +133,7 @@ class Bsd::Slab_alloc : public Genode::Slab
static Genode::size_t _calculate_block_size(Genode::size_t object_size)
{
Genode::size_t const block_size = 16*object_size;
Genode::size_t const block_size = 8*object_size;
return Genode::align_addr(block_size, 12);
}
@ -164,7 +164,7 @@ class Bsd::Malloc
enum {
SLAB_START_LOG2 = 5, /* 32 B */
SLAB_STOP_LOG2 = 16, /* 64 KiB */
SLAB_STOP_LOG2 = 17, /* 128 KiB */
NUM_SLABS = (SLAB_STOP_LOG2 - SLAB_START_LOG2) + 1,
};
@ -329,7 +329,7 @@ extern "C" void *malloc(size_t size, int type, int flags)
{
void *addr = malloc_backend().alloc(size);
if (flags & M_ZERO)
if (addr && (flags & M_ZERO))
Genode::memset(addr, 0, size);
return addr;

View File

@ -1,6 +1,7 @@
/*
* \brief Audio driver BSD API emulation
* \author Josef Soentgen
* \author Sebstian Sumpf
* \date 2014-11-09
*/
@ -12,6 +13,7 @@
*/
/* Genode includes */
#include <base/log.h>
#include <base/sleep.h>
#include <base/snprintf.h>
#include <util/string.h>
@ -39,21 +41,381 @@ void mtx_leave(struct mutex *mtx) {
** sys/systm.h **
*****************/
static int _vprintf(char const *format, va_list list)
{
char buf[128] { };
Genode::String_console sc(buf, sizeof(buf));
sc.vprintf(format, list);
return sc.len();
namespace Bsd {
class Console;
class Format_command;
}
/**
* Format string command representation
*/
class Bsd::Format_command
{
public:
enum Type { INT, UINT, STRING, CHAR, PTR, PERCENT,
INVALID };
enum Length { DEFAULT, LONG, SIZE_T, LONG_LONG };
private:
/**
* Read decimal value from string
*/
int decode_decimal(const char *str, int *consumed)
{
int res = 0;
while (1) {
char c = str[*consumed];
if (!c || c < '0' || c > '0' + 9)
return res;
res = (res * 10) + c - '0';
(*consumed)++;
}
}
public:
Type type = INVALID; /* format argument type */
Length length = DEFAULT; /* format argument length */
int padding = 0; /* min number of characters to print */
int base = 10; /* base of numeric arguments */
bool zeropad = false; /* pad with zero instead of space */
bool uppercase = false; /* use upper case for hex numbers */
bool prefix = false; /* prefix with 0x */
int consumed = 0; /* nb of consumed format string chars */
/**
* Constructor
*
* \param format begin of command in format string
*/
explicit Format_command(const char *format)
{
/* check for command begin and eat the character */
if (format[consumed] != '%') return;
if (!format[++consumed]) return;
/* check for %$x syntax */
prefix = (format[consumed] == '#') || (format[consumed] == '.');
if (prefix && !format[++consumed]) return;
/* heading zero indicates zero-padding */
zeropad = (format[consumed] == '0');
/* read decimal padding value */
padding = decode_decimal(format, &consumed);
if (!format[consumed]) return;
/* decode length */
switch (format[consumed]) {
case 'l':
{
/* long long ints are marked by a subsequenting 'l' character */
bool is_long_long = (format[consumed + 1] == 'l');
length = is_long_long ? LONG_LONG : LONG;
consumed += is_long_long ? 2 : 1;
break;
}
case 'z':
case 'Z':
length = SIZE_T;
consumed++;
break;
case 'p':
length = LONG;
break;
default: break;
}
if (!format[consumed]) return;
/* decode type */
switch (format[consumed]) {
case 'd':
case 'i': type = INT; base = 10; break;
case 'o': type = UINT; base = 8; break;
case 'u': type = UINT; base = 10; break;
case 'x': type = UINT; base = 16; break;
case 'X': type = UINT; base = 16; uppercase = 1; break;
case 'p': type = PTR; base = 16; break;
case 'c': type = CHAR; break;
case 's': type = STRING; break;
case '%': type = PERCENT; break;
case 0: return;
default: break;
}
/* eat type character */
consumed++;
if (type != PTR || !format[consumed])
return;
switch (format[consumed]) {
default: return;
}
consumed++;
}
int numeric()
{
return (type == INT || type == UINT || type == PTR);
}
};
/**
* Convert digit to ASCII value
*/
static char ascii(int digit, int uppercase = 0)
{
if (digit > 9)
return digit + (uppercase ? 'A' : 'a') - 10;
return digit + '0';
}
class Bsd::Console
{
private:
enum { BUF_SIZE = 216 };
char _buf[BUF_SIZE + 1];
unsigned _idx = 0;
void _flush()
{
if (!_idx)
return;
_buf[_idx] = 0;
Genode::log(Genode::Cstring(_buf));
_idx = 0;
}
/**
* Output signed value with the specified base
*/
template <typename T>
void _out_signed(T value, unsigned base)
{
/**
* for base 8, the number of digits is the number of value bytes times 3
* at a max, because 0xff is 0o377 and accumulating this implies a
* strictly decreasing factor
*/
char buf[sizeof(value)*3];
/* set flag if value is negative */
int neg = value < 0 ? 1 : 0;
/* get absolute value */
value = value < 0 ? -value : value;
int i = 0;
/* handle zero as special case */
if (value == 0)
buf[i++] = ascii(0);
/* fill buffer starting with the least significant digits */
else
for (; value > 0; value /= base)
buf[i++] = ascii(value % base);
/* add sign to buffer for negative values */
if (neg)
_out_char('-');
/* output buffer in reverse order */
for (; i--; )
_out_char(buf[i]);
}
/**
* Output unsigned value with the specified base and padding
*/
template <typename T>
void _out_unsigned(T value, unsigned base, int pad)
{
/**
* for base 8, the number of digits is the number of value bytes times 3
* at a max, because 0xff is 0o377 and accumulating this implies a
* strictly decreasing factor
*/
char buf[sizeof(value)*3];
int i = 0;
/* handle zero as special case */
if (value == 0) {
buf[i++] = ascii(0);
pad--;
}
/* fill buffer starting with the least significant digits */
for (; value > 0; value /= base, pad--)
buf[i++] = ascii(value % base);
/* add padding zeros */
for (; pad-- > 0; )
_out_char(ascii(0));
/* output buffer in reverse order */
for (; i--; )
_out_char(buf[i]);
}
protected:
void _out_char(char c)
{
if (c == '\n' || _idx == BUF_SIZE || c == 0)
_flush();
else
_buf[_idx++] = c;
}
void _out_string(const char *str)
{
if (str)
while (*str) _out_char(*str++);
else
_flush();
}
public:
static Console &c()
{
static Console _inst;
return _inst;
}
void vprintf(const char *format, va_list list)
{
while (*format) {
/* eat and output plain characters */
if (*format != '%') {
_out_char(*format++);
continue;
}
/* parse format argument descriptor */
Format_command cmd(format);
/* read numeric argument from va_list */
long long numeric_arg = 0;
if (cmd.numeric()) {
switch (cmd.length) {
case Format_command::LONG_LONG:
numeric_arg = va_arg(list, long long);
break;
case Format_command::LONG:
numeric_arg = (cmd.type == Format_command::UINT) ?
(long long)va_arg(list, unsigned long) : va_arg(list, long);
break;
case Format_command::SIZE_T:
numeric_arg = va_arg(list, size_t);
break;
case Format_command::DEFAULT:
numeric_arg = (cmd.type == Format_command::UINT) ?
(long long)va_arg(list, unsigned int) : va_arg(list, int);
break;
}
}
/* call type-specific output routines */
switch (cmd.type) {
case Format_command::INT:
if (cmd.length == Format_command::LONG_LONG)
_out_signed<long long>(numeric_arg, cmd.base);
else
_out_signed<long>(numeric_arg, cmd.base);
break;
case Format_command::UINT:
if (cmd.prefix && cmd.base == 16)
_out_string("0x");
if (cmd.length == Format_command::LONG_LONG) {
_out_unsigned<unsigned long long>(numeric_arg, cmd.base, cmd.padding);
break;
}
/* fall through */
case Format_command::PTR:
_out_unsigned<unsigned long>(numeric_arg, cmd.base, cmd.padding);
break;
case Format_command::CHAR:
_out_char(va_arg(list, int));
break;
case Format_command::STRING:
_out_string(va_arg(list, const char *));
break;
case Format_command::PERCENT:
_out_char('%');
break;
case Format_command::INVALID:
_out_string("<warning: unsupported format string argument>");
/* consume the argument of the unsupported command */
va_arg(list, long);
break;
}
/* proceed with format string after command */
format += cmd.consumed;
}
}
};
extern "C" void panic(char const *format, ...)
{
va_list list;
va_start(list, format);
_vprintf(format, list);
Bsd::Console::c().vprintf(format, list);
va_end(list);
Genode::sleep_forever();
@ -65,10 +427,11 @@ extern "C" int printf(const char *format, ...)
va_list list;
va_start(list, format);
int const result = _vprintf(format, list);
Bsd::Console::c().vprintf(format, list);
va_end(list);
return result;
/* hopefully this gets never checked... */
return 0;
}

View File

@ -71,9 +71,9 @@ class Bsd::Timer
millisecs = _timer_conn.elapsed_ms();
}
void delay(Genode::uint64_t ms)
void delay(Genode::uint64_t us)
{
_timer_conn.msleep(ms);
_timer_conn.usleep(us);
}
};
@ -120,6 +120,10 @@ extern "C" int msleep(const volatile void *ident, struct mutex *mtx,
extern "C" void wakeup(const volatile void *ident)
{
if (!_sleep_task) {
Genode::error("sleep task is NULL");
Genode::sleep_forever();
}
_sleep_task->unblock();
_sleep_task = nullptr;
}
@ -133,3 +137,24 @@ extern "C" void delay(int delay)
{
_bsd_timer->delay(delay);
}
/****************
** sys/time.h **
****************/
void microuptime(struct timeval *tv)
{
_bsd_timer->update_millisecs();
if (!tv) { return; }
/*
* So far only needed by auich_calibrate, which
* reuqires microseconds - switching the Bsd::Timer
* implementation over to the new Genode::Timer API
* is probably necessary for that to work properly.
*/
tv->tv_sec = millisecs / 1000;
tv->tv_usec = 0;
}