squashed proto wip

Change-Id: Iff1e1d5afda995b0251f5c42cd92ed59952fca45
diff --git a/system/dev/audio/intel-hda/controller/intel-hda-dsp.cpp b/system/dev/audio/intel-hda/controller/intel-hda-dsp.cpp
index 7225814..0f1adc3 100644
--- a/system/dev/audio/intel-hda/controller/intel-hda-dsp.cpp
+++ b/system/dev/audio/intel-hda/controller/intel-hda-dsp.cpp
@@ -75,10 +75,10 @@
         ZX_DEBUG_ASSERT(ctx);
         DEV->Disable();
     },
-    .irq_enable = [](void* ctx, ihda_dsp_irq_callback_t* callback, void* cookie) -> zx_status_t
+    .irq_enable = [](void* ctx, const ihda_dsp_irq_t* callback) -> zx_status_t
     {
         ZX_DEBUG_ASSERT(ctx);
-        return DEV->IrqEnable(callback, cookie);
+        return DEV->IrqEnable(callback);
     },
     .irq_disable = [](void* ctx)
     {
@@ -163,16 +163,16 @@
     if (pp_regs() == nullptr) {
         return;
     }
-    if (irq_callback_ == nullptr) {
+    if (irq_callback_.callback == nullptr) {
         return;
     }
-    ZX_DEBUG_ASSERT(irq_cookie_ != nullptr);
+    ZX_DEBUG_ASSERT(irq_callback_.ctx != nullptr);
     ZX_DEBUG_ASSERT(pp_regs() != nullptr);
     uint32_t ppsts = REG_RD(&pp_regs()->ppsts);
     if (!(ppsts & HDA_PPSTS_PIS)) {
         return;
     }
-    irq_callback_(irq_cookie_);
+    irq_callback_.callback(irq_callback_.ctx);
 }
 
 zx_status_t IntelHDADSP::DeviceGetProtocol(uint32_t proto_id, void* protocol) {
@@ -282,15 +282,14 @@
     REG_WR(&pp_regs()->ppctl, 0u);
 }
 
-zx_status_t IntelHDADSP::IrqEnable(ihda_dsp_irq_callback_t* callback, void* cookie) {
+zx_status_t IntelHDADSP::IrqEnable(const ihda_dsp_irq_t* callback) {
     fbl::AutoLock dsp_lock(&dsp_lock_);
-    if (irq_callback_ != nullptr) {
+    if (irq_callback_.callback != nullptr) {
         return ZX_ERR_ALREADY_EXISTS;
     }
-    ZX_DEBUG_ASSERT(irq_cookie_ == nullptr);
+    ZX_DEBUG_ASSERT(irq_callback_.ctx == nullptr);
 
-    irq_callback_ = callback;
-    irq_cookie_ = cookie;
+    irq_callback_ = *callback;
 
     REG_SET_BITS<uint32_t>(&pp_regs()->ppctl, HDA_PPCTL_PIE);
 
@@ -300,8 +299,8 @@
 void IntelHDADSP::IrqDisable() {
     fbl::AutoLock dsp_lock(&dsp_lock_);
     REG_CLR_BITS<uint32_t>(&pp_regs()->ppctl, HDA_PPCTL_PIE);
-    irq_callback_ = nullptr;
-    irq_cookie_ = nullptr;
+    irq_callback_.callback = nullptr;
+    irq_callback_.ctx = nullptr;
 }
 
 zx_status_t IntelHDADSP::CodecGetDispatcherChannel(zx_handle_t* remote_endpoint_out) {
diff --git a/system/dev/audio/intel-hda/controller/intel-hda-dsp.h b/system/dev/audio/intel-hda/controller/intel-hda-dsp.h
index 059d4ef..da18b2b 100644
--- a/system/dev/audio/intel-hda/controller/intel-hda-dsp.h
+++ b/system/dev/audio/intel-hda/controller/intel-hda-dsp.h
@@ -67,7 +67,7 @@
     zx_status_t GetBti(zx_handle_t* out_handle);
     void Enable();
     void Disable();
-    zx_status_t IrqEnable(ihda_dsp_irq_callback_t* callback, void* cookie);
+    zx_status_t IrqEnable(const ihda_dsp_irq_t* callback);
     void IrqDisable();
 
     // ZX_PROTOCOL_IHDA_CODEC Interface
@@ -87,8 +87,7 @@
     IntelHDAController& controller_;
 
     fbl::Mutex dsp_lock_;
-    ihda_dsp_irq_callback_t* irq_callback_ TA_GUARDED(dsp_lock_) = nullptr;
-    void* irq_cookie_ TA_GUARDED(dsp_lock_) = nullptr;
+    ihda_dsp_irq_t irq_callback_ TA_GUARDED(dsp_lock_) = {nullptr, nullptr};
 
     // Driver connection state
     fbl::Mutex codec_driver_channel_lock_;
diff --git a/system/dev/audio/intel-hda/dsp/intel-audio-dsp.cpp b/system/dev/audio/intel-hda/dsp/intel-audio-dsp.cpp
index 1b03fa7..6b81bf5 100644
--- a/system/dev/audio/intel-hda/dsp/intel-audio-dsp.cpp
+++ b/system/dev/audio/intel-hda/dsp/intel-audio-dsp.cpp
@@ -164,11 +164,15 @@
 
     // Set IRQ handler and enable HDA interrupt.
     // Interrupts are still masked at the DSP level.
-    res = ihda_dsp_irq_enable(&ihda_dsp_,
-                              [](void* cookie) {
-                                  auto thiz = static_cast<IntelAudioDsp*>(cookie);
-                                  thiz->ProcessIrq();
-                              }, this);
+
+    ihda_dsp_irq_t callback = {
+        [](void* cookie) {
+            auto thiz = static_cast<IntelAudioDsp*>(cookie);
+            thiz->ProcessIrq();
+        },
+        this,
+    };
+    res = ihda_dsp_irq_enable(&ihda_dsp_, &callback);
     if (res != ZX_OK) {
         LOG(ERROR, "Failed to set DSP interrupt callback (res %d)\n", res);
         return res;
@@ -179,7 +183,8 @@
 
 zx_status_t IntelAudioDsp::ParseNhlt() {
     size_t size = 0;
-    zx_status_t res = device_get_metadata(codec_device(), MD_KEY_NHLT,
+    zx_status_t res = device_get_metadata(codec_device(),
+                                          *reinterpret_cast<const uint32_t*>(MD_KEY_NHLT),
                                           nhlt_buf_, sizeof(nhlt_buf_), &size);
     if (res != ZX_OK) {
         LOG(ERROR, "Failed to fetch NHLT (res %d)\n", res);
diff --git a/system/dev/block/ahci/ahci.c b/system/dev/block/ahci/ahci.c
index c5c1776..703a5dc 100644
--- a/system/dev/block/ahci/ahci.c
+++ b/system/dev/block/ahci/ahci.c
@@ -9,8 +9,10 @@
 #include <ddk/io-buffer.h>
 #include <ddk/phys-iter.h>
 #include <ddk/protocol/pci.h>
+#include <ddk/protocol/pci-lib.h>
 
 #include <assert.h>
+#include <hw/pci.h>
 #include <zircon/listnode.h>
 #include <zircon/syscalls.h>
 #include <zircon/types.h>
diff --git a/system/dev/block/aml-sd-emmc/aml-sd-emmc.c b/system/dev/block/aml-sd-emmc/aml-sd-emmc.c
index 478c5ef..70168a8 100644
--- a/system/dev/block/aml-sd-emmc/aml-sd-emmc.c
+++ b/system/dev/block/aml-sd-emmc/aml-sd-emmc.c
@@ -211,7 +211,7 @@
     return ZX_OK;
 }
 
-static zx_status_t aml_sd_emmc_set_bus_width(void* ctx, uint32_t bw) {
+static zx_status_t aml_sd_emmc_set_bus_width(void* ctx, sdmmc_bus_width_t bw) {
     aml_sd_emmc_t* dev = (aml_sd_emmc_t*)ctx;
 
     mtx_lock(&dev->mtx);
@@ -219,15 +219,15 @@
     uint32_t config = regs->sd_emmc_cfg;
 
     switch (bw) {
-    case SDMMC_BUS_WIDTH_1:
+    case SDMMC_BUS_WIDTH_ONE:
         update_bits(&config, AML_SD_EMMC_CFG_BUS_WIDTH_MASK, AML_SD_EMMC_CFG_BUS_WIDTH_LOC,
                     AML_SD_EMMC_CFG_BUS_WIDTH_1BIT);
         break;
-    case SDMMC_BUS_WIDTH_4:
+    case SDMMC_BUS_WIDTH_FOUR:
         update_bits(&config, AML_SD_EMMC_CFG_BUS_WIDTH_MASK, AML_SD_EMMC_CFG_BUS_WIDTH_LOC,
                     AML_SD_EMMC_CFG_BUS_WIDTH_4BIT);
         break;
-    case SDMMC_BUS_WIDTH_8:
+    case SDMMC_BUS_WIDTH_EIGHT:
         update_bits(&config, AML_SD_EMMC_CFG_BUS_WIDTH_MASK, AML_SD_EMMC_CFG_BUS_WIDTH_LOC,
                     AML_SD_EMMC_CFG_BUS_WIDTH_8BIT);
         break;
@@ -250,7 +250,8 @@
         .blockcount = 1,
         .blocksize = blk_pattern_size,
         .use_dma = false,
-        .virt = tuning_res,
+        .virt_buffer = tuning_res,
+        .virt_size = blk_pattern_size,
     };
     return aml_sd_emmc_request(dev, &tuning_req);
 }
@@ -614,7 +615,7 @@
                 goto complete;
             }
             uint32_t data_copied = 0;
-            uint32_t* dest = (uint32_t*)req->virt;
+            uint32_t* dest = (uint32_t*)req->virt_buffer;
             volatile uint32_t* src = (volatile uint32_t*)(io_buffer_virt(&dev->mmio) +
                                                           AML_SD_EMMC_PING_BUFFER_BASE);
             while (length) {
@@ -804,7 +805,7 @@
         desc->cmd_info |= AML_SD_EMMC_CMD_INFO_DATA_WR;
         uint32_t data_copied = 0;
         uint32_t data_remaining = length;
-        uint32_t* src = (uint32_t*)req->virt;
+        uint32_t* src = (uint32_t*)req->virt_buffer;
         volatile uint32_t* dest = (volatile uint32_t*)(io_buffer_virt(&dev->mmio) +
                                                        AML_SD_EMMC_PING_BUFFER_BASE);
         while (data_remaining) {
diff --git a/system/dev/block/imx-sdhci/imx-sdhci.c b/system/dev/block/imx-sdhci/imx-sdhci.c
index 53bc8f3..df2b877 100644
--- a/system/dev/block/imx-sdhci/imx-sdhci.c
+++ b/system/dev/block/imx-sdhci/imx-sdhci.c
@@ -356,7 +356,7 @@
     // Sequentially read each block
     for (size_t byteid = 0; byteid < req->blocksize; byteid += 4) {
         const size_t offset = dev->data_blockid * req->blocksize + byteid;
-        uint32_t* wrd = req->virt + offset;
+        uint32_t* wrd = req->virt_buffer + offset;
         *wrd = dev->regs->data_buff_acc_port; //TODO: Can't read this if DMA is enabled!
     }
     dev->data_blockid += 1;
@@ -375,7 +375,7 @@
     // Sequentially write each block
     for (size_t byteid = 0; byteid < req->blocksize; byteid += 4) {
         const size_t offset = dev->data_blockid * req->blocksize + byteid;
-        uint32_t* wrd = req->virt + offset;
+        uint32_t* wrd = req->virt_buffer + offset;
         dev->regs->data_buff_acc_port = *wrd; //TODO: Can't write if DMA is enabled
     }
     dev->data_blockid += 1;
@@ -778,7 +778,7 @@
 }
 
 /* SDMMC PROTOCOL Implementations: set_bus_width */
-static zx_status_t imx_sdhci_set_bus_width(void* ctx, uint32_t bus_width) {
+static zx_status_t imx_sdhci_set_bus_width(void* ctx, sdmmc_bus_width_t bus_width) {
     SDHCI_FUNC_ENTRY_LOG;
     if (bus_width >= SDMMC_BUS_WIDTH_MAX) {
         return ZX_ERR_INVALID_ARGS;
@@ -788,22 +788,22 @@
 
     mtx_lock(&dev->mtx);
 
-    if ((bus_width == SDMMC_BUS_WIDTH_8) && !(dev->info.caps & SDMMC_HOST_CAP_BUS_WIDTH_8)) {
+    if ((bus_width == SDMMC_BUS_WIDTH_EIGHT) && !(dev->info.caps & SDMMC_HOST_CAP_BUS_WIDTH_8)) {
         SDHCI_ERROR("8-bit bus width not supported\n");
         status = ZX_ERR_NOT_SUPPORTED;
         goto unlock;
     }
 
     switch (bus_width) {
-        case SDMMC_BUS_WIDTH_1:
+        case SDMMC_BUS_WIDTH_ONE:
             dev->regs->prot_ctrl &= ~IMX_SDHC_PROT_CTRL_DTW_MASK;
             dev->regs->prot_ctrl |= IMX_SDHC_PROT_CTRL_DTW_1;
             break;
-        case SDMMC_BUS_WIDTH_4:
+        case SDMMC_BUS_WIDTH_FOUR:
             dev->regs->prot_ctrl &= ~IMX_SDHC_PROT_CTRL_DTW_MASK;
             dev->regs->prot_ctrl |= IMX_SDHC_PROT_CTRL_DTW_4;
             break;
-        case SDMMC_BUS_WIDTH_8:
+        case SDMMC_BUS_WIDTH_EIGHT:
             dev->regs->prot_ctrl &= ~IMX_SDHC_PROT_CTRL_DTW_MASK;
             dev->regs->prot_ctrl |= IMX_SDHC_PROT_CTRL_DTW_8;
             break;
@@ -985,7 +985,7 @@
     // enable clocks
     mtx_unlock(&dev->mtx);
     imx_sdhci_set_bus_freq(dev, SD_FREQ_SETUP_HZ);
-    imx_sdhci_set_bus_width(dev, SDMMC_BUS_WIDTH_1);
+    imx_sdhci_set_bus_width(dev, SDMMC_BUS_WIDTH_ONE);
 }
 
 /* SDMMC PROTOCOL Implementations: request */
diff --git a/system/dev/block/pci-sdhci/pci-sdhci.c b/system/dev/block/pci-sdhci/pci-sdhci.c
index c903f7b..d1d72b5 100644
--- a/system/dev/block/pci-sdhci/pci-sdhci.c
+++ b/system/dev/block/pci-sdhci/pci-sdhci.c
@@ -50,7 +50,7 @@
     }
 }
 
-static zx_status_t pci_sdhci_get_mmio(void* ctx, volatile sdhci_regs_t** out) {
+static zx_status_t pci_sdhci_get_mmio(void* ctx, zx_handle_t* out) {
     pci_sdhci_device_t* dev = ctx;
     if (dev->regs == NULL) {
         zx_status_t status = pci_map_bar(&dev->pci, 0u, ZX_CACHE_POLICY_UNCACHED_DEVICE,
@@ -60,8 +60,7 @@
             return status;
         }
     }
-    *out = dev->regs;
-    return ZX_OK;
+    return zx_vmo_clone(dev->regs_handle, ZX_RIGHT_SAME_RIGHTS, 0, dev->regs_size, out);
 }
 
 static zx_status_t pci_sdhci_get_bti(void* ctx, uint32_t index, zx_handle_t* out_handle) {
diff --git a/system/dev/block/sdhci/sdhci.c b/system/dev/block/sdhci/sdhci.c
index 8644588..705d708 100644
--- a/system/dev/block/sdhci/sdhci.c
+++ b/system/dev/block/sdhci/sdhci.c
@@ -29,6 +29,7 @@
 #include <hw/sdmmc.h>
 
 // Zircon Includes
+#include <zircon/process.h>
 #include <zircon/threads.h>
 #include <zircon/assert.h>
 #include <lib/sync/completion.h>
@@ -76,6 +77,7 @@
     zx_handle_t irq_handle;
     thrd_t irq_thread;
 
+    zx_handle_t regs_handle;
     volatile sdhci_regs_t* regs;
 
     sdhci_protocol_t sdhci;
@@ -146,7 +148,7 @@
 
 static bool sdhci_supports_adma2_64bit(sdhci_device_t* dev) {
     return (dev->info.caps & SDMMC_HOST_CAP_ADMA2) &&
-           (dev->info.caps & SDMMC_HOST_CAP_64BIT) &&
+           (dev->info.caps & SDMMC_HOST_CAP_SIXTY_FOUR_BIT) &&
            !(dev->quirks & SDHCI_QUIRK_NO_DMA);
 }
 
@@ -281,7 +283,7 @@
         // Sequentially read each block.
         for (size_t byteid = 0; byteid < req->blocksize; byteid += 4) {
             const size_t offset = dev->data_blockid * req->blocksize + byteid;
-            uint32_t* wrd = req->virt + offset;
+            uint32_t* wrd = req->virt_buffer + offset;
             *wrd = dev->regs->data;
         }
         dev->data_blockid += 1;
@@ -301,7 +303,7 @@
     // Sequentially write each block.
     for (size_t byteid = 0; byteid < req->blocksize; byteid += 4) {
         const size_t offset = dev->data_blockid * req->blocksize + byteid;
-        uint32_t* wrd = req->virt + offset;
+        uint32_t* wrd = req->virt_buffer + offset;
         dev->regs->data = *wrd;
     }
     dev->data_blockid += 1;
@@ -614,7 +616,7 @@
     mtx_lock(&dev->mtx);
 
     // Validate the controller supports the requested voltage
-    if ((voltage == SDMMC_VOLTAGE_330) && !(dev->info.caps & SDMMC_HOST_CAP_VOLTAGE_330)) {
+    if ((voltage == SDMMC_VOLTAGE_V330) && !(dev->info.caps & SDMMC_HOST_CAP_VOLTAGE_330)) {
         zxlogf(TRACE, "sdhci: 3.3V signal voltage not supported\n");
         st = ZX_ERR_NOT_SUPPORTED;
         goto unlock;
@@ -625,7 +627,7 @@
     zx_nanosleep(zx_deadline_after(ZX_MSEC(2)));
 
     switch (voltage) {
-    case SDMMC_VOLTAGE_180: {
+    case SDMMC_VOLTAGE_V180: {
         regs->ctrl2 |= SDHCI_HOSTCTRL2_1P8V_SIGNALLING_ENA;
         // 1.8V regulator out should be stable within 5ms
         zx_nanosleep(zx_deadline_after(ZX_MSEC(5)));
@@ -638,7 +640,7 @@
         }
         break;
     }
-    case SDMMC_VOLTAGE_330: {
+    case SDMMC_VOLTAGE_V330: {
         regs->ctrl2 &= ~SDHCI_HOSTCTRL2_1P8V_SIGNALLING_ENA;
         // 3.3V regulator out should be stable within 5ms
         zx_nanosleep(zx_deadline_after(ZX_MSEC(5)));
@@ -658,10 +660,10 @@
     // Make sure our changes are acknolwedged.
     uint32_t expected_mask = SDHCI_PWRCTRL_SD_BUS_POWER;
     switch (voltage) {
-    case SDMMC_VOLTAGE_180:
+    case SDMMC_VOLTAGE_V180:
         expected_mask |= SDHCI_PWRCTRL_SD_BUS_VOLTAGE_1P8V;
         break;
-    case SDMMC_VOLTAGE_330:
+    case SDMMC_VOLTAGE_V330:
         expected_mask |= SDHCI_PWRCTRL_SD_BUS_VOLTAGE_3P3V;
         break;
     default:
@@ -685,7 +687,7 @@
     return st;
 }
 
-static zx_status_t sdhci_set_bus_width(void* ctx, uint32_t bus_width) {
+static zx_status_t sdhci_set_bus_width(void* ctx, sdmmc_bus_width_t bus_width) {
     if (bus_width >= SDMMC_BUS_WIDTH_MAX) {
         return ZX_ERR_INVALID_ARGS;
     }
@@ -695,22 +697,22 @@
 
     mtx_lock(&dev->mtx);
 
-    if ((bus_width == SDMMC_BUS_WIDTH_8) && !(dev->info.caps & SDMMC_HOST_CAP_BUS_WIDTH_8)) {
+    if ((bus_width == SDMMC_BUS_WIDTH_EIGHT) && !(dev->info.caps & SDMMC_HOST_CAP_BUS_WIDTH_8)) {
         zxlogf(TRACE, "sdhci: 8-bit bus width not supported\n");
         st =  ZX_ERR_NOT_SUPPORTED;
         goto unlock;
     }
 
     switch (bus_width) {
-    case SDMMC_BUS_WIDTH_1:
+    case SDMMC_BUS_WIDTH_ONE:
         dev->regs->ctrl0 &= ~SDHCI_HOSTCTRL_EXT_DATA_WIDTH;
         dev->regs->ctrl0 &= ~SDHCI_HOSTCTRL_FOUR_BIT_BUS_WIDTH;
         break;
-    case SDMMC_BUS_WIDTH_4:
+    case SDMMC_BUS_WIDTH_FOUR:
         dev->regs->ctrl0 &= ~SDHCI_HOSTCTRL_EXT_DATA_WIDTH;
         dev->regs->ctrl0 |= SDHCI_HOSTCTRL_FOUR_BIT_BUS_WIDTH;
         break;
-    case SDMMC_BUS_WIDTH_8:
+    case SDMMC_BUS_WIDTH_EIGHT:
         dev->regs->ctrl0 |= SDHCI_HOSTCTRL_EXT_DATA_WIDTH;
         break;
     default:
@@ -808,11 +810,11 @@
     return st;
 }
 
-static void sdhci_hw_reset(void* ctx) {
+static void sdhci_hw_reset2(void* ctx) {
     sdhci_device_t* dev = ctx;
     mtx_lock(&dev->mtx);
     if (dev->sdhci.ops->hw_reset) {
-        dev->sdhci.ops->hw_reset(dev->sdhci.ctx);
+        sdhci_hw_reset(&dev->sdhci);
     }
     mtx_unlock(&dev->mtx);
 }
@@ -902,7 +904,7 @@
     .set_bus_width = sdhci_set_bus_width,
     .set_bus_freq = sdhci_set_bus_freq,
     .set_timing = sdhci_set_timing,
-    .hw_reset = sdhci_hw_reset,
+    .hw_reset = sdhci_hw_reset2,
     .perform_tuning = sdhci_perform_tuning,
     .request = sdhci_request,
 };
@@ -919,6 +921,8 @@
 
 static void sdhci_release(void* ctx) {
     sdhci_device_t* dev = ctx;
+    zx_vmar_unmap(zx_vmar_root_self(), (uintptr_t)dev->regs, sizeof(dev->regs));
+    zx_handle_close(dev->regs_handle);
     zx_handle_close(dev->irq_handle);
     zx_handle_close(dev->bti_handle);
     zx_handle_close(dev->iobuf.vmo_handle);
@@ -1053,12 +1057,18 @@
     }
 
     // Map the Device Registers so that we can perform MMIO against the device.
-    status = dev->sdhci.ops->get_mmio(dev->sdhci.ctx, &dev->regs);
+    status = dev->sdhci.ops->get_mmio(dev->sdhci.ctx, &dev->regs_handle);
     if (status != ZX_OK) {
         zxlogf(ERROR, "sdhci: error %d in get_mmio\n", status);
         goto fail;
     }
-
+    status = zx_vmar_map(zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0,
+                         dev->regs_handle, 0, ROUNDUP(sizeof(dev->regs), PAGE_SIZE),
+                         (uintptr_t*)&dev->regs);
+    if (status != ZX_OK) {
+        zxlogf(ERROR, "sdhci: error %d in zx_vmar_map\n", status);
+        goto fail;
+    }
     status = dev->sdhci.ops->get_bti(dev->sdhci.ctx, 0, &dev->bti_handle);
     if (status != ZX_OK) {
         zxlogf(ERROR, "sdhci: error %d in get_bti\n", status);
@@ -1108,7 +1118,7 @@
         dev->info.caps |= SDMMC_HOST_CAP_ADMA2;
     }
     if (caps0 & SDHCI_CORECFG_64BIT_SUPPORT) {
-        dev->info.caps |= SDMMC_HOST_CAP_64BIT;
+        dev->info.caps |= SDMMC_HOST_CAP_SIXTY_FOUR_BIT;
     }
     if (caps0 & SDHCI_CORECFG_3P3_VOLT_SUPPORT) {
         dev->info.caps |= SDMMC_HOST_CAP_VOLTAGE_330;
diff --git a/system/dev/block/sdmmc/mmc.c b/system/dev/block/sdmmc/mmc.c
index 1d54c25..ee04178 100644
--- a/system/dev/block/sdmmc/mmc.c
+++ b/system/dev/block/sdmmc/mmc.c
@@ -71,9 +71,9 @@
 
 static uint8_t mmc_select_bus_width(sdmmc_device_t* dev) {
     // TODO verify host 8-bit support
-    uint8_t bus_widths[] = { SDMMC_BUS_WIDTH_8, MMC_EXT_CSD_BUS_WIDTH_8,
-                             SDMMC_BUS_WIDTH_4, MMC_EXT_CSD_BUS_WIDTH_4,
-                             SDMMC_BUS_WIDTH_1, MMC_EXT_CSD_BUS_WIDTH_1 };
+    uint8_t bus_widths[] = { SDMMC_BUS_WIDTH_EIGHT, MMC_EXT_CSD_BUS_WIDTH_8,
+                             SDMMC_BUS_WIDTH_FOUR, MMC_EXT_CSD_BUS_WIDTH_4,
+                             SDMMC_BUS_WIDTH_ONE, MMC_EXT_CSD_BUS_WIDTH_1 };
     for (unsigned i = 0; i < (sizeof(bus_widths)/sizeof(uint8_t)); i += 2) {
         if (mmc_set_bus_width(dev, bus_widths[i], bus_widths[i+1]) == ZX_OK) {
             break;
@@ -270,13 +270,13 @@
     }
 
     dev->type = SDMMC_TYPE_MMC;
-    dev->bus_width = SDMMC_BUS_WIDTH_1;
-    dev->signal_voltage = SDMMC_VOLTAGE_330;
+    dev->bus_width = SDMMC_BUS_WIDTH_ONE;
+    dev->signal_voltage = SDMMC_VOLTAGE_V330;
 
     // Switch to high-speed timing
     if (mmc_supports_hs(dev) || mmc_supports_hsddr(dev) || mmc_supports_hs200(dev)) {
         // Switch to 1.8V signal voltage
-        sdmmc_voltage_t new_voltage = SDMMC_VOLTAGE_180;
+        sdmmc_voltage_t new_voltage = SDMMC_VOLTAGE_V180;
         if ((st = sdmmc_set_signal_voltage(&dev->host, new_voltage)) != ZX_OK) {
             zxlogf(ERROR, "mmc: failed to switch to 1.8V signalling, retcode = %d\n", st);
             goto err;
@@ -286,7 +286,7 @@
         mmc_select_bus_width(dev);
 
         // Must perform tuning at HS200 first if HS400 is supported
-        if (mmc_supports_hs200(dev) && dev->bus_width != SDMMC_BUS_WIDTH_1 &&
+        if (mmc_supports_hs200(dev) && dev->bus_width != SDMMC_BUS_WIDTH_ONE &&
                 !(dev->host_info.prefs & SDMMC_HOST_PREFS_DISABLE_HS200)) {
             if ((st = mmc_switch_timing(dev, SDMMC_TIMING_HS200)) != ZX_OK) {
                 goto err;
@@ -301,7 +301,7 @@
                 goto err;
             }
 
-            if (mmc_supports_hs400(dev) && dev->bus_width == SDMMC_BUS_WIDTH_8 &&
+            if (mmc_supports_hs400(dev) && dev->bus_width == SDMMC_BUS_WIDTH_EIGHT &&
                     !(dev->host_info.prefs & SDMMC_HOST_PREFS_DISABLE_HS400)) {
                 if ((st = mmc_switch_timing(dev, SDMMC_TIMING_HS)) != ZX_OK) {
                     goto err;
@@ -311,7 +311,7 @@
                     goto err;
                 }
 
-                if ((st = mmc_set_bus_width(dev, SDMMC_BUS_WIDTH_8,
+                if ((st = mmc_set_bus_width(dev, SDMMC_BUS_WIDTH_EIGHT,
                                             MMC_EXT_CSD_BUS_WIDTH_8_DDR)) != ZX_OK) {
                     goto err;
                 }
@@ -329,12 +329,12 @@
                 goto err;
             }
 
-            if (mmc_supports_hsddr(dev) && (dev->bus_width != SDMMC_BUS_WIDTH_1)) {
+            if (mmc_supports_hsddr(dev) && (dev->bus_width != SDMMC_BUS_WIDTH_ONE)) {
                 if ((st = mmc_switch_timing(dev, SDMMC_TIMING_HSDDR)) != ZX_OK) {
                     goto err;
                 }
 
-                uint8_t mmc_bus_width = (dev->bus_width == SDMMC_BUS_WIDTH_4) ?
+                uint8_t mmc_bus_width = (dev->bus_width == SDMMC_BUS_WIDTH_FOUR) ?
                                             MMC_EXT_CSD_BUS_WIDTH_4_DDR :
                                             MMC_EXT_CSD_BUS_WIDTH_8_DDR;
                 if ((st = mmc_set_bus_width(dev, dev->bus_width, mmc_bus_width)) != ZX_OK) {
diff --git a/system/dev/block/sdmmc/ops.c b/system/dev/block/sdmmc/ops.c
index d15c559..314401d 100644
--- a/system/dev/block/sdmmc/ops.c
+++ b/system/dev/block/sdmmc/ops.c
@@ -120,7 +120,7 @@
         .use_dma = sdmmc_use_dma(dev),
     };
 
-    if (dev->signal_voltage == SDMMC_VOLTAGE_180) {
+    if (dev->signal_voltage == SDMMC_VOLTAGE_V180) {
         return ZX_OK;
     }
 
@@ -131,7 +131,7 @@
     }
     zx_nanosleep(zx_deadline_after(ZX_MSEC(20)));
     //TODO: clock gating while switching voltage
-    st = sdmmc_set_signal_voltage(&dev->host, SDMMC_VOLTAGE_180);
+    st = sdmmc_set_signal_voltage(&dev->host, SDMMC_VOLTAGE_V180);
     if (st != ZX_OK) {
         zxlogf(TRACE, "sd: SD_VOLTAGE_SWITCH failed, retcode = %d\n", st);
         return st;
@@ -239,11 +239,12 @@
     };
 
     if (use_dma) {
-        req.virt = NULL;
+        req.virt_buffer = NULL;
         req.dma_vmo = dma_vmo;
         req.buf_offset = buf_offset;
     } else {
-        req.virt = buf + buf_offset;
+        req.virt_buffer = buf + buf_offset;
+        req.virt_size = blk_size;
     }
     req.use_dma = use_dma;
 
@@ -334,7 +335,8 @@
         .blockcount = 1,
         .blocksize = 512,
         .use_dma = false,
-        .virt = ext_csd,
+        .virt_buffer = ext_csd,
+        .virt_size = 512,
         .cmd_flags = MMC_SEND_EXT_CSD_FLAGS,
     };
     zx_status_t st = sdmmc_request(&dev->host, &req);
diff --git a/system/dev/block/sdmmc/sdio.c b/system/dev/block/sdmmc/sdio.c
index 841afaa..000dc25 100644
--- a/system/dev/block/sdmmc/sdio.c
+++ b/system/dev/block/sdmmc/sdio.c
@@ -14,6 +14,7 @@
 #include <ddk/protocol/sdmmc.h>
 #include <ddk/protocol/sdio.h>
 
+#include <hw/sdio.h>
 #include <zircon/process.h>
 #include <zircon/threads.h>
 
@@ -53,7 +54,7 @@
     // Use io_rw_direct whenever possible.
     if (!use_dma && data_size == 1) {
         return sdio_rw_byte(dev, txn->write, fn_idx, addr,
-                            *(uintptr_t*)(txn->virt), txn->virt);
+                            *(uintptr_t*)(txn->virt_buffer), txn->virt_buffer);
     }
 
     if ((data_size % 4) != 0) {
@@ -64,7 +65,7 @@
         return ZX_ERR_NOT_SUPPORTED;
     }
     bool dma_supported = sdmmc_use_dma(dev);
-    void *buf = use_dma ? NULL : txn->virt;
+    void *buf = use_dma ? NULL : txn->virt_buffer;
     zx_handle_t dma_vmo = use_dma ? txn->dma_vmo : ZX_HANDLE_INVALID;
     uint64_t buf_offset = txn->buf_offset;
 
@@ -130,7 +131,8 @@
     sdio_rw_txn_t txn;
     txn.addr = addr;
     txn.write = false;
-    txn.virt = dword;
+    txn.virt_buffer = dword;
+    txn.virt_size = 4;
     txn.data_size = 4;
     txn.incr = true;
     txn.use_dma = false;
@@ -143,7 +145,8 @@
     sdio_rw_txn_t txn;
     txn.addr = addr;
     txn.write = true;
-    txn.virt = (void *)&dword;
+    txn.virt_buffer = (void *)&dword;
+    txn.virt_size = 4;
     txn.data_size = 4;
     txn.incr = true;
     txn.use_dma = false;
@@ -241,7 +244,7 @@
         dev->sdio_dev.hw_info.caps |= SDIO_CARD_LOW_SPEED;
     }
     if (card_caps & SDIO_CIA_CCCR_CARD_CAP_4BLS) {
-        dev->sdio_dev.hw_info.caps |= SDIO_CARD_4BIT_BUS;
+        dev->sdio_dev.hw_info.caps |= SDIO_CARD_FOUR_BIT_BUS;
     }
 
     //speed
@@ -278,13 +281,13 @@
         return status;
     }
     if (drv_strength & SDIO_CIA_CCCR_DRV_STRENGTH_SDTA) {
-        dev->sdio_dev.hw_info.caps |= SDIO_DRIVER_TYPE_A;
+        dev->sdio_dev.hw_info.caps |= SDIO_CARD_TYPE_A;
     }
     if (drv_strength & SDIO_CIA_CCCR_DRV_STRENGTH_SDTB) {
-        dev->sdio_dev.hw_info.caps |= SDIO_DRIVER_TYPE_B;
+        dev->sdio_dev.hw_info.caps |= SDIO_CARD_TYPE_B;
     }
     if (drv_strength & SDIO_CIA_CCCR_DRV_STRENGTH_SDTD) {
-        dev->sdio_dev.hw_info.caps |= SDIO_DRIVER_TYPE_D;
+        dev->sdio_dev.hw_info.caps |= SDIO_CARD_TYPE_D;
     }
     return status;
 }
@@ -518,7 +521,7 @@
 static zx_status_t sdio_enable_4bit_bus(sdmmc_device_t *dev) {
     zx_status_t st = ZX_OK;
     if ((dev->sdio_dev.hw_info.caps & SDIO_CARD_LOW_SPEED) &&
-        !(dev->sdio_dev.hw_info.caps & SDIO_CARD_4BIT_BUS)) {
+        !(dev->sdio_dev.hw_info.caps & SDIO_CARD_FOUR_BIT_BUS)) {
         zxlogf(ERROR, "sdio: Switching to 4-bit bus unsupported\n");
         return ZX_ERR_NOT_SUPPORTED;
     }
@@ -535,13 +538,13 @@
         zxlogf(ERROR, "sdio: Error while switching the bus width\n");
         return st;
     }
-    if ((st = sdmmc_set_bus_width(&dev->host, SDMMC_BUS_WIDTH_4)) != ZX_OK) {
+    if ((st = sdmmc_set_bus_width(&dev->host, SDMMC_BUS_WIDTH_FOUR)) != ZX_OK) {
           zxlogf(ERROR, "sdio: failed to switch the host bus width to %d, retcode = %d\n",
-                 SDMMC_BUS_WIDTH_4, st);
+                 SDMMC_BUS_WIDTH_FOUR, st);
           return ZX_ERR_INTERNAL;
     }
 
-    dev->bus_width = SDMMC_BUS_WIDTH_4;
+    dev->bus_width = SDMMC_BUS_WIDTH_FOUR;
     return ZX_OK;
 }
 
@@ -773,7 +776,7 @@
         return ZX_ERR_NOT_SUPPORTED;
     }
     dev->type = SDMMC_TYPE_SDIO;
-    dev->signal_voltage = SDMMC_VOLTAGE_180;
+    dev->signal_voltage = SDMMC_VOLTAGE_V180;
     dev->sdio_dev.hw_info.num_funcs = get_bits(ocr, SDIO_SEND_OP_COND_RESP_NUM_FUNC_MASK,
                                                SDIO_SEND_OP_COND_RESP_NUM_FUNC_LOC);
     uint16_t addr = 0;
diff --git a/system/dev/block/sdmmc/sdio.h b/system/dev/block/sdmmc/sdio.h
index ecd3095..061d36a 100644
--- a/system/dev/block/sdmmc/sdio.h
+++ b/system/dev/block/sdmmc/sdio.h
@@ -25,6 +25,9 @@
     sdio_function_t funcs[SDIO_MAX_FUNCS];
 } sdio_device_t;
 
+static inline bool sdio_fn_idx_valid(uint8_t fn_idx) {
+    return (fn_idx < SDIO_MAX_FUNCS);
+}
 
 static inline bool sdio_is_uhs_supported(uint32_t hw_caps) {
     return ((hw_caps & SDIO_CARD_UHS_SDR50) || (hw_caps & SDIO_CARD_UHS_SDR104) ||
diff --git a/system/dev/block/sdmmc/sdmmc.c b/system/dev/block/sdmmc/sdmmc.c
index 7b5d354..b1910c2 100644
--- a/system/dev/block/sdmmc/sdmmc.c
+++ b/system/dev/block/sdmmc/sdmmc.c
@@ -385,7 +385,7 @@
     zx_status_t st = ZX_OK;
     if (sdmmc_use_dma(dev)) {
         req->use_dma = true;
-        req->virt = NULL;
+        req->virt_buffer = NULL;
         req->pmt = ZX_HANDLE_INVALID;
         req->dma_vmo =  txn->bop.rw.vmo;
         req->buf_offset = txn->bop.rw.offset_vmo;
@@ -393,12 +393,13 @@
         req->use_dma = false;
         st = zx_vmar_map(zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
                          0, txn->bop.rw.vmo, txn->bop.rw.offset_vmo, txn->bop.rw.length,
-                         (uintptr_t*)&req->virt);
+                         (uintptr_t*)&req->virt_buffer);
         if (st != ZX_OK) {
             zxlogf(TRACE, "sdmmc: do_txn vmo map error %d\n", st);
             block_complete(&txn->bop, st, dev);
             return;
         }
+        req->virt_size = txn->bop.rw.length;
     }
 
     st = sdmmc_request(&dev->host, req);
@@ -417,7 +418,7 @@
     }
 exit:
     if (!req->use_dma) {
-        zx_vmar_unmap(zx_vmar_root_self(), (uintptr_t)req->virt, txn->bop.rw.length);
+        zx_vmar_unmap(zx_vmar_root_self(), (uintptr_t)req->virt_buffer, req->virt_size);
     }
     block_complete(&txn->bop, st, dev);
     zxlogf(TRACE, "sdmmc: do_txn complete\n");
diff --git a/system/dev/block/sdmmc/sdmmc.h b/system/dev/block/sdmmc/sdmmc.h
index 23da68e..fff443b 100644
--- a/system/dev/block/sdmmc/sdmmc.h
+++ b/system/dev/block/sdmmc/sdmmc.h
@@ -92,7 +92,7 @@
 } sdmmc_device_t;
 
 static inline bool sdmmc_use_dma(sdmmc_device_t* dev) {
-    return (dev->host_info.caps & (SDMMC_HOST_CAP_ADMA2 | SDMMC_HOST_CAP_64BIT));
+    return (dev->host_info.caps & (SDMMC_HOST_CAP_ADMA2 | SDMMC_HOST_CAP_SIXTY_FOUR_BIT));
 }
 
 // SD/MMC shared ops
diff --git a/system/dev/bluetooth/bt-hci-broadcom/bt-hci-broadcom.c b/system/dev/bluetooth/bt-hci-broadcom/bt-hci-broadcom.c
index 3fb4cf2..4ff9aea 100644
--- a/system/dev/bluetooth/bt-hci-broadcom/bt-hci-broadcom.c
+++ b/system/dev/bluetooth/bt-hci-broadcom/bt-hci-broadcom.c
@@ -15,6 +15,7 @@
 #include <string.h>
 #include <threads.h>
 #include <zircon/device/bt-hci.h>
+#include <zircon/device/serial.h>
 #include <zircon/status.h>
 #include <zircon/threads.h>
 
diff --git a/system/dev/bluetooth/bt-transport-uart/bt-transport-uart.c b/system/dev/bluetooth/bt-transport-uart/bt-transport-uart.c
index 5d75698..091eab0 100644
--- a/system/dev/bluetooth/bt-transport-uart/bt-transport-uart.c
+++ b/system/dev/bluetooth/bt-transport-uart/bt-transport-uart.c
@@ -10,6 +10,7 @@
 #include <ddk/protocol/platform-defs.h>
 #include <ddk/protocol/serial.h>
 #include <zircon/device/bt-hci.h>
+#include <zircon/device/serial.h>
 #include <zircon/status.h>
 
 #include <assert.h>
diff --git a/system/dev/board/astro/astro-bluetooth.c b/system/dev/board/astro/astro-bluetooth.c
index d4799f1..acaebf5 100644
--- a/system/dev/board/astro/astro-bluetooth.c
+++ b/system/dev/board/astro/astro-bluetooth.c
@@ -14,6 +14,7 @@
 #include <hw/reg.h>
 #include <soc/aml-s905d2/s905d2-gpio.h>
 #include <soc/aml-s905d2/s905d2-hw.h>
+#include <zircon/device/serial.h>
 
 #include "astro.h"
 
diff --git a/system/dev/board/vim/vim-uart.c b/system/dev/board/vim/vim-uart.c
index e47780b..9a0827e 100644
--- a/system/dev/board/vim/vim-uart.c
+++ b/system/dev/board/vim/vim-uart.c
@@ -14,6 +14,7 @@
 #include <soc/aml-s912/s912-gpio.h>
 #include <soc/aml-s912/s912-hw.h>
 #include <unistd.h>
+#include <zircon/device/serial.h>
 
 #include "vim.h"
 
diff --git a/system/dev/bus/pci/kpci.c b/system/dev/bus/pci/kpci.c
index 3fa33f5..0904eff 100644
--- a/system/dev/bus/pci/kpci.c
+++ b/system/dev/bus/pci/kpci.c
@@ -84,11 +84,11 @@
     snprintf(args, sizeof(args), "%s,%02x:%02x:%02x", req->data,
              device->info.bus_id, device->info.dev_id, device->info.func_id);
 
-    uint32_t actual;
+    size_t actual;
     pci_msg_t resp = {};
     zx_status_t st = pciroot_get_auxdata(&device->pciroot, args, resp.data, req->outlen, &actual);
     if (st == ZX_OK) {
-        resp.datalen = actual;
+        resp.datalen = (uint32_t)actual;
     }
 
     return pci_rpc_reply(ch, st, 0, req, &resp);
diff --git a/system/dev/bus/pci/proxy.c b/system/dev/bus/pci/proxy.c
index f4863f6..a0c68b5 100644
--- a/system/dev/bus/pci/proxy.c
+++ b/system/dev/bus/pci/proxy.c
@@ -242,7 +242,7 @@
     return status;
 }
 
-static zx_status_t pci_op_map_interrupt(void* ctx, int which_irq, zx_handle_t* out_handle) {
+static zx_status_t pci_op_map_interrupt(void* ctx, int32_t which_irq, zx_handle_t* out_handle) {
     if (!out_handle) {
         return ZX_ERR_INVALID_ARGS;
     }
@@ -316,7 +316,7 @@
 }
 
 static zx_status_t pci_op_get_auxdata(void* ctx, const char* args, void* data,
-                                      uint32_t bytes, uint32_t* actual) {
+                                      size_t bytes, size_t* actual) {
     kpci_device_t* dev = ctx;
     size_t arglen = strlen(args);
     if (arglen > PCI_MAX_DATA) {
diff --git a/system/dev/bus/platform/platform-bus.cpp b/system/dev/bus/platform/platform-bus.cpp
index b229e6d..eccbb7b 100644
--- a/system/dev/bus/platform/platform-bus.cpp
+++ b/system/dev/bus/platform/platform-bus.cpp
@@ -36,7 +36,8 @@
     return ZX_OK;
 }
 
-zx_status_t PlatformBus::GetBti(uint32_t iommu_index, uint32_t bti_id, zx_handle_t* out_handle) {
+zx_status_t PlatformBus::IommuGetBti(uint32_t iommu_index, uint32_t bti_id,
+                                     zx_handle_t* out_handle) {
     if (iommu_index != 0) {
         return ZX_ERR_OUT_OF_RANGE;
     }
@@ -243,7 +244,7 @@
             // return default implementation
             auto proto = static_cast<iommu_protocol_t*>(out);
             proto->ctx = this;
-            proto->ops = &iommu_proto_ops_;
+            proto->ops = &iommu_protocol_ops_;
             return ZX_OK;
         }
         break;
diff --git a/system/dev/bus/platform/platform-bus.h b/system/dev/bus/platform/platform-bus.h
index 3cb3ca1..2ad3bb7 100644
--- a/system/dev/bus/platform/platform-bus.h
+++ b/system/dev/bus/platform/platform-bus.h
@@ -54,7 +54,7 @@
     zx_status_t SetBoardInfo(const pbus_board_info_t* info);
 
     // IOMMU protocol implementation.
-    zx_status_t GetBti(uint32_t iommu_index, uint32_t bti_id, zx_handle_t* out_handle);
+    zx_status_t IommuGetBti(uint32_t iommu_index, uint32_t bti_id, zx_handle_t* out_handle);
 
     // Returns the resource handle to be used for creating MMIO regions and IRQs.
     // Currently this just returns the root resource, but we may change this to a more
diff --git a/system/dev/bus/platform/platform-device.cpp b/system/dev/bus/platform/platform-device.cpp
index 5cd9dd0..a050f09 100644
--- a/system/dev/bus/platform/platform-device.cpp
+++ b/system/dev/bus/platform/platform-device.cpp
@@ -123,7 +123,7 @@
 
     const pbus_bti_t& bti = dr->bti(index);
 
-    zx_status_t status = bus_->GetBti(bti.iommu_index, bti.bti_id, out_handle);
+    zx_status_t status = bus_->IommuGetBti(bti.iommu_index, bti.bti_id, out_handle);
 
     if (status == ZX_OK) {
         *out_handle_count = 1;
diff --git a/system/dev/bus/platform/platform-protocol-device.cpp b/system/dev/bus/platform/platform-protocol-device.cpp
index 6857e4a..dc28512 100644
--- a/system/dev/bus/platform/platform-protocol-device.cpp
+++ b/system/dev/bus/platform/platform-protocol-device.cpp
@@ -140,7 +140,7 @@
 
     const pbus_bti_t& bti = resources_.bti(index);
 
-    return bus_->GetBti(bti.iommu_index, bti.bti_id, out_handle);
+    return bus_->IommuGetBti(bti.iommu_index, bti.bti_id, out_handle);
 }
 
 zx_status_t ProtocolDevice::GetDeviceInfo(pdev_device_info_t* out_info) {
diff --git a/system/dev/bus/virtio/backends/backend.h b/system/dev/bus/virtio/backends/backend.h
index 37c02b6..939e105 100644
--- a/system/dev/bus/virtio/backends/backend.h
+++ b/system/dev/bus/virtio/backends/backend.h
@@ -4,6 +4,7 @@
 #pragma once
 
 #include <ddk/protocol/pci.h>
+#include <ddk/protocol/pci-lib.h>
 #include <fbl/mutex.h>
 #include <fbl/unique_ptr.h>
 #include <virtio/virtio.h>
diff --git a/system/dev/bus/virtio/backends/pci_modern.cpp b/system/dev/bus/virtio/backends/pci_modern.cpp
index 6b8c932..92415b3 100644
--- a/system/dev/bus/virtio/backends/pci_modern.cpp
+++ b/system/dev/bus/virtio/backends/pci_modern.cpp
@@ -94,9 +94,9 @@
     fbl::AutoLock lock(&lock_);
 
     // try to parse capabilities
-    for (uint8_t off = pci_get_first_capability(&pci_, kPciCapIdVendor);
+    for (uint8_t off = pci_get_first_capability(&pci_, PCI_CAP_ID_VENDOR);
          off != 0;
-         off = pci_get_next_capability(&pci_, off, kPciCapIdVendor)) {
+         off = pci_get_next_capability(&pci_, off, PCI_CAP_ID_VENDOR)) {
         virtio_pci_cap_t cap;
 
         ReadVirtioCap(&pci_, off, cap);
diff --git a/system/dev/bus/virtio/ethernet.cpp b/system/dev/bus/virtio/ethernet.cpp
index bacf78a..941b017 100644
--- a/system/dev/bus/virtio/ethernet.cpp
+++ b/system/dev/bus/virtio/ethernet.cpp
@@ -96,9 +96,9 @@
     eth->Stop();
 }
 
-zx_status_t virtio_net_start(void* ctx, ethmac_ifc_t* ifc, void* cookie) {
+zx_status_t virtio_net_start(void* ctx, const ethmac_ifc_t* ifc) {
     virtio::EthernetDevice* eth = static_cast<virtio::EthernetDevice*>(ctx);
-    return eth->Start(ifc, cookie);
+    return eth->Start(ifc);
 }
 
 zx_status_t virtio_net_queue_tx(void* ctx, uint32_t options, ethmac_netbuf_t* netbuf) {
@@ -106,7 +106,8 @@
     return eth->QueueTx(options, netbuf);
 }
 
-static zx_status_t virtio_set_param(void* ctx, uint32_t param, int32_t value, void* data) {
+static zx_status_t virtio_set_param(void* ctx, uint32_t param, int32_t value, const void* data,
+                                    size_t data_size) {
     return ZX_ERR_NOT_SUPPORTED;
 }
 
@@ -183,7 +184,7 @@
 
 EthernetDevice::EthernetDevice(zx_device_t* bus_device, zx::bti bti, fbl::unique_ptr<Backend> backend)
     : Device(bus_device, fbl::move(bti), fbl::move(backend)), rx_(this), tx_(this), bufs_(nullptr),
-      unkicked_(0), ifc_(nullptr), cookie_(nullptr) {
+      unkicked_(0), ifc_({nullptr, nullptr}) {
 }
 
 EthernetDevice::~EthernetDevice() {
@@ -296,7 +297,7 @@
 }
 
 void EthernetDevice::ReleaseLocked() {
-    ifc_ = nullptr;
+    ifc_.ops = nullptr;
     ReleaseBuffers(fbl::move(bufs_));
     Device::Release();
 }
@@ -306,7 +307,7 @@
     // Lock to prevent changes to ifc_.
     {
         fbl::AutoLock lock(&state_lock_);
-        if (!ifc_) {
+        if (!ifc_.ops) {
             return;
         }
         // Ring::IrqRingUpdate will call this lambda on each rx buffer filled by
@@ -325,7 +326,7 @@
             LTRACE_DO(hexdump8_ex(data, len, 0));
 
             // Pass the data up the stack to the generic Ethernet driver
-            ifc_->recv(cookie_, data, len, 0);
+            ethmac_ifc_recv(&ifc_, data, len, 0);
             assert((desc->flags & VRING_DESC_F_NEXT) == 0);
             LTRACE_DO(virtio_dump_desc(desc));
             rx_.FreeDesc(id);
@@ -352,13 +353,13 @@
 void EthernetDevice::IrqConfigChange() {
     LTRACE_ENTRY;
     fbl::AutoLock lock(&state_lock_);
-    if (!ifc_) {
+    if (!ifc_.ops) {
         return;
     }
 
     // Re-read our configuration
     CopyDeviceConfig(&config_, sizeof(config_));
-    ifc_->status(cookie_, (config_.status & VIRTIO_NET_S_LINK_UP) ? ETH_STATUS_ONLINE : 0);
+    ethmac_ifc_status(&ifc_, (config_.status & VIRTIO_NET_S_LINK_UP) ? ETH_STATUS_ONLINE : 0);
 }
 
 zx_status_t EthernetDevice::Query(uint32_t options, ethmac_info_t* info) {
@@ -378,28 +379,27 @@
 void EthernetDevice::Stop() {
     LTRACE_ENTRY;
     fbl::AutoLock lock(&state_lock_);
-    ifc_ = nullptr;
+    ifc_.ops = nullptr;
 }
 
-zx_status_t EthernetDevice::Start(ethmac_ifc_t* ifc, void* cookie) {
+zx_status_t EthernetDevice::Start(const ethmac_ifc_t* ifc) {
     LTRACE_ENTRY;
     if (!ifc) {
         return ZX_ERR_INVALID_ARGS;
     }
     fbl::AutoLock lock(&state_lock_);
-    if (!bufs_ || ifc_) {
+    if (!bufs_ || ifc_.ops) {
         return ZX_ERR_BAD_STATE;
     }
-    ifc_ = ifc;
-    cookie_ = cookie;
-    ifc_->status(cookie_, (config_.status & VIRTIO_NET_S_LINK_UP) ? ETH_STATUS_ONLINE : 0);
+    ifc_ = *ifc;
+    ethmac_ifc_status(&ifc_, (config_.status & VIRTIO_NET_S_LINK_UP) ? ETH_STATUS_ONLINE : 0);
     return ZX_OK;
 }
 
 zx_status_t EthernetDevice::QueueTx(uint32_t options, ethmac_netbuf_t* netbuf) {
     LTRACE_ENTRY;
-    void* data = netbuf->data;
-    size_t length = netbuf->len;
+    void* data = netbuf->data_buffer;
+    size_t length = netbuf->data_size;
     // First, validate the packet
     if (!data || length > virtio_hdr_len_ + kVirtioMtu) {
         LTRACEF("dropping packet; invalid packet\n");
diff --git a/system/dev/bus/virtio/ethernet.h b/system/dev/bus/virtio/ethernet.h
index 592df49..ae3e2ce 100644
--- a/system/dev/bus/virtio/ethernet.h
+++ b/system/dev/bus/virtio/ethernet.h
@@ -38,7 +38,7 @@
     // DDK protocol hooks; see ddk/protocol/ethernet.h
     zx_status_t Query(uint32_t options, ethmac_info_t* info) TA_EXCL(state_lock_);
     void Stop() TA_EXCL(state_lock_);
-    zx_status_t Start(ethmac_ifc_t* ifc, void* cookie) TA_EXCL(state_lock_);
+    zx_status_t Start(const ethmac_ifc_t* ifc) TA_EXCL(state_lock_);
     zx_status_t QueueTx(uint32_t options, ethmac_netbuf_t* netbuf) TA_EXCL(state_lock_);
 
     const char* tag() const override { return "virtio-net"; }
@@ -67,8 +67,7 @@
     size_t virtio_hdr_len_;
 
     // Ethmac callback interface; see ddk/protocol/ethernet.h
-    ethmac_ifc_t* ifc_ TA_GUARDED(state_lock_);
-    void* cookie_;
+    ethmac_ifc_t ifc_ TA_GUARDED(state_lock_);
 };
 
 } // namespace virtio
diff --git a/system/dev/bus/virtio/gpu.cpp b/system/dev/bus/virtio/gpu.cpp
index a18129e..7fbbdf9 100644
--- a/system/dev/bus/virtio/gpu.cpp
+++ b/system/dev/bus/virtio/gpu.cpp
@@ -43,13 +43,12 @@
     zx::pmt pmt;
 } imported_image_t;
 
-void GpuDevice::virtio_gpu_set_display_controller_cb(void* ctx, void* cb_ctx,
-                                                     display_controller_cb_t* cb) {
+void GpuDevice::virtio_gpu_set_display_controller_interface(
+    void* ctx, const display_controller_interface_t* intf) {
     GpuDevice* gd = static_cast<GpuDevice*>(ctx);
     {
         fbl::AutoLock al(&gd->flush_lock_);
-        gd->dc_cb_ = cb;
-        gd->dc_cb_ctx_ = cb_ctx;
+        gd->dc_intf_ = *intf;
     }
 
     added_display_args_t args = {};
@@ -60,9 +59,10 @@
         .height = gd->pmode_.r.height,
         .refresh_rate_e2 = kRefreshRateHz * 100,
     },
-    args.pixel_formats = &gd->supported_formats_,
+    args.pixel_format_list = &gd->supported_formats_,
     args.pixel_format_count = 1,
-    cb->on_displays_changed(cb_ctx, &args, 1, nullptr, 0);
+    display_controller_interface_on_displays_changed(intf, &args, 1, nullptr, 0,
+                                                     nullptr, 0, nullptr);
 }
 
 zx_status_t GpuDevice::virtio_gpu_import_vmo_image(void* ctx, image_t* image,
@@ -100,7 +100,7 @@
         return status;
     }
 
-    image->handle = import_data.release();
+    image->handle = reinterpret_cast<uint64_t>(import_data.release());
 
     return ZX_OK;
 }
@@ -109,26 +109,26 @@
     delete reinterpret_cast<imported_image_t*>(image->handle);
 }
 
-void GpuDevice::virtio_gpu_check_configuration(void* ctx,
-                                               const display_config_t** display_configs,
-                                               uint32_t* display_cfg_result,
-                                               uint32_t** layer_cfg_results,
-                                               uint32_t display_count) {
+uint32_t GpuDevice::virtio_gpu_check_configuration(void* ctx,
+                                                   const display_config_t** display_configs,
+                                                   size_t display_count,
+                                                   uint32_t** layer_cfg_results,
+                                                   size_t* layer_cfg_result_count) {
     GpuDevice* gd = static_cast<GpuDevice*>(ctx);
     if (display_count != 1) {
         ZX_DEBUG_ASSERT(display_count == 0);
-        return;
+        return CONFIG_DISPLAY_OK;
     }
     ZX_DEBUG_ASSERT(display_configs[0]->display_id == kDisplayId);
     bool success;
     if (display_configs[0]->layer_count != 1) {
         success = display_configs[0]->layer_count == 0;
     } else {
-        primary_layer_t* layer = &display_configs[0]->layers[0]->cfg.primary;
+        primary_layer_t* layer = &display_configs[0]->layer_list[0]->cfg.primary;
         frame_t frame = {
                 .x_pos = 0, .y_pos = 0, .width = gd->pmode_.r.width, .height = gd->pmode_.r.height,
         };
-        success = display_configs[0]->layers[0]->type == LAYER_PRIMARY
+        success = display_configs[0]->layer_list[0]->type == LAYER_TYPE_PRIMARY
                 && layer->transform_mode == FRAME_TRANSFORM_IDENTITY
                 && layer->image.width == gd->pmode_.r.width
                 && layer->image.height == gd->pmode_.r.height
@@ -142,14 +142,16 @@
         for (unsigned i = 1; i < display_configs[0]->layer_count; i++) {
             layer_cfg_results[0][i] = CLIENT_MERGE_SRC;
         }
+        layer_cfg_result_count[0] = display_configs[0]->layer_count;
     }
+    return CONFIG_DISPLAY_OK;
 }
 
 void GpuDevice::virtio_gpu_apply_configuration(void* ctx, const display_config_t** display_configs,
-                                               uint32_t display_count) {
+                                               size_t display_count) {
     GpuDevice* gd = static_cast<GpuDevice*>(ctx);
-    void* handle = display_count == 0 || display_configs[0]->layer_count == 0
-            ? nullptr : display_configs[0]->layers[0]->cfg.primary.image.handle;
+    uint64_t handle = display_count == 0 || display_configs[0]->layer_count == 0
+            ? 0 : display_configs[0]->layer_list[0]->cfg.primary.image.handle;
 
     {
         fbl::AutoLock al(&gd->flush_lock_);
@@ -416,10 +418,10 @@
 
         {
             fbl::AutoLock al(&flush_lock_);
-            if (dc_cb_) {
-                void* handles[] = { static_cast<void*>(displayed_fb_) };
-                dc_cb_->on_display_vsync(dc_cb_ctx_, kDisplayId,
-                                         next_deadline, handles, displayed_fb_ != nullptr);
+            if (dc_intf_.ops) {
+                uint64_t handles[] = { reinterpret_cast<uint64_t>(displayed_fb_) };
+                display_controller_interface_on_display_vsync(
+                    &dc_intf_, kDisplayId, next_deadline, handles, displayed_fb_ != nullptr);
             }
         }
         next_deadline = zx_time_add_duration(next_deadline, period);
@@ -456,7 +458,8 @@
 
     LTRACEF("publishing device\n");
 
-    display_proto_ops_.set_display_controller_cb = virtio_gpu_set_display_controller_cb;
+    display_proto_ops_.set_display_controller_interface =
+        virtio_gpu_set_display_controller_interface;
     display_proto_ops_.import_vmo_image = virtio_gpu_import_vmo_image;
     display_proto_ops_.release_image = virtio_gpu_release_image;
     display_proto_ops_.check_configuration = virtio_gpu_check_configuration;
diff --git a/system/dev/bus/virtio/gpu.h b/system/dev/bus/virtio/gpu.h
index d8b2953..2dc384e 100644
--- a/system/dev/bus/virtio/gpu.h
+++ b/system/dev/bus/virtio/gpu.h
@@ -9,6 +9,7 @@
 
 #include <ddk/protocol/display-controller.h>
 #include <fbl/unique_ptr.h>
+#include <zircon/pixelformat.h>
 #include <zircon/compiler.h>
 
 #include "device.h"
@@ -37,17 +38,16 @@
 
 private:
     // DDK driver hooks
-    static void virtio_gpu_set_display_controller_cb(
-            void* ctx, void* cb_ctx, display_controller_cb_t* cb);
+    static void virtio_gpu_set_display_controller_interface(
+            void* ctx, const display_controller_interface_t* intf);
     static zx_status_t virtio_gpu_import_vmo_image(
             void* ctx, image_t* image, zx_handle_t vmo, size_t offset);
     static void virtio_gpu_release_image(void* ctx, image_t* image);
-    static void virtio_gpu_check_configuration(
-            void* ctx, const display_config_t** display_configs,
-            uint32_t* display_cfg_result, uint32_t** layer_cfg_result,
-            uint32_t display_count);
+    static uint32_t virtio_gpu_check_configuration(
+        void* ctx, const display_config_t** display_configs, size_t display_count,
+        uint32_t** layer_cfg_results, size_t* layer_cfg_result_count);
     static void virtio_gpu_apply_configuration(
-            void* ctx, const display_config_t** display_configs, uint32_t display_count);
+            void* ctx, const display_config_t** display_configs, size_t display_count);
     static uint32_t virtio_gpu_compute_linear_stride(
             void* ctx, uint32_t width, zx_pixel_format_t format);
     static zx_status_t virtio_gpu_allocate_vmo(void* ctx, uint64_t size, zx_handle_t* vmo_out);
@@ -93,8 +93,7 @@
     cnd_t flush_cond_ = {};
     bool flush_pending_ = false;
 
-    display_controller_cb_t* dc_cb_;
-    void* dc_cb_ctx_;
+    display_controller_interface_t dc_intf_;
 
     struct imported_image* current_fb_;
     struct imported_image* displayed_fb_;
diff --git a/system/dev/bus/virtio/input.cpp b/system/dev/bus/virtio/input.cpp
index 86348ef..432dbf1 100644
--- a/system/dev/bus/virtio/input.cpp
+++ b/system/dev/bus/virtio/input.cpp
@@ -178,7 +178,7 @@
 }
 
 zx_status_t InputDevice::virtio_input_set_report(void* ctx, uint8_t rpt_type, uint8_t rpt_id,
-                                                 void* data, size_t len) {
+                                                 const void* data, size_t len) {
     return ZX_ERR_NOT_SUPPORTED;
 }
 
@@ -198,9 +198,9 @@
     return ZX_OK;
 }
 
-zx_status_t InputDevice::virtio_input_start(void* ctx, hidbus_ifc_t* ifc, void* cookie) {
+zx_status_t InputDevice::virtio_input_start(void* ctx, const hidbus_ifc_t* ifc) {
     virtio::InputDevice* inp = static_cast<virtio::InputDevice*>(ctx);
-    return inp->Start(ifc, cookie);
+    return inp->Start(ifc);
 }
 
 void InputDevice::virtio_input_stop(void* ctx) {
@@ -247,10 +247,10 @@
     // keyboard.
     if (cfg_rel_size > 0 || cfg_abs_size > 0) {
         // Pointer
-        dev_class_ = HID_DEV_CLASS_POINTER;
+        dev_class_ = HID_DEVICE_CLASS_POINTER;
     } else if (cfg_key_size > 0) {
         // Keyboard
-        dev_class_ = HID_DEV_CLASS_KBD;
+        dev_class_ = HID_DEVICE_CLASS_KBD;
     } else {
         return ZX_ERR_NOT_SUPPORTED;
     }
@@ -315,7 +315,7 @@
     hidbus_ops_.get_protocol = virtio_input_get_protocol;
     hidbus_ops_.set_protocol = virtio_input_set_protocol;
 
-    hidbus_ifc_ = nullptr;
+    hidbus_ifc_.ops = nullptr;
 
     device_add_args_t args = {};
     args.version = DEVICE_ADD_ARGS_VERSION;
@@ -337,26 +337,23 @@
     return ZX_OK;
 }
 
-zx_status_t InputDevice::Start(hidbus_ifc_t* ifc, void* cookie) {
+zx_status_t InputDevice::Start(const hidbus_ifc_t* ifc) {
     fbl::AutoLock lock(&lock_);
-    if (hidbus_ifc_ != nullptr) {
+    if (hidbus_ifc_.ops != nullptr) {
         return ZX_ERR_ALREADY_BOUND;
     }
-    hidbus_ifc_ = ifc;
-    hidbus_cookie_ = cookie;
+    hidbus_ifc_ = *ifc;
     return ZX_OK;
 }
 
 void InputDevice::Stop() {
     fbl::AutoLock lock(&lock_);
-    hidbus_ifc_ = nullptr;
-    hidbus_cookie_ = nullptr;
+    hidbus_ifc_.ops = nullptr;
 }
 
 void InputDevice::Release() {
     fbl::AutoLock lock(&lock_);
-    hidbus_ifc_ = nullptr;
-    hidbus_cookie_ = nullptr;
+    hidbus_ifc_.ops = nullptr;
     for (size_t i = 0; i < kEventCount; ++i) {
         if (io_buffer_is_valid(&buffers_[i])) {
             io_buffer_release(&buffers_[i]);
@@ -366,7 +363,7 @@
 
 zx_status_t InputDevice::Query(uint32_t options, hid_info_t* info) {
     info->dev_num = dev_class_; // Use type for dev_num for now.
-    info->dev_class = dev_class_;
+    info->device_class = dev_class_;
     info->boot_device = true;
     return ZX_OK;
 }
@@ -376,7 +373,7 @@
         return ZX_ERR_INVALID_ARGS;
     }
 
-    if (desc_type != HID_DESC_TYPE_REPORT) {
+    if (desc_type != HID_DESCRIPTION_TYPE_REPORT) {
         return ZX_ERR_NOT_FOUND;
     }
     const uint8_t* buf = nullptr;
@@ -450,10 +447,10 @@
         }
     } else if (event->type == VIRTIO_INPUT_EV_SYN) {
         fbl::AutoLock lock(&lock_);
-        if (hidbus_ifc_) {
-            hidbus_ifc_->io_queue(hidbus_cookie_,
-                                  reinterpret_cast<const uint8_t*>(&report_),
-                                  sizeof(report_));
+        if (hidbus_ifc_.ops) {
+            hidbus_ifc_io_queue(&hidbus_ifc_,
+                                reinterpret_cast<const uint8_t*>(&report_),
+                                sizeof(report_));
         }
     }
 }
diff --git a/system/dev/bus/virtio/input.h b/system/dev/bus/virtio/input.h
index cbca217..bdcf8fe 100644
--- a/system/dev/bus/virtio/input.h
+++ b/system/dev/bus/virtio/input.h
@@ -32,20 +32,20 @@
     static void virtio_input_release(void* ctx);
 
     static zx_status_t virtio_input_query(void* ctx, uint32_t options, hid_info_t* info);
-    static zx_status_t virtio_input_start(void* ctx, hidbus_ifc_t* ifc, void* cookie);
+    static zx_status_t virtio_input_start(void* ctx, const hidbus_ifc_t* ifc);
     static void virtio_input_stop(void* ctx);
     static zx_status_t virtio_input_get_descriptor(void* ctx, uint8_t desc_type,
                                                    void** data, size_t* len);
     static zx_status_t virtio_input_get_report(void* ctx, uint8_t rpt_type, uint8_t rpt_id,
                                                void* data, size_t len, size_t* out_len);
     static zx_status_t virtio_input_set_report(void* ctx, uint8_t rpt_type, uint8_t rpt_id,
-                                               void* data, size_t len);
+                                               const void* data, size_t len);
     static zx_status_t virtio_input_get_idle(void* ctx, uint8_t rpt_type, uint8_t* duration);
     static zx_status_t virtio_input_set_idle(void* ctx, uint8_t rpt_type, uint8_t duration);
     static zx_status_t virtio_input_get_protocol(void* ctx, uint8_t* protocol);
     static zx_status_t virtio_input_set_protocol(void* ctx, uint8_t protocol);
 
-    zx_status_t Start(hidbus_ifc_t* ifc, void* cookie);
+    zx_status_t Start(const hidbus_ifc_t* ifc);
     void Stop();
     zx_status_t Query(uint32_t options, hid_info_t* info);
     zx_status_t GetDescriptor(uint8_t desc_type, void** data, size_t* len);
@@ -65,7 +65,7 @@
 
     uint8_t dev_class_;
     hidbus_protocol_ops_t hidbus_ops_;
-    hidbus_ifc_t* hidbus_ifc_;
+    hidbus_ifc_t hidbus_ifc_;
     void* hidbus_cookie_;
 
     boot_kbd_report_t report_;
diff --git a/system/dev/bus/virtio/virtio_driver.cpp b/system/dev/bus/virtio/virtio_driver.cpp
index 20b8f59..a7d7f96 100644
--- a/system/dev/bus/virtio/virtio_driver.cpp
+++ b/system/dev/bus/virtio/virtio_driver.cpp
@@ -16,6 +16,7 @@
 #include <fbl/unique_ptr.h>
 
 #include <zircon/compiler.h>
+#include <zircon/pixelformat.h>
 #include <zircon/types.h>
 
 #include "backends/pci.h"
@@ -53,7 +54,7 @@
     // If no vendor capabilities are found then we will default to the legacy
     // interface.
     fbl::unique_ptr<virtio::Backend> backend = nullptr;
-    if (pci_get_first_capability(&pci, kPciCapIdVendor) != 0) {
+    if (pci_get_first_capability(&pci, PCI_CAP_ID_VENDOR) != 0) {
         zxlogf(SPEW, "virtio %02x:%02x.%1x using modern PCI backend\n", info.bus_id, info.dev_id, info.func_id);
         backend.reset(new virtio::PciModernBackend(pci, info));
     } else {
diff --git a/system/dev/display/aml-canvas/aml-canvas-proxy-client.c b/system/dev/display/aml-canvas/aml-canvas-proxy-client.c
index dea38ad..c6e8a83 100644
--- a/system/dev/display/aml-canvas/aml-canvas-proxy-client.c
+++ b/system/dev/display/aml-canvas/aml-canvas-proxy-client.c
@@ -23,7 +23,7 @@
 #include "aml-canvas.h"
 
 static zx_status_t aml_canvas_proxy_config(void* ctx, zx_handle_t vmo,
-                                           size_t offset, canvas_info_t* info,
+                                           size_t offset, const canvas_info_t* info,
                                            uint8_t* canvas_idx) {
     aml_canvas_proxy_t* proxy = ctx;
     rpc_canvas_req_t req = {
diff --git a/system/dev/display/aml-canvas/aml-canvas.c b/system/dev/display/aml-canvas/aml-canvas.c
index 4b8cff5..12a4669 100644
--- a/system/dev/display/aml-canvas/aml-canvas.c
+++ b/system/dev/display/aml-canvas/aml-canvas.c
@@ -34,7 +34,7 @@
 }
 
 static zx_status_t aml_canvas_config(void* ctx, zx_handle_t vmo,
-                                     size_t offset, canvas_info_t* info,
+                                     size_t offset, const canvas_info_t* info,
                                      uint8_t* canvas_idx) {
     aml_canvas_t* canvas = ctx;
     zx_status_t status = ZX_OK;
diff --git a/system/dev/display/astro-display/astro-display.cpp b/system/dev/display/astro-display/astro-display.cpp
index ad36288..eff8dcc 100644
--- a/system/dev/display/astro-display/astro-display.cpp
+++ b/system/dev/display/astro-display/astro-display.cpp
@@ -8,7 +8,7 @@
 
 namespace {
 // List of supported pixel formats
-const zx_pixel_format_t kSupportedPixelFormats = { ZX_PIXEL_FORMAT_RGB_x888 };
+zx_pixel_format_t kSupportedPixelFormats[] = { ZX_PIXEL_FORMAT_RGB_x888 };
 
 constexpr uint64_t kDisplayId = PANEL_DISPLAY_ID;
 
@@ -75,30 +75,32 @@
     args->panel.params.height = height_;
     args->panel.params.width = width_;
     args->panel.params.refresh_rate_e2 = 3000; // Just guess that it's 30fps
-    args->pixel_formats = &kSupportedPixelFormats;
-    args->pixel_format_count = sizeof(kSupportedPixelFormats) / sizeof(zx_pixel_format_t);
+    args->pixel_format_list = kSupportedPixelFormats;
+    args->pixel_format_count = countof(kSupportedPixelFormats);
     args->cursor_info_count = 0;
 }
 
 // part of ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL ops
-uint32_t AstroDisplay::ComputeLinearStride(uint32_t width, zx_pixel_format_t format) {
+uint32_t AstroDisplay::DisplayControllerComputeLinearStride(uint32_t width,
+                                                            zx_pixel_format_t format) {
     // The astro display controller needs buffers with a stride that is an even
     // multiple of 32.
     return ROUNDUP(width, 32 / ZX_PIXEL_FORMAT_BYTES(format));
 }
 
 // part of ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL ops
-void AstroDisplay::SetDisplayControllerCb(void* cb_ctx, display_controller_cb_t* cb) {
+void AstroDisplay::DisplayControllerSetDisplayControllerInterface(
+    const display_controller_interface_t* intf) {
     fbl::AutoLock lock(&display_lock_);
-    dc_cb_ = cb;
-    dc_cb_ctx_ = cb_ctx;
+    dc_intf_ = ddk::DisplayControllerInterfaceProxy(intf);
     added_display_args_t args;
     PopulateAddedDisplayArgs(&args);
-    dc_cb_->on_displays_changed(dc_cb_ctx_, &args, 1, NULL, 0);
+    dc_intf_.OnDisplaysChanged(&args, 1, nullptr, 0, nullptr, 0, nullptr);
 }
 
 // part of ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL ops
-zx_status_t AstroDisplay::ImportVmoImage(image_t* image, const zx::vmo& vmo, size_t offset) {
+zx_status_t AstroDisplay::DisplayControllerImportVmoImage(image_t* image, zx_handle_t vmo,
+                                                          size_t offset) {
     zx_status_t status = ZX_OK;
     fbl::AutoLock lock(&image_lock_);
 
@@ -107,7 +109,7 @@
         return status;
     }
 
-    uint32_t stride = ComputeLinearStride(image->width, image->pixel_format);
+    uint32_t stride = DisplayControllerComputeLinearStride(image->width, image->pixel_format);
 
     canvas_info_t canvas_info;
     canvas_info.height          = image->height;
@@ -117,7 +119,7 @@
     canvas_info.endianness      = 0;
 
     zx_handle_t dup_vmo;
-    status = zx_handle_duplicate(vmo.get(), ZX_RIGHT_SAME_RIGHTS, &dup_vmo);
+    status = zx_handle_duplicate(vmo, ZX_RIGHT_SAME_RIGHTS, &dup_vmo);
     if (status != ZX_OK) {
         return status;
     }
@@ -134,13 +136,13 @@
         DISP_INFO("Reusing previously allocated canvas (index = %d)\n", local_canvas_idx);
     }
     imported_images_.SetOne(local_canvas_idx);
-    image->handle = reinterpret_cast<void*>(local_canvas_idx);;
+    image->handle = local_canvas_idx;
 
     return status;
 }
 
 // part of ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL ops
-void AstroDisplay::ReleaseImage(image_t* image) {
+void AstroDisplay::DisplayControllerReleaseImage(image_t* image) {
     fbl::AutoLock lock(&image_lock_);
     size_t local_canvas_idx = (size_t)image->handle;
     if (imported_images_.GetOne(local_canvas_idx)) {
@@ -150,14 +152,13 @@
 }
 
 // part of ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL ops
-void AstroDisplay::CheckConfiguration(const display_config_t** display_configs,
-                                      uint32_t* display_cfg_result,
-                                      uint32_t** layer_cfg_results,
-                                      uint32_t display_count) {
-    *display_cfg_result = CONFIG_DISPLAY_OK;
+uint32_t AstroDisplay::DisplayControllerCheckConfiguration(
+    const display_config_t** display_configs, size_t display_count, uint32_t** layer_cfg_results,
+    size_t* layer_cfg_result_count) {
+
     if (display_count != 1) {
         ZX_DEBUG_ASSERT(display_count == 0);
-        return;
+        return CONFIG_DISPLAY_OK;
     }
     ZX_DEBUG_ASSERT(display_configs[0]->display_id == PANEL_DISPLAY_ID);
 
@@ -167,11 +168,11 @@
     if (display_configs[0]->layer_count != 1) {
         success = display_configs[0]->layer_count == 0;
     } else {
-        const primary_layer_t& layer = display_configs[0]->layers[0]->cfg.primary;
+        const primary_layer_t& layer = display_configs[0]->layer_list[0]->cfg.primary;
         frame_t frame = {
             .x_pos = 0, .y_pos = 0, .width = width_, .height = height_,
         };
-        success = display_configs[0]->layers[0]->type == LAYER_PRIMARY
+        success = display_configs[0]->layer_list[0]->type == LAYER_TYPE_PRIMARY
                 && layer.transform_mode == FRAME_TRANSFORM_IDENTITY
                 && layer.image.width == width_
                 && layer.image.height == height_
@@ -185,12 +186,14 @@
         for (unsigned i = 1; i < display_configs[0]->layer_count; i++) {
             layer_cfg_results[0][i] = CLIENT_MERGE_SRC;
         }
+        layer_cfg_result_count[0] = display_configs[0]->layer_count;
     }
+    return CONFIG_DISPLAY_OK;
 }
 
 // part of ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL ops
-void AstroDisplay::ApplyConfiguration(const display_config_t** display_configs,
-                                      uint32_t display_count) {
+void AstroDisplay::DisplayControllerApplyConfiguration( const display_config_t** display_configs,
+                                                        size_t display_count) {
     ZX_DEBUG_ASSERT(display_configs);
 
     fbl::AutoLock lock(&display_lock_);
@@ -199,7 +202,7 @@
     if (display_count == 1 && display_configs[0]->layer_count) {
         // Since Astro does not support plug'n play (fixed display), there is no way
         // a checked configuration could be invalid at this point.
-        addr = (uint8_t) (uint64_t) display_configs[0]->layers[0]->cfg.primary.image.handle;
+        addr = (uint8_t) (uint64_t) display_configs[0]->layer_list[0]->cfg.primary.image.handle;
         current_image_valid_= true;
         current_image_ = addr;
         osd_->Flip(addr);
@@ -210,7 +213,7 @@
 }
 
 // part of ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL ops
-zx_status_t AstroDisplay::AllocateVmo(uint64_t size, zx_handle_t* vmo_out) {
+zx_status_t AstroDisplay::DisplayControllerAllocateVmo(uint64_t size, zx_handle_t* vmo_out) {
     return zx_vmo_create_contiguous(bti_.get(), size, 0, vmo_out);
 }
 
@@ -274,7 +277,7 @@
     }
 
     format_ = ZX_PIXEL_FORMAT_RGB_x888;
-    stride_ = ComputeLinearStride(width_, format_);
+    stride_ = DisplayControllerComputeLinearStride(width_, format_);
 
     if (!skip_disp_init_) {
         // Ensure Max Bit Rate / pixel clock ~= 8 (8.xxx). This is because the clock calculation
@@ -363,10 +366,10 @@
         imported_images_.Reset(kMaxImportedImages);
     }
 
-    if (dc_cb_) {
+    if (dc_intf_.is_valid()) {
         added_display_args_t args;
         PopulateAddedDisplayArgs(&args);
-        dc_cb_->on_displays_changed(dc_cb_ctx_, &args, 1,nullptr, 0);
+        dc_intf_.OnDisplaysChanged(&args, 1, nullptr, 0, nullptr, 0, nullptr);
     }
 
     return ZX_OK;
@@ -381,11 +384,11 @@
             break;
         }
         fbl::AutoLock lock(&display_lock_);
-        void* live = reinterpret_cast<void*>(current_image_);
+        uint64_t live[] = { current_image_ };
         bool current_image_valid = current_image_valid_;
-        if (dc_cb_) {
-            dc_cb_->on_display_vsync(dc_cb_ctx_, kDisplayId, zx_clock_get(ZX_CLOCK_MONOTONIC),
-                                             &live, current_image_valid);
+        if (dc_intf_.is_valid()) {
+            dc_intf_.OnDisplayVsync(kDisplayId, zx_clock_get(ZX_CLOCK_MONOTONIC),
+                                    live, current_image_valid);
         }
     }
 
diff --git a/system/dev/display/astro-display/astro-display.h b/system/dev/display/astro-display/astro-display.h
index a28b5ea..d846f53 100644
--- a/system/dev/display/astro-display/astro-display.h
+++ b/system/dev/display/astro-display/astro-display.h
@@ -7,6 +7,7 @@
 #include <unistd.h>
 
 #include <zircon/compiler.h>
+#include <zircon/pixelformat.h>
 #include <zircon/thread_annotations.h>
 #include <lib/zx/interrupt.h>
 #include <lib/zx/bti.h>
@@ -18,6 +19,7 @@
 #include <ddk/debug.h>
 
 #include <ddktl/protocol/display-controller.h>
+#include <ddktl/protocol/empty-protocol.h>
 #include <ddktl/device.h>
 
 #include <fbl/unique_ptr.h>
@@ -44,7 +46,8 @@
 using DeviceType = ddk::Device<AstroDisplay, ddk::Unbindable>;
 
 class AstroDisplay : public DeviceType,
-                     public ddk::DisplayControllerProtocol<AstroDisplay> {
+                     public ddk::DisplayControllerProtocol<AstroDisplay>,
+                     public ddk::EmptyProtocol<ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL> {
 public:
     AstroDisplay(zx_device_t* parent, uint32_t width, uint32_t height)
         : DeviceType(parent), width_(width), height_(height) {}
@@ -53,15 +56,16 @@
     zx_status_t Bind();
 
     // Required functions needed to implement Display Controller Protocol
-    void SetDisplayControllerCb(void* cb_ctx, display_controller_cb_t* cb);
-    zx_status_t ImportVmoImage(image_t* image, const zx::vmo& vmo, size_t offset);
-    void ReleaseImage(image_t* image);
-    void CheckConfiguration(const display_config_t** display_config,
-                            uint32_t* display_cfg_result, uint32_t** layer_cfg_result,
-                            uint32_t display_count);
-    void ApplyConfiguration(const display_config_t** display_config, uint32_t display_count);
-    uint32_t ComputeLinearStride(uint32_t width, zx_pixel_format_t format);
-    zx_status_t AllocateVmo(uint64_t size, zx_handle_t* vmo_out);
+    void DisplayControllerSetDisplayControllerInterface(const display_controller_interface_t* intf);
+    zx_status_t DisplayControllerImportVmoImage(image_t* image, zx_handle_t vmo, size_t offset);
+    void DisplayControllerReleaseImage(image_t* image);
+    uint32_t DisplayControllerCheckConfiguration(const display_config_t** display_configs,
+                                                 size_t display_count, uint32_t** layer_cfg_results,
+                                                 size_t* layer_cfg_result_count);
+    void DisplayControllerApplyConfiguration(const display_config_t** display_config,
+                                             size_t display_count);
+    uint32_t DisplayControllerComputeLinearStride(uint32_t width, zx_pixel_format_t format);
+    zx_status_t DisplayControllerAllocateVmo(uint64_t size, zx_handle_t* vmo_out);
 
     // Required functions for DeviceType
     void DdkUnbind();
@@ -124,11 +128,10 @@
     DisplaySetting                      disp_setting_;
 
     // Display controller related data
-    display_controller_cb_t*            dc_cb_ TA_GUARDED(display_lock_);
-    void*                               dc_cb_ctx_ TA_GUARDED(display_lock_);
+    ddk::DisplayControllerInterfaceProxy dc_intf_ TA_GUARDED(display_lock_);
 
     // Simple hashtable
-    ImportedImageBitmap                imported_images_ TA_GUARDED(image_lock_);;
+    ImportedImageBitmap                  imported_images_ TA_GUARDED(image_lock_);;
 
     // Objects
     fbl::unique_ptr<astro_display::Osd>                 osd_;
diff --git a/system/dev/display/display/client.cpp b/system/dev/display/display/client.cpp
index f9a2e77..c95a5c9 100644
--- a/system/dev/display/display/client.cpp
+++ b/system/dev/display/display/client.cpp
@@ -10,11 +10,11 @@
 #include <lib/fidl/cpp/message.h>
 #include <lib/async/cpp/task.h>
 #include <math.h>
+#include <zircon/pixelformat.h>
 #include <zircon/device/display-controller.h>
 
 #include "client.h"
 
-#define DC_IMPL_CALL(fn, ...) controller_->ops()->fn(controller_->ops_ctx(), __VA_ARGS__)
 #define SELECT_TABLE_CASE(NAME) case NAME ## Ordinal: table = &NAME ## RequestTable; break
 #define HANDLE_REQUEST_CASE(NAME) \
     case fuchsia_display_Controller ## NAME ## Ordinal: { \
@@ -211,13 +211,13 @@
         dc_image.planes[i].bytes_per_row = req->image_config.planes[i].bytes_per_row;
     }
 
-    resp->res = DC_IMPL_CALL(import_vmo_image, &dc_image, vmo.get(), req->offset);
+    resp->res = controller_->dc()->ImportVmoImage(&dc_image, vmo.get(), req->offset);
 
     if (resp->res == ZX_OK) {
         fbl::AllocChecker ac;
         auto image = fbl::AdoptRef(new (&ac) Image(controller_, dc_image, fbl::move(vmo)));
         if (!ac.check()) {
-            DC_IMPL_CALL(release_image, &dc_image);
+            controller_->dc()->ReleaseImage(&dc_image);
 
             resp->res = ZX_ERR_NO_MEMORY;
             return;
@@ -434,7 +434,7 @@
         return;
     }
 
-    layer->pending_layer_.type = LAYER_PRIMARY;
+    layer->pending_layer_.type = LAYER_TYPE_PRIMARY;
     primary_layer_t* primary_layer = &layer->pending_layer_.cfg.primary;
 
     populate_image(req->image_config, &primary_layer->image);
@@ -459,7 +459,7 @@
         const fuchsia_display_ControllerSetLayerPrimaryPositionRequest* req,
         fidl::Builder* resp_builder, const fidl_type_t** resp_table) {
     auto layer = layers_.find(req->layer_id);
-    if (!layer.IsValid() || layer->pending_layer_.type != LAYER_PRIMARY) {
+    if (!layer.IsValid() || layer->pending_layer_.type != LAYER_TYPE_PRIMARY) {
         zxlogf(ERROR, "SetLayerPrimaryPosition on invalid layer\n");
         TearDown();
         return;
@@ -493,7 +493,7 @@
         const fuchsia_display_ControllerSetLayerPrimaryAlphaRequest* req,
         fidl::Builder* resp_builder, const fidl_type_t** resp_table) {
     auto layer = layers_.find(req->layer_id);
-    if (!layer.IsValid() || layer->pending_layer_.type != LAYER_PRIMARY) {
+    if (!layer.IsValid() || layer->pending_layer_.type != LAYER_TYPE_PRIMARY) {
         zxlogf(ERROR, "SetLayerPrimaryAlpha on invalid layer\n");
         TearDown();
         return;
@@ -529,7 +529,7 @@
         return;
     }
 
-    layer->pending_layer_.type = LAYER_CURSOR;
+    layer->pending_layer_.type = LAYER_TYPE_CURSOR;
     layer->pending_cursor_x_ = layer->pending_cursor_y_ = 0;
 
 
@@ -546,7 +546,7 @@
         const fuchsia_display_ControllerSetLayerCursorPositionRequest* req,
         fidl::Builder* resp_builder, const fidl_type_t** resp_table) {
     auto layer = layers_.find(req->layer_id);
-    if (!layer.IsValid() || layer->pending_layer_.type != LAYER_CURSOR) {
+    if (!layer.IsValid() || layer->pending_layer_.type != LAYER_TYPE_CURSOR) {
         zxlogf(ERROR, "SetLayerCursorPosition on invalid layer\n");
         TearDown();
         return;
@@ -575,7 +575,7 @@
     // Increase the size of the static array when large color formats are introduced
     ZX_ASSERT(req->color_bytes.count <= sizeof(layer->pending_color_bytes_));
 
-    layer->pending_layer_.type = LAYER_COLOR;
+    layer->pending_layer_.type = LAYER_TYPE_COLOR;
     color_layer_t* color_layer = &layer->pending_layer_.cfg.color;
 
     color_layer->format = req->pixel_format;
@@ -589,7 +589,7 @@
 void Client::HandleSetLayerImage(const fuchsia_display_ControllerSetLayerImageRequest* req,
                                  fidl::Builder* resp_builder, const fidl_type_t** resp_table) {
     auto layer = layers_.find(req->layer_id);
-    if (!layer.IsValid() || layer->pending_layer_.type == LAYER_COLOR) {
+    if (!layer.IsValid() || layer->pending_layer_.type == LAYER_TYPE_COLOR) {
         zxlogf(ERROR, "SetLayerImage ordinal with invalid layer\n");
         TearDown();
         return;
@@ -601,9 +601,9 @@
         return;
     }
     // Only primary or cursor layers can have images
-    ZX_ASSERT(layer->pending_layer_.type == LAYER_PRIMARY
-            || layer->pending_layer_.type == LAYER_CURSOR);
-    image_t* cur_image = layer->pending_layer_.type == LAYER_PRIMARY ?
+    ZX_ASSERT(layer->pending_layer_.type == LAYER_TYPE_PRIMARY
+            || layer->pending_layer_.type == LAYER_TYPE_CURSOR);
+    image_t* cur_image = layer->pending_layer_.type == LAYER_TYPE_PRIMARY ?
             &layer->pending_layer_.cfg.primary.image : &layer->pending_layer_.cfg.cursor.image;
     if (!image->HasSameConfig(*cur_image)) {
         zxlogf(ERROR, "SetLayerImage with mismatch layer config\n");
@@ -769,9 +769,9 @@
                 layer->config_change_ = false;
 
                 image_t* new_image_config = nullptr;
-                if (layer->current_layer_.type == LAYER_PRIMARY) {
+                if (layer->current_layer_.type == LAYER_TYPE_PRIMARY) {
                     new_image_config = &layer->current_layer_.cfg.primary.image;
-                } else if (layer->current_layer_.type == LAYER_CURSOR) {
+                } else if (layer->current_layer_.type == LAYER_TYPE_CURSOR) {
                     new_image_config = &layer->current_layer_.cfg.cursor.image;
 
                     layer->current_cursor_x_ = layer->pending_cursor_x_;
@@ -786,10 +786,11 @@
                             fbl::clamp(layer->current_cursor_y_,
                                        -static_cast<int32_t>(new_image_config->height) + 1,
                                        static_cast<int32_t>(mode->v_addressable) - 1);
-                } else if (layer->current_layer_.type == LAYER_COLOR) {
+                } else if (layer->current_layer_.type == LAYER_TYPE_COLOR) {
                     memcpy(layer->current_color_bytes_, layer->pending_color_bytes_,
                            sizeof(layer->current_color_bytes_));
-                    layer->current_layer_.cfg.color.color = layer->current_color_bytes_;
+                    layer->current_layer_.cfg.color.color_list = layer->current_color_bytes_;
+                    layer->current_layer_.cfg.color.color_count = 4;
                 } else {
                     // type is validated in ::CheckConfig, so something must be very wrong.
                     ZX_ASSERT(false);
@@ -829,7 +830,7 @@
         fidl::Builder* resp_builder, const fidl_type_t** resp_table) {
     auto resp = resp_builder->New<fuchsia_display_ControllerComputeLinearImageStrideResponse>();
     *resp_table = &fuchsia_display_ControllerComputeLinearImageStrideResponseTable;
-    resp->stride = DC_IMPL_CALL(compute_linear_stride, req->width, req->pixel_format);
+    resp->stride = controller_->dc()->ComputeLinearStride(req->width, req->pixel_format);
 }
 
 void Client::HandleAllocateVmo(const fuchsia_display_ControllerAllocateVmoRequest* req,
@@ -839,7 +840,7 @@
     auto resp = resp_builder->New<fuchsia_display_ControllerAllocateVmoResponse>();
     *resp_table = &fuchsia_display_ControllerAllocateVmoResponseTable;
 
-    resp->res = DC_IMPL_CALL(allocate_vmo, req->size, handle_out);
+    resp->res = controller_->dc()->AllocateVmo(req->size, handle_out);
     *has_handle_out = resp->res == ZX_OK;
     resp->vmo = *has_handle_out ? FIDL_HANDLE_PRESENT : FIDL_HANDLE_ABSENT;
 }
@@ -874,7 +875,7 @@
         display_layer_cfg_results[config_idx++] = layer_cfg_results + layer_idx;
 
         // Create this display's compact layer_t* array
-        display_config.pending_.layers = layers + layer_idx;
+        display_config.pending_.layer_list = layers + layer_idx;
 
         // Frame used for checking that each layer's dest_frame lies entirely
         // within the composed output.
@@ -891,7 +892,7 @@
             layers[layer_idx++] = &layer_node.layer->pending_layer_;
 
             bool invalid = false;
-            if (layer_node.layer->pending_layer_.type == LAYER_PRIMARY) {
+            if (layer_node.layer->pending_layer_.type == LAYER_TYPE_PRIMARY) {
                 primary_layer_t* layer = &layer_node.layer->pending_layer_.cfg.primary;
                 // Frame for checking that the layer's src_frame lies entirely
                 // within the source image.
@@ -901,13 +902,14 @@
                 };
                 invalid = (!frame_contains(image_frame, layer->src_frame)
                         || !frame_contains(display_frame, layer->dest_frame));
-            } else if (layer_node.layer->pending_layer_.type == LAYER_CURSOR) {
+            } else if (layer_node.layer->pending_layer_.type == LAYER_TYPE_CURSOR) {
                 // The image is already set, so nothing to do here, and there's
                 // nothing that could make this invald.
-            } else if (layer_node.layer->pending_layer_.type == LAYER_COLOR) {
+            } else if (layer_node.layer->pending_layer_.type == LAYER_TYPE_COLOR) {
                 // There aren't any API constraints on valid colors.
-                layer_node.layer->pending_layer_.cfg.color.color =
+                layer_node.layer->pending_layer_.cfg.color.color_list =
                         layer_node.layer->pending_color_bytes_;
+                layer_node.layer->pending_layer_.cfg.color.color_count = 4;
             } else {
                 invalid = true;
             }
@@ -928,9 +930,10 @@
         return false;
     }
 
-    uint32_t display_cfg_result = CONFIG_DISPLAY_OK;
-    DC_IMPL_CALL(check_configuration, configs, &display_cfg_result,
-                 display_layer_cfg_results, config_idx);
+    size_t layer_cfg_results_count;
+    uint32_t display_cfg_result =
+        controller_->dc()->CheckConfiguration(configs, config_idx, display_layer_cfg_results,
+                                              &layer_cfg_results_count);
 
     if (display_cfg_result != CONFIG_DISPLAY_OK) {
         if (resp) {
@@ -1020,7 +1023,7 @@
     int layer_idx = 0;
     for (auto& display_config : configs_) {
         display_config.current_.layer_count = 0;
-        display_config.current_.layers = layers + layer_idx;
+        display_config.current_.layer_list = layers + layer_idx;
         display_config.vsync_layer_count_ = 0;
 
         // Displays with no current layers are filtered out in Controller::ApplyConfig,
@@ -1049,10 +1052,10 @@
                 layer->displayed_image_ = fbl::move(node->self);
                 list_remove_head(&layer->waiting_images_);
 
-                void* handle = layer->displayed_image_->info().handle;
-                if (layer->current_layer_.type == LAYER_PRIMARY) {
+                uint64_t handle = layer->displayed_image_->info().handle;
+                if (layer->current_layer_.type == LAYER_TYPE_PRIMARY) {
                     layer->current_layer_.cfg.primary.image.handle = handle;
-                } else if (layer->current_layer_.type == LAYER_CURSOR) {
+                } else if (layer->current_layer_.type == LAYER_TYPE_CURSOR) {
                     layer->current_layer_.cfg.cursor.image.handle = handle;
                 } else {
                     // type is validated in ::CheckConfig, so something must be very wrong.
@@ -1069,8 +1072,8 @@
                     console_fb_display_id_ = display_config.id;
 
                     auto fb = layer->displayed_image_;
-                    uint32_t stride = DC_IMPL_CALL(compute_linear_stride,
-                                                   fb->info().width, fb->info().pixel_format);
+                    uint32_t stride = controller_->dc()->ComputeLinearStride(
+                        fb->info().width, fb->info().pixel_format);
                     uint32_t size = fb->info().height *
                             ZX_PIXEL_FORMAT_BYTES(fb->info().pixel_format) * stride;
                     zx_framebuffer_set_range(get_root_resource(),
@@ -1087,7 +1090,7 @@
 
             display_config.current_.layer_count++;
             layers[layer_idx++] = &layer->current_layer_;
-            if (layer->current_layer_.type != LAYER_COLOR) {
+            if (layer->current_layer_.type != LAYER_TYPE_COLOR) {
                 display_config.vsync_layer_count_++;
                 if (layer->displayed_image_ == nullptr) {
                     config_missing_image = true;
@@ -1123,8 +1126,8 @@
     ApplyConfig();
 }
 
-void Client::OnDisplaysChanged(const uint64_t* displays_added, uint32_t added_count,
-                               const uint64_t* displays_removed, uint32_t removed_count) {
+void Client::OnDisplaysChanged(const uint64_t* displays_added, size_t added_count,
+                               const uint64_t* displays_removed, size_t removed_count) {
     ZX_DEBUG_ASSERT(controller_->current_thread_is_loop());
     ZX_DEBUG_ASSERT(mtx_trylock(controller_->mtx()) == thrd_busy);
 
@@ -1177,7 +1180,7 @@
         req->added.count++;
 
         config->current_.display_id = config->id;
-        config->current_.layers = nullptr;
+        config->current_.layer_list = nullptr;
         config->current_.layer_count = 0;
 
         if (edid_timings) {
@@ -1443,8 +1446,8 @@
 }
 
 void ClientProxy::OnDisplaysChanged(const uint64_t* displays_added,
-                                    uint32_t added_count, const uint64_t* displays_removed,
-                                    uint32_t removed_count) {
+                                    size_t added_count, const uint64_t* displays_removed,
+                                    size_t removed_count) {
     handler_.OnDisplaysChanged(displays_added, added_count, displays_removed, removed_count);
 }
 
@@ -1469,7 +1472,7 @@
 }
 
 void ClientProxy::OnDisplayVsync(uint64_t display_id, zx_time_t timestamp,
-                                 uint64_t* image_ids, uint32_t count) {
+                                 uint64_t* image_ids, size_t count) {
     ZX_DEBUG_ASSERT(mtx_trylock(controller_->mtx()) == thrd_busy);
 
     if (!enable_vsync_) {
diff --git a/system/dev/display/display/client.h b/system/dev/display/display/client.h
index 5a05ba6..42a6d4b 100644
--- a/system/dev/display/display/client.h
+++ b/system/dev/display/display/client.h
@@ -130,9 +130,9 @@
     zx_status_t Init(zx_handle_t server_handle);
 
     void OnDisplaysChanged(const uint64_t* displays_added,
-                           uint32_t added_count,
+                           size_t added_count,
                            const uint64_t* displays_removed,
-                           uint32_t removed_count);
+                          size_t removed_count);
     void SetOwnership(bool is_owner);
     void ApplyConfig();
 
@@ -255,9 +255,9 @@
 
     // Requires holding controller_->mtx() lock
     void OnDisplayVsync(uint64_t display_id, zx_time_t timestamp,
-                        uint64_t* image_ids, uint32_t count);
-    void OnDisplaysChanged(const uint64_t* displays_added, uint32_t added_count,
-                           const uint64_t* displays_removed, uint32_t removed_count);
+                        uint64_t* image_ids, size_t count);
+    void OnDisplaysChanged(const uint64_t* displays_added, size_t added_count,
+                           const uint64_t* displays_removed, size_t removed_count);
     void SetOwnership(bool is_owner);
     void ReapplyConfig();
 
diff --git a/system/dev/display/display/controller.cpp b/system/dev/display/display/controller.cpp
index d74059c..ef550cc 100644
--- a/system/dev/display/display/controller.cpp
+++ b/system/dev/display/display/controller.cpp
@@ -14,29 +14,6 @@
 
 namespace {
 
-void on_displays_changed(void* ctx, added_display_args_t* displays_added, uint32_t added_count,
-                         uint64_t* displays_removed, uint32_t removed_count) {
-    static_cast<display::Controller*>(ctx)->OnDisplaysChanged(
-            displays_added, added_count, displays_removed, removed_count);
-}
-
-void on_display_vsync(void* ctx, uint64_t display, zx_time_t timestamp,
-                      void** handles, uint32_t handle_count) {
-    static_cast<display::Controller*>(ctx)->OnDisplayVsync(display, timestamp,
-                                                           handles, handle_count);
-}
-
-zx_status_t get_audio_format(void* ctx, uint64_t display_id, uint32_t fmt_idx,
-                             audio_stream_format_range_t* fmt_out) {
-    return static_cast<display::Controller*>(ctx)->GetAudioFormat(display_id, fmt_idx, fmt_out);
-}
-
-display_controller_cb_t dc_cb = {
-    .on_displays_changed = on_displays_changed,
-    .on_display_vsync = on_display_vsync,
-    .get_audio_format = get_audio_format,
-};
-
 typedef struct i2c_bus {
     i2c_impl_protocol_t* i2c;
     uint32_t bus_id;
@@ -89,14 +66,12 @@
     // Go through all the display mode timings and record whether or not
     // a basic layer configuration is acceptable.
     layer_t test_layer = {};
-    layer_t* test_layers[] = { &test_layer };
-    test_layer.cfg.primary.image.pixel_format = info->pixel_formats_[0];
-
+    layer_t* test_layers[] = { &test_layer }; test_layer.cfg.primary.image.pixel_format = info->pixel_formats_[0]; 
     display_config_t test_config;
     const display_config_t* test_configs[] = { &test_config };
     test_config.display_id = info->id;
     test_config.layer_count = 1;
-    test_config.layers = test_layers;
+    test_config.layer_list = test_layers;
 
     for (auto timing = edid::timing_iterator(&info->edid); timing.is_valid(); ++timing) {
         uint32_t width = timing->horizontal_addressable;
@@ -121,9 +96,10 @@
 
             uint32_t display_cfg_result;
             uint32_t layer_result = 0;
+            size_t display_layer_results_count;
             uint32_t* display_layer_results[] = { &layer_result };
-            ops_.ops->check_configuration(ops_.ctx, test_configs, &display_cfg_result,
-                                          display_layer_results, 1);
+            display_cfg_result = dc_.CheckConfiguration(test_configs, 1, display_layer_results,
+                                                        &display_layer_results_count);
             if (display_cfg_result == CONFIG_DISPLAY_OK) {
                 fbl::AllocChecker ac;
                 info->edid_timings.push_back(*timing, &ac);
@@ -237,8 +213,14 @@
     }
 }
 
-void Controller::OnDisplaysChanged(added_display_args_t* displays_added, uint32_t added_count,
-                                   uint64_t* displays_removed, uint32_t removed_count) {
+void Controller::DisplayControllerInterfaceOnDisplaysChanged(
+    const added_display_args_t* displays_added, size_t added_count,
+    const uint64_t* displays_removed, size_t removed_count,
+    added_display_info_t* out_display_info_list, size_t display_info_count,
+    size_t* display_info_actual) {
+
+    ZX_DEBUG_ASSERT(!out_display_info_list || added_count == display_info_count);
+
     fbl::unique_ptr<fbl::RefPtr<DisplayInfo>[]> added_success;
     fbl::unique_ptr<uint64_t[]> removed;
     fbl::unique_ptr<async::Task> task;
@@ -294,6 +276,7 @@
         info->vsync_layer_count = 0;
 
         auto& display_params = displays_added[i];
+        auto* display_info = out_display_info_list ? &out_display_info_list[i] : nullptr;
 
         info->id = display_params.display_id;
 
@@ -307,9 +290,9 @@
             zxlogf(INFO, "Out of memory when processing display hotplug\n");
             break;
         }
-        memcpy(info->pixel_formats_.get(), display_params.pixel_formats,
+        memcpy(info->pixel_formats_.get(), display_params.pixel_format_list,
                display_params.pixel_format_count * sizeof(zx_pixel_format_t));
-        memcpy(info->cursor_infos_.get(), display_params.cursor_infos,
+        memcpy(info->cursor_infos_.get(), display_params.cursor_info_list,
                display_params.cursor_info_count * sizeof(cursor_info_t));
 
         info->has_edid = display_params.edid_present;
@@ -353,18 +336,19 @@
                 }
             }
 
-            display_params.is_hdmi_out = info->edid.is_hdmi();
-            display_params.is_standard_srgb_out = info->edid.is_standard_rgb();
-            display_params.audio_format_count = static_cast<uint32_t>(info->edid_audio_.size());
+            if (display_info) {
+                display_info->is_hdmi_out = info->edid.is_hdmi();
+                display_info->is_standard_srgb_out = info->edid.is_standard_rgb();
+                display_info->audio_format_count = static_cast<uint32_t>(info->edid_audio_.size());
 
-            static_assert(sizeof(display_params.monitor_name) ==
-                    sizeof(edid::Descriptor::Monitor::data) + 1, "Possible overflow");
-            static_assert(sizeof(display_params.monitor_name) ==
-                    sizeof(edid::Descriptor::Monitor::data) + 1, "Possible overflow");
-            strcpy(display_params.monitor_name, info->edid.monitor_name());
-            strcpy(display_params.monitor_serial, info->edid.monitor_serial());
-            display_params.manufacturer_name = info->edid.manufacturer_name();
-
+                static_assert(sizeof(display_info->monitor_name) ==
+                        sizeof(edid::Descriptor::Monitor::data) + 1, "Possible overflow");
+                static_assert(sizeof(display_info->monitor_name) ==
+                        sizeof(edid::Descriptor::Monitor::data) + 1, "Possible overflow");
+                strcpy(display_info->monitor_name, info->edid.monitor_name());
+                strcpy(display_info->monitor_serial, info->edid.monitor_serial());
+                display_info->manufacturer_name = info->edid.manufacturer_name();
+            }
             if (zxlog_level_enabled_etc(DDK_LOG_TRACE)) {
                 zxlogf(TRACE, "Manufacturer \"%s\", product %d, name \"%s\", serial \"%s\"\n",
                        info->edid.manufacturer_name(), info->edid.product_code(),
@@ -381,6 +365,8 @@
             zxlogf(INFO, "Ignoring duplicate display\n");
         }
     }
+    if (display_info_actual)
+        *display_info_actual = added_success_count;
 
     task->set_handler([this,
                        added_ptr = added_success.release(), removed_ptr = removed.release(),
@@ -426,8 +412,9 @@
     task.release()->Post(loop_.dispatcher());
 }
 
-void Controller::OnDisplayVsync(uint64_t display_id, zx_time_t timestamp,
-                                void** handles, uint32_t handle_count) {
+void Controller::DisplayControllerInterfaceOnDisplayVsync(uint64_t display_id, zx_time_t timestamp,
+                                                          const uint64_t* handles,
+                                                          size_t handle_count) {
     fbl::AutoLock lock(&mtx_);
     DisplayInfo* info = nullptr;
     for (auto& display_config : displays_) {
@@ -459,7 +446,7 @@
             // Otherwise the change is done when the last handle_count==info->layer_count
             // images match the handles in the correct order.
             auto node = list_peek_tail_type(&info->images, image_node_t, link);
-            int32_t handle_idx = handle_count - 1;
+            ssize_t handle_idx = handle_count - 1;
             while (handle_idx >= 0 && node != nullptr) {
                 if (handles[handle_idx] != node->self->info().handle) {
                     break;
@@ -541,8 +528,8 @@
     }
 }
 
-zx_status_t Controller::GetAudioFormat(uint64_t display_id, uint32_t fmt_idx,
-                                       audio_stream_format_range_t* fmt_out) {
+zx_status_t Controller::DisplayControllerInterfaceGetAudioFormat(
+    uint64_t display_id, uint32_t fmt_idx, audio_stream_format_range_t* fmt_out) {
     fbl::AutoLock lock(&mtx_);
     auto display = displays_.find(display_id);
     if (!display.IsValid()) {
@@ -650,11 +637,11 @@
         applied_stamp_ = client_stamp;
     }
 
-    ops_.ops->apply_configuration(ops_.ctx, display_configs, display_count);
+    dc_.ApplyConfiguration(display_configs, display_count);
 }
 
 void Controller::ReleaseImage(Image* image) {
-    ops_.ops->release_image(ops_.ctx, &image->info());
+    dc_.ReleaseImage(&image->info());
 }
 
 void Controller::SetVcMode(uint8_t vc_mode) {
@@ -816,10 +803,12 @@
 
 zx_status_t Controller::Bind(fbl::unique_ptr<display::Controller>* device_ptr) {
     zx_status_t status;
-    if (device_get_protocol(parent_, ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL, &ops_)) {
+    display_controller_protocol_t dc_proto;
+    if (device_get_protocol(parent_, ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL, &dc_proto)) {
         ZX_DEBUG_ASSERT_MSG(false, "Display controller bind mismatch");
         return ZX_ERR_NOT_SUPPORTED;
     }
+    dc_ = ddk::DisplayControllerProtocolProxy(&dc_proto);
 
     if (device_get_protocol(parent_, ZX_PROTOCOL_I2C_IMPL, &i2c_ops_) == ZX_OK) {
         has_i2c_ops_ = true;
@@ -839,7 +828,8 @@
     }
     __UNUSED auto ptr = device_ptr->release();
 
-    ops_.ops->set_display_controller_cb(ops_.ctx, this, &dc_cb);
+    display_controller_interface_t intf = {&display_controller_interface_ops_, this};
+    dc_.SetDisplayControllerInterface(&intf);
 
     return ZX_OK;
 }
diff --git a/system/dev/display/display/controller.h b/system/dev/display/display/controller.h
index 04b38c5..78d3bb3 100644
--- a/system/dev/display/display/controller.h
+++ b/system/dev/display/display/controller.h
@@ -7,6 +7,7 @@
 #if __cplusplus
 
 #include <ddktl/device.h>
+#include <ddktl/protocol/display-controller.h>
 #include <ddktl/protocol/empty-protocol.h>
 #include <ddk/protocol/display-controller.h>
 #include <ddk/protocol/i2c-impl.h>
@@ -67,6 +68,7 @@
 
 using ControllerParent = ddk::Device<Controller, ddk::Unbindable, ddk::Openable, ddk::OpenAtable>;
 class Controller : public ControllerParent,
+                   public ddk::DisplayControllerInterface<Controller>,
                    public ddk::EmptyProtocol<ZX_PROTOCOL_DISPLAY_CONTROLLER> {
 public:
     Controller(zx_device_t* parent);
@@ -79,12 +81,18 @@
     void DdkRelease();
     zx_status_t Bind(fbl::unique_ptr<display::Controller>* device_ptr);
 
-    void OnDisplaysChanged(added_display_args_t* displays_added, uint32_t added_count,
-                           uint64_t* displays_removed, uint32_t removed_count);
-    void OnDisplayVsync(uint64_t display_id, zx_time_t timestamp,
-                        void** handles, uint32_t handle_count);
-    zx_status_t GetAudioFormat(uint64_t display_id, uint32_t fmt_idx,
-                               audio_stream_format_range_t* fmt_out);
+    void DisplayControllerInterfaceOnDisplaysChanged(const added_display_args_t* displays_added,
+                                                     size_t added_count,
+                                                     const uint64_t* displays_removed,
+                                                     size_t removed_count,
+                                                     added_display_info_t* out_display_info_list,
+                                                     size_t display_info_count,
+                                                     size_t* display_info_actual);
+    void DisplayControllerInterfaceOnDisplayVsync(uint64_t display_id, zx_time_t timestamp,
+                                                  const uint64_t* handles, size_t handle_count);
+    zx_status_t DisplayControllerInterfaceGetAudioFormat(uint64_t display_id, uint32_t fmt_idx,
+                                                         audio_stream_format_range_t* fmt_out);
+
     void OnClientDead(ClientProxy* client);
     void SetVcMode(uint8_t mode);
     void ShowActiveDisplay();
@@ -105,8 +113,7 @@
     bool GetCursorInfo(uint64_t display_id, fbl::Array<cursor_info_t>* cursor_info_out)
                        __TA_NO_THREAD_SAFETY_ANALYSIS;
 
-    display_controller_protocol_ops_t* ops() { return ops_.ops; }
-    void* ops_ctx() { return ops_.ctx; }
+    ddk::DisplayControllerProtocolProxy* dc() { return &dc_; }
     async::Loop& loop() { return loop_; }
     bool current_thread_is_loop() { return thrd_current() == loop_thread_; }
     mtx_t* mtx() { return &mtx_; }
@@ -131,7 +138,7 @@
 
     async::Loop loop_;
     thrd_t loop_thread_;
-    display_controller_protocol_t ops_;
+    ddk::DisplayControllerProtocolProxy dc_;
     i2c_impl_protocol_t i2c_ops_;
     bool has_i2c_ops_;
 };
diff --git a/system/dev/display/imx8m-display/imx8m-display.c b/system/dev/display/imx8m-display/imx8m-display.c
index e1b69e1..3222dbe 100644
--- a/system/dev/display/imx8m-display/imx8m-display.c
+++ b/system/dev/display/imx8m-display/imx8m-display.c
@@ -18,13 +18,14 @@
 #include <string.h>
 #include <unistd.h>
 #include <zircon/assert.h>
+#include <zircon/pixelformat.h>
 #include <zircon/syscalls.h>
 
 #define PANEL_DISPLAY_ID 1
 #define DISPLAY_WIDTH 1920
 #define DISPLAY_HEIGHT 1080
 #define DISPLAY_FORMAT ZX_PIXEL_FORMAT_RGB_x888
-static const zx_pixel_format_t supported_pixel_formats = { DISPLAY_FORMAT };
+static zx_pixel_format_t supported_pixel_formats[] = { DISPLAY_FORMAT };
 
 typedef struct image_info {
     zx_handle_t pmt;
@@ -44,24 +45,25 @@
     args->panel.params.height = DISPLAY_HEIGHT;
     args->panel.params.width = DISPLAY_WIDTH;
     args->panel.params.refresh_rate_e2 = 3000; // Just guess that it's 30fps
-    args->pixel_formats = &supported_pixel_formats;
-    args->pixel_format_count = sizeof(supported_pixel_formats) / sizeof(zx_pixel_format_t);
+    args->pixel_format_list = supported_pixel_formats;
+    args->pixel_format_count = countof(supported_pixel_formats);
     args->cursor_info_count = 0;
 }
 
-static void imx8m_set_display_controller_cb(void* ctx, void* cb_ctx, display_controller_cb_t* cb) {
+static void imx8m_set_display_controller_interface(void* ctx,
+                                                   const display_controller_interface_t* intf) {
     imx8m_display_t* display = ctx;
 
     mtx_lock(&display->display_lock);
 
     bool notify_display = io_buffer_is_valid(&display->fbuffer);
-    display->dc_cb = cb;
-    display->dc_cb_ctx = cb_ctx;
+    display->dc_intf = *intf;
 
     added_display_args_t args;
     populate_added_display_args(display, &args);
     if (notify_display) {
-        display->dc_cb->on_displays_changed(display->dc_cb_ctx, &args, 1, NULL, 0);
+        display_controller_interface_on_displays_changed(&display->dc_intf, &args, 1, NULL, 0,
+                                                         NULL, 0, NULL);
     }
     mtx_unlock(&display->display_lock);
 }
@@ -96,7 +98,7 @@
 
     import_info->paddr = paddr[0];
     list_add_head(&display->imported_images, &import_info->node);
-    image->handle = (void*) paddr[0];
+    image->handle = paddr[0];
 
     mtx_unlock(&display->image_lock);
 
@@ -117,7 +119,7 @@
 
     image_info_t* info;
     list_for_every_entry(&display->imported_images, info, image_info_t, node) {
-        if ((void*) info->paddr == image->handle) {
+        if (info->paddr == image->handle) {
             list_delete(&info->node);
             break;
         }
@@ -131,15 +133,14 @@
     }
 }
 
-static void imx8m_check_configuration(void* ctx,
-                                      const display_config_t** display_configs,
-                                      uint32_t* display_cfg_result,
-                                      uint32_t** layer_cfg_results,
-                                      uint32_t display_count) {
-    *display_cfg_result = CONFIG_DISPLAY_OK;
+static uint32_t imx8m_check_configuration(void* ctx,
+                                          const display_config_t** display_configs,
+                                          size_t display_count,
+                                          uint32_t** layer_cfg_results,
+                                          size_t* layer_cfg_result_count) {
     if (display_count != 1) {
         ZX_DEBUG_ASSERT(display_count == 0);
-        return;
+        return CONFIG_DISPLAY_OK;
     }
     ZX_DEBUG_ASSERT(display_configs[0]->display_id == PANEL_DISPLAY_ID);
 
@@ -150,11 +151,11 @@
     if (display_configs[0]->layer_count != 1) {
         success = display_configs[0]->layer_count == 0;
     } else {
-        primary_layer_t* layer = &display_configs[0]->layers[0]->cfg.primary;
+        primary_layer_t* layer = &display_configs[0]->layer_list[0]->cfg.primary;
         frame_t frame = {
             .x_pos = 0, .y_pos = 0, .width = DISPLAY_WIDTH, .height = DISPLAY_HEIGHT,
         };
-        success = display_configs[0]->layers[0]->type == LAYER_PRIMARY
+        success = display_configs[0]->layer_list[0]->type == LAYER_TYPE_PRIMARY
                 && layer->transform_mode == FRAME_TRANSFORM_IDENTITY
                 && layer->image.width == DISPLAY_WIDTH
                 && layer->image.height == DISPLAY_HEIGHT
@@ -168,18 +169,20 @@
         for (unsigned i = 1; i < display_configs[0]->layer_count; i++) {
             layer_cfg_results[0][i] = CLIENT_MERGE_SRC;
         }
+        layer_cfg_result_count[0] = display_configs[0]->layer_count;
     }
     mtx_unlock(&display->display_lock);
+    return CONFIG_DISPLAY_OK;
 }
 
 static void imx8m_apply_configuration(void* ctx, const display_config_t** display_configs,
-                                      uint32_t display_count) {
+                                      size_t display_count) {
     imx8m_display_t* display = ctx;
     mtx_lock(&display->display_lock);
 
     zx_paddr_t addr;
     if (display_count == 1 && display_configs[0]->layer_count) {
-        addr = (zx_paddr_t) display_configs[0]->layers[0]->cfg.primary.image.handle;
+        addr = (zx_paddr_t) display_configs[0]->layer_list[0]->cfg.primary.image.handle;
     } else {
         addr = 0;
     }
@@ -195,7 +198,7 @@
 }
 
 static display_controller_protocol_ops_t display_controller_ops = {
-    .set_display_controller_cb = imx8m_set_display_controller_cb,
+    .set_display_controller_interface = imx8m_set_display_controller_interface,
     .import_vmo_image = imx8m_import_vmo_image,
     .release_image = imx8m_release_image,
     .check_configuration = imx8m_check_configuration,
@@ -246,10 +249,11 @@
 
     writel(io_buffer_phys(&display->fbuffer), io_buffer_virt(&display->mmio_dc) +  0x80c0);
 
-    if (display->dc_cb) {
+    if (display->dc_intf.ops) {
         added_display_args_t args;
         populate_added_display_args(display, &args);
-        display->dc_cb->on_displays_changed(display->dc_cb_ctx, &args, 1, NULL, 0);
+        display_controller_interface_on_displays_changed(&display->dc_intf, &args, 1, NULL, 0,
+                                                         NULL, 0, NULL);
     }
     mtx_unlock(&display->display_lock);
 
diff --git a/system/dev/display/imx8m-display/imx8m-display.h b/system/dev/display/imx8m-display/imx8m-display.h
index e8e60fa..32dfcea 100644
--- a/system/dev/display/imx8m-display/imx8m-display.h
+++ b/system/dev/display/imx8m-display/imx8m-display.h
@@ -37,7 +37,6 @@
     io_buffer_t                         mmio_dc;
     io_buffer_t                         fbuffer;
 
-    display_controller_cb_t*            dc_cb;
-    void*                               dc_cb_ctx;
+    display_controller_interface_t      dc_intf;
     list_node_t                         imported_images;
 } imx8m_display_t;
diff --git a/system/dev/display/intel-i915/intel-i915.cpp b/system/dev/display/intel-i915/intel-i915.cpp
index e8e16d5..6ab5b36 100644
--- a/system/dev/display/intel-i915/intel-i915.cpp
+++ b/system/dev/display/intel-i915/intel-i915.cpp
@@ -252,7 +252,7 @@
         }
     }
 
-    if (dc_cb_ && (added_device || display_removed != INVALID_DISPLAY_ID)) {
+    if (dc_intf_.is_valid() && (added_device || display_removed != INVALID_DISPLAY_ID)) {
         CallOnDisplaysChanged(&added_device, added_device != nullptr ? 1 : 0,
                              &display_removed, display_removed != INVALID_DISPLAY_ID);
     }
@@ -261,7 +261,7 @@
 void Controller::HandlePipeVsync(registers::Pipe pipe, zx_time_t timestamp) {
     fbl::AutoLock lock(&display_lock_);
 
-    if (!dc_cb_) {
+    if (!dc_intf_.is_valid()) {
         return;
     }
 
@@ -291,7 +291,7 @@
     }
 
     if (id != INVALID_DISPLAY_ID && handle_count) {
-        dc_cb_->on_display_vsync(dc_cb_ctx_, id, timestamp, handles, handle_count);
+        dc_intf_.OnDisplayVsync(id, timestamp, handles, handle_count);
     }
 }
 
@@ -768,9 +768,11 @@
     return ZX_OK;
 }
 
-void Controller::CallOnDisplaysChanged(DisplayDevice** added, uint32_t added_count,
-                                       uint64_t* removed, uint32_t removed_count) {
+void Controller::CallOnDisplaysChanged(DisplayDevice** added, size_t added_count,
+                                       uint64_t* removed, size_t removed_count) {
     added_display_args_t added_args[added_count];
+    added_display_info_t added_info[added_count];
+    size_t added_actual;
     for (unsigned i = 0; i < added_count; i++) {
         added_args[i].display_id = added[i]->id();
         added_args[i].edid_present = true;
@@ -780,18 +782,21 @@
         added_args[i].cursor_infos = cursor_infos;
         added_args[i].cursor_info_count = static_cast<uint32_t>(fbl::count_of(cursor_infos));
     }
-    dc_cb_->on_displays_changed(dc_cb_ctx_, added_args, added_count, removed, removed_count);
-    for (unsigned i = 0; i < added_count; i++) {
-        added[i]->set_is_hdmi(added_args[i].is_hdmi_out);
+    dc_intf_->OnDisplayChanged(added_args, added_count, removed, removed_count,
+                                added_info, added_count, &added_actual);
+    ZX_DEBUG_ASSERT(added_count == added_actual);
+    for (unsigned i = 0; i < added_actual; i++) {
+        added[i]->set_is_hdmi(added_info[i].is_hdmi_out);
     }
 }
 
 // DisplayController methods
 
-void Controller::SetDisplayControllerCb(void* cb_ctx, display_controller_cb_t* cb) {
+void Controller::DisplayControllerSetDisplayControllerInterface(
+    const display_controller_interface_t* intf) {
+
     fbl::AutoLock lock(&display_lock_);
-    dc_cb_ctx_ = cb_ctx;
-    dc_cb_ = cb;
+    dc_intf_ = ddk::DisplayControllerInterfaceProxy(intf);
 
     if (ready_for_callback_ && display_devices_.size()) {
         DisplayDevice* added_displays[registers::kDdiCount];
@@ -803,7 +808,8 @@
     }
 }
 
-zx_status_t Controller::ImportVmoImage(image_t* image, const zx::vmo& vmo, size_t offset) {
+zx_status_t Controller::DisplayControllerImportVmoImage(image_t* image, zx_handle_t vmo,
+                                                        size_t offset) {
     if (!(image->type == IMAGE_TYPE_SIMPLE || image->type == IMAGE_TYPE_X_TILED
                 || image->type == IMAGE_TYPE_Y_LEGACY_TILED
                 || image->type == IMAGE_TYPE_YF_TILED)) {
@@ -848,7 +854,7 @@
         gtt_region = fbl::move(alt_gtt_region);
     }
 
-    status = gtt_region->PopulateRegion(vmo.get(), offset / PAGE_SIZE, length);
+    status = gtt_region->PopulateRegion(vmo, offset / PAGE_SIZE, length);
     if (status != ZX_OK) {
         return status;
     }
@@ -858,7 +864,7 @@
     return ZX_OK;
 }
 
-void Controller::ReleaseImage(image_t* image) {
+void Controller::DisplayControllerReleaseImage(image_t* image) {
     fbl::AutoLock lock(&gtt_lock_);
     for (unsigned i = 0; i < imported_images_.size(); i++) {
         if (imported_images_[i]->base() == reinterpret_cast<uint64_t>(image->handle)) {
@@ -868,7 +874,7 @@
     }
 }
 
-const fbl::unique_ptr<GttRegion>& Controller::GetGttRegion(void* handle) {
+const fbl::unique_ptr<GttRegion>& Controller::DisplayControllerGetGttRegion(void* handle) {
     fbl::AutoLock lock(&gtt_lock_);
     for (auto& region : imported_images_) {
         if (region->base() == reinterpret_cast<uint64_t>(handle)) {
@@ -1314,29 +1320,26 @@
     return true;
 }
 
-void Controller::CheckConfiguration(const display_config_t** display_config,
-                                    uint32_t* display_cfg_result, uint32_t** layer_cfg_result,
-                                    uint32_t display_count) {
+uint32_t Controller::DisplayControllerCheckConfiguration(const display_config_t** display_config,
+                                                         size_t display_count,
+                                                         uint32_t** layer_cfg_result,
+                                                         size_t* layer_cfg_result_count) {
     fbl::AutoLock lock(&display_lock_);
 
     if (display_count == 0) {
         // All displays off is supported
-        *display_cfg_result = CONFIG_DISPLAY_OK;
-        return;
+        return CONFIG_DISPLAY_OK;
     }
 
     uint64_t pipe_alloc[registers::kPipeCount];
     if (!CalculatePipeAllocation(display_config, display_count, pipe_alloc)) {
-        *display_cfg_result = CONFIG_DISPLAY_TOO_MANY;
-        return;
+        return CONFIG_DISPLAY_TOO_MANY;
     }
 
     if (!CheckDisplayLimits(display_config, display_count, layer_cfg_result)) {
-        *display_cfg_result = CONFIG_DISPLAY_UNSUPPORTED_MODES;
-        return;
+        return CONFIG_DISPLAY_UNSUPPORTED_MODES;
     }
 
-    *display_cfg_result = CONFIG_DISPLAY_OK;
     for (unsigned i = 0; i < display_count; i++) {
         auto* config = display_config[i];
         DisplayDevice* display = nullptr;
@@ -1509,6 +1512,8 @@
             }
         }
     }
+
+    return CONFIG_DISPLAY_OK;
 }
 
 bool Controller::CalculatePipeAllocation(const display_config_t** display_config,
@@ -1612,20 +1617,21 @@
         }
     }
 
-    if (dc_cb_) {
+    if (dc_intf_.is_valid) {
         zx_time_t now = fake_vsync_count ? zx_clock_get(ZX_CLOCK_MONOTONIC) : 0;
         for (unsigned i = 0; i < fake_vsync_count; i++) {
-            dc_cb_->on_display_vsync(dc_cb_ctx_, fake_vsyncs[i], now, nullptr, 0);
+            dc_intf_.OnDisplayVsync(fake_vsyncs[i], now, nullptr, 0);
         }
     }
 }
 
-uint32_t Controller::ComputeLinearStride(uint32_t width, zx_pixel_format_t format) {
+uint32_t Controller::DisplayControllerComputeLinearStride(uint32_t width,
+                                                          zx_pixel_format_t format) {
     return fbl::round_up(width,
             get_tile_byte_width(IMAGE_TYPE_SIMPLE, format) / ZX_PIXEL_FORMAT_BYTES(format));
 }
 
-zx_status_t Controller::AllocateVmo(uint64_t size, zx_handle_t* vmo_out) {
+zx_status_t Controller::DisplayControllerAllocateVmo(uint64_t size, zx_handle_t* vmo_out) {
     return zx_vmo_create(size, 0, vmo_out);
 }
 
@@ -1931,7 +1937,7 @@
     {
         fbl::AutoLock lock(&display_lock_);
         uint32_t size = static_cast<uint32_t>(display_devices_.size());
-        if (size && dc_cb_) {
+        if (size && dc_intf_.is_valid()) {
             DisplayDevice* added_displays[registers::kDdiCount];
             for (unsigned i = 0; i < size; i++) {
                 added_displays[i] = display_devices_[i].get();
diff --git a/system/dev/display/intel-i915/intel-i915.h b/system/dev/display/intel-i915/intel-i915.h
index 952ecc6..bb5c24b 100644
--- a/system/dev/display/intel-i915/intel-i915.h
+++ b/system/dev/display/intel-i915/intel-i915.h
@@ -10,6 +10,7 @@
 #include <ddk/protocol/pci.h>
 #include <ddk/protocol/i2c-impl.h>
 #include <ddktl/protocol/display-controller.h>
+#include <ddktl/protocol/empty-protocol.h>
 
 #include <fbl/unique_ptr.h>
 #include <fbl/vector.h>
@@ -57,7 +58,9 @@
 using DeviceType = ddk::Device<Controller, ddk::Unbindable,
                                ddk::Suspendable, ddk::Resumable, ddk::GetProtocolable>;
 
-class Controller : public DeviceType, public ddk::DisplayControllerProtocol<Controller> {
+class Controller : public DeviceType,
+                   public ddk::DisplayControllerProtocol<Controller>,
+                   public ddk::EmptyProtocol<ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL> {
 public:
     Controller(zx_device_t* parent);
     ~Controller();
@@ -73,15 +76,16 @@
     zx_status_t Bind(fbl::unique_ptr<i915::Controller>* controller_ptr);
 
     // display controller protocol ops
-    void SetDisplayControllerCb(void* cb_ctx, display_controller_cb_t* cb);
-    zx_status_t ImportVmoImage(image_t* image, const zx::vmo& vmo, size_t offset);
-    void ReleaseImage(image_t* image);
-    void CheckConfiguration(const display_config_t** display_config,
-                            uint32_t* display_cfg_result, uint32_t** layer_cfg_result,
-                            uint32_t display_count);
-    void ApplyConfiguration(const display_config_t** display_config, uint32_t display_count);
-    uint32_t ComputeLinearStride(uint32_t width, zx_pixel_format_t format);
-    zx_status_t AllocateVmo(uint64_t size, zx_handle_t* vmo_out);
+    void DisplayControllerSetDisplayControllerInterface(const display_controller_interface* intf);
+    zx_status_t DisplayControllerImportVmoImage(image_t* image, zx_handle_t vmo, size_t offset);
+    void DisplayControllerReleaseImage(image_t* image);
+    uint32_t DisplayControllerCheckConfiguration(const display_config_t** display_config,
+                                                 size_t display_count, uint32_t** layer_cfg_result,
+                                                 size_t* layer_cfg_result_count);
+    void DisplayControllerApplyConfiguration(const display_config_t** display_config,
+                                             size_t display_count);
+    uint32_t DisplayControllerComputeLinearStride(uint32_t width, zx_pixel_format_t format);
+    zx_status_t DisplayControllerAllocateVmo(uint64_t size, zx_handle_t* vmo_out);
 
     // gpu core ops
     zx_status_t ReadPciConfig16(uint16_t addr, uint16_t* value_out);
@@ -185,8 +189,7 @@
     bool gpu_released_ = false;
     bool display_released_ = false;
 
-    void* dc_cb_ctx_ __TA_GUARDED(display_lock_);
-    display_controller_cb_t* dc_cb_ __TA_GUARDED(display_lock_) = nullptr;
+    ddk::DisplayControllerInterfaceProxy dc_intf_ __TA_GUARDED(display_lock_) = nullptr;
     bool ready_for_callback_ __TA_GUARDED(display_lock_) = false;
 
     Gtt gtt_ __TA_GUARDED(gtt_lock_);
diff --git a/system/dev/display/simple/simple-bochs.c b/system/dev/display/simple/simple-bochs.c
index 7692167..f40ec46 100644
--- a/system/dev/display/simple/simple-bochs.c
+++ b/system/dev/display/simple/simple-bochs.c
@@ -7,6 +7,8 @@
 #include <ddk/device.h>
 #include <ddk/driver.h>
 #include <ddk/protocol/pci.h>
+#include <ddk/protocol/pci-lib.h>
+#include <hw/pci.h>
 #include <zircon/pixelformat.h>
 #include <zircon/process.h>
 
diff --git a/system/dev/display/simple/simple-display.cpp b/system/dev/display/simple/simple-display.cpp
index 19e32e9..64c1c37 100644
--- a/system/dev/display/simple/simple-display.cpp
+++ b/system/dev/display/simple/simple-display.cpp
@@ -10,6 +10,7 @@
 #include <hw/pci.h>
 
 #include <assert.h>
+#include <zircon/pixelformat.h>
 #include <zircon/process.h>
 #include <zircon/syscalls.h>
 #include <zircon/types.h>
@@ -23,11 +24,11 @@
 // implement display controller protocol
 static constexpr uint64_t kDisplayId = 1;
 
-static void* const kImageHandle = reinterpret_cast<void*>(0xdecafc0ffee);
+static constexpr uint64_t kImageHandle = 0xdecafc0ffee;
 
-void SimpleDisplay::SetDisplayControllerCb(void* cb_ctx, display_controller_cb_t* cb) {
-    cb_ctx_ = cb_ctx;
-    cb_ = cb;
+void SimpleDisplay::DisplayControllerSetDisplayControllerInterface(
+    const display_controller_interface_t* intf) {
+    intf_ = ddk::DisplayControllerInterfaceProxy(intf);
 
     added_display_args_t args = {};
     args.display_id = kDisplayId;
@@ -35,17 +36,19 @@
     args.panel.params.height = height_;
     args.panel.params.width = width_;
     args.panel.params.refresh_rate_e2 = 3000; // Just guess that it's 30fps
-    args.pixel_formats = &format_;
+    args.pixel_format_list = &format_;
     args.pixel_format_count = 1;
 
-    cb->on_displays_changed(cb_ctx, &args, 1, nullptr, 0);
+    intf_.OnDisplaysChanged(&args, 1, nullptr, 0, nullptr, 0, nullptr);
 }
 
-zx_status_t SimpleDisplay::ImportVmoImage(image_t* image, const zx::vmo& vmo, size_t offset) {
+zx_status_t SimpleDisplay::DisplayControllerImportVmoImage(image_t* image, zx_handle_t vmo,
+                                                           size_t offset) {
     zx_info_handle_basic_t import_info;
     size_t actual, avail;
-    zx_status_t status = vmo.get_info(ZX_INFO_HANDLE_BASIC,
-                                      &import_info, sizeof(import_info), &actual, &avail);
+    zx_status_t status = zx::unowned_vmo(vmo)->get_info(ZX_INFO_HANDLE_BASIC,
+                                                        &import_info, sizeof(import_info), &actual,
+                                                        &avail);
     if (status != ZX_OK) {
         return status;
     }
@@ -60,29 +63,28 @@
     return ZX_OK;
 }
 
-void SimpleDisplay::ReleaseImage(image_t* image) {
+void SimpleDisplay::DisplayControllerReleaseImage(image_t* image) {
     // noop
 }
 
-void SimpleDisplay::CheckConfiguration(const display_config_t** display_configs,
-                                       uint32_t* display_cfg_result,
-                                       uint32_t** layer_cfg_results,
-                                       uint32_t display_count) {
-    *display_cfg_result = CONFIG_DISPLAY_OK;
+uint32_t SimpleDisplay::DisplayControllerCheckConfiguration(
+    const display_config_t** display_configs, size_t display_count, uint32_t** layer_cfg_results,
+    size_t* layer_cfg_result_count) {
+
     if (display_count != 1) {
         ZX_DEBUG_ASSERT(display_count == 0);
-        return;
+        return CONFIG_DISPLAY_OK;
     }
     ZX_DEBUG_ASSERT(display_configs[0]->display_id == kDisplayId);
     bool success;
     if (display_configs[0]->layer_count != 1) {
         success = false;
     } else {
-        primary_layer_t* layer = &display_configs[0]->layers[0]->cfg.primary;
+        primary_layer_t* layer = &display_configs[0]->layer_list[0]->cfg.primary;
         frame_t frame = {
                 .x_pos = 0, .y_pos = 0, .width = width_, .height = height_,
         };
-        success = display_configs[0]->layers[0]->type == LAYER_PRIMARY
+        success = display_configs[0]->layer_list[0]->type == LAYER_TYPE_PRIMARY
                 && layer->transform_mode == FRAME_TRANSFORM_IDENTITY
                 && layer->image.width == width_
                 && layer->image.height == height_
@@ -96,24 +98,26 @@
         for (unsigned i = 1; i < display_configs[0]->layer_count; i++) {
             layer_cfg_results[0][i] = CLIENT_MERGE_SRC;
         }
+        layer_cfg_result_count[0] = display_configs[0]->layer_count;
     }
+    return CONFIG_DISPLAY_OK;
 }
 
-void SimpleDisplay::ApplyConfiguration(const display_config_t** display_config,
-                                       uint32_t display_count) {
+void SimpleDisplay::DisplayControllerApplyConfiguration(const display_config_t** display_config,
+                                                        size_t display_count) {
     bool has_image = display_count != 0 && display_config[0]->layer_count != 0;
-    void* handles[] = { kImageHandle };
-    if (cb_) {
-        cb_->on_display_vsync(cb_ctx_, kDisplayId, zx_clock_get(ZX_CLOCK_MONOTONIC),
-                              handles, has_image);
+    uint64_t handles[] = { kImageHandle };
+    if (intf_.is_valid()) {
+        intf_.OnDisplayVsync(kDisplayId, zx_clock_get(ZX_CLOCK_MONOTONIC), handles, has_image);
     }
 }
 
-uint32_t SimpleDisplay::ComputeLinearStride(uint32_t width, zx_pixel_format_t format) {
+uint32_t SimpleDisplay::DisplayControllerComputeLinearStride(uint32_t width,
+                                                             zx_pixel_format_t format) {
     return (width == width_ && format == format_) ? stride_ : 0;
 }
 
-zx_status_t SimpleDisplay::AllocateVmo(uint64_t size, zx_handle_t* vmo_out) {
+zx_status_t SimpleDisplay::DisplayControllerAllocateVmo(uint64_t size, zx_handle_t* vmo_out) {
     zx_info_handle_count handle_count;
     size_t actual, avail;
     zx_status_t status = framebuffer_handle_.get_info(ZX_INFO_HANDLE_COUNT, &handle_count,
diff --git a/system/dev/display/simple/simple-display.h b/system/dev/display/simple/simple-display.h
index 3de2165..913b3d1 100644
--- a/system/dev/display/simple/simple-display.h
+++ b/system/dev/display/simple/simple-display.h
@@ -12,6 +12,7 @@
 
 #include <ddktl/device.h>
 #include <ddktl/protocol/display-controller.h>
+#include <ddktl/protocol/empty-protocol.h>
 #include <fbl/unique_ptr.h>
 #include <lib/zx/vmo.h>
 
@@ -19,7 +20,8 @@
 using DeviceType = ddk::Device<SimpleDisplay, ddk::Unbindable>;
 
 class SimpleDisplay : public DeviceType,
-                      public ddk::DisplayControllerProtocol<SimpleDisplay> {
+                      public ddk::DisplayControllerProtocol<SimpleDisplay>,
+                      public ddk::EmptyProtocol<ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL> {
 public:
     SimpleDisplay(zx_device_t* parent, zx_handle_t vmo,
                   uintptr_t framebuffer, uint64_t framebuffer_size,
@@ -31,15 +33,16 @@
     void DdkRelease();
     zx_status_t Bind(const char* name, fbl::unique_ptr<SimpleDisplay>* controller_ptr);
 
-    void SetDisplayControllerCb(void* cb_ctx, display_controller_cb_t* cb);
-    zx_status_t ImportVmoImage(image_t* image, const zx::vmo& vmo, size_t offset);
-    void ReleaseImage(image_t* image);
-    void CheckConfiguration(const display_config_t** display_config,
-                            uint32_t* display_cfg_result, uint32_t** layer_cfg_result,
-                            uint32_t display_count);
-    void ApplyConfiguration(const display_config_t** display_config, uint32_t display_count);
-    uint32_t ComputeLinearStride(uint32_t width, zx_pixel_format_t format);
-    zx_status_t AllocateVmo(uint64_t size, zx_handle_t* vmo_out);
+    void DisplayControllerSetDisplayControllerInterface(const display_controller_interface_t* intf);
+    zx_status_t DisplayControllerImportVmoImage(image_t* image, zx_handle_t vmo, size_t offset);
+    void DisplayControllerReleaseImage(image_t* image);
+    uint32_t DisplayControllerCheckConfiguration(const display_config_t** display_configs,
+                                                 size_t display_count, uint32_t** layer_cfg_results,
+                                                 size_t* layer_cfg_result_count);
+    void DisplayControllerApplyConfiguration(const display_config_t** display_config,
+                                             size_t display_count);
+    uint32_t DisplayControllerComputeLinearStride(uint32_t width, zx_pixel_format_t format);
+    zx_status_t DisplayControllerAllocateVmo(uint64_t size, zx_handle_t* vmo_out);
 
 private:
     zx::vmo framebuffer_handle_;
@@ -52,8 +55,7 @@
     uint32_t stride_;
     zx_pixel_format_t format_;
 
-    display_controller_cb_t* cb_;
-    void* cb_ctx_;
+    ddk::DisplayControllerInterfaceProxy intf_;
 };
 
 #endif // __cplusplus
diff --git a/system/dev/display/simple/simple-nv.c b/system/dev/display/simple/simple-nv.c
index a944464..81d7438d 100644
--- a/system/dev/display/simple/simple-nv.c
+++ b/system/dev/display/simple/simple-nv.c
@@ -5,7 +5,7 @@
 #include <ddk/binding.h>
 #include <ddk/device.h>
 #include <ddk/driver.h>
-#include <ddk/protocol/pci.h>
+#include <hw/pci.h>
 
 #include "simple-display.h"
 
diff --git a/system/dev/display/vim-display/vim-display.cpp b/system/dev/display/vim-display/vim-display.cpp
index 5f42625..20b38c5 100644
--- a/system/dev/display/vim-display/vim-display.cpp
+++ b/system/dev/display/vim-display/vim-display.cpp
@@ -26,13 +26,14 @@
 #include <string.h>
 #include <unistd.h>
 #include <zircon/assert.h>
+#include <zircon/pixelformat.h>
 #include <zircon/syscalls.h>
 
 /* Default formats */
 static const uint8_t _ginput_color_format   = HDMI_COLOR_FORMAT_444;
 static const uint8_t _gcolor_depth          = HDMI_COLOR_DEPTH_24B;
 
-static const zx_pixel_format_t _gsupported_pixel_formats = { ZX_PIXEL_FORMAT_RGB_x888 };
+static zx_pixel_format_t _gsupported_pixel_formats[] = { ZX_PIXEL_FORMAT_RGB_x888 };
 
 typedef struct image_info {
     zx_handle_t pmt;
@@ -46,8 +47,8 @@
     args->display_id = display->display_id;
     args->edid_present = true;
     args->panel.i2c_bus_id = 0;
-    args->pixel_formats = &_gsupported_pixel_formats;
-    args->pixel_format_count = sizeof(_gsupported_pixel_formats) / sizeof(zx_pixel_format_t);
+    args->pixel_format_list = _gsupported_pixel_formats;
+    args->pixel_format_count = countof(_gsupported_pixel_formats);
     args->cursor_info_count = 0;
 }
 
@@ -57,19 +58,21 @@
     return ROUNDUP(width, 32 / ZX_PIXEL_FORMAT_BYTES(format));
 }
 
-static void vim_set_display_controller_cb(void* ctx, void* cb_ctx, display_controller_cb_t* cb) {
+static void vim_set_display_controller_interface(void* ctx,
+                                                 const display_controller_interface_t* intf) {
     vim2_display_t* display = static_cast<vim2_display_t*>(ctx);
     mtx_lock(&display->display_lock);
 
-    display->dc_cb = cb;
-    display->dc_cb_ctx = cb_ctx;
+    display->dc_intf = *intf;
 
     if (display->display_attached) {
         added_display_args_t args;
+        added_display_info_t info;
         populate_added_display_args(display, &args);
-        display->dc_cb->on_displays_changed(display->dc_cb_ctx, &args, 1, NULL, 0);
+        display_controller_interface_on_displays_changed(&display->dc_intf, &args, 1, NULL, 0,
+                                                         &info, 1, NULL);
 
-        if (args.is_standard_srgb_out) {
+        if (info.is_standard_srgb_out) {
             display->output_color_format = HDMI_COLOR_FORMAT_RGB;
         } else {
             display->output_color_format = HDMI_COLOR_FORMAT_444;
@@ -117,7 +120,7 @@
         if (status != ZX_OK) {
             return ZX_ERR_NO_RESOURCES;
         }
-        image->handle = (void*)(uint64_t)import_info->canvas_idx[0];
+        image->handle = import_info->canvas_idx[0];
     } else if (image->pixel_format == ZX_PIXEL_FORMAT_NV12) {
         if (image->height % 2 != 0) {
             return ZX_ERR_INVALID_ARGS;
@@ -164,8 +167,8 @@
             return ZX_ERR_NO_RESOURCES;
         }
         // The handle used by hardware is VVUUYY, so the UV plane is included twice.
-        image->handle = (void*)(((uint64_t)import_info->canvas_idx[1] << 16) |
-                                (import_info->canvas_idx[1] << 8) | import_info->canvas_idx[0]);
+        image->handle = (((uint64_t)import_info->canvas_idx[1] << 16) |
+                         (import_info->canvas_idx[1] << 8) | import_info->canvas_idx[0]);
     } else {
         return ZX_ERR_INVALID_ARGS;
     }
@@ -199,20 +202,19 @@
     }
 }
 
-static void vim_check_configuration(void* ctx,
-                                    const display_config_t** display_configs,
-                                    uint32_t* display_cfg_result,
-                                    uint32_t** layer_cfg_results,
-                                    uint32_t display_count) {
-    *display_cfg_result = CONFIG_DISPLAY_OK;
+static uint32_t vim_check_configuration(void* ctx,
+                                        const display_config_t** display_configs,
+                                        size_t display_count,
+                                        uint32_t** layer_cfg_results,
+                                        size_t* layer_cfg_result_count) {
     if (display_count != 1) {
         if (display_count > 1) {
             // The core display driver should never see a configuration with more
             // than 1 display, so this is a bug in the core driver.
             ZX_DEBUG_ASSERT(false);
-            *display_cfg_result = CONFIG_DISPLAY_TOO_MANY;
+            return CONFIG_DISPLAY_TOO_MANY;
         }
-        return;
+        return CONFIG_DISPLAY_OK;
     }
     vim2_display_t* display = static_cast<vim2_display_t*>(ctx);
     mtx_lock(&display->display_lock);
@@ -220,7 +222,7 @@
     // no-op, just wait for the client to try a new config
     if (!display->display_attached || display_configs[0]->display_id != display->display_id) {
         mtx_unlock(&display->display_lock);
-        return;
+        return CONFIG_DISPLAY_OK;
     }
 
     struct hdmi_param p;
@@ -228,8 +230,7 @@
             && get_vic(&display_configs[0]->mode, &p) != ZX_OK)
             || (display_configs[0]->mode.v_addressable % 8)) {
         mtx_unlock(&display->display_lock);
-        *display_cfg_result = CONFIG_DISPLAY_UNSUPPORTED_MODES;
-        return;
+        return CONFIG_DISPLAY_UNSUPPORTED_MODES;
     }
 
     bool success;
@@ -238,7 +239,7 @@
     } else {
         uint32_t width = display_configs[0]->mode.h_addressable;
         uint32_t height = display_configs[0]->mode.v_addressable;
-        primary_layer_t* layer = &display_configs[0]->layers[0]->cfg.primary;
+        primary_layer_t* layer = &display_configs[0]->layer_list[0]->cfg.primary;
         frame_t frame = {
                 .x_pos = 0, .y_pos = 0, .width = width, .height = height,
         };
@@ -246,7 +247,7 @@
                                                            layer->image.width,
                                                            layer->image.pixel_format)
                 * ZX_PIXEL_FORMAT_BYTES(layer->image.pixel_format);
-        success = display_configs[0]->layers[0]->type == LAYER_PRIMARY
+        success = display_configs[0]->layer_list[0]->type == LAYER_TYPE_PRIMARY
                 && layer->transform_mode == FRAME_TRANSFORM_IDENTITY
                 && layer->image.width == width
                 && layer->image.height == height
@@ -263,13 +264,15 @@
         for (unsigned i = 1; i < display_configs[0]->layer_count; i++) {
             layer_cfg_results[0][i] = CLIENT_MERGE_SRC;
         }
+        layer_cfg_result_count[0] = display_configs[0]->layer_count;
     }
     mtx_unlock(&display->display_lock);
+    return CONFIG_DISPLAY_OK;
 }
 
 static void vim_apply_configuration(void* ctx,
                                     const display_config_t** display_configs,
-                                    uint32_t display_count) {
+                                    size_t display_count) {
     vim2_display_t* display = static_cast<vim2_display_t*>(ctx);
     mtx_lock(&display->display_lock);
 
@@ -296,14 +299,14 @@
             mtx_unlock(&display->display_lock);
             return;
         }
-        if (display_configs[0]->layers[0]->cfg.primary.image.pixel_format == ZX_PIXEL_FORMAT_NV12) {
+        if (display_configs[0]->layer_list[0]->cfg.primary.image.pixel_format == ZX_PIXEL_FORMAT_NV12) {
             uint32_t addr =
-                (uint32_t)(uint64_t)display_configs[0]->layers[0]->cfg.primary.image.handle;
+                (uint32_t)(uint64_t)display_configs[0]->layer_list[0]->cfg.primary.image.handle;
             flip_vd(display, 0, addr);
             disable_osd(display, 1);
         } else {
             uint8_t addr;
-            addr = (uint8_t)(uint64_t)display_configs[0]->layers[0]->cfg.primary.image.handle;
+            addr = (uint8_t)(uint64_t)display_configs[0]->layer_list[0]->cfg.primary.image.handle;
             flip_osd(display, 1, addr);
             disable_vd(display, 0);
         }
@@ -325,7 +328,7 @@
 }
 
 static display_controller_protocol_ops_t display_controller_ops = {
-    .set_display_controller_cb = vim_set_display_controller_cb,
+    .set_display_controller_interface = vim_set_display_controller_interface,
     .import_vmo_image = vim_import_vmo_image,
     .release_image = vim_release_image,
     .check_configuration = vim_check_configuration,
@@ -513,6 +516,7 @@
 
         bool display_added = false;
         added_display_args_t args;
+        added_display_info_t info;
         uint64_t display_removed = INVALID_DISPLAY_ID;
         if (hpd && !display->display_attached) {
             DISP_ERROR("Display is connected\n");
@@ -533,27 +537,30 @@
             gpio_set_polarity(&display->gpio, 0, GPIO_POLARITY_HIGH);
         }
 
-        if (display->dc_cb &&
+        if (display->dc_intf.ops &&
                 (display_removed != INVALID_DISPLAY_ID || display_added)) {
-            display->dc_cb->on_displays_changed(display->dc_cb_ctx,
-                                                &args,
-                                                display_added ? 1 : 0,
-                                                &display_removed,
-                                                display_removed != INVALID_DISPLAY_ID);
+            display_controller_interface_on_displays_changed(&display->dc_intf,
+                                                             &args,
+                                                             display_added ? 1 : 0,
+                                                             &display_removed,
+                                                             display_removed != INVALID_DISPLAY_ID,
+                                                             &info,
+                                                             display_added ? 1 : 0,
+                                                             NULL);
             if (display_added) {
                 // See if we need to change output color to RGB
-                if (args.is_standard_srgb_out) {
+                if (info.is_standard_srgb_out) {
                     display->output_color_format = HDMI_COLOR_FORMAT_RGB;
                 } else {
                     display->output_color_format = HDMI_COLOR_FORMAT_444;
                 }
-                display->audio_format_count = args.audio_format_count;
+                display->audio_format_count = info.audio_format_count;
 
-                display->manufacturer_name = args.manufacturer_name;
-                memcpy(display->monitor_name, args.monitor_name, sizeof(args.monitor_name));
-                memcpy(display->monitor_serial, args.monitor_serial, sizeof(args.monitor_serial));
-                static_assert(sizeof(display->monitor_name) == sizeof(args.monitor_name), "");
-                static_assert(sizeof(display->monitor_serial) == sizeof(args.monitor_serial), "");
+                display->manufacturer_name = info.manufacturer_name;
+                memcpy(display->monitor_name, info.monitor_name, sizeof(info.monitor_name));
+                memcpy(display->monitor_serial, info.monitor_serial, sizeof(info.monitor_serial));
+                static_assert(sizeof(display->monitor_name) == sizeof(info.monitor_name), "");
+                static_assert(sizeof(display->monitor_serial) == sizeof(info.monitor_serial), "");
             }
         }
 
@@ -563,7 +570,7 @@
             vim2_audio_on_display_removed(display, display_removed);
         }
 
-        if (display_added && args.audio_format_count) {
+        if (display_added && info.audio_format_count) {
             vim2_audio_on_display_added(display, display->display_id);
         }
     }
@@ -586,18 +593,18 @@
 
         uint64_t display_id = display->display_id;
         bool attached = display->display_attached;
-        void* live[2] = {};
+        uint64_t live[2] = {};
         uint32_t current_image_count = 0;
         if (display->current_image_valid) {
-            live[current_image_count++] = (void*)(uint64_t)display->current_image;
+            live[current_image_count++] = display->current_image;
         }
         if (display->vd1_image_valid) {
-            live[current_image_count++] = (void*)(uint64_t)display->vd1_image;
+            live[current_image_count++] = display->vd1_image;
         }
 
-        if (display->dc_cb && attached) {
-            display->dc_cb->on_display_vsync(display->dc_cb_ctx, display_id, timestamp, live,
-                                             current_image_count);
+        if (display->dc_intf.ops && attached) {
+            display_controller_interface_on_display_vsync(&display->dc_intf, display_id, timestamp,
+                                                          live, current_image_count);
         }
         mtx_unlock(&display->display_lock);
     }
diff --git a/system/dev/display/vim-display/vim-display.h b/system/dev/display/vim-display/vim-display.h
index 366089b..bd51ea0 100644
--- a/system/dev/display/vim-display/vim-display.h
+++ b/system/dev/display/vim-display/vim-display.h
@@ -103,8 +103,7 @@
     struct hdmi_param*                  p;
     display_mode_t                      cur_display_mode;
 
-    display_controller_cb_t*            dc_cb;
-    void*                               dc_cb_ctx;
+    display_controller_interface_t      dc_intf;
     list_node_t                         imported_images;
 
     // A reference to the object which controls the VIM2 DAIs used to feed audio
diff --git a/system/dev/display/vim-display/vim-spdif-audio-stream.cpp b/system/dev/display/vim-display/vim-spdif-audio-stream.cpp
index 1e50256..ff712ed 100644
--- a/system/dev/display/vim-display/vim-spdif-audio-stream.cpp
+++ b/system/dev/display/vim-display/vim-spdif-audio-stream.cpp
@@ -328,8 +328,8 @@
     // generate clock rates up to 192KHz, and can generate 16, 20, and 24 bit audio.
     for (unsigned i = 0; i < display_->audio_format_count; i++) {
         audio_stream_format_range_t range;
-        zx_status_t status = display_->dc_cb->get_audio_format(
-                display_->dc_cb_ctx, display_->display_id, i, &range);
+        zx_status_t status = display_controller_interface_get_audio_format(
+            &display_->dc_intf, display_->display_id, i, &range);
         ZX_ASSERT(status == ZX_OK);
 
         constexpr uint32_t SUPPORTED_FORMATS = AUDIO_SAMPLE_FORMAT_16BIT |
diff --git a/system/dev/ethernet/aml-dwmac/aml-dwmac.cpp b/system/dev/ethernet/aml-dwmac/aml-dwmac.cpp
index 430575d..d10bf6a 100644
--- a/system/dev/ethernet/aml-dwmac/aml-dwmac.cpp
+++ b/system/dev/ethernet/aml-dwmac/aml-dwmac.cpp
@@ -15,6 +15,7 @@
 #include <lib/fzl/vmar-manager.h>
 #include <soc/aml-s912/s912-hw.h>
 #include <zircon/compiler.h>
+#include <zircon/device/ethernet.h>
 
 #include <stdio.h>
 #include <string.h>
@@ -484,14 +485,14 @@
     ethmac_proxy_.reset();
 }
 
-zx_status_t AmlDWMacDevice::EthmacStart(fbl::unique_ptr<ddk::EthmacIfcProxy> proxy) {
+zx_status_t AmlDWMacDevice::EthmacStart(const ethmac_ifc_t* ifc) {
     fbl::AutoLock lock(&lock_);
 
     if (ethmac_proxy_ != nullptr) {
         zxlogf(ERROR, "aml_dwmac:  Already bound!!!");
         return ZX_ERR_ALREADY_BOUND;
     } else {
-        ethmac_proxy_ = fbl::move(proxy);
+        ethmac_proxy_ = fbl::make_unique<ddk::EthmacIfcProxy>(ifc);
         UpdateLinkStatus();
         zxlogf(INFO, "aml_dwmac: Started\n");
     }
@@ -599,7 +600,7 @@
         }
     }
 
-    if (netbuf->len > kTxnBufSize) {
+    if (netbuf->data_size > kTxnBufSize) {
         return ZX_ERR_INVALID_ARGS;
     }
     if (tx_descriptors_[curr_tx_buf_].txrx_status & DESC_TXSTS_OWNBYDMA) {
@@ -608,10 +609,10 @@
     }
     uint8_t* temptr = &tx_buffer_[curr_tx_buf_ * kTxnBufSize];
 
-    memcpy(temptr, netbuf->data, netbuf->len);
+    memcpy(temptr, netbuf->data_buffer, netbuf->data_size);
     hw_mb();
 
-    zx_cache_flush(temptr, netbuf->len, ZX_CACHE_FLUSH_DATA);
+    zx_cache_flush(temptr, netbuf->data_size, ZX_CACHE_FLUSH_DATA);
 
     //Descriptors are pre-iniitialized with the paddr of their corresponding
     // buffers, only need to setup the control and status fields.
@@ -620,7 +621,7 @@
         DESC_TXCTRL_TXLAST |
         DESC_TXCTRL_TXFIRST |
         DESC_TXCTRL_TXCHAIN |
-        (netbuf->len & DESC_TXCTRL_SIZE1MASK);
+        ((uint32_t)netbuf->data_size & DESC_TXCTRL_SIZE1MASK);
 
     tx_descriptors_[curr_tx_buf_].txrx_status = DESC_TXSTS_OWNBYDMA;
     curr_tx_buf_ = (curr_tx_buf_ + 1) % kNumDesc;
@@ -631,7 +632,8 @@
     return ZX_OK;
 }
 
-zx_status_t AmlDWMacDevice::EthmacSetParam(uint32_t param, int32_t value, void* data) {
+zx_status_t AmlDWMacDevice::EthmacSetParam(uint32_t param, int32_t value, const void* data,
+                                           size_t data_size) {
     zxlogf(INFO, "SetParam called  %x  %x\n", param, value);
     return ZX_OK;
 }
diff --git a/system/dev/ethernet/aml-dwmac/aml-dwmac.h b/system/dev/ethernet/aml-dwmac/aml-dwmac.h
index f9e4bcd..94fcf4e 100644
--- a/system/dev/ethernet/aml-dwmac/aml-dwmac.h
+++ b/system/dev/ethernet/aml-dwmac/aml-dwmac.h
@@ -92,9 +92,9 @@
 
     zx_status_t EthmacQuery(uint32_t options, ethmac_info_t* info);
     void EthmacStop() __TA_EXCLUDES(lock_);
-    zx_status_t EthmacStart(fbl::unique_ptr<ddk::EthmacIfcProxy> proxy) __TA_EXCLUDES(lock_);
+    zx_status_t EthmacStart(const ethmac_ifc_t* ifc) __TA_EXCLUDES(lock_);
     zx_status_t EthmacQueueTx(uint32_t options, ethmac_netbuf_t* netbuf) __TA_EXCLUDES(lock_);
-    zx_status_t EthmacSetParam(uint32_t param, int32_t value, void* data);
+    zx_status_t EthmacSetParam(uint32_t param, int32_t value, const void* data, size_t data_size);
     zx_status_t MDIOWrite(uint32_t reg, uint32_t val);
     zx_status_t MDIORead(uint32_t reg, uint32_t* val);
     zx_handle_t EthmacGetBti();
diff --git a/system/dev/ethernet/asix-88179/asix-88179.c b/system/dev/ethernet/asix-88179/asix-88179.c
index 5a8f3ae..1fc2fc2 100644
--- a/system/dev/ethernet/asix-88179/asix-88179.c
+++ b/system/dev/ethernet/asix-88179/asix-88179.c
@@ -85,8 +85,7 @@
     uint64_t rx_endpoint_delay;    // wait time between 2 recv requests
     uint64_t tx_endpoint_delay;    // wait time between 2 transmit requests
     // callback interface to attached ethernet layer
-    ethmac_ifc_t* ifc;
-    void* cookie;
+    ethmac_ifc_t ifc;
 
     thrd_t thread;
     mtx_t mutex;
@@ -297,7 +296,7 @@
         }
         if (!drop) {
             zxlogf(SPEW, "offset = %zd\n", offset);
-            eth->ifc->recv(eth->cookie, read_data + offset + 2, pkt_len - 2, 0);
+            ethmac_ifc_recv(&eth->ifc, read_data + offset + 2, pkt_len - 2, 0);
         }
 
         // Advance past this packet in the completed read
@@ -327,7 +326,7 @@
             eth->rx_endpoint_delay += ETHMAC_RECV_DELAY;
         }
         usb_reset_endpoint(&eth->usb, eth->bulk_in_addr);
-    } else if ((request->response.status == ZX_OK) && eth->ifc) {
+    } else if ((request->response.status == ZX_OK) && eth->ifc.ops) {
         ax88179_recv(eth, request);
     }
 
@@ -343,15 +342,15 @@
 static zx_status_t ax88179_append_to_tx_req(usb_protocol_t* usb, usb_request_t* req,
                                             ethmac_netbuf_t* netbuf) {
     zx_off_t offset = ALIGN(req->header.length, 4);
-    if (offset + sizeof(ax88179_tx_hdr_t) + netbuf->len > USB_BUF_SIZE) {
+    if (offset + sizeof(ax88179_tx_hdr_t) + netbuf->data_size > USB_BUF_SIZE) {
         return ZX_ERR_BUFFER_TOO_SMALL;
     }
     ax88179_tx_hdr_t hdr = {
-        .tx_len = htole16(netbuf->len),
+        .tx_len = htole16(netbuf->data_size),
     };
     usb_req_copy_to(usb, req, &hdr, sizeof(hdr), offset);
-    usb_req_copy_to(usb, req, netbuf->data, netbuf->len, offset + sizeof(hdr));
-    req->header.length = offset + sizeof(hdr) + netbuf->len;
+    usb_req_copy_to(usb, req, netbuf->data_buffer, netbuf->data_size, offset + sizeof(hdr));
+    req->header.length = offset + sizeof(hdr) + netbuf->data_size;
     return ZX_OK;
 }
 
@@ -376,8 +375,8 @@
                                                                next_netbuf) == ZX_OK) {
             list_remove_head_type(&eth->pending_netbuf, ethmac_netbuf_t, node);
             mtx_lock(&eth->mutex);
-            if (eth->ifc) {
-                eth->ifc->complete_tx(eth->cookie, next_netbuf, ZX_OK);
+            if (eth->ifc.ops) {
+                ethmac_ifc_complete_tx(&eth->ifc, next_netbuf, ZX_OK);
             }
             mtx_unlock(&eth->mutex);
             next_netbuf = list_peek_head_type(&eth->pending_netbuf, ethmac_netbuf_t, node);
@@ -442,13 +441,13 @@
                     usb_request_queue(&eth->usb, req);
                 }
                 zxlogf(TRACE, "ax88179 now online\n");
-                if (eth->ifc) {
-                    eth->ifc->status(eth->cookie, ETH_STATUS_ONLINE);
+                if (eth->ifc.ops) {
+                    ethmac_ifc_status(&eth->ifc, ETH_STATUS_ONLINE);
                 }
             } else if (!online && was_online) {
                 zxlogf(TRACE, "ax88179 now offline\n");
-                if (eth->ifc) {
-                    eth->ifc->status(eth->cookie, 0);
+                if (eth->ifc.ops) {
+                    ethmac_ifc_status(&eth->ifc, 0);
                 }
             }
         }
@@ -458,7 +457,7 @@
 }
 
 static zx_status_t ax88179_queue_tx(void* ctx, uint32_t options, ethmac_netbuf_t* netbuf) {
-    size_t length = netbuf->len;
+    size_t length = netbuf->data_size;
 
     if (length > (AX88179_MTU + MAX_ETH_HDRS)) {
         zxlogf(ERROR, "ax88179: unsupported packet length %zu\n", length);
@@ -589,21 +588,20 @@
 static void ax88179_stop(void* ctx) {
     ax88179_t* eth = ctx;
     mtx_lock(&eth->mutex);
-    eth->ifc = NULL;
+    eth->ifc.ops = NULL;
     mtx_unlock(&eth->mutex);
 }
 
-static zx_status_t ax88179_start(void* ctx, ethmac_ifc_t* ifc, void* cookie) {
+static zx_status_t ax88179_start(void* ctx, const ethmac_ifc_t* ifc) {
     ax88179_t* eth = ctx;
     zx_status_t status = ZX_OK;
 
     mtx_lock(&eth->mutex);
-    if (eth->ifc) {
+    if (eth->ifc.ops) {
         status = ZX_ERR_BAD_STATE;
     } else {
-        eth->ifc = ifc;
-        eth->cookie = cookie;
-        eth->ifc->status(eth->cookie, eth->online ? ETH_STATUS_ONLINE : 0);
+        eth->ifc = *ifc;
+        ethmac_ifc_status(&eth->ifc, eth->online ? ETH_STATUS_ONLINE : 0);
     }
     mtx_unlock(&eth->mutex);
 
@@ -648,7 +646,7 @@
 }
 
 static zx_status_t ax88179_set_multicast_filter(ax88179_t* eth, int32_t n_addresses,
-                                                uint8_t* address_bytes) {
+                                                const uint8_t* address_bytes, size_t address_size) {
     zx_status_t status = ZX_OK;
     eth->multicast_filter_overflow = (n_addresses == ETHMAC_MULTICAST_FILTER_OVERFLOW) ||
         (n_addresses > MAX_MULTICAST_FILTER_ADDRS);
@@ -656,6 +654,8 @@
         status = ax88179_set_multicast_promisc(eth, true);
         return status;
     }
+    if (address_size < n_addresses * ETH_MAC_SIZE)
+        return ZX_ERR_OUT_OF_RANGE;
 
     uint8_t filter[MULTICAST_FILTER_NBYTES];
     memset(filter, 0, MULTICAST_FILTER_NBYTES);
@@ -671,7 +671,8 @@
 }
 
 static void ax88179_dump_regs(ax88179_t* eth);
-static zx_status_t ax88179_set_param(void *ctx, uint32_t param, int32_t value, void* data) {
+static zx_status_t ax88179_set_param(void *ctx, uint32_t param, int32_t value, const void* data,
+                                     size_t data_size) {
     ax88179_t* eth = ctx;
     zx_status_t status = ZX_OK;
 
@@ -685,7 +686,7 @@
         status = ax88179_set_multicast_promisc(eth, (bool)value);
         break;
     case ETHMAC_SETPARAM_MULTICAST_FILTER:
-        status = ax88179_set_multicast_filter(eth, value, (uint8_t*)data);
+        status = ax88179_set_multicast_filter(eth, value, (const uint8_t*)data, data_size);
         break;
     case ETHMAC_SETPARAM_DUMP_REGS:
         ax88179_dump_regs(eth);
diff --git a/system/dev/ethernet/asix-88772b/asix-88772b.c b/system/dev/ethernet/asix-88772b/asix-88772b.c
index 885da38..28af44c 100644
--- a/system/dev/ethernet/asix-88772b/asix-88772b.c
+++ b/system/dev/ethernet/asix-88772b/asix-88772b.c
@@ -65,8 +65,7 @@
     uint64_t tx_endpoint_delay;    // wait time between 2 transmit requests
 
     // callback interface to attached ethernet layer
-    ethmac_ifc_t* ifc;
-    void* cookie;
+    ethmac_ifc_t ifc;
 
     mtx_t mutex;
 } ax88772b_t;
@@ -177,7 +176,7 @@
             return;
         }
 
-        eth->ifc->recv(eth->cookie, pkt, length1, 0);
+        ethmac_ifc_recv(&eth->ifc, pkt, length1, 0);
         pkt += length1;
         len -= length1;
 
@@ -194,7 +193,7 @@
 
 // Send a netbuf to the USB interface using the provided request
 static zx_status_t ax88772b_send(ax88772b_t* eth, usb_request_t* request, ethmac_netbuf_t* netbuf) {
-    size_t length = netbuf->len;
+    size_t length = netbuf->data_size;
 
     if (length + ETH_HEADER_SIZE > USB_BUF_OUT_SIZE) {
         zxlogf(ERROR, "ax88772b: unsupported packet length %zu\n", length);
@@ -211,7 +210,7 @@
     header[3] = hi ^ 0xFF;
 
     usb_req_copy_to(&eth->usb, request, header, ETH_HEADER_SIZE, 0);
-    usb_req_copy_to(&eth->usb, request, netbuf->data, length, ETH_HEADER_SIZE);
+    usb_req_copy_to(&eth->usb, request, netbuf->data_buffer, length, ETH_HEADER_SIZE);
     request->header.length = length + ETH_HEADER_SIZE;
 
     zx_nanosleep(zx_deadline_after(ZX_USEC(eth->tx_endpoint_delay)));
@@ -238,7 +237,7 @@
             eth->rx_endpoint_delay += ETHMAC_RECV_DELAY;
         }
         usb_reset_endpoint(&eth->usb, eth->bulk_in_addr);
-    } else if ((request->response.status == ZX_OK) && eth->ifc) {
+    } else if ((request->response.status == ZX_OK) && eth->ifc.ops) {
         ax88772b_recv(eth, request);
     }
 
@@ -265,8 +264,8 @@
         ethmac_netbuf_t* netbuf = list_remove_head_type(&eth->pending_netbufs, ethmac_netbuf_t,
                                                         node);
         zx_status_t send_result = ax88772b_send(eth, request, netbuf);
-        if (eth->ifc) {
-            eth->ifc->complete_tx(eth->cookie, netbuf, send_result);
+        if (eth->ifc.ops) {
+            ethmac_ifc_complete_tx(&eth->ifc, netbuf, send_result);
         }
     } else {
         list_add_tail(&eth->free_write_reqs, &request->node);
@@ -310,8 +309,8 @@
             bool was_online = eth->online;
             eth->online = online;
             if (online && !was_online) {
-                if (eth->ifc) {
-                    eth->ifc->status(eth->cookie, ETH_STATUS_ONLINE);
+                if (eth->ifc.ops) {
+                    ethmac_ifc_status(&eth->ifc, ETH_STATUS_ONLINE);
                 }
 
                 // Now that we are online, queue all our read requests
@@ -322,8 +321,8 @@
                     usb_request_queue(&eth->usb, req);
                 }
             } else if (!online && was_online) {
-                if (eth->ifc) {
-                    eth->ifc->status(eth->cookie, 0);
+                if (eth->ifc.ops) {
+                    ethmac_ifc_status(&eth->ifc, 0);
                 }
             }
         }
@@ -415,21 +414,20 @@
 static void ax88772b_stop(void* ctx) {
     ax88772b_t* eth = ctx;
     mtx_lock(&eth->mutex);
-    eth->ifc = NULL;
+    eth->ifc.ops = NULL;
     mtx_unlock(&eth->mutex);
 }
 
-static zx_status_t ax88772b_start(void* ctx, ethmac_ifc_t* ifc, void* cookie) {
+static zx_status_t ax88772b_start(void* ctx, const ethmac_ifc_t* ifc) {
     ax88772b_t* eth = ctx;
     zx_status_t status = ZX_OK;
 
     mtx_lock(&eth->mutex);
-    if (eth->ifc) {
+    if (eth->ifc.ops) {
         status = ZX_ERR_BAD_STATE;
     } else {
-        eth->ifc = ifc;
-        eth->cookie = cookie;
-        eth->ifc->status(eth->cookie, eth->online ? ETH_STATUS_ONLINE : 0);
+        eth->ifc = *ifc;
+        ethmac_ifc_status(&eth->ifc, eth->online ? ETH_STATUS_ONLINE : 0);
     }
     mtx_unlock(&eth->mutex);
 
@@ -456,7 +454,8 @@
     return status;
 }
 
-static zx_status_t ax88772b_set_param(void *ctx, uint32_t param, int32_t value, void* data) {
+static zx_status_t ax88772b_set_param(void *ctx, uint32_t param, int32_t value, const void* data,
+                                      size_t data_size) {
     ax88772b_t* eth = ctx;
     zx_status_t status = ZX_OK;
 
diff --git a/system/dev/ethernet/ethernet/ethernet.c b/system/dev/ethernet/ethernet/ethernet.c
index 97e19ab..4bedecc 100644
--- a/system/dev/ethernet/ethernet/ethernet.c
+++ b/system/dev/ethernet/ethernet/ethernet.c
@@ -155,7 +155,7 @@
         (*requesters_count)++;
         edev->state |= state_bit;
         if (*requesters_count == 1) {
-            status = edev0->mac.ops->set_param(edev0->mac.ctx, param_id, true, NULL);
+            status = ethmac_set_param(&edev0->mac, param_id, true, NULL, 0);
             if (status != ZX_OK) {
                 (*requesters_count)--;
                 edev->state &= ~state_bit;
@@ -165,7 +165,7 @@
         (*requesters_count)--;
         edev->state &= ~state_bit;
         if (*requesters_count == 0) {
-            status = edev0->mac.ops->set_param(edev0->mac.ctx, param_id, false, NULL);
+            status = ethmac_set_param(&edev0->mac, param_id, false, NULL, 0);
             if (status != ZX_OK) {
                 (*requesters_count)++;
                 edev->state |= state_bit;
@@ -195,15 +195,15 @@
     list_for_every_entry(&edev0->list_active, edev_i, ethdev_t, node) {
         for (uint32_t i = 0; i < edev_i->n_multicast; i++) {
             if (n_multicast == MULTICAST_LIST_LIMIT) {
-                return edev0->mac.ops->set_param(edev0->mac.ctx, ETHMAC_SETPARAM_MULTICAST_FILTER,
-                                                 ETHMAC_MULTICAST_FILTER_OVERFLOW, NULL);
+                return ethmac_set_param(&edev0->mac, ETHMAC_SETPARAM_MULTICAST_FILTER,
+                                        ETHMAC_MULTICAST_FILTER_OVERFLOW, NULL, 0);
             }
             memcpy(multicast[n_multicast], edev_i->multicast[i], ETH_MAC_SIZE);
             n_multicast++;
         }
     }
-    return edev0->mac.ops->set_param(edev0->mac.ctx, ETHMAC_SETPARAM_MULTICAST_FILTER,
-                                     n_multicast, multicast);
+    return ethmac_set_param(&edev0->mac, ETHMAC_SETPARAM_MULTICAST_FILTER, n_multicast, multicast,
+                            n_multicast * ETH_MAC_SIZE);
 }
 
 static int eth_multicast_addr_index(ethdev_t* edev, uint8_t* mac) {
@@ -228,8 +228,8 @@
         return eth_rebuild_multicast_filter_locked(edev);
     } else {
         ethdev0_t* edev0 = edev->edev0;
-        return edev0->mac.ops->set_param(edev0->mac.ctx, ETHMAC_SETPARAM_MULTICAST_FILTER,
-                                         ETHMAC_MULTICAST_FILTER_OVERFLOW, NULL);
+        return ethmac_set_param(&edev0->mac, ETHMAC_SETPARAM_MULTICAST_FILTER,
+                                ETHMAC_MULTICAST_FILTER_OVERFLOW, NULL, 0);
     }
     return ZX_OK;
 }
@@ -272,8 +272,7 @@
                "MULTICAST_TEST_FILTER invoked. Turning multicast-promisc off unconditionally.\n");
         return eth_test_clear_multicast_promisc_locked(edev);
     case ETH_MULTICAST_DUMP_REGS:
-        return edev->edev0->mac.ops->set_param(edev->edev0->mac.ctx,
-                                               ETHMAC_SETPARAM_DUMP_REGS, 0, NULL);
+        return ethmac_set_param(&edev->edev0->mac, ETHMAC_SETPARAM_DUMP_REGS, 0, NULL, 0);
     default:
         return ZX_ERR_INVALID_ARGS;
     }
@@ -362,7 +361,7 @@
 
 // TODO: I think if this arrives at the wrong time during teardown we
 // can deadlock with the ethermac device
-static void eth0_recv(void* cookie, void* data, size_t len, uint32_t flags) {
+static void eth0_recv(void* cookie, const void* data, size_t len, uint32_t flags) {
     ethdev0_t* edev0 = cookie;
 
     ethdev_t* edev;
@@ -394,8 +393,8 @@
 static void eth0_complete_tx(void* cookie, ethmac_netbuf_t* netbuf, zx_status_t status) {
     tx_info_t* tx_info = containerof(netbuf, tx_info_t, netbuf);
     ethdev_t* edev = tx_info->edev;
-    eth_fifo_entry_t entry = {.offset = netbuf->data - edev->io_buf,
-                              .length = netbuf->len,
+    eth_fifo_entry_t entry = {.offset = netbuf->data_buffer - edev->io_buf,
+                              .length = netbuf->data_size,
                               .flags = status == ZX_OK ? ETH_FIFO_TX_OK : 0,
                               .cookie = tx_info->fifo_cookie};
 
@@ -407,7 +406,7 @@
     tx_fifo_write(edev, &entry, 1);
 }
 
-static ethmac_ifc_t ethmac_ifc = {
+static ethmac_ifc_ops_t ethmac_ifc = {
     .status = eth0_status,
     .recv = eth0_recv,
     .complete_tx = eth0_complete_tx,
@@ -480,14 +479,14 @@
             if (opts) {
                 zxlogf(SPEW, "setting OPT_MORE (%u packets to go)\n", count);
             }
-            tx_info->netbuf.data = edev->io_buf + e->offset;
+            tx_info->netbuf.data_buffer = edev->io_buf + e->offset;
             if (edev0->info.features & ETHMAC_FEATURE_DMA) {
                 tx_info->netbuf.phys = edev->paddr_map[e->offset / PAGE_SIZE] +
                                        (e->offset & PAGE_MASK);
             }
-            tx_info->netbuf.len = e->length;
+            tx_info->netbuf.data_size = e->length;
             tx_info->fifo_cookie = e->cookie;
-            status = edev0->mac.ops->queue_tx(edev0->mac.ctx, opts, &tx_info->netbuf);
+            status = ethmac_queue_tx(&edev0->mac, opts, &tx_info->netbuf);
             if (edev->state & ETHDEV_TX_LOOPBACK) {
                 eth_tx_echo(edev0, edev->io_buf + e->offset, e->length);
             }
@@ -630,7 +629,7 @@
             status = ZX_ERR_NO_MEMORY;
             goto fail;
         }
-        zx_handle_t bti = edev->edev0->mac.ops->get_bti(edev->edev0->mac.ctx);
+        zx_handle_t bti = ethmac_get_bti(&edev->edev0->mac);
         if ((status = zx_bti_pin(bti, ZX_BTI_PERM_READ | ZX_BTI_PERM_WRITE,
                                  vmo, 0, size, edev->paddr_map, pages, &edev->pmt)) != ZX_OK) {
             zxlogf(ERROR, "eth [%s]: bti_pin failed, can't pin vmo: %d\n",
@@ -692,7 +691,7 @@
         // Re-acquire lock afterwards. Set busy to prevent problems with other ioctls.
         edev0->state |= ETHDEV0_BUSY;
         mtx_unlock(&edev0->lock);
-        status = edev0->mac.ops->start(edev0->mac.ctx, &ethmac_ifc, edev0);
+        status = ethmac_start(&edev->edev0->mac, &(ethmac_ifc_t){&ethmac_ifc, edev0});
         mtx_lock(&edev0->lock);
         edev0->state &= ~ETHDEV0_BUSY;
     } else {
@@ -733,7 +732,7 @@
                 // Re-acquire lock afterwards. Set busy to prevent problems with other ioctls.
                 edev0->state |= ETHDEV0_BUSY;
                 mtx_unlock(&edev0->lock);
-                edev0->mac.ops->stop(edev0->mac.ctx);
+                ethmac_stop(&edev->edev0->mac);
                 mtx_lock(&edev0->lock);
                 edev0->state &= ~ETHDEV0_BUSY;
             }
@@ -1130,7 +1129,7 @@
         goto fail;
     }
 
-    if ((status = edev0->mac.ops->query(edev0->mac.ctx, 0, &edev0->info)) < 0) {
+    if ((status = ethmac_query(&edev0->mac, 0, &edev0->info)) < 0) {
         zxlogf(ERROR, "eth: bind: ethermac query failed: %d\n", status);
         goto fail;
     }
diff --git a/system/dev/ethernet/ethertap/ethertap.cpp b/system/dev/ethernet/ethertap/ethertap.cpp
index 5cbe84b..915522c 100644
--- a/system/dev/ethernet/ethertap/ethertap.cpp
+++ b/system/dev/ethernet/ethertap/ethertap.cpp
@@ -9,6 +9,7 @@
 #include <fbl/type_support.h>
 #include <pretty/hexdump.h>
 #include <zircon/compiler.h>
+#include <zircon/device/ethernet.h>
 
 #include <stdio.h>
 #include <string.h>
@@ -124,13 +125,13 @@
     ethmac_proxy_.reset();
 }
 
-zx_status_t TapDevice::EthmacStart(fbl::unique_ptr<ddk::EthmacIfcProxy> proxy) {
+zx_status_t TapDevice::EthmacStart(const ethmac_ifc_t* ifc) {
     ethertap_trace("EthmacStart\n");
     fbl::AutoLock lock(&lock_);
     if (ethmac_proxy_ != nullptr) {
         return ZX_ERR_ALREADY_BOUND;
     } else {
-        ethmac_proxy_.swap(proxy);
+        ethmac_proxy_ = fbl::make_unique<ddk::EthmacIfcProxy>(ifc);
         ethmac_proxy_->Status(online_ ? ETH_STATUS_ONLINE : 0u);
     }
     return ZX_OK;
@@ -144,9 +145,9 @@
     uint8_t temp_buf[ETHERTAP_MAX_MTU + sizeof(ethertap_socket_header_t)];
     auto header = reinterpret_cast<ethertap_socket_header*>(temp_buf);
     uint8_t* data = temp_buf + sizeof(ethertap_socket_header_t);
-    size_t length = netbuf->len;
+    size_t length = netbuf->data_size;
     ZX_DEBUG_ASSERT(length <= mtu_);
-    memcpy(data, netbuf->data, length);
+    memcpy(data, netbuf->data_buffer, length);
     header->type = ETHERTAP_MSG_PACKET;
 
     if (unlikely(options_ & ETHERTAP_OPT_TRACE_PACKETS)) {
@@ -162,7 +163,8 @@
     return status == ZX_ERR_SHOULD_WAIT ? ZX_ERR_UNAVAILABLE : status;
 }
 
-zx_status_t TapDevice::EthmacSetParam(uint32_t param, int32_t value, void* data) {
+zx_status_t TapDevice::EthmacSetParam(uint32_t param, int32_t value, const void* data,
+                                      size_t data_size) {
     fbl::AutoLock lock(&lock_);
     if (!(options_ & ETHERTAP_OPT_REPORT_PARAM) || dead_) {
         return ZX_ERR_NOT_SUPPORTED;
@@ -185,7 +187,7 @@
         // Send the final byte of each address, sorted lowest-to-highest.
         uint32_t i;
         for (i = 0; i < static_cast<uint32_t>(value) && i < sizeof(send_buf.report.data); i++) {
-            send_buf.report.data[i] = static_cast<uint8_t*>(data)[i * ETH_MAC_SIZE + 5];
+            send_buf.report.data[i] = static_cast<const uint8_t*>(data)[i * ETH_MAC_SIZE + 5];
         }
         send_buf.report.data_length = i;
         qsort(send_buf.report.data, send_buf.report.data_length, 1,
diff --git a/system/dev/ethernet/ethertap/ethertap.h b/system/dev/ethernet/ethertap/ethertap.h
index a111f55..b675e3a 100644
--- a/system/dev/ethernet/ethertap/ethertap.h
+++ b/system/dev/ethernet/ethertap/ethertap.h
@@ -38,9 +38,10 @@
 
     zx_status_t EthmacQuery(uint32_t options, ethmac_info_t* info);
     void EthmacStop();
-    zx_status_t EthmacStart(fbl::unique_ptr<ddk::EthmacIfcProxy> proxy);
+    zx_status_t EthmacStart(const ethmac_ifc_t* ifc);
     zx_status_t EthmacQueueTx(uint32_t options, ethmac_netbuf_t* netbuf);
-    zx_status_t EthmacSetParam(uint32_t param, int32_t value, void* data);
+    zx_status_t EthmacSetParam(uint32_t param, int32_t value, const void* data,
+                                  size_t data_size);
     // No DMA capability, so return invalid handle for get_bti
     zx_handle_t EthmacGetBti();
     int Thread();
diff --git a/system/dev/ethernet/rndis/rndishost.c b/system/dev/ethernet/rndis/rndishost.c
index 50b4895..5d99305 100644
--- a/system/dev/ethernet/rndis/rndishost.c
+++ b/system/dev/ethernet/rndis/rndishost.c
@@ -11,6 +11,7 @@
 #include <ddk/protocol/ethernet.h>
 #include <ddk/protocol/usb.h>
 #include <ddk/usb/usb.h>
+#include <zircon/device/ethernet.h>
 #include <zircon/hw/usb-cdc.h>
 #include <zircon/hw/usb.h>
 #include <zircon/listnode.h>
@@ -53,8 +54,7 @@
     uint64_t tx_endpoint_delay;    // wait time between 2 transmit requests
 
     // Interface to the ethernet layer.
-    ethmac_ifc_t* ifc;
-    void* cookie;
+    ethmac_ifc_t ifc;
 
     mtx_t mutex;
 } rndishost_t;
@@ -136,7 +136,7 @@
         }
         usb_reset_endpoint(&eth->usb, eth->bulk_in_addr);
     }
-    if ((request->response.status == ZX_OK) && eth->ifc) {
+    if ((request->response.status == ZX_OK) && eth->ifc.ops) {
         size_t len = request->response.actual;
 
         uint8_t* read_data;
@@ -147,7 +147,7 @@
             return;
         }
 
-        eth->ifc->recv(eth->cookie, read_data, len, 0);
+        ethmac_ifc_recv(&eth->ifc, read_data, len, 0);
     }
 
     // TODO: Only usb_request_queue if the device is online.
@@ -216,22 +216,21 @@
 static void rndishost_stop(void* ctx) {
     rndishost_t* eth = (rndishost_t*)ctx;
     mtx_lock(&eth->mutex);
-    eth->ifc = NULL;
+    eth->ifc.ops = NULL;
     mtx_unlock(&eth->mutex);
 }
 
-static zx_status_t rndishost_start(void* ctx, ethmac_ifc_t* ifc, void* cookie) {
+static zx_status_t rndishost_start(void* ctx, const ethmac_ifc_t* ifc) {
     rndishost_t* eth = (rndishost_t*)ctx;
     zx_status_t status = ZX_OK;
 
     mtx_lock(&eth->mutex);
-    if (eth->ifc) {
+    if (eth->ifc.ops) {
         status = ZX_ERR_ALREADY_BOUND;
     } else {
-        eth->ifc = ifc;
-        eth->cookie = cookie;
+        eth->ifc = *ifc;
         // TODO: Check that the device is online before sending ETH_STATUS_ONLINE.
-        eth->ifc->status(eth->cookie, ETH_STATUS_ONLINE);
+        ethmac_ifc_status(&eth->ifc, ETH_STATUS_ONLINE);
     }
     mtx_unlock(&eth->mutex);
 
@@ -239,9 +238,9 @@
 }
 
 static zx_status_t rndishost_queue_tx(void* ctx, uint32_t options, ethmac_netbuf_t* netbuf) {
-    size_t length = netbuf->len;
+    size_t length = netbuf->data_size;
     rndishost_t* eth = (rndishost_t*)ctx;
-    uint8_t* byte_data = netbuf->data;
+    uint8_t* byte_data = netbuf->data_buffer;
     zx_status_t status = ZX_OK;
 
     mtx_lock(&eth->mutex);
@@ -292,7 +291,8 @@
     rndishost_free(eth);
 }
 
-static zx_status_t rndishost_set_param(void *ctx, uint32_t param, int32_t value, void* data) {
+static zx_status_t rndishost_set_param(void *ctx, uint32_t param, int32_t value, const void* data,
+                                       size_t data_size) {
     return ZX_ERR_NOT_SUPPORTED;
 }
 
@@ -509,7 +509,7 @@
     eth->bulk_in_addr = bulk_in_addr;
     eth->bulk_out_addr = bulk_out_addr;
     eth->intr_addr = intr_addr;
-    eth->ifc = NULL;
+    eth->ifc.ops = NULL;
     memcpy(&eth->usb, &usb, sizeof(eth->usb));
 
     for (int i = 0; i < READ_REQ_COUNT; i++) {
diff --git a/system/dev/ethernet/usb-cdc-ecm/usb-cdc-ecm.c b/system/dev/ethernet/usb-cdc-ecm/usb-cdc-ecm.c
index d224113..e7e999e 100644
--- a/system/dev/ethernet/usb-cdc-ecm/usb-cdc-ecm.c
+++ b/system/dev/ethernet/usb-cdc-ecm/usb-cdc-ecm.c
@@ -9,6 +9,7 @@
 #include <ddk/protocol/ethernet.h>
 #include <ddk/protocol/usb.h>
 #include <ddk/usb/usb.h>
+#include <zircon/device/ethernet.h>
 #include <zircon/hw/usb-cdc.h>
 #include <lib/sync/completion.h>
 
@@ -44,8 +45,7 @@
     usb_protocol_t usb;
 
     mtx_t ethmac_mutex;
-    ethmac_ifc_t* ethmac_ifc;
-    void* ethmac_cookie;
+    ethmac_ifc_t ethmac_ifc;
 
     // Device attributes
     uint8_t mac_addr[ETH_MAC_SIZE];
@@ -81,11 +81,11 @@
 
     mtx_lock(&ctx->tx_mutex);
     ctx->unbound = true;
-    if (ctx->ethmac_ifc) {
+    if (ctx->ethmac_ifc.ops) {
         ethmac_netbuf_t* netbuf;
         while ((netbuf = list_remove_head_type(&ctx->tx_pending_infos, ethmac_netbuf_t, node)) !=
                NULL) {
-            ctx->ethmac_ifc->complete_tx(ctx->ethmac_cookie, netbuf, ZX_ERR_PEER_CLOSED);
+            ethmac_ifc_complete_tx(&ctx->ethmac_ifc, netbuf, ZX_ERR_PEER_CLOSED);
         }
     }
     mtx_unlock(&ctx->tx_mutex);
@@ -130,16 +130,16 @@
     if (is_online) {
         zxlogf(INFO, "%s: connected to network\n", module_name);
         ctx->online = true;
-        if (ctx->ethmac_ifc) {
-            ctx->ethmac_ifc->status(ctx->ethmac_cookie, ETH_STATUS_ONLINE);
+        if (ctx->ethmac_ifc.ops) {
+            ethmac_ifc_status(&ctx->ethmac_ifc, ETH_STATUS_ONLINE);
         } else {
             zxlogf(ERROR, "%s: not connected to ethermac interface\n", module_name);
         }
     } else {
         zxlogf(INFO, "%s: no connection to network\n", module_name);
         ctx->online = false;
-        if (ctx->ethmac_ifc) {
-            ctx->ethmac_ifc->status(ctx->ethmac_cookie, 0);
+        if (ctx->ethmac_ifc.ops) {
+            ethmac_ifc_status(&ctx->ethmac_ifc, 0);
         }
     }
 
@@ -147,14 +147,15 @@
     mtx_unlock(&ctx->ethmac_mutex);
 }
 
-static zx_status_t ethmac_query(void* ctx, uint32_t options, ethmac_info_t* info) {
+static zx_status_t ecm_ethmac_query(void* ctx, uint32_t options, ethmac_info_t* info) {
     ecm_ctx_t* eth = ctx;
 
     zxlogf(TRACE, "%s: %s called\n", module_name, __FUNCTION__);
 
     // No options are supported
     if (options) {
-        zxlogf(ERROR, "%s: unexpected options (0x%"PRIx32") to ethmac_query\n", module_name, options);
+        zxlogf(ERROR, "%s: unexpected options (0x%"PRIx32") to ecm_ethmac_query\n", module_name,
+               options);
         return ZX_ERR_INVALID_ARGS;
     }
 
@@ -165,26 +166,25 @@
     return ZX_OK;
 }
 
-static void ethmac_stop(void* cookie) {
+static void ecm_ethmac_stop(void* cookie) {
     zxlogf(TRACE, "%s: %s called\n", module_name, __FUNCTION__);
     ecm_ctx_t* ctx = cookie;
     mtx_lock(&ctx->ethmac_mutex);
-    ctx->ethmac_ifc = NULL;
+    ctx->ethmac_ifc.ops = NULL;
     mtx_unlock(&ctx->ethmac_mutex);
 }
 
-static zx_status_t ethmac_start(void* ctx_cookie, ethmac_ifc_t* ifc, void* ethmac_cookie) {
+static zx_status_t ecm_ethmac_start(void* ctx_cookie, const ethmac_ifc_t* ifc) {
     zxlogf(TRACE, "%s: %s called\n", module_name, __FUNCTION__);
     ecm_ctx_t* ctx = ctx_cookie;
     zx_status_t status = ZX_OK;
 
     mtx_lock(&ctx->ethmac_mutex);
-    if (ctx->ethmac_ifc) {
+    if (ctx->ethmac_ifc.ops) {
         status = ZX_ERR_ALREADY_BOUND;
     } else {
-        ctx->ethmac_ifc = ifc;
-        ctx->ethmac_cookie = ethmac_cookie;
-        ctx->ethmac_ifc->status(ethmac_cookie, ctx->online ? ETH_STATUS_ONLINE : 0);
+        ctx->ethmac_ifc = *ifc;
+        ethmac_ifc_status(&ctx->ethmac_ifc, ctx->online ? ETH_STATUS_ONLINE : 0);
     }
     mtx_unlock(&ctx->ethmac_mutex);
 
@@ -203,8 +203,8 @@
 }
 
 static zx_status_t send_locked(ecm_ctx_t* ctx, ethmac_netbuf_t* netbuf) {
-    uint8_t* byte_data = netbuf->data;
-    size_t length = netbuf->len;
+    uint8_t* byte_data = netbuf->data_buffer;
+    size_t length = netbuf->data_size;
 
     // Make sure that we can get all of the tx buffers we need to use
     usb_request_t* tx_req = list_remove_head_type(&ctx->tx_txn_bufs, usb_request_t, node);
@@ -264,8 +264,8 @@
     mtx_unlock(&ctx->tx_mutex);
 
     mtx_lock(&ctx->ethmac_mutex);
-    if (additional_tx_queued && ctx->ethmac_ifc) {
-        ctx->ethmac_ifc->complete_tx(ctx->ethmac_cookie, netbuf, send_status);
+    if (additional_tx_queued && ctx->ethmac_ifc.ops) {
+        ethmac_ifc_complete_tx(&ctx->ethmac_ifc, netbuf, send_status);
     }
     mtx_unlock(&ctx->ethmac_mutex);
 
@@ -287,8 +287,8 @@
     }
 
     mtx_lock(&ctx->ethmac_mutex);
-    if (ctx->ethmac_ifc) {
-        ctx->ethmac_ifc->recv(ctx->ethmac_cookie, read_data, len, 0);
+    if (ctx->ethmac_ifc.ops) {
+        ethmac_ifc_recv(&ctx->ethmac_ifc, read_data, len, 0);
     }
     mtx_unlock(&ctx->ethmac_mutex);
 }
@@ -325,9 +325,9 @@
     usb_request_queue(&ctx->usb, request);
 }
 
-static zx_status_t ethmac_queue_tx(void* cookie, uint32_t options, ethmac_netbuf_t* netbuf) {
+static zx_status_t ecm_ethmac_queue_tx(void* cookie, uint32_t options, ethmac_netbuf_t* netbuf) {
     ecm_ctx_t* ctx = cookie;
-    size_t length = netbuf->len;
+    size_t length = netbuf->data_size;
     zx_status_t status;
 
     if (length > ctx->mtu || length == 0) {
@@ -352,16 +352,17 @@
     return status;
 }
 
-static zx_status_t ethmac_set_param(void *cookie, uint32_t param, int32_t value, void* data) {
+static zx_status_t ecm_ethmac_set_param(void *cookie, uint32_t param, int32_t value,
+                                        const void* data, size_t data_size) {
     return ZX_ERR_NOT_SUPPORTED;
 }
 
 static ethmac_protocol_ops_t ethmac_ops = {
-    .query = ethmac_query,
-    .stop = ethmac_stop,
-    .start = ethmac_start,
-    .queue_tx = ethmac_queue_tx,
-    .set_param = ethmac_set_param,
+    .query = ecm_ethmac_query,
+    .stop = ecm_ethmac_stop,
+    .start = ecm_ethmac_start,
+    .queue_tx = ecm_ethmac_queue_tx,
+    .set_param = ecm_ethmac_set_param,
 };
 
 static void ecm_interrupt_complete(usb_request_t* request, void* cookie) {
diff --git a/system/dev/ethernet/usb-cdc-function/cdc-eth-function.c b/system/dev/ethernet/usb-cdc-function/cdc-eth-function.c
index 6f1dd09..647ff8c 100644
--- a/system/dev/ethernet/usb-cdc-function/cdc-eth-function.c
+++ b/system/dev/ethernet/usb-cdc-function/cdc-eth-function.c
@@ -21,6 +21,7 @@
 #include <zircon/process.h>
 #include <zircon/syscalls.h>
 #include <zircon/device/usb-peripheral.h>
+#include <zircon/device/ethernet.h>
 #include <zircon/hw/usb-cdc.h>
 
 #define BULK_REQ_SIZE   2048
@@ -45,8 +46,7 @@
     uint8_t mac_addr[ETH_MAC_SIZE];
 
     mtx_t ethmac_mutex;
-    ethmac_ifc_t* ethmac_ifc;
-    void* ethmac_cookie;
+    ethmac_ifc_t ethmac_ifc;
     bool online;
 
     mtx_t tx_mutex;
@@ -187,22 +187,21 @@
     zxlogf(TRACE, "%s:\n", __FUNCTION__);
     usb_cdc_t* cdc = cookie;
     mtx_lock(&cdc->ethmac_mutex);
-    cdc->ethmac_ifc = NULL;
+    cdc->ethmac_ifc.ops = NULL;
     mtx_unlock(&cdc->ethmac_mutex);
 }
 
-static zx_status_t cdc_ethmac_start(void* ctx_cookie, ethmac_ifc_t* ifc, void* ethmac_cookie) {
+static zx_status_t cdc_ethmac_start(void* ctx_cookie, const ethmac_ifc_t* ifc) {
     zxlogf(TRACE, "%s:\n", __FUNCTION__);
     usb_cdc_t* cdc = ctx_cookie;
     zx_status_t status = ZX_OK;
 
     mtx_lock(&cdc->ethmac_mutex);
-    if (cdc->ethmac_ifc) {
+    if (cdc->ethmac_ifc.ops) {
         status = ZX_ERR_ALREADY_BOUND;
     } else {
-        cdc->ethmac_ifc = ifc;
-        cdc->ethmac_cookie = ethmac_cookie;
-        cdc->ethmac_ifc->status(ethmac_cookie, cdc->online ? ETH_STATUS_ONLINE : 0);
+        cdc->ethmac_ifc = *ifc;
+        ethmac_ifc_status(&cdc->ethmac_ifc, cdc->online ? ETH_STATUS_ONLINE : 0);
     }
     mtx_unlock(&cdc->ethmac_mutex);
 
@@ -210,8 +209,8 @@
 }
 
 static zx_status_t cdc_send_locked(usb_cdc_t* cdc, ethmac_netbuf_t* netbuf) {
-    uint8_t* byte_data = netbuf->data;
-    size_t length = netbuf->len;
+    uint8_t* byte_data = netbuf->data_buffer;
+    size_t length = netbuf->data_size;
 
     // Make sure that we can get all of the tx buffers we need to use
     usb_request_t* tx_req = list_remove_head_type(&cdc->bulk_in_reqs, usb_request_t, node);
@@ -237,7 +236,7 @@
 
 static zx_status_t cdc_ethmac_queue_tx(void* cookie, uint32_t options, ethmac_netbuf_t* netbuf) {
     usb_cdc_t* cdc = cookie;
-    size_t length = netbuf->len;
+    size_t length = netbuf->data_size;
     zx_status_t status;
 
     if (!cdc->online || length > ETH_MTU || length == 0) {
@@ -261,7 +260,8 @@
     return status;
 }
 
-static zx_status_t ethmac_set_param(void *cookie, uint32_t param, int32_t value, void* data) {
+static zx_status_t cdc_ethmac_set_param(void *cookie, uint32_t param, int32_t value,
+                                        const void* data, size_t data_size) {
     return ZX_ERR_NOT_SUPPORTED;
 }
 
@@ -270,7 +270,7 @@
     .stop = cdc_ethmac_stop,
     .start = cdc_ethmac_start,
     .queue_tx = cdc_ethmac_queue_tx,
-    .set_param = ethmac_set_param,
+    .set_param = cdc_ethmac_set_param,
 };
 
 static void cdc_intr_complete(usb_request_t* req, void* cookie) {
@@ -355,10 +355,10 @@
 
     if (req->response.status == ZX_OK) {
         mtx_lock(&cdc->ethmac_mutex);
-        if (cdc->ethmac_ifc) {
+        if (cdc->ethmac_ifc.ops) {
             uint8_t* data = NULL;
             usb_function_req_mmap(&cdc->function, req, (void*)&data);
-            cdc->ethmac_ifc->recv(cdc->ethmac_cookie, data, req->response.actual, 0);
+            ethmac_ifc_recv(&cdc->ethmac_ifc, data, req->response.actual, 0);
         }
         mtx_unlock(&cdc->ethmac_mutex);
     }
@@ -387,8 +387,8 @@
 
     if (additional_tx_queued) {
         mtx_lock(&cdc->ethmac_mutex);
-        if (cdc->ethmac_ifc) {
-            cdc->ethmac_ifc->complete_tx(cdc->ethmac_cookie, netbuf, send_status);
+        if (cdc->ethmac_ifc.ops) {
+            ethmac_ifc_complete_tx(&cdc->ethmac_ifc, netbuf, send_status);
         }
         mtx_unlock(&cdc->ethmac_mutex);
     }
@@ -423,8 +423,8 @@
 
     mtx_lock(&cdc->ethmac_mutex);
     cdc->online = false;
-    if (cdc->ethmac_ifc) {
-        cdc->ethmac_ifc->status(cdc->ethmac_cookie, 0);
+    if (cdc->ethmac_ifc.ops) {
+        ethmac_ifc_status(&cdc->ethmac_ifc, 0);
     }
     mtx_unlock(&cdc->ethmac_mutex);
 
@@ -484,8 +484,8 @@
 
     mtx_lock(&cdc->ethmac_mutex);
     cdc->online = online;
-    if (cdc->ethmac_ifc) {
-        cdc->ethmac_ifc->status(cdc->ethmac_cookie, online ? ETH_STATUS_ONLINE : 0);
+    if (cdc->ethmac_ifc.ops) {
+        ethmac_ifc_status(&cdc->ethmac_ifc, online ? ETH_STATUS_ONLINE : 0);
     }
     mtx_unlock(&cdc->ethmac_mutex);
 
@@ -505,11 +505,11 @@
 
     mtx_lock(&cdc->tx_mutex);
     cdc->unbound = true;
-    if (cdc->ethmac_ifc) {
+    if (cdc->ethmac_ifc.ops) {
         ethmac_netbuf_t* netbuf;
         while ((netbuf = list_remove_head_type(&cdc->tx_pending_infos, ethmac_netbuf_t, node)) !=
                NULL) {
-            cdc->ethmac_ifc->complete_tx(cdc->ethmac_cookie, netbuf, ZX_ERR_PEER_CLOSED);
+            ethmac_ifc_complete_tx(&cdc->ethmac_ifc, netbuf, ZX_ERR_PEER_CLOSED);
         }
     }
     mtx_unlock(&cdc->tx_mutex);
diff --git a/system/dev/i2c/intel-i2c/intel-i2c-controller.c b/system/dev/i2c/intel-i2c/intel-i2c-controller.c
index 6745f68..cc7e048 100644
--- a/system/dev/i2c/intel-i2c/intel-i2c-controller.c
+++ b/system/dev/i2c/intel-i2c/intel-i2c-controller.c
@@ -6,7 +6,9 @@
 #include <ddk/debug.h>
 #include <ddk/device.h>
 #include <ddk/driver.h>
+#include <ddk/protocol/auxdata.h>
 #include <ddk/protocol/pci.h>
+#include <ddk/protocol/pci-lib.h>
 #include <hw/reg.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -741,17 +743,16 @@
                                        pci_protocol_t* pci) {
     // get child info from aux data, max 4
     // TODO: this seems nonstandard to device model
-    uint8_t childdata[sizeof(auxdata_i2c_device_t) * 4];
+    auxdata_i2c_device_t childdata[4];
     memset(childdata, 0, sizeof(childdata));
 
-    uint32_t actual;
-    zx_status_t status = pci_get_auxdata(pci, "i2c-child", childdata, sizeof(childdata),
-                             &actual);
+    size_t actual;
+    zx_status_t status = pci_get_auxdata(pci, "i2c-child", childdata, sizeof(childdata), &actual);
     if (status != ZX_OK) {
         return;
     }
 
-    auxdata_i2c_device_t* child = (auxdata_i2c_device_t*)childdata;
+    auxdata_i2c_device_t* child = &childdata[0];
     uint32_t count = actual / sizeof(auxdata_i2c_device_t);
     uint32_t bus_speed = 0;
     while (count--) {
diff --git a/system/dev/input/focaltech/ft3x27.cpp b/system/dev/input/focaltech/ft3x27.cpp
index 3badb17..4dd1651 100644
--- a/system/dev/input/focaltech/ft3x27.cpp
+++ b/system/dev/input/focaltech/ft3x27.cpp
@@ -52,7 +52,7 @@
             for (uint i = 0; i < kMaxPoints; i++) {
                 ParseReport(&ft_rpt_.fingers[i], &i2c_buf[i * kFingerRptSize + 1]);
             }
-            if (proxy_.is_valid()) {
+            if (true /*proxy_.is_valid()*/) {
                 proxy_.IoQueue(reinterpret_cast<uint8_t*>(&ft_rpt_), sizeof(ft3x27_touch_t));
             }
         } else {
@@ -125,12 +125,12 @@
     return ZX_OK;
 }
 
-zx_status_t Ft3x27Device::HidBusQuery(uint32_t options, hid_info_t* info) {
+zx_status_t Ft3x27Device::HidbusQuery(uint32_t options, hid_info_t* info) {
     if (!info) {
         return ZX_ERR_INVALID_ARGS;
     }
     info->dev_num = 0;
-    info->dev_class = HID_DEV_CLASS_OTHER;
+    info->device_class = HID_DEVICE_CLASS_OTHER;
     info->boot_device = false;
 
     return ZX_OK;
@@ -151,12 +151,12 @@
     thrd_join(thread_, NULL);
     {
         fbl::AutoLock lock(&proxy_lock_);
-        proxy_.clear();
+        //proxy_.clear();
     }
     return ZX_OK;
 }
 
-zx_status_t Ft3x27Device::HidBusGetDescriptor(uint8_t desc_type, void** data, size_t* len) {
+zx_status_t Ft3x27Device::HidbusGetDescriptor(uint8_t desc_type, void** data, size_t* len) {
 
     const uint8_t* desc_ptr;
     uint8_t* buf;
@@ -171,43 +171,44 @@
     return ZX_OK;
 }
 
-zx_status_t Ft3x27Device::HidBusGetReport(uint8_t rpt_type, uint8_t rpt_id, void* data,
+zx_status_t Ft3x27Device::HidbusGetReport(uint8_t rpt_type, uint8_t rpt_id, void* data,
                                           size_t len, size_t* out_len) {
     return ZX_ERR_NOT_SUPPORTED;
 }
 
-zx_status_t Ft3x27Device::HidBusSetReport(uint8_t rpt_type, uint8_t rpt_id, void* data,
+zx_status_t Ft3x27Device::HidbusSetReport(uint8_t rpt_type, uint8_t rpt_id, const void* data,
                                           size_t len) {
     return ZX_ERR_NOT_SUPPORTED;
 }
 
-zx_status_t Ft3x27Device::HidBusGetIdle(uint8_t rpt_id, uint8_t* duration) {
+zx_status_t Ft3x27Device::HidbusGetIdle(uint8_t rpt_id, uint8_t* duration) {
     return ZX_ERR_NOT_SUPPORTED;
 }
 
-zx_status_t Ft3x27Device::HidBusSetIdle(uint8_t rpt_id, uint8_t duration) {
+zx_status_t Ft3x27Device::HidbusSetIdle(uint8_t rpt_id, uint8_t duration) {
     return ZX_ERR_NOT_SUPPORTED;
 }
 
-zx_status_t Ft3x27Device::HidBusGetProtocol(uint8_t* protocol) {
+zx_status_t Ft3x27Device::HidbusGetProtocol(uint8_t* protocol) {
     return ZX_ERR_NOT_SUPPORTED;
 }
 
-zx_status_t Ft3x27Device::HidBusSetProtocol(uint8_t protocol) {
+zx_status_t Ft3x27Device::HidbusSetProtocol(uint8_t protocol) {
     return ZX_OK;
 }
 
-void Ft3x27Device::HidBusStop() {
+void Ft3x27Device::HidbusStop() {
     fbl::AutoLock lock(&proxy_lock_);
-    proxy_.clear();
+    //proxy_.clear();
 }
 
-zx_status_t Ft3x27Device::HidBusStart(ddk::HidBusIfcProxy proxy) {
+zx_status_t Ft3x27Device::HidbusStart(const hidbus_ifc_t* ifc) {
     fbl::AutoLock lock(&proxy_lock_);
-    if (proxy_.is_valid()) {
+    if (true /*proxy_.is_valid()*/) {
         zxlogf(ERROR, "ft3x27: Already bound!\n");
         return ZX_ERR_ALREADY_BOUND;
     } else {
+        ddk::HidbusIfcProxy proxy(ifc);
         proxy_ = proxy;
         zxlogf(INFO, "ft3x27: started\n");
     }
@@ -235,4 +236,4 @@
 
 extern "C" zx_status_t ft3x27_bind(void* ctx, zx_device_t* device, void** cookie) {
     return ft::Ft3x27Device::Create(device);
-}
\ No newline at end of file
+}
diff --git a/system/dev/input/focaltech/ft3x27.h b/system/dev/input/focaltech/ft3x27.h
index 6c3ffb3..13461ef 100644
--- a/system/dev/input/focaltech/ft3x27.h
+++ b/system/dev/input/focaltech/ft3x27.h
@@ -56,7 +56,7 @@
 
 namespace ft {
 class Ft3x27Device : public ddk::Device<Ft3x27Device, ddk::Unbindable>,
-                     public ddk::HidBusProtocol<Ft3x27Device> {
+                     public ddk::HidbusProtocol<Ft3x27Device> {
 public:
     Ft3x27Device(zx_device_t* device);
 
@@ -65,19 +65,19 @@
     void DdkRelease();
     void DdkUnbind() __TA_EXCLUDES(proxy_lock_);
 
-    // HidBus required methods
-    void HidBusStop();
-    zx_status_t HidBusGetDescriptor(uint8_t desc_type, void** data, size_t* len);
-    zx_status_t HidBusGetReport(uint8_t rpt_type, uint8_t rpt_id, void* data,
+    // Hidbus required methods
+    void HidbusStop();
+    zx_status_t HidbusGetDescriptor(uint8_t desc_type, void** data, size_t* len);
+    zx_status_t HidbusGetReport(uint8_t rpt_type, uint8_t rpt_id, void* data,
                                 size_t len, size_t* out_len);
-    zx_status_t HidBusSetReport(uint8_t rpt_type, uint8_t rpt_id, void* data,
+    zx_status_t HidbusSetReport(uint8_t rpt_type, uint8_t rpt_id, const void* data,
                                 size_t len);
-    zx_status_t HidBusGetIdle(uint8_t rpt_id, uint8_t* duration);
-    zx_status_t HidBusSetIdle(uint8_t rpt_id, uint8_t duration);
-    zx_status_t HidBusGetProtocol(uint8_t* protocol);
-    zx_status_t HidBusSetProtocol(uint8_t protocol);
-    zx_status_t HidBusStart(ddk::HidBusIfcProxy proxy) __TA_EXCLUDES(proxy_lock_);
-    zx_status_t HidBusQuery(uint32_t options, hid_info_t* info) __TA_EXCLUDES(proxy_lock_);
+    zx_status_t HidbusGetIdle(uint8_t rpt_id, uint8_t* duration);
+    zx_status_t HidbusSetIdle(uint8_t rpt_id, uint8_t duration);
+    zx_status_t HidbusGetProtocol(uint8_t* protocol);
+    zx_status_t HidbusSetProtocol(uint8_t protocol);
+    zx_status_t HidbusStart(const hidbus_ifc_t* ifc) __TA_EXCLUDES(proxy_lock_);
+    zx_status_t HidbusQuery(uint32_t options, hid_info_t* info) __TA_EXCLUDES(proxy_lock_);
 
 private:
     //Only one I2c channel is passed to this driver, so index should always
@@ -114,6 +114,6 @@
     fbl::atomic<bool> running_;
 
     fbl::Mutex proxy_lock_;
-    ddk::HidBusIfcProxy proxy_ __TA_GUARDED(proxy_lock_);
+    ddk::HidbusIfcProxy proxy_ __TA_GUARDED(proxy_lock_);
 };
-}
\ No newline at end of file
+}
diff --git a/system/dev/input/hid/hid.c b/system/dev/input/hid/hid.c
index 9b73b46..25b78ad 100644
--- a/system/dev/input/hid/hid.c
+++ b/system/dev/input/hid/hid.c
@@ -90,43 +90,43 @@
     return hid->hid.ops->query(hid->hid.ctx, options, info);
 }
 
-static inline zx_status_t hid_op_start(hid_device_t* hid, hidbus_ifc_t* ifc, void* cookie) {
-    return hid->hid.ops->start(hid->hid.ctx, ifc, cookie);
+static inline zx_status_t hid_op_start(hid_device_t* hid, const hidbus_ifc_t* ifc) {
+    return hidbus_start(&hid->hid, ifc);
 }
 
 static inline void hid_op_stop(hid_device_t* hid) {
-    hid->hid.ops->stop(hid->hid.ctx);
+    hidbus_stop(&hid->hid);
 }
 
 static inline zx_status_t hid_op_get_descriptor(hid_device_t* hid, uint8_t desc_type,
                                                 void** data, size_t* len) {
-    return hid->hid.ops->get_descriptor(hid->hid.ctx, desc_type, data, len);
+    return hidbus_get_descriptor(&hid->hid, desc_type, data, len);
 }
 
 static inline zx_status_t hid_op_get_report(hid_device_t* hid, uint8_t rpt_type, uint8_t rpt_id,
                                             void* data, size_t len, size_t* out_len) {
-    return hid->hid.ops->get_report(hid->hid.ctx, rpt_type, rpt_id, data, len, out_len);
+    return hidbus_get_report(&hid->hid, rpt_type, rpt_id, data, len, out_len);
 }
 
 static inline zx_status_t hid_op_set_report(hid_device_t* hid, uint8_t rpt_type, uint8_t rpt_id,
                                             void* data, size_t len) {
-    return hid->hid.ops->set_report(hid->hid.ctx, rpt_type, rpt_id, data, len);
+    return hidbus_set_report(&hid->hid, rpt_type, rpt_id, data, len);
 }
 
 static inline zx_status_t hid_op_get_idle(hid_device_t* hid, uint8_t rpt_id, uint8_t* duration) {
-    return hid->hid.ops->get_idle(hid->hid.ctx, rpt_id, duration);
+    return hidbus_get_idle(&hid->hid, rpt_id, duration);
 }
 
 static inline zx_status_t hid_op_set_idle(hid_device_t* hid, uint8_t rpt_id, uint8_t duration) {
-    return hid->hid.ops->set_idle(hid->hid.ctx, rpt_id, duration);
+    return hidbus_set_idle(&hid->hid, rpt_id, duration);
 }
 
 static inline zx_status_t hid_op_get_protocol(hid_device_t* hid, uint8_t* protocol) {
-    return hid->hid.ops->get_protocol(hid->hid.ctx, protocol);
+    return hidbus_get_protocol(&hid->hid, protocol);
 }
 
 static inline zx_status_t hid_op_set_protocol(hid_device_t* hid, uint8_t protocol) {
-    return hid->hid.ops->set_protocol(hid->hid.ctx, protocol);
+    return hidbus_set_protocol(&hid->hid, protocol);
 }
 
 
@@ -155,9 +155,10 @@
 
     int* reply = out_buf;
     *reply = INPUT_PROTO_NONE;
-    if (hid->info.dev_class == HID_DEV_CLASS_KBD || hid->info.dev_class == HID_DEV_CLASS_KBD_POINTER) {
+    if (hid->info.device_class == HID_DEVICE_CLASS_KBD ||
+        hid->info.device_class == HID_DEVICE_CLASS_KBD_POINTER) {
         *reply = INPUT_PROTO_KBD;
-    } else if (hid->info.dev_class == HID_DEV_CLASS_POINTER) {
+    } else if (hid->info.device_class == HID_DEVICE_CLASS_POINTER) {
         *reply = INPUT_PROTO_MOUSE;
     }
     *out_actual = sizeof(*reply);
@@ -586,7 +587,7 @@
 #if BOOT_MOUSE_HACK
         // Ignore the HID report descriptor from the device, since we're putting
         // the device into boot protocol mode.
-        if (dev->info.dev_class == HID_DEV_CLASS_POINTER) {
+        if (dev->info.device_class == HID_DEVICE_CLASS_POINTER) {
             if (dev->info.boot_device) {
                 zxlogf(INFO, "hid: boot mouse hack for \"%s\":  "
                        "report count (%zu->1), "
@@ -729,7 +730,8 @@
     .release = hid_release_device,
 };
 
-void hid_io_queue(void* cookie, const uint8_t* buf, size_t len) {
+void hid_io_queue(void* cookie, const void* _buf, size_t len) {
+    const uint8_t* buf = _buf;
     hid_device_t* hid = cookie;
 
     mtx_lock(&hid->instance_lock);
@@ -825,7 +827,7 @@
     mtx_unlock(&hid->instance_lock);
 }
 
-hidbus_ifc_t hid_ifc = {
+hidbus_ifc_ops_t hid_ifc_ops = {
     .io_queue = hid_io_queue,
 };
 
@@ -861,14 +863,14 @@
         }
 
         // Disable numlock
-        if (hiddev->info.dev_class == HID_DEV_CLASS_KBD) {
+        if (hiddev->info.device_class == HID_DEVICE_CLASS_KBD) {
             uint8_t zero = 0;
             hid_op_set_report(hiddev, HID_REPORT_TYPE_OUTPUT, 0, &zero, sizeof(zero));
             // ignore failure for now
         }
     }
 
-    status = hid_op_get_descriptor(hiddev, HID_DESC_TYPE_REPORT,
+    status = hid_op_get_descriptor(hiddev, HID_DESCRIPTION_TYPE_REPORT,
             (void**)&hiddev->hid_report_desc, &hiddev->hid_report_desc_len);
     if (status != ZX_OK) {
         zxlogf(ERROR, "hid: could not retrieve HID report descriptor: %d\n", status);
@@ -903,7 +905,7 @@
     }
 
     // TODO: delay calling start until we've been opened by someone
-    status = hid_op_start(hiddev, &hid_ifc, hiddev);
+    status = hid_op_start(hiddev, &(hidbus_ifc_t){&hid_ifc_ops, hiddev});
     if (status != ZX_OK) {
         zxlogf(ERROR, "hid: could not start hid device: %d\n", status);
         device_remove(hiddev->zxdev);
diff --git a/system/dev/input/hidctl/hidctl.cpp b/system/dev/input/hidctl/hidctl.cpp
index a7f9aba..0cf1ea3 100644
--- a/system/dev/input/hidctl/hidctl.cpp
+++ b/system/dev/input/hidctl/hidctl.cpp
@@ -35,7 +35,7 @@
             return ZX_ERR_INVALID_ARGS;
         }
 
-        if (config->dev_class > HID_DEV_CLASS_LAST) {
+        if (config->dev_class > HID_DEVICE_CLASS_LAST) {
             return ZX_ERR_INVALID_ARGS;
         }
 
@@ -104,41 +104,41 @@
     // The thread will call DdkRemove when it exits the loop.
 }
 
-zx_status_t HidDevice::HidBusQuery(uint32_t options, hid_info_t* info) {
+zx_status_t HidDevice::HidbusQuery(uint32_t options, hid_info_t* info) {
     zxlogf(TRACE, "hidctl: query\n");
 
     info->dev_num = 0;
-    info->dev_class = dev_class_;
+    info->device_class = dev_class_;
     info->boot_device = boot_device_;
     return ZX_OK;
 }
 
-zx_status_t HidDevice::HidBusStart(ddk::HidBusIfcProxy proxy) {
+zx_status_t HidDevice::HidbusStart(const hidbus_ifc_t* ifc) {
     zxlogf(TRACE, "hidctl: start\n");
 
     fbl::AutoLock lock(&lock_);
     if (proxy_.is_valid()) {
         return ZX_ERR_ALREADY_BOUND;
     }
-    proxy_ = proxy;
+    proxy_ = ddk::HidbusIfcProxy(ifc);
     return ZX_OK;
 }
 
-void HidDevice::HidBusStop() {
+void HidDevice::HidbusStop() {
     zxlogf(TRACE, "hidctl: stop\n");
 
     fbl::AutoLock lock(&lock_);
     proxy_.clear();
 }
 
-zx_status_t HidDevice::HidBusGetDescriptor(uint8_t desc_type, void** data, size_t* len) {
+zx_status_t HidDevice::HidbusGetDescriptor(uint8_t desc_type, void** data, size_t* len) {
     zxlogf(TRACE, "hidctl: get descriptor %u\n", desc_type);
 
     if (data == nullptr || len == nullptr) {
         return ZX_ERR_INVALID_ARGS;
     }
 
-    if (desc_type != HID_DESC_TYPE_REPORT) {
+    if (desc_type != HID_DESCRIPTION_TYPE_REPORT) {
         return ZX_ERR_NOT_FOUND;
     }
 
@@ -151,8 +151,8 @@
     return ZX_OK;
 }
 
-zx_status_t HidDevice::HidBusGetReport(uint8_t rpt_type, uint8_t rpt_id, void* data, size_t len,
-                            size_t* out_len) {
+zx_status_t HidDevice::HidbusGetReport(uint8_t rpt_type, uint8_t rpt_id,
+                                       void* data, size_t len, size_t* out_len) {
     zxlogf(TRACE, "hidctl: get report type=%u id=%u\n", rpt_type, rpt_id);
 
     if (out_len == nullptr) {
@@ -163,35 +163,36 @@
     return ZX_ERR_NOT_SUPPORTED;
 }
 
-zx_status_t HidDevice::HidBusSetReport(uint8_t rpt_type, uint8_t rpt_id, void* data, size_t len) {
+zx_status_t HidDevice::HidbusSetReport(uint8_t rpt_type, uint8_t rpt_id,
+                                       const void* data, size_t len) {
     zxlogf(TRACE, "hidctl: set report type=%u id=%u\n", rpt_type, rpt_id);
 
     // TODO: send set report message over socket
     return ZX_ERR_NOT_SUPPORTED;
 }
 
-zx_status_t HidDevice::HidBusGetIdle(uint8_t rpt_id, uint8_t* duration) {
+zx_status_t HidDevice::HidbusGetIdle(uint8_t rpt_id, uint8_t* duration) {
     zxlogf(TRACE, "hidctl: get idle\n");
 
     // TODO: send get idle message over socket
     return ZX_ERR_NOT_SUPPORTED;
 }
 
-zx_status_t HidDevice::HidBusSetIdle(uint8_t rpt_id, uint8_t duration) {
+zx_status_t HidDevice::HidbusSetIdle(uint8_t rpt_id, uint8_t duration) {
     zxlogf(TRACE, "hidctl: set idle\n");
 
     // TODO: send set idle message over socket
     return ZX_OK;
 }
 
-zx_status_t HidDevice::HidBusGetProtocol(uint8_t* protocol) {
+zx_status_t HidDevice::HidbusGetProtocol(uint8_t* protocol) {
     zxlogf(TRACE, "hidctl: get protocol\n");
 
     // TODO: send get protocol message over socket
     return ZX_ERR_NOT_SUPPORTED;
 }
 
-zx_status_t HidDevice::HidBusSetProtocol(uint8_t protocol) {
+zx_status_t HidDevice::HidbusSetProtocol(uint8_t protocol) {
     zxlogf(TRACE, "hidctl: set protocol\n");
 
     // TODO: send set protocol message over socket
diff --git a/system/dev/input/hidctl/hidctl.h b/system/dev/input/hidctl/hidctl.h
index a3d7b94..7714d14 100644
--- a/system/dev/input/hidctl/hidctl.h
+++ b/system/dev/input/hidctl/hidctl.h
@@ -27,24 +27,24 @@
 };
 
 class HidDevice : public ddk::Device<HidDevice, ddk::Unbindable>,
-                  public ddk::HidBusProtocol<HidDevice> {
+                  public ddk::HidbusProtocol<HidDevice> {
   public:
     HidDevice(zx_device_t* device, const hid_ioctl_config* config, zx::socket data);
 
     void DdkRelease();
     void DdkUnbind();
 
-    zx_status_t HidBusQuery(uint32_t options, hid_info_t* info);
-    zx_status_t HidBusStart(ddk::HidBusIfcProxy proxy);
-    void HidBusStop();
-    zx_status_t HidBusGetDescriptor(uint8_t desc_type, void** data, size_t* len);
-    zx_status_t HidBusGetReport(uint8_t rpt_type, uint8_t rpt_id, void* data, size_t len,
+    zx_status_t HidbusQuery(uint32_t options, hid_info_t* info);
+    zx_status_t HidbusStart(const hidbus_ifc_t* ifc);
+    void HidbusStop();
+    zx_status_t HidbusGetDescriptor(uint8_t desc_type, void** data, size_t* len);
+    zx_status_t HidbusGetReport(uint8_t rpt_type, uint8_t rpt_id, void* data, size_t len,
                                 size_t* out_len);
-    zx_status_t HidBusSetReport(uint8_t rpt_type, uint8_t rpt_id, void* data, size_t len);
-    zx_status_t HidBusGetIdle(uint8_t rpt_id, uint8_t* duration);
-    zx_status_t HidBusSetIdle(uint8_t rpt_id, uint8_t duration);
-    zx_status_t HidBusGetProtocol(uint8_t* protocol);
-    zx_status_t HidBusSetProtocol(uint8_t protocol);
+    zx_status_t HidbusSetReport(uint8_t rpt_type, uint8_t rpt_id, const void* data, size_t len);
+    zx_status_t HidbusGetIdle(uint8_t rpt_id, uint8_t* duration);
+    zx_status_t HidbusSetIdle(uint8_t rpt_id, uint8_t duration);
+    zx_status_t HidbusGetProtocol(uint8_t* protocol);
+    zx_status_t HidbusSetProtocol(uint8_t protocol);
 
     int Thread();
     void Shutdown();
@@ -59,7 +59,7 @@
     uint32_t mtu_ = 256;  // TODO: set this based on report_desc_
 
     fbl::Mutex lock_;
-    ddk::HidBusIfcProxy proxy_ __TA_GUARDED(lock_);
+    ddk::HidbusIfcProxy proxy_ __TA_GUARDED(lock_);
     zx::socket data_;
     thrd_t thread_;
 };
diff --git a/system/dev/input/i2c-hid/i2c-hid.c b/system/dev/input/i2c-hid/i2c-hid.c
index 283fe60..17178e2 100644
--- a/system/dev/input/i2c-hid/i2c-hid.c
+++ b/system/dev/input/i2c-hid/i2c-hid.c
@@ -47,7 +47,7 @@
     zx_device_t* i2cdev;
 
     mtx_t ifc_lock;
-    hidbus_ifc_t* ifc;
+    hidbus_ifc_t ifc;
     void* cookie;
 
     i2c_hid_desc_t* hiddesc;
@@ -114,20 +114,19 @@
         return ZX_ERR_INVALID_ARGS;
     }
     info->dev_num = 0;
-    info->dev_class = HID_DEV_CLASS_OTHER;
+    info->device_class = HID_DEVICE_CLASS_OTHER;
     info->boot_device = false;
     return ZX_OK;
 }
 
-static zx_status_t i2c_hid_start(void* ctx, hidbus_ifc_t* ifc, void* cookie) {
+static zx_status_t i2c_hid_start(void* ctx, const hidbus_ifc_t* ifc) {
     i2c_hid_device_t* hid = ctx;
     mtx_lock(&hid->ifc_lock);
-    if (hid->ifc) {
+    if (hid->ifc.ops) {
         mtx_unlock(&hid->ifc_lock);
         return ZX_ERR_ALREADY_BOUND;
     }
-    hid->ifc = ifc;
-    hid->cookie = cookie;
+    hid->ifc = *ifc;
     mtx_unlock(&hid->ifc_lock);
     return ZX_OK;
 }
@@ -135,14 +134,13 @@
 static void i2c_hid_stop(void* ctx) {
     i2c_hid_device_t* hid = ctx;
     mtx_lock(&hid->ifc_lock);
-    hid->ifc = NULL;
-    hid->cookie = NULL;
+    hid->ifc.ops = NULL;
     mtx_unlock(&hid->ifc_lock);
 }
 
 static zx_status_t i2c_hid_get_descriptor(void* ctx, uint8_t desc_type,
         void** data, size_t* len) {
-    if (desc_type != HID_DESC_TYPE_REPORT) {
+    if (desc_type != HID_DESCRIPTION_TYPE_REPORT) {
         return ZX_ERR_NOT_FOUND;
     }
 
@@ -183,7 +181,7 @@
 }
 
 static zx_status_t i2c_hid_set_report(void* ctx, uint8_t rpt_type, uint8_t rpt_id,
-        void* data, size_t len) {
+        const void* data, size_t len) {
     return ZX_ERR_NOT_SUPPORTED;
 }
 
@@ -310,8 +308,8 @@
         }
 
         mtx_lock(&dev->ifc_lock);
-        if (dev->ifc) {
-            dev->ifc->io_queue(dev->cookie, buf + 2, report_len - 2);
+        if (dev->ifc.ops) {
+            hidbus_ifc_io_queue(&dev->ifc, buf + 2, report_len - 2);
         }
         mtx_unlock(&dev->ifc_lock);
 
@@ -403,8 +401,8 @@
         mtx_unlock(&dev->i2c_lock);
 
         mtx_lock(&dev->ifc_lock);
-        if (dev->ifc) {
-            dev->ifc->io_queue(dev->cookie, buf + 2, report_len - 2);
+        if (dev->ifc.ops) {
+            hidbus_ifc_io_queue(&dev->ifc, buf + 2, report_len - 2);
         }
         mtx_unlock(&dev->ifc_lock);
     }
diff --git a/system/dev/input/usb-hid/usb-hid.c b/system/dev/input/usb-hid/usb-hid.c
index 57cf161..e017974 100644
--- a/system/dev/input/usb-hid/usb-hid.c
+++ b/system/dev/input/usb-hid/usb-hid.c
@@ -35,7 +35,7 @@
     bool req_queued;
 
     mtx_t lock;
-    hidbus_ifc_t* ifc;
+    hidbus_ifc_t ifc;
     void* cookie;
 
     uint8_t interface;
@@ -63,8 +63,8 @@
         break;
     case ZX_OK:
         mtx_lock(&hid->lock);
-        if (hid->ifc) {
-            hid->ifc->io_queue(hid->cookie, buffer, req->response.actual);
+        if (hid->ifc.ops) {
+            hidbus_ifc_io_queue(&hid->ifc, buffer, req->response.actual);
         }
         mtx_unlock(&hid->lock);
         break;
@@ -88,20 +88,19 @@
     }
     usb_hid_device_t* hid = ctx;
     info->dev_num = hid->info.dev_num;
-    info->dev_class = hid->info.dev_class;
+    info->device_class = hid->info.device_class;
     info->boot_device = hid->info.boot_device;
     return ZX_OK;
 }
 
-static zx_status_t usb_hid_start(void* ctx, hidbus_ifc_t* ifc, void* cookie) {
+static zx_status_t usb_hid_start(void* ctx, const hidbus_ifc_t* ifc) {
     usb_hid_device_t* hid = ctx;
     mtx_lock(&hid->lock);
-    if (hid->ifc) {
+    if (hid->ifc.ops) {
         mtx_unlock(&hid->lock);
         return ZX_ERR_ALREADY_BOUND;
     }
-    hid->ifc = ifc;
-    hid->cookie = cookie;
+    hid->ifc = *ifc;
     if (!hid->req_queued) {
         hid->req_queued = true;
         usb_request_queue(&hid->usb, hid->req);
@@ -115,8 +114,7 @@
     // this callback
     usb_hid_device_t* hid = ctx;
     mtx_lock(&hid->lock);
-    hid->ifc = NULL;
-    hid->cookie = NULL;
+    hid->ifc.ops = NULL;
     mtx_unlock(&hid->lock);
 }
 
@@ -173,11 +171,11 @@
 }
 
 static zx_status_t usb_hid_set_report(void* ctx, uint8_t rpt_type, uint8_t rpt_id,
-                                      void* data, size_t len) {
+                                      const void* data, size_t len) {
     usb_hid_device_t* hid = ctx;
     return usb_hid_control(hid, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
                            USB_HID_SET_REPORT, (rpt_type << 8 | rpt_id),
-                           hid->interface, data, len, NULL);
+                           hid->interface, (void*)data, len, NULL);
 }
 
 static zx_status_t usb_hid_get_idle(void* ctx, uint8_t rpt_id, uint8_t* duration) {
@@ -298,11 +296,11 @@
         usbhid->hid_desc = hid_desc;
 
         usbhid->info.boot_device = intf->bInterfaceSubClass == USB_HID_SUBCLASS_BOOT;
-        usbhid->info.dev_class = HID_DEV_CLASS_OTHER;
+        usbhid->info.device_class = HID_DEVICE_CLASS_OTHER;
         if (intf->bInterfaceProtocol == USB_HID_PROTOCOL_KBD) {
-            usbhid->info.dev_class = HID_DEV_CLASS_KBD;
+            usbhid->info.device_class = HID_DEVICE_CLASS_KBD;
         } else if (intf->bInterfaceProtocol == USB_HID_PROTOCOL_MOUSE) {
-            usbhid->info.dev_class = HID_DEV_CLASS_POINTER;
+            usbhid->info.device_class = HID_DEVICE_CLASS_POINTER;
         }
 
         status = usb_req_alloc(&usb, &usbhid->req, usb_ep_max_packet(endpt),
diff --git a/system/dev/light/ams-light/tcs3400.cpp b/system/dev/light/ams-light/tcs3400.cpp
index e845463..c5d0bc3 100644
--- a/system/dev/light/ams-light/tcs3400.cpp
+++ b/system/dev/light/ams-light/tcs3400.cpp
@@ -152,13 +152,11 @@
                     if (input_rpt_.illuminance > threshold_high) {
                         input_rpt_.event =
                             HID_USAGE_SENSOR_EVENT_HIGH_THRESHOLD_CROSS_UPWARD_VAL;
-                        proxy_.IoQueue(reinterpret_cast<uint8_t*>(&input_rpt_),
-                                       sizeof(ambient_light_input_rpt_t));
+                        proxy_.IoQueue(&input_rpt_, sizeof(ambient_light_input_rpt_t));
                     } else if (input_rpt_.illuminance < threshold_low) {
                         input_rpt_.event =
                             HID_USAGE_SENSOR_EVENT_LOW_THRESHOLD_CROSS_DOWNWARD_VAL;
-                        proxy_.IoQueue(reinterpret_cast<uint8_t*>(&input_rpt_),
-                                       sizeof(ambient_light_input_rpt_t));
+                        proxy_.IoQueue(&input_rpt_, sizeof(ambient_light_input_rpt_t));
                     }
                 }
                 // If report could not be filled, we do not ioqueue
@@ -185,8 +183,7 @@
                 if (proxy_.is_valid()) {
                     FillInputRpt(); // We ioqueue even if report filling failed reporting bad state
                     input_rpt_.event = HID_USAGE_SENSOR_EVENT_PERIOD_EXCEEDED_VAL;
-                    proxy_.IoQueue(reinterpret_cast<uint8_t*>(&input_rpt_),
-                                   sizeof(ambient_light_input_rpt_t));
+                    proxy_.IoQueue(&input_rpt_, sizeof(ambient_light_input_rpt_t));
                 }
             }
             {
@@ -236,31 +233,31 @@
     return ZX_OK;
 }
 
-zx_status_t Tcs3400Device::HidBusStart(ddk::HidBusIfcProxy proxy) {
+zx_status_t Tcs3400Device::HidbusStart(const hidbus_ifc_t* ifc) {
     fbl::AutoLock lock(&proxy_input_lock_);
     if (proxy_.is_valid()) {
         return ZX_ERR_ALREADY_BOUND;
     } else {
-        proxy_ = proxy;
+        proxy_ = ddk::HidbusIfcProxy(ifc);
     }
     return ZX_OK;
 }
 
-zx_status_t Tcs3400Device::HidBusQuery(uint32_t options, hid_info_t* info) {
+zx_status_t Tcs3400Device::HidbusQuery(uint32_t options, hid_info_t* info) {
     if (!info) {
         return ZX_ERR_INVALID_ARGS;
     }
     info->dev_num = 0;
-    info->dev_class = HID_DEV_CLASS_OTHER;
+    info->device_class = HID_DEVICE_CLASS_OTHER;
     info->boot_device = false;
 
     return ZX_OK;
 }
 
-void Tcs3400Device::HidBusStop() {
+void Tcs3400Device::HidbusStop() {
 }
 
-zx_status_t Tcs3400Device::HidBusGetDescriptor(uint8_t desc_type, void** data, size_t* len) {
+zx_status_t Tcs3400Device::HidbusGetDescriptor(uint8_t desc_type, void** data, size_t* len) {
     const uint8_t* desc_ptr;
     uint8_t* buf;
     *len = get_ambient_light_report_desc(&desc_ptr);
@@ -274,7 +271,7 @@
     return ZX_OK;
 }
 
-zx_status_t Tcs3400Device::HidBusGetReport(uint8_t rpt_type, uint8_t rpt_id, void* data,
+zx_status_t Tcs3400Device::HidbusGetReport(uint8_t rpt_type, uint8_t rpt_id, void* data,
                                            size_t len, size_t* out_len) {
     if (rpt_id != AMBIENT_LIGHT_RPT_ID_INPUT && rpt_id != AMBIENT_LIGHT_RPT_ID_FEATURE) {
         return ZX_ERR_NOT_SUPPORTED;
@@ -297,7 +294,7 @@
     return ZX_OK;
 }
 
-zx_status_t Tcs3400Device::HidBusSetReport(uint8_t rpt_type, uint8_t rpt_id, void* data,
+zx_status_t Tcs3400Device::HidbusSetReport(uint8_t rpt_type, uint8_t rpt_id, const void* data,
                                            size_t len) {
     if (rpt_id != AMBIENT_LIGHT_RPT_ID_FEATURE) {
         return ZX_ERR_NOT_SUPPORTED;
@@ -307,32 +304,32 @@
     }
     {
         fbl::AutoLock lock(&feature_lock_);
-        ambient_light_feature_rpt_t* out = static_cast<ambient_light_feature_rpt_t*>(data);
+        auto* out = static_cast<const ambient_light_feature_rpt_t*>(data);
         feature_rpt_ = *out; // TA doesn't work on a memcpy taking an address as in &feature_rpt_
     }
 
     zx_port_packet packet = {TCS_CONFIGURE, ZX_PKT_TYPE_USER, ZX_OK, {}};
     zx_status_t status = zx_port_queue(port_handle_, &packet);
     if (status != ZX_OK) {
-        zxlogf(ERROR, "Tcs3400Device::HidBusSetReport: zx_port_queue failed: %d\n", status);
+        zxlogf(ERROR, "Tcs3400Device::HidbusSetReport: zx_port_queue failed: %d\n", status);
         return ZX_ERR_INTERNAL;
     }
     return ZX_OK;
 }
 
-zx_status_t Tcs3400Device::HidBusGetIdle(uint8_t rpt_id, uint8_t* duration) {
+zx_status_t Tcs3400Device::HidbusGetIdle(uint8_t rpt_id, uint8_t* duration) {
     return ZX_ERR_NOT_SUPPORTED;
 }
 
-zx_status_t Tcs3400Device::HidBusSetIdle(uint8_t rpt_id, uint8_t duration) {
+zx_status_t Tcs3400Device::HidbusSetIdle(uint8_t rpt_id, uint8_t duration) {
     return ZX_ERR_NOT_SUPPORTED;
 }
 
-zx_status_t Tcs3400Device::HidBusGetProtocol(uint8_t* protocol) {
+zx_status_t Tcs3400Device::HidbusGetProtocol(uint8_t* protocol) {
     return ZX_ERR_NOT_SUPPORTED;
 }
 
-zx_status_t Tcs3400Device::HidBusSetProtocol(uint8_t protocol) {
+zx_status_t Tcs3400Device::HidbusSetProtocol(uint8_t protocol) {
     return ZX_OK;
 }
 
diff --git a/system/dev/light/ams-light/tcs3400.h b/system/dev/light/ams-light/tcs3400.h
index e15147d..a848633 100644
--- a/system/dev/light/ams-light/tcs3400.h
+++ b/system/dev/light/ams-light/tcs3400.h
@@ -30,7 +30,7 @@
 // complies with a HID descriptor that was manually scripted (i.e. - not
 // reported by the device iteself).
 class Tcs3400Device : public DeviceType,
-                      public ddk::HidBusProtocol<Tcs3400Device> {
+                      public ddk::HidbusProtocol<Tcs3400Device> {
 public:
     Tcs3400Device(zx_device_t* device)
         : DeviceType(device) {}
@@ -40,19 +40,19 @@
     // Methods required by the ddk mixins
     zx_status_t DdkRead(void* buf, size_t count, zx_off_t off, size_t* actual);
 
-    zx_status_t HidBusStart(ddk::HidBusIfcProxy proxy) TA_EXCL(proxy_input_lock_);
-    zx_status_t HidBusQuery(uint32_t options, hid_info_t* info);
-    void HidBusStop();
-    zx_status_t HidBusGetDescriptor(uint8_t desc_type, void** data, size_t* len);
-    zx_status_t HidBusGetReport(uint8_t rpt_type, uint8_t rpt_id, void* data,
+    zx_status_t HidbusStart(const hidbus_ifc_t* ifc) TA_EXCL(proxy_input_lock_);
+    zx_status_t HidbusQuery(uint32_t options, hid_info_t* info);
+    void HidbusStop();
+    zx_status_t HidbusGetDescriptor(uint8_t desc_type, void** data, size_t* len);
+    zx_status_t HidbusGetReport(uint8_t rpt_type, uint8_t rpt_id, void* data,
                                 size_t len, size_t* out_len)
         TA_EXCL(proxy_input_lock_, feature_lock_);
-    zx_status_t HidBusSetReport(uint8_t rpt_type, uint8_t rpt_id, void* data,
+    zx_status_t HidbusSetReport(uint8_t rpt_type, uint8_t rpt_id, const void* data,
                                 size_t len) TA_EXCL(feature_lock_);
-    zx_status_t HidBusGetIdle(uint8_t rpt_id, uint8_t* duration);
-    zx_status_t HidBusSetIdle(uint8_t rpt_id, uint8_t duration);
-    zx_status_t HidBusGetProtocol(uint8_t* protocol);
-    zx_status_t HidBusSetProtocol(uint8_t protocol);
+    zx_status_t HidbusGetIdle(uint8_t rpt_id, uint8_t* duration);
+    zx_status_t HidbusSetIdle(uint8_t rpt_id, uint8_t duration);
+    zx_status_t HidbusGetProtocol(uint8_t* protocol);
+    zx_status_t HidbusSetProtocol(uint8_t protocol);
 
     void DdkUnbind();
     void DdkRelease();
@@ -68,7 +68,7 @@
     fbl::Mutex proxy_input_lock_ TA_ACQ_BEFORE(i2c_lock_);
     fbl::Mutex feature_lock_;
     fbl::Mutex i2c_lock_;
-    ddk::HidBusIfcProxy proxy_ TA_GUARDED(proxy_input_lock_);
+    ddk::HidbusIfcProxy proxy_ TA_GUARDED(proxy_input_lock_);
     ambient_light_input_rpt_t input_rpt_ TA_GUARDED(proxy_input_lock_);
     ambient_light_feature_rpt_t feature_rpt_ TA_GUARDED(feature_lock_);
     zx_status_t FillInputRpt() TA_REQ(proxy_input_lock_);
diff --git a/system/dev/misc/test/test.c b/system/dev/misc/test/test.c
index 4061bb8..8a6c791 100644
--- a/system/dev/misc/test/test.c
+++ b/system/dev/misc/test/test.c
@@ -10,6 +10,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <zircon/device/test.h>
 #include <zircon/listnode.h>
 
 typedef struct test_device {
@@ -17,7 +18,6 @@
     zx_handle_t output;
     zx_handle_t control;
     test_func_t test_func;
-    void* cookie;
 } test_device_t;
 
 typedef struct test_root {
@@ -50,16 +50,16 @@
     return device->control;
 }
 
-static void test_device_set_test_func(void* ctx, test_func_t func, void* cookie) {
+static void test_device_set_test_func(void* ctx, const test_func_t* func) {
     test_device_t* device = ctx;
-    device->test_func = func;
-    device->cookie = cookie;
+    device->test_func = *func;
 }
 
-static zx_status_t test_device_run_tests(void *ctx, test_report_t* report, const void* arg, size_t arglen) {
+static zx_status_t test_device_run_tests(void *ctx, const void* arg, size_t arglen,
+                                         test_report_t* report) {
     test_device_t* device = ctx;
-    if (device->test_func != NULL) {
-        return device->test_func(device->cookie, report, arg, arglen);
+    if (device->test_func.callback != NULL) {
+        return device->test_func.callback(device->test_func.ctx, arg, arglen, report);
     } else {
         return ZX_ERR_NOT_SUPPORTED;
     }
@@ -102,7 +102,7 @@
         if (outlen != sizeof(test_report_t)) {
             return ZX_ERR_BUFFER_TOO_SMALL;
         }
-        zx_status_t status = test_device_run_tests(dev, (test_report_t*)out, in, inlen);
+        zx_status_t status = test_device_run_tests(dev, in, inlen, (test_report_t*)out);
         *out_actual = sizeof(test_report_t);
         return status;
 
diff --git a/system/dev/nand/aml-rawnand/aml-rawnand.c b/system/dev/nand/aml-rawnand/aml-rawnand.c
index 68592f1..ad0a54f 100644
--- a/system/dev/nand/aml-rawnand/aml-rawnand.c
+++ b/system/dev/nand/aml-rawnand/aml-rawnand.c
@@ -445,9 +445,13 @@
 }
 
 static zx_status_t aml_read_page_hwecc(void* ctx,
-                                       void* data,
-                                       void* oob,
                                        uint32_t nand_page,
+                                       void* data,
+                                       size_t data_size,
+                                       size_t* data_actual,
+                                       void* oob,
+                                       size_t oob_size,
+                                       size_t* oob_actual,
                                        int* ecc_correct) {
     aml_raw_nand_t* raw_nand = (aml_raw_nand_t*)ctx;
     uint32_t cmd;
@@ -540,7 +544,9 @@
  */
 static zx_status_t aml_write_page_hwecc(void* ctx,
                                         const void* data,
+                                        size_t data_size,
                                         const void* oob,
+                                        size_t oob_size,
                                         uint32_t nand_page)
 {
     aml_raw_nand_t *raw_nand = (aml_raw_nand_t*)ctx;
@@ -807,7 +813,9 @@
 
 static zx_status_t aml_read_page0(aml_raw_nand_t* raw_nand,
                                   void* data,
+                                  size_t data_size,
                                   void* oob,
+                                  size_t oob_size,
                                   uint32_t nand_page,
                                   int* ecc_correct,
                                   int retries) {
@@ -815,8 +823,8 @@
 
     retries++;
     do {
-        status = aml_read_page_hwecc(raw_nand, data, oob,
-                                     nand_page, ecc_correct);
+        status = aml_read_page_hwecc(raw_nand, nand_page, data, data_size, NULL, oob, oob_size,
+                                     NULL, ecc_correct);
     } while (status != ZX_OK && --retries > 0);
     if (status != ZX_OK)
         zxlogf(ERROR, "%s: Read error\n", __func__);
@@ -843,7 +851,7 @@
      * starting at Page 0. Read the first we can.
      */
     for (uint32_t i = 0; i < 7; i++) {
-        status = aml_read_page0(raw_nand, data, NULL, i * 128,
+        status = aml_read_page0(raw_nand, data, raw_nand->writesize, NULL, 0, i * 128,
                                 &ecc_correct, 3);
         if (status == ZX_OK)
             break;
diff --git a/system/dev/nand/nand/nand.c b/system/dev/nand/nand/nand.c
index 25af02f..3075a44 100644
--- a/system/dev/nand/nand/nand.c
+++ b/system/dev/nand/nand/nand.c
@@ -34,8 +34,8 @@
 
 #define NAND_READ_RETRIES 3
 
-static void nand_io_complete(nand_op_t* nand_op, zx_status_t status) {
-    nand_op->completion_cb(nand_op, status);
+static void nand_io_complete(nand_io_t* io, zx_status_t status) {
+    io->completion_cb(io->cookie, status, &io->nand_op);
 }
 
 // Calls controller specific read function.
@@ -49,7 +49,8 @@
     zx_status_t status;
 
     do {
-        status = raw_nand_read_page_hwecc(&dev->host, data, oob, nand_page, corrected_bits);
+        status = raw_nand_read_page_hwecc(&dev->host, nand_page, data, dev->nand_info.page_size,
+                                          NULL, oob, dev->nand_info.oob_size, NULL, corrected_bits);
         if (status != ZX_OK) {
             zxlogf(ERROR, "%s: Retrying Read@%u\n", __func__, nand_page);
         }
@@ -64,7 +65,8 @@
 // data, oob: pointers to user oob/data buffers.
 // nand_page : NAND page address to read.
 zx_status_t nand_write_page(nand_device_t* dev, void* data, void* oob, uint32_t nand_page) {
-    return raw_nand_write_page_hwecc(&dev->host, data, oob, nand_page);
+    return raw_nand_write_page_hwecc(&dev->host, data, dev->nand_info.page_size, oob,
+                                     dev->nand_info.oob_size, nand_page);
 }
 
 // Calls controller specific erase function.
@@ -73,7 +75,7 @@
     return raw_nand_erase_block(&dev->host, nand_page);
 }
 
-zx_status_t nand_erase_op(nand_device_t* dev, nand_op_t* nand_op) {
+zx_status_t nand_erase_op(nand_device_t* dev, nand_operation_t* nand_op) {
     uint32_t nand_page;
 
     for (uint32_t i = 0; i < nand_op->erase.num_blocks; i++) {
@@ -87,7 +89,7 @@
     return ZX_OK;
 }
 
-static zx_status_t nand_read_op(nand_device_t* dev, nand_op_t* nand_op) {
+static zx_status_t nand_read_op(nand_device_t* dev, nand_operation_t* nand_op) {
     uint8_t *aligned_vaddr_data = NULL;
     uint8_t *aligned_vaddr_oob = NULL;
     uint8_t *vaddr_data = NULL;
@@ -175,7 +177,7 @@
     return status;
 }
 
-static zx_status_t nand_write_op(nand_device_t* dev, nand_op_t* nand_op) {
+static zx_status_t nand_write_op(nand_device_t* dev, nand_operation_t* nand_op) {
     uint8_t *aligned_vaddr_data = NULL;
     uint8_t *aligned_vaddr_oob = NULL;
     uint8_t *vaddr_data = NULL;
@@ -258,7 +260,7 @@
 
 static void nand_do_io(nand_device_t* dev, nand_io_t* io) {
     zx_status_t status = ZX_OK;
-    nand_op_t* nand_op = &io->nand_op;
+    nand_operation_t* nand_op = &io->nand_op;
 
     ZX_DEBUG_ASSERT(dev != NULL);
     ZX_DEBUG_ASSERT(io != NULL);
@@ -275,7 +277,7 @@
     default:
         ZX_DEBUG_ASSERT(false); // Unexpected.
     }
-    nand_io_complete(nand_op, status);
+    nand_io_complete(io, status);
 }
 
 // Initialization is complete by the time the thread starts.
@@ -315,34 +317,38 @@
     return ZX_OK;
 }
 
-static void nand_query(void* ctx, nand_info_t* info_out, size_t* nand_op_size_out) {
+static void _nand_query(void* ctx, nand_info_t* info_out, size_t* nand_op_size_out) {
     nand_device_t* dev = (nand_device_t*)ctx;
 
     memcpy(info_out, &dev->nand_info, sizeof(*info_out));
     *nand_op_size_out = sizeof(nand_io_t);
 }
 
-static void nand_queue(void* ctx, nand_op_t* op) {
+static void _nand_queue(void* ctx, nand_operation_t* op, nand_queue_callback completion_cb,
+                       void* cookie) {
     nand_device_t* dev = (nand_device_t*)ctx;
     nand_io_t* io = containerof(op, nand_io_t, nand_op);
 
-    if (op->completion_cb == NULL) {
+    if (completion_cb == NULL) {
         zxlogf(TRACE, "nand: nand op %p completion_cb unset!\n", op);
         zxlogf(TRACE, "nand: cannot queue command!\n");
         return;
     }
 
+    io->completion_cb = completion_cb;
+    io->cookie = cookie;
+
     switch (op->command) {
     case NAND_OP_READ:
     case NAND_OP_WRITE: {
         if (op->rw.offset_nand >= dev->num_nand_pages || !op->rw.length ||
             (dev->num_nand_pages - op->rw.offset_nand) < op->rw.length) {
-            op->completion_cb(op, ZX_ERR_OUT_OF_RANGE);
+            completion_cb(cookie, ZX_ERR_OUT_OF_RANGE, op);
             return;
         }
         if (op->rw.data_vmo == ZX_HANDLE_INVALID &&
             op->rw.oob_vmo == ZX_HANDLE_INVALID) {
-            op->completion_cb(op, ZX_ERR_BAD_HANDLE);
+            completion_cb(cookie, ZX_ERR_BAD_HANDLE, op);
             return;
         }
         break;
@@ -351,13 +357,13 @@
         if (!op->erase.num_blocks ||
             op->erase.first_block >= dev->nand_info.num_blocks ||
             (op->erase.num_blocks > (dev->nand_info.num_blocks - op->erase.first_block))) {
-            op->completion_cb(op, ZX_ERR_OUT_OF_RANGE);
+            completion_cb(cookie, ZX_ERR_OUT_OF_RANGE, op);
             return;
         }
         break;
 
     default:
-        op->completion_cb(op, ZX_ERR_NOT_SUPPORTED);
+        completion_cb(cookie, ZX_ERR_NOT_SUPPORTED, op);
         return;
     }
 
@@ -370,18 +376,18 @@
     mtx_unlock(&dev->lock);
 }
 
-static zx_status_t nand_get_factory_bad_block_list(void* ctx, uint32_t* bad_blocks,
-                                                   uint32_t bad_block_len,
-                                                   uint32_t* num_bad_blocks) {
+static zx_status_t _nand_get_factory_bad_block_list(void* ctx, uint32_t* bad_blocks,
+                                                   size_t bad_block_len,
+                                                   size_t* num_bad_blocks) {
     *num_bad_blocks = 0;
     return ZX_ERR_NOT_SUPPORTED;
 }
 
 // Nand protocol.
 static nand_protocol_ops_t nand_proto = {
-    .query = nand_query,
-    .queue = nand_queue,
-    .get_factory_bad_block_list = nand_get_factory_bad_block_list,
+    .query = _nand_query,
+    .queue = _nand_queue,
+    .get_factory_bad_block_list = _nand_get_factory_bad_block_list,
 };
 
 static void nand_unbind(void* ctx) {
@@ -401,7 +407,7 @@
     nand_io_t* io = NULL;
     list_for_every_entry (&dev->io_list, io, nand_io_t, node) {
         mtx_unlock(&dev->lock);
-        nand_io_complete(&io->nand_op, ZX_ERR_BAD_STATE);
+        nand_io_complete(io, ZX_ERR_BAD_STATE);
         mtx_lock(&dev->lock);
     }
     mtx_unlock(&dev->lock);
@@ -471,7 +477,7 @@
         zxlogf(ERROR, "nand: failed to get nand info, function does not exist\n");
         goto fail;
     }
-    st = raw_nand_get_info(&dev->host, &dev->nand_info);
+    st = raw_nand_get_nand_info(&dev->host, &dev->nand_info);
     if (st != ZX_OK) {
         zxlogf(ERROR, "nand: get_nand_info returned error %d\n", st);
         goto fail;
diff --git a/system/dev/nand/nand/nand.h b/system/dev/nand/nand/nand.h
index 666dfab..b163668 100644
--- a/system/dev/nand/nand/nand.h
+++ b/system/dev/nand/nand/nand.h
@@ -31,7 +31,9 @@
 
 // Nand io transactions. One per client request.
 typedef struct nand_io {
-    nand_op_t nand_op;
+    nand_operation_t nand_op;
+    nand_queue_callback completion_cb;
+    void* cookie;
     list_node_t node;
 } nand_io_t;
 
diff --git a/system/dev/nand/nand/nand_driver_test.c b/system/dev/nand/nand/nand_driver_test.c
index dc98da7..6afa0e8 100644
--- a/system/dev/nand/nand/nand_driver_test.c
+++ b/system/dev/nand/nand/nand_driver_test.c
@@ -21,9 +21,9 @@
 
 // The code in this file is only used for testing, the ioctl() is the entry
 // point into this code, called by the nand driver's unit test.
-static void nandtest_complete(nand_op_t* nand_op, zx_status_t status) {
+static void nandtest_complete(void* cookie, zx_status_t status, nand_operation_t* nand_op) {
     nand_op->command = status;
-    sync_completion_signal((sync_completion_t*)nand_op->cookie);
+    sync_completion_signal((sync_completion_t*)cookie);
 }
 
 static zx_status_t nand_test_get_info(nand_device_t* dev, void* reply, size_t max,
@@ -50,7 +50,7 @@
     nand_info_t nand_info;
     size_t nand_op_size_out;
     nand_io_t nand_io;
-    nand_op_t* nand_op = &nand_io.nand_op;
+    nand_operation_t* nand_op = &nand_io.nand_op;
     nandtest_rw_page_data_oob_t* cmd_read_page;
     nandtest_resp_t resp_hdr;
     zx_handle_t vmo_data;
@@ -98,11 +98,8 @@
     nand_op->rw.data_vmo = do_data ? vmo_data : ZX_HANDLE_INVALID;
     nand_op->rw.oob_vmo = do_oob ? vmo_oob : ZX_HANDLE_INVALID;
 
-    nand_op->completion_cb = nandtest_complete;
-    nand_op->cookie = &completion;
-
     // Queue the data read op and wait for response.
-    dev->nand_proto.ops->queue(dev, nand_op);
+    dev->nand_proto.ops->queue(dev, nand_op, nandtest_complete, &completion);
     sync_completion_wait(&completion, ZX_TIME_INFINITE);
 
     resp_hdr.status = nand_op->command; // Status stored here by callback.
@@ -123,7 +120,7 @@
     nand_info_t nand_info;
     size_t nand_op_size_out;
     nand_io_t nand_io;
-    nand_op_t* nand_op = &nand_io.nand_op;
+    nand_operation_t* nand_op = &nand_io.nand_op;
     nandtest_rw_page_data_oob_t* cmd_write_page;
     nandtest_resp_t resp_hdr;
     zx_handle_t vmo_data, vmo_oob;
@@ -176,11 +173,8 @@
     nand_op->rw.data_vmo = do_data ? vmo_data : ZX_HANDLE_INVALID;
     nand_op->rw.oob_vmo = do_oob ? vmo_oob : ZX_HANDLE_INVALID;
 
-    nand_op->completion_cb = nandtest_complete;
-    nand_op->cookie = &completion;
-
     // Queue the data read op and wait for response.
-    dev->nand_proto.ops->queue(dev, nand_op);
+    dev->nand_proto.ops->queue(dev, nand_op, nandtest_complete, &completion);
     sync_completion_wait(&completion, ZX_TIME_INFINITE);
 
     resp_hdr.status = nand_op->command; // Status stored here by callback.
@@ -206,7 +200,7 @@
     nand_info_t nand_info;
     size_t nand_op_size_out;
     nand_io_t nand_io;
-    nand_op_t* nand_op = &nand_io.nand_op;
+    nand_operation_t* nand_op = &nand_io.nand_op;
     nandtest_cmd_erase_block_t* cmd_erase_block;
     nandtest_resp_t resp_hdr;
 
@@ -228,11 +222,9 @@
     nand_op->command = NAND_OP_ERASE;
     nand_op->erase.first_block = cmd_erase_block->nandblock;
     nand_op->erase.num_blocks = 1;
-    nand_op->completion_cb = nandtest_complete;
-    nand_op->cookie = &completion;
 
     // Queue the data read op and wait for response.
-    dev->nand_proto.ops->queue(dev, nand_op);
+    dev->nand_proto.ops->queue(dev, nand_op, nandtest_complete, &completion);
     sync_completion_wait(&completion, ZX_TIME_INFINITE);
 
     resp_hdr.status = nand_op->command; // Status stored here by callback.
diff --git a/system/dev/nand/nandpart/aml-bad-block.cpp b/system/dev/nand/nandpart/aml-bad-block.cpp
index 5a1fbbe..1c848fe 100644
--- a/system/dev/nand/nandpart/aml-bad-block.cpp
+++ b/system/dev/nand/nandpart/aml-bad-block.cpp
@@ -30,8 +30,8 @@
     zx_status_t status;
 };
 
-void CompletionCallback(nand_op_t* op, zx_status_t status) {
-    auto* ctx = static_cast<BlockOperationContext*>(op->cookie);
+void CompletionCallback(void* cookie, zx_status_t status, nand_operation_t* op) {
+    auto* ctx = static_cast<BlockOperationContext*>(cookie);
 
     zxlogf(TRACE, "Completion status: %d\n", status);
     ctx->status = status;
@@ -42,7 +42,7 @@
 } // namespace
 
 zx_status_t AmlBadBlock::Create(Config config, fbl::RefPtr<BadBlock>* out) {
-    // Query parent to get its nand_info_t and size for nand_op_t.
+    // Query parent to get its nand_info_t and size for nand_operation_t.
     nand_info_t nand_info;
     size_t parent_op_size;
     config.nand_proto.ops->query(config.nand_proto.ctx, &nand_info, &parent_op_size);
@@ -104,13 +104,11 @@
     sync_completion_t completion;
     BlockOperationContext op_ctx = {.completion_event = &completion,
                                     .status = ZX_ERR_INTERNAL};
-    auto* nand_op = reinterpret_cast<nand_op_t*>(nand_op_.get());
+    auto* nand_op = reinterpret_cast<nand_operation_t*>(nand_op_.get());
     nand_op->erase.command = NAND_OP_ERASE;
     nand_op->erase.first_block = block;
     nand_op->erase.num_blocks = 1;
-    nand_op->completion_cb = CompletionCallback;
-    nand_op->cookie = &op_ctx;
-    nand_.Queue(nand_op);
+    nand_.Queue(nand_op, CompletionCallback, &op_ctx);
 
     // Wait on completion.
     sync_completion_wait(&completion, ZX_TIME_INFINITE);
@@ -166,7 +164,7 @@
     BlockOperationContext op_ctx = {.completion_event = &completion,
                                     .status = ZX_ERR_INTERNAL};
 
-    auto* nand_op = reinterpret_cast<nand_op_t*>(nand_op_.get());
+    auto* nand_op = reinterpret_cast<nand_operation_t*>(nand_op_.get());
     nand_op->rw.command = NAND_OP_WRITE;
     nand_op->rw.data_vmo = data_vmo_.get();
     nand_op->rw.oob_vmo = oob_vmo_.get();
@@ -174,9 +172,7 @@
     nand_op->rw.offset_nand = nand_page;
     nand_op->rw.offset_data_vmo = 0;
     nand_op->rw.offset_oob_vmo = 0;
-    nand_op->completion_cb = CompletionCallback;
-    nand_op->cookie = &op_ctx;
-    nand_.Queue(nand_op);
+    nand_.Queue(nand_op, CompletionCallback, &op_ctx);
 
     // Wait on completion.
     sync_completion_wait(&completion, ZX_TIME_INFINITE);
@@ -230,7 +226,7 @@
     sync_completion_t completion;
     BlockOperationContext op_ctx = {.completion_event = &completion,
                                     .status = ZX_ERR_INTERNAL};
-    auto* nand_op = reinterpret_cast<nand_op_t*>(nand_op_.get());
+    auto* nand_op = reinterpret_cast<nand_operation_t*>(nand_op_.get());
     nand_op->rw.command = NAND_OP_READ;
     nand_op->rw.data_vmo = data_vmo_.get();
     nand_op->rw.oob_vmo = oob_vmo_.get();
@@ -238,9 +234,7 @@
     nand_op->rw.offset_nand = nand_page;
     nand_op->rw.offset_data_vmo = 0;
     nand_op->rw.offset_oob_vmo = 0;
-    nand_op->completion_cb = CompletionCallback;
-    nand_op->cookie = &op_ctx;
-    nand_.Queue(nand_op);
+    nand_.Queue(nand_op, CompletionCallback, &op_ctx);
 
     // Wait on completion.
     sync_completion_wait(&completion, ZX_TIME_INFINITE);
diff --git a/system/dev/nand/nandpart/nandpart.cpp b/system/dev/nand/nandpart/nandpart.cpp
index e6a403a..fb99240 100644
--- a/system/dev/nand/nandpart/nandpart.cpp
+++ b/system/dev/nand/nandpart/nandpart.cpp
@@ -30,10 +30,17 @@
 
 constexpr uint8_t fvm_guid[] = GUID_FVM_VALUE;
 
+struct NandPartOp {
+    nand_operation_t translated_op;
+    nand_queue_callback completion_cb;
+    void* cookie;
+};
+
 // Shim for calling sub-partition's callback.
-void CompletionCallback(nand_op_t* op, zx_status_t status) {
-    op = static_cast<nand_op_t*>(op->cookie);
-    op->completion_cb(op, status);
+void CompletionCallback(void* cookie, zx_status_t status, nand_operation_t* op) {
+    auto* nandpart_op = reinterpret_cast<NandPartOp*>(op);
+    nandpart_op->completion_cb(nandpart_op->cookie, status,
+                               static_cast<nand_operation_t*>(cookie));
 }
 
 } // namespace
@@ -48,7 +55,7 @@
         return ZX_ERR_NOT_SUPPORTED;
     }
 
-    // Query parent to get its nand_info_t and size for nand_op_t.
+    // Query parent to get its nand_info_t and size for nand_operation_t.
     nand_info_t nand_info;
     size_t parent_op_size;
     nand_proto.ops->query(nand_proto.ctx, &nand_info, &parent_op_size);
@@ -186,15 +193,17 @@
     return ZX_OK;
 }
 
-void NandPartDevice::Query(nand_info_t* info_out, size_t* nand_op_size_out) {
+void NandPartDevice::NandQuery(nand_info_t* info_out, size_t* nand_op_size_out) {
     memcpy(info_out, &nand_info_, sizeof(*info_out));
     // Add size of translated_op.
-    *nand_op_size_out = parent_op_size_ + sizeof(nand_op_t);
+    *nand_op_size_out = parent_op_size_ + sizeof(NandPartOp);
 }
 
-void NandPartDevice::Queue(nand_op_t* op) {
-    auto* translated_op =
-        reinterpret_cast<nand_op_t*>(reinterpret_cast<uintptr_t>(op) + parent_op_size_);
+void NandPartDevice::NandQueue(nand_operation_t* op, nand_queue_callback completion_cb,
+                               void* cookie) {
+    auto* nandpart_op =
+        reinterpret_cast<NandPartOp*>(reinterpret_cast<uintptr_t>(op) + parent_op_size_);
+    auto* translated_op = &nandpart_op->translated_op;
     uint32_t command = op->command;
 
     // Copy client's op to translated op
@@ -210,26 +219,26 @@
         translated_op->erase.first_block += erase_block_start_;
         break;
     default:
-        op->completion_cb(op, ZX_ERR_NOT_SUPPORTED);
+        completion_cb(cookie, ZX_ERR_NOT_SUPPORTED, op);
         return;
     }
 
-    translated_op->completion_cb = CompletionCallback;
-    translated_op->cookie = op;
+    nandpart_op->completion_cb = completion_cb;
+    nandpart_op->cookie = cookie;
 
     // Call parent's queue
-    nand_.Queue(translated_op);
+    nand_.Queue(translated_op, CompletionCallback, op);
 }
 
-zx_status_t NandPartDevice::GetFactoryBadBlockList(uint32_t* bad_blocks, uint32_t bad_block_len,
-                                                   uint32_t* num_bad_blocks) {
+zx_status_t NandPartDevice::NandGetFactoryBadBlockList(uint32_t* bad_blocks, size_t bad_block_len,
+                                                       size_t* num_bad_blocks) {
     // TODO implement this.
     *num_bad_blocks = 0;
     return ZX_ERR_NOT_SUPPORTED;
 }
 
-zx_status_t NandPartDevice::GetBadBlockList(uint32_t* bad_block_list, uint32_t bad_block_list_len,
-                                            uint32_t* bad_block_count) {
+zx_status_t NandPartDevice::BadBlockGetBadBlockList(
+    uint32_t* bad_block_list, size_t bad_block_list_len, size_t* bad_block_count) {
 
     if (!bad_block_list_) {
         const zx_status_t status = bad_block_->GetBadBlockList(
@@ -242,8 +251,8 @@
         }
     }
 
-    *bad_block_count = static_cast<uint32_t>(bad_block_list_.size());
-    zxlogf(TRACE, "nandpart: %s: Bad block count: %u\n", name(), *bad_block_count);
+    *bad_block_count = bad_block_list_.size();
+    zxlogf(TRACE, "nandpart: %s: Bad block count: %zu\n", name(), *bad_block_count);
 
     if (bad_block_list_len == 0 || bad_block_list_.size() == 0) {
         return ZX_OK;
@@ -257,7 +266,7 @@
     return ZX_OK;
 }
 
-zx_status_t NandPartDevice::MarkBlockBad(uint32_t block) {
+zx_status_t NandPartDevice::BadBlockMarkBlockBad(uint32_t block) {
     if (block >= nand_info_.num_blocks) {
         return ZX_ERR_OUT_OF_RANGE;
     }
@@ -275,10 +284,10 @@
     proto->ctx = this;
     switch (proto_id) {
     case ZX_PROTOCOL_NAND:
-        proto->ops = &nand_proto_ops_;
+        proto->ops = &ops_;
         break;
     case ZX_PROTOCOL_BAD_BLOCK:
-        proto->ops = &bad_block_proto_ops_;
+        proto->ops = &bad_block_protocol_ops_;
         break;
     default:
         return ZX_ERR_NOT_SUPPORTED;
diff --git a/system/dev/nand/nandpart/nandpart.h b/system/dev/nand/nandpart/nandpart.h
index 12aa6f7..406cabe 100644
--- a/system/dev/nand/nandpart/nandpart.h
+++ b/system/dev/nand/nandpart/nandpart.h
@@ -25,7 +25,7 @@
 
 class NandPartDevice : public DeviceType,
                        public ddk::NandProtocol<NandPartDevice>,
-                       public ddk::BadBlockable<NandPartDevice> {
+                       public ddk::BadBlockProtocol<NandPartDevice> {
 public:
     // Spawns device nodes based on parent node.
     static zx_status_t Create(zx_device_t* parent);
@@ -43,15 +43,15 @@
     void DdkRelease() { delete this; }
 
     // nand protocol implementation.
-    void Query(nand_info_t* info_out, size_t* nand_op_size_out);
-    void Queue(nand_op_t* op);
-    zx_status_t GetFactoryBadBlockList(uint32_t* bad_blocks, uint32_t bad_block_len,
-                                       uint32_t* num_bad_blocks);
+    void NandQuery(nand_info_t* info_out, size_t* nand_op_size_out);
+    void NandQueue(nand_operation_t* op, nand_queue_callback completion_cb, void* cookie);
+    zx_status_t NandGetFactoryBadBlockList(uint32_t* bad_blocks, size_t bad_block_len,
+                                           size_t* num_bad_blocks);
 
     // Bad block protocol implementation.
-    zx_status_t GetBadBlockList(uint32_t* bad_block_list, uint32_t bad_block_list_len,
-                                uint32_t* bad_block_count);
-    zx_status_t MarkBlockBad(uint32_t block);
+    zx_status_t BadBlockGetBadBlockList(uint32_t* bad_block_list, size_t bad_block_list_len,
+                                size_t* bad_block_count);
+    zx_status_t BadBlockMarkBlockBad(uint32_t block);
 
 private:
     explicit NandPartDevice(zx_device_t* parent, const nand_protocol_t& nand_proto,
diff --git a/system/dev/nand/nandpart/test/aml-bad-block-test.cpp b/system/dev/nand/nandpart/test/aml-bad-block-test.cpp
index e5b931b..901b027 100644
--- a/system/dev/nand/nandpart/test/aml-bad-block-test.cpp
+++ b/system/dev/nand/nandpart/test/aml-bad-block-test.cpp
@@ -77,10 +77,11 @@
 
 void MockQuery(void* ctx, nand_info_t* info_out, size_t* nand_op_size_out) {
     memcpy(info_out, &kNandInfo, sizeof(kNandInfo));
-    *nand_op_size_out = sizeof(nand_op_t);
+    *nand_op_size_out = sizeof(nand_operation_t);
 }
 
-void MockQueue(void* ctx, nand_op_t* op) {
+void MockQueue(void* ctx, nand_operation_t* op, nand_queue_callback completion_cb,
+               void* cookie) {
     auto* context = static_cast<Context*>(ctx);
 
     switch (op->command) {
@@ -93,7 +94,7 @@
             op->erase.first_block + op->erase.num_blocks >= kNumBlocks) {
 
             unittest_printf("Trying to write to a page that is out of range!\n");
-            op->completion_cb(op, ZX_ERR_OUT_OF_RANGE);
+            completion_cb(cookie, ZX_ERR_OUT_OF_RANGE, op);
             return;
         }
         const NandPage start_page = op->erase.first_block * kPagesPerBlock;
@@ -101,11 +102,11 @@
         for (NandPage page = start_page; page < end_page; page++) {
             context->table_entries.erase(page);
         }
-        op->completion_cb(op, ZX_OK);
+        completion_cb(cookie, ZX_OK, op);
         return;
     }
     default:
-        op->completion_cb(op, ZX_ERR_NOT_SUPPORTED);
+        completion_cb(cookie, ZX_ERR_NOT_SUPPORTED, op);
         return;
     }
 
@@ -119,7 +120,7 @@
                                                     &data_buf);
     __UNUSED auto unused = data_vmo.release();
     if (status != ZX_OK) {
-        op->completion_cb(op, status);
+        completion_cb(cookie, status, op);
         return;
     }
     auto data_unmapper = fbl::MakeAutoCall([&]() {
@@ -132,7 +133,7 @@
                                         ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, &oob_buf);
     __UNUSED auto __ = oob_vmo.release();
     if (status != ZX_OK) {
-        op->completion_cb(op, status);
+        completion_cb(cookie, status, op);
         return;
     }
     auto oob_unmapper = fbl::MakeAutoCall([&]() {
@@ -147,7 +148,7 @@
             auto it = context->table_entries.find(op->rw.offset_nand + i);
             if (it != context->table_entries.end()) {
                 if (!it->valid_) {
-                    op->completion_cb(op, ZX_ERR_IO);
+                    completion_cb(cookie, ZX_ERR_IO, op);
                     return;
                 }
                 memset(data + (i * kPageSize), 0, kPageSize);
@@ -162,7 +163,7 @@
                 memset(oob + i, 0xFF, sizeof(*oob));
             }
         }
-        op->completion_cb(op, ZX_OK);
+        completion_cb(cookie, ZX_OK, op);
         break;
 
     case NAND_OP_WRITE:
@@ -181,10 +182,10 @@
                 break;
             }
         }
-        op->completion_cb(op, status);
+        completion_cb(cookie, status, op);
         break;
     default:
-        op->completion_cb(op, ZX_ERR_NOT_SUPPORTED);
+        completion_cb(cookie, ZX_ERR_NOT_SUPPORTED, op);
         break;
     }
 }
diff --git a/system/dev/nand/ram-nand/ram-nand.cpp b/system/dev/nand/ram-nand/ram-nand.cpp
index c3cd04e..5e1bab7 100644
--- a/system/dev/nand/ram-nand/ram-nand.cpp
+++ b/system/dev/nand/ram-nand/ram-nand.cpp
@@ -23,7 +23,9 @@
 namespace {
 
 struct RamNandOp {
-    nand_op_t op;
+    nand_operation_t op;
+    nand_queue_callback completion_cb;
+    void* cookie;
     list_node_t node;
 };
 
@@ -45,8 +47,7 @@
             if (!nand_op) {
                 break;
             }
-            nand_op_t* operation = &nand_op->op;
-            operation->completion_cb(operation, ZX_ERR_BAD_STATE);
+            nand_op->completion_cb(nand_op->cookie, ZX_ERR_BAD_STATE, &nand_op->op);
         }
     }
 
@@ -178,24 +179,25 @@
     }
 }
 
-void NandDevice::Query(nand_info_t* info_out, size_t* nand_op_size_out) {
+void NandDevice::NandQuery(nand_info_t* info_out, size_t* nand_op_size_out) {
     *info_out = params_;
     *nand_op_size_out = sizeof(RamNandOp);
 }
 
-void NandDevice::Queue(nand_op_t* operation) {
+void NandDevice::NandQueue(nand_operation_t* operation, nand_queue_callback completion_cb,
+                           void* cookie) {
     uint32_t max_pages = params_.NumPages();
     switch (operation->command) {
     case NAND_OP_READ:
     case NAND_OP_WRITE: {
         if (operation->rw.offset_nand >= max_pages || !operation->rw.length ||
             (max_pages - operation->rw.offset_nand) < operation->rw.length) {
-            operation->completion_cb(operation, ZX_ERR_OUT_OF_RANGE);
+            completion_cb(cookie, ZX_ERR_OUT_OF_RANGE, operation);
             return;
         }
         if (operation->rw.data_vmo == ZX_HANDLE_INVALID &&
             operation->rw.oob_vmo == ZX_HANDLE_INVALID) {
-            operation->completion_cb(operation, ZX_ERR_BAD_HANDLE);
+            completion_cb(cookie, ZX_ERR_BAD_HANDLE, operation);
             return;
         }
         break;
@@ -204,25 +206,25 @@
         if (!operation->erase.num_blocks ||
             operation->erase.first_block >= params_.num_blocks ||
             params_.num_blocks - operation->erase.first_block < operation->erase.num_blocks) {
-            operation->completion_cb(operation, ZX_ERR_OUT_OF_RANGE);
+            completion_cb(cookie, ZX_ERR_OUT_OF_RANGE, operation);
             return;
         }
         break;
 
     default:
-        operation->completion_cb(operation, ZX_ERR_NOT_SUPPORTED);
+        completion_cb(cookie, ZX_ERR_NOT_SUPPORTED, operation);
         return;
     }
 
-    if (AddToList(operation)) {
+    if (AddToList(operation, completion_cb, cookie)) {
         sync_completion_signal(&wake_signal_);
     } else {
-        operation->completion_cb(operation, ZX_ERR_BAD_STATE);
+        completion_cb(cookie, ZX_ERR_BAD_STATE, operation);
     }
 }
 
-zx_status_t NandDevice::GetFactoryBadBlockList(uint32_t* bad_blocks, uint32_t bad_block_len,
-                                               uint32_t* num_bad_blocks) {
+zx_status_t NandDevice::NandGetFactoryBadBlockList(uint32_t* bad_blocks, size_t bad_block_len,
+                                                   size_t* num_bad_blocks) {
     *num_bad_blocks = 0;
     return ZX_OK;
 }
@@ -232,29 +234,32 @@
     dead_ = true;
 }
 
-bool NandDevice::AddToList(nand_op_t* operation) {
+bool NandDevice::AddToList(nand_operation_t* operation, nand_queue_callback completion_cb,
+                           void* cookie) {
     fbl::AutoLock lock(&lock_);
     bool is_dead = dead_;
     if (!dead_) {
         RamNandOp* nand_op = reinterpret_cast<RamNandOp*>(operation);
+        nand_op->completion_cb = completion_cb;
+        nand_op->cookie = cookie;
         list_add_tail(&txn_list_, &nand_op->node);
     }
     return !is_dead;
 }
 
-bool NandDevice::RemoveFromList(nand_op_t** operation) {
+bool NandDevice::RemoveFromList(nand_operation_t** operation) {
     fbl::AutoLock lock(&lock_);
     bool is_dead = dead_;
     if (!dead_) {
         RamNandOp* nand_op = list_remove_head_type(&txn_list_, RamNandOp, node);
-        *operation = reinterpret_cast<nand_op_t*>(nand_op);
+        *operation = reinterpret_cast<nand_operation_t*>(nand_op);
     }
     return !is_dead;
 }
 
 int NandDevice::WorkerThread() {
     for (;;) {
-        nand_op_t* operation;
+        nand_operation_t* operation;
         for (;;) {
             if (!RemoveFromList(&operation)) {
                 return 0;
@@ -286,7 +291,8 @@
             ZX_DEBUG_ASSERT(false);  // Unexpected.
         }
 
-        operation->completion_cb(operation, status);
+        auto *op = reinterpret_cast<RamNandOp*>(operation);
+        op->completion_cb(op->cookie, status, operation);
     }
 }
 
@@ -295,7 +301,7 @@
     return device->WorkerThread();
 }
 
-zx_status_t NandDevice::ReadWriteData(nand_op_t* operation) {
+zx_status_t NandDevice::ReadWriteData(nand_operation_t* operation) {
     if (operation->rw.data_vmo == ZX_HANDLE_INVALID) {
         return ZX_OK;
     }
@@ -323,7 +329,7 @@
     return zx_vmo_read(operation->rw.data_vmo, addr, vmo_addr, length);
 }
 
-zx_status_t NandDevice::ReadWriteOob(nand_op_t* operation) {
+zx_status_t NandDevice::ReadWriteOob(nand_operation_t* operation) {
     if (operation->rw.oob_vmo == ZX_HANDLE_INVALID) {
         return ZX_OK;
     }
@@ -342,7 +348,7 @@
     return zx_vmo_read(operation->rw.oob_vmo, addr, vmo_addr, length);
 }
 
-zx_status_t NandDevice::Erase(nand_op_t* operation) {
+zx_status_t NandDevice::Erase(nand_operation_t* operation) {
     ZX_DEBUG_ASSERT(operation->command == NAND_OP_ERASE);
 
     uint32_t block_size = params_.page_size * params_.pages_per_block;
diff --git a/system/dev/nand/ram-nand/ram-nand.h b/system/dev/nand/ram-nand/ram-nand.h
index 09c630e..32ee47c 100644
--- a/system/dev/nand/ram-nand/ram-nand.h
+++ b/system/dev/nand/ram-nand/ram-nand.h
@@ -67,23 +67,25 @@
                          void* out_buf, size_t out_len, size_t* out_actual);
 
     // NAND protocol implementation.
-    void Query(nand_info_t* info_out, size_t* nand_op_size_out);
-    void Queue(nand_op_t* operation);
-    zx_status_t GetFactoryBadBlockList(uint32_t* bad_blocks, uint32_t bad_block_len,
-                                       uint32_t* num_bad_blocks);
+    void NandQuery(nand_info_t* info_out, size_t* nand_op_size_out);
+    void NandQueue(nand_operation_t* operation, nand_queue_callback completion_cb,
+                   void* cookie);
+    zx_status_t NandGetFactoryBadBlockList(uint32_t* bad_blocks, size_t bad_block_len,
+                                       size_t* num_bad_blocks);
 
   private:
     void Kill();
-    bool AddToList(nand_op_t* operation);
-    bool RemoveFromList(nand_op_t** operation);
+    bool AddToList(nand_operation_t* operation, nand_queue_callback completion_cb,
+                   void* cookie);
+    bool RemoveFromList(nand_operation_t** operation);
     int WorkerThread();
     static int WorkerThreadStub(void* arg);
     uint32_t MainDataSize() const { return params_.NumPages() * params_.page_size; }
 
     // Implementation of the actual commands.
-    zx_status_t ReadWriteData(nand_op_t* operation);
-    zx_status_t ReadWriteOob(nand_op_t* operation);
-    zx_status_t Erase(nand_op_t* operation);
+    zx_status_t ReadWriteData(nand_operation_t* operation);
+    zx_status_t ReadWriteOob(nand_operation_t* operation);
+    zx_status_t Erase(nand_operation_t* operation);
 
     uintptr_t mapped_addr_ = 0;
     zx::vmo vmo_;
diff --git a/system/dev/nand/ram-nand/test/ram-nand.cpp b/system/dev/nand/ram-nand/test/ram-nand.cpp
index 563aa29..9c26f93 100644
--- a/system/dev/nand/ram-nand/test/ram-nand.cpp
+++ b/system/dev/nand/ram-nand/test/ram-nand.cpp
@@ -79,7 +79,7 @@
 
     if (operation_size) {
         nand_info_t info;
-        device->Query(&info, operation_size);
+        device->NandQuery(&info, operation_size);
     }
 
     char name[NAME_MAX];
@@ -126,9 +126,9 @@
 
     nand_info_t info;
     size_t operation_size;
-    device.Query(&info, &operation_size);
+    device.NandQuery(&info, &operation_size);
     ASSERT_EQ(0, memcmp(&info, &params, sizeof(info)));
-    ASSERT_GT(operation_size, sizeof(nand_op_t));
+    ASSERT_GT(operation_size, sizeof(nand_operation_t));
     END_TEST;
 }
 
@@ -144,19 +144,19 @@
                                nullptr, 0, nullptr));
 
     uint32_t result[4];
-    uint32_t num_bad_blocks;
-    device->GetFactoryBadBlockList(result, sizeof(result), &num_bad_blocks);
+    size_t num_bad_blocks;
+    device->NandGetFactoryBadBlockList(result, sizeof(result), &num_bad_blocks);
     ASSERT_EQ(0, num_bad_blocks);
     END_TEST;
 }
 
-// Data to be pre-pended to a nand_op_t issued to the device.
+// Data to be pre-pended to a nand_operation_t issued to the device.
 struct OpHeader {
     class Operation* operation;
     class NandTest* test;
 };
 
-// Wrapper for a nand_op_t.
+// Wrapper for a nand_operation_t.
 class Operation {
   public:
     explicit Operation(size_t op_size, NandTest* test = 0)
@@ -172,11 +172,11 @@
     size_t buffer_size() const { return buffer_size_; }
     char* buffer() const { return mapped_addr_; }
 
-    // Creates a vmo and sets the handle on the nand_op_t.
+    // Creates a vmo and sets the handle on the nand_operation_t.
     bool SetDataVmo();
     bool SetOobVmo();
 
-    nand_op_t* GetOperation();
+    nand_operation_t* GetOperation();
 
     void OnCompletion(zx_status_t status) {
         status_ = status;
@@ -202,7 +202,7 @@
 };
 
 bool Operation::SetDataVmo() {
-    nand_op_t* operation = GetOperation();
+    nand_operation_t* operation = GetOperation();
     if (!operation) {
         return false;
     }
@@ -211,7 +211,7 @@
 }
 
 bool Operation::SetOobVmo() {
-    nand_op_t* operation = GetOperation();
+    nand_operation_t* operation = GetOperation();
     if (!operation) {
         return false;
     }
@@ -219,11 +219,11 @@
     return operation->rw.oob_vmo != ZX_HANDLE_INVALID;
 }
 
-nand_op_t* Operation::GetOperation() {
+nand_operation_t* Operation::GetOperation() {
     if (!raw_buffer_) {
         CreateOperation();
     }
-    return reinterpret_cast<nand_op_t*>(raw_buffer_.get() + sizeof(OpHeader));
+    return reinterpret_cast<nand_operation_t*>(raw_buffer_.get() + sizeof(OpHeader));
 }
 
 zx_handle_t Operation::GetVmo() {
@@ -266,7 +266,7 @@
     NandTest() {}
     ~NandTest() {}
 
-    static void CompletionCb(nand_op_t* op, zx_status_t status) {
+    static void CompletionCb(void* cookie, zx_status_t status, nand_operation_t* op) {
         OpHeader* header =
                 reinterpret_cast<OpHeader*>(reinterpret_cast<char*>(op) - sizeof(OpHeader));
 
@@ -307,30 +307,29 @@
     NandTest test;
     Operation operation(op_size, &test);
 
-    nand_op_t* op = operation.GetOperation();
+    nand_operation_t* op = operation.GetOperation();
     ASSERT_TRUE(op);
 
     op->rw.command = NAND_OP_WRITE;
-    op->completion_cb = &NandTest::CompletionCb;
-    device->Queue(op);
+    device->NandQueue(op, &NandTest::CompletionCb, nullptr);
 
     ASSERT_TRUE(test.Wait());
     ASSERT_EQ(ZX_ERR_OUT_OF_RANGE, operation.status());
 
     op->rw.length = 1;
-    device->Queue(op);
+    device->NandQueue(op, &NandTest::CompletionCb, nullptr);
     ASSERT_TRUE(test.Wait());
     ASSERT_EQ(ZX_ERR_BAD_HANDLE, operation.status());
 
     op->rw.offset_nand = kNumPages;
-    device->Queue(op);
+    device->NandQueue(op, &NandTest::CompletionCb, nullptr);
     ASSERT_TRUE(test.Wait());
     ASSERT_EQ(ZX_ERR_OUT_OF_RANGE, operation.status());
 
     ASSERT_TRUE(operation.SetDataVmo());
 
     op->rw.offset_nand = kNumPages - 1;
-    device->Queue(op);
+    device->NandQueue(op, &NandTest::CompletionCb, nullptr);
     ASSERT_TRUE(test.Wait());
     ASSERT_EQ(ZX_OK, operation.status());
 
@@ -351,20 +350,18 @@
 
 // Prepares the operation to write num_pages starting at offset.
 void SetForWrite(int offset, int num_pages, Operation* operation) {
-    nand_op_t* op = operation->GetOperation();
+    nand_operation_t* op = operation->GetOperation();
     op->rw.command = NAND_OP_WRITE;
     op->rw.length = num_pages;
     op->rw.offset_nand = offset;
-    op->completion_cb = &NandTest::CompletionCb;
 }
 
 // Prepares the operation to read num_pages starting at offset.
 void SetForRead(int offset, int num_pages, Operation* operation) {
-    nand_op_t* op = operation->GetOperation();
+    nand_operation_t* op = operation->GetOperation();
     op->rw.command = NAND_OP_READ;
     op->rw.length = num_pages;
     op->rw.offset_nand = offset;
-    op->completion_cb = &NandTest::CompletionCb;
 }
 
 bool ReadWriteTest() {
@@ -379,11 +376,11 @@
     ASSERT_TRUE(operation.SetDataVmo());
     memset(operation.buffer(), 0x55, operation.buffer_size());
 
-    nand_op_t* op = operation.GetOperation();
+    nand_operation_t* op = operation.GetOperation();
     op->rw.corrected_bit_flips = 125;
 
     SetForWrite(4, 4, &operation);
-    device->Queue(op);
+    device->NandQueue(op, &NandTest::CompletionCb, nullptr);
 
     ASSERT_TRUE(test.Wait());
     ASSERT_EQ(ZX_OK, operation.status());
@@ -392,7 +389,7 @@
     op->rw.command = NAND_OP_READ;
     memset(operation.buffer(), 0, operation.buffer_size());
 
-    device->Queue(op);
+    device->NandQueue(op, &NandTest::CompletionCb, nullptr);
     ASSERT_TRUE(test.Wait());
     ASSERT_EQ(ZX_OK, operation.status());
     ASSERT_EQ(0, op->rw.corrected_bit_flips);
@@ -415,12 +412,12 @@
     ASSERT_TRUE(operation.SetOobVmo());
     memset(operation.buffer(), 0x55, operation.buffer_size());
 
-    nand_op_t* op = operation.GetOperation();
+    nand_operation_t* op = operation.GetOperation();
     op->rw.corrected_bit_flips = 125;
 
     SetForRead(0, kNumPages, &operation);
     op->rw.offset_oob_vmo = kNumPages;
-    device->Queue(op);
+    device->NandQueue(op, &NandTest::CompletionCb, nullptr);
 
     ASSERT_TRUE(test.Wait());
     ASSERT_EQ(ZX_OK, operation.status());
@@ -468,8 +465,8 @@
     SetForRead(0, 2, operations[9].get());
 
     for (const auto& operation : operations) {
-        nand_op_t* op = operation->GetOperation();
-        device->Queue(op);
+        nand_operation_t* op = operation->GetOperation();
+        device->NandQueue(op, &NandTest::CompletionCb, nullptr);
     }
 
     ASSERT_TRUE(test.WaitFor(10));
@@ -507,33 +504,32 @@
     NandTest test;
     Operation operation(op_size, &test);
 
-    nand_op_t* op = operation.GetOperation();
+    nand_operation_t* op = operation.GetOperation();
     op->rw.command = NAND_OP_READ;
-    op->completion_cb = &NandTest::CompletionCb;
 
-    device->Queue(op);
+    device->NandQueue(op, &NandTest::CompletionCb, nullptr);
     ASSERT_TRUE(test.Wait());
     ASSERT_EQ(ZX_ERR_OUT_OF_RANGE, operation.status());
 
     op->rw.length = 1;
-    device->Queue(op);
+    device->NandQueue(op, &NandTest::CompletionCb, nullptr);
     ASSERT_TRUE(test.Wait());
     ASSERT_EQ(ZX_ERR_BAD_HANDLE, operation.status());
 
     op->rw.offset_nand = kNumPages;
-    device->Queue(op);
+    device->NandQueue(op, &NandTest::CompletionCb, nullptr);
     ASSERT_TRUE(test.Wait());
     ASSERT_EQ(ZX_ERR_OUT_OF_RANGE, operation.status());
 
     ASSERT_TRUE(operation.SetOobVmo());
 
     op->rw.offset_nand = kNumPages - 1;
-    device->Queue(op);
+    device->NandQueue(op, &NandTest::CompletionCb, nullptr);
     ASSERT_TRUE(test.Wait());
     ASSERT_EQ(ZX_OK, operation.status());
 
     op->rw.length = 5;
-    device->Queue(op);
+    device->NandQueue(op, &NandTest::CompletionCb, nullptr);
     ASSERT_TRUE(test.Wait());
     ASSERT_EQ(ZX_ERR_OUT_OF_RANGE, operation.status());
 
@@ -554,11 +550,11 @@
     const char desired[kOobSize] = { 'a', 'b', 'c', 'd' };
     memcpy(operation.buffer(), desired, kOobSize);
 
-    nand_op_t* op = operation.GetOperation();
+    nand_operation_t* op = operation.GetOperation();
     op->rw.corrected_bit_flips = 125;
 
     SetForWrite(2, 1, &operation);
-    device->Queue(op);
+    device->NandQueue(op, &NandTest::CompletionCb, nullptr);
 
     ASSERT_TRUE(test.Wait());
     ASSERT_EQ(ZX_OK, operation.status());
@@ -569,7 +565,7 @@
     op->rw.offset_nand = 1;
     memset(operation.buffer(), 0, kOobSize * 2);
 
-    device->Queue(op);
+    device->NandQueue(op, &NandTest::CompletionCb, nullptr);
     ASSERT_TRUE(test.Wait());
     ASSERT_EQ(ZX_OK, operation.status());
     ASSERT_EQ(0, op->rw.corrected_bit_flips);
@@ -595,12 +591,12 @@
     memset(operation.buffer(), 0x55, kPageSize * 2);
     memset(operation.buffer() + kPageSize * 2, 0xaa, kOobSize * 2);
 
-    nand_op_t* op = operation.GetOperation();
+    nand_operation_t* op = operation.GetOperation();
     op->rw.corrected_bit_flips = 125;
 
     SetForWrite(2, 2, &operation);
     op->rw.offset_oob_vmo = 2;  // OOB is right after data.
-    device->Queue(op);
+    device->NandQueue(op, &NandTest::CompletionCb, nullptr);
 
     ASSERT_TRUE(test.Wait());
     ASSERT_EQ(ZX_OK, operation.status());
@@ -609,7 +605,7 @@
     op->rw.command = NAND_OP_READ;
     memset(operation.buffer(), 0, kPageSize * 4);
 
-    device->Queue(op);
+    device->NandQueue(op, &NandTest::CompletionCb, nullptr);
     ASSERT_TRUE(test.Wait());
     ASSERT_EQ(ZX_OK, operation.status());
     ASSERT_EQ(0, op->rw.corrected_bit_flips);
@@ -635,23 +631,22 @@
     Operation operation(op_size, &test);
     ASSERT_TRUE(operation.SetDataVmo());
 
-    nand_op_t* op = operation.GetOperation();
+    nand_operation_t* op = operation.GetOperation();
     op->erase.command = NAND_OP_ERASE;
-    op->completion_cb = &NandTest::CompletionCb;
 
-    device->Queue(op);
+    device->NandQueue(op, &NandTest::CompletionCb, nullptr);
     ASSERT_TRUE(test.Wait());
     ASSERT_EQ(ZX_ERR_OUT_OF_RANGE, operation.status());
 
     op->erase.first_block = 5;
     op->erase.num_blocks = 1;
-    device->Queue(op);
+    device->NandQueue(op, &NandTest::CompletionCb, nullptr);
     ASSERT_TRUE(test.Wait());
     ASSERT_EQ(ZX_ERR_OUT_OF_RANGE, operation.status());
 
     op->erase.first_block = 4;
     op->erase.num_blocks = 2;
-    device->Queue(op);
+    device->NandQueue(op, &NandTest::CompletionCb, nullptr);
     ASSERT_TRUE(test.Wait());
     ASSERT_EQ(ZX_ERR_OUT_OF_RANGE, operation.status());
 
@@ -668,13 +663,12 @@
     NandTest test;
     Operation operation(op_size, &test);
 
-    nand_op_t* op = operation.GetOperation();
+    nand_operation_t* op = operation.GetOperation();
     op->erase.command = NAND_OP_ERASE;
     op->erase.first_block = 3;
     op->erase.num_blocks = 2;
-    op->completion_cb = &NandTest::CompletionCb;
 
-    device->Queue(op);
+    device->NandQueue(op, &NandTest::CompletionCb, nullptr);
     ASSERT_TRUE(test.Wait());
     ASSERT_EQ(ZX_OK, operation.status());
 
@@ -683,7 +677,7 @@
     ASSERT_TRUE(operation.SetDataVmo());
     ASSERT_TRUE(operation.SetOobVmo());
     op->rw.offset_oob_vmo = kNumPages;
-    device->Queue(op);
+    device->NandQueue(op, &NandTest::CompletionCb, nullptr);
 
     ASSERT_TRUE(test.Wait());
     ASSERT_EQ(ZX_OK, operation.status());
diff --git a/system/dev/nand/skip-block/skip-block.cpp b/system/dev/nand/skip-block/skip-block.cpp
index 42f6e3b..a9f65ea 100644
--- a/system/dev/nand/skip-block/skip-block.cpp
+++ b/system/dev/nand/skip-block/skip-block.cpp
@@ -37,8 +37,8 @@
 
 // Called when all page reads in a block finish. If another block still needs
 // to be read, it queues it up as another operation.
-void ReadCompletionCallback(nand_op_t* op, zx_status_t status) {
-    auto* ctx = static_cast<BlockOperationContext*>(op->cookie);
+void ReadCompletionCallback(void* cookie, zx_status_t status, nand_operation_t* op) {
+    auto* ctx = static_cast<BlockOperationContext*>(cookie);
     if (status != ZX_OK || ctx->current_block + 1 == ctx->op.block + ctx->op.block_count) {
         ctx->status = status;
         ctx->mark_bad = false;
@@ -57,16 +57,16 @@
 
     op->rw.offset_nand = ctx->physical_block * ctx->nand_info->pages_per_block;
     op->rw.offset_data_vmo += ctx->nand_info->pages_per_block;
-    ctx->nand->Queue(op);
+    ctx->nand->Queue(op, ReadCompletionCallback, cookie);
     return;
 }
 
-void EraseCompletionCallback(nand_op_t* op, zx_status_t status);
+void EraseCompletionCallback(void* cookie, zx_status_t status, nand_operation_t* op);
 
 // Called when all page writes in a block finish. If another block still needs
 // to be written, it queues up an erase.
-void WriteCompletionCallback(nand_op_t* op, zx_status_t status) {
-    auto* ctx = static_cast<BlockOperationContext*>(op->cookie);
+void WriteCompletionCallback(void* cookie, zx_status_t status, nand_operation_t* op) {
+    auto* ctx = static_cast<BlockOperationContext*>(cookie);
 
     if (status != ZX_OK || ctx->current_block + 1 == ctx->op.block + ctx->op.block_count) {
         ctx->status = status;
@@ -87,15 +87,14 @@
     op->erase.command = NAND_OP_ERASE;
     op->erase.first_block = ctx->physical_block;
     op->erase.num_blocks = 1;
-    op->completion_cb = EraseCompletionCallback;
-    ctx->nand->Queue(op);
+    ctx->nand->Queue(op, EraseCompletionCallback, cookie);
     return;
 }
 
 // Called when a block erase operation finishes. Subsequently queues up writes
 // to the block.
-void EraseCompletionCallback(nand_op_t* op, zx_status_t status) {
-    auto* ctx = static_cast<BlockOperationContext*>(op->cookie);
+void EraseCompletionCallback(void* cookie, zx_status_t status, nand_operation_t* op) {
+    auto* ctx = static_cast<BlockOperationContext*>(cookie);
 
     if (status != ZX_OK) {
         ctx->status = status;
@@ -109,9 +108,8 @@
     op->rw.length = ctx->nand_info->pages_per_block;
     op->rw.offset_nand = ctx->physical_block * ctx->nand_info->pages_per_block;
     op->rw.offset_data_vmo = ctx->op.vmo_offset;
-    op->rw.pages = nullptr;
-    op->completion_cb = WriteCompletionCallback;
-    ctx->nand->Queue(op);
+    op->rw.page_list = nullptr;
+    ctx->nand->Queue(op, WriteCompletionCallback, cookie);
     return;
 }
 
@@ -167,7 +165,7 @@
 }
 
 zx_status_t SkipBlockDevice::GetBadBlockList(fbl::Array<uint32_t>* bad_blocks) {
-    uint32_t bad_block_count;
+    size_t bad_block_count;
     zx_status_t status = bad_block_.GetBadBlockList(nullptr, 0, &bad_block_count);
     if (status != ZX_OK) {
         return status;
@@ -176,7 +174,7 @@
         bad_blocks->reset();
         return ZX_OK;
     }
-    const uint32_t bad_block_list_len = bad_block_count;
+    const size_t bad_block_list_len = bad_block_count;
     fbl::unique_ptr<uint32_t[]> bad_block_list(new uint32_t[bad_block_count]);
     status = bad_block_.GetBadBlockList(bad_block_list.get(), bad_block_list_len, &bad_block_count);
     if (status != ZX_OK) {
@@ -194,9 +192,9 @@
 
     fbl::AutoLock al(&lock_);
 
-    if (sizeof(nand_op_t) > parent_op_size_) {
+    if (sizeof(nand_operation_t) > parent_op_size_) {
         zxlogf(ERROR, "skip-block: parent op size, %zu, is smaller than minimum op size: %zu\n",
-               sizeof(nand_op_t), parent_op_size_);
+               sizeof(nand_operation_t), parent_op_size_);
         return ZX_ERR_INTERNAL;
     }
 
@@ -276,7 +274,7 @@
         .mark_bad = false,
     };
 
-    auto* nand_op = reinterpret_cast<nand_op_t*>(nand_op_.get());
+    auto* nand_op = reinterpret_cast<nand_operation_t*>(nand_op_.get());
     nand_op->rw.command = NAND_OP_READ;
     nand_op->rw.data_vmo = op.vmo;
     nand_op->rw.oob_vmo = ZX_HANDLE_INVALID;
@@ -284,9 +282,7 @@
     nand_op->rw.offset_nand = physical_block * nand_info_.pages_per_block;
     nand_op->rw.offset_data_vmo = op.vmo_offset;
     // The read callback will enqueue subsequent reads.
-    nand_op->completion_cb = ReadCompletionCallback;
-    nand_op->cookie = &op_context;
-    nand_.Queue(nand_op);
+    nand_.Queue(nand_op, ReadCompletionCallback, &op_context);
 
     // Wait on completion.
     sync_completion_wait(&completion, ZX_TIME_INFINITE);
@@ -323,14 +319,12 @@
                 .mark_bad = false,
             };
 
-            auto* nand_op = reinterpret_cast<nand_op_t*>(nand_op_.get());
+            auto* nand_op = reinterpret_cast<nand_operation_t*>(nand_op_.get());
             nand_op->erase.command = NAND_OP_ERASE;
             nand_op->erase.first_block = physical_block;
             nand_op->erase.num_blocks = 1;
             // The erase callback will enqueue subsequent writes and erases.
-            nand_op->completion_cb = EraseCompletionCallback;
-            nand_op->cookie = &op_context;
-            nand_.Queue(nand_op);
+            nand_.Queue(nand_op, EraseCompletionCallback, &op_context);
 
             // Wait on completion.
             sync_completion_wait(&completion, ZX_TIME_INFINITE);
diff --git a/system/dev/scpi/aml-scpi-s912/aml-mailbox.c b/system/dev/scpi/aml-scpi-s912/aml-mailbox.c
index d272769..22990de 100644
--- a/system/dev/scpi/aml-scpi-s912/aml-mailbox.c
+++ b/system/dev/scpi/aml-scpi-s912/aml-mailbox.c
@@ -34,8 +34,8 @@
 }
 
 static zx_status_t aml_mailbox_send_cmd(void* ctx,
-                                        mailbox_channel_t* channel,
-                                        mailbox_data_buf_t* mdata) {
+                                        const mailbox_channel_t* channel,
+                                        const mailbox_data_buf_t* mdata) {
     aml_mailbox_t* mailbox = ctx;
     int rx_mailbox_id;
     if (!channel || !mdata) {
@@ -53,7 +53,7 @@
 
     if (mdata->tx_size != 0) {
         uint32_t num = GET_NUM_WORDS(mdata->tx_size);
-        uint32_t* tx_payload = (uint32_t*)(mdata->tx_buf);
+        uint32_t* tx_payload = (uint32_t*)(mdata->tx_buffer);
         for (uint32_t i = 0; i < num; i++) {
             // AP writes parameters to Payload
             WRITE32_MAILBOX_PL_REG(tx_mailbox->payload_offset + i, tx_payload[i]);
@@ -73,7 +73,7 @@
     // AP reads the Payload to get requested information
     if (channel->rx_size != 0) {
         uint32_t num = GET_NUM_WORDS(channel->rx_size);
-        uint32_t* rx_payload = (uint32_t*)(channel->rx_buf);
+        uint32_t* rx_payload = (uint32_t*)(channel->rx_buffer);
         for (uint32_t i = 0; i < num; i++) {
             rx_payload[i] = READ32_MAILBOX_PL_REG(rx_mailbox->payload_offset + i);
         }
@@ -103,7 +103,7 @@
 };
 
 static mailbox_protocol_ops_t mailbox_ops = {
-    .send_cmd = aml_mailbox_send_cmd,
+    .send_command = aml_mailbox_send_cmd,
 };
 
 static zx_status_t aml_mailbox_bind(void* ctx, zx_device_t* parent) {
diff --git a/system/dev/scpi/aml-scpi-s912/aml-scpi.c b/system/dev/scpi/aml-scpi-s912/aml-scpi.c
index 4bb83ce..3d43e75 100644
--- a/system/dev/scpi/aml-scpi-s912/aml-scpi.c
+++ b/system/dev/scpi/aml-scpi-s912/aml-scpi.c
@@ -56,7 +56,7 @@
     uint32_t mailbox_status = 0;
     mailbox_data_buf_t mdata;
     mdata.cmd = PACK_SCPI_CMD(cmd, client_id, 0);
-    mdata.tx_buf = tx_buf;
+    mdata.tx_buffer = tx_buf;
     mdata.tx_size = tx_size;
 
     mailbox_channel_t channel;
@@ -66,15 +66,15 @@
         return status;
     }
 
-    channel.rx_buf = rx_buf;
+    channel.rx_buffer = rx_buf;
     channel.rx_size = rx_size;
 
-    status = mailbox_send_cmd(&scpi->mailbox, &channel, &mdata);
+    status = mailbox_send_command(&scpi->mailbox, &channel, &mdata);
     if (rx_buf) {
         mailbox_status = *(uint32_t*)(rx_buf);
     }
     if (status != ZX_OK || mailbox_status != 0) {
-        SCPI_ERROR("mailbox_send_cmd failed - error status %d\n", status);
+        SCPI_ERROR("mailbox_send_command failed - error status %d\n", status);
         return status;
     }
     return ZX_OK;
diff --git a/system/dev/serial/aml-uart/aml-uart.cpp b/system/dev/serial/aml-uart/aml-uart.cpp
index a333f87..1408eaf 100644
--- a/system/dev/serial/aml-uart/aml-uart.cpp
+++ b/system/dev/serial/aml-uart/aml-uart.cpp
@@ -20,6 +20,7 @@
 #include <fbl/auto_call.h>
 #include <fbl/auto_lock.h>
 #include <hwreg/mmio.h>
+#include <zircon/device/serial.h>
 #include <zircon/threads.h>
 #include <zircon/types.h>
 
@@ -69,7 +70,7 @@
     constexpr uint32_t kDefaultBaudRate = 115200;
     constexpr uint32_t kDefaultConfig =
         SERIAL_DATA_BITS_8 | SERIAL_STOP_BITS_1 | SERIAL_PARITY_NONE;
-    uart->Config(kDefaultBaudRate, kDefaultConfig);
+    uart->SerialImplConfig(kDefaultBaudRate, kDefaultConfig);
 
     status = uart->DdkAdd("aml-uart");
     if (status != ZX_OK) {
@@ -121,12 +122,12 @@
     return 0;
 }
 
-zx_status_t AmlUart::GetInfo(serial_port_info_t* info) {
+zx_status_t AmlUart::SerialImplGetInfo(serial_port_info_t* info) {
     memcpy(info, &serial_port_info_, sizeof(*info));
     return ZX_OK;
 }
 
-zx_status_t AmlUart::Config(uint32_t baud_rate, uint32_t flags) {
+zx_status_t AmlUart::SerialImplConfig(uint32_t baud_rate, uint32_t flags) {
     hwreg::RegisterIo mmio(io_buffer_virt(&mmio_));
 
     // Control register is determined completely by this logic, so start with a clean slate.
@@ -261,7 +262,7 @@
     }
 }
 
-zx_status_t AmlUart::Enable(bool enable) {
+zx_status_t AmlUart::SerialImplEnable(bool enable) {
     fbl::AutoLock al(&enable_lock_);
 
     if (enable && !enabled_) {
@@ -289,7 +290,7 @@
     return ZX_OK;
 }
 
-zx_status_t AmlUart::Read(void* buf, size_t length, size_t* out_actual) {
+zx_status_t AmlUart::SerialImplRead(void* buf, size_t length, size_t* out_actual) {
     hwreg::RegisterIo mmio(io_buffer_virt(&mmio_));
 
     auto* bufptr = static_cast<uint8_t*>(buf);
@@ -307,7 +308,7 @@
     return ZX_OK;
 }
 
-zx_status_t AmlUart::Write(const void* buf, size_t length, size_t* out_actual) {
+zx_status_t AmlUart::SerialImplWrite(const void* buf, size_t length, size_t* out_actual) {
     hwreg::RegisterIo mmio(io_buffer_virt(&mmio_));
 
     const auto* bufptr = static_cast<const uint8_t*>(buf);
@@ -324,7 +325,7 @@
     return ZX_OK;
 }
 
-zx_status_t AmlUart::SetNotifyCallback(serial_notify_cb cb, void* cookie) {
+zx_status_t AmlUart::SerialImplSetNotifyCallback(const serial_notify_t* cb) {
     {
         fbl::AutoLock al(&enable_lock_);
 
@@ -334,7 +335,8 @@
         }
 
         fbl::AutoLock al2(&status_lock_);
-        notify_cb_ = [=](uint32_t state) { cb(state, cookie); };
+        serial_notify_t notify_cb = *cb;
+        notify_cb_ = [=](uint32_t state) { notify_cb.callback(notify_cb.ctx, state); };
     }
 
     // This will trigger notifying current state.
diff --git a/system/dev/serial/aml-uart/aml-uart.h b/system/dev/serial/aml-uart/aml-uart.h
index 33eff7d..33e5001 100644
--- a/system/dev/serial/aml-uart/aml-uart.h
+++ b/system/dev/serial/aml-uart/aml-uart.h
@@ -33,18 +33,18 @@
         DdkRemove();
     }
     void DdkRelease() {
-        Enable(false);
+        SerialImplEnable(false);
         io_buffer_release(&mmio_);
         delete this;
     }
 
     // Serial protocol implementation.
-    zx_status_t GetInfo(serial_port_info_t* info);
-    zx_status_t Config(uint32_t baud_rate, uint32_t flags);
-    zx_status_t Enable(bool enable);
-    zx_status_t Read(void* buf, size_t length, size_t* out_actual);
-    zx_status_t Write(const void* buf, size_t length, size_t* out_actual);
-    zx_status_t SetNotifyCallback(serial_notify_cb cb, void* cookie);
+    zx_status_t SerialImplGetInfo(serial_port_info_t* info);
+    zx_status_t SerialImplConfig(uint32_t baud_rate, uint32_t flags);
+    zx_status_t SerialImplEnable(bool enable);
+    zx_status_t SerialImplRead(void* buf, size_t length, size_t* out_actual);
+    zx_status_t SerialImplWrite(const void* buf, size_t length, size_t* out_actual);
+    zx_status_t SerialImplSetNotifyCallback(const serial_notify_t* cb);
 
 private:
     using Callback = fbl::Function<void(uint32_t)>;
diff --git a/system/dev/serial/ftdi/ftdi.c b/system/dev/serial/ftdi/ftdi.c
index 28d429a..8f5fe67 100644
--- a/system/dev/serial/ftdi/ftdi.c
+++ b/system/dev/serial/ftdi/ftdi.c
@@ -9,6 +9,7 @@
 #include <ddk/protocol/serial-impl.h>
 #include <ddk/protocol/usb.h>
 #include <ddk/usb/usb.h>
+#include <zircon/device/serial.h>
 #include <zircon/listnode.h>
 #include <zircon/hw/usb.h>
 
@@ -45,8 +46,7 @@
     serial_port_info_t serial_port_info;
     serial_impl_protocol_t serial;
 
-    serial_notify_cb notify_cb;
-    void* notify_cb_cookie;
+    serial_notify_t notify_cb;
     bool enabled;
     uint32_t state;
     // pool of free USB requests
@@ -68,8 +68,8 @@
 
     if (state != ftdi->state) {
         ftdi->state = state;
-        if (ftdi->notify_cb) {
-            ftdi->notify_cb(state, ftdi->notify_cb_cookie);
+        if (ftdi->notify_cb.callback) {
+            ftdi->notify_cb.callback(ftdi->notify_cb.ctx, state);
         }
     }
     return state;
@@ -278,15 +278,14 @@
     return ZX_OK;
 }
 
-static zx_status_t ftdi_set_notify_callback(void* ctx, serial_notify_cb cb, void* cookie) {
+static zx_status_t ftdi_set_notify_callback(void* ctx, const serial_notify_t* cb) {
     ftdi_t* ftdi = ctx;
 
     if (ftdi->enabled) {
         return ZX_ERR_BAD_STATE;
     }
 
-    ftdi->notify_cb = cb;
-    ftdi->notify_cb_cookie = cookie;
+    ftdi->notify_cb = *cb;
 
     mtx_lock(&ftdi->mutex);
     ftdi_check_state(ftdi);
@@ -295,7 +294,7 @@
     return ZX_OK;
 }
 
-static serial_impl_ops_t ftdi_serial_ops = {
+static serial_impl_protocol_ops_t ftdi_serial_ops = {
     .get_info = ftdi_serial_get_info,
     .config = ftdi_serial_config,
     .enable = ftdi_serial_enable,
diff --git a/system/dev/serial/serial/serial.c b/system/dev/serial/serial/serial.c
index a2e5546..7b1ff8d 100644
--- a/system/dev/serial/serial/serial.c
+++ b/system/dev/serial/serial/serial.c
@@ -37,6 +37,8 @@
 #define EVENT_WRITABLE_SIGNAL ZX_USER_SIGNAL_1
 #define EVENT_CANCEL_SIGNAL ZX_USER_SIGNAL_2
 
+const serial_notify_t kNoCallback = {NULL, NULL};
+
 // This thread handles data transfer in both directions
 static int platform_serial_thread(void* arg) {
     serial_port_t* port = arg;
@@ -136,7 +138,7 @@
     }
 
     serial_impl_enable(&port->serial, false);
-    serial_impl_set_notify_callback(&port->serial, NULL, NULL);
+    serial_impl_set_notify_callback(&port->serial, &kNoCallback);
 
     zx_handle_close(port->event);
     zx_handle_close(port->socket);
@@ -149,7 +151,7 @@
     return 0;
 }
 
-static void platform_serial_state_cb(uint32_t state, void* cookie) {
+static void platform_serial_state_cb(void* cookie, uint32_t state) {
     serial_port_t* port = cookie;
 
     // update our event handle signals with latest state from the serial driver
@@ -213,7 +215,7 @@
         goto fail;
     }
 
-    serial_impl_set_notify_callback(&port->serial, platform_serial_state_cb, port);
+    serial_impl_set_notify_callback(&port->serial, &(serial_notify_t){platform_serial_state_cb, port});
 
     status = serial_impl_enable(&port->serial, true);
     if (status != ZX_OK) {
@@ -255,7 +257,7 @@
         return ZX_ERR_ALREADY_BOUND;
     }
 
-    serial_impl_set_notify_callback(&port->serial, platform_serial_state_cb, port);
+    serial_impl_set_notify_callback(&port->serial, &(serial_notify_t){platform_serial_state_cb, port});
 
     zx_status_t status = serial_impl_enable(&port->serial, true);
     if (status == ZX_OK) {
@@ -272,7 +274,7 @@
     mtx_lock(&port->lock);
 
     if (port->open) {
-        serial_impl_set_notify_callback(&port->serial, NULL, NULL);
+        serial_impl_set_notify_callback(&port->serial, &kNoCallback);
         serial_impl_enable(&port->serial, false);
         port->open = false;
         mtx_unlock(&port->lock);
@@ -333,7 +335,7 @@
     serial_port_t* port = ctx;
 
     serial_impl_enable(&port->serial, false);
-    serial_impl_set_notify_callback(&port->serial, NULL, NULL);
+    serial_impl_set_notify_callback(&port->serial, &kNoCallback);
     zx_handle_close(port->event);
     zx_handle_close(port->socket);
     free(port);
diff --git a/system/dev/test/ddk-test/ddk-test.c b/system/dev/test/ddk-test/ddk-test.c
index 10afe69..c35b0b6 100644
--- a/system/dev/test/ddk-test/ddk-test.c
+++ b/system/dev/test/ddk-test/ddk-test.c
@@ -34,7 +34,7 @@
     }
 }
 
-static zx_status_t ddk_test_func(void* cookie, test_report_t* report, const void* arg, size_t arglen) {
+static zx_status_t ddk_test_func(void* cookie, const void* arg, size_t arglen, test_report_t* report) {
     zx_device_t* dev = (zx_device_t*)cookie;
 
     test_protocol_t proto;
@@ -62,6 +62,6 @@
     }
 
     ddk_test_dev = parent;
-    proto.ops->set_test_func(proto.ctx, ddk_test_func, parent);
+    proto.ops->set_test_func(proto.ctx, &(test_func_t){ddk_test_func, parent});
     return ZX_OK;
 }
diff --git a/system/fidl/ddk/protocols/acpi.fidl b/system/fidl/ddk/protocols/acpi.fidl
new file mode 100644
index 0000000..75cb1eb
--- /dev/null
+++ b/system/fidl/ddk/protocols/acpi.fidl
@@ -0,0 +1,14 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.acpi;
+
+using zx;
+
+[Layout="ddk-protocol", DefaultProtocol]
+interface Acpi {
+  1: MapResource(uint32 resource_id, uint32 cache_policy) -> (zx.status s, vector<void>? vaddr,
+                                                              handle<resource> @handle);
+  2: MapInterrupt(int64 irq_id) -> (zx.status s, handle<interrupt> @handle);
+};
diff --git a/system/fidl/ddk/protocols/amlogic-canvas.fidl b/system/fidl/ddk/protocols/amlogic-canvas.fidl
new file mode 100644
index 0000000..93d7f67
--- /dev/null
+++ b/system/fidl/ddk/protocols/amlogic-canvas.fidl
@@ -0,0 +1,24 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.amlogic_canvas;
+
+using zx;
+
+struct CanvasInfo {
+    uint32 height;
+    uint32 stride_bytes;
+    uint32 wrap;
+    uint32 blkmode;
+    uint32 endianness;
+};
+
+[Layout="ddk-protocol", DefaultProtocol]
+interface Canvas {
+    /// Configures a canvas.
+    /// Adds a framebuffer to the canvas lookup table.
+    1: Config(handle<vmo> vmo, usize offset, CanvasInfo info) -> (zx.status s, uint8 canvas_idx);
+    /// Frees up a canvas.
+    2: Free(uint8 canvas_idx) -> (zx.status s);
+};
diff --git a/system/fidl/ddk/protocols/bad-block.fidl b/system/fidl/ddk/protocols/bad-block.fidl
new file mode 100644
index 0000000..5fbe9a4
--- /dev/null
+++ b/system/fidl/ddk/protocols/bad-block.fidl
@@ -0,0 +1,20 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.bad_block;
+
+using zx;
+
+[Layout="ddk-protocol"]
+interface BadBlock {
+  /// Fills in |bad_blocks| with a list of bad blocks, up until
+  /// |bad_blocks_count|. The order of blocks is undefined.
+  /// |bad_blocks_actual| will be filled in with the actual number of bad
+  /// blocks. It is recommended to first make call with |bad_blocks_count|
+  /// equal to 0 in order to determine how large the |bad_blocks| is.
+  1: GetBadBlockList() -> (zx.status s, vector<uint32> bad_blocks);
+
+  /// Sets |block| as bad. If block is already marked bad, it has no effect.
+  2: MarkBlockBad(uint32 block) -> (zx.status s);
+};
diff --git a/system/fidl/ddk/protocols/block.fidl b/system/fidl/ddk/protocols/block.fidl
new file mode 100644
index 0000000..c825f9b
--- /dev/null
+++ b/system/fidl/ddk/protocols/block.fidl
@@ -0,0 +1,92 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.block;
+
+using zircon.device.block;
+using zx;
+
+struct BlockReadWrite {
+    /// Command and flags.
+    uint32 command;
+    /// Available for temporary use.
+    uint32 extra;
+    /// VMO of data to read or write.
+    handle<vmo> vmo;
+    /// Transfer length in blocks (0 is invalid).
+    uint32 length;
+    /// Device offset in blocks.
+    uint64 offset_dev;
+    /// VMO offset in blocks.
+    uint64 offset_vmo;
+    /// Optional physical page list.
+    vector<uint64>? page;
+};
+
+struct BlockTrim {
+    /// Command and flags.
+    uint32 command;
+    // ???
+};
+
+union BlockOp {
+    /// All Commands
+    uint32 command;
+    /// `BLOCK_OP_READ`, `BLOCK_OP_WRITE`
+    BlockReadWrite rw;
+    /// `BLOCK_OP_TRIM`
+    BlockTrim trim;
+};
+
+/// Read and Write ops use rw for parameters.
+///
+/// If rw.pages is not NULL, the VMO is already appropriately pinned
+/// for IO and pages is an array of the physical addresses covering
+/// offset_vmo * block_size through (offset_vmo + length + 1U) * block_size.
+///
+/// The number of entries in this array is always
+/// ((rw.length + 1U * block_size + PAGE_SIZE - 1) / PAGE_SIZE)
+const uint32 BLOCK_OP_READ = 0x00000001;
+const uint32 BLOCK_OP_WRITE = 0x00000002;
+
+/// Write any controller or device cached data to nonvolatile storage.
+/// This operation always implies BARRIER_BEFORE and BARRIER_AFTER,
+/// meaning that previous operations will complete before it starts
+/// and later operations will not start until it is done.
+const uint32 BLOCK_OP_FLUSH = 0x00000003;
+
+// TBD
+const uint32 BLOCK_OP_TRIM = 0x00000004;
+const uint32 BLOCK_OP_MASK = 0x000000FF;
+
+/// Mark this operation as "Force Unit Access" (FUA), indicating that
+/// it should not complete until the data is written to the non-volatile
+/// medium (write), and that reads should bypass any on-device caches.
+const uint32 BLOCK_FL_FORCE_ACCESS = 0x00001000;
+
+/// Require that this operation will not begin until all previous
+/// operations have completed.
+///
+/// Prevents earlier operations from being reordered after this one.
+const uint32 BLOCK_FL_BARRIER_BEFORE = 0x00000100;
+
+/// Require that this operation complete before any subsequent
+/// operations are started.
+///
+/// Prevents later operations from being reordered before this one.
+const uint32 BLOCK_FL_BARRIER_AFTER = 0x00000200;
+
+[Layout="ddk-protocol", DefaultProtocol]
+interface Block {
+  /// Obtain the parameters of the block device (block_info_t) and
+  /// the required size of block_txn_t.  The block_txn_t's submitted
+  /// via queue() must have block_op_size_out - sizeof(block_op_t) bytes
+  /// available at the end of the structure for the use of the driver.
+  1: Query() -> (zircon.device.block.BlockInfo info, usize block_op_size);
+  /// Submit an IO request for processing.  Success or failure will
+  /// be reported via the completion_cb() in the block_op_t.  This
+  /// callback may be called before the queue() method returns.
+  [Async]
+  2: Queue(BlockOp? txn) -> (zx.status status, BlockOp op);
+};
diff --git a/system/fidl/ddk/protocols/bt-gatt-svc.fidl b/system/fidl/ddk/protocols/bt-gatt-svc.fidl
new file mode 100644
index 0000000..43b6935
--- /dev/null
+++ b/system/fidl/ddk/protocols/bt-gatt-svc.fidl
@@ -0,0 +1,132 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.bt_gatt_svc;
+
+using zx;
+
+//using BtGattId = uint64;
+enum BtGattId : uint64 {};
+
+struct BtGattUuid {
+    array<uint8>:16 bytes;
+};
+
+/// ATT protocol error codes.
+enum BtGattErr : uint8 {
+    NO_ERROR = 0x00;
+    INVALID_HANDLE = 0x01;
+    READ_NOT_PERMITTED = 0x02;
+    WRITE_NOT_PERMITTED = 0x03;
+    INVALID_PDU = 0x04;
+    INSUFFICIENT_AUTHENTICATION = 0x05;
+    REQUEST_NOT_SUPPORTED = 0x06;
+    INVALID_OFFSET = 0x07;
+    INSUFFICIENT_AUTHORIZATION = 0x08;
+    PREPARE_QUEUE_FULL = 0x09;
+    ATTRIBUTE_NOT_FOUND = 0x0A;
+    ATTRIBUTENOTLONG = 0x0B;
+    INSUFFICIENT_ENCRYPTION_KEY_SIZE = 0x0C;
+    INVALID_ATTRIBUTE_VALUE_LENGTH = 0x0D;
+    UNLIKELY_ERROR = 0x0E;
+    INSUFFICIENT_ENCRYPTION = 0x0F;
+    UNSUPPORTED_GROUP_TYPE = 0x10;
+    INSUFFICIENT_RESOURCES = 0x11;
+};
+
+/// Represents the status of a GATT operation.
+struct BtGattStatus {
+    /// Represents errors reported by the host (i.e. not over ATT).
+    zx.status status;
+
+    /// ATT protocol error.
+    BtGattErr att_ecode;
+};
+
+//inline bool bt_gatt_status_is_success(bt_gatt_status_t* status) {
+//    return (status->status == ZX_OK) &&
+//           (status->att_ecode == BT_GATT_ERR_NO_ERROR);
+//}
+
+/// Possible values for the characteristic properties bitfield.
+enum BtGattChrPropr : uint8 {
+    BROADCAST = 0x01;
+    READ = 0x02;
+    WRITE_WITHOUT_RESPONSE = 0x04;
+    WRITE = 0x08;
+    NOTIFY = 0x10;
+    INDICATE = 0x20;
+    AUTHENTICATED_SIGNED_WRITES = 0x40;
+    EXTENDED_PROPERTIES = 0x80;
+};
+
+enum BtGattChrExtProp : uint16 {
+    RELIABLE_WRITE = 0x0100;
+    WRITABLE_AUXILIARIES = 0x0200;
+};
+
+/// Represents a GATT characteristic descriptor.
+struct BtGattDescriptor {
+    BtGattId id;
+    BtGattUuid type;
+};
+
+/// Represents a GATT characteristic.
+struct BtGattChr {
+    BtGattId id;
+    BtGattUuid type;
+
+    /// The bitmask of characteristic properties. The |extended_properties| field
+    /// is populated if the "Characteristic Extended Properties" descriptor is
+    /// present.
+    ///
+    /// See enums |BtGattChrProp| and |BtGattChrExtProp| for possible bit values.
+    uint8 properties;
+    uint16 extended_properties;
+
+    vector<BtGattDescriptor> descriptor;
+};
+
+/// Value change notification callback of the |EnableNotifications| function.
+[Layout="ddk-callback"]
+interface BtGattNotificationValue {
+    1: Callback(BtGattId id, vector<void> value) -> ();
+};
+
+[Layout="ddk-protocol"]
+interface BtGattSvc {
+    /// Connects to and starts characteristic discovery on the remote service.
+    ///
+    /// |status| will contain the result of the characteristic discovery procedure if it was
+    /// initiated by |connect|. The service will be ready to receive further requests once this
+    /// has been called successfully and the |status| callback has been called with success.
+    [Async]
+    1: Connect() -> (BtGattStatus status, vector<BtGattChr> characteristic);
+
+    /// Stops this service and unregisters previously registered callbacks.
+    2: Stop() -> ();
+
+    /// Reads the value of the characteristic with the given ID.
+    [Async]
+    3: ReadCharacteristic(BtGattId id) -> (BtGattStatus status, BtGattId id, vector<void> value);
+
+    /// Reads the long value of the characteristic with the given ID.
+    [Async]
+    4: ReadLongCharacteristic(BtGattId id, uint16 offset, usize max_bytes)
+           -> (BtGattStatus status, BtGattId id, vector<void> value);
+
+    [Async]
+    5: WriteCharacteristic(BtGattId id, vector<void> buf) -> (BtGattStatus status, BtGattId id);
+
+    /// Enables notifications from the characteristic with the given ID. Returns
+    /// `ZX_ERR_BAD_STATE` if the service has not been started yet.
+    ///
+    /// Returns `ZX_ERR_SHOULD_WAIT` if this request is already in progress.
+    ///
+    /// The async callback will be called to asynchronously report the result
+    /// of this operation.
+    [Async]
+    6: EnableNotifications(BtGattId id, BtGattNotificationValue value_cb)
+           -> (BtGattStatus status, BtGattId id);
+};
diff --git a/system/fidl/ddk/protocols/bt-hci.fidl b/system/fidl/ddk/protocols/bt-hci.fidl
new file mode 100644
index 0000000..25174c8
--- /dev/null
+++ b/system/fidl/ddk/protocols/bt-hci.fidl
@@ -0,0 +1,26 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.bt_hci;
+
+using zx;
+
+[Layout="ddk-protocol", DefaultProtocol]
+interface BtHci {
+  /// Open the two-way HCI command channel for sending HCI commands and
+  /// receiving event packets.  Returns ZX_ERR_ALREADY_BOUND if the channel
+  /// is already open.
+  1: OpenCommandChannel() -> (zx.status s, handle<channel> channel);
+  /// Open the two-way HCI ACL data channel.
+  /// Returns ZX_ERR_ALREADY_BOUND if the channel is already open.
+  2: OpenAclDataChannel() -> (zx.status s, handle<channel> channel);
+  /// Open an output-only channel for monitoring HCI traffic.
+  /// The format of each message is: [1-octet flags] [n-octet payload]
+  /// The flags octet is a bitfield with the following values defined:
+  ///  - 0x00: The payload represents a command packet sent from the host to the
+  ///          controller.
+  ///  - 0x01: The payload represents an event packet sent by the controller.
+  /// Returns ZX_ERR_ALREADY_BOUND if the channel is already open.
+  3: OpenSnoopChannel() -> (zx.status s, handle<channel> channel);
+};
diff --git a/system/fidl/ddk/protocols/clk.fidl b/system/fidl/ddk/protocols/clk.fidl
new file mode 100644
index 0000000..2b2c0f0
--- /dev/null
+++ b/system/fidl/ddk/protocols/clk.fidl
@@ -0,0 +1,13 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.clk;
+
+using zx;
+
+[Layout="ddk-protocol", DefaultProtocol]
+interface Clk {
+  1: Enable(uint32 index) -> (zx.status s);
+  2: Disable(uint32 index) -> (zx.status s);
+};
diff --git a/system/fidl/ddk/protocols/display-controller.fidl b/system/fidl/ddk/protocols/display-controller.fidl
new file mode 100644
index 0000000..349d6b6
--- /dev/null
+++ b/system/fidl/ddk/protocols/display-controller.fidl
@@ -0,0 +1,390 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.display_controller;
+
+using zircon.device.audio;
+using zx;
+
+//using ZxPixelFormat = uint32;
+enum ZxPixelFormat : uint32 {};
+
+/// The image is linear and VMO backed.
+const uint32 IMAGE_TYPE_SIMPLE = 0;
+
+/// A structure containing information about each plane of an image.
+struct ImagePlane {
+    uint32 byte_offset;
+    uint32 bytes_per_row;
+};
+
+/// A structure containing information about an image.
+struct Image {
+    /// The width and height of the image in pixels.
+    uint32 width;
+    uint32 height;
+
+    /// The pixel format of the image.
+    ZxPixelFormat pixel_format;
+
+    /// The type conveys information about what is providing the pixel data. If this is not
+    /// IMAGE_FORMAT_SIMPLE, it is up to the driver and buffer producer to agree on the meaning
+    /// of the value through some mechanism outside the scope of this API.
+    uint32 type;
+
+    array<ImagePlane>:4 planes;
+
+    /// A driver-defined handle to the image. Each handle must be unique.
+    uint64 @handle;
+};
+
+const uint32 INVALID_DISPLAY_ID = 0;
+
+/// A fallback structure to convey display information without an edid.
+struct DisplayParams {
+    uint32 width;
+    uint32 height;
+    uint32 refresh_rate_e2;
+};
+
+/// Info about valid cursor configuratoins.
+struct CursorInfo {
+    /// The width and height of the cursor configuration, in pixels.
+    uint32 width;
+    uint32 height;
+    ZxPixelFormat format;
+};
+
+union Panel {
+    /// The bus_id to use to read this display's edid from the device's i2c protocol.
+    uint32 i2c_bus_id;
+    /// The display's parameters if an edid is not present.
+    DisplayParams params;
+};
+
+/// A structure containing information a connected display.
+struct AddedDisplayArgs {
+    uint64 display_id;
+
+    /// A flag indicating whether or not the display has a valid edid.
+    ///
+    /// If true, the device should expose an ZX_PROTOCOL_I2C_IMPL device through get_protocol, in
+    /// addition to the ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL protocol. Note that the i2c device
+    /// will be called from the on_displays_changed callback, so care should be taken to avoid
+    /// deadlocks or double-locking.
+    ///
+    /// If no edid is present, then the meaning of display_config's mode structure is
+    /// undefined, and drivers should ignore it in check_configuration and apply_configuration.
+    bool edid_present;
+    Panel panel;
+
+    /// A list of pixel formats supported by the display. The first entry is the
+    /// preferred pixel format.
+    vector<ZxPixelFormat> pixel_format;
+
+    /// A list of cursor configurations most likely to be accepted by the driver. Can
+    /// be null if cursor_count is 0.
+    ///
+    /// The driver may reject some of these configurations in some circumstances, and
+    /// it may accept other configurations, but at least one of these configurations
+    /// should be valid at most times.
+    vector<CursorInfo> cursor_info;
+};
+
+/// Out parameters will be populated before on_displays_changed returns.
+struct AddedDisplayInfo {
+    bool is_hdmi_out;
+    bool is_standard_srgb_out;
+
+    uint32 audio_format_count;
+
+    string manufacturer_name;
+    /// null-terminated
+    string:14 monitor_name;
+    /// null-terminated
+    string:14 monitor_serial;
+};
+
+/// The client will not make any `ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL` calls into the device
+/// during these callbacks.
+[Layout="ddk-interface"]
+interface DisplayControllerInterface {
+    /// Callbacks which are invoked when displays are added or removed. |added_display_list| and
+    /// |removed_display_list| point to arrays of the display ids which were added and removed. If
+    /// |added_display_count| or |removed_display_count| is 0, the corresponding array can be NULL.
+    ///
+    /// The driver must be done accessing any images which were on the removed displays.
+    ///
+    /// The driver should call this function when the callback is registered if any displays
+    /// are present.
+    1: OnDisplaysChanged(vector<AddedDisplayArgs> added_display,
+                         vector<uint64> removed_display) -> (vector<AddedDisplayInfo> display_info);
+
+    /// |timestamp| is the ZX_CLOCK_MONOTONIC timestamp at which the vsync occurred.
+    /// |handles| points to an array of image handles of each framebuffer being
+    /// displayed, in increasing z-order.
+    2: OnDisplayVsync(uint64 display_id, zx.time timestamp, vector<uint64> @handle) -> ();
+
+    3: GetAudioFormat(uint64 display_id, uint32 fmt_idx)
+           -> (zx.status s, zircon.device.audio.AudioStreamFormatRange fmt);
+};
+
+enum Alpha : uint8 {
+    DISABLE = 0;
+    PREMULTIPLIED = 1;
+    HW_MULTIPLY = 2;
+};
+
+/// Rotations are applied counter-clockwise, and are applied before reflections.
+enum FrameTransform : uint32 {
+    IDENTITY = 0;
+    REFLECT_X = 1;
+    REFLECT_Y = 2;
+    ROT_90 = 3;
+    ROT_180 = 4;
+    ROT_270 = 5;
+    ROT_90_REFLECT_X = 6;
+    ROT_90_REFLECT_Y = 7;
+};
+
+struct Frame {
+    /// (|x_pos|, |y_pos|) specifies the position of the upper-left corner
+    /// of the frame.
+    uint32 x_pos;
+    uint32 y_pos;
+    uint32 width;
+    uint32 height;
+};
+
+struct PrimaryLayer {
+    Image image;
+
+    /// An ALPHA_* constant.
+    ///
+    /// If |alpha_mode| == `ALPHA_DISABLED`, the layer is opaque and alpha_layer_val is ignored.
+    ///
+    /// If |alpha_mode| == `PREMULTIPLIED` or `HW_MULTIPLY` and |alpha_layer_val| is NaN, the alpha
+    /// used when blending is determined by the per-pixel alpha channel.
+    ///
+    /// If |alpha_mode| == `PREMULTIPLIED` or `HW_MULTIPLY` and |alpha_layer_val| is not NaN, the
+    /// alpha used when blending is the product of alpha_layer_val and any per-pixel alpha.
+    /// Additionally, if alpha_mode == PREMULTIPLIED, then the hardware must premultiply the color
+    /// channel with alpha_layer_val before blending.
+    ///
+    /// If alpha_layer_val is not NaN, it will be in the range [0, 1].
+    Alpha alpha_mode;
+    float32 alpha_layer_val;
+
+    FrameTransform transform_mode;
+
+    /// The source frame, where (0,0) is the top-left corner of the image. The
+    /// client guarantees that src_frame lies entirely within the image.
+    Frame src_frame;
+
+    /// The destination frame, where (0,0) is the top-left corner of the
+    /// composed output. The client guarantees that dest_frame lies entirely
+    /// within the composed output.
+    Frame dest_frame;
+};
+
+struct CursorLayer {
+    Image image;
+
+    /// The position of the top-left corner of the cursor's image. When being
+    /// applied to a display, the cursor is guaranteed to have at least one
+    /// pixel of overlap with the display.
+    int32 x_pos;
+    int32 y_pos;
+};
+
+struct ColorLayer {
+    ZxPixelFormat format;
+    /// The color to use for the layer. The color is little-endian, and is
+    /// guaranteed to be of the appropriate size.
+    vector<uint8> color;
+};
+
+/// Types of layers.
+
+enum LayerType : uint32 {
+    PRIMARY = 0;
+    CURSOR = 1;
+    COLOR = 2;
+};
+
+union LayerConfig {
+    PrimaryLayer primary;
+    CursorLayer cursor;
+    ColorLayer color;
+};
+
+struct Layer {
+    LayerType type;
+    /// z_index of the layer. See |check_configuration| and |apply_configuration|.
+    uint32 z_index;
+    LayerConfig cfg;
+};
+
+/// constants for display_config's mode_flags field
+enum ModeFlag : uint32 {
+    VSYNC_POSITIVE     = 0x1;
+    HSYNC_POSITIVE     = 0x2;
+    INTERLACED         = 0x4;
+    ALTERNATING_VBLANK = 0x8;
+    DOUBLE_CLOCKED     = 0x10;
+};
+
+/// The video parameters which specify the display mode.
+struct DisplayMode {
+    uint32 pixel_clock_10khz;
+    uint32 h_addressable;
+    uint32 h_front_porch;
+    uint32 h_sync_pulse;
+    uint32 h_blanking;
+    uint32 v_addressable;
+    uint32 v_front_porch;
+    uint32 v_sync_pulse;
+    uint32 v_blanking;
+    /// A bitmask of MODE_FLAG_* values
+    uint32 flags;
+};
+
+enum ColorConversion : uint32 {
+    /// If set, use the 0 vector for the color conversion preoffset
+    PREOFFSET = 0x1;
+    /// If set, use the identity matrix for the color conversion coefficients
+    COEFFICIENTS = 0x2;
+    /// If set, use the 0 vector for the color conversion postoffset
+    POSTOFFSET = 0x4;
+};
+
+struct DisplayConfig {
+    /// the display id to which the configuration applies
+    uint64 display_id;
+
+    DisplayMode mode;
+
+    /// Bitmask of COLOR_CONVERSION_* flags
+    uint32 cc_flags;
+    /// Color conversion is applied to each pixel according to the formula:
+    ///
+    /// (cc_coefficients * (pixel + cc_preoffsets)) + cc_postoffsets
+    ///
+    /// where pixel is a column vector consiting of the pixel's 3 components.
+    array<float32>:3 cc_preoffsets;
+    array<array<float32>:3>:3 cc_coefficients;
+    array<float32>:3 cc_postoffsets;
+
+    vector<Layer?> layer;
+};
+
+enum ConfigDisplay : uint32 {
+    /// The display mode configuration is valid. Note that this is distinct from
+    /// whether or not the layer configuration is valid.
+    OK = 0;
+    /// Error indicating that the hardware cannot simultaniously support the
+    /// requested number of displays.
+    TOO_MANY = 1;
+    /// Error indicating that the hardware cannot simultaniously support the given
+    /// set of display modes. To support a mode, the display must be able to display
+    /// a single layer with width and height equal to the requested mode and the
+    /// preferred pixel format.
+    UNSUPPORTED_MODES = 2;
+};
+
+enum Client : uint32 {
+    /// The client should convert the corresponding layer to a primary layer.
+    USE_PRIMARY = 0x1;
+    /// The client should compose all layers with MERGE_BASE and MERGE_SRC into a new,
+    /// single primary layer at the MERGE_BASE layer's z-order. The driver must accept
+    /// a fullscreen layer with the default pixel format, but may accept other layer
+    /// parameters.
+    ///
+    /// MERGE_BASE should only be set on one layer per display. If it is set on multiple
+    /// layers, the client will arbitrarily pick one and change the rest to MERGE_SRC.
+    MERGE_BASE = 0x2;
+    MERGE_SRC = 0x4;
+    /// The client should pre-scale the image so that src_frame's dimensions are equal
+    /// to dest_frame's dimensions.
+    FRAME_SCALE = 0x8;
+    /// The client should pre-clip the image so that src_frame's dimensions are equal to
+    /// the image's dimensions.
+    SRC_FRAME = 0x10;
+    /// The client should pre-apply the transformation so TRANSFORM_IDENTITY can be used.
+    TRANSFORM = 0x20;
+    /// The client should apply the color conversion.
+    COLOR_CONVERSION = 0x40;
+    /// The client should apply the alpha transformation itself.
+    ALPHA = 0x80;
+};
+
+/// The client guarantees that check_configuration and apply_configuration are always
+/// made from a single thread. The client makes no other threading guarantees.
+[Layout="ddk-protocol"]
+interface DisplayController {
+    /// The function will only be called once, and it will be called before any other
+    /// functions are called.
+    1: SetDisplayControllerInterface(DisplayControllerInterface intf) -> ();
+
+    /// Imports a VMO backed image into the driver. The driver should set image->handle. The
+    /// driver does not own the vmo handle passed to this function.
+    2: ImportVmoImage(Image? image, handle<vmo> vmo, usize offset) -> (zx.status s);
+
+    /// Releases any driver state associated with the given image. The client guarantees that
+    /// any images passed to apply_config will not be released until a vsync occurs with a
+    /// more recent image.
+    3: ReleaseImage(Image? image) -> ();
+
+    /// Validates the given configuration.
+    ///
+    /// The configuration may not include all displays. Omiteed displays should be treated as
+    /// whichever of off or displaying a blank screen results in a more premissive validation.
+    ///
+    /// All displays in a configuration will have at least one layer. The layers will be
+    /// arranged in increasing z-order, and their z_index fields will be set consecutively.
+    ///
+    /// Whether or not the driver can accept the configuration cannot depend on the
+    /// particular image handles, as it must always be possible to present a new image in
+    /// place of another image with a matching configuration. It also cannot depend on the
+    /// cursor position, as that can be updated without another call to check_configuration.
+    ///
+    /// display_cfg_result should be set to a CONFIG_DISPLAY_* error if the combination of
+    /// display modes is not supported.
+    ///
+    /// layer_cfg_result points to an array of arrays. The primary length is display_count, the
+    /// secondary lengths are the corresponding display_cfg's layer_count. If display_cfg_result
+    /// is CONFIG_DISPLAY_OK, any errors in layer configuration should be returned as a CLIENT*
+    /// flag in the corresponding layer_cfg_result entry.
+    ///
+    /// The driver must not retain references to the configuration after this function returns.
+    /// TODO: Fix me...
+    4: CheckConfiguration(vector<DisplayConfig?> display_config)
+           -> (uint32 display_cfg_result, vector<uint32>? layer_cfg_result);
+
+    /// Applies the configuration.
+    ///
+    /// All configurations passed to this function will be derived from configurations which
+    /// have been succesfully validated, with the only differences either being omitted layers
+    /// or different image handles. To account for any layers which are not present, the driver
+    /// must use the z_index values of the present layers to configure them as if the whole
+    /// configuration was present.
+    ///
+    /// Unlike with check_configuration, displays included in the configuration are not
+    /// guaranteed to include any layers. Both omitted displays and displays with no layers
+    /// can either be turned off or set to display a blank screen, but for displays with no
+    /// layers there is a strong preference to display a blank screen instead of turn them off.
+    /// In either case, the driver must drop all references to old images and invoke the vsync
+    /// callback after doing so.
+    ///
+    /// The driver must not retain references to the configuration after this function returns.
+    5: ApplyConfiguration(vector<DisplayConfig?> display_config) -> ();
+
+    /// Computes the stride (in pixels) necessary for a linear image with the given width
+    /// and pixel format. Returns 0 on error.
+    6: ComputeLinearStride(uint32 width, ZxPixelFormat pixel_format) -> (uint32 s);
+
+    /// Allocates a VMO of the requested size which can be used for images.
+    // TODO: move this functionallity into a seperate video buffer management system.
+    7: AllocateVmo(uint64 size) -> (zx.status s, handle<vmo> vmo);
+};
diff --git a/system/fidl/ddk/protocols/ethernet.fidl b/system/fidl/ddk/protocols/ethernet.fidl
new file mode 100644
index 0000000..35f3911
--- /dev/null
+++ b/system/fidl/ddk/protocols/ethernet.fidl
@@ -0,0 +1,149 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.ethernet;
+
+using zircon.listnode;
+using zx;
+
+const uint32 ETH_MAC_SIZE            = 6;    // bytes
+const uint32 ETH_MTU_SIZE            = 1500; // bytes
+const uint32 ETH_FRAME_MAX_HDR_SIZE  = 18;   // bytes. MAC Dest(6) + MAC Src(6) + 802.1Q tag(4) + Ethertype(2)
+const uint32 ETH_FRAME_MAX_SIZE      = 1518;
+
+/// The ethermac interface supports both synchronous and asynchronous transmissions using the
+/// proto->queue_tx() and ifc->complete_tx() methods.
+///
+/// Receive operations are supported with the ifc->recv() interface.
+// TODO: implement netbuf-based receive operations by implementing proto->queue_rx() and
+// ifc->complete_rx()
+///
+/// The FEATURE_WLAN flag indicates a device that supports wlan operations.
+///
+/// The FEATURE_SYNTH flag indicates a device that is not backed by hardware.
+///
+/// The FEATURE_DMA flag indicates that the device can copy the buffer data using DMA and will ensure
+/// that physical addresses are provided in netbufs.
+
+enum EthmacFeature : uint32 {
+    WLAN  = 0x1;
+    SYNTH = 0x2;
+    DMA   = 0x4;
+};
+
+struct EthmacInfo {
+    uint32 features;
+    uint32 mtu;
+    array<uint8>:ETH_MAC_SIZE mac;
+    array<uint8>:2 reserved0;
+    array<uint32>:4 reserved1;
+};
+
+union Internal {
+    uint64 val;
+    vector<void> ptr;
+};
+
+struct EthmacNetbuf {
+    /// Provided by the generic ethernet driver.
+    vector<void> data;
+    /// Only used if ETHMAC_FEATURE_DMA is available.
+    zx.paddr phys;
+    uint16 reserved;
+    uint32 flags;
+
+    /// Shared between the generic ethernet and ethmac drivers.
+    zircon.listnode.ListNode node;
+
+    /// For use by the ethmac driver.
+    Internal u;
+};
+
+[Layout="ddk-interface"]
+interface EthmacIfc {
+    1: Status(uint32 status) -> ();
+
+    2: Recv(vector<void> data, uint32 flags) -> ();
+
+    /// complete_tx() is called to return ownership of a netbuf to the generic ethernet driver.
+    /// Return status indicates queue state:
+    ///   ZX_OK: Packet has been enqueued.
+    ///   Other: Packet could not be enqueued.
+    /// Upon a return of ZX_OK, the packet has been enqueued, but no information is returned as to
+    /// the completion state of the transmission itself.
+    3: CompleteTx(EthmacNetbuf? netbuf, zx.status status) -> ();
+};
+
+/// Indicates that additional data is available to be sent after this call finishes. Allows a ethmac
+/// driver to batch tx to hardware if possible.
+const uint32 ETHMAC_TX_OPT_MORE = 1;
+
+/// SETPARAM_ values identify the parameter to set. Each call to set_param()
+/// takes an int32_t |value| and void* |data| which have meaning specific to
+/// the parameter being set.
+
+/// |value| is bool. |data| is unused.
+const uint32 ETHMAC_SETPARAM_PROMISC = 1;
+
+/// |value| is bool. |data| is unused.
+const uint32 ETHMAC_SETPARAM_MULTICAST_PROMISC = 2;
+
+const int32 ETHMAC_MULTICAST_FILTER_OVERFLOW  = -1;
+
+/// |value| is number of addresses, or ETHMAC_MULTICAST_FILTER_OVERFLOW for "too many to count."
+/// |data| is |value|*6 bytes of MAC addresses. Caller retains ownership.
+/// If |value| is _OVERFLOW, |data| is ignored.
+const uint32 ETHMAC_SETPARAM_MULTICAST_FILTER  = 3;
+
+const uint32 ETHMAC_SETPARAM_DUMP_REGS         = 4;
+
+/// The ethernet midlayer will never call ethermac_protocol
+/// methods from multiple threads simultaneously, but it
+/// can call send() methods at the same time as non-send
+/// methods.
+[Layout="ddk-protocol"]
+interface Ethmac {
+    /// Obtain information about the ethermac device and supported features
+    /// Safe to call at any time.
+    1: Query(uint32 options) -> (zx.status s, EthmacInfo info);
+
+    /// Shut down a running ethermac
+    /// Safe to call if the ethermac is already stopped.
+    2: Stop() -> ();
+
+    /// Start ethermac running with ifc_virt
+    /// Callbacks on ifc may be invoked from now until stop() is called
+    3: Start(EthmacIfc ifc) -> (zx.status s);
+
+    /// Request transmission of the packet in netbuf. Return status indicates queue state:
+    ///   ZX_ERR_SHOULD_WAIT: Packet is being enqueued.
+    ///   ZX_OK: Packet has been enqueued.
+    ///   Other: Packet could not be enqueued.
+    ///
+    /// In the SHOULD_WAIT case the driver takes ownership of the netbuf and must call complete_tx()
+    /// to return it once the enqueue is complete. complete_tx() may be used to return the packet
+    /// before transmission itself completes, but MUST NOT be called from within the queue_tx()
+    /// implementation.
+    ///
+    /// queue_tx() may be called at any time after start() is called including from multiple threads
+    /// simultaneously.
+    4: QueueTx(uint32 options, EthmacNetbuf? netbuf) -> (zx.status s);
+
+    /// Request a settings change for the driver. Return status indicates disposition:
+    ///   ZX_OK: Request has been handled.
+    ///   ZX_ERR_NOT_SUPPORTED: Driver does not support this setting.
+    ///   Other: Error trying to support this request.
+    ///
+    /// |value| and |data| usage are defined for each |param|; see comments above.
+    ///
+    /// set_param() may be called at any time after start() is called including from multiple threads
+    /// simultaneously.
+    5: SetParam(uint32 param, int32 value, vector<void> data) -> (zx.status s);
+
+    /// Get the BTI handle (needed to pin DMA memory) for this device.
+    /// This method is only valid on devices that advertise ETHMAC_FEATURE_DMA
+    /// The caller does *not* take ownership of the BTI handle and must never close
+    /// the handle.
+    6: GetBti() -> (handle<bti> bti);
+};
diff --git a/system/fidl/ddk/protocols/gpio.fidl b/system/fidl/ddk/protocols/gpio.fidl
new file mode 100644
index 0000000..4f207ee
--- /dev/null
+++ b/system/fidl/ddk/protocols/gpio.fidl
@@ -0,0 +1,45 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.gpio;
+
+using zx;
+
+
+/// Flags for `ConfigIn`.
+const uint32 GPIO_PULL_DOWN = 0x0;
+const uint32 GPIO_PULL_UP = 0x10;
+const uint32 GPIO_NO_PULL = 0x20;
+const uint32 GPIO_PULL_MASK = 0x30;
+
+/// Values for `SetPolarity`.
+enum GpioPolarity : uint32 {
+    LOW = 0x0;
+    HIGH = 0x1;
+};
+
+/// In the functions below, the GPIO index is relative to the list of GPIOs for the device.
+/// For example, the list of GPIOs a platform device has access to would likely be a small
+/// subset of the total number of GPIOs, while a platform bus implementation driver would
+/// have access to the complete set of GPIOs.
+[Layout="ddk-protocol"]
+interface Gpio {
+    /// Configures a GPIO for input.
+    1: ConfigIn(uint32 index, uint32 flags) -> (zx.status s);
+    /// Configures a GPIO for output.
+    2: ConfigOut(uint32 index, uint8 initial_value) -> (zx.status s);
+    /// Configures the GPIO pin for an alternate function (I2C, SPI, etc)
+    /// the interpretation of "function" is platform dependent.
+    3: SetAltFunction(uint32 index, uint64 function) -> (zx.status s);
+    /// Reads the current value of a GPIO (0 or 1).
+    4: Read(uint32 index) -> (zx.status s, uint8 value);
+    /// Sets the current value of the GPIO (any non-zero value maps to 1).
+    5: Write(uint32 index, uint8 value) -> (zx.status s);
+    /// Gets an interrupt object pertaining to a particular GPIO pin.
+    6: GetInterrupt(uint32 index, uint32 flags) -> (zx.status s, handle<interrupt> irq);
+    /// Release the interrupt.
+    7: ReleaseInterrupt(uint32 index) -> (zx.status s);
+    /// Set GPIO polarity.
+    8: SetPolarity(uint32 index, GpioPolarity polarity) -> (zx.status s);
+};
diff --git a/system/fidl/ddk/protocols/hidbus.fidl b/system/fidl/ddk/protocols/hidbus.fidl
new file mode 100644
index 0000000..d246ca9
--- /dev/null
+++ b/system/fidl/ddk/protocols/hidbus.fidl
@@ -0,0 +1,66 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.hidbus;
+
+using zx;
+
+enum HidDescriptionType : uint8 {
+    REPORT = 0x22;
+};
+
+enum HidReportType : uint8 {
+    INPUT = 1;
+    OUTPUT = 2;
+    FEATURE = 3;
+};
+
+enum HidProtocol : uint8 {
+    BOOT = 0;
+    REPORT = 0;
+};
+
+enum HidDeviceClass : uint8 {
+    OTHER = 0;
+    KBD = 1;
+    POINTER = 2;
+    KBD_POINTER = 3;
+
+    FIRST = 0;
+    LAST = 3;
+};
+
+struct HidInfo {
+    uint8 dev_num;
+    HidDeviceClass device_class;
+    bool boot_device;
+};
+
+[Layout="ddk-interface"]
+interface HidbusIfc {
+    /// Queues a report received by the hidbus device.
+    1: IoQueue(vector<void> buf) -> ();
+};
+
+[Layout="ddk-protocol"]
+interface Hidbus {
+    /// Obtain information about the hidbus device and supported features.
+    /// Safe to call at any time.
+    1: Query(uint32 options) -> (zx.status s, HidInfo info);
+    /// Start the hidbus device. The device may begin queueing hid reports via
+    /// ifc->io_queue before this function returns. It is an error to start an
+    /// already-started hidbus device.
+    2: Start(HidbusIfc ifc) -> (zx.status s);
+    /// Stop the hidbus device. Safe to call if the hidbus is already stopped.
+    3: Stop() -> ();
+    /// What are the ownership semantics with regards to the data buffer passed back?
+    /// is len an input and output parameter?
+    4: GetDescriptor(HidDescriptionType desc_type) -> (zx.status s, vector<void>? data);
+    5: GetReport(HidReportType rpt_type, uint8 rpt_id) -> (zx.status s, vector<void> data);
+    6: SetReport(HidReportType rpt_type, uint8 rpt_id, vector<void> data) -> (zx.status s);
+    7: GetIdle(uint8 rpt_id) -> (zx.status s, uint8 duration);
+    8: SetIdle(uint8 rpt_id, uint8 duration) -> (zx.status s);
+    9: GetProtocol() -> (zx.status s, HidProtocol protocol);
+    10: SetProtocol(HidProtocol protocol) -> (zx.status s);
+};
diff --git a/system/fidl/ddk/protocols/i2c-impl.fidl b/system/fidl/ddk/protocols/i2c-impl.fidl
new file mode 100644
index 0000000..dc13058
--- /dev/null
+++ b/system/fidl/ddk/protocols/i2c-impl.fidl
@@ -0,0 +1,18 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.i2c;
+
+using zx;
+
+/// Low-level protocol for i2c drivers.
+[Layout="ddk-protocol"]
+interface I2cImpl {
+    1: GetBusCount() -> (uint32 count);
+    2: GetMaxTransferSize(uint32 bus_id) -> (zx.status s, usize size);
+    /// Sets the bitrate for the i2c bus in KHz units.
+    3: SetBitrate(uint32 bus_id, uint32 bitrate) -> (zx.status s);
+    [Async]
+    4: Transact(uint32 bus_id, uint16 address, vector<void> write) -> (vector<void> read);
+};
diff --git a/system/fidl/ddk/protocols/i2c.fidl b/system/fidl/ddk/protocols/i2c.fidl
new file mode 100644
index 0000000..166a389
--- /dev/null
+++ b/system/fidl/ddk/protocols/i2c.fidl
@@ -0,0 +1,25 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.i2c;
+
+using zx;
+
+const uint32 I2C_10_BIT_ADDR_MASK = 0xF000;
+
+[Layout="ddk-protocol"]
+interface I2c {
+    /// Writes and reads data on an i2c channel. If both write_length and read_length
+    /// are greater than zero, this call will perform a write operation immediately followed
+    /// by a read operation with no other traffic occuring on the bus in between.
+    /// If read_length is zero, then i2c_transact will only perform a write operation,
+    /// and if write_length is zero, then it will only perform a read operation.
+    /// The results of the operation are returned asynchronously via the complete_cb.
+    /// The cookie parameter can be used to pass your own private data to the complete_cb callback.
+    [Async]
+    1: Transact(uint32 index, vector<void> write, usize read_length) -> (zx.status status,
+                                                                         vector<void> read);
+    /// Returns the maximum transfer size for read and write operations on the channel.
+    2: GetMaxTransferSize(uint32 index) -> (zx.status s, usize size);
+};
diff --git a/system/fidl/ddk/protocols/intel-gpu-core.fidl b/system/fidl/ddk/protocols/intel-gpu-core.fidl
new file mode 100644
index 0000000..84278c5
--- /dev/null
+++ b/system/fidl/ddk/protocols/intel-gpu-core.fidl
@@ -0,0 +1,58 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.intel_gpu_core;
+
+using zx;
+
+const uint32 IMAGE_TYPE_X_TILED = 1;
+const uint32 IMAGE_TYPE_Y_LEGACY_TILED = 2;
+const uint32 IMAGE_TYPE_YF_TILED = 3;
+
+[Layout="ddk-callback"]
+interface ZxIntelGpuCoreInterrupt {
+    1: Callback(uint32 master_interrupt_control) -> ();
+};
+
+[Layout="ddk-protocol"]
+interface ZxIntelGpuCore {
+    /// Reads 16 bits from pci config space; returned in |value_out|.
+    1: ReadPciConfig16(uint16 addr) -> (zx.status s, uint16 value);
+
+    /// Maps the given |pci_bar|; address returned in |addr_out|, size in bytes returned in
+    /// |size_out|.
+    2: MapPciMmio(uint32 pci_bar) -> (zx.status s, vector<void>? buf);
+
+    /// Unmaps the given |pci_bar|.
+    3: UnmapPciMmio(uint32 pci_bar) -> (zx.status s);
+
+    /// Returns a bus transaction initiator.
+    4: GetPciBti(uint32 index) -> (zx.status s, handle<bti> bti);
+
+    /// Registers the given |callback| to be invoked with parameter |data| when an interrupt occurs
+    /// matching |interrupt_mask|.
+    5: RegisterInterruptCallback(ZxIntelGpuCoreInterrupt callback,
+                                 uint32 interrupt_mask) -> (zx.status s);
+
+    /// Un-registers a previously registered interrupt callback.
+    6: UnregisterInterruptCallback() -> (zx.status s);
+
+    /// Returns the size of the GTT (global translation table) in bytes.
+    7: GttGetSize() -> (uint64 size);
+
+    /// Allocates a region of the GTT of the given |page_count|, returning the page-aligned virtual
+    /// address in |addr_out|.
+    8: GttAlloc(uint64 page_count) -> (zx.status s, uint64 addr);
+
+    /// Frees the GTT allocation given by |addr|.
+    9: GttFree(uint64 addr) -> (zx.status s);
+
+    /// Clears the page table entries for the GTT allocation given by |addr|.
+    10: GttClear(uint64 addr) -> (zx.status s);
+
+    /// Inserts page tables entries for the GTT allocation given by |addr| for the vmo represented by
+    /// handle |buffer|, at the given |page_offset| and |page_count|. Takes ownership of |buffer|.
+    11: GttInsert(uint64 addr, handle<vmo> buffer, uint64 page_offset,
+                  uint64 page_count) -> (zx.status s);
+};
diff --git a/system/fidl/ddk/protocols/intel-hda-codec.fidl b/system/fidl/ddk/protocols/intel-hda-codec.fidl
new file mode 100644
index 0000000..bc55657
--- /dev/null
+++ b/system/fidl/ddk/protocols/intel-hda-codec.fidl
@@ -0,0 +1,13 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.intel_hda_codec;
+
+using zx;
+
+[Layout="ddk-protocol"]
+interface IhdaCodec {
+  /// Fetch a zx_handle_t to a channel which can be used to communicate with the codec device.
+  1: GetDriverChannel() -> (zx.status s, handle<channel> channel);
+};
diff --git a/system/fidl/ddk/protocols/intel-hda-dsp.fidl b/system/fidl/ddk/protocols/intel-hda-dsp.fidl
new file mode 100644
index 0000000..2bcc44b
--- /dev/null
+++ b/system/fidl/ddk/protocols/intel-hda-dsp.fidl
@@ -0,0 +1,42 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.intel_hda_dsp;
+
+using zx;
+
+const string MD_KEY_NHLT = "NHLT";
+
+struct ZxPcieDeviceInfo {};
+
+[Layout="ddk-callback"]
+interface IhdaDspIrq {
+    1: Callback() -> ();
+};
+
+[Layout="ddk-protocol"]
+interface IhdaDsp {
+    /// Fetch the parent HDA controller's PCI device info.
+    1: GetDevInfo() -> (ZxPcieDeviceInfo? out);
+
+    /// Fetch a VMO that represents the BAR holding the Audio DSP registers.
+    2: GetMmio() -> (zx.status s, handle<vmo> vmo, usize size);
+
+    /// Fetch a handle to our bus transaction initiator.
+    3: GetBti() -> (zx.status s, handle<bti> bti);
+
+    /// Enables DSP
+    4: Enable() -> ();
+
+    /// Disable DSP
+    5: Disable() -> ();
+
+    /// Enables DSP interrupts and set a callback to be invoked when an interrupt is
+    /// raised.
+    /// Returns `ZX_ERR_ALREADY_EXISTS` if a callback is already set.
+    6: IrqEnable(IhdaDspIrq callback) -> (zx.status s);
+
+    /// Disable DSP interrupts and clears the callback.
+    7: IrqDisable() -> ();
+};
diff --git a/system/fidl/ddk/protocols/iommu.fidl b/system/fidl/ddk/protocols/iommu.fidl
new file mode 100644
index 0000000..199e189
--- /dev/null
+++ b/system/fidl/ddk/protocols/iommu.fidl
@@ -0,0 +1,13 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.iommu;
+
+using zx;
+
+[Layout="ddk-protocol"]
+interface Iommu {
+  1: GetBti(uint32 iommu_index, uint32 bti_id) -> (zx.status s, handle<bti> @handle);
+};
+
diff --git a/system/fidl/ddk/protocols/libs/audio.fidl b/system/fidl/ddk/protocols/libs/audio.fidl
new file mode 100644
index 0000000..f1f6bdc
--- /dev/null
+++ b/system/fidl/ddk/protocols/libs/audio.fidl
@@ -0,0 +1,31 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library zircon.device.audio;
+
+enum AudioSampleFormat : uint32 {
+    BITSTREAM     = 0x1;
+    @8BIT         = 0x2;
+    @16BIT        = 0x4;
+    @20BIT_PACKED = 0x8;
+    @24BIT_PACKED = 0x10;
+    @20BIT_IN32   = 0x20;
+    @24BIT_IN32   = 0x40;
+    @32BIT        = 0x80;
+    @32BIT_FLOAT  = 0x100;
+
+    FLAG_UNSIGNED      = 0x4000;
+    FLAG_INVERT_ENDIAN = 0x8000;
+    FLAG_MASK = 0xC000;
+};
+
+[repr="C", Packed]
+struct AudioStreamFormatRange {
+    AudioSampleFormat   sample_formats;
+    uint32              min_frames_per_second;
+    uint32              max_frames_per_second;
+    uint8               min_channels;
+    uint8               max_channels;
+    uint16              flags;
+};
diff --git a/system/fidl/ddk/protocols/libs/block.fidl b/system/fidl/ddk/protocols/libs/block.fidl
new file mode 100644
index 0000000..3d34c46
--- /dev/null
+++ b/system/fidl/ddk/protocols/libs/block.fidl
@@ -0,0 +1,19 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library zircon.device.block;
+
+[repr="C"]
+struct BlockInfo {
+    /// The number of blocks in this block device.
+    uint64 block_count;
+    /// The size of a single block.
+    uint32 block_size;
+    /// Max size in bytes per transfer.
+    /// May be BLOCK_MAXRANSFER_UNBOUNDED if there
+    /// is no restriction.
+    uint32 max_transfer_size;
+    uint32 flags;
+    uint32 reserved;
+};
diff --git a/system/fidl/ddk/protocols/libs/listnode.fidl b/system/fidl/ddk/protocols/libs/listnode.fidl
new file mode 100644
index 0000000..f67863b
--- /dev/null
+++ b/system/fidl/ddk/protocols/libs/listnode.fidl
@@ -0,0 +1,11 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library zircon.listnode;
+
+[repr="C"]
+struct ListNode {
+    ListNode? prev;
+    ListNode? next;
+};
diff --git a/system/fidl/ddk/protocols/libs/nand.fidl b/system/fidl/ddk/protocols/libs/nand.fidl
new file mode 100644
index 0000000..86d40a9
--- /dev/null
+++ b/system/fidl/ddk/protocols/libs/nand.fidl
@@ -0,0 +1,23 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library zircon.device.nand;
+
+[repr="C"]
+struct NandInfo {
+    /// Read/write unit size, in bytes.
+    uint32 page_size;
+    /// Erase block size, in pages.
+    uint32 pages_per_block;
+    /// Device size, in erase blocks.
+    uint32 num_blocks;
+    /// Number of ECC bits (correctable bit flips), per correction chunk.
+    uint32 ecc_bits;
+    /// Available out of band bytes per page.
+    uint32 oob_size;
+    /// NAND_CLASS_PARTMAP, NAND_CLASS_FTL or NAND_CLASS_RAW.
+    uint32 nand_class;
+    /// Partition type GUID from partition map.
+    array<uint8>:16 partition_guid;
+};
diff --git a/system/fidl/ddk/protocols/libs/pci.fidl b/system/fidl/ddk/protocols/libs/pci.fidl
new file mode 100644
index 0000000..64db00d
--- /dev/null
+++ b/system/fidl/ddk/protocols/libs/pci.fidl
@@ -0,0 +1,42 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library zircon.syscalls.pci;
+
+[repr="C"]
+union PciField {
+    usize addr;
+    handle<vmo> @handle;
+};
+
+[repr="C"]
+struct ZxPciBar {
+    uint32 id;
+    uint32 type;
+    usize size;
+    PciField u;
+};
+
+[repr="C"]
+enum ZxPciIrqMode : uint8 {
+    DISABLED = 0;
+    LEGACY   = 1;
+    MSI      = 2;
+    MSI_X    = 3;
+};
+
+[repr="C"]
+struct ZxPcieDeviceInfo {
+    uint16 vendor_id;
+    uint16 device_id;
+
+    uint8  base_class;
+    uint8  sub_class;
+    uint8  program_interface;
+    uint8  revision_id;
+
+    uint8  bus_id;
+    uint8  dev_id;
+    uint8  func_id;
+};
diff --git a/system/fidl/ddk/protocols/libs/phys-iter.fidl b/system/fidl/ddk/protocols/libs/phys-iter.fidl
new file mode 100644
index 0000000..d0fc808
--- /dev/null
+++ b/system/fidl/ddk/protocols/libs/phys-iter.fidl
@@ -0,0 +1,35 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.phys_iter;
+
+using zx;
+
+/// Specifies the buffer to iterate over.
+[repr="C"]
+struct PhysIterBuffer {
+    /// List of physical addresses backing the buffer starting at vmo_offset.
+    zx.paddr? phys;
+    /// Number of entries in phys list.
+    uint64 phys_count;
+    /// Length of the buffer starting at vmo_offset.
+    usize length;
+    /// Offset into first page to start iterating on.
+    uint64 vmo_offset;
+};
+
+/// Used to iterate over contiguous buffer ranges in the physical address space.
+[repr="C"]
+struct PhysIter {
+    PhysIterBuffer buf;
+
+    /// Current offset in the txn (relative to buffer vmo_offset)
+    zx.off     offset;
+    /// Max length to be returned by phys_iter_next()
+    usize      max_length;
+    /// index of page in buf->phys that contains offset
+    uint64     page;
+    /// last valid page index in buf->phys
+    uint64     last_page;
+};
diff --git a/system/fidl/ddk/protocols/libs/sdhci.fidl b/system/fidl/ddk/protocols/libs/sdhci.fidl
new file mode 100644
index 0000000..76b7ba9
--- /dev/null
+++ b/system/fidl/ddk/protocols/libs/sdhci.fidl
@@ -0,0 +1,38 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library hw.sdhci;
+
+[Packed, repr="C"]
+struct SdhciRegs {
+    uint32 arg2;          // 00h
+    uint32 blkcntsiz;     // 04h
+    uint32 arg1;          // 08h
+    uint32 cmd;           // 0Ch
+    uint32 resp0;         // 10h
+    uint32 resp1;         // 14h
+    uint32 resp2;         // 18h
+    uint32 resp3;         // 1Ch
+    uint32 data;          // 20h
+    uint32 state;         // 24h
+    uint32 ctrl0;         // 28h
+    uint32 ctrl1;         // 2Ch
+    uint32 irq;           // 30h
+    uint32 irqmsk;        // 34h
+    uint32 irqen;         // 38h
+    uint32 ctrl2;         // 3Ch
+    uint32 caps0;         // 40h
+    uint32 caps1;         // 44h
+    uint32 maxcaps0;      // 48h
+    uint32 maxcaps1;      // 4Ch
+    uint32 forceirq;      // 50h
+    uint32 admaerr;       // 54h
+    uint32 admaaddr0;     // 58h
+    uint32 admaaddr1;     // 5Ch
+    array<uint32>:4 preset;     // 60h
+    array<uint8>:112 resvd;
+    uint32 busctl;
+    array<uint8>:24 reserved_4;
+    uint32 slotirqversion;
+};
diff --git a/system/fidl/ddk/protocols/libs/usb-device.fidl b/system/fidl/ddk/protocols/libs/usb-device.fidl
new file mode 100644
index 0000000..337e695
--- /dev/null
+++ b/system/fidl/ddk/protocols/libs/usb-device.fidl
@@ -0,0 +1,14 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library zircon.device.usb_device;
+
+[repr="C"]
+enum UsbMode : uint32 {
+    NONE = 0;
+    HOST = 1;
+    DEVICE = 2;
+    OTG = 3;
+};
+
diff --git a/system/fidl/ddk/protocols/libs/usb-hub.fidl b/system/fidl/ddk/protocols/libs/usb-hub.fidl
new file mode 100644
index 0000000..71dcbff
--- /dev/null
+++ b/system/fidl/ddk/protocols/libs/usb-hub.fidl
@@ -0,0 +1,39 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library zircon.hw.usb_hub;
+
+[Packed, repr="C"]
+struct UsbHighSpeed {
+    // variable length depending on number of ports
+    array<uint8>:4  DeviceRemovable;
+    array<uint8>:4  PortPwrCtrlMask;
+};
+
+[Packed, repr="C"]
+struct UsbSuperSpeed {
+    uint8 bHubHdrDecLat;
+    uint16 wHubDelay;
+    uint16 DeviceRemovable;
+};
+
+[Packed, repr="C"]
+union UsbGen {
+    /// USB 2.0
+    UsbHighSpeed hs;
+    /// USB 3.0
+    UsbSuperSpeed ss;
+};
+
+[Packed, repr="C"]
+struct UsbHubDescriptor {
+    uint8 bDescLength;
+    uint8 bDescriptorType;
+    uint8 bNbrPorts;
+    uint16 wHubCharacteristics;
+    uint8 bPowerOn2PwrGood;
+    uint8 bHubContrCurrent;
+    UsbGen u;
+};
+
diff --git a/system/fidl/ddk/protocols/libs/usb.fidl b/system/fidl/ddk/protocols/libs/usb.fidl
new file mode 100644
index 0000000..c200c99
--- /dev/null
+++ b/system/fidl/ddk/protocols/libs/usb.fidl
@@ -0,0 +1,79 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library zircon.hw.usb;
+
+[repr="C"]
+enum UsbSpeed : uint8 {
+    UNDEFINED = 0;
+    FULL = 1;
+    LOW = 2;
+    HIGH = 3;
+    SUPER = 4;
+};
+
+[Packed, repr="C"]
+struct UsbSetup {
+    uint8 bmRequestType;
+    uint8 bRequest;
+    uint16 wValue;
+    uint16 wIndex;
+    uint16 wLength;
+};
+
+[Packed, repr="C"]
+struct UsbDescriptorHeader {
+    uint8 bLength;
+    uint8 bDescriptorType;
+};
+
+[Packed, repr="C"]
+struct UsbDeviceDescriptor {
+    uint8 bLength;
+    uint8 bDescriptorType;
+    uint16 bcdUSB;
+    uint8 bDeviceClass;
+    uint8 bDeviceSubClass;
+    uint8 bDeviceProtocol;
+    uint8 bMaxPacketSize0;
+    uint16 idVendor;
+    uint16 idProduct;
+    uint16 bcdDevice;
+    uint8 iManufacturer;
+    uint8 iProduct;
+    uint8 iSerialNumber;
+    uint8 bNumConfigurations;
+};
+
+[Packed, repr="C"]
+struct UsbInterfaceDescriptor {
+    uint8 bLength;
+    uint8 bDescriptorType;
+    uint8 bInterfaceNumber;
+    uint8 bAlternateSetting;
+    uint8 bNumEndpoints;
+    uint8 bInterfaceClass;
+    uint8 bInterfaceSubClass;
+    uint8 bInterfaceProtocol;
+    uint8 iInterface;
+};
+
+[Packed, repr="C"]
+struct UsbEndpointDescriptor {
+    uint8 bLength;
+    uint8 bDescriptorType;
+    uint8 bEndpointAddress;
+    uint8 bmAttributes;
+    uint16 wMaxPacketSize;
+    uint8 bInterval;
+};
+
+[Packed, repr="C"]
+struct UsbSsEpCompDescriptor {
+    uint8 bLength;
+    uint8 bDescriptorType;
+    uint8 bMaxBurst;
+    uint8 bmAttributes;
+    uint16 wBytesPerInterval;
+};
diff --git a/system/fidl/ddk/protocols/mailbox.fidl b/system/fidl/ddk/protocols/mailbox.fidl
new file mode 100644
index 0000000..b1b608e
--- /dev/null
+++ b/system/fidl/ddk/protocols/mailbox.fidl
@@ -0,0 +1,22 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.mailbox;
+
+using zx;
+
+struct MailboxDataBuf {
+    uint32 cmd;
+    vector<void> tx;
+};
+
+struct MailboxChannel {
+    uint32 mailbox;
+    vector<void> rx;
+};
+
+[Layout="ddk-protocol"]
+interface Mailbox {
+  1: SendCommand(MailboxChannel channel, MailboxDataBuf mdata) -> (zx.status s);
+};
diff --git a/system/fidl/ddk/protocols/makefile b/system/fidl/ddk/protocols/makefile
new file mode 100644
index 0000000..3a536b7
--- /dev/null
+++ b/system/fidl/ddk/protocols/makefile
@@ -0,0 +1,152 @@
+# Copyright 2018 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+LOCAL_DIR := $(patsubst %/,%,$(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))))
+FIDLC := ../../../../build-arm64/tools/fidlc
+
+CLANG_FORMAT := clang-format --style="{Language: Cpp, ColumnLimit: 100, UseTab: Never, IndentWidth: 4, IndentCaseLabels: false, AlignAfterOpenBracket: Align, SpacesBeforeTrailingComments: 1, BreakBeforeBraces: Attach, AccessModifierOffset: -4, DerivePointerAlignment: false, PointerAlignment: Left, AllowShortFunctionsOnASingleLine: Inline, AllowShortIfStatementsOnASingleLine: false, KeepEmptyLinesAtTheStartOfBlocks: true, AlignEscapedNewlinesLeft: false, ForEachMacros: ['list_for_every_entry','list_for_every_entry_safe'], AlwaysBreakTemplateDeclarations: true}"
+
+define run-fidl = 
+$(FIDLC) --ddk-header ddk/protocols/$@.h $(patsubst %.fidl,--files %.fidl, $^) \
+	--files $(LOCAL_DIR)/$@.fidl
+$(FIDLC) --ddktl-header ddktl/protocols/$@.h $(patsubst %.fidl,--files %.fidl, $^) \
+	--files $(LOCAL_DIR)/$@.fidl
+$(CLANG_FORMAT) ddk/protocols/$@.h > ddk/protocols/$@.formatted.h
+$(CLANG_FORMAT) ddktl/protocols/$@.h > ddktl/protocols/$@.formatted.h
+$(CLANG_FORMAT) ddktl/protocols/$@-internal.h > ddktl/protocols/$@-internal.formatted.h
+cp -f ddk/protocols/$@.formatted.h ../../../ulib/ddk/include/ddk/protocol/$@.h
+cp -f ddktl/protocols/$@.formatted.h ../../../ulib/ddktl/include/ddktl/protocol/$@.h
+cp -f ddktl/protocols/$@-internal.formatted.h ../../../ulib/ddktl/include/ddktl/protocol/$@-internal.h
+endef
+
+acpi:
+	$(run-fidl)
+
+amlogic-canvas:
+	$(run-fidl)
+
+bad-block:
+	$(run-fidl)
+
+block: $(LOCAL_DIR)/libs/block.fidl
+	$(run-fidl)
+
+bt-gatt-svc:
+	$(run-fidl)
+
+bt-hci:
+	$(run-fidl)
+
+clk:
+	$(run-fidl)
+
+display-controller: $(LOCAL_DIR)/libs/audio.fidl
+	$(run-fidl)
+
+ethernet: $(LOCAL_DIR)/libs/listnode.fidl
+	$(run-fidl)
+
+gpio:
+	$(run-fidl)
+
+hidbus:
+	$(run-fidl)
+
+i2c-impl:
+	$(run-fidl)
+
+i2c:
+	$(run-fidl)
+
+intel-gpu-core:
+	$(run-fidl)
+
+intel-hda-codec:
+	$(run-fidl)
+
+intel-hda-dsp:
+	$(run-fidl)
+
+iommu:
+	$(run-fidl)
+
+mailbox:
+	$(run-fidl)
+
+nand: $(LOCAL_DIR)/libs/nand.fidl
+	$(run-fidl)
+
+pci: $(LOCAL_DIR)/libs/pci.fidl
+	$(run-fidl)
+
+pciroot:
+	$(run-fidl)
+
+platform-bus:
+	$(run-fidl)
+
+platform-device:
+	$(run-fidl)
+
+platform-proxy:
+	$(run-fidl)
+
+rawnand: $(LOCAL_DIR)/libs/nand.fidl
+	$(run-fidl)
+
+scpi:
+	$(run-fidl)
+
+sdhci: $(LOCAL_DIR)/libs/sdhci.fidl
+	$(run-fidl)
+
+sdio:
+	$(run-fidl)
+
+sdmmc: $(LOCAL_DIR)/libs/listnode.fidl $(LOCAL_DIR)/libs/block.fidl $(LOCAL_DIR)/block.fidl
+	$(run-fidl)
+
+serial-impl: $(LOCAL_DIR)/serial.fidl
+	$(run-fidl)
+
+serial:
+	$(run-fidl)
+
+test:
+	$(run-fidl)
+
+usb-bus: $(LOCAL_DIR)/libs/usb.fidl $(LOCAL_DIR)/libs/usb-hub.fidl $(LOCAL_DIR)/usb-hub.fidl
+	$(run-fidl)
+
+usb-dci: $(LOCAL_DIR)/libs/listnode.fidl $(LOCAL_DIR)/libs/phys-iter.fidl \
+	$(LOCAL_DIR)/libs/usb.fidl $(LOCAL_DIR)/libs/usb-hub.fidl $(LOCAL_DIR)/usb.fidl
+	$(run-fidl)
+
+usb-function: $(LOCAL_DIR)/libs/listnode.fidl $(LOCAL_DIR)/libs/phys-iter.fidl \
+	$(LOCAL_DIR)/libs/usb.fidl $(LOCAL_DIR)/libs/usb-hub.fidl $(LOCAL_DIR)/usb.fidl
+	$(run-fidl)
+
+usb-hci: $(LOCAL_DIR)/libs/listnode.fidl $(LOCAL_DIR)/libs/phys-iter.fidl \
+	$(LOCAL_DIR)/libs/usb.fidl $(LOCAL_DIR)/libs/usb-hub.fidl $(LOCAL_DIR)/usb.fidl \
+	$(LOCAL_DIR)/usb-hub.fidl $(LOCAL_DIR)/usb-bus.fidl
+	$(run-fidl)
+
+usb-hub: $(LOCAL_DIR)/libs/usb-hub.fidl
+	$(run-fidl)
+
+usb-mode-switch: $(LOCAL_DIR)/libs/usb-device.fidl $(LOCAL_DIR)/hidbus.fidl
+	$(run-fidl)
+
+usb: $(LOCAL_DIR)/libs/listnode.fidl $(LOCAL_DIR)/libs/phys-iter.fidl \
+	$(LOCAL_DIR)/libs/usb.fidl $(LOCAL_DIR)/libs/usb-hub.fidl
+	$(run-fidl)
+
+all: acpi amlogic-canvas bad-block block bt-gatt-svc bt-hci clk display-controller ethernet gpio \
+	hidbus i2c-impl i2c intel-gpu-core intel-hda-codec intel-hda-dsp iommu mailbox nand pci \
+	pciroot platform-bus platform-device platform-proxy rawnand scpi sdhci sdio sdmmc \
+	serial-impl serial test usb-bus usb-dci usb-function usb-hci usb-hub usb-mode-switch usb
+
+clean:
+	rm -rf ddk
+	rm -rf ddktl
diff --git a/system/fidl/ddk/protocols/nand.fidl b/system/fidl/ddk/protocols/nand.fidl
new file mode 100644
index 0000000..cf5ab31
--- /dev/null
+++ b/system/fidl/ddk/protocols/nand.fidl
@@ -0,0 +1,127 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.nand;
+
+using zircon.device.nand;
+using zx;
+
+/// NandOperation's are submitted for processing via the queue() method of the
+/// Nand Protocol. Once submitted, the contents of the NandOperation may be modified
+/// while it's being processed.
+///
+/// The completion_cb() must eventually be called upon success or failure and
+/// at that point the cookie field must contain whatever value was in it when
+/// the NandOperation was originally queued.
+///
+/// Any mention of "in pages" in this file means nand pages, as reported by
+/// nand_info.page_size, as opposed to physical memory pages (RAM). That's true
+/// even for vmo-related values.
+///
+/// corrected_bit_flips are always related to nand_info.ecc_bits, so it is
+/// possible to obtain a value that is larger than what is being read (in the oob
+/// case). On the other hand, if errors cannot be corrected, the operation will
+/// fail, and corrected_bit_flips will be undefined.
+
+/// NOTE: The protocol can be extended with barriers to support controllers that
+/// may issue multiple simultaneous request to the IO chips.
+
+enum NandOp : uint32 {
+   READ = 0x1;
+   WRITE = 0x2;
+   ERASE = 0x3;
+};
+
+/// A single operation can read or write an arbitrary number of pages,
+/// including out of band (OOB) data for each page. If either regular
+/// data or OOB is not required, the relevant VMO handle should be set to
+/// ZX_HANDLE_INVALID.
+///
+/// Note that length dictates the number of pages to access, regardless
+/// of the type of data requested: regular data, OOB or both.
+///
+/// The OOB data will be copied to (and from) a contiguous memory range
+/// starting at the given offset. Note that said offset is given in nand
+/// pages even though OOB is just a handful of bytes per page. In other
+/// words, after said offset, the OOB data for each page is located
+/// nand_info.oob_size bytes apart.
+///
+/// For example, to read 5 pages worth of data + OOB, with page size of
+/// 2 kB and 16 bytes of OOB per page, setting:
+///
+///     data_vmo = oob_vmo = vmo_handle
+///     length = 5
+///     offset_nand = 20
+///     offset_data_vmo = 0
+///     offset_oob_vmo = 5
+///
+/// will transfer pages [20, 24] to the first 2048 * 5 bytes of the vmo,
+/// followed by 16 * 5 bytes of OOB data starting at offset 2048 * 5.
+struct NandReadWrite {
+    /// Command.
+    NandOp command;
+    /// vmo of data to read or write.
+    handle<vmo> data_vmo;
+    /// vmo of OOB data to read or write.
+    handle<vmo> oob_vmo;
+    /// Number of pages to access.
+    /// (0 is invalid).
+    uint32 length;
+    /// Offset into nand, in pages.
+    uint32 offset_nand;
+    /// Data vmo offset in (nand) pages.
+    uint64 offset_data_vmo;
+    /// OOB vmo offset in (nand) pages.
+    uint64 offset_oob_vmo;
+    /// Optional physical page list.
+    vector<uint64>? page;
+    /// Return value from READ_DATA, max corrected bit flips in any
+    /// underlying ECC chunk read. The caller can compare this value
+    /// against ecc_bits to decide whether the nand erase block needs to
+    /// be recycled.
+    uint32 corrected_bit_flips;
+};
+
+struct NandErase {
+    /// Command.
+    NandOp command;
+    /// Offset into nand, in erase blocks.
+    uint32 first_block;
+    /// Number of blocks to erase.
+    /// (0 is invalid).
+    uint32 num_blocks;
+};
+
+union NandOperation {
+    /// All Commands.
+    NandOp command;
+    /// NAND_OP_READ, NAND_OP_WRITE.
+    NandReadWrite rw;
+    /// NAND_OP_ERASE.
+    NandErase erase;
+};
+
+[Layout="ddk-protocol", DefaultProtocol]
+interface Nand {
+    /// Obtains the parameters of the nand device (nand_info_t) and the required
+    /// size of nand_op_t. The nand_op_t's submitted via queue() must have
+    /// nand_op_size_out - sizeof(nand_op_t) bytes available at the end of the
+    /// structure for the use of the driver.
+    1: Query() -> (zircon.device.nand.NandInfo info, usize nand_op_size);
+
+    /// Submits an IO request for processing. Success or failure will be reported
+    /// via the completion_cb() in the nand_op_t. The callback may be called
+    /// before the queue() method returns.
+    [Async]
+    2: Queue(NandOperation? op) -> (zx.status s, NandOperation? op);
+
+    /// Gets the list of bad erase blocks, as reported by the nand manufacturer.
+    /// The caller must allocate a table large enough to hold the expected number
+    /// of entries, and pass the size of that table on |bad_block_len|.
+    /// On return, |num_bad_blocks| contains the number of bad blocks found.
+    /// This should only be called before writing any data to the nand, and the
+    /// returned data should be saved somewhere else, along blocks that become
+    /// bad after they've been in use.
+    3: GetFactoryBadBlockList() -> (zx.status s, vector<uint32> bad_blocks);
+};
diff --git a/system/fidl/ddk/protocols/pci.fidl b/system/fidl/ddk/protocols/pci.fidl
new file mode 100644
index 0000000..6d9c702
--- /dev/null
+++ b/system/fidl/ddk/protocols/pci.fidl
@@ -0,0 +1,68 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.pci;
+
+using zircon.syscalls.pci;
+using zx;
+
+enum PciCfg : uint16 {
+    VENDOR_ID = 0x00;
+    DEVICE_ID = 0x02;
+    REVISION_ID = 0x08;
+    CLASS_CODE = 0x09;
+    SUBSYSTEM_VENDOR_ID = 0x2C;
+    SUBSYSTEM_ID = 0x2E;
+    CAPABILITIES_PTR = 0x34;
+};
+
+enum PciCapId : uint8 {
+    NULL = 0x00;
+    PCI_PWR_MGMT = 0x01;
+    AGP = 0x02;
+    VPD = 0x03;
+    MSI = 0x05;
+    PCIX = 0x07;
+    HYPERTRANSPORT = 0x08;
+    VENDOR = 0x09;
+    DEBUG_PORT = 0x0A;
+    COMPACT_PCI_CRC = 0x0B;
+    PCI_HOT_PLUG = 0x0C;
+    PCI_BRIDGE_SUBSYSTEM_VID = 0x0D;
+    AGP8X = 0x0E;
+    SECURE_DEVICE = 0x0F;
+    PCI_EXPRESS = 0x10;
+    MSIX = 0x11;
+    SATA_DATA_NDX_CFG = 0x12;
+    ADVANCED_FEATURES = 0x13;
+    ENHANCED_ALLOCATION = 0x14;
+};
+
+[Layout="ddk-protocol"]
+interface Pci {
+    1: GetBar(uint32 bar_id) -> (zx.status s, zircon.syscalls.pci.ZxPciBar res);
+    2: MapBar(uint32 bar_id, uint32 cache_policy) -> (zx.status s, vector<void>? vaddr,
+                                                      handle<vmo> @handle);
+    3: EnableBusMaster(bool enable) -> (zx.status s);
+    4: ResetDevice() -> (zx.status s);
+    5: MapInterrupt(int32 which_irq) -> (zx.status s, handle<interrupt> @handle);
+    6: QueryIrqMode(zircon.syscalls.pci.ZxPciIrqMode mode) -> (zx.status s, uint32 max_irqs);
+    7: SetIrqMode(zircon.syscalls.pci.ZxPciIrqMode mode, uint32 requested_irq_count) -> (zx.status s);
+    8: GetDeviceInfo() -> (zx.status s, zircon.syscalls.pci.ZxPcieDeviceInfo into);
+    9: ConfigRead(uint16 offset, usize width) -> (zx.status s, uint32 value);
+    10: ConfigWrite(uint16 offset, usize width, uint32 value) -> (zx.status s);
+    11: GetNextCapability(uint8 type, uint8 offset) -> (uint8 cap);
+    12: GetAuxdata(string args) -> (zx.status s, vector<void> data);
+    13: GetBti(uint32 index) -> (zx.status s, handle<bti> bti);
+};
+
+// TODO: Implement the following.
+//static inline uint8_t pci_get_first_capability(const pci_protocol_t* pci, uint8_t type) {
+//    return pci_get_next_capability(pci, kPciCfgCapabilitiesPtr - 1u, type);
+//}
+//static inline zx_status_t pci_get_auxdata(const pci_protocol_t* pci,
+//                                          const char* args, void* data,
+//                                          uint32_t bytes, uint32_t* actual) {
+//    return pci->ops->get_auxdata(pci->ctx, args, data, bytes, actual);
+//}
diff --git a/system/fidl/ddk/protocols/pciroot.fidl b/system/fidl/ddk/protocols/pciroot.fidl
new file mode 100644
index 0000000..e04481d
--- /dev/null
+++ b/system/fidl/ddk/protocols/pciroot.fidl
@@ -0,0 +1,13 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.pciroot;
+
+using zx;
+
+[Layout="ddk-protocol"]
+interface Pciroot {
+    1: GetAuxdata(string args) -> (zx.status s, vector<void> data);
+    2: GetBti(uint32 bdf, uint32 index) -> (zx.status s, handle<bti> bti);
+};
diff --git a/system/fidl/ddk/protocols/platform-bus.fidl b/system/fidl/ddk/protocols/platform-bus.fidl
new file mode 100644
index 0000000..278e199
--- /dev/null
+++ b/system/fidl/ddk/protocols/platform-bus.fidl
@@ -0,0 +1,120 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.platform_bus;
+
+using zx;
+
+struct PbusMmio {
+    /// Physical address of MMIO region.
+    /// Does not need to be page aligned.
+    zx.paddr  base;
+    /// Length of MMIO region in bytes.
+    /// Does not need to be page aligned.
+    usize     length;
+};
+
+struct PbusIrq {
+    uint32    irq;
+    /// `ZX_INTERRUPT_MODE_*` flags
+    uint32    mode;
+};
+
+struct PbusGpio {
+    uint32    gpio;
+};
+
+struct PbusI2cChannel{
+    uint32    bus_id;
+    uint16    address;
+};
+
+struct PbusClk {
+    uint32 clk;
+};
+
+struct PbusBti {
+    uint32    iommu_index;
+    uint32    bti_id;
+};
+
+/// Device metadata.
+struct PbusMetadata {
+    /// Metadata type.
+    uint32    type;
+    /// Pointer to metadata.
+    vector<void> data;
+};
+
+/// Device metadata to be passed from bootloader via a ZBI record.
+struct PbusBootMetadata {
+    /// Metadata type (matches `zbi_header_t.type` for bootloader metadata).
+    uint32 zbi_type;
+    /// Matches `zbi_header_t.extra` for bootloader metadata.
+    /// Used in cases where bootloader provides multiple metadata records of the same type.
+    uint32 zbi_extra;
+};
+
+struct PbusDev {
+    string name;
+    /// `BIND_PLATFORM_DEV_VID`
+    uint32 vid;
+    /// `BIND_PLATFORM_DEV_PID`
+    uint32 pid;
+    /// `BIND_PLATFORM_DEV_DID`
+    uint32 did;
+    vector<PbusMmio> mmio;
+    vector<PbusIrq> irq;
+    vector<PbusGpio> gpio;
+    vector<PbusI2cChannel> i2c_channel;
+    vector<PbusClk> clk;
+    vector<PbusBti> bti;
+    vector<PbusMetadata> metadata;
+    vector<PbusBootMetadata> boot_metadata;
+    /// List of this device's child devices.
+    /// This is only used in cases where children of a platform device also need to access
+    /// platform bus resources.
+    vector<PbusDev?> children;
+    /// Extra protocols to be provided to this platform device and its children.
+    /// These fields are only used for the top level `pbus_dev_t`.
+    vector<uint32> protocol;
+};
+
+/// Subset of pdev_board_info_t to be set by the board driver.
+struct PbusBoardInfo {
+    /// Board specific revision number.
+    uint32 board_revision;
+};
+
+[Layout="ddk-callback"]
+interface PlatformProxyCb {
+    1: Callback(vector<void> req, vector<handle> req_handle) -> (zx.status s, vector<void> resp,
+                                                                 vector<handle> resp_handle);
+};
+
+[Layout="ddk-protocol"]
+interface PlatformDevice {
+    /// Adds a new platform device to the bus, using configuration provided by |dev|.
+    /// Platform devices are created in their own separate devhosts.
+    1: DeviceAdd(PbusDev dev) -> (zx.status s);
+    /// Adds a device for binding a protocol implementation driver.
+    /// These devices are added in the same devhost as the platform bus.
+    /// After the driver binds to the device it calls `pbus_register_protocol()`
+    /// to register its protocol with the platform bus.
+    /// `pbus_protocol_device_add()` blocks until the protocol implementation driver
+    /// registers its protocol (or times out).
+    2: ProtocolDeviceAdd(uint32 proto_id, PbusDev dev) -> (zx.status s);
+    /// Called by protocol implementation drivers to register their protocol
+    /// with the platform bus.
+    3: RegisterProtocol(uint32 proto_id, vector<void> protocol, PlatformProxyCb proxy_cb)
+           -> (zx.status s);
+    /// Returns the board name for the underlying hardware.
+    /// Board drivers may use this to differentiate between multiple boards that they support.
+    4: GetBoardName() -> (string name);
+    /// Board drivers may use this to set information about the board
+    /// (like the board revision number).
+    /// Platform device drivers can access this via `pdev_get_board_info()`.
+    5: SetBoardInfo(PbusBoardInfo info) -> (zx.status s);
+};
+
diff --git a/system/fidl/ddk/protocols/platform-device.fidl b/system/fidl/ddk/protocols/platform-device.fidl
new file mode 100644
index 0000000..723e4d3
--- /dev/null
+++ b/system/fidl/ddk/protocols/platform-device.fidl
@@ -0,0 +1,50 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.platform_device;
+
+using zx;
+
+// TODO: Not need this anymore.
+[repr="C"]
+struct ZxDevice {};
+[repr="C"]
+struct DeviceAddArgs {};
+
+struct PdevDeviceInfo {
+    uint32 vid;
+    uint32 pid;
+    uint32 did;
+    uint32 mmio_count;
+    uint32 irq_count;
+    uint32 gpio_count;
+    uint32 i2c_channel_count;
+    uint32 clk_count;
+    uint32 bti_count;
+    uint32 metadata_count;
+    array<uint32>:8 reserved;
+    string:32 name;
+};
+
+struct PdevBoardInfo {
+    /// Vendor ID for the board.
+    uint32 vid;
+    /// Product ID for the board.
+    uint32 pid;
+    /// Board name from the boot image platform ID record.
+    string:32 board_name;
+    /// Board specific revision number.
+    uint32 board_revision;
+};
+
+[Layout="ddk-protocol"]
+interface PlatformDevice {
+    1: MapMmio(uint32 index, uint32 cache_policy) -> (zx.status s, vector<void>? vaddr,
+                                                      zx.paddr paddr, handle<vmo> @handle);
+    2: MapInterrupt(uint32 index, uint32 flags) -> (zx.status s, handle<interrupt> irq);
+    3: GetBti(uint32 index) -> (zx.status s, handle<bti> bti);
+    4: GetDeviceInfo() -> (zx.status s, PdevDeviceInfo info);
+    5: GetBoardInfo() -> (zx.status s, PdevBoardInfo info);
+    6: DeviceAdd (uint32 index, DeviceAddArgs args) -> (zx.status s, ZxDevice? out);
+};
diff --git a/system/fidl/ddk/protocols/platform-proxy.fidl b/system/fidl/ddk/protocols/platform-proxy.fidl
new file mode 100644
index 0000000..ee74653
--- /dev/null
+++ b/system/fidl/ddk/protocols/platform-proxy.fidl
@@ -0,0 +1,38 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.platform_proxy;
+
+using zx;
+
+struct ZxTxid {};
+
+const uint32 PLATFORM_PROXY_MAX_DATA = 4096;
+
+/// Header for RPC requests.
+struct PlatformProxyReq {
+    ZxTxid txid;
+    uint32 device_id;
+    uint32 proto_id;
+    uint32 op;
+};
+
+/// Header for RPC responses.
+struct PlatformProxyRsp {
+    ZxTxid txid;
+    zx.status status;
+};
+
+[Layout="ddk-protocol"]
+interface PlatformProxy {
+    /// Used by protocol client drivers to register their local protocol implementation
+    /// with the platform proxy driver.
+    1: RegisterProtocol(uint32 proto_id, vector<void> protocol) -> (zx.status s);
+    /// Used by protocol client drivers to proxy a protocol call to the protocol implementation
+    /// driver in the platform bus driver's devhost.
+    2: Proxy(vector<void> req, vector<handle> req_handle) -> (zx.status s, vector<void> resp,
+                                                              vector<handle> resp_handle);
+};
+
+
diff --git a/system/fidl/ddk/protocols/rawnand.fidl b/system/fidl/ddk/protocols/rawnand.fidl
new file mode 100644
index 0000000..b2b4c48
--- /dev/null
+++ b/system/fidl/ddk/protocols/rawnand.fidl
@@ -0,0 +1,29 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.rawnand;
+
+using zircon.device.nand;
+using zx;
+
+[Layout="ddk-protocol"]
+interface RawNand {
+    /// Read one nand page with hwecc.
+    1: ReadPageHwecc(uint32 nandpage) -> (zx.status s, vector<void> data, vector<void> oob,
+                                          int32 ecc_correct);
+
+    /// Write one nand page with hwecc.
+    2: WritePageHwecc(vector<void> data, vector<void> oob, uint32 nandpage) -> (zx.status s);
+
+    /// Erase nand block.
+    3: EraseBlock(uint32 nandpage) -> (zx.status s);
+
+    4: GetNandInfo() -> (zx.status s, zircon.device.nand.NandInfo info);
+
+    /// Send ONFI command down to controller.
+    5: CmdCtrl(int32 cmd, uint32 ctrl) -> ();
+
+    /// Read byte (used to read status as well as other info, such as ID).
+    6: ReadByte() -> (uint8 byte);
+};
diff --git a/system/fidl/ddk/protocols/scpi.fidl b/system/fidl/ddk/protocols/scpi.fidl
new file mode 100644
index 0000000..37cedda
--- /dev/null
+++ b/system/fidl/ddk/protocols/scpi.fidl
@@ -0,0 +1,32 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.scpi;
+
+using zx;
+
+const uint32 MAX_DVFS_OPPS = 16;
+
+[Layout="Packed"]
+struct ScpiOppEntry {
+    uint32 freq_hz;
+    uint32 volt_mv;
+};
+
+[Layout="Packed"]
+struct ScpiOpp {
+   array<ScpiOppEntry>:MAX_DVFS_OPPS opp;
+   /// In usecs.
+   uint32 latency;
+   uint32 count;
+};
+
+[Layout="ddk-protocol"]
+interface Scpi {
+  1: GetSensor(string name) -> (zx.status s, uint32 sensor_id);
+  2: GetSensorValue(uint32 sensor_id) -> (zx.status s, uint32 sensor_value);
+  3: GetDvfsInfo(uint8 power_domain) -> (zx.status s, ScpiOpp opps);
+  4: GetDvfsIdx(uint8 power_domain) -> (zx.status s, uint16 index);
+  5: SetDvfsIdx(uint8 power_domain, uint16 index) -> (zx.status s);
+};
diff --git a/system/fidl/ddk/protocols/sdhci.fidl b/system/fidl/ddk/protocols/sdhci.fidl
new file mode 100644
index 0000000..90d2632
--- /dev/null
+++ b/system/fidl/ddk/protocols/sdhci.fidl
@@ -0,0 +1,45 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.sdhci;
+
+using hw.sdhci;
+using zx;
+
+enum SdhciQuirk : uint64 {
+    /// This is a BCM28xx specific quirk. The bottom 8 bits of the 136
+    /// bit response are normally filled by 7 CRC bits and 1 reserved bit.
+    /// The BCM controller checks the CRC for us and strips it off in the
+    /// process.
+    /// The higher level stack expects 136B responses to be packed in a
+    /// certain way so we shift all the fields back to their proper offsets.
+    STRIP_RESPONSE_CRC                 = 0x1;
+    /// BCM28xx quirk: The BCM28xx appears to use its internal DMA engine to
+    /// perform transfers against the SD card. Normally we would use SDMA or
+    /// ADMA (if the part supported it). Since this part doesn't appear to
+    /// support either, we just use PIO.
+    NO_DMA                             = 0x2;
+    /// The bottom 8 bits of the 136 bit response are normally filled by 7 CRC bits
+    /// and 1 reserved bit. Some controllers strip off the CRC.
+    /// The higher level stack expects 136B responses to be packed in a certain way
+    /// so we shift all the fields back to their proper offsets.
+    STRIP_RESPONSE_CRC_PRESERVE_ORDER  = 0x4;
+};
+
+[Layout="ddk-protocol"]
+interface Sdhci {
+    // TODO: should be replaced with a generic busdev mechanism
+    1: GetInterrupt() -> (zx.status s, handle<interrupt> irq);
+    2: GetMmio() -> (zx.status s, handle<vmo> mmio);
+    /// Gets a handle to the bus transaction initiator for the device. The caller
+    /// receives ownership of the handle.
+    3: GetBti(uint32 index) -> (zx.status s, handle<bti> bti);
+
+    4: GetBaseClock() -> (uint32 clock);
+
+    /// returns device quirks
+    5: GetQuirks() -> (uint64 clock);
+    /// platform specific HW reset
+    6: HwReset() -> ();
+};
diff --git a/system/fidl/ddk/protocols/sdio.fidl b/system/fidl/ddk/protocols/sdio.fidl
new file mode 100644
index 0000000..e4b1578
--- /dev/null
+++ b/system/fidl/ddk/protocols/sdio.fidl
@@ -0,0 +1,83 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.sdio;
+
+using zx;
+
+const uint8 SDIO_FN_0 = 0;
+const uint8 SDIO_FN_1 = 0;
+const uint8 SDIO_FN_2 = 0;
+/// Including func 0
+const uint8 SDIO_MAX_FUNCS = 8;
+
+struct SdioFuncHwInfo {
+    uint32 manufacturer_id;
+    uint32 product_id;
+    uint32 max_blk_size;
+    uint32 max_tran_speed;
+    uint8  fn_intf_code;
+};
+
+enum SDIO_CARD : uint32 {
+    MULTI_BLOCK    = 0x1;
+    SRW            = 0x2;
+    DIRECT_COMMAND = 0x4;
+    SUSPEND_RESUME = 0x8;
+    LOW_SPEED      = 0x10;
+    HIGH_SPEED     = 0x20;
+    HIGH_POWER     = 0x40;
+    FOUR_BIT_BUS   = 0x80;
+    HS_SDR12       = 0x100;
+    HS_SDR25       = 0x200;
+    UHS_SDR50      = 0x400;
+    UHS_SDR104     = 0x800;
+    UHS_DDR50      = 0x1000;
+    TYPE_A       = 0x2000;
+    TYPE_B       = 0x4000;
+    TYPE_C       = 0x8000;
+    TYPE_D       = 0x10000;
+};
+
+struct SdioDeviceHwInfo {
+    /// number of sdio funcs
+    uint32  num_funcs;
+    uint32  sdio_vsn;
+    uint32  cccr_vsn;
+    uint32  caps;
+};
+
+struct SdioHwInfo {
+    SdioDeviceHwInfo dev_hw_info;
+    array<SdioFuncHwInfo>:SDIO_MAX_FUNCS funcs_hw_info;
+    uint32 host_max_transfer_size;
+};
+
+struct SdioRwTxn {
+    uint32 addr;
+    uint32 data_size;
+    bool incr;
+    bool fifo;
+    bool write;
+    bool use_dma;
+    /// Used if use_dma is true
+    handle<vmo> dma_vmo;
+    /// Used if use_dma is false
+    vector<void> virt;
+    /// offset into dma_vmo or virt
+    uint64 buf_offset;
+};
+
+[Layout="ddk-protocol"]
+interface Sdio {
+    1: GetDevHwInfo() -> (zx.status s, SdioHwInfo hw_info);
+    3: EnableFn(uint8 fn_idx) -> (zx.status s);
+    4: DisableFn(uint8 fn_idx) -> (zx.status s);
+    5: EnableFnIntr(uint8 fn_idx) -> (zx.status s);
+    6: DisableFnIntr(uint8 fn_idx) -> (zx.status s);
+    7: UpdateBlockSize(uint8 fn_idx, uint16 blk_sz, bool deflt) -> (zx.status s);
+    8: GetBlockSize(uint8 fn_idx) -> (zx.status s, uint16 cur_blk_size);
+    9: DoRwTxn(uint8 fn_idx, SdioRwTxn? txn) -> (zx.status s);
+};
+
diff --git a/system/fidl/ddk/protocols/sdmmc.fidl b/system/fidl/ddk/protocols/sdmmc.fidl
new file mode 100644
index 0000000..4801832
--- /dev/null
+++ b/system/fidl/ddk/protocols/sdmmc.fidl
@@ -0,0 +1,115 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.sdmmc;
+
+using ddk.protocol.block;
+using zircon.listnode;
+using zx;
+
+enum SdmmcVoltage : uint8 {
+    V330 = 0;
+    V180 = 1;
+    MAX = 2;
+};
+
+enum SdmmcBusWidth : uint8 {
+    ONE = 0;
+    FOUR = 1;
+    EIGHT = 2;
+    MAX = 3;
+};
+
+enum SdmmcTiming : uint8 {
+    LEGACY = 0;
+    HS = 1;
+    HSDDR = 2;
+    HS200 = 3;
+    HS400 = 4;
+    SDR12 = 5;
+    SDR25 = 6;
+    SDR50 = 7;
+    SDR104 = 8;
+    DDR50 = 9;
+    MAX = 10;
+};
+
+/// block io transactions. one per client request
+struct SdmmcTxn {
+    ddk.protocol.block.BlockOp bop;
+    zircon.listnode.ListNode node;
+};
+
+/// number of pages per request - 2M per request
+/// matches DMA_DESC_COUNT in dev/block/sdhci
+/// (PAGE_SIZE / sizeof(zx_paddr_t))
+const uint64 SDMMC_PAGES_COUNT = 512;
+
+/// sdmmc requests. one per command
+struct SdmmcReq {
+    uint32 cmd_idx;
+    uint32 cmd_flags;
+    uint32 arg;
+
+    /// data command parameters
+    uint16 blockcount;
+    uint16 blocksize;
+    bool use_dma;
+    /// Used if use_dma is true
+    handle<vmo> dma_vmo;
+    /// Used if use_dma is false
+    vector<void> virt;
+    /// offset into dma_vmo or virt
+    uint64 buf_offset;
+    handle pmt;
+
+    /// response data
+    array<uint32>:4 response;
+
+    /// status
+    zx.status status;
+};
+
+enum SdmmcHostCap : uint64 {
+    BUS_WIDTH_8 = 0x1;
+    ADMA2       = 0x2;
+    SIXTY_FOUR_BIT = 0x4;
+    VOLTAGE_330 = 0x8;
+    AUTO_CMD12  = 0x10;
+};
+
+enum SdmmcHostPrefs : uint64 {
+    DISABLE_HS400 = 0x1;
+    DISABLE_HS200 = 0x2;
+};
+
+struct SdmmcHostInfo {
+    /// Controller capabilities
+    uint64 caps;
+    /// Maximum data request size
+    uint64 max_transfer_size;
+    uint64 max_transfer_size_non_dma;
+    /// Host specific preferences
+    uint64 prefs;
+};
+
+[Layout="ddk-protocol"]
+interface Sdmmc {
+    /// Get host info.
+    1: HostInfo() -> (zx.status s, SdmmcHostInfo info);
+    /// Set signal voltage.
+    2: SetSignalVoltage(SdmmcVoltage voltage) -> (zx.status s);
+    /// Set bus width.
+    3: SetBusWidth(SdmmcBusWidth bus_width) -> (zx.status s);
+    /// Set bus frequency.
+    4: SetBusFreq(uint32 bus_freq) -> (zx.status s);
+    /// Set mmc timing.
+    5: SetTiming(SdmmcTiming timing) -> (zx.status s);
+    /// Issue a hw reset.
+    6: HwReset() -> ();
+    /// Perform tuning.
+    7: PerformTuning(uint32 cmd_idx) -> (zx.status s);
+    /// Issue a request.
+    8: Request(SdmmcReq? req) -> (zx.status s);
+};
diff --git a/system/fidl/ddk/protocols/serial-impl.fidl b/system/fidl/ddk/protocols/serial-impl.fidl
new file mode 100644
index 0000000..8933fba
--- /dev/null
+++ b/system/fidl/ddk/protocols/serial-impl.fidl
@@ -0,0 +1,33 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.serial_impl;
+
+using zx;
+using ddk.protocol.serial;
+
+enum SerialState : uint32 {
+    READABLE = 0x1;
+    WRITABLE = 0x2;
+};
+
+/// Callback for notification of readable/writeable state changes
+/// This may be called from an interrupt thread it should just signal another thread
+/// and return as soon as possible. In particular, it may not be safe to make protocol calls
+/// from these callbacks.
+[Layout="ddk-callback"]
+interface SerialNotify {
+  1: Callback(SerialState state) -> ();
+};
+
+[Layout="ddk-protocol", DefaultProtocol]
+interface SerialImpl {
+  1: GetInfo() -> (zx.status s, ddk.protocol.serial.SerialPortInfo info);
+  /// Configures the given serial port.
+  2: Config(uint32 baud_rate, uint32 flags) -> (zx.status s);
+  3: Enable(bool enable) -> (zx.status s);
+  4: Read() -> (zx.status s, vector<void> buf);
+  5: Write(vector<void> buf) -> (zx.status s, usize actual);
+  6: SetNotifyCallback(SerialNotify cb) -> (zx.status s);
+};
diff --git a/system/fidl/ddk/protocols/serial.fidl b/system/fidl/ddk/protocols/serial.fidl
new file mode 100644
index 0000000..36c8261
--- /dev/null
+++ b/system/fidl/ddk/protocols/serial.fidl
@@ -0,0 +1,29 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.serial;
+
+using zx;
+
+struct SerialPortInfo {
+    uint32 serial_class;
+    /// Vendor and product ID of hardware attached to this serial port,
+    /// or zero if not applicable.
+    uint32 serial_vid;
+    uint32 serial_pid;
+};
+
+/// High level serial protocol for use by client drivers.
+/// When used with the platform device protocol, "port" will be relative to
+/// the list of serial ports assigned to your device rather than the global
+/// list of serial ports.
+[Layout="ddk-protocol", DefaultProtocol]
+interface Serial {
+  1: GetInfo() -> (zx.status s, SerialPortInfo info);
+  /// Configures the given serial port.
+  2: Config(uint32 baud_rate, uint32 flags) -> (zx.status s);
+  /// Returns a socket that can be used for reading and writing data
+  /// from the given serial port.
+  3: OpenSocket() -> (zx.status s, handle<socket> @handle);
+};
diff --git a/system/fidl/ddk/protocols/skip-block.fidl b/system/fidl/ddk/protocols/skip-block.fidl
new file mode 100644
index 0000000..c2a2cad
--- /dev/null
+++ b/system/fidl/ddk/protocols/skip-block.fidl
@@ -0,0 +1,8 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.skip_block;
+
+[Layout="ddk-protocol", DefaultProtocol]
+interface SkipBlock {};
diff --git a/system/fidl/ddk/protocols/test.fidl b/system/fidl/ddk/protocols/test.fidl
new file mode 100644
index 0000000..83e1977
--- /dev/null
+++ b/system/fidl/ddk/protocols/test.fidl
@@ -0,0 +1,42 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.test;
+
+using zx;
+
+struct TestReport {
+    uint64 n_tests;
+    uint64 n_success;
+    uint64 n_failed;
+};
+
+[Layout="ddk-callback"]
+interface TestFunc {
+    1: Callback(vector<void> arg) -> (zx.status s, TestReport report);
+};
+
+[Layout="ddk-protocol"]
+interface Test {
+    /// Sets test output socket.
+    1: SetOutputSocket(handle<socket> @handle) -> ();
+
+    /// Gets test output socket.
+    2: GetOutputSocket() -> (handle<socket> h);
+
+    /// Sets control channel.
+    3: SetControlChannel(handle<channel> @handle) -> ();
+
+    /// Gets control channel.
+    4: GetControlChannel() -> (handle<channel> @handle);
+
+    /// Sets test function.
+    5: SetTestFunc(TestFunc func) -> ();
+
+    /// Run tests, calls the function set in |SetTestFunc|.
+    6: RunTests(vector<void> arg) -> (zx.status s, TestReport report);
+
+    /// Calls `device_remove()`.
+    7: Destroy() -> ();
+};
diff --git a/system/fidl/ddk/protocols/usb-bus.fidl b/system/fidl/ddk/protocols/usb-bus.fidl
new file mode 100644
index 0000000..3c4bc77
--- /dev/null
+++ b/system/fidl/ddk/protocols/usb-bus.fidl
@@ -0,0 +1,33 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.usb_bus;
+
+using ddk.protocol.usb_hub;
+using zircon.hw.usb;
+using zircon.hw.usb_hub;
+using zx;
+
+// TODO: Not need this anymore.
+[repr="C"]
+struct ZxDevice {};
+
+[Layout="ddk-protocol"]
+interface UsbBus {
+    /// Hub support.
+    1: ConfigureHub(ZxDevice? hub_device, zircon.hw.usb.UsbSpeed speed,
+                    zircon.hw.usb_hub.UsbHubDescriptor descriptor) -> (zx.status s);
+    2: HubDeviceAdded(ZxDevice? hub_device, int64 port, zircon.hw.usb.UsbSpeed speed)
+           -> (zx.status s);
+    3: HubDeviceRemoved(ZxDevice? hub_device, int64 port) -> (zx.status s);
+    4: SetHubInterface(ZxDevice? usb_device, ddk.protocol.usb_hub.UsbHub hub) -> (zx.status s);
+};
+
+/// Interface for use by the HCI controller to use to notify when devices are added and removed.
+[Layout="ddk-interface"]
+interface UsbBusInterface {
+    1: AddDevice(uint32 device_id, uint32 hub_id, zircon.hw.usb.UsbSpeed speed) -> (zx.status s);
+    2: RemoveDevice(uint32 device_id) -> ();
+    3: ResetHubPort(uint32 hub_id, uint32 port) -> ();
+};
diff --git a/system/fidl/ddk/protocols/usb-dci.fidl b/system/fidl/ddk/protocols/usb-dci.fidl
new file mode 100644
index 0000000..2d11e04
--- /dev/null
+++ b/system/fidl/ddk/protocols/usb-dci.fidl
@@ -0,0 +1,35 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.usb_dci;
+
+using ddk.protocol.usb;
+using zircon.hw.usb;
+using zx;
+
+/// This protocol is used for USB peripheral controller drivers.
+///
+/// Callbacks implemented by the USB device driver.
+[Layout="ddk-interface"]
+interface UsbDciInterface {
+    /// callback for handling ep0 control requests
+    1: Control(zircon.hw.usb.UsbSetup setup) -> (zx.status status, vector<void> buffer,
+                                                 usize actual);
+    2: SetConnected(bool connected) -> ();
+    3: SetSpeed(zircon.hw.usb.UsbSpeed speed) -> ();
+};
+
+[Layout="ddk-protocol"]
+interface UsbDci {
+    1: RequestQueue(ddk.protocol.usb.UsbRequest? req) -> ();
+    /// Registers callback interface with the controller driver.
+    2: SetInterface(UsbDciInterface @interface) -> (zx.status s);
+    3: ConfigEp(zircon.hw.usb.UsbEndpointDescriptor ep_desc,
+                zircon.hw.usb.UsbSsEpCompDescriptor ss_comp_desc) -> (zx.status s);
+    4: DisableEp(uint8 ep_address) -> (zx.status s);
+    5: EpSetStall(uint8 ep_address) -> (zx.status s);
+    6: EpClearStall(uint8 ep_address) -> (zx.status s);
+    /// Shares a copy of the DCI driver's BTI handle.
+    7: GetBti() -> (zx.status s, handle<bti> bti);
+};
diff --git a/system/fidl/ddk/protocols/usb-function.fidl b/system/fidl/ddk/protocols/usb-function.fidl
new file mode 100644
index 0000000..1a16441
--- /dev/null
+++ b/system/fidl/ddk/protocols/usb-function.fidl
@@ -0,0 +1,81 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.usb_function;
+
+using ddk.protocol.usb;
+using ddk.phys_iter;
+using zircon.hw.usb;
+using zx;
+
+/// This protocol is used for USB peripheral function functions.
+/// Callbacks implemented by the function driver.
+[Layout="ddk-interface"]
+interface UsbFunctionInterface {
+    /// Callback for handling ep0 control requests.
+    /// Return the descriptor list for the function. Callee retains ownership of descriptors.
+    // TODO(voydanoff) - descriptors will likely vary (different max packet sizes, etc)
+    // depending on whether we are in low/full, high or super speed mode.
+    // We will need to add a usb_speed_t argument to this callback.
+    1: GetDescriptors() -> (vector<zircon.hw.usb.UsbDescriptorHeader>? descriptor);
+
+    /// Callback for handling ep0 control requests.
+    2: Control(zircon.hw.usb.UsbSetup setup) -> (zx.status s, vector<void> buffer, usize actual);
+
+    /// Called to inform the function driver when the USB device configured state changes.
+    /// Called with configured == true in response to a SET_CONFIGURATION control request
+    /// that selects a configuration that contains this function. In this case, the function driver
+    /// should call usb_function_config_ep() to configure its endpoints.
+    /// Called with configured == false when configuration is disabled or USB is disconnected.
+    /// The function driver should then call usb_function_disable_ep() to disable its endpoints.
+    3: SetConfigured(bool configured, zircon.hw.usb.UsbSpeed speed) -> (zx.status s);
+
+    /// Called to set an alternate setting for an interface due to a SET_INTERFACE control request.
+    /// The function driver should call usb_function_config_ep() and/or usb_function_config_ep()
+    /// to configure or disable the interface's endpoints as appropriate.
+    4: SetInterface(uint64 @interface, uint64 alt_setting) -> (zx.status s);
+};
+
+[Layout="ddk-protocol"]
+interface UsbDciInterface {
+    1: ReqAlloc(uint64 data_size, uint8 ep_address) -> (zx.status s, ddk.protocol.usb.UsbRequest? req);
+    2: ReqAllocVmo(handle<vmo> vmo, uint64 vmo_offset, uint64 length,
+                   uint8 ep_address) -> (zx.status s, ddk.protocol.usb.UsbRequest? req);
+    3: ReqInit(ddk.protocol.usb.UsbRequest? req, handle<vmo> vmo, uint64 vmo_offset, uint64 length,
+               uint8 ep_address) -> (zx.status s);
+    4: ReqCopyFrom(ddk.protocol.usb.UsbRequest? req, usize offset) -> (vector<void> data);
+    5: ReqCopyTo(ddk.protocol.usb.UsbRequest req, vector<void> data, usize offset) -> (isize len);
+    6: ReqMmap(ddk.protocol.usb.UsbRequest? req) -> (zx.status s, vector<void>? data);
+    7: ReqCacheop(ddk.protocol.usb.UsbRequest? req, uint32 op, usize offset, usize length) -> (zx.status s);
+    8: ReqCacheFlush(ddk.protocol.usb.UsbRequest? req, usize offset, usize length) -> (zx.status s);
+    9: ReqCacheFlushInvalidate(ddk.protocol.usb.UsbRequest? req, usize offset, usize length) -> (zx.status s);
+    10: ReqPhysmap(ddk.protocol.usb.UsbRequest? req) -> (zx.status s);
+    11: ReqRelease(ddk.protocol.usb.UsbRequest? req) -> ();
+    12: ReqComplete(ddk.protocol.usb.UsbRequest? req, zx.status status, usize actual) -> ();
+    13: ReqPhysIterInit(ddk.protocol.usb.UsbRequest? req, usize actual, usize max_length)
+            -> (ddk.phys_iter.PhysIter iter);
+    /// Registers the function driver's callback interface.
+    14: RegisterFunc(UsbFunctionInterface intf) -> (zx.status s);
+    /// Allocates a unique interface descriptor number.
+    15: AllocInterface() -> (zx.status s, uint8 intf_num);
+    /// Allocates a unique endpoint descriptor number.
+    /// Direction should be either `USB_DIR_OUT` or `USB_DIR_IN`.
+    16: AllocEp(uint8 direction) -> (zx.status s, uint8 address);
+    /// Configures an endpoint based on the provided usb_endpoint_descriptor_t and
+    /// usb_ss_ep_comp_descriptor_t descriptors.
+    17: ConfigEp(zircon.hw.usb.UsbEndpointDescriptor? ep_desc,
+                 zircon.hw.usb.UsbSsEpCompDescriptor? ss_comp_desc) -> (zx.status s);
+    /// Disables an endpoint. called when the device is no longer configured or an alternate interface
+    /// is selected.
+    18: DisableEp(uint8 ep_addr) -> (zx.status s);
+    /// Adds a string descriptor to the device configuration.
+    19: AllocStringDesc(string @string) -> (zx.status s, uint8 index);
+    /// Helper for queueing a usb request on an endpoint.
+    20: Queue(ddk.protocol.usb.UsbRequest? req) -> ();
+    /// Stalls an endpoint.
+    21: EpSetStall(uint8 ep_address) -> (zx.status s);
+    /// Clears endpoint stall state.
+    22: EpClearStall(uint8 ep_address) -> (zx.status s);
+};
+
diff --git a/system/fidl/ddk/protocols/usb-hci.fidl b/system/fidl/ddk/protocols/usb-hci.fidl
new file mode 100644
index 0000000..6a88dd7
--- /dev/null
+++ b/system/fidl/ddk/protocols/usb-hci.fidl
@@ -0,0 +1,34 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.usb_hci;
+
+using ddk.protocol.usb;
+using ddk.protocol.usb_bus;
+using zircon.hw.usb;
+using zircon.hw.usb_hub;
+using zx;
+
+[Layout="ddk-protocol"]
+interface UsbHci {
+    1: RequestQueue(ddk.protocol.usb.UsbRequest? usb_request) -> ();
+    2: SetBusInterface(ddk.protocol.usb_bus.UsbBusInterface bus_intf) -> ();
+    3: GetMaxDeviceCount() -> (usize count);
+    /// Enables or disables an endpoint using parameters derived from |ep_desc|.
+    4: EnableEndpoint(uint32 device_id, zircon.hw.usb.UsbEndpointDescriptor? ep_desc,
+                      zircon.hw.usb.UsbSsEpCompDescriptor? ss_com_desc, bool enable) -> (zx.status s);
+
+    /// Returns the current frame (in milliseconds), used for isochronous transfers.
+    5: GetCurrentFrame() -> (uint64 frame);
+
+    /// Hub support.
+    6: ConfigureHub(uint32 device_id, zircon.hw.usb.UsbSpeed speed,
+                    zircon.hw.usb_hub.UsbHubDescriptor descriptor) -> (zx.status s);
+    7: HubDeviceAdded(uint32 device_id, int64 port, zircon.hw.usb.UsbSpeed speed) -> (zx.status s);
+    8: HubDeviceRemoved(uint32 device_id, int64 port) -> (zx.status s);
+    9: ResetEndpoint(uint32 device_id, uint8 ep_address) -> (zx.status s);
+    10: GetMaxTransferSize(uint32 device_id, uint8 ep_address) -> (usize size);
+    11: CancelAll(uint32 device_id, uint8 ep_address) -> (usize size);
+    12: GetBti() -> (handle<bti> bti);
+};
diff --git a/system/fidl/ddk/protocols/usb-hub.fidl b/system/fidl/ddk/protocols/usb-hub.fidl
new file mode 100644
index 0000000..4aa43d5
--- /dev/null
+++ b/system/fidl/ddk/protocols/usb-hub.fidl
@@ -0,0 +1,11 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.usb_hub;
+
+/// Interface for use by the usb-bus to talk to the hub driver.
+[Layout="ddk-protocol"]
+interface UsbHub {
+    1: ResetPort(uint32 port) -> ();
+};
diff --git a/system/fidl/ddk/protocols/usb-mode-switch.fidl b/system/fidl/ddk/protocols/usb-mode-switch.fidl
new file mode 100644
index 0000000..8c209c3
--- /dev/null
+++ b/system/fidl/ddk/protocols/usb-mode-switch.fidl
@@ -0,0 +1,15 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.usb_mode_switch;
+
+using ddk.protocol.hidbus;
+using zircon.device.usb_device;
+using zx;
+
+[Layout="ddk-protocol"]
+interface UsbModeSwitch {
+  1: SetMode(zircon.device.usb_device.UsbMode mode) -> (zx.status s,
+                                                        ddk.protocol.hidbus.HidInfo info);
+};
diff --git a/system/fidl/ddk/protocols/usb.fidl b/system/fidl/ddk/protocols/usb.fidl
new file mode 100644
index 0000000..e3106a3
--- /dev/null
+++ b/system/fidl/ddk/protocols/usb.fidl
@@ -0,0 +1,164 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library ddk.protocol.usb;
+
+using ddk.phys_iter;
+using zircon.hw.usb;
+using zircon.hw.usb_hub;
+using zircon.listnode;
+using zx;
+
+//using UsbSpeed = uint8;
+enum UsbSpeed : uint8 {};
+
+[Layout="ddk-callback"]
+interface UsbRequestComplete {
+    1: Callback(UsbRequest? req) -> ();
+};
+
+[Layout="ddk-callback"]
+interface UsbRequestRelease {
+    1: Callback(UsbRequest? req) -> ();
+};
+
+/// Should be set by the requestor.
+struct UsbHeader {
+    /// Frame number for scheduling isochronous transfers.
+    uint64 frame;
+    uint32 device_id;
+    /// bEndpointAddress from endpoint descriptor.
+    uint8 ep_address;
+    /// Number of bytes to transfer.
+    zx.off length;
+    /// Send zero length packet if length is multiple of max packet size.
+    bool send_zlp;
+};
+
+/// Response data.
+/// (Filled in by processor before |UsbRequestComplete()| is called)
+struct UsbResponse {
+    /// Status of transaction.
+    zx.status status;
+    /// Number of bytes actually transferred (on success).
+    zx.off actual;
+};
+
+struct UsbRequest {
+    UsbHeader header;
+
+    /// For control transactions.
+    zircon.hw.usb.UsbSetup setup;
+
+    /// VMO handle for payload.
+    handle<vmo> vmo_handle;
+    handle<bti> bti_handle;
+    usize size;
+    /// Offset of the start of data from first page address of the vmo.
+    zx.off offset;
+    /// Mapped address of the first page of the vmo.
+    /// Add offset to get actual data.
+    vector<void> virt;
+
+    handle pmt;
+    /// Phys addresses of the payload.
+    vector<zx.paddr> phys_list;
+
+    /// The |complete.callback()| callback is set by the requestor and is
+    /// invoked by the 'complete' ops method when it is called by
+    /// the processor upon completion of the usb request.
+    /// The saved_complete_cb field can be used to temporarily save
+    /// the original callback and overwrite it with the desired intermediate
+    /// callback.
+    UsbRequestComplete? complete;
+
+    /// Set by the requestor for opting out of the complete_cb()
+    /// callback for successfully completed requests. The callback
+    /// will still be invoked if an error is encountered.
+    /// This is useful for isochronous requests, where the requestor
+    /// may not care about most callbacks. They will still have to request
+    /// callbacks at a regular interval to queue more data, and free or
+    /// reuse previously silently completed requests.
+    bool cb_on_error_only;
+
+    /// The current 'owner' of the usb request may save the original
+    /// complete callback and cookie, allowing them to insert an
+    /// intermediate callback.
+    UsbRequestComplete? saved_complete;
+
+    UsbResponse response;
+
+    /// list node and context
+    /// the current "owner" of the usb_request may use these however desired
+    /// (eg, the requestor may use node to hold the usb_request on a free list
+    /// and when it's queued the processor may use node to hold the usb_request
+    /// in a transaction queue)
+    zircon.listnode.ListNode node;
+
+    vector<void> context;
+
+    /// The release.callback() callback is set by the allocator and is
+    /// invoked by the 'usb_request_release' method when it is called
+    /// by the requestor.
+    UsbRequestRelease? release;
+};
+
+[Layout="ddk-protocol"]
+interface Usb {
+    1: ReqAlloc(uint64 data_size, uint8 ep_address) -> (zx.status s, UsbRequest? req);
+    2: ReqAllocVmo(handle<vmo> vmo, uint64 vmo_offset, uint64 length,
+                   uint8 ep_address) -> (zx.status s, UsbRequest? req);
+    3: ReqInit(UsbRequest? req, handle<vmo> vmo, uint64 vmo_offset, uint64 length,
+                   uint8 ep_address) -> (zx.status s);
+    4: ReqCopyFrom(UsbRequest? req, usize offset) -> (isize s, vector<void> data);
+    5: ReqCopyTo(UsbRequest? req, vector<void> data, usize offset) -> (isize s);
+    6: ReqMmap(UsbRequest? req) -> (zx.status s, vector<void>? data);
+    7: ReqCacheop(UsbRequest? req, uint32 op, usize offset, usize length) -> (zx.status s);
+    8: ReqCacheFlush(UsbRequest? req, usize offset, usize length) -> (zx.status s);
+    9: ReqCacheFlushInvalidate(UsbRequest? req, zx.off offset, usize length) -> (zx.status s);
+    10: ReqPhysmap(UsbRequest? req) -> (zx.status s);
+    11: ReqRelease(UsbRequest? req) -> ();
+    12: ReqComplete(UsbRequest? req, zx.status status, zx.off actual) -> ();
+    13: ReqPhysIterInit(UsbRequest? req, usize max_length) -> (ddk.phys_iter.PhysIter iter);
+    14: Control(uint8 request_type, uint8 @request, uint16 value, uint16 index,
+                vector<void> data, zx.time timeout) -> (zx.status s, usize length);
+    /// queues a USB request
+    15: RequestQueue(UsbRequest? req) -> ();
+    16: GetSpeed() -> (UsbSpeed s);
+    17: SetInterface(int64 interface_number, int64 alt_setting) -> (zx.status s);
+    18: SetConfiguration(int64 configuration) -> (zx.status s);
+    /// Resets an endpoint that is in a halted or error state.
+    /// Endpoints will be halted if the device returns a STALL in response to a USB transaction.
+    /// When that occurs, the transaction will fail with ERR_IO_REFUSED.
+    /// usb_reset_endpoint() the endpoint to normal running state.
+    19: ResetEndpoint(uint8 ep_address) -> (zx.status s);
+    /// returns the maximum amount of data that can be transferred on an endpoint in a single
+    /// transaction.
+    20: GetMaxTransferSize(uint8 ep_address) -> (usize s);
+    21: GetDeviceId() -> (uint32 dev_id);
+    22: GetDeviceDescriptor() -> (zircon.hw.usb.UsbDeviceDescriptor desc);
+    /// returns the USB descriptors for the USB device or interface
+    /// the returned value is de-allocated with free()
+    23: GetDescriptorList() -> (vector<void>? descriptors);
+    /// returns the USB descriptors following the interface's existing descriptors
+    /// the returned value is de-allocated with free()
+    24: GetAdditionalDescriptorList() -> (vector<void>? descriptors);
+    /// Fetch the descriptor using the provided descriptor ID and language ID.  If
+    /// the language ID requested is not available, the first entry of the language
+    /// ID table will be used instead and be provided in the updated version of the
+    /// parameter.
+    ///
+    /// The string will be encoded using UTF-8, and will be truncated to fit the
+    /// space provided by the buflen parameter.  buflen will be updated to indicate
+    /// the amount of space needed to hold the actual UTF-8 encoded string lenth, and
+    /// may be larger than the original value passed.  Embedded nulls may be present
+    /// in the string, and the result may not be null terminated if the string
+    /// occupies the entire provided buffer.
+    25: GetStringDescriptor(uint8 desc_id, uint16 lang_id) -> (zx.status s, uint16 lang_id,
+                                                               vector<void> buf);
+    /// marks the interface as claimed and appends the interface descriptor to the
+    /// interface's existing descriptor
+    26: ClaimInterface(zircon.hw.usb.UsbInterfaceDescriptor? intf, usize length) -> (zx.status s);
+    27: CancelAll(uint8 ep_address) -> (zx.status s);
+};
diff --git a/system/public/zircon/device/display-controller.h b/system/public/zircon/device/display-controller.h
index edb4653..049d958 100644
--- a/system/public/zircon/device/display-controller.h
+++ b/system/public/zircon/device/display-controller.h
@@ -15,5 +15,5 @@
 IOCTL_WRAPPER_OUT(ioctl_display_controller_get_handle,
                   IOCTL_DISPLAY_CONTROLLER_GET_HANDLE, zx_handle_t);
 
-#define IMAGE_TYPE_SIMPLE 0
+#define IMAGE_TYPE_SIMPLE UINT32_C(0)
 #define INVALID_ID 0
diff --git a/system/ulib/ddk/include/ddk/protocol/acpi.h b/system/ulib/ddk/include/ddk/protocol/acpi.h
index a113c1b..9ab9364 100644
--- a/system/ulib/ddk/include/ddk/protocol/acpi.h
+++ b/system/ulib/ddk/include/ddk/protocol/acpi.h
@@ -1,7 +1,9 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
 #include <zircon/compiler.h>
@@ -9,26 +11,33 @@
 
 __BEGIN_CDECLS;
 
+// Forward declarations
+
+typedef struct acpi_protocol acpi_protocol_t;
+
+// Declarations
+
 typedef struct acpi_protocol_ops {
-    zx_status_t (*map_resource)(void* ctx, uint32_t res_id, uint32_t cache_policy,
-                                void** vaddr, size_t* size, zx_handle_t* out_handle);
-    zx_status_t (*map_interrupt)(void* ctx, int which_irq, zx_handle_t* out_handle);
+    zx_status_t (*map_resource)(void* ctx, uint32_t resource_id, uint32_t cache_policy,
+                                void** out_vaddr_buffer, size_t* vaddr_size,
+                                zx_handle_t* out_handle);
+    zx_status_t (*map_interrupt)(void* ctx, int64_t irq_id, zx_handle_t* out_handle);
 } acpi_protocol_ops_t;
 
-typedef struct acpi_protocol {
+struct acpi_protocol {
     acpi_protocol_ops_t* ops;
     void* ctx;
-} acpi_protocol_t;
+};
 
-static inline zx_status_t acpi_map_resource(acpi_protocol_t* acpi, uint32_t res_id,
-                                           uint32_t cache_policy, void** vaddr, size_t* size,
-                                           zx_handle_t* out_handle) {
-    return acpi->ops->map_resource(acpi->ctx, res_id, cache_policy, vaddr, size, out_handle);
+static inline zx_status_t acpi_map_resource(const acpi_protocol_t* proto, uint32_t resource_id,
+                                            uint32_t cache_policy, void** out_vaddr_buffer,
+                                            size_t* vaddr_size, zx_handle_t* out_handle) {
+    return proto->ops->map_resource(proto->ctx, resource_id, cache_policy, out_vaddr_buffer,
+                                    vaddr_size, out_handle);
 }
-
-static inline zx_status_t acpi_map_interrupt(acpi_protocol_t* acpi, int which_irq,
-                                            zx_handle_t* out_handle) {
-    return acpi->ops->map_interrupt(acpi->ctx, which_irq, out_handle);
+static inline zx_status_t acpi_map_interrupt(const acpi_protocol_t* proto, int64_t irq_id,
+                                             zx_handle_t* out_handle) {
+    return proto->ops->map_interrupt(proto->ctx, irq_id, out_handle);
 }
 
 __END_CDECLS;
diff --git a/system/ulib/ddk/include/ddk/protocol/amlogic-canvas.h b/system/ulib/ddk/include/ddk/protocol/amlogic-canvas.h
index 5c8835b..ed73d59 100644
--- a/system/ulib/ddk/include/ddk/protocol/amlogic-canvas.h
+++ b/system/ulib/ddk/include/ddk/protocol/amlogic-canvas.h
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
 #include <zircon/compiler.h>
@@ -9,37 +11,42 @@
 
 __BEGIN_CDECLS;
 
-typedef struct {
+// Forward declarations
+
+typedef struct canvas_info canvas_info_t;
+typedef struct canvas_protocol canvas_protocol_t;
+
+// Declarations
+
+struct canvas_info {
     uint32_t height;
     uint32_t stride_bytes;
     uint32_t wrap;
     uint32_t blkmode;
     uint32_t endianness;
-} canvas_info_t;
+};
 
-typedef struct {
-    zx_status_t (*config)(void* ctx, zx_handle_t vmo,
-                 size_t offset, canvas_info_t* info,
-                 uint8_t* canvas_idx);
+typedef struct canvas_protocol_ops {
+    zx_status_t (*config)(void* ctx, zx_handle_t vmo, size_t offset, const canvas_info_t* info,
+                          uint8_t* out_canvas_idx);
     zx_status_t (*free)(void* ctx, uint8_t canvas_idx);
 } canvas_protocol_ops_t;
 
-typedef struct {
+struct canvas_protocol {
     canvas_protocol_ops_t* ops;
     void* ctx;
-} canvas_protocol_t;
+};
 
-// Configures a canvas
-// Adds a framebuffer to the canvas lookup table
-static inline zx_status_t canvas_config(canvas_protocol_t* canvas, zx_handle_t vmo,
-                                        size_t offset, canvas_info_t* info,
-                                        uint8_t* canvas_idx) {
-    return canvas->ops->config(canvas->ctx, vmo, offset,
-                               info, canvas_idx);
+// Configures a canvas.
+// Adds a framebuffer to the canvas lookup table.
+static inline zx_status_t canvas_config(const canvas_protocol_t* proto, zx_handle_t vmo,
+                                        size_t offset, const canvas_info_t* info,
+                                        uint8_t* out_canvas_idx) {
+    return proto->ops->config(proto->ctx, vmo, offset, info, out_canvas_idx);
+}
+// Frees up a canvas.
+static inline zx_status_t canvas_free(const canvas_protocol_t* proto, uint8_t canvas_idx) {
+    return proto->ops->free(proto->ctx, canvas_idx);
 }
 
-// Frees up a canvas
-static inline zx_status_t canvas_free(canvas_protocol_t* canvas, uint8_t canvas_idx) {
-    return canvas->ops->free(canvas->ctx, canvas_idx);
-}
 __END_CDECLS;
diff --git a/system/ulib/ddk/include/ddk/protocol/bad-block.h b/system/ulib/ddk/include/ddk/protocol/bad-block.h
index e68298d..46e3655 100644
--- a/system/ulib/ddk/include/ddk/protocol/bad-block.h
+++ b/system/ulib/ddk/include/ddk/protocol/bad-block.h
@@ -2,39 +2,48 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
-#include <assert.h>
-#include <stdint.h>
-
+#include <zircon/compiler.h>
 #include <zircon/types.h>
 
+__BEGIN_CDECLS;
+
+// Forward declarations
+
+typedef struct bad_block_protocol bad_block_protocol_t;
+
+// Declarations
+
 typedef struct bad_block_protocol_ops {
-    // Fills in |bad_block_list| with a list of bad blocks, up until
-    // |bad_block_list_len|. The order of blocks is undefined.
-    // |bad_block_count| will be filled in with the actual number of bad
-    // blocks. It is recommended to first make call with |bad_block_list_len|
-    // equal to 0 in order to determine how large the |bad_block_list| is.
-    zx_status_t (*get_bad_block_list)(void* ctx, uint32_t* bad_block_list,
-                                      uint32_t bad_block_list_len, uint32_t* bad_block_count);
-
-    // Sets |block| as bad. If block is already marked bad, it has no effect.
+    zx_status_t (*get_bad_block_list)(void* ctx, uint32_t* out_bad_blocks_list,
+                                      size_t bad_blocks_count, size_t* out_bad_blocks_actual);
     zx_status_t (*mark_block_bad)(void* ctx, uint32_t block);
-
 } bad_block_protocol_ops_t;
 
-typedef struct bad_block_protocol {
+struct bad_block_protocol {
     bad_block_protocol_ops_t* ops;
     void* ctx;
-} bad_block_protocol_t;
+};
 
-static inline zx_status_t bad_block_get_bad_block_list(
-    bad_block_protocol_t* proto, uint32_t* bad_block_list, uint32_t bad_block_list_len,
-    uint32_t* bad_block_count) {
-    return proto->ops->get_bad_block_list(proto->ctx, bad_block_list, bad_block_list_len,
-                                          bad_block_count);
+// Fills in |bad_blocks| with a list of bad blocks, up until
+// |bad_blocks_count|. The order of blocks is undefined.
+// |bad_blocks_actual| will be filled in with the actual number of bad
+// blocks. It is recommended to first make call with |bad_blocks_count|
+// equal to 0 in order to determine how large the |bad_blocks| is.
+static inline zx_status_t bad_block_get_bad_block_list(const bad_block_protocol_t* proto,
+                                                       uint32_t* out_bad_blocks_list,
+                                                       size_t bad_blocks_count,
+                                                       size_t* out_bad_blocks_actual) {
+    return proto->ops->get_bad_block_list(proto->ctx, out_bad_blocks_list, bad_blocks_count,
+                                          out_bad_blocks_actual);
 }
-
-static inline zx_status_t bad_block_mark_block_bad(bad_block_protocol_t* proto, uint32_t block) {
+// Sets |block| as bad. If block is already marked bad, it has no effect.
+static inline zx_status_t bad_block_mark_block_bad(const bad_block_protocol_t* proto,
+                                                   uint32_t block) {
     return proto->ops->mark_block_bad(proto->ctx, block);
 }
+
+__END_CDECLS;
diff --git a/system/ulib/ddk/include/ddk/protocol/bt-hci.h b/system/ulib/ddk/include/ddk/protocol/bt-hci.h
index dd386d2..a8902ec 100644
--- a/system/ulib/ddk/include/ddk/protocol/bt-hci.h
+++ b/system/ulib/ddk/include/ddk/protocol/bt-hci.h
@@ -1,7 +1,9 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
 #include <zircon/compiler.h>
@@ -9,44 +11,46 @@
 
 __BEGIN_CDECLS;
 
-typedef struct {
-    // Open the two-way HCI command channel for sending HCI commands and
-    // receiving event packets.  Returns ZX_ERR_ALREADY_BOUND if the channel
-    // is already open.
+// Forward declarations
+
+typedef struct bt_hci_protocol bt_hci_protocol_t;
+
+// Declarations
+
+typedef struct bt_hci_protocol_ops {
     zx_status_t (*open_command_channel)(void* ctx, zx_handle_t* out_channel);
-
-    // Open the two-way HCI ACL data channel.
-    // Returns ZX_ERR_ALREADY_BOUND if the channel is already open.
     zx_status_t (*open_acl_data_channel)(void* ctx, zx_handle_t* out_channel);
-
-    // Open an output-only channel for monitoring HCI traffic.
-    // The format of each message is: [1-octet flags] [n-octet payload]
-    // The flags octet is a bitfield with the following values defined:
-    //  - 0x00: The payload represents a command packet sent from the host to the
-    //          controller.
-    //  - 0x01: The payload represents an event packet sent by the controller.
-    // Returns ZX_ERR_ALREADY_BOUND if the channel is already open.
     zx_status_t (*open_snoop_channel)(void* ctx, zx_handle_t* out_channel);
 } bt_hci_protocol_ops_t;
 
-typedef struct {
+struct bt_hci_protocol {
     bt_hci_protocol_ops_t* ops;
     void* ctx;
-} bt_hci_protocol_t;
+};
 
-static inline zx_status_t bt_hci_open_command_channel(bt_hci_protocol_t* bt_hci,
+// Open the two-way HCI command channel for sending HCI commands and
+// receiving event packets.  Returns ZX_ERR_ALREADY_BOUND if the channel
+// is already open.
+static inline zx_status_t bt_hci_open_command_channel(const bt_hci_protocol_t* proto,
                                                       zx_handle_t* out_channel) {
-    return bt_hci->ops->open_command_channel(bt_hci->ctx, out_channel);
+    return proto->ops->open_command_channel(proto->ctx, out_channel);
 }
-
-static inline zx_status_t bt_hci_open_acl_data_channel(bt_hci_protocol_t* bt_hci,
+// Open the two-way HCI ACL data channel.
+// Returns ZX_ERR_ALREADY_BOUND if the channel is already open.
+static inline zx_status_t bt_hci_open_acl_data_channel(const bt_hci_protocol_t* proto,
                                                        zx_handle_t* out_channel) {
-    return bt_hci->ops->open_acl_data_channel(bt_hci->ctx, out_channel);
+    return proto->ops->open_acl_data_channel(proto->ctx, out_channel);
 }
-
-static inline zx_status_t bt_hci_open_snoop_channel(bt_hci_protocol_t* bt_hci,
+// Open an output-only channel for monitoring HCI traffic.
+// The format of each message is: [1-octet flags] [n-octet payload]
+// The flags octet is a bitfield with the following values defined:
+//  - 0x00: The payload represents a command packet sent from the host to the
+//          controller.
+//  - 0x01: The payload represents an event packet sent by the controller.
+// Returns ZX_ERR_ALREADY_BOUND if the channel is already open.
+static inline zx_status_t bt_hci_open_snoop_channel(const bt_hci_protocol_t* proto,
                                                     zx_handle_t* out_channel) {
-    return bt_hci->ops->open_snoop_channel(bt_hci->ctx, out_channel);
+    return proto->ops->open_snoop_channel(proto->ctx, out_channel);
 }
 
 __END_CDECLS;
diff --git a/system/ulib/ddk/include/ddk/protocol/clk.h b/system/ulib/ddk/include/ddk/protocol/clk.h
index 195442f..9e40e8f 100644
--- a/system/ulib/ddk/include/ddk/protocol/clk.h
+++ b/system/ulib/ddk/include/ddk/protocol/clk.h
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
 #include <zircon/compiler.h>
@@ -9,22 +11,27 @@
 
 __BEGIN_CDECLS;
 
+// Forward declarations
+
+typedef struct clk_protocol clk_protocol_t;
+
+// Declarations
+
 typedef struct clk_protocol_ops {
     zx_status_t (*enable)(void* ctx, uint32_t index);
     zx_status_t (*disable)(void* ctx, uint32_t index);
 } clk_protocol_ops_t;
 
-typedef struct {
+struct clk_protocol {
     clk_protocol_ops_t* ops;
     void* ctx;
-} clk_protocol_t;
+};
 
-static inline zx_status_t clk_enable(clk_protocol_t * clk, const uint32_t index) {
-    return clk->ops->enable(clk->ctx, index);
+static inline zx_status_t clk_enable(const clk_protocol_t* proto, uint32_t index) {
+    return proto->ops->enable(proto->ctx, index);
+}
+static inline zx_status_t clk_disable(const clk_protocol_t* proto, uint32_t index) {
+    return proto->ops->disable(proto->ctx, index);
 }
 
-static inline zx_status_t clk_disable(clk_protocol_t * clk, const uint32_t index) {
-    return clk->ops->disable(clk->ctx, index);
-}
-
-__END_CDECLS;
\ No newline at end of file
+__END_CDECLS;
diff --git a/system/ulib/ddk/include/ddk/protocol/display-controller.h b/system/ulib/ddk/include/ddk/protocol/display-controller.h
index 5e9b4a9..aa81069 100644
--- a/system/ulib/ddk/include/ddk/protocol/display-controller.h
+++ b/system/ulib/ddk/include/ddk/protocol/display-controller.h
@@ -2,234 +2,126 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
 #include <zircon/compiler.h>
 #include <zircon/device/audio.h>
 #include <zircon/types.h>
-#include <zircon/pixelformat.h>
 
 __BEGIN_CDECLS;
 
-/**
- * protocol/display-controller.h - display controller protocol definitions
- */
+// Forward declarations
 
-// The image is linear and VMO backed.
-#define IMAGE_TYPE_SIMPLE 0
+typedef struct image_plane image_plane_t;
+typedef uint32_t client_t;
+// The client should convert the corresponding layer to a primary layer.
+#define CLIENT_USE_PRIMARY UINT32_C(1)
+// The client should compose all layers with MERGE_BASE and MERGE_SRC into a new,
+// single primary layer at the MERGE_BASE layer's z-order. The driver must accept
+// a fullscreen layer with the default pixel format, but may accept other layer
+// parameters.
+// MERGE_BASE should only be set on one layer per display. If it is set on multiple
+// layers, the client will arbitrarily pick one and change the rest to MERGE_SRC.
+#define CLIENT_MERGE_BASE UINT32_C(2)
+#define CLIENT_MERGE_SRC UINT32_C(4)
+// The client should pre-scale the image so that src_frame's dimensions are equal
+// to dest_frame's dimensions.
+#define CLIENT_FRAME_SCALE UINT32_C(8)
+// The client should pre-clip the image so that src_frame's dimensions are equal to
+// the image's dimensions.
+#define CLIENT_SRC_FRAME UINT32_C(16)
+// The client should pre-apply the transformation so TRANSFORM_IDENTITY can be used.
+#define CLIENT_TRANSFORM UINT32_C(32)
+// The client should apply the color conversion.
+#define CLIENT_COLOR_CONVERSION UINT32_C(64)
+// The client should apply the alpha transformation itself.
+#define CLIENT_ALPHA UINT32_C(128)
 
-// a structure containing information about each plane of an image.
-typedef struct image_plane {
-    uint32_t byte_offset;
-    uint32_t bytes_per_row;
-} image_plane_t;
+typedef uint32_t config_display_t;
+// The display mode configuration is valid. Note that this is distinct from
+// whether or not the layer configuration is valid.
+#define CONFIG_DISPLAY_OK UINT32_C(0)
+// Error indicating that the hardware cannot simultaniously support the
+// requested number of displays.
+#define CONFIG_DISPLAY_TOO_MANY UINT32_C(1)
+// Error indicating that the hardware cannot simultaniously support the given
+// set of display modes. To support a mode, the display must be able to display
+// a single layer with width and height equal to the requested mode and the
+// preferred pixel format.
+#define CONFIG_DISPLAY_UNSUPPORTED_MODES UINT32_C(2)
 
-// a structure containing information about an image
-typedef struct image {
-    // the width and height of the image in pixels
-    uint32_t width;
-    uint32_t height;
-
-    // the pixel format of the image
-    zx_pixel_format_t pixel_format;
-
-    // The type conveys information about what is providing the pixel data. If this is not
-    // IMAGE_FORMAT_SIMPLE, it is up to the driver and buffer producer to agree on the meaning
-    // of the value through some mechanism outside the scope of this API.
-    uint32_t type;
-
-    image_plane_t planes[4];
-
-    // A driver-defined handle to the image. Each handle must be unique.
-    void* handle;
-} image_t;
-
-#define INVALID_DISPLAY_ID 0
-
-// a fallback structure to convey display information without an edid
-typedef struct display_params {
-    uint32_t width;
-    uint32_t height;
-    uint32_t refresh_rate_e2;
-} display_params_t;
-
-// Info about valid cursor configuratoins.
-typedef struct cursor_info {
-    // The width and height of the cursor configuration, in pixels.
-    uint32_t width;
-    uint32_t height;
-    zx_pixel_format_t format;
-} cursor_info_t;
-
-// a structure containing information a connected display
-typedef struct added_display_args {
-    uint64_t display_id;
-
-    // A flag indicating whether or not the display has a valid edid.
-    //
-    // If true, the device should expose an ZX_PROTOCOL_I2C_IMPL device through get_protocol, in
-    // addition to the ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL protocol. Note that the i2c device
-    // will be called from the on_displays_changed callback, so care should be taken to avoid
-    // deadlocks or double-locking.
-    //
-    // If no edid is present, then the meaning of display_config's mode structure is
-    // undefined, and drivers should ignore it in check_configuration and apply_configuration.
-    bool edid_present;
-    union {
-        // the bus_id to use to read this display's edid from the device's i2c protocol
-        uint32_t i2c_bus_id;
-        // the display's parameters if an edid is not present
-        display_params_t params;
-    } panel;
-
-    // A list of pixel formats supported by the display. The first entry is the
-    // preferred pixel format.
-    const zx_pixel_format_t* pixel_formats;
-    uint32_t pixel_format_count;
-
-    // A list of cursor configurations most likely to be accepted by the driver. Can
-    // be null if cursor_count is 0.
-    //
-    // The driver may reject some of these configurations in some circumstances, and
-    // it may accept other configurations, but at least one of these configurations
-    // should be valid at most times.
-    const cursor_info_t* cursor_infos;
-    uint32_t cursor_info_count;
-
-    // Out parameters will be populated before on_displays_changed returns.
-    bool is_hdmi_out;
-    bool is_standard_srgb_out;
-
-    uint32_t audio_format_count;
-
-    const char* manufacturer_name;
-    char monitor_name[14]; // null-terminated
-    char monitor_serial[14]; // null-terminated
-} added_display_args_t;
-
-// The client will not make any ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL calls into the device
-// during these callbacks.
-typedef struct display_controller_cb {
-    // Callbacks which are invoked when displays are added or removed. |displays_added| and
-    // |displays_removed| point to arrays of the display ids which were added and removed. If
-    // |added_count| or |removed_count| is 0, the corresponding array can be NULL.
-    //
-    // The driver must be done accessing any images which were on the removed displays.
-    //
-    // The driver should call this function when the callback is registered if any displays
-    // are present.
-    void (*on_displays_changed)(void* ctx,
-                                added_display_args_t* added_displays, uint32_t added_count,
-                                uint64_t* removed_displays, uint32_t removed_count);
-
-    // |timestamp| is the ZX_CLOCK_MONOTONIC timestamp at which the vsync occurred.
-    // |handles| points to an array of image handles of each framebuffer being
-    // displayed, in increasing z-order.
-    void (*on_display_vsync)(void* ctx, uint64_t display_id, zx_time_t timestamp,
-                             void** handles, uint32_t handle_count);
-
-    zx_status_t (*get_audio_format)(void* ctx, uint64_t display_id, uint32_t fmt_idx,
-                                    audio_stream_format_range_t* fmt_out);
-} display_controller_cb_t;
-
-#define ALPHA_DISABLE 0
-#define ALPHA_PREMULTIPLIED 1
-#define ALPHA_HW_MULTIPLY 2
-
-// Rotations are applied counter-clockwise, and are applied before reflections.
-#define FRAME_TRANSFORM_IDENTITY 0
-#define FRAME_TRANSFORM_REFLECT_X 1
-#define FRAME_TRANSFORM_REFLECT_Y 2
-#define FRAME_TRANSFORM_ROT_90 3
-#define FRAME_TRANSFORM_ROT_180 4
-#define FRAME_TRANSFORM_ROT_270 5
-#define FRAME_TRANSFORM_ROT_90_REFLECT_X 6
-#define FRAME_TRANSFORM_ROT_90_REFLECT_Y 7
-
-typedef struct frame {
-    // (x_pos, y_pos) specifies the position of the upper-left corner
-    // of the frame.
-    uint32_t x_pos;
-    uint32_t y_pos;
-    uint32_t width;
-    uint32_t height;
-} frame_t;
-
-typedef struct primary_layer {
-    image_t image;
-
-    // An ALPHA_* constant.
-    //
-    // If alpha_mode == ALPHA_DISABLED, the layer is opaque and alpha_layer_val is ignored.
-    //
-    // If alpha_mode == PREMULTIPLIED or HW_MULTIPLY and alpha_layer_val is NaN, the alpha
-    // used when blending is determined by the per-pixel alpha channel.
-    //
-    // If alpha_mode == PREMULTIPLIED or HW_MULTIPLY and alpha_layer_val is not NaN, the
-    // alpha used when blending is the product of alpha_layer_val and any per-pixel alpha.
-    // Additionally, if alpha_mode == PREMULTIPLIED, then the hardware must premultiply the color
-    // channel with alpha_layer_val before blending.
-    //
-    // If alpha_layer_val is not NaN, it will be in the range [0, 1].
-    uint32_t alpha_mode;
-    float alpha_layer_val;
-
-    uint32_t transform_mode;
-
-    // The source frame, where (0,0) is the top-left corner of the image. The
-    // client guarantees that src_frame lies entirely within the image.
-    frame_t src_frame;
-
-    // The destination frame, where (0,0) is the top-left corner of the
-    // composed output. The client guarantees that dest_frame lies entirely
-    // within the composed output.
-    frame_t dest_frame;
-} primary_layer_t;
-
-typedef struct cursor_layer {
-    image_t image;
-
-    // The position of the top-left corner of the cursor's image. When being
-    // applied to a display, the cursor is guaranteed to have at least one
-    // pixel of overlap with the display.
-    int32_t x_pos;
-    int32_t y_pos;
-} cursor_layer_t;
-
-typedef struct color_layer {
-    zx_pixel_format_t format;
-    // The color to use for the layer. The color is little-endian, and is
-    // guaranteed to be of the appropriate size.
-    uint8_t* color;
-} color_layer_t;
-
-// Types of layers.
-
-#define LAYER_PRIMARY 0
-#define LAYER_CURSOR 1
-#define LAYER_COLOR 2
-
-typedef struct layer {
-    // One of the LAYER_* flags.
-    uint32_t type;
-    // z_index of the layer. See |check_configuration| and |apply_configuration|.
-    uint32_t z_index;
-    union {
-        primary_layer_t primary;
-        cursor_layer_t cursor;
-        color_layer_t color;
-    } cfg;
-} layer_t;
+typedef uint32_t color_conversion_t;
+// If set, use the 0 vector for the color conversion preoffset
+#define COLOR_CONVERSION_PREOFFSET UINT32_C(1)
+// If set, use the identity matrix for the color conversion coefficients
+#define COLOR_CONVERSION_COEFFICIENTS UINT32_C(2)
+// If set, use the 0 vector for the color conversion postoffset
+#define COLOR_CONVERSION_POSTOFFSET UINT32_C(4)
 
 // constants for display_config's mode_flags field
-#define MODE_FLAG_VSYNC_POSITIVE (1 << 0)
-#define MODE_FLAG_HSYNC_POSITIVE (1 << 1)
-#define MODE_FLAG_INTERLACED (1 << 2)
-#define MODE_FLAG_ALTERNATING_VBLANK (1 << 3)
-#define MODE_FLAG_DOUBLE_CLOCKED (1 << 4)
+typedef uint32_t mode_flag_t;
+#define MODE_FLAG_VSYNC_POSITIVE UINT32_C(1)
+#define MODE_FLAG_HSYNC_POSITIVE UINT32_C(2)
+#define MODE_FLAG_INTERLACED UINT32_C(4)
+#define MODE_FLAG_ALTERNATING_VBLANK UINT32_C(8)
+#define MODE_FLAG_DOUBLE_CLOCKED UINT32_C(16)
+
+typedef struct display_mode display_mode_t;
+typedef struct display_config display_config_t;
+// Types of layers.
+typedef uint32_t layer_type_t;
+#define LAYER_TYPE_PRIMARY UINT32_C(0)
+#define LAYER_TYPE_CURSOR UINT32_C(1)
+#define LAYER_TYPE_COLOR UINT32_C(2)
+
+// Rotations are applied counter-clockwise, and are applied before reflections.
+typedef uint32_t frame_transform_t;
+#define FRAME_TRANSFORM_IDENTITY UINT32_C(0)
+#define FRAME_TRANSFORM_REFLECT_X UINT32_C(1)
+#define FRAME_TRANSFORM_REFLECT_Y UINT32_C(2)
+#define FRAME_TRANSFORM_ROT_90 UINT32_C(3)
+#define FRAME_TRANSFORM_ROT_180 UINT32_C(4)
+#define FRAME_TRANSFORM_ROT_270 UINT32_C(5)
+#define FRAME_TRANSFORM_ROT_90_REFLECT_X UINT32_C(6)
+#define FRAME_TRANSFORM_ROT_90_REFLECT_Y UINT32_C(7)
+
+typedef struct frame frame_t;
+typedef struct added_display_info added_display_info_t;
+typedef uint32_t zx_pixel_format_t;
+
+typedef struct cursor_info cursor_info_t;
+typedef struct color_layer color_layer_t;
+typedef struct image image_t;
+typedef struct cursor_layer cursor_layer_t;
+typedef uint8_t alpha_t;
+#define ALPHA_DISABLE UINT8_C(0)
+#define ALPHA_PREMULTIPLIED UINT8_C(1)
+#define ALPHA_HW_MULTIPLY UINT8_C(2)
+
+typedef struct primary_layer primary_layer_t;
+typedef union layer_config layer_config_t;
+typedef struct layer layer_t;
+typedef struct display_params display_params_t;
+typedef union panel panel_t;
+typedef struct added_display_args added_display_args_t;
+typedef struct display_controller_interface display_controller_interface_t;
+typedef struct display_controller_protocol display_controller_protocol_t;
+
+// Declarations
+
+// The image is linear and VMO backed.
+#define IMAGE_TYPE_SIMPLE UINT32_C(0)
+
+// A structure containing information about each plane of an image.
+struct image_plane {
+    uint32_t byte_offset;
+    uint32_t bytes_per_row;
+};
 
 // The video parameters which specify the display mode.
-typedef struct display_mode {
+struct display_mode {
     uint32_t pixel_clock_10khz;
     uint32_t h_addressable;
     uint32_t h_front_porch;
@@ -239,146 +131,312 @@
     uint32_t v_front_porch;
     uint32_t v_sync_pulse;
     uint32_t v_blanking;
-    uint32_t flags; // A bitmask of MODE_FLAG_* values
-} display_mode_t;
+    // A bitmask of MODE_FLAG_* values
+    uint32_t flags;
+};
 
-// If set, use the 0 vector for the color conversion preoffset
-#define COLOR_CONVERSION_PREOFFSET (1 << 0)
-// If set, use the identity matrix for the color conversion coefficients
-#define COLOR_CONVERSION_COEFFICIENTS (1 << 1)
-// If set, use the 0 vector for the color conversion postoffset
-#define COLOR_CONVERSION_POSTOFFSET (1 << 2)
-
-typedef struct display_config {
+struct display_config {
     // the display id to which the configuration applies
     uint64_t display_id;
-
     display_mode_t mode;
-
     // Bitmask of COLOR_CONVERSION_* flags
     uint32_t cc_flags;
     // Color conversion is applied to each pixel according to the formula:
-    //
     // (cc_coefficients * (pixel + cc_preoffsets)) + cc_postoffsets
-    //
     // where pixel is a column vector consiting of the pixel's 3 components.
     float cc_preoffsets[3];
     float cc_coefficients[3][3];
     float cc_postoffsets[3];
+    layer_t** layer_list;
+    size_t layer_count;
+};
 
-    uint32_t layer_count;
-    layer_t** layers;
-} display_config_t;
+struct frame {
+    // (|x_pos|, |y_pos|) specifies the position of the upper-left corner
+    // of the frame.
+    uint32_t x_pos;
+    uint32_t y_pos;
+    uint32_t width;
+    uint32_t height;
+};
 
-// The display mode configuration is valid. Note that this is distinct from
-// whether or not the layer configuration is valid.
-#define CONFIG_DISPLAY_OK 0
-// Error indicating that the hardware cannot simultaniously support the
-// requested number of displays.
-#define CONFIG_DISPLAY_TOO_MANY 1
-// Error indicating that the hardware cannot simultaniously support the given
-// set of display modes. To support a mode, the display must be able to display
-// a single layer with width and height equal to the requested mode and the
-// preferred pixel format.
-#define CONFIG_DISPLAY_UNSUPPORTED_MODES 2
+// Out parameters will be populated before on_displays_changed returns.
+struct added_display_info {
+    bool is_hdmi_out;
+    bool is_standard_srgb_out;
+    uint32_t audio_format_count;
+    const char* manufacturer_name;
+    // null-terminated
+    char monitor_name[14];
+    // null-terminated
+    char monitor_serial[14];
+};
 
-// The client should convert the corresponding layer to a primary layer.
-#define CLIENT_USE_PRIMARY (1 << 0)
-// The client should compose all layers with MERGE_BASE and MERGE_SRC into a new,
-// single primary layer at the MERGE_BASE layer's z-order. The driver must accept
-// a fullscreen layer with the default pixel format, but may accept other layer
-// parameters.
-//
-// MERGE_BASE should only be set on one layer per display. If it is set on multiple
-// layers, the client will arbitrarily pick one and change the rest to MERGE_SRC.
-#define CLIENT_MERGE_BASE (1 << 1)
-#define CLIENT_MERGE_SRC (1 << 2)
-// The client should pre-scale the image so that src_frame's dimensions are equal
-// to dest_frame's dimensions.
-#define CLIENT_FRAME_SCALE (1 << 3)
-// The client should pre-clip the image so that src_frame's dimensions are equal to
-// the image's dimensions.
-#define CLIENT_SRC_FRAME (1 << 4)
-// The client should pre-apply the transformation so TRANSFORM_IDENTITY can be used.
-#define CLIENT_TRANSFORM (1 << 5)
-// The client should apply the color conversion.
-#define CLIENT_COLOR_CONVERSION (1 << 6)
-// The client should apply the alpha transformation itself.
-#define CLIENT_ALPHA (1 << 7)
+// Info about valid cursor configuratoins.
+struct cursor_info {
+    // The width and height of the cursor configuration, in pixels.
+    uint32_t width;
+    uint32_t height;
+    zx_pixel_format_t format;
+};
+
+struct color_layer {
+    zx_pixel_format_t format;
+    // The color to use for the layer. The color is little-endian, and is
+    // guaranteed to be of the appropriate size.
+    uint8_t* color_list;
+    size_t color_count;
+};
+
+// A structure containing information about an image.
+struct image {
+    // The width and height of the image in pixels.
+    uint32_t width;
+    uint32_t height;
+    // The pixel format of the image.
+    zx_pixel_format_t pixel_format;
+    // The type conveys information about what is providing the pixel data. If this is not
+    // IMAGE_FORMAT_SIMPLE, it is up to the driver and buffer producer to agree on the meaning
+    // of the value through some mechanism outside the scope of this API.
+    uint32_t type;
+    image_plane_t planes[4];
+    // A driver-defined handle to the image. Each handle must be unique.
+    uint64_t handle;
+};
+
+struct cursor_layer {
+    image_t image;
+    // The position of the top-left corner of the cursor's image. When being
+    // applied to a display, the cursor is guaranteed to have at least one
+    // pixel of overlap with the display.
+    zx_status_t x_pos;
+    zx_status_t y_pos;
+};
+
+#define INVALID_DISPLAY_ID UINT32_C(0)
+
+struct primary_layer {
+    image_t image;
+    // An ALPHA_* constant.
+    // If |alpha_mode| == `ALPHA_DISABLED`, the layer is opaque and alpha_layer_val is ignored.
+    // If |alpha_mode| == `PREMULTIPLIED` or `HW_MULTIPLY` and |alpha_layer_val| is NaN, the alpha
+    // used when blending is determined by the per-pixel alpha channel.
+    // If |alpha_mode| == `PREMULTIPLIED` or `HW_MULTIPLY` and |alpha_layer_val| is not NaN, the
+    // alpha used when blending is the product of alpha_layer_val and any per-pixel alpha.
+    // Additionally, if alpha_mode == PREMULTIPLIED, then the hardware must premultiply the color
+    // channel with alpha_layer_val before blending.
+    // If alpha_layer_val is not NaN, it will be in the range [0, 1].
+    alpha_t alpha_mode;
+    float alpha_layer_val;
+    frame_transform_t transform_mode;
+    // The source frame, where (0,0) is the top-left corner of the image. The
+    // client guarantees that src_frame lies entirely within the image.
+    frame_t src_frame;
+    // The destination frame, where (0,0) is the top-left corner of the
+    // composed output. The client guarantees that dest_frame lies entirely
+    // within the composed output.
+    frame_t dest_frame;
+};
+
+union layer_config {
+    primary_layer_t primary;
+    cursor_layer_t cursor;
+    color_layer_t color;
+};
+
+struct layer {
+    layer_type_t type;
+    // z_index of the layer. See |check_configuration| and |apply_configuration|.
+    uint32_t z_index;
+    layer_config_t cfg;
+};
+
+// A fallback structure to convey display information without an edid.
+struct display_params {
+    uint32_t width;
+    uint32_t height;
+    uint32_t refresh_rate_e2;
+};
+
+union panel {
+    // The bus_id to use to read this display's edid from the device's i2c protocol.
+    uint32_t i2c_bus_id;
+    // The display's parameters if an edid is not present.
+    display_params_t params;
+};
+
+// A structure containing information a connected display.
+struct added_display_args {
+    uint64_t display_id;
+    // A flag indicating whether or not the display has a valid edid.
+    // If true, the device should expose an ZX_PROTOCOL_I2C_IMPL device through get_protocol, in
+    // addition to the ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL protocol. Note that the i2c device
+    // will be called from the on_displays_changed callback, so care should be taken to avoid
+    // deadlocks or double-locking.
+    // If no edid is present, then the meaning of display_config's mode structure is
+    // undefined, and drivers should ignore it in check_configuration and apply_configuration.
+    bool edid_present;
+    panel_t panel;
+    // A list of pixel formats supported by the display. The first entry is the
+    // preferred pixel format.
+    zx_pixel_format_t* pixel_format_list;
+    size_t pixel_format_count;
+    // A list of cursor configurations most likely to be accepted by the driver. Can
+    // be null if cursor_count is 0.
+    // The driver may reject some of these configurations in some circumstances, and
+    // it may accept other configurations, but at least one of these configurations
+    // should be valid at most times.
+    cursor_info_t* cursor_info_list;
+    size_t cursor_info_count;
+};
+
+typedef struct display_controller_interface_ops {
+    void (*on_displays_changed)(void* ctx, const added_display_args_t* added_display_list,
+                                size_t added_display_count, const uint64_t* removed_display_list,
+                                size_t removed_display_count,
+                                added_display_info_t* out_display_info_list,
+                                size_t display_info_count, size_t* out_display_info_actual);
+    void (*on_display_vsync)(void* ctx, uint64_t display_id, int64_t timestamp,
+                             const uint64_t* handle_list, size_t handle_count);
+    zx_status_t (*get_audio_format)(void* ctx, uint64_t display_id, uint32_t fmt_idx,
+                                    audio_stream_format_range_t* out_fmt);
+} display_controller_interface_ops_t;
+
+// The client will not make any `ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL` calls into the device
+// during these callbacks.
+struct display_controller_interface {
+    display_controller_interface_ops_t* ops;
+    void* ctx;
+};
+
+// Callbacks which are invoked when displays are added or removed. |added_display_list| and
+// |removed_display_list| point to arrays of the display ids which were added and removed. If
+// |added_display_count| or |removed_display_count| is 0, the corresponding array can be NULL.
+// The driver must be done accessing any images which were on the removed displays.
+// The driver should call this function when the callback is registered if any displays
+// are present.
+static inline void display_controller_interface_on_displays_changed(
+    const display_controller_interface_t* proto, const added_display_args_t* added_display_list,
+    size_t added_display_count, const uint64_t* removed_display_list, size_t removed_display_count,
+    added_display_info_t* out_display_info_list, size_t display_info_count,
+    size_t* out_display_info_actual) {
+    proto->ops->on_displays_changed(
+        proto->ctx, added_display_list, added_display_count, removed_display_list,
+        removed_display_count, out_display_info_list, display_info_count, out_display_info_actual);
+}
+// |timestamp| is the ZX_CLOCK_MONOTONIC timestamp at which the vsync occurred.
+// |handles| points to an array of image handles of each framebuffer being
+// displayed, in increasing z-order.
+static inline void
+display_controller_interface_on_display_vsync(const display_controller_interface_t* proto,
+                                              uint64_t display_id, int64_t timestamp,
+                                              const uint64_t* handle_list, size_t handle_count) {
+    proto->ops->on_display_vsync(proto->ctx, display_id, timestamp, handle_list, handle_count);
+}
+static inline zx_status_t
+display_controller_interface_get_audio_format(const display_controller_interface_t* proto,
+                                              uint64_t display_id, uint32_t fmt_idx,
+                                              audio_stream_format_range_t* out_fmt) {
+    return proto->ops->get_audio_format(proto->ctx, display_id, fmt_idx, out_fmt);
+}
+
+typedef struct display_controller_protocol_ops {
+    void (*set_display_controller_interface)(void* ctx, const display_controller_interface_t* intf);
+    zx_status_t (*import_vmo_image)(void* ctx, image_t* image, zx_handle_t vmo, size_t offset);
+    void (*release_image)(void* ctx, image_t* image);
+    uint32_t (*check_configuration)(void* ctx, const display_config_t** display_config_list,
+                                    size_t display_config_count,
+                                    uint32_t** out_layer_cfg_result_list,
+                                    size_t* layer_cfg_result_count);
+    void (*apply_configuration)(void* ctx, const display_config_t** display_config_list,
+                                size_t display_config_count);
+    uint32_t (*compute_linear_stride)(void* ctx, uint32_t width, zx_pixel_format_t pixel_format);
+    zx_status_t (*allocate_vmo)(void* ctx, uint64_t size, zx_handle_t* out_vmo);
+} display_controller_protocol_ops_t;
 
 // The client guarantees that check_configuration and apply_configuration are always
 // made from a single thread. The client makes no other threading guarantees.
-typedef struct display_controller_protocol_ops {
-    // The function will only be called once, and it will be called before any other
-    // functions are called.
-    void (*set_display_controller_cb)(void* ctx, void* cb_ctx, display_controller_cb_t* cb);
-
-    // Imports a VMO backed image into the driver. The driver should set image->handle. The
-    // driver does not own the vmo handle passed to this function.
-    zx_status_t (*import_vmo_image)(void* ctx, image_t* image,
-                                    zx_handle_t vmo, size_t offset);
-
-    // Releases any driver state associated with the given image. The client guarantees that
-    // any images passed to apply_config will not be released until a vsync occurs with a
-    // more recent image.
-    void (*release_image)(void* ctx, image_t* image);
-
-    // Validates the given configuration.
-    //
-    // The configuration may not include all displays. Omiteed displays should be treated as
-    // whichever of off or displaying a blank screen results in a more premissive validation.
-    //
-    // All displays in a configuration will have at least one layer. The layers will be
-    // arranged in increasing z-order, and their z_index fields will be set consecutively.
-    //
-    // Whether or not the driver can accept the configuration cannot depend on the
-    // particular image handles, as it must always be possible to present a new image in
-    // place of another image with a matching configuration. It also cannot depend on the
-    // cursor position, as that can be updated without another call to check_configuration.
-    //
-    // display_cfg_result should be set to a CONFIG_DISPLAY_* error if the combination of
-    // display modes is not supported.
-    //
-    // layer_cfg_result points to an array of arrays. The primary length is display_count, the
-    // secondary lengths are the corresponding display_cfg's layer_count. If display_cfg_result
-    // is CONFIG_DISPLAY_OK, any errors in layer configuration should be returned as a CLIENT*
-    // flag in the corresponding layer_cfg_result entry.
-    //
-    // The driver must not retain references to the configuration after this function returns.
-    void (*check_configuration)(void* ctx, const display_config_t** display_config,
-                                uint32_t* display_cfg_result, uint32_t** layer_cfg_result,
-                                uint32_t display_count);
-
-    // Applies the configuration.
-    //
-    // All configurations passed to this function will be derived from configurations which
-    // have been succesfully validated, with the only differences either being omitted layers
-    // or different image handles. To account for any layers which are not present, the driver
-    // must use the z_index values of the present layers to configure them as if the whole
-    // configuration was present.
-    //
-    // Unlike with check_configuration, displays included in the configuration are not
-    // guaranteed to include any layers. Both omitted displays and displays with no layers
-    // can either be turned off or set to display a blank screen, but for displays with no
-    // layers there is a strong preference to display a blank screen instead of turn them off.
-    // In either case, the driver must drop all references to old images and invoke the vsync
-    // callback after doing so.
-    //
-    // The driver must not retain references to the configuration after this function returns.
-    void (*apply_configuration)(void* ctx,
-                                const display_config_t** display_configs, uint32_t display_count);
-
-    // Computes the stride (in pixels) necessary for a linear image with the given width
-    // and pixel format. Returns 0 on error.
-    uint32_t (*compute_linear_stride)(void* ctx, uint32_t width, zx_pixel_format_t pixel_format);
-
-    // Allocates a VMO of the requested size which can be used for images.
-    // TODO: move this functionallity into a seperate video buffer management system.
-    zx_status_t (*allocate_vmo)(void* ctx, uint64_t size, zx_handle_t* vmo_out);
-} display_controller_protocol_ops_t;
-
-typedef struct zx_display_controller_protocol {
+struct display_controller_protocol {
     display_controller_protocol_ops_t* ops;
     void* ctx;
-} display_controller_protocol_t;
+};
+
+// The function will only be called once, and it will be called before any other
+// functions are called.
+static inline void
+display_controller_set_display_controller_interface(const display_controller_protocol_t* proto,
+                                                    const display_controller_interface_t* intf) {
+    proto->ops->set_display_controller_interface(proto->ctx, intf);
+}
+// Imports a VMO backed image into the driver. The driver should set image->handle. The
+// driver does not own the vmo handle passed to this function.
+static inline zx_status_t
+display_controller_import_vmo_image(const display_controller_protocol_t* proto, image_t* image,
+                                    zx_handle_t vmo, size_t offset) {
+    return proto->ops->import_vmo_image(proto->ctx, image, vmo, offset);
+}
+// Releases any driver state associated with the given image. The client guarantees that
+// any images passed to apply_config will not be released until a vsync occurs with a
+// more recent image.
+static inline void display_controller_release_image(const display_controller_protocol_t* proto,
+                                                    image_t* image) {
+    proto->ops->release_image(proto->ctx, image);
+}
+// Validates the given configuration.
+// The configuration may not include all displays. Omiteed displays should be treated as
+// whichever of off or displaying a blank screen results in a more premissive validation.
+// All displays in a configuration will have at least one layer. The layers will be
+// arranged in increasing z-order, and their z_index fields will be set consecutively.
+// Whether or not the driver can accept the configuration cannot depend on the
+// particular image handles, as it must always be possible to present a new image in
+// place of another image with a matching configuration. It also cannot depend on the
+// cursor position, as that can be updated without another call to check_configuration.
+// display_cfg_result should be set to a CONFIG_DISPLAY_* error if the combination of
+// display modes is not supported.
+// layer_cfg_result points to an array of arrays. The primary length is display_count, the
+// secondary lengths are the corresponding display_cfg's layer_count. If display_cfg_result
+// is CONFIG_DISPLAY_OK, any errors in layer configuration should be returned as a CLIENT*
+// flag in the corresponding layer_cfg_result entry.
+// The driver must not retain references to the configuration after this function returns.
+// TODO: Fix me...
+static inline uint32_t display_controller_check_configuration(
+    const display_controller_protocol_t* proto, const display_config_t** display_config_list,
+    size_t display_config_count, uint32_t** out_layer_cfg_result_list,
+    size_t* layer_cfg_result_count) {
+    return proto->ops->check_configuration(proto->ctx, display_config_list, display_config_count,
+                                           out_layer_cfg_result_list, layer_cfg_result_count);
+}
+// Applies the configuration.
+// All configurations passed to this function will be derived from configurations which
+// have been succesfully validated, with the only differences either being omitted layers
+// or different image handles. To account for any layers which are not present, the driver
+// must use the z_index values of the present layers to configure them as if the whole
+// configuration was present.
+// Unlike with check_configuration, displays included in the configuration are not
+// guaranteed to include any layers. Both omitted displays and displays with no layers
+// can either be turned off or set to display a blank screen, but for displays with no
+// layers there is a strong preference to display a blank screen instead of turn them off.
+// In either case, the driver must drop all references to old images and invoke the vsync
+// callback after doing so.
+// The driver must not retain references to the configuration after this function returns.
+static inline void
+display_controller_apply_configuration(const display_controller_protocol_t* proto,
+                                       const display_config_t** display_config_list,
+                                       size_t display_config_count) {
+    proto->ops->apply_configuration(proto->ctx, display_config_list, display_config_count);
+}
+// Computes the stride (in pixels) necessary for a linear image with the given width
+// and pixel format. Returns 0 on error.
+static inline uint32_t
+display_controller_compute_linear_stride(const display_controller_protocol_t* proto, uint32_t width,
+                                         zx_pixel_format_t pixel_format) {
+    return proto->ops->compute_linear_stride(proto->ctx, width, pixel_format);
+}
+// Allocates a VMO of the requested size which can be used for images.
+static inline zx_status_t
+display_controller_allocate_vmo(const display_controller_protocol_t* proto, uint64_t size,
+                                zx_handle_t* out_vmo) {
+    return proto->ops->allocate_vmo(proto->ctx, size, out_vmo);
+}
+
 __END_CDECLS;
diff --git a/system/ulib/ddk/include/ddk/protocol/ethernet.h b/system/ulib/ddk/include/ddk/protocol/ethernet.h
index 20d3358..bcbeddc 100644
--- a/system/ulib/ddk/include/ddk/protocol/ethernet.h
+++ b/system/ulib/ddk/include/ddk/protocol/ethernet.h
@@ -1,154 +1,193 @@
-// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
 #include <zircon/compiler.h>
-#include <zircon/device/ethernet.h>
 #include <zircon/listnode.h>
 #include <zircon/types.h>
 
 __BEGIN_CDECLS;
 
-#define ETH_MAC_SIZE           (6)    // bytes
-#define ETH_MTU_SIZE           (1500) // bytes
-#define ETH_FRAME_MAX_HDR_SIZE (18)   // bytes. MAC Dest(6) + MAC Src(6) + 802.1Q tag(4) + Ethertype(2)
-#define ETH_FRAME_MAX_SIZE     (ETH_MTU_SIZE + ETH_FRAME_MAX_HDR_SIZE)
+// Forward declarations
 
+typedef union internal internal_t;
 // The ethermac interface supports both synchronous and asynchronous transmissions using the
 // proto->queue_tx() and ifc->complete_tx() methods.
-//
 // Receive operations are supported with the ifc->recv() interface.
-// TODO: implement netbuf-based receive operations by implementing proto->queue_rx() and
-// ifc->complete_rx()
-//
 // The FEATURE_WLAN flag indicates a device that supports wlan operations.
-//
 // The FEATURE_SYNTH flag indicates a device that is not backed by hardware.
-//
 // The FEATURE_DMA flag indicates that the device can copy the buffer data using DMA and will ensure
 // that physical addresses are provided in netbufs.
+typedef uint32_t ethmac_feature_t;
+#define ETHMAC_FEATURE_WLAN UINT32_C(1)
+#define ETHMAC_FEATURE_SYNTH UINT32_C(2)
+#define ETHMAC_FEATURE_DMA UINT32_C(4)
 
-#define ETHMAC_FEATURE_WLAN     (1u)
-#define ETHMAC_FEATURE_SYNTH    (2u)
-#define ETHMAC_FEATURE_DMA      (4u)
+typedef struct ethmac_info ethmac_info_t;
+typedef struct ethmac_netbuf ethmac_netbuf_t;
+typedef struct ethmac_ifc ethmac_ifc_t;
+typedef struct ethmac_protocol ethmac_protocol_t;
 
-typedef struct ethmac_info {
-    uint32_t features;
-    uint32_t mtu;
-    uint8_t mac[ETH_MAC_SIZE];
-    uint8_t reserved0[2];
-    uint32_t reserved1[4];
-} ethmac_info_t;
+// Declarations
 
-typedef struct ethmac_netbuf {
-    // Provided by the generic ethernet driver
-    void* data;
-    zx_paddr_t phys;  // Only used if ETHMAC_FEATURE_DMA is available
-    uint16_t len;
-    uint16_t reserved;
-    uint32_t flags;
+union internal {
+    uint64_t val;
+    void* ptr_buffer;
+    size_t ptr_size;
+};
 
-    // Shared between the generic ethernet and ethmac drivers
-    list_node_t node;
-
-    // For use by the ethmac driver
-    union {
-        uint64_t val;
-        void* ptr;
-    };
-} ethmac_netbuf_t;
-
-typedef struct ethmac_ifc_virt {
-    void (*status)(void* cookie, uint32_t status);
-
-    void (*recv)(void* cookie, void* data, size_t length, uint32_t flags);
-
-    // complete_tx() is called to return ownership of a netbuf to the generic ethernet driver.
-    // Return status indicates queue state:
-    //   ZX_OK: Packet has been enqueued.
-    //   Other: Packet could not be enqueued.
-    // Upon a return of ZX_OK, the packet has been enqueued, but no information is returned as to
-    // the completion state of the transmission itself.
-    void (*complete_tx)(void* cookie, ethmac_netbuf_t* netbuf, zx_status_t status);
-} ethmac_ifc_t;
-
-// Indicates that additional data is available to be sent after this call finishes. Allows a ethmac
-// driver to batch tx to hardware if possible.
-#define ETHMAC_TX_OPT_MORE (1u)
-
-// SETPARAM_ values identify the parameter to set. Each call to set_param()
-// takes an int32_t |value| and void* |data| which have meaning specific to
-// the parameter being set.
-
-// |value| is bool. |data| is unused.
-#define ETHMAC_SETPARAM_PROMISC (1u)
-
-// |value| is bool. |data| is unused.
-#define ETHMAC_SETPARAM_MULTICAST_PROMISC (2u)
-
-#define ETHMAC_MULTICAST_FILTER_OVERFLOW -1
+#define ETHMAC_SETPARAM_DUMP_REGS UINT32_C(4)
 
 // |value| is number of addresses, or ETHMAC_MULTICAST_FILTER_OVERFLOW for "too many to count."
 // |data| is |value|*6 bytes of MAC addresses. Caller retains ownership.
 // If |value| is _OVERFLOW, |data| is ignored.
-#define ETHMAC_SETPARAM_MULTICAST_FILTER (3u)
+#define ETHMAC_SETPARAM_MULTICAST_FILTER UINT32_C(3)
 
-#define ETHMAC_SETPARAM_DUMP_REGS (4u)
+#define ETHMAC_MULTICAST_FILTER_OVERFLOW INT32_C(-1)
+
+// |value| is bool. |data| is unused.
+#define ETHMAC_SETPARAM_MULTICAST_PROMISC UINT32_C(2)
+
+// Indicates that additional data is available to be sent after this call finishes. Allows a ethmac
+// driver to batch tx to hardware if possible.
+#define ETHMAC_TX_OPT_MORE UINT32_C(1)
+
+struct ethmac_info {
+    uint32_t features;
+    uint32_t mtu;
+    uint8_t mac[6];
+    uint8_t reserved0[2];
+    uint32_t reserved1[4];
+};
+
+// SETPARAM_ values identify the parameter to set. Each call to set_param()
+// takes an int32_t |value| and void* |data| which have meaning specific to
+// the parameter being set.
+// |value| is bool. |data| is unused.
+#define ETHMAC_SETPARAM_PROMISC UINT32_C(1)
+
+#define ETH_FRAME_MAX_SIZE UINT32_C(1518)
+
+#define ETH_FRAME_MAX_HDR_SIZE UINT32_C(18)
+
+#define ETH_MTU_SIZE UINT32_C(1500)
+
+#define ETH_MAC_SIZE UINT32_C(6)
+
+struct ethmac_netbuf {
+    // Provided by the generic ethernet driver.
+    void* data_buffer;
+    size_t data_size;
+    // Only used if ETHMAC_FEATURE_DMA is available.
+    uint64_t phys;
+    uint16_t reserved;
+    uint32_t flags;
+    // Shared between the generic ethernet and ethmac drivers.
+    list_node_t node;
+    // For use by the ethmac driver.
+    internal_t u;
+};
+
+typedef struct ethmac_ifc_ops {
+    void (*status)(void* ctx, uint32_t status);
+    void (*recv)(void* ctx, const void* data_buffer, size_t data_size, uint32_t flags);
+    void (*complete_tx)(void* ctx, ethmac_netbuf_t* netbuf, zx_status_t status);
+} ethmac_ifc_ops_t;
+
+struct ethmac_ifc {
+    ethmac_ifc_ops_t* ops;
+    void* ctx;
+};
+
+static inline void ethmac_ifc_status(const ethmac_ifc_t* proto, uint32_t status) {
+    proto->ops->status(proto->ctx, status);
+}
+static inline void ethmac_ifc_recv(const ethmac_ifc_t* proto, const void* data_buffer,
+                                   size_t data_size, uint32_t flags) {
+    proto->ops->recv(proto->ctx, data_buffer, data_size, flags);
+}
+// complete_tx() is called to return ownership of a netbuf to the generic ethernet driver.
+// Return status indicates queue state:
+//   ZX_OK: Packet has been enqueued.
+//   Other: Packet could not be enqueued.
+// Upon a return of ZX_OK, the packet has been enqueued, but no information is returned as to
+// the completion state of the transmission itself.
+static inline void ethmac_ifc_complete_tx(const ethmac_ifc_t* proto, ethmac_netbuf_t* netbuf,
+                                          zx_status_t status) {
+    proto->ops->complete_tx(proto->ctx, netbuf, status);
+}
+
+typedef struct ethmac_protocol_ops {
+    zx_status_t (*query)(void* ctx, uint32_t options, ethmac_info_t* out_info);
+    void (*stop)(void* ctx);
+    zx_status_t (*start)(void* ctx, const ethmac_ifc_t* ifc);
+    zx_status_t (*queue_tx)(void* ctx, uint32_t options, ethmac_netbuf_t* netbuf);
+    zx_status_t (*set_param)(void* ctx, uint32_t param, zx_status_t value, const void* data_buffer,
+                             size_t data_size);
+    zx_handle_t (*get_bti)(void* ctx);
+} ethmac_protocol_ops_t;
 
 // The ethernet midlayer will never call ethermac_protocol
 // methods from multiple threads simultaneously, but it
 // can call send() methods at the same time as non-send
 // methods.
-typedef struct ethmac_protocol_ops {
-    // Obtain information about the ethermac device and supported features
-    // Safe to call at any time.
-    zx_status_t (*query)(void* ctx, uint32_t options, ethmac_info_t* info);
-
-    // Shut down a running ethermac
-    // Safe to call if the ethermac is already stopped.
-    void (*stop)(void* ctx);
-
-    // Start ethermac running with ifc_virt
-    // Callbacks on ifc may be invoked from now until stop() is called
-    zx_status_t (*start)(void* ctx, ethmac_ifc_t* ifc, void* cookie);
-
-    // Request transmission of the packet in netbuf. Return status indicates queue state:
-    //   ZX_ERR_SHOULD_WAIT: Packet is being enqueued.
-    //   ZX_OK: Packet has been enqueued.
-    //   Other: Packet could not be enqueued.
-    //
-    // In the SHOULD_WAIT case the driver takes ownership of the netbuf and must call complete_tx()
-    // to return it once the enqueue is complete. complete_tx() may be used to return the packet
-    // before transmission itself completes, but MUST NOT be called from within the queue_tx()
-    // implementation.
-    //
-    // queue_tx() may be called at any time after start() is called including from multiple threads
-    // simultaneously.
-    zx_status_t (*queue_tx)(void* ctx, uint32_t options, ethmac_netbuf_t* netbuf);
-
-    // Request a settings change for the driver. Return status indicates disposition:
-    //   ZX_OK: Request has been handled.
-    //   ZX_ERR_NOT_SUPPORTED: Driver does not support this setting.
-    //   Other: Error trying to support this request.
-    //
-    // |value| and |data| usage are defined for each |param|; see comments above.
-    //
-    // set_param() may be called at any time after start() is called including from multiple threads
-    // simultaneously.
-    zx_status_t (*set_param)(void* ctx, uint32_t param, int32_t value, void* data);
-
-    // Get the BTI handle (needed to pin DMA memory) for this device.
-    // This method is only valid on devices that advertise ETHMAC_FEATURE_DMA
-    // The caller does *not* take ownership of the BTI handle and must never close
-    // the handle.
-    zx_handle_t (*get_bti)(void* ctx);
-} ethmac_protocol_ops_t;
-
-typedef struct ethmac_protocol {
+struct ethmac_protocol {
     ethmac_protocol_ops_t* ops;
     void* ctx;
-} ethmac_protocol_t;
+};
+
+// Obtain information about the ethermac device and supported features
+// Safe to call at any time.
+static inline zx_status_t ethmac_query(const ethmac_protocol_t* proto, uint32_t options,
+                                       ethmac_info_t* out_info) {
+    return proto->ops->query(proto->ctx, options, out_info);
+}
+// Shut down a running ethermac
+// Safe to call if the ethermac is already stopped.
+static inline void ethmac_stop(const ethmac_protocol_t* proto) {
+    proto->ops->stop(proto->ctx);
+}
+// Start ethermac running with ifc_virt
+// Callbacks on ifc may be invoked from now until stop() is called
+static inline zx_status_t ethmac_start(const ethmac_protocol_t* proto, const ethmac_ifc_t* ifc) {
+    return proto->ops->start(proto->ctx, ifc);
+}
+// Request transmission of the packet in netbuf. Return status indicates queue state:
+//   ZX_ERR_SHOULD_WAIT: Packet is being enqueued.
+//   ZX_OK: Packet has been enqueued.
+//   Other: Packet could not be enqueued.
+// In the SHOULD_WAIT case the driver takes ownership of the netbuf and must call complete_tx()
+// to return it once the enqueue is complete. complete_tx() may be used to return the packet
+// before transmission itself completes, but MUST NOT be called from within the queue_tx()
+// implementation.
+// queue_tx() may be called at any time after start() is called including from multiple threads
+// simultaneously.
+static inline zx_status_t ethmac_queue_tx(const ethmac_protocol_t* proto, uint32_t options,
+                                          ethmac_netbuf_t* netbuf) {
+    return proto->ops->queue_tx(proto->ctx, options, netbuf);
+}
+// Request a settings change for the driver. Return status indicates disposition:
+//   ZX_OK: Request has been handled.
+//   ZX_ERR_NOT_SUPPORTED: Driver does not support this setting.
+//   Other: Error trying to support this request.
+// |value| and |data| usage are defined for each |param|; see comments above.
+// set_param() may be called at any time after start() is called including from multiple threads
+// simultaneously.
+static inline zx_status_t ethmac_set_param(const ethmac_protocol_t* proto, uint32_t param,
+                                           zx_status_t value, const void* data_buffer,
+                                           size_t data_size) {
+    return proto->ops->set_param(proto->ctx, param, value, data_buffer, data_size);
+}
+// Get the BTI handle (needed to pin DMA memory) for this device.
+// This method is only valid on devices that advertise ETHMAC_FEATURE_DMA
+// The caller does *not* take ownership of the BTI handle and must never close
+// the handle.
+static inline zx_handle_t ethmac_get_bti(const ethmac_protocol_t* proto) {
+    return proto->ops->get_bti(proto->ctx);
+}
 
 __END_CDECLS;
diff --git a/system/ulib/ddk/include/ddk/protocol/gpio.h b/system/ulib/ddk/include/ddk/protocol/gpio.h
index b50f6ed..8d15afa 100644
--- a/system/ulib/ddk/include/ddk/protocol/gpio.h
+++ b/system/ulib/ddk/include/ddk/protocol/gpio.h
@@ -1,7 +1,9 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
 #include <zircon/compiler.h>
@@ -9,81 +11,84 @@
 
 __BEGIN_CDECLS;
 
-// flags for gpio_config_in()
-#define GPIO_PULL_DOWN          (0 << 0)
-#define GPIO_PULL_UP            (1 << 0)
-#define GPIO_NO_PULL            (2 << 0)
-#define GPIO_PULL_MASK          (3 << 0)
+// Forward declarations
 
-// Values for gpio_set_polarity()
-#define GPIO_POLARITY_LOW       0
-#define GPIO_POLARITY_HIGH      1
+// Values for `SetPolarity`.
+typedef uint32_t gpio_polarity_t;
+#define GPIO_POLARITY_LOW UINT32_C(0)
+#define GPIO_POLARITY_HIGH UINT32_C(1)
 
-// In the functions below, the GPIO index is relative to the list of GPIOs for the device.
-// For example, the list of GPIOs a platform device has access to would likely be a small
-// subset of the total number of GPIOs, while a platform bus implementation driver would
-// have access to the complete set of GPIOs.
+typedef struct gpio_protocol gpio_protocol_t;
 
-typedef struct {
+// Declarations
+
+// Flags for `ConfigIn`.
+#define GPIO_PULL_DOWN UINT32_C(0x0)
+
+#define GPIO_PULL_UP UINT32_C(0x10)
+
+#define GPIO_PULL_MASK UINT32_C(0x30)
+
+#define GPIO_NO_PULL UINT32_C(0x20)
+
+typedef struct gpio_protocol_ops {
     zx_status_t (*config_in)(void* ctx, uint32_t index, uint32_t flags);
     zx_status_t (*config_out)(void* ctx, uint32_t index, uint8_t initial_value);
     zx_status_t (*set_alt_function)(void* ctx, uint32_t index, uint64_t function);
     zx_status_t (*read)(void* ctx, uint32_t index, uint8_t* out_value);
     zx_status_t (*write)(void* ctx, uint32_t index, uint8_t value);
-    zx_status_t (*get_interrupt)(void* ctx, uint32_t pin, uint32_t flags, zx_handle_t* out_handle);
-    zx_status_t (*release_interrupt)(void* ctx, uint32_t pin);
-    zx_status_t (*set_polarity)(void* ctx, uint32_t pin, uint32_t polarity);
+    zx_status_t (*get_interrupt)(void* ctx, uint32_t index, uint32_t flags, zx_handle_t* out_irq);
+    zx_status_t (*release_interrupt)(void* ctx, uint32_t index);
+    zx_status_t (*set_polarity)(void* ctx, uint32_t index, gpio_polarity_t polarity);
 } gpio_protocol_ops_t;
 
-typedef struct {
+// In the functions below, the GPIO index is relative to the list of GPIOs for the device.
+// For example, the list of GPIOs a platform device has access to would likely be a small
+// subset of the total number of GPIOs, while a platform bus implementation driver would
+// have access to the complete set of GPIOs.
+struct gpio_protocol {
     gpio_protocol_ops_t* ops;
     void* ctx;
-} gpio_protocol_t;
+};
 
-// configures a GPIO for input
-static inline zx_status_t gpio_config_in(const gpio_protocol_t* gpio, uint32_t index,
+// Configures a GPIO for input.
+static inline zx_status_t gpio_config_in(const gpio_protocol_t* proto, uint32_t index,
                                          uint32_t flags) {
-    return gpio->ops->config_in(gpio->ctx, index, flags);
+    return proto->ops->config_in(proto->ctx, index, flags);
 }
-
-// configures a GPIO for output
-static inline zx_status_t gpio_config_out(const gpio_protocol_t* gpio, uint32_t index,
+// Configures a GPIO for output.
+static inline zx_status_t gpio_config_out(const gpio_protocol_t* proto, uint32_t index,
                                           uint8_t initial_value) {
-    return gpio->ops->config_out(gpio->ctx, index, initial_value);
+    return proto->ops->config_out(proto->ctx, index, initial_value);
 }
-
-// configures the GPIO pin for an alternate function (I2C, SPI, etc)
-// the interpretation of "function" is platform dependent
-static inline zx_status_t gpio_set_alt_function(const gpio_protocol_t* gpio, uint32_t index,
+// Configures the GPIO pin for an alternate function (I2C, SPI, etc)
+// the interpretation of "function" is platform dependent.
+static inline zx_status_t gpio_set_alt_function(const gpio_protocol_t* proto, uint32_t index,
                                                 uint64_t function) {
-    return gpio->ops->set_alt_function(gpio->ctx, index, function);
+    return proto->ops->set_alt_function(proto->ctx, index, function);
 }
-
-// reads the current value of a GPIO (0 or 1)
-static inline zx_status_t gpio_read(const gpio_protocol_t* gpio, uint32_t index,
+// Reads the current value of a GPIO (0 or 1).
+static inline zx_status_t gpio_read(const gpio_protocol_t* proto, uint32_t index,
                                     uint8_t* out_value) {
-    return gpio->ops->read(gpio->ctx, index, out_value);
+    return proto->ops->read(proto->ctx, index, out_value);
+}
+// Sets the current value of the GPIO (any non-zero value maps to 1).
+static inline zx_status_t gpio_write(const gpio_protocol_t* proto, uint32_t index, uint8_t value) {
+    return proto->ops->write(proto->ctx, index, value);
+}
+// Gets an interrupt object pertaining to a particular GPIO pin.
+static inline zx_status_t gpio_get_interrupt(const gpio_protocol_t* proto, uint32_t index,
+                                             uint32_t flags, zx_handle_t* out_irq) {
+    return proto->ops->get_interrupt(proto->ctx, index, flags, out_irq);
+}
+// Release the interrupt.
+static inline zx_status_t gpio_release_interrupt(const gpio_protocol_t* proto, uint32_t index) {
+    return proto->ops->release_interrupt(proto->ctx, index);
+}
+// Set GPIO polarity.
+static inline zx_status_t gpio_set_polarity(const gpio_protocol_t* proto, uint32_t index,
+                                            gpio_polarity_t polarity) {
+    return proto->ops->set_polarity(proto->ctx, index, polarity);
 }
 
-// sets the current value of the GPIO (any non-zero value maps to 1)
-static inline zx_status_t gpio_write(const gpio_protocol_t* gpio, uint32_t index, uint8_t value) {
-    return gpio->ops->write(gpio->ctx, index, value);
-}
-
-// gets an interrupt object pertaining to a particular GPIO pin
-static inline zx_status_t gpio_get_interrupt(const gpio_protocol_t* gpio, uint32_t index,
-                                             uint32_t flags, zx_handle_t* out_handle) {
-    return gpio->ops->get_interrupt(gpio->ctx, index, flags, out_handle);
-}
-
-// release the interrupt
-static inline zx_status_t gpio_release_interrupt(const gpio_protocol_t* gpio, uint32_t pin) {
-    return gpio->ops->release_interrupt(gpio->ctx, pin);
-}
-
-// Set GPIO polarity
-static inline zx_status_t gpio_set_polarity(const gpio_protocol_t* gpio, uint32_t pin,
-                                            uint32_t polarity) {
-    return gpio->ops->set_polarity(gpio->ctx, pin, polarity);
-}
 __END_CDECLS;
diff --git a/system/ulib/ddk/include/ddk/protocol/hidbus.h b/system/ulib/ddk/include/ddk/protocol/hidbus.h
index d690b1a..909ed6d 100644
--- a/system/ulib/ddk/include/ddk/protocol/hidbus.h
+++ b/system/ulib/ddk/include/ddk/protocol/hidbus.h
@@ -1,7 +1,9 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
 #include <zircon/compiler.h>
@@ -9,69 +11,126 @@
 
 __BEGIN_CDECLS;
 
-enum {
-    HID_DESC_TYPE_REPORT = 0x22,
-};
+// Forward declarations
 
-enum {
-    HID_REPORT_TYPE_INPUT = 1,
-    HID_REPORT_TYPE_OUTPUT = 2,
-    HID_REPORT_TYPE_FEATURE = 3,
-};
+typedef uint8_t hid_device_class_t;
+#define HID_DEVICE_CLASS_OTHER UINT8_C(0)
+#define HID_DEVICE_CLASS_KBD UINT8_C(1)
+#define HID_DEVICE_CLASS_POINTER UINT8_C(2)
+#define HID_DEVICE_CLASS_KBD_POINTER UINT8_C(3)
+#define HID_DEVICE_CLASS_FIRST UINT8_C(0)
+#define HID_DEVICE_CLASS_LAST UINT8_C(3)
 
-enum {
-    HID_PROTOCOL_BOOT = 0,
-    HID_PROTOCOL_REPORT = 1,
-};
+typedef struct hid_info hid_info_t;
+typedef uint8_t hid_description_type_t;
+#define HID_DESCRIPTION_TYPE_REPORT UINT8_C(34)
 
-enum {
-    HID_DEV_CLASS_OTHER = 0,
-    HID_DEV_CLASS_KBD = 1,
-    HID_DEV_CLASS_POINTER = 2,
-    HID_DEV_CLASS_KBD_POINTER = 3,
+typedef uint8_t hid_report_type_t;
+#define HID_REPORT_TYPE_INPUT UINT8_C(1)
+#define HID_REPORT_TYPE_OUTPUT UINT8_C(2)
+#define HID_REPORT_TYPE_FEATURE UINT8_C(3)
 
-    HID_DEV_CLASS_FIRST = HID_DEV_CLASS_OTHER,
-    HID_DEV_CLASS_LAST = HID_DEV_CLASS_KBD_POINTER,
-};
+typedef struct hidbus_ifc hidbus_ifc_t;
+typedef uint8_t hid_protocol_t;
+#define HID_PROTOCOL_BOOT UINT8_C(0)
+#define HID_PROTOCOL_REPORT UINT8_C(0)
 
-typedef struct hid_info {
+typedef struct hidbus_protocol hidbus_protocol_t;
+
+// Declarations
+
+struct hid_info {
     uint8_t dev_num;
-    uint8_t dev_class;
+    hid_device_class_t device_class;
     bool boot_device;
-} hid_info_t;
+};
 
-typedef struct hidbus_ifc {
-    // Queues a report received by the hidbus device.
-    void (*io_queue)(void* cookie, const uint8_t* buf, size_t len);
-} hidbus_ifc_t;
+typedef struct hidbus_ifc_ops {
+    void (*io_queue)(void* ctx, const void* buf_buffer, size_t buf_size);
+} hidbus_ifc_ops_t;
+
+struct hidbus_ifc {
+    hidbus_ifc_ops_t* ops;
+    void* ctx;
+};
+
+// Queues a report received by the hidbus device.
+static inline void hidbus_ifc_io_queue(const hidbus_ifc_t* proto, const void* buf_buffer,
+                                       size_t buf_size) {
+    proto->ops->io_queue(proto->ctx, buf_buffer, buf_size);
+}
 
 typedef struct hidbus_protocol_ops {
-    // Obtain information about the hidbus device and supported features.
-    // Safe to call at any time.
-    zx_status_t (*query)(void* ctx, uint32_t options, hid_info_t* info);
-
-    // Start the hidbus device. The device may begin queueing hid reports via
-    // ifc->io_queue before this function returns. It is an error to start an
-    // already-started hidbus device.
-    zx_status_t (*start)(void* ctx, hidbus_ifc_t* ifc, void* cookie);
-
-    // Stop the hidbus device. Safe to call if the hidbus is already stopped.
+    zx_status_t (*query)(void* ctx, uint32_t options, hid_info_t* out_info);
+    zx_status_t (*start)(void* ctx, const hidbus_ifc_t* ifc);
     void (*stop)(void* ctx);
-
-    // HID operations. See Device Class Definition for HID for details.
-    zx_status_t (*get_descriptor)(void* ctx, uint8_t desc_type, void** data, size_t* len);
-    zx_status_t (*get_report)(void* ctx, uint8_t rpt_type, uint8_t rpt_id, void* data, size_t len,
-                              size_t* out_len);
-    zx_status_t (*set_report)(void* ctx, uint8_t rpt_type, uint8_t rpt_id, void* data, size_t len);
-    zx_status_t (*get_idle)(void* ctx, uint8_t rpt_id, uint8_t* duration);
+    zx_status_t (*get_descriptor)(void* ctx, hid_description_type_t desc_type,
+                                  void** out_data_buffer, size_t* data_size);
+    zx_status_t (*get_report)(void* ctx, hid_report_type_t rpt_type, uint8_t rpt_id,
+                              void* out_data_buffer, size_t data_size, size_t* out_data_actual);
+    zx_status_t (*set_report)(void* ctx, hid_report_type_t rpt_type, uint8_t rpt_id,
+                              const void* data_buffer, size_t data_size);
+    zx_status_t (*get_idle)(void* ctx, uint8_t rpt_id, uint8_t* out_duration);
     zx_status_t (*set_idle)(void* ctx, uint8_t rpt_id, uint8_t duration);
-    zx_status_t (*get_protocol)(void* ctx, uint8_t* protocol);
-    zx_status_t (*set_protocol)(void* ctx, uint8_t protocol);
+    zx_status_t (*get_protocol)(void* ctx, hid_protocol_t* out_protocol);
+    zx_status_t (*set_protocol)(void* ctx, hid_protocol_t protocol);
 } hidbus_protocol_ops_t;
 
-typedef struct hidbus_protocol {
+struct hidbus_protocol {
     hidbus_protocol_ops_t* ops;
     void* ctx;
-} hidbus_protocol_t;
+};
+
+// Obtain information about the hidbus device and supported features.
+// Safe to call at any time.
+static inline zx_status_t hidbus_query(const hidbus_protocol_t* proto, uint32_t options,
+                                       hid_info_t* out_info) {
+    return proto->ops->query(proto->ctx, options, out_info);
+}
+// Start the hidbus device. The device may begin queueing hid reports via
+// ifc->io_queue before this function returns. It is an error to start an
+// already-started hidbus device.
+static inline zx_status_t hidbus_start(const hidbus_protocol_t* proto, const hidbus_ifc_t* ifc) {
+    return proto->ops->start(proto->ctx, ifc);
+}
+// Stop the hidbus device. Safe to call if the hidbus is already stopped.
+static inline void hidbus_stop(const hidbus_protocol_t* proto) {
+    proto->ops->stop(proto->ctx);
+}
+// What are the ownership semantics with regards to the data buffer passed back?
+// is len an input and output parameter?
+static inline zx_status_t hidbus_get_descriptor(const hidbus_protocol_t* proto,
+                                                hid_description_type_t desc_type,
+                                                void** out_data_buffer, size_t* data_size) {
+    return proto->ops->get_descriptor(proto->ctx, desc_type, out_data_buffer, data_size);
+}
+static inline zx_status_t hidbus_get_report(const hidbus_protocol_t* proto,
+                                            hid_report_type_t rpt_type, uint8_t rpt_id,
+                                            void* out_data_buffer, size_t data_size,
+                                            size_t* out_data_actual) {
+    return proto->ops->get_report(proto->ctx, rpt_type, rpt_id, out_data_buffer, data_size,
+                                  out_data_actual);
+}
+static inline zx_status_t hidbus_set_report(const hidbus_protocol_t* proto,
+                                            hid_report_type_t rpt_type, uint8_t rpt_id,
+                                            const void* data_buffer, size_t data_size) {
+    return proto->ops->set_report(proto->ctx, rpt_type, rpt_id, data_buffer, data_size);
+}
+static inline zx_status_t hidbus_get_idle(const hidbus_protocol_t* proto, uint8_t rpt_id,
+                                          uint8_t* out_duration) {
+    return proto->ops->get_idle(proto->ctx, rpt_id, out_duration);
+}
+static inline zx_status_t hidbus_set_idle(const hidbus_protocol_t* proto, uint8_t rpt_id,
+                                          uint8_t duration) {
+    return proto->ops->set_idle(proto->ctx, rpt_id, duration);
+}
+static inline zx_status_t hidbus_get_protocol(const hidbus_protocol_t* proto,
+                                              hid_protocol_t* out_protocol) {
+    return proto->ops->get_protocol(proto->ctx, out_protocol);
+}
+static inline zx_status_t hidbus_set_protocol(const hidbus_protocol_t* proto,
+                                              hid_protocol_t protocol) {
+    return proto->ops->set_protocol(proto->ctx, protocol);
+}
 
 __END_CDECLS;
diff --git a/system/ulib/ddk/include/ddk/protocol/intel-gpu-core.h b/system/ulib/ddk/include/ddk/protocol/intel-gpu-core.h
index 6cdd6e5..6a38a34 100644
--- a/system/ulib/ddk/include/ddk/protocol/intel-gpu-core.h
+++ b/system/ulib/ddk/include/ddk/protocol/intel-gpu-core.h
@@ -1,7 +1,9 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
 #include <zircon/compiler.h>
@@ -9,59 +11,109 @@
 
 __BEGIN_CDECLS;
 
-#define IMAGE_TYPE_X_TILED 1
-#define IMAGE_TYPE_Y_LEGACY_TILED 2
-#define IMAGE_TYPE_YF_TILED 3
+// Forward declarations
 
-typedef void (*zx_intel_gpu_core_interrupt_callback_t)(void* data,
-                                                       uint32_t master_interrupt_control);
+typedef struct zx_intel_gpu_core_interrupt zx_intel_gpu_core_interrupt_t;
+typedef struct zx_intel_gpu_core_protocol zx_intel_gpu_core_protocol_t;
+
+// Declarations
+
+#define IMAGE_TYPE_X_TILED UINT32_C(1)
+
+struct zx_intel_gpu_core_interrupt {
+    void (*callback)(void* ctx, uint32_t master_interrupt_control);
+    void* ctx;
+};
 
 typedef struct zx_intel_gpu_core_protocol_ops {
-    // Reads 16 bits from pci config space; returned in |value_out|.
-    zx_status_t (*read_pci_config_16)(void* ctx, uint16_t addr, uint16_t* value_out);
-
-    // Maps the given |pci_bar|; address returned in |addr_out|, size in bytes returned in
-    // |size_out|.
-    zx_status_t (*map_pci_mmio)(void* ctx, uint32_t pci_bar, void** addr_out, uint64_t* size_out);
-
-    // Unmaps the given |pci_bar|.
+    zx_status_t (*read_pci_config16)(void* ctx, uint16_t addr, uint16_t* out_value);
+    zx_status_t (*map_pci_mmio)(void* ctx, uint32_t pci_bar, void** out_buf_buffer,
+                                size_t* buf_size);
     zx_status_t (*unmap_pci_mmio)(void* ctx, uint32_t pci_bar);
-
-    // Returns a bus transaction initiator.
-    zx_status_t (*get_pci_bti)(void* ctx, uint32_t index, zx_handle_t* bti_out);
-
-    // Registers the given |callback| to be invoked with parameter |data| when an interrupt occurs
-    // matching |interrupt_mask|.
+    zx_status_t (*get_pci_bti)(void* ctx, uint32_t index, zx_handle_t* out_bti);
     zx_status_t (*register_interrupt_callback)(void* ctx,
-                                               zx_intel_gpu_core_interrupt_callback_t callback,
-                                               void* data, uint32_t interrupt_mask);
-
-    // Un-registers a previously registered interrupt callback.
+                                               const zx_intel_gpu_core_interrupt_t* callback,
+                                               uint32_t interrupt_mask);
     zx_status_t (*unregister_interrupt_callback)(void* ctx);
-
-    // Returns the size of the GTT (global translation table) in bytes.
     uint64_t (*gtt_get_size)(void* ctx);
-
-    // Allocates a region of the GTT of the given |page_count|, returning the page-aligned virtual
-    // address in |addr_out|.
-    zx_status_t (*gtt_alloc)(void* ctx, uint64_t page_count, uint64_t* addr_out);
-
-    // Frees the GTT allocation given by |addr|.
+    zx_status_t (*gtt_alloc)(void* ctx, uint64_t page_count, uint64_t* out_addr);
     zx_status_t (*gtt_free)(void* ctx, uint64_t addr);
-
-    // Clears the page table entries for the GTT allocation given by |addr|.
     zx_status_t (*gtt_clear)(void* ctx, uint64_t addr);
-
-    // Inserts page tables entries for the GTT allocation given by |addr| for the vmo represented by
-    // handle |buffer|, at the given |page_offset| and |page_count|. Takes ownership of |buffer|.
     zx_status_t (*gtt_insert)(void* ctx, uint64_t addr, zx_handle_t buffer, uint64_t page_offset,
                               uint64_t page_count);
-
 } zx_intel_gpu_core_protocol_ops_t;
 
-typedef struct zx_intel_gpu_core_protocol {
+struct zx_intel_gpu_core_protocol {
     zx_intel_gpu_core_protocol_ops_t* ops;
     void* ctx;
-} zx_intel_gpu_core_protocol_t;
+};
+
+// Reads 16 bits from pci config space; returned in |value_out|.
+static inline zx_status_t
+zx_intel_gpu_core_read_pci_config16(const zx_intel_gpu_core_protocol_t* proto, uint16_t addr,
+                                    uint16_t* out_value) {
+    return proto->ops->read_pci_config16(proto->ctx, addr, out_value);
+}
+// Maps the given |pci_bar|; address returned in |addr_out|, size in bytes returned in
+// |size_out|.
+static inline zx_status_t zx_intel_gpu_core_map_pci_mmio(const zx_intel_gpu_core_protocol_t* proto,
+                                                         uint32_t pci_bar, void** out_buf_buffer,
+                                                         size_t* buf_size) {
+    return proto->ops->map_pci_mmio(proto->ctx, pci_bar, out_buf_buffer, buf_size);
+}
+// Unmaps the given |pci_bar|.
+static inline zx_status_t
+zx_intel_gpu_core_unmap_pci_mmio(const zx_intel_gpu_core_protocol_t* proto, uint32_t pci_bar) {
+    return proto->ops->unmap_pci_mmio(proto->ctx, pci_bar);
+}
+// Returns a bus transaction initiator.
+static inline zx_status_t zx_intel_gpu_core_get_pci_bti(const zx_intel_gpu_core_protocol_t* proto,
+                                                        uint32_t index, zx_handle_t* out_bti) {
+    return proto->ops->get_pci_bti(proto->ctx, index, out_bti);
+}
+// Registers the given |callback| to be invoked with parameter |data| when an interrupt occurs
+// matching |interrupt_mask|.
+static inline zx_status_t
+zx_intel_gpu_core_register_interrupt_callback(const zx_intel_gpu_core_protocol_t* proto,
+                                              const zx_intel_gpu_core_interrupt_t* callback,
+                                              uint32_t interrupt_mask) {
+    return proto->ops->register_interrupt_callback(proto->ctx, callback, interrupt_mask);
+}
+// Un-registers a previously registered interrupt callback.
+static inline zx_status_t
+zx_intel_gpu_core_unregister_interrupt_callback(const zx_intel_gpu_core_protocol_t* proto) {
+    return proto->ops->unregister_interrupt_callback(proto->ctx);
+}
+// Returns the size of the GTT (global translation table) in bytes.
+static inline uint64_t zx_intel_gpu_core_gtt_get_size(const zx_intel_gpu_core_protocol_t* proto) {
+    return proto->ops->gtt_get_size(proto->ctx);
+}
+// Allocates a region of the GTT of the given |page_count|, returning the page-aligned virtual
+// address in |addr_out|.
+static inline zx_status_t zx_intel_gpu_core_gtt_alloc(const zx_intel_gpu_core_protocol_t* proto,
+                                                      uint64_t page_count, uint64_t* out_addr) {
+    return proto->ops->gtt_alloc(proto->ctx, page_count, out_addr);
+}
+// Frees the GTT allocation given by |addr|.
+static inline zx_status_t zx_intel_gpu_core_gtt_free(const zx_intel_gpu_core_protocol_t* proto,
+                                                     uint64_t addr) {
+    return proto->ops->gtt_free(proto->ctx, addr);
+}
+// Clears the page table entries for the GTT allocation given by |addr|.
+static inline zx_status_t zx_intel_gpu_core_gtt_clear(const zx_intel_gpu_core_protocol_t* proto,
+                                                      uint64_t addr) {
+    return proto->ops->gtt_clear(proto->ctx, addr);
+}
+// Inserts page tables entries for the GTT allocation given by |addr| for the vmo represented by
+// handle |buffer|, at the given |page_offset| and |page_count|. Takes ownership of |buffer|.
+static inline zx_status_t zx_intel_gpu_core_gtt_insert(const zx_intel_gpu_core_protocol_t* proto,
+                                                       uint64_t addr, zx_handle_t buffer,
+                                                       uint64_t page_offset, uint64_t page_count) {
+    return proto->ops->gtt_insert(proto->ctx, addr, buffer, page_offset, page_count);
+}
+
+#define IMAGE_TYPE_YF_TILED UINT32_C(3)
+
+#define IMAGE_TYPE_Y_LEGACY_TILED UINT32_C(2)
 
 __END_CDECLS;
diff --git a/system/ulib/ddk/include/ddk/protocol/intel-hda-codec.h b/system/ulib/ddk/include/ddk/protocol/intel-hda-codec.h
index d786a0d..6155275 100644
--- a/system/ulib/ddk/include/ddk/protocol/intel-hda-codec.h
+++ b/system/ulib/ddk/include/ddk/protocol/intel-hda-codec.h
@@ -1,7 +1,9 @@
-// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
 #include <zircon/compiler.h>
@@ -9,15 +11,25 @@
 
 __BEGIN_CDECLS;
 
+// Forward declarations
+
+typedef struct ihda_codec_protocol ihda_codec_protocol_t;
+
+// Declarations
+
 typedef struct ihda_codec_protocol_ops {
-    // Fetch a zx_handle_t to a channel which can be used to communicate with the codec device.
-    zx_status_t (*get_driver_channel)(void* ctx, zx_handle_t* channel_out);
+    zx_status_t (*get_driver_channel)(void* ctx, zx_handle_t* out_channel);
 } ihda_codec_protocol_ops_t;
 
-typedef struct ihda_codec_protocol {
+struct ihda_codec_protocol {
     ihda_codec_protocol_ops_t* ops;
     void* ctx;
-} ihda_codec_protocol_t;
+};
+
+// Fetch a zx_handle_t to a channel which can be used to communicate with the codec device.
+static inline zx_status_t ihda_codec_get_driver_channel(const ihda_codec_protocol_t* proto,
+                                                        zx_handle_t* out_channel) {
+    return proto->ops->get_driver_channel(proto->ctx, out_channel);
+}
 
 __END_CDECLS;
-
diff --git a/system/ulib/ddk/include/ddk/protocol/intel-hda-dsp.h b/system/ulib/ddk/include/ddk/protocol/intel-hda-dsp.h
index 5793931..0fca5c8 100644
--- a/system/ulib/ddk/include/ddk/protocol/intel-hda-dsp.h
+++ b/system/ulib/ddk/include/ddk/protocol/intel-hda-dsp.h
@@ -2,81 +2,76 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
 #include <zircon/compiler.h>
 #include <zircon/types.h>
-#include <zircon/syscalls/pci.h>
 
 __BEGIN_CDECLS;
 
-// Key to get NHLT metadata
-#define MD_KEY_NHLT 'NHLT'
+// Forward declarations
 
-typedef void (ihda_dsp_irq_callback_t)(void* cookie);
+typedef struct ihda_dsp_irq ihda_dsp_irq_t;
+typedef struct ihda_dsp_protocol ihda_dsp_protocol_t;
+
+// Declarations
+
+#define MD_KEY_NHLT "NHLT"
+
+struct ihda_dsp_irq {
+    void (*callback)(void* ctx);
+    void* ctx;
+};
 
 typedef struct ihda_dsp_protocol_ops {
-    // Fetch the parent HDA controller's PCI device info
-    void (*get_dev_info)(void* ctx, zx_pcie_device_info_t* out_info);
-
-    // Fetch a VMO that represents the BAR holding the Audio DSP registers.
+    void (*get_dev_info)(void* ctx, zx_pcie_device_info_t* out_out);
     zx_status_t (*get_mmio)(void* ctx, zx_handle_t* out_vmo, size_t* out_size);
-
-    // Fetch a handle to our bus transaction initiator.
-    zx_status_t (*get_bti)(void* ctx, zx_handle_t* out_handle);
-
-    // Enables DSP
+    zx_status_t (*get_bti)(void* ctx, zx_handle_t* out_bti);
     void (*enable)(void* ctx);
-
-    // Disable DSP
     void (*disable)(void* ctx);
-
-    // Enables DSP interrupts and set a callback to be invoked when an interrupt is
-    // raised.
-    // Returns ZX_ERR_ALREADY_EXISTS if a callback is already set.
-    zx_status_t (*irq_enable)(void* ctx, ihda_dsp_irq_callback_t* callback, void* cookie);
-
-    // Disable DSP interrupts and clears the callback.
+    zx_status_t (*irq_enable)(void* ctx, const ihda_dsp_irq_t* callback);
     void (*irq_disable)(void* ctx);
 } ihda_dsp_protocol_ops_t;
 
-typedef struct ihda_dsp_protocol {
+struct ihda_dsp_protocol {
     ihda_dsp_protocol_ops_t* ops;
     void* ctx;
-} ihda_dsp_protocol_t;
+};
 
-static inline void ihda_dsp_get_dev_info(const ihda_dsp_protocol_t* ihda_dsp,
-                                         zx_pcie_device_info_t* out_info) {
-    ihda_dsp->ops->get_dev_info(ihda_dsp->ctx, out_info);
+// Fetch the parent HDA controller's PCI device info.
+static inline void ihda_dsp_get_dev_info(const ihda_dsp_protocol_t* proto,
+                                         zx_pcie_device_info_t* out_out) {
+    proto->ops->get_dev_info(proto->ctx, out_out);
 }
-
-static inline zx_status_t ihda_dsp_get_mmio(const ihda_dsp_protocol_t* ihda_dsp,
-                                            zx_handle_t* out_vmo,
+// Fetch a VMO that represents the BAR holding the Audio DSP registers.
+static inline zx_status_t ihda_dsp_get_mmio(const ihda_dsp_protocol_t* proto, zx_handle_t* out_vmo,
                                             size_t* out_size) {
-    return ihda_dsp->ops->get_mmio(ihda_dsp->ctx, out_vmo, out_size);
+    return proto->ops->get_mmio(proto->ctx, out_vmo, out_size);
 }
-
-static inline zx_status_t ihda_dsp_get_bti(const ihda_dsp_protocol_t* ihda_dsp,
-                                           zx_handle_t* out_handle) {
-    return ihda_dsp->ops->get_bti(ihda_dsp->ctx, out_handle);
+// Fetch a handle to our bus transaction initiator.
+static inline zx_status_t ihda_dsp_get_bti(const ihda_dsp_protocol_t* proto, zx_handle_t* out_bti) {
+    return proto->ops->get_bti(proto->ctx, out_bti);
 }
-
-static inline void ihda_dsp_enable(const ihda_dsp_protocol_t* ihda_dsp) {
-    return ihda_dsp->ops->enable(ihda_dsp->ctx);
+// Enables DSP
+static inline void ihda_dsp_enable(const ihda_dsp_protocol_t* proto) {
+    proto->ops->enable(proto->ctx);
 }
-
-static inline void ihda_dsp_disable(const ihda_dsp_protocol_t* ihda_dsp) {
-    return ihda_dsp->ops->disable(ihda_dsp->ctx);
+// Disable DSP
+static inline void ihda_dsp_disable(const ihda_dsp_protocol_t* proto) {
+    proto->ops->disable(proto->ctx);
 }
-
-static inline zx_status_t ihda_dsp_irq_enable(const ihda_dsp_protocol_t* ihda_dsp,
-                                              ihda_dsp_irq_callback_t* callback,
-                                              void* cookie) {
-    return ihda_dsp->ops->irq_enable(ihda_dsp->ctx, callback, cookie);
+// Enables DSP interrupts and set a callback to be invoked when an interrupt is
+// raised.
+// Returns `ZX_ERR_ALREADY_EXISTS` if a callback is already set.
+static inline zx_status_t ihda_dsp_irq_enable(const ihda_dsp_protocol_t* proto,
+                                              const ihda_dsp_irq_t* callback) {
+    return proto->ops->irq_enable(proto->ctx, callback);
 }
-
-static inline void ihda_dsp_irq_disable(const ihda_dsp_protocol_t* ihda_dsp) {
-    ihda_dsp->ops->irq_disable(ihda_dsp->ctx);
+// Disable DSP interrupts and clears the callback.
+static inline void ihda_dsp_irq_disable(const ihda_dsp_protocol_t* proto) {
+    proto->ops->irq_disable(proto->ctx);
 }
 
 __END_CDECLS;
diff --git a/system/ulib/ddk/include/ddk/protocol/iommu.h b/system/ulib/ddk/include/ddk/protocol/iommu.h
index decb994..c9ab1f6 100644
--- a/system/ulib/ddk/include/ddk/protocol/iommu.h
+++ b/system/ulib/ddk/include/ddk/protocol/iommu.h
@@ -2,30 +2,34 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
 #include <zircon/compiler.h>
 #include <zircon/types.h>
-#include <lib/sync/completion.h>
-
-#include <string.h>
 
 __BEGIN_CDECLS;
 
-typedef struct {
+// Forward declarations
+
+typedef struct iommu_protocol iommu_protocol_t;
+
+// Declarations
+
+typedef struct iommu_protocol_ops {
     zx_status_t (*get_bti)(void* ctx, uint32_t iommu_index, uint32_t bti_id,
                            zx_handle_t* out_handle);
 } iommu_protocol_ops_t;
 
-typedef struct {
+struct iommu_protocol {
     iommu_protocol_ops_t* ops;
     void* ctx;
-} iommu_protocol_t;
+};
 
-// Returns a bus transaction initiator handle for the given index
-static inline zx_status_t iommu_get_bti(iommu_protocol_t* iommu, uint32_t iommu_index,
+static inline zx_status_t iommu_get_bti(const iommu_protocol_t* proto, uint32_t iommu_index,
                                         uint32_t bti_id, zx_handle_t* out_handle) {
-    return iommu->ops->get_bti(iommu->ctx, iommu_index, bti_id, out_handle);
+    return proto->ops->get_bti(proto->ctx, iommu_index, bti_id, out_handle);
 }
 
 __END_CDECLS;
diff --git a/system/ulib/ddk/include/ddk/protocol/mailbox.h b/system/ulib/ddk/include/ddk/protocol/mailbox.h
index 445f7d4..12d61db 100644
--- a/system/ulib/ddk/include/ddk/protocol/mailbox.h
+++ b/system/ulib/ddk/include/ddk/protocol/mailbox.h
@@ -2,38 +2,49 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
 #include <zircon/compiler.h>
 #include <zircon/types.h>
 
 __BEGIN_CDECLS;
-typedef struct {
-    uint32_t    cmd;
-    uint32_t    tx_size;
-    void*       tx_buf;
-} mailbox_data_buf_t;
 
-typedef struct {
-    uint32_t    mailbox;
-    uint32_t    rx_size;
-    void *      rx_buf;
-} mailbox_channel_t;
+// Forward declarations
 
-typedef struct {
-    zx_status_t (*send_cmd)(void* ctx, mailbox_channel_t* channel,
-                 mailbox_data_buf_t* mdata);
+typedef struct mailbox_data_buf mailbox_data_buf_t;
+typedef struct mailbox_channel mailbox_channel_t;
+typedef struct mailbox_protocol mailbox_protocol_t;
+
+// Declarations
+
+struct mailbox_data_buf {
+    uint32_t cmd;
+    void* tx_buffer;
+    size_t tx_size;
+};
+
+struct mailbox_channel {
+    uint32_t mailbox;
+    void* rx_buffer;
+    size_t rx_size;
+};
+
+typedef struct mailbox_protocol_ops {
+    zx_status_t (*send_command)(void* ctx, const mailbox_channel_t* channel,
+                                const mailbox_data_buf_t* mdata);
 } mailbox_protocol_ops_t;
 
-typedef struct {
+struct mailbox_protocol {
     mailbox_protocol_ops_t* ops;
     void* ctx;
-} mailbox_protocol_t;
+};
 
-// sends a command via the mailbox
-static inline zx_status_t mailbox_send_cmd(mailbox_protocol_t* mailbox,
-                                           mailbox_channel_t* channel,
-                                           mailbox_data_buf_t* mdata) {
-    return mailbox->ops->send_cmd(mailbox->ctx, channel, mdata);
+static inline zx_status_t mailbox_send_command(const mailbox_protocol_t* proto,
+                                               const mailbox_channel_t* channel,
+                                               const mailbox_data_buf_t* mdata) {
+    return proto->ops->send_command(proto->ctx, channel, mdata);
 }
+
 __END_CDECLS;
diff --git a/system/ulib/ddk/include/ddk/protocol/nand.h b/system/ulib/ddk/include/ddk/protocol/nand.h
index 227699d..bccb103 100644
--- a/system/ulib/ddk/include/ddk/protocol/nand.h
+++ b/system/ulib/ddk/include/ddk/protocol/nand.h
@@ -2,131 +2,152 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
-#include <assert.h>
-#include <stdint.h>
-
+#include <zircon/compiler.h>
 #include <zircon/device/nand.h>
 #include <zircon/types.h>
 
-// nand_op_t's are submitted for processing via the queue() method of the
-// nand_protocol. Once submitted, the contents of the nand_op_t may be modified
+__BEGIN_CDECLS;
+
+// Forward declarations
+
+// NandOperation's are submitted for processing via the queue() method of the
+// Nand Protocol. Once submitted, the contents of the NandOperation may be modified
 // while it's being processed.
-//
 // The completion_cb() must eventually be called upon success or failure and
 // at that point the cookie field must contain whatever value was in it when
-// the nand_op_t was originally queued.
-//
+// the NandOperation was originally queued.
 // Any mention of "in pages" in this file means nand pages, as reported by
 // nand_info.page_size, as opposed to physical memory pages (RAM). That's true
 // even for vmo-related values.
-//
 // corrected_bit_flips are always related to nand_info.ecc_bits, so it is
 // possible to obtain a value that is larger than what is being read (in the oob
 // case). On the other hand, if errors cannot be corrected, the operation will
 // fail, and corrected_bit_flips will be undefined.
-
 // NOTE: The protocol can be extended with barriers to support controllers that
 // may issue multiple simultaneous request to the IO chips.
+typedef uint32_t nand_op_t;
+#define NAND_OP_READ UINT32_C(1)
+#define NAND_OP_WRITE UINT32_C(2)
+#define NAND_OP_ERASE UINT32_C(3)
 
-#define NAND_OP_READ                    0x00000001
-#define NAND_OP_WRITE                   0x00000002
-#define NAND_OP_ERASE                   0x00000003
+typedef struct nand_read_write nand_read_write_t;
+typedef struct nand_erase nand_erase_t;
+typedef union nand_operation nand_operation_t;
+typedef struct nand_protocol nand_protocol_t;
+typedef void (*nand_queue_callback)(void* ctx, zx_status_t s, nand_operation_t* op);
 
-typedef struct nand_op nand_op_t;
+// Declarations
 
-struct nand_op {
-    union {
-        // All Commands.
-        uint32_t command;                // Command.
+// A single operation can read or write an arbitrary number of pages,
+// including out of band (OOB) data for each page. If either regular
+// data or OOB is not required, the relevant VMO handle should be set to
+// ZX_HANDLE_INVALID.
+// Note that length dictates the number of pages to access, regardless
+// of the type of data requested: regular data, OOB or both.
+// The OOB data will be copied to (and from) a contiguous memory range
+// starting at the given offset. Note that said offset is given in nand
+// pages even though OOB is just a handful of bytes per page. In other
+// words, after said offset, the OOB data for each page is located
+// nand_info.oob_size bytes apart.
+// For example, to read 5 pages worth of data + OOB, with page size of
+// 2 kB and 16 bytes of OOB per page, setting:
+//     data_vmo = oob_vmo = vmo_handle
+//     length = 5
+//     offset_nand = 20
+//     offset_data_vmo = 0
+//     offset_oob_vmo = 5
+// will transfer pages [20, 24] to the first 2048 * 5 bytes of the vmo,
+// followed by 16 * 5 bytes of OOB data starting at offset 2048 * 5.
+struct nand_read_write {
+    // Command.
+    nand_op_t command;
+    // vmo of data to read or write.
+    zx_handle_t data_vmo;
+    // vmo of OOB data to read or write.
+    zx_handle_t oob_vmo;
+    // Number of pages to access.
+    // (0 is invalid).
+    uint32_t length;
+    // Offset into nand, in pages.
+    uint32_t offset_nand;
+    // Data vmo offset in (nand) pages.
+    uint64_t offset_data_vmo;
+    // OOB vmo offset in (nand) pages.
+    uint64_t offset_oob_vmo;
+    // Optional physical page list.
+    uint64_t* page_list;
+    size_t page_count;
+    // Return value from READ_DATA, max corrected bit flips in any
+    // underlying ECC chunk read. The caller can compare this value
+    // against ecc_bits to decide whether the nand erase block needs to
+    // be recycled.
+    uint32_t corrected_bit_flips;
+};
 
-        // NAND_OP_READ, NAND_OP_WRITE.
-        //
-        // A single operation can read or write an arbitrary number of pages,
-        // including out of band (OOB) data for each page. If either regular
-        // data or OOB is not required, the relevant VMO handle should be set to
-        // ZX_HANDLE_INVALID.
-        //
-        // Note that length dictates the number of pages to access, regardless
-        // of the type of data requested: regular data, OOB or both.
-        //
-        // The OOB data will be copied to (and from) a contiguous memory range
-        // starting at the given offset. Note that said offset is given in nand
-        // pages even though OOB is just a handful of bytes per page. In other
-        // words, after said offset, the OOB data for each page is located
-        // nand_info.oob_size bytes apart.
-        //
-        // For example, to read 5 pages worth of data + OOB, with page size of
-        // 2 kB and 16 bytes of OOB per page, setting:
-        //
-        //     data_vmo = oob_vmo = vmo_handle
-        //     length = 5
-        //     offset_nand = 20
-        //     offset_data_vmo = 0
-        //     offset_oob_vmo = 5
-        //
-        // will transfer pages [20, 24] to the first 2048 * 5 bytes of the vmo,
-        // followed by 16 * 5 bytes of OOB data starting at offset 2048 * 5.
-        //
-        struct {
-            uint32_t command;            // Command.
-            zx_handle_t data_vmo;        // vmo of data to read or write.
-            zx_handle_t oob_vmo;         // vmo of OOB data to read or write.
-            uint32_t length;             // Number of pages to access.
-                                         // (0 is invalid).
-            uint32_t offset_nand;        // Offset into nand, in pages.
-            uint64_t offset_data_vmo;    // Data vmo offset in (nand) pages.
-            uint64_t offset_oob_vmo;     // OOB vmo offset in (nand) pages.
-            uint64_t* pages;             // Optional physical page list.
-            // Return value from READ_DATA, max corrected bit flips in any
-            // underlying ECC chunk read. The caller can compare this value
-            // against ecc_bits to decide whether the nand erase block needs to
-            // be recycled.
-            uint32_t corrected_bit_flips;
-        } rw;
+struct nand_erase {
+    // Command.
+    nand_op_t command;
+    // Offset into nand, in erase blocks.
+    uint32_t first_block;
+    // Number of blocks to erase.
+    // (0 is invalid).
+    uint32_t num_blocks;
+};
 
-        // NAND_OP_ERASE.
-        struct {
-            uint32_t command;            // Command.
-            uint32_t first_block;        // Offset into nand, in erase blocks.
-            uint32_t num_blocks;         // Number of blocks to erase.
-                                         // (0 is invalid).
-        } erase;
-    };
-
-    // The completion_cb() will be called when the nand operation succeeds or
-    // fails.
-    void (*completion_cb)(nand_op_t* op, zx_status_t status);
-
-    // This is a caller-owned field that is not modified by the driver stack.
-    void *cookie;
+union nand_operation {
+    // All Commands.
+    nand_op_t command;
+    // NAND_OP_READ, NAND_OP_WRITE.
+    nand_read_write_t rw;
+    // NAND_OP_ERASE.
+    nand_erase_t erase;
 };
 
 typedef struct nand_protocol_ops {
-    // Obtains the parameters of the nand device (nand_info_t) and the required
-    // size of nand_op_t. The nand_op_t's submitted via queue() must have
-    // nand_op_size_out - sizeof(nand_op_t) bytes available at the end of the
-    // structure for the use of the driver.
-    void (*query)(void* ctx, nand_info_t* info_out, size_t* nand_op_size_out);
-
-    // Submits an IO request for processing. Success or failure will be reported
-    // via the completion_cb() in the nand_op_t. The callback may be called
-    // before the queue() method returns.
-    void (*queue)(void* ctx, nand_op_t* op);
-
-    // Gets the list of bad erase blocks, as reported by the nand manufacturer.
-    // The caller must allocate a table large enough to hold the expected number
-    // of entries, and pass the size of that table on |bad_block_len|.
-    // On return, |num_bad_blocks| contains the number of bad blocks found.
-    // This should only be called before writing any data to the nand, and the
-    // returned data should be saved somewhere else, along blocks that become
-    // bad after they've been in use.
-    zx_status_t (*get_factory_bad_block_list)(void* ctx, uint32_t* bad_blocks,
-                                              uint32_t bad_block_len, uint32_t* num_bad_blocks);
+    void (*query)(void* ctx, nand_info_t* out_info, size_t* out_nand_op_size);
+    void (*queue)(void* ctx, nand_operation_t* op, nand_queue_callback callback, void* cookie);
+    zx_status_t (*get_factory_bad_block_list)(void* ctx, uint32_t* out_bad_blocks_list,
+                                              size_t bad_blocks_count,
+                                              size_t* out_bad_blocks_actual);
 } nand_protocol_ops_t;
 
-typedef struct nand_protocol {
+struct nand_protocol {
     nand_protocol_ops_t* ops;
     void* ctx;
-} nand_protocol_t;
+};
+
+// Obtains the parameters of the nand device (nand_info_t) and the required
+// size of nand_op_t. The nand_op_t's submitted via queue() must have
+// nand_op_size_out - sizeof(nand_op_t) bytes available at the end of the
+// structure for the use of the driver.
+static inline void nand_query(const nand_protocol_t* proto, nand_info_t* out_info,
+                              size_t* out_nand_op_size) {
+    proto->ops->query(proto->ctx, out_info, out_nand_op_size);
+}
+// Submits an IO request for processing. Success or failure will be reported
+// via the completion_cb() in the nand_op_t. The callback may be called
+// before the queue() method returns.
+static inline void nand_queue(const nand_protocol_t* proto, nand_operation_t* op,
+                              nand_queue_callback callback, void* cookie) {
+    proto->ops->queue(proto->ctx, op, callback, cookie);
+}
+// Gets the list of bad erase blocks, as reported by the nand manufacturer.
+// The caller must allocate a table large enough to hold the expected number
+// of entries, and pass the size of that table on |bad_block_len|.
+// On return, |num_bad_blocks| contains the number of bad blocks found.
+// This should only be called before writing any data to the nand, and the
+// returned data should be saved somewhere else, along blocks that become
+// bad after they've been in use.
+static inline zx_status_t nand_get_factory_bad_block_list(const nand_protocol_t* proto,
+                                                          uint32_t* out_bad_blocks_list,
+                                                          size_t bad_blocks_count,
+                                                          size_t* out_bad_blocks_actual) {
+    return proto->ops->get_factory_bad_block_list(proto->ctx, out_bad_blocks_list, bad_blocks_count,
+                                                  out_bad_blocks_actual);
+}
+
+__END_CDECLS;
diff --git a/system/ulib/ddk/include/ddk/protocol/pci-lib.h b/system/ulib/ddk/include/ddk/protocol/pci-lib.h
new file mode 100644
index 0000000..7069ede
--- /dev/null
+++ b/system/ulib/ddk/include/ddk/protocol/pci-lib.h
@@ -0,0 +1,54 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+#include <ddk/protocol/pci.h>
+
+__BEGIN_CDECLS;
+
+static inline zx_status_t pci_config_read8(const pci_protocol_t* pci,
+                                           uint16_t offset, uint8_t* value) {
+    uint32_t value_;
+    zx_status_t st = pci->ops->config_read(pci->ctx, offset, sizeof(uint8_t), &value_);
+    *value = value_ & UINT8_MAX;
+    return st;
+}
+
+static inline zx_status_t pci_config_read16(const pci_protocol_t* pci,
+                                            uint16_t offset, uint16_t* value) {
+    uint32_t value_;
+    zx_status_t st = pci->ops->config_read(pci->ctx, offset, sizeof(uint16_t), &value_);
+    *value = value_ & UINT16_MAX;
+    return st;
+}
+
+static inline zx_status_t pci_config_read32(const pci_protocol_t* pci,
+                                            uint16_t offset, uint32_t* value) {
+    return pci->ops->config_read(pci->ctx, offset, sizeof(uint32_t), value);
+}
+
+static inline zx_status_t pci_config_write8(const pci_protocol_t* pci,
+                                            uint16_t offset, uint8_t value) {
+    return pci->ops->config_write(pci->ctx, offset, sizeof(uint8_t), value);
+}
+
+static inline zx_status_t pci_config_write16(const pci_protocol_t* pci,
+                                             uint16_t offset, uint16_t value) {
+    return pci->ops->config_write(pci->ctx, offset, sizeof(uint16_t), value);
+}
+
+static inline zx_status_t pci_config_write32(const pci_protocol_t* pci,
+                                             uint16_t offset, uint32_t value) {
+    return pci->ops->config_write(pci->ctx, offset, sizeof(uint32_t), value);
+}
+
+static inline uint8_t pci_get_first_capability(const pci_protocol_t* pci, uint8_t type) {
+    // the next_capability method will always look at the second byte next
+    // pointer to fetch the next capability. By offsetting the CapPtr field
+    // by -1 we can pretend we're working with a normal capability entry
+    return pci_get_next_capability(pci, PCI_CFG_CAPABILITIES_PTR - 1u, type);
+}
+
+__END_CDECLS;
diff --git a/system/ulib/ddk/include/ddk/protocol/pci.h b/system/ulib/ddk/include/ddk/protocol/pci.h
index 36dd50a..5f8c8c0 100644
--- a/system/ulib/ddk/include/ddk/protocol/pci.h
+++ b/system/ulib/ddk/include/ddk/protocol/pci.h
@@ -1,174 +1,127 @@
-// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
+
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
-#include <ddk/protocol/auxdata.h>
-#include <hw/pci.h>
 #include <zircon/compiler.h>
 #include <zircon/syscalls/pci.h>
 #include <zircon/types.h>
 
 __BEGIN_CDECLS;
 
-/**
- * protocols/pci.h - PCI protocol definitions
- *
- * The PCI host driver publishes zx_device_t's with its config set to a pci_device_config_t.
- */
+// Forward declarations
 
-enum pci_header_fields {
-    kPciCfgVendorId = 0x00,
-    kPciCfgDeviceId = 0x02,
-    kPciCfgRevisionId = 0x08,
-    kPciCfgClassCode = 0x09,
-    kPciCfgSubsystemVendorId = 0x2C,
-    kPciCfgSubsystemId = 0x2E,
-    kPciCfgCapabilitiesPtr = 0x34,
-};
+typedef struct pci_protocol pci_protocol_t;
+typedef uint16_t pci_cfg_t;
+#define PCI_CFG_VENDOR_ID UINT16_C(0)
+#define PCI_CFG_DEVICE_ID UINT16_C(2)
+#define PCI_CFG_REVISION_ID UINT16_C(8)
+#define PCI_CFG_CLASS_CODE UINT16_C(9)
+#define PCI_CFG_SUBSYSTEM_VENDOR_ID UINT16_C(44)
+#define PCI_CFG_SUBSYSTEM_ID UINT16_C(46)
+#define PCI_CFG_CAPABILITIES_PTR UINT16_C(52)
 
-enum pci_cap_types {
-    kPciCapIdNull = 0x00,
-    kPciCapIdPciPwrMgmt = 0x01,
-    kPciCapIdAgp = 0x02,
-    kPciCapIdVpd = 0x03,
-    kPciCapIdMsi = 0x05,
-    kPciCapIdPcix = 0x07,
-    kPciCapIdHypertransport = 0x08,
-    kPciCapIdVendor = 0x09,
-    kPciCapIdDebugPort = 0x0A,
-    kPciCapIdCompactPciCrc = 0x0B,
-    kPciCapIdPciHotplug = 0x0C,
-    kPciCapIdPciBridgeSubsystemVid = 0x0D,
-    kPciCapIdAgp8x = 0x0E,
-    kPciCapIdSecureDevice = 0x0F,
-    kPciCapIdPciExpress = 0x10,
-    kPciCapIdMsix = 0x11,
-    kPciCapIdSataDataNdxCfg = 0x12,
-    kPciCapIdAdvancedFeatures = 0x13,
-    kPciCapIdEnhancedAllocation = 0x14,
-};
+typedef uint8_t pci_cap_id_t;
+#define PCI_CAP_ID_NULL UINT8_C(0)
+#define PCI_CAP_ID_PCI_PWR_MGMT UINT8_C(1)
+#define PCI_CAP_ID_AGP UINT8_C(2)
+#define PCI_CAP_ID_VPD UINT8_C(3)
+#define PCI_CAP_ID_MSI UINT8_C(5)
+#define PCI_CAP_ID_PCIX UINT8_C(7)
+#define PCI_CAP_ID_HYPERTRANSPORT UINT8_C(8)
+#define PCI_CAP_ID_VENDOR UINT8_C(9)
+#define PCI_CAP_ID_DEBUG_PORT UINT8_C(10)
+#define PCI_CAP_ID_COMPACT_PCI_CRC UINT8_C(11)
+#define PCI_CAP_ID_PCI_HOT_PLUG UINT8_C(12)
+#define PCI_CAP_ID_PCI_BRIDGE_SUBSYSTEM_VID UINT8_C(13)
+#define PCI_CAP_ID_AGP8X UINT8_C(14)
+#define PCI_CAP_ID_SECURE_DEVICE UINT8_C(15)
+#define PCI_CAP_ID_PCI_EXPRESS UINT8_C(16)
+#define PCI_CAP_ID_MSIX UINT8_C(17)
+#define PCI_CAP_ID_SATA_DATA_NDX_CFG UINT8_C(18)
+#define PCI_CAP_ID_ADVANCED_FEATURES UINT8_C(19)
+#define PCI_CAP_ID_ENHANCED_ALLOCATION UINT8_C(20)
 
+// Declarations
 
 typedef struct pci_protocol_ops {
-    zx_status_t (*get_bar)(void* ctx, uint32_t bar_id,  zx_pci_bar_t* out_res);
+    zx_status_t (*get_bar)(void* ctx, uint32_t bar_id, zx_pci_bar_t* out_res);
     zx_status_t (*map_bar)(void* ctx, uint32_t bar_id, uint32_t cache_policy,
-                                void** vaddr, size_t* size, zx_handle_t* out_handle);
+                           void** out_vaddr_buffer, size_t* vaddr_size, zx_handle_t* out_handle);
     zx_status_t (*enable_bus_master)(void* ctx, bool enable);
     zx_status_t (*reset_device)(void* ctx);
-    zx_status_t (*map_interrupt)(void* ctx, int which_irq, zx_handle_t* out_handle);
-    zx_status_t (*query_irq_mode)(void* ctx, zx_pci_irq_mode_t mode,
-                                       uint32_t* out_max_irqs);
-    zx_status_t (*set_irq_mode)(void* ctx, zx_pci_irq_mode_t mode,
-                                uint32_t requested_irq_count);
-    zx_status_t (*get_device_info)(void* ctx, zx_pcie_device_info_t* out_info);
-    zx_status_t (*config_read)(void* ctx, uint16_t offset, size_t width, uint32_t* value);
+    zx_status_t (*map_interrupt)(void* ctx, zx_status_t which_irq, zx_handle_t* out_handle);
+    zx_status_t (*query_irq_mode)(void* ctx, zx_pci_irq_mode_t mode, uint32_t* out_max_irqs);
+    zx_status_t (*set_irq_mode)(void* ctx, zx_pci_irq_mode_t mode, uint32_t requested_irq_count);
+    zx_status_t (*get_device_info)(void* ctx, zx_pcie_device_info_t* out_into);
+    zx_status_t (*config_read)(void* ctx, uint16_t offset, size_t width, uint32_t* out_value);
     zx_status_t (*config_write)(void* ctx, uint16_t offset, size_t width, uint32_t value);
-    uint8_t     (*get_next_capability)(void* ctx, uint8_t type, uint8_t offset);
-    zx_status_t (*get_auxdata)(void* ctx, const char* args,
-                               void* data, uint32_t bytes, uint32_t* actual);
-    zx_status_t (*get_bti)(void* ctx, uint32_t index, zx_handle_t* out_handle);
+    uint8_t (*get_next_capability)(void* ctx, uint8_t type, uint8_t offset);
+    zx_status_t (*get_auxdata)(void* ctx, const char* args, void* out_data_buffer, size_t data_size,
+                               size_t* out_data_actual);
+    zx_status_t (*get_bti)(void* ctx, uint32_t index, zx_handle_t* out_bti);
 } pci_protocol_ops_t;
-typedef struct pci_protocol {
+
+struct pci_protocol {
     pci_protocol_ops_t* ops;
     void* ctx;
-} pci_protocol_t;
+};
 
-static inline zx_status_t pci_get_bar(const pci_protocol_t* pci, uint32_t res_id,
-                                      zx_pci_bar_t* out_info) {
-    return pci->ops->get_bar(pci->ctx, res_id, out_info);
+static inline zx_status_t pci_get_bar(const pci_protocol_t* proto, uint32_t bar_id,
+                                      zx_pci_bar_t* out_res) {
+    return proto->ops->get_bar(proto->ctx, bar_id, out_res);
 }
-
-static inline zx_status_t pci_map_bar(const pci_protocol_t* pci, uint32_t bar_id,
-                                      uint32_t cache_policy, void** vaddr, size_t* size,
-                                      zx_handle_t* out_handle) {
-    return pci->ops->map_bar(pci->ctx, bar_id, cache_policy, vaddr, size, out_handle);
+static inline zx_status_t pci_map_bar(const pci_protocol_t* proto, uint32_t bar_id,
+                                      uint32_t cache_policy, void** out_vaddr_buffer,
+                                      size_t* vaddr_size, zx_handle_t* out_handle) {
+    return proto->ops->map_bar(proto->ctx, bar_id, cache_policy, out_vaddr_buffer, vaddr_size,
+                               out_handle);
 }
-
-static inline zx_status_t pci_enable_bus_master(const pci_protocol_t* pci, bool enable) {
-    return pci->ops->enable_bus_master(pci->ctx, enable);
+static inline zx_status_t pci_enable_bus_master(const pci_protocol_t* proto, bool enable) {
+    return proto->ops->enable_bus_master(proto->ctx, enable);
 }
-
-static inline zx_status_t pci_get_bti(const pci_protocol_t* pci, uint32_t index, zx_handle_t* bti) {
-    return pci->ops->get_bti(pci->ctx, index, bti);
+static inline zx_status_t pci_reset_device(const pci_protocol_t* proto) {
+    return proto->ops->reset_device(proto->ctx);
 }
-
-static inline zx_status_t pci_reset_device(const pci_protocol_t* pci) {
-    return pci->ops->reset_device(pci->ctx);
-}
-
-static inline zx_status_t pci_map_interrupt(const pci_protocol_t* pci, int which_irq,
+static inline zx_status_t pci_map_interrupt(const pci_protocol_t* proto, zx_status_t which_irq,
                                             zx_handle_t* out_handle) {
-    return pci->ops->map_interrupt(pci->ctx, which_irq, out_handle);
+    return proto->ops->map_interrupt(proto->ctx, which_irq, out_handle);
 }
-
-static inline zx_status_t pci_query_irq_mode(const pci_protocol_t* pci, zx_pci_irq_mode_t mode,
+static inline zx_status_t pci_query_irq_mode(const pci_protocol_t* proto, zx_pci_irq_mode_t mode,
                                              uint32_t* out_max_irqs) {
-    return pci->ops->query_irq_mode(pci->ctx, mode, out_max_irqs);
+    return proto->ops->query_irq_mode(proto->ctx, mode, out_max_irqs);
 }
-
-static inline zx_status_t pci_set_irq_mode(const pci_protocol_t* pci, zx_pci_irq_mode_t mode,
+static inline zx_status_t pci_set_irq_mode(const pci_protocol_t* proto, zx_pci_irq_mode_t mode,
                                            uint32_t requested_irq_count) {
-    return pci->ops->set_irq_mode(pci->ctx, mode, requested_irq_count);
+    return proto->ops->set_irq_mode(proto->ctx, mode, requested_irq_count);
 }
-
-static inline zx_status_t pci_get_device_info(const pci_protocol_t* pci,
-                                              zx_pcie_device_info_t* out_info) {
-    return pci->ops->get_device_info(pci->ctx, out_info);
+static inline zx_status_t pci_get_device_info(const pci_protocol_t* proto,
+                                              zx_pcie_device_info_t* out_into) {
+    return proto->ops->get_device_info(proto->ctx, out_into);
 }
-
-static inline zx_status_t pci_config_read8(const pci_protocol_t* pci,
-                                           uint16_t offset, uint8_t* value) {
-    uint32_t value_;
-    zx_status_t st = pci->ops->config_read(pci->ctx, offset, sizeof(uint8_t), &value_);
-    *value = value_ & UINT8_MAX;
-    return st;
+static inline zx_status_t pci_config_read(const pci_protocol_t* proto, uint16_t offset,
+                                          size_t width, uint32_t* out_value) {
+    return proto->ops->config_read(proto->ctx, offset, width, out_value);
 }
-
-static inline zx_status_t pci_config_read16(const pci_protocol_t* pci,
-                                            uint16_t offset, uint16_t* value) {
-    uint32_t value_;
-    zx_status_t st = pci->ops->config_read(pci->ctx, offset, sizeof(uint16_t), &value_);
-    *value = value_ & UINT16_MAX;
-    return st;
+static inline zx_status_t pci_config_write(const pci_protocol_t* proto, uint16_t offset,
+                                           size_t width, uint32_t value) {
+    return proto->ops->config_write(proto->ctx, offset, width, value);
 }
-
-static inline zx_status_t pci_config_read32(const pci_protocol_t* pci,
-                                            uint16_t offset, uint32_t* value) {
-    return pci->ops->config_read(pci->ctx, offset, sizeof(uint32_t), value);
+static inline uint8_t pci_get_next_capability(const pci_protocol_t* proto, uint8_t type,
+                                              uint8_t offset) {
+    return proto->ops->get_next_capability(proto->ctx, type, offset);
 }
-
-static inline zx_status_t pci_config_write8(const pci_protocol_t* pci,
-                                            uint16_t offset, uint8_t value) {
-    return pci->ops->config_write(pci->ctx, offset, sizeof(uint8_t), value);
+static inline zx_status_t pci_get_auxdata(const pci_protocol_t* proto, const char* args,
+                                          void* out_data_buffer, size_t data_size,
+                                          size_t* out_data_actual) {
+    return proto->ops->get_auxdata(proto->ctx, args, out_data_buffer, data_size, out_data_actual);
 }
-
-static inline zx_status_t pci_config_write16(const pci_protocol_t* pci,
-                                             uint16_t offset, uint16_t value) {
-    return pci->ops->config_write(pci->ctx, offset, sizeof(uint16_t), value);
-}
-
-static inline zx_status_t pci_config_write32(const pci_protocol_t* pci,
-                                             uint16_t offset, uint32_t value) {
-    return pci->ops->config_write(pci->ctx, offset, sizeof(uint32_t), value);
-}
-
-static inline uint8_t pci_get_next_capability(const pci_protocol_t* pci,
-                                              uint8_t type, uint8_t offset) {
-    return pci->ops->get_next_capability(pci->ctx, type, offset);
-}
-
-static inline uint8_t pci_get_first_capability(const pci_protocol_t* pci, uint8_t type) {
-    // the next_capability method will always look at the second byte next
-    // pointer to fetch the next capability. By offsetting the CapPtr field
-    // by -1 we can pretend we're working with a normal capability entry
-    return pci_get_next_capability(pci, kPciCfgCapabilitiesPtr - 1u, type);
-}
-
-static inline zx_status_t pci_get_auxdata(const pci_protocol_t* pci,
-                                          const char* args, void* data,
-                                          uint32_t bytes, uint32_t* actual) {
-    return pci->ops->get_auxdata(pci->ctx, args, data, bytes, actual);
+static inline zx_status_t pci_get_bti(const pci_protocol_t* proto, uint32_t index,
+                                      zx_handle_t* out_bti) {
+    return proto->ops->get_bti(proto->ctx, index, out_bti);
 }
 
 __END_CDECLS;
diff --git a/system/ulib/ddk/include/ddk/protocol/pciroot.h b/system/ulib/ddk/include/ddk/protocol/pciroot.h
index e57b815..3d3c163 100644
--- a/system/ulib/ddk/include/ddk/protocol/pciroot.h
+++ b/system/ulib/ddk/include/ddk/protocol/pciroot.h
@@ -1,35 +1,41 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
-#include <ddk/protocol/auxdata.h>
 #include <zircon/compiler.h>
 #include <zircon/types.h>
 
 __BEGIN_CDECLS;
 
+// Forward declarations
+
+typedef struct pciroot_protocol pciroot_protocol_t;
+
+// Declarations
+
 typedef struct pciroot_protocol_ops {
-    zx_status_t (*get_auxdata)(void* ctx, const char* args, void* data,
-                               uint32_t bytes, uint32_t* actual);
-    zx_status_t (*get_bti)(void* ctx, uint32_t bdf, uint32_t index, zx_handle_t* bti);
+    zx_status_t (*get_auxdata)(void* ctx, const char* args, void* out_data_buffer, size_t data_size,
+                               size_t* out_data_actual);
+    zx_status_t (*get_bti)(void* ctx, uint32_t bdf, uint32_t index, zx_handle_t* out_bti);
 } pciroot_protocol_ops_t;
 
-typedef struct pciroot_protocol {
+struct pciroot_protocol {
     pciroot_protocol_ops_t* ops;
     void* ctx;
-} pciroot_protocol_t;
+};
 
-static inline zx_status_t pciroot_get_auxdata(pciroot_protocol_t* pciroot,
-                                              const char* args, void* data,
-                                              uint32_t bytes, uint32_t* actual) {
-    return pciroot->ops->get_auxdata(pciroot->ctx, args, data, bytes, actual);
+static inline zx_status_t pciroot_get_auxdata(const pciroot_protocol_t* proto, const char* args,
+                                              void* out_data_buffer, size_t data_size,
+                                              size_t* out_data_actual) {
+    return proto->ops->get_auxdata(proto->ctx, args, out_data_buffer, data_size, out_data_actual);
 }
-
-static inline zx_status_t pciroot_get_bti(pciroot_protocol_t* pciroot,
-                                          uint32_t bdf, uint32_t index, zx_handle_t* bti) {
-    return pciroot->ops->get_bti(pciroot->ctx, bdf, index, bti);
+static inline zx_status_t pciroot_get_bti(const pciroot_protocol_t* proto, uint32_t bdf,
+                                          uint32_t index, zx_handle_t* out_bti) {
+    return proto->ops->get_bti(proto->ctx, bdf, index, out_bti);
 }
 
 __END_CDECLS;
diff --git a/system/ulib/ddk/include/ddk/protocol/rawnand.h b/system/ulib/ddk/include/ddk/protocol/rawnand.h
index b67e5fa..7422e9f 100644
--- a/system/ulib/ddk/include/ddk/protocol/rawnand.h
+++ b/system/ulib/ddk/include/ddk/protocol/rawnand.h
@@ -2,77 +2,74 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
-#include <assert.h>
-#include <stdint.h>
-
 #include <zircon/compiler.h>
-#include <zircon/listnode.h>
-
-#include <ddk/protocol/nand.h>
+#include <zircon/device/nand.h>
+#include <zircon/types.h>
 
 __BEGIN_CDECLS;
 
+// Forward declarations
+
+typedef struct raw_nand_protocol raw_nand_protocol_t;
+
+// Declarations
+
 typedef struct raw_nand_protocol_ops {
-    // Read one nand page with hwecc.
-    zx_status_t (*read_page_hwecc)(void* ctx, void *data, void *oob,
-                                   uint32_t nandpage, int *ecc_correct);
-    // Write one nand page with hwecc.
-    zx_status_t (*write_page_hwecc)(void* ctx, const void* data, const void* oob,
-                                    uint32_t nandpage);
-    // Erase nand block.
+    zx_status_t (*read_page_hwecc)(void* ctx, uint32_t nandpage, void* out_data_buffer,
+                                   size_t data_size, size_t* out_data_actual, void* out_oob_buffer,
+                                   size_t oob_size, size_t* out_oob_actual,
+                                   zx_status_t* out_ecc_correct);
+    zx_status_t (*write_page_hwecc)(void* ctx, const void* data_buffer, size_t data_size,
+                                    const void* oob_buffer, size_t oob_size, uint32_t nandpage);
     zx_status_t (*erase_block)(void* ctx, uint32_t nandpage);
-    zx_status_t (*get_nand_info)(void *ctx, struct nand_info *info);
-    // Send ONFI command down to controller.
-    void (*cmd_ctrl)(void *ctx, int32_t cmd, uint32_t ctrl);
-    // Read byte (used to read status as well as other info, such as ID).
-    uint8_t (*read_byte)(void *ctx);
+    zx_status_t (*get_nand_info)(void* ctx, nand_info_t* out_info);
+    void (*cmd_ctrl)(void* ctx, zx_status_t cmd, uint32_t ctrl);
+    uint8_t (*read_byte)(void* ctx);
 } raw_nand_protocol_ops_t;
 
-typedef struct raw_nand_protocol {
-    raw_nand_protocol_ops_t *ops;
-    void *ctx;
-} raw_nand_protocol_t;
+struct raw_nand_protocol {
+    raw_nand_protocol_ops_t* ops;
+    void* ctx;
+};
 
-static inline zx_status_t raw_nand_read_page_hwecc(raw_nand_protocol_t *raw_nand,
-                                                   void *data, void *oob,
-                                                   uint32_t nand_page,
-                                                   int *ecc_correct)
-{
-    return raw_nand->ops->read_page_hwecc(raw_nand->ctx, data, oob, nand_page,
-                                         ecc_correct);
+// Read one nand page with hwecc.
+static inline zx_status_t
+raw_nand_read_page_hwecc(const raw_nand_protocol_t* proto, uint32_t nandpage, void* out_data_buffer,
+                         size_t data_size, size_t* out_data_actual, void* out_oob_buffer,
+                         size_t oob_size, size_t* out_oob_actual, zx_status_t* out_ecc_correct) {
+    return proto->ops->read_page_hwecc(proto->ctx, nandpage, out_data_buffer, data_size,
+                                       out_data_actual, out_oob_buffer, oob_size, out_oob_actual,
+                                       out_ecc_correct);
 }
-
-static inline zx_status_t raw_nand_write_page_hwecc(raw_nand_protocol_t* raw_nand,
-                                                    const void* data, const void* oob,
-                                                    uint32_t nand_page)
-{
-    return raw_nand->ops->write_page_hwecc(raw_nand->ctx, data, oob, nand_page);
+// Write one nand page with hwecc.
+static inline zx_status_t raw_nand_write_page_hwecc(const raw_nand_protocol_t* proto,
+                                                    const void* data_buffer, size_t data_size,
+                                                    const void* oob_buffer, size_t oob_size,
+                                                    uint32_t nandpage) {
+    return proto->ops->write_page_hwecc(proto->ctx, data_buffer, data_size, oob_buffer, oob_size,
+                                        nandpage);
 }
-
-static inline zx_status_t raw_nand_erase_block(raw_nand_protocol_t *raw_nand,
-                                               uint32_t nand_page)
-{
-    return raw_nand->ops->erase_block(raw_nand->ctx, nand_page);
+// Erase nand block.
+static inline zx_status_t raw_nand_erase_block(const raw_nand_protocol_t* proto,
+                                               uint32_t nandpage) {
+    return proto->ops->erase_block(proto->ctx, nandpage);
 }
-
-static inline zx_status_t raw_nand_get_info(raw_nand_protocol_t *raw_nand,
-                                            struct nand_info *info)
-{
-    return raw_nand->ops->get_nand_info(raw_nand->ctx, info);
+static inline zx_status_t raw_nand_get_nand_info(const raw_nand_protocol_t* proto,
+                                                 nand_info_t* out_info) {
+    return proto->ops->get_nand_info(proto->ctx, out_info);
 }
-
-static inline void raw_nand_cmd_ctrl(raw_nand_protocol_t *raw_nand,
-                                     int32_t cmd, uint32_t ctrl)
-{
-    raw_nand->ops->cmd_ctrl(raw_nand->ctx, cmd, ctrl);
+// Send ONFI command down to controller.
+static inline void raw_nand_cmd_ctrl(const raw_nand_protocol_t* proto, zx_status_t cmd,
+                                     uint32_t ctrl) {
+    proto->ops->cmd_ctrl(proto->ctx, cmd, ctrl);
 }
-
-static inline uint8_t raw_nand_read_byte(raw_nand_protocol_t *raw_nand)
-{
-    return raw_nand->ops->read_byte(raw_nand->ctx);
+// Read byte (used to read status as well as other info, such as ID).
+static inline uint8_t raw_nand_read_byte(const raw_nand_protocol_t* proto) {
+    return proto->ops->read_byte(proto->ctx);
 }
 
 __END_CDECLS;
-
diff --git a/system/ulib/ddk/include/ddk/protocol/scpi.h b/system/ulib/ddk/include/ddk/protocol/scpi.h
index 951acad..cd4c150 100644
--- a/system/ulib/ddk/include/ddk/protocol/scpi.h
+++ b/system/ulib/ddk/include/ddk/protocol/scpi.h
@@ -2,66 +2,69 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
 #include <zircon/compiler.h>
 #include <zircon/types.h>
 
-#define MAX_DVFS_OPPS       16
-
 __BEGIN_CDECLS;
 
-typedef struct {
+// Forward declarations
+
+typedef struct scpi_opp_entry scpi_opp_entry_t;
+typedef struct scpi_opp scpi_opp_t;
+typedef struct scpi_protocol scpi_protocol_t;
+
+// Declarations
+
+struct scpi_opp_entry {
     uint32_t freq_hz;
     uint32_t volt_mv;
-} __PACKED scpi_opp_entry_t;
+};
 
-typedef struct {
-    scpi_opp_entry_t opp[MAX_DVFS_OPPS];
-    uint32_t latency; /* in usecs */
+struct scpi_opp {
+    scpi_opp_entry_t opp[16];
+    // In usecs.
+    uint32_t latency;
     uint32_t count;
-} __PACKED scpi_opp_t;
+};
 
-typedef struct {
-    zx_status_t (*get_sensor)(void* ctx, const char* name, uint32_t* sensor_value);
-    zx_status_t (*get_sensor_value)(void* ctx, uint32_t sensor_id, uint32_t* sensor_value);
-    zx_status_t (*get_dvfs_info)(void* ctx, uint8_t power_domain, scpi_opp_t* opps);
-    zx_status_t (*get_dvfs_idx)(void* ctx, uint8_t power_domain, uint16_t* idx);
-    zx_status_t (*set_dvfs_idx)(void* ctx, uint8_t power_domain, uint16_t idx);
+typedef struct scpi_protocol_ops {
+    zx_status_t (*get_sensor)(void* ctx, const char* name, uint32_t* out_sensor_id);
+    zx_status_t (*get_sensor_value)(void* ctx, uint32_t sensor_id, uint32_t* out_sensor_value);
+    zx_status_t (*get_dvfs_info)(void* ctx, uint8_t power_domain, scpi_opp_t* out_opps);
+    zx_status_t (*get_dvfs_idx)(void* ctx, uint8_t power_domain, uint16_t* out_index);
+    zx_status_t (*set_dvfs_idx)(void* ctx, uint8_t power_domain, uint16_t index);
 } scpi_protocol_ops_t;
 
-typedef struct {
+struct scpi_protocol {
     scpi_protocol_ops_t* ops;
     void* ctx;
-} scpi_protocol_t;
+};
 
-// Get the sensor id
-static inline zx_status_t scpi_get_sensor(scpi_protocol_t* scpi, const char* name,
-                                          uint32_t* sensor_value) {
-    return scpi->ops->get_sensor(scpi->ctx, name, sensor_value);
+static inline zx_status_t scpi_get_sensor(const scpi_protocol_t* proto, const char* name,
+                                          uint32_t* out_sensor_id) {
+    return proto->ops->get_sensor(proto->ctx, name, out_sensor_id);
+}
+static inline zx_status_t scpi_get_sensor_value(const scpi_protocol_t* proto, uint32_t sensor_id,
+                                                uint32_t* out_sensor_value) {
+    return proto->ops->get_sensor_value(proto->ctx, sensor_id, out_sensor_value);
+}
+static inline zx_status_t scpi_get_dvfs_info(const scpi_protocol_t* proto, uint8_t power_domain,
+                                             scpi_opp_t* out_opps) {
+    return proto->ops->get_dvfs_info(proto->ctx, power_domain, out_opps);
+}
+static inline zx_status_t scpi_get_dvfs_idx(const scpi_protocol_t* proto, uint8_t power_domain,
+                                            uint16_t* out_index) {
+    return proto->ops->get_dvfs_idx(proto->ctx, power_domain, out_index);
+}
+static inline zx_status_t scpi_set_dvfs_idx(const scpi_protocol_t* proto, uint8_t power_domain,
+                                            uint16_t index) {
+    return proto->ops->set_dvfs_idx(proto->ctx, power_domain, index);
 }
 
-// Get the sensor id's value
-static inline zx_status_t scpi_get_sensor_value(scpi_protocol_t* scpi, uint32_t sensor_id,
-                                                uint32_t* sensor_value) {
-    return scpi->ops->get_sensor_value(scpi->ctx, sensor_id, sensor_value);
-}
+#define MAX_DVFS_OPPS UINT32_C(16)
 
-// Get the DVFS info
-static inline zx_status_t scpi_get_dvfs_info(scpi_protocol_t* scpi, uint8_t power_domain,
-                                             scpi_opp_t* opps) {
-    return scpi->ops->get_dvfs_info(scpi->ctx, power_domain, opps);
-}
-
-// Get the current operating point from DVFS table
-static inline zx_status_t scpi_get_dvfs_idx(scpi_protocol_t* scpi, uint8_t power_domain,
-                                            uint16_t* idx) {
-    return scpi->ops->get_dvfs_idx(scpi->ctx, power_domain, idx);
-}
-
-// Set a new operating point from the DVFS table
-static inline zx_status_t scpi_set_dvfs_idx(scpi_protocol_t* scpi, uint8_t power_domain,
-                                            uint16_t idx) {
-    return scpi->ops->set_dvfs_idx(scpi->ctx, power_domain, idx);
-}
 __END_CDECLS;
diff --git a/system/ulib/ddk/include/ddk/protocol/sdhci.h b/system/ulib/ddk/include/ddk/protocol/sdhci.h
index 7d5985b..f011dbb 100644
--- a/system/ulib/ddk/include/ddk/protocol/sdhci.h
+++ b/system/ulib/ddk/include/ddk/protocol/sdhci.h
@@ -1,7 +1,9 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
 #include <hw/sdhci.h>
@@ -10,44 +12,66 @@
 
 __BEGIN_CDECLS;
 
-typedef struct sdhci_protocol_ops {
-    // TODO: should be replaced with a generic busdev mechanism
-    zx_status_t (*get_interrupt)(void* ctx, zx_handle_t* handle_out);
-    zx_status_t (*get_mmio)(void* ctx, volatile sdhci_regs_t** out);
-    // Gets a handle to the bus transaction initiator for the device. The caller
-    // receives ownership of the handle.
-    zx_status_t (*get_bti)(void* ctx, uint32_t index, zx_handle_t* out_handle);
+// Forward declarations
 
-    uint32_t (*get_base_clock)(void* ctx);
-
-    // returns device quirks
-    uint64_t (*get_quirks)(void* ctx);
-    // platform specific HW reset
-    void (*hw_reset)(void* ctx);
-} sdhci_protocol_ops_t;
-
+typedef struct sdhci_protocol sdhci_protocol_t;
+typedef uint64_t sdhci_quirk_t;
 // This is a BCM28xx specific quirk. The bottom 8 bits of the 136
 // bit response are normally filled by 7 CRC bits and 1 reserved bit.
 // The BCM controller checks the CRC for us and strips it off in the
 // process.
 // The higher level stack expects 136B responses to be packed in a
 // certain way so we shift all the fields back to their proper offsets.
-#define SDHCI_QUIRK_STRIP_RESPONSE_CRC                (1 << 0)
+#define SDHCI_QUIRK_STRIP_RESPONSE_CRC UINT64_C(1)
 // BCM28xx quirk: The BCM28xx appears to use its internal DMA engine to
 // perform transfers against the SD card. Normally we would use SDMA or
 // ADMA (if the part supported it). Since this part doesn't appear to
 // support either, we just use PIO.
-#define SDHCI_QUIRK_NO_DMA                            (1 << 1)
+#define SDHCI_QUIRK_NO_DMA UINT64_C(2)
 // The bottom 8 bits of the 136 bit response are normally filled by 7 CRC bits
 // and 1 reserved bit. Some controllers strip off the CRC.
 // The higher level stack expects 136B responses to be packed in a certain way
 // so we shift all the fields back to their proper offsets.
-#define SDHCI_QUIRK_STRIP_RESPONSE_CRC_PRESERVE_ORDER (1 << 2)
+#define SDHCI_QUIRK_STRIP_RESPONSE_CRC_PRESERVE_ORDER UINT64_C(4)
 
+// Declarations
 
-typedef struct sdhci_protocol {
+typedef struct sdhci_protocol_ops {
+    zx_status_t (*get_interrupt)(void* ctx, zx_handle_t* out_irq);
+    zx_status_t (*get_mmio)(void* ctx, zx_handle_t* out_mmio);
+    zx_status_t (*get_bti)(void* ctx, uint32_t index, zx_handle_t* out_bti);
+    uint32_t (*get_base_clock)(void* ctx);
+    uint64_t (*get_quirks)(void* ctx);
+    void (*hw_reset)(void* ctx);
+} sdhci_protocol_ops_t;
+
+struct sdhci_protocol {
     sdhci_protocol_ops_t* ops;
     void* ctx;
-} sdhci_protocol_t;
+};
+
+static inline zx_status_t sdhci_get_interrupt(const sdhci_protocol_t* proto, zx_handle_t* out_irq) {
+    return proto->ops->get_interrupt(proto->ctx, out_irq);
+}
+static inline zx_status_t sdhci_get_mmio(const sdhci_protocol_t* proto, zx_handle_t* out_mmio) {
+    return proto->ops->get_mmio(proto->ctx, out_mmio);
+}
+// Gets a handle to the bus transaction initiator for the device. The caller
+// receives ownership of the handle.
+static inline zx_status_t sdhci_get_bti(const sdhci_protocol_t* proto, uint32_t index,
+                                        zx_handle_t* out_bti) {
+    return proto->ops->get_bti(proto->ctx, index, out_bti);
+}
+static inline uint32_t sdhci_get_base_clock(const sdhci_protocol_t* proto) {
+    return proto->ops->get_base_clock(proto->ctx);
+}
+// returns device quirks
+static inline uint64_t sdhci_get_quirks(const sdhci_protocol_t* proto) {
+    return proto->ops->get_quirks(proto->ctx);
+}
+// platform specific HW reset
+static inline void sdhci_hw_reset(const sdhci_protocol_t* proto) {
+    proto->ops->hw_reset(proto->ctx);
+}
 
 __END_CDECLS;
diff --git a/system/ulib/ddk/include/ddk/protocol/sdio.h b/system/ulib/ddk/include/ddk/protocol/sdio.h
index c16e251..0bbe9cc 100644
--- a/system/ulib/ddk/include/ddk/protocol/sdio.h
+++ b/system/ulib/ddk/include/ddk/protocol/sdio.h
@@ -1,120 +1,135 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
 #include <zircon/compiler.h>
-#include <zircon/listnode.h>
-#include <hw/sdio.h>
+#include <zircon/types.h>
 
-#define SDIO_FN_0   0
-#define SDIO_FN_1   1
-#define SDIO_FN_2   2
-#define SDIO_MAX_FUNCS 8 // Including func 0
+__BEGIN_CDECLS;
 
-typedef struct sdio_func_hw_info {
+// Forward declarations
+
+typedef struct sdio_func_hw_info sdio_func_hw_info_t;
+typedef uint32_t sdio_card_t;
+#define SDIO_CARD_MULTI_BLOCK UINT32_C(1)
+#define SDIO_CARD_SRW UINT32_C(2)
+#define SDIO_CARD_DIRECT_COMMAND UINT32_C(4)
+#define SDIO_CARD_SUSPEND_RESUME UINT32_C(8)
+#define SDIO_CARD_LOW_SPEED UINT32_C(16)
+#define SDIO_CARD_HIGH_SPEED UINT32_C(32)
+#define SDIO_CARD_HIGH_POWER UINT32_C(64)
+#define SDIO_CARD_FOUR_BIT_BUS UINT32_C(128)
+#define SDIO_CARD_HS_SDR12 UINT32_C(256)
+#define SDIO_CARD_HS_SDR25 UINT32_C(512)
+#define SDIO_CARD_UHS_SDR50 UINT32_C(1024)
+#define SDIO_CARD_UHS_SDR104 UINT32_C(2048)
+#define SDIO_CARD_UHS_DDR50 UINT32_C(4096)
+#define SDIO_CARD_TYPE_A UINT32_C(8192)
+#define SDIO_CARD_TYPE_B UINT32_C(16384)
+#define SDIO_CARD_TYPE_C UINT32_C(32768)
+#define SDIO_CARD_TYPE_D UINT32_C(65536)
+
+typedef struct sdio_device_hw_info sdio_device_hw_info_t;
+typedef struct sdio_hw_info sdio_hw_info_t;
+typedef struct sdio_rw_txn sdio_rw_txn_t;
+typedef struct sdio_protocol sdio_protocol_t;
+
+// Declarations
+
+struct sdio_func_hw_info {
     uint32_t manufacturer_id;
     uint32_t product_id;
     uint32_t max_blk_size;
     uint32_t max_tran_speed;
-    uint8_t  fn_intf_code;
-} sdio_func_hw_info_t;
+    uint8_t fn_intf_code;
+};
 
-typedef struct sdio_device_hw_info {
-    uint32_t  num_funcs; // number of sdio funcs
-    uint32_t  sdio_vsn;
-    uint32_t  cccr_vsn;
-    uint32_t  caps;
-#define SDIO_CARD_MULTI_BLOCK    (1 << 0)
-#define SDIO_CARD_SRW            (1 << 1)
-#define SDIO_CARD_DIRECT_COMMAND (1 << 2)
-#define SDIO_CARD_SUSPEND_RESUME (1 << 3)
-#define SDIO_CARD_LOW_SPEED      (1 << 4)
-#define SDIO_CARD_HIGH_SPEED     (1 << 5)
-#define SDIO_CARD_HIGH_POWER     (1 << 6)
-#define SDIO_CARD_4BIT_BUS       (1 << 7)
-#define SDIO_CARD_HS_SDR12       (1 << 8)
-#define SDIO_CARD_HS_SDR25       (1 << 9)
-#define SDIO_CARD_UHS_SDR50      (1 << 10)
-#define SDIO_CARD_UHS_SDR104     (1 << 11)
-#define SDIO_CARD_UHS_DDR50      (1 << 12)
-#define SDIO_DRIVER_TYPE_A       (1 << 13)
-#define SDIO_DRIVER_TYPE_B       (1 << 14)
-#define SDIO_DRIVER_TYPE_C       (1 << 15)
-#define SDIO_DRIVER_TYPE_D       (1 << 16)
-} sdio_device_hw_info_t;
+// Including func 0
+#define SDIO_MAX_FUNCS UINT8_C(8)
 
-typedef struct sdio_hw_info {
+#define SDIO_FN_2 UINT8_C(0)
+
+#define SDIO_FN_1 UINT8_C(0)
+
+#define SDIO_FN_0 UINT8_C(0)
+
+struct sdio_device_hw_info {
+    // number of sdio funcs
+    uint32_t num_funcs;
+    uint32_t sdio_vsn;
+    uint32_t cccr_vsn;
+    uint32_t caps;
+};
+
+struct sdio_hw_info {
     sdio_device_hw_info_t dev_hw_info;
-    sdio_func_hw_info_t funcs_hw_info[SDIO_MAX_FUNCS];
+    sdio_func_hw_info_t funcs_hw_info[8];
     uint32_t host_max_transfer_size;
-} sdio_hw_info_t;
+};
 
-typedef struct sdio_rw_txn {
+struct sdio_rw_txn {
     uint32_t addr;
     uint32_t data_size;
     bool incr;
     bool fifo;
     bool write;
     bool use_dma;
-    zx_handle_t dma_vmo; // Used if use_dma is true
-    void* virt;          // Used if use_dma is false
-    uint64_t buf_offset; // offset into dma_vmo or virt
-} sdio_rw_txn_t;
+    // Used if use_dma is true
+    zx_handle_t dma_vmo;
+    // Used if use_dma is false
+    void* virt_buffer;
+    size_t virt_size;
+    // offset into dma_vmo or virt
+    uint64_t buf_offset;
+};
 
 typedef struct sdio_protocol_ops {
-    zx_status_t (*get_dev_hw_info)(void* ctx, sdio_hw_info_t *hw_info);
-    zx_status_t (*enable_fn)(void *ctx, uint8_t fn_idx);
-    zx_status_t (*disable_fn)(void *ctx, uint8_t fn_idx);
-    zx_status_t (*enable_fn_intr)(void *ctx, uint8_t fn_idx);
-    zx_status_t (*disable_fn_intr)(void *ctx, uint8_t fn_idx);
-    zx_status_t (*update_block_size)(void *ctx, uint8_t fn_idx, uint16_t blk_sz, bool deflt);
-    zx_status_t (*get_block_size)(void *ctx, uint8_t fn_idx, uint16_t *cur_blk_size);
-    zx_status_t (*do_rw_txn)(void *ctx, uint8_t fn_idx, sdio_rw_txn_t *txn);
+    zx_status_t (*get_dev_hw_info)(void* ctx, sdio_hw_info_t* out_hw_info);
+    zx_status_t (*enable_fn)(void* ctx, uint8_t fn_idx);
+    zx_status_t (*disable_fn)(void* ctx, uint8_t fn_idx);
+    zx_status_t (*enable_fn_intr)(void* ctx, uint8_t fn_idx);
+    zx_status_t (*disable_fn_intr)(void* ctx, uint8_t fn_idx);
+    zx_status_t (*update_block_size)(void* ctx, uint8_t fn_idx, uint16_t blk_sz, bool deflt);
+    zx_status_t (*get_block_size)(void* ctx, uint8_t fn_idx, uint16_t* out_cur_blk_size);
+    zx_status_t (*do_rw_txn)(void* ctx, uint8_t fn_idx, sdio_rw_txn_t* txn);
 } sdio_protocol_ops_t;
 
-typedef struct sdio_protocol {
+struct sdio_protocol {
     sdio_protocol_ops_t* ops;
     void* ctx;
-} sdio_protocol_t;
+};
 
-static inline bool sdio_fn_idx_valid(uint8_t fn_idx) {
-    return (fn_idx < SDIO_MAX_FUNCS);
+static inline zx_status_t sdio_get_dev_hw_info(const sdio_protocol_t* proto,
+                                               sdio_hw_info_t* out_hw_info) {
+    return proto->ops->get_dev_hw_info(proto->ctx, out_hw_info);
 }
-
-static inline zx_status_t sdio_enable_fn(sdio_protocol_t* sdio, uint8_t fn_idx) {
-    return sdio->ops->enable_fn(sdio->ctx, fn_idx);
+static inline zx_status_t sdio_enable_fn(const sdio_protocol_t* proto, uint8_t fn_idx) {
+    return proto->ops->enable_fn(proto->ctx, fn_idx);
 }
-
-static inline zx_status_t sdio_disable_fn(sdio_protocol_t* sdio, uint8_t fn_idx) {
-    return sdio->ops->disable_fn(sdio->ctx, fn_idx);
+static inline zx_status_t sdio_disable_fn(const sdio_protocol_t* proto, uint8_t fn_idx) {
+    return proto->ops->disable_fn(proto->ctx, fn_idx);
 }
-
-static inline zx_status_t sdio_enable_fn_intr(sdio_protocol_t* sdio, uint8_t fn_idx) {
-    return sdio->ops->enable_fn_intr(sdio->ctx, fn_idx);
+static inline zx_status_t sdio_enable_fn_intr(const sdio_protocol_t* proto, uint8_t fn_idx) {
+    return proto->ops->enable_fn_intr(proto->ctx, fn_idx);
 }
-
-static inline zx_status_t sdio_disable_fn_intr(sdio_protocol_t* sdio, uint8_t fn_idx) {
-    return sdio->ops->disable_fn_intr(sdio->ctx, fn_idx);
+static inline zx_status_t sdio_disable_fn_intr(const sdio_protocol_t* proto, uint8_t fn_idx) {
+    return proto->ops->disable_fn_intr(proto->ctx, fn_idx);
 }
-
-static inline zx_status_t sdio_update_block_size(sdio_protocol_t* sdio, uint8_t fn_idx,
+static inline zx_status_t sdio_update_block_size(const sdio_protocol_t* proto, uint8_t fn_idx,
                                                  uint16_t blk_sz, bool deflt) {
-    return sdio->ops->update_block_size(sdio->ctx, fn_idx, blk_sz, deflt);
+    return proto->ops->update_block_size(proto->ctx, fn_idx, blk_sz, deflt);
+}
+static inline zx_status_t sdio_get_block_size(const sdio_protocol_t* proto, uint8_t fn_idx,
+                                              uint16_t* out_cur_blk_size) {
+    return proto->ops->get_block_size(proto->ctx, fn_idx, out_cur_blk_size);
+}
+static inline zx_status_t sdio_do_rw_txn(const sdio_protocol_t* proto, uint8_t fn_idx,
+                                         sdio_rw_txn_t* txn) {
+    return proto->ops->do_rw_txn(proto->ctx, fn_idx, txn);
 }
 
-static inline zx_status_t sdio_get_block_size(sdio_protocol_t* sdio, uint8_t fn_idx,
-                                              uint16_t *cur_blk_size) {
-    return sdio->ops->get_block_size(sdio->ctx, fn_idx, cur_blk_size);
-}
-
-static inline zx_status_t sdio_do_rw_txn(sdio_protocol_t* sdio, uint8_t fn_idx,
-                                         sdio_rw_txn_t *txn) {
-    return sdio->ops->do_rw_txn(sdio->ctx, fn_idx, txn);
-}
-
-static inline zx_status_t sdio_get_dev_hw_info(sdio_protocol_t* sdio,
-                                            sdio_hw_info_t *dev_info) {
-    return sdio->ops->get_dev_hw_info(sdio->ctx, dev_info);
-}
+__END_CDECLS;
diff --git a/system/ulib/ddk/include/ddk/protocol/sdmmc.h b/system/ulib/ddk/include/ddk/protocol/sdmmc.h
index d3f0b34..1b7fd7c 100644
--- a/system/ulib/ddk/include/ddk/protocol/sdmmc.h
+++ b/system/ulib/ddk/include/ddk/protocol/sdmmc.h
@@ -1,151 +1,156 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
+#include <ddk/protocol/block.h>
 #include <zircon/compiler.h>
 #include <zircon/listnode.h>
-
-#include <ddk/protocol/block.h>
+#include <zircon/types.h>
 
 __BEGIN_CDECLS;
 
-typedef enum sdmmc_voltage {
-    SDMMC_VOLTAGE_330,
-    SDMMC_VOLTAGE_180,
-    SDMMC_VOLTAGE_MAX,
-} sdmmc_voltage_t;
+// Forward declarations
 
-typedef enum sdmmc_bus_width {
-    SDMMC_BUS_WIDTH_1,
-    SDMMC_BUS_WIDTH_4,
-    SDMMC_BUS_WIDTH_8,
-    SDMMC_BUS_WIDTH_MAX,
-} sdmmc_bus_width_t;
-
-typedef enum sdmmc_timing {
-    SDMMC_TIMING_LEGACY,
-    SDMMC_TIMING_HS,
-    SDMMC_TIMING_HSDDR,
-    SDMMC_TIMING_HS200,
-    SDMMC_TIMING_HS400,
-    SDMMC_TIMING_SDR12,
-    SDMMC_TIMING_SDR25,
-    SDMMC_TIMING_SDR50,
-    SDMMC_TIMING_SDR104,
-    SDMMC_TIMING_DDR50,
-    SDMMC_TIMING_MAX,
-} sdmmc_timing_t;
-
-// block io transactions. one per client request
-typedef struct sdmmc_txn {
-    block_op_t bop;
-    list_node_t node;
-} sdmmc_txn_t;
+typedef uint64_t sdmmc_host_prefs_t;
+#define SDMMC_HOST_PREFS_DISABLE_HS400 UINT64_C(1)
+#define SDMMC_HOST_PREFS_DISABLE_HS200 UINT64_C(2)
 
 typedef struct sdmmc_req sdmmc_req_t;
+typedef struct sdmmc_host_info sdmmc_host_info_t;
+typedef uint8_t sdmmc_voltage_t;
+#define SDMMC_VOLTAGE_V330 UINT8_C(0)
+#define SDMMC_VOLTAGE_V180 UINT8_C(1)
+#define SDMMC_VOLTAGE_MAX UINT8_C(2)
 
-// number of pages per request - 2M per request
-// matches DMA_DESC_COUNT in dev/block/sdhci
-#define SDMMC_PAGES_COUNT  (PAGE_SIZE / sizeof(zx_paddr_t))
+typedef uint64_t sdmmc_host_cap_t;
+#define SDMMC_HOST_CAP_BUS_WIDTH_8 UINT64_C(1)
+#define SDMMC_HOST_CAP_ADMA2 UINT64_C(2)
+#define SDMMC_HOST_CAP_SIXTY_FOUR_BIT UINT64_C(4)
+#define SDMMC_HOST_CAP_VOLTAGE_330 UINT64_C(8)
+#define SDMMC_HOST_CAP_AUTO_CMD12 UINT64_C(16)
+
+typedef uint8_t sdmmc_timing_t;
+#define SDMMC_TIMING_LEGACY UINT8_C(0)
+#define SDMMC_TIMING_HS UINT8_C(1)
+#define SDMMC_TIMING_HSDDR UINT8_C(2)
+#define SDMMC_TIMING_HS200 UINT8_C(3)
+#define SDMMC_TIMING_HS400 UINT8_C(4)
+#define SDMMC_TIMING_SDR12 UINT8_C(5)
+#define SDMMC_TIMING_SDR25 UINT8_C(6)
+#define SDMMC_TIMING_SDR50 UINT8_C(7)
+#define SDMMC_TIMING_SDR104 UINT8_C(8)
+#define SDMMC_TIMING_DDR50 UINT8_C(9)
+#define SDMMC_TIMING_MAX UINT8_C(10)
+
+typedef uint8_t sdmmc_bus_width_t;
+#define SDMMC_BUS_WIDTH_ONE UINT8_C(0)
+#define SDMMC_BUS_WIDTH_FOUR UINT8_C(1)
+#define SDMMC_BUS_WIDTH_EIGHT UINT8_C(2)
+#define SDMMC_BUS_WIDTH_MAX UINT8_C(3)
+
+typedef struct sdmmc_protocol sdmmc_protocol_t;
+typedef struct sdmmc_txn sdmmc_txn_t;
+
+// Declarations
 
 // sdmmc requests. one per command
 struct sdmmc_req {
     uint32_t cmd_idx;
     uint32_t cmd_flags;
     uint32_t arg;
-
     // data command parameters
     uint16_t blockcount;
     uint16_t blocksize;
     bool use_dma;
-    zx_handle_t dma_vmo; // Used if use_dma is true
-    void* virt;          // Used if use_dma is false
-    uint64_t buf_offset; // offset into dma_vmo or virt
+    // Used if use_dma is true
+    zx_handle_t dma_vmo;
+    // Used if use_dma is false
+    void* virt_buffer;
+    size_t virt_size;
+    // offset into dma_vmo or virt
+    uint64_t buf_offset;
     zx_handle_t pmt;
-
     // response data
     uint32_t response[4];
-
     // status
     zx_status_t status;
 };
 
-typedef struct sdmmc_host_info {
+struct sdmmc_host_info {
     // Controller capabilities
     uint64_t caps;
-#define SDMMC_HOST_CAP_BUS_WIDTH_8   (1 << 0)
-#define SDMMC_HOST_CAP_ADMA2         (1 << 1)
-#define SDMMC_HOST_CAP_64BIT         (1 << 2)
-#define SDMMC_HOST_CAP_VOLTAGE_330   (1 << 3)
-#define SDMMC_HOST_CAP_AUTO_CMD12    (1 << 4)
     // Maximum data request size
     uint64_t max_transfer_size;
     uint64_t max_transfer_size_non_dma;
     // Host specific preferences
     uint64_t prefs;
-#define SDMMC_HOST_PREFS_DISABLE_HS400         (1 << 0)
-#define SDMMC_HOST_PREFS_DISABLE_HS200         (1 << 1)
+};
 
-} sdmmc_host_info_t;
+// number of pages per request - 2M per request
+// matches DMA_DESC_COUNT in dev/block/sdhci
+// (PAGE_SIZE / sizeof(zx_paddr_t))
+#define SDMMC_PAGES_COUNT UINT64_C(512)
 
 typedef struct sdmmc_protocol_ops {
-    // get host info
-    zx_status_t (*host_info)(void* ctx, sdmmc_host_info_t* info);
-    // set signal voltage
+    zx_status_t (*host_info)(void* ctx, sdmmc_host_info_t* out_info);
     zx_status_t (*set_signal_voltage)(void* ctx, sdmmc_voltage_t voltage);
-    // set bus width
     zx_status_t (*set_bus_width)(void* ctx, sdmmc_bus_width_t bus_width);
-    // set bus frequency
     zx_status_t (*set_bus_freq)(void* ctx, uint32_t bus_freq);
-    // set mmc timing
     zx_status_t (*set_timing)(void* ctx, sdmmc_timing_t timing);
-    // issue a hw reset
     void (*hw_reset)(void* ctx);
-    // perform tuning
     zx_status_t (*perform_tuning)(void* ctx, uint32_t cmd_idx);
-    // issue a request
     zx_status_t (*request)(void* ctx, sdmmc_req_t* req);
 } sdmmc_protocol_ops_t;
 
-typedef struct sdmmc_protocol {
+struct sdmmc_protocol {
     sdmmc_protocol_ops_t* ops;
     void* ctx;
-} sdmmc_protocol_t;
+};
 
-static inline zx_status_t sdmmc_host_info(sdmmc_protocol_t* sdmmc, sdmmc_host_info_t* info) {
-    return sdmmc->ops->host_info(sdmmc->ctx, info);
+// Get host info.
+static inline zx_status_t sdmmc_host_info(const sdmmc_protocol_t* proto,
+                                          sdmmc_host_info_t* out_info) {
+    return proto->ops->host_info(proto->ctx, out_info);
 }
-
-static inline zx_status_t sdmmc_set_signal_voltage(sdmmc_protocol_t* sdmmc,
+// Set signal voltage.
+static inline zx_status_t sdmmc_set_signal_voltage(const sdmmc_protocol_t* proto,
                                                    sdmmc_voltage_t voltage) {
-    return sdmmc->ops->set_signal_voltage(sdmmc->ctx, voltage);
+    return proto->ops->set_signal_voltage(proto->ctx, voltage);
 }
-
-static inline zx_status_t sdmmc_set_bus_width(sdmmc_protocol_t* sdmmc,
+// Set bus width.
+static inline zx_status_t sdmmc_set_bus_width(const sdmmc_protocol_t* proto,
                                               sdmmc_bus_width_t bus_width) {
-    return sdmmc->ops->set_bus_width(sdmmc->ctx, bus_width);
+    return proto->ops->set_bus_width(proto->ctx, bus_width);
+}
+// Set bus frequency.
+static inline zx_status_t sdmmc_set_bus_freq(const sdmmc_protocol_t* proto, uint32_t bus_freq) {
+    return proto->ops->set_bus_freq(proto->ctx, bus_freq);
+}
+// Set mmc timing.
+static inline zx_status_t sdmmc_set_timing(const sdmmc_protocol_t* proto, sdmmc_timing_t timing) {
+    return proto->ops->set_timing(proto->ctx, timing);
+}
+// Issue a hw reset.
+static inline void sdmmc_hw_reset(const sdmmc_protocol_t* proto) {
+    proto->ops->hw_reset(proto->ctx);
+}
+// Perform tuning.
+static inline zx_status_t sdmmc_perform_tuning(const sdmmc_protocol_t* proto, uint32_t cmd_idx) {
+    return proto->ops->perform_tuning(proto->ctx, cmd_idx);
+}
+// Issue a request.
+static inline zx_status_t sdmmc_request(const sdmmc_protocol_t* proto, sdmmc_req_t* req) {
+    return proto->ops->request(proto->ctx, req);
 }
 
-static inline zx_status_t sdmmc_set_bus_freq(sdmmc_protocol_t* sdmmc, uint32_t bus_freq) {
-    return sdmmc->ops->set_bus_freq(sdmmc->ctx, bus_freq);
-}
-
-static inline zx_status_t sdmmc_set_timing(sdmmc_protocol_t* sdmmc, sdmmc_timing_t timing) {
-    return sdmmc->ops->set_timing(sdmmc->ctx, timing);
-}
-
-static inline void sdmmc_hw_reset(sdmmc_protocol_t* sdmmc) {
-    sdmmc->ops->hw_reset(sdmmc->ctx);
-}
-
-static inline zx_status_t sdmmc_perform_tuning(sdmmc_protocol_t* sdmmc, uint32_t cmd_idx) {
-    return sdmmc->ops->perform_tuning(sdmmc->ctx, cmd_idx);
-}
-
-static inline zx_status_t sdmmc_request(sdmmc_protocol_t* sdmmc, sdmmc_req_t* req) {
-    return sdmmc->ops->request(sdmmc->ctx, req);
-}
+// block io transactions. one per client request
+struct sdmmc_txn {
+    block_op_t bop;
+    list_node_t node;
+};
 
 __END_CDECLS;
diff --git a/system/ulib/ddk/include/ddk/protocol/serial-impl.h b/system/ulib/ddk/include/ddk/protocol/serial-impl.h
index 32f658e..af0dd36 100644
--- a/system/ulib/ddk/include/ddk/protocol/serial-impl.h
+++ b/system/ulib/ddk/include/ddk/protocol/serial-impl.h
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
 #include <ddk/protocol/serial.h>
@@ -10,76 +12,61 @@
 
 __BEGIN_CDECLS;
 
-// Low level serial protocol to be implemented by serial drivers
-// This is only used by bus drivers like platform bus
+// Forward declarations
 
-// state flags for serial_notify_cb
-enum {
-    SERIAL_STATE_READABLE = (1 << 0),
-    SERIAL_STATE_WRITABLE = (1 << 1),
+typedef uint32_t serial_state_t;
+#define SERIAL_STATE_READABLE UINT32_C(1)
+#define SERIAL_STATE_WRITABLE UINT32_C(2)
+
+typedef struct serial_notify serial_notify_t;
+typedef struct serial_impl_protocol serial_impl_protocol_t;
+
+// Declarations
+
+struct serial_notify {
+    void (*callback)(void* ctx, serial_state_t state);
+    void* ctx;
 };
 
-// Callback for notification of readable/writeable state changes
-// This may be called from an interrupt thread it should just signal another thread
-// and return as soon as possible. In particular, it may not be safe to make protocol calls
-// from these callbacks.
-typedef void (*serial_notify_cb)(uint32_t state, void* cookie);
-
-typedef struct {
-    zx_status_t (*get_info)(void* ctx, serial_port_info_t* info);
+typedef struct serial_impl_protocol_ops {
+    zx_status_t (*get_info)(void* ctx, serial_port_info_t* out_info);
     zx_status_t (*config)(void* ctx, uint32_t baud_rate, uint32_t flags);
     zx_status_t (*enable)(void* ctx, bool enable);
-    zx_status_t (*read)(void* ctx, void* buf, size_t length, size_t* out_actual);
-    zx_status_t (*write)(void* ctx, const void* buf, size_t length,
-                         size_t* out_actual);
-    zx_status_t (*set_notify_callback)(void* ctx, serial_notify_cb cb,
-                                       void* cookie);
-} serial_impl_ops_t;
+    zx_status_t (*read)(void* ctx, void* out_buf_buffer, size_t buf_size, size_t* out_buf_actual);
+    zx_status_t (*write)(void* ctx, const void* buf_buffer, size_t buf_size, size_t* out_actual);
+    zx_status_t (*set_notify_callback)(void* ctx, const serial_notify_t* cb);
+} serial_impl_protocol_ops_t;
 
-typedef struct {
-    serial_impl_ops_t* ops;
+struct serial_impl_protocol {
+    serial_impl_protocol_ops_t* ops;
     void* ctx;
-} serial_impl_protocol_t;
+};
 
-static inline zx_status_t serial_impl_get_info(serial_impl_protocol_t* serial,
-                                          serial_port_info_t* info) {
-    return serial->ops->get_info(serial->ctx, info);
+static inline zx_status_t serial_impl_get_info(const serial_impl_protocol_t* proto,
+                                               serial_port_info_t* out_info) {
+    return proto->ops->get_info(proto->ctx, out_info);
 }
-
-// Configures the given serial port
-static inline zx_status_t serial_impl_config(serial_impl_protocol_t* serial, uint32_t baud_rate,
-                                             uint32_t flags) {
-    return serial->ops->config(serial->ctx, baud_rate, flags);
+// Configures the given serial port.
+static inline zx_status_t serial_impl_config(const serial_impl_protocol_t* proto,
+                                             uint32_t baud_rate, uint32_t flags) {
+    return proto->ops->config(proto->ctx, baud_rate, flags);
 }
-
-// Enables or disables the given serial port
-static inline zx_status_t serial_impl_enable(serial_impl_protocol_t* serial, bool enable) {
-    return serial->ops->enable(serial->ctx, enable);
+static inline zx_status_t serial_impl_enable(const serial_impl_protocol_t* proto, bool enable) {
+    return proto->ops->enable(proto->ctx, enable);
 }
-
-// Reads data from the given serial port
-// Returns ZX_ERR_SHOULD_WAIT if no data is available to read
-static inline zx_status_t serial_impl_read(serial_impl_protocol_t* serial, void* buf, size_t length,
-                                           size_t* out_actual) {
-    return serial->ops->read(serial->ctx, buf, length, out_actual);
+static inline zx_status_t serial_impl_read(const serial_impl_protocol_t* proto,
+                                           void* out_buf_buffer, size_t buf_size,
+                                           size_t* out_buf_actual) {
+    return proto->ops->read(proto->ctx, out_buf_buffer, buf_size, out_buf_actual);
 }
-
-// Reads data from the given serial port
-// Returns ZX_ERR_SHOULD_WAIT if transmit buffer is full and writing is not possible
-static inline zx_status_t serial_impl_write(serial_impl_protocol_t* serial, const void* buf,
-                                            size_t length, size_t* out_actual) {
-    return serial->ops->write(serial->ctx, buf, length, out_actual);
+static inline zx_status_t serial_impl_write(const serial_impl_protocol_t* proto,
+                                            const void* buf_buffer, size_t buf_size,
+                                            size_t* out_actual) {
+    return proto->ops->write(proto->ctx, buf_buffer, buf_size, out_actual);
 }
-
-// Sets a callback to be called when the port's readable and writeble state changes
-// Pass NULL to clear previously installed callback
-// The callback may be called from an interrupt thread it should just signal another thread
-// and return as soon as possible. In particular, it may not be safe to make protocol calls
-// from the callback.
-// Returns ZX_ERR_BAD_STATE called while the driver is in enabled state.
-static inline zx_status_t serial_impl_set_notify_callback(serial_impl_protocol_t* serial,
-                                                          serial_notify_cb cb, void* cookie) {
-    return serial->ops->set_notify_callback(serial->ctx, cb, cookie);
+static inline zx_status_t serial_impl_set_notify_callback(const serial_impl_protocol_t* proto,
+                                                          const serial_notify_t* cb) {
+    return proto->ops->set_notify_callback(proto->ctx, cb);
 }
 
 __END_CDECLS;
diff --git a/system/ulib/ddk/include/ddk/protocol/serial.h b/system/ulib/ddk/include/ddk/protocol/serial.h
index ada9f9b..d44cc3a 100644
--- a/system/ulib/ddk/include/ddk/protocol/serial.h
+++ b/system/ulib/ddk/include/ddk/protocol/serial.h
@@ -2,51 +2,59 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
 #include <zircon/compiler.h>
-#include <zircon/device/serial.h>
 #include <zircon/types.h>
 
 __BEGIN_CDECLS;
 
-typedef struct {
+// Forward declarations
+
+typedef struct serial_port_info serial_port_info_t;
+typedef struct serial_protocol serial_protocol_t;
+
+// Declarations
+
+struct serial_port_info {
     uint32_t serial_class;
-    // vendor and product ID of hardware attached to this serial port,
-    // or zero if not applicable
+    // Vendor and product ID of hardware attached to this serial port,
+    // or zero if not applicable.
     uint32_t serial_vid;
     uint32_t serial_pid;
-} serial_port_info_t;
+};
 
-// High level serial protocol for use by client drivers
-// When used with the platform device protocol, "port" will be relative to
-// the list of serial ports assigned to your device rather than the global
-// list of serial ports.
-typedef struct {
-    zx_status_t (*get_info)(void* ctx, serial_port_info_t* info);
+typedef struct serial_protocol_ops {
+    zx_status_t (*get_info)(void* ctx, serial_port_info_t* out_info);
     zx_status_t (*config)(void* ctx, uint32_t baud_rate, uint32_t flags);
     zx_status_t (*open_socket)(void* ctx, zx_handle_t* out_handle);
 } serial_protocol_ops_t;
 
-typedef struct {
+// High level serial protocol for use by client drivers.
+// When used with the platform device protocol, "port" will be relative to
+// the list of serial ports assigned to your device rather than the global
+// list of serial ports.
+struct serial_protocol {
     serial_protocol_ops_t* ops;
     void* ctx;
-} serial_protocol_t;
+};
 
-static inline zx_status_t serial_get_info(serial_protocol_t* serial, serial_port_info_t* info) {
-    return serial->ops->get_info(serial->ctx, info);
+static inline zx_status_t serial_get_info(const serial_protocol_t* proto,
+                                          serial_port_info_t* out_info) {
+    return proto->ops->get_info(proto->ctx, out_info);
 }
-
-// configures the given serial port
-static inline zx_status_t serial_config(serial_protocol_t* serial, uint32_t baud_rate,
+// Configures the given serial port.
+static inline zx_status_t serial_config(const serial_protocol_t* proto, uint32_t baud_rate,
                                         uint32_t flags) {
-    return serial->ops->config(serial->ctx, baud_rate, flags);
+    return proto->ops->config(proto->ctx, baud_rate, flags);
 }
-
-// returns a socket that can be used for reading and writing data
-// from the given serial port
-static inline zx_status_t serial_open_socket(serial_protocol_t* serial, zx_handle_t* out_handle) {
-    return serial->ops->open_socket(serial->ctx, out_handle);
+// Returns a socket that can be used for reading and writing data
+// from the given serial port.
+static inline zx_status_t serial_open_socket(const serial_protocol_t* proto,
+                                             zx_handle_t* out_handle) {
+    return proto->ops->open_socket(proto->ctx, out_handle);
 }
 
 __END_CDECLS;
diff --git a/system/ulib/ddk/include/ddk/protocol/test.h b/system/ulib/ddk/include/ddk/protocol/test.h
index 092cd52..1628b1d 100644
--- a/system/ulib/ddk/include/ddk/protocol/test.h
+++ b/system/ulib/ddk/include/ddk/protocol/test.h
@@ -1,39 +1,80 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
-#include <zircon/device/test.h>
+#include <zircon/compiler.h>
+#include <zircon/types.h>
 
-typedef test_ioctl_test_report_t test_report_t;
+__BEGIN_CDECLS;
 
-typedef zx_status_t (*test_func_t)(void* cookie, test_report_t* report, const void* arg, size_t arglen);
+// Forward declarations
+
+typedef struct test_report test_report_t;
+typedef struct test_func test_func_t;
+typedef struct test_protocol test_protocol_t;
+
+// Declarations
+
+struct test_report {
+    uint64_t n_tests;
+    uint64_t n_success;
+    uint64_t n_failed;
+};
+
+struct test_func {
+    zx_status_t (*callback)(void* ctx, const void* arg_buffer, size_t arg_size,
+                            test_report_t* out_report);
+    void* ctx;
+};
 
 typedef struct test_protocol_ops {
-    // sets test output socket
     void (*set_output_socket)(void* ctx, zx_handle_t handle);
-
-    // gets test output socket
     zx_handle_t (*get_output_socket)(void* ctx);
-
-    // sets control channel
     void (*set_control_channel)(void* ctx, zx_handle_t handle);
-
-    // gets control channel
     zx_handle_t (*get_control_channel)(void* ctx);
-
-    // sets test function
-    void (*set_test_func)(void* ctx, test_func_t func, void* cookie);
-
-    // run tests, calls the function set in set_test_func
-    zx_status_t (*run_tests)(void* ctx, test_report_t* report, const void* arg, size_t arglen);
-
-    // calls device_remove()
+    void (*set_test_func)(void* ctx, const test_func_t* func);
+    zx_status_t (*run_tests)(void* ctx, const void* arg_buffer, size_t arg_size,
+                             test_report_t* out_report);
     void (*destroy)(void* ctx);
 } test_protocol_ops_t;
 
-typedef struct test_protocol {
+struct test_protocol {
     test_protocol_ops_t* ops;
     void* ctx;
-} test_protocol_t;
+};
+
+// Sets test output socket.
+static inline void test_set_output_socket(const test_protocol_t* proto, zx_handle_t handle) {
+    proto->ops->set_output_socket(proto->ctx, handle);
+}
+// Gets test output socket.
+static inline zx_handle_t test_get_output_socket(const test_protocol_t* proto) {
+    return proto->ops->get_output_socket(proto->ctx);
+}
+// Sets control channel.
+static inline void test_set_control_channel(const test_protocol_t* proto, zx_handle_t handle) {
+    proto->ops->set_control_channel(proto->ctx, handle);
+}
+// Gets control channel.
+static inline zx_handle_t test_get_control_channel(const test_protocol_t* proto) {
+    return proto->ops->get_control_channel(proto->ctx);
+}
+// Sets test function.
+static inline void test_set_test_func(const test_protocol_t* proto, const test_func_t* func) {
+    proto->ops->set_test_func(proto->ctx, func);
+}
+// Run tests, calls the function set in |SetTestFunc|.
+static inline zx_status_t test_run_tests(const test_protocol_t* proto, const void* arg_buffer,
+                                         size_t arg_size, test_report_t* out_report) {
+    return proto->ops->run_tests(proto->ctx, arg_buffer, arg_size, out_report);
+}
+// Calls `device_remove()`.
+static inline void test_destroy(const test_protocol_t* proto) {
+    proto->ops->destroy(proto->ctx);
+}
+
+__END_CDECLS;
diff --git a/system/ulib/ddktl/include/ddktl/protocol/acpi-internal.h b/system/ulib/ddktl/include/ddktl/protocol/acpi-internal.h
new file mode 100644
index 0000000..f1e8660
--- /dev/null
+++ b/system/ulib/ddktl/include/ddktl/protocol/acpi-internal.h
@@ -0,0 +1,34 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: This file is machine generated by fidlc.
+
+#pragma once
+
+#include <ddk/protocol/acpi.h>
+#include <fbl/type_support.h>
+
+namespace ddk {
+namespace internal {
+
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_acpi_protocol_map_resource, AcpiMapResource,
+                                     zx_status_t (C::*)(uint32_t resource_id, uint32_t cache_policy,
+                                                        void** out_vaddr_buffer, size_t* vaddr_size,
+                                                        zx_handle_t* out_handle));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_acpi_protocol_map_interrupt, AcpiMapInterrupt,
+                                     zx_status_t (C::*)(int64_t irq_id, zx_handle_t* out_handle));
+
+template <typename D>
+constexpr void CheckAcpiProtocolSubclass() {
+    static_assert(internal::has_acpi_protocol_map_resource<D>::value,
+                  "AcpiProtocol subclasses must implement "
+                  "zx_status_t AcpiMapResource(uint32_t resource_id, uint32_t cache_policy, void** "
+                  "out_vaddr_buffer, size_t* vaddr_size, zx_handle_t* out_handle");
+    static_assert(internal::has_acpi_protocol_map_interrupt<D>::value,
+                  "AcpiProtocol subclasses must implement "
+                  "zx_status_t AcpiMapInterrupt(int64_t irq_id, zx_handle_t* out_handle");
+}
+
+} // namespace internal
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/acpi.h b/system/ulib/ddktl/include/ddktl/protocol/acpi.h
new file mode 100644
index 0000000..9e41a66
--- /dev/null
+++ b/system/ulib/ddktl/include/ddktl/protocol/acpi.h
@@ -0,0 +1,108 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: This file is machine generated by fidlc.
+
+#pragma once
+
+#include <ddk/protocol/acpi.h>
+#include <ddktl/device-internal.h>
+#include <zircon/assert.h>
+#include <zircon/compiler.h>
+#include <zircon/types.h>
+
+#include "acpi-internal.h"
+
+// DDK acpi-protocol support
+//
+// :: Proxies ::
+//
+// ddk::AcpiProtocolProxy is a simple wrapper around
+// acpi_protocol_t. It does not own the pointers passed to it
+//
+// :: Mixins ::
+//
+// ddk::AcpiProtocol is a mixin class that simplifies writing DDK drivers
+// that implement the acpi protocol. It doesn't set the base protocol.
+//
+// :: Examples ::
+//
+// // A driver that implements a ZX_PROTOCOL_ACPI device.
+// class AcpiDevice {
+// using AcpiDeviceType = ddk::Device<AcpiDevice, /* ddk mixins */>;
+//
+// class AcpiDevice : public AcpiDeviceType,
+//                    public ddk::AcpiProtocol<AcpiDevice> {
+//   public:
+//     AcpiDevice(zx_device_t* parent)
+//         : AcpiDeviceType("my-acpi-protocol-device", parent) {}
+//
+//     zx_status_t AcpiMapResource(uint32_t resource_id, uint32_t cache_policy, void**
+//     out_vaddr_buffer, size_t* vaddr_size, zx_handle_t* out_handle);
+//
+//     zx_status_t AcpiMapInterrupt(int64_t irq_id, zx_handle_t* out_handle);
+//
+//     ...
+// };
+
+namespace ddk {
+
+template <typename D>
+class AcpiProtocol : public internal::base_protocol {
+public:
+    AcpiProtocol() {
+        internal::CheckAcpiProtocolSubclass<D>();
+        ops_.map_resource = AcpiMapResource;
+        ops_.map_interrupt = AcpiMapInterrupt;
+
+        // Can only inherit from one base_protocol implementation.
+        ZX_ASSERT(ddk_proto_id_ = 0);
+        ddk_proto_id_ = ZX_PROTOCOL_ACPI;
+        ddk_proto_ops_ = &ops_;
+    }
+
+protected:
+    acpi_protocol_ops_t ops_ = {};
+
+private:
+    static zx_status_t AcpiMapResource(void* ctx, uint32_t resource_id, uint32_t cache_policy,
+                                       void** out_vaddr_buffer, size_t* vaddr_size,
+                                       zx_handle_t* out_handle) {
+        return static_cast<D*>(ctx)->AcpiMapResource(resource_id, cache_policy, out_vaddr_buffer,
+                                                     vaddr_size, out_handle);
+    }
+    static zx_status_t AcpiMapInterrupt(void* ctx, int64_t irq_id, zx_handle_t* out_handle) {
+        return static_cast<D*>(ctx)->AcpiMapInterrupt(irq_id, out_handle);
+    }
+};
+
+class AcpiProtocolProxy {
+public:
+    AcpiProtocolProxy() : ops_(nullptr), ctx_(nullptr) {}
+    AcpiProtocolProxy(const acpi_protocol_t* proto) : ops_(proto->ops), ctx_(proto->ctx) {}
+
+    void GetProto(acpi_protocol_t* proto) {
+        proto->ctx = ctx_;
+        proto->ops = ops_;
+    }
+    bool is_valid() { return ops_ != nullptr; }
+    void clear() {
+        ctx_ = nullptr;
+        ops_ = nullptr;
+    }
+    zx_status_t MapResource(uint32_t resource_id, uint32_t cache_policy, void** out_vaddr_buffer,
+                            size_t* vaddr_size, zx_handle_t* out_handle) {
+        return ops_->map_resource(ctx_, resource_id, cache_policy, out_vaddr_buffer, vaddr_size,
+                                  out_handle);
+    }
+    zx_status_t MapInterrupt(int64_t irq_id, zx_handle_t* out_handle) {
+        return ops_->map_interrupt(ctx_, irq_id, out_handle);
+    }
+
+private:
+    acpi_protocol_ops_t* ops_;
+    void* ctx_;
+};
+
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/amlogic-canvas-internal.h b/system/ulib/ddktl/include/ddktl/protocol/amlogic-canvas-internal.h
index 292b1b3..2f69399 100644
--- a/system/ulib/ddktl/include/ddktl/protocol/amlogic-canvas-internal.h
+++ b/system/ulib/ddktl/include/ddktl/protocol/amlogic-canvas-internal.h
@@ -2,28 +2,33 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
+#include <ddk/protocol/amlogic-canvas.h>
 #include <fbl/type_support.h>
 
 namespace ddk {
 namespace internal {
 
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_canvas_config, CanvasConfig,
-        zx_status_t (C::*)(zx_handle_t, size_t, canvas_info_t*, uint8_t*));
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_canvas_free, CanvasFree,
-        zx_status_t (C::*)(uint8_t));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_canvas_protocol_config, CanvasConfig,
+                                     zx_status_t (C::*)(zx_handle_t vmo, size_t offset,
+                                                        const canvas_info_t* info,
+                                                        uint8_t* out_canvas_idx));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_canvas_protocol_free, CanvasFree,
+                                     zx_status_t (C::*)(uint8_t canvas_idx));
 
 template <typename D>
 constexpr void CheckCanvasProtocolSubclass() {
-    static_assert(internal::has_canvas_config<D>::value,
+    static_assert(internal::has_canvas_protocol_config<D>::value,
                   "CanvasProtocol subclasses must implement "
-                  "CanvasConfig(zx_handle_t vmo, size_t offset, canvas_info_t* info, "
-                  "uint8_t* canvas_idx)");
-    static_assert(internal::has_canvas_free<D>::value,
+                  "zx_status_t CanvasConfig(zx_handle_t vmo, size_t offset, const canvas_info_t* "
+                  "info, uint8_t* out_canvas_idx");
+    static_assert(internal::has_canvas_protocol_free<D>::value,
                   "CanvasProtocol subclasses must implement "
-                  "CanvasFree(uint8_t canvas_idx)");
- }
+                  "zx_status_t CanvasFree(uint8_t canvas_idx");
+}
 
-}  // namespace internal
-}  // namespace ddk
+} // namespace internal
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/amlogic-canvas.h b/system/ulib/ddktl/include/ddktl/protocol/amlogic-canvas.h
index b5158fb..49e7f67 100644
--- a/system/ulib/ddktl/include/ddktl/protocol/amlogic-canvas.h
+++ b/system/ulib/ddktl/include/ddktl/protocol/amlogic-canvas.h
@@ -2,42 +2,47 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
-#include <ddk/driver.h>
 #include <ddk/protocol/amlogic-canvas.h>
 #include <ddktl/device-internal.h>
 #include <zircon/assert.h>
+#include <zircon/compiler.h>
+#include <zircon/types.h>
 
 #include "amlogic-canvas-internal.h"
 
-// DDK canvas protocol support.
+// DDK canvas-protocol support
 //
 // :: Proxies ::
 //
-// ddk::CanvasProtocolProxy is a simple wrappers around canvas_protocol_t. It does
-// not own the pointers passed to it.
+// ddk::CanvasProtocolProxy is a simple wrapper around
+// canvas_protocol_t. It does not own the pointers passed to it
 //
 // :: Mixins ::
 //
-// ddk::CanvasProtocol is a mixin class that simplifies writing DDK drivers that
-// implement the canvas protocol.
+// ddk::CanvasProtocol is a mixin class that simplifies writing DDK drivers
+// that implement the canvas protocol. It doesn't set the base protocol.
 //
 // :: Examples ::
 //
-// // A driver that implements a ZX_PROTOCOL_AMLOGIC_CANVAS device.
-// class CanvasDevice;
+// // A driver that implements a ZX_PROTOCOL_CANVAS device.
+// class CanvasDevice {
 // using CanvasDeviceType = ddk::Device<CanvasDevice, /* ddk mixins */>;
 //
 // class CanvasDevice : public CanvasDeviceType,
 //                      public ddk::CanvasProtocol<CanvasDevice> {
 //   public:
 //     CanvasDevice(zx_device_t* parent)
-//       : CanvasDeviceType("my-canvas-device", parent) {}
+//         : CanvasDeviceType("my-canvas-protocol-device", parent) {}
 //
-//    zx_status_t CanvasConfig(zx_handle_t vmo, size_t offset, canvas_info_t* info,
-//                             uint8_t* canvas_idx);
-//    zx_status_t CanvasFree(uint8_t canvas_idx);
+//     zx_status_t CanvasConfig(zx_handle_t vmo, size_t offset, const canvas_info_t* info, uint8_t*
+//     out_canvas_idx);
+//
+//     zx_status_t CanvasFree(uint8_t canvas_idx);
+//
 //     ...
 // };
 
@@ -51,9 +56,9 @@
         ops_.config = CanvasConfig;
         ops_.free = CanvasFree;
 
-        // Can only inherit from one base_protocol implemenation
-        ZX_ASSERT(ddk_proto_id_ == 0);
-        ddk_proto_id_ = ZX_PROTOCOL_AMLOGIC_CANVAS;
+        // Can only inherit from one base_protocol implementation.
+        ZX_ASSERT(ddk_proto_id_ = 0);
+        ddk_proto_id_ = ZX_PROTOCOL_CANVAS;
         ddk_proto_ops_ = &ops_;
     }
 
@@ -61,10 +66,13 @@
     canvas_protocol_ops_t ops_ = {};
 
 private:
-    static zx_status_t CanvasConfig(void* ctx, zx_handle_t vmo, size_t offset, canvas_info_t* info,
-                                    uint8_t* canvas_idx) {
-        return static_cast<D*>(ctx)->CanvasConfig(vmo, offset, info, canvas_idx);
+    // Configures a canvas.
+    // Adds a framebuffer to the canvas lookup table.
+    static zx_status_t CanvasConfig(void* ctx, zx_handle_t vmo, size_t offset,
+                                    const canvas_info_t* info, uint8_t* out_canvas_idx) {
+        return static_cast<D*>(ctx)->CanvasConfig(vmo, offset, info, out_canvas_idx);
     }
+    // Frees up a canvas.
     static zx_status_t CanvasFree(void* ctx, uint8_t canvas_idx) {
         return static_cast<D*>(ctx)->CanvasFree(canvas_idx);
     }
@@ -72,21 +80,26 @@
 
 class CanvasProtocolProxy {
 public:
-    CanvasProtocolProxy(canvas_protocol_t* proto)
-        : ops_(proto->ops), ctx_(proto->ctx) {}
+    CanvasProtocolProxy() : ops_(nullptr), ctx_(nullptr) {}
+    CanvasProtocolProxy(const canvas_protocol_t* proto) : ops_(proto->ops), ctx_(proto->ctx) {}
 
     void GetProto(canvas_protocol_t* proto) {
         proto->ctx = ctx_;
         proto->ops = ops_;
     }
-
-    zx_status_t Config(zx_handle_t vmo, size_t offset, canvas_info_t* info,
-                       uint8_t* canvas_idx) {
-        return ops_->config(ctx_, vmo, offset, info, canvas_idx);
+    bool is_valid() { return ops_ != nullptr; }
+    void clear() {
+        ctx_ = nullptr;
+        ops_ = nullptr;
     }
-    zx_status_t Free(uint8_t canvas_idx) {
-        return ops_->free(ctx_, canvas_idx);
+    // Configures a canvas.
+    // Adds a framebuffer to the canvas lookup table.
+    zx_status_t Config(zx_handle_t vmo, size_t offset, const canvas_info_t* info,
+                       uint8_t* out_canvas_idx) {
+        return ops_->config(ctx_, vmo, offset, info, out_canvas_idx);
     }
+    // Frees up a canvas.
+    zx_status_t Free(uint8_t canvas_idx) { return ops_->free(ctx_, canvas_idx); }
 
 private:
     canvas_protocol_ops_t* ops_;
diff --git a/system/ulib/ddktl/include/ddktl/protocol/bad-block-internal.h b/system/ulib/ddktl/include/ddktl/protocol/bad-block-internal.h
index 51f3d63..f8acf21 100644
--- a/system/ulib/ddktl/include/ddktl/protocol/bad-block-internal.h
+++ b/system/ulib/ddktl/include/ddktl/protocol/bad-block-internal.h
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
 #include <ddk/protocol/bad-block.h>
@@ -10,21 +12,23 @@
 namespace ddk {
 namespace internal {
 
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_get_bad_block_list2, GetBadBlockList,
-                                     zx_status_t (C::*)(uint32_t*, uint32_t, uint32_t*));
-
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_mark_block_bad, MarkBlockBad,
-                                     zx_status_t (C::*)(uint32_t));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_bad_block_protocol_get_bad_block_list,
+                                     BadBlockGetBadBlockList,
+                                     zx_status_t (C::*)(uint32_t* out_bad_blocks_list,
+                                                        size_t bad_blocks_count,
+                                                        size_t* out_bad_blocks_actual));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_bad_block_protocol_mark_block_bad, BadBlockMarkBlockBad,
+                                     zx_status_t (C::*)(uint32_t block));
 
 template <typename D>
-constexpr void CheckBadBlockable() {
-    static_assert(internal::has_get_bad_block_list2<D>::value,
+constexpr void CheckBadBlockProtocolSubclass() {
+    static_assert(internal::has_bad_block_protocol_get_bad_block_list<D>::value,
                   "BadBlockProtocol subclasses must implement "
-                  "GetBadBlockList(uint32_t* bad_blocks, "
-                  "uint32_t bad_block_len, uint32_t* num_bad_blocks)");
-    static_assert(internal::has_mark_block_bad<D>::value,
+                  "zx_status_t BadBlockGetBadBlockList(uint32_t* out_bad_blocks_list, size_t "
+                  "bad_blocks_count, size_t* out_bad_blocks_actual");
+    static_assert(internal::has_bad_block_protocol_mark_block_bad<D>::value,
                   "BadBlockProtocol subclasses must implement "
-                  "MarkBlockBad(uint32_t block)");
+                  "zx_status_t BadBlockMarkBlockBad(uint32_t block");
 }
 
 } // namespace internal
diff --git a/system/ulib/ddktl/include/ddktl/protocol/bad-block.h b/system/ulib/ddktl/include/ddktl/protocol/bad-block.h
index a423ec7..3107e1a 100644
--- a/system/ulib/ddktl/include/ddktl/protocol/bad-block.h
+++ b/system/ulib/ddktl/include/ddktl/protocol/bad-block.h
@@ -2,41 +2,46 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
 #include <ddk/protocol/bad-block.h>
 #include <ddktl/device-internal.h>
+#include <zircon/assert.h>
+#include <zircon/compiler.h>
+#include <zircon/types.h>
 
 #include "bad-block-internal.h"
 
-// DDK bad-block protocol support.
+// DDK bad-block-protocol support
 //
 // :: Proxies ::
 //
-// ddk::BadBlockProtocolProxy is a simple wrappers around bad_block_protocol_t. It does
-// not own the pointers passed to it.
+// ddk::BadBlockProtocolProxy is a simple wrapper around
+// bad_block_protocol_t. It does not own the pointers passed to it
 //
 // :: Mixins ::
 //
-// ddk::BadBlockable is a mixin class that simplifies writing DDK drivers that
-// implement the bad-block protocol. It does not set the base protocol.
+// ddk::BadBlockProtocol is a mixin class that simplifies writing DDK drivers
+// that implement the bad-block protocol. It doesn't set the base protocol.
 //
 // :: Examples ::
 //
 // // A driver that implements a ZX_PROTOCOL_BAD_BLOCK device.
-// class BadBlockDevice;
+// class BadBlockDevice {
 // using BadBlockDeviceType = ddk::Device<BadBlockDevice, /* ddk mixins */>;
 //
 // class BadBlockDevice : public BadBlockDeviceType,
-//                        public ddk::BadBlockable<BadBlockDevice> {
+//                        public ddk::BadBlockProtocol<BadBlockDevice> {
 //   public:
 //     BadBlockDevice(zx_device_t* parent)
-//       : BadBlockDeviceType("my-bad-block-device", parent) {}
+//         : BadBlockDeviceType("my-bad-block-protocol-device", parent) {}
 //
-//     zx_status_t GetBadBlockList(uint32_t* bad_block_list, uint32_t bad_block_list_len,
-//                                 uint32_t* bad_block_count);
-//     zx_status_t IsBlockBad(uint32_t block, bool* is_bad);
-//     zx_status_t MarkBlockBad(uint32_t block);
+//     zx_status_t BadBlockGetBadBlockList(uint32_t* out_bad_blocks_list, size_t bad_blocks_count,
+//     size_t* out_bad_blocks_actual);
+//
+//     zx_status_t BadBlockMarkBlockBad(uint32_t block);
 //
 //     ...
 // };
@@ -44,42 +49,61 @@
 namespace ddk {
 
 template <typename D>
-class BadBlockable : public internal::base_mixin {
+class BadBlockProtocol : public internal::base_mixin {
 public:
-    BadBlockable() {
-        internal::CheckBadBlockable<D>();
-        bad_block_proto_ops_.get_bad_block_list = GetBadBlockList;
-        bad_block_proto_ops_.mark_block_bad = MarkBlockBad;
+    BadBlockProtocol() {
+        internal::CheckBadBlockProtocolSubclass<D>();
+        bad_block_protocol_ops_.get_bad_block_list = BadBlockGetBadBlockList;
+        bad_block_protocol_ops_.mark_block_bad = BadBlockMarkBlockBad;
     }
 
 protected:
-    bad_block_protocol_ops_t bad_block_proto_ops_ = {};
+    bad_block_protocol_ops_t bad_block_protocol_ops_ = {};
 
 private:
-    static zx_status_t GetBadBlockList(void* ctx, uint32_t* bad_block_list,
-                                       uint32_t bad_block_list_len, uint32_t* bad_block_count) {
-        return static_cast<D*>(ctx)->GetBadBlockList(bad_block_list, bad_block_list_len,
-                                                      bad_block_count);
+    // Fills in |bad_blocks| with a list of bad blocks, up until
+    // |bad_blocks_count|. The order of blocks is undefined.
+    // |bad_blocks_actual| will be filled in with the actual number of bad
+    // blocks. It is recommended to first make call with |bad_blocks_count|
+    // equal to 0 in order to determine how large the |bad_blocks| is.
+    static zx_status_t BadBlockGetBadBlockList(void* ctx, uint32_t* out_bad_blocks_list,
+                                               size_t bad_blocks_count,
+                                               size_t* out_bad_blocks_actual) {
+        return static_cast<D*>(ctx)->BadBlockGetBadBlockList(out_bad_blocks_list, bad_blocks_count,
+                                                             out_bad_blocks_actual);
     }
-
-    static zx_status_t MarkBlockBad(void* ctx, uint32_t block) {
-        return static_cast<D*>(ctx)->MarkBlockBad(block);
+    // Sets |block| as bad. If block is already marked bad, it has no effect.
+    static zx_status_t BadBlockMarkBlockBad(void* ctx, uint32_t block) {
+        return static_cast<D*>(ctx)->BadBlockMarkBlockBad(block);
     }
 };
 
 class BadBlockProtocolProxy {
 public:
-    BadBlockProtocolProxy(bad_block_protocol_t* proto)
-        : ops_(proto->ops), ctx_(proto->ctx) {}
+    BadBlockProtocolProxy() : ops_(nullptr), ctx_(nullptr) {}
+    BadBlockProtocolProxy(const bad_block_protocol_t* proto) : ops_(proto->ops), ctx_(proto->ctx) {}
 
-    zx_status_t GetBadBlockList(uint32_t* bad_block_list, uint32_t bad_block_list_len,
-                                uint32_t* bad_block_count) {
-        return ops_->get_bad_block_list(ctx_, bad_block_list, bad_block_list_len, bad_block_count);
+    void GetProto(bad_block_protocol_t* proto) {
+        proto->ctx = ctx_;
+        proto->ops = ops_;
     }
-
-    zx_status_t MarkBlockBad(uint32_t block) {
-        return ops_->mark_block_bad(ctx_, block);
+    bool is_valid() { return ops_ != nullptr; }
+    void clear() {
+        ctx_ = nullptr;
+        ops_ = nullptr;
     }
+    // Fills in |bad_blocks| with a list of bad blocks, up until
+    // |bad_blocks_count|. The order of blocks is undefined.
+    // |bad_blocks_actual| will be filled in with the actual number of bad
+    // blocks. It is recommended to first make call with |bad_blocks_count|
+    // equal to 0 in order to determine how large the |bad_blocks| is.
+    zx_status_t GetBadBlockList(uint32_t* out_bad_blocks_list, size_t bad_blocks_count,
+                                size_t* out_bad_blocks_actual) {
+        return ops_->get_bad_block_list(ctx_, out_bad_blocks_list, bad_blocks_count,
+                                        out_bad_blocks_actual);
+    }
+    // Sets |block| as bad. If block is already marked bad, it has no effect.
+    zx_status_t MarkBlockBad(uint32_t block) { return ops_->mark_block_bad(ctx_, block); }
 
 private:
     bad_block_protocol_ops_t* ops_;
diff --git a/system/ulib/ddktl/include/ddktl/protocol/bt-hci-internal.h b/system/ulib/ddktl/include/ddktl/protocol/bt-hci-internal.h
new file mode 100644
index 0000000..9f415b8
--- /dev/null
+++ b/system/ulib/ddktl/include/ddktl/protocol/bt-hci-internal.h
@@ -0,0 +1,38 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: This file is machine generated by fidlc.
+
+#pragma once
+
+#include <ddk/protocol/bt-hci.h>
+#include <fbl/type_support.h>
+
+namespace ddk {
+namespace internal {
+
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_bt_hci_protocol_open_command_channel,
+                                     BtHciOpenCommandChannel,
+                                     zx_status_t (C::*)(zx_handle_t* out_channel));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_bt_hci_protocol_open_acl_data_channel,
+                                     BtHciOpenAclDataChannel,
+                                     zx_status_t (C::*)(zx_handle_t* out_channel));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_bt_hci_protocol_open_snoop_channel, BtHciOpenSnoopChannel,
+                                     zx_status_t (C::*)(zx_handle_t* out_channel));
+
+template <typename D>
+constexpr void CheckBtHciProtocolSubclass() {
+    static_assert(internal::has_bt_hci_protocol_open_command_channel<D>::value,
+                  "BtHciProtocol subclasses must implement "
+                  "zx_status_t BtHciOpenCommandChannel(zx_handle_t* out_channel");
+    static_assert(internal::has_bt_hci_protocol_open_acl_data_channel<D>::value,
+                  "BtHciProtocol subclasses must implement "
+                  "zx_status_t BtHciOpenAclDataChannel(zx_handle_t* out_channel");
+    static_assert(internal::has_bt_hci_protocol_open_snoop_channel<D>::value,
+                  "BtHciProtocol subclasses must implement "
+                  "zx_status_t BtHciOpenSnoopChannel(zx_handle_t* out_channel");
+}
+
+} // namespace internal
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/bt-hci.h b/system/ulib/ddktl/include/ddktl/protocol/bt-hci.h
index a7505fa..897e254 100644
--- a/system/ulib/ddktl/include/ddktl/protocol/bt-hci.h
+++ b/system/ulib/ddktl/include/ddktl/protocol/bt-hci.h
@@ -1,48 +1,51 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
-#include <ddk/driver.h>
+#include <ddk/protocol/bt-hci.h>
 #include <ddktl/device-internal.h>
-#include <fbl/type_support.h>
 #include <zircon/assert.h>
+#include <zircon/compiler.h>
+#include <zircon/types.h>
 
-// DDK bt-hci protocol support
+#include "bt-hci-internal.h"
+
+// DDK bt-hci-protocol support
+//
+// :: Proxies ::
+//
+// ddk::BtHciProtocolProxy is a simple wrapper around
+// bt_hci_protocol_t. It does not own the pointers passed to it
 //
 // :: Mixins ::
 //
-// ddk::BtHciProtocol enables writing DDK drivers that implement the bt-hci
-// protocol.  The bt-hci protocol is currently empty, being a protocol that is
-// implemented entirely through ioctls.
+// ddk::BtHciProtocol is a mixin class that simplifies writing DDK drivers
+// that implement the bt-hci protocol. It doesn't set the base protocol.
 //
-// :: Example ::
+// :: Examples ::
 //
-// // A driver that implements a ZX_PROTOCOL_BT_HCI device
-// class BtHciDevice;
-// using BtHciDeviceType = ddk::Device<BtHciDevice, ddk::Ioctlable,
-//                                    /* other ddk mixins */>;
+// // A driver that implements a ZX_PROTOCOL_BT_HCI device.
+// class BtHciDevice {
+// using BtHciDeviceType = ddk::Device<BtHciDevice, /* ddk mixins */>;
 //
 // class BtHciDevice : public BtHciDeviceType,
 //                     public ddk::BtHciProtocol<BtHciDevice> {
 //   public:
 //     BtHciDevice(zx_device_t* parent)
-//       : BtHciDeviceType(parent)  {}
+//         : BtHciDeviceType("my-bt-hci-protocol-device", parent) {}
 //
-//     zx_status_t Bind() {
-//         return DdkAdd("my-bt-hci-device");
-//     }
+//     zx_status_t BtHciOpenCommandChannel(zx_handle_t* out_channel);
 //
-//     void DdkRelease() {
-//         // Clean up
-//     }
+//     zx_status_t BtHciOpenAclDataChannel(zx_handle_t* out_channel);
 //
-//     zx_status_t DdkIoctl(uint32_t op, const void *in_buf ... ) {
-//        // Handle IOCTL_BT_HCI_*
-//     }
+//     zx_status_t BtHciOpenSnoopChannel(zx_handle_t* out_channel);
+//
+//     ...
 // };
-//
 
 namespace ddk {
 
@@ -50,10 +53,83 @@
 class BtHciProtocol : public internal::base_protocol {
 public:
     BtHciProtocol() {
-        // Can only inherit from one base_protocol implementation
-        ZX_ASSERT(this->ddk_proto_id_ == 0);
+        internal::CheckBtHciProtocolSubclass<D>();
+        ops_.open_command_channel = BtHciOpenCommandChannel;
+        ops_.open_acl_data_channel = BtHciOpenAclDataChannel;
+        ops_.open_snoop_channel = BtHciOpenSnoopChannel;
+
+        // Can only inherit from one base_protocol implementation.
+        ZX_ASSERT(ddk_proto_id_ = 0);
         ddk_proto_id_ = ZX_PROTOCOL_BT_HCI;
+        ddk_proto_ops_ = &ops_;
     }
+
+protected:
+    bt_hci_protocol_ops_t ops_ = {};
+
+private:
+    // Open the two-way HCI command channel for sending HCI commands and
+    // receiving event packets.  Returns ZX_ERR_ALREADY_BOUND if the channel
+    // is already open.
+    static zx_status_t BtHciOpenCommandChannel(void* ctx, zx_handle_t* out_channel) {
+        return static_cast<D*>(ctx)->BtHciOpenCommandChannel(out_channel);
+    }
+    // Open the two-way HCI ACL data channel.
+    // Returns ZX_ERR_ALREADY_BOUND if the channel is already open.
+    static zx_status_t BtHciOpenAclDataChannel(void* ctx, zx_handle_t* out_channel) {
+        return static_cast<D*>(ctx)->BtHciOpenAclDataChannel(out_channel);
+    }
+    // Open an output-only channel for monitoring HCI traffic.
+    // The format of each message is: [1-octet flags] [n-octet payload]
+    // The flags octet is a bitfield with the following values defined:
+    //  - 0x00: The payload represents a command packet sent from the host to the
+    //          controller.
+    //  - 0x01: The payload represents an event packet sent by the controller.
+    // Returns ZX_ERR_ALREADY_BOUND if the channel is already open.
+    static zx_status_t BtHciOpenSnoopChannel(void* ctx, zx_handle_t* out_channel) {
+        return static_cast<D*>(ctx)->BtHciOpenSnoopChannel(out_channel);
+    }
+};
+
+class BtHciProtocolProxy {
+public:
+    BtHciProtocolProxy() : ops_(nullptr), ctx_(nullptr) {}
+    BtHciProtocolProxy(const bt_hci_protocol_t* proto) : ops_(proto->ops), ctx_(proto->ctx) {}
+
+    void GetProto(bt_hci_protocol_t* proto) {
+        proto->ctx = ctx_;
+        proto->ops = ops_;
+    }
+    bool is_valid() { return ops_ != nullptr; }
+    void clear() {
+        ctx_ = nullptr;
+        ops_ = nullptr;
+    }
+    // Open the two-way HCI command channel for sending HCI commands and
+    // receiving event packets.  Returns ZX_ERR_ALREADY_BOUND if the channel
+    // is already open.
+    zx_status_t OpenCommandChannel(zx_handle_t* out_channel) {
+        return ops_->open_command_channel(ctx_, out_channel);
+    }
+    // Open the two-way HCI ACL data channel.
+    // Returns ZX_ERR_ALREADY_BOUND if the channel is already open.
+    zx_status_t OpenAclDataChannel(zx_handle_t* out_channel) {
+        return ops_->open_acl_data_channel(ctx_, out_channel);
+    }
+    // Open an output-only channel for monitoring HCI traffic.
+    // The format of each message is: [1-octet flags] [n-octet payload]
+    // The flags octet is a bitfield with the following values defined:
+    //  - 0x00: The payload represents a command packet sent from the host to the
+    //          controller.
+    //  - 0x01: The payload represents an event packet sent by the controller.
+    // Returns ZX_ERR_ALREADY_BOUND if the channel is already open.
+    zx_status_t OpenSnoopChannel(zx_handle_t* out_channel) {
+        return ops_->open_snoop_channel(ctx_, out_channel);
+    }
+
+private:
+    bt_hci_protocol_ops_t* ops_;
+    void* ctx_;
 };
 
 } // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/clk-internal.h b/system/ulib/ddktl/include/ddktl/protocol/clk-internal.h
index c901463..5d1b195 100644
--- a/system/ulib/ddktl/include/ddktl/protocol/clk-internal.h
+++ b/system/ulib/ddktl/include/ddktl/protocol/clk-internal.h
@@ -2,27 +2,30 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
+#include <ddk/protocol/clk.h>
 #include <fbl/type_support.h>
 
 namespace ddk {
 namespace internal {
 
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_clk_enable, ClkEnable,
-        zx_status_t (C::*)(uint32_t));
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_clk_disable, ClkDisable,
-        zx_status_t (C::*)(uint32_t));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_clk_protocol_enable, ClkEnable,
+                                     zx_status_t (C::*)(uint32_t index));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_clk_protocol_disable, ClkDisable,
+                                     zx_status_t (C::*)(uint32_t index));
 
 template <typename D>
 constexpr void CheckClkProtocolSubclass() {
-    static_assert(internal::has_clk_enable<D>::value,
+    static_assert(internal::has_clk_protocol_enable<D>::value,
                   "ClkProtocol subclasses must implement "
-                  "ClkEnable(uint32_t index)");
-    static_assert(internal::has_clk_disable<D>::value,
+                  "zx_status_t ClkEnable(uint32_t index");
+    static_assert(internal::has_clk_protocol_disable<D>::value,
                   "ClkProtocol subclasses must implement "
-                  "ClkDisable(uint32_t index)");
- }
+                  "zx_status_t ClkDisable(uint32_t index");
+}
 
-}  // namespace internal
-}  // namespace ddk
+} // namespace internal
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/clk.h b/system/ulib/ddktl/include/ddktl/protocol/clk.h
index d5a7c70..ba950cb 100644
--- a/system/ulib/ddktl/include/ddktl/protocol/clk.h
+++ b/system/ulib/ddktl/include/ddktl/protocol/clk.h
@@ -2,40 +2,46 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
 #include <ddk/protocol/clk.h>
 #include <ddktl/device-internal.h>
 #include <zircon/assert.h>
-#include <ddk/driver.h>
+#include <zircon/compiler.h>
+#include <zircon/types.h>
+
 #include "clk-internal.h"
 
-// DDK clock protocol support.
+// DDK clk-protocol support
 //
 // :: Proxies ::
 //
-// ddk::ClkProtocolProxy is a simple wrappers around clk_protocol_t. It does
-// not own the pointers passed to it.
+// ddk::ClkProtocolProxy is a simple wrapper around
+// clk_protocol_t. It does not own the pointers passed to it
 //
 // :: Mixins ::
 //
-// ddk::ClkProtocol is a mixin class that simplifies writing DDK drivers that
-// implement the clock protocol.
+// ddk::ClkProtocol is a mixin class that simplifies writing DDK drivers
+// that implement the clk protocol. It doesn't set the base protocol.
 //
 // :: Examples ::
 //
 // // A driver that implements a ZX_PROTOCOL_CLK device.
-// class ClkDevice;
+// class ClkDevice {
 // using ClkDeviceType = ddk::Device<ClkDevice, /* ddk mixins */>;
 //
 // class ClkDevice : public ClkDeviceType,
 //                   public ddk::ClkProtocol<ClkDevice> {
 //   public:
 //     ClkDevice(zx_device_t* parent)
-//       : ClkDeviceType("my-clk-device", parent) {}
+//         : ClkDeviceType("my-clk-protocol-device", parent) {}
 //
-//        zx_status_t ClkEnable(uint32_t index);
-//        zx_status_t ClkDisable(uint32_t index);
+//     zx_status_t ClkEnable(uint32_t index);
+//
+//     zx_status_t ClkDisable(uint32_t index);
+//
 //     ...
 // };
 
@@ -49,8 +55,8 @@
         ops_.enable = ClkEnable;
         ops_.disable = ClkDisable;
 
-        // Can only inherit from one base_protocol implemenation
-        ZX_ASSERT(ddk_proto_id_ == 0);
+        // Can only inherit from one base_protocol implementation.
+        ZX_ASSERT(ddk_proto_id_ = 0);
         ddk_proto_id_ = ZX_PROTOCOL_CLK;
         ddk_proto_ops_ = &ops_;
     }
@@ -69,20 +75,20 @@
 
 class ClkProtocolProxy {
 public:
-    ClkProtocolProxy(clk_protocol_t* proto)
-        : ops_(proto->ops), ctx_(proto->ctx) {}
+    ClkProtocolProxy() : ops_(nullptr), ctx_(nullptr) {}
+    ClkProtocolProxy(const clk_protocol_t* proto) : ops_(proto->ops), ctx_(proto->ctx) {}
 
     void GetProto(clk_protocol_t* proto) {
         proto->ctx = ctx_;
         proto->ops = ops_;
     }
-
-    zx_status_t Enable(uint32_t index) {
-        return ops_->enable(ctx_, index);
+    bool is_valid() { return ops_ != nullptr; }
+    void clear() {
+        ctx_ = nullptr;
+        ops_ = nullptr;
     }
-    zx_status_t Disable(uint32_t index) {
-        return ops_->disable(ctx_, index);
-    }
+    zx_status_t Enable(uint32_t index) { return ops_->enable(ctx_, index); }
+    zx_status_t Disable(uint32_t index) { return ops_->disable(ctx_, index); }
 
 private:
     clk_protocol_ops_t* ops_;
diff --git a/system/ulib/ddktl/include/ddktl/protocol/display-controller-internal.h b/system/ulib/ddktl/include/ddktl/protocol/display-controller-internal.h
new file mode 100644
index 0000000..cd4190b
--- /dev/null
+++ b/system/ulib/ddktl/include/ddktl/protocol/display-controller-internal.h
@@ -0,0 +1,109 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: This file is machine generated by fidlc.
+
+#pragma once
+
+#include <ddk/protocol/display-controller.h>
+#include <fbl/type_support.h>
+
+namespace ddk {
+namespace internal {
+
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(
+    has_display_controller_interface_on_displays_changed,
+    DisplayControllerInterfaceOnDisplaysChanged,
+    void (C::*)(const added_display_args_t* added_display_list, size_t added_display_count,
+                const uint64_t* removed_display_list, size_t removed_display_count,
+                added_display_info_t* out_display_info_list, size_t display_info_count,
+                size_t* out_display_info_actual));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_display_controller_interface_on_display_vsync,
+                                     DisplayControllerInterfaceOnDisplayVsync,
+                                     void (C::*)(uint64_t display_id, int64_t timestamp,
+                                                 const uint64_t* handle_list, size_t handle_count));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_display_controller_interface_get_audio_format,
+                                     DisplayControllerInterfaceGetAudioFormat,
+                                     zx_status_t (C::*)(uint64_t display_id, uint32_t fmt_idx,
+                                                        audio_stream_format_range_t* out_fmt));
+
+template <typename D>
+constexpr void CheckDisplayControllerInterfaceSubclass() {
+    static_assert(
+        internal::has_display_controller_interface_on_displays_changed<D>::value,
+        "DisplayControllerInterface subclasses must implement "
+        "void DisplayControllerInterfaceOnDisplaysChanged(const added_display_args_t* "
+        "added_display_list, size_t added_display_count, const uint64_t* removed_display_list, "
+        "size_t removed_display_count, added_display_info_t* out_display_info_list, size_t "
+        "display_info_count, size_t* out_display_info_actual");
+    static_assert(internal::has_display_controller_interface_on_display_vsync<D>::value,
+                  "DisplayControllerInterface subclasses must implement "
+                  "void DisplayControllerInterfaceOnDisplayVsync(uint64_t display_id, int64_t "
+                  "timestamp, const uint64_t* handle_list, size_t handle_count");
+    static_assert(internal::has_display_controller_interface_get_audio_format<D>::value,
+                  "DisplayControllerInterface subclasses must implement "
+                  "zx_status_t DisplayControllerInterfaceGetAudioFormat(uint64_t display_id, "
+                  "uint32_t fmt_idx, audio_stream_format_range_t* out_fmt");
+}
+
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(
+    has_display_controller_protocol_set_display_controller_interface,
+    DisplayControllerSetDisplayControllerInterface,
+    void (C::*)(const display_controller_interface_t* intf));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_display_controller_protocol_import_vmo_image,
+                                     DisplayControllerImportVmoImage,
+                                     zx_status_t (C::*)(image_t* image, zx_handle_t vmo,
+                                                        size_t offset));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_display_controller_protocol_release_image,
+                                     DisplayControllerReleaseImage, void (C::*)(image_t* image));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(
+    has_display_controller_protocol_check_configuration, DisplayControllerCheckConfiguration,
+    uint32_t (C::*)(const display_config_t** display_config_list, size_t display_config_count,
+                    uint32_t** out_layer_cfg_result_list, size_t* layer_cfg_result_count));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_display_controller_protocol_apply_configuration,
+                                     DisplayControllerApplyConfiguration,
+                                     void (C::*)(const display_config_t** display_config_list,
+                                                 size_t display_config_count));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_display_controller_protocol_compute_linear_stride,
+                                     DisplayControllerComputeLinearStride,
+                                     uint32_t (C::*)(uint32_t width,
+                                                     zx_pixel_format_t pixel_format));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_display_controller_protocol_allocate_vmo,
+                                     DisplayControllerAllocateVmo,
+                                     zx_status_t (C::*)(uint64_t size, zx_handle_t* out_vmo));
+
+template <typename D>
+constexpr void CheckDisplayControllerProtocolSubclass() {
+    static_assert(
+        internal::has_display_controller_protocol_set_display_controller_interface<D>::value,
+        "DisplayControllerProtocol subclasses must implement "
+        "void DisplayControllerSetDisplayControllerInterface(const display_controller_interface_t* "
+        "intf");
+    static_assert(internal::has_display_controller_protocol_import_vmo_image<D>::value,
+                  "DisplayControllerProtocol subclasses must implement "
+                  "zx_status_t DisplayControllerImportVmoImage(image_t* image, zx_handle_t vmo, "
+                  "size_t offset");
+    static_assert(internal::has_display_controller_protocol_release_image<D>::value,
+                  "DisplayControllerProtocol subclasses must implement "
+                  "void DisplayControllerReleaseImage(image_t* image");
+    static_assert(internal::has_display_controller_protocol_check_configuration<D>::value,
+                  "DisplayControllerProtocol subclasses must implement "
+                  "uint32_t DisplayControllerCheckConfiguration(const display_config_t** "
+                  "display_config_list, size_t display_config_count, uint32_t** "
+                  "out_layer_cfg_result_list, size_t* layer_cfg_result_count");
+    static_assert(internal::has_display_controller_protocol_apply_configuration<D>::value,
+                  "DisplayControllerProtocol subclasses must implement "
+                  "void DisplayControllerApplyConfiguration(const display_config_t** "
+                  "display_config_list, size_t display_config_count");
+    static_assert(internal::has_display_controller_protocol_compute_linear_stride<D>::value,
+                  "DisplayControllerProtocol subclasses must implement "
+                  "uint32_t DisplayControllerComputeLinearStride(uint32_t width, zx_pixel_format_t "
+                  "pixel_format");
+    static_assert(internal::has_display_controller_protocol_allocate_vmo<D>::value,
+                  "DisplayControllerProtocol subclasses must implement "
+                  "zx_status_t DisplayControllerAllocateVmo(uint64_t size, zx_handle_t* out_vmo");
+}
+
+} // namespace internal
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/display-controller.h b/system/ulib/ddktl/include/ddktl/protocol/display-controller.h
index 47303e1..becbbb3 100644
--- a/system/ulib/ddktl/include/ddktl/protocol/display-controller.h
+++ b/system/ulib/ddktl/include/ddktl/protocol/display-controller.h
@@ -2,69 +2,346 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
-#include <ddk/driver.h>
 #include <ddk/protocol/display-controller.h>
 #include <ddktl/device-internal.h>
-#include <lib/zx/vmo.h>
 #include <zircon/assert.h>
+#include <zircon/compiler.h>
+#include <zircon/device/audio.h>
+#include <zircon/types.h>
+
+#include "display-controller-internal.h"
+
+// DDK display-controller-protocol support
+//
+// :: Proxies ::
+//
+// ddk::DisplayControllerProtocolProxy is a simple wrapper around
+// display_controller_protocol_t. It does not own the pointers passed to it
+//
+// :: Mixins ::
+//
+// ddk::DisplayControllerProtocol is a mixin class that simplifies writing DDK drivers
+// that implement the display-controller protocol. It doesn't set the base protocol.
+//
+// :: Examples ::
+//
+// // A driver that implements a ZX_PROTOCOL_DISPLAY_CONTROLLER device.
+// class DisplayControllerDevice {
+// using DisplayControllerDeviceType = ddk::Device<DisplayControllerDevice, /* ddk mixins */>;
+//
+// class DisplayControllerDevice : public DisplayControllerDeviceType,
+//                                 public ddk::DisplayControllerProtocol<DisplayControllerDevice> {
+//   public:
+//     DisplayControllerDevice(zx_device_t* parent)
+//         : DisplayControllerDeviceType("my-display-controller-protocol-device", parent) {}
+//
+//     void DisplayControllerSetDisplayControllerInterface(const display_controller_interface_t*
+//     intf);
+//
+//     zx_status_t DisplayControllerImportVmoImage(image_t* image, zx_handle_t vmo, size_t offset);
+//
+//     void DisplayControllerReleaseImage(image_t* image);
+//
+//     uint32_t DisplayControllerCheckConfiguration(const display_config_t** display_config_list,
+//     size_t display_config_count, uint32_t** out_layer_cfg_result_list, size_t*
+//     layer_cfg_result_count);
+//
+//     void DisplayControllerApplyConfiguration(const display_config_t** display_config_list, size_t
+//     display_config_count);
+//
+//     uint32_t DisplayControllerComputeLinearStride(uint32_t width, zx_pixel_format_t
+//     pixel_format);
+//
+//     zx_status_t DisplayControllerAllocateVmo(uint64_t size, zx_handle_t* out_vmo);
+//
+//     ...
+// };
 
 namespace ddk {
 
+// The client will not make any `ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL` calls into the device
+// during these callbacks.
 template <typename D>
-class DisplayControllerProtocol : public internal::base_protocol {
-  public:
-    DisplayControllerProtocol() {
-        // TODO(stevensd): Add subclass check once API is stabilized
-        ops_.set_display_controller_cb = SetDisplayControllerCb;
-        ops_.import_vmo_image = ImportVmoImage;
-        ops_.release_image = ReleaseImage;
-        ops_.check_configuration = CheckConfiguration;
-        ops_.apply_configuration = ApplyConfiguration;
-        ops_.compute_linear_stride = ComputeLinearStride;
-        ops_.allocate_vmo = AllocateVmo;
-
-        // Can only inherit from one base_protocol implemenation
-        ZX_ASSERT(ddk_proto_id_ == 0);
-        ddk_proto_id_ = ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL;
-        ddk_proto_ops_ = &ops_;
+class DisplayControllerInterface : public internal::base_mixin {
+public:
+    DisplayControllerInterface() {
+        internal::CheckDisplayControllerInterfaceSubclass<D>();
+        display_controller_interface_ops_.on_displays_changed =
+            DisplayControllerInterfaceOnDisplaysChanged;
+        display_controller_interface_ops_.on_display_vsync =
+            DisplayControllerInterfaceOnDisplayVsync;
+        display_controller_interface_ops_.get_audio_format =
+            DisplayControllerInterfaceGetAudioFormat;
     }
 
-  private:
-    static void SetDisplayControllerCb(void* ctx, void* cb_ctx, display_controller_cb_t* cb) {
-        static_cast<D*>(ctx)->SetDisplayControllerCb(cb_ctx, cb);
-    }
+protected:
+    display_controller_interface_ops_t display_controller_interface_ops_ = {};
 
-    static zx_status_t ImportVmoImage(void* ctx, image_t* image, zx_handle_t vmo, size_t offset) {
-        return static_cast<D*>(ctx)->ImportVmoImage(image, *zx::unowned_vmo(vmo), offset);
+private:
+    // Callbacks which are invoked when displays are added or removed. |added_display_list| and
+    // |removed_display_list| point to arrays of the display ids which were added and removed. If
+    // |added_display_count| or |removed_display_count| is 0, the corresponding array can be NULL.
+    // The driver must be done accessing any images which were on the removed displays.
+    // The driver should call this function when the callback is registered if any displays
+    // are present.
+    static void DisplayControllerInterfaceOnDisplaysChanged(
+        void* ctx, const added_display_args_t* added_display_list, size_t added_display_count,
+        const uint64_t* removed_display_list, size_t removed_display_count,
+        added_display_info_t* out_display_info_list, size_t display_info_count,
+        size_t* out_display_info_actual) {
+        static_cast<D*>(ctx)->DisplayControllerInterfaceOnDisplaysChanged(
+            added_display_list, added_display_count, removed_display_list, removed_display_count,
+            out_display_info_list, display_info_count, out_display_info_actual);
     }
-
-    static void ReleaseImage(void* ctx, image_t* image) {
-        static_cast<D*>(ctx)->ReleaseImage(image);
+    // |timestamp| is the ZX_CLOCK_MONOTONIC timestamp at which the vsync occurred.
+    // |handles| points to an array of image handles of each framebuffer being
+    // displayed, in increasing z-order.
+    static void DisplayControllerInterfaceOnDisplayVsync(void* ctx, uint64_t display_id,
+                                                         int64_t timestamp,
+                                                         const uint64_t* handle_list,
+                                                         size_t handle_count) {
+        static_cast<D*>(ctx)->DisplayControllerInterfaceOnDisplayVsync(display_id, timestamp,
+                                                                       handle_list, handle_count);
     }
-
-    static void CheckConfiguration(void* ctx, const display_config_t** display_config,
-                                   uint32_t* display_cfg_result, uint32_t** layer_cfg_result,
-                                   uint32_t display_count) {
-        static_cast<D*>(ctx)->CheckConfiguration(display_config, display_cfg_result,
-                                                 layer_cfg_result, display_count);
+    static zx_status_t
+    DisplayControllerInterfaceGetAudioFormat(void* ctx, uint64_t display_id, uint32_t fmt_idx,
+                                             audio_stream_format_range_t* out_fmt) {
+        return static_cast<D*>(ctx)->DisplayControllerInterfaceGetAudioFormat(display_id, fmt_idx,
+                                                                              out_fmt);
     }
-
-    static void ApplyConfiguration(void* ctx, const display_config_t** display_config,
-                                   uint32_t display_count) {
-        static_cast<D*>(ctx)->ApplyConfiguration(display_config, display_count);
-    }
-
-    static uint32_t ComputeLinearStride(void* ctx, uint32_t width, zx_pixel_format_t format) {
-        return static_cast<D*>(ctx)->ComputeLinearStride(width, format);
-    }
-
-    static zx_status_t AllocateVmo(void* ctx, uint64_t size, zx_handle_t* vmo_out) {
-        return static_cast<D*>(ctx)->AllocateVmo(size, vmo_out);
-    }
-
-    display_controller_protocol_ops_t ops_ = {};
 };
 
-}
+class DisplayControllerInterfaceProxy {
+public:
+    DisplayControllerInterfaceProxy() : ops_(nullptr), ctx_(nullptr) {}
+    DisplayControllerInterfaceProxy(const display_controller_interface_t* proto)
+        : ops_(proto->ops), ctx_(proto->ctx) {}
+
+    void GetProto(display_controller_interface_t* proto) {
+        proto->ctx = ctx_;
+        proto->ops = ops_;
+    }
+    bool is_valid() { return ops_ != nullptr; }
+    void clear() {
+        ctx_ = nullptr;
+        ops_ = nullptr;
+    }
+    // Callbacks which are invoked when displays are added or removed. |added_display_list| and
+    // |removed_display_list| point to arrays of the display ids which were added and removed. If
+    // |added_display_count| or |removed_display_count| is 0, the corresponding array can be NULL.
+    // The driver must be done accessing any images which were on the removed displays.
+    // The driver should call this function when the callback is registered if any displays
+    // are present.
+    void OnDisplaysChanged(const added_display_args_t* added_display_list,
+                           size_t added_display_count, const uint64_t* removed_display_list,
+                           size_t removed_display_count,
+                           added_display_info_t* out_display_info_list, size_t display_info_count,
+                           size_t* out_display_info_actual) {
+        ops_->on_displays_changed(ctx_, added_display_list, added_display_count,
+                                  removed_display_list, removed_display_count,
+                                  out_display_info_list, display_info_count,
+                                  out_display_info_actual);
+    }
+    // |timestamp| is the ZX_CLOCK_MONOTONIC timestamp at which the vsync occurred.
+    // |handles| points to an array of image handles of each framebuffer being
+    // displayed, in increasing z-order.
+    void OnDisplayVsync(uint64_t display_id, int64_t timestamp, const uint64_t* handle_list,
+                        size_t handle_count) {
+        ops_->on_display_vsync(ctx_, display_id, timestamp, handle_list, handle_count);
+    }
+    zx_status_t GetAudioFormat(uint64_t display_id, uint32_t fmt_idx,
+                               audio_stream_format_range_t* out_fmt) {
+        return ops_->get_audio_format(ctx_, display_id, fmt_idx, out_fmt);
+    }
+
+private:
+    display_controller_interface_ops_t* ops_;
+    void* ctx_;
+};
+
+// The client guarantees that check_configuration and apply_configuration are always
+// made from a single thread. The client makes no other threading guarantees.
+template <typename D>
+class DisplayControllerProtocol : public internal::base_mixin {
+public:
+    DisplayControllerProtocol() {
+        internal::CheckDisplayControllerProtocolSubclass<D>();
+        display_controller_protocol_ops_.set_display_controller_interface =
+            DisplayControllerSetDisplayControllerInterface;
+        display_controller_protocol_ops_.import_vmo_image = DisplayControllerImportVmoImage;
+        display_controller_protocol_ops_.release_image = DisplayControllerReleaseImage;
+        display_controller_protocol_ops_.check_configuration = DisplayControllerCheckConfiguration;
+        display_controller_protocol_ops_.apply_configuration = DisplayControllerApplyConfiguration;
+        display_controller_protocol_ops_.compute_linear_stride =
+            DisplayControllerComputeLinearStride;
+        display_controller_protocol_ops_.allocate_vmo = DisplayControllerAllocateVmo;
+    }
+
+protected:
+    display_controller_protocol_ops_t display_controller_protocol_ops_ = {};
+
+private:
+    // The function will only be called once, and it will be called before any other
+    // functions are called.
+    static void
+    DisplayControllerSetDisplayControllerInterface(void* ctx,
+                                                   const display_controller_interface_t* intf) {
+        static_cast<D*>(ctx)->DisplayControllerSetDisplayControllerInterface(intf);
+    }
+    // Imports a VMO backed image into the driver. The driver should set image->handle. The
+    // driver does not own the vmo handle passed to this function.
+    static zx_status_t DisplayControllerImportVmoImage(void* ctx, image_t* image, zx_handle_t vmo,
+                                                       size_t offset) {
+        return static_cast<D*>(ctx)->DisplayControllerImportVmoImage(image, vmo, offset);
+    }
+    // Releases any driver state associated with the given image. The client guarantees that
+    // any images passed to apply_config will not be released until a vsync occurs with a
+    // more recent image.
+    static void DisplayControllerReleaseImage(void* ctx, image_t* image) {
+        static_cast<D*>(ctx)->DisplayControllerReleaseImage(image);
+    }
+    // Validates the given configuration.
+    // The configuration may not include all displays. Omiteed displays should be treated as
+    // whichever of off or displaying a blank screen results in a more premissive validation.
+    // All displays in a configuration will have at least one layer. The layers will be
+    // arranged in increasing z-order, and their z_index fields will be set consecutively.
+    // Whether or not the driver can accept the configuration cannot depend on the
+    // particular image handles, as it must always be possible to present a new image in
+    // place of another image with a matching configuration. It also cannot depend on the
+    // cursor position, as that can be updated without another call to check_configuration.
+    // display_cfg_result should be set to a CONFIG_DISPLAY_* error if the combination of
+    // display modes is not supported.
+    // layer_cfg_result points to an array of arrays. The primary length is display_count, the
+    // secondary lengths are the corresponding display_cfg's layer_count. If display_cfg_result
+    // is CONFIG_DISPLAY_OK, any errors in layer configuration should be returned as a CLIENT*
+    // flag in the corresponding layer_cfg_result entry.
+    // The driver must not retain references to the configuration after this function returns.
+    // TODO: Fix me...
+    static uint32_t DisplayControllerCheckConfiguration(
+        void* ctx, const display_config_t** display_config_list, size_t display_config_count,
+        uint32_t** out_layer_cfg_result_list, size_t* layer_cfg_result_count) {
+        return static_cast<D*>(ctx)->DisplayControllerCheckConfiguration(
+            display_config_list, display_config_count, out_layer_cfg_result_list,
+            layer_cfg_result_count);
+    }
+    // Applies the configuration.
+    // All configurations passed to this function will be derived from configurations which
+    // have been succesfully validated, with the only differences either being omitted layers
+    // or different image handles. To account for any layers which are not present, the driver
+    // must use the z_index values of the present layers to configure them as if the whole
+    // configuration was present.
+    // Unlike with check_configuration, displays included in the configuration are not
+    // guaranteed to include any layers. Both omitted displays and displays with no layers
+    // can either be turned off or set to display a blank screen, but for displays with no
+    // layers there is a strong preference to display a blank screen instead of turn them off.
+    // In either case, the driver must drop all references to old images and invoke the vsync
+    // callback after doing so.
+    // The driver must not retain references to the configuration after this function returns.
+    static void DisplayControllerApplyConfiguration(void* ctx,
+                                                    const display_config_t** display_config_list,
+                                                    size_t display_config_count) {
+        static_cast<D*>(ctx)->DisplayControllerApplyConfiguration(display_config_list,
+                                                                  display_config_count);
+    }
+    // Computes the stride (in pixels) necessary for a linear image with the given width
+    // and pixel format. Returns 0 on error.
+    static uint32_t DisplayControllerComputeLinearStride(void* ctx, uint32_t width,
+                                                         zx_pixel_format_t pixel_format) {
+        return static_cast<D*>(ctx)->DisplayControllerComputeLinearStride(width, pixel_format);
+    }
+    // Allocates a VMO of the requested size which can be used for images.
+    static zx_status_t DisplayControllerAllocateVmo(void* ctx, uint64_t size,
+                                                    zx_handle_t* out_vmo) {
+        return static_cast<D*>(ctx)->DisplayControllerAllocateVmo(size, out_vmo);
+    }
+};
+
+class DisplayControllerProtocolProxy {
+public:
+    DisplayControllerProtocolProxy() : ops_(nullptr), ctx_(nullptr) {}
+    DisplayControllerProtocolProxy(const display_controller_protocol_t* proto)
+        : ops_(proto->ops), ctx_(proto->ctx) {}
+
+    void GetProto(display_controller_protocol_t* proto) {
+        proto->ctx = ctx_;
+        proto->ops = ops_;
+    }
+    bool is_valid() { return ops_ != nullptr; }
+    void clear() {
+        ctx_ = nullptr;
+        ops_ = nullptr;
+    }
+    // The function will only be called once, and it will be called before any other
+    // functions are called.
+    void SetDisplayControllerInterface(const display_controller_interface_t* intf) {
+        ops_->set_display_controller_interface(ctx_, intf);
+    }
+    // Imports a VMO backed image into the driver. The driver should set image->handle. The
+    // driver does not own the vmo handle passed to this function.
+    zx_status_t ImportVmoImage(image_t* image, zx_handle_t vmo, size_t offset) {
+        return ops_->import_vmo_image(ctx_, image, vmo, offset);
+    }
+    // Releases any driver state associated with the given image. The client guarantees that
+    // any images passed to apply_config will not be released until a vsync occurs with a
+    // more recent image.
+    void ReleaseImage(image_t* image) { ops_->release_image(ctx_, image); }
+    // Validates the given configuration.
+    // The configuration may not include all displays. Omiteed displays should be treated as
+    // whichever of off or displaying a blank screen results in a more premissive validation.
+    // All displays in a configuration will have at least one layer. The layers will be
+    // arranged in increasing z-order, and their z_index fields will be set consecutively.
+    // Whether or not the driver can accept the configuration cannot depend on the
+    // particular image handles, as it must always be possible to present a new image in
+    // place of another image with a matching configuration. It also cannot depend on the
+    // cursor position, as that can be updated without another call to check_configuration.
+    // display_cfg_result should be set to a CONFIG_DISPLAY_* error if the combination of
+    // display modes is not supported.
+    // layer_cfg_result points to an array of arrays. The primary length is display_count, the
+    // secondary lengths are the corresponding display_cfg's layer_count. If display_cfg_result
+    // is CONFIG_DISPLAY_OK, any errors in layer configuration should be returned as a CLIENT*
+    // flag in the corresponding layer_cfg_result entry.
+    // The driver must not retain references to the configuration after this function returns.
+    // TODO: Fix me...
+    uint32_t CheckConfiguration(const display_config_t** display_config_list,
+                                size_t display_config_count, uint32_t** out_layer_cfg_result_list,
+                                size_t* layer_cfg_result_count) {
+        return ops_->check_configuration(ctx_, display_config_list, display_config_count,
+                                         out_layer_cfg_result_list, layer_cfg_result_count);
+    }
+    // Applies the configuration.
+    // All configurations passed to this function will be derived from configurations which
+    // have been succesfully validated, with the only differences either being omitted layers
+    // or different image handles. To account for any layers which are not present, the driver
+    // must use the z_index values of the present layers to configure them as if the whole
+    // configuration was present.
+    // Unlike with check_configuration, displays included in the configuration are not
+    // guaranteed to include any layers. Both omitted displays and displays with no layers
+    // can either be turned off or set to display a blank screen, but for displays with no
+    // layers there is a strong preference to display a blank screen instead of turn them off.
+    // In either case, the driver must drop all references to old images and invoke the vsync
+    // callback after doing so.
+    // The driver must not retain references to the configuration after this function returns.
+    void ApplyConfiguration(const display_config_t** display_config_list,
+                            size_t display_config_count) {
+        ops_->apply_configuration(ctx_, display_config_list, display_config_count);
+    }
+    // Computes the stride (in pixels) necessary for a linear image with the given width
+    // and pixel format. Returns 0 on error.
+    uint32_t ComputeLinearStride(uint32_t width, zx_pixel_format_t pixel_format) {
+        return ops_->compute_linear_stride(ctx_, width, pixel_format);
+    }
+    // Allocates a VMO of the requested size which can be used for images.
+    zx_status_t AllocateVmo(uint64_t size, zx_handle_t* out_vmo) {
+        return ops_->allocate_vmo(ctx_, size, out_vmo);
+    }
+
+private:
+    display_controller_protocol_ops_t* ops_;
+    void* ctx_;
+};
+
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/ethernet-internal.h b/system/ulib/ddktl/include/ddktl/protocol/ethernet-internal.h
index 449b74f..8416fba 100644
--- a/system/ulib/ddktl/include/ddktl/protocol/ethernet-internal.h
+++ b/system/ulib/ddktl/include/ddktl/protocol/ethernet-internal.h
@@ -1,108 +1,73 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
-#include <ddktl/device-internal.h>
-#include <zircon/types.h>
+#include <ddk/protocol/ethernet.h>
 #include <fbl/type_support.h>
-#include <fbl/unique_ptr.h>
-
-#include <stdint.h>
 
 namespace ddk {
-
-class EthmacIfcProxy;
-
 namespace internal {
 
-DECLARE_HAS_MEMBER_FN(has_ethmac_status, EthmacStatus);
-DECLARE_HAS_MEMBER_FN(has_ethmac_recv, EthmacRecv);
-DECLARE_HAS_MEMBER_FN(has_ethmac_complete_tx, EthmacCompleteTx);
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_ethmac_ifc_status, EthmacIfcStatus,
+                                     void (C::*)(uint32_t status));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_ethmac_ifc_recv, EthmacIfcRecv,
+                                     void (C::*)(const void* data_buffer, size_t data_size,
+                                                 uint32_t flags));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_ethmac_ifc_complete_tx, EthmacIfcCompleteTx,
+                                     void (C::*)(ethmac_netbuf_t* netbuf, zx_status_t status));
 
 template <typename D>
-constexpr void CheckEthmacIfc() {
-    static_assert(internal::has_ethmac_status<D>::value,
-                  "EthmacIfc subclasses must implement EthmacStatus");
-    static_assert(fbl::is_same<decltype(&D::EthmacStatus),
-                                void (D::*)(uint32_t)>::value,
-                  "EthmacStatus must be a non-static member function with signature "
-                  "'void EthmacStatus(uint32_t)', and be visible to ddk::EthmacIfc<D> "
-                  "(either because they are public, or because of friendship).");
-    static_assert(internal::has_ethmac_recv<D>::value,
-                  "EthmacIfc subclasses must implement EthmacRecv");
-    static_assert(fbl::is_same<decltype(&D::EthmacRecv),
-                                void (D::*)(void*, size_t, uint32_t)>::value,
-                  "EthmacQuery must be a non-static member function with signature "
-                  "'void EthmacRecv(void*, size_t, uint32_t)', and be visible to "
-                  "ddk::EthmacIfc<D> (either because they are public, or because of "
-                  "friendship).");
-    static_assert(internal::has_ethmac_complete_tx<D>::value,
-                  "EthmacIfc subclasses must implement EthmacCompleteTx");
-    static_assert(fbl::is_same<decltype(&D::EthmacCompleteTx),
-                                void (D::*)(ethmac_netbuf_t*, zx_status_t)>::value,
-                  "EthmacCompleteTx must be a non-static member function with signature "
-                  "'void EthmacCompleteTx(ethmac_netbuf_t*, zx_status_t)', and be visible to "
-                  "ddk::EthmacIfc<D> (either because they are public, or because of friendship).");
+constexpr void CheckEthmacIfcSubclass() {
+    static_assert(internal::has_ethmac_ifc_status<D>::value,
+                  "EthmacIfc subclasses must implement "
+                  "void EthmacIfcStatus(uint32_t status");
+    static_assert(internal::has_ethmac_ifc_recv<D>::value,
+                  "EthmacIfc subclasses must implement "
+                  "void EthmacIfcRecv(const void* data_buffer, size_t data_size, uint32_t flags");
+    static_assert(internal::has_ethmac_ifc_complete_tx<D>::value,
+                  "EthmacIfc subclasses must implement "
+                  "void EthmacIfcCompleteTx(ethmac_netbuf_t* netbuf, zx_status_t status");
 }
 
-DECLARE_HAS_MEMBER_FN(has_ethmac_query, EthmacQuery);
-DECLARE_HAS_MEMBER_FN(has_ethmac_stop, EthmacStop);
-DECLARE_HAS_MEMBER_FN(has_ethmac_start, EthmacStart);
-DECLARE_HAS_MEMBER_FN(has_ethmac_queue_tx, EthmacQueueTx);
-DECLARE_HAS_MEMBER_FN(has_ethmac_set_param, EthmacSetParam);
-DECLARE_HAS_MEMBER_FN(has_ethmac_get_bti, EthmacGetBti);
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_ethmac_protocol_query, EthmacQuery,
+                                     zx_status_t (C::*)(uint32_t options, ethmac_info_t* out_info));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_ethmac_protocol_stop, EthmacStop, void (C::*)());
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_ethmac_protocol_start, EthmacStart,
+                                     zx_status_t (C::*)(const ethmac_ifc_t* ifc));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_ethmac_protocol_queue_tx, EthmacQueueTx,
+                                     zx_status_t (C::*)(uint32_t options, ethmac_netbuf_t* netbuf));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_ethmac_protocol_set_param, EthmacSetParam,
+                                     zx_status_t (C::*)(uint32_t param, zx_status_t value,
+                                                        const void* data_buffer, size_t data_size));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_ethmac_protocol_get_bti, EthmacGetBti,
+                                     zx_handle_t (C::*)());
 
 template <typename D>
 constexpr void CheckEthmacProtocolSubclass() {
-    static_assert(internal::has_ethmac_query<D>::value,
-                  "EthmacProtocol subclasses must implement EthmacQuery");
-    static_assert(fbl::is_same<decltype(&D::EthmacQuery),
-                                zx_status_t (D::*)(uint32_t, ethmac_info_t*)>::value,
-                  "EthmacQuery must be a non-static member function with signature "
-                  "'zx_status_t EthmacQuery(uint32_t, ethmac_info_t*)', and be visible to "
-                  "ddk::EthmacProtocol<D> (either because they are public, or because of "
-                  "friendship).");
-    static_assert(internal::has_ethmac_stop<D>::value,
-                  "EthmacProtocol subclasses must implement EthmacStop");
-    static_assert(fbl::is_same<decltype(&D::EthmacStop),
-                                void (D::*)()>::value,
-                  "EthmacStop must be a non-static member function with signature "
-                  "'void EthmacStop()', and be visible to ddk::EthmacProtocol<D> (either "
-                  "because they are public, or because of friendship).");
-    static_assert(internal::has_ethmac_start<D>::value,
-                  "EthmacProtocol subclasses must implement EthmacStart");
-    static_assert(fbl::is_same<decltype(&D::EthmacStart),
-                                zx_status_t (D::*)(fbl::unique_ptr<EthmacIfcProxy>)>::value,
-                  "EthmacStart must be a non-static member function with signature "
-                  "'zx_status_t EthmacStart(fbl::unique_ptr<EthmacIfcProxy>)', and be visible "
-                  "to ddk::EthmacProtocol<D> (either because they are public, or because of "
-                  "friendship).");
-    static_assert(internal::has_ethmac_queue_tx<D>::value,
-                  "EthmacProtocol subclasses must implement EthmacQueueTx");
-    static_assert(fbl::is_same<decltype(&D::EthmacQueueTx),
-                                zx_status_t (D::*)(uint32_t, ethmac_netbuf_t*)>::value,
-                  "EthmacQueueTx must be a non-static member function with signature "
-                  "'zx_status_t EthmacQueueTx(uint32_t, ethmac_netbuf_t*)', and be visible to "
-                  "ddk::EthmacProtocol<D> (either because they are public, or because of "
-                  "friendship).");
-    static_assert(internal::has_ethmac_set_param<D>::value,
-                  "EthmacProtocol subclasses must implement EthmacSetParam");
-    static_assert(fbl::is_same<decltype(&D::EthmacSetParam),
-                                zx_status_t (D::*)(uint32_t, int32_t, void*)>::value,
-                  "EthmacSetParam must be a non-static member function with signature "
-                  "'zx_status_t EthmacSetParam(uint32_t, int32_t, void*)', and be visible to "
-                  "ddk::EthmacProtocol<D> (either because they are public, or because of "
-                  "friendship).");
-    static_assert(internal::has_ethmac_get_bti<D>::value,
-                  "EthmacProtocol subclasses must implement EthmacGetBti");
-    static_assert(fbl::is_same<decltype(&D::EthmacGetBti),
-                                zx_handle_t (D::*)()>::value,
-                  "EthmacGetBti must be a non-static member function with signature "
-                  "'zx_handle_t EthmacGetBti()', and be visible to ddk::EthmacProtocol<D> "
-                  "(either because they are public, or because of friendship).");
+    static_assert(internal::has_ethmac_protocol_query<D>::value,
+                  "EthmacProtocol subclasses must implement "
+                  "zx_status_t EthmacQuery(uint32_t options, ethmac_info_t* out_info");
+    static_assert(internal::has_ethmac_protocol_stop<D>::value,
+                  "EthmacProtocol subclasses must implement "
+                  "void EthmacStop(");
+    static_assert(internal::has_ethmac_protocol_start<D>::value,
+                  "EthmacProtocol subclasses must implement "
+                  "zx_status_t EthmacStart(const ethmac_ifc_t* ifc");
+    static_assert(internal::has_ethmac_protocol_queue_tx<D>::value,
+                  "EthmacProtocol subclasses must implement "
+                  "zx_status_t EthmacQueueTx(uint32_t options, ethmac_netbuf_t* netbuf");
+    static_assert(internal::has_ethmac_protocol_set_param<D>::value,
+                  "EthmacProtocol subclasses must implement "
+                  "zx_status_t EthmacSetParam(uint32_t param, zx_status_t value, const void* "
+                  "data_buffer, size_t data_size");
+    static_assert(internal::has_ethmac_protocol_get_bti<D>::value,
+                  "EthmacProtocol subclasses must implement "
+                  "zx_handle_t EthmacGetBti(");
 }
 
-}  // namespace internal
-}  // namespace ddk
+} // namespace internal
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/ethernet.h b/system/ulib/ddktl/include/ddktl/protocol/ethernet.h
index e1dc9a7..f464584 100644
--- a/system/ulib/ddktl/include/ddktl/protocol/ethernet.h
+++ b/system/ulib/ddktl/include/ddktl/protocol/ethernet.h
@@ -1,250 +1,246 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
-#include <ddk/driver.h>
 #include <ddk/protocol/ethernet.h>
-#include <ddktl/protocol/ethernet-internal.h>
-#include <fbl/type_support.h>
-#include <fbl/unique_ptr.h>
+#include <ddktl/device-internal.h>
 #include <zircon/assert.h>
+#include <zircon/compiler.h>
+#include <zircon/listnode.h>
+#include <zircon/types.h>
 
-// DDK ethernet protocol support
+#include "ethernet-internal.h"
+
+// DDK ethmac-protocol support
 //
 // :: Proxies ::
 //
-// ddk::EthmacIfcProxy and ddk::EthmacProtocolProxy are simple wrappers around ethmac_ifc_t and
-// ethmac_protocol_t, respectively. They do not own the pointers passed to them.
+// ddk::EthmacProtocolProxy is a simple wrapper around
+// ethmac_protocol_t. It does not own the pointers passed to it
 //
 // :: Mixins ::
 //
-// ddk::EthmacIfc and ddk::EthmacProtocol are mixin classes that simplify writing DDK drivers that
-// interact with the ethernet protocol. They take care of implementing the function pointer tables
-// and calling into the object that wraps them.
+// ddk::EthmacProtocol is a mixin class that simplifies writing DDK drivers
+// that implement the ethmac protocol. It doesn't set the base protocol.
 //
 // :: Examples ::
 //
-// // A driver that communicates with a ZX_PROTOCOL_ETHERNET_IMPL device as a ethmac_ifc_t
-// class EthDevice;
-// using EthDeviceType = ddk::Device<EthDevice, /* ddk mixins */>;
-//
-// class EthDevice : public EthDeviceType,
-//                   public ddk::EthmacIfc<EthDevice> {
-//   public:
-//     EthDevice(zx_device_t* parent)
-//       : EthDeviceType("my-eth-device"),
-//         parent_(parent) {}
-//
-//     zx_status_t Bind() {
-//         ethmac_protocol_t* ops;
-//         auto status = get_device_protocol(parent_, ZX_PROTOCOL_ETHERNET_IMPL,
-//                                           reinterpret_cast<void**>(&ops));
-//         if (status != ZX_OK) {
-//             return status;
-//         }
-//        proxy_.reset(new ddk::EthmacProtocolProxy(ops, parent_));
-//        status = proxy_->Start(this);
-//        if (status != ZX_OK) {
-//            return status;
-//        }
-//        return device_add(ddk_device(), parent_);
-//     }
-//
-//     void DdkRelease() {
-//         // Clean up
-//     }
-//
-//     void EthmacStatus(uint32_t status) {
-//         // Report status
-//     }
-//
-//     void EthmacRecv(void* buf, size_t length, uint32_t flags) {
-//         // Receive data buffer from ethmac device
-//     }
-//
-//   private:
-//     zx_device_t* parent_;
-//     fbl::unique_ptr<ddk::EthmacProtocolProxy> proxy_;
-// };
-//
-//
-// // A driver that implements a ZX_PROTOCOL_ETHERNET_IMPL device
-// class EthmacDevice;
+// // A driver that implements a ZX_PROTOCOL_ETHMAC device.
+// class EthmacDevice {
 // using EthmacDeviceType = ddk::Device<EthmacDevice, /* ddk mixins */>;
 //
 // class EthmacDevice : public EthmacDeviceType,
 //                      public ddk::EthmacProtocol<EthmacDevice> {
 //   public:
 //     EthmacDevice(zx_device_t* parent)
-//       : EthmacDeviceType("my-ethmac-device"),
-//         parent_(parent) {}
+//         : EthmacDeviceType("my-ethmac-protocol-device", parent) {}
 //
-//     zx_status_t Bind() {
-//         return device_add(ddk_device(), parent_);
-//     }
+//     zx_status_t EthmacQuery(uint32_t options, ethmac_info_t* out_info);
 //
-//     void DdkRelease() {
-//         // Clean up
-//     }
+//     void EthmacStop();
 //
-//     zx_status_t EthmacQuery(uint32_t options, ethmac_info_t* info) {
-//         // Fill out the ethmac info
-//         return ZX_OK;
-//     }
+//     zx_status_t EthmacStart(const ethmac_ifc_t* ifc);
 //
-//     void EthmacStop() {
-//         // Device should stop
-//     }
+//     zx_status_t EthmacQueueTx(uint32_t options, ethmac_netbuf_t* netbuf);
 //
-//     zx_status_t EthmacStart(fbl::unique_ptr<ddk::EthmacIfcProxy> proxy) {
-//         // Start ethmac operation
-//         proxy_.swap(proxy);
-//         return ZX_OK;
-//     }
+//     zx_status_t EthmacSetParam(uint32_t param, zx_status_t value, const void* data_buffer, size_t
+//     data_size);
 //
-//     zx_status_t EthmacQueueTx(uint32_t options, ethmac_netbuf_t* netbuf) {
-//         // Send the data
-//         return ZX_OK;
-//     }
+//     zx_handle_t EthmacGetBti();
 //
-//     zx_status_t EthmacSetParam(uint32_t param, int32_t value, void* data) {
-//         // Set the parameter
-//         return ZX_OK;
-//     }
-//
-//   private:
-//     zx_device_t* parent_;
-//     fbl::unique_ptr<ddk::EthmacIfcProxy> proxy_;
+//     ...
 // };
 
 namespace ddk {
 
 template <typename D>
-class EthmacIfc {
+class EthmacIfc : public internal::base_mixin {
 public:
     EthmacIfc() {
-        internal::CheckEthmacIfc<D>();
-        ifc_.status = Status;
-        ifc_.recv = Recv;
-        ifc_.complete_tx = CompleteTx;
+        internal::CheckEthmacIfcSubclass<D>();
+        ethmac_ifc_ops_.status = EthmacIfcStatus;
+        ethmac_ifc_ops_.recv = EthmacIfcRecv;
+        ethmac_ifc_ops_.complete_tx = EthmacIfcCompleteTx;
     }
 
-    ethmac_ifc_t* ethmac_ifc() { return &ifc_; }
+protected:
+    ethmac_ifc_ops_t ethmac_ifc_ops_ = {};
 
 private:
-    static void Status(void* cookie, uint32_t status) {
-        static_cast<D*>(cookie)->EthmacStatus(status);
+    static void EthmacIfcStatus(void* ctx, uint32_t status) {
+        static_cast<D*>(ctx)->EthmacIfcStatus(status);
     }
-
-    static void Recv(void* cookie, void* data, size_t length, uint32_t flags) {
-        static_cast<D*>(cookie)->EthmacRecv(data, length, flags);
+    static void EthmacIfcRecv(void* ctx, const void* data_buffer, size_t data_size,
+                              uint32_t flags) {
+        static_cast<D*>(ctx)->EthmacIfcRecv(data_buffer, data_size, flags);
     }
-
-    static void CompleteTx(void* cookie, ethmac_netbuf_t* netbuf, zx_status_t status) {
-        static_cast<D*>(cookie)->EthmacCompleteTx(netbuf, status);
+    // complete_tx() is called to return ownership of a netbuf to the generic ethernet driver.
+    // Return status indicates queue state:
+    //   ZX_OK: Packet has been enqueued.
+    //   Other: Packet could not be enqueued.
+    // Upon a return of ZX_OK, the packet has been enqueued, but no information is returned as to
+    // the completion state of the transmission itself.
+    static void EthmacIfcCompleteTx(void* ctx, ethmac_netbuf_t* netbuf, zx_status_t status) {
+        static_cast<D*>(ctx)->EthmacIfcCompleteTx(netbuf, status);
     }
-
-    ethmac_ifc_t ifc_ = {};
 };
 
 class EthmacIfcProxy {
 public:
-    EthmacIfcProxy(ethmac_ifc_t* ifc, void* cookie)
-        : ifc_(ifc), cookie_(cookie) {}
+    EthmacIfcProxy() : ops_(nullptr), ctx_(nullptr) {}
+    EthmacIfcProxy(const ethmac_ifc_t* proto) : ops_(proto->ops), ctx_(proto->ctx) {}
 
-    void Status(uint32_t status) {
-        ifc_->status(cookie_, status);
+    void GetProto(ethmac_ifc_t* proto) {
+        proto->ctx = ctx_;
+        proto->ops = ops_;
     }
-
-    void Recv(void* data, size_t length, uint32_t flags) {
-        ifc_->recv(cookie_, data, length, flags);
+    bool is_valid() { return ops_ != nullptr; }
+    void clear() {
+        ctx_ = nullptr;
+        ops_ = nullptr;
     }
-
+    void Status(uint32_t status) { ops_->status(ctx_, status); }
+    void Recv(const void* data_buffer, size_t data_size, uint32_t flags) {
+        ops_->recv(ctx_, data_buffer, data_size, flags);
+    }
+    // complete_tx() is called to return ownership of a netbuf to the generic ethernet driver.
+    // Return status indicates queue state:
+    //   ZX_OK: Packet has been enqueued.
+    //   Other: Packet could not be enqueued.
+    // Upon a return of ZX_OK, the packet has been enqueued, but no information is returned as to
+    // the completion state of the transmission itself.
     void CompleteTx(ethmac_netbuf_t* netbuf, zx_status_t status) {
-        ifc_->complete_tx(cookie_, netbuf, status);
+        ops_->complete_tx(ctx_, netbuf, status);
     }
 
 private:
-    ethmac_ifc_t* ifc_;
-    void* cookie_;
+    ethmac_ifc_ops_t* ops_;
+    void* ctx_;
 };
 
+// The ethernet midlayer will never call ethermac_protocol
+// methods from multiple threads simultaneously, but it
+// can call send() methods at the same time as non-send
+// methods.
 template <typename D>
-class EthmacProtocol : public internal::base_protocol {
+class EthmacProtocol : public internal::base_mixin {
 public:
     EthmacProtocol() {
         internal::CheckEthmacProtocolSubclass<D>();
-        ops_.query = Query;
-        ops_.stop = Stop;
-        ops_.start = Start;
-        ops_.queue_tx = QueueTx;
-        ops_.set_param = SetParam;
-        ops_.get_bti = GetBti;
-
-        // Can only inherit from one base_protocol implemenation
-        ZX_ASSERT(ddk_proto_id_ == 0);
-        ddk_proto_id_ = ZX_PROTOCOL_ETHERNET_IMPL;
-        ddk_proto_ops_ = &ops_;
+        ethmac_protocol_ops_.query = EthmacQuery;
+        ethmac_protocol_ops_.stop = EthmacStop;
+        ethmac_protocol_ops_.start = EthmacStart;
+        ethmac_protocol_ops_.queue_tx = EthmacQueueTx;
+        ethmac_protocol_ops_.set_param = EthmacSetParam;
+        ethmac_protocol_ops_.get_bti = EthmacGetBti;
     }
 
+protected:
+    ethmac_protocol_ops_t ethmac_protocol_ops_ = {};
+
 private:
-    static zx_status_t Query(void* ctx, uint32_t options, ethmac_info_t* info) {
-        return static_cast<D*>(ctx)->EthmacQuery(options, info);
+    // Obtain information about the ethermac device and supported features
+    // Safe to call at any time.
+    static zx_status_t EthmacQuery(void* ctx, uint32_t options, ethmac_info_t* out_info) {
+        return static_cast<D*>(ctx)->EthmacQuery(options, out_info);
     }
-
-    static void Stop(void* ctx) {
-        static_cast<D*>(ctx)->EthmacStop();
+    // Shut down a running ethermac
+    // Safe to call if the ethermac is already stopped.
+    static void EthmacStop(void* ctx) { static_cast<D*>(ctx)->EthmacStop(); }
+    // Start ethermac running with ifc_virt
+    // Callbacks on ifc may be invoked from now until stop() is called
+    static zx_status_t EthmacStart(void* ctx, const ethmac_ifc_t* ifc) {
+        return static_cast<D*>(ctx)->EthmacStart(ifc);
     }
-
-    static zx_status_t Start(void* ctx, ethmac_ifc_t* ifc, void* cookie) {
-        auto ifc_proxy = fbl::unique_ptr<EthmacIfcProxy>(new EthmacIfcProxy(ifc, cookie));
-        return static_cast<D*>(ctx)->EthmacStart(fbl::move(ifc_proxy));
-    }
-
-    static zx_status_t QueueTx(void* ctx, uint32_t options, ethmac_netbuf_t* netbuf) {
+    // Request transmission of the packet in netbuf. Return status indicates queue state:
+    //   ZX_ERR_SHOULD_WAIT: Packet is being enqueued.
+    //   ZX_OK: Packet has been enqueued.
+    //   Other: Packet could not be enqueued.
+    // In the SHOULD_WAIT case the driver takes ownership of the netbuf and must call complete_tx()
+    // to return it once the enqueue is complete. complete_tx() may be used to return the packet
+    // before transmission itself completes, but MUST NOT be called from within the queue_tx()
+    // implementation.
+    // queue_tx() may be called at any time after start() is called including from multiple threads
+    // simultaneously.
+    static zx_status_t EthmacQueueTx(void* ctx, uint32_t options, ethmac_netbuf_t* netbuf) {
         return static_cast<D*>(ctx)->EthmacQueueTx(options, netbuf);
     }
-
-    static zx_status_t SetParam(void* ctx, uint32_t param, int32_t value, void* data) {
-        return static_cast<D*>(ctx)->EthmacSetParam(param, value, data);
+    // Request a settings change for the driver. Return status indicates disposition:
+    //   ZX_OK: Request has been handled.
+    //   ZX_ERR_NOT_SUPPORTED: Driver does not support this setting.
+    //   Other: Error trying to support this request.
+    // |value| and |data| usage are defined for each |param|; see comments above.
+    // set_param() may be called at any time after start() is called including from multiple threads
+    // simultaneously.
+    static zx_status_t EthmacSetParam(void* ctx, uint32_t param, zx_status_t value,
+                                      const void* data_buffer, size_t data_size) {
+        return static_cast<D*>(ctx)->EthmacSetParam(param, value, data_buffer, data_size);
     }
-
-    static zx_handle_t GetBti(void* ctx) {
-        return static_cast<D*>(ctx)->EthmacGetBti();
-    }
-
-    ethmac_protocol_ops_t ops_ = {};
+    // Get the BTI handle (needed to pin DMA memory) for this device.
+    // This method is only valid on devices that advertise ETHMAC_FEATURE_DMA
+    // The caller does *not* take ownership of the BTI handle and must never close
+    // the handle.
+    static zx_handle_t EthmacGetBti(void* ctx) { return static_cast<D*>(ctx)->EthmacGetBti(); }
 };
 
 class EthmacProtocolProxy {
 public:
-    EthmacProtocolProxy(ethmac_protocol_t* proto)
-        : ops_(proto->ops), ctx_(proto->ctx) {}
+    EthmacProtocolProxy() : ops_(nullptr), ctx_(nullptr) {}
+    EthmacProtocolProxy(const ethmac_protocol_t* proto) : ops_(proto->ops), ctx_(proto->ctx) {}
 
-    zx_status_t Query(uint32_t options, ethmac_info_t* info) {
-        return ops_->query(ctx_, options, info);
+    void GetProto(ethmac_protocol_t* proto) {
+        proto->ctx = ctx_;
+        proto->ops = ops_;
     }
-
-    template <typename D>
-    zx_status_t Start(D* ifc) {
-        static_assert(fbl::is_base_of<EthmacIfc<D>, D>::value,
-                      "Start must be called with a subclass of EthmacIfc");
-        return ops_->start(ctx_, ifc->ethmac_ifc(), ifc);
+    bool is_valid() { return ops_ != nullptr; }
+    void clear() {
+        ctx_ = nullptr;
+        ops_ = nullptr;
     }
-
-    void Stop() {
-        ops_->stop(ctx_);
+    // Obtain information about the ethermac device and supported features
+    // Safe to call at any time.
+    zx_status_t Query(uint32_t options, ethmac_info_t* out_info) {
+        return ops_->query(ctx_, options, out_info);
     }
-
+    // Shut down a running ethermac
+    // Safe to call if the ethermac is already stopped.
+    void Stop() { ops_->stop(ctx_); }
+    // Start ethermac running with ifc_virt
+    // Callbacks on ifc may be invoked from now until stop() is called
+    zx_status_t Start(const ethmac_ifc_t* ifc) { return ops_->start(ctx_, ifc); }
+    // Request transmission of the packet in netbuf. Return status indicates queue state:
+    //   ZX_ERR_SHOULD_WAIT: Packet is being enqueued.
+    //   ZX_OK: Packet has been enqueued.
+    //   Other: Packet could not be enqueued.
+    // In the SHOULD_WAIT case the driver takes ownership of the netbuf and must call complete_tx()
+    // to return it once the enqueue is complete. complete_tx() may be used to return the packet
+    // before transmission itself completes, but MUST NOT be called from within the queue_tx()
+    // implementation.
+    // queue_tx() may be called at any time after start() is called including from multiple threads
+    // simultaneously.
     zx_status_t QueueTx(uint32_t options, ethmac_netbuf_t* netbuf) {
         return ops_->queue_tx(ctx_, options, netbuf);
     }
-
-    zx_status_t SetParam(uint32_t param, int32_t value, void* data) {
-        return ops_->set_param(ctx_, param, value, data);
+    // Request a settings change for the driver. Return status indicates disposition:
+    //   ZX_OK: Request has been handled.
+    //   ZX_ERR_NOT_SUPPORTED: Driver does not support this setting.
+    //   Other: Error trying to support this request.
+    // |value| and |data| usage are defined for each |param|; see comments above.
+    // set_param() may be called at any time after start() is called including from multiple threads
+    // simultaneously.
+    zx_status_t SetParam(uint32_t param, zx_status_t value, const void* data_buffer,
+                         size_t data_size) {
+        return ops_->set_param(ctx_, param, value, data_buffer, data_size);
     }
+    // Get the BTI handle (needed to pin DMA memory) for this device.
+    // This method is only valid on devices that advertise ETHMAC_FEATURE_DMA
+    // The caller does *not* take ownership of the BTI handle and must never close
+    // the handle.
+    zx_handle_t GetBti() { return ops_->get_bti(ctx_); }
 
 private:
     ethmac_protocol_ops_t* ops_;
diff --git a/system/ulib/ddktl/include/ddktl/protocol/gpio-internal.h b/system/ulib/ddktl/include/ddktl/protocol/gpio-internal.h
index a4c0d43..293e333 100644
--- a/system/ulib/ddktl/include/ddktl/protocol/gpio-internal.h
+++ b/system/ulib/ddktl/include/ddktl/protocol/gpio-internal.h
@@ -2,57 +2,62 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
+#include <ddk/protocol/gpio.h>
 #include <fbl/type_support.h>
 
 namespace ddk {
 namespace internal {
 
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_gpio_config_in, GpioConfigIn,
-        zx_status_t (C::*)(uint32_t, uint32_t));
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_gpio_config_out, GpioConfigOut,
-        zx_status_t (C::*)(uint32_t, uint8_t));
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_gpio_set_alt_function, GpioSetAltFunction,
-        zx_status_t (C::*)(uint32_t, uint64_t));
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_gpio_read, GpioRead,
-        zx_status_t (C::*)(uint32_t, uint8_t*));
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_gpio_write, GpioWrite,
-        zx_status_t (C::*)(uint32_t, uint8_t));
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_gpio_get_interrupt, GpioGetInterrupt,
-        zx_status_t (C::*)(uint32_t, uint32_t, zx_handle_t*));
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_gpio_release_interrupt, GpioReleaseInterrupt,
-        zx_status_t (C::*)(uint32_t));
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_gpio_set_polarity, GpioSetPolarity,
-        zx_status_t (C::*)(uint32_t, uint32_t));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_gpio_protocol_config_in, GpioConfigIn,
+                                     zx_status_t (C::*)(uint32_t index, uint32_t flags));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_gpio_protocol_config_out, GpioConfigOut,
+                                     zx_status_t (C::*)(uint32_t index, uint8_t initial_value));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_gpio_protocol_set_alt_function, GpioSetAltFunction,
+                                     zx_status_t (C::*)(uint32_t index, uint64_t function));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_gpio_protocol_read, GpioRead,
+                                     zx_status_t (C::*)(uint32_t index, uint8_t* out_value));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_gpio_protocol_write, GpioWrite,
+                                     zx_status_t (C::*)(uint32_t index, uint8_t value));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_gpio_protocol_get_interrupt, GpioGetInterrupt,
+                                     zx_status_t (C::*)(uint32_t index, uint32_t flags,
+                                                        zx_handle_t* out_irq));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_gpio_protocol_release_interrupt, GpioReleaseInterrupt,
+                                     zx_status_t (C::*)(uint32_t index));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_gpio_protocol_set_polarity, GpioSetPolarity,
+                                     zx_status_t (C::*)(uint32_t index, gpio_polarity_t polarity));
 
 template <typename D>
 constexpr void CheckGpioProtocolSubclass() {
-    static_assert(internal::has_gpio_config_in<D>::value,
+    static_assert(internal::has_gpio_protocol_config_in<D>::value,
                   "GpioProtocol subclasses must implement "
-                  "GpioConfigIn(uint32_t index, uint32_t flags)");
-    static_assert(internal::has_gpio_config_out<D>::value,
+                  "zx_status_t GpioConfigIn(uint32_t index, uint32_t flags");
+    static_assert(internal::has_gpio_protocol_config_out<D>::value,
                   "GpioProtocol subclasses must implement "
-                  "GpioConfigOut(uint32_t index, uint8_t initial_value)");
-    static_assert(internal::has_gpio_set_alt_function<D>::value,
+                  "zx_status_t GpioConfigOut(uint32_t index, uint8_t initial_value");
+    static_assert(internal::has_gpio_protocol_set_alt_function<D>::value,
                   "GpioProtocol subclasses must implement "
-                  "GpioSetAltFunction(uint32_t index, uint64_t function)");
-    static_assert(internal::has_gpio_read<D>::value,
+                  "zx_status_t GpioSetAltFunction(uint32_t index, uint64_t function");
+    static_assert(internal::has_gpio_protocol_read<D>::value,
                   "GpioProtocol subclasses must implement "
-                  "GpioRead(uint32_t index, uint8_t* out_value)");
-    static_assert(internal::has_gpio_write<D>::value,
+                  "zx_status_t GpioRead(uint32_t index, uint8_t* out_value");
+    static_assert(internal::has_gpio_protocol_write<D>::value,
                   "GpioProtocol subclasses must implement "
-                  "GpioWrite(uint32_t index, uint8_t value)");
-    static_assert(internal::has_gpio_get_interrupt<D>::value,
+                  "zx_status_t GpioWrite(uint32_t index, uint8_t value");
+    static_assert(
+        internal::has_gpio_protocol_get_interrupt<D>::value,
+        "GpioProtocol subclasses must implement "
+        "zx_status_t GpioGetInterrupt(uint32_t index, uint32_t flags, zx_handle_t* out_irq");
+    static_assert(internal::has_gpio_protocol_release_interrupt<D>::value,
                   "GpioProtocol subclasses must implement "
-                  "GpioGetInterrupt(uint32_t index, uint32_t flags, zx_handle_t* out_handle)");
-    static_assert(internal::has_gpio_release_interrupt<D>::value,
+                  "zx_status_t GpioReleaseInterrupt(uint32_t index");
+    static_assert(internal::has_gpio_protocol_set_polarity<D>::value,
                   "GpioProtocol subclasses must implement "
-                  "GpioReleaseInterrupt(uint32_t index)");
-    static_assert(internal::has_gpio_set_polarity<D>::value,
-                  "GpioProtocol subclasses must implement "
-                  "GpioSetPolarity(uint32_t index, uint32_t polarity)");
- }
+                  "zx_status_t GpioSetPolarity(uint32_t index, gpio_polarity_t polarity");
+}
 
-}  // namespace internal
-}  // namespace ddk
+} // namespace internal
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/gpio.h b/system/ulib/ddktl/include/ddktl/protocol/gpio.h
index 6c5ae88..853228a 100644
--- a/system/ulib/ddktl/include/ddktl/protocol/gpio.h
+++ b/system/ulib/ddktl/include/ddktl/protocol/gpio.h
@@ -2,135 +2,163 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
-#include <ddk/driver.h>
 #include <ddk/protocol/gpio.h>
 #include <ddktl/device-internal.h>
 #include <zircon/assert.h>
+#include <zircon/compiler.h>
+#include <zircon/types.h>
 
 #include "gpio-internal.h"
 
-// DDK GPIO protocol support.
+// DDK gpio-protocol support
 //
 // :: Proxies ::
 //
-// ddk::GpioProtocolProxy is a simple wrappers around gpio_protocol_t. It does
-// not own the pointers passed to it.
+// ddk::GpioProtocolProxy is a simple wrapper around
+// gpio_protocol_t. It does not own the pointers passed to it
 //
 // :: Mixins ::
 //
-// ddk::GpioProtocol is a mixin class that simplifies writing DDK drivers that
-// implement the GPIO protocol.
+// ddk::GpioProtocol is a mixin class that simplifies writing DDK drivers
+// that implement the gpio protocol. It doesn't set the base protocol.
 //
 // :: Examples ::
 //
 // // A driver that implements a ZX_PROTOCOL_GPIO device.
-// class GpioDevice;
+// class GpioDevice {
 // using GpioDeviceType = ddk::Device<GpioDevice, /* ddk mixins */>;
 //
 // class GpioDevice : public GpioDeviceType,
 //                    public ddk::GpioProtocol<GpioDevice> {
 //   public:
 //     GpioDevice(zx_device_t* parent)
-//       : GpioDeviceType("my-gpio-device", parent) {}
+//         : GpioDeviceType("my-gpio-protocol-device", parent) {}
 //
 //     zx_status_t GpioConfigIn(uint32_t index, uint32_t flags);
+//
 //     zx_status_t GpioConfigOut(uint32_t index, uint8_t initial_value);
+//
 //     zx_status_t GpioSetAltFunction(uint32_t index, uint64_t function);
+//
 //     zx_status_t GpioRead(uint32_t index, uint8_t* out_value);
+//
 //     zx_status_t GpioWrite(uint32_t index, uint8_t value);
-//     zx_status_t GpioGetInterrupt(uint32_t index, uint32_t flags, zx_handle_t *out_handle);
+//
+//     zx_status_t GpioGetInterrupt(uint32_t index, uint32_t flags, zx_handle_t* out_irq);
+//
 //     zx_status_t GpioReleaseInterrupt(uint32_t index);
-//     zx_status_t GpioSetPolarity(uint32_t index, uint32_t polarity);
+//
+//     zx_status_t GpioSetPolarity(uint32_t index, gpio_polarity_t polarity);
+//
 //     ...
 // };
 
 namespace ddk {
 
+// In the functions below, the GPIO index is relative to the list of GPIOs for the device.
+// For example, the list of GPIOs a platform device has access to would likely be a small
+// subset of the total number of GPIOs, while a platform bus implementation driver would
+// have access to the complete set of GPIOs.
 template <typename D>
-class GpioProtocol : public internal::base_protocol {
+class GpioProtocol : public internal::base_mixin {
 public:
     GpioProtocol() {
         internal::CheckGpioProtocolSubclass<D>();
-        ops_.config_in = GpioConfigIn;
-        ops_.config_out = GpioConfigOut;
-        ops_.set_alt_function = GpioSetAltFunction;
-        ops_.read = GpioRead;
-        ops_.write = GpioWrite;
-        ops_.get_interrupt = GpioGetInterrupt;
-        ops_.release_interrupt = GpioReleaseInterrupt;
-        ops_.set_polarity = GpioSetPolarity;
-
-        // Can only inherit from one base_protocol implemenation
-        ZX_ASSERT(ddk_proto_id_ == 0);
-        ddk_proto_id_ = ZX_PROTOCOL_GPIO;
-        ddk_proto_ops_ = &ops_;
+        gpio_protocol_ops_.config_in = GpioConfigIn;
+        gpio_protocol_ops_.config_out = GpioConfigOut;
+        gpio_protocol_ops_.set_alt_function = GpioSetAltFunction;
+        gpio_protocol_ops_.read = GpioRead;
+        gpio_protocol_ops_.write = GpioWrite;
+        gpio_protocol_ops_.get_interrupt = GpioGetInterrupt;
+        gpio_protocol_ops_.release_interrupt = GpioReleaseInterrupt;
+        gpio_protocol_ops_.set_polarity = GpioSetPolarity;
     }
 
 protected:
-    gpio_protocol_ops_t ops_ = {};
+    gpio_protocol_ops_t gpio_protocol_ops_ = {};
 
 private:
+    // Configures a GPIO for input.
     static zx_status_t GpioConfigIn(void* ctx, uint32_t index, uint32_t flags) {
         return static_cast<D*>(ctx)->GpioConfigIn(index, flags);
     }
+    // Configures a GPIO for output.
     static zx_status_t GpioConfigOut(void* ctx, uint32_t index, uint8_t initial_value) {
         return static_cast<D*>(ctx)->GpioConfigOut(index, initial_value);
     }
+    // Configures the GPIO pin for an alternate function (I2C, SPI, etc)
+    // the interpretation of "function" is platform dependent.
     static zx_status_t GpioSetAltFunction(void* ctx, uint32_t index, uint64_t function) {
         return static_cast<D*>(ctx)->GpioSetAltFunction(index, function);
     }
+    // Reads the current value of a GPIO (0 or 1).
     static zx_status_t GpioRead(void* ctx, uint32_t index, uint8_t* out_value) {
         return static_cast<D*>(ctx)->GpioRead(index, out_value);
     }
+    // Sets the current value of the GPIO (any non-zero value maps to 1).
     static zx_status_t GpioWrite(void* ctx, uint32_t index, uint8_t value) {
         return static_cast<D*>(ctx)->GpioWrite(index, value);
     }
+    // Gets an interrupt object pertaining to a particular GPIO pin.
     static zx_status_t GpioGetInterrupt(void* ctx, uint32_t index, uint32_t flags,
-                                        zx_handle_t* out_handle) {
-        return static_cast<D*>(ctx)->GpioGetInterrupt(index, flags, out_handle);
+                                        zx_handle_t* out_irq) {
+        return static_cast<D*>(ctx)->GpioGetInterrupt(index, flags, out_irq);
     }
+    // Release the interrupt.
     static zx_status_t GpioReleaseInterrupt(void* ctx, uint32_t index) {
         return static_cast<D*>(ctx)->GpioReleaseInterrupt(index);
     }
-    static zx_status_t GpioSetPolarity(void* ctx, uint32_t index, uint32_t polarity) {
+    // Set GPIO polarity.
+    static zx_status_t GpioSetPolarity(void* ctx, uint32_t index, gpio_polarity_t polarity) {
         return static_cast<D*>(ctx)->GpioSetPolarity(index, polarity);
     }
 };
 
 class GpioProtocolProxy {
 public:
-    GpioProtocolProxy(gpio_protocol_t* proto)
-        : ops_(proto->ops), ctx_(proto->ctx) {}
+    GpioProtocolProxy() : ops_(nullptr), ctx_(nullptr) {}
+    GpioProtocolProxy(const gpio_protocol_t* proto) : ops_(proto->ops), ctx_(proto->ctx) {}
 
     void GetProto(gpio_protocol_t* proto) {
         proto->ctx = ctx_;
         proto->ops = ops_;
     }
-
+    bool is_valid() { return ops_ != nullptr; }
+    void clear() {
+        ctx_ = nullptr;
+        ops_ = nullptr;
+    }
+    // Configures a GPIO for input.
     zx_status_t ConfigIn(uint32_t index, uint32_t flags) {
         return ops_->config_in(ctx_, index, flags);
     }
+    // Configures a GPIO for output.
     zx_status_t ConfigOut(uint32_t index, uint8_t initial_value) {
         return ops_->config_out(ctx_, index, initial_value);
     }
+    // Configures the GPIO pin for an alternate function (I2C, SPI, etc)
+    // the interpretation of "function" is platform dependent.
     zx_status_t SetAltFunction(uint32_t index, uint64_t function) {
         return ops_->set_alt_function(ctx_, index, function);
     }
+    // Reads the current value of a GPIO (0 or 1).
     zx_status_t Read(uint32_t index, uint8_t* out_value) {
         return ops_->read(ctx_, index, out_value);
     }
-    zx_status_t Write(uint32_t index, uint8_t value) {
-        return ops_->write(ctx_, index, value);
+    // Sets the current value of the GPIO (any non-zero value maps to 1).
+    zx_status_t Write(uint32_t index, uint8_t value) { return ops_->write(ctx_, index, value); }
+    // Gets an interrupt object pertaining to a particular GPIO pin.
+    zx_status_t GetInterrupt(uint32_t index, uint32_t flags, zx_handle_t* out_irq) {
+        return ops_->get_interrupt(ctx_, index, flags, out_irq);
     }
-    zx_status_t GetInterrupt(uint32_t index, uint32_t flags, zx_handle_t* out_handle) {
-        return ops_->get_interrupt(ctx_, index, flags, out_handle);
-    }
-    zx_status_t ReleaseInterrupt(uint32_t index) {
-        return ops_->release_interrupt(ctx_, index);
-    }
-    zx_status_t SetPolarity(uint32_t index, uint32_t polarity) {
+    // Release the interrupt.
+    zx_status_t ReleaseInterrupt(uint32_t index) { return ops_->release_interrupt(ctx_, index); }
+    // Set GPIO polarity.
+    zx_status_t SetPolarity(uint32_t index, gpio_polarity_t polarity) {
         return ops_->set_polarity(ctx_, index, polarity);
     }
 
diff --git a/system/ulib/ddktl/include/ddktl/protocol/hidbus-internal.h b/system/ulib/ddktl/include/ddktl/protocol/hidbus-internal.h
index e995637..71a45c3 100644
--- a/system/ulib/ddktl/include/ddktl/protocol/hidbus-internal.h
+++ b/system/ulib/ddktl/include/ddktl/protocol/hidbus-internal.h
@@ -1,125 +1,87 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
-#include <ddktl/device-internal.h>
-#include <zircon/types.h>
+#include <ddk/protocol/hidbus.h>
 #include <fbl/type_support.h>
-#include <fbl/unique_ptr.h>
-
-#include <stdint.h>
 
 namespace ddk {
-
-class HidBusIfcProxy;
-
 namespace internal {
 
-DECLARE_HAS_MEMBER_FN(has_hidbus_query, HidBusQuery);
-DECLARE_HAS_MEMBER_FN(has_hidbus_start, HidBusStart);
-DECLARE_HAS_MEMBER_FN(has_hidbus_stop, HidBusStop);
-DECLARE_HAS_MEMBER_FN(has_hidbus_get_descriptor, HidBusGetDescriptor);
-DECLARE_HAS_MEMBER_FN(has_hidbus_get_report, HidBusGetReport);
-DECLARE_HAS_MEMBER_FN(has_hidbus_set_report, HidBusSetReport);
-DECLARE_HAS_MEMBER_FN(has_hidbus_get_idle, HidBusGetIdle);
-DECLARE_HAS_MEMBER_FN(has_hidbus_set_idle, HidBusSetIdle);
-DECLARE_HAS_MEMBER_FN(has_hidbus_get_protocol, HidBusGetProtocol);
-DECLARE_HAS_MEMBER_FN(has_hidbus_set_protocol, HidBusSetProtocol);
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_hidbus_ifc_io_queue, HidbusIfcIoQueue,
+                                     void (C::*)(const void* buf_buffer, size_t buf_size));
 
 template <typename D>
-constexpr void CheckHidBusProtocolSubclass() {
-    static_assert(internal::has_hidbus_query<D>::value,
-                  "HidBusProtocol subclasses must implement HidBusQuery");
-    static_assert(fbl::is_same<decltype(&D::HidBusQuery),
-                                zx_status_t (D::*)(uint32_t options, hid_info_t* info)>::value,
-                  "HidBusQuery must be a non-static member function with signature "
-                  "'zx_status_t HidBusQuery(uint32_t options, hid_info_t* info)', and be visible to "
-                  "ddk::HidBusProtocol<D> (either because they are public, or because of "
-                  "friendship).");
-
-    static_assert(internal::has_hidbus_start<D>::value,
-                  "HidBusProtocol subclasses must implement HidBusStart");
-    static_assert(fbl::is_same<decltype(&D::HidBusStart),
-                                zx_status_t (D::*)(HidBusIfcProxy proxy)>::value,
-                  "HidBusStart must be a non-static member function with signature "
-                  "'zx_status_t HidBusStart(HidBusIfcProxy proxy)', and be visible to "
-                  "ddk::HidBusProtocol<D> (either because they are public, or because of "
-                  "friendship).");
-
-    static_assert(internal::has_hidbus_stop<D>::value,
-                  "HidBusProtocol subclasses must implement HidBusStop");
-    static_assert(fbl::is_same<decltype(&D::HidBusStop),
-                                void (D::*)()>::value,
-                  "HidBusStop must be a non-static member function with signature "
-                  "'void HidBusStop()', and be visible to "
-                  "ddk::HidBusProtocol<D> (either because they are public, or because of "
-                  "friendship).");
-
-    static_assert(internal::has_hidbus_get_descriptor<D>::value,
-                  "HidBusProtocol subclasses must implement HidBusGetDescriptor");
-    static_assert(fbl::is_same<decltype(&D::HidBusGetDescriptor),
-                                zx_status_t (D::*)(uint8_t desc_type, void** data, size_t* len)>::value,
-                  "HidBusGetDescriptor must be a non-static member function with signature "
-                  "'zx_status_t HidBusGetDescriptor(uint8_t desc_type, void** data, size_t* len)', and be visible to "
-                  "ddk::HidBusProtocol<D> (either because they are public, or because of "
-                  "friendship).");
-
-    static_assert(internal::has_hidbus_get_report<D>::value,
-                  "HidBusProtocol subclasses must implement HidBusGetReport");
-    static_assert(fbl::is_same<decltype(&D::HidBusGetReport),
-                                zx_status_t (D::*)(uint8_t rpt_type, uint8_t rpt_id, void* data, size_t len, size_t* out_len)>::value,
-                  "HidBusGetReport must be a non-static member function with signature "
-                  "'zx_status_t HidBusGetReport(uint8_t rpt_type, uint8_t rpt_id, void* data, size_t len, size_t* out_len)',"
-                  " and be visible to ddk::HidBusProtocol<D> (either because they are public, or because of "
-                  "friendship).");
-
-    static_assert(internal::has_hidbus_set_report<D>::value,
-                  "HidBusProtocol subclasses must implement HidBusSetReport");
-    static_assert(fbl::is_same<decltype(&D::HidBusSetReport),
-                                zx_status_t (D::*)(uint8_t rpt_type, uint8_t rpt_id, void* data, size_t len)>::value,
-                  "HidBusSetReport must be a non-static member function with signature "
-                  "'zx_status_t HidBusSetReport(uint8_t rpt_type, uint8_t rpt_id, void* data, size_t len)', and be visible to "
-                  "ddk::HidBusProtocol<D> (either because they are public, or because of "
-                  "friendship).");
-
-    static_assert(internal::has_hidbus_get_idle<D>::value,
-                  "HidBusProtocol subclasses must implement HidBusGetIdle");
-    static_assert(fbl::is_same<decltype(&D::HidBusGetIdle),
-                                zx_status_t (D::*)(uint8_t rpt_id, uint8_t* duration)>::value,
-                  "HidBusGetIdle must be a non-static member function with signature "
-                  "'zx_status_t HidBusGetIdle(uint8_t rpt_id, uint8_t* duration)', and be visible to "
-                  "ddk::HidBusProtocol<D> (either because they are public, or because of "
-                  "friendship).");
-
-    static_assert(internal::has_hidbus_set_idle<D>::value,
-                  "HidBusProtocol subclasses must implement HidBusSetIdle");
-    static_assert(fbl::is_same<decltype(&D::HidBusSetIdle),
-                                zx_status_t (D::*)(uint8_t rpt_id, uint8_t duration)>::value,
-                  "HidBusSetIdle must be a non-static member function with signature "
-                  "'zx_status_t HidBusSetIdle(uint8_t rpt_id, uint8_t duration)', and be visible to "
-                  "ddk::HidBusProtocol<D> (either because they are public, or because of "
-                  "friendship).");
-
-    static_assert(internal::has_hidbus_get_protocol<D>::value,
-                  "HidBusProtocol subclasses must implement HidBusGetProtocol");
-    static_assert(fbl::is_same<decltype(&D::HidBusGetProtocol),
-                                zx_status_t (D::*)(uint8_t* protocol)>::value,
-                  "HidBusGetProtocol must be a non-static member function with signature "
-                  "'zx_status_t HidBusGetProtocol(uint8_t* protocol)', and be visible to "
-                  "ddk::HidBusProtocol<D> (either because they are public, or because of "
-                  "friendship).");
-
-    static_assert(internal::has_hidbus_set_protocol<D>::value,
-                  "HidBusProtocol subclasses must implement HidBusSetProtocol");
-    static_assert(fbl::is_same<decltype(&D::HidBusSetProtocol),
-                                zx_status_t (D::*)(uint8_t protocol)>::value,
-                  "HidBusSetProtocol must be a non-static member function with signature "
-                  "'zx_status_t HidBusSetProtocol(uint8_t protocol)', and be visible to "
-                  "ddk::HidBusProtocol<D> (either because they are public, or because of "
-                  "friendship).");
+constexpr void CheckHidbusIfcSubclass() {
+    static_assert(internal::has_hidbus_ifc_io_queue<D>::value,
+                  "HidbusIfc subclasses must implement "
+                  "void HidbusIfcIoQueue(const void* buf_buffer, size_t buf_size");
 }
 
-}  // namespace internal
-}  // namespace ddk
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_hidbus_protocol_query, HidbusQuery,
+                                     zx_status_t (C::*)(uint32_t options, hid_info_t* out_info));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_hidbus_protocol_start, HidbusStart,
+                                     zx_status_t (C::*)(const hidbus_ifc_t* ifc));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_hidbus_protocol_stop, HidbusStop, void (C::*)());
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_hidbus_protocol_get_descriptor, HidbusGetDescriptor,
+                                     zx_status_t (C::*)(hid_description_type_t desc_type,
+                                                        void** out_data_buffer, size_t* data_size));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_hidbus_protocol_get_report, HidbusGetReport,
+                                     zx_status_t (C::*)(hid_report_type_t rpt_type, uint8_t rpt_id,
+                                                        void* out_data_buffer, size_t data_size,
+                                                        size_t* out_data_actual));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_hidbus_protocol_set_report, HidbusSetReport,
+                                     zx_status_t (C::*)(hid_report_type_t rpt_type, uint8_t rpt_id,
+                                                        const void* data_buffer, size_t data_size));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_hidbus_protocol_get_idle, HidbusGetIdle,
+                                     zx_status_t (C::*)(uint8_t rpt_id, uint8_t* out_duration));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_hidbus_protocol_set_idle, HidbusSetIdle,
+                                     zx_status_t (C::*)(uint8_t rpt_id, uint8_t duration));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_hidbus_protocol_get_protocol, HidbusGetProtocol,
+                                     zx_status_t (C::*)(hid_protocol_t* out_protocol));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_hidbus_protocol_set_protocol, HidbusSetProtocol,
+                                     zx_status_t (C::*)(hid_protocol_t protocol));
+
+template <typename D>
+constexpr void CheckHidbusProtocolSubclass() {
+    static_assert(internal::has_hidbus_protocol_query<D>::value,
+                  "HidbusProtocol subclasses must implement "
+                  "zx_status_t HidbusQuery(uint32_t options, hid_info_t* out_info");
+    static_assert(internal::has_hidbus_protocol_start<D>::value,
+                  "HidbusProtocol subclasses must implement "
+                  "zx_status_t HidbusStart(const hidbus_ifc_t* ifc");
+    static_assert(internal::has_hidbus_protocol_stop<D>::value,
+                  "HidbusProtocol subclasses must implement "
+                  "void HidbusStop(");
+    static_assert(internal::has_hidbus_protocol_get_descriptor<D>::value,
+                  "HidbusProtocol subclasses must implement "
+                  "zx_status_t HidbusGetDescriptor(hid_description_type_t desc_type, void** "
+                  "out_data_buffer, size_t* data_size");
+    static_assert(internal::has_hidbus_protocol_get_report<D>::value,
+                  "HidbusProtocol subclasses must implement "
+                  "zx_status_t HidbusGetReport(hid_report_type_t rpt_type, uint8_t rpt_id, void* "
+                  "out_data_buffer, size_t data_size, size_t* out_data_actual");
+    static_assert(internal::has_hidbus_protocol_set_report<D>::value,
+                  "HidbusProtocol subclasses must implement "
+                  "zx_status_t HidbusSetReport(hid_report_type_t rpt_type, uint8_t rpt_id, const "
+                  "void* data_buffer, size_t data_size");
+    static_assert(internal::has_hidbus_protocol_get_idle<D>::value,
+                  "HidbusProtocol subclasses must implement "
+                  "zx_status_t HidbusGetIdle(uint8_t rpt_id, uint8_t* out_duration");
+    static_assert(internal::has_hidbus_protocol_set_idle<D>::value,
+                  "HidbusProtocol subclasses must implement "
+                  "zx_status_t HidbusSetIdle(uint8_t rpt_id, uint8_t duration");
+    static_assert(internal::has_hidbus_protocol_get_protocol<D>::value,
+                  "HidbusProtocol subclasses must implement "
+                  "zx_status_t HidbusGetProtocol(hid_protocol_t* out_protocol");
+    static_assert(internal::has_hidbus_protocol_set_protocol<D>::value,
+                  "HidbusProtocol subclasses must implement "
+                  "zx_status_t HidbusSetProtocol(hid_protocol_t protocol");
+}
+
+} // namespace internal
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/hidbus.h b/system/ulib/ddktl/include/ddktl/protocol/hidbus.h
index a7a5336..2d29ce4 100644
--- a/system/ulib/ddktl/include/ddktl/protocol/hidbus.h
+++ b/system/ulib/ddktl/include/ddktl/protocol/hidbus.h
@@ -1,160 +1,231 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
-#include <ddk/driver.h>
 #include <ddk/protocol/hidbus.h>
-#include <ddktl/protocol/hidbus-internal.h>
-#include <fbl/type_support.h>
-#include <fbl/unique_ptr.h>
+#include <ddktl/device-internal.h>
 #include <zircon/assert.h>
+#include <zircon/compiler.h>
+#include <zircon/types.h>
 
-// DDK hidbus protocol support
+#include "hidbus-internal.h"
+
+// DDK hidbus-protocol support
 //
 // :: Proxies ::
 //
-// ddk::HidBusIfcProxy is simple wrappers around hidbus_ifc_t. It does not own the pointers passed
-// to it.
+// ddk::HidbusProtocolProxy is a simple wrapper around
+// hidbus_protocol_t. It does not own the pointers passed to it
 //
 // :: Mixins ::
 //
-// ddk::HidBusProtocol is a mixin class that simplifies writing DDK drivers that
-// implement the hidbus protocol. They take care of implementing the function pointer tables
-// and calling into the object that wraps them.
+// ddk::HidbusProtocol is a mixin class that simplifies writing DDK drivers
+// that implement the hidbus protocol. It doesn't set the base protocol.
 //
 // :: Examples ::
 //
-// // A driver that implements a ZX_PROTOCOL_HIDBUS device
-// class HidBusDevice;
-// using HidBusDeviceType = ddk::Device<HidBusDevice, /* ddk mixins */>;
+// // A driver that implements a ZX_PROTOCOL_HIDBUS device.
+// class HidbusDevice {
+// using HidbusDeviceType = ddk::Device<HidbusDevice, /* ddk mixins */>;
 //
-// class HidBusDevice : public HidBusDeviceType,
-//                      public ddk::HidBusProtocol<HidBusDevice> {
+// class HidbusDevice : public HidbusDeviceType,
+//                      public ddk::HidbusProtocol<HidbusDevice> {
 //   public:
-//     HidBusDevice(zx_device_t* parent)
-//       : HidBusDeviceType(parent) {}
+//     HidbusDevice(zx_device_t* parent)
+//         : HidbusDeviceType("my-hidbus-protocol-device", parent) {}
 //
-//     zx_status_t Bind() {
-//         DdkAdd();
-//     }
+//     zx_status_t HidbusQuery(uint32_t options, hid_info_t* out_info);
 //
-//     void DdkRelease() {
-//         // Clean up
-//     }
+//     zx_status_t HidbusStart(const hidbus_ifc_t* ifc);
 //
-//     zx_status_t HidBusStart(ddk::HidBusIfcProxy proxy) {
-//         // Start hidbus operation
-//         proxy_ = proxy;
-//         return ZX_OK;
-//     }
+//     void HidbusStop();
 //
-//     zx_status_t HidBusQuery(uint32_t options, hid_info_t* info) {
-//         ...
-//     }
+//     zx_status_t HidbusGetDescriptor(hid_description_type_t desc_type, void** out_data_buffer,
+//     size_t* data_size);
 //
-//     ...
-//   private:
-//     ddk::HidBusIfcProxy proxy_;
+//     zx_status_t HidbusGetReport(hid_report_type_t rpt_type, uint8_t rpt_id, void*
+//     out_data_buffer, size_t data_size, size_t* out_data_actual);
+//
+//     zx_status_t HidbusSetReport(hid_report_type_t rpt_type, uint8_t rpt_id, const void*
+//     data_buffer, size_t data_size);
+//
+//     zx_status_t HidbusGetIdle(uint8_t rpt_id, uint8_t* out_duration);
+//
+//     zx_status_t HidbusSetIdle(uint8_t rpt_id, uint8_t duration);
+//
+//     zx_status_t HidbusGetProtocol(hid_protocol_t* out_protocol);
+//
+//     zx_status_t HidbusSetProtocol(hid_protocol_t protocol);
+//
 //     ...
 // };
 
 namespace ddk {
 
-class HidBusIfcProxy {
+template <typename D>
+class HidbusIfc : public internal::base_mixin {
 public:
-    HidBusIfcProxy()
-        : ifc_(nullptr), cookie_(nullptr) {}
-
-    HidBusIfcProxy(hidbus_ifc_t* ifc, void* cookie)
-        : ifc_(ifc), cookie_(cookie) {}
-
-    void IoQueue(const uint8_t* buf, size_t len) {
-        ifc_->io_queue(cookie_, buf, len);
+    HidbusIfc() {
+        internal::CheckHidbusIfcSubclass<D>();
+        hidbus_ifc_ops_.io_queue = HidbusIfcIoQueue;
     }
 
-    bool is_valid() const {
-        return ifc_ != nullptr;
-    }
+protected:
+    hidbus_ifc_ops_t hidbus_ifc_ops_ = {};
 
+private:
+    // Queues a report received by the hidbus device.
+    static void HidbusIfcIoQueue(void* ctx, const void* buf_buffer, size_t buf_size) {
+        static_cast<D*>(ctx)->HidbusIfcIoQueue(buf_buffer, buf_size);
+    }
+};
+
+class HidbusIfcProxy {
+public:
+    HidbusIfcProxy() : ops_(nullptr), ctx_(nullptr) {}
+    HidbusIfcProxy(const hidbus_ifc_t* proto) : ops_(proto->ops), ctx_(proto->ctx) {}
+
+    void GetProto(hidbus_ifc_t* proto) {
+        proto->ctx = ctx_;
+        proto->ops = ops_;
+    }
+    bool is_valid() { return ops_ != nullptr; }
     void clear() {
-        ifc_ = nullptr;
-        cookie_ = nullptr;
+        ctx_ = nullptr;
+        ops_ = nullptr;
+    }
+    // Queues a report received by the hidbus device.
+    void IoQueue(const void* buf_buffer, size_t buf_size) {
+        ops_->io_queue(ctx_, buf_buffer, buf_size);
     }
 
 private:
-    hidbus_ifc_t* ifc_;
-    void* cookie_;
+    hidbus_ifc_ops_t* ops_;
+    void* ctx_;
 };
 
 template <typename D>
-class HidBusProtocol : public internal::base_protocol {
+class HidbusProtocol : public internal::base_mixin {
 public:
-    HidBusProtocol() {
-        internal::CheckHidBusProtocolSubclass<D>();
-        ops_.query = Query;
-        ops_.start = Start;
-        ops_.stop = Stop;
-        ops_.get_descriptor = GetDescriptor;
-        ops_.get_report = GetReport;
-        ops_.set_report = SetReport;
-        ops_.get_idle = GetIdle;
-        ops_.set_idle = SetIdle;
-        ops_.get_protocol = GetProtocol;
-        ops_.set_protocol = SetProtocol;
-
-        // Can only inherit from one base_protocol implemenation
-        ZX_ASSERT(ddk_proto_id_ == 0);
-        ddk_proto_id_ = ZX_PROTOCOL_HIDBUS;
-        ddk_proto_ops_ = &ops_;
+    HidbusProtocol() {
+        internal::CheckHidbusProtocolSubclass<D>();
+        hidbus_protocol_ops_.query = HidbusQuery;
+        hidbus_protocol_ops_.start = HidbusStart;
+        hidbus_protocol_ops_.stop = HidbusStop;
+        hidbus_protocol_ops_.get_descriptor = HidbusGetDescriptor;
+        hidbus_protocol_ops_.get_report = HidbusGetReport;
+        hidbus_protocol_ops_.set_report = HidbusSetReport;
+        hidbus_protocol_ops_.get_idle = HidbusGetIdle;
+        hidbus_protocol_ops_.set_idle = HidbusSetIdle;
+        hidbus_protocol_ops_.get_protocol = HidbusGetProtocol;
+        hidbus_protocol_ops_.set_protocol = HidbusSetProtocol;
     }
 
+protected:
+    hidbus_protocol_ops_t hidbus_protocol_ops_ = {};
+
 private:
-    static zx_status_t Query(void* ctx, uint32_t options, hid_info_t* info) {
-        return static_cast<D*>(ctx)->HidBusQuery(options, info);
+    // Obtain information about the hidbus device and supported features.
+    // Safe to call at any time.
+    static zx_status_t HidbusQuery(void* ctx, uint32_t options, hid_info_t* out_info) {
+        return static_cast<D*>(ctx)->HidbusQuery(options, out_info);
     }
-
-    static zx_status_t Start(void* ctx, hidbus_ifc_t* ifc, void* cookie) {
-        HidBusIfcProxy proxy(ifc, cookie);
-        return static_cast<D*>(ctx)->HidBusStart(proxy);
+    // Start the hidbus device. The device may begin queueing hid reports via
+    // ifc->io_queue before this function returns. It is an error to start an
+    // already-started hidbus device.
+    static zx_status_t HidbusStart(void* ctx, const hidbus_ifc_t* ifc) {
+        return static_cast<D*>(ctx)->HidbusStart(ifc);
     }
-
-    static void Stop(void* ctx) {
-        static_cast<D*>(ctx)->HidBusStop();
+    // Stop the hidbus device. Safe to call if the hidbus is already stopped.
+    static void HidbusStop(void* ctx) { static_cast<D*>(ctx)->HidbusStop(); }
+    // What are the ownership semantics with regards to the data buffer passed back?
+    // is len an input and output parameter?
+    static zx_status_t HidbusGetDescriptor(void* ctx, hid_description_type_t desc_type,
+                                           void** out_data_buffer, size_t* data_size) {
+        return static_cast<D*>(ctx)->HidbusGetDescriptor(desc_type, out_data_buffer, data_size);
     }
-
-    static zx_status_t GetDescriptor(void* ctx, uint8_t desc_type, void** data, size_t* len) {
-        return static_cast<D*>(ctx)->HidBusGetDescriptor(desc_type, data, len);
+    static zx_status_t HidbusGetReport(void* ctx, hid_report_type_t rpt_type, uint8_t rpt_id,
+                                       void* out_data_buffer, size_t data_size,
+                                       size_t* out_data_actual) {
+        return static_cast<D*>(ctx)->HidbusGetReport(rpt_type, rpt_id, out_data_buffer, data_size,
+                                                     out_data_actual);
     }
-
-    static zx_status_t GetReport(void* ctx, uint8_t rpt_type, uint8_t rpt_id, void* data,
-                                 size_t len, size_t* out_len) {
-        return static_cast<D*>(ctx)->HidBusGetReport(rpt_type, rpt_id, data, len, out_len);
+    static zx_status_t HidbusSetReport(void* ctx, hid_report_type_t rpt_type, uint8_t rpt_id,
+                                       const void* data_buffer, size_t data_size) {
+        return static_cast<D*>(ctx)->HidbusSetReport(rpt_type, rpt_id, data_buffer, data_size);
     }
-
-    static zx_status_t SetReport(void* ctx, uint8_t rpt_type, uint8_t rpt_id, void* data,
-                                 size_t len) {
-        return static_cast<D*>(ctx)->HidBusSetReport(rpt_type, rpt_id, data, len);
+    static zx_status_t HidbusGetIdle(void* ctx, uint8_t rpt_id, uint8_t* out_duration) {
+        return static_cast<D*>(ctx)->HidbusGetIdle(rpt_id, out_duration);
     }
-
-    static zx_status_t GetIdle(void* ctx, uint8_t rpt_id, uint8_t* duration) {
-        return static_cast<D*>(ctx)->HidBusGetIdle(rpt_id, duration);
+    static zx_status_t HidbusSetIdle(void* ctx, uint8_t rpt_id, uint8_t duration) {
+        return static_cast<D*>(ctx)->HidbusSetIdle(rpt_id, duration);
     }
-
-    static zx_status_t SetIdle(void* ctx, uint8_t rpt_id, uint8_t duration) {
-        return static_cast<D*>(ctx)->HidBusSetIdle(rpt_id, duration);
+    static zx_status_t HidbusGetProtocol(void* ctx, hid_protocol_t* out_protocol) {
+        return static_cast<D*>(ctx)->HidbusGetProtocol(out_protocol);
     }
-
-    static zx_status_t GetProtocol(void* ctx, uint8_t* protocol) {
-        return static_cast<D*>(ctx)->HidBusGetProtocol(protocol);
+    static zx_status_t HidbusSetProtocol(void* ctx, hid_protocol_t protocol) {
+        return static_cast<D*>(ctx)->HidbusSetProtocol(protocol);
     }
+};
 
-    static zx_status_t SetProtocol(void* ctx, uint8_t protocol) {
-        return static_cast<D*>(ctx)->HidBusSetProtocol(protocol);
+class HidbusProtocolProxy {
+public:
+    HidbusProtocolProxy() : ops_(nullptr), ctx_(nullptr) {}
+    HidbusProtocolProxy(const hidbus_protocol_t* proto) : ops_(proto->ops), ctx_(proto->ctx) {}
+
+    void GetProto(hidbus_protocol_t* proto) {
+        proto->ctx = ctx_;
+        proto->ops = ops_;
     }
+    bool is_valid() { return ops_ != nullptr; }
+    void clear() {
+        ctx_ = nullptr;
+        ops_ = nullptr;
+    }
+    // Obtain information about the hidbus device and supported features.
+    // Safe to call at any time.
+    zx_status_t Query(uint32_t options, hid_info_t* out_info) {
+        return ops_->query(ctx_, options, out_info);
+    }
+    // Start the hidbus device. The device may begin queueing hid reports via
+    // ifc->io_queue before this function returns. It is an error to start an
+    // already-started hidbus device.
+    zx_status_t Start(const hidbus_ifc_t* ifc) { return ops_->start(ctx_, ifc); }
+    // Stop the hidbus device. Safe to call if the hidbus is already stopped.
+    void Stop() { ops_->stop(ctx_); }
+    // What are the ownership semantics with regards to the data buffer passed back?
+    // is len an input and output parameter?
+    zx_status_t GetDescriptor(hid_description_type_t desc_type, void** out_data_buffer,
+                              size_t* data_size) {
+        return ops_->get_descriptor(ctx_, desc_type, out_data_buffer, data_size);
+    }
+    zx_status_t GetReport(hid_report_type_t rpt_type, uint8_t rpt_id, void* out_data_buffer,
+                          size_t data_size, size_t* out_data_actual) {
+        return ops_->get_report(ctx_, rpt_type, rpt_id, out_data_buffer, data_size,
+                                out_data_actual);
+    }
+    zx_status_t SetReport(hid_report_type_t rpt_type, uint8_t rpt_id, const void* data_buffer,
+                          size_t data_size) {
+        return ops_->set_report(ctx_, rpt_type, rpt_id, data_buffer, data_size);
+    }
+    zx_status_t GetIdle(uint8_t rpt_id, uint8_t* out_duration) {
+        return ops_->get_idle(ctx_, rpt_id, out_duration);
+    }
+    zx_status_t SetIdle(uint8_t rpt_id, uint8_t duration) {
+        return ops_->set_idle(ctx_, rpt_id, duration);
+    }
+    zx_status_t GetProtocol(hid_protocol_t* out_protocol) {
+        return ops_->get_protocol(ctx_, out_protocol);
+    }
+    zx_status_t SetProtocol(hid_protocol_t protocol) { return ops_->set_protocol(ctx_, protocol); }
 
-    hidbus_protocol_ops_t ops_ = {};
+private:
+    hidbus_protocol_ops_t* ops_;
+    void* ctx_;
 };
 
 } // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/intel-gpu-core-internal.h b/system/ulib/ddktl/include/ddktl/protocol/intel-gpu-core-internal.h
new file mode 100644
index 0000000..a3dc5d2
--- /dev/null
+++ b/system/ulib/ddktl/include/ddktl/protocol/intel-gpu-core-internal.h
@@ -0,0 +1,90 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: This file is machine generated by fidlc.
+
+#pragma once
+
+#include <ddk/protocol/intel-gpu-core.h>
+#include <fbl/type_support.h>
+
+namespace ddk {
+namespace internal {
+
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_zx_intel_gpu_core_protocol_read_pci_config16,
+                                     ZxIntelGpuCoreReadPciConfig16,
+                                     zx_status_t (C::*)(uint16_t addr, uint16_t* out_value));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_zx_intel_gpu_core_protocol_map_pci_mmio,
+                                     ZxIntelGpuCoreMapPciMmio,
+                                     zx_status_t (C::*)(uint32_t pci_bar, void** out_buf_buffer,
+                                                        size_t* buf_size));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_zx_intel_gpu_core_protocol_unmap_pci_mmio,
+                                     ZxIntelGpuCoreUnmapPciMmio,
+                                     zx_status_t (C::*)(uint32_t pci_bar));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_zx_intel_gpu_core_protocol_get_pci_bti,
+                                     ZxIntelGpuCoreGetPciBti,
+                                     zx_status_t (C::*)(uint32_t index, zx_handle_t* out_bti));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(
+    has_zx_intel_gpu_core_protocol_register_interrupt_callback,
+    ZxIntelGpuCoreRegisterInterruptCallback,
+    zx_status_t (C::*)(const zx_intel_gpu_core_interrupt_t* callback, uint32_t interrupt_mask));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_zx_intel_gpu_core_protocol_unregister_interrupt_callback,
+                                     ZxIntelGpuCoreUnregisterInterruptCallback,
+                                     zx_status_t (C::*)());
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_zx_intel_gpu_core_protocol_gtt_get_size,
+                                     ZxIntelGpuCoreGttGetSize, uint64_t (C::*)());
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_zx_intel_gpu_core_protocol_gtt_alloc,
+                                     ZxIntelGpuCoreGttAlloc,
+                                     zx_status_t (C::*)(uint64_t page_count, uint64_t* out_addr));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_zx_intel_gpu_core_protocol_gtt_free, ZxIntelGpuCoreGttFree,
+                                     zx_status_t (C::*)(uint64_t addr));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_zx_intel_gpu_core_protocol_gtt_clear,
+                                     ZxIntelGpuCoreGttClear, zx_status_t (C::*)(uint64_t addr));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_zx_intel_gpu_core_protocol_gtt_insert,
+                                     ZxIntelGpuCoreGttInsert,
+                                     zx_status_t (C::*)(uint64_t addr, zx_handle_t buffer,
+                                                        uint64_t page_offset, uint64_t page_count));
+
+template <typename D>
+constexpr void CheckZxIntelGpuCoreProtocolSubclass() {
+    static_assert(internal::has_zx_intel_gpu_core_protocol_read_pci_config16<D>::value,
+                  "ZxIntelGpuCoreProtocol subclasses must implement "
+                  "zx_status_t ZxIntelGpuCoreReadPciConfig16(uint16_t addr, uint16_t* out_value");
+    static_assert(internal::has_zx_intel_gpu_core_protocol_map_pci_mmio<D>::value,
+                  "ZxIntelGpuCoreProtocol subclasses must implement "
+                  "zx_status_t ZxIntelGpuCoreMapPciMmio(uint32_t pci_bar, void** out_buf_buffer, "
+                  "size_t* buf_size");
+    static_assert(internal::has_zx_intel_gpu_core_protocol_unmap_pci_mmio<D>::value,
+                  "ZxIntelGpuCoreProtocol subclasses must implement "
+                  "zx_status_t ZxIntelGpuCoreUnmapPciMmio(uint32_t pci_bar");
+    static_assert(internal::has_zx_intel_gpu_core_protocol_get_pci_bti<D>::value,
+                  "ZxIntelGpuCoreProtocol subclasses must implement "
+                  "zx_status_t ZxIntelGpuCoreGetPciBti(uint32_t index, zx_handle_t* out_bti");
+    static_assert(internal::has_zx_intel_gpu_core_protocol_register_interrupt_callback<D>::value,
+                  "ZxIntelGpuCoreProtocol subclasses must implement "
+                  "zx_status_t ZxIntelGpuCoreRegisterInterruptCallback(const "
+                  "zx_intel_gpu_core_interrupt_t* callback, uint32_t interrupt_mask");
+    static_assert(internal::has_zx_intel_gpu_core_protocol_unregister_interrupt_callback<D>::value,
+                  "ZxIntelGpuCoreProtocol subclasses must implement "
+                  "zx_status_t ZxIntelGpuCoreUnregisterInterruptCallback(");
+    static_assert(internal::has_zx_intel_gpu_core_protocol_gtt_get_size<D>::value,
+                  "ZxIntelGpuCoreProtocol subclasses must implement "
+                  "uint64_t ZxIntelGpuCoreGttGetSize(");
+    static_assert(internal::has_zx_intel_gpu_core_protocol_gtt_alloc<D>::value,
+                  "ZxIntelGpuCoreProtocol subclasses must implement "
+                  "zx_status_t ZxIntelGpuCoreGttAlloc(uint64_t page_count, uint64_t* out_addr");
+    static_assert(internal::has_zx_intel_gpu_core_protocol_gtt_free<D>::value,
+                  "ZxIntelGpuCoreProtocol subclasses must implement "
+                  "zx_status_t ZxIntelGpuCoreGttFree(uint64_t addr");
+    static_assert(internal::has_zx_intel_gpu_core_protocol_gtt_clear<D>::value,
+                  "ZxIntelGpuCoreProtocol subclasses must implement "
+                  "zx_status_t ZxIntelGpuCoreGttClear(uint64_t addr");
+    static_assert(internal::has_zx_intel_gpu_core_protocol_gtt_insert<D>::value,
+                  "ZxIntelGpuCoreProtocol subclasses must implement "
+                  "zx_status_t ZxIntelGpuCoreGttInsert(uint64_t addr, zx_handle_t buffer, uint64_t "
+                  "page_offset, uint64_t page_count");
+}
+
+} // namespace internal
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/intel-gpu-core.h b/system/ulib/ddktl/include/ddktl/protocol/intel-gpu-core.h
new file mode 100644
index 0000000..f3476f5
--- /dev/null
+++ b/system/ulib/ddktl/include/ddktl/protocol/intel-gpu-core.h
@@ -0,0 +1,211 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: This file is machine generated by fidlc.
+
+#pragma once
+
+#include <ddk/protocol/intel-gpu-core.h>
+#include <ddktl/device-internal.h>
+#include <zircon/assert.h>
+#include <zircon/compiler.h>
+#include <zircon/types.h>
+
+#include "intel-gpu-core-internal.h"
+
+// DDK zx-intel-gpu-core-protocol support
+//
+// :: Proxies ::
+//
+// ddk::ZxIntelGpuCoreProtocolProxy is a simple wrapper around
+// zx_intel_gpu_core_protocol_t. It does not own the pointers passed to it
+//
+// :: Mixins ::
+//
+// ddk::ZxIntelGpuCoreProtocol is a mixin class that simplifies writing DDK drivers
+// that implement the zx-intel-gpu-core protocol. It doesn't set the base protocol.
+//
+// :: Examples ::
+//
+// // A driver that implements a ZX_PROTOCOL_ZX_INTEL_GPU_CORE device.
+// class ZxIntelGpuCoreDevice {
+// using ZxIntelGpuCoreDeviceType = ddk::Device<ZxIntelGpuCoreDevice, /* ddk mixins */>;
+//
+// class ZxIntelGpuCoreDevice : public ZxIntelGpuCoreDeviceType,
+//                              public ddk::ZxIntelGpuCoreProtocol<ZxIntelGpuCoreDevice> {
+//   public:
+//     ZxIntelGpuCoreDevice(zx_device_t* parent)
+//         : ZxIntelGpuCoreDeviceType("my-zx-intel-gpu-core-protocol-device", parent) {}
+//
+//     zx_status_t ZxIntelGpuCoreReadPciConfig16(uint16_t addr, uint16_t* out_value);
+//
+//     zx_status_t ZxIntelGpuCoreMapPciMmio(uint32_t pci_bar, void** out_buf_buffer, size_t*
+//     buf_size);
+//
+//     zx_status_t ZxIntelGpuCoreUnmapPciMmio(uint32_t pci_bar);
+//
+//     zx_status_t ZxIntelGpuCoreGetPciBti(uint32_t index, zx_handle_t* out_bti);
+//
+//     zx_status_t ZxIntelGpuCoreRegisterInterruptCallback(const zx_intel_gpu_core_interrupt_t*
+//     callback, uint32_t interrupt_mask);
+//
+//     zx_status_t ZxIntelGpuCoreUnregisterInterruptCallback();
+//
+//     uint64_t ZxIntelGpuCoreGttGetSize();
+//
+//     zx_status_t ZxIntelGpuCoreGttAlloc(uint64_t page_count, uint64_t* out_addr);
+//
+//     zx_status_t ZxIntelGpuCoreGttFree(uint64_t addr);
+//
+//     zx_status_t ZxIntelGpuCoreGttClear(uint64_t addr);
+//
+//     zx_status_t ZxIntelGpuCoreGttInsert(uint64_t addr, zx_handle_t buffer, uint64_t page_offset,
+//     uint64_t page_count);
+//
+//     ...
+// };
+
+namespace ddk {
+
+template <typename D>
+class ZxIntelGpuCoreProtocol : public internal::base_mixin {
+public:
+    ZxIntelGpuCoreProtocol() {
+        internal::CheckZxIntelGpuCoreProtocolSubclass<D>();
+        zx_intel_gpu_core_protocol_ops_.read_pci_config16 = ZxIntelGpuCoreReadPciConfig16;
+        zx_intel_gpu_core_protocol_ops_.map_pci_mmio = ZxIntelGpuCoreMapPciMmio;
+        zx_intel_gpu_core_protocol_ops_.unmap_pci_mmio = ZxIntelGpuCoreUnmapPciMmio;
+        zx_intel_gpu_core_protocol_ops_.get_pci_bti = ZxIntelGpuCoreGetPciBti;
+        zx_intel_gpu_core_protocol_ops_.register_interrupt_callback =
+            ZxIntelGpuCoreRegisterInterruptCallback;
+        zx_intel_gpu_core_protocol_ops_.unregister_interrupt_callback =
+            ZxIntelGpuCoreUnregisterInterruptCallback;
+        zx_intel_gpu_core_protocol_ops_.gtt_get_size = ZxIntelGpuCoreGttGetSize;
+        zx_intel_gpu_core_protocol_ops_.gtt_alloc = ZxIntelGpuCoreGttAlloc;
+        zx_intel_gpu_core_protocol_ops_.gtt_free = ZxIntelGpuCoreGttFree;
+        zx_intel_gpu_core_protocol_ops_.gtt_clear = ZxIntelGpuCoreGttClear;
+        zx_intel_gpu_core_protocol_ops_.gtt_insert = ZxIntelGpuCoreGttInsert;
+    }
+
+protected:
+    zx_intel_gpu_core_protocol_ops_t zx_intel_gpu_core_protocol_ops_ = {};
+
+private:
+    // Reads 16 bits from pci config space; returned in |value_out|.
+    static zx_status_t ZxIntelGpuCoreReadPciConfig16(void* ctx, uint16_t addr,
+                                                     uint16_t* out_value) {
+        return static_cast<D*>(ctx)->ZxIntelGpuCoreReadPciConfig16(addr, out_value);
+    }
+    // Maps the given |pci_bar|; address returned in |addr_out|, size in bytes returned in
+    // |size_out|.
+    static zx_status_t ZxIntelGpuCoreMapPciMmio(void* ctx, uint32_t pci_bar, void** out_buf_buffer,
+                                                size_t* buf_size) {
+        return static_cast<D*>(ctx)->ZxIntelGpuCoreMapPciMmio(pci_bar, out_buf_buffer, buf_size);
+    }
+    // Unmaps the given |pci_bar|.
+    static zx_status_t ZxIntelGpuCoreUnmapPciMmio(void* ctx, uint32_t pci_bar) {
+        return static_cast<D*>(ctx)->ZxIntelGpuCoreUnmapPciMmio(pci_bar);
+    }
+    // Returns a bus transaction initiator.
+    static zx_status_t ZxIntelGpuCoreGetPciBti(void* ctx, uint32_t index, zx_handle_t* out_bti) {
+        return static_cast<D*>(ctx)->ZxIntelGpuCoreGetPciBti(index, out_bti);
+    }
+    // Registers the given |callback| to be invoked with parameter |data| when an interrupt occurs
+    // matching |interrupt_mask|.
+    static zx_status_t ZxIntelGpuCoreRegisterInterruptCallback(
+        void* ctx, const zx_intel_gpu_core_interrupt_t* callback, uint32_t interrupt_mask) {
+        return static_cast<D*>(ctx)->ZxIntelGpuCoreRegisterInterruptCallback(callback,
+                                                                             interrupt_mask);
+    }
+    // Un-registers a previously registered interrupt callback.
+    static zx_status_t ZxIntelGpuCoreUnregisterInterruptCallback(void* ctx) {
+        return static_cast<D*>(ctx)->ZxIntelGpuCoreUnregisterInterruptCallback();
+    }
+    // Returns the size of the GTT (global translation table) in bytes.
+    static uint64_t ZxIntelGpuCoreGttGetSize(void* ctx) {
+        return static_cast<D*>(ctx)->ZxIntelGpuCoreGttGetSize();
+    }
+    // Allocates a region of the GTT of the given |page_count|, returning the page-aligned virtual
+    // address in |addr_out|.
+    static zx_status_t ZxIntelGpuCoreGttAlloc(void* ctx, uint64_t page_count, uint64_t* out_addr) {
+        return static_cast<D*>(ctx)->ZxIntelGpuCoreGttAlloc(page_count, out_addr);
+    }
+    // Frees the GTT allocation given by |addr|.
+    static zx_status_t ZxIntelGpuCoreGttFree(void* ctx, uint64_t addr) {
+        return static_cast<D*>(ctx)->ZxIntelGpuCoreGttFree(addr);
+    }
+    // Clears the page table entries for the GTT allocation given by |addr|.
+    static zx_status_t ZxIntelGpuCoreGttClear(void* ctx, uint64_t addr) {
+        return static_cast<D*>(ctx)->ZxIntelGpuCoreGttClear(addr);
+    }
+    // Inserts page tables entries for the GTT allocation given by |addr| for the vmo represented by
+    // handle |buffer|, at the given |page_offset| and |page_count|. Takes ownership of |buffer|.
+    static zx_status_t ZxIntelGpuCoreGttInsert(void* ctx, uint64_t addr, zx_handle_t buffer,
+                                               uint64_t page_offset, uint64_t page_count) {
+        return static_cast<D*>(ctx)->ZxIntelGpuCoreGttInsert(addr, buffer, page_offset, page_count);
+    }
+};
+
+class ZxIntelGpuCoreProtocolProxy {
+public:
+    ZxIntelGpuCoreProtocolProxy() : ops_(nullptr), ctx_(nullptr) {}
+    ZxIntelGpuCoreProtocolProxy(const zx_intel_gpu_core_protocol_t* proto)
+        : ops_(proto->ops), ctx_(proto->ctx) {}
+
+    void GetProto(zx_intel_gpu_core_protocol_t* proto) {
+        proto->ctx = ctx_;
+        proto->ops = ops_;
+    }
+    bool is_valid() { return ops_ != nullptr; }
+    void clear() {
+        ctx_ = nullptr;
+        ops_ = nullptr;
+    }
+    // Reads 16 bits from pci config space; returned in |value_out|.
+    zx_status_t ReadPciConfig16(uint16_t addr, uint16_t* out_value) {
+        return ops_->read_pci_config16(ctx_, addr, out_value);
+    }
+    // Maps the given |pci_bar|; address returned in |addr_out|, size in bytes returned in
+    // |size_out|.
+    zx_status_t MapPciMmio(uint32_t pci_bar, void** out_buf_buffer, size_t* buf_size) {
+        return ops_->map_pci_mmio(ctx_, pci_bar, out_buf_buffer, buf_size);
+    }
+    // Unmaps the given |pci_bar|.
+    zx_status_t UnmapPciMmio(uint32_t pci_bar) { return ops_->unmap_pci_mmio(ctx_, pci_bar); }
+    // Returns a bus transaction initiator.
+    zx_status_t GetPciBti(uint32_t index, zx_handle_t* out_bti) {
+        return ops_->get_pci_bti(ctx_, index, out_bti);
+    }
+    // Registers the given |callback| to be invoked with parameter |data| when an interrupt occurs
+    // matching |interrupt_mask|.
+    zx_status_t RegisterInterruptCallback(const zx_intel_gpu_core_interrupt_t* callback,
+                                          uint32_t interrupt_mask) {
+        return ops_->register_interrupt_callback(ctx_, callback, interrupt_mask);
+    }
+    // Un-registers a previously registered interrupt callback.
+    zx_status_t UnregisterInterruptCallback() { return ops_->unregister_interrupt_callback(ctx_); }
+    // Returns the size of the GTT (global translation table) in bytes.
+    uint64_t GttGetSize() { return ops_->gtt_get_size(ctx_); }
+    // Allocates a region of the GTT of the given |page_count|, returning the page-aligned virtual
+    // address in |addr_out|.
+    zx_status_t GttAlloc(uint64_t page_count, uint64_t* out_addr) {
+        return ops_->gtt_alloc(ctx_, page_count, out_addr);
+    }
+    // Frees the GTT allocation given by |addr|.
+    zx_status_t GttFree(uint64_t addr) { return ops_->gtt_free(ctx_, addr); }
+    // Clears the page table entries for the GTT allocation given by |addr|.
+    zx_status_t GttClear(uint64_t addr) { return ops_->gtt_clear(ctx_, addr); }
+    // Inserts page tables entries for the GTT allocation given by |addr| for the vmo represented by
+    // handle |buffer|, at the given |page_offset| and |page_count|. Takes ownership of |buffer|.
+    zx_status_t GttInsert(uint64_t addr, zx_handle_t buffer, uint64_t page_offset,
+                          uint64_t page_count) {
+        return ops_->gtt_insert(ctx_, addr, buffer, page_offset, page_count);
+    }
+
+private:
+    zx_intel_gpu_core_protocol_ops_t* ops_;
+    void* ctx_;
+};
+
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/intel-hda-codec-internal.h b/system/ulib/ddktl/include/ddktl/protocol/intel-hda-codec-internal.h
new file mode 100644
index 0000000..a9c51ef
--- /dev/null
+++ b/system/ulib/ddktl/include/ddktl/protocol/intel-hda-codec-internal.h
@@ -0,0 +1,27 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: This file is machine generated by fidlc.
+
+#pragma once
+
+#include <ddk/protocol/intel-hda-codec.h>
+#include <fbl/type_support.h>
+
+namespace ddk {
+namespace internal {
+
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_ihda_codec_protocol_get_driver_channel,
+                                     IhdaCodecGetDriverChannel,
+                                     zx_status_t (C::*)(zx_handle_t* out_channel));
+
+template <typename D>
+constexpr void CheckIhdaCodecProtocolSubclass() {
+    static_assert(internal::has_ihda_codec_protocol_get_driver_channel<D>::value,
+                  "IhdaCodecProtocol subclasses must implement "
+                  "zx_status_t IhdaCodecGetDriverChannel(zx_handle_t* out_channel");
+}
+
+} // namespace internal
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/intel-hda-codec.h b/system/ulib/ddktl/include/ddktl/protocol/intel-hda-codec.h
new file mode 100644
index 0000000..6d5aea2
--- /dev/null
+++ b/system/ulib/ddktl/include/ddktl/protocol/intel-hda-codec.h
@@ -0,0 +1,91 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: This file is machine generated by fidlc.
+
+#pragma once
+
+#include <ddk/protocol/intel-hda-codec.h>
+#include <ddktl/device-internal.h>
+#include <zircon/assert.h>
+#include <zircon/compiler.h>
+#include <zircon/types.h>
+
+#include "intel-hda-codec-internal.h"
+
+// DDK ihda-codec-protocol support
+//
+// :: Proxies ::
+//
+// ddk::IhdaCodecProtocolProxy is a simple wrapper around
+// ihda_codec_protocol_t. It does not own the pointers passed to it
+//
+// :: Mixins ::
+//
+// ddk::IhdaCodecProtocol is a mixin class that simplifies writing DDK drivers
+// that implement the ihda-codec protocol. It doesn't set the base protocol.
+//
+// :: Examples ::
+//
+// // A driver that implements a ZX_PROTOCOL_IHDA_CODEC device.
+// class IhdaCodecDevice {
+// using IhdaCodecDeviceType = ddk::Device<IhdaCodecDevice, /* ddk mixins */>;
+//
+// class IhdaCodecDevice : public IhdaCodecDeviceType,
+//                         public ddk::IhdaCodecProtocol<IhdaCodecDevice> {
+//   public:
+//     IhdaCodecDevice(zx_device_t* parent)
+//         : IhdaCodecDeviceType("my-ihda-codec-protocol-device", parent) {}
+//
+//     zx_status_t IhdaCodecGetDriverChannel(zx_handle_t* out_channel);
+//
+//     ...
+// };
+
+namespace ddk {
+
+template <typename D>
+class IhdaCodecProtocol : public internal::base_mixin {
+public:
+    IhdaCodecProtocol() {
+        internal::CheckIhdaCodecProtocolSubclass<D>();
+        ihda_codec_protocol_ops_.get_driver_channel = IhdaCodecGetDriverChannel;
+    }
+
+protected:
+    ihda_codec_protocol_ops_t ihda_codec_protocol_ops_ = {};
+
+private:
+    // Fetch a zx_handle_t to a channel which can be used to communicate with the codec device.
+    static zx_status_t IhdaCodecGetDriverChannel(void* ctx, zx_handle_t* out_channel) {
+        return static_cast<D*>(ctx)->IhdaCodecGetDriverChannel(out_channel);
+    }
+};
+
+class IhdaCodecProtocolProxy {
+public:
+    IhdaCodecProtocolProxy() : ops_(nullptr), ctx_(nullptr) {}
+    IhdaCodecProtocolProxy(const ihda_codec_protocol_t* proto)
+        : ops_(proto->ops), ctx_(proto->ctx) {}
+
+    void GetProto(ihda_codec_protocol_t* proto) {
+        proto->ctx = ctx_;
+        proto->ops = ops_;
+    }
+    bool is_valid() { return ops_ != nullptr; }
+    void clear() {
+        ctx_ = nullptr;
+        ops_ = nullptr;
+    }
+    // Fetch a zx_handle_t to a channel which can be used to communicate with the codec device.
+    zx_status_t GetDriverChannel(zx_handle_t* out_channel) {
+        return ops_->get_driver_channel(ctx_, out_channel);
+    }
+
+private:
+    ihda_codec_protocol_ops_t* ops_;
+    void* ctx_;
+};
+
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/intel-hda-dsp-internal.h b/system/ulib/ddktl/include/ddktl/protocol/intel-hda-dsp-internal.h
new file mode 100644
index 0000000..cc64901
--- /dev/null
+++ b/system/ulib/ddktl/include/ddktl/protocol/intel-hda-dsp-internal.h
@@ -0,0 +1,54 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: This file is machine generated by fidlc.
+
+#pragma once
+
+#include <ddk/protocol/intel-hda-dsp.h>
+#include <fbl/type_support.h>
+
+namespace ddk {
+namespace internal {
+
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_ihda_dsp_protocol_get_dev_info, IhdaDspGetDevInfo,
+                                     void (C::*)(zx_pcie_device_info_t* out_out));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_ihda_dsp_protocol_get_mmio, IhdaDspGetMmio,
+                                     zx_status_t (C::*)(zx_handle_t* out_vmo, size_t* out_size));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_ihda_dsp_protocol_get_bti, IhdaDspGetBti,
+                                     zx_status_t (C::*)(zx_handle_t* out_bti));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_ihda_dsp_protocol_enable, IhdaDspEnable, void (C::*)());
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_ihda_dsp_protocol_disable, IhdaDspDisable, void (C::*)());
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_ihda_dsp_protocol_irq_enable, IhdaDspIrqEnable,
+                                     zx_status_t (C::*)(const ihda_dsp_irq_t* callback));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_ihda_dsp_protocol_irq_disable, IhdaDspIrqDisable,
+                                     void (C::*)());
+
+template <typename D>
+constexpr void CheckIhdaDspProtocolSubclass() {
+    static_assert(internal::has_ihda_dsp_protocol_get_dev_info<D>::value,
+                  "IhdaDspProtocol subclasses must implement "
+                  "void IhdaDspGetDevInfo(zx_pcie_device_info_t* out_out");
+    static_assert(internal::has_ihda_dsp_protocol_get_mmio<D>::value,
+                  "IhdaDspProtocol subclasses must implement "
+                  "zx_status_t IhdaDspGetMmio(zx_handle_t* out_vmo, size_t* out_size");
+    static_assert(internal::has_ihda_dsp_protocol_get_bti<D>::value,
+                  "IhdaDspProtocol subclasses must implement "
+                  "zx_status_t IhdaDspGetBti(zx_handle_t* out_bti");
+    static_assert(internal::has_ihda_dsp_protocol_enable<D>::value,
+                  "IhdaDspProtocol subclasses must implement "
+                  "void IhdaDspEnable(");
+    static_assert(internal::has_ihda_dsp_protocol_disable<D>::value,
+                  "IhdaDspProtocol subclasses must implement "
+                  "void IhdaDspDisable(");
+    static_assert(internal::has_ihda_dsp_protocol_irq_enable<D>::value,
+                  "IhdaDspProtocol subclasses must implement "
+                  "zx_status_t IhdaDspIrqEnable(const ihda_dsp_irq_t* callback");
+    static_assert(internal::has_ihda_dsp_protocol_irq_disable<D>::value,
+                  "IhdaDspProtocol subclasses must implement "
+                  "void IhdaDspIrqDisable(");
+}
+
+} // namespace internal
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/intel-hda-dsp.h b/system/ulib/ddktl/include/ddktl/protocol/intel-hda-dsp.h
new file mode 100644
index 0000000..1417c23
--- /dev/null
+++ b/system/ulib/ddktl/include/ddktl/protocol/intel-hda-dsp.h
@@ -0,0 +1,144 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: This file is machine generated by fidlc.
+
+#pragma once
+
+#include <ddk/protocol/intel-hda-dsp.h>
+#include <ddktl/device-internal.h>
+#include <zircon/assert.h>
+#include <zircon/compiler.h>
+#include <zircon/types.h>
+
+#include "intel-hda-dsp-internal.h"
+
+// DDK ihda-dsp-protocol support
+//
+// :: Proxies ::
+//
+// ddk::IhdaDspProtocolProxy is a simple wrapper around
+// ihda_dsp_protocol_t. It does not own the pointers passed to it
+//
+// :: Mixins ::
+//
+// ddk::IhdaDspProtocol is a mixin class that simplifies writing DDK drivers
+// that implement the ihda-dsp protocol. It doesn't set the base protocol.
+//
+// :: Examples ::
+//
+// // A driver that implements a ZX_PROTOCOL_IHDA_DSP device.
+// class IhdaDspDevice {
+// using IhdaDspDeviceType = ddk::Device<IhdaDspDevice, /* ddk mixins */>;
+//
+// class IhdaDspDevice : public IhdaDspDeviceType,
+//                       public ddk::IhdaDspProtocol<IhdaDspDevice> {
+//   public:
+//     IhdaDspDevice(zx_device_t* parent)
+//         : IhdaDspDeviceType("my-ihda-dsp-protocol-device", parent) {}
+//
+//     void IhdaDspGetDevInfo(zx_pcie_device_info_t* out_out);
+//
+//     zx_status_t IhdaDspGetMmio(zx_handle_t* out_vmo, size_t* out_size);
+//
+//     zx_status_t IhdaDspGetBti(zx_handle_t* out_bti);
+//
+//     void IhdaDspEnable();
+//
+//     void IhdaDspDisable();
+//
+//     zx_status_t IhdaDspIrqEnable(const ihda_dsp_irq_t* callback);
+//
+//     void IhdaDspIrqDisable();
+//
+//     ...
+// };
+
+namespace ddk {
+
+template <typename D>
+class IhdaDspProtocol : public internal::base_mixin {
+public:
+    IhdaDspProtocol() {
+        internal::CheckIhdaDspProtocolSubclass<D>();
+        ihda_dsp_protocol_ops_.get_dev_info = IhdaDspGetDevInfo;
+        ihda_dsp_protocol_ops_.get_mmio = IhdaDspGetMmio;
+        ihda_dsp_protocol_ops_.get_bti = IhdaDspGetBti;
+        ihda_dsp_protocol_ops_.enable = IhdaDspEnable;
+        ihda_dsp_protocol_ops_.disable = IhdaDspDisable;
+        ihda_dsp_protocol_ops_.irq_enable = IhdaDspIrqEnable;
+        ihda_dsp_protocol_ops_.irq_disable = IhdaDspIrqDisable;
+    }
+
+protected:
+    ihda_dsp_protocol_ops_t ihda_dsp_protocol_ops_ = {};
+
+private:
+    // Fetch the parent HDA controller's PCI device info.
+    static void IhdaDspGetDevInfo(void* ctx, zx_pcie_device_info_t* out_out) {
+        static_cast<D*>(ctx)->IhdaDspGetDevInfo(out_out);
+    }
+    // Fetch a VMO that represents the BAR holding the Audio DSP registers.
+    static zx_status_t IhdaDspGetMmio(void* ctx, zx_handle_t* out_vmo, size_t* out_size) {
+        return static_cast<D*>(ctx)->IhdaDspGetMmio(out_vmo, out_size);
+    }
+    // Fetch a handle to our bus transaction initiator.
+    static zx_status_t IhdaDspGetBti(void* ctx, zx_handle_t* out_bti) {
+        return static_cast<D*>(ctx)->IhdaDspGetBti(out_bti);
+    }
+    // Enables DSP
+    static void IhdaDspEnable(void* ctx) { static_cast<D*>(ctx)->IhdaDspEnable(); }
+    // Disable DSP
+    static void IhdaDspDisable(void* ctx) { static_cast<D*>(ctx)->IhdaDspDisable(); }
+    // Enables DSP interrupts and set a callback to be invoked when an interrupt is
+    // raised.
+    // Returns `ZX_ERR_ALREADY_EXISTS` if a callback is already set.
+    static zx_status_t IhdaDspIrqEnable(void* ctx, const ihda_dsp_irq_t* callback) {
+        return static_cast<D*>(ctx)->IhdaDspIrqEnable(callback);
+    }
+    // Disable DSP interrupts and clears the callback.
+    static void IhdaDspIrqDisable(void* ctx) { static_cast<D*>(ctx)->IhdaDspIrqDisable(); }
+};
+
+class IhdaDspProtocolProxy {
+public:
+    IhdaDspProtocolProxy() : ops_(nullptr), ctx_(nullptr) {}
+    IhdaDspProtocolProxy(const ihda_dsp_protocol_t* proto) : ops_(proto->ops), ctx_(proto->ctx) {}
+
+    void GetProto(ihda_dsp_protocol_t* proto) {
+        proto->ctx = ctx_;
+        proto->ops = ops_;
+    }
+    bool is_valid() { return ops_ != nullptr; }
+    void clear() {
+        ctx_ = nullptr;
+        ops_ = nullptr;
+    }
+    // Fetch the parent HDA controller's PCI device info.
+    void GetDevInfo(zx_pcie_device_info_t* out_out) { ops_->get_dev_info(ctx_, out_out); }
+    // Fetch a VMO that represents the BAR holding the Audio DSP registers.
+    zx_status_t GetMmio(zx_handle_t* out_vmo, size_t* out_size) {
+        return ops_->get_mmio(ctx_, out_vmo, out_size);
+    }
+    // Fetch a handle to our bus transaction initiator.
+    zx_status_t GetBti(zx_handle_t* out_bti) { return ops_->get_bti(ctx_, out_bti); }
+    // Enables DSP
+    void Enable() { ops_->enable(ctx_); }
+    // Disable DSP
+    void Disable() { ops_->disable(ctx_); }
+    // Enables DSP interrupts and set a callback to be invoked when an interrupt is
+    // raised.
+    // Returns `ZX_ERR_ALREADY_EXISTS` if a callback is already set.
+    zx_status_t IrqEnable(const ihda_dsp_irq_t* callback) {
+        return ops_->irq_enable(ctx_, callback);
+    }
+    // Disable DSP interrupts and clears the callback.
+    void IrqDisable() { ops_->irq_disable(ctx_); }
+
+private:
+    ihda_dsp_protocol_ops_t* ops_;
+    void* ctx_;
+};
+
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/iommu-internal.h b/system/ulib/ddktl/include/ddktl/protocol/iommu-internal.h
index 073c442..2b4baaa 100644
--- a/system/ulib/ddktl/include/ddktl/protocol/iommu-internal.h
+++ b/system/ulib/ddktl/include/ddktl/protocol/iommu-internal.h
@@ -2,22 +2,27 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
+#include <ddk/protocol/iommu.h>
 #include <fbl/type_support.h>
 
 namespace ddk {
 namespace internal {
 
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_get_bti, GetBti,
-        zx_status_t (C::*)(uint32_t iommu_index, uint32_t bti_id, zx_handle_t* out_handle));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_iommu_protocol_get_bti, IommuGetBti,
+                                     zx_status_t (C::*)(uint32_t iommu_index, uint32_t bti_id,
+                                                        zx_handle_t* out_handle));
 
 template <typename D>
 constexpr void CheckIommuProtocolSubclass() {
-    static_assert(internal::has_get_bti<D>::value,
-                  "IommuProtocol subclasses must implement "
-                  "GetBti(uint32_t iommu_index, uint32_t bti_id, zx_handle_t* out_handle)");
- }
+    static_assert(
+        internal::has_iommu_protocol_get_bti<D>::value,
+        "IommuProtocol subclasses must implement "
+        "zx_status_t IommuGetBti(uint32_t iommu_index, uint32_t bti_id, zx_handle_t* out_handle");
+}
 
-}  // namespace internal
-}  // namespace ddk
+} // namespace internal
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/iommu.h b/system/ulib/ddktl/include/ddktl/protocol/iommu.h
index a85dff1..bec135a 100644
--- a/system/ulib/ddktl/include/ddktl/protocol/iommu.h
+++ b/system/ulib/ddktl/include/ddktl/protocol/iommu.h
@@ -2,72 +2,81 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
 #include <ddk/protocol/iommu.h>
 #include <ddktl/device-internal.h>
 #include <zircon/assert.h>
+#include <zircon/compiler.h>
+#include <zircon/types.h>
 
 #include "iommu-internal.h"
 
-// DDK IOMMU protocol support.
+// DDK iommu-protocol support
 //
 // :: Proxies ::
 //
-// ddk::IommuProtocolProxy is a simple wrappers around iommu_protocol_t. It does
-// not own the pointers passed to it.
+// ddk::IommuProtocolProxy is a simple wrapper around
+// iommu_protocol_t. It does not own the pointers passed to it
 //
 // :: Mixins ::
 //
-// ddk::IommuProtocol is a mixin class that simplifies writing DDK drivers that
-// implement the platform bus protocol.
+// ddk::IommuProtocol is a mixin class that simplifies writing DDK drivers
+// that implement the iommu protocol. It doesn't set the base protocol.
 //
 // :: Examples ::
 //
 // // A driver that implements a ZX_PROTOCOL_IOMMU device.
-// class IommuDevice;
+// class IommuDevice {
 // using IommuDeviceType = ddk::Device<IommuDevice, /* ddk mixins */>;
 //
 // class IommuDevice : public IommuDeviceType,
 //                     public ddk::IommuProtocol<IommuDevice> {
 //   public:
 //     IommuDevice(zx_device_t* parent)
-//       : IommuDeviceType("my-iommu-device", parent) {}
+//         : IommuDeviceType("my-iommu-protocol-device", parent) {}
 //
-//    zx_status_t GetBti(uint32_t iommu_index, uint32_t bti_id, zx_handle_t* out_handle);
+//     zx_status_t IommuGetBti(uint32_t iommu_index, uint32_t bti_id, zx_handle_t* out_handle);
+//
 //     ...
 // };
 
 namespace ddk {
 
 template <typename D>
-class IommuProtocol {
+class IommuProtocol : public internal::base_mixin {
 public:
     IommuProtocol() {
         internal::CheckIommuProtocolSubclass<D>();
-        iommu_proto_ops_.get_bti = GetBti;
+        iommu_protocol_ops_.get_bti = IommuGetBti;
     }
 
 protected:
-    iommu_protocol_ops_t iommu_proto_ops_ = {};
+    iommu_protocol_ops_t iommu_protocol_ops_ = {};
 
 private:
-    static zx_status_t GetBti(void* ctx, uint32_t iommu_index, uint32_t bti_id,
-                              zx_handle_t* out_handle) {
-        return static_cast<D*>(ctx)->GetBti(iommu_index, bti_id, out_handle);
+    static zx_status_t IommuGetBti(void* ctx, uint32_t iommu_index, uint32_t bti_id,
+                                   zx_handle_t* out_handle) {
+        return static_cast<D*>(ctx)->IommuGetBti(iommu_index, bti_id, out_handle);
     }
 };
 
 class IommuProtocolProxy {
 public:
-    IommuProtocolProxy(iommu_protocol_t* proto)
-        : ops_(proto->ops), ctx_(proto->ctx) {}
+    IommuProtocolProxy() : ops_(nullptr), ctx_(nullptr) {}
+    IommuProtocolProxy(const iommu_protocol_t* proto) : ops_(proto->ops), ctx_(proto->ctx) {}
 
     void GetProto(iommu_protocol_t* proto) {
         proto->ctx = ctx_;
         proto->ops = ops_;
     }
-
+    bool is_valid() { return ops_ != nullptr; }
+    void clear() {
+        ctx_ = nullptr;
+        ops_ = nullptr;
+    }
     zx_status_t GetBti(uint32_t iommu_index, uint32_t bti_id, zx_handle_t* out_handle) {
         return ops_->get_bti(ctx_, iommu_index, bti_id, out_handle);
     }
diff --git a/system/ulib/ddktl/include/ddktl/protocol/mailbox-internal.h b/system/ulib/ddktl/include/ddktl/protocol/mailbox-internal.h
index 72bac82..41c43cc 100644
--- a/system/ulib/ddktl/include/ddktl/protocol/mailbox-internal.h
+++ b/system/ulib/ddktl/include/ddktl/protocol/mailbox-internal.h
@@ -2,22 +2,27 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
+#include <ddk/protocol/mailbox.h>
 #include <fbl/type_support.h>
 
 namespace ddk {
 namespace internal {
 
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_mailbox_send_cmd, MailboxSendCmd,
-        zx_status_t (C::*)(mailbox_channel_t*, mailbox_data_buf_t*));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_mailbox_protocol_send_command, MailboxSendCommand,
+                                     zx_status_t (C::*)(const mailbox_channel_t* channel,
+                                                        const mailbox_data_buf_t* mdata));
 
 template <typename D>
 constexpr void CheckMailboxProtocolSubclass() {
-    static_assert(internal::has_mailbox_send_cmd<D>::value,
+    static_assert(internal::has_mailbox_protocol_send_command<D>::value,
                   "MailboxProtocol subclasses must implement "
-                  "MailboxSendCmd(mailbox_channel_t* channel, mailbox_data_buf_t* mdata)");
- }
+                  "zx_status_t MailboxSendCommand(const mailbox_channel_t* channel, const "
+                  "mailbox_data_buf_t* mdata");
+}
 
-}  // namespace internal
-}  // namespace ddk
+} // namespace internal
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/mailbox.h b/system/ulib/ddktl/include/ddktl/protocol/mailbox.h
index 6111052..8d4d7d3 100644
--- a/system/ulib/ddktl/include/ddktl/protocol/mailbox.h
+++ b/system/ulib/ddktl/include/ddktl/protocol/mailbox.h
@@ -2,74 +2,84 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
 #include <ddk/protocol/mailbox.h>
 #include <ddktl/device-internal.h>
 #include <zircon/assert.h>
+#include <zircon/compiler.h>
+#include <zircon/types.h>
 
 #include "mailbox-internal.h"
 
-// DDK mailbox protocol support.
+// DDK mailbox-protocol support
 //
 // :: Proxies ::
 //
-// ddk::MailboxProtocolProxy is a simple wrappers around mailbox_protocol_t. It does
-// not own the pointers passed to it.
+// ddk::MailboxProtocolProxy is a simple wrapper around
+// mailbox_protocol_t. It does not own the pointers passed to it
 //
 // :: Mixins ::
 //
-// ddk::MailboxProtocol is a mixin class that simplifies writing DDK drivers that
-// implement the mailbox protocol.
+// ddk::MailboxProtocol is a mixin class that simplifies writing DDK drivers
+// that implement the mailbox protocol. It doesn't set the base protocol.
 //
 // :: Examples ::
 //
 // // A driver that implements a ZX_PROTOCOL_MAILBOX device.
-// class MailboxDevice;
+// class MailboxDevice {
 // using MailboxDeviceType = ddk::Device<MailboxDevice, /* ddk mixins */>;
 //
 // class MailboxDevice : public MailboxDeviceType,
-//                   public ddk::MailboxProtocol<MailboxDevice> {
+//                       public ddk::MailboxProtocol<MailboxDevice> {
 //   public:
 //     MailboxDevice(zx_device_t* parent)
-//       : MailboxDeviceType("my-mailbox-device", parent) {}
+//         : MailboxDeviceType("my-mailbox-protocol-device", parent) {}
 //
-//    zx_status_t MailboxSendCmd(mailbox_channel_t* channel, mailbox_data_buf_t* mdata);
+//     zx_status_t MailboxSendCommand(const mailbox_channel_t* channel, const mailbox_data_buf_t*
+//     mdata);
+//
 //     ...
 // };
 
 namespace ddk {
 
 template <typename D>
-class MailboxProtocol {
+class MailboxProtocol : public internal::base_mixin {
 public:
     MailboxProtocol() {
         internal::CheckMailboxProtocolSubclass<D>();
-        mailbox_proto_ops_.send_cmd = MailboxSendCmd;
+        mailbox_protocol_ops_.send_command = MailboxSendCommand;
     }
 
 protected:
-    mailbox_protocol_ops_t mailbox_proto_ops_ = {};
+    mailbox_protocol_ops_t mailbox_protocol_ops_ = {};
 
 private:
-    static zx_status_t MailboxSendCmd(void* ctx, mailbox_channel_t* channel,
-                                      mailbox_data_buf_t* mdata) {
-        return static_cast<D*>(ctx)->MailboxSendCmd(channel, mdata);
+    static zx_status_t MailboxSendCommand(void* ctx, const mailbox_channel_t* channel,
+                                          const mailbox_data_buf_t* mdata) {
+        return static_cast<D*>(ctx)->MailboxSendCommand(channel, mdata);
     }
 };
 
 class MailboxProtocolProxy {
 public:
-    MailboxProtocolProxy(mailbox_protocol_t* proto)
-        : ops_(proto->ops), ctx_(proto->ctx) {}
+    MailboxProtocolProxy() : ops_(nullptr), ctx_(nullptr) {}
+    MailboxProtocolProxy(const mailbox_protocol_t* proto) : ops_(proto->ops), ctx_(proto->ctx) {}
 
     void GetProto(mailbox_protocol_t* proto) {
         proto->ctx = ctx_;
         proto->ops = ops_;
     }
-
-    zx_status_t SendCmd(mailbox_channel_t* channel, mailbox_data_buf_t* mdata) {
-        return ops_->send_cmd(ctx_, channel, mdata);
+    bool is_valid() { return ops_ != nullptr; }
+    void clear() {
+        ctx_ = nullptr;
+        ops_ = nullptr;
+    }
+    zx_status_t SendCommand(const mailbox_channel_t* channel, const mailbox_data_buf_t* mdata) {
+        return ops_->send_command(ctx_, channel, mdata);
     }
 
 private:
diff --git a/system/ulib/ddktl/include/ddktl/protocol/nand-internal.h b/system/ulib/ddktl/include/ddktl/protocol/nand-internal.h
index 9e9e1be..d5c0255 100644
--- a/system/ulib/ddktl/include/ddktl/protocol/nand-internal.h
+++ b/system/ulib/ddktl/include/ddktl/protocol/nand-internal.h
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
 #include <ddk/protocol/nand.h>
@@ -10,27 +12,31 @@
 namespace ddk {
 namespace internal {
 
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_query, Query,
-                                     void (C::*)(nand_info_t*, size_t*));
-
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_queue, Queue, void (C::*)(nand_op_t*));
-
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_get_factory_bad_block_list, GetFactoryBadBlockList,
-                                     zx_status_t (C::*)(uint32_t* , uint32_t , uint32_t*));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_nand_protocol_query, NandQuery,
+                                     void (C::*)(nand_info_t* out_info, size_t* out_nand_op_size));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_nand_protocol_queue, NandQueue,
+                                     void (C::*)(nand_operation_t* op, nand_queue_callback callback,
+                                                 void* cookie));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_nand_protocol_get_factory_bad_block_list,
+                                     NandGetFactoryBadBlockList,
+                                     zx_status_t (C::*)(uint32_t* out_bad_blocks_list,
+                                                        size_t bad_blocks_count,
+                                                        size_t* out_bad_blocks_actual));
 
 template <typename D>
 constexpr void CheckNandProtocolSubclass() {
-    static_assert(internal::has_query<D>::value,
+    static_assert(internal::has_nand_protocol_query<D>::value,
                   "NandProtocol subclasses must implement "
-                  "Query(nand_info_t* info_out, size_t* nand_op_size_out)");
-    static_assert(internal::has_queue<D>::value,
+                  "void NandQuery(nand_info_t* out_info, size_t* out_nand_op_size");
+    static_assert(
+        internal::has_nand_protocol_queue<D>::value,
+        "NandProtocol subclasses must implement "
+        "void NandQueue(nand_operation_t* op, nand_queue_callback callback, void* cookie");
+    static_assert(internal::has_nand_protocol_get_factory_bad_block_list<D>::value,
                   "NandProtocol subclasses must implement "
-                  "Queue(nand_op_t* operation)");
-    static_assert(internal::has_get_factory_bad_block_list<D>::value,
-                  "NandProtocol subclasses must implement "
-                  "GetFactoryBadBlockList(uint32_t* bad_blocks, "
-                  "uint32_t bad_block_len, uint32_t* num_bad_blocks)");
+                  "zx_status_t NandGetFactoryBadBlockList(uint32_t* out_bad_blocks_list, size_t "
+                  "bad_blocks_count, size_t* out_bad_blocks_actual");
 }
 
-}  // namespace internal
-}  // namespace ddk
+} // namespace internal
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/nand.h b/system/ulib/ddktl/include/ddktl/protocol/nand.h
index 6245670..405bf4c 100644
--- a/system/ulib/ddktl/include/ddktl/protocol/nand.h
+++ b/system/ulib/ddktl/include/ddktl/protocol/nand.h
@@ -2,43 +2,50 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
-#include <ddk/driver.h>
 #include <ddk/protocol/nand.h>
 #include <ddktl/device-internal.h>
 #include <zircon/assert.h>
+#include <zircon/compiler.h>
+#include <zircon/device/nand.h>
+#include <zircon/types.h>
 
 #include "nand-internal.h"
 
-// DDK nand protocol support.
+// DDK nand-protocol support
 //
 // :: Proxies ::
 //
-// ddk::NandProtocolProxy is a simple wrappers around nand_protocol_t. It does
-// not own the pointers passed to it.
+// ddk::NandProtocolProxy is a simple wrapper around
+// nand_protocol_t. It does not own the pointers passed to it
 //
 // :: Mixins ::
 //
-// ddk::NandProtocol is a mixin class that simplifies writing DDK drivers that
-// implement the nand protocol.
+// ddk::NandProtocol is a mixin class that simplifies writing DDK drivers
+// that implement the nand protocol. It doesn't set the base protocol.
 //
 // :: Examples ::
 //
 // // A driver that implements a ZX_PROTOCOL_NAND device.
-// class NandDevice;
+// class NandDevice {
 // using NandDeviceType = ddk::Device<NandDevice, /* ddk mixins */>;
 //
 // class NandDevice : public NandDeviceType,
 //                    public ddk::NandProtocol<NandDevice> {
 //   public:
 //     NandDevice(zx_device_t* parent)
-//       : NandDeviceType("my-nand-device", parent) {}
+//         : NandDeviceType("my-nand-protocol-device", parent) {}
 //
-//     void Query(nand_info_t* info_out, size_t* nand_op_size_out);
-//     void Queue(nand_op_t* operation);
-//     zx_status_t GetFactoryBadBlockList(uint32_t* bad_blocks, uint32_t bad_block_len,
-//                                        uint32_t* num_bad_blocks);
+//     void NandQuery(nand_info_t* out_info, size_t* out_nand_op_size);
+//
+//     void NandQueue(nand_operation_t* op, nand_queue_callback callback, void* cookie);
+//
+//     zx_status_t NandGetFactoryBadBlockList(uint32_t* out_bad_blocks_list, size_t
+//     bad_blocks_count, size_t* out_bad_blocks_actual);
+//
 //     ...
 // };
 
@@ -49,51 +56,87 @@
 public:
     NandProtocol() {
         internal::CheckNandProtocolSubclass<D>();
-        nand_proto_ops_.query = Query;
-        nand_proto_ops_.queue = Queue;
-        nand_proto_ops_.get_factory_bad_block_list = GetFactoryBadBlockList;
+        ops_.query = NandQuery;
+        ops_.queue = NandQueue;
+        ops_.get_factory_bad_block_list = NandGetFactoryBadBlockList;
 
         // Can only inherit from one base_protocol implementation.
-        ZX_ASSERT(ddk_proto_id_ == 0);
+        ZX_ASSERT(ddk_proto_id_ = 0);
         ddk_proto_id_ = ZX_PROTOCOL_NAND;
-        ddk_proto_ops_ = &nand_proto_ops_;
+        ddk_proto_ops_ = &ops_;
     }
 
 protected:
-    nand_protocol_ops_t nand_proto_ops_ = {};
+    nand_protocol_ops_t ops_ = {};
 
 private:
-    static void Query(void* ctx, nand_info_t* info_out, size_t* nand_op_size_out) {
-        static_cast<D*>(ctx)->Query(info_out, nand_op_size_out);
+    // Obtains the parameters of the nand device (nand_info_t) and the required
+    // size of nand_op_t. The nand_op_t's submitted via queue() must have
+    // nand_op_size_out - sizeof(nand_op_t) bytes available at the end of the
+    // structure for the use of the driver.
+    static void NandQuery(void* ctx, nand_info_t* out_info, size_t* out_nand_op_size) {
+        static_cast<D*>(ctx)->NandQuery(out_info, out_nand_op_size);
     }
-
-    static void Queue(void* ctx, nand_op_t* operation) {
-        static_cast<D*>(ctx)->Queue(operation);
+    // Submits an IO request for processing. Success or failure will be reported
+    // via the completion_cb() in the nand_op_t. The callback may be called
+    // before the queue() method returns.
+    static void NandQueue(void* ctx, nand_operation_t* op, nand_queue_callback callback,
+                          void* cookie) {
+        static_cast<D*>(ctx)->NandQueue(op, callback, cookie);
     }
-
-    static zx_status_t GetFactoryBadBlockList(void* ctx, uint32_t* bad_blocks,
-                                              uint32_t bad_block_len, uint32_t* num_bad_blocks) {
-        return static_cast<D*>(ctx)->GetFactoryBadBlockList(bad_blocks, bad_block_len,
-                                                            num_bad_blocks);
+    // Gets the list of bad erase blocks, as reported by the nand manufacturer.
+    // The caller must allocate a table large enough to hold the expected number
+    // of entries, and pass the size of that table on |bad_block_len|.
+    // On return, |num_bad_blocks| contains the number of bad blocks found.
+    // This should only be called before writing any data to the nand, and the
+    // returned data should be saved somewhere else, along blocks that become
+    // bad after they've been in use.
+    static zx_status_t NandGetFactoryBadBlockList(void* ctx, uint32_t* out_bad_blocks_list,
+                                                  size_t bad_blocks_count,
+                                                  size_t* out_bad_blocks_actual) {
+        return static_cast<D*>(ctx)->NandGetFactoryBadBlockList(
+            out_bad_blocks_list, bad_blocks_count, out_bad_blocks_actual);
     }
 };
 
 class NandProtocolProxy {
 public:
-    NandProtocolProxy(nand_protocol_t* proto)
-        : ops_(proto->ops), ctx_(proto->ctx) {}
+    NandProtocolProxy() : ops_(nullptr), ctx_(nullptr) {}
+    NandProtocolProxy(const nand_protocol_t* proto) : ops_(proto->ops), ctx_(proto->ctx) {}
 
-    void Query(nand_info_t* info_out, size_t* nand_op_size_out) {
-        ops_->query(ctx_, info_out, nand_op_size_out);
+    void GetProto(nand_protocol_t* proto) {
+        proto->ctx = ctx_;
+        proto->ops = ops_;
     }
-
-    void Queue(nand_op_t* operation) {
-        ops_->queue(ctx_, operation);
+    bool is_valid() { return ops_ != nullptr; }
+    void clear() {
+        ctx_ = nullptr;
+        ops_ = nullptr;
     }
-
-    zx_status_t GetFactoryBadBlockList(uint32_t* bad_blocks, uint32_t bad_block_len,
-                                       uint32_t* num_bad_blocks) {
-        return ops_->get_factory_bad_block_list(ctx_, bad_blocks, bad_block_len, num_bad_blocks);
+    // Obtains the parameters of the nand device (nand_info_t) and the required
+    // size of nand_op_t. The nand_op_t's submitted via queue() must have
+    // nand_op_size_out - sizeof(nand_op_t) bytes available at the end of the
+    // structure for the use of the driver.
+    void Query(nand_info_t* out_info, size_t* out_nand_op_size) {
+        ops_->query(ctx_, out_info, out_nand_op_size);
+    }
+    // Submits an IO request for processing. Success or failure will be reported
+    // via the completion_cb() in the nand_op_t. The callback may be called
+    // before the queue() method returns.
+    void Queue(nand_operation_t* op, nand_queue_callback callback, void* cookie) {
+        ops_->queue(ctx_, op, callback, cookie);
+    }
+    // Gets the list of bad erase blocks, as reported by the nand manufacturer.
+    // The caller must allocate a table large enough to hold the expected number
+    // of entries, and pass the size of that table on |bad_block_len|.
+    // On return, |num_bad_blocks| contains the number of bad blocks found.
+    // This should only be called before writing any data to the nand, and the
+    // returned data should be saved somewhere else, along blocks that become
+    // bad after they've been in use.
+    zx_status_t GetFactoryBadBlockList(uint32_t* out_bad_blocks_list, size_t bad_blocks_count,
+                                       size_t* out_bad_blocks_actual) {
+        return ops_->get_factory_bad_block_list(ctx_, out_bad_blocks_list, bad_blocks_count,
+                                                out_bad_blocks_actual);
     }
 
 private:
diff --git a/system/ulib/ddktl/include/ddktl/protocol/pci-internal.h b/system/ulib/ddktl/include/ddktl/protocol/pci-internal.h
new file mode 100644
index 0000000..4f37e57
--- /dev/null
+++ b/system/ulib/ddktl/include/ddktl/protocol/pci-internal.h
@@ -0,0 +1,96 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: This file is machine generated by fidlc.
+
+#pragma once
+
+#include <ddk/protocol/pci.h>
+#include <fbl/type_support.h>
+
+namespace ddk {
+namespace internal {
+
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_pci_protocol_get_bar, PciGetBar,
+                                     zx_status_t (C::*)(uint32_t bar_id, zx_pci_bar_t* out_res));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_pci_protocol_map_bar, PciMapBar,
+                                     zx_status_t (C::*)(uint32_t bar_id, uint32_t cache_policy,
+                                                        void** out_vaddr_buffer, size_t* vaddr_size,
+                                                        zx_handle_t* out_handle));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_pci_protocol_enable_bus_master, PciEnableBusMaster,
+                                     zx_status_t (C::*)(bool enable));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_pci_protocol_reset_device, PciResetDevice,
+                                     zx_status_t (C::*)());
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_pci_protocol_map_interrupt, PciMapInterrupt,
+                                     zx_status_t (C::*)(zx_status_t which_irq,
+                                                        zx_handle_t* out_handle));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_pci_protocol_query_irq_mode, PciQueryIrqMode,
+                                     zx_status_t (C::*)(zx_pci_irq_mode_t mode,
+                                                        uint32_t* out_max_irqs));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_pci_protocol_set_irq_mode, PciSetIrqMode,
+                                     zx_status_t (C::*)(zx_pci_irq_mode_t mode,
+                                                        uint32_t requested_irq_count));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_pci_protocol_get_device_info, PciGetDeviceInfo,
+                                     zx_status_t (C::*)(zx_pcie_device_info_t* out_into));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_pci_protocol_config_read, PciConfigRead,
+                                     zx_status_t (C::*)(uint16_t offset, size_t width,
+                                                        uint32_t* out_value));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_pci_protocol_config_write, PciConfigWrite,
+                                     zx_status_t (C::*)(uint16_t offset, size_t width,
+                                                        uint32_t value));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_pci_protocol_get_next_capability, PciGetNextCapability,
+                                     uint8_t (C::*)(uint8_t type, uint8_t offset));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_pci_protocol_get_auxdata, PciGetAuxdata,
+                                     zx_status_t (C::*)(const char* args, void* out_data_buffer,
+                                                        size_t data_size, size_t* out_data_actual));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_pci_protocol_get_bti, PciGetBti,
+                                     zx_status_t (C::*)(uint32_t index, zx_handle_t* out_bti));
+
+template <typename D>
+constexpr void CheckPciProtocolSubclass() {
+    static_assert(internal::has_pci_protocol_get_bar<D>::value,
+                  "PciProtocol subclasses must implement "
+                  "zx_status_t PciGetBar(uint32_t bar_id, zx_pci_bar_t* out_res");
+    static_assert(internal::has_pci_protocol_map_bar<D>::value,
+                  "PciProtocol subclasses must implement "
+                  "zx_status_t PciMapBar(uint32_t bar_id, uint32_t cache_policy, void** "
+                  "out_vaddr_buffer, size_t* vaddr_size, zx_handle_t* out_handle");
+    static_assert(internal::has_pci_protocol_enable_bus_master<D>::value,
+                  "PciProtocol subclasses must implement "
+                  "zx_status_t PciEnableBusMaster(bool enable");
+    static_assert(internal::has_pci_protocol_reset_device<D>::value,
+                  "PciProtocol subclasses must implement "
+                  "zx_status_t PciResetDevice(");
+    static_assert(internal::has_pci_protocol_map_interrupt<D>::value,
+                  "PciProtocol subclasses must implement "
+                  "zx_status_t PciMapInterrupt(zx_status_t which_irq, zx_handle_t* out_handle");
+    static_assert(internal::has_pci_protocol_query_irq_mode<D>::value,
+                  "PciProtocol subclasses must implement "
+                  "zx_status_t PciQueryIrqMode(zx_pci_irq_mode_t mode, uint32_t* out_max_irqs");
+    static_assert(internal::has_pci_protocol_set_irq_mode<D>::value,
+                  "PciProtocol subclasses must implement "
+                  "zx_status_t PciSetIrqMode(zx_pci_irq_mode_t mode, uint32_t requested_irq_count");
+    static_assert(internal::has_pci_protocol_get_device_info<D>::value,
+                  "PciProtocol subclasses must implement "
+                  "zx_status_t PciGetDeviceInfo(zx_pcie_device_info_t* out_into");
+    static_assert(internal::has_pci_protocol_config_read<D>::value,
+                  "PciProtocol subclasses must implement "
+                  "zx_status_t PciConfigRead(uint16_t offset, size_t width, uint32_t* out_value");
+    static_assert(internal::has_pci_protocol_config_write<D>::value,
+                  "PciProtocol subclasses must implement "
+                  "zx_status_t PciConfigWrite(uint16_t offset, size_t width, uint32_t value");
+    static_assert(internal::has_pci_protocol_get_next_capability<D>::value,
+                  "PciProtocol subclasses must implement "
+                  "uint8_t PciGetNextCapability(uint8_t type, uint8_t offset");
+    static_assert(internal::has_pci_protocol_get_auxdata<D>::value,
+                  "PciProtocol subclasses must implement "
+                  "zx_status_t PciGetAuxdata(const char* args, void* out_data_buffer, size_t "
+                  "data_size, size_t* out_data_actual");
+    static_assert(internal::has_pci_protocol_get_bti<D>::value,
+                  "PciProtocol subclasses must implement "
+                  "zx_status_t PciGetBti(uint32_t index, zx_handle_t* out_bti");
+}
+
+} // namespace internal
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/pci.h b/system/ulib/ddktl/include/ddktl/protocol/pci.h
index 4c9ba37..2683497 100644
--- a/system/ulib/ddktl/include/ddktl/protocol/pci.h
+++ b/system/ulib/ddktl/include/ddktl/protocol/pci.h
@@ -1,130 +1,202 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
 #include <ddk/protocol/pci.h>
+#include <ddktl/device-internal.h>
+#include <zircon/assert.h>
+#include <zircon/compiler.h>
+#include <zircon/syscalls/pci.h>
+#include <zircon/types.h>
 
-// DDK PCI protocol support
+#include "pci-internal.h"
+
+// DDK pci-protocol support
 //
-// :: Proxy ::
+// :: Proxies ::
 //
-// ddk::PciProtocolProxy is a simple wrapper around pci_protocol_t. It does not own the pointers
-// passed to it.
+// ddk::PciProtocolProxy is a simple wrapper around
+// pci_protocol_t. It does not own the pointers passed to it
 //
-// :: Mixin ::
+// :: Mixins ::
 //
-// No mixins are defined, as it is not expected that there will be multiple implementations of the
-// pci protocol.
+// ddk::PciProtocol is a mixin class that simplifies writing DDK drivers
+// that implement the pci protocol. It doesn't set the base protocol.
 //
-// :: Example ::
+// :: Examples ::
 //
-// // A driver that communicates with a ZX_PROTOCOL_PCI device
-// class MyDevice;
-// using MyDeviceType = ddk::Device<MyDevice, /* ddk mixins */>;
+// // A driver that implements a ZX_PROTOCOL_PCI device.
+// class PciDevice {
+// using PciDeviceType = ddk::Device<PciDevice, /* ddk mixins */>;
 //
-// class MyDevice : public MyDeviceType {
+// class PciDevice : public PciDeviceType,
+//                   public ddk::PciProtocol<PciDevice> {
 //   public:
-//     MyDevice(zx_device_t* parent)
-//       : MyDeviceType(parent) {}
+//     PciDevice(zx_device_t* parent)
+//         : PciDeviceType("my-pci-protocol-device", parent) {}
 //
-//     void DdkRelease() {
-//         // Clean up
-//         delete this;
-//     }
+//     zx_status_t PciGetBar(uint32_t bar_id, zx_pci_bar_t* out_res);
 //
-//     zx_status_t Bind() {
-//         pci_protocol_t* ops;
-//         auto status = get_device_protocol(parent_, ZX_PROTOCOL_PCI,
-//                                           reinterpret_cast<void**>(&ops));
-//         if (status != ZX_OK) {
-//             return status;
-//         }
-//         pci_.reset(new ddk::PciProtocolProxy(ops));
+//     zx_status_t PciMapBar(uint32_t bar_id, uint32_t cache_policy, void** out_vaddr_buffer,
+//     size_t* vaddr_size, zx_handle_t* out_handle);
 //
-//         // Query interrupt capabilities, etc.
-//         uint32_t irq_count = 0;
-//         if (pci_.QueryIrqModeCaps(ZX_PCIE_IRQ_MODE_MSI, &irq_count) == ZX_OK) {
-//             // etc
-//         }
-
-//         return DdkAdd("my-device");
-//     }
+//     zx_status_t PciEnableBusMaster(bool enable);
 //
-//   private:
-//     fbl::unique_ptr<ddk::PciProtocolProxy> pci_;
+//     zx_status_t PciResetDevice();
+//
+//     zx_status_t PciMapInterrupt(zx_status_t which_irq, zx_handle_t* out_handle);
+//
+//     zx_status_t PciQueryIrqMode(zx_pci_irq_mode_t mode, uint32_t* out_max_irqs);
+//
+//     zx_status_t PciSetIrqMode(zx_pci_irq_mode_t mode, uint32_t requested_irq_count);
+//
+//     zx_status_t PciGetDeviceInfo(zx_pcie_device_info_t* out_into);
+//
+//     zx_status_t PciConfigRead(uint16_t offset, size_t width, uint32_t* out_value);
+//
+//     zx_status_t PciConfigWrite(uint16_t offset, size_t width, uint32_t value);
+//
+//     uint8_t PciGetNextCapability(uint8_t type, uint8_t offset);
+//
+//     zx_status_t PciGetAuxdata(const char* args, void* out_data_buffer, size_t data_size, size_t*
+//     out_data_actual);
+//
+//     zx_status_t PciGetBti(uint32_t index, zx_handle_t* out_bti);
+//
+//     ...
 // };
 
 namespace ddk {
 
+template <typename D>
+class PciProtocol : public internal::base_mixin {
+public:
+    PciProtocol() {
+        internal::CheckPciProtocolSubclass<D>();
+        pci_protocol_ops_.get_bar = PciGetBar;
+        pci_protocol_ops_.map_bar = PciMapBar;
+        pci_protocol_ops_.enable_bus_master = PciEnableBusMaster;
+        pci_protocol_ops_.reset_device = PciResetDevice;
+        pci_protocol_ops_.map_interrupt = PciMapInterrupt;
+        pci_protocol_ops_.query_irq_mode = PciQueryIrqMode;
+        pci_protocol_ops_.set_irq_mode = PciSetIrqMode;
+        pci_protocol_ops_.get_device_info = PciGetDeviceInfo;
+        pci_protocol_ops_.config_read = PciConfigRead;
+        pci_protocol_ops_.config_write = PciConfigWrite;
+        pci_protocol_ops_.get_next_capability = PciGetNextCapability;
+        pci_protocol_ops_.get_auxdata = PciGetAuxdata;
+        pci_protocol_ops_.get_bti = PciGetBti;
+    }
+
+protected:
+    pci_protocol_ops_t pci_protocol_ops_ = {};
+
+private:
+    static zx_status_t PciGetBar(void* ctx, uint32_t bar_id, zx_pci_bar_t* out_res) {
+        return static_cast<D*>(ctx)->PciGetBar(bar_id, out_res);
+    }
+    static zx_status_t PciMapBar(void* ctx, uint32_t bar_id, uint32_t cache_policy,
+                                 void** out_vaddr_buffer, size_t* vaddr_size,
+                                 zx_handle_t* out_handle) {
+        return static_cast<D*>(ctx)->PciMapBar(bar_id, cache_policy, out_vaddr_buffer, vaddr_size,
+                                               out_handle);
+    }
+    static zx_status_t PciEnableBusMaster(void* ctx, bool enable) {
+        return static_cast<D*>(ctx)->PciEnableBusMaster(enable);
+    }
+    static zx_status_t PciResetDevice(void* ctx) { return static_cast<D*>(ctx)->PciResetDevice(); }
+    static zx_status_t PciMapInterrupt(void* ctx, zx_status_t which_irq, zx_handle_t* out_handle) {
+        return static_cast<D*>(ctx)->PciMapInterrupt(which_irq, out_handle);
+    }
+    static zx_status_t PciQueryIrqMode(void* ctx, zx_pci_irq_mode_t mode, uint32_t* out_max_irqs) {
+        return static_cast<D*>(ctx)->PciQueryIrqMode(mode, out_max_irqs);
+    }
+    static zx_status_t PciSetIrqMode(void* ctx, zx_pci_irq_mode_t mode,
+                                     uint32_t requested_irq_count) {
+        return static_cast<D*>(ctx)->PciSetIrqMode(mode, requested_irq_count);
+    }
+    static zx_status_t PciGetDeviceInfo(void* ctx, zx_pcie_device_info_t* out_into) {
+        return static_cast<D*>(ctx)->PciGetDeviceInfo(out_into);
+    }
+    static zx_status_t PciConfigRead(void* ctx, uint16_t offset, size_t width,
+                                     uint32_t* out_value) {
+        return static_cast<D*>(ctx)->PciConfigRead(offset, width, out_value);
+    }
+    static zx_status_t PciConfigWrite(void* ctx, uint16_t offset, size_t width, uint32_t value) {
+        return static_cast<D*>(ctx)->PciConfigWrite(offset, width, value);
+    }
+    static uint8_t PciGetNextCapability(void* ctx, uint8_t type, uint8_t offset) {
+        return static_cast<D*>(ctx)->PciGetNextCapability(type, offset);
+    }
+    static zx_status_t PciGetAuxdata(void* ctx, const char* args, void* out_data_buffer,
+                                     size_t data_size, size_t* out_data_actual) {
+        return static_cast<D*>(ctx)->PciGetAuxdata(args, out_data_buffer, data_size,
+                                                   out_data_actual);
+    }
+    static zx_status_t PciGetBti(void* ctx, uint32_t index, zx_handle_t* out_bti) {
+        return static_cast<D*>(ctx)->PciGetBti(index, out_bti);
+    }
+};
+
 class PciProtocolProxy {
-  public:
-    PciProtocolProxy(pci_protocol_t* proto)
-      : ops_(proto->ops), ctx_(proto->ctx) {}
+public:
+    PciProtocolProxy() : ops_(nullptr), ctx_(nullptr) {}
+    PciProtocolProxy(const pci_protocol_t* proto) : ops_(proto->ops), ctx_(proto->ctx) {}
 
-    zx_status_t GetResource(uint32_t res_id, zx_pci_bar_t* out_res) {
-        return ops_->get_resource(ctx_, res_id, out_res);
+    void GetProto(pci_protocol_t* proto) {
+        proto->ctx = ctx_;
+        proto->ops = ops_;
     }
-
-    zx_status_t MapResource(uint32_t res_id, uint32_t cache_policy, void** vaddr, size_t* size,
-                            zx_handle_t* out_handle) {
-        return ops_->map_resource(ctx_, res_id, cache_policy, vaddr, size, out_handle);
+    bool is_valid() { return ops_ != nullptr; }
+    void clear() {
+        ctx_ = nullptr;
+        ops_ = nullptr;
     }
-
-    zx_status_t EnableBusMaster(bool enable) {
-        return ops_->enable_bus_master(ctx_, enable);
+    zx_status_t GetBar(uint32_t bar_id, zx_pci_bar_t* out_res) {
+        return ops_->get_bar(ctx_, bar_id, out_res);
     }
-
-    zx_status_t ResetDevice() {
-        return ops_->reset_device(ctx_);
+    zx_status_t MapBar(uint32_t bar_id, uint32_t cache_policy, void** out_vaddr_buffer,
+                       size_t* vaddr_size, zx_handle_t* out_handle) {
+        return ops_->map_bar(ctx_, bar_id, cache_policy, out_vaddr_buffer, vaddr_size, out_handle);
     }
-
-    zx_status_t MapInterrupt(int which_irq, zx_handle_t* out_handle) {
+    zx_status_t EnableBusMaster(bool enable) { return ops_->enable_bus_master(ctx_, enable); }
+    zx_status_t ResetDevice() { return ops_->reset_device(ctx_); }
+    zx_status_t MapInterrupt(zx_status_t which_irq, zx_handle_t* out_handle) {
         return ops_->map_interrupt(ctx_, which_irq, out_handle);
     }
-
-    zx_status_t QueryIrqModeCaps(zx_pci_irq_mode_t mode, uint32_t* out_max_irqs) {
+    zx_status_t QueryIrqMode(zx_pci_irq_mode_t mode, uint32_t* out_max_irqs) {
         return ops_->query_irq_mode(ctx_, mode, out_max_irqs);
     }
-
     zx_status_t SetIrqMode(zx_pci_irq_mode_t mode, uint32_t requested_irq_count) {
         return ops_->set_irq_mode(ctx_, mode, requested_irq_count);
     }
-
-    zx_status_t GetDeviceInfo(zx_pcie_device_info_t* out_info) {
-        return ops_->get_device_info(ctx_, out_info);
+    zx_status_t GetDeviceInfo(zx_pcie_device_info_t* out_into) {
+        return ops_->get_device_info(ctx_, out_into);
     }
-
-    zx_status_t ConfigRead(uint8_t offset, size_t width, uint32_t *value) {
-        return ops_->config_read(ctx_, offset, width, value);
+    zx_status_t ConfigRead(uint16_t offset, size_t width, uint32_t* out_value) {
+        return ops_->config_read(ctx_, offset, width, out_value);
     }
-
-    zx_status_t ConfigRead8(uint8_t offset, uint8_t *value) {
-        uint32_t val;
-        zx_status_t status = ConfigRead(offset, 8, &val);
-        *value = val & 0xff;
-        return status;
+    zx_status_t ConfigWrite(uint16_t offset, size_t width, uint32_t value) {
+        return ops_->config_write(ctx_, offset, width, value);
     }
-
-    zx_status_t ConfigRead16(uint8_t offset, uint16_t *value) {
-        uint32_t val;
-        zx_status_t status = ConfigRead(offset, 16, &val);
-        *value = val & 0xffff;
-        return status;
-    }
-
     uint8_t GetNextCapability(uint8_t type, uint8_t offset) {
         return ops_->get_next_capability(ctx_, type, offset);
     }
-
-    uint8_t GetFirstCapability(uint8_t type) {
-        return GetNextCapability(kPciCfgCapabilitiesPtr - 1u, type);
+    zx_status_t GetAuxdata(const char* args, void* out_data_buffer, size_t data_size,
+                           size_t* out_data_actual) {
+        return ops_->get_auxdata(ctx_, args, out_data_buffer, data_size, out_data_actual);
+    }
+    zx_status_t GetBti(uint32_t index, zx_handle_t* out_bti) {
+        return ops_->get_bti(ctx_, index, out_bti);
     }
 
-  private:
+private:
     pci_protocol_ops_t* ops_;
     void* ctx_;
 };
 
-}  // namespace ddk
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/pciroot-internal.h b/system/ulib/ddktl/include/ddktl/protocol/pciroot-internal.h
new file mode 100644
index 0000000..ea96ab0
--- /dev/null
+++ b/system/ulib/ddktl/include/ddktl/protocol/pciroot-internal.h
@@ -0,0 +1,34 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: This file is machine generated by fidlc.
+
+#pragma once
+
+#include <ddk/protocol/pciroot.h>
+#include <fbl/type_support.h>
+
+namespace ddk {
+namespace internal {
+
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_pciroot_protocol_get_auxdata, PcirootGetAuxdata,
+                                     zx_status_t (C::*)(const char* args, void* out_data_buffer,
+                                                        size_t data_size, size_t* out_data_actual));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_pciroot_protocol_get_bti, PcirootGetBti,
+                                     zx_status_t (C::*)(uint32_t bdf, uint32_t index,
+                                                        zx_handle_t* out_bti));
+
+template <typename D>
+constexpr void CheckPcirootProtocolSubclass() {
+    static_assert(internal::has_pciroot_protocol_get_auxdata<D>::value,
+                  "PcirootProtocol subclasses must implement "
+                  "zx_status_t PcirootGetAuxdata(const char* args, void* out_data_buffer, size_t "
+                  "data_size, size_t* out_data_actual");
+    static_assert(internal::has_pciroot_protocol_get_bti<D>::value,
+                  "PcirootProtocol subclasses must implement "
+                  "zx_status_t PcirootGetBti(uint32_t bdf, uint32_t index, zx_handle_t* out_bti");
+}
+
+} // namespace internal
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/pciroot.h b/system/ulib/ddktl/include/ddktl/protocol/pciroot.h
new file mode 100644
index 0000000..bf97bd1
--- /dev/null
+++ b/system/ulib/ddktl/include/ddktl/protocol/pciroot.h
@@ -0,0 +1,102 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: This file is machine generated by fidlc.
+
+#pragma once
+
+#include <ddk/protocol/pciroot.h>
+#include <ddktl/device-internal.h>
+#include <zircon/assert.h>
+#include <zircon/compiler.h>
+#include <zircon/types.h>
+
+#include "pciroot-internal.h"
+
+// DDK pciroot-protocol support
+//
+// :: Proxies ::
+//
+// ddk::PcirootProtocolProxy is a simple wrapper around
+// pciroot_protocol_t. It does not own the pointers passed to it
+//
+// :: Mixins ::
+//
+// ddk::PcirootProtocol is a mixin class that simplifies writing DDK drivers
+// that implement the pciroot protocol. It doesn't set the base protocol.
+//
+// :: Examples ::
+//
+// // A driver that implements a ZX_PROTOCOL_PCIROOT device.
+// class PcirootDevice {
+// using PcirootDeviceType = ddk::Device<PcirootDevice, /* ddk mixins */>;
+//
+// class PcirootDevice : public PcirootDeviceType,
+//                       public ddk::PcirootProtocol<PcirootDevice> {
+//   public:
+//     PcirootDevice(zx_device_t* parent)
+//         : PcirootDeviceType("my-pciroot-protocol-device", parent) {}
+//
+//     zx_status_t PcirootGetAuxdata(const char* args, void* out_data_buffer, size_t data_size,
+//     size_t* out_data_actual);
+//
+//     zx_status_t PcirootGetBti(uint32_t bdf, uint32_t index, zx_handle_t* out_bti);
+//
+//     ...
+// };
+
+namespace ddk {
+
+template <typename D>
+class PcirootProtocol : public internal::base_mixin {
+public:
+    PcirootProtocol() {
+        internal::CheckPcirootProtocolSubclass<D>();
+        pciroot_protocol_ops_.get_auxdata = PcirootGetAuxdata;
+        pciroot_protocol_ops_.get_bti = PcirootGetBti;
+    }
+
+protected:
+    pciroot_protocol_ops_t pciroot_protocol_ops_ = {};
+
+private:
+    static zx_status_t PcirootGetAuxdata(void* ctx, const char* args, void* out_data_buffer,
+                                         size_t data_size, size_t* out_data_actual) {
+        return static_cast<D*>(ctx)->PcirootGetAuxdata(args, out_data_buffer, data_size,
+                                                       out_data_actual);
+    }
+    static zx_status_t PcirootGetBti(void* ctx, uint32_t bdf, uint32_t index,
+                                     zx_handle_t* out_bti) {
+        return static_cast<D*>(ctx)->PcirootGetBti(bdf, index, out_bti);
+    }
+};
+
+class PcirootProtocolProxy {
+public:
+    PcirootProtocolProxy() : ops_(nullptr), ctx_(nullptr) {}
+    PcirootProtocolProxy(const pciroot_protocol_t* proto) : ops_(proto->ops), ctx_(proto->ctx) {}
+
+    void GetProto(pciroot_protocol_t* proto) {
+        proto->ctx = ctx_;
+        proto->ops = ops_;
+    }
+    bool is_valid() { return ops_ != nullptr; }
+    void clear() {
+        ctx_ = nullptr;
+        ops_ = nullptr;
+    }
+    zx_status_t GetAuxdata(const char* args, void* out_data_buffer, size_t data_size,
+                           size_t* out_data_actual) {
+        return ops_->get_auxdata(ctx_, args, out_data_buffer, data_size, out_data_actual);
+    }
+    zx_status_t GetBti(uint32_t bdf, uint32_t index, zx_handle_t* out_bti) {
+        return ops_->get_bti(ctx_, bdf, index, out_bti);
+    }
+
+private:
+    pciroot_protocol_ops_t* ops_;
+    void* ctx_;
+};
+
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/rawnand-internal.h b/system/ulib/ddktl/include/ddktl/protocol/rawnand-internal.h
new file mode 100644
index 0000000..dd07e28
--- /dev/null
+++ b/system/ulib/ddktl/include/ddktl/protocol/rawnand-internal.h
@@ -0,0 +1,60 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: This file is machine generated by fidlc.
+
+#pragma once
+
+#include <ddk/protocol/rawnand.h>
+#include <fbl/type_support.h>
+
+namespace ddk {
+namespace internal {
+
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_raw_nand_protocol_read_page_hwecc, RawNandReadPageHwecc,
+                                     zx_status_t (C::*)(uint32_t nandpage, void* out_data_buffer,
+                                                        size_t data_size, size_t* out_data_actual,
+                                                        void* out_oob_buffer, size_t oob_size,
+                                                        size_t* out_oob_actual,
+                                                        zx_status_t* out_ecc_correct));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_raw_nand_protocol_write_page_hwecc, RawNandWritePageHwecc,
+                                     zx_status_t (C::*)(const void* data_buffer, size_t data_size,
+                                                        const void* oob_buffer, size_t oob_size,
+                                                        uint32_t nandpage));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_raw_nand_protocol_erase_block, RawNandEraseBlock,
+                                     zx_status_t (C::*)(uint32_t nandpage));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_raw_nand_protocol_get_nand_info, RawNandGetNandInfo,
+                                     zx_status_t (C::*)(nand_info_t* out_info));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_raw_nand_protocol_cmd_ctrl, RawNandCmdCtrl,
+                                     void (C::*)(zx_status_t cmd, uint32_t ctrl));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_raw_nand_protocol_read_byte, RawNandReadByte,
+                                     uint8_t (C::*)());
+
+template <typename D>
+constexpr void CheckRawNandProtocolSubclass() {
+    static_assert(internal::has_raw_nand_protocol_read_page_hwecc<D>::value,
+                  "RawNandProtocol subclasses must implement "
+                  "zx_status_t RawNandReadPageHwecc(uint32_t nandpage, void* out_data_buffer, "
+                  "size_t data_size, size_t* out_data_actual, void* out_oob_buffer, size_t "
+                  "oob_size, size_t* out_oob_actual, zx_status_t* out_ecc_correct");
+    static_assert(internal::has_raw_nand_protocol_write_page_hwecc<D>::value,
+                  "RawNandProtocol subclasses must implement "
+                  "zx_status_t RawNandWritePageHwecc(const void* data_buffer, size_t data_size, "
+                  "const void* oob_buffer, size_t oob_size, uint32_t nandpage");
+    static_assert(internal::has_raw_nand_protocol_erase_block<D>::value,
+                  "RawNandProtocol subclasses must implement "
+                  "zx_status_t RawNandEraseBlock(uint32_t nandpage");
+    static_assert(internal::has_raw_nand_protocol_get_nand_info<D>::value,
+                  "RawNandProtocol subclasses must implement "
+                  "zx_status_t RawNandGetNandInfo(nand_info_t* out_info");
+    static_assert(internal::has_raw_nand_protocol_cmd_ctrl<D>::value,
+                  "RawNandProtocol subclasses must implement "
+                  "void RawNandCmdCtrl(zx_status_t cmd, uint32_t ctrl");
+    static_assert(internal::has_raw_nand_protocol_read_byte<D>::value,
+                  "RawNandProtocol subclasses must implement "
+                  "uint8_t RawNandReadByte(");
+}
+
+} // namespace internal
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/rawnand.h b/system/ulib/ddktl/include/ddktl/protocol/rawnand.h
new file mode 100644
index 0000000..8455044
--- /dev/null
+++ b/system/ulib/ddktl/include/ddktl/protocol/rawnand.h
@@ -0,0 +1,149 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: This file is machine generated by fidlc.
+
+#pragma once
+
+#include <ddk/protocol/rawnand.h>
+#include <ddktl/device-internal.h>
+#include <zircon/assert.h>
+#include <zircon/compiler.h>
+#include <zircon/device/nand.h>
+#include <zircon/types.h>
+
+#include "rawnand-internal.h"
+
+// DDK raw-nand-protocol support
+//
+// :: Proxies ::
+//
+// ddk::RawNandProtocolProxy is a simple wrapper around
+// raw_nand_protocol_t. It does not own the pointers passed to it
+//
+// :: Mixins ::
+//
+// ddk::RawNandProtocol is a mixin class that simplifies writing DDK drivers
+// that implement the raw-nand protocol. It doesn't set the base protocol.
+//
+// :: Examples ::
+//
+// // A driver that implements a ZX_PROTOCOL_RAW_NAND device.
+// class RawNandDevice {
+// using RawNandDeviceType = ddk::Device<RawNandDevice, /* ddk mixins */>;
+//
+// class RawNandDevice : public RawNandDeviceType,
+//                       public ddk::RawNandProtocol<RawNandDevice> {
+//   public:
+//     RawNandDevice(zx_device_t* parent)
+//         : RawNandDeviceType("my-raw-nand-protocol-device", parent) {}
+//
+//     zx_status_t RawNandReadPageHwecc(uint32_t nandpage, void* out_data_buffer, size_t data_size,
+//     size_t* out_data_actual, void* out_oob_buffer, size_t oob_size, size_t* out_oob_actual,
+//     zx_status_t* out_ecc_correct);
+//
+//     zx_status_t RawNandWritePageHwecc(const void* data_buffer, size_t data_size, const void*
+//     oob_buffer, size_t oob_size, uint32_t nandpage);
+//
+//     zx_status_t RawNandEraseBlock(uint32_t nandpage);
+//
+//     zx_status_t RawNandGetNandInfo(nand_info_t* out_info);
+//
+//     void RawNandCmdCtrl(zx_status_t cmd, uint32_t ctrl);
+//
+//     uint8_t RawNandReadByte();
+//
+//     ...
+// };
+
+namespace ddk {
+
+template <typename D>
+class RawNandProtocol : public internal::base_mixin {
+public:
+    RawNandProtocol() {
+        internal::CheckRawNandProtocolSubclass<D>();
+        raw_nand_protocol_ops_.read_page_hwecc = RawNandReadPageHwecc;
+        raw_nand_protocol_ops_.write_page_hwecc = RawNandWritePageHwecc;
+        raw_nand_protocol_ops_.erase_block = RawNandEraseBlock;
+        raw_nand_protocol_ops_.get_nand_info = RawNandGetNandInfo;
+        raw_nand_protocol_ops_.cmd_ctrl = RawNandCmdCtrl;
+        raw_nand_protocol_ops_.read_byte = RawNandReadByte;
+    }
+
+protected:
+    raw_nand_protocol_ops_t raw_nand_protocol_ops_ = {};
+
+private:
+    // Read one nand page with hwecc.
+    static zx_status_t RawNandReadPageHwecc(void* ctx, uint32_t nandpage, void* out_data_buffer,
+                                            size_t data_size, size_t* out_data_actual,
+                                            void* out_oob_buffer, size_t oob_size,
+                                            size_t* out_oob_actual, zx_status_t* out_ecc_correct) {
+        return static_cast<D*>(ctx)->RawNandReadPageHwecc(nandpage, out_data_buffer, data_size,
+                                                          out_data_actual, out_oob_buffer, oob_size,
+                                                          out_oob_actual, out_ecc_correct);
+    }
+    // Write one nand page with hwecc.
+    static zx_status_t RawNandWritePageHwecc(void* ctx, const void* data_buffer, size_t data_size,
+                                             const void* oob_buffer, size_t oob_size,
+                                             uint32_t nandpage) {
+        return static_cast<D*>(ctx)->RawNandWritePageHwecc(data_buffer, data_size, oob_buffer,
+                                                           oob_size, nandpage);
+    }
+    // Erase nand block.
+    static zx_status_t RawNandEraseBlock(void* ctx, uint32_t nandpage) {
+        return static_cast<D*>(ctx)->RawNandEraseBlock(nandpage);
+    }
+    static zx_status_t RawNandGetNandInfo(void* ctx, nand_info_t* out_info) {
+        return static_cast<D*>(ctx)->RawNandGetNandInfo(out_info);
+    }
+    // Send ONFI command down to controller.
+    static void RawNandCmdCtrl(void* ctx, zx_status_t cmd, uint32_t ctrl) {
+        static_cast<D*>(ctx)->RawNandCmdCtrl(cmd, ctrl);
+    }
+    // Read byte (used to read status as well as other info, such as ID).
+    static uint8_t RawNandReadByte(void* ctx) { return static_cast<D*>(ctx)->RawNandReadByte(); }
+};
+
+class RawNandProtocolProxy {
+public:
+    RawNandProtocolProxy() : ops_(nullptr), ctx_(nullptr) {}
+    RawNandProtocolProxy(const raw_nand_protocol_t* proto) : ops_(proto->ops), ctx_(proto->ctx) {}
+
+    void GetProto(raw_nand_protocol_t* proto) {
+        proto->ctx = ctx_;
+        proto->ops = ops_;
+    }
+    bool is_valid() { return ops_ != nullptr; }
+    void clear() {
+        ctx_ = nullptr;
+        ops_ = nullptr;
+    }
+    // Read one nand page with hwecc.
+    zx_status_t ReadPageHwecc(uint32_t nandpage, void* out_data_buffer, size_t data_size,
+                              size_t* out_data_actual, void* out_oob_buffer, size_t oob_size,
+                              size_t* out_oob_actual, zx_status_t* out_ecc_correct) {
+        return ops_->read_page_hwecc(ctx_, nandpage, out_data_buffer, data_size, out_data_actual,
+                                     out_oob_buffer, oob_size, out_oob_actual, out_ecc_correct);
+    }
+    // Write one nand page with hwecc.
+    zx_status_t WritePageHwecc(const void* data_buffer, size_t data_size, const void* oob_buffer,
+                               size_t oob_size, uint32_t nandpage) {
+        return ops_->write_page_hwecc(ctx_, data_buffer, data_size, oob_buffer, oob_size, nandpage);
+    }
+    // Erase nand block.
+    zx_status_t EraseBlock(uint32_t nandpage) { return ops_->erase_block(ctx_, nandpage); }
+    zx_status_t GetNandInfo(nand_info_t* out_info) { return ops_->get_nand_info(ctx_, out_info); }
+    // Send ONFI command down to controller.
+    void CmdCtrl(zx_status_t cmd, uint32_t ctrl) { ops_->cmd_ctrl(ctx_, cmd, ctrl); }
+    // Read byte (used to read status as well as other info, such as ID).
+    uint8_t ReadByte() { return ops_->read_byte(ctx_); }
+
+private:
+    raw_nand_protocol_ops_t* ops_;
+    void* ctx_;
+};
+
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/scpi-internal.h b/system/ulib/ddktl/include/ddktl/protocol/scpi-internal.h
index c44f04a..0cbd632 100644
--- a/system/ulib/ddktl/include/ddktl/protocol/scpi-internal.h
+++ b/system/ulib/ddktl/include/ddktl/protocol/scpi-internal.h
@@ -2,42 +2,47 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
+#include <ddk/protocol/scpi.h>
 #include <fbl/type_support.h>
 
 namespace ddk {
 namespace internal {
 
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_scpi_get_sensor, ScpiGetSensor,
-        zx_status_t (C::*)(const char*, uint32_t*));
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_scpi_get_sensor_value, ScpiGetSensorValue,
-        zx_status_t (C::*)(uint32_t, uint32_t*));
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_scpi_get_dvfs_info, ScpiGetDvfsInfo,
-        zx_status_t (C::*)(uint8_t, scpi_opp_t*));
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_scpi_get_dvfs_idx, ScpiGetDvfsIdx,
-        zx_status_t (C::*)(uint8_t, uint16_t*));
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_scpi_set_dvfs_idx, ScpiSetDvfsIdx,
-        zx_status_t (C::*)(uint8_t, uint16_t));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_scpi_protocol_get_sensor, ScpiGetSensor,
+                                     zx_status_t (C::*)(const char* name, uint32_t* out_sensor_id));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_scpi_protocol_get_sensor_value, ScpiGetSensorValue,
+                                     zx_status_t (C::*)(uint32_t sensor_id,
+                                                        uint32_t* out_sensor_value));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_scpi_protocol_get_dvfs_info, ScpiGetDvfsInfo,
+                                     zx_status_t (C::*)(uint8_t power_domain,
+                                                        scpi_opp_t* out_opps));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_scpi_protocol_get_dvfs_idx, ScpiGetDvfsIdx,
+                                     zx_status_t (C::*)(uint8_t power_domain, uint16_t* out_index));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_scpi_protocol_set_dvfs_idx, ScpiSetDvfsIdx,
+                                     zx_status_t (C::*)(uint8_t power_domain, uint16_t index));
 
 template <typename D>
 constexpr void CheckScpiProtocolSubclass() {
-    static_assert(internal::has_scpi_get_sensor<D>::value,
+    static_assert(internal::has_scpi_protocol_get_sensor<D>::value,
                   "ScpiProtocol subclasses must implement "
-                  "ScpiGetSensor(const char* name, uint32_t* sensor_id)");
-    static_assert(internal::has_scpi_get_sensor_value<D>::value,
+                  "zx_status_t ScpiGetSensor(const char* name, uint32_t* out_sensor_id");
+    static_assert(internal::has_scpi_protocol_get_sensor_value<D>::value,
                   "ScpiProtocol subclasses must implement "
-                  "ScpiGetSensorValue(uint32_t sensor_id, uint32_t* sensor_value)");
-    static_assert(internal::has_scpi_get_dvfs_info<D>::value,
+                  "zx_status_t ScpiGetSensorValue(uint32_t sensor_id, uint32_t* out_sensor_value");
+    static_assert(internal::has_scpi_protocol_get_dvfs_info<D>::value,
                   "ScpiProtocol subclasses must implement "
-                  "ScpiGetDvfsInfo(uint8_t power_domain, scpi_opp_t* opps)");
-    static_assert(internal::has_scpi_get_dvfs_idx<D>::value,
+                  "zx_status_t ScpiGetDvfsInfo(uint8_t power_domain, scpi_opp_t* out_opps");
+    static_assert(internal::has_scpi_protocol_get_dvfs_idx<D>::value,
                   "ScpiProtocol subclasses must implement "
-                  "ScpiGetDvfsIdx(uint8_t power_domain, uint16_t* idx)");
-    static_assert(internal::has_scpi_set_dvfs_idx<D>::value,
+                  "zx_status_t ScpiGetDvfsIdx(uint8_t power_domain, uint16_t* out_index");
+    static_assert(internal::has_scpi_protocol_set_dvfs_idx<D>::value,
                   "ScpiProtocol subclasses must implement "
-                  "ScpiSetDvfsIdx(uint8_t power_domain, uint16_t idx)");
- }
+                  "zx_status_t ScpiSetDvfsIdx(uint8_t power_domain, uint16_t index");
+}
 
-}  // namespace internal
-}  // namespace ddk
+} // namespace internal
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/scpi.h b/system/ulib/ddktl/include/ddktl/protocol/scpi.h
index 13d6e23..b89cbe7 100644
--- a/system/ulib/ddktl/include/ddktl/protocol/scpi.h
+++ b/system/ulib/ddktl/include/ddktl/protocol/scpi.h
@@ -2,107 +2,121 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
 #include <ddk/protocol/scpi.h>
 #include <ddktl/device-internal.h>
 #include <zircon/assert.h>
+#include <zircon/compiler.h>
+#include <zircon/types.h>
 
 #include "scpi-internal.h"
 
-// DDK SCPI protocol support.
+// DDK scpi-protocol support
 //
 // :: Proxies ::
 //
-// ddk::ScpiProtocolProxy is a simple wrappers around scpi_protocol_t. It does
-// not own the pointers passed to it.
+// ddk::ScpiProtocolProxy is a simple wrapper around
+// scpi_protocol_t. It does not own the pointers passed to it
 //
 // :: Mixins ::
 //
-// ddk::ScpiProtocol is a mixin class that simplifies writing DDK drivers that
-// implement the SCPI protocol.
+// ddk::ScpiProtocol is a mixin class that simplifies writing DDK drivers
+// that implement the scpi protocol. It doesn't set the base protocol.
 //
 // :: Examples ::
 //
 // // A driver that implements a ZX_PROTOCOL_SCPI device.
-// class ScpiDevice;
+// class ScpiDevice {
 // using ScpiDeviceType = ddk::Device<ScpiDevice, /* ddk mixins */>;
 //
 // class ScpiDevice : public ScpiDeviceType,
 //                    public ddk::ScpiProtocol<ScpiDevice> {
 //   public:
 //     ScpiDevice(zx_device_t* parent)
-//       : ScpiDeviceType("my-scpi-device", parent) {}
+//         : ScpiDeviceType("my-scpi-protocol-device", parent) {}
 //
-//    zx_status_t ScpiGetSensor(const char* name, uint32_t* sensor_id);
-//    zx_status_t ScpiGetSensorValue(uint32_t sensor_id, uint32_t* sensor_value);
-//    zx_status_t ScpiGetDvfsInfo(uint8_t power_domain, scpi_opp_t* opps);
-//    zx_status_t ScpiGetDvfsIdx(uint8_t power_domain, uint16_t* idx);
-//    zx_status_t ScpiSetDvfsIdx(uint8_t power_domain, uint16_t idx);
+//     zx_status_t ScpiGetSensor(const char* name, uint32_t* out_sensor_id);
+//
+//     zx_status_t ScpiGetSensorValue(uint32_t sensor_id, uint32_t* out_sensor_value);
+//
+//     zx_status_t ScpiGetDvfsInfo(uint8_t power_domain, scpi_opp_t* out_opps);
+//
+//     zx_status_t ScpiGetDvfsIdx(uint8_t power_domain, uint16_t* out_index);
+//
+//     zx_status_t ScpiSetDvfsIdx(uint8_t power_domain, uint16_t index);
+//
 //     ...
 // };
 
 namespace ddk {
 
 template <typename D>
-class ScpiProtocol {
+class ScpiProtocol : public internal::base_mixin {
 public:
     ScpiProtocol() {
         internal::CheckScpiProtocolSubclass<D>();
-        scpi_proto_ops_.get_sensor = ScpiGetSensor;
-        scpi_proto_ops_.get_sensor_value = ScpiGetSensorValue;
-        scpi_proto_ops_.get_dvfs_info = ScpiGetDvfsInfo;
-        scpi_proto_ops_.get_dvfs_idx = ScpiGetDvfsIdx;
-        scpi_proto_ops_.set_dvfs_idx = ScpiSetDvfsIdx;
+        scpi_protocol_ops_.get_sensor = ScpiGetSensor;
+        scpi_protocol_ops_.get_sensor_value = ScpiGetSensorValue;
+        scpi_protocol_ops_.get_dvfs_info = ScpiGetDvfsInfo;
+        scpi_protocol_ops_.get_dvfs_idx = ScpiGetDvfsIdx;
+        scpi_protocol_ops_.set_dvfs_idx = ScpiSetDvfsIdx;
     }
 
 protected:
-    scpi_protocol_ops_t scpi_proto_ops_ = {};
+    scpi_protocol_ops_t scpi_protocol_ops_ = {};
 
 private:
-    static zx_status_t ScpiGetSensor(void* ctx, const char* name, uint32_t* sensor_id) {
-        return static_cast<D*>(ctx)->ScpiGetSensor(name, sensor_id);
+    static zx_status_t ScpiGetSensor(void* ctx, const char* name, uint32_t* out_sensor_id) {
+        return static_cast<D*>(ctx)->ScpiGetSensor(name, out_sensor_id);
     }
-    static zx_status_t ScpiGetSensorValue(void* ctx, uint32_t sensor_id, uint32_t* sensor_value) {
-        return static_cast<D*>(ctx)->ScpiGetSensorValue(sensor_id, sensor_value);
+    static zx_status_t ScpiGetSensorValue(void* ctx, uint32_t sensor_id,
+                                          uint32_t* out_sensor_value) {
+        return static_cast<D*>(ctx)->ScpiGetSensorValue(sensor_id, out_sensor_value);
     }
-    static zx_status_t ScpiGetDvfsInfo(void* ctx, uint8_t power_domain, scpi_opp_t* opps) {
-        return static_cast<D*>(ctx)->ScpiGetDvfsInfo(power_domain, opps);
+    static zx_status_t ScpiGetDvfsInfo(void* ctx, uint8_t power_domain, scpi_opp_t* out_opps) {
+        return static_cast<D*>(ctx)->ScpiGetDvfsInfo(power_domain, out_opps);
     }
-    static zx_status_t ScpiGetDvfsIdx(void* ctx, uint8_t power_domain, uint16_t* idx) {
-        return static_cast<D*>(ctx)->ScpiGetDvfsIdx(power_domain, idx);
+    static zx_status_t ScpiGetDvfsIdx(void* ctx, uint8_t power_domain, uint16_t* out_index) {
+        return static_cast<D*>(ctx)->ScpiGetDvfsIdx(power_domain, out_index);
     }
-    static zx_status_t ScpiSetDvfsIdx(void* ctx, uint8_t power_domain, uint16_t idx) {
-        return static_cast<D*>(ctx)->ScpiSetDvfsIdx(power_domain, idx);
+    static zx_status_t ScpiSetDvfsIdx(void* ctx, uint8_t power_domain, uint16_t index) {
+        return static_cast<D*>(ctx)->ScpiSetDvfsIdx(power_domain, index);
     }
 };
 
 class ScpiProtocolProxy {
 public:
-    ScpiProtocolProxy(scpi_protocol_t* proto)
-        : ops_(proto->ops), ctx_(proto->ctx) {}
+    ScpiProtocolProxy() : ops_(nullptr), ctx_(nullptr) {}
+    ScpiProtocolProxy(const scpi_protocol_t* proto) : ops_(proto->ops), ctx_(proto->ctx) {}
 
     void GetProto(scpi_protocol_t* proto) {
         proto->ctx = ctx_;
         proto->ops = ops_;
     }
+    bool is_valid() { return ops_ != nullptr; }
+    void clear() {
+        ctx_ = nullptr;
+        ops_ = nullptr;
+    }
+    zx_status_t GetSensor(const char* name, uint32_t* out_sensor_id) {
+        return ops_->get_sensor(ctx_, name, out_sensor_id);
+    }
+    zx_status_t GetSensorValue(uint32_t sensor_id, uint32_t* out_sensor_value) {
+        return ops_->get_sensor_value(ctx_, sensor_id, out_sensor_value);
+    }
+    zx_status_t GetDvfsInfo(uint8_t power_domain, scpi_opp_t* out_opps) {
+        return ops_->get_dvfs_info(ctx_, power_domain, out_opps);
+    }
+    zx_status_t GetDvfsIdx(uint8_t power_domain, uint16_t* out_index) {
+        return ops_->get_dvfs_idx(ctx_, power_domain, out_index);
+    }
+    zx_status_t SetDvfsIdx(uint8_t power_domain, uint16_t index) {
+        return ops_->set_dvfs_idx(ctx_, power_domain, index);
+    }
 
-    zx_status_t GetSensor(const char* name, uint32_t* sensor_id) {
-        return ops_->get_sensor(ctx_, name, sensor_id);
-    }
-    zx_status_t GetSensorValue(uint32_t sensor_id, uint32_t* sensor_value) {
-        return ops_->get_sensor_value(ctx_, sensor_id, sensor_value);
-    }
-    zx_status_t GetDvfsInfo(uint8_t power_domain, scpi_opp_t* opps) {
-        return ops_->get_dvfs_info(ctx_, power_domain, opps);
-    }
-    zx_status_t GetDvfsIdx(uint8_t power_domain, uint16_t* idx) {
-        return ops_->get_dvfs_idx(ctx_, power_domain, idx);
-    }
-    zx_status_t SetDvfsIdx(uint8_t power_domain, uint16_t idx) {
-        return ops_->set_dvfs_idx(ctx_, power_domain, idx);
-    }
-\
 private:
     scpi_protocol_ops_t* ops_;
     void* ctx_;
diff --git a/system/ulib/ddktl/include/ddktl/protocol/sdhci-internal.h b/system/ulib/ddktl/include/ddktl/protocol/sdhci-internal.h
new file mode 100644
index 0000000..f54dac9
--- /dev/null
+++ b/system/ulib/ddktl/include/ddktl/protocol/sdhci-internal.h
@@ -0,0 +1,50 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: This file is machine generated by fidlc.
+
+#pragma once
+
+#include <ddk/protocol/sdhci.h>
+#include <fbl/type_support.h>
+
+namespace ddk {
+namespace internal {
+
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_sdhci_protocol_get_interrupt, SdhciGetInterrupt,
+                                     zx_status_t (C::*)(zx_handle_t* out_irq));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_sdhci_protocol_get_mmio, SdhciGetMmio,
+                                     zx_status_t (C::*)(zx_handle_t* out_mmio));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_sdhci_protocol_get_bti, SdhciGetBti,
+                                     zx_status_t (C::*)(uint32_t index, zx_handle_t* out_bti));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_sdhci_protocol_get_base_clock, SdhciGetBaseClock,
+                                     uint32_t (C::*)());
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_sdhci_protocol_get_quirks, SdhciGetQuirks,
+                                     uint64_t (C::*)());
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_sdhci_protocol_hw_reset, SdhciHwReset, void (C::*)());
+
+template <typename D>
+constexpr void CheckSdhciProtocolSubclass() {
+    static_assert(internal::has_sdhci_protocol_get_interrupt<D>::value,
+                  "SdhciProtocol subclasses must implement "
+                  "zx_status_t SdhciGetInterrupt(zx_handle_t* out_irq");
+    static_assert(internal::has_sdhci_protocol_get_mmio<D>::value,
+                  "SdhciProtocol subclasses must implement "
+                  "zx_status_t SdhciGetMmio(zx_handle_t* out_mmio");
+    static_assert(internal::has_sdhci_protocol_get_bti<D>::value,
+                  "SdhciProtocol subclasses must implement "
+                  "zx_status_t SdhciGetBti(uint32_t index, zx_handle_t* out_bti");
+    static_assert(internal::has_sdhci_protocol_get_base_clock<D>::value,
+                  "SdhciProtocol subclasses must implement "
+                  "uint32_t SdhciGetBaseClock(");
+    static_assert(internal::has_sdhci_protocol_get_quirks<D>::value,
+                  "SdhciProtocol subclasses must implement "
+                  "uint64_t SdhciGetQuirks(");
+    static_assert(internal::has_sdhci_protocol_hw_reset<D>::value,
+                  "SdhciProtocol subclasses must implement "
+                  "void SdhciHwReset(");
+}
+
+} // namespace internal
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/sdhci.h b/system/ulib/ddktl/include/ddktl/protocol/sdhci.h
new file mode 100644
index 0000000..fd03b50
--- /dev/null
+++ b/system/ulib/ddktl/include/ddktl/protocol/sdhci.h
@@ -0,0 +1,128 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: This file is machine generated by fidlc.
+
+#pragma once
+
+#include <ddk/protocol/sdhci.h>
+#include <ddktl/device-internal.h>
+#include <hw/sdhci.h>
+#include <zircon/assert.h>
+#include <zircon/compiler.h>
+#include <zircon/types.h>
+
+#include "sdhci-internal.h"
+
+// DDK sdhci-protocol support
+//
+// :: Proxies ::
+//
+// ddk::SdhciProtocolProxy is a simple wrapper around
+// sdhci_protocol_t. It does not own the pointers passed to it
+//
+// :: Mixins ::
+//
+// ddk::SdhciProtocol is a mixin class that simplifies writing DDK drivers
+// that implement the sdhci protocol. It doesn't set the base protocol.
+//
+// :: Examples ::
+//
+// // A driver that implements a ZX_PROTOCOL_SDHCI device.
+// class SdhciDevice {
+// using SdhciDeviceType = ddk::Device<SdhciDevice, /* ddk mixins */>;
+//
+// class SdhciDevice : public SdhciDeviceType,
+//                     public ddk::SdhciProtocol<SdhciDevice> {
+//   public:
+//     SdhciDevice(zx_device_t* parent)
+//         : SdhciDeviceType("my-sdhci-protocol-device", parent) {}
+//
+//     zx_status_t SdhciGetInterrupt(zx_handle_t* out_irq);
+//
+//     zx_status_t SdhciGetMmio(zx_handle_t* out_mmio);
+//
+//     zx_status_t SdhciGetBti(uint32_t index, zx_handle_t* out_bti);
+//
+//     uint32_t SdhciGetBaseClock();
+//
+//     uint64_t SdhciGetQuirks();
+//
+//     void SdhciHwReset();
+//
+//     ...
+// };
+
+namespace ddk {
+
+template <typename D>
+class SdhciProtocol : public internal::base_mixin {
+public:
+    SdhciProtocol() {
+        internal::CheckSdhciProtocolSubclass<D>();
+        sdhci_protocol_ops_.get_interrupt = SdhciGetInterrupt;
+        sdhci_protocol_ops_.get_mmio = SdhciGetMmio;
+        sdhci_protocol_ops_.get_bti = SdhciGetBti;
+        sdhci_protocol_ops_.get_base_clock = SdhciGetBaseClock;
+        sdhci_protocol_ops_.get_quirks = SdhciGetQuirks;
+        sdhci_protocol_ops_.hw_reset = SdhciHwReset;
+    }
+
+protected:
+    sdhci_protocol_ops_t sdhci_protocol_ops_ = {};
+
+private:
+    static zx_status_t SdhciGetInterrupt(void* ctx, zx_handle_t* out_irq) {
+        return static_cast<D*>(ctx)->SdhciGetInterrupt(out_irq);
+    }
+    static zx_status_t SdhciGetMmio(void* ctx, zx_handle_t* out_mmio) {
+        return static_cast<D*>(ctx)->SdhciGetMmio(out_mmio);
+    }
+    // Gets a handle to the bus transaction initiator for the device. The caller
+    // receives ownership of the handle.
+    static zx_status_t SdhciGetBti(void* ctx, uint32_t index, zx_handle_t* out_bti) {
+        return static_cast<D*>(ctx)->SdhciGetBti(index, out_bti);
+    }
+    static uint32_t SdhciGetBaseClock(void* ctx) {
+        return static_cast<D*>(ctx)->SdhciGetBaseClock();
+    }
+    // returns device quirks
+    static uint64_t SdhciGetQuirks(void* ctx) { return static_cast<D*>(ctx)->SdhciGetQuirks(); }
+    // platform specific HW reset
+    static void SdhciHwReset(void* ctx) { static_cast<D*>(ctx)->SdhciHwReset(); }
+};
+
+class SdhciProtocolProxy {
+public:
+    SdhciProtocolProxy() : ops_(nullptr), ctx_(nullptr) {}
+    SdhciProtocolProxy(const sdhci_protocol_t* proto) : ops_(proto->ops), ctx_(proto->ctx) {}
+
+    void GetProto(sdhci_protocol_t* proto) {
+        proto->ctx = ctx_;
+        proto->ops = ops_;
+    }
+    bool is_valid() { return ops_ != nullptr; }
+    void clear() {
+        ctx_ = nullptr;
+        ops_ = nullptr;
+    }
+    zx_status_t GetInterrupt(zx_handle_t* out_irq) { return ops_->get_interrupt(ctx_, out_irq); }
+    zx_status_t GetMmio(zx_handle_t* out_mmio) { return ops_->get_mmio(ctx_, out_mmio); }
+    // Gets a handle to the bus transaction initiator for the device. The caller
+    // receives ownership of the handle.
+    zx_status_t GetBti(uint32_t index, zx_handle_t* out_bti) {
+        return ops_->get_bti(ctx_, index, out_bti);
+    }
+    uint32_t GetBaseClock() { return ops_->get_base_clock(ctx_); }
+    // returns device quirks
+    uint64_t GetQuirks() { return ops_->get_quirks(ctx_); }
+    // platform specific HW reset
+    void HwReset() { ops_->hw_reset(ctx_); }
+
+private:
+    sdhci_protocol_ops_t* ops_;
+    void* ctx_;
+};
+
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/sdio-internal.h b/system/ulib/ddktl/include/ddktl/protocol/sdio-internal.h
new file mode 100644
index 0000000..3c78159
--- /dev/null
+++ b/system/ulib/ddktl/include/ddktl/protocol/sdio-internal.h
@@ -0,0 +1,63 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: This file is machine generated by fidlc.
+
+#pragma once
+
+#include <ddk/protocol/sdio.h>
+#include <fbl/type_support.h>
+
+namespace ddk {
+namespace internal {
+
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_sdio_protocol_get_dev_hw_info, SdioGetDevHwInfo,
+                                     zx_status_t (C::*)(sdio_hw_info_t* out_hw_info));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_sdio_protocol_enable_fn, SdioEnableFn,
+                                     zx_status_t (C::*)(uint8_t fn_idx));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_sdio_protocol_disable_fn, SdioDisableFn,
+                                     zx_status_t (C::*)(uint8_t fn_idx));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_sdio_protocol_enable_fn_intr, SdioEnableFnIntr,
+                                     zx_status_t (C::*)(uint8_t fn_idx));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_sdio_protocol_disable_fn_intr, SdioDisableFnIntr,
+                                     zx_status_t (C::*)(uint8_t fn_idx));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_sdio_protocol_update_block_size, SdioUpdateBlockSize,
+                                     zx_status_t (C::*)(uint8_t fn_idx, uint16_t blk_sz,
+                                                        bool deflt));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_sdio_protocol_get_block_size, SdioGetBlockSize,
+                                     zx_status_t (C::*)(uint8_t fn_idx,
+                                                        uint16_t* out_cur_blk_size));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_sdio_protocol_do_rw_txn, SdioDoRwTxn,
+                                     zx_status_t (C::*)(uint8_t fn_idx, sdio_rw_txn_t* txn));
+
+template <typename D>
+constexpr void CheckSdioProtocolSubclass() {
+    static_assert(internal::has_sdio_protocol_get_dev_hw_info<D>::value,
+                  "SdioProtocol subclasses must implement "
+                  "zx_status_t SdioGetDevHwInfo(sdio_hw_info_t* out_hw_info");
+    static_assert(internal::has_sdio_protocol_enable_fn<D>::value,
+                  "SdioProtocol subclasses must implement "
+                  "zx_status_t SdioEnableFn(uint8_t fn_idx");
+    static_assert(internal::has_sdio_protocol_disable_fn<D>::value,
+                  "SdioProtocol subclasses must implement "
+                  "zx_status_t SdioDisableFn(uint8_t fn_idx");
+    static_assert(internal::has_sdio_protocol_enable_fn_intr<D>::value,
+                  "SdioProtocol subclasses must implement "
+                  "zx_status_t SdioEnableFnIntr(uint8_t fn_idx");
+    static_assert(internal::has_sdio_protocol_disable_fn_intr<D>::value,
+                  "SdioProtocol subclasses must implement "
+                  "zx_status_t SdioDisableFnIntr(uint8_t fn_idx");
+    static_assert(internal::has_sdio_protocol_update_block_size<D>::value,
+                  "SdioProtocol subclasses must implement "
+                  "zx_status_t SdioUpdateBlockSize(uint8_t fn_idx, uint16_t blk_sz, bool deflt");
+    static_assert(internal::has_sdio_protocol_get_block_size<D>::value,
+                  "SdioProtocol subclasses must implement "
+                  "zx_status_t SdioGetBlockSize(uint8_t fn_idx, uint16_t* out_cur_blk_size");
+    static_assert(internal::has_sdio_protocol_do_rw_txn<D>::value,
+                  "SdioProtocol subclasses must implement "
+                  "zx_status_t SdioDoRwTxn(uint8_t fn_idx, sdio_rw_txn_t* txn");
+}
+
+} // namespace internal
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/sdio.h b/system/ulib/ddktl/include/ddktl/protocol/sdio.h
new file mode 100644
index 0000000..bfcb348
--- /dev/null
+++ b/system/ulib/ddktl/include/ddktl/protocol/sdio.h
@@ -0,0 +1,143 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: This file is machine generated by fidlc.
+
+#pragma once
+
+#include <ddk/protocol/sdio.h>
+#include <ddktl/device-internal.h>
+#include <zircon/assert.h>
+#include <zircon/compiler.h>
+#include <zircon/types.h>
+
+#include "sdio-internal.h"
+
+// DDK sdio-protocol support
+//
+// :: Proxies ::
+//
+// ddk::SdioProtocolProxy is a simple wrapper around
+// sdio_protocol_t. It does not own the pointers passed to it
+//
+// :: Mixins ::
+//
+// ddk::SdioProtocol is a mixin class that simplifies writing DDK drivers
+// that implement the sdio protocol. It doesn't set the base protocol.
+//
+// :: Examples ::
+//
+// // A driver that implements a ZX_PROTOCOL_SDIO device.
+// class SdioDevice {
+// using SdioDeviceType = ddk::Device<SdioDevice, /* ddk mixins */>;
+//
+// class SdioDevice : public SdioDeviceType,
+//                    public ddk::SdioProtocol<SdioDevice> {
+//   public:
+//     SdioDevice(zx_device_t* parent)
+//         : SdioDeviceType("my-sdio-protocol-device", parent) {}
+//
+//     zx_status_t SdioGetDevHwInfo(sdio_hw_info_t* out_hw_info);
+//
+//     zx_status_t SdioEnableFn(uint8_t fn_idx);
+//
+//     zx_status_t SdioDisableFn(uint8_t fn_idx);
+//
+//     zx_status_t SdioEnableFnIntr(uint8_t fn_idx);
+//
+//     zx_status_t SdioDisableFnIntr(uint8_t fn_idx);
+//
+//     zx_status_t SdioUpdateBlockSize(uint8_t fn_idx, uint16_t blk_sz, bool deflt);
+//
+//     zx_status_t SdioGetBlockSize(uint8_t fn_idx, uint16_t* out_cur_blk_size);
+//
+//     zx_status_t SdioDoRwTxn(uint8_t fn_idx, sdio_rw_txn_t* txn);
+//
+//     ...
+// };
+
+namespace ddk {
+
+template <typename D>
+class SdioProtocol : public internal::base_mixin {
+public:
+    SdioProtocol() {
+        internal::CheckSdioProtocolSubclass<D>();
+        sdio_protocol_ops_.get_dev_hw_info = SdioGetDevHwInfo;
+        sdio_protocol_ops_.enable_fn = SdioEnableFn;
+        sdio_protocol_ops_.disable_fn = SdioDisableFn;
+        sdio_protocol_ops_.enable_fn_intr = SdioEnableFnIntr;
+        sdio_protocol_ops_.disable_fn_intr = SdioDisableFnIntr;
+        sdio_protocol_ops_.update_block_size = SdioUpdateBlockSize;
+        sdio_protocol_ops_.get_block_size = SdioGetBlockSize;
+        sdio_protocol_ops_.do_rw_txn = SdioDoRwTxn;
+    }
+
+protected:
+    sdio_protocol_ops_t sdio_protocol_ops_ = {};
+
+private:
+    static zx_status_t SdioGetDevHwInfo(void* ctx, sdio_hw_info_t* out_hw_info) {
+        return static_cast<D*>(ctx)->SdioGetDevHwInfo(out_hw_info);
+    }
+    static zx_status_t SdioEnableFn(void* ctx, uint8_t fn_idx) {
+        return static_cast<D*>(ctx)->SdioEnableFn(fn_idx);
+    }
+    static zx_status_t SdioDisableFn(void* ctx, uint8_t fn_idx) {
+        return static_cast<D*>(ctx)->SdioDisableFn(fn_idx);
+    }
+    static zx_status_t SdioEnableFnIntr(void* ctx, uint8_t fn_idx) {
+        return static_cast<D*>(ctx)->SdioEnableFnIntr(fn_idx);
+    }
+    static zx_status_t SdioDisableFnIntr(void* ctx, uint8_t fn_idx) {
+        return static_cast<D*>(ctx)->SdioDisableFnIntr(fn_idx);
+    }
+    static zx_status_t SdioUpdateBlockSize(void* ctx, uint8_t fn_idx, uint16_t blk_sz, bool deflt) {
+        return static_cast<D*>(ctx)->SdioUpdateBlockSize(fn_idx, blk_sz, deflt);
+    }
+    static zx_status_t SdioGetBlockSize(void* ctx, uint8_t fn_idx, uint16_t* out_cur_blk_size) {
+        return static_cast<D*>(ctx)->SdioGetBlockSize(fn_idx, out_cur_blk_size);
+    }
+    static zx_status_t SdioDoRwTxn(void* ctx, uint8_t fn_idx, sdio_rw_txn_t* txn) {
+        return static_cast<D*>(ctx)->SdioDoRwTxn(fn_idx, txn);
+    }
+};
+
+class SdioProtocolProxy {
+public:
+    SdioProtocolProxy() : ops_(nullptr), ctx_(nullptr) {}
+    SdioProtocolProxy(const sdio_protocol_t* proto) : ops_(proto->ops), ctx_(proto->ctx) {}
+
+    void GetProto(sdio_protocol_t* proto) {
+        proto->ctx = ctx_;
+        proto->ops = ops_;
+    }
+    bool is_valid() { return ops_ != nullptr; }
+    void clear() {
+        ctx_ = nullptr;
+        ops_ = nullptr;
+    }
+    zx_status_t GetDevHwInfo(sdio_hw_info_t* out_hw_info) {
+        return ops_->get_dev_hw_info(ctx_, out_hw_info);
+    }
+    zx_status_t EnableFn(uint8_t fn_idx) { return ops_->enable_fn(ctx_, fn_idx); }
+    zx_status_t DisableFn(uint8_t fn_idx) { return ops_->disable_fn(ctx_, fn_idx); }
+    zx_status_t EnableFnIntr(uint8_t fn_idx) { return ops_->enable_fn_intr(ctx_, fn_idx); }
+    zx_status_t DisableFnIntr(uint8_t fn_idx) { return ops_->disable_fn_intr(ctx_, fn_idx); }
+    zx_status_t UpdateBlockSize(uint8_t fn_idx, uint16_t blk_sz, bool deflt) {
+        return ops_->update_block_size(ctx_, fn_idx, blk_sz, deflt);
+    }
+    zx_status_t GetBlockSize(uint8_t fn_idx, uint16_t* out_cur_blk_size) {
+        return ops_->get_block_size(ctx_, fn_idx, out_cur_blk_size);
+    }
+    zx_status_t DoRwTxn(uint8_t fn_idx, sdio_rw_txn_t* txn) {
+        return ops_->do_rw_txn(ctx_, fn_idx, txn);
+    }
+
+private:
+    sdio_protocol_ops_t* ops_;
+    void* ctx_;
+};
+
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/sdmmc-internal.h b/system/ulib/ddktl/include/ddktl/protocol/sdmmc-internal.h
new file mode 100644
index 0000000..1f73322
--- /dev/null
+++ b/system/ulib/ddktl/include/ddktl/protocol/sdmmc-internal.h
@@ -0,0 +1,60 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: This file is machine generated by fidlc.
+
+#pragma once
+
+#include <ddk/protocol/sdmmc.h>
+#include <fbl/type_support.h>
+
+namespace ddk {
+namespace internal {
+
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_sdmmc_protocol_host_info, SdmmcHostInfo,
+                                     zx_status_t (C::*)(sdmmc_host_info_t* out_info));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_sdmmc_protocol_set_signal_voltage, SdmmcSetSignalVoltage,
+                                     zx_status_t (C::*)(sdmmc_voltage_t voltage));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_sdmmc_protocol_set_bus_width, SdmmcSetBusWidth,
+                                     zx_status_t (C::*)(sdmmc_bus_width_t bus_width));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_sdmmc_protocol_set_bus_freq, SdmmcSetBusFreq,
+                                     zx_status_t (C::*)(uint32_t bus_freq));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_sdmmc_protocol_set_timing, SdmmcSetTiming,
+                                     zx_status_t (C::*)(sdmmc_timing_t timing));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_sdmmc_protocol_hw_reset, SdmmcHwReset, void (C::*)());
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_sdmmc_protocol_perform_tuning, SdmmcPerformTuning,
+                                     zx_status_t (C::*)(uint32_t cmd_idx));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_sdmmc_protocol_request, SdmmcRequest,
+                                     zx_status_t (C::*)(sdmmc_req_t* req));
+
+template <typename D>
+constexpr void CheckSdmmcProtocolSubclass() {
+    static_assert(internal::has_sdmmc_protocol_host_info<D>::value,
+                  "SdmmcProtocol subclasses must implement "
+                  "zx_status_t SdmmcHostInfo(sdmmc_host_info_t* out_info");
+    static_assert(internal::has_sdmmc_protocol_set_signal_voltage<D>::value,
+                  "SdmmcProtocol subclasses must implement "
+                  "zx_status_t SdmmcSetSignalVoltage(sdmmc_voltage_t voltage");
+    static_assert(internal::has_sdmmc_protocol_set_bus_width<D>::value,
+                  "SdmmcProtocol subclasses must implement "
+                  "zx_status_t SdmmcSetBusWidth(sdmmc_bus_width_t bus_width");
+    static_assert(internal::has_sdmmc_protocol_set_bus_freq<D>::value,
+                  "SdmmcProtocol subclasses must implement "
+                  "zx_status_t SdmmcSetBusFreq(uint32_t bus_freq");
+    static_assert(internal::has_sdmmc_protocol_set_timing<D>::value,
+                  "SdmmcProtocol subclasses must implement "
+                  "zx_status_t SdmmcSetTiming(sdmmc_timing_t timing");
+    static_assert(internal::has_sdmmc_protocol_hw_reset<D>::value,
+                  "SdmmcProtocol subclasses must implement "
+                  "void SdmmcHwReset(");
+    static_assert(internal::has_sdmmc_protocol_perform_tuning<D>::value,
+                  "SdmmcProtocol subclasses must implement "
+                  "zx_status_t SdmmcPerformTuning(uint32_t cmd_idx");
+    static_assert(internal::has_sdmmc_protocol_request<D>::value,
+                  "SdmmcProtocol subclasses must implement "
+                  "zx_status_t SdmmcRequest(sdmmc_req_t* req");
+}
+
+} // namespace internal
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/sdmmc.h b/system/ulib/ddktl/include/ddktl/protocol/sdmmc.h
new file mode 100644
index 0000000..7188087
--- /dev/null
+++ b/system/ulib/ddktl/include/ddktl/protocol/sdmmc.h
@@ -0,0 +1,155 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: This file is machine generated by fidlc.
+
+#pragma once
+
+#include <ddk/protocol/block.h>
+#include <ddk/protocol/sdmmc.h>
+#include <ddktl/device-internal.h>
+#include <zircon/assert.h>
+#include <zircon/compiler.h>
+#include <zircon/listnode.h>
+#include <zircon/types.h>
+
+#include "sdmmc-internal.h"
+
+// DDK sdmmc-protocol support
+//
+// :: Proxies ::
+//
+// ddk::SdmmcProtocolProxy is a simple wrapper around
+// sdmmc_protocol_t. It does not own the pointers passed to it
+//
+// :: Mixins ::
+//
+// ddk::SdmmcProtocol is a mixin class that simplifies writing DDK drivers
+// that implement the sdmmc protocol. It doesn't set the base protocol.
+//
+// :: Examples ::
+//
+// // A driver that implements a ZX_PROTOCOL_SDMMC device.
+// class SdmmcDevice {
+// using SdmmcDeviceType = ddk::Device<SdmmcDevice, /* ddk mixins */>;
+//
+// class SdmmcDevice : public SdmmcDeviceType,
+//                     public ddk::SdmmcProtocol<SdmmcDevice> {
+//   public:
+//     SdmmcDevice(zx_device_t* parent)
+//         : SdmmcDeviceType("my-sdmmc-protocol-device", parent) {}
+//
+//     zx_status_t SdmmcHostInfo(sdmmc_host_info_t* out_info);
+//
+//     zx_status_t SdmmcSetSignalVoltage(sdmmc_voltage_t voltage);
+//
+//     zx_status_t SdmmcSetBusWidth(sdmmc_bus_width_t bus_width);
+//
+//     zx_status_t SdmmcSetBusFreq(uint32_t bus_freq);
+//
+//     zx_status_t SdmmcSetTiming(sdmmc_timing_t timing);
+//
+//     void SdmmcHwReset();
+//
+//     zx_status_t SdmmcPerformTuning(uint32_t cmd_idx);
+//
+//     zx_status_t SdmmcRequest(sdmmc_req_t* req);
+//
+//     ...
+// };
+
+namespace ddk {
+
+template <typename D>
+class SdmmcProtocol : public internal::base_mixin {
+public:
+    SdmmcProtocol() {
+        internal::CheckSdmmcProtocolSubclass<D>();
+        sdmmc_protocol_ops_.host_info = SdmmcHostInfo;
+        sdmmc_protocol_ops_.set_signal_voltage = SdmmcSetSignalVoltage;
+        sdmmc_protocol_ops_.set_bus_width = SdmmcSetBusWidth;
+        sdmmc_protocol_ops_.set_bus_freq = SdmmcSetBusFreq;
+        sdmmc_protocol_ops_.set_timing = SdmmcSetTiming;
+        sdmmc_protocol_ops_.hw_reset = SdmmcHwReset;
+        sdmmc_protocol_ops_.perform_tuning = SdmmcPerformTuning;
+        sdmmc_protocol_ops_.request = SdmmcRequest;
+    }
+
+protected:
+    sdmmc_protocol_ops_t sdmmc_protocol_ops_ = {};
+
+private:
+    // Get host info.
+    static zx_status_t SdmmcHostInfo(void* ctx, sdmmc_host_info_t* out_info) {
+        return static_cast<D*>(ctx)->SdmmcHostInfo(out_info);
+    }
+    // Set signal voltage.
+    static zx_status_t SdmmcSetSignalVoltage(void* ctx, sdmmc_voltage_t voltage) {
+        return static_cast<D*>(ctx)->SdmmcSetSignalVoltage(voltage);
+    }
+    // Set bus width.
+    static zx_status_t SdmmcSetBusWidth(void* ctx, sdmmc_bus_width_t bus_width) {
+        return static_cast<D*>(ctx)->SdmmcSetBusWidth(bus_width);
+    }
+    // Set bus frequency.
+    static zx_status_t SdmmcSetBusFreq(void* ctx, uint32_t bus_freq) {
+        return static_cast<D*>(ctx)->SdmmcSetBusFreq(bus_freq);
+    }
+    // Set mmc timing.
+    static zx_status_t SdmmcSetTiming(void* ctx, sdmmc_timing_t timing) {
+        return static_cast<D*>(ctx)->SdmmcSetTiming(timing);
+    }
+    // Issue a hw reset.
+    static void SdmmcHwReset(void* ctx) { static_cast<D*>(ctx)->SdmmcHwReset(); }
+    // Perform tuning.
+    static zx_status_t SdmmcPerformTuning(void* ctx, uint32_t cmd_idx) {
+        return static_cast<D*>(ctx)->SdmmcPerformTuning(cmd_idx);
+    }
+    // Issue a request.
+    static zx_status_t SdmmcRequest(void* ctx, sdmmc_req_t* req) {
+        return static_cast<D*>(ctx)->SdmmcRequest(req);
+    }
+};
+
+class SdmmcProtocolProxy {
+public:
+    SdmmcProtocolProxy() : ops_(nullptr), ctx_(nullptr) {}
+    SdmmcProtocolProxy(const sdmmc_protocol_t* proto) : ops_(proto->ops), ctx_(proto->ctx) {}
+
+    void GetProto(sdmmc_protocol_t* proto) {
+        proto->ctx = ctx_;
+        proto->ops = ops_;
+    }
+    bool is_valid() { return ops_ != nullptr; }
+    void clear() {
+        ctx_ = nullptr;
+        ops_ = nullptr;
+    }
+    // Get host info.
+    zx_status_t HostInfo(sdmmc_host_info_t* out_info) { return ops_->host_info(ctx_, out_info); }
+    // Set signal voltage.
+    zx_status_t SetSignalVoltage(sdmmc_voltage_t voltage) {
+        return ops_->set_signal_voltage(ctx_, voltage);
+    }
+    // Set bus width.
+    zx_status_t SetBusWidth(sdmmc_bus_width_t bus_width) {
+        return ops_->set_bus_width(ctx_, bus_width);
+    }
+    // Set bus frequency.
+    zx_status_t SetBusFreq(uint32_t bus_freq) { return ops_->set_bus_freq(ctx_, bus_freq); }
+    // Set mmc timing.
+    zx_status_t SetTiming(sdmmc_timing_t timing) { return ops_->set_timing(ctx_, timing); }
+    // Issue a hw reset.
+    void HwReset() { ops_->hw_reset(ctx_); }
+    // Perform tuning.
+    zx_status_t PerformTuning(uint32_t cmd_idx) { return ops_->perform_tuning(ctx_, cmd_idx); }
+    // Issue a request.
+    zx_status_t Request(sdmmc_req_t* req) { return ops_->request(ctx_, req); }
+
+private:
+    sdmmc_protocol_ops_t* ops_;
+    void* ctx_;
+};
+
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/serial-impl-internal.h b/system/ulib/ddktl/include/ddktl/protocol/serial-impl-internal.h
index a02c8a3..7e81fe9 100644
--- a/system/ulib/ddktl/include/ddktl/protocol/serial-impl-internal.h
+++ b/system/ulib/ddktl/include/ddktl/protocol/serial-impl-internal.h
@@ -2,52 +2,54 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
-#include <ddk/protocol/serial.h>
+#include <ddk/protocol/serial-impl.h>
 #include <fbl/type_support.h>
 
 namespace ddk {
 namespace internal {
 
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(serial_has_get_info, GetInfo,
-                                     zx_status_t (C::*)(serial_port_info_t*));
-
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(serial_has_config, Config,
-                                     zx_status_t (C::*)(uint32_t, uint32_t));
-
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(serial_has_enable, Enable,
-                                     zx_status_t (C::*)(bool));
-
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(serial_has_read, Read,
-                                     zx_status_t (C::*)(void*, size_t, size_t*));
-
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(serial_has_write, Write,
-                                     zx_status_t (C::*)(const void*, size_t, size_t*));
-
-DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(serial_has_set_notify_callback, SetNotifyCallback,
-                                     zx_status_t (C::*)(serial_notify_cb, void*));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_serial_impl_protocol_get_info, SerialImplGetInfo,
+                                     zx_status_t (C::*)(serial_port_info_t* out_info));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_serial_impl_protocol_config, SerialImplConfig,
+                                     zx_status_t (C::*)(uint32_t baud_rate, uint32_t flags));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_serial_impl_protocol_enable, SerialImplEnable,
+                                     zx_status_t (C::*)(bool enable));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_serial_impl_protocol_read, SerialImplRead,
+                                     zx_status_t (C::*)(void* out_buf_buffer, size_t buf_size,
+                                                        size_t* out_buf_actual));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_serial_impl_protocol_write, SerialImplWrite,
+                                     zx_status_t (C::*)(const void* buf_buffer, size_t buf_size,
+                                                        size_t* out_actual));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_serial_impl_protocol_set_notify_callback,
+                                     SerialImplSetNotifyCallback,
+                                     zx_status_t (C::*)(const serial_notify_t* cb));
 
 template <typename D>
 constexpr void CheckSerialImplProtocolSubclass() {
-    static_assert(internal::serial_has_get_info<D>::value,
+    static_assert(internal::has_serial_impl_protocol_get_info<D>::value,
                   "SerialImplProtocol subclasses must implement "
-                  "zx_status_t GetInfo(serial_port_info_t* info)");
-    static_assert(internal::serial_has_config<D>::value,
+                  "zx_status_t SerialImplGetInfo(serial_port_info_t* out_info");
+    static_assert(internal::has_serial_impl_protocol_config<D>::value,
                   "SerialImplProtocol subclasses must implement "
-                  "zx_status_t Config(uint32_t baud_rate, uint32_t flags)");
-    static_assert(internal::serial_has_enable<D>::value,
+                  "zx_status_t SerialImplConfig(uint32_t baud_rate, uint32_t flags");
+    static_assert(internal::has_serial_impl_protocol_enable<D>::value,
                   "SerialImplProtocol subclasses must implement "
-                  "zx_status_t Enable(bool enable)");
-    static_assert(internal::serial_has_read<D>::value,
+                  "zx_status_t SerialImplEnable(bool enable");
+    static_assert(
+        internal::has_serial_impl_protocol_read<D>::value,
+        "SerialImplProtocol subclasses must implement "
+        "zx_status_t SerialImplRead(void* out_buf_buffer, size_t buf_size, size_t* out_buf_actual");
+    static_assert(
+        internal::has_serial_impl_protocol_write<D>::value,
+        "SerialImplProtocol subclasses must implement "
+        "zx_status_t SerialImplWrite(const void* buf_buffer, size_t buf_size, size_t* out_actual");
+    static_assert(internal::has_serial_impl_protocol_set_notify_callback<D>::value,
                   "SerialImplProtocol subclasses must implement "
-                  "zx_status_t Read(void* buf, size_t length, size_t* out_actual)");
-    static_assert(internal::serial_has_write<D>::value,
-                  "SerialImplProtocol subclasses must implement "
-                  "zx_status_t Write(const void* buf, size_t length, size_t* out_actual)");
-    static_assert(internal::serial_has_set_notify_callback<D>::value,
-                  "SerialImplProtocol subclasses must implement "
-                  "zx_status_t SetNotifyCallback(serial_notify_cb cb, void* cookie)");
+                  "zx_status_t SerialImplSetNotifyCallback(const serial_notify_t* cb");
 }
 
 } // namespace internal
diff --git a/system/ulib/ddktl/include/ddktl/protocol/serial-impl.h b/system/ulib/ddktl/include/ddktl/protocol/serial-impl.h
index bbfbe7e..6cdafea 100644
--- a/system/ulib/ddktl/include/ddktl/protocol/serial-impl.h
+++ b/system/ulib/ddktl/include/ddktl/protocol/serial-impl.h
@@ -2,43 +2,55 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
-#include <ddk/driver.h>
 #include <ddk/protocol/serial-impl.h>
+#include <ddk/protocol/serial.h>
 #include <ddktl/device-internal.h>
 #include <zircon/assert.h>
+#include <zircon/compiler.h>
+#include <zircon/types.h>
 
 #include "serial-impl-internal.h"
 
-// DDK serial-impl protocol support.
+// DDK serial-impl-protocol support
 //
 // :: Proxies ::
 //
-// ddk::SerialImplProtocolProxy is a simple wrappers around serial_protocol_t. It does
-// not own the pointers passed to it.
+// ddk::SerialImplProtocolProxy is a simple wrapper around
+// serial_impl_protocol_t. It does not own the pointers passed to it
 //
 // :: Mixins ::
 //
-// ddk::SerialImplProtocol is a mixin class that simplifies writing DDK drivers that
-// implement the serial protocol.
+// ddk::SerialImplProtocol is a mixin class that simplifies writing DDK drivers
+// that implement the serial-impl protocol. It doesn't set the base protocol.
 //
 // :: Examples ::
 //
-// // A driver that implements a ZX_PROTOCOL_NAND device.
-// class SerialImplDevice;
+// // A driver that implements a ZX_PROTOCOL_SERIAL_IMPL device.
+// class SerialImplDevice {
 // using SerialImplDeviceType = ddk::Device<SerialImplDevice, /* ddk mixins */>;
 //
-// class SerialImplDevice : public SerialDeviceType,
+// class SerialImplDevice : public SerialImplDeviceType,
 //                          public ddk::SerialImplProtocol<SerialImplDevice> {
 //   public:
 //     SerialImplDevice(zx_device_t* parent)
-//       : SerialImplDeviceType("my-serial-device", parent) {}
+//         : SerialImplDeviceType("my-serial-impl-protocol-device", parent) {}
 //
-//     void Query(serial_info_t* info_out, size_t* serial_op_size_out);
-//     void Queue(serial_op_t* operation);
-//     zx_status_t GetFactoryBadBlockList(uint32_t* bad_blocks, uint32_t bad_block_len,
-//                                        uint32_t* num_bad_blocks);
+//     zx_status_t SerialImplGetInfo(serial_port_info_t* out_info);
+//
+//     zx_status_t SerialImplConfig(uint32_t baud_rate, uint32_t flags);
+//
+//     zx_status_t SerialImplEnable(bool enable);
+//
+//     zx_status_t SerialImplRead(void* out_buf_buffer, size_t buf_size, size_t* out_buf_actual);
+//
+//     zx_status_t SerialImplWrite(const void* buf_buffer, size_t buf_size, size_t* out_actual);
+//
+//     zx_status_t SerialImplSetNotifyCallback(const serial_notify_t* cb);
+//
 //     ...
 // };
 
@@ -49,79 +61,79 @@
 public:
     SerialImplProtocol() {
         internal::CheckSerialImplProtocolSubclass<D>();
-        serial_proto_ops_.get_info = GetInfo;
-        serial_proto_ops_.config = Config;
-        serial_proto_ops_.enable = Enable;
-        serial_proto_ops_.read = Read;
-        serial_proto_ops_.write = Write;
-        serial_proto_ops_.set_notify_callback = SetNotifyCallback;
+        ops_.get_info = SerialImplGetInfo;
+        ops_.config = SerialImplConfig;
+        ops_.enable = SerialImplEnable;
+        ops_.read = SerialImplRead;
+        ops_.write = SerialImplWrite;
+        ops_.set_notify_callback = SerialImplSetNotifyCallback;
 
         // Can only inherit from one base_protocol implementation.
-        ZX_ASSERT(ddk_proto_id_ == 0);
+        ZX_ASSERT(ddk_proto_id_ = 0);
         ddk_proto_id_ = ZX_PROTOCOL_SERIAL_IMPL;
-        ddk_proto_ops_ = &serial_proto_ops_;
+        ddk_proto_ops_ = &ops_;
     }
 
 protected:
-    serial_impl_ops_t serial_proto_ops_ = {};
+    serial_impl_protocol_ops_t ops_ = {};
 
 private:
-    static zx_status_t GetInfo(void* ctx, serial_port_info_t* info) {
-        return static_cast<D*>(ctx)->GetInfo(info);
+    static zx_status_t SerialImplGetInfo(void* ctx, serial_port_info_t* out_info) {
+        return static_cast<D*>(ctx)->SerialImplGetInfo(out_info);
     }
-
-    static zx_status_t Config(void* ctx, uint32_t baud_rate, uint32_t flags) {
-        return static_cast<D*>(ctx)->Config(baud_rate, flags);
+    // Configures the given serial port.
+    static zx_status_t SerialImplConfig(void* ctx, uint32_t baud_rate, uint32_t flags) {
+        return static_cast<D*>(ctx)->SerialImplConfig(baud_rate, flags);
     }
-
-    static zx_status_t Enable(void* ctx, bool enable) {
-        return static_cast<D*>(ctx)->Enable(enable);
+    static zx_status_t SerialImplEnable(void* ctx, bool enable) {
+        return static_cast<D*>(ctx)->SerialImplEnable(enable);
     }
-
-    static zx_status_t Read(void* ctx, void* buf, size_t length, size_t* out_actual) {
-        return static_cast<D*>(ctx)->Read(buf, length, out_actual);
+    static zx_status_t SerialImplRead(void* ctx, void* out_buf_buffer, size_t buf_size,
+                                      size_t* out_buf_actual) {
+        return static_cast<D*>(ctx)->SerialImplRead(out_buf_buffer, buf_size, out_buf_actual);
     }
-
-    static zx_status_t Write(void* ctx, const void* buf, size_t length, size_t* out_actual) {
-        return static_cast<D*>(ctx)->Write(buf, length, out_actual);
+    static zx_status_t SerialImplWrite(void* ctx, const void* buf_buffer, size_t buf_size,
+                                       size_t* out_actual) {
+        return static_cast<D*>(ctx)->SerialImplWrite(buf_buffer, buf_size, out_actual);
     }
-
-    static zx_status_t SetNotifyCallback(void* ctx, serial_notify_cb cb, void* cookie) {
-        return static_cast<D*>(ctx)->SetNotifyCallback(cb, cookie);
+    static zx_status_t SerialImplSetNotifyCallback(void* ctx, const serial_notify_t* cb) {
+        return static_cast<D*>(ctx)->SerialImplSetNotifyCallback(cb);
     }
 };
 
 class SerialImplProtocolProxy {
 public:
-    SerialImplProtocolProxy(serial_impl_protocol_t* proto)
+    SerialImplProtocolProxy() : ops_(nullptr), ctx_(nullptr) {}
+    SerialImplProtocolProxy(const serial_impl_protocol_t* proto)
         : ops_(proto->ops), ctx_(proto->ctx) {}
 
-    zx_status_t GetInfo(serial_port_info_t* info) {
-        return ops_->get_info(ctx_, info);
+    void GetProto(serial_impl_protocol_t* proto) {
+        proto->ctx = ctx_;
+        proto->ops = ops_;
     }
-
+    bool is_valid() { return ops_ != nullptr; }
+    void clear() {
+        ctx_ = nullptr;
+        ops_ = nullptr;
+    }
+    zx_status_t GetInfo(serial_port_info_t* out_info) { return ops_->get_info(ctx_, out_info); }
+    // Configures the given serial port.
     zx_status_t Config(uint32_t baud_rate, uint32_t flags) {
         return ops_->config(ctx_, baud_rate, flags);
     }
-
-    zx_status_t Enable(bool enable) {
-        return ops_->enable(ctx_, enable);
+    zx_status_t Enable(bool enable) { return ops_->enable(ctx_, enable); }
+    zx_status_t Read(void* out_buf_buffer, size_t buf_size, size_t* out_buf_actual) {
+        return ops_->read(ctx_, out_buf_buffer, buf_size, out_buf_actual);
     }
-
-    zx_status_t Read(void* buf, size_t length, size_t* out_actual) {
-        return ops_->read(ctx_, buf, length, out_actual);
+    zx_status_t Write(const void* buf_buffer, size_t buf_size, size_t* out_actual) {
+        return ops_->write(ctx_, buf_buffer, buf_size, out_actual);
     }
-
-    zx_status_t Write(const void* buf, size_t length, size_t* out_actual) {
-        return ops_->write(ctx_, buf, length, out_actual);
-    }
-
-    zx_status_t SetNotifyCallback(serial_notify_cb cb, void* cookie) {
-        return ops_->set_notify_callback(ctx_, cb, cookie);
+    zx_status_t SetNotifyCallback(const serial_notify_t* cb) {
+        return ops_->set_notify_callback(ctx_, cb);
     }
 
 private:
-    serial_impl_ops_t* ops_;
+    serial_impl_protocol_ops_t* ops_;
     void* ctx_;
 };
 
diff --git a/system/ulib/ddktl/include/ddktl/protocol/serial-internal.h b/system/ulib/ddktl/include/ddktl/protocol/serial-internal.h
new file mode 100644
index 0000000..5582a83
--- /dev/null
+++ b/system/ulib/ddktl/include/ddktl/protocol/serial-internal.h
@@ -0,0 +1,36 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: This file is machine generated by fidlc.
+
+#pragma once
+
+#include <ddk/protocol/serial.h>
+#include <fbl/type_support.h>
+
+namespace ddk {
+namespace internal {
+
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_serial_protocol_get_info, SerialGetInfo,
+                                     zx_status_t (C::*)(serial_port_info_t* out_info));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_serial_protocol_config, SerialConfig,
+                                     zx_status_t (C::*)(uint32_t baud_rate, uint32_t flags));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_serial_protocol_open_socket, SerialOpenSocket,
+                                     zx_status_t (C::*)(zx_handle_t* out_handle));
+
+template <typename D>
+constexpr void CheckSerialProtocolSubclass() {
+    static_assert(internal::has_serial_protocol_get_info<D>::value,
+                  "SerialProtocol subclasses must implement "
+                  "zx_status_t SerialGetInfo(serial_port_info_t* out_info");
+    static_assert(internal::has_serial_protocol_config<D>::value,
+                  "SerialProtocol subclasses must implement "
+                  "zx_status_t SerialConfig(uint32_t baud_rate, uint32_t flags");
+    static_assert(internal::has_serial_protocol_open_socket<D>::value,
+                  "SerialProtocol subclasses must implement "
+                  "zx_status_t SerialOpenSocket(zx_handle_t* out_handle");
+}
+
+} // namespace internal
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/serial.h b/system/ulib/ddktl/include/ddktl/protocol/serial.h
new file mode 100644
index 0000000..a07f210
--- /dev/null
+++ b/system/ulib/ddktl/include/ddktl/protocol/serial.h
@@ -0,0 +1,117 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: This file is machine generated by fidlc.
+
+#pragma once
+
+#include <ddk/protocol/serial.h>
+#include <ddktl/device-internal.h>
+#include <zircon/assert.h>
+#include <zircon/compiler.h>
+#include <zircon/types.h>
+
+#include "serial-internal.h"
+
+// DDK serial-protocol support
+//
+// :: Proxies ::
+//
+// ddk::SerialProtocolProxy is a simple wrapper around
+// serial_protocol_t. It does not own the pointers passed to it
+//
+// :: Mixins ::
+//
+// ddk::SerialProtocol is a mixin class that simplifies writing DDK drivers
+// that implement the serial protocol. It doesn't set the base protocol.
+//
+// :: Examples ::
+//
+// // A driver that implements a ZX_PROTOCOL_SERIAL device.
+// class SerialDevice {
+// using SerialDeviceType = ddk::Device<SerialDevice, /* ddk mixins */>;
+//
+// class SerialDevice : public SerialDeviceType,
+//                      public ddk::SerialProtocol<SerialDevice> {
+//   public:
+//     SerialDevice(zx_device_t* parent)
+//         : SerialDeviceType("my-serial-protocol-device", parent) {}
+//
+//     zx_status_t SerialGetInfo(serial_port_info_t* out_info);
+//
+//     zx_status_t SerialConfig(uint32_t baud_rate, uint32_t flags);
+//
+//     zx_status_t SerialOpenSocket(zx_handle_t* out_handle);
+//
+//     ...
+// };
+
+namespace ddk {
+
+// High level serial protocol for use by client drivers.
+// When used with the platform device protocol, "port" will be relative to
+// the list of serial ports assigned to your device rather than the global
+// list of serial ports.
+template <typename D>
+class SerialProtocol : public internal::base_protocol {
+public:
+    SerialProtocol() {
+        internal::CheckSerialProtocolSubclass<D>();
+        ops_.get_info = SerialGetInfo;
+        ops_.config = SerialConfig;
+        ops_.open_socket = SerialOpenSocket;
+
+        // Can only inherit from one base_protocol implementation.
+        ZX_ASSERT(ddk_proto_id_ = 0);
+        ddk_proto_id_ = ZX_PROTOCOL_SERIAL;
+        ddk_proto_ops_ = &ops_;
+    }
+
+protected:
+    serial_protocol_ops_t ops_ = {};
+
+private:
+    static zx_status_t SerialGetInfo(void* ctx, serial_port_info_t* out_info) {
+        return static_cast<D*>(ctx)->SerialGetInfo(out_info);
+    }
+    // Configures the given serial port.
+    static zx_status_t SerialConfig(void* ctx, uint32_t baud_rate, uint32_t flags) {
+        return static_cast<D*>(ctx)->SerialConfig(baud_rate, flags);
+    }
+    // Returns a socket that can be used for reading and writing data
+    // from the given serial port.
+    static zx_status_t SerialOpenSocket(void* ctx, zx_handle_t* out_handle) {
+        return static_cast<D*>(ctx)->SerialOpenSocket(out_handle);
+    }
+};
+
+class SerialProtocolProxy {
+public:
+    SerialProtocolProxy() : ops_(nullptr), ctx_(nullptr) {}
+    SerialProtocolProxy(const serial_protocol_t* proto) : ops_(proto->ops), ctx_(proto->ctx) {}
+
+    void GetProto(serial_protocol_t* proto) {
+        proto->ctx = ctx_;
+        proto->ops = ops_;
+    }
+    bool is_valid() { return ops_ != nullptr; }
+    void clear() {
+        ctx_ = nullptr;
+        ops_ = nullptr;
+    }
+    zx_status_t GetInfo(serial_port_info_t* out_info) { return ops_->get_info(ctx_, out_info); }
+    // Configures the given serial port.
+    zx_status_t Config(uint32_t baud_rate, uint32_t flags) {
+        return ops_->config(ctx_, baud_rate, flags);
+    }
+    // Returns a socket that can be used for reading and writing data
+    // from the given serial port.
+    zx_status_t OpenSocket(zx_handle_t* out_handle) { return ops_->open_socket(ctx_, out_handle); }
+
+private:
+    serial_protocol_ops_t* ops_;
+    void* ctx_;
+};
+
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/test-internal.h b/system/ulib/ddktl/include/ddktl/protocol/test-internal.h
new file mode 100644
index 0000000..8821ea1
--- /dev/null
+++ b/system/ulib/ddktl/include/ddktl/protocol/test-internal.h
@@ -0,0 +1,57 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: This file is machine generated by fidlc.
+
+#pragma once
+
+#include <ddk/protocol/test.h>
+#include <fbl/type_support.h>
+
+namespace ddk {
+namespace internal {
+
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_test_protocol_set_output_socket, TestSetOutputSocket,
+                                     void (C::*)(zx_handle_t handle));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_test_protocol_get_output_socket, TestGetOutputSocket,
+                                     zx_handle_t (C::*)());
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_test_protocol_set_control_channel, TestSetControlChannel,
+                                     void (C::*)(zx_handle_t handle));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_test_protocol_get_control_channel, TestGetControlChannel,
+                                     zx_handle_t (C::*)());
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_test_protocol_set_test_func, TestSetTestFunc,
+                                     void (C::*)(const test_func_t* func));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_test_protocol_run_tests, TestRunTests,
+                                     zx_status_t (C::*)(const void* arg_buffer, size_t arg_size,
+                                                        test_report_t* out_report));
+DECLARE_HAS_MEMBER_FN_WITH_SIGNATURE(has_test_protocol_destroy, TestDestroy, void (C::*)());
+
+template <typename D>
+constexpr void CheckTestProtocolSubclass() {
+    static_assert(internal::has_test_protocol_set_output_socket<D>::value,
+                  "TestProtocol subclasses must implement "
+                  "void TestSetOutputSocket(zx_handle_t handle");
+    static_assert(internal::has_test_protocol_get_output_socket<D>::value,
+                  "TestProtocol subclasses must implement "
+                  "zx_handle_t TestGetOutputSocket(");
+    static_assert(internal::has_test_protocol_set_control_channel<D>::value,
+                  "TestProtocol subclasses must implement "
+                  "void TestSetControlChannel(zx_handle_t handle");
+    static_assert(internal::has_test_protocol_get_control_channel<D>::value,
+                  "TestProtocol subclasses must implement "
+                  "zx_handle_t TestGetControlChannel(");
+    static_assert(internal::has_test_protocol_set_test_func<D>::value,
+                  "TestProtocol subclasses must implement "
+                  "void TestSetTestFunc(const test_func_t* func");
+    static_assert(internal::has_test_protocol_run_tests<D>::value,
+                  "TestProtocol subclasses must implement "
+                  "zx_status_t TestRunTests(const void* arg_buffer, size_t arg_size, "
+                  "test_report_t* out_report");
+    static_assert(internal::has_test_protocol_destroy<D>::value,
+                  "TestProtocol subclasses must implement "
+                  "void TestDestroy(");
+}
+
+} // namespace internal
+} // namespace ddk
diff --git a/system/ulib/ddktl/include/ddktl/protocol/test.h b/system/ulib/ddktl/include/ddktl/protocol/test.h
index 3d1601c..416522d 100644
--- a/system/ulib/ddktl/include/ddktl/protocol/test.h
+++ b/system/ulib/ddktl/include/ddktl/protocol/test.h
@@ -1,106 +1,143 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// WARNING: This file is machine generated by fidlc.
+
 #pragma once
 
 #include <ddk/protocol/test.h>
+#include <ddktl/device-internal.h>
 #include <zircon/assert.h>
-#include <lib/zx/channel.h>
-#include <lib/zx/socket.h>
+#include <zircon/compiler.h>
+#include <zircon/types.h>
 
-// DDK test protocol support
+#include "test-internal.h"
+
+// DDK test-protocol support
 //
-// :: Proxy ::
+// :: Proxies ::
 //
-// ddk::TestProtocolProxy is a simple wrapper around test_protocol_t. It does not own the pointers
-// passed to it.
+// ddk::TestProtocolProxy is a simple wrapper around
+// test_protocol_t. It does not own the pointers passed to it
 //
-// :: Mixin ::
+// :: Mixins ::
 //
-// No mixins are defined, as it is not expected that there will be multiple implementations of the
-// test protocol.
+// ddk::TestProtocol is a mixin class that simplifies writing DDK drivers
+// that implement the test protocol. It doesn't set the base protocol.
 //
-// :: Example ::
+// :: Examples ::
 //
-// // A driver that communicates with a ZX_PROTOCOL_TEST device
-// class MyDevice;
-// using MyDeviceType = ddk::Device<MyDevice, /* ddk mixins */>;
+// // A driver that implements a ZX_PROTOCOL_TEST device.
+// class TestDevice {
+// using TestDeviceType = ddk::Device<TestDevice, /* ddk mixins */>;
 //
-// static zx_status_t my_test_func(void* cookie, test_report_t* report, const void* arg,
-//                                 size_t arglen) {
-//     auto dev = static_cast<MyDevice*>(cookie);
-//     // run tests and set up report
-//     return ZX_OK;
-// }
-//
-// class MyDevice : public MyDeviceType {
+// class TestDevice : public TestDeviceType,
+//                    public ddk::TestProtocol<TestDevice> {
 //   public:
-//     MyDevice(zx_device_t* parent)
-//       : MyDeviceType("my-device"),
-//         parent_(parent) {}
+//     TestDevice(zx_device_t* parent)
+//         : TestDeviceType("my-test-protocol-device", parent) {}
 //
-//     void DdkRelease() {
-//         // Clean up
-//     }
+//     void TestSetOutputSocket(zx_handle_t handle);
 //
-//     zx_status_t Bind() {
-//         test_protocol_t* ops;
-//         auto status = get_device_protocol(parent_, ZX_PROTOCOL_TEST,
-//                                           reinterpret_cast<void**>(&ops));
-//         if (status != ZX_OK) {
-//             return status;
-//         }
-//        proxy_.reset(new ddk::TestProtocolProxy(ops, parent_));
+//     zx_handle_t TestGetOutputSocket();
 //
-//        // Set up the test
-//        proxy_->SetTestFunc(my_test_func, this);
-//        return Add(parent_);
-//     }
+//     void TestSetControlChannel(zx_handle_t handle);
 //
-//   private:
-//     fbl::unique_ptr<ddk::TestProtocolProxy> proxy_;
+//     zx_handle_t TestGetControlChannel();
+//
+//     void TestSetTestFunc(const test_func_t* func);
+//
+//     zx_status_t TestRunTests(const void* arg_buffer, size_t arg_size, test_report_t* out_report);
+//
+//     void TestDestroy();
+//
+//     ...
 // };
 
 namespace ddk {
 
-class TestProtocolProxy {
-  public:
-    TestProtocolProxy(test_protocol_t* proto)
-      : ops_(proto->ops), ctx_(proto->ctx) {}
-
-    void SetOutputSocket(zx::socket socket) {
-        ops_->set_output_socket(ctx_, socket.release());
+template <typename D>
+class TestProtocol : public internal::base_mixin {
+public:
+    TestProtocol() {
+        internal::CheckTestProtocolSubclass<D>();
+        test_protocol_ops_.set_output_socket = TestSetOutputSocket;
+        test_protocol_ops_.get_output_socket = TestGetOutputSocket;
+        test_protocol_ops_.set_control_channel = TestSetControlChannel;
+        test_protocol_ops_.get_control_channel = TestGetControlChannel;
+        test_protocol_ops_.set_test_func = TestSetTestFunc;
+        test_protocol_ops_.run_tests = TestRunTests;
+        test_protocol_ops_.destroy = TestDestroy;
     }
 
-    zx::socket GetOutputSocket() {
-        return zx::socket(ops_->get_output_socket(ctx_));
+protected:
+    test_protocol_ops_t test_protocol_ops_ = {};
+
+private:
+    // Sets test output socket.
+    static void TestSetOutputSocket(void* ctx, zx_handle_t handle) {
+        static_cast<D*>(ctx)->TestSetOutputSocket(handle);
     }
-
-    void SetControlChannel(zx::channel chan) {
-        ops_->set_control_channel(ctx_, chan.release());
+    // Gets test output socket.
+    static zx_handle_t TestGetOutputSocket(void* ctx) {
+        return static_cast<D*>(ctx)->TestGetOutputSocket();
     }
-
-    zx::channel GetControlChannel() {
-        return zx::channel(ops_->get_control_channel(ctx_));
+    // Sets control channel.
+    static void TestSetControlChannel(void* ctx, zx_handle_t handle) {
+        static_cast<D*>(ctx)->TestSetControlChannel(handle);
     }
-
-    void SetTestFunc(test_func_t func, void* cookie) {
-        ops_->set_test_func(ctx_, func, cookie);
+    // Gets control channel.
+    static zx_handle_t TestGetControlChannel(void* ctx) {
+        return static_cast<D*>(ctx)->TestGetControlChannel();
     }
-
-    zx_status_t RunTests(test_report_t* report, const void* arg, size_t arglen) {
-        return ops_->run_tests(ctx_, report, arg, arglen);
+    // Sets test function.
+    static void TestSetTestFunc(void* ctx, const test_func_t* func) {
+        static_cast<D*>(ctx)->TestSetTestFunc(func);
     }
-
-    void Destroy() {
-        ops_->destroy(ctx_);
+    // Run tests, calls the function set in |SetTestFunc|.
+    static zx_status_t TestRunTests(void* ctx, const void* arg_buffer, size_t arg_size,
+                                    test_report_t* out_report) {
+        return static_cast<D*>(ctx)->TestRunTests(arg_buffer, arg_size, out_report);
     }
-
-  private:
-    test_protocol_ops_t* ops_;
-    void* ctx_;
-
+    // Calls `device_remove()`.
+    static void TestDestroy(void* ctx) { static_cast<D*>(ctx)->TestDestroy(); }
 };
 
-}  // namespace ddk
+class TestProtocolProxy {
+public:
+    TestProtocolProxy() : ops_(nullptr), ctx_(nullptr) {}
+    TestProtocolProxy(const test_protocol_t* proto) : ops_(proto->ops), ctx_(proto->ctx) {}
+
+    void GetProto(test_protocol_t* proto) {
+        proto->ctx = ctx_;
+        proto->ops = ops_;
+    }
+    bool is_valid() { return ops_ != nullptr; }
+    void clear() {
+        ctx_ = nullptr;
+        ops_ = nullptr;
+    }
+    // Sets test output socket.
+    void SetOutputSocket(zx_handle_t handle) { ops_->set_output_socket(ctx_, handle); }
+    // Gets test output socket.
+    zx_handle_t GetOutputSocket() { return ops_->get_output_socket(ctx_); }
+    // Sets control channel.
+    void SetControlChannel(zx_handle_t handle) { ops_->set_control_channel(ctx_, handle); }
+    // Gets control channel.
+    zx_handle_t GetControlChannel() { return ops_->get_control_channel(ctx_); }
+    // Sets test function.
+    void SetTestFunc(const test_func_t* func) { ops_->set_test_func(ctx_, func); }
+    // Run tests, calls the function set in |SetTestFunc|.
+    zx_status_t RunTests(const void* arg_buffer, size_t arg_size, test_report_t* out_report) {
+        return ops_->run_tests(ctx_, arg_buffer, arg_size, out_report);
+    }
+    // Calls `device_remove()`.
+    void Destroy() { ops_->destroy(ctx_); }
+
+private:
+    test_protocol_ops_t* ops_;
+    void* ctx_;
+};
+
+} // namespace ddk
diff --git a/system/ulib/ddktl/test/ddktl-test.cpp b/system/ulib/ddktl/test/ddktl-test.cpp
index 65e812b..f2de174 100644
--- a/system/ulib/ddktl/test/ddktl-test.cpp
+++ b/system/ulib/ddktl/test/ddktl-test.cpp
@@ -38,7 +38,7 @@
     }
 }
 
-zx_status_t ddktl_test_func(void* cookie, test_report_t* report, const void* arg, size_t arglen) {
+zx_status_t ddktl_test_func(void* cookie, const void* arg, size_t arglen, test_report_t* report) {
     auto dev = static_cast<zx_device_t*>(cookie);
 
     test_protocol_t proto;
@@ -69,7 +69,8 @@
         return status;
     }
 
-    proto.ops->set_test_func(proto.ctx, ddktl_test_func, parent);
+    const test_func_t test = {ddktl_test_func, parent};
+    proto.ops->set_test_func(proto.ctx, &test);
 
     return ZX_OK;
 }
diff --git a/system/ulib/ddktl/test/ethernet-tests.cpp b/system/ulib/ddktl/test/ethernet-tests.cpp
index 3482313..9e9b47a 100644
--- a/system/ulib/ddktl/test/ethernet-tests.cpp
+++ b/system/ulib/ddktl/test/ethernet-tests.cpp
@@ -26,17 +26,17 @@
 
     void DdkRelease() {}
 
-    void EthmacStatus(uint32_t status) {
+    void EthmacIfcStatus(uint32_t status) {
         status_this_ = get_this();
         status_called_ = true;
     }
 
-    void EthmacRecv(void* data, size_t length, uint32_t flags) {
+    void EthmacIfcRecv(const void* data, size_t length, uint32_t flags) {
         recv_this_ = get_this();
         recv_called_ = true;
     }
 
-    void EthmacCompleteTx(ethmac_netbuf_t* netbuf, zx_status_t status) {
+    void EthmacIfcCompleteTx(ethmac_netbuf_t* netbuf, zx_status_t status) {
         complete_tx_this_ = get_this();
         complete_tx_called_ = true;
     }
@@ -52,8 +52,11 @@
         END_HELPER;
     }
 
+    ethmac_ifc_t ethmac_ifc() { return {&ethmac_ifc_ops_, this}; }
+
     zx_status_t StartProtocol(ddk::EthmacProtocolProxy* proxy) {
-        return proxy->Start(this);
+        const ethmac_ifc_t ifc = ethmac_ifc();
+        return proxy->Start(&ifc);
     }
 
   private:
@@ -77,7 +80,7 @@
     zx_status_t DdkGetProtocol(uint32_t proto_id, void* out) {
         if (proto_id != ZX_PROTOCOL_ETHERNET_IMPL) return ZX_ERR_INVALID_ARGS;
         ddk::AnyProtocol* proto = static_cast<ddk::AnyProtocol*>(out);
-        proto->ops = ddk_proto_ops_;
+        proto->ops = &ethmac_protocol_ops_;
         proto->ctx = this;
         return ZX_OK;
     }
@@ -95,9 +98,9 @@
         stop_called_ = true;
     }
 
-    zx_status_t EthmacStart(fbl::unique_ptr<ddk::EthmacIfcProxy> proxy) {
+    zx_status_t EthmacStart(const ethmac_ifc_t* ifc) {
         start_this_ = get_this();
-        proxy_.swap(proxy);
+        proxy_ = fbl::make_unique<ddk::EthmacIfcProxy>(ifc);
         start_called_ = true;
         return ZX_OK;
     }
@@ -108,7 +111,7 @@
         return ZX_OK;
     }
 
-    zx_status_t EthmacSetParam(uint32_t param, int32_t value, void* data) {
+    zx_status_t EthmacSetParam(uint32_t param, int32_t value, const void* data, size_t data_size) {
         set_param_this_ = get_this();
         set_param_called_ = true;
         return ZX_OK;
@@ -162,9 +165,9 @@
     TestEthmacIfc dev;
 
     auto ifc = dev.ethmac_ifc();
-    ifc->status(&dev, 0);
-    ifc->recv(&dev, nullptr, 0, 0);
-    ifc->complete_tx(&dev, nullptr, ZX_OK);
+    ethmac_ifc_status(&ifc, 0);
+    ethmac_ifc_recv(&ifc, nullptr, 0, 0);
+    ethmac_ifc_complete_tx(&ifc, nullptr, ZX_OK);
 
     EXPECT_TRUE(dev.VerifyCalls(), "");
 
@@ -175,7 +178,8 @@
     BEGIN_TEST;
 
     TestEthmacIfc dev;
-    ddk::EthmacIfcProxy proxy(dev.ethmac_ifc(), &dev);
+    const ethmac_ifc_t ifc = dev.ethmac_ifc();
+    ddk::EthmacIfcProxy proxy(&ifc);
 
     proxy.Status(0);
     proxy.Recv(nullptr, 0, 0);
@@ -200,12 +204,13 @@
     status = dev.DdkGetProtocol(ZX_PROTOCOL_ETHERNET_IMPL, reinterpret_cast<void*>(&proto));
     EXPECT_EQ(ZX_OK, status, "");
 
-    EXPECT_EQ(ZX_OK, proto.ops->query(proto.ctx, 0, nullptr), "");
+    EXPECT_EQ(ZX_OK, ethmac_query(&proto, 0, nullptr), "");
     proto.ops->stop(proto.ctx);
-    EXPECT_EQ(ZX_OK, proto.ops->start(proto.ctx, nullptr, nullptr), "");
+    ethmac_ifc_t ifc = {nullptr, nullptr};
+    EXPECT_EQ(ZX_OK, ethmac_start(&proto, &ifc), "");
     ethmac_netbuf_t netbuf = {};
-    EXPECT_EQ(ZX_OK, proto.ops->queue_tx(proto.ctx, 0, &netbuf), "");
-    EXPECT_EQ(ZX_OK, proto.ops->set_param(proto.ctx, 0, 0, nullptr), "");
+    EXPECT_EQ(ZX_OK, ethmac_queue_tx(&proto, 0, &netbuf), "");
+    EXPECT_EQ(ZX_OK, ethmac_set_param(&proto, 0, 0, nullptr, 0), "");
 
     EXPECT_TRUE(dev.VerifyCalls(), "");
 
@@ -227,13 +232,14 @@
     ddk::EthmacProtocolProxy proxy(&proto);
     // The EthmacIfc to hand to the parent device.
     TestEthmacIfc ifc_dev;
+    ethmac_ifc_t ifc = ifc_dev.ethmac_ifc();
 
     EXPECT_EQ(ZX_OK, proxy.Query(0, nullptr), "");
     proxy.Stop();
-    EXPECT_EQ(ZX_OK, proxy.Start(&ifc_dev), "");
+    EXPECT_EQ(ZX_OK, proxy.Start(&ifc), "");
     ethmac_netbuf_t netbuf = {};
     EXPECT_EQ(ZX_OK, proxy.QueueTx(0, &netbuf), "");
-    EXPECT_EQ(ZX_OK, proxy.SetParam(0, 0, nullptr));
+    EXPECT_EQ(ZX_OK, proxy.SetParam(0, 0, nullptr, 0));
 
     EXPECT_TRUE(protocol_dev.VerifyCalls(), "");