mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-01 23:20:55 +00:00
parent
8d746a701e
commit
03cec5cdd7
@ -4,10 +4,8 @@ Audio
|
|||||||
#####
|
#####
|
||||||
|
|
||||||
The audio driver is ported from OpenBSD 6.6 and includes support for
|
The audio driver is ported from OpenBSD 6.6 and includes support for
|
||||||
Intel HD Audio, ICH as well as for Ensoniq AudioPCI (ES1370) compatible
|
Intel HD Audio devices. The HDA driver works on real hardware and
|
||||||
soundcards. The HDA driver works on real hardware and Virtualbox
|
supposedly in VirtualBox.
|
||||||
whereas the ES1370 driver is only used in Qemu. The ICH driver is only
|
|
||||||
tested in Virtualbox where it produces audible artifacts.
|
|
||||||
|
|
||||||
|
|
||||||
Usage and configuration
|
Usage and configuration
|
||||||
|
@ -1,18 +1,13 @@
|
|||||||
sys/lib/libkern/strlcpy.c
|
sys/lib/libkern/strlcpy.c
|
||||||
sys/dev/audio.c
|
sys/dev/audio.c
|
||||||
sys/dev/audio_if.h
|
sys/dev/audio_if.h
|
||||||
sys/dev/pci/auich.c
|
|
||||||
sys/dev/pci/azalia.c
|
sys/dev/pci/azalia.c
|
||||||
sys/dev/pci/azalia.h
|
sys/dev/pci/azalia.h
|
||||||
sys/dev/pci/azalia_codec.c
|
sys/dev/pci/azalia_codec.c
|
||||||
sys/dev/pci/eap.c
|
|
||||||
sys/dev/pci/eapreg.h
|
|
||||||
sys/dev/pci/pcidevs.h
|
sys/dev/pci/pcidevs.h
|
||||||
sys/dev/pci/pcidevs_data.h
|
sys/dev/pci/pcidevs_data.h
|
||||||
sys/dev/mulaw.c
|
sys/dev/mulaw.c
|
||||||
sys/dev/mulaw.h
|
sys/dev/mulaw.h
|
||||||
sys/dev/ic/ac97.c
|
|
||||||
sys/dev/ic/ac97.h
|
|
||||||
sys/sys/audioio.h
|
sys/sys/audioio.h
|
||||||
sys/sys/device.h
|
sys/sys/device.h
|
||||||
sys/sys/queue.h
|
sys/sys/queue.h
|
||||||
|
@ -13,7 +13,7 @@ INC_DIR += $(AUDIO_CONTRIB_DIR)
|
|||||||
|
|
||||||
LIBS += dde_bsd_audio_include
|
LIBS += dde_bsd_audio_include
|
||||||
|
|
||||||
SRC_CC += dummies.cc driver.cc irq.cc mem.cc misc.cc scheduler.cc timer.cc
|
SRC_CC += dummies.cc driver.cc mem.cc misc.cc scheduler.cc timer.cc
|
||||||
SRC_C += bsd_emul.c
|
SRC_C += bsd_emul.c
|
||||||
SRC_S += setjmp.S
|
SRC_S += setjmp.S
|
||||||
|
|
||||||
|
13
repos/dde_bsd/lib/mk/dde_bsd_audio_pci.inc
Normal file
13
repos/dde_bsd/lib/mk/dde_bsd_audio_pci.inc
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
include $(REP_DIR)/lib/mk/dde_bsd_audio.inc
|
||||||
|
|
||||||
|
SRC_C += bsd_emul_pci.c
|
||||||
|
SRC_CC += pci.cc
|
||||||
|
|
||||||
|
# enable when debugging
|
||||||
|
#CC_OPT += -DAZALIA_DEBUG
|
||||||
|
#CC_OPT += -DDIAGNOSTIC
|
||||||
|
|
||||||
|
# HDA driver
|
||||||
|
SRC_C += dev/pci/azalia.c dev/pci/azalia_codec.c
|
||||||
|
|
||||||
|
# vi: set ft=make :
|
@ -1,49 +0,0 @@
|
|||||||
LIB_DIR = $(REP_DIR)/src/lib/audio
|
|
||||||
LIB_INC_DIR = $(LIB_DIR)/include
|
|
||||||
|
|
||||||
AUDIO_CONTRIB_DIR := $(call select_from_ports,dde_bsd)/src/lib/audio
|
|
||||||
|
|
||||||
#
|
|
||||||
# Set include paths up before adding the dde_bsd_audio_include library
|
|
||||||
# because it will use INC_DIR += and must be at the end
|
|
||||||
#
|
|
||||||
INC_DIR += $(LIB_DIR)
|
|
||||||
INC_DIR += $(LIB_INC_DIR)
|
|
||||||
INC_DIR += $(AUDIO_CONTRIB_DIR)
|
|
||||||
|
|
||||||
LIBS += dde_bsd_audio_include
|
|
||||||
|
|
||||||
SRC_C := bsd_emul_pci.c
|
|
||||||
SRC_CC += pci.cc
|
|
||||||
|
|
||||||
CC_OPT += -Wno-unused-but-set-variable
|
|
||||||
|
|
||||||
# disable builtins
|
|
||||||
CC_OPT += -fno-builtin-printf -fno-builtin-snprintf -fno-builtin-vsnprintf \
|
|
||||||
-fno-builtin-malloc -fno-builtin-free -fno-builtin-log -fno-builtin-log2
|
|
||||||
|
|
||||||
CC_OPT += -D_KERNEL
|
|
||||||
|
|
||||||
# enable when debugging
|
|
||||||
#CC_OPT += -DAC97_DEBUG
|
|
||||||
#CC_OPT += -DAUICH_DEBUG
|
|
||||||
#CC_OPT += -DAZALIA_DEBUG
|
|
||||||
#CC_OPT += -DDIAGNOSTIC
|
|
||||||
|
|
||||||
# AC97 codec
|
|
||||||
SRC_C += dev/ic/ac97.c
|
|
||||||
|
|
||||||
# HDA driver
|
|
||||||
SRC_C += dev/pci/azalia.c dev/pci/azalia_codec.c
|
|
||||||
|
|
||||||
# ICH driver
|
|
||||||
SRC_C += dev/pci/auich.c
|
|
||||||
|
|
||||||
# ES1370
|
|
||||||
SRC_C += dev/pci/eap.c
|
|
||||||
|
|
||||||
vpath %.c $(AUDIO_CONTRIB_DIR)
|
|
||||||
vpath %.c $(LIB_DIR)
|
|
||||||
vpath %.cc $(LIB_DIR)
|
|
||||||
|
|
||||||
# vi: set ft=make :
|
|
@ -1,6 +1,6 @@
|
|||||||
INC_DIR += $(LIB_INC_DIR)/spec/x86_32 $(LIB_INC_DIR)/spec/x86
|
INC_DIR += $(LIB_INC_DIR)/spec/x86_32 $(LIB_INC_DIR)/spec/x86
|
||||||
|
|
||||||
include $(REP_DIR)/lib/mk/dde_bsd_audio.inc
|
include $(REP_DIR)/lib/mk/dde_bsd_audio_pci.inc
|
||||||
|
|
||||||
vpath %.S $(LIB_DIR)/spec/x86_32
|
vpath %.S $(LIB_DIR)/spec/x86_32
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
INC_DIR += $(LIB_INC_DIR)/spec/x86_64 $(LIB_INC_DIR)/spec/x86
|
INC_DIR += $(LIB_INC_DIR)/spec/x86_64 $(LIB_INC_DIR)/spec/x86
|
||||||
|
|
||||||
include $(REP_DIR)/lib/mk/dde_bsd_audio.inc
|
include $(REP_DIR)/lib/mk/dde_bsd_audio_pci.inc
|
||||||
|
|
||||||
vpath %.S $(LIB_DIR)/spec/x86_64
|
vpath %.S $(LIB_DIR)/spec/x86_64
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
4d3a973ccec12ca00589f9213c2ce663d4a4e496
|
03360eec0f7a11d523e2b0c88568c95cb691d3ac
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
PORT_DIR := $(call port_dir,$(REP_DIR)/ports/dde_bsd)
|
PORT_DIR := $(call port_dir,$(REP_DIR)/ports/dde_bsd)
|
||||||
|
|
||||||
MK_FILES := dde_bsd_audio.inc dde_bsd_audio_include.mk dde_bsd_audio_pci.mk
|
MK_FILES := dde_bsd_audio.inc dde_bsd_audio_include.mk dde_bsd_audio_pci.inc
|
||||||
|
|
||||||
LIB_MK := $(addprefix lib/mk/, $(MK_FILES)) \
|
LIB_MK := $(addprefix lib/mk/, $(MK_FILES)) \
|
||||||
$(foreach SPEC,x86_32 x86_64,lib/mk/spec/$(SPEC)/dde_bsd_audio.mk) \
|
$(foreach SPEC,x86_32 x86_64,lib/mk/spec/$(SPEC)/dde_bsd_audio.mk) \
|
||||||
@ -11,18 +11,13 @@ MIRROR_FROM_REP_DIR := $(LIB_MK) src/lib src/drivers patches include
|
|||||||
MIRROR_FROM_PORT_DIR := $(addprefix src/lib/audio/, \
|
MIRROR_FROM_PORT_DIR := $(addprefix src/lib/audio/, \
|
||||||
dev/pci/azalia_codec.c \
|
dev/pci/azalia_codec.c \
|
||||||
dev/pci/pcidevs.h \
|
dev/pci/pcidevs.h \
|
||||||
dev/pci/eap.c \
|
|
||||||
dev/pci/pcidevs_data.h \
|
dev/pci/pcidevs_data.h \
|
||||||
dev/pci/azalia.h \
|
dev/pci/azalia.h \
|
||||||
dev/pci/eapreg.h \
|
|
||||||
dev/pci/azalia.c \
|
dev/pci/azalia.c \
|
||||||
dev/pci/auich.c \
|
|
||||||
dev/mulaw.h \
|
dev/mulaw.h \
|
||||||
dev/audio_if.h \
|
dev/audio_if.h \
|
||||||
dev/mulaw.c \
|
dev/mulaw.c \
|
||||||
dev/audio.c \
|
dev/audio.c \
|
||||||
dev/ic/ac97.h \
|
|
||||||
dev/ic/ac97.c \
|
|
||||||
lib/libkern \
|
lib/libkern \
|
||||||
sys/device.h \
|
sys/device.h \
|
||||||
sys/audioio.h \
|
sys/audioio.h \
|
||||||
|
@ -1,47 +1,33 @@
|
|||||||
assert_spec x86
|
assert_spec x86
|
||||||
|
|
||||||
#
|
if {[have_include "power_on/qemu"]} {
|
||||||
# Check used commands
|
puts "\nAudio_out test running on Qemu is not supported.\n"
|
||||||
#
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
set wget [installed_command wget]
|
if {[have_spec linux]} {
|
||||||
|
puts"\nAudio_out test running on Linux is not supported.\n"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
#
|
|
||||||
# Configure
|
|
||||||
#
|
|
||||||
|
|
||||||
set use_mixer 0
|
create_boot_directory
|
||||||
|
build {
|
||||||
#
|
|
||||||
# Build
|
|
||||||
#
|
|
||||||
|
|
||||||
set build_components {
|
|
||||||
core init timer
|
core init timer
|
||||||
|
drivers/acpi
|
||||||
|
drivers/platform
|
||||||
|
app/pci_decode
|
||||||
|
server/report_rom
|
||||||
drivers/audio
|
drivers/audio
|
||||||
test/audio_out
|
test/audio_out
|
||||||
}
|
}
|
||||||
|
|
||||||
lappend_if $use_mixer build_components server/mixer
|
install_config {
|
||||||
|
<config verbose="yes">
|
||||||
source ${genode_dir}/repos/base/run/platform_drv.inc
|
|
||||||
append_platform_drv_build_components
|
|
||||||
|
|
||||||
build $build_components
|
|
||||||
|
|
||||||
create_boot_directory
|
|
||||||
|
|
||||||
#
|
|
||||||
# Config
|
|
||||||
#
|
|
||||||
|
|
||||||
append config {
|
|
||||||
<config>
|
|
||||||
<parent-provides>
|
<parent-provides>
|
||||||
<service name="ROM"/>
|
<service name="ROM"/>
|
||||||
<service name="IRQ"/>
|
<service name="IRQ"/>
|
||||||
<service name="IO_MEM"/>
|
<service name="IO_MEM"/>
|
||||||
<service name="IO_PORT"/>
|
|
||||||
<service name="PD"/>
|
<service name="PD"/>
|
||||||
<service name="RM"/>
|
<service name="RM"/>
|
||||||
<service name="CPU"/>
|
<service name="CPU"/>
|
||||||
@ -54,60 +40,86 @@ append config {
|
|||||||
<start name="timer">
|
<start name="timer">
|
||||||
<resource name="RAM" quantum="1M"/>
|
<resource name="RAM" quantum="1M"/>
|
||||||
<provides><service name="Timer"/></provides>
|
<provides><service name="Timer"/></provides>
|
||||||
</start>}
|
</start>
|
||||||
|
|
||||||
append_platform_drv_config
|
<start name="report_rom">
|
||||||
|
|
||||||
append_if $use_mixer config {
|
|
||||||
<start name="mixer">
|
|
||||||
<resource name="RAM" quantum="2M"/>
|
<resource name="RAM" quantum="2M"/>
|
||||||
<provides><service name="Audio_out"/></provides>
|
<provides> <service name="Report"/> <service name="ROM"/> </provides>
|
||||||
<route>
|
<config>
|
||||||
<service name="Audio_out"> <child name="audio_drv"/> </service>
|
<policy label="pci_decode -> system" report="acpi_drv -> acpi"/>
|
||||||
<any-service> <parent/> <any-child/> </any-service>
|
<policy label="platform_drv -> devices" report="pci_decode -> devices"/>
|
||||||
</route>
|
</config>
|
||||||
</start>}
|
</start>
|
||||||
|
|
||||||
append_if [have_spec linux] config {
|
<start name="acpi_drv" caps="350">
|
||||||
<start name="audio_drv" ld="no">}
|
<resource name="RAM" quantum="4M"/>
|
||||||
append_if [expr ![have_spec linux]] config {
|
<route>
|
||||||
<start name="audio_drv">}
|
<service name="Report"> <child name="report_rom"/> </service>
|
||||||
append config {
|
<service name="IO_MEM"> <parent/> </service>
|
||||||
<binary name="} [audio_drv_binary] {"/>
|
<service name="LOG"> <parent/> </service>
|
||||||
|
<service name="PD"> <parent/> </service>
|
||||||
|
<service name="RM"> <parent/> </service>
|
||||||
|
<service name="CPU"> <parent/> </service>
|
||||||
|
<service name="ROM"> <parent/> </service>
|
||||||
|
</route>
|
||||||
|
</start>
|
||||||
|
|
||||||
|
<start name="pci_decode" caps="350">
|
||||||
|
<resource name="RAM" quantum="1M"/>
|
||||||
|
<route>
|
||||||
|
<service name="Report"> <child name="report_rom"/> </service>
|
||||||
|
<service name="ROM" label="system"> <child name="report_rom"/> </service>
|
||||||
|
<service name="IO_MEM"> <parent/> </service>
|
||||||
|
<service name="LOG"> <parent/> </service>
|
||||||
|
<service name="PD"> <parent/> </service>
|
||||||
|
<service name="RM"> <parent/> </service>
|
||||||
|
<service name="CPU"> <parent/> </service>
|
||||||
|
<service name="ROM"> <parent/> </service>
|
||||||
|
</route>
|
||||||
|
</start>
|
||||||
|
|
||||||
|
<start name="platform_drv" caps="100" managing_system="yes">
|
||||||
|
<resource name="RAM" quantum="1M"/>
|
||||||
|
<provides>
|
||||||
|
<service name="Platform"/>
|
||||||
|
</provides>
|
||||||
|
<route>
|
||||||
|
<service name="ROM" label="devices"> <child name="report_rom"/> </service>
|
||||||
|
<service name="IRQ"> <parent/> </service>
|
||||||
|
<service name="IO_MEM"> <parent/> </service>
|
||||||
|
<service name="ROM"> <parent/> </service>
|
||||||
|
<service name="PD"> <parent/> </service>
|
||||||
|
<service name="CPU"> <parent/> </service>
|
||||||
|
<service name="LOG"> <parent/> </service>
|
||||||
|
<service name="Timer"> <parent/> </service>
|
||||||
|
</route>
|
||||||
|
<config>
|
||||||
|
<policy label="audio_drv -> "> <pci class="AUDIO"/> <pci class="HDAUDIO"/> </policy>
|
||||||
|
</config>
|
||||||
|
</start>
|
||||||
|
|
||||||
|
<start name="audio_drv" caps="150">
|
||||||
|
<binary name="pci_audio_drv"/>
|
||||||
<resource name="RAM" quantum="8M"/>
|
<resource name="RAM" quantum="8M"/>
|
||||||
<provides> <service name="Audio_out"/> </provides>
|
<provides> <service name="Audio_out"/> </provides>
|
||||||
<!--
|
|
||||||
The proper ALSA device might need to be configured, e.g.
|
|
||||||
<config alsa_device="hw:CARD=Schiit,DEV=0"/>
|
|
||||||
when using Linux.
|
|
||||||
-->
|
|
||||||
<config/>
|
<config/>
|
||||||
</start>
|
</start>
|
||||||
|
|
||||||
<start name="test-audio_out">
|
<start name="test-audio_out">
|
||||||
<resource name="RAM" quantum="4M"/>
|
<resource name="RAM" quantum="4M"/>
|
||||||
<config>
|
<config>
|
||||||
<filename>sample.raw</filename>
|
<filename>sample.raw</filename>
|
||||||
</config>
|
</config>
|
||||||
<route>}
|
<route>
|
||||||
append_if $use_mixer config {
|
|
||||||
<service name="Audio_out"><child name="mixer"/></service>}
|
|
||||||
append config {
|
|
||||||
<any-service><parent/><any-child/></any-service>
|
<any-service><parent/><any-child/></any-service>
|
||||||
</route>
|
</route>
|
||||||
</start>
|
</start>
|
||||||
</config>}
|
</config>}
|
||||||
|
|
||||||
install_config $config
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Get sample file
|
# Get sample file
|
||||||
#
|
#
|
||||||
|
|
||||||
if {[info exists env(GENODE_SAMPLE_RAW)]} {
|
|
||||||
catch { exec $wget $::env(GENODE_SAMPLE_RAW) -O bin/sample.raw }
|
|
||||||
}
|
|
||||||
|
|
||||||
if {![file exists bin/sample.raw]} {
|
if {![file exists bin/sample.raw]} {
|
||||||
puts ""
|
puts ""
|
||||||
puts "The sample file is missing. Please take a look at"
|
puts "The sample file is missing. Please take a look at"
|
||||||
@ -117,22 +129,12 @@ if {![file exists bin/sample.raw]} {
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
#
|
build_boot_image {
|
||||||
# Boot modules
|
core ld.lib.so init timer
|
||||||
#
|
platform_drv acpi_drv pci_decode report_rom
|
||||||
|
pci_audio_drv test-audio_out sample.raw
|
||||||
append boot_modules {
|
|
||||||
core ld.lib.so init timer } [audio_drv_binary] {
|
|
||||||
test-audio_out sample.raw
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lappend_if $use_mixer boot_modules mixer
|
|
||||||
|
|
||||||
append_platform_drv_boot_modules
|
|
||||||
|
|
||||||
build_boot_image $boot_modules
|
|
||||||
|
|
||||||
append qemu_args " -nographic -soundhw es1370 "
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# For obvious reasons the timeout depends on the total
|
# For obvious reasons the timeout depends on the total
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
REQUIRES = x86
|
REQUIRES = x86
|
||||||
TARGET = pci_audio_drv
|
TARGET = pci_audio_drv
|
||||||
SRC_CC = main.cc
|
SRC_CC = main.cc
|
||||||
LIBS = dde_bsd_audio dde_bsd_audio_pci base
|
LIBS = dde_bsd_audio base
|
||||||
INC_DIR += $(REP_DIR)/include
|
INC_DIR += $(REP_DIR)/include
|
||||||
|
|
||||||
vpath %.cc $(REP_DIR)/src/drivers/audio
|
vpath %.cc $(REP_DIR)/src/drivers/audio
|
||||||
|
@ -24,25 +24,8 @@ namespace Bsd {
|
|||||||
int probe_drivers(Genode::Env&, Genode::Allocator&);
|
int probe_drivers(Genode::Env&, Genode::Allocator&);
|
||||||
|
|
||||||
void mem_init(Genode::Env&, Genode::Allocator &);
|
void mem_init(Genode::Env&, Genode::Allocator &);
|
||||||
void irq_init(Genode::Entrypoint&, Genode::Allocator&);
|
|
||||||
void timer_init(Genode::Env&);
|
void timer_init(Genode::Env&);
|
||||||
void update_time();
|
void update_time();
|
||||||
|
|
||||||
|
|
||||||
/**************************
|
|
||||||
** Bus_driver interface **
|
|
||||||
**************************/
|
|
||||||
|
|
||||||
struct Bus_driver
|
|
||||||
{
|
|
||||||
virtual Genode::Irq_session_capability irq_session() = 0;
|
|
||||||
|
|
||||||
virtual Genode::addr_t alloc(Genode::size_t size, int align) = 0;
|
|
||||||
virtual void free(Genode::addr_t virt, Genode::size_t size) = 0;
|
|
||||||
virtual Genode::addr_t virt_to_phys(Genode::addr_t virt) = 0;
|
|
||||||
virtual Genode::addr_t phys_to_virt(Genode::addr_t phys) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _BSD_H_ */
|
#endif /* _BSD_H_ */
|
||||||
|
@ -40,8 +40,6 @@ short pv[] = { -1, PCI_BUS_PARENT };
|
|||||||
struct cfdata cfdata[] = {
|
struct cfdata cfdata[] = {
|
||||||
{&audio_ca, &audio_cd, 0, 0, 0, 0, pv+0, 0, 0},
|
{&audio_ca, &audio_cd, 0, 0, 0, 0, pv+0, 0, 0},
|
||||||
{&azalia_ca, &azalia_cd, 0, 0, 0, 0, pv+1, 0, 0},
|
{&azalia_ca, &azalia_cd, 0, 0, 0, 0, pv+1, 0, 0},
|
||||||
{&eap_ca, &eap_cd, 0, 0, 0, 0, pv+1, 0, 0},
|
|
||||||
{&auich_ca, &auich_cd, 0, 0, 0, 0, pv+1, 0, 0},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -616,7 +616,6 @@ void Audio::init_driver(Genode::Env &env, Genode::Allocator &alloc,
|
|||||||
Genode::Signal_context_capability announce_sigh)
|
Genode::Signal_context_capability announce_sigh)
|
||||||
{
|
{
|
||||||
Bsd::mem_init(env, alloc);
|
Bsd::mem_init(env, alloc);
|
||||||
Bsd::irq_init(env.ep(), alloc);
|
|
||||||
Bsd::timer_init(env);
|
Bsd::timer_init(env);
|
||||||
|
|
||||||
static Task bsd_task(env, alloc, config, announce_sigh);
|
static Task bsd_task(env, alloc, config, announce_sigh);
|
||||||
|
@ -1,161 +0,0 @@
|
|||||||
/*
|
|
||||||
* \brief Signal context for IRQ's
|
|
||||||
* \author Josef Soentgen
|
|
||||||
* \date 2014-10-14
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2014-2020 Genode Labs GmbH
|
|
||||||
*
|
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Genode includes */
|
|
||||||
#include <base/log.h>
|
|
||||||
#include <base/thread.h>
|
|
||||||
#include <base/tslab.h>
|
|
||||||
#include <timer_session/connection.h>
|
|
||||||
#include <irq_session/connection.h>
|
|
||||||
|
|
||||||
/* local includes */
|
|
||||||
#include <audio/audio.h>
|
|
||||||
#include <bsd.h>
|
|
||||||
#include <bsd_emul.h>
|
|
||||||
#include <scheduler.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace Bsd {
|
|
||||||
class Irq;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void run_irq(void *args);
|
|
||||||
|
|
||||||
|
|
||||||
class Bsd::Irq
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
typedef int (*intrh_t)(void*);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Context encapsulates the handling of an IRQ
|
|
||||||
*/
|
|
||||||
class Context
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
enum { STACK_SIZE = 1024 * sizeof(long) };
|
|
||||||
|
|
||||||
Bsd::Task _task;
|
|
||||||
Genode::Irq_session_client _irq;
|
|
||||||
Genode::Signal_handler<Context> _dispatcher;
|
|
||||||
|
|
||||||
intrh_t _intrh;
|
|
||||||
void *_intarg;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Signal handler
|
|
||||||
*/
|
|
||||||
void _handle()
|
|
||||||
{
|
|
||||||
_task.unblock();
|
|
||||||
Bsd::scheduler().schedule();
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
Context(Genode::Entrypoint &ep,
|
|
||||||
Genode::Irq_session_capability cap,
|
|
||||||
intrh_t intrh, void *intarg)
|
|
||||||
:
|
|
||||||
_task(run_irq, this, "irq", Bsd::Task::PRIORITY_3,
|
|
||||||
Bsd::scheduler(), STACK_SIZE),
|
|
||||||
_irq(cap),
|
|
||||||
_dispatcher(ep, *this, &Context::_handle),
|
|
||||||
_intrh(intrh), _intarg(intarg)
|
|
||||||
{
|
|
||||||
_irq.sigh(_dispatcher);
|
|
||||||
_irq.ack_irq();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle IRQ
|
|
||||||
*/
|
|
||||||
void handle_irq()
|
|
||||||
{
|
|
||||||
_intrh(_intarg);
|
|
||||||
_irq.ack_irq();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
Genode::Allocator &_alloc;
|
|
||||||
Genode::Entrypoint &_ep;
|
|
||||||
Context *_ctx;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
Irq(Genode::Allocator &alloc, Genode::Entrypoint &ep)
|
|
||||||
: _alloc(alloc), _ep(ep), _ctx(nullptr) { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Request an IRQ
|
|
||||||
*/
|
|
||||||
void establish_intr(Genode::Irq_session_capability cap, intrh_t intrh, void *intarg)
|
|
||||||
{
|
|
||||||
if (_ctx) {
|
|
||||||
Genode::error("interrupt already established");
|
|
||||||
Genode::sleep_forever();
|
|
||||||
}
|
|
||||||
|
|
||||||
_ctx = new (&_alloc) Context(_ep, cap, intrh, intarg);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static Bsd::Irq *_bsd_irq;
|
|
||||||
|
|
||||||
|
|
||||||
void Bsd::irq_init(Genode::Entrypoint &ep, Genode::Allocator &alloc)
|
|
||||||
{
|
|
||||||
static Bsd::Irq irq_context(alloc, ep);
|
|
||||||
_bsd_irq = &irq_context;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void run_irq(void *args)
|
|
||||||
{
|
|
||||||
Bsd::Irq::Context *ctx = static_cast<Bsd::Irq::Context*>(args);
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
Bsd::scheduler().current()->block_and_schedule();
|
|
||||||
ctx->handle_irq();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**********************
|
|
||||||
** dev/pci/pcivar.h **
|
|
||||||
**********************/
|
|
||||||
|
|
||||||
extern "C" int pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ih) {
|
|
||||||
return 0; }
|
|
||||||
|
|
||||||
|
|
||||||
extern "C" void *pci_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih,
|
|
||||||
int ipl, int (*intrh)(void *), void *intarg,
|
|
||||||
const char *intrstr)
|
|
||||||
{
|
|
||||||
Bsd::Bus_driver *drv = (Bsd::Bus_driver*)pc;
|
|
||||||
|
|
||||||
_bsd_irq->establish_intr(drv->irq_session(), intrh, intarg);
|
|
||||||
return _bsd_irq;
|
|
||||||
}
|
|
@ -16,162 +16,130 @@
|
|||||||
#include <base/log.h>
|
#include <base/log.h>
|
||||||
#include <base/object_pool.h>
|
#include <base/object_pool.h>
|
||||||
#include <dataspace/client.h>
|
#include <dataspace/client.h>
|
||||||
#include <io_port_session/connection.h>
|
#include <platform_session/device.h>
|
||||||
#include <io_mem_session/connection.h>
|
#include <platform_session/dma_buffer.h>
|
||||||
#include <legacy/x86/platform_session/connection.h>
|
|
||||||
#include <legacy/x86/platform_device/client.h>
|
|
||||||
#include <util/retry.h>
|
#include <util/retry.h>
|
||||||
|
|
||||||
/* local includes */
|
/* local includes */
|
||||||
|
#include <audio/audio.h>
|
||||||
#include <bsd.h>
|
#include <bsd.h>
|
||||||
#include <bsd_emul.h>
|
#include <bsd_emul.h>
|
||||||
|
#include <scheduler.h>
|
||||||
|
|
||||||
#include <extern_c_begin.h>
|
#include <extern_c_begin.h>
|
||||||
# include <dev/pci/pcidevs.h>
|
# include <dev/pci/pcidevs.h>
|
||||||
#include <extern_c_end.h>
|
#include <extern_c_end.h>
|
||||||
|
|
||||||
|
static constexpr bool debug = false;
|
||||||
|
|
||||||
extern "C" int probe_cfdata(struct pci_attach_args *);
|
extern "C" int probe_cfdata(struct pci_attach_args *);
|
||||||
|
|
||||||
|
static void run_irq(void *args);
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
class Pci_driver : public Bsd::Bus_driver
|
class Pci_driver
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
|
|
||||||
enum Pci_config { IRQ = 0x3c, CMD = 0x4,
|
|
||||||
CMD_IO = 0x1, CMD_MEMORY = 0x2, CMD_MASTER = 0x4 };
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Genode::Env &_env;
|
enum { DMA_SIZE = 1024 * 1024 };
|
||||||
Genode::Allocator &_alloc;
|
|
||||||
|
Genode::Env & _env;
|
||||||
|
Platform::Connection _pci { _env };
|
||||||
|
Platform::Dma_buffer _buffer { _pci, DMA_SIZE, Genode::UNCACHED };
|
||||||
|
Genode::Allocator_avl _alloc;
|
||||||
|
|
||||||
|
struct Device
|
||||||
|
{
|
||||||
|
Platform::Device dev;
|
||||||
|
Platform::Device::Irq irq;
|
||||||
|
Platform::Device::Mmio mmio;
|
||||||
|
|
||||||
|
Device(Platform::Connection &pci,
|
||||||
|
Platform::Device::Name const &name)
|
||||||
|
: dev { pci, name }, irq { dev }, mmio { dev }
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
Genode::Constructible<Device> _device { };
|
||||||
|
|
||||||
|
uint16_t _vendor_id { 0U };
|
||||||
|
uint16_t _device_id { 0U };
|
||||||
|
uint32_t _class_code { 0U };
|
||||||
|
uint16_t _sub_vendor_id { 0U };
|
||||||
|
uint16_t _sub_device_id { 0U };
|
||||||
|
|
||||||
|
typedef int (*intrh_t)(void*);
|
||||||
|
|
||||||
|
intrh_t _irq_func { nullptr };
|
||||||
|
void * _irq_arg { nullptr };
|
||||||
|
Bsd::Task _irq_task { run_irq, this, "irq", Bsd::Task::PRIORITY_3,
|
||||||
|
Bsd::scheduler(), 1024 * sizeof(long) };
|
||||||
|
|
||||||
|
Genode::Io_signal_handler<Pci_driver> _irq_handler { _env.ep(), *this,
|
||||||
|
&Pci_driver::_irq_handle };
|
||||||
|
|
||||||
struct pci_attach_args _pa { 0, 0, 0, 0, 0 };
|
struct pci_attach_args _pa { 0, 0, 0, 0, 0 };
|
||||||
|
|
||||||
Platform::Connection _pci { _env };
|
void _irq_handle()
|
||||||
Platform::Device_capability _cap;
|
|
||||||
|
|
||||||
Genode::Io_port_connection *_io_port { nullptr };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Dma_region_manager provides memory used for DMA
|
|
||||||
* and manages its mappings.
|
|
||||||
*/
|
|
||||||
struct Dma_region_manager : public Genode::Allocator_avl
|
|
||||||
{
|
{
|
||||||
Genode::Env &env;
|
_irq_task.unblock();
|
||||||
|
Bsd::scheduler().schedule();
|
||||||
|
}
|
||||||
|
|
||||||
enum { BACKING_STORE_SIZE = 1024 * 1024 };
|
Genode::addr_t _buffer_base() {
|
||||||
|
return (Genode::addr_t)_buffer.local_addr<char>(); }
|
||||||
|
|
||||||
Genode::addr_t base;
|
void _handle_device_list() { /* intentionally left empty */ }
|
||||||
Genode::addr_t mapped_base;
|
|
||||||
|
|
||||||
bool _dma_initialized { false };
|
void _wait_for_device_list(Genode::Entrypoint &ep,
|
||||||
|
Platform::Connection &pci)
|
||||||
|
{
|
||||||
|
using namespace Genode;
|
||||||
|
Constructible<Io_signal_handler<Pci_driver>> handler { };
|
||||||
|
|
||||||
Pci_driver &_drv;
|
bool device_list = false;
|
||||||
|
while (!device_list) {
|
||||||
Dma_region_manager(Genode::Env &env,
|
pci.update();
|
||||||
Genode::Allocator &alloc,
|
pci.with_xml([&] (Xml_node & xml) {
|
||||||
Pci_driver &drv)
|
if (xml.num_sub_nodes()) {
|
||||||
: Genode::Allocator_avl(&alloc), env(env), _drv(drv) { }
|
pci.sigh(Signal_context_capability());
|
||||||
|
if (handler.constructed())
|
||||||
Genode::addr_t alloc(Genode::size_t size, unsigned align)
|
handler.destruct();
|
||||||
{
|
device_list = true;
|
||||||
using namespace Genode;
|
return;
|
||||||
|
|
||||||
if (!_dma_initialized) {
|
|
||||||
try {
|
|
||||||
Ram_dataspace_capability cap = _drv._alloc_dma_memory(BACKING_STORE_SIZE);
|
|
||||||
mapped_base = (addr_t)env.rm().attach(cap);
|
|
||||||
base = _drv._dma_addr(cap);
|
|
||||||
|
|
||||||
Allocator_avl::add_range(mapped_base, BACKING_STORE_SIZE);
|
|
||||||
} catch (...) {
|
|
||||||
Genode::error("alloc DMA memory failed");
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
_dma_initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Allocator_avl::alloc_aligned(size, align).convert<Genode::addr_t>(
|
if (!handler.constructed()) {
|
||||||
[&] (void *ptr) { return (addr_t)ptr; },
|
handler.construct(ep, *this,
|
||||||
[&] (Alloc_error) { return 0UL; });
|
&Pci_driver::_handle_device_list);
|
||||||
}
|
pci.sigh(*handler);
|
||||||
|
}
|
||||||
|
|
||||||
void free(Genode::addr_t virt, Genode::size_t size) {
|
ep.wait_and_dispatch_one_io_signal();
|
||||||
Genode::Allocator_avl::free((void*)virt, size); }
|
|
||||||
|
|
||||||
Genode::addr_t virt_to_phys(Genode::addr_t virt) {
|
|
||||||
return virt - mapped_base + base; }
|
|
||||||
|
|
||||||
Genode::addr_t phys_to_virt(Genode::addr_t phys) {
|
|
||||||
return phys - base + mapped_base; }
|
|
||||||
|
|
||||||
} _dma_region_manager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Scan pci bus for sound devices
|
|
||||||
*/
|
|
||||||
Platform::Device_capability _scan_pci(Platform::Device_capability const &prev)
|
|
||||||
{
|
|
||||||
Platform::Device_capability cap;
|
|
||||||
/* shift values for Pci interface used by Genode */
|
|
||||||
cap = _pci.with_upgrade([&] () {
|
|
||||||
return _pci.next_device(prev,
|
|
||||||
PCI_CLASS_MULTIMEDIA << 16,
|
|
||||||
PCI_CLASS_MASK << 16); });
|
|
||||||
|
|
||||||
if (prev.valid())
|
|
||||||
_pci.release_device(prev);
|
|
||||||
return cap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allocate DMA memory from the PCI driver
|
|
||||||
*/
|
|
||||||
Genode::Ram_dataspace_capability _alloc_dma_memory(Genode::size_t size)
|
|
||||||
{
|
|
||||||
size_t donate = size;
|
|
||||||
|
|
||||||
return Genode::retry<Genode::Out_of_ram>(
|
|
||||||
[&] () {
|
|
||||||
return Genode::retry<Genode::Out_of_caps>(
|
|
||||||
[&] () { return _pci.alloc_dma_buffer(size, Genode::UNCACHED); },
|
|
||||||
[&] () { _pci.upgrade_caps(2); });
|
|
||||||
},
|
|
||||||
[&] () {
|
|
||||||
_pci.upgrade_ram(donate);
|
|
||||||
donate = donate * 2 > size ? 4096 : donate * 2;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get physical address for DMA dataspace
|
|
||||||
*/
|
|
||||||
Genode::addr_t _dma_addr(Genode::Ram_dataspace_capability ds_cap)
|
|
||||||
{
|
|
||||||
return _pci.dma_addr(ds_cap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Pci_driver(Genode::Env &env, Genode::Allocator &alloc)
|
Pci_driver(Genode::Env &env, Genode::Allocator & alloc)
|
||||||
:
|
:
|
||||||
_env(env), _alloc(alloc),
|
_env(env), _alloc(&alloc)
|
||||||
_dma_region_manager(_env, _alloc, *this)
|
{
|
||||||
{ }
|
_alloc.add_range(_buffer_base(), DMA_SIZE);
|
||||||
|
|
||||||
Genode::Env &env() { return _env; }
|
/* will "block" until device list becomes available */
|
||||||
|
_wait_for_device_list(_env.ep(), _pci);
|
||||||
|
}
|
||||||
|
|
||||||
Genode::Allocator &alloc() { return _alloc; }
|
uint16_t sub_device_id() { return _sub_device_id; }
|
||||||
|
uint16_t sub_vendor_id() { return _sub_vendor_id; }
|
||||||
Platform::Device_capability cap() { return _cap; }
|
|
||||||
|
|
||||||
Platform::Connection &pci() { return _pci; }
|
|
||||||
|
|
||||||
int probe()
|
int probe()
|
||||||
{
|
{
|
||||||
|
using namespace Genode;
|
||||||
|
|
||||||
_pci.upgrade_ram(8*1024);
|
_pci.upgrade_ram(8*1024);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -183,149 +151,130 @@ class Pci_driver : public Bsd::Bus_driver
|
|||||||
_pa.pa_dmat = (bus_dma_tag_t)this;
|
_pa.pa_dmat = (bus_dma_tag_t)this;
|
||||||
_pa.pa_pc = (pci_chipset_tag_t)this;
|
_pa.pa_pc = (pci_chipset_tag_t)this;
|
||||||
|
|
||||||
int found = 0;
|
bool found = false;
|
||||||
while ((_cap = _scan_pci(_cap)).valid()) {
|
_pci.update();
|
||||||
Platform::Device_client device(_cap);
|
_pci.with_xml([&] (Xml_node node) {
|
||||||
|
node.for_each_sub_node("device", [&] (Xml_node node)
|
||||||
|
{
|
||||||
|
if (found) return;
|
||||||
|
|
||||||
uint8_t bus, dev, func;
|
String<16> name = node.attribute_value("name", String<16>());
|
||||||
device.bus_address(&bus, &dev, &func);
|
|
||||||
|
|
||||||
if ((device.device_id() == PCI_PRODUCT_INTEL_CORE4G_HDA_2) ||
|
node.with_optional_sub_node("pci-config", [&] (Xml_node node)
|
||||||
(device.vendor_id() == PCI_VENDOR_INTEL &&
|
{
|
||||||
bus == 0 && dev == 3 && func == 0)) {
|
_vendor_id = node.attribute_value("vendor_id", 0U);
|
||||||
Genode::warning("ignore ", (unsigned)bus, ":", (unsigned)dev, ":",
|
_device_id = node.attribute_value("device_id", 0U);
|
||||||
(unsigned)func, ", not supported HDMI/DP HDA device");
|
_class_code = node.attribute_value("class", 0U);
|
||||||
continue;
|
_sub_vendor_id = node.attribute_value("sub_vendor_id", 0U);
|
||||||
}
|
_sub_device_id = node.attribute_value("sub_device_id", 0U);
|
||||||
|
|
||||||
/* we do the shifting to match OpenBSD's assumptions */
|
if ((_device_id == PCI_PRODUCT_INTEL_CORE4G_HDA_2) ||
|
||||||
_pa.pa_tag = 0x80000000UL | (bus << 16) | (dev << 11) | (func << 8);
|
(_vendor_id == PCI_VENDOR_INTEL && name == "00:03.0")) {
|
||||||
_pa.pa_class = device.class_code() << 8;
|
warning("ignore ", name,
|
||||||
_pa.pa_id = device.vendor_id() | device.device_id() << 16;
|
", not supported HDMI/DP HDA device");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (probe_cfdata(&_pa)) {
|
/* we only construct the first useable device we find */
|
||||||
found++;
|
_device.construct(_pci, name);
|
||||||
break;
|
_device->irq.sigh(_irq_handler);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return found;
|
/* we do the shifting to match OpenBSD's assumptions */
|
||||||
|
_pa.pa_tag = 0x80000000UL;
|
||||||
|
_pa.pa_class = _class_code << 8;
|
||||||
|
_pa.pa_id = _vendor_id | _device_id << 16;
|
||||||
|
|
||||||
|
if (probe_cfdata(&_pa))
|
||||||
|
found = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return found ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************
|
void irq_handler(intrh_t handler, void * arg)
|
||||||
** Bus_driver interface **
|
{
|
||||||
**************************/
|
_irq_func = handler;
|
||||||
|
_irq_arg = arg;
|
||||||
|
}
|
||||||
|
|
||||||
Genode::Irq_session_capability irq_session() override {
|
void handle_irq()
|
||||||
return Platform::Device_client(_cap).irq(0); }
|
{
|
||||||
|
_irq_func(_irq_arg);
|
||||||
|
_device->irq.ack();
|
||||||
|
}
|
||||||
|
|
||||||
Genode::addr_t alloc(Genode::size_t size, int align) override {
|
|
||||||
return _dma_region_manager.alloc(size, align); }
|
|
||||||
|
|
||||||
void free(Genode::addr_t virt, Genode::size_t size) override {
|
/*********************
|
||||||
_dma_region_manager.free(virt, size); }
|
** Mmio management **
|
||||||
|
*********************/
|
||||||
|
|
||||||
Genode::addr_t virt_to_phys(Genode::addr_t virt) override {
|
Genode::addr_t mmio_base() { return _device->mmio.base(); }
|
||||||
return _dma_region_manager.virt_to_phys(virt); }
|
Genode::size_t mmio_size() { return _device->mmio.size(); }
|
||||||
|
|
||||||
Genode::addr_t phys_to_virt(Genode::addr_t phys) override {
|
template <typename T>
|
||||||
return _dma_region_manager.phys_to_virt(phys); }
|
T read(Genode::size_t offset) {
|
||||||
|
return *(volatile T*)(_device->mmio.base() + offset); }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void write(Genode::size_t offset, T value) {
|
||||||
|
*(volatile T*)(_device->mmio.base() + offset) = value; }
|
||||||
|
|
||||||
|
|
||||||
|
/********************
|
||||||
|
** DMA management **
|
||||||
|
********************/
|
||||||
|
|
||||||
|
Genode::addr_t alloc(Genode::size_t size, unsigned align)
|
||||||
|
{
|
||||||
|
using namespace Genode;
|
||||||
|
|
||||||
|
return _alloc.alloc_aligned(size, align).convert<Genode::addr_t>(
|
||||||
|
[&] (void *ptr) { return (addr_t)ptr; },
|
||||||
|
[&] (Allocator_avl::Alloc_error) { return 0UL; });
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(Genode::addr_t virt, Genode::size_t size) {
|
||||||
|
_alloc.free((void*)virt, size); }
|
||||||
|
|
||||||
|
Genode::addr_t virt_to_phys(Genode::addr_t virt) {
|
||||||
|
return virt - _buffer_base() + _buffer.dma_addr(); }
|
||||||
|
|
||||||
|
Genode::addr_t phys_to_virt(Genode::addr_t phys) {
|
||||||
|
return phys - _buffer.dma_addr() + _buffer_base(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
** Bus space helper **
|
** dev/pci/pcivar.h **
|
||||||
**********************/
|
**********************/
|
||||||
|
|
||||||
struct Bus_space
|
extern "C" int pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ih) {
|
||||||
|
return 0; }
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" void *pci_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih,
|
||||||
|
int ipl, int (*intrh)(void *), void *intarg,
|
||||||
|
const char *intrstr)
|
||||||
{
|
{
|
||||||
virtual unsigned read_1(unsigned long address) = 0;
|
Pci_driver * drv = (Pci_driver*) pc;
|
||||||
virtual unsigned read_2(unsigned long address) = 0;
|
drv->irq_handler(intrh, intarg);
|
||||||
virtual unsigned read_4(unsigned long address) = 0;
|
return drv;
|
||||||
|
}
|
||||||
virtual void write_1(unsigned long address, unsigned char value) = 0;
|
|
||||||
virtual void write_2(unsigned long address, unsigned short value) = 0;
|
|
||||||
virtual void write_4(unsigned long address, unsigned int value) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*********************
|
|
||||||
** I/O port helper **
|
|
||||||
*********************/
|
|
||||||
|
|
||||||
struct Io_port : public Bus_space
|
|
||||||
{
|
|
||||||
Genode::Io_port_session_client _io;
|
|
||||||
Genode::addr_t _base;
|
|
||||||
|
|
||||||
Io_port(Genode::addr_t base, Genode::Io_port_session_capability cap)
|
|
||||||
: _io(cap), _base(base) { }
|
|
||||||
|
|
||||||
unsigned read_1(unsigned long address) {
|
|
||||||
return _io.inb(_base + address); }
|
|
||||||
|
|
||||||
unsigned read_2(unsigned long address) {
|
|
||||||
return _io.inw(_base + address); }
|
|
||||||
|
|
||||||
unsigned read_4(unsigned long address) {
|
|
||||||
return _io.inl(_base + address); }
|
|
||||||
|
|
||||||
void write_1(unsigned long address, unsigned char value) {
|
|
||||||
_io.outb(_base + address, value); }
|
|
||||||
|
|
||||||
void write_2(unsigned long address, unsigned short value) {
|
|
||||||
_io.outw(_base + address, value); }
|
|
||||||
|
|
||||||
void write_4(unsigned long address, unsigned int value) {
|
|
||||||
_io.outl(_base + address, value); }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/***********************
|
|
||||||
** I/O memory helper **
|
|
||||||
***********************/
|
|
||||||
|
|
||||||
struct Io_memory : public Bus_space
|
|
||||||
{
|
|
||||||
Genode::Io_mem_session_client _mem;
|
|
||||||
Genode::Io_mem_dataspace_capability _mem_ds;
|
|
||||||
Genode::addr_t _vaddr;
|
|
||||||
|
|
||||||
Io_memory(Genode::Region_map &rm,
|
|
||||||
Genode::addr_t base,
|
|
||||||
Genode::Io_mem_session_capability cap)
|
|
||||||
:
|
|
||||||
_mem(cap),
|
|
||||||
_mem_ds(_mem.dataspace())
|
|
||||||
{
|
|
||||||
if (!_mem_ds.valid())
|
|
||||||
throw Genode::Exception();
|
|
||||||
|
|
||||||
_vaddr = rm.attach(_mem_ds);
|
|
||||||
_vaddr |= base & 0xfff;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned read_1(unsigned long address) {
|
|
||||||
return *(volatile unsigned char*)(_vaddr + address); }
|
|
||||||
|
|
||||||
unsigned read_2(unsigned long address) {
|
|
||||||
return *(volatile unsigned short*)(_vaddr + address); }
|
|
||||||
|
|
||||||
unsigned read_4(unsigned long address) {
|
|
||||||
return *(volatile unsigned int*)(_vaddr + address); }
|
|
||||||
|
|
||||||
void write_1(unsigned long address, unsigned char value) {
|
|
||||||
*(volatile unsigned char*)(_vaddr + address) = value; }
|
|
||||||
|
|
||||||
void write_2(unsigned long address, unsigned short value) {
|
|
||||||
*(volatile unsigned short*)(_vaddr + address) = value; }
|
|
||||||
|
|
||||||
void write_4(unsigned long address, unsigned int value) {
|
|
||||||
*(volatile unsigned int*)(_vaddr + address) = value; }
|
|
||||||
};
|
|
||||||
|
|
||||||
} /* anonymous namespace */
|
} /* anonymous namespace */
|
||||||
|
|
||||||
|
static void run_irq(void *args)
|
||||||
|
{
|
||||||
|
Pci_driver & pci_drv = *(Pci_driver*)args;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
Bsd::scheduler().current()->block_and_schedule();
|
||||||
|
pci_drv.handle_irq();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int Bsd::probe_drivers(Genode::Env &env, Genode::Allocator &alloc)
|
int Bsd::probe_drivers(Genode::Env &env, Genode::Allocator &alloc)
|
||||||
{
|
{
|
||||||
@ -362,57 +311,19 @@ extern "C" int pci_mapreg_map(struct pci_attach_args *pa,
|
|||||||
/* calculate BAR from given register */
|
/* calculate BAR from given register */
|
||||||
int r = (reg - 0x10) / 4;
|
int r = (reg - 0x10) / 4;
|
||||||
|
|
||||||
Pci_driver *drv = (Pci_driver*)pa->pa_pc;
|
if (r) {
|
||||||
|
Genode::error("MAP BAR ", r, " not implemented yet");
|
||||||
Platform::Device_capability cap = drv->cap();
|
return -1;
|
||||||
Platform::Device_client device(cap);
|
|
||||||
Platform::Device::Resource res = device.resource(r);
|
|
||||||
|
|
||||||
switch (res.type()) {
|
|
||||||
case Platform::Device::Resource::IO:
|
|
||||||
{
|
|
||||||
Io_port *iop = new (&drv->alloc())
|
|
||||||
Io_port(res.base(), device.io_port(r));
|
|
||||||
*tagp = (Genode::addr_t) iop;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Platform::Device::Resource::MEMORY:
|
|
||||||
{
|
|
||||||
Io_memory *iom = new (&drv->alloc())
|
|
||||||
Io_memory(drv->env().rm(), res.base(), device.io_mem(r));
|
|
||||||
*tagp = (Genode::addr_t) iom;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Platform::Device::Resource::INVALID:
|
|
||||||
{
|
|
||||||
Genode::error("PCI resource type invalid");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*handlep = res.base();
|
Pci_driver *drv = (Pci_driver*)pa->pa_pc;
|
||||||
|
*tagp = (Genode::addr_t)drv;
|
||||||
|
*handlep = drv->mmio_base();
|
||||||
|
|
||||||
if (basep != 0)
|
if (basep != 0)
|
||||||
*basep = res.base();
|
*basep = drv->mmio_base();
|
||||||
if (sizep != 0)
|
if (sizep != 0)
|
||||||
*sizep = maxsize > 0 && res.size() > maxsize ? maxsize : res.size();
|
*sizep = maxsize > 0 && drv->mmio_size() > maxsize ? maxsize : drv->mmio_size();
|
||||||
|
|
||||||
/* enable bus master and I/O or memory bits */
|
|
||||||
uint16_t cmd = device.config_read(Pci_driver::CMD, Platform::Device::ACCESS_16BIT);
|
|
||||||
if (res.type() == Platform::Device::Resource::IO) {
|
|
||||||
cmd &= ~Pci_driver:: CMD_MEMORY;
|
|
||||||
cmd |= Pci_driver::CMD_IO;
|
|
||||||
} else {
|
|
||||||
cmd &= ~Pci_driver::CMD_IO;
|
|
||||||
cmd |= Pci_driver::CMD_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd |= Pci_driver::CMD_MASTER;
|
|
||||||
|
|
||||||
drv->pci().with_upgrade([&] () {
|
|
||||||
device.config_write(Pci_driver::CMD, cmd, Platform::Device::ACCESS_16BIT);
|
|
||||||
});
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -424,17 +335,25 @@ extern "C" int pci_mapreg_map(struct pci_attach_args *pa,
|
|||||||
extern "C" pcireg_t pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg)
|
extern "C" pcireg_t pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg)
|
||||||
{
|
{
|
||||||
Pci_driver *drv = (Pci_driver *)pc;
|
Pci_driver *drv = (Pci_driver *)pc;
|
||||||
Platform::Device_client device(drv->cap());
|
|
||||||
return device.config_read(reg, Platform::Device::ACCESS_32BIT);
|
switch (reg) {
|
||||||
|
case 0x4: return 0x207; /* command register */
|
||||||
|
case 0x10: return drv->mmio_base();
|
||||||
|
case 0x2c: return drv->sub_device_id() << 16 | drv->sub_vendor_id();
|
||||||
|
default:
|
||||||
|
if (debug)
|
||||||
|
Genode::warning("Ignore reading of PCI config space @ ", reg);
|
||||||
|
};
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extern "C" void pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg,
|
extern "C" void pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg,
|
||||||
pcireg_t val)
|
pcireg_t val)
|
||||||
{
|
{
|
||||||
Pci_driver *drv = (Pci_driver *)pc;
|
if (debug)
|
||||||
Platform::Device_client device(drv->cap());
|
Genode::warning("Ignore writing of PCI config space @ ",
|
||||||
return device.config_write(reg, val, Platform::Device::ACCESS_32BIT);
|
reg, " val=", val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -446,8 +365,7 @@ extern "C" u_int8_t bus_space_read_1(bus_space_tag_t space,
|
|||||||
bus_space_handle_t handle,
|
bus_space_handle_t handle,
|
||||||
bus_size_t offset)
|
bus_size_t offset)
|
||||||
{
|
{
|
||||||
Bus_space *bus = (Bus_space*)space;
|
return ((Pci_driver*)space)->read<Genode::uint8_t>(offset);
|
||||||
return bus->read_1(offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -455,8 +373,7 @@ extern "C" u_int16_t bus_space_read_2(bus_space_tag_t space,
|
|||||||
bus_space_handle_t handle,
|
bus_space_handle_t handle,
|
||||||
bus_size_t offset)
|
bus_size_t offset)
|
||||||
{
|
{
|
||||||
Bus_space *bus = (Bus_space*)space;
|
return ((Pci_driver*)space)->read<Genode::uint16_t>(offset);
|
||||||
return bus->read_2(offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -464,8 +381,7 @@ extern "C" u_int32_t bus_space_read_4(bus_space_tag_t space,
|
|||||||
bus_space_handle_t handle,
|
bus_space_handle_t handle,
|
||||||
bus_size_t offset)
|
bus_size_t offset)
|
||||||
{
|
{
|
||||||
Bus_space *bus = (Bus_space*)space;
|
return ((Pci_driver*)space)->read<Genode::uint32_t>(offset);
|
||||||
return bus->read_4(offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -473,8 +389,7 @@ extern "C" void bus_space_write_1(bus_space_tag_t space,
|
|||||||
bus_space_handle_t handle,
|
bus_space_handle_t handle,
|
||||||
bus_size_t offset, u_int8_t value)
|
bus_size_t offset, u_int8_t value)
|
||||||
{
|
{
|
||||||
Bus_space *bus = (Bus_space*)space;
|
((Pci_driver*)space)->write(offset, value);
|
||||||
bus->write_1(offset, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -482,8 +397,7 @@ extern "C" void bus_space_write_2(bus_space_tag_t space,
|
|||||||
bus_space_handle_t handle,
|
bus_space_handle_t handle,
|
||||||
bus_size_t offset, u_int16_t value)
|
bus_size_t offset, u_int16_t value)
|
||||||
{
|
{
|
||||||
Bus_space *bus = (Bus_space*)space;
|
((Pci_driver*)space)->write(offset, value);
|
||||||
bus->write_2(offset, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -491,8 +405,7 @@ extern "C" void bus_space_write_4(bus_space_tag_t space,
|
|||||||
bus_space_handle_t handle,
|
bus_space_handle_t handle,
|
||||||
bus_size_t offset, u_int32_t value)
|
bus_size_t offset, u_int32_t value)
|
||||||
{
|
{
|
||||||
Bus_space *bus = (Bus_space*)space;
|
((Pci_driver*)space)->write(offset, value);
|
||||||
bus->write_4(offset, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -520,7 +433,7 @@ extern "C" void bus_dmamap_destroy(bus_dma_tag_t tag, bus_dmamap_t map) {
|
|||||||
extern "C" int bus_dmamap_load(bus_dma_tag_t tag, bus_dmamap_t dmam, void *buf,
|
extern "C" int bus_dmamap_load(bus_dma_tag_t tag, bus_dmamap_t dmam, void *buf,
|
||||||
bus_size_t buflen, struct proc *p, int flags)
|
bus_size_t buflen, struct proc *p, int flags)
|
||||||
{
|
{
|
||||||
Bsd::Bus_driver *drv = (Bsd::Bus_driver *)tag;
|
Pci_driver * drv = (Pci_driver*) tag;
|
||||||
|
|
||||||
Genode::addr_t virt = (Genode::addr_t)buf;
|
Genode::addr_t virt = (Genode::addr_t)buf;
|
||||||
dmam->dm_segs[0].ds_addr = drv->virt_to_phys(virt);
|
dmam->dm_segs[0].ds_addr = drv->virt_to_phys(virt);
|
||||||
@ -540,7 +453,7 @@ extern "C" int bus_dmamem_alloc(bus_dma_tag_t tag, bus_size_t size, bus_size_t a
|
|||||||
bus_size_t boundary, bus_dma_segment_t *segs, int nsegs,
|
bus_size_t boundary, bus_dma_segment_t *segs, int nsegs,
|
||||||
int *rsegs, int flags)
|
int *rsegs, int flags)
|
||||||
{
|
{
|
||||||
Bsd::Bus_driver *drv = (Bsd::Bus_driver *)tag;
|
Pci_driver * drv = (Pci_driver*) tag;
|
||||||
|
|
||||||
Genode::addr_t virt = drv->alloc(size, Genode::log2(alignment));
|
Genode::addr_t virt = drv->alloc(size, Genode::log2(alignment));
|
||||||
if (virt == 0)
|
if (virt == 0)
|
||||||
@ -556,7 +469,7 @@ extern "C" int bus_dmamem_alloc(bus_dma_tag_t tag, bus_size_t size, bus_size_t a
|
|||||||
|
|
||||||
extern "C" void bus_dmamem_free(bus_dma_tag_t tag, bus_dma_segment_t *segs, int nsegs)
|
extern "C" void bus_dmamem_free(bus_dma_tag_t tag, bus_dma_segment_t *segs, int nsegs)
|
||||||
{
|
{
|
||||||
Bsd::Bus_driver *drv = (Bsd::Bus_driver *)tag;
|
Pci_driver * drv = (Pci_driver*) tag;
|
||||||
|
|
||||||
for (int i = 0; i < nsegs; i++) {
|
for (int i = 0; i < nsegs; i++) {
|
||||||
Genode::addr_t phys = (Genode::addr_t)segs[i].ds_addr;
|
Genode::addr_t phys = (Genode::addr_t)segs[i].ds_addr;
|
||||||
@ -575,7 +488,7 @@ extern "C" int bus_dmamem_map(bus_dma_tag_t tag, bus_dma_segment_t *segs, int ns
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bsd::Bus_driver *drv = (Bsd::Bus_driver *)tag;
|
Pci_driver * drv = (Pci_driver*) tag;
|
||||||
|
|
||||||
Genode::addr_t phys = (Genode::addr_t)segs[0].ds_addr;
|
Genode::addr_t phys = (Genode::addr_t)segs[0].ds_addr;
|
||||||
Genode::addr_t virt = drv->phys_to_virt(phys);
|
Genode::addr_t virt = drv->phys_to_virt(phys);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user