diff --git a/kernel-src/arch/x86-64/main.c b/kernel-src/arch/x86-64/main.c index b39065b0..10d7f6ed 100644 --- a/kernel-src/arch/x86-64/main.c +++ b/kernel-src/arch/x86-64/main.c @@ -80,6 +80,8 @@ void kernel_entry() { sockfs_init(); ext2_init(); + acpi_initdevice(); + tty_init(); pty_init(); diff --git a/kernel-src/include/kernel/acpi.h b/kernel-src/include/kernel/acpi.h index 892454ef..d90f5047 100644 --- a/kernel-src/include/kernel/acpi.h +++ b/kernel-src/include/kernel/acpi.h @@ -10,4 +10,9 @@ void acpi_init(void); int acpi_poweroff(void); int acpi_reboot(void); -#endif \ No newline at end of file +void acpi_signaldevice(char c); + +// Depends on devfs +void acpi_initdevice(void); + +#endif diff --git a/kernel-src/include/kernel/devfs.h b/kernel-src/include/kernel/devfs.h index 14988a47..90180d83 100644 --- a/kernel-src/include/kernel/devfs.h +++ b/kernel-src/include/kernel/devfs.h @@ -18,6 +18,7 @@ #define DEV_MAJOR_NET 10 #define DEV_MAJOR_MOUSE 11 #define DEV_MAJOR_PTY 12 +#define DEV_MAJOR_ACPI 13 typedef struct { int (*open)(int minor, vnode_t **vnode, int flags); diff --git a/kernel-src/io/acpi/acpi.c b/kernel-src/io/acpi/acpi.c index ec3e6530..13ebd8a3 100644 --- a/kernel-src/io/acpi/acpi.c +++ b/kernel-src/io/acpi/acpi.c @@ -22,7 +22,7 @@ void acpi_early_init(void) { void acpi_dopoweroff(uacpi_handle ctx) { (void)ctx; - acpi_poweroff(); + acpi_signaldevice('p'); } static uacpi_interrupt_ret handle_pwrbtn(uacpi_handle ctx) { diff --git a/kernel-src/io/acpi/dev.c b/kernel-src/io/acpi/dev.c new file mode 100644 index 00000000..02957c3e --- /dev/null +++ b/kernel-src/io/acpi/dev.c @@ -0,0 +1,119 @@ +#include +#include +#include +#include +#include +#include + +static ringbuffer_t ringbuffer; +static pollheader_t pollheader; +static spinlock_t lock; + +void acpi_signaldevice(char c) { + long ipl = spinlock_acquireraiseipl(&lock, IPL_DPC); + + if (ringbuffer_write(&ringbuffer, &c, 1)) + poll_event(&pollheader, POLLIN); + + spinlock_releaseloweripl(&lock, ipl); +} + +static int internalpoll(polldata_t *data, int events) { + int revents = 0; + if (events & POLLOUT) + revents |= POLLOUT; + + if ((events & POLLIN) && RINGBUFFER_DATACOUNT(&ringbuffer)) + revents |= POLLIN; + + if (revents == 0) + poll_add(&pollheader, data, events); + + return revents; +} + +static int read(int minor, void *buffer, size_t size, uintmax_t offset, int flags, size_t *readc) { + *readc = 0; + + if (size < 1) + return 0; + + polldesc_t desc; + int error = poll_initdesc(&desc, 1); + if (error) + return error; + + for (;;) { + long ipl = spinlock_acquireraiseipl(&lock, IPL_DPC); + + int revents = internalpoll(&desc.data[0], POLLIN); + + spinlock_releaseloweripl(&lock, ipl); + + if (revents) + break; + + if (flags & V_FFLAGS_NONBLOCKING) { + error = EAGAIN; + goto leave; + } + + error = poll_dowait(&desc, 0); + + if (error) + goto leave; + + poll_leave(&desc); + } + + long ipl = spinlock_acquireraiseipl(&lock, IPL_DPC); + + *readc = ringbuffer_read(&ringbuffer, buffer, size); + + spinlock_releaseloweripl(&lock, ipl); + + leave: + poll_leave(&desc); + poll_destroydesc(&desc); + return error; +} + +static int write(int minor, void *buffer, size_t size, uintmax_t offset, int flags, size_t *writec) { + if (size < 1) { + *writec = 0; + return 0; + } + + char *c = buffer; + switch (*c) { + case 'p': + acpi_poweroff(); + break; + case 'r': + acpi_reboot(); + break; + } + + return EIO; +} + +static int poll(int minor, polldata_t *data, int events) { + long ipl = spinlock_acquireraiseipl(&lock, IPL_DPC); + + int revents = internalpoll(data, events); + + spinlock_releaseloweripl(&lock, ipl); + return revents; +} + +static devops_t acpiops = { + .read = read, + .write = write, + .poll = poll +}; + +void acpi_initdevice(void) { + __assert(devfs_register(&acpiops, "acpi", V_TYPE_CHDEV, DEV_MAJOR_ACPI, 0, 0600, NULL) == 0); + __assert(ringbuffer_init(&ringbuffer, 64) == 0); + POLL_INITHEADER(&pollheader); +}