2 Commits

Author SHA1 Message Date
bcd09a898c Add parallel port handling in parallel.c
Implement parallel port support with detection and configuration.
Add LPT port handling in parallel.c
Implement LPT port detection and configuration functions.
2026-02-04 20:53:22 +01:00
5cf2549d58 Add parallel.h header for LPT device management
This creates the header file for a parallel port driver
2026-02-02 13:18:31 -08:00
4 changed files with 201 additions and 48 deletions

130
kernel/parallel.c Normal file
View File

@@ -0,0 +1,130 @@
#include "parallel.h"
#include "io.h"
#include "irq.h"
#include "serial.h" // or your print/terminal for debug
// Standard PC LPT base addresses
static const uint16_t lpt_base_addrs[LPT_MAX_PORTS] = {
0x378, // LPT1
0x278 // LPT2
};
lpt_device_t lpt_devices[LPT_MAX_PORTS];
// Register offsets
#define LPT_DATA(base) (base + 0)
#define LPT_STATUS(base) (base + 1)
#define LPT_CONTROL(base) (base + 2)
// STATUS bits
// bit 7: Busy (inverted), 6: Ack, 5: Paper Out, 4: Select, 3: Error
// CONTROL bits
// bit 0: Strobe, 1: Auto Linefeed, 2: Init, 3: Select In, 5: Bidirectional (PS/2)
// Simple presence check: write/read control & status
static bool lpt_detect(uint16_t base) {
uint8_t orig_ctrl = inb(LPT_CONTROL(base));
outb(LPT_CONTROL(base), orig_ctrl ^ 0x0F);
uint8_t new_ctrl = inb(LPT_CONTROL(base));
outb(LPT_CONTROL(base), orig_ctrl);
// If bits changed as expected, port likely exists
if (((orig_ctrl ^ new_ctrl) & 0x0F) == 0x0F) {
return true;
}
return false;
}
static void lpt_configure_bidir(uint16_t base, bool enable) {
uint8_t ctrl = inb(LPT_CONTROL(base));
if (enable) {
ctrl |= (1 << 5); // Set bidirectional bit (PS/2)
} else {
ctrl &= ~(1 << 5);
}
outb(LPT_CONTROL(base), ctrl);
}
void lpt_set_mode(lpt_port_t port, lpt_mode_t mode) {
if (port < 0 || port >= LPT_MAX_PORTS) return;
if (!lpt_devices[port].present) return;
uint16_t base = lpt_devices[port].base;
switch (mode) {
case LPT_MODE_COMPAT:
lpt_configure_bidir(base, false);
break;
case LPT_MODE_BIDIR:
lpt_configure_bidir(base, true);
break;
case LPT_MODE_EPP:
// TODO: EPP requires chipset support & config
// For now, just enable bidir as a baseline
lpt_configure_bidir(base, true);
break;
case LPT_MODE_ECP:
// TODO: ECP requires FIFO, DMA, and ECR register
// Stub for future implementation
lpt_configure_bidir(base, true);
break;
}
lpt_devices[port].mode = mode;
}
void lpt_write_byte(lpt_port_t port, uint8_t value) {
if (port < 0 || port >= LPT_MAX_PORTS) return;
if (!lpt_devices[port].present) return;
uint16_t base = lpt_devices[port].base;
// Wait until not busy (bit 7 is inverted busy)
while (!(inb(LPT_STATUS(base)) & 0x80))
;
outb(LPT_DATA(base), value);
// Pulse strobe
uint8_t ctrl = inb(LPT_CONTROL(base));
outb(LPT_CONTROL(base), ctrl | 0x01);
outb(LPT_CONTROL(base), ctrl & ~0x01);
}
uint8_t lpt_read_byte(lpt_port_t port) {
if (port < 0 || port >= LPT_MAX_PORTS) return 0xFF;
if (!lpt_devices[port].present) return 0xFF;
uint16_t base = lpt_devices[port].base;
// In bidirectional mode, data register is input
return inb(LPT_DATA(base));
}
// IRQ hook: you wire this into your IRQ handler for the LPT IRQ (usually 7 or 5)
void lpt_irq_handler(lpt_port_t port) {
// For now, just a stub. Later:
// - read status
// - acknowledge interrupt
// - wake waiting writer/reader
(void)port;
}
// Initialize all LPT ports
void lpt_init_all(void) {
for (int i = 0; i < LPT_MAX_PORTS; i++) {
lpt_devices[i].base = lpt_base_addrs[i];
lpt_devices[i].present = lpt_detect(lpt_devices[i].base);
lpt_devices[i].mode = LPT_MODE_COMPAT;
lpt_devices[i].irq = 0; // You can fill this if you parse BIOS/PCI/ACPI
if (lpt_devices[i].present) {
serial_write("LPT detected at base 0x");
// use your print_hex here if you want
}
}
// If you want interrupt-driven I/O:
// - Map LPT IRQ (usually 7 for LPT1, 5 for LPT2) in your PIC/IRQ layer
// - In your IRQ handler, call lpt_irq_handler(port)
}

40
kernel/parallel.h Normal file
View File

@@ -0,0 +1,40 @@
#ifndef PARALLEL_H
#define PARALLEL_H
#include <stdint.h>
#include <stdbool.h>
typedef enum {
LPT_PORT_NONE = -1,
LPT1_PORT = 0,
LPT2_PORT = 1,
LPT_MAX_PORTS = 2
} lpt_port_t;
typedef enum {
LPT_MODE_COMPAT = 0, // Standard (SPP)
LPT_MODE_BIDIR, // PS/2 bidirectional
LPT_MODE_EPP, // IEEE 1284 EPP
LPT_MODE_ECP // IEEE 1284 ECP
} lpt_mode_t;
typedef struct {
uint16_t base; // Base I/O address (e.g., 0x378, 0x278)
bool present; // Detected
lpt_mode_t mode; // Current mode
uint8_t irq; // IRQ line (if known/used)
} lpt_device_t;
extern lpt_device_t lpt_devices[LPT_MAX_PORTS];
void lpt_init_all(void);
void lpt_set_mode(lpt_port_t port, lpt_mode_t mode);
// Simple polled I/O
void lpt_write_byte(lpt_port_t port, uint8_t value);
uint8_t lpt_read_byte(lpt_port_t port);
// IRQ-driven hook (you implement the handler logic)
void lpt_irq_handler(lpt_port_t port);
#endif

View File

@@ -3,13 +3,12 @@
#include <stddef.h>
extern int memcmp(const void *s1, const void *s2, size_t n);
extern void *memmove(void *dst, const void *src, size_t n);
extern void *memcpy(void *dst, const void *src, size_t n);
extern void *memset(void *dst, int c, size_t n);
extern int memcmp(const void* s1, const void* s2, size_t n);
extern void* memmove(void* dst, const void* src, size_t n);
extern void* memcpy(void* dst, const void* src, size_t n);
extern void* memset(void* dst, int c, size_t n);
extern size_t strlen(const char *s);
extern int strcmp(const char *s1, const char *s2);
extern char *strncpy(char *dst, const char *src, size_t n);
extern size_t strlen(const char* s);
extern int strcmp(const char* s1, const char* s2);
#endif // CLASSICOS_KLIBC_STRING_H

View File

@@ -1,8 +1,8 @@
#include <string.h>
int memcmp(const void *s1, const void *s2, size_t n) {
const unsigned char *c1 = s1;
const unsigned char *c2 = s2;
int memcmp(const void* s1, const void* s2, size_t n) {
const unsigned char* c1 = s1;
const unsigned char* c2 = s2;
int d = 0;
while (n--) {
@@ -13,9 +13,9 @@ int memcmp(const void *s1, const void *s2, size_t n) {
return d;
}
void *memmove(void *dst, const void *src, size_t n) {
const char *p = src;
char *q = dst;
void* memmove(void* dst, const void* src, size_t n) {
const char* p = src;
char* q = dst;
#if defined(__i386__) || defined(__x86_64__)
if (q < p) {
__asm__ volatile("cld; rep; movsb" : "+c"(n), "+S"(p), "+D"(q));
@@ -41,19 +41,19 @@ void *memmove(void *dst, const void *src, size_t n) {
return dst;
}
void *memcpy(void *dst, const void *src, size_t n) {
const char *p = src;
char *q = dst;
void* memcpy(void* dst, const void* src, size_t n) {
const char* p = src;
char* q = dst;
#if defined(__i386__)
size_t nl = n >> 2;
__asm__ volatile("cld ; rep ; movsl ; movl %3,%0 ; rep ; movsb"
: "+c"(nl), "+S"(p), "+D"(q)
: "r"(n & 3));
: "+c"(nl), "+S"(p), "+D"(q)
: "r"(n & 3));
#elif defined(__x86_64__)
size_t nq = n >> 3;
__asm__ volatile("cld ; rep ; movsq ; movl %3,%%ecx ; rep ; movsb"
: "+c"(nq), "+S"(p), "+D"(q)
: "r"((uint32_t)(n & 7)));
: "+c"(nq), "+S"(p), "+D"(q)
: "r"((uint32_t)(n & 7)));
#else
while (n--) {
*q++ = *p++;
@@ -63,20 +63,20 @@ void *memcpy(void *dst, const void *src, size_t n) {
return dst;
}
void *memset(void *dst, int c, size_t n) {
char *q = dst;
void* memset(void* dst, int c, size_t n) {
char* q = dst;
#if defined(__i386__)
size_t nl = n >> 2;
__asm__ volatile("cld ; rep ; stosl ; movl %3,%0 ; rep ; stosb"
: "+c"(nl), "+D"(q)
: "a"((unsigned char)c * 0x01010101U), "r"(n & 3));
: "+c"(nl), "+D"(q)
: "a"((unsigned char)c * 0x01010101U), "r"(n & 3));
#elif defined(__x86_64__)
size_t nq = n >> 3;
__asm__ volatile("cld ; rep ; stosq ; movl %3,%%ecx ; rep ; stosb"
: "+c"(nq), "+D"(q)
: "a"((unsigned char)c * 0x0101010101010101U),
"r"((uint32_t)n & 7));
: "+c"(nq), "+D"(q)
: "a"((unsigned char)c * 0x0101010101010101U),
"r"((uint32_t)n & 7));
#else
while (n--) {
*q++ = c;
@@ -86,15 +86,15 @@ void *memset(void *dst, int c, size_t n) {
return dst;
}
size_t strlen(const char *s) {
const char *ss = s;
size_t strlen(const char* s) {
const char* ss = s;
while (*ss) ss++;
return ss - s;
}
int strcmp(const char *s1, const char *s2) {
const unsigned char *c1 = (const unsigned char *)s1;
const unsigned char *c2 = (const unsigned char *)s2;
int strcmp(const char* s1, const char* s2) {
const unsigned char* c1 = (const unsigned char*)s1;
const unsigned char* c2 = (const unsigned char*)s2;
unsigned char ch;
int d = 0;
@@ -105,19 +105,3 @@ int strcmp(const char *s1, const char *s2) {
return d;
}
char *strncpy(char *dst, const char *src, size_t n) {
char *q = dst;
const char *p = src;
char ch;
while (n) {
n--;
*q++ = ch = *p++;
if (!ch) break;
}
memset(q, 0, n);
return dst;
}