mirror of
https://github.com/subhobhai943/SUB-OS.git
synced 2026-10-25 16:52:29 +00:00
Add three real platform device drivers (x86 hardware, ARM-stubbed): - drivers/timer/hpet.c + include/drivers/hpet.h: High Precision Event Timer. Maps the HPET block at the standard 0xFED00000, reads the femtosecond period from the capability register, enables the main counter and exposes a monotonic nanosecond time source (hpet_get_ns) far finer than the 100 Hz PIT. - drivers/char/lpt.c + include/drivers/lpt.h: IBM PC parallel port (LPT1) with the Centronics data/strobe handshake over ports 0x378/0x379/0x37A. - drivers/char/nvram.c + include/drivers/nvram.h: MC146818 CMOS NVRAM read/write over 0x70/0x71, preserving the NMI-disable bit, with checksum and hex dump. Wired all three into the [5/14] device-enumeration boot step and added LazyBox applets `hpet`, `lpt`, and `nvram`. Verified live under QEMU (screenshotted): HPET reports 100 MHz / 3 comparators / 10 ns period and its counter advances ~1.4 s of real time between two `hpet` runs; NVRAM dumps 128 bytes with a computed checksum; LPT1 detected at 0x378. Clean build on x86_64/aarch64/armv8i; 0 panics / 0 OOM. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX
81 lines
2.5 KiB
C
81 lines
2.5 KiB
C
// IBM PC parallel port (LPT1) printer driver for SUB-OS.
|
|
//
|
|
// Implements the classic Centronics handshake: place a byte on the data lines,
|
|
// wait for the peripheral to be ready (nBUSY high), then pulse the STROBE line.
|
|
|
|
#include <drivers/lpt.h>
|
|
#include <kernel/printk.h>
|
|
|
|
#if defined(__x86_64__)
|
|
#include <arch/x86_64/io.h>
|
|
|
|
#define LPT1_DATA 0x378
|
|
#define LPT1_STATUS 0x379 // bit7 nBUSY (1 = ready), bit6 nACK, bit5 PAPER, bit4 SELECT
|
|
#define LPT1_CONTROL 0x37A // bit0 STROBE, bit1 AUTOLF, bit2 nINIT, bit3 SELECT
|
|
|
|
#define LPT_STATUS_BUSY 0x80
|
|
#define LPT_CTRL_STROBE 0x01
|
|
#define LPT_CTRL_INIT 0x04
|
|
#define LPT_CTRL_SELECT 0x08
|
|
|
|
static bool g_present = false;
|
|
static uint64_t g_bytes_written = 0;
|
|
|
|
void lpt_init(void) {
|
|
uint8_t status = inb(LPT1_STATUS);
|
|
// A floating (unimplemented) port typically reads back all-ones.
|
|
if (status == 0xFF) {
|
|
g_present = false;
|
|
printk(KERN_INFO "LPT: no parallel port at 0x%03X\n", LPT1_DATA);
|
|
return;
|
|
}
|
|
// Bring the port out of reset and select the printer.
|
|
outb(LPT1_CONTROL, LPT_CTRL_INIT | LPT_CTRL_SELECT);
|
|
g_present = true;
|
|
printk(ANSI_BRIGHT_GREEN "LPT: " ANSI_RESET
|
|
"Parallel port LPT1 online at 0x%03X (status 0x%02X)\n", LPT1_DATA, status);
|
|
}
|
|
|
|
bool lpt_present(void) { return g_present; }
|
|
uint8_t lpt_status(void) { return g_present ? inb(LPT1_STATUS) : 0xFF; }
|
|
|
|
int lpt_putc(char c) {
|
|
if (!g_present) return -1;
|
|
|
|
// Wait (bounded) for the peripheral to raise nBUSY.
|
|
int spins = 100000;
|
|
while (spins-- > 0 && !(inb(LPT1_STATUS) & LPT_STATUS_BUSY)) {
|
|
/* busy-wait */
|
|
}
|
|
|
|
outb(LPT1_DATA, (uint8_t)c);
|
|
|
|
// Pulse STROBE low->high to latch the byte.
|
|
uint8_t ctrl = inb(LPT1_CONTROL);
|
|
outb(LPT1_CONTROL, ctrl | LPT_CTRL_STROBE);
|
|
outb(LPT1_CONTROL, ctrl & ~LPT_CTRL_STROBE);
|
|
|
|
g_bytes_written++;
|
|
return 0;
|
|
}
|
|
|
|
int lpt_write(const char* buf, size_t len) {
|
|
if (!g_present || !buf) return -1;
|
|
int n = 0;
|
|
for (size_t i = 0; i < len; i++) {
|
|
if (lpt_putc(buf[i]) != 0) break;
|
|
n++;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
#else // Parallel port is an x86 platform device.
|
|
|
|
void lpt_init(void) { }
|
|
bool lpt_present(void) { return false; }
|
|
int lpt_putc(char c) { (void)c; return -1; }
|
|
int lpt_write(const char* buf, size_t len) { (void)buf; (void)len; return -1; }
|
|
uint8_t lpt_status(void) { return 0xFF; }
|
|
|
|
#endif
|