mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-29 15:44:02 +00:00
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:
parent
9bd3d2aa5c
commit
9d7a58f6a7
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
789276c39e114f0e0ca304a892fe92705da1b50e
|
||||
823dbe660265cdb53067d515c7dc1a623297c468
|
||||
|
@ -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
|
||||
|
||||
#
|
||||
|
@ -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 \
|
||||
|
@ -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"/>
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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_ */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user