blob: 4c9ba374aa53306979db7c907d02434f4e2f0476 [file] [log] [blame]
// Copyright 2017 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>
// DDK PCI protocol support
//
// :: Proxy ::
//
// ddk::PciProtocolProxy is a simple wrapper around pci_protocol_t. It does not own the pointers
// passed to it.
//
// :: Mixin ::
//
// No mixins are defined, as it is not expected that there will be multiple implementations of the
// pci protocol.
//
// :: Example ::
//
// // A driver that communicates with a ZX_PROTOCOL_PCI device
// class MyDevice;
// using MyDeviceType = ddk::Device<MyDevice, /* ddk mixins */>;
//
// class MyDevice : public MyDeviceType {
// public:
// MyDevice(zx_device_t* parent)
// : MyDeviceType(parent) {}
//
// void DdkRelease() {
// // Clean up
// delete this;
// }
//
// 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));
//
// // 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");
// }
//
// private:
// fbl::unique_ptr<ddk::PciProtocolProxy> pci_;
// };
namespace ddk {
class PciProtocolProxy {
public:
PciProtocolProxy(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);
}
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);
}
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(int 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) {
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 ConfigRead(uint8_t offset, size_t width, uint32_t *value) {
return ops_->config_read(ctx_, offset, width, 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 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);
}
private:
pci_protocol_ops_t* ops_;
void* ctx_;
};
} // namespace ddk