OSS: Open Sound System server
Currently supports Intel HDA, AC97, and ES1370 audio cards. See README for further details.
This commit is contained in:
parent
8ac3209aa8
commit
7d8f446475
7
README
7
README
|
@ -147,9 +147,14 @@ The Genode source tree is composed of the following subdirectories:
|
||||||
|
|
||||||
:'dde_ipxe':
|
:'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.
|
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':
|
:'qt4':
|
||||||
|
|
||||||
This source-code repository contains the Genode version of Qt4 framework.
|
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 @@
|
||||||
|
/* dummy */
|
|
@ -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 @@
|
||||||
|
/* dummy */
|
|
@ -0,0 +1 @@
|
||||||
|
/* dummy */
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" int uiomove (void *address, size_t nbytes, enum uio_rw rwflag, uio_t * uio)
|
||||||
|
{
|
||||||
|
if (rwflag != uio->rw || nbytes > uio->size)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
void *target = rwflag == UIO_READ ? (void *)uio->data : address;
|
||||||
|
void *source = rwflag == UIO_READ ? address : (void *)uio->data;
|
||||||
|
nbytes = nbytes > uio->size ? uio->size : nbytes;
|
||||||
|
Genode::memcpy(target, source, nbytes);
|
||||||
|
uio->size -= nbytes;
|
||||||
|
uio->data += nbytes;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait queues
|
||||||
|
*/
|
||||||
|
extern "C" int oss_sleep(struct oss_wait_queue *wq, oss_mutex_t * mutex, int ticks,
|
||||||
|
oss_native_word * flags, unsigned int *status)
|
||||||
|
{
|
||||||
|
*status = 0;
|
||||||
|
|
||||||
|
if (!wq)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
wq->blocked = 1;
|
||||||
|
unsigned long start = jiffies;
|
||||||
|
|
||||||
|
while (wq->blocked) {
|
||||||
|
Irq::check_irq(true);
|
||||||
|
|
||||||
|
if (jiffies - start > (unsigned long)ticks) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" void oss_wakeup(struct oss_wait_queue *wq, oss_mutex_t * mutex,
|
||||||
|
oss_native_word * flags, short events)
|
||||||
|
{
|
||||||
|
if (wq)
|
||||||
|
wq->blocked = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" oss_wait_queue_t *oss_create_wait_queue(oss_device_t * osdev, const char *name)
|
||||||
|
{
|
||||||
|
return new (env()->heap()) oss_wait_queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*********
|
||||||
|
** DMA **
|
||||||
|
*********/
|
||||||
|
|
||||||
|
extern "C" void * dma_alloc(oss_native_word *phys, size_t size)
|
||||||
|
{
|
||||||
|
void *virt = KERNEL_MALLOC(size);
|
||||||
|
*phys = (oss_native_word)dde_kit_pgtab_get_physaddr(virt);
|
||||||
|
|
||||||
|
return virt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" int __oss_alloc_dmabuf (int dev, dmap_p dmap, unsigned int alloc_flags,
|
||||||
|
oss_uint64_t maxaddr, int direction)
|
||||||
|
{
|
||||||
|
/* allocate DMA buffer depending on flags */
|
||||||
|
oss_native_word phys;
|
||||||
|
int size = 64 * 1024;
|
||||||
|
|
||||||
|
if (dmap->dmabuf)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (dmap->flags & DMAP_SMALLBUF)
|
||||||
|
size = SMALL_DMABUF_SIZE;
|
||||||
|
if (dmap->flags & DMAP_MEDIUMBUF)
|
||||||
|
size = MEDIUM_DMABUF_SIZE;
|
||||||
|
|
||||||
|
if ((alloc_flags & DMABUF_SIZE_16BITS) && size > 32 * 1024)
|
||||||
|
size = 32 * 1024;
|
||||||
|
if (alloc_flags & DMABUF_LARGE)
|
||||||
|
size = 356 * 1024;
|
||||||
|
|
||||||
|
if (!(dmap->dmabuf = (unsigned char*)dma_alloc(&phys, size)))
|
||||||
|
return OSS_ENOMEM;
|
||||||
|
|
||||||
|
dmap->buffsize = size;
|
||||||
|
dmap->dmabuf_phys = phys;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void oss_free_dmabuf (int dev, dmap_p dmap)
|
||||||
|
{
|
||||||
|
if (!dmap->dmabuf)
|
||||||
|
return;
|
||||||
|
|
||||||
|
KERNEL_FREE(dmap->dmabuf);
|
||||||
|
dmap->dmabuf = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************
|
||||||
|
** string.h **
|
||||||
|
**************/
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
size_t strlen(const char *s)
|
||||||
|
{
|
||||||
|
return Genode::strlen(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *strcpy(char *to, const char *from)
|
||||||
|
{
|
||||||
|
char *save = to;
|
||||||
|
|
||||||
|
for (; (*to = *from); ++from, ++to);
|
||||||
|
return(save);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *strncpy(char *to, const char *from, size_t n)
|
||||||
|
{
|
||||||
|
return Genode::strncpy(to, from, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int strcmp(const char *s1, const char *s2)
|
||||||
|
{
|
||||||
|
return Genode::strcmp(s1, s2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int sprintf(char *str, const char *format, ...)
|
||||||
|
{
|
||||||
|
|
||||||
|
va_list list;
|
||||||
|
va_start(list, format);
|
||||||
|
|
||||||
|
String_console sc(str, 1024);
|
||||||
|
|
||||||
|
sc.vprintf(format, list);
|
||||||
|
|
||||||
|
va_end(list);
|
||||||
|
|
||||||
|
return sc.len();
|
||||||
|
}
|
||||||
|
} /* extern "C" */
|
||||||
|
|
||||||
|
|
||||||
|
static oss_cdev_drv_t *dsp_drv; /* DSP device */
|
||||||
|
static oss_cdev_drv_t *mix_drv; /* mixer */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal ioctl
|
||||||
|
*/
|
||||||
|
int ioctl_dsp(int cmd, ioctl_arg arg)
|
||||||
|
{
|
||||||
|
return dsp_drv->ioctl(0, 0, cmd, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup DSP
|
||||||
|
*/
|
||||||
|
int audio_init()
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!dsp_drv) {
|
||||||
|
PERR("No output devices");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open device */
|
||||||
|
int new_dev = 0;
|
||||||
|
if (dsp_drv->open(0, 0, 0, 0, 0, &new_dev)) {
|
||||||
|
PERR("Error opening sound card");
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set fragment policy (TODO: make configurable) */
|
||||||
|
int policy = 8;
|
||||||
|
if (ioctl_dsp(SNDCTL_DSP_POLICY, &policy) == -1)
|
||||||
|
PERR("Error setting policy");
|
||||||
|
|
||||||
|
/* set format */
|
||||||
|
int val = AFMT_S16_LE;
|
||||||
|
if (ioctl_dsp(SNDCTL_DSP_SETFMT, &val) == -1) {
|
||||||
|
PERR("Error setting audio format to S16_LE");
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set two channels */
|
||||||
|
val = 2;
|
||||||
|
if (ioctl_dsp(SNDCTL_DSP_CHANNELS, &val) == -1) {
|
||||||
|
PERR("Error enabling two channels");
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set sample rate */
|
||||||
|
val = 44100;
|
||||||
|
if (ioctl_dsp(SNDCTL_DSP_SPEED, &val) == -1) {
|
||||||
|
PERR("Error setting sample rate to %d HZ", val);
|
||||||
|
return -5;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int audio_play(short *data, int size)
|
||||||
|
{
|
||||||
|
uio_t io = { (char *)data, size, UIO_WRITE };
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if ((ret = dsp_drv->write(0, 0, &io, size)) != size)
|
||||||
|
PERR("Error writing data s: %d r: %d func %p", size, ret, dsp_drv->write);
|
||||||
|
|
||||||
|
Irq::check_irq();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" void oss_install_chrdev (oss_device_t * osdev, char *name, int dev_class,
|
||||||
|
int instance, oss_cdev_drv_t * drv, int flags)
|
||||||
|
{
|
||||||
|
/* only look for first mixer and first dsp */
|
||||||
|
if (instance != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (dev_class == OSS_DEV_DSP) {
|
||||||
|
PINF("Found dsp: '%s'", name ? name : "<noname>");
|
||||||
|
dsp_drv = drv;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev_class == OSS_DEV_MIXER) {
|
||||||
|
PINF("Found mixer: '%s'", name ? name : "<noname>");
|
||||||
|
mix_drv = drv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* \brief Drivers quirks
|
||||||
|
* \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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* OSS includes */
|
||||||
|
extern "C" {
|
||||||
|
#include <oss_config.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <quirks.h>
|
||||||
|
|
||||||
|
/* Genode includes */
|
||||||
|
#include <base/printf.h>
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Qemu es1370 emulation does not support 'inb' for the serial interface
|
||||||
|
* control register (ports 0x20 - 0x23)
|
||||||
|
*/
|
||||||
|
static unsigned char qemu_es1370_inb_quirk(_oss_device_t *osdev, addr_t port)
|
||||||
|
{
|
||||||
|
unsigned base = osdev->res[0].base;
|
||||||
|
unsigned addr = port - base;
|
||||||
|
|
||||||
|
if (addr < 0x20 && addr > 0x23)
|
||||||
|
return dde_kit_inb(port);
|
||||||
|
|
||||||
|
unsigned val = dde_kit_inl(base + 0x20) >> (8 * (addr - 0x20));
|
||||||
|
return val & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void setup_quirks(struct oss_driver *drv)
|
||||||
|
{
|
||||||
|
if (!strcmp(drv->name, "oss_audiopci"))
|
||||||
|
drv->inb_quirk = qemu_es1370_inb_quirk;
|
||||||
|
}
|
|
@ -0,0 +1,205 @@
|
||||||
|
/*
|
||||||
|
* \brief Signal context for IRQ's
|
||||||
|
* \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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <oss_config.h>
|
||||||
|
#include <dde_kit/interrupt.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
/* our local incarnation of sender and receiver */
|
||||||
|
static Signal_helper *_signal = 0;
|
||||||
|
static Genode::Lock _irq_sync(Genode::Lock::LOCKED);
|
||||||
|
static Genode::Lock _irq_wait(Genode::Lock::LOCKED);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This contains the Linux-driver handlers
|
||||||
|
*/
|
||||||
|
struct Irq_handler : Genode::List<Irq_handler>::Element
|
||||||
|
{
|
||||||
|
oss_device_t *osdev; /* OSS device */
|
||||||
|
|
||||||
|
Irq_handler(oss_device_t *osdev)
|
||||||
|
: osdev(osdev) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signal context for IRQs
|
||||||
|
*/
|
||||||
|
class Irq_context : public Driver_context,
|
||||||
|
public Genode::List<Irq_context>::Element
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
unsigned int _irq; /* IRQ number */
|
||||||
|
Genode::List<Irq_handler> _handler_list; /* List of registered handlers */
|
||||||
|
Genode::Signal_context_capability _ctx_cap; /* capability for this context */
|
||||||
|
|
||||||
|
static Genode::List<Irq_context> *_list()
|
||||||
|
{
|
||||||
|
static Genode::List<Irq_context> _l;
|
||||||
|
return &_l;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find context for given IRQ number
|
||||||
|
*/
|
||||||
|
static Irq_context *_find_ctx(unsigned int irq)
|
||||||
|
{
|
||||||
|
for (Irq_context *i = _list()->first(); i; i = i->next())
|
||||||
|
if (i->_irq == irq)
|
||||||
|
return i;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* called by the DDE kit upon IRQ */
|
||||||
|
static void _dde_handler(void *irq)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Make sure there is only one interrupt handled at a time, since dde_kit
|
||||||
|
* will use one thread per IRQ
|
||||||
|
*/
|
||||||
|
static Genode::Lock handler_lock;
|
||||||
|
Genode::Lock::Guard guard(handler_lock);
|
||||||
|
|
||||||
|
/* unlock if main thread is waiting */
|
||||||
|
_irq_wait.unlock();
|
||||||
|
|
||||||
|
Irq_context *ctx = static_cast<Irq_context *>(irq);
|
||||||
|
|
||||||
|
/* set context & submit signal */
|
||||||
|
_signal->sender()->context(ctx->_ctx_cap);
|
||||||
|
_signal->sender()->submit();
|
||||||
|
|
||||||
|
/* wait for interrupt to get acked at device side */
|
||||||
|
_irq_sync.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call one IRQ handler
|
||||||
|
*/
|
||||||
|
inline bool _handle_one(Irq_handler *h)
|
||||||
|
{
|
||||||
|
bool handled = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* It might be that the next interrupt triggers right after the device has
|
||||||
|
* acknowledged the IRQ
|
||||||
|
*/
|
||||||
|
oss_device_t *osdev = h->osdev;
|
||||||
|
do {
|
||||||
|
if (!osdev->irq_top(osdev))
|
||||||
|
return handled;
|
||||||
|
|
||||||
|
if (osdev->irq_bottom)
|
||||||
|
osdev->irq_bottom(osdev);
|
||||||
|
|
||||||
|
handled = true;
|
||||||
|
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call all handlers registered for this context
|
||||||
|
*/
|
||||||
|
bool _handle()
|
||||||
|
{
|
||||||
|
bool handled = false;
|
||||||
|
/* report IRQ to all clients */
|
||||||
|
for (Irq_handler *h = _handler_list.first(); h; h = h->next()) {
|
||||||
|
|
||||||
|
handled |= _handle_one(h);
|
||||||
|
dde_kit_log(0, "IRQ: %u ret: %u h: %p dev: %p", _irq, handled, h->osdev->irq_top, h->osdev);
|
||||||
|
}
|
||||||
|
/* interrupt should be acked at device now */
|
||||||
|
_irq_sync.unlock();
|
||||||
|
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Irq_context(unsigned int irq)
|
||||||
|
: _irq(irq),
|
||||||
|
_ctx_cap(_signal->receiver()->manage(this))
|
||||||
|
{
|
||||||
|
/* register at DDE (shared) */
|
||||||
|
int ret = dde_kit_interrupt_attach(_irq, 0, 0, _dde_handler, this);
|
||||||
|
if (ret)
|
||||||
|
PERR("Interrupt attach return %d for IRQ %u", ret, irq);
|
||||||
|
|
||||||
|
_list()->insert(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void handle() { _handle(); }
|
||||||
|
const char *debug() { return "Irq_context"; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request an IRQ
|
||||||
|
*/
|
||||||
|
static void request_irq(unsigned int irq, oss_device_t *osdev)
|
||||||
|
{
|
||||||
|
Irq_handler *h = new(Genode::env()->heap()) Irq_handler(osdev);
|
||||||
|
Irq_context *ctx = _find_ctx(irq);
|
||||||
|
|
||||||
|
/* if this IRQ is not registered */
|
||||||
|
if (!ctx)
|
||||||
|
ctx = new (Genode::env()->heap()) Irq_context(irq);
|
||||||
|
|
||||||
|
/* register Linux handler */
|
||||||
|
ctx->_handler_list.insert(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool check_irq()
|
||||||
|
{
|
||||||
|
bool handled = false;
|
||||||
|
for (Irq_context *i = _list()->first(); i; i = i->next())
|
||||||
|
handled |= i->_handle();
|
||||||
|
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wait()
|
||||||
|
{
|
||||||
|
_irq_wait.lock();
|
||||||
|
check_irq();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void Irq::init(Genode::Signal_receiver *recv) {
|
||||||
|
_signal = new (Genode::env()->heap()) Signal_helper(recv); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***********************
|
||||||
|
** linux/interrupt.h **
|
||||||
|
***********************/
|
||||||
|
|
||||||
|
extern "C" void request_irq(unsigned int irq, oss_device_t *osdev)
|
||||||
|
{
|
||||||
|
dde_kit_log(VERBOSE_OSS, "Request irq %u handler %p", irq, osdev->irq_top);
|
||||||
|
Irq_context::request_irq(irq, osdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Irq::check_irq(bool block)
|
||||||
|
{
|
||||||
|
if (!Irq_context::check_irq() && block)
|
||||||
|
Irq_context::wait();
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
TARGET = oss_drv
|
||||||
|
REQUIRES = x86_32
|
||||||
|
LIBS = cxx env dde_kit signal server
|
||||||
|
CONTRIB_DIR = $(REP_DIR)/contrib
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
CC_OPT += -Ulinux -D_KERNEL -fno-omit-frame-pointer
|
||||||
|
|
||||||
|
#
|
||||||
|
# Silence C code
|
||||||
|
#
|
||||||
|
CC_C_OPT = -Wno-unused-variable -Wno-unused-but-set-variable \
|
||||||
|
-Wno-implicit-function-declaration \
|
||||||
|
-Wno-sign-compare
|
||||||
|
|
||||||
|
#
|
||||||
|
# Native Genode sources
|
||||||
|
#
|
||||||
|
SRC_CC = os.cc main.cc driver.cc irq.cc quirks.cc
|
||||||
|
SRC_C = dummies.c
|
||||||
|
|
||||||
|
#
|
||||||
|
# Driver sources
|
||||||
|
#
|
||||||
|
DRV = $(addprefix $(CONTRIB_DIR)/,kernel/drv target)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Framwork sources
|
||||||
|
#
|
||||||
|
FRAMEWORK = $(addprefix $(CONTRIB_DIR)/kernel/framework/,\
|
||||||
|
osscore audio mixer vmix_core midi ac97)
|
||||||
|
|
||||||
|
# find C files
|
||||||
|
SRC_C += $(shell find $(DRV) $(FRAMEWORK) -name *.c -exec basename {} ";")
|
||||||
|
|
||||||
|
# find directories for VPATH
|
||||||
|
PATHS = $(shell find $(DRV) $(FRAMEWORK) -type d)
|
||||||
|
|
||||||
|
# add include directories
|
||||||
|
INC_DIR += $(CONTRIB_DIR)/kernel/framework/include $(CONTRIB_DIR)/include \
|
||||||
|
$(PRG_DIR)/include $(PRG_DIR)
|
||||||
|
|
||||||
|
|
||||||
|
vpath %.cc $(PRG_DIR)/signal
|
||||||
|
vpath %.c $(PATHS)
|
|
@ -25,7 +25,7 @@ namespace Audio_out {
|
||||||
|
|
||||||
class Session_rpc_object : public Genode::Rpc_object<Session, Session_rpc_object>
|
class Session_rpc_object : public Genode::Rpc_object<Session, Session_rpc_object>
|
||||||
{
|
{
|
||||||
private:
|
protected:
|
||||||
|
|
||||||
Packet_stream_tx::Rpc_object<Channel> _channel;
|
Packet_stream_tx::Rpc_object<Channel> _channel;
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,11 @@
|
||||||
#
|
#
|
||||||
#REPOSITORIES += $(GENODE_DIR)/linux_drivers
|
#REPOSITORIES += $(GENODE_DIR)/linux_drivers
|
||||||
|
|
||||||
|
#
|
||||||
|
# Drivers ported from the Open Sound System
|
||||||
|
#
|
||||||
|
#REPOSITORIES += $(GENODE_DIR)/dde_oss
|
||||||
|
|
||||||
#
|
#
|
||||||
# Drivers ported from iPXE
|
# Drivers ported from iPXE
|
||||||
#
|
#
|
||||||
|
|
Loading…
Reference in New Issue