OSS: Open Sound System server

Currently supports Intel HDA, AC97, and ES1370 audio cards. See README
for further details.
This commit is contained in:
Sebastian Sumpf 2012-10-23 15:21:43 +02:00 committed by Norman Feske
parent 8ac3209aa8
commit 7d8f446475
24 changed files with 2099 additions and 2 deletions

7
README
View File

@ -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
View 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
View 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.

View 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
View 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

View 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();
}

View 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) { }

View 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_ */

View File

@ -0,0 +1 @@
/* dummy */

View 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_ */

View 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_ */

View 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_ */

View 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_ */

View 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_ */

View File

@ -0,0 +1 @@
/* dummy */

View File

@ -0,0 +1 @@
/* dummy */

View 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;
}

View 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);
}

View 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;
}
}

View 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;
}

View 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();
}

View 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)

View File

@ -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;

View File

@ -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
#