summaryrefslogtreecommitdiff
path: root/Kernel/Devices/PCISerialDevice.cpp
blob: 4ade853feeee3757baea97a35691d8376a0875ab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/*
 * Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include <Kernel/Devices/PCISerialDevice.h>
#include <Kernel/Sections.h>

namespace Kernel {

static SerialDevice* s_the = nullptr;

UNMAP_AFTER_INIT void PCISerialDevice::detect()
{
    size_t current_device_minor = 68;
    PCI::enumerate([&](const PCI::Address& address, PCI::ID id) {
        if (address.is_null())
            return;

        for (auto& board_definition : board_definitions) {
            if (board_definition.device_id != id)
                continue;

            auto bar_base = PCI::get_BAR(address, board_definition.pci_bar) & ~1;
            auto port_base = IOAddress(bar_base + board_definition.first_offset);
            for (size_t i = 0; i < board_definition.port_count; i++) {
                auto serial_device = new SerialDevice(port_base.offset(board_definition.port_size * i), current_device_minor++);
                if (board_definition.baud_rate != SerialDevice::Baud::Baud38400) // non-default baud
                    serial_device->set_baud(board_definition.baud_rate);

                // If this is the first port of the first pci serial device, store it as the debug PCI serial port (TODO: Make this configurable somehow?)
                if (!is_available())
                    s_the = serial_device;
                // NOTE: We intentionally leak the reference to serial_device here, as it is eternal
            }

            dmesgln("PCISerialDevice: Found {} @ {}", board_definition.name, address);
            return;
        }
    });
}

SerialDevice& PCISerialDevice::the()
{
    VERIFY(s_the);
    return *s_the;
}

bool PCISerialDevice::is_available()
{
    return s_the;
}

}