Compare commits
5 Commits
dc35c42371
...
2198dedb96
Author | SHA1 | Date | |
---|---|---|---|
2198dedb96 | |||
cd9219df52 | |||
e8f3dd4cf9 | |||
6c26236167 | |||
b17793134e |
@ -44,3 +44,4 @@ luna_app(gol.cpp gol)
|
||||
luna_app(buffer-test.cpp buffer-test)
|
||||
luna_app(socket-test.cpp socket-test)
|
||||
luna_app(socket-client.cpp socket-client)
|
||||
luna_app(mouse.cpp mouse)
|
||||
|
16
apps/mouse.cpp
Normal file
16
apps/mouse.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
#include <moon/Mouse.h>
|
||||
#include <os/File.h>
|
||||
|
||||
Result<int> luna_main(int, char**)
|
||||
{
|
||||
auto mouse = TRY(os::File::open("/dev/mouse", os::File::ReadOnly));
|
||||
mouse->set_buffer(os::File::NotBuffered);
|
||||
|
||||
while (1)
|
||||
{
|
||||
moon::MousePacket packet;
|
||||
TRY(mouse->read_typed(packet));
|
||||
|
||||
os::println("Mouse packet: xdelta=%d, ydelta=%d, buttons=%d", packet.xdelta, packet.ydelta, packet.buttons);
|
||||
}
|
||||
}
|
@ -59,6 +59,7 @@ set(SOURCES
|
||||
src/fs/devices/ConsoleDevice.cpp
|
||||
src/fs/devices/FramebufferDevice.cpp
|
||||
src/fs/devices/UARTDevice.cpp
|
||||
src/fs/devices/MouseDevice.cpp
|
||||
src/fs/InitRD.cpp
|
||||
src/binfmt/ELF.cpp
|
||||
src/binfmt/BinaryFormat.cpp
|
||||
@ -80,6 +81,7 @@ if("${LUNA_ARCH}" MATCHES "x86_64")
|
||||
src/arch/x86_64/init/GDT.cpp
|
||||
src/arch/x86_64/init/IDT.cpp
|
||||
src/arch/x86_64/init/PIC.cpp
|
||||
src/arch/x86_64/PS2Mouse.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
|
22
kernel/src/api/Mouse.h
Normal file
22
kernel/src/api/Mouse.h
Normal file
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
#include <luna/Types.h>
|
||||
|
||||
namespace moon
|
||||
{
|
||||
enum MouseButton
|
||||
{
|
||||
Left = (1 << 0),
|
||||
Middle = (1 << 1),
|
||||
Right = (1 << 2),
|
||||
};
|
||||
|
||||
struct [[gnu::packed]] MousePacket
|
||||
{
|
||||
i16 xdelta;
|
||||
i16 ydelta;
|
||||
u8 buttons;
|
||||
u8 _padding[3];
|
||||
};
|
||||
|
||||
static_assert(sizeof(MousePacket) == 8);
|
||||
}
|
@ -1,10 +1,12 @@
|
||||
#include "arch/CPU.h"
|
||||
#include "Log.h"
|
||||
#include "api/Mouse.h"
|
||||
#include "arch/Keyboard.h"
|
||||
#include "arch/Timer.h"
|
||||
#include "arch/x86_64/CPU.h"
|
||||
#include "arch/x86_64/IO.h"
|
||||
#include "fs/devices/ConsoleDevice.h"
|
||||
#include "fs/devices/MouseDevice.h"
|
||||
#include "memory/MemoryManager.h"
|
||||
#include "sys/Syscall.h"
|
||||
#include "thread/Scheduler.h"
|
||||
@ -27,8 +29,9 @@ extern void change_pic_masks(u8 pic1_mask, u8 pic2_mask);
|
||||
extern void pic_eoi(unsigned char irq);
|
||||
extern void pic_eoi(Registers* regs);
|
||||
extern void setup_idt();
|
||||
extern void init_mouse();
|
||||
|
||||
static Thread* g_io_thread;
|
||||
Thread* g_io_thread;
|
||||
|
||||
typedef void (*interrupt_handler_t)(Registers*, void*);
|
||||
|
||||
@ -139,15 +142,19 @@ extern "C" void handle_x86_exception(Registers* regs)
|
||||
}
|
||||
|
||||
CircularQueue<u8, 60> scancode_queue;
|
||||
CircularQueue<moon::MousePacket, 20> mouse_queue;
|
||||
|
||||
void io_thread()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
u8 scancode;
|
||||
while (!scancode_queue.try_pop(scancode)) kernel_wait_for_event();
|
||||
moon::MousePacket packet;
|
||||
|
||||
ConsoleDevice::did_press_or_release_key(scancode);
|
||||
if (scancode_queue.try_pop(scancode)) { ConsoleDevice::did_press_or_release_key(scancode); }
|
||||
else if (mouse_queue.try_pop(packet)) { MouseDevice::add_mouse_event(packet); }
|
||||
else
|
||||
kernel_wait_for_event();
|
||||
}
|
||||
}
|
||||
|
||||
@ -261,6 +268,8 @@ namespace CPU
|
||||
|
||||
remap_pic();
|
||||
|
||||
init_mouse();
|
||||
|
||||
sync_interrupts();
|
||||
}
|
||||
|
||||
|
118
kernel/src/arch/x86_64/PS2Mouse.cpp
Normal file
118
kernel/src/arch/x86_64/PS2Mouse.cpp
Normal file
@ -0,0 +1,118 @@
|
||||
#include "Log.h"
|
||||
#include "api/Mouse.h"
|
||||
#include "arch/CPU.h"
|
||||
#include "arch/x86_64/IO.h"
|
||||
#include "fs/devices/MouseDevice.h"
|
||||
#include "thread/Thread.h"
|
||||
|
||||
extern Thread* g_io_thread;
|
||||
|
||||
static u8 g_mouse_packet[3];
|
||||
static int g_index = 0;
|
||||
|
||||
#define PS2_MOUSE_Y_OVERFLOW 0x80
|
||||
#define PS2_MOUSE_X_OVERFLOW 0x40
|
||||
#define PS2_MOUSE_Y_SIGN 0x20
|
||||
#define PS2_MOUSE_X_SIGN 0x10
|
||||
#define PS2_MOUSE_ALWAYS_1 0x08
|
||||
#define PS2_MOUSE_MIDDLE_BTN 0x04
|
||||
#define PS2_MOUSE_RIGHT_BTN 0x02
|
||||
#define PS2_MOUSE_LEFT_BTN 0x01
|
||||
|
||||
extern CircularQueue<moon::MousePacket, 20> mouse_queue;
|
||||
|
||||
static void process_mouse_event(u8 data)
|
||||
{
|
||||
if (g_index == 0)
|
||||
{
|
||||
// NOTE: https://wiki.osdev.org/Mouse_Input#PS2_Mouse says to discard the packet if X or Y overflow is 1, but
|
||||
// https://wiki.osdev.org/PS2_Mouse uses it. Discard for now.
|
||||
if (data & PS2_MOUSE_X_OVERFLOW) return;
|
||||
if (data & PS2_MOUSE_Y_OVERFLOW) return;
|
||||
|
||||
if ((data & PS2_MOUSE_ALWAYS_1) == 0) return;
|
||||
}
|
||||
|
||||
g_mouse_packet[g_index++] = data;
|
||||
if (g_index < 3) return;
|
||||
g_index = 0;
|
||||
|
||||
moon::MousePacket packet;
|
||||
packet.xdelta = g_mouse_packet[1];
|
||||
packet.ydelta = g_mouse_packet[2];
|
||||
packet.buttons = 0;
|
||||
|
||||
u8 flags = g_mouse_packet[0];
|
||||
if (flags & PS2_MOUSE_X_SIGN) packet.xdelta = -packet.xdelta;
|
||||
if (flags & PS2_MOUSE_Y_SIGN) packet.ydelta = -packet.ydelta;
|
||||
|
||||
if (flags & PS2_MOUSE_MIDDLE_BTN) packet.buttons |= moon::MouseButton::Middle;
|
||||
if (flags & PS2_MOUSE_RIGHT_BTN) packet.buttons |= moon::MouseButton::Right;
|
||||
if (flags & PS2_MOUSE_LEFT_BTN) packet.buttons |= moon::MouseButton::Left;
|
||||
|
||||
MouseDevice::add_mouse_event(packet);
|
||||
}
|
||||
|
||||
static void mouse_interrupt(Registers*, void*)
|
||||
{
|
||||
const u8 data = IO::inb(0x60);
|
||||
process_mouse_event(data);
|
||||
}
|
||||
|
||||
#define PS2_MOUSE_TIMEOUT 100000
|
||||
|
||||
static void mouse_wait()
|
||||
{
|
||||
int timeout = PS2_MOUSE_TIMEOUT;
|
||||
while (--timeout)
|
||||
{
|
||||
if ((IO::inb(0x64) & 0b10) == 0) return;
|
||||
CPU::pause();
|
||||
}
|
||||
}
|
||||
|
||||
static void mouse_wait_for_input()
|
||||
{
|
||||
int timeout = PS2_MOUSE_TIMEOUT;
|
||||
while (--timeout)
|
||||
{
|
||||
if (IO::inb(0x64) & 0b1) return;
|
||||
CPU::pause();
|
||||
}
|
||||
}
|
||||
|
||||
static void mouse_write_data(u8 byte)
|
||||
{
|
||||
mouse_wait();
|
||||
IO::outb(0x64, 0xD4);
|
||||
mouse_wait();
|
||||
IO::outb(0x60, byte);
|
||||
}
|
||||
|
||||
void init_mouse()
|
||||
{
|
||||
CPU::register_interrupt(12, mouse_interrupt, nullptr);
|
||||
|
||||
IO::outb(0x64, 0xA8); // Enable PS/2 auxiliary port
|
||||
|
||||
mouse_wait();
|
||||
IO::outb(0x64, 0x20); // Get Compaq status byte
|
||||
mouse_wait_for_input();
|
||||
u8 status = IO::inb(0x60);
|
||||
status |= 0x02; // Enable IRQ12
|
||||
status &= ~0x20; // Disable Mouse Clock
|
||||
mouse_wait();
|
||||
IO::outb(0x64, 0x60); // Set Compaq status byte
|
||||
mouse_wait();
|
||||
IO::outb(0x60, status);
|
||||
|
||||
mouse_write_data(0xF6); // Reset defaults
|
||||
mouse_wait();
|
||||
IO::inb(0x60);
|
||||
|
||||
mouse_write_data(0xF4); // Send automatic packets when the mouse moves or is clicked
|
||||
mouse_wait();
|
||||
IO::inb(0x60);
|
||||
|
||||
g_index = 0;
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
#include "fs/devices/ConsoleDevice.h"
|
||||
#include "fs/devices/FramebufferDevice.h"
|
||||
#include "fs/devices/FullDevice.h"
|
||||
#include "fs/devices/MouseDevice.h"
|
||||
#include "fs/devices/NullDevice.h"
|
||||
#include "fs/devices/UARTDevice.h"
|
||||
#include "fs/devices/ZeroDevice.h"
|
||||
@ -70,6 +71,7 @@ namespace DeviceRegistry
|
||||
ConsoleDevice::create();
|
||||
FramebufferDevice::create();
|
||||
UARTDevice::create();
|
||||
MouseDevice::create();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ namespace DeviceRegistry
|
||||
Disk = 4,
|
||||
DiskPartition = 5,
|
||||
Serial = 6,
|
||||
Input = 7,
|
||||
};
|
||||
|
||||
Result<SharedPtr<Device>> fetch_special_device(u32 major, u32 minor);
|
||||
|
50
kernel/src/fs/devices/MouseDevice.cpp
Normal file
50
kernel/src/fs/devices/MouseDevice.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
#include "fs/devices/MouseDevice.h"
|
||||
|
||||
SharedPtr<MouseDevice> MouseDevice::s_mouse_device = {};
|
||||
|
||||
Result<void> MouseDevice::create()
|
||||
{
|
||||
auto device = TRY(make_shared<MouseDevice>());
|
||||
s_mouse_device = device;
|
||||
return DeviceRegistry::register_special_device(DeviceRegistry::Input, 0, device);
|
||||
}
|
||||
|
||||
Result<usize> MouseDevice::read(u8* buf, usize, usize length) const
|
||||
{
|
||||
usize nread = 0;
|
||||
while (length >= sizeof(moon::MousePacket))
|
||||
{
|
||||
if (!m_packet_queue.try_pop(*(moon::MousePacket*)buf)) break;
|
||||
|
||||
buf += sizeof(moon::MousePacket);
|
||||
length -= sizeof(moon::MousePacket);
|
||||
nread += sizeof(moon::MousePacket);
|
||||
}
|
||||
|
||||
return nread;
|
||||
}
|
||||
|
||||
Result<usize> MouseDevice::write(const u8* buf, usize, usize length)
|
||||
{
|
||||
usize nwritten = 0;
|
||||
while (length >= sizeof(moon::MousePacket))
|
||||
{
|
||||
if (!m_packet_queue.try_push(*(const moon::MousePacket*)buf)) break;
|
||||
|
||||
buf += sizeof(moon::MousePacket);
|
||||
length -= sizeof(moon::MousePacket);
|
||||
nwritten += sizeof(moon::MousePacket);
|
||||
}
|
||||
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
void MouseDevice::add_mouse_event(const moon::MousePacket& packet)
|
||||
{
|
||||
if (s_mouse_device) s_mouse_device->m_packet_queue.try_push(packet);
|
||||
}
|
||||
|
||||
bool MouseDevice::will_block_if_read() const
|
||||
{
|
||||
return m_packet_queue.is_empty();
|
||||
}
|
31
kernel/src/fs/devices/MouseDevice.h
Normal file
31
kernel/src/fs/devices/MouseDevice.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
#include "api/Mouse.h"
|
||||
#include "fs/devices/DeviceRegistry.h"
|
||||
#include <luna/CircularQueue.h>
|
||||
|
||||
class MouseDevice : public Device
|
||||
{
|
||||
public:
|
||||
// Initializer for DeviceRegistry.
|
||||
static Result<void> create();
|
||||
|
||||
Result<usize> read(u8*, usize, usize) const override;
|
||||
|
||||
Result<usize> write(const u8*, usize, usize) override;
|
||||
|
||||
static void add_mouse_event(const moon::MousePacket& packet);
|
||||
|
||||
bool will_block_if_read() const override;
|
||||
|
||||
StringView device_path() const override
|
||||
{
|
||||
return "mouse";
|
||||
}
|
||||
|
||||
virtual ~MouseDevice() = default;
|
||||
|
||||
private:
|
||||
mutable CircularQueue<moon::MousePacket, 200> m_packet_queue;
|
||||
|
||||
static SharedPtr<MouseDevice> s_mouse_device;
|
||||
};
|
@ -16,6 +16,11 @@ template <typename T, usize Size> class CircularQueue
|
||||
{
|
||||
}
|
||||
|
||||
bool is_empty()
|
||||
{
|
||||
return m_tail.load() == m_head.load();
|
||||
}
|
||||
|
||||
bool try_push(const T& value)
|
||||
{
|
||||
usize current_tail = m_tail.load(MemoryOrder::Relaxed);
|
||||
@ -71,6 +76,11 @@ template <typename T> class DynamicCircularQueue
|
||||
if (m_data) free_impl(m_data);
|
||||
}
|
||||
|
||||
bool is_empty()
|
||||
{
|
||||
return m_tail.load() == m_head.load();
|
||||
}
|
||||
|
||||
Result<void> set_size(usize size)
|
||||
{
|
||||
m_data = (T*)TRY(calloc_impl(size + 1, sizeof(T), false));
|
||||
|
@ -143,6 +143,19 @@ namespace os
|
||||
*/
|
||||
Result<void> read(Buffer& buf, usize size);
|
||||
|
||||
/**
|
||||
* @brief Read an object from this File.
|
||||
*
|
||||
* @tparam T The type of the object to read.
|
||||
* @param object A reference to the object in question.
|
||||
* @return Result<void> Whether the operation succeeded.
|
||||
*/
|
||||
template <typename T> Result<void> read_typed(T& object)
|
||||
{
|
||||
TRY(raw_read((u8*)&object, sizeof(T)));
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read the entire File's contents.
|
||||
*
|
||||
@ -178,6 +191,20 @@ namespace os
|
||||
*/
|
||||
void rewind();
|
||||
|
||||
enum BufferingMode
|
||||
{
|
||||
NotBuffered = _IONBF,
|
||||
LineBuffered = _IOLBF,
|
||||
FullyBuffered = _IOFBF,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Change the buffering mode of this File.
|
||||
*
|
||||
* @param mode The buffering mode.
|
||||
*/
|
||||
void set_buffer(BufferingMode mode);
|
||||
|
||||
File(Badge<File>);
|
||||
~File();
|
||||
|
||||
|
@ -226,6 +226,11 @@ namespace os
|
||||
fflush(m_file);
|
||||
}
|
||||
|
||||
void File::set_buffer(BufferingMode mode)
|
||||
{
|
||||
setvbuf(m_file, NULL, mode, 0);
|
||||
}
|
||||
|
||||
// FIXME: Do not allocate memory for printing.
|
||||
Result<void> print_impl(SharedPtr<File> f, StringView fmt, va_list ap)
|
||||
{
|
||||
|
@ -9,7 +9,9 @@ mkdir -p $LUNA_BASE
|
||||
mkdir -p $LUNA_BASE/usr/include
|
||||
mkdir -p $LUNA_BASE/usr/include/luna
|
||||
mkdir -p $LUNA_BASE/usr/include/os
|
||||
mkdir -p $LUNA_BASE/usr/include/moon
|
||||
|
||||
cp --preserve=timestamps -RT libc/include/ $LUNA_BASE/usr/include
|
||||
cp --preserve=timestamps -RT libluna/include/luna/ $LUNA_BASE/usr/include/luna
|
||||
cp --preserve=timestamps -RT libos/include/os/ $LUNA_BASE/usr/include/os
|
||||
cp --preserve=timestamps -RT kernel/src/api/ $LUNA_BASE/usr/include/moon
|
||||
|
Loading…
Reference in New Issue
Block a user