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
6 changed files with 201 additions and 215 deletions

View File

@@ -1,107 +0,0 @@
#include "fat16.h"
#include "ata.h" // Use ata_read_sector and ata_write_sector
#include "print.h" // For debugging
#include <string.h> // For string manipulation
// Global variables
static fat16_boot_sector_t boot_sector;
static uint32_t root_dir_sector = FAT16_ROOT_DIR_SECTOR;
// Read a sector from the disk using ATA
bool read_sector(uint32_t lba, uint8_t* buffer) {
return ata_read_sector(lba, buffer);
}
// Write a sector to the disk using ATA
bool write_sector(uint32_t lba, const uint8_t* buffer) {
return ata_write_sector(lba, buffer);
}
// Parse the boot sector to retrieve basic file system info
bool parse_fat16_boot_sector(void) {
uint8_t sector_buffer[FAT16_SECTOR_SIZE];
// Read the boot sector
if (!read_sector(FAT16_BOOT_SECTOR, sector_buffer)) {
print_string("[FAT16] Failed to read boot sector\n");
return false;
}
// Cast to boot sector structure
memcpy(&boot_sector, sector_buffer, sizeof(fat16_boot_sector_t));
// Check for FAT16 signature
if (boot_sector.oem_name[0] != 'F' || boot_sector.oem_name[1] != 'A' || boot_sector.oem_name[2] != 'T') {
print_string("[FAT16] Invalid FAT16 boot sector signature\n");
return false;
}
print_string("[FAT16] FAT16 boot sector parsed successfully\n");
return true;
}
// Parse the root directory
bool parse_fat16_root_dir(void) {
uint8_t sector_buffer[FAT16_SECTOR_SIZE];
for (int i = 0; i < (boot_sector.max_root_entries / (FAT16_SECTOR_SIZE / sizeof(fat16_dir_entry_t))); i++) {
// Read root directory sector
if (!read_sector(root_dir_sector + i, sector_buffer)) {
print_string("[FAT16] Failed to read root directory sector\n");
return false;
}
// Parse the root directory entries
for (int j = 0; j < (FAT16_SECTOR_SIZE / sizeof(fat16_dir_entry_t)); j++) {
fat16_dir_entry_t* entry = (fat16_dir_entry_t*)&sector_buffer[j * sizeof(fat16_dir_entry_t)];
if (entry->name[0] == 0x00) {
// End of directory entries
return true;
}
if (entry->name[0] != 0xE5) {
// Print file name (8.3 format)
char filename[12];
strncpy(filename, (char*)entry->name, 8);
filename[8] = '.';
strncpy(&filename[9], (char*)entry->ext, 3);
filename[11] = '\0';
print_string(filename);
print_string("\n");
}
}
}
return true;
}
// Read a specific directory entry from the FAT16 root directory
bool read_fat16_entry(uint16_t entry_index, fat16_dir_entry_t* entry) {
uint8_t sector_buffer[FAT16_SECTOR_SIZE];
uint32_t sector_num = FAT16_ROOT_DIR_SECTOR + (entry_index / (FAT16_SECTOR_SIZE / sizeof(fat16_dir_entry_t)));
uint16_t entry_offset = entry_index % (FAT16_SECTOR_SIZE / sizeof(fat16_dir_entry_t));
// Read the sector
if (!read_sector(sector_num, sector_buffer)) {
print_string("[FAT16] Failed to read root directory sector\n");
return false;
}
// Get the entry
memcpy(entry, &sector_buffer[entry_offset * sizeof(fat16_dir_entry_t)], sizeof(fat16_dir_entry_t));
return true;
}
// Mount the FAT16 filesystem
bool mount_fat16(void) {
// Parse the boot sector
if (!parse_fat16_boot_sector()) {
return false;
}
// Parse the root directory
if (!parse_fat16_root_dir()) {
return false;
}
print_string("[FAT16] Filesystem mounted successfully\n");
return true;
}

View File

@@ -1,60 +0,0 @@
#ifndef FAT16_H
#define FAT16_H
#include <stdint.h>
#include <stdbool.h>
/* FAT16 Constants */
#define FAT16_SECTOR_SIZE 512
#define FAT16_CLUSTER_SIZE 1
#define FAT16_MAX_FILENAME_LEN 11 // 8.3 format
#define FAT16_ROOT_DIR_ENTRIES 224 // Fat16 root directory entries (typically 512 bytes per entry)
#define FAT16_BOOT_SECTOR 0
#define FAT16_FAT1_SECTOR 1
#define FAT16_FAT2_SECTOR 2
#define FAT16_ROOT_DIR_SECTOR 19 // First sector of root directory
/* Boot Sector */
typedef struct {
uint8_t jmp[3]; // Jump instruction to code
uint8_t oem_name[8]; // OEM Name
uint16_t bytes_per_sector; // Bytes per sector (512)
uint8_t sectors_per_cluster; // Sectors per cluster
uint16_t reserved_sectors; // Reserved sectors
uint8_t num_fats; // Number of FAT tables
uint16_t max_root_entries; // Max number of root directory entries
uint16_t total_sectors_16; // Total sectors in FAT16
uint8_t media_type; // Media type (0xF8 = fixed drive)
uint16_t sectors_per_fat; // Sectors per FAT table
uint16_t sectors_per_track; // Sectors per track (for CHS addressing)
uint16_t num_heads; // Number of heads (for CHS addressing)
uint32_t hidden_sectors; // Hidden sectors (before the partition)
uint32_t total_sectors_32; // Total sectors in FAT16 (extended)
} __attribute__((packed)) fat16_boot_sector_t;
/* FAT16 Directory Entry */
typedef struct {
uint8_t name[8]; // File name (8 chars)
uint8_t ext[3]; // File extension (3 chars)
uint8_t attributes; // File attributes (e.g., directory, read-only)
uint8_t reserved; // Reserved
uint8_t creation_time[2]; // Creation time
uint8_t creation_date[2]; // Creation date
uint8_t last_access_date[2]; // Last access date
uint8_t first_cluster_high[2]; // High part of first cluster number
uint8_t last_mod_time[2]; // Last modification time
uint8_t last_mod_date[2]; // Last modification date
uint8_t first_cluster_low[2]; // Low part of first cluster number
uint32_t file_size; // File size in bytes
} __attribute__((packed)) fat16_dir_entry_t;
/* Function Prototypes */
bool mount_fat16(void);
bool read_sector(uint32_t lba, uint8_t* buffer);
bool write_sector(uint32_t lba, const uint8_t* buffer);
bool parse_fat16_boot_sector(void);
bool parse_fat16_root_dir(void);
bool read_fat16_entry(uint16_t entry_index, fat16_dir_entry_t* entry);
#endif // FAT16_H

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;
}