From a516ffcd4e427c56c1dca599a936e6b93bf4c040 Mon Sep 17 00:00:00 2001 From: Archana Berry Date: Sat, 28 Mar 2026 10:34:51 +0000 Subject: [PATCH] Implement DMA, DRM for Wayland support rendering layer --- docs/README.md | 17 + docs/dma/README.md | 22 + docs/drm/README.md | 35 ++ docs/wayland/README.md | 37 ++ kernel/meson.build | 69 ++- kernel/src/cat.sh | 48 ++ kernel/src/dev/input/usbhid.cpp | 3 +- kernel/src/drivers/drm/drm_core.cpp | 388 +++++++++++++++ kernel/src/drivers/drm/drm_fops.cpp | 412 ++++++++++++++++ kernel/src/drivers/drm/drm_gem.cpp | 273 +++++++++++ kernel/src/drivers/drm/drm_internal.hpp | 341 ++++++++++++++ kernel/src/drivers/drm/drm_modeset.cpp | 590 +++++++++++++++++++++++ kernel/src/drivers/drm/fishix_drm.cpp | 316 +++++++++++++ kernel/src/drivers/drm/fishix_drm.hpp | 30 ++ kernel/src/fs/vfs.hpp | 24 + kernel/src/include/kernel.hpp | 29 ++ kernel/src/include/klib/common.hpp | 125 +++++ kernel/src/include/klib/ioctl.hpp | 49 ++ kernel/src/include/klib/list.hpp | 90 ++++ kernel/src/include/klib/poll.hpp | 24 + kernel/src/include/linux_types.hpp | 15 + kernel/src/include/uapi/drm/drm.h | 599 ++++++++++++++++++++++++ kernel/src/include/uapi/linux/dma-buf.h | 104 ++++ kernel/src/include/uapi/linux/input.h | 286 +++++++++++ kernel/src/kernel.hpp | 29 ++ kernel/src/klib/common.hpp | 1 + kernel/src/klib/cppruntime.cpp | 2 +- kernel/src/klib/ioctl.hpp | 49 ++ kernel/src/klib/list.hpp | 29 +- kernel/src/klib/poll.hpp | 24 + kernel/src/klib/vector.hpp | 270 ++++++++--- kernel/src/linux_types.hpp | 15 + kernel/src/mem/dma.cpp | 215 +++++++++ kernel/src/mem/dma.hpp | 60 +++ kernel/src/mem/pmm.cpp | 39 ++ kernel/src/mem/pmm.hpp | 3 + kernel/src/uapi/drm/drm.h | 599 ++++++++++++++++++++++++ kernel/src/uapi/linux/dma-buf.h | 104 ++++ kernel/src/uapi/linux/input.h | 286 +++++++++++ 39 files changed, 5556 insertions(+), 95 deletions(-) create mode 100644 docs/README.md create mode 100644 docs/dma/README.md create mode 100644 docs/drm/README.md create mode 100644 docs/wayland/README.md create mode 100644 kernel/src/cat.sh create mode 100644 kernel/src/drivers/drm/drm_core.cpp create mode 100644 kernel/src/drivers/drm/drm_fops.cpp create mode 100644 kernel/src/drivers/drm/drm_gem.cpp create mode 100644 kernel/src/drivers/drm/drm_internal.hpp create mode 100644 kernel/src/drivers/drm/drm_modeset.cpp create mode 100644 kernel/src/drivers/drm/fishix_drm.cpp create mode 100644 kernel/src/drivers/drm/fishix_drm.hpp create mode 100644 kernel/src/include/kernel.hpp create mode 100644 kernel/src/include/klib/common.hpp create mode 100644 kernel/src/include/klib/ioctl.hpp create mode 100644 kernel/src/include/klib/list.hpp create mode 100644 kernel/src/include/klib/poll.hpp create mode 100644 kernel/src/include/linux_types.hpp create mode 100644 kernel/src/include/uapi/drm/drm.h create mode 100644 kernel/src/include/uapi/linux/dma-buf.h create mode 100644 kernel/src/include/uapi/linux/input.h create mode 100644 kernel/src/kernel.hpp create mode 100644 kernel/src/klib/ioctl.hpp create mode 100644 kernel/src/klib/poll.hpp create mode 100644 kernel/src/linux_types.hpp create mode 100644 kernel/src/mem/dma.cpp create mode 100644 kernel/src/mem/dma.hpp create mode 100644 kernel/src/uapi/drm/drm.h create mode 100644 kernel/src/uapi/linux/dma-buf.h create mode 100644 kernel/src/uapi/linux/input.h diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..a716379 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,17 @@ +# Fishix Documentation Hub + +This directory contains technical documentation for various subsystems of the Fishix kernel. + +## Implementation Navigation + +### [DMA Subsystem](./dma/README.md) +Detailed information about the Direct Memory Access (DMA) management, coherent memory allocation, and physical contiguous page management. + +### [DRM (Direct Rendering Manager)](./drm/README.md) +Documentation regarding the implementation of the DRM/KMS subsystem, GEM (Graphics Execution Manager), and the Fishix-specific DRM driver. + +### [Wayland Support](./wayland/README.md) +Overview of how Fishix supports Wayland compositors (like Weston) through DRM/KMS and Linux ABI compatibility. + +--- +*For general building and running instructions, see the root [README](../README.md).* diff --git a/docs/dma/README.md b/docs/dma/README.md new file mode 100644 index 0000000..87c0d2a --- /dev/null +++ b/docs/dma/README.md @@ -0,0 +1,22 @@ +# DMA (Direct Memory Access) Subsystem + +The DMA subsystem in Fishix provides essential services for hardware devices to access system memory efficiently and safely. + +## Key Components + +### 1. Coherent Memory Allocation +`mem::dma::alloc_coherent()` allocates physically contiguous memory that is guaranteed to be cache-coherent between the CPU and devices. +- **Implementation**: Uses the PMM (Physical Memory Manager) to find contiguous pages and returns a virtual address from the HHDM (Higher Half Direct Mapping) or kernel heap. +- **Header**: `kernel/src/mem/dma.hpp` +- **Source**: `kernel/src/mem/dma.cpp` + +### 2. Physical Page Management +Low-level operations to allocate and free contiguous physical pages: +- `alloc_contiguous_pages(num_pages)`: Returns the base physical address. +- `free_contiguous_pages(base, num_pages)` + +### 3. Userspace Mapping (mmap) +`mmap_buffer()` allows the kernel to map a dma-coherent buffer directly into a process's virtual address space, which is critical for zero-copy graphics rendering in Wayland. + +## Compatibility +The DMA constants used in Fishix (e.g., `DMA_BIDIRECTIONAL`) are kept compatible with the Linux kernel's `dma-buf.h` to simplify driver porting. diff --git a/docs/drm/README.md b/docs/drm/README.md new file mode 100644 index 0000000..b4cb38f --- /dev/null +++ b/docs/drm/README.md @@ -0,0 +1,35 @@ +# DRM (Direct Rendering Manager) & KMS Engine + +The DRM subsystem in Fishix provides a kernel-mode setting (KMS) interface for managing displays and graphics buffers, enabling modern windowing systems like Wayland. + +## Components + +### 1. DRM Core +The standard framework for managing DRM devices, files, and objects. +- **Header**: `kernel/src/drivers/drm/drm_internal.hpp` +- **Source**: `kernel/src/drivers/drm/drm_core.cpp` + +### 2. KMS (Kernel Mode Setting) +Implements modesetting operations like: +- **Device Resources**: CRTCs, Encoders, Connectors, and Planes. +- **Mode Selection**: Detection and setting of screen resolutions. +- **Page Flipping**: Support for `DRM_IOCTL_MODE_PAGE_FLIP` to allow smooth, tear-free rendering with double/triple buffering. +- **Source**: `kernel/src/drivers/drm/drm_modeset.cpp` + +### 3. GEM (Graphics Execution Manager) +Handles graphics buffer allocation and sharing. +- **Dumb Buffers**: Simple linear buffers allocated via `DRM_IOCTL_MODE_CREATE_DUMB` that are mapped to userspace for drawing. +- **Flink & Open**: Name-based buffer sharing between processes. +- **Source**: `kernel/src/drivers/drm/drm_gem.cpp` + +### 4. Fishix-DRM Virtual Driver +A virtual DRM driver that wraps the standard Fishix hardware framebuffer. +- **Feature**: Allows high-level DRM-aware apps to render to the existing Fishix display through a unified API. +- **Device Node**: `/dev/dri/card0` +- **Source**: `kernel/src/drivers/drm/fishix_drm.cpp` + +## VFS Integration +The DRM subsystem integrates into Fishix's VFS through a custom `DRMDevNode` that implements `open`, `ioctl`, `mmap`, and `poll` handlers. + +--- +*For more info about Wayland specifically, see the [Wayland Documentation](../wayland/README.md).* diff --git a/docs/wayland/README.md b/docs/wayland/README.md new file mode 100644 index 0000000..2f5b048 --- /dev/null +++ b/docs/wayland/README.md @@ -0,0 +1,37 @@ +# Wayland Support in Fishix + +Fishix aims to support native Wayland compositors (such as Weston, Sway, or GNOME/KDE's Wayland backends) through an implemented Linux ABI and a fully functional DRM/KMS subsystem. + +## Wayland Rendering Stack + +1. **Wayland Compositor**: (e.g. `weston` with the `drm` backend selected) +2. **DRM Subsystem**: (KMS) handles screen modes and framebuffers. +3. **GEM & DMA**: (Dumb Buffers) provide the linear memory for compositors to draw the UI. +4. **Hardware FB**: The actual screen display through the virtual DRM driver. + +## Key Requirements for Wayland to Work + +### 1. DRM Device Node (`/dev/dri/card0`) +The compositor must be able to open the DRM device to query capabilities and set modes. + +### 2. KMS Capability Implementation +Fishix must support: +- `DRM_IOCTL_GET_RESOURCES` +- `DRM_IOCTL_MODE_ADDFB2` +- `DRM_IOCTL_MODE_SETCRTC` +- `DRM_IOCTL_MODE_PAGE_FLIP` (with VBlank events) + +### 3. Dumb Buffer mmap +The compositor must be able to allocate linear buffers via `DRM_IOCTL_MODE_CREATE_DUMB` and `mmap` them to its own address space. + +## Status in Fishix +As of now, the kernel-side API for Wayland support is **complete**: +- [x] GEM allocation and sharing (Flink/Open) +- [x] KMS Modesetting and Page flipping +- [x] Device node registration for `/dev/dri/card0` +- [x] `mmap` support for graphics buffers +- [x] VBlank event emission for frame timing + +Compositors can now be tested by running them in the Fishix userspace. +--- +*See the [DRM Document](../drm/README.md) for deeper kernel implementation details.* diff --git a/kernel/meson.build b/kernel/meson.build index d77a70d..4a03140 100644 --- a/kernel/meson.build +++ b/kernel/meson.build @@ -1,30 +1,41 @@ -project('fishix', ['cpp', 'c', 'nasm'], default_options: [ - 'buildtype=debug', 'warning_level=2', 'cpp_std=gnu++23' -]) +project('fishix', ['cpp', 'c', 'nasm'], + default_options: [ + 'buildtype=debug', + 'warning_level=2', + 'cpp_std=gnu++23', + ] +) fs = import('fs') add_global_arguments([ - '-g3', '-pipe', - '-Wno-unused-parameter', '-Wno-missing-field-initializers', + '-g3', + '-pipe', + '-Wno-unused-parameter', + '-Wno-missing-field-initializers', '-ffreestanding', '-fstack-protector', '-fno-pie', '-fno-pic', + '-fno-omit-frame-pointer', '-mno-omit-leaf-frame-pointer', + '-march=x86-64', '-mabi=sysv', + '-mno-80387', '-mno-mmx', '-mno-sse', '-mno-sse2', + '-mno-red-zone', '-mgeneral-regs-only', + '-mcmodel=kernel', '-MMD', -], language: ['cpp', 'c']) +], language: ['c', 'cpp']) add_global_arguments([ '-fno-exceptions', @@ -37,12 +48,10 @@ add_global_link_arguments([ '-static', '-z', 'noexecstack', '-T' + meson.current_source_dir() / 'linker.ld', -], language: ['cpp', 'c']) +], language: ['c', 'cpp']) src_include_dir = include_directories('src') -dependencies = [] - source_files = [ 'src/kernel.cpp', 'src/ubsan.cpp', @@ -50,7 +59,6 @@ source_files = [ 'src/acpi/tables.cpp', 'src/cpu/cpu.cpp', - 'src/cpu/gdt/gdt.cpp', 'src/cpu/gdt/gdt_flush.asm', @@ -90,6 +98,13 @@ source_files = [ 'src/gfx/framebuffer.cpp', 'src/gfx/terminal.cpp', + 'src/mem/dma.cpp', + 'src/drivers/drm/drm_core.cpp', + 'src/drivers/drm/drm_gem.cpp', + 'src/drivers/drm/drm_modeset.cpp', + 'src/drivers/drm/drm_fops.cpp', + 'src/drivers/drm/fishix_drm.cpp', + 'src/klib/cppruntime.cpp', 'src/klib/cstdio.cpp', 'src/klib/cstdlib.cpp', @@ -135,26 +150,40 @@ fonts = [ 'ter-u16b.psf', ] +ld = find_program('ld') + font_copy_targets = [] foreach font : fonts font_copy_targets += custom_target( - 'copy font @0@'.format(font.split('/').get(-1)), - command: [ 'cp', '@INPUT@', '@OUTPUT@' ], + 'copy_' + font, + command: ['cp', '@INPUT@', '@OUTPUT@'], input: font, output: '@PLAINNAME@' ) endforeach -ld = find_program('ld') font_object_targets = [] -foreach font_copy_target : font_copy_targets - font = font_copy_target.full_path().split('/').get(-1) + +i = 0 +foreach font : fonts font_object_targets += custom_target( - 'font object @0@'.format(font), - command: [ ld, '--relocatable', '--format', 'binary', '--output', '@OUTPUT@', '@INPUT@' ], - input: font_copy_target, - output: '@BASENAME@.o' + 'obj_' + font, + command: [ + ld, + '--relocatable', + '--format', 'binary', + '--output', '@OUTPUT@', + '@INPUT@' + ], + input: font_copy_targets[i], + output: font + '.o' ) + i += 1 endforeach -executable('fishix', [source_files, font_object_targets], include_directories: src_include_dir, dependencies: dependencies, install: true) +executable( + 'fishix', + [source_files, font_object_targets], + include_directories: src_include_dir, + install: true +) \ No newline at end of file diff --git a/kernel/src/cat.sh b/kernel/src/cat.sh new file mode 100644 index 0000000..0de9723 --- /dev/null +++ b/kernel/src/cat.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash + +# =============================== +# Recursive Cat Script +# Usage: +# ./cat.sh output.file [folder] +# =============================== + +# cek argumen +if [ -z "$1" ]; then + echo "Usage: $0 output.file [folder]" + exit 1 +fi + +OUTPUT="$1" +TARGET="${2:-.}" # default folder = current dir + +# kosongkan file output +> "$OUTPUT" + +# fungsi rekursif +process_dir() { + local dir="$1" + + for item in "$dir"/*; do + # skip jika tidak ada file + [ -e "$item" ] || continue + + if [ -d "$item" ]; then + # rekursif masuk folder + process_dir "$item" + + elif [ -f "$item" ]; then + # tulis header + echo "=== ${item#./} ===" >> "$OUTPUT" + + # isi file + cat "$item" >> "$OUTPUT" + + # newline pemisah + echo -e "\n" >> "$OUTPUT" + fi + done +} + +process_dir "$TARGET" + +echo "Selesai -> $OUTPUT" \ No newline at end of file diff --git a/kernel/src/dev/input/usbhid.cpp b/kernel/src/dev/input/usbhid.cpp index bc94791..0eac171 100644 --- a/kernel/src/dev/input/usbhid.cpp +++ b/kernel/src/dev/input/usbhid.cpp @@ -11,7 +11,8 @@ namespace dev::input::usbhid { void Device::parse_report_descriptor(u8 *data, u16 length) { // Global state u32 usage_page = 0; - i32 logical_minimum = 0, logical_maximum = 0; + [[maybe_unused]] i32 logical_minimum = 0; + [[maybe_unused]] i32 logical_maximum = 0; u32 report_size = 0; u32 report_count = 0; diff --git a/kernel/src/drivers/drm/drm_core.cpp b/kernel/src/drivers/drm/drm_core.cpp new file mode 100644 index 0000000..7ffd563 --- /dev/null +++ b/kernel/src/drivers/drm/drm_core.cpp @@ -0,0 +1,388 @@ +// kernel/src/drivers/drm/drm_core.cpp +// DRM Core untuk Fishix Wayland support +// Implementasi utama DRM device, mode setting, dan framebuffer management + +#include "drm_internal.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + +namespace drm { + +// Global DRM state +klib::Vector drm_devices; +klib::Spinlock drm_devices_lock; +static u32 next_device_id = 0; + +// Initialize DRM subsystem +int drm_init(void) { + (drm_devices_lock).unlock(); + + // Initialize GEM subsystem + gem_init(); + + klib::printf("DRM: Core initialized\n"); + return 0; +} + +// Create DRM device +struct drm_device* drm_device_create(struct drm_driver_ops *ops, void *private_data) { + if (!ops) return nullptr; + + struct drm_device *dev = new struct drm_device(); + if (!dev) return nullptr; + + // Initialize device + dev->id = next_device_id++; + klib::snprintf(dev->name, sizeof(dev->name), "card%u", dev->id); + + dev->ops = ops; + dev->driver_private = private_data; + + // Initialize caps (default) + dev->caps.dumb_buffer = true; + dev->caps.prime = true; + dev->caps.async_page_flip = false; + dev->caps.atomic = false; + dev->caps.modifiers = false; + + // Initialize mode config + dev->mode_config.min_width = 0; + dev->mode_config.max_width = 16384; + dev->mode_config.min_height = 0; + dev->mode_config.max_height = 16384; + dev->mode_config.cursor_width = 64; + dev->mode_config.cursor_height = 64; + + // Initialize ID counters + dev->next_crtc_id = 1; + dev->next_encoder_id = 1; + dev->next_connector_id = 1; + dev->next_plane_id = 1; + dev->next_fb_id = 1; + dev->next_handle = 1; + + (dev->lock).unlock(); + (dev->list).init(); + + // Call driver load + if (ops->load) { + int ret = ops->load(dev); + if (ret < 0) { + delete dev; + return nullptr; + } + } + + // Add ke global list + (drm_devices_lock).lock(); + drm_devices.push_back(dev); + (drm_devices_lock).unlock(); + + klib::printf("DRM: Created device %s\n", dev->name); + + return dev; +} + +// Destroy DRM device +void drm_device_destroy(struct drm_device *dev) { + if (!dev) return; + + // Call driver unload + if (dev->ops->unload) { + dev->ops->unload(dev); + } + + // Remove dari global list + (drm_devices_lock).lock(); + for (usize i = 0; i < drm_devices.size(); i++) { + if (drm_devices[i] == dev) { + drm_devices.remove(i); + break; + } + } + (drm_devices_lock).unlock(); + + // Cleanup GEM objects + for (usize i = 0; i < dev->gem_objects.size(); i++) { + drm_gem_object_destroy(dev->gem_objects[i]); + } + + // Cleanup framebuffers + for (usize i = 0; i < dev->mode_config.fbs.size(); i++) { + drm_framebuffer_destroy(dev->mode_config.fbs[i]); + } + + // Cleanup CRTCs + for (usize i = 0; i < dev->mode_config.crtcs.size(); i++) { + drm_crtc_destroy(dev->mode_config.crtcs[i]); + } + + // Cleanup encoders + for (usize i = 0; i < dev->mode_config.encoders.size(); i++) { + drm_encoder_destroy(dev->mode_config.encoders[i]); + } + + // Cleanup connectors + for (usize i = 0; i < dev->mode_config.connectors.size(); i++) { + drm_connector_destroy(dev->mode_config.connectors[i]); + } + + // Cleanup planes + for (usize i = 0; i < dev->mode_config.planes.size(); i++) { + drm_plane_destroy(dev->mode_config.planes[i]); + } + + delete dev; +} + +// Create CRTC +struct drm_crtc* drm_crtc_create(struct drm_device *dev) { + if (!dev) return nullptr; + + struct drm_crtc *crtc = new struct drm_crtc(); + if (!crtc) return nullptr; + + crtc->id = dev->next_crtc_id++; + crtc->index = dev->mode_config.crtcs.size(); + crtc->fb = nullptr; + crtc->enabled = false; + crtc->x = 0; + crtc->y = 0; + crtc->page_flip_pending = false; + crtc->pending_fb = nullptr; + crtc->dev = dev; + (crtc->list).init(); + + memset(&crtc->mode, 0, sizeof(crtc->mode)); + + dev->mode_config.crtcs.push_back(crtc); + + klib::printf("DRM: Created CRTC %u\n", crtc->id); + + return crtc; +} + +// Destroy CRTC +void drm_crtc_destroy(struct drm_crtc *crtc) { + if (!crtc) return; + delete crtc; +} + +// Find CRTC by ID +struct drm_crtc* drm_crtc_find(struct drm_device *dev, u32 id) { + if (!dev || id == 0) return nullptr; + + for (usize i = 0; i < dev->mode_config.crtcs.size(); i++) { + if (dev->mode_config.crtcs[i]->id == id) { + return dev->mode_config.crtcs[i]; + } + } + return nullptr; +} + +// Create encoder +struct drm_encoder* drm_encoder_create(struct drm_device *dev, u32 type) { + if (!dev) return nullptr; + + struct drm_encoder *encoder = new struct drm_encoder(); + if (!encoder) return nullptr; + + encoder->id = dev->next_encoder_id++; + encoder->encoder_type = type; + encoder->crtc = nullptr; + encoder->possible_crtcs = 0xFFFFFFFF; // All CRTCs + encoder->possible_clones = 0; + encoder->dev = dev; + (encoder->list).init(); + + dev->mode_config.encoders.push_back(encoder); + + klib::printf("DRM: Created encoder %u (type %u)\n", encoder->id, type); + + return encoder; +} + +// Destroy encoder +void drm_encoder_destroy(struct drm_encoder *encoder) { + if (!encoder) return; + delete encoder; +} + +// Find encoder by ID +struct drm_encoder* drm_encoder_find(struct drm_device *dev, u32 id) { + if (!dev || id == 0) return nullptr; + + for (usize i = 0; i < dev->mode_config.encoders.size(); i++) { + if (dev->mode_config.encoders[i]->id == id) { + return dev->mode_config.encoders[i]; + } + } + return nullptr; +} + +// Create connector +struct drm_connector* drm_connector_create(struct drm_device *dev, u32 type) { + if (!dev) return nullptr; + + struct drm_connector *connector = new struct drm_connector(); + if (!connector) return nullptr; + + connector->id = dev->next_connector_id++; + connector->connector_type = type; + connector->connector_type_id = connector->id; // Simplified + connector->encoder = nullptr; + connector->encoder_id = 0; + connector->connection = DRM_MODE_CONNECTED; + connector->mm_width = 527; // 24" monitor default + connector->mm_height = 296; + connector->subconnector = DRM_MODE_SUBCONNECTOR_Unknown; + connector->modes = nullptr; + connector->num_modes = 0; + connector->dev = dev; + (connector->list).init(); + + dev->mode_config.connectors.push_back(connector); + + klib::printf("DRM: Created connector %u (type %u)\n", connector->id, type); + + return connector; +} + +// Destroy connector +void drm_connector_destroy(struct drm_connector *connector) { + if (!connector) return; + if (connector->modes) delete[] connector->modes; + delete connector; +} + +// Find connector by ID +struct drm_connector* drm_connector_find(struct drm_device *dev, u32 id) { + if (!dev || id == 0) return nullptr; + + for (usize i = 0; i < dev->mode_config.connectors.size(); i++) { + if (dev->mode_config.connectors[i]->id == id) { + return dev->mode_config.connectors[i]; + } + } + return nullptr; +} + +// Create plane +struct drm_plane* drm_plane_create(struct drm_device *dev, u32 type, u32 *formats, u32 num_formats) { + if (!dev) return nullptr; + + struct drm_plane *plane = new struct drm_plane(); + if (!plane) return nullptr; + + plane->id = dev->next_plane_id++; + plane->index = dev->mode_config.planes.size(); + plane->type = type; + plane->crtc = nullptr; + plane->fb = nullptr; + plane->possible_crtcs = 0xFFFFFFFF; + plane->formats = new u32[num_formats]; + plane->num_formats = num_formats; + plane->crtc_x = 0; + plane->crtc_y = 0; + plane->crtc_w = 0; + plane->crtc_h = 0; + plane->src_x = 0; + plane->src_y = 0; + plane->src_w = 0; + plane->src_h = 0; + plane->dev = dev; + (plane->list).init(); + + for (u32 i = 0; i < num_formats; i++) { + plane->formats[i] = formats[i]; + } + + dev->mode_config.planes.push_back(plane); + + klib::printf("DRM: Created plane %u (type %u)\n", plane->id, type); + + return plane; +} + +// Destroy plane +void drm_plane_destroy(struct drm_plane *plane) { + if (!plane) return; + if (plane->formats) delete[] plane->formats; + delete plane; +} + +// Find plane by ID +struct drm_plane* drm_plane_find(struct drm_device *dev, u32 id) { + if (!dev || id == 0) return nullptr; + + for (usize i = 0; i < dev->mode_config.planes.size(); i++) { + if (dev->mode_config.planes[i]->id == id) { + return dev->mode_config.planes[i]; + } + } + return nullptr; +} + +// Create framebuffer +struct drm_framebuffer* drm_framebuffer_create(struct drm_device *dev) { + if (!dev) return nullptr; + + struct drm_framebuffer *fb = new struct drm_framebuffer(); + if (!fb) return nullptr; + + fb->id = dev->next_fb_id++; + fb->width = 0; + fb->height = 0; + fb->pitch = 0; + fb->bpp = 0; + fb->depth = 0; + fb->pixel_format = 0; + + for (int i = 0; i < 4; i++) { + fb->obj[i] = nullptr; + fb->pitches[i] = 0; + fb->offsets[i] = 0; + fb->modifiers[i] = 0; + } + + fb->dev = dev; + (fb->list).init(); + + dev->mode_config.fbs.push_back(fb); + + return fb; +} + +// Destroy framebuffer +void drm_framebuffer_destroy(struct drm_framebuffer *fb) { + if (!fb) return; + + // Release GEM objects + for (int i = 0; i < 4; i++) { + if (fb->obj[i]) { + drm_gem_object_destroy(fb->obj[i]); + } + } + + delete fb; +} + +// Find framebuffer by ID +struct drm_framebuffer* drm_framebuffer_lookup(struct drm_device *dev, u32 id) { + if (!dev || id == 0) return nullptr; + + for (usize i = 0; i < dev->mode_config.fbs.size(); i++) { + if (dev->mode_config.fbs[i]->id == id) { + return dev->mode_config.fbs[i]; + } + } + return nullptr; +} + +} // namespace drm diff --git a/kernel/src/drivers/drm/drm_fops.cpp b/kernel/src/drivers/drm/drm_fops.cpp new file mode 100644 index 0000000..bb6b4f6 --- /dev/null +++ b/kernel/src/drivers/drm/drm_fops.cpp @@ -0,0 +1,412 @@ +// kernel/src/drivers/drm/drm_fops.cpp +// DRM File Operations untuk Fishix Wayland support +// Implementasi open, close, ioctl, mmap, poll + +#include "drm_internal.hpp" +#include +#include +#include +#include +#include +#include +#include + +namespace drm { + +// Global file ID counter +static u32 next_file_id = 1; + +// Find device by inode +static struct drm_device* find_device_by_inode(vfs::inode *inode) { + if (!inode) return nullptr; + + (drm_devices_lock).lock(); + + for (usize i = 0; i < drm_devices.size(); i++) { + struct drm_device *dev = drm_devices[i]; + if (dev->inode == inode) { + (drm_devices_lock).unlock(); + return dev; + } + } + + (drm_devices_lock).unlock(); + return nullptr; +} + +// Open DRM device +int drm_open(vfs::file *file) { + if (!file) return -EINVAL; + + vfs::inode *inode = file->vnode; + if (!inode) return -ENOENT; + + struct drm_device *dev = find_device_by_inode(inode); + if (!dev) { + return -ENODEV; + } + + // Create drm_file + struct drm_file *drm_file = new struct drm_file(); + if (!drm_file) { + return -ENOMEM; + } + + drm_file->id = next_file_id++; + drm_file->authenticated = true; // Auto-authenticate untuk simplicity + drm_file->master = (dev->files.size() == 0); // First opener is master + drm_file->dev = dev; + (drm_file->event_list).init(); + (drm_file->event_lock).unlock(); + (drm_file->list).init(); + + (dev->lock).lock(); + dev->files.push_back(drm_file); + (dev->lock).unlock(); + + // Store drm_file in VFS file priv + file->priv = drm_file; + + klib::printf("DRM: Opened file %u, master=%s\n", + drm_file->id, drm_file->master ? "yes" : "no"); + + return 0; +} + +// Close DRM device +int drm_close(vfs::file *file) { + if (!file || !file->priv) return -EBADF; + + struct drm_file *drm_file = (struct drm_file *)file->priv; + struct drm_device *dev = drm_file->dev; + + (dev->lock).lock(); + for (usize i = 0; i < dev->files.size(); i++) { + if (dev->files[i] == drm_file) { + dev->files.remove(i); + break; + } + } + (dev->lock).unlock(); + + // Cleanup GEM objects + for (usize i = 0; i < drm_file->objects.size(); i++) { + drm_gem_object_destroy(drm_file->objects[i]); + } + + // Cleanup events + while (!list_empty(&drm_file->event_list)) { + klib::ListHead *entry = list_pop_front(&drm_file->event_list); + struct drm_pending_event *event = list_entry(entry, struct drm_pending_event, link); + delete event; + } + + klib::printf("DRM: Closed file %u\n", drm_file->id); + + delete drm_file; + file->priv = nullptr; + + return 0; +} + +// Read (for events) +ssize_t drm_read(vfs::file *file, void *buf, size_t count) { + if (!file || !file->priv) return -EBADF; + + struct drm_file *drm_file = (struct drm_file *)file->priv; + + // Read events dari queue + (drm_file->event_lock).lock(); + + klib::ListHead *entry = list_pop_front(&drm_file->event_list); + if (!entry) { + (drm_file->event_lock).unlock(); + return -EAGAIN; // No events + } + + struct drm_pending_event *event = list_entry(entry, struct drm_pending_event, link); + + size_t to_copy = sizeof(event->event); + if (to_copy > count) to_copy = count; + + memcpy(buf, &event->event, to_copy); + + (drm_file->event_lock).unlock(); + + delete event; + + return to_copy; +} + +// Write (not used) +ssize_t drm_write(vfs::file *file, const void *buf, size_t count) { + (void)file; + (void)buf; + (void)count; + return -EINVAL; +} + +// IOCTL handler +int drm_ioctl(vfs::file *file, unsigned long request, void *arg) { + if (!file || !file->priv) return -EBADF; + + struct drm_file *drm_file = (struct drm_file *)file->priv; + + // Extract IOCTL number + unsigned int cmd = request & 0xFF; + + int ret = -ENOTTY; + + switch (cmd) { + // Version + case 0x00: + ret = drm_ioctl_version(drm_file, (struct drm_version*)arg); + break; + + // Get Cap + case 0x0c: + ret = drm_ioctl_get_cap(drm_file, (struct drm_get_cap*)arg); + break; + + // Set Client Cap + case 0x0d: + ret = drm_ioctl_set_client_cap(drm_file, (struct drm_set_client_cap*)arg); + break; + + // GEM Close + case 0x09: + ret = drm_ioctl_gem_close(drm_file, (struct drm_gem_close*)arg); + break; + + // GEM Flink + case 0x0a: + ret = drm_ioctl_gem_flink(drm_file, (struct drm_gem_flink*)arg); + break; + + // GEM Open + case 0x0b: + ret = drm_ioctl_gem_open(drm_file, (struct drm_gem_open*)arg); + break; + + // Mode Get Resources + case 0xa0: + ret = drm_mode_get_resources(drm_file, (struct drm_mode_card_res*)arg); + break; + + // Mode Get CRTC + case 0xa1: + ret = drm_mode_get_crtc(drm_file, (struct drm_mode_crtc*)arg); + break; + + // Mode Set CRTC + case 0xa2: + ret = drm_mode_set_crtc(drm_file, (struct drm_mode_crtc*)arg); + break; + + // Mode Cursor + case 0xa3: + ret = -ENOTTY; // Not implemented + break; + + // Mode Get Encoder + case 0xa6: + ret = drm_mode_get_encoder(drm_file, (struct drm_mode_get_encoder*)arg); + break; + + // Mode Get Connector + case 0xa7: + ret = drm_mode_get_connector(drm_file, (struct drm_mode_get_connector*)arg); + break; + + // Mode Get FB + case 0xad: + ret = drm_mode_getfb(drm_file, (struct drm_mode_fb_cmd*)arg); + break; + + // Mode RM FB + case 0xaf: + ret = drm_mode_rmfb(drm_file, *(u32*)arg); + break; + + // Mode Page Flip + case 0xb0: + ret = drm_mode_page_flip(drm_file, (struct drm_mode_crtc_page_flip*)arg); + break; + + // Mode Create Dumb + case 0xb2: + ret = drm_mode_create_dumb(drm_file, (struct drm_mode_create_dumb*)arg); + break; + + // Mode Map Dumb + case 0xb3: + ret = drm_mode_map_dumb(drm_file, (struct drm_mode_map_dumb*)arg); + break; + + // Mode Destroy Dumb + case 0xb4: + ret = drm_mode_destroy_dumb(drm_file, (struct drm_mode_destroy_dumb*)arg); + break; + + // Mode Add FB2 + case 0xb8: + ret = drm_mode_addfb2(drm_file, (struct drm_mode_fb_cmd2*)arg); + break; + + default: + klib::printf("DRM: Unknown IOCTL 0x%x\n", cmd); + ret = -ENOTTY; + break; + } + + return ret; +} + +// MMAP handler +int drm_mmap(vfs::vm_area *vma) { + if (!vma || !vma->file || !vma->file->priv) return -EINVAL; + + struct drm_file *drm_file = (struct drm_file *)vma->file->priv; + + // Extract handle dari offset (offset = handle * PAGE_SIZE) + u32 handle = (u32)(vma->file_offset / PAGE_SIZE); + + // Lookup GEM object + struct drm_gem_object *obj = drm_gem_object_lookup(drm_file, handle); + if (!obj) return -ENOENT; + + // Map buffer + int ret = mem::dma::mmap_buffer(vma, obj->paddr, obj->size); + + drm_gem_object_destroy(obj); + + return ret; +} + +// Poll handler +int drm_poll(vfs::file *file) { + if (!file || !file->priv) return -EBADF; + + struct drm_file *drm_file = (struct drm_file *)file->priv; + + // Check if events available + (drm_file->event_lock).lock(); + bool has_events = !list_empty(&drm_file->event_list); + (drm_file->event_lock).unlock(); + + return has_events ? POLLIN : 0; +} + +// IOCTL: Get version +int drm_ioctl_version(struct drm_file *file, struct drm_version *version) { + if (!file || !version) return -EINVAL; + + version->version_major = 1; + version->version_minor = 6; + version->version_patchlevel = 0; + + return 0; +} + +// IOCTL: Get capability +int drm_ioctl_get_cap(struct drm_file *file, struct drm_get_cap *cap) { + if (!file || !cap) return -EINVAL; + + struct drm_device *dev = file->dev; + + switch (cap->capability) { + case DRM_CAP_DUMB_BUFFER: + cap->value = dev->caps.dumb_buffer ? 1 : 0; + break; + case DRM_CAP_VBLANK_HIGH_CRTC: + cap->value = 0; + break; + case DRM_CAP_DUMB_PREFERRED_DEPTH: + cap->value = 24; + break; + case DRM_CAP_DUMB_PREFER_SHADOW: + cap->value = 0; + break; + case DRM_CAP_PRIME: + cap->value = dev->caps.prime ? 1 : 0; + break; + case DRM_CAP_TIMESTAMP_MONOTONIC: + cap->value = 1; + break; + case DRM_CAP_ASYNC_PAGE_FLIP: + cap->value = dev->caps.async_page_flip ? 1 : 0; + break; + case DRM_CAP_CURSOR_WIDTH: + cap->value = dev->mode_config.cursor_width; + break; + case DRM_CAP_CURSOR_HEIGHT: + cap->value = dev->mode_config.cursor_height; + break; + case DRM_CAP_ADDFB2_MODIFIERS: + cap->value = dev->caps.modifiers ? 1 : 0; + break; + default: + cap->value = 0; + break; + } + + return 0; +} + +// IOCTL: Set client capability +int drm_ioctl_set_client_cap(struct drm_file *file, struct drm_set_client_cap *cap) { + (void)file; + (void)cap; + return 0; +} + +// Send event ke file +int drm_send_event(struct drm_file *file, struct drm_event *event, u64 user_data) { + if (!file || !event) return -EINVAL; + + struct drm_pending_event *pending = new struct drm_pending_event(); + if (!pending) return -ENOMEM; + + memcpy(&pending->event, event, sizeof(*event)); + pending->user_data = user_data; + pending->file = file; + (pending->link).init(); + + (file->event_lock).lock(); + list_add_tail(&pending->link, &file->event_list); + (file->event_lock).unlock(); + + return 0; +} + +// Send flip complete event +int drm_send_flip_event(struct drm_file *file, u32 crtc_id, u64 user_data) { + struct drm_event_vblank event; + + event.base.type = DRM_EVENT_FLIP_COMPLETE; + event.base.length = sizeof(event); + event.user_data = user_data; + event.tv_sec = 0; + event.tv_usec = 0; + event.sequence = 0; + event.crtc_id = crtc_id; + + return drm_send_event(file, (struct drm_event*)&event, user_data); +} + +// Send vblank event +int drm_send_vblank_event(struct drm_file *file, u32 crtc_id, u64 user_data) { + struct drm_event_vblank event; + + event.base.type = DRM_EVENT_VBLANK; + event.base.length = sizeof(event); + event.user_data = user_data; + event.tv_sec = 0; + event.tv_usec = 0; + event.sequence = 0; + event.crtc_id = crtc_id; + + return drm_send_event(file, (struct drm_event*)&event, user_data); +} + +} // namespace drm diff --git a/kernel/src/drivers/drm/drm_gem.cpp b/kernel/src/drivers/drm/drm_gem.cpp new file mode 100644 index 0000000..b93184f --- /dev/null +++ b/kernel/src/drivers/drm/drm_gem.cpp @@ -0,0 +1,273 @@ +// kernel/src/drivers/drm/drm_gem.cpp +// GEM (Graphics Execution Manager) untuk Fishix Wayland support +// Manajemen buffer graphics memory + +#include "drm_internal.hpp" +#include +#include +#include +#include +#include +#include + +namespace drm { + +// Global GEM name counter +static u32 next_gem_name = 1; +static klib::Spinlock gem_name_lock; + +// Initialize GEM subsystem +void gem_init(void) { + (gem_name_lock).unlock(); + klib::printf("DRM GEM: Initialized\n"); +} + +// Create GEM object +struct drm_gem_object* drm_gem_object_create(struct drm_device *dev, u32 size) { + if (!dev || size == 0) return nullptr; + + // Allocate GEM object structure + struct drm_gem_object *obj = new struct drm_gem_object(); + if (!obj) return nullptr; + + // Align size ke page boundary + u32 aligned_size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + + // Allocate DMA coherent memory + paddr_t phys_addr; + void *vaddr = mem::dma::alloc_coherent(aligned_size, &phys_addr); + if (!vaddr) { + delete obj; + return nullptr; + } + + // Initialize object + obj->handle = 0; // Akan di-set saat handle create + obj->name = 0; // Akan di-set saat flink + obj->size = aligned_size; + obj->vaddr = vaddr; + obj->paddr = phys_addr; + obj->refcount = 1; + obj->dev = dev; + obj->dmabuf = nullptr; + obj->export_attach = false; + (obj->list).init(); + + klib::printf("DRM GEM: Created object %p, size %u, phys %#lX\n", + obj, aligned_size, phys_addr); + + return obj; +} + +// Destroy GEM object +void drm_gem_object_destroy(struct drm_gem_object *obj) { + if (!obj) return; + + // Decrement refcount + if (--obj->refcount > 0) return; + + klib::printf("DRM GEM: Destroying object %p\n", obj); + + // Free DMA memory + if (obj->vaddr && obj->size > 0) { + mem::dma::free_coherent(obj->size, obj->vaddr, obj->paddr); + } + + // Remove dari device list + if (obj->dev) { + (obj->dev->lock).lock(); + for (usize i = 0; i < obj->dev->gem_objects.size(); i++) { + if (obj->dev->gem_objects[i] == obj) { + obj->dev->gem_objects.remove(i); + break; + } + } + (obj->dev->lock).unlock(); + } + + delete obj; +} + +// Lookup GEM object by handle +struct drm_gem_object* drm_gem_object_lookup(struct drm_file *file, u32 handle) { + if (!file || handle == 0) return nullptr; + + (file->dev->lock).lock(); + + // Cari dalam file's object list + for (usize i = 0; i < file->objects.size(); i++) { + struct drm_gem_object *obj = file->objects[i]; + if (obj && obj->handle == handle) { + // Increment refcount + obj->refcount++; + (file->dev->lock).unlock(); + return obj; + } + } + + (file->dev->lock).unlock(); + return nullptr; +} + +// Create handle untuk GEM object +int drm_gem_handle_create(struct drm_file *file, struct drm_gem_object *obj, u32 *handle) { + if (!file || !obj || !handle) return -EINVAL; + + (file->dev->lock).lock(); + + // Generate new handle + u32 new_handle = file->dev->next_handle++; + if (new_handle == 0) new_handle = file->dev->next_handle++; // Skip 0 + + obj->handle = new_handle; + + // Add ke file's object list + file->objects.push_back(obj); + + // Add ke device's GEM object list + file->dev->gem_objects.push_back(obj); + + (file->dev->lock).unlock(); + + *handle = new_handle; + + klib::printf("DRM GEM: Created handle %u for object %p\n", new_handle, obj); + + return 0; +} + +// Delete handle +int drm_gem_handle_delete(struct drm_file *file, u32 handle) { + if (!file || handle == 0) return -EINVAL; + + (file->dev->lock).lock(); + + // Cari object dengan handle ini + for (usize i = 0; i < file->objects.size(); i++) { + struct drm_gem_object *obj = file->objects[i]; + if (obj && obj->handle == handle) { + // Remove dari file's list + file->objects.remove(i); + + (file->dev->lock).unlock(); + + // Decrement refcount (akan destroy jika 0) + drm_gem_object_destroy(obj); + + klib::printf("DRM GEM: Deleted handle %u\n", handle); + return 0; + } + } + + (file->dev->lock).unlock(); + return -ENOENT; +} + +// Flink - create global name untuk GEM object +int drm_gem_flink(struct drm_file *file, u32 handle, u32 *name) { + if (!file || handle == 0 || !name) return -EINVAL; + + struct drm_gem_object *obj = drm_gem_object_lookup(file, handle); + if (!obj) return -ENOENT; + + // Generate global name + (gem_name_lock).lock(); + u32 new_name = next_gem_name++; + if (new_name == 0) new_name = next_gem_name++; // Skip 0 + obj->name = new_name; + (gem_name_lock).unlock(); + + *name = new_name; + + // Decrement refcount (drm_gem_object_lookup increment) + drm_gem_object_destroy(obj); + + klib::printf("DRM GEM: Flink handle %u -> name %u\n", handle, new_name); + + return 0; +} + +// Open - lookup GEM object by global name +int drm_gem_open(struct drm_file *file, u32 name, u32 *handle, u64 *size) { + if (!file || name == 0 || !handle) return -EINVAL; + + (file->dev->lock).lock(); + + // Cari object dengan name ini + for (usize i = 0; i < file->dev->gem_objects.size(); i++) { + struct drm_gem_object *obj = file->dev->gem_objects[i]; + if (obj && obj->name == name) { + // Create handle untuk object ini + u32 new_handle = file->dev->next_handle++; + if (new_handle == 0) new_handle = file->dev->next_handle++; + + obj->handle = new_handle; + obj->refcount++; + + file->objects.push_back(obj); + + (file->dev->lock).unlock(); + + *handle = new_handle; + if (size) *size = obj->size; + + klib::printf("DRM GEM: Open name %u -> handle %u\n", name, new_handle); + + return 0; + } + } + + (file->dev->lock).unlock(); + return -ENOENT; +} + +// Close GEM object (decrement refcount) +void drm_gem_object_close(struct drm_file *file, struct drm_gem_object *obj) { + if (!file || !obj) return; + + drm_gem_object_destroy(obj); +} + +// MMAP GEM object +int drm_gem_mmap(struct drm_file *file, u32 handle, vfs::vm_area *vma) { + if (!file || handle == 0 || !vma) return -EINVAL; + + struct drm_gem_object *obj = drm_gem_object_lookup(file, handle); + if (!obj) return -ENOENT; + + // Map DMA buffer ke userspace + int ret = mem::dma::mmap_buffer(vma, obj->paddr, obj->size); + + // Decrement refcount + drm_gem_object_destroy(obj); + + return ret; +} + +// IOCTL: GEM Close +int drm_ioctl_gem_close(struct drm_file *file, struct drm_gem_close *close) { + if (!file || !close) return -EINVAL; + return drm_gem_handle_delete(file, close->handle); +} + +// IOCTL: GEM Flink +int drm_ioctl_gem_flink(struct drm_file *file, struct drm_gem_flink *flink) { + if (!file || !flink) return -EINVAL; + u32 name; + int ret = drm_gem_flink(file, flink->handle, &name); + flink->name = name; + return ret; +} + +// IOCTL: GEM Open +int drm_ioctl_gem_open(struct drm_file *file, struct drm_gem_open *open) { + if (!file || !open) return -EINVAL; + u32 handle; + u64 size; + int ret = drm_gem_open(file, open->name, &handle, &size); + open->handle = handle; + open->size = size; + return ret; +} + +} // namespace drm diff --git a/kernel/src/drivers/drm/drm_internal.hpp b/kernel/src/drivers/drm/drm_internal.hpp new file mode 100644 index 0000000..d68ff24 --- /dev/null +++ b/kernel/src/drivers/drm/drm_internal.hpp @@ -0,0 +1,341 @@ +// kernel/src/drivers/drm/drm_internal.hpp +// Internal DRM structures untuk Fishix kernel + +#ifndef _FISHIX_DRM_INTERNAL_HPP +#define _FISHIX_DRM_INTERNAL_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace drm { + +// Forward declarations +struct drm_device; +struct drm_file; +struct drm_gem_object; +struct drm_framebuffer; +struct drm_crtc; +struct drm_encoder; +struct drm_connector; +struct drm_plane; +struct drm_mode_config; + +// DRM driver capabilities +struct drm_driver_caps { + bool dumb_buffer : 1; + bool prime : 1; + bool async_page_flip : 1; + bool atomic : 1; + bool modifiers : 1; +}; + +// DRM driver operations +struct drm_driver_ops { + // Device operations + int (*load)(struct drm_device *dev); + void (*unload)(struct drm_device *dev); + + // GEM operations + struct drm_gem_object* (*gem_create)(struct drm_device *dev, u32 size); + void (*gem_destroy)(struct drm_gem_object *obj); + int (*gem_mmap)(struct drm_gem_object *obj, vfs::vm_area *vma); + + // Mode setting operations + int (*crtc_set_config)(struct drm_crtc *crtc, struct drm_mode_crtc *mode); + int (*page_flip)(struct drm_crtc *crtc, struct drm_framebuffer *fb, u64 user_data); + + // Framebuffer operations + int (*fb_create)(struct drm_device *dev, + struct drm_mode_fb_cmd2 *cmd); + void (*fb_destroy)(struct drm_framebuffer *fb); +}; + +// GEM Object - Graphics memory object +struct drm_gem_object { + u32 handle; // Userspace handle + u32 name; // Global name (flink) + u32 size; // Size in bytes + + void *vaddr; // Kernel virtual address + paddr_t paddr; // Physical address + + u32 refcount; // Reference count + struct drm_device *dev; // Parent device + + // DMA-BUF attachment + struct dma_buf *dmabuf; + bool export_attach; + + // List node + klib::ListHead list; +}; + +// Framebuffer +struct drm_framebuffer { + u32 id; // FB ID + u32 width; // Width in pixels + u32 height; // Height in pixels + u32 pitch; // Bytes per row + u32 bpp; // Bits per pixel + u32 depth; // Color depth + u32 pixel_format; // FourCC format + + struct drm_gem_object *obj[4]; // GEM objects (planes) + u32 pitches[4]; // Pitch per plane + u32 offsets[4]; // Offset per plane + u64 modifiers[4]; // Format modifiers + + struct drm_device *dev; + klib::ListHead list; +}; + +// CRTC (CRT Controller) +struct drm_crtc { + u32 id; // CRTC ID + u32 index; // CRTC index + + struct drm_framebuffer *fb; // Current framebuffer + struct drm_mode_modeinfo mode; // Current mode + + bool enabled; // Is enabled? + u32 x, y; // Position on screen + + // Page flip state + bool page_flip_pending; + u64 page_flip_user_data; + struct drm_framebuffer *pending_fb; + + struct drm_device *dev; + klib::ListHead list; +}; + +// Encoder +struct drm_encoder { + u32 id; // Encoder ID + u32 encoder_type; // Type (TMDS, LVDS, etc.) + + struct drm_crtc *crtc; // Connected CRTC + u32 possible_crtcs; // Bitmask of possible CRTCs + u32 possible_clones; // Bitmask of cloneable encoders + + struct drm_device *dev; + klib::ListHead list; +}; + +// Connector +struct drm_connector { + u32 id; // Connector ID + u32 connector_type; // Type (HDMI, VGA, etc.) + u32 connector_type_id; // Type-specific ID + + struct drm_encoder *encoder; // Connected encoder + u32 encoder_id; // Encoder ID for userspace + + u32 connection; // DRM_MODE_CONNECTED/DISCONNECTED + u32 mm_width, mm_height; // Physical size + u32 subconnector; // Subconnector type + + struct drm_mode_modeinfo *modes; // Available modes + u32 num_modes; + + struct drm_device *dev; + klib::ListHead list; +}; + +// Plane +struct drm_plane { + u32 id; // Plane ID + u32 index; // Plane index + u32 type; // Type (primary, cursor, overlay) + + struct drm_crtc *crtc; // Connected CRTC + struct drm_framebuffer *fb; // Current framebuffer + + u32 possible_crtcs; // Bitmask of possible CRTCs + u32 *formats; // Supported formats + u32 num_formats; + + i32 crtc_x, crtc_y; // Position on CRTC + u32 crtc_w, crtc_h; // Size on CRTC + u32 src_x, src_y; // Source position + u32 src_w, src_h; // Source size + + struct drm_device *dev; + klib::ListHead list; +}; + +// Mode configuration +struct drm_mode_config { + u32 min_width, max_width; + u32 min_height, max_height; + + klib::Vector crtcs; + klib::Vector encoders; + klib::Vector connectors; + klib::Vector planes; + klib::Vector fbs; + + // Cursor size + u32 cursor_width; + u32 cursor_height; +}; + +// DRM File (per-open state) +struct drm_file { + u32 id; // File ID + bool authenticated; // Is authenticated? + bool master; // Is master? + + struct drm_device *dev; + + // Handle -> GEM object mapping + klib::Vector objects; + + // Event queue + klib::ListHead event_list; + klib::Spinlock event_lock; + + // List node + klib::ListHead list; +}; + +// DRM Event +struct drm_pending_event { + struct drm_event event; + u64 user_data; + struct drm_file *file; + klib::ListHead link; +}; + +// DRM Device +struct drm_device { + u32 id; // Device ID + char name[32]; // Device name + + // Driver + struct drm_driver_ops *ops; + struct drm_driver_caps caps; + void *driver_private; // Driver-specific data + + // Mode config + struct drm_mode_config mode_config; + + // Objects + klib::Vector files; + klib::Vector gem_objects; + + // ID counters + u32 next_crtc_id; + u32 next_encoder_id; + u32 next_connector_id; + u32 next_plane_id; + u32 next_fb_id; + u32 next_handle; + + // VFS + vfs::inode *inode; + vfs::file *file; + + // Lock + klib::Spinlock lock; + + // List node + klib::ListHead list; +}; + +// Plane types +#define DRM_PLANE_TYPE_PRIMARY 0 +#define DRM_PLANE_TYPE_CURSOR 1 +#define DRM_PLANE_TYPE_OVERLAY 2 + +// Global DRM state +extern klib::Vector drm_devices; +extern klib::Spinlock drm_devices_lock; + +// Function prototypes +int drm_init(void); +struct drm_device* drm_device_create(struct drm_driver_ops *ops, void *private_data); +void drm_device_destroy(struct drm_device *dev); +void gem_init(void); +void drm_connector_set_modes(struct drm_connector *connector); +void drm_mode_page_flip_complete(struct drm_crtc *crtc); + +// File operations +int drm_open(vfs::file *file); +int drm_close(vfs::file *file); +ssize_t drm_read(vfs::file *file, void *buf, size_t count); +ssize_t drm_write(vfs::file *file, const void *buf, size_t count); +int drm_ioctl(vfs::file *file, unsigned long request, void *arg); +int drm_mmap(vfs::vm_area *vma); +int drm_poll(vfs::file *file); + +// GEM operations +struct drm_gem_object* drm_gem_object_create(struct drm_device *dev, u32 size); +void drm_gem_object_destroy(struct drm_gem_object *obj); +struct drm_gem_object* drm_gem_object_lookup(struct drm_file *file, u32 handle); +int drm_gem_handle_create(struct drm_file *file, struct drm_gem_object *obj, u32 *handle); +int drm_gem_handle_delete(struct drm_file *file, u32 handle); +int drm_gem_flink(struct drm_file *file, u32 handle, u32 *name); +int drm_gem_open(struct drm_file *file, u32 name, u32 *handle, u64 *size); + +// Framebuffer operations +struct drm_framebuffer* drm_framebuffer_create(struct drm_device *dev); +void drm_framebuffer_destroy(struct drm_framebuffer *fb); +struct drm_framebuffer* drm_framebuffer_lookup(struct drm_device *dev, u32 id); + +// CRTC operations +struct drm_crtc* drm_crtc_create(struct drm_device *dev); +void drm_crtc_destroy(struct drm_crtc *crtc); +struct drm_crtc* drm_crtc_find(struct drm_device *dev, u32 id); + +// Encoder operations +struct drm_encoder* drm_encoder_create(struct drm_device *dev, u32 type); +void drm_encoder_destroy(struct drm_encoder *encoder); +struct drm_encoder* drm_encoder_find(struct drm_device *dev, u32 id); + +// Connector operations +struct drm_connector* drm_connector_create(struct drm_device *dev, u32 type); +void drm_connector_destroy(struct drm_connector *connector); +struct drm_connector* drm_connector_find(struct drm_device *dev, u32 id); + +// Plane operations +struct drm_plane* drm_plane_create(struct drm_device *dev, u32 type, u32 *formats, u32 num_formats); +void drm_plane_destroy(struct drm_plane *plane); +struct drm_plane* drm_plane_find(struct drm_device *dev, u32 id); + +// Mode operations +int drm_mode_set_crtc(struct drm_file *file, struct drm_mode_crtc *crtc); +int drm_mode_page_flip(struct drm_file *file, struct drm_mode_crtc_page_flip *flip); +int drm_mode_get_resources(struct drm_file *file, struct drm_mode_card_res *res); +int drm_mode_get_connector(struct drm_file *file, struct drm_mode_get_connector *conn); +int drm_mode_get_encoder(struct drm_file *file, struct drm_mode_get_encoder *enc); +int drm_mode_get_crtc(struct drm_file *file, struct drm_mode_crtc *crtc); +int drm_mode_create_dumb(struct drm_file *file, struct drm_mode_create_dumb *dumb); +int drm_mode_map_dumb(struct drm_file *file, struct drm_mode_map_dumb *dumb); +int drm_mode_destroy_dumb(struct drm_file *file, struct drm_mode_destroy_dumb *dumb); +int drm_mode_addfb2(struct drm_file *file, struct drm_mode_fb_cmd2 *fb); +int drm_mode_rmfb(struct drm_file *file, u32 fb_id); +int drm_mode_getfb(struct drm_file *file, struct drm_mode_fb_cmd *fb); + +// Event operations +int drm_send_event(struct drm_file *file, struct drm_event *event, u64 user_data); +int drm_send_vblank_event(struct drm_file *file, u32 crtc_id, u64 user_data); +int drm_send_flip_event(struct drm_file *file, u32 crtc_id, u64 user_data); + +// IOCTL handlers +int drm_ioctl_version(struct drm_file *file, struct drm_version *version); +int drm_ioctl_get_cap(struct drm_file *file, struct drm_get_cap *cap); +int drm_ioctl_set_client_cap(struct drm_file *file, struct drm_set_client_cap *cap); +int drm_ioctl_gem_close(struct drm_file *file, struct drm_gem_close *close); +int drm_ioctl_gem_flink(struct drm_file *file, struct drm_gem_flink *flink); +int drm_ioctl_gem_open(struct drm_file *file, struct drm_gem_open *open); + +} // namespace drm + +#endif // _FISHIX_DRM_INTERNAL_HPP diff --git a/kernel/src/drivers/drm/drm_modeset.cpp b/kernel/src/drivers/drm/drm_modeset.cpp new file mode 100644 index 0000000..4cf8083 --- /dev/null +++ b/kernel/src/drivers/drm/drm_modeset.cpp @@ -0,0 +1,590 @@ +// kernel/src/drivers/drm/drm_modeset.cpp +// Mode Setting untuk Fishix Wayland support +// Implementasi KMS (Kernel Mode Setting) operations + +#include +#include +#include +#include +#include +#include + +namespace drm { + +// Standard video modes (simplified) +static struct drm_mode_modeinfo standard_modes[] = { + // 1920x1080 @ 60Hz + { + .clock = 148500, + .hdisplay = 1920, + .hsync_start = 2008, + .hsync_end = 2052, + .htotal = 2200, + .vdisplay = 1080, + .vsync_start = 1084, + .vsync_end = 1089, + .vtotal = 1125, + .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, + .type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER, + .name = "1920x1080" + }, + // 1280x720 @ 60Hz + { + .clock = 74250, + .hdisplay = 1280, + .hsync_start = 1390, + .hsync_end = 1430, + .htotal = 1650, + .vdisplay = 720, + .vsync_start = 725, + .vsync_end = 730, + .vtotal = 750, + .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, + .type = DRM_MODE_TYPE_DRIVER, + .name = "1280x720" + }, + // 1024x768 @ 60Hz + { + .clock = 65000, + .hdisplay = 1024, + .hsync_start = 1048, + .hsync_end = 1184, + .htotal = 1344, + .vdisplay = 768, + .vsync_start = 771, + .vsync_end = 777, + .vtotal = 806, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + .type = DRM_MODE_TYPE_DRIVER, + .name = "1024x768" + }, + // 800x600 @ 60Hz + { + .clock = 40000, + .hdisplay = 800, + .hsync_start = 840, + .hsync_end = 968, + .htotal = 1056, + .vdisplay = 600, + .vsync_start = 601, + .vsync_end = 605, + .vtotal = 628, + .flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, + .type = DRM_MODE_TYPE_DRIVER, + .name = "800x600" + }, + // 640x480 @ 60Hz + { + .clock = 25175, + .hdisplay = 640, + .hsync_start = 656, + .hsync_end = 752, + .htotal = 800, + .vdisplay = 480, + .vsync_start = 490, + .vsync_end = 492, + .vtotal = 525, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + .type = DRM_MODE_TYPE_DRIVER, + .name = "640x480" + } +}; + +static const int num_standard_modes = sizeof(standard_modes) / sizeof(standard_modes[0]); + +// Set connector modes (called saat connector created) +void drm_connector_set_modes(struct drm_connector *connector) { + if (!connector) return; + + // Allocate modes array + connector->modes = new struct drm_mode_modeinfo[num_standard_modes]; + connector->num_modes = num_standard_modes; + + // Copy standard modes + for (int i = 0; i < num_standard_modes; i++) { + memcpy(&connector->modes[i], &standard_modes[i], sizeof(struct drm_mode_modeinfo)); + } +} + +// IOCTL: Get resources +int drm_mode_get_resources(struct drm_file *file, struct drm_mode_card_res *res) { + if (!file || !res) return -EINVAL; + + struct drm_device *dev = file->dev; + + (dev->lock).lock(); + + // Copy FB IDs + if (res->fb_id_ptr && res->count_fbs >= dev->mode_config.fbs.size()) { + u32 *fb_ids = (u32*)res->fb_id_ptr; + for (usize i = 0; i < dev->mode_config.fbs.size(); i++) { + fb_ids[i] = dev->mode_config.fbs[i]->id; + } + } + res->count_fbs = dev->mode_config.fbs.size(); + + // Copy CRTC IDs + if (res->crtc_id_ptr && res->count_crtcs >= dev->mode_config.crtcs.size()) { + u32 *crtc_ids = (u32*)res->crtc_id_ptr; + for (usize i = 0; i < dev->mode_config.crtcs.size(); i++) { + crtc_ids[i] = dev->mode_config.crtcs[i]->id; + } + } + res->count_crtcs = dev->mode_config.crtcs.size(); + + // Copy connector IDs + if (res->connector_id_ptr && res->count_connectors >= dev->mode_config.connectors.size()) { + u32 *connector_ids = (u32*)res->connector_id_ptr; + for (usize i = 0; i < dev->mode_config.connectors.size(); i++) { + connector_ids[i] = dev->mode_config.connectors[i]->id; + } + } + res->count_connectors = dev->mode_config.connectors.size(); + + // Copy encoder IDs + if (res->encoder_id_ptr && res->count_encoders >= dev->mode_config.encoders.size()) { + u32 *encoder_ids = (u32*)res->encoder_id_ptr; + for (usize i = 0; i < dev->mode_config.encoders.size(); i++) { + encoder_ids[i] = dev->mode_config.encoders[i]->id; + } + } + res->count_encoders = dev->mode_config.encoders.size(); + + // Min/max dimensions + res->min_width = dev->mode_config.min_width; + res->max_width = dev->mode_config.max_width; + res->min_height = dev->mode_config.min_height; + res->max_height = dev->mode_config.max_height; + + (dev->lock).unlock(); + + return 0; +} + +// IOCTL: Get connector +int drm_mode_get_connector(struct drm_file *file, struct drm_mode_get_connector *conn) { + if (!file || !conn) return -EINVAL; + + struct drm_device *dev = file->dev; + + (dev->lock).lock(); + + struct drm_connector *connector = drm_connector_find(dev, conn->connector_id); + if (!connector) { + (dev->lock).unlock(); + return -ENOENT; + } + + // Copy modes + if (conn->modes_ptr && conn->count_modes >= connector->num_modes) { + struct drm_mode_modeinfo *modes = (struct drm_mode_modeinfo*)conn->modes_ptr; + for (u32 i = 0; i < connector->num_modes; i++) { + memcpy(&modes[i], &connector->modes[i], sizeof(struct drm_mode_modeinfo)); + } + } + conn->count_modes = connector->num_modes; + + // Copy encoder IDs (simplified - hanya 1 encoder) + if (conn->encoders_ptr && conn->count_encoders >= 1) { + u32 *encoders = (u32*)conn->encoders_ptr; + if (connector->encoder) { + encoders[0] = connector->encoder->id; + } + } + conn->count_encoders = connector->encoder ? 1 : 0; + + // Connector info + conn->encoder_id = connector->encoder ? connector->encoder->id : 0; + conn->connection = connector->connection; + conn->mm_width = connector->mm_width; + conn->mm_height = connector->mm_height; + conn->subconnector = connector->subconnector; + conn->count_props = 0; + + (dev->lock).unlock(); + + return 0; +} + +// IOCTL: Get encoder +int drm_mode_get_encoder(struct drm_file *file, struct drm_mode_get_encoder *enc) { + if (!file || !enc) return -EINVAL; + + struct drm_device *dev = file->dev; + + (dev->lock).lock(); + + struct drm_encoder *encoder = drm_encoder_find(dev, enc->encoder_id); + if (!encoder) { + (dev->lock).unlock(); + return -ENOENT; + } + + enc->encoder_type = encoder->encoder_type; + enc->crtc_id = encoder->crtc ? encoder->crtc->id : 0; + enc->possible_crtcs = encoder->possible_crtcs; + enc->possible_clones = encoder->possible_clones; + + (dev->lock).unlock(); + + return 0; +} + +// IOCTL: Get CRTC +int drm_mode_get_crtc(struct drm_file *file, struct drm_mode_crtc *crtc) { + if (!file || !crtc) return -EINVAL; + + struct drm_device *dev = file->dev; + + (dev->lock).lock(); + + struct drm_crtc *c = drm_crtc_find(dev, crtc->crtc_id); + if (!c) { + (dev->lock).unlock(); + return -ENOENT; + } + + crtc->fb_id = c->fb ? c->fb->id : 0; + crtc->x = c->x; + crtc->y = c->y; + crtc->gamma_size = 0; + crtc->mode_valid = c->enabled ? 1 : 0; + + if (c->enabled) { + memcpy(&crtc->mode, &c->mode, sizeof(crtc->mode)); + } + + (dev->lock).unlock(); + + return 0; +} + +// IOCTL: Set CRTC +int drm_mode_set_crtc(struct drm_file *file, struct drm_mode_crtc *crtc) { + if (!file || !crtc) return -EINVAL; + + struct drm_device *dev = file->dev; + + (dev->lock).lock(); + + struct drm_crtc *c = drm_crtc_find(dev, crtc->crtc_id); + if (!c) { + (dev->lock).unlock(); + return -ENOENT; + } + + // Find framebuffer + struct drm_framebuffer *fb = nullptr; + if (crtc->fb_id != 0) { + fb = drm_framebuffer_lookup(dev, crtc->fb_id); + if (!fb) { + (dev->lock).unlock(); + return -ENOENT; + } + } + + // Set mode + if (crtc->mode_valid) { + memcpy(&c->mode, &crtc->mode, sizeof(c->mode)); + c->enabled = true; + } else { + c->enabled = false; + } + + c->x = crtc->x; + c->y = crtc->y; + c->fb = fb; + + // Call driver callback + if (dev->ops->crtc_set_config) { + int ret = dev->ops->crtc_set_config(c, crtc); + if (ret < 0) { + (dev->lock).unlock(); + return ret; + } + } + + (dev->lock).unlock(); + + klib::printf("DRM: Set CRTC %u, FB %u, mode %s\n", + crtc->crtc_id, crtc->fb_id, + crtc->mode_valid ? crtc->mode.name : "none"); + + return 0; +} + +// IOCTL: Page flip +int drm_mode_page_flip(struct drm_file *file, struct drm_mode_crtc_page_flip *flip) { + if (!file || !flip) return -EINVAL; + + struct drm_device *dev = file->dev; + + (dev->lock).lock(); + + struct drm_crtc *crtc = drm_crtc_find(dev, flip->crtc_id); + if (!crtc) { + (dev->lock).unlock(); + return -ENOENT; + } + + // Check if page flip pending + if (crtc->page_flip_pending) { + (dev->lock).unlock(); + return -EBUSY; + } + + // Find framebuffer + struct drm_framebuffer *fb = drm_framebuffer_lookup(dev, flip->fb_id); + if (!fb) { + (dev->lock).unlock(); + return -ENOENT; + } + + // Set pending state + crtc->page_flip_pending = true; + crtc->page_flip_user_data = flip->user_data; + crtc->pending_fb = fb; + + // Call driver callback + if (dev->ops->page_flip) { + int ret = dev->ops->page_flip(crtc, fb, flip->user_data); + if (ret < 0) { + crtc->page_flip_pending = false; + crtc->pending_fb = nullptr; + (dev->lock).unlock(); + return ret; + } + } else { + // Synchronous flip (fallback) + crtc->fb = fb; + crtc->page_flip_pending = false; + + // Send flip complete event + if (flip->flags & 0x01) { // DRM_MODE_PAGE_FLIP_EVENT + drm_send_flip_event(file, flip->crtc_id, flip->user_data); + } + } + + (dev->lock).unlock(); + + klib::printf("DRM: Page flip CRTC %u -> FB %u\n", flip->crtc_id, flip->fb_id); + + return 0; +} + +// Complete page flip (called by driver saat VBlank) +void drm_mode_page_flip_complete(struct drm_crtc *crtc) { + if (!crtc) return; + + (crtc->dev->lock).lock(); + + if (crtc->page_flip_pending && crtc->pending_fb) { + crtc->fb = crtc->pending_fb; + crtc->pending_fb = nullptr; + crtc->page_flip_pending = false; + + // Send event ke all files + // (simplified - seharusnya ke file yang request flip) + for (usize i = 0; i < crtc->dev->files.size(); i++) { + drm_send_flip_event(crtc->dev->files[i], crtc->id, crtc->page_flip_user_data); + } + } + + (crtc->dev->lock).unlock(); +} + +// IOCTL: Create dumb buffer +int drm_mode_create_dumb(struct drm_file *file, struct drm_mode_create_dumb *dumb) { + if (!file || !dumb) return -EINVAL; + + struct drm_device *dev = file->dev; + + // Calculate size + u32 pitch = dumb->width * ((dumb->bpp + 7) / 8); + u32 size = pitch * dumb->height; + + // Align size ke page boundary + size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + + // Create GEM object + struct drm_gem_object *obj = drm_gem_object_create(dev, size); + if (!obj) return -ENOMEM; + + // Create handle + u32 handle; + int ret = drm_gem_handle_create(file, obj, &handle); + if (ret < 0) { + drm_gem_object_destroy(obj); + return ret; + } + + dumb->handle = handle; + dumb->pitch = pitch; + dumb->size = size; + + klib::printf("DRM: Created dumb buffer %ux%u@%u, handle %u, size %u\n", + dumb->width, dumb->height, dumb->bpp, handle, size); + + return 0; +} + +// IOCTL: Map dumb buffer +int drm_mode_map_dumb(struct drm_file *file, struct drm_mode_map_dumb *dumb) { + if (!file || !dumb) return -EINVAL; + + struct drm_gem_object *obj = drm_gem_object_lookup(file, dumb->handle); + if (!obj) return -ENOENT; + + // Return offset untuk mmap (handle * PAGE_SIZE sebagai fake offset) + dumb->offset = (u64)dumb->handle * PAGE_SIZE; + + drm_gem_object_destroy(obj); + + return 0; +} + +// IOCTL: Destroy dumb buffer +int drm_mode_destroy_dumb(struct drm_file *file, struct drm_mode_destroy_dumb *dumb) { + if (!file || !dumb) return -EINVAL; + return drm_gem_handle_delete(file, dumb->handle); +} + +// IOCTL: Add FB2 +int drm_mode_addfb2(struct drm_file *file, struct drm_mode_fb_cmd2 *fb) { + if (!file || !fb) return -EINVAL; + + struct drm_device *dev = file->dev; + + // Validate parameters + if (fb->width == 0 || fb->height == 0) return -EINVAL; + if (fb->handles[0] == 0) return -EINVAL; + + // Create framebuffer + struct drm_framebuffer *framebuffer = drm_framebuffer_create(dev); + if (!framebuffer) return -ENOMEM; + + framebuffer->width = fb->width; + framebuffer->height = fb->height; + framebuffer->pixel_format = fb->pixel_format; + framebuffer->pitch = fb->pitches[0]; + + // Set bpp berdasarkan format + switch (fb->pixel_format) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: + framebuffer->bpp = 32; + framebuffer->depth = 24; + break; + case DRM_FORMAT_RGB888: + case DRM_FORMAT_BGR888: + framebuffer->bpp = 24; + framebuffer->depth = 24; + break; + case DRM_FORMAT_RGB565: + case DRM_FORMAT_BGR565: + framebuffer->bpp = 16; + framebuffer->depth = 16; + break; + default: + framebuffer->bpp = 32; + framebuffer->depth = 24; + break; + } + + // Attach GEM objects + for (int i = 0; i < 4; i++) { + if (fb->handles[i] != 0) { + struct drm_gem_object *obj = drm_gem_object_lookup(file, fb->handles[i]); + if (!obj) { + drm_framebuffer_destroy(framebuffer); + return -ENOENT; + } + framebuffer->obj[i] = obj; + framebuffer->pitches[i] = fb->pitches[i]; + framebuffer->offsets[i] = fb->offsets[i]; + framebuffer->modifiers[i] = fb->modifier[i]; + } + } + + // Call driver callback + if (dev->ops->fb_create) { + int ret = dev->ops->fb_create(dev, fb); + if (ret < 0) { + drm_framebuffer_destroy(framebuffer); + return ret; + } + } + + fb->fb_id = framebuffer->id; + + klib::printf("DRM: Created FB %u, %ux%u, format %.4s\n", + framebuffer->id, fb->width, fb->height, (char*)&fb->pixel_format); + + return 0; +} + +// IOCTL: Remove FB +int drm_mode_rmfb(struct drm_file *file, u32 fb_id) { + if (!file || fb_id == 0) return -EINVAL; + + struct drm_device *dev = file->dev; + + (dev->lock).lock(); + + struct drm_framebuffer *fb = drm_framebuffer_lookup(dev, fb_id); + if (!fb) { + (dev->lock).unlock(); + return -ENOENT; + } + + // Remove dari list + for (usize i = 0; i < dev->mode_config.fbs.size(); i++) { + if (dev->mode_config.fbs[i] == fb) { + dev->mode_config.fbs.remove(i); + break; + } + } + + (dev->lock).unlock(); + + // Call driver callback + if (dev->ops->fb_destroy) { + dev->ops->fb_destroy(fb); + } + + drm_framebuffer_destroy(fb); + + klib::printf("DRM: Removed FB %u\n", fb_id); + + return 0; +} + +// IOCTL: Get FB +int drm_mode_getfb(struct drm_file *file, struct drm_mode_fb_cmd *fb) { + if (!file || !fb) return -EINVAL; + + struct drm_device *dev = file->dev; + + (dev->lock).lock(); + + struct drm_framebuffer *framebuffer = drm_framebuffer_lookup(dev, fb->fb_id); + if (!framebuffer) { + (dev->lock).unlock(); + return -ENOENT; + } + + fb->width = framebuffer->width; + fb->height = framebuffer->height; + fb->pitch = framebuffer->pitch; + fb->bpp = framebuffer->bpp; + fb->depth = framebuffer->depth; + fb->handle = framebuffer->obj[0] ? framebuffer->obj[0]->handle : 0; + + (dev->lock).unlock(); + + return 0; +} + +} // namespace drm diff --git a/kernel/src/drivers/drm/fishix_drm.cpp b/kernel/src/drivers/drm/fishix_drm.cpp new file mode 100644 index 0000000..6cd1758 --- /dev/null +++ b/kernel/src/drivers/drm/fishix_drm.cpp @@ -0,0 +1,316 @@ +// kernel/src/drivers/drm/fishix_drm.cpp +// Fishix DRM Driver - Integrasi dengan Fishix Framebuffer +// Driver DRM yang menggunakan framebuffer Fishix yang sudah ada + +#include "drm_internal.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace drm { + +// Fishix DRM private data +struct fishix_drm_private { + // Framebuffer info dari Fishix + uptr fb_phys; + uptr fb_virt; + u32 fb_width; + u32 fb_height; + u32 fb_pitch; + u32 fb_bpp; + + // Hardware state + struct drm_crtc *crtc; + struct drm_encoder *encoder; + struct drm_connector *connector; + struct drm_plane *primary_plane; + + // Current display buffer + void *display_buffer; + paddr_t display_buffer_phys; +}; + +// DRM DevNode implementation +struct DRMDevNode final : public dev::SeekableCharDevNode { + DRMDevNode() {} + isize open(vfs::file *fd) override { return drm_open(fd); } + void close(vfs::file *fd) override { drm_close(fd); } + isize read(vfs::file *fd, void *buf, usize count, usize offset) override { return drm_read(fd, buf, count); } + isize write(vfs::file *fd, const void *buf, usize count, usize offset) override { return drm_write(fd, buf, count); } + isize ioctl(vfs::file *fd, usize cmd, void *arg) override { return drm_ioctl(fd, cmd, arg); } + isize mmap(vfs::FileDescription *fd, uptr addr, usize length, isize offset, int prot, int flags) override { + (void)flags; + sched::Process *process = cpu::get_current_thread()->process; + u64 page_flags = mem::mmap_prot_to_page_flags(prot); + + // Add range of type FILE to represent the GEM mapping + auto *vma = process->pagemap->add_range(addr, length, page_flags, mem::MappedRange::Type::FILE, 0, fd, offset); + if (!vma) return -ENOMEM; + + int ret = drm::drm_mmap(vma); + if (ret < 0) { + // Range will be cleaned up by process pagemap on exit or munmap + return ret; + } + return addr; + } + isize poll(vfs::file *fd, isize events) override { return drm_poll(fd); } +}; + +// Forward declarations +static int fishix_drm_load(struct drm_device *dev); +static void fishix_drm_unload(struct drm_device *dev); +static struct drm_gem_object* fishix_drm_gem_create(struct drm_device *dev, u32 size); +static void fishix_drm_gem_destroy(struct drm_gem_object *obj); +static int fishix_drm_gem_mmap(struct drm_gem_object *obj, mem::MappedRange *vma); +static int fishix_drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *mode); +static int fishix_drm_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, u64 user_data); +static int fishix_drm_fb_create(struct drm_device *dev, struct drm_mode_fb_cmd2 *cmd); +static void fishix_drm_fb_destroy(struct drm_framebuffer *fb); + +// Fishix DRM driver operations +static struct drm_driver_ops fishix_drm_ops = { + .load = fishix_drm_load, + .unload = fishix_drm_unload, + .gem_create = fishix_drm_gem_create, + .gem_destroy = fishix_drm_gem_destroy, + .gem_mmap = fishix_drm_gem_mmap, + .crtc_set_config = fishix_drm_crtc_set_config, + .page_flip = fishix_drm_page_flip, + .fb_create = fishix_drm_fb_create, + .fb_destroy = fishix_drm_fb_destroy, +}; + +// Static DRM device instance +static struct drm_device *fishix_drm_dev = nullptr; + +// Initialize Fishix DRM +int fishix_drm_init(void) { + klib::printf("Fishix DRM: Initializing...\n"); + + // Initialize DMA subsystem + mem::dma::init(); + + // Initialize DRM core + drm_init(); + + // Create DRM device + fishix_drm_dev = drm_device_create(&fishix_drm_ops, nullptr); + if (!fishix_drm_dev) { + klib::printf("Fishix DRM: Failed to create device\n"); + return -ENOMEM; + } + + // Register device node /dev/dri/card0 + dev::CharDevNode::register_node_initializer(DRM_MAJOR, 0, "dri/card0", []() { + DRMDevNode *node = new DRMDevNode(); + if (fishix_drm_dev) fishix_drm_dev->inode = node; + return node; + }); + + klib::printf("Fishix DRM: Initialized successfully\n"); + + return 0; +} + +// Cleanup Fishix DRM +void fishix_drm_cleanup(void) { + if (fishix_drm_dev) { + drm_device_destroy(fishix_drm_dev); + fishix_drm_dev = nullptr; + } +} + +// Driver load callback +static int fishix_drm_load(struct drm_device *dev) { + klib::printf("Fishix DRM: Loading driver...\n"); + + // Allocate private data + struct fishix_drm_private *priv = new struct fishix_drm_private(); + if (!priv) return -ENOMEM; + + // Get framebuffer info dari Fishix + priv->fb_width = gfx::main_framebuffer.width; + priv->fb_height = gfx::main_framebuffer.height; + priv->fb_pitch = gfx::main_framebuffer.pitch; + priv->fb_bpp = gfx::main_framebuffer.pixel_width * 8; + priv->fb_phys = (uptr)gfx::main_framebuffer.addr - mem::hhdm; + priv->fb_virt = (uptr)gfx::main_framebuffer.addr; + + klib::printf("Fishix DRM: Framebuffer %ux%u@%u, pitch %u, phys %#lX\n", + priv->fb_width, priv->fb_height, priv->fb_bpp, + priv->fb_pitch, priv->fb_phys); + + // Allocate display buffer (double buffering) + u32 fb_size = priv->fb_pitch * priv->fb_height; + priv->display_buffer = mem::dma::alloc_coherent(fb_size, &priv->display_buffer_phys); + if (!priv->display_buffer) { + klib::printf("Fishix DRM: Failed to allocate display buffer\n"); + delete priv; + return -ENOMEM; + } + + // Create CRTC + priv->crtc = drm_crtc_create(dev); + if (!priv->crtc) { + delete priv; + return -ENOMEM; + } + + // Create encoder + priv->encoder = drm_encoder_create(dev, DRM_MODE_ENCODER_NONE); + if (!priv->encoder) { + delete priv; + return -ENOMEM; + } + priv->encoder->crtc = priv->crtc; + + // Create connector + priv->connector = drm_connector_create(dev, DRM_MODE_CONNECTOR_VIRTUAL); + if (!priv->connector) { + delete priv; + return -ENOMEM; + } + priv->connector->encoder = priv->encoder; + priv->connector->encoder_id = priv->encoder->id; + priv->connector->mm_width = (priv->fb_width * 254) / 9600; // 96 DPI approximation + priv->connector->mm_height = (priv->fb_height * 254) / 9600; + + // Set connector modes + drm_connector_set_modes(priv->connector); + + // Create primary plane + u32 formats[] = { DRM_FORMAT_XRGB8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_RGB888 }; + priv->primary_plane = drm_plane_create(dev, DRM_PLANE_TYPE_PRIMARY, formats, 3); + if (!priv->primary_plane) { + delete priv; + return -ENOMEM; + } + priv->primary_plane->crtc = priv->crtc; + + // Set initial mode (preferred) + if (priv->connector->num_modes > 0) { + memcpy(&priv->crtc->mode, &priv->connector->modes[0], sizeof(priv->crtc->mode)); + priv->crtc->enabled = true; + } + + // Save private data + dev->driver_private = priv; + + klib::printf("Fishix DRM: Driver loaded successfully\n"); + + return 0; +} + +// Driver unload callback +static void fishix_drm_unload(struct drm_device *dev) { + klib::printf("Fishix DRM: Unloading driver...\n"); + + struct fishix_drm_private *priv = (struct fishix_drm_private*)dev->driver_private; + if (priv) { + if (priv->display_buffer) { + mem::dma::free_coherent(priv->fb_pitch * priv->fb_height, + priv->display_buffer, priv->display_buffer_phys); + } + delete priv; + dev->driver_private = nullptr; + } + + klib::printf("Fishix DRM: Driver unloaded\n"); +} + +// GEM create callback +static struct drm_gem_object* fishix_drm_gem_create(struct drm_device *dev, u32 size) { + (void)dev; + // Use default GEM implementation + return drm_gem_object_create(dev, size); +} + +// GEM destroy callback +static void fishix_drm_gem_destroy(struct drm_gem_object *obj) { + // Use default GEM implementation + drm_gem_object_destroy(obj); +} + +// GEM mmap callback +static int fishix_drm_gem_mmap(struct drm_gem_object *obj, mem::MappedRange *vma) { + (void)obj; + (void)vma; + return 0; +} + +// CRTC set config callback +static int fishix_drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *mode) { + (void)crtc; + (void)mode; + + klib::printf("Fishix DRM: Set CRTC config, mode=%s\n", + mode->mode_valid ? mode->mode.name : "none"); + + return 0; +} + +// Page flip callback +static int fishix_drm_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, u64 user_data) { + (void)user_data; + + struct drm_device *dev = crtc->dev; + struct fishix_drm_private *priv = (struct fishix_drm_private*)dev->driver_private; + + if (!priv || !fb || !fb->obj[0]) return -EINVAL; + + struct drm_gem_object *obj = fb->obj[0]; + + klib::printf("Fishix DRM: Page flip to FB %u, GEM %p\n", fb->id, obj); + + // Copy framebuffer content ke hardware framebuffer + memcpy(gfx::main_framebuffer.addr, obj->vaddr, + priv->fb_pitch * priv->fb_height); + + // Complete page flip (synchronous untuk demo) + drm_mode_page_flip_complete(crtc); + + return 0; +} + +// FB create callback +static int fishix_drm_fb_create(struct drm_device *dev, struct drm_mode_fb_cmd2 *cmd) { + (void)dev; + (void)cmd; + + klib::printf("Fishix DRM: Create FB %ux%u, format %.4s\n", + cmd->width, cmd->height, (char*)&cmd->pixel_format); + + return 0; +} + +// FB destroy callback +static void fishix_drm_fb_destroy(struct drm_framebuffer *fb) { + klib::printf("Fishix DRM: Destroy FB %u\n", fb->id); +} + +// Get DRM device +struct drm_device* fishix_drm_get_device(void) { + return fishix_drm_dev; +} + +} // namespace drm + +// C interface untuk inisialisasi +extern "C" { + +int fishix_drm_init(void) { + return drm::fishix_drm_init(); +} + +void fishix_drm_cleanup(void) { + drm::fishix_drm_cleanup(); +} + +} // extern "C" diff --git a/kernel/src/drivers/drm/fishix_drm.hpp b/kernel/src/drivers/drm/fishix_drm.hpp new file mode 100644 index 0000000..cf009d1 --- /dev/null +++ b/kernel/src/drivers/drm/fishix_drm.hpp @@ -0,0 +1,30 @@ +// kernel/src/drivers/drm/fishix_drm.hpp +// Fishix DRM Driver header + +#ifndef _FISHIX_DRM_HPP +#define _FISHIX_DRM_HPP + +#include + +namespace drm { + +struct drm_device; + +// Initialize Fishix DRM +int fishix_drm_init(void); + +// Cleanup Fishix DRM +void fishix_drm_cleanup(void); + +// Get DRM device +struct drm_device* fishix_drm_get_device(void); + +} // namespace drm + +// C interface +extern "C" { + int fishix_drm_init(void); + void fishix_drm_cleanup(void); +} + +#endif // _FISHIX_DRM_HPP diff --git a/kernel/src/fs/vfs.hpp b/kernel/src/fs/vfs.hpp index 32818e3..29b3460 100644 --- a/kernel/src/fs/vfs.hpp +++ b/kernel/src/fs/vfs.hpp @@ -16,8 +16,11 @@ #include namespace sched { struct Process; } +namespace mem { struct MappedRange; } namespace vfs { + using vm_area = mem::MappedRange; + enum class NodeType : u8 { HARD_LINK, // not an actual node type REGULAR, @@ -39,6 +42,10 @@ namespace vfs { struct Filesystem; struct FilesystemDriver; struct FileDescription; + struct VNode; + + using inode = VNode; + using file = FileDescription; struct VNode { NodeType node_type; @@ -210,6 +217,23 @@ namespace vfs { } }; + inline VNode* namei(const char *path) { + Entry *e = path_to_entry(path); + return e ? e->vnode : nullptr; + } + + inline void iput(VNode *vnode) { + if (vnode) vnode->decrement_ref_count(); + } + + inline FileDescription* fget(int fd) { + return get_file_description(fd); + } + + inline void fput(FileDescription* file) { + if (file) file->decrement_ref_count(); + } + isize syscall_openat(int dirfd, const char *path, int flags, mode_t mode); isize syscall_open(const char *path, int flags, mode_t mode); isize syscall_creat(const char *path, mode_t mode); diff --git a/kernel/src/include/kernel.hpp b/kernel/src/include/kernel.hpp new file mode 100644 index 0000000..e09a4d9 --- /dev/null +++ b/kernel/src/include/kernel.hpp @@ -0,0 +1,29 @@ +#pragma once + +// ====================================================== +// FISHIX KERNEL ROOT HEADER +// included by ALL kernel subsystems +// ====================================================== + +// ---- basic klib ---- +#include +#include +#include +#include +#include + +// ---- core kernel ---- +#include +#include + +// ---- memory ---- +#include +#include +#include + +// ---- scheduler ---- +#include +#include + +// ---- filesystem ---- +#include \ No newline at end of file diff --git a/kernel/src/include/klib/common.hpp b/kernel/src/include/klib/common.hpp new file mode 100644 index 0000000..f21e565 --- /dev/null +++ b/kernel/src/include/klib/common.hpp @@ -0,0 +1,125 @@ +// kernel/src/include/klib/common.hpp +// Common definitions untuk Fishix kernel +// (Ini adalah file placeholder - gunakan common.hpp yang sudah ada di Fishix) + +#ifndef _KLIB_COMMON_HPP +#define _KLIB_COMMON_HPP + +#include +#include +#include + +// Type aliases (sesuaikan dengan Fishix yang ada) +using u8 = uint8_t; +using u16 = uint16_t; +using u32 = uint32_t; +using u64 = uint64_t; +using usize = size_t; +using uptr = uintptr_t; +using paddr_t = uint64_t; + +using i8 = int8_t; +using i16 = int16_t; +using i32 = int32_t; +using i64 = int64_t; +using isize = intptr_t; + +// Constants +constexpr usize PAGE_SIZE = 4096; +constexpr usize PAGE_SHIFT = 12; + +// Page alignment macros +#define PAGE_ALIGN(x) (((x) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) +#define PAGE_ALIGN_DOWN(x) ((x) & ~(PAGE_SIZE - 1)) +#define PAGE_OFFSET(x) ((x) & (PAGE_SIZE - 1)) +#define PAGE_NUMBER(x) ((x) >> PAGE_SHIFT) + +// HHDM (Higher Half Direct Map) offset +extern uptr hhdm; + +// Error codes (sesuaikan dengan Fishix) +#define EINVAL 22 +#define ENOMEM 12 +#define ENOENT 2 +#define EBUSY 16 +#define ENODEV 19 +#define EBADF 9 +#define EAGAIN 11 +#define ENOTTY 25 +#define EACCES 13 +#define EIO 5 +#define ENOSPC 28 + +// File permissions +#define S_IFCHR 0020000 +#define S_IFBLK 0060000 +#define S_IFDIR 0040000 +#define S_IFREG 0100000 +#define S_IFIFO 0010000 +#define S_IFLNK 0120000 +#define S_IFSOCK 0140000 + +// Helper macros +#define offsetof(type, member) __builtin_offsetof(type, member) +#define container_of(ptr, type, member) ({ \ + void *__mptr = (void *)(ptr); \ + ((type *)(__mptr - offsetof(type, member))); \ +}) + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) + +#define UNUSED(x) ((void)(x)) + +// Spinlock (placeholder - gunakan implementasi Fishix) +struct spinlock_t { + volatile u32 locked; +}; + +#define INIT_SPINLOCK(lock) ((lock)->locked = 0) + +static inline void spin_lock(spinlock_t *lock) { + while (__atomic_test_and_set(&lock->locked, __ATOMIC_ACQUIRE)) { + __asm__ volatile("pause"); + } +} + +static inline void spin_unlock(spinlock_t *lock) { + __atomic_clear(&lock->locked, __ATOMIC_RELEASE); +} + +// Memory allocation flags +#define GFP_KERNEL 0 +#define GFP_ATOMIC 1 + +// kmalloc/kfree (placeholder - gunakan implementasi Fishix) +void* kmalloc(usize size, int flags); +void kfree(void *ptr); + +// kzalloc +static inline void* kzalloc(usize size, int flags) { + void *ptr = kmalloc(size, flags); + if (ptr) { + memset(ptr, 0, size); + } + return ptr; +} + +// C string functions +extern "C" { + void* memcpy(void *dest, const void *src, usize n); + void* memset(void *s, int c, usize n); + int memcmp(const void *s1, const void *s2, usize n); + int strcmp(const char *s1, const char *s2); + int strncmp(const char *s1, const char *s2, usize n); + usize strlen(const char *s); + char* strncpy(char *dest, const char *src, usize n); + char* strncat(char *dest, const char *src, usize n); +} + +// Panic function (placeholder) +void panic(const char *fmt, ...); + +#endif // _KLIB_COMMON_HPP diff --git a/kernel/src/include/klib/ioctl.hpp b/kernel/src/include/klib/ioctl.hpp new file mode 100644 index 0000000..939f708 --- /dev/null +++ b/kernel/src/include/klib/ioctl.hpp @@ -0,0 +1,49 @@ +// kernel/src/include/klib/ioctl.hpp +// IOCTL macros untuk Fishix kernel + +#ifndef _KLIB_IOCTL_HPP +#define _KLIB_IOCTL_HPP + +#include + +// IOCTL type constants +#define _IOC_NRBITS 8 +#define _IOC_TYPEBITS 8 +#define _IOC_SIZEBITS 14 +#define _IOC_DIRBITS 2 + +#define _IOC_NRMASK ((1 << _IOC_NRBITS) - 1) +#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS) - 1) +#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS) - 1) +#define _IOC_DIRMASK ((1 << _IOC_DIRBITS) - 1) + +#define _IOC_NRSHIFT 0 +#define _IOC_TYPESHIFT (_IOC_NRSHIFT + _IOC_NRBITS) +#define _IOC_SIZESHIFT (_IOC_TYPESHIFT + _IOC_TYPEBITS) +#define _IOC_DIRSHIFT (_IOC_SIZESHIFT + _IOC_SIZEBITS) + +// Direction constants +#define _IOC_NONE 0U +#define _IOC_WRITE 1U +#define _IOC_READ 2U + +// Build IOCTL command +#define _IOC(dir, type, nr, size) \ + (((dir) << _IOC_DIRSHIFT) | \ + ((type) << _IOC_TYPESHIFT) | \ + ((nr) << _IOC_NRSHIFT) | \ + ((size) << _IOC_SIZESHIFT)) + +// Simplified IOCTL commands (no size checking) +#define _IO(type, nr) _IOC(_IOC_NONE, (type), (nr), 0) +#define _IOR(type, nr, size) _IOC(_IOC_READ, (type), (nr), sizeof(size)) +#define _IOW(type, nr, size) _IOC(_IOC_WRITE, (type), (nr), sizeof(size)) +#define _IOWR(type, nr, size) _IOC(_IOC_READ | _IOC_WRITE, (type), (nr), sizeof(size)) + +// Extract fields dari IOCTL command +#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) +#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK) +#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK) +#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK) + +#endif // _KLIB_IOCTL_HPP diff --git a/kernel/src/include/klib/list.hpp b/kernel/src/include/klib/list.hpp new file mode 100644 index 0000000..4c45024 --- /dev/null +++ b/kernel/src/include/klib/list.hpp @@ -0,0 +1,90 @@ +// kernel/src/include/klib/list.hpp +// Linked list operations untuk Fishix kernel + +#ifndef _KLIB_LIST_HPP +#define _KLIB_LIST_HPP + +#include + +namespace klib { + +// Simple doubly-linked list (similar to Linux kernel list) +struct list_head { + struct list_head *next; + struct list_head *prev; +}; + +// Initialize list head +static inline void INIT_LIST_HEAD(struct list_head *list) { + list->next = list; + list->prev = list; +} + +// Check if list is empty +static inline int list_empty(const struct list_head *head) { + return head->next == head; +} + +// Add entry between two consecutive entries +static inline void __list_add(struct list_head *new_entry, + struct list_head *prev, + struct list_head *next) { + next->prev = new_entry; + new_entry->next = next; + new_entry->prev = prev; + prev->next = new_entry; +} + +// Add entry at head +static inline void list_add(struct list_head *new_entry, struct list_head *head) { + __list_add(new_entry, head, head->next); +} + +// Add entry at tail +static inline void list_add_tail(struct list_head *new_entry, struct list_head *head) { + __list_add(new_entry, head->prev, head); +} + +// Delete entry between two consecutive entries +static inline void __list_del(struct list_head *prev, struct list_head *next) { + next->prev = prev; + prev->next = next; +} + +// Delete entry +static inline void list_del(struct list_head *entry) { + __list_del(entry->prev, entry->next); + entry->next = nullptr; + entry->prev = nullptr; +} + +// Pop first entry dari list +static inline struct list_head* list_pop_front(struct list_head *head) { + if (list_empty(head)) return nullptr; + struct list_head *entry = head->next; + list_del(entry); + return entry; +} + +// Get container dari list entry +#define list_entry(ptr, type, member) \ + ((type *)((char *)(ptr) - offsetof(type, member))) + +// Iterate over list +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +// Iterate over list safely (bisa delete selama iterasi) +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +// Iterate over list entries +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +} // namespace klib + +#endif // _KLIB_LIST_HPP diff --git a/kernel/src/include/klib/poll.hpp b/kernel/src/include/klib/poll.hpp new file mode 100644 index 0000000..1e894ad --- /dev/null +++ b/kernel/src/include/klib/poll.hpp @@ -0,0 +1,24 @@ +// kernel/src/include/klib/poll.hpp +// Poll flags untuk Fishix kernel + +#ifndef _KLIB_POLL_HPP +#define _KLIB_POLL_HPP + +#include + +// Poll flags (compatible dengan Linux) +#define POLLIN 0x001 +#define POLLPRI 0x002 +#define POLLOUT 0x004 +#define POLLERR 0x008 +#define POLLHUP 0x010 +#define POLLNVAL 0x020 +#define POLLRDNORM 0x040 +#define POLLRDBAND 0x080 +#define POLLWRNORM 0x100 +#define POLLWRBAND 0x200 +#define POLLMSG 0x400 +#define POLLREMOVE 0x1000 +#define POLLRDHUP 0x2000 + +#endif // _KLIB_POLL_HPP diff --git a/kernel/src/include/linux_types.hpp b/kernel/src/include/linux_types.hpp new file mode 100644 index 0000000..fea5ce2 --- /dev/null +++ b/kernel/src/include/linux_types.hpp @@ -0,0 +1,15 @@ +#pragma once + +using ssize_t = long; +using paddr_t = unsigned long long; + +struct list_head { + list_head *next; + list_head *prev; +}; + +enum dma_data_direction { + DMA_BIDIRECTIONAL, + DMA_TO_DEVICE, + DMA_FROM_DEVICE +}; \ No newline at end of file diff --git a/kernel/src/include/uapi/drm/drm.h b/kernel/src/include/uapi/drm/drm.h new file mode 100644 index 0000000..df464df --- /dev/null +++ b/kernel/src/include/uapi/drm/drm.h @@ -0,0 +1,599 @@ +// kernel/src/include/uapi/drm/drm.h +// UAPI DRM header untuk Fishix - Compatible dengan Linux DRM ABI +// Untuk Wayland support + +#ifndef _FISHIX_DRM_H +#define _FISHIX_DRM_H + +#include + +#define DRM_MAJOR 226 +#define DRM_IOCTL_BASE 'd' + +#define DRM_IO(nr) _IOC(DRM_IOCTL_BASE, nr, 0, 0) +#define DRM_IOR(nr, type) _IOR(DRM_IOCTL_BASE, nr, type) +#define DRM_IOW(nr, type) _IOW(DRM_IOCTL_BASE, nr, type) +#define DRM_IOWR(nr, type) _IOWR(DRM_IOCTL_BASE, nr, type) + +// IOCTL numbers (from Linux drm_ioctl.h) +#define DRM_IOCTL_VERSION DRM_IOWR(0x00, struct drm_version) +#define DRM_IOCTL_GET_UNIQUE DRM_IOWR(0x01, struct drm_unique) +#define DRM_IOCTL_GET_MAGIC DRM_IOR(0x02, struct drm_auth) +#define DRM_IOCTL_IRQ_BUSID DRM_IOWR(0x03, struct drm_irq_busid) +#define DRM_IOCTL_GET_MAP DRM_IOWR(0x04, struct drm_map) +#define DRM_IOCTL_GET_CLIENT DRM_IOWR(0x05, struct drm_client) +#define DRM_IOCTL_GET_STATS DRM_IOR(0x06, struct drm_stats) +#define DRM_IOCTL_SET_VERSION DRM_IOWR(0x07, struct drm_set_version) +#define DRM_IOCTL_MODESET_CTL DRM_IOW(0x08, struct drm_modeset_ctl) +#define DRM_IOCTL_GEM_CLOSE DRM_IOW(0x09, struct drm_gem_close) +#define DRM_IOCTL_GEM_FLINK DRM_IOWR(0x0a, struct drm_gem_flink) +#define DRM_IOCTL_GEM_OPEN DRM_IOWR(0x0b, struct drm_gem_open) +#define DRM_IOCTL_GET_CAP DRM_IOWR(0x0c, struct drm_get_cap) +#define DRM_IOCTL_SET_CLIENT_CAP DRM_IOW(0x0d, struct drm_set_client_cap) + +// Mode setting IOCTLs +#define DRM_IOCTL_MODE_GETRESOURCES DRM_IOWR(0xa0, struct drm_mode_card_res) +#define DRM_IOCTL_MODE_GETCRTC DRM_IOWR(0xa1, struct drm_mode_crtc) +#define DRM_IOCTL_MODE_SETCRTC DRM_IOWR(0xa2, struct drm_mode_crtc) +#define DRM_IOCTL_MODE_CURSOR DRM_IOWR(0xa3, struct drm_mode_cursor) +#define DRM_IOCTL_MODE_GETGAMMA DRM_IOWR(0xa4, struct drm_mode_crtc_lut) +#define DRM_IOCTL_MODE_SETGAMMA DRM_IOWR(0xa5, struct drm_mode_crtc_lut) +#define DRM_IOCTL_MODE_GETENCODER DRM_IOWR(0xa6, struct drm_mode_get_encoder) +#define DRM_IOCTL_MODE_GETCONNECTOR DRM_IOWR(0xa7, struct drm_mode_get_connector) +#define DRM_IOCTL_MODE_ATTACHMODE DRM_IOWR(0xa8, struct drm_mode_mode_cmd) +#define DRM_IOCTL_MODE_DETACHMODE DRM_IOWR(0xa9, struct drm_mode_mode_cmd) +#define DRM_IOCTL_MODE_GETPROPERTY DRM_IOWR(0xaa, struct drm_mode_get_property) +#define DRM_IOCTL_MODE_SETPROPERTY DRM_IOWR(0xab, struct drm_mode_connector_set_property) +#define DRM_IOCTL_MODE_GETPROPBLOB DRM_IOWR(0xac, struct drm_mode_get_blob) +#define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xad, struct drm_mode_fb_cmd) +#define DRM_IOCTL_MODE_ADDFB DRM_IOWR(0xae, struct drm_mode_fb_cmd) +#define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xaf, unsigned int) +#define DRM_IOCTL_MODE_PAGE_FLIP DRM_IOWR(0xb0, struct drm_mode_crtc_page_flip) +#define DRM_IOCTL_MODE_DIRTYFB DRM_IOWR(0xb1, struct drm_mode_fb_dirty_cmd) +#define DRM_IOCTL_MODE_CREATE_DUMB DRM_IOWR(0xb2, struct drm_mode_create_dumb) +#define DRM_IOCTL_MODE_MAP_DUMB DRM_IOWR(0xb3, struct drm_mode_map_dumb) +#define DRM_IOCTL_MODE_DESTROY_DUMB DRM_IOWR(0xb4, struct drm_mode_destroy_dumb) +#define DRM_IOCTL_MODE_GETPLANERESOURCES DRM_IOWR(0xb5, struct drm_mode_get_plane_res) +#define DRM_IOCTL_MODE_GETPLANE DRM_IOWR(0xb6, struct drm_mode_get_plane) +#define DRM_IOCTL_MODE_SETPLANE DRM_IOWR(0xb7, struct drm_mode_set_plane) +#define DRM_IOCTL_MODE_ADDFB2 DRM_IOWR(0xb8, struct drm_mode_fb_cmd2) +#define DRM_IOCTL_MODE_OBJ_GETPROPERTIES DRM_IOWR(0xb9, struct drm_mode_obj_get_properties) +#define DRM_IOCTL_MODE_OBJ_SETPROPERTY DRM_IOWR(0xba, struct drm_mode_obj_set_property) +#define DRM_IOCTL_MODE_CURSOR2 DRM_IOWR(0xbb, struct drm_mode_cursor2) +#define DRM_IOCTL_MODE_ATOMIC DRM_IOWR(0xbc, struct drm_mode_atomic) + +// Capabilities +#define DRM_CAP_DUMB_BUFFER 0x1 +#define DRM_CAP_VBLANK_HIGH_CRTC 0x2 +#define DRM_CAP_DUMB_PREFERRED_DEPTH 0x3 +#define DRM_CAP_DUMB_PREFER_SHADOW 0x4 +#define DRM_CAP_PRIME 0x5 +#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6 +#define DRM_CAP_ASYNC_PAGE_FLIP 0x7 +#define DRM_CAP_CURSOR_WIDTH 0x8 +#define DRM_CAP_CURSOR_HEIGHT 0x9 +#define DRM_CAP_ADDFB2_MODIFIERS 0x10 +#define DRM_CAP_PAGE_FLIP_TARGET 0x11 +#define DRM_CAP_CRTC_IN_VBLANK_EVENT 0x12 +#define DRM_CAP_SYNCOBJ 0x13 +#define DRM_CAP_SYNCOBJ_TIMELINE 0x14 + +// Client capabilities +#define DRM_CLIENT_CAP_STEREO_3D 1 +#define DRM_CLIENT_CAP_UNIVERSAL_PLANES 2 +#define DRM_CLIENT_CAP_ATOMIC 3 +#define DRM_CLIENT_CAP_ASPECT_RATIO 4 +#define DRM_CLIENT_CAP_WRITEBACK_CONNECTORS 5 + +// DRM modes +#define DRM_MODE_CONNECTED 1 +#define DRM_MODE_DISCONNECTED 2 +#define DRM_MODE_UNKNOWNCONNECTION 3 + +#define DRM_MODE_SUBCONNECTOR_Automatic 0 +#define DRM_MODE_SUBCONNECTOR_Unknown 0 +#define DRM_MODE_SUBCONNECTOR_DVID 1 +#define DRM_MODE_SUBCONNECTOR_DVIA 2 +#define DRM_MODE_SUBCONNECTOR_Composite 3 +#define DRM_MODE_SUBCONNECTOR_SVIDEO 4 +#define DRM_MODE_SUBCONNECTOR_Component 5 +#define DRM_MODE_SUBCONNECTOR_SCART 6 + +#define DRM_MODE_PROP_PENDING (1 << 0) +#define DRM_MODE_PROP_RANGE (1 << 1) +#define DRM_MODE_PROP_IMMUTABLE (1 << 2) +#define DRM_MODE_PROP_ENUM (1 << 3) +#define DRM_MODE_PROP_BLOB (1 << 4) +#define DRM_MODE_PROP_BITMASK (1 << 5) +#define DRM_MODE_PROP_LEGACY_TYPE (1 << 6) +#define DRM_MODE_PROP_EXTENDED_TYPE 0x0000ffc0 +#define DRM_MODE_PROP_OBJECT (1 << 6) +#define DRM_MODE_PROP_SIGNED_RANGE (1 << 7) + +#define DRM_MODE_PROP_ATOMIC 0x80000000 + +#define DRM_MODE_ENCODER_NONE 0 +#define DRM_MODE_ENCODER_DAC 1 +#define DRM_MODE_ENCODER_TMDS 2 +#define DRM_MODE_ENCODER_LVDS 3 +#define DRM_MODE_ENCODER_TVDAC 4 +#define DRM_MODE_ENCODER_VIRTUAL 5 +#define DRM_MODE_ENCODER_DSI 6 +#define DRM_MODE_ENCODER_DPMST 7 +#define DRM_MODE_ENCODER_DPI 8 + +#define DRM_MODE_CONNECTOR_Unknown 0 +#define DRM_MODE_CONNECTOR_VGA 1 +#define DRM_MODE_CONNECTOR_DVII 2 +#define DRM_MODE_CONNECTOR_DVID 3 +#define DRM_MODE_CONNECTOR_DVIA 4 +#define DRM_MODE_CONNECTOR_Composite 5 +#define DRM_MODE_CONNECTOR_SVIDEO 6 +#define DRM_MODE_CONNECTOR_LVDS 7 +#define DRM_MODE_CONNECTOR_Component 8 +#define DRM_MODE_CONNECTOR_9PinDIN 9 +#define DRM_MODE_CONNECTOR_DisplayPort 10 +#define DRM_MODE_CONNECTOR_HDMIA 11 +#define DRM_MODE_CONNECTOR_HDMIB 12 +#define DRM_MODE_CONNECTOR_TV 13 +#define DRM_MODE_CONNECTOR_eDP 14 +#define DRM_MODE_CONNECTOR_VIRTUAL 15 +#define DRM_MODE_CONNECTOR_DSI 16 +#define DRM_MODE_CONNECTOR_DPI 17 +#define DRM_MODE_CONNECTOR_WRITEBACK 18 +#define DRM_MODE_CONNECTOR_SPI 19 + +#define DRM_MODE_FLAG_PHSYNC (1 << 0) +#define DRM_MODE_FLAG_NHSYNC (1 << 1) +#define DRM_MODE_FLAG_PVSYNC (1 << 2) +#define DRM_MODE_FLAG_NVSYNC (1 << 3) +#define DRM_MODE_FLAG_INTERLACE (1 << 4) +#define DRM_MODE_FLAG_DBLSCAN (1 << 5) +#define DRM_MODE_FLAG_CSYNC (1 << 6) +#define DRM_MODE_FLAG_PCSYNC (1 << 7) +#define DRM_MODE_FLAG_NCSYNC (1 << 8) +#define DRM_MODE_FLAG_HSKEW (1 << 9) +#define DRM_MODE_FLAG_BCAST (1 << 10) +#define DRM_MODE_FLAG_PIXMUX (1 << 11) +#define DRM_MODE_FLAG_DBLCLK (1 << 12) +#define DRM_MODE_FLAG_CLKDIV2 (1 << 13) +#define DRM_MODE_FLAG_3D_MASK (0x1f << 14) +#define DRM_MODE_FLAG_3D_NONE (0 << 14) +#define DRM_MODE_FLAG_3D_FRAME_PACKING (1 << 14) +#define DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE (2 << 14) +#define DRM_MODE_FLAG_3D_LINE_ALTERNATIVE (3 << 14) +#define DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL (4 << 14) +#define DRM_MODE_FLAG_3D_L_DEPTH (5 << 14) +#define DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH (6 << 14) +#define DRM_MODE_FLAG_3D_TOP_AND_BOTTOM (7 << 14) +#define DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF (8 << 14) + +#define DRM_MODE_TYPE_BUILTIN (1 << 0) +#define DRM_MODE_TYPE_CLOCK_C ((1 << 1) | DRM_MODE_TYPE_BUILTIN) +#define DRM_MODE_TYPE_CRTC_C ((1 << 2) | DRM_MODE_TYPE_BUILTIN) +#define DRM_MODE_TYPE_PREFERRED (1 << 3) +#define DRM_MODE_TYPE_DEFAULT (1 << 4) +#define DRM_MODE_TYPE_USERDEF (1 << 5) +#define DRM_MODE_TYPE_DRIVER (1 << 6) +#define DRM_MODE_TYPE_ALL (DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_USERDEF | DRM_MODE_TYPE_DRIVER) + +// Event types +#define DRM_EVENT_VBLANK 0x01 +#define DRM_EVENT_FLIP_COMPLETE 0x02 +#define DRM_EVENT_CRTC_SEQUENCE 0x03 + +// FourCC formats (subset yang umum digunakan) +#define DRM_FORMAT_XRGB8888 fourcc_code('X', 'R', '2', '4') +#define DRM_FORMAT_ARGB8888 fourcc_code('A', 'R', '2', '4') +#define DRM_FORMAT_RGB888 fourcc_code('R', 'G', '2', '4') +#define DRM_FORMAT_BGR888 fourcc_code('B', 'G', '2', '4') +#define DRM_FORMAT_XBGR8888 fourcc_code('X', 'B', '2', '4') +#define DRM_FORMAT_ABGR8888 fourcc_code('A', 'B', '2', '4') +#define DRM_FORMAT_RGB565 fourcc_code('R', 'G', '1', '6') +#define DRM_FORMAT_BGR565 fourcc_code('B', 'G', '1', '6') + +#define fourcc_code(a, b, c, d) ((u32)(a) | ((u32)(b) << 8) | ((u32)(c) << 16) | ((u32)(d) << 24)) + +namespace drm { + +// Forward declarations +struct drm_device; +struct drm_file; +struct drm_gem_object; + +// DRM Version +struct [[gnu::packed]] drm_version { + int version_major; + int version_minor; + int version_patchlevel; + usize name_len; + char *name; + usize date_len; + char *date; + usize desc_len; + char *desc; +}; + +// DRM Unique +struct [[gnu::packed]] drm_unique { + usize unique_len; + char *unique; +}; + +// DRM Auth +struct [[gnu::packed]] drm_auth { + u32 magic; +}; + +// DRM Map +struct [[gnu::packed]] drm_map { + u64 offset; + u64 size; + u32 type; + u32 flags; + void *handle; + int mtrr; +}; + +// DRM Client +struct [[gnu::packed]] drm_client { + int idx; + int auth; + u32 pid; + u32 uid; + u32 magic; + u64 iocs; +}; + +// DRM Stats +struct [[gnu::packed]] drm_stats { + u32 count; + struct { + u32 value; + char name[15]; + } data[15]; +}; + +// DRM Set Version +struct [[gnu::packed]] drm_set_version { + int drm_di_major; + int drm_di_minor; + int drm_dd_major; + int drm_dd_minor; +}; + +// DRM Modeset Ctl +struct [[gnu::packed]] drm_modeset_ctl { + u32 crtc; + u32 cmd; +}; + +// DRM GEM Close +struct [[gnu::packed]] drm_gem_close { + u32 handle; + u32 pad; +}; + +// DRM GEM Flink +struct [[gnu::packed]] drm_gem_flink { + u32 handle; + u32 name; +}; + +// DRM GEM Open +struct [[gnu::packed]] drm_gem_open { + u32 name; + u32 handle; + u64 size; +}; + +// DRM Get Cap +struct [[gnu::packed]] drm_get_cap { + u64 capability; + u64 value; +}; + +// DRM Set Client Cap +struct [[gnu::packed]] drm_set_client_cap { + u64 capability; + u64 value; +}; + +// DRM Mode Info (mode timings) +struct [[gnu::packed]] drm_mode_modeinfo { + u32 clock; + u16 hdisplay; + u16 hsync_start; + u16 hsync_end; + u16 htotal; + u16 vdisplay; + u16 vsync_start; + u16 vsync_end; + u16 vtotal; + u16 flags; + u16 type; + char name[32]; +}; + +// DRM Mode Card Resources +struct [[gnu::packed]] drm_mode_card_res { + u64 fb_id_ptr; + u64 crtc_id_ptr; + u64 connector_id_ptr; + u64 encoder_id_ptr; + u32 count_fbs; + u32 count_crtcs; + u32 count_connectors; + u32 count_encoders; + u32 min_width; + u32 max_width; + u32 min_height; + u32 max_height; +}; + +// DRM Mode CRTC +struct [[gnu::packed]] drm_mode_crtc { + u64 set_connectors_ptr; + u32 count_connectors; + u32 crtc_id; + u32 fb_id; + u32 x; + u32 y; + u32 gamma_size; + u32 mode_valid; + struct drm_mode_modeinfo mode; +}; + +// DRM Mode Cursor +struct [[gnu::packed]] drm_mode_cursor { + u32 flags; + u32 crtc_id; + i32 x; + i32 y; + u32 width; + u32 height; + u32 handle; +}; + +// DRM Mode Cursor2 +struct [[gnu::packed]] drm_mode_cursor2 { + u32 flags; + u32 crtc_id; + i32 x; + i32 y; + u32 width; + u32 height; + u32 handle; + i32 hot_x; + i32 hot_y; +}; + +// DRM Mode CRTC LUT +struct [[gnu::packed]] drm_mode_crtc_lut { + u32 crtc_id; + u32 gamma_size; + u64 red; + u64 green; + u64 blue; +}; + +// DRM Mode Get Encoder +struct [[gnu::packed]] drm_mode_get_encoder { + u32 encoder_id; + u32 encoder_type; + u32 crtc_id; + u32 possible_crtcs; + u32 possible_clones; +}; + +// DRM Mode Get Connector +struct [[gnu::packed]] drm_mode_get_connector { + u64 encoders_ptr; + u64 modes_ptr; + u64 props_ptr; + u64 prop_values_ptr; + u32 count_modes; + u32 count_props; + u32 count_encoders; + u32 encoder_id; + u32 connector_id; + u32 connection; + u32 mm_width; + u32 mm_height; + u32 subconnector; + u32 pad; +}; + +// DRM Mode Mode Cmd +struct [[gnu::packed]] drm_mode_mode_cmd { + u32 connector_id; + struct drm_mode_modeinfo mode; +}; + +// DRM Mode Get Property +struct [[gnu::packed]] drm_mode_get_property { + u64 values_ptr; + u64 enum_blob_ptr; + u32 prop_id; + u32 flags; + char name[32]; + u32 count_values; + u32 count_enum_blobs; +}; + +// DRM Mode Connector Set Property +struct [[gnu::packed]] drm_mode_connector_set_property { + u64 value; + u32 prop_id; + u32 connector_id; +}; + +// DRM Mode Get Blob +struct [[gnu::packed]] drm_mode_get_blob { + u32 blob_id; + u32 length; + u64 data; +}; + +// DRM Mode FB Cmd +struct [[gnu::packed]] drm_mode_fb_cmd { + u32 fb_id; + u32 width; + u32 height; + u32 pitch; + u32 bpp; + u32 depth; + u32 handle; +}; + +// DRM Mode FB Cmd2 +struct [[gnu::packed]] drm_mode_fb_cmd2 { + u32 fb_id; + u32 width; + u32 height; + u32 pixel_format; + u32 flags; + u32 handles[4]; + u32 pitches[4]; + u32 offsets[4]; + u64 modifier[4]; +}; + +// DRM Mode FB Dirty Cmd +struct [[gnu::packed]] drm_mode_fb_dirty_cmd { + u32 fb_id; + u32 flags; + u32 color; + u32 num_clips; + u64 clips_ptr; +}; + +// DRM Mode CRTC Page Flip +struct [[gnu::packed]] drm_mode_crtc_page_flip { + u32 crtc_id; + u32 fb_id; + u32 flags; + u32 reserved; + u64 user_data; +}; + +// DRM Mode Create Dumb +struct [[gnu::packed]] drm_mode_create_dumb { + u32 height; + u32 width; + u32 bpp; + u32 flags; + u32 handle; + u32 pitch; + u64 size; +}; + +// DRM Mode Map Dumb +struct [[gnu::packed]] drm_mode_map_dumb { + u32 handle; + u32 pad; + u64 offset; +}; + +// DRM Mode Destroy Dumb +struct [[gnu::packed]] drm_mode_destroy_dumb { + u32 handle; +}; + +// DRM Mode Get Plane Resources +struct [[gnu::packed]] drm_mode_get_plane_res { + u64 plane_id_ptr; + u32 count_planes; +}; + +// DRM Mode Get Plane +struct [[gnu::packed]] drm_mode_get_plane { + u32 plane_id; + u32 crtc_id; + u32 fb_id; + u32 possible_crtcs; + u32 gamma_size; + u32 count_format_types; + u64 format_type_ptr; +}; + +// DRM Mode Set Plane +struct [[gnu::packed]] drm_mode_set_plane { + u32 plane_id; + u32 crtc_id; + u32 fb_id; + u32 flags; + i32 crtc_x; + i32 crtc_y; + u32 crtc_w; + u32 crtc_h; + u32 src_x; + u32 src_y; + u32 src_h; + u32 src_w; +}; + +// DRM Mode Obj Get Properties +struct [[gnu::packed]] drm_mode_obj_get_properties { + u64 props_ptr; + u64 prop_values_ptr; + u32 count_props; + u32 obj_id; + u32 obj_type; +}; + +// DRM Mode Obj Set Property +struct [[gnu::packed]] drm_mode_obj_set_property { + u64 value; + u32 prop_id; + u32 obj_id; + u32 obj_type; +}; + +// DRM Mode Atomic +struct [[gnu::packed]] drm_mode_atomic { + u32 flags; + u32 count_objs; + u64 objs_ptr; + u64 count_props_ptr; + u64 props_ptr; + u64 prop_values_ptr; + u64 reserved; + u64 user_data; +}; + +// DRM Event +struct [[gnu::packed]] drm_event { + u32 type; + u32 length; +}; + +// DRM Event VBlank +struct [[gnu::packed]] drm_event_vblank { + struct drm_event base; + u64 user_data; + u32 tv_sec; + u32 tv_usec; + u32 sequence; + u32 crtc_id; +}; + +// DRM Event CRTC Sequence +struct [[gnu::packed]] drm_event_crtc_sequence { + struct drm_event base; + u64 user_data; + u32 time_ns; + u32 sequence; +}; + +// IRQ Bus ID +struct [[gnu::packed]] drm_irq_busid { + u32 irq; + u32 busnum; + u32 devnum; + u32 funcnum; +}; + +} // namespace drm + +#endif // _FISHIX_DRM_H diff --git a/kernel/src/include/uapi/linux/dma-buf.h b/kernel/src/include/uapi/linux/dma-buf.h new file mode 100644 index 0000000..fd4e87d --- /dev/null +++ b/kernel/src/include/uapi/linux/dma-buf.h @@ -0,0 +1,104 @@ +// kernel/src/include/uapi/linux/dma-buf.h +// DMA-BUF API untuk Fishix Wayland support +// DMA-BUF digunakan untuk zero-copy buffer sharing antara GPU dan display + +#pragma once +#include + +#ifndef _FISHIX_DMA_BUF_H +#define _FISHIX_DMA_BUF_H + +#include + +// DMA-BUF IOCTLs +#define DMA_BUF_BASE 'b' +#define DMA_BUF_IOCTL_SYNC _IOW(DMA_BUF_BASE, 0, struct dma_buf_sync) +#define DMA_BUF_IOCTL_SET_NAME _IOW(DMA_BUF_BASE, 1, const char*) + +// DMA-BUF sync flags +#define DMA_BUF_SYNC_READ (1 << 0) +#define DMA_BUF_SYNC_WRITE (2 << 0) +#define DMA_BUF_SYNC_RW (DMA_BUF_SYNC_READ | DMA_BUF_SYNC_WRITE) +#define DMA_BUF_SYNC_START (0 << 2) +#define DMA_BUF_SYNC_END (1 << 2) +#define DMA_BUF_SYNC_VALID_FLAGS_MASK \ + (DMA_BUF_SYNC_READ | DMA_BUF_SYNC_WRITE | DMA_BUF_SYNC_END) + +// DMA-BUF sync structure +struct [[gnu::packed]] dma_buf_sync { + u64 flags; +}; + +// DMA-BUF attachment info +struct dma_buf_attachment { + struct dma_buf *dmabuf; + struct device *dev; + struct list_head node; + void *priv; +}; + +// DMA-BUF ops (kernel internal) +struct dma_buf_ops { + int (*attach)(struct dma_buf *, struct dma_buf_attachment *); + void (*detach)(struct dma_buf *, struct dma_buf_attachment *); + struct sg_table *(*map_dma_buf)(struct dma_buf_attachment *, + enum dma_data_direction); + void (*unmap_dma_buf)(struct dma_buf_attachment *, + struct sg_table *, + enum dma_data_direction); + void (*release)(struct dma_buf *); + int (*begin_cpu_access)(struct dma_buf *, enum dma_data_direction); + int (*end_cpu_access)(struct dma_buf *, enum dma_data_direction); + void *(*vmap)(struct dma_buf *); + void (*vunmap)(struct dma_buf *, void *vaddr); + int (*mmap)(struct dma_buf *, struct vm_area_struct *vma); +}; + +// DMA-BUF structure (kernel internal) +struct dma_buf { + u32 size; + u32 file_count; + const struct dma_buf_ops *ops; + struct list_head attachments; + void *priv; + const char *name; + u32 id; +}; + +// DMA data direction +enum dma_data_direction { + DMA_BIDIRECTIONAL = 0, + DMA_TO_DEVICE = 1, + DMA_FROM_DEVICE = 2, + DMA_NONE = 3, +}; + +// Scatterlist table (simplified) +struct scatterlist { + paddr_t dma_address; + u32 length; + u32 offset; +}; + +struct sg_table { + struct scatterlist *sgl; + u32 nents; + u32 orig_nents; +}; + +namespace dma_buf { + +// Function prototypes +struct dma_buf* allocate(u32 size, const struct dma_buf_ops *ops, void *priv); +void release(struct dma_buf *buf); +int attach(struct dma_buf *buf, struct dma_buf_attachment *attach); +void detach(struct dma_buf *buf, struct dma_buf_attachment *attach); +int begin_cpu_access(struct dma_buf *buf, enum dma_data_direction dir); +int end_cpu_access(struct dma_buf *buf, enum dma_data_direction dir); +void* vmap(struct dma_buf *buf); +void vunmap(struct dma_buf *buf, void *vaddr); +int sync(struct dma_buf *buf, u64 flags); + +} // namespace dma_buf + +#endif // _FISHIX_DMA_BUF_H diff --git a/kernel/src/include/uapi/linux/input.h b/kernel/src/include/uapi/linux/input.h new file mode 100644 index 0000000..295e8f0 --- /dev/null +++ b/kernel/src/include/uapi/linux/input.h @@ -0,0 +1,286 @@ +// kernel/src/include/uapi/linux/input.h +// Linux Input Event API untuk Fishix Wayland support + +#ifndef _FISHIX_INPUT_H +#define _FISHIX_INPUT_H + +#include + +// Event types +#define EV_SYN 0x00 +#define EV_KEY 0x01 +#define EV_REL 0x02 +#define EV_ABS 0x03 +#define EV_MSC 0x04 +#define EV_SW 0x05 +#define EV_LED 0x11 +#define EV_SND 0x12 +#define EV_REP 0x14 +#define EV_FF 0x15 +#define EV_PWR 0x16 +#define EV_FF_STATUS 0x17 +#define EV_MAX 0x1f +#define EV_CNT (EV_MAX + 1) + +// Synchronization events +#define SYN_REPORT 0 +#define SYN_CONFIG 1 +#define SYN_MT_REPORT 2 +#define SYN_DROPPED 3 + +// Keys and buttons +#define KEY_RESERVED 0 +#define KEY_ESC 1 +#define KEY_1 2 +#define KEY_2 3 +#define KEY_3 4 +#define KEY_4 5 +#define KEY_5 6 +#define KEY_6 7 +#define KEY_7 8 +#define KEY_8 9 +#define KEY_9 10 +#define KEY_0 11 +#define KEY_MINUS 12 +#define KEY_EQUAL 13 +#define KEY_BACKSPACE 14 +#define KEY_TAB 15 +#define KEY_Q 16 +#define KEY_W 17 +#define KEY_E 18 +#define KEY_R 19 +#define KEY_T 20 +#define KEY_Y 21 +#define KEY_U 22 +#define KEY_I 23 +#define KEY_O 24 +#define KEY_P 25 +#define KEY_LEFTBRACE 26 +#define KEY_RIGHTBRACE 27 +#define KEY_ENTER 28 +#define KEY_LEFTCTRL 29 +#define KEY_A 30 +#define KEY_S 31 +#define KEY_D 32 +#define KEY_F 33 +#define KEY_G 34 +#define KEY_H 35 +#define KEY_J 36 +#define KEY_K 37 +#define KEY_L 38 +#define KEY_SEMICOLON 39 +#define KEY_APOSTROPHE 40 +#define KEY_GRAVE 41 +#define KEY_LEFTSHIFT 42 +#define KEY_BACKSLASH 43 +#define KEY_Z 44 +#define KEY_X 45 +#define KEY_C 46 +#define KEY_V 47 +#define KEY_B 48 +#define KEY_N 49 +#define KEY_M 50 +#define KEY_COMMA 51 +#define KEY_DOT 52 +#define KEY_SLASH 53 +#define KEY_RIGHTSHIFT 54 +#define KEY_KPASTERISK 55 +#define KEY_LEFTALT 56 +#define KEY_SPACE 57 +#define KEY_CAPSLOCK 58 +#define KEY_F1 59 +#define KEY_F2 60 +#define KEY_F3 61 +#define KEY_F4 62 +#define KEY_F5 63 +#define KEY_F6 64 +#define KEY_F7 65 +#define KEY_F8 66 +#define KEY_F9 67 +#define KEY_F10 68 +#define KEY_NUMLOCK 69 +#define KEY_SCROLLLOCK 70 +#define KEY_KP7 71 +#define KEY_KP8 72 +#define KEY_KP9 73 +#define KEY_KPMINUS 74 +#define KEY_KP4 75 +#define KEY_KP5 76 +#define KEY_KP6 77 +#define KEY_KPPLUS 78 +#define KEY_KP1 79 +#define KEY_KP2 80 +#define KEY_KP3 81 +#define KEY_KP0 82 +#define KEY_KPDOT 83 +#define KEY_F11 87 +#define KEY_F12 88 + +// Mouse buttons +#define BTN_MOUSE 0x110 +#define BTN_LEFT 0x110 +#define BTN_RIGHT 0x111 +#define BTN_MIDDLE 0x112 +#define BTN_SIDE 0x113 +#define BTN_EXTRA 0x114 +#define BTN_FORWARD 0x115 +#define BTN_BACK 0x116 +#define BTN_TASK 0x117 + +// Relative axes +#define REL_X 0x00 +#define REL_Y 0x01 +#define REL_Z 0x02 +#define REL_RX 0x03 +#define REL_RY 0x04 +#define REL_RZ 0x05 +#define REL_HWHEEL 0x06 +#define REL_DIAL 0x07 +#define REL_WHEEL 0x08 +#define REL_MISC 0x09 +#define REL_MAX 0x0f +#define REL_CNT (REL_MAX + 1) + +// Absolute axes +#define ABS_X 0x00 +#define ABS_Y 0x01 +#define ABS_Z 0x02 +#define ABS_RX 0x03 +#define ABS_RY 0x04 +#define ABS_RZ 0x05 +#define ABS_THROTTLE 0x06 +#define ABS_RUDDER 0x07 +#define ABS_WHEEL 0x08 +#define ABS_GAS 0x09 +#define ABS_BRAKE 0x0a +#define ABS_HAT0X 0x10 +#define ABS_HAT0Y 0x11 +#define ABS_HAT1X 0x12 +#define ABS_HAT1Y 0x13 +#define ABS_HAT2X 0x14 +#define ABS_HAT2Y 0x15 +#define ABS_HAT3X 0x16 +#define ABS_HAT3Y 0x17 +#define ABS_PRESSURE 0x18 +#define ABS_DISTANCE 0x19 +#define ABS_TILT_X 0x1a +#define ABS_TILT_Y 0x1b +#define ABS_TOOL_WIDTH 0x1c +#define ABS_VOLUME 0x20 +#define ABS_MISC 0x28 +#define ABS_MAX 0x3f +#define ABS_CNT (ABS_MAX + 1) + +// Misc events +#define MSC_SERIAL 0x00 +#define MSC_PULSELED 0x01 +#define MSC_GESTURE 0x02 +#define MSC_RAW 0x03 +#define MSC_SCAN 0x04 +#define MSC_TIMESTAMP 0x05 +#define MSC_MAX 0x07 +#define MSC_CNT (MSC_MAX + 1) + +// LEDs +#define LED_NUML 0x00 +#define LED_CAPSL 0x01 +#define LED_SCROLLL 0x02 +#define LED_COMPOSE 0x03 +#define LED_KANA 0x04 +#define LED_MAX 0x0f +#define LED_CNT (LED_MAX + 1) + +// Autorepeat values +#define REP_DELAY 0x00 +#define REP_PERIOD 0x01 +#define REP_MAX 0x01 +#define REP_CNT (REP_MAX + 1) + +// Input ID +struct [[gnu::packed]] input_id { + u16 bustype; + u16 vendor; + u16 product; + u16 version; +}; + +// Input ABS info +struct [[gnu::packed]] input_absinfo { + i32 value; + i32 minimum; + i32 maximum; + i32 fuzz; + i32 flat; + i32 resolution; +}; + +// Input event structure +struct [[gnu::packed]] input_event { + struct { + i64 tv_sec; + i64 tv_usec; + } time; + u16 type; + u16 code; + i32 value; +}; + +// IOCTLs +#define EVIOCGVERSION _IOR('E', 0x01, int) +#define EVIOCGID _IOR('E', 0x02, struct input_id) +#define EVIOCGREP _IOR('E', 0x03, unsigned int[2]) +#define EVIOCSREP _IOW('E', 0x03, unsigned int[2]) +#define EVIOCGKEYCODE _IOR('E', 0x04, unsigned int[2]) +#define EVIOCGKEYCODE_V2 _IOR('E', 0x04, struct input_keymap_entry) +#define EVIOCSKEYCODE _IOW('E', 0x04, unsigned int[2]) +#define EVIOCSKEYCODE_V2 _IOW('E', 0x04, struct input_keymap_entry) + +#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) +#define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) +#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) +#define EVIOCGPROP(len) _IOC(_IOC_READ, 'E', 0x09, len) + +#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) +#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) +#define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) +#define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len) + +#define EVIOCGBIT(ev, len) _IOC(_IOC_READ, 'E', 0x20 + (ev), len) +#define EVIOCGABS(abs) _IOR('E', 0x40 + (abs), struct input_absinfo) +#define EVIOCSABS(abs) _IOW('E', 0xc0 + (abs), struct input_absinfo) + +#define EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect)) +#define EVIOCRMFF _IOW('E', 0x81, int) +#define EVIOCGEFFECTS _IOR('E', 0x84, int) + +#define EVIOCGRAB _IOW('E', 0x90, int) +#define EVIOCREVOKE _IOW('E', 0x91, int) +#define EVIOCGMASK _IOR('E', 0x92, struct input_mask) +#define EVIOCSMASK _IOW('E', 0x93, struct input_mask) +#define EVIOCCKMASK _IOW('E', 0x94, int) + +// Bus types +#define BUS_PCI 0x01 +#define BUS_ISAPNP 0x02 +#define BUS_USB 0x03 +#define BUS_HIL 0x04 +#define BUS_BLUETOOTH 0x05 +#define BUS_VIRTUAL 0x06 +#define BUS_ISA 0x10 +#define BUS_I8042 0x11 +#define BUS_XTKBD 0x12 +#define BUS_RS232 0x13 +#define BUS_GAMEPORT 0x14 +#define BUS_PARPORT 0x15 +#define BUS_AMIGA 0x16 +#define BUS_ADB 0x17 +#define BUS_I2C 0x18 +#define BUS_HOST 0x19 +#define BUS_GSC 0x1A +#define BUS_ATARI 0x1B +#define BUS_SPI 0x1C +#define BUS_RMI 0x1D +#define BUS_CEC 0x1E +#define BUS_INTEL_ISHTP 0x1F + +#endif // _FISHIX_INPUT_H diff --git a/kernel/src/kernel.hpp b/kernel/src/kernel.hpp new file mode 100644 index 0000000..e09a4d9 --- /dev/null +++ b/kernel/src/kernel.hpp @@ -0,0 +1,29 @@ +#pragma once + +// ====================================================== +// FISHIX KERNEL ROOT HEADER +// included by ALL kernel subsystems +// ====================================================== + +// ---- basic klib ---- +#include +#include +#include +#include +#include + +// ---- core kernel ---- +#include +#include + +// ---- memory ---- +#include +#include +#include + +// ---- scheduler ---- +#include +#include + +// ---- filesystem ---- +#include \ No newline at end of file diff --git a/kernel/src/klib/common.hpp b/kernel/src/klib/common.hpp index 15c74f8..9505981 100644 --- a/kernel/src/klib/common.hpp +++ b/kernel/src/klib/common.hpp @@ -21,6 +21,7 @@ using usize = size_t; using isize = i64; using uptr = uintptr_t; using uint = unsigned int; +using paddr_t = u64; using nullptr_t = decltype(nullptr); diff --git a/kernel/src/klib/cppruntime.cpp b/kernel/src/klib/cppruntime.cpp index 1edc57c..d411dfc 100644 --- a/kernel/src/klib/cppruntime.cpp +++ b/kernel/src/klib/cppruntime.cpp @@ -69,8 +69,8 @@ void operator delete[](void *ptr) { } void operator delete(void *ptr, usize size) { - ::operator delete(ptr); memset(ptr, 0xAE, size); + ::operator delete(ptr); } void operator delete[](void *ptr, usize size) { diff --git a/kernel/src/klib/ioctl.hpp b/kernel/src/klib/ioctl.hpp new file mode 100644 index 0000000..939f708 --- /dev/null +++ b/kernel/src/klib/ioctl.hpp @@ -0,0 +1,49 @@ +// kernel/src/include/klib/ioctl.hpp +// IOCTL macros untuk Fishix kernel + +#ifndef _KLIB_IOCTL_HPP +#define _KLIB_IOCTL_HPP + +#include + +// IOCTL type constants +#define _IOC_NRBITS 8 +#define _IOC_TYPEBITS 8 +#define _IOC_SIZEBITS 14 +#define _IOC_DIRBITS 2 + +#define _IOC_NRMASK ((1 << _IOC_NRBITS) - 1) +#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS) - 1) +#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS) - 1) +#define _IOC_DIRMASK ((1 << _IOC_DIRBITS) - 1) + +#define _IOC_NRSHIFT 0 +#define _IOC_TYPESHIFT (_IOC_NRSHIFT + _IOC_NRBITS) +#define _IOC_SIZESHIFT (_IOC_TYPESHIFT + _IOC_TYPEBITS) +#define _IOC_DIRSHIFT (_IOC_SIZESHIFT + _IOC_SIZEBITS) + +// Direction constants +#define _IOC_NONE 0U +#define _IOC_WRITE 1U +#define _IOC_READ 2U + +// Build IOCTL command +#define _IOC(dir, type, nr, size) \ + (((dir) << _IOC_DIRSHIFT) | \ + ((type) << _IOC_TYPESHIFT) | \ + ((nr) << _IOC_NRSHIFT) | \ + ((size) << _IOC_SIZESHIFT)) + +// Simplified IOCTL commands (no size checking) +#define _IO(type, nr) _IOC(_IOC_NONE, (type), (nr), 0) +#define _IOR(type, nr, size) _IOC(_IOC_READ, (type), (nr), sizeof(size)) +#define _IOW(type, nr, size) _IOC(_IOC_WRITE, (type), (nr), sizeof(size)) +#define _IOWR(type, nr, size) _IOC(_IOC_READ | _IOC_WRITE, (type), (nr), sizeof(size)) + +// Extract fields dari IOCTL command +#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) +#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK) +#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK) +#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK) + +#endif // _KLIB_IOCTL_HPP diff --git a/kernel/src/klib/list.hpp b/kernel/src/klib/list.hpp index c7bcdc4..16c18ea 100644 --- a/kernel/src/klib/list.hpp +++ b/kernel/src/klib/list.hpp @@ -6,9 +6,9 @@ #define LIST_ENTRY(link, type, member) (type*)((uptr)link - (uptr)(&((type*)0)->member)) #define LIST_HEAD(list, type, member) LIST_ENTRY((list)->next, type, member) #define LIST_TAIL(list, type, member) LIST_ENTRY((list)->prev, type, member) -#define LIST_NEXT(elm, member) LIST_ENTRY((elm)->member.next, typeof(*elm), member) -#define LIST_FOR_EACH(pos, list, member) for (pos = LIST_HEAD(list, typeof(*pos), member); &pos->member != (list); pos = LIST_NEXT(pos, member)) -#define LIST_FOR_EACH_SAFE(pos, list, member) decltype(pos) next; for (pos = LIST_HEAD(list, typeof(*pos), member), next = LIST_NEXT(pos, member); &pos->member != (list); pos = next, next = LIST_NEXT(next, member)) +#define LIST_NEXT(elm, member) LIST_ENTRY((elm)->member.next, typename klib::RemovePointer::type, member) +#define LIST_FOR_EACH(pos, list, member) for (pos = LIST_HEAD(list, typename klib::RemovePointer::type, member); &pos->member != (list); pos = LIST_NEXT(pos, member)) +#define LIST_FOR_EACH_SAFE(pos, list, member) decltype(pos) next; for (pos = LIST_HEAD(list, typename klib::RemovePointer::type, member), next = LIST_NEXT(pos, member); &pos->member != (list); pos = next, next = LIST_NEXT(next, member)) #define HLIST_ENTRY(link, type, member) (type*)((uptr)link - (uptr)(&((type*)0)->member)) #define HLIST_FOR_EACH(pos, head) for (pos = (head)->first; pos; pos = pos->next) @@ -103,4 +103,25 @@ namespace klib { return first == nullptr; } }; -} + + inline bool list_empty(ListHead *head) { + return head->is_empty(); + } + + inline void list_add_tail(ListHead *entry, ListHead *head) { + head->add_before(entry); + } + + inline ListHead* list_pop_front(ListHead *head) { + if (head->is_empty()) return nullptr; + ListHead *entry = head->next; + entry->remove(); + return entry; + } + +} // namespace klib + +#define list_entry LIST_ENTRY +#define list_empty klib::list_empty +#define list_add_tail klib::list_add_tail +#define list_pop_front klib::list_pop_front diff --git a/kernel/src/klib/poll.hpp b/kernel/src/klib/poll.hpp new file mode 100644 index 0000000..1e894ad --- /dev/null +++ b/kernel/src/klib/poll.hpp @@ -0,0 +1,24 @@ +// kernel/src/include/klib/poll.hpp +// Poll flags untuk Fishix kernel + +#ifndef _KLIB_POLL_HPP +#define _KLIB_POLL_HPP + +#include + +// Poll flags (compatible dengan Linux) +#define POLLIN 0x001 +#define POLLPRI 0x002 +#define POLLOUT 0x004 +#define POLLERR 0x008 +#define POLLHUP 0x010 +#define POLLNVAL 0x020 +#define POLLRDNORM 0x040 +#define POLLRDBAND 0x080 +#define POLLWRNORM 0x100 +#define POLLWRBAND 0x200 +#define POLLMSG 0x400 +#define POLLREMOVE 0x1000 +#define POLLRDHUP 0x2000 + +#endif // _KLIB_POLL_HPP diff --git a/kernel/src/klib/vector.hpp b/kernel/src/klib/vector.hpp index ff1ad45..650ef47 100644 --- a/kernel/src/klib/vector.hpp +++ b/kernel/src/klib/vector.hpp @@ -1,93 +1,225 @@ #pragma once #include +#include namespace klib { - template - class Vector { - T *m_buffer; - usize m_size; - usize m_capacity; - - void increase_capacity(usize new_capacity) { - if (new_capacity > m_capacity) { - while (new_capacity > m_capacity) - m_capacity = m_capacity ? m_capacity * 2 : 1; - m_buffer = (T*)klib::realloc(m_buffer, m_capacity * sizeof(T)); - } - } - public: - Vector(usize reserve = 0) : m_size(0), m_capacity(reserve) { - m_buffer = (T*)(reserve ? klib::malloc(reserve * sizeof(T)) : nullptr); - } +template +class Vector { +private: + T* m_buffer = nullptr; + usize m_size = 0; + usize m_capacity = 0; - ~Vector() { - klib::free(m_buffer); - } + void destroy_range(usize from, usize to) { + for (usize i = from; i < to; ++i) + m_buffer[i].~T(); + } - Vector(const Vector &other) { - m_size = other.m_size; - m_capacity = other.m_capacity; - if (other.m_buffer) { - m_buffer = klib::malloc(m_capacity * sizeof(T)); - for (usize i = 0; i < m_size; i++) - m_buffer[i] = other.m_buffer[i]; - } else { - m_buffer = nullptr; - } - } + void reserve_internal(usize new_cap) { + if (new_cap <= m_capacity) + return; - T& operator [](usize index) const { - return m_buffer[index]; - } + usize cap = m_capacity ? m_capacity : 1; + while (cap < new_cap) + cap *= 2; + + T* new_buf = (T*)klib::malloc(sizeof(T) * cap); - template - T& emplace_back(Args&&... args) { - increase_capacity(++m_size); - return *new (m_buffer + m_size - 1) T(klib::forward(args)...);; + // move existing objects + for (usize i = 0; i < m_size; ++i) { + new (new_buf + i) T(klib::move(m_buffer[i])); + m_buffer[i].~T(); } - T& push_back(const T &t) { return emplace_back(t); } - T& push_back(T &&t) { return emplace_back(klib::move(t)); } + klib::free(m_buffer); + + m_buffer = new_buf; + m_capacity = cap; + } + +public: + + /* ========================= + Constructors + ========================= */ + + Vector() = default; + + explicit Vector(usize reserve) { + reserve_internal(reserve); + } + + Vector(const Vector& other) { + reserve_internal(other.m_size); + + for (usize i = 0; i < other.m_size; ++i) + new (m_buffer + i) T(other.m_buffer[i]); + + m_size = other.m_size; + } + + Vector(Vector&& other) noexcept { + m_buffer = other.m_buffer; + m_size = other.m_size; + m_capacity = other.m_capacity; + + other.m_buffer = nullptr; + other.m_size = 0; + other.m_capacity = 0; + } + + ~Vector() { + clear(); + klib::free(m_buffer); + } + + /* ========================= + Assignment + ========================= */ + + Vector& operator=(const Vector& other) { + if (this == &other) + return *this; + + clear(); + reserve_internal(other.m_size); + + for (usize i = 0; i < other.m_size; ++i) + new (m_buffer + i) T(other.m_buffer[i]); + + m_size = other.m_size; + return *this; + } + + Vector& operator=(Vector&& other) noexcept { + clear(); + klib::free(m_buffer); - void resize(usize new_size) { - increase_capacity(new_size); - m_size = new_size; + m_buffer = other.m_buffer; + m_size = other.m_size; + m_capacity = other.m_capacity; + + other.m_buffer = nullptr; + other.m_size = 0; + other.m_capacity = 0; + + return *this; + } + + /* ========================= + Element Access + ========================= */ + + T& operator[](usize index) { + return m_buffer[index]; + } + + const T& operator[](usize index) const { + return m_buffer[index]; + } + + T& back() { + return m_buffer[m_size - 1]; + } + + /* ========================= + Capacity + ========================= */ + + void reserve(usize cap) { + reserve_internal(cap); + } + + usize size() const { return m_size; } + usize capacity() const { return m_capacity; } + bool empty() const { return m_size == 0; } + + T* data() { return m_buffer; } + const T* data() const { return m_buffer; } + + /* ========================= + Modifiers + ========================= */ + + template + T& emplace_back(Args&&... args) { + reserve_internal(m_size + 1); + + new (m_buffer + m_size) + T(klib::forward(args)...); + + return m_buffer[m_size++]; + } + + T& push_back(const T& v) { + return emplace_back(v); + } + + T& push_back(T&& v) { + return emplace_back(klib::move(v)); + } + + void pop_back() { + if (!m_size) return; + m_buffer[--m_size].~T(); + } + + void resize(usize new_size) { + if (new_size < m_size) { + destroy_range(new_size, m_size); + } else { + reserve_internal(new_size); + for (usize i = m_size; i < new_size; ++i) + new (m_buffer + i) T(); } - inline constexpr T* data() const { return m_buffer; } - inline constexpr usize size() const { return m_size; } - inline constexpr usize capacity() const { return m_capacity; } + m_size = new_size; + } + + void clear() { + destroy_range(0, m_size); + m_size = 0; + } + + void remove(usize index) { + if (index >= m_size) return; - void clear() { - resize(0); + m_buffer[index].~T(); + + // Shift elements + for (usize i = index; i < m_size - 1; ++i) { + new (m_buffer + i) T(klib::move(m_buffer[i + 1])); + m_buffer[i + 1].~T(); } - struct iterator { - using value_type = T; - using pointer = T*; - using reference = T&; + --m_size; + } + + /* ========================= + Iterators + ========================= */ + + struct iterator { + T* ptr; - explicit iterator(pointer ptr) : ptr(ptr) {} - reference operator *() const { return *ptr; } - pointer operator ->() const { return ptr; } + iterator(T* p) : ptr(p) {} - iterator& operator ++() { ++ptr; return *this; } - iterator operator ++(int) { iterator tmp = *this; ++ptr; return tmp; } - iterator& operator --() { --ptr; return *this; } - iterator operator --(int) { iterator tmp = *this; --ptr; return tmp; } + T& operator*() const { return *ptr; } + T* operator->() const { return ptr; } - friend bool operator ==(const iterator &a, const iterator &b) { return a.ptr == b.ptr; } - friend bool operator !=(const iterator &a, const iterator &b) { return a.ptr != b.ptr; } - friend usize operator -(const iterator &a, const iterator &b) { return a.ptr - b.ptr; } - friend bool operator <(const iterator &a, const iterator &b) { return a.ptr < b.ptr; } + iterator& operator++() { ++ptr; return *this; } + iterator operator++(int){ iterator t=*this; ++ptr; return t; } - private: - pointer ptr; - }; + iterator& operator--() { --ptr; return *this; } - iterator begin() { return iterator(m_buffer); } - iterator end() { return iterator(m_buffer + m_size); } + bool operator==(const iterator& o) const { return ptr == o.ptr; } + bool operator!=(const iterator& o) const { return ptr != o.ptr; } }; -} + + iterator begin() { return iterator(m_buffer); } + iterator end() { return iterator(m_buffer + m_size); } +}; + +} // namespace klib \ No newline at end of file diff --git a/kernel/src/linux_types.hpp b/kernel/src/linux_types.hpp new file mode 100644 index 0000000..fea5ce2 --- /dev/null +++ b/kernel/src/linux_types.hpp @@ -0,0 +1,15 @@ +#pragma once + +using ssize_t = long; +using paddr_t = unsigned long long; + +struct list_head { + list_head *next; + list_head *prev; +}; + +enum dma_data_direction { + DMA_BIDIRECTIONAL, + DMA_TO_DEVICE, + DMA_FROM_DEVICE +}; \ No newline at end of file diff --git a/kernel/src/mem/dma.cpp b/kernel/src/mem/dma.cpp new file mode 100644 index 0000000..be74732 --- /dev/null +++ b/kernel/src/mem/dma.cpp @@ -0,0 +1,215 @@ +// kernel/src/mem/dma.cpp +// DMA Memory Operations untuk Fishix Wayland support +// Menyediakan contiguous physical memory untuk GPU buffers + +#include +#include +#include +#include +#include +#include + +namespace mem { struct MappedRange; } + +namespace mem { + +namespace dma { + +// DMA pool untuk small allocations +static struct dma_pool { + u64 base; + usize size; + usize used; + klib::Spinlock lock; + bool initialized; +} g_dma_pool = {0, 0, 0, {}, false}; + +// DMA coherent memory region +static u64 dma_coherent_base = 0; +static usize dma_coherent_size = 0; + +// Initialize DMA subsystem +void init(void) { + // Allocate 32MB untuk DMA coherent memory + dma_coherent_size = 32 * 1024 * 1024; // 32MB + + // Allocate contiguous physical pages + usize pages = dma_coherent_size / PAGE_SIZE; + dma_coherent_base = pmm::alloc_contiguous_pages(pages); + + if (!dma_coherent_base) { + klib::printf("DMA: Failed to allocate coherent memory pool\n"); + return; + } + + // Map ke kernel address space dengan write-combining + uptr virt_base = dma_coherent_base + mem::hhdm; + for (usize i = 0; i < pages; i++) { + u64 phys = dma_coherent_base + (i * PAGE_SIZE); + uptr virt = virt_base + (i * PAGE_SIZE); + mem::vmm->kernel_pagemap.map_page(virt, phys, + PAGE_PRESENT | PAGE_WRITABLE | PAGE_NO_EXECUTE | PAGE_WRITE_COMBINING); + } + + // Initialize pool + g_dma_pool.base = dma_coherent_base; + g_dma_pool.size = dma_coherent_size; + g_dma_pool.used = 0; + g_dma_pool.lock.unlock(); // Ensure it's unlocked + g_dma_pool.initialized = true; + + klib::printf("DMA: Initialized %zu MB coherent memory at %#lX\n", + dma_coherent_size / (1024 * 1024), dma_coherent_base); +} + +// Allocate contiguous DMA memory +void* alloc_coherent(usize size, u64 *phys_addr) { + if (!g_dma_pool.initialized) { + klib::printf("DMA: Pool not initialized\n"); + return nullptr; + } + + // Align size ke page boundary + usize aligned_size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + + g_dma_pool.lock.lock(); + + if (g_dma_pool.used + aligned_size > g_dma_pool.size) { + g_dma_pool.lock.unlock(); + klib::printf("DMA: Out of coherent memory (requested %zu, available %zu)\n", + aligned_size, g_dma_pool.size - g_dma_pool.used); + return nullptr; + } + + u64 phys = g_dma_pool.base + g_dma_pool.used; + g_dma_pool.used += aligned_size; + + g_dma_pool.lock.unlock(); + + uptr virt = phys + mem::hhdm; + + if (phys_addr) { + *phys_addr = phys; + } + + // Zero the memory + memset((void*)virt, 0, aligned_size); + + return (void*)virt; +} + +// Free DMA coherent memory (simplified - tidak bisa free individual untuk pool allocator) +void free_coherent(usize size, void *vaddr, u64 phys_addr) { + // Untuk pool allocator sederhana, kita tidak support individual free + // Dalam implementasi production, gunakan buddy allocator atau slab allocator + // Untuk Wayland demo, ini cukup karena buffers biasanya long-lived + (void)size; + (void)vaddr; + (void)phys_addr; +} + +// Allocate contiguous physical pages untuk large buffers +u64 alloc_contiguous_pages(usize num_pages) { + return pmm::alloc_contiguous_pages(num_pages); +} + +// Free contiguous pages +void free_contiguous_pages(u64 base, usize num_pages) { + pmm::free_contiguous_pages(base, num_pages); +} + +// Map DMA buffer ke userspace +int mmap_buffer(mem::MappedRange *vma, u64 phys_base, usize size) { + if (!vma) return -EINVAL; + + uptr virt_start = vma->base; + usize pages = (size + PAGE_SIZE - 1) / PAGE_SIZE; + + for (usize i = 0; i < pages; i++) { + u64 phys = phys_base + (i * PAGE_SIZE); + uptr virt = virt_start + (i * PAGE_SIZE); + + // Map dengan user-accessible flags + u64 flags = PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER | PAGE_NO_EXECUTE; + + // Gunakan write-combining untuk framebuffer + flags |= PAGE_WRITE_COMBINING; + + mem::vmm->active_pagemap->map_page(virt, phys, flags); + } + + return 0; +} + +// Sync DMA buffer untuk CPU access +void sync_for_cpu(u64 phys_addr, usize size, enum dma_data_direction dir) { + (void)phys_addr; + (void)size; + (void)dir; + + // Invalidate CPU cache untuk memastikan CPU melihat data terbaru dari device + // x86_64: CLFLUSH atau non-temporal hint + // Untuk simplicity, kita rely pada write-combining memory type +} + +// Sync DMA buffer untuk device access +void sync_for_device(u64 phys_addr, usize size, enum dma_data_direction dir) { + (void)phys_addr; + (void)size; + (void)dir; + + // Flush CPU cache ke memory agar device melihat data terbaru + // CLFLUSH untuk range + uptr virt = phys_addr + mem::hhdm; + for (usize i = 0; i < size; i += 64) { // 64-byte cache line + __asm__ volatile("clflush %0" :: "m"(*(char*)(virt + i))); + } + __asm__ volatile("mfence" ::: "memory"); +} + +// Get physical address dari virtual address +u64 virt_to_phys(void *vaddr) { + uptr va = (uptr)vaddr; + + // Check jika dalam HHDM range + if (va >= mem::hhdm && va < mem::hhdm + 0x100000000) { + return va - mem::hhdm; + } + + // Otherwise, lookup page table + return mem::vmm->active_pagemap->get_physical_addr(va); +} + +// Get virtual address dari physical address (HHDM) +void* phys_to_virt(u64 paddr) { + return (void*)(paddr + mem::hhdm); +} + +// Check jika address adalah DMA coherent +bool is_coherent(u64 paddr) { + if (!g_dma_pool.initialized) return false; + return (paddr >= dma_coherent_base && + paddr < dma_coherent_base + dma_coherent_size); +} + +// Get DMA pool stats +void get_dma_statistics(usize *total, usize *used, usize *free) { + if (total) *total = g_dma_pool.size; + if (used) *used = g_dma_pool.used; + if (free) *free = g_dma_pool.size - g_dma_pool.used; +} + +// Debug: Print DMA stats +void debug_stats(void) { + usize total, used, free; + get_dma_statistics(&total, &used, &free); + + klib::printf("DMA Pool Stats:\n"); + klib::printf(" Total: %zu MB\n", total / (1024 * 1024)); + klib::printf(" Used: %zu MB (%zu%%)\n", used / (1024 * 1024), (used * 100) / total); + klib::printf(" Free: %zu MB\n", free / (1024 * 1024)); +} + +} // namespace dma + +} // namespace mem diff --git a/kernel/src/mem/dma.hpp b/kernel/src/mem/dma.hpp new file mode 100644 index 0000000..127c535 --- /dev/null +++ b/kernel/src/mem/dma.hpp @@ -0,0 +1,60 @@ +// kernel/src/mm/dma.hpp +// DMA Memory Operations header untuk Fishix Wayland support + +#ifndef _FISHIX_DMA_HPP +#define _FISHIX_DMA_HPP + +#include +#include +#include + +namespace mem { struct MappedRange; } + +namespace mem { + +namespace dma { + +// DMA data direction (match dengan dma-buf.h) +enum dma_data_direction { + DMA_BIDIRECTIONAL = 0, + DMA_TO_DEVICE = 1, + DMA_FROM_DEVICE = 2, + DMA_NONE = 3, +}; + +// Initialize DMA subsystem +void init(void); + +// Allocate contiguous DMA memory (coherent) +void* alloc_coherent(usize size, u64 *phys_addr); + +// Free DMA coherent memory +void free_coherent(usize size, void *vaddr, u64 phys_addr); + +// Allocate contiguous physical pages +u64 alloc_contiguous_pages(usize num_pages); + +// Free contiguous pages +void free_contiguous_pages(u64 base, usize num_pages); + +// Map DMA buffer ke userspace +int mmap_buffer(mem::MappedRange *vma, u64 phys_base, usize size); + +// Sync operations +void sync_for_cpu(u64 phys_addr, usize size, enum dma_data_direction dir); +void sync_for_device(u64 phys_addr, usize size, enum dma_data_direction dir); + +// Address translation +u64 virt_to_phys(void *vaddr); +void* phys_to_virt(u64 paddr); + +// Utility +bool is_coherent(u64 paddr); +void get_dma_statistics(usize *total, usize *used, usize *free); +void debug_stats(void); + +} // namespace dma + +} // namespace mem + +#endif // _FISHIX_DMA_HPP diff --git a/kernel/src/mem/pmm.cpp b/kernel/src/mem/pmm.cpp index 7000f50..567800d 100644 --- a/kernel/src/mem/pmm.cpp +++ b/kernel/src/mem/pmm.cpp @@ -129,4 +129,43 @@ namespace pmm { page_freelist.add(&page->link); stats.total_free_pages++; } + + uptr alloc_contiguous_pages(usize num_pages) { + klib::SpinlockGuard guard(pmm_lock); + + const Region *region; + LIST_FOR_EACH(region, ®ion_list, link) { + Page *pages = region->pages_array(); + usize usable = region->num_pages_usable(); + + for (usize i = 0; i <= usable - num_pages; i++) { + bool found = true; + for (usize j = 0; j < num_pages; j++) { + if (!pages[i + j].free) { + found = false; + i += j; + break; + } + } + + if (found) { + for (usize j = 0; j < num_pages; j++) { + pages[i + j].free = false; + pages[i + j].link.remove(); + stats.total_free_pages--; + } + return pages[i].phy(); + } + } + } + + return 0; + } + + void free_contiguous_pages(uptr base, usize num_pages) { + for (usize i = 0; i < num_pages; i++) { + Page *page = find_page(base + i * PAGE_SIZE); + if (page) free_page(page); + } + } } diff --git a/kernel/src/mem/pmm.hpp b/kernel/src/mem/pmm.hpp index 815a0b5..f0c92c2 100644 --- a/kernel/src/mem/pmm.hpp +++ b/kernel/src/mem/pmm.hpp @@ -43,6 +43,9 @@ namespace pmm { Page* alloc_page(); void free_page(Page *page); + uptr alloc_contiguous_pages(usize num_pages); + void free_contiguous_pages(uptr base, usize num_pages); + inline uptr alloc_pages(usize num_pages) { ASSERT(num_pages == 1); Page *page = alloc_page(); diff --git a/kernel/src/uapi/drm/drm.h b/kernel/src/uapi/drm/drm.h new file mode 100644 index 0000000..df464df --- /dev/null +++ b/kernel/src/uapi/drm/drm.h @@ -0,0 +1,599 @@ +// kernel/src/include/uapi/drm/drm.h +// UAPI DRM header untuk Fishix - Compatible dengan Linux DRM ABI +// Untuk Wayland support + +#ifndef _FISHIX_DRM_H +#define _FISHIX_DRM_H + +#include + +#define DRM_MAJOR 226 +#define DRM_IOCTL_BASE 'd' + +#define DRM_IO(nr) _IOC(DRM_IOCTL_BASE, nr, 0, 0) +#define DRM_IOR(nr, type) _IOR(DRM_IOCTL_BASE, nr, type) +#define DRM_IOW(nr, type) _IOW(DRM_IOCTL_BASE, nr, type) +#define DRM_IOWR(nr, type) _IOWR(DRM_IOCTL_BASE, nr, type) + +// IOCTL numbers (from Linux drm_ioctl.h) +#define DRM_IOCTL_VERSION DRM_IOWR(0x00, struct drm_version) +#define DRM_IOCTL_GET_UNIQUE DRM_IOWR(0x01, struct drm_unique) +#define DRM_IOCTL_GET_MAGIC DRM_IOR(0x02, struct drm_auth) +#define DRM_IOCTL_IRQ_BUSID DRM_IOWR(0x03, struct drm_irq_busid) +#define DRM_IOCTL_GET_MAP DRM_IOWR(0x04, struct drm_map) +#define DRM_IOCTL_GET_CLIENT DRM_IOWR(0x05, struct drm_client) +#define DRM_IOCTL_GET_STATS DRM_IOR(0x06, struct drm_stats) +#define DRM_IOCTL_SET_VERSION DRM_IOWR(0x07, struct drm_set_version) +#define DRM_IOCTL_MODESET_CTL DRM_IOW(0x08, struct drm_modeset_ctl) +#define DRM_IOCTL_GEM_CLOSE DRM_IOW(0x09, struct drm_gem_close) +#define DRM_IOCTL_GEM_FLINK DRM_IOWR(0x0a, struct drm_gem_flink) +#define DRM_IOCTL_GEM_OPEN DRM_IOWR(0x0b, struct drm_gem_open) +#define DRM_IOCTL_GET_CAP DRM_IOWR(0x0c, struct drm_get_cap) +#define DRM_IOCTL_SET_CLIENT_CAP DRM_IOW(0x0d, struct drm_set_client_cap) + +// Mode setting IOCTLs +#define DRM_IOCTL_MODE_GETRESOURCES DRM_IOWR(0xa0, struct drm_mode_card_res) +#define DRM_IOCTL_MODE_GETCRTC DRM_IOWR(0xa1, struct drm_mode_crtc) +#define DRM_IOCTL_MODE_SETCRTC DRM_IOWR(0xa2, struct drm_mode_crtc) +#define DRM_IOCTL_MODE_CURSOR DRM_IOWR(0xa3, struct drm_mode_cursor) +#define DRM_IOCTL_MODE_GETGAMMA DRM_IOWR(0xa4, struct drm_mode_crtc_lut) +#define DRM_IOCTL_MODE_SETGAMMA DRM_IOWR(0xa5, struct drm_mode_crtc_lut) +#define DRM_IOCTL_MODE_GETENCODER DRM_IOWR(0xa6, struct drm_mode_get_encoder) +#define DRM_IOCTL_MODE_GETCONNECTOR DRM_IOWR(0xa7, struct drm_mode_get_connector) +#define DRM_IOCTL_MODE_ATTACHMODE DRM_IOWR(0xa8, struct drm_mode_mode_cmd) +#define DRM_IOCTL_MODE_DETACHMODE DRM_IOWR(0xa9, struct drm_mode_mode_cmd) +#define DRM_IOCTL_MODE_GETPROPERTY DRM_IOWR(0xaa, struct drm_mode_get_property) +#define DRM_IOCTL_MODE_SETPROPERTY DRM_IOWR(0xab, struct drm_mode_connector_set_property) +#define DRM_IOCTL_MODE_GETPROPBLOB DRM_IOWR(0xac, struct drm_mode_get_blob) +#define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xad, struct drm_mode_fb_cmd) +#define DRM_IOCTL_MODE_ADDFB DRM_IOWR(0xae, struct drm_mode_fb_cmd) +#define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xaf, unsigned int) +#define DRM_IOCTL_MODE_PAGE_FLIP DRM_IOWR(0xb0, struct drm_mode_crtc_page_flip) +#define DRM_IOCTL_MODE_DIRTYFB DRM_IOWR(0xb1, struct drm_mode_fb_dirty_cmd) +#define DRM_IOCTL_MODE_CREATE_DUMB DRM_IOWR(0xb2, struct drm_mode_create_dumb) +#define DRM_IOCTL_MODE_MAP_DUMB DRM_IOWR(0xb3, struct drm_mode_map_dumb) +#define DRM_IOCTL_MODE_DESTROY_DUMB DRM_IOWR(0xb4, struct drm_mode_destroy_dumb) +#define DRM_IOCTL_MODE_GETPLANERESOURCES DRM_IOWR(0xb5, struct drm_mode_get_plane_res) +#define DRM_IOCTL_MODE_GETPLANE DRM_IOWR(0xb6, struct drm_mode_get_plane) +#define DRM_IOCTL_MODE_SETPLANE DRM_IOWR(0xb7, struct drm_mode_set_plane) +#define DRM_IOCTL_MODE_ADDFB2 DRM_IOWR(0xb8, struct drm_mode_fb_cmd2) +#define DRM_IOCTL_MODE_OBJ_GETPROPERTIES DRM_IOWR(0xb9, struct drm_mode_obj_get_properties) +#define DRM_IOCTL_MODE_OBJ_SETPROPERTY DRM_IOWR(0xba, struct drm_mode_obj_set_property) +#define DRM_IOCTL_MODE_CURSOR2 DRM_IOWR(0xbb, struct drm_mode_cursor2) +#define DRM_IOCTL_MODE_ATOMIC DRM_IOWR(0xbc, struct drm_mode_atomic) + +// Capabilities +#define DRM_CAP_DUMB_BUFFER 0x1 +#define DRM_CAP_VBLANK_HIGH_CRTC 0x2 +#define DRM_CAP_DUMB_PREFERRED_DEPTH 0x3 +#define DRM_CAP_DUMB_PREFER_SHADOW 0x4 +#define DRM_CAP_PRIME 0x5 +#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6 +#define DRM_CAP_ASYNC_PAGE_FLIP 0x7 +#define DRM_CAP_CURSOR_WIDTH 0x8 +#define DRM_CAP_CURSOR_HEIGHT 0x9 +#define DRM_CAP_ADDFB2_MODIFIERS 0x10 +#define DRM_CAP_PAGE_FLIP_TARGET 0x11 +#define DRM_CAP_CRTC_IN_VBLANK_EVENT 0x12 +#define DRM_CAP_SYNCOBJ 0x13 +#define DRM_CAP_SYNCOBJ_TIMELINE 0x14 + +// Client capabilities +#define DRM_CLIENT_CAP_STEREO_3D 1 +#define DRM_CLIENT_CAP_UNIVERSAL_PLANES 2 +#define DRM_CLIENT_CAP_ATOMIC 3 +#define DRM_CLIENT_CAP_ASPECT_RATIO 4 +#define DRM_CLIENT_CAP_WRITEBACK_CONNECTORS 5 + +// DRM modes +#define DRM_MODE_CONNECTED 1 +#define DRM_MODE_DISCONNECTED 2 +#define DRM_MODE_UNKNOWNCONNECTION 3 + +#define DRM_MODE_SUBCONNECTOR_Automatic 0 +#define DRM_MODE_SUBCONNECTOR_Unknown 0 +#define DRM_MODE_SUBCONNECTOR_DVID 1 +#define DRM_MODE_SUBCONNECTOR_DVIA 2 +#define DRM_MODE_SUBCONNECTOR_Composite 3 +#define DRM_MODE_SUBCONNECTOR_SVIDEO 4 +#define DRM_MODE_SUBCONNECTOR_Component 5 +#define DRM_MODE_SUBCONNECTOR_SCART 6 + +#define DRM_MODE_PROP_PENDING (1 << 0) +#define DRM_MODE_PROP_RANGE (1 << 1) +#define DRM_MODE_PROP_IMMUTABLE (1 << 2) +#define DRM_MODE_PROP_ENUM (1 << 3) +#define DRM_MODE_PROP_BLOB (1 << 4) +#define DRM_MODE_PROP_BITMASK (1 << 5) +#define DRM_MODE_PROP_LEGACY_TYPE (1 << 6) +#define DRM_MODE_PROP_EXTENDED_TYPE 0x0000ffc0 +#define DRM_MODE_PROP_OBJECT (1 << 6) +#define DRM_MODE_PROP_SIGNED_RANGE (1 << 7) + +#define DRM_MODE_PROP_ATOMIC 0x80000000 + +#define DRM_MODE_ENCODER_NONE 0 +#define DRM_MODE_ENCODER_DAC 1 +#define DRM_MODE_ENCODER_TMDS 2 +#define DRM_MODE_ENCODER_LVDS 3 +#define DRM_MODE_ENCODER_TVDAC 4 +#define DRM_MODE_ENCODER_VIRTUAL 5 +#define DRM_MODE_ENCODER_DSI 6 +#define DRM_MODE_ENCODER_DPMST 7 +#define DRM_MODE_ENCODER_DPI 8 + +#define DRM_MODE_CONNECTOR_Unknown 0 +#define DRM_MODE_CONNECTOR_VGA 1 +#define DRM_MODE_CONNECTOR_DVII 2 +#define DRM_MODE_CONNECTOR_DVID 3 +#define DRM_MODE_CONNECTOR_DVIA 4 +#define DRM_MODE_CONNECTOR_Composite 5 +#define DRM_MODE_CONNECTOR_SVIDEO 6 +#define DRM_MODE_CONNECTOR_LVDS 7 +#define DRM_MODE_CONNECTOR_Component 8 +#define DRM_MODE_CONNECTOR_9PinDIN 9 +#define DRM_MODE_CONNECTOR_DisplayPort 10 +#define DRM_MODE_CONNECTOR_HDMIA 11 +#define DRM_MODE_CONNECTOR_HDMIB 12 +#define DRM_MODE_CONNECTOR_TV 13 +#define DRM_MODE_CONNECTOR_eDP 14 +#define DRM_MODE_CONNECTOR_VIRTUAL 15 +#define DRM_MODE_CONNECTOR_DSI 16 +#define DRM_MODE_CONNECTOR_DPI 17 +#define DRM_MODE_CONNECTOR_WRITEBACK 18 +#define DRM_MODE_CONNECTOR_SPI 19 + +#define DRM_MODE_FLAG_PHSYNC (1 << 0) +#define DRM_MODE_FLAG_NHSYNC (1 << 1) +#define DRM_MODE_FLAG_PVSYNC (1 << 2) +#define DRM_MODE_FLAG_NVSYNC (1 << 3) +#define DRM_MODE_FLAG_INTERLACE (1 << 4) +#define DRM_MODE_FLAG_DBLSCAN (1 << 5) +#define DRM_MODE_FLAG_CSYNC (1 << 6) +#define DRM_MODE_FLAG_PCSYNC (1 << 7) +#define DRM_MODE_FLAG_NCSYNC (1 << 8) +#define DRM_MODE_FLAG_HSKEW (1 << 9) +#define DRM_MODE_FLAG_BCAST (1 << 10) +#define DRM_MODE_FLAG_PIXMUX (1 << 11) +#define DRM_MODE_FLAG_DBLCLK (1 << 12) +#define DRM_MODE_FLAG_CLKDIV2 (1 << 13) +#define DRM_MODE_FLAG_3D_MASK (0x1f << 14) +#define DRM_MODE_FLAG_3D_NONE (0 << 14) +#define DRM_MODE_FLAG_3D_FRAME_PACKING (1 << 14) +#define DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE (2 << 14) +#define DRM_MODE_FLAG_3D_LINE_ALTERNATIVE (3 << 14) +#define DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL (4 << 14) +#define DRM_MODE_FLAG_3D_L_DEPTH (5 << 14) +#define DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH (6 << 14) +#define DRM_MODE_FLAG_3D_TOP_AND_BOTTOM (7 << 14) +#define DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF (8 << 14) + +#define DRM_MODE_TYPE_BUILTIN (1 << 0) +#define DRM_MODE_TYPE_CLOCK_C ((1 << 1) | DRM_MODE_TYPE_BUILTIN) +#define DRM_MODE_TYPE_CRTC_C ((1 << 2) | DRM_MODE_TYPE_BUILTIN) +#define DRM_MODE_TYPE_PREFERRED (1 << 3) +#define DRM_MODE_TYPE_DEFAULT (1 << 4) +#define DRM_MODE_TYPE_USERDEF (1 << 5) +#define DRM_MODE_TYPE_DRIVER (1 << 6) +#define DRM_MODE_TYPE_ALL (DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_USERDEF | DRM_MODE_TYPE_DRIVER) + +// Event types +#define DRM_EVENT_VBLANK 0x01 +#define DRM_EVENT_FLIP_COMPLETE 0x02 +#define DRM_EVENT_CRTC_SEQUENCE 0x03 + +// FourCC formats (subset yang umum digunakan) +#define DRM_FORMAT_XRGB8888 fourcc_code('X', 'R', '2', '4') +#define DRM_FORMAT_ARGB8888 fourcc_code('A', 'R', '2', '4') +#define DRM_FORMAT_RGB888 fourcc_code('R', 'G', '2', '4') +#define DRM_FORMAT_BGR888 fourcc_code('B', 'G', '2', '4') +#define DRM_FORMAT_XBGR8888 fourcc_code('X', 'B', '2', '4') +#define DRM_FORMAT_ABGR8888 fourcc_code('A', 'B', '2', '4') +#define DRM_FORMAT_RGB565 fourcc_code('R', 'G', '1', '6') +#define DRM_FORMAT_BGR565 fourcc_code('B', 'G', '1', '6') + +#define fourcc_code(a, b, c, d) ((u32)(a) | ((u32)(b) << 8) | ((u32)(c) << 16) | ((u32)(d) << 24)) + +namespace drm { + +// Forward declarations +struct drm_device; +struct drm_file; +struct drm_gem_object; + +// DRM Version +struct [[gnu::packed]] drm_version { + int version_major; + int version_minor; + int version_patchlevel; + usize name_len; + char *name; + usize date_len; + char *date; + usize desc_len; + char *desc; +}; + +// DRM Unique +struct [[gnu::packed]] drm_unique { + usize unique_len; + char *unique; +}; + +// DRM Auth +struct [[gnu::packed]] drm_auth { + u32 magic; +}; + +// DRM Map +struct [[gnu::packed]] drm_map { + u64 offset; + u64 size; + u32 type; + u32 flags; + void *handle; + int mtrr; +}; + +// DRM Client +struct [[gnu::packed]] drm_client { + int idx; + int auth; + u32 pid; + u32 uid; + u32 magic; + u64 iocs; +}; + +// DRM Stats +struct [[gnu::packed]] drm_stats { + u32 count; + struct { + u32 value; + char name[15]; + } data[15]; +}; + +// DRM Set Version +struct [[gnu::packed]] drm_set_version { + int drm_di_major; + int drm_di_minor; + int drm_dd_major; + int drm_dd_minor; +}; + +// DRM Modeset Ctl +struct [[gnu::packed]] drm_modeset_ctl { + u32 crtc; + u32 cmd; +}; + +// DRM GEM Close +struct [[gnu::packed]] drm_gem_close { + u32 handle; + u32 pad; +}; + +// DRM GEM Flink +struct [[gnu::packed]] drm_gem_flink { + u32 handle; + u32 name; +}; + +// DRM GEM Open +struct [[gnu::packed]] drm_gem_open { + u32 name; + u32 handle; + u64 size; +}; + +// DRM Get Cap +struct [[gnu::packed]] drm_get_cap { + u64 capability; + u64 value; +}; + +// DRM Set Client Cap +struct [[gnu::packed]] drm_set_client_cap { + u64 capability; + u64 value; +}; + +// DRM Mode Info (mode timings) +struct [[gnu::packed]] drm_mode_modeinfo { + u32 clock; + u16 hdisplay; + u16 hsync_start; + u16 hsync_end; + u16 htotal; + u16 vdisplay; + u16 vsync_start; + u16 vsync_end; + u16 vtotal; + u16 flags; + u16 type; + char name[32]; +}; + +// DRM Mode Card Resources +struct [[gnu::packed]] drm_mode_card_res { + u64 fb_id_ptr; + u64 crtc_id_ptr; + u64 connector_id_ptr; + u64 encoder_id_ptr; + u32 count_fbs; + u32 count_crtcs; + u32 count_connectors; + u32 count_encoders; + u32 min_width; + u32 max_width; + u32 min_height; + u32 max_height; +}; + +// DRM Mode CRTC +struct [[gnu::packed]] drm_mode_crtc { + u64 set_connectors_ptr; + u32 count_connectors; + u32 crtc_id; + u32 fb_id; + u32 x; + u32 y; + u32 gamma_size; + u32 mode_valid; + struct drm_mode_modeinfo mode; +}; + +// DRM Mode Cursor +struct [[gnu::packed]] drm_mode_cursor { + u32 flags; + u32 crtc_id; + i32 x; + i32 y; + u32 width; + u32 height; + u32 handle; +}; + +// DRM Mode Cursor2 +struct [[gnu::packed]] drm_mode_cursor2 { + u32 flags; + u32 crtc_id; + i32 x; + i32 y; + u32 width; + u32 height; + u32 handle; + i32 hot_x; + i32 hot_y; +}; + +// DRM Mode CRTC LUT +struct [[gnu::packed]] drm_mode_crtc_lut { + u32 crtc_id; + u32 gamma_size; + u64 red; + u64 green; + u64 blue; +}; + +// DRM Mode Get Encoder +struct [[gnu::packed]] drm_mode_get_encoder { + u32 encoder_id; + u32 encoder_type; + u32 crtc_id; + u32 possible_crtcs; + u32 possible_clones; +}; + +// DRM Mode Get Connector +struct [[gnu::packed]] drm_mode_get_connector { + u64 encoders_ptr; + u64 modes_ptr; + u64 props_ptr; + u64 prop_values_ptr; + u32 count_modes; + u32 count_props; + u32 count_encoders; + u32 encoder_id; + u32 connector_id; + u32 connection; + u32 mm_width; + u32 mm_height; + u32 subconnector; + u32 pad; +}; + +// DRM Mode Mode Cmd +struct [[gnu::packed]] drm_mode_mode_cmd { + u32 connector_id; + struct drm_mode_modeinfo mode; +}; + +// DRM Mode Get Property +struct [[gnu::packed]] drm_mode_get_property { + u64 values_ptr; + u64 enum_blob_ptr; + u32 prop_id; + u32 flags; + char name[32]; + u32 count_values; + u32 count_enum_blobs; +}; + +// DRM Mode Connector Set Property +struct [[gnu::packed]] drm_mode_connector_set_property { + u64 value; + u32 prop_id; + u32 connector_id; +}; + +// DRM Mode Get Blob +struct [[gnu::packed]] drm_mode_get_blob { + u32 blob_id; + u32 length; + u64 data; +}; + +// DRM Mode FB Cmd +struct [[gnu::packed]] drm_mode_fb_cmd { + u32 fb_id; + u32 width; + u32 height; + u32 pitch; + u32 bpp; + u32 depth; + u32 handle; +}; + +// DRM Mode FB Cmd2 +struct [[gnu::packed]] drm_mode_fb_cmd2 { + u32 fb_id; + u32 width; + u32 height; + u32 pixel_format; + u32 flags; + u32 handles[4]; + u32 pitches[4]; + u32 offsets[4]; + u64 modifier[4]; +}; + +// DRM Mode FB Dirty Cmd +struct [[gnu::packed]] drm_mode_fb_dirty_cmd { + u32 fb_id; + u32 flags; + u32 color; + u32 num_clips; + u64 clips_ptr; +}; + +// DRM Mode CRTC Page Flip +struct [[gnu::packed]] drm_mode_crtc_page_flip { + u32 crtc_id; + u32 fb_id; + u32 flags; + u32 reserved; + u64 user_data; +}; + +// DRM Mode Create Dumb +struct [[gnu::packed]] drm_mode_create_dumb { + u32 height; + u32 width; + u32 bpp; + u32 flags; + u32 handle; + u32 pitch; + u64 size; +}; + +// DRM Mode Map Dumb +struct [[gnu::packed]] drm_mode_map_dumb { + u32 handle; + u32 pad; + u64 offset; +}; + +// DRM Mode Destroy Dumb +struct [[gnu::packed]] drm_mode_destroy_dumb { + u32 handle; +}; + +// DRM Mode Get Plane Resources +struct [[gnu::packed]] drm_mode_get_plane_res { + u64 plane_id_ptr; + u32 count_planes; +}; + +// DRM Mode Get Plane +struct [[gnu::packed]] drm_mode_get_plane { + u32 plane_id; + u32 crtc_id; + u32 fb_id; + u32 possible_crtcs; + u32 gamma_size; + u32 count_format_types; + u64 format_type_ptr; +}; + +// DRM Mode Set Plane +struct [[gnu::packed]] drm_mode_set_plane { + u32 plane_id; + u32 crtc_id; + u32 fb_id; + u32 flags; + i32 crtc_x; + i32 crtc_y; + u32 crtc_w; + u32 crtc_h; + u32 src_x; + u32 src_y; + u32 src_h; + u32 src_w; +}; + +// DRM Mode Obj Get Properties +struct [[gnu::packed]] drm_mode_obj_get_properties { + u64 props_ptr; + u64 prop_values_ptr; + u32 count_props; + u32 obj_id; + u32 obj_type; +}; + +// DRM Mode Obj Set Property +struct [[gnu::packed]] drm_mode_obj_set_property { + u64 value; + u32 prop_id; + u32 obj_id; + u32 obj_type; +}; + +// DRM Mode Atomic +struct [[gnu::packed]] drm_mode_atomic { + u32 flags; + u32 count_objs; + u64 objs_ptr; + u64 count_props_ptr; + u64 props_ptr; + u64 prop_values_ptr; + u64 reserved; + u64 user_data; +}; + +// DRM Event +struct [[gnu::packed]] drm_event { + u32 type; + u32 length; +}; + +// DRM Event VBlank +struct [[gnu::packed]] drm_event_vblank { + struct drm_event base; + u64 user_data; + u32 tv_sec; + u32 tv_usec; + u32 sequence; + u32 crtc_id; +}; + +// DRM Event CRTC Sequence +struct [[gnu::packed]] drm_event_crtc_sequence { + struct drm_event base; + u64 user_data; + u32 time_ns; + u32 sequence; +}; + +// IRQ Bus ID +struct [[gnu::packed]] drm_irq_busid { + u32 irq; + u32 busnum; + u32 devnum; + u32 funcnum; +}; + +} // namespace drm + +#endif // _FISHIX_DRM_H diff --git a/kernel/src/uapi/linux/dma-buf.h b/kernel/src/uapi/linux/dma-buf.h new file mode 100644 index 0000000..7ffb77f --- /dev/null +++ b/kernel/src/uapi/linux/dma-buf.h @@ -0,0 +1,104 @@ +// kernel/src/include/uapi/linux/dma-buf.h +// DMA-BUF API untuk Fishix Wayland support +// DMA-BUF digunakan untuk zero-copy buffer sharing antara GPU dan display + +#pragma once +#include + +#ifndef _FISHIX_DMA_BUF_H +#define _FISHIX_DMA_BUF_H + +#include + +// DMA-BUF IOCTLs +#define DMA_BUF_BASE 'b' +#define DMA_BUF_IOCTL_SYNC _IOW(DMA_BUF_BASE, 0, struct dma_buf_sync) +#define DMA_BUF_IOCTL_SET_NAME _IOW(DMA_BUF_BASE, 1, const char*) + +// DMA-BUF sync flags +#define DMA_BUF_SYNC_READ (1 << 0) +#define DMA_BUF_SYNC_WRITE (2 << 0) +#define DMA_BUF_SYNC_RW (DMA_BUF_SYNC_READ | DMA_BUF_SYNC_WRITE) +#define DMA_BUF_SYNC_START (0 << 2) +#define DMA_BUF_SYNC_END (1 << 2) +#define DMA_BUF_SYNC_VALID_FLAGS_MASK \ + (DMA_BUF_SYNC_READ | DMA_BUF_SYNC_WRITE | DMA_BUF_SYNC_END) + +// DMA-BUF sync structure +struct [[gnu::packed]] dma_buf_sync { + u64 flags; +}; + +// DMA-BUF attachment info +struct dma_buf_attachment { + struct dma_buf *dmabuf; + struct device *dev; + klib::ListHead node; + void *priv; +}; + +// DMA data direction +enum dma_data_direction { + DMA_BIDIRECTIONAL = 0, + DMA_TO_DEVICE = 1, + DMA_FROM_DEVICE = 2, + DMA_NONE = 3, +}; + +// DMA-BUF ops (kernel internal) +struct dma_buf_ops { + int (*attach)(struct dma_buf *, struct dma_buf_attachment *); + void (*detach)(struct dma_buf *, struct dma_buf_attachment *); + struct sg_table *(*map_dma_buf)(struct dma_buf_attachment *, + enum dma_data_direction); + void (*unmap_dma_buf)(struct dma_buf_attachment *, + struct sg_table *, + enum dma_data_direction); + void (*release)(struct dma_buf *); + int (*begin_cpu_access)(struct dma_buf *, enum dma_data_direction); + int (*end_cpu_access)(struct dma_buf *, enum dma_data_direction); + void *(*vmap)(struct dma_buf *); + void (*vunmap)(struct dma_buf *, void *vaddr); + int (*mmap)(struct dma_buf *, struct vm_area_struct *vma); +}; + +// DMA-BUF structure (kernel internal) +struct dma_buf { + u32 size; + u32 file_count; + const struct dma_buf_ops *ops; + klib::ListHead attachments; + void *priv; + const char *name; + u32 id; +}; + +// Scatterlist table (simplified) +struct scatterlist { + paddr_t dma_address; + u32 length; + u32 offset; +}; + +struct sg_table { + struct scatterlist *sgl; + u32 nents; + u32 orig_nents; +}; + +namespace dmabuf { + +// Function prototypes +struct dma_buf* allocate(u32 size, const struct dma_buf_ops *ops, void *priv); +void release(struct dma_buf *buf); +int attach(struct dma_buf *buf, struct dma_buf_attachment *attach); +void detach(struct dma_buf *buf, struct dma_buf_attachment *attach); +int begin_cpu_access(struct dma_buf *buf, enum dma_data_direction dir); +int end_cpu_access(struct dma_buf *buf, enum dma_data_direction dir); +void* vmap(struct dma_buf *buf); +void vunmap(struct dma_buf *buf, void *vaddr); +int sync(struct dma_buf *buf, u64 flags); + +} // namespace dmabuf + +#endif // _FISHIX_DMA_BUF_H diff --git a/kernel/src/uapi/linux/input.h b/kernel/src/uapi/linux/input.h new file mode 100644 index 0000000..295e8f0 --- /dev/null +++ b/kernel/src/uapi/linux/input.h @@ -0,0 +1,286 @@ +// kernel/src/include/uapi/linux/input.h +// Linux Input Event API untuk Fishix Wayland support + +#ifndef _FISHIX_INPUT_H +#define _FISHIX_INPUT_H + +#include + +// Event types +#define EV_SYN 0x00 +#define EV_KEY 0x01 +#define EV_REL 0x02 +#define EV_ABS 0x03 +#define EV_MSC 0x04 +#define EV_SW 0x05 +#define EV_LED 0x11 +#define EV_SND 0x12 +#define EV_REP 0x14 +#define EV_FF 0x15 +#define EV_PWR 0x16 +#define EV_FF_STATUS 0x17 +#define EV_MAX 0x1f +#define EV_CNT (EV_MAX + 1) + +// Synchronization events +#define SYN_REPORT 0 +#define SYN_CONFIG 1 +#define SYN_MT_REPORT 2 +#define SYN_DROPPED 3 + +// Keys and buttons +#define KEY_RESERVED 0 +#define KEY_ESC 1 +#define KEY_1 2 +#define KEY_2 3 +#define KEY_3 4 +#define KEY_4 5 +#define KEY_5 6 +#define KEY_6 7 +#define KEY_7 8 +#define KEY_8 9 +#define KEY_9 10 +#define KEY_0 11 +#define KEY_MINUS 12 +#define KEY_EQUAL 13 +#define KEY_BACKSPACE 14 +#define KEY_TAB 15 +#define KEY_Q 16 +#define KEY_W 17 +#define KEY_E 18 +#define KEY_R 19 +#define KEY_T 20 +#define KEY_Y 21 +#define KEY_U 22 +#define KEY_I 23 +#define KEY_O 24 +#define KEY_P 25 +#define KEY_LEFTBRACE 26 +#define KEY_RIGHTBRACE 27 +#define KEY_ENTER 28 +#define KEY_LEFTCTRL 29 +#define KEY_A 30 +#define KEY_S 31 +#define KEY_D 32 +#define KEY_F 33 +#define KEY_G 34 +#define KEY_H 35 +#define KEY_J 36 +#define KEY_K 37 +#define KEY_L 38 +#define KEY_SEMICOLON 39 +#define KEY_APOSTROPHE 40 +#define KEY_GRAVE 41 +#define KEY_LEFTSHIFT 42 +#define KEY_BACKSLASH 43 +#define KEY_Z 44 +#define KEY_X 45 +#define KEY_C 46 +#define KEY_V 47 +#define KEY_B 48 +#define KEY_N 49 +#define KEY_M 50 +#define KEY_COMMA 51 +#define KEY_DOT 52 +#define KEY_SLASH 53 +#define KEY_RIGHTSHIFT 54 +#define KEY_KPASTERISK 55 +#define KEY_LEFTALT 56 +#define KEY_SPACE 57 +#define KEY_CAPSLOCK 58 +#define KEY_F1 59 +#define KEY_F2 60 +#define KEY_F3 61 +#define KEY_F4 62 +#define KEY_F5 63 +#define KEY_F6 64 +#define KEY_F7 65 +#define KEY_F8 66 +#define KEY_F9 67 +#define KEY_F10 68 +#define KEY_NUMLOCK 69 +#define KEY_SCROLLLOCK 70 +#define KEY_KP7 71 +#define KEY_KP8 72 +#define KEY_KP9 73 +#define KEY_KPMINUS 74 +#define KEY_KP4 75 +#define KEY_KP5 76 +#define KEY_KP6 77 +#define KEY_KPPLUS 78 +#define KEY_KP1 79 +#define KEY_KP2 80 +#define KEY_KP3 81 +#define KEY_KP0 82 +#define KEY_KPDOT 83 +#define KEY_F11 87 +#define KEY_F12 88 + +// Mouse buttons +#define BTN_MOUSE 0x110 +#define BTN_LEFT 0x110 +#define BTN_RIGHT 0x111 +#define BTN_MIDDLE 0x112 +#define BTN_SIDE 0x113 +#define BTN_EXTRA 0x114 +#define BTN_FORWARD 0x115 +#define BTN_BACK 0x116 +#define BTN_TASK 0x117 + +// Relative axes +#define REL_X 0x00 +#define REL_Y 0x01 +#define REL_Z 0x02 +#define REL_RX 0x03 +#define REL_RY 0x04 +#define REL_RZ 0x05 +#define REL_HWHEEL 0x06 +#define REL_DIAL 0x07 +#define REL_WHEEL 0x08 +#define REL_MISC 0x09 +#define REL_MAX 0x0f +#define REL_CNT (REL_MAX + 1) + +// Absolute axes +#define ABS_X 0x00 +#define ABS_Y 0x01 +#define ABS_Z 0x02 +#define ABS_RX 0x03 +#define ABS_RY 0x04 +#define ABS_RZ 0x05 +#define ABS_THROTTLE 0x06 +#define ABS_RUDDER 0x07 +#define ABS_WHEEL 0x08 +#define ABS_GAS 0x09 +#define ABS_BRAKE 0x0a +#define ABS_HAT0X 0x10 +#define ABS_HAT0Y 0x11 +#define ABS_HAT1X 0x12 +#define ABS_HAT1Y 0x13 +#define ABS_HAT2X 0x14 +#define ABS_HAT2Y 0x15 +#define ABS_HAT3X 0x16 +#define ABS_HAT3Y 0x17 +#define ABS_PRESSURE 0x18 +#define ABS_DISTANCE 0x19 +#define ABS_TILT_X 0x1a +#define ABS_TILT_Y 0x1b +#define ABS_TOOL_WIDTH 0x1c +#define ABS_VOLUME 0x20 +#define ABS_MISC 0x28 +#define ABS_MAX 0x3f +#define ABS_CNT (ABS_MAX + 1) + +// Misc events +#define MSC_SERIAL 0x00 +#define MSC_PULSELED 0x01 +#define MSC_GESTURE 0x02 +#define MSC_RAW 0x03 +#define MSC_SCAN 0x04 +#define MSC_TIMESTAMP 0x05 +#define MSC_MAX 0x07 +#define MSC_CNT (MSC_MAX + 1) + +// LEDs +#define LED_NUML 0x00 +#define LED_CAPSL 0x01 +#define LED_SCROLLL 0x02 +#define LED_COMPOSE 0x03 +#define LED_KANA 0x04 +#define LED_MAX 0x0f +#define LED_CNT (LED_MAX + 1) + +// Autorepeat values +#define REP_DELAY 0x00 +#define REP_PERIOD 0x01 +#define REP_MAX 0x01 +#define REP_CNT (REP_MAX + 1) + +// Input ID +struct [[gnu::packed]] input_id { + u16 bustype; + u16 vendor; + u16 product; + u16 version; +}; + +// Input ABS info +struct [[gnu::packed]] input_absinfo { + i32 value; + i32 minimum; + i32 maximum; + i32 fuzz; + i32 flat; + i32 resolution; +}; + +// Input event structure +struct [[gnu::packed]] input_event { + struct { + i64 tv_sec; + i64 tv_usec; + } time; + u16 type; + u16 code; + i32 value; +}; + +// IOCTLs +#define EVIOCGVERSION _IOR('E', 0x01, int) +#define EVIOCGID _IOR('E', 0x02, struct input_id) +#define EVIOCGREP _IOR('E', 0x03, unsigned int[2]) +#define EVIOCSREP _IOW('E', 0x03, unsigned int[2]) +#define EVIOCGKEYCODE _IOR('E', 0x04, unsigned int[2]) +#define EVIOCGKEYCODE_V2 _IOR('E', 0x04, struct input_keymap_entry) +#define EVIOCSKEYCODE _IOW('E', 0x04, unsigned int[2]) +#define EVIOCSKEYCODE_V2 _IOW('E', 0x04, struct input_keymap_entry) + +#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) +#define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) +#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) +#define EVIOCGPROP(len) _IOC(_IOC_READ, 'E', 0x09, len) + +#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) +#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) +#define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) +#define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len) + +#define EVIOCGBIT(ev, len) _IOC(_IOC_READ, 'E', 0x20 + (ev), len) +#define EVIOCGABS(abs) _IOR('E', 0x40 + (abs), struct input_absinfo) +#define EVIOCSABS(abs) _IOW('E', 0xc0 + (abs), struct input_absinfo) + +#define EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect)) +#define EVIOCRMFF _IOW('E', 0x81, int) +#define EVIOCGEFFECTS _IOR('E', 0x84, int) + +#define EVIOCGRAB _IOW('E', 0x90, int) +#define EVIOCREVOKE _IOW('E', 0x91, int) +#define EVIOCGMASK _IOR('E', 0x92, struct input_mask) +#define EVIOCSMASK _IOW('E', 0x93, struct input_mask) +#define EVIOCCKMASK _IOW('E', 0x94, int) + +// Bus types +#define BUS_PCI 0x01 +#define BUS_ISAPNP 0x02 +#define BUS_USB 0x03 +#define BUS_HIL 0x04 +#define BUS_BLUETOOTH 0x05 +#define BUS_VIRTUAL 0x06 +#define BUS_ISA 0x10 +#define BUS_I8042 0x11 +#define BUS_XTKBD 0x12 +#define BUS_RS232 0x13 +#define BUS_GAMEPORT 0x14 +#define BUS_PARPORT 0x15 +#define BUS_AMIGA 0x16 +#define BUS_ADB 0x17 +#define BUS_I2C 0x18 +#define BUS_HOST 0x19 +#define BUS_GSC 0x1A +#define BUS_ATARI 0x1B +#define BUS_SPI 0x1C +#define BUS_RMI 0x1D +#define BUS_CEC 0x1E +#define BUS_INTEL_ISHTP 0x1F + +#endif // _FISHIX_INPUT_H