|
| 1 | +// This file is a part of the IncludeOS unikernel - www.includeos.org |
| 2 | +// |
| 3 | +// Copyright 2015 Oslo and Akershus University College of Applied Sciences |
| 4 | +// and Alfred Bratterud |
| 5 | +// |
| 6 | +// Licensed under the Apache License, Version 2.0 (the "License"); |
| 7 | +// you may not use this file except in compliance with the License. |
| 8 | +// You may obtain a copy of the License at |
| 9 | +// |
| 10 | +// http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | +// |
| 12 | +// Unless required by applicable law or agreed to in writing, software |
| 13 | +// distributed under the License is distributed on an "AS IS" BASIS, |
| 14 | +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 15 | +// See the License for the specific language governing permissions and |
| 16 | +// limitations under the License. |
| 17 | + |
| 18 | +#ifndef KERNEL_SOLO5_MANAGER_HPP |
| 19 | +#define KERNEL_SOLO5_MANAGER_HPP |
| 20 | + |
| 21 | +#include <vector> |
| 22 | +#include <cstdio> |
| 23 | +#include <unordered_map> |
| 24 | +#include <delegate> |
| 25 | + |
| 26 | +#include <hw/pci_device.hpp> |
| 27 | +#include <hw/devices.hpp> |
| 28 | + |
| 29 | +class Solo5_manager { |
| 30 | +private: |
| 31 | + using Device_registry = std::unordered_map<PCI::classcode, std::vector<hw::PCI_Device>>; |
| 32 | + |
| 33 | +public: |
| 34 | + template <PCI::classcode CLASS> |
| 35 | + static hw::PCI_Device& device(const int n) noexcept { |
| 36 | + return devices_[CLASS][n]; |
| 37 | + }; |
| 38 | + |
| 39 | + template <PCI::classcode CLASS> |
| 40 | + static size_t num_of_devices() noexcept { |
| 41 | + return devices_[CLASS].size(); |
| 42 | + } |
| 43 | + |
| 44 | + /** Whats being stored and returned is a unique_ptr of the given device */ |
| 45 | + template <typename Device_type> |
| 46 | + using Dev_ptr = std::unique_ptr<Device_type>; |
| 47 | + |
| 48 | + /** The function (factory) thats create the Dev_ptr from PCI_Device, supplied by the driver */ |
| 49 | + template <typename Device_type> |
| 50 | + using Driver_factory = delegate< Dev_ptr<Device_type>(hw::PCI_Device&) >; |
| 51 | + |
| 52 | + /** |
| 53 | + * @brief Register a specific type of driver factory |
| 54 | + * @details Register a specific type of driver factory |
| 55 | + * (function that creates a pointer to the given Device, with its full driver implementation) |
| 56 | + * Indexed as a combination of vendor + product |
| 57 | + * |
| 58 | + * @param vendor Driver vendor id |
| 59 | + * @param product Driver product id |
| 60 | + * @param driver_factory Function for creating a driver |
| 61 | + * @tparam Device_type The specific type of Device the driver is for |
| 62 | + */ |
| 63 | + template <typename Device_type> |
| 64 | + static void register_driver(uint16_t vendor, uint16_t product, |
| 65 | + Driver_factory<Device_type> driver_factory) |
| 66 | + { |
| 67 | + drivers<Device_type>().emplace(get_driver_id(vendor, product), driver_factory); |
| 68 | + } |
| 69 | + |
| 70 | + /** Currently a combination of Model + Product (we don't care about the revision etc. atm.)*/ |
| 71 | + using driver_id_t = uint32_t; |
| 72 | + |
| 73 | + /** Combine vendor and product id to represent a driver id */ |
| 74 | + static driver_id_t get_driver_id(uint16_t vendor, uint16_t product) |
| 75 | + { return (uint32_t)(vendor) << 16 | product; } |
| 76 | + |
| 77 | + static driver_id_t get_driver_id(hw::PCI_Device& dev) |
| 78 | + { return get_driver_id(dev.vendor_id(), dev.product_id()); } |
| 79 | + |
| 80 | +private: |
| 81 | + static Device_registry devices_; |
| 82 | + |
| 83 | + /** A register for a specific type of drivers: map[driver_id, driver_factory]*/ |
| 84 | + template <typename Device_type> |
| 85 | + using Driver_registry = std::unordered_map<driver_id_t, Driver_factory<Device_type> >; |
| 86 | + |
| 87 | + /** |
| 88 | + * @brief Retrieve drivers (factories) of a given type of device |
| 89 | + * |
| 90 | + * @return A collection of driver factories indexed by driver_id |
| 91 | + */ |
| 92 | + template <typename Device_type> |
| 93 | + static Driver_registry<Device_type>& drivers() { |
| 94 | + static Driver_registry<Device_type> drivers_; |
| 95 | + return drivers_; |
| 96 | + } |
| 97 | + |
| 98 | + template <typename Device_type> |
| 99 | + inline static bool register_device(hw::PCI_Device& dev); |
| 100 | + |
| 101 | + /** |
| 102 | + * Keep track of certain devices |
| 103 | + * |
| 104 | + * The PCI manager can probe and keep track of devices which can (possibly) |
| 105 | + * be specialized by the Dev-class later. |
| 106 | + */ |
| 107 | + static void init(); |
| 108 | + |
| 109 | + friend class OS; |
| 110 | +}; //< class Solo5_manager |
| 111 | + |
| 112 | +template <typename Device_type> |
| 113 | +inline bool Solo5_manager::register_device(hw::PCI_Device& dev) { |
| 114 | + try { |
| 115 | + auto driver_factory = drivers<Device_type>().at(get_driver_id(dev)); |
| 116 | + INFO2("| +--+ Driver: Found"); |
| 117 | + |
| 118 | + hw::Devices::register_device(driver_factory(dev)); |
| 119 | + return true; |
| 120 | + } catch(std::out_of_range) { |
| 121 | + INFO2("| +--+ Driver: Not found"); |
| 122 | + } |
| 123 | + return false; |
| 124 | +} |
| 125 | + |
| 126 | +#endif //< KERNEL_SOLO5_MANAGER_HPP |
0 commit comments