Add the user-space mediated firmware contract, HDA/UAC stream descriptors, 
acquire-release circular DMA buffers, MSI-X acknowledgement hooks, Bluetooth 
HCI ACL capability checks and Hurd LED namespace records.

Signed-off-by: Breno Rodrigues Alves <[email protected]>
---
 modern/include/mach/c17/audio.h     | 113 +++++++++++++++
 modern/include/mach/c17/bluetooth.h |  42 ++++++
 modern/include/mach/c17/firmware.h  |  73 ++++++++++
 modern/include/mach/c17/leds.h      |  51 +++++++
 modern/interfaces/firmware.defs     |  47 +++++++
 modern/src/drivers/audio.c          | 204 ++++++++++++++++++++++++++++
 modern/src/drivers/bluetooth.c      |  57 ++++++++
 modern/src/drivers/firmware.c       | 119 ++++++++++++++++
 modern/src/drivers/leds.c           |  80 +++++++++++
 modern/tests/test_modern_platform.c | 161 ++++++++++++++++++++++
 10 files changed, 947 insertions(+)
 create mode 100644 modern/include/mach/c17/audio.h
 create mode 100644 modern/include/mach/c17/bluetooth.h
 create mode 100644 modern/include/mach/c17/firmware.h
 create mode 100644 modern/include/mach/c17/leds.h
 create mode 100644 modern/interfaces/firmware.defs
 create mode 100644 modern/src/drivers/audio.c
 create mode 100644 modern/src/drivers/bluetooth.c
 create mode 100644 modern/src/drivers/firmware.c
 create mode 100644 modern/src/drivers/leds.c
 create mode 100644 modern/tests/test_modern_platform.c

diff --git a/modern/include/mach/c17/audio.h b/modern/include/mach/c17/audio.h
new file mode 100644
index 00000000..cec62c71
--- /dev/null
+++ b/modern/include/mach/c17/audio.h
@@ -0,0 +1,113 @@
+/* Intel HDA and USB Audio Class contract for GNU Mach.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+
+   This file is part of GNU Mach.
+
+   GNU Mach is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   Only MMIO, DMA ownership and interrupt acknowledgement belong here.
+   Codec policy and USB class parsing remain Hurd server responsibilities.  */
+
+#ifndef _MACH_C17_AUDIO_H
+#define _MACH_C17_AUDIO_H 1
+
+#include <mach/c17/driver.h>
+
+#define MACH_AUDIO_MAX_CHANNELS 32u
+#define MACH_AUDIO_MAX_RATE 192000u
+#define MACH_AUDIO_MIN_RATE 44100u
+#define MACH_AUDIO_RING_FRAMES 1024u
+#define MACH_HDA_MAX_STREAMS 16u
+
+typedef enum mach_audio_format
+{
+  MACH_AUDIO_S16_LE = 16,
+  MACH_AUDIO_S24_LE = 24,
+  MACH_AUDIO_S32_LE = 32
+} mach_audio_format_t;
+
+typedef enum mach_usb_audio_version
+{
+  MACH_UAC1 = 1,
+  MACH_UAC2 = 2
+} mach_usb_audio_version_t;
+
+struct mach_audio_ring
+{
+  uint8_t *data;
+  size_t frame_bytes;
+  uint32_t frame_count;
+  mach_atomic_u32 producer;
+  mach_atomic_u32 consumer;
+};
+
+struct mach_audio_stream
+{
+  struct mach_audio_ring ring;
+  uint32_t stream_id;
+  uint32_t sample_rate;
+  uint16_t channels;
+  mach_audio_format_t format;
+  bool capture;
+  bool running;
+  uint32_t irq;
+};
+
+struct mach_hda_ops
+{
+  mach_error_t (*set_stream) (void *context, uint32_t stream_id,
+                              mach_phys_t buffer, size_t bytes);
+  mach_error_t (*set_codec_verb) (void *context, uint8_t codec,
+                                  uint32_t verb);
+  void (*ack_irq) (void *context, uint32_t irq);
+};
+
+struct mach_hda_controller
+{
+  struct mach_mmio mmio;
+  struct mach_dma dma;
+  const struct mach_hda_ops *ops;
+  void *context;
+  struct mach_audio_stream streams[MACH_HDA_MAX_STREAMS];
+  uint32_t stream_count;
+  uint32_t msix_vectors;
+};
+
+struct mach_uac_stream_descriptor
+{
+  mach_usb_audio_version_t version;
+  uint32_t sample_rate;
+  uint16_t channels;
+  mach_audio_format_t format;
+  uint16_t max_packet;
+  bool capture;
+};
+
+mach_error_t mach_audio_ring_init (struct mach_audio_ring *ring,
+                                   uint8_t *data, uint32_t frame_count,
+                                   size_t frame_bytes);
+size_t mach_audio_ring_available (const struct mach_audio_ring *ring);
+size_t mach_audio_ring_space (const struct mach_audio_ring *ring);
+size_t mach_audio_ring_write (struct mach_audio_ring *ring,
+                              const uint8_t *frames, size_t count);
+size_t mach_audio_ring_read (struct mach_audio_ring *ring, uint8_t *frames,
+                             size_t count);
+
+mach_error_t mach_hda_init (struct mach_hda_controller *controller,
+                            const struct mach_mmio *mmio,
+                            const struct mach_dma *dma,
+                            const struct mach_hda_ops *ops, void *context);
+mach_error_t mach_hda_add_stream (struct mach_hda_controller *controller,
+                                  const struct mach_uac_stream_descriptor 
*desc,
+                                  uint8_t *buffer, uint32_t frames,
+                                  uint32_t *stream_id);
+mach_error_t mach_hda_start (struct mach_hda_controller *controller,
+                             uint32_t stream_id, mach_phys_t dma_address);
+void mach_hda_interrupt (struct mach_hda_controller *controller,
+                         uint32_t irq);
+mach_error_t mach_uac_validate (const struct mach_uac_stream_descriptor *desc);
+
+#endif /* _MACH_C17_AUDIO_H */
diff --git a/modern/include/mach/c17/bluetooth.h 
b/modern/include/mach/c17/bluetooth.h
new file mode 100644
index 00000000..2d96fa80
--- /dev/null
+++ b/modern/include/mach/c17/bluetooth.h
@@ -0,0 +1,42 @@
+/* Bluetooth HCI transport contract for GNU Mach.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+
+   This file is part of GNU Mach.
+
+   GNU Mach is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.  */
+
+#ifndef _MACH_C17_BLUETOOTH_H
+#define _MACH_C17_BLUETOOTH_H 1
+
+#include <mach/c17/ipc.h>
+
+#define MACH_BT_ACL_MAX 4096u
+
+typedef enum mach_bt_transport
+{
+  MACH_BT_USB = 1,
+  MACH_BT_PCIE = 2
+} mach_bt_transport_t;
+
+struct mach_bt_hci
+{
+  mach_bt_transport_t transport;
+  struct mach_ipc_port *port;
+  mach_atomic_u32 tx_sequence;
+  mach_atomic_u32 rx_sequence;
+  bool ready;
+};
+
+mach_error_t mach_bt_init (struct mach_bt_hci *hci,
+                           mach_bt_transport_t transport);
+mach_error_t mach_bt_attach_port (struct mach_bt_hci *hci,
+                                  struct mach_ipc_port *port);
+mach_error_t mach_bt_submit_acl (struct mach_bt_hci *hci,
+                                 const struct mach_ipc_ool *buffer,
+                                 size_t offset, size_t length);
+uint32_t mach_bt_next_sequence (struct mach_bt_hci *hci);
+
+#endif /* _MACH_C17_BLUETOOTH_H */
diff --git a/modern/include/mach/c17/firmware.h 
b/modern/include/mach/c17/firmware.h
new file mode 100644
index 00000000..3bb80331
--- /dev/null
+++ b/modern/include/mach/c17/firmware.h
@@ -0,0 +1,73 @@
+/* User-space firmware loading contract for GNU Mach.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+
+   This file is part of GNU Mach.
+
+   GNU Mach is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   No firmware image is embedded here.  The Hurd server owns and validates
+   the image; the kernel-side object exposes only bounded MMIO writes.  */
+
+#ifndef _MACH_C17_FIRMWARE_H
+#define _MACH_C17_FIRMWARE_H 1
+
+#include <mach/c17/driver.h>
+
+#define MACH_FIRMWARE_MAX_CHUNK 4096u
+#define MACH_FIRMWARE_FLAG_WRITE32 0x1u
+#define MACH_FIRMWARE_FLAG_WRITE8 0x2u
+#define MACH_FIRMWARE_MAX_IMAGE (16u * 1024u * 1024u)
+
+typedef enum mach_firmware_state
+{
+  MACH_FIRMWARE_EMPTY = 0,
+  MACH_FIRMWARE_VALIDATED,
+  MACH_FIRMWARE_UPLOADING,
+  MACH_FIRMWARE_COMMITTED,
+  MACH_FIRMWARE_FAILED
+} mach_firmware_state_t;
+
+struct mach_firmware_image
+{
+  const uint8_t *data;
+  size_t length;
+  uint32_t crc32;
+};
+
+struct mach_firmware_ops
+{
+  /* This callback is the only privileged operation in the protocol.  */
+  mach_error_t (*write) (void *context, mach_phys_t offset,
+                         const uint8_t *data, size_t length);
+  void (*fence) (void *context);
+};
+
+struct mach_firmware_session
+{
+  const struct mach_firmware_ops *ops;
+  void *context;
+  mach_phys_t window;
+  size_t window_length;
+  size_t next_offset;
+  size_t image_length;
+  uint32_t expected_crc32;
+  mach_firmware_state_t state;
+};
+
+uint32_t mach_firmware_crc32 (const uint8_t *data, size_t length);
+mach_error_t mach_firmware_init (struct mach_firmware_session *session,
+                                 const struct mach_firmware_ops *ops,
+                                 void *context, mach_phys_t window,
+                                 size_t window_length);
+mach_error_t mach_firmware_validate (struct mach_firmware_session *session,
+                                     const struct mach_firmware_image *image);
+mach_error_t mach_firmware_upload (struct mach_firmware_session *session,
+                                   size_t offset, const uint8_t *data,
+                                   size_t length);
+mach_error_t mach_firmware_commit (struct mach_firmware_session *session);
+void mach_firmware_abort (struct mach_firmware_session *session);
+
+#endif /* _MACH_C17_FIRMWARE_H */
diff --git a/modern/include/mach/c17/leds.h b/modern/include/mach/c17/leds.h
new file mode 100644
index 00000000..153256af
--- /dev/null
+++ b/modern/include/mach/c17/leds.h
@@ -0,0 +1,51 @@
+/* GPIO, ACPI/EC and Hurd LED namespace contract for GNU Mach.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+
+   This file is part of GNU Mach.
+
+   GNU Mach is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.  */
+
+#ifndef _MACH_C17_LEDS_H
+#define _MACH_C17_LEDS_H 1
+
+#include <mach/c17/base.h>
+
+#define MACH_LED_NAME_MAX 24u
+#define MACH_LED_MAX 32u
+
+typedef enum mach_led_kind
+{
+  MACH_LED_DIAGNOSTIC = 1,
+  MACH_LED_DISK = 2,
+  MACH_LED_POWER = 3,
+  MACH_LED_CAPSLOCK = 4,
+  MACH_LED_WIRELESS = 5
+} mach_led_kind_t;
+
+struct mach_led
+{
+  char name[MACH_LED_NAME_MAX];
+  mach_led_kind_t kind;
+  uint32_t gpio;
+  bool value;
+  bool writable;
+};
+
+struct mach_led_bank
+{
+  struct mach_led leds[MACH_LED_MAX];
+  uint32_t count;
+};
+
+mach_error_t mach_led_bank_init (struct mach_led_bank *bank);
+mach_error_t mach_led_register (struct mach_led_bank *bank, const char *name,
+                                mach_led_kind_t kind, uint32_t gpio,
+                                bool writable, uint32_t *id);
+mach_error_t mach_led_set (struct mach_led_bank *bank, uint32_t id, bool 
value);
+mach_error_t mach_led_get (const struct mach_led_bank *bank, uint32_t id,
+                           bool *value);
+
+#endif /* _MACH_C17_LEDS_H */
diff --git a/modern/interfaces/firmware.defs b/modern/interfaces/firmware.defs
new file mode 100644
index 00000000..b13cd530
--- /dev/null
+++ b/modern/interfaces/firmware.defs
@@ -0,0 +1,47 @@
+/* GNU Mach firmware service contract.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+
+   This file is part of GNU Mach.
+
+   GNU Mach is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   This interface deliberately carries no firmware bytes.  A Hurd server
+   owns the image, validates its digest and asks the minimal kernel-side
+   MMIO primitive to transfer it.  */
+
+subsystem mach_firmware 4200;
+
+#include <mach/std_types.defs>
+
+routine firmware_open (
+  server: mach_port_t;
+  device: mach_port_t;
+  out session: mach_port_t);
+
+routine firmware_query (
+  session: mach_port_t;
+  out max_chunk: uint32_t;
+  out flags: uint32_t);
+
+routine firmware_validate (
+  session: mach_port_t;
+  image_size: uint64_t;
+  image_crc32: uint32_t;
+  out result: kern_return_t);
+
+routine firmware_upload (
+  session: mach_port_t;
+  offset: uint64_t;
+  image: pointer_t;
+  image_count: uint32_t;
+  out result: kern_return_t);
+
+routine firmware_commit (
+  session: mach_port_t;
+  out result: kern_return_t);
+
+routine firmware_close (
+  session: mach_port_t);
diff --git a/modern/src/drivers/audio.c b/modern/src/drivers/audio.c
new file mode 100644
index 00000000..6a6323b5
--- /dev/null
+++ b/modern/src/drivers/audio.c
@@ -0,0 +1,204 @@
+/* Intel HDA and USB Audio Class DMA engine for GNU Mach.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+
+   This file is part of GNU Mach.
+
+   GNU Mach is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   The producer publishes frames with release semantics and the consumer
+   observes them with acquire semantics.  Codec policy, mixer controls and
+   UAC descriptors are intentionally left to the user-space audio server.  */
+
+#include <mach/c17/audio.h>
+
+static uint32_t
+audio_load (const mach_atomic_u32 *value)
+{
+  return atomic_load_explicit (value, memory_order_acquire);
+}
+
+static uint32_t
+audio_distance (uint32_t producer, uint32_t consumer,
+                uint32_t frame_count)
+{
+  return producer >= consumer ? producer - consumer
+                              : frame_count - consumer + producer;
+}
+
+mach_error_t
+mach_audio_ring_init (struct mach_audio_ring *ring, uint8_t *data,
+                      uint32_t frame_count, size_t frame_bytes)
+{
+  if (ring == NULL || data == NULL || frame_count < 2u || frame_bytes == 0
+      || frame_count > 65536u)
+    return MACH_EINVAL;
+  ring->data = data;
+  ring->frame_bytes = frame_bytes;
+  ring->frame_count = frame_count;
+  atomic_init (&ring->producer, 0u);
+  atomic_init (&ring->consumer, 0u);
+  return MACH_OK;
+}
+
+size_t
+mach_audio_ring_available (const struct mach_audio_ring *ring)
+{
+  uint32_t producer;
+  uint32_t consumer;
+
+  if (ring == NULL || ring->frame_count == 0)
+    return 0;
+  producer = audio_load (&ring->producer);
+  consumer = audio_load (&ring->consumer);
+  return audio_distance (producer, consumer, ring->frame_count);
+}
+
+size_t
+mach_audio_ring_space (const struct mach_audio_ring *ring)
+{
+  if (ring == NULL || ring->frame_count < 2u)
+    return 0;
+  return (size_t) ring->frame_count - 1u
+         - mach_audio_ring_available (ring);
+}
+
+size_t
+mach_audio_ring_write (struct mach_audio_ring *ring, const uint8_t *frames,
+                       size_t count)
+{
+  uint32_t producer;
+  size_t written = 0;
+
+  if (ring == NULL || frames == NULL || ring->frame_count < 2u)
+    return 0;
+  count = count < mach_audio_ring_space (ring) ? count
+                                               : mach_audio_ring_space (ring);
+  producer = atomic_load_explicit (&ring->producer, memory_order_relaxed);
+  while (written < count)
+    {
+      mach_memcpy (ring->data + producer * ring->frame_bytes,
+                   frames + written * ring->frame_bytes, ring->frame_bytes);
+      producer = (producer + 1u) % ring->frame_count;
+      written++;
+    }
+  atomic_store_explicit (&ring->producer, producer, memory_order_release);
+  return written;
+}
+
+size_t
+mach_audio_ring_read (struct mach_audio_ring *ring, uint8_t *frames,
+                      size_t count)
+{
+  uint32_t consumer;
+  size_t read = 0;
+
+  if (ring == NULL || frames == NULL || ring->frame_count < 2u)
+    return 0;
+  count = count < mach_audio_ring_available (ring) ? count
+                                                   : mach_audio_ring_available 
(ring);
+  consumer = atomic_load_explicit (&ring->consumer, memory_order_relaxed);
+  while (read < count)
+    {
+      mach_memcpy (frames + read * ring->frame_bytes,
+                   ring->data + consumer * ring->frame_bytes,
+                   ring->frame_bytes);
+      consumer = (consumer + 1u) % ring->frame_count;
+      read++;
+    }
+  atomic_store_explicit (&ring->consumer, consumer, memory_order_release);
+  return read;
+}
+
+mach_error_t
+mach_uac_validate (const struct mach_uac_stream_descriptor *desc)
+{
+  if (desc == NULL || (desc->version != MACH_UAC1 && desc->version != 
MACH_UAC2)
+      || desc->sample_rate < MACH_AUDIO_MIN_RATE
+      || desc->sample_rate > MACH_AUDIO_MAX_RATE || desc->channels == 0
+      || desc->channels > MACH_AUDIO_MAX_CHANNELS || desc->max_packet == 0
+      || (desc->format != MACH_AUDIO_S16_LE
+          && desc->format != MACH_AUDIO_S24_LE
+          && desc->format != MACH_AUDIO_S32_LE))
+    return MACH_EINVAL;
+  return MACH_OK;
+}
+
+mach_error_t
+mach_hda_init (struct mach_hda_controller *controller,
+               const struct mach_mmio *mmio, const struct mach_dma *dma,
+               const struct mach_hda_ops *ops, void *context)
+{
+  if (controller == NULL || mmio == NULL || dma == NULL || ops == NULL
+      || ops->set_stream == NULL || ops->set_codec_verb == NULL)
+    return MACH_EINVAL;
+  mach_memset (controller, 0, sizeof (*controller));
+  controller->mmio = *mmio;
+  controller->dma = *dma;
+  controller->ops = ops;
+  controller->context = context;
+  return MACH_OK;
+}
+
+mach_error_t
+mach_hda_add_stream (struct mach_hda_controller *controller,
+                     const struct mach_uac_stream_descriptor *desc,
+                     uint8_t *buffer, uint32_t frames, uint32_t *stream_id)
+{
+  struct mach_audio_stream *stream;
+  size_t bytes_per_sample;
+  mach_error_t error;
+
+  error = mach_uac_validate (desc);
+  if (error != MACH_OK || controller == NULL || stream_id == NULL
+      || controller->stream_count >= MACH_HDA_MAX_STREAMS)
+    return error != MACH_OK ? error : MACH_ENOMEM;
+  bytes_per_sample = ((size_t) desc->format + 7u) / 8u;
+  stream = &controller->streams[controller->stream_count];
+  error = mach_audio_ring_init (&stream->ring, buffer, frames,
+                                bytes_per_sample * desc->channels);
+  if (error != MACH_OK)
+    return error;
+  stream->stream_id = controller->stream_count + 1u;
+  stream->sample_rate = desc->sample_rate;
+  stream->channels = desc->channels;
+  stream->format = desc->format;
+  stream->capture = desc->capture;
+  *stream_id = stream->stream_id;
+  controller->stream_count++;
+  return MACH_OK;
+}
+
+mach_error_t
+mach_hda_start (struct mach_hda_controller *controller, uint32_t stream_id,
+                mach_phys_t dma_address)
+{
+  struct mach_audio_stream *stream;
+  mach_error_t error;
+
+  if (controller == NULL || stream_id == 0 || stream_id > 
controller->stream_count)
+    return MACH_EINVAL;
+  stream = &controller->streams[stream_id - 1u];
+  error = controller->ops->set_stream (controller->context, stream_id,
+                                       dma_address,
+                                       stream->ring.frame_count
+                                       * stream->ring.frame_bytes);
+  if (error == MACH_OK)
+    {
+      stream->running = true;
+      stream->irq = stream_id;
+      controller->msix_vectors++;
+    }
+  return error;
+}
+
+void
+mach_hda_interrupt (struct mach_hda_controller *controller, uint32_t irq)
+{
+  if (controller == NULL || controller->ops == NULL
+      || controller->ops->ack_irq == NULL)
+    return;
+  controller->ops->ack_irq (controller->context, irq);
+}
diff --git a/modern/src/drivers/bluetooth.c b/modern/src/drivers/bluetooth.c
new file mode 100644
index 00000000..c491273d
--- /dev/null
+++ b/modern/src/drivers/bluetooth.c
@@ -0,0 +1,57 @@
+/* Bluetooth HCI transport capability for GNU Mach.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+
+   This file is part of GNU Mach.
+
+   GNU Mach is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   Pairing, encryption, firmware policy and packet decoding stay in the
+   user-space Bluetooth server.  The kernel only checks buffer ownership.  */
+
+#include <mach/c17/bluetooth.h>
+
+mach_error_t
+mach_bt_init (struct mach_bt_hci *hci, mach_bt_transport_t transport)
+{
+  if (hci == NULL || (transport != MACH_BT_USB && transport != MACH_BT_PCIE))
+    return MACH_EINVAL;
+  mach_memset (hci, 0, sizeof (*hci));
+  hci->transport = transport;
+  atomic_init (&hci->tx_sequence, 0u);
+  atomic_init (&hci->rx_sequence, 0u);
+  return MACH_OK;
+}
+
+mach_error_t
+mach_bt_attach_port (struct mach_bt_hci *hci, struct mach_ipc_port *port)
+{
+  if (hci == NULL || port == NULL)
+    return MACH_EINVAL;
+  hci->port = port;
+  hci->ready = true;
+  return MACH_OK;
+}
+
+mach_error_t
+mach_bt_submit_acl (struct mach_bt_hci *hci, const struct mach_ipc_ool *buffer,
+                    size_t offset, size_t length)
+{
+  if (hci == NULL || !hci->ready || buffer == NULL || length == 0
+      || length > MACH_BT_ACL_MAX || offset > buffer->length
+      || length > buffer->length - offset)
+    return MACH_EINVAL;
+  atomic_fetch_add_explicit (&hci->tx_sequence, 1u, memory_order_release);
+  return MACH_OK;
+}
+
+uint32_t
+mach_bt_next_sequence (struct mach_bt_hci *hci)
+{
+  if (hci == NULL)
+    return 0;
+  return atomic_fetch_add_explicit (&hci->rx_sequence, 1u,
+                                    memory_order_acq_rel) + 1u;
+}
diff --git a/modern/src/drivers/firmware.c b/modern/src/drivers/firmware.c
new file mode 100644
index 00000000..1156eded
--- /dev/null
+++ b/modern/src/drivers/firmware.c
@@ -0,0 +1,119 @@
+/* User-space mediated firmware transfer for GNU Mach.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+
+   This file is part of GNU Mach.
+
+   GNU Mach is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   The implementation contains no image and no vendor-specific protocol.
+   It validates a server-owned image, bounds every transfer and delegates
+   the actual register write to the minimal device capability.  */
+
+#include <mach/c17/firmware.h>
+
+static uint32_t
+firmware_crc32_byte (uint32_t crc, uint8_t byte)
+{
+  crc ^= byte;
+  for (unsigned int bit = 0; bit < 8u; bit++)
+    crc = (crc >> 1) ^ (0xedb88320u & (uint32_t) -(int32_t) (crc & 1u));
+  return crc;
+}
+
+uint32_t
+mach_firmware_crc32 (const uint8_t *data, size_t length)
+{
+  uint32_t crc = 0xffffffffu;
+
+  if (data == NULL && length != 0)
+    return 0;
+  for (size_t index = 0; index < length; index++)
+    crc = firmware_crc32_byte (crc, data[index]);
+  return ~crc;
+}
+
+mach_error_t
+mach_firmware_init (struct mach_firmware_session *session,
+                    const struct mach_firmware_ops *ops, void *context,
+                    mach_phys_t window, size_t window_length)
+{
+  if (session == NULL || ops == NULL || ops->write == NULL
+      || window_length == 0)
+    return MACH_EINVAL;
+  mach_memset (session, 0, sizeof (*session));
+  session->ops = ops;
+  session->context = context;
+  session->window = window;
+  session->window_length = window_length;
+  session->state = MACH_FIRMWARE_EMPTY;
+  return MACH_OK;
+}
+
+mach_error_t
+mach_firmware_validate (struct mach_firmware_session *session,
+                        const struct mach_firmware_image *image)
+{
+  if (session == NULL || image == NULL || image->data == NULL
+      || image->length == 0 || image->length > MACH_FIRMWARE_MAX_IMAGE
+      || image->length > session->window_length)
+    return MACH_EINVAL;
+  if (mach_firmware_crc32 (image->data, image->length) != image->crc32)
+    {
+      session->state = MACH_FIRMWARE_FAILED;
+      return MACH_EIO;
+    }
+  session->image_length = image->length;
+  session->expected_crc32 = image->crc32;
+  session->next_offset = 0;
+  session->state = MACH_FIRMWARE_VALIDATED;
+  return MACH_OK;
+}
+
+mach_error_t
+mach_firmware_upload (struct mach_firmware_session *session, size_t offset,
+                      const uint8_t *data, size_t length)
+{
+  mach_error_t error;
+
+  if (session == NULL || data == NULL || length == 0
+      || (session->state != MACH_FIRMWARE_VALIDATED
+          && session->state != MACH_FIRMWARE_UPLOADING)
+      || offset != session->next_offset || offset > session->image_length
+      || length > MACH_FIRMWARE_MAX_CHUNK
+      || length > session->image_length - offset)
+    return MACH_EINVAL;
+  session->state = MACH_FIRMWARE_UPLOADING;
+  error = session->ops->write (session->context, session->window + offset,
+                               data, length);
+  if (error != MACH_OK)
+    {
+      session->state = MACH_FIRMWARE_FAILED;
+      return error;
+    }
+  session->next_offset += length;
+  session->state = session->next_offset == session->image_length
+                   ? MACH_FIRMWARE_VALIDATED : MACH_FIRMWARE_UPLOADING;
+  return MACH_OK;
+}
+
+mach_error_t
+mach_firmware_commit (struct mach_firmware_session *session)
+{
+  if (session == NULL || session->state != MACH_FIRMWARE_VALIDATED
+      || session->next_offset != session->image_length)
+    return MACH_EINVAL;
+  if (session->ops->fence != NULL)
+    session->ops->fence (session->context);
+  session->state = MACH_FIRMWARE_COMMITTED;
+  return MACH_OK;
+}
+
+void
+mach_firmware_abort (struct mach_firmware_session *session)
+{
+  if (session != NULL)
+    session->state = MACH_FIRMWARE_FAILED;
+}
diff --git a/modern/src/drivers/leds.c b/modern/src/drivers/leds.c
new file mode 100644
index 00000000..a3802bfd
--- /dev/null
+++ b/modern/src/drivers/leds.c
@@ -0,0 +1,80 @@
+/* GPIO and Hurd LED namespace capability for GNU Mach.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+
+   This file is part of GNU Mach.
+
+   GNU Mach is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   The Hurd translator owns policy and translates these records to
+   /dev/leds/<name>.  This layer stores no ACPI/EC protocol or vendor blob.  */
+
+#include <mach/c17/leds.h>
+
+static bool
+led_name_valid (const char *name)
+{
+  size_t length = 0;
+
+  if (name == NULL || name[0] == '\0')
+    return false;
+  while (name[length] != '\0')
+    {
+      if (length >= MACH_LED_NAME_MAX - 1u || name[length] == '/')
+        return false;
+      length++;
+    }
+  return true;
+}
+
+mach_error_t
+mach_led_bank_init (struct mach_led_bank *bank)
+{
+  if (bank == NULL)
+    return MACH_EINVAL;
+  mach_memset (bank, 0, sizeof (*bank));
+  return MACH_OK;
+}
+
+mach_error_t
+mach_led_register (struct mach_led_bank *bank, const char *name,
+                   mach_led_kind_t kind, uint32_t gpio, bool writable,
+                   uint32_t *id)
+{
+  struct mach_led *led;
+  size_t length;
+
+  if (bank == NULL || !led_name_valid (name) || id == NULL
+      || kind < MACH_LED_DIAGNOSTIC || kind > MACH_LED_WIRELESS
+      || bank->count >= MACH_LED_MAX)
+    return MACH_EINVAL;
+  length = mach_strlen (name);
+  led = &bank->leds[bank->count];
+  mach_memcpy (led->name, name, length + 1u);
+  led->kind = kind;
+  led->gpio = gpio;
+  led->writable = writable;
+  *id = bank->count++ + 1u;
+  return MACH_OK;
+}
+
+mach_error_t
+mach_led_set (struct mach_led_bank *bank, uint32_t id, bool value)
+{
+  if (bank == NULL || id == 0 || id > bank->count
+      || !bank->leds[id - 1u].writable)
+    return MACH_EPERM;
+  bank->leds[id - 1u].value = value;
+  return MACH_OK;
+}
+
+mach_error_t
+mach_led_get (const struct mach_led_bank *bank, uint32_t id, bool *value)
+{
+  if (bank == NULL || value == NULL || id == 0 || id > bank->count)
+    return MACH_EINVAL;
+  *value = bank->leds[id - 1u].value;
+  return MACH_OK;
+}
diff --git a/modern/tests/test_modern_platform.c 
b/modern/tests/test_modern_platform.c
new file mode 100644
index 00000000..9194c0ae
--- /dev/null
+++ b/modern/tests/test_modern_platform.c
@@ -0,0 +1,161 @@
+/* Tests for the firmware, audio, iGPU, Bluetooth and LED contracts.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+
+   This file is part of GNU Mach.
+
+   GNU Mach is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.  */
+
+#include <mach/c17/audio.h>
+#include <mach/c17/bluetooth.h>
+#include <mach/c17/firmware.h>
+#include <mach/c17/igpu.h>
+#include <mach/c17/leds.h>
+
+#include "test.h"
+
+struct firmware_capture
+{
+  uint8_t bytes[64];
+  size_t writes;
+  bool fenced;
+};
+
+static mach_error_t
+capture_write (void *context, mach_phys_t offset, const uint8_t *data,
+               size_t length)
+{
+  struct firmware_capture *capture = context;
+  if (offset + length > sizeof (capture->bytes))
+    return MACH_ERANGE;
+  memcpy (capture->bytes + offset, data, length);
+  capture->writes++;
+  return MACH_OK;
+}
+
+static void
+capture_fence (void *context)
+{
+  ((struct firmware_capture *) context)->fenced = true;
+}
+
+struct audio_capture
+{
+  uint32_t stream;
+  mach_phys_t address;
+  size_t bytes;
+  uint32_t irq;
+};
+
+static mach_error_t
+capture_stream (void *context, uint32_t stream, mach_phys_t address, size_t 
bytes)
+{
+  struct audio_capture *capture = context;
+  capture->stream = stream;
+  capture->address = address;
+  capture->bytes = bytes;
+  return MACH_OK;
+}
+
+static mach_error_t
+capture_verb (void *context, uint8_t codec, uint32_t verb)
+{
+  (void) context;
+  (void) codec;
+  (void) verb;
+  return MACH_OK;
+}
+
+static void
+capture_irq (void *context, uint32_t irq)
+{
+  ((struct audio_capture *) context)->irq = irq;
+}
+
+static void
+run_tests (void)
+{
+  static const struct mach_firmware_ops firmware_ops =
+    { capture_write, capture_fence };
+  static const struct mach_hda_ops audio_ops =
+    { capture_stream, capture_verb, capture_irq };
+  struct firmware_capture firmware_capture_state = { { 0 }, 0, false };
+  struct mach_firmware_session session;
+  uint8_t firmware[] = { 1, 2, 3, 4, 5, 6 };
+  struct mach_firmware_image image;
+  uint8_t audio_data[4096];
+  uint8_t frames[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
+  uint8_t result[8] = { 0 };
+  struct mach_audio_ring ring;
+  struct mach_hda_controller hda;
+  struct mach_uac_stream_descriptor descriptor;
+  struct audio_capture audio_capture_state = { 0, 0, 0, 0 };
+  struct mach_mmio mmio = { 0 };
+  struct mach_dma dma = { 0 };
+  uint32_t stream_id;
+  struct mach_igpu gpu;
+  struct mach_ipc_ool ool = { MACH_REFCOUNT_INIT (1), 0x1000, 128, 0, 1 };
+  uint32_t ring_id;
+  struct mach_bt_hci hci;
+  struct mach_led_bank leds;
+  uint32_t led_id;
+  bool value;
+
+  image.data = firmware;
+  image.length = sizeof (firmware);
+  image.crc32 = mach_firmware_crc32 (firmware, sizeof (firmware));
+  CHECK_EQ (mach_firmware_init (&session, &firmware_ops,
+                                &firmware_capture_state, 0, sizeof (firmware)),
+            MACH_OK);
+  CHECK_EQ (mach_firmware_validate (&session, &image), MACH_OK);
+  CHECK_EQ (mach_firmware_upload (&session, 0, firmware, 3), MACH_OK);
+  CHECK_EQ (mach_firmware_upload (&session, 3, firmware + 3, 3), MACH_OK);
+  CHECK_EQ (mach_firmware_commit (&session), MACH_OK);
+  CHECK (firmware_capture_state.fenced);
+  CHECK_EQ (firmware_capture_state.writes, 2);
+  CHECK (memcmp (firmware_capture_state.bytes, firmware, sizeof (firmware)) == 
0);
+
+  CHECK_EQ (mach_audio_ring_init (&ring, audio_data, 8, 1), MACH_OK);
+  CHECK_EQ (mach_audio_ring_write (&ring, frames, 8), 7);
+  CHECK_EQ (mach_audio_ring_read (&ring, result, 4), 4);
+  CHECK (memcmp (result, frames, 4) == 0);
+  descriptor.version = MACH_UAC2;
+  descriptor.sample_rate = 48000;
+  descriptor.channels = 2;
+  descriptor.format = MACH_AUDIO_S24_LE;
+  descriptor.max_packet = 192;
+  descriptor.capture = false;
+  CHECK_EQ (mach_hda_init (&hda, &mmio, &dma, &audio_ops,
+                           &audio_capture_state), MACH_OK);
+  CHECK_EQ (mach_hda_add_stream (&hda, &descriptor, audio_data, 64,
+                                 &stream_id), MACH_OK);
+  CHECK_EQ (mach_hda_start (&hda, stream_id, 0x2000), MACH_OK);
+  CHECK_EQ (audio_capture_state.address, 0x2000);
+  mach_hda_interrupt (&hda, 7);
+  CHECK_EQ (audio_capture_state.irq, 7);
+
+  CHECK_EQ (mach_igpu_init (&gpu, MACH_IGPU_INTEL), MACH_OK);
+  CHECK_EQ (mach_igpu_add_bar (&gpu, 0x100000000ull, 0x100000,
+                               true), MACH_OK);
+  CHECK_EQ (mach_igpu_claim_uma (&gpu, 0x80000000ull, 0x200000), MACH_OK);
+  CHECK_EQ (mach_igpu_add_ring (&gpu, 0x300000, 4096, &ring_id), MACH_OK);
+  CHECK_EQ (mach_igpu_submit (&gpu, ring_id, &ool, 0, 64), MACH_OK);
+
+  CHECK_EQ (mach_bt_init (&hci, MACH_BT_USB), MACH_OK);
+  CHECK_EQ (mach_bt_attach_port (&hci, (struct mach_ipc_port *) &gpu), 
MACH_OK);
+  CHECK_EQ (mach_bt_submit_acl (&hci, &ool, 0, 32), MACH_OK);
+  CHECK_EQ (mach_bt_next_sequence (&hci), 1);
+
+  CHECK_EQ (mach_led_bank_init (&leds), MACH_OK);
+  CHECK_EQ (mach_led_register (&leds, "wifi", MACH_LED_WIRELESS, 4, true,
+                               &led_id), MACH_OK);
+  CHECK_EQ (mach_led_set (&leds, led_id, true), MACH_OK);
+  CHECK_EQ (mach_led_get (&leds, led_id, &value), MACH_OK);
+  CHECK (value);
+  CHECK_EQ (mach_led_register (&leds, "bad/name", MACH_LED_POWER, 5, true,
+                               &led_id), MACH_EINVAL);
+}
+
+TEST_MAIN ("modern platform contracts")
-- 
2.56.0


Reply via email to