The Pedigree Project 0.1
modules/drivers/common/ahci/main.cc
1/*
2 * Copyright (c) 2026, Pedigree Developers
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "pedigree/kernel/Log.h"
18#include "pedigree/kernel/linker/KernelElf.h"
19#include "pedigree/kernel/machine/Machine.h"
20#include "pedigree/kernel/utilities/List.h"
21#include "pedigree/kernel/utilities/new"
22
23#include "AhciController.h"
24#include "modules/Module.h"
25
26namespace {
27List<Device*> candidates;
28List<AhciController*> controllers;
29
30void collect(Device* device) {
31 for (size_t i = 0; i < device->getNumChildren(); ++i) {
32 if (device->getChild(i)->getSpecificType() == String("ahci-controller"))
33 return;
34 }
35 candidates.pushBack(device);
36}
37
38Module::UnloadAdmission admitUnload(bool) {
39 for (auto* controller : controllers) {
40 if (!controller->prepareDiskRemoval()) {
41 for (auto* rollback : controllers)
42 rollback->cancelDiskRemoval();
43 return Module::UnloadAdmission::Busy;
44 }
45 }
46 return Module::UnloadAdmission::Ready;
47}
48
49bool entry() {
50 Device::searchByClassSubclassAndProgInterface(0x01, 0x06, 0x01, collect);
51 while (candidates.count()) {
52 Device* pci = candidates.popFront();
53 auto* controller = new AhciController(pci);
54 if (!controller->initialiseController()) {
55 controller->shutdown();
56 delete controller;
57 continue;
58 }
59 {
61 controller->setParent(pci);
62 pci->addChild(controller);
63 }
64 controllers.pushBack(controller);
65 }
66 if (!controllers.count()) {
67 NOTICE("AHCI: no supported SATA disks found");
68 return false;
69 }
70 return KernelElf::instance().registerUnloadAdmission(&entry, &admitUnload);
71}
72
73void exit() {
74 while (controllers.count()) {
75 AhciController* controller = controllers.popFront();
76 controller->shutdown();
77 Machine::setShutdownDetail("AHCI: removing controller from device tree");
78 {
80 controller->getParent()->removeChild(controller);
81 controller->setParent(nullptr);
82 }
83 Machine::setShutdownDetail("AHCI: releasing controller");
84 delete controller;
85 }
86}
87} // namespace
88
89MODULE_INFO("ahci", &entry, &exit, "pci", "scsi");
void addChild(Device *pDevice)
Definition Device.cc:135
Device * getParent() const
Definition Device.h:166
void setParent(Device *p)
Definition Device.h:170
void removeChild(size_t n)
Definition Device.cc:147
bool registerUnloadAdmission(ModuleEntry ownerEntry, Module::UnloadAdmissionHook hook)
static KernelElf & instance()
Definition KernelElf.h:135
Definition List.h:61
static void setShutdownDetail(const char *detail)
Definition Machine.cc:38
T popFront()
Definition List.h:330
size_t count() const
Definition List.h:212
void pushBack(const T &value)
Definition List.h:216