mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-18 21:27:56 +00:00
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':
|
||||
|
||||
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.
|
||||
|
124
dde_oss/Makefile
Normal file
124
dde_oss/Makefile
Normal file
@ -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)
|
37
dde_oss/README
Normal file
37
dde_oss/README
Normal file
@ -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.
|
||||
|
13
dde_oss/patches/hda_irq.patch
Normal file
13
dde_oss/patches/hda_irq.patch
Normal file
@ -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;
|
99
dde_oss/run/oss.run
Normal file
99
dde_oss/run/oss.run
Normal file
@ -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
|
||||
|
176
dde_oss/src/drivers/oss/driver.cc
Normal file
176
dde_oss/src/drivers/oss/driver.cc
Normal file
@ -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();
|
||||
}
|
||||
|
67
dde_oss/src/drivers/oss/dummies.c
Normal file
67
dde_oss/src/drivers/oss/dummies.c
Normal file
@ -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) { }
|
||||
|
27
dde_oss/src/drivers/oss/include/audio.h
Normal file
27
dde_oss/src/drivers/oss/include/audio.h
Normal file
@ -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_ */
|
1
dde_oss/src/drivers/oss/include/buildid.h
Normal file
1
dde_oss/src/drivers/oss/include/buildid.h
Normal file
@ -0,0 +1 @@
|
||||
/* dummy */
|
23
dde_oss/src/drivers/oss/include/devid.h
Normal file
23
dde_oss/src/drivers/oss/include/devid.h
Normal file
@ -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_ */
|
19
dde_oss/src/drivers/oss/include/inttypes.h
Normal file
19
dde_oss/src/drivers/oss/include/inttypes.h
Normal file
@ -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_ */
|
324
dde_oss/src/drivers/oss/include/os.h
Normal file
324
dde_oss/src/drivers/oss/include/os.h
Normal file
@ -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_ */
|
24
dde_oss/src/drivers/oss/include/quirks.h
Normal file
24
dde_oss/src/drivers/oss/include/quirks.h
Normal file
@ -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_ */
|
102
dde_oss/src/drivers/oss/include/signal.h
Normal file
102
dde_oss/src/drivers/oss/include/signal.h
Normal file
@ -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_ */
|
1
dde_oss/src/drivers/oss/include/sys/ioctl.h
Normal file
1
dde_oss/src/drivers/oss/include/sys/ioctl.h
Normal file
@ -0,0 +1 @@
|
||||
/* dummy */
|
1
dde_oss/src/drivers/oss/include/timestamp.h
Normal file
1
dde_oss/src/drivers/oss/include/timestamp.h
Normal file
@ -0,0 +1 @@
|
||||
/* dummy */
|
294
dde_oss/src/drivers/oss/main.cc
Normal file
294
dde_oss/src/drivers/oss/main.cc
Normal file
@ -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;
|
||||
}
|
||||
|
44
dde_oss/src/drivers/oss/module.inc
Normal file
44
dde_oss/src/drivers/oss/module.inc
Normal file
@ -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);
|
||||
}
|
||||
|
||||
|
413
dde_oss/src/drivers/oss/os.cc
Normal file
413
dde_oss/src/drivers/oss/os.cc
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
|
47
dde_oss/src/drivers/oss/quirks.cc
Normal file
47
dde_oss/src/drivers/oss/quirks.cc
Normal file
@ -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;
|
||||
}
|
205
dde_oss/src/drivers/oss/signal/irq.cc
Normal file
205
dde_oss/src/drivers/oss/signal/irq.cc
Normal file
@ -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();
|
||||
}
|
46
dde_oss/src/drivers/oss/target.mk
Normal file
46
dde_oss/src/drivers/oss/target.mk
Normal file
@ -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>
|
||||
{
|
||||
private:
|
||||
protected:
|
||||
|
||||
Packet_stream_tx::Rpc_object<Channel> _channel;
|
||||
|
||||
|
@ -15,6 +15,11 @@
|
||||
#
|
||||
#REPOSITORIES += $(GENODE_DIR)/linux_drivers
|
||||
|
||||
#
|
||||
# Drivers ported from the Open Sound System
|
||||
#
|
||||
#REPOSITORIES += $(GENODE_DIR)/dde_oss
|
||||
|
||||
#
|
||||
# Drivers ported from iPXE
|
||||
#
|
||||
|
Loading…
Reference in New Issue
Block a user