feat: Intel HDA audio driver, audio streaming syscalls, userspace Music app, fixes and improvements, rudimentary Bluetooth support

This commit is contained in:
2026-03-10 17:14:33 +01:00
parent 807c2602fe
commit 576ad34f95
58 changed files with 11275 additions and 137 deletions
+90
View File
@@ -0,0 +1,90 @@
/*
* Audio.hpp
* Audio syscall implementations
* Routes audio to Intel HDA or Bluetooth A2DP based on handle
* Copyright (c) 2026 Daniel Hammer
*/
#pragma once
#include <cstdint>
#include <Drivers/Audio/IntelHda.hpp>
#include <Drivers/USB/Bluetooth/Bluetooth.hpp>
#include <Drivers/USB/Bluetooth/A2dp.hpp>
#include "Syscall.hpp"
namespace Montauk {
// Audio handle convention:
// 0x00 - 0x0F : Intel HDA handles
// 0x100 : Bluetooth A2DP audio output
static constexpr int AUDIO_HANDLE_BT = 0x100;
static int64_t Sys_AudioOpen(uint32_t sampleRate, uint8_t channels, uint8_t bitsPerSample) {
// If HDA is available, use it (primary output)
if (Drivers::Audio::IntelHda::IsInitialized()) {
return (int64_t)Drivers::Audio::IntelHda::Open(sampleRate, channels, bitsPerSample);
}
// Fallback: try Bluetooth audio if available
if (Drivers::USB::Bluetooth::IsInitialized()) {
auto state = Drivers::USB::Bluetooth::A2dp::GetState();
if (state == Drivers::USB::Bluetooth::A2dp::State::Open ||
state == Drivers::USB::Bluetooth::A2dp::State::Streaming ||
state == Drivers::USB::Bluetooth::A2dp::State::Configured) {
Drivers::USB::Bluetooth::A2dp::ConfigureStream(sampleRate, channels, bitsPerSample);
Drivers::USB::Bluetooth::A2dp::StartStream();
return AUDIO_HANDLE_BT;
}
}
return -1;
}
static int64_t Sys_AudioClose(int handle) {
if (handle == AUDIO_HANDLE_BT) {
Drivers::USB::Bluetooth::A2dp::StopStream();
return 0;
}
Drivers::Audio::IntelHda::Close(handle);
return 0;
}
static int64_t Sys_AudioWrite(int handle, const uint8_t* data, uint32_t size) {
if (handle == AUDIO_HANDLE_BT) {
return (int64_t)Drivers::USB::Bluetooth::A2dp::WriteAudio(data, size);
}
return (int64_t)Drivers::Audio::IntelHda::Write(handle, data, size);
}
static int64_t Sys_AudioCtl(int handle, int cmd, int value) {
if (handle == AUDIO_HANDLE_BT) {
switch (cmd) {
case AUDIO_CTL_SET_VOLUME:
Drivers::USB::Bluetooth::A2dp::SetVolume(value);
return 0;
case AUDIO_CTL_GET_VOLUME:
return Drivers::USB::Bluetooth::A2dp::GetVolume();
case AUDIO_CTL_PAUSE:
if (value) Drivers::USB::Bluetooth::A2dp::StopStream();
else Drivers::USB::Bluetooth::A2dp::StartStream();
return 0;
case AUDIO_CTL_GET_OUTPUT:
return 1; // Bluetooth
default:
return -1;
}
}
// Additional control commands for audio routing
if (cmd == AUDIO_CTL_GET_OUTPUT) return 0; // HDA
if (cmd == AUDIO_CTL_BT_STATUS) {
if (!Drivers::USB::Bluetooth::IsInitialized()) return 0;
return (int64_t)Drivers::USB::Bluetooth::A2dp::GetState();
}
return (int64_t)Drivers::Audio::IntelHda::Control(handle, cmd, value);
}
};
+104
View File
@@ -0,0 +1,104 @@
/*
* BluetoothSyscall.hpp
* SYS_BTSCAN, SYS_BTCONNECT, SYS_BTDISCONNECT, SYS_BTLIST, SYS_BTINFO
* Copyright (c) 2026 Daniel Hammer
*/
#pragma once
#include <cstdint>
#include <Drivers/USB/Bluetooth/Bluetooth.hpp>
#include <Drivers/USB/Bluetooth/Hci.hpp>
#include <Libraries/Memory.hpp>
#include "Syscall.hpp"
namespace Montauk {
static int64_t Sys_BtScan(BtScanResult* buf, int maxCount, uint32_t timeoutMs) {
if (!buf || maxCount <= 0) return -1;
if (!Drivers::USB::Bluetooth::IsInitialized()) return -1;
// Use a stack buffer for kernel-side results (max 16)
Drivers::USB::Bluetooth::Hci::InquiryDevice tmpBuf[16];
int kMax = maxCount;
if (kMax > 16) kMax = 16;
int found = Drivers::USB::Bluetooth::Scan(tmpBuf, kMax, timeoutMs);
if (found < 0) return found;
// Convert kernel InquiryDevice to userspace BtScanResult
for (int i = 0; i < found; i++) {
memcpy(buf[i].bdAddr, tmpBuf[i].BdAddr, 6);
buf[i]._pad[0] = 0;
buf[i]._pad[1] = 0;
buf[i].classOfDevice = tmpBuf[i].ClassOfDevice;
buf[i].rssi = tmpBuf[i].Rssi;
buf[i]._pad2[0] = 0;
buf[i]._pad2[1] = 0;
buf[i]._pad2[2] = 0;
memcpy(buf[i].name, tmpBuf[i].Name, 64);
}
return (int64_t)found;
}
static int64_t Sys_BtConnect(const uint8_t* bdAddr) {
if (!bdAddr) return -1;
if (!Drivers::USB::Bluetooth::IsInitialized()) return -1;
return (int64_t)Drivers::USB::Bluetooth::Connect(bdAddr);
}
static int64_t Sys_BtDisconnect(const uint8_t* bdAddr) {
if (!bdAddr) return -1;
if (!Drivers::USB::Bluetooth::IsInitialized()) return -1;
return (int64_t)Drivers::USB::Bluetooth::Disconnect(bdAddr);
}
static int64_t Sys_BtList(BtDevInfo* buf, int maxCount) {
if (!buf || maxCount <= 0) return 0;
if (!Drivers::USB::Bluetooth::IsInitialized()) return 0;
Drivers::USB::Bluetooth::Hci::ConnectionInfo tmpBuf[4];
int kMax = maxCount;
if (kMax > 4) kMax = 4;
int count = Drivers::USB::Bluetooth::ListConnected(tmpBuf, kMax);
for (int i = 0; i < count; i++) {
memcpy(buf[i].bdAddr, tmpBuf[i].BdAddr, 6);
buf[i].connected = tmpBuf[i].Active ? 1 : 0;
buf[i].encrypted = tmpBuf[i].Encrypted ? 1 : 0;
buf[i].handle = tmpBuf[i].Handle;
buf[i].linkType = tmpBuf[i].LinkType;
buf[i]._pad = 0;
}
return (int64_t)count;
}
static int64_t Sys_BtInfo(BtAdapterInfo* buf) {
if (!buf) return -1;
memset(buf, 0, sizeof(BtAdapterInfo));
if (!Drivers::USB::Bluetooth::IsInitialized()) {
buf->initialized = 0;
return -1;
}
buf->initialized = 1;
memcpy(buf->bdAddr, Drivers::USB::Bluetooth::GetBdAddr(), 6);
buf->scanning = Drivers::USB::Bluetooth::Hci::IsInquiryActive() ? 1 : 0;
// Copy adapter name
const char* name = "MontaukOS";
int i = 0;
for (; i < 63 && name[i]; i++) buf->name[i] = name[i];
buf->name[i] = '\0';
return 0;
}
}
+100 -22
View File
@@ -9,13 +9,18 @@
#include <Hal/Apic/ApicInit.hpp>
#include <Drivers/PS2/PS2Controller.hpp>
#include <Drivers/USB/Xhci.hpp>
#include <Drivers/USB/UsbDevice.hpp>
#include <Drivers/USB/Bluetooth/Bluetooth.hpp>
#include <Drivers/Net/E1000.hpp>
#include <Drivers/Net/E1000E.hpp>
#include <Drivers/Graphics/IntelGPU.hpp>
#include <Drivers/Storage/Ahci.hpp>
#include <Drivers/Audio/IntelHda.hpp>
#include <Pci/Pci.hpp>
#include "Syscall.hpp"
#include <Drivers/Storage/BlockDevice.hpp>
#include <Drivers/Storage/Nvme.hpp>
namespace Montauk {
@@ -92,10 +97,12 @@ namespace Montauk {
auto* dev = Drivers::USB::Xhci::GetDevice(slot);
if (!dev || !dev->Active) continue;
const char* devName = "USB Device";
if (dev->InterfaceClass == 3) {
if (dev->InterfaceClass == Drivers::USB::UsbDevice::CLASS_HID) {
if (dev->InterfaceProtocol == 1) devName = "USB HID Keyboard";
else if (dev->InterfaceProtocol == 2) devName = "USB HID Mouse";
else devName = "USB HID Device";
} else if (dev->InterfaceClass == Drivers::USB::UsbDevice::CLASS_WIRELESS) {
devName = "Bluetooth Adapter";
} else if (dev->InterfaceClass == 8) {
devName = "USB Mass Storage";
} else if (dev->InterfaceClass == 9) {
@@ -129,6 +136,22 @@ namespace Montauk {
}
}
// Audio (category 9)
if (Drivers::Audio::IntelHda::IsInitialized()) {
uint32_t codecId = Drivers::Audio::IntelHda::GetCodecVendorId();
char detail[48];
int p = 0;
p = dl_append(detail, p, "HDA Codec ", 48);
p = dl_append_hex(detail, p, codecId >> 16, 4, 48);
p = dl_append(detail, p, ":", 48);
p = dl_append_hex(detail, p, codecId & 0xFFFF, 4, 48);
add(9, "Intel HDA", detail);
}
if (Drivers::USB::Bluetooth::IsInitialized()) {
add(9, "Bluetooth Audio", "A2DP (SBC)");
}
// Storage (category 7)
if (Drivers::Storage::Ahci::IsInitialized()) {
for (int port = 0; port < 32 && count < maxCount; port++) {
@@ -152,6 +175,27 @@ namespace Montauk {
}
}
if (Drivers::Storage::Nvme::IsInitialized()) {
for (int ns = 0; ns < Drivers::Storage::Nvme::GetNamespaceCount() && count < maxCount; ns++) {
auto* nsInfo = Drivers::Storage::Nvme::GetNamespaceInfo(ns);
if (!nsInfo || !nsInfo->Active) continue;
uint64_t sectors = nsInfo->SectorCount;
uint64_t sizeMB = (sectors * nsInfo->SectorSize) / (1024 * 1024);
uint64_t sizeGB = sizeMB / 1024;
char detail[48];
int p = 0;
if (sizeGB > 0) {
p = dl_append_dec(detail, p, (int)sizeGB, 48);
p = dl_append(detail, p, " GiB, NVMe ns ", 48);
} else {
p = dl_append_dec(detail, p, (int)sizeMB, 48);
p = dl_append(detail, p, " MiB, NVMe ns ", 48);
}
p = dl_append_dec(detail, p, ns, 48);
add(7, nsInfo->Model, detail);
}
}
// PCI devices (category 8)
auto& pciDevs = Pci::GetDevices();
for (int i = 0; i < (int)pciDevs.size() && count < maxCount; i++) {
@@ -174,30 +218,64 @@ namespace Montauk {
return count;
}
static int Sys_DiskInfo(DiskInfo* buf, int port) {
static int Sys_DiskInfo(DiskInfo* buf, int blockDevIndex) {
if (buf == nullptr) return -1;
if (!Drivers::Storage::Ahci::IsInitialized()) return -1;
auto* info = Drivers::Storage::Ahci::GetPortInfo(port);
if (!info) return -1;
auto* bdev = Drivers::Storage::GetBlockDevice(blockDevIndex);
if (!bdev) return -1;
buf->port = info->PortIndex;
buf->type = (uint8_t)info->Type;
buf->sataGen = (uint8_t)info->SataGen;
buf->sectorCount = info->SectorCount;
buf->sectorSizeLog = info->SectorSizeLog;
buf->sectorSizePhys = info->SectorSizePhys;
buf->rpm = info->Rpm;
buf->ncqDepth = info->NcqDepth;
buf->supportsLba48 = info->SupportsLba48 ? 1 : 0;
buf->supportsNcq = info->SupportsNcq ? 1 : 0;
buf->supportsTrim = info->SupportsTrim ? 1 : 0;
buf->supportsSmart = info->SupportsSmart ? 1 : 0;
buf->supportsWriteCache = info->SupportsWriteCache ? 1 : 0;
buf->supportsReadAhead = info->SupportsReadAhead ? 1 : 0;
dl_strcpy(buf->model, info->Model, 41);
dl_strcpy(buf->serial, info->Serial, 21);
dl_strcpy(buf->firmware, info->Firmware, 9);
// Zero the struct first so SATA-specific fields default to 0
for (unsigned i = 0; i < sizeof(DiskInfo); i++)
((uint8_t*)buf)[i] = 0;
buf->port = (uint8_t)blockDevIndex;
buf->sectorCount = bdev->SectorCount;
buf->sectorSizeLog = bdev->SectorSize;
buf->sectorSizePhys = bdev->SectorSize;
dl_strcpy(buf->model, bdev->Model, 41);
// Try to fill AHCI-specific fields if this is an AHCI device
if (Drivers::Storage::Ahci::IsInitialized()) {
for (int p = 0; p < 32; p++) {
auto* info = Drivers::Storage::Ahci::GetPortInfo(p);
if (!info) continue;
// Match by sector count and model name
if (info->SectorCount == bdev->SectorCount &&
info->Model[0] == bdev->Model[0]) {
buf->type = (uint8_t)info->Type;
buf->sataGen = (uint8_t)info->SataGen;
buf->sectorSizeLog = info->SectorSizeLog;
buf->sectorSizePhys = info->SectorSizePhys;
buf->rpm = info->Rpm;
buf->ncqDepth = info->NcqDepth;
buf->supportsLba48 = info->SupportsLba48 ? 1 : 0;
buf->supportsNcq = info->SupportsNcq ? 1 : 0;
buf->supportsTrim = info->SupportsTrim ? 1 : 0;
buf->supportsSmart = info->SupportsSmart ? 1 : 0;
buf->supportsWriteCache = info->SupportsWriteCache ? 1 : 0;
buf->supportsReadAhead = info->SupportsReadAhead ? 1 : 0;
dl_strcpy(buf->serial, info->Serial, 21);
dl_strcpy(buf->firmware, info->Firmware, 9);
break;
}
}
}
// For NVMe devices: set type=3 (NVMe), rpm=1 (SSD)
if (buf->type == 0 && Drivers::Storage::Nvme::IsInitialized()) {
for (int ns = 0; ns < Drivers::Storage::Nvme::GetNamespaceCount(); ns++) {
auto* nsInfo = Drivers::Storage::Nvme::GetNamespaceInfo(ns);
if (!nsInfo) continue;
if (nsInfo->SectorCount == bdev->SectorCount) {
buf->type = 3; // NVMe
buf->rpm = 1; // SSD / non-rotating
break;
}
}
}
// If type is still 0, this block device is not recognized
if (buf->type == 0) return -1;
return 0;
}
+20
View File
@@ -30,6 +30,8 @@
#include "Device.hpp" // SYS_DEVLIST, SYS_DISKINFO
#include "Storage.hpp" // SYS_PARTLIST, SYS_DISKREAD, SYS_DISKWRITE
#include "Window.hpp" // SYS_WINCREATE, SYS_WINDESTROY, SYS_WINPRESENT, SYS_WINPOLL, SYS_WINENUM, SYS_WINMAP, SYS_WINSENDEVENT, SYS_WINRESIZE, SYS_WINSETSCALE, SYS_WINGETSCALE
#include "Audio.hpp" // SYS_AUDIOOPEN, SYS_AUDIOCLOSE, SYS_AUDIOWRITE, SYS_AUDIOCTL
#include "BluetoothSyscall.hpp" // SYS_BTSCAN, SYS_BTCONNECT, SYS_BTDISCONNECT, SYS_BTLIST, SYS_BTINFO
// Assembly entry point
extern "C" void SyscallEntry();
@@ -243,6 +245,24 @@ namespace Montauk {
return (int64_t)Sys_FsMount((int)frame->arg1, (int)frame->arg2);
case SYS_FSFORMAT:
return (int64_t)Sys_FsFormat((const FsFormatParams*)frame->arg1);
case SYS_AUDIOOPEN:
return Sys_AudioOpen((uint32_t)frame->arg1, (uint8_t)frame->arg2, (uint8_t)frame->arg3);
case SYS_AUDIOCLOSE:
return Sys_AudioClose((int)frame->arg1);
case SYS_AUDIOWRITE:
return Sys_AudioWrite((int)frame->arg1, (const uint8_t*)frame->arg2, (uint32_t)frame->arg3);
case SYS_AUDIOCTL:
return Sys_AudioCtl((int)frame->arg1, (int)frame->arg2, (int)frame->arg3);
case SYS_BTSCAN:
return Sys_BtScan((BtScanResult*)frame->arg1, (int)frame->arg2, (uint32_t)frame->arg3);
case SYS_BTCONNECT:
return Sys_BtConnect((const uint8_t*)frame->arg1);
case SYS_BTDISCONNECT:
return Sys_BtDisconnect((const uint8_t*)frame->arg1);
case SYS_BTLIST:
return Sys_BtList((BtDevInfo*)frame->arg1, (int)frame->arg2);
case SYS_BTINFO:
return Sys_BtInfo((BtAdapterInfo*)frame->arg1);
default:
return -1;
}
+52 -2
View File
@@ -149,6 +149,28 @@ namespace Montauk {
static constexpr uint64_t SYS_FSMOUNT = 75;
static constexpr uint64_t SYS_FSFORMAT = 76;
/* Audio.hpp */
static constexpr uint64_t SYS_AUDIOOPEN = 80;
static constexpr uint64_t SYS_AUDIOCLOSE = 81;
static constexpr uint64_t SYS_AUDIOWRITE = 82;
static constexpr uint64_t SYS_AUDIOCTL = 83;
// Audio control commands (for SYS_AUDIOCTL)
static constexpr int AUDIO_CTL_SET_VOLUME = 0;
static constexpr int AUDIO_CTL_GET_VOLUME = 1;
static constexpr int AUDIO_CTL_GET_POS = 2;
static constexpr int AUDIO_CTL_PAUSE = 3;
static constexpr int AUDIO_CTL_GET_OUTPUT = 4; // 0=HDA, 1=Bluetooth
static constexpr int AUDIO_CTL_SET_OUTPUT = 5; // Switch audio output
static constexpr int AUDIO_CTL_BT_STATUS = 6; // Get Bluetooth connection status
/* Bluetooth.hpp */
static constexpr uint64_t SYS_BTSCAN = 84;
static constexpr uint64_t SYS_BTCONNECT = 85;
static constexpr uint64_t SYS_BTDISCONNECT = 86;
static constexpr uint64_t SYS_BTLIST = 87;
static constexpr uint64_t SYS_BTINFO = 88;
static constexpr int SOCK_TCP = 1;
static constexpr int SOCK_UDP = 2;
@@ -244,8 +266,8 @@ namespace Montauk {
};
struct DiskInfo {
uint8_t port; // AHCI port index
uint8_t type; // 0=none, 1=SATA, 2=SATAPI
uint8_t port; // block device index
uint8_t type; // 0=none, 1=SATA, 2=SATAPI, 3=NVMe
uint8_t sataGen; // SATA gen (1/2/3)
uint8_t _pad0;
uint64_t sectorCount; // Total user-addressable sectors
@@ -314,6 +336,34 @@ namespace Montauk {
uint64_t heapUsed; // heapNext - UserHeapBase (bytes)
};
// Bluetooth scan result (returned by SYS_BTSCAN)
struct BtScanResult {
uint8_t bdAddr[6];
uint8_t _pad[2];
uint32_t classOfDevice;
int8_t rssi;
uint8_t _pad2[3];
char name[64];
};
// Bluetooth connected device info (returned by SYS_BTLIST)
struct BtDevInfo {
uint8_t bdAddr[6];
uint8_t connected;
uint8_t encrypted;
uint16_t handle;
uint8_t linkType;
uint8_t _pad;
};
// Bluetooth adapter info (returned by SYS_BTINFO)
struct BtAdapterInfo {
uint8_t bdAddr[6];
uint8_t initialized;
uint8_t scanning;
char name[64];
};
// Stack frame pushed by SyscallEntry.asm
struct SyscallFrame {
uint64_t r15, r14, r13, r12, rbp, rbx; // callee-saved