Files
ladybird/Kernel/Devices/Device.h
Liav A 6a9c717a30 Kernel: Expose device presence in /sys/dev/char and /sys/dev/block
These files are not marked as block devices or character devices so they
are not meant to be used as device nodes. The filenames are formatted to
the pattern "major:minor", but a Userland program need to call the parse
these format and inspect the the major and minor numbers and create the
real device nodes in /dev.

Later on, it might be a good idea to ensure we don't create new
SysFSComponents on the heap for each Device, but rather generate
them only when required (and preferably to not create a SysFSComponent
at all if possible).
2021-09-08 00:42:20 +02:00

89 lines
2.5 KiB
C++

/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
// Device is the base class of everything that lives in the /dev directory.
//
// To expose a Device to the filesystem, simply pass two unique numbers to the constructor,
// and then mknod a file in /dev with those numbers.
//
// There are two main subclasses:
// - BlockDevice (random access)
// - CharacterDevice (sequential)
#include <AK/DoublyLinkedList.h>
#include <AK/Function.h>
#include <AK/HashMap.h>
#include <AK/RefPtr.h>
#include <Kernel/Devices/AsyncDeviceRequest.h>
#include <Kernel/FileSystem/File.h>
#include <Kernel/FileSystem/SysFS.h>
#include <Kernel/Locking/Mutex.h>
#include <Kernel/UnixTypes.h>
namespace Kernel {
class Device : public File {
protected:
enum class State {
Normal,
BeingRemoved,
};
public:
virtual ~Device() override;
unsigned major() const { return m_major; }
unsigned minor() const { return m_minor; }
virtual String absolute_path(const OpenFileDescription&) const override;
virtual String absolute_path() const;
UserID uid() const { return m_uid; }
GroupID gid() const { return m_gid; }
virtual bool is_device() const override { return true; }
virtual void before_removing();
static void for_each(Function<void(Device&)>);
static Device* get_device(unsigned major, unsigned minor);
void process_next_queued_request(Badge<AsyncDeviceRequest>, const AsyncDeviceRequest&);
template<typename AsyncRequestType, typename... Args>
KResultOr<NonnullRefPtr<AsyncRequestType>> try_make_request(Args&&... args)
{
auto request = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) AsyncRequestType(*this, forward<Args>(args)...)));
SpinlockLocker lock(m_requests_lock);
bool was_empty = m_requests.is_empty();
m_requests.append(request);
if (was_empty)
request->do_start(move(lock));
return request;
}
protected:
Device(unsigned major, unsigned minor);
void set_uid(UserID uid) { m_uid = uid; }
void set_gid(GroupID gid) { m_gid = gid; }
static MutexProtected<HashMap<u32, Device*>>& all_devices();
private:
unsigned m_major { 0 };
unsigned m_minor { 0 };
UserID m_uid { 0 };
GroupID m_gid { 0 };
State m_state { State::Normal };
Spinlock m_requests_lock;
DoublyLinkedList<RefPtr<AsyncDeviceRequest>> m_requests;
WeakPtr<SysFSDeviceComponent> m_sysfs_component;
};
}