OSS: Open Sound System server

Currently supports Intel HDA, AC97, and ES1370 audio cards. See README
for further details.
devel
Sebastian Sumpf 10 years ago committed by Norman Feske
parent 8ac3209aa8
commit 7d8f446475

@ -147,9 +147,14 @@ The Genode source tree is composed of the following subdirectories:
:'dde_ipxe':
This source-code repository contains the device driver environment for
This source-code repository contains the device-driver environment for
executing drivers of the iPXE project.
:'dde_oss':
This source-code repository contains the device-driver environment for the
audio drivers of the Open Sound System (OSS).
:'qt4':
This source-code repository contains the Genode version of Qt4 framework.

@ -0,0 +1,124 @@
#
# \brief Download and setup OSS sources
# \author Sebastian Sumpf
# \date 2012-08-30
CONTRIB_DIR = contrib
DOWNLOAD_DIR = download
VERBOSE ?= @
ECHO = @echo
CC ?= gcc
PATCHES := $(shell find patches -name \*.patch)
OSS = oss-v4.2-build2006-src-bsd
OSS_TBZ2 = $(OSS).tar.bz2
OSS_URL = http://www.4front-tech.com/developer/sources/stable/bsd/$(OSS_TBZ2)
# needed for preparation
CONTENT_SETUP = $(addprefix setup/,srcconf.c srcconf_freebsd.inc srcconf_vxworks.inc gen_driver_freebsd.inc)
CONTENT += $(CONTENT_SETUP)
# oss framework
CONTENT_FRAMEWORK = $(addprefix kernel/framework/include/,oss_config.h oss_memblk.h \
oss_version.h audio_core.h mixer_core.h oss_calls.h \
internal.h oss_pci.h spdif.h midi_core.h grc3.h ac97.h \
ossddk/oss_exports.h ossddk/oss_limits.PHh ossddk/ossddk.h)
CONTENT += $(CONTENT_FRAMEWORK)
# oss core
CONTENT_CORE = $(addprefix kernel/framework/osscore/,oss_memblk.c oss_core_options.c \
oss_core_services.c)
CONTENT += $(CONTENT_CORE)
CONTENT += include/soundcard.h kernel/drv/.config
# audio core
CONTENT_AUDIO = $(addprefix kernel/framework/audio/,oss_audio_core.c oss_spdif.c oss_audiofmt.c \
ulaw.h audiocnv.inc oss_grc3.c fltdata2_h.inc \
grc3code.inc grc3inc.inc)
CONTENT += $(CONTENT_AUDIO)
# mixer core
CONTENT_MIXER = $(addprefix kernel/framework/mixer/,oss_mixer_core.c mixerdefs.h)
CONTENT += $(CONTENT_MIXER)
# vmixer core
CONTENT_VMIX = $(addprefix kernel/framework/vmix_core/,vmix_core.c vmix_input.c vmix.h db_scale.h \
vmix_import.inc vmix_import_int.inc \
rec_export.inc rec_export_int.inc \
vmix_output.c outexport.inc outexport_int.inc \
playmix.inc playmix_int.inc playmix_src.inc)
CONTENT += $(CONTENT_VMIX)
# midi core
CONTENT_MIDI = $(addprefix kernel/framework/midi/,oss_midi_core.c oss_midi_timers.c oss_midi_mapper.c \
oss_midi_queue.c)
CONTENT += $(CONTENT_MIDI)
# AC97 core
CONTENT += kernel/framework/ac97
# drivers
CONTENT_DRV += oss_ich oss_hdaudio oss_audiopci
CONTENT += $(addprefix kernel/drv/,$(CONTENT_DRV))
#
# Utility to check if a tool is installed
#
check_tool = $(if $(shell which $(1)),,$(error Need to have '$(1)' installed.))
$(call check_tool,wget)
$(call check_tool,patch)
#
# Print help information by default
#
help:
$(ECHO)
$(ECHO) "Download integrate OSS sources with Genode"
$(ECHO)
$(ECHO) "--- available commands ---"
$(ECHO) "prepare - download and integrate OSS source code"
$(ECHO) "clean - remove contib sources except downloaded archives"
$(ECHO) "cleanall - remove contib sources and downloaded archives"
$(ECHO)
#
# Build and execute 'srcconf' utility, build 'devices.list'
#
setup:
$(VERBOSE)ln -sf srcconf_freebsd.inc $(CONTRIB_DIR)/setup/srcconf_linux.inc
$(VERBOSE)ln -sf gen_driver_freebsd.inc $(CONTRIB_DIR)/setup/gen_driver_linux.inc
$(VERBOSE)mkdir -p $(CONTRIB_DIR)/kernel/framework/include
$(VERBOSE)mkdir -p $(CONTRIB_DIR)/kernel/OS/Linux
$(VERBOSE)$(CC) -g -I$(CONTRIB_DIR)/setup -o srcconf $(CONTRIB_DIR)/setup/srcconf.c
$(VERBOSE)cat `find $(CONTRIB_DIR)/kernel/drv -name .devices`| grep -v '^#' > $(CONTRIB_DIR)/devices.list
$(VERBOSE)cd $(CONTRIB_DIR) && ../srcconf
$(VERBOSE)cd $(CONTRIB_DIR)/target/build ; for f in *.c; do mv $$f pci_$$f; done
$(VERBOSE)rm srcconf
prepare: $(CONTRIB_DIR)/.prepared setup
$(CONTRIB_DIR)/.prepared: Makefile
$(CONTRIB_DIR)/.prepared: $(DOWNLOAD_DIR)/$(OSS_TBZ2)
$(ECHO) "extracting source code to '$(CONTRIB_DIR)'"
$(VERBOSE)tar xfj $< --transform "s/$(OSS)/$(CONTRIB_DIR)/" $(addprefix $(OSS)/,$(CONTENT))
$(VERBOSE)touch $@
$(ECHO) "applying patches to '$(CONTRIB_DIR)/'"
$(VERBOSE)for i in $(PATCHES); do patch -d $(CONTRIB_DIR) -p1 < $$i; done
$(DOWNLOAD_DIR):
$(VERBOSE)mkdir -p $@
$(DOWNLOAD_DIR)/$(OSS_TBZ2): $(DOWNLOAD_DIR)
$(ECHO) "downloading source code to '$@'"
$(VERBOSE)cd $(DOWNLOAD_DIR); wget -c $(OSS_URL)
$(VERBOSE)touch $@
clean:
$(VERBOSE)rm -rf $(CONTRIB_DIR)
cleanall: clean
$(VERBOSE)rm -rf $(DOWNLOAD_DIR)

@ -0,0 +1,37 @@
This repository contains the Genode port of the
[http://http://www.4front-tech.com - Open Sound System] (OSS).
OSS
###
Usage
=====
On first use, please call
! make prepare
on the top-level makefile of this repository. Also you need to make sure to
add the 'dde_oss' repository to your REPOSITORIES variable in 'etc/build.conf'.
Example
=======
An OSS demo configuration can be found under 'run/oss.run' and can be started
via
! make run/oss
from the Genode build directory. Be sure to adjust the 'filename' tag of the
'audio0' program. The file has to reside under: '<Genode build directory>/bin'.
The file format is header less two channel float 32 at 44100 Hz. You may use
the 'sox' utility to create these audio files:
! sox -c 2 -r 44100 foo.mp3 foo.f32
Supported devices
=================
Currently supported devices can be found in 'contrib/devices.list' in this
repository after preparation.

@ -0,0 +1,13 @@
diff -r aa33e3290f44 kernel/drv/oss_hdaudio/oss_hdaudio.c
--- a/kernel/drv/oss_hdaudio/oss_hdaudio.c Tue Nov 20 11:10:35 2012 +0100
+++ b/kernel/drv/oss_hdaudio/oss_hdaudio.c Tue Nov 20 11:13:14 2012 +0100
@@ -255,8 +255,7 @@
if (status & (1 << 30)) /* Controller interrupt (RIRB) */
{
- if (rirb_intr (devc))
- serviced = 1;
+ serviced = rirb_intr (devc);
}
}
return serviced;

@ -0,0 +1,99 @@
if {![have_spec x86_32]} {
puts "\nOSS currently only supported on x86_32\n"
exit 0
}
#
# Build
#
set build_components {
core init
drivers/timer
drivers/oss
drivers/pci
drivers/acpi
test/audio_out
}
build $build_components
create_boot_directory
#
# Config
#
append config {
<config>
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="IO_PORT"/>
<service name="CAP"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="SIGNAL" />
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<start name="acpi">
<resource name="RAM" quantum="2M"/>
<binary name="acpi_drv"/>
<provides>
<service name="PCI"/>
<service name="IRQ" />
</provides>
<route>
<service name="PCI"> <any-child /> </service>
<any-service> <parent/> <any-child /> </any-service>
</route>
</start>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides><service name="Timer"/></provides>
</start>
<start name="oss_drv">
<resource name="RAM" quantum="6M"/>
<route>
<service name="IRQ"><child name="acpi" /></service>
<any-service> <parent /> <any-child /></any-service>
</route>
<provides>
<service name="Audio_out"/>
</provides>
</start>
<start name="audio0">
<binary name="test-audio_out"/>
<resource name="RAM" quantum="8M"/>
<config>
<filename>sample.raw</filename>
</config>
<route>
<service name="Audio_out"> <child name="oss_drv"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
</config>}
install_config $config
#
# Boot modules
#
set boot_modules {
core init timer pci_drv oss_drv acpi_drv sample.raw test-audio_out }
build_boot_image $boot_modules
append qemu_args " -m 256 -soundhw ac97 -nographic"
run_genode_until forever

@ -0,0 +1,176 @@
/*
* \brief Driver probing and registration
* \author Sebasitian Sumpf
* \date 2012-11-20
*/
/*
* Copyright (C) 2012 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.
*/
#include <base/printf.h>
#include <pci_session/connection.h>
#include <pci_device/client.h>
extern "C" {
#include <oss_config.h>
#include <dde_kit/pci.h>
}
#include <quirks.h>
/**
* Driver management class
*/
class Driver
{
private:
enum { MAX_DRIVER = 10 };
oss_driver *_drivers[MAX_DRIVER + 1]; /* reigsted drivers */
Driver()
{
Genode::memset(_drivers, 0, sizeof(oss_driver *) * (MAX_DRIVER + 1));
dde_kit_pci_init();
}
/**
* Match vendor product IDs
*/
bool _match(oss_driver *driver, Pci::Device_capability &cap)
{
Pci::Device_client client(cap);
unsigned short vendor_id = client.vendor_id();
unsigned short device_id = client.device_id();
device_id_t *id_table = driver->id_table;
for (int i = 0; id_table[i].vendor; i++) {
if (id_table[i].vendor == vendor_id &&
id_table[i].product == device_id) {
PINF("Found card: vendor 0x%x: product: 0x%x driver: %s",
vendor_id, device_id, driver->name);
return true;
}
}
return false;
}
/**
* Probe device with registered drivers
*/
oss_driver *_probe_driver(Pci::Device_capability &cap)
{
for (int i = 0; _drivers[i]; i++)
if (_match(_drivers[i], cap))
return _drivers[i];
return 0;
}
public:
static Driver *d()
{
static Driver _d;
return &_d;
}
/**
* Register drivers
*/
void add(oss_driver *driver)
{
for (int i = 0; i < MAX_DRIVER; i++)
if (!_drivers[i]) {
_drivers[i] = driver;
return;
}
PWRN("Driver limit of %d reached", MAX_DRIVER);
}
/**
* Probe PCI devices with registered drivers
*/
void probe()
{
using namespace Genode;
Pci::Connection pci;
Pci::Device_capability cap = pci.first_device();
Pci::Device_capability old;
oss_driver *driver = 0;
while (cap.valid()) {
Pci::Device_client client(cap);
/* check for audio device class */
enum {
CLASS_MASK = 0xff0000,
CLASS_MULTIMEDIA = 0x40000, /* class multimedia */
};
/*
* Just test for multimedia class, since some devices (e.g., intel
* hda) do set the subclass to something different then audio (0x1).
*/
bool audio = (client.class_code() & CLASS_MASK) == CLASS_MULTIMEDIA;
if (audio && (driver = _probe_driver(cap))) {
uint8_t bus, dev, func;
client.bus_address(&bus, &dev, &func);
/* setup oss device */
oss_device_t *ossdev = new (env()->heap()) oss_device_t;
Genode::memset(ossdev, 0, sizeof(oss_device_t));
ossdev->bus = bus;
ossdev->dev = dev;
ossdev->fun = func;
/* set I/O resources */
for (int i = 0; i < Pci::Device::NUM_RESOURCES; i++) {
Pci::Device::Resource res = client.resource(i);
ossdev->res[i].base = res.base();
ossdev->res[i].size = res.size();
ossdev->res[i].io = res.type() == Pci::Device::Resource::IO ? 1 : 0;
}
ossdev->drv = driver;
/* set quirks */
setup_quirks(driver);
driver->attach(ossdev);
}
old = cap;
cap = pci.next_device(cap);
pci.release_device(old);
}
}
};
/*****************
** C interface **
*****************/
extern "C" void register_driver(struct oss_driver *driver)
{
dde_kit_log(VERBOSE_OSS, "Register driver: %s", driver->name);
Driver::d()->add(driver);
}
extern "C" void probe_drivers(void)
{
Driver::d()->probe();
}

@ -0,0 +1,67 @@
/*
* \brief OSS-dummy functions
* \author Sebastian Sumpf
* \date 20120-11-20
*/
/*
* Copyright (C) 20120-2012 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.
*/
#include <oss_config.h>
#include <oss_pci.h>
/**
* PCI
*/
int pci_write_config_dword (oss_device_t * osdev, offset_t where, unsigned int val)
{ TRACE; return 0; }
/**
* OSS
*/
void oss_pci_byteswap (oss_device_t * osdev, int mode) { }
int oss_register_device (oss_device_t * osdev, const char *name)
{ TRACE; return 0; }
void oss_unregister_device (oss_device_t * osdev)
{ TRACE; }
int oss_disable_device (oss_device_t * osdev)
{ TRACE; return 0; }
void oss_unregister_interrupts (oss_device_t * osdev)
{ TRACE; }
void * oss_get_osid (oss_device_t * osdev) { TRACE; return 0; }
int oss_get_cardinfo (int cardnum, oss_card_info * ci) { TRACE; return 0; }
oss_device_t * osdev_clone (oss_device_t * orig_osdev, int new_instance) { TRACE; return 0; }
timeout_id_t timeout (void (*func) (void *), void *arg, unsigned long long ticks) { TRACE; return 0; }
void untimeout(timeout_id_t id) { TRACE; }
/* wait queues */
void oss_reset_wait_queue (struct oss_wait_queue *wq) { }

@ -0,0 +1,27 @@
/*
* \brief Audio handling
* \author Sebastian Sumpf
* \date 2012-11-20
*/
/*
* Copyright (C) 2012 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.
*/
#ifndef _INCLUDE__AUDIO_H_
#define _INCLUDE__AUDIO_H_
/**
* Initialize audio if device is present
*/
int audio_init();
/**
* Play data of size
*/
int audio_play(short *data, int size);
#endif /* _INCLUDE__AUDIO_H_ */

@ -0,0 +1,23 @@
/*
* \brief Operating system specific device id structure
* \author Sebastian Sumpf
* \date 2012-11-20
*/
/*
* Copyright (C) 2012 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.
*/
#ifndef _INCLUDE__DEVID_H_
#define _INCLUDE__DEVID_H_
typedef struct
{
unsigned short vendor;
unsigned short product;
} device_id_t;
#endif /* _INCLUDE__DEVID_H_ */

@ -0,0 +1,19 @@
/*
* \brief Included by OSS code
* \author Sebastian Sumpf
* \date 2012-11-20
*/
/*
* Copyright (C) 2012 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.
*/
#ifndef _INCLUDE__INTTYPES_H_
#define _INCLUDE__INTTYPES_H_
#include <oss_config.h>
#endif /* _INCLUDE__INTTYPES_H_ */

@ -0,0 +1,324 @@
/*
* \brief OS specific definitions
* \author Sebastian Sumpf
* \date 2012-10-19
*/
/*
* Copyright (C) 2012 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.
*/
#ifndef _INCLUDE__OS_H_
#define _INCLUDE__OS_H_
#ifdef __cplusplus
extern "C" {
#endif
/* DDE kit includes */
#include <dde_kit/memory.h>
#include <dde_kit/printf.h>
#include <dde_kit/types.h>
#include <dde_kit/resources.h>
#include <dde_kit/timer.h>
/* OSS includes */
#include <oss_errno.h>
#include <devid.h>
#define VERBOSE_OSS 0
/*******************
** Configuration **
*******************/
/* not really used */
#define OS_VERSION
#define OSS_LICENSE "BSD"
#define OSS_BUILD_ID ""
#define OSS_COMPILE_DATE __DATE__
#define NULL 0
/***********
** Types **
***********/
typedef dde_kit_uint64_t oss_uint64_t;
typedef dde_kit_int64_t oss_int64_t;
typedef dde_kit_addr_t oss_native_word;
typedef void * oss_dma_handle_t;
typedef int oss_mutex_t;
typedef int oss_poll_event_t;
typedef dde_kit_size_t size_t;
typedef void dev_info_t;
typedef int pid_t;
typedef dde_kit_addr_t offset_t;
typedef dde_kit_addr_t addr_t;
typedef unsigned timeout_id_t;
typedef dde_kit_uint8_t uint8_t;
typedef dde_kit_uint16_t uint16_t;
typedef dde_kit_int16_t int16_t;
typedef dde_kit_uint32_t uint32_t;
typedef dde_kit_int32_t int32_t;
typedef dde_kit_uint64_t uint64_t;
typedef dde_kit_int64_t int64_t;
struct fileinfo
{
int mode;
int acc_flags;
};
#define ISSET_FILE_FLAG(fileinfo, flag) (fileinfo->acc_flags & (flag) ? 1 : 0)
enum uio_rw { UIO_READ, UIO_WRITE };
/*
* IO vector
*/
typedef struct uio
{
char *data;
size_t size;
enum uio_rw rw;
} uio_t;
/*
* Copy uio vector data to address
*/
int uiomove (void *address, size_t nbytes, enum uio_rw rwflag, uio_t * uio_p);
/*
* Debugging
*/
enum {
CE_PANIC = 1,
CE_WARN = 2,
CE_NOTE = 3,
CE_CONT = 4,
};
#define cmn_err(level, format, arg...) \
{ \
if (level < VERBOSE_OSS) \
dde_kit_printf(format, ##arg); \
}
#define DDB(x) x
/***********
** Posix **
***********/
/**************
** string.h **
**************/
void *memcpy(void *dest, const void *src, size_t n);
void *memset(void *s, int c, size_t n);
int strcmp(const char *s1, const char *s2);
char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t n);
size_t strlen(const char *);
/*************
** stdio.h **
*************/
int sprintf(char *str, const char *format, ...);
/*************
** fcntl.h **
*************/
enum {
O_ACCMODE = 0x3,
O_NONBLOCK = 0x40000,
};
/************
** poll.h **
************/
enum {
POLLIN,
POLLRDNORM,
POLLWRNORM,
POLLOUT,
};
/*********
** OSS **
*********/
#define TRACE \
{ \
if (VERBOSE_OSS) \
dde_kit_printf("\033[32m%s\033[0m called, not implemented\n", __PRETTY_FUNCTION__); \
}
#define TRACEN(name) \
{ \
if (VERBOSE_OSS) \
dde_kit_printf("\033[32m%s\033[0m called, not implemented\n", name); \
}
#define HZ DDE_KIT_HZ
#define GET_JIFFIES() jiffies
#define MUTEX_INIT(osdev, mutex, hier)
#define MUTEX_ENTER_IRQDISABLE(mutex, flags) { flags = 1; }
#define MUTEX_ENTER(mutex, flags) { flags = 1; }
#define MUTEX_EXIT(mutex, flags) { flags--; }
#define MUTEX_EXIT_IRQRESTORE(mutex, flags) { flags--; }
#define MUTEX_CLEANUP(mutex)
#define GET_PROCESS_NAME(f) NULL
#define GET_PROCESS_PID(p) -1
#define KERNEL_MALLOC(size) (dde_kit_large_malloc(size))
#define KERNEL_FREE(ptr) (dde_kit_large_free(ptr))
void * dma_alloc(oss_native_word *phys, size_t size);
#define CONTIG_MALLOC(osdev, sz, memlimit, phaddr, handle) dma_alloc(phaddr, sz)
#define CONTIG_FREE(osdev, p, sz, handle) KERNEL_FREE(p)
/*
* OSS device */
struct resource
{
unsigned base;
unsigned size;
unsigned io;
};
struct _oss_device_t
{
void *devc;
int cardnum;
int available;
char *hw_info;
char nick[32];
char handle[32];
/* audio */
int num_audio_engines;
int num_audiorec;
int num_audioduplex;
/* mixer */
int num_mixerdevs;
/* midi */
int num_mididevs;
/* PCI/IRQ */
int bus, dev, fun;
oss_tophalf_handler_t irq_top;
oss_bottomhalf_handler_t irq_bottom;
struct resource res[5];
int first_mixer; /* This must be set to -1 by osdev_create() */
struct oss_driver *drv; /* driver for this device */
};
/*
* I/O mem/ports
*/
void * pci_map(struct _oss_device_t *osdev, int resource, addr_t phys, size_t size);
#define MAP_PCI_MEM(osdev, ix, phaddr, size) pci_map(osdev, ix, phaddr, size)
oss_native_word pci_map_io(struct _oss_device_t *osdev, int resource, unsigned base);
#define MAP_PCI_IOADDR(osdev, nr, io) pci_map_io(osdev, nr, io)
#define UNMAP_PCI_MEM(osdev, ix, ph, virt, size) TRACEN("UNMAP_PCI_MEM")
#define UNMAP_PCI_IOADDR(osdev, ix) {}
struct oss_driver
{
char *name;
device_id_t *id_table;
int (*attach)(struct _oss_device_t *osdev);
int (*detach)(struct _oss_device_t *osdev);
unsigned char (*inb_quirk)(struct _oss_device_t *osdev, addr_t port);
};
/*
* Used for blocking, is unblocked during IRQs
*/
struct oss_wait_queue
{
int blocked;
};
void oss_udelay(unsigned long ticks);
timeout_id_t timeout (void (*func) (void *), void *arg, unsigned long long ticks);
void untimeout(timeout_id_t id);
/*********
** PCI **
*********/
#define PCI_READB(odev, addr) (*(volatile unsigned char *)(addr))
#define PCI_WRITEB(osdev, addr, value) (*(volatile unsigned char *)(addr) = (value))
#define PCI_READW(odev, addr) (*(volatile unsigned short *)(addr))
#define PCI_WRITEW(osdev, addr, value) (*(volatile unsigned short *)(addr) = (value))
#define PCI_READL(odev, addr) (*(volatile unsigned int *)(addr))
#define PCI_WRITEL(osdev, addr, value) (*(volatile unsigned int *)(addr) = (value))
/*************
** Port IO **
*************/
unsigned char io_inb(struct _oss_device_t *osdev, addr_t port);
#define INB(osdev, port) io_inb(osdev, port)
#define INW(osdev, port) dde_kit_inw(port)
#define INL(osdev, port) dde_kit_inl(port)
#define OUTB(osdev, val, port) dde_kit_outb(port, val)
#define OUTW(osdev, val, port) dde_kit_outw(port, val)
#define OUTL(osdev, val, port) dde_kit_outl(port, val)
/**********************
** Genode interface **
**********************/
void register_driver(struct oss_driver *driver);
void probe_drivers(void);
void request_irq(unsigned irq, struct _oss_device_t *osdev);
#ifdef __cplusplus
}
#endif
#endif /* _INCLUDE__OS_H_ */

@ -0,0 +1,24 @@
/*
* \brief Driver quirks interface
* \author Sebastian Sumpf
* \date 2012-11-27
*/
/*
* Copyright (C) 2012 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.
*/
#ifndef _INCLUDE__QUIRKS_H_
#define _INCLUDE__QUIRKS_H_
struct oss_driver;
/**
* Check and possibly set quirks for given driver
*/
void setup_quirks(struct oss_driver *drv);
#endif /* _INCLUDE__QUIRKS_H_ */

@ -0,0 +1,102 @@
/*
* \brief Main-signal receiver and signal-helper functions
* \author Sebastian Sumpf <sebastian.sumpf@genode-labs.com>
* \date 2012-05-23
*/
/*
* Copyright (C) 2012 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.
*/
#ifndef _SIGNAL_H_
#define _SIGNAL_H_
#include <base/env.h>
#include <base/printf.h>
#include <base/signal.h>
/**
* Context base for IRQ, Timer, etc.
*/
class Driver_context : public Genode::Signal_context
{
public:
/**
* Perform context operation
*/
virtual void handle() = 0;
virtual char const *debug() = 0;
};
/**
* This singelton currently received all signals
*/
class Service_handler
{
private:
Genode::Signal_receiver *_receiver;
Service_handler() { }
public:
static Service_handler * s()
{
static Service_handler _s;
return &_s;
}
void receiver(Genode::Signal_receiver *recv) { _receiver = recv; }
void check_signal(bool block = true)
{
while (_receiver->pending() || block) {
Genode::Signal s = _receiver->wait_for_signal();
/* handle signal IRQ, timer, or event signals */
Driver_context *ctx = static_cast<Driver_context *>(s.context());
ctx->handle();
block = false;
}
}
};
/**
* Helper that holds sender and receiver
*/
class Signal_helper
{
private:
Genode::Signal_receiver *_receiver;
Genode::Signal_transmitter *_sender;
public:
Signal_helper(Genode::Signal_receiver *recv)
: _receiver(recv),
_sender(new (Genode::env()->heap()) Genode::Signal_transmitter()) { }
Genode::Signal_receiver *receiver() const { return _receiver; }
Genode::Signal_transmitter *sender() const { return _sender; }
};
namespace Irq
{
void init(Genode::Signal_receiver *recv);
void check_irq(bool block = false);
}
#endif /* _SIGNAL_H_ */

@ -0,0 +1,294 @@
/*
* \brief Audio-session-entry point
* \author Sebastian Sumpf
* \date 2012-11-20
*/
/*
* Copyright (C) 2012 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.
*/
extern "C" {
#include <oss_config.h>
}
#include <base/env.h>
#include <base/sleep.h>
#include <root/component.h>
#include <cap_session/connection.h>
#include <audio_out_session/rpc_object.h>
#include <util/misc_math.h>
#include <audio.h>
#include <signal.h>
using namespace Genode;
static const bool verbose = false;
static bool audio_out_active = false;
/**
* Packet-stream signal dispatcher
*
* TODO: Move to generic code
*/
template <typename T>
class Signal_dispatcher : public Driver_context,
public Genode::Signal_context_capability
{
private:
T &obj;
void (T::*member) ();
Genode::Signal_receiver *sig_rec;
public:
/**
* Constructor
*
* \param sig_rec signal receiver to associate the signal
* handler with
* \param obj,member object and member function to call when
* the signal occurs
*/
Signal_dispatcher(Genode::Signal_receiver *sig_rec,
T &obj, void (T::*member)())
:
Genode::Signal_context_capability(sig_rec->manage(this)),
obj(obj), member(member),
sig_rec(sig_rec)
{ }
~Signal_dispatcher() { sig_rec->dissolve(this); }
void handle() { (obj.*member)(); }
char const *debug() { return "Signal_dispatcher"; }
};
namespace Audio_out {
class Session_component;
enum Channel_number { LEFT, RIGHT, MAX_CHANNELS, INVALID = MAX_CHANNELS };
static Session_component *channel_acquired[MAX_CHANNELS];
class Session_component : public Session_rpc_object
{
private:
Ram_dataspace_capability _ds;
Channel_number _channel;
Signal_dispatcher<Session_component> _process_packet_dispatcher;
Ram_dataspace_capability _alloc_dataspace(size_t size)
{
_ds = env()->ram_session()->alloc(size);
return _ds;
}
void _process_packets()
{
/* handle audio-out packets */
Session_component *left = channel_acquired[LEFT],
*right = channel_acquired[RIGHT];
while (left->channel()->packet_avail() &&
right->channel()->packet_avail() &&
left->channel()->ready_to_ack() &&
right->channel()->ready_to_ack()) {
/* get packets for channels */
Packet_descriptor p[MAX_CHANNELS];
static short data[2 * PERIOD];
p[LEFT] = left->channel()->get_packet();
p[RIGHT] = right->channel()->get_packet();
/* convert float to S16LE */
for (int i = 0; i < 2 * PERIOD; i += 2) {
data[i] = left->channel()->packet_content(p[LEFT])[i / 2] * 32767;
data[i + 1] = right->channel()->packet_content(p[RIGHT])[i / 2] * 32767;
}
if (verbose)
PDBG("play packet");
/* send to driver */
int err;
if (audio_out_active)
if ((err = audio_play(data, 4 * PERIOD)))
PWRN("Error %d during playback", err);
/* acknowledge packet to the client */
if (p[LEFT].valid())
left->channel()->acknowledge_packet(p[LEFT]);
if (p[RIGHT].valid())
right->channel()->acknowledge_packet(p[RIGHT]);
}
}
public:
Session_component(Channel_number channel, size_t buffer_size,
Rpc_entrypoint &ep, Signal_receiver *sig_rec)
: Session_rpc_object(_alloc_dataspace(buffer_size), ep), _channel(channel),
_process_packet_dispatcher(sig_rec, *this,
&Session_component::_process_packets)
{
Audio_out::channel_acquired[_channel] = this;
Session_rpc_object::_channel.sigh_packet_avail(_process_packet_dispatcher);
Session_rpc_object::_channel.sigh_ready_to_ack(_process_packet_dispatcher);
}
~Session_component()
{
Audio_out::channel_acquired[_channel] = 0;
env()->ram_session()->free(_ds);
}
/*********************************
** Audio-out-session interface **
*********************************/
void flush()
{
while (channel()->packet_avail())
channel()->acknowledge_packet(channel()->get_packet());
}
void sync_session(Session_capability audio_out_session) { }
};
static bool channel_number_from_string(const char *name,
Channel_number *out_number)
{
static struct Names {
const char *name;
Channel_number number;
} names[] = {
{ "left", LEFT }, { "front left", LEFT },
{ "right", RIGHT }, { "front right", RIGHT },
{ 0, INVALID }
};
for (Names *n = names; n->name; ++n)
if (!Genode::strcmp(name, n->name)) {
*out_number = n->number;
return true;
}
return false;
}
/**
* Session creation policy for our service
*/
struct Root_policy
{
void aquire(const char *args)
{
size_t ram_quota =
Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
size_t buffer_size =
Arg_string::find_arg(args, "buffer_size").ulong_value(0);
size_t session_size =
align_addr(sizeof(Session_component), 12);
if ((ram_quota < session_size) ||
(buffer_size > ram_quota - session_size)) {
PERR("insufficient 'ram_quota', got %zd, need %zd",
ram_quota, buffer_size + session_size);
throw Root::Quota_exceeded();
}
char channel_name[16];
Channel_number channel_number;
Arg_string::find_arg(args, "channel").string(channel_name,
sizeof(channel_name),
"left");
if (!channel_number_from_string(channel_name, &channel_number))
throw Root::Invalid_args();
if (channel_acquired[channel_number])
throw Root::Unavailable();
}
void release() { }
};
typedef Root_component<Session_component, Root_policy> Root_component;
/*
* Root component, handling new session requests.
*/
class Root : public Root_component
{
private:
Rpc_entrypoint &_channel_ep;
Signal_receiver *_sig_rec;
protected:
Session_component *_create_session(const char *args)
{
size_t buffer_size =
Arg_string::find_arg(args, "buffer_size").ulong_value(0);
if (!audio_out_active)
throw Root::Unavailable();
char channel_name[16];
Channel_number channel_number = INVALID;
Arg_string::find_arg(args, "channel").string(channel_name,
sizeof(channel_name),
"left");
channel_number_from_string(channel_name, &channel_number);
return new (md_alloc())
Session_component(channel_number, buffer_size, _channel_ep, _sig_rec);
}
public:
Root(Rpc_entrypoint *session_ep, Allocator *md_alloc, Signal_receiver *sig_rec)
: Root_component(session_ep, md_alloc), _channel_ep(*session_ep), _sig_rec(sig_rec)
{ }
};
}
int main()
{
static Signal_receiver recv;
enum { STACK_SIZE = 1024 * sizeof(addr_t) };
static Cap_connection cap;
static Rpc_entrypoint ep(&cap, STACK_SIZE, "audio_ep");
dde_kit_timer_init(0, 0);
Irq::init(&recv);
Service_handler::s()->receiver(&recv);
/* probe drivers */
probe_drivers();
audio_out_active = audio_init() ? false : true;
if (audio_out_active) {
static Audio_out::Root audio_root(&ep, env()->heap(), &recv);
env()->parent()->announce(ep.manage(&audio_root));
}
while (true)
Service_handler::s()->check_signal(true);
return 1;
}

@ -0,0 +1,44 @@
/*
* \brief This file is included for every driver
* \author Sebastian Sumpf
* \date 2012-11-20
*
* See: Files in 'target/build/', which are generated by 'srcconf'
*/
/*
* Copyright (C) 2012 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.
*/
#include <oss_config.h>
/* Dummies */
#define DEFINE_CLASS_0(a,b,c,d)
#define TUNABLE_INT(a,b)
#define DRIVER_MODULE(name, b, c, d, e, f)
/* defined in specific driver file */
extern int DRIVER_ATTACH(struct _oss_device_t *);
extern int DRIVER_DETACH(struct _oss_device_t *);
/* setup driver structure */
static struct oss_driver driver =
{
.name = DRIVER_NICK,
.id_table = id_table,
.attach = DRIVER_ATTACH,
.detach = DRIVER_DETACH
};
/**
* Register driver upon startup
*/
static void __attribute__((constructor)) init(void)
{
register_driver(&driver);
}

@ -0,0 +1,413 @@
/*
* \brief OSS environment
* \author Sebastian Sumpf
* \date 2012-11-20
*/
/*
* Copyright (C) 2012 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.
*/
#include <timer_session/connection.h>
extern "C"
{
#include <oss_config.h>
#include <oss_pci.h>
#include <dde_kit/pci.h>
#include <dde_kit/pgtab.h>
#include <dde_kit/resources.h>
}
#include <audio.h>
#include <signal.h>
/******************
** oss_config.h **
******************/
int oss_num_cards = 0;
/**********
** os.h **
**********/
using namespace Genode;
static Timer::Connection _timer;
void oss_udelay(unsigned long usecs)
{
unsigned long start = jiffies;
/* check for IRQs etc */
Service_handler::s()->check_signal(false);
unsigned delta = (jiffies - start) * 10000;
/* return if already expired */
if (delta > usecs)
return;
usecs -= delta;
/* delay */
_timer.msleep(usecs < 1000 ? 1 : usecs / 1000);
}
/*********
** PCI **
*********/
extern "C" int pci_read_config_byte(oss_device_t *osdev, offset_t where, unsigned char *val)
{
dde_kit_pci_readb(osdev->bus, osdev->dev, osdev->fun, where, val);
return *val == ~0 ? -1 : 0;
}
extern "C" int pci_write_config_byte(oss_device_t *osdev, offset_t where, unsigned char val)
{
dde_kit_pci_writeb(osdev->bus, osdev->dev, osdev->fun, where, val);
return 0;
}
extern "C" int pci_read_config_word(oss_device_t *osdev, offset_t where, unsigned short *val)
{
dde_kit_pci_readw(osdev->bus, osdev->dev, osdev->fun, where, val);
return *val == ~0 ? -1 : 0;
}
extern "C" int pci_write_config_word(oss_device_t *osdev, offset_t where, unsigned short val)
{
dde_kit_pci_writew(osdev->bus, osdev->dev, osdev->fun, where, val);
return 0;
}
extern "C" int pci_read_config_dword(oss_device_t *osdev, offset_t where, unsigned int *val)
{
dde_kit_pci_readl(osdev->bus, osdev->dev, osdev->fun, where, val);
return *val == ~0U ? -1 : 0;
}
extern "C" int pci_read_config_irq(oss_device_t *osdev, offset_t where, unsigned char *val)
{
int ret = pci_read_config_byte(osdev, where, val);
return ret;
}
extern "C" void *pci_map(oss_device_t *osdev, int resource, addr_t phys, size_t size)
{
addr_t addr;
if (dde_kit_request_mem(phys, size, 0, &addr))
return 0;
return (void *)addr;
}
extern "C" oss_native_word pci_map_io(struct _oss_device_t *osdev, int resource, unsigned base)
{
if (osdev->res[resource].io)
dde_kit_request_io(osdev->res[resource].base, osdev->res[resource].size);
return base;
}
/*************
** PORT/IO **
*************/
unsigned char io_inb(struct _oss_device_t *osdev, addr_t port)
{
return osdev->drv->inb_quirk ? osdev->drv->inb_quirk(osdev, port)
: dde_kit_inb(port);
}
/*********
** OSS **
*********/
extern "C" int oss_register_interrupts(oss_device_t * osdev, int intrnum,
oss_tophalf_handler_t top,
oss_bottomhalf_handler_t bottom)
{
if (!osdev || intrnum != 0 || !top) {
PWRN("Bad interrupt index %d, bad device (%p), or bad handler %p",
intrnum, osdev, top);
return OSS_EINVAL;
}
unsigned char irq;
pci_read_config_irq(osdev, PCI_INTERRUPT_LINE, &irq);
/* setup bottom and top half handlers */
osdev->irq_top = top;
osdev->irq_bottom = bottom;
request_irq(irq, osdev);
return 0;
}