From b9869b666a2295a92ebb97819bab26ea7c6c97d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josef=20S=C3=B6ntgen?= Date: Fri, 26 Jun 2020 17:13:58 +0200 Subject: [PATCH] dde_bsd: use bsd_task to handle I/O Originally, the kernel code should have been executed within the context of the main task like it is done in dde_linux. The initial port of the HDA driver, however, did not required doing so and the session called code directly. When using USB device, that is no longer possible as we have to suspend the execution during the execution of the kernel code. So we pass in the audio data and schedule the kernel. Fixes #3929. --- repos/dde_bsd/src/lib/audio/driver.cc | 110 ++++++++++++++++++++++---- 1 file changed, 95 insertions(+), 15 deletions(-) diff --git a/repos/dde_bsd/src/lib/audio/driver.cc b/repos/dde_bsd/src/lib/audio/driver.cc index e9bbf72377..4e70006095 100644 --- a/repos/dde_bsd/src/lib/audio/driver.cc +++ b/repos/dde_bsd/src/lib/audio/driver.cc @@ -410,6 +410,9 @@ static bool configure_audio_device(Genode::Env &env, dev_t dev, Genode::Xml_node } +static void run_bsd(void *p); + + namespace { struct Task_args @@ -427,14 +430,77 @@ namespace { announce_sigh(announce_sigh) { } }; + + struct Task + { + Task_args _args; + + Bsd::Task _task; + + Genode::Signal_handler _handler; + + void _handle_signal() + { + _task.unblock(); + Bsd::scheduler().schedule(); + } + + struct Operation + { + struct uio uio; + bool pending; + int result; + }; + + Operation _play { { 0, 0, UIO_READ, nullptr, 0 }, false, -1 }; + Operation _record { { 0, 0, UIO_WRITE, nullptr, 0 }, false, -1 }; + + template + Task(Genode::Env &env, Genode::Allocator &alloc, + Genode::Xml_node config, + Genode::Signal_context_capability announce_sigh) + : + _args { env, alloc, config, announce_sigh }, + _task { run_bsd, this, "bsd", Bsd::Task::PRIORITY_0, + Bsd::scheduler(), 2048 * sizeof(Genode::addr_t) }, + _handler { env.ep(), *this, &Task::_handle_signal } + { } + + void unblock() { _task.unblock(); } + + void request_playback(short *src, size_t size) + { + _play.uio = { 0, size, UIO_READ, src, size }; + _play.pending = true; + _play.result = -1; + } + + int playback_result() const + { + return _play.result; + } + + void request_recording(short *dst, size_t size) + { + _record.uio = { 0, size, UIO_WRITE, dst, size }; + _record.pending = true; + _record.result = -1; + } + + int recording_result() const + { + return _record.result; + } + }; } -static void run_bsd(void *p) +void run_bsd(void *p) { - Task_args *args = static_cast(p); + Task *task = static_cast(p); - int const success = Bsd::probe_drivers(args->env, args->alloc); + int const success = Bsd::probe_drivers(task->_args.env, + task->_args.alloc); if (!success) { Genode::error("no supported sound card found"); Genode::sleep_forever(); @@ -445,14 +511,24 @@ static void run_bsd(void *p) Genode::sleep_forever(); } - adev_usuable = configure_audio_device(args->env, adev, args->config); + adev_usuable = configure_audio_device(task->_args.env, adev, + task->_args.config); - if (adev_usuable && args->announce_sigh.valid()) { - Genode::Signal_transmitter(args->announce_sigh).submit(); + if (adev_usuable && task->_args.announce_sigh.valid()) { + Genode::Signal_transmitter(task->_args.announce_sigh).submit(); } while (true) { Bsd::scheduler().current()->block_and_schedule(); + + if (task->_play.pending) { + task->_play.result = audiowrite(adev, &task->_play.uio, IO_NDELAY); + task->_play.pending = false; + } + if (task->_record.pending) { + task->_record.result = audioread(adev, &task->_record.uio, IO_NDELAY); + task->_record.pending = false; + } } } @@ -497,6 +573,9 @@ void Audio::update_config(Genode::Env &env, Genode::Xml_node config) } +static Task *_bsd_task; + + void Audio::init_driver(Genode::Env &env, Genode::Allocator &alloc, Genode::Xml_node config, Genode::Signal_context_capability announce_sigh) @@ -505,11 +584,8 @@ void Audio::init_driver(Genode::Env &env, Genode::Allocator &alloc, Bsd::irq_init(env.ep(), alloc); Bsd::timer_init(env); - static Task_args args(env, alloc, config, announce_sigh); - - static Bsd::Task task_bsd(run_bsd, &args, "bsd", - Bsd::Task::PRIORITY_0, Bsd::scheduler(), - 2048 * sizeof(Genode::addr_t)); + static Task bsd_task(env, alloc, config, announce_sigh); + _bsd_task = &bsd_task; Bsd::scheduler().schedule(); } @@ -524,13 +600,17 @@ void Audio::record_sigh(Genode::Signal_context_capability sigh) { int Audio::play(short *data, Genode::size_t size) { - struct uio uio = { 0, size, UIO_READ, data, size }; - return audiowrite(adev, &uio, IO_NDELAY); + _bsd_task->request_playback(data, size); + _bsd_task->unblock(); + Bsd::scheduler().schedule(); + return _bsd_task->playback_result(); } int Audio::record(short *data, Genode::size_t size) { - struct uio uio = { 0, size, UIO_WRITE, data, size }; - return audioread(adev, &uio, IO_NDELAY); + _bsd_task->request_recording(data, size); + _bsd_task->unblock(); + Bsd::scheduler().schedule(); + return _bsd_task->recording_result(); }