Compare commits
19 Commits
5c20d5e291
...
f77aa65dc5
| Author | SHA1 | Date | |
|---|---|---|---|
| f77aa65dc5 | |||
| 9589b5984d | |||
| 32806a5af3 | |||
| 876fbe3d7c | |||
| c1b8f5e475 | |||
| cf31ea9cbe | |||
| 7e6b8c93b4 | |||
| dd2bbe4588 | |||
| e01e35713b | |||
| 82d5d9ba58 | |||
| d168492462 | |||
| 6f2e8320a9 | |||
| bf4831f468 | |||
| 5647cf24d2 | |||
| 85f61aded5 | |||
| 21639071c2 | |||
| 68506a789a | |||
| d9ca25b796 | |||
| e9c81477d7 |
@@ -6,19 +6,6 @@
|
|||||||
|
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
|
||||||
// This is ugly but my clangd does not like including
|
|
||||||
// intrinsic headers at all
|
|
||||||
#if !defined(__SSE__) || !defined(__SSE2__)
|
|
||||||
#pragma GCC push_options
|
|
||||||
#ifndef __SSE__
|
|
||||||
#pragma GCC target("sse")
|
|
||||||
#endif
|
|
||||||
#ifndef __SSE2__
|
|
||||||
#pragma GCC target("sse2")
|
|
||||||
#endif
|
|
||||||
#define BAN_MATH_POP_OPTIONS
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace BAN::Math
|
namespace BAN::Math
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -49,12 +36,11 @@ namespace BAN::Math
|
|||||||
template<integral T>
|
template<integral T>
|
||||||
inline constexpr T gcd(T a, T b)
|
inline constexpr T gcd(T a, T b)
|
||||||
{
|
{
|
||||||
T t;
|
|
||||||
while (b)
|
while (b)
|
||||||
{
|
{
|
||||||
t = b;
|
T temp = b;
|
||||||
b = a % b;
|
b = a % b;
|
||||||
a = t;
|
a = temp;
|
||||||
}
|
}
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
@@ -79,25 +65,20 @@ namespace BAN::Math
|
|||||||
return (x & (x - 1)) == 0;
|
return (x & (x - 1)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<BAN::integral T>
|
template<integral T>
|
||||||
static constexpr bool will_multiplication_overflow(T a, T b)
|
__attribute__((always_inline))
|
||||||
|
inline constexpr bool will_multiplication_overflow(T a, T b)
|
||||||
{
|
{
|
||||||
if (a == 0 || b == 0)
|
T dummy;
|
||||||
return false;
|
return __builtin_mul_overflow(a, b, &dummy);
|
||||||
if ((a > 0) == (b > 0))
|
|
||||||
return a > BAN::numeric_limits<T>::max() / b;
|
|
||||||
else
|
|
||||||
return a < BAN::numeric_limits<T>::min() / b;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<BAN::integral T>
|
template<integral T>
|
||||||
static constexpr bool will_addition_overflow(T a, T b)
|
__attribute__((always_inline))
|
||||||
|
inline constexpr bool will_addition_overflow(T a, T b)
|
||||||
{
|
{
|
||||||
if (a > 0 && b > 0)
|
T dummy;
|
||||||
return a > BAN::numeric_limits<T>::max() - b;
|
return __builtin_add_overflow(a, b, &dummy);
|
||||||
if (a < 0 && b < 0)
|
|
||||||
return a < BAN::numeric_limits<T>::min() - b;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -111,6 +92,19 @@ namespace BAN::Math
|
|||||||
return sizeof(T) * 8 - __builtin_clzll(x) - 1;
|
return sizeof(T) * 8 - __builtin_clzll(x) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is ugly but my clangd does not like including
|
||||||
|
// intrinsic headers at all
|
||||||
|
#if !defined(__SSE__) || !defined(__SSE2__)
|
||||||
|
#pragma GCC push_options
|
||||||
|
#ifndef __SSE__
|
||||||
|
#pragma GCC target("sse")
|
||||||
|
#endif
|
||||||
|
#ifndef __SSE2__
|
||||||
|
#pragma GCC target("sse2")
|
||||||
|
#endif
|
||||||
|
#define BAN_MATH_POP_OPTIONS
|
||||||
|
#endif
|
||||||
|
|
||||||
template<floating_point T>
|
template<floating_point T>
|
||||||
inline constexpr T floor(T x)
|
inline constexpr T floor(T x)
|
||||||
{
|
{
|
||||||
@@ -172,7 +166,23 @@ namespace BAN::Math
|
|||||||
"jne 1b;"
|
"jne 1b;"
|
||||||
: "+t"(a)
|
: "+t"(a)
|
||||||
: "u"(b)
|
: "u"(b)
|
||||||
: "ax"
|
: "ax", "cc"
|
||||||
|
);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<floating_point T>
|
||||||
|
inline constexpr T remainder(T a, T b)
|
||||||
|
{
|
||||||
|
asm(
|
||||||
|
"1:"
|
||||||
|
"fprem1;"
|
||||||
|
"fnstsw %%ax;"
|
||||||
|
"testb $4, %%ah;"
|
||||||
|
"jne 1b;"
|
||||||
|
: "+t"(a)
|
||||||
|
: "u"(b)
|
||||||
|
: "ax", "cc"
|
||||||
);
|
);
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
@@ -447,9 +457,9 @@ namespace BAN::Math
|
|||||||
return sqrt<T>(x * x + y * y);
|
return sqrt<T>(x * x + y * y);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef BAN_MATH_POP_OPTIONS
|
#ifdef BAN_MATH_POP_OPTIONS
|
||||||
#undef BAN_MATH_POP_OPTIONS
|
#undef BAN_MATH_POP_OPTIONS
|
||||||
#pragma GCC pop_options
|
#pragma GCC pop_options
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
Binary file not shown.
@@ -139,6 +139,7 @@ if("${BANAN_ARCH}" STREQUAL "x86_64")
|
|||||||
arch/x86_64/Signal.S
|
arch/x86_64/Signal.S
|
||||||
arch/x86_64/Syscall.S
|
arch/x86_64/Syscall.S
|
||||||
arch/x86_64/Thread.S
|
arch/x86_64/Thread.S
|
||||||
|
arch/x86_64/User.S
|
||||||
arch/x86_64/Yield.S
|
arch/x86_64/Yield.S
|
||||||
)
|
)
|
||||||
elseif("${BANAN_ARCH}" STREQUAL "i686")
|
elseif("${BANAN_ARCH}" STREQUAL "i686")
|
||||||
@@ -150,6 +151,7 @@ elseif("${BANAN_ARCH}" STREQUAL "i686")
|
|||||||
arch/i686/Signal.S
|
arch/i686/Signal.S
|
||||||
arch/i686/Syscall.S
|
arch/i686/Syscall.S
|
||||||
arch/i686/Thread.S
|
arch/i686/Thread.S
|
||||||
|
arch/i686/User.S
|
||||||
arch/i686/Yield.S
|
arch/i686/Yield.S
|
||||||
)
|
)
|
||||||
else()
|
else()
|
||||||
|
|||||||
54
kernel/arch/i686/User.S
Normal file
54
kernel/arch/i686/User.S
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# bool safe_user_memcpy(void*, const void*, size_t)
|
||||||
|
.global safe_user_memcpy
|
||||||
|
.global safe_user_memcpy_end
|
||||||
|
.global safe_user_memcpy_fault
|
||||||
|
safe_user_memcpy:
|
||||||
|
xorl %eax, %eax
|
||||||
|
xchgl 4(%esp), %edi
|
||||||
|
xchgl 8(%esp), %esi
|
||||||
|
movl 12(%esp), %ecx
|
||||||
|
movl %edi, %edx
|
||||||
|
rep movsb
|
||||||
|
movl 4(%esp), %edi
|
||||||
|
movl 8(%esp), %esi
|
||||||
|
incl %eax
|
||||||
|
safe_user_memcpy_fault:
|
||||||
|
ret
|
||||||
|
safe_user_memcpy_end:
|
||||||
|
|
||||||
|
# bool safe_user_strncpy(void*, const void*, size_t)
|
||||||
|
.global safe_user_strncpy
|
||||||
|
.global safe_user_strncpy_end
|
||||||
|
.global safe_user_strncpy_fault
|
||||||
|
safe_user_strncpy:
|
||||||
|
xchgl 4(%esp), %edi
|
||||||
|
xchgl 8(%esp), %esi
|
||||||
|
movl 12(%esp), %ecx
|
||||||
|
|
||||||
|
testl %ecx, %ecx
|
||||||
|
jz safe_user_strncpy_fault
|
||||||
|
|
||||||
|
.safe_user_strncpy_loop:
|
||||||
|
movb (%esi), %al
|
||||||
|
movb %al, (%edi)
|
||||||
|
testb %al, %al
|
||||||
|
jz .safe_user_strncpy_done
|
||||||
|
|
||||||
|
incl %edi
|
||||||
|
incl %esi
|
||||||
|
decl %ecx
|
||||||
|
jnz .safe_user_strncpy_loop
|
||||||
|
|
||||||
|
safe_user_strncpy_fault:
|
||||||
|
xorl %eax, %eax
|
||||||
|
jmp .safe_user_strncpy_return
|
||||||
|
|
||||||
|
.safe_user_strncpy_done:
|
||||||
|
movl $1, %eax
|
||||||
|
|
||||||
|
.safe_user_strncpy_return:
|
||||||
|
movl 4(%esp), %edi
|
||||||
|
movl 8(%esp), %esi
|
||||||
|
ret
|
||||||
|
|
||||||
|
safe_user_strncpy_end:
|
||||||
@@ -866,7 +866,7 @@ namespace Kernel
|
|||||||
last_address -= rem;
|
last_address -= rem;
|
||||||
|
|
||||||
ASSERT(is_canonical(first_address));
|
ASSERT(is_canonical(first_address));
|
||||||
ASSERT(is_canonical(last_address));
|
ASSERT(is_canonical(last_address - 1));
|
||||||
const vaddr_t uc_vaddr_start = uncanonicalize(first_address);
|
const vaddr_t uc_vaddr_start = uncanonicalize(first_address);
|
||||||
const vaddr_t uc_vaddr_end = uncanonicalize(last_address);
|
const vaddr_t uc_vaddr_end = uncanonicalize(last_address);
|
||||||
|
|
||||||
@@ -948,7 +948,7 @@ namespace Kernel
|
|||||||
last_address -= rem;
|
last_address -= rem;
|
||||||
|
|
||||||
ASSERT(is_canonical(first_address));
|
ASSERT(is_canonical(first_address));
|
||||||
ASSERT(is_canonical(last_address));
|
ASSERT(is_canonical(last_address - 1));
|
||||||
|
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard _(m_lock);
|
||||||
|
|
||||||
|
|||||||
87
kernel/arch/x86_64/User.S
Normal file
87
kernel/arch/x86_64/User.S
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
# bool safe_user_memcpy(void*, const void*, size_t)
|
||||||
|
.global safe_user_memcpy
|
||||||
|
.global safe_user_memcpy_end
|
||||||
|
.global safe_user_memcpy_fault
|
||||||
|
safe_user_memcpy:
|
||||||
|
xorq %rax, %rax
|
||||||
|
movq %rdx, %rcx
|
||||||
|
rep movsb
|
||||||
|
incq %rax
|
||||||
|
safe_user_memcpy_fault:
|
||||||
|
ret
|
||||||
|
safe_user_memcpy_end:
|
||||||
|
|
||||||
|
# bool safe_user_strncpy(void*, const void*, size_t)
|
||||||
|
.global safe_user_strncpy
|
||||||
|
.global safe_user_strncpy_end
|
||||||
|
.global safe_user_strncpy_fault
|
||||||
|
safe_user_strncpy:
|
||||||
|
movq %rdx, %rcx
|
||||||
|
testq %rcx, %rcx
|
||||||
|
jz safe_user_strncpy_fault
|
||||||
|
|
||||||
|
.safe_user_strncpy_align_loop:
|
||||||
|
testb $0x7, %sil
|
||||||
|
jz .safe_user_strncpy_align_done
|
||||||
|
|
||||||
|
movb (%rsi), %al
|
||||||
|
movb %al, (%rdi)
|
||||||
|
testb %al, %al
|
||||||
|
jz .safe_user_strncpy_done
|
||||||
|
|
||||||
|
incq %rdi
|
||||||
|
incq %rsi
|
||||||
|
decq %rcx
|
||||||
|
jnz .safe_user_strncpy_align_loop
|
||||||
|
jmp safe_user_strncpy_fault
|
||||||
|
|
||||||
|
.safe_user_strncpy_align_done:
|
||||||
|
movq $0x0101010101010101, %r8
|
||||||
|
movq $0x8080808080808080, %r9
|
||||||
|
|
||||||
|
.safe_user_strncpy_qword_loop:
|
||||||
|
cmpq $8, %rcx
|
||||||
|
jb .safe_user_strncpy_qword_done
|
||||||
|
|
||||||
|
movq (%rsi), %rax
|
||||||
|
movq %rax, %r10
|
||||||
|
movq %rax, %r11
|
||||||
|
|
||||||
|
# https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
|
||||||
|
subq %r8, %r10
|
||||||
|
notq %r11
|
||||||
|
andq %r11, %r10
|
||||||
|
andq %r9, %r10
|
||||||
|
jnz .safe_user_strncpy_byte_loop
|
||||||
|
|
||||||
|
movq %rax, (%rdi)
|
||||||
|
|
||||||
|
addq $8, %rdi
|
||||||
|
addq $8, %rsi
|
||||||
|
subq $8, %rcx
|
||||||
|
jnz .safe_user_strncpy_qword_loop
|
||||||
|
jmp safe_user_strncpy_fault
|
||||||
|
|
||||||
|
.safe_user_strncpy_qword_done:
|
||||||
|
testq %rcx, %rcx
|
||||||
|
jz safe_user_strncpy_fault
|
||||||
|
|
||||||
|
.safe_user_strncpy_byte_loop:
|
||||||
|
movb (%rsi), %al
|
||||||
|
movb %al, (%rdi)
|
||||||
|
testb %al, %al
|
||||||
|
jz .safe_user_strncpy_done
|
||||||
|
|
||||||
|
incq %rdi
|
||||||
|
incq %rsi
|
||||||
|
decq %rcx
|
||||||
|
jnz .safe_user_strncpy_byte_loop
|
||||||
|
|
||||||
|
safe_user_strncpy_fault:
|
||||||
|
xorq %rax, %rax
|
||||||
|
ret
|
||||||
|
|
||||||
|
.safe_user_strncpy_done:
|
||||||
|
movb $1, %al
|
||||||
|
ret
|
||||||
|
safe_user_strncpy_end:
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
class AC97AudioController : public AudioController, public Interruptable
|
class AC97AudioController final : public AudioController, public Interruptable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static BAN::ErrorOr<void> create(PCI::Device& pci_device);
|
static BAN::ErrorOr<void> create(PCI::Device& pci_device);
|
||||||
@@ -23,11 +23,15 @@ namespace Kernel
|
|||||||
uint32_t get_current_pin() const override { return 0; }
|
uint32_t get_current_pin() const override { return 0; }
|
||||||
BAN::ErrorOr<void> set_current_pin(uint32_t pin) override { if (pin != 0) return BAN::Error::from_errno(EINVAL); return {}; }
|
BAN::ErrorOr<void> set_current_pin(uint32_t pin) override { if (pin != 0) return BAN::Error::from_errno(EINVAL); return {}; }
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> set_volume_mdB(int32_t) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AC97AudioController(PCI::Device& pci_device)
|
AC97AudioController(PCI::Device& pci_device)
|
||||||
: m_pci_device(pci_device)
|
: m_pci_device(pci_device)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
uint32_t get_volume_data() const;
|
||||||
|
|
||||||
BAN::ErrorOr<void> initialize();
|
BAN::ErrorOr<void> initialize();
|
||||||
BAN::ErrorOr<void> initialize_bld();
|
BAN::ErrorOr<void> initialize_bld();
|
||||||
BAN::ErrorOr<void> initialize_interrupts();
|
BAN::ErrorOr<void> initialize_interrupts();
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
#include <kernel/Memory/ByteRingBuffer.h>
|
#include <kernel/Memory/ByteRingBuffer.h>
|
||||||
#include <kernel/PCI.h>
|
#include <kernel/PCI.h>
|
||||||
|
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -28,6 +30,8 @@ namespace Kernel
|
|||||||
virtual uint32_t get_current_pin() const = 0;
|
virtual uint32_t get_current_pin() const = 0;
|
||||||
virtual BAN::ErrorOr<void> set_current_pin(uint32_t) = 0;
|
virtual BAN::ErrorOr<void> set_current_pin(uint32_t) = 0;
|
||||||
|
|
||||||
|
virtual BAN::ErrorOr<void> set_volume_mdB(int32_t) = 0;
|
||||||
|
|
||||||
bool can_read_impl() const override { return false; }
|
bool can_read_impl() const override { return false; }
|
||||||
bool can_write_impl() const override { SpinLockGuard _(m_spinlock); return !m_sample_data->full(); }
|
bool can_write_impl() const override { SpinLockGuard _(m_spinlock); return !m_sample_data->full(); }
|
||||||
bool has_error_impl() const override { return false; }
|
bool has_error_impl() const override { return false; }
|
||||||
@@ -44,6 +48,8 @@ namespace Kernel
|
|||||||
static constexpr size_t m_sample_data_capacity = 1 << 20;
|
static constexpr size_t m_sample_data_capacity = 1 << 20;
|
||||||
BAN::UniqPtr<ByteRingBuffer> m_sample_data;
|
BAN::UniqPtr<ByteRingBuffer> m_sample_data;
|
||||||
|
|
||||||
|
snd_volume_info m_volume_info {};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const dev_t m_rdev;
|
const dev_t m_rdev;
|
||||||
char m_name[10] {};
|
char m_name[10] {};
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace Kernel
|
|||||||
|
|
||||||
class HDAudioController;
|
class HDAudioController;
|
||||||
|
|
||||||
class HDAudioFunctionGroup : public AudioController
|
class HDAudioFunctionGroup final : public AudioController
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static BAN::ErrorOr<BAN::RefPtr<HDAudioFunctionGroup>> create(BAN::RefPtr<HDAudioController>, uint8_t cid, HDAudio::AFGNode&&);
|
static BAN::ErrorOr<BAN::RefPtr<HDAudioFunctionGroup>> create(BAN::RefPtr<HDAudioController>, uint8_t cid, HDAudio::AFGNode&&);
|
||||||
@@ -24,6 +24,8 @@ namespace Kernel
|
|||||||
uint32_t get_current_pin() const override;
|
uint32_t get_current_pin() const override;
|
||||||
BAN::ErrorOr<void> set_current_pin(uint32_t) override;
|
BAN::ErrorOr<void> set_current_pin(uint32_t) override;
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> set_volume_mdB(int32_t) override;
|
||||||
|
|
||||||
void handle_new_data() override;
|
void handle_new_data() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -46,7 +48,6 @@ namespace Kernel
|
|||||||
BAN::ErrorOr<void> recurse_output_paths(const HDAudio::AFGWidget& widget, BAN::Vector<const HDAudio::AFGWidget*>& path);
|
BAN::ErrorOr<void> recurse_output_paths(const HDAudio::AFGWidget& widget, BAN::Vector<const HDAudio::AFGWidget*>& path);
|
||||||
|
|
||||||
uint16_t get_format_data() const;
|
uint16_t get_format_data() const;
|
||||||
uint16_t get_volume_data() const;
|
|
||||||
|
|
||||||
size_t bdl_offset() const;
|
size_t bdl_offset() const;
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,16 @@ namespace Kernel::HDAudio
|
|||||||
} pin_complex;
|
} pin_complex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Amplifier
|
||||||
|
{
|
||||||
|
uint8_t offset;
|
||||||
|
uint8_t num_steps;
|
||||||
|
uint8_t step_size;
|
||||||
|
bool mute;
|
||||||
|
};
|
||||||
|
|
||||||
|
BAN::Optional<Amplifier> output_amplifier;
|
||||||
|
|
||||||
BAN::Vector<uint16_t> connections;
|
BAN::Vector<uint16_t> connections;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#if ARCH(x86_64)
|
#if ARCH(x86_64)
|
||||||
#define KERNEL_OFFSET 0xFFFFFFFF80000000
|
#define KERNEL_OFFSET 0xFFFFFFFF80000000
|
||||||
#define USERSPACE_END 0xFFFF800000000000
|
#define USERSPACE_END 0x800000000000
|
||||||
#elif ARCH(i686)
|
#elif ARCH(i686)
|
||||||
#define KERNEL_OFFSET 0xC0000000
|
#define KERNEL_OFFSET 0xC0000000
|
||||||
#define USERSPACE_END 0xC0000000
|
#define USERSPACE_END 0xC0000000
|
||||||
|
|||||||
@@ -137,8 +137,27 @@ namespace Kernel
|
|||||||
// Reset mixer to default values
|
// Reset mixer to default values
|
||||||
m_mixer->write16(AudioMixerRegister::Reset, 0);
|
m_mixer->write16(AudioMixerRegister::Reset, 0);
|
||||||
|
|
||||||
// Master volume 100%, no mute
|
// Master volumes
|
||||||
m_mixer->write16(AudioMixerRegister::MasterVolume, 0x0000);
|
m_mixer->write16(AudioMixerRegister::MasterVolume, 0x2020);
|
||||||
|
if (m_mixer->read16(AudioMixerRegister::MasterVolume) == 0x2020)
|
||||||
|
{
|
||||||
|
m_volume_info = {
|
||||||
|
.min_mdB = -94500,
|
||||||
|
.max_mdB = 0,
|
||||||
|
.step_mdB = 1500,
|
||||||
|
.mdB = 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_volume_info = {
|
||||||
|
.min_mdB = -46500,
|
||||||
|
.max_mdB = 0,
|
||||||
|
.step_mdB = 1500,
|
||||||
|
.mdB = 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
m_mixer->write16(AudioMixerRegister::MasterVolume, get_volume_data());
|
||||||
|
|
||||||
// PCM output volume left/right +0 db, no mute
|
// PCM output volume left/right +0 db, no mute
|
||||||
m_mixer->write16(AudioMixerRegister::PCMOutVolume, 0x0808);
|
m_mixer->write16(AudioMixerRegister::PCMOutVolume, 0x0808);
|
||||||
@@ -187,6 +206,19 @@ namespace Kernel
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t AC97AudioController::get_volume_data() const
|
||||||
|
{
|
||||||
|
const uint32_t steps = (-m_volume_info.mdB + m_volume_info.step_mdB / 2) / m_volume_info.step_mdB;
|
||||||
|
return (steps << 8) | steps;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> AC97AudioController::set_volume_mdB(int32_t mdB)
|
||||||
|
{
|
||||||
|
m_volume_info.mdB = BAN::Math::clamp(mdB, m_volume_info.min_mdB, m_volume_info.max_mdB);
|
||||||
|
m_mixer->write16(AudioMixerRegister::MasterVolume, get_volume_data());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
void AC97AudioController::handle_new_data()
|
void AC97AudioController::handle_new_data()
|
||||||
{
|
{
|
||||||
ASSERT(m_spinlock.current_processor_has_lock());
|
ASSERT(m_spinlock.current_processor_has_lock());
|
||||||
|
|||||||
@@ -105,6 +105,12 @@ namespace Kernel
|
|||||||
case SND_SET_PIN:
|
case SND_SET_PIN:
|
||||||
TRY(set_current_pin(*static_cast<uint32_t*>(arg)));
|
TRY(set_current_pin(*static_cast<uint32_t*>(arg)));
|
||||||
return 0;
|
return 0;
|
||||||
|
case SND_GET_VOLUME_INFO:
|
||||||
|
*static_cast<snd_volume_info*>(arg) = m_volume_info;
|
||||||
|
return 0;
|
||||||
|
case SND_SET_VOLUME_MDB:
|
||||||
|
TRY(set_volume_mdB(*static_cast<int32_t*>(arg)));
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CharacterDevice::ioctl_impl(cmd, arg);
|
return CharacterDevice::ioctl_impl(cmd, arg);
|
||||||
|
|||||||
@@ -136,6 +136,37 @@ namespace Kernel
|
|||||||
return BAN::Error::from_errno(ENOTSUP);
|
return BAN::Error::from_errno(ENOTSUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> HDAudioFunctionGroup::set_volume_mdB(int32_t mdB)
|
||||||
|
{
|
||||||
|
mdB = BAN::Math::clamp(mdB, m_volume_info.min_mdB, m_volume_info.max_mdB);
|
||||||
|
|
||||||
|
const auto& path = m_output_paths[m_output_path_index];
|
||||||
|
for (size_t i = 0; i < path.size(); i++)
|
||||||
|
{
|
||||||
|
if (!path[i]->output_amplifier.has_value())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const int32_t step_round = (mdB >= 0)
|
||||||
|
? +m_volume_info.step_mdB / 2
|
||||||
|
: -m_volume_info.step_mdB / 2;
|
||||||
|
const uint32_t step = (mdB + step_round) / m_volume_info.step_mdB + path[i]->output_amplifier->offset;
|
||||||
|
const uint32_t volume = 0b1'0'1'1'0000'0'0000000 | step;
|
||||||
|
|
||||||
|
TRY(m_controller->send_command({
|
||||||
|
.data = static_cast<uint8_t>(volume & 0xFF),
|
||||||
|
.command = static_cast<uint16_t>(0x300 | (volume >> 8)),
|
||||||
|
.node_index = path[i]->id,
|
||||||
|
.codec_address = m_cid,
|
||||||
|
}));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_volume_info.mdB = mdB;
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
size_t HDAudioFunctionGroup::bdl_offset() const
|
size_t HDAudioFunctionGroup::bdl_offset() const
|
||||||
{
|
{
|
||||||
const size_t bdl_entry_bytes = m_bdl_entry_sample_frames * get_channels() * sizeof(uint16_t);
|
const size_t bdl_entry_bytes = m_bdl_entry_sample_frames * get_channels() * sizeof(uint16_t);
|
||||||
@@ -291,13 +322,6 @@ namespace Kernel
|
|||||||
return 0b0'0'000'000'0'001'0001;
|
return 0b0'0'000'000'0'001'0001;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t HDAudioFunctionGroup::get_volume_data() const
|
|
||||||
{
|
|
||||||
// TODO: don't hardcode this
|
|
||||||
// left and right output, no mute, max gain
|
|
||||||
return 0b1'0'1'1'0000'0'1111111;
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::ErrorOr<void> HDAudioFunctionGroup::enable_output_path(uint8_t index)
|
BAN::ErrorOr<void> HDAudioFunctionGroup::enable_output_path(uint8_t index)
|
||||||
{
|
{
|
||||||
ASSERT(index < m_output_paths.size());
|
ASSERT(index < m_output_paths.size());
|
||||||
@@ -318,7 +342,6 @@ namespace Kernel
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto format = get_format_data();
|
const auto format = get_format_data();
|
||||||
const auto volume = get_volume_data();
|
|
||||||
|
|
||||||
for (size_t i = 0; i < path.size(); i++)
|
for (size_t i = 0; i < path.size(); i++)
|
||||||
{
|
{
|
||||||
@@ -347,13 +370,17 @@ namespace Kernel
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// set volume
|
// set volume to 0 dB, no mute
|
||||||
|
if (path[i]->output_amplifier.has_value())
|
||||||
|
{
|
||||||
|
const uint32_t volume = 0b1'0'1'1'0000'0'0000000 | path[i]->output_amplifier->offset;
|
||||||
TRY(m_controller->send_command({
|
TRY(m_controller->send_command({
|
||||||
.data = static_cast<uint8_t>(volume & 0xFF),
|
.data = static_cast<uint8_t>(volume & 0xFF),
|
||||||
.command = static_cast<uint16_t>(0x300 | (volume >> 8)),
|
.command = static_cast<uint16_t>(0x300 | (volume >> 8)),
|
||||||
.node_index = path[i]->id,
|
.node_index = path[i]->id,
|
||||||
.codec_address = m_cid,
|
.codec_address = m_cid,
|
||||||
}));
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
switch (path[i]->type)
|
switch (path[i]->type)
|
||||||
{
|
{
|
||||||
@@ -398,6 +425,41 @@ namespace Kernel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update volume info to this path
|
||||||
|
m_volume_info.min_mdB = 0;
|
||||||
|
m_volume_info.max_mdB = 0;
|
||||||
|
m_volume_info.step_mdB = 0;
|
||||||
|
for (size_t i = 0; i < path.size(); i++)
|
||||||
|
{
|
||||||
|
if (!path[i]->output_amplifier.has_value())
|
||||||
|
continue;
|
||||||
|
const auto& amp = path[i]->output_amplifier.value();
|
||||||
|
|
||||||
|
const int32_t step_mdB = amp.step_size * 250;
|
||||||
|
m_volume_info.step_mdB = step_mdB;
|
||||||
|
m_volume_info.min_mdB = -amp.offset * step_mdB;
|
||||||
|
m_volume_info.max_mdB = (amp.num_steps - amp.offset) * step_mdB;
|
||||||
|
m_volume_info.mdB = BAN::Math::clamp(m_volume_info.mdB, m_volume_info.min_mdB, m_volume_info.max_mdB);
|
||||||
|
|
||||||
|
const int32_t step_round = (m_volume_info.mdB >= 0)
|
||||||
|
? +step_mdB / 2
|
||||||
|
: -step_mdB / 2;
|
||||||
|
const uint32_t step = (m_volume_info.mdB + step_round) / step_mdB + amp.offset;
|
||||||
|
const uint32_t volume = 0b1'0'1'1'0000'0'0000000 | step;
|
||||||
|
|
||||||
|
TRY(m_controller->send_command({
|
||||||
|
.data = static_cast<uint8_t>(volume & 0xFF),
|
||||||
|
.command = static_cast<uint16_t>(0x300 | (volume >> 8)),
|
||||||
|
.node_index = path[i]->id,
|
||||||
|
.codec_address = m_cid,
|
||||||
|
}));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_volume_info.min_mdB == 0 && m_volume_info.max_mdB == 0)
|
||||||
|
m_volume_info.mdB = 0;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -319,6 +319,20 @@ namespace Kernel
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (const uint32_t out_amp_cap = send_command_or_zero(0xF00, 0x12))
|
||||||
|
{
|
||||||
|
const uint8_t offset = (out_amp_cap >> 0) & 0x7F;
|
||||||
|
const uint8_t num_steps = (out_amp_cap >> 8) & 0x7F;
|
||||||
|
const uint8_t step_size = (out_amp_cap >> 16) & 0x7F;
|
||||||
|
const bool mute = (out_amp_cap >> 31);
|
||||||
|
result.output_amplifier = HDAudio::AFGWidget::Amplifier {
|
||||||
|
.offset = offset,
|
||||||
|
.num_steps = num_steps,
|
||||||
|
.step_size = step_size,
|
||||||
|
.mute = mute,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const uint8_t connection_info = send_command_or_zero(0xF00, 0x0E);
|
const uint8_t connection_info = send_command_or_zero(0xF00, 0x0E);
|
||||||
const uint8_t conn_width = (connection_info & 0x80) ? 2 : 1;
|
const uint8_t conn_width = (connection_info & 0x80) ? 2 : 1;
|
||||||
const uint8_t conn_count = connection_info & 0x3F;
|
const uint8_t conn_count = connection_info & 0x3F;
|
||||||
|
|||||||
@@ -164,6 +164,33 @@ namespace Kernel
|
|||||||
"Unkown Exception 0x1F",
|
"Unkown Exception 0x1F",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern "C" uint8_t safe_user_memcpy[];
|
||||||
|
extern "C" uint8_t safe_user_memcpy_end[];
|
||||||
|
extern "C" uint8_t safe_user_memcpy_fault[];
|
||||||
|
|
||||||
|
extern "C" uint8_t safe_user_strncpy[];
|
||||||
|
extern "C" uint8_t safe_user_strncpy_end[];
|
||||||
|
extern "C" uint8_t safe_user_strncpy_fault[];
|
||||||
|
|
||||||
|
struct safe_user_page_fault
|
||||||
|
{
|
||||||
|
const uint8_t* ip_start;
|
||||||
|
const uint8_t* ip_end;
|
||||||
|
const uint8_t* ip_fault;
|
||||||
|
};
|
||||||
|
static constexpr safe_user_page_fault s_safe_user_page_faults[] {
|
||||||
|
{
|
||||||
|
.ip_start = safe_user_memcpy,
|
||||||
|
.ip_end = safe_user_memcpy_end,
|
||||||
|
.ip_fault = safe_user_memcpy_fault,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ip_start = safe_user_strncpy,
|
||||||
|
.ip_end = safe_user_strncpy_end,
|
||||||
|
.ip_fault = safe_user_strncpy_fault,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
extern "C" void cpp_isr_handler(uint32_t isr, uint32_t error, InterruptStack* interrupt_stack, const Registers* regs)
|
extern "C" void cpp_isr_handler(uint32_t isr, uint32_t error, InterruptStack* interrupt_stack, const Registers* regs)
|
||||||
{
|
{
|
||||||
if (g_paniced)
|
if (g_paniced)
|
||||||
@@ -201,6 +228,15 @@ namespace Kernel
|
|||||||
if (result.value())
|
if (result.value())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
const uint8_t* ip = reinterpret_cast<const uint8_t*>(interrupt_stack->ip);
|
||||||
|
for (const auto& safe_user : s_safe_user_page_faults)
|
||||||
|
{
|
||||||
|
if (ip < safe_user.ip_start || ip >= safe_user.ip_end)
|
||||||
|
continue;
|
||||||
|
interrupt_stack->ip = reinterpret_cast<vaddr_t>(safe_user.ip_fault);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ISR::DeviceNotAvailable:
|
case ISR::DeviceNotAvailable:
|
||||||
|
|||||||
@@ -136,6 +136,9 @@ namespace Kernel::Input
|
|||||||
m_scancode_to_keycode_extended[0x49] = keycode_function(18);
|
m_scancode_to_keycode_extended[0x49] = keycode_function(18);
|
||||||
m_scancode_to_keycode_extended[0x51] = keycode_function(19);
|
m_scancode_to_keycode_extended[0x51] = keycode_function(19);
|
||||||
m_scancode_to_keycode_normal[0x46] = keycode_function(20);
|
m_scancode_to_keycode_normal[0x46] = keycode_function(20);
|
||||||
|
m_scancode_to_keycode_extended[0x20] = keycode_function(21);
|
||||||
|
m_scancode_to_keycode_extended[0x2E] = keycode_function(22);
|
||||||
|
m_scancode_to_keycode_extended[0x30] = keycode_function(23);
|
||||||
|
|
||||||
// Arrow keys
|
// Arrow keys
|
||||||
m_scancode_to_keycode_extended[0x48] = keycode_normal(5, 0);
|
m_scancode_to_keycode_extended[0x48] = keycode_normal(5, 0);
|
||||||
@@ -246,6 +249,9 @@ namespace Kernel::Input
|
|||||||
m_scancode_to_keycode_extended[0x7D] = keycode_function(18);
|
m_scancode_to_keycode_extended[0x7D] = keycode_function(18);
|
||||||
m_scancode_to_keycode_extended[0x7A] = keycode_function(19);
|
m_scancode_to_keycode_extended[0x7A] = keycode_function(19);
|
||||||
m_scancode_to_keycode_normal[0x7E] = keycode_function(20);
|
m_scancode_to_keycode_normal[0x7E] = keycode_function(20);
|
||||||
|
m_scancode_to_keycode_extended[0x23] = keycode_function(21);
|
||||||
|
m_scancode_to_keycode_extended[0x21] = keycode_function(22);
|
||||||
|
m_scancode_to_keycode_extended[0x32] = keycode_function(23);
|
||||||
|
|
||||||
// Arrow keys
|
// Arrow keys
|
||||||
m_scancode_to_keycode_extended[0x75] = keycode_normal(5, 0);
|
m_scancode_to_keycode_extended[0x75] = keycode_normal(5, 0);
|
||||||
@@ -356,6 +362,9 @@ namespace Kernel::Input
|
|||||||
m_scancode_to_keycode_normal[0x6F] = keycode_function(18);
|
m_scancode_to_keycode_normal[0x6F] = keycode_function(18);
|
||||||
m_scancode_to_keycode_normal[0x6D] = keycode_function(19);
|
m_scancode_to_keycode_normal[0x6D] = keycode_function(19);
|
||||||
m_scancode_to_keycode_normal[0x5F] = keycode_function(20);
|
m_scancode_to_keycode_normal[0x5F] = keycode_function(20);
|
||||||
|
m_scancode_to_keycode_normal[0x9C] = keycode_function(21);
|
||||||
|
m_scancode_to_keycode_normal[0x9D] = keycode_function(22);
|
||||||
|
m_scancode_to_keycode_normal[0x95] = keycode_function(23);
|
||||||
|
|
||||||
// Arrow keys
|
// Arrow keys
|
||||||
m_scancode_to_keycode_normal[0x63] = keycode_normal(5, 0);
|
m_scancode_to_keycode_normal[0x63] = keycode_normal(5, 0);
|
||||||
|
|||||||
@@ -3887,237 +3887,45 @@ namespace Kernel
|
|||||||
return region->allocate_page_containing(address, wants_write);
|
return region->allocate_page_containing(address, wants_write);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: The following 3 functions could be simplified into one generic helper function
|
extern "C" bool safe_user_memcpy(void*, const void*, size_t);
|
||||||
|
extern "C" bool safe_user_strncpy(void*, const void*, size_t);
|
||||||
|
|
||||||
|
static inline bool is_valid_user_address(const void* user_addr, size_t size)
|
||||||
|
{
|
||||||
|
const vaddr_t user_vaddr = reinterpret_cast<vaddr_t>(user_addr);
|
||||||
|
if (BAN::Math::will_addition_overflow<vaddr_t>(user_vaddr, size))
|
||||||
|
return false;
|
||||||
|
if (user_vaddr + size > USERSPACE_END)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> Process::read_from_user(const void* user_addr, void* out, size_t size)
|
BAN::ErrorOr<void> Process::read_from_user(const void* user_addr, void* out, size_t size)
|
||||||
{
|
{
|
||||||
const vaddr_t user_vaddr = reinterpret_cast<vaddr_t>(user_addr);
|
if (!is_valid_user_address(user_addr, size))
|
||||||
|
return BAN::Error::from_errno(EFAULT);
|
||||||
auto* out_u8 = static_cast<uint8_t*>(out);
|
if (!safe_user_memcpy(out, user_addr, size))
|
||||||
size_t ncopied = 0;
|
|
||||||
|
|
||||||
{
|
|
||||||
RWLockRDGuard _(m_memory_region_lock);
|
|
||||||
|
|
||||||
const size_t first_index = find_mapped_region(user_vaddr);
|
|
||||||
for (size_t i = first_index; ncopied < size && i < m_mapped_regions.size(); i++)
|
|
||||||
{
|
|
||||||
auto& region = m_mapped_regions[i];
|
|
||||||
if (!region->contains(user_vaddr + ncopied))
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
return BAN::Error::from_errno(EFAULT);
|
||||||
|
|
||||||
const size_t ncopy = BAN::Math::min<size_t>(
|
|
||||||
(region->vaddr() + region->size()) - (user_vaddr + ncopied),
|
|
||||||
size - ncopied
|
|
||||||
);
|
|
||||||
|
|
||||||
const size_t page_count = range_page_count(user_vaddr + ncopied, ncopy);
|
|
||||||
const vaddr_t page_base = (user_vaddr + ncopied) & PAGE_ADDR_MASK;
|
|
||||||
for (size_t p = 0; p < page_count; p++)
|
|
||||||
{
|
|
||||||
const auto flags = PageTable::UserSupervisor | PageTable::Present;
|
|
||||||
if ((m_page_table->get_page_flags(page_base + p * PAGE_SIZE) & flags) != flags)
|
|
||||||
goto read_from_user_with_allocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(out_u8 + ncopied, reinterpret_cast<void*>(user_vaddr + ncopied), ncopy);
|
|
||||||
ncopied += ncopy;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ncopied >= size)
|
|
||||||
return {};
|
return {};
|
||||||
if (ncopied > 0)
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
read_from_user_with_allocation:
|
|
||||||
RWLockWRGuard _(m_memory_region_lock);
|
|
||||||
|
|
||||||
const size_t first_index = find_mapped_region(user_vaddr + ncopied);
|
|
||||||
for (size_t i = first_index; ncopied < size && i < m_mapped_regions.size(); i++)
|
|
||||||
{
|
|
||||||
auto& region = m_mapped_regions[i];
|
|
||||||
if (!region->contains(user_vaddr + ncopied))
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
|
|
||||||
const size_t ncopy = BAN::Math::min<size_t>(
|
|
||||||
(region->vaddr() + region->size()) - (user_vaddr + ncopied),
|
|
||||||
size - ncopied
|
|
||||||
);
|
|
||||||
|
|
||||||
const size_t page_count = range_page_count(user_vaddr + ncopied, ncopy);
|
|
||||||
const vaddr_t page_base = (user_vaddr + ncopied) & PAGE_ADDR_MASK;
|
|
||||||
for (size_t p = 0; p < page_count; p++)
|
|
||||||
{
|
|
||||||
const auto flags = PageTable::UserSupervisor | PageTable::Present;
|
|
||||||
if ((m_page_table->get_page_flags(page_base + p * PAGE_SIZE) & flags) == flags)
|
|
||||||
continue;
|
|
||||||
if (!TRY(region->allocate_page_containing(page_base + p * PAGE_SIZE, false)))
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(out_u8 + ncopied, reinterpret_cast<void*>(user_vaddr + ncopied), ncopy);
|
|
||||||
ncopied += ncopy;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ncopied >= size)
|
|
||||||
return {};
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> Process::read_string_from_user(const char* user_addr, char* out, size_t max_size)
|
BAN::ErrorOr<void> Process::read_string_from_user(const char* user_addr, char* out, size_t max_size)
|
||||||
{
|
{
|
||||||
const vaddr_t user_vaddr = reinterpret_cast<vaddr_t>(user_addr);
|
max_size = BAN::Math::min<size_t>(max_size, USERSPACE_END - reinterpret_cast<vaddr_t>(user_addr));
|
||||||
|
if (!is_valid_user_address(user_addr, max_size))
|
||||||
size_t ncopied = 0;
|
return BAN::Error::from_errno(EFAULT);
|
||||||
|
if (!safe_user_strncpy(out, user_addr, max_size))
|
||||||
{
|
|
||||||
RWLockRDGuard _(m_memory_region_lock);
|
|
||||||
|
|
||||||
const size_t first_index = find_mapped_region(user_vaddr);
|
|
||||||
for (size_t i = first_index; ncopied < max_size && i < m_mapped_regions.size(); i++)
|
|
||||||
{
|
|
||||||
auto& region = m_mapped_regions[i];
|
|
||||||
if (!region->contains(user_vaddr + ncopied))
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
return BAN::Error::from_errno(EFAULT);
|
||||||
|
|
||||||
vaddr_t last_page = 0;
|
|
||||||
|
|
||||||
for (; ncopied < max_size; ncopied++)
|
|
||||||
{
|
|
||||||
const vaddr_t curr_page = (user_vaddr + ncopied) & PAGE_ADDR_MASK;
|
|
||||||
if (curr_page != last_page)
|
|
||||||
{
|
|
||||||
const auto flags = PageTable::UserSupervisor | PageTable::Present;
|
|
||||||
if ((m_page_table->get_page_flags(curr_page) & flags) != flags)
|
|
||||||
goto read_string_from_user_with_allocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
out[ncopied] = user_addr[ncopied];
|
|
||||||
if (out[ncopied] == '\0')
|
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
last_page = curr_page;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ncopied >= max_size)
|
|
||||||
return BAN::Error::from_errno(ENAMETOOLONG);
|
|
||||||
if (ncopied > 0)
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
read_string_from_user_with_allocation:
|
|
||||||
RWLockWRGuard _(m_memory_region_lock);
|
|
||||||
|
|
||||||
const size_t first_index = find_mapped_region(user_vaddr + ncopied);
|
|
||||||
for (size_t i = first_index; ncopied < max_size && i < m_mapped_regions.size(); i++)
|
|
||||||
{
|
|
||||||
auto& region = m_mapped_regions[i];
|
|
||||||
if (!region->contains(user_vaddr + ncopied))
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
|
|
||||||
vaddr_t last_page = 0;
|
|
||||||
|
|
||||||
for (; ncopied < max_size; ncopied++)
|
|
||||||
{
|
|
||||||
const vaddr_t curr_page = (user_vaddr + ncopied) & PAGE_ADDR_MASK;
|
|
||||||
if (curr_page != last_page)
|
|
||||||
{
|
|
||||||
const auto flags = PageTable::UserSupervisor | PageTable::Present;
|
|
||||||
if ((m_page_table->get_page_flags(curr_page) & flags) == flags)
|
|
||||||
;
|
|
||||||
else if (!TRY(region->allocate_page_containing(curr_page, false)))
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
out[ncopied] = user_addr[ncopied];
|
|
||||||
if (out[ncopied] == '\0')
|
|
||||||
return {};
|
|
||||||
|
|
||||||
last_page = curr_page;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ncopied >= max_size)
|
|
||||||
return BAN::Error::from_errno(ENAMETOOLONG);
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> Process::write_to_user(void* user_addr, const void* in, size_t size)
|
BAN::ErrorOr<void> Process::write_to_user(void* user_addr, const void* in, size_t size)
|
||||||
{
|
{
|
||||||
const vaddr_t user_vaddr = reinterpret_cast<vaddr_t>(user_addr);
|
if (!is_valid_user_address(user_addr, size))
|
||||||
|
return BAN::Error::from_errno(EFAULT);
|
||||||
const auto* in_u8 = static_cast<const uint8_t*>(in);
|
if (!safe_user_memcpy(user_addr, in, size))
|
||||||
size_t ncopied = 0;
|
|
||||||
|
|
||||||
{
|
|
||||||
RWLockRDGuard _(m_memory_region_lock);
|
|
||||||
|
|
||||||
const size_t first_index = find_mapped_region(user_vaddr);
|
|
||||||
for (size_t i = first_index; ncopied < size && i < m_mapped_regions.size(); i++)
|
|
||||||
{
|
|
||||||
auto& region = m_mapped_regions[i];
|
|
||||||
if (!region->contains(user_vaddr + ncopied))
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
return BAN::Error::from_errno(EFAULT);
|
||||||
|
|
||||||
const size_t ncopy = BAN::Math::min<size_t>(
|
|
||||||
(region->vaddr() + region->size()) - (user_vaddr + ncopied),
|
|
||||||
size - ncopied
|
|
||||||
);
|
|
||||||
|
|
||||||
const size_t page_count = range_page_count(user_vaddr + ncopied, ncopy);
|
|
||||||
const vaddr_t page_base = (user_vaddr + ncopied) & PAGE_ADDR_MASK;
|
|
||||||
for (size_t i = 0; i < page_count; i++)
|
|
||||||
{
|
|
||||||
const auto flags = PageTable::UserSupervisor | PageTable::ReadWrite | PageTable::Present;
|
|
||||||
if ((m_page_table->get_page_flags(page_base + i * PAGE_SIZE) & flags) != flags)
|
|
||||||
goto write_to_user_with_allocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(reinterpret_cast<void*>(user_vaddr + ncopied), in_u8 + ncopied, ncopy);
|
|
||||||
ncopied += ncopy;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ncopied >= size)
|
|
||||||
return {};
|
return {};
|
||||||
if (ncopied > 0)
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
write_to_user_with_allocation:
|
|
||||||
RWLockWRGuard _(m_memory_region_lock);
|
|
||||||
|
|
||||||
const size_t first_index = find_mapped_region(user_vaddr + ncopied);
|
|
||||||
for (size_t i = first_index; ncopied < size && i < m_mapped_regions.size(); i++)
|
|
||||||
{
|
|
||||||
auto& region = m_mapped_regions[i];
|
|
||||||
if (!region->contains(user_vaddr + ncopied))
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
|
|
||||||
const size_t ncopy = BAN::Math::min<size_t>(
|
|
||||||
(region->vaddr() + region->size()) - (user_vaddr + ncopied),
|
|
||||||
size - ncopied
|
|
||||||
);
|
|
||||||
|
|
||||||
const size_t page_count = range_page_count(user_vaddr + ncopied, ncopy);
|
|
||||||
const vaddr_t page_base = (user_vaddr + ncopied) & PAGE_ADDR_MASK;
|
|
||||||
for (size_t p = 0; p < page_count; p++)
|
|
||||||
{
|
|
||||||
const auto flags = PageTable::UserSupervisor | PageTable::ReadWrite | PageTable::Present;
|
|
||||||
if ((m_page_table->get_page_flags(page_base + p * PAGE_SIZE) & flags) == flags)
|
|
||||||
continue;
|
|
||||||
if (!TRY(region->allocate_page_containing(page_base + p * PAGE_SIZE, true)))
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(reinterpret_cast<void*>(user_vaddr + ncopied), in_u8 + ncopied, ncopy);
|
|
||||||
ncopied += ncopy;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ncopied >= size)
|
|
||||||
return {};
|
|
||||||
return BAN::Error::from_errno(EFAULT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<MemoryRegion*> Process::validate_and_pin_pointer_access(const void* ptr, size_t size, bool needs_write)
|
BAN::ErrorOr<MemoryRegion*> Process::validate_and_pin_pointer_access(const void* ptr, size_t size, bool needs_write)
|
||||||
|
|||||||
@@ -342,6 +342,9 @@ namespace Kernel
|
|||||||
s_scancode_to_keycode[0x4B] = keycode_function(18);
|
s_scancode_to_keycode[0x4B] = keycode_function(18);
|
||||||
s_scancode_to_keycode[0x4E] = keycode_function(19);
|
s_scancode_to_keycode[0x4E] = keycode_function(19);
|
||||||
s_scancode_to_keycode[0x47] = keycode_function(20);
|
s_scancode_to_keycode[0x47] = keycode_function(20);
|
||||||
|
s_scancode_to_keycode[0x7F] = keycode_function(21);
|
||||||
|
s_scancode_to_keycode[0x81] = keycode_function(22);
|
||||||
|
s_scancode_to_keycode[0x80] = keycode_function(23);
|
||||||
|
|
||||||
s_scancode_to_keycode[0x53] = keycode_numpad(0, 0);
|
s_scancode_to_keycode[0x53] = keycode_numpad(0, 0);
|
||||||
s_scancode_to_keycode[0x54] = keycode_numpad(0, 1);
|
s_scancode_to_keycode[0x54] = keycode_numpad(0, 1);
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ namespace LibAudio
|
|||||||
|
|
||||||
LibAudio::Packet packet {
|
LibAudio::Packet packet {
|
||||||
.type = LibAudio::Packet::Notify,
|
.type = LibAudio::Packet::Notify,
|
||||||
.parameter = 0,
|
.parameter = {},
|
||||||
};
|
};
|
||||||
|
|
||||||
send(m_server_fd, &packet, sizeof(packet), 0);
|
send(m_server_fd, &packet, sizeof(packet), 0);
|
||||||
|
|||||||
@@ -40,6 +40,14 @@ namespace LibAudio
|
|||||||
SetPin, // parameter: pin number
|
SetPin, // parameter: pin number
|
||||||
// response: nothing
|
// response: nothing
|
||||||
// set the active pin of the current device
|
// set the active pin of the current device
|
||||||
|
|
||||||
|
GetVolume, // parameter: ignored
|
||||||
|
// response: 10 * volume percentage (uint32_t)
|
||||||
|
// get the volume of the current device
|
||||||
|
|
||||||
|
SetVolume, // parameter: 10 * volume percentage (uint32_t)
|
||||||
|
// response: nothing
|
||||||
|
// set the volume of the current device
|
||||||
} type;
|
} type;
|
||||||
|
|
||||||
uint64_t parameter;
|
uint64_t parameter;
|
||||||
|
|||||||
@@ -1,35 +1,3 @@
|
|||||||
.global memchr
|
|
||||||
memchr:
|
|
||||||
xchgl 4(%esp), %edi
|
|
||||||
movl 8(%esp), %eax
|
|
||||||
movl 12(%esp), %ecx
|
|
||||||
movl $1, %edx
|
|
||||||
cmpl $1, %ecx # clear ZF if count is zero
|
|
||||||
repne scasb
|
|
||||||
cmovel %edi, %edx
|
|
||||||
leal -1(%edx), %eax
|
|
||||||
movl 4(%esp), %edi
|
|
||||||
ret
|
|
||||||
|
|
||||||
.global memcmp
|
|
||||||
memcmp:
|
|
||||||
xchgl 4(%esp), %edi
|
|
||||||
xchgl 8(%esp), %esi
|
|
||||||
movl 12(%esp), %ecx
|
|
||||||
testl %ecx, %ecx # set ZF if count is zero
|
|
||||||
repe cmpsb
|
|
||||||
jne .memcmp_not_equal
|
|
||||||
xorl %eax, %eax
|
|
||||||
jmp .memcmp_done
|
|
||||||
.memcmp_not_equal:
|
|
||||||
movzbl -1(%edi), %eax
|
|
||||||
movzbl -1(%esi), %ecx
|
|
||||||
subl %ecx, %eax
|
|
||||||
.memcmp_done:
|
|
||||||
movl 4(%esp), %edi
|
|
||||||
movl 8(%esp), %esi
|
|
||||||
ret
|
|
||||||
|
|
||||||
.global memcpy
|
.global memcpy
|
||||||
memcpy:
|
memcpy:
|
||||||
xchgl 4(%esp), %edi
|
xchgl 4(%esp), %edi
|
||||||
@@ -74,14 +42,3 @@ memset:
|
|||||||
movl 4(%esp), %edi
|
movl 4(%esp), %edi
|
||||||
movl %edx, %eax
|
movl %edx, %eax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.global strlen
|
|
||||||
strlen:
|
|
||||||
xchgl 4(%esp), %edi
|
|
||||||
xorb %al, %al
|
|
||||||
movl $-1, %ecx
|
|
||||||
repne scasb
|
|
||||||
movl 4(%esp), %edi
|
|
||||||
movl $-2, %eax
|
|
||||||
subl %ecx, %eax
|
|
||||||
ret
|
|
||||||
|
|||||||
@@ -1,28 +1,3 @@
|
|||||||
.global memchr
|
|
||||||
memchr:
|
|
||||||
movb %sil, %al
|
|
||||||
movq %rdx, %rcx
|
|
||||||
movq $1, %rdx
|
|
||||||
cmpq $1, %rcx # clear ZF if count is zero
|
|
||||||
repne scasb
|
|
||||||
cmoveq %rdi, %rdx
|
|
||||||
leaq -1(%rdx), %rax
|
|
||||||
ret
|
|
||||||
|
|
||||||
.global memcmp
|
|
||||||
memcmp:
|
|
||||||
movq %rdx, %rcx
|
|
||||||
testq %rcx, %rcx # set ZF if count is zero
|
|
||||||
repe cmpsb
|
|
||||||
jne .memcmp_not_equal
|
|
||||||
xorq %rax, %rax
|
|
||||||
ret
|
|
||||||
.memcmp_not_equal:
|
|
||||||
movzbl -1(%rdi), %eax
|
|
||||||
movzbl -1(%rsi), %ecx
|
|
||||||
subq %rcx, %rax
|
|
||||||
ret
|
|
||||||
|
|
||||||
.global memcpy
|
.global memcpy
|
||||||
memcpy:
|
memcpy:
|
||||||
movq %rdi, %rax
|
movq %rdi, %rax
|
||||||
@@ -52,11 +27,154 @@ memset:
|
|||||||
movq %r8, %rax
|
movq %r8, %rax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__SSE2__)
|
||||||
|
|
||||||
|
.global memchr
|
||||||
|
memchr:
|
||||||
|
testq %rdx, %rdx
|
||||||
|
jz .memchr_no_match
|
||||||
|
|
||||||
|
movd %esi, %xmm0
|
||||||
|
punpcklbw %xmm0, %xmm0
|
||||||
|
punpcklwd %xmm0, %xmm0
|
||||||
|
pshufd $0, %xmm0, %xmm0
|
||||||
|
|
||||||
|
movq %rdi, %rcx
|
||||||
|
andq $15, %rcx
|
||||||
|
jz .memchr_loop
|
||||||
|
|
||||||
|
movq %rdi, %rsi
|
||||||
|
subq %rcx, %rsi
|
||||||
|
movdqa (%rsi), %xmm1
|
||||||
|
pcmpeqb %xmm0, %xmm1
|
||||||
|
pmovmskb %xmm1, %eax
|
||||||
|
shrl %cl, %eax
|
||||||
|
jnz .memchr_match
|
||||||
|
|
||||||
|
leaq 16(%rsi), %rdi
|
||||||
|
|
||||||
|
addq %rcx, %rdx
|
||||||
|
subq $16, %rdx
|
||||||
|
jbe .memchr_no_match
|
||||||
|
|
||||||
|
.memchr_loop:
|
||||||
|
movdqa (%rdi), %xmm1
|
||||||
|
pcmpeqb %xmm0, %xmm1
|
||||||
|
pmovmskb %xmm1, %eax
|
||||||
|
testl %eax, %eax
|
||||||
|
jnz .memchr_match
|
||||||
|
|
||||||
|
addq $16, %rdi
|
||||||
|
subq $16, %rdx
|
||||||
|
ja .memchr_loop
|
||||||
|
|
||||||
|
.memchr_no_match:
|
||||||
|
xorq %rax, %rax
|
||||||
|
ret
|
||||||
|
|
||||||
|
.memchr_match:
|
||||||
|
bsfl %eax, %eax
|
||||||
|
cmpq %rdx, %rax
|
||||||
|
jae .memchr_no_match
|
||||||
|
addq %rdi, %rax
|
||||||
|
ret
|
||||||
|
|
||||||
|
.global memcmp
|
||||||
|
memcmp:
|
||||||
|
testq %rdx, %rdx
|
||||||
|
jz .memcmp_equal
|
||||||
|
|
||||||
|
movq %rdi, %rax
|
||||||
|
movq %rsi, %rcx
|
||||||
|
andq $15, %rax
|
||||||
|
andq $15, %rcx
|
||||||
|
cmpq %rax, %rcx
|
||||||
|
cmovaq %rcx, %rax
|
||||||
|
|
||||||
|
testq %rax, %rax
|
||||||
|
jz .memcmp_loop
|
||||||
|
|
||||||
|
movq $16, %rcx
|
||||||
|
subq %rax, %rcx
|
||||||
|
|
||||||
|
cmpq %rcx, %rdx
|
||||||
|
cmovbq %rdx, %rcx
|
||||||
|
|
||||||
|
subq %rcx, %rdx
|
||||||
|
|
||||||
|
.memcmp_align_loop:
|
||||||
|
movzbl (%rdi), %eax
|
||||||
|
movzbl (%rsi), %r8d
|
||||||
|
subl %r8d, %eax
|
||||||
|
jnz .memcmp_return
|
||||||
|
|
||||||
|
incq %rdi
|
||||||
|
incq %rsi
|
||||||
|
decq %rcx
|
||||||
|
jnz .memcmp_align_loop
|
||||||
|
|
||||||
|
.memcmp_loop:
|
||||||
|
movdqu (%rdi), %xmm0
|
||||||
|
movdqu (%rsi), %xmm1
|
||||||
|
pcmpeqb %xmm0, %xmm1
|
||||||
|
pmovmskb %xmm1, %eax
|
||||||
|
xorl $0xFFFF, %eax
|
||||||
|
jnz .memcmp_differ
|
||||||
|
|
||||||
|
addq $16, %rdi
|
||||||
|
addq $16, %rsi
|
||||||
|
subq $16, %rdx
|
||||||
|
ja .memcmp_loop
|
||||||
|
|
||||||
|
.memcmp_equal:
|
||||||
|
xorl %eax, %eax
|
||||||
|
.memcmp_return:
|
||||||
|
ret
|
||||||
|
|
||||||
|
.memcmp_differ:
|
||||||
|
bsfl %eax, %ecx
|
||||||
|
cmpq %rdx, %rcx
|
||||||
|
jae .memcmp_equal
|
||||||
|
movzbl (%rdi, %rcx), %eax
|
||||||
|
movzbl (%rsi, %rcx), %edx
|
||||||
|
subl %edx, %eax
|
||||||
|
ret
|
||||||
|
|
||||||
.global strlen
|
.global strlen
|
||||||
strlen:
|
strlen:
|
||||||
xorb %al, %al
|
movq %rdi, %rsi
|
||||||
movq $-1, %rcx
|
|
||||||
repne scasb
|
pxor %xmm0, %xmm0
|
||||||
movq $-2, %rax
|
|
||||||
subq %rcx, %rax
|
movq %rsi, %rcx
|
||||||
|
andq $15, %rcx
|
||||||
|
jz .strlen_loop
|
||||||
|
|
||||||
|
movq %rsi, %rdx
|
||||||
|
subq %rcx, %rdx
|
||||||
|
movdqa (%rdx), %xmm1
|
||||||
|
pcmpeqb %xmm0, %xmm1
|
||||||
|
pmovmskb %xmm1, %eax
|
||||||
|
shrl %cl, %eax
|
||||||
|
jnz .strlen_null_found
|
||||||
|
|
||||||
|
leaq 16(%rdx), %rsi
|
||||||
|
|
||||||
|
.strlen_loop:
|
||||||
|
movdqa (%rsi), %xmm1
|
||||||
|
pcmpeqb %xmm0, %xmm1
|
||||||
|
pmovmskb %xmm1, %eax
|
||||||
|
testl %eax, %eax
|
||||||
|
jnz .strlen_null_found
|
||||||
|
|
||||||
|
addq $16, %rsi
|
||||||
|
jmp .strlen_loop
|
||||||
|
|
||||||
|
.strlen_null_found:
|
||||||
|
bsfl %eax, %eax
|
||||||
|
addq %rsi, %rax
|
||||||
|
subq %rdi, %rax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include <ctype.h>
|
||||||
#include <fnmatch.h>
|
#include <fnmatch.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -5,6 +6,8 @@
|
|||||||
|
|
||||||
static int fnmatch_impl(const char* pattern, const char* string, int flags, bool leading)
|
static int fnmatch_impl(const char* pattern, const char* string, int flags, bool leading)
|
||||||
{
|
{
|
||||||
|
const bool ignore_case = !!(flags & FNM_IGNORECASE);
|
||||||
|
|
||||||
while (*pattern)
|
while (*pattern)
|
||||||
{
|
{
|
||||||
if ((flags & FNM_PERIOD) && leading && *string == '.' && *pattern != '.')
|
if ((flags & FNM_PERIOD) && leading && *string == '.' && *pattern != '.')
|
||||||
@@ -34,9 +37,13 @@ static int fnmatch_impl(const char* pattern, const char* string, int flags, bool
|
|||||||
uint8_t ch;
|
uint8_t ch;
|
||||||
uint32_t bitmap[0x100 / 8] {};
|
uint32_t bitmap[0x100 / 8] {};
|
||||||
while ((ch = *pattern++) != ']')
|
while ((ch = *pattern++) != ']')
|
||||||
|
{
|
||||||
|
if (ignore_case)
|
||||||
|
ch = tolower(ch);
|
||||||
bitmap[ch / 32] |= 1 << (ch % 32);
|
bitmap[ch / 32] |= 1 << (ch % 32);
|
||||||
|
}
|
||||||
|
|
||||||
ch = *string++;
|
ch = ignore_case ? tolower(*string++) : *string++;
|
||||||
if (!!(bitmap[ch / 32] & (1 << (ch % 32))) == negate)
|
if (!!(bitmap[ch / 32] & (1 << (ch % 32))) == negate)
|
||||||
return FNM_NOMATCH;
|
return FNM_NOMATCH;
|
||||||
|
|
||||||
@@ -63,7 +70,10 @@ static int fnmatch_impl(const char* pattern, const char* string, int flags, bool
|
|||||||
if (*pattern == '\0')
|
if (*pattern == '\0')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (*pattern != *string)
|
const char lhs = ignore_case ? tolower(*pattern) : *pattern;
|
||||||
|
const char rhs = ignore_case ? tolower(*string) : *string;
|
||||||
|
|
||||||
|
if (lhs != rhs)
|
||||||
return FNM_NOMATCH;
|
return FNM_NOMATCH;
|
||||||
if ((flags & FNM_PATHNAME) && *string == '/')
|
if ((flags & FNM_PATHNAME) && *string == '/')
|
||||||
leading = true;
|
leading = true;
|
||||||
|
|||||||
@@ -1,3 +1,11 @@
|
|||||||
|
#ifndef assert
|
||||||
|
#ifdef NDEBUG
|
||||||
|
#define assert(ignore) ((void)0)
|
||||||
|
#else
|
||||||
|
#define assert(expr) ((expr) ? (void)0 : __assert_fail(#expr, __FILE__, __LINE__, __func__))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef _ASSERT_H
|
#ifndef _ASSERT_H
|
||||||
#define _ASSERT_H 1
|
#define _ASSERT_H 1
|
||||||
|
|
||||||
@@ -5,12 +13,6 @@
|
|||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
|
|
||||||
#ifdef NDEBUG
|
|
||||||
#define assert(ignore) ((void)0)
|
|
||||||
#else
|
|
||||||
#define assert(expr) ((expr) ? (void)0 : __assert_fail(#expr, __FILE__, __LINE__, __func__))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(__cplusplus) && __STDC_VERSION__ >= 201112L && __STDC_VERSION__ < 202311L
|
#if !defined(__cplusplus) && __STDC_VERSION__ >= 201112L && __STDC_VERSION__ < 202311L
|
||||||
#define static_assert _Static_assert
|
#define static_assert _Static_assert
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ __BEGIN_DECLS
|
|||||||
#define FNM_PATHNAME 0x01
|
#define FNM_PATHNAME 0x01
|
||||||
#define FNM_PERIOD 0x02
|
#define FNM_PERIOD 0x02
|
||||||
#define FNM_NOESCAPE 0x04
|
#define FNM_NOESCAPE 0x04
|
||||||
|
#define FNM_CASEFOLD 0x08
|
||||||
|
#define FNM_IGNORECASE FNM_CASEFOLD
|
||||||
|
|
||||||
int fnmatch(const char* pattern, const char* string, int flags);
|
int fnmatch(const char* pattern, const char* string, int flags);
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,13 @@ struct ifreq
|
|||||||
#define SIOCGIFFLAGS 9
|
#define SIOCGIFFLAGS 9
|
||||||
#define SIOCGIFMTU 10
|
#define SIOCGIFMTU 10
|
||||||
|
|
||||||
|
#define IFF_UP 0x01
|
||||||
|
#define IFF_BROADCAST 0x02
|
||||||
|
#define IFF_LOOPBACK 0x04
|
||||||
|
#define IFF_POINTOPOINT 0x08
|
||||||
|
#define IFF_RUNNING 0x10
|
||||||
|
#define IFF_MULTICAST 0x20
|
||||||
|
|
||||||
void if_freenameindex(struct if_nameindex* ptr);
|
void if_freenameindex(struct if_nameindex* ptr);
|
||||||
char* if_indextoname(unsigned ifindex, char* ifname);
|
char* if_indextoname(unsigned ifindex, char* ifname);
|
||||||
struct if_nameindex* if_nameindex(void);
|
struct if_nameindex* if_nameindex(void);
|
||||||
|
|||||||
@@ -18,49 +18,26 @@ __BEGIN_DECLS
|
|||||||
#define IPPROTO_TCP 6
|
#define IPPROTO_TCP 6
|
||||||
#define IPPROTO_UDP 7
|
#define IPPROTO_UDP 7
|
||||||
|
|
||||||
enum
|
#define IP_ADD_MEMBERSHIP 0
|
||||||
{
|
#define IP_ADD_SOURCE_MEMBERSHIP 1
|
||||||
IP_ADD_MEMBERSHIP,
|
#define IP_DROP_MEMBERSHIP 2
|
||||||
#define IP_ADD_MEMBERSHIP IP_ADD_MEMBERSHIP
|
#define IP_DROP_SOURCE_MEMBERSHIP 3
|
||||||
IP_ADD_SOURCE_MEMBERSHIP,
|
#define IP_MULTICAST_IF 4
|
||||||
#define IP_ADD_SOURCE_MEMBERSHIP IP_ADD_SOURCE_MEMBERSHIP
|
#define IP_MULTICAST_LOOP 5
|
||||||
IP_DROP_MEMBERSHIP,
|
#define IP_MULTICAST_TTL 6
|
||||||
#define IP_DROP_MEMBERSHIP IP_DROP_MEMBERSHIP
|
#define IP_TTL 7
|
||||||
IP_DROP_SOURCE_MEMBERSHIP,
|
#define IP_TOS 8
|
||||||
#define IP_DROP_SOURCE_MEMBERSHIP IP_DROP_SOURCE_MEMBERSHIP
|
|
||||||
IP_MULTICAST_IF,
|
|
||||||
#define IP_MULTICAST_IF IP_MULTICAST_IF
|
|
||||||
IP_MULTICAST_LOOP,
|
|
||||||
#define IP_MULTICAST_LOOP IP_MULTICAST_LOOP
|
|
||||||
IP_MULTICAST_TTL,
|
|
||||||
#define IP_MULTICAST_TTL IP_MULTICAST_TTL
|
|
||||||
IP_TTL,
|
|
||||||
#define IP_TTL IP_TTL
|
|
||||||
IP_TOS,
|
|
||||||
#define IP_TOS IP_TOS
|
|
||||||
};
|
|
||||||
|
|
||||||
enum
|
#define IPV6_ADD_MEMBERSHIP 0
|
||||||
{
|
#define IPV6_DROP_MEMBERSHIP 1
|
||||||
IPV6_ADD_MEMBERSHIP,
|
#define IPV6_JOIN_GROUP 2
|
||||||
#define IPV6_ADD_MEMBERSHIP IPV6_ADD_MEMBERSHIP
|
#define IPV6_LEAVE_GROUP 3
|
||||||
IPV6_DROP_MEMBERSHIP,
|
#define IPV6_MULTICAST_HOPS 4
|
||||||
#define IPV6_DROP_MEMBERSHIP IPV6_DROP_MEMBERSHIP
|
#define IPV6_MULTICAST_IF 5
|
||||||
IPV6_JOIN_GROUP,
|
#define IPV6_MULTICAST_LOOP 6
|
||||||
#define IPV6_JOIN_GROUP IPV6_JOIN_GROUP
|
#define IPV6_UNICAST_HOPS 7
|
||||||
IPV6_LEAVE_GROUP,
|
#define IPV6_V6ONLY 8
|
||||||
#define IPV6_LEAVE_GROUP IPV6_LEAVE_GROUP
|
#define IPV6_TCLASS 9
|
||||||
IPV6_MULTICAST_HOPS,
|
|
||||||
#define IPV6_MULTICAST_HOPS IPV6_MULTICAST_HOPS
|
|
||||||
IPV6_MULTICAST_IF,
|
|
||||||
#define IPV6_MULTICAST_IF IPV6_MULTICAST_IF
|
|
||||||
IPV6_MULTICAST_LOOP,
|
|
||||||
#define IPV6_MULTICAST_LOOP IPV6_MULTICAST_LOOP
|
|
||||||
IPV6_UNICAST_HOPS,
|
|
||||||
#define IPV6_UNICAST_HOPS IPV6_UNICAST_HOPS
|
|
||||||
IPV6_V6ONLY,
|
|
||||||
#define IPV6_V6ONLY IPV6_V6ONLY
|
|
||||||
};
|
|
||||||
|
|
||||||
#define IN_CLASSA(a) ((((in_addr_t)(a)) & 0x80000000) == 0)
|
#define IN_CLASSA(a) ((((in_addr_t)(a)) & 0x80000000) == 0)
|
||||||
#define IN_CLASSA_NET 0xFF000000
|
#define IN_CLASSA_NET 0xFF000000
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ int sched_setparam(pid_t pid, const struct sched_param* param);
|
|||||||
int sched_setscheduler(pid_t pid, int, const struct sched_param* param);
|
int sched_setscheduler(pid_t pid, int, const struct sched_param* param);
|
||||||
int sched_yield(void);
|
int sched_yield(void);
|
||||||
|
|
||||||
|
int sched_getcpu(void);
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ char* strndup(const char* s, size_t n);
|
|||||||
size_t strnlen(const char* s, size_t maxlen);
|
size_t strnlen(const char* s, size_t maxlen);
|
||||||
char* strpbrk(const char* s1, const char* s2);
|
char* strpbrk(const char* s1, const char* s2);
|
||||||
char* strrchr(const char* s, int c);
|
char* strrchr(const char* s, int c);
|
||||||
|
char* strsep(char** __restrict stringp, const char* __restrict delim);
|
||||||
char* strsignal(int signum);
|
char* strsignal(int signum);
|
||||||
size_t strspn(const char* s1, const char* s2);
|
size_t strspn(const char* s1, const char* s2);
|
||||||
char* strstr(const char* s1, const char* s2);
|
char* strstr(const char* s1, const char* s2);
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#define I_ATMARK 1
|
#define I_ATMARK 1
|
||||||
#define I_CANPUT 2
|
#define I_CANPUT 2
|
||||||
#define I_CKBAND 3
|
#define I_CKBAND 3
|
||||||
@@ -50,6 +52,13 @@ struct winsize
|
|||||||
#define TIOCGWINSZ 50
|
#define TIOCGWINSZ 50
|
||||||
#define TIOCSWINSZ 51
|
#define TIOCSWINSZ 51
|
||||||
|
|
||||||
|
struct snd_volume_info
|
||||||
|
{
|
||||||
|
int32_t min_mdB;
|
||||||
|
int32_t max_mdB;
|
||||||
|
int32_t step_mdB;
|
||||||
|
int32_t mdB;
|
||||||
|
};
|
||||||
#define SND_GET_CHANNELS 60 /* stores number of channels to uint32_t argument */
|
#define SND_GET_CHANNELS 60 /* stores number of channels to uint32_t argument */
|
||||||
#define SND_GET_SAMPLE_RATE 61 /* stores sample rate to uint32_t argument */
|
#define SND_GET_SAMPLE_RATE 61 /* stores sample rate to uint32_t argument */
|
||||||
#define SND_RESET_BUFFER 62 /* stores the size of internal buffer to uint32_t argument and clears the buffer */
|
#define SND_RESET_BUFFER 62 /* stores the size of internal buffer to uint32_t argument and clears the buffer */
|
||||||
@@ -57,6 +66,8 @@ struct winsize
|
|||||||
#define SND_GET_TOTAL_PINS 64 /* gets the number of pins on the current device as uint32_t */
|
#define SND_GET_TOTAL_PINS 64 /* gets the number of pins on the current device as uint32_t */
|
||||||
#define SND_GET_PIN 65 /* gets the currently active pin as uint32_t */
|
#define SND_GET_PIN 65 /* gets the currently active pin as uint32_t */
|
||||||
#define SND_SET_PIN 66 /* sets the currently active pin to uint32_t */
|
#define SND_SET_PIN 66 /* sets the currently active pin to uint32_t */
|
||||||
|
#define SND_GET_VOLUME_INFO 67 /* gets the current volume as snd_volume_info */
|
||||||
|
#define SND_SET_VOLUME_MDB 68 /* sets the current volume to int32_t dB */
|
||||||
|
|
||||||
#define JOYSTICK_GET_LEDS 80 /* get controller led bitmap to uint8_t argument */
|
#define JOYSTICK_GET_LEDS 80 /* get controller led bitmap to uint8_t argument */
|
||||||
#define JOYSTICK_SET_LEDS 81 /* set controller leds to uint8_t bitmap */
|
#define JOYSTICK_SET_LEDS 81 /* set controller leds to uint8_t bitmap */
|
||||||
|
|||||||
@@ -494,6 +494,10 @@ enum
|
|||||||
#define _SC_XOPEN_UUCP _SC_XOPEN_UUCP
|
#define _SC_XOPEN_UUCP _SC_XOPEN_UUCP
|
||||||
_SC_XOPEN_VERSION,
|
_SC_XOPEN_VERSION,
|
||||||
#define _SC_XOPEN_VERSION _SC_XOPEN_VERSION
|
#define _SC_XOPEN_VERSION _SC_XOPEN_VERSION
|
||||||
|
_SC_PHYS_PAGES,
|
||||||
|
#define _SC_PHYS_PAGES _SC_PHYS_PAGES
|
||||||
|
_SC_AVPHYS_PAGES,
|
||||||
|
#define _SC_AVPHYS_PAGES _SC_AVPHYS_PAGES
|
||||||
};
|
};
|
||||||
|
|
||||||
#define F_OK 0x01
|
#define F_OK 0x01
|
||||||
|
|||||||
@@ -256,7 +256,7 @@ FUNC_EXPR1(nearbyint, BAN::Math::rint(a))
|
|||||||
FUNC_EXPR2(nextafter, nextafter_impl(a, b))
|
FUNC_EXPR2(nextafter, nextafter_impl(a, b))
|
||||||
FUNC_EXPR2_TYPE(nexttoward, long double, nextafter_impl(a, b))
|
FUNC_EXPR2_TYPE(nexttoward, long double, nextafter_impl(a, b))
|
||||||
FUNC_EXPR2(pow, ({ if (isnan(a)) return a; if (isnan(b)) return b; BAN::Math::pow(a, b); }))
|
FUNC_EXPR2(pow, ({ if (isnan(a)) return a; if (isnan(b)) return b; BAN::Math::pow(a, b); }))
|
||||||
// remainder
|
BAN_FUNC2(remainder)
|
||||||
// remquo
|
// remquo
|
||||||
BAN_FUNC1(rint)
|
BAN_FUNC1(rint)
|
||||||
FUNC_EXPR1(round, ({ if (!isfinite(a)) return a; BAN::Math::round(a); }))
|
FUNC_EXPR1(round, ({ if (!isfinite(a)) return a; BAN::Math::round(a); }))
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <kernel/API/SharedPage.h>
|
||||||
|
|
||||||
|
extern volatile Kernel::API::SharedPage* g_shared_page;
|
||||||
|
|
||||||
int sched_get_priority_max(int policy)
|
int sched_get_priority_max(int policy)
|
||||||
{
|
{
|
||||||
(void)policy;
|
(void)policy;
|
||||||
@@ -18,3 +22,17 @@ int sched_yield(void)
|
|||||||
{
|
{
|
||||||
return syscall(SYS_YIELD);
|
return syscall(SYS_YIELD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sched_getcpu(void)
|
||||||
|
{
|
||||||
|
if (g_shared_page == nullptr)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
uint8_t cpu;
|
||||||
|
#if defined(__x86_64__)
|
||||||
|
asm volatile("movb %%gs:0, %0" : "=r"(cpu));
|
||||||
|
#elif defined(__i686__)
|
||||||
|
asm volatile("movb %%fs:0, %0" : "=q"(cpu));
|
||||||
|
#endif
|
||||||
|
return cpu;
|
||||||
|
}
|
||||||
|
|||||||
@@ -49,8 +49,12 @@ int sem_timedwait(sem_t* __restrict sem, const struct timespec* __restrict absti
|
|||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
uint32_t expected = BAN::atomic_load(sem->value);
|
uint32_t expected = BAN::atomic_load(sem->value);
|
||||||
if (expected > 0 && BAN::atomic_compare_exchange(sem->value, expected, expected - 1))
|
if (expected > 0)
|
||||||
|
{
|
||||||
|
if (!BAN::atomic_compare_exchange(sem->value, expected, expected - 1))
|
||||||
|
continue;
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const int op = FUTEX_WAIT | (sem->shared ? 0 : FUTEX_PRIVATE) | FUTEX_REALTIME;
|
const int op = FUTEX_WAIT | (sem->shared ? 0 : FUTEX_PRIVATE) | FUTEX_REALTIME;
|
||||||
if (futex(op, &sem->value, expected, abstime) == -1 && (errno == EINTR || errno == ETIMEDOUT))
|
if (futex(op, &sem->value, expected, abstime) == -1 && (errno == EINTR || errno == ETIMEDOUT))
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ static mode_t parse_mode_string(const char* mode_str)
|
|||||||
return 0;
|
return 0;
|
||||||
if (len == 3 && mode_str[1] == mode_str[2])
|
if (len == 3 && mode_str[1] == mode_str[2])
|
||||||
return 0;
|
return 0;
|
||||||
if (strspn(mode_str + 1, "b+") != len - 1)
|
if (strspn(mode_str + 1, "tb+") != len - 1)
|
||||||
return 0;
|
return 0;
|
||||||
bool plus = (mode_str[1] == '+' || mode_str[2] == '+');
|
bool plus = (mode_str[1] == '+' || mode_str[2] == '+');
|
||||||
switch (mode_str[0])
|
switch (mode_str[0])
|
||||||
|
|||||||
@@ -274,6 +274,25 @@ char* strrchr(const char* str, int c)
|
|||||||
return (*str == c) ? (char*)str : nullptr;
|
return (*str == c) ? (char*)str : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* strsep(char** __restrict stringp, const char* __restrict delim)
|
||||||
|
{
|
||||||
|
if (*stringp == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
char* original = *stringp;
|
||||||
|
|
||||||
|
char* match = strpbrk(*stringp, delim);
|
||||||
|
if (match == nullptr)
|
||||||
|
*stringp = nullptr;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*stringp = match + 1;
|
||||||
|
*match = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
|
||||||
char* strstr(const char* haystack, const char* needle)
|
char* strstr(const char* haystack, const char* needle)
|
||||||
{
|
{
|
||||||
const size_t needle_len = strlen(needle);
|
const size_t needle_len = strlen(needle);
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/banan-os.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
@@ -1180,6 +1181,25 @@ long sysconf(int name)
|
|||||||
case _SC_GETGR_R_SIZE_MAX: return 1024;
|
case _SC_GETGR_R_SIZE_MAX: return 1024;
|
||||||
case _SC_GETPW_R_SIZE_MAX: return 1024;
|
case _SC_GETPW_R_SIZE_MAX: return 1024;
|
||||||
case _SC_THREAD_STACK_MIN: return PTHREAD_STACK_MIN;
|
case _SC_THREAD_STACK_MIN: return PTHREAD_STACK_MIN;
|
||||||
|
|
||||||
|
case _SC_PHYS_PAGES:
|
||||||
|
case _SC_AVPHYS_PAGES:
|
||||||
|
{
|
||||||
|
int fd = open("/proc/meminfo", O_RDONLY);
|
||||||
|
if (fd == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
full_meminfo_t meminfo;
|
||||||
|
const size_t nread = read(fd, &meminfo, sizeof(meminfo));
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
if (nread != sizeof(meminfo))
|
||||||
|
return -1;
|
||||||
|
if (name == _SC_PHYS_PAGES)
|
||||||
|
return meminfo.free_pages + meminfo.used_pages;
|
||||||
|
if (name == _SC_AVPHYS_PAGES)
|
||||||
|
return meminfo.free_pages;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
|
|||||||
@@ -98,12 +98,53 @@ bool AudioServer::on_client_packet(int fd, LibAudio::Packet packet)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
reset_kernel_buffer();
|
reset_kernel_buffer();
|
||||||
if (uint32_t pin = packet.parameter; ioctl(device().fd, SND_SET_PIN, &pin) != 0)
|
if (ioctl(device().fd, SND_SET_PIN, &packet.parameter) != 0)
|
||||||
dwarnln("Failed to set pin {}: {}", packet.parameter, strerror(errno));
|
dwarnln("Failed to set pin {}: {}", packet.parameter, strerror(errno));
|
||||||
else
|
else
|
||||||
|
{
|
||||||
device().current_pin = packet.parameter;
|
device().current_pin = packet.parameter;
|
||||||
|
|
||||||
|
// NOTE: different pins have different volume controls
|
||||||
|
if (ioctl(device().fd, SND_GET_VOLUME_INFO, &device().volume) != 0)
|
||||||
|
dwarnln("Failed to query new volume: {}", strerror(errno));
|
||||||
|
}
|
||||||
update();
|
update();
|
||||||
break;
|
break;
|
||||||
|
case LibAudio::Packet::GetVolume:
|
||||||
|
{
|
||||||
|
// NOTE: maybe we should map [0->100%] -> [min, 0] instead?
|
||||||
|
|
||||||
|
const auto& volume = device().volume;
|
||||||
|
if (volume.min_mdB == volume.max_mdB)
|
||||||
|
response = 1000;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const double min_dB = volume.min_mdB / 1000.0;
|
||||||
|
const double max_dB = volume.max_mdB / 1000.0;
|
||||||
|
const double dB = volume.mdB / 1000.0;
|
||||||
|
const double percent = (BAN::Math::pow(10.0, (dB - min_dB) / (max_dB - min_dB)) - 1.0) / 9.0;
|
||||||
|
response = BAN::Math::round(percent * 1000.0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LibAudio::Packet::SetVolume:
|
||||||
|
{
|
||||||
|
// NOTE: maybe we should map [0->100%] -> [min, 0] instead?
|
||||||
|
|
||||||
|
const auto& volume = device().volume;
|
||||||
|
const double min_dB = volume.min_mdB / 1000.0;
|
||||||
|
const double max_dB = volume.max_mdB / 1000.0;
|
||||||
|
const double percent = packet.parameter / 1000.0;
|
||||||
|
const double dB = min_dB + (max_dB - min_dB) * BAN::Math::log10(1.0 + 9.0 * percent);
|
||||||
|
|
||||||
|
const int32_t mdB = BAN::Math::round(dB * 1000.0);
|
||||||
|
if (ioctl(device().fd, SND_SET_VOLUME_MDB, &mdB) != 0)
|
||||||
|
dwarnln("Failed to set volume: {}", strerror(errno));
|
||||||
|
else if (ioctl(device().fd, SND_GET_VOLUME_INFO, &device().volume) != 0)
|
||||||
|
dwarnln("Failed to query new volume: {}", strerror(errno));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
dwarnln("unknown packet type {}", static_cast<uint8_t>(packet.type));
|
dwarnln("unknown packet type {}", static_cast<uint8_t>(packet.type));
|
||||||
return false;
|
return false;
|
||||||
@@ -278,7 +319,7 @@ void AudioServer::send_samples()
|
|||||||
for (size_t i = 0; i < samples_to_send; i++)
|
for (size_t i = 0; i < samples_to_send; i++)
|
||||||
{
|
{
|
||||||
sample_buffer[i] = BAN::Math::clamp<sample_t>(
|
sample_buffer[i] = BAN::Math::clamp<sample_t>(
|
||||||
0.2 * m_samples[m_samples_sent + i] * BAN::numeric_limits<kernel_sample_t>::max(),
|
m_samples[m_samples_sent + i] * BAN::numeric_limits<kernel_sample_t>::max(),
|
||||||
BAN::numeric_limits<kernel_sample_t>::min(),
|
BAN::numeric_limits<kernel_sample_t>::min(),
|
||||||
BAN::numeric_limits<kernel_sample_t>::max()
|
BAN::numeric_limits<kernel_sample_t>::max()
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
#include <LibAudio/Audio.h>
|
#include <LibAudio/Audio.h>
|
||||||
#include <LibAudio/Protocol.h>
|
#include <LibAudio/Protocol.h>
|
||||||
|
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
struct AudioDevice
|
struct AudioDevice
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
@@ -15,6 +17,7 @@ struct AudioDevice
|
|||||||
uint32_t sample_rate;
|
uint32_t sample_rate;
|
||||||
uint32_t total_pins;
|
uint32_t total_pins;
|
||||||
uint32_t current_pin;
|
uint32_t current_pin;
|
||||||
|
snd_volume_info volume;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AudioServer
|
class AudioServer
|
||||||
|
|||||||
@@ -68,6 +68,8 @@ static BAN::Optional<AudioDevice> initialize_audio_device(int fd)
|
|||||||
return {};
|
return {};
|
||||||
if (ioctl(fd, SND_GET_PIN, &result.current_pin) != 0)
|
if (ioctl(fd, SND_GET_PIN, &result.current_pin) != 0)
|
||||||
return {};
|
return {};
|
||||||
|
if (ioctl(fd, SND_GET_VOLUME_INFO, &result.volume) != 0)
|
||||||
|
return {};
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ banan_link_library(TaskBar ban)
|
|||||||
banan_link_library(TaskBar libc)
|
banan_link_library(TaskBar libc)
|
||||||
banan_link_library(TaskBar libfont)
|
banan_link_library(TaskBar libfont)
|
||||||
banan_link_library(TaskBar libgui)
|
banan_link_library(TaskBar libgui)
|
||||||
|
banan_include_headers(TaskBar libaudio)
|
||||||
banan_include_headers(TaskBar libinput)
|
banan_include_headers(TaskBar libinput)
|
||||||
|
|
||||||
install(TARGETS TaskBar OPTIONAL)
|
install(TARGETS TaskBar OPTIONAL)
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
|
#include <LibAudio/Protocol.h>
|
||||||
#include <LibFont/Font.h>
|
#include <LibFont/Font.h>
|
||||||
#include <LibGUI/Window.h>
|
#include <LibGUI/Window.h>
|
||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
|
||||||
static BAN::ErrorOr<long long> read_integer_from_file(const char* file)
|
static BAN::ErrorOr<long long> read_integer_from_file(const char* file)
|
||||||
{
|
{
|
||||||
@@ -60,12 +63,57 @@ static BAN::String get_battery_percentage()
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int open_audio_server_fd()
|
||||||
|
{
|
||||||
|
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (fd == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
sockaddr_un addr;
|
||||||
|
addr.sun_family = AF_UNIX;
|
||||||
|
strcpy(addr.sun_path, LibAudio::s_audio_server_socket.data());
|
||||||
|
if (connect(fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BAN::String get_audio_volume()
|
||||||
|
{
|
||||||
|
static int fd = -1;
|
||||||
|
if (fd == -1 && (fd = open_audio_server_fd()) == -1)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
const LibAudio::Packet request {
|
||||||
|
.type = LibAudio::Packet::GetVolume,
|
||||||
|
.parameter = {},
|
||||||
|
};
|
||||||
|
if (send(fd, &request, sizeof(request), 0) != sizeof(request))
|
||||||
|
{
|
||||||
|
close(fd);
|
||||||
|
fd = -1;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t response;
|
||||||
|
if (recv(fd, &response, sizeof(response), 0) != sizeof(response))
|
||||||
|
{
|
||||||
|
close(fd);
|
||||||
|
fd = -1;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return MUST(BAN::String::formatted("vol {}% | ", response / 10));
|
||||||
|
}
|
||||||
|
|
||||||
static BAN::ErrorOr<BAN::String> get_task_bar_string()
|
static BAN::ErrorOr<BAN::String> get_task_bar_string()
|
||||||
{
|
{
|
||||||
BAN::String result;
|
BAN::String result;
|
||||||
|
|
||||||
TRY(result.append(get_battery_percentage()));
|
TRY(result.append(get_battery_percentage()));
|
||||||
|
|
||||||
|
TRY(result.append(get_audio_volume()));
|
||||||
|
|
||||||
const time_t current_time = time(nullptr);
|
const time_t current_time = time(nullptr);
|
||||||
TRY(result.append(ctime(¤t_time)));
|
TRY(result.append(ctime(¤t_time)));
|
||||||
result.pop_back();
|
result.pop_back();
|
||||||
@@ -79,6 +127,8 @@ int main()
|
|||||||
constexpr uint32_t bg_color = 0xFF202020;
|
constexpr uint32_t bg_color = 0xFF202020;
|
||||||
constexpr uint32_t fg_color = 0xFFFFFFFF;
|
constexpr uint32_t fg_color = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
signal(SIGUSR1, [](int) {});
|
||||||
|
|
||||||
auto font = MUST(LibFont::Font::load("/usr/share/fonts/lat0-16.psfu"_sv));
|
auto font = MUST(LibFont::Font::load("/usr/share/fonts/lat0-16.psfu"_sv));
|
||||||
|
|
||||||
auto attributes = LibGUI::Window::default_attributes;
|
auto attributes = LibGUI::Window::default_attributes;
|
||||||
@@ -99,7 +149,8 @@ int main()
|
|||||||
|
|
||||||
bool is_running = true;
|
bool is_running = true;
|
||||||
|
|
||||||
const auto update_time_string =
|
uint32_t old_text_w = 0;
|
||||||
|
const auto update_string =
|
||||||
[&]()
|
[&]()
|
||||||
{
|
{
|
||||||
auto text_or_error = get_task_bar_string();
|
auto text_or_error = get_task_bar_string();
|
||||||
@@ -112,15 +163,20 @@ int main()
|
|||||||
const uint32_t text_x = window->width() - text_w - padding;
|
const uint32_t text_x = window->width() - text_w - padding;
|
||||||
const uint32_t text_y = padding;
|
const uint32_t text_y = padding;
|
||||||
|
|
||||||
|
const uint32_t inval_w = BAN::Math::max(text_w, old_text_w);
|
||||||
|
const uint32_t inval_x = window->width() - inval_w - padding;
|
||||||
|
|
||||||
auto& texture = window->texture();
|
auto& texture = window->texture();
|
||||||
texture.fill_rect(text_x, text_y, text_w, text_h, bg_color);
|
texture.fill_rect(inval_x, text_y, inval_w, text_h, bg_color);
|
||||||
texture.draw_text(text, font, text_x, text_y, fg_color);
|
texture.draw_text(text, font, text_x, text_y, fg_color);
|
||||||
window->invalidate(text_x, text_y, text_w, text_h);
|
window->invalidate(inval_x, text_y, inval_w, text_h);
|
||||||
|
|
||||||
|
old_text_w = text_w;
|
||||||
};
|
};
|
||||||
|
|
||||||
while (is_running)
|
while (is_running)
|
||||||
{
|
{
|
||||||
update_time_string();
|
update_string();
|
||||||
|
|
||||||
constexpr uint64_t ns_per_s = 1'000'000'000;
|
constexpr uint64_t ns_per_s = 1'000'000'000;
|
||||||
|
|
||||||
|
|||||||
@@ -418,11 +418,23 @@ void WindowServer::on_window_set_cursor(int fd, const LibGUI::WindowPacket::Wind
|
|||||||
invalidate(cursor_area().get_bounding_box(old_cursor));
|
invalidate(cursor_area().get_bounding_box(old_cursor));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void update_volume(const char* new_volume)
|
||||||
|
{
|
||||||
|
char command[128];
|
||||||
|
sprintf(command, "audioctl --volume %s && kill -USR1 TaskBar", new_volume);
|
||||||
|
system(command);
|
||||||
|
}
|
||||||
|
|
||||||
void WindowServer::on_key_event(LibInput::KeyEvent event)
|
void WindowServer::on_key_event(LibInput::KeyEvent event)
|
||||||
{
|
{
|
||||||
if (event.key == LibInput::Key::Super)
|
if (event.key == LibInput::Key::Super)
|
||||||
m_is_mod_key_held = event.pressed();
|
m_is_mod_key_held = event.pressed();
|
||||||
|
|
||||||
|
if (event.pressed() && event.key == LibInput::Key::VolumeDown)
|
||||||
|
update_volume("-5");
|
||||||
|
if (event.pressed() && event.key == LibInput::Key::VolumeUp)
|
||||||
|
update_volume("+5");
|
||||||
|
|
||||||
// Stop WindowServer with mod+shift+E
|
// Stop WindowServer with mod+shift+E
|
||||||
if (m_is_mod_key_held && event.pressed() && event.shift() && event.key == LibInput::Key::E)
|
if (m_is_mod_key_held && event.pressed() && event.shift() && event.key == LibInput::Key::E)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -74,17 +74,20 @@ static uint32_t send_request(int fd, LibAudio::Packet packet, bool wait_response
|
|||||||
|
|
||||||
static void list_devices(int fd)
|
static void list_devices(int fd)
|
||||||
{
|
{
|
||||||
const uint32_t current_device = send_request(fd, { .type = LibAudio::Packet::GetDevice, .parameter = 0 }, true);
|
const uint32_t current_device = send_request(fd, { .type = LibAudio::Packet::GetDevice, .parameter = {} }, true);
|
||||||
const uint32_t current_pin = send_request(fd, { .type = LibAudio::Packet::GetPin, .parameter = 0 }, true);
|
const uint32_t current_pin = send_request(fd, { .type = LibAudio::Packet::GetPin, .parameter = {} }, true);
|
||||||
|
|
||||||
const uint32_t total_devices = send_request(fd, { .type = LibAudio::Packet::QueryDevices, .parameter = 0 }, true);
|
const uint32_t total_devices = send_request(fd, { .type = LibAudio::Packet::QueryDevices, .parameter = {} }, true);
|
||||||
for (uint32_t dev = 0; dev < total_devices; dev++)
|
for (uint32_t dev = 0; dev < total_devices; dev++)
|
||||||
{
|
{
|
||||||
const uint32_t total_pins = send_request(fd, { .type = LibAudio::Packet::QueryPins, .parameter = dev }, true);
|
const uint32_t total_pins = send_request(fd, { .type = LibAudio::Packet::QueryPins, .parameter = dev }, true);
|
||||||
|
|
||||||
printf("Device %" PRIu32 "", dev);
|
printf("Device %" PRIu32 "", dev);
|
||||||
if (dev == current_device)
|
if (dev == current_device)
|
||||||
printf(" (current)");
|
{
|
||||||
|
const uint32_t volume = send_request(fd, { .type = LibAudio::Packet::GetVolume, .parameter = {} }, true);
|
||||||
|
printf(" (current) %" PRIu32 "%%", volume / 10);
|
||||||
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
for (uint32_t pin = 0; pin < total_pins; pin++)
|
for (uint32_t pin = 0; pin < total_pins; pin++)
|
||||||
@@ -103,16 +106,20 @@ int main(int argc, char** argv)
|
|||||||
BAN::Optional<uint32_t> device;
|
BAN::Optional<uint32_t> device;
|
||||||
BAN::Optional<uint32_t> pin;
|
BAN::Optional<uint32_t> pin;
|
||||||
|
|
||||||
|
BAN::Optional<uint32_t> volume;
|
||||||
|
BAN::Optional<bool> volume_rel; // no value: absolute, false positive, true negative
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
static option long_options[] {
|
static option long_options[] {
|
||||||
{ "list", no_argument, nullptr, 'l' },
|
{ "list", no_argument, nullptr, 'l' },
|
||||||
{ "device", required_argument, nullptr, 'd' },
|
{ "device", required_argument, nullptr, 'd' },
|
||||||
{ "pin", required_argument, nullptr, 'p' },
|
{ "pin", required_argument, nullptr, 'p' },
|
||||||
|
{ "volume", required_argument, nullptr, 'v' },
|
||||||
{ "help", no_argument, nullptr, 'h' },
|
{ "help", no_argument, nullptr, 'h' },
|
||||||
};
|
};
|
||||||
|
|
||||||
int ch = getopt_long(argc, argv, "ld:p:h", long_options, nullptr);
|
int ch = getopt_long(argc, argv, "ld:p:v:h", long_options, nullptr);
|
||||||
if (ch == -1)
|
if (ch == -1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -125,6 +132,7 @@ int main(int argc, char** argv)
|
|||||||
fprintf(stderr, " -l, --list list devices and their pins\n");
|
fprintf(stderr, " -l, --list list devices and their pins\n");
|
||||||
fprintf(stderr, " -d, --device N set device index N as the current one\n");
|
fprintf(stderr, " -d, --device N set device index N as the current one\n");
|
||||||
fprintf(stderr, " -p, --pin N set pin N as the current one\n");
|
fprintf(stderr, " -p, --pin N set pin N as the current one\n");
|
||||||
|
fprintf(stderr, " -v, --volume N set volume to N%%. if + or - is given, volume is relative to the current volume\n");
|
||||||
fprintf(stderr, " -h, --help show this message and exit\n");
|
fprintf(stderr, " -h, --help show this message and exit\n");
|
||||||
return 0;
|
return 0;
|
||||||
case 'l':
|
case 'l':
|
||||||
@@ -136,6 +144,11 @@ int main(int argc, char** argv)
|
|||||||
case 'p':
|
case 'p':
|
||||||
pin = parse_u32_or_exit(optarg);
|
pin = parse_u32_or_exit(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 'v':
|
||||||
|
if (optarg[0] == '-' || optarg[0] == '+')
|
||||||
|
volume_rel = (optarg[0] == '-');
|
||||||
|
volume = parse_u32_or_exit(optarg + volume_rel.has_value());
|
||||||
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
fprintf(stderr, "invalid option %c\n", optopt);
|
fprintf(stderr, "invalid option %c\n", optopt);
|
||||||
fprintf(stderr, "see '%s --help' for usage\n", argv[0]);
|
fprintf(stderr, "see '%s --help' for usage\n", argv[0]);
|
||||||
@@ -143,7 +156,7 @@ int main(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!device.has_value() && !pin.has_value())
|
if (!device.has_value() && !pin.has_value() && !volume.has_value())
|
||||||
list = true;
|
list = true;
|
||||||
|
|
||||||
const int fd = get_server_fd();
|
const int fd = get_server_fd();
|
||||||
@@ -156,6 +169,30 @@ int main(int argc, char** argv)
|
|||||||
if (pin.has_value())
|
if (pin.has_value())
|
||||||
send_request(fd, { .type = LibAudio::Packet::SetPin, .parameter = pin.value() }, false);
|
send_request(fd, { .type = LibAudio::Packet::SetPin, .parameter = pin.value() }, false);
|
||||||
|
|
||||||
|
if (volume.has_value())
|
||||||
|
{
|
||||||
|
const uint32_t volume10 = volume.value() * 10;
|
||||||
|
|
||||||
|
uint32_t param;
|
||||||
|
if (!volume_rel.has_value())
|
||||||
|
param = volume10;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const uint32_t current = send_request(fd, { .type = LibAudio::Packet::GetVolume, .parameter = {} }, true);
|
||||||
|
if (!volume_rel.value())
|
||||||
|
param = current + volume10;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (current > volume10)
|
||||||
|
param = current - volume10;
|
||||||
|
else
|
||||||
|
param = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
send_request(fd, { .type = LibAudio::Packet::SetVolume, .parameter = param }, false);
|
||||||
|
}
|
||||||
|
|
||||||
if (list)
|
if (list)
|
||||||
list_devices(fd);
|
list_devices(fd);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <dirent.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -65,12 +67,18 @@ static int signal_name_to_number(const char* name)
|
|||||||
exit_with_error("unknown signal '%s'\n", name);
|
exit_with_error("unknown signal '%s'\n", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_int(const char* string)
|
static bool parse_int_safe(const char* string, int& out)
|
||||||
{
|
{
|
||||||
errno = 0;
|
errno = 0;
|
||||||
char* endptr;
|
char* endptr;
|
||||||
const int result = strtol(string, &endptr, 0);
|
out = strtol(string, &endptr, 0);
|
||||||
if (*endptr != '\0' || errno)
|
return *endptr == '\0' && errno == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_int(const char* string)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
if (!parse_int_safe(string, result))
|
||||||
exit_with_error("invalid integer '%s'\n", string);
|
exit_with_error("invalid integer '%s'\n", string);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -166,9 +174,61 @@ int main(int argc, char** argv)
|
|||||||
if (i >= argc)
|
if (i >= argc)
|
||||||
exit_with_error("missing pids\n");
|
exit_with_error("missing pids\n");
|
||||||
|
|
||||||
|
DIR* proc_dirp = opendir("/proc");
|
||||||
|
if (proc_dirp == NULL)
|
||||||
|
perror("opendir");
|
||||||
|
|
||||||
for (; i < argc; i++)
|
for (; i < argc; i++)
|
||||||
if (kill(parse_int(argv[i]), sig) == -1)
|
{
|
||||||
|
pid_t pid;
|
||||||
|
if (parse_int_safe(argv[i], pid))
|
||||||
|
{
|
||||||
|
if (kill(pid, sig) == -1)
|
||||||
perror("kill");
|
perror("kill");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t arg_len = strlen(argv[i]);
|
||||||
|
if (proc_dirp == NULL || arg_len >= NAME_MAX)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "cannot find process \"%s\"\n", argv[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
dirent* dirent;
|
||||||
|
rewinddir(proc_dirp);
|
||||||
|
while ((dirent = readdir(proc_dirp)))
|
||||||
|
{
|
||||||
|
if (dirent->d_type != DT_DIR || !isdigit(dirent->d_name[0]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
char path_buffer[PATH_MAX + 8];
|
||||||
|
sprintf(path_buffer, "%s/cmdline", dirent->d_name);
|
||||||
|
|
||||||
|
int fd = openat(dirfd(proc_dirp), path_buffer, O_RDONLY);
|
||||||
|
if (fd == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
char buffer[NAME_MAX + 1];
|
||||||
|
const ssize_t nread = read(fd, buffer, arg_len + 1);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
if (nread != static_cast<ssize_t>(arg_len + 1) || strcmp(argv[i], buffer) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (kill(parse_int(dirent->d_name), sig) == -1)
|
||||||
|
perror("kill");
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
fprintf(stderr, "cannot find process \"%s\"\n", argv[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proc_dirp)
|
||||||
|
closedir(proc_dirp);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user