1// Copyright 2016 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <stdio.h> 6#include <stdlib.h> 7#include <string.h> 8 9#include <ddk/binding.h> 10#include <ddk/debug.h> 11#include <ddk/device.h> 12#include <ddk/driver.h> 13#include <ddk/protocol/pci.h> 14 15#include <fbl/alloc_checker.h> 16#include <fbl/unique_ptr.h> 17 18#include <zircon/compiler.h> 19#include <zircon/types.h> 20 21#include "backends/pci.h" 22#include "block.h" 23#include "console.h" 24#include "device.h" 25#include "ethernet.h" 26#include "gpu.h" 27#include "input.h" 28#include "rng.h" 29 30extern "C" zx_status_t virtio_pci_bind(void* ctx, zx_device_t* bus_device, void** cookie) { 31 zx_status_t status; 32 pci_protocol_t pci; 33 34 // grab the pci device and configuration to pass to the backend 35 if (device_get_protocol(bus_device, ZX_PROTOCOL_PCI, &pci)) { 36 return ZX_ERR_INVALID_ARGS; 37 } 38 39 zx_pcie_device_info_t info; 40 status = pci_get_device_info(&pci, &info); 41 if (status != ZX_OK) { 42 return status; 43 } 44 45 zx::bti bti; 46 status = pci_get_bti(&pci, 0, bti.reset_and_get_address()); 47 if (status != ZX_OK) { 48 return status; 49 } 50 51 // Due to the similarity between Virtio 0.9.5 legacy devices and Virtio 1.0 52 // transitional devices we need to check whether modern capabilities exist. 53 // If no vendor capabilities are found then we will default to the legacy 54 // interface. 55 fbl::unique_ptr<virtio::Backend> backend = nullptr; 56 if (pci_get_first_capability(&pci, kPciCapIdVendor) != 0) { 57 zxlogf(SPEW, "virtio %02x:%02x.%1x using modern PCI backend\n", info.bus_id, info.dev_id, info.func_id); 58 backend.reset(new virtio::PciModernBackend(pci, info)); 59 } else { 60 zxlogf(SPEW, "virtio %02x:%02x.%1x using legacy PCI backend\n", info.bus_id, info.dev_id, info.func_id); 61 backend.reset(new virtio::PciLegacyBackend(pci, info)); 62 } 63 64 status = backend->Bind(); 65 if (status != ZX_OK) { 66 return status; 67 } 68 69 // Now that the backend for this device has been initialized we can 70 // compose a device based on the PCI device id 71 fbl::unique_ptr<virtio::Device> virtio_device = nullptr; 72 switch (info.device_id) { 73 case VIRTIO_DEV_TYPE_NETWORK: 74 case VIRTIO_DEV_TYPE_T_NETWORK: 75 virtio_device.reset(new virtio::EthernetDevice(bus_device, fbl::move(bti), 76 fbl::move(backend))); 77 break; 78 case VIRTIO_DEV_TYPE_BLOCK: 79 case VIRTIO_DEV_TYPE_T_BLOCK: 80 virtio_device.reset(new virtio::BlockDevice(bus_device, fbl::move(bti), 81 fbl::move(backend))); 82 break; 83 case VIRTIO_DEV_TYPE_CONSOLE: 84 case VIRTIO_DEV_TYPE_T_CONSOLE: 85 virtio_device.reset(new virtio::ConsoleDevice(bus_device, fbl::move(bti), 86 fbl::move(backend))); 87 break; 88 case VIRTIO_DEV_TYPE_GPU: 89 virtio_device.reset(new virtio::GpuDevice(bus_device, fbl::move(bti), fbl::move(backend))); 90 break; 91 case VIRTIO_DEV_TYPE_ENTROPY: 92 case VIRTIO_DEV_TYPE_T_ENTROPY: 93 virtio_device.reset(new virtio::RngDevice(bus_device, fbl::move(bti), fbl::move(backend))); 94 break; 95 case VIRTIO_DEV_TYPE_INPUT: 96 virtio_device.reset(new virtio::InputDevice(bus_device, fbl::move(bti), 97 fbl::move(backend))); 98 break; 99 default: 100 return ZX_ERR_NOT_SUPPORTED; 101 } 102 103 status = virtio_device->Init(); 104 if (status != ZX_OK) { 105 return status; 106 } 107 108 // if we're here, we're successful so drop the unique ptr ref to the object and let it live on 109 __UNUSED auto ptr = virtio_device.release(); 110 return ZX_OK; 111} 112